Skip to content

Commit

Permalink
Merge pull request #1 from maxenglander/2087-consul-service-resource
Browse files Browse the repository at this point in the history
Feature request: consul_service resource
  • Loading branch information
maxenglander committed Oct 29, 2015
2 parents 0961f5c + fa94d7f commit cd0b46f
Show file tree
Hide file tree
Showing 7 changed files with 513 additions and 10 deletions.
4 changes: 4 additions & 0 deletions builtin/providers/consul/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
type Config struct {
Datacenter string `mapstructure:"datacenter"`
Address string `mapstructure:"address"`
Token string `mapstructure:"token"`
Scheme string `mapstructure:"scheme"`
}

Expand All @@ -25,6 +26,9 @@ func (c *Config) Client() (*consulapi.Client, error) {
if c.Scheme != "" {
config.Scheme = c.Scheme
}
if c.Token != "" {
config.Token = c.Token
}
client, err := consulapi.NewClient(config)

log.Printf("[INFO] Consul Client configured with address: '%s', scheme: '%s', datacenter: '%s'",
Expand Down
17 changes: 17 additions & 0 deletions builtin/providers/consul/get_dc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package consul

import (
"fmt"

consulapi "github.com/hashicorp/consul/api"
)

// getDC is used to get the datacenter of the local agent
func getDC(client *consulapi.Client) (string, error) {
info, err := client.Agent().Self()
if err != nil {
return "", fmt.Errorf("Failed to get datacenter from Consul agent: %v", err)
}
dc := info["Config"]["Datacenter"].(string)
return dc, nil
}
135 changes: 135 additions & 0 deletions builtin/providers/consul/resource_consul_agent_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package consul

import (
"fmt"

consulapi "github.com/hashicorp/consul/api"
"github.com/hashicorp/terraform/helper/schema"
)

func resourceConsulAgentService() *schema.Resource {
return &schema.Resource{
Create: resourceConsulAgentServiceCreate,
Update: resourceConsulAgentServiceCreate,
Read: resourceConsulAgentServiceRead,
Delete: resourceConsulAgentServiceDelete,

Schema: map[string]*schema.Schema{
"address": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},

"id": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},

"name": &schema.Schema{
Type: schema.TypeString,
Required: true,
},

"port": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
ForceNew: true,
},

"tags": &schema.Schema{
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
ForceNew: true,
},
},
}
}

func resourceConsulAgentServiceCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*consulapi.Client)
agent := client.Agent()

name := d.Get("name").(string)
registration := consulapi.AgentServiceRegistration{Name: name}

if address, ok := d.GetOk("address"); ok {
registration.Address = address.(string)
}

if id, ok := d.GetOk("id"); ok {
registration.ID = id.(string)
}

if port, ok := d.GetOk("port"); ok {
registration.Port = port.(int)
}

if v, ok := d.GetOk("tags"); ok {
vs := v.([]interface{})
s := make([]string, len(vs))
for i, raw := range vs {
s[i] = raw.(string)
}
registration.Tags = s
}

if err := agent.ServiceRegister(&registration); err != nil {
return fmt.Errorf("Failed to register service '%s' with Consul agent: %v", name, err)
}

// Update the resource
if serviceMap, err := agent.Services(); err != nil {
return fmt.Errorf("Failed to read services from Consul agent: %v", err)
} else if service, ok := serviceMap[name]; !ok {
return fmt.Errorf("Failed to read service '%s' from Consul agent: %v", name, err)
} else {
d.Set("address", service.Address)
d.Set("name", service.Service)
d.Set("port", service.Port)
d.Set("tags", service.Tags)
d.SetId(service.ID)
}

return nil
}

func resourceConsulAgentServiceRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*consulapi.Client)
agent := client.Agent()

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

if services, err := agent.Services(); err != nil {
return fmt.Errorf("Failed to get services from Consul agent: %v", err)
} else if service, ok := services[name]; !ok {
return fmt.Errorf("Failed to get service '%s' from Consul agent", name)
} else {
d.Set("address", service.Address)
d.Set("name", service.Service)
d.Set("port", service.Port)
d.Set("tags", service.Tags)
d.SetId(service.ID)
}

return nil
}

func resourceConsulAgentServiceDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*consulapi.Client)
catalog := client.Agent()

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

if err := catalog.ServiceDeregister(name); err != nil {
return fmt.Errorf("Failed to deregister service '%s' from Consul agent: %v", name, err)
}

// Clear the ID
d.SetId("")
return nil
}
85 changes: 85 additions & 0 deletions builtin/providers/consul/resource_consul_agent_service_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package consul

import (
"fmt"
"testing"

consulapi "github.com/hashicorp/consul/api"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)

func TestAccConsulAgentService_basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() {},
Providers: testAccProviders,
CheckDestroy: testAccCheckConsulAgentServiceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccConsulAgentServiceConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckConsulAgentServiceExists(),
testAccCheckConsulAgentServiceValue("consul_agent_service.app", "address", "www.google.com"),
testAccCheckConsulAgentServiceValue("consul_agent_service.app", "id", "google"),
testAccCheckConsulAgentServiceValue("consul_agent_service.app", "name", "google"),
),
},
},
})
}

func testAccCheckConsulAgentServiceDestroy(s *terraform.State) error {
agent := testAccProvider.Meta().(*consulapi.Client).Agent()
services, err := agent.Services()
if err != nil {
return fmt.Errorf("Could not retrieve services: %#v", err)
}
_, ok := services["google"]
if ok {
return fmt.Errorf("Service still exists: %#v", "google")
}
return nil
}

func testAccCheckConsulAgentServiceExists() resource.TestCheckFunc {
return func(s *terraform.State) error {
agent := testAccProvider.Meta().(*consulapi.Client).Agent()
services, err := agent.Services()
if err != nil {
return err
}
_, ok := services["google"]
if !ok {
return fmt.Errorf("Service does not exist: %#v", "google")
}
return nil
}
}

func testAccCheckConsulAgentServiceValue(n, attr, val string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rn, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Resource not found")
}
out, ok := rn.Primary.Attributes[attr]
if !ok {
return fmt.Errorf("Attribute '%s' not found: %#v", attr, rn.Primary.Attributes)
}
if val != "<any>" && out != val {
return fmt.Errorf("Attribute '%s' value '%s' != '%s'", attr, out, val)
}
if val == "<any>" && out == "" {
return fmt.Errorf("Attribute '%s' value '%s'", attr, out)
}
return nil
}
}

const testAccConsulAgentServiceConfig = `
resource "consul_agent_service" "app" {
name = "google"
address = "www.google.com"
port = 80
}
`

0 comments on commit cd0b46f

Please sign in to comment.