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