~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/component/all/resource.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 all
 
5
 
 
6
import (
 
7
        "io"
 
8
        "os"
 
9
        "reflect"
 
10
 
 
11
        jujucmd "github.com/juju/cmd"
 
12
        "github.com/juju/errors"
 
13
        "gopkg.in/juju/names.v2"
 
14
 
 
15
        "github.com/juju/juju/api/base"
 
16
        "github.com/juju/juju/apiserver/charmrevisionupdater"
 
17
        "github.com/juju/juju/apiserver/common"
 
18
        "github.com/juju/juju/apiserver/common/apihttp"
 
19
        "github.com/juju/juju/cmd/juju/charmcmd"
 
20
        "github.com/juju/juju/cmd/juju/commands"
 
21
        "github.com/juju/juju/cmd/modelcmd"
 
22
        "github.com/juju/juju/resource"
 
23
        "github.com/juju/juju/resource/api"
 
24
        "github.com/juju/juju/resource/api/client"
 
25
        internalapi "github.com/juju/juju/resource/api/private"
 
26
        internalclient "github.com/juju/juju/resource/api/private/client"
 
27
        internalserver "github.com/juju/juju/resource/api/private/server"
 
28
        "github.com/juju/juju/resource/api/server"
 
29
        "github.com/juju/juju/resource/cmd"
 
30
        "github.com/juju/juju/resource/context"
 
31
        contextcmd "github.com/juju/juju/resource/context/cmd"
 
32
        "github.com/juju/juju/resource/resourceadapters"
 
33
        corestate "github.com/juju/juju/state"
 
34
        unitercontext "github.com/juju/juju/worker/uniter/runner/context"
 
35
        "github.com/juju/juju/worker/uniter/runner/jujuc"
 
36
)
 
37
 
 
38
// resources exposes the registration methods needed
 
39
// for the top-level component machinery.
 
40
type resources struct{}
 
41
 
 
42
// RegisterForServer is the top-level registration method
 
43
// for the component in a jujud context.
 
44
func (r resources) registerForServer() error {
 
45
        r.registerState()
 
46
        r.registerAgentWorkers()
 
47
        r.registerPublicFacade()
 
48
        r.registerHookContext()
 
49
        return nil
 
50
}
 
51
 
 
52
// RegisterForClient is the top-level registration method
 
53
// for the component in a "juju" command context.
 
54
func (r resources) registerForClient() error {
 
55
        r.registerPublicCommands()
 
56
        return nil
 
57
}
 
58
 
 
59
// registerPublicFacade adds the resources public API facade
 
60
// to the API server.
 
61
func (r resources) registerPublicFacade() {
 
62
        if !markRegistered(resource.ComponentName, "public-facade") {
 
63
                return
 
64
        }
 
65
 
 
66
        // NOTE: facade is also defined in api/facadeversions.go.
 
67
        common.RegisterStandardFacade(
 
68
                resource.FacadeName,
 
69
                server.Version,
 
70
                resourceadapters.NewPublicFacade,
 
71
        )
 
72
 
 
73
        common.RegisterAPIModelEndpoint(api.HTTPEndpointPattern, apihttp.HandlerSpec{
 
74
                Constraints: apihttp.HandlerConstraints{
 
75
                        AuthKind:            names.UserTagKind,
 
76
                        StrictValidation:    true,
 
77
                        ControllerModelOnly: false,
 
78
                },
 
79
                NewHandler: resourceadapters.NewUploadHandler,
 
80
        })
 
81
}
 
82
 
 
83
// resourcesApiClient adds a Close() method to the resources public API client.
 
84
type resourcesAPIClient struct {
 
85
        *client.Client
 
86
        closeConnFunc func() error
 
87
}
 
88
 
 
89
// Close implements io.Closer.
 
90
func (client resourcesAPIClient) Close() error {
 
91
        return client.closeConnFunc()
 
92
}
 
93
 
 
94
// registerAgentWorkers adds the resources workers to the agents.
 
95
func (r resources) registerAgentWorkers() {
 
96
        if !markRegistered(resource.ComponentName, "agent-workers") {
 
97
                return
 
98
        }
 
99
 
 
100
        charmrevisionupdater.RegisterLatestCharmHandler("resources", resourceadapters.NewLatestCharmHandler)
 
101
}
 
102
 
 
103
// registerState registers the state functionality for resources.
 
104
func (resources) registerState() {
 
105
        if !markRegistered(resource.ComponentName, "state") {
 
106
                return
 
107
        }
 
108
 
 
109
        corestate.SetResourcesComponent(resourceadapters.NewResourceState)
 
110
        corestate.SetResourcesPersistence(resourceadapters.NewResourcePersistence)
 
111
        corestate.RegisterCleanupHandler(corestate.CleanupKindResourceBlob, resourceadapters.CleanUpBlob)
 
112
}
 
113
 
 
114
// registerPublicCommands adds the resources-related commands
 
115
// to the "juju" supercommand.
 
116
func (r resources) registerPublicCommands() {
 
117
        if !markRegistered(resource.ComponentName, "public-commands") {
 
118
                return
 
119
        }
 
120
 
 
121
        charmcmd.RegisterSubCommand(func(spec charmcmd.CharmstoreSpec) jujucmd.Command {
 
122
                base := charmcmd.NewCommandBase(spec)
 
123
                resBase := &resourceadapters.CharmCmdBase{base}
 
124
                return cmd.NewListCharmResourcesCommand(resBase)
 
125
        })
 
126
 
 
127
        commands.RegisterEnvCommand(func() modelcmd.ModelCommand {
 
128
                return cmd.NewUploadCommand(cmd.UploadDeps{
 
129
                        NewClient: func(c *cmd.UploadCommand) (cmd.UploadClient, error) {
 
130
                                return resourceadapters.NewAPIClient(c.NewAPIRoot)
 
131
                        },
 
132
                        OpenResource: func(s string) (cmd.ReadSeekCloser, error) {
 
133
                                return os.Open(s)
 
134
                        },
 
135
                })
 
136
 
 
137
        })
 
138
 
 
139
        commands.RegisterEnvCommand(func() modelcmd.ModelCommand {
 
140
                return cmd.NewShowServiceCommand(cmd.ShowServiceDeps{
 
141
                        NewClient: func(c *cmd.ShowServiceCommand) (cmd.ShowServiceClient, error) {
 
142
                                return resourceadapters.NewAPIClient(c.NewAPIRoot)
 
143
                        },
 
144
                })
 
145
        })
 
146
}
 
147
 
 
148
// TODO(katco): This seems to be common across components. Pop up a
 
149
// level and genericize?
 
150
func (r resources) registerHookContext() {
 
151
        if markRegistered(resource.ComponentName, "hook-context") == false {
 
152
                return
 
153
        }
 
154
 
 
155
        unitercontext.RegisterComponentFunc(
 
156
                resource.ComponentName,
 
157
                func(config unitercontext.ComponentConfig) (jujuc.ContextComponent, error) {
 
158
                        unitID := names.NewUnitTag(config.UnitName).String()
 
159
                        hctxClient, err := r.newUnitFacadeClient(unitID, config.APICaller)
 
160
                        if err != nil {
 
161
                                return nil, errors.Trace(err)
 
162
                        }
 
163
                        // TODO(ericsnow) Pass the unit's tag through to the component?
 
164
                        return context.NewContextAPI(hctxClient, config.DataDir), nil
 
165
                },
 
166
        )
 
167
 
 
168
        r.registerHookContextCommands()
 
169
        r.registerHookContextFacade()
 
170
}
 
171
 
 
172
func (c resources) registerHookContextCommands() {
 
173
        if markRegistered(resource.ComponentName, "hook-context-commands") == false {
 
174
                return
 
175
        }
 
176
 
 
177
        jujuc.RegisterCommand(
 
178
                contextcmd.GetCmdName,
 
179
                func(ctx jujuc.Context) (jujucmd.Command, error) {
 
180
                        compCtx, err := ctx.Component(resource.ComponentName)
 
181
                        if err != nil {
 
182
                                return nil, errors.Trace(err)
 
183
                        }
 
184
                        typedCtx, ok := compCtx.(*context.Context)
 
185
                        if !ok {
 
186
                                return nil, errors.Trace(err)
 
187
                        }
 
188
                        cmd, err := contextcmd.NewGetCmd(typedCtx)
 
189
                        if err != nil {
 
190
                                return nil, errors.Trace(err)
 
191
                        }
 
192
                        return cmd, nil
 
193
                },
 
194
        )
 
195
}
 
196
 
 
197
func (r resources) registerHookContextFacade() {
 
198
        common.RegisterHookContextFacade(
 
199
                context.HookContextFacade,
 
200
                internalserver.FacadeVersion,
 
201
                r.newHookContextFacade,
 
202
                reflect.TypeOf(&internalserver.UnitFacade{}),
 
203
        )
 
204
 
 
205
        common.RegisterAPIModelEndpoint(internalapi.HTTPEndpointPattern, apihttp.HandlerSpec{
 
206
                Constraints: apihttp.HandlerConstraints{
 
207
                        AuthKind:            names.UnitTagKind,
 
208
                        StrictValidation:    true,
 
209
                        ControllerModelOnly: false,
 
210
                },
 
211
                NewHandler: resourceadapters.NewDownloadHandler,
 
212
        })
 
213
}
 
214
 
 
215
// resourcesUnitDatastore is a shim to elide serviceName from
 
216
// ListResources.
 
217
type resourcesUnitDataStore struct {
 
218
        resources corestate.Resources
 
219
        unit      *corestate.Unit
 
220
}
 
221
 
 
222
// ListResources implements resource/api/private/server.UnitDataStore.
 
223
func (ds *resourcesUnitDataStore) ListResources() (resource.ServiceResources, error) {
 
224
        return ds.resources.ListResources(ds.unit.ApplicationName())
 
225
}
 
226
 
 
227
// GetResource implements resource/api/private/server.UnitDataStore.
 
228
func (ds *resourcesUnitDataStore) GetResource(name string) (resource.Resource, error) {
 
229
        return ds.resources.GetResource(ds.unit.ApplicationName(), name)
 
230
}
 
231
 
 
232
// OpenResource implements resource/api/private/server.UnitDataStore.
 
233
func (ds *resourcesUnitDataStore) OpenResource(name string) (resource.Resource, io.ReadCloser, error) {
 
234
        return ds.resources.OpenResourceForUniter(ds.unit, name)
 
235
}
 
236
 
 
237
func (r resources) newHookContextFacade(st *corestate.State, unit *corestate.Unit) (interface{}, error) {
 
238
        res, err := st.Resources()
 
239
        if err != nil {
 
240
                return nil, errors.Trace(err)
 
241
        }
 
242
        return internalserver.NewUnitFacade(&resourcesUnitDataStore{res, unit}), nil
 
243
}
 
244
 
 
245
func (r resources) newUnitFacadeClient(unitName string, caller base.APICaller) (context.APIClient, error) {
 
246
 
 
247
        facadeCaller := base.NewFacadeCallerForVersion(caller, context.HookContextFacade, internalserver.FacadeVersion)
 
248
        httpClient, err := caller.HTTPClient()
 
249
        if err != nil {
 
250
                return nil, errors.Trace(err)
 
251
        }
 
252
        unitHTTPClient := internalclient.NewUnitHTTPClient(httpClient, unitName)
 
253
 
 
254
        return internalclient.NewUnitFacadeClient(facadeCaller, unitHTTPClient), nil
 
255
}