Merge pull request #7694 from jtopjian/provider-rabbitmq
RabbitMQ Provider
This commit is contained in:
commit
05994cef31
|
@ -0,0 +1,26 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cd
|
||||||
|
echo 'deb http://www.rabbitmq.com/debian/ testing main' | sudo tee /etc/apt/sources.list.d/rabbitmq.list
|
||||||
|
wget -O- https://www.rabbitmq.com/rabbitmq-release-signing-key.asc | sudo apt-key add -
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y git make mercurial
|
||||||
|
sudo apt-get install -y rabbitmq-server
|
||||||
|
sudo rabbitmq-plugins enable rabbitmq_management
|
||||||
|
|
||||||
|
sudo wget -O /usr/local/bin/gimme https://raw.githubusercontent.com/travis-ci/gimme/master/gimme
|
||||||
|
sudo chmod +x /usr/local/bin/gimme
|
||||||
|
gimme 1.6 >> .bashrc
|
||||||
|
|
||||||
|
mkdir ~/go
|
||||||
|
eval "$(/usr/local/bin/gimme 1.6)"
|
||||||
|
echo 'export GOPATH=$HOME/go' >> .bashrc
|
||||||
|
export GOPATH=$HOME/go
|
||||||
|
|
||||||
|
export PATH=$PATH:$HOME/terraform:$HOME/go/bin
|
||||||
|
echo 'export PATH=$PATH:$HOME/terraform:$HOME/go/bin' >> .bashrc
|
||||||
|
source .bashrc
|
||||||
|
|
||||||
|
go get -u github.com/kardianos/govendor
|
||||||
|
go get github.com/hashicorp/terraform
|
|
@ -0,0 +1,34 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/michaelklishin/rabbit-hole"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccBinding_importBasic(t *testing.T) {
|
||||||
|
resourceName := "rabbitmq_binding.test"
|
||||||
|
var bindingInfo rabbithole.BindingInfo
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccBindingCheckDestroy(bindingInfo),
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccBindingConfig_basic,
|
||||||
|
Check: testAccBindingCheck(
|
||||||
|
resourceName, &bindingInfo,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
|
||||||
|
resource.TestStep{
|
||||||
|
ResourceName: resourceName,
|
||||||
|
ImportState: true,
|
||||||
|
ImportStateVerify: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/michaelklishin/rabbit-hole"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccExchange_importBasic(t *testing.T) {
|
||||||
|
resourceName := "rabbitmq_exchange.test"
|
||||||
|
var exchangeInfo rabbithole.ExchangeInfo
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccExchangeCheckDestroy(&exchangeInfo),
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccExchangeConfig_basic,
|
||||||
|
Check: testAccExchangeCheck(
|
||||||
|
resourceName, &exchangeInfo,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
|
||||||
|
resource.TestStep{
|
||||||
|
ResourceName: resourceName,
|
||||||
|
ImportState: true,
|
||||||
|
ImportStateVerify: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/michaelklishin/rabbit-hole"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccPermissions_importBasic(t *testing.T) {
|
||||||
|
resourceName := "rabbitmq_permissions.test"
|
||||||
|
var permissionInfo rabbithole.PermissionInfo
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccPermissionsCheckDestroy(&permissionInfo),
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccPermissionsConfig_basic,
|
||||||
|
Check: testAccPermissionsCheck(
|
||||||
|
resourceName, &permissionInfo,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
|
||||||
|
resource.TestStep{
|
||||||
|
ResourceName: resourceName,
|
||||||
|
ImportState: true,
|
||||||
|
ImportStateVerify: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/michaelklishin/rabbit-hole"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccPolicy_importBasic(t *testing.T) {
|
||||||
|
resourceName := "rabbitmq_policy.test"
|
||||||
|
var policy rabbithole.Policy
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccPolicyCheckDestroy(&policy),
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccPolicyConfig_basic,
|
||||||
|
Check: testAccPolicyCheck(
|
||||||
|
resourceName, &policy,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
|
||||||
|
resource.TestStep{
|
||||||
|
ResourceName: resourceName,
|
||||||
|
ImportState: true,
|
||||||
|
ImportStateVerify: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
|
@ -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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccUser_importBasic(t *testing.T) {
|
||||||
|
resourceName := "rabbitmq_user.test"
|
||||||
|
var user string
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccUserCheckDestroy(user),
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccUserConfig_basic,
|
||||||
|
Check: testAccUserCheck(
|
||||||
|
resourceName, &user,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
|
||||||
|
resource.TestStep{
|
||||||
|
ResourceName: resourceName,
|
||||||
|
ImportState: true,
|
||||||
|
ImportStateVerify: true,
|
||||||
|
ImportStateVerifyIgnore: []string{"password"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccVhost_importBasic(t *testing.T) {
|
||||||
|
resourceName := "rabbitmq_vhost.test"
|
||||||
|
var vhost string
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccVhostCheckDestroy(vhost),
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccVhostConfig_basic,
|
||||||
|
Check: testAccVhostCheck(
|
||||||
|
resourceName, &vhost,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
|
||||||
|
resource.TestStep{
|
||||||
|
ResourceName: resourceName,
|
||||||
|
ImportState: true,
|
||||||
|
ImportStateVerify: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/michaelklishin/rabbit-hole"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Provider() terraform.ResourceProvider {
|
||||||
|
return &schema.Provider{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"endpoint": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
DefaultFunc: schema.EnvDefaultFunc("RABBITMQ_ENDPOINT", nil),
|
||||||
|
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
|
||||||
|
value := v.(string)
|
||||||
|
if value == "" {
|
||||||
|
errors = append(errors, fmt.Errorf("Endpoint must not be an empty string"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"username": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
DefaultFunc: schema.EnvDefaultFunc("RABBITMQ_USERNAME", nil),
|
||||||
|
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
|
||||||
|
value := v.(string)
|
||||||
|
if value == "" {
|
||||||
|
errors = append(errors, fmt.Errorf("Username must not be an empty string"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"password": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
DefaultFunc: schema.EnvDefaultFunc("RABBITMQ_PASSWORD", nil),
|
||||||
|
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
|
||||||
|
value := v.(string)
|
||||||
|
if value == "" {
|
||||||
|
errors = append(errors, fmt.Errorf("Password must not be an empty string"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"insecure": &schema.Schema{
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
DefaultFunc: schema.EnvDefaultFunc("RABBITMQ_INSECURE", nil),
|
||||||
|
},
|
||||||
|
|
||||||
|
"cacert_file": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
DefaultFunc: schema.EnvDefaultFunc("RABBITMQ_CACERT", ""),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
ResourcesMap: map[string]*schema.Resource{
|
||||||
|
"rabbitmq_binding": resourceBinding(),
|
||||||
|
"rabbitmq_exchange": resourceExchange(),
|
||||||
|
"rabbitmq_permissions": resourcePermissions(),
|
||||||
|
"rabbitmq_policy": resourcePolicy(),
|
||||||
|
"rabbitmq_queue": resourceQueue(),
|
||||||
|
"rabbitmq_user": resourceUser(),
|
||||||
|
"rabbitmq_vhost": resourceVhost(),
|
||||||
|
},
|
||||||
|
|
||||||
|
ConfigureFunc: providerConfigure,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func providerConfigure(d *schema.ResourceData) (interface{}, error) {
|
||||||
|
|
||||||
|
var username = d.Get("username").(string)
|
||||||
|
var password = d.Get("password").(string)
|
||||||
|
var endpoint = d.Get("endpoint").(string)
|
||||||
|
var insecure = d.Get("insecure").(bool)
|
||||||
|
var cacertFile = d.Get("cacert_file").(string)
|
||||||
|
|
||||||
|
// Configure TLS/SSL:
|
||||||
|
// Ignore self-signed cert warnings
|
||||||
|
// Specify a custom CA / intermediary cert
|
||||||
|
// Specify a certificate and key
|
||||||
|
tlsConfig := &tls.Config{}
|
||||||
|
if cacertFile != "" {
|
||||||
|
caCert, err := ioutil.ReadFile(cacertFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
caCertPool := x509.NewCertPool()
|
||||||
|
caCertPool.AppendCertsFromPEM(caCert)
|
||||||
|
tlsConfig.RootCAs = caCertPool
|
||||||
|
}
|
||||||
|
if insecure {
|
||||||
|
tlsConfig.InsecureSkipVerify = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect to RabbitMQ management interface
|
||||||
|
transport := &http.Transport{TLSClientConfig: tlsConfig}
|
||||||
|
rmqc, err := rabbithole.NewTLSClient(endpoint, username, password, transport)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rmqc, nil
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
// To run these acceptance tests, you will need access to a RabbitMQ server
|
||||||
|
// with the management plugin enabled.
|
||||||
|
//
|
||||||
|
// Set the RABBITMQ_ENDPOINT, RABBITMQ_USERNAME, and RABBITMQ_PASSWORD
|
||||||
|
// environment variables before running the tests.
|
||||||
|
//
|
||||||
|
// You can run the tests like this:
|
||||||
|
// make testacc TEST=./builtin/providers/rabbitmq
|
||||||
|
|
||||||
|
var testAccProviders map[string]terraform.ResourceProvider
|
||||||
|
var testAccProvider *schema.Provider
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
testAccProvider = Provider().(*schema.Provider)
|
||||||
|
testAccProviders = map[string]terraform.ResourceProvider{
|
||||||
|
"rabbitmq": testAccProvider,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProvider(t *testing.T) {
|
||||||
|
if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProvider_impl(t *testing.T) {
|
||||||
|
var _ terraform.ResourceProvider = Provider()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccPreCheck(t *testing.T) {
|
||||||
|
for _, name := range []string{"RABBITMQ_ENDPOINT", "RABBITMQ_USERNAME", "RABBITMQ_PASSWORD"} {
|
||||||
|
if v := os.Getenv(name); v == "" {
|
||||||
|
t.Fatal("RABBITMQ_ENDPOINT, RABBITMQ_USERNAME and RABBITMQ_PASSWORD must be set for acceptance tests")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,195 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/michaelklishin/rabbit-hole"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceBinding() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: CreateBinding,
|
||||||
|
Read: ReadBinding,
|
||||||
|
Delete: DeleteBinding,
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"source": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"vhost": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"destination": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"destination_type": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"properties_key": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"routing_key": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"arguments": &schema.Schema{
|
||||||
|
Type: schema.TypeMap,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateBinding(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
rmqc := meta.(*rabbithole.Client)
|
||||||
|
|
||||||
|
vhost := d.Get("vhost").(string)
|
||||||
|
bindingInfo := rabbithole.BindingInfo{
|
||||||
|
Source: d.Get("source").(string),
|
||||||
|
Destination: d.Get("destination").(string),
|
||||||
|
DestinationType: d.Get("destination_type").(string),
|
||||||
|
RoutingKey: d.Get("routing_key").(string),
|
||||||
|
PropertiesKey: d.Get("properties_key").(string),
|
||||||
|
Arguments: d.Get("arguments").(map[string]interface{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := declareBinding(rmqc, vhost, bindingInfo); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
name := fmt.Sprintf("%s/%s/%s/%s/%s", vhost, bindingInfo.Source, bindingInfo.Destination, bindingInfo.DestinationType, bindingInfo.PropertiesKey)
|
||||||
|
d.SetId(name)
|
||||||
|
|
||||||
|
return ReadBinding(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadBinding(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
rmqc := meta.(*rabbithole.Client)
|
||||||
|
|
||||||
|
bindingId := strings.Split(d.Id(), "/")
|
||||||
|
if len(bindingId) < 5 {
|
||||||
|
return fmt.Errorf("Unable to determine binding ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
vhost := bindingId[0]
|
||||||
|
source := bindingId[1]
|
||||||
|
destination := bindingId[2]
|
||||||
|
destinationType := bindingId[3]
|
||||||
|
propertiesKey := bindingId[4]
|
||||||
|
|
||||||
|
bindings, err := rmqc.ListBindingsIn(vhost)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Bindings retrieved: %#v", bindings)
|
||||||
|
bindingFound := false
|
||||||
|
for _, binding := range bindings {
|
||||||
|
if binding.Source == source && binding.Destination == destination && binding.DestinationType == destinationType && binding.PropertiesKey == propertiesKey {
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Found Binding: %#v", binding)
|
||||||
|
bindingFound = true
|
||||||
|
|
||||||
|
d.Set("vhost", binding.Vhost)
|
||||||
|
d.Set("source", binding.Source)
|
||||||
|
d.Set("destination", binding.Destination)
|
||||||
|
d.Set("destination_type", binding.DestinationType)
|
||||||
|
d.Set("routing_key", binding.RoutingKey)
|
||||||
|
d.Set("properties_key", binding.PropertiesKey)
|
||||||
|
d.Set("arguments", binding.Arguments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The binding could not be found,
|
||||||
|
// so consider it deleted and remove from state
|
||||||
|
if !bindingFound {
|
||||||
|
d.SetId("")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteBinding(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
rmqc := meta.(*rabbithole.Client)
|
||||||
|
|
||||||
|
bindingId := strings.Split(d.Id(), "/")
|
||||||
|
if len(bindingId) < 5 {
|
||||||
|
return fmt.Errorf("Unable to determine binding ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
vhost := bindingId[0]
|
||||||
|
source := bindingId[1]
|
||||||
|
destination := bindingId[2]
|
||||||
|
destinationType := bindingId[3]
|
||||||
|
propertiesKey := bindingId[4]
|
||||||
|
|
||||||
|
bindingInfo := rabbithole.BindingInfo{
|
||||||
|
Vhost: vhost,
|
||||||
|
Source: source,
|
||||||
|
Destination: destination,
|
||||||
|
DestinationType: destinationType,
|
||||||
|
PropertiesKey: propertiesKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Attempting to delete binding for %s/%s/%s/%s/%s",
|
||||||
|
vhost, source, destination, destinationType, propertiesKey)
|
||||||
|
|
||||||
|
resp, err := rmqc.DeleteBinding(vhost, bindingInfo)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Binding delete response: %#v", resp)
|
||||||
|
|
||||||
|
if resp.StatusCode == 404 {
|
||||||
|
// The binding was already deleted
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
return fmt.Errorf("Error deleting RabbitMQ binding: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func declareBinding(rmqc *rabbithole.Client, vhost string, bindingInfo rabbithole.BindingInfo) error {
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Attempting to declare binding for %s/%s/%s/%s/%s",
|
||||||
|
vhost, bindingInfo.Source, bindingInfo.Destination, bindingInfo.DestinationType, bindingInfo.PropertiesKey)
|
||||||
|
|
||||||
|
resp, err := rmqc.DeclareBinding(vhost, bindingInfo)
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Binding declare response: %#v", resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
return fmt.Errorf("Error declaring RabbitMQ binding: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/michaelklishin/rabbit-hole"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccBinding(t *testing.T) {
|
||||||
|
var bindingInfo rabbithole.BindingInfo
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccBindingCheckDestroy(bindingInfo),
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccBindingConfig_basic,
|
||||||
|
Check: testAccBindingCheck(
|
||||||
|
"rabbitmq_binding.test", &bindingInfo,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccBindingCheck(rn string, bindingInfo *rabbithole.BindingInfo) 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("binding id not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
rmqc := testAccProvider.Meta().(*rabbithole.Client)
|
||||||
|
bindingParts := strings.Split(rs.Primary.ID, "/")
|
||||||
|
|
||||||
|
bindings, err := rmqc.ListBindingsIn(bindingParts[0])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error retrieving exchange: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, binding := range bindings {
|
||||||
|
if binding.Source == bindingParts[1] && binding.Destination == bindingParts[2] && binding.DestinationType == bindingParts[3] && binding.PropertiesKey == bindingParts[4] {
|
||||||
|
bindingInfo = &binding
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("Unable to find binding %s", rn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccBindingCheckDestroy(bindingInfo rabbithole.BindingInfo) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rmqc := testAccProvider.Meta().(*rabbithole.Client)
|
||||||
|
|
||||||
|
bindings, err := rmqc.ListBindingsIn(bindingInfo.Vhost)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error retrieving exchange: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, binding := range bindings {
|
||||||
|
if binding.Source == bindingInfo.Source && binding.Destination == bindingInfo.Destination && binding.DestinationType == bindingInfo.DestinationType && binding.PropertiesKey == bindingInfo.PropertiesKey {
|
||||||
|
return fmt.Errorf("Binding still exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccBindingConfig_basic = `
|
||||||
|
resource "rabbitmq_vhost" "test" {
|
||||||
|
name = "test"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_permissions" "guest" {
|
||||||
|
user = "guest"
|
||||||
|
vhost = "${rabbitmq_vhost.test.name}"
|
||||||
|
permissions {
|
||||||
|
configure = ".*"
|
||||||
|
write = ".*"
|
||||||
|
read = ".*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_exchange" "test" {
|
||||||
|
name = "test"
|
||||||
|
vhost = "${rabbitmq_permissions.guest.vhost}"
|
||||||
|
settings {
|
||||||
|
type = "fanout"
|
||||||
|
durable = false
|
||||||
|
auto_delete = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_queue" "test" {
|
||||||
|
name = "test"
|
||||||
|
vhost = "${rabbitmq_permissions.guest.vhost}"
|
||||||
|
settings {
|
||||||
|
durable = true
|
||||||
|
auto_delete = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_binding" "test" {
|
||||||
|
source = "${rabbitmq_exchange.test.name}"
|
||||||
|
vhost = "${rabbitmq_vhost.test.name}"
|
||||||
|
destination = "${rabbitmq_queue.test.name}"
|
||||||
|
destination_type = "queue"
|
||||||
|
routing_key = "#"
|
||||||
|
properties_key = "%23"
|
||||||
|
}`
|
|
@ -0,0 +1,189 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/michaelklishin/rabbit-hole"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceExchange() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: CreateExchange,
|
||||||
|
Read: ReadExchange,
|
||||||
|
Delete: DeleteExchange,
|
||||||
|
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{
|
||||||
|
"type": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"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 CreateExchange(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 := declareExchange(rmqc, vhost, name, settingsMap); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
id := fmt.Sprintf("%s@%s", name, vhost)
|
||||||
|
d.SetId(id)
|
||||||
|
|
||||||
|
return ReadExchange(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadExchange(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
rmqc := meta.(*rabbithole.Client)
|
||||||
|
|
||||||
|
exchangeId := strings.Split(d.Id(), "@")
|
||||||
|
if len(exchangeId) < 2 {
|
||||||
|
return fmt.Errorf("Unable to determine exchange ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
name := exchangeId[0]
|
||||||
|
vhost := exchangeId[1]
|
||||||
|
|
||||||
|
exchangeSettings, err := rmqc.GetExchange(vhost, name)
|
||||||
|
if err != nil {
|
||||||
|
return checkDeleted(d, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Exchange retrieved %s: %#v", d.Id(), exchangeSettings)
|
||||||
|
|
||||||
|
d.Set("name", exchangeSettings.Name)
|
||||||
|
d.Set("vhost", exchangeSettings.Vhost)
|
||||||
|
|
||||||
|
exchange := make([]map[string]interface{}, 1)
|
||||||
|
e := make(map[string]interface{})
|
||||||
|
e["type"] = exchangeSettings.Type
|
||||||
|
e["durable"] = exchangeSettings.Durable
|
||||||
|
e["auto_delete"] = exchangeSettings.AutoDelete
|
||||||
|
e["arguments"] = exchangeSettings.Arguments
|
||||||
|
exchange[0] = e
|
||||||
|
d.Set("settings", exchange)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteExchange(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
rmqc := meta.(*rabbithole.Client)
|
||||||
|
|
||||||
|
exchangeId := strings.Split(d.Id(), "@")
|
||||||
|
if len(exchangeId) < 2 {
|
||||||
|
return fmt.Errorf("Unable to determine exchange ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
name := exchangeId[0]
|
||||||
|
vhost := exchangeId[1]
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Attempting to delete exchange %s", d.Id())
|
||||||
|
|
||||||
|
resp, err := rmqc.DeleteExchange(vhost, name)
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Exchange delete response: %#v", resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == 404 {
|
||||||
|
// The exchange was automatically deleted
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
return fmt.Errorf("Error deleting RabbitMQ exchange: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func declareExchange(rmqc *rabbithole.Client, vhost string, name string, settingsMap map[string]interface{}) error {
|
||||||
|
exchangeSettings := rabbithole.ExchangeSettings{}
|
||||||
|
|
||||||
|
if v, ok := settingsMap["type"].(string); ok {
|
||||||
|
exchangeSettings.Type = v
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := settingsMap["durable"].(bool); ok {
|
||||||
|
exchangeSettings.Durable = v
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := settingsMap["auto_delete"].(bool); ok {
|
||||||
|
exchangeSettings.AutoDelete = v
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := settingsMap["arguments"].(map[string]interface{}); ok {
|
||||||
|
exchangeSettings.Arguments = v
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Attempting to declare exchange %s@%s: %#v", name, vhost, exchangeSettings)
|
||||||
|
|
||||||
|
resp, err := rmqc.DeclareExchange(vhost, name, exchangeSettings)
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Exchange declare response: %#v", resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
return fmt.Errorf("Error declaring RabbitMQ exchange: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/michaelklishin/rabbit-hole"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccExchange(t *testing.T) {
|
||||||
|
var exchangeInfo rabbithole.ExchangeInfo
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccExchangeCheckDestroy(&exchangeInfo),
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccExchangeConfig_basic,
|
||||||
|
Check: testAccExchangeCheck(
|
||||||
|
"rabbitmq_exchange.test", &exchangeInfo,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccExchangeCheck(rn string, exchangeInfo *rabbithole.ExchangeInfo) 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("exchange id not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
rmqc := testAccProvider.Meta().(*rabbithole.Client)
|
||||||
|
exchParts := strings.Split(rs.Primary.ID, "@")
|
||||||
|
|
||||||
|
exchanges, err := rmqc.ListExchangesIn(exchParts[1])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error retrieving exchange: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, exchange := range exchanges {
|
||||||
|
if exchange.Name == exchParts[0] && exchange.Vhost == exchParts[1] {
|
||||||
|
exchangeInfo = &exchange
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("Unable to find exchange %s", rn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccExchangeCheckDestroy(exchangeInfo *rabbithole.ExchangeInfo) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rmqc := testAccProvider.Meta().(*rabbithole.Client)
|
||||||
|
|
||||||
|
exchanges, err := rmqc.ListExchangesIn(exchangeInfo.Vhost)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error retrieving exchange: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, exchange := range exchanges {
|
||||||
|
if exchange.Name == exchangeInfo.Name && exchange.Vhost == exchangeInfo.Vhost {
|
||||||
|
return fmt.Errorf("Exchange %s@%s still exist", exchangeInfo.Name, exchangeInfo.Vhost)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccExchangeConfig_basic = `
|
||||||
|
resource "rabbitmq_vhost" "test" {
|
||||||
|
name = "test"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_permissions" "guest" {
|
||||||
|
user = "guest"
|
||||||
|
vhost = "${rabbitmq_vhost.test.name}"
|
||||||
|
permissions {
|
||||||
|
configure = ".*"
|
||||||
|
write = ".*"
|
||||||
|
read = ".*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_exchange" "test" {
|
||||||
|
name = "test"
|
||||||
|
vhost = "${rabbitmq_permissions.guest.vhost}"
|
||||||
|
settings {
|
||||||
|
type = "fanout"
|
||||||
|
durable = false
|
||||||
|
auto_delete = true
|
||||||
|
}
|
||||||
|
}`
|
|
@ -0,0 +1,205 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/michaelklishin/rabbit-hole"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourcePermissions() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: CreatePermissions,
|
||||||
|
Update: UpdatePermissions,
|
||||||
|
Read: ReadPermissions,
|
||||||
|
Delete: DeletePermissions,
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"user": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"vhost": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Default: "/",
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"permissions": &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Required: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"configure": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"write": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"read": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreatePermissions(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
rmqc := meta.(*rabbithole.Client)
|
||||||
|
|
||||||
|
user := d.Get("user").(string)
|
||||||
|
vhost := d.Get("vhost").(string)
|
||||||
|
permsList := d.Get("permissions").([]interface{})
|
||||||
|
|
||||||
|
permsMap, ok := permsList[0].(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Unable to parse permissions")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := setPermissionsIn(rmqc, vhost, user, permsMap); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
id := fmt.Sprintf("%s@%s", user, vhost)
|
||||||
|
d.SetId(id)
|
||||||
|
|
||||||
|
return ReadPermissions(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadPermissions(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
rmqc := meta.(*rabbithole.Client)
|
||||||
|
|
||||||
|
permissionId := strings.Split(d.Id(), "@")
|
||||||
|
if len(permissionId) < 2 {
|
||||||
|
return fmt.Errorf("Unable to determine Permission ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
user := permissionId[0]
|
||||||
|
vhost := permissionId[1]
|
||||||
|
|
||||||
|
userPerms, err := rmqc.GetPermissionsIn(vhost, user)
|
||||||
|
if err != nil {
|
||||||
|
return checkDeleted(d, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Permission retrieved for %s: %#v", d.Id(), userPerms)
|
||||||
|
|
||||||
|
d.Set("user", userPerms.User)
|
||||||
|
d.Set("vhost", userPerms.Vhost)
|
||||||
|
|
||||||
|
perms := make([]map[string]interface{}, 1)
|
||||||
|
p := make(map[string]interface{})
|
||||||
|
p["configure"] = userPerms.Configure
|
||||||
|
p["write"] = userPerms.Write
|
||||||
|
p["read"] = userPerms.Read
|
||||||
|
perms[0] = p
|
||||||
|
d.Set("permissions", perms)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdatePermissions(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
rmqc := meta.(*rabbithole.Client)
|
||||||
|
|
||||||
|
permissionId := strings.Split(d.Id(), "@")
|
||||||
|
if len(permissionId) < 2 {
|
||||||
|
return fmt.Errorf("Unable to determine Permission ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
user := permissionId[0]
|
||||||
|
vhost := permissionId[1]
|
||||||
|
|
||||||
|
if d.HasChange("permissions") {
|
||||||
|
_, newPerms := d.GetChange("permissions")
|
||||||
|
|
||||||
|
newPermsList := newPerms.([]interface{})
|
||||||
|
permsMap, ok := newPermsList[0].(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Unable to parse permissions")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := setPermissionsIn(rmqc, vhost, user, permsMap); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ReadPermissions(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeletePermissions(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
rmqc := meta.(*rabbithole.Client)
|
||||||
|
|
||||||
|
permissionId := strings.Split(d.Id(), "@")
|
||||||
|
if len(permissionId) < 2 {
|
||||||
|
return fmt.Errorf("Unable to determine Permission ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
user := permissionId[0]
|
||||||
|
vhost := permissionId[1]
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Attempting to delete permission for %s", d.Id())
|
||||||
|
|
||||||
|
resp, err := rmqc.ClearPermissionsIn(vhost, user)
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Permission delete response: %#v", resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == 404 {
|
||||||
|
// The permissions were already deleted
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
return fmt.Errorf("Error deleting RabbitMQ permission: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setPermissionsIn(rmqc *rabbithole.Client, vhost string, user string, permsMap map[string]interface{}) error {
|
||||||
|
perms := rabbithole.Permissions{}
|
||||||
|
|
||||||
|
if v, ok := permsMap["configure"].(string); ok {
|
||||||
|
perms.Configure = v
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := permsMap["write"].(string); ok {
|
||||||
|
perms.Write = v
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := permsMap["read"].(string); ok {
|
||||||
|
perms.Read = v
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Attempting to set permissions for %s@%s: %#v", user, vhost, perms)
|
||||||
|
|
||||||
|
resp, err := rmqc.UpdatePermissionsIn(vhost, user, perms)
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Permission response: %#v", resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
return fmt.Errorf("Error setting permissions: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,124 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/michaelklishin/rabbit-hole"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccPermissions(t *testing.T) {
|
||||||
|
var permissionInfo rabbithole.PermissionInfo
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccPermissionsCheckDestroy(&permissionInfo),
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccPermissionsConfig_basic,
|
||||||
|
Check: testAccPermissionsCheck(
|
||||||
|
"rabbitmq_permissions.test", &permissionInfo,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccPermissionsConfig_update,
|
||||||
|
Check: testAccPermissionsCheck(
|
||||||
|
"rabbitmq_permissions.test", &permissionInfo,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccPermissionsCheck(rn string, permissionInfo *rabbithole.PermissionInfo) 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("permission id not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
rmqc := testAccProvider.Meta().(*rabbithole.Client)
|
||||||
|
perms, err := rmqc.ListPermissions()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error retrieving permissions: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
userParts := strings.Split(rs.Primary.ID, "@")
|
||||||
|
for _, perm := range perms {
|
||||||
|
if perm.User == userParts[0] && perm.Vhost == userParts[1] {
|
||||||
|
permissionInfo = &perm
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("Unable to find permissions for user %s", rn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccPermissionsCheckDestroy(permissionInfo *rabbithole.PermissionInfo) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rmqc := testAccProvider.Meta().(*rabbithole.Client)
|
||||||
|
perms, err := rmqc.ListPermissions()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error retrieving permissions: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, perm := range perms {
|
||||||
|
if perm.User == permissionInfo.User && perm.Vhost == permissionInfo.Vhost {
|
||||||
|
return fmt.Errorf("Permissions still exist for user %s@%s", permissionInfo.User, permissionInfo.Vhost)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccPermissionsConfig_basic = `
|
||||||
|
resource "rabbitmq_vhost" "test" {
|
||||||
|
name = "test"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_user" "test" {
|
||||||
|
name = "mctest"
|
||||||
|
password = "foobar"
|
||||||
|
tags = ["administrator"]
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_permissions" "test" {
|
||||||
|
user = "${rabbitmq_user.test.name}"
|
||||||
|
vhost = "${rabbitmq_vhost.test.name}"
|
||||||
|
permissions {
|
||||||
|
configure = ".*"
|
||||||
|
write = ".*"
|
||||||
|
read = ".*"
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
const testAccPermissionsConfig_update = `
|
||||||
|
resource "rabbitmq_vhost" "test" {
|
||||||
|
name = "test"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_user" "test" {
|
||||||
|
name = "mctest"
|
||||||
|
password = "foobar"
|
||||||
|
tags = ["administrator"]
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_permissions" "test" {
|
||||||
|
user = "${rabbitmq_user.test.name}"
|
||||||
|
vhost = "${rabbitmq_vhost.test.name}"
|
||||||
|
permissions {
|
||||||
|
configure = ".*"
|
||||||
|
write = ".*"
|
||||||
|
read = ""
|
||||||
|
}
|
||||||
|
}`
|
|
@ -0,0 +1,239 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/michaelklishin/rabbit-hole"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourcePolicy() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: CreatePolicy,
|
||||||
|
Update: UpdatePolicy,
|
||||||
|
Read: ReadPolicy,
|
||||||
|
Delete: DeletePolicy,
|
||||||
|
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,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"policy": &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Required: true,
|
||||||
|
MaxItems: 1,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"pattern": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"priority": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply_to": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"definition": &schema.Schema{
|
||||||
|
Type: schema.TypeMap,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreatePolicy(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
rmqc := meta.(*rabbithole.Client)
|
||||||
|
|
||||||
|
name := d.Get("name").(string)
|
||||||
|
vhost := d.Get("vhost").(string)
|
||||||
|
policyList := d.Get("policy").([]interface{})
|
||||||
|
|
||||||
|
policyMap, ok := policyList[0].(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Unable to parse policy")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := putPolicy(rmqc, vhost, name, policyMap); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
id := fmt.Sprintf("%s@%s", name, vhost)
|
||||||
|
d.SetId(id)
|
||||||
|
|
||||||
|
return ReadPolicy(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadPolicy(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
rmqc := meta.(*rabbithole.Client)
|
||||||
|
|
||||||
|
policyId := strings.Split(d.Id(), "@")
|
||||||
|
if len(policyId) < 2 {
|
||||||
|
return fmt.Errorf("Unable to determine policy ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
user := policyId[0]
|
||||||
|
vhost := policyId[1]
|
||||||
|
|
||||||
|
policy, err := rmqc.GetPolicy(vhost, user)
|
||||||
|
if err != nil {
|
||||||
|
return checkDeleted(d, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Policy retrieved for %s: %#v", d.Id(), policy)
|
||||||
|
|
||||||
|
d.Set("name", policy.Name)
|
||||||
|
d.Set("vhost", policy.Vhost)
|
||||||
|
|
||||||
|
setPolicy := make([]map[string]interface{}, 1)
|
||||||
|
p := make(map[string]interface{})
|
||||||
|
p["pattern"] = policy.Pattern
|
||||||
|
p["priority"] = policy.Priority
|
||||||
|
p["apply_to"] = policy.ApplyTo
|
||||||
|
|
||||||
|
policyDefinition := make(map[string]interface{})
|
||||||
|
for key, value := range policy.Definition {
|
||||||
|
if v, ok := value.([]interface{}); ok {
|
||||||
|
var nodes []string
|
||||||
|
for _, node := range v {
|
||||||
|
if n, ok := node.(string); ok {
|
||||||
|
nodes = append(nodes, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value = strings.Join(nodes, ",")
|
||||||
|
}
|
||||||
|
policyDefinition[key] = value
|
||||||
|
}
|
||||||
|
p["definition"] = policyDefinition
|
||||||
|
setPolicy[0] = p
|
||||||
|
|
||||||
|
d.Set("policy", setPolicy)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdatePolicy(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
rmqc := meta.(*rabbithole.Client)
|
||||||
|
|
||||||
|
policyId := strings.Split(d.Id(), "@")
|
||||||
|
if len(policyId) < 2 {
|
||||||
|
return fmt.Errorf("Unable to determine policy ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
user := policyId[0]
|
||||||
|
vhost := policyId[1]
|
||||||
|
|
||||||
|
if d.HasChange("policy") {
|
||||||
|
_, newPolicy := d.GetChange("policy")
|
||||||
|
|
||||||
|
policyList := newPolicy.([]interface{})
|
||||||
|
policyMap, ok := policyList[0].(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Unable to parse policy")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := putPolicy(rmqc, user, vhost, policyMap); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ReadPolicy(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeletePolicy(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
rmqc := meta.(*rabbithole.Client)
|
||||||
|
|
||||||
|
policyId := strings.Split(d.Id(), "@")
|
||||||
|
if len(policyId) < 2 {
|
||||||
|
return fmt.Errorf("Unable to determine policy ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
user := policyId[0]
|
||||||
|
vhost := policyId[1]
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Attempting to delete policy for %s", d.Id())
|
||||||
|
|
||||||
|
resp, err := rmqc.DeletePolicy(vhost, user)
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Policy delete response: %#v", resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == 404 {
|
||||||
|
// the policy was automatically deleted
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
return fmt.Errorf("Error deleting RabbitMQ policy: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func putPolicy(rmqc *rabbithole.Client, vhost string, name string, policyMap map[string]interface{}) error {
|
||||||
|
policy := rabbithole.Policy{}
|
||||||
|
policy.Vhost = vhost
|
||||||
|
policy.Name = name
|
||||||
|
|
||||||
|
if v, ok := policyMap["pattern"].(string); ok {
|
||||||
|
policy.Pattern = v
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := policyMap["priority"].(int); ok {
|
||||||
|
policy.Priority = v
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := policyMap["apply_to"].(string); ok {
|
||||||
|
policy.ApplyTo = v
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := policyMap["definition"].(map[string]interface{}); ok {
|
||||||
|
// special case for ha-mode = nodes
|
||||||
|
if x, ok := v["ha-mode"]; ok && x == "nodes" {
|
||||||
|
var nodes rabbithole.NodeNames
|
||||||
|
nodes = strings.Split(v["ha-params"].(string), ",")
|
||||||
|
v["ha-params"] = nodes
|
||||||
|
}
|
||||||
|
policyDefinition := rabbithole.PolicyDefinition{}
|
||||||
|
policyDefinition = v
|
||||||
|
policy.Definition = policyDefinition
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Attempting to declare policy for %s@%s: %#v", name, vhost, policy)
|
||||||
|
|
||||||
|
resp, err := rmqc.PutPolicy(vhost, name, policy)
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Policy declare response: %#v", resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
return fmt.Errorf("Error declaring RabbitMQ policy: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,141 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/michaelklishin/rabbit-hole"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccPolicy(t *testing.T) {
|
||||||
|
var policy rabbithole.Policy
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccPolicyCheckDestroy(&policy),
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccPolicyConfig_basic,
|
||||||
|
Check: testAccPolicyCheck(
|
||||||
|
"rabbitmq_policy.test", &policy,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccPolicyConfig_update,
|
||||||
|
Check: testAccPolicyCheck(
|
||||||
|
"rabbitmq_policy.test", &policy,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccPolicyCheck(rn string, policy *rabbithole.Policy) 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("policy id not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
rmqc := testAccProvider.Meta().(*rabbithole.Client)
|
||||||
|
policyParts := strings.Split(rs.Primary.ID, "@")
|
||||||
|
|
||||||
|
policies, err := rmqc.ListPolicies()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error retrieving policies: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range policies {
|
||||||
|
if p.Name == policyParts[0] && p.Vhost == policyParts[1] {
|
||||||
|
policy = &p
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("Unable to find policy %s", rn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccPolicyCheckDestroy(policy *rabbithole.Policy) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rmqc := testAccProvider.Meta().(*rabbithole.Client)
|
||||||
|
|
||||||
|
policies, err := rmqc.ListPolicies()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error retrieving policies: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range policies {
|
||||||
|
if p.Name == policy.Name && p.Vhost == policy.Vhost {
|
||||||
|
return fmt.Errorf("Policy %s@%s still exist", policy.Name, policy.Vhost)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccPolicyConfig_basic = `
|
||||||
|
resource "rabbitmq_vhost" "test" {
|
||||||
|
name = "test"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_permissions" "guest" {
|
||||||
|
user = "guest"
|
||||||
|
vhost = "${rabbitmq_vhost.test.name}"
|
||||||
|
permissions {
|
||||||
|
configure = ".*"
|
||||||
|
write = ".*"
|
||||||
|
read = ".*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_policy" "test" {
|
||||||
|
name = "test"
|
||||||
|
vhost = "${rabbitmq_permissions.guest.vhost}"
|
||||||
|
policy {
|
||||||
|
pattern = ".*"
|
||||||
|
priority = 0
|
||||||
|
apply_to = "all"
|
||||||
|
definition {
|
||||||
|
ha-mode = "nodes"
|
||||||
|
ha-params = "a,b,c"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
const testAccPolicyConfig_update = `
|
||||||
|
resource "rabbitmq_vhost" "test" {
|
||||||
|
name = "test"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_permissions" "guest" {
|
||||||
|
user = "guest"
|
||||||
|
vhost = "${rabbitmq_vhost.test.name}"
|
||||||
|
permissions {
|
||||||
|
configure = ".*"
|
||||||
|
write = ".*"
|
||||||
|
read = ".*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_policy" "test" {
|
||||||
|
name = "test"
|
||||||
|
vhost = "${rabbitmq_permissions.guest.vhost}"
|
||||||
|
policy {
|
||||||
|
pattern = ".*"
|
||||||
|
priority = 0
|
||||||
|
apply_to = "all"
|
||||||
|
definition {
|
||||||
|
ha-mode = "all"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}`
|
|
@ -0,0 +1,174 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/michaelklishin/rabbit-hole"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceUser() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: CreateUser,
|
||||||
|
Update: UpdateUser,
|
||||||
|
Read: ReadUser,
|
||||||
|
Delete: DeleteUser,
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"password": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Sensitive: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"tags": &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Required: true,
|
||||||
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateUser(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
rmqc := meta.(*rabbithole.Client)
|
||||||
|
|
||||||
|
name := d.Get("name").(string)
|
||||||
|
|
||||||
|
var tagList []string
|
||||||
|
for _, v := range d.Get("tags").([]interface{}) {
|
||||||
|
tagList = append(tagList, v.(string))
|
||||||
|
}
|
||||||
|
tags := strings.Join(tagList, ",")
|
||||||
|
|
||||||
|
userSettings := rabbithole.UserSettings{
|
||||||
|
Password: d.Get("password").(string),
|
||||||
|
Tags: tags,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Attempting to create user %s", name)
|
||||||
|
|
||||||
|
resp, err := rmqc.PutUser(name, userSettings)
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: user creation response: %#v", resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
return fmt.Errorf("Error creating RabbitMQ user: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(name)
|
||||||
|
|
||||||
|
return ReadUser(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadUser(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
rmqc := meta.(*rabbithole.Client)
|
||||||
|
|
||||||
|
user, err := rmqc.GetUser(d.Id())
|
||||||
|
if err != nil {
|
||||||
|
return checkDeleted(d, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: User retrieved: %#v", user)
|
||||||
|
|
||||||
|
d.Set("name", user.Name)
|
||||||
|
|
||||||
|
tags := strings.Split(user.Tags, ",")
|
||||||
|
d.Set("tags", tags)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateUser(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
rmqc := meta.(*rabbithole.Client)
|
||||||
|
|
||||||
|
name := d.Id()
|
||||||
|
|
||||||
|
if d.HasChange("password") {
|
||||||
|
_, newPassword := d.GetChange("password")
|
||||||
|
|
||||||
|
userSettings := rabbithole.UserSettings{
|
||||||
|
Password: newPassword.(string),
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Attempting to update password for %s", name)
|
||||||
|
|
||||||
|
resp, err := rmqc.PutUser(name, userSettings)
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Password update response: %#v", resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
return fmt.Errorf("Error updating RabbitMQ user: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("tags") {
|
||||||
|
_, newTags := d.GetChange("tags")
|
||||||
|
|
||||||
|
var tagList []string
|
||||||
|
for _, v := range newTags.([]interface{}) {
|
||||||
|
tagList = append(tagList, v.(string))
|
||||||
|
}
|
||||||
|
tags := strings.Join(tagList, ",")
|
||||||
|
|
||||||
|
userSettings := rabbithole.UserSettings{
|
||||||
|
Tags: tags,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Attempting to update tags for %s", name)
|
||||||
|
|
||||||
|
resp, err := rmqc.PutUser(name, userSettings)
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Tags update response: %#v", resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
return fmt.Errorf("Error updating RabbitMQ user: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return ReadUser(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteUser(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
rmqc := meta.(*rabbithole.Client)
|
||||||
|
|
||||||
|
name := d.Id()
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Attempting to delete user %s", name)
|
||||||
|
|
||||||
|
resp, err := rmqc.DeleteUser(name)
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: User delete response: %#v", resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == 404 {
|
||||||
|
// the user was automatically deleted
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
return fmt.Errorf("Error deleting RabbitMQ user: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/michaelklishin/rabbit-hole"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccUser(t *testing.T) {
|
||||||
|
var user string
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccUserCheckDestroy(user),
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccUserConfig_basic,
|
||||||
|
Check: testAccUserCheck(
|
||||||
|
"rabbitmq_user.test", &user,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccUserConfig_update,
|
||||||
|
Check: testAccUserCheck(
|
||||||
|
"rabbitmq_user.test", &user,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccUserCheck(rn string, name *string) 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("user id not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
rmqc := testAccProvider.Meta().(*rabbithole.Client)
|
||||||
|
users, err := rmqc.ListUsers()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error retrieving users: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
if user.Name == rs.Primary.ID {
|
||||||
|
*name = rs.Primary.ID
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("Unable to find user %s", rn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccUserCheckDestroy(name string) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rmqc := testAccProvider.Meta().(*rabbithole.Client)
|
||||||
|
users, err := rmqc.ListUsers()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error retrieving users: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
if user.Name == name {
|
||||||
|
return fmt.Errorf("user still exists: %s", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccUserConfig_basic = `
|
||||||
|
resource "rabbitmq_user" "test" {
|
||||||
|
name = "mctest"
|
||||||
|
password = "foobar"
|
||||||
|
tags = ["administrator", "management"]
|
||||||
|
}`
|
||||||
|
|
||||||
|
const testAccUserConfig_update = `
|
||||||
|
resource "rabbitmq_user" "test" {
|
||||||
|
name = "mctest"
|
||||||
|
password = "foobarry"
|
||||||
|
tags = ["management"]
|
||||||
|
}`
|
|
@ -0,0 +1,85 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/michaelklishin/rabbit-hole"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceVhost() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: CreateVhost,
|
||||||
|
Read: ReadVhost,
|
||||||
|
Delete: DeleteVhost,
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateVhost(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
rmqc := meta.(*rabbithole.Client)
|
||||||
|
|
||||||
|
vhost := d.Get("name").(string)
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Attempting to create vhost %s", vhost)
|
||||||
|
|
||||||
|
resp, err := rmqc.PutVhost(vhost, rabbithole.VhostSettings{})
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: vhost creation response: %#v", resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(vhost)
|
||||||
|
|
||||||
|
return ReadVhost(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadVhost(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
rmqc := meta.(*rabbithole.Client)
|
||||||
|
|
||||||
|
vhost, err := rmqc.GetVhost(d.Id())
|
||||||
|
if err != nil {
|
||||||
|
return checkDeleted(d, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Vhost retrieved: %#v", vhost)
|
||||||
|
|
||||||
|
d.Set("name", vhost.Name)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteVhost(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
rmqc := meta.(*rabbithole.Client)
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: Attempting to delete vhost %s", d.Id())
|
||||||
|
|
||||||
|
resp, err := rmqc.DeleteVhost(d.Id())
|
||||||
|
log.Printf("[DEBUG] RabbitMQ: vhost deletion response: %#v", resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == 404 {
|
||||||
|
// the vhost was automatically deleted
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
return fmt.Errorf("Error deleting RabbitMQ user: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/michaelklishin/rabbit-hole"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccVhost(t *testing.T) {
|
||||||
|
var vhost string
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccVhostCheckDestroy(vhost),
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccVhostConfig_basic,
|
||||||
|
Check: testAccVhostCheck(
|
||||||
|
"rabbitmq_vhost.test", &vhost,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccVhostCheck(rn string, name *string) 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("vhost id not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
rmqc := testAccProvider.Meta().(*rabbithole.Client)
|
||||||
|
vhosts, err := rmqc.ListVhosts()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error retrieving vhosts: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, vhost := range vhosts {
|
||||||
|
if vhost.Name == rs.Primary.ID {
|
||||||
|
*name = rs.Primary.ID
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("Unable to find vhost %s", rn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccVhostCheckDestroy(name string) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rmqc := testAccProvider.Meta().(*rabbithole.Client)
|
||||||
|
vhosts, err := rmqc.ListVhosts()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error retrieving vhosts: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, vhost := range vhosts {
|
||||||
|
if vhost.Name == name {
|
||||||
|
return fmt.Errorf("vhost still exists: %s", vhost)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccVhostConfig_basic = `
|
||||||
|
resource "rabbitmq_vhost" "test" {
|
||||||
|
name = "test"
|
||||||
|
}`
|
|
@ -0,0 +1,14 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func checkDeleted(d *schema.ResourceData, err error) error {
|
||||||
|
if err.Error() == "not found" {
|
||||||
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
|
@ -38,6 +38,7 @@ import (
|
||||||
packetprovider "github.com/hashicorp/terraform/builtin/providers/packet"
|
packetprovider "github.com/hashicorp/terraform/builtin/providers/packet"
|
||||||
postgresqlprovider "github.com/hashicorp/terraform/builtin/providers/postgresql"
|
postgresqlprovider "github.com/hashicorp/terraform/builtin/providers/postgresql"
|
||||||
powerdnsprovider "github.com/hashicorp/terraform/builtin/providers/powerdns"
|
powerdnsprovider "github.com/hashicorp/terraform/builtin/providers/powerdns"
|
||||||
|
rabbitmqprovider "github.com/hashicorp/terraform/builtin/providers/rabbitmq"
|
||||||
randomprovider "github.com/hashicorp/terraform/builtin/providers/random"
|
randomprovider "github.com/hashicorp/terraform/builtin/providers/random"
|
||||||
rundeckprovider "github.com/hashicorp/terraform/builtin/providers/rundeck"
|
rundeckprovider "github.com/hashicorp/terraform/builtin/providers/rundeck"
|
||||||
scalewayprovider "github.com/hashicorp/terraform/builtin/providers/scaleway"
|
scalewayprovider "github.com/hashicorp/terraform/builtin/providers/scaleway"
|
||||||
|
@ -93,6 +94,7 @@ var InternalProviders = map[string]plugin.ProviderFunc{
|
||||||
"packet": packetprovider.Provider,
|
"packet": packetprovider.Provider,
|
||||||
"postgresql": postgresqlprovider.Provider,
|
"postgresql": postgresqlprovider.Provider,
|
||||||
"powerdns": powerdnsprovider.Provider,
|
"powerdns": powerdnsprovider.Provider,
|
||||||
|
"rabbitmq": rabbitmqprovider.Provider,
|
||||||
"random": randomprovider.Provider,
|
"random": randomprovider.Provider,
|
||||||
"rundeck": rundeckprovider.Provider,
|
"rundeck": rundeckprovider.Provider,
|
||||||
"scaleway": scalewayprovider.Provider,
|
"scaleway": scalewayprovider.Provider,
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
The workflow is pretty standard:
|
||||||
|
|
||||||
|
1. Fork it
|
||||||
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
||||||
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
||||||
|
4. Push to the branch (`git push -u origin my-new-feature`)
|
||||||
|
5. Create new Pull Request
|
||||||
|
|
||||||
|
## Running Tests
|
||||||
|
|
||||||
|
First run `bin/ci/before_build.sh` that will create a vhost and user(s) needed
|
||||||
|
by the test suite.
|
||||||
|
|
||||||
|
The project uses [Ginkgo](http://onsi.github.io/ginkgo/) and [Gomega](https://github.com/onsi/gomega).
|
||||||
|
|
||||||
|
To clone dependencies and run tests, use `make`. It is also possible
|
||||||
|
to use the brilliant [Ginkgo CLI runner](http://onsi.github.io/ginkgo/#the-ginkgo-cli) e.g.
|
||||||
|
to only run a subset of tests.
|
|
@ -0,0 +1,32 @@
|
||||||
|
## Changes Between 1.0.0 and 1.1.0 (unreleased)
|
||||||
|
|
||||||
|
### More Complete Message Stats Information
|
||||||
|
|
||||||
|
Message stats now include fields such as `deliver_get` and `redeliver`.
|
||||||
|
|
||||||
|
GH issue: [#73](https://github.com/michaelklishin/rabbit-hole/pull/73).
|
||||||
|
|
||||||
|
Contributed by Edward Wilde.
|
||||||
|
|
||||||
|
|
||||||
|
## 1.0 (first tagged release, Dec 25th, 2015)
|
||||||
|
|
||||||
|
### TLS Support
|
||||||
|
|
||||||
|
`rabbithole.NewTLSClient` is a new function which works
|
||||||
|
much like `NewClient` but additionally accepts a transport.
|
||||||
|
|
||||||
|
Contributed by @[GrimTheReaper](https://github.com/GrimTheReaper).
|
||||||
|
|
||||||
|
### Federation Support
|
||||||
|
|
||||||
|
It is now possible to create federation links
|
||||||
|
over HTTP API.
|
||||||
|
|
||||||
|
Contributed by [Ryan Grenz](https://github.com/grenzr-bskyb).
|
||||||
|
|
||||||
|
### Core Operations Support
|
||||||
|
|
||||||
|
Most common HTTP API operations (listing and management of
|
||||||
|
vhosts, users, permissions, queues, exchanges, and bindings)
|
||||||
|
are supported by the client.
|
|
@ -0,0 +1,23 @@
|
||||||
|
Copyright (c) 2013, Michael Klishin
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
Redistributions in binary form must reproduce the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,26 @@
|
||||||
|
export GOPATH := $(CURDIR)
|
||||||
|
|
||||||
|
COVER_FILE := coverage
|
||||||
|
|
||||||
|
all: test
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
|
||||||
|
test: install-dependencies
|
||||||
|
go test -v
|
||||||
|
|
||||||
|
cover: install-dependencies install-cover
|
||||||
|
go test -v -test.coverprofile="$(COVER_FILE).prof"
|
||||||
|
sed -i.bak 's|_'$(GOPATH)'|.|g' $(COVER_FILE).prof
|
||||||
|
go tool cover -html=$(COVER_FILE).prof -o $(COVER_FILE).html
|
||||||
|
rm $(COVER_FILE).prof*
|
||||||
|
|
||||||
|
install-cover:
|
||||||
|
go get code.google.com/p/go.tools/cmd/cover
|
||||||
|
|
||||||
|
install-dependencies:
|
||||||
|
go get github.com/onsi/ginkgo
|
||||||
|
go get github.com/onsi/gomega
|
||||||
|
go get github.com/streadway/amqp
|
||||||
|
# to get Ginkgo CLI
|
||||||
|
go install github.com/onsi/ginkgo/ginkgo
|
|
@ -0,0 +1,296 @@
|
||||||
|
# Rabbit Hole, a RabbitMQ HTTP API Client for Go
|
||||||
|
|
||||||
|
This library is a [RabbitMQ HTTP API](https://raw.githack.com/rabbitmq/rabbitmq-management/rabbitmq_v3_6_0/priv/www/api/index.html) client for the Go language.
|
||||||
|
|
||||||
|
## Supported Go Versions
|
||||||
|
|
||||||
|
Rabbit Hole requires Go 1.3+.
|
||||||
|
|
||||||
|
|
||||||
|
## Supported RabbitMQ Versions
|
||||||
|
|
||||||
|
* RabbitMQ 3.x
|
||||||
|
|
||||||
|
All versions require [RabbitMQ Management UI plugin](http://www.rabbitmq.com/management.html) to be installed and enabled.
|
||||||
|
|
||||||
|
|
||||||
|
## Project Maturity
|
||||||
|
|
||||||
|
Rabbit Hole is a fairly mature library (started in October 2013)
|
||||||
|
designed after a couple of other RabbitMQ HTTP API clients with stable
|
||||||
|
APIs. Breaking API changes are not out of the question but not without
|
||||||
|
a reasonable version bump.
|
||||||
|
|
||||||
|
It is largely (80-90%) feature complete and decently documented.
|
||||||
|
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```
|
||||||
|
go get github.com/michaelklishin/rabbit-hole
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
### Overview
|
||||||
|
|
||||||
|
To import the package:
|
||||||
|
|
||||||
|
``` go
|
||||||
|
import (
|
||||||
|
"github.com/michaelklishin/rabbit-hole"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
All HTTP API operations are accessible via `rabbithole.Client`, which
|
||||||
|
should be instantiated with `rabbithole.NewClient`:
|
||||||
|
|
||||||
|
``` go
|
||||||
|
// URI, username, password
|
||||||
|
rmqc, _ = NewClient("http://127.0.0.1:15672", "guest", "guest")
|
||||||
|
```
|
||||||
|
|
||||||
|
SSL/TSL is now available, by adding a Transport Layer to the parameters
|
||||||
|
of `rabbithole.NewTLSClient`:
|
||||||
|
``` go
|
||||||
|
transport := &http.Transport{TLSClientConfig: tlsConfig}
|
||||||
|
rmqc, _ := NewTLSClient("https://127.0.0.1:15672", "guest", "guest", transport)
|
||||||
|
```
|
||||||
|
However, RabbitMQ-Management does not have SSL/TLS enabled by default,
|
||||||
|
so you must enable it.
|
||||||
|
|
||||||
|
[API reference](http://godoc.org/github.com/michaelklishin/rabbit-hole) is available on [godoc.org](http://godoc.org).
|
||||||
|
|
||||||
|
|
||||||
|
### Getting Overview
|
||||||
|
|
||||||
|
``` go
|
||||||
|
res, err := rmqc.Overview()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Node and Cluster Status
|
||||||
|
|
||||||
|
``` go
|
||||||
|
xs, err := rmqc.ListNodes()
|
||||||
|
// => []NodeInfo, err
|
||||||
|
|
||||||
|
node, err := rmqc.GetNode("rabbit@mercurio")
|
||||||
|
// => NodeInfo, err
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Operations on Connections
|
||||||
|
|
||||||
|
``` go
|
||||||
|
xs, err := rmqc.ListConnections()
|
||||||
|
// => []ConnectionInfo, err
|
||||||
|
|
||||||
|
conn, err := rmqc.GetConnection("127.0.0.1:50545 -> 127.0.0.1:5672")
|
||||||
|
// => ConnectionInfo, err
|
||||||
|
|
||||||
|
// Forcefully close connection
|
||||||
|
_, err := rmqc.CloseConnection("127.0.0.1:50545 -> 127.0.0.1:5672")
|
||||||
|
// => *http.Response, err
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Operations on Channels
|
||||||
|
|
||||||
|
``` go
|
||||||
|
xs, err := rmqc.ListChannels()
|
||||||
|
// => []ChannelInfo, err
|
||||||
|
|
||||||
|
ch, err := rmqc.GetChannel("127.0.0.1:50545 -> 127.0.0.1:5672 (1)")
|
||||||
|
// => ChannelInfo, err
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Operations on Vhosts
|
||||||
|
|
||||||
|
``` go
|
||||||
|
xs, err := rmqc.ListVhosts()
|
||||||
|
// => []VhostInfo, err
|
||||||
|
|
||||||
|
// information about individual vhost
|
||||||
|
x, err := rmqc.GetVhost("/")
|
||||||
|
// => VhostInfo, err
|
||||||
|
|
||||||
|
// creates or updates individual vhost
|
||||||
|
resp, err := rmqc.PutVhost("/", VhostSettings{Tracing: false})
|
||||||
|
// => *http.Response, err
|
||||||
|
|
||||||
|
// deletes individual vhost
|
||||||
|
resp, err := rmqc.DeleteVhost("/")
|
||||||
|
// => *http.Response, err
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Managing Users
|
||||||
|
|
||||||
|
``` go
|
||||||
|
xs, err := rmqc.ListUsers()
|
||||||
|
// => []UserInfo, err
|
||||||
|
|
||||||
|
// information about individual user
|
||||||
|
x, err := rmqc.GetUser("my.user")
|
||||||
|
// => UserInfo, err
|
||||||
|
|
||||||
|
// creates or updates individual user
|
||||||
|
resp, err := rmqc.PutUser("my.user", UserSettings{Password: "s3krE7", Tags: "management,policymaker"})
|
||||||
|
// => *http.Response, err
|
||||||
|
|
||||||
|
// deletes individual user
|
||||||
|
resp, err := rmqc.DeleteUser("my.user")
|
||||||
|
// => *http.Response, err
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Managing Permissions
|
||||||
|
|
||||||
|
``` go
|
||||||
|
xs, err := rmqc.ListPermissions()
|
||||||
|
// => []PermissionInfo, err
|
||||||
|
|
||||||
|
// permissions of individual user
|
||||||
|
x, err := rmqc.ListPermissionsOf("my.user")
|
||||||
|
// => []PermissionInfo, err
|
||||||
|
|
||||||
|
// permissions of individual user in vhost
|
||||||
|
x, err := rmqc.GetPermissionsIn("/", "my.user")
|
||||||
|
// => PermissionInfo, err
|
||||||
|
|
||||||
|
// updates permissions of user in vhost
|
||||||
|
resp, err := rmqc.UpdatePermissionsIn("/", "my.user", Permissions{Configure: ".*", Write: ".*", Read: ".*"})
|
||||||
|
// => *http.Response, err
|
||||||
|
|
||||||
|
// revokes permissions in vhost
|
||||||
|
resp, err := rmqc.ClearPermissionsIn("/", "my.user")
|
||||||
|
// => *http.Response, err
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Operations on Exchanges
|
||||||
|
|
||||||
|
``` go
|
||||||
|
xs, err := rmqc.ListExchanges()
|
||||||
|
// => []ExchangeInfo, err
|
||||||
|
|
||||||
|
// list exchanges in a vhost
|
||||||
|
xs, err := rmqc.ListExchangesIn("/")
|
||||||
|
// => []ExchangeInfo, err
|
||||||
|
|
||||||
|
// information about individual exchange
|
||||||
|
x, err := rmqc.GetExchange("/", "amq.fanout")
|
||||||
|
// => ExchangeInfo, err
|
||||||
|
|
||||||
|
// declares an exchange
|
||||||
|
resp, err := rmqc.DeclareExchange("/", "an.exchange", ExchangeSettings{Type: "fanout", Durable: false})
|
||||||
|
// => *http.Response, err
|
||||||
|
|
||||||
|
// deletes individual exchange
|
||||||
|
resp, err := rmqc.DeleteExchange("/", "an.exchange")
|
||||||
|
// => *http.Response, err
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Operations on Queues
|
||||||
|
|
||||||
|
``` go
|
||||||
|
qs, err := rmqc.ListQueues()
|
||||||
|
// => []QueueInfo, err
|
||||||
|
|
||||||
|
// list queues in a vhost
|
||||||
|
qs, err := rmqc.ListQueuesIn("/")
|
||||||
|
// => []QueueInfo, err
|
||||||
|
|
||||||
|
// information about individual queue
|
||||||
|
q, err := rmqc.GetQueue("/", "a.queue")
|
||||||
|
// => QueueInfo, err
|
||||||
|
|
||||||
|
// declares a queue
|
||||||
|
resp, err := rmqc.DeclareQueue("/", "a.queue", QueueSettings{Durable: false})
|
||||||
|
// => *http.Response, err
|
||||||
|
|
||||||
|
// deletes individual queue
|
||||||
|
resp, err := rmqc.DeleteQueue("/", "a.queue")
|
||||||
|
// => *http.Response, err
|
||||||
|
|
||||||
|
// purges all messages in queue
|
||||||
|
resp, err := rmqc.PurgeQueue("/", "a.queue")
|
||||||
|
// => *http.Response, err
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Operations on Bindings
|
||||||
|
|
||||||
|
``` go
|
||||||
|
bs, err := rmqc.ListBindings()
|
||||||
|
// => []BindingInfo, err
|
||||||
|
|
||||||
|
// list bindings in a vhost
|
||||||
|
bs, err := rmqc.ListBindingsIn("/")
|
||||||
|
// => []BindingInfo, err
|
||||||
|
|
||||||
|
// list bindings of a queue
|
||||||
|
bs, err := rmqc.ListQueueBindings("/", "a.queue")
|
||||||
|
// => []BindingInfo, err
|
||||||
|
|
||||||
|
// declare a binding
|
||||||
|
resp, err := rmqc.DeclareBinding("/", BindingInfo{
|
||||||
|
Source: "an.exchange",
|
||||||
|
Destination: "a.queue",
|
||||||
|
DestinationType: "queue",
|
||||||
|
RoutingKey: "#",
|
||||||
|
})
|
||||||
|
// => *http.Response, err
|
||||||
|
|
||||||
|
// deletes individual binding
|
||||||
|
resp, err := rmqc.DeleteBinding("/", BindingInfo{
|
||||||
|
Source: "an.exchange",
|
||||||
|
Destination: "a.queue",
|
||||||
|
DestinationType: "queue",
|
||||||
|
RoutingKey: "#",
|
||||||
|
PropertiesKey: "%23",
|
||||||
|
})
|
||||||
|
// => *http.Response, err
|
||||||
|
```
|
||||||
|
|
||||||
|
### HTTPS Connections
|
||||||
|
|
||||||
|
``` go
|
||||||
|
var tlsConfig *tls.Config
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
transport := &http.Transport{TLSClientConfig: tlsConfig}
|
||||||
|
|
||||||
|
rmqc, err := NewTLSClient("https://127.0.0.1:15672", "guest", "guest", transport)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Changing Transport Layer
|
||||||
|
|
||||||
|
``` go
|
||||||
|
var transport *http.Transport
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
rmqc.SetTransport(transport)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## CI Status
|
||||||
|
|
||||||
|
[![Build Status](https://travis-ci.org/michaelklishin/rabbit-hole.svg?branch=master)](https://travis-ci.org/michaelklishin/rabbit-hole)
|
||||||
|
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
See [CONTRIBUTING.md](https://github.com/michaelklishin/rabbit-hole/blob/master/CONTRIBUTING.md)
|
||||||
|
|
||||||
|
|
||||||
|
## License & Copyright
|
||||||
|
|
||||||
|
2-clause BSD license.
|
||||||
|
|
||||||
|
(c) Michael S. Klishin, 2013-2016.
|
|
@ -0,0 +1,157 @@
|
||||||
|
package rabbithole
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/bindings
|
||||||
|
//
|
||||||
|
|
||||||
|
// Example response:
|
||||||
|
//
|
||||||
|
// [
|
||||||
|
// {
|
||||||
|
// "source": "",
|
||||||
|
// "vhost": "\/",
|
||||||
|
// "destination": "amq.gen-Dzw36tPTm_VsmILY9oTG9w",
|
||||||
|
// "destination_type": "queue",
|
||||||
|
// "routing_key": "amq.gen-Dzw36tPTm_VsmILY9oTG9w",
|
||||||
|
// "arguments": {
|
||||||
|
//
|
||||||
|
// },
|
||||||
|
// "properties_key": "amq.gen-Dzw36tPTm_VsmILY9oTG9w"
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
|
||||||
|
type BindingInfo struct {
|
||||||
|
// Binding source (exchange name)
|
||||||
|
Source string `json:"source"`
|
||||||
|
Vhost string `json:"vhost"`
|
||||||
|
// Binding destination (queue or exchange name)
|
||||||
|
Destination string `json:"destination"`
|
||||||
|
// Destination type, either "queue" or "exchange"
|
||||||
|
DestinationType string `json:"destination_type"`
|
||||||
|
RoutingKey string `json:"routing_key"`
|
||||||
|
Arguments map[string]interface{} `json:"arguments"`
|
||||||
|
PropertiesKey string `json:"properties_key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns all bindings
|
||||||
|
func (c *Client) ListBindings() (rec []BindingInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "bindings/")
|
||||||
|
if err != nil {
|
||||||
|
return []BindingInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return []BindingInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/bindings/{vhost}
|
||||||
|
//
|
||||||
|
|
||||||
|
// Returns all bindings in a virtual host.
|
||||||
|
func (c *Client) ListBindingsIn(vhost string) (rec []BindingInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "bindings/"+url.QueryEscape(vhost))
|
||||||
|
if err != nil {
|
||||||
|
return []BindingInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return []BindingInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/queues/{vhost}/{queue}/bindings
|
||||||
|
//
|
||||||
|
|
||||||
|
// Example response:
|
||||||
|
// [
|
||||||
|
// {"source":"",
|
||||||
|
// "vhost":"/",
|
||||||
|
// "destination":"amq.gen-H0tnavWatL7g7uU2q5cAPA",
|
||||||
|
// "destination_type":"queue",
|
||||||
|
// "routing_key":"amq.gen-H0tnavWatL7g7uU2q5cAPA",
|
||||||
|
// "arguments":{},
|
||||||
|
// "properties_key":"amq.gen-H0tnavWatL7g7uU2q5cAPA"},
|
||||||
|
// {"source":"temp",
|
||||||
|
// "vhost":"/",
|
||||||
|
// "destination":"amq.gen-H0tnavWatL7g7uU2q5cAPA",
|
||||||
|
// "destination_type":"queue",
|
||||||
|
// "routing_key":"",
|
||||||
|
// "arguments":{},
|
||||||
|
// "properties_key":"~"}
|
||||||
|
// ]
|
||||||
|
|
||||||
|
// Returns all bindings of individual queue.
|
||||||
|
func (c *Client) ListQueueBindings(vhost, queue string) (rec []BindingInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "queues/"+url.QueryEscape(vhost)+"/"+url.QueryEscape(queue)+"/bindings")
|
||||||
|
if err != nil {
|
||||||
|
return []BindingInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return []BindingInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POST /api/bindings/{vhost}/e/{source}/{destination_type}/{destination}
|
||||||
|
//
|
||||||
|
|
||||||
|
// DeclareBinding updates information about a binding between a source and a target
|
||||||
|
func (c *Client) DeclareBinding(vhost string, info BindingInfo) (res *http.Response, err error) {
|
||||||
|
info.Vhost = vhost
|
||||||
|
|
||||||
|
if info.Arguments == nil {
|
||||||
|
info.Arguments = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
body, err := json.Marshal(info)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := newRequestWithBody(c, "POST", "bindings/"+url.QueryEscape(vhost)+"/e/"+url.QueryEscape(info.Source)+"/"+url.QueryEscape(string(info.DestinationType[0]))+"/"+url.QueryEscape(info.Destination), body)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = executeRequest(c, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// DELETE /api/bindings/{vhost}/e/{source}/{destination_type}/{destination}/{props}
|
||||||
|
//
|
||||||
|
|
||||||
|
// DeleteBinding delets an individual binding
|
||||||
|
func (c *Client) DeleteBinding(vhost string, info BindingInfo) (res *http.Response, err error) {
|
||||||
|
req, err := newRequestWithBody(c, "DELETE", "bindings/"+url.QueryEscape(vhost)+"/e/"+url.QueryEscape(info.Source)+"/"+url.QueryEscape(string(info.DestinationType[0]))+"/"+url.QueryEscape(info.Destination)+"/"+url.QueryEscape(info.PropertiesKey), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = executeRequest(c, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
package rabbithole
|
||||||
|
|
||||||
|
import "net/url"
|
||||||
|
|
||||||
|
// Brief (very incomplete) connection information.
|
||||||
|
type BriefConnectionDetails struct {
|
||||||
|
// Connection name
|
||||||
|
Name string `json:"name"`
|
||||||
|
// Client port
|
||||||
|
PeerPort Port `json:"peer_port"`
|
||||||
|
// Client host
|
||||||
|
PeerHost string `json:"peer_host"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChannelInfo struct {
|
||||||
|
// Channel number
|
||||||
|
Number int `json:"number"`
|
||||||
|
// Channel name
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// basic.qos (prefetch count) value used
|
||||||
|
PrefetchCount int `json:"prefetch_count"`
|
||||||
|
// How many consumers does this channel have
|
||||||
|
ConsumerCount int `json:"consumer_count"`
|
||||||
|
|
||||||
|
// Number of unacknowledged messages on this channel
|
||||||
|
UnacknowledgedMessageCount int `json:"messages_unacknowledged"`
|
||||||
|
// Number of messages on this channel unconfirmed to publishers
|
||||||
|
UnconfirmedMessageCount int `json:"messages_unconfirmed"`
|
||||||
|
// Number of messages on this channel uncommited to message store
|
||||||
|
UncommittedMessageCount int `json:"messages_uncommitted"`
|
||||||
|
// Number of acks on this channel uncommited to message store
|
||||||
|
UncommittedAckCount int `json:"acks_uncommitted"`
|
||||||
|
|
||||||
|
// TODO(mk): custom deserializer to date/time?
|
||||||
|
IdleSince string `json:"idle_since"`
|
||||||
|
|
||||||
|
// True if this channel uses publisher confirms
|
||||||
|
UsesPublisherConfirms bool `json:"confirm"`
|
||||||
|
// True if this channel uses transactions
|
||||||
|
Transactional bool `json:"transactional"`
|
||||||
|
// True if this channel is blocked via channel.flow
|
||||||
|
ClientFlowBlocked bool `json:"client_flow_blocked"`
|
||||||
|
|
||||||
|
User string `json:"user"`
|
||||||
|
Vhost string `json:"vhost"`
|
||||||
|
Node string `json:"node"`
|
||||||
|
|
||||||
|
ConnectionDetails BriefConnectionDetails `json:"connection_details"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/channels
|
||||||
|
//
|
||||||
|
|
||||||
|
// Returns information about all open channels.
|
||||||
|
func (c *Client) ListChannels() (rec []ChannelInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "channels")
|
||||||
|
if err != nil {
|
||||||
|
return []ChannelInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return []ChannelInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/channels/{name}
|
||||||
|
//
|
||||||
|
|
||||||
|
// Returns channel information.
|
||||||
|
func (c *Client) GetChannel(name string) (rec *ChannelInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "channels/"+url.QueryEscape(name))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
|
@ -0,0 +1,132 @@
|
||||||
|
package rabbithole
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
// URI of a RabbitMQ node to use, not including the path, e.g. http://127.0.0.1:15672.
|
||||||
|
Endpoint string
|
||||||
|
// Username to use. This RabbitMQ user must have the "management" tag.
|
||||||
|
Username string
|
||||||
|
// Password to use.
|
||||||
|
Password string
|
||||||
|
host string
|
||||||
|
transport *http.Transport
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient(uri string, username string, password string) (me *Client, err error) {
|
||||||
|
u, err := url.Parse(uri)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
me = &Client{
|
||||||
|
Endpoint: uri,
|
||||||
|
host: u.Host,
|
||||||
|
Username: username,
|
||||||
|
Password: password,
|
||||||
|
}
|
||||||
|
|
||||||
|
return me, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewTLSClient Creates a Client with a Transport Layer; it is up to the developer to make that layer Secure.
|
||||||
|
func NewTLSClient(uri string, username string, password string, transport *http.Transport) (me *Client, err error) {
|
||||||
|
u, err := url.Parse(uri)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
me = &Client{
|
||||||
|
Endpoint: uri,
|
||||||
|
host: u.Host,
|
||||||
|
Username: username,
|
||||||
|
Password: password,
|
||||||
|
transport: transport,
|
||||||
|
}
|
||||||
|
|
||||||
|
return me, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//SetTransport changes the Transport Layer that the Client will use.
|
||||||
|
func (c *Client) SetTransport(transport *http.Transport) {
|
||||||
|
c.transport = transport
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGETRequest(client *Client, path string) (*http.Request, error) {
|
||||||
|
s := client.Endpoint + "/api/" + path
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", s, nil)
|
||||||
|
|
||||||
|
req.Close = true
|
||||||
|
req.SetBasicAuth(client.Username, client.Password)
|
||||||
|
// set Opaque to preserve percent-encoded path. MK.
|
||||||
|
req.URL.Opaque = "//" + client.host + "/api/" + path
|
||||||
|
|
||||||
|
return req, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRequestWithBody(client *Client, method string, path string, body []byte) (*http.Request, error) {
|
||||||
|
s := client.Endpoint + "/api/" + path
|
||||||
|
|
||||||
|
req, err := http.NewRequest(method, s, bytes.NewReader(body))
|
||||||
|
|
||||||
|
req.Close = true
|
||||||
|
req.SetBasicAuth(client.Username, client.Password)
|
||||||
|
// set Opaque to preserve percent-encoded path. MK.
|
||||||
|
req.URL.Opaque = "//" + client.host + "/api/" + path
|
||||||
|
|
||||||
|
req.Header.Add("Content-Type", "application/json")
|
||||||
|
|
||||||
|
return req, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func executeRequest(client *Client, req *http.Request) (res *http.Response, err error) {
|
||||||
|
var httpc *http.Client
|
||||||
|
if client.transport != nil {
|
||||||
|
httpc = &http.Client{Transport: client.transport}
|
||||||
|
} else {
|
||||||
|
httpc = &http.Client{}
|
||||||
|
}
|
||||||
|
res, err = httpc.Do(req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func executeAndParseRequest(client *Client, req *http.Request, rec interface{}) (err error) {
|
||||||
|
var httpc *http.Client
|
||||||
|
if client.transport != nil {
|
||||||
|
httpc = &http.Client{Transport: client.transport}
|
||||||
|
} else {
|
||||||
|
httpc = &http.Client{}
|
||||||
|
}
|
||||||
|
res, err := httpc.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer res.Body.Close() // always close body
|
||||||
|
|
||||||
|
if isNotFound(res) {
|
||||||
|
return errors.New("not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.NewDecoder(res.Body).Decode(&rec)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNotFound(res *http.Response) bool {
|
||||||
|
return res.StatusCode == http.StatusNotFound
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package rabbithole
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
// Extra arguments as a map (on queues, bindings, etc)
|
||||||
|
type Properties map[string]interface{}
|
||||||
|
|
||||||
|
// Port used by RabbitMQ or clients
|
||||||
|
type Port int
|
||||||
|
|
||||||
|
func (p *Port) UnmarshalJSON(b []byte) error {
|
||||||
|
stringValue := string(b)
|
||||||
|
var parsed int64
|
||||||
|
var err error
|
||||||
|
if stringValue[0] == '"' && stringValue[len(stringValue)-1] == '"' {
|
||||||
|
parsed, err = strconv.ParseInt(stringValue[1:len(stringValue)-1], 10, 32)
|
||||||
|
} else {
|
||||||
|
parsed, err = strconv.ParseInt(stringValue, 10, 32)
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
*p = Port(int(parsed))
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rate of change of a numerical value
|
||||||
|
type RateDetails struct {
|
||||||
|
Rate float32 `json:"rate"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RabbitMQ context (Erlang app) running on
|
||||||
|
// a node
|
||||||
|
type BrokerContext struct {
|
||||||
|
Node string `json:"node"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
Port Port `json:"port"`
|
||||||
|
Ignore bool `json:"ignore_in_use"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic published messages statistics
|
||||||
|
type MessageStats struct {
|
||||||
|
Publish int `json:"publish"`
|
||||||
|
PublishDetails RateDetails `json:"publish_details"`
|
||||||
|
Deliver int `json:"deliver"`
|
||||||
|
DeliverDetails RateDetails `json:"deliver_details"`
|
||||||
|
DeliverNoAck int `json:"deliver_noack"`
|
||||||
|
DeliverNoAckDetails RateDetails `json:"deliver_noack_details"`
|
||||||
|
DeliverGet int `json:"deliver_get"`
|
||||||
|
DeliverGetDetails RateDetails `json:"deliver_get_details"`
|
||||||
|
Redeliver int `json:"redeliver"`
|
||||||
|
RedeliverDetails RateDetails `json:"redeliver_details"`
|
||||||
|
Get int `json:"get"`
|
||||||
|
GetDetails RateDetails `json:"get_details"`
|
||||||
|
GetNoAck int `json:"get_no_ack"`
|
||||||
|
GetNoAckDetails RateDetails `json:"get_no_ack_details"`
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
package rabbithole
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Provides information about connection to a RabbitMQ node.
|
||||||
|
type ConnectionInfo struct {
|
||||||
|
// Connection name
|
||||||
|
Name string `json:"name"`
|
||||||
|
// Node the client is connected to
|
||||||
|
Node string `json:"node"`
|
||||||
|
// Number of open channels
|
||||||
|
Channels int `json:"channels"`
|
||||||
|
// Connection state
|
||||||
|
State string `json:"state"`
|
||||||
|
// Connection type, network (via AMQP client) or direct (via direct Erlang client)
|
||||||
|
Type string `json:"type"`
|
||||||
|
|
||||||
|
// Server port
|
||||||
|
Port Port `json:"port"`
|
||||||
|
// Client port
|
||||||
|
PeerPort Port `json:"peer_port"`
|
||||||
|
|
||||||
|
// Server host
|
||||||
|
Host string `json:"host"`
|
||||||
|
// Client host
|
||||||
|
PeerHost string `json:"peer_host"`
|
||||||
|
|
||||||
|
// Last connection blocking reason, if any
|
||||||
|
LastBlockedBy string `json:"last_blocked_by"`
|
||||||
|
// When connection was last blocked
|
||||||
|
LastBlockedAge string `json:"last_blocked_age"`
|
||||||
|
|
||||||
|
// True if connection uses TLS/SSL
|
||||||
|
UsesTLS bool `json:"ssl"`
|
||||||
|
// Client certificate subject
|
||||||
|
PeerCertSubject string `json:"peer_cert_subject"`
|
||||||
|
// Client certificate validity
|
||||||
|
PeerCertValidity string `json:"peer_cert_validity"`
|
||||||
|
// Client certificate issuer
|
||||||
|
PeerCertIssuer string `json:"peer_cert_issuer"`
|
||||||
|
|
||||||
|
// TLS/SSL protocol and version
|
||||||
|
SSLProtocol string `json:"ssl_protocol"`
|
||||||
|
// Key exchange mechanism
|
||||||
|
SSLKeyExchange string `json:"ssl_key_exchange"`
|
||||||
|
// SSL cipher suite used
|
||||||
|
SSLCipher string `json:"ssl_cipher"`
|
||||||
|
// SSL hash
|
||||||
|
SSLHash string `json:"ssl_hash"`
|
||||||
|
|
||||||
|
// Protocol, e.g. AMQP 0-9-1 or MQTT 3-1
|
||||||
|
Protocol string `json:"protocol"`
|
||||||
|
User string `json:"user"`
|
||||||
|
// Virtual host
|
||||||
|
Vhost string `json:"vhost"`
|
||||||
|
|
||||||
|
// Heartbeat timeout
|
||||||
|
Timeout int `json:"timeout"`
|
||||||
|
// Maximum frame size (AMQP 0-9-1)
|
||||||
|
FrameMax int `json:"frame_max"`
|
||||||
|
|
||||||
|
// A map of client properties (name, version, capabilities, etc)
|
||||||
|
ClientProperties Properties `json:"client_properties"`
|
||||||
|
|
||||||
|
// Octets received
|
||||||
|
RecvOct uint64 `json:"recv_oct"`
|
||||||
|
// Octets sent
|
||||||
|
SendOct uint64 `json:"send_oct"`
|
||||||
|
RecvCount uint64 `json:"recv_cnt"`
|
||||||
|
SendCount uint64 `json:"send_cnt"`
|
||||||
|
SendPending uint64 `json:"send_pend"`
|
||||||
|
// Ingress data rate
|
||||||
|
RecvOctDetails RateDetails `json:"recv_oct_details"`
|
||||||
|
// Egress data rate
|
||||||
|
SendOctDetails RateDetails `json:"send_oct_details"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/connections
|
||||||
|
//
|
||||||
|
|
||||||
|
func (c *Client) ListConnections() (rec []ConnectionInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "connections")
|
||||||
|
if err != nil {
|
||||||
|
return []ConnectionInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return []ConnectionInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/connections/{name}
|
||||||
|
//
|
||||||
|
|
||||||
|
func (c *Client) GetConnection(name string) (rec *ConnectionInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "connections/"+url.QueryEscape(name))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// DELETE /api/connections/{name}
|
||||||
|
//
|
||||||
|
|
||||||
|
func (c *Client) CloseConnection(name string) (res *http.Response, err error) {
|
||||||
|
req, err := newRequestWithBody(c, "DELETE", "connections/"+url.QueryEscape(name), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = executeRequest(c, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
|
@ -0,0 +1,177 @@
|
||||||
|
/*
|
||||||
|
Rabbit Hole is a Go client for the RabbitMQ HTTP API.
|
||||||
|
|
||||||
|
All HTTP API operations are accessible via `rabbithole.Client`, which
|
||||||
|
should be instantiated with `rabbithole.NewClient`.
|
||||||
|
|
||||||
|
// URI, username, password
|
||||||
|
rmqc, _ = NewClient("http://127.0.0.1:15672", "guest", "guest")
|
||||||
|
|
||||||
|
Getting Overview
|
||||||
|
|
||||||
|
res, err := rmqc.Overview()
|
||||||
|
|
||||||
|
Node and Cluster Status
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// => []NodeInfo, err
|
||||||
|
xs, err := rmqc.ListNodes()
|
||||||
|
|
||||||
|
node, err := rmqc.GetNode("rabbit@mercurio")
|
||||||
|
// => NodeInfo, err
|
||||||
|
|
||||||
|
Operations on Connections
|
||||||
|
|
||||||
|
xs, err := rmqc.ListConnections()
|
||||||
|
// => []ConnectionInfo, err
|
||||||
|
|
||||||
|
conn, err := rmqc.GetConnection("127.0.0.1:50545 -> 127.0.0.1:5672")
|
||||||
|
// => ConnectionInfo, err
|
||||||
|
|
||||||
|
// Forcefully close connection
|
||||||
|
_, err := rmqc.CloseConnection("127.0.0.1:50545 -> 127.0.0.1:5672")
|
||||||
|
// => *http.Response, err
|
||||||
|
|
||||||
|
Operations on Channels
|
||||||
|
|
||||||
|
xs, err := rmqc.ListChannels()
|
||||||
|
// => []ChannelInfo, err
|
||||||
|
|
||||||
|
ch, err := rmqc.GetChannel("127.0.0.1:50545 -> 127.0.0.1:5672 (1)")
|
||||||
|
// => ChannelInfo, err
|
||||||
|
|
||||||
|
Operations on Exchanges
|
||||||
|
|
||||||
|
xs, err := rmqc.ListExchanges()
|
||||||
|
// => []ExchangeInfo, err
|
||||||
|
|
||||||
|
// list exchanges in a vhost
|
||||||
|
xs, err := rmqc.ListExchangesIn("/")
|
||||||
|
// => []ExchangeInfo, err
|
||||||
|
|
||||||
|
// information about individual exchange
|
||||||
|
x, err := rmqc.GetExchange("/", "amq.fanout")
|
||||||
|
// => ExchangeInfo, err
|
||||||
|
|
||||||
|
// declares an exchange
|
||||||
|
resp, err := rmqc.DeclareExchange("/", "an.exchange", ExchangeSettings{Type: "fanout", Durable: false})
|
||||||
|
// => *http.Response, err
|
||||||
|
|
||||||
|
// deletes individual exchange
|
||||||
|
resp, err := rmqc.DeleteExchange("/", "an.exchange")
|
||||||
|
// => *http.Response, err
|
||||||
|
|
||||||
|
Operations on Queues
|
||||||
|
|
||||||
|
xs, err := rmqc.ListQueues()
|
||||||
|
// => []QueueInfo, err
|
||||||
|
|
||||||
|
// list queues in a vhost
|
||||||
|
xs, err := rmqc.ListQueuesIn("/")
|
||||||
|
// => []QueueInfo, err
|
||||||
|
|
||||||
|
// information about individual queue
|
||||||
|
x, err := rmqc.GetQueue("/", "a.queue")
|
||||||
|
// => QueueInfo, err
|
||||||
|
|
||||||
|
// declares a queue
|
||||||
|
resp, err := rmqc.DeclareQueue("/", "a.queue", QueueSettings{Durable: false})
|
||||||
|
// => *http.Response, err
|
||||||
|
|
||||||
|
// deletes individual queue
|
||||||
|
resp, err := rmqc.DeleteQueue("/", "a.queue")
|
||||||
|
// => *http.Response, err
|
||||||
|
|
||||||
|
// purges all messages in queue
|
||||||
|
resp, err := rmqc.PurgeQueue("/", "a.queue")
|
||||||
|
// => *http.Response, err
|
||||||
|
|
||||||
|
Operations on Bindings
|
||||||
|
|
||||||
|
bs, err := rmqc.ListBindings()
|
||||||
|
// => []BindingInfo, err
|
||||||
|
|
||||||
|
// list bindings in a vhost
|
||||||
|
bs, err := rmqc.ListBindingsIn("/")
|
||||||
|
// => []BindingInfo, err
|
||||||
|
|
||||||
|
// list bindings of a queue
|
||||||
|
bs, err := rmqc.ListQueueBindings("/", "a.queue")
|
||||||
|
// => []BindingInfo, err
|
||||||
|
|
||||||
|
// declare a binding
|
||||||
|
resp, err := rmqc.DeclareBinding("/", BindingInfo{
|
||||||
|
Source: "an.exchange",
|
||||||
|
Destination: "a.queue",
|
||||||
|
DestinationType: "queue",
|
||||||
|
RoutingKey: "#",
|
||||||
|
})
|
||||||
|
// => *http.Response, err
|
||||||
|
|
||||||
|
// deletes individual binding
|
||||||
|
resp, err := rmqc.DeleteBinding("/", BindingInfo{
|
||||||
|
Source: "an.exchange",
|
||||||
|
Destination: "a.queue",
|
||||||
|
DestinationType: "queue",
|
||||||
|
RoutingKey: "#",
|
||||||
|
PropertiesKey: "%23",
|
||||||
|
})
|
||||||
|
// => *http.Response, err
|
||||||
|
|
||||||
|
Operations on Vhosts
|
||||||
|
|
||||||
|
xs, err := rmqc.ListVhosts()
|
||||||
|
// => []VhostInfo, err
|
||||||
|
|
||||||
|
// information about individual vhost
|
||||||
|
x, err := rmqc.GetVhost("/")
|
||||||
|
// => VhostInfo, err
|
||||||
|
|
||||||
|
// creates or updates individual vhost
|
||||||
|
resp, err := rmqc.PutVhost("/", VhostSettings{Tracing: false})
|
||||||
|
// => *http.Response, err
|
||||||
|
|
||||||
|
// deletes individual vhost
|
||||||
|
resp, err := rmqc.DeleteVhost("/")
|
||||||
|
// => *http.Response, err
|
||||||
|
|
||||||
|
Managing Users
|
||||||
|
|
||||||
|
xs, err := rmqc.ListUsers()
|
||||||
|
// => []UserInfo, err
|
||||||
|
|
||||||
|
// information about individual user
|
||||||
|
x, err := rmqc.GetUser("my.user")
|
||||||
|
// => UserInfo, err
|
||||||
|
|
||||||
|
// creates or updates individual user
|
||||||
|
resp, err := rmqc.PutUser("my.user", UserSettings{Password: "s3krE7", Tags: "management policymaker"})
|
||||||
|
// => *http.Response, err
|
||||||
|
|
||||||
|
// deletes individual user
|
||||||
|
resp, err := rmqc.DeleteUser("my.user")
|
||||||
|
// => *http.Response, err
|
||||||
|
|
||||||
|
Managing Permissions
|
||||||
|
|
||||||
|
xs, err := rmqc.ListPermissions()
|
||||||
|
// => []PermissionInfo, err
|
||||||
|
|
||||||
|
// permissions of individual user
|
||||||
|
x, err := rmqc.ListPermissionsOf("my.user")
|
||||||
|
// => []PermissionInfo, err
|
||||||
|
|
||||||
|
// permissions of individual user in vhost
|
||||||
|
x, err := rmqc.GetPermissionsIn("/", "my.user")
|
||||||
|
// => PermissionInfo, err
|
||||||
|
|
||||||
|
// updates permissions of user in vhost
|
||||||
|
resp, err := rmqc.UpdatePermissionsIn("/", "my.user", Permissions{Configure: ".*", Write: ".*", Read: ".*"})
|
||||||
|
// => *http.Response, err
|
||||||
|
|
||||||
|
// revokes permissions in vhost
|
||||||
|
resp, err := rmqc.ClearPermissionsIn("/", "my.user")
|
||||||
|
// => *http.Response, err
|
||||||
|
*/
|
||||||
|
package rabbithole
|
|
@ -0,0 +1,219 @@
|
||||||
|
package rabbithole
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/exchanges
|
||||||
|
//
|
||||||
|
|
||||||
|
type IngressEgressStats struct {
|
||||||
|
PublishIn int `json:"publish_in"`
|
||||||
|
PublishInDetails RateDetails `json:"publish_in_details"`
|
||||||
|
|
||||||
|
PublishOut int `json:"publish_out"`
|
||||||
|
PublishOutDetails RateDetails `json:"publish_out_details"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExchangeInfo struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Vhost string `json:"vhost"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Durable bool `json:"durable"`
|
||||||
|
AutoDelete bool `json:"auto_delete"`
|
||||||
|
Internal bool `json:"internal"`
|
||||||
|
Arguments map[string]interface{} `json:"arguments"`
|
||||||
|
|
||||||
|
MessageStats IngressEgressStats `json:"message_stats"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExchangeSettings struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Durable bool `json:"durable"`
|
||||||
|
AutoDelete bool `json:"auto_delete"`
|
||||||
|
Arguments map[string]interface{} `json:"arguments"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListExchanges() (rec []ExchangeInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "exchanges")
|
||||||
|
if err != nil {
|
||||||
|
return []ExchangeInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return []ExchangeInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/exchanges/{vhost}
|
||||||
|
//
|
||||||
|
|
||||||
|
func (c *Client) ListExchangesIn(vhost string) (rec []ExchangeInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "exchanges/"+url.QueryEscape(vhost))
|
||||||
|
if err != nil {
|
||||||
|
return []ExchangeInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return []ExchangeInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/exchanges/{vhost}/{name}
|
||||||
|
//
|
||||||
|
|
||||||
|
// Example response:
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// "incoming": [
|
||||||
|
// {
|
||||||
|
// "stats": {
|
||||||
|
// "publish": 2760,
|
||||||
|
// "publish_details": {
|
||||||
|
// "rate": 20
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "channel_details": {
|
||||||
|
// "name": "127.0.0.1:46928 -> 127.0.0.1:5672 (2)",
|
||||||
|
// "number": 2,
|
||||||
|
// "connection_name": "127.0.0.1:46928 -> 127.0.0.1:5672",
|
||||||
|
// "peer_port": 46928,
|
||||||
|
// "peer_host": "127.0.0.1"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ],
|
||||||
|
// "outgoing": [
|
||||||
|
// {
|
||||||
|
// "stats": {
|
||||||
|
// "publish": 1280,
|
||||||
|
// "publish_details": {
|
||||||
|
// "rate": 20
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "queue": {
|
||||||
|
// "name": "amq.gen-7NhO_yRr4lDdp-8hdnvfuw",
|
||||||
|
// "vhost": "rabbit\/hole"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ],
|
||||||
|
// "message_stats": {
|
||||||
|
// "publish_in": 2760,
|
||||||
|
// "publish_in_details": {
|
||||||
|
// "rate": 20
|
||||||
|
// },
|
||||||
|
// "publish_out": 1280,
|
||||||
|
// "publish_out_details": {
|
||||||
|
// "rate": 20
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "name": "amq.fanout",
|
||||||
|
// "vhost": "rabbit\/hole",
|
||||||
|
// "type": "fanout",
|
||||||
|
// "durable": true,
|
||||||
|
// "auto_delete": false,
|
||||||
|
// "internal": false,
|
||||||
|
// "arguments": {
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
type ExchangeIngressDetails struct {
|
||||||
|
Stats MessageStats `json:"stats"`
|
||||||
|
ChannelDetails PublishingChannel `json:"channel_details"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PublishingChannel struct {
|
||||||
|
Number int `json:"number"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
ConnectionName string `json:"connection_name"`
|
||||||
|
PeerPort Port `json:"peer_port"`
|
||||||
|
PeerHost string `json:"peer_host"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type NameAndVhost struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Vhost string `json:"vhost"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExchangeEgressDetails struct {
|
||||||
|
Stats MessageStats `json:"stats"`
|
||||||
|
Queue NameAndVhost `json:"queue"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DetailedExchangeInfo struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Vhost string `json:"vhost"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Durable bool `json:"durable"`
|
||||||
|
AutoDelete bool `json:"auto_delete"`
|
||||||
|
Internal bool `json:"internal"`
|
||||||
|
Arguments map[string]interface{} `json:"arguments"`
|
||||||
|
|
||||||
|
Incoming []ExchangeIngressDetails `json:"incoming"`
|
||||||
|
Outgoing []ExchangeEgressDetails `json:"outgoing"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetExchange(vhost, exchange string) (rec *DetailedExchangeInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "exchanges/"+url.QueryEscape(vhost)+"/"+exchange)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// PUT /api/exchanges/{vhost}/{exchange}
|
||||||
|
//
|
||||||
|
|
||||||
|
func (c *Client) DeclareExchange(vhost, exchange string, info ExchangeSettings) (res *http.Response, err error) {
|
||||||
|
if info.Arguments == nil {
|
||||||
|
info.Arguments = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
body, err := json.Marshal(info)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := newRequestWithBody(c, "PUT", "exchanges/"+url.QueryEscape(vhost)+"/"+url.QueryEscape(exchange), body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = executeRequest(c, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// DELETE /api/exchanges/{vhost}/{name}
|
||||||
|
//
|
||||||
|
|
||||||
|
func (c *Client) DeleteExchange(vhost, exchange string) (res *http.Response, err error) {
|
||||||
|
req, err := newRequestWithBody(c, "DELETE", "exchanges/"+url.QueryEscape(vhost)+"/"+url.QueryEscape(exchange), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = executeRequest(c, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
package rabbithole
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Federation definition: additional arguments
|
||||||
|
// added to the entities (queues, exchanges or both)
|
||||||
|
// that match a policy.
|
||||||
|
type FederationDefinition struct {
|
||||||
|
Uri string `json:"uri"`
|
||||||
|
Expires int `json:"expires"`
|
||||||
|
MessageTTL int32 `json:"message-ttl"`
|
||||||
|
MaxHops int `json:"max-hops"`
|
||||||
|
PrefetchCount int `json:"prefetch-count"`
|
||||||
|
ReconnectDelay int `json:"reconnect-delay"`
|
||||||
|
AckMode string `json:"ack-mode"`
|
||||||
|
TrustUserId bool `json:"trust-user-id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Represents a configured Federation upstream.
|
||||||
|
type FederationUpstream struct {
|
||||||
|
Definition FederationDefinition `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// PUT /api/parameters/federation-upstream/{vhost}/{upstream}
|
||||||
|
//
|
||||||
|
|
||||||
|
// Updates a federation upstream
|
||||||
|
func (c *Client) PutFederationUpstream(vhost string, upstreamName string, fDef FederationDefinition) (res *http.Response, err error) {
|
||||||
|
fedUp := FederationUpstream{
|
||||||
|
Definition: fDef,
|
||||||
|
}
|
||||||
|
body, err := json.Marshal(fedUp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := newRequestWithBody(c, "PUT", "parameters/federation-upstream/"+url.QueryEscape(vhost)+"/"+url.QueryEscape(upstreamName), body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = executeRequest(c, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// DELETE /api/parameters/federation-upstream/{vhost}/{name}
|
||||||
|
//
|
||||||
|
|
||||||
|
// Deletes a federation upstream.
|
||||||
|
func (c *Client) DeleteFederationUpstream(vhost, upstreamName string) (res *http.Response, err error) {
|
||||||
|
req, err := newRequestWithBody(c, "DELETE", "parameters/federation-upstream/"+url.QueryEscape(vhost)+"/"+url.QueryEscape(upstreamName), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = executeRequest(c, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
package rabbithole
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/overview
|
||||||
|
//
|
||||||
|
|
||||||
|
type QueueTotals struct {
|
||||||
|
Messages int `json:"messages"`
|
||||||
|
MessagesDetails RateDetails `json:"messages_details"`
|
||||||
|
|
||||||
|
MessagesReady int `json:"messages_ready"`
|
||||||
|
MessagesReadyDetails RateDetails `json:"messages_ready_details"`
|
||||||
|
|
||||||
|
MessagesUnacknowledged int `json:"messages_unacknowledged"`
|
||||||
|
MessagesUnacknowledgedDetails RateDetails `json:"messages_unacknowledged_details"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ObjectTotals struct {
|
||||||
|
Consumers int `json:"consumers"`
|
||||||
|
Queues int `json:"queues"`
|
||||||
|
Exchanges int `json:"exchanges"`
|
||||||
|
Connections int `json:"connections"`
|
||||||
|
Channels int `json:"channels"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Listener struct {
|
||||||
|
Node string `json:"node"`
|
||||||
|
Protocol string `json:"protocol"`
|
||||||
|
IpAddress string `json:"ip_address"`
|
||||||
|
Port Port `json:"port"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Overview struct {
|
||||||
|
ManagementVersion string `json:"management_version"`
|
||||||
|
StatisticsLevel string `json:"statistics_level"`
|
||||||
|
RabbitMQVersion string `json:"rabbitmq_version"`
|
||||||
|
ErlangVersion string `json:"erlang_version"`
|
||||||
|
FullErlangVersion string `json:"erlang_full_version"`
|
||||||
|
ExchangeTypes []ExchangeType `json:"exchange_types"`
|
||||||
|
MessageStats MessageStats `json:"message_stats"`
|
||||||
|
QueueTotals QueueTotals `json:"queue_totals"`
|
||||||
|
ObjectTotals ObjectTotals `json:"object_totals"`
|
||||||
|
Node string `json:"node"`
|
||||||
|
StatisticsDBNode string `json:"statistics_db_node"`
|
||||||
|
Listeners []Listener `json:"listeners"`
|
||||||
|
Contexts []BrokerContext `json:"contexts"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Overview() (rec *Overview, err error) {
|
||||||
|
req, err := newGETRequest(c, "overview")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/whoami
|
||||||
|
//
|
||||||
|
|
||||||
|
type WhoamiInfo struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Tags string `json:"tags"`
|
||||||
|
AuthBackend string `json:"auth_backend"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Whoami() (rec *WhoamiInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "whoami")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
|
@ -0,0 +1,301 @@
|
||||||
|
package rabbithole
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: this probably should be fixed in RabbitMQ management plugin
|
||||||
|
type OsPid string
|
||||||
|
|
||||||
|
type NameDescriptionEnabled struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AuthMechanism NameDescriptionEnabled
|
||||||
|
|
||||||
|
type ExchangeType NameDescriptionEnabled
|
||||||
|
|
||||||
|
type NameDescriptionVersion struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErlangApp NameDescriptionVersion
|
||||||
|
|
||||||
|
type NodeInfo struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
NodeType string `json:"type"`
|
||||||
|
IsRunning bool `json:"running"`
|
||||||
|
OsPid OsPid `json:"os_pid"`
|
||||||
|
|
||||||
|
FdUsed int `json:"fd_used"`
|
||||||
|
FdTotal int `json:"fd_total"`
|
||||||
|
SocketsUsed int `json:"sockets_used"`
|
||||||
|
SocketsTotal int `json:"sockets_total"`
|
||||||
|
MemUsed int `json:"mem_used"`
|
||||||
|
MemLimit int `json:"mem_limit"`
|
||||||
|
MemAlarm bool `json:"mem_alarm"`
|
||||||
|
DiskFree int `json:"disk_free"`
|
||||||
|
DiskFreeLimit int `json:"disk_free_limit"`
|
||||||
|
DiskFreeAlarm bool `json:"disk_free_alarm"`
|
||||||
|
|
||||||
|
// Erlang scheduler run queue length
|
||||||
|
RunQueueLength uint32 `json:"run_queue"`
|
||||||
|
Processors uint32 `json:"processors"`
|
||||||
|
Uptime uint64 `json:"uptime"`
|
||||||
|
|
||||||
|
ExchangeTypes []ExchangeType `json:"exchange_types"`
|
||||||
|
AuthMechanisms []AuthMechanism `json:"auth_mechanisms"`
|
||||||
|
ErlangApps []ErlangApp `json:"applications"`
|
||||||
|
Contexts []BrokerContext `json:"contexts"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/nodes
|
||||||
|
//
|
||||||
|
|
||||||
|
func (c *Client) ListNodes() (rec []NodeInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "nodes")
|
||||||
|
if err != nil {
|
||||||
|
return []NodeInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/nodes/{name}
|
||||||
|
//
|
||||||
|
|
||||||
|
// {
|
||||||
|
// "partitions": [],
|
||||||
|
// "os_pid": "39292",
|
||||||
|
// "fd_used": 35,
|
||||||
|
// "fd_total": 256,
|
||||||
|
// "sockets_used": 4,
|
||||||
|
// "sockets_total": 138,
|
||||||
|
// "mem_used": 69964432,
|
||||||
|
// "mem_limit": 2960660889,
|
||||||
|
// "mem_alarm": false,
|
||||||
|
// "disk_free_limit": 50000000,
|
||||||
|
// "disk_free": 188362731520,
|
||||||
|
// "disk_free_alarm": false,
|
||||||
|
// "proc_used": 370,
|
||||||
|
// "proc_total": 1048576,
|
||||||
|
// "statistics_level": "fine",
|
||||||
|
// "uptime": 98355255,
|
||||||
|
// "run_queue": 0,
|
||||||
|
// "processors": 8,
|
||||||
|
// "exchange_types": [
|
||||||
|
// {
|
||||||
|
// "name": "topic",
|
||||||
|
// "description": "AMQP topic exchange, as per the AMQP specification",
|
||||||
|
// "enabled": true
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "x-consistent-hash",
|
||||||
|
// "description": "Consistent Hashing Exchange",
|
||||||
|
// "enabled": true
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "fanout",
|
||||||
|
// "description": "AMQP fanout exchange, as per the AMQP specification",
|
||||||
|
// "enabled": true
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "direct",
|
||||||
|
// "description": "AMQP direct exchange, as per the AMQP specification",
|
||||||
|
// "enabled": true
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "headers",
|
||||||
|
// "description": "AMQP headers exchange, as per the AMQP specification",
|
||||||
|
// "enabled": true
|
||||||
|
// }
|
||||||
|
// ],
|
||||||
|
// "auth_mechanisms": [
|
||||||
|
// {
|
||||||
|
// "name": "AMQPLAIN",
|
||||||
|
// "description": "QPid AMQPLAIN mechanism",
|
||||||
|
// "enabled": true
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "PLAIN",
|
||||||
|
// "description": "SASL PLAIN authentication mechanism",
|
||||||
|
// "enabled": true
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "RABBIT-CR-DEMO",
|
||||||
|
// "description": "RabbitMQ Demo challenge-response authentication mechanism",
|
||||||
|
// "enabled": false
|
||||||
|
// }
|
||||||
|
// ],
|
||||||
|
// "applications": [
|
||||||
|
// {
|
||||||
|
// "name": "amqp_client",
|
||||||
|
// "description": "RabbitMQ AMQP Client",
|
||||||
|
// "version": "3.2.0"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "asn1",
|
||||||
|
// "description": "The Erlang ASN1 compiler version 2.0.3",
|
||||||
|
// "version": "2.0.3"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "cowboy",
|
||||||
|
// "description": "Small, fast, modular HTTP server.",
|
||||||
|
// "version": "0.5.0-rmq3.2.0-git4b93c2d"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "crypto",
|
||||||
|
// "description": "CRYPTO version 2",
|
||||||
|
// "version": "3.1"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "inets",
|
||||||
|
// "description": "INETS CXC 138 49",
|
||||||
|
// "version": "5.9.6"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "kernel",
|
||||||
|
// "description": "ERTS CXC 138 10",
|
||||||
|
// "version": "2.16.3"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "mnesia",
|
||||||
|
// "description": "MNESIA CXC 138 12",
|
||||||
|
// "version": "4.10"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "mochiweb",
|
||||||
|
// "description": "MochiMedia Web Server",
|
||||||
|
// "version": "2.7.0-rmq3.2.0-git680dba8"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "os_mon",
|
||||||
|
// "description": "CPO CXC 138 46",
|
||||||
|
// "version": "2.2.13"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "public_key",
|
||||||
|
// "description": "Public key infrastructure",
|
||||||
|
// "version": "0.20"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "rabbit",
|
||||||
|
// "description": "RabbitMQ",
|
||||||
|
// "version": "3.2.0"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "rabbitmq_consistent_hash_exchange",
|
||||||
|
// "description": "Consistent Hash Exchange Type",
|
||||||
|
// "version": "3.2.0"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "rabbitmq_management",
|
||||||
|
// "description": "RabbitMQ Management Console",
|
||||||
|
// "version": "3.2.0"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "rabbitmq_management_agent",
|
||||||
|
// "description": "RabbitMQ Management Agent",
|
||||||
|
// "version": "3.2.0"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "rabbitmq_mqtt",
|
||||||
|
// "description": "RabbitMQ MQTT Adapter",
|
||||||
|
// "version": "3.2.0"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "rabbitmq_shovel",
|
||||||
|
// "description": "Data Shovel for RabbitMQ",
|
||||||
|
// "version": "3.2.0"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "rabbitmq_shovel_management",
|
||||||
|
// "description": "Shovel Status",
|
||||||
|
// "version": "3.2.0"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "rabbitmq_stomp",
|
||||||
|
// "description": "Embedded Rabbit Stomp Adapter",
|
||||||
|
// "version": "3.2.0"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "rabbitmq_web_dispatch",
|
||||||
|
// "description": "RabbitMQ Web Dispatcher",
|
||||||
|
// "version": "3.2.0"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "rabbitmq_web_stomp",
|
||||||
|
// "description": "Rabbit WEB-STOMP - WebSockets to Stomp adapter",
|
||||||
|
// "version": "3.2.0"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "sasl",
|
||||||
|
// "description": "SASL CXC 138 11",
|
||||||
|
// "version": "2.3.3"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "sockjs",
|
||||||
|
// "description": "SockJS",
|
||||||
|
// "version": "0.3.4-rmq3.2.0-git3132eb9"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "ssl",
|
||||||
|
// "description": "Erlang\/OTP SSL application",
|
||||||
|
// "version": "5.3.1"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "stdlib",
|
||||||
|
// "description": "ERTS CXC 138 10",
|
||||||
|
// "version": "1.19.3"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "webmachine",
|
||||||
|
// "description": "webmachine",
|
||||||
|
// "version": "1.10.3-rmq3.2.0-gite9359c7"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "xmerl",
|
||||||
|
// "description": "XML parser",
|
||||||
|
// "version": "1.3.4"
|
||||||
|
// }
|
||||||
|
// ],
|
||||||
|
// "contexts": [
|
||||||
|
// {
|
||||||
|
// "description": "Redirect to port 15672",
|
||||||
|
// "path": "\/",
|
||||||
|
// "port": 55672,
|
||||||
|
// "ignore_in_use": true
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "description": "RabbitMQ Management",
|
||||||
|
// "path": "\/",
|
||||||
|
// "port": 15672
|
||||||
|
// }
|
||||||
|
// ],
|
||||||
|
// "name": "rabbit@mercurio",
|
||||||
|
// "type": "disc",
|
||||||
|
// "running": true
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (c *Client) GetNode(name string) (rec *NodeInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "nodes/"+url.QueryEscape(name))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
package rabbithole
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/permissions
|
||||||
|
//
|
||||||
|
|
||||||
|
// Example response:
|
||||||
|
//
|
||||||
|
// [{"user":"guest","vhost":"/","configure":".*","write":".*","read":".*"}]
|
||||||
|
|
||||||
|
type PermissionInfo struct {
|
||||||
|
User string `json:"user"`
|
||||||
|
Vhost string `json:"vhost"`
|
||||||
|
|
||||||
|
// Configuration permissions
|
||||||
|
Configure string `json:"configure"`
|
||||||
|
// Write permissions
|
||||||
|
Write string `json:"write"`
|
||||||
|
// Read permissions
|
||||||
|
Read string `json:"read"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns permissions for all users and virtual hosts.
|
||||||
|
func (c *Client) ListPermissions() (rec []PermissionInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "permissions/")
|
||||||
|
if err != nil {
|
||||||
|
return []PermissionInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return []PermissionInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/users/{user}/permissions
|
||||||
|
//
|
||||||
|
|
||||||
|
// Returns permissions of a specific user.
|
||||||
|
func (c *Client) ListPermissionsOf(username string) (rec []PermissionInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "users/"+url.QueryEscape(username)+"/permissions")
|
||||||
|
if err != nil {
|
||||||
|
return []PermissionInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return []PermissionInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/permissions/{vhost}/{user}
|
||||||
|
//
|
||||||
|
|
||||||
|
// Returns permissions of user in virtual host.
|
||||||
|
func (c *Client) GetPermissionsIn(vhost, username string) (rec PermissionInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "permissions/"+url.QueryEscape(vhost)+"/"+url.QueryEscape(username))
|
||||||
|
if err != nil {
|
||||||
|
return PermissionInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return PermissionInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// PUT /api/permissions/{vhost}/{user}
|
||||||
|
//
|
||||||
|
|
||||||
|
type Permissions struct {
|
||||||
|
Configure string `json:"configure"`
|
||||||
|
Write string `json:"write"`
|
||||||
|
Read string `json:"read"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates permissions of user in virtual host.
|
||||||
|
func (c *Client) UpdatePermissionsIn(vhost, username string, permissions Permissions) (res *http.Response, err error) {
|
||||||
|
body, err := json.Marshal(permissions)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := newRequestWithBody(c, "PUT", "permissions/"+url.QueryEscape(vhost)+"/"+url.QueryEscape(username), body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = executeRequest(c, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// DELETE /api/permissions/{vhost}/{user}
|
||||||
|
//
|
||||||
|
|
||||||
|
// Clears (deletes) permissions of user in virtual host.
|
||||||
|
func (c *Client) ClearPermissionsIn(vhost, username string) (res *http.Response, err error) {
|
||||||
|
req, err := newRequestWithBody(c, "DELETE", "permissions/"+url.QueryEscape(vhost)+"/"+url.QueryEscape(username), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = executeRequest(c, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package rabbithole
|
||||||
|
|
||||||
|
func (c *Client) EnabledProtocols() (xs []string, err error) {
|
||||||
|
overview, err := c.Overview()
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// we really need to implement Map/Filter/etc. MK.
|
||||||
|
xs = make([]string, len(overview.Listeners))
|
||||||
|
for i, lnr := range overview.Listeners {
|
||||||
|
xs[i] = lnr.Protocol
|
||||||
|
}
|
||||||
|
|
||||||
|
return xs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ProtocolPorts() (res map[string]Port, err error) {
|
||||||
|
res = map[string]Port{}
|
||||||
|
|
||||||
|
overview, err := c.Overview()
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, lnr := range overview.Listeners {
|
||||||
|
res[lnr.Protocol] = lnr.Port
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
package rabbithole
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Policy definition: additional arguments
|
||||||
|
// added to the entities (queues, exchanges or both)
|
||||||
|
// that match a policy.
|
||||||
|
type PolicyDefinition map[string]interface{}
|
||||||
|
|
||||||
|
type NodeNames []string
|
||||||
|
|
||||||
|
// Represents a configured policy.
|
||||||
|
type Policy struct {
|
||||||
|
// Virtual host this policy is in.
|
||||||
|
Vhost string `json:"vhost"`
|
||||||
|
// Regular expression pattern used to match queues and exchanges,
|
||||||
|
// , e.g. "^ha\..+"
|
||||||
|
Pattern string `json:"pattern"`
|
||||||
|
// What this policy applies to: "queues", "exchanges", etc.
|
||||||
|
ApplyTo string `json:"apply-to"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Priority int `json:"priority"`
|
||||||
|
// Additional arguments added to the entities (queues,
|
||||||
|
// exchanges or both) that match a policy
|
||||||
|
Definition PolicyDefinition `json:"definition"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/policies
|
||||||
|
//
|
||||||
|
|
||||||
|
// Return all policies (across all virtual hosts).
|
||||||
|
func (c *Client) ListPolicies() (rec []Policy, err error) {
|
||||||
|
req, err := newGETRequest(c, "policies")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/policies/{vhost}
|
||||||
|
//
|
||||||
|
|
||||||
|
// Returns policies in a specific virtual host.
|
||||||
|
func (c *Client) ListPoliciesIn(vhost string) (rec []Policy, err error) {
|
||||||
|
req, err := newGETRequest(c, "policies/"+url.QueryEscape(vhost))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/policies/{vhost}/{name}
|
||||||
|
//
|
||||||
|
|
||||||
|
// Returns individual policy in virtual host.
|
||||||
|
func (c *Client) GetPolicy(vhost, name string) (rec *Policy, err error) {
|
||||||
|
req, err := newGETRequest(c, "policies/"+url.QueryEscape(vhost)+"/"+url.QueryEscape(name))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// PUT /api/policies/{vhost}/{name}
|
||||||
|
//
|
||||||
|
|
||||||
|
// Updates a policy.
|
||||||
|
func (c *Client) PutPolicy(vhost string, name string, policy Policy) (res *http.Response, err error) {
|
||||||
|
body, err := json.Marshal(policy)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := newRequestWithBody(c, "PUT", "policies/"+url.QueryEscape(vhost)+"/"+url.QueryEscape(name), body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = executeRequest(c, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// DELETE /api/policies/{vhost}/{name}
|
||||||
|
//
|
||||||
|
|
||||||
|
// Deletes a policy.
|
||||||
|
func (c *Client) DeletePolicy(vhost, name string) (res *http.Response, err error) {
|
||||||
|
req, err := newRequestWithBody(c, "DELETE", "policies/"+url.QueryEscape(vhost)+"/"+url.QueryEscape(name), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = executeRequest(c, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
|
@ -0,0 +1,283 @@
|
||||||
|
package rabbithole
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Information about backing queue (queue storage engine).
|
||||||
|
type BackingQueueStatus struct {
|
||||||
|
Q1 int `json:"q1"`
|
||||||
|
Q2 int `json:"q2"`
|
||||||
|
Q3 int `json:"q3"`
|
||||||
|
Q4 int `json:"q4"`
|
||||||
|
// Total queue length
|
||||||
|
Length int64 `json:"len"`
|
||||||
|
// Number of pending acks from consumers
|
||||||
|
PendingAcks int64 `json:"pending_acks"`
|
||||||
|
// Number of messages held in RAM
|
||||||
|
RAMMessageCount int64 `json:"ram_msg_count"`
|
||||||
|
// Number of outstanding acks held in RAM
|
||||||
|
RAMAckCount int64 `json:"ram_ack_count"`
|
||||||
|
// Number of persistent messages in the store
|
||||||
|
PersistentCount int64 `json:"persistent_count"`
|
||||||
|
// Average ingress (inbound) rate, not including messages
|
||||||
|
// that straight through to auto-acking consumers.
|
||||||
|
AverageIngressRate float64 `json:"avg_ingress_rate"`
|
||||||
|
// Average egress (outbound) rate, not including messages
|
||||||
|
// that straight through to auto-acking consumers.
|
||||||
|
AverageEgressRate float64 `json:"avg_egress_rate"`
|
||||||
|
// rate at which unacknowledged message records enter RAM,
|
||||||
|
// e.g. because messages are delivered requiring acknowledgement
|
||||||
|
AverageAckIngressRate float32 `json:"avg_ack_ingress_rate"`
|
||||||
|
// rate at which unacknowledged message records leave RAM,
|
||||||
|
// e.g. because acks arrive or unacked messages are paged out
|
||||||
|
AverageAckEgressRate float32 `json:"avg_ack_egress_rate"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OwnerPidDetails struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
PeerPort Port `json:"peer_port"`
|
||||||
|
PeerHost string `json:"peer_host"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type QueueInfo struct {
|
||||||
|
// Queue name
|
||||||
|
Name string `json:"name"`
|
||||||
|
// Virtual host this queue belongs to
|
||||||
|
Vhost string `json:"vhost"`
|
||||||
|
// Is this queue durable?
|
||||||
|
Durable bool `json:"durable"`
|
||||||
|
// Is this queue auto-delted?
|
||||||
|
AutoDelete bool `json:"auto_delete"`
|
||||||
|
// Extra queue arguments
|
||||||
|
Arguments map[string]interface{} `json:"arguments"`
|
||||||
|
|
||||||
|
// RabbitMQ node that hosts master for this queue
|
||||||
|
Node string `json:"node"`
|
||||||
|
// Queue status
|
||||||
|
Status string `json:"status"`
|
||||||
|
|
||||||
|
// Total amount of RAM used by this queue
|
||||||
|
Memory int64 `json:"memory"`
|
||||||
|
// How many consumers this queue has
|
||||||
|
Consumers int `json:"consumers"`
|
||||||
|
// Utilisation of all the consumers
|
||||||
|
ConsumerUtilisation float64 `json:"consumer_utilisation"`
|
||||||
|
// If there is an exclusive consumer, its consumer tag
|
||||||
|
ExclusiveConsumerTag string `json:"exclusive_consumer_tag"`
|
||||||
|
|
||||||
|
// Policy applied to this queue, if any
|
||||||
|
Policy string `json:"policy"`
|
||||||
|
|
||||||
|
// Total bytes of messages in this queues
|
||||||
|
MessagesBytes int64 `json:"message_bytes"`
|
||||||
|
MessagesBytesPersistent int64 `json:"message_bytes_persistent"`
|
||||||
|
MessagesBytesRAM int64 `json:"message_bytes_ram"`
|
||||||
|
|
||||||
|
// Total number of messages in this queue
|
||||||
|
Messages int `json:"messages"`
|
||||||
|
MessagesDetails RateDetails `json:"messages_details"`
|
||||||
|
MessagesPersistent int `json:"messages_persistent"`
|
||||||
|
MessagesRAM int `json:"messages_ram"`
|
||||||
|
|
||||||
|
// Number of messages ready to be delivered
|
||||||
|
MessagesReady int `json:"messages_ready"`
|
||||||
|
MessagesReadyDetails RateDetails `json:"messages_ready_details"`
|
||||||
|
|
||||||
|
// Number of messages delivered and pending acknowledgements from consumers
|
||||||
|
MessagesUnacknowledged int `json:"messages_unacknowledged"`
|
||||||
|
MessagesUnacknowledgedDetails RateDetails `json:"messages_unacknowledged_details"`
|
||||||
|
|
||||||
|
MessageStats MessageStats `json:"message_stats"`
|
||||||
|
|
||||||
|
OwnerPidDetails OwnerPidDetails `json:"owner_pid_details"`
|
||||||
|
|
||||||
|
BackingQueueStatus BackingQueueStatus `json:"backing_queue_status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DetailedQueueInfo QueueInfo
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/queues
|
||||||
|
//
|
||||||
|
|
||||||
|
// [
|
||||||
|
// {
|
||||||
|
// "owner_pid_details": {
|
||||||
|
// "name": "127.0.0.1:46928 -> 127.0.0.1:5672",
|
||||||
|
// "peer_port": 46928,
|
||||||
|
// "peer_host": "127.0.0.1"
|
||||||
|
// },
|
||||||
|
// "message_stats": {
|
||||||
|
// "publish": 19830,
|
||||||
|
// "publish_details": {
|
||||||
|
// "rate": 5
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "messages": 15,
|
||||||
|
// "messages_details": {
|
||||||
|
// "rate": 0
|
||||||
|
// },
|
||||||
|
// "messages_ready": 15,
|
||||||
|
// "messages_ready_details": {
|
||||||
|
// "rate": 0
|
||||||
|
// },
|
||||||
|
// "messages_unacknowledged": 0,
|
||||||
|
// "messages_unacknowledged_details": {
|
||||||
|
// "rate": 0
|
||||||
|
// },
|
||||||
|
// "policy": "",
|
||||||
|
// "exclusive_consumer_tag": "",
|
||||||
|
// "consumers": 0,
|
||||||
|
// "memory": 143112,
|
||||||
|
// "backing_queue_status": {
|
||||||
|
// "q1": 0,
|
||||||
|
// "q2": 0,
|
||||||
|
// "delta": [
|
||||||
|
// "delta",
|
||||||
|
// "undefined",
|
||||||
|
// 0,
|
||||||
|
// "undefined"
|
||||||
|
// ],
|
||||||
|
// "q3": 0,
|
||||||
|
// "q4": 15,
|
||||||
|
// "len": 15,
|
||||||
|
// "pending_acks": 0,
|
||||||
|
// "target_ram_count": "infinity",
|
||||||
|
// "ram_msg_count": 15,
|
||||||
|
// "ram_ack_count": 0,
|
||||||
|
// "next_seq_id": 19830,
|
||||||
|
// "persistent_count": 0,
|
||||||
|
// "avg_ingress_rate": 4.9920127795527,
|
||||||
|
// "avg_egress_rate": 4.9920127795527,
|
||||||
|
// "avg_ack_ingress_rate": 0,
|
||||||
|
// "avg_ack_egress_rate": 0
|
||||||
|
// },
|
||||||
|
// "status": "running",
|
||||||
|
// "name": "amq.gen-QLEaT5Rn_ogbN3O8ZOQt3Q",
|
||||||
|
// "vhost": "rabbit\/hole",
|
||||||
|
// "durable": false,
|
||||||
|
// "auto_delete": false,
|
||||||
|
// "arguments": {
|
||||||
|
// "x-message-ttl": 5000
|
||||||
|
// },
|
||||||
|
// "node": "rabbit@marzo"
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
|
||||||
|
func (c *Client) ListQueues() (rec []QueueInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "queues")
|
||||||
|
if err != nil {
|
||||||
|
return []QueueInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return []QueueInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/queues/{vhost}
|
||||||
|
//
|
||||||
|
|
||||||
|
func (c *Client) ListQueuesIn(vhost string) (rec []QueueInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "queues/"+url.QueryEscape(vhost))
|
||||||
|
if err != nil {
|
||||||
|
return []QueueInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return []QueueInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/queues/{vhost}/{name}
|
||||||
|
//
|
||||||
|
|
||||||
|
func (c *Client) GetQueue(vhost, queue string) (rec *DetailedQueueInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "queues/"+url.QueryEscape(vhost)+"/"+queue)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// PUT /api/exchanges/{vhost}/{exchange}
|
||||||
|
//
|
||||||
|
|
||||||
|
type QueueSettings struct {
|
||||||
|
Durable bool `json:"durable"`
|
||||||
|
AutoDelete bool `json:"auto_delete"`
|
||||||
|
Arguments map[string]interface{} `json:"arguments"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeclareQueue(vhost, queue string, info QueueSettings) (res *http.Response, err error) {
|
||||||
|
if info.Arguments == nil {
|
||||||
|
info.Arguments = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
body, err := json.Marshal(info)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := newRequestWithBody(c, "PUT", "queues/"+url.QueryEscape(vhost)+"/"+url.QueryEscape(queue), body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = executeRequest(c, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// DELETE /api/queues/{vhost}/{name}
|
||||||
|
//
|
||||||
|
|
||||||
|
func (c *Client) DeleteQueue(vhost, queue string) (res *http.Response, err error) {
|
||||||
|
req, err := newRequestWithBody(c, "DELETE", "queues/"+url.QueryEscape(vhost)+"/"+url.QueryEscape(queue), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = executeRequest(c, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// DELETE /api/queues/{vhost}/{name}/contents
|
||||||
|
//
|
||||||
|
|
||||||
|
func (c *Client) PurgeQueue(vhost, queue string) (res *http.Response, err error) {
|
||||||
|
req, err := newRequestWithBody(c, "DELETE", "queues/"+url.QueryEscape(vhost)+"/"+url.QueryEscape(queue)+"/contents", nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = executeRequest(c, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
package rabbithole
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserInfo struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
PasswordHash string `json:"password_hash"`
|
||||||
|
// Tags control permissions. Built-in tags: administrator, management, policymaker.
|
||||||
|
Tags string `json:"tags"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Settings used to create users. Tags must be comma-separated.
|
||||||
|
type UserSettings struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
// Tags control permissions. Administrator grants full
|
||||||
|
// permissions, management grants management UI and HTTP API
|
||||||
|
// access, policymaker grants policy management permissions.
|
||||||
|
Tags string `json:"tags"`
|
||||||
|
|
||||||
|
// *never* returned by RabbitMQ. Set by the client
|
||||||
|
// to create/update a user. MK.
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/users
|
||||||
|
//
|
||||||
|
|
||||||
|
// Example response:
|
||||||
|
// [{"name":"guest","password_hash":"8LYTIFbVUwi8HuV/dGlp2BYsD1I=","tags":"administrator"}]
|
||||||
|
|
||||||
|
// Returns a list of all users in a cluster.
|
||||||
|
func (c *Client) ListUsers() (rec []UserInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "users/")
|
||||||
|
if err != nil {
|
||||||
|
return []UserInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return []UserInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/users/{name}
|
||||||
|
//
|
||||||
|
|
||||||
|
// Returns information about individual user.
|
||||||
|
func (c *Client) GetUser(username string) (rec *UserInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "users/"+url.QueryEscape(username))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// PUT /api/users/{name}
|
||||||
|
//
|
||||||
|
|
||||||
|
// Updates information about individual user.
|
||||||
|
func (c *Client) PutUser(username string, info UserSettings) (res *http.Response, err error) {
|
||||||
|
body, err := json.Marshal(info)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := newRequestWithBody(c, "PUT", "users/"+url.QueryEscape(username), body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = executeRequest(c, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// DELETE /api/users/{name}
|
||||||
|
//
|
||||||
|
|
||||||
|
// Deletes user.
|
||||||
|
func (c *Client) DeleteUser(username string) (res *http.Response, err error) {
|
||||||
|
req, err := newRequestWithBody(c, "DELETE", "users/"+url.QueryEscape(username), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = executeRequest(c, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
|
@ -0,0 +1,160 @@
|
||||||
|
package rabbithole
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/vhosts
|
||||||
|
//
|
||||||
|
|
||||||
|
// Example response:
|
||||||
|
|
||||||
|
// [
|
||||||
|
// {
|
||||||
|
// "message_stats": {
|
||||||
|
// "publish": 78,
|
||||||
|
// "publish_details": {
|
||||||
|
// "rate": 0
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "messages": 0,
|
||||||
|
// "messages_details": {
|
||||||
|
// "rate": 0
|
||||||
|
// },
|
||||||
|
// "messages_ready": 0,
|
||||||
|
// "messages_ready_details": {
|
||||||
|
// "rate": 0
|
||||||
|
// },
|
||||||
|
// "messages_unacknowledged": 0,
|
||||||
|
// "messages_unacknowledged_details": {
|
||||||
|
// "rate": 0
|
||||||
|
// },
|
||||||
|
// "recv_oct": 16653,
|
||||||
|
// "recv_oct_details": {
|
||||||
|
// "rate": 0
|
||||||
|
// },
|
||||||
|
// "send_oct": 40495,
|
||||||
|
// "send_oct_details": {
|
||||||
|
// "rate": 0
|
||||||
|
// },
|
||||||
|
// "name": "\/",
|
||||||
|
// "tracing": false
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "29dd51888b834698a8b5bc3e7f8623aa1c9671f5",
|
||||||
|
// "tracing": false
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
|
||||||
|
type VhostInfo struct {
|
||||||
|
// Virtual host name
|
||||||
|
Name string `json:"name"`
|
||||||
|
// True if tracing is enabled for this virtual host
|
||||||
|
Tracing bool `json:"tracing"`
|
||||||
|
|
||||||
|
// Total number of messages in queues of this virtual host
|
||||||
|
Messages int `json:"messages"`
|
||||||
|
MessagesDetails RateDetails `json:"messages_details"`
|
||||||
|
|
||||||
|
// Total number of messages ready to be delivered in queues of this virtual host
|
||||||
|
MessagesReady int `json:"messages_ready"`
|
||||||
|
MessagesReadyDetails RateDetails `json:"messages_ready_details"`
|
||||||
|
|
||||||
|
// Total number of messages pending acknowledgement from consumers in this virtual host
|
||||||
|
MessagesUnacknowledged int `json:"messages_unacknowledged"`
|
||||||
|
MessagesUnacknowledgedDetails RateDetails `json:"messages_unacknowledged_details"`
|
||||||
|
|
||||||
|
// Octets received
|
||||||
|
RecvOct uint64 `json:"recv_oct"`
|
||||||
|
// Octets sent
|
||||||
|
SendOct uint64 `json:"send_oct"`
|
||||||
|
RecvCount uint64 `json:"recv_cnt"`
|
||||||
|
SendCount uint64 `json:"send_cnt"`
|
||||||
|
SendPending uint64 `json:"send_pend"`
|
||||||
|
RecvOctDetails RateDetails `json:"recv_oct_details"`
|
||||||
|
SendOctDetails RateDetails `json:"send_oct_details"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a list of virtual hosts.
|
||||||
|
func (c *Client) ListVhosts() (rec []VhostInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "vhosts")
|
||||||
|
if err != nil {
|
||||||
|
return []VhostInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return []VhostInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// GET /api/vhosts/{name}
|
||||||
|
//
|
||||||
|
|
||||||
|
// Returns information about a specific virtual host.
|
||||||
|
func (c *Client) GetVhost(vhostname string) (rec *VhostInfo, err error) {
|
||||||
|
req, err := newGETRequest(c, "vhosts/"+url.QueryEscape(vhostname))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = executeAndParseRequest(c, req, &rec); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// PUT /api/vhosts/{name}
|
||||||
|
//
|
||||||
|
|
||||||
|
// Settings used to create or modify virtual hosts.
|
||||||
|
type VhostSettings struct {
|
||||||
|
// True if tracing should be enabled.
|
||||||
|
Tracing bool `json:"tracing"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates or updates a virtual host.
|
||||||
|
func (c *Client) PutVhost(vhostname string, settings VhostSettings) (res *http.Response, err error) {
|
||||||
|
body, err := json.Marshal(settings)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := newRequestWithBody(c, "PUT", "vhosts/"+url.QueryEscape(vhostname), body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = executeRequest(c, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// DELETE /api/vhosts/{name}
|
||||||
|
//
|
||||||
|
|
||||||
|
// Deletes a virtual host.
|
||||||
|
func (c *Client) DeleteVhost(vhostname string) (res *http.Response, err error) {
|
||||||
|
req, err := newRequestWithBody(c, "DELETE", "vhosts/"+url.QueryEscape(vhostname), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = executeRequest(c, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
|
@ -1448,6 +1448,12 @@
|
||||||
"path": "github.com/maximilien/softlayer-go/softlayer",
|
"path": "github.com/maximilien/softlayer-go/softlayer",
|
||||||
"revision": "85659debe44fab5792fc92cf755c04b115b9dc19"
|
"revision": "85659debe44fab5792fc92cf755c04b115b9dc19"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"checksumSHA1": "GSum+utW01N3KeMdvAPnsW0TemM=",
|
||||||
|
"path": "github.com/michaelklishin/rabbit-hole",
|
||||||
|
"revision": "88550829bcdcf614361c73459c903578eb44074e",
|
||||||
|
"revisionTime": "2016-07-06T11:10:56Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "7niW29CvYceZ6zbia6b/LT+yD/M=",
|
"checksumSHA1": "7niW29CvYceZ6zbia6b/LT+yD/M=",
|
||||||
"path": "github.com/mitchellh/cli",
|
"path": "github.com/mitchellh/cli",
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
---
|
||||||
|
layout: "rabbitmq"
|
||||||
|
page_title: "Provider: RabbitMQ"
|
||||||
|
sidebar_current: "docs-rabbitmq-index"
|
||||||
|
description: |-
|
||||||
|
A provider for a RabbitMQ Server.
|
||||||
|
---
|
||||||
|
|
||||||
|
# RabbitMQ Provider
|
||||||
|
|
||||||
|
[RabbitMQ](http://www.rabbitmq.com) is an AMQP message broker server. The
|
||||||
|
RabbitMQ provider exposes resources used to manage the configuration of
|
||||||
|
resources in a RabbitMQ server.
|
||||||
|
|
||||||
|
Use the navigation to the left to read about the available resources.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
The following is a minimal example:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Configure the RabbitMQ provider
|
||||||
|
provider "rabbitmq" {
|
||||||
|
endpoint = "http://127.0.0.1"
|
||||||
|
username = "guest"
|
||||||
|
password = "guest"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create a virtual host
|
||||||
|
resource "rabbitmq_vhost" "vhost_1" {
|
||||||
|
name = "vhost_1"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
The RabbitMQ management plugin must be enabled to use this provider. You can
|
||||||
|
enable the plugin by doing something similar to:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sudo rabbitmq-plugins enable rabbitmq_management
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `endpoint` - (Required) The HTTP URL of the management plugin on the
|
||||||
|
RabbitMQ server. The RabbitMQ management plugin *must* be enabled in order
|
||||||
|
to use this provder. _Note_: This is not the IP address or hostname of the
|
||||||
|
RabbitMQ server that you would use to access RabbitMQ directly.
|
||||||
|
* `username` - (Required) Username to use to authenticate with the server.
|
||||||
|
* `password` - (Optional) Password for the given user.
|
||||||
|
* `insecure` - (Optional) Trust self-signed certificates.
|
||||||
|
* `cacert_file` - (Optional) The path to a custom CA / intermediate certificate.
|
|
@ -0,0 +1,89 @@
|
||||||
|
---
|
||||||
|
layout: "rabbitmq"
|
||||||
|
page_title: "RabbitMQ: rabbitmq_binding"
|
||||||
|
sidebar_current: "docs-rabbitmq-resource-binding"
|
||||||
|
description: |-
|
||||||
|
Creates and manages a binding on a RabbitMQ server.
|
||||||
|
---
|
||||||
|
|
||||||
|
# rabbitmq\_binding
|
||||||
|
|
||||||
|
The ``rabbitmq_binding`` resource creates and manages a binding relationship
|
||||||
|
between a queue an exchange.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "rabbitmq_vhost" "test" {
|
||||||
|
name = "test"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_permissions" "guest" {
|
||||||
|
user = "guest"
|
||||||
|
vhost = "${rabbitmq_vhost.test.name}"
|
||||||
|
permissions {
|
||||||
|
configure = ".*"
|
||||||
|
write = ".*"
|
||||||
|
read = ".*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_exchange" "test" {
|
||||||
|
name = "test"
|
||||||
|
vhost = "${rabbitmq_permissions.guest.vhost}"
|
||||||
|
settings {
|
||||||
|
type = "fanout"
|
||||||
|
durable = false
|
||||||
|
auto_delete = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_queue" "test" {
|
||||||
|
name = "test"
|
||||||
|
vhost = "${rabbitmq_permissions.guest.vhost}"
|
||||||
|
settings {
|
||||||
|
durable = true
|
||||||
|
auto_delete = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_binding" "test" {
|
||||||
|
source = "${rabbitmq_exchange.test.name}"
|
||||||
|
vhost = "${rabbitmq_vhost.test.name}"
|
||||||
|
destination = "${rabbitmq_queue.test.name}"
|
||||||
|
destination_type = "queue"
|
||||||
|
routing_key = "#"
|
||||||
|
properties_key = "%23"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `source` - (Required) The source exchange.
|
||||||
|
|
||||||
|
* `vhost` - (Required) The vhost to create the resource in.
|
||||||
|
|
||||||
|
* `destination` - (Required) The destination queue or exchange.
|
||||||
|
|
||||||
|
* `destination_type` - (Required) The type of destination (queue or exchange).
|
||||||
|
|
||||||
|
* `properties_key` - (Required) A unique key to refer to the binding.
|
||||||
|
|
||||||
|
* `routing_key` - (Optional) A routing key for the binding.
|
||||||
|
|
||||||
|
* `arguments` - (Optional) Additional key/value arguments for the binding.
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
No further attributes are exported.
|
||||||
|
|
||||||
|
## Import
|
||||||
|
|
||||||
|
Bindings can be imported using the `id` which is composed of
|
||||||
|
`vhost/source/destination/destination_type/properties_key`. E.g.
|
||||||
|
|
||||||
|
```
|
||||||
|
terraform import rabbitmq_binding.test test/test/test/queue/%23
|
||||||
|
```
|
|
@ -0,0 +1,75 @@
|
||||||
|
---
|
||||||
|
layout: "rabbitmq"
|
||||||
|
page_title: "RabbitMQ: rabbitmq_exchange"
|
||||||
|
sidebar_current: "docs-rabbitmq-resource-exchange"
|
||||||
|
description: |-
|
||||||
|
Creates and manages an exchange on a RabbitMQ server.
|
||||||
|
---
|
||||||
|
|
||||||
|
# rabbitmq\_exchange
|
||||||
|
|
||||||
|
The ``rabbitmq_exchange`` resource creates and manages an exchange.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "rabbitmq_vhost" "test" {
|
||||||
|
name = "test"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_permissions" "guest" {
|
||||||
|
user = "guest"
|
||||||
|
vhost = "${rabbitmq_vhost.test.name}"
|
||||||
|
permissions {
|
||||||
|
configure = ".*"
|
||||||
|
write = ".*"
|
||||||
|
read = ".*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_exchange" "test" {
|
||||||
|
name = "test"
|
||||||
|
vhost = "${rabbitmq_permissions.guest.vhost}"
|
||||||
|
settings {
|
||||||
|
type = "fanout"
|
||||||
|
durable = false
|
||||||
|
auto_delete = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `name` - (Required) The name of the exchange.
|
||||||
|
|
||||||
|
* `vhost` - (Required) The vhost to create the resource in.
|
||||||
|
|
||||||
|
* `settings` - (Required) The settings of the exchange. The structure is
|
||||||
|
described below.
|
||||||
|
|
||||||
|
The `settings` block supports:
|
||||||
|
|
||||||
|
* `type` - (Required) The type of exchange.
|
||||||
|
|
||||||
|
* `durable` - (Optional) Whether the exchange survives server restarts.
|
||||||
|
Defaults to `false`.
|
||||||
|
|
||||||
|
* `auto_delete` - (Optional) Whether the exchange will self-delete when all
|
||||||
|
queues have finished using it.
|
||||||
|
|
||||||
|
* `arguments` - (Optional) Additional key/value settings for the exchange.
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
No further attributes are exported.
|
||||||
|
|
||||||
|
## Import
|
||||||
|
|
||||||
|
Exchanges can be imported using the `id` which is composed of `name@vhost`.
|
||||||
|
E.g.
|
||||||
|
|
||||||
|
```
|
||||||
|
terraform import rabbitmq_exchange.test test@vhost
|
||||||
|
```
|
|
@ -0,0 +1,66 @@
|
||||||
|
---
|
||||||
|
layout: "rabbitmq"
|
||||||
|
page_title: "RabbitMQ: rabbitmq_permissions"
|
||||||
|
sidebar_current: "docs-rabbitmq-resource-permissions"
|
||||||
|
description: |-
|
||||||
|
Creates and manages a user's permissions on a RabbitMQ server.
|
||||||
|
---
|
||||||
|
|
||||||
|
# rabbitmq\_permissions
|
||||||
|
|
||||||
|
The ``rabbitmq_permissions`` resource creates and manages a user's set of
|
||||||
|
permissions.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "rabbitmq_vhost" "test" {
|
||||||
|
name = "test"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_user" "test" {
|
||||||
|
name = "mctest"
|
||||||
|
password = "foobar"
|
||||||
|
tags = ["administrator"]
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_permissions" "test" {
|
||||||
|
user = "${rabbitmq_user.test.name}"
|
||||||
|
vhost = "${rabbitmq_vhost.test.name}"
|
||||||
|
permissions {
|
||||||
|
configure = ".*"
|
||||||
|
write = ".*"
|
||||||
|
read = ".*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `user` - (Required) The user to apply the permissions to.
|
||||||
|
|
||||||
|
* `vhost` - (Required) The vhost to create the resource in.
|
||||||
|
|
||||||
|
* `permissions` - (Required) The settings of the permissions. The structure is
|
||||||
|
described below.
|
||||||
|
|
||||||
|
The `permissions` block supports:
|
||||||
|
|
||||||
|
* `configure` - (Required) The "configure" ACL.
|
||||||
|
* `write` - (Required) The "write" ACL.
|
||||||
|
* `read` - (Required) The "read" ACL.
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
No further attributes are exported.
|
||||||
|
|
||||||
|
## Import
|
||||||
|
|
||||||
|
Permissions can be imported using the `id` which is composed of `user@vhost`.
|
||||||
|
E.g.
|
||||||
|
|
||||||
|
```
|
||||||
|
terraform import rabbitmq_permissions.test user@vhost
|
||||||
|
```
|
|
@ -0,0 +1,75 @@
|
||||||
|
---
|
||||||
|
layout: "rabbitmq"
|
||||||
|
page_title: "RabbitMQ: rabbitmq_policy"
|
||||||
|
sidebar_current: "docs-rabbitmq-resource-policy"
|
||||||
|
description: |-
|
||||||
|
Creates and manages a policy on a RabbitMQ server.
|
||||||
|
---
|
||||||
|
|
||||||
|
# rabbitmq\_policy
|
||||||
|
|
||||||
|
The ``rabbitmq_policy`` resource creates and manages policies for exchanges
|
||||||
|
and queues.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "rabbitmq_vhost" "test" {
|
||||||
|
name = "test"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_permissions" "guest" {
|
||||||
|
user = "guest"
|
||||||
|
vhost = "${rabbitmq_vhost.test.name}"
|
||||||
|
permissions {
|
||||||
|
configure = ".*"
|
||||||
|
write = ".*"
|
||||||
|
read = ".*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "rabbitmq_policy" "test" {
|
||||||
|
name = "test"
|
||||||
|
vhost = "${rabbitmq_permissions.guest.vhost}"
|
||||||
|
policy {
|
||||||
|
pattern = ".*"
|
||||||
|
priority = 0
|
||||||
|
apply_to = "all"
|
||||||
|
definition {
|
||||||
|
ha-mode = "all"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `name` - (Required) The name of the policy.
|
||||||
|
|
||||||
|
* `vhost` - (Required) The vhost to create the resource in.
|
||||||
|
|
||||||
|
* `policy` - (Required) The settings of the policy. The structure is
|
||||||
|
described below.
|
||||||
|
|
||||||
|
The `policy` block supports:
|
||||||
|
|
||||||
|
* `pattern` - (Required) A pattern to match an exchange or queue name.
|
||||||
|
* `priority` - (Required) The policy with the greater priority is applied first.
|
||||||
|
* `apply_to` - (Required) Can either be "exchange", "queues", or "all".
|
||||||
|
* `definition` - (Required) Key/value pairs of the policy definition. See the
|
||||||
|
RabbitMQ documentation for definition references and examples.
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
No further attributes are exported.
|
||||||
|
|
||||||
|
## Import
|
||||||
|
|
||||||
|
Policies can be imported using the `id` which is composed of `name@vhost`.
|
||||||
|
E.g.
|
||||||
|
|
||||||
|
```
|
||||||
|
terraform import rabbitmq_policy.test name@vhost
|
||||||
|
```
|
|
@ -0,0 +1,71 @@
|
||||||
|
---
|
||||||
|
layout: "rabbitmq"
|
||||||
|
page_title: "RabbitMQ: rabbitmq_queue"
|
||||||
|
sidebar_current: "docs-rabbitmq-resource-queue"
|
||||||
|
description: |-
|
||||||
|
Creates and manages a queue on a RabbitMQ server.
|
||||||
|
---
|
||||||
|
|
||||||
|
# rabbitmq\_queue
|
||||||
|
|
||||||
|
The ``rabbitmq_queue`` resource creates and manages a queue.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `name` - (Required) The name of the queue.
|
||||||
|
|
||||||
|
* `vhost` - (Required) The vhost to create the resource in.
|
||||||
|
|
||||||
|
* `settings` - (Required) The settings of the queue. The structure is
|
||||||
|
described below.
|
||||||
|
|
||||||
|
The `settings` block supports:
|
||||||
|
|
||||||
|
* `durable` - (Optional) Whether the queue survives server restarts.
|
||||||
|
Defaults to `false`.
|
||||||
|
|
||||||
|
* `auto_delete` - (Optional) Whether the queue will self-delete when all
|
||||||
|
consumers have unsubscribed.
|
||||||
|
|
||||||
|
* `arguments` - (Optional) Additional key/value settings for the queue.
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
No further attributes are exported.
|
||||||
|
|
||||||
|
## Import
|
||||||
|
|
||||||
|
Queues can be imported using the `id` which is composed of `name@vhost`. E.g.
|
||||||
|
|
||||||
|
```
|
||||||
|
terraform import rabbitmq_queue.test name@vhost
|
||||||
|
```
|
|
@ -0,0 +1,45 @@
|
||||||
|
---
|
||||||
|
layout: "rabbitmq"
|
||||||
|
page_title: "RabbitMQ: rabbitmq_user"
|
||||||
|
sidebar_current: "docs-rabbitmq-resource-user"
|
||||||
|
description: |-
|
||||||
|
Creates and manages a user on a RabbitMQ server.
|
||||||
|
---
|
||||||
|
|
||||||
|
# rabbitmq\_user
|
||||||
|
|
||||||
|
The ``rabbitmq_user`` resource creates and manages a user.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "rabbitmq_user" "test" {
|
||||||
|
name = "mctest"
|
||||||
|
password = "foobar"
|
||||||
|
tags = ["administrator", "management"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `name` - (Required) The name of the user.
|
||||||
|
|
||||||
|
* `password` - (Required) The password of the user. The value of this argument
|
||||||
|
is plain-text so make sure to secure where this is defined.
|
||||||
|
|
||||||
|
* `tags` - (Required) Which permission model to apply to the user. Valid
|
||||||
|
options are: management, policymaker, monitoring, and administrator.
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
No further attributes are exported.
|
||||||
|
|
||||||
|
## Import
|
||||||
|
|
||||||
|
Users can be imported using the `name`, e.g.
|
||||||
|
|
||||||
|
```
|
||||||
|
terraform import rabbitmq_user.test mctest
|
||||||
|
```
|
|
@ -0,0 +1,37 @@
|
||||||
|
---
|
||||||
|
layout: "rabbitmq"
|
||||||
|
page_title: "RabbitMQ: rabbitmq_vhost"
|
||||||
|
sidebar_current: "docs-rabbitmq-resource-vhost"
|
||||||
|
description: |-
|
||||||
|
Creates and manages a vhost on a RabbitMQ server.
|
||||||
|
---
|
||||||
|
|
||||||
|
# rabbitmq\_vhost
|
||||||
|
|
||||||
|
The ``rabbitmq_vhost`` resource creates and manages a vhost.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "rabbitmq_vhost" "my_vhost" {
|
||||||
|
name = "my_vhost"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `name` - (Required) The name of the vhost.
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
No further attributes are exported.
|
||||||
|
|
||||||
|
## Import
|
||||||
|
|
||||||
|
Vhosts can be imported using the `name`, e.g.
|
||||||
|
|
||||||
|
```
|
||||||
|
terraform import rabbitmq_vhost.my_vhost my_vhost
|
||||||
|
```
|
|
@ -284,6 +284,10 @@
|
||||||
|
|
||||||
<li<%= sidebar_current("docs-providers-powerdns") %>>
|
<li<%= sidebar_current("docs-providers-powerdns") %>>
|
||||||
<a href="/docs/providers/powerdns/index.html">PowerDNS</a>
|
<a href="/docs/providers/powerdns/index.html">PowerDNS</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li<%= sidebar_current("docs-providers-rabbitmq") %>>
|
||||||
|
<a href="/docs/providers/rabbitmq/index.html">RabbitMQ</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li<%= sidebar_current("docs-providers-random") %>>
|
<li<%= sidebar_current("docs-providers-random") %>>
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
<% wrap_layout :inner do %>
|
||||||
|
<% content_for :sidebar do %>
|
||||||
|
<div class="docs-sidebar hidden-print affix-top" role="complementary">
|
||||||
|
<ul class="nav docs-sidenav">
|
||||||
|
<li<%= sidebar_current("docs-home") %>>
|
||||||
|
<a href="/docs/providers/index.html">« Documentation Home</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li<%= sidebar_current("docs-rabbitmq-index") %>>
|
||||||
|
<a href="/docs/providers/rabbitmq/index.html">RabbitMQ Provider</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li<%= sidebar_current(/^docs-rabbitmq-resource/) %>>
|
||||||
|
<a href="#">Resources</a>
|
||||||
|
<ul class="nav nav-visible">
|
||||||
|
<li<%= sidebar_current("docs-rabbitmq-resource-binding") %>>
|
||||||
|
<a href="/docs/providers/rabbitmq/r/binding.html">rabbitmq_binding</a>
|
||||||
|
</li>
|
||||||
|
<li<%= sidebar_current("docs-rabbitmq-resource-exchange") %>>
|
||||||
|
<a href="/docs/providers/rabbitmq/r/exchange.html">rabbitmq_exchange</a>
|
||||||
|
</li>
|
||||||
|
<li<%= sidebar_current("docs-rabbitmq-resource-permissions") %>>
|
||||||
|
<a href="/docs/providers/rabbitmq/r/permissions.html">rabbitmq_permissions</a>
|
||||||
|
</li>
|
||||||
|
<li<%= sidebar_current("docs-rabbitmq-resource-policy") %>>
|
||||||
|
<a href="/docs/providers/rabbitmq/r/policy.html">rabbitmq_policy</a>
|
||||||
|
</li>
|
||||||
|
<li<%= sidebar_current("docs-rabbitmq-resource-queue") %>>
|
||||||
|
<a href="/docs/providers/rabbitmq/r/queue.html">rabbitmq_queue</a>
|
||||||
|
</li>
|
||||||
|
<li<%= sidebar_current("docs-rabbitmq-resource-user") %>>
|
||||||
|
<a href="/docs/providers/rabbitmq/r/user.html">rabbitmq_user</a>
|
||||||
|
</li>
|
||||||
|
<li<%= sidebar_current("docs-rabbitmq-resource-vhost") %>>
|
||||||
|
<a href="/docs/providers/rabbitmq/r/vhost.html">rabbitmq_vhost</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= yield %>
|
||||||
|
<% end %>
|
Loading…
Reference in New Issue