Beispiel #1
0
// formatConfigTabular writes a tabular summary of config information.
func formatConfigTabular(writer io.Writer, value interface{}) error {
	configValues, ok := value.(config.ConfigValues)
	if !ok {
		return errors.Errorf("expected value of type %T, got %T", configValues, value)
	}

	tw := output.TabWriter(writer)
	w := output.Wrapper{tw}

	var valueNames []string
	for name := range configValues {
		valueNames = append(valueNames, name)
	}
	sort.Strings(valueNames)
	w.Println("Attribute", "From", "Value")

	for _, name := range valueNames {
		info := configValues[name]
		out := &bytes.Buffer{}
		err := cmd.FormatYaml(out, info.Value)
		if err != nil {
			return errors.Annotatef(err, "formatting value for %q", name)
		}
		// Some attribute values have a newline appended
		// which makes the output messy.
		valString := strings.TrimSuffix(out.String(), "\n")
		w.Println(name, info.Source, valString)
	}

	tw.Flush()
	return nil
}
Beispiel #2
0
func formatServiceDetailTabular(writer io.Writer, resources FormattedServiceDetails) {
	// note that the unit resource can be a zero value here, to indicate that
	// the unit has not downloaded that resource yet.

	fmt.Fprintln(writer, "[Units]")

	sort.Sort(byUnitID(resources.Resources))
	// To format things into columns.
	tw := output.TabWriter(writer)

	// Write the header.
	fmt.Fprintln(tw, "Unit\tResource\tRevision\tExpected")

	for _, r := range resources.Resources {
		fmt.Fprintf(tw, "%v\t%v\t%v\t%v\n",
			r.unitNumber,
			r.Expected.Name,
			r.Unit.combinedRevision,
			r.revProgress,
		)
	}
	tw.Flush()

	writeUpdates(resources.Updates, writer, tw)
}
Beispiel #3
0
// FormatTabular writes a tabular summary of payloads.
func FormatTabular(writer io.Writer, value interface{}) error {
	payloads, valueConverted := value.([]FormattedPayload)
	if !valueConverted {
		return errors.Errorf("expected value of type %T, got %T", payloads, value)
	}

	// TODO(ericsnow) sort the rows first?

	tw := output.TabWriter(writer)

	// Write the header.
	fmt.Fprintln(tw, tabularSection)
	fmt.Fprintln(tw, tabularHeader)

	// Print each payload to its own row.
	for _, payload := range payloads {
		// tabularColumns must be kept in sync with these.
		fmt.Fprintf(tw, tabularRow+"\n",
			payload.Unit,
			payload.Machine,
			payload.Class,
			payload.Status,
			payload.Type,
			payload.ID,
			strings.Join(payload.Labels, " "),
		)
	}
	tw.Flush()

	return nil
}
Beispiel #4
0
Datei: list.go Projekt: bac/juju
func (c *listCommand) formatModelUsers(writer io.Writer, value interface{}) error {
	users, ok := value.(map[string]common.ModelUserInfo)
	if !ok {
		return errors.Errorf("expected value of type %T, got %T", users, value)
	}
	modelUsers := set.NewStrings()
	for name := range users {
		modelUsers.Add(name)
	}
	tw := output.TabWriter(writer)
	w := output.Wrapper{tw}
	w.Println("Name", "Display name", "Access", "Last connection")
	for _, name := range modelUsers.SortedValues() {
		user := users[name]

		var highlight *ansiterm.Context
		userName := name
		if c.isLoggedInUser(name) {
			userName += "*"
			highlight = output.CurrentHighlight
		}
		w.PrintColor(highlight, userName)
		w.Println(user.DisplayName, user.Access, user.LastConnection)
	}
	tw.Flush()
	return nil
}
Beispiel #5
0
Datei: list.go Projekt: bac/juju
func (c *listCommand) formatControllerUsers(writer io.Writer, value interface{}) error {
	users, valueConverted := value.([]UserInfo)
	if !valueConverted {
		return errors.Errorf("expected value of type %T, got %T", users, value)
	}

	tw := output.TabWriter(writer)
	w := output.Wrapper{tw}
	w.Println("Controller: " + c.ControllerName())
	w.Println()
	w.Println("Name", "Display name", "Access", "Date created", "Last connection")
	for _, user := range users {
		conn := user.LastConnection
		if user.Disabled {
			conn += " (disabled)"
		}
		var highlight *ansiterm.Context
		userName := user.Username
		if c.isLoggedInUser(user.Username) {
			userName += "*"
			highlight = output.CurrentHighlight
		}
		w.PrintColor(highlight, userName)
		w.Println(user.DisplayName, user.Access, user.DateCreated, conn)
	}
	tw.Flush()
	return nil
}
Beispiel #6
0
// FormatCharmTabular returns a tabular summary of charm resources.
func FormatCharmTabular(writer io.Writer, value interface{}) error {
	resources, valueConverted := value.([]FormattedCharmResource)
	if !valueConverted {
		return errors.Errorf("expected value of type %T, got %T", resources, value)
	}

	// TODO(ericsnow) sort the rows first?

	// To format things into columns.
	tw := output.TabWriter(writer)

	// Write the header.
	// We do not print a section label.
	fmt.Fprintln(tw, "Resource\tRevision")

	// Print each info to its own row.
	for _, res := range resources {
		// the column headers must be kept in sync with these.
		fmt.Fprintf(tw, "%s\t%d\n",
			res.Name,
			res.Revision,
		)
	}
	tw.Flush()

	return nil
}
Beispiel #7
0
// formatPoolsTabular returns a tabular summary of pool instances.
func formatPoolsTabular(writer io.Writer, pools map[string]PoolInfo) {
	tw := output.TabWriter(writer)
	print := func(values ...string) {
		fmt.Fprintln(tw, strings.Join(values, "\t"))
	}

	print("Name", "Provider", "Attrs")

	poolNames := make([]string, 0, len(pools))
	for name := range pools {
		poolNames = append(poolNames, name)
	}
	sort.Strings(poolNames)
	for _, name := range poolNames {
		pool := pools[name]
		// order by key for deterministic return
		keys := make([]string, 0, len(pool.Attrs))
		for key := range pool.Attrs {
			keys = append(keys, key)
		}
		sort.Strings(keys)
		attrs := make([]string, len(pool.Attrs))
		for i, key := range keys {
			attrs[i] = fmt.Sprintf("%v=%v", key, pool.Attrs[key])
		}
		print(name, pool.Provider, strings.Join(attrs, " "))
	}
	tw.Flush()
}
Beispiel #8
0
func formatRegionsTabular(writer io.Writer, regions yaml.MapSlice) error {
	tw := output.TabWriter(writer)
	w := output.Wrapper{tw}
	for _, r := range regions {
		w.Println(r.Key)
	}
	tw.Flush()
	return nil
}
Beispiel #9
0
func newSummaryFormatter(writer io.Writer) *summaryFormatter {
	f := &summaryFormatter{
		ipAddrs:     make([]net.IPNet, 0),
		netStrings:  make([]string, 0),
		openPorts:   set.NewStrings(),
		stateToUnit: make(map[status.Status]int),
	}
	f.tw = output.TabWriter(writer)
	return f
}
Beispiel #10
0
// formatCloudsTabular writes a tabular summary of cloud information.
func formatCloudsTabular(writer io.Writer, value interface{}) error {
	clouds, ok := value.(*cloudList)
	if !ok {
		return errors.Errorf("expected value of type %T, got %T", clouds, value)
	}

	tw := output.TabWriter(writer)
	p := func(values ...string) {
		text := strings.Join(values, "\t")
		fmt.Fprintln(tw, text)
	}
	p("CLOUD\tTYPE\tREGIONS")

	cloudNamesSorted := func(someClouds map[string]*cloudDetails) []string {
		// For tabular we'll sort alphabetically, user clouds last.
		var names []string
		for name, _ := range someClouds {
			names = append(names, name)
		}
		sort.Strings(names)
		return names
	}

	printClouds := func(someClouds map[string]*cloudDetails) {
		cloudNames := cloudNamesSorted(someClouds)

		for _, name := range cloudNames {
			info := someClouds[name]
			var regions []string
			for _, region := range info.Regions {
				regions = append(regions, fmt.Sprint(region.Key))
			}
			// TODO(wallyworld) - we should be smarter about handling
			// long region text, for now we'll display the first 7 as
			// that covers all clouds except AWS and Azure and will
			// prevent wrapping on a reasonable terminal width.
			regionCount := len(regions)
			if regionCount > 7 {
				regionCount = 7
			}
			regionText := strings.Join(regions[:regionCount], ", ")
			if len(regions) > 7 {
				regionText = regionText + " ..."
			}
			p(name, info.CloudType, regionText)
		}
	}
	printClouds(clouds.public)
	printClouds(clouds.builtin)
	printClouds(clouds.personal)

	tw.Flush()
	return nil
}
Beispiel #11
0
// formatVolumeListTabular returns a tabular summary of volume instances.
func formatVolumeListTabular(writer io.Writer, infos map[string]VolumeInfo) error {
	tw := output.TabWriter(writer)

	print := func(values ...string) {
		fmt.Fprintln(tw, strings.Join(values, "\t"))
	}
	print("Machine", "Unit", "Storage", "Id", "Provider Id", "Device", "Size", "State", "Message")

	volumeAttachmentInfos := make(volumeAttachmentInfos, 0, len(infos))
	for volumeId, info := range infos {
		volumeAttachmentInfo := volumeAttachmentInfo{
			VolumeId:   volumeId,
			VolumeInfo: info,
		}
		if info.Attachments == nil {
			volumeAttachmentInfos = append(volumeAttachmentInfos, volumeAttachmentInfo)
			continue
		}
		// Each unit attachment must have a corresponding volume
		// attachment. Enumerate each of the volume attachments,
		// and locate the corresponding unit attachment if any.
		// Each volume attachment has at most one corresponding
		// unit attachment.
		for machineId, machineInfo := range info.Attachments.Machines {
			volumeAttachmentInfo := volumeAttachmentInfo
			volumeAttachmentInfo.MachineId = machineId
			volumeAttachmentInfo.MachineVolumeAttachment = machineInfo
			for unitId, unitInfo := range info.Attachments.Units {
				if unitInfo.MachineId == machineId {
					volumeAttachmentInfo.UnitId = unitId
					volumeAttachmentInfo.UnitStorageAttachment = unitInfo
					break
				}
			}
			volumeAttachmentInfos = append(volumeAttachmentInfos, volumeAttachmentInfo)
		}
	}
	sort.Sort(volumeAttachmentInfos)

	for _, info := range volumeAttachmentInfos {
		var size string
		if info.Size > 0 {
			size = humanize.IBytes(info.Size * humanize.MiByte)
		}
		print(
			info.MachineId, info.UnitId, info.Storage,
			info.VolumeId, info.ProviderVolumeId,
			info.DeviceName, size,
			string(info.Status.Current), info.Status.Message,
		)
	}

	return tw.Flush()
}
Beispiel #12
0
// formatFilesystemListTabular writes a tabular summary of filesystem instances.
func formatFilesystemListTabular(writer io.Writer, infos map[string]FilesystemInfo) error {
	tw := output.TabWriter(writer)

	print := func(values ...string) {
		fmt.Fprintln(tw, strings.Join(values, "\t"))
	}
	print("MACHINE", "UNIT", "STORAGE", "ID", "VOLUME", "PROVIDER-ID", "MOUNTPOINT", "SIZE", "STATE", "MESSAGE")

	filesystemAttachmentInfos := make(filesystemAttachmentInfos, 0, len(infos))
	for filesystemId, info := range infos {
		filesystemAttachmentInfo := filesystemAttachmentInfo{
			FilesystemId:   filesystemId,
			FilesystemInfo: info,
		}
		if info.Attachments == nil {
			filesystemAttachmentInfos = append(filesystemAttachmentInfos, filesystemAttachmentInfo)
			continue
		}
		// Each unit attachment must have a corresponding filesystem
		// attachment. Enumerate each of the filesystem attachments,
		// and locate the corresponding unit attachment if any.
		// Each filesystem attachment has at most one corresponding
		// unit attachment.
		for machineId, machineInfo := range info.Attachments.Machines {
			filesystemAttachmentInfo := filesystemAttachmentInfo
			filesystemAttachmentInfo.MachineId = machineId
			filesystemAttachmentInfo.MachineFilesystemAttachment = machineInfo
			for unitId, unitInfo := range info.Attachments.Units {
				if unitInfo.MachineId == machineId {
					filesystemAttachmentInfo.UnitId = unitId
					filesystemAttachmentInfo.UnitStorageAttachment = unitInfo
					break
				}
			}
			filesystemAttachmentInfos = append(filesystemAttachmentInfos, filesystemAttachmentInfo)
		}
	}
	sort.Sort(filesystemAttachmentInfos)

	for _, info := range filesystemAttachmentInfos {
		var size string
		if info.Size > 0 {
			size = humanize.IBytes(info.Size * humanize.MiByte)
		}
		print(
			info.MachineId, info.UnitId, info.Storage,
			info.FilesystemId, info.Volume, info.ProviderFilesystemId,
			info.MountPoint, size,
			string(info.Status.Current), info.Status.Message,
		)
	}

	return tw.Flush()
}
Beispiel #13
0
// formatMetadataTabular writes a tabular summary of cloud image metadata.
func formatMetadataTabular(writer io.Writer, metadata []MetadataInfo) {
	tw := output.TabWriter(writer)
	print := func(values ...string) {
		fmt.Fprintln(tw, strings.Join(values, "\t"))
	}
	print("Source", "Series", "Arch", "Region", "Image id", "Stream", "Virt Type", "Storage Type")

	for _, m := range metadata {
		print(m.Source, m.Series, m.Arch, m.Region, m.ImageId, m.Stream, m.VirtType, m.RootStorageType)
	}
	tw.Flush()
}
Beispiel #14
0
// formatConfigTabular writes a tabular summary of default config information.
func formatDefaultConfigTabular(writer io.Writer, value interface{}) error {
	defaultValues, ok := value.(config.ModelDefaultAttributes)
	if !ok {
		return errors.Errorf("expected value of type %T, got %T", defaultValues, value)
	}

	tw := output.TabWriter(writer)
	w := output.Wrapper{tw}

	p := func(name string, value config.AttributeDefaultValues) {
		var c, d interface{}
		switch value.Default {
		case nil:
			d = "-"
		case "":
			d = `""`
		default:
			d = value.Default
		}
		switch value.Controller {
		case nil:
			c = "-"
		case "":
			c = `""`
		default:
			c = value.Controller
		}
		w.Println(name, d, c)
		for _, region := range value.Regions {
			w.Println("  "+region.Name, region.Value, "-")
		}
	}
	var valueNames []string
	for name := range defaultValues {
		valueNames = append(valueNames, name)
	}
	sort.Strings(valueNames)

	w.Println("Attribute", "Default", "Controller")

	for _, name := range valueNames {
		info := defaultValues[name]
		out := &bytes.Buffer{}
		err := cmd.FormatYaml(out, info)
		if err != nil {
			return errors.Annotatef(err, "formatting value for %q", name)
		}
		p(name, info)
	}

	tw.Flush()
	return nil
}
Beispiel #15
0
// formatMetadataTabular writes a tabular summary of cloud image metadata.
func formatMetadataTabular(writer io.Writer, metadata []MetadataInfo) {
	tw := output.TabWriter(writer)
	print := func(values ...string) {
		fmt.Fprintln(tw, strings.Join(values, "\t"))
	}
	print("SOURCE", "SERIES", "ARCH", "REGION", "IMAGE-ID", "STREAM", "VIRT-TYPE", "STORAGE-TYPE")

	for _, m := range metadata {
		print(m.Source, m.Series, m.Arch, m.Region, m.ImageId, m.Stream, m.VirtType, m.RootStorageType)
	}
	tw.Flush()
}
Beispiel #16
0
// FormatMachineTabular writes a tabular summary of machine
func FormatMachineTabular(writer io.Writer, forceColor bool, value interface{}) error {
	fs, valueConverted := value.(formattedMachineStatus)
	if !valueConverted {
		return errors.Errorf("expected value of type %T, got %T", fs, value)
	}
	tw := output.TabWriter(writer)
	if forceColor {
		tw.SetColorCapable(forceColor)
	}
	printMachines(tw, fs.Machines)
	tw.Flush()

	return nil
}
Beispiel #17
0
Datei: list.go Projekt: bac/juju
// printTabular prints the list of actions in tabular format
func (c *listCommand) printTabular(writer io.Writer, value interface{}) error {
	list, ok := value.([]listOutput)
	if !ok {
		return errors.New("unexpected value")
	}

	tw := output.TabWriter(writer)
	fmt.Fprintf(tw, "%s\t%s\n", "Action", "Description")
	for _, value := range list {
		fmt.Fprintf(tw, "%s\t%s\n", value.action, strings.TrimSpace(value.description))
	}
	tw.Flush()
	return nil
}
Beispiel #18
0
Datei: list.go Projekt: bac/juju
// formatCloudsTabular writes a tabular summary of cloud information.
func formatCloudsTabular(writer io.Writer, value interface{}) error {
	clouds, ok := value.(*cloudList)
	if !ok {
		return errors.Errorf("expected value of type %T, got %T", clouds, value)
	}

	tw := output.TabWriter(writer)
	w := output.Wrapper{tw}
	w.Println("Cloud", "Regions", "Default", "Type", "Description")
	w.SetColumnAlignRight(1)

	cloudNamesSorted := func(someClouds map[string]*cloudDetails) []string {
		// For tabular we'll sort alphabetically, user clouds last.
		var names []string
		for name, _ := range someClouds {
			names = append(names, name)
		}
		sort.Strings(names)
		return names
	}

	printClouds := func(someClouds map[string]*cloudDetails, color *ansiterm.Context) {
		cloudNames := cloudNamesSorted(someClouds)

		for _, name := range cloudNames {
			info := someClouds[name]
			defaultRegion := ""
			if len(info.Regions) > 0 {
				defaultRegion = info.RegionsMap[info.Regions[0].Key.(string)].Name
			}
			description := info.CloudDescription
			if len(description) > 40 {
				description = description[:39]
			}
			w.PrintColor(color, name)
			w.Println(len(info.Regions), defaultRegion, info.CloudType, description)
		}
	}
	printClouds(clouds.public, nil)
	printClouds(clouds.builtin, nil)
	printClouds(clouds.personal, ansiterm.Foreground(ansiterm.BrightBlue))

	w.Println("\nTry 'list-regions <cloud>' to see available regions.")
	w.Println("'show-cloud <cloud>' or 'regions --format yaml <cloud>' can be used to see region endpoints.")
	w.Println("'add-cloud' can add private clouds or private infrastructure.")
	w.Println("Update the known public clouds with 'update-clouds'.")
	tw.Flush()
	return nil
}
Beispiel #19
0
func formatWhoAmITabular(writer io.Writer, value interface{}) error {
	details, ok := value.(whoAmI)
	if !ok {
		return errors.Errorf("expected value of type %T, got %T", details, value)
	}
	tw := output.TabWriter(writer)
	fmt.Fprintf(tw, "Controller:\t%s\n", details.ControllerName)
	modelName := details.ModelName
	if modelName == "" {
		modelName = "<no-current-model>"
	}
	fmt.Fprintf(tw, "Model:\t%s\n", modelName)
	fmt.Fprintf(tw, "User:\t%s", details.UserName)
	return tw.Flush()
}
Beispiel #20
0
Datei: list.go Projekt: bac/juju
// FormatTabularBlockedModels writes out tabular format for blocked models.
// This method is exported as it is also used by destroy-model.
func FormatTabularBlockedModels(writer io.Writer, value interface{}) error {
	models, ok := value.([]modelBlockInfo)
	if !ok {
		return errors.Errorf("expected value of type %T, got %T", models, value)
	}

	tw := output.TabWriter(writer)
	w := output.Wrapper{tw}
	w.Println("Name", "Model UUID", "Owner", "Disabled commands")
	for _, model := range models {
		w.Println(model.Name, model.UUID, model.Owner, strings.Join(model.CommandSets, ", "))
	}
	tw.Flush()
	return nil
}
Beispiel #21
0
// formatCredentialsTabular writes a tabular summary of cloud information.
func formatCredentialsTabular(writer io.Writer, value interface{}) error {
	credentials, ok := value.(credentialsMap)
	if !ok {
		return errors.Errorf("expected value of type %T, got %T", credentials, value)
	}

	if len(credentials.Credentials) == 0 {
		fmt.Fprintln(writer, "No credentials to display.")
		return nil
	}

	// For tabular we'll sort alphabetically by cloud, and then by credential name.
	var cloudNames []string
	for name := range credentials.Credentials {
		cloudNames = append(cloudNames, name)
	}
	sort.Strings(cloudNames)

	tw := output.TabWriter(writer)
	p := func(values ...string) {
		text := strings.Join(values, "\t")
		fmt.Fprintln(tw, text)
	}
	p("CLOUD\tCREDENTIALS")
	for _, cloudName := range cloudNames {
		var haveDefault bool
		var credentialNames []string
		credentials := credentials.Credentials[cloudName]
		for credentialName := range credentials.Credentials {
			if credentialName == credentials.DefaultCredential {
				credentialNames = append([]string{credentialName + "*"}, credentialNames...)
				haveDefault = true
			} else {
				credentialNames = append(credentialNames, credentialName)
			}
		}
		if haveDefault {
			sort.Strings(credentialNames[1:])
		} else {
			sort.Strings(credentialNames)
		}
		p(cloudName, strings.Join(credentialNames, ", "))
	}
	tw.Flush()

	return nil
}
Beispiel #22
0
Datei: list.go Projekt: bac/juju
// printTabular prints the list of spaces in tabular format
func (c *listCommand) printTabular(writer io.Writer, value interface{}) error {
	tw := output.TabWriter(writer)
	if c.Short {
		list, ok := value.(formattedShortList)
		if !ok {
			return errors.New("unexpected value")
		}
		fmt.Fprintln(tw, "Space")
		spaces := list.Spaces
		sort.Strings(spaces)
		for _, space := range spaces {
			fmt.Fprintf(tw, "%v\n", space)
		}
	} else {
		list, ok := value.(formattedList)
		if !ok {
			return errors.New("unexpected value")
		}

		fmt.Fprintf(tw, "%s\t%s\n", "Space", "Subnets")
		spaces := []string{}
		for name, _ := range list.Spaces {
			spaces = append(spaces, name)
		}
		sort.Strings(spaces)
		for _, name := range spaces {
			subnets := list.Spaces[name]
			fmt.Fprintf(tw, "%s", name)
			if len(subnets) == 0 {
				fmt.Fprintf(tw, "\n")
				continue
			}
			cidrs := []string{}
			for subnet, _ := range subnets {
				cidrs = append(cidrs, subnet)
			}
			sort.Strings(cidrs)
			for _, cidr := range cidrs {
				fmt.Fprintf(tw, "\t%v\n", cidr)
			}
		}
	}
	tw.Flush()
	return nil
}
Beispiel #23
0
// formatSummary returns a summary of available plans.
func formatSummary(writer io.Writer, value interface{}) error {
	plans, ok := value.([]plan)
	if !ok {
		return errors.Errorf("expected value of type %T, got %T", plans, value)
	}
	tw := output.TabWriter(writer)
	p := func(values ...interface{}) {
		for _, v := range values {
			fmt.Fprintf(tw, "%s\t", v)
		}
		fmt.Fprintln(tw)
	}
	p("Plan", "Price")
	for _, plan := range plans {
		p(plan.URL, plan.Price)
	}
	tw.Flush()
	return nil
}
Beispiel #24
0
Datei: list.go Projekt: bac/juju
// formatBlocks writes block list representation.
func formatBlocks(writer io.Writer, value interface{}) error {
	blocks, ok := value.([]BlockInfo)
	if !ok {
		return errors.Errorf("expected value of type %T, got %T", blocks, value)
	}

	if len(blocks) == 0 {
		fmt.Fprintf(writer, "No commands are currently disabled.")
		return nil
	}

	tw := output.TabWriter(writer)
	w := output.Wrapper{tw}
	w.Println("Disabled commands", "Message")
	for _, info := range blocks {
		w.Println(info.Commands, info.Message)
	}
	tw.Flush()

	return nil
}
Beispiel #25
0
func formatUnitDetailTabular(writer io.Writer, resources FormattedUnitDetails) {
	// note that the unit resource can be a zero value here, to indicate that
	// the unit has not downloaded that resource yet.

	fmt.Fprintln(writer, "[Unit]")

	sort.Sort(byUnitID(resources))
	// To format things into columns.
	tw := output.TabWriter(writer)

	// Write the header.
	fmt.Fprintln(tw, "RESOURCE\tREVISION\tEXPECTED")

	for _, r := range resources {
		fmt.Fprintf(tw, "%v\t%v\t%v\n",
			r.Expected.Name,
			r.Unit.combinedRevision,
			r.revProgress,
		)
	}
	tw.Flush()
}
Beispiel #26
0
func formatUnitTabular(writer io.Writer, resources []FormattedUnitResource) {
	// TODO(ericsnow) sort the rows first?

	fmt.Fprintln(writer, "[Unit]")

	// To format things into columns.
	tw := output.TabWriter(writer)

	// Write the header.
	// We do not print a section label.
	fmt.Fprintln(tw, "Resource\tRevision")

	// Print each info to its own row.
	for _, r := range resources {
		// the column headers must be kept in sync with these.
		fmt.Fprintf(tw, "%v\t%v\n",
			r.Name,
			r.combinedRevision,
		)
	}
	tw.Flush()
}
Beispiel #27
0
func (c *addModelCommand) unsupportedCloudOrRegionError(cloudClient CloudAPI, defaultCloudTag names.CloudTag) (err error) {
	clouds, err := cloudClient.Clouds()
	if err != nil {
		return errors.Annotate(err, "querying supported clouds")
	}
	cloudNames := make([]string, 0, len(clouds))
	for tag := range clouds {
		cloudNames = append(cloudNames, tag.Id())
	}
	sort.Strings(cloudNames)

	var buf bytes.Buffer
	tw := output.TabWriter(&buf)
	fmt.Fprintln(tw, "CLOUD\tREGIONS")
	for _, cloudName := range cloudNames {
		cloud := clouds[names.NewCloudTag(cloudName)]
		regionNames := make([]string, len(cloud.Regions))
		for i, region := range cloud.Regions {
			regionNames[i] = region.Name
		}
		fmt.Fprintf(tw, "%s\t%s\n", cloudName, strings.Join(regionNames, ", "))
	}
	tw.Flush()

	var prefix string
	if defaultCloudTag != (names.CloudTag{}) {
		prefix = fmt.Sprintf(`
%q is neither a cloud supported by this controller,
nor a region in the controller's default cloud %q.
The clouds/regions supported by this controller are:`[1:],
			c.CloudRegion, defaultCloudTag.Id())
	} else {
		prefix = fmt.Sprintf(`
%q is not a cloud supported by this controller,
and there is no default cloud. The clouds/regions supported
by this controller are:`[1:], c.CloudRegion)
	}
	return errors.Errorf("%s\n\n%s", prefix, buf.String())
}
Beispiel #28
0
func formatServiceTabular(writer io.Writer, info FormattedServiceInfo) {
	// TODO(ericsnow) sort the rows first?

	fmt.Fprintln(writer, "[Application]")
	tw := output.TabWriter(writer)
	fmt.Fprintln(tw, "Resource\tSupplied by\tRevision")

	// Print each info to its own row.
	for _, r := range info.Resources {
		// the column headers must be kept in sync with these.
		fmt.Fprintf(tw, "%v\t%v\t%v\n",
			r.Name,
			r.combinedOrigin,
			r.combinedRevision,
		)
	}

	// Don't forget to flush!  The Tab writer won't actually write to the output
	// until you flush, which would then have its output incorrectly ordered
	// with the below fmt.Fprintlns.
	tw.Flush()

	writeUpdates(info.Updates, writer, tw)
}
Beispiel #29
0
// formatListTabular writes a tabular summary of storage instances.
func formatStorageListTabular(writer io.Writer, storageInfo map[string]StorageInfo) error {
	tw := output.TabWriter(writer)
	p := func(values ...interface{}) {
		for _, v := range values {
			fmt.Fprintf(tw, "%v\t", v)
		}
		fmt.Fprintln(tw)
	}
	p("[Storage]")
	p("Unit\tId\tLocation\tStatus\tMessage")

	byUnit := make(map[string]map[string]storageAttachmentInfo)
	for storageId, storageInfo := range storageInfo {
		if storageInfo.Attachments == nil {
			byStorage := byUnit[""]
			if byStorage == nil {
				byStorage = make(map[string]storageAttachmentInfo)
				byUnit[""] = byStorage
			}
			byStorage[storageId] = storageAttachmentInfo{
				storageId:  storageId,
				kind:       storageInfo.Kind,
				persistent: storageInfo.Persistent,
				status:     storageInfo.Status,
			}
			continue
		}
		for unitId, a := range storageInfo.Attachments.Units {
			byStorage := byUnit[unitId]
			if byStorage == nil {
				byStorage = make(map[string]storageAttachmentInfo)
				byUnit[unitId] = byStorage
			}
			byStorage[storageId] = storageAttachmentInfo{
				storageId:  storageId,
				unitId:     unitId,
				kind:       storageInfo.Kind,
				persistent: storageInfo.Persistent,
				location:   a.Location,
				status:     storageInfo.Status,
			}
		}
	}

	// First sort by units
	units := make([]string, 0, len(storageInfo))
	for unit := range byUnit {
		units = append(units, unit)
	}
	sort.Strings(slashSeparatedIds(units))

	for _, unit := range units {
		// Then sort by storage ids
		byStorage := byUnit[unit]
		storageIds := make([]string, 0, len(byStorage))
		for storageId := range byStorage {
			storageIds = append(storageIds, storageId)
		}
		sort.Strings(slashSeparatedIds(storageIds))

		for _, storageId := range storageIds {
			info := byStorage[storageId]
			p(info.unitId, info.storageId, info.location, info.status.Current, info.status.Message)
		}
	}
	tw.Flush()

	return nil
}
// formatControllersTabular returns a tabular summary of controller/model items
// sorted by controller name alphabetically.
func formatControllersTabular(writer io.Writer, set ControllerSet, promptRefresh bool) error {
	tw := output.TabWriter(writer)
	w := output.Wrapper{tw}

	if promptRefresh && len(set.Controllers) > 0 {
		fmt.Fprintln(writer, "Use --refresh to see the latest information.")
		fmt.Fprintln(writer)
	}
	w.Println("CONTROLLER", "MODEL", "USER", "ACCESS", "CLOUD/REGION", "MODELS", "MACHINES", "HA", "VERSION")
	tw.SetColumnAlignRight(5)
	tw.SetColumnAlignRight(6)
	tw.SetColumnAlignRight(7)

	names := []string{}
	for name := range set.Controllers {
		names = append(names, name)
	}
	sort.Strings(names)

	for _, name := range names {
		c := set.Controllers[name]
		modelName := noValueDisplay
		if c.ModelName != "" {
			modelName = c.ModelName
		}
		userName := noValueDisplay
		access := noValueDisplay
		if c.User != "" {
			userName = c.User
			access = notKnownDisplay
			if c.Access != "" {
				access = c.Access
			}
		}
		if name == set.CurrentController {
			name += "*"
			w.PrintColor(output.CurrentHighlight, name)
		} else {
			w.Print(name)
		}
		cloudRegion := c.Cloud
		if c.CloudRegion != "" {
			cloudRegion += "/" + c.CloudRegion
		}
		agentVersion := c.AgentVersion
		staleVersion := false
		if agentVersion == "" {
			agentVersion = notKnownDisplay
		} else {
			agentVersionNum, err := version.Parse(agentVersion)
			staleVersion = err == nil && jujuversion.Current.Compare(agentVersionNum) > 0
		}
		machineCount := noValueDisplay
		if c.MachineCount != nil && *c.MachineCount > 0 {
			machineCount = fmt.Sprintf("%d", *c.MachineCount)
		}
		modelCount := noValueDisplay
		if c.ModelCount != nil && *c.ModelCount > 0 {
			modelCount = fmt.Sprintf("%d", *c.ModelCount)
		}
		w.Print(modelName, userName, access, cloudRegion, modelCount, machineCount)
		controllerMachineInfo, warn := controllerMachineStatus(c.ControllerMachines)
		if warn {
			w.PrintColor(output.WarningHighlight, controllerMachineInfo)
		} else {
			w.Print(controllerMachineInfo)
		}
		if staleVersion {
			w.PrintColor(output.WarningHighlight, agentVersion)
		} else {
			w.Print(agentVersion)
		}
		w.Println()
	}
	tw.Flush()
	return nil
}