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