github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/storage/attach.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package storage 5 6 import ( 7 "github.com/juju/cmd" 8 "github.com/juju/errors" 9 10 "github.com/juju/juju/apiserver/params" 11 jujucmd "github.com/juju/juju/cmd" 12 "github.com/juju/juju/cmd/juju/common" 13 "github.com/juju/juju/cmd/modelcmd" 14 ) 15 16 // NewAttachStorageCommandWithAPI returns a command 17 // used to attach storage to application units. 18 func NewAttachStorageCommandWithAPI() cmd.Command { 19 cmd := &attachStorageCommand{} 20 cmd.newEntityAttacherCloser = func() (EntityAttacherCloser, error) { 21 return cmd.NewStorageAPI() 22 } 23 return modelcmd.Wrap(cmd) 24 } 25 26 // NewAttachStorageCommand returns a command used to 27 // attach storage to application units. 28 func NewAttachStorageCommand(new NewEntityAttacherCloserFunc) cmd.Command { 29 cmd := &attachStorageCommand{} 30 cmd.newEntityAttacherCloser = new 31 return modelcmd.Wrap(cmd) 32 } 33 34 const ( 35 attachStorageCommandDoc = ` 36 Attach existing storage to a unit. Specify a unit 37 and one or more storage IDs to attach to it. 38 39 Examples: 40 juju attach-storage postgresql/1 pgdata/0 41 ` 42 43 attachStorageCommandArgs = `<unit> <storage> [<storage> ...]` 44 ) 45 46 // attachStorageCommand adds unit storage instances dynamically. 47 type attachStorageCommand struct { 48 StorageCommandBase 49 modelcmd.IAASOnlyCommand 50 newEntityAttacherCloser NewEntityAttacherCloserFunc 51 unitId string 52 storageIds []string 53 } 54 55 // Init implements Command.Init. 56 func (c *attachStorageCommand) Init(args []string) error { 57 if len(args) < 2 { 58 return errors.New("attach-storage requires a unit ID and at least one storage ID") 59 } 60 c.unitId = args[0] 61 c.storageIds = args[1:] 62 return nil 63 } 64 65 // Info implements Command.Info. 66 func (c *attachStorageCommand) Info() *cmd.Info { 67 return jujucmd.Info(&cmd.Info{ 68 Name: "attach-storage", 69 Purpose: "Attaches existing storage to a unit.", 70 Doc: attachStorageCommandDoc, 71 Args: attachStorageCommandArgs, 72 }) 73 } 74 75 // Run implements Command.Run. 76 func (c *attachStorageCommand) Run(ctx *cmd.Context) error { 77 attacher, err := c.newEntityAttacherCloser() 78 if err != nil { 79 return err 80 } 81 defer attacher.Close() 82 83 results, err := attacher.Attach(c.unitId, c.storageIds) 84 if err != nil { 85 if params.IsCodeUnauthorized(err) { 86 common.PermissionsMessage(ctx.Stderr, "attach storage") 87 } 88 return errors.Trace(err) 89 } 90 for i, result := range results { 91 if result.Error == nil { 92 ctx.Infof("attaching %s to %s", c.storageIds[i], c.unitId) 93 } 94 } 95 var anyFailed bool 96 for i, result := range results { 97 if result.Error != nil { 98 ctx.Infof("failed to attach %s to %s: %s", c.storageIds[i], c.unitId, result.Error) 99 anyFailed = true 100 } 101 } 102 if anyFailed { 103 return cmd.ErrSilent 104 } 105 return nil 106 } 107 108 // NewEntityAttacherCloser is the type of a function that returns an 109 // EntityAttacherCloser. 110 type NewEntityAttacherCloserFunc func() (EntityAttacherCloser, error) 111 112 // EntityAttacherCloser extends EntityAttacher with a Closer method. 113 type EntityAttacherCloser interface { 114 EntityAttacher 115 Close() error 116 } 117 118 // EntityAttacher defines an interface for attaching storage with the 119 // specified IDs to a unit. 120 type EntityAttacher interface { 121 Attach(string, []string) ([]params.ErrorResult, error) 122 }