github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/cmd/juju/block/list.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package block
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  	"sort"
    10  	"strings"
    11  
    12  	"github.com/juju/cmd"
    13  	"github.com/juju/errors"
    14  	"github.com/juju/gnuflag"
    15  	"gopkg.in/juju/names.v2"
    16  
    17  	"github.com/juju/juju/api"
    18  	"github.com/juju/juju/api/controller"
    19  	"github.com/juju/juju/apiserver/params"
    20  	"github.com/juju/juju/cmd/modelcmd"
    21  	"github.com/juju/juju/cmd/output"
    22  )
    23  
    24  // NewListCommand returns the command that lists the disabled
    25  // commands for the model.
    26  func NewListCommand() cmd.Command {
    27  	return modelcmd.Wrap(&listCommand{
    28  		apiFunc: func(c newAPIRoot) (blockListAPI, error) {
    29  			return getBlockAPI(c)
    30  		},
    31  		controllerAPIFunc: func(c newControllerAPIRoot) (controllerListAPI, error) {
    32  			return getControllerAPI(c)
    33  		},
    34  	})
    35  }
    36  
    37  const listCommandDoc = `
    38  List disabled commands for the model.
    39  ` + commandSets + `
    40  See also:
    41      disable-command
    42      enable-command
    43  `
    44  
    45  // listCommand list blocks.
    46  type listCommand struct {
    47  	modelcmd.ModelCommandBase
    48  	apiFunc           func(newAPIRoot) (blockListAPI, error)
    49  	controllerAPIFunc func(newControllerAPIRoot) (controllerListAPI, error)
    50  	all               bool
    51  	out               cmd.Output
    52  }
    53  
    54  // Init implements Command.Init.
    55  func (c *listCommand) Init(args []string) (err error) {
    56  	return cmd.CheckEmpty(args)
    57  }
    58  
    59  // Info implements Command.Info.
    60  func (c *listCommand) Info() *cmd.Info {
    61  	return &cmd.Info{
    62  		Name:    "disabled-commands",
    63  		Purpose: "List disabled commands.",
    64  		Doc:     listCommandDoc,
    65  		Aliases: []string{"list-disabled-commands"},
    66  	}
    67  }
    68  
    69  // SetFlags implements Command.SetFlags.
    70  func (c *listCommand) SetFlags(f *gnuflag.FlagSet) {
    71  	c.ModelCommandBase.SetFlags(f)
    72  	f.BoolVar(&c.all, "all", false, "Lists for all models (administrative users only)")
    73  	c.out.AddFlags(f, "tabular", map[string]cmd.Formatter{
    74  		"yaml":    cmd.FormatYaml,
    75  		"json":    cmd.FormatJson,
    76  		"tabular": c.formatter,
    77  	})
    78  }
    79  
    80  // Run implements Command.Run.
    81  func (c *listCommand) Run(ctx *cmd.Context) (err error) {
    82  	if c.all {
    83  		return c.listForController(ctx)
    84  	}
    85  	return c.listForModel(ctx)
    86  }
    87  
    88  const noBlocks = "No commands are currently disabled."
    89  
    90  func (c *listCommand) listForModel(ctx *cmd.Context) (err error) {
    91  	api, err := c.apiFunc(c)
    92  	if err != nil {
    93  		return errors.Trace(err)
    94  	}
    95  	defer api.Close()
    96  
    97  	result, err := api.List()
    98  	if err != nil {
    99  		return errors.Trace(err)
   100  	}
   101  	if len(result) == 0 && c.out.Name() == "tabular" {
   102  		ctx.Infof(noBlocks)
   103  		return nil
   104  	}
   105  	return c.out.Write(ctx, formatBlockInfo(result))
   106  }
   107  
   108  func (c *listCommand) listForController(ctx *cmd.Context) (err error) {
   109  	api, err := c.controllerAPIFunc(c)
   110  	if err != nil {
   111  		return errors.Trace(err)
   112  	}
   113  	defer api.Close()
   114  
   115  	result, err := api.ListBlockedModels()
   116  	if err != nil {
   117  		return errors.Trace(err)
   118  	}
   119  	if len(result) == 0 && c.out.Name() == "tabular" {
   120  		ctx.Infof(noBlocks)
   121  		return nil
   122  	}
   123  	info, err := FormatModelBlockInfo(result)
   124  	if err != nil {
   125  		return errors.Trace(err)
   126  	}
   127  	return c.out.Write(ctx, info)
   128  }
   129  
   130  func (c *listCommand) formatter(writer io.Writer, value interface{}) error {
   131  	if c.all {
   132  		return FormatTabularBlockedModels(writer, value)
   133  	}
   134  	return formatBlocks(writer, value)
   135  }
   136  
   137  // blockListAPI defines the client API methods that block list command uses.
   138  type blockListAPI interface {
   139  	Close() error
   140  	List() ([]params.Block, error)
   141  }
   142  
   143  // controllerListAPI defines the methods on the controller API endpoint
   144  // that the blocks command calls.
   145  type controllerListAPI interface {
   146  	Close() error
   147  	ListBlockedModels() ([]params.ModelBlockInfo, error)
   148  }
   149  
   150  // BlockInfo defines the serialization behaviour of the block information.
   151  type BlockInfo struct {
   152  	Commands string `yaml:"command-set" json:"command-set"`
   153  	Message  string `yaml:"message,omitempty" json:"message,omitempty"`
   154  }
   155  
   156  // formatBlockInfo takes a set of Block and creates a
   157  // mapping to information structures.
   158  func formatBlockInfo(all []params.Block) []BlockInfo {
   159  	output := make([]BlockInfo, len(all))
   160  	for i, one := range all {
   161  		set, ok := toCmdValue[one.Type]
   162  		if !ok {
   163  			set = "<unknown>"
   164  		}
   165  		output[i] = BlockInfo{
   166  			Commands: set,
   167  			Message:  one.Message,
   168  		}
   169  	}
   170  	return output
   171  }
   172  
   173  // formatBlocks writes block list representation.
   174  func formatBlocks(writer io.Writer, value interface{}) error {
   175  	blocks, ok := value.([]BlockInfo)
   176  	if !ok {
   177  		return errors.Errorf("expected value of type %T, got %T", blocks, value)
   178  	}
   179  
   180  	if len(blocks) == 0 {
   181  		fmt.Fprintf(writer, "No commands are currently disabled.")
   182  		return nil
   183  	}
   184  
   185  	tw := output.TabWriter(writer)
   186  	w := output.Wrapper{tw}
   187  	w.Println("DISABLED COMMANDS", "MESSAGE")
   188  	for _, info := range blocks {
   189  		w.Println(info.Commands, info.Message)
   190  	}
   191  	tw.Flush()
   192  
   193  	return nil
   194  }
   195  
   196  type newControllerAPIRoot interface {
   197  	NewControllerAPIRoot() (api.Connection, error)
   198  }
   199  
   200  // getControllerAPI returns a block api for block manipulation.
   201  func getControllerAPI(c newControllerAPIRoot) (*controller.Client, error) {
   202  	root, err := c.NewControllerAPIRoot()
   203  	if err != nil {
   204  		return nil, errors.Trace(err)
   205  	}
   206  	return controller.NewClient(root), nil
   207  }
   208  
   209  type modelBlockInfo struct {
   210  	Name        string   `yaml:"name" json:"name"`
   211  	UUID        string   `yaml:"model-uuid" json:"model-uuid"`
   212  	Owner       string   `yaml:"owner" json:"owner"`
   213  	CommandSets []string `yaml:"disabled-commands,omitempty" json:"disabled-commands,omitempty"`
   214  }
   215  
   216  func FormatModelBlockInfo(all []params.ModelBlockInfo) ([]modelBlockInfo, error) {
   217  	output := make([]modelBlockInfo, len(all))
   218  	for i, one := range all {
   219  		tag, err := names.ParseUserTag(one.OwnerTag)
   220  		if err != nil {
   221  			return nil, errors.Trace(err)
   222  		}
   223  		output[i] = modelBlockInfo{
   224  			Name:        one.Name,
   225  			UUID:        one.UUID,
   226  			Owner:       tag.Canonical(),
   227  			CommandSets: blocksToStr(one.Blocks),
   228  		}
   229  	}
   230  	return output, nil
   231  }
   232  
   233  // FormatTabularBlockedModels writes out tabular format for blocked models.
   234  // This method is exported as it is also used by destroy-model.
   235  func FormatTabularBlockedModels(writer io.Writer, value interface{}) error {
   236  	models, ok := value.([]modelBlockInfo)
   237  	if !ok {
   238  		return errors.Errorf("expected value of type %T, got %T", models, value)
   239  	}
   240  
   241  	tw := output.TabWriter(writer)
   242  	w := output.Wrapper{tw}
   243  	w.Println("NAME", "MODEL UUID", "OWNER", "DISABLED COMMANDS")
   244  	for _, model := range models {
   245  		w.Println(model.Name, model.UUID, model.Owner, strings.Join(model.CommandSets, ", "))
   246  	}
   247  	tw.Flush()
   248  	return nil
   249  }
   250  
   251  func blocksToStr(blocks []string) []string {
   252  	result := make([]string, len(blocks))
   253  	for i, val := range blocks {
   254  		result[i] = operationFromType(val)
   255  	}
   256  	sort.Strings(result)
   257  	return result
   258  }