// serviceConfig constructs the config for all good instances of a single service. func serviceConfig(client *api.Client, name string, passing map[string]bool, tagPrefix string) (config []string) { if name == "" || len(passing) == 0 { return nil } q := &api.QueryOptions{RequireConsistent: true} svcs, _, err := client.Catalog().Service(name, "", q) if err != nil { log.Printf("[WARN] [%s] Error getting catalog service %s. %v", name, err) return nil } for _, svc := range svcs { // check if the instance is in the list of instances // which passed the health check if _, ok := passing[svc.ServiceID]; !ok { continue } for _, tag := range svc.ServiceTags { if host, path, ok := parseURLPrefixTag(tag, tagPrefix); ok { name, addr, port := svc.ServiceName, svc.ServiceAddress, svc.ServicePort if runtime.GOOS == "darwin" && !strings.Contains(addr, ".") { addr += ".local" } config = append(config, fmt.Sprintf("route add %s %s%s http://%s:%d/ tags %q", name, host, path, addr, port, strings.Join(svc.ServiceTags, ","))) } } } return config }
func putKV(client *api.Client, key, value string, index uint64) (bool, error) { p := &api.KVPair{Key: key[1:], Value: []byte(value), ModifyIndex: index} ok, _, err := client.KV().CAS(p, nil) if err != nil { return false, err } return ok, nil }
func getKV(client *api.Client, key string, waitIndex uint64) (string, uint64, error) { q := &api.QueryOptions{RequireConsistent: true, WaitIndex: waitIndex} kvpair, meta, err := client.KV().Get(key, q) if err != nil { return "", 0, err } if kvpair == nil { return "", meta.LastIndex, nil } return strings.TrimSpace(string(kvpair.Value)), meta.LastIndex, nil }
// datacenter returns the datacenter of the local agent func datacenter(c *api.Client) (string, error) { self, err := c.Agent().Self() if err != nil { return "", err } cfg, ok := self["Config"] if !ok { return "", errors.New("consul: self.Config not found") } dc, ok := cfg["Datacenter"].(string) if !ok { return "", errors.New("consul: self.Datacenter not found") } return dc, nil }
// watchAutoConfig monitors the consul health checks and creates a new configuration // on every change. func watchAutoConfig(client *api.Client, tagPrefix string, config chan []string) { var lastIndex uint64 for { q := &api.QueryOptions{RequireConsistent: true, WaitIndex: lastIndex} checks, meta, err := client.Health().State("passing", q) if err != nil { log.Printf("[WARN] Error fetching health state. %v", err) time.Sleep(time.Second) continue } log.Printf("[INFO] Health changed to #%d", meta.LastIndex) config <- servicesConfig(client, checks, tagPrefix) lastIndex = meta.LastIndex } }
func nextValue(client *api.Client, path string, lastIndex uint64) (string, uint64) { for { q := &api.QueryOptions{RequireConsistent: true, WaitIndex: lastIndex} kvpair, meta, err := client.KV().Get(path, q) if err != nil { log.Printf("[WARN] Error fetching config from %s. %v", path, err) time.Sleep(time.Second) continue } if kvpair == nil { return "", meta.LastIndex } return strings.TrimSpace(string(kvpair.Value)), meta.LastIndex } }