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