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 }