This is an automated email from the ASF dual-hosted git repository.
rohit pushed a commit to branch main
in repository
https://gitbox.apache.org/repos/asf/cloudstack-terraform-provider.git
The following commit(s) were added to refs/heads/main by this push:
new 997dbb2 Fix: #117 - Allow Multiple SSH Keypairs (#122)
997dbb2 is described below
commit 997dbb21211c551469b98ca13cbee430c4fcd49e
Author: CodeBleu <[email protected]>
AuthorDate: Tue Jul 30 03:16:06 2024 -0400
Fix: #117 - Allow Multiple SSH Keypairs (#122)
---
cloudstack/resource_cloudstack_instance.go | 53 +++++++++++++--
cloudstack/resource_cloudstack_instance_test.go | 89 +++++++++++++++++++++++++
website/docs/r/instance.html.markdown | 7 +-
3 files changed, 140 insertions(+), 9 deletions(-)
diff --git a/cloudstack/resource_cloudstack_instance.go
b/cloudstack/resource_cloudstack_instance.go
index a4e2cae..09e345d 100644
--- a/cloudstack/resource_cloudstack_instance.go
+++ b/cloudstack/resource_cloudstack_instance.go
@@ -139,9 +139,17 @@ func resourceCloudStackInstance() *schema.Resource {
ForceNew: true,
},
- "keypair": {
- Type: schema.TypeString,
- Optional: true,
+ "keypair": &schema.Schema{
+ Type: schema.TypeString,
+ Optional: true,
+ ConflictsWith: []string{"keypairs"},
+ },
+
+ "keypairs": {
+ Type: schema.TypeList,
+ Optional: true,
+ Elem: &schema.Schema{Type:
schema.TypeString},
+ ConflictsWith: []string{"keypair"},
},
"host_id": {
@@ -213,6 +221,7 @@ func resourceCloudStackInstance() *schema.Resource {
}
func resourceCloudStackInstanceCreate(d *schema.ResourceData, meta
interface{}) error {
+
cs := meta.(*cloudstack.CloudStackClient)
// Retrieve the service_offering ID
@@ -354,6 +363,14 @@ func resourceCloudStackInstanceCreate(d
*schema.ResourceData, meta interface{})
p.SetKeypair(keypair.(string))
}
+ if keypairs, ok := d.GetOk("keypairs"); ok {
+ var keypairStrings []string
+ for _, kp := range keypairs.([]interface{}) {
+ keypairStrings = append(keypairStrings,
fmt.Sprintf("%v", kp))
+ }
+ p.SetKeypairs(keypairStrings)
+ }
+
// If a host_id is supplied, add it to the parameter struct
if hostid, ok := d.GetOk("host_id"); ok {
@@ -493,6 +510,7 @@ func resourceCloudStackInstanceRead(d *schema.ResourceData,
meta interface{}) er
}
func resourceCloudStackInstanceUpdate(d *schema.ResourceData, meta
interface{}) error {
+
cs := meta.(*cloudstack.CloudStackClient)
name := d.Get("name").(string)
@@ -537,7 +555,8 @@ func resourceCloudStackInstanceUpdate(d
*schema.ResourceData, meta interface{})
// Attributes that require reboot to update
if d.HasChange("name") || d.HasChange("service_offering") ||
d.HasChange("affinity_group_ids") ||
- d.HasChange("affinity_group_names") || d.HasChange("keypair")
|| d.HasChange("user_data") {
+ d.HasChange("affinity_group_names") || d.HasChange("keypair")
|| d.HasChange("keypairs") || d.HasChange("user_data") {
+
// Before we can actually make these changes, the virtual
machine must be stopped
_, err := cs.VirtualMachine.StopVirtualMachine(
cs.VirtualMachine.NewStopVirtualMachineParams(d.Id()))
@@ -631,8 +650,8 @@ func resourceCloudStackInstanceUpdate(d
*schema.ResourceData, meta interface{})
}
// Check if the keypair has changed and if so, update the
keypair
- if d.HasChange("keypair") {
- log.Printf("[DEBUG] SSH keypair changed for %s,
starting update", name)
+ if d.HasChange("keypair") || d.HasChange("keypairs") {
+ log.Printf("[DEBUG] SSH keypair(s) changed for %s,
starting update", name)
p :=
cs.SSH.NewResetSSHKeyForVirtualMachineParams(d.Id())
@@ -640,6 +659,26 @@ func resourceCloudStackInstanceUpdate(d
*schema.ResourceData, meta interface{})
p.SetKeypair(keypair.(string))
}
+ if keypairs, ok := d.GetOk("keypairs"); ok {
+
+ // Convert keypairsInterface to []interface{}
+ keypairsInterfaces := keypairs.([]interface{})
+
+ // Now, safely convert []interface{} to
[]string with error handling
+ strKeyPairs := make([]string,
len(keypairsInterfaces))
+
+ for i, v := range keypairsInterfaces {
+ switch v := v.(type) {
+ case string:
+ strKeyPairs[i] = v
+ default:
+ log.Printf("Value at index %d
is not a string: %v", i, v)
+ continue
+ }
+ }
+ p.SetKeypairs(strKeyPairs)
+ }
+
// If there is a project supplied, we retrieve and set
the project id
if err := setProjectid(p, cs, d); err != nil {
return err
@@ -648,7 +687,7 @@ func resourceCloudStackInstanceUpdate(d
*schema.ResourceData, meta interface{})
_, err = cs.SSH.ResetSSHKeyForVirtualMachine(p)
if err != nil {
return fmt.Errorf(
- "Error changing the SSH keypair for
instance %s: %s", name, err)
+ "Error changing the SSH keypair(s) for
instance %s: %s", name, err)
}
}
diff --git a/cloudstack/resource_cloudstack_instance_test.go
b/cloudstack/resource_cloudstack_instance_test.go
index 38307dc..d7eeada 100644
--- a/cloudstack/resource_cloudstack_instance_test.go
+++ b/cloudstack/resource_cloudstack_instance_test.go
@@ -150,6 +150,68 @@ func TestAccCloudStackInstance_keyPair(t *testing.T) {
})
}
+func TestAccCloudStackInstance_keyPairs(t *testing.T) {
+ var instance cloudstack.VirtualMachine
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckCloudStackInstanceDestroy,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccCloudStackInstance_keyPairs,
+ Check: resource.ComposeTestCheckFunc(
+
testAccCheckCloudStackInstanceExists("cloudstack_instance.foobar", &instance),
+
resource.TestCheckResourceAttr("cloudstack_instance.foobar", "keypairs.#",
"2"), // Expecting 2 key pairs
+
resource.TestCheckResourceAttr("cloudstack_instance.foobar", "keypairs.0",
"terraform-test-keypair-foo"),
+
resource.TestCheckResourceAttr("cloudstack_instance.foobar", "keypairs.1",
"terraform-test-keypair-bar"),
+ ),
+ },
+ },
+ })
+}
+
+func TestAccCloudStackInstance_keyPair_update(t *testing.T) {
+ var instance cloudstack.VirtualMachine
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckCloudStackInstanceDestroy,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccCloudStackInstance_keyPair,
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckCloudStackInstanceExists(
+ "cloudstack_instance.foobar",
&instance),
+ resource.TestCheckResourceAttr(
+ "cloudstack_instance.foobar",
"keypair", "terraform-test-keypair"),
+ ),
+ },
+
+ {
+ Config: testAccCloudStackInstance_keyPairs,
+ Check: resource.ComposeTestCheckFunc(
+
testAccCheckCloudStackInstanceExists("cloudstack_instance.foobar", &instance),
+
resource.TestCheckResourceAttr("cloudstack_instance.foobar", "keypairs.#",
"2"), // Expecting 2 key pairs
+
resource.TestCheckResourceAttr("cloudstack_instance.foobar", "keypairs.0",
"terraform-test-keypair-foo"),
+
resource.TestCheckResourceAttr("cloudstack_instance.foobar", "keypairs.1",
"terraform-test-keypair-bar"),
+ ),
+ },
+
+ {
+ Config: testAccCloudStackInstance_keyPair,
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckCloudStackInstanceExists(
+ "cloudstack_instance.foobar",
&instance),
+ resource.TestCheckResourceAttr(
+ "cloudstack_instance.foobar",
"keypair", "terraform-test-keypair"),
+ ),
+ },
+ },
+ })
+}
+
func TestAccCloudStackInstance_project(t *testing.T) {
var instance cloudstack.VirtualMachine
@@ -416,6 +478,33 @@ resource "cloudstack_instance" "foobar" {
expunge = true
}`
+const testAccCloudStackInstance_keyPairs = `
+resource "cloudstack_network" "foo" {
+ name = "terraform-network"
+ cidr = "10.1.1.0/24"
+ network_offering = "DefaultIsolatedNetworkOfferingWithSourceNatService"
+ zone = "Sandbox-simulator"
+}
+
+resource "cloudstack_ssh_keypair" "foo" {
+ name = "terraform-test-keypair-foo"
+}
+
+resource "cloudstack_ssh_keypair" "bar" {
+ name = "terraform-test-keypair-bar"
+}
+
+resource "cloudstack_instance" "foobar" {
+ name = "terraform-test"
+ display_name = "terraform-test"
+ service_offering= "Small Instance"
+ network_id = "${cloudstack_network.foo.id}"
+ template = "CentOS 5.6 (64-bit) no GUI (Simulator)"
+ zone = "Sandbox-simulator"
+ keypairs = ["${cloudstack_ssh_keypair.foo.name}",
"${cloudstack_ssh_keypair.bar.name}"]
+ expunge = true
+}`
+
const testAccCloudStackInstance_project = `
resource "cloudstack_network" "foo" {
name = "terraform-network"
diff --git a/website/docs/r/instance.html.markdown
b/website/docs/r/instance.html.markdown
index ee21f69..d4d6187 100644
--- a/website/docs/r/instance.html.markdown
+++ b/website/docs/r/instance.html.markdown
@@ -34,7 +34,7 @@ The following arguments are supported:
* `service_offering` - (Required) The name or ID of the service offering used
for this instance.
-* `host_id` - (Optional) destination Host ID to deploy the VM to - parameter
available
+* `host_id` - (Optional) destination Host ID to deploy the VM to - parameter
available
for root admin only
* `pod_id` - (Optional) destination Pod ID to deploy the VM to - parameter
available for root admin only
@@ -82,7 +82,10 @@ The following arguments are supported:
instance. This can be either plain text or base64 encoded text.
* `keypair` - (Optional) The name of the SSH key pair that will be used to
- access this instance.
+ access this instance. (Mutual exclusive with keypairs)
+
+* `keypairs` - (Optional) A list of SSH key pair names that will be used to
+ access this instance. (Mutual exclusive with keypair)
* `expunge` - (Optional) This determines if the instance is expunged when it is
destroyed (defaults false)