diff --git a/builtin/providers/rabbitmq/import_queue_test.go b/builtin/providers/rabbitmq/import_queue_test.go new file mode 100644 index 000000000..ceb3eec80 --- /dev/null +++ b/builtin/providers/rabbitmq/import_queue_test.go @@ -0,0 +1,34 @@ +package rabbitmq + +import ( + "testing" + + "github.com/michaelklishin/rabbit-hole" + + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccQueue_importBasic(t *testing.T) { + resourceName := "rabbitmq_queue.test" + var queue rabbithole.QueueInfo + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccQueueCheckDestroy(&queue), + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccQueueConfig_basic, + Check: testAccQueueCheck( + resourceName, &queue, + ), + }, + + resource.TestStep{ + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} diff --git a/builtin/providers/rabbitmq/provider.go b/builtin/providers/rabbitmq/provider.go index 99bf6ac40..790e6e29f 100644 --- a/builtin/providers/rabbitmq/provider.go +++ b/builtin/providers/rabbitmq/provider.go @@ -74,6 +74,7 @@ func Provider() terraform.ResourceProvider { ResourcesMap: map[string]*schema.Resource{ "rabbitmq_exchange": resourceExchange(), "rabbitmq_permissions": resourcePermissions(), + "rabbitmq_queue": resourceQueue(), "rabbitmq_user": resourceUser(), "rabbitmq_vhost": resourceVhost(), }, diff --git a/builtin/providers/rabbitmq/resource_queue.go b/builtin/providers/rabbitmq/resource_queue.go new file mode 100644 index 000000000..097b04d62 --- /dev/null +++ b/builtin/providers/rabbitmq/resource_queue.go @@ -0,0 +1,180 @@ +package rabbitmq + +import ( + "fmt" + "log" + "strings" + + "github.com/michaelklishin/rabbit-hole" + + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceQueue() *schema.Resource { + return &schema.Resource{ + Create: CreateQueue, + Read: ReadQueue, + Delete: DeleteQueue, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "vhost": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "/", + ForceNew: true, + }, + + "settings": &schema.Schema{ + Type: schema.TypeList, + Required: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "durable": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "auto_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "arguments": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + }, + }, + }, + }, + }, + } +} + +func CreateQueue(d *schema.ResourceData, meta interface{}) error { + rmqc := meta.(*rabbithole.Client) + + name := d.Get("name").(string) + vhost := d.Get("vhost").(string) + settingsList := d.Get("settings").([]interface{}) + + settingsMap, ok := settingsList[0].(map[string]interface{}) + if !ok { + return fmt.Errorf("Unable to parse settings") + } + + if err := declareQueue(rmqc, vhost, name, settingsMap); err != nil { + return err + } + + id := fmt.Sprintf("%s@%s", name, vhost) + d.SetId(id) + + return ReadQueue(d, meta) +} + +func ReadQueue(d *schema.ResourceData, meta interface{}) error { + rmqc := meta.(*rabbithole.Client) + + queueId := strings.Split(d.Id(), "@") + if len(queueId) < 2 { + return fmt.Errorf("Unable to determine Queue ID") + } + + user := queueId[0] + vhost := queueId[1] + + queueSettings, err := rmqc.GetQueue(vhost, user) + if err != nil { + return checkDeleted(d, err) + } + + log.Printf("[DEBUG] RabbitMQ: Queue retrieved for %s: %#v", d.Id(), queueSettings) + + d.Set("name", queueSettings.Name) + d.Set("vhost", queueSettings.Vhost) + + queue := make([]map[string]interface{}, 1) + e := make(map[string]interface{}) + e["durable"] = queueSettings.Durable + e["auto_delete"] = queueSettings.AutoDelete + e["arguments"] = queueSettings.Arguments + queue[0] = e + + d.Set("settings", queue) + + return nil +} + +func DeleteQueue(d *schema.ResourceData, meta interface{}) error { + rmqc := meta.(*rabbithole.Client) + + queueId := strings.Split(d.Id(), "@") + if len(queueId) < 2 { + return fmt.Errorf("Unable to determine Queue ID") + } + + user := queueId[0] + vhost := queueId[1] + + log.Printf("[DEBUG] RabbitMQ: Attempting to delete queue for %s", d.Id()) + + resp, err := rmqc.DeleteQueue(vhost, user) + log.Printf("[DEBUG] RabbitMQ: Queue delete response: %#v", resp) + if err != nil { + return err + } + + if resp.StatusCode == 404 { + // the queue was automatically deleted + return nil + } + + if resp.StatusCode >= 400 { + return fmt.Errorf("Error deleting RabbitMQ queue: %s", resp.Status) + } + + return nil +} + +func declareQueue(rmqc *rabbithole.Client, vhost string, name string, settingsMap map[string]interface{}) error { + queueSettings := rabbithole.QueueSettings{} + + if v, ok := settingsMap["durable"].(bool); ok { + queueSettings.Durable = v + } + + if v, ok := settingsMap["auto_delete"].(bool); ok { + queueSettings.AutoDelete = v + } + + if v, ok := settingsMap["arguments"].(map[string]interface{}); ok { + queueSettings.Arguments = v + } + + log.Printf("[DEBUG] RabbitMQ: Attempting to declare queue for %s@%s: %#v", name, vhost, queueSettings) + + resp, err := rmqc.DeclareQueue(vhost, name, queueSettings) + log.Printf("[DEBUG] RabbitMQ: Queue declare response: %#v", resp) + if err != nil { + return err + } + + if resp.StatusCode >= 400 { + return fmt.Errorf("Error declaring RabbitMQ queue: %s", resp.Status) + } + + return nil +} diff --git a/builtin/providers/rabbitmq/resource_queue_test.go b/builtin/providers/rabbitmq/resource_queue_test.go new file mode 100644 index 000000000..4d63104c6 --- /dev/null +++ b/builtin/providers/rabbitmq/resource_queue_test.go @@ -0,0 +1,102 @@ +package rabbitmq + +import ( + "fmt" + "strings" + "testing" + + "github.com/michaelklishin/rabbit-hole" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccQueue(t *testing.T) { + var queueInfo rabbithole.QueueInfo + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccQueueCheckDestroy(&queueInfo), + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccQueueConfig_basic, + Check: testAccQueueCheck( + "rabbitmq_queue.test", &queueInfo, + ), + }, + }, + }) +} + +func testAccQueueCheck(rn string, queueInfo *rabbithole.QueueInfo) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[rn] + if !ok { + return fmt.Errorf("resource not found: %s", rn) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("queue id not set") + } + + rmqc := testAccProvider.Meta().(*rabbithole.Client) + queueParts := strings.Split(rs.Primary.ID, "@") + + queues, err := rmqc.ListQueuesIn(queueParts[1]) + if err != nil { + return fmt.Errorf("Error retrieving queue: %s", err) + } + + for _, queue := range queues { + if queue.Name == queueParts[0] && queue.Vhost == queueParts[1] { + queueInfo = &queue + return nil + } + } + + return fmt.Errorf("Unable to find queue %s", rn) + } +} + +func testAccQueueCheckDestroy(queueInfo *rabbithole.QueueInfo) resource.TestCheckFunc { + return func(s *terraform.State) error { + rmqc := testAccProvider.Meta().(*rabbithole.Client) + + queues, err := rmqc.ListQueuesIn(queueInfo.Vhost) + if err != nil { + return fmt.Errorf("Error retrieving queue: %s", err) + } + + for _, queue := range queues { + if queue.Name == queueInfo.Name && queue.Vhost == queueInfo.Vhost { + return fmt.Errorf("Queue %s@%s still exist", queueInfo.Name, queueInfo.Vhost) + } + } + + return nil + } +} + +const testAccQueueConfig_basic = ` +resource "rabbitmq_vhost" "test" { + name = "test" +} + +resource "rabbitmq_permissions" "guest" { + user = "guest" + vhost = "${rabbitmq_vhost.test.name}" + permissions { + configure = ".*" + write = ".*" + read = ".*" + } +} + +resource "rabbitmq_queue" "test" { + name = "test" + vhost = "${rabbitmq_permissions.guest.vhost}" + settings { + durable = false + auto_delete = true + } +}`