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 17import datetime 18from unittest import mock 19import uuid 20 21from keystoneauth1 import access 22from keystoneauth1 import fixture 23from osc_lib.cli import format_columns 24 25from openstackclient.tests.unit import fakes 26from openstackclient.tests.unit import utils 27 28base_url = 'http://identity:5000/v3/' 29 30domain_id = 'd1' 31domain_name = 'oftheking' 32domain_description = 'domain description' 33 34DOMAIN = { 35 'id': domain_id, 36 'name': domain_name, 37 'description': domain_description, 38 'enabled': True, 39 'tags': [], 40 'links': base_url + 'domains/' + domain_id, 41} 42 43group_id = 'gr-010' 44group_name = 'spencer davis' 45 46GROUP = { 47 'id': group_id, 48 'name': group_name, 49 'links': base_url + 'groups/' + group_id, 50} 51 52mapping_id = 'test_mapping' 53mapping_rules_file_path = '/tmp/path/to/file' 54# Copied from 55# (https://github.com/openstack/keystone/blob\ 56# master/keystone/tests/mapping_fixtures.py 57EMPLOYEE_GROUP_ID = "0cd5e9" 58DEVELOPER_GROUP_ID = "xyz" 59MAPPING_RULES = [ 60 { 61 "local": [ 62 { 63 "group": { 64 "id": EMPLOYEE_GROUP_ID 65 } 66 } 67 ], 68 "remote": [ 69 { 70 "type": "orgPersonType", 71 "not_any_of": [ 72 "Contractor", 73 "Guest" 74 ] 75 } 76 ] 77 } 78] 79 80MAPPING_RULES_2 = [ 81 { 82 "local": [ 83 { 84 "group": { 85 "id": DEVELOPER_GROUP_ID 86 } 87 } 88 ], 89 "remote": [ 90 { 91 "type": "orgPersonType", 92 "any_one_of": [ 93 "Contractor" 94 ] 95 } 96 ] 97 } 98] 99 100 101MAPPING_RESPONSE = { 102 "id": mapping_id, 103 "rules": MAPPING_RULES 104} 105 106MAPPING_RESPONSE_2 = { 107 "id": mapping_id, 108 "rules": MAPPING_RULES_2 109} 110 111project_id = '8-9-64' 112project_name = 'beatles' 113project_description = 'Fab Four' 114 115PROJECT = { 116 'id': project_id, 117 'name': project_name, 118 'description': project_description, 119 'enabled': True, 120 'domain_id': domain_id, 121 'tags': [], 122 'links': base_url + 'projects/' + project_id, 123} 124 125PROJECT_2 = { 126 'id': project_id + '-2222', 127 'name': project_name + ' reprise', 128 'description': project_description + 'plus four more', 129 'enabled': True, 130 'domain_id': domain_id, 131 'tags': [], 132 'links': base_url + 'projects/' + project_id, 133} 134 135region_id = 'region_one' 136region_parent_region_id = 'region_two' 137region_description = 'region one' 138 139REGION = { 140 'id': region_id, 141 'description': region_description, 142 'parent_region_id': region_parent_region_id, 143 'links': base_url + 'regions/' + region_id, 144} 145 146PROJECT_WITH_PARENT = { 147 'id': project_id + '-with-parent', 148 'name': project_name + ' and their parents', 149 'description': project_description + ' plus another four', 150 'enabled': True, 151 'domain_id': domain_id, 152 'parent_id': project_id, 153 'tags': [], 154 'links': base_url + 'projects/' + (project_id + '-with-parent'), 155} 156 157PROJECT_WITH_GRANDPARENT = { 158 'id': project_id + '-with-grandparent', 159 'name': project_name + ', granny and grandpa', 160 'description': project_description + ' plus another eight?', 161 'enabled': True, 162 'domain_id': domain_id, 163 'parent_id': PROJECT_WITH_PARENT['id'], 164 'tags': [], 165 'links': base_url + 'projects/' + (project_id + '-with-grandparent'), 166} 167 168parents = [{'project': PROJECT}] 169grandparents = [{'project': PROJECT}, {'project': PROJECT_WITH_PARENT}] 170ids_for_parents = [PROJECT['id']] 171ids_for_parents_and_grandparents = [PROJECT['id'], PROJECT_WITH_PARENT['id']] 172 173children = [{'project': PROJECT_WITH_GRANDPARENT}] 174ids_for_children = [PROJECT_WITH_GRANDPARENT['id']] 175 176 177role_id = 'r1' 178role_name = 'roller' 179role_description = 'role description' 180 181ROLE = { 182 'id': role_id, 183 'name': role_name, 184 'domain': None, 185 'links': base_url + 'roles/' + role_id, 186} 187 188ROLE_2 = { 189 'id': 'r2', 190 'name': 'Rolls Royce', 191 'domain': domain_id, 192 'links': base_url + 'roles/' + 'r2', 193} 194 195ROLES = [ROLE, ROLE_2] 196 197service_id = 's-123' 198service_name = 'Texaco' 199service_type = 'gas' 200service_description = 'oil brand' 201 202SERVICE = { 203 'id': service_id, 204 'name': service_name, 205 'type': service_type, 206 'description': service_description, 207 'enabled': True, 208 'links': base_url + 'services/' + service_id, 209} 210 211SERVICE_WITHOUT_NAME = { 212 'id': service_id, 213 'type': service_type, 214 'description': service_description, 215 'enabled': True, 216 'links': base_url + 'services/' + service_id, 217} 218 219endpoint_id = 'e-123' 220endpoint_url = 'http://127.0.0.1:35357' 221endpoint_region = 'RegionOne' 222endpoint_interface = 'admin' 223 224ENDPOINT = { 225 'id': endpoint_id, 226 'url': endpoint_url, 227 'region': endpoint_region, 228 'interface': endpoint_interface, 229 'service_id': service_id, 230 'enabled': True, 231 'links': base_url + 'endpoints/' + endpoint_id, 232} 233 234endpoint_group_id = 'eg-123' 235endpoint_group_description = 'eg 123 description' 236endpoint_group_filters = { 237 'service_id': service_id, 238 'region_id': endpoint_region, 239} 240endpoint_group_filters_2 = { 241 'region_id': endpoint_region, 242} 243endpoint_group_file_path = '/tmp/path/to/file' 244 245ENDPOINT_GROUP = { 246 'id': endpoint_group_id, 247 'filters': endpoint_group_filters, 248 'description': endpoint_group_description, 249 'links': base_url + 'endpoint_groups/' + endpoint_group_id, 250} 251 252user_id = 'bbbbbbb-aaaa-aaaa-aaaa-bbbbbbbaaaa' 253user_name = 'paul' 254user_description = 'Sir Paul' 255user_email = 'paul@applecorps.com' 256 257USER = { 258 'id': user_id, 259 'name': user_name, 260 'default_project_id': project_id, 261 'email': user_email, 262 'enabled': True, 263 'domain_id': domain_id, 264 'links': base_url + 'users/' + user_id, 265} 266 267trust_id = 't-456' 268trust_expires = None 269trust_impersonation = False 270trust_roles = {"id": role_id, "name": role_name}, 271 272TRUST = { 273 'expires_at': trust_expires, 274 'id': trust_id, 275 'impersonation': trust_impersonation, 276 'links': base_url + 'trusts/' + trust_id, 277 'project_id': project_id, 278 'roles': trust_roles, 279 'trustee_user_id': user_id, 280 'trustor_user_id': user_id, 281} 282 283token_expires = '2016-09-05T18:04:52+0000' 284token_id = 'tttttttt-tttt-tttt-tttt-tttttttttttt' 285 286UNSCOPED_TOKEN = { 287 'expires': token_expires, 288 'id': token_id, 289 'user_id': user_id, 290} 291 292TOKEN_WITH_PROJECT_ID = { 293 'expires': token_expires, 294 'id': token_id, 295 'project_id': project_id, 296 'user_id': user_id, 297} 298 299TOKEN_WITH_DOMAIN_ID = { 300 'expires': token_expires, 301 'id': token_id, 302 'domain_id': domain_id, 303 'user_id': user_id, 304} 305 306idp_id = 'test_idp' 307idp_description = 'super exciting IdP description' 308idp_remote_ids = ['entity1', 'entity2'] 309formatted_idp_remote_ids = format_columns.ListColumn(idp_remote_ids) 310 311IDENTITY_PROVIDER = { 312 'id': idp_id, 313 'remote_ids': idp_remote_ids, 314 'enabled': True, 315 'description': idp_description, 316 'domain_id': domain_id, 317} 318 319protocol_id = 'protocol' 320 321mapping_id = 'test_mapping' 322mapping_id_updated = 'prod_mapping' 323 324sp_id = 'BETA' 325sp_description = 'Service Provider to burst into' 326service_provider_url = 'https://beta.example.com/Shibboleth.sso/POST/SAML' 327sp_auth_url = ('https://beta.example.com/v3/OS-FEDERATION/identity_providers/' 328 'idp/protocol/saml2/auth') 329 330SERVICE_PROVIDER = { 331 'id': sp_id, 332 'enabled': True, 333 'description': sp_description, 334 'sp_url': service_provider_url, 335 'auth_url': sp_auth_url 336} 337 338PROTOCOL_ID_MAPPING = { 339 'id': protocol_id, 340 'mapping': mapping_id 341} 342 343PROTOCOL_OUTPUT = { 344 'id': protocol_id, 345 'mapping_id': mapping_id, 346 'identity_provider': idp_id 347} 348 349PROTOCOL_OUTPUT_UPDATED = { 350 'id': protocol_id, 351 'mapping_id': mapping_id_updated, 352 'identity_provider': idp_id 353} 354 355# Assignments 356 357ASSIGNMENT_WITH_PROJECT_ID_AND_USER_ID = { 358 'scope': {'project': {'id': project_id}}, 359 'user': {'id': user_id}, 360 'role': {'id': role_id}, 361} 362 363ASSIGNMENT_WITH_PROJECT_ID_AND_USER_ID_INCLUDE_NAMES = { 364 'scope': { 365 'project': { 366 'domain': {'id': domain_id, 367 'name': domain_name}, 368 'id': project_id, 369 'name': project_name}}, 370 'user': { 371 'domain': {'id': domain_id, 372 'name': domain_name}, 373 'id': user_id, 374 'name': user_name}, 375 'role': {'id': role_id, 376 'name': role_name}, 377} 378 379ASSIGNMENT_WITH_PROJECT_ID_AND_USER_ID_INHERITED = { 380 'scope': {'project': {'id': project_id}, 381 'OS-INHERIT:inherited_to': 'projects'}, 382 'user': {'id': user_id}, 383 'role': {'id': role_id}, 384} 385 386ASSIGNMENT_WITH_PROJECT_ID_AND_GROUP_ID = { 387 'scope': {'project': {'id': project_id}}, 388 'group': {'id': group_id}, 389 'role': {'id': role_id}, 390} 391 392ASSIGNMENT_WITH_DOMAIN_ID_AND_USER_ID = { 393 'scope': {'domain': {'id': domain_id}}, 394 'user': {'id': user_id}, 395 'role': {'id': role_id}, 396} 397 398ASSIGNMENT_WITH_DOMAIN_ROLE = { 399 'scope': {'domain': {'id': domain_id}}, 400 'user': {'id': user_id}, 401 'role': {'id': ROLE_2['id']}, 402} 403 404ASSIGNMENT_WITH_DOMAIN_ID_AND_USER_ID_INCLUDE_NAMES = { 405 'scope': { 406 'domain': {'id': domain_id, 407 'name': domain_name}}, 408 'user': { 409 'domain': {'id': domain_id, 410 'name': domain_name}, 411 'id': user_id, 412 'name': user_name}, 413 'role': {'id': role_id, 414 'name': role_name}, 415} 416 417ASSIGNMENT_WITH_DOMAIN_ID_AND_USER_ID_INHERITED = { 418 'scope': {'domain': {'id': domain_id}, 419 'OS-INHERIT:inherited_to': 'projects'}, 420 'user': {'id': user_id}, 421 'role': {'id': role_id}, 422} 423 424ASSIGNMENT_WITH_DOMAIN_ID_AND_GROUP_ID = { 425 'scope': {'domain': {'id': domain_id}}, 426 'group': {'id': group_id}, 427 'role': {'id': role_id}, 428} 429 430consumer_id = 'test consumer id' 431consumer_description = 'someone we trust' 432consumer_secret = 'test consumer secret' 433 434OAUTH_CONSUMER = { 435 'id': consumer_id, 436 'secret': consumer_secret, 437 'description': consumer_description 438} 439 440access_token_id = 'test access token id' 441access_token_secret = 'test access token secret' 442access_token_expires = '2014-05-18T03:13:18.152071Z' 443 444OAUTH_ACCESS_TOKEN = { 445 'id': access_token_id, 446 'expires': access_token_expires, 447 'key': access_token_id, 448 'secret': access_token_secret 449} 450 451request_token_id = 'test request token id' 452request_token_secret = 'test request token secret' 453request_token_expires = '2014-05-17T11:10:51.511336Z' 454 455OAUTH_REQUEST_TOKEN = { 456 'id': request_token_id, 457 'expires': request_token_expires, 458 'key': request_token_id, 459 'secret': request_token_secret 460} 461 462oauth_verifier_pin = '6d74XaDS' 463OAUTH_VERIFIER = { 464 'oauth_verifier': oauth_verifier_pin 465} 466 467app_cred_id = 'app-cred-id' 468app_cred_name = 'testing_app_cred' 469app_cred_role = {"id": role_id, "name": role_name, "domain": None}, 470app_cred_description = 'app credential for testing' 471app_cred_expires = datetime.datetime(2022, 1, 1, 0, 0) 472app_cred_expires_str = app_cred_expires.strftime('%Y-%m-%dT%H:%M:%S%z') 473app_cred_secret = 'moresecuresecret' 474app_cred_access_rules = ( 475 '[{"path": "/v2.1/servers", "method": "GET", "service": "compute"}]' 476) 477app_cred_access_rules_path = '/tmp/access_rules.json' 478access_rule_id = 'access-rule-id' 479access_rule_service = 'compute' 480access_rule_path = '/v2.1/servers' 481access_rule_method = 'GET' 482APP_CRED_BASIC = { 483 'id': app_cred_id, 484 'name': app_cred_name, 485 'project_id': project_id, 486 'roles': app_cred_role, 487 'description': None, 488 'expires_at': None, 489 'unrestricted': False, 490 'secret': app_cred_secret, 491 'access_rules': None 492} 493APP_CRED_OPTIONS = { 494 'id': app_cred_id, 495 'name': app_cred_name, 496 'project_id': project_id, 497 'roles': app_cred_role, 498 'description': app_cred_description, 499 'expires_at': app_cred_expires_str, 500 'unrestricted': False, 501 'secret': app_cred_secret, 502 'access_rules': None, 503} 504ACCESS_RULE = { 505 'id': access_rule_id, 506 'service': access_rule_service, 507 'path': access_rule_path, 508 'method': access_rule_method, 509} 510APP_CRED_ACCESS_RULES = { 511 'id': app_cred_id, 512 'name': app_cred_name, 513 'project_id': project_id, 514 'roles': app_cred_role, 515 'description': None, 516 'expires_at': None, 517 'unrestricted': False, 518 'secret': app_cred_secret, 519 'access_rules': app_cred_access_rules 520} 521 522registered_limit_id = 'registered-limit-id' 523registered_limit_default_limit = 10 524registered_limit_description = 'default limit of foobars' 525registered_limit_resource_name = 'foobars' 526REGISTERED_LIMIT = { 527 'id': registered_limit_id, 528 'default_limit': registered_limit_default_limit, 529 'resource_name': registered_limit_resource_name, 530 'service_id': service_id, 531 'description': None, 532 'region_id': None 533} 534REGISTERED_LIMIT_OPTIONS = { 535 'id': registered_limit_id, 536 'default_limit': registered_limit_default_limit, 537 'resource_name': registered_limit_resource_name, 538 'service_id': service_id, 539 'description': registered_limit_description, 540 'region_id': region_id 541} 542 543limit_id = 'limit-id' 544limit_resource_limit = 15 545limit_description = 'limit of foobars' 546limit_resource_name = 'foobars' 547LIMIT = { 548 'id': limit_id, 549 'project_id': project_id, 550 'resource_limit': limit_resource_limit, 551 'resource_name': limit_resource_name, 552 'service_id': service_id, 553 'description': None, 554 'region_id': None 555} 556LIMIT_OPTIONS = { 557 'id': limit_id, 558 'project_id': project_id, 559 'resource_limit': limit_resource_limit, 560 'resource_name': limit_resource_name, 561 'service_id': service_id, 562 'description': limit_description, 563 'region_id': region_id 564} 565 566 567def fake_auth_ref(fake_token, fake_service=None): 568 """Create an auth_ref using keystoneauth's fixtures""" 569 token_copy = copy.deepcopy(fake_token) 570 token_id = token_copy.pop('id') 571 token = fixture.V3Token(**token_copy) 572 # An auth_ref is actually an access info object 573 auth_ref = access.create( 574 body=token, 575 auth_token=token_id, 576 ) 577 578 # Create a service catalog 579 if fake_service: 580 service = token.add_service( 581 fake_service['type'], 582 fake_service['name'], 583 ) 584 # TODO(dtroyer): Add an 'id' element to KSA's _Service fixure 585 service['id'] = fake_service['id'] 586 for e in fake_service['endpoints']: 587 region = e.get('region_id') or e.get('region', '<none>') 588 service.add_endpoint( 589 e['interface'], 590 e['url'], 591 region=region, 592 ) 593 594 return auth_ref 595 596 597class FakeAuth(object): 598 599 def __init__(self, auth_method_class=None): 600 self._auth_method_class = auth_method_class 601 602 def get_token(self, *args, **kwargs): 603 return token_id 604 605 606class FakeSession(object): 607 608 def __init__(self, **kwargs): 609 self.auth = FakeAuth() 610 611 612class FakeIdentityv3Client(object): 613 614 def __init__(self, **kwargs): 615 self.domains = mock.Mock() 616 self.domains.resource_class = fakes.FakeResource(None, {}) 617 self.credentials = mock.Mock() 618 self.credentials.resource_class = fakes.FakeResource(None, {}) 619 self.endpoints = mock.Mock() 620 self.endpoints.resource_class = fakes.FakeResource(None, {}) 621 self.endpoint_filter = mock.Mock() 622 self.endpoint_filter.resource_class = fakes.FakeResource(None, {}) 623 self.endpoint_groups = mock.Mock() 624 self.endpoint_groups.resource_class = fakes.FakeResource(None, {}) 625 self.groups = mock.Mock() 626 self.groups.resource_class = fakes.FakeResource(None, {}) 627 self.oauth1 = mock.Mock() 628 self.oauth1.resource_class = fakes.FakeResource(None, {}) 629 self.projects = mock.Mock() 630 self.projects.resource_class = fakes.FakeResource(None, {}) 631 self.regions = mock.Mock() 632 self.regions.resource_class = fakes.FakeResource(None, {}) 633 self.roles = mock.Mock() 634 self.roles.resource_class = fakes.FakeResource(None, {}) 635 self.services = mock.Mock() 636 self.services.resource_class = fakes.FakeResource(None, {}) 637 self.session = mock.Mock() 638 self.session.auth.auth_ref.service_catalog.resource_class = \ 639 fakes.FakeResource(None, {}) 640 self.tokens = mock.Mock() 641 self.tokens.resource_class = fakes.FakeResource(None, {}) 642 self.trusts = mock.Mock() 643 self.trusts.resource_class = fakes.FakeResource(None, {}) 644 self.users = mock.Mock() 645 self.users.resource_class = fakes.FakeResource(None, {}) 646 self.role_assignments = mock.Mock() 647 self.role_assignments.resource_class = fakes.FakeResource(None, {}) 648 self.auth_token = kwargs['token'] 649 self.management_url = kwargs['endpoint'] 650 self.auth = FakeAuth() 651 self.auth.client = mock.Mock() 652 self.auth.client.resource_class = fakes.FakeResource(None, {}) 653 self.application_credentials = mock.Mock() 654 self.application_credentials.resource_class = fakes.FakeResource(None, 655 {}) 656 self.access_rules = mock.Mock() 657 self.access_rules.resource_class = fakes.FakeResource(None, {}) 658 self.inference_rules = mock.Mock() 659 self.inference_rules.resource_class = fakes.FakeResource(None, {}) 660 self.registered_limits = mock.Mock() 661 self.registered_limits.resource_class = fakes.FakeResource(None, {}) 662 self.limits = mock.Mock() 663 self.limits.resource_class = fakes.FakeResource(None, {}) 664 665 666class FakeFederationManager(object): 667 668 def __init__(self, **kwargs): 669 self.identity_providers = mock.Mock() 670 self.identity_providers.resource_class = fakes.FakeResource(None, {}) 671 self.mappings = mock.Mock() 672 self.mappings.resource_class = fakes.FakeResource(None, {}) 673 self.protocols = mock.Mock() 674 self.protocols.resource_class = fakes.FakeResource(None, {}) 675 self.projects = mock.Mock() 676 self.projects.resource_class = fakes.FakeResource(None, {}) 677 self.domains = mock.Mock() 678 self.domains.resource_class = fakes.FakeResource(None, {}) 679 self.service_providers = mock.Mock() 680 self.service_providers.resource_class = fakes.FakeResource(None, {}) 681 682 683class FakeFederatedClient(FakeIdentityv3Client): 684 685 def __init__(self, **kwargs): 686 super(FakeFederatedClient, self).__init__(**kwargs) 687 self.federation = FakeFederationManager() 688 689 690class FakeOAuth1Client(FakeIdentityv3Client): 691 692 def __init__(self, **kwargs): 693 super(FakeOAuth1Client, self).__init__(**kwargs) 694 695 self.access_tokens = mock.Mock() 696 self.access_tokens.resource_class = fakes.FakeResource(None, {}) 697 self.consumers = mock.Mock() 698 self.consumers.resource_class = fakes.FakeResource(None, {}) 699 self.request_tokens = mock.Mock() 700 self.request_tokens.resource_class = fakes.FakeResource(None, {}) 701 702 703class TestIdentityv3(utils.TestCommand): 704 705 def setUp(self): 706 super(TestIdentityv3, self).setUp() 707 708 self.app.client_manager.identity = FakeIdentityv3Client( 709 endpoint=fakes.AUTH_URL, 710 token=fakes.AUTH_TOKEN, 711 ) 712 713 714class TestFederatedIdentity(utils.TestCommand): 715 716 def setUp(self): 717 super(TestFederatedIdentity, self).setUp() 718 719 self.app.client_manager.identity = FakeFederatedClient( 720 endpoint=fakes.AUTH_URL, 721 token=fakes.AUTH_TOKEN 722 ) 723 724 725class TestOAuth1(utils.TestCommand): 726 727 def setUp(self): 728 super(TestOAuth1, self).setUp() 729 730 self.app.client_manager.identity = FakeOAuth1Client( 731 endpoint=fakes.AUTH_URL, 732 token=fakes.AUTH_TOKEN 733 ) 734 735 736class FakeProject(object): 737 """Fake one or more project.""" 738 739 @staticmethod 740 def create_one_project(attrs=None): 741 """Create a fake project. 742 743 :param Dictionary attrs: 744 A dictionary with all attributes 745 :return: 746 A FakeResource object, with id, name, and so on 747 """ 748 749 attrs = attrs or {} 750 751 # set default attributes. 752 project_info = { 753 'id': 'project-id-' + uuid.uuid4().hex, 754 'name': 'project-name-' + uuid.uuid4().hex, 755 'description': 'project-description-' + uuid.uuid4().hex, 756 'enabled': True, 757 'is_domain': False, 758 'domain_id': 'domain-id-' + uuid.uuid4().hex, 759 'parent_id': 'parent-id-' + uuid.uuid4().hex, 760 'tags': [], 761 'links': 'links-' + uuid.uuid4().hex, 762 } 763 project_info.update(attrs) 764 765 project = fakes.FakeResource(info=copy.deepcopy(project_info), 766 loaded=True) 767 return project 768 769 @staticmethod 770 def create_projects(attrs=None, count=2): 771 """Create multiple fake projects. 772 773 :param Dictionary attrs: 774 A dictionary with all attributes 775 :param int count: 776 The number of projects to fake 777 :return: 778 A list of FakeResource objects faking the projects 779 """ 780 781 projects = [] 782 for i in range(0, count): 783 projects.append(FakeProject.create_one_project(attrs)) 784 return projects 785 786 787class FakeDomain(object): 788 """Fake one or more domain.""" 789 790 @staticmethod 791 def create_one_domain(attrs=None): 792 """Create a fake domain. 793 794 :param Dictionary attrs: 795 A dictionary with all attributes 796 :return: 797 A FakeResource object, with id, name, and so on 798 """ 799 800 attrs = attrs or {} 801 802 # set default attributes. 803 domain_info = { 804 'id': 'domain-id-' + uuid.uuid4().hex, 805 'name': 'domain-name-' + uuid.uuid4().hex, 806 'description': 'domain-description-' + uuid.uuid4().hex, 807 'enabled': True, 808 'tags': [], 809 'links': 'links-' + uuid.uuid4().hex, 810 } 811 domain_info.update(attrs) 812 813 domain = fakes.FakeResource(info=copy.deepcopy(domain_info), 814 loaded=True) 815 return domain 816 817 818class FakeCredential(object): 819 """Fake one or more credential.""" 820 821 @staticmethod 822 def create_one_credential(attrs=None): 823 """Create a fake credential. 824 825 :param Dictionary attrs: 826 A dictionary with all attributes 827 :return: 828 A FakeResource object, with id, type, and so on 829 """ 830 831 attrs = attrs or {} 832 833 # set default attributes. 834 credential_info = { 835 'id': 'credential-id-' + uuid.uuid4().hex, 836 'type': 'cert', 837 'user_id': 'user-id-' + uuid.uuid4().hex, 838 'blob': 'credential-data-' + uuid.uuid4().hex, 839 'project_id': 'project-id-' + uuid.uuid4().hex, 840 'links': 'links-' + uuid.uuid4().hex, 841 } 842 credential_info.update(attrs) 843 844 credential = fakes.FakeResource( 845 info=copy.deepcopy(credential_info), loaded=True) 846 return credential 847 848 @staticmethod 849 def create_credentials(attrs=None, count=2): 850 """Create multiple fake credentials. 851 852 :param Dictionary attrs: 853 A dictionary with all attributes 854 :param int count: 855 The number of credentials to fake 856 :return: 857 A list of FakeResource objects faking the credentials 858 """ 859 credentials = [] 860 for i in range(0, count): 861 credential = FakeCredential.create_one_credential(attrs) 862 credentials.append(credential) 863 864 return credentials 865 866 @staticmethod 867 def get_credentials(credentials=None, count=2): 868 """Get an iterable MagicMock object with a list of faked credentials. 869 870 If credentials list is provided, then initialize the Mock object with 871 the list. Otherwise create one. 872 873 :param List credentials: 874 A list of FakeResource objects faking credentials 875 :param Integer count: 876 The number of credentials to be faked 877 :return: 878 An iterable Mock object with side_effect set to a list of faked 879 credentials 880 """ 881 if credentials is None: 882 credentials = FakeCredential.create_credentials(count) 883 884 return mock.Mock(side_effect=credentials) 885 886 887class FakeUser(object): 888 """Fake one or more user.""" 889 890 @staticmethod 891 def create_one_user(attrs=None): 892 """Create a fake user. 893 894 :param Dictionary attrs: 895 A dictionary with all attributes 896 :return: 897 A FakeResource object, with id, name, and so on 898 """ 899 900 attrs = attrs or {} 901 902 # set default attributes. 903 user_info = { 904 'id': 'user-id-' + uuid.uuid4().hex, 905 'name': 'user-name-' + uuid.uuid4().hex, 906 'default_project_id': 'project-' + uuid.uuid4().hex, 907 'email': 'user-email-' + uuid.uuid4().hex, 908 'enabled': True, 909 'domain_id': 'domain-id-' + uuid.uuid4().hex, 910 'links': 'links-' + uuid.uuid4().hex, 911 } 912 user_info.update(attrs) 913 914 user = fakes.FakeResource(info=copy.deepcopy(user_info), 915 loaded=True) 916 return user 917 918 @staticmethod 919 def create_users(attrs=None, count=2): 920 """Create multiple fake users. 921 922 :param Dictionary attrs: 923 A dictionary with all attributes 924 :param int count: 925 The number of users to fake 926 :return: 927 A list of FakeResource objects faking the users 928 """ 929 users = [] 930 for i in range(0, count): 931 user = FakeUser.create_one_user(attrs) 932 users.append(user) 933 934 return users 935 936 @staticmethod 937 def get_users(users=None, count=2): 938 """Get an iterable MagicMock object with a list of faked users. 939 940 If users list is provided, then initialize the Mock object with 941 the list. Otherwise create one. 942 943 :param List users: 944 A list of FakeResource objects faking users 945 :param Integer count: 946 The number of users to be faked 947 :return 948 An iterable Mock object with side_effect set to a list of faked 949 users 950 """ 951 if users is None: 952 users = FakeUser.create_users(count) 953 954 return mock.Mock(side_effect=users) 955 956 957class FakeGroup(object): 958 """Fake one or more group.""" 959 960 @staticmethod 961 def create_one_group(attrs=None): 962 """Create a fake group. 963 964 :param Dictionary attrs: 965 A dictionary with all attributes 966 :return: 967 A FakeResource object, with id, name, and so on 968 """ 969 970 attrs = attrs or {} 971 972 # set default attributes. 973 group_info = { 974 'id': 'group-id-' + uuid.uuid4().hex, 975 'name': 'group-name-' + uuid.uuid4().hex, 976 'links': 'links-' + uuid.uuid4().hex, 977 'domain_id': 'domain-id-' + uuid.uuid4().hex, 978 'description': 'group-description-' + uuid.uuid4().hex, 979 } 980 group_info.update(attrs) 981 982 group = fakes.FakeResource(info=copy.deepcopy(group_info), 983 loaded=True) 984 return group 985 986 @staticmethod 987 def create_groups(attrs=None, count=2): 988 """Create multiple fake groups. 989 990 :param Dictionary attrs: 991 A dictionary with all attributes 992 :param int count: 993 The number of groups to fake 994 :return: 995 A list of FakeResource objects faking the groups 996 """ 997 groups = [] 998 for i in range(0, count): 999 group = FakeGroup.create_one_group(attrs) 1000 groups.append(group) 1001 1002 return groups 1003 1004 @staticmethod 1005 def get_groups(groups=None, count=2): 1006 """Get an iterable MagicMock object with a list of faked groups. 1007 1008 If groups list is provided, then initialize the Mock object with 1009 the list. Otherwise create one. 1010 1011 :param List groups: 1012 A list of FakeResource objects faking groups 1013 :param Integer count: 1014 The number of groups to be faked 1015 :return: 1016 An iterable Mock object with side_effect set to a list of faked 1017 groups 1018 """ 1019 if groups is None: 1020 groups = FakeGroup.create_groups(count) 1021 1022 return mock.Mock(side_effect=groups) 1023 1024 1025class FakeEndpoint(object): 1026 """Fake one or more endpoint.""" 1027 1028 @staticmethod 1029 def create_one_endpoint(attrs=None): 1030 """Create a fake endpoint. 1031 1032 :param Dictionary attrs: 1033 A dictionary with all attributes 1034 :return: 1035 A FakeResource object, with id, url, and so on 1036 """ 1037 1038 attrs = attrs or {} 1039 1040 # set default attributes. 1041 endpoint_info = { 1042 'id': 'endpoint-id-' + uuid.uuid4().hex, 1043 'url': 'url-' + uuid.uuid4().hex, 1044 'region': 'endpoint-region-' + uuid.uuid4().hex, 1045 'interface': 'admin', 1046 'service_id': 'service-id-' + uuid.uuid4().hex, 1047 'enabled': True, 1048 'links': 'links-' + uuid.uuid4().hex, 1049 } 1050 endpoint_info.update(attrs) 1051 1052 endpoint = fakes.FakeResource(info=copy.deepcopy(endpoint_info), 1053 loaded=True) 1054 return endpoint 1055 1056 @staticmethod 1057 def create_one_endpoint_filter(attrs=None): 1058 """Create a fake endpoint project relationship. 1059 1060 :param Dictionary attrs: 1061 A dictionary with all attributes of endpoint filter 1062 :return: 1063 A FakeResource object with project, endpoint and so on 1064 """ 1065 attrs = attrs or {} 1066 1067 # Set default attribute 1068 endpoint_filter_info = { 1069 'project': 'project-id-' + uuid.uuid4().hex, 1070 'endpoint': 'endpoint-id-' + uuid.uuid4().hex, 1071 } 1072 1073 # Overwrite default attributes if there are some attributes set 1074 endpoint_filter_info.update(attrs) 1075 1076 endpoint_filter = fakes.FakeModel( 1077 copy.deepcopy(endpoint_filter_info)) 1078 1079 return endpoint_filter 1080 1081 1082class FakeEndpointGroup(object): 1083 """Fake one or more endpoint group.""" 1084 1085 @staticmethod 1086 def create_one_endpointgroup(attrs=None): 1087 """Create a fake endpoint group. 1088 1089 :param Dictionary attrs: 1090 A dictionary with all attributes 1091 :return: 1092 A FakeResource object, with id, url, and so on 1093 """ 1094 1095 attrs = attrs or {} 1096 1097 # set default attributes. 1098 endpointgroup_info = { 1099 'id': 'endpoint-group-id-' + uuid.uuid4().hex, 1100 'name': 'endpoint-group-name-' + uuid.uuid4().hex, 1101 'filters': { 1102 'region': 'region-' + uuid.uuid4().hex, 1103 'service_id': 'service-id-' + uuid.uuid4().hex, 1104 }, 1105 'description': 'endpoint-group-description-' + uuid.uuid4().hex, 1106 'links': 'links-' + uuid.uuid4().hex, 1107 } 1108 endpointgroup_info.update(attrs) 1109 1110 endpoint = fakes.FakeResource(info=copy.deepcopy(endpointgroup_info), 1111 loaded=True) 1112 return endpoint 1113 1114 @staticmethod 1115 def create_one_endpointgroup_filter(attrs=None): 1116 """Create a fake endpoint project relationship. 1117 1118 :param Dictionary attrs: 1119 A dictionary with all attributes of endpointgroup filter 1120 :return: 1121 A FakeResource object with project, endpointgroup and so on 1122 """ 1123 attrs = attrs or {} 1124 1125 # Set default attribute 1126 endpointgroup_filter_info = { 1127 'project': 'project-id-' + uuid.uuid4().hex, 1128 'endpointgroup': 'endpointgroup-id-' + uuid.uuid4().hex, 1129 } 1130 1131 # Overwrite default attributes if there are some attributes set 1132 endpointgroup_filter_info.update(attrs) 1133 1134 endpointgroup_filter = fakes.FakeModel( 1135 copy.deepcopy(endpointgroup_filter_info)) 1136 1137 return endpointgroup_filter 1138 1139 1140class FakeService(object): 1141 """Fake one or more service.""" 1142 1143 @staticmethod 1144 def create_one_service(attrs=None): 1145 """Create a fake service. 1146 1147 :param Dictionary attrs: 1148 A dictionary with all attributes 1149 :return: 1150 A FakeResource object, with id, name, and so on 1151 """ 1152 1153 attrs = attrs or {} 1154 1155 # set default attributes. 1156 service_info = { 1157 'id': 'service-id-' + uuid.uuid4().hex, 1158 'name': 'service-name-' + uuid.uuid4().hex, 1159 'type': 'service-type-' + uuid.uuid4().hex, 1160 'description': 'service-description-' + uuid.uuid4().hex, 1161 'enabled': True, 1162 'links': 'links-' + uuid.uuid4().hex, 1163 } 1164 service_info.update(attrs) 1165 1166 service = fakes.FakeResource(info=copy.deepcopy(service_info), 1167 loaded=True) 1168 return service 1169 1170 1171class FakeRoleAssignment(object): 1172 """Fake one or more role assignment.""" 1173 1174 @staticmethod 1175 def create_one_role_assignment(attrs=None): 1176 """Create a fake role assignment. 1177 1178 :param Dictionary attrs: 1179 A dictionary with all attributes 1180 :return: 1181 A FakeResource object, with scope, user, and so on 1182 """ 1183 1184 attrs = attrs or {} 1185 1186 # set default attributes. 1187 role_assignment_info = { 1188 'scope': {'project': {'id': 'project-id-' + uuid.uuid4().hex}}, 1189 'user': {'id': 'user-id-' + uuid.uuid4().hex}, 1190 'role': {'id': 'role-id-' + uuid.uuid4().hex}, 1191 } 1192 role_assignment_info.update(attrs) 1193 1194 role_assignment = fakes.FakeResource( 1195 info=copy.deepcopy(role_assignment_info), loaded=True) 1196 1197 return role_assignment 1198 1199 1200class FakeImpliedRoleResponse(object): 1201 """Fake one or more role assignment.""" 1202 def __init__(self, prior_role, implied_roles): 1203 self.prior_role = prior_role 1204 self.implies = [role for role in implied_roles] 1205 1206 @staticmethod 1207 def create_list(): 1208 """Create a fake implied role list response. 1209 1210 :return: 1211 A list of FakeImpliedRoleResponse objects 1212 """ 1213 1214 # set default attributes. 1215 implied_roles = [ 1216 FakeImpliedRoleResponse(ROLES[0], [ROLES[1]]) 1217 ] 1218 1219 return implied_roles 1220