// etcd needs to be initialized beforehand func TestControllerInitEtcdLayout(t *testing.T) { etcdClient := etcd.NewClient([]string{"http://localhost:4001"}) tests := []struct { name string numberOfTasks uint64 }{ {"test-1", 2}, {"test-2", 4}, } for i, tt := range tests { c := New(tt.name, etcdClient, tt.numberOfTasks, []string{"Parents", "Children"}) c.InitEtcdLayout() for taskID := uint64(0); taskID < tt.numberOfTasks; taskID++ { key := etcdutil.FreeTaskPath(c.name, strconv.FormatUint(taskID, 10)) if _, err := etcdClient.Get(key, false, false); err != nil { t.Errorf("task %d: etcdClient.Get %v failed: %v", i, key, err) } key = etcdutil.MetaPath(c.name, taskID) if _, err := etcdClient.Get(key, false, false); err != nil { t.Errorf("task %d: etcdClient.Get %v failed: %v", i, key, err) } } c.DestroyEtcdLayout() } }
// watch meta flag and receive any notification. func (f *framework) watchMeta() { watchPath := etcdutil.MetaPath(f.name, f.taskID) // The function parses the watch response of meta flag, and passes the result // to central event handling. responseHandler := func(resp *etcd.Response) { // Note: Why "get"? // We first try to get the index. If there's value in it, we also parse it. if resp.Action != "set" && resp.Action != "get" { return } epoch, taskID, linkType, meta, err := parseMetaValue(resp.Node.Value) if err != nil { f.log.Panicf("parseMetaValue failed: %v", err) } f.metaChan <- &metaChange{ from: taskID, epoch: epoch, linkType: linkType, meta: meta, } } f.metaWatchStop = make(chan bool, 1) // Need to pass in taskID to make it work. Didn't know why. err := etcdutil.WatchMeta(f.etcdClient, watchPath, f.metaWatchStop, responseHandler) if err != nil { f.log.Panicf("WatchMeta failed. path: %s, err: %v", watchPath, err) } }
func (f *framework) FlagMeta(ctx context.Context, linkType, meta string) { epoch, ok := ctx.Value(epochKey).(uint64) if !ok { f.log.Panicf("Can not find epochKey in FlagMeta, epoch: %d", epoch) } // send the meta change notification to every task of specified link type. for _, id := range f.topology[linkType].GetNeighbors(epoch) { // The value is made of "epoch-fromID-metadata" // // Epoch is prepended to meta. When a new one starts and replaces // the old one, it doesn't need to handle previous things, whose // epoch is smaller than current one. value := fmt.Sprintf("%d-%d-%s-%s", epoch, f.taskID, linkType, meta) _, err := f.etcdClient.Set(etcdutil.MetaPath(f.name, id), value, 0) if err != nil { f.log.Panicf("etcdClient.Set failed; key: %s, value: %s, error: %v", etcdutil.MetaPath(f.name, id), value, err) } } }
func (c *Controller) InitEtcdLayout() error { // Initilize the job epoch to 0 etcdutil.MustCreate(c.etcdclient, c.logger, etcdutil.EpochPath(c.name), "0", 0) c.setupWatchOnJobStatus() // initiate etcd data layout for tasks // currently it creates as many unassigned tasks as task masters. for i := uint64(0); i < c.numOfTasks; i++ { key := etcdutil.FreeTaskPath(c.name, strconv.FormatUint(i, 10)) etcdutil.MustCreate(c.etcdclient, c.logger, key, "", 0) key = etcdutil.MetaPath(c.name, i) etcdutil.MustCreate(c.etcdclient, c.logger, key, "", 0) } return nil }