~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/cmd/juju/subnet/list.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

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