Example #1
0
func (h *CfgGetHandler) ServeHTTP(
	w http.ResponseWriter, req *http.Request) {
	// TODO: Might need to scrub auth passwords from this output.
	cfg := h.mgr.Cfg()
	indexDefs, indexDefsCAS, indexDefsErr :=
		cbgt.CfgGetIndexDefs(cfg)
	nodeDefsWanted, nodeDefsWantedCAS, nodeDefsWantedErr :=
		cbgt.CfgGetNodeDefs(cfg, cbgt.NODE_DEFS_WANTED)
	nodeDefsKnown, nodeDefsKnownCAS, nodeDefsKnownErr :=
		cbgt.CfgGetNodeDefs(cfg, cbgt.NODE_DEFS_KNOWN)
	planPIndexes, planPIndexesCAS, planPIndexesErr :=
		cbgt.CfgGetPlanPIndexes(cfg)
	MustEncode(w, RESTCfg{
		Status:            "ok",
		IndexDefs:         indexDefs,
		IndexDefsCAS:      indexDefsCAS,
		IndexDefsErr:      indexDefsErr,
		NodeDefsWanted:    nodeDefsWanted,
		NodeDefsWantedCAS: nodeDefsWantedCAS,
		NodeDefsWantedErr: nodeDefsWantedErr,
		NodeDefsKnown:     nodeDefsKnown,
		NodeDefsKnownCAS:  nodeDefsKnownCAS,
		NodeDefsKnownErr:  nodeDefsKnownErr,
		PlanPIndexes:      planPIndexes,
		PlanPIndexesCAS:   planPIndexesCAS,
		PlanPIndexesErr:   planPIndexesErr,
	})
}
Example #2
0
// WaitForWantedNodes blocks until the nodeDefsWanted in the cfg is
// equal to or a superset of the provided wantedNodes, and returns the
// "nodes to remove" (actualWantedNodes SET-DIFFERENCE wantedNodes).
func WaitForWantedNodes(cfg cbgt.Cfg, wantedNodes []string,
	cancelCh <-chan struct{}, secs int) (
	[]string, error) {
	var nodeDefWantedUUIDs []string

	for i := 0; i < secs; i++ {
		select {
		case <-cancelCh:
			return nil, ErrCtlCanceled
		default:
		}

		nodeDefsWanted, _, err :=
			cbgt.CfgGetNodeDefs(cfg, cbgt.NODE_DEFS_WANTED)
		if err != nil {
			return nil, err
		}

		nodeDefWantedUUIDs = nil
		for _, nodeDef := range nodeDefsWanted.NodeDefs {
			nodeDefWantedUUIDs = append(nodeDefWantedUUIDs, nodeDef.UUID)
		}

		if len(cbgt.StringsRemoveStrings(wantedNodes, nodeDefWantedUUIDs)) <= 0 {
			return cbgt.StringsRemoveStrings(nodeDefWantedUUIDs, wantedNodes), nil
		}

		time.Sleep(1 * time.Second)
	}

	return nil, fmt.Errorf("ctl: WaitForWantedNodes"+
		" could not attain wantedNodes: %#v,"+
		" only reached nodeDefWantedUUIDs: %#v",
		wantedNodes, nodeDefWantedUUIDs)
}
Example #3
0
func CurrentMemberNodes(cfg cbgt.Cfg) ([]CtlNode, error) {
	nodeDefsWanted, _, err := cbgt.CfgGetNodeDefs(cfg, cbgt.NODE_DEFS_WANTED)
	if err != nil {
		return nil, err
	}

	var memberNodes []CtlNode

	for _, nodeDef := range nodeDefsWanted.NodeDefs {
		memberNode := CtlNode{
			UUID:       nodeDef.UUID,
			ServiceURL: "http://" + nodeDef.HostPort,
		}

		if nodeDef.Extras != "" {
			// Early versions of ns_server integration had a simple,
			// non-JSON "host:port" format for nodeDef.Extras, which
			// we use as default.
			nsHostPort := nodeDef.Extras

			var e struct {
				NsHostPort string `json:"nsHostPort"`
			}

			err := json.Unmarshal([]byte(nodeDef.Extras), &e)
			if err != nil {
				nsHostPort = e.NsHostPort
			}

			memberNode.ManagerURL = "http://" + nsHostPort
		}

		memberNodes = append(memberNodes, memberNode)
	}

	return memberNodes, nil
}
Example #4
0
// PlannerSteps helps command-line tools implement the planner steps:
// * "unregister" - unregisters nodesRemove from the cfg.
// * "planner" - runs the planner to save a new plan into the cfg.
// * "failover" - a composite step, comprised of "unregister" and "failover_".
// * "failover_" - processes the nodesRemove as nodes to be failover'ed.
//
// The "NODES-REMOVE-ALL" step overrides the nodesRemove with every
// known and wanted node.  This can have a lot of impact, and was
// meant to be used for cluster cleanup/purging situations.
func PlannerSteps(steps map[string]bool,
	cfg cbgt.Cfg, version, server string, options map[string]string,
	nodesRemove []string, dryRun bool, plannerFilter cbgt.PlannerFilter) error {
	if steps != nil && steps["failover"] {
		steps["unregister"] = true
		steps["failover_"] = true
	}

	if steps != nil && steps["NODES-REMOVE-ALL"] {
		nodesRemove = nil

		nodesSeen := map[string]bool{}
		for _, kind := range []string{
			cbgt.NODE_DEFS_WANTED,
			cbgt.NODE_DEFS_KNOWN,
		} {
			nodeDefs, _, err := cbgt.CfgGetNodeDefs(cfg, kind)
			if err != nil {
				return err
			}

			for _, nodeDef := range nodeDefs.NodeDefs {
				if !nodesSeen[nodeDef.UUID] {
					nodesSeen[nodeDef.UUID] = true
					nodesRemove = append(nodesRemove, nodeDef.UUID)
				}
			}
		}
	}

	log.Printf("planner: nodesRemove: %#v", nodesRemove)

	if steps != nil && steps["unregister"] {
		log.Printf("planner: step unregister")

		if !dryRun {
			err := cbgt.UnregisterNodes(cfg, cbgt.VERSION, nodesRemove)
			if err != nil {
				return err
			}
		}
	}

	if steps != nil && steps["planner"] {
		log.Printf("planner: step planner")

		if !dryRun {
			_, err :=
				cbgt.Plan(cfg, cbgt.VERSION, "", server, options, plannerFilter)
			if err != nil {
				return err
			}
		}
	}

	if steps != nil && steps["failover_"] {
		log.Printf("planner: step failover_")

		if !dryRun {
			_, err := Failover(cfg, cbgt.VERSION, server, options, nodesRemove)
			if err != nil {
				return err
			}
		}
	}

	return nil
}
Example #5
0
func (h *NsStatusHandler) ServeHTTP(
	w http.ResponseWriter, req *http.Request) {

	cfg := h.mgr.Cfg()
	planPIndexes, _, err := cbgt.CfgGetPlanPIndexes(cfg)
	if err != nil {
		rest.ShowError(w, req, "could not retrieve plan pIndexes", 500)
		return
	}

	nodesDefs, _, err := cbgt.CfgGetNodeDefs(cfg, cbgt.NODE_DEFS_WANTED)
	if err != nil {
		rest.ShowError(w, req, "could not retrieve node defs (wanted)", 500)
		return
	}

	_, indexDefsMap, err := h.mgr.GetIndexDefs(false)
	if err != nil {
		rest.ShowError(w, req, "could not retrieve index defs", 500)
		return
	}

	w.Write(cbgt.JsonOpenBrace)
	w.Write(statsNamePrefix)
	w.Write([]byte("status"))
	w.Write(statsNameSuffix)
	w.Write([]byte("["))

	indexDefNames := make(sort.StringSlice, 0, len(indexDefsMap))
	for indexDefName := range indexDefsMap {
		indexDefNames = append(indexDefNames, indexDefName)
	}

	sort.Sort(indexDefNames)

	for i, indexDefName := range indexDefNames {
		indexDef := indexDefsMap[indexDefName]
		if i > 0 {
			w.Write(cbgt.JsonComma)
		}

		rest.MustEncode(w, struct {
			Completion int      `json:"completion"`
			Hosts      []string `json:"hosts"`
			Status     string   `json:"status"`
			Bucket     string   `json:"bucket"`
			Name       string   `json:"name"`
		}{
			Bucket: indexDef.SourceName,
			Name:   indexDefName,
			Hosts:  HostsForIndex(indexDefName, planPIndexes, nodesDefs),
			// FIXME hard-coded
			Completion: 100,
			Status:     "Ready",
		})

	}
	w.Write([]byte("],"))
	w.Write(statsNamePrefix)
	w.Write([]byte("code"))
	w.Write(statsNameSuffix)
	w.Write([]byte("\"success\""))
	w.Write(cbgt.JsonCloseBrace)

}
Example #6
0
func RunRecentInfoCache(mgr *cbgt.Manager) {
	cfg := mgr.Cfg()

	cfgChangedCh := make(chan struct{}, 10)

	go func() { // Debounce cfg events to feed into the cfgChangedCh.
		ech := make(chan cbgt.CfgEvent)
		cfg.Subscribe(cbgt.PLAN_PINDEXES_KEY, ech)

		for {
			<-ech // First, wait for a cfg event.

			debounceTimeCh := time.After(500 * time.Millisecond)

		DEBOUNCE_LOOP:
			for {
				select {
				case <-ech:
					// NO-OP when there are more, spammy cfg events.

				case <-debounceTimeCh:
					break DEBOUNCE_LOOP
				}
			}

			cfgChangedCh <- struct{}{}
		}
	}()

	tickCh := time.Tick(1 * time.Minute)

	for {
		var nodeDefs *cbgt.NodeDefs
		var planPIndexes *cbgt.PlanPIndexes

		indexDefs, indexDefsMap, err := mgr.GetIndexDefs(false)
		if err == nil {
			nodeDefs, _, err = cbgt.CfgGetNodeDefs(cfg, cbgt.NODE_DEFS_WANTED)
			if err == nil {
				planPIndexes, _, err = cbgt.CfgGetPlanPIndexes(cfg)
			}
		}

		rd := &recentInfo{
			indexDefs:    indexDefs,
			indexDefsMap: indexDefsMap,
			nodeDefs:     nodeDefs,
			planPIndexes: planPIndexes,
			err:          err,
		}

		runtime.ReadMemStats(&rd.memStats)

	REUSE_CACHE:
		for {
			select {
			case <-cfgChangedCh:
				break REUSE_CACHE

			case <-tickCh:
				break REUSE_CACHE

			case recentInfoCh <- rd:
				if rd.err != nil {
					break REUSE_CACHE
				}
			}
		}
	}
}