github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/state/migration_export_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state_test 5 6 import ( 7 "math/rand" 8 "time" 9 10 "github.com/juju/names" 11 jc "github.com/juju/testing/checkers" 12 "github.com/juju/version" 13 gc "gopkg.in/check.v1" 14 15 "github.com/juju/juju/constraints" 16 "github.com/juju/juju/core/description" 17 "github.com/juju/juju/state" 18 "github.com/juju/juju/status" 19 "github.com/juju/juju/testing/factory" 20 ) 21 22 // Constraints stores megabytes by default for memory and root disk. 23 const ( 24 gig uint64 = 1024 25 26 addedHistoryCount = 5 27 // 6 for the one initial + 5 added. 28 expectedHistoryCount = addedHistoryCount + 1 29 ) 30 31 var testAnnotations = map[string]string{ 32 "string": "value", 33 "another": "one", 34 } 35 36 type MigrationSuite struct { 37 ConnSuite 38 } 39 40 type statusSetter interface { 41 SetStatus(status.Status, string, map[string]interface{}) error 42 } 43 44 func (s *MigrationSuite) setLatestTools(c *gc.C, latestTools version.Number) { 45 dbModel, err := s.State.Model() 46 c.Assert(err, jc.ErrorIsNil) 47 err = dbModel.UpdateLatestToolsVersion(latestTools) 48 c.Assert(err, jc.ErrorIsNil) 49 } 50 51 func (s *MigrationSuite) setRandSequenceValue(c *gc.C, name string) int { 52 var value int 53 var err error 54 count := rand.Intn(5) + 1 55 for i := 0; i < count; i++ { 56 value, err = state.Sequence(s.State, name) 57 c.Assert(err, jc.ErrorIsNil) 58 } 59 // The value stored in the doc is one higher than what it returns. 60 return value + 1 61 } 62 63 func (s *MigrationSuite) primeStatusHistory(c *gc.C, entity statusSetter, statusVal status.Status, count int) { 64 for i := 0; i < count; i++ { 65 c.Logf("setting status for %v", entity) 66 err := entity.SetStatus(statusVal, "", map[string]interface{}{"index": count - i}) 67 c.Assert(err, jc.ErrorIsNil) 68 } 69 } 70 71 func (s *MigrationSuite) makeServiceWithLeader(c *gc.C, serviceName string, count int, leader int) { 72 c.Assert(leader < count, jc.IsTrue) 73 units := make([]*state.Unit, count) 74 service := s.Factory.MakeService(c, &factory.ServiceParams{ 75 Name: serviceName, 76 Charm: s.Factory.MakeCharm(c, &factory.CharmParams{ 77 Name: serviceName, 78 }), 79 }) 80 for i := 0; i < count; i++ { 81 units[i] = s.Factory.MakeUnit(c, &factory.UnitParams{ 82 Service: service, 83 }) 84 } 85 err := s.State.LeadershipClaimer().ClaimLeadership( 86 service.Name(), 87 units[leader].Name(), 88 time.Minute) 89 c.Assert(err, jc.ErrorIsNil) 90 } 91 92 type MigrationExportSuite struct { 93 MigrationSuite 94 } 95 96 var _ = gc.Suite(&MigrationExportSuite{}) 97 98 func (s *MigrationExportSuite) checkStatusHistory(c *gc.C, history []description.Status, statusVal status.Status) { 99 for i, st := range history { 100 c.Check(st.Value(), gc.Equals, string(statusVal)) 101 c.Check(st.Message(), gc.Equals, "") 102 c.Check(st.Data(), jc.DeepEquals, map[string]interface{}{"index": i + 1}) 103 } 104 } 105 106 func (s *MigrationExportSuite) TestModelInfo(c *gc.C) { 107 stModel, err := s.State.Model() 108 c.Assert(err, jc.ErrorIsNil) 109 err = s.State.SetAnnotations(stModel, testAnnotations) 110 c.Assert(err, jc.ErrorIsNil) 111 latestTools := version.MustParse("2.0.1") 112 s.setLatestTools(c, latestTools) 113 err = s.State.SetModelConstraints(constraints.MustParse("arch=amd64 mem=8G")) 114 c.Assert(err, jc.ErrorIsNil) 115 machineSeq := s.setRandSequenceValue(c, "machine") 116 fooSeq := s.setRandSequenceValue(c, "service-foo") 117 s.State.SwitchBlockOn(state.ChangeBlock, "locked down") 118 119 model, err := s.State.Export() 120 c.Assert(err, jc.ErrorIsNil) 121 122 dbModel, err := s.State.Model() 123 c.Assert(err, jc.ErrorIsNil) 124 c.Assert(model.Tag(), gc.Equals, dbModel.ModelTag()) 125 c.Assert(model.Owner(), gc.Equals, dbModel.Owner()) 126 config, err := dbModel.Config() 127 c.Assert(err, jc.ErrorIsNil) 128 c.Assert(model.Config(), jc.DeepEquals, config.AllAttrs()) 129 c.Assert(model.LatestToolsVersion(), gc.Equals, latestTools) 130 c.Assert(model.Annotations(), jc.DeepEquals, testAnnotations) 131 constraints := model.Constraints() 132 c.Assert(constraints, gc.NotNil) 133 c.Assert(constraints.Architecture(), gc.Equals, "amd64") 134 c.Assert(constraints.Memory(), gc.Equals, 8*gig) 135 c.Assert(model.Sequences(), jc.DeepEquals, map[string]int{ 136 "machine": machineSeq, 137 "service-foo": fooSeq, 138 // blocks is added by the switch block on call above. 139 "block": 1, 140 }) 141 c.Assert(model.Blocks(), jc.DeepEquals, map[string]string{ 142 "all-changes": "locked down", 143 }) 144 } 145 146 func (s *MigrationExportSuite) TestModelUsers(c *gc.C) { 147 // Make sure we have some last connection times for the admin user, 148 // and create a few other users. 149 lastConnection := state.NowToTheSecond() 150 owner, err := s.State.ModelUser(s.Owner) 151 c.Assert(err, jc.ErrorIsNil) 152 err = state.UpdateModelUserLastConnection(owner, lastConnection) 153 c.Assert(err, jc.ErrorIsNil) 154 155 bobTag := names.NewUserTag("bob@external") 156 bob, err := s.State.AddModelUser(state.ModelUserSpec{ 157 User: bobTag, 158 CreatedBy: s.Owner, 159 Access: state.ModelReadAccess, 160 }) 161 c.Assert(err, jc.ErrorIsNil) 162 err = state.UpdateModelUserLastConnection(bob, lastConnection) 163 c.Assert(err, jc.ErrorIsNil) 164 165 model, err := s.State.Export() 166 c.Assert(err, jc.ErrorIsNil) 167 168 users := model.Users() 169 c.Assert(users, gc.HasLen, 2) 170 171 exportedBob := users[0] 172 // admin is "test-admin", and results are sorted 173 exportedAdmin := users[1] 174 175 c.Assert(exportedAdmin.Name(), gc.Equals, s.Owner) 176 c.Assert(exportedAdmin.DisplayName(), gc.Equals, owner.DisplayName()) 177 c.Assert(exportedAdmin.CreatedBy(), gc.Equals, s.Owner) 178 c.Assert(exportedAdmin.DateCreated(), gc.Equals, owner.DateCreated()) 179 c.Assert(exportedAdmin.LastConnection(), gc.Equals, lastConnection) 180 c.Assert(exportedAdmin.ReadOnly(), jc.IsFalse) 181 182 c.Assert(exportedBob.Name(), gc.Equals, bobTag) 183 c.Assert(exportedBob.DisplayName(), gc.Equals, "") 184 c.Assert(exportedBob.CreatedBy(), gc.Equals, s.Owner) 185 c.Assert(exportedBob.DateCreated(), gc.Equals, bob.DateCreated()) 186 c.Assert(exportedBob.LastConnection(), gc.Equals, lastConnection) 187 c.Assert(exportedBob.ReadOnly(), jc.IsTrue) 188 } 189 190 func (s *MigrationExportSuite) TestMachines(c *gc.C) { 191 // Add a machine with an LXC container. 192 machine1 := s.Factory.MakeMachine(c, &factory.MachineParams{ 193 Constraints: constraints.MustParse("arch=amd64 mem=8G"), 194 }) 195 nested := s.Factory.MakeMachineNested(c, machine1.Id(), nil) 196 err := s.State.SetAnnotations(machine1, testAnnotations) 197 c.Assert(err, jc.ErrorIsNil) 198 s.primeStatusHistory(c, machine1, status.StatusStarted, addedHistoryCount) 199 200 model, err := s.State.Export() 201 c.Assert(err, jc.ErrorIsNil) 202 203 machines := model.Machines() 204 c.Assert(machines, gc.HasLen, 1) 205 206 exported := machines[0] 207 c.Assert(exported.Tag(), gc.Equals, machine1.MachineTag()) 208 c.Assert(exported.Series(), gc.Equals, machine1.Series()) 209 c.Assert(exported.Annotations(), jc.DeepEquals, testAnnotations) 210 constraints := exported.Constraints() 211 c.Assert(constraints, gc.NotNil) 212 c.Assert(constraints.Architecture(), gc.Equals, "amd64") 213 c.Assert(constraints.Memory(), gc.Equals, 8*gig) 214 215 tools, err := machine1.AgentTools() 216 c.Assert(err, jc.ErrorIsNil) 217 exTools := exported.Tools() 218 c.Assert(exTools, gc.NotNil) 219 c.Assert(exTools.Version(), jc.DeepEquals, tools.Version) 220 221 history := exported.StatusHistory() 222 c.Assert(history, gc.HasLen, expectedHistoryCount) 223 s.checkStatusHistory(c, history[:addedHistoryCount], status.StatusStarted) 224 225 containers := exported.Containers() 226 c.Assert(containers, gc.HasLen, 1) 227 container := containers[0] 228 c.Assert(container.Tag(), gc.Equals, nested.MachineTag()) 229 } 230 231 func (s *MigrationExportSuite) TestServices(c *gc.C) { 232 service := s.Factory.MakeService(c, &factory.ServiceParams{ 233 Settings: map[string]interface{}{ 234 "foo": "bar", 235 }, 236 Constraints: constraints.MustParse("arch=amd64 mem=8G"), 237 }) 238 err := service.UpdateLeaderSettings(&goodToken{}, map[string]string{ 239 "leader": "true", 240 }) 241 c.Assert(err, jc.ErrorIsNil) 242 err = service.SetMetricCredentials([]byte("sekrit")) 243 c.Assert(err, jc.ErrorIsNil) 244 err = s.State.SetAnnotations(service, testAnnotations) 245 c.Assert(err, jc.ErrorIsNil) 246 s.primeStatusHistory(c, service, status.StatusActive, addedHistoryCount) 247 248 model, err := s.State.Export() 249 c.Assert(err, jc.ErrorIsNil) 250 251 services := model.Services() 252 c.Assert(services, gc.HasLen, 1) 253 254 exported := services[0] 255 c.Assert(exported.Name(), gc.Equals, service.Name()) 256 c.Assert(exported.Tag(), gc.Equals, service.ServiceTag()) 257 c.Assert(exported.Series(), gc.Equals, service.Series()) 258 c.Assert(exported.Annotations(), jc.DeepEquals, testAnnotations) 259 260 c.Assert(exported.Settings(), jc.DeepEquals, map[string]interface{}{ 261 "foo": "bar", 262 }) 263 c.Assert(exported.SettingsRefCount(), gc.Equals, 1) 264 c.Assert(exported.LeadershipSettings(), jc.DeepEquals, map[string]interface{}{ 265 "leader": "true", 266 }) 267 c.Assert(exported.MetricsCredentials(), jc.DeepEquals, []byte("sekrit")) 268 269 constraints := exported.Constraints() 270 c.Assert(constraints, gc.NotNil) 271 c.Assert(constraints.Architecture(), gc.Equals, "amd64") 272 c.Assert(constraints.Memory(), gc.Equals, 8*gig) 273 274 history := exported.StatusHistory() 275 c.Assert(history, gc.HasLen, expectedHistoryCount) 276 s.checkStatusHistory(c, history[:addedHistoryCount], status.StatusActive) 277 } 278 279 func (s *MigrationExportSuite) TestMultipleServices(c *gc.C) { 280 s.Factory.MakeService(c, &factory.ServiceParams{Name: "first"}) 281 s.Factory.MakeService(c, &factory.ServiceParams{Name: "second"}) 282 s.Factory.MakeService(c, &factory.ServiceParams{Name: "third"}) 283 284 model, err := s.State.Export() 285 c.Assert(err, jc.ErrorIsNil) 286 287 services := model.Services() 288 c.Assert(services, gc.HasLen, 3) 289 } 290 291 func (s *MigrationExportSuite) TestUnits(c *gc.C) { 292 unit := s.Factory.MakeUnit(c, &factory.UnitParams{ 293 Constraints: constraints.MustParse("arch=amd64 mem=8G"), 294 }) 295 err := unit.SetMeterStatus("GREEN", "some info") 296 c.Assert(err, jc.ErrorIsNil) 297 err = s.State.SetAnnotations(unit, testAnnotations) 298 c.Assert(err, jc.ErrorIsNil) 299 s.primeStatusHistory(c, unit, status.StatusActive, addedHistoryCount) 300 s.primeStatusHistory(c, unit.Agent(), status.StatusIdle, addedHistoryCount) 301 302 model, err := s.State.Export() 303 c.Assert(err, jc.ErrorIsNil) 304 305 services := model.Services() 306 c.Assert(services, gc.HasLen, 1) 307 308 service := services[0] 309 units := service.Units() 310 c.Assert(units, gc.HasLen, 1) 311 312 exported := units[0] 313 314 c.Assert(exported.Name(), gc.Equals, unit.Name()) 315 c.Assert(exported.Tag(), gc.Equals, unit.UnitTag()) 316 c.Assert(exported.Validate(), jc.ErrorIsNil) 317 c.Assert(exported.MeterStatusCode(), gc.Equals, "GREEN") 318 c.Assert(exported.MeterStatusInfo(), gc.Equals, "some info") 319 c.Assert(exported.Annotations(), jc.DeepEquals, testAnnotations) 320 constraints := exported.Constraints() 321 c.Assert(constraints, gc.NotNil) 322 c.Assert(constraints.Architecture(), gc.Equals, "amd64") 323 c.Assert(constraints.Memory(), gc.Equals, 8*gig) 324 325 workloadHistory := exported.WorkloadStatusHistory() 326 c.Assert(workloadHistory, gc.HasLen, expectedHistoryCount) 327 s.checkStatusHistory(c, workloadHistory[:addedHistoryCount], status.StatusActive) 328 329 agentHistory := exported.AgentStatusHistory() 330 c.Assert(agentHistory, gc.HasLen, expectedHistoryCount) 331 s.checkStatusHistory(c, agentHistory[:addedHistoryCount], status.StatusIdle) 332 } 333 334 func (s *MigrationExportSuite) TestServiceLeadership(c *gc.C) { 335 s.makeServiceWithLeader(c, "mysql", 2, 1) 336 s.makeServiceWithLeader(c, "wordpress", 4, 2) 337 338 model, err := s.State.Export() 339 c.Assert(err, jc.ErrorIsNil) 340 341 leaders := make(map[string]string) 342 for _, service := range model.Services() { 343 leaders[service.Name()] = service.Leader() 344 } 345 c.Assert(leaders, jc.DeepEquals, map[string]string{ 346 "mysql": "mysql/1", 347 "wordpress": "wordpress/2", 348 }) 349 } 350 351 func (s *MigrationExportSuite) TestUnitsOpenPorts(c *gc.C) { 352 unit := s.Factory.MakeUnit(c, nil) 353 err := unit.OpenPorts("tcp", 1234, 2345) 354 c.Assert(err, jc.ErrorIsNil) 355 356 model, err := s.State.Export() 357 c.Assert(err, jc.ErrorIsNil) 358 359 machines := model.Machines() 360 c.Assert(machines, gc.HasLen, 1) 361 362 ports := machines[0].OpenedPorts() 363 c.Assert(ports, gc.HasLen, 1) 364 365 port := ports[0] 366 c.Assert(port.SubnetID(), gc.Equals, "") 367 opened := port.OpenPorts() 368 c.Assert(opened, gc.HasLen, 1) 369 c.Assert(opened[0].UnitName(), gc.Equals, unit.Name()) 370 } 371 372 func (s *MigrationExportSuite) TestRelations(c *gc.C) { 373 // Need to remove owner from service. 374 ignored := s.Owner 375 wordpress := state.AddTestingService(c, s.State, "wordpress", state.AddTestingCharm(c, s.State, "wordpress"), ignored) 376 mysql := state.AddTestingService(c, s.State, "mysql", state.AddTestingCharm(c, s.State, "mysql"), ignored) 377 // InferEndpoints will always return provider, requirer 378 eps, err := s.State.InferEndpoints("mysql", "wordpress") 379 c.Assert(err, jc.ErrorIsNil) 380 rel, err := s.State.AddRelation(eps...) 381 msEp, wpEp := eps[0], eps[1] 382 c.Assert(err, jc.ErrorIsNil) 383 wordpress_0 := s.Factory.MakeUnit(c, &factory.UnitParams{Service: wordpress}) 384 mysql_0 := s.Factory.MakeUnit(c, &factory.UnitParams{Service: mysql}) 385 386 ru, err := rel.Unit(wordpress_0) 387 c.Assert(err, jc.ErrorIsNil) 388 wordpressSettings := map[string]interface{}{ 389 "name": "wordpress/0", 390 } 391 err = ru.EnterScope(wordpressSettings) 392 c.Assert(err, jc.ErrorIsNil) 393 394 ru, err = rel.Unit(mysql_0) 395 c.Assert(err, jc.ErrorIsNil) 396 mysqlSettings := map[string]interface{}{ 397 "name": "mysql/0", 398 } 399 err = ru.EnterScope(mysqlSettings) 400 c.Assert(err, jc.ErrorIsNil) 401 402 model, err := s.State.Export() 403 c.Assert(err, jc.ErrorIsNil) 404 405 rels := model.Relations() 406 c.Assert(rels, gc.HasLen, 1) 407 408 exRel := rels[0] 409 c.Assert(exRel.Id(), gc.Equals, rel.Id()) 410 c.Assert(exRel.Key(), gc.Equals, rel.String()) 411 412 exEps := exRel.Endpoints() 413 c.Assert(exEps, gc.HasLen, 2) 414 415 checkEndpoint := func( 416 exEndpoint description.Endpoint, 417 unitName string, 418 ep state.Endpoint, 419 settings map[string]interface{}, 420 ) { 421 c.Logf("%#v", exEndpoint) 422 c.Check(exEndpoint.ServiceName(), gc.Equals, ep.ServiceName) 423 c.Check(exEndpoint.Name(), gc.Equals, ep.Name) 424 c.Check(exEndpoint.UnitCount(), gc.Equals, 1) 425 c.Check(exEndpoint.Settings(unitName), jc.DeepEquals, settings) 426 c.Check(exEndpoint.Role(), gc.Equals, string(ep.Role)) 427 c.Check(exEndpoint.Interface(), gc.Equals, ep.Interface) 428 c.Check(exEndpoint.Optional(), gc.Equals, ep.Optional) 429 c.Check(exEndpoint.Limit(), gc.Equals, ep.Limit) 430 c.Check(exEndpoint.Scope(), gc.Equals, string(ep.Scope)) 431 } 432 checkEndpoint(exEps[0], mysql_0.Name(), msEp, mysqlSettings) 433 checkEndpoint(exEps[1], wordpress_0.Name(), wpEp, wordpressSettings) 434 } 435 436 type goodToken struct{} 437 438 // Check implements leadership.Token 439 func (*goodToken) Check(interface{}) error { 440 return nil 441 }