1
// Copyright 2015 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
11
jc "github.com/juju/testing/checkers"
12
gc "gopkg.in/check.v1"
13
"gopkg.in/juju/environschema.v1"
15
"github.com/juju/juju/environs"
16
"github.com/juju/juju/environs/config"
17
"github.com/juju/juju/provider/lxd"
18
"github.com/juju/juju/testing"
19
"github.com/juju/juju/tools/lxdclient"
22
type configSuite struct {
28
var _ = gc.Suite(&configSuite{})
30
func (s *configSuite) SetUpTest(c *gc.C) {
31
s.BaseSuite.SetUpTest(c)
33
cfg, err := testing.ModelConfig(c).Apply(lxd.ConfigAttrs)
34
c.Assert(err, jc.ErrorIsNil)
38
func (s *configSuite) TestDefaults(c *gc.C) {
39
cfg := lxd.NewBaseConfig(c)
40
ecfg := lxd.NewConfig(cfg)
42
values, extras := ecfg.Values(c)
43
c.Assert(extras, gc.HasLen, 0)
45
c.Check(values, jc.DeepEquals, lxd.ConfigValues{
53
func (s *configSuite) TestClientConfigLocal(c *gc.C) {
54
cfg := lxd.NewBaseConfig(c)
55
ecfg := lxd.NewConfig(cfg)
56
values, _ := ecfg.Values(c)
57
c.Assert(values.RemoteURL, gc.Equals, "")
59
clientCfg, err := ecfg.ClientConfig()
60
c.Assert(err, jc.ErrorIsNil)
62
c.Check(clientCfg, jc.DeepEquals, lxdclient.Config{
63
Remote: lxdclient.Remote{
66
Protocol: lxdclient.LXDProtocol,
73
func (s *configSuite) TestClientConfigNonLocal(c *gc.C) {
74
cfg := lxd.NewBaseConfig(c)
75
ecfg := lxd.NewConfig(cfg)
76
ecfg = ecfg.Apply(c, map[string]interface{}{
77
"remote-url": "10.0.0.1",
78
"client-cert": "<a valid x.509 cert>",
79
"client-key": "<a valid x.509 key>",
80
"server-cert": "<a valid x.509 server cert>",
83
clientCfg, err := ecfg.ClientConfig()
84
c.Assert(err, jc.ErrorIsNil)
86
c.Check(clientCfg, jc.DeepEquals, lxdclient.Config{
87
Remote: lxdclient.Remote{
90
Protocol: lxdclient.LXDProtocol,
91
Cert: &lxdclient.Cert{
92
Name: fmt.Sprintf("juju cert for env %q", s.config.Name()),
93
CertPEM: []byte("<a valid x.509 cert>"),
94
KeyPEM: []byte("<a valid x.509 key>"),
96
ServerPEMCert: "<a valid x.509 server cert>",
101
func (s *configSuite) TestUpdateForClientConfigLocal(c *gc.C) {
102
cfg := lxd.NewBaseConfig(c)
103
ecfg := lxd.NewConfig(cfg)
105
clientCfg, err := ecfg.ClientConfig()
106
c.Assert(err, jc.ErrorIsNil)
107
updated, err := ecfg.UpdateForClientConfig(clientCfg)
108
c.Assert(err, jc.ErrorIsNil)
110
values, extras := updated.Values(c)
111
c.Assert(extras, gc.HasLen, 0)
113
c.Check(values, jc.DeepEquals, lxd.ConfigValues{
121
func (s *configSuite) TestUpdateForClientConfigNonLocal(c *gc.C) {
122
cfg := lxd.NewBaseConfig(c)
123
ecfg := lxd.NewConfig(cfg)
124
ecfg = ecfg.Apply(c, map[string]interface{}{
125
"remote-url": "10.0.0.1",
126
"client-cert": "<a valid x.509 cert>",
127
"client-key": "<a valid x.509 key>",
128
"server-cert": "<a valid x.509 server cert>",
131
before, extras := ecfg.Values(c)
132
c.Assert(extras, gc.HasLen, 0)
134
clientCfg, err := ecfg.ClientConfig()
135
c.Assert(err, jc.ErrorIsNil)
136
updated, err := ecfg.UpdateForClientConfig(clientCfg)
137
c.Assert(err, jc.ErrorIsNil)
139
after, extras := updated.Values(c)
140
c.Assert(extras, gc.HasLen, 0)
142
c.Check(before, jc.DeepEquals, lxd.ConfigValues{
143
RemoteURL: "10.0.0.1",
144
ClientCert: "<a valid x.509 cert>",
145
ClientKey: "<a valid x.509 key>",
146
ServerCert: "<a valid x.509 server cert>",
148
c.Check(after, jc.DeepEquals, lxd.ConfigValues{
149
RemoteURL: "10.0.0.1",
150
ClientCert: "<a valid x.509 cert>",
151
ClientKey: "<a valid x.509 key>",
152
ServerCert: "<a valid x.509 server cert>",
156
func (s *configSuite) TestUpdateForClientConfigGeneratedCert(c *gc.C) {
157
cfg := lxd.NewBaseConfig(c)
158
ecfg := lxd.NewConfig(cfg)
159
ecfg = ecfg.Apply(c, map[string]interface{}{
160
"remote-url": "10.0.0.1",
166
before, extras := ecfg.Values(c)
167
c.Assert(extras, gc.HasLen, 0)
169
clientCfg, err := ecfg.ClientConfig()
170
c.Assert(err, jc.ErrorIsNil)
171
updated, err := ecfg.UpdateForClientConfig(clientCfg)
172
c.Assert(err, jc.ErrorIsNil)
174
after, extras := updated.Values(c)
175
c.Assert(extras, gc.HasLen, 0)
177
c.Check(before, jc.DeepEquals, lxd.ConfigValues{
178
RemoteURL: "10.0.0.1",
184
after.ClientCert = ""
186
after.ServerCert = ""
187
c.Check(after, jc.DeepEquals, lxd.ConfigValues{
188
RemoteURL: "10.0.0.1",
195
// TODO(ericsnow) Each test only deals with a single field, so having
196
// multiple values in insert and remove (in configTestSpec) is a little
197
// misleading and unecessary.
199
// configTestSpec defines a subtest to run in a table driven test.
200
type configTestSpec struct {
201
// info describes the subtest.
203
// insert holds attrs that should be merged into the config.
205
// remove has the names of attrs that should be removed.
207
// expect defines the expected attributes in a success case.
209
// err is the error message to expect in a failure case.
213
func (ts configTestSpec) checkSuccess(c *gc.C, value interface{}, err error) {
214
if !c.Check(err, jc.ErrorIsNil) {
218
var cfg *config.Config
219
switch typed := value.(type) {
222
case environs.Environ:
226
attrs := cfg.AllAttrs()
227
for field, value := range ts.expect {
228
c.Check(attrs[field], gc.Equals, value)
232
func (ts configTestSpec) checkFailure(c *gc.C, err error, msg string) {
233
c.Check(err, gc.ErrorMatches, msg+": "+ts.err)
236
func (ts configTestSpec) checkAttrs(c *gc.C, attrs map[string]interface{}, cfg *config.Config) {
237
for field, expected := range cfg.UnknownAttrs() {
238
value := attrs[field]
239
c.Check(value, gc.Equals, expected)
243
func (ts configTestSpec) attrs() testing.Attrs {
244
attrs := lxd.ConfigAttrs
245
return attrs.Merge(ts.insert).Delete(ts.remove...)
248
func (ts configTestSpec) newConfig(c *gc.C) *config.Config {
250
cfg, err := testing.ModelConfig(c).Apply(attrs)
251
c.Assert(err, jc.ErrorIsNil)
255
func (ts configTestSpec) fixCfg(c *gc.C, cfg *config.Config) *config.Config {
256
fixes := make(map[string]interface{})
258
// Set changed values.
259
fixes = updateAttrs(fixes, ts.insert)
261
newCfg, err := cfg.Apply(fixes)
262
c.Assert(err, jc.ErrorIsNil)
266
func updateAttrs(attrs, updates testing.Attrs) testing.Attrs {
267
updated := make(testing.Attrs, len(attrs))
268
for k, v := range attrs {
271
for k, v := range updates {
277
var newConfigTests = []configTestSpec{{
278
info: "remote-url is optional",
279
remove: []string{"remote-url"},
280
expect: testing.Attrs{"remote-url": ""},
282
info: "remote-url can be empty",
283
insert: testing.Attrs{"remote-url": ""},
284
expect: testing.Attrs{"remote-url": ""},
286
info: "client-cert is optional",
287
remove: []string{"client-cert"},
288
expect: testing.Attrs{"client-cert": ""},
290
info: "client-cert can be empty",
291
insert: testing.Attrs{"client-cert": ""},
292
expect: testing.Attrs{"client-cert": ""},
294
info: "client-key is optional",
295
remove: []string{"client-key"},
296
expect: testing.Attrs{"client-key": ""},
298
info: "client-key can be empty",
299
insert: testing.Attrs{"client-key": ""},
300
expect: testing.Attrs{"client-key": ""},
302
info: "server-cert is optional",
303
remove: []string{"server-cert"},
304
expect: testing.Attrs{"server-cert": ""},
306
info: "unknown field is not touched",
307
insert: testing.Attrs{"unknown-field": 12345},
308
expect: testing.Attrs{"unknown-field": 12345},
311
func (s *configSuite) TestNewModelConfig(c *gc.C) {
312
// TODO(ericsnow) Move to a functional suite.
313
if !s.IsRunningLocally(c) {
314
c.Skip("LXD not running locally")
317
// TODO(redir): Remove after wily or in yakkety.
320
for i, test := range newConfigTests {
321
c.Logf("test %d: %s", i, test.info)
323
testConfig := test.newConfig(c)
324
environ, err := environs.New(environs.OpenParams{lxdCloudSpec(), testConfig})
328
test.checkFailure(c, err, "invalid config")
330
test.checkSuccess(c, environ, err)
335
// TODO(wwitzel3) refactor to provider_test file
336
func (s *configSuite) TestValidateNewConfig(c *gc.C) {
337
for i, test := range newConfigTests {
338
c.Logf("test %d: %s", i, test.info)
340
testConfig := test.newConfig(c)
341
validatedConfig, err := lxd.Provider.Validate(testConfig, nil)
345
test.checkFailure(c, err, "invalid config")
347
c.Check(validatedConfig, gc.NotNil)
348
test.checkSuccess(c, validatedConfig, err)
353
// TODO(wwitzel3) refactor to the provider_test file
354
func (s *configSuite) TestValidateOldConfig(c *gc.C) {
355
for i, test := range newConfigTests {
356
c.Logf("test %d: %s", i, test.info)
358
oldcfg := test.newConfig(c)
360
oldcfg, err = lxd.Provider.Validate(oldcfg, nil)
361
c.Assert(err, jc.ErrorIsNil)
362
newcfg := test.fixCfg(c, s.config)
363
expected := updateAttrs(lxd.ConfigAttrs, test.insert)
365
// Validate the new config (relative to the old one) using the
367
validatedConfig, err := lxd.Provider.Validate(newcfg, oldcfg)
371
test.checkFailure(c, err, "invalid base config")
373
if !c.Check(err, jc.ErrorIsNil) {
376
// We verify that Validate filled in the defaults
378
c.Check(validatedConfig, gc.NotNil)
379
test.checkAttrs(c, expected, validatedConfig)
384
// TODO(ericsnow) Add tests for client-cert and client-key.
386
var changeConfigTests = []configTestSpec{{
387
info: "no change, no error",
388
expect: lxd.ConfigAttrs,
390
info: "can insert unknown field",
391
insert: testing.Attrs{"unknown": "ignoti"},
392
expect: testing.Attrs{"unknown": "ignoti"},
395
// TODO(wwitzel3) refactor this to the provider_test file.
396
func (s *configSuite) TestValidateChange(c *gc.C) {
397
for i, test := range changeConfigTests {
398
c.Logf("test %d: %s", i, test.info)
400
testConfig := test.newConfig(c)
401
validatedConfig, err := lxd.Provider.Validate(testConfig, s.config)
405
test.checkFailure(c, err, "invalid config change")
407
test.checkSuccess(c, validatedConfig, err)
412
func (s *configSuite) TestSetConfig(c *gc.C) {
413
// TODO(ericsnow) Move to a functional suite.
414
if !s.IsRunningLocally(c) {
415
c.Skip("LXD not running locally")
418
// TODO(redir): Remove after wily or in yakkety.
421
for i, test := range changeConfigTests {
422
c.Logf("test %d: %s", i, test.info)
424
environ, err := environs.New(environs.OpenParams{lxdCloudSpec(), s.config})
425
c.Assert(err, jc.ErrorIsNil)
427
testConfig := test.newConfig(c)
428
err = environ.SetConfig(testConfig)
432
test.checkFailure(c, err, "invalid config change")
433
expected, err := lxd.Provider.Validate(s.config, nil)
434
c.Assert(err, jc.ErrorIsNil)
435
test.checkAttrs(c, environ.Config().AllAttrs(), expected)
437
test.checkSuccess(c, environ.Config(), err)
442
func (*configSuite) TestSchema(c *gc.C) {
443
fields := lxd.Provider.(interface {
444
Schema() environschema.Fields
446
// Check that all the fields defined in environs/config
447
// are in the returned schema.
448
globalFields, err := config.Schema(nil)
449
c.Assert(err, gc.IsNil)
450
for name, field := range globalFields {
451
c.Check(fields[name], jc.DeepEquals, field)
455
func lxdCloudSpec() environs.CloudSpec {
456
return environs.CloudSpec{