Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cloudstack/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ func Provider() *schema.Provider {
"cloudstack_firewall": resourceCloudStackFirewall(),
"cloudstack_host": resourceCloudStackHost(),
"cloudstack_instance": resourceCloudStackInstance(),
"cloudstack_instance_group": resourceCloudStackInstanceGroup(),
"cloudstack_ipaddress": resourceCloudStackIPAddress(),
"cloudstack_kubernetes_cluster": resourceCloudStackKubernetesCluster(),
"cloudstack_kubernetes_version": resourceCloudStackKubernetesVersion(),
Expand Down
147 changes: 147 additions & 0 deletions cloudstack/resource_cloudstack_instance_group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//

package cloudstack

import (
"fmt"
"log"
"strings"

"github.com/apache/cloudstack-go/v2/cloudstack"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func resourceCloudStackInstanceGroup() *schema.Resource {
return &schema.Resource{
Create: resourceCloudStackInstanceGroupCreate,
Read: resourceCloudStackInstanceGroupRead,
Update: resourceCloudStackInstanceGroupUpdate,
Delete: resourceCloudStackInstanceGroupDelete,
Importer: &schema.ResourceImporter{
State: importStatePassthrough,
},

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},

"project": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
},
}
}

func resourceCloudStackInstanceGroupCreate(d *schema.ResourceData, meta interface{}) error {
cs := meta.(*cloudstack.CloudStackClient)

name := d.Get("name").(string)

// Create a new parameter struct
p := cs.VMGroup.NewCreateInstanceGroupParams(name)

// If there is a project supplied, we retrieve and set the project id
if err := setProjectid(p, cs, d); err != nil {
return err
}

log.Printf("[DEBUG] Creating instance group %s", name)
r, err := cs.VMGroup.CreateInstanceGroup(p)
if err != nil {
return err
}

log.Printf("[DEBUG] Instance group %s successfully created", name)
d.SetId(r.Id)

return resourceCloudStackInstanceGroupRead(d, meta)
}

func resourceCloudStackInstanceGroupRead(d *schema.ResourceData, meta interface{}) error {
cs := meta.(*cloudstack.CloudStackClient)

log.Printf("[DEBUG] Retrieving instance group %s", d.Get("name").(string))

// Get the instance group details
ig, count, err := cs.VMGroup.GetInstanceGroupByID(
d.Id(),
cloudstack.WithProject(d.Get("project").(string)),
)
if err != nil {
if count == 0 {
log.Printf("[DEBUG] Instance group %s does no longer exist", d.Get("name").(string))
d.SetId("")
return nil
}

return err
}

d.Set("name", ig.Name)
setValueOrID(d, "project", ig.Project, ig.Projectid)

return nil
}

func resourceCloudStackInstanceGroupUpdate(d *schema.ResourceData, meta interface{}) error {
cs := meta.(*cloudstack.CloudStackClient)

if d.HasChange("name") {
name := d.Get("name").(string)

// Create a new parameter struct
p := cs.VMGroup.NewUpdateInstanceGroupParams(d.Id())
p.SetName(name)

log.Printf("[DEBUG] Updating instance group %s", d.Id())
_, err := cs.VMGroup.UpdateInstanceGroup(p)
if err != nil {
return fmt.Errorf("Error updating instance group: %s", err)
}
}

return resourceCloudStackInstanceGroupRead(d, meta)
}

func resourceCloudStackInstanceGroupDelete(d *schema.ResourceData, meta interface{}) error {
cs := meta.(*cloudstack.CloudStackClient)

// Create a new parameter struct
p := cs.VMGroup.NewDeleteInstanceGroupParams(d.Id())

// Delete the instance group
_, err := cs.VMGroup.DeleteInstanceGroup(p)
if err != nil {
// This is a very poor way to be told the ID does no longer exist :(
if strings.Contains(err.Error(), fmt.Sprintf(
"Invalid parameter id value=%s due to incorrect long value format, "+
"or entity does not exist", d.Id())) {
return nil
}

return fmt.Errorf("Error deleting instance group: %s", err)
}

return nil
}
147 changes: 147 additions & 0 deletions cloudstack/resource_cloudstack_instance_group_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//

package cloudstack

import (
"fmt"
"testing"

"github.com/apache/cloudstack-go/v2/cloudstack"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
)

func TestAccCloudStackInstanceGroup_basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudStackInstanceGroupDestroy,
Steps: []resource.TestStep{
{
Config: testAccCloudStackInstanceGroup_basic,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudStackInstanceGroupExists("cloudstack_instance_group.foo"),
resource.TestCheckResourceAttr(
"cloudstack_instance_group.foo", "name", "terraform-group"),
),
},
},
})
}

func TestAccCloudStackInstanceGroup_update(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudStackInstanceGroupDestroy,
Steps: []resource.TestStep{
{
Config: testAccCloudStackInstanceGroup_basic,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudStackInstanceGroupExists("cloudstack_instance_group.foo"),
resource.TestCheckResourceAttr(
"cloudstack_instance_group.foo", "name", "terraform-group"),
),
},
{
Config: testAccCloudStackInstanceGroup_renamed,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudStackInstanceGroupExists("cloudstack_instance_group.foo"),
resource.TestCheckResourceAttr(
"cloudstack_instance_group.foo", "name", "terraform-group-renamed"),
),
},
},
})
}

func TestAccCloudStackInstanceGroup_import(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudStackInstanceGroupDestroy,
Steps: []resource.TestStep{
{
Config: testAccCloudStackInstanceGroup_basic,
},
{
ResourceName: "cloudstack_instance_group.foo",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccCheckCloudStackInstanceGroupExists(n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}

if rs.Primary.ID == "" {
return fmt.Errorf("No instance group ID is set")
}

cs := testAccProvider.Meta().(*cloudstack.CloudStackClient)
ig, _, err := cs.VMGroup.GetInstanceGroupByID(rs.Primary.ID)
if err != nil {
return err
}

if ig.Id != rs.Primary.ID {
return fmt.Errorf("Instance group not found")
}

return nil
}
}

func testAccCheckCloudStackInstanceGroupDestroy(s *terraform.State) error {
cs := testAccProvider.Meta().(*cloudstack.CloudStackClient)

for _, rs := range s.RootModule().Resources {
if rs.Type != "cloudstack_instance_group" {
continue
}

if rs.Primary.ID == "" {
return fmt.Errorf("No instance group ID is set")
}

_, _, err := cs.VMGroup.GetInstanceGroupByID(rs.Primary.ID)
if err == nil {
return fmt.Errorf("Instance group %s still exists", rs.Primary.ID)
}
}

return nil
}

const testAccCloudStackInstanceGroup_basic = `
resource "cloudstack_instance_group" "foo" {
name = "terraform-group"
}`

const testAccCloudStackInstanceGroup_renamed = `
resource "cloudstack_instance_group" "foo" {
name = "terraform-group-renamed"
}`
61 changes: 61 additions & 0 deletions website/docs/r/instance_group.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
layout: "cloudstack"
page_title: "CloudStack: cloudstack_instance_group"
sidebar_current: "docs-cloudstack-resource-instance-group"
description: |-
Creates an instance group.
---

# cloudstack_instance_group

Creates an instance group. Instance groups are a simple way to organize
instances; an instance joins a group by setting its `group` argument to the
group's name.

## Example Usage

```hcl
resource "cloudstack_instance_group" "web" {
name = "web-servers"
}

resource "cloudstack_instance" "web" {
name = "web-01"
group = cloudstack_instance_group.web.name
service_offering = "small"
network_id = cloudstack_network.default.id
template = "CentOS 7.0"
zone = "zone-01"
}
```

## Argument Reference

The following arguments are supported:

* `name` - (Required) The name of the instance group.

* `project` - (Optional) The name or ID of the project to create this instance
group in. Changing this forces a new resource to be created.

## Attributes Reference

The following attributes are exported:

* `id` - The id of the instance group.
* `name` - The name of the instance group.

## Import

Instance groups can be imported; use `<INSTANCE GROUP ID>` as the import ID. For
example:

```shell
terraform import cloudstack_instance_group.web 6226ea4d-9cbe-4cc9-b30c-b9532146da5b
```

When importing into a project you need to prefix the import ID with the project name:

```shell
terraform import cloudstack_instance_group.web my-project/6226ea4d-9cbe-4cc9-b30c-b9532146da5b
```
Loading