github.com/minamijoyo/terraform@v0.7.8-0.20161029001309-18b3736ba44b/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 serviceID := serviceData["id"].(string) 151 serviceIDs[i] = serviceID 152 153 var tags []string 154 if v := serviceData["tags"].(*schema.Set).List(); len(v) > 0 { 155 tags = make([]string, len(v)) 156 for i, raw := range v { 157 tags[i] = raw.(string) 158 } 159 } 160 161 registration := &consulapi.CatalogRegistration{ 162 Address: address, 163 Datacenter: dc, 164 Node: node, 165 Service: &consulapi.AgentService{ 166 Address: serviceData["address"].(string), 167 ID: serviceID, 168 Service: serviceData["name"].(string), 169 Port: serviceData["port"].(int), 170 Tags: tags, 171 }, 172 } 173 174 if _, err := catalog.Register(registration, &wOpts); err != nil { 175 return fmt.Errorf("Failed to register Consul catalog entry with node '%s' at address '%s' in %s: %v", 176 node, address, dc, err) 177 } 178 } 179 } else { 180 registration := &consulapi.CatalogRegistration{ 181 Address: address, 182 Datacenter: dc, 183 Node: node, 184 } 185 186 if _, err := catalog.Register(registration, &wOpts); err != nil { 187 return fmt.Errorf("Failed to register Consul catalog entry with node '%s' at address '%s' in %s: %v", 188 node, address, dc, err) 189 } 190 } 191 192 // Update the resource 193 qOpts := consulapi.QueryOptions{Datacenter: dc} 194 if _, _, err := catalog.Node(node, &qOpts); err != nil { 195 return fmt.Errorf("Failed to read Consul catalog entry for node '%s' at address '%s' in %s: %v", 196 node, address, dc, err) 197 } else { 198 d.Set("datacenter", dc) 199 } 200 201 sort.Strings(serviceIDs) 202 serviceIDsJoined := strings.Join(serviceIDs, ",") 203 204 d.SetId(fmt.Sprintf("%s-%s-[%s]", node, address, serviceIDsJoined)) 205 206 return nil 207 } 208 209 func resourceConsulCatalogEntryRead(d *schema.ResourceData, meta interface{}) error { 210 client := meta.(*consulapi.Client) 211 catalog := client.Catalog() 212 213 // Get the DC, error if not available. 214 var dc string 215 if v, ok := d.GetOk("datacenter"); ok { 216 dc = v.(string) 217 } 218 219 node := d.Get("node").(string) 220 221 // Setup the operations using the datacenter 222 qOpts := consulapi.QueryOptions{Datacenter: dc} 223 224 if _, _, err := catalog.Node(node, &qOpts); err != nil { 225 return fmt.Errorf("Failed to get node '%s' from Consul catalog: %v", node, err) 226 } 227 228 return nil 229 } 230 231 func resourceConsulCatalogEntryDelete(d *schema.ResourceData, meta interface{}) error { 232 client := meta.(*consulapi.Client) 233 catalog := client.Catalog() 234 235 var dc string 236 if v, ok := d.GetOk("datacenter"); ok { 237 dc = v.(string) 238 } else { 239 var err error 240 if dc, err = getDC(d, client); err != nil { 241 return err 242 } 243 } 244 245 var token string 246 if v, ok := d.GetOk("token"); ok { 247 token = v.(string) 248 } 249 250 // Setup the operations using the datacenter 251 wOpts := consulapi.WriteOptions{Datacenter: dc, Token: token} 252 253 address := d.Get("address").(string) 254 node := d.Get("node").(string) 255 256 deregistration := consulapi.CatalogDeregistration{ 257 Address: address, 258 Datacenter: dc, 259 Node: node, 260 } 261 262 if _, err := catalog.Deregister(&deregistration, &wOpts); err != nil { 263 return fmt.Errorf("Failed to deregister Consul catalog entry with node '%s' at address '%s' in %s: %v", 264 node, address, dc, err) 265 } 266 267 // Clear the ID 268 d.SetId("") 269 return nil 270 }