1# Copyright 2013 Nebula Inc. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); you may 4# not use this file except in compliance with the License. You may obtain 5# a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# License for the specific language governing permissions and limitations 13# under the License. 14# 15 16import copy 17from unittest import mock 18import uuid 19 20from novaclient import api_versions 21 22from openstackclient.api import compute_v2 23from openstackclient.tests.unit import fakes 24from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes 25from openstackclient.tests.unit.image.v2 import fakes as image_fakes 26from openstackclient.tests.unit.network.v2 import fakes as network_fakes 27from openstackclient.tests.unit import utils 28from openstackclient.tests.unit.volume.v2 import fakes as volume_fakes 29 30floating_ip_num = 100 31fix_ip_num = 100 32injected_file_num = 100 33injected_file_size_num = 10240 34injected_path_size_num = 255 35key_pair_num = 100 36core_num = 20 37ram_num = 51200 38instance_num = 10 39property_num = 128 40secgroup_rule_num = 20 41secgroup_num = 10 42servgroup_num = 10 43servgroup_members_num = 10 44project_name = 'project_test' 45QUOTA = { 46 'project': project_name, 47 'floating-ips': floating_ip_num, 48 'fix-ips': fix_ip_num, 49 'injected-files': injected_file_num, 50 'injected-file-size': injected_file_size_num, 51 'injected-path-size': injected_path_size_num, 52 'key-pairs': key_pair_num, 53 'cores': core_num, 54 'ram': ram_num, 55 'instances': instance_num, 56 'properties': property_num, 57 'secgroup_rules': secgroup_rule_num, 58 'secgroups': secgroup_num, 59 'server-groups': servgroup_num, 60 'server-group-members': servgroup_members_num 61} 62 63QUOTA_columns = tuple(sorted(QUOTA)) 64QUOTA_data = tuple(QUOTA[x] for x in sorted(QUOTA)) 65 66 67class FakeAggregate(object): 68 """Fake one aggregate.""" 69 70 @staticmethod 71 def create_one_aggregate(attrs=None): 72 """Create a fake aggregate. 73 74 :param Dictionary attrs: 75 A dictionary with all attributes 76 :return: 77 A FakeResource object, with id and other attributes 78 """ 79 attrs = attrs or {} 80 81 # Set default attribute 82 aggregate_info = { 83 "name": "aggregate-name-" + uuid.uuid4().hex, 84 "availability_zone": "ag_zone", 85 "hosts": [], 86 "id": "aggregate-id-" + uuid.uuid4().hex, 87 "metadata": { 88 "availability_zone": "ag_zone", 89 "key1": "value1", 90 } 91 } 92 93 # Overwrite default attributes. 94 aggregate_info.update(attrs) 95 96 aggregate = fakes.FakeResource( 97 info=copy.deepcopy(aggregate_info), 98 loaded=True) 99 return aggregate 100 101 @staticmethod 102 def create_aggregates(attrs=None, count=2): 103 """Create multiple fake aggregates. 104 105 :param Dictionary attrs: 106 A dictionary with all attributes 107 :param int count: 108 The number of aggregates to fake 109 :return: 110 A list of FakeResource objects faking the aggregates 111 """ 112 aggregates = [] 113 for i in range(0, count): 114 aggregates.append(FakeAggregate.create_one_aggregate(attrs)) 115 116 return aggregates 117 118 @staticmethod 119 def get_aggregates(aggregates=None, count=2): 120 """Get an iterable MagicMock object with a list of faked aggregates. 121 122 If aggregates list is provided, then initialize the Mock object 123 with the list. Otherwise create one. 124 125 :param List aggregates: 126 A list of FakeResource objects faking aggregates 127 :param int count: 128 The number of aggregates to fake 129 :return: 130 An iterable Mock object with side_effect set to a list of faked 131 aggregates 132 """ 133 if aggregates is None: 134 aggregates = FakeAggregate.create_aggregates(count) 135 return mock.Mock(side_effect=aggregates) 136 137 138class FakeComputev2Client(object): 139 140 def __init__(self, **kwargs): 141 self.agents = mock.Mock() 142 self.agents.resource_class = fakes.FakeResource(None, {}) 143 144 self.aggregates = mock.Mock() 145 self.aggregates.resource_class = fakes.FakeResource(None, {}) 146 147 self.availability_zones = mock.Mock() 148 self.availability_zones.resource_class = fakes.FakeResource(None, {}) 149 150 self.images = mock.Mock() 151 self.images.resource_class = fakes.FakeResource(None, {}) 152 153 self.limits = mock.Mock() 154 self.limits.resource_class = fakes.FakeResource(None, {}) 155 156 self.servers = mock.Mock() 157 self.servers.resource_class = fakes.FakeResource(None, {}) 158 159 self.services = mock.Mock() 160 self.services.resource_class = fakes.FakeResource(None, {}) 161 162 self.extensions = mock.Mock() 163 self.extensions.resource_class = fakes.FakeResource(None, {}) 164 165 self.flavors = mock.Mock() 166 self.flavors.resource_class = fakes.FakeResource(None, {}) 167 168 self.flavor_access = mock.Mock() 169 self.flavor_access.resource_class = fakes.FakeResource(None, {}) 170 171 self.quotas = mock.Mock() 172 self.quotas.resource_class = fakes.FakeResource(None, {}) 173 174 self.quota_classes = mock.Mock() 175 self.quota_classes.resource_class = fakes.FakeResource(None, {}) 176 177 self.usage = mock.Mock() 178 self.usage.resource_class = fakes.FakeResource(None, {}) 179 180 self.volumes = mock.Mock() 181 self.volumes.resource_class = fakes.FakeResource(None, {}) 182 183 self.hypervisors = mock.Mock() 184 self.hypervisors.resource_class = fakes.FakeResource(None, {}) 185 186 self.hypervisors_stats = mock.Mock() 187 self.hypervisors_stats.resource_class = fakes.FakeResource(None, {}) 188 189 self.keypairs = mock.Mock() 190 self.keypairs.resource_class = fakes.FakeResource(None, {}) 191 192 self.hosts = mock.Mock() 193 self.hosts.resource_class = fakes.FakeResource(None, {}) 194 195 self.server_groups = mock.Mock() 196 self.server_groups.resource_class = fakes.FakeResource(None, {}) 197 198 self.instance_action = mock.Mock() 199 self.instance_action.resource_class = fakes.FakeResource(None, {}) 200 201 self.auth_token = kwargs['token'] 202 203 self.management_url = kwargs['endpoint'] 204 205 self.api_version = api_versions.APIVersion('2.1') 206 207 208class TestComputev2(utils.TestCommand): 209 210 def setUp(self): 211 super(TestComputev2, self).setUp() 212 213 self.app.client_manager.compute = FakeComputev2Client( 214 endpoint=fakes.AUTH_URL, 215 token=fakes.AUTH_TOKEN, 216 ) 217 218 self.app.client_manager.compute.api = compute_v2.APIv2( 219 session=self.app.client_manager.session, 220 endpoint=fakes.AUTH_URL, 221 ) 222 223 self.app.client_manager.identity = identity_fakes.FakeIdentityv2Client( 224 endpoint=fakes.AUTH_URL, 225 token=fakes.AUTH_TOKEN, 226 ) 227 228 self.app.client_manager.image = image_fakes.FakeImagev2Client( 229 endpoint=fakes.AUTH_URL, 230 token=fakes.AUTH_TOKEN, 231 ) 232 233 self.app.client_manager.network = network_fakes.FakeNetworkV2Client( 234 endpoint=fakes.AUTH_URL, 235 token=fakes.AUTH_TOKEN, 236 ) 237 238 self.app.client_manager.volume = volume_fakes.FakeVolumeClient( 239 endpoint=fakes.AUTH_URL, 240 token=fakes.AUTH_TOKEN, 241 ) 242 243 244class FakeAgent(object): 245 """Fake one or more agent.""" 246 247 @staticmethod 248 def create_one_agent(attrs=None): 249 """Create a fake agent. 250 251 :param Dictionary attrs: 252 A dictionary with all attributes 253 :return: 254 A FakeResource object, with agent_id, os, and so on 255 """ 256 257 attrs = attrs or {} 258 259 # set default attributes. 260 agent_info = { 261 'agent_id': 'agent-id-' + uuid.uuid4().hex, 262 'os': 'agent-os-' + uuid.uuid4().hex, 263 'architecture': 'agent-architecture', 264 'version': '8.0', 265 'url': 'http://127.0.0.1', 266 'md5hash': 'agent-md5hash', 267 'hypervisor': 'hypervisor', 268 } 269 270 # Overwrite default attributes. 271 agent_info.update(attrs) 272 273 agent = fakes.FakeResource(info=copy.deepcopy(agent_info), 274 loaded=True) 275 return agent 276 277 @staticmethod 278 def create_agents(attrs=None, count=2): 279 """Create multiple fake agents. 280 281 :param Dictionary attrs: 282 A dictionary with all attributes 283 :param int count: 284 The number of agents to fake 285 :return: 286 A list of FakeResource objects faking the agents 287 """ 288 agents = [] 289 for i in range(0, count): 290 agents.append(FakeAgent.create_one_agent(attrs)) 291 292 return agents 293 294 295class FakeExtension(object): 296 """Fake one or more extension.""" 297 298 @staticmethod 299 def create_one_extension(attrs=None): 300 """Create a fake extension. 301 302 :param Dictionary attrs: 303 A dictionary with all attributes 304 :return: 305 A FakeResource object with name, namespace, etc. 306 """ 307 attrs = attrs or {} 308 309 # Set default attributes. 310 extension_info = { 311 'name': 'name-' + uuid.uuid4().hex, 312 'namespace': ( 313 'http://docs.openstack.org/compute/ext/multinic/api/v1.1'), 314 'description': 'description-' + uuid.uuid4().hex, 315 'updated': '2014-01-07T12:00:0-00:00', 316 'alias': 'NMN', 317 'links': ('[{"href":' 318 '"https://github.com/openstack/compute-api", "type":' 319 ' "text/html", "rel": "describedby"}]') 320 } 321 322 # Overwrite default attributes. 323 extension_info.update(attrs) 324 325 extension = fakes.FakeResource( 326 info=copy.deepcopy(extension_info), 327 loaded=True) 328 return extension 329 330 331class FakeHypervisor(object): 332 """Fake one or more hypervisor.""" 333 334 @staticmethod 335 def create_one_hypervisor(attrs=None): 336 """Create a fake hypervisor. 337 338 :param Dictionary attrs: 339 A dictionary with all attributes 340 :return: 341 A FakeResource object, with id, hypervisor_hostname, and so on 342 """ 343 attrs = attrs or {} 344 345 # Set default attributes. 346 hypervisor_info = { 347 'id': 'hypervisor-id-' + uuid.uuid4().hex, 348 'hypervisor_hostname': 'hypervisor-hostname-' + uuid.uuid4().hex, 349 'status': 'enabled', 350 'host_ip': '192.168.0.10', 351 'cpu_info': { 352 'aaa': 'aaa', 353 }, 354 'free_disk_gb': 50, 355 'hypervisor_version': 2004001, 356 'disk_available_least': 50, 357 'local_gb': 50, 358 'free_ram_mb': 1024, 359 'service': { 360 'host': 'aaa', 361 'disabled_reason': None, 362 'id': 1, 363 }, 364 'vcpus_used': 0, 365 'hypervisor_type': 'QEMU', 366 'local_gb_used': 0, 367 'vcpus': 4, 368 'memory_mb_used': 512, 369 'memory_mb': 1024, 370 'current_workload': 0, 371 'state': 'up', 372 'running_vms': 0, 373 } 374 375 # Overwrite default attributes. 376 hypervisor_info.update(attrs) 377 378 hypervisor = fakes.FakeResource(info=copy.deepcopy(hypervisor_info), 379 loaded=True) 380 return hypervisor 381 382 @staticmethod 383 def create_hypervisors(attrs=None, count=2): 384 """Create multiple fake hypervisors. 385 386 :param Dictionary attrs: 387 A dictionary with all attributes 388 :param int count: 389 The number of hypervisors to fake 390 :return: 391 A list of FakeResource objects faking the hypervisors 392 """ 393 hypervisors = [] 394 for i in range(0, count): 395 hypervisors.append(FakeHypervisor.create_one_hypervisor(attrs)) 396 397 return hypervisors 398 399 400class FakeHypervisorStats(object): 401 """Fake one or more hypervisor stats.""" 402 403 @staticmethod 404 def create_one_hypervisor_stats(attrs=None): 405 """Create a fake hypervisor stats. 406 407 :param Dictionary attrs: 408 A dictionary with all attributes 409 :return: 410 A FakeResource object, with count, current_workload, and so on 411 """ 412 attrs = attrs or {} 413 414 # Set default attributes. 415 stats_info = { 416 'count': 2, 417 'current_workload': 0, 418 'disk_available_least': 50, 419 'free_disk_gb': 100, 420 'free_ram_mb': 23000, 421 'local_gb': 100, 422 'local_gb_used': 0, 423 'memory_mb': 23800, 424 'memory_mb_used': 1400, 425 'running_vms': 3, 426 'vcpus': 8, 427 'vcpus_used': 3, 428 } 429 430 # Overwrite default attributes. 431 stats_info.update(attrs) 432 433 # Set default method. 434 hypervisor_stats_method = {'to_dict': stats_info} 435 436 hypervisor_stats = fakes.FakeResource( 437 info=copy.deepcopy(stats_info), 438 methods=copy.deepcopy(hypervisor_stats_method), 439 loaded=True) 440 return hypervisor_stats 441 442 @staticmethod 443 def create_hypervisors_stats(attrs=None, count=2): 444 """Create multiple fake hypervisors stats. 445 446 :param Dictionary attrs: 447 A dictionary with all attributes 448 :param int count: 449 The number of hypervisors to fake 450 :return: 451 A list of FakeResource objects faking the hypervisors 452 """ 453 hypervisors = [] 454 for i in range(0, count): 455 hypervisors.append( 456 FakeHypervisorStats.create_one_hypervisor_stats(attrs)) 457 458 return hypervisors 459 460 461class FakeSecurityGroup(object): 462 """Fake one or more security groups.""" 463 464 @staticmethod 465 def create_one_security_group(attrs=None): 466 """Create a fake security group. 467 468 :param Dictionary attrs: 469 A dictionary with all attributes 470 :return: 471 A FakeResource object, with id, name, etc. 472 """ 473 attrs = attrs or {} 474 475 # Set default attributes. 476 security_group_attrs = { 477 'id': 'security-group-id-' + uuid.uuid4().hex, 478 'name': 'security-group-name-' + uuid.uuid4().hex, 479 'description': 'security-group-description-' + uuid.uuid4().hex, 480 'tenant_id': 'project-id-' + uuid.uuid4().hex, 481 'rules': [], 482 } 483 484 # Overwrite default attributes. 485 security_group_attrs.update(attrs) 486 return security_group_attrs 487 488 @staticmethod 489 def create_security_groups(attrs=None, count=2): 490 """Create multiple fake security groups. 491 492 :param Dictionary attrs: 493 A dictionary with all attributes 494 :param int count: 495 The number of security groups to fake 496 :return: 497 A list of FakeResource objects faking the security groups 498 """ 499 security_groups = [] 500 for i in range(0, count): 501 security_groups.append( 502 FakeSecurityGroup.create_one_security_group(attrs)) 503 504 return security_groups 505 506 @staticmethod 507 def get_security_groups(security_groups=None, count=2): 508 """Get an iterable MagicMock with a list of faked security groups. 509 510 If security groups list is provided, then initialize the Mock object 511 with the list. Otherwise create one. 512 513 :param List security_groups: 514 A list of FakeResource objects faking security groups 515 :param int count: 516 The number of security groups to fake 517 :return: 518 An iterable Mock object with side_effect set to a list of faked 519 security groups 520 """ 521 if security_groups is None: 522 security_groups = FakeSecurityGroup.create_security_groups(count) 523 return mock.Mock(side_effect=security_groups) 524 525 526class FakeSecurityGroupRule(object): 527 """Fake one or more security group rules.""" 528 529 @staticmethod 530 def create_one_security_group_rule(attrs=None): 531 """Create a fake security group rule. 532 533 :param Dictionary attrs: 534 A dictionary with all attributes 535 :return: 536 A FakeResource object, with id, etc. 537 """ 538 attrs = attrs or {} 539 540 # Set default attributes. 541 security_group_rule_attrs = { 542 'from_port': 0, 543 'group': {}, 544 'id': 'security-group-rule-id-' + uuid.uuid4().hex, 545 'ip_protocol': 'tcp', 546 'ip_range': {'cidr': '0.0.0.0/0'}, 547 'parent_group_id': 'security-group-id-' + uuid.uuid4().hex, 548 'to_port': 0, 549 } 550 551 # Overwrite default attributes. 552 security_group_rule_attrs.update(attrs) 553 554 return security_group_rule_attrs 555 556 @staticmethod 557 def create_security_group_rules(attrs=None, count=2): 558 """Create multiple fake security group rules. 559 560 :param Dictionary attrs: 561 A dictionary with all attributes 562 :param int count: 563 The number of security group rules to fake 564 :return: 565 A list of FakeResource objects faking the security group rules 566 """ 567 security_group_rules = [] 568 for i in range(0, count): 569 security_group_rules.append( 570 FakeSecurityGroupRule.create_one_security_group_rule(attrs)) 571 572 return security_group_rules 573 574 575class FakeServer(object): 576 """Fake one or more compute servers.""" 577 578 @staticmethod 579 def create_one_server(attrs=None, methods=None): 580 """Create a fake server. 581 582 :param Dictionary attrs: 583 A dictionary with all attributes 584 :param Dictionary methods: 585 A dictionary with all methods 586 :return: 587 A FakeResource object, with id, name, metadata, and so on 588 """ 589 attrs = attrs or {} 590 methods = methods or {} 591 592 # Set default attributes. 593 server_info = { 594 'id': 'server-id-' + uuid.uuid4().hex, 595 'name': 'server-name-' + uuid.uuid4().hex, 596 'metadata': {}, 597 'image': { 598 'id': 'image-id-' + uuid.uuid4().hex, 599 }, 600 'flavor': { 601 'id': 'flavor-id-' + uuid.uuid4().hex, 602 }, 603 'OS-EXT-STS:power_state': 1, 604 } 605 606 # Overwrite default attributes. 607 server_info.update(attrs) 608 609 server = fakes.FakeResource(info=copy.deepcopy(server_info), 610 methods=methods, 611 loaded=True) 612 return server 613 614 @staticmethod 615 def create_servers(attrs=None, methods=None, count=2): 616 """Create multiple fake servers. 617 618 :param Dictionary attrs: 619 A dictionary with all attributes 620 :param Dictionary methods: 621 A dictionary with all methods 622 :param int count: 623 The number of servers to fake 624 :return: 625 A list of FakeResource objects faking the servers 626 """ 627 servers = [] 628 for i in range(0, count): 629 servers.append(FakeServer.create_one_server(attrs, methods)) 630 631 return servers 632 633 @staticmethod 634 def get_servers(servers=None, count=2): 635 """Get an iterable MagicMock object with a list of faked servers. 636 637 If servers list is provided, then initialize the Mock object with the 638 list. Otherwise create one. 639 640 :param List servers: 641 A list of FakeResource objects faking servers 642 :param int count: 643 The number of servers to fake 644 :return: 645 An iterable Mock object with side_effect set to a list of faked 646 servers 647 """ 648 if servers is None: 649 servers = FakeServer.create_servers(count) 650 return mock.Mock(side_effect=servers) 651 652 653class FakeServerEvent(object): 654 """Fake one or more server event.""" 655 656 @staticmethod 657 def create_one_server_event(attrs=None): 658 """Create a fake server event. 659 660 :param attrs: 661 A dictionary with all attributes 662 :return: 663 A FakeResource object, with id and other attributes 664 """ 665 attrs = attrs or {} 666 667 # Set default attributes 668 server_event_info = { 669 "instance_uuid": "server-event-" + uuid.uuid4().hex, 670 "user_id": "user-id-" + uuid.uuid4().hex, 671 "start_time": "2017-02-27T07:47:13.000000", 672 "request_id": "req-" + uuid.uuid4().hex, 673 "action": "create", 674 "message": None, 675 "project_id": "project-id-" + uuid.uuid4().hex, 676 "events": [{ 677 "finish_time": "2017-02-27T07:47:25.000000", 678 "start_time": "2017-02-27T07:47:15.000000", 679 "traceback": None, 680 "event": "compute__do_build_and_run_instance", 681 "result": "Success" 682 }] 683 } 684 # Overwrite default attributes 685 server_event_info.update(attrs) 686 687 server_event = fakes.FakeResource( 688 info=copy.deepcopy(server_event_info), 689 loaded=True, 690 ) 691 return server_event 692 693 694class FakeService(object): 695 """Fake one or more services.""" 696 697 @staticmethod 698 def create_one_service(attrs=None): 699 """Create a fake service. 700 701 :param Dictionary attrs: 702 A dictionary with all attributes 703 :return: 704 A FakeResource object, with id, host, binary, and so on 705 """ 706 attrs = attrs or {} 707 708 # Set default attributes. 709 service_info = { 710 'id': 'id-' + uuid.uuid4().hex, 711 'host': 'host-' + uuid.uuid4().hex, 712 'binary': 'binary-' + uuid.uuid4().hex, 713 'status': 'enabled', 714 'zone': 'zone-' + uuid.uuid4().hex, 715 'state': 'state-' + uuid.uuid4().hex, 716 'updated_at': 'time-' + uuid.uuid4().hex, 717 'disabled_reason': 'earthquake', 718 } 719 720 # Overwrite default attributes. 721 service_info.update(attrs) 722 723 service = fakes.FakeResource(info=copy.deepcopy(service_info), 724 loaded=True) 725 726 return service 727 728 @staticmethod 729 def create_services(attrs=None, count=2): 730 """Create multiple fake services. 731 732 :param Dictionary attrs: 733 A dictionary with all attributes 734 :param int count: 735 The number of services to fake 736 :return: 737 A list of FakeResource objects faking the services 738 """ 739 services = [] 740 for i in range(0, count): 741 services.append(FakeService.create_one_service(attrs)) 742 743 return services 744 745 746class FakeFlavor(object): 747 """Fake one or more flavors.""" 748 749 @staticmethod 750 def create_one_flavor(attrs=None): 751 """Create a fake flavor. 752 753 :param Dictionary attrs: 754 A dictionary with all attributes 755 :return: 756 A FakeResource object, with id, name, ram, vcpus, and so on 757 """ 758 attrs = attrs or {} 759 760 # Set default attributes. 761 flavor_info = { 762 'id': 'flavor-id-' + uuid.uuid4().hex, 763 'name': 'flavor-name-' + uuid.uuid4().hex, 764 'ram': 8192, 765 'vcpus': 4, 766 'disk': 128, 767 'swap': 0, 768 'rxtx_factor': 1.0, 769 'OS-FLV-DISABLED:disabled': False, 770 'os-flavor-access:is_public': True, 771 'description': 'description', 772 'OS-FLV-EXT-DATA:ephemeral': 0, 773 'properties': {'property': 'value'}, 774 } 775 776 # Overwrite default attributes. 777 flavor_info.update(attrs) 778 779 # Set default methods. 780 flavor_methods = { 781 'set_keys': None, 782 'unset_keys': None, 783 'get_keys': {'property': 'value'}, 784 } 785 786 flavor = fakes.FakeResource(info=copy.deepcopy(flavor_info), 787 methods=flavor_methods, 788 loaded=True) 789 790 # Set attributes with special mappings in nova client. 791 flavor.disabled = flavor_info['OS-FLV-DISABLED:disabled'] 792 flavor.is_public = flavor_info['os-flavor-access:is_public'] 793 flavor.ephemeral = flavor_info['OS-FLV-EXT-DATA:ephemeral'] 794 795 return flavor 796 797 @staticmethod 798 def create_flavors(attrs=None, count=2): 799 """Create multiple fake flavors. 800 801 :param Dictionary attrs: 802 A dictionary with all attributes 803 :param int count: 804 The number of flavors to fake 805 :return: 806 A list of FakeResource objects faking the flavors 807 """ 808 flavors = [] 809 for i in range(0, count): 810 flavors.append(FakeFlavor.create_one_flavor(attrs)) 811 812 return flavors 813 814 @staticmethod 815 def get_flavors(flavors=None, count=2): 816 """Get an iterable MagicMock object with a list of faked flavors. 817 818 If flavors list is provided, then initialize the Mock object with the 819 list. Otherwise create one. 820 821 :param List flavors: 822 A list of FakeResource objects faking flavors 823 :param int count: 824 The number of flavors to fake 825 :return: 826 An iterable Mock object with side_effect set to a list of faked 827 flavors 828 """ 829 if flavors is None: 830 flavors = FakeFlavor.create_flavors(count) 831 return mock.Mock(side_effect=flavors) 832 833 834class FakeFlavorAccess(object): 835 """Fake one or more flavor accesses.""" 836 837 @staticmethod 838 def create_one_flavor_access(attrs=None): 839 """Create a fake flavor access. 840 841 :param Dictionary attrs: 842 A dictionary with all attributes 843 :return: 844 A FakeResource object, with flavor_id, tenat_id 845 """ 846 attrs = attrs or {} 847 848 # Set default attributes. 849 flavor_access_info = { 850 'flavor_id': 'flavor-id-' + uuid.uuid4().hex, 851 'tenant_id': 'tenant-id-' + uuid.uuid4().hex, 852 } 853 854 # Overwrite default attributes. 855 flavor_access_info.update(attrs) 856 857 flavor_access = fakes.FakeResource( 858 info=copy.deepcopy(flavor_access_info), loaded=True) 859 860 return flavor_access 861 862 863class FakeKeypair(object): 864 """Fake one or more keypairs.""" 865 866 @staticmethod 867 def create_one_keypair(attrs=None, no_pri=False): 868 """Create a fake keypair 869 870 :param Dictionary attrs: 871 A dictionary with all attributes 872 :return: 873 A FakeResource object, name, fingerprint, and so on 874 """ 875 attrs = attrs or {} 876 877 # Set default attributes. 878 keypair_info = { 879 'name': 'keypair-name-' + uuid.uuid4().hex, 880 'fingerprint': 'dummy', 881 'public_key': 'dummy', 882 'user_id': 'user' 883 } 884 if not no_pri: 885 keypair_info['private_key'] = 'private_key' 886 887 # Overwrite default attributes. 888 keypair_info.update(attrs) 889 890 keypair = fakes.FakeResource(info=copy.deepcopy(keypair_info), 891 loaded=True) 892 893 return keypair 894 895 @staticmethod 896 def create_keypairs(attrs=None, count=2): 897 """Create multiple fake keypairs. 898 899 :param Dictionary attrs: 900 A dictionary with all attributes 901 :param int count: 902 The number of keypairs to fake 903 :return: 904 A list of FakeResource objects faking the keypairs 905 """ 906 907 keypairs = [] 908 for i in range(0, count): 909 keypairs.append(FakeKeypair.create_one_keypair(attrs)) 910 911 return keypairs 912 913 @staticmethod 914 def get_keypairs(keypairs=None, count=2): 915 """Get an iterable MagicMock object with a list of faked keypairs. 916 917 If keypairs list is provided, then initialize the Mock object with the 918 list. Otherwise create one. 919 920 :param List keypairs: 921 A list of FakeResource objects faking keypairs 922 :param int count: 923 The number of keypairs to fake 924 :return: 925 An iterable Mock object with side_effect set to a list of faked 926 keypairs 927 """ 928 if keypairs is None: 929 keypairs = FakeKeypair.create_keypairs(count) 930 return mock.Mock(side_effect=keypairs) 931 932 933class FakeAvailabilityZone(object): 934 """Fake one or more compute availability zones (AZs).""" 935 936 @staticmethod 937 def create_one_availability_zone(attrs=None): 938 """Create a fake AZ. 939 940 :param Dictionary attrs: 941 A dictionary with all attributes 942 :return: 943 A FakeResource object with zoneName, zoneState, etc. 944 """ 945 attrs = attrs or {} 946 947 # Set default attributes. 948 host_name = uuid.uuid4().hex 949 service_name = uuid.uuid4().hex 950 service_updated_at = uuid.uuid4().hex 951 availability_zone = { 952 'zoneName': uuid.uuid4().hex, 953 'zoneState': {'available': True}, 954 'hosts': {host_name: {service_name: { 955 'available': True, 956 'active': True, 957 'updated_at': service_updated_at, 958 }}}, 959 } 960 961 # Overwrite default attributes. 962 availability_zone.update(attrs) 963 964 availability_zone = fakes.FakeResource( 965 info=copy.deepcopy(availability_zone), 966 loaded=True) 967 return availability_zone 968 969 @staticmethod 970 def create_availability_zones(attrs=None, count=2): 971 """Create multiple fake AZs. 972 973 :param Dictionary attrs: 974 A dictionary with all attributes 975 :param int count: 976 The number of AZs to fake 977 :return: 978 A list of FakeResource objects faking the AZs 979 """ 980 availability_zones = [] 981 for i in range(0, count): 982 availability_zone = \ 983 FakeAvailabilityZone.create_one_availability_zone(attrs) 984 availability_zones.append(availability_zone) 985 986 return availability_zones 987 988 989class FakeFloatingIP(object): 990 """Fake one or more floating ip.""" 991 992 @staticmethod 993 def create_one_floating_ip(attrs=None): 994 """Create a fake floating ip. 995 996 :param Dictionary attrs: 997 A dictionary with all attributes 998 :return: 999 A FakeResource object, with id, ip, and so on 1000 """ 1001 attrs = attrs or {} 1002 1003 # Set default attributes. 1004 floating_ip_attrs = { 1005 'id': 'floating-ip-id-' + uuid.uuid4().hex, 1006 'ip': '1.0.9.0', 1007 'fixed_ip': '2.0.9.0', 1008 'instance_id': 'server-id-' + uuid.uuid4().hex, 1009 'pool': 'public', 1010 } 1011 1012 # Overwrite default attributes. 1013 floating_ip_attrs.update(attrs) 1014 1015 return floating_ip_attrs 1016 1017 @staticmethod 1018 def create_floating_ips(attrs=None, count=2): 1019 """Create multiple fake floating ips. 1020 1021 :param Dictionary attrs: 1022 A dictionary with all attributes 1023 :param int count: 1024 The number of floating ips to fake 1025 :return: 1026 A list of FakeResource objects faking the floating ips 1027 """ 1028 floating_ips = [] 1029 for i in range(0, count): 1030 floating_ips.append(FakeFloatingIP.create_one_floating_ip(attrs)) 1031 return floating_ips 1032 1033 @staticmethod 1034 def get_floating_ips(floating_ips=None, count=2): 1035 """Get an iterable MagicMock object with a list of faked floating ips. 1036 1037 If floating_ips list is provided, then initialize the Mock object 1038 with the list. Otherwise create one. 1039 1040 :param List floating_ips: 1041 A list of FakeResource objects faking floating ips 1042 :param int count: 1043 The number of floating ips to fake 1044 :return: 1045 An iterable Mock object with side_effect set to a list of faked 1046 floating ips 1047 """ 1048 if floating_ips is None: 1049 floating_ips = FakeFloatingIP.create_floating_ips(count) 1050 return mock.Mock(side_effect=floating_ips) 1051 1052 1053class FakeFloatingIPPool(object): 1054 """Fake one or more floating ip pools.""" 1055 1056 @staticmethod 1057 def create_one_floating_ip_pool(attrs=None): 1058 """Create a fake floating ip pool. 1059 1060 :param Dictionary attrs: 1061 A dictionary with all attributes 1062 :return: 1063 A FakeResource object, with name, etc 1064 """ 1065 if attrs is None: 1066 attrs = {} 1067 1068 # Set default attributes. 1069 floating_ip_pool_attrs = { 1070 'name': 'floating-ip-pool-name-' + uuid.uuid4().hex, 1071 } 1072 1073 # Overwrite default attributes. 1074 floating_ip_pool_attrs.update(attrs) 1075 1076 return floating_ip_pool_attrs 1077 1078 @staticmethod 1079 def create_floating_ip_pools(attrs=None, count=2): 1080 """Create multiple fake floating ip pools. 1081 1082 :param Dictionary attrs: 1083 A dictionary with all attributes 1084 :param int count: 1085 The number of floating ip pools to fake 1086 :return: 1087 A list of FakeResource objects faking the floating ip pools 1088 """ 1089 floating_ip_pools = [] 1090 for i in range(0, count): 1091 floating_ip_pools.append( 1092 FakeFloatingIPPool.create_one_floating_ip_pool(attrs) 1093 ) 1094 return floating_ip_pools 1095 1096 1097class FakeNetwork(object): 1098 """Fake one or more networks.""" 1099 1100 @staticmethod 1101 def create_one_network(attrs=None): 1102 """Create a fake network. 1103 1104 :param Dictionary attrs: 1105 A dictionary with all attributes 1106 :return: 1107 A FakeResource object, with id, label, cidr and so on 1108 """ 1109 attrs = attrs or {} 1110 1111 # Set default attributes. 1112 network_attrs = { 1113 'bridge': 'br100', 1114 'bridge_interface': None, 1115 'broadcast': '10.0.0.255', 1116 'cidr': '10.0.0.0/24', 1117 'cidr_v6': None, 1118 'created_at': '2016-02-11T11:17:37.000000', 1119 'deleted': False, 1120 'deleted_at': None, 1121 'dhcp_server': '10.0.0.1', 1122 'dhcp_start': '10.0.0.2', 1123 'dns1': '8.8.4.4', 1124 'dns2': None, 1125 'enable_dhcp': True, 1126 'gateway': '10.0.0.1', 1127 'gateway_v6': None, 1128 'host': None, 1129 'id': 'network-id-' + uuid.uuid4().hex, 1130 'injected': False, 1131 'label': 'network-label-' + uuid.uuid4().hex, 1132 'mtu': None, 1133 'multi_host': False, 1134 'netmask': '255.255.255.0', 1135 'netmask_v6': None, 1136 'priority': None, 1137 'project_id': 'project-id-' + uuid.uuid4().hex, 1138 'rxtx_base': None, 1139 'share_address': False, 1140 'updated_at': None, 1141 'vlan': None, 1142 'vpn_private_address': None, 1143 'vpn_public_address': None, 1144 'vpn_public_port': None, 1145 } 1146 1147 # Overwrite default attributes. 1148 network_attrs.update(attrs) 1149 1150 return network_attrs 1151 1152 @staticmethod 1153 def create_networks(attrs=None, count=2): 1154 """Create multiple fake networks. 1155 1156 :param Dictionary attrs: 1157 A dictionary with all attributes 1158 :param int count: 1159 The number of networks to fake 1160 :return: 1161 A list of FakeResource objects faking the networks 1162 """ 1163 networks = [] 1164 for i in range(0, count): 1165 networks.append(FakeNetwork.create_one_network(attrs)) 1166 1167 return networks 1168 1169 @staticmethod 1170 def get_networks(networks=None, count=2): 1171 """Get an iterable MagicMock object with a list of faked networks. 1172 1173 If networks list is provided, then initialize the Mock object with the 1174 list. Otherwise create one. 1175 1176 :param List networks: 1177 A list of FakeResource objects faking networks 1178 :param int count: 1179 The number of networks to fake 1180 :return: 1181 An iterable Mock object with side_effect set to a list of faked 1182 networks 1183 """ 1184 if networks is None: 1185 networks = FakeNetwork.create_networks(count=count) 1186 return mock.Mock(side_effect=networks) 1187 1188 1189class FakeHost(object): 1190 """Fake one host.""" 1191 1192 @staticmethod 1193 def create_one_host(attrs=None): 1194 """Create a fake host. 1195 1196 :param Dictionary attrs: 1197 A dictionary with all attributes 1198 :return: 1199 A FakeResource object, with uuid and other attributes 1200 """ 1201 attrs = attrs or {} 1202 1203 # Set default attributes. 1204 host_info = { 1205 "service_id": 1, 1206 "host": "host1", 1207 "uuid": 'host-id-' + uuid.uuid4().hex, 1208 "vcpus": 10, 1209 "memory_mb": 100, 1210 "local_gb": 100, 1211 "vcpus_used": 5, 1212 "memory_mb_used": 50, 1213 "local_gb_used": 10, 1214 "hypervisor_type": "xen", 1215 "hypervisor_version": 1, 1216 "hypervisor_hostname": "devstack1", 1217 "free_ram_mb": 50, 1218 "free_disk_gb": 50, 1219 "current_workload": 10, 1220 "running_vms": 1, 1221 "cpu_info": "", 1222 "disk_available_least": 1, 1223 "host_ip": "10.10.10.10", 1224 "supported_instances": "", 1225 "metrics": "", 1226 "pci_stats": "", 1227 "extra_resources": "", 1228 "stats": "", 1229 "numa_topology": "", 1230 "ram_allocation_ratio": 1.0, 1231 "cpu_allocation_ratio": 1.0, 1232 "zone": 'zone-' + uuid.uuid4().hex, 1233 "host_name": 'name-' + uuid.uuid4().hex, 1234 "service": 'service-' + uuid.uuid4().hex, 1235 "cpu": 4, 1236 "disk_gb": 100, 1237 'project': 'project-' + uuid.uuid4().hex, 1238 } 1239 host_info.update(attrs) 1240 return host_info 1241 1242 1243class FakeServerGroup(object): 1244 """Fake one server group""" 1245 1246 @staticmethod 1247 def create_one_server_group(attrs=None): 1248 """Create a fake server group 1249 1250 :param Dictionary attrs: 1251 A dictionary with all attributes 1252 :return: 1253 A FakeResource object, with id and other attributes 1254 """ 1255 if attrs is None: 1256 attrs = {} 1257 1258 # Set default attributes. 1259 server_group_info = { 1260 'id': 'server-group-id-' + uuid.uuid4().hex, 1261 'members': [], 1262 'metadata': {}, 1263 'name': 'server-group-name-' + uuid.uuid4().hex, 1264 'policies': [], 1265 'project_id': 'server-group-project-id-' + uuid.uuid4().hex, 1266 'user_id': 'server-group-user-id-' + uuid.uuid4().hex, 1267 } 1268 1269 # Overwrite default attributes. 1270 server_group_info.update(attrs) 1271 1272 server_group = fakes.FakeResource( 1273 info=copy.deepcopy(server_group_info), 1274 loaded=True) 1275 return server_group 1276 1277 1278class FakeUsage(object): 1279 """Fake one or more usage.""" 1280 1281 @staticmethod 1282 def create_one_usage(attrs=None): 1283 """Create a fake usage. 1284 1285 :param Dictionary attrs: 1286 A dictionary with all attributes 1287 :return: 1288 A FakeResource object, with tenant_id and other attributes 1289 """ 1290 if attrs is None: 1291 attrs = {} 1292 1293 # Set default attributes. 1294 usage_info = { 1295 'tenant_id': 'usage-tenant-id-' + uuid.uuid4().hex, 1296 'total_memory_mb_usage': 512.0, 1297 'total_vcpus_usage': 1.0, 1298 'total_local_gb_usage': 1.0, 1299 'server_usages': [ 1300 { 1301 'ended_at': None, 1302 'flavor': 'usage-flavor-' + uuid.uuid4().hex, 1303 'hours': 1.0, 1304 'local_gb': 1, 1305 'memory_mb': 512, 1306 'name': 'usage-name-' + uuid.uuid4().hex, 1307 'instance_id': uuid.uuid4().hex, 1308 'state': 'active', 1309 'uptime': 3600, 1310 'vcpus': 1 1311 } 1312 ] 1313 } 1314 1315 # Overwrite default attributes. 1316 usage_info.update(attrs) 1317 1318 usage = fakes.FakeResource(info=copy.deepcopy(usage_info), 1319 loaded=True) 1320 1321 return usage 1322 1323 @staticmethod 1324 def create_usages(attrs=None, count=2): 1325 """Create multiple fake services. 1326 1327 :param Dictionary attrs: 1328 A dictionary with all attributes 1329 :param int count: 1330 The number of services to fake 1331 :return: 1332 A list of FakeResource objects faking the services 1333 """ 1334 usages = [] 1335 for i in range(0, count): 1336 usages.append(FakeUsage.create_one_usage(attrs)) 1337 1338 return usages 1339 1340 1341class FakeQuota(object): 1342 """Fake quota""" 1343 1344 @staticmethod 1345 def create_one_comp_quota(attrs=None): 1346 """Create one quota""" 1347 1348 attrs = attrs or {} 1349 1350 quota_attrs = { 1351 'id': 'project-id-' + uuid.uuid4().hex, 1352 'cores': 20, 1353 'fixed_ips': 30, 1354 'injected_files': 100, 1355 'injected_file_content_bytes': 10240, 1356 'injected_file_path_bytes': 255, 1357 'instances': 50, 1358 'key_pairs': 20, 1359 'metadata_items': 10, 1360 'ram': 51200, 1361 'server_groups': 10, 1362 'server_group_members': 10 1363 } 1364 1365 quota_attrs.update(attrs) 1366 quota = fakes.FakeResource( 1367 info=copy.deepcopy(quota_attrs), 1368 loaded=True) 1369 1370 quota.project_id = quota_attrs['id'] 1371 1372 return quota 1373 1374 @staticmethod 1375 def create_one_default_comp_quota(attrs=None): 1376 """Crate one quota""" 1377 1378 attrs = attrs or {} 1379 1380 quota_attrs = { 1381 'id': 'project-id-' + uuid.uuid4().hex, 1382 'cores': 10, 1383 'fixed_ips': 10, 1384 'injected_files': 100, 1385 'injected_file_content_bytes': 10240, 1386 'injected_file_path_bytes': 255, 1387 'instances': 20, 1388 'key_pairs': 20, 1389 'metadata_items': 10, 1390 'ram': 51200, 1391 'server_groups': 10, 1392 'server_group_members': 10 1393 } 1394 1395 quota_attrs.update(attrs) 1396 quota = fakes.FakeResource( 1397 info=copy.deepcopy(quota_attrs), 1398 loaded=True) 1399 1400 quota.project_id = quota_attrs['id'] 1401 1402 return quota 1403 1404 @staticmethod 1405 def create_one_comp_detailed_quota(attrs=None): 1406 """Create one quota""" 1407 1408 attrs = attrs or {} 1409 1410 quota_attrs = { 1411 'id': 'project-id-' + uuid.uuid4().hex, 1412 'cores': {'reserved': 0, 'in_use': 0, 'limit': 20}, 1413 'fixed_ips': {'reserved': 0, 'in_use': 0, 'limit': 30}, 1414 'injected_files': {'reserved': 0, 'in_use': 0, 'limit': 100}, 1415 'injected_file_content_bytes': { 1416 'reserved': 0, 'in_use': 0, 'limit': 10240}, 1417 'injected_file_path_bytes': { 1418 'reserved': 0, 'in_use': 0, 'limit': 255}, 1419 'instances': {'reserved': 0, 'in_use': 0, 'limit': 50}, 1420 'key_pairs': {'reserved': 0, 'in_use': 0, 'limit': 20}, 1421 'metadata_items': {'reserved': 0, 'in_use': 0, 'limit': 10}, 1422 'ram': {'reserved': 0, 'in_use': 0, 'limit': 51200}, 1423 'server_groups': {'reserved': 0, 'in_use': 0, 'limit': 10}, 1424 'server_group_members': {'reserved': 0, 'in_use': 0, 'limit': 10} 1425 } 1426 1427 quota_attrs.update(attrs) 1428 quota = fakes.FakeResource( 1429 info=copy.deepcopy(quota_attrs), 1430 loaded=True) 1431 1432 quota.project_id = quota_attrs['id'] 1433 1434 return quota 1435 1436 1437class FakeLimits(object): 1438 """Fake limits""" 1439 1440 def __init__(self, absolute_attrs=None, rate_attrs=None): 1441 self.absolute_limits_attrs = { 1442 'maxServerMeta': 128, 1443 'maxTotalInstances': 10, 1444 'maxPersonality': 5, 1445 'totalServerGroupsUsed': 0, 1446 'maxImageMeta': 128, 1447 'maxPersonalitySize': 10240, 1448 'maxTotalRAMSize': 51200, 1449 'maxServerGroups': 10, 1450 'maxSecurityGroupRules': 20, 1451 'maxTotalKeypairs': 100, 1452 'totalCoresUsed': 0, 1453 'totalRAMUsed': 0, 1454 'maxSecurityGroups': 10, 1455 'totalFloatingIpsUsed': 0, 1456 'totalInstancesUsed': 0, 1457 'maxServerGroupMembers': 10, 1458 'maxTotalFloatingIps': 10, 1459 'totalSecurityGroupsUsed': 0, 1460 'maxTotalCores': 20, 1461 } 1462 absolute_attrs = absolute_attrs or {} 1463 self.absolute_limits_attrs.update(absolute_attrs) 1464 1465 self.rate_limits_attrs = [{ 1466 "uri": "*", 1467 "limit": [ 1468 { 1469 "value": 10, 1470 "verb": "POST", 1471 "remaining": 2, 1472 "unit": "MINUTE", 1473 "next-available": "2011-12-15T22:42:45Z" 1474 }, 1475 { 1476 "value": 10, 1477 "verb": "PUT", 1478 "remaining": 2, 1479 "unit": "MINUTE", 1480 "next-available": "2011-12-15T22:42:45Z" 1481 }, 1482 { 1483 "value": 100, 1484 "verb": "DELETE", 1485 "remaining": 100, 1486 "unit": "MINUTE", 1487 "next-available": "2011-12-15T22:42:45Z" 1488 } 1489 ] 1490 }] 1491 1492 @property 1493 def absolute(self): 1494 for (name, value) in self.absolute_limits_attrs.items(): 1495 yield FakeAbsoluteLimit(name, value) 1496 1497 def absolute_limits(self): 1498 reference_data = [] 1499 for (name, value) in self.absolute_limits_attrs.items(): 1500 reference_data.append((name, value)) 1501 return reference_data 1502 1503 @property 1504 def rate(self): 1505 for group in self.rate_limits_attrs: 1506 uri = group['uri'] 1507 for rate in group['limit']: 1508 yield FakeRateLimit(rate['verb'], uri, rate['value'], 1509 rate['remaining'], rate['unit'], 1510 rate['next-available']) 1511 1512 def rate_limits(self): 1513 reference_data = [] 1514 for group in self.rate_limits_attrs: 1515 uri = group['uri'] 1516 for rate in group['limit']: 1517 reference_data.append((rate['verb'], uri, rate['value'], 1518 rate['remaining'], rate['unit'], 1519 rate['next-available'])) 1520 return reference_data 1521 1522 1523class FakeAbsoluteLimit(object): 1524 """Data model that represents an absolute limit""" 1525 1526 def __init__(self, name, value): 1527 self.name = name 1528 self.value = value 1529 1530 1531class FakeRateLimit(object): 1532 """Data model that represents a flattened view of a single rate limit""" 1533 1534 def __init__(self, verb, uri, value, remain, 1535 unit, next_available): 1536 self.verb = verb 1537 self.uri = uri 1538 self.value = value 1539 self.remain = remain 1540 self.unit = unit 1541 self.next_available = next_available 1542