1# Licensed under the Apache License, Version 2.0 (the "License"); you may 2# not use this file except in compliance with the License. You may obtain 3# a copy of the License at 4# 5# http://www.apache.org/licenses/LICENSE-2.0 6# 7# Unless required by applicable law or agreed to in writing, software 8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10# License for the specific language governing permissions and limitations 11# under the License. 12 13from unittest import mock 14 15from openstack.compute.v2 import server 16from openstack.image.v2 import image 17from openstack.tests.unit import base 18 19IDENTIFIER = 'IDENTIFIER' 20EXAMPLE = { 21 'OS-DCF:diskConfig': 'AUTO', 22 'OS-EXT-AZ:availability_zone': 'us-west', 23 'OS-EXT-SRV-ATTR:host': 'compute', 24 'OS-EXT-SRV-ATTR:hostname': 'new-server-test', 25 'OS-EXT-SRV-ATTR:hypervisor_hostname': 'fake-mini', 26 'OS-EXT-SRV-ATTR:instance_name': 'instance-00000001', 27 'OS-EXT-SRV-ATTR:kernel_id': '', 28 'OS-EXT-SRV-ATTR:launch_index': 0, 29 'OS-EXT-SRV-ATTR:ramdisk_id': '', 30 'OS-EXT-SRV-ATTR:reservation_id': 'r-ov3q80zj', 31 'OS-EXT-SRV-ATTR:root_device_name': '/dev/sda', 32 'OS-EXT-SRV-ATTR:user_data': 'IyEvYmluL2Jhc2gKL2Jpbi9IHlvdSEiCg==', 33 'OS-EXT-STS:power_state': 1, 34 'OS-EXT-STS:task_state': None, 35 'OS-EXT-STS:vm_state': 'active', 36 'OS-SRV-USG:launched_at': '2017-02-14T19:23:59.895661', 37 'OS-SRV-USG:terminated_at': '2015-03-09T12:15:57.233772', 38 'OS-SCH-HNT:scheduler_hints': {'key': '30'}, 39 'accessIPv4': '1.2.3.4', 40 'accessIPv6': '80fe::', 41 'adminPass': '27', 42 'addresses': { 43 'private': [ 44 { 45 'OS-EXT-IPS-MAC:mac_addr': 'aa:bb:cc:dd:ee:ff', 46 'OS-EXT-IPS:type': 'fixed', 47 'addr': '192.168.0.3', 48 'version': 4 49 } 50 ] 51 }, 52 'block_device_mapping_v2': {'key': '29'}, 53 'config_drive': '', 54 'created': '2017-02-14T19:23:58Z', 55 'description': 'dummy', 56 'flavorRef': '5', 57 'flavor': { 58 'disk': 1, 59 'ephemeral': 0, 60 'extra_specs': { 61 'hw:cpu_policy': 'dedicated', 62 'hw:mem_page_size': '2048' 63 }, 64 'original_name': 'm1.tiny.specs', 65 'ram': 512, 66 'swap': 0, 67 'vcpus': 1 68 }, 69 'hostId': '2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6', 70 'host_status': 'UP', 71 'id': IDENTIFIER, 72 'imageRef': '8', 73 'image': { 74 'id': '70a599e0-31e7-49b7-b260-868f441e862b', 75 'links': [ 76 { 77 'href': 'http://openstack.example.com/images/70a599e0', 78 'rel': 'bookmark' 79 } 80 ] 81 }, 82 'key_name': 'dummy', 83 'links': [ 84 { 85 'href': 'http://openstack.example.com/v2.1/servers/9168b536', 86 'rel': 'self' 87 }, 88 { 89 'href': 'http://openstack.example.com/servers/9168b536', 90 'rel': 'bookmark' 91 } 92 ], 93 'locked': True, 94 'metadata': { 95 'My Server Name': 'Apache1' 96 }, 97 'name': 'new-server-test', 98 'networks': 'auto', 99 'os-extended-volumes:volumes_attached': [], 100 'progress': 0, 101 'security_groups': [ 102 { 103 'name': 'default' 104 } 105 ], 106 'server_groups': ['3caf4187-8010-491f-b6f5-a4a68a40371e'], 107 'status': 'ACTIVE', 108 'tags': [], 109 'tenant_id': '6f70656e737461636b20342065766572', 110 'trusted_image_certificates': [ 111 '0b5d2c72-12cc-4ba6-a8d7-3ff5cc1d8cb8', 112 '674736e3-f25c-405c-8362-bbf991e0ce0a' 113 ], 114 'updated': '2017-02-14T19:24:00Z', 115 'user_id': 'fake' 116} 117 118 119class TestServer(base.TestCase): 120 121 def setUp(self): 122 super(TestServer, self).setUp() 123 self.resp = mock.Mock() 124 self.resp.body = None 125 self.resp.json = mock.Mock(return_value=self.resp.body) 126 self.resp.status_code = 200 127 self.sess = mock.Mock() 128 self.sess.post = mock.Mock(return_value=self.resp) 129 130 def test_basic(self): 131 sot = server.Server() 132 self.assertEqual('server', sot.resource_key) 133 self.assertEqual('servers', sot.resources_key) 134 self.assertEqual('/servers', sot.base_path) 135 self.assertTrue(sot.allow_create) 136 self.assertTrue(sot.allow_fetch) 137 self.assertTrue(sot.allow_commit) 138 self.assertTrue(sot.allow_delete) 139 self.assertTrue(sot.allow_list) 140 141 self.assertDictEqual({"access_ipv4": "access_ip_v4", 142 "access_ipv6": "access_ip_v6", 143 "auto_disk_config": "auto_disk_config", 144 "availability_zone": "availability_zone", 145 "changes_before": "changes-before", 146 "changes_since": "changes-since", 147 "compute_host": "host", 148 "has_config_drive": "config_drive", 149 "created_at": "created_at", 150 "description": "description", 151 "flavor": "flavor", 152 "hostname": "hostname", 153 "image": "image", 154 "ipv4_address": "ip", 155 "ipv6_address": "ip6", 156 "id": "uuid", 157 "deleted_only": "deleted", 158 "is_soft_deleted": "soft_deleted", 159 "kernel_id": "kernel_id", 160 "key_name": "key_name", 161 "launch_index": "launch_index", 162 "launched_at": "launched_at", 163 "limit": "limit", 164 "locked_by": "locked_by", 165 "marker": "marker", 166 "name": "name", 167 "node": "node", 168 "power_state": "power_state", 169 "progress": "progress", 170 "project_id": "project_id", 171 "ramdisk_id": "ramdisk_id", 172 "reservation_id": "reservation_id", 173 "root_device_name": "root_device_name", 174 "sort_dir": "sort_dir", 175 "sort_key": "sort_key", 176 "status": "status", 177 "task_state": "task_state", 178 "terminated_at": "terminated_at", 179 "user_id": "user_id", 180 "vm_state": "vm_state", 181 "all_projects": "all_tenants", 182 "tags": "tags", 183 "any_tags": "tags-any", 184 "not_tags": "not-tags", 185 "not_any_tags": "not-tags-any", 186 }, 187 sot._query_mapping._mapping) 188 189 def test_make_it(self): 190 sot = server.Server(**EXAMPLE) 191 self.assertEqual(EXAMPLE['accessIPv4'], sot.access_ipv4) 192 self.assertEqual(EXAMPLE['accessIPv6'], sot.access_ipv6) 193 self.assertEqual(EXAMPLE['addresses'], sot.addresses) 194 self.assertEqual(EXAMPLE['created'], sot.created_at) 195 self.assertEqual(EXAMPLE['config_drive'], sot.has_config_drive) 196 self.assertEqual(EXAMPLE['flavorRef'], sot.flavor_id) 197 self.assertEqual(EXAMPLE['flavor'], sot.flavor) 198 self.assertEqual(EXAMPLE['hostId'], sot.host_id) 199 self.assertEqual(EXAMPLE['host_status'], sot.host_status) 200 self.assertEqual(EXAMPLE['id'], sot.id) 201 self.assertEqual(EXAMPLE['imageRef'], sot.image_id) 202 self.assertEqual(image.Image(**EXAMPLE['image']), sot.image) 203 self.assertEqual(EXAMPLE['links'], sot.links) 204 self.assertEqual(EXAMPLE['metadata'], sot.metadata) 205 self.assertEqual(EXAMPLE['networks'], sot.networks) 206 self.assertEqual(EXAMPLE['name'], sot.name) 207 self.assertEqual(EXAMPLE['progress'], sot.progress) 208 self.assertEqual(EXAMPLE['tenant_id'], sot.project_id) 209 self.assertEqual(EXAMPLE['server_groups'], sot.server_groups) 210 self.assertEqual(EXAMPLE['status'], sot.status) 211 self.assertEqual(EXAMPLE['updated'], sot.updated_at) 212 self.assertEqual(EXAMPLE['user_id'], sot.user_id) 213 self.assertEqual(EXAMPLE['key_name'], sot.key_name) 214 self.assertEqual(EXAMPLE['OS-DCF:diskConfig'], sot.disk_config) 215 self.assertEqual(EXAMPLE['OS-EXT-AZ:availability_zone'], 216 sot.availability_zone) 217 self.assertEqual(EXAMPLE['OS-EXT-STS:power_state'], sot.power_state) 218 self.assertEqual(EXAMPLE['OS-EXT-STS:task_state'], sot.task_state) 219 self.assertEqual(EXAMPLE['OS-EXT-STS:vm_state'], sot.vm_state) 220 self.assertEqual(EXAMPLE['os-extended-volumes:volumes_attached'], 221 sot.attached_volumes) 222 self.assertEqual(EXAMPLE['OS-SRV-USG:launched_at'], sot.launched_at) 223 self.assertEqual(EXAMPLE['OS-SRV-USG:terminated_at'], 224 sot.terminated_at) 225 self.assertEqual(EXAMPLE['security_groups'], sot.security_groups) 226 self.assertEqual(EXAMPLE['adminPass'], sot.admin_password) 227 self.assertEqual(EXAMPLE['block_device_mapping_v2'], 228 sot.block_device_mapping) 229 self.assertEqual(EXAMPLE['OS-EXT-SRV-ATTR:host'], 230 sot.compute_host) 231 self.assertEqual(EXAMPLE['OS-EXT-SRV-ATTR:hostname'], 232 sot.hostname) 233 self.assertEqual(EXAMPLE['OS-EXT-SRV-ATTR:hypervisor_hostname'], 234 sot.hypervisor_hostname) 235 self.assertEqual(EXAMPLE['OS-EXT-SRV-ATTR:instance_name'], 236 sot.instance_name) 237 self.assertEqual(EXAMPLE['OS-EXT-SRV-ATTR:kernel_id'], 238 sot.kernel_id) 239 self.assertEqual(EXAMPLE['OS-EXT-SRV-ATTR:launch_index'], 240 sot.launch_index) 241 self.assertEqual(EXAMPLE['OS-EXT-SRV-ATTR:ramdisk_id'], 242 sot.ramdisk_id) 243 self.assertEqual(EXAMPLE['OS-EXT-SRV-ATTR:reservation_id'], 244 sot.reservation_id) 245 self.assertEqual(EXAMPLE['OS-EXT-SRV-ATTR:root_device_name'], 246 sot.root_device_name) 247 self.assertEqual(EXAMPLE['OS-SCH-HNT:scheduler_hints'], 248 sot.scheduler_hints) 249 self.assertEqual(EXAMPLE['OS-EXT-SRV-ATTR:user_data'], sot.user_data) 250 self.assertEqual(EXAMPLE['locked'], sot.is_locked) 251 self.assertEqual(EXAMPLE['trusted_image_certificates'], 252 sot.trusted_image_certificates) 253 254 def test__prepare_server(self): 255 zone = 1 256 data = 2 257 hints = {"hint": 3} 258 259 sot = server.Server(id=1, availability_zone=zone, user_data=data, 260 scheduler_hints=hints, min_count=2, max_count=3) 261 request = sot._prepare_request() 262 263 self.assertNotIn("OS-EXT-AZ:availability_zone", 264 request.body[sot.resource_key]) 265 self.assertEqual(request.body[sot.resource_key]["availability_zone"], 266 zone) 267 268 self.assertNotIn("OS-EXT-SRV-ATTR:user_data", 269 request.body[sot.resource_key]) 270 self.assertEqual(request.body[sot.resource_key]["user_data"], 271 data) 272 273 self.assertNotIn("OS-SCH-HNT:scheduler_hints", 274 request.body[sot.resource_key]) 275 self.assertEqual(request.body["OS-SCH-HNT:scheduler_hints"], hints) 276 277 self.assertEqual(2, request.body[sot.resource_key]['min_count']) 278 self.assertEqual(3, request.body[sot.resource_key]['max_count']) 279 280 def test_change_password(self): 281 sot = server.Server(**EXAMPLE) 282 283 self.assertIsNone(sot.change_password(self.sess, 'a')) 284 285 url = 'servers/IDENTIFIER/action' 286 body = {"changePassword": {"adminPass": "a"}} 287 headers = {'Accept': ''} 288 self.sess.post.assert_called_with( 289 url, json=body, headers=headers, microversion=None) 290 291 def test_reboot(self): 292 sot = server.Server(**EXAMPLE) 293 294 self.assertIsNone(sot.reboot(self.sess, 'HARD')) 295 296 url = 'servers/IDENTIFIER/action' 297 body = {"reboot": {"type": "HARD"}} 298 headers = {'Accept': ''} 299 self.sess.post.assert_called_with( 300 url, json=body, headers=headers, microversion=None) 301 302 def test_force_delete(self): 303 sot = server.Server(**EXAMPLE) 304 305 self.assertIsNone(sot.force_delete(self.sess)) 306 307 url = 'servers/IDENTIFIER/action' 308 body = {'forceDelete': None} 309 headers = {'Accept': ''} 310 self.sess.post.assert_called_with( 311 url, json=body, headers=headers, microversion=None) 312 313 def test_rebuild(self): 314 sot = server.Server(**EXAMPLE) 315 # Let the translate pass through, that portion is tested elsewhere 316 sot._translate_response = lambda arg: arg 317 318 result = sot.rebuild(self.sess, name='noo', admin_password='seekr3t', 319 image='http://image/1', access_ipv4="12.34.56.78", 320 access_ipv6="fe80::100", 321 metadata={"meta var": "meta val"}, 322 user_data="ZWNobyAiaGVsbG8gd29ybGQi") 323 324 self.assertIsInstance(result, server.Server) 325 326 url = 'servers/IDENTIFIER/action' 327 body = { 328 "rebuild": { 329 "name": "noo", 330 "imageRef": "http://image/1", 331 "adminPass": "seekr3t", 332 "accessIPv4": "12.34.56.78", 333 "accessIPv6": "fe80::100", 334 "metadata": {"meta var": "meta val"}, 335 "user_data": "ZWNobyAiaGVsbG8gd29ybGQi", 336 "preserve_ephemeral": False 337 } 338 } 339 headers = {'Accept': ''} 340 self.sess.post.assert_called_with( 341 url, json=body, headers=headers, microversion=None) 342 343 def test_rebuild_minimal(self): 344 sot = server.Server(**EXAMPLE) 345 # Let the translate pass through, that portion is tested elsewhere 346 sot._translate_response = lambda arg: arg 347 348 result = sot.rebuild(self.sess, name='nootoo', 349 admin_password='seekr3two', 350 image='http://image/2') 351 352 self.assertIsInstance(result, server.Server) 353 354 url = 'servers/IDENTIFIER/action' 355 body = { 356 "rebuild": { 357 "name": "nootoo", 358 "imageRef": "http://image/2", 359 "adminPass": "seekr3two", 360 "preserve_ephemeral": False 361 } 362 } 363 headers = {'Accept': ''} 364 self.sess.post.assert_called_with( 365 url, json=body, headers=headers, microversion=None) 366 367 def test_resize(self): 368 sot = server.Server(**EXAMPLE) 369 370 self.assertIsNone(sot.resize(self.sess, '2')) 371 372 url = 'servers/IDENTIFIER/action' 373 body = {"resize": {"flavorRef": "2"}} 374 headers = {'Accept': ''} 375 self.sess.post.assert_called_with( 376 url, json=body, headers=headers, microversion=None) 377 378 def test_confirm_resize(self): 379 sot = server.Server(**EXAMPLE) 380 381 self.assertIsNone(sot.confirm_resize(self.sess)) 382 383 url = 'servers/IDENTIFIER/action' 384 body = {"confirmResize": None} 385 headers = {'Accept': ''} 386 self.sess.post.assert_called_with( 387 url, json=body, headers=headers, microversion=None) 388 389 def test_revert_resize(self): 390 sot = server.Server(**EXAMPLE) 391 392 self.assertIsNone(sot.revert_resize(self.sess)) 393 394 url = 'servers/IDENTIFIER/action' 395 body = {"revertResize": None} 396 headers = {'Accept': ''} 397 self.sess.post.assert_called_with( 398 url, json=body, headers=headers, microversion=None) 399 400 def test_create_image_header(self): 401 sot = server.Server(**EXAMPLE) 402 name = 'noo' 403 metadata = {'nu': 'image', 'created': 'today'} 404 405 url = 'servers/IDENTIFIER/action' 406 body = {"createImage": {'name': name, 'metadata': metadata}} 407 headers = {'Accept': ''} 408 409 rsp = mock.Mock() 410 rsp.json.return_value = None 411 rsp.headers = {'Location': 'dummy/dummy2'} 412 rsp.status_code = 200 413 414 self.sess.post.return_value = rsp 415 416 self.endpoint_data = mock.Mock(spec=['min_microversion', 417 'max_microversion'], 418 min_microversion=None, 419 max_microversion='2.44') 420 self.sess.get_endpoint_data.return_value = self.endpoint_data 421 422 image_id = sot.create_image(self.sess, name, metadata) 423 424 self.sess.post.assert_called_with( 425 url, json=body, headers=headers, microversion=None) 426 427 self.assertEqual('dummy2', image_id) 428 429 def test_create_image_microver(self): 430 sot = server.Server(**EXAMPLE) 431 name = 'noo' 432 metadata = {'nu': 'image', 'created': 'today'} 433 434 url = 'servers/IDENTIFIER/action' 435 body = {"createImage": {'name': name, 'metadata': metadata}} 436 headers = {'Accept': ''} 437 438 rsp = mock.Mock() 439 rsp.json.return_value = {'image_id': 'dummy3'} 440 rsp.headers = {'Location': 'dummy/dummy2'} 441 rsp.status_code = 200 442 443 self.sess.post.return_value = rsp 444 445 self.endpoint_data = mock.Mock(spec=['min_microversion', 446 'max_microversion'], 447 min_microversion='2.1', 448 max_microversion='2.56') 449 self.sess.get_endpoint_data.return_value = self.endpoint_data 450 self.sess.default_microversion = None 451 452 image_id = sot.create_image(self.sess, name, metadata) 453 454 self.sess.post.assert_called_with( 455 url, json=body, headers=headers, microversion='2.45') 456 457 self.assertEqual('dummy3', image_id) 458 459 def test_create_image_minimal(self): 460 sot = server.Server(**EXAMPLE) 461 name = 'noo' 462 url = 'servers/IDENTIFIER/action' 463 body = {"createImage": {'name': name}} 464 headers = {'Accept': ''} 465 466 rsp = mock.Mock() 467 rsp.json.return_value = None 468 rsp.headers = {'Location': 'dummy/dummy2'} 469 rsp.status_code = 200 470 471 self.sess.post.return_value = rsp 472 473 self.endpoint_data = mock.Mock(spec=['min_microversion', 474 'max_microversion'], 475 min_microversion='2.1', 476 max_microversion='2.56') 477 self.sess.get_endpoint_data.return_value = self.endpoint_data 478 self.sess.default_microversion = None 479 480 self.assertIsNone(self.resp.body, sot.create_image(self.sess, name)) 481 482 self.sess.post.assert_called_with( 483 url, json=body, headers=headers, microversion='2.45') 484 485 def test_add_security_group(self): 486 sot = server.Server(**EXAMPLE) 487 488 self.assertIsNone(sot.add_security_group(self.sess, "group")) 489 490 url = 'servers/IDENTIFIER/action' 491 body = {"addSecurityGroup": {"name": "group"}} 492 headers = {'Accept': ''} 493 self.sess.post.assert_called_with( 494 url, json=body, headers=headers, microversion=None) 495 496 def test_remove_security_group(self): 497 sot = server.Server(**EXAMPLE) 498 499 self.assertIsNone(sot.remove_security_group(self.sess, "group")) 500 501 url = 'servers/IDENTIFIER/action' 502 body = {"removeSecurityGroup": {"name": "group"}} 503 headers = {'Accept': ''} 504 self.sess.post.assert_called_with( 505 url, json=body, headers=headers, microversion=None) 506 507 def test_reset_state(self): 508 sot = server.Server(**EXAMPLE) 509 510 self.assertIsNone(sot.reset_state(self.sess, 'active')) 511 512 url = 'servers/IDENTIFIER/action' 513 body = {"os-resetState": {"state": 'active'}} 514 headers = {'Accept': ''} 515 self.sess.post.assert_called_with( 516 url, json=body, headers=headers, microversion=None) 517 518 def test_add_fixed_ip(self): 519 sot = server.Server(**EXAMPLE) 520 521 res = sot.add_fixed_ip(self.sess, "NETWORK-ID") 522 523 self.assertIsNone(res) 524 url = 'servers/IDENTIFIER/action' 525 body = {"addFixedIp": {"networkId": "NETWORK-ID"}} 526 headers = {'Accept': ''} 527 self.sess.post.assert_called_with( 528 url, json=body, headers=headers, microversion=None) 529 530 def test_remove_fixed_ip(self): 531 sot = server.Server(**EXAMPLE) 532 533 res = sot.remove_fixed_ip(self.sess, "ADDRESS") 534 535 self.assertIsNone(res) 536 url = 'servers/IDENTIFIER/action' 537 body = {"removeFixedIp": {"address": "ADDRESS"}} 538 headers = {'Accept': ''} 539 self.sess.post.assert_called_with( 540 url, json=body, headers=headers, microversion=None) 541 542 def test_add_floating_ip(self): 543 sot = server.Server(**EXAMPLE) 544 545 res = sot.add_floating_ip(self.sess, "FLOATING-IP") 546 547 self.assertIsNone(res) 548 url = 'servers/IDENTIFIER/action' 549 body = {"addFloatingIp": {"address": "FLOATING-IP"}} 550 headers = {'Accept': ''} 551 self.sess.post.assert_called_with( 552 url, json=body, headers=headers, microversion=None) 553 554 def test_add_floating_ip_with_fixed_addr(self): 555 sot = server.Server(**EXAMPLE) 556 557 res = sot.add_floating_ip(self.sess, "FLOATING-IP", "FIXED-ADDR") 558 559 self.assertIsNone(res) 560 url = 'servers/IDENTIFIER/action' 561 body = {"addFloatingIp": {"address": "FLOATING-IP", 562 "fixed_address": "FIXED-ADDR"}} 563 headers = {'Accept': ''} 564 self.sess.post.assert_called_with( 565 url, json=body, headers=headers, microversion=None) 566 567 def test_remove_floating_ip(self): 568 sot = server.Server(**EXAMPLE) 569 570 res = sot.remove_floating_ip(self.sess, "I-AM-FLOATING") 571 572 self.assertIsNone(res) 573 url = 'servers/IDENTIFIER/action' 574 body = {"removeFloatingIp": {"address": "I-AM-FLOATING"}} 575 headers = {'Accept': ''} 576 self.sess.post.assert_called_with( 577 url, json=body, headers=headers, microversion=None) 578 579 def test_backup(self): 580 sot = server.Server(**EXAMPLE) 581 582 res = sot.backup(self.sess, "name", "daily", 1) 583 584 self.assertIsNone(res) 585 url = 'servers/IDENTIFIER/action' 586 body = {"createBackup": {"name": "name", "backup_type": "daily", 587 "rotation": 1}} 588 headers = {'Accept': ''} 589 self.sess.post.assert_called_with( 590 url, json=body, headers=headers, microversion=None) 591 592 def test_pause(self): 593 sot = server.Server(**EXAMPLE) 594 595 res = sot.pause(self.sess) 596 597 self.assertIsNone(res) 598 url = 'servers/IDENTIFIER/action' 599 body = {"pause": None} 600 headers = {'Accept': ''} 601 self.sess.post.assert_called_with( 602 url, json=body, headers=headers, microversion=None) 603 604 def test_unpause(self): 605 sot = server.Server(**EXAMPLE) 606 607 res = sot.unpause(self.sess) 608 609 self.assertIsNone(res) 610 url = 'servers/IDENTIFIER/action' 611 body = {"unpause": None} 612 headers = {'Accept': ''} 613 self.sess.post.assert_called_with( 614 url, json=body, headers=headers, microversion=None) 615 616 def test_suspend(self): 617 sot = server.Server(**EXAMPLE) 618 619 res = sot.suspend(self.sess) 620 621 self.assertIsNone(res) 622 url = 'servers/IDENTIFIER/action' 623 body = {"suspend": None} 624 headers = {'Accept': ''} 625 self.sess.post.assert_called_with( 626 url, json=body, headers=headers, microversion=None) 627 628 def test_resume(self): 629 sot = server.Server(**EXAMPLE) 630 631 res = sot.resume(self.sess) 632 633 self.assertIsNone(res) 634 url = 'servers/IDENTIFIER/action' 635 body = {"resume": None} 636 headers = {'Accept': ''} 637 self.sess.post.assert_called_with( 638 url, json=body, headers=headers, microversion=None) 639 640 def test_lock(self): 641 sot = server.Server(**EXAMPLE) 642 643 res = sot.lock(self.sess) 644 645 self.assertIsNone(res) 646 url = 'servers/IDENTIFIER/action' 647 body = {"lock": None} 648 headers = {'Accept': ''} 649 self.sess.post.assert_called_with( 650 url, json=body, headers=headers, microversion=None) 651 652 def test_unlock(self): 653 sot = server.Server(**EXAMPLE) 654 655 res = sot.unlock(self.sess) 656 657 self.assertIsNone(res) 658 url = 'servers/IDENTIFIER/action' 659 body = {"unlock": None} 660 headers = {'Accept': ''} 661 self.sess.post.assert_called_with( 662 url, json=body, headers=headers, microversion=None) 663 664 def test_rescue(self): 665 sot = server.Server(**EXAMPLE) 666 667 res = sot.rescue(self.sess) 668 669 self.assertIsNone(res) 670 url = 'servers/IDENTIFIER/action' 671 body = {"rescue": {}} 672 headers = {'Accept': ''} 673 self.sess.post.assert_called_with( 674 url, json=body, headers=headers, microversion=None) 675 676 def test_rescue_with_options(self): 677 sot = server.Server(**EXAMPLE) 678 679 res = sot.rescue(self.sess, admin_pass='SECRET', image_ref='IMG-ID') 680 681 self.assertIsNone(res) 682 url = 'servers/IDENTIFIER/action' 683 body = {"rescue": {'adminPass': 'SECRET', 684 'rescue_image_ref': 'IMG-ID'}} 685 headers = {'Accept': ''} 686 self.sess.post.assert_called_with( 687 url, json=body, headers=headers, microversion=None) 688 689 def test_unrescue(self): 690 sot = server.Server(**EXAMPLE) 691 692 res = sot.unrescue(self.sess) 693 694 self.assertIsNone(res) 695 url = 'servers/IDENTIFIER/action' 696 body = {"unrescue": None} 697 headers = {'Accept': ''} 698 self.sess.post.assert_called_with( 699 url, json=body, headers=headers, microversion=None) 700 701 def test_evacuate(self): 702 sot = server.Server(**EXAMPLE) 703 704 res = sot.evacuate(self.sess) 705 706 self.assertIsNone(res) 707 url = 'servers/IDENTIFIER/action' 708 body = {"evacuate": {}} 709 headers = {'Accept': ''} 710 self.sess.post.assert_called_with( 711 url, json=body, headers=headers, microversion=None) 712 713 def test_evacuate_with_options(self): 714 sot = server.Server(**EXAMPLE) 715 716 res = sot.evacuate(self.sess, host='HOST2', admin_pass='NEW_PASS', 717 force=True) 718 719 self.assertIsNone(res) 720 url = 'servers/IDENTIFIER/action' 721 body = {"evacuate": {'host': 'HOST2', 'adminPass': 'NEW_PASS', 722 'force': True}} 723 headers = {'Accept': ''} 724 self.sess.post.assert_called_with( 725 url, json=body, headers=headers, microversion=None) 726 727 def test_start(self): 728 sot = server.Server(**EXAMPLE) 729 730 res = sot.start(self.sess) 731 732 self.assertIsNone(res) 733 url = 'servers/IDENTIFIER/action' 734 body = {"os-start": None} 735 headers = {'Accept': ''} 736 self.sess.post.assert_called_with( 737 url, json=body, headers=headers, microversion=None) 738 739 def test_stop(self): 740 sot = server.Server(**EXAMPLE) 741 742 res = sot.stop(self.sess) 743 744 self.assertIsNone(res) 745 url = 'servers/IDENTIFIER/action' 746 body = {"os-stop": None} 747 headers = {'Accept': ''} 748 self.sess.post.assert_called_with( 749 url, json=body, headers=headers, microversion=None) 750 751 def test_shelve(self): 752 sot = server.Server(**EXAMPLE) 753 754 res = sot.shelve(self.sess) 755 756 self.assertIsNone(res) 757 url = 'servers/IDENTIFIER/action' 758 body = {"shelve": None} 759 headers = {'Accept': ''} 760 self.sess.post.assert_called_with( 761 url, json=body, headers=headers, microversion=None) 762 763 def test_unshelve(self): 764 sot = server.Server(**EXAMPLE) 765 766 res = sot.unshelve(self.sess) 767 768 self.assertIsNone(res) 769 url = 'servers/IDENTIFIER/action' 770 body = {"unshelve": None} 771 headers = {'Accept': ''} 772 self.sess.post.assert_called_with( 773 url, json=body, headers=headers, microversion=None) 774 775 def test_unshelve_availability_zone(self): 776 sot = server.Server(**EXAMPLE) 777 778 res = sot.unshelve(self.sess, sot.availability_zone) 779 780 self.assertIsNone(res) 781 url = 'servers/IDENTIFIER/action' 782 body = {"unshelve": { 783 "availability_zone": sot.availability_zone 784 }} 785 headers = {'Accept': ''} 786 self.sess.post.assert_called_with( 787 url, json=body, headers=headers, microversion=None) 788 789 def test_migrate(self): 790 sot = server.Server(**EXAMPLE) 791 792 res = sot.migrate(self.sess) 793 794 self.assertIsNone(res) 795 url = 'servers/IDENTIFIER/action' 796 body = {"migrate": None} 797 798 headers = {'Accept': ''} 799 self.sess.post.assert_called_with( 800 url, json=body, headers=headers, microversion=None) 801 802 def test_get_console_output(self): 803 sot = server.Server(**EXAMPLE) 804 805 res = sot.get_console_output(self.sess) 806 807 self.assertIsNone(res) 808 url = 'servers/IDENTIFIER/action' 809 body = {'os-getConsoleOutput': {}} 810 headers = {'Accept': ''} 811 self.sess.post.assert_called_with( 812 url, json=body, headers=headers, microversion=None) 813 814 res = sot.get_console_output(self.sess, length=1) 815 816 self.assertIsNone(res) 817 url = 'servers/IDENTIFIER/action' 818 body = {'os-getConsoleOutput': {'length': 1}} 819 820 headers = {'Accept': ''} 821 self.sess.post.assert_called_with( 822 url, json=body, headers=headers, microversion=None) 823 824 def test_get_console_url(self): 825 sot = server.Server(**EXAMPLE) 826 827 resp = mock.Mock() 828 resp.body = {'console': {'a': 'b'}} 829 resp.json = mock.Mock(return_value=resp.body) 830 resp.status_code = 200 831 self.sess.post.return_value = resp 832 833 res = sot.get_console_url(self.sess, 'novnc') 834 self.sess.post.assert_called_with( 835 'servers/IDENTIFIER/action', 836 json={'os-getVNCConsole': {'type': 'novnc'}}, 837 headers={'Accept': ''}, microversion=None) 838 self.assertDictEqual(resp.body['console'], res) 839 840 sot.get_console_url(self.sess, 'xvpvnc') 841 self.sess.post.assert_called_with( 842 'servers/IDENTIFIER/action', 843 json={'os-getVNCConsole': {'type': 'xvpvnc'}}, 844 headers={'Accept': ''}, microversion=None) 845 846 sot.get_console_url(self.sess, 'spice-html5') 847 self.sess.post.assert_called_with( 848 'servers/IDENTIFIER/action', 849 json={'os-getSPICEConsole': {'type': 'spice-html5'}}, 850 headers={'Accept': ''}, microversion=None) 851 852 sot.get_console_url(self.sess, 'rdp-html5') 853 self.sess.post.assert_called_with( 854 'servers/IDENTIFIER/action', 855 json={'os-getRDPConsole': {'type': 'rdp-html5'}}, 856 headers={'Accept': ''}, microversion=None) 857 858 sot.get_console_url(self.sess, 'serial') 859 self.sess.post.assert_called_with( 860 'servers/IDENTIFIER/action', 861 json={'os-getSerialConsole': {'type': 'serial'}}, 862 headers={'Accept': ''}, microversion=None) 863 864 self.assertRaises(ValueError, 865 sot.get_console_url, 866 self.sess, 867 'fake_type' 868 ) 869 870 def test_live_migrate_no_force(self): 871 sot = server.Server(**EXAMPLE) 872 873 class FakeEndpointData: 874 min_microversion = None 875 max_microversion = None 876 self.sess.get_endpoint_data.return_value = FakeEndpointData() 877 878 ex = self.assertRaises( 879 ValueError, 880 sot.live_migrate, 881 self.sess, host='HOST2', force=False, block_migration=False) 882 self.assertIn( 883 "Live migration on this cloud implies 'force'", 884 str(ex)) 885 886 def test_live_migrate_no_microversion_force_true(self): 887 sot = server.Server(**EXAMPLE) 888 889 class FakeEndpointData: 890 min_microversion = None 891 max_microversion = None 892 self.sess.get_endpoint_data.return_value = FakeEndpointData() 893 894 res = sot.live_migrate( 895 self.sess, host='HOST2', force=True, block_migration=True, 896 disk_over_commit=True) 897 898 self.assertIsNone(res) 899 url = 'servers/IDENTIFIER/action' 900 body = { 901 'os-migrateLive': { 902 'host': 'HOST2', 903 'disk_over_commit': True, 904 'block_migration': True 905 } 906 } 907 908 headers = {'Accept': ''} 909 self.sess.post.assert_called_with( 910 url, json=body, headers=headers, microversion=None) 911 912 def test_live_migrate_25(self): 913 sot = server.Server(**EXAMPLE) 914 915 class FakeEndpointData: 916 min_microversion = '2.1' 917 max_microversion = '2.25' 918 self.sess.get_endpoint_data.return_value = FakeEndpointData() 919 self.sess.default_microversion = None 920 921 res = sot.live_migrate( 922 self.sess, host='HOST2', force=True, block_migration=False) 923 924 self.assertIsNone(res) 925 url = 'servers/IDENTIFIER/action' 926 body = { 927 "os-migrateLive": { 928 'block_migration': False, 929 'host': 'HOST2', 930 } 931 } 932 933 headers = {'Accept': ''} 934 self.sess.post.assert_called_with( 935 url, json=body, headers=headers, microversion='2.25') 936 937 def test_live_migrate_25_default_block(self): 938 sot = server.Server(**EXAMPLE) 939 940 class FakeEndpointData: 941 min_microversion = '2.1' 942 max_microversion = '2.25' 943 self.sess.get_endpoint_data.return_value = FakeEndpointData() 944 self.sess.default_microversion = None 945 946 res = sot.live_migrate( 947 self.sess, host='HOST2', force=True, block_migration=None) 948 949 self.assertIsNone(res) 950 url = 'servers/IDENTIFIER/action' 951 body = { 952 "os-migrateLive": { 953 'block_migration': 'auto', 954 'host': 'HOST2', 955 } 956 } 957 958 headers = {'Accept': ''} 959 self.sess.post.assert_called_with( 960 url, json=body, headers=headers, microversion='2.25') 961 962 def test_live_migrate_30(self): 963 sot = server.Server(**EXAMPLE) 964 965 class FakeEndpointData: 966 min_microversion = '2.1' 967 max_microversion = '2.30' 968 self.sess.get_endpoint_data.return_value = FakeEndpointData() 969 self.sess.default_microversion = None 970 971 res = sot.live_migrate( 972 self.sess, host='HOST2', force=False, block_migration=False) 973 974 self.assertIsNone(res) 975 url = 'servers/IDENTIFIER/action' 976 body = { 977 'os-migrateLive': { 978 'block_migration': False, 979 'host': 'HOST2' 980 } 981 } 982 983 headers = {'Accept': ''} 984 self.sess.post.assert_called_with( 985 url, json=body, headers=headers, microversion='2.30') 986 987 def test_live_migrate_30_force(self): 988 sot = server.Server(**EXAMPLE) 989 990 class FakeEndpointData: 991 min_microversion = '2.1' 992 max_microversion = '2.30' 993 self.sess.get_endpoint_data.return_value = FakeEndpointData() 994 self.sess.default_microversion = None 995 996 res = sot.live_migrate( 997 self.sess, host='HOST2', force=True, block_migration=None) 998 999 self.assertIsNone(res) 1000 url = 'servers/IDENTIFIER/action' 1001 body = { 1002 'os-migrateLive': { 1003 'block_migration': 'auto', 1004 'host': 'HOST2', 1005 'force': True, 1006 } 1007 } 1008 1009 headers = {'Accept': ''} 1010 self.sess.post.assert_called_with( 1011 url, json=body, headers=headers, microversion='2.30') 1012 1013 def test_get_topology(self): 1014 sot = server.Server(**EXAMPLE) 1015 1016 class FakeEndpointData: 1017 min_microversion = '2.1' 1018 max_microversion = '2.78' 1019 self.sess.get_endpoint_data.return_value = FakeEndpointData() 1020 self.sess.default_microversion = None 1021 1022 response = mock.Mock() 1023 1024 topology = { 1025 "nodes": [ 1026 { 1027 "cpu_pinning": { 1028 "0": 0, 1029 "1": 5 1030 }, 1031 "host_node": 0, 1032 "memory_mb": 1024, 1033 "siblings": [ 1034 [ 1035 0, 1036 1 1037 ] 1038 ], 1039 "vcpu_set": [ 1040 0, 1041 1 1042 ] 1043 }, 1044 { 1045 "cpu_pinning": { 1046 "2": 1, 1047 "3": 8 1048 }, 1049 "host_node": 1, 1050 "memory_mb": 2048, 1051 "siblings": [ 1052 [ 1053 2, 1054 3 1055 ] 1056 ], 1057 "vcpu_set": [ 1058 2, 1059 3 1060 ] 1061 } 1062 ], 1063 "pagesize_kb": 4 1064 } 1065 1066 response.status_code = 200 1067 response.json.return_value = { 1068 'topology': topology 1069 } 1070 1071 self.sess.get.return_value = response 1072 1073 fetched_topology = sot.fetch_topology(self.sess) 1074 1075 url = 'servers/IDENTIFIER/topology' 1076 self.sess.get.assert_called_with(url) 1077 1078 self.assertEqual(fetched_topology, topology) 1079 1080 def test_get_security_groups(self): 1081 sot = server.Server(**EXAMPLE) 1082 1083 response = mock.Mock() 1084 1085 sgs = [{ 1086 'description': 'default', 1087 'id': 1, 1088 'name': 'default', 1089 'rules': [ 1090 { 1091 'direction': 'egress', 1092 'ethertype': 'IPv6', 1093 'id': '3c0e45ff-adaf-4124-b083-bf390e5482ff', 1094 'port_range_max': None, 1095 'port_range_min': None, 1096 'protocol': None, 1097 'remote_group_id': None, 1098 'remote_ip_prefix': None, 1099 'security_group_id': '1', 1100 'project_id': 'e4f50856753b4dc6afee5fa6b9b6c550', 1101 'revision_number': 1, 1102 'tags': ['tag1,tag2'], 1103 'tenant_id': 'e4f50856753b4dc6afee5fa6b9b6c550', 1104 'created_at': '2018-03-19T19:16:56Z', 1105 'updated_at': '2018-03-19T19:16:56Z', 1106 'description': '' 1107 } 1108 ], 1109 'tenant_id': 'e4f50856753b4dc6afee5fa6b9b6c550' 1110 }] 1111 1112 response.status_code = 200 1113 response.json.return_value = { 1114 'security_groups': sgs 1115 } 1116 self.sess.get.return_value = response 1117 1118 sot.fetch_security_groups(self.sess) 1119 1120 url = 'servers/IDENTIFIER/os-security-groups' 1121 self.sess.get.assert_called_with(url) 1122 1123 self.assertEqual(sot.security_groups, sgs) 1124