Skip to content

Commit

Permalink
fix(ins-keys): Make VSI keys optional
Browse files Browse the repository at this point in the history
  • Loading branch information
deepaksibm authored and hkantare committed Jul 19, 2024
1 parent 4a0fdce commit 12aa4b3
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 47 deletions.
102 changes: 56 additions & 46 deletions ibm/service/vpc/resource_ibm_is_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -400,15 +400,15 @@ func ResourceIBMISInstance() *schema.Resource {
Optional: true,
ForceNew: true,
ConflictsWith: []string{"catalog_offering.0.version_crn"},
RequiredWith: []string{isInstanceZone, isInstancePrimaryNetworkInterface, isInstanceKeys, isInstanceVPC, isInstanceProfile},
RequiredWith: []string{isInstanceZone, isInstancePrimaryNetworkInterface, isInstanceVPC, isInstanceProfile},
Description: "Identifies a catalog offering by a unique CRN property",
},
isInstanceCatalogOfferingVersionCrn: {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ConflictsWith: []string{"catalog_offering.0.offering_crn"},
RequiredWith: []string{isInstanceZone, isInstancePrimaryNetworkInterface, isInstanceKeys, isInstanceVPC, isInstanceProfile},
RequiredWith: []string{isInstanceZone, isInstancePrimaryNetworkInterface, isInstanceVPC, isInstanceProfile},
Description: "Identifies a version of a catalog offering by a unique CRN property",
},
isInstanceCatalogOfferingPlanCrn: {
Expand Down Expand Up @@ -1143,7 +1143,7 @@ func ResourceIBMISInstance() *schema.Resource {
Optional: true,
ConflictsWith: []string{"boot_volume.0.snapshot", "boot_volume.0.snapshot_crn", "catalog_offering.0.offering_crn", "catalog_offering.0.version_crn", "boot_volume.0.volume_id"},
AtLeastOneOf: []string{isInstanceImage, isInstanceSourceTemplate, "boot_volume.0.snapshot", "boot_volume.0.snapshot_crn", "catalog_offering.0.offering_crn", "catalog_offering.0.version_crn", "boot_volume.0.volume_id"},
RequiredWith: []string{isInstanceZone, isInstanceKeys, isInstanceVPC, isInstanceProfile},
RequiredWith: []string{isInstanceZone, isInstanceVPC, isInstanceProfile},
Description: "image id",
},

Expand All @@ -1159,7 +1159,7 @@ func ResourceIBMISInstance() *schema.Resource {
Optional: true,
ForceNew: true,
Computed: true,
RequiredWith: []string{isInstanceZone, isInstanceProfile, isInstanceKeys, isInstanceVPC},
RequiredWith: []string{isInstanceZone, isInstanceProfile, isInstanceVPC},
AtLeastOneOf: []string{isInstanceImage, isInstanceSourceTemplate, "boot_volume.0.volume_id", "boot_volume.0.snapshot", "boot_volume.0.snapshot_crn", "catalog_offering.0.offering_crn", "catalog_offering.0.version_crn"},
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",
Expand All @@ -1179,7 +1179,7 @@ func ResourceIBMISInstance() *schema.Resource {

isInstanceVolumeSnapshot: {
Type: schema.TypeString,
RequiredWith: []string{isInstanceZone, isInstanceProfile, isInstanceKeys, isInstanceVPC},
RequiredWith: []string{isInstanceZone, isInstanceProfile, isInstanceVPC},
AtLeastOneOf: []string{isInstanceImage, isInstanceSourceTemplate, "boot_volume.0.snapshot", "boot_volume.0.snapshot_crn", "catalog_offering.0.offering_crn", "catalog_offering.0.version_crn", "boot_volume.0.volume_id"},
ConflictsWith: []string{isInstanceImage, isInstanceSourceTemplate, "catalog_offering.0.offering_crn", "catalog_offering.0.version_crn", "boot_volume.0.volume_id", "boot_volume.0.snapshot_crn"},
Optional: true,
Expand All @@ -1188,7 +1188,7 @@ func ResourceIBMISInstance() *schema.Resource {
},
isInstanceVolumeSnapshotCrn: {
Type: schema.TypeString,
RequiredWith: []string{isInstanceZone, isInstanceProfile, isInstanceKeys, isInstanceVPC},
RequiredWith: []string{isInstanceZone, isInstanceProfile, isInstanceVPC},
AtLeastOneOf: []string{isInstanceImage, isInstanceSourceTemplate, "boot_volume.0.snapshot", "boot_volume.0.snapshot_crn", "catalog_offering.0.offering_crn", "catalog_offering.0.version_crn", "boot_volume.0.volume_id"},
ConflictsWith: []string{isInstanceImage, isInstanceSourceTemplate, "catalog_offering.0.offering_crn", "catalog_offering.0.version_crn", "boot_volume.0.volume_id", "boot_volume.0.snapshot"},
Optional: true,
Expand Down Expand Up @@ -2121,16 +2121,18 @@ func instanceCreateByImage(d *schema.ResourceData, meta interface{}, profile, na
instanceproto.NetworkInterfaces = intfs
}

keySet := d.Get(isInstanceKeys).(*schema.Set)
if keySet.Len() != 0 {
keyobjs := make([]vpcv1.KeyIdentityIntf, keySet.Len())
for i, key := range keySet.List() {
keystr := key.(string)
keyobjs[i] = &vpcv1.KeyIdentity{
ID: &keystr,
if keySetIntf, ok := d.GetOk(isInstanceKeys); ok {
keySet := keySetIntf.(*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
}
instanceproto.Keys = keyobjs
}

if userdata, ok := d.GetOk(isInstanceUserData); ok {
Expand Down Expand Up @@ -2568,16 +2570,18 @@ func instanceCreateByCatalogOffering(d *schema.ResourceData, meta interface{}, p
instanceproto.NetworkInterfaces = intfs
}

keySet := d.Get(isInstanceKeys).(*schema.Set)
if keySet.Len() != 0 {
keyobjs := make([]vpcv1.KeyIdentityIntf, keySet.Len())
for i, key := range keySet.List() {
keystr := key.(string)
keyobjs[i] = &vpcv1.KeyIdentity{
ID: &keystr,
if keySetIntf, ok := d.GetOk(isInstanceKeys); ok {
keySet := keySetIntf.(*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
}
instanceproto.Keys = keyobjs
}

if userdata, ok := d.GetOk(isInstanceUserData); ok {
Expand Down Expand Up @@ -2994,16 +2998,18 @@ func instanceCreateByTemplate(d *schema.ResourceData, meta interface{}, profile,
instanceproto.NetworkInterfaces = intfs
}

keySet := d.Get(isInstanceKeys).(*schema.Set)
if keySet.Len() != 0 {
keyobjs := make([]vpcv1.KeyIdentityIntf, keySet.Len())
for i, key := range keySet.List() {
keystr := key.(string)
keyobjs[i] = &vpcv1.KeyIdentity{
ID: &keystr,
if keySetIntf, ok := d.GetOk(isInstanceKeys); ok {
keySet := keySetIntf.(*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
}
instanceproto.Keys = keyobjs
}

if userdata, ok := d.GetOk(isInstanceUserData); ok {
Expand Down Expand Up @@ -3427,16 +3433,18 @@ func instanceCreateBySnapshot(d *schema.ResourceData, meta interface{}, profile,
instanceproto.NetworkInterfaces = intfs
}

keySet := d.Get(isInstanceKeys).(*schema.Set)
if keySet.Len() != 0 {
keyobjs := make([]vpcv1.KeyIdentityIntf, keySet.Len())
for i, key := range keySet.List() {
keystr := key.(string)
keyobjs[i] = &vpcv1.KeyIdentity{
ID: &keystr,
if keySetIntf, ok := d.GetOk(isInstanceKeys); ok {
keySet := keySetIntf.(*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
}
instanceproto.Keys = keyobjs
}

if userdata, ok := d.GetOk(isInstanceUserData); ok {
Expand Down Expand Up @@ -3826,16 +3834,18 @@ func instanceCreateByVolume(d *schema.ResourceData, meta interface{}, profile, n
instanceproto.NetworkInterfaces = intfs
}

keySet := d.Get(isInstanceKeys).(*schema.Set)
if keySet.Len() != 0 {
keyobjs := make([]vpcv1.KeyIdentityIntf, keySet.Len())
for i, key := range keySet.List() {
keystr := key.(string)
keyobjs[i] = &vpcv1.KeyIdentity{
ID: &keystr,
if keySetIntf, ok := d.GetOk(isInstanceKeys); ok {
keySet := keySetIntf.(*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
}
instanceproto.Keys = keyobjs
}

if userdata, ok := d.GetOk(isInstanceUserData); ok {
Expand Down
85 changes: 85 additions & 0 deletions ibm/service/vpc/resource_ibm_is_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,60 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE
},
})
}

func TestAccIBMISInstanceWithoutKeys_basic(t *testing.T) {
var instance string
vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100))
name := fmt.Sprintf("tf-instnace-%d", acctest.RandIntRange(10, 100))
subnetname := fmt.Sprintf("tf-subnet-%d", acctest.RandIntRange(10, 100))
userData1 := "a"
userData2 := "b"

resource.Test(t, resource.TestCase{
PreCheck: func() { acc.TestAccPreCheck(t) },
Providers: acc.TestAccProviders,
CheckDestroy: testAccCheckIBMISInstanceDestroy,
Steps: []resource.TestStep{
{
Config: testAccCheckIBMISInstanceWithoutKeysConfig(vpcname, subnetname, name, userData1),
Check: resource.ComposeTestCheckFunc(
testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance),
resource.TestCheckResourceAttr(
"ibm_is_instance.testacc_instance", "name", name),
resource.TestCheckResourceAttr(
"ibm_is_instance.testacc_instance", "user_data", userData1),
resource.TestCheckResourceAttr(
"ibm_is_instance.testacc_instance", "zone", acc.ISZoneName),
resource.TestCheckResourceAttrSet(
"ibm_is_instance.testacc_instance", "vcpu.#"),
resource.TestCheckResourceAttrSet(
"ibm_is_instance.testacc_instance", "vcpu.0.manufacturer"),
),
},
{
Config: testAccCheckIBMISInstanceWithoutKeysConfig(vpcname, subnetname, name, userData2),
Check: resource.ComposeTestCheckFunc(
testAccCheckIBMISInstanceExists("ibm_is_instance.testacc_instance", instance),
resource.TestCheckResourceAttr(
"ibm_is_instance.testacc_instance", "name", name),
resource.TestCheckResourceAttr(
"ibm_is_instance.testacc_instance", "user_data", userData2),
resource.TestCheckResourceAttr(
"ibm_is_instance.testacc_instance", "zone", acc.ISZoneName),
resource.TestCheckResourceAttrSet(
"ibm_is_instance.testacc_instance", "primary_network_interface.0.port_speed"),
resource.TestCheckResourceAttrSet(
"ibm_is_instance.testacc_instance", "vcpu.#"),
resource.TestCheckResourceAttrSet(
"ibm_is_instance.testacc_instance", "vcpu.0.manufacturer"),
resource.TestCheckResourceAttrSet(
"ibm_is_instance.testacc_instance", "numa_count"),
),
},
},
})
}

func TestAccIBMISInstance_concom(t *testing.T) {
var instance string
vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100))
Expand Down Expand Up @@ -1403,6 +1457,37 @@ func testAccCheckIBMISInstanceConfig(vpcname, subnetname, sshname, publicKey, na
}
}`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, sshname, publicKey, name, acc.IsImage, acc.InstanceProfileName, userData, acc.ISZoneName)
}

func testAccCheckIBMISInstanceWithoutKeysConfig(vpcname, subnetname, name, userData string) string {
return fmt.Sprintf(`
resource "ibm_is_vpc" "testacc_vpc" {
name = "%s"
}
resource "ibm_is_subnet" "testacc_subnet" {
name = "%s"
vpc = ibm_is_vpc.testacc_vpc.id
zone = "%s"
ipv4_cidr_block = "%s"
}
resource "ibm_is_instance" "testacc_instance" {
name = "%s"
image = "%s"
profile = "%s"
primary_network_interface {
subnet = ibm_is_subnet.testacc_subnet.id
}
user_data = "%s"
vpc = ibm_is_vpc.testacc_vpc.id
zone = "%s"
network_interfaces {
subnet = ibm_is_subnet.testacc_subnet.id
name = "eth1"
}
}`, vpcname, subnetname, acc.ISZoneName, acc.ISCIDR, name, acc.IsImage, acc.InstanceProfileName, userData, acc.ISZoneName)
}

func testAccCheckIBMISInstanceConComConfig(vpcname, subnetname, sshname, publicKey, name, userData string, esb bool) string {
return fmt.Sprintf(`
resource "ibm_is_vpc" "testacc_vpc" {
Expand Down
5 changes: 4 additions & 1 deletion website/docs/r/is_instance.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -567,8 +567,11 @@ Review the argument references that you can specify for your resource.

~> **Note:**
`image` conflicts with `boot_volume.0.snapshot` and `catalog_offering`, not required when creating instance using `instance_template` or `catalog_offering`
- `keys` - (Required, List) A comma-separated list of SSH keys that you want to add to your instance.
- `keys` - (Optional, List) A comma-separated list of SSH keys that you want to add to your instance. The public SSH keys for the administrative user of the virtual server instance. Keys will be made available to the virtual server instance as cloud-init vendor data. For cloud-init enabled images, these keys will also be added as SSH authorized keys for the administrative user.

~> **Note:**
For Windows images, the keys of type rsa must be specified, and one will be selected to encrypt the administrator password. Keys are optional for other images, but if no keys are specified, the instance will be inaccessible unless the specified image provides another means of access.

~> **Note:**
**&#x2022;** `ed25519` can only be used if the operating system supports this key type.</br>
**&#x2022;** `ed25519` can't be used with Windows or VMware images.</br>
Expand Down

0 comments on commit 12aa4b3

Please sign in to comment.