~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/resource/cmd/show_service.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 cmd
 
5
 
 
6
import (
 
7
        "github.com/juju/cmd"
 
8
        "github.com/juju/errors"
 
9
        "gopkg.in/juju/names.v2"
 
10
        "launchpad.net/gnuflag"
 
11
 
 
12
        "github.com/juju/juju/cmd/modelcmd"
 
13
        "github.com/juju/juju/resource"
 
14
)
 
15
 
 
16
// ShowServiceClient has the API client methods needed by ShowServiceCommand.
 
17
type ShowServiceClient interface {
 
18
        // ListResources returns info about resources for applications in the model.
 
19
        ListResources(services []string) ([]resource.ServiceResources, error)
 
20
        // Close closes the connection.
 
21
        Close() error
 
22
}
 
23
 
 
24
// ShowServiceDeps is a type that contains external functions that ShowService
 
25
// depends on to function.
 
26
type ShowServiceDeps struct {
 
27
        // NewClient returns the value that wraps the API for showing application
 
28
        // resources from the server.
 
29
        NewClient func(*ShowServiceCommand) (ShowServiceClient, error)
 
30
}
 
31
 
 
32
// ShowServiceCommand implements the upload command.
 
33
type ShowServiceCommand struct {
 
34
        modelcmd.ModelCommandBase
 
35
 
 
36
        details bool
 
37
        deps    ShowServiceDeps
 
38
        out     cmd.Output
 
39
        target  string
 
40
}
 
41
 
 
42
// NewShowServiceCommand returns a new command that lists resources defined
 
43
// by a charm.
 
44
func NewShowServiceCommand(deps ShowServiceDeps) *ShowServiceCommand {
 
45
        return &ShowServiceCommand{deps: deps}
 
46
}
 
47
 
 
48
// Info implements cmd.Command.Info.
 
49
func (c *ShowServiceCommand) Info() *cmd.Info {
 
50
        return &cmd.Info{
 
51
                Name:    "resources",
 
52
                Aliases: []string{"list-resources"},
 
53
                Args:    "application-or-unit",
 
54
                Purpose: "show the resources for a service or unit",
 
55
                Doc: `
 
56
This command shows the resources required by and those in use by an existing
 
57
application or unit in your model.  When run for an application, it will also show any
 
58
updates available for resources from the charmstore.
 
59
`,
 
60
        }
 
61
}
 
62
 
 
63
// SetFlags implements cmd.Command.SetFlags.
 
64
func (c *ShowServiceCommand) SetFlags(f *gnuflag.FlagSet) {
 
65
        const defaultFlag = "tabular"
 
66
        c.out.AddFlags(f, defaultFlag, map[string]cmd.Formatter{
 
67
                defaultFlag: FormatSvcTabular,
 
68
                "yaml":      cmd.FormatYaml,
 
69
                "json":      cmd.FormatJson,
 
70
        })
 
71
 
 
72
        f.BoolVar(&c.details, "details", false, "show detailed information about resources used by each unit.")
 
73
}
 
74
 
 
75
// Init implements cmd.Command.Init. It will return an error satisfying
 
76
// errors.BadRequest if you give it an incorrect number of arguments.
 
77
func (c *ShowServiceCommand) Init(args []string) error {
 
78
        if len(args) == 0 {
 
79
                return errors.NewBadRequest(nil, "missing application name")
 
80
        }
 
81
        c.target = args[0]
 
82
        if err := cmd.CheckEmpty(args[1:]); err != nil {
 
83
                return errors.NewBadRequest(err, "")
 
84
        }
 
85
        return nil
 
86
}
 
87
 
 
88
// Run implements cmd.Command.Run.
 
89
func (c *ShowServiceCommand) Run(ctx *cmd.Context) error {
 
90
        apiclient, err := c.deps.NewClient(c)
 
91
        if err != nil {
 
92
                return errors.Annotatef(err, "can't connect to %s", c.ConnectionName())
 
93
        }
 
94
        defer apiclient.Close()
 
95
 
 
96
        var unit string
 
97
        var service string
 
98
        if names.IsValidApplication(c.target) {
 
99
                service = c.target
 
100
        } else {
 
101
                service, err = names.UnitApplication(c.target)
 
102
                if err != nil {
 
103
                        return errors.Errorf("%q is neither an application nor a unit", c.target)
 
104
                }
 
105
                unit = c.target
 
106
        }
 
107
 
 
108
        vals, err := apiclient.ListResources([]string{service})
 
109
        if err != nil {
 
110
                return errors.Trace(err)
 
111
        }
 
112
        if len(vals) != 1 {
 
113
                return errors.Errorf("bad data returned from server")
 
114
        }
 
115
        v := vals[0]
 
116
        if unit == "" {
 
117
                return c.formatServiceResources(ctx, v)
 
118
        }
 
119
        return c.formatUnitResources(ctx, unit, service, v)
 
120
}
 
121
 
 
122
func (c *ShowServiceCommand) formatServiceResources(ctx *cmd.Context, sr resource.ServiceResources) error {
 
123
        if c.details {
 
124
                formatted, err := FormatServiceDetails(sr)
 
125
                if err != nil {
 
126
                        return errors.Trace(err)
 
127
                }
 
128
 
 
129
                return c.out.Write(ctx, formatted)
 
130
        }
 
131
 
 
132
        formatted, err := formatServiceResources(sr)
 
133
        if err != nil {
 
134
                return errors.Trace(err)
 
135
        }
 
136
        return c.out.Write(ctx, formatted)
 
137
}
 
138
 
 
139
func (c *ShowServiceCommand) formatUnitResources(ctx *cmd.Context, unit, service string, sr resource.ServiceResources) error {
 
140
        if c.details {
 
141
                formatted, err := detailedResources(unit, sr)
 
142
                if err != nil {
 
143
                        return errors.Trace(err)
 
144
                }
 
145
                return c.out.Write(ctx, FormattedUnitDetails(formatted))
 
146
        }
 
147
 
 
148
        resources, err := unitResources(unit, service, sr)
 
149
        if err != nil {
 
150
                return errors.Trace(err)
 
151
        }
 
152
        res := make([]FormattedUnitResource, len(resources))
 
153
 
 
154
        for i, r := range resources {
 
155
                res[i] = FormattedUnitResource(FormatSvcResource(r))
 
156
        }
 
157
 
 
158
        return c.out.Write(ctx, res)
 
159
 
 
160
}
 
161
 
 
162
func unitResources(unit, service string, v resource.ServiceResources) ([]resource.Resource, error) {
 
163
        for _, res := range v.UnitResources {
 
164
                if res.Tag.Id() == unit {
 
165
                        return res.Resources, nil
 
166
                }
 
167
        }
 
168
        // TODO(natefinch): we need to differentiate between a unit with no
 
169
        // resources and a unit that doesn't exist. This requires a serverside
 
170
        // change.
 
171
        return nil, nil
 
172
}