Пример #1
0
Файл: input.go Проект: elos/elos
// dateInput retrieves a time.Time value as textual input over a
// a series of messages
//
// Use dateInput when you need a full date and time, i.e., 1/1/1 12:00
// If you only need a time, use 'timeInput'.
func dateInput(ui cli.Ui, text string) (time.Time, error) {
	ui.Output(text + " [date]")

	var (
		inputErr                    error
		year, month, day, hour, min int
	)

	if year, inputErr = intInput(ui, "Year (e.g., 2016)"); inputErr != nil {
		return *new(time.Time), inputErr
	}

	if month, inputErr = intInput(ui, "Month (e.g., 1 for January)"); inputErr != nil {
		return *new(time.Time), inputErr
	}

	if day, inputErr = intInput(ui, "Day [e.g., 1]"); inputErr != nil {
		return *new(time.Time), inputErr
	}

	if hour, inputErr = intInput(ui, "Hour [e.g., 13]"); inputErr != nil {
		return *new(time.Time), inputErr
	}

	if min, inputErr = intInput(ui, "Minute [e.g., 59]"); inputErr != nil {
		return *new(time.Time), inputErr
	}

	return time.Date(year, time.Month(month), day, hour, min, 0, 0, time.Local), nil
}
Пример #2
0
func (c *Command) startShutdownWatcher(agent *Agent, ui cli.Ui) (graceful <-chan struct{}, forceful <-chan struct{}) {
	g := make(chan struct{})
	f := make(chan struct{})
	graceful = g
	forceful = f

	go func() {
		<-c.ShutdownCh

		c.lock.Lock()
		c.shuttingDown = true
		c.lock.Unlock()

		ui.Output("Gracefully shutting down agent...")
		go func() {
			if err := agent.Shutdown(); err != nil {
				ui.Error(fmt.Sprintf("Error: %s", err))
				return
			}
			close(g)
		}()

		select {
		case <-g:
			// Gracefully shut down properly
		case <-c.ShutdownCh:
			close(f)
		}
	}()

	return
}
Пример #3
0
func validateContext(ctx *terraform.Context, ui cli.Ui) bool {
	if ws, es := ctx.Validate(); len(ws) > 0 || len(es) > 0 {
		ui.Output(
			"There are warnings and/or errors related to your configuration. Please\n" +
				"fix these before continuing.\n")

		if len(ws) > 0 {
			ui.Warn("Warnings:\n")
			for _, w := range ws {
				ui.Warn(fmt.Sprintf("  * %s", w))
			}

			if len(es) > 0 {
				ui.Output("")
			}
		}

		if len(es) > 0 {
			ui.Error("Errors:\n")
			for _, e := range es {
				ui.Error(fmt.Sprintf("  * %s", e))
			}
			return false
		} else {
			ui.Warn(fmt.Sprintf("\n"+
				"No errors found. Continuing with %d warning(s).\n", len(ws)))
			return true
		}
	}

	return true
}
Пример #4
0
func PrintRawField(ui cli.Ui, secret *api.Secret, field string) int {
	var val interface{}
	switch {
	case secret.Auth != nil:
		switch field {
		case "token":
			val = secret.Auth.ClientToken
		case "token_accessor":
			val = secret.Auth.Accessor
		case "token_duration":
			val = secret.Auth.LeaseDuration
		case "token_renewable":
			val = secret.Auth.Renewable
		case "token_policies":
			val = secret.Auth.Policies
		default:
			val = secret.Data[field]
		}

	case secret.WrapInfo != nil:
		switch field {
		case "wrapping_token":
			val = secret.WrapInfo.Token
		case "wrapping_token_ttl":
			val = secret.WrapInfo.TTL
		case "wrapping_token_creation_time":
			val = secret.WrapInfo.CreationTime.Format(time.RFC3339Nano)
		case "wrapped_accessor":
			val = secret.WrapInfo.WrappedAccessor
		default:
			val = secret.Data[field]
		}

	default:
		switch field {
		case "refresh_interval":
			val = secret.LeaseDuration
		default:
			val = secret.Data[field]
		}
	}

	if val != nil {
		// c.Ui.Output() prints a CR character which in this case is
		// not desired. Since Vault CLI currently only uses BasicUi,
		// which writes to standard output, os.Stdout is used here to
		// directly print the message. If mitchellh/cli exposes method
		// to print without CR, this check needs to be removed.
		if reflect.TypeOf(ui).String() == "*cli.BasicUi" {
			fmt.Fprintf(os.Stdout, fmt.Sprintf("%v", val))
		} else {
			ui.Output(fmt.Sprintf("%v", val))
		}
		return 0
	} else {
		ui.Error(fmt.Sprintf(
			"Field %s not present in secret", field))
		return 1
	}
}
Пример #5
0
// dumpAllocStatus is a helper to generate a more user-friendly error message
// for scheduling failures, displaying a high level status of why the job
// could not be scheduled out.
func dumpAllocStatus(ui cli.Ui, alloc *api.Allocation, length int) {
	// Print filter stats
	ui.Output(fmt.Sprintf("Allocation %q status %q (%d/%d nodes filtered)",
		limit(alloc.ID, length), alloc.ClientStatus,
		alloc.Metrics.NodesFiltered, alloc.Metrics.NodesEvaluated))
	ui.Output(formatAllocMetrics(alloc.Metrics, true, "  "))
}
Пример #6
0
func outputFormatTable(ui cli.Ui, s *api.Secret, whitespace bool) int {
	config := columnize.DefaultConfig()
	config.Delim = "♨"
	config.Glue = "\t"
	config.Prefix = ""

	input := make([]string, 0, 5)
	input = append(input, fmt.Sprintf("Key %s Value", config.Delim))

	if s.LeaseID != "" && s.LeaseDuration > 0 {
		input = append(input, fmt.Sprintf("lease_id %s %s", config.Delim, s.LeaseID))
		input = append(input, fmt.Sprintf(
			"lease_duration %s %d", config.Delim, s.LeaseDuration))
		input = append(input, fmt.Sprintf(
			"lease_renewable %s %s", config.Delim, strconv.FormatBool(s.Renewable)))
	}

	if s.Auth != nil {
		input = append(input, fmt.Sprintf("token %s %s", config.Delim, s.Auth.ClientToken))
		input = append(input, fmt.Sprintf("token_duration %s %d", config.Delim, s.Auth.LeaseDuration))
		input = append(input, fmt.Sprintf("token_renewable %s %v", config.Delim, s.Auth.Renewable))
		input = append(input, fmt.Sprintf("token_policies %s %v", config.Delim, s.Auth.Policies))
		for k, v := range s.Auth.Metadata {
			input = append(input, fmt.Sprintf("token_meta_%s %s %#v", k, config.Delim, v))
		}
	}

	for k, v := range s.Data {
		input = append(input, fmt.Sprintf("%s %s %v", k, config.Delim, v))
	}

	ui.Output(columnize.Format(input, config))
	return 0
}
Пример #7
0
func (y YamlFormatter) Output(ui cli.Ui, secret *api.Secret, data interface{}) error {
	b, err := yaml.Marshal(data)
	if err == nil {
		ui.Output(strings.TrimSpace(string(b)))
	}
	return err
}
Пример #8
0
Файл: cal.go Проект: elos/elos
func createFixture(ui cli.Ui, ownerID string, db data.DB) (fixture *models.Fixture, err error) {
	ui.Output("Creating a fixture")

	fixture = models.NewFixture()
	fixture.SetID(db.NewID())
	fixture.OwnerId = ownerID
	fixture.CreatedAt = time.Now()

	if fixture.Name, err = stringInput(ui, "Name of the fixture:"); err != nil {
		return
	}

	if fixture.Label, err = boolInput(ui, "Is this a label?"); err != nil {
		return
	}

	if !fixture.Label {
		if fixture.StartTime, err = timeInput(ui, "Start time of fixture?"); err != nil {
			return
		}

		if fixture.EndTime, err = timeInput(ui, "End time of fixture?"); err != nil {
			return
		}
	}

	fixture.UpdatedAt = time.Now()

	err = db.Save(fixture)
	return
}
Пример #9
0
func (t TableFormatter) OutputList(ui cli.Ui, secret *api.Secret, list []interface{}) error {
	config := columnize.DefaultConfig()
	config.Delim = "♨"
	config.Glue = "\t"
	config.Prefix = ""

	input := make([]string, 0, 5)

	input = append(input, "Keys")

	keys := make([]string, 0, len(list))
	for _, k := range list {
		keys = append(keys, k.(string))
	}
	sort.Strings(keys)

	for _, k := range keys {
		input = append(input, fmt.Sprintf("%s", k))
	}

	if len(secret.Warnings) != 0 {
		input = append(input, "")
		input = append(input, "The following warnings were returned from the Vault server:")
		for _, warning := range secret.Warnings {
			input = append(input, fmt.Sprintf("* %s", warning))
		}
	}

	ui.Output(columnize.Format(input, config))
	return nil
}
Пример #10
0
func outputFormatTableList(ui cli.Ui, s *api.Secret) int {
	config := columnize.DefaultConfig()
	config.Delim = "♨"
	config.Glue = "\t"
	config.Prefix = ""

	input := make([]string, 0, 5)

	input = append(input, "Keys")

	keys := make([]string, 0, len(s.Data["keys"].([]interface{})))
	for _, k := range s.Data["keys"].([]interface{}) {
		keys = append(keys, k.(string))
	}
	sort.Strings(keys)

	for _, k := range keys {
		input = append(input, fmt.Sprintf("%s", k))
	}

	if len(s.Warnings) != 0 {
		input = append(input, "")
		for _, warning := range s.Warnings {
			input = append(input, fmt.Sprintf("* %s", warning))
		}
	}

	ui.Output(columnize.Format(input, config))
	return 0
}
Пример #11
0
func (j JsonFormatter) Output(ui cli.Ui, secret *api.Secret, data interface{}) error {
	b, err := json.Marshal(data)
	if err == nil {
		var out bytes.Buffer
		json.Indent(&out, b, "", "\t")
		ui.Output(out.String())
	}
	return err
}
Пример #12
0
func (t TableFormatter) OutputSecret(ui cli.Ui, secret, s *api.Secret) error {
	config := columnize.DefaultConfig()
	config.Delim = "♨"
	config.Glue = "\t"
	config.Prefix = ""

	input := make([]string, 0, 5)

	input = append(input, fmt.Sprintf("Key %s Value", config.Delim))

	if s.LeaseDuration > 0 {
		if s.LeaseID != "" {
			input = append(input, fmt.Sprintf("lease_id %s %s", config.Delim, s.LeaseID))
		}
		input = append(input, fmt.Sprintf(
			"lease_duration %s %d", config.Delim, s.LeaseDuration))
		if s.LeaseID != "" {
			input = append(input, fmt.Sprintf(
				"lease_renewable %s %s", config.Delim, strconv.FormatBool(s.Renewable)))
		}
	}

	if s.Auth != nil {
		input = append(input, fmt.Sprintf("token %s %s", config.Delim, s.Auth.ClientToken))
		input = append(input, fmt.Sprintf("token_accessor %s %s", config.Delim, s.Auth.Accessor))
		input = append(input, fmt.Sprintf("token_duration %s %d", config.Delim, s.Auth.LeaseDuration))
		input = append(input, fmt.Sprintf("token_renewable %s %v", config.Delim, s.Auth.Renewable))
		input = append(input, fmt.Sprintf("token_policies %s %v", config.Delim, s.Auth.Policies))
		for k, v := range s.Auth.Metadata {
			input = append(input, fmt.Sprintf("token_meta_%s %s %#v", k, config.Delim, v))
		}
	}

	keys := make([]string, 0, len(s.Data))
	for k := range s.Data {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	for _, k := range keys {
		input = append(input, fmt.Sprintf("%s %s %v", k, config.Delim, s.Data[k]))
	}

	if len(s.Warnings) != 0 {
		input = append(input, "")
		input = append(input, "The following warnings were returned from the Vault server:")
		for _, warning := range s.Warnings {
			input = append(input, fmt.Sprintf("* %s", warning))
		}
	}

	ui.Output(columnize.Format(input, config))
	return nil
}
Пример #13
0
func outputFormatYAMLList(ui cli.Ui, s *api.Secret) int {
	b, err := yaml.Marshal(s.Data["keys"])
	if err != nil {
		ui.Error(fmt.Sprintf(
			"Error formatting secret: %s", err))
		return 1
	}

	ui.Output(strings.TrimSpace(string(b)))
	return 0
}
Пример #14
0
func outputFormatJSONList(ui cli.Ui, s *api.Secret) int {
	b, err := json.Marshal(s.Data["keys"])
	if err != nil {
		ui.Error(fmt.Sprintf(
			"Error formatting keys: %s", err))
		return 1
	}

	var out bytes.Buffer
	json.Indent(&out, b, "", "\t")
	ui.Output(out.String())
	return 0
}
Пример #15
0
Файл: input.go Проект: elos/elos
// intInput requests an integer input (signed)
//
// Use intInput if you need to retrieve an integer.
func intInput(ui cli.Ui, text string) (int, error) {
	for {
		input, err := ui.Ask(text + " [integer]:")
		if err != nil {
			return 0, err
		}

		i64, err := strconv.ParseInt(input, 10, 64)
		if err == nil {
			return int(i64), nil
		}

		out := "Invalid input, please try again. Valid integer expressions include: 1, 12, -300 etc."
		ui.Output(strings.TrimSpace(out))
	}
}
Пример #16
0
// directOutput -
func directOutput(ui cli.Ui, channel, prefix, line string) {

	channelType := strings.ToUpper(channel)
	if ui == nil {
		fmt.Printf("%s%s", prefix, line)
	} else {
		switch channelType {
		case "ERROR":
			ui.Error(fmt.Sprintf("%s%s", prefix, line))
		case "INFO":
			ui.Info(fmt.Sprintf("%s%s", prefix, line))
		case "WARN":
			ui.Warn(fmt.Sprintf("%s%s", prefix, line))
		default:
			ui.Output(fmt.Sprintf("%s%s", prefix, line))
		}
	}
}
Пример #17
0
Файл: input.go Проект: elos/elos
// timeInput retrieves a time.Time value, but only pays attention
// to the hour and the minute components. It fills in the year 0,
// month 0, day 0, second 0 and nsecond 0. It uses time.Local for
// location information.
//
// Use timeInput if you need to retrieve a time of the form 12:45,
// but if you care also abou the calendrical components, such as
// the year, month and day, use 'dateInput'.
func timeInput(ui cli.Ui, text string) (t time.Time, err error) {
	ui.Output(text + " [time]")

	var (
		inputErr  error
		hour, min int
	)

	if hour, inputErr = intInput(ui, "Hour [e.g., 13]"); inputErr != nil {
		return *new(time.Time), inputErr
	}

	if min, inputErr = intInput(ui, "Minute [e.g., 59]"); inputErr != nil {
		return *new(time.Time), inputErr
	}

	return time.Date(0, 0, 0, hour, min, 0, 0, time.Local), nil
}
Пример #18
0
func (c *ConsoleCommand) modeInteractive(session *repl.Session, ui cli.Ui) int {
	// Configure input
	l, err := readline.NewEx(wrappedreadline.Override(&readline.Config{
		Prompt:            "> ",
		InterruptPrompt:   "^C",
		EOFPrompt:         "exit",
		HistorySearchFold: true,
	}))
	if err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Error initializing console: %s",
			err))
		return 1
	}
	defer l.Close()

	for {
		// Read a line
		line, err := l.Readline()
		if err == readline.ErrInterrupt {
			if len(line) == 0 {
				break
			} else {
				continue
			}
		} else if err == io.EOF {
			break
		}

		out, err := session.Handle(line)
		if err == repl.ErrSessionExit {
			break
		}
		if err != nil {
			ui.Error(err.Error())
			continue
		}

		ui.Output(out)
	}

	return 0
}
Пример #19
0
Файл: cal.go Проект: elos/elos
func printFixtures(ui cli.Ui, fixtures []*models.Fixture) {
	if len(fixtures) == 0 {
		ui.Output(" -- No fixtures")
		return
	}
	sort.Sort(byStartTime(fixtures))
	for _, f := range fixtures {
		var output string
		if f.Label {
			output = fmt.Sprintf("* %s [Label]", f.Name)
		} else {
			output = fmt.Sprintf(`
			 * %s [%s - %s]
			`, f.Name, f.StartTime.Format("15:04"), f.EndTime.Format("15:04"))
		}

		ui.Output(strings.TrimSpace(output))
	}
}
Пример #20
0
func (t TableFormatter) OutputList(ui cli.Ui, secret *api.Secret, list []interface{}) error {
	config := columnize.DefaultConfig()
	config.Delim = "♨"
	config.Glue = "\t"
	config.Prefix = ""

	input := make([]string, 0, 5)

	if len(list) > 0 {
		input = append(input, "Keys")
		input = append(input, "----")

		keys := make([]string, 0, len(list))
		for _, k := range list {
			keys = append(keys, k.(string))
		}
		sort.Strings(keys)

		for _, k := range keys {
			input = append(input, fmt.Sprintf("%s", k))
		}
	}

	tableOutputStr := columnize.Format(input, config)

	// Print the warning separately because the length of first
	// column in the output will be increased by the length of
	// the longest warning string making the output look bad.
	warningsInput := make([]string, 0, 5)
	if len(secret.Warnings) != 0 {
		warningsInput = append(warningsInput, "")
		warningsInput = append(warningsInput, "The following warnings were returned from the Vault server:")
		for _, warning := range secret.Warnings {
			warningsInput = append(warningsInput, fmt.Sprintf("* %s", warning))
		}
	}

	warningsOutputStr := columnize.Format(warningsInput, config)

	ui.Output(fmt.Sprintf("%s\n%s", tableOutputStr, warningsOutputStr))

	return nil
}
Пример #21
0
func (c *ConsoleCommand) modePiped(session *repl.Session, ui cli.Ui) int {
	var lastResult string
	scanner := bufio.NewScanner(wrappedstreams.Stdin())
	for scanner.Scan() {
		// Handle it. If there is an error exit immediately
		result, err := session.Handle(strings.TrimSpace(scanner.Text()))
		if err != nil {
			ui.Error(err.Error())
			return 1
		}

		// Store the last result
		lastResult = result
	}

	// Output the final result
	ui.Output(lastResult)

	return 0
}
Пример #22
0
Файл: input.go Проект: elos/elos
// boolInput requests a boolean input
//
// Use this where you need to take a boolean value. If you are
// looking for a confirmation prompt, however, use 'yesNo'
func boolInput(ui cli.Ui, text string) (bool, error) {
	for {
		input, err := ui.Ask(text + " [boolean]:")
		if err != nil {
			return false, err
		}

		switch input {
		case "yes":
			return true, err
		case "no":
			return false, err
		default:
			b, err := strconv.ParseBool(input)
			if err == nil {
				return b, nil
			}

			out := " Invalid input, please try again. Valid boolean expressions include: true, false, 0, 1 etc."
			ui.Output(strings.TrimSpace(out))
		}
	}
}
Пример #23
0
// dumpAllocStatus is a helper to generate a more user-friendly error message
// for scheduling failures, displaying a high level status of why the job
// could not be scheduled out.
func dumpAllocStatus(ui cli.Ui, alloc *api.Allocation, length int) {
	// Print filter stats
	ui.Output(fmt.Sprintf("Allocation %q status %q (%d/%d nodes filtered)",
		limit(alloc.ID, length), alloc.ClientStatus,
		alloc.Metrics.NodesFiltered, alloc.Metrics.NodesEvaluated))

	// Print a helpful message if we have an eligibility problem
	if alloc.Metrics.NodesEvaluated == 0 {
		ui.Output("  * No nodes were eligible for evaluation")
	}

	// Print a helpful message if the user has asked for a DC that has no
	// available nodes.
	for dc, available := range alloc.Metrics.NodesAvailable {
		if available == 0 {
			ui.Output(fmt.Sprintf("  * No nodes are available in datacenter %q", dc))
		}
	}

	// Print filter info
	for class, num := range alloc.Metrics.ClassFiltered {
		ui.Output(fmt.Sprintf("  * Class %q filtered %d nodes", class, num))
	}
	for cs, num := range alloc.Metrics.ConstraintFiltered {
		ui.Output(fmt.Sprintf("  * Constraint %q filtered %d nodes", cs, num))
	}

	// Print exhaustion info
	if ne := alloc.Metrics.NodesExhausted; ne > 0 {
		ui.Output(fmt.Sprintf("  * Resources exhausted on %d nodes", ne))
	}
	for class, num := range alloc.Metrics.ClassExhausted {
		ui.Output(fmt.Sprintf("  * Class %q exhausted on %d nodes", class, num))
	}
	for dim, num := range alloc.Metrics.DimensionExhausted {
		ui.Output(fmt.Sprintf("  * Dimension %q exhausted on %d nodes", dim, num))
	}

	// Print scores
	for name, score := range alloc.Metrics.Scores {
		ui.Output(fmt.Sprintf("  * Score %q = %f", name, score))
	}
}
Пример #24
0
// dumpAllocStatus is a helper to generate a more user-friendly error message
// for scheduling failures, displaying a high level status of why the job
// could not be scheduled out.
func dumpAllocStatus(ui cli.Ui, alloc *api.Allocation) {
	// Print filter stats
	ui.Output(fmt.Sprintf("Allocation %q status %q (%d/%d nodes filtered)",
		alloc.ID, alloc.ClientStatus,
		alloc.Metrics.NodesFiltered, alloc.Metrics.NodesEvaluated))

	// Print a helpful message if we have an eligibility problem
	if alloc.Metrics.NodesEvaluated == 0 {
		ui.Output("  * No nodes were eligible for evaluation")
	}

	// Print filter info
	for class, num := range alloc.Metrics.ClassFiltered {
		ui.Output(fmt.Sprintf("  * Class %q filtered %d nodes", class, num))
	}
	for cs, num := range alloc.Metrics.ConstraintFiltered {
		ui.Output(fmt.Sprintf("  * Constraint %q filtered %d nodes", cs, num))
	}

	// Print exhaustion info
	if ne := alloc.Metrics.NodesExhausted; ne > 0 {
		ui.Output(fmt.Sprintf("  * Resources exhausted on %d nodes", ne))
	}
	for class, num := range alloc.Metrics.ClassExhausted {
		ui.Output(fmt.Sprintf("  * Class %q exhausted on %d nodes", class, num))
	}
	for dim, num := range alloc.Metrics.DimensionExhausted {
		ui.Output(fmt.Sprintf("  * Dimension %q exhausted on %d nodes", dim, num))
	}

	// Print scores
	for name, score := range alloc.Metrics.Scores {
		ui.Output(fmt.Sprintf("  * Score %q = %f", name, score))
	}
}
Пример #25
0
func (t TableFormatter) OutputSecret(ui cli.Ui, secret, s *api.Secret) error {
	config := columnize.DefaultConfig()
	config.Delim = "♨"
	config.Glue = "\t"
	config.Prefix = ""

	input := make([]string, 0, 5)

	input = append(input, fmt.Sprintf("Key %s Value", config.Delim))

	input = append(input, fmt.Sprintf("--- %s -----", config.Delim))

	if s.LeaseDuration > 0 {
		if s.LeaseID != "" {
			input = append(input, fmt.Sprintf("lease_id %s %s", config.Delim, s.LeaseID))
			input = append(input, fmt.Sprintf(
				"lease_duration %s %d", config.Delim, s.LeaseDuration))
		} else {
			input = append(input, fmt.Sprintf(
				"refresh_interval %s %d", config.Delim, s.LeaseDuration))
		}
		if s.LeaseID != "" {
			input = append(input, fmt.Sprintf(
				"lease_renewable %s %s", config.Delim, strconv.FormatBool(s.Renewable)))
		}
	}

	if s.Auth != nil {
		input = append(input, fmt.Sprintf("token %s %s", config.Delim, s.Auth.ClientToken))
		input = append(input, fmt.Sprintf("token_accessor %s %s", config.Delim, s.Auth.Accessor))
		input = append(input, fmt.Sprintf("token_duration %s %d", config.Delim, s.Auth.LeaseDuration))
		input = append(input, fmt.Sprintf("token_renewable %s %v", config.Delim, s.Auth.Renewable))
		input = append(input, fmt.Sprintf("token_policies %s %v", config.Delim, s.Auth.Policies))
		for k, v := range s.Auth.Metadata {
			input = append(input, fmt.Sprintf("token_meta_%s %s %#v", k, config.Delim, v))
		}
	}

	if s.WrapInfo != nil {
		input = append(input, fmt.Sprintf("wrapping_token: %s %s", config.Delim, s.WrapInfo.Token))
		input = append(input, fmt.Sprintf("wrapping_token_ttl: %s %d", config.Delim, s.WrapInfo.TTL))
		input = append(input, fmt.Sprintf("wrapping_token_creation_time: %s %s", config.Delim, s.WrapInfo.CreationTime.String()))
		if s.WrapInfo.WrappedAccessor != "" {
			input = append(input, fmt.Sprintf("wrapped_accessor: %s %s", config.Delim, s.WrapInfo.WrappedAccessor))
		}
	}

	keys := make([]string, 0, len(s.Data))
	for k := range s.Data {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	for _, k := range keys {
		input = append(input, fmt.Sprintf("%s %s %v", k, config.Delim, s.Data[k]))
	}

	tableOutputStr := columnize.Format(input, config)

	// Print the warning separately because the length of first
	// column in the output will be increased by the length of
	// the longest warning string making the output look bad.
	warningsInput := make([]string, 0, 5)
	if len(s.Warnings) != 0 {
		warningsInput = append(warningsInput, "")
		warningsInput = append(warningsInput, "The following warnings were returned from the Vault server:")
		for _, warning := range s.Warnings {
			warningsInput = append(warningsInput, fmt.Sprintf("* %s", warning))
		}
	}

	warningsOutputStr := columnize.Format(warningsInput, config)

	ui.Output(fmt.Sprintf("%s\n%s", tableOutputStr, warningsOutputStr))

	return nil
}