diff --git a/go.mod b/go.mod index db6bae49d6..f8dabc34b8 100644 --- a/go.mod +++ b/go.mod @@ -38,7 +38,7 @@ require ( github.com/IBM/secrets-manager-go-sdk/v2 v2.0.11 github.com/IBM/vmware-go-sdk v0.1.3 github.com/IBM/vpc-beta-go-sdk v0.8.0 - github.com/IBM/vpc-go-sdk v0.67.1 + github.com/IBM/vpc-go-sdk v0.70.1 github.com/ScaleFT/sshkeys v0.0.0-20200327173127-6142f742bca5 github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 github.com/akamai/AkamaiOPEN-edgegrid-golang/v5 v5.0.0 diff --git a/go.sum b/go.sum index b0631c2fae..c65ccac5d5 100644 --- a/go.sum +++ b/go.sum @@ -167,8 +167,8 @@ github.com/IBM/vmware-go-sdk v0.1.3 h1:uJL3kwzM0jAKsT6Gj9tE5xT9SZBVXVaJvZdxrSMx8 github.com/IBM/vmware-go-sdk v0.1.3/go.mod h1:OyQKRInGGsBaOyE5LIZCqH7b1DZ01BvIYa8BgGy+wWo= github.com/IBM/vpc-beta-go-sdk v0.8.0 h1:cEPpv4iw3Ba5W2d0AWg3TIbKeJ8y1nPuUuibR5Jt9eE= github.com/IBM/vpc-beta-go-sdk v0.8.0/go.mod h1:hORgIyTFRzXrZIK9IohaWmCRBBlYiDRagsufi7M6akE= -github.com/IBM/vpc-go-sdk v0.67.1 h1:z0q1af1iItV4kHgreM21vzZtw6XQ13og2GBkX7WCJ8c= -github.com/IBM/vpc-go-sdk v0.67.1/go.mod h1:VL7sy61ybg6tvA60SepoQx7TFe20m7JyNUt+se2tHP4= +github.com/IBM/vpc-go-sdk v0.70.1 h1:6NsbRkiA5gDNxe7cjNx8Pi1j9s0PlhwNQj29wsKZxAo= +github.com/IBM/vpc-go-sdk v0.70.1/go.mod h1:K3vVlje72PYE3ZRt1iouE+jSIq+vCyYzT1HiFC06hUA= 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/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= diff --git a/ibm/acctest/acctest.go b/ibm/acctest/acctest.go index c280b47b6d..09516ffd5f 100644 --- a/ibm/acctest/acctest.go +++ b/ibm/acctest/acctest.go @@ -104,6 +104,8 @@ var ( InstanceName string InstanceProfileName string InstanceProfileNameUpdate string + ISCatalogImageName string + ISBootSnapshotID string IsBareMetalServerProfileName string IsBareMetalServerImage string IsBareMetalServerImage2 string @@ -972,6 +974,18 @@ func init() { fmt.Println("[INFO] Set the environment variable SL_INSTANCE_PROFILE_UPDATE for testing ibm_is_instance resource else it is set to default value 'cx2-4x8'") } + ISCatalogImageName = os.Getenv("IS_CATALOG_IMAGE_NAME") + if ISCatalogImageName == "" { + ISCatalogImageName = "test-catalog" + fmt.Println("[INFO] Set the environment variable IS_CATALOG_IMAGE_NAME for testing ibm_is_instance_template resource else it is set to default value 'test-catalog'") + } + + ISBootSnapshotID = os.Getenv("IS_BOOT_SNAPSHOT_ID") + if ISBootSnapshotID == "" { + ISBootSnapshotID = "r006-d7fejbe-2dhj-442df-b2iha-ccjbecbjbcejce" + fmt.Println("[INFO] Set the environment variable IS_BOOT_SNAPSHOT_ID for testing ibm_is_instance_template resource else it is set to default value 'r006-d7fejbe-2dhj-442df-b2iha-ccjbecbjbcejce'") + } + IsBareMetalServerProfileName = os.Getenv("IS_BARE_METAL_SERVER_PROFILE") if IsBareMetalServerProfileName == "" { IsBareMetalServerProfileName = "bx2-metal-96x384" // for next gen infrastructure diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index d532fe7677..db3d0d7161 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -488,50 +488,52 @@ func Provider() *schema.Provider { "ibm_is_instance_cluster_network_attachment": vpc.DataSourceIBMIsInstanceClusterNetworkAttachment(), "ibm_is_instance_cluster_network_attachments": vpc.DataSourceIBMIsInstanceClusterNetworkAttachments(), - "ibm_is_dedicated_host": vpc.DataSourceIbmIsDedicatedHost(), - "ibm_is_dedicated_hosts": vpc.DataSourceIbmIsDedicatedHosts(), - "ibm_is_dedicated_host_profile": vpc.DataSourceIbmIsDedicatedHostProfile(), - "ibm_is_dedicated_host_profiles": vpc.DataSourceIbmIsDedicatedHostProfiles(), - "ibm_is_dedicated_host_group": vpc.DataSourceIbmIsDedicatedHostGroup(), - "ibm_is_dedicated_host_groups": vpc.DataSourceIbmIsDedicatedHostGroups(), - "ibm_is_dedicated_host_disk": vpc.DataSourceIbmIsDedicatedHostDisk(), - "ibm_is_dedicated_host_disks": vpc.DataSourceIbmIsDedicatedHostDisks(), - "ibm_is_placement_group": vpc.DataSourceIbmIsPlacementGroup(), - "ibm_is_placement_groups": vpc.DataSourceIbmIsPlacementGroups(), - "ibm_is_floating_ip": vpc.DataSourceIBMISFloatingIP(), - "ibm_is_floating_ips": vpc.DataSourceIBMIsFloatingIps(), - "ibm_is_flow_log": vpc.DataSourceIBMIsFlowLog(), - "ibm_is_flow_logs": vpc.DataSourceIBMISFlowLogs(), - "ibm_is_image": vpc.DataSourceIBMISImage(), - "ibm_is_images": vpc.DataSourceIBMISImages(), - "ibm_is_image_export_job": vpc.DataSourceIBMIsImageExport(), - "ibm_is_image_export_jobs": vpc.DataSourceIBMIsImageExports(), - "ibm_is_endpoint_gateway_targets": vpc.DataSourceIBMISEndpointGatewayTargets(), - "ibm_is_instance_group": vpc.DataSourceIBMISInstanceGroup(), - "ibm_is_instance_groups": vpc.DataSourceIBMISInstanceGroups(), - "ibm_is_instance_group_memberships": vpc.DataSourceIBMISInstanceGroupMemberships(), - "ibm_is_instance_group_membership": vpc.DataSourceIBMISInstanceGroupMembership(), - "ibm_is_instance_group_manager": vpc.DataSourceIBMISInstanceGroupManager(), - "ibm_is_instance_group_managers": vpc.DataSourceIBMISInstanceGroupManagers(), - "ibm_is_instance_group_manager_policies": vpc.DataSourceIBMISInstanceGroupManagerPolicies(), - "ibm_is_instance_group_manager_policy": vpc.DataSourceIBMISInstanceGroupManagerPolicy(), - "ibm_is_instance_group_manager_action": vpc.DataSourceIBMISInstanceGroupManagerAction(), - "ibm_is_instance_group_manager_actions": vpc.DataSourceIBMISInstanceGroupManagerActions(), - "ibm_is_virtual_endpoint_gateways": vpc.DataSourceIBMISEndpointGateways(), - "ibm_is_virtual_endpoint_gateway_ips": vpc.DataSourceIBMISEndpointGatewayIPs(), - "ibm_is_virtual_endpoint_gateway": vpc.DataSourceIBMISEndpointGateway(), - "ibm_is_instance_template": vpc.DataSourceIBMISInstanceTemplate(), - "ibm_is_instance_templates": vpc.DataSourceIBMISInstanceTemplates(), - "ibm_is_instance_profile": vpc.DataSourceIBMISInstanceProfile(), - "ibm_is_instance_profiles": vpc.DataSourceIBMISInstanceProfiles(), - "ibm_is_instance": vpc.DataSourceIBMISInstance(), - "ibm_is_instances": vpc.DataSourceIBMISInstances(), - "ibm_is_instance_network_attachment": vpc.DataSourceIBMIsInstanceNetworkAttachment(), - "ibm_is_instance_network_attachments": vpc.DataSourceIBMIsInstanceNetworkAttachments(), - "ibm_is_instance_network_interface": vpc.DataSourceIBMIsInstanceNetworkInterface(), - "ibm_is_instance_network_interfaces": vpc.DataSourceIBMIsInstanceNetworkInterfaces(), - "ibm_is_instance_disk": vpc.DataSourceIbmIsInstanceDisk(), - "ibm_is_instance_disks": vpc.DataSourceIbmIsInstanceDisks(), + "ibm_is_dedicated_host": vpc.DataSourceIbmIsDedicatedHost(), + "ibm_is_dedicated_hosts": vpc.DataSourceIbmIsDedicatedHosts(), + "ibm_is_dedicated_host_profile": vpc.DataSourceIbmIsDedicatedHostProfile(), + "ibm_is_dedicated_host_profiles": vpc.DataSourceIbmIsDedicatedHostProfiles(), + "ibm_is_dedicated_host_group": vpc.DataSourceIbmIsDedicatedHostGroup(), + "ibm_is_dedicated_host_groups": vpc.DataSourceIbmIsDedicatedHostGroups(), + "ibm_is_dedicated_host_disk": vpc.DataSourceIbmIsDedicatedHostDisk(), + "ibm_is_dedicated_host_disks": vpc.DataSourceIbmIsDedicatedHostDisks(), + "ibm_is_placement_group": vpc.DataSourceIbmIsPlacementGroup(), + "ibm_is_placement_groups": vpc.DataSourceIbmIsPlacementGroups(), + "ibm_is_floating_ip": vpc.DataSourceIBMISFloatingIP(), + "ibm_is_floating_ips": vpc.DataSourceIBMIsFloatingIps(), + "ibm_is_flow_log": vpc.DataSourceIBMIsFlowLog(), + "ibm_is_flow_logs": vpc.DataSourceIBMISFlowLogs(), + "ibm_is_image": vpc.DataSourceIBMISImage(), + "ibm_is_images": vpc.DataSourceIBMISImages(), + "ibm_is_image_bare_metal_server_profiles": vpc.DataSourceIBMIsImageBareMetalServerProfiles(), + "ibm_is_image_instance_profiles": vpc.DataSourceIBMIsImageInstanceProfiles(), + "ibm_is_image_export_job": vpc.DataSourceIBMIsImageExport(), + "ibm_is_image_export_jobs": vpc.DataSourceIBMIsImageExports(), + "ibm_is_endpoint_gateway_targets": vpc.DataSourceIBMISEndpointGatewayTargets(), + "ibm_is_instance_group": vpc.DataSourceIBMISInstanceGroup(), + "ibm_is_instance_groups": vpc.DataSourceIBMISInstanceGroups(), + "ibm_is_instance_group_memberships": vpc.DataSourceIBMISInstanceGroupMemberships(), + "ibm_is_instance_group_membership": vpc.DataSourceIBMISInstanceGroupMembership(), + "ibm_is_instance_group_manager": vpc.DataSourceIBMISInstanceGroupManager(), + "ibm_is_instance_group_managers": vpc.DataSourceIBMISInstanceGroupManagers(), + "ibm_is_instance_group_manager_policies": vpc.DataSourceIBMISInstanceGroupManagerPolicies(), + "ibm_is_instance_group_manager_policy": vpc.DataSourceIBMISInstanceGroupManagerPolicy(), + "ibm_is_instance_group_manager_action": vpc.DataSourceIBMISInstanceGroupManagerAction(), + "ibm_is_instance_group_manager_actions": vpc.DataSourceIBMISInstanceGroupManagerActions(), + "ibm_is_virtual_endpoint_gateways": vpc.DataSourceIBMISEndpointGateways(), + "ibm_is_virtual_endpoint_gateway_ips": vpc.DataSourceIBMISEndpointGatewayIPs(), + "ibm_is_virtual_endpoint_gateway": vpc.DataSourceIBMISEndpointGateway(), + "ibm_is_instance_template": vpc.DataSourceIBMISInstanceTemplate(), + "ibm_is_instance_templates": vpc.DataSourceIBMISInstanceTemplates(), + "ibm_is_instance_profile": vpc.DataSourceIBMISInstanceProfile(), + "ibm_is_instance_profiles": vpc.DataSourceIBMISInstanceProfiles(), + "ibm_is_instance": vpc.DataSourceIBMISInstance(), + "ibm_is_instances": vpc.DataSourceIBMISInstances(), + "ibm_is_instance_network_attachment": vpc.DataSourceIBMIsInstanceNetworkAttachment(), + "ibm_is_instance_network_attachments": vpc.DataSourceIBMIsInstanceNetworkAttachments(), + "ibm_is_instance_network_interface": vpc.DataSourceIBMIsInstanceNetworkInterface(), + "ibm_is_instance_network_interfaces": vpc.DataSourceIBMIsInstanceNetworkInterfaces(), + "ibm_is_instance_disk": vpc.DataSourceIbmIsInstanceDisk(), + "ibm_is_instance_disks": vpc.DataSourceIbmIsInstanceDisks(), // reserved ips "ibm_is_instance_network_interface_reserved_ip": vpc.DataSourceIBMISInstanceNICReservedIP(), @@ -587,6 +589,7 @@ func Provider() *schema.Provider { "ibm_is_snapshot_consistency_group": vpc.DataSourceIBMIsSnapshotConsistencyGroup(), "ibm_is_snapshot_consistency_groups": vpc.DataSourceIBMIsSnapshotConsistencyGroups(), "ibm_is_snapshots": vpc.DataSourceSnapshots(), + "ibm_is_snapshot_instance_profiles": vpc.DataSourceIBMIsSnapshotInstanceProfiles(), "ibm_is_share": vpc.DataSourceIbmIsShare(), "ibm_is_source_share": vpc.DataSourceIbmIsSourceShare(), "ibm_is_shares": vpc.DataSourceIbmIsShares(), @@ -612,6 +615,7 @@ func Provider() *schema.Provider { "ibm_is_volumes": vpc.DataSourceIBMIsVolumes(), "ibm_is_volume_profile": vpc.DataSourceIBMISVolumeProfile(), "ibm_is_volume_profiles": vpc.DataSourceIBMISVolumeProfiles(), + "ibm_is_volume_instance_profiles": vpc.DataSourceIBMIsVolumeInstanceProfiles(), "ibm_is_vpc": vpc.DataSourceIBMISVPC(), "ibm_is_vpc_dns_resolution_binding": vpc.DataSourceIBMIsVPCDnsResolutionBinding(), "ibm_is_vpc_dns_resolution_bindings": vpc.DataSourceIBMIsVPCDnsResolutionBindings(), 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 7092c54755..c5e8ad4efd 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 @@ -156,6 +156,25 @@ func DataSourceIBMIsBareMetalServer() *schema.Resource { Computed: true, Description: "The size of the disk in GB (gigabytes)", }, + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The usage constraints to be matched against the requested bare metal server properties to determine compatibility.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this disk.", + }, + "api_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The API version with which to evaluate the expressions.", + }, + }, + }, + }, }, }, }, @@ -1029,6 +1048,16 @@ func dataSourceIBMISBareMetalServerRead(context context.Context, d *schema.Resou isBareMetalServerDiskResourceType: disk.ResourceType, isBareMetalServerDiskSize: disk.Size, } + if disk.AllowedUse != nil { + usageConstraintList := []map[string]interface{}{} + modelMap, err := ResourceceIBMIsBareMetalServerDiskAllowedUseToMap(disk.AllowedUse) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Resource) ibm_is_bare_metal_server", "read") + log.Println(tfErr.GetDiag()) + } + usageConstraintList = append(usageConstraintList, modelMap) + currentDisk["allowed_use"] = usageConstraintList + } diskList = append(diskList, currentDisk) } } diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_disk.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_disk.go index beded4c8d9..a6f107335d 100644 --- a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_disk.go +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_disk.go @@ -67,6 +67,25 @@ func DataSourceIBMIsBareMetalServerDisk() *schema.Resource { Computed: true, Description: "The size of the disk in GB (gigabytes)", }, + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The usage constraints to be matched against the requested bare metal server properties to determine compatibility.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this disk.", + }, + "api_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The API version with which to evaluate the expressions.", + }, + }, + }, + }, }, } } @@ -107,6 +126,16 @@ func dataSourceIBMISBareMetalServerDiskRead(context context.Context, d *schema.R if err = d.Set("size", flex.IntValue(bareMetalServerDisk.Size)); err != nil { return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting size: %s", err), "(Data) ibm_is_bare_metal_server_disk", "read", "set-size").GetDiag() } - + allowedUses := []map[string]interface{}{} + if bareMetalServerDisk.AllowedUse != nil { + modelMap, err := ResourceceIBMIsBareMetalServerDiskAllowedUseToMap(bareMetalServerDisk.AllowedUse) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting allowed_use: %s", err), "(Data) ibm_is_bare_metal_server_disk", "read", "set-allowed_use").GetDiag() + } + allowedUses = append(allowedUses, modelMap) + } + if err = d.Set("allowed_use", allowedUses); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting allowed_use: %s", err), "(Data) ibm_is_bare_metal_server_disk", "read", "set-allowed_use").GetDiag() + } return nil } diff --git a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_disks.go b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_disks.go index e950cf0c6c..bb29e3c4be 100644 --- a/ibm/service/vpc/data_source_ibm_is_bare_metal_server_disks.go +++ b/ibm/service/vpc/data_source_ibm_is_bare_metal_server_disks.go @@ -71,6 +71,25 @@ func DataSourceIBMIsBareMetalServerDisks() *schema.Resource { Computed: true, Description: "The size of the disk in GB (gigabytes)", }, + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The usage constraints to be matched against the requested bare metal server properties to determine compatibility.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this disk.", + }, + "api_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The API version with which to evaluate the expressions.", + }, + }, + }, + }, }, }, }, @@ -107,8 +126,18 @@ func dataSourceIBMISBareMetalServerDisksRead(context context.Context, d *schema. isBareMetalServerDiskResourceType: disk.ResourceType, isBareMetalServerDiskSize: disk.Size, } + if disk.AllowedUse != nil { + usageConstraintList := []map[string]interface{}{} + modelMap, err := ResourceceIBMIsBareMetalServerDiskAllowedUseToMap(disk.AllowedUse) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting allowed_use: %s", err), "(Data) ibm_is_bare_metal_server_disks", "read", "set-allowed_use").GetDiag() + } + usageConstraintList = append(usageConstraintList, modelMap) + l["allowed_use"] = usageConstraintList + } disksInfo = append(disksInfo, l) } + d.SetId(dataSourceIBMISBMSDisksID(d)) if err = d.Set(isBareMetalServerDisks, disksInfo); err != nil { return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting disks: %s", err), "(Data) ibm_is_bare_metal_server_disks", "read", "set-disks").GetDiag() 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 2eabdcf536..b07b418b5e 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 @@ -199,6 +199,25 @@ func DataSourceIBMIsBareMetalServers() *schema.Resource { Computed: true, Description: "The size of the disk in GB (gigabytes)", }, + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The usage constraints to be matched against the requested bare metal server properties to determine compatibility.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this disk.", + }, + "api_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The API version with which to evaluate the expressions.", + }, + }, + }, + }, }, }, }, @@ -1045,6 +1064,16 @@ func dataSourceIBMISBareMetalServersRead(context context.Context, d *schema.Reso isBareMetalServerDiskResourceType: disk.ResourceType, isBareMetalServerDiskSize: disk.Size, } + if disk.AllowedUse != nil { + usageConstraintList := []map[string]interface{}{} + modelMap, err := ResourceceIBMIsBareMetalServerDiskAllowedUseToMap(disk.AllowedUse) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Resource) ibm_is_bare_metal_server", "read") + log.Println(tfErr.GetDiag()) + } + usageConstraintList = append(usageConstraintList, modelMap) + currentDisk["allowed_use"] = usageConstraintList + } diskList = append(diskList, currentDisk) } } diff --git a/ibm/service/vpc/data_source_ibm_is_image.go b/ibm/service/vpc/data_source_ibm_is_image.go index f2debfaa36..e87788b4e2 100644 --- a/ibm/service/vpc/data_source_ibm_is_image.go +++ b/ibm/service/vpc/data_source_ibm_is_image.go @@ -258,6 +258,30 @@ func DataSourceIBMISImage() *schema.Resource { }, }, }, + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The usage constraints to match against the requested instance or bare metal server properties to determine compatibility.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The API version with which to evaluate the expressions.", + }, + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using this image.", + }, + "instance": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a virtual server instance provisioned using this image.", + }, + }, + }, + }, isImageAccessTags: { Type: schema.TypeSet, Computed: true, @@ -414,6 +438,19 @@ func imageGetByName(context context.Context, d *schema.ResourceData, meta interf return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting catalog_offering: %s", err), "(Data) ibm_is_image", "read", "set-catalog_offering").GetDiag() } } + allowedUse := []map[string]interface{}{} + if image.AllowedUse != nil { + modelMap, err := DataSourceIBMIsImageAllowedUseToMap(image.AllowedUse) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_image", "read") + log.Println(tfErr.GetDiag()) + } + allowedUse = append(allowedUse, modelMap) + } + if err = d.Set("allowed_use", allowedUse); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting allowed_use: %s", err), "(Data) ibm_is_image", "read") + log.Println(tfErr.GetDiag()) + } return nil } @@ -509,6 +546,19 @@ func imageGetById(context context.Context, d *schema.ResourceData, meta interfac return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting catalog_offering: %s", err), "(Data) ibm_is_image", "read", "set-catalog_offering").GetDiag() } } + allowedUse := []map[string]interface{}{} + if image.AllowedUse != nil { + modelMap, err := DataSourceIBMIsImageAllowedUseToMap(image.AllowedUse) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_image", "read") + log.Println(tfErr.GetDiag()) + } + allowedUse = append(allowedUse, modelMap) + } + if err = d.Set("allowed_use", allowedUse); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting allowed_use: %s", err), "(Data) ibm_is_image", "read") + log.Println(tfErr.GetDiag()) + } return nil } @@ -607,3 +657,17 @@ func dataSourceImageResourceGroupToMap(resourceGroupItem vpcv1.ResourceGroupRefe return resourceGroupMap } + +func DataSourceIBMIsImageAllowedUseToMap(model *vpcv1.ImageAllowedUse) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.BareMetalServer != nil { + modelMap["bare_metal_server"] = *model.BareMetalServer + } + if model.Instance != nil { + modelMap["instance"] = *model.Instance + } + if model.ApiVersion != nil { + modelMap["api_version"] = *model.ApiVersion + } + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_image_bare_metal_server_profiles.go b/ibm/service/vpc/data_source_ibm_is_image_bare_metal_server_profiles.go new file mode 100644 index 0000000000..1bfa7ec1aa --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_image_bare_metal_server_profiles.go @@ -0,0 +1,119 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsImageBareMetalServerProfiles() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsImageBareMetalServerProfilesRead, + + Schema: map[string]*schema.Schema{ + "identifier": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The image identifier.", + }, + "bare_metal_server_profiles": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A page of bare metal server profiles compatible with the image.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this bare metal server profile.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The name for this bare metal server profile.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsImageBareMetalServerProfilesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_image_bare_metal_server_profiles", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + listImageBareMetalServerProfilesOptions := &vpcv1.ListImageBareMetalServerProfilesOptions{} + + listImageBareMetalServerProfilesOptions.SetID(d.Get("identifier").(string)) + + start := "" + allrecs := []vpcv1.BareMetalServerProfileReference{} + for { + if start != "" { + listImageBareMetalServerProfilesOptions.Start = &start + } + imageBareMetalServerProfiles, response, err := vpcClient.ListImageBareMetalServerProfiles(listImageBareMetalServerProfilesOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_image_bare_metal_server_profiles", "read") + log.Printf("[DEBUG]\n%s\n%s", tfErr.GetDebugMessage(), response) + return tfErr.GetDiag() + } + start = flex.GetNext(imageBareMetalServerProfiles.Next) + allrecs = append(allrecs, imageBareMetalServerProfiles.BareMetalServerProfiles...) + if start == "" { + break + } + } + + d.SetId(dataSourceIBMIsImageBareMetalServerProfilesID(d)) + + mapSlice := []map[string]interface{}{} + for _, modelItem := range allrecs { + modelMap, err := DataSourceIBMIsImageBareMetalServerProfilesBareMetalServerProfileReferenceToMap(&modelItem) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_image_bare_metal_server_profiles", "read") + return tfErr.GetDiag() + } + mapSlice = append(mapSlice, modelMap) + } + + if err = d.Set("bare_metal_server_profiles", mapSlice); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting bare_metal_server_profiles %s", err), "(Data) ibm_is_image_bare_metal_server_profiles", "read") + return tfErr.GetDiag() + } + + return nil +} + +// dataSourceIBMIsImageBareMetalServerProfilesID returns a reasonable ID for the list. +func dataSourceIBMIsImageBareMetalServerProfilesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func DataSourceIBMIsImageBareMetalServerProfilesBareMetalServerProfileReferenceToMap(model *vpcv1.BareMetalServerProfileReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_image_bare_metal_server_profiles_test.go b/ibm/service/vpc/data_source_ibm_is_image_bare_metal_server_profiles_test.go new file mode 100644 index 0000000000..0f1dbc9093 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_image_bare_metal_server_profiles_test.go @@ -0,0 +1,40 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMIsImageBareMetalServerProfilesDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsImageBareMetalServerProfilesDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_image_bare_metal_server_profiles.is_image_bare_metal_server_profiles_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_image_bare_metal_server_profiles.is_image_bare_metal_server_profiles_instance", "bare_metal_server_profiles.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_image_bare_metal_server_profiles.is_image_bare_metal_server_profiles_instance", "bare_metal_server_profiles.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_image_bare_metal_server_profiles.is_image_bare_metal_server_profiles_instance", "bare_metal_server_profiles.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_image_bare_metal_server_profiles.is_image_bare_metal_server_profiles_instance", "bare_metal_server_profiles.0.resource_type"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsImageBareMetalServerProfilesDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_is_image_bare_metal_server_profiles" "is_image_bare_metal_server_profiles_instance" { + identifier = "%s" + } + `, acc.IsImage) +} diff --git a/ibm/service/vpc/data_source_ibm_is_image_instance_profiles.go b/ibm/service/vpc/data_source_ibm_is_image_instance_profiles.go new file mode 100644 index 0000000000..6cc98e8489 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_image_instance_profiles.go @@ -0,0 +1,119 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsImageInstanceProfiles() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsImageInstanceProfilesRead, + + Schema: map[string]*schema.Schema{ + "identifier": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The image identifier.", + }, + "instance_profiles": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A page of instance profiles compatible with the image.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual server instance profile.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this virtual server instance profile.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsImageInstanceProfilesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_image_instance_profiles", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + listImageInstanceProfilesOptions := &vpcv1.ListImageInstanceProfilesOptions{} + + listImageInstanceProfilesOptions.SetID(d.Get("identifier").(string)) + + start := "" + allrecs := []vpcv1.InstanceProfileReference{} + for { + if start != "" { + listImageInstanceProfilesOptions.Start = &start + } + imageInstanceProfile, response, err := vpcClient.ListImageInstanceProfiles(listImageInstanceProfilesOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_image_instance_profiles", "read") + log.Printf("[DEBUG]\n%s\n%s", tfErr.GetDebugMessage(), response) + return tfErr.GetDiag() + } + start = flex.GetNext(imageInstanceProfile.Next) + allrecs = append(allrecs, imageInstanceProfile.InstanceProfiles...) + if start == "" { + break + } + } + + d.SetId(dataSourceIBMIsImageInstanceProfilesID(d)) + + mapSlice := []map[string]interface{}{} + for _, modelItem := range allrecs { + modelMap, err := DataSourceIBMIsImageInstanceProfilesInstanceProfileReferenceToMap(&modelItem) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_image_instance_profiles", "read") + return tfErr.GetDiag() + } + mapSlice = append(mapSlice, modelMap) + } + + if err = d.Set("instance_profiles", mapSlice); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting instance_profiles %s", err), "(Data) ibm_is_image_instance_profiles", "read") + return tfErr.GetDiag() + } + + return nil +} + +// dataSourceIBMIsImageInstanceProfilesID returns a reasonable ID for the list. +func dataSourceIBMIsImageInstanceProfilesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func DataSourceIBMIsImageInstanceProfilesInstanceProfileReferenceToMap(model *vpcv1.InstanceProfileReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_image_instance_profiles_test.go b/ibm/service/vpc/data_source_ibm_is_image_instance_profiles_test.go new file mode 100644 index 0000000000..4082579de0 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_image_instance_profiles_test.go @@ -0,0 +1,40 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMIsImageInstanceProfilesDataSourceBasic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsImageInstanceProfilesDataSourceConfigBasic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_image_instance_profiles.is_image_instance_profiles_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_image_instance_profiles.is_image_instance_profiles_instance", "instance_profiles.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_image_instance_profiles.is_image_instance_profiles_instance", "instance_profiles.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_image_instance_profiles.is_image_instance_profiles_instance", "instance_profiles.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_image_instance_profiles.is_image_instance_profiles_instance", "instance_profiles.0.resource_type"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsImageInstanceProfilesDataSourceConfigBasic() string { + return fmt.Sprintf(` + data "ibm_is_image_instance_profiles" "is_image_instance_profiles_instance" { + identifier = "%s" + } + `, acc.IsImage) +} diff --git a/ibm/service/vpc/data_source_ibm_is_image_test.go b/ibm/service/vpc/data_source_ibm_is_image_test.go index 552d7f0e81..b36312dbaf 100644 --- a/ibm/service/vpc/data_source_ibm_is_image_test.go +++ b/ibm/service/vpc/data_source_ibm_is_image_test.go @@ -30,6 +30,10 @@ func TestAccIBMISImageDataSource_basic(t *testing.T) { resource.TestCheckResourceAttrSet(resName, "architecture"), resource.TestCheckResourceAttrSet(resName, "visibility"), resource.TestCheckResourceAttrSet(resName, "status"), + resource.TestCheckResourceAttrSet(resName, "allowed_use.#"), + resource.TestCheckResourceAttrSet(resName, "allowed_use.0.api_version"), + resource.TestCheckResourceAttrSet(resName, "allowed_use.0.bare_metal_server"), + resource.TestCheckResourceAttrSet(resName, "allowed_use.0.instance"), ), }, }, diff --git a/ibm/service/vpc/data_source_ibm_is_images.go b/ibm/service/vpc/data_source_ibm_is_images.go index 0f22416a1b..ae81dc944a 100644 --- a/ibm/service/vpc/data_source_ibm_is_images.go +++ b/ibm/service/vpc/data_source_ibm_is_images.go @@ -270,6 +270,30 @@ func DataSourceIBMISImages() *schema.Resource { }, }, }, + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The usage constraints to match against the requested instance or bare metal server properties to determine compatibility.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The API version with which to evaluate the expressions.", + }, + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using this image.", + }, + "instance": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a virtual server instance provisioned using this image.", + }, + }, + }, + }, isImageUserDataFormat: { Type: schema.TypeString, Computed: true, @@ -454,6 +478,19 @@ func imageList(context context.Context, d *schema.ResourceData, meta interface{} catalogOfferingList = append(catalogOfferingList, catalogOfferingMap) l[isImageCatalogOffering] = catalogOfferingList } + if image.UserDataFormat != nil { + l["user_data_format"] = *image.UserDataFormat + } + if image.AllowedUse != nil { + usageConstraintList := []map[string]interface{}{} + modelMap, err := DataSourceIBMIsImageAllowedUseToMap(image.AllowedUse) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_image", "read") + log.Println(tfErr.GetDiag()) + } + usageConstraintList = append(usageConstraintList, modelMap) + l["allowed_use"] = usageConstraintList + } accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *image.CRN, "", isImageAccessTagType) if err != nil { log.Printf( diff --git a/ibm/service/vpc/data_source_ibm_is_images_test.go b/ibm/service/vpc/data_source_ibm_is_images_test.go index 08c30998de..428a2bc9fd 100644 --- a/ibm/service/vpc/data_source_ibm_is_images_test.go +++ b/ibm/service/vpc/data_source_ibm_is_images_test.go @@ -53,6 +53,10 @@ func TestAccIBMISImagesDataSource_All(t *testing.T) { resource.TestCheckResourceAttrSet(resName, "images.0.status"), resource.TestCheckResourceAttrSet(resName, "images.0.resource_group.0.id"), resource.TestCheckResourceAttrSet(resName, "images.0.resource_group.0.name"), + resource.TestCheckResourceAttrSet(resName, "images.0.allowed_use.#"), + resource.TestCheckResourceAttrSet(resName, "images.0.allowed_use.0.api_version"), + resource.TestCheckResourceAttrSet(resName, "images.0.allowed_use.0.bare_metal_server"), + resource.TestCheckResourceAttrSet(resName, "images.0.allowed_use.0.instance"), ), }, }, diff --git a/ibm/service/vpc/data_source_ibm_is_instance_profile.go b/ibm/service/vpc/data_source_ibm_is_instance_profile.go index c8a5b66c90..b1c045ccc9 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_profile.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_profile.go @@ -980,7 +980,7 @@ func instanceProfileGet(context context.Context, d *schema.ResourceData, meta in // Manufacturer details added. if profile.VcpuManufacturer != nil { - err = d.Set(isInstanceVCPUManufacturer, dataSourceInstanceProfileFlattenVcpuManufacture(*profile.VcpuManufacturer)) + err = d.Set(isInstanceVCPUManufacturer, dataSourceInstanceProfileFlattenVcpuManufacture(*profile.VcpuManufacturer.(*vpcv1.InstanceProfileVcpuManufacturer))) if err != nil { return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting vcpu_manufacturer: %s", err), "(Data) ibm_is_instance_profile", "read", "set-vcpu_manufacturer").GetDiag() } diff --git a/ibm/service/vpc/data_source_ibm_is_instance_profiles.go b/ibm/service/vpc/data_source_ibm_is_instance_profiles.go index 3f14eba2b3..d7b96a7478 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_profiles.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_profiles.go @@ -952,7 +952,7 @@ func instanceProfilesList(context context.Context, d *schema.ResourceData, meta // reduce the line of code here. - sumit's suggestions if profile.VcpuManufacturer != nil { vcpuManufacturerList := []map[string]interface{}{} - vcpuManufacturerMap := dataSourceInstanceProfileVcpuManufacturerToMap(*profile.VcpuManufacturer) + vcpuManufacturerMap := dataSourceInstanceProfileVcpuManufacturerToMap(*profile.VcpuManufacturer.(*vpcv1.InstanceProfileVcpuManufacturer)) vcpuManufacturerList = append(vcpuManufacturerList, vcpuManufacturerMap) l["vcpu_manufacturer"] = vcpuManufacturerList } 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 0d7732b852..843b167bfc 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_template.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_template.go @@ -306,6 +306,35 @@ func DataSourceIBMISInstanceTemplate() *schema.Resource { Computed: true, Description: "The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource.", }, + "source_snapshot": { + Type: schema.TypeString, + Computed: true, + Description: "The snapshot to use as a source for the volume's data.", + }, + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The usage constraints to be matched against the requested instance or bare metal server properties to determine compatibility.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume.", + }, + "instance": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume.", + }, + "api_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The API version with which to evaluate the expressions.", + }, + }, + }, + }, isInstanceTemplateVolAttTags: { Type: schema.TypeSet, Computed: true, @@ -868,6 +897,30 @@ func DataSourceIBMISInstanceTemplate() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The usage constraints to be matched against the requested instance or bare metal server properties to determine compatibility.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume.", + }, + "instance": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume.", + }, + "api_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The API version with which to evaluate the expressions.", + }, + }, + }, + }, isInstanceTemplateBootVolumeTags: { Type: schema.TypeSet, Computed: true, @@ -1318,6 +1371,19 @@ func dataSourceIBMISInstanceTemplateRead(context context.Context, d *schema.Reso encryptionKey := volumeInst.EncryptionKey.(*vpcv1.EncryptionKeyIdentity) newVolume[isInstanceTemplateVolAttVolEncryptionKey] = *encryptionKey.CRN } + if volumeInst.AllowedUse != nil { + modelMap, err := DataSourceIBMIsVolumeAllowedUseToMap(volumeInst.AllowedUse) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting allowed_use: %s", err), "(Data) ibm_is_instance_template", "read", "set-allowed_use").GetDiag() + } + newVolume["allowed_use"] = []map[string]interface{}{modelMap} + } + + if volumeInst.SourceSnapshot != nil { + sourceSnapshot := volumeInst.SourceSnapshot.(*vpcv1.SnapshotIdentity) + newVolume["source_snapshot"] = *sourceSnapshot.ID + } + if volumeInst.UserTags != nil { newVolume[isInstanceTemplateVolAttTags] = instanceTemplate.BootVolumeAttachment.Volume.UserTags } @@ -1350,6 +1416,14 @@ func dataSourceIBMISInstanceTemplateRead(context context.Context, d *schema.Reso volProfInst := volProfIntf.(*vpcv1.VolumeProfileIdentity) bootVol[isInstanceTemplateBootProfile] = volProfInst.Name } + if instanceTemplate.BootVolumeAttachment.Volume.AllowedUse != nil { + modelMap, err := DataSourceIBMIsVolumeAllowedUseToMap(instanceTemplate.BootVolumeAttachment.Volume.AllowedUse) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting allowed_use: %s", err), "(Data) ibm_is_instance_template", "read", "set-allowed_use").GetDiag() + } + bootVol["allowed_use"] = []map[string]interface{}{modelMap} + + } if instanceTemplate.BootVolumeAttachment.Volume.UserTags != nil { bootVol[isInstanceTemplateBootVolumeTags] = instanceTemplate.BootVolumeAttachment.Volume.UserTags } @@ -1711,6 +1785,17 @@ func dataSourceIBMISInstanceTemplateRead(context context.Context, d *schema.Reso if volumeInst.UserTags != nil { newVolume[isInstanceTemplateVolAttTags] = volumeInst.UserTags } + if volumeInst.AllowedUse != nil { + modelMap, err := DataSourceIBMIsVolumeAllowedUseToMap(volumeInst.AllowedUse) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting allowed_use: %s", err), "(Data) ibm_is_instance_template", "read", "set-allowed_use").GetDiag() + } + newVolume["allowed_use"] = []map[string]interface{}{modelMap} + } + if volumeInst.SourceSnapshot != nil { + sourceSnapshot := volumeInst.SourceSnapshot.(*vpcv1.SnapshotIdentity) + newVolume["source_snapshot"] = *sourceSnapshot.ID + } newVolumeArr = append(newVolumeArr, newVolume) volumeAttach[isInstanceTemplateVolAttVolPrototype] = newVolumeArr @@ -1740,6 +1825,13 @@ func dataSourceIBMISInstanceTemplateRead(context context.Context, d *schema.Reso volProfInst := volProfIntf.(*vpcv1.VolumeProfileIdentity) bootVol[isInstanceTemplateBootProfile] = volProfInst.Name } + if instanceTemplate.BootVolumeAttachment.Volume.AllowedUse != nil { + modelMap, err := DataSourceIBMIsVolumeAllowedUseToMap(instanceTemplate.BootVolumeAttachment.Volume.AllowedUse) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting allowed_use: %s", err), "(Data) ibm_is_instance_template", "read", "set-allowed_use").GetDiag() + } + bootVol["allowed_use"] = []map[string]interface{}{modelMap} + } if instanceTemplate.BootVolumeAttachment.Volume.UserTags != nil { bootVol[isInstanceTemplateBootVolumeTags] = instanceTemplate.BootVolumeAttachment.Volume.UserTags } @@ -2647,3 +2739,16 @@ func DataSourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeClu modelMap["href"] = *model.Href return modelMap, nil } +func DataSourceIBMIsVolumeAllowedUseToMap(model *vpcv1.VolumeAllowedUsePrototype) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.BareMetalServer != nil { + modelMap["bare_metal_server"] = *model.BareMetalServer + } + if model.Instance != nil { + modelMap["instance"] = *model.Instance + } + if model.ApiVersion != nil { + modelMap["api_version"] = *model.ApiVersion + } + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_instance_template_test.go b/ibm/service/vpc/data_source_ibm_is_instance_template_test.go index 4846a776d0..3e25fe8868 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 @@ -240,6 +240,49 @@ func TestAccIBMISInstanceTemplate_ReservedIp_Basic(t *testing.T) { }) } +func TestAccIBMISInstanceTemplate_AllowedUse_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) + volAttachName := fmt.Sprintf("tf-testvolattach%d", randInt) + sshKeyName := fmt.Sprintf("tf-testsshkey%d", randInt) + userTag := "tag-0" + bandwidth := int64(2000) + apiVersion := "2025-07-02" + bareMetalServer := "true" + instanceval := "true" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceTemplateAllowedUseConfig(vpcName, subnetName, sshKeyName, publicKey, templateName, volAttachName, userTag, apiVersion, bareMetalServer, instanceval, bandwidth), + 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", "boot_volume_attachment.0.allowed_use.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data", "boot_volume_attachment.0.allowed_use.0.bare_metal_server"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data", "boot_volume_attachment.0.allowed_use.0.instance"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_template.instance_template_data", "boot_volume_attachment.0.allowed_use.0.api_version"), + resource.TestCheckResourceAttr("data.ibm_is_instance_template.instance_template_data", "boot_volume_attachment.0.allowed_use.0.bare_metal_server", bareMetalServer), + resource.TestCheckResourceAttr("data.ibm_is_instance_template.instance_template_data", "boot_volume_attachment.0.allowed_use.0.instance", instanceval), + resource.TestCheckResourceAttr("data.ibm_is_instance_template.instance_template_data", "boot_volume_attachment.0.allowed_use.0.api_version", apiVersion), + ), + }, + }, + }) +} + func testAccCheckIBMISInstanceTemplateDConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { return testAccCheckIBMISInstanceTemplateConfig(vpcName, subnetName, sshKeyName, publicKey, templateName) + fmt.Sprintf(` data "ibm_is_instance_template" "instance_template_data" { @@ -285,3 +328,11 @@ func testAccCheckIBMISInstanceTemplateRipDataConfig(vpcName, subnetName, sshKeyN } `) } + +func testAccCheckIBMISInstanceTemplateAllowedUseConfig(vpcName, subnetName, sshKeyName, publicKey, templateName, volAttachName, userTag, apiVersion, bareMetalServer, instanceval string, bandwidth int64) string { + return testAccCheckIBMISInstanceTemplateWithBoot_AllowedUse(vpcName, subnetName, sshKeyName, publicKey, templateName, volAttachName, userTag, apiVersion, bareMetalServer, instanceval, bandwidth) + 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 f3405d6ba9..7d8b2a7ee3 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_templates.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_templates.go @@ -336,6 +336,35 @@ func DataSourceIBMISInstanceTemplates() *schema.Resource { Computed: true, Description: "The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource.", }, + "source_snapshot": { + Type: schema.TypeString, + Computed: true, + Description: "The snapshot to use as a source for the volume's data.", + }, + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The usage constraints to be matched against the requested instance or bare metal server properties to determine compatibility.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume.", + }, + "instance": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume.", + }, + "api_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The API version with which to evaluate the expressions.", + }, + }, + }, + }, isInstanceTemplateVolAttTags: { Type: schema.TypeSet, Computed: true, @@ -925,6 +954,30 @@ func DataSourceIBMISInstanceTemplates() *schema.Resource { Type: schema.TypeInt, Computed: true, }, + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The usage constraints to be matched against the requested instance or bare metal server properties to determine compatibility.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume.", + }, + "instance": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume.", + }, + "api_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The API version with which to evaluate the expressions.", + }, + }, + }, + }, isInstanceTemplateBootVolumeTags: { Type: schema.TypeSet, Computed: true, @@ -1272,6 +1325,19 @@ func dataSourceIBMISInstanceTemplatesRead(context context.Context, d *schema.Res encryptionKey := volumeInst.EncryptionKey.(*vpcv1.EncryptionKeyIdentity) newVolume[isInstanceTemplateVolAttVolEncryptionKey] = *encryptionKey.CRN } + if volumeInst.SourceSnapshot != nil { + sourceSnapshot := volumeInst.SourceSnapshot.(*vpcv1.SnapshotIdentity) + newVolume["source_snapshot"] = *sourceSnapshot.ID + } + allowedUses := []interface{}{} + if volumeInst.AllowedUse != nil { + modelMap, err := DataSourceIBMIsVolumeAllowedUseToMap(volumeInst.AllowedUse) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting allowed_use: %s", err), "(Data) ibm_is_instance_template", "read", "set-allowed_use").GetDiag() + } + allowedUses = append(allowedUses, modelMap) + newVolume["allowed_use"] = allowedUses + } if volumeInst.UserTags != nil { newVolume[isInstanceTemplateVolAttTags] = instance.BootVolumeAttachment.Volume.UserTags } @@ -1302,6 +1368,12 @@ func dataSourceIBMISInstanceTemplatesRead(context context.Context, d *schema.Res if volumeIntf.Bandwidth != nil { bootVol["bandwidth"] = volumeIntf.Bandwidth } + allowedUses := []interface{}{} + if instance.BootVolumeAttachment.Volume.AllowedUse != nil { + modelMap, _ := DataSourceIBMIsVolumeAllowedUseToMap(instance.BootVolumeAttachment.Volume.AllowedUse) + allowedUses = append(allowedUses, modelMap) + bootVol["allowed_use"] = allowedUses + } if instance.BootVolumeAttachment.Volume.UserTags != nil { bootVol[isInstanceTemplateBootVolumeTags] = instance.BootVolumeAttachment.Volume.UserTags } 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 567e44a7c9..c7d9331c89 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 @@ -215,6 +215,51 @@ func TestAccIBMISInstanceTemplates_dataReservedIp(t *testing.T) { }) } +func TestAccIBMISInstanceTemplates_dataAllowedUse(t *testing.T) { + randInt := acctest.RandIntRange(10, 100) + + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDVtuCfWKVGKaRmaRG6JQZY8YdxnDgGzVOK93IrV9R5Hl0JP1oiLLWlZQS2reAKb8lBqyDVEREpaoRUDjqDqXG8J/kR42FKN51su914pjSBc86wJ02VtT1Wm1zRbSg67kT+g8/T1jCgB5XBODqbcICHVP8Z1lXkgbiHLwlUrbz6OZkGJHo/M/kD1Eme8lctceIYNz/Ilm7ewMXZA4fsidpto9AjyarrJLufrOBl4MRVcZTDSJ7rLP982aHpu9pi5eJAjOZc7Og7n4ns3NFppiCwgVMCVUQbN5GBlWhZ1OsT84ZiTf+Zy8ew+Yg5T7Il8HuC7loWnz+esQPf0s3xhC/kTsGgZreIDoh/rxJfD67wKXetNSh5RH/n5BqjaOuXPFeNXmMhKlhj9nJ8scayx/wsvOGuocEIkbyJSLj3sLUU403OafgatEdnJOwbqg6rUNNF5RIjpJpL7eEWlKIi1j9LyhmPJ+fEO7TmOES82VpCMHpLbe4gf/MhhJ/Xy8DKh9s= root@ffd8363b1226 + `) + vpcName := fmt.Sprintf("tf-testvpc%d", randInt) + subnetName := fmt.Sprintf("tf-testsubnet%d", randInt) + templateName := fmt.Sprintf("tf-testtemplate%d", randInt) + volAttachName := fmt.Sprintf("tf-testvolattach%d", randInt) + sshKeyName := fmt.Sprintf("tf-testsshkey%d", randInt) + userTag := "tag-0" + bandwidth := int64(2000) + apiVersion := "2025-07-02" + bareMetalServer := "true" + instanceval := "true" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceTemplatesAllowedUseConfig(vpcName, subnetName, sshKeyName, publicKey, templateName, volAttachName, userTag, apiVersion, bareMetalServer, instanceval, bandwidth), + 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.boot_volume_attachment.0.allowed_use.#"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.boot_volume_attachment.0.allowed_use.0.bare_metal_server"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.boot_volume_attachment.0.allowed_use.0.instance"), + resource.TestCheckResourceAttrSet( + "data.ibm_is_instance_templates.instance_templates_data", "templates.0.boot_volume_attachment.0.allowed_use.0.api_version"), + resource.TestCheckResourceAttr("data.ibm_is_instance_templates.instance_templates_data", "templates.0.boot_volume_attachment.0.allowed_use.0.bare_metal_server", bareMetalServer), + resource.TestCheckResourceAttr("data.ibm_is_instance_templates.instance_templates_data", "templates.0.boot_volume_attachment.0.allowed_use.0.instance", instanceval), + resource.TestCheckResourceAttr("data.ibm_is_instance_templates.instance_templates_data", "templates.0.boot_volume_attachment.0.allowed_use.0.api_version", apiVersion), + ), + }, + }, + }) +} + func testAccCheckIBMISInstanceTemplatesDConfig(vpcName, subnetName, sshKeyName, publicKey, templateName string) string { return testAccCheckIBMISInstanceTemplateConfig(vpcName, subnetName, sshKeyName, publicKey, templateName) + fmt.Sprintf(` @@ -259,3 +304,12 @@ func testAccCheckIBMISInstanceTemplatesReservedIpConfig(vpcName, subnetName, ssh } `) } + +func testAccCheckIBMISInstanceTemplatesAllowedUseConfig(vpcName, subnetName, sshKeyName, publicKey, templateName, volAttachName, userTag, apiVersion, bareMetalServer, instanceval string, bandwidth int64) string { + return testAccCheckIBMISInstanceTemplateWithBoot_AllowedUse(vpcName, subnetName, sshKeyName, publicKey, templateName, volAttachName, userTag, apiVersion, bareMetalServer, instanceval, bandwidth) + fmt.Sprintf(` + + data "ibm_is_instance_templates" "instance_templates_data" { + depends_on = [ibm_is_instance_template.instancetemplate1] + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_snapshot.go b/ibm/service/vpc/data_source_ibm_is_snapshot.go index 4d6ed8a482..a168322b8d 100644 --- a/ibm/service/vpc/data_source_ibm_is_snapshot.go +++ b/ibm/service/vpc/data_source_ibm_is_snapshot.go @@ -405,6 +405,30 @@ func DataSourceSnapshot() *schema.Resource { }, }, }, + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The usage constraints to match against the requested instance or bare metal server properties to determine compatibility. Can only be specified for bootable snapshots.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this snapshot.", + }, + "instance": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a virtual server instance provisioned using this snapshot.", + }, + "api_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The API version with which to evaluate the expressions.", + }, + }, + }, + }, }, } } @@ -645,6 +669,18 @@ func snapshotGetByNameOrID(context context.Context, d *schema.ResourceData, meta if err = d.Set("backup_policy_plan", backupPolicyPlanList); err != nil { return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting backup_policy_plan: %s", err), "(Data) ibm_is_snapshot", "read", "set-backup_policy_plan").GetDiag() } + allowedUsed := []map[string]interface{}{} + if snapshot.AllowedUse != nil { + modelMap, err := DataSourceIBMIsSnapshotAllowedUseToMap(snapshot.AllowedUse) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_snapshot", "read") + log.Println(tfErr.GetDiag()) + } + allowedUsed = append(allowedUsed, modelMap) + } + if err = d.Set("allowed_use", allowedUsed); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting allowed_use: %s", err), "(Data) ibm_is_snapshot", "read", "set-allowed_use").GetDiag() + } accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *snapshot.CRN, "", isAccessTagType) if err != nil { log.Printf( @@ -829,6 +865,18 @@ func snapshotGetByNameOrID(context context.Context, d *schema.ResourceData, meta if err = d.Set("backup_policy_plan", backupPolicyPlanList); err != nil { return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting backup_policy_plan: %s", err), "(Data) ibm_is_snapshot", "read", "set-backup_policy_plan").GetDiag() } + allowedUses := []map[string]interface{}{} + if snapshot.AllowedUse != nil { + modelMap, err := DataSourceIBMIsSnapshotAllowedUseToMap(snapshot.AllowedUse) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_snapshot", "read") + log.Println(tfErr.GetDiag()) + } + allowedUses = append(allowedUses, modelMap) + } + if err = d.Set("allowed_use", allowedUses); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting allowed_use: %s", err), "(Data) ibm_is_snapshot", "read", "set-allowed_use").GetDiag() + } accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *snapshot.CRN, "", isAccessTagType) if err != nil { log.Printf( @@ -848,3 +896,17 @@ func resourceIbmIsSnapshotCatalogOfferingVersionPlanReferenceDeletedToMap(catalo return catalogOfferingVersionPlanReferenceDeletedMap } + +func DataSourceIBMIsSnapshotAllowedUseToMap(model *vpcv1.SnapshotAllowedUse) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.BareMetalServer != nil { + modelMap["bare_metal_server"] = *model.BareMetalServer + } + if model.Instance != nil { + modelMap["instance"] = *model.Instance + } + if model.ApiVersion != nil { + modelMap["api_version"] = *model.ApiVersion + } + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_snapshot_instance_profiles.go b/ibm/service/vpc/data_source_ibm_is_snapshot_instance_profiles.go new file mode 100644 index 0000000000..de778077a8 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_snapshot_instance_profiles.go @@ -0,0 +1,119 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsSnapshotInstanceProfiles() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsSnapshotInstanceProfilesRead, + + Schema: map[string]*schema.Schema{ + "identifier": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The snapshot identifier.", + }, + "instance_profiles": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A page of instance profiles compatible with the snapshot.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual server instance profile.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this virtual server instance profile.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsSnapshotInstanceProfilesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_snapshot_instance_profiles", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + listSnapshotInstanceProfilesOptions := &vpcv1.ListSnapshotInstanceProfilesOptions{} + + listSnapshotInstanceProfilesOptions.SetID(d.Get("identifier").(string)) + + start := "" + allrecs := []vpcv1.InstanceProfileReference{} + for { + if start != "" { + listSnapshotInstanceProfilesOptions.Start = &start + } + snapshotInstanceProfile, response, err := vpcClient.ListSnapshotInstanceProfiles(listSnapshotInstanceProfilesOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_snapshot_instance_profiles", "read") + log.Printf("[DEBUG]\n%s\n%s", tfErr.GetDebugMessage(), response) + return tfErr.GetDiag() + } + start = flex.GetNext(snapshotInstanceProfile.Next) + allrecs = append(allrecs, snapshotInstanceProfile.InstanceProfiles...) + if start == "" { + break + } + } + + d.SetId(dataSourceIBMIsSnapshotInstanceProfilesID(d)) + + mapSlice := []map[string]interface{}{} + for _, modelItem := range allrecs { + modelMap, err := DataSourceIBMIsSnapshotInstanceProfilesInstanceProfileReferenceToMap(&modelItem) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_snapshot_instance_profiles", "read") + return tfErr.GetDiag() + } + mapSlice = append(mapSlice, modelMap) + } + + if err = d.Set("instance_profiles", mapSlice); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting instance_profiles %s", err), "(Data) ibm_is_snapshot_instance_profiles", "read") + return tfErr.GetDiag() + } + + return nil +} + +// dataSourceIBMIsSnapshotInstanceProfilesID returns a reasonable ID for the list. +func dataSourceIBMIsSnapshotInstanceProfilesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func DataSourceIBMIsSnapshotInstanceProfilesInstanceProfileReferenceToMap(model *vpcv1.InstanceProfileReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_snapshot_instance_profiles_test.go b/ibm/service/vpc/data_source_ibm_is_snapshot_instance_profiles_test.go new file mode 100644 index 0000000000..3bf4298f61 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_snapshot_instance_profiles_test.go @@ -0,0 +1,52 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMIsSnapshotInstanceProfilesDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfsnapshotuat-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsSnapshotInstanceProfilesDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, volname, name, name1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_instance_profiles.is_snapshot_instance_profiles", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_instance_profiles.is_snapshot_instance_profiles", "instance_profiles.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_instance_profiles.is_snapshot_instance_profiles", "instance_profiles.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_instance_profiles.is_snapshot_instance_profiles", "instance_profiles.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_snapshot_instance_profiles.is_snapshot_instance_profiles", "instance_profiles.0.resource_type"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsSnapshotInstanceProfilesDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, volname, name, name1 string) string { + return testAccCheckIBMISSnapshotConfig(vpcname, subnetname, sshname, publicKey, volname, name, name1) + fmt.Sprintf(` + data "ibm_is_snapshot_instance_profiles" "is_snapshot_instance_profiles" { + identifier = ibm_is_snapshot.testacc_snapshot.id + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_snapshot_test.go b/ibm/service/vpc/data_source_ibm_is_snapshot_test.go index 7d3febec0e..a19565b2a0 100644 --- a/ibm/service/vpc/data_source_ibm_is_snapshot_test.go +++ b/ibm/service/vpc/data_source_ibm_is_snapshot_test.go @@ -42,6 +42,10 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE resource.TestCheckResourceAttrSet(snpName, "crn"), resource.TestCheckResourceAttrSet(snpName, "lifecycle_state"), resource.TestCheckResourceAttrSet(snpName, "encryption"), + resource.TestCheckResourceAttrSet(snpName, "allowed_use.#"), + resource.TestCheckResourceAttrSet(snpName, "allowed_use.0.bare_metal_server"), + resource.TestCheckResourceAttrSet(snpName, "allowed_use.0.instance"), + resource.TestCheckResourceAttrSet(snpName, "allowed_use.0.api_version"), // resource.TestCheckResourceAttrSet(snpName, "captured_at"), // Commented as the attribute is optional. ), }, diff --git a/ibm/service/vpc/data_source_ibm_is_snapshots.go b/ibm/service/vpc/data_source_ibm_is_snapshots.go index 24731eec68..c6c67d9ed8 100644 --- a/ibm/service/vpc/data_source_ibm_is_snapshots.go +++ b/ibm/service/vpc/data_source_ibm_is_snapshots.go @@ -516,6 +516,30 @@ func DataSourceSnapshots() *schema.Resource { }, }, }, + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The usage constraints to match against the requested instance or bare metal server properties to determine compatibility. Can only be specified for bootable snapshots.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this snapshot.", + }, + "instance": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a virtual server instance provisioned using this snapshot.", + }, + "api_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The API version with which to evaluate the expressions.", + }, + }, + }, + }, }, }, }, @@ -762,6 +786,16 @@ func getSnapshots(context context.Context, d *schema.ResourceData, meta interfac backupPolicyPlanList = append(backupPolicyPlanList, backupPolicyPlan) } l[isSnapshotBackupPolicyPlan] = backupPolicyPlanList + if snapshot.AllowedUse != nil { + allowedUseList := []map[string]interface{}{} + modelMap, err := DataSourceIBMIsSnapshotAllowedUseToMap(snapshot.AllowedUse) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_snapshots", "read") + log.Println(tfErr.GetDiag()) + } + allowedUseList = append(allowedUseList, modelMap) + l["allowed_use"] = allowedUseList + } accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *snapshot.CRN, "", isAccessTagType) if err != nil { log.Printf( diff --git a/ibm/service/vpc/data_source_ibm_is_snapshots_test.go b/ibm/service/vpc/data_source_ibm_is_snapshots_test.go index 59e7dc95a6..ce4d4050c6 100644 --- a/ibm/service/vpc/data_source_ibm_is_snapshots_test.go +++ b/ibm/service/vpc/data_source_ibm_is_snapshots_test.go @@ -49,6 +49,10 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE resource.TestCheckResourceAttrSet(snpName, "snapshots.0.lifecycle_state"), resource.TestCheckResourceAttrSet(snpName, "snapshots.0.encryption"), resource.TestCheckResourceAttrSet(snpName, "snapshots.0.captured_at"), + resource.TestCheckResourceAttrSet(snpName, "snapshots.0.allowed_use.#"), + resource.TestCheckResourceAttrSet(snpName, "snapshots.0.allowed_use.0.bare_metal_server"), + resource.TestCheckResourceAttrSet(snpName, "snapshots.0.allowed_use.0.instance"), + resource.TestCheckResourceAttrSet(snpName, "snapshots.0.allowed_use.0.api_version"), ), }, }, diff --git a/ibm/service/vpc/data_source_ibm_is_volume.go b/ibm/service/vpc/data_source_ibm_is_volume.go index e8fa9e1d24..ddebcac7f9 100644 --- a/ibm/service/vpc/data_source_ibm_is_volume.go +++ b/ibm/service/vpc/data_source_ibm_is_volume.go @@ -321,6 +321,30 @@ func DataSourceIBMISVolume() *schema.Resource { Computed: true, Description: "The resource group name in which resource is provisioned", }, + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The usage constraints to be matched against the requested instance or bare metal server properties to determine compatibility.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume.", + }, + "instance": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume.", + }, + "api_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The API version with which to evaluate the expressions.", + }, + }, + }, + }, }, } } @@ -579,6 +603,17 @@ func volumeGet(context context.Context, d *schema.ResourceData, meta interface{} return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting adjustable_iops_states: %s", err), "(Data) ibm_is_volume", "read", "set-adjustable_iops_states").GetDiag() } + allowedUses := []map[string]interface{}{} + if volume.AllowedUse != nil { + modelMap, err := ResourceceIBMIsVolumeAllowedUseToMap(volume.AllowedUse) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting allowed_use: %s", err), "(Data) ibm_is_volume", "read", "set-allowed_use").GetDiag() + } + allowedUses = append(allowedUses, modelMap) + } + if err = d.Set("allowed_use", allowedUses); err != nil { + return flex.DiscriminatedTerraformErrorf(err, fmt.Sprintf("Error setting allowed_use: %s", err), "(Data) ibm_is_volume", "read", "set-allowed_use").GetDiag() + } return nil } diff --git a/ibm/service/vpc/data_source_ibm_is_volume_instance_profiles.go b/ibm/service/vpc/data_source_ibm_is_volume_instance_profiles.go new file mode 100644 index 0000000000..e5502ff612 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_volume_instance_profiles.go @@ -0,0 +1,119 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/vpc-go-sdk/vpcv1" +) + +func DataSourceIBMIsVolumeInstanceProfiles() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIBMIsVolumeInstanceProfilesRead, + + Schema: map[string]*schema.Schema{ + "identifier": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "The volume identifier.", + }, + "instance_profiles": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "A page of instance profiles compatible with the volume.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual server instance profile.", + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for this virtual server instance profile.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIBMIsVolumeInstanceProfilesRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + vpcClient, err := vpcClient(meta) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_volume_instance_profiles", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + listvolumeInstanceProfilesOptions := &vpcv1.ListVolumeInstanceProfilesOptions{} + + listvolumeInstanceProfilesOptions.SetID(d.Get("identifier").(string)) + + start := "" + allrecs := []vpcv1.InstanceProfileReference{} + for { + if start != "" { + listvolumeInstanceProfilesOptions.Start = &start + } + volumeInstanceProfile, response, err := vpcClient.ListVolumeInstanceProfiles(listvolumeInstanceProfilesOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_volume_instance_profiles", "read") + log.Printf("[DEBUG]\n%s\n%s", tfErr.GetDebugMessage(), response) + return tfErr.GetDiag() + } + start = flex.GetNext(volumeInstanceProfile.Next) + allrecs = append(allrecs, volumeInstanceProfile.InstanceProfiles...) + if start == "" { + break + } + } + + d.SetId(dataSourceIBMIsVolumeInstanceProfilesID(d)) + + mapSlice := []map[string]interface{}{} + for _, modelItem := range allrecs { + modelMap, err := DataSourceIBMIsVolumeInstanceProfilesInstanceProfileReferenceToMap(&modelItem) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_volume_instance_profiles", "read") + return tfErr.GetDiag() + } + mapSlice = append(mapSlice, modelMap) + } + + if err = d.Set("instance_profiles", mapSlice); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting instance_profiles %s", err), "(Data) ibm_is_volume_instance_profiles", "read") + return tfErr.GetDiag() + } + + return nil +} + +// dataSourceIBMIsVolumeInstanceProfilesID returns a reasonable ID for the list. +func dataSourceIBMIsVolumeInstanceProfilesID(d *schema.ResourceData) string { + return time.Now().UTC().String() +} + +func DataSourceIBMIsVolumeInstanceProfilesInstanceProfileReferenceToMap(model *vpcv1.InstanceProfileReference) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + modelMap["href"] = *model.Href + modelMap["name"] = *model.Name + modelMap["resource_type"] = *model.ResourceType + return modelMap, nil +} diff --git a/ibm/service/vpc/data_source_ibm_is_volume_instance_profiles_test.go b/ibm/service/vpc/data_source_ibm_is_volume_instance_profiles_test.go new file mode 100644 index 0000000000..919e19ed12 --- /dev/null +++ b/ibm/service/vpc/data_source_ibm_is_volume_instance_profiles_test.go @@ -0,0 +1,51 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIBMIsVolumeInstanceProfilesDataSourceBasic(t *testing.T) { + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfsnapshotuat-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMIsVolumeInstanceProfilesDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, volname, name, name1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_is_volume_instance_profiles.is_volume_instance_profiles_instance", "id"), + resource.TestCheckResourceAttrSet("data.ibm_is_volume_instance_profiles.is_volume_instance_profiles_instance", "instance_profiles.#"), + resource.TestCheckResourceAttrSet("data.ibm_is_volume_instance_profiles.is_volume_instance_profiles_instance", "instance_profiles.0.href"), + resource.TestCheckResourceAttrSet("data.ibm_is_volume_instance_profiles.is_volume_instance_profiles_instance", "instance_profiles.0.name"), + resource.TestCheckResourceAttrSet("data.ibm_is_volume_instance_profiles.is_volume_instance_profiles_instance", "instance_profiles.0.resource_type"), + ), + }, + }, + }) +} + +func testAccCheckIBMIsVolumeInstanceProfilesDataSourceConfigBasic(vpcname, subnetname, sshname, publicKey, volname, name, name1 string) string { + return testAccCheckIBMISSnapshotConfig(vpcname, subnetname, sshname, publicKey, volname, name, name1) + fmt.Sprintf(` + data "ibm_is_volume_instance_profiles" "is_volume_instance_profiles_instance" { + identifier = ibm_is_instance.testacc_instance.volume_attachments[0].volume_id + } + `) +} diff --git a/ibm/service/vpc/data_source_ibm_is_volume_test.go b/ibm/service/vpc/data_source_ibm_is_volume_test.go index ffbf25c412..ec6c7ae208 100644 --- a/ibm/service/vpc/data_source_ibm_is_volume_test.go +++ b/ibm/service/vpc/data_source_ibm_is_volume_test.go @@ -193,6 +193,14 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE resName, "operating_system.0.vendor"), resource.TestCheckResourceAttrSet( resName, "operating_system.0.version"), + resource.TestCheckResourceAttrSet( + resName, "allowed_use.#"), + resource.TestCheckResourceAttrSet( + resName, "allowed_use.0.bare_metal_server"), + resource.TestCheckResourceAttrSet( + resName, "allowed_use.0.instance"), + resource.TestCheckResourceAttrSet( + resName, "allowed_use.0.api_version"), ), }, }, diff --git a/ibm/service/vpc/data_source_ibm_is_volumes.go b/ibm/service/vpc/data_source_ibm_is_volumes.go index 1fc565a38e..f537eb2938 100644 --- a/ibm/service/vpc/data_source_ibm_is_volumes.go +++ b/ibm/service/vpc/data_source_ibm_is_volumes.go @@ -641,6 +641,30 @@ func DataSourceIBMIsVolumes() *schema.Resource { Computed: true, Description: "The health of this resource.", }, + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The usage constraints to be matched against the requested instance or bare metal server properties to determine compatibility.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume.", + }, + "instance": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume.", + }, + "api_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The API version with which to evaluate the expressions.", + }, + }, + }, + }, }, }, }, @@ -872,6 +896,16 @@ func dataSourceVolumeCollectionVolumesToMap(volumesItem vpcv1.Volume, meta inter if volumesItem.UserTags != nil { volumesMap[isVolumeTags] = volumesItem.UserTags } + if volumesItem.AllowedUse != nil { + usageConstraintList := []map[string]interface{}{} + modelMap, err := ResourceceIBMIsVolumeAllowedUseToMap(volumesItem.AllowedUse) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_is_volumes", "read") + log.Println(tfErr.GetDiag()) + } + usageConstraintList = append(usageConstraintList, modelMap) + volumesMap["allowed_use"] = usageConstraintList + } accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *volumesItem.CRN, "", isVolumeAccessTagType) if err != nil { log.Printf( diff --git a/ibm/service/vpc/data_source_ibm_is_volumes_test.go b/ibm/service/vpc/data_source_ibm_is_volumes_test.go index 82b1339725..9353236d99 100644 --- a/ibm/service/vpc/data_source_ibm_is_volumes_test.go +++ b/ibm/service/vpc/data_source_ibm_is_volumes_test.go @@ -110,6 +110,14 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE resName, "volumes.0.operating_system.0.vendor"), resource.TestCheckResourceAttrSet( resName, "volumes.0.operating_system.0.version"), + resource.TestCheckResourceAttrSet( + resName, "volumes.0.allowed_use.#"), + resource.TestCheckResourceAttrSet( + resName, "volumes.0.allowed_use.0.bare_metal_server"), + resource.TestCheckResourceAttrSet( + resName, "volumes.0.allowed_use.0.instance"), + resource.TestCheckResourceAttrSet( + resName, "volumes.0.allowed_use.0.api_version"), ), }, }, 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 89f5b87270..aff0e593a2 100644 --- a/ibm/service/vpc/resource_ibm_is_bare_metal_server.go +++ b/ibm/service/vpc/resource_ibm_is_bare_metal_server.go @@ -259,6 +259,25 @@ func ResourceIBMIsBareMetalServer() *schema.Resource { Computed: true, Description: "The size of the disk in GB (gigabytes)", }, + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The usage constraints to match against the requested instance or bare metal server properties to determine compatibility.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An image can only be used for bare metal instantiation if this expression resolves to true.", + }, + "api_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The API version with which to evaluate the expressions.", + }, + }, + }, + }, }, }, }, @@ -2192,6 +2211,16 @@ func bareMetalServerGet(context context.Context, d *schema.ResourceData, meta in isBareMetalServerDiskResourceType: disk.ResourceType, isBareMetalServerDiskSize: disk.Size, } + if disk.AllowedUse != nil { + usageConstraintList := []map[string]interface{}{} + modelMap, err := ResourceceIBMIsBareMetalServerDiskAllowedUseToMap(disk.AllowedUse) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Resource) ibm_is_bare_metal_server", "read") + log.Println(tfErr.GetDiag()) + } + usageConstraintList = append(usageConstraintList, modelMap) + currentDisk["allowed_use"] = usageConstraintList + } diskList = append(diskList, currentDisk) } } diff --git a/ibm/service/vpc/resource_ibm_is_bare_metal_server_disk.go b/ibm/service/vpc/resource_ibm_is_bare_metal_server_disk.go index fdd4899d25..abc6876ba8 100644 --- a/ibm/service/vpc/resource_ibm_is_bare_metal_server_disk.go +++ b/ibm/service/vpc/resource_ibm_is_bare_metal_server_disk.go @@ -50,6 +50,52 @@ func ResourceIBMIsBareMetalServerDisk() *schema.Resource { Description: "Bare metal server disk name", ValidateFunc: validate.InvokeValidator("ibm_is_bare_metal_server_disk", isBareMetalServerDiskName), }, + + "created_at": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The date and time that the disk was created.", + }, + "href": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The URL for this bare metal server disk.", + }, + "interface_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The disk attachment interface used:- `fcp`: Fiber Channel Protocol- `sata`: Serial Advanced Technology Attachment- `nvme`: Non-Volatile Memory ExpressThe enumerated values for this property may[expand](https://cloud.ibm.com/apidocs/vpc#property-value-expansion) in the future.", + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The resource type.", + }, + "size": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + Description: "The size of the disk in GB (gigabytes).", + }, + + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Description: "The usage constraints to match against the requested instance or bare metal server properties to determine compatibility.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "An image can only be used for bare metal instantiation if this expression resolves to true.", + }, + "api_version": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Description: "The API version with which to evaluate the expressions.", + }, + }, + }, + }, }, } } @@ -147,9 +193,59 @@ func bareMetalServerDiskGet(context context.Context, d *schema.ResourceData, ses err = fmt.Errorf("Error setting name: %s", err) return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_bare_metal_server_disk", "read", "set-name").GetDiag() } + + if err = d.Set("created_at", disk.CreatedAt.String()); err != nil { + err = fmt.Errorf("Error setting created_at: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_bare_metal_server_disk", "read", "set-created_at").GetDiag() + } + + if err = d.Set("href", *disk.Href); err != nil { + err = fmt.Errorf("Error setting href: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_bare_metal_server_disk", "read", "set-href").GetDiag() + } + + if err = d.Set("interface_type", *disk.InterfaceType); err != nil { + err = fmt.Errorf("Error setting interface_type: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_bare_metal_server_disk", "read", "set-interface_type").GetDiag() + } + + if err = d.Set("resource_type", *disk.ResourceType); err != nil { + err = fmt.Errorf("Error setting resource_type: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_bare_metal_server_disk", "read", "set-resource_type").GetDiag() + } + + if err = d.Set("size", *disk.Size); err != nil { + err = fmt.Errorf("Error setting size: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_bare_metal_server_disk", "read", "set-interface_type").GetDiag() + } + + allowedUses := []map[string]interface{}{} + if disk.AllowedUse != nil { + modelMap, err := ResourceceIBMIsBareMetalServerDiskAllowedUseToMap(disk.AllowedUse) + if err != nil { + err = fmt.Errorf("Error setting allowed_use: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_bare_metal_server_disk", "read", "set-allowed_use").GetDiag() + } + allowedUses = append(allowedUses, modelMap) + } + if err = d.Set("allowed_use", allowedUses); err != nil { + err = fmt.Errorf("Error setting allowed_use: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_bare_metal_server_disk", "read", "set-allowed_use").GetDiag() + } return nil } +func ResourceceIBMIsBareMetalServerDiskAllowedUseToMap(model *vpcv1.BareMetalServerDiskAllowedUse) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.BareMetalServer != nil { + modelMap["bare_metal_server"] = *model.BareMetalServer + } + if model.ApiVersion != nil { + modelMap["api_version"] = *model.ApiVersion + } + return modelMap, nil +} + func resourceIBMISBareMetalServerDiskRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var bareMetalServerId, diskId string if bmsId, ok := d.GetOk(isBareMetalServerID); ok { diff --git a/ibm/service/vpc/resource_ibm_is_image.go b/ibm/service/vpc/resource_ibm_is_image.go index dc6257d3d8..d9b3069dc8 100644 --- a/ibm/service/vpc/resource_ibm_is_image.go +++ b/ibm/service/vpc/resource_ibm_is_image.go @@ -257,6 +257,38 @@ func ResourceIBMISImage() *schema.Resource { Computed: true, Description: "The user data format for this image", }, + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "The usage constraints to match against the requested instance or bare metal server properties to determine compatibility.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_image", "allowed_use.api_version"), + Description: "The API version with which to evaluate the expressions.", + }, + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_image", "allowed_use.bare_metal_server"), + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using this image.", + }, + "instance": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_image", "allowed_use.instance"), + Description: "The expression that must be satisfied by the properties of a virtual server instance provisioned using this image.", + }, + }, + }, + }, }, } } @@ -291,6 +323,27 @@ func ResourceIBMISImageValidator() *validate.ResourceValidator { Regexp: `^([A-Za-z0-9_.-]|[A-Za-z0-9_.-][A-Za-z0-9_ .-]*[A-Za-z0-9_.-]):([A-Za-z0-9_.-]|[A-Za-z0-9_.-][A-Za-z0-9_ .-]*[A-Za-z0-9_.-])$`, MinValueLength: 1, MaxValueLength: 128}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "allowed_use.api_version", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$`}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "allowed_use.bare_metal_server", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([a-zA-Z_][a-zA-Z0-9_]*|[-+*/%]|&&|\|\||!|==|!=|<|<=|>|>=|~|\bin\b|\(|\)|\[|\]|,|\.|"|'|"|'|\s+|\d+)+$`}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "allowed_use.instance", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([a-zA-Z_][a-zA-Z0-9_]*|[-+*/%]|&&|\|\||!|==|!=|<|<=|>|>=|~|\bin\b|\(|\)|\[|\]|,|\.|"|'|"|'|\s+|\d+)+$`}) ibmISImageResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_image", Schema: validateSchema} return &ibmISImageResourceValidator } @@ -334,6 +387,13 @@ func imgCreateByFile(context context.Context, d *schema.ResourceData, meta inter Name: &operatingSystem, }, } + if allowedUse, ok := d.GetOk("allowed_use"); ok { + allowedUseModel, err := ResourceIBMUsageConstraintsMapToImageAllowUsePrototype(allowedUse.([]interface{})[0].(map[string]interface{})) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_image", "create", "parse-allowed_use").GetDiag() + } + imagePrototype.AllowedUse = allowedUseModel + } if obsoleteAtOk, ok := d.GetOk(isImageObsolescenceAt); ok { obsoleteAt, err := strfmt.ParseDateTime(obsoleteAtOk.(string)) if err != nil { @@ -415,6 +475,13 @@ func imgCreateByVolume(context context.Context, d *schema.ResourceData, meta int imagePrototype.SourceVolume = &vpcv1.VolumeIdentity{ ID: &volume, } + if allowedUse, ok := d.GetOk("allowed_use"); ok { + allowedUseModel, err := ResourceIBMUsageConstraintsMapToImageAllowUsePrototype(allowedUse.([]interface{})[0].(map[string]interface{})) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_image", "create", "parse-allowed_use").GetDiag() + } + imagePrototype.AllowedUse = allowedUseModel + } options := &vpcv1.GetVolumeOptions{ ID: &volume, } @@ -703,6 +770,13 @@ func imgUpdate(context context.Context, d *schema.ResourceData, meta interface{} imagePatchModel.DeprecationAt = &deprecateAt } } + if d.HasChange("allowed_use") { + allowedUseModel, err := ResourceIBMIsImageMapToImageAllowedUsePatch(d.Get("allowed_use").([]interface{})[0].(map[string]interface{})) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_image", "update", "parse-allowed_use").GetDiag() + } + imagePatchModel.AllowedUse = allowedUseModel + } imagePatch, err := imagePatchModel.AsPatch() if err != nil { tfErr := flex.TerraformErrorf(err, fmt.Sprintf("imagePatchModel.AsPatch failed: %s", err.Error()), "ibm_is_image", "update") @@ -736,6 +810,20 @@ func resourceIBMISImageRead(context context.Context, d *schema.ResourceData, met return nil } +func ResourceIBMIsImageMapToImageAllowedUsePatch(modelMap map[string]interface{}) (*vpcv1.ImageAllowedUsePatch, error) { + model := &vpcv1.ImageAllowedUsePatch{} + if modelMap["api_version"] != nil && modelMap["api_version"].(string) != "" { + model.ApiVersion = core.StringPtr(modelMap["api_version"].(string)) + } + if modelMap["bare_metal_server"] != nil && modelMap["bare_metal_server"].(string) != "" { + model.BareMetalServer = core.StringPtr(modelMap["bare_metal_server"].(string)) + } + if modelMap["instance"] != nil && modelMap["instance"].(string) != "" { + model.Instance = core.StringPtr(modelMap["instance"].(string)) + } + return model, nil +} + func imgGet(context context.Context, d *schema.ResourceData, meta interface{}, id string) diag.Diagnostics { sess, err := vpcClient(meta) if err != nil { @@ -849,6 +937,17 @@ func imgGet(context context.Context, d *schema.ResourceData, meta interface{}, i return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_image", "read", "set-checksum").GetDiag() } } + if !core.IsNil(image.AllowedUse) { + allowedUseMap, err := ResourceIBMIsImageImageAllowUseToMap(image.AllowedUse) + if err != nil { + err = fmt.Errorf("Error setting allowed_use: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_image", "read", "set-allowed_use").GetDiag() + } + if err = d.Set("allowed_use", []map[string]interface{}{allowedUseMap}); err != nil { + err = fmt.Errorf("Error setting allowed_use: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_image", "read", "set-allowed_use").GetDiag() + } + } tags, err := flex.GetGlobalTagsUsingCRN(meta, *image.CRN, "", isImageUserTagType) if err != nil { log.Printf( @@ -1006,3 +1105,31 @@ func imgExists(d *schema.ResourceData, meta interface{}, id string) (bool, error } return true, nil } + +func ResourceIBMUsageConstraintsMapToImageAllowUsePrototype(modelMap map[string]interface{}) (*vpcv1.ImageAllowedUsePrototype, error) { + model := &vpcv1.ImageAllowedUsePrototype{} + if modelMap["api_version"] != nil && modelMap["api_version"].(string) != "" { + model.ApiVersion = core.StringPtr(modelMap["api_version"].(string)) + } + if modelMap["bare_metal_server"] != nil && modelMap["bare_metal_server"].(string) != "" { + model.BareMetalServer = core.StringPtr(modelMap["bare_metal_server"].(string)) + } + if modelMap["instance"] != nil && modelMap["instance"].(string) != "" { + model.Instance = core.StringPtr(modelMap["instance"].(string)) + } + return model, nil +} + +func ResourceIBMIsImageImageAllowUseToMap(model *vpcv1.ImageAllowedUse) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.BareMetalServer != nil { + modelMap["bare_metal_server"] = *model.BareMetalServer + } + if model.Instance != nil { + modelMap["instance"] = *model.Instance + } + if model.Instance != nil { + modelMap["api_version"] = *model.ApiVersion + } + return modelMap, nil +} diff --git a/ibm/service/vpc/resource_ibm_is_image_test.go b/ibm/service/vpc/resource_ibm_is_image_test.go index c05ea420bc..ae36d0f62e 100644 --- a/ibm/service/vpc/resource_ibm_is_image_test.go +++ b/ibm/service/vpc/resource_ibm_is_image_test.go @@ -68,6 +68,63 @@ func TestAccIBMISImage_accessTags(t *testing.T) { }, }) } +func TestAccIBMISImage_allowedUse(t *testing.T) { + var image string + name := fmt.Sprintf("tfimg-name-%d", acctest.RandIntRange(10, 100)) + apiVersion := "2025-07-02" + bareMetalServer := "enable_secure_boot==true" + instance := "enable_secure_boot==true" + apiVersionUpdate := "2025-07-02" + bareMetalServerUpdate := "true" + instanceUpdate := "true" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheckImage(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: checkImageDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISImageConfigAllowedUse(name, apiVersion, bareMetalServer, instance), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISImageExists("ibm_is_image.isExampleImage", image), + resource.TestCheckResourceAttr( + "ibm_is_image.isExampleImage", "name", name), + resource.TestCheckResourceAttrSet("ibm_is_image.isExampleImage", "user_data_format"), + resource.TestCheckResourceAttrSet( + "ibm_is_image.isExampleImage", "allowed_use.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_image.isExampleImage", "allowed_use.0.bare_metal_server"), + resource.TestCheckResourceAttrSet( + "ibm_is_image.isExampleImage", "allowed_use.0.instance"), + resource.TestCheckResourceAttrSet( + "ibm_is_image.isExampleImage", "allowed_use.0.api_version"), + resource.TestCheckResourceAttr("ibm_is_image.isExampleImage", "allowed_use.0.bare_metal_server", bareMetalServer), + resource.TestCheckResourceAttr("ibm_is_image.isExampleImage", "allowed_use.0.instance", instance), + resource.TestCheckResourceAttr("ibm_is_image.isExampleImage", "allowed_use.0.api_version", apiVersion), + ), + }, + { + Config: testAccCheckIBMISImageConfigAllowedUse(name, apiVersionUpdate, bareMetalServerUpdate, instanceUpdate), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISImageExists("ibm_is_image.isExampleImage", image), + resource.TestCheckResourceAttr( + "ibm_is_image.isExampleImage", "name", name), + resource.TestCheckResourceAttrSet("ibm_is_image.isExampleImage", "user_data_format"), + resource.TestCheckResourceAttrSet( + "ibm_is_image.isExampleImage", "allowed_use.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_image.isExampleImage", "allowed_use.0.bare_metal_server"), + resource.TestCheckResourceAttrSet( + "ibm_is_image.isExampleImage", "allowed_use.0.instance"), + resource.TestCheckResourceAttrSet( + "ibm_is_image.isExampleImage", "allowed_use.0.api_version"), + resource.TestCheckResourceAttr("ibm_is_image.isExampleImage", "allowed_use.0.bare_metal_server", bareMetalServerUpdate), + resource.TestCheckResourceAttr("ibm_is_image.isExampleImage", "allowed_use.0.instance", instanceUpdate), + resource.TestCheckResourceAttr("ibm_is_image.isExampleImage", "allowed_use.0.api_version", apiVersionUpdate), + ), + }, + }, + }) +} func testAccCheckIBMISImageAccessTagsConfig(name string) string { return fmt.Sprintf(` @@ -329,6 +386,22 @@ func testAccCheckIBMISImageConfig(name string) string { } `, acc.Image_cos_url, name, acc.Image_operating_system) } + +func testAccCheckIBMISImageConfigAllowedUse(name, apiVersion, bareMetalServer, instance string) string { + return fmt.Sprintf(` + resource "ibm_is_image" "isExampleImage" { + href = "%s" + name = "%s" + operating_system = "%s" + allowed_use { + api_version = "%s" + bare_metal_server = "%s" + instance = "%s" + } + } + `, acc.Image_cos_url, name, acc.Image_operating_system, apiVersion, bareMetalServer, instance) +} + func testAccCheckIBMISImageLifecycleConfig(name, deprecationAt, obsolescenceAt string) string { return fmt.Sprintf(` resource "ibm_is_image" "isExampleImage" { diff --git a/ibm/service/vpc/resource_ibm_is_instance.go b/ibm/service/vpc/resource_ibm_is_instance.go index d54c58ae02..54e605bea7 100644 --- a/ibm/service/vpc/resource_ibm_is_instance.go +++ b/ibm/service/vpc/resource_ibm_is_instance.go @@ -810,6 +810,39 @@ func ResourceIBMISInstance() *schema.Resource { Computed: true, Description: "The maximum bandwidth (in megabits per second) for the volume. For this property to be specified, the volume storage_generation must be 2.", }, + + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "The usage constraints to be matched against requested instance or bare metal server properties to determine compatibility.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", "allowed_use.api_version"), + Description: "The API version with which to evaluate the expressions.", + }, + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", "allowed_use.bare_metal_server"), + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume.", + }, + "instance": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", "allowed_use.instance"), + Description: "The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume.", + }, + }, + }, + }, }, }, }, @@ -1541,6 +1574,38 @@ func ResourceIBMISInstance() *schema.Resource { ConflictsWith: []string{isInstanceImage, isInstanceSourceTemplate, "boot_volume.0.snapshot", "boot_volume.0.snapshot_crn", "boot_volume.0.name", "boot_volume.0.encryption", "catalog_offering.0.offering_crn", "catalog_offering.0.version_crn"}, Description: "The unique identifier for this volume", }, + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "The usage constraints to be matched against requested instance or bare metal server properties to determine compatibility.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", "allowed_use.api_version"), + Description: "The API version with which to evaluate the expressions.", + }, + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", "allowed_use.bare_metal_server"), + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume.", + }, + "instance": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", "allowed_use.instance"), + Description: "The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume.", + }, + }, + }, + }, isInstanceVolAttVolAutoDelete: { Type: schema.TypeBool, Optional: true, @@ -2298,6 +2363,11 @@ func instanceCreateByImage(context context.Context, d *schema.ResourceData, meta } volumeattItemPrototypeModel.UserTags = userTagsArray } + //allowed use + if _, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.allowed_use", i)); ok { + allowedUseModel, _ := ResourceIBMIsVolumeAllowedUseMapToVolumeAllowedUsePrototype(d.Get(fmt.Sprintf("volume_prototypes.%d.allowed_use", i)).([]interface{})[0].(map[string]interface{})) + volumeattItemPrototypeModel.AllowedUse = allowedUseModel + } volumeattItemModel.Volume = volumeattItemPrototypeModel @@ -2400,6 +2470,13 @@ func instanceCreateByImage(context context.Context, d *schema.ResourceData, meta volTemplate.Profile = &vpcv1.VolumeProfileIdentity{ Name: &bootProfile, } + //boot volume allowed use + if _, ok := bootvol["allowed_use"]; ok { + allowedUseModel, _ := ResourceIBMIsVolumeAllowedUseMapToVolumeAllowedUsePrototype(bootvol["allowed_use"].([]interface{})[0].(map[string]interface{})) + if allowedUseModel != nil { + volTemplate.AllowedUse = allowedUseModel + } + } var userTags *schema.Set if v, ok := bootvol[isInstanceBootVolumeTags]; ok { userTags = v.(*schema.Set) @@ -2860,6 +2937,12 @@ func instanceCreateByCatalogOffering(context context.Context, d *schema.Resource volumeattItemPrototypeModel.UserTags = userTagsArray } + //allowed use + if _, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.allowed_use", i)); ok { + allowedUseModel, _ := ResourceIBMIsVolumeAllowedUseMapToVolumeAllowedUsePrototype(d.Get(fmt.Sprintf("volume_prototypes.%d.allowed_use", i)).([]interface{})[0].(map[string]interface{})) + volumeattItemPrototypeModel.AllowedUse = allowedUseModel + } + volumeattItemModel.Volume = volumeattItemPrototypeModel volumeatt = append(volumeatt, *volumeattItemModel) @@ -2992,6 +3075,13 @@ func instanceCreateByCatalogOffering(context context.Context, d *schema.Resource volTemplate.Profile = &vpcv1.VolumeProfileIdentity{ Name: &volprof, } + //boot volume allowed use + if _, ok := bootvol["allowed_use"]; ok { + allowedUseModel, _ := ResourceIBMIsVolumeAllowedUseMapToVolumeAllowedUsePrototype(bootvol["allowed_use"].([]interface{})[0].(map[string]interface{})) + if allowedUseModel != nil { + volTemplate.AllowedUse = allowedUseModel + } + } deleteboolIntf := bootvol[isInstanceVolAttVolAutoDelete] deletebool := deleteboolIntf.(bool) instanceproto.BootVolumeAttachment = &vpcv1.VolumeAttachmentPrototypeInstanceByImageContext{ @@ -3427,6 +3517,12 @@ func instanceCreateByTemplate(context context.Context, d *schema.ResourceData, m volumeattItemPrototypeModel.UserTags = userTagsArray } + //allowed use + if _, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.allowed_use", i)); ok { + allowedUseModel, _ := ResourceIBMIsVolumeAllowedUseMapToVolumeAllowedUsePrototype(d.Get(fmt.Sprintf("volume_prototypes.%d.allowed_use", i)).([]interface{})[0].(map[string]interface{})) + volumeattItemPrototypeModel.AllowedUse = allowedUseModel + } + volumeattItemModel.Volume = volumeattItemPrototypeModel volumeatt = append(volumeatt, *volumeattItemModel) @@ -3543,6 +3639,13 @@ func instanceCreateByTemplate(context context.Context, d *schema.ResourceData, m volTemplate.Profile = &vpcv1.VolumeProfileIdentity{ Name: &volprof, } + //boot volume allowed use + if _, ok := bootvol["allowed_use"]; ok { + allowedUseModel, _ := ResourceIBMIsVolumeAllowedUseMapToVolumeAllowedUsePrototype(bootvol["allowed_use"].([]interface{})[0].(map[string]interface{})) + if allowedUseModel != nil { + volTemplate.AllowedUse = allowedUseModel + } + } var userTags *schema.Set if v, ok := bootvol[isInstanceBootVolumeTags]; ok { userTags = v.(*schema.Set) @@ -3990,6 +4093,12 @@ func instanceCreateBySnapshot(context context.Context, d *schema.ResourceData, m } } } + //allowed use + if _, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.allowed_use", i)); ok { + allowedUseModel, _ := ResourceIBMIsVolumeAllowedUseMapToVolumeAllowedUsePrototype(d.Get(fmt.Sprintf("volume_prototypes.%d.allowed_use", i)).([]interface{})[0].(map[string]interface{})) + volumeattItemPrototypeModel.AllowedUse = allowedUseModel + } + volTags := d.Get(fmt.Sprintf("volume_prototypes.%d.volume_tags", i)).(*schema.Set) if volTags != nil && volTags.Len() != 0 { userTagsArray := make([]string, volTags.Len()) @@ -4116,6 +4225,12 @@ func instanceCreateBySnapshot(context context.Context, d *schema.ResourceData, m CRN: &snapshotCrnStr, } } + if _, ok := bootvol["allowed_use"]; ok { + allowedUseModel, _ := ResourceIBMIsVolumeAllowedUseMapToVolumeAllowedUsePrototype(bootvol["allowed_use"].([]interface{})[0].(map[string]interface{})) + if allowedUseModel != nil { + volTemplate.AllowedUse = allowedUseModel + } + } deleteboolIntf := bootvol[isInstanceVolAttVolAutoDelete] deletebool := deleteboolIntf.(bool) instanceproto.BootVolumeAttachment = &vpcv1.VolumeAttachmentPrototypeInstanceBySourceSnapshotContext{ @@ -4571,6 +4686,12 @@ func instanceCreateByVolume(context context.Context, d *schema.ResourceData, met volumeattItemPrototypeModel.UserTags = userTagsArray } + //allowed use + if _, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.allowed_use", i)); ok { + allowedUseModel, _ := ResourceIBMIsVolumeAllowedUseMapToVolumeAllowedUsePrototype(d.Get(fmt.Sprintf("volume_prototypes.%d.allowed_use", i)).([]interface{})[0].(map[string]interface{})) + volumeattItemPrototypeModel.AllowedUse = allowedUseModel + } + volumeattItemModel.Volume = volumeattItemPrototypeModel volumeatt = append(volumeatt, *volumeattItemModel) @@ -5106,7 +5227,6 @@ func isRestartStartAction(instanceC *vpcv1.VpcV1, id string, d *schema.ResourceD select { case <-subticker.C: - log.Println("Instance is still in starting state, force retry by restarting the instance.") actiontype := "stop" createinsactoptions := &vpcv1.CreateInstanceActionOptions{ InstanceID: &id, @@ -5723,6 +5843,12 @@ func instanceGet(context context.Context, d *schema.ResourceData, meta interface if vol.UserTags != nil { bootVol[isInstanceBootVolumeTags] = vol.UserTags } + if vol.AllowedUse != nil { + usageConstraintList := []map[string]interface{}{} + modelMap, _ := ResourceceIBMIsVolumeAllowedUseToMap(vol.AllowedUse) + usageConstraintList = append(usageConstraintList, modelMap) + bootVol["allowed_use"] = usageConstraintList + } } } bootVolList = append(bootVolList, bootVol) @@ -6558,6 +6684,48 @@ func instanceUpdate(context context.Context, d *schema.ResourceData, meta interf return tfErr.GetDiag() } } + + bootVolAllowedUse := "boot_volume.0.allowed_use" + if d.HasChange(bootVolAllowedUse) && !d.IsNewResource() { + volId := d.Get("boot_volume.0.volume_id").(string) + allowedUseModel, _ := ResourceIBMIsInstanceMapToVolumeAllowedUsePatchPrototype(d.Get("boot_volume.0.allowed_use").([]interface{})[0].(map[string]interface{})) + optionsget := &vpcv1.GetVolumeOptions{ + ID: &volId, + } + _, response, err := instanceC.GetVolumeWithContext(context, optionsget) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetVolumeWithContext failed: %s", err.Error()), "ibm_is_instance", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + eTag := response.Headers.Get("ETag") + options := &vpcv1.UpdateVolumeOptions{ + ID: &volId, + } + options.IfMatch = &eTag + volumeAllowedUsePatchModel := &vpcv1.VolumePatch{} + volumeAllowedUsePatchModel.AllowedUse = allowedUseModel + volumeNamePatch, err := volumeAllowedUsePatchModel.AsPatch() + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("bootvolumeTagsPatchModel.AsPatch() failed: %s", err.Error()), "ibm_is_instance", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + options.VolumePatch = volumeNamePatch + vol, _, err := instanceC.UpdateVolumeWithContext(context, options) + if vol == nil || err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("UpdateVolumeWithContext failed: %s", err.Error()), "ibm_is_instance", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + _, err = isWaitForVolumeAvailable(instanceC, volId, d.Timeout(schema.TimeoutCreate)) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("isWaitForVolumeAvailable failed: %s", err.Error()), "ibm_is_instance", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + } + bootVolTags := "boot_volume.0.tags" if d.HasChange(bootVolTags) && !d.IsNewResource() { var userTags *schema.Set @@ -7760,7 +7928,6 @@ func isRestartStopAction(instanceC *vpcv1.VpcV1, id string, d *schema.ResourceDa select { case <-subticker.C: - log.Println("Instance is still in stopping state, retrying to stop with -force") actiontype := "stop" createinsactoptions := &vpcv1.CreateInstanceActionOptions{ InstanceID: &id, @@ -8388,6 +8555,7 @@ func volumesEqual(oldVol, newVol map[string]interface{}) bool { "volume_encryption_key", "volume_tags", "volume_bandwidth", + "allowed_use", } for _, field := range fieldsToCompare { @@ -8405,6 +8573,12 @@ func volumesEqual(oldVol, newVol map[string]interface{}) bool { } continue } + if field == "allowed_use" { + if !compareAllowedUse(oldVal, newVal) { + return false + } + continue + } if !reflect.DeepEqual(oldVal, newVal) { return false @@ -8581,6 +8755,30 @@ func handleVolumePrototypesUpdate(d *schema.ResourceData, instanceC *vpcv1.VpcV1 volumePatchModel.UserTags = userTagsArray volchanged = true } + + // Compare allowed_use if present + allowedUseOld, oldOk := oldVol["allowed_use"].([]interface{}) + allowedUseNew, newOk := newVol["allowed_use"].([]interface{}) + if oldOk == newOk && oldOk && newOk { + if len(allowedUseOld) == len(allowedUseNew) && len(allowedUseOld) > 0 && len(allowedUseNew) > 0 { + oldallowedUse := allowedUseOld[0].(map[string]interface{}) + newallowedUse := allowedUseNew[0].(map[string]interface{}) + model := &vpcv1.VolumeAllowedUsePatch{} + if oldallowedUse["api_version"] != newallowedUse["api_version"] { + model.ApiVersion = core.StringPtr(oldallowedUse["api_version"].(string)) + } + if oldallowedUse["bare_metal_server"] != newallowedUse["bare_metal_server"] { + model.BareMetalServer = core.StringPtr(oldallowedUse["bare_metal_server"].(string)) + } + if oldallowedUse["instance"] != newallowedUse["instance"] { + model.Instance = core.StringPtr(oldallowedUse["instance"].(string)) + } + if model != nil { + volumePatchModel.AllowedUse = model + volchanged = true + } + } + } if volchanged { volumePatch, err := volumePatchModel.AsPatch() if err != nil { @@ -8676,6 +8874,15 @@ func handleVolumePrototypesUpdate(d *schema.ResourceData, instanceC *vpcv1.VpcV1 volAtt.Iops = &iops } } + + //allowed use + if _, ok := d.GetOk(fmt.Sprintf("volume_prototypes.%d.allowed_use", i)); ok { + allowedUseModel, err := ResourceIBMIsVolumeAllowedUseMapToVolumeAllowedUsePrototype(d.Get(fmt.Sprintf("volume_prototypes.%d.allowed_use", i)).([]interface{})[0].(map[string]interface{})) + if err != nil { + return err + } + volAtt.AllowedUse = allowedUseModel + } createvolattoptions.Volume = volAtt newVolume, _, err := instanceC.CreateInstanceVolumeAttachment(createvolattoptions) if err != nil { @@ -8725,16 +8932,31 @@ func hasVolumeChanged(d *schema.ResourceData, newIndex int, oldVol, newVol map[s "volume_capacity", "volume_profile", "volume_bandwidth", + "allowed_use", } // Compare standard fields for _, field := range fieldsToCompare { - oldVal := oldVol[field] - newVal := newVol[field] - if !reflect.DeepEqual(oldVal, newVal) { + oldVal, oldOk := oldVol[field] + newVal, newOk := newVol[field] + + if oldOk != newOk { return true } + + if oldOk && newOk { + if field == "allowed_use" { + if !compareAllowedUse(oldVal, newVal) { + return true + } + continue + } + + if !reflect.DeepEqual(oldVal, newVal) { + return true + } + } } // Compare delete_volume_on_instance_delete @@ -8762,6 +8984,36 @@ func hasVolumeChanged(d *schema.ResourceData, newIndex int, oldVol, newVol map[s return false } +// Helper function to compare allowed use +func compareAllowedUse(old, new interface{}) bool { + if old == nil && new == nil { + return true + } + if old == nil || new == nil { + return false + } + + oldSchema, okOld := old.(*map[string]interface{}) + newSchema, okNew := new.(*map[string]interface{}) + + if !okOld || !okNew { + // Ensure the old and new are actually maps + // fmt.Println("Error: Provided values are not of expected type") + return false + } + + // Compare each field in the schema + // Fields: api_version, bare_metal_server, instance + for key := range *oldSchema { + if !reflect.DeepEqual((*oldSchema)[key], (*newSchema)[key]) { + // If any field differs, return false + return false + } + } + + return true +} + func isTieredProfile(profile string) bool { switch profile { case "general-purpose", "10iops-tier", "5iops-tier": @@ -8853,6 +9105,15 @@ func setVolumePrototypesInState(d *schema.ResourceData, instance *vpcv1.Instance vol["volume_bandwidth"] = volumeRef.Bandwidth vol["volume_crn"] = *volume.Volume.CRN vol["volume_resource_type"] = *volume.Volume.ResourceType + if volumeRef.AllowedUse != nil { + allowedUseList := []map[string]interface{}{} + modelMap, _ := ResourceceIBMIsVolumeAllowedUseToMap(volumeRef.AllowedUse) + allowedUseList = append(allowedUseList, modelMap) + vol["allowed_use"] = allowedUseList + } + if volumeRef.SourceSnapshot != nil && volumeRef.SourceSnapshot.ID != nil { + vol["volume_source_snapshot"] = *volumeRef.SourceSnapshot.ID + } } volumeAttRef, _, err := instanceC.GetInstanceVolumeAttachment(getInstanceVolumeAttachmentOptions) diff --git a/ibm/service/vpc/resource_ibm_is_instance_template.go b/ibm/service/vpc/resource_ibm_is_instance_template.go index 5a74cd401c..38d3bb26c5 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_template.go +++ b/ibm/service/vpc/resource_ibm_is_instance_template.go @@ -70,6 +70,9 @@ const ( isInstanceTemplateCatalogOfferingOfferingCrn = "offering_crn" isInstanceTemplateCatalogOfferingVersionCrn = "version_crn" isInstanceTemplateCatalogOfferingPlanCrn = "plan_crn" + + // Source snapshot support + isInstanceTemplateSourceSnapshot = "source_snapshot" ) func ResourceIBMISInstanceTemplate() *schema.Resource { @@ -412,6 +415,12 @@ func ResourceIBMISInstanceTemplate() *schema.Resource { ForceNew: true, Description: "The maximum bandwidth (in megabits per second) for the volume. For this property to be specified, the volume storage_generation must be 2.", }, + "source_snapshot": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The snapshot to use as a source for the volume's data.", + }, isInstanceTemplateVolAttVolEncryptionKey: { Type: schema.TypeString, Optional: true, @@ -426,6 +435,42 @@ func ResourceIBMISInstanceTemplate() *schema.Resource { Set: flex.ResourceIBMVPCHash, Description: "UserTags for the volume instance", }, + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + ForceNew: true, + Computed: true, + Description: "The usage constraints to be matched against requested instance or bare metal server properties to determine compatibility.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", "allowed_use.api_version"), + Description: "The API version with which to evaluate the expressions.", + }, + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", "allowed_use.bare_metal_server"), + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume.", + }, + "instance": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", "allowed_use.instance"), + Description: "The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume.", + }, + }, + }, + }, }, }, }, @@ -437,7 +482,7 @@ func ResourceIBMISInstanceTemplate() *schema.Resource { Type: schema.TypeList, MinItems: 0, MaxItems: 1, - ExactlyOneOf: []string{isInstanceTemplateCatalogOffering, isInstanceTemplateImage}, + ExactlyOneOf: []string{isInstanceTemplateCatalogOffering, isInstanceTemplateImage, "boot_volume.0.source_snapshot"}, Optional: true, ForceNew: true, Description: "The catalog offering or offering version to use when provisioning this virtual server instance template. If an offering is specified, the latest version of that offering will be used. The specified offering or offering version may be in a different account in the same enterprise, subject to IAM policies.", @@ -1148,7 +1193,7 @@ func ResourceIBMISInstanceTemplate() *schema.Resource { isInstanceTemplateImage: { Type: schema.TypeString, ForceNew: true, - ExactlyOneOf: []string{isInstanceTemplateCatalogOffering, isInstanceTemplateImage}, + ExactlyOneOf: []string{isInstanceTemplateCatalogOffering, isInstanceTemplateImage, "boot_volume.0.source_snapshot"}, Optional: true, Description: "image name", }, @@ -1202,6 +1247,53 @@ func ResourceIBMISInstanceTemplate() *schema.Resource { Optional: true, Computed: true, }, + isInstanceTemplateSourceSnapshot: { + Type: schema.TypeString, + ForceNew: true, + ExactlyOneOf: []string{ + isInstanceTemplateCatalogOffering, + isInstanceTemplateImage, + "boot_volume.0.source_snapshot", + }, + Optional: true, + Description: "The snapshot to create this virtual server instance template from", + }, + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + ForceNew: true, + Description: "The usage constraints to be matched against requested instance or bare metal server properties to determine compatibility.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", "allowed_use.api_version"), + Description: "The API version with which to evaluate the expressions.", + }, + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", "allowed_use.bare_metal_server"), + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume.", + }, + "instance": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", "allowed_use.instance"), + Description: "The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume.", + }, + }, + }, + }, }, }, }, @@ -1328,18 +1420,27 @@ func resourceIBMisInstanceTemplateCreate(context context.Context, d *schema.Reso name := d.Get(isInstanceTemplateName).(string) vpcID := d.Get(isInstanceTemplateVPC).(string) zone := d.Get(isInstanceTemplateZone).(string) - image := d.Get(isInstanceTemplateImage).(string) + // Determine creation method based on what's provided if catalogOfferingOk, ok := d.GetOk(isInstanceTemplateCatalogOffering); ok { + // Existing catalog offering logic catalogOffering := catalogOfferingOk.([]interface{})[0].(map[string]interface{}) offeringCrn, _ := catalogOffering[isInstanceTemplateCatalogOfferingOfferingCrn].(string) versionCrn, _ := catalogOffering[isInstanceTemplateCatalogOfferingVersionCrn].(string) planCrn, _ := catalogOffering[isInstanceTemplateCatalogOfferingPlanCrn].(string) + err := instanceTemplateCreateByCatalogOffering(context, d, meta, profile, name, vpcID, zone, offeringCrn, versionCrn, planCrn) if err != nil { return err } + } else if sourceSnapshotID, ok := d.GetOk("boot_volume.0.source_snapshot"); ok { + sourceSnapshotIDStr := sourceSnapshotID.(string) + err := instanceTemplateCreateBySourceSnapshot(context, d, meta, profile, name, vpcID, zone, sourceSnapshotIDStr) + if err != nil { + return err + } } else { + image := d.Get(isInstanceTemplateImage).(string) err := instanceTemplateCreate(context, d, meta, profile, name, vpcID, zone, image) if err != nil { return err @@ -1348,7 +1449,6 @@ func resourceIBMisInstanceTemplateCreate(context context.Context, d *schema.Reso return resourceIBMisInstanceTemplateRead(context, d, meta) } - func resourceIBMisInstanceTemplateRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { ID := d.Id() err := instanceTemplateGet(context, d, meta, ID) @@ -1387,7 +1487,7 @@ func resourceIBMisInstanceTemplateExists(d *schema.ResourceData, meta interface{ return ok, err } -func instanceTemplateCreateByCatalogOffering(context context.Context, d *schema.ResourceData, meta interface{}, profile, name, vpcID, zone, offeringCrn, versionCrn, planCrn string) diag.Diagnostics { +func instanceTemplateCreateBySourceSnapshot(context context.Context, d *schema.ResourceData, meta interface{}, profile, name, vpcID, zone, sourceSnapshotID string) diag.Diagnostics { sess, err := vpcClient(meta) if err != nil { tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "create", "initialize-client") @@ -1395,7 +1495,7 @@ func instanceTemplateCreateByCatalogOffering(context context.Context, d *schema. return tfErr.GetDiag() } - instanceproto := &vpcv1.InstanceTemplatePrototypeInstanceTemplateByCatalogOffering{ + instanceproto := &vpcv1.InstanceTemplatePrototypeInstanceTemplateBySourceSnapshot{ Zone: &vpcv1.ZoneIdentity{ Name: &zone, }, @@ -1406,6 +1506,11 @@ func instanceTemplateCreateByCatalogOffering(context context.Context, d *schema. ID: &vpcID, }, } + + if name != "" { + instanceproto.Name = &name + } + // cluster changes if clusterNetworkAttachmentOk, ok := d.GetOk("cluster_network_attachments"); ok { clusterNetworkAttachmentList := clusterNetworkAttachmentOk.([]interface{}) @@ -1425,47 +1530,25 @@ func instanceTemplateCreateByCatalogOffering(context context.Context, d *schema. if _, ok := d.GetOkExists("enable_secure_boot"); ok { instanceproto.EnableSecureBoot = core.BoolPtr(d.Get("enable_secure_boot").(bool)) } - var planOffering *vpcv1.CatalogOfferingVersionPlanIdentityCatalogOfferingVersionPlanByCRN - planOffering = nil - if planCrn != "" { - planOffering = &vpcv1.CatalogOfferingVersionPlanIdentityCatalogOfferingVersionPlanByCRN{ - CRN: &planCrn, - } - } - if offeringCrn != "" { - catalogOffering := &vpcv1.InstanceCatalogOfferingPrototypeCatalogOfferingByOffering{ - Offering: &vpcv1.CatalogOfferingIdentityCatalogOfferingByCRN{ - CRN: &offeringCrn, - }, - } - if planOffering != nil { - catalogOffering.Plan = planOffering - } - instanceproto.CatalogOffering = catalogOffering - } - if versionCrn != "" { - catalogOffering := &vpcv1.InstanceCatalogOfferingPrototypeCatalogOfferingByVersion{ - Version: &vpcv1.CatalogOfferingVersionIdentityCatalogOfferingVersionByCRN{ - CRN: &versionCrn, - }, - } - if planOffering != nil { - catalogOffering.Plan = planOffering + + metadataServiceEnabled := d.Get(isInstanceTemplateMetadataServiceEnabled).(bool) + if metadataServiceEnabled { + instanceproto.MetadataService = &vpcv1.InstanceMetadataServicePrototype{ + Enabled: &metadataServiceEnabled, } - instanceproto.CatalogOffering = catalogOffering } - if name != "" { - instanceproto.Name = &name + if metadataService := GetInstanceTemplateMetadataServiceOptions(d); metadataService != nil { + instanceproto.MetadataService = metadataService } // vni if networkattachmentsintf, ok := d.GetOk("network_attachments"); ok { networkAttachments := []vpcv1.InstanceNetworkAttachmentPrototype{} for i, networkAttachmentsItem := range networkattachmentsintf.([]interface{}) { - allowipspoofing := fmt.Sprintf("network_attachments.%d.allow_ip_spoofing", i) - autodelete := fmt.Sprintf("network_attachments.%d.auto_delete", i) - enablenat := fmt.Sprintf("network_attachments.%d.enable_infrastructure_nat", i) + allowipspoofing := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.allow_ip_spoofing", i) + autodelete := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.auto_delete", i) + enablenat := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.enable_infrastructure_nat", i) networkAttachmentsItemModel, err := resourceIBMIsInstanceTemplateMapToInstanceNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat, d, networkAttachmentsItem.(map[string]interface{})) if err != nil { return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "create", "parse-network_attachments").GetDiag() @@ -1486,17 +1569,6 @@ func instanceTemplateCreateByCatalogOffering(context context.Context, d *schema. instanceproto.PrimaryNetworkAttachment = primaryNetworkAttachmentModel } - metadataServiceEnabled := d.Get(isInstanceTemplateMetadataServiceEnabled).(bool) - if metadataServiceEnabled { - instanceproto.MetadataService = &vpcv1.InstanceMetadataServicePrototype{ - Enabled: &metadataServiceEnabled, - } - } - - if metadataService := GetInstanceTemplateMetadataServiceOptions(d); metadataService != nil { - instanceproto.MetadataService = metadataService - } - if defaultTrustedProfileTargetIntf, ok := d.GetOk(isInstanceDefaultTrustedProfileTarget); ok { defaultTrustedProfiletarget := defaultTrustedProfileTargetIntf.(string) @@ -1537,6 +1609,32 @@ func instanceTemplateCreateByCatalogOffering(context context.Context, d *schema. instanceproto.PlacementTarget = dHostGrpPlaementTarget } + if resAffinity, ok := d.GetOk(isReservationAffinity); ok { + resAff := resAffinity.([]interface{})[0].(map[string]interface{}) + var resAffinity = &vpcv1.InstanceReservationAffinityPrototype{} + policy, ok := resAff["policy"] + policyStr := policy.(string) + if policyStr != "" && ok { + resAffinity.Policy = &policyStr + } + poolIntf, okPool := resAff[isReservationAffinityPool] + if okPool && poolIntf != nil && poolIntf.([]interface{}) != nil && len(poolIntf.([]interface{})) > 0 { + pool := poolIntf.([]interface{})[0].(map[string]interface{}) + id, okId := pool["id"] + if okId { + idStr, ok := id.(string) + if idStr != "" && ok { + var resAffPool = make([]vpcv1.ReservationIdentityIntf, 1) + resAffPool[0] = &vpcv1.ReservationIdentity{ + ID: &idStr, + } + resAffinity.Pool = resAffPool + } + } + } + instanceproto.ReservationAffinity = resAffinity + } + if placementGroupInf, ok := d.GetOk(isPlacementTargetPlacementGroup); ok { placementGrpStr := placementGroupInf.(string) placementGrp := &vpcv1.InstancePlacementTargetPrototypePlacementGroupIdentity{ @@ -1553,7 +1651,11 @@ func instanceTemplateCreateByCatalogOffering(context context.Context, d *schema. // BOOT VOLUME ATTACHMENT for instance template if boot, ok := d.GetOk(isInstanceTemplateBootVolume); ok { bootvol := boot.([]interface{})[0].(map[string]interface{}) - var volTemplate = &vpcv1.VolumePrototypeInstanceByImageContext{} + var volTemplate = &vpcv1.VolumePrototypeInstanceBySourceSnapshotContext{ + SourceSnapshot: &vpcv1.SnapshotIdentityByID{ + ID: &sourceSnapshotID, + }, + } name, ok := bootvol[isInstanceTemplateBootName] namestr := name.(string) if ok && namestr != "" { @@ -1608,7 +1710,13 @@ func instanceTemplateCreateByCatalogOffering(context context.Context, d *schema. deleteVolumeOption = deleteVolume.(bool) } - instanceproto.BootVolumeAttachment = &vpcv1.VolumeAttachmentPrototypeInstanceByImageContext{ + //allowed use + if bootvol["allowed_use"] != nil && len(bootvol["allowed_use"].([]interface{})) > 0 { + AllowedUseModel, _ := ResourceIBMIsVolumeAllowedUseMapToVolumeAllowedUsePrototype(bootvol["allowed_use"].([]interface{})[0].(map[string]interface{})) + volTemplate.AllowedUse = AllowedUseModel + } + + instanceproto.BootVolumeAttachment = &vpcv1.VolumeAttachmentPrototypeInstanceBySourceSnapshotContext{ DeleteVolumeOnInstanceDelete: &deleteVolumeOption, Volume: volTemplate, } @@ -1628,7 +1736,7 @@ func instanceTemplateCreateByCatalogOffering(context context.Context, d *schema. volIdStr := vol[isInstanceTemplateVolAttVol].(string) if volIdStr != "" { - volInterface.Volume = &vpcv1.VolumeAttachmentPrototypeVolume{ + volInterface.Volume = &vpcv1.VolumeAttachmentPrototypeVolumeVolumeIdentity{ ID: &volIdStr, } } else { @@ -1643,14 +1751,28 @@ func instanceTemplateCreateByCatalogOffering(context context.Context, d *schema. }, Capacity: &capacity, } - // bandwidth changes + + //bandwidth changes bandwidth := int64(newvol["bandwidth"].(int)) if bandwidth != int64(0) { volPrototype.Bandwidth = &bandwidth } - iops := int64(newvol[isInstanceTemplateVolAttVolIops].(int)) + // source_snapshot + sourceSnapshot := newvol["source_snapshot"].(string) + if sourceSnapshot != "" { + volPrototype.SourceSnapshot = &vpcv1.SnapshotIdentity{ + ID: &sourceSnapshot, + } + } + + //allowed use + if newvol["allowed_use"] != nil && len(newvol["allowed_use"].([]interface{})) > 0 { + AllowedUseModel, _ := ResourceIBMIsVolumeAllowedUseMapToVolumeAllowedUsePrototype(newvol["allowed_use"].([]interface{})[0].(map[string]interface{})) + volPrototype.AllowedUse = AllowedUseModel + } + iops := int64(newvol[isInstanceTemplateVolAttVolIops].(int)) encryptionKey := newvol[isInstanceTemplateVolAttVolEncryptionKey].(string) if iops != 0 { @@ -1828,10 +1950,6 @@ func instanceTemplateCreateByCatalogOffering(context context.Context, d *schema. reservedIpAutoDelete = primip[isInstanceTemplateNicReservedIpAutoDelete].(bool) okAuto = true } - // reservedipautodeleteok, okAuto = primip[isInstanceTemplateNicReservedIpAutoDelete] - // if okAuto { - // reservedIpAutoDelete = reservedipautodeleteok.(bool) - // } } if PrimaryIpv4Address != "" && reservedIpAddress != "" && PrimaryIpv4Address != reservedIpAddress { err = fmt.Errorf("Error creating instance template, network_interfaces error, use either primary_ipv4_address(%s) or primary_ip.0.address(%s)", PrimaryIpv4Address, reservedIpAddress) @@ -1893,7 +2011,6 @@ func instanceTemplateCreateByCatalogOffering(context context.Context, d *schema. instanceproto.ResourceGroup = &vpcv1.ResourceGroupIdentity{ ID: &grpstr, } - } options := &vpcv1.CreateInstanceTemplateOptions{ @@ -1906,22 +2023,36 @@ func instanceTemplateCreateByCatalogOffering(context context.Context, d *schema. log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) return tfErr.GetDiag() } - instance := instanceIntf.(*vpcv1.InstanceTemplate) - d.SetId(*instance.ID) + var instanceID string + + switch instance := instanceIntf.(type) { + case *vpcv1.InstanceTemplate: + instanceID = *instance.ID + case *vpcv1.InstanceTemplateInstanceByImageInstanceTemplateContext: + instanceID = *instance.ID + case *vpcv1.InstanceTemplateInstanceBySourceSnapshotInstanceTemplateContext: + instanceID = *instance.ID + case *vpcv1.InstanceTemplateInstanceByCatalogOfferingInstanceTemplateContext: + instanceID = *instance.ID + default: + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("unexpected instance template type: %T", instanceIntf), "ibm_is_instance_template", "create") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(instanceID) return nil } -func instanceTemplateCreate(context context.Context, d *schema.ResourceData, meta interface{}, profile, name, vpcID, zone, image string) diag.Diagnostics { +func instanceTemplateCreateByCatalogOffering(context context.Context, d *schema.ResourceData, meta interface{}, profile, name, vpcID, zone, offeringCrn, versionCrn, planCrn string) diag.Diagnostics { sess, err := vpcClient(meta) if err != nil { tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "create", "initialize-client") log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) return tfErr.GetDiag() } - instanceproto := &vpcv1.InstanceTemplatePrototype{ - Image: &vpcv1.ImageIdentity{ - ID: &image, - }, + + instanceproto := &vpcv1.InstanceTemplatePrototypeInstanceTemplateByCatalogOffering{ Zone: &vpcv1.ZoneIdentity{ Name: &zone, }, @@ -1932,9 +2063,6 @@ func instanceTemplateCreate(context context.Context, d *schema.ResourceData, met ID: &vpcID, }, } - if name != "" { - instanceproto.Name = &name - } // cluster changes if clusterNetworkAttachmentOk, ok := d.GetOk("cluster_network_attachments"); ok { clusterNetworkAttachmentList := clusterNetworkAttachmentOk.([]interface{}) @@ -1954,25 +2082,47 @@ func instanceTemplateCreate(context context.Context, d *schema.ResourceData, met if _, ok := d.GetOkExists("enable_secure_boot"); ok { instanceproto.EnableSecureBoot = core.BoolPtr(d.Get("enable_secure_boot").(bool)) } - metadataServiceEnabled := d.Get(isInstanceTemplateMetadataServiceEnabled).(bool) - if metadataServiceEnabled { - instanceproto.MetadataService = &vpcv1.InstanceMetadataServicePrototype{ - Enabled: &metadataServiceEnabled, + var planOffering *vpcv1.CatalogOfferingVersionPlanIdentityCatalogOfferingVersionPlanByCRN + planOffering = nil + if planCrn != "" { + planOffering = &vpcv1.CatalogOfferingVersionPlanIdentityCatalogOfferingVersionPlanByCRN{ + CRN: &planCrn, + } + } + if offeringCrn != "" { + catalogOffering := &vpcv1.InstanceCatalogOfferingPrototypeCatalogOfferingByOffering{ + Offering: &vpcv1.CatalogOfferingIdentityCatalogOfferingByCRN{ + CRN: &offeringCrn, + }, + } + if planOffering != nil { + catalogOffering.Plan = planOffering + } + instanceproto.CatalogOffering = catalogOffering + } + if versionCrn != "" { + catalogOffering := &vpcv1.InstanceCatalogOfferingPrototypeCatalogOfferingByVersion{ + Version: &vpcv1.CatalogOfferingVersionIdentityCatalogOfferingVersionByCRN{ + CRN: &versionCrn, + }, + } + if planOffering != nil { + catalogOffering.Plan = planOffering } + instanceproto.CatalogOffering = catalogOffering } - if metadataService := GetInstanceTemplateMetadataServiceOptions(d); metadataService != nil { - instanceproto.MetadataService = metadataService + if name != "" { + instanceproto.Name = &name } // vni - if networkattachmentsintf, ok := d.GetOk("network_attachments"); ok { networkAttachments := []vpcv1.InstanceNetworkAttachmentPrototype{} for i, networkAttachmentsItem := range networkattachmentsintf.([]interface{}) { - allowipspoofing := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.allow_ip_spoofing", i) - autodelete := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.auto_delete", i) - enablenat := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.enable_infrastructure_nat", i) + allowipspoofing := fmt.Sprintf("network_attachments.%d.allow_ip_spoofing", i) + autodelete := fmt.Sprintf("network_attachments.%d.auto_delete", i) + enablenat := fmt.Sprintf("network_attachments.%d.enable_infrastructure_nat", i) networkAttachmentsItemModel, err := resourceIBMIsInstanceTemplateMapToInstanceNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat, d, networkAttachmentsItem.(map[string]interface{})) if err != nil { return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "create", "parse-network_attachments").GetDiag() @@ -1993,6 +2143,17 @@ func instanceTemplateCreate(context context.Context, d *schema.ResourceData, met instanceproto.PrimaryNetworkAttachment = primaryNetworkAttachmentModel } + metadataServiceEnabled := d.Get(isInstanceTemplateMetadataServiceEnabled).(bool) + if metadataServiceEnabled { + instanceproto.MetadataService = &vpcv1.InstanceMetadataServicePrototype{ + Enabled: &metadataServiceEnabled, + } + } + + if metadataService := GetInstanceTemplateMetadataServiceOptions(d); metadataService != nil { + instanceproto.MetadataService = metadataService + } + if defaultTrustedProfileTargetIntf, ok := d.GetOk(isInstanceDefaultTrustedProfileTarget); ok { defaultTrustedProfiletarget := defaultTrustedProfileTargetIntf.(string) @@ -2032,31 +2193,6 @@ func instanceTemplateCreate(context context.Context, d *schema.ResourceData, met } instanceproto.PlacementTarget = dHostGrpPlaementTarget } - if resAffinity, ok := d.GetOk(isReservationAffinity); ok { - resAff := resAffinity.([]interface{})[0].(map[string]interface{}) - var resAffinity = &vpcv1.InstanceReservationAffinityPrototype{} - policy, ok := resAff["policy"] - policyStr := policy.(string) - if policyStr != "" && ok { - resAffinity.Policy = &policyStr - } - poolIntf, okPool := resAff[isReservationAffinityPool] - if okPool && poolIntf != nil && poolIntf.([]interface{}) != nil && len(poolIntf.([]interface{})) > 0 { - pool := poolIntf.([]interface{})[0].(map[string]interface{}) - id, okId := pool["id"] - if okId { - idStr, ok := id.(string) - if idStr != "" && ok { - var resAffPool = make([]vpcv1.ReservationIdentityIntf, 1) - resAffPool[0] = &vpcv1.ReservationIdentity{ - ID: &idStr, - } - resAffinity.Pool = resAffPool - } - } - } - instanceproto.ReservationAffinity = resAffinity - } if placementGroupInf, ok := d.GetOk(isPlacementTargetPlacementGroup); ok { placementGrpStr := placementGroupInf.(string) @@ -2100,6 +2236,7 @@ func instanceTemplateCreate(context context.Context, d *schema.ResourceData, met volBandwith64 := int64(volBandwith) volTemplate.Bandwidth = &volBandwith64 } + volcap := bootvol["size"].(int) volcapint64 := int64(volcap) if volcap == 0 { @@ -2129,6 +2266,553 @@ func instanceTemplateCreate(context context.Context, d *schema.ResourceData, met deleteVolumeOption = deleteVolume.(bool) } + //allowed use + if bootvol["allowed_use"] != nil && len(bootvol["allowed_use"].([]interface{})) > 0 { + AllowedUseModel, _ := ResourceIBMIsVolumeAllowedUseMapToVolumeAllowedUsePrototype(bootvol["allowed_use"].([]interface{})[0].(map[string]interface{})) + volTemplate.AllowedUse = AllowedUseModel + } + + instanceproto.BootVolumeAttachment = &vpcv1.VolumeAttachmentPrototypeInstanceByImageContext{ + DeleteVolumeOnInstanceDelete: &deleteVolumeOption, + Volume: volTemplate, + } + } + + // Handle volume attachments + if volsintf, ok := d.GetOk(isInstanceTemplateVolumeAttachments); ok { + vols := volsintf.([]interface{}) + var intfs []vpcv1.VolumeAttachmentPrototype + for _, resource := range vols { + vol := resource.(map[string]interface{}) + volInterface := &vpcv1.VolumeAttachmentPrototype{} + deleteVolBool := vol[isInstanceTemplateVolumeDeleteOnInstanceDelete].(bool) + volInterface.DeleteVolumeOnInstanceDelete = &deleteVolBool + attachmentnamestr := vol[isInstanceTemplateVolAttachmentName].(string) + volInterface.Name = &attachmentnamestr + volIdStr := vol[isInstanceTemplateVolAttVol].(string) + + if volIdStr != "" { + volInterface.Volume = &vpcv1.VolumeAttachmentPrototypeVolume{ + ID: &volIdStr, + } + } else { + newvolintf := vol[isInstanceTemplateVolAttVolPrototype].([]interface{})[0] + newvol := newvolintf.(map[string]interface{}) + profileName := newvol[isInstanceTemplateVolAttVolProfile].(string) + capacity := int64(newvol[isInstanceTemplateVolAttVolCapacity].(int)) + + volPrototype := &vpcv1.VolumeAttachmentPrototypeVolumeVolumePrototypeInstanceContext{ + Profile: &vpcv1.VolumeProfileIdentity{ + Name: &profileName, + }, + Capacity: &capacity, + } + // bandwidth changes + bandwidth := int64(newvol["bandwidth"].(int)) + if bandwidth != int64(0) { + volPrototype.Bandwidth = &bandwidth + } + + // source_snapshot + sourceSnapshot := newvol["source_snapshot"].(string) + if sourceSnapshot != "" { + volPrototype.SourceSnapshot = &vpcv1.SnapshotIdentity{ + ID: &sourceSnapshot, + } + } + + //allowed use + if newvol["allowed_use"] != nil && len(newvol["allowed_use"].([]interface{})) > 0 { + AllowedUseModel, _ := ResourceIBMIsVolumeAllowedUseMapToVolumeAllowedUsePrototype(newvol["allowed_use"].([]interface{})[0].(map[string]interface{})) + volPrototype.AllowedUse = AllowedUseModel + } + + iops := int64(newvol[isInstanceTemplateVolAttVolIops].(int)) + + encryptionKey := newvol[isInstanceTemplateVolAttVolEncryptionKey].(string) + + if iops != 0 { + volPrototype.Iops = &iops + } + + if encryptionKey != "" { + volPrototype.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ + CRN: &encryptionKey, + } + } + var userTags *schema.Set + if v, ok := newvol[isInstanceTemplateVolAttTags]; ok { + userTags = v.(*schema.Set) + if userTags != nil && userTags.Len() != 0 { + userTagsArray := make([]string, userTags.Len()) + for i, userTag := range userTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + volPrototype.UserTags = userTagsArray + } + } + volInterface.Volume = volPrototype + } + + intfs = append(intfs, *volInterface) + } + instanceproto.VolumeAttachments = intfs + } + + // Handle primary network interface + if primnicintf, ok := d.GetOk(isInstanceTemplatePrimaryNetworkInterface); ok { + primnic := primnicintf.([]interface{})[0].(map[string]interface{}) + subnetintf, _ := primnic[isInstanceTemplateNicSubnet] + subnetintfstr := subnetintf.(string) + var primnicobj = &vpcv1.NetworkInterfacePrototype{} + primnicobj.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetintfstr, + } + + if name, ok := primnic[isInstanceTemplateNicName]; ok { + namestr := name.(string) + if namestr != "" { + primnicobj.Name = &namestr + } + } + allowIPSpoofing, ok := primnic[isInstanceTemplateNicAllowIPSpoofing] + allowIPSpoofingbool := allowIPSpoofing.(bool) + if ok { + primnicobj.AllowIPSpoofing = &allowIPSpoofingbool + } + + secgrpintf, ok := primnic[isInstanceTemplateNicSecurityGroups] + if ok { + secgrpSet := secgrpintf.(*schema.Set) + if secgrpSet.Len() != 0 { + var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) + for i, secgrpIntf := range secgrpSet.List() { + secgrpIntfstr := secgrpIntf.(string) + secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &secgrpIntfstr, + } + } + primnicobj.SecurityGroups = secgrpobjs + } + } + // reserved ip changes + var PrimaryIpv4Address, reservedIp, reservedIpAddress, reservedIpName string + var reservedIpAutoDelete, okAuto bool + if IPAddress, ok := primnic[isInstanceTemplateNicPrimaryIpv4Address]; ok { + PrimaryIpv4Address = IPAddress.(string) + } + primaryIpOk, ok := primnic[isInstanceTemplateNicPrimaryIP] + if ok && len(primaryIpOk.([]interface{})) > 0 { + primip := primaryIpOk.([]interface{})[0].(map[string]interface{}) + + reservedipok, _ := primip[isInstanceTemplateNicReservedIpId] + reservedIp = reservedipok.(string) + reservedipv4Ok, _ := primip[isInstanceTemplateNicReservedIpAddress] + reservedIpAddress = reservedipv4Ok.(string) + reservedipnameOk, _ := primip[isInstanceTemplateNicReservedIpName] + reservedIpName = reservedipnameOk.(string) + reservedipautodeleteok, okAuto := primip[isInstanceTemplateNicReservedIpAutoDelete] + if okAuto { + reservedIpAutoDelete = reservedipautodeleteok.(bool) + } + } + if PrimaryIpv4Address != "" && reservedIpAddress != "" && PrimaryIpv4Address != reservedIpAddress { + err = 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) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "create", "parse-request-body").GetDiag() + } + if reservedIp != "" { + primnicobj.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &reservedIp, + } + } else { + if PrimaryIpv4Address != "" || reservedIpAddress != "" || reservedIpName != "" || okAuto { + primaryipobj := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + if PrimaryIpv4Address != "" { + primaryipobj.Address = &PrimaryIpv4Address + } + if reservedIpAddress != "" { + primaryipobj.Address = &reservedIpAddress + } + if reservedIpName != "" { + primaryipobj.Name = &reservedIpName + } + if okAuto { + primaryipobj.AutoDelete = &reservedIpAutoDelete + } + primnicobj.PrimaryIP = primaryipobj + } + } + instanceproto.PrimaryNetworkInterface = primnicobj + } + + // Handle additional network interface + if nicsintf, ok := d.GetOk(isInstanceTemplateNetworkInterfaces); ok { + nics := nicsintf.([]interface{}) + var intfs []vpcv1.NetworkInterfacePrototype + for _, resource := range nics { + nic := resource.(map[string]interface{}) + nwInterface := &vpcv1.NetworkInterfacePrototype{} + subnetintf, _ := nic[isInstanceTemplateNicSubnet] + subnetintfstr := subnetintf.(string) + nwInterface.Subnet = &vpcv1.SubnetIdentity{ + ID: &subnetintfstr, + } + + name, ok := nic[isInstanceTemplateNicName] + namestr := name.(string) + if ok && namestr != "" { + nwInterface.Name = &namestr + } + allowIPSpoofing, ok := nic[isInstanceTemplateNicAllowIPSpoofing] + allowIPSpoofingbool := allowIPSpoofing.(bool) + if ok { + nwInterface.AllowIPSpoofing = &allowIPSpoofingbool + } + secgrpintf, ok := nic[isInstanceTemplateNicSecurityGroups] + if ok { + secgrpSet := secgrpintf.(*schema.Set) + if secgrpSet.Len() != 0 { + var secgrpobjs = make([]vpcv1.SecurityGroupIdentityIntf, secgrpSet.Len()) + for i, secgrpIntf := range secgrpSet.List() { + secgrpIntfstr := secgrpIntf.(string) + secgrpobjs[i] = &vpcv1.SecurityGroupIdentity{ + ID: &secgrpIntfstr, + } + } + nwInterface.SecurityGroups = secgrpobjs + } + } + // reserved ip changes + var PrimaryIpv4Address, reservedIp, reservedIpAddress, reservedIpName string + var reservedIpAutoDelete, okAuto bool + if IPAddress, ok := nic[isInstanceTemplateNicPrimaryIpv4Address]; ok { + PrimaryIpv4Address = IPAddress.(string) + } + primaryIpOk, ok := nic[isInstanceTemplateNicPrimaryIP] + if ok && len(primaryIpOk.([]interface{})) > 0 { + primip := primaryIpOk.([]interface{})[0].(map[string]interface{}) + + reservedipok, _ := primip[isInstanceTemplateNicReservedIpId] + reservedIp = reservedipok.(string) + reservedipv4Ok, _ := primip[isInstanceTemplateNicReservedIpAddress] + reservedIpAddress = reservedipv4Ok.(string) + reservedipnameOk, _ := primip[isInstanceTemplateNicReservedIpName] + reservedIpName = reservedipnameOk.(string) + // var reservedipautodeleteok interface{} + + if v, ok := primip[isInstanceTemplateNicReservedIpAutoDelete].(bool); ok && v { + log.Printf("[INFO] 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 { + err = fmt.Errorf("Error creating instance template, network_interfaces error, use either primary_ipv4_address(%s) or primary_ip.0.address(%s)", PrimaryIpv4Address, reservedIpAddress) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "create", "parse-request-body").GetDiag() + } + if reservedIp != "" && (PrimaryIpv4Address != "" || reservedIpAddress != "" || reservedIpName != "" || okAuto) { + err = fmt.Errorf("Error creating instance template, network_interfaces error, reserved_ip(%s) is mutually exclusive with other primary_ip attributes", reservedIp) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "create", "parse-request-body").GetDiag() + } + if reservedIp != "" { + nwInterface.PrimaryIP = &vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity{ + ID: &reservedIp, + } + } else { + if PrimaryIpv4Address != "" || reservedIpAddress != "" || reservedIpName != "" || okAuto { + primaryipobj := &vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext{} + if PrimaryIpv4Address != "" { + primaryipobj.Address = &PrimaryIpv4Address + } + if reservedIpAddress != "" { + primaryipobj.Address = &reservedIpAddress + } + if reservedIpName != "" { + primaryipobj.Name = &reservedIpName + } + if okAuto { + primaryipobj.AutoDelete = &reservedIpAutoDelete + } + nwInterface.PrimaryIP = primaryipobj + } + } + intfs = append(intfs, *nwInterface) + } + instanceproto.NetworkInterfaces = intfs + } + + // Handle SSH Keys + keySet := d.Get(isInstanceTemplateKeys).(*schema.Set) + if keySet.Len() != 0 { + keyobjs := make([]vpcv1.KeyIdentityIntf, keySet.Len()) + for i, key := range keySet.List() { + keystr := key.(string) + keyobjs[i] = &vpcv1.KeyIdentity{ + ID: &keystr, + } + } + instanceproto.Keys = keyobjs + } + + // Handle user data + if userdata, ok := d.GetOk(isInstanceTemplateUserData); ok { + userdatastr := userdata.(string) + instanceproto.UserData = &userdatastr + } + + // handle resource group + if grp, ok := d.GetOk(isInstanceTemplateResourceGroup); ok { + grpstr := grp.(string) + instanceproto.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &grpstr, + } + + } + + options := &vpcv1.CreateInstanceTemplateOptions{ + InstanceTemplatePrototype: instanceproto, + } + + instanceIntf, _, err := sess.CreateInstanceTemplateWithContext(context, options) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("CreateInstanceTemplateWithContext failed: %s", err.Error()), "ibm_is_instance_template", "create") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + instance := instanceIntf.(*vpcv1.InstanceTemplate) + d.SetId(*instance.ID) + return nil +} + +func instanceTemplateCreate(context context.Context, d *schema.ResourceData, meta interface{}, profile, name, vpcID, zone, image string) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "create", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + instanceproto := &vpcv1.InstanceTemplatePrototype{ + Image: &vpcv1.ImageIdentity{ + ID: &image, + }, + Zone: &vpcv1.ZoneIdentity{ + Name: &zone, + }, + Profile: &vpcv1.InstanceProfileIdentity{ + Name: &profile, + }, + VPC: &vpcv1.VPCIdentity{ + ID: &vpcID, + }, + } + if name != "" { + instanceproto.Name = &name + } + // cluster changes + if clusterNetworkAttachmentOk, ok := d.GetOk("cluster_network_attachments"); ok { + clusterNetworkAttachmentList := clusterNetworkAttachmentOk.([]interface{}) + clusterNetworkAttachments := []vpcv1.InstanceClusterNetworkAttachmentPrototypeInstanceContext{} + for _, clusterNetworkAttachmentsItem := range clusterNetworkAttachmentList { + clusterNetworkAttachmentsItemModel, err := ResourceIBMIsInstanceTemplateMapToInstanceClusterNetworkAttachmentPrototypeInstanceContext(clusterNetworkAttachmentsItem.(map[string]interface{})) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "create", "parse-cluster_network_attachments").GetDiag() + } + clusterNetworkAttachments = append(clusterNetworkAttachments, *clusterNetworkAttachmentsItemModel) + } + instanceproto.ClusterNetworkAttachments = clusterNetworkAttachments + } + if _, ok := d.GetOk("confidential_compute_mode"); ok { + instanceproto.ConfidentialComputeMode = core.StringPtr(d.Get("confidential_compute_mode").(string)) + } + if _, ok := d.GetOkExists("enable_secure_boot"); ok { + instanceproto.EnableSecureBoot = core.BoolPtr(d.Get("enable_secure_boot").(bool)) + } + metadataServiceEnabled := d.Get(isInstanceTemplateMetadataServiceEnabled).(bool) + if metadataServiceEnabled { + instanceproto.MetadataService = &vpcv1.InstanceMetadataServicePrototype{ + Enabled: &metadataServiceEnabled, + } + } + + if metadataService := GetInstanceTemplateMetadataServiceOptions(d); metadataService != nil { + instanceproto.MetadataService = metadataService + } + + // vni + + if networkattachmentsintf, ok := d.GetOk("network_attachments"); ok { + networkAttachments := []vpcv1.InstanceNetworkAttachmentPrototype{} + for i, networkAttachmentsItem := range networkattachmentsintf.([]interface{}) { + allowipspoofing := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.allow_ip_spoofing", i) + autodelete := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.auto_delete", i) + enablenat := fmt.Sprintf("network_attachments.%d.virtual_network_interface.0.enable_infrastructure_nat", i) + networkAttachmentsItemModel, err := resourceIBMIsInstanceTemplateMapToInstanceNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat, d, networkAttachmentsItem.(map[string]interface{})) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "create", "parse-network_attachments").GetDiag() + } + networkAttachments = append(networkAttachments, *networkAttachmentsItemModel) + } + instanceproto.NetworkAttachments = networkAttachments + } + if primnetworkattachmentintf, ok := d.GetOk("primary_network_attachment"); ok && len(primnetworkattachmentintf.([]interface{})) > 0 { + i := 0 + allowipspoofing := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.allow_ip_spoofing", i) + autodelete := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.auto_delete", i) + enablenat := fmt.Sprintf("primary_network_attachment.%d.virtual_network_interface.0.enable_infrastructure_nat", i) + primaryNetworkAttachmentModel, err := resourceIBMIsInstanceTemplateMapToInstanceNetworkAttachmentPrototype(allowipspoofing, autodelete, enablenat, d, primnetworkattachmentintf.([]interface{})[0].(map[string]interface{})) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "create", "parse-primary_network_attachment").GetDiag() + } + instanceproto.PrimaryNetworkAttachment = primaryNetworkAttachmentModel + } + + if defaultTrustedProfileTargetIntf, ok := d.GetOk(isInstanceDefaultTrustedProfileTarget); ok { + defaultTrustedProfiletarget := defaultTrustedProfileTargetIntf.(string) + + target := &vpcv1.TrustedProfileIdentity{} + if strings.HasPrefix(defaultTrustedProfiletarget, "crn") { + target.CRN = &defaultTrustedProfiletarget + } else { + target.ID = &defaultTrustedProfiletarget + } + instanceproto.DefaultTrustedProfile = &vpcv1.InstanceDefaultTrustedProfilePrototype{ + Target: target, + } + + if defaultTrustedProfileAutoLinkIntf, ok := d.GetOkExists(isInstanceDefaultTrustedProfileAutoLink); ok { + defaultTrustedProfileAutoLink := defaultTrustedProfileAutoLinkIntf.(bool) + instanceproto.DefaultTrustedProfile.AutoLink = &defaultTrustedProfileAutoLink + } + } + if availablePolicyHostFailureIntf, ok := d.GetOk(isInstanceTemplateAvailablePolicyHostFailure); ok { + availablePolicyHostFailure := availablePolicyHostFailureIntf.(string) + instanceproto.AvailabilityPolicy = &vpcv1.InstanceAvailabilityPolicyPrototype{ + HostFailure: &availablePolicyHostFailure, + } + } + if dHostIdInf, ok := d.GetOk(isPlacementTargetDedicatedHost); ok { + dHostIdStr := dHostIdInf.(string) + dHostPlaementTarget := &vpcv1.InstancePlacementTargetPrototypeDedicatedHostIdentity{ + ID: &dHostIdStr, + } + instanceproto.PlacementTarget = dHostPlaementTarget + } + + if dHostGrpIdInf, ok := d.GetOk(isPlacementTargetDedicatedHostGroup); ok { + dHostGrpIdStr := dHostGrpIdInf.(string) + dHostGrpPlaementTarget := &vpcv1.InstancePlacementTargetPrototypeDedicatedHostGroupIdentity{ + ID: &dHostGrpIdStr, + } + instanceproto.PlacementTarget = dHostGrpPlaementTarget + } + if resAffinity, ok := d.GetOk(isReservationAffinity); ok { + resAff := resAffinity.([]interface{})[0].(map[string]interface{}) + var resAffinity = &vpcv1.InstanceReservationAffinityPrototype{} + policy, ok := resAff["policy"] + policyStr := policy.(string) + if policyStr != "" && ok { + resAffinity.Policy = &policyStr + } + poolIntf, okPool := resAff[isReservationAffinityPool] + if okPool && poolIntf != nil && poolIntf.([]interface{}) != nil && len(poolIntf.([]interface{})) > 0 { + pool := poolIntf.([]interface{})[0].(map[string]interface{}) + id, okId := pool["id"] + if okId { + idStr, ok := id.(string) + if idStr != "" && ok { + var resAffPool = make([]vpcv1.ReservationIdentityIntf, 1) + resAffPool[0] = &vpcv1.ReservationIdentity{ + ID: &idStr, + } + resAffinity.Pool = resAffPool + } + } + } + instanceproto.ReservationAffinity = resAffinity + } + + if placementGroupInf, ok := d.GetOk(isPlacementTargetPlacementGroup); ok { + placementGrpStr := placementGroupInf.(string) + placementGrp := &vpcv1.InstancePlacementTargetPrototypePlacementGroupIdentity{ + ID: &placementGrpStr, + } + instanceproto.PlacementTarget = placementGrp + } + + if totalVolBandwidthIntf, ok := d.GetOk(isInstanceTotalVolumeBandwidth); ok { + totalVolBandwidthStr := int64(totalVolBandwidthIntf.(int)) + instanceproto.TotalVolumeBandwidth = &totalVolBandwidthStr + } + + // BOOT VOLUME ATTACHMENT for instance template + if boot, ok := d.GetOk(isInstanceTemplateBootVolume); ok { + bootvol := boot.([]interface{})[0].(map[string]interface{}) + var volTemplate = &vpcv1.VolumePrototypeInstanceByImageContext{} + name, ok := bootvol[isInstanceTemplateBootName] + namestr := name.(string) + if ok && namestr != "" { + volTemplate.Name = &namestr + } + + var userTags *schema.Set + if v, ok := bootvol[isInstanceTemplateBootVolumeTags]; ok { + userTags = v.(*schema.Set) + if userTags != nil && userTags.Len() != 0 { + userTagsArray := make([]string, userTags.Len()) + for i, userTag := range userTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + volTemplate.UserTags = userTagsArray + } + } + + // bandwidth changes + volBandwith := bootvol["bandwidth"].(int) + if volBandwith != 0 { + volBandwith64 := int64(volBandwith) + volTemplate.Bandwidth = &volBandwith64 + } + volcap := bootvol["size"].(int) + volcapint64 := int64(volcap) + if volcap == 0 { + volcap := 100 + volcapint64 = int64(volcap) + } + volprof := bootvol["profile"].(string) + if volprof == "" { + volprof = "general-purpose" + } + volTemplate.Capacity = &volcapint64 + volTemplate.Profile = &vpcv1.VolumeProfileIdentity{ + Name: &volprof, + } + + if encryption, ok := bootvol[isInstanceTemplateBootEncryption]; ok { + bootEncryption := encryption.(string) + if bootEncryption != "" { + volTemplate.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ + CRN: &bootEncryption, + } + } + } + + var deleteVolumeOption bool + if deleteVolume, ok := bootvol[isInstanceTemplateVolumeDeleteOnInstanceDelete]; ok { + deleteVolumeOption = deleteVolume.(bool) + } + + //allowed use + if bootvol["allowed_use"] != nil && len(bootvol["allowed_use"].([]interface{})) > 0 { + AllowedUseModel, _ := ResourceIBMIsVolumeAllowedUseMapToVolumeAllowedUsePrototype(bootvol["allowed_use"].([]interface{})[0].(map[string]interface{})) + volTemplate.AllowedUse = AllowedUseModel + } + instanceproto.BootVolumeAttachment = &vpcv1.VolumeAttachmentPrototypeInstanceByImageContext{ DeleteVolumeOnInstanceDelete: &deleteVolumeOption, Volume: volTemplate, @@ -2171,6 +2855,20 @@ func instanceTemplateCreate(context context.Context, d *schema.ResourceData, met volPrototype.Bandwidth = &bandwidth } + // source_snapshot + sourceSnapshot := newvol["source_snapshot"].(string) + if sourceSnapshot != "" { + volPrototype.SourceSnapshot = &vpcv1.SnapshotIdentity{ + ID: &sourceSnapshot, + } + } + + //allowed use + if newvol["allowed_use"] != nil && len(newvol["allowed_use"].([]interface{})) > 0 { + AllowedUseModel, _ := ResourceIBMIsVolumeAllowedUseMapToVolumeAllowedUsePrototype(newvol["allowed_use"].([]interface{})[0].(map[string]interface{})) + volPrototype.AllowedUse = AllowedUseModel + } + iops := int64(newvol[isInstanceTemplateVolAttVolIops].(int)) encryptionKey := newvol[isInstanceTemplateVolAttVolEncryptionKey].(string) @@ -2452,285 +3150,203 @@ func instanceTemplateGet(context context.Context, d *schema.ResourceData, meta i log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) return tfErr.GetDiag() } - instanceTemplate := instanceIntf.(*vpcv1.InstanceTemplate) - if !core.IsNil(instanceTemplate.Name) { - if err = d.Set("name", instanceTemplate.Name); err != nil { - err = fmt.Errorf("Error setting name: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-name").GetDiag() - } - } - if err = d.Set("crn", instanceTemplate.CRN); err != nil { - err = fmt.Errorf("Error setting crn: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-crn").GetDiag() - } - if instanceTemplate.AvailabilityPolicy != nil && instanceTemplate.AvailabilityPolicy.HostFailure != nil { - if err = d.Set("availability_policy_host_failure", instanceTemplate.AvailabilityPolicy.HostFailure); err != nil { - err = fmt.Errorf("Error setting availability_policy_host_failure: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-availability_policy_host_failure").GetDiag() - } - } - // cluster changes - clusterNetworkAttachments := []map[string]interface{}{} - for _, clusterNetworkAttachmentsItem := range instanceTemplate.ClusterNetworkAttachments { - clusterNetworkAttachmentsItemMap, err := ResourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeInstanceContextToMap(&clusterNetworkAttachmentsItem) // #nosec G601 - if err != nil { - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "cluster_network_attachments-to-map").GetDiag() + switch v := instanceIntf.(type) { + case *vpcv1.InstanceTemplate: + instanceTemplate := v + + if !core.IsNil(instanceTemplate.Name) { + if err = d.Set("name", instanceTemplate.Name); err != nil { + err = fmt.Errorf("Error setting name: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-name").GetDiag() + } } - clusterNetworkAttachments = append(clusterNetworkAttachments, clusterNetworkAttachmentsItemMap) - } - if err = d.Set("cluster_network_attachments", clusterNetworkAttachments); err != nil { - err = fmt.Errorf("Error setting cluster_network_attachments: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-cluster_network_attachments").GetDiag() - } - if !core.IsNil(instanceTemplate.ConfidentialComputeMode) { - if err = d.Set("confidential_compute_mode", instanceTemplate.ConfidentialComputeMode); err != nil { - err = fmt.Errorf("Error setting confidential_compute_mode: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-confidential_compute_mode").GetDiag() + if err = d.Set("crn", instanceTemplate.CRN); err != nil { + err = fmt.Errorf("Error setting crn: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-crn").GetDiag() } - } - if !core.IsNil(instanceTemplate.EnableSecureBoot) { - if err = d.Set("enable_secure_boot", instanceTemplate.EnableSecureBoot); err != nil { - err = fmt.Errorf("Error setting enable_secure_boot: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-enable_secure_boot").GetDiag() + if instanceTemplate.AvailabilityPolicy != nil && instanceTemplate.AvailabilityPolicy.HostFailure != nil { + if err = d.Set("availability_policy_host_failure", instanceTemplate.AvailabilityPolicy.HostFailure); err != nil { + err = fmt.Errorf("Error setting availability_policy_host_failure: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-availability_policy_host_failure").GetDiag() + } } - } - - // vni if any - if !core.IsNil(instanceTemplate.NetworkAttachments) { - networkAttachments := []map[string]interface{}{} - for _, networkAttachmentsItem := range instanceTemplate.NetworkAttachments { - networkAttachmentsItemMap, err := resourceIBMIsInstanceTemplateNetworkAttachmentReferenceToMap(&networkAttachmentsItem, instanceC) + // cluster changes + clusterNetworkAttachments := []map[string]interface{}{} + for _, clusterNetworkAttachmentsItem := range instanceTemplate.ClusterNetworkAttachments { + clusterNetworkAttachmentsItemMap, err := ResourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeInstanceContextToMap(&clusterNetworkAttachmentsItem) // #nosec G601 if err != nil { - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "network_attachments-to-map").GetDiag() + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "cluster_network_attachments-to-map").GetDiag() } - networkAttachments = append(networkAttachments, networkAttachmentsItemMap) + clusterNetworkAttachments = append(clusterNetworkAttachments, clusterNetworkAttachmentsItemMap) } - if err = d.Set("network_attachments", networkAttachments); err != nil { - err = fmt.Errorf("Error setting network_attachments: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-network_attachments").GetDiag() + if err = d.Set("cluster_network_attachments", clusterNetworkAttachments); err != nil { + err = fmt.Errorf("Error setting cluster_network_attachments: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-cluster_network_attachments").GetDiag() } - } - - if !core.IsNil(instanceTemplate.PrimaryNetworkAttachment) { - primaryNetworkAttachmentMap, err := resourceIBMIsInstanceTemplateNetworkAttachmentReferenceToMap(instanceTemplate.PrimaryNetworkAttachment, instanceC) - if err != nil { - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "primary_network_attachment-to-map").GetDiag() + if !core.IsNil(instanceTemplate.ConfidentialComputeMode) { + if err = d.Set("confidential_compute_mode", instanceTemplate.ConfidentialComputeMode); err != nil { + err = fmt.Errorf("Error setting confidential_compute_mode: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-confidential_compute_mode").GetDiag() + } } - if err = d.Set("primary_network_attachment", []map[string]interface{}{primaryNetworkAttachmentMap}); err != nil { - err = fmt.Errorf("Error setting primary_network_attachment: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-primary_network_attachment").GetDiag() + if !core.IsNil(instanceTemplate.EnableSecureBoot) { + if err = d.Set("enable_secure_boot", instanceTemplate.EnableSecureBoot); err != nil { + err = fmt.Errorf("Error setting enable_secure_boot: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-enable_secure_boot").GetDiag() + } } - } - - // catalog offering if any - if instanceTemplate.CatalogOffering != nil { - catOfferingList := make([]map[string]interface{}, 0) - insTempCatalogOffering := instanceTemplate.CatalogOffering.(*vpcv1.InstanceCatalogOfferingPrototype) - - currentOffering := map[string]interface{}{} - if insTempCatalogOffering.Offering != nil { - offering := insTempCatalogOffering.Offering.(*vpcv1.CatalogOfferingIdentity) - currentOffering[isInstanceTemplateCatalogOfferingOfferingCrn] = *offering.CRN - } - if insTempCatalogOffering.Version != nil { - version := insTempCatalogOffering.Version.(*vpcv1.CatalogOfferingVersionIdentity) - currentOffering[isInstanceTemplateCatalogOfferingVersionCrn] = *version.CRN - } - if insTempCatalogOffering.Plan != nil { - plan := insTempCatalogOffering.Plan.(*vpcv1.CatalogOfferingVersionPlanIdentity) - if plan.CRN != nil && *plan.CRN != "" { - currentOffering[isInstanceTemplateCatalogOfferingPlanCrn] = *plan.CRN + // vni if any + if !core.IsNil(instanceTemplate.NetworkAttachments) { + networkAttachments := []map[string]interface{}{} + for _, networkAttachmentsItem := range instanceTemplate.NetworkAttachments { + networkAttachmentsItemMap, err := resourceIBMIsInstanceTemplateNetworkAttachmentReferenceToMap(&networkAttachmentsItem, instanceC) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "network_attachments-to-map").GetDiag() + } + networkAttachments = append(networkAttachments, networkAttachmentsItemMap) + } + if err = d.Set("network_attachments", networkAttachments); err != nil { + err = fmt.Errorf("Error setting network_attachments: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-network_attachments").GetDiag() } } - catOfferingList = append(catOfferingList, currentOffering) - if err = d.Set(isInstanceTemplateCatalogOffering, catOfferingList); err != nil { - err = fmt.Errorf("Error setting catalog_offering: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-catalog_offering").GetDiag() - } - } - if instanceTemplate.ReservationAffinity != nil { - reservationAffinity := []map[string]interface{}{} - reservationAffinityMap := map[string]interface{}{} - - reservationAffinityMap[isReservationAffinityPolicyResp] = instanceTemplate.ReservationAffinity.Policy - if instanceTemplate.ReservationAffinity.Pool != nil && len(instanceTemplate.ReservationAffinity.Pool) > 0 { - pool := instanceTemplate.ReservationAffinity.Pool[0] - res := "" - if idPool, ok := pool.(*vpcv1.ReservationIdentityByID); ok { - res = *idPool.ID - } else if crnPool, ok := pool.(*vpcv1.ReservationIdentityByCRN); ok { - res = *crnPool.CRN - } else if hrefPool, ok := pool.(*vpcv1.ReservationIdentityByHref); ok { - res = *hrefPool.Href + if !core.IsNil(instanceTemplate.PrimaryNetworkAttachment) { + primaryNetworkAttachmentMap, err := resourceIBMIsInstanceTemplateNetworkAttachmentReferenceToMap(instanceTemplate.PrimaryNetworkAttachment, instanceC) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "primary_network_attachment-to-map").GetDiag() + } + if err = d.Set("primary_network_attachment", []map[string]interface{}{primaryNetworkAttachmentMap}); err != nil { + err = fmt.Errorf("Error setting primary_network_attachment: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-primary_network_attachment").GetDiag() } - reservationAffinityMap[isReservationAffinityPool] = res } - reservationAffinity = append(reservationAffinity, reservationAffinityMap) - if err = d.Set(isReservationAffinity, reservationAffinity); err != nil { - err = fmt.Errorf("Error setting reservation_affinity: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-reservation_affinity").GetDiag() + if instanceTemplate.ReservationAffinity != nil { + reservationAffinity := []map[string]interface{}{} + reservationAffinityMap := map[string]interface{}{} + + reservationAffinityMap[isReservationAffinityPolicyResp] = instanceTemplate.ReservationAffinity.Policy + if instanceTemplate.ReservationAffinity.Pool != nil && len(instanceTemplate.ReservationAffinity.Pool) > 0 { + pool := instanceTemplate.ReservationAffinity.Pool[0] + res := "" + if idPool, ok := pool.(*vpcv1.ReservationIdentityByID); ok { + res = *idPool.ID + } else if crnPool, ok := pool.(*vpcv1.ReservationIdentityByCRN); ok { + res = *crnPool.CRN + } else if hrefPool, ok := pool.(*vpcv1.ReservationIdentityByHref); ok { + res = *hrefPool.Href + } + reservationAffinityMap[isReservationAffinityPool] = res + } + reservationAffinity = append(reservationAffinity, reservationAffinityMap) + if err = d.Set(isReservationAffinity, reservationAffinity); err != nil { + err = fmt.Errorf("Error setting reservation_affinity: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-reservation_affinity").GetDiag() + } } - } - if instanceTemplate.Profile != nil { - instanceProfileIntf := instanceTemplate.Profile - identity := instanceProfileIntf.(*vpcv1.InstanceProfileIdentity) - if err = d.Set(isInstanceTemplateProfile, *identity.Name); err != nil { - err = fmt.Errorf("Error setting profile: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-profile").GetDiag() + if instanceTemplate.Profile != nil { + instanceProfileIntf := instanceTemplate.Profile + identity := instanceProfileIntf.(*vpcv1.InstanceProfileIdentity) + if err = d.Set(isInstanceTemplateProfile, *identity.Name); err != nil { + err = fmt.Errorf("Error setting profile: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-profile").GetDiag() + } } - } - if instanceTemplate.DefaultTrustedProfile != nil { - if instanceTemplate.DefaultTrustedProfile.AutoLink != nil { - if err = d.Set(isInstanceDefaultTrustedProfileAutoLink, instanceTemplate.DefaultTrustedProfile.AutoLink); err != nil { - err = fmt.Errorf("Error setting default_trusted_profile_auto_link: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-default_trusted_profile_auto_link").GetDiag() + if instanceTemplate.DefaultTrustedProfile != nil { + if instanceTemplate.DefaultTrustedProfile.AutoLink != nil { + if err = d.Set(isInstanceDefaultTrustedProfileAutoLink, instanceTemplate.DefaultTrustedProfile.AutoLink); err != nil { + err = fmt.Errorf("Error setting default_trusted_profile_auto_link: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-default_trusted_profile_auto_link").GetDiag() + } } - } - if instanceTemplate.DefaultTrustedProfile.Target != nil { - switch reflect.TypeOf(instanceTemplate.DefaultTrustedProfile.Target).String() { - case "*vpcv1.TrustedProfileIdentityTrustedProfileByID": - { - target := instanceTemplate.DefaultTrustedProfile.Target.(*vpcv1.TrustedProfileIdentityByID) - if err = d.Set(isInstanceDefaultTrustedProfileTarget, target.ID); err != nil { - err = fmt.Errorf("Error setting default_trusted_profile_target: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-default_trusted_profile_target").GetDiag() + if instanceTemplate.DefaultTrustedProfile.Target != nil { + switch reflect.TypeOf(instanceTemplate.DefaultTrustedProfile.Target).String() { + case "*vpcv1.TrustedProfileIdentityTrustedProfileByID": + { + target := instanceTemplate.DefaultTrustedProfile.Target.(*vpcv1.TrustedProfileIdentityByID) + if err = d.Set(isInstanceDefaultTrustedProfileTarget, target.ID); err != nil { + err = fmt.Errorf("Error setting default_trusted_profile_target: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-default_trusted_profile_target").GetDiag() + } } - } - case "*vpcv1.TrustedProfileIdentityTrustedProfileByCRN": - { - target := instanceTemplate.DefaultTrustedProfile.Target.(*vpcv1.TrustedProfileIdentityByCRN) - if err = d.Set(isInstanceDefaultTrustedProfileTarget, target.CRN); err != nil { - err = fmt.Errorf("Error setting default_trusted_profile_target: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-default_trusted_profile_target").GetDiag() + case "*vpcv1.TrustedProfileIdentityTrustedProfileByCRN": + { + target := instanceTemplate.DefaultTrustedProfile.Target.(*vpcv1.TrustedProfileIdentityByCRN) + if err = d.Set(isInstanceDefaultTrustedProfileTarget, target.CRN); err != nil { + err = fmt.Errorf("Error setting default_trusted_profile_target: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-default_trusted_profile_target").GetDiag() + } } } } } - } - if instanceTemplate.TotalVolumeBandwidth != nil { - if err = d.Set(isInstanceTotalVolumeBandwidth, int(*instanceTemplate.TotalVolumeBandwidth)); err != nil { - err = fmt.Errorf("Error setting total_volume_bandwidth: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-total_volume_bandwidth").GetDiag() - } - } - if instanceTemplate.MetadataService != nil { - if err = d.Set(isInstanceTemplateMetadataServiceEnabled, instanceTemplate.MetadataService.Enabled); err != nil { - err = fmt.Errorf("Error setting metadata_service_enabled: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-metadata_service_enabled").GetDiag() + if instanceTemplate.TotalVolumeBandwidth != nil { + if err = d.Set(isInstanceTotalVolumeBandwidth, int(*instanceTemplate.TotalVolumeBandwidth)); err != nil { + err = fmt.Errorf("Error setting total_volume_bandwidth: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-total_volume_bandwidth").GetDiag() + } } - metadataService := []map[string]interface{}{} - metadataServiceMap := map[string]interface{}{} + if instanceTemplate.MetadataService != nil { + if err = d.Set(isInstanceTemplateMetadataServiceEnabled, instanceTemplate.MetadataService.Enabled); err != nil { + err = fmt.Errorf("Error setting metadata_service_enabled: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-metadata_service_enabled").GetDiag() + } + metadataService := []map[string]interface{}{} + metadataServiceMap := map[string]interface{}{} - metadataServiceMap[isInstanceMetadataServiceEnabled1] = instanceTemplate.MetadataService.Enabled - if instanceTemplate.MetadataService.Protocol != nil { - metadataServiceMap[isInstanceMetadataServiceProtocol] = instanceTemplate.MetadataService.Protocol + metadataServiceMap[isInstanceMetadataServiceEnabled1] = instanceTemplate.MetadataService.Enabled + if instanceTemplate.MetadataService.Protocol != nil { + metadataServiceMap[isInstanceMetadataServiceProtocol] = instanceTemplate.MetadataService.Protocol + } + if instanceTemplate.MetadataService.ResponseHopLimit != nil { + metadataServiceMap[isInstanceMetadataServiceRespHopLimit] = instanceTemplate.MetadataService.ResponseHopLimit + } + metadataService = append(metadataService, metadataServiceMap) + if err = d.Set(isInstanceMetadataService, metadataService); err != nil { + err = fmt.Errorf("Error setting metadata_service: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-metadata_service").GetDiag() + } } - if instanceTemplate.MetadataService.ResponseHopLimit != nil { - metadataServiceMap[isInstanceMetadataServiceRespHopLimit] = instanceTemplate.MetadataService.ResponseHopLimit + + var placementTargetList []map[string]interface{} + if instanceTemplate.PlacementTarget != nil { + placementTargetMap := resourceIbmIsInstanceTemplateInstancePlacementTargetPrototypeToMap(*instanceTemplate.PlacementTarget.(*vpcv1.InstancePlacementTargetPrototype)) + if len(placementTargetMap) > 0 { + placementTargetList = append(placementTargetList, placementTargetMap) + } } - metadataService = append(metadataService, metadataServiceMap) - if err = d.Set(isInstanceMetadataService, metadataService); err != nil { - err = fmt.Errorf("Error setting metadata_service: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-metadata_service").GetDiag() + if err = d.Set(isInstanceTemplatePlacementTarget, placementTargetList); err != nil { + err = fmt.Errorf("Error setting placement_target InstanceTemplateInstanceByImageInstanceTemplateContext: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-placement_target").GetDiag() } - } - - var placementTargetMap map[string]interface{} - if instanceTemplate.PlacementTarget != nil { - placementTargetMap = resourceIbmIsInstanceTemplateInstancePlacementTargetPrototypeToMap(*instanceTemplate.PlacementTarget.(*vpcv1.InstancePlacementTargetPrototype)) - } - if err = d.Set(isInstanceTemplatePlacementTarget, []map[string]interface{}{placementTargetMap}); err != nil { - err = fmt.Errorf("Error setting placement_target: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-placement_target").GetDiag() - } - if instanceTemplate.PrimaryNetworkInterface != nil { - primaryNicList := make([]map[string]interface{}, 0) - currentPrimNic := map[string]interface{}{} - currentPrimNic[isInstanceTemplateNicName] = *instanceTemplate.PrimaryNetworkInterface.Name - if instanceTemplate.PrimaryNetworkInterface.PrimaryIP != nil { - pipIntf := instanceTemplate.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 := instanceTemplate.PrimaryNetworkInterface.Subnet - subnetIdentity := subInf.(*vpcv1.SubnetIdentity) - currentPrimNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID - if instanceTemplate.PrimaryNetworkInterface.AllowIPSpoofing != nil { - currentPrimNic[isInstanceTemplateNicAllowIPSpoofing] = *instanceTemplate.PrimaryNetworkInterface.AllowIPSpoofing - } - if len(instanceTemplate.PrimaryNetworkInterface.SecurityGroups) != 0 { - secgrpList := []string{} - for i := 0; i < len(instanceTemplate.PrimaryNetworkInterface.SecurityGroups); i++ { - secGrpInf := instanceTemplate.PrimaryNetworkInterface.SecurityGroups[i] - subnetIdentity := secGrpInf.(*vpcv1.SecurityGroupIdentity) - secgrpList = append(secgrpList, string(*subnetIdentity.ID)) - } - currentPrimNic[isInstanceTemplateNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) - } - primaryNicList = append(primaryNicList, currentPrimNic) - if err = d.Set(isInstanceTemplatePrimaryNetworkInterface, primaryNicList); err != nil { - err = fmt.Errorf("Error setting primary_network_interface: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-primary_network_interface").GetDiag() - } - } - - if instanceTemplate.NetworkInterfaces != nil { - interfacesList := make([]map[string]interface{}, 0) - for _, intfc := range instanceTemplate.NetworkInterfaces { - currentNic := map[string]interface{}{} - currentNic[isInstanceTemplateNicName] = *intfc.Name - if intfc.PrimaryIP != nil { + if instanceTemplate.PrimaryNetworkInterface != nil { + primaryNicList := make([]map[string]interface{}, 0) + currentPrimNic := map[string]interface{}{} + currentPrimNic[isInstanceTemplateNicName] = *instanceTemplate.PrimaryNetworkInterface.Name + if instanceTemplate.PrimaryNetworkInterface.PrimaryIP != nil { + pipIntf := instanceTemplate.PrimaryNetworkInterface.PrimaryIP // 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 + currentPrimNic[isInstanceTemplateNicPrimaryIpv4Address] = pip.Address + currentPrimIp[isInstanceTemplateNicReservedIpId] = pip.ID 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 + currentPrimNic[isInstanceTemplateNicPrimaryIpv4Address] = pip.Address currentPrimIp[isInstanceTemplateNicReservedIpAddress] = pip.Address currentPrimIp[isInstanceTemplateNicReservedIpAutoDelete] = pip.AutoDelete currentPrimIp[isInstanceTemplateNicReservedIpName] = pip.Name @@ -2742,138 +3358,669 @@ func instanceTemplateGet(context context.Context, d *schema.ResourceData, meta i } } primaryIpList = append(primaryIpList, currentPrimIp) - currentNic[isInstanceTemplateNicPrimaryIP] = primaryIpList + currentPrimNic[isInstanceTemplateNicPrimaryIP] = primaryIpList } - if intfc.AllowIPSpoofing != nil { - currentNic[isInstanceTemplateNicAllowIPSpoofing] = *intfc.AllowIPSpoofing - } - subInf := intfc.Subnet + subInf := instanceTemplate.PrimaryNetworkInterface.Subnet subnetIdentity := subInf.(*vpcv1.SubnetIdentity) - currentNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID - if len(intfc.SecurityGroups) != 0 { + currentPrimNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID + if instanceTemplate.PrimaryNetworkInterface.AllowIPSpoofing != nil { + currentPrimNic[isInstanceTemplateNicAllowIPSpoofing] = *instanceTemplate.PrimaryNetworkInterface.AllowIPSpoofing + } + if len(instanceTemplate.PrimaryNetworkInterface.SecurityGroups) != 0 { secgrpList := []string{} - for i := 0; i < len(intfc.SecurityGroups); i++ { - secGrpInf := intfc.SecurityGroups[i] + for i := 0; i < len(instanceTemplate.PrimaryNetworkInterface.SecurityGroups); i++ { + secGrpInf := instanceTemplate.PrimaryNetworkInterface.SecurityGroups[i] subnetIdentity := secGrpInf.(*vpcv1.SecurityGroupIdentity) secgrpList = append(secgrpList, string(*subnetIdentity.ID)) } - currentNic[isInstanceTemplateNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + currentPrimNic[isInstanceTemplateNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + primaryNicList = append(primaryNicList, currentPrimNic) + if err = d.Set(isInstanceTemplatePrimaryNetworkInterface, primaryNicList); err != nil { + err = fmt.Errorf("Error setting primary_network_interface: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-primary_network_interface").GetDiag() } - interfacesList = append(interfacesList, currentNic) } - if err = d.Set(isInstanceTemplateNetworkInterfaces, interfacesList); err != nil { - err = fmt.Errorf("Error setting network_interfaces: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-network_interfaces").GetDiag() + + // catalog offering if any + + if instanceTemplate.CatalogOffering != nil { + catOfferingList := make([]map[string]interface{}, 0) + insTempCatalogOffering := instanceTemplate.CatalogOffering.(*vpcv1.InstanceCatalogOfferingPrototype) + + currentOffering := map[string]interface{}{} + if insTempCatalogOffering.Offering != nil { + offering := insTempCatalogOffering.Offering.(*vpcv1.CatalogOfferingIdentity) + currentOffering[isInstanceTemplateCatalogOfferingOfferingCrn] = *offering.CRN + } + if insTempCatalogOffering.Version != nil { + version := insTempCatalogOffering.Version.(*vpcv1.CatalogOfferingVersionIdentity) + currentOffering[isInstanceTemplateCatalogOfferingVersionCrn] = *version.CRN + } + if insTempCatalogOffering.Plan != nil { + plan := insTempCatalogOffering.Plan.(*vpcv1.CatalogOfferingVersionPlanIdentity) + if plan.CRN != nil && *plan.CRN != "" { + currentOffering[isInstanceTemplateCatalogOfferingPlanCrn] = *plan.CRN + } + } + catOfferingList = append(catOfferingList, currentOffering) + if err = d.Set(isInstanceTemplateCatalogOffering, catOfferingList); err != nil { + err = fmt.Errorf("Error setting catalog_offering: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-catalog_offering").GetDiag() + } } - } - if instanceTemplate.Image != nil { - imageInf := instanceTemplate.Image - imageIdentity := imageInf.(*vpcv1.ImageIdentity) - if err = d.Set(isInstanceTemplateImage, *imageIdentity.ID); err != nil { - err = fmt.Errorf("Error setting image: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-image").GetDiag() + if instanceTemplate.NetworkInterfaces != nil { + interfacesList := make([]map[string]interface{}, 0) + for _, intfc := range instanceTemplate.NetworkInterfaces { + currentNic := map[string]interface{}{} + currentNic[isInstanceTemplateNicName] = *intfc.Name + if intfc.PrimaryIP != nil { + // reserved ip changes + primaryIpList := make([]map[string]interface{}, 0) + currentPrimIp := map[string]interface{}{} + pipIntf := intfc.PrimaryIP + switch reflect.TypeOf(pipIntf).String() { + case "*vpcv1.NetworkInterfaceIPPrototype": + { + pip := pipIntf.(*vpcv1.NetworkInterfaceIPPrototype) + currentNic[isInstanceTemplateNicPrimaryIpv4Address] = pip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAddress] = pip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAutoDelete] = pip.AutoDelete + currentPrimIp[isInstanceTemplateNicReservedIpName] = pip.Name + currentPrimIp[isInstanceTemplateNicReservedIpId] = pip.ID + } + case "*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext": + { + pip := pipIntf.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext) + currentNic[isInstanceTemplateNicPrimaryIpv4Address] = pip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAddress] = pip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAutoDelete] = pip.AutoDelete + currentPrimIp[isInstanceTemplateNicReservedIpName] = pip.Name + } + case "*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity": + { + pip := pipIntf.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity) + currentPrimIp[isInstanceTemplateNicReservedIpId] = pip.ID + } + } + primaryIpList = append(primaryIpList, currentPrimIp) + currentNic[isInstanceTemplateNicPrimaryIP] = primaryIpList + } + if intfc.AllowIPSpoofing != nil { + currentNic[isInstanceTemplateNicAllowIPSpoofing] = *intfc.AllowIPSpoofing + } + subInf := intfc.Subnet + subnetIdentity := subInf.(*vpcv1.SubnetIdentity) + currentNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID + if len(intfc.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(intfc.SecurityGroups); i++ { + secGrpInf := intfc.SecurityGroups[i] + subnetIdentity := secGrpInf.(*vpcv1.SecurityGroupIdentity) + secgrpList = append(secgrpList, string(*subnetIdentity.ID)) + } + currentNic[isInstanceTemplateNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + interfacesList = append(interfacesList, currentNic) + } + if err = d.Set(isInstanceTemplateNetworkInterfaces, interfacesList); err != nil { + err = fmt.Errorf("Error setting network_interfaces: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-network_interfaces").GetDiag() + } } - } - vpcInf := instanceTemplate.VPC - vpcRef := vpcInf.(*vpcv1.VPCIdentity) - if err = d.Set(isInstanceTemplateVPC, vpcRef.ID); err != nil { - err = fmt.Errorf("Error setting vpc: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-vpc").GetDiag() - } - zoneInf := instanceTemplate.Zone - zone := zoneInf.(*vpcv1.ZoneIdentity) - if err = d.Set(isInstanceTemplateZone, *zone.Name); err != nil { - err = fmt.Errorf("Error setting zone: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-zone").GetDiag() - } - interfacesList := make([]map[string]interface{}, 0) - if instanceTemplate.VolumeAttachments != nil { - for _, volume := range instanceTemplate.VolumeAttachments { - volumeAttach := map[string]interface{}{} - volumeAttach[isInstanceTemplateVolAttName] = *volume.Name - volumeAttach[isInstanceTemplateDeleteVolume] = *volume.DeleteVolumeOnInstanceDelete - newVolumeArr := []map[string]interface{}{} - newVolume := map[string]interface{}{} - volumeIntf := volume.Volume - volumeInst := volumeIntf.(*vpcv1.VolumeAttachmentPrototypeVolume) - if volumeInst.ID != nil { - volumeAttach[isInstanceTemplateVolAttVol] = *volumeInst.ID + + if instanceTemplate.Image != nil { + imageInf := instanceTemplate.Image + imageIdentity := imageInf.(*vpcv1.ImageIdentity) + if err = d.Set(isInstanceTemplateImage, *imageIdentity.ID); err != nil { + err = fmt.Errorf("Error setting image: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-image").GetDiag() + } + } + vpcInf := instanceTemplate.VPC + vpcRef := vpcInf.(*vpcv1.VPCIdentity) + if err = d.Set(isInstanceTemplateVPC, vpcRef.ID); err != nil { + err = fmt.Errorf("Error setting vpc: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-vpc").GetDiag() + } + zoneInf := instanceTemplate.Zone + zone := zoneInf.(*vpcv1.ZoneIdentity) + if err = d.Set(isInstanceTemplateZone, *zone.Name); err != nil { + err = fmt.Errorf("Error setting zone: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-zone").GetDiag() + } + interfacesList := make([]map[string]interface{}, 0) + if instanceTemplate.VolumeAttachments != nil { + for _, volume := range instanceTemplate.VolumeAttachments { + volumeAttach := map[string]interface{}{} + volumeAttach[isInstanceTemplateVolAttName] = *volume.Name + volumeAttach[isInstanceTemplateDeleteVolume] = *volume.DeleteVolumeOnInstanceDelete + newVolumeArr := []map[string]interface{}{} + newVolume := map[string]interface{}{} + volumeIntf := volume.Volume + volumeInst := volumeIntf.(*vpcv1.VolumeAttachmentPrototypeVolume) + if volumeInst.ID != nil { + volumeAttach[isInstanceTemplateVolAttVol] = *volumeInst.ID + } + + if volumeInst.Capacity != nil { + newVolume[isInstanceTemplateVolAttVolCapacity] = *volumeInst.Capacity + } + if volumeInst.Profile != nil { + profile := volumeInst.Profile.(*vpcv1.VolumeProfileIdentity) + newVolume[isInstanceTemplateVolAttVolProfile] = profile.Name + } + + if volumeInst.Iops != nil { + newVolume[isInstanceTemplateVolAttVolIops] = *volumeInst.Iops + } + if volumeInst.EncryptionKey != nil { + encryptionKey := volumeInst.EncryptionKey.(*vpcv1.EncryptionKeyIdentity) + newVolume[isInstanceTemplateVolAttVolEncryptionKey] = *encryptionKey.CRN + } + if volumeInst.UserTags != nil { + newVolume[isInstanceTemplateVolAttTags] = volumeInst.UserTags + } + // bandwidth changes + if volumeInst.Bandwidth != nil { + newVolume["bandwidth"] = volumeInst.Bandwidth + } + // source_snapshot + if volumeInst.SourceSnapshot != nil { + sourceSnapshot := volumeInst.SourceSnapshot.(*vpcv1.SnapshotIdentity) + newVolume["source_snapshot"] = *sourceSnapshot.ID + } + + //allowed use + allowedUses := []map[string]interface{}{} + if volumeInst.AllowedUse != nil { + modelMap, err := ResourceIBMIsVolumeAllowedUseToMap(volumeInst.AllowedUse) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Resource) ibm_is_instance_template", "read") + log.Println(tfErr.GetDiag()) + } + allowedUses = append(allowedUses, modelMap) + newVolume["allowed_use"] = allowedUses + } + + if len(newVolume) > 0 { + newVolumeArr = append(newVolumeArr, newVolume) + } + volumeAttach[isInstanceTemplateVolAttVolPrototype] = newVolumeArr + interfacesList = append(interfacesList, volumeAttach) + } + if err = d.Set(isInstanceTemplateVolumeAttachments, interfacesList); err != nil { + err = fmt.Errorf("Error setting volume_attachments: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-volume_attachments").GetDiag() + } + } + if instanceTemplate.BootVolumeAttachment != nil { + bootVolList := make([]map[string]interface{}, 0) + bootVol := map[string]interface{}{} + bootVol[isInstanceTemplateDeleteVolume] = *instanceTemplate.BootVolumeAttachment.DeleteVolumeOnInstanceDelete + if instanceTemplate.BootVolumeAttachment.Volume != nil { + volumeIntf := instanceTemplate.BootVolumeAttachment.Volume + bootVol[isInstanceTemplateBootName] = volumeIntf.Name + bootVol[isInstanceTemplateBootSize] = volumeIntf.Capacity + if volumeIntf.Profile != nil { + volProfIntf := volumeIntf.Profile + volProfInst := volProfIntf.(*vpcv1.VolumeProfileIdentity) + bootVol[isInstanceTemplateBootProfile] = volProfInst.Name + } + if volumeIntf.EncryptionKey != nil { + volEncryption := volumeIntf.EncryptionKey + volEncryptionIntf := volEncryption.(*vpcv1.EncryptionKeyIdentity) + bootVol[isInstanceTemplateBootEncryption] = volEncryptionIntf.CRN + } + if volumeIntf.UserTags != nil { + bootVol[isVolumeTags] = volumeIntf.UserTags + } + if volumeIntf.Bandwidth != nil { + bootVol["bandwidth"] = volumeIntf.Bandwidth + } + + allowedUses := []map[string]interface{}{} + if volumeIntf.AllowedUse != nil { + modelMap, _ := ResourceIBMIsVolumeAllowedUseToMap(volumeIntf.AllowedUse) + allowedUses = append(allowedUses, modelMap) + } + bootVol["allowed_use"] = allowedUses + } + + bootVolList = append(bootVolList, bootVol) + + if err = d.Set(isInstanceTemplateBootVolume, bootVolList); err != nil { + err = fmt.Errorf("Error setting boot_volume: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-boot_volume").GetDiag() + } + } + + if instanceTemplate.ResourceGroup != nil { + if err = d.Set(isInstanceTemplateResourceGroup, instanceTemplate.ResourceGroup.ID); err != nil { + err = fmt.Errorf("Error setting resource_group: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-resource_group").GetDiag() } + } + case *vpcv1.InstanceTemplateInstanceBySourceSnapshotInstanceTemplateContext: + instanceTemplate := v - if volumeInst.Capacity != nil { - newVolume[isInstanceTemplateVolAttVolCapacity] = *volumeInst.Capacity + if !core.IsNil(instanceTemplate.Name) { + if err = d.Set("name", instanceTemplate.Name); err != nil { + err = fmt.Errorf("Error setting name: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-name").GetDiag() + } + } + if err = d.Set("crn", instanceTemplate.CRN); err != nil { + err = fmt.Errorf("Error setting crn: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-crn").GetDiag() + } + if instanceTemplate.AvailabilityPolicy != nil && instanceTemplate.AvailabilityPolicy.HostFailure != nil { + if err = d.Set("availability_policy_host_failure", instanceTemplate.AvailabilityPolicy.HostFailure); err != nil { + err = fmt.Errorf("Error setting availability_policy_host_failure: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-availability_policy_host_failure").GetDiag() } - if volumeInst.Profile != nil { - profile := volumeInst.Profile.(*vpcv1.VolumeProfileIdentity) - newVolume[isInstanceTemplateVolAttVolProfile] = profile.Name + } + // cluster changes + clusterNetworkAttachments := []map[string]interface{}{} + for _, clusterNetworkAttachmentsItem := range instanceTemplate.ClusterNetworkAttachments { + clusterNetworkAttachmentsItemMap, err := ResourceIBMIsInstanceTemplateInstanceClusterNetworkAttachmentPrototypeInstanceContextToMap(&clusterNetworkAttachmentsItem) // #nosec G601 + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "cluster_network_attachments-to-map").GetDiag() + } + clusterNetworkAttachments = append(clusterNetworkAttachments, clusterNetworkAttachmentsItemMap) + } + if err = d.Set("cluster_network_attachments", clusterNetworkAttachments); err != nil { + err = fmt.Errorf("Error setting cluster_network_attachments: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-cluster_network_attachments").GetDiag() + } + if !core.IsNil(instanceTemplate.ConfidentialComputeMode) { + if err = d.Set("confidential_compute_mode", instanceTemplate.ConfidentialComputeMode); err != nil { + err = fmt.Errorf("Error setting confidential_compute_mode: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-confidential_compute_mode").GetDiag() + } + } + if !core.IsNil(instanceTemplate.EnableSecureBoot) { + if err = d.Set("enable_secure_boot", instanceTemplate.EnableSecureBoot); err != nil { + err = fmt.Errorf("Error setting enable_secure_boot: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-enable_secure_boot").GetDiag() } + } - if volumeInst.Iops != nil { - newVolume[isInstanceTemplateVolAttVolIops] = *volumeInst.Iops + // vni if any + if !core.IsNil(instanceTemplate.NetworkAttachments) { + networkAttachments := []map[string]interface{}{} + for _, networkAttachmentsItem := range instanceTemplate.NetworkAttachments { + networkAttachmentsItemMap, err := resourceIBMIsInstanceTemplateNetworkAttachmentReferenceToMap(&networkAttachmentsItem, instanceC) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "network_attachments-to-map").GetDiag() + } + networkAttachments = append(networkAttachments, networkAttachmentsItemMap) } - if volumeInst.EncryptionKey != nil { - encryptionKey := volumeInst.EncryptionKey.(*vpcv1.EncryptionKeyIdentity) - newVolume[isInstanceTemplateVolAttVolEncryptionKey] = *encryptionKey.CRN + if err = d.Set("network_attachments", networkAttachments); err != nil { + err = fmt.Errorf("Error setting network_attachments: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-network_attachments").GetDiag() + } + } + + if !core.IsNil(instanceTemplate.PrimaryNetworkAttachment) { + primaryNetworkAttachmentMap, err := resourceIBMIsInstanceTemplateNetworkAttachmentReferenceToMap(instanceTemplate.PrimaryNetworkAttachment, instanceC) + if err != nil { + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "primary_network_attachment-to-map").GetDiag() } - if volumeInst.UserTags != nil { - newVolume[isInstanceTemplateVolAttTags] = volumeInst.UserTags + if err = d.Set("primary_network_attachment", []map[string]interface{}{primaryNetworkAttachmentMap}); err != nil { + err = fmt.Errorf("Error setting primary_network_attachment: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-primary_network_attachment").GetDiag() } - // bandwidth changes - if volumeInst.Bandwidth != nil { - newVolume["bandwidth"] = volumeInst.Bandwidth + } + + if instanceTemplate.ReservationAffinity != nil { + reservationAffinity := []map[string]interface{}{} + reservationAffinityMap := map[string]interface{}{} + + reservationAffinityMap[isReservationAffinityPolicyResp] = instanceTemplate.ReservationAffinity.Policy + if instanceTemplate.ReservationAffinity.Pool != nil && len(instanceTemplate.ReservationAffinity.Pool) > 0 { + pool := instanceTemplate.ReservationAffinity.Pool[0] + res := "" + if idPool, ok := pool.(*vpcv1.ReservationIdentityByID); ok { + res = *idPool.ID + } else if crnPool, ok := pool.(*vpcv1.ReservationIdentityByCRN); ok { + res = *crnPool.CRN + } else if hrefPool, ok := pool.(*vpcv1.ReservationIdentityByHref); ok { + res = *hrefPool.Href + } + reservationAffinityMap[isReservationAffinityPool] = res } - if len(newVolume) > 0 { - newVolumeArr = append(newVolumeArr, newVolume) + reservationAffinity = append(reservationAffinity, reservationAffinityMap) + if err = d.Set(isReservationAffinity, reservationAffinity); err != nil { + err = fmt.Errorf("Error setting reservation_affinity: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-reservation_affinity").GetDiag() } - volumeAttach[isInstanceTemplateVolAttVolPrototype] = newVolumeArr - interfacesList = append(interfacesList, volumeAttach) } - if err = d.Set(isInstanceTemplateVolumeAttachments, interfacesList); err != nil { - err = fmt.Errorf("Error setting volume_attachments: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-volume_attachments").GetDiag() + + if instanceTemplate.Profile != nil { + instanceProfileIntf := instanceTemplate.Profile + identity := instanceProfileIntf.(*vpcv1.InstanceProfileIdentity) + if err = d.Set(isInstanceTemplateProfile, *identity.Name); err != nil { + err = fmt.Errorf("Error setting profile: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-profile").GetDiag() + } } - } - if instanceTemplate.BootVolumeAttachment != nil { - bootVolList := make([]map[string]interface{}, 0) - bootVol := map[string]interface{}{} - bootVol[isInstanceTemplateDeleteVolume] = *instanceTemplate.BootVolumeAttachment.DeleteVolumeOnInstanceDelete - if instanceTemplate.BootVolumeAttachment.Volume != nil { - volumeIntf := instanceTemplate.BootVolumeAttachment.Volume - bootVol[isInstanceTemplateBootName] = volumeIntf.Name - bootVol[isInstanceTemplateBootSize] = volumeIntf.Capacity - if volumeIntf.Profile != nil { - volProfIntf := volumeIntf.Profile - volProfInst := volProfIntf.(*vpcv1.VolumeProfileIdentity) - bootVol[isInstanceTemplateBootProfile] = volProfInst.Name + + if instanceTemplate.DefaultTrustedProfile != nil { + if instanceTemplate.DefaultTrustedProfile.AutoLink != nil { + if err = d.Set(isInstanceDefaultTrustedProfileAutoLink, instanceTemplate.DefaultTrustedProfile.AutoLink); err != nil { + err = fmt.Errorf("Error setting default_trusted_profile_auto_link: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-default_trusted_profile_auto_link").GetDiag() + } + } + if instanceTemplate.DefaultTrustedProfile.Target != nil { + switch reflect.TypeOf(instanceTemplate.DefaultTrustedProfile.Target).String() { + case "*vpcv1.TrustedProfileIdentityTrustedProfileByID": + { + target := instanceTemplate.DefaultTrustedProfile.Target.(*vpcv1.TrustedProfileIdentityByID) + if err = d.Set(isInstanceDefaultTrustedProfileTarget, target.ID); err != nil { + err = fmt.Errorf("Error setting default_trusted_profile_target: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-default_trusted_profile_target").GetDiag() + } + } + case "*vpcv1.TrustedProfileIdentityTrustedProfileByCRN": + { + target := instanceTemplate.DefaultTrustedProfile.Target.(*vpcv1.TrustedProfileIdentityByCRN) + if err = d.Set(isInstanceDefaultTrustedProfileTarget, target.CRN); err != nil { + err = fmt.Errorf("Error setting default_trusted_profile_target: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-default_trusted_profile_target").GetDiag() + } + } + } + } + } + + if instanceTemplate.TotalVolumeBandwidth != nil { + if err = d.Set(isInstanceTotalVolumeBandwidth, int(*instanceTemplate.TotalVolumeBandwidth)); err != nil { + err = fmt.Errorf("Error setting total_volume_bandwidth: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-total_volume_bandwidth").GetDiag() + } + } + if instanceTemplate.MetadataService != nil { + if err = d.Set(isInstanceTemplateMetadataServiceEnabled, instanceTemplate.MetadataService.Enabled); err != nil { + err = fmt.Errorf("Error setting metadata_service_enabled: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-metadata_service_enabled").GetDiag() + } + metadataService := []map[string]interface{}{} + metadataServiceMap := map[string]interface{}{} + + metadataServiceMap[isInstanceMetadataServiceEnabled1] = instanceTemplate.MetadataService.Enabled + if instanceTemplate.MetadataService.Protocol != nil { + metadataServiceMap[isInstanceMetadataServiceProtocol] = instanceTemplate.MetadataService.Protocol + } + if instanceTemplate.MetadataService.ResponseHopLimit != nil { + metadataServiceMap[isInstanceMetadataServiceRespHopLimit] = instanceTemplate.MetadataService.ResponseHopLimit + } + metadataService = append(metadataService, metadataServiceMap) + if err = d.Set(isInstanceMetadataService, metadataService); err != nil { + err = fmt.Errorf("Error setting metadata_service: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-metadata_service").GetDiag() + } + } + + var placementTargetList []map[string]interface{} + if instanceTemplate.PlacementTarget != nil { + placementTargetMap := resourceIbmIsInstanceTemplateInstancePlacementTargetPrototypeToMap(*instanceTemplate.PlacementTarget.(*vpcv1.InstancePlacementTargetPrototype)) + if len(placementTargetMap) > 0 { + placementTargetList = append(placementTargetList, placementTargetMap) + } + } + if err = d.Set(isInstanceTemplatePlacementTarget, placementTargetList); err != nil { + err = fmt.Errorf("Error setting placement_target InstanceTemplateInstanceBySourceSnapshotInstanceTemplateContext: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-placement_target").GetDiag() + } + if instanceTemplate.PrimaryNetworkInterface != nil { + primaryNicList := make([]map[string]interface{}, 0) + currentPrimNic := map[string]interface{}{} + currentPrimNic[isInstanceTemplateNicName] = *instanceTemplate.PrimaryNetworkInterface.Name + if instanceTemplate.PrimaryNetworkInterface.PrimaryIP != nil { + pipIntf := instanceTemplate.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 } - if volumeIntf.EncryptionKey != nil { - volEncryption := volumeIntf.EncryptionKey - volEncryptionIntf := volEncryption.(*vpcv1.EncryptionKeyIdentity) - bootVol[isInstanceTemplateBootEncryption] = volEncryptionIntf.CRN + subInf := instanceTemplate.PrimaryNetworkInterface.Subnet + subnetIdentity := subInf.(*vpcv1.SubnetIdentity) + currentPrimNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID + if instanceTemplate.PrimaryNetworkInterface.AllowIPSpoofing != nil { + currentPrimNic[isInstanceTemplateNicAllowIPSpoofing] = *instanceTemplate.PrimaryNetworkInterface.AllowIPSpoofing } - if volumeIntf.UserTags != nil { - bootVol[isVolumeTags] = volumeIntf.UserTags + if len(instanceTemplate.PrimaryNetworkInterface.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(instanceTemplate.PrimaryNetworkInterface.SecurityGroups); i++ { + secGrpInf := instanceTemplate.PrimaryNetworkInterface.SecurityGroups[i] + subnetIdentity := secGrpInf.(*vpcv1.SecurityGroupIdentity) + secgrpList = append(secgrpList, string(*subnetIdentity.ID)) + } + currentPrimNic[isInstanceTemplateNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) } - if volumeIntf.Bandwidth != nil { - bootVol["bandwidth"] = volumeIntf.Bandwidth + primaryNicList = append(primaryNicList, currentPrimNic) + if err = d.Set(isInstanceTemplatePrimaryNetworkInterface, primaryNicList); err != nil { + err = fmt.Errorf("Error setting primary_network_interface: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-primary_network_interface").GetDiag() } } - bootVolList = append(bootVolList, bootVol) + if instanceTemplate.NetworkInterfaces != nil { + interfacesList := make([]map[string]interface{}, 0) + for _, intfc := range instanceTemplate.NetworkInterfaces { + currentNic := map[string]interface{}{} + currentNic[isInstanceTemplateNicName] = *intfc.Name + if intfc.PrimaryIP != nil { + // reserved ip changes + primaryIpList := make([]map[string]interface{}, 0) + currentPrimIp := map[string]interface{}{} + pipIntf := intfc.PrimaryIP + switch reflect.TypeOf(pipIntf).String() { + case "*vpcv1.NetworkInterfaceIPPrototype": + { + pip := pipIntf.(*vpcv1.NetworkInterfaceIPPrototype) + currentNic[isInstanceTemplateNicPrimaryIpv4Address] = pip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAddress] = pip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAutoDelete] = pip.AutoDelete + currentPrimIp[isInstanceTemplateNicReservedIpName] = pip.Name + currentPrimIp[isInstanceTemplateNicReservedIpId] = pip.ID + } + case "*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext": + { + pip := pipIntf.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext) + currentNic[isInstanceTemplateNicPrimaryIpv4Address] = pip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAddress] = pip.Address + currentPrimIp[isInstanceTemplateNicReservedIpAutoDelete] = pip.AutoDelete + currentPrimIp[isInstanceTemplateNicReservedIpName] = pip.Name + } + case "*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity": + { + pip := pipIntf.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity) + currentPrimIp[isInstanceTemplateNicReservedIpId] = pip.ID + } + } + primaryIpList = append(primaryIpList, currentPrimIp) + currentNic[isInstanceTemplateNicPrimaryIP] = primaryIpList + } + if intfc.AllowIPSpoofing != nil { + currentNic[isInstanceTemplateNicAllowIPSpoofing] = *intfc.AllowIPSpoofing + } + subInf := intfc.Subnet + subnetIdentity := subInf.(*vpcv1.SubnetIdentity) + currentNic[isInstanceTemplateNicSubnet] = *subnetIdentity.ID + if len(intfc.SecurityGroups) != 0 { + secgrpList := []string{} + for i := 0; i < len(intfc.SecurityGroups); i++ { + secGrpInf := intfc.SecurityGroups[i] + subnetIdentity := secGrpInf.(*vpcv1.SecurityGroupIdentity) + secgrpList = append(secgrpList, string(*subnetIdentity.ID)) + } + currentNic[isInstanceTemplateNicSecurityGroups] = flex.NewStringSet(schema.HashString, secgrpList) + } + interfacesList = append(interfacesList, currentNic) + } + if err = d.Set(isInstanceTemplateNetworkInterfaces, interfacesList); err != nil { + err = fmt.Errorf("Error setting network_interfaces: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-network_interfaces").GetDiag() + } + } - if err = d.Set(isInstanceTemplateBootVolume, bootVolList); err != nil { - err = fmt.Errorf("Error setting boot_volume: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-boot_volume").GetDiag() + vpcInf := instanceTemplate.VPC + vpcRef := vpcInf.(*vpcv1.VPCIdentity) + if err = d.Set(isInstanceTemplateVPC, vpcRef.ID); err != nil { + err = fmt.Errorf("Error setting vpc: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-vpc").GetDiag() + } + zoneInf := instanceTemplate.Zone + zone := zoneInf.(*vpcv1.ZoneIdentity) + if err = d.Set(isInstanceTemplateZone, *zone.Name); err != nil { + err = fmt.Errorf("Error setting zone: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-zone").GetDiag() + } + interfacesList := make([]map[string]interface{}, 0) + if instanceTemplate.VolumeAttachments != nil { + for _, volume := range instanceTemplate.VolumeAttachments { + volumeAttach := map[string]interface{}{} + volumeAttach[isInstanceTemplateVolAttName] = *volume.Name + volumeAttach[isInstanceTemplateDeleteVolume] = *volume.DeleteVolumeOnInstanceDelete + newVolumeArr := []map[string]interface{}{} + newVolume := map[string]interface{}{} + volumeIntf := volume.Volume + volumeInst := volumeIntf.(*vpcv1.VolumeAttachmentPrototypeVolume) + if volumeInst.ID != nil { + volumeAttach[isInstanceTemplateVolAttVol] = *volumeInst.ID + } + + if volumeInst.Capacity != nil { + newVolume[isInstanceTemplateVolAttVolCapacity] = *volumeInst.Capacity + } + if volumeInst.Profile != nil { + profile := volumeInst.Profile.(*vpcv1.VolumeProfileIdentity) + newVolume[isInstanceTemplateVolAttVolProfile] = profile.Name + } + + if volumeInst.Iops != nil { + newVolume[isInstanceTemplateVolAttVolIops] = *volumeInst.Iops + } + if volumeInst.EncryptionKey != nil { + encryptionKey := volumeInst.EncryptionKey.(*vpcv1.EncryptionKeyIdentity) + newVolume[isInstanceTemplateVolAttVolEncryptionKey] = *encryptionKey.CRN + } + if volumeInst.UserTags != nil { + newVolume[isInstanceTemplateVolAttTags] = volumeInst.UserTags + } + // bandwidth changes + if volumeInst.Bandwidth != nil { + newVolume["bandwidth"] = volumeInst.Bandwidth + } + // source_snapshot + if volumeInst.SourceSnapshot != nil { + sourceSnapshot := volumeInst.SourceSnapshot.(*vpcv1.SnapshotIdentity) + newVolume["source_snapshot"] = *sourceSnapshot.ID + } + + //allowed use + allowedUses := []map[string]interface{}{} + if volumeInst.AllowedUse != nil { + modelMap, err := ResourceIBMIsVolumeAllowedUseToMap(volumeInst.AllowedUse) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Resource) ibm_is_instance_template", "read") + log.Println(tfErr.GetDiag()) + } + allowedUses = append(allowedUses, modelMap) + newVolume["allowed_use"] = allowedUses + } + if len(newVolume) > 0 { + newVolumeArr = append(newVolumeArr, newVolume) + } + volumeAttach[isInstanceTemplateVolAttVolPrototype] = newVolumeArr + interfacesList = append(interfacesList, volumeAttach) + } + if err = d.Set(isInstanceTemplateVolumeAttachments, interfacesList); err != nil { + err = fmt.Errorf("Error setting volume_attachments: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-volume_attachments").GetDiag() + } + } + if instanceTemplate.BootVolumeAttachment != nil { + bootVolList := make([]map[string]interface{}, 0) + bootVol := map[string]interface{}{} + bootVol[isInstanceTemplateDeleteVolume] = *instanceTemplate.BootVolumeAttachment.DeleteVolumeOnInstanceDelete + if instanceTemplate.BootVolumeAttachment.Volume != nil { + volumeIntf := instanceTemplate.BootVolumeAttachment.Volume + bootVol[isInstanceTemplateBootName] = volumeIntf.Name + bootVol[isInstanceTemplateBootSize] = volumeIntf.Capacity + bootVol["source_snapshot"] = *volumeIntf.SourceSnapshot.(*vpcv1.SnapshotIdentity).ID + + if volumeIntf.Profile != nil { + volProfIntf := volumeIntf.Profile + volProfInst := volProfIntf.(*vpcv1.VolumeProfileIdentity) + bootVol[isInstanceTemplateBootProfile] = volProfInst.Name + } + if volumeIntf.EncryptionKey != nil { + volEncryption := volumeIntf.EncryptionKey + volEncryptionIntf := volEncryption.(*vpcv1.EncryptionKeyIdentity) + bootVol[isInstanceTemplateBootEncryption] = volEncryptionIntf.CRN + } + if volumeIntf.UserTags != nil { + bootVol[isVolumeTags] = volumeIntf.UserTags + } + if volumeIntf.Bandwidth != nil { + bootVol["bandwidth"] = volumeIntf.Bandwidth + } + allowedUses := []map[string]interface{}{} + if volumeIntf.AllowedUse != nil { + modelMap, _ := ResourceIBMIsVolumeAllowedUseToMap(volumeIntf.AllowedUse) + allowedUses = append(allowedUses, modelMap) + bootVol["allowed_use"] = allowedUses + } + } + + bootVolList = append(bootVolList, bootVol) + + if err = d.Set(isInstanceTemplateBootVolume, bootVolList); err != nil { + err = fmt.Errorf("Error setting boot_volume: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-boot_volume").GetDiag() + } } - } - if instanceTemplate.ResourceGroup != nil { - if err = d.Set(isInstanceTemplateResourceGroup, instanceTemplate.ResourceGroup.ID); err != nil { - err = fmt.Errorf("Error setting resource_group: %s", err) - return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-resource_group").GetDiag() + if instanceTemplate.ResourceGroup != nil { + if err = d.Set(isInstanceTemplateResourceGroup, instanceTemplate.ResourceGroup.ID); err != nil { + err = fmt.Errorf("Error setting resource_group: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_template", "read", "set-resource_group").GetDiag() + } } + default: + log.Println("Unknown or unsupported instance template context type") } + return nil } diff --git a/ibm/service/vpc/resource_ibm_is_instance_template_test.go b/ibm/service/vpc/resource_ibm_is_instance_template_test.go index 4395b3b383..fa30702326 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_template_test.go +++ b/ibm/service/vpc/resource_ibm_is_instance_template_test.go @@ -1175,3 +1175,360 @@ func testAccCheckIBMISInstanceTemplateWithBootBandwidth(vpcName, subnetName, ssh `, vpcName, subnetName, acc.ISZoneName, sshKeyName, publicKey, templateName, acc.IsImage, userTag, bandwidth, acc.ISZoneName) } + +func testAccCheckIBMISInstanceTemplateComprehensiveConfig(vpcName, subnetName, sshKeyName, publicKey, templateNameImg, templateNameSnapshot, templateNameCatalog string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "subnet" { + name = "%s" + vpc = ibm_is_vpc.vpc.id + zone = "%s" + total_ipv4_address_count = 64 + } + + resource "ibm_is_ssh_key" "sshkey" { + name = "%s" + public_key = "%s" + } + + data "ibm_is_image" "catalog_image" { + name = "%s" + } + + # Template 1: From Image + resource "ibm_is_instance_template" "template_from_image" { + name = "%s" + image = "%s" + profile = "cx2-2x4" + + primary_network_interface { + subnet = ibm_is_subnet.subnet.id + } + + vpc = ibm_is_vpc.vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.sshkey.id] + + user_data = base64encode(<<-EOF + #!/bin/bash + apt-get update + apt-get install -y nginx + systemctl start nginx + systemctl enable nginx + echo "Template from Image" > /var/www/html/index.html + EOF + ) + } + + # Template 2: From Snapshot + resource "ibm_is_instance_template" "template_from_snapshot" { + name = "%s" + profile = "cx2-2x4" + + boot_volume { + source_snapshot = "%s" + } + + primary_network_interface { + subnet = ibm_is_subnet.subnet.id + } + + vpc = ibm_is_vpc.vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.sshkey.id] + + user_data = base64encode(<<-EOF + #!/bin/bash + apt-get update + apt-get install -y nginx + systemctl start nginx + systemctl enable nginx + echo "Template from Snapshot" > /var/www/html/index.html + EOF + ) + } + + # Template 3: From Catalog Offering + resource "ibm_is_instance_template" "template_from_catalog" { + name = "%s" + profile = "cx2-2x4" + + catalog_offering { + version_crn = data.ibm_is_image.catalog_image.catalog_offering.0.version.0.crn + } + + primary_network_interface { + subnet = ibm_is_subnet.subnet.id + } + + vpc = ibm_is_vpc.vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.sshkey.id] + + user_data = base64encode(<<-EOF + #!/bin/bash + apt-get update + apt-get install -y nginx + systemctl start nginx + systemctl enable nginx + echo "Template from Catalog" > /var/www/html/index.html + EOF + ) + } + `, vpcName, subnetName, acc.ISZoneName, sshKeyName, publicKey, acc.ISCatalogImageName, templateNameImg, acc.IsImage, acc.ISZoneName, templateNameSnapshot, acc.ISBootSnapshotID, acc.ISZoneName, templateNameCatalog, acc.ISZoneName) +} + +func TestAccIBMISInstanceTemplate_comprehensive(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) + templateNameImg := fmt.Sprintf("tf-testtemplate-img%d", randInt) + templateNameSnapshot := fmt.Sprintf("tf-testtemplate-snapshot%d", randInt) + templateNameCatalog := fmt.Sprintf("tf-testtemplate-catalog%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: testAccCheckIBMISInstanceTemplateComprehensiveConfig(vpcName, subnetName, sshKeyName, publicKey, templateNameImg, templateNameSnapshot, templateNameCatalog), + Check: resource.ComposeTestCheckFunc( + // Check Template from Image + resource.TestCheckResourceAttr( + "ibm_is_instance_template.template_from_image", "name", templateNameImg), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.template_from_image", "image"), + resource.TestCheckResourceAttr( + "ibm_is_instance_template.template_from_image", "profile", "cx2-2x4"), + resource.TestCheckResourceAttr( + "ibm_is_instance_template.template_from_image", "zone", acc.ISZoneName), + + // Check Template from Snapshot + resource.TestCheckResourceAttr( + "ibm_is_instance_template.template_from_snapshot", "name", templateNameSnapshot), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.template_from_snapshot", "boot_volume.0.source_snapshot"), + resource.TestCheckResourceAttr( + "ibm_is_instance_template.template_from_snapshot", "profile", "cx2-2x4"), + resource.TestCheckResourceAttr( + "ibm_is_instance_template.template_from_snapshot", "zone", acc.ISZoneName), + + // Check Template from Catalog + resource.TestCheckResourceAttr( + "ibm_is_instance_template.template_from_catalog", "name", templateNameCatalog), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.template_from_catalog", "catalog_offering.0.version_crn"), + resource.TestCheckResourceAttr( + "ibm_is_instance_template.template_from_catalog", "profile", "cx2-2x4"), + resource.TestCheckResourceAttr( + "ibm_is_instance_template.template_from_catalog", "zone", acc.ISZoneName), + + // Check common attributes for all templates + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.template_from_image", "vpc"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.template_from_snapshot", "vpc"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.template_from_catalog", "vpc"), + ), + }, + }, + }) +} + +func TestAccIBMISInstanceTemplateBoot_WithAllowedUse(t *testing.T) { + randInt := acctest.RandIntRange(10, 100) + + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDVtuCfWKVGKaRmaRG6JQZY8YdxnDgGzVOK93IrV9R5Hl0JP1oiLLWlZQS2reAKb8lBqyDVEREpaoRUDjqDqXG8J/kR42FKN51su914pjSBc86wJ02VtT1Wm1zRbSg67kT+g8/T1jCgB5XBODqbcICHVP8Z1lXkgbiHLwlUrbz6OZkGJHo/M/kD1Eme8lctceIYNz/Ilm7ewMXZA4fsidpto9AjyarrJLufrOBl4MRVcZTDSJ7rLP982aHpu9pi5eJAjOZc7Og7n4ns3NFppiCwgVMCVUQbN5GBlWhZ1OsT84ZiTf+Zy8ew+Yg5T7Il8HuC7loWnz+esQPf0s3xhC/kTsGgZreIDoh/rxJfD67wKXetNSh5RH/n5BqjaOuXPFeNXmMhKlhj9nJ8scayx/wsvOGuocEIkbyJSLj3sLUU403OafgatEdnJOwbqg6rUNNF5RIjpJpL7eEWlKIi1j9LyhmPJ+fEO7TmOES82VpCMHpLbe4gf/MhhJ/Xy8DKh9s= root@ffd8363b1226 + `) + vpcName := fmt.Sprintf("tf-testvpc%d", randInt) + subnetName := fmt.Sprintf("tf-testsubnet%d", randInt) + templateName := fmt.Sprintf("tf-testtemplate%d", randInt) + volAttachName := fmt.Sprintf("tf-testvolattach%d", randInt) + sshKeyName := fmt.Sprintf("tf-testsshkey%d", randInt) + userTag := "tag-0" + bandwidth := int64(2000) + apiVersion := "2025-07-02" + bareMetalServer := "true" + instanceval := "true" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceTemplateWithBoot_AllowedUse(vpcName, subnetName, sshKeyName, publicKey, templateName, volAttachName, userTag, apiVersion, bareMetalServer, instanceval, bandwidth), + 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", "boot_volume.0.allowed_use.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "boot_volume.0.allowed_use.0.bare_metal_server"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "boot_volume.0.allowed_use.0.instance"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "boot_volume.0.allowed_use.0.api_version"), + resource.TestCheckResourceAttr("ibm_is_instance_template.instancetemplate1", "boot_volume.0.allowed_use.0.bare_metal_server", bareMetalServer), + resource.TestCheckResourceAttr("ibm_is_instance_template.instancetemplate1", "boot_volume.0.allowed_use.0.instance", instanceval), + resource.TestCheckResourceAttr("ibm_is_instance_template.instancetemplate1", "boot_volume.0.allowed_use.0.api_version", apiVersion), + ), + }, + }, + }) +} + +func testAccCheckIBMISInstanceTemplateWithBoot_AllowedUse(vpcName, subnetName, sshKeyName, publicKey, templateName, volAttachName, userTag, apiVersion, bareMetalServer, instanceval string, bandwidth int64) 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" + total_ipv4_address_count = 256 + } + + resource "ibm_is_ssh_key" "sshkey" { + name = "%s" + public_key = "%s" + } + resource "ibm_is_instance_template" "instancetemplate1" { + name = "%s" + image = "%s" + profile = "bx2-8x32" + + primary_network_interface { + subnet = ibm_is_subnet.subnet2.id + } + boot_volume{ + tags = ["%s"] + bandwidth = %d + profile = "sdp" + size = 250 + allowed_use { + api_version = "%s" + bare_metal_server = "%s" + instance = "%s" + } + } + vpc = ibm_is_vpc.vpc2.id + zone = "%s" + keys = [ibm_is_ssh_key.sshkey.id] + } + + + `, vpcName, subnetName, acc.ISZoneName, sshKeyName, publicKey, templateName, acc.IsImage, userTag, bandwidth, apiVersion, bareMetalServer, instanceval, acc.ISZoneName) + +} + +func TestAccIBMISInstanceTemplate_WithAllowedUse(t *testing.T) { + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + templateName := fmt.Sprintf("tf-instance-template-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfsnapshotuat-%d", acctest.RandIntRange(10, 100)) + apiVersion := "2025-07-01" + bareMetalServer := "true" + instanceVal := "true" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceTemplateWith_AllowedUse(vpcname, subnetname, sshname, publicKey, volname, name, name1, apiVersion, bareMetalServer, instanceVal, templateName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_is_instance_template.instancetemplate1", "name", templateName), + // boot volume allowed use + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "boot_volume.0.allowed_use.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "boot_volume.0.allowed_use.0.bare_metal_server"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "boot_volume.0.allowed_use.0.instance"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "boot_volume.0.allowed_use.0.api_version"), + resource.TestCheckResourceAttr("ibm_is_instance_template.instancetemplate1", "boot_volume.0.allowed_use.0.bare_metal_server", bareMetalServer), + resource.TestCheckResourceAttr("ibm_is_instance_template.instancetemplate1", "boot_volume.0.allowed_use.0.instance", instanceVal), + resource.TestCheckResourceAttr("ibm_is_instance_template.instancetemplate1", "boot_volume.0.allowed_use.0.api_version", apiVersion), + + // volume attchment volume_prototype allowed use + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "volume_attachments.0.volume_prototype.0.allowed_use.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "volume_attachments.0.volume_prototype.0.allowed_use.0.bare_metal_server"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "volume_attachments.0.volume_prototype.0.allowed_use.0.instance"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "volume_attachments.0.volume_prototype.0.allowed_use.0.api_version"), + resource.TestCheckResourceAttr("ibm_is_instance_template.instancetemplate1", "volume_attachments.0.volume_prototype.0.allowed_use.0.bare_metal_server", bareMetalServer), + resource.TestCheckResourceAttr("ibm_is_instance_template.instancetemplate1", "volume_attachments.0.volume_prototype.0.allowed_use.0.instance", instanceVal), + resource.TestCheckResourceAttr("ibm_is_instance_template.instancetemplate1", "volume_attachments.0.volume_prototype.0.allowed_use.0.api_version", apiVersion), + ), + }, + }, + }) +} + +func testAccCheckIBMISInstanceTemplateWith_AllowedUse(vpcname, subnetname, sshname, publicKey, volname, name, sname, apiVersion, bareMetalServer, instanceVal, templateName string) string { + return testAccCheckIBMISSnapshotConfigAllowedUse(vpcname, subnetname, sshname, publicKey, volname, name, sname, apiVersion, bareMetalServer, instanceVal) + fmt.Sprintf(` + resource "ibm_is_instance_template" "instancetemplate1" { + name = "%s" + profile = "bx2-8x32" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + boot_volume { + profile = "general-purpose" + size = 250 + source_snapshot = ibm_is_snapshot.testacc_snapshot.id + allowed_use { + api_version = "%s" + bare_metal_server = "%s" + instance = "%s" + } + } + volume_attachments { + delete_volume_on_instance_delete = true + name = "volume-attachment-tfp" + volume_prototype { + iops = 6000 + profile = "custom" + capacity = 100 + source_snapshot = ibm_is_snapshot.testacc_snapshot.id + allowed_use { + api_version = "%s" + bare_metal_server = "%s" + instance = "%s" + } + } + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + } + `, templateName, apiVersion, bareMetalServer, instanceVal, apiVersion, bareMetalServer, instanceVal, acc.ISZoneName) + +} diff --git a/ibm/service/vpc/resource_ibm_is_instance_test.go b/ibm/service/vpc/resource_ibm_is_instance_test.go index 9f2f0fadd0..3b8f4179b3 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_test.go +++ b/ibm/service/vpc/resource_ibm_is_instance_test.go @@ -4459,3 +4459,106 @@ func testAccCheckIBMISInstanceVolumeTagsConfig(prefix, vpcname, subnetname, sshn } `, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, prefix, dataVolumeName, dataVolumeName) } + +func TestAccIBMISInstance_AllowedUse(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)) + instanceName := fmt.Sprintf("tf-instance-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfsnapshotuat-%d", acctest.RandIntRange(10, 100)) + apiVersion := "2025-07-02" + bareMetalServer := "true" + instanceval := "true" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceConfig_AllowedUse(vpcname, subnetname, sshname, publicKey, volname, name, name1, apiVersion, bareMetalServer, instanceval, instanceName), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance_allowed_use", instance), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance_allowed_use", "name", instanceName), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance_allowed_use", "zone", acc.ISZoneName), + + // Volume prototype checks + resource.TestCheckResourceAttr("ibm_is_instance.testacc_instance_allowed_use", "volume_prototypes.#", "1"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance_allowed_use", "volume_prototypes.0.allowed_use.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance_allowed_use", "volume_prototypes.0.allowed_use.0.bare_metal_server"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance_allowed_use", "volume_prototypes.0.allowed_use.0.instance"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance_allowed_use", "volume_prototypes.0.allowed_use.0.api_version"), + resource.TestCheckResourceAttr("ibm_is_instance.testacc_instance_allowed_use", "volume_prototypes.0.allowed_use.0.bare_metal_server", bareMetalServer), + resource.TestCheckResourceAttr("ibm_is_instance.testacc_instance_allowed_use", "volume_prototypes.0.allowed_use.0.instance", instanceval), + resource.TestCheckResourceAttr("ibm_is_instance.testacc_instance_allowed_use", "volume_prototypes.0.allowed_use.0.api_version", apiVersion), + + // Boot volume checks + resource.TestCheckResourceAttr("ibm_is_instance.testacc_instance_allowed_use", "boot_volume.#", "1"), + resource.TestCheckResourceAttrSet("ibm_is_instance.testacc_instance_allowed_use", "boot_volume.0.volume_id"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance_allowed_use", "boot_volume.0.allowed_use.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance_allowed_use", "boot_volume.0.allowed_use.0.bare_metal_server"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance_allowed_use", "boot_volume.0.allowed_use.0.instance"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance.testacc_instance_allowed_use", "boot_volume.0.allowed_use.0.api_version"), + resource.TestCheckResourceAttr("ibm_is_instance.testacc_instance_allowed_use", "boot_volume.0.allowed_use.0.bare_metal_server", bareMetalServer), + resource.TestCheckResourceAttr("ibm_is_instance.testacc_instance_allowed_use", "boot_volume.0.allowed_use.0.instance", instanceval), + resource.TestCheckResourceAttr("ibm_is_instance.testacc_instance_allowed_use", "boot_volume.0.allowed_use.0.api_version", apiVersion), + ), + }, + }, + }) +} + +func testAccCheckIBMISInstanceConfig_AllowedUse(vpcname, subnetname, sshname, publicKey, volname, name, name1, apiVersion, bareMetalServer, instanceval, insName string) string { + + return testAccCheckIBMISSnapshotConfig(vpcname, subnetname, sshname, publicKey, volname, name, name1) + fmt.Sprintf(` + resource "ibm_is_instance" "testacc_instance_allowed_use" { + name = "%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] + boot_volume { + name = "example-boot-volume" + snapshot = ibm_is_snapshot.testacc_snapshot.id + size = 100 + allowed_use { + api_version = "%s" + instance = "%s" + bare_metal_server = "%s" + } + } + volume_prototypes { + name = "example-prototype" + delete_volume_on_instance_delete = true + volume_name = "example-volume" + volume_capacity = 100 + volume_profile = "custom" + volume_source_snapshot = ibm_is_snapshot.testacc_snapshot.id + allowed_use { + api_version = "%s" + bare_metal_server = "%s" + instance = "%s" + } + } + } + `, insName, acc.InstanceProfileName, acc.ISZoneName, apiVersion, bareMetalServer, instanceval, apiVersion, bareMetalServer, instanceval) +} diff --git a/ibm/service/vpc/resource_ibm_is_instance_volume_attachment.go b/ibm/service/vpc/resource_ibm_is_instance_volume_attachment.go index 012e0b2573..a3c06524fa 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_volume_attachment.go +++ b/ibm/service/vpc/resource_ibm_is_instance_volume_attachment.go @@ -224,6 +224,39 @@ func ResourceIBMISInstanceVolumeAttachment() *schema.Resource { Type: schema.TypeString, Computed: true, }, + + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "The usage constraints to be matched against requested instance or bare metal server properties to determine compatibility.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_volume_attachment", "allowed_use.api_version"), + Description: "The API version with which to evaluate the expressions.", + }, + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_volume_attachment", "allowed_use.bare_metal_server"), + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume.", + }, + "instance": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_volume_attachment", "allowed_use.instance"), + Description: "The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume.", + }, + }, + }, + }, }, } } @@ -281,6 +314,27 @@ func ResourceIBMISInstanceVolumeAttachmentValidator() *validate.ResourceValidato Regexp: `^[A-Za-z0-9:_ .-]+$`, MinValueLength: 1, MaxValueLength: 128}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "allowed_use.api_version", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$`}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "allowed_use.bare_metal_server", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([a-zA-Z_][a-zA-Z0-9_]*|[-+*/%]|&&|\|\||!|==|!=|<|<=|>|>=|~|\bin\b|\(|\)|\[|\]|,|\.|"|'|"|'|\s+|\d+)+$`}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "allowed_use.instance", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([a-zA-Z_][a-zA-Z0-9_]*|[-+*/%]|&&|\|\||!|==|!=|<|<=|>|>=|~|\bin\b|\(|\)|\[|\]|,|\.|"|'|"|'|\s+|\d+)+$`}) ibmISInstanceVolumeAttachmentValidator := validate.ResourceValidator{ResourceName: "ibm_is_instance_volume_attachment", Schema: validateSchema} return &ibmISInstanceVolumeAttachmentValidator @@ -380,6 +434,10 @@ func instanceVolAttachmentCreate(context context.Context, d *schema.ResourceData volProtoVol.Bandwidth = &volBandwidthInt } } + if allowedUse, ok := d.GetOk("allowed_use"); ok { + allowedUseModel, _ := ResourceIBMIsVolumeAllowedUseMapToVolumeAllowedUsePrototype(allowedUse.([]interface{})[0].(map[string]interface{})) + volProtoVol.AllowedUse = allowedUseModel + } var iops int64 if volIops, ok := d.GetOk(isInstanceVolIops); ok { iops = int64(volIops.(int)) @@ -598,6 +656,19 @@ func instanceVolumeAttachmentGet(context context.Context, d *schema.ResourceData return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_volume_attachment", "read", "set-snapshot_crn").GetDiag() } } + allowedUses := []map[string]interface{}{} + if volumeDetail.AllowedUse != nil { + modelMap, err := ResourceceIBMIsVolumeAllowedUseToMap(volumeDetail.AllowedUse) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Resource) ibm_is_instance_volume_attachment", "read") + log.Println(tfErr.GetDiag()) + } + allowedUses = append(allowedUses, modelMap) + } + if err = d.Set("allowed_use", allowedUses); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting allowed_use: %s", err), "(Resource) ibm_is_instance_volume_attachment", "read") + log.Println(tfErr.GetDiag()) + } tags, err := flex.GetGlobalTagsUsingCRN(meta, *volumeDetail.CRN, "", isInstanceUserTagType) if err != nil { log.Printf( @@ -714,12 +785,56 @@ func instanceVolAttUpdate(context context.Context, d *schema.ResourceData, meta } + if d.HasChange("allowed_use") { + volId := d.Get(isInstanceVolAttVol).(string) + volumeProfilePatchModel := &vpcv1.VolumePatch{} + if d.HasChange("allowed_use") { + allowedUseModel, _ := ResourceIBMIsInstanceMapToVolumeAllowedUsePatchPrototype(d.Get("allowed_use").([]interface{})[0].(map[string]interface{})) + volumeProfilePatchModel.AllowedUse = allowedUseModel + } + volumeProfilePatch, err := volumeProfilePatchModel.AsPatch() + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("volumeProfilePatchModel.AsPatch() failed: %s", err.Error()), "ibm_is_instance_volume_attachment", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + optionsget := &vpcv1.GetVolumeOptions{ + ID: &volId, + } + _, response, err := instanceC.GetVolumeWithContext(context, optionsget) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetVolumeWithContext failed: %s", err.Error()), "ibm_is_instance_volume_attachment", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + eTag := response.Headers.Get("ETag") + updateVolumeProfileOptions := &vpcv1.UpdateVolumeOptions{ + ID: &volId, + } + updateVolumeProfileOptions.IfMatch = &eTag + updateVolumeProfileOptions.VolumePatch = volumeProfilePatch + _, response, err = instanceC.UpdateVolumeWithContext(context, updateVolumeProfileOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("UpdateVolumeWithContext failed: %s", err.Error()), "ibm_is_instance_volume_attachment", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + _, err = isWaitForVolumeAvailable(instanceC, volId, d.Timeout(schema.TimeoutCreate)) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("isWaitForVolumeAvailable failed: %s", err.Error()), "ibm_is_instance_volume_attachment", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + } + // profile/iops update volId := "" if volIdOk, ok := d.GetOk(isInstanceVolAttVol); ok { volId = volIdOk.(string) } + volProfile := "" if volProfileOk, ok := d.GetOk(isInstanceVolProfile); ok { volProfile = volProfileOk.(string) diff --git a/ibm/service/vpc/resource_ibm_is_snapshot.go b/ibm/service/vpc/resource_ibm_is_snapshot.go index ec41ec6e32..83b767e4aa 100644 --- a/ibm/service/vpc/resource_ibm_is_snapshot.go +++ b/ibm/service/vpc/resource_ibm_is_snapshot.go @@ -474,6 +474,39 @@ func ResourceIBMSnapshot() *schema.Resource { }, }, }, + + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "The usage constraints to match against the requested instance or bare metal server properties to determine compatibility. Can only be specified for bootable snapshots.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_snapshot", "allowed_use.api_version"), + Description: "The expression that must be satisfied by the properties of a virtual server instance provisioned using this snapshot.", + }, + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_snapshot", "allowed_use.bare_metal_server"), + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this snapshot.", + }, + "instance": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_snapshot", "allowed_use.instance"), + Description: "The expression that must be satisfied by a virtual server instance provisioned using this image.", + }, + }, + }, + }, }, } } @@ -508,6 +541,27 @@ func ResourceIBMISSnapshotValidator() *validate.ResourceValidator { Regexp: `^([A-Za-z0-9_.-]|[A-Za-z0-9_.-][A-Za-z0-9_ .-]*[A-Za-z0-9_.-]):([A-Za-z0-9_.-]|[A-Za-z0-9_.-][A-Za-z0-9_ .-]*[A-Za-z0-9_.-])$`, MinValueLength: 1, MaxValueLength: 128}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "allowed_use.api_version", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$`}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "allowed_use.bare_metal_server", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([a-zA-Z_][a-zA-Z0-9_]*|[-+*/%]|&&|\|\||!|==|!=|<|<=|>|>=|~|\bin\b|\(|\)|\[|\]|,|\.|"|'|"|'|\s+|\d+)+$`}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "allowed_use.instance", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([a-zA-Z_][a-zA-Z0-9_]*|[-+*/%]|&&|\|\||!|==|!=|<|<=|>|>=|~|\bin\b|\(|\)|\[|\]|,|\.|"|'|"|'|\s+|\d+)+$`}) ibmISSnapshotResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_snapshot", Schema: validateSchema} return &ibmISSnapshotResourceValidator } @@ -538,6 +592,11 @@ func resourceIBMISSnapshotCreate(context context.Context, d *schema.ResourceData snapshotprototypeoptions.Name = &name } + if allowedUse, ok := d.GetOk("allowed_use"); ok { + allowedUseModel, _ := ResourceIBMIsSnapshotMapToSnapshotAllowedUse(allowedUse.([]interface{})[0].(map[string]interface{})) + snapshotprototypeoptions.AllowedUse = allowedUseModel + } + if grp, ok := d.GetOk(isVPCResourceGroup); ok { rg := grp.(string) snapshotprototypeoptions.ResourceGroup = &vpcv1.ResourceGroupIdentity{ @@ -562,6 +621,11 @@ func resourceIBMISSnapshotCreate(context context.Context, d *schema.ResourceData } } + if allowedUse, ok := d.GetOk("allowed_use"); ok { + allowedUseModel, _ := ResourceIBMIsSnapshotMapToSnapshotAllowedUse(allowedUse.([]interface{})[0].(map[string]interface{})) + snapshotprototypeoptionsbysourcesnapshot.AllowedUse = allowedUseModel + } + if grp, ok := d.GetOk(isVPCResourceGroup); ok { rg := grp.(string) snapshotprototypeoptionsbysourcesnapshot.ResourceGroup = &vpcv1.ResourceGroupIdentity{ @@ -612,7 +676,6 @@ func resourceIBMISSnapshotCreate(context context.Context, d *schema.ResourceData } } } - if snapbyVolFlag { options.SnapshotPrototype = snapshotprototypeoptions } else { @@ -914,6 +977,19 @@ func snapshotGet(context context.Context, d *schema.ResourceData, meta interface err = fmt.Errorf("Error setting backup_policy_plan: %s", err) return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_snapshot", "read", "set-backup_policy_plan").GetDiag() } + allowedUses := []map[string]interface{}{} + if snapshot.AllowedUse != nil { + modelMap, err := DataSourceIBMIsSnapshotAllowedUseToMap(snapshot.AllowedUse) + if err != nil { + err = fmt.Errorf("Error setting allowed_use: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_snapshot", "read", "set-allowed_use").GetDiag() + } + allowedUses = append(allowedUses, modelMap) + } + if err = d.Set("allowed_use", allowedUses); err != nil { + err = fmt.Errorf("Error setting allowed_use: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_snapshot", "read", "set-allowed_use").GetDiag() + } accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *snapshot.CRN, "", isAccessTagType) if err != nil { log.Printf( @@ -1042,6 +1118,57 @@ func snapshotUpdate(context context.Context, d *schema.ResourceData, meta interf } } + + if d.HasChange("allowed_use") { + getSnapshotOptions := &vpcv1.GetSnapshotOptions{ + ID: &id, + } + _, response, err := sess.GetSnapshot(getSnapshotOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetSnapshotWithContext failed: %s", err.Error()), "ibm_is_snapshot", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + eTag := response.Headers.Get("ETag") + + updateSnapshotOptions := &vpcv1.UpdateSnapshotOptions{ + ID: &id, + } + updateSnapshotOptions.IfMatch = &eTag + allowedUseModel, err := ResourceIBMIsSnapshotMapToSnapshotAllowedUsePatch(d.Get("allowed_use").([]interface{})[0].(map[string]interface{})) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error in settting allowed_use: %s", err.Error()), "ibm_is_snapshot", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + snapshotPatchModel := &vpcv1.SnapshotPatch{ + AllowedUse: allowedUseModel, + } + snapshotPatch, err := snapshotPatchModel.AsPatch() + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("snapshotPatchModel.AsPatch failed: %s", err.Error()), "ibm_is_snapshot", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + updateSnapshotOptions.SnapshotPatch = snapshotPatch + _, response, err = sess.UpdateSnapshot(updateSnapshotOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("UpdateSnapshotWithContext failed: %s", err.Error()), "ibm_is_snapshot", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + _, err = isWaitForSnapshotUpdate(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Wait for Snapshot update failed: %s", err.Error()), "ibm_is_snapshot", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + } + if d.HasChange(isSnapshotClones) { ovs, nvs := d.GetChange(isSnapshotClones) ov := ovs.(*schema.Set) @@ -1313,3 +1440,30 @@ func snapshotExists(d *schema.ResourceData, meta interface{}, id string) (bool, } return true, nil } +func ResourceIBMIsSnapshotMapToSnapshotAllowedUsePatch(modelMap map[string]interface{}) (*vpcv1.SnapshotAllowedUsePatch, error) { + model := &vpcv1.SnapshotAllowedUsePatch{} + if modelMap["api_version"] != nil && modelMap["api_version"].(string) != "" { + model.ApiVersion = core.StringPtr(modelMap["api_version"].(string)) + } + if modelMap["bare_metal_server"] != nil && modelMap["bare_metal_server"].(string) != "" { + model.BareMetalServer = core.StringPtr(modelMap["bare_metal_server"].(string)) + } + if modelMap["instance"] != nil && modelMap["instance"].(string) != "" { + model.Instance = core.StringPtr(modelMap["instance"].(string)) + } + return model, nil +} + +func ResourceIBMIsSnapshotMapToSnapshotAllowedUse(modelMap map[string]interface{}) (*vpcv1.SnapshotAllowedUsePrototype, error) { + model := &vpcv1.SnapshotAllowedUsePrototype{} + if modelMap["api_version"] != nil && modelMap["api_version"].(string) != "" { + model.ApiVersion = core.StringPtr(modelMap["api_version"].(string)) + } + if modelMap["bare_metal_server"] != nil && modelMap["bare_metal_server"].(string) != "" { + model.BareMetalServer = core.StringPtr(modelMap["bare_metal_server"].(string)) + } + if modelMap["instance"] != nil && modelMap["instance"].(string) != "" { + model.Instance = core.StringPtr(modelMap["instance"].(string)) + } + return model, nil +} diff --git a/ibm/service/vpc/resource_ibm_is_snapshot_test.go b/ibm/service/vpc/resource_ibm_is_snapshot_test.go index c18d61e340..a37a47fa33 100644 --- a/ibm/service/vpc/resource_ibm_is_snapshot_test.go +++ b/ibm/service/vpc/resource_ibm_is_snapshot_test.go @@ -55,6 +55,72 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }, }) } + +func TestAccIBMISSnapshot_allowedUse(t *testing.T) { + var snapshot string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfsnapshotuat-%d", acctest.RandIntRange(10, 100)) + name2 := fmt.Sprintf("tfsnapshotuat-%d", acctest.RandIntRange(10, 100)) + apiVersion := "2025-07-01" + bareMetalServer := "true" + instance := "true" + apiVersionUpdate := "2025-07-02" + bareMetalServerUpdate := "true" + instanceUpdate := "true" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISSnapshotDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISSnapshotConfigAllowedUse(vpcname, subnetname, sshname, publicKey, volname, name, name1, apiVersion, bareMetalServer, instance), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISSnapshotExists("ibm_is_snapshot.testacc_snapshot", snapshot), + resource.TestCheckResourceAttr( + "ibm_is_snapshot.testacc_snapshot", "name", name1), + resource.TestCheckResourceAttrSet( + "ibm_is_snapshot.testacc_snapshot", "allowed_use.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_snapshot.testacc_snapshot", "allowed_use.0.bare_metal_server"), + resource.TestCheckResourceAttrSet( + "ibm_is_snapshot.testacc_snapshot", "allowed_use.0.instance"), + resource.TestCheckResourceAttrSet( + "ibm_is_snapshot.testacc_snapshot", "allowed_use.0.api_version"), + resource.TestCheckResourceAttr("ibm_is_snapshot.testacc_snapshot", "allowed_use.0.bare_metal_server", bareMetalServer), + resource.TestCheckResourceAttr("ibm_is_snapshot.testacc_snapshot", "allowed_use.0.instance", instance), + resource.TestCheckResourceAttr("ibm_is_snapshot.testacc_snapshot", "allowed_use.0.api_version", apiVersion), + ), + }, + { + Config: testAccCheckIBMISSnapshotConfigAllowedUse(vpcname, subnetname, sshname, publicKey, volname, name, name2, apiVersionUpdate, bareMetalServerUpdate, instanceUpdate), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISSnapshotExists("ibm_is_snapshot.testacc_snapshot", snapshot), + resource.TestCheckResourceAttr( + "ibm_is_snapshot.testacc_snapshot", "name", name2), + resource.TestCheckResourceAttrSet( + "ibm_is_snapshot.testacc_snapshot", "allowed_use.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_snapshot.testacc_snapshot", "allowed_use.0.bare_metal_server"), + resource.TestCheckResourceAttrSet( + "ibm_is_snapshot.testacc_snapshot", "allowed_use.0.instance"), + resource.TestCheckResourceAttrSet( + "ibm_is_snapshot.testacc_snapshot", "allowed_use.0.api_version"), + resource.TestCheckResourceAttr("ibm_is_snapshot.testacc_snapshot", "allowed_use.0.bare_metal_server", bareMetalServerUpdate), + resource.TestCheckResourceAttr("ibm_is_snapshot.testacc_snapshot", "allowed_use.0.instance", instanceUpdate), + resource.TestCheckResourceAttr("ibm_is_snapshot.testacc_snapshot", "allowed_use.0.api_version", apiVersionUpdate), + ), + }, + }, + }) +} + func TestAccIBMISSnapshot_serviceTags(t *testing.T) { var snapshot string vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) @@ -310,6 +376,52 @@ func testAccCheckIBMISSnapshotConfig(vpcname, subnetname, sshname, publicKey, vo }`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, sname) } + +func testAccCheckIBMISSnapshotConfigAllowedUse(vpcname, subnetname, sshname, publicKey, volname, name, sname, apiVersion, bareMetalServer, instance string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + network_interfaces { + subnet = ibm_is_subnet.testacc_subnet.id + name = "eth1" + } + } + resource "ibm_is_snapshot" "testacc_snapshot" { + name = "%s" + source_volume = ibm_is_instance.testacc_instance.volume_attachments[0].volume_id + allowed_use { + api_version = "%s" + bare_metal_server = "%s" + instance = "%s" + } + }`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, sname, apiVersion, bareMetalServer, instance) + +} + func testAccCheckIBMISSnapshotEncryptedConfig(vpcname, subnetname, sshname, publicKey, volname, name, sname string) string { return fmt.Sprintf(` resource "ibm_is_vpc" "testacc_vpc" { diff --git a/ibm/service/vpc/resource_ibm_is_volume.go b/ibm/service/vpc/resource_ibm_is_volume.go index a29c7dab53..ab315fcafa 100644 --- a/ibm/service/vpc/resource_ibm_is_volume.go +++ b/ibm/service/vpc/resource_ibm_is_volume.go @@ -239,6 +239,38 @@ func ResourceIBMISVolume() *schema.Resource { }, }, }, + "allowed_use": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "The usage constraints to match against the requested instance or bare metal server properties to determine compatibility.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", "allowed_use.api_version"), + Description: "The API version with which to evaluate the expressions.", + }, + "bare_metal_server": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", "allowed_use.bare_metal_server"), + Description: "The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume.", + }, + "instance": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", "allowed_use.instance"), + Description: "The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume.", + }, + }, + }, + }, // defined_performance changes "adjustable_capacity_states": &schema.Schema{ Type: schema.TypeList, @@ -448,6 +480,27 @@ func ResourceIBMISVolumeValidator() *validate.ResourceValidator { Regexp: `^([A-Za-z0-9_.-]|[A-Za-z0-9_.-][A-Za-z0-9_ .-]*[A-Za-z0-9_.-]):([A-Za-z0-9_.-]|[A-Za-z0-9_.-][A-Za-z0-9_ .-]*[A-Za-z0-9_.-])$`, MinValueLength: 1, MaxValueLength: 128}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "allowed_use.api_version", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$`}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "allowed_use.bare_metal_server", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([a-zA-Z_][a-zA-Z0-9_]*|[-+*/%]|&&|\|\||!|==|!=|<|<=|>|>=|~|\bin\b|\(|\)|\[|\]|,|\.|"|'|"|'|\s+|\d+)+$`}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "allowed_use.instance", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([a-zA-Z_][a-zA-Z0-9_]*|[-+*/%]|&&|\|\||!|==|!=|<|<=|>|>=|~|\bin\b|\(|\)|\[|\]|,|\.|"|'|"|'|\s+|\d+)+$`}) ibmISVolumeResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_volume", Schema: validateSchema} return &ibmISVolumeResourceValidator @@ -562,6 +615,11 @@ func volCreate(context context.Context, d *schema.ResourceData, meta interface{} volTemplate.UserTags = userTagsArray } } + if allowedUse, ok := d.GetOk("allowed_use"); ok { + allowedUseModel, _ := ResourceIBMIsVolumeAllowedUseMapToVolumeAllowedUsePrototype(allowedUse.([]interface{})[0].(map[string]interface{})) + volTemplate.AllowedUse = allowedUseModel + } + options.VolumePrototype = volTemplate vol, _, err := sess.CreateVolumeWithContext(context, options) if err != nil { @@ -740,6 +798,19 @@ func volGet(context context.Context, d *schema.ResourceData, meta interface{}, i return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_volume", "read", "set-health_reasons").GetDiag() } } + allowedUses := []map[string]interface{}{} + if volume.AllowedUse != nil { + modelMap, err := ResourceceIBMIsVolumeAllowedUseToMap(volume.AllowedUse) + if err != nil { + err = fmt.Errorf("Error setting allowed_use: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_volume", "read", "set-allowed_use").GetDiag() + } + allowedUses = append(allowedUses, modelMap) + } + if err = d.Set("allowed_use", allowedUses); err != nil { + err = fmt.Errorf("Error setting allowed_use: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_volume", "read", "set-allowed_use").GetDiag() + } // catalog catalogList := make([]map[string]interface{}, 0) if volume.CatalogOffering != nil { @@ -960,6 +1031,49 @@ func volUpdate(context context.Context, d *schema.ResourceData, meta interface{} } } + if d.HasChange("allowed_use") { + allowedUseModel, _ := ResourceIBMIsInstanceMapToVolumeAllowedUsePatchPrototype(d.Get("allowed_use").([]interface{})[0].(map[string]interface{})) + optionsget := &vpcv1.GetVolumeOptions{ + ID: &id, + } + _, response, err := sess.GetVolume(optionsget) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetVolumeWithContext failed: %s", err.Error()), "ibm_is_volume", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + eTag := response.Headers.Get("ETag") + options := &vpcv1.UpdateVolumeOptions{ + ID: &id, + } + options.IfMatch = &eTag + volumePatchModel := &vpcv1.VolumePatch{} + volumePatchModel.AllowedUse = allowedUseModel + volumePatch, err := volumePatchModel.AsPatch() + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("volumeProfilePatchModel.AsPatch() for iops failed: %s", err.Error()), "ibm_is_volume", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + options.VolumePatch = volumePatch + _, _, err = sess.UpdateVolumeWithContext(context, options) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("UpdateVolumeWithContext failed: %s", err.Error()), "ibm_is_volume", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + _, err = isWaitForVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("isWaitForVolumeAvailable failed: %s", err.Error()), "ibm_is_volume", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + } + // profile/ iops update if !d.HasChange(isVolumeProfileName) && *oldVol.Profile.Name == "sdp" && d.HasChange(isVolumeIops) { volumeProfilePatchModel := &vpcv1.VolumePatch{} @@ -1367,3 +1481,59 @@ func deleteAllSnapshots(sess *vpcv1.VpcV1, id string) error { } return nil } + +func ResourceIBMIsVolumeAllowedUseMapToVolumeAllowedUsePrototype(modelMap map[string]interface{}) (*vpcv1.VolumeAllowedUsePrototype, error) { + model := &vpcv1.VolumeAllowedUsePrototype{} + if modelMap["api_version"] != nil && modelMap["api_version"].(string) != "" { + model.ApiVersion = core.StringPtr(modelMap["api_version"].(string)) + } + if modelMap["bare_metal_server"] != nil && modelMap["bare_metal_server"].(string) != "" { + model.BareMetalServer = core.StringPtr(modelMap["bare_metal_server"].(string)) + } + if modelMap["instance"] != nil && modelMap["instance"].(string) != "" { + model.Instance = core.StringPtr(modelMap["instance"].(string)) + } + return model, nil +} + +func ResourceIBMIsInstanceMapToVolumeAllowedUsePatchPrototype(modelMap map[string]interface{}) (*vpcv1.VolumeAllowedUsePatch, error) { + model := &vpcv1.VolumeAllowedUsePatch{} + if modelMap["api_version"] != nil && modelMap["api_version"].(string) != "" { + model.ApiVersion = core.StringPtr(modelMap["api_version"].(string)) + } + if modelMap["bare_metal_server"] != nil && modelMap["bare_metal_server"].(string) != "" { + model.BareMetalServer = core.StringPtr(modelMap["bare_metal_server"].(string)) + } + if modelMap["instance"] != nil && modelMap["instance"].(string) != "" { + model.Instance = core.StringPtr(modelMap["instance"].(string)) + } + return model, nil +} + +func ResourceIBMIsVolumeAllowedUseToMap(model *vpcv1.VolumeAllowedUsePrototype) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.BareMetalServer != nil { + modelMap["bare_metal_server"] = *model.BareMetalServer + } + if model.Instance != nil { + modelMap["instance"] = *model.Instance + } + if model.ApiVersion != nil { + modelMap["api_version"] = *model.ApiVersion + } + return modelMap, nil +} + +func ResourceceIBMIsVolumeAllowedUseToMap(model *vpcv1.VolumeAllowedUse) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.BareMetalServer != nil { + modelMap["bare_metal_server"] = *model.BareMetalServer + } + if model.Instance != nil { + modelMap["instance"] = *model.Instance + } + if model.ApiVersion != nil { + modelMap["api_version"] = *model.ApiVersion + } + return modelMap, nil +} diff --git a/ibm/service/vpc/resource_ibm_is_volume_test.go b/ibm/service/vpc/resource_ibm_is_volume_test.go index 4e4c8fef4b..23e2a7a6bc 100644 --- a/ibm/service/vpc/resource_ibm_is_volume_test.go +++ b/ibm/service/vpc/resource_ibm_is_volume_test.go @@ -220,6 +220,75 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }, }) } + +func TestAccIBMISVolume_snapshot_alloweduse(t *testing.T) { + var vol string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100)) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-ssh-%d", acctest.RandIntRange(10, 100)) + volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tfsnapshotuat-%d", acctest.RandIntRange(10, 100)) + apiVersion := "2025-07-02" + bareMetalServer := "enable_secure_boot==true" + instance := "enable_secure_boot==true" + apiVersionUpdate := "2025-07-05" + bareMetalServerUpdate := "true" + instanceUpdate := "true" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVolumeDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISVolumeConfigSnapshotAllowedUse(vpcname, subnetname, sshname, publicKey, volname, name, name1, apiVersion, bareMetalServer, instance), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), + resource.TestCheckResourceAttrSet("ibm_is_volume.storage", "health_state"), + resource.TestCheckResourceAttrSet("ibm_is_volume.storage", "health_reasons.#"), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "name", volname), + resource.TestCheckResourceAttrSet( + "ibm_is_volume.storage", "allowed_use.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_volume.storage", "allowed_use.0.bare_metal_server"), + resource.TestCheckResourceAttrSet( + "ibm_is_volume.storage", "allowed_use.0.instance"), + resource.TestCheckResourceAttrSet( + "ibm_is_volume.storage", "allowed_use.0.api_version"), + resource.TestCheckResourceAttr("ibm_is_volume.storage", "allowed_use.0.bare_metal_server", bareMetalServer), + resource.TestCheckResourceAttr("ibm_is_volume.storage", "allowed_use.0.instance", instance), + resource.TestCheckResourceAttr("ibm_is_volume.storage", "allowed_use.0.api_version", apiVersion), + ), + }, + { + Config: testAccCheckIBMISVolumeConfigSnapshotAllowedUse(vpcname, subnetname, sshname, publicKey, volname, name, name1, apiVersionUpdate, bareMetalServerUpdate, instanceUpdate), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), + resource.TestCheckResourceAttrSet("ibm_is_volume.storage", "health_state"), + resource.TestCheckResourceAttrSet("ibm_is_volume.storage", "health_reasons.#"), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "name", volname), + resource.TestCheckResourceAttrSet( + "ibm_is_volume.storage", "allowed_use.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_volume.storage", "allowed_use.0.bare_metal_server"), + resource.TestCheckResourceAttrSet( + "ibm_is_volume.storage", "allowed_use.0.instance"), + resource.TestCheckResourceAttrSet( + "ibm_is_volume.storage", "allowed_use.0.api_version"), + resource.TestCheckResourceAttr("ibm_is_volume.storage", "allowed_use.0.bare_metal_server", bareMetalServerUpdate), + resource.TestCheckResourceAttr("ibm_is_volume.storage", "allowed_use.0.instance", instanceUpdate), + resource.TestCheckResourceAttr("ibm_is_volume.storage", "allowed_use.0.api_version", apiVersionUpdate), + ), + }, + }, + }) +} + func TestAccIBMISVolume_snapshotcrn(t *testing.T) { var vol string vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) @@ -758,6 +827,23 @@ func testAccCheckIBMISVolumeConfigSnapshot(vpcname, subnetname, sshname, publicK } `, volname, acc.ISZoneName) } + +func testAccCheckIBMISVolumeConfigSnapshotAllowedUse(vpcname, subnetname, sshname, publicKey, volname, name, name1, apiVersion, bareMetalServer, instance string) string { + + return testAccCheckIBMISSnapshotConfig(vpcname, subnetname, sshname, publicKey, volname, name, name1) + fmt.Sprintf(` + resource "ibm_is_volume" "storage" { + name = "%s" + profile = "general-purpose" + zone = "%s" + source_snapshot= ibm_is_snapshot.testacc_snapshot.id + allowed_use { + api_version = "%s" + bare_metal_server = "%s" + instance = "%s" + } + } + `, volname, acc.ISZoneName, apiVersion, bareMetalServer, instance) +} func testAccCheckIBMISVolumeConfigSnapshotCrn(vpcname, subnetname, sshname, publicKey, volname, name, name1 string) string { return testAccCheckIBMISSnapshotConfig(vpcname, subnetname, sshname, publicKey, volname, name, name1) + fmt.Sprintf(` diff --git a/website/docs/d/is_bare_metal_server.markdown b/website/docs/d/is_bare_metal_server.markdown index 1612f89eb0..c88bb88766 100644 --- a/website/docs/d/is_bare_metal_server.markdown +++ b/website/docs/d/is_bare_metal_server.markdown @@ -63,12 +63,21 @@ In addition to all argument reference list, you can access the following attribu - `crn` - (String) The CRN for this bare metal server - `disks` - (List) The disks for this bare metal server, including any disks that are associated with the boot_target. Nested scheme for `disks`: + - `allowed_use` - (List) The usage constraints to be matched against the requested bare metal server properties to determine compatibility. + + Nested schema for `allowed_use`: + - `api_version` - (String) The API version with which to evaluate the expressions. + + - `bare_metal_server` - (String)The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this disk. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following property is supported:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled for this bare metal server. - `href` - (String) The URL for this bare metal server disk. - `id` - (String) The unique identifier for this bare metal server disk. - `interface_type` - (String) The disk interface used for attaching the disk. The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered. [ **nvme**, **sata** ] - `name` - (String) The user-defined name for this disk - `resource_type` - (String) The resource type - - `size` - (Integer) The size of the disk in GB (gigabytes) + - `size` - (Integer) The size of the disk in GB (gigabytes) - `enable_secure_boot` - (Boolean) Indicates whether secure boot is enabled. If enabled, the image must support secure boot or the server will fail to boot. - `health_reasons` - (List) The reasons for the current health_state (if any). diff --git a/website/docs/d/is_bare_metal_server_disk.markdown b/website/docs/d/is_bare_metal_server_disk.markdown index 8648328c19..10538daf8b 100644 --- a/website/docs/d/is_bare_metal_server_disk.markdown +++ b/website/docs/d/is_bare_metal_server_disk.markdown @@ -41,6 +41,15 @@ Review the argument references that you can specify for your data source. ## Attribute reference In addition to the argument reference list, you can access the following attribute references after your data source is created. +- `allowed_use` - (List) The usage constraints to be matched against the requested bare metal server properties to determine compatibility. + + Nested schema for `allowed_use`: + - `api_version` - (String) The API version with which to evaluate the expressions. + + - `bare_metal_server` - (String) The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this disk..The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following property is supported:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled for this bare metal server. - `href` - (String) The URL for this bare metal server disk. - `id` - (String) The unique identifier for this bare metal server disk. - `interface_type` - (String) The disk interface used for attaching the disk. Supported values are [ **nvme**, **sata** ]. diff --git a/website/docs/d/is_bare_metal_server_disks.markdown b/website/docs/d/is_bare_metal_server_disks.markdown index ab12ba9b38..257e0b5e96 100644 --- a/website/docs/d/is_bare_metal_server_disks.markdown +++ b/website/docs/d/is_bare_metal_server_disks.markdown @@ -42,6 +42,21 @@ In addition to the argument reference list, you can access the following attribu - `disks` - (List of objects) A list of bare metal server disks. Disk is a block device that is locally attached to the physical server. By default, the listed disks are sorted by their created_at property values, with the newest disk first. Nested scheme for `disks`: + - `allowed_use` - (List) The usage constraints to be matched against the requested bare metal server properties to determine compatibility. + + Nested schema for `allowed_use`: + - `api_version` - (String) The API version with which to evaluate the expressions. + + - `bare_metal_server` - (String) The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this disk. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following property is supported:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled for this bare metal server. + - `href` - (String) The URL for this bare metal server disk. + - `id` - (String) The unique identifier for this bare metal server disk. + - `interface_type` - (String) The disk interface used for attaching the disk. Supported values are [ **nvme**, **sata** ]. + - `name` - (String) The user-defined name for this disk. + - `resource_type` - (String) The resource type. + - `size` - (String) The size of the disk in GB (gigabytes). - `href` - (String) The URL for this bare metal server disk. - `id` - (String) The unique identifier for this bare metal server disk. - `interface_type` - (String) The disk interface used for attaching the disk. Supported values are [ **nvme**, **sata** ]. diff --git a/website/docs/d/is_bare_metal_servers.markdown b/website/docs/d/is_bare_metal_servers.markdown index 6b73c612b3..2abff34c65 100644 --- a/website/docs/d/is_bare_metal_servers.markdown +++ b/website/docs/d/is_bare_metal_servers.markdown @@ -55,6 +55,15 @@ Review the attribute references that you can access after you retrieve your data - `crn` - (String) The CRN for this bare metal server - `disks` - (List) The disks for this bare metal server, including any disks that are associated with the boot_target. Nested scheme for `disks`: + - `allowed_use` - (List) The usage constraints to be matched against the requested bare metal server properties to determine compatibility. + + Nested schema for `allowed_use`: + - `api_version` - (String) The API version with which to evaluate the expressions. If specified, the value must be between `2019-01-01` and today's date (in UTC). If unspecified, the version query parameter value will be used. + + - `bare_metal_server` - (String) The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this disk..The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following property is supported:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled for this bare metal server. - `href` - (String) The URL for this bare metal server disk. - `id` - (String) The unique identifier for this bare metal server disk. - `interface_type` - (String) The disk interface used for attaching the disk. The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered. [ **nvme**, **sata** ] diff --git a/website/docs/d/is_image.html.markdown b/website/docs/d/is_image.html.markdown index 0f338c240c..892f91203f 100644 --- a/website/docs/d/is_image.html.markdown +++ b/website/docs/d/is_image.html.markdown @@ -102,6 +102,24 @@ In addition to all argument reference list, you can access the following attribu - `more_info` - (String) Link to documentation about this status reason - `source_volume` - The source volume id of the image. +- `allowed_use` - (List) The usage constraints to match against the requested instance or bare metal server properties to determine compatibility. + + Nested schema for `allowed_use`: + - `api_version` - (String) The API version with which to evaluate the expressions. + + - `bare_metal_server` - (String) The expression that must be satisfied by the properties of a bare metal server provisioned using this image. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following property is supported, corresponding to `BareMetalServer` properties:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled. + + - `instance` - (String) The expression that must be satisfied by the properties of a virtual server instance provisioned using this image. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following variables are supported, corresponding to `Instance` properties:
+ **•** `gpu.count` - (integer) The number of GPUs.
+ **•** `gpu.manufacturer` - (string) The GPU manufacturer.
+ **•** `gpu.memory` - (integer) The overall amount of GPU memory in GiB (gibibytes).
+ **•** `gpu.model` - (string) The GPU model.
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled.
- `user_data_format` - (String) The user data format for this image. ~> **Note:**
Supported values are :
diff --git a/website/docs/d/is_image_bare_metal_server_profiles.html.markdown b/website/docs/d/is_image_bare_metal_server_profiles.html.markdown new file mode 100644 index 0000000000..f37b705569 --- /dev/null +++ b/website/docs/d/is_image_bare_metal_server_profiles.html.markdown @@ -0,0 +1,48 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_image_bare_metal_server_profiles" +description: |- + Get information about ImageBareMetalServerProfileCollection +--- + +# ibm_is_image_bare_metal_server_profiles + +Provides a read-only data source to retrieve information about an ImageBareMetalServerProfileCollection.For more information, about infrastructure image bare metal server profiles, see [IBM Cloud Importing and managing custom images](https://cloud.ibm.com/docs/vpc?topic=vpc-managing-images). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +```terraform +data "ibm_is_image_bare_metal_server_profiles" "example" { + identifier = "ibm_is_image.isExampleImage.id" +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `identifier` - (Required, String) The image identifier. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `id` - The unique identifier of the ImageBareMetalServerProfileCollection. +- `bare_metal_server_profiles` - (List) A page of bare metal server profiles compatible with the image. + + Nested schema for **bare_metal_server_profiles**: + - `href` - (String) The URL for this bare metal server profile. + - `name` - (String) The name for this bare metal server profile. + - `resource_type` - (String) The resource type. diff --git a/website/docs/d/is_image_instance_profiles.html.markdown b/website/docs/d/is_image_instance_profiles.html.markdown new file mode 100644 index 0000000000..de5ed699bc --- /dev/null +++ b/website/docs/d/is_image_instance_profiles.html.markdown @@ -0,0 +1,48 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_image_instance_profiles" +description: |- + Get information about ImageInstanceProfiles +--- + +# ibm_is_image_instance_profiles + +Provides a read-only data source to retrieve information about an ImageInstanceProfileCollection.For more information, about infrastructure image instance profiles, see [IBM Cloud Importing and managing custom images](https://cloud.ibm.com/docs/vpc?topic=vpc-managing-images). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +```terraform +data "ibm_is_image_instance_profiles" "example" { + identifier = "ibm_is_image.isExampleImage.id" +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `identifier` - (Required, String) The image identifier. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `id` - The unique identifier of the ImageInstanceProfileCollection. +- `instance_profiles` - (List) A page of instance profiles compatible with the image. + + Nested schema for **instance_profiles**: + - `href` - (String) The URL for this virtual server instance profile. + - `name` - (String) The globally unique name for this virtual server instance profile. + - `resource_type` - (String) The resource type. diff --git a/website/docs/d/is_images.html.markdown b/website/docs/d/is_images.html.markdown index da545dd2ce..0db90e2145 100644 --- a/website/docs/d/is_images.html.markdown +++ b/website/docs/d/is_images.html.markdown @@ -55,6 +55,24 @@ You can access the following attribute references after your data source is crea Nested scheme for `images`: - `access_tags` - (List) Access management tags associated for image. + - `allowed_use` - (List) The usage constraints to match against the requested instance or bare metal server properties to determine compatibility. + + Nested schema for `allowed_use`: + - `api_version` - (String) The API version with which to evaluate the expressions. + + - `bare_metal_server` - (String) The expression that must be satisfied by the properties of a bare metal server provisioned using this image. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following property is supported, corresponding to `BareMetalServer` properties:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled. + + - `instance` - (String) The expression that must be satisfied by the properties of a virtual server instance provisioned using this image. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following variables are supported, corresponding to `Instance` properties:
+ **•** `gpu.count` - (integer) The number of GPUs.
+ **•** `gpu.manufacturer` - (string) The GPU manufacturer.
+ **•** `gpu.memory` - (integer) The overall amount of GPU memory in GiB (gibibytes).
+ **•** `gpu.model` - (string) The GPU model.
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled.
- `architecture` - (String) The architecture for this image. - `crn` - (String) The CRN for this image. - `catalog_offering` - (List) The catalog offering for this image. diff --git a/website/docs/d/is_instance_template.html.markdown b/website/docs/d/is_instance_template.html.markdown index 8cc3876e66..d062b3e288 100644 --- a/website/docs/d/is_instance_template.html.markdown +++ b/website/docs/d/is_instance_template.html.markdown @@ -50,6 +50,24 @@ You can access the following attribute references after your data source is crea - `boot_volume` - (List) A nested block describes the boot volume configuration for the template. Nested scheme for `boot_volume`: + - `allowed_use` - (Optional, List) The usage constraints to be matched against requested instance or bare metal server properties to determine compatibility. Can only be specified if `source_snapshot` is bootable. If not specified, the value of this property will be inherited from the `source_image` + + Nested schema for `allowed_use`: + - `api_version` - (Optional, String) The API version with which to evaluate the expressions. + + - `bare_metal_server` - (Optional, String) The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following property is supported, corresponding to the `BareMetalServer` property:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled. + + - `instance` - (Optional, String) The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following variables are supported, corresponding to `Instance` properties:
+ **•** `gpu.count` - (integer) The number of GPUs.
+ **•** `gpu.manufacturer` - (string) The GPU manufacturer.
+ **•** `gpu.memory` - (integer) The overall amount of GPU memory in GiB (gibibytes).
+ **•** `gpu.model` - (string) The GPU model.
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled.
- `bandwidth` - (Optional, Integer) The maximum bandwidth (in megabits per second) for the volume. For this property to be specified, the volume storage_generation must be 2. - `delete_volume_on_instance_delete` - (String) You can configure to delete the boot volume based on instance deletion. - `encryption` - (String) The encryption key CRN such as HPCS, Key Protect, etc., is provided to encrypt the boot volume attached. @@ -231,11 +249,30 @@ You can access the following attribute references after your data source is crea - `volume_prototype` - (List) A nested block describing prototype for the volume. Nested scheme for `volume_prototype`: + - `allowed_use` - (Optional, List) The usage constraints to be matched against requested instance or bare metal server properties to determine compatibility. Can only be specified if source_snapshot is bootable. If not specified, the value of this property will be inherited from the source_snapshot. + + Nested schema for `allowed_use`: + - `api_version` - (Optional, String) The API version with which to evaluate the expressions. + + - `bare_metal_server` - (Optional, String) The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following property is supported, corresponding to the `BareMetalServer` property:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled. + + - `instance` - (Optional, String) The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following variables are supported, corresponding to `Instance` properties:
+ **•** `gpu.count` - (integer) The number of GPUs.
+ **•** `gpu.manufacturer` - (string) The GPU manufacturer.
+ **•** `gpu.memory` - (integer) The overall amount of GPU memory in GiB (gibibytes).
+ **•** `gpu.model` - (string) The GPU model.
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled.
- `bandwidth` - (Optional, Integer) The maximum bandwidth (in megabits per second) for the volume. For this property to be specified, the volume storage_generation must be 2. - `capacity` - (String) The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes can expand in the future. - `encryption_key` - (String) The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource. - `iops` - (String) The maximum input/output operations per second (IOPS) for the volume. - `profile` - (String) The global unique name for the volume profile to use for the volume. + - `source_snapshot` - The snapshot to use as a source for the volume's data. To create a volume from a `source_snapshot`, the volume profile and the source snapshot must have the same `storage_generation` value. - `tags` - (String) User Tags associated with the volume. (https://cloud.ibm.com/apidocs/tagging#types-of-tags) - `vpc` - (String) The VPC ID that the instance templates needs to be created. - `zone` - (String) The name of the zone. diff --git a/website/docs/d/is_instance_templates.html.markdown b/website/docs/d/is_instance_templates.html.markdown index a77866d67f..b2eb739bcf 100644 --- a/website/docs/d/is_instance_templates.html.markdown +++ b/website/docs/d/is_instance_templates.html.markdown @@ -37,6 +37,24 @@ You can access the following attribute references after your data source is crea - `boot_volume` - (List) A nested block describes the boot volume configuration for the template. Nested scheme for `boot_volume`: + - `allowed_use` - (List) The usage constraints to be matched against requested instance or bare metal server properties to determine compatibility. Can only be specified if `source_snapshot` is bootable. If not specified, the value of this property will be inherited from the `source_image. + + Nested schema for `allowed_use`: + - `api_version` - (String) The API version with which to evaluate the expressions. + + - `bare_metal_server` - (String) TThe expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
the following variable is supported, corresponding to the `BareMetalServer` property:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled. + + - `instance` - (String) The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following variables are supported, corresponding to `Instance` properties:
+ **•** `gpu.count` - (integer) The number of GPUs.
+ **•** `gpu.manufacturer` - (string) The GPU manufacturer.
+ **•** `gpu.memory` - (integer) The overall amount of GPU memory in GiB (gibibytes).
+ **•** `gpu.model` - (string) The GPU.
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled.
- `bandwidth` - (Optional, Integer) The maximum bandwidth (in megabits per second) for the volume. For this property to be specified, the volume storage_generation must be 2. - `delete_volume_on_instance_delete` - (String) You can configure to delete the boot volume based on instance deletion. - `encryption` - (String) The encryption key CRN such as HPCS, Key Protect, etc., is provided to encrypt the boot volume attached. @@ -219,10 +237,29 @@ You can access the following attribute references after your data source is crea - `volume_prototype` - (List) A nested block describing prototype for the volume. Nested scheme for `volume_prototype`: + - `allowed_use` - (List) The usage constraints to be matched against requested instance or bare metal server properties to determine compatibility. Can only be specified if `source_snapshot` is bootable. If not specified, the value of this property will be inherited from the `source_image. + + Nested schema for `allowed_use`: + - `api_version` - (String) The API version with which to evaluate the expressions. + + - `bare_metal_server` - (String) TThe expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
the following variable is supported, corresponding to the `BareMetalServer` property:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled. + + - `instance` - (String) The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following variables are supported, corresponding to `Instance` properties:
+ **•** `gpu.count` - (integer) The number of GPUs.
+ **•** `gpu.manufacturer` - (string) The GPU manufacturer.
+ **•** `gpu.memory` - (integer) The overall amount of GPU memory in GiB (gibibytes).
+ **•** `gpu.model` - (string) The GPU.
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled.
- `capacity` - (String) The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes can expand in the future. - `encryption_key` - (String) The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource. - `iops` - (String) The maximum input/output operations per second (IOPS) for the volume. - `profile` - (String) The global unique name for the volume profile to use for the volume. + - `source_snapshot` - The snapshot to use as a source for the volume's data. To create a volume from a `source_snapshot`, the volume profile and the source snapshot must have the same `storage_generation` value. - `tags` - (String) User Tags associated with the volume. (https://cloud.ibm.com/apidocs/tagging#types-of-tags) - `vpc` - (String) The VPC ID that the instance templates needs to be created. - `zone` - (String) The name of the zone. diff --git a/website/docs/d/is_snapshot.html.markdown b/website/docs/d/is_snapshot.html.markdown index 8ade1cb2ce..1dc9a127da 100644 --- a/website/docs/d/is_snapshot.html.markdown +++ b/website/docs/d/is_snapshot.html.markdown @@ -90,6 +90,24 @@ Review the argument references that you can specify for your data source. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your data source is created. - `access_tags` - (Array of Strings) Access management tags associated with the snapshot. +- `allowed_use` - (List) The usage constraints to be matched against the requested instance properties to determine compatibility. While bare metal servers cannot be provisioned from snapshots, an image or volume created from this snapshot will inherit its allowed_use value. Only present on bootable snapshots. The value of this property will be inherited from the source volume or source snapshot at snapshot creation, but can be changed. + + Nested schema for `allowed_use`: + - `api_version` - (String) The API version with which to evaluate the expressions. + + - `bare_metal_server` - (String) The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this snapshot. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
the following variable is supported, corresponding to the `BareMetalServer` property:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled. + + - `instance` - (String) The expression that must be satisfied by the properties of a virtual server instance provisioned using this snapshot. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following variables are supported, corresponding to `Instance` properties:
+ **•** `gpu.count` - (integer) The number of GPUs.
+ **•** `gpu.manufacturer` - (string) The GPU manufacturer.
+ **•** `gpu.memory` - (integer) The overall amount of GPU memory in GiB (gibibytes).
+ **•** `gpu.model` - (string) The GPU.
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled.
- `backup_policy_plan` - (List) If present, the backup policy plan which created this snapshot. Nested scheme for `backup_policy_plan`: diff --git a/website/docs/d/is_snapshot_instance_profiles.html.markdown b/website/docs/d/is_snapshot_instance_profiles.html.markdown new file mode 100644 index 0000000000..dbebfefb28 --- /dev/null +++ b/website/docs/d/is_snapshot_instance_profiles.html.markdown @@ -0,0 +1,48 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_snapshot_instance_profiles" +description: |- + Get information about SnapshotInstanceProfiles +--- + +# ibm_is_snapshot_instance_profiles + +Provides a read-only data source to retrieve information about an SnapshotInstanceProfileCollection.For more information, about infrastructure snapshots instance profiles, see [viewing snapshots](https://cloud.ibm.com/docs/vpc?topic=vpc-snapshots-vpc-view). + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +```terraform +data "ibm_is_snapshot_instance_profiles" "example" { + identifier = "ibm_is_snapshot.example.id" +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `identifier` - (Required, String) The snapshot identifier. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `id` - The unique identifier of the SnapshotInstanceProfileCollection. +- `instance_profiles` - (List) A page of instance profiles compatible with the snapshot. + + Nested schema for **instance_profiles**: + - `href` - (String) The URL for this virtual server instance profile. + - `name` - (String) The globally unique name for this virtual server instance profile. + - `resource_type` - (String) The resource type. diff --git a/website/docs/d/is_snapshots.html.markdown b/website/docs/d/is_snapshots.html.markdown index 1df61ec574..3d1d433fdb 100644 --- a/website/docs/d/is_snapshots.html.markdown +++ b/website/docs/d/is_snapshots.html.markdown @@ -57,6 +57,24 @@ In addition to all argument reference list, you can access the following attribu Nested scheme for `snapshots`: - `access_tags` - (Array of Strings) Access management tags associated with the snapshot. + - `allowed_use` - (List) The usage constraints to be matched against the requested instance properties to determine compatibility. While bare metal servers cannot be provisioned from snapshots, an image or volume created from this snapshot will inherit its allowed_use value. Only present on bootable snapshots. The value of this property will be inherited from the source volume or source snapshot at snapshot creation, but can be changed. + + Nested schema for `allowed_use`: + - `api_version` - (String) The API version with which to evaluate the expressions. + + - `bare_metal_server` - (String) The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this snapshot. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
the following variable is supported, corresponding to the `BareMetalServer` property:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled. + + - `instance` - (String) The expression that must be satisfied by the properties of a virtual server instance provisioned using this snapshot. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following variables are supported, corresponding to `Instance` properties:
+ **•** `gpu.count` - (integer) The number of GPUs.
+ **•** `gpu.manufacturer` - (string) The GPU manufacturer.
+ **•** `gpu.memory` - (integer) The overall amount of GPU memory in GiB (gibibytes).
+ **•** `gpu.model` - (string) The GPU.
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled.
- `id` - (String) The unique identifier for this snapshot. - `backup_policy_plan` - (List) If present, the backup policy plan which created this snapshot. diff --git a/website/docs/d/is_volume.html.markdown b/website/docs/d/is_volume.html.markdown index ffbf4b54ad..395304d3cd 100644 --- a/website/docs/d/is_volume.html.markdown +++ b/website/docs/d/is_volume.html.markdown @@ -49,6 +49,24 @@ In addition to all argument reference list, you can access the following attribu - `attachment_state` - (Boolean) The attachment state of the volume - `adjustable_capacity_states` - (List) The attachment states that support adjustable capacity for this volume. Allowable list items are: `attached`, `unattached`, `unusable`. - `adjustable_iops_states` - (List) The attachment states that support adjustable IOPS for this volume. Allowable list items are: `attached`, `unattached`, `unusable`. +- `allowed_use` - (List) The usage constraints to be matched against the requested instance or bare metal server properties to determine compatibility. Only present for boot volumes. The value of this property will be inherited from the source image or snapshot at volume creation, but can be changed. + + Nested schema for `allowed_use`: + - `api_version` - (String) The API version with which to evaluate the expressions. + + - `bare_metal_server` - (String) The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following property is supported, corresponding to the BareMetalServer property:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled. + + - `instance` - (String) The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following variables are supported, corresponding to `Instance`
+ **•** `gpu.count` - (integer) The number of GPUs.
+ **•** `gpu.manufacturer` - (string) The GPU manufacturer.
+ **•** `gpu.memory` - (integer) The overall amount of GPU memory in GiB (gibibytes).
+ **•** `gpu.model` - (string) The GPU model.
+ **•** `enable_secure_boot` - (boolean)Indicates whether secure boot is enabled.
- `bandwidth` - The maximum bandwidth (in megabits per second) for the volume - `busy` - (Boolean) Indicates whether this volume is performing an operation that must be serialized. This must be `false` to perform an operation that is specified to require serialization. - `capacity` - (String) The capacity of the volume in gigabytes. diff --git a/website/docs/d/is_volume_instance_profiles.html.markdown b/website/docs/d/is_volume_instance_profiles.html.markdown new file mode 100644 index 0000000000..431f68fc0e --- /dev/null +++ b/website/docs/d/is_volume_instance_profiles.html.markdown @@ -0,0 +1,48 @@ +--- +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : ibm_is_volume_instance_profiles" +description: |- + Get information about VolumeInstanceProfiles +--- + +# ibm_is_volume_instance_profiles + +Provides a read-only data source to retrieve information about an VolumeInstanceProfileCollection.For more information, about the volume concepts, see [expandable volume concepts for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-expanding-block-storage-volumes#expandable-volume-concepts).. + +**Note:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example Usage + +```terraform +data "ibm_is_volume_instance_profiles" "example" { + identifier = "ibm_is_instance.example.boot_volume.0.volume_id" +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +- `identifier` - (Required, String) The volume identifier. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +- `id` - The unique identifier of the VolumeInstanceProfileCollection. +- `instance_profiles` - (List) A page of instance profiles compatible with the volume. + + Nested schema for **instance_profiles**: + - `href` - (String) The URL for this virtual server instance profile. + - `name` - (String) The globally unique name for this virtual server instance profile. + - `resource_type` - (String) The resource type. diff --git a/website/docs/d/is_volumes.html.markdown b/website/docs/d/is_volumes.html.markdown index 609bd268be..6e2008e8ac 100644 --- a/website/docs/d/is_volumes.html.markdown +++ b/website/docs/d/is_volumes.html.markdown @@ -48,6 +48,24 @@ In addition to all argument references listed, you can access the following attr - `adjustable_capacity_states` - (List) The attachment states that support adjustable capacity for this volume. Allowable list items are: `attached`, `unattached`, `unusable`. - `adjustable_iops_states` - (List) The attachment states that support adjustable IOPS for this volume. Allowable list items are: `attached`, `unattached`, `unusable`. - `attachment_state` - (Boolean) The attachment state of the volume + - `allowed_use` - (List) The usage constraints to be matched against the requested instance or bare metal server properties to determine compatibility. Only present for boot volumes. The value of this property will be inherited from the source image or snapshot at volume creation, but can be changed. + + Nested schema for `allowed_use`: + - `api_version` - (String) The API version with which to evaluate the expressions. + + - `bare_metal_server` - (String) The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following property is supported, corresponding to the BareMetalServer property:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled. + + - `instance` - (String) The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following variables are supported, corresponding to `Instance`
+ **•** `gpu.count` - (integer) The number of GPUs.
+ **•** `gpu.manufacturer` - (string) The GPU manufacturer.
+ **•** `gpu.memory` - (integer) The overall amount of GPU memory in GiB (gibibytes).
+ **•** `gpu.model` - (string) The GPU model.
+ **•** `enable_secure_boot` - (boolean)Indicates whether secure boot is enabled.
- `bandwidth` - (Integer) The maximum bandwidth (in megabits per second) for the volume. - `busy` - (Boolean) Indicates whether this volume is performing an operation that must be serialized. This must be `false` to perform an operation that is specified to require serialization. - `capacity` - (Integer) The capacity to use for the volume (in gigabytes). The specified minimum and maximum capacity values for creating or updating volumes may expand in the future. diff --git a/website/docs/r/is_bare_metal_server.markdown b/website/docs/r/is_bare_metal_server.markdown index e999bf4e9d..942586738f 100644 --- a/website/docs/r/is_bare_metal_server.markdown +++ b/website/docs/r/is_bare_metal_server.markdown @@ -397,6 +397,23 @@ In addition to all argument reference list, you can access the following attribu - `core_count` - (Integer) The total number of cores - `socket_count` - (Integer) The total number of CPU sockets - `threads_per_core` - (Integer) The total number of hardware threads per core +- `disks` - (List) The disks for this bare metal server, including any disks that are associated with the boot_target. + Nested scheme for `disks`: + - `allowed_use` - (List) The usage constraints to be matched against the requested bare metal server properties to determine compatibility. Only present for disks which are referenced in a bare metal server's boot_target property. The value of this property will be inherited from the source image at creation. + + Nested schema for `allowed_use`: + - `api_version` - (String) The API version with which to evaluate the expressions. + + - `bare_metal_server` - (String) The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this disk. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following property is supported:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled for this bare metal server. + - `href` - (String) The URL for this bare metal server disk. + - `id` - (String) The unique identifier for this bare metal server disk. + - `interface_type` - (String) The disk interface used for attaching the disk. The enumerated values for this property are expected to expand in the future. When processing this property, check for and log unknown values. Optionally halt processing and surface the error, or bypass the resource on which the unexpected property value was encountered. [ **nvme**, **sata** ] + - `name` - (String) The user-defined name for this disk + - `resource_type` - (String) The resource type + - `size` - (Integer) The size of the disk in GB (gigabytes) - `href` - (String) The URL for this bare metal server - `id` - (String) The unique identifier for this bare metal server - `memory` - (Integer) The amount of memory, truncated to whole gibibytes diff --git a/website/docs/r/is_bare_metal_server_disk.markdown b/website/docs/r/is_bare_metal_server_disk.markdown index 9fed0006ec..30666c68e6 100644 --- a/website/docs/r/is_bare_metal_server_disk.markdown +++ b/website/docs/r/is_bare_metal_server_disk.markdown @@ -43,3 +43,19 @@ Review the argument references that you can specify for your resource. - `disk` - (Required, String) The unique identifier for the disk to be renamed on the Bare metal server. - `name` - (Optional, String) The name for the disk. + +## Attribute reference +- `allowed_use` - (List) The usage constraints to be matched against the requested bare metal server properties to determine compatibility. + + Nested schema for `allowed_use`: + - `api_version` - (String) The API version with which to evaluate the expressions. If specified, the value must be between 2019-01-01 and today's date (in UTC). If unspecified, the version query parameter value will be used. + + - `bare_metal_server` - (String) The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this disk..The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + ~> **NOTE**
In addition, the following property is supported:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled for this bare metal server. +- `href` - (String) The URL for this bare metal server disk. +- `id` - (String) The unique identifier for this bare metal server disk. +- `interface_type` - (String) The disk interface used for attaching the disk. Supported values are [ **nvme**, **sata** ]. +- `name` - (String) The user-defined name for this disk. +- `resource_type` - (String) The resource type. +- `size` - (String) The size of the disk in GB (gigabytes). \ No newline at end of file diff --git a/website/docs/r/is_image.html.markdown b/website/docs/r/is_image.html.markdown index 407fd4fbb0..7815495994 100644 --- a/website/docs/r/is_image.html.markdown +++ b/website/docs/r/is_image.html.markdown @@ -77,7 +77,24 @@ resource "ibm_is_image" "example" { ~> **NOTE** `obsolescence_at` must be later than `deprecation_at` (if `deprecation_at` is set). +## Example usage (using href, operating_system and allowed_use) +```terraform +resource "ibm_is_image" "example" { + name = "example-image" + href = "cos://us-south/buckettesttest/livecd.ubuntu-cpc.azure.vhd" + operating_system = "ubuntu-16-04-amd64" + encrypted_data_key = "eJxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0=" + encryption_key = "crn:v1:bluemix:public:kms:us-south:a/6xxxxxxxxxxxxxxx:xxxxxxx-xxxx-xxxx-xxxxxxx:key:dxxxxxx-fxxx-4xxx-9xxx-7xxxxxxxx" + allowed_use { + api_version = "2025-04-03" + bare_metal_server = "enable_secure_boot == true" + instance = "enable_secure_boot == true" + } +} +``` + ~> **NOTE** + `operating_system` is required with `href`. ## Argument reference Review the argument references that you can specify for your resource. @@ -89,6 +106,24 @@ Review the argument references that you can specify for your resource. **•** For more information, about creating access tags, see [working with tags](https://cloud.ibm.com/docs/account?topic=account-tag&interface=ui#create-access-console).
**•** You must have the access listed in the [Granting users access to tag resources](https://cloud.ibm.com/docs/account?topic=account-access) for `access_tags`
**•** `access_tags` must be in the format `key:value`. +- `allowed_use` - (Optional, List) The usage constraints to match against the requested instance or bare metal server properties to determine compatibility. + + Nested schema for `allowed_use`: + - `api_version` - (Optional, String) The API version with which to evaluate the expressions. + + - `bare_metal_server` - (Optional, String) The expression that must be satisfied by the properties of a bare metal server provisioned using this image. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following property is supported, corresponding to `BareMetalServer` properties:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled. + + - `instance` - (Optional, String) The expression that must be satisfied by the properties of a virtual server instance provisioned using this image. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following variables are supported, corresponding to `Instance` properties:
+ **•** `gpu.count` - (integer) The number of GPUs.
+ **•** `gpu.manufacturer` - (string) The GPU manufacturer.
+ **•** `gpu.memory` - (integer) The overall amount of GPU memory in GiB (gibibytes).
+ **•** `gpu.model` - (string) The GPU model.
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled.
- `deprecate` - (Bool) This flag deprecates an image, resulting in its status becoming deprecated and deprecation_at being set to the current date and time. The image must: - be an existing image and have a status of available diff --git a/website/docs/r/is_instance.html.markdown b/website/docs/r/is_instance.html.markdown index dcf9a1576b..e6edb31218 100644 --- a/website/docs/r/is_instance.html.markdown +++ b/website/docs/r/is_instance.html.markdown @@ -611,6 +611,24 @@ Review the argument references that you can specify for your resource. - `boot_volume` (Optional, List) A list of boot volumes for an instance. Nested scheme for `boot_volume`: + - `allowed_use` - (Optional, List) The usage constraints to be matched against requested instance or bare metal server properties to determine compatibility. Can only be specified if `source_snapshot` is bootable. If not specified, the value of this property will be inherited from the `source_image`. + + Nested schema for `allowed_use`: + - `api_version` - (Optional, String) The API version with which to evaluate the expressions. + + - `bare_metal_server` - (Optional, String)The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following property is supported, corresponding to the `BareMetalServer` property:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled. + + - `instance` - (Optional, String) The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following variables are supported, corresponding to `Instance` properties:
+ **•** `gpu.count` - (integer) The number of GPUs.
+ **•** `gpu.manufacturer` - (string) The GPU manufacturer.
+ **•** `gpu.memory` - (integer) The overall amount of GPU memory in GiB (gibibytes).
+ **•** `gpu.model` - (string) The GPU model.
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled.
- `auto_delete_volume` - (Optional, String) If set to **true**, when deleting the instance the volume will also be deleted - `bandwidth` - (Optional, Integer) The maximum bandwidth (in megabits per second) for the volume. For this property to be specified, the volume storage_generation must be 2. - `encryption` - (Optional, String) The type of encryption to use for the boot volume. @@ -919,6 +937,24 @@ Review the argument references that you can specify for your resource. - `name` - (String) The name of the volume prototype. - `profile` - (String) The profile of the volume prototype. - `size`- (Integer) The capacity of the volume in gigabytes. + - `allowed_use` - (Optional, List) The usage constraints to be matched against requested instance or bare metal server properties to determine compatibility. Can only be specified if `source_snapshot` is bootable. If not specified, the value of this property will be inherited from the `source_snapshot`. + + Nested schema for `allowed_use`: + - `api_version` - (Optional, String) The API version with which to evaluate the expressions. + + - `bare_metal_server` - (Optional, String) The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following property is supported, corresponding to the `BareMetalServer` property:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled. + + - `instance` - (Optional, String) The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following variables are supported, corresponding to `Instance` property:
+ **•** `gpu.count` - (integer) The number of GPUs.
+ **•** `gpu.manufacturer` - (string) The GPU manufacturer.
+ **•** `gpu.memory` - (integer) The overall amount of GPU memory in GiB (gibibytes).
+ **•** `gpu.model` - (string) The GPU model.
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled.
- `vpc` - (Required, Forces new resource, String) The ID of the VPC where you want to create the instance. When using `instance_template`, `vpc` is not required. - `zone` - (Required, Forces new resource, String) The name of the VPC zone where you want to create the instance. When using `instance_template`, `zone` is not required. @@ -933,7 +969,7 @@ In addition to all argument reference list, you can access the following attribu - `iops`- (Integer) The number of input and output operations per second of the volume. - `name` - (String) The name of the boot volume. - `profile` - (String) The profile of the volume. - - `size`- (Integer) The capacity of the volume in gigabytes. + - `size`- (Integer) The capacity of the volume in gigabytes. - `catalog_offering` - (List) The [catalog](https://cloud.ibm.com/docs/account?topic=account-restrict-by-user&interface=ui) offering or offering version to use when provisioning this virtual server instance. If an offering is specified, the latest version of that offering will be used. The specified offering or offering version may be in a different account in the same [enterprise](https://cloud.ibm.com/docs/account?topic=account-what-is-enterprise), subject to IAM policies. Nested scheme for `catalog_offering`: diff --git a/website/docs/r/is_instance_template.html.markdown b/website/docs/r/is_instance_template.html.markdown index 97f48ad953..a41a351c62 100644 --- a/website/docs/r/is_instance_template.html.markdown +++ b/website/docs/r/is_instance_template.html.markdown @@ -257,6 +257,37 @@ resource "ibm_is_instance_template" "is_instance_template" { } ``` +``` +// Instance Template with volume attachment as source snapshot +resource "ibm_is_instance_template" "instancetemplate1" { + name = "tfp-instance-temp" + image = data.ibm_is_image.example.id + profile = "bx2-8x32" + + primary_network_interface { + subnet = ibm_is_subnet.example.id + } + volume_attachments { + delete_volume_on_instance_delete = true + name = "vol-attach-tfp" + volume_prototype { + iops = 6000 + profile = "custom" + capacity = 100 + source_snapshot = ibm_is_snapshot.example.id + allowed_use { + api_version = "2025-04-03" + bare_metal_server = "true" + instance = "true" + } + } + } + vpc = ibm_is_vpc.example.id + zone = "us-south-2" + keys = [ibm_is_ssh_key.example.id] +} +``` + ## Argument reference Review the argument references that you can specify for your resource. - `availability_policy_host_failure` - (Optional, String) The availability policy to use for this virtual server instance. The action to perform if the compute host experiences a failure. Supported values are `restart` and `stop`. @@ -264,6 +295,24 @@ Review the argument references that you can specify for your resource. - `boot_volume` - (Optional, List) A nested block describes the boot volume configuration for the template. Nested scheme for `boot_volume`: + - `allowed_use` - (Optional, List) The usage constraints to be matched against requested instance or bare metal server properties to determine compatibility. Can only be specified if `source_snapshot` present and bootable. If not specified, the value of this property will be inherited from the `source_image` + + Nested schema for `allowed_use`: + - `api_version` - (Optional, String) The API version with which to evaluate the expressions. + + - `bare_metal_server` - (Optional, String) The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following property is supported, corresponding to the `BareMetalServer` property:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled. + + - `instance` - (Optional, String) The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following variables are supported, corresponding to `Instance` properties:
+ **•** `gpu.count` - (integer) The number of GPUs.
+ **•** `gpu.manufacturer` - (string) The GPU manufacturer.
+ **•** `gpu.memory` - (integer) The overall amount of GPU memory in GiB (gibibytes).
+ **•** `gpu.model` - (string) The GPU model.
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled.
- `bandwidth` - (Optional, Integer) The maximum bandwidth (in megabits per second) for the volume. For this property to be specified, the volume storage_generation must be 2. - `delete_volume_on_instance_delete` - (Optional, Bool) You can configure to delete the boot volume based on instance deletion. - `encryption` - (Optional, String) The encryption key CRN to encrypt the boot volume attached. @@ -457,11 +506,30 @@ Review the argument references that you can specify for your resource. - `volume_prototype` - (Optional, Forces new resource, List) Nested scheme for `volume_prototype`: + - `allowed_use` - (Optional, List) The usage constraints to be matched against requested instance or bare metal server properties to determine compatibility. Can only be specified if `source_snapshot` is present and bootable. If not specified, the value of this property will be inherited from the `source_snapshot`. + + Nested schema for `allowed_use`: + - `api_version` - (Optional, String) The API version with which to evaluate the expressions. + + - `bare_metal_server` - (Optional, String) The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following property is supported, corresponding to the `BareMetalServer` property:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled. + + - `instance` - (Optional, String) The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following variables are supported, corresponding to `Instance` properties:
+ **•** `gpu.count` - (integer) The number of GPUs.
+ **•** `gpu.manufacturer` - (string) The GPU manufacturer.
+ **•** `gpu.memory` - (integer) The overall amount of GPU memory in GiB (gibibytes).
+ **•** `gpu.model` - (string) The GPU model.
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled.
- `bandwidth` - (Optional, Integer) The maximum bandwidth (in megabits per second) for the volume. For this property to be specified, the volume storage_generation must be 2. - `capacity` - (Required, Forces new resource, Integer) The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes may expand in the future. - `encryption_key` - (Optional, Forces new resource, String) The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for the resource. - `iops` - (Optional, Forces new resource, Integer) The maximum input and output operations per second (IOPS) for the volume. - `profile` - (Required, Forces new resource, String) The global unique name for the volume profile to use for the volume. Allowed values areFor more information, about volume profiles, see [volume profiles](https://cloud.ibm.com/docs/vpc?topic=vpc-block-storage-profiles) + - `source_snapshot` - The snapshot to use as a source for the volume's data. To create a volume from a `source_snapshot`, the volume profile and the source snapshot must have the same `storage_generation` value. - `tags`- (Optional, Array of Strings) A list of user tags that you want to add to your volume. (https://cloud.ibm.com/apidocs/tagging#types-of-tags) ~>**Note:** diff --git a/website/docs/r/is_instance_volume_attachment.html.markdown b/website/docs/r/is_instance_volume_attachment.html.markdown index 153f026b52..2883697a82 100644 --- a/website/docs/r/is_instance_volume_attachment.html.markdown +++ b/website/docs/r/is_instance_volume_attachment.html.markdown @@ -154,6 +154,24 @@ The `ibm_is_instance_volume_attachment` resource provides the following [Timeout ## Argument reference Review the argument references that you can specify for your resource. +- `allowed_use` - (Optional, List) The usage constraints to be matched against requested instance or bare metal server properties to determine compatibility. Can only be specified if source_snapshot is bootable. + + Nested schema for `allowed_use`: + - `api_version` - (Optional, String) The API version with which to evaluate the expressions. If specified, the value must be between `2019-01-01` and today's date (in UTC). If unspecified, the version query parameter value will be used. + + - `bare_metal_server` - (Optional, String) The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following property is supported, corresponding to the BareMetalServer property:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled. + + - `instance` - (Optional, String) The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume. If unspecified, the expression will be set to true .The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following variables are supported, corresponding to `Instance`
+ **•** `gpu.count` - (integer) The number of GPUs.
+ **•** `gpu.manufacturer` - (string) The GPU manufacturer.
+ **•** `gpu.memory` - (integer) The overall amount of GPU memory in GiB (gibibytes).
+ **•** `gpu.model` - (string) The GPU model.
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled.
- `bandwidth` - (Optional, Integer) The maximum bandwidth (in megabits per second) for the volume. For this property to be specified, the volume storage_generation must be 2. - `capacity` - (Optional, Integer) The capacity of the volume in gigabytes. diff --git a/website/docs/r/is_snapshot.html.markdown b/website/docs/r/is_snapshot.html.markdown index 6d31cf926e..332d30eeec 100644 --- a/website/docs/r/is_snapshot.html.markdown +++ b/website/docs/r/is_snapshot.html.markdown @@ -89,6 +89,19 @@ resource "ibm_is_snapshot" "example_copy" { } ``` + ## Example usage (allowed use) +```terraform +resource "ibm_is_snapshot" "example_allowed_use" { + name = "example-snapshot" + source_volume = ibm_is_instance.testacc_instance.volume_attachments[0].volume_id + allowed_use { + api_version = "2025-03-31" + bare_metal_server = "true" + instance = "true" + } +} +``` + ## Timeouts The `ibm_is_snapshot` resource provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: @@ -106,6 +119,24 @@ Review the argument references that you can specify for your resource. **•** For more information, about creating access tags, see [working with tags](https://cloud.ibm.com/docs/account?topic=account-tag&interface=ui#create-access-console).
**•** You must have the access listed in the [Granting users access to tag resources](https://cloud.ibm.com/docs/account?topic=account-access) for `access_tags`
**•** `access_tags` must be in the format `key:value`. + - `allowed_use` - (Optional, List) The usage constraints to match against the requested instance or bare metal server properties to determine compatibility. Can only be specified for bootable snapshots. + + Nested schema for `allowed_use`: + - `api_version` - (Optional, String) The API version with which to evaluate the expressions. + + - `bare_metal_server` - (Optional, String) The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this snapshot. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
the following variable is supported, corresponding to the `BareMetalServer` property:
+ **•** `enable_secure_boot` - (boolean)Indicates whether secure boot is enabled. + + - `instance` - (Optional, String) The expression that must be satisfied by the properties of a virtual server instance provisioned using this snapshot. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following variables are supported, corresponding to `Instance` properties:
+ **•** `gpu.count` - (integer) The number of GPUs.
+ **•** `gpu.manufacturer` - (string) The GPU manufacturer.
+ **•** `gpu.memory` - (integer) The overall amount of GPU memory in GiB (gibibytes).
+ **•** `gpu.model` - (string) The GPU.
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled.
- `clones` - (Optional, List) The list of zones to create a clone of this snapshot. - `encryption_key` - (String) A reference CRN to the root key used to wrap the data encryption key for the source snapshot. - `name` - (Optional, String) The name of the snapshot. @@ -199,6 +230,7 @@ In addition to all argument reference list, you can access the following attribu - `name` - (String) The globally unique name for this region. - `resource_type` - (String) The resource type. + ## Import The `ibm_is_snapshot` can be imported using ID. diff --git a/website/docs/r/is_volume.html.markdown b/website/docs/r/is_volume.html.markdown index e37f264ce4..a07b836179 100644 --- a/website/docs/r/is_volume.html.markdown +++ b/website/docs/r/is_volume.html.markdown @@ -54,6 +54,22 @@ resource "ibm_is_volume" "storage" { source_snapshot = ibm_is_snapshot.example.id } ``` + +The following example creates a volume from snapshot with allowed_use. +```terraform +resource "ibm_is_volume" "storage" { + name = "example-volume" + profile = "general-purpose" + zone = "us-south-1" + source_snapshot = ibm_is_snapshot.example.id + allowed_use { + api_version = "2025-07-02" + bare_metal_server = "enable_secure_boot == true" + instance = "enable_secure_boot == true" + } +} +``` + ## Timeouts The `ibm_is_volume` resource provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: @@ -73,6 +89,24 @@ Review the argument references that you can specify for your resource. **•** `access_tags` must be in the format `key:value`. - `adjustable_capacity_states` - (List) The attachment states that support adjustable capacity for this volume. Allowable list items are: `attached`, `unattached`, `unusable`. - `adjustable_iops_states` - (List) The attachment states that support adjustable IOPS for this volume. Allowable list items are: `attached`, `unattached`, `unusable`. +- `allowed_use` - (Optional, List) The usage constraints to be matched against the requested instance or bare metal server properties to determine compatibility. Can only be specified if `source_snapshot` is bootable. If not specified, the value of this property will be inherited from the `source_snapshot`. + + Nested schema for `allowed_use`: + - `api_version` - (Optional, String) The API version with which to evaluate the expressions. + + - `bare_metal_server` - (Optional, String) The expression that must be satisfied by the properties of a bare metal server provisioned using the image data in this volume. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following property is supported, corresponding to the `BareMetalServer` property:
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled. + + - `instance` - (Optional, String) The expression that must be satisfied by the properties of a virtual server instance provisioned using this volume. If unspecified, the expression will be set to true. The expression follows [Common Expression Language](https://github.com/google/cel-spec/blob/master/doc/langdef.md), but does not support built-in functions and macros. + + ~> **NOTE**
In addition, the following variables are supported, corresponding to `Instance` properties:
+ **•** `gpu.count` - (integer) The number of GPUs.
+ **•** `gpu.manufacturer` - (string) The GPU manufacturer.
+ **•** `gpu.memory` - (integer) The overall amount of GPU memory in GiB (gibibytes).
+ **•** `gpu.model` - (string) The GPU model.
+ **•** `enable_secure_boot` - (boolean) Indicates whether secure boot is enabled.
- `bandwidth` - (Optional, Integer) The maximum bandwidth (in megabits per second) for the volume. For this property to be specified, the volume storage_generation must be 2. - `capacity` - (Optional, Integer) (The capacity of the volume in gigabytes. This defaults to `100`, minimum to `10 ` and maximum to `16000`.