github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/cmd/juju/subnet/add.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package subnet 5 6 import ( 7 "strings" 8 9 "github.com/juju/cmd" 10 "github.com/juju/errors" 11 "github.com/juju/juju/network" 12 "gopkg.in/juju/names.v2" 13 14 "github.com/juju/juju/apiserver/params" 15 "github.com/juju/juju/cmd/juju/common" 16 "github.com/juju/juju/cmd/modelcmd" 17 ) 18 19 // NewAddCommand returns a command used to add an existing subnet to Juju. 20 func NewAddCommand() cmd.Command { 21 return modelcmd.Wrap(&addCommand{}) 22 } 23 24 // addCommand calls the API to add an existing subnet to Juju. 25 type addCommand struct { 26 SubnetCommandBase 27 28 CIDR names.SubnetTag 29 RawCIDR string // before normalizing (e.g. 10.10.0.0/8 to 10.0.0.0/8) 30 ProviderId string 31 Space names.SpaceTag 32 Zones []string 33 } 34 35 const addCommandDoc = ` 36 Adds an existing subnet to Juju, making it available for use. Unlike 37 "juju create-subnet", this command does not create a new subnet, so it 38 is supported on a wider variety of clouds (where SDN features are not 39 available, e.g. MAAS). The subnet will be associated with the given 40 existing Juju network space. 41 42 Subnets can be referenced by either their CIDR or ProviderId (if the 43 provider supports it). If CIDR is used an multiple subnets have the 44 same CIDR, an error will be returned, including the list of possible 45 provider IDs uniquely identifying each subnet. 46 47 Any availablility zones associated with the added subnet are automatically 48 discovered using the cloud API (if supported). If this is not possible, 49 since any subnet needs to be part of at least one zone, specifying 50 zone(s) is required. 51 ` 52 53 // Info is defined on the cmd.Command interface. 54 func (c *addCommand) Info() *cmd.Info { 55 return &cmd.Info{ 56 Name: "add-subnet", 57 Args: "<CIDR>|<provider-id> <space> [<zone1> <zone2> ...]", 58 Purpose: "Add an existing subnet to Juju.", 59 Doc: strings.TrimSpace(addCommandDoc), 60 } 61 } 62 63 // Init is defined on the cmd.Command interface. It checks the 64 // arguments for sanity and sets up the command to run. 65 func (c *addCommand) Init(args []string) (err error) { 66 defer errors.DeferredAnnotatef(&err, "invalid arguments specified") 67 68 // Ensure we have 2 or more arguments. 69 switch len(args) { 70 case 0: 71 return errNoCIDROrID 72 case 1: 73 return errNoSpace 74 } 75 76 // Try to validate first argument as a CIDR first. 77 c.RawCIDR = args[0] 78 c.CIDR, err = c.ValidateCIDR(args[0], false) 79 if err != nil { 80 // If it's not a CIDR it could be a ProviderId, so ignore the 81 // error. 82 c.ProviderId = args[0] 83 c.RawCIDR = "" 84 } 85 86 // Validate the space name. 87 c.Space, err = c.ValidateSpace(args[1]) 88 if err != nil { 89 return err 90 } 91 92 // Add any given zones. 93 for _, zone := range args[2:] { 94 c.Zones = append(c.Zones, zone) 95 } 96 return nil 97 } 98 99 // Run implements Command.Run. 100 func (c *addCommand) Run(ctx *cmd.Context) error { 101 return c.RunWithAPI(ctx, func(api SubnetAPI, ctx *cmd.Context) error { 102 if c.CIDR.Id() != "" && c.RawCIDR != c.CIDR.Id() { 103 ctx.Infof( 104 "WARNING: using CIDR %q instead of the incorrectly specified %q.", 105 c.CIDR.Id(), c.RawCIDR, 106 ) 107 } 108 109 // Add the existing subnet. 110 err := api.AddSubnet(c.CIDR, network.Id(c.ProviderId), c.Space, c.Zones) 111 // TODO(dimitern): Change this once the API returns a concrete error. 112 if err != nil && strings.Contains(err.Error(), "multiple subnets with") { 113 // Special case: multiple subnets with the same CIDR exist 114 ctx.Infof("ERROR: %v.", err) 115 return nil 116 } else if err != nil { 117 if params.IsCodeUnauthorized(err) { 118 common.PermissionsMessage(ctx.Stderr, "add a subnet") 119 } 120 return errors.Annotatef(err, "cannot add subnet") 121 } 122 123 if c.ProviderId != "" { 124 ctx.Infof("added subnet with ProviderId %q in space %q", c.ProviderId, c.Space.Id()) 125 } else { 126 ctx.Infof("added subnet with CIDR %q in space %q", c.CIDR.Id(), c.Space.Id()) 127 } 128 return nil 129 }) 130 }