1
// Copyright 2016 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
9
"github.com/juju/errors"
10
"github.com/juju/names"
11
jc "github.com/juju/testing/checkers"
12
"github.com/juju/utils"
13
"github.com/juju/version"
14
gc "gopkg.in/check.v1"
16
"github.com/juju/juju/constraints"
17
"github.com/juju/juju/core/description"
18
"github.com/juju/juju/network"
19
"github.com/juju/juju/state"
20
"github.com/juju/juju/status"
21
"github.com/juju/juju/testing/factory"
24
type MigrationImportSuite struct {
28
var _ = gc.Suite(&MigrationImportSuite{})
30
func (s *MigrationImportSuite) checkStatusHistory(c *gc.C, exported, imported status.StatusHistoryGetter, size int) {
31
exportedHistory, err := exported.StatusHistory(size)
32
c.Assert(err, jc.ErrorIsNil)
33
importedHistory, err := imported.StatusHistory(size)
34
c.Assert(err, jc.ErrorIsNil)
35
for i := 0; i < size; i++ {
36
c.Check(importedHistory[i].Status, gc.Equals, exportedHistory[i].Status)
37
c.Check(importedHistory[i].Message, gc.Equals, exportedHistory[i].Message)
38
c.Check(importedHistory[i].Data, jc.DeepEquals, exportedHistory[i].Data)
39
c.Check(importedHistory[i].Since, jc.DeepEquals, exportedHistory[i].Since)
43
func (s *MigrationImportSuite) TestExisting(c *gc.C) {
44
out, err := s.State.Export()
45
c.Assert(err, jc.ErrorIsNil)
47
_, _, err = s.State.Import(out)
48
c.Assert(err, jc.Satisfies, errors.IsAlreadyExists)
51
func (s *MigrationImportSuite) importModel(c *gc.C) (*state.Model, *state.State) {
52
out, err := s.State.Export()
53
c.Assert(err, jc.ErrorIsNil)
55
uuid := utils.MustNewUUID().String()
56
in := newModel(out, uuid, "new")
58
newModel, newSt, err := s.State.Import(in)
59
c.Assert(err, jc.ErrorIsNil)
60
return newModel, newSt
63
func (s *MigrationImportSuite) assertAnnotations(c *gc.C, newSt *state.State, entity state.GlobalEntity) {
64
annotations, err := newSt.Annotations(entity)
65
c.Assert(err, jc.ErrorIsNil)
66
c.Assert(annotations, jc.DeepEquals, testAnnotations)
69
func (s *MigrationImportSuite) TestNewModel(c *gc.C) {
70
cons := constraints.MustParse("arch=amd64 mem=8G")
71
latestTools := version.MustParse("2.0.1")
72
s.setLatestTools(c, latestTools)
73
c.Assert(s.State.SetModelConstraints(cons), jc.ErrorIsNil)
74
machineSeq := s.setRandSequenceValue(c, "machine")
75
fooSeq := s.setRandSequenceValue(c, "service-foo")
76
s.State.SwitchBlockOn(state.ChangeBlock, "locked down")
78
original, err := s.State.Model()
79
c.Assert(err, jc.ErrorIsNil)
81
err = s.State.SetAnnotations(original, testAnnotations)
82
c.Assert(err, jc.ErrorIsNil)
84
out, err := s.State.Export()
85
c.Assert(err, jc.ErrorIsNil)
87
uuid := utils.MustNewUUID().String()
88
in := newModel(out, uuid, "new")
90
newModel, newSt, err := s.State.Import(in)
91
c.Assert(err, jc.ErrorIsNil)
94
c.Assert(newModel.Owner(), gc.Equals, original.Owner())
95
c.Assert(newModel.LatestToolsVersion(), gc.Equals, latestTools)
96
s.assertAnnotations(c, newSt, newModel)
98
originalConfig, err := original.Config()
99
c.Assert(err, jc.ErrorIsNil)
100
originalAttrs := originalConfig.AllAttrs()
102
newConfig, err := newModel.Config()
103
c.Assert(err, jc.ErrorIsNil)
104
newAttrs := newConfig.AllAttrs()
106
c.Assert(newAttrs["uuid"], gc.Equals, uuid)
107
c.Assert(newAttrs["name"], gc.Equals, "new")
109
// Now drop the uuid and name and the rest of the attributes should match.
110
delete(newAttrs, "uuid")
111
delete(newAttrs, "name")
112
delete(originalAttrs, "uuid")
113
delete(originalAttrs, "name")
114
c.Assert(newAttrs, jc.DeepEquals, originalAttrs)
116
newCons, err := newSt.ModelConstraints()
117
c.Assert(err, jc.ErrorIsNil)
118
// Can't test the constraints directly, so go through the string repr.
119
c.Assert(newCons.String(), gc.Equals, cons.String())
121
seq, err := state.Sequence(newSt, "machine")
122
c.Assert(err, jc.ErrorIsNil)
123
c.Assert(seq, gc.Equals, machineSeq)
124
seq, err = state.Sequence(newSt, "service-foo")
125
c.Assert(err, jc.ErrorIsNil)
126
c.Assert(seq, gc.Equals, fooSeq)
128
blocks, err := newSt.AllBlocks()
129
c.Assert(err, jc.ErrorIsNil)
130
c.Assert(blocks, gc.HasLen, 1)
131
c.Assert(blocks[0].Type(), gc.Equals, state.ChangeBlock)
132
c.Assert(blocks[0].Message(), gc.Equals, "locked down")
135
func (s *MigrationImportSuite) newModelUser(c *gc.C, name string, readOnly bool, lastConnection time.Time) *state.ModelUser {
136
access := state.ModelAdminAccess
138
access = state.ModelReadAccess
140
user, err := s.State.AddModelUser(state.ModelUserSpec{
141
User: names.NewUserTag(name),
145
c.Assert(err, jc.ErrorIsNil)
146
if !lastConnection.IsZero() {
147
err = state.UpdateModelUserLastConnection(user, lastConnection)
148
c.Assert(err, jc.ErrorIsNil)
153
func (s *MigrationImportSuite) AssertUserEqual(c *gc.C, newUser, oldUser *state.ModelUser) {
154
c.Assert(newUser.UserName(), gc.Equals, oldUser.UserName())
155
c.Assert(newUser.DisplayName(), gc.Equals, oldUser.DisplayName())
156
c.Assert(newUser.CreatedBy(), gc.Equals, oldUser.CreatedBy())
157
c.Assert(newUser.DateCreated(), gc.Equals, oldUser.DateCreated())
158
c.Assert(newUser.ReadOnly(), gc.Equals, oldUser.ReadOnly())
160
connTime, err := oldUser.LastConnection()
161
if state.IsNeverConnectedError(err) {
162
_, err := newUser.LastConnection()
163
// The new user should also return an error for last connection.
164
c.Assert(err, jc.Satisfies, state.IsNeverConnectedError)
166
c.Assert(err, jc.ErrorIsNil)
167
newTime, err := newUser.LastConnection()
168
c.Assert(err, jc.ErrorIsNil)
169
c.Assert(newTime, gc.Equals, connTime)
173
func (s *MigrationImportSuite) TestModelUsers(c *gc.C) {
174
// To be sure with this test, we create three env users, and remove
176
err := s.State.RemoveModelUser(s.Owner)
177
c.Assert(err, jc.ErrorIsNil)
179
lastConnection := state.NowToTheSecond()
181
bravo := s.newModelUser(c, "bravo@external", false, lastConnection)
182
charlie := s.newModelUser(c, "charlie@external", true, lastConnection)
183
delta := s.newModelUser(c, "delta@external", true, time.Time{})
185
newModel, newSt := s.importModel(c)
188
// Check the import values of the users.
189
for _, user := range []*state.ModelUser{bravo, charlie, delta} {
190
newUser, err := newSt.ModelUser(user.UserTag())
191
c.Assert(err, jc.ErrorIsNil)
192
s.AssertUserEqual(c, newUser, user)
195
// Also make sure that there aren't any more.
196
allUsers, err := newModel.Users()
197
c.Assert(err, jc.ErrorIsNil)
198
c.Assert(allUsers, gc.HasLen, 3)
201
func (s *MigrationImportSuite) AssertMachineEqual(c *gc.C, newMachine, oldMachine *state.Machine) {
202
c.Assert(newMachine.Id(), gc.Equals, oldMachine.Id())
203
c.Assert(newMachine.Principals(), jc.DeepEquals, oldMachine.Principals())
204
c.Assert(newMachine.Series(), gc.Equals, oldMachine.Series())
205
c.Assert(newMachine.ContainerType(), gc.Equals, oldMachine.ContainerType())
206
newHardware, err := newMachine.HardwareCharacteristics()
207
c.Assert(err, jc.ErrorIsNil)
208
oldHardware, err := oldMachine.HardwareCharacteristics()
209
c.Assert(err, jc.ErrorIsNil)
210
c.Assert(newHardware, jc.DeepEquals, oldHardware)
211
c.Assert(newMachine.Jobs(), jc.DeepEquals, oldMachine.Jobs())
212
c.Assert(newMachine.Life(), gc.Equals, oldMachine.Life())
213
newTools, err := newMachine.AgentTools()
214
c.Assert(err, jc.ErrorIsNil)
215
oldTools, err := oldMachine.AgentTools()
216
c.Assert(err, jc.ErrorIsNil)
217
c.Assert(newTools, jc.DeepEquals, oldTools)
220
func (s *MigrationImportSuite) TestMachines(c *gc.C) {
221
// Let's add a machine with an LXC container.
222
cons := constraints.MustParse("arch=amd64 mem=8G")
223
machine1 := s.Factory.MakeMachine(c, &factory.MachineParams{
226
err := s.State.SetAnnotations(machine1, testAnnotations)
227
c.Assert(err, jc.ErrorIsNil)
228
s.primeStatusHistory(c, machine1, status.StatusStarted, 5)
230
// machine1 should have some instance data.
231
hardware, err := machine1.HardwareCharacteristics()
232
c.Assert(err, jc.ErrorIsNil)
233
c.Assert(hardware, gc.NotNil)
235
_ = s.Factory.MakeMachineNested(c, machine1.Id(), nil)
237
allMachines, err := s.State.AllMachines()
238
c.Assert(err, jc.ErrorIsNil)
239
c.Assert(allMachines, gc.HasLen, 2)
241
_, newSt := s.importModel(c)
244
importedMachines, err := newSt.AllMachines()
245
c.Assert(err, jc.ErrorIsNil)
246
c.Assert(importedMachines, gc.HasLen, 2)
248
// AllMachines returns the machines in the same order, yay us.
249
for i, newMachine := range importedMachines {
250
s.AssertMachineEqual(c, newMachine, allMachines[i])
253
// And a few extra checks.
254
parent := importedMachines[0]
255
container := importedMachines[1]
256
containers, err := parent.Containers()
257
c.Assert(err, jc.ErrorIsNil)
258
c.Assert(containers, jc.DeepEquals, []string{container.Id()})
259
parentId, isContainer := container.ParentId()
260
c.Assert(parentId, gc.Equals, parent.Id())
261
c.Assert(isContainer, jc.IsTrue)
263
s.assertAnnotations(c, newSt, parent)
264
s.checkStatusHistory(c, machine1, parent, 5)
266
newCons, err := parent.Constraints()
267
c.Assert(err, jc.ErrorIsNil)
268
// Can't test the constraints directly, so go through the string repr.
269
c.Assert(newCons.String(), gc.Equals, cons.String())
272
func (s *MigrationImportSuite) TestServices(c *gc.C) {
273
// Add a service with both settings and leadership settings.
274
cons := constraints.MustParse("arch=amd64 mem=8G")
275
service := s.Factory.MakeService(c, &factory.ServiceParams{
276
Settings: map[string]interface{}{
281
err := service.UpdateLeaderSettings(&goodToken{}, map[string]string{
284
c.Assert(err, jc.ErrorIsNil)
285
err = service.SetMetricCredentials([]byte("sekrit"))
286
c.Assert(err, jc.ErrorIsNil)
287
// Expose the service.
288
c.Assert(service.SetExposed(), jc.ErrorIsNil)
289
err = s.State.SetAnnotations(service, testAnnotations)
290
c.Assert(err, jc.ErrorIsNil)
291
s.primeStatusHistory(c, service, status.StatusActive, 5)
293
allServices, err := s.State.AllServices()
294
c.Assert(err, jc.ErrorIsNil)
295
c.Assert(allServices, gc.HasLen, 1)
297
_, newSt := s.importModel(c)
300
importedServices, err := newSt.AllServices()
301
c.Assert(err, jc.ErrorIsNil)
302
c.Assert(importedServices, gc.HasLen, 1)
304
exported := allServices[0]
305
imported := importedServices[0]
307
c.Assert(imported.ServiceTag(), gc.Equals, exported.ServiceTag())
308
c.Assert(imported.Series(), gc.Equals, exported.Series())
309
c.Assert(imported.IsExposed(), gc.Equals, exported.IsExposed())
310
c.Assert(imported.MetricCredentials(), jc.DeepEquals, exported.MetricCredentials())
312
exportedConfig, err := exported.ConfigSettings()
313
c.Assert(err, jc.ErrorIsNil)
314
importedConfig, err := imported.ConfigSettings()
315
c.Assert(err, jc.ErrorIsNil)
316
c.Assert(importedConfig, jc.DeepEquals, exportedConfig)
318
exportedLeaderSettings, err := exported.LeaderSettings()
319
c.Assert(err, jc.ErrorIsNil)
320
importedLeaderSettings, err := imported.LeaderSettings()
321
c.Assert(err, jc.ErrorIsNil)
322
c.Assert(importedLeaderSettings, jc.DeepEquals, exportedLeaderSettings)
324
s.assertAnnotations(c, newSt, imported)
325
s.checkStatusHistory(c, service, imported, 5)
327
newCons, err := imported.Constraints()
328
c.Assert(err, jc.ErrorIsNil)
329
// Can't test the constraints directly, so go through the string repr.
330
c.Assert(newCons.String(), gc.Equals, cons.String())
333
func (s *MigrationImportSuite) TestServiceLeaders(c *gc.C) {
334
s.makeServiceWithLeader(c, "mysql", 2, 1)
335
s.makeServiceWithLeader(c, "wordpress", 4, 2)
337
_, newSt := s.importModel(c)
340
leaders := make(map[string]string)
341
for key, value := range state.LeadershipLeases(newSt) {
342
leaders[key] = value.Holder
344
c.Assert(leaders, jc.DeepEquals, map[string]string{
346
"wordpress": "wordpress/2",
350
func (s *MigrationImportSuite) TestUnits(c *gc.C) {
351
cons := constraints.MustParse("arch=amd64 mem=8G")
352
exported, pwd := s.Factory.MakeUnitReturningPassword(c, &factory.UnitParams{
355
err := exported.SetMeterStatus("GREEN", "some info")
356
c.Assert(err, jc.ErrorIsNil)
357
err = s.State.SetAnnotations(exported, testAnnotations)
358
c.Assert(err, jc.ErrorIsNil)
359
s.primeStatusHistory(c, exported, status.StatusActive, 5)
360
s.primeStatusHistory(c, exported.Agent(), status.StatusIdle, 5)
362
_, newSt := s.importModel(c)
365
importedServices, err := newSt.AllServices()
366
c.Assert(err, jc.ErrorIsNil)
367
c.Assert(importedServices, gc.HasLen, 1)
369
importedUnits, err := importedServices[0].AllUnits()
370
c.Assert(err, jc.ErrorIsNil)
371
c.Assert(importedUnits, gc.HasLen, 1)
372
imported := importedUnits[0]
374
c.Assert(imported.UnitTag(), gc.Equals, exported.UnitTag())
375
c.Assert(imported.PasswordValid(pwd), jc.IsTrue)
377
exportedMachineId, err := exported.AssignedMachineId()
378
c.Assert(err, jc.ErrorIsNil)
379
importedMachineId, err := imported.AssignedMachineId()
380
c.Assert(err, jc.ErrorIsNil)
381
c.Assert(importedMachineId, gc.Equals, exportedMachineId)
382
meterStatus, err := imported.GetMeterStatus()
383
c.Assert(err, jc.ErrorIsNil)
384
c.Assert(meterStatus, gc.Equals, state.MeterStatus{state.MeterGreen, "some info"})
385
s.assertAnnotations(c, newSt, imported)
386
s.checkStatusHistory(c, exported, imported, 5)
387
s.checkStatusHistory(c, exported.Agent(), imported.Agent(), 5)
389
newCons, err := imported.Constraints()
390
c.Assert(err, jc.ErrorIsNil)
391
// Can't test the constraints directly, so go through the string repr.
392
c.Assert(newCons.String(), gc.Equals, cons.String())
395
func (s *MigrationImportSuite) TestRelations(c *gc.C) {
396
// Need to remove owner from service.
398
wordpress := state.AddTestingService(c, s.State, "wordpress", state.AddTestingCharm(c, s.State, "wordpress"), ignored)
399
state.AddTestingService(c, s.State, "mysql", state.AddTestingCharm(c, s.State, "mysql"), ignored)
400
eps, err := s.State.InferEndpoints("mysql", "wordpress")
401
c.Assert(err, jc.ErrorIsNil)
402
rel, err := s.State.AddRelation(eps...)
403
c.Assert(err, jc.ErrorIsNil)
404
wordpress_0 := s.Factory.MakeUnit(c, &factory.UnitParams{Service: wordpress})
406
ru, err := rel.Unit(wordpress_0)
407
c.Assert(err, jc.ErrorIsNil)
408
relSettings := map[string]interface{}{
409
"name": "wordpress/0",
411
err = ru.EnterScope(relSettings)
412
c.Assert(err, jc.ErrorIsNil)
414
_, newSt := s.importModel(c)
417
newWordpress, err := newSt.Service("wordpress")
418
c.Assert(err, jc.ErrorIsNil)
419
c.Assert(state.RelationCount(newWordpress), gc.Equals, 1)
420
rels, err := newWordpress.Relations()
421
c.Assert(err, jc.ErrorIsNil)
422
c.Assert(rels, gc.HasLen, 1)
423
units, err := newWordpress.AllUnits()
424
c.Assert(err, jc.ErrorIsNil)
425
c.Assert(units, gc.HasLen, 1)
427
ru, err = rels[0].Unit(units[0])
428
c.Assert(err, jc.ErrorIsNil)
430
settings, err := ru.Settings()
431
c.Assert(err, jc.ErrorIsNil)
432
c.Assert(settings.Map(), gc.DeepEquals, relSettings)
435
func (s *MigrationImportSuite) TestUnitsOpenPorts(c *gc.C) {
436
unit := s.Factory.MakeUnit(c, nil)
437
err := unit.OpenPorts("tcp", 1234, 2345)
438
c.Assert(err, jc.ErrorIsNil)
440
_, newSt := s.importModel(c)
443
// Even though the opened ports document is stored with the
444
// machine, the only way to easily access it is through the units.
445
imported, err := newSt.Unit(unit.Name())
446
c.Assert(err, jc.ErrorIsNil)
448
ports, err := imported.OpenedPorts()
449
c.Assert(err, jc.ErrorIsNil)
450
c.Assert(ports, gc.HasLen, 1)
451
c.Assert(ports[0], gc.Equals, network.PortRange{
458
// newModel replaces the uuid and name of the config attributes so we
459
// can use all the other data to validate imports. An owner and name of the
460
// model are unique together in a controller.
461
func newModel(m description.Model, uuid, name string) description.Model {
462
return &mockModel{m, uuid, name}
465
type mockModel struct {
471
func (m *mockModel) Tag() names.ModelTag {
472
return names.NewModelTag(m.uuid)
475
func (m *mockModel) Config() map[string]interface{} {
476
c := m.Model.Config()