diff --git a/examples/ibm-is-ng/main.tf b/examples/ibm-is-ng/main.tf index 66f01f9cc9a..0dd6a29ec85 100644 --- a/examples/ibm-is-ng/main.tf +++ b/examples/ibm-is-ng/main.tf @@ -18,6 +18,60 @@ resource "ibm_is_subnet" "subnet1" { ipv4_cidr_block = "10.240.0.0/28" } +resource "ibm_is_instance_template" "instancetemplate1" { + name = "testtemplate" + image = "r006-14140f94-fcc4-11e9-96e7-a72723715315" + profile = "bx2-8x32" + + primary_network_interface { + subnet = ibm_is_subnet.subnet2.id + allow_ip_spoofing = true + } + + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + keys = [ibm_is_ssh_key.sshkey.id] + + boot_volume { + name = "testbootvol" + delete_volume_on_instance_delete = true + } + volume_attachments { + delete_volume_on_instance_delete = true + name = "volatt-01" + volume_prototype { + iops = 3000 + profile = "general-purpose" + capacity = 200 + } + } +} + +resource "ibm_is_instance_template" "instancetemplate2" { + name = "testtemplate1" + image = "r006-14140f94-fcc4-11e9-96e7-a72723715315" + profile = "bx2-8x32" + + primary_network_interface { + subnet = ibm_is_subnet.subnet2.id + allow_ip_spoofing = true + } + + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + keys = [ibm_is_ssh_key.sshkey.id] + + boot_volume { + name = "testbootvol" + delete_volume_on_instance_delete = true + } + volume_attachments { + delete_volume_on_instance_delete = true + name = "volatt-01" + volume = ibm_is_volume.vol1.id + } +} + resource "ibm_is_lb" "lb2" { name = "mylb" subnets = [ibm_is_subnet.subnet1.id] diff --git a/ibm/data_source_ibm_is_instance_templates.go b/ibm/data_source_ibm_is_instance_templates.go index e0372b1c5b2..04c94cac16f 100644 --- a/ibm/data_source_ibm_is_instance_templates.go +++ b/ibm/data_source_ibm_is_instance_templates.go @@ -142,6 +142,34 @@ func dataSourceIBMISInstanceTemplates() *schema.Resource { Type: schema.TypeString, Computed: true, }, + isInstanceTemplateVolAttVolPrototype: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplateVolAttVolIops: { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum I/O operations per second (IOPS) for the volume.", + }, + isInstanceTemplateVolAttVolProfile: { + Type: schema.TypeString, + Computed: true, + Description: "The globally unique name for the volume profile to use for this volume.", + }, + isInstanceTemplateVolAttVolCapacity: { + Type: schema.TypeInt, + Computed: true, + Description: "The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes may expand in the future.", + }, + isInstanceTemplateVolAttVolEncryptionKey: { + Type: schema.TypeString, + Computed: true, + Description: "The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource.", + }, + }, + }, + }, }, }, }, @@ -387,7 +415,31 @@ func dataSourceIBMISInstanceTemplatesRead(d *schema.ResourceData, meta interface volumeAttach[isInstanceTemplateDeleteVolume] = *volume.DeleteVolumeOnInstanceDelete volumeIntf := volume.Volume volumeInst := volumeIntf.(*vpcv1.VolumeAttachmentVolumePrototypeInstanceContext) - volumeAttach[isInstanceTemplateVolAttVolume] = volumeInst.Name + newVolumeArr := []map[string]interface{}{} + newVolume := map[string]interface{}{} + + if volumeInst.ID != nil { + volumeAttach[isInstanceTemplateVolAttVolume] = *volumeInst.ID + } + + if volumeInst.Capacity != nil { + newVolume[isInstanceTemplateVolAttVolCapacity] = *volumeInst.Capacity + } + if volumeInst.Profile != nil { + profile := volumeInst.Profile.(*vpcv1.VolumeProfileIdentity) + newVolume[isInstanceTemplateVolAttVolProfile] = profile.Name + } + + if volumeInst.Iops != nil { + newVolume[isInstanceTemplateVolAttVolIops] = *volumeInst.Iops + } + if volumeInst.EncryptionKey != nil { + encryptionKey := volumeInst.EncryptionKey.(*vpcv1.EncryptionKeyIdentity) + newVolume[isInstanceTemplateVolAttVolEncryptionKey] = *encryptionKey.CRN + } + newVolumeArr = append(newVolumeArr, newVolume) + volumeAttach[isInstanceTemplateVolAttVolPrototype] = newVolumeArr + interfacesList = append(interfacesList, volumeAttach) } template[isInstanceTemplateVolumeAttachments] = interfacesList diff --git a/ibm/provider_test.go b/ibm/provider_test.go index d72c6d14866..39793e200ee 100644 --- a/ibm/provider_test.go +++ b/ibm/provider_test.go @@ -344,7 +344,7 @@ func init() { isImage = os.Getenv("IS_IMAGE") if isImage == "" { //isImage = "fc538f61-7dd6-4408-978c-c6b85b69fe76" // for classic infrastructure - isImage = "r006-ed3f775f-ad7e-4e37-ae62-7199b4988b00" // for next gen infrastructure + isImage = "r006-5b05b4fe-bcbc-4309-ad45-3354813227a0" // for next gen infrastructure fmt.Println("[INFO] Set the environment variable IS_IMAGE for testing ibm_is_instance, ibm_is_floating_ip else it is set to default value 'r006-ed3f775f-ad7e-4e37-ae62-7199b4988b00'") } diff --git a/ibm/resource_ibm_is_instance_template.go b/ibm/resource_ibm_is_instance_template.go index 8fea8da7553..f4cdc0613b4 100644 --- a/ibm/resource_ibm_is_instance_template.go +++ b/ibm/resource_ibm_is_instance_template.go @@ -15,6 +15,9 @@ import ( const ( isInstanceTemplateBootVolume = "boot_volume" isInstanceTemplateVolAttVolAutoDelete = "auto_delete" + isInstanceTemplateVolAttVol = "volume" + isInstanceTemplateVolAttachmentName = "name" + isInstanceTemplateVolAttVolPrototype = "volume_prototype" isInstanceTemplateVolAttVolCapacity = "capacity" isInstanceTemplateVolAttVolIops = "iops" isInstanceTemplateVolAttVolName = "name" @@ -52,10 +55,17 @@ func resourceIBMISInstanceTemplate() *schema.Resource { Exists: resourceIBMisInstanceTemplateExists, Importer: &schema.ResourceImporter{}, - CustomizeDiff: customdiff.Sequence( - func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return resourceTagsCustomizeDiff(diff) - }, + CustomizeDiff: customdiff.All( + customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return resourceTagsCustomizeDiff(diff) + }, + ), + + customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return resourceVolumeAttachmentValidate(diff) + }), ), Schema: map[string]*schema.Schema{ @@ -104,16 +114,55 @@ func resourceIBMISInstanceTemplate() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ isInstanceTemplateVolumeDeleteOnInstanceDelete: { - Type: schema.TypeBool, - Required: true, + Type: schema.TypeBool, + Required: true, + Description: "If set to true, when deleting the instance the volume will also be deleted.", }, - "name": { - Type: schema.TypeString, - Required: true, + isInstanceTemplateVolAttachmentName: { + Type: schema.TypeString, + Required: true, + Description: "The user-defined name for this volume attachment.", }, - "volume": { - Type: schema.TypeString, - Required: true, + isInstanceTemplateVolAttVol: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The unique identifier for this volume.", + }, + isInstanceTemplateVolAttVolPrototype: { + Type: schema.TypeList, + MaxItems: 1, + MinItems: 1, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isInstanceTemplateVolAttVolIops: { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Description: "The maximum I/O operations per second (IOPS) for the volume.", + }, + isInstanceTemplateVolAttVolProfile: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The globally unique name for the volume profile to use for this volume.", + }, + isInstanceTemplateVolAttVolCapacity: { + Type: schema.TypeInt, + Required: true, + ForceNew: true, + Description: "The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes may expand in the future.", + }, + isInstanceTemplateVolAttVolEncryptionKey: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource.", + }, + }, + }, }, }, }, @@ -430,17 +479,43 @@ func instanceTemplateCreate(d *schema.ResourceData, meta interface{}, profile, n for _, resource := range vols { vol := resource.(map[string]interface{}) volInterface := &vpcv1.VolumeAttachmentPrototypeInstanceContext{} - deleteVol, _ := vol[isInstanceTemplateVolumeDeleteOnInstanceDelete] - deleteVolBool := deleteVol.(bool) + deleteVolBool := vol[isInstanceTemplateVolumeDeleteOnInstanceDelete].(bool) volInterface.DeleteVolumeOnInstanceDelete = &deleteVolBool - name, _ := vol["name"] - namestr := name.(string) - volInterface.Name = &namestr - volintf, _ := vol["volume"] - volintfstr := volintf.(string) - volInterface.Volume = &vpcv1.VolumeAttachmentVolumePrototypeInstanceContext{ - ID: &volintfstr, + attachmentnamestr := vol[isInstanceTemplateVolAttachmentName].(string) + volInterface.Name = &attachmentnamestr + volIdStr := vol[isInstanceTemplateVolAttVol].(string) + + if volIdStr != "" { + volInterface.Volume = &vpcv1.VolumeAttachmentVolumePrototypeInstanceContextVolumeIdentity{ + ID: &volIdStr, + } + } else { + newvolintf := vol[isInstanceTemplateVolAttVolPrototype].([]interface{})[0] + newvol := newvolintf.(map[string]interface{}) + profileName := newvol[isInstanceTemplateVolAttVolProfile].(string) + capacity := int64(newvol[isInstanceTemplateVolAttVolCapacity].(int)) + + volPrototype := &vpcv1.VolumeAttachmentVolumePrototypeInstanceContextVolumePrototypeInstanceContext{ + Profile: &vpcv1.VolumeProfileIdentity{ + Name: &profileName, + }, + Capacity: &capacity, + } + iops := int64(newvol[isInstanceTemplateVolAttVolIops].(int)) + encryptionKey := newvol[isInstanceTemplateVolAttVolEncryptionKey].(string) + + if iops != 0 { + volPrototype.Iops = &iops + } + + if encryptionKey != "" { + volPrototype.EncryptionKey = &vpcv1.EncryptionKeyIdentity{ + CRN: &encryptionKey, + } + } + volInterface.Volume = volPrototype } + intfs = append(intfs, *volInterface) } instanceproto.VolumeAttachments = intfs @@ -679,16 +754,33 @@ func instanceTemplateGet(d *schema.ResourceData, meta interface{}, ID string) er volumeAttach := map[string]interface{}{} volumeAttach[isInstanceTemplateVolAttName] = *volume.Name volumeAttach[isInstanceTemplateDeleteVolume] = *volume.DeleteVolumeOnInstanceDelete - volumeID := map[string]interface{}{} + newVolumeArr := []map[string]interface{}{} + newVolume := map[string]interface{}{} volumeIntf := volume.Volume volumeInst := volumeIntf.(*vpcv1.VolumeAttachmentVolumePrototypeInstanceContext) - if volumeInst.Name != nil { - volumeID["name"] = *volumeInst.Name + 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 { - volumeID["iops"] = *volumeInst.Iops + newVolume[isInstanceTemplateVolAttVolIops] = *volumeInst.Iops + } + if volumeInst.EncryptionKey != nil { + encryptionKey := volumeInst.EncryptionKey.(*vpcv1.EncryptionKeyIdentity) + newVolume[isInstanceTemplateVolAttVolEncryptionKey] = *encryptionKey.CRN + } + if len(newVolume) > 0 { + newVolumeArr = append(newVolumeArr, newVolume) } - volumeAttach[isInstanceTemplateVolAttVolume] = volumeID + volumeAttach[isInstanceTemplateVolAttVolPrototype] = newVolumeArr interfacesList = append(interfacesList, volumeAttach) } d.Set(isInstanceTemplateVolumeAttachments, interfacesList) diff --git a/ibm/resource_ibm_is_instance_template_test.go b/ibm/resource_ibm_is_instance_template_test.go index 85192e9fb21..0ac51eb33cc 100644 --- a/ibm/resource_ibm_is_instance_template_test.go +++ b/ibm/resource_ibm_is_instance_template_test.go @@ -42,6 +42,35 @@ func TestAccIBMISInstanceTemplate_basic(t *testing.T) { }) } +func TestAccIBMISInstanceTemplate_WithVolumeAttachment(t *testing.T) { + randInt := acctest.RandIntRange(10, 100) + + publicKey := strings.TrimSpace(` + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDVtuCfWKVGKaRmaRG6JQZY8YdxnDgGzVOK93IrV9R5Hl0JP1oiLLWlZQS2reAKb8lBqyDVEREpaoRUDjqDqXG8J/kR42FKN51su914pjSBc86wJ02VtT1Wm1zRbSg67kT+g8/T1jCgB5XBODqbcICHVP8Z1lXkgbiHLwlUrbz6OZkGJHo/M/kD1Eme8lctceIYNz/Ilm7ewMXZA4fsidpto9AjyarrJLufrOBl4MRVcZTDSJ7rLP982aHpu9pi5eJAjOZc7Og7n4ns3NFppiCwgVMCVUQbN5GBlWhZ1OsT84ZiTf+Zy8ew+Yg5T7Il8HuC7loWnz+esQPf0s3xhC/kTsGgZreIDoh/rxJfD67wKXetNSh5RH/n5BqjaOuXPFeNXmMhKlhj9nJ8scayx/wsvOGuocEIkbyJSLj3sLUU403OafgatEdnJOwbqg6rUNNF5RIjpJpL7eEWlKIi1j9LyhmPJ+fEO7TmOES82VpCMHpLbe4gf/MhhJ/Xy8DKh9s= root@ffd8363b1226 + `) + vpcName := fmt.Sprintf("tf-testvpc%d", randInt) + subnetName := fmt.Sprintf("tf-testsubnet%d", randInt) + templateName := fmt.Sprintf("tf-testtemplate%d", randInt) + volAttachName := fmt.Sprintf("tf-testvolattach%d", randInt) + sshKeyName := fmt.Sprintf("tf-testsshkey%d", randInt) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckIBMISInstanceTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceTemplateWithVolume(vpcName, subnetName, sshKeyName, publicKey, templateName, volAttachName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_is_instance_template.instancetemplate1", "name", templateName), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_template.instancetemplate1", "profile"), + ), + }, + }, + }) +} + func testAccCheckIBMISInstanceTemplateDestroy(s *terraform.State) error { sess, _ := testAccProvider.Meta().(ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { @@ -104,3 +133,52 @@ func testAccCheckIBMISInstanceTemplateConfig(vpcName, subnetName, sshKeyName, pu `, vpcName, subnetName, sshKeyName, publicKey, templateName) } + +func testAccCheckIBMISInstanceTemplateWithVolume(vpcName, subnetName, sshKeyName, publicKey, templateName, volAttachName string) string { + return fmt.Sprintf(` + provider "ibm" { + generation = 2 + } + + resource "ibm_is_vpc" "vpc2" { + name = "%s" + } + + resource "ibm_is_subnet" "subnet2" { + name = "%s" + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + ipv4_cidr_block = "10.240.64.0/28" + } + + resource "ibm_is_ssh_key" "sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance_template" "instancetemplate1" { + name = "%s" + image = "%s" + profile = "bx2-8x32" + + primary_network_interface { + subnet = ibm_is_subnet.subnet2.id + } + volume_attachments { + delete_volume_on_instance_delete = true + name = "%s" + volume_prototype { + iops = 9000 + profile = "general-purpose" + capacity = 100 + } + } + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + keys = [ibm_is_ssh_key.sshkey.id] + } + + + `, vpcName, subnetName, sshKeyName, publicKey, templateName, isImage, volAttachName) + +} diff --git a/ibm/structures.go b/ibm/structures.go index b9e1af05cdb..3d201ef0b2f 100644 --- a/ibm/structures.go +++ b/ibm/structures.go @@ -1978,6 +1978,34 @@ func resourceTagsCustomizeDiff(diff *schema.ResourceDiff) error { return nil } +func resourceVolumeAttachmentValidate(diff *schema.ResourceDiff) error { + + if volsintf, ok := diff.GetOk("volume_attachments"); ok { + vols := volsintf.([]interface{}) + for volAttIdx := range vols { + volumeid := "volume_attachments." + strconv.Itoa(volAttIdx) + "." + isInstanceTemplateVolAttVol + volumePrototype := "volume_attachments." + strconv.Itoa(volAttIdx) + "." + isInstanceTemplateVolAttVolPrototype + var volIdnterpolated = false + var volumeIdFound = false + if _, volumeIdFound = diff.GetOk(volumeid); !volumeIdFound { + if !diff.NewValueKnown(volumeid) { + volIdnterpolated = true + } + } + _, volPrototypeFound := diff.GetOk(volumePrototype) + + if volPrototypeFound && (volumeIdFound || volIdnterpolated) { + return fmt.Errorf("InstanceTemplate - volume_attachments[%d]: Cannot provide both 'volume' and 'volume_prototype' together.", volAttIdx) + } + if !volPrototypeFound && !volumeIdFound && !volIdnterpolated { + return fmt.Errorf("InstanceTemplate - volume_attachments[%d]: Volume details missing. Provide either 'volume' or 'volume_prototype'.", volAttIdx) + } + } + } + + return nil +} + func flattenRoleData(object []iampolicymanagementv1.Role, roleType string) []map[string]string { var roles []map[string]string diff --git a/website/docs/d/is_instance_templates.html.markdown b/website/docs/d/is_instance_templates.html.markdown index 537a291a587..af0a5d3ebf9 100644 --- a/website/docs/d/is_instance_templates.html.markdown +++ b/website/docs/d/is_instance_templates.html.markdown @@ -48,7 +48,12 @@ In addition to all arguments above, the following attributes are exported: * `profile` - Profile for the boot volume configured. * `delete_volume_on_instance_delete` - Configured to delete the boot volume to be deleted upon instance deletion. * `volume_attachments` - A nested block describing the storage volume configuration for the template. - * `name` - Name of the boot volume. + * `name` - Name of the volume attachment * `volume` - Storage volume ID created under VPC. * `delete_volume_on_instance_delete` - Configured to delete the storage volume to be deleted upon instance deletion. + * `volume_prototype` A nested block describing prototype for the volume + * `iops` - The maximum I/O operations per second (IOPS) for the volume. + * `profile` - The globally unique name for the volume profile to use for this volume. + * `capacity` - 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` - 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. * `user_data` - User data provided for the instance. diff --git a/website/docs/r/is_instance_template.html.markdown b/website/docs/r/is_instance_template.html.markdown index 91cc6cf126b..701ae0cc417 100644 --- a/website/docs/r/is_instance_template.html.markdown +++ b/website/docs/r/is_instance_template.html.markdown @@ -50,6 +50,20 @@ resource "ibm_is_dedicated_host" "is_dedicated_host" { resource_group = data.ibm_resource_group.default.id } +resource "ibm_is_volume" "datavol" { + name = "datavol1" + resource_group = data.ibm_resource_group.default.id + zone = "us-south-2" + + profile = "general-purpose" + capacity = 50 +} + +data "ibm_resource_group" "default" { + is_default = true +} + +// Create a new volume with the volume attachment. This template format can be used with instance groups resource "ibm_is_instance_template" "instancetemplate1" { name = "testtemplate" image = "r006-14140f94-fcc4-11e9-96e7-a72723715315" @@ -68,6 +82,41 @@ resource "ibm_is_instance_template" "instancetemplate1" { name = "testbootvol" delete_volume_on_instance_delete = true } + volume_attachments { + delete_volume_on_instance_delete = true + name = "volatt-01" + volume_prototype { + iops = 3000 + profile = "general-purpose" + capacity = 200 + } + } +} + +// Template with volume attachment that attaches exisiting storage volume. This template cannot be used with instance groups +resource "ibm_is_instance_template" "instancetemplate2" { + name = "testtemplate1" + image = "r006-14140f94-fcc4-11e9-96e7-a72723715315" + profile = "bx2-8x32" + + primary_network_interface { + subnet = ibm_is_subnet.subnet2.id + allow_ip_spoofing = true + } + + vpc = ibm_is_vpc.vpc2.id + zone = "us-south-2" + keys = [ibm_is_ssh_key.sshkey.id] + + boot_volume { + name = "testbootvol" + delete_volume_on_instance_delete = true + } + volume_attachments { + delete_volume_on_instance_delete = true + name = "volatt-01" + volume = ibm_is_volume.datavol.id + } } resource "ibm_is_instance_template" "instancetemplate1" { @@ -144,48 +193,49 @@ The following arguments are supported: * `name` - (Optional, string) Name of the boot volume. * `delete_volume_on_instance_delete` - (Optional, bool) Configured to delete the boot volume to be deleted upon instance deletion. * `volume_attachments` - (Optional, list) A nested block describing the storage volume configuration for the template. Nested volume_attachments blocks have the following structure: - * `name` - (Required, string) Name of the boot volume. - * `volume` - (Required, string) Storage volume ID created under VPC. + * `name` - (Required, string) Name of the volume attachment. + * `volume` - (Optional, string, ForceNew) Storage volume ID created under VPC. * `delete_volume_on_instance_delete` - (Required, bool) Configured to delete the storage volume to be deleted upon instance deletion. + * `volume_prototype` - (Optional, list, ForceNew) + * `iops` - (Optional, int) The maximum I/O operations per second (IOPS) for the volume. + * `profile` - (Optional, string) The globally unique name for the volume profile to use for this volume. + * `capacity` - (Optional, int) The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes may expand in the future. + * `encryption_key` - (Optional, string) The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource. * `user_data` - (Optional, string) User data provided for the instance. -**NOTE**: `volume_attachments` Volume attachments are not supported for instance groups, so if you plan to use this instance template with an instance group do not include volume attachment for Data volumes. Otherwise, you can add one or more secondary data volumes to be included in the template to be used when you provision the instances with the Template +**NOTE**: `volume_attachments` Provide either 'volume' with a storage volume id, or 'volume_prototype' to create a new volume. If you plan to use this template with instance group, provide the 'volume_prototype'. Instance group does not support template with existing storage volume IDs. ## Attribute Reference In addition to all arguments above, the following attributes are exported: * `id` - Id of the instance template -* `name` - Instance Template name -* `volume_attachments` - Collection of volume attachments. Nested `volume_attachments` blocks have the following structure: - * `delete_volume_on_instance_delete` - If set to true, when deleting the instance the volume will also be deleted. - * `name` - The user-defined name for this volume attachment. - * `volume` - The identity of the volume to attach to the instance, or a prototype object for a newvolume. -* `primary_network_interfaces` - A nested block describing the primary network interface for the template - * `allow_ip_spoofing` - Indicates whether source IP spoofing is allowed on this interface. - * `subnet` - The VPC subnet to assign to the interface. - * `name` - Name of the interface. - * `primary_ipv4_address` - Pv4 address assigned to the primary network interface. - * `security_groups` - List of security groups under the subnet. -* `network_interfaces` - A nested block describing the network interfaces for the template. - * `allow_ip_spoofing` - Indicates whether source IP spoofing is allowed on this interface. - * `subnet` - The VPC subnet to assign to the interface. - * `name` - Name of the interface. - * `primary_ipv4_address` - IPv4 address assigned to the network interface. - * `security_groups` - List of security groups under the subnet. -* `boot_volume` - A nested block describing the boot volume configuration for the template. - * `encryption` - encryption key CRN to encrypt the boot volume attached. - * `name` - Name of the boot volume. - * `size` - Boot volume size to configured in GB. - * `profile` - Profile for the boot volume configured. - * `delete_volume_on_instance_delete` - Configured to delete the boot volume to be deleted upon instance deletion. -* `resource_group` - Resource group ID. -* `user_data` - User data provided for the instance. -* `image` - The ID of the image to used to create the template. -* `placement_target` - The placement restrictions to use for the virtual server instance. - * `id` - The unique identifier for this dedicated host - * `crn` - The CRN for this dedicated host. - * `href` - The URL for this dedicated host. +* `primary_network_interfaces` - (Required, list) A nested block describing the primary network interface for the template. Nested primary_network_interface block have the following structure: + * `subnet` - (Required, Forces new resource, string) The VPC subnet to assign to the interface. + * `name` - (Optional, string) Name of the interface. + * `primary_ipv4_address` - (Optional, string) IPv4 address assigned to the primary network interface. + * `security_groups` - (Optional, list) List of security groups under the subnet. + * `allow_ip_spoofing` - (Optional, bool) Indicates whether IP spoofing is allowed on this interface. If false, IP spoofing is prevented on this interface. If true, IP spoofing is allowed on this interface. +* `volume_attachments` - (Optional, list) A nested block describing the storage volume configuration for the template. Nested volume_attachments blocks have the following structure: + * `name` - (Required, string) Name of the volume attachment. + * `volume` - (Optional, string, ForceNew) Storage volume ID created under VPC. + * `delete_volume_on_instance_delete` - (Required, bool) Configured to delete the storage volume to be deleted upon instance deletion. + * `volume_prototype` - (Optional, list, ForceNew) A nested block describing prototype for the volume + * `iops` - (Optional, int) The maximum I/O operations per second (IOPS) for the volume. + * `profile` - (Optional, string) The globally unique name for the volume profile to use for this volume. + * `capacity` - (Optional, int) The capacity of the volume in gigabytes. The specified minimum and maximum capacity values for creating or updating volumes may expand in the future. + * `encryption_key` - (Optional, string) The CRN of the [Key Protect Root Key](https://cloud.ibm.com/docs/key-protect?topic=key-protect-getting-started-tutorial) or [Hyper Protect Crypto Service Root Key](https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-get-started) for this resource. +* `network_interfaces` - (Optional, list) A nested block describing the network interfaces for the template. Nested network_interfaces blocks have the following structure: + * `subnet` - (Required, Forces new resource, string) The VPC subnet to assign to the interface. + * `name` - (Optional, string) Name of the interface. + * `primary_ipv4_address` - (Optional, string) IPv4 address assigned to the network interface. + * `security_groups` - (Optional, list) List of security groups under the subnet. + * `allow_ip_spoofing` - (Optional, bool) Indicates whether IP spoofing is allowed on this interface. If false, IP spoofing is prevented on this interface. If true, IP spoofing is allowed on this interface. +* `boot_volume` - (Optional, block) A nested block describing the boot volume configuration for the template. Nested boot_volume blocks have the following structure: + * `encryption` - (Optional, string) encryption key CRN to encrypt the boot volume attached. + * `name` - (Optional, string) Name of the boot volume. + * `delete_volume_on_instance_delete` - (Optional, bool) Configured to delete the boot volume to be deleted upon instance deletion. +* `resource_group` - (Optional, Forces new resource, string) Resource group ID. ## Import