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 }