/
get.go
177 lines (160 loc) · 4.8 KB
/
get.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package application
import (
"context"
"github.com/juju/charm/v13"
"github.com/juju/schema"
"gopkg.in/juju/environschema.v1"
apiservererrors "github.com/juju/juju/apiserver/errors"
corebase "github.com/juju/juju/core/base"
corecharm "github.com/juju/juju/core/charm"
"github.com/juju/juju/core/config"
"github.com/juju/juju/core/constraints"
"github.com/juju/juju/core/model"
"github.com/juju/juju/rpc/params"
)
// Get returns the charm configuration for an application.
func (api *APIBase) Get(ctx context.Context, args params.ApplicationGet) (params.ApplicationGetResults, error) {
return api.getConfig(ctx, args, describe)
}
// Get returns the charm configuration for an application.
func (api *APIBase) getConfig(
ctx context.Context,
args params.ApplicationGet,
describe func(settings charm.Settings, config *charm.Config) map[string]interface{},
) (params.ApplicationGetResults, error) {
if err := api.checkCanRead(); err != nil {
return params.ApplicationGetResults{}, err
}
app, err := api.backend.Application(args.ApplicationName)
if err != nil {
return params.ApplicationGetResults{}, err
}
// We need a guard on the API server-side for direct API callers such as
// python-libjuju. Always default to the master branch.
if args.BranchName == "" {
args.BranchName = model.GenerationMaster
}
settings, err := app.CharmConfig(args.BranchName)
if err != nil {
return params.ApplicationGetResults{}, err
}
ch, _, err := app.Charm()
if err != nil {
return params.ApplicationGetResults{}, err
}
configInfo := describe(settings, ch.Config())
appConfig, err := app.ApplicationConfig()
if err != nil {
return params.ApplicationGetResults{}, err
}
providerSchema, providerDefaults, err := ConfigSchema()
if err != nil {
return params.ApplicationGetResults{}, err
}
appConfigInfo := describeAppConfig(appConfig, providerSchema, providerDefaults)
var cons constraints.Value
if app.IsPrincipal() {
cons, err = app.Constraints()
if err != nil {
return params.ApplicationGetResults{}, err
}
}
endpoints, err := app.EndpointBindings()
if err != nil {
return params.ApplicationGetResults{}, err
}
allSpaceInfosLookup, err := api.networkService.GetAllSpaces(ctx)
if err != nil {
return params.ApplicationGetResults{}, apiservererrors.ServerError(err)
}
bindingMap, err := endpoints.MapWithSpaceNames(allSpaceInfosLookup)
if err != nil {
return params.ApplicationGetResults{}, err
}
var appChannel string
// If the applications charm origin is from charm-hub, then build the real
// channel and send that back.
origin := app.CharmOrigin()
if corecharm.CharmHub.Matches(origin.Source) && origin.Channel != nil {
ch := charm.MakePermissiveChannel(origin.Channel.Track, origin.Channel.Risk, origin.Channel.Branch)
appChannel = ch.String()
}
base, err := corebase.ParseBase(origin.Platform.OS, origin.Platform.Channel)
if err != nil {
return params.ApplicationGetResults{}, err
}
return params.ApplicationGetResults{
Application: args.ApplicationName,
Charm: ch.Meta().Name,
CharmConfig: configInfo,
ApplicationConfig: appConfigInfo,
Constraints: cons,
Base: params.Base{
Name: base.OS,
Channel: base.Channel.String(),
},
Channel: appChannel,
EndpointBindings: bindingMap,
}, nil
}
func describeAppConfig(
appConfig config.ConfigAttributes,
schemaFields environschema.Fields,
defaults schema.Defaults,
) map[string]interface{} {
results := make(map[string]interface{})
for name, field := range schemaFields {
defaultValue := defaults[name]
info := map[string]interface{}{
"description": field.Description,
"type": field.Type,
"source": "unset",
}
if defaultValue == schema.Omit {
results[name] = info
continue
}
set := false
if value := appConfig[name]; value != nil && defaultValue != value {
set = true
info["value"] = value
info["source"] = "user"
}
if defaultValue != nil {
info["default"] = defaultValue
if !set {
info["value"] = defaultValue
info["source"] = "default"
}
}
results[name] = info
}
return results
}
func describe(settings charm.Settings, config *charm.Config) map[string]interface{} {
results := make(map[string]interface{})
for name, option := range config.Options {
info := map[string]interface{}{
"description": option.Description,
"type": option.Type,
"source": "unset",
}
set := false
if value := settings[name]; value != nil && option.Default != value {
set = true
info["value"] = value
info["source"] = "user"
}
if option.Default != nil {
info["default"] = option.Default
if !set {
info["value"] = option.Default
info["source"] = "default"
}
}
results[name] = info
}
return results
}