Example #1
0
func formatOneline(writer io.Writer, value interface{}, printf onelinePrintf) error {
	fs, valueConverted := value.(formattedStatus)
	if !valueConverted {
		return errors.Errorf("expected value of type %T, got %T", fs, value)
	}

	pprint := func(uName string, u unitStatus, level int) {
		var fmtPorts string
		if len(u.OpenedPorts) > 0 {
			fmtPorts = fmt.Sprintf(" %s", strings.Join(u.OpenedPorts, ", "))
		}
		format := indent("\n", level*2, "- %s: %s (%v)"+fmtPorts)
		printf(writer, format, uName, u, level)
	}

	for _, svcName := range utils.SortStringsNaturally(stringKeysFromMap(fs.Applications)) {
		svc := fs.Applications[svcName]
		for _, uName := range utils.SortStringsNaturally(stringKeysFromMap(svc.Units)) {
			unit := svc.Units[uName]
			pprint(uName, unit, 0)
			recurseUnits(unit, 1, pprint)
		}
	}

	return nil
}
Example #2
0
func printMachines(tw *ansiterm.TabWriter, machines map[string]machineStatus) {
	w := output.Wrapper{tw}
	w.Println("MACHINE", "STATE", "DNS", "INS-ID", "SERIES", "AZ")
	for _, name := range utils.SortStringsNaturally(stringKeysFromMap(machines)) {
		printMachine(w, machines[name])
	}
}
Example #3
0
// FormatSummary writes a summary of the current environment
// including the following information:
// - Headers:
//   - All subnets the environment occupies.
//   - All ports the environment utilizes.
// - Sections:
//   - Machines: Displays total #, and then the # in each state.
//   - Units: Displays total #, and then # in each state.
//   - Applications: Displays total #, their names, and how many of each
//     are exposed.
func FormatSummary(writer io.Writer, value interface{}) error {
	fs, valueConverted := value.(formattedStatus)
	if !valueConverted {
		return errors.Errorf("expected value of type %T, got %T", fs, value)
	}

	f := newSummaryFormatter(writer)
	stateToMachine := f.aggregateMachineStates(fs.Machines)
	svcExposure := f.aggregateServiceAndUnitStates(fs.Applications)
	p := f.delimitValuesWithTabs

	// Print everything out
	p("Running on subnets:", strings.Join(f.netStrings, ", "))
	p(" Utilizing ports:", f.portsInColumnsOf(3))
	f.tw.Flush()

	// Right align summary information
	f.tw.Init(writer, 0, 1, 2, ' ', tabwriter.AlignRight)
	p("# Machines:", fmt.Sprintf("(%d)", len(fs.Machines)))
	f.printStateToCount(stateToMachine)
	p(" ")

	p("# Units:", fmt.Sprintf("(%d)", f.numUnits))
	f.printStateToCount(f.stateToUnit)
	p(" ")

	p("# Applications:", fmt.Sprintf("(%d)", len(fs.Applications)))
	for _, svcName := range utils.SortStringsNaturally(stringKeysFromMap(svcExposure)) {
		s := svcExposure[svcName]
		p(svcName, fmt.Sprintf("%d/%d\texposed", s[true], s[true]+s[false]))
	}
	f.tw.Flush()

	return nil
}
Example #4
0
func checkSort(c *gc.C, expected []string, xform func([]string)) {
	input := copyStrSlice(expected)
	xform(input)
	origInput := copyStrSlice(input)
	utils.SortStringsNaturally(input)
	c.Check(input, gc.DeepEquals, expected, gc.Commentf("input was: %#v", origInput))
}
Example #5
0
func printMachines(tw *ansiterm.TabWriter, machines map[string]machineStatus) {
	w := output.Wrapper{tw}
	w.Println("Machine", "State", "DNS", "Inst id", "Series", "AZ")
	for _, name := range utils.SortStringsNaturally(stringKeysFromMap(machines)) {
		printMachine(w, machines[name])
	}
}
Example #6
0
File: facade.go Project: bac/juju
// MinionReports returns details of the reports made by migration
// minions to the controller for the current migration phase.
func (api *API) MinionReports() (params.MinionReports, error) {
	var out params.MinionReports

	mig, err := api.backend.LatestMigration()
	if err != nil {
		return out, errors.Trace(err)
	}

	reports, err := mig.MinionReports()
	if err != nil {
		return out, errors.Trace(err)
	}

	out.MigrationId = mig.Id()
	phase, err := mig.Phase()
	if err != nil {
		return out, errors.Trace(err)
	}
	out.Phase = phase.String()

	out.SuccessCount = len(reports.Succeeded)

	out.Failed = make([]string, len(reports.Failed))
	for i := 0; i < len(out.Failed); i++ {
		out.Failed[i] = reports.Failed[i].String()
	}
	utils.SortStringsNaturally(out.Failed)

	out.UnknownCount = len(reports.Unknown)

	unknown := make([]string, len(reports.Unknown))
	for i := 0; i < len(unknown); i++ {
		unknown[i] = reports.Unknown[i].String()
	}
	utils.SortStringsNaturally(unknown)

	// Limit the number of unknowns reported
	numSamples := out.UnknownCount
	if numSamples > 10 {
		numSamples = 10
	}
	out.UnknownSample = unknown[:numSamples]

	return out, nil
}
Example #7
0
func (f *summaryFormatter) aggregateServiceAndUnitStates(services map[string]applicationStatus) map[string]map[bool]int {
	svcExposure := make(map[string]map[bool]int)
	for _, name := range utils.SortStringsNaturally(stringKeysFromMap(services)) {
		s := services[name]
		// Grab unit states
		for _, un := range utils.SortStringsNaturally(stringKeysFromMap(s.Units)) {
			u := s.Units[un]
			f.trackUnit(un, u, 0)
			recurseUnits(u, 1, f.trackUnit)
		}

		if _, ok := svcExposure[name]; !ok {
			svcExposure[name] = make(map[bool]int)
		}

		svcExposure[name][s.Exposed]++
	}
	return svcExposure
}
Example #8
0
File: utils.go Project: bac/juju
// recurseUnits calls the given recurseMap function on the given unit
// and its subordinates (recursively defined on the given unit).
func recurseUnits(u unitStatus, il int, recurseMap func(string, unitStatus, int)) {
	if len(u.Subordinates) == 0 {
		return
	}
	for _, uName := range utils.SortStringsNaturally(stringKeysFromMap(u.Subordinates)) {
		unit := u.Subordinates[uName]
		recurseMap(uName, unit, il)
		recurseUnits(unit, il+1, recurseMap)
	}
}
Example #9
0
func (st *mockState) AllMachines() (machines []common.Machine, _ error) {
	// Ensure we get machines in id order.
	var ids []string
	for id := range st.machines {
		ids = append(ids, id)
	}
	utils.SortStringsNaturally(ids)
	for _, id := range ids {
		machines = append(machines, st.machines[id])
	}
	return machines, nil
}
Example #10
0
File: list.go Project: bac/juju
// Run grabs the Actions spec from the api.  It then sets up a sensible
// output format for the map.
func (c *listCommand) Run(ctx *cmd.Context) error {
	api, err := c.NewActionAPIClient()
	if err != nil {
		return err
	}
	defer api.Close()

	actions, err := api.ApplicationCharmActions(params.Entity{c.applicationTag.String()})
	if err != nil {
		return err
	}

	if c.fullSchema {
		verboseSpecs := make(map[string]interface{})
		for k, v := range actions {
			verboseSpecs[k] = v.Params
		}

		return c.out.Write(ctx, verboseSpecs)
	}

	shortOutput := make(map[string]string)
	var sortedNames []string
	for name, action := range actions {
		shortOutput[name] = action.Description
		if shortOutput[name] == "" {
			shortOutput[name] = "No description"
		}
		sortedNames = append(sortedNames, name)
	}
	utils.SortStringsNaturally(sortedNames)

	var output interface{}
	switch c.out.Name() {
	case "yaml", "json":
		output = shortOutput
	default:
		if len(sortedNames) == 0 {
			ctx.Infof("No actions defined for %s.", c.applicationTag.Id())
			return nil
		}
		var list []listOutput
		for _, name := range sortedNames {
			list = append(list, listOutput{name, shortOutput[name]})
		}
		output = list
	}

	return c.out.Write(ctx, output)
}
Example #11
0
func (f *summaryFormatter) aggregateMachineStates(machines map[string]machineStatus) map[status.Status]int {
	stateToMachine := make(map[status.Status]int)
	for _, name := range utils.SortStringsNaturally(stringKeysFromMap(machines)) {
		m := machines[name]
		f.resolveAndTrackIp(m.DNSName)

		if agentState := m.JujuStatus.Current; agentState == "" {
			agentState = status.Pending
		} else {
			stateToMachine[agentState]++
		}
	}
	return stateToMachine
}
Example #12
0
func printMachine(w output.Wrapper, m machineStatus) {
	// We want to display availability zone so extract from hardware info".
	hw, err := instance.ParseHardware(m.Hardware)
	if err != nil {
		logger.Warningf("invalid hardware info %s for machine %v", m.Hardware, m)
	}
	az := ""
	if hw.AvailabilityZone != nil {
		az = *hw.AvailabilityZone
	}
	w.Print(m.Id)
	w.PrintStatus(m.JujuStatus.Current)
	w.Println(m.DNSName, m.InstanceId, m.Series, az)
	for _, name := range utils.SortStringsNaturally(stringKeysFromMap(m.Containers)) {
		printMachine(w, m.Containers[name])
	}
}
Example #13
0
// FormatTabular writes a tabular summary of machines, applications, and
// units. Any subordinate items are indented by two spaces beneath
// their superior.
func FormatTabular(writer io.Writer, forceColor bool, value interface{}) error {
	const maxVersionWidth = 15
	const ellipsis = "..."
	const truncatedWidth = maxVersionWidth - len(ellipsis)

	fs, valueConverted := value.(formattedStatus)
	if !valueConverted {
		return errors.Errorf("expected value of type %T, got %T", fs, value)
	}
	// To format things into columns.
	tw := output.TabWriter(writer)
	if forceColor {
		tw.SetColorCapable(forceColor)
	}
	w := output.Wrapper{tw}
	p := w.Println
	outputHeaders := func(values ...interface{}) {
		p()
		p(values...)
	}

	cloudRegion := fs.Model.Cloud
	if fs.Model.CloudRegion != "" {
		cloudRegion += "/" + fs.Model.CloudRegion
	}

	header := []interface{}{"MODEL", "CONTROLLER", "CLOUD/REGION", "VERSION"}
	values := []interface{}{fs.Model.Name, fs.Model.Controller, cloudRegion, fs.Model.Version}
	message := getModelMessage(fs.Model)
	if message != "" {
		header = append(header, "NOTES")
		values = append(values, message)
	}

	// The first set of headers don't use outputHeaders because it adds the blank line.
	p(header...)
	p(values...)

	units := make(map[string]unitStatus)
	metering := false
	relations := newRelationFormatter()
	outputHeaders("APP", "VERSION", "STATUS", "SCALE", "CHARM", "STORE", "REV", "OS", "NOTES")
	tw.SetColumnAlignRight(3)
	tw.SetColumnAlignRight(6)
	for _, appName := range utils.SortStringsNaturally(stringKeysFromMap(fs.Applications)) {
		app := fs.Applications[appName]
		version := app.Version
		// Don't let a long version push out the version column.
		if len(version) > maxVersionWidth {
			version = version[:truncatedWidth] + ellipsis
		}
		// Notes may well contain other things later.
		notes := ""
		if app.Exposed {
			notes = "exposed"
		}
		w.Print(appName, version)
		w.PrintStatus(app.StatusInfo.Current)
		scale, warn := fs.applicationScale(appName)
		if warn {
			w.PrintColor(output.WarningHighlight, scale)
		} else {
			w.Print(scale)
		}
		p(app.CharmName,
			app.CharmOrigin,
			app.CharmRev,
			app.OS,
			notes)

		for un, u := range app.Units {
			units[un] = u
			if u.MeterStatus != nil {
				metering = true
			}
		}
		// Ensure that we pick a consistent name for peer relations.
		sortedRelTypes := make([]string, 0, len(app.Relations))
		for relType := range app.Relations {
			sortedRelTypes = append(sortedRelTypes, relType)
		}
		sort.Strings(sortedRelTypes)

		subs := set.NewStrings(app.SubordinateTo...)
		for _, relType := range sortedRelTypes {
			for _, related := range app.Relations[relType] {
				relations.add(related, appName, relType, subs.Contains(related))
			}
		}

	}

	pUnit := func(name string, u unitStatus, level int) {
		message := u.WorkloadStatusInfo.Message
		agentDoing := agentDoing(u.JujuStatusInfo)
		if agentDoing != "" {
			message = fmt.Sprintf("(%s) %s", agentDoing, message)
		}
		w.Print(indent("", level*2, name))
		w.PrintStatus(u.WorkloadStatusInfo.Current)
		w.PrintStatus(u.JujuStatusInfo.Current)
		p(
			u.Machine,
			u.PublicAddress,
			strings.Join(u.OpenedPorts, ","),
			message,
		)
	}

	outputHeaders("UNIT", "WORKLOAD", "AGENT", "MACHINE", "PUBLIC-ADDRESS", "PORTS", "MESSAGE")
	for _, name := range utils.SortStringsNaturally(stringKeysFromMap(units)) {
		u := units[name]
		pUnit(name, u, 0)
		const indentationLevel = 1
		recurseUnits(u, indentationLevel, pUnit)
	}

	if metering {
		outputHeaders("METER", "STATUS", "MESSAGE")
		for _, name := range utils.SortStringsNaturally(stringKeysFromMap(units)) {
			u := units[name]
			if u.MeterStatus != nil {
				p(name, u.MeterStatus.Color, u.MeterStatus.Message)
			}
		}
	}

	p()
	printMachines(tw, fs.Machines)

	if relations.len() > 0 {
		outputHeaders("RELATION", "PROVIDES", "CONSUMES", "TYPE")
		for _, k := range relations.sorted() {
			r := relations.get(k)
			if r != nil {
				p(r.relation, r.application1, r.application2, r.relationType())
			}
		}
	}

	tw.Flush()
	return nil
}
Example #14
0
func (f *summaryFormatter) printStateToCount(m map[status.Status]int) {
	for _, stateToCount := range utils.SortStringsNaturally(stringKeysFromMap(m)) {
		numInStatus := m[status.Status(stateToCount)]
		f.delimitValuesWithTabs(stateToCount+":", fmt.Sprintf(" %d ", numInStatus))
	}
}