// Create etcd directory structure from a map, slice or struct. func Create(kapi client.KeysAPI, path string, val reflect.Value) error { switch val.Kind() { case reflect.Ptr: orig := val.Elem() if !orig.IsValid() { return nil } if err := Create(kapi, path, orig); err != nil { return err } case reflect.Interface: orig := val.Elem() if err := Create(kapi, path, orig); err != nil { return err } case reflect.Struct: for i := 0; i < val.NumField(); i++ { t := val.Type().Field(i) k := t.Tag.Get("etcd") if err := Create(kapi, path+"/"+k, val.Field(i)); err != nil { return err } } case reflect.Map: if strings.HasPrefix(pathx.Base(path), "_") { log.Printf("create hidden directory in etcd: %s", path) } for _, k := range val.MapKeys() { v := val.MapIndex(k) if err := Create(kapi, path+"/"+k.String(), v); err != nil { return err } } case reflect.Slice: for i := 0; i < val.Len(); i++ { Create(kapi, fmt.Sprintf("%s/%d", path, i), val.Index(i)) } case reflect.String: if strings.HasPrefix(pathx.Base(path), "_") { log.Printf("set hidden key in etcd: %s", path) } _, err := kapi.Set(context.TODO(), path, val.String(), nil) if err != nil { return err } case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64: if strings.HasPrefix(pathx.Base(path), "_") { log.Printf("set hidden key in etcd: %s", path) } _, err := kapi.Set(context.TODO(), path, fmt.Sprintf("%v", val.Interface()), nil) if err != nil { return err } default: return fmt.Errorf("unsupported type: %s for path: %s", val.Kind(), path) } return nil }
// mkCommandFunc executes the "mk" command. func mkCommandFunc(c *cli.Context, ki client.KeysAPI) { if len(c.Args()) == 0 { handleError(ExitBadArgs, errors.New("key required")) } key := c.Args()[0] value, err := argOrStdin(c.Args(), os.Stdin, 1) if err != nil { handleError(ExitBadArgs, errors.New("value required")) } ttl := c.Int("ttl") ctx, cancel := contextWithTotalTimeout(c) // Since PrevNoExist means that the Node must not exist previously, // this Set method always creates a new key. Therefore, mk command // succeeds only if the key did not previously exist, and the command // prevents one from overwriting values accidentally. resp, err := ki.Set(ctx, key, value, &client.SetOptions{TTL: time.Duration(ttl) * time.Second, PrevExist: client.PrevNoExist}) cancel() if err != nil { handleError(ExitServerError, err) } printResponseKey(resp, c.GlobalString("output")) }
func mustCreateServiceDirectory(ctx context.Context, kApi etcd.KeysAPI, basepath string) { myContext, myCancel := context.WithTimeout(ctx, DefaultTimeout) defer myCancel() _, err := kApi.Set(myContext, basepath, "", &etcd.SetOptions{Dir: true, PrevExist: etcd.PrevNoExist}) log.WithField("error", err).Warn("error creating servicedef directory") }
func doServerBeat(kapi client.KeysAPI) { var key = runningbase + *serverbeatname myuuid := uuid.NewV4() uuidstring := myuuid.String() fmt.Println("Badum") _, err := kapi.Set(context.TODO(), key, uuidstring, &client.SetOptions{PrevExist: client.PrevNoExist, TTL: time.Second * 60}) if err != nil { log.Fatal(err) } running := true counter := *serverbeatcount for running { time.Sleep(time.Second * time.Duration(*serverbeattime)) fmt.Println("Badum") _, err := kapi.Set(context.TODO(), key, uuidstring, &client.SetOptions{PrevExist: client.PrevExist, TTL: time.Second * 60, PrevValue: uuidstring}) if err != nil { log.Fatal(err) } if *serverbeatcount != 0 { counter = counter - 1 if counter == 0 { running = false } } } _, err = kapi.Delete(context.TODO(), key, &client.DeleteOptions{PrevValue: uuidstring}) if err != nil { log.Fatal(err) } }
// mkCommandFunc executes the "mk" command. func mkCommandFunc(c *cli.Context, ki client.KeysAPI) { if len(c.Args()) == 0 { handleError(ExitBadArgs, errors.New("key required")) } key := c.Args()[0] value, err := argOrStdin(c.Args(), os.Stdin, 1) if err != nil { handleError(ExitBadArgs, errors.New("value required")) } ttl := c.Int("ttl") inorder := c.Bool("in-order") var resp *client.Response ctx, cancel := contextWithTotalTimeout(c) if !inorder { // Since PrevNoExist means that the Node must not exist previously, // this Set method always creates a new key. Therefore, mk command // succeeds only if the key did not previously exist, and the command // prevents one from overwriting values accidentally. resp, err = ki.Set(ctx, key, value, &client.SetOptions{TTL: time.Duration(ttl) * time.Second, PrevExist: client.PrevNoExist}) } else { // If in-order flag is specified then create an inorder key under // the directory identified by the key argument. resp, err = ki.CreateInOrder(ctx, key, value, &client.CreateInOrderOptions{TTL: time.Duration(ttl) * time.Second}) } cancel() if err != nil { handleError(ExitServerError, err) } printResponseKey(resp, c.GlobalString("output")) }
func Store(api etcd.KeysAPI, path string, ttl time.Duration) frameworkid.Storage { // TODO(jdef) validate Config return &storage{ LookupFunc: func(ctx context.Context) (string, error) { if response, err := api.Get(ctx, path, nil); err != nil { if !etcdutil.IsEtcdNotFound(err) { return "", fmt.Errorf("unexpected failure attempting to load framework ID from etcd: %v", err) } } else { return response.Node.Value, nil } return "", nil }, RemoveFunc: func(ctx context.Context) (err error) { if _, err = api.Delete(ctx, path, &etcd.DeleteOptions{Recursive: true}); err != nil { if !etcdutil.IsEtcdNotFound(err) { return fmt.Errorf("failed to delete framework ID from etcd: %v", err) } } return }, StoreFunc: func(ctx context.Context, id string) (err error) { _, err = api.Set(ctx, path, id, &etcd.SetOptions{TTL: ttl}) return }, } }
func setJob(ctx context.Context, kapi client.KeysAPI, j *job) error { errChan := make(chan error) done := make(chan struct{}) go func() { buf := new(bytes.Buffer) if err := json.NewEncoder(buf).Encode(j); err != nil { errChan <- err return } value := buf.String() fmt.Println("setJob:", value) opts := &client.SetOptions{} if _, err := kapi.Set(ctx, j.ETCDKey, value, opts); err != nil { errChan <- err return } done <- struct{}{} }() select { case <-done: return nil case v := <-errChan: return v case <-ctx.Done(): return ctx.Err() } }
func sync(kapi client.KeysAPI, syncChannel chan blocker.ControlMsg) { for { msg := <-syncChannel start := time.Now() var folder string if msg.Ip.To4() == nil { folder = "dblock6/" } else { folder = "dblock/" } _, err := kapi.Set(context.Background(), folder+msg.Ip.String(), "0", &client.SetOptions{TTL: 60 * time.Second, PrevExist: client.PrevNoExist}) if err != nil { if err.(client.Error).Code == client.ErrorCodeNodeExist { log.Print("Block already existed, not adding again") } else { log.Fatal(err) } } else { // print common key info log.Println("[sync]\tAdded block: " + msg.Ip.String()) } elapsed := time.Since(start) log.Printf("sync took %s", elapsed) sync_timing.Observe(elapsed.Seconds()) } }
func NewPubSubTopicByKey(ctx context.Context, keyid string, ttl time.Duration, kapi etcdc.KeysAPI) (*EtcdPubSubTopic, error) { _, err := kapi.Get(ctx, keyid, nil) if IsKeyNotFound(err) { opt := &etcdc.SetOptions{PrevExist: etcdc.PrevNoExist, TTL: ttl, Dir: true} _, err = kapi.Set(ctx, keyid, "", opt) if err != nil && !IsCompareAndSwapFailure(err) && !IsNodeExists(err) { return nil, err } } else if err != nil { return nil, err } keepalive, err := NewNodeKeepAlive(keyid, ttl, kapi) if err != nil { return nil, err } dlog("signal: new signal(pub/sub) for %v, ttl:%v", keyid, ttl) return &EtcdPubSubTopic{ ctx: ctx, keyid: keyid, kapi: kapi, ttl: ttl, keepalive: keepalive, stop: make(chan bool), }, nil }
func setValues(kapi client.KeysAPI, kvs map[string]string) error { for k, v := range kvs { if _, err := kapi.Set(context.Background(), k, v, &client.SetOptions{}); err != nil { return err } } return nil }
func importFunc(dir string, file string, f iodatafmt.DataFmt, replace bool, yes bool, e Etcdtool, c *cli.Context, ki client.KeysAPI) { // Check if dir exists and is a directory. exists, err := dirExists(dir, c, ki) if err != nil { fatalf("Specified dir doesn't exist: %s", dir) } if exists { exist, err := isDir(dir, c, ki) if err != nil { fatal(err.Error()) } if exist { fatalf("Specified dir is not a directory: %s", dir) } } // Load file. m, err := iodatafmt.Load(file, f) if err != nil { fatal(err.Error()) } // Validate data. if c.Bool("validate") { validateFunc(e, dir, m) } if exists { if replace { if !askYesNo(fmt.Sprintf("Do you want to overwrite data in directory: %s", dir)) { os.Exit(1) } // Delete dir. if _, err = ki.Delete(context.TODO(), dir, &client.DeleteOptions{Recursive: true}); err != nil { fatal(err.Error()) } } else { if !yes { if !askYesNo(fmt.Sprintf("Do you want to overwrite data in directory: %s", dir)) { os.Exit(1) } } } } else { // Create dir. if _, err := ki.Set(context.TODO(), dir, "", &client.SetOptions{Dir: true}); err != nil { fatal(err.Error()) } } // Import data. if err = etcdmap.Create(ki, dir, reflect.ValueOf(m)); err != nil { fatal(err.Error()) } }
func setHostPort(k client.KeysAPI, base, host, port string, ttl time.Duration) error { o := client.SetOptions{TTL: ttl} if _, err := k.Set(dctx(), base+"/host", host, &o); err != nil { return err } if _, err := k.Set(dctx(), base+"/port", port, &o); err != nil { return err } return nil }
func doConfig(kapi client.KeysAPI) { var key = configbase + *configserver + "/" + *configvar resp, err := kapi.Set(context.TODO(), key, *configval, nil) if err != nil { log.Fatal(err) } fmt.Println(resp.Action + " " + resp.Node.Key + " to " + resp.Node.Value) }
func (s *Server) put(ctx context.Context, client etcd.KeysAPI, vulcanpath, servicename, instancename string) error { myContext, cancel := context.WithTimeout(ctx, DefaultTimeout) defer cancel() key := fmt.Sprintf(serverPathPattern, vulcanpath, servicename, instancename) se, err := json.Marshal(s) if err != nil { return err } _, err = client.Set(myContext, key, fmt.Sprintf("%s", se), &etcd.SetOptions{TTL: serverTTL, PrevExist: etcd.PrevIgnore}) return err }
func (b *Backend) put(ctx context.Context, client etcd.KeysAPI, vulcanpath, servicename string) error { myContext, cancel := context.WithTimeout(ctx, DefaultTimeout) defer cancel() key := fmt.Sprintf(backendPathPattern, vulcanpath, servicename) be, err := json.Marshal(b) if err != nil { return err } _, err = client.Set(myContext, key, fmt.Sprintf("%s", be), &etcd.SetOptions{TTL: 0, PrevExist: etcd.PrevIgnore}) return err }
// createDir will create path if it doesn't exist and is not root. func createDir(kapi client.KeysAPI, path string) error { if path != "/" { if _, err := kapi.Set(context.TODO(), path, "", &client.SetOptions{Dir: true, PrevExist: client.PrevNoExist}); err != nil { if etcdErr, ok := err.(client.Error); ok { if etcdErr.Code == client.ErrorCodeNodeExist { return nil } } return err } } return nil }
func noRetryList(kapi client.KeysAPI) []func() error { return []func() error{ func() error { opts := &client.SetOptions{PrevExist: client.PrevNoExist} _, err := kapi.Set(context.Background(), "/setkey", "bar", opts) return err }, func() error { _, err := kapi.Delete(context.Background(), "/delkey", nil) return err }, } }
// mkdirCommandFunc executes the "mkdir" command. func mkdirCommandFunc(c *cli.Context, ki client.KeysAPI, prevExist client.PrevExistType) { if len(c.Args()) == 0 { handleError(ExitBadArgs, errors.New("key required")) } key := c.Args()[0] ttl := c.Int("ttl") _, err := ki.Set(context.TODO(), key, "", &client.SetOptions{TTL: time.Duration(ttl) * time.Second, Dir: true, PrevExist: prevExist}) if err != nil { handleError(ExitServerError, err) } }
// updatedirCommandFunc executes the "updatedir" command. func updatedirCommandFunc(c *cli.Context, ki client.KeysAPI) { if len(c.Args()) == 0 { handleError(ExitBadArgs, errors.New("key required")) } key := c.Args()[0] ttl := c.Int("ttl") ctx, cancel := contextWithTotalTimeout(c) _, err := ki.Set(ctx, key, "", &client.SetOptions{TTL: time.Duration(ttl) * time.Second, Dir: true, PrevExist: client.PrevExist}) cancel() if err != nil { handleError(ExitServerError, err) } }
func runSet(ki client.KeysAPI, setc chan set, wg *sync.WaitGroup) { for s := range setc { log.Println("copying key:", s.key) if s.ttl != 0 && s.ttl < 300 { log.Printf("extending key %s's ttl to 300 seconds", s.key) s.ttl = 5 * 60 } _, err := ki.Set(context.TODO(), s.key, s.value, &client.SetOptions{TTL: time.Duration(s.ttl) * time.Second}) if err != nil { log.Fatalf("failed to copy key: %v\n", err) } } wg.Done() }
// updatedirCommandFunc executes the "updatedir" command. func updatedirCommandFunc(c *cli.Context, ki client.KeysAPI) { if len(c.Args()) == 0 { handleError(ExitBadArgs, errors.New("key required")) } key := c.Args()[0] value, err := argOrStdin(c.Args(), os.Stdin, 1) if err != nil { handleError(ExitBadArgs, errors.New("value required")) } ttl := c.Int("ttl") _, err = ki.Set(context.TODO(), key, value, &client.SetOptions{TTL: time.Duration(ttl) * time.Second, Dir: true, PrevExist: client.PrevExist}) if err != nil { handleError(ExitServerError, err) } }
func (s *v2Stresser) run(ctx context.Context, kv clientV2.KeysAPI) { for { if err := s.rateLimiter.Wait(ctx); err == context.Canceled { return } setctx, setcancel := context.WithTimeout(ctx, clientV2.DefaultRequestTimeout) key := fmt.Sprintf("foo%016x", rand.Intn(s.keySuffixRange)) _, err := kv.Set(setctx, key, string(randBytes(s.keySize)), nil) if err == nil { atomic.AddInt64(&s.atomicModifiedKey, 1) } setcancel() if err == context.Canceled { return } } }
// mkdirCommandFunc executes the "mkdir" command. func mkdirCommandFunc(c *cli.Context, ki client.KeysAPI, prevExist client.PrevExistType) { if len(c.Args()) == 0 { handleError(ExitBadArgs, errors.New("key required")) } key := c.Args()[0] ttl := c.Int("ttl") ctx, cancel := contextWithTotalTimeout(c) resp, err := ki.Set(ctx, key, "", &client.SetOptions{TTL: time.Duration(ttl) * time.Second, Dir: true, PrevExist: prevExist}) cancel() if err != nil { handleError(ExitServerError, err) } if c.GlobalString("output") != "simple" { printResponseKey(resp, c.GlobalString("output")) } }
// NewRuntimeConfiguration initialize etcd tree, do some validations, and returns a ready RuntimeConfiguration func NewRuntimeConfiguration(dataSource etcd.KeysAPI, etcdClient etcd.Client, etcdDir string, workspacePath string) (*RuntimeConfiguration, error) { data, err := ioutil.ReadFile(filepath.Join(workspacePath, "initial.yaml")) if err != nil { return nil, fmt.Errorf("Error while trying to read initial data: %s", err) } var iVals initialValues err = yaml.Unmarshal(data, &iVals) if err != nil { return nil, fmt.Errorf("Error while reading initial data: %s", err) } if iVals.CoreOSVersion == "" { return nil, errors.New("A valid initial CoreOS version is required in initial data") } fmt.Printf("Initial Values: CoreOSVersion=%s\n", iVals.CoreOSVersion) instance := &RuntimeConfiguration{ DataSource: dataSource, EtcdClient: etcdClient, EtcdDir: etcdDir, WorkspacePath: workspacePath, initialCoreOSVersion: iVals.CoreOSVersion, } _, err = instance.GetCoreOSVersion() if err != nil { etcdError, found := err.(etcd.Error) if found && etcdError.Code == etcd.ErrorCodeKeyNotFound { // Initializing ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() _, err = dataSource.Set(ctx, path.Join(etcdDir, "/coreos-version"), iVals.CoreOSVersion, nil) if err != nil { return nil, fmt.Errorf("Error while initializing etcd tree: %s", err) } fmt.Printf("Initialized etcd tree (%s)", etcdDir) } else { return nil, fmt.Errorf("Error while checking GetCoreOSVersion: %s", err) } } return instance, nil }
// updateCommandFunc executes the "update" command. func updateCommandFunc(c *cli.Context, ki client.KeysAPI) { if len(c.Args()) == 0 { handleError(ExitBadArgs, errors.New("key required")) } key := c.Args()[0] value, err := argOrStdin(c.Args(), os.Stdin, 1) if err != nil { handleError(ExitBadArgs, errors.New("value required")) } ttl := c.Int("ttl") resp, err := ki.Set(context.TODO(), key, value, &client.SetOptions{TTL: time.Duration(ttl) * time.Second, PrevExist: client.PrevExist}) if err != nil { handleError(ExitServerError, err) } printResponseKey(resp, c.GlobalString("output")) }
func makeTimestamps(kAPI client.KeysAPI, dir string, dry bool) { for { for { if dry { break } keyshort := strconv.FormatInt(time.Now().UnixNano(), 16) key := fmt.Sprintf("%016s", keyshort) _, err := kAPI.Set(context.TODO(), path.Join(dir, key), "timestamp", &client.SetOptions{}) if err == nil { break } } fmt.Printf("made a timestamp at %v, sleeping for a day to make another one\n", time.Now()) time.Sleep(day) } }
// put updates/creates the job. func put(kapi client.KeysAPI, job *Job) error { job.FinishedTimestamp = time.Now().UTC().String()[:19] buf := new(bytes.Buffer) if err := json.NewEncoder(buf).Encode(job); err != nil { return err } value := buf.String() if _, err := kapi.Set(context.Background(), ctx, job.ETCDKey, value, nil); err != nil { if err == context.Canceled { return fmt.Errorf("ctx is canceled by another routine") } else if err == context.DeadlineExceeded { return fmt.Errorf("ctx is attached with a deadline and it exceeded") } else if cerr, ok := err.(*client.ClusterError); ok { return fmt.Errorf("*client.ClusterError %v", cerr.Errors()) } else { return fmt.Errorf("bad cluster endpoints, which are not etcd servers: %+v", err) } } return nil }
// setCommandFunc executes the "set" command. func setCommandFunc(c *cli.Context, ki client.KeysAPI) { if len(c.Args()) == 0 { handleError(ExitBadArgs, errors.New("key required")) } key := c.Args()[0] value, err := argOrStdin(c.Args(), os.Stdin, 1) if err != nil { handleError(ExitBadArgs, errors.New("value required")) } ttl := c.Int("ttl") prevValue := c.String("swap-with-value") prevIndex := c.Int("swap-with-index") // TODO: handle transport timeout resp, err := ki.Set(context.TODO(), key, value, &client.SetOptions{TTL: time.Duration(ttl) * time.Second, PrevIndex: uint64(prevIndex), PrevValue: prevValue}) if err != nil { handleError(ExitServerError, err) } printResponseKey(resp, c.GlobalString("output")) }
func compareAndSwapUntil(ctx context.Context, tries int, keyid string, kapi etcdc.KeysAPI, evaluator func(res *etcdc.Response, setOpts *etcdc.SetOptions) (val string, err error), ) error { //uncomment for debugging.. id := int64(0) if Usedtracedlogging { id = dice().Int63() } for i := 0; i < tries; i++ { resp, err := kapi.Get(ctx, keyid, &etcdc.GetOptions{Quorum: true}) if err != nil { dlog("%v kapi get error %v", keyid, err) return err } opt := &etcdc.SetOptions{} nv, err := evaluator(resp, opt) if err != nil { dlog("%v eval error %v", keyid, err) return err } dtrace("before: %v \tnewval:%v try:%v idx:%v key:%v", id, nv, i, resp.Index, keyid) _, err = kapi.Set(ctx, keyid, nv, opt) if err == nil { dlog("%v update successful %v", keyid, err) return nil } else if !IsCompareAndSwapFailure(err) { dlog("unexpected error %v", err) return err } dtrace("after : %v \tnewval:%v try:%v key:%v error: %v", id, nv, i, keyid, err) backoff(i) } return CASErrorOutOfRetries }
// keysToEtcd copies local keys into etcd. // // It only fails if it cannot copy ssh_host_key to sshHostKey. All other // abnormal conditions are logged, but not considered to be failures. func keysToEtcd(c cookoo.Context, k client.KeysAPI, ciphers []string, etcdPath string) error { lpath := "/etc/ssh/ssh_host_%s_key" privkey := "%s/sshHost%sKey" for _, cipher := range ciphers { path := fmt.Sprintf(lpath, cipher) key := fmt.Sprintf(privkey, etcdPath, cipher) content, err := ioutil.ReadFile(path) if err != nil { log.Infof(c, "No key named %s", path) } else if _, err := k.Set(dctx(), key, string(content), &client.SetOptions{}); err != nil { log.Errf(c, "Could not store ssh key in etcd: %s", err) } } // Now we set the generic key: if content, err := ioutil.ReadFile("/etc/ssh/ssh_host_key"); err != nil { log.Errf(c, "Could not read the ssh_host_key file.") return err } else if _, err := k.Set(dctx(), "sshHostKey", string(content), &client.SetOptions{}); err != nil { log.Errf(c, "Failed to set sshHostKey in etcd.") return err } return nil }