github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/consul/resource_consul_catalog_entry.go (about)

     1  package consul
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"sort"
     7  	"strings"
     8  
     9  	consulapi "github.com/hashicorp/consul/api"
    10  	"github.com/hashicorp/terraform/helper/hashcode"
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  )
    13  
    14  func resourceConsulCatalogEntry() *schema.Resource {
    15  	return &schema.Resource{
    16  		Create: resourceConsulCatalogEntryCreate,
    17  		Update: resourceConsulCatalogEntryCreate,
    18  		Read:   resourceConsulCatalogEntryRead,
    19  		Delete: resourceConsulCatalogEntryDelete,
    20  
    21  		Schema: map[string]*schema.Schema{
    22  			"address": &schema.Schema{
    23  				Type:     schema.TypeString,
    24  				Required: true,
    25  				ForceNew: true,
    26  			},
    27  
    28  			"datacenter": &schema.Schema{
    29  				Type:     schema.TypeString,
    30  				Optional: true,
    31  				Computed: true,
    32  				ForceNew: true,
    33  			},
    34  
    35  			"node": &schema.Schema{
    36  				Type:     schema.TypeString,
    37  				Required: true,
    38  				ForceNew: true,
    39  			},
    40  
    41  			"service": &schema.Schema{
    42  				Type:     schema.TypeSet,
    43  				Optional: true,
    44  				ForceNew: true,
    45  				Elem: &schema.Resource{
    46  					Schema: map[string]*schema.Schema{
    47  						"address": &schema.Schema{
    48  							Type:     schema.TypeString,
    49  							Optional: true,
    50  							ForceNew: true,
    51  						},
    52  
    53  						"id": &schema.Schema{
    54  							Type:     schema.TypeString,
    55  							Optional: true,
    56  							Computed: true,
    57  							ForceNew: true,
    58  						},
    59  
    60  						"name": &schema.Schema{
    61  							Type:     schema.TypeString,
    62  							Required: true,
    63  							ForceNew: true,
    64  						},
    65  
    66  						"port": &schema.Schema{
    67  							Type:     schema.TypeInt,
    68  							Optional: true,
    69  							ForceNew: true,
    70  						},
    71  
    72  						"tags": &schema.Schema{
    73  							Type:     schema.TypeSet,
    74  							Optional: true,
    75  							ForceNew: true,
    76  							Elem:     &schema.Schema{Type: schema.TypeString},
    77  							Set:      resourceConsulCatalogEntryServiceTagsHash,
    78  						},
    79  					},
    80  				},
    81  				Set: resourceConsulCatalogEntryServicesHash,
    82  			},
    83  
    84  			"token": &schema.Schema{
    85  				Type:     schema.TypeString,
    86  				Optional: true,
    87  			},
    88  		},
    89  	}
    90  }
    91  
    92  func resourceConsulCatalogEntryServiceTagsHash(v interface{}) int {
    93  	return hashcode.String(v.(string))
    94  }
    95  
    96  func resourceConsulCatalogEntryServicesHash(v interface{}) int {
    97  	var buf bytes.Buffer
    98  	m := v.(map[string]interface{})
    99  	buf.WriteString(fmt.Sprintf("%s-", m["id"].(string)))
   100  	buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
   101  	buf.WriteString(fmt.Sprintf("%s-", m["address"].(string)))
   102  	buf.WriteString(fmt.Sprintf("%d-", m["port"].(int)))
   103  	if v, ok := m["tags"]; ok {
   104  		vs := v.(*schema.Set).List()
   105  		s := make([]string, len(vs))
   106  		for i, raw := range vs {
   107  			s[i] = raw.(string)
   108  		}
   109  		sort.Strings(s)
   110  
   111  		for _, v := range s {
   112  			buf.WriteString(fmt.Sprintf("%s-", v))
   113  		}
   114  	}
   115  	return hashcode.String(buf.String())
   116  }
   117  
   118  func resourceConsulCatalogEntryCreate(d *schema.ResourceData, meta interface{}) error {
   119  	client := meta.(*consulapi.Client)
   120  	catalog := client.Catalog()
   121  
   122  	var dc string
   123  	if v, ok := d.GetOk("datacenter"); ok {
   124  		dc = v.(string)
   125  	} else {
   126  		var err error
   127  		if dc, err = getDC(d, client); err != nil {
   128  			return err
   129  		}
   130  	}
   131  
   132  	var token string
   133  	if v, ok := d.GetOk("token"); ok {
   134  		token = v.(string)
   135  	}
   136  
   137  	// Setup the operations using the datacenter
   138  	wOpts := consulapi.WriteOptions{Datacenter: dc, Token: token}
   139  
   140  	address := d.Get("address").(string)
   141  	node := d.Get("node").(string)
   142  
   143  	var serviceIDs []string
   144  	if service, ok := d.GetOk("service"); ok {
   145  		serviceList := service.(*schema.Set).List()
   146  		serviceIDs = make([]string, len(serviceList))
   147  		for i, rawService := range serviceList {
   148  			serviceData := rawService.(map[string]interface{})
   149  
   150  			if len(serviceData["id"].(string)) == 0 {
   151  				serviceData["id"] = serviceData["name"].(string)
   152  			}
   153  			serviceID := serviceData["id"].(string)
   154  			serviceIDs[i] = serviceID
   155  
   156  			var tags []string
   157  			if v := serviceData["tags"].(*schema.Set).List(); len(v) > 0 {
   158  				tags = make([]string, len(v))
   159  				for i, raw := range v {
   160  					tags[i] = raw.(string)
   161  				}
   162  			}
   163  
   164  			registration := &consulapi.CatalogRegistration{
   165  				Address:    address,
   166  				Datacenter: dc,
   167  				Node:       node,
   168  				Service: &consulapi.AgentService{
   169  					Address: serviceData["address"].(string),
   170  					ID:      serviceID,
   171  					Service: serviceData["name"].(string),
   172  					Port:    serviceData["port"].(int),
   173  					Tags:    tags,
   174  				},
   175  			}
   176  
   177  			if _, err := catalog.Register(registration, &wOpts); err != nil {
   178  				return fmt.Errorf("Failed to register Consul catalog entry with node '%s' at address '%s' in %s: %v",
   179  					node, address, dc, err)
   180  			}
   181  		}
   182  	} else {
   183  		registration := &consulapi.CatalogRegistration{
   184  			Address:    address,
   185  			Datacenter: dc,
   186  			Node:       node,
   187  		}
   188  
   189  		if _, err := catalog.Register(registration, &wOpts); err != nil {
   190  			return fmt.Errorf("Failed to register Consul catalog entry with node '%s' at address '%s' in %s: %v",
   191  				node, address, dc, err)
   192  		}
   193  	}
   194  
   195  	// Update the resource
   196  	qOpts := consulapi.QueryOptions{Datacenter: dc}
   197  	if _, _, err := catalog.Node(node, &qOpts); err != nil {
   198  		return fmt.Errorf("Failed to read Consul catalog entry for node '%s' at address '%s' in %s: %v",
   199  			node, address, dc, err)
   200  	} else {
   201  		d.Set("datacenter", dc)
   202  	}
   203  
   204  	sort.Strings(serviceIDs)
   205  	serviceIDsJoined := strings.Join(serviceIDs, ",")
   206  
   207  	d.SetId(fmt.Sprintf("%s-%s-[%s]", node, address, serviceIDsJoined))
   208  
   209  	return nil
   210  }
   211  
   212  func resourceConsulCatalogEntryRead(d *schema.ResourceData, meta interface{}) error {
   213  	client := meta.(*consulapi.Client)
   214  	catalog := client.Catalog()
   215  
   216  	// Get the DC, error if not available.
   217  	var dc string
   218  	if v, ok := d.GetOk("datacenter"); ok {
   219  		dc = v.(string)
   220  	}
   221  
   222  	node := d.Get("node").(string)
   223  
   224  	// Setup the operations using the datacenter
   225  	qOpts := consulapi.QueryOptions{Datacenter: dc}
   226  
   227  	if _, _, err := catalog.Node(node, &qOpts); err != nil {
   228  		return fmt.Errorf("Failed to get node '%s' from Consul catalog: %v", node, err)
   229  	}
   230  
   231  	return nil
   232  }
   233  
   234  func resourceConsulCatalogEntryDelete(d *schema.ResourceData, meta interface{}) error {
   235  	client := meta.(*consulapi.Client)
   236  	catalog := client.Catalog()
   237  
   238  	var dc string
   239  	if v, ok := d.GetOk("datacenter"); ok {
   240  		dc = v.(string)
   241  	} else {
   242  		var err error
   243  		if dc, err = getDC(d, client); err != nil {
   244  			return err
   245  		}
   246  	}
   247  
   248  	var token string
   249  	if v, ok := d.GetOk("token"); ok {
   250  		token = v.(string)
   251  	}
   252  
   253  	// Setup the operations using the datacenter
   254  	wOpts := consulapi.WriteOptions{Datacenter: dc, Token: token}
   255  
   256  	address := d.Get("address").(string)
   257  	node := d.Get("node").(string)
   258  
   259  	deregistration := consulapi.CatalogDeregistration{
   260  		Address:    address,
   261  		Datacenter: dc,
   262  		Node:       node,
   263  	}
   264  
   265  	if _, err := catalog.Deregister(&deregistration, &wOpts); err != nil {
   266  		return fmt.Errorf("Failed to deregister Consul catalog entry with node '%s' at address '%s' in %s: %v",
   267  			node, address, dc, err)
   268  	}
   269  
   270  	// Clear the ID
   271  	d.SetId("")
   272  	return nil
   273  }