func TestConsistencyNoChange(t *testing.T) { _, kvStore, applicator, rc, alerter := setup(t) rcSHA, _ := rc.Manifest.SHA() err := applicator.SetLabel(labels.NODE, "node1", "nodeQuality", "good") Assert(t).IsNil(err, "expected no error assigning label") // Install manifest on a single node rc.ReplicasDesired = 1 err = rc.meetDesires() Assert(t).IsNil(err, "unexpected error scheduling nodes") numNodes := waitForNodes(t, rc, 1) Assert(t).AreEqual(numNodes, 1, "took too long to schedule") // Verify that the node is consistent manifest, _, err := kvStore.Pod(kp.INTENT_TREE, "node1", "testPod") Assert(t).IsNil(err, "could not fetch intent") sha, _ := manifest.SHA() Assert(t).AreEqual(rcSHA, sha, "controller did not set intent initially") // Make no changes // The controller shouldn't alter the node err = rc.meetDesires() Assert(t).IsNil(err, "unexpected error scheduling nodes") manifest, _, err = kvStore.Pod(kp.INTENT_TREE, "node1", "testPod") Assert(t).IsNil(err, "could not fetch intent") sha, _ = manifest.SHA() Assert(t).AreEqual(rcSHA, sha, "controller modified the node's intent") Assert(t).AreEqual(len(alerter.Alerts), 0, "expected no alerts to fire") }
func TestConsistencyDelete(t *testing.T) { _, kvStore, applicator, rc, alerter := setup(t) rcSHA, _ := rc.Manifest.SHA() err := applicator.SetLabel(labels.NODE, "node1", "nodeQuality", "good") Assert(t).IsNil(err, "expected no error assigning label") // Install manifest on a single node rc.ReplicasDesired = 1 err = rc.meetDesires() Assert(t).IsNil(err, "unexpected error scheduling nodes") // Delete the intent manifest _, err = kvStore.DeletePod(kp.INTENT_TREE, "node1", "testPod") Assert(t).IsNil(err, "unexpected error deleting intent manifest") _, _, err = kvStore.Pod(kp.INTENT_TREE, "node1", "testPod") Assert(t).AreEqual(pods.NoCurrentManifest, err, "unexpected pod result") // Controller should force the node back to the canonical manifest err = rc.meetDesires() Assert(t).IsNil(err, "unexpected error scheduling nodes") manifest, _, err := kvStore.Pod(kp.INTENT_TREE, "node1", "testPod") Assert(t).IsNil(err, "could not fetch intent") sha, _ := manifest.SHA() Assert(t).AreEqual(rcSHA, sha, "controller did not reset intent") Assert(t).AreEqual(len(alerter.Alerts), 0, "expected no alerts to fire") }
func TestConsistencyModify(t *testing.T) { _, kvStore, applicator, rc, alerter := setup(t) rcSHA, _ := rc.Manifest.SHA() err := applicator.SetLabel(labels.NODE, "node1", "nodeQuality", "good") Assert(t).IsNil(err, "expected no error assigning label") // Install manifest on a single node rc.ReplicasDesired = 1 err = rc.meetDesires() Assert(t).IsNil(err, "unexpected error scheduling nodes") // Modify the intent manifest b := rc.Manifest.GetBuilder() b.SetConfig(map[interface{}]interface{}{"test": true}) manifest2 := b.GetManifest() sha2, _ := manifest2.SHA() Assert(t).AreNotEqual(rcSHA, sha2, "failed to set different intent manifest") kvStore.SetPod(kp.INTENT_TREE, "node1", manifest2) // Controller should force the node back to the canonical manifest err = rc.meetDesires() Assert(t).IsNil(err, "unexpected error scheduling nodes") manifest, _, err := kvStore.Pod(kp.INTENT_TREE, "node1", "testPod") Assert(t).IsNil(err, "could not fetch intent") sha, _ := manifest.SHA() Assert(t).AreEqual(rcSHA, sha, "controller did not reset intent") Assert(t).AreEqual(len(alerter.Alerts), 0, "expected no alerts to fire") }
func createDaemonSet(store *consulStore, t *testing.T) ds_fields.DaemonSet { podID := types.PodID("some_pod_id") minHealth := 0 clusterName := ds_fields.ClusterName("some_name") azLabel := pc_fields.AvailabilityZone("some_zone") selector := klabels.Everything(). Add(pc_fields.AvailabilityZoneLabel, klabels.EqualsOperator, []string{azLabel.String()}) manifestBuilder := manifest.NewBuilder() manifestBuilder.SetID(podID) manifest := manifestBuilder.GetManifest() timeout := replication.NoTimeout ds, err := store.Create(manifest, minHealth, clusterName, selector, podID, timeout) if err != nil { t.Fatalf("Unable to create daemon set: %s", err) } if ds.ID == "" { t.Error("daemon set should have an id") } Assert(t).AreNotEqual(ds.ID, "", "Daemon set should have an id") Assert(t).AreNotEqual(ds.PodID, "", "Daemon set should have a pod id") Assert(t).AreEqual(ds.PodID, podID, "Daemon set pod id was not set correctly") Assert(t).AreEqual(ds.MinHealth, minHealth, "Daemon set minimum health was not set correctly") Assert(t).AreEqual(ds.Name, clusterName, "Daemon set cluster name was not set correctly") Assert(t).IsFalse(ds.Disabled, "Daemon set disabled field was not set correctly") testLabels := klabels.Set{ pc_fields.AvailabilityZoneLabel: azLabel.String(), } if matches := ds.NodeSelector.Matches(testLabels); !matches { t.Error("The daemon set has a bad node selector") } originalSHA, err := manifest.SHA() if err != nil { t.Fatal("Unable to retrieve SHA from manifest") } getSHA, err := ds.Manifest.SHA() if err != nil { t.Fatal("Unable to retrieve SHA from manifest retrieved from daemon set") } Assert(t).AreEqual(originalSHA, getSHA, "Daemon set manifest not set correctly") return ds }
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) } }
func TestGet(t *testing.T) { store := consulStoreWithFakeKV() // // Create DaemonSet // podID := types.PodID("some_pod_id") minHealth := 0 clusterName := ds_fields.ClusterName("some_name") azLabel := pc_fields.AvailabilityZone("some_zone") selector := klabels.Everything(). Add(pc_fields.AvailabilityZoneLabel, klabels.EqualsOperator, []string{azLabel.String()}) manifestBuilder := manifest.NewBuilder() manifestBuilder.SetID(podID) manifest := manifestBuilder.GetManifest() timeout := replication.NoTimeout ds, err := store.Create(manifest, minHealth, clusterName, selector, podID, timeout) if err != nil { t.Fatalf("Unable to create daemon set: %s", err) } Assert(t).AreNotEqual(ds.ID, "", "Daemon set should have an id") // // Get DaemonSet and verify it is the same // getDS, _, err := store.Get(ds.ID) if err != nil { t.Fatalf("Error retrieving created daemon set: %s", err) } Assert(t).AreNotEqual(getDS.ID, "", "Daemon set should have an id") Assert(t).AreNotEqual(getDS.PodID, "", "Daemon set should have a pod id") Assert(t).AreEqual(ds.ID, getDS.ID, "Daemon set should be equal ids") Assert(t).AreEqual(ds.PodID, getDS.PodID, "Daemon set should have equal pod ids") Assert(t).AreEqual(ds.MinHealth, getDS.MinHealth, "Daemon set should have equal minimum healths") Assert(t).AreEqual(ds.Name, getDS.Name, "Daemon set should have equal names") Assert(t).AreEqual(ds.Disabled, getDS.Disabled, "Daemon set should have same disabled fields") testLabels := klabels.Set{ pc_fields.AvailabilityZoneLabel: azLabel.String(), } if matches := getDS.NodeSelector.Matches(testLabels); !matches { t.Error("The daemon set has a bad node selector") } originalSHA, err := manifest.SHA() if err != nil { t.Fatal("Unable to retrieve SHA from manifest") } getSHA, err := getDS.Manifest.SHA() if err != nil { t.Fatal("Unable to retrieve SHA from manifest retrieved from daemon set") } Assert(t).AreEqual(originalSHA, getSHA, "Daemon set shas were not equal") // Invalid get opertaion _, _, err = store.Get("bad_id") if err == nil { t.Error("Expected get operation to fail when getting a daemon set which does not exist") } }