github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/cmd/juju/subnet/list.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 "net" 8 "strings" 9 10 "github.com/juju/gnuflag" 11 12 "github.com/juju/cmd" 13 "github.com/juju/errors" 14 "github.com/juju/juju/apiserver/params" 15 "gopkg.in/juju/names.v2" 16 17 "github.com/juju/juju/cmd/modelcmd" 18 "github.com/juju/juju/cmd/output" 19 ) 20 21 // NewListCommand returns a cammin used to list all subnets 22 // known to Juju. 23 func NewListCommand() cmd.Command { 24 return modelcmd.Wrap(&listCommand{}) 25 } 26 27 // listCommand displays a list of all subnets known to Juju 28 type listCommand struct { 29 SubnetCommandBase 30 31 SpaceName string 32 ZoneName string 33 34 spaceTag *names.SpaceTag 35 36 Out cmd.Output 37 } 38 39 const listCommandDoc = ` 40 Displays a list of all subnets known to Juju. Results can be filtered 41 using the optional --space and/or --zone arguments to only display 42 subnets associated with a given network space and/or availability zone. 43 44 Like with other Juju commands, the output and its format can be changed 45 using the --format and --output (or -o) optional arguments. Supported 46 output formats include "yaml" (default) and "json". To redirect the 47 output to a file, use --output. 48 ` 49 50 // Info is defined on the cmd.Command interface. 51 func (c *listCommand) Info() *cmd.Info { 52 return &cmd.Info{ 53 Name: "subnets", 54 Args: "[--space <name>] [--zone <name>] [--format yaml|json] [--output <path>]", 55 Purpose: "List subnets known to Juju.", 56 Doc: strings.TrimSpace(listCommandDoc), 57 Aliases: []string{"list-subnets"}, 58 } 59 } 60 61 // SetFlags is defined on the cmd.Command interface. 62 func (c *listCommand) SetFlags(f *gnuflag.FlagSet) { 63 c.SubnetCommandBase.SetFlags(f) 64 c.Out.AddFlags(f, "yaml", output.DefaultFormatters) 65 66 f.StringVar(&c.SpaceName, "space", "", "Filter results by space name") 67 f.StringVar(&c.ZoneName, "zone", "", "Filter results by zone name") 68 } 69 70 // Init is defined on the cmd.Command interface. It checks the 71 // arguments for sanity and sets up the command to run. 72 func (c *listCommand) Init(args []string) error { 73 // No arguments are accepted, just flags. 74 err := cmd.CheckEmpty(args) 75 if err != nil { 76 return err 77 } 78 79 // Validate space name, if given and store as tag. 80 c.spaceTag = nil 81 if c.SpaceName != "" { 82 tag, err := c.ValidateSpace(c.SpaceName) 83 if err != nil { 84 c.SpaceName = "" 85 return err 86 } 87 c.spaceTag = &tag 88 } 89 return nil 90 } 91 92 // Run implements Command.Run. 93 func (c *listCommand) Run(ctx *cmd.Context) error { 94 return c.RunWithAPI(ctx, func(api SubnetAPI, ctx *cmd.Context) error { 95 // Validate space and/or zone, if given to display a nicer error 96 // message. 97 // Get the list of subnets, filtering them as requested. 98 subnets, err := api.ListSubnets(c.spaceTag, c.ZoneName) 99 if err != nil { 100 return errors.Annotate(err, "cannot list subnets") 101 } 102 103 // Display a nicer message in case no subnets were found. 104 if len(subnets) == 0 { 105 if c.SpaceName != "" || c.ZoneName != "" { 106 ctx.Infof("No subnets found matching requested criteria.") 107 } else { 108 ctx.Infof("No subnets to display.") 109 } 110 return nil 111 } 112 113 // Construct the output list for displaying with the chosen 114 // format. 115 result := formattedList{ 116 Subnets: make(map[string]formattedSubnet), 117 } 118 for _, sub := range subnets { 119 subResult := formattedSubnet{ 120 ProviderId: sub.ProviderId, 121 Zones: sub.Zones, 122 } 123 124 // Use the CIDR to determine the subnet type. 125 if ip, _, err := net.ParseCIDR(sub.CIDR); err != nil { 126 return errors.Errorf("subnet %q has invalid CIDR", sub.CIDR) 127 } else if ip.To4() != nil { 128 subResult.Type = typeIPv4 129 } else if ip.To16() != nil { 130 subResult.Type = typeIPv6 131 } 132 // Space must be valid, but verify anyway. 133 spaceTag, err := names.ParseSpaceTag(sub.SpaceTag) 134 if err != nil { 135 return errors.Annotatef(err, "subnet %q has invalid space", sub.CIDR) 136 } 137 subResult.Space = spaceTag.Id() 138 139 // Display correct status according to the life cycle value. 140 switch sub.Life { 141 case params.Alive: 142 subResult.Status = statusInUse 143 case params.Dying, params.Dead: 144 subResult.Status = statusTerminating 145 } 146 147 result.Subnets[sub.CIDR] = subResult 148 } 149 150 return c.Out.Write(ctx, result) 151 }) 152 } 153 154 const ( 155 typeIPv4 = "ipv4" 156 typeIPv6 = "ipv6" 157 158 statusInUse = "in-use" 159 statusTerminating = "terminating" 160 ) 161 162 type formattedList struct { 163 Subnets map[string]formattedSubnet `json:"subnets" yaml:"subnets"` 164 } 165 166 type formattedSubnet struct { 167 Type string `json:"type" yaml:"type"` 168 ProviderId string `json:"provider-id,omitempty" yaml:"provider-id,omitempty"` 169 Status string `json:"status,omitempty" yaml:"status,omitempty"` 170 Space string `json:"space" yaml:"space"` 171 Zones []string `json:"zones" yaml:"zones"` 172 }