Пример #1
0
func formatOneline(value interface{}, printf onelinePrintf) ([]byte, error) {
	fs, valueConverted := value.(formattedStatus)
	if !valueConverted {
		return nil, errors.Errorf("expected value of type %T, got %T", fs, value)
	}
	var out bytes.Buffer

	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(&out, format, uName, u, level)
	}

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

	return out.Bytes(), nil
}
Пример #2
0
// FormatMachineTabular returns a tabular summary of machine
func FormatMachineTabular(value interface{}) ([]byte, error) {
	fs, valueConverted := value.(formattedMachineStatus)
	if !valueConverted {
		return nil, errors.Errorf("expected value of type %T, got %T", fs, value)
	}
	var out bytes.Buffer
	// To format things into columns.
	tw := tabwriter.NewWriter(&out, 0, 1, 1, ' ', 0)
	p := func(values ...interface{}) {
		for _, v := range values {
			fmt.Fprintf(tw, "%s\t", v)
		}
		fmt.Fprintln(tw)
	}

	p("\n[Machines]")
	p("ID\tSTATE\tDNS\tINS-ID\tSERIES\tAZ")
	for _, name := range common.SortStringsNaturally(stringKeysFromMap(fs.Machines)) {
		m := fs.Machines[name]
		// 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
		}
		p(m.Id, m.AgentState, m.DNSName, m.InstanceId, m.Series, az)
	}
	tw.Flush()

	return out.Bytes(), nil
}
Пример #3
0
// FormatSummary returns 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.
//   - Services: Displays total #, their names, and how many of each
//     are exposed.
func FormatSummary(value interface{}) ([]byte, error) {
	fs, valueConverted := value.(formattedStatus)
	if !valueConverted {
		return nil, errors.Errorf("expected value of type %T, got %T", fs, value)
	}

	f := newSummaryFormatter()
	stateToMachine := f.aggregateMachineStates(fs.Machines)
	svcExposure := f.aggregateServiceAndUnitStates(fs.Services)
	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(&f.out, 0, 2, 1, ' ', 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("# SERVICES:", fmt.Sprintf(" (%d)", len(fs.Services)))
	for _, svcName := range common.SortStringsNaturally(stringKeysFromMap(svcExposure)) {
		s := svcExposure[svcName]
		p(svcName, fmt.Sprintf("%d/%d\texposed", s[true], s[true]+s[false]))
	}
	f.tw.Flush()

	return f.out.Bytes(), nil
}
Пример #4
0
func (f *summaryFormatter) aggregateServiceAndUnitStates(services map[string]serviceStatus) map[string]map[bool]int {
	svcExposure := make(map[string]map[bool]int)
	for _, name := range common.SortStringsNaturally(stringKeysFromMap(services)) {
		s := services[name]
		// Grab unit states
		for _, un := range common.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
}
Пример #5
0
// 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 common.SortStringsNaturally(stringKeysFromMap(u.Subordinates)) {
		unit := u.Subordinates[uName]
		recurseMap(uName, unit, il)
		recurseUnits(unit, il+1, recurseMap)
	}
}
Пример #6
0
func (f *summaryFormatter) aggregateMachineStates(machines map[string]machineStatus) map[status.Status]int {
	stateToMachine := make(map[status.Status]int)
	for _, name := range common.SortStringsNaturally(stringKeysFromMap(machines)) {
		m := machines[name]
		f.resolveAndTrackIp(m.DNSName)

		if agentState := m.JujuStatus.Current; agentState == "" {
			agentState = status.StatusPending
		} else {
			stateToMachine[agentState]++
		}
	}
	return stateToMachine
}
Пример #7
0
// FormatTabular returns a tabular summary of machines, services, and
// units. Any subordinate items are indented by two spaces beneath
// their superior.
func FormatTabular(value interface{}) ([]byte, error) {
	fs, valueConverted := value.(formattedStatus)
	if !valueConverted {
		return nil, errors.Errorf("expected value of type %T, got %T", fs, value)
	}
	var out bytes.Buffer
	// To format things into columns.
	tw := tabwriter.NewWriter(&out, 0, 1, 1, ' ', 0)
	p := func(values ...interface{}) {
		for _, v := range values {
			fmt.Fprintf(tw, "%s\t", v)
		}
		fmt.Fprintln(tw)
	}

	if envStatus := fs.ModelStatus; envStatus != nil {
		p("[Model]")
		if envStatus.AvailableVersion != "" {
			p("UPGRADE-AVAILABLE")
			p(envStatus.AvailableVersion)
		}
		p()
		tw.Flush()
	}

	units := make(map[string]unitStatus)
	relations := newRelationFormatter()
	p("[Services]")
	p("NAME\tSTATUS\tEXPOSED\tCHARM")
	for _, svcName := range common.SortStringsNaturally(stringKeysFromMap(fs.Services)) {
		svc := fs.Services[svcName]
		for un, u := range svc.Units {
			units[un] = u
		}

		subs := set.NewStrings(svc.SubordinateTo...)
		p(svcName, svc.StatusInfo.Current, fmt.Sprintf("%t", svc.Exposed), svc.Charm)
		for relType, relatedUnits := range svc.Relations {
			for _, related := range relatedUnits {
				relations.add(related, svcName, relType, subs.Contains(related))
			}
		}

	}
	if relations.len() > 0 {
		p()
		p("[Relations]")
		p("SERVICE1\tSERVICE2\tRELATION\tTYPE")
		for _, k := range relations.sorted() {
			r := relations.get(k)
			if r != nil {
				p(r.service1, r.service2, r.relation, r.relationType())
			}
		}
	}
	tw.Flush()

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

	header := []string{"ID", "WORKLOAD-STATE", "AGENT-STATE", "VERSION", "MACHINE", "PORTS", "PUBLIC-ADDRESS", "MESSAGE"}

	p("\n[Units]")
	p(strings.Join(header, "\t"))
	for _, name := range common.SortStringsNaturally(stringKeysFromMap(units)) {
		u := units[name]
		pUnit(name, u, 0)
		const indentationLevel = 1
		recurseUnits(u, indentationLevel, pUnit)
	}
	tw.Flush()

	p("\n[Machines]")
	p("ID\tSTATE\tDNS\tINS-ID\tSERIES\tAZ")
	for _, name := range common.SortStringsNaturally(stringKeysFromMap(fs.Machines)) {
		m := fs.Machines[name]
		// 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
		}
		p(m.Id, m.AgentState, m.DNSName, m.InstanceId, m.Series, az)
	}
	tw.Flush()

	return out.Bytes(), nil
}
Пример #8
0
// FormatTabular returns a tabular summary of machines, services, and
// units. Any subordinate items are indented by two spaces beneath
// their superior.
func FormatTabular(value interface{}) ([]byte, error) {
	fs, valueConverted := value.(formattedStatus)
	if !valueConverted {
		return nil, errors.Errorf("expected value of type %T, got %T", fs, value)
	}
	var out bytes.Buffer
	// To format things into columns.
	tw := tabwriter.NewWriter(&out, 0, 1, 1, ' ', 0)
	p := func(values ...interface{}) {
		for _, v := range values {
			fmt.Fprintf(tw, "%s\t", v)
		}
		fmt.Fprintln(tw)
	}

	if envStatus := fs.EnvironmentStatus; envStatus != nil {
		p("[Environment]")
		if envStatus.AvailableVersion != "" {
			p("UPGRADE-AVAILABLE")
			p(envStatus.AvailableVersion)
		}
		p()
		tw.Flush()
	}

	units := make(map[string]unitStatus)
	p("[Services]")
	p("NAME\tSTATUS\tEXPOSED\tCHARM")
	for _, svcName := range common.SortStringsNaturally(stringKeysFromMap(fs.Services)) {
		svc := fs.Services[svcName]
		for un, u := range svc.Units {
			units[un] = u
		}
		p(svcName, svc.StatusInfo.Current, fmt.Sprintf("%t", svc.Exposed), svc.Charm)
	}
	tw.Flush()

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

	// See if we have new or old data; that determines what data we can display.
	newStatus := false
	for _, u := range units {
		if u.AgentStatusInfo.Current != "" {
			newStatus = true
			break
		}
	}
	var header []string
	if newStatus {
		header = []string{"ID", "WORKLOAD-STATE", "AGENT-STATE", "VERSION", "MACHINE", "PORTS", "PUBLIC-ADDRESS", "MESSAGE"}
	} else {
		header = []string{"ID", "STATE", "VERSION", "MACHINE", "PORTS", "PUBLIC-ADDRESS"}
	}

	p("\n[Units]")
	p(strings.Join(header, "\t"))
	for _, name := range common.SortStringsNaturally(stringKeysFromMap(units)) {
		u := units[name]
		pUnit(name, u, 0)
		const indentationLevel = 1
		recurseUnits(u, indentationLevel, pUnit)
	}
	tw.Flush()

	p("\n[Machines]")
	p("ID\tSTATE\tVERSION\tDNS\tINS-ID\tSERIES\tHARDWARE")
	for _, name := range common.SortStringsNaturally(stringKeysFromMap(fs.Machines)) {
		m := fs.Machines[name]
		p(m.Id, m.AgentState, m.AgentVersion, m.DNSName, m.InstanceId, m.Series, m.Hardware)
	}
	tw.Flush()

	return out.Bytes(), nil
}
Пример #9
0
func (f *summaryFormatter) printStateToCount(m map[status.Status]int) {
	for _, stateToCount := range common.SortStringsNaturally(stringKeysFromMap(m)) {
		numInStatus := m[status.Status(stateToCount)]
		f.delimitValuesWithTabs(stateToCount+":", fmt.Sprintf(" %d ", numInStatus))
	}
}