github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/core/description/model_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package description 5 6 import ( 7 "fmt" 8 "time" 9 10 "github.com/juju/errors" 11 jc "github.com/juju/testing/checkers" 12 "github.com/juju/version" 13 gc "gopkg.in/check.v1" 14 "gopkg.in/juju/names.v2" 15 "gopkg.in/yaml.v2" 16 17 "github.com/juju/juju/testing" 18 ) 19 20 type ModelSerializationSuite struct { 21 testing.BaseSuite 22 } 23 24 var _ = gc.Suite(&ModelSerializationSuite{}) 25 26 func (*ModelSerializationSuite) TestNil(c *gc.C) { 27 _, err := importModel(nil) 28 c.Check(err, gc.ErrorMatches, "version: expected int, got nothing") 29 } 30 31 func (*ModelSerializationSuite) TestMissingVersion(c *gc.C) { 32 _, err := importModel(map[string]interface{}{}) 33 c.Check(err, gc.ErrorMatches, "version: expected int, got nothing") 34 } 35 36 func (*ModelSerializationSuite) TestNonIntVersion(c *gc.C) { 37 _, err := importModel(map[string]interface{}{ 38 "version": "hello", 39 }) 40 c.Check(err.Error(), gc.Equals, `version: expected int, got string("hello")`) 41 } 42 43 func (*ModelSerializationSuite) TestUnknownVersion(c *gc.C) { 44 _, err := importModel(map[string]interface{}{ 45 "version": 42, 46 }) 47 c.Check(err.Error(), gc.Equals, `version 42 not valid`) 48 } 49 50 func (*ModelSerializationSuite) TestUpdateConfig(c *gc.C) { 51 model := NewModel(ModelArgs{ 52 Config: map[string]interface{}{ 53 "name": "awesome", 54 "uuid": "some-uuid", 55 }, 56 CloudRegion: "some-region", 57 }) 58 model.UpdateConfig(map[string]interface{}{ 59 "name": "something else", 60 "key": "value", 61 }) 62 c.Assert(model.Config(), jc.DeepEquals, map[string]interface{}{ 63 "name": "something else", 64 "uuid": "some-uuid", 65 "key": "value", 66 }) 67 } 68 69 func (s *ModelSerializationSuite) exportImport(c *gc.C, initial Model) Model { 70 bytes, err := Serialize(initial) 71 c.Assert(err, jc.ErrorIsNil) 72 model, err := Deserialize(bytes) 73 c.Assert(err, jc.ErrorIsNil) 74 return model 75 } 76 77 func (s *ModelSerializationSuite) TestParsingYAML(c *gc.C) { 78 args := ModelArgs{ 79 Owner: names.NewUserTag("magic"), 80 Config: map[string]interface{}{ 81 "name": "awesome", 82 "uuid": "some-uuid", 83 }, 84 LatestToolsVersion: version.MustParse("2.0.1"), 85 Blocks: map[string]string{ 86 "all-changes": "locked down", 87 }, 88 } 89 initial := NewModel(args) 90 adminUser := names.NewUserTag("admin@local") 91 initial.AddUser(UserArgs{ 92 Name: adminUser, 93 CreatedBy: adminUser, 94 DateCreated: time.Date(2015, 10, 9, 12, 34, 56, 0, time.UTC), 95 }) 96 addMinimalMachine(initial, "0") 97 addMinimalApplication(initial) 98 model := s.exportImport(c, initial) 99 100 c.Assert(model.Owner(), gc.Equals, args.Owner) 101 c.Assert(model.Tag().Id(), gc.Equals, "some-uuid") 102 c.Assert(model.Config(), jc.DeepEquals, args.Config) 103 c.Assert(model.LatestToolsVersion(), gc.Equals, args.LatestToolsVersion) 104 c.Assert(model.Blocks(), jc.DeepEquals, args.Blocks) 105 users := model.Users() 106 c.Assert(users, gc.HasLen, 1) 107 c.Assert(users[0].Name(), gc.Equals, adminUser) 108 machines := model.Machines() 109 c.Assert(machines, gc.HasLen, 1) 110 c.Assert(machines[0].Id(), gc.Equals, "0") 111 applications := model.Applications() 112 c.Assert(applications, gc.HasLen, 1) 113 c.Assert(applications[0].Name(), gc.Equals, "ubuntu") 114 } 115 116 func (s *ModelSerializationSuite) TestParsingOptionals(c *gc.C) { 117 args := ModelArgs{ 118 Owner: names.NewUserTag("magic"), 119 Config: map[string]interface{}{ 120 "name": "awesome", 121 "uuid": "some-uuid", 122 }, 123 } 124 initial := NewModel(args) 125 model := s.exportImport(c, initial) 126 c.Assert(model.LatestToolsVersion(), gc.Equals, version.Zero) 127 } 128 129 func (s *ModelSerializationSuite) TestAnnotations(c *gc.C) { 130 initial := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 131 annotations := map[string]string{ 132 "string": "value", 133 "another": "one", 134 } 135 initial.SetAnnotations(annotations) 136 137 bytes, err := yaml.Marshal(initial) 138 c.Assert(err, jc.ErrorIsNil) 139 140 model, err := Deserialize(bytes) 141 c.Assert(err, jc.ErrorIsNil) 142 c.Assert(model.Annotations(), jc.DeepEquals, annotations) 143 } 144 145 func (s *ModelSerializationSuite) TestSequences(c *gc.C) { 146 initial := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 147 initial.SetSequence("machine", 4) 148 initial.SetSequence("application-foo", 3) 149 initial.SetSequence("application-bar", 1) 150 bytes, err := yaml.Marshal(initial) 151 c.Assert(err, jc.ErrorIsNil) 152 153 model, err := Deserialize(bytes) 154 c.Assert(err, jc.ErrorIsNil) 155 156 c.Assert(model.Sequences(), jc.DeepEquals, map[string]int{ 157 "machine": 4, 158 "application-foo": 3, 159 "application-bar": 1, 160 }) 161 } 162 163 func (s *ModelSerializationSuite) TestConstraints(c *gc.C) { 164 initial := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 165 args := ConstraintsArgs{ 166 Architecture: "amd64", 167 Memory: 8 * gig, 168 } 169 initial.SetConstraints(args) 170 171 bytes, err := yaml.Marshal(initial) 172 c.Assert(err, jc.ErrorIsNil) 173 174 model, err := Deserialize(bytes) 175 c.Assert(err, jc.ErrorIsNil) 176 c.Assert(model.Constraints(), jc.DeepEquals, newConstraints(args)) 177 } 178 179 func (*ModelSerializationSuite) TestModelValidation(c *gc.C) { 180 model := NewModel(ModelArgs{}) 181 err := model.Validate() 182 c.Assert(err, gc.ErrorMatches, "missing model owner not valid") 183 c.Assert(err, jc.Satisfies, errors.IsNotValid) 184 } 185 186 func (*ModelSerializationSuite) TestModelValidationChecksMachines(c *gc.C) { 187 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner"), CloudRegion: "some-region"}) 188 model.AddMachine(MachineArgs{}) 189 err := model.Validate() 190 c.Assert(err, gc.ErrorMatches, "machine missing id not valid") 191 c.Assert(err, jc.Satisfies, errors.IsNotValid) 192 } 193 194 func (s *ModelSerializationSuite) addMachineToModel(model Model, id string) Machine { 195 machine := model.AddMachine(MachineArgs{Id: names.NewMachineTag(id)}) 196 machine.SetInstance(CloudInstanceArgs{InstanceId: "magic"}) 197 machine.SetTools(minimalAgentToolsArgs()) 198 machine.SetStatus(minimalStatusArgs()) 199 return machine 200 } 201 202 func (s *ModelSerializationSuite) TestModelValidationChecksMachinesGood(c *gc.C) { 203 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner"), CloudRegion: "some-region"}) 204 s.addMachineToModel(model, "0") 205 err := model.Validate() 206 c.Assert(err, jc.ErrorIsNil) 207 } 208 209 func (s *ModelSerializationSuite) TestModelValidationChecksOpenPortsUnits(c *gc.C) { 210 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner"), CloudRegion: "some-region"}) 211 machine := s.addMachineToModel(model, "0") 212 machine.AddOpenedPorts(OpenedPortsArgs{ 213 OpenedPorts: []PortRangeArgs{ 214 { 215 UnitName: "missing/0", 216 FromPort: 8080, 217 ToPort: 8080, 218 Protocol: "tcp", 219 }, 220 }, 221 }) 222 err := model.Validate() 223 c.Assert(err.Error(), gc.Equals, "unknown unit names in open ports: [missing/0]") 224 } 225 226 func (*ModelSerializationSuite) TestModelValidationChecksApplications(c *gc.C) { 227 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner"), CloudRegion: "some-region"}) 228 model.AddApplication(ApplicationArgs{}) 229 err := model.Validate() 230 c.Assert(err, gc.ErrorMatches, "application missing name not valid") 231 c.Assert(err, jc.Satisfies, errors.IsNotValid) 232 } 233 234 func (s *ModelSerializationSuite) addApplicationToModel(model Model, name string, numUnits int) Application { 235 application := model.AddApplication(ApplicationArgs{ 236 Tag: names.NewApplicationTag(name), 237 Settings: map[string]interface{}{}, 238 LeadershipSettings: map[string]interface{}{}, 239 }) 240 application.SetStatus(minimalStatusArgs()) 241 for i := 0; i < numUnits; i++ { 242 // The index i is used as both the machine id and the unit id. 243 // A happy coincidence. 244 machine := s.addMachineToModel(model, fmt.Sprint(i)) 245 unit := application.AddUnit(UnitArgs{ 246 Tag: names.NewUnitTag(fmt.Sprintf("%s/%d", name, i)), 247 Machine: machine.Tag(), 248 }) 249 unit.SetTools(minimalAgentToolsArgs()) 250 unit.SetAgentStatus(minimalStatusArgs()) 251 unit.SetWorkloadStatus(minimalStatusArgs()) 252 } 253 254 return application 255 } 256 257 func (s *ModelSerializationSuite) wordpressModel() (Model, Endpoint, Endpoint) { 258 model := NewModel(ModelArgs{ 259 Owner: names.NewUserTag("owner"), 260 Config: map[string]interface{}{ 261 "uuid": "some-uuid", 262 }, 263 CloudRegion: "some-region", 264 }) 265 s.addApplicationToModel(model, "wordpress", 2) 266 s.addApplicationToModel(model, "mysql", 1) 267 268 // Add a relation between wordpress and mysql. 269 rel := model.AddRelation(RelationArgs{ 270 Id: 42, 271 Key: "special key", 272 }) 273 wordpressEndpoint := rel.AddEndpoint(EndpointArgs{ 274 ApplicationName: "wordpress", 275 Name: "db", 276 // Ignoring other aspects of endpoints. 277 }) 278 mysqlEndpoint := rel.AddEndpoint(EndpointArgs{ 279 ApplicationName: "mysql", 280 Name: "mysql", 281 // Ignoring other aspects of endpoints. 282 }) 283 return model, wordpressEndpoint, mysqlEndpoint 284 } 285 286 func (s *ModelSerializationSuite) wordpressModelWithSettings() Model { 287 model, wordpressEndpoint, mysqlEndpoint := s.wordpressModel() 288 289 wordpressEndpoint.SetUnitSettings("wordpress/0", map[string]interface{}{ 290 "key": "value", 291 }) 292 wordpressEndpoint.SetUnitSettings("wordpress/1", map[string]interface{}{ 293 "key": "value", 294 }) 295 mysqlEndpoint.SetUnitSettings("mysql/0", map[string]interface{}{ 296 "key": "value", 297 }) 298 return model 299 } 300 301 func (s *ModelSerializationSuite) TestModelValidationChecksRelationsMissingSettings(c *gc.C) { 302 model, _, _ := s.wordpressModel() 303 err := model.Validate() 304 c.Assert(err, gc.ErrorMatches, "missing relation settings for units \\[wordpress/0 wordpress/1\\] in relation 42") 305 } 306 307 func (s *ModelSerializationSuite) TestModelValidationChecksRelationsMissingSettings2(c *gc.C) { 308 model, wordpressEndpoint, _ := s.wordpressModel() 309 310 wordpressEndpoint.SetUnitSettings("wordpress/0", map[string]interface{}{ 311 "key": "value", 312 }) 313 wordpressEndpoint.SetUnitSettings("wordpress/1", map[string]interface{}{ 314 "key": "value", 315 }) 316 err := model.Validate() 317 c.Assert(err, gc.ErrorMatches, "missing relation settings for units \\[mysql/0\\] in relation 42") 318 } 319 320 func (s *ModelSerializationSuite) TestModelValidationChecksRelations(c *gc.C) { 321 model := s.wordpressModelWithSettings() 322 err := model.Validate() 323 c.Assert(err, jc.ErrorIsNil) 324 } 325 326 func (s *ModelSerializationSuite) TestModelSerializationWithRelations(c *gc.C) { 327 initial := s.wordpressModelWithSettings() 328 bytes, err := yaml.Marshal(initial) 329 c.Assert(err, jc.ErrorIsNil) 330 model, err := Deserialize(bytes) 331 c.Assert(err, jc.ErrorIsNil) 332 c.Assert(model, jc.DeepEquals, initial) 333 } 334 335 func (s *ModelSerializationSuite) TestModelValidationChecksSubnets(c *gc.C) { 336 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 337 model.AddSubnet(SubnetArgs{CIDR: "10.0.0.0/24", SpaceName: "foo"}) 338 model.AddSubnet(SubnetArgs{CIDR: "10.0.1.0/24"}) 339 err := model.Validate() 340 c.Assert(err, gc.ErrorMatches, `subnet "10.0.0.0/24" references non-existent space "foo"`) 341 model.AddSpace(SpaceArgs{Name: "foo"}) 342 err = model.Validate() 343 c.Assert(err, jc.ErrorIsNil) 344 } 345 346 func (s *ModelSerializationSuite) TestModelValidationChecksAddressMachineID(c *gc.C) { 347 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 348 model.AddIPAddress(IPAddressArgs{Value: "192.168.1.0", MachineID: "42"}) 349 err := model.Validate() 350 c.Assert(err, gc.ErrorMatches, `ip address "192.168.1.0" references non-existent machine "42"`) 351 } 352 353 func (s *ModelSerializationSuite) TestModelValidationChecksAddressDeviceName(c *gc.C) { 354 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 355 args := IPAddressArgs{Value: "192.168.1.0", MachineID: "42", DeviceName: "foo"} 356 model.AddIPAddress(args) 357 s.addMachineToModel(model, "42") 358 err := model.Validate() 359 c.Assert(err, gc.ErrorMatches, `ip address "192.168.1.0" references non-existent device "foo"`) 360 } 361 362 func (s *ModelSerializationSuite) TestModelValidationChecksAddressValueEmpty(c *gc.C) { 363 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 364 args := IPAddressArgs{MachineID: "42", DeviceName: "foo"} 365 model.AddIPAddress(args) 366 s.addMachineToModel(model, "42") 367 model.AddLinkLayerDevice(LinkLayerDeviceArgs{Name: "foo", MachineID: "42"}) 368 err := model.Validate() 369 c.Assert(err, gc.ErrorMatches, `ip address has invalid value ""`) 370 } 371 372 func (s *ModelSerializationSuite) TestModelValidationChecksAddressValueInvalid(c *gc.C) { 373 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 374 args := IPAddressArgs{MachineID: "42", DeviceName: "foo", Value: "foobar"} 375 model.AddIPAddress(args) 376 s.addMachineToModel(model, "42") 377 model.AddLinkLayerDevice(LinkLayerDeviceArgs{Name: "foo", MachineID: "42"}) 378 err := model.Validate() 379 c.Assert(err, gc.ErrorMatches, `ip address has invalid value "foobar"`) 380 } 381 382 func (s *ModelSerializationSuite) TestModelValidationChecksAddressSubnetEmpty(c *gc.C) { 383 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 384 args := IPAddressArgs{MachineID: "42", DeviceName: "foo", Value: "192.168.1.1"} 385 model.AddIPAddress(args) 386 s.addMachineToModel(model, "42") 387 model.AddLinkLayerDevice(LinkLayerDeviceArgs{Name: "foo", MachineID: "42"}) 388 err := model.Validate() 389 c.Assert(err, gc.ErrorMatches, `ip address "192.168.1.1" has empty subnet CIDR`) 390 } 391 392 func (s *ModelSerializationSuite) TestModelValidationChecksAddressSubnetInvalid(c *gc.C) { 393 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 394 args := IPAddressArgs{ 395 MachineID: "42", 396 DeviceName: "foo", 397 Value: "192.168.1.1", 398 SubnetCIDR: "foo", 399 } 400 model.AddIPAddress(args) 401 s.addMachineToModel(model, "42") 402 model.AddLinkLayerDevice(LinkLayerDeviceArgs{Name: "foo", MachineID: "42"}) 403 err := model.Validate() 404 c.Assert(err, gc.ErrorMatches, `ip address "192.168.1.1" has invalid subnet CIDR "foo"`) 405 } 406 407 func (s *ModelSerializationSuite) TestModelValidationChecksAddressSucceeds(c *gc.C) { 408 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 409 args := IPAddressArgs{ 410 MachineID: "42", 411 DeviceName: "foo", 412 Value: "192.168.1.1", 413 SubnetCIDR: "192.168.1.0/24", 414 } 415 model.AddIPAddress(args) 416 s.addMachineToModel(model, "42") 417 model.AddLinkLayerDevice(LinkLayerDeviceArgs{Name: "foo", MachineID: "42"}) 418 err := model.Validate() 419 c.Assert(err, jc.ErrorIsNil) 420 } 421 422 func (s *ModelSerializationSuite) TestModelValidationChecksAddressGatewayAddressInvalid(c *gc.C) { 423 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 424 args := IPAddressArgs{ 425 MachineID: "42", 426 DeviceName: "foo", 427 Value: "192.168.1.1", 428 SubnetCIDR: "192.168.1.0/24", 429 GatewayAddress: "foo", 430 } 431 model.AddIPAddress(args) 432 s.addMachineToModel(model, "42") 433 model.AddLinkLayerDevice(LinkLayerDeviceArgs{Name: "foo", MachineID: "42"}) 434 err := model.Validate() 435 c.Assert(err, gc.ErrorMatches, `ip address "192.168.1.1" has invalid gateway address "foo"`) 436 } 437 438 func (s *ModelSerializationSuite) TestModelValidationChecksAddressGatewayAddressValid(c *gc.C) { 439 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 440 args := IPAddressArgs{ 441 MachineID: "42", 442 DeviceName: "foo", 443 Value: "192.168.1.2", 444 SubnetCIDR: "192.168.1.0/24", 445 GatewayAddress: "192.168.1.1", 446 } 447 model.AddIPAddress(args) 448 s.addMachineToModel(model, "42") 449 model.AddLinkLayerDevice(LinkLayerDeviceArgs{Name: "foo", MachineID: "42"}) 450 err := model.Validate() 451 c.Assert(err, jc.ErrorIsNil) 452 } 453 454 func (s *ModelSerializationSuite) TestModelValidationChecksLinkLayerDeviceMachineId(c *gc.C) { 455 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 456 model.AddLinkLayerDevice(LinkLayerDeviceArgs{Name: "foo", MachineID: "42"}) 457 err := model.Validate() 458 c.Assert(err, gc.ErrorMatches, `device "foo" references non-existent machine "42"`) 459 s.addMachineToModel(model, "42") 460 err = model.Validate() 461 c.Assert(err, jc.ErrorIsNil) 462 } 463 464 func (s *ModelSerializationSuite) TestModelValidationChecksLinkLayerName(c *gc.C) { 465 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 466 model.AddLinkLayerDevice(LinkLayerDeviceArgs{MachineID: "42"}) 467 s.addMachineToModel(model, "42") 468 err := model.Validate() 469 c.Assert(err, gc.ErrorMatches, "device has empty name.*") 470 } 471 472 func (s *ModelSerializationSuite) TestModelValidationChecksLinkLayerMACAddress(c *gc.C) { 473 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 474 args := LinkLayerDeviceArgs{MachineID: "42", Name: "foo", MACAddress: "DEADBEEF"} 475 model.AddLinkLayerDevice(args) 476 s.addMachineToModel(model, "42") 477 err := model.Validate() 478 c.Assert(err, gc.ErrorMatches, `device "foo" has invalid MACAddress "DEADBEEF"`) 479 } 480 481 func (s *ModelSerializationSuite) TestModelValidationChecksParentExists(c *gc.C) { 482 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 483 args := LinkLayerDeviceArgs{MachineID: "42", Name: "foo", ParentName: "bar", MACAddress: "01:23:45:67:89:ab"} 484 model.AddLinkLayerDevice(args) 485 s.addMachineToModel(model, "42") 486 err := model.Validate() 487 c.Assert(err, gc.ErrorMatches, `device "foo" has non-existent parent "bar"`) 488 model.AddLinkLayerDevice(LinkLayerDeviceArgs{Name: "bar", MachineID: "42"}) 489 err = model.Validate() 490 c.Assert(err, jc.ErrorIsNil) 491 } 492 493 func (s *ModelSerializationSuite) TestModelValidationChecksParentIsNotItself(c *gc.C) { 494 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 495 args := LinkLayerDeviceArgs{MachineID: "42", Name: "foo", ParentName: "foo"} 496 model.AddLinkLayerDevice(args) 497 s.addMachineToModel(model, "42") 498 err := model.Validate() 499 c.Assert(err, gc.ErrorMatches, `device "foo" is its own parent`) 500 } 501 502 func (s *ModelSerializationSuite) TestModelValidationChecksParentIsABridge(c *gc.C) { 503 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 504 args := LinkLayerDeviceArgs{MachineID: "42", Name: "foo", ParentName: "m#43#d#bar"} 505 model.AddLinkLayerDevice(args) 506 args2 := LinkLayerDeviceArgs{MachineID: "43", Name: "bar"} 507 model.AddLinkLayerDevice(args2) 508 s.addMachineToModel(model, "42") 509 s.addMachineToModel(model, "43") 510 err := model.Validate() 511 c.Assert(err, gc.ErrorMatches, `device "foo" on a container but not a bridge`) 512 } 513 514 func (s *ModelSerializationSuite) TestModelValidationChecksChildDeviceContained(c *gc.C) { 515 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 516 args := LinkLayerDeviceArgs{MachineID: "42", Name: "foo", ParentName: "m#43#d#bar"} 517 model.AddLinkLayerDevice(args) 518 args2 := LinkLayerDeviceArgs{MachineID: "43", Name: "bar", Type: "bridge"} 519 model.AddLinkLayerDevice(args2) 520 s.addMachineToModel(model, "42") 521 s.addMachineToModel(model, "43") 522 err := model.Validate() 523 c.Assert(err, gc.ErrorMatches, `ParentName "m#43#d#bar" for non-container machine "42"`) 524 } 525 526 func (s *ModelSerializationSuite) TestModelValidationChecksParentOnHost(c *gc.C) { 527 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 528 args := LinkLayerDeviceArgs{MachineID: "41/lxd/0", Name: "foo", ParentName: "m#43#d#bar"} 529 model.AddLinkLayerDevice(args) 530 args2 := LinkLayerDeviceArgs{MachineID: "43", Name: "bar", Type: "bridge"} 531 model.AddLinkLayerDevice(args2) 532 machine := s.addMachineToModel(model, "41") 533 container := machine.AddContainer(MachineArgs{Id: names.NewMachineTag("41/lxd/0")}) 534 container.SetInstance(CloudInstanceArgs{InstanceId: "magic"}) 535 container.SetTools(minimalAgentToolsArgs()) 536 container.SetStatus(minimalStatusArgs()) 537 s.addMachineToModel(model, "43") 538 err := model.Validate() 539 c.Assert(err, gc.ErrorMatches, `parent machine of device "foo" not host machine "41"`) 540 } 541 542 func (s *ModelSerializationSuite) TestModelValidationLinkLayerDeviceContainer(c *gc.C) { 543 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 544 args := LinkLayerDeviceArgs{MachineID: "43/lxd/0", Name: "foo", ParentName: "m#43#d#bar"} 545 model.AddLinkLayerDevice(args) 546 args2 := LinkLayerDeviceArgs{MachineID: "43", Name: "bar", Type: "bridge"} 547 model.AddLinkLayerDevice(args2) 548 machine := s.addMachineToModel(model, "43") 549 container := machine.AddContainer(MachineArgs{Id: names.NewMachineTag("43/lxd/0")}) 550 container.SetInstance(CloudInstanceArgs{InstanceId: "magic"}) 551 container.SetTools(minimalAgentToolsArgs()) 552 container.SetStatus(minimalStatusArgs()) 553 err := model.Validate() 554 c.Assert(err, jc.ErrorIsNil) 555 } 556 557 func (s *ModelSerializationSuite) TestSpaces(c *gc.C) { 558 initial := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 559 space := initial.AddSpace(SpaceArgs{Name: "special"}) 560 c.Assert(space.Name(), gc.Equals, "special") 561 spaces := initial.Spaces() 562 c.Assert(spaces, gc.HasLen, 1) 563 c.Assert(spaces[0], gc.Equals, space) 564 565 bytes, err := yaml.Marshal(initial) 566 c.Assert(err, jc.ErrorIsNil) 567 568 model, err := Deserialize(bytes) 569 c.Assert(err, jc.ErrorIsNil) 570 c.Assert(model.Spaces(), jc.DeepEquals, spaces) 571 572 } 573 574 func (s *ModelSerializationSuite) TestLinkLayerDevice(c *gc.C) { 575 initial := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 576 device := initial.AddLinkLayerDevice(LinkLayerDeviceArgs{Name: "foo"}) 577 c.Assert(device.Name(), gc.Equals, "foo") 578 devices := initial.LinkLayerDevices() 579 c.Assert(devices, gc.HasLen, 1) 580 c.Assert(devices[0], jc.DeepEquals, device) 581 582 bytes, err := yaml.Marshal(initial) 583 c.Assert(err, jc.ErrorIsNil) 584 585 model, err := Deserialize(bytes) 586 c.Assert(err, jc.ErrorIsNil) 587 c.Assert(model.LinkLayerDevices(), jc.DeepEquals, devices) 588 } 589 590 func (s *ModelSerializationSuite) TestSubnets(c *gc.C) { 591 initial := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 592 subnet := initial.AddSubnet(SubnetArgs{CIDR: "10.0.0.0/24"}) 593 c.Assert(subnet.CIDR(), gc.Equals, "10.0.0.0/24") 594 subnets := initial.Subnets() 595 c.Assert(subnets, gc.HasLen, 1) 596 c.Assert(subnets[0], jc.DeepEquals, subnet) 597 598 bytes, err := yaml.Marshal(initial) 599 c.Assert(err, jc.ErrorIsNil) 600 601 model, err := Deserialize(bytes) 602 c.Assert(err, jc.ErrorIsNil) 603 c.Assert(model.Subnets(), jc.DeepEquals, subnets) 604 } 605 606 func (s *ModelSerializationSuite) TestIPAddress(c *gc.C) { 607 initial := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 608 addr := initial.AddIPAddress(IPAddressArgs{Value: "10.0.0.4"}) 609 c.Assert(addr.Value(), gc.Equals, "10.0.0.4") 610 addresses := initial.IPAddresses() 611 c.Assert(addresses, gc.HasLen, 1) 612 c.Assert(addresses[0], jc.DeepEquals, addr) 613 614 bytes, err := yaml.Marshal(initial) 615 c.Assert(err, jc.ErrorIsNil) 616 617 model, err := Deserialize(bytes) 618 c.Assert(err, jc.ErrorIsNil) 619 c.Assert(model.IPAddresses(), jc.DeepEquals, addresses) 620 } 621 622 func (s *ModelSerializationSuite) TestSSHHostKey(c *gc.C) { 623 initial := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 624 key := initial.AddSSHHostKey(SSHHostKeyArgs{MachineID: "foo"}) 625 c.Assert(key.MachineID(), gc.Equals, "foo") 626 keys := initial.SSHHostKeys() 627 c.Assert(keys, gc.HasLen, 1) 628 c.Assert(keys[0], jc.DeepEquals, key) 629 630 bytes, err := yaml.Marshal(initial) 631 c.Assert(err, jc.ErrorIsNil) 632 633 model, err := Deserialize(bytes) 634 c.Assert(err, jc.ErrorIsNil) 635 c.Assert(model.SSHHostKeys(), jc.DeepEquals, keys) 636 } 637 638 func (s *ModelSerializationSuite) TestCloudImageMetadata(c *gc.C) { 639 storageSize := uint64(3) 640 initial := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 641 image := initial.AddCloudImageMetadata(CloudImageMetadataArgs{ 642 Stream: "stream", 643 Region: "region-test", 644 Version: "14.04", 645 Series: "trusty", 646 Arch: "arch", 647 VirtType: "virtType-test", 648 RootStorageType: "rootStorageType-test", 649 RootStorageSize: &storageSize, 650 Source: "test", 651 Priority: 2, 652 ImageId: "1", 653 DateCreated: 2, 654 }) 655 c.Assert(image.Stream(), gc.Equals, "stream") 656 c.Assert(image.Region(), gc.Equals, "region-test") 657 c.Assert(image.Version(), gc.Equals, "14.04") 658 c.Assert(image.Arch(), gc.Equals, "arch") 659 c.Assert(image.VirtType(), gc.Equals, "virtType-test") 660 c.Assert(image.RootStorageType(), gc.Equals, "rootStorageType-test") 661 value, ok := image.RootStorageSize() 662 c.Assert(ok, jc.IsTrue) 663 c.Assert(value, gc.Equals, uint64(3)) 664 c.Assert(image.Source(), gc.Equals, "test") 665 c.Assert(image.Priority(), gc.Equals, 2) 666 c.Assert(image.ImageId(), gc.Equals, "1") 667 c.Assert(image.DateCreated(), gc.Equals, int64(2)) 668 669 metadata := initial.CloudImageMetadata() 670 c.Assert(metadata, gc.HasLen, 1) 671 c.Assert(metadata[0], jc.DeepEquals, image) 672 673 bytes, err := yaml.Marshal(initial) 674 c.Assert(err, jc.ErrorIsNil) 675 676 model, err := Deserialize(bytes) 677 c.Assert(err, jc.ErrorIsNil) 678 c.Assert(model.CloudImageMetadata(), jc.DeepEquals, metadata) 679 } 680 681 func (s *ModelSerializationSuite) TestAction(c *gc.C) { 682 initial := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 683 enqueued := time.Now().UTC() 684 action := initial.AddAction(ActionArgs{ 685 Name: "foo", 686 Enqueued: enqueued, 687 Parameters: map[string]interface{}{}, 688 Results: map[string]interface{}{}, 689 }) 690 c.Assert(action.Name(), gc.Equals, "foo") 691 c.Assert(action.Enqueued(), gc.Equals, enqueued) 692 actions := initial.Actions() 693 c.Assert(actions, gc.HasLen, 1) 694 c.Assert(actions[0], jc.DeepEquals, action) 695 696 bytes, err := yaml.Marshal(initial) 697 c.Assert(err, jc.ErrorIsNil) 698 699 model, err := Deserialize(bytes) 700 c.Assert(err, jc.ErrorIsNil) 701 c.Assert(model.Actions(), jc.DeepEquals, actions) 702 } 703 704 func (s *ModelSerializationSuite) TestVolumeValidation(c *gc.C) { 705 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 706 model.AddVolume(testVolumeArgs()) 707 err := model.Validate() 708 c.Assert(err, gc.ErrorMatches, `volume\[0\]: volume "1234" missing status not valid`) 709 } 710 711 func (s *ModelSerializationSuite) TestVolumes(c *gc.C) { 712 initial := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 713 volume := initial.AddVolume(testVolumeArgs()) 714 volume.SetStatus(minimalStatusArgs()) 715 volumes := initial.Volumes() 716 c.Assert(volumes, gc.HasLen, 1) 717 c.Assert(volumes[0], gc.Equals, volume) 718 719 bytes, err := yaml.Marshal(initial) 720 c.Assert(err, jc.ErrorIsNil) 721 722 model, err := Deserialize(bytes) 723 c.Assert(err, jc.ErrorIsNil) 724 c.Assert(model.Volumes(), jc.DeepEquals, volumes) 725 } 726 727 func (s *ModelSerializationSuite) TestFilesystemValidation(c *gc.C) { 728 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 729 model.AddFilesystem(testFilesystemArgs()) 730 err := model.Validate() 731 c.Assert(err, gc.ErrorMatches, `filesystem\[0\]: filesystem "1234" missing status not valid`) 732 } 733 734 func (s *ModelSerializationSuite) TestFilesystems(c *gc.C) { 735 initial := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 736 filesystem := initial.AddFilesystem(testFilesystemArgs()) 737 filesystem.SetStatus(minimalStatusArgs()) 738 filesystem.AddAttachment(testFilesystemAttachmentArgs()) 739 filesystems := initial.Filesystems() 740 c.Assert(filesystems, gc.HasLen, 1) 741 c.Assert(filesystems[0], gc.Equals, filesystem) 742 743 bytes, err := yaml.Marshal(initial) 744 c.Assert(err, jc.ErrorIsNil) 745 746 model, err := Deserialize(bytes) 747 c.Assert(err, jc.ErrorIsNil) 748 c.Assert(model.Filesystems(), jc.DeepEquals, filesystems) 749 } 750 751 func (s *ModelSerializationSuite) TestStorage(c *gc.C) { 752 initial := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 753 storage := initial.AddStorage(testStorageArgs()) 754 storages := initial.Storages() 755 c.Assert(storages, gc.HasLen, 1) 756 c.Assert(storages[0], jc.DeepEquals, storage) 757 758 bytes, err := yaml.Marshal(initial) 759 c.Assert(err, jc.ErrorIsNil) 760 761 model, err := Deserialize(bytes) 762 c.Assert(err, jc.ErrorIsNil) 763 c.Assert(model.Storages(), jc.DeepEquals, storages) 764 } 765 766 func (s *ModelSerializationSuite) TestStoragePools(c *gc.C) { 767 initial := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 768 poolOne := map[string]interface{}{ 769 "foo": 42, 770 "value": true, 771 } 772 poolTwo := map[string]interface{}{ 773 "value": "spanner", 774 } 775 initial.AddStoragePool(StoragePoolArgs{ 776 Name: "one", Provider: "sparkles", Attributes: poolOne}) 777 initial.AddStoragePool(StoragePoolArgs{ 778 Name: "two", Provider: "spanner", Attributes: poolTwo}) 779 780 pools := initial.StoragePools() 781 c.Assert(pools, gc.HasLen, 2) 782 one, two := pools[0], pools[1] 783 c.Check(one.Name(), gc.Equals, "one") 784 c.Check(one.Provider(), gc.Equals, "sparkles") 785 c.Check(one.Attributes(), jc.DeepEquals, poolOne) 786 c.Check(two.Name(), gc.Equals, "two") 787 c.Check(two.Provider(), gc.Equals, "spanner") 788 c.Check(two.Attributes(), jc.DeepEquals, poolTwo) 789 790 bytes, err := yaml.Marshal(initial) 791 c.Assert(err, jc.ErrorIsNil) 792 793 model, err := Deserialize(bytes) 794 c.Assert(err, jc.ErrorIsNil) 795 796 pools = model.StoragePools() 797 c.Assert(pools, gc.HasLen, 2) 798 one, two = pools[0], pools[1] 799 c.Check(one.Name(), gc.Equals, "one") 800 c.Check(one.Provider(), gc.Equals, "sparkles") 801 c.Check(one.Attributes(), jc.DeepEquals, poolOne) 802 c.Check(two.Name(), gc.Equals, "two") 803 c.Check(two.Provider(), gc.Equals, "spanner") 804 c.Check(two.Attributes(), jc.DeepEquals, poolTwo) 805 }