Beispiel #1
0
func dispatchCommand(c *cli.Context, client *etcd.Client, cmd *command.Command) {
	targets := c.StringSlice("target")
	if targets == nil || len(targets) == 0 {
		log.Warningln("no target set! try to send command to all registered host.")
		targets = fetchHosts(c, client)
	}
	if targets == nil {
		log.Fatalln("no target to send command.")
	} else {
		log.Infoln("send command to: ", targets)
	}
	for _, target := range targets {
		key := fmt.Sprintf("/beacon/commands/single/%s/%s/",
			target, cmd.Id)
		if c.GlobalString("prefix") != "" {
			key = fmt.Sprintf("/%s%s", strings.Trim(c.GlobalString("prefix"), "/"), key)
		}

		if _, err := client.Set(key, cmd.Marshal(), 0); err != nil {
			log.WithFields(log.Fields{
				"error": err.Error(),
			}).Fatalln("send command failed.")
		}
	}
}
Beispiel #2
0
func RemoveService(client *etcd.Client, s *Service) error {
	basekey := appendPrefix(fmt.Sprintf("/beacon/registry/%s/haproxy/%s",
		s.Cluster, s.Proto), s.Prefix)

	var key string
	if s.Proto == "tcp" {
		key = fmt.Sprintf("%s/%s", basekey, s.Name)
	} else {
		key = fmt.Sprintf("%s/%s/backends/%s", basekey, s.Name, s.Backend)
	}

	log.WithFields(log.Fields{
		"key": key,
	}).Debugln("start to delete a service key.")
	if _, err := client.Delete(key, true); err != nil {
		return err
	}
	log.WithFields(log.Fields{
		"name":    s.Name,
		"backend": s.Backend,
		"proto":   s.Proto,
	}).Infoln("service unregistered.")

	return nil
}
Beispiel #3
0
func acquire(c *etcd.Client, key, value string, ttl uint64) (uint64, error) {
	resp, err := c.Create(key, value, ttl)
	if err != nil {
		return 0, err
	}
	return resp.EtcdIndex, nil
}
Beispiel #4
0
func NewEtcdClient(addr string, dialTimeout time.Duration) (*EtcdClient, error) {
	var c *api.Client
	/*
		var err error
		if cert != "" && key != "" {
			c, err = etcd.NewTLSClient(machines, cert, key, caCert)
			if err != nil {
				return &Client{c}, err
			}
		} else {
			c = etcd.NewClient(machines)
		}
	*/

	// machine addresses
	machines := []string{addr}

	// create custom client
	c = api.NewClient(machines)
	if !c.SetCluster(machines) {
		return nil, errors.New("cannot connect to etcd cluster: " + addr)
	}

	// configure dial timeout
	c.SetDialTimeout(dialTimeout)

	return &EtcdClient{addr: addr, client: c}, nil
}
Beispiel #5
0
//Acquire will attempt to acquire the lock, if blocking is set to true it will wait forever to do so.
//Setting blocking to false would be the equivalent of a fictional TryAcquire, an immediate return
//if locking fails.
func Acquire(c *etcd.Client, key, value string, ttl uint64, blocking bool) (*Lock, error) {
	index := uint64(0)
	var err error
	tryAcquire := true
LOOP:
	for {
		if tryAcquire {
			index, err = acquire(c, key, value, ttl)
			if err == nil {
				break LOOP
			}
			if !blocking {
				return nil, err
			}
			tryAcquire = false
		}
		resp, err := c.Watch(key, 0, false, nil, nil)
		if err != nil {
			return nil, err
		}
		if resp.Action != "compareAndSwap" {
			tryAcquire = true
		}
	}
	return &Lock{
		c:     c,
		key:   key,
		value: value,
		ttl:   ttl,
		index: index,
		held:  true,
	}, nil
}
Beispiel #6
0
// NewEtcdClient returns an *etcd.Client with a connection to named machines.
// It returns an error if a connection to the cluster cannot be made.
func NewEtcdClient(machines []string, cert, key string, caCert string) (*Client, error) {
	var c *goetcd.Client
	var err error
	if cert != "" && key != "" {
		c, err = goetcd.NewTLSClient(machines, cert, key, caCert)
		if err != nil {
			return &Client{c}, err
		}
	} else {
		c = goetcd.NewClient(machines)
	}
	// Configure the DialTimeout, since 1 second is often too short
	c.SetDialTimeout(time.Duration(3) * time.Second)

	maxConnectAttempts := 10
	for attempt := 1; attempt <= maxConnectAttempts; attempt++ {
		success := c.SetCluster(machines)
		if success {
			break
			return &Client{c}, nil
		}

		if attempt == maxConnectAttempts {
			break
			return &Client{c}, errors.New("cannot connect to etcd cluster: " + strings.Join(machines, ","))
		}
		log.Info(fmt.Sprintf("[Attempt: %d] Attempting access to etcd after 5 second sleep", attempt))
		time.Sleep(5 * time.Second)
	}

	return &Client{c}, nil
}
Beispiel #7
0
// getAddress will return the host:port address of the service taking care of
// the task that we want to talk to.
// Currently we grab the information from etcd every time. Local cache could be used.
// If it failed, e.g. network failure, it should return error.
func GetAddress(client *etcd.Client, name string, id uint64) (string, error) {
	resp, err := client.Get(TaskMasterPath(name, id), false, false)
	if err != nil {
		return "", err
	}
	return resp.Node.Value, nil
}
Beispiel #8
0
func MustCreate(c *etcd.Client, logger *log.Logger, key, value string, ttl uint64) *etcd.Response {
	resp, err := c.Create(key, value, ttl)
	if err != nil {
		logger.Panicf("Create failed. Key: %s, err: %v", key, err)
	}
	return resp
}
Beispiel #9
0
func GetAndWatchEpoch(client *etcd.Client, appname string, epochC chan uint64, stop chan bool) (uint64, error) {
	resp, err := client.Get(EpochPath(appname), false, false)
	if err != nil {
		log.Fatal("etcdutil: can not get epoch from etcd")
	}
	ep, err := strconv.ParseUint(resp.Node.Value, 10, 64)
	if err != nil {
		return 0, err
	}
	receiver := make(chan *etcd.Response, 1)
	go client.Watch(EpochPath(appname), resp.EtcdIndex+1, false, receiver, stop)
	go func() {
		for resp := range receiver {
			if resp.Action != "compareAndSwap" && resp.Action != "set" {
				continue
			}
			epoch, err := strconv.ParseUint(resp.Node.Value, 10, 64)
			if err != nil {
				log.Fatal("etcdutil: can't parse epoch from etcd")
			}
			epochC <- epoch
		}
	}()

	return ep, nil
}
Beispiel #10
0
// latestRunningVersion retrieves the highest version of the application published
// to etcd. If no app has been published, returns 0.
func latestRunningVersion(client *etcd.Client, appName string) int {
	r := regexp.MustCompile(appNameRegex)
	if client == nil {
		// FIXME: client should only be nil during tests. This should be properly refactored.
		if appName == "ceci-nest-pas-une-app" {
			return 3
		}
		return 0
	}
	resp, err := client.Get(fmt.Sprintf("/deis/services/%s", appName), false, true)
	if err != nil {
		// no app has been published here (key not found) or there was an error
		return 0
	}
	var versions []int
	for _, node := range resp.Node.Nodes {
		match := r.FindStringSubmatch(node.Key)
		// account for keys that may not be an application container
		if match == nil {
			continue
		}
		version, err := strconv.Atoi(match[2])
		if err != nil {
			log.Println(err)
			return 0
		}
		versions = append(versions, version)
	}
	return max(versions)
}
Beispiel #11
0
func cleanup(r *bytes.Buffer, e *etcd.Client, ep *testProcess, dp *testProcess) {
	if r != nil {
		log.Debug("Writing report")
		rpath := testDir + "/report.txt"
		if err := ioutil.WriteFile(rpath, r.Bytes(), 0644); err != nil {
			log.WithFields(log.Fields{
				"error": err,
				"func":  "ioutil.WriteFile",
				"path":  rpath,
			}).Warning("Could not write report")
		}
	}
	if dp != nil {
		log.Debug("Exiting cdhcpd")
		_ = dp.finish()
		time.Sleep(time.Second)
	}
	if e != nil {
		log.Debug("Clearing test data")
		if _, err := e.Delete("/lochness", true); err != nil {
			log.WithFields(log.Fields{
				"error": err,
				"func":  "etcd.Delete",
			}).Warning("Could not clear test-created data from etcd")
		}
		time.Sleep(time.Second)
	}
	if ep != nil {
		log.Debug("Exiting etcd")
		_ = ep.finish()
	}
	log.Info("Done")
}
Beispiel #12
0
func etcdClientSetUp(t *testing.T, rawClient *etcd.Client) map[string]interface{} {
	var err error
	if _, err = rawClient.SetDir("test", 0); err != nil {
		t.Fatal(err)
	}
	if _, err = rawClient.Set("test/index", "1", 0); err != nil {
		t.Fatal(err)
	}
	if _, err = rawClient.SetDir("test/values", 0); err != nil {
		t.Fatal(err)
	}
	if _, err = rawClient.Set("test/values/a", "aye", 0); err != nil {
		t.Fatal(err)
	}
	if _, err = rawClient.Set("test/values/b", "bee", 0); err != nil {
		t.Fatal(err)
	}

	want := make(map[string]interface{})
	wantValues := make(map[string]interface{})
	wantValues["a"] = "aye"
	wantValues["b"] = "bee"
	want["values"] = wantValues
	want["index"] = "1"
	return want
}
func addDNS(record string, service *kapi.Service, etcdClient *etcd.Client) error {
	// if PortalIP is not set, a DNS entry should not be created
	if !kapi.IsServiceIPSet(service) {
		log.Printf("Skipping dns record for headless service: %s\n", service.Name)
		return nil
	}

	for i := range service.Spec.Ports {
		svc := skymsg.Service{
			Host:     service.Spec.PortalIP,
			Port:     service.Spec.Ports[i].Port,
			Priority: 10,
			Weight:   10,
			Ttl:      30,
		}
		b, err := json.Marshal(svc)
		if err != nil {
			return err
		}
		// Set with no TTL, and hope that kubernetes events are accurate.

		log.Printf("Setting DNS record: %v -> %s:%d\n", record, service.Spec.PortalIP, service.Spec.Ports[i].Port)
		_, err = etcdClient.Set(skymsg.Path(record), string(b), uint64(0))
		if err != nil {
			return err
		}
	}
	return nil
}
Beispiel #14
0
// SetKey is used to log key value pairs to stdout/etcd so that dray can pass
// them down to subsequent images as needed. By default keys are logged to
// stdout as ----BEGIN PANAMAX DATA----\nkey=value\n----END PANAMAX DATA----
// tags. If LOG_TO env var is set to etcd, then keys are logged to etcd.
// The etcd api is set using ETCD_API env variable.
func SetKey(key string, value string) error {
	logTo := os.Getenv("LOG_TO")
	if logTo == "" {
		logTo = "stdout"
	}
	logTo = strings.ToLower(logTo)

	if logTo == "etcd" {
		log.Info("Logging Keys to etcd...")
		var ec *etcd.Client
		eIP := os.Getenv("ETCD_API")
		if eIP == "" {
			eIP = "172.17.42.1:4001"
		}
		eIP = fmt.Sprintf("http://%s", eIP)
		ms := []string{eIP}
		ec = etcd.NewClient(ms)
		_, e := ec.Set(key, value, 0)

		if e != nil {
			return e
		}
	} else {
		fmt.Printf("\n----BEGIN PANAMAX DATA----\n%s=%s\n----END PANAMAX DATA----\n", key, value)
	}
	return nil
}
Beispiel #15
0
func NewEtcd(prefixKey string, config *EtcdConfig) (*Etcd, error) {
	var (
		client *etcd.Client
		err    error
	)

	if config.CertFile != "" && config.KeyFile != "" {
		if client, err = etcd.NewTLSClient(config.Machines, config.CertFile, config.KeyFile, config.CaFile); err != nil {
			Logger.Error("Failed to connect to Etcd. Error: %+v.", err)
			return nil, err
		}
	} else {
		client = etcd.NewClient(config.Machines)
	}

	// Set the default value if not provided.
	if config.EtcdConsistency == "" {
		config.EtcdConsistency = etcd.STRONG_CONSISTENCY
	}

	if err = client.SetConsistency(config.EtcdConsistency); err != nil {
		Logger.Error("Failed to set Etcd consitency. Error: %+v.", err)
		return nil, err
	}

	return &Etcd{client: client, prefixKey: prefixKey}, nil
}
Beispiel #16
0
func EtcdMkDir(client *etcd.Client, path string, ttl uint64) error {
	_, err := client.SetDir(path, ttl)
	if err != nil {
		return err
	}
	return nil
}
func getRuntimeConfFromEtcd(client *etcd.Client, etcd_path string) (*RuntimeConfig, error) {
	resp, err := client.Get(etcd_path, false, false)
	if err != nil {
		return nil, fmt.Errorf("failed to get RuntimeConfig:%v", err)
	}
	r := bytes.NewReader([]byte(resp.Node.Value))
	return ReadRuntimeConfig(r)
}
Beispiel #18
0
// SetEtcd sets an array of values into a test etcd instance.
func SetEtcd(t *testing.T, keys []string, values []string, c *etcd.Client) {
	for i, key := range keys {
		_, err := c.Set(key, values[i], 0)
		if err != nil {
			t.Fatal(err)
		}
	}
}
Beispiel #19
0
func (b *backends) Watch(client *etcd.Client) {
	receiver := make(chan *etcd.Response)
	go client.Watch(b.path, uint64(b.watchIndex), true, receiver, nil)

	for {
		resp := <-receiver
		b.Update(resp.Node, resp.Action)
	}
}
Beispiel #20
0
func beat(client *etcd.Client, ip string, conf *config.Config) {
	for {
		if _, err := client.Set(conf.Etcd_dir+"/"+ip, conf.Agent_id, uint64(conf.Heartbeat_interval*2)); err != nil {
			log.Fatal(err)
		}
		fmt.Printf("%v beat sent.\n", time.Now())
		time.Sleep(time.Second * time.Duration(conf.Heartbeat_interval))
	}
}
Beispiel #21
0
func AnnounceSite(id string, site Site, client *etcd.Client) {
	key := fmt.Sprintf("/nginx/sites/%s", id)
	value := FormatSite(site)

	client.Set(key, value, 60)
	log.Println("announcing", id, "as", value)
	time.Sleep(30 * time.Second)
	go AnnounceSite(id, site, client)
}
Beispiel #22
0
func addLockDirChild(client *etcd.Client, key string) (*etcd.Response, error) {
	hostname, err := os.Hostname()
	if err != nil {
		return nil, errgo.Notef(err, "fail to get hostname")
	}
	client.SyncCluster()

	return client.AddChild(key, hostname, 0)
}
Beispiel #23
0
func setDirCommandFunc(cmd *cobra.Command, args []string, client *etcd.Client) (*etcd.Response, error) {
	if len(args) == 0 {
		return nil, errors.New("Key required")
	}
	key := args[0]
	ttl := ttlFlag

	return client.SetDir(key, uint64(ttl))
}
Beispiel #24
0
func unlock(c *etcd.Client) {
	for {
		_, err := c.Set("lock", "unlock", 0)
		if err == nil {
			return
		}
		fmt.Println(err)
	}
}
Beispiel #25
0
// On any change we just refresh everything
func handleChange(etcdClient *etcd.Client) {

	resp, err := etcdClient.Get(etcdWatchKey, false, true)
	if err != nil {
		fmt.Println(err)
		return
	}

	// Go and fetch all the services in REDIS
	redisClient := clients.RedisClient()
	if (redisClient == nil) {
		fmt.Println("Couldn't connect to redis")
		return
	}
	defer redisClient.Close()

	keys, err := redis.Strings(redisClient.Do("KEYS", "frontend:*"))
	if err != nil {
		fmt.Println(err)
		return
	}

	// Now we delete everything in redis and add everything back in from etcd
	redisClient.Send("MULTI")
	if len(keys) > 0 {
		redisClient.Send("DEL", redis.Args{}.AddFlat(keys)...)
	}

	for _, node := range resp.Node.Nodes {
		// This first level is a frontend
		split := strings.Split(node.Key, "/")
		domain := split[len(split) - 1]

		frontendKey := "frontend:" + domain

		// Belt and braces - delete this key just in case its not already (but it should be)
		redisClient.Send("DEL", frontendKey)
		redisClient.Send("RPUSH", frontendKey, domain)

		for _, instNode := range node.Nodes {
			instsplit := strings.Split(instNode.Key, "/")
			inst := instsplit[len(instsplit) - 1]
			host := "http://" + inst
			redisClient.Send("RPUSH", frontendKey, host)
		}
	}

	// Should be everything
	_, err = redisClient.Do("EXEC")
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("Resynced hipache from etcd")
}
Beispiel #26
0
func get(e *etcd.Client, q string, t uint16) ([]dns.RR, error) {
	path := questionToPath(q, t)
	r, err := e.Get(path, false, false)
	if err != nil {
		return nil, err
	}
	h := dns.RR_Header{Name: q, Rrtype: t, Class: dns.ClassINET, Ttl: 60} // Ttl is overridden
	rr := parseValue(t, r.Node.Value, h)
	return []dns.RR{rr}, nil
}
Beispiel #27
0
func getCurrentVersion(client *etcd.Client, key string) *etcd.Response {
	for {
		if resp, err := client.Get(key, false, false); err == nil {
			// failed to fetch first value
			return resp
		} else {
			time.Sleep(time.Second)
		}
	}
}
Beispiel #28
0
func newAdapter(client *etcd.Client, workPool *workpool.WorkPool) *ETCDStoreAdapter {
	client.SetConsistency(etcd.STRONG_CONSISTENCY)

	return &ETCDStoreAdapter{
		client:            client,
		workPool:          workPool,
		inflightWatches:   map[chan bool]bool{},
		inflightWatchLock: &sync.Mutex{},
	}
}
Beispiel #29
0
func getEtcdValueOrDefault(c *etcd.Client, key string, defaultValue string) string {
	resp, err := c.Get(key, false, false)
	if err != nil {
		if strings.Contains(fmt.Sprintf("%v", err), "Key not found") {
			return defaultValue
		}
		assert(err, "url")
	}
	return resp.Node.Value
}
Beispiel #30
-1
// CanConnect checks a given SSH key against the list of authorized users in etcd
// to check if a user with a given key is allowed to connect. It takes in an active
// etcd.Client struct pointer and the ssh key to test and returns a username
// and boolean representing if they are allowed to connect.
func CanConnect(e *etcd.Client, sshkey string) (user string, allowed bool) {
	reply, err := e.Get("/flitter/builder/users/", true, true)

	if err != nil {
		log.Printf("etcd: %s", err)
		return "", false
	}

	keybit := strings.Split(sshkey, " ")[1]
	fp := GetFingerprint(keybit)

	for _, userdir := range reply.Node.Nodes {
		for _, fpnode := range userdir.Nodes {
			thisFpSplit := strings.Split(fpnode.Key, "/")
			thisFp := thisFpSplit[len(thisFpSplit)-1]

			if fp == thisFp {
				userpath := strings.Split(userdir.Key, "/")
				user := userpath[len(userpath)-1]
				return user, true
			}
		}
	}

	return
}