From 48459dfaad7f5fc221d3ae688879b64137ea59fb Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Thu, 14 Apr 2022 12:31:25 +0530 Subject: [PATCH] feature(reserved ip): support for reserved ip changes --- examples/ibm-is-ng/main.tf | 35 ++ go.mod | 2 +- go.sum | 2 + ibm/provider/provider.go | 153 ++--- .../data_source_ibm_is_bare_metal_server.go | 99 ++- ..._is_bare_metal_server_network_interface.go | 69 +- ...are_metal_server_network_interface_test.go | 8 +- ...is_bare_metal_server_network_interfaces.go | 62 +- ...re_metal_server_network_interfaces_test.go | 6 + ...ta_source_ibm_is_bare_metal_server_test.go | 8 + .../data_source_ibm_is_bare_metal_servers.go | 81 ++- ...a_source_ibm_is_bare_metal_servers_test.go | 6 + .../vpc/data_source_ibm_is_floating_ip.go | 269 +++++++- .../data_source_ibm_is_floating_ip_test.go | 5 + .../vpc/data_source_ibm_is_floating_ips.go | 187 +++++- .../data_source_ibm_is_floating_ips_test.go | 5 + .../vpc/data_source_ibm_is_flow_log.go | 4 +- .../vpc/data_source_ibm_is_instance.go | 131 +++- ...ource_ibm_is_instance_network_interface.go | 58 +- ..._instance_network_interface_reserved_ip.go | 143 +++++ ...ance_network_interface_reserved_ip_test.go | 93 +++ ...instance_network_interface_reserved_ips.go | 172 +++++ ...nce_network_interface_reserved_ips_test.go | 95 +++ ..._ibm_is_instance_network_interface_test.go | 5 + ...urce_ibm_is_instance_network_interfaces.go | 62 +- ...ibm_is_instance_network_interfaces_test.go | 5 + .../data_source_ibm_is_instance_template.go | 172 ++++- ...ta_source_ibm_is_instance_template_test.go | 33 + .../data_source_ibm_is_instance_templates.go | 105 +++- ...a_source_ibm_is_instance_templates_test.go | 35 ++ .../vpc/data_source_ibm_is_instance_test.go | 78 +++ .../vpc/data_source_ibm_is_instances.go | 117 +++- .../vpc/data_source_ibm_is_instances_test.go | 57 ++ ibm/service/vpc/data_source_ibm_is_lb.go | 97 ++- ibm/service/vpc/data_source_ibm_is_lb_test.go | 33 + ibm/service/vpc/data_source_ibm_is_lbs.go | 54 +- .../vpc/data_source_ibm_is_lbs_test.go | 36 ++ .../data_source_ibm_is_subnet_reserved_ip.go | 9 + .../data_source_ibm_is_subnet_reserved_ips.go | 6 + .../vpc/data_source_ibm_is_vpn_gateway.go | 2 +- .../vpc/data_source_ibm_is_vpn_gateways.go | 3 +- .../vpc/resource_ibm_is_bare_metal_server.go | 262 +++++++- ..._is_bare_metal_server_network_interface.go | 204 ++++-- ...al_server_network_interface_allow_float.go | 154 ++++- ...rver_network_interface_allow_float_test.go | 78 +++ ...are_metal_server_network_interface_test.go | 76 +++ .../resource_ibm_is_bare_metal_server_test.go | 63 ++ .../vpc/resource_ibm_is_floating_ip.go | 237 ++++++- .../vpc/resource_ibm_is_floating_ip_test.go | 10 + ibm/service/vpc/resource_ibm_is_flow_log.go | 2 +- ibm/service/vpc/resource_ibm_is_instance.go | 587 +++++++++++++++++- ...ource_ibm_is_instance_network_interface.go | 183 +++++- ..._ibm_is_instance_network_interface_test.go | 81 +++ .../vpc/resource_ibm_is_instance_template.go | 270 +++++++- .../resource_ibm_is_instance_template_test.go | 75 +++ .../vpc/resource_ibm_is_instance_test.go | 71 +++ ibm/service/vpc/resource_ibm_is_lb.go | 55 +- ibm/service/vpc/resource_ibm_is_lb_test.go | 44 ++ ...rity_group_network_interface_attachment.go | 4 +- ...group_network_interface_attachment_test.go | 4 +- .../vpc/resource_ibm_is_subnet_reserved_ip.go | 64 +- .../vpc/resource_ibm_is_vpn_gateway.go | 2 +- website/docs/d/is_bare_metal_server.markdown | 8 + ...re_metal_server_network_interface.markdown | 7 +- ...e_metal_server_network_interfaces.markdown | 6 +- website/docs/d/is_bare_metal_servers.markdown | 10 + website/docs/d/is_floating_ip.html.markdown | 23 +- website/docs/d/is_floating_ips.html.markdown | 13 +- website/docs/d/is_instance.html.markdown | 20 +- ...s_instance_network_interface.html.markdown | 11 +- ...etwork_interface_reserved_ip.html.markdown | 44 ++ ...twork_interface_reserved_ips.html.markdown | 46 ++ ..._instance_network_interfaces.html.markdown | 10 +- website/docs/d/is_instances.html.markdown | 22 +- website/docs/d/is_lb.html.markdown | 10 +- website/docs/d/is_lbs.html.markdown | 10 +- .../d/is_subnet_reserved_ip.html.markdown | 1 + .../d/is_subnet_reserved_ips.html.markdown | 1 + website/docs/d/is_vpn_gateway.html.markdown | 10 +- website/docs/d/is_vpn_gateways.html.markdown | 9 +- website/docs/r/is_bare_metal_server.markdown | 69 +- ...re_metal_server_network_interface.markdown | 3 + ...ver_network_interface_allow_float.markdown | 3 + website/docs/r/is_floating_ip.html.markdown | 32 +- website/docs/r/is_instance.html.markdown | 15 +- ...s_instance_network_interface.html.markdown | 6 + website/docs/r/is_lb.html.markdown | 10 +- .../r/is_subnet_reserved_ip.html.markdown | 3 +- .../is_virtual_endpoint_gateway.html.markdown | 2 +- 89 files changed, 5134 insertions(+), 398 deletions(-) create mode 100644 ibm/service/vpc/data_source_ibm_is_instance_network_interface_reserved_ip.go create mode 100644 ibm/service/vpc/data_source_ibm_is_instance_network_interface_reserved_ip_test.go create mode 100644 ibm/service/vpc/data_source_ibm_is_instance_network_interface_reserved_ips.go create mode 100644 ibm/service/vpc/data_source_ibm_is_instance_network_interface_reserved_ips_test.go create mode 100644 website/docs/d/is_instance_network_interface_reserved_ip.html.markdown create mode 100644 website/docs/d/is_instance_network_interface_reserved_ips.html.markdown diff --git a/examples/ibm-is-ng/main.tf b/examples/ibm-is-ng/main.tf index 95ba567c16..6fd44ebd44 100644 --- a/examples/ibm-is-ng/main.tf +++ b/examples/ibm-is-ng/main.tf @@ -692,6 +692,41 @@ 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] +} + + +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 diff --git a/go.mod b/go.mod index 703866c104..8524105e26 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/IBM/scc-go-sdk/v3 v3.1.6 github.com/IBM/schematics-go-sdk v0.1.3 github.com/IBM/secrets-manager-go-sdk v0.1.19 - github.com/IBM/vpc-go-sdk v0.17.0 + github.com/IBM/vpc-go-sdk v0.19.0 github.com/PromonLogicalis/asn1 v0.0.0-20190312173541-d60463189a56 // indirect github.com/ScaleFT/sshkeys v0.0.0-20200327173127-6142f742bca5 github.com/Shopify/sarama v1.29.1 diff --git a/go.sum b/go.sum index 69cbd102eb..ed922e8789 100644 --- a/go.sum +++ b/go.sum @@ -104,6 +104,8 @@ github.com/IBM/secrets-manager-go-sdk v0.1.19 h1:0GPs5EoTaWNsjo4QPj64GNxlWfN8VHJ 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.17.0 h1:H9qsEx1UJoAR79s1R7n3bGPdOPW6+wLNEUyCjnesaxs= github.com/IBM/vpc-go-sdk v0.17.0/go.mod h1:+fTuJIR/SWXru/B5XEANwV4GCLV5fRppFEzlYGwGm7k= +github.com/IBM/vpc-go-sdk v0.19.0 h1:f6fqF4W1h3dtAk+U8XLEUv1lPZ8jnvRoEFkTgOBPw8Q= +github.com/IBM/vpc-go-sdk v0.19.0/go.mod h1:KCdyxbJdWtN4pyWC1SqLH0Jk/y4ed8nv9gZb4ZxfepQ= 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= diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index 8a79e7f9d0..58069bc55d 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -389,80 +389,85 @@ func Provider() *schema.Provider { "ibm_is_instance_network_interfaces": vpc.DataSourceIBMIsInstanceNetworkInterfaces(), "ibm_is_instance_disk": vpc.DataSourceIbmIsInstanceDisk(), "ibm_is_instance_disks": vpc.DataSourceIbmIsInstanceDisks(), - "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_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_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_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_feature": appconfiguration.DataSourceIBMAppConfigFeature(), - "ibm_app_config_features": appconfiguration.DataSourceIBMAppConfigFeatures(), + + // 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_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_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_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_feature": appconfiguration.DataSourceIBMAppConfigFeature(), + "ibm_app_config_features": appconfiguration.DataSourceIBMAppConfigFeatures(), "ibm_resource_quota": resourcecontroller.DataSourceIBMResourceQuota(), "ibm_resource_group": resourcemanager.DataSourceIBMResourceGroup(), diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server.go index f96b7167fb..0fa002b117 100644 --- a/ibm/service/vpc/data_source_ibm_is_bare_metal_server.go +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server.go @@ -158,9 +158,8 @@ func DataSourceIBMIsBareMetalServer() *schema.Resource { Computed: true, }, isBareMetalServerNicPortSpeed: { - Type: schema.TypeInt, - Computed: true, - Deprecated: "This field is deprected", + Type: schema.TypeInt, + Computed: true, }, isBareMetalServerNicHref: { Type: schema.TypeString, @@ -189,6 +188,26 @@ func DataSourceIBMIsBareMetalServer() *schema.Resource { 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", + }, }, }, }, @@ -240,6 +259,26 @@ func DataSourceIBMIsBareMetalServer() *schema.Resource { 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", + }, }, }, }, @@ -369,7 +408,7 @@ func dataSourceIBMISBareMetalServerRead(context context.Context, d *schema.Resou 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 { + if len(bmservers.BareMetalServers) == 0 { return diag.FromErr(fmt.Errorf("[ERROR] No bare metal servers found with name %s", name)) } bms = &bmservers.BareMetalServers[0] @@ -454,12 +493,27 @@ func dataSourceIBMISBareMetalServerRead(context context.Context, d *schema.Resou 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{}{ - isBareMetalServerNicIpAddress: *bms.PrimaryNetworkInterface.PrimaryIpv4Address, + 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 } - primaryIpList = append(primaryIpList, currentIP) - currentPrimNic[isBareMetalServerNicPrimaryIP] = primaryIpList getnicoptions := &vpcv1.GetBareMetalServerNetworkInterfaceOptions{ BareMetalServerID: bms.ID, ID: bms.PrimaryNetworkInterface.ID, @@ -474,6 +528,7 @@ func dataSourceIBMISBareMetalServerRead(context context.Context, d *schema.Resou { 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++ { @@ -486,6 +541,7 @@ func dataSourceIBMISBareMetalServerRead(context context.Context, d *schema.Resou { primNic := bmsnic.(*vpcv1.BareMetalServerNetworkInterfaceByVlan) currentPrimNic[isInstanceNicAllowIPSpoofing] = *primNic.AllowIPSpoofing + currentPrimNic[isBareMetalServerNicPortSpeed] = *primNic.PortSpeed if len(primNic.SecurityGroups) != 0 { secgrpList := []string{} @@ -510,12 +566,27 @@ func dataSourceIBMISBareMetalServerRead(context context.Context, d *schema.Resou currentNic["id"] = *intfc.ID currentNic[isBareMetalServerNicHref] = *intfc.Href currentNic[isBareMetalServerNicName] = *intfc.Name - primaryIpList := make([]map[string]interface{}, 0) - currentIP := map[string]interface{}{ - isBareMetalServerNicIpAddress: *intfc.PrimaryIpv4Address, + 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 } - primaryIpList = append(primaryIpList, currentIP) - currentNic[isBareMetalServerNicPrimaryIP] = primaryIpList getnicoptions := &vpcv1.GetBareMetalServerNetworkInterfaceOptions{ BareMetalServerID: bms.ID, ID: intfc.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 index e865d1aadf..c202ce6be5 100644 --- 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 @@ -21,7 +21,7 @@ const ( isBareMetalServerNicIpAddress = "address" isBareMetalServerNicIpCRN = "crn" isBareMetalServerNicIpHref = "href" - isBareMetalServerNicIpID = "id" + isBareMetalServerNicIpID = "reserved_ip" isBareMetalServerNicIpName = "name" isBareMetalServerNicIpAutoDelete = "auto_delete" isBareMetalServerNicHref = "href" @@ -138,6 +138,26 @@ func DataSourceIBMIsBareMetalServerNetworkInterface() *schema.Resource { 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", + }, }, }, }, @@ -243,8 +263,21 @@ func dataSourceIBMISBareMetalServerNetworkInterfaceRead(context context.Context, d.Set(isBareMetalServerNicPortSpeed, *nic.PortSpeed) } primaryIpList := make([]map[string]interface{}, 0) - currentIP := map[string]interface{}{ - isBareMetalServerNicIpAddress: *nic.PrimaryIpv4Address, + 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) @@ -297,14 +330,30 @@ func dataSourceIBMISBareMetalServerNetworkInterfaceRead(context context.Context, 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{}{ - isBareMetalServerNicIpAddress: *nic.PrimaryIpv4Address, + 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) } - primaryIpList = append(primaryIpList, currentIP) - d.Set(isBareMetalServerNicPrimaryIP, primaryIpList) d.Set(isBareMetalServerNicResourceType, *nic.ResourceType) 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 index c636a68e27..d55d1f0bbd 100644 --- 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 @@ -33,7 +33,13 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE Config: testAccCheckIBMISBareMetalServerNetworkInterfaceDataSourceConfig(vpcname, subnetname, sshname, publicKey, name), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISBareMetalServerExists("ibm_is_bare_metal_server.testacc_bms", server), - resource.TestCheckResourceAttrSet(resName, "network_interfaces.0.id"), + 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"), ), }, }, 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 index 1a150af9c7..c64cd8e384 100644 --- 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 @@ -116,6 +116,26 @@ func DataSourceIBMIsBareMetalServerNetworkInterfaces() *schema.Resource { 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", + }, }, }, }, @@ -225,12 +245,27 @@ func dataSourceIBMISBareMetalServerNetworkInterfacesRead(context context.Context if nic.PortSpeed != nil { l[isBareMetalServerNicPortSpeed] = *nic.PortSpeed } - primaryIpList := make([]map[string]interface{}, 0) - currentIP := map[string]interface{}{ - isBareMetalServerNicIpAddress: *nic.PrimaryIpv4Address, + 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 } - primaryIpList = append(primaryIpList, currentIP) - l[isBareMetalServerNicPrimaryIP] = primaryIpList l[isBareMetalServerNicResourceType] = *nic.ResourceType if nic.SecurityGroups != nil && len(nic.SecurityGroups) != 0 { secgrpList := []string{} @@ -278,8 +313,21 @@ func dataSourceIBMISBareMetalServerNetworkInterfacesRead(context context.Context } primaryIpList := make([]map[string]interface{}, 0) - currentIP := map[string]interface{}{ - isBareMetalServerNicIpAddress: *nic.PrimaryIpv4Address, + 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 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 index 51cf0b87fe..b904b145b2 100644 --- 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 @@ -35,6 +35,12 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE 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"), ), }, }, diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_test.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_test.go index 624cdd811d..3424358fe3 100644 --- a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_test.go +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_test.go @@ -37,6 +37,14 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE 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"), ), }, }, diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_servers.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_servers.go index 3059f8c49b..3b87170cdb 100644 --- a/ibm/service/vpc/data_source_ibm_is_bare_metal_servers.go +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_servers.go @@ -163,9 +163,8 @@ func DataSourceIBMIsBareMetalServers() *schema.Resource { Computed: true, }, isBareMetalServerNicPortSpeed: { - Type: schema.TypeInt, - Computed: true, - Deprecated: "This field is deprected", + Type: schema.TypeInt, + Computed: true, }, isBareMetalServerNicHref: { Type: schema.TypeString, @@ -194,6 +193,26 @@ func DataSourceIBMIsBareMetalServers() *schema.Resource { 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", + }, }, }, }, @@ -245,6 +264,26 @@ func DataSourceIBMIsBareMetalServers() *schema.Resource { 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", + }, }, }, }, @@ -413,8 +452,21 @@ func dataSourceIBMISBareMetalServersRead(context context.Context, d *schema.Reso currentPrimNic[isBareMetalServerNicHref] = *bms.PrimaryNetworkInterface.Href currentPrimNic[isBareMetalServerNicSubnet] = *bms.PrimaryNetworkInterface.Subnet.ID primaryIpList := make([]map[string]interface{}, 0) - currentIP := map[string]interface{}{ - isBareMetalServerNicIpAddress: *bms.PrimaryNetworkInterface.PrimaryIpv4Address, + 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 @@ -432,6 +484,7 @@ func dataSourceIBMISBareMetalServersRead(context context.Context, d *schema.Reso { 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++ { @@ -444,6 +497,7 @@ func dataSourceIBMISBareMetalServersRead(context context.Context, d *schema.Reso { primNic := bmsnic.(*vpcv1.BareMetalServerNetworkInterfaceByVlan) currentPrimNic[isInstanceNicAllowIPSpoofing] = *primNic.AllowIPSpoofing + currentPrimNic[isBareMetalServerNicPortSpeed] = *primNic.PortSpeed if len(primNic.SecurityGroups) != 0 { secgrpList := []string{} @@ -469,8 +523,21 @@ func dataSourceIBMISBareMetalServersRead(context context.Context, d *schema.Reso currentNic[isBareMetalServerNicHref] = *intfc.Href currentNic[isBareMetalServerNicName] = *intfc.Name primaryIpList := make([]map[string]interface{}, 0) - currentIP := map[string]interface{}{ - isBareMetalServerNicIpAddress: *intfc.PrimaryIpv4Address, + 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 diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_servers_test.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_servers_test.go index 726b57d334..96979a9b09 100644 --- a/ibm/service/vpc/data_source_ibm_is_bare_metal_servers_test.go +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_servers_test.go @@ -36,6 +36,12 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE 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"), ), }, }, diff --git a/ibm/service/vpc/data_source_ibm_is_floating_ip.go b/ibm/service/vpc/data_source_ibm_is_floating_ip.go index 7c834d43bd..95bbdf48f3 100644 --- a/ibm/service/vpc/data_source_ibm_is_floating_ip.go +++ b/ibm/service/vpc/data_source_ibm_is_floating_ip.go @@ -5,6 +5,7 @@ package vpc import ( "fmt" + "reflect" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM/vpc-go-sdk/vpcv1" @@ -12,13 +13,27 @@ import ( ) const ( - floatingIPName = "name" - floatingIPAddress = "address" - floatingIPStatus = "status" - floatingIPZone = "zone" - floatingIPTarget = "target" - floatingIPTags = "tags" - floatingIPCRN = "crn" + 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 { @@ -57,6 +72,89 @@ func DataSourceIBMISFloatingIP() *schema.Resource { 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, @@ -116,15 +214,15 @@ func floatingIPGet(d *schema.ResourceData, meta interface{}, name string) error d.Set(floatingIPZone, *ip.Zone.Name) d.Set(floatingIPCRN, *ip.CRN) - - target, ok := ip.Target.(*vpcv1.FloatingIPTarget) - if ok { - d.Set(floatingIPTarget, target.ID) - } + 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 on get of vpc Floating IP (%s) tags: %s", *ip.Address, err) + fmt.Printf("[ERROR] Error on get of vpc Floating IP (%s) tags: %s", *ip.Address, err) } d.Set(floatingIPTags, tags) @@ -137,3 +235,148 @@ func floatingIPGet(d *schema.ResourceData, meta interface{}, name string) error 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/service/vpc/data_source_ibm_is_floating_ip_test.go b/ibm/service/vpc/data_source_ibm_is_floating_ip_test.go index 777a82b26a..03f3720454 100644 --- a/ibm/service/vpc/data_source_ibm_is_floating_ip_test.go +++ b/ibm/service/vpc/data_source_ibm_is_floating_ip_test.go @@ -35,6 +35,11 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resName, "name", fipname), 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"), ), }, }, diff --git a/ibm/service/vpc/data_source_ibm_is_floating_ips.go b/ibm/service/vpc/data_source_ibm_is_floating_ips.go index d1fab8d802..c26c5af8ce 100644 --- a/ibm/service/vpc/data_source_ibm_is_floating_ips.go +++ b/ibm/service/vpc/data_source_ibm_is_floating_ips.go @@ -7,6 +7,7 @@ import ( "context" "fmt" "log" + "reflect" "time" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" @@ -131,6 +132,40 @@ func DataSourceIBMIsFloatingIps() *schema.Resource { 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, @@ -321,37 +356,139 @@ func dataSourceFloatingIPCollectionFloatingIpsResourceGroupToMap(resourceGroupIt func dataSourceFloatingIPCollectionFloatingIpsTargetToMap(targetItemIntf vpcv1.FloatingIPTargetIntf) (targetMap map[string]interface{}) { targetMap = map[string]interface{}{} - targetItem := targetItemIntf.(*vpcv1.FloatingIPTarget) - if targetItem.Deleted != nil { - deletedList := []map[string]interface{}{} - deletedMap := dataSourceFloatingIPCollectionTargetDeletedToMap(*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.PrimaryIpv4Address != nil { - targetMap["primary_ipv4_address"] = targetItem.PrimaryIpv4Address - } - if targetItem.ResourceType != nil { - targetMap["resource_type"] = targetItem.ResourceType - } - if targetItem.CRN != nil { - targetMap["crn"] = targetItem.CRN + 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 dataSourceFloatingIPCollectionTargetDeletedToMap(deletedItem vpcv1.NetworkInterfaceReferenceDeleted) (deletedMap map[string]interface{}) { +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 { 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 index 5aa85053f7..c6be008628 100644 --- a/ibm/service/vpc/data_source_ibm_is_floating_ips_test.go +++ b/ibm/service/vpc/data_source_ibm_is_floating_ips_test.go @@ -34,6 +34,11 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE 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"), ), }, }, diff --git a/ibm/service/vpc/data_source_ibm_is_flow_log.go b/ibm/service/vpc/data_source_ibm_is_flow_log.go index 604d930009..5cec87c65a 100644 --- a/ibm/service/vpc/data_source_ibm_is_flow_log.go +++ b/ibm/service/vpc/data_source_ibm_is_flow_log.go @@ -321,7 +321,7 @@ func dataSourceFlowLogCollectorResourceGroupToMap(resourceGroupItem vpcv1.Resour return resourceGroupMap } -func dataSourceFlowLogCollectorFlattenStorageBucket(result vpcv1.CloudObjectStorageBucketReference) (finalList []map[string]interface{}) { +func dataSourceFlowLogCollectorFlattenStorageBucket(result vpcv1.LegacyCloudObjectStorageBucketReference) (finalList []map[string]interface{}) { finalList = []map[string]interface{}{} finalMap := dataSourceFlowLogCollectorStorageBucketToMap(result) finalList = append(finalList, finalMap) @@ -329,7 +329,7 @@ func dataSourceFlowLogCollectorFlattenStorageBucket(result vpcv1.CloudObjectStor return finalList } -func dataSourceFlowLogCollectorStorageBucketToMap(storageBucketItem vpcv1.CloudObjectStorageBucketReference) (storageBucketMap map[string]interface{}) { +func dataSourceFlowLogCollectorStorageBucketToMap(storageBucketItem vpcv1.LegacyCloudObjectStorageBucketReference) (storageBucketMap map[string]interface{}) { storageBucketMap = map[string]interface{}{} if storageBucketItem.Name != nil { diff --git a/ibm/service/vpc/data_source_ibm_is_instance.go b/ibm/service/vpc/data_source_ibm_is_instance.go index c4f02ebc26..77f1e1ce05 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance.go +++ b/ibm/service/vpc/data_source_ibm_is_instance.go @@ -23,10 +23,17 @@ import ( ) const ( - isInstancePEM = "private_key" - isInstancePassphrase = "passphrase" - isInstanceInitPassword = "password" - isInstanceInitKeys = "keys" + 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 { @@ -237,6 +244,40 @@ func DataSourceIBMISInstance() *schema.Resource { 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, @@ -274,6 +315,40 @@ func DataSourceIBMISInstance() *schema.Resource { 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, @@ -614,7 +689,29 @@ func instanceGetByName(d *schema.ResourceData, meta interface{}, name string) er currentPrimNic := map[string]interface{}{} currentPrimNic["id"] = *instance.PrimaryNetworkInterface.ID currentPrimNic[isInstanceNicName] = *instance.PrimaryNetworkInterface.Name - currentPrimNic[isInstanceNicPrimaryIpv4Address] = *instance.PrimaryNetworkInterface.PrimaryIpv4Address + + // 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, @@ -646,7 +743,29 @@ func instanceGetByName(d *schema.ResourceData, meta interface{}, name string) er currentNic := map[string]interface{}{} currentNic["id"] = *intfc.ID currentNic[isInstanceNicName] = *intfc.Name - currentNic[isInstanceNicPrimaryIpv4Address] = *intfc.PrimaryIpv4Address + + // 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, 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 index 5fc422780e..bba64f8c06 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_network_interface.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_network_interface.go @@ -109,6 +109,40 @@ func DataSourceIBMIsInstanceNetworkInterface() *schema.Resource { 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, @@ -281,9 +315,31 @@ func dataSourceIBMIsInstanceNetworkInterfaceRead(context context.Context, d *sch 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.PrimaryIpv4Address); err != nil { + 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)) } 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 0000000000..49fd59f5ba --- /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 0000000000..371baa7963 --- /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 0000000000..db39ddd2a0 --- /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 0000000000..82fff4d747 --- /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 index c2bf7822fc..eca890cb95 100644 --- 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 @@ -44,6 +44,11 @@ func TestAccIBMIsInstanceNetworkInterfaceDataSourceBasic(t *testing.T) { 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"), ), }, }, 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 index cbbfc7f7e9..3784983517 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_network_interfaces.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_network_interfaces.go @@ -116,6 +116,40 @@ func DataSourceIBMIsInstanceNetworkInterfaces() *schema.Resource { 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, @@ -327,8 +361,32 @@ func dataSourceNetworkInterfaceCollectionNetworkInterfacesToMap(networkInterface if networkInterfacesItem.PortSpeed != nil { networkInterfacesMap["port_speed"] = networkInterfacesItem.PortSpeed } - if networkInterfacesItem.PrimaryIpv4Address != nil { - networkInterfacesMap["primary_ipv4_address"] = networkInterfacesItem.PrimaryIpv4Address + 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 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 index d77f290f5e..7cb51eaed1 100644 --- 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 @@ -34,6 +34,11 @@ func TestAccIBMIsInstanceNetworkInterfacesDataSourceBasic(t *testing.T) { 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"), ), }, }, diff --git a/ibm/service/vpc/data_source_ibm_is_instance_template.go b/ibm/service/vpc/data_source_ibm_is_instance_template.go index 7ed9d37a06..2304531b87 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_template.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_template.go @@ -6,6 +6,7 @@ package vpc import ( "context" "fmt" + "log" "reflect" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" @@ -185,6 +186,30 @@ func DataSourceIBMISInstanceTemplate() *schema.Resource { 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, @@ -212,6 +237,30 @@ func DataSourceIBMISInstanceTemplate() *schema.Resource { 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, @@ -368,11 +417,47 @@ func dataSourceIBMISInstanceTemplateRead(context context.Context, d *schema.Reso } 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.PrimaryIpv4Address != nil { - currentPrimNic[isInstanceTemplateNicPrimaryIpv4Address] = *instance.PrimaryNetworkInterface.PrimaryIpv4Address + 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) @@ -396,8 +481,31 @@ func dataSourceIBMISInstanceTemplateRead(context context.Context, d *schema.Reso for _, intfc := range instance.NetworkInterfaces { currentNic := map[string]interface{}{} currentNic[isInstanceTemplateNicName] = *intfc.Name - if intfc.PrimaryIpv4Address != nil { - currentNic[isInstanceTemplateNicPrimaryIpv4Address] = *intfc.PrimaryIpv4Address + 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 @@ -565,8 +673,43 @@ func dataSourceIBMISInstanceTemplateRead(context context.Context, d *schema.Reso 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 + 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) @@ -590,8 +733,21 @@ func dataSourceIBMISInstanceTemplateRead(context context.Context, d *schema.Reso for _, intfc := range instance.NetworkInterfaces { currentNic := map[string]interface{}{} currentNic[isInstanceTemplateNicName] = *intfc.Name - if intfc.PrimaryIpv4Address != nil { - currentNic[isInstanceTemplateNicPrimaryIpv4Address] = *intfc.PrimaryIpv4Address + 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 diff --git a/ibm/service/vpc/data_source_ibm_is_instance_template_test.go b/ibm/service/vpc/data_source_ibm_is_instance_template_test.go index 7c4c7935fe..80c7318b47 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_template_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_template_test.go @@ -40,6 +40,32 @@ func TestAccIBMISInstanceTemplate_dataBasic(t *testing.T) { }, }) } +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(` @@ -48,3 +74,10 @@ func testAccCheckIBMISInstanceTemplateDConfig(vpcName, subnetName, sshKeyName, p } `) } +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 index 8a126ba206..4998764f92 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_templates.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_templates.go @@ -238,6 +238,30 @@ func DataSourceIBMISInstanceTemplates() *schema.Resource { 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, @@ -265,6 +289,30 @@ func DataSourceIBMISInstanceTemplates() *schema.Resource { 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, @@ -406,8 +454,33 @@ func dataSourceIBMISInstanceTemplatesRead(d *schema.ResourceData, meta interface 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 + + 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) @@ -431,8 +504,32 @@ func dataSourceIBMISInstanceTemplatesRead(d *schema.ResourceData, meta interface for _, intfc := range instance.NetworkInterfaces { currentNic := map[string]interface{}{} currentNic[isInstanceTemplateNicName] = *intfc.Name - if intfc.PrimaryIpv4Address != nil { - currentNic[isInstanceTemplateNicPrimaryIpv4Address] = *intfc.PrimaryIpv4Address + 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 diff --git a/ibm/service/vpc/data_source_ibm_is_instance_templates_test.go b/ibm/service/vpc/data_source_ibm_is_instance_templates_test.go index 45466c4666..00e12cb8c2 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_templates_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_templates_test.go @@ -40,6 +40,34 @@ func TestAccIBMISInstanceTemplates_dataBasic(t *testing.T) { }, }) } +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(` @@ -48,3 +76,10 @@ func testAccCheckIBMISInstanceTemplatesDConfig(vpcName, subnetName, sshKeyName, } `) } +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 index 02ff17cb98..0682ae52f1 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_test.go @@ -5,6 +5,7 @@ package vpc_test import ( "fmt" + "strings" "testing" acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" @@ -41,6 +42,44 @@ func TestAccIBMISInstanceDataSource_basic(t *testing.T) { }, }) } +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(` @@ -82,3 +121,42 @@ data "ibm_is_instance" "ds_instance" { 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/service/vpc/data_source_ibm_is_instances.go b/ibm/service/vpc/data_source_ibm_is_instances.go index b04661e681..7e763d86bd 100644 --- a/ibm/service/vpc/data_source_ibm_is_instances.go +++ b/ibm/service/vpc/data_source_ibm_is_instances.go @@ -252,6 +252,40 @@ func DataSourceIBMISInstances() *schema.Resource { 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, @@ -336,6 +370,40 @@ func DataSourceIBMISInstances() *schema.Resource { 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, @@ -738,7 +806,30 @@ func instancesList(d *schema.ResourceData, meta interface{}) error { currentPrimNic := map[string]interface{}{} currentPrimNic["id"] = *instance.PrimaryNetworkInterface.ID currentPrimNic[isInstanceNicName] = *instance.PrimaryNetworkInterface.Name - currentPrimNic[isInstanceNicPrimaryIpv4Address] = *instance.PrimaryNetworkInterface.PrimaryIpv4Address + + // 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, @@ -767,7 +858,29 @@ func instancesList(d *schema.ResourceData, meta interface{}) error { currentNic := map[string]interface{}{} currentNic["id"] = *intfc.ID currentNic[isInstanceNicName] = *intfc.Name - currentNic[isInstanceNicPrimaryIpv4Address] = *intfc.PrimaryIpv4Address + + // 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, diff --git a/ibm/service/vpc/data_source_ibm_is_instances_test.go b/ibm/service/vpc/data_source_ibm_is_instances_test.go index 8c528a1025..1aaa043ba5 100644 --- a/ibm/service/vpc/data_source_ibm_is_instances_test.go +++ b/ibm/service/vpc/data_source_ibm_is_instances_test.go @@ -60,6 +60,56 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }, }) } +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 @@ -137,6 +187,13 @@ func testAccCheckIBMISInstancesDataSourceConfig() string { }`) } +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" { diff --git a/ibm/service/vpc/data_source_ibm_is_lb.go b/ibm/service/vpc/data_source_ibm_is_lb.go index 9e79dc97eb..bd1b0ba186 100644 --- a/ibm/service/vpc/data_source_ibm_is_lb.go +++ b/ibm/service/vpc/data_source_ibm_is_lb.go @@ -14,24 +14,30 @@ import ( ) 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" + 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 { @@ -224,6 +230,40 @@ func DataSourceIBMISLB() *schema.Resource { }, }, }, + 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, @@ -308,14 +348,35 @@ func lbGetByName(d *schema.ResourceData, meta interface{}, name string) error { } 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) diff --git a/ibm/service/vpc/data_source_ibm_is_lb_test.go b/ibm/service/vpc/data_source_ibm_is_lb_test.go index be752a3d02..3a62ebb2eb 100644 --- a/ibm/service/vpc/data_source_ibm_is_lb_test.go +++ b/ibm/service/vpc/data_source_ibm_is_lb_test.go @@ -34,6 +34,39 @@ func TestAccIBMISLBDatasource_basic(t *testing.T) { }, }) } +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(` diff --git a/ibm/service/vpc/data_source_ibm_is_lbs.go b/ibm/service/vpc/data_source_ibm_is_lbs.go index 3ce73f7ce9..a6fe7bc033 100644 --- a/ibm/service/vpc/data_source_ibm_is_lbs.go +++ b/ibm/service/vpc/data_source_ibm_is_lbs.go @@ -93,7 +93,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, @@ -283,15 +316,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 { diff --git a/ibm/service/vpc/data_source_ibm_is_lbs_test.go b/ibm/service/vpc/data_source_ibm_is_lbs_test.go index 9cb4b8f820..fd078bd5f5 100644 --- a/ibm/service/vpc/data_source_ibm_is_lbs_test.go +++ b/ibm/service/vpc/data_source_ibm_is_lbs_test.go @@ -42,6 +42,42 @@ func TestAccIBMISLBSDatasource_basic(t *testing.T) { }, }) +} +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 { diff --git a/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ip.go b/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ip.go index a22ae0b207..87160da4b0 100644 --- a/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ip.go +++ b/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ip.go @@ -58,6 +58,11 @@ func DataSourceIBMISReservedIP() *schema.Resource { 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, @@ -117,10 +122,14 @@ func dataSdataSourceIBMISReservedIPRead(d *schema.ResourceData, meta interface{} 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 { target, ok := reserveIP.Target.(*vpcv1.ReservedIPTarget) diff --git a/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ips.go b/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ips.go index 938e5aa5c5..1a5382d6a3 100644 --- a/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ips.go +++ b/ibm/service/vpc/data_source_ibm_is_subnet_reserved_ips.go @@ -73,6 +73,11 @@ func DataSourceIBMISReservedIPs() *schema.Resource { 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, @@ -143,6 +148,7 @@ func dataSdataSourceIBMISReservedIPsRead(d *schema.ResourceData, meta interface{ 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 diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_gateway.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateway.go index 532d8fca68..1ffff78b2e 100644 --- a/ibm/service/vpc/data_source_ibm_is_vpn_gateway.go +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateway.go @@ -370,7 +370,7 @@ func dataSourceVPNGatewayFlattenMembers(result []vpcv1.VPNGatewayMember) (member func dataSourceVPNGatewayMembersToMap(membersItem vpcv1.VPNGatewayMember) (membersMap map[string]interface{}) { membersMap = map[string]interface{}{} - if membersItem.PrivateIP != nil { + if membersItem.PrivateIP != nil && membersItem.PrivateIP.Address != nil { membersMap["private_ip_address"] = membersItem.PrivateIP.Address } if membersItem.PublicIP != nil { diff --git a/ibm/service/vpc/data_source_ibm_is_vpn_gateways.go b/ibm/service/vpc/data_source_ibm_is_vpn_gateways.go index 30aed92b7a..e0e0abc7bb 100644 --- a/ibm/service/vpc/data_source_ibm_is_vpn_gateways.go +++ b/ibm/service/vpc/data_source_ibm_is_vpn_gateways.go @@ -62,7 +62,6 @@ func DataSourceIBMISVPNGateways() *schema.Resource { Computed: true, Description: "The private IP address assigned to the VPN gateway member", }, - "role": { Type: schema.TypeString, Computed: true, @@ -161,7 +160,7 @@ func dataSourceIBMVPNGatewaysRead(d *schema.ResourceData, meta interface{}) erro 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 } } diff --git a/ibm/service/vpc/resource_ibm_is_bare_metal_server.go b/ibm/service/vpc/resource_ibm_is_bare_metal_server.go index 891ebd8375..bbd85cfacf 100644 --- a/ibm/service/vpc/resource_ibm_is_bare_metal_server.go +++ b/ibm/service/vpc/resource_ibm_is_bare_metal_server.go @@ -247,10 +247,42 @@ func ResourceIBMIsBareMetalServer() *schema.Resource { 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, - Optional: true, Computed: true, - Description: "The globally unique IP address", + 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", }, }, }, @@ -348,6 +380,34 @@ func ResourceIBMIsBareMetalServer() *schema.Resource { Computed: true, Description: "The globally unique IP address", }, + isBareMetalServerNicIpHref: { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this reserved IP", + }, + isBareMetalServerNicIpAutoDelete: { + Type: schema.TypeString, + 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", + }, }, }, }, @@ -573,10 +633,35 @@ func resourceIBMISBareMetalServerCreate(context context.Context, d *schema.Resou if primaryIpIntf, ok := primnic[isBareMetalServerNicPrimaryIP]; ok && len(primaryIpIntf.([]interface{})) > 0 { primaryIp := primaryIpIntf.([]interface{})[0].(map[string]interface{}) - reservedIpAddressOk, ok := primaryIp[isBareMetalServerNicIpAddress] - if ok && reservedIpAddressOk.(string) != "" { - reservedIpAddress := reservedIpAddressOk.(string) - primnicobj.PrimaryIpv4Address = &reservedIpAddress + + 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 + } } } @@ -661,11 +746,35 @@ func resourceIBMISBareMetalServerCreate(context context.Context, d *schema.Resou if primaryIpIntf, ok := nic[isBareMetalServerNicPrimaryIP]; ok && len(primaryIpIntf.([]interface{})) > 0 { primaryIp := primaryIpIntf.([]interface{})[0].(map[string]interface{}) - reservedIpAddressOk, ok := primaryIp[isBareMetalServerNicIpAddress] - if ok && reservedIpAddressOk.(string) != "" { - reservedIpAddress := reservedIpAddressOk.(string) - nicobj.PrimaryIpv4Address = &reservedIpAddress + + 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] @@ -720,10 +829,35 @@ func resourceIBMISBareMetalServerCreate(context context.Context, d *schema.Resou if primaryIpIntf, ok := nic[isBareMetalServerNicPrimaryIP]; ok && len(primaryIpIntf.([]interface{})) > 0 { primaryIp := primaryIpIntf.([]interface{})[0].(map[string]interface{}) - reservedIpAddressOk, ok := primaryIp[isBareMetalServerNicIpAddress] - if ok && reservedIpAddressOk.(string) != "" { - reservedIpAddress := reservedIpAddressOk.(string) - nicobj.PrimaryIpv4Address = &reservedIpAddress + 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 + } } } @@ -881,13 +1015,38 @@ func bareMetalServerGet(context context.Context, d *schema.ResourceData, meta in return fmt.Errorf("[ERROR] Error getting network interfaces attached to the bare metal server %s\n%s", err, response) } - primaryIpList := make([]map[string]interface{}, 0) - currentIP := map[string]interface{}{ - isBareMetalServerNicIpAddress: *bms.PrimaryNetworkInterface.PrimaryIpv4Address, - } - primaryIpList = append(primaryIpList, currentIP) - currentPrimNic[isBareMetalServerNicPrimaryIP] = primaryIpList + 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": { @@ -947,12 +1106,38 @@ func bareMetalServerGet(context context.Context, d *schema.ResourceData, meta in if err != nil { return fmt.Errorf("[ERROR] Error getting network interfaces attached to the bare metal server %s\n%s", err, response) } - primaryIpList := make([]map[string]interface{}, 0) - currentIP := map[string]interface{}{ - isBareMetalServerNicIpAddress: *intfc.PrimaryIpv4Address, + 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 + } + 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 network interface(%s): %s\n%s", *bms.PrimaryNetworkInterface.PrimaryIP.ID, *bms.PrimaryNetworkInterface.ID, err, response) + } + currentIP[isBareMetalServerNicIpAutoDelete] = bmsRip.AutoDelete + + primaryIpList = append(primaryIpList, currentIP) + currentNic[isBareMetalServerNicPrimaryIP] = primaryIpList } - primaryIpList = append(primaryIpList, currentIP) - currentNic[isBareMetalServerNicPrimaryIP] = primaryIpList + switch reflect.TypeOf(bmsnicintf).String() { case "*vpcv1.BareMetalServerNetworkInterfaceByPci": { @@ -1074,6 +1259,33 @@ func bareMetalServerUpdate(context context.Context, d *schema.ResourceData, meta 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, 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 index 9c2d41c96a..37fba71487 100644 --- 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 @@ -118,14 +118,16 @@ func ResourceIBMIsBareMetalServerNetworkInterface() *schema.Resource { 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, - Description: "The globally unique IP address", + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"primary_ip.0.reserved_ip"}, + Description: "The globally unique IP address", }, isBareMetalServerNicIpHref: { Type: schema.TypeString, @@ -133,16 +135,18 @@ func ResourceIBMIsBareMetalServerNetworkInterface() *schema.Resource { Description: "The URL for this reserved IP", }, isBareMetalServerNicIpID: { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "The unique identifier for this reserved IP", + 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, - Description: "The unique user-defined name for this reserved IP", + 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, @@ -150,10 +154,11 @@ func ResourceIBMIsBareMetalServerNetworkInterface() *schema.Resource { Description: "The resource type: [ subnet_reserved_ip ]", }, isBareMetalServerNicIpAutoDelete: { - Type: schema.TypeBool, - Optional: true, - Computed: true, - Description: "If set to true, this reserved IP will be automatically deleted when the target is deleted or when the reserved IP is unbound.", + 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.", }, }, }, @@ -331,11 +336,35 @@ func resourceIBMISBareMetalServerNetworkInterfaceCreate(context context.Context, if primaryIpIntf, ok := d.GetOk(isBareMetalServerNicPrimaryIP); ok && len(primaryIpIntf.([]interface{})) > 0 { primaryIp := primaryIpIntf.([]interface{})[0].(map[string]interface{}) - reservedIpAddressOk, ok := primaryIp[isBareMetalServerNicIpAddress] - if ok && reservedIpAddressOk.(string) != "" { - reservedIpAddress := reservedIpAddressOk.(string) - nicOptions.PrimaryIpv4Address = &reservedIpAddress + 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() @@ -355,7 +384,7 @@ func resourceIBMISBareMetalServerNetworkInterfaceCreate(context context.Context, 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)) } - err = bareMetalServerNICGet(d, meta, nic, bareMetalServerId) + err = bareMetalServerNICGet(d, meta, sess, nic, bareMetalServerId) if err != nil { return diag.FromErr(err) } @@ -437,11 +466,35 @@ func createVlanTypeNetworkInterface(context context.Context, d *schema.ResourceD if primaryIpIntf, ok := d.GetOk(isBareMetalServerNicPrimaryIP); ok && len(primaryIpIntf.([]interface{})) > 0 { primaryIp := primaryIpIntf.([]interface{})[0].(map[string]interface{}) - reservedIpAddressOk, ok := primaryIp[isBareMetalServerNicIpAddress] - if ok && reservedIpAddressOk.(string) != "" { - reservedIpAddress := reservedIpAddressOk.(string) - nicOptions.PrimaryIpv4Address = &reservedIpAddress + 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() @@ -461,7 +514,7 @@ func createVlanTypeNetworkInterface(context context.Context, d *schema.ResourceD if err != nil || nic == nil { return fmt.Errorf("[DEBUG] Create bare metal server (%s) network interface err %s\n%s", bareMetalServerId, err, response) } - err = bareMetalServerNICGet(d, meta, nic, bareMetalServerId) + err = bareMetalServerNICGet(d, meta, sess, nic, bareMetalServerId) if err != nil { return err } @@ -499,14 +552,14 @@ func resourceIBMISBareMetalServerNetworkInterfaceRead(context context.Context, d } 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, nicIntf, bareMetalServerId) + err = bareMetalServerNICGet(d, meta, sess, nicIntf, bareMetalServerId) if err != nil { return diag.FromErr(err) } return nil } -func bareMetalServerNICGet(d *schema.ResourceData, meta interface{}, nicIntf interface{}, bareMetalServerId string) error { +func bareMetalServerNICGet(d *schema.ResourceData, meta interface{}, sess *vpcv1.VpcV1, nicIntf interface{}, bareMetalServerId string) error { switch reflect.TypeOf(nicIntf).String() { case "*vpcv1.BareMetalServerNetworkInterfaceByPci": { @@ -537,14 +590,37 @@ func bareMetalServerNICGet(d *schema.ResourceData, meta interface{}, nicIntf int if nic.PortSpeed != nil { d.Set(isBareMetalServerNicPortSpeed, *nic.PortSpeed) } - primaryIpList := make([]map[string]interface{}, 0) - currentIP := map[string]interface{}{ + 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) - isBareMetalServerNicIpAddress: *nic.PrimaryIpv4Address, + d.Set(isBareMetalServerNicPrimaryIP, primaryIpList) } - primaryIpList = append(primaryIpList, currentIP) - d.Set(isBareMetalServerNicPrimaryIP, primaryIpList) - d.Set(isBareMetalServerNicResourceType, *nic.ResourceType) if nic.SecurityGroups != nil && len(nic.SecurityGroups) != 0 { @@ -594,10 +670,32 @@ func bareMetalServerNICGet(d *schema.ResourceData, meta interface{}, nicIntf int d.Set(isBareMetalServerNicPortSpeed, nic.PortSpeed) primaryIpList := make([]map[string]interface{}, 0) - currentIP := map[string]interface{}{ - - isBareMetalServerNicIpAddress: *nic.PrimaryIpv4Address, + 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) @@ -636,12 +734,40 @@ func resourceIBMISBareMetalServerNetworkInterfaceUpdate(context context.Context, 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(isBareMetalServerNicEnableInfraNAT); ok { + if ais, ok := d.GetOk(isBareMetalServerNicAllowIPSpoofing); ok { aisBool = ais.(bool) } nicPatchModel.AllowIPSpoofing = &aisBool @@ -686,7 +812,7 @@ func resourceIBMISBareMetalServerNetworkInterfaceUpdate(context context.Context, 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, nicIntf, bareMetalServerId)) + return diag.FromErr(bareMetalServerNICGet(d, meta, sess, nicIntf, bareMetalServerId)) } return 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 index 2d2aabc2e1..4806ec803c 100644 --- 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 @@ -100,14 +100,47 @@ func ResourceIBMIsBareMetalServerNetworkInterfaceAllowFloat() *schema.Resource { 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, - Optional: true, Computed: true, - Description: "The globally unique IP address", + 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", }, }, }, @@ -146,8 +179,7 @@ func ResourceIBMIsBareMetalServerNetworkInterfaceAllowFloat() *schema.Resource { }, isBareMetalServerNicVlan: { Type: schema.TypeInt, - Optional: true, - Computed: true, + Required: true, Description: "Indicates the 802.1Q VLAN ID tag that must be used for all traffic on this interface", }, isBareMetalServerNicAllowInterfaceToFloat: { @@ -214,10 +246,34 @@ func createVlanTypeNetworkInterfaceAllowFloat(context context.Context, d *schema if primaryIpIntf, ok := d.GetOk(isBareMetalServerNicPrimaryIP); ok && len(primaryIpIntf.([]interface{})) > 0 { primaryIp := primaryIpIntf.([]interface{})[0].(map[string]interface{}) - reservedIpAddressOk, ok := primaryIp[isBareMetalServerNicIpAddress] - if ok && reservedIpAddressOk.(string) != "" { - reservedIpAddress := reservedIpAddressOk.(string) - nicOptions.PrimaryIpv4Address = &reservedIpAddress + 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 + } } } @@ -238,7 +294,7 @@ func createVlanTypeNetworkInterfaceAllowFloat(context context.Context, d *schema if err != nil || nic == nil { return fmt.Errorf("[DEBUG] Create bare metal server (%s) network interface err %s\n%s", bareMetalServerId, err, response) } - err = bareMetalServerNICGet(d, meta, nic, bareMetalServerId) + err = bareMetalServerNICAllowFloatGet(d, meta, sess, nic, bareMetalServerId) if err != nil { return err } @@ -287,7 +343,7 @@ func resourceIBMISBareMetalServerNetworkInterfaceAllowFloatRead(context context. } } } - err = bareMetalServerNICAllowFloatGet(d, meta, nicIntf, bareMetalServerId) + err = bareMetalServerNICAllowFloatGet(d, meta, sess, nicIntf, bareMetalServerId) if err != nil { return diag.FromErr(err) } @@ -331,7 +387,7 @@ func findNicsWithoutBMS(context context.Context, sess *vpcv1.VpcV1, nicId string return nil, nil, fmt.Errorf("[ERROR] Error Network interface not found") } -func bareMetalServerNICAllowFloatGet(d *schema.ResourceData, meta interface{}, nicIntf interface{}, bareMetalServerId string) error { +func bareMetalServerNICAllowFloatGet(d *schema.ResourceData, meta interface{}, sess *vpcv1.VpcV1, nicIntf interface{}, bareMetalServerId string) error { switch reflect.TypeOf(nicIntf).String() { case "*vpcv1.BareMetalServerNetworkInterfaceByPci": { @@ -363,10 +419,33 @@ func bareMetalServerNICAllowFloatGet(d *schema.ResourceData, meta interface{}, n d.Set(isBareMetalServerNicPortSpeed, *nic.PortSpeed) } primaryIpList := make([]map[string]interface{}, 0) - currentIP := map[string]interface{}{ + 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 + } - isBareMetalServerNicIpAddress: *nic.PrimaryIpv4Address, + 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) @@ -412,9 +491,21 @@ func bareMetalServerNICAllowFloatGet(d *schema.ResourceData, meta interface{}, n d.Set(isBareMetalServerNicPortSpeed, nic.PortSpeed) primaryIpList := make([]map[string]interface{}, 0) - currentIP := map[string]interface{}{ - - isBareMetalServerNicIpAddress: *nic.PrimaryIpv4Address, + 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) @@ -450,6 +541,33 @@ func resourceIBMISBareMetalServerNetworkInterfaceAllowFloatUpdate(context contex 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, @@ -459,7 +577,7 @@ func resourceIBMISBareMetalServerNetworkInterfaceAllowFloatUpdate(context contex if d.HasChange(isBareMetalServerNicAllowIPSpoofing) { flag = true aisBool := false - if ais, ok := d.GetOk(isBareMetalServerNicEnableInfraNAT); ok { + if ais, ok := d.GetOk(isBareMetalServerNicAllowIPSpoofing); ok { aisBool = ais.(bool) } nicPatchModel.AllowIPSpoofing = &aisBool @@ -492,7 +610,7 @@ func resourceIBMISBareMetalServerNetworkInterfaceAllowFloatUpdate(context contex 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, nicIntf, bareMetalServerId)) + return diag.FromErr(bareMetalServerNICAllowFloatGet(d, meta, sess, nicIntf, bareMetalServerId)) } 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 index 4593255da7..f25fe97db7 100644 --- 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 @@ -20,6 +20,35 @@ import ( ) 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)) + 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), + ), + }, + }, + }) +} +func TestAccIBMISBareMetalServerNetworkInterfaceAllowFloat_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)) @@ -131,3 +160,52 @@ func testAccCheckIBMISBareMetalServerNetworkInterfaceAllowFloatConfig(vpcname, s `, 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_test.go b/ibm/service/vpc/resource_ibm_is_bare_metal_server_network_interface_test.go index 9dd8a63ce8..dd7091c99f 100644 --- 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 @@ -47,6 +47,35 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }, }) } +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 { @@ -153,3 +182,50 @@ func testAccCheckIBMISBareMetalServerNetworkInterfaceConfig(vpcname, subnetname, `, 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 index b72122e82d..8bdf640a5c 100644 --- a/ibm/service/vpc/resource_ibm_is_bare_metal_server_test.go +++ b/ibm/service/vpc/resource_ibm_is_bare_metal_server_test.go @@ -46,6 +46,34 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }, }) } +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 { @@ -122,3 +150,38 @@ func testAccCheckIBMISBareMetalServerConfig(vpcname, subnetname, sshname, public } `, 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/service/vpc/resource_ibm_is_floating_ip.go b/ibm/service/vpc/resource_ibm_is_floating_ip.go index 1de8cb4427..1824328f7e 100644 --- a/ibm/service/vpc/resource_ibm_is_floating_ip.go +++ b/ibm/service/vpc/resource_ibm_is_floating_ip.go @@ -8,6 +8,7 @@ import ( "fmt" "log" "os" + "reflect" "time" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" @@ -116,6 +117,88 @@ func ResourceIBMISFloatingIP() *schema.Resource { ConflictsWith: []string{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, @@ -307,12 +390,15 @@ func fipGet(d *schema.ResourceData, meta interface{}, id string) error { 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) + targetId, targetMap := floatingIPCollectionFloatingIpTargetToMap(floatingip.Target) + if targetId != "" { + d.Set(isFloatingIPTarget, targetId) } else { d.Set(isFloatingIPTarget, "") } + targetList := []map[string]interface{}{} + targetList = append(targetList, targetMap) + d.Set(floatingIPTargets, targetList) tags, err := flex.GetTagsUsingCRN(meta, *floatingip.CRN) if err != nil { log.Printf( @@ -570,3 +656,148 @@ func checkIfZoneChanged(oldNic, newNic, currentZone string, floatingipC *vpcv1.V } return false } + +func floatingIPCollectionFloatingIpTargetToMap(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 := 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 index c714285e99..7e3fca9fc0 100644 --- a/ibm/service/vpc/resource_ibm_is_floating_ip_test.go +++ b/ibm/service/vpc/resource_ibm_is_floating_ip_test.go @@ -46,6 +46,11 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE "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"), ), }, { @@ -58,6 +63,11 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE "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"), ), }, }, diff --git a/ibm/service/vpc/resource_ibm_is_flow_log.go b/ibm/service/vpc/resource_ibm_is_flow_log.go index e8b67fb509..fcd794b1a6 100644 --- a/ibm/service/vpc/resource_ibm_is_flow_log.go +++ b/ibm/service/vpc/resource_ibm_is_flow_log.go @@ -225,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 diff --git a/ibm/service/vpc/resource_ibm_is_instance.go b/ibm/service/vpc/resource_ibm_is_instance.go index 576d35ac4d..a36b34317b 100644 --- a/ibm/service/vpc/resource_ibm_is_instance.go +++ b/ibm/service/vpc/resource_ibm_is_instance.go @@ -370,10 +370,62 @@ func ResourceIBMISInstance() *schema.Resource { Deprecated: "This field is deprected", }, isInstanceNicPrimaryIpv4Address: { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - Computed: true, + 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, @@ -413,10 +465,58 @@ func ResourceIBMISInstance() *schema.Resource { Computed: true, }, isInstanceNicPrimaryIpv4Address: { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - Computed: true, + 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, @@ -924,11 +1024,59 @@ func instanceCreateByImage(d *schema.ResourceData, meta interface{}, profile, na if namestr != "" { primnicobj.Name = &namestr } + + // reserved ip changes + + var ipv4str, reservedIp, reservedipv4, reservedipname string + var autodelete, okAuto bool ipv4, _ := primnic[isInstanceNicPrimaryIpv4Address] - ipv4str := ipv4.(string) - if ipv4str != "" { - primnicobj.PrimaryIpv4Address = &ipv4str + 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 { @@ -967,10 +1115,57 @@ func instanceCreateByImage(d *schema.ResourceData, meta interface{}, profile, na 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) - if ipv4str != "" { - nwInterface.PrimaryIpv4Address = &ipv4str + 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) @@ -1183,10 +1378,57 @@ func instanceCreateByTemplate(d *schema.ResourceData, meta interface{}, profile, if namestr != "" { primnicobj.Name = &namestr } + + // reserved ip changes + + var ipv4str, reservedIp, reservedipv4, reservedipname string + var autodelete, okAuto bool ipv4, _ := primnic[isInstanceNicPrimaryIpv4Address] - ipv4str := ipv4.(string) - if ipv4str != "" { - primnicobj.PrimaryIpv4Address = &ipv4str + 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) @@ -1226,10 +1468,57 @@ func instanceCreateByTemplate(d *schema.ResourceData, meta interface{}, profile, 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) - if ipv4str != "" { - nwInterface.PrimaryIpv4Address = &ipv4str + 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) @@ -1327,7 +1616,7 @@ func instanceCreateByVolume(d *schema.ResourceData, meta interface{}, profile, n if err != nil { return err } - instanceproto := &vpcv1.InstancePrototypeInstanceByVolume{ + instanceproto := &vpcv1.InstancePrototypeInstanceBySourceSnapshot{ Zone: &vpcv1.ZoneIdentity{ Name: &zone, }, @@ -1381,7 +1670,7 @@ func instanceCreateByVolume(d *schema.ResourceData, meta interface{}, profile, n if boot, ok := d.GetOk(isInstanceBootVolume); ok { bootvol := boot.([]interface{})[0].(map[string]interface{}) - var volTemplate = &vpcv1.VolumeAttachmentVolumePrototypeInstanceByVolumeContext{} + var volTemplate = &vpcv1.VolumePrototypeInstanceBySourceSnapshotContext{} name, ok := bootvol[isInstanceBootAttachmentName] namestr := name.(string) @@ -1414,7 +1703,7 @@ func instanceCreateByVolume(d *schema.ResourceData, meta interface{}, profile, n } } deletebool := true - instanceproto.BootVolumeAttachment = &vpcv1.VolumeAttachmentPrototypeInstanceByVolumeContext{ + instanceproto.BootVolumeAttachment = &vpcv1.VolumeAttachmentPrototypeInstanceBySourceSnapshotContext{ DeleteVolumeOnInstanceDelete: &deletebool, Volume: volTemplate, } @@ -1437,11 +1726,59 @@ func instanceCreateByVolume(d *schema.ResourceData, meta interface{}, profile, n if namestr != "" { primnicobj.Name = &namestr } + + // reserved ip changes + + var ipv4str, reservedIp, reservedipv4, reservedipname string + var autodelete, okAuto bool ipv4, _ := primnic[isInstanceNicPrimaryIpv4Address] - ipv4str := ipv4.(string) - if ipv4str != "" { - primnicobj.PrimaryIpv4Address = &ipv4str + 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 { @@ -1480,10 +1817,56 @@ func instanceCreateByVolume(d *schema.ResourceData, meta interface{}, profile, n 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) - if ipv4str != "" { - nwInterface.PrimaryIpv4Address = &ipv4str + 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) @@ -1653,11 +2036,26 @@ func isInstanceRefreshFunc(instanceC *vpcv1.VpcV1, id string, d *schema.Resource // 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 + statusReasonsList = append(statusReasonsList, currentSR) + } + } + d.Set(isInstanceStatusReasons, statusReasonsList) + } + out, err := json.MarshalIndent(instanceStatusReason, "", " ") if err != nil { - 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, 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("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, 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 @@ -1790,7 +2188,39 @@ func instanceGet(d *schema.ResourceData, meta interface{}, id string) error { currentPrimNic := map[string]interface{}{} currentPrimNic["id"] = *instance.PrimaryNetworkInterface.ID currentPrimNic[isInstanceNicName] = *instance.PrimaryNetworkInterface.Name - currentPrimNic[isInstanceNicPrimaryIpv4Address] = *instance.PrimaryNetworkInterface.PrimaryIpv4Address + + //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, @@ -1823,7 +2253,41 @@ func instanceGet(d *schema.ResourceData, meta interface{}, id string) error { currentNic := map[string]interface{}{} currentNic["id"] = *intfc.ID currentNic[isInstanceNicName] = *intfc.Name - currentNic[isInstanceNicPrimaryIpv4Address] = *intfc.PrimaryIpv4Address + + // 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, @@ -2151,6 +2615,33 @@ func instanceUpdate(d *schema.ResourceData, meta interface{}) error { } } + 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(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 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) @@ -2186,6 +2677,36 @@ func instanceUpdate(d *schema.ResourceData, meta interface{}) error { 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) + 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 := 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) diff --git a/ibm/service/vpc/resource_ibm_is_instance_network_interface.go b/ibm/service/vpc/resource_ibm_is_instance_network_interface.go index f04e65943f..a79ea7b3ef 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_network_interface.go +++ b/ibm/service/vpc/resource_ibm_is_instance_network_interface.go @@ -62,12 +62,65 @@ func ResourceIBMIsInstanceNetworkInterface() *schema.Resource { 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, - 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.", + 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, @@ -216,8 +269,58 @@ func resourceIBMIsInstanceNetworkInterfaceCreate(context context.Context, d *sch if name, ok := d.GetOk(isInstanceNicName); ok { createInstanceNetworkInterfaceOptions.SetName(name.(string)) } - if primary_ipv4, ok := d.GetOk(isInstanceNicPrimaryIpv4Address); ok { - createInstanceNetworkInterfaceOptions.SetPrimaryIpv4Address(primary_ipv4.(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 { @@ -318,8 +421,41 @@ func resourceIBMIsInstanceNetworkInterfaceRead(context context.Context, d *schem if err = d.Set(isInstanceNicName, *networkInterface.Name); err != nil { return diag.FromErr(fmt.Errorf("[ERROR] Error setting name: %s", err)) } - if err = d.Set(isInstanceNicPrimaryIpv4Address, *networkInterface.PrimaryIpv4Address); err != nil { - return diag.FromErr(fmt.Errorf("[ERROR] Error setting primary_ipv4_address: %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{} @@ -415,6 +551,33 @@ func resourceIBMIsInstanceNetworkInterfaceUpdate(context context.Context, d *sch patchVals.Name = core.StringPtr(d.Get(isInstanceNicName).(string)) hasChange = true } + 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(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) 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 index 949df220bb..b61b3dd53a 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_network_interface_test.go +++ b/ibm/service/vpc/resource_ibm_is_instance_network_interface_test.go @@ -64,6 +64,41 @@ func TestAccIBMIsInstanceNetworkInterfaceAllArgs(t *testing.T) { }, }) } +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(` @@ -109,6 +144,52 @@ func testAccCheckIBMIsInstanceNetworkInterfaceConfig(vpcname, subnetname, sshnam } `, 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 { diff --git a/ibm/service/vpc/resource_ibm_is_instance_template.go b/ibm/service/vpc/resource_ibm_is_instance_template.go index 85434d0258..836d7860a9 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_template.go +++ b/ibm/service/vpc/resource_ibm_is_instance_template.go @@ -6,6 +6,7 @@ package vpc import ( "context" "fmt" + "log" "reflect" "strings" @@ -52,6 +53,11 @@ const ( 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 { @@ -259,9 +265,52 @@ func ResourceIBMISInstanceTemplate() *schema.Resource { Computed: true, }, isInstanceTemplateNicPrimaryIpv4Address: { - Type: schema.TypeString, - Optional: true, - Computed: true, + 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, @@ -295,9 +344,49 @@ func ResourceIBMISInstanceTemplate() *schema.Resource { Computed: true, }, isInstanceTemplateNicPrimaryIpv4Address: { - Type: schema.TypeString, - Optional: true, - Computed: true, + 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, @@ -695,13 +784,53 @@ func instanceTemplateCreate(d *schema.ResourceData, meta interface{}, profile, n primnicobj.SecurityGroups = secgrpobjs } } - instanceproto.PrimaryNetworkInterface = primnicobj - + // reserved ip changes + var PrimaryIpv4Address, reservedIp, reservedIpAddress, reservedIpName string + var reservedIpAutoDelete, okAuto bool if IPAddress, ok := primnic[isInstanceTemplateNicPrimaryIpv4Address]; ok { - if PrimaryIpv4Address := IPAddress.(string); PrimaryIpv4Address != "" { - primnicobj.PrimaryIpv4Address = &PrimaryIpv4Address + 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 @@ -741,9 +870,60 @@ func instanceTemplateCreate(d *schema.ResourceData, meta interface{}, profile, n nwInterface.SecurityGroups = secgrpobjs } } + // reserved ip changes + var PrimaryIpv4Address, reservedIp, reservedIpAddress, reservedIpName string + var reservedIpAutoDelete, okAuto bool if IPAddress, ok := nic[isInstanceTemplateNicPrimaryIpv4Address]; ok { - if PrimaryIpv4Address := IPAddress.(string); PrimaryIpv4Address != "" { - nwInterface.PrimaryIpv4Address = &PrimaryIpv4Address + 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) @@ -855,8 +1035,37 @@ func instanceTemplateGet(d *schema.ResourceData, meta interface{}, ID string) er 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 + 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) @@ -882,8 +1091,37 @@ func instanceTemplateGet(d *schema.ResourceData, meta interface{}, ID string) er for _, intfc := range instance.NetworkInterfaces { currentNic := map[string]interface{}{} currentNic[isInstanceTemplateNicName] = *intfc.Name - if intfc.PrimaryIpv4Address != nil { - currentNic[isInstanceTemplateNicPrimaryIpv4Address] = *intfc.PrimaryIpv4Address + 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 diff --git a/ibm/service/vpc/resource_ibm_is_instance_template_test.go b/ibm/service/vpc/resource_ibm_is_instance_template_test.go index d20f5e2875..d015c0f422 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_template_test.go +++ b/ibm/service/vpc/resource_ibm_is_instance_template_test.go @@ -44,6 +44,35 @@ func TestAccIBMISInstanceTemplate_basic(t *testing.T) { }, }) } +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) @@ -189,6 +218,52 @@ func testAccCheckIBMISInstanceTemplateConfig(vpcName, subnetName, sshKeyName, pu `, 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 { diff --git a/ibm/service/vpc/resource_ibm_is_instance_test.go b/ibm/service/vpc/resource_ibm_is_instance_test.go index 801d5e03f5..e9f6ee4fba 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_test.go +++ b/ibm/service/vpc/resource_ibm_is_instance_test.go @@ -65,6 +65,38 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }, }) } +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 @@ -799,6 +831,45 @@ func testAccCheckIBMISInstanceConfig(vpcname, subnetname, sshname, publicKey, na } }`, 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(` diff --git a/ibm/service/vpc/resource_ibm_is_lb.go b/ibm/service/vpc/resource_ibm_is_lb.go index 6f1380a6e6..6482f58f13 100644 --- a/ibm/service/vpc/resource_ibm_is_lb.go +++ b/ibm/service/vpc/resource_ibm_is_lb.go @@ -116,7 +116,40 @@ func ResourceIBMISLB() *schema.Resource { 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, @@ -423,15 +456,35 @@ func lbGet(d *schema.ResourceData, meta interface{}, id string) error { } 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 { diff --git a/ibm/service/vpc/resource_ibm_is_lb_test.go b/ibm/service/vpc/resource_ibm_is_lb_test.go index 7464594a49..7954ccd2e9 100644 --- a/ibm/service/vpc/resource_ibm_is_lb_test.go +++ b/ibm/service/vpc/resource_ibm_is_lb_test.go @@ -51,6 +51,50 @@ func TestAccIBMISLB_basic(t *testing.T) { }, }) } +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 diff --git a/ibm/service/vpc/resource_ibm_is_security_group_network_interface_attachment.go b/ibm/service/vpc/resource_ibm_is_security_group_network_interface_attachment.go index 0878e27258..3089ef35d3 100644 --- a/ibm/service/vpc/resource_ibm_is_security_group_network_interface_attachment.go +++ b/ibm/service/vpc/resource_ibm_is_security_group_network_interface_attachment.go @@ -214,7 +214,9 @@ func resourceIBMISSecurityGroupNetworkInterfaceAttachmentRead(d *schema.Resource 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 { diff --git a/ibm/service/vpc/resource_ibm_is_security_group_network_interface_attachment_test.go b/ibm/service/vpc/resource_ibm_is_security_group_network_interface_attachment_test.go index 0c71040290..e7edc37345 100644 --- a/ibm/service/vpc/resource_ibm_is_security_group_network_interface_attachment_test.go +++ b/ibm/service/vpc/resource_ibm_is_security_group_network_interface_attachment_test.go @@ -61,11 +61,11 @@ func testAccCheckIBMISSecurityGroupNwInterfaceAttachmentDestroy(s *terraform.Sta 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) } diff --git a/ibm/service/vpc/resource_ibm_is_subnet_reserved_ip.go b/ibm/service/vpc/resource_ibm_is_subnet_reserved_ip.go index 5104dc356b..b520acbd1c 100644 --- a/ibm/service/vpc/resource_ibm_is_subnet_reserved_ip.go +++ b/ibm/service/vpc/resource_ibm_is_subnet_reserved_ip.go @@ -5,12 +5,14 @@ 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/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" ) @@ -19,6 +21,7 @@ const ( isReservedIPProvisioningDone = "done" isReservedIP = "reserved_ip" isReservedIPTarget = "target" + isReservedIPLifecycleState = "lifecycle_state" ) func ResourceIBMISReservedIP() *schema.Resource { @@ -65,6 +68,11 @@ func ResourceIBMISReservedIP() *schema.Resource { Optional: true, Description: "The unique identifier for target.", }, + isReservedIPLifecycleState: { + Type: schema.TypeString, + Computed: true, + Description: "The lifecycle state of the reserved IP", + }, /* Response Parameters =================== @@ -74,8 +82,10 @@ func ResourceIBMISReservedIP() *schema.Resource { isReservedIPAddress: { Type: schema.TypeString, + Optional: true, + ForceNew: true, Computed: true, - Description: "The user-defined or system-provided name for this reserved IP.", + Description: "The address for this reserved IP.", }, isReservedIP: { Type: schema.TypeString, @@ -139,6 +149,13 @@ func resourceIBMISReservedIPCreate(d *schema.ResourceData, meta interface{}) err 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 @@ -155,6 +172,10 @@ func resourceIBMISReservedIPCreate(d *schema.ResourceData, meta interface{}) err // 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) } @@ -175,6 +196,9 @@ func resourceIBMISReservedIPRead(d *schema.ResourceData, meta interface{}) error 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) @@ -303,3 +327,41 @@ func get(d *schema.ResourceData, meta interface{}) (*vpcv1.ReservedIP, error) { } 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_vpn_gateway.go b/ibm/service/vpc/resource_ibm_is_vpn_gateway.go index ab2a9f0360..295d64d515 100644 --- a/ibm/service/vpc/resource_ibm_is_vpn_gateway.go +++ b/ibm/service/vpc/resource_ibm_is_vpn_gateway.go @@ -417,7 +417,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 } } diff --git a/website/docs/d/is_bare_metal_server.markdown b/website/docs/d/is_bare_metal_server.markdown index d481419048..317adb7da1 100644 --- a/website/docs/d/is_bare_metal_server.markdown +++ b/website/docs/d/is_bare_metal_server.markdown @@ -84,6 +84,10 @@ In addition to all argument reference list, you can access the following attribu 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. @@ -97,6 +101,10 @@ In addition to all argument reference list, you can access the following attribu 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 diff --git a/website/docs/d/is_bare_metal_server_network_interface.markdown b/website/docs/d/is_bare_metal_server_network_interface.markdown index 853f2470f8..bb84c340d4 100644 --- a/website/docs/d/is_bare_metal_server_network_interface.markdown +++ b/website/docs/d/is_bare_metal_server_network_interface.markdown @@ -53,12 +53,9 @@ In addition to the argument reference list, you can access the following attribu - `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 - - - `id` - (String) The unique identifier 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** ] + - `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 diff --git a/website/docs/d/is_bare_metal_server_network_interfaces.markdown b/website/docs/d/is_bare_metal_server_network_interfaces.markdown index 9cb08a4d55..0d9b924eb7 100644 --- a/website/docs/d/is_bare_metal_server_network_interfaces.markdown +++ b/website/docs/d/is_bare_metal_server_network_interfaces.markdown @@ -56,12 +56,10 @@ In addition to the argument reference list, you can access the following attribu - `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 - - - `id` - (String) The unique identifier 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** ] - - `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 diff --git a/website/docs/d/is_bare_metal_servers.markdown b/website/docs/d/is_bare_metal_servers.markdown index eae85a57c8..4803333a61 100644 --- a/website/docs/d/is_bare_metal_servers.markdown +++ b/website/docs/d/is_bare_metal_servers.markdown @@ -66,6 +66,11 @@ Review the attribute references that you can access after you retrieve your data - `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. @@ -77,6 +82,11 @@ Review the attribute references that you can access after you retrieve your data - `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 diff --git a/website/docs/d/is_floating_ip.html.markdown b/website/docs/d/is_floating_ip.html.markdown index 456f203f18..5886bfa9e1 100644 --- a/website/docs/d/is_floating_ip.html.markdown +++ b/website/docs/d/is_floating_ip.html.markdown @@ -40,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 index 28a39b39a3..44fa1a8a9e 100644 --- a/website/docs/d/is_floating_ips.html.markdown +++ b/website/docs/d/is_floating_ips.html.markdown @@ -67,11 +67,18 @@ In addition to all argument references listed, you can access the following attr - `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_ipv4_address` - (String) The primary IPv4 address. If the address has not yet been selected, the value will be `0.0.0.0`. + - `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. + - `href` - (String) The URL for this zone. - `name` - (String) The globally unique name for this zone. - diff --git a/website/docs/d/is_instance.html.markdown b/website/docs/d/is_instance.html.markdown index 1b07ca67f1..3da9796633 100644 --- a/website/docs/d/is_instance.html.markdown +++ b/website/docs/d/is_instance.html.markdown @@ -126,7 +126,15 @@ In addition to all argument reference list, you can access the following attribu 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. 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 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. @@ -145,7 +153,15 @@ 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. 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 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. diff --git a/website/docs/d/is_instance_network_interface.html.markdown b/website/docs/d/is_instance_network_interface.html.markdown index ee22659835..bb2de919f6 100644 --- a/website/docs/d/is_instance_network_interface.html.markdown +++ b/website/docs/d/is_instance_network_interface.html.markdown @@ -105,7 +105,16 @@ In addition to all arguments above, the following attributes are exported: - `port_speed` - (Integer) The network interface port speed in Mbps. -- `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`: + - `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. Same as `primary_ip.0.address` - `resource_type` - (String) The resource type. 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 0000000000..ee4cc5b8a8 --- /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 0000000000..fb67e91234 --- /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 index 5abe22cf18..7a80709325 100644 --- a/website/docs/d/is_instance_network_interfaces.html.markdown +++ b/website/docs/d/is_instance_network_interfaces.html.markdown @@ -93,7 +93,15 @@ In addition to all argument references listed, you can access the following attr - `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_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`: + - `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. Same as `primary_ip.0.address` - `resource_type` - (String) The resource type. - `security_groups` - (List) Collection of security groups. diff --git a/website/docs/d/is_instances.html.markdown b/website/docs/d/is_instances.html.markdown index 924bf506be..5fcb51714e 100644 --- a/website/docs/d/is_instances.html.markdown +++ b/website/docs/d/is_instances.html.markdown @@ -93,7 +93,15 @@ In addition to all argument reference list, you can access the following attribu 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. 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 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. @@ -113,7 +121,16 @@ 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. 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 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. @@ -137,4 +154,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_lb.html.markdown b/website/docs/d/is_lb.html.markdown index fa8de6c120..da49b63454 100644 --- a/website/docs/d/is_lb.html.markdown +++ b/website/docs/d/is_lb.html.markdown @@ -93,7 +93,15 @@ 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. +- `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 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. diff --git a/website/docs/d/is_lbs.html.markdown b/website/docs/d/is_lbs.html.markdown index acccf1a7b0..a7316b7ea4 100644 --- a/website/docs/d/is_lbs.html.markdown +++ b/website/docs/d/is_lbs.html.markdown @@ -64,7 +64,15 @@ 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. diff --git a/website/docs/d/is_subnet_reserved_ip.html.markdown b/website/docs/d/is_subnet_reserved_ip.html.markdown index 1a909c2c31..04b9914e9f 100644 --- a/website/docs/d/is_subnet_reserved_ip.html.markdown +++ b/website/docs/d/is_subnet_reserved_ip.html.markdown @@ -42,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) TThe 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 340fcc5263..f885f016bc 100644 --- a/website/docs/d/is_subnet_reserved_ips.html.markdown +++ b/website/docs/d/is_subnet_reserved_ips.html.markdown @@ -45,6 +45,7 @@ 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) TThe 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. diff --git a/website/docs/d/is_vpn_gateway.html.markdown b/website/docs/d/is_vpn_gateway.html.markdown index d729ff9bf0..666094a9db 100644 --- a/website/docs/d/is_vpn_gateway.html.markdown +++ b/website/docs/d/is_vpn_gateway.html.markdown @@ -53,7 +53,15 @@ In addition to all argument references listed, you can access the following attr - `members` - (List) Collection of VPN gateway members. Nested scheme for **members**: - - `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. + + - `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. diff --git a/website/docs/d/is_vpn_gateways.html.markdown b/website/docs/d/is_vpn_gateways.html.markdown index 555085c76f..b3452f9955 100644 --- a/website/docs/d/is_vpn_gateways.html.markdown +++ b/website/docs/d/is_vpn_gateways.html.markdown @@ -44,7 +44,14 @@ 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**. diff --git a/website/docs/r/is_bare_metal_server.markdown b/website/docs/r/is_bare_metal_server.markdown index 7d67ee3617..1cf20a8491 100644 --- a/website/docs/r/is_bare_metal_server.markdown +++ b/website/docs/r/is_bare_metal_server.markdown @@ -26,34 +26,72 @@ provider "ibm" { In the following example, you can create a Bare Metal Server: +### Basic Example Using AMI Lookup ```terraform -resource "ibm_is_vpc" "vpc" { - name = "testvpc" +resource "ibm_is_vpc" "example" { + name = "example-vpc" } -resource "ibm_is_subnet" "subnet" { - name = "testsubnet" +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" "ssh" { - 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_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_vpc" "example" { + name = "example-vpc" +} + +resource "ibm_is_subnet" "example" { + name = "example-subnet" + vpc = ibm_is_vpc.example.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" "bms" { profile = "mx2d-metal-32x192" - name = "my-bms" - image = "r134-31c8ca90-2623-48d7-8cf7-737be6fc4c3e" - zone = "us-south-3" - keys = [ibm_is_ssh_key.ssh.id] + 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.subnet.id + 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.vpc.id + vpc = ibm_is_vpc.example.id } ``` @@ -75,7 +113,7 @@ Review the argument references that you can specify for your resource. - `keys` - (Required, List) Comma separated IDs of ssh keys. - `name` - (Optional, String) The bare metal server name. - ~> **NOTE:** + -> **NOTE:** a bare metal server can take up to 30 mins to clean up on delete, replacement/re-creation using the same name will return error - `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. @@ -89,6 +127,9 @@ Review the argument references that you can specify for your resource. 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. @@ -128,6 +169,8 @@ In addition to all argument reference list, you can access the following attribu 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. diff --git a/website/docs/r/is_bare_metal_server_network_interface.markdown b/website/docs/r/is_bare_metal_server_network_interface.markdown index 02930e785f..b30ba37db8 100644 --- a/website/docs/r/is_bare_metal_server_network_interface.markdown +++ b/website/docs/r/is_bare_metal_server_network_interface.markdown @@ -92,6 +92,9 @@ Review the argument references that you can specify for your resource. - `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 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 index d2dac17a99..99c5c7a9f3 100644 --- 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 @@ -91,6 +91,9 @@ Review the argument references that you can specify for your resource. - `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 diff --git a/website/docs/r/is_floating_ip.html.markdown b/website/docs/r/is_floating_ip.html.markdown index 674c001b69..4628fed2bd 100644 --- a/website/docs/r/is_floating_ip.html.markdown +++ b/website/docs/r/is_floating_ip.html.markdown @@ -44,8 +44,8 @@ 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: @@ -59,12 +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. + ~> **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. @@ -73,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_instance.html.markdown b/website/docs/r/is_instance.html.markdown index 19026362da..c20cc59efd 100644 --- a/website/docs/r/is_instance.html.markdown +++ b/website/docs/r/is_instance.html.markdown @@ -307,6 +307,12 @@ Review the argument references that you can specify for your resource. `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_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. If the address has not yet been selected, the value will be 0.0.0.0. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `name`- (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 IPV4 address of the interface. - `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. @@ -320,7 +326,14 @@ Review the argument references that you can specify for your resource. `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. + - `port_speed` - (Deprecated, Integer) Speed 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`: + - `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. If the address has not yet been selected, the value will be 0.0.0.0. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `name`- (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. Use `primary_ip` 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, String) The name of the profile that you want to use for your instance. To list supported profiles, run `ibmcloud is instance-profiles`. diff --git a/website/docs/r/is_instance_network_interface.html.markdown b/website/docs/r/is_instance_network_interface.html.markdown index df5bde23b9..a0ad209f87 100644 --- a/website/docs/r/is_instance_network_interface.html.markdown +++ b/website/docs/r/is_instance_network_interface.html.markdown @@ -79,6 +79,12 @@ The following arguments are supported: - `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. If the address has not yet been selected, the value will be 0.0.0.0. This property may add support for IPv6 addresses in the future. When processing a value in this property, verify that the address is in an expected format. If it is not, log an error. Optionally halt processing and surface the error, or bypass the resource on which the unexpected IP address format was encountered. + - `name`- (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. diff --git a/website/docs/r/is_lb.html.markdown b/website/docs/r/is_lb.html.markdown index ef429f6bfc..e55285b66b 100644 --- a/website/docs/r/is_lb.html.markdown +++ b/website/docs/r/is_lb.html.markdown @@ -74,7 +74,15 @@ 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. diff --git a/website/docs/r/is_subnet_reserved_ip.html.markdown b/website/docs/r/is_subnet_reserved_ip.html.markdown index 8d4ece9f3c..0a153883fe 100644 --- a/website/docs/r/is_subnet_reserved_ip.html.markdown +++ b/website/docs/r/is_subnet_reserved_ip.html.markdown @@ -82,6 +82,7 @@ resource "ibm_is_subnet_reserved_ip" "example4" { ## Argument reference Review the argument references that you can specify for your resource. +- `address` - (Optional, 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- `. - `subnet` - (Required, Forces new resource, String) The subnet ID for the reserved IP. @@ -90,10 +91,10 @@ 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. -- `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 **/**. +- `lifecycle_state` - (String) TThe 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. diff --git a/website/docs/r/is_virtual_endpoint_gateway.html.markdown b/website/docs/r/is_virtual_endpoint_gateway.html.markdown index 7e75b660f3..f76acaf543 100644 --- a/website/docs/r/is_virtual_endpoint_gateway.html.markdown +++ b/website/docs/r/is_virtual_endpoint_gateway.html.markdown @@ -117,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.