func (s *FakeDSStore) Create( manifest manifest.Manifest, minHealth int, name fields.ClusterName, nodeSelector klabels.Selector, podID types.PodID, timeout time.Duration, ) (fields.DaemonSet, error) { id := fields.ID(uuid.New()) ds := fields.DaemonSet{ ID: id, Disabled: false, Manifest: manifest, MinHealth: minHealth, Name: name, NodeSelector: nodeSelector, PodID: podID, Timeout: timeout, } s.writeLock.Lock() defer s.writeLock.Unlock() if _, ok := s.daemonSets[id]; ok { return ds, util.Errorf("Daemon set uuid collision on id: %v", id) } s.daemonSets[id] = ds return ds, nil }
// these parts of Create may require a retry func (s *consulStore) innerCreate( manifest manifest.Manifest, minHealth int, name fields.ClusterName, nodeSelector klabels.Selector, podID types.PodID, timeout time.Duration, ) (fields.DaemonSet, error) { id := fields.ID(uuid.New()) dsPath, err := s.dsPath(id) if err != nil { return fields.DaemonSet{}, util.Errorf("Error getting daemon set path: %v", err) } ds := fields.DaemonSet{ ID: id, Disabled: false, Manifest: manifest, MinHealth: minHealth, Name: name, NodeSelector: nodeSelector, PodID: podID, Timeout: timeout, } // Marshals ds into []bytes using overloaded MarshalJSON rawDS, err := json.Marshal(ds) if err != nil { return fields.DaemonSet{}, util.Errorf("Could not marshal DS as json: %s", err) } success, _, err := s.kv.CAS(&api.KVPair{ Key: dsPath, Value: rawDS, ModifyIndex: 0, }, nil) if err != nil { return fields.DaemonSet{}, consulutil.NewKVError("cas", dsPath, err) } if !success { return fields.DaemonSet{}, CASError(dsPath) } return ds, nil }
func main() { cmd, consulOpts := flags.ParseWithConsulOptions() client := kp.NewConsulClient(consulOpts) logger := logging.NewLogger(logrus.Fields{}) dsstore := dsstore.NewConsul(client, 3, &logger) applicator := labels.NewConsulApplicator(client, 3) switch cmd { case CmdCreate: minHealth, err := strconv.Atoi(*createMinHealth) if err != nil { log.Fatalf("Invalid value for minimum health, expected integer: %v", err) } name := ds_fields.ClusterName(*createName) manifest, err := manifest.FromPath(*createManifest) if err != nil { log.Fatalf("%s", err) } podID := manifest.ID() if *createTimeout <= time.Duration(0) { log.Fatalf("Timeout must be a positive non-zero value, got '%v'", *createTimeout) } selectorString := *createSelector if *createEverywhere { selectorString = klabels.Everything().String() } else if selectorString == "" { selectorString = klabels.Nothing().String() log.Fatal("Explicit everything selector not allowed, please use the --everwhere flag") } selector, err := parseNodeSelectorWithPrompt(klabels.Nothing(), selectorString, applicator) if err != nil { log.Fatalf("Error occurred: %v", err) } if err = confirmMinheathForSelector(minHealth, selector, applicator); err != nil { log.Fatalf("Error occurred: %v", err) } ds, err := dsstore.Create(manifest, minHealth, name, selector, podID, *createTimeout) if err != nil { log.Fatalf("err: %v", err) } fmt.Printf("%v has been created in consul", ds.ID) fmt.Println() case CmdGet: id := ds_fields.ID(*getID) ds, _, err := dsstore.Get(id) if err != nil { log.Fatalf("err: %v", err) } bytes, err := json.Marshal(ds) if err != nil { logger.WithError(err).Fatalln("Unable to marshal daemon set as JSON") } fmt.Printf("%s", bytes) case CmdList: dsList, err := dsstore.List() if err != nil { log.Fatalf("err: %v", err) } podID := types.PodID(*listPod) for _, ds := range dsList { if *listPod == "" || podID == ds.PodID { fmt.Printf("%s/%s:%s\n", ds.PodID, ds.Name, ds.ID) } } case CmdEnable: id := ds_fields.ID(*enableID) mutator := func(ds ds_fields.DaemonSet) (ds_fields.DaemonSet, error) { if !ds.Disabled { return ds, util.Errorf("Daemon set has already been enabled") } ds.Disabled = false return ds, nil } _, err := dsstore.MutateDS(id, mutator) if err != nil { log.Fatalf("err: %v", err) } fmt.Printf("The daemon set '%s' has been successfully enabled in consul", id.String()) fmt.Println() case CmdDisable: id := ds_fields.ID(*disableID) mutator := func(ds ds_fields.DaemonSet) (ds_fields.DaemonSet, error) { if ds.Disabled { return ds, util.Errorf("Daemon set has already been disabled") } ds.Disabled = true return ds, nil } _, err := dsstore.MutateDS(id, mutator) if err != nil { log.Fatalf("err: %v", err) } fmt.Printf("The daemon set '%s' has been successfully disabled in consul", id.String()) fmt.Println() case CmdDelete: id := ds_fields.ID(*deleteID) err := dsstore.Delete(id) if err != nil { log.Fatalf("err: %v", err) } fmt.Printf("The daemon set '%s' has been successfully deleted from consul", id.String()) fmt.Println() case CmdUpdate: id := ds_fields.ID(*updateID) mutator := func(ds ds_fields.DaemonSet) (ds_fields.DaemonSet, error) { changed := false if *updateMinHealth != "" { minHealth, err := strconv.Atoi(*updateMinHealth) if err != nil { log.Fatalf("Invalid value for minimum health, expected integer") } if ds.MinHealth != minHealth { changed = true ds.MinHealth = minHealth } } if *updateName != "" { name := ds_fields.ClusterName(*updateName) if ds.Name != name { changed = true ds.Name = name } } if *updateTimeout != TimeoutNotSpecified { if *updateTimeout <= time.Duration(0) { return ds, util.Errorf("Timeout must be a positive non-zero value, got '%v'", *createTimeout) } if ds.Timeout != *updateTimeout { changed = true ds.Timeout = *updateTimeout } } if *updateManifest != "" { manifest, err := manifest.FromPath(*updateManifest) if err != nil { return ds, util.Errorf("%s", err) } if manifest.ID() != ds.PodID { return ds, util.Errorf("Manifest ID of %s does not match daemon set's pod ID (%s)", manifest.ID(), ds.PodID) } dsSHA, err := ds.Manifest.SHA() if err != nil { return ds, util.Errorf("Unable to get SHA from consul daemon set manifest: %v", err) } newSHA, err := manifest.SHA() if err != nil { return ds, util.Errorf("Unable to get SHA from new manifest: %v", err) } if dsSHA != newSHA { changed = true ds.Manifest = manifest } } if updateSelectorGiven { selectorString := *updateSelector if *updateEverywhere { selectorString = klabels.Everything().String() } else if selectorString == "" { return ds, util.Errorf("Explicit everything selector not allowed, please use the --everwhere flag") } selector, err := parseNodeSelectorWithPrompt(ds.NodeSelector, selectorString, applicator) if err != nil { return ds, util.Errorf("Error occurred: %v", err) } if ds.NodeSelector.String() != selector.String() { changed = true ds.NodeSelector = selector } } if !changed { return ds, util.Errorf("No changes were made") } if updateSelectorGiven || *updateMinHealth != "" { if err := confirmMinheathForSelector(ds.MinHealth, ds.NodeSelector, applicator); err != nil { return ds, util.Errorf("Error occurred: %v", err) } } return ds, nil } _, err := dsstore.MutateDS(id, mutator) if err != nil { log.Fatalf("err: %v", err) } fmt.Printf("The daemon set '%s' has been successfully updated in consul", id.String()) fmt.Println() case CmdTestSelector: selectorString := *testSelectorString if *testSelectorEverywhere { selectorString = klabels.Everything().String() } else if selectorString == "" { fmt.Println("Explicit everything selector not allowed, please use the --everwhere flag") } selector, err := parseNodeSelector(selectorString) if err != nil { log.Fatalf("Error occurred: %v", err) } matches, err := applicator.GetMatches(selector, labels.NODE, false) if err != nil { log.Fatalf("Error getting matching labels: %v", err) } fmt.Println(matches) default: log.Fatalf("Unrecognized command %v", cmd) } }
// This function removes all pods with a DSIDLabel where the daemon set id does // not exist in the store at every interval specified because it is possible // that the farm will unexpectedly crash or someone deletes or modifies a node func (dsf *Farm) cleanupDaemonSetPods(quitCh <-chan struct{}) { timer := time.NewTimer(time.Duration(0)) for { select { case <-quitCh: return case <-timer.C: } timer.Reset(cleanupInterval) allDaemonSets, err := dsf.dsStore.List() if err != nil { dsf.logger.Errorf("Unable to get daemon sets from intent tree in daemon set farm: %v", err) continue } dsIDMap := make(map[fields.ID]ds_fields.DaemonSet) for _, dsFields := range allDaemonSets { dsIDMap[dsFields.ID] = dsFields } dsIDLabelSelector := klabels.Everything(). Add(DSIDLabel, klabels.ExistsOperator, []string{}) allPods, err := dsf.applicator.GetMatches(dsIDLabelSelector, labels.POD) if err != nil { dsf.logger.Errorf("Unable to get matches for daemon sets in pod store: %v", err) continue } for _, podLabels := range allPods { // Only check if it is a pod scheduled by a daemon set dsID := podLabels.Labels.Get(DSIDLabel) // Check if the daemon set exists, if it doesn't unschedule the pod if _, ok := dsIDMap[fields.ID(dsID)]; ok { continue } nodeName, podID, err := labels.NodeAndPodIDFromPodLabel(podLabels) if err != nil { dsf.logger.NoFields().Error(err) continue } // TODO: Since this mirrors the unschedule function in daemon_set.go, // We should find a nice way to couple them together dsf.logger.NoFields().Infof("Unscheduling '%v' in node '%v' with dangling daemon set uuid '%v'", podID, nodeName, dsID) _, err = dsf.kpStore.DeletePod(kp.INTENT_TREE, nodeName, podID) if err != nil { dsf.logger.NoFields().Errorf("Unable to delete pod id '%v' in node '%v', from intent tree: %v", podID, nodeName, err) continue } id := labels.MakePodLabelKey(nodeName, podID) err = dsf.applicator.RemoveLabel(labels.POD, id, DSIDLabel) if err != nil { dsf.logger.NoFields().Errorf("Error removing ds pod id label '%v': %v", id, err) } } } }