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.V 12 13""" 14fakes 15---------------------------------- 16 17Fakes used for testing 18""" 19 20import datetime 21import hashlib 22import json 23import uuid 24 25from openstack.cloud import meta 26from openstack.orchestration.util import template_format 27from openstack import utils 28 29PROJECT_ID = '1c36b64c840a42cd9e9b931a369337f0' 30FLAVOR_ID = u'0c1d9008-f546-4608-9e8f-f8bdaec8dddd' 31CHOCOLATE_FLAVOR_ID = u'0c1d9008-f546-4608-9e8f-f8bdaec8ddde' 32STRAWBERRY_FLAVOR_ID = u'0c1d9008-f546-4608-9e8f-f8bdaec8dddf' 33COMPUTE_ENDPOINT = 'https://compute.example.com/v2.1' 34ORCHESTRATION_ENDPOINT = 'https://orchestration.example.com/v1/{p}'.format( 35 p=PROJECT_ID) 36NO_MD5 = '93b885adfe0da089cdf634904fd59f71' 37NO_SHA256 = '6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d' 38FAKE_PUBLIC_KEY = ( 39 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCkF3MX59OrlBs3dH5CU7lNmvpbrgZxSpyGj" 40 "lnE8Flkirnc/Up22lpjznoxqeoTAwTW034k7Dz6aYIrZGmQwe2TkE084yqvlj45Dkyoj95fW/" 41 "sZacm0cZNuL69EObEGHdprfGJQajrpz22NQoCD8TFB8Wv+8om9NH9Le6s+WPe98WC77KLw8qg" 42 "fQsbIey+JawPWl4O67ZdL5xrypuRjfIPWjgy/VH85IXg/Z/GONZ2nxHgSShMkwqSFECAC5L3P" 43 "HB+0+/12M/iikdatFSVGjpuHvkLOs3oe7m6HlOfluSJ85BzLWBbvva93qkGmLg4ZAc8rPh2O+" 44 "YIsBUHNLLMM/oQp Generated-by-Nova\n") 45 46 47def make_fake_flavor(flavor_id, name, ram=100, disk=1600, vcpus=24): 48 return { 49 u'OS-FLV-DISABLED:disabled': False, 50 u'OS-FLV-EXT-DATA:ephemeral': 0, 51 u'disk': disk, 52 u'id': flavor_id, 53 u'links': [{ 54 u'href': u'{endpoint}/flavors/{id}'.format( 55 endpoint=COMPUTE_ENDPOINT, id=flavor_id), 56 u'rel': u'self' 57 }, { 58 u'href': u'{endpoint}/flavors/{id}'.format( 59 endpoint=COMPUTE_ENDPOINT, id=flavor_id), 60 u'rel': u'bookmark' 61 }], 62 u'name': name, 63 u'os-flavor-access:is_public': True, 64 u'ram': ram, 65 u'rxtx_factor': 1.0, 66 u'swap': u'', 67 u'vcpus': vcpus 68 } 69 70 71FAKE_FLAVOR = make_fake_flavor(FLAVOR_ID, 'vanilla') 72FAKE_CHOCOLATE_FLAVOR = make_fake_flavor( 73 CHOCOLATE_FLAVOR_ID, 'chocolate', ram=200) 74FAKE_STRAWBERRY_FLAVOR = make_fake_flavor( 75 STRAWBERRY_FLAVOR_ID, 'strawberry', ram=300) 76FAKE_FLAVOR_LIST = [FAKE_FLAVOR, FAKE_CHOCOLATE_FLAVOR, FAKE_STRAWBERRY_FLAVOR] 77FAKE_TEMPLATE = '''heat_template_version: 2014-10-16 78 79parameters: 80 length: 81 type: number 82 default: 10 83 84resources: 85 my_rand: 86 type: OS::Heat::RandomString 87 properties: 88 length: {get_param: length} 89outputs: 90 rand: 91 value: 92 get_attr: [my_rand, value] 93''' 94FAKE_TEMPLATE_CONTENT = template_format.parse(FAKE_TEMPLATE) 95 96 97def make_fake_server( 98 server_id, name, status='ACTIVE', admin_pass=None, 99 addresses=None, image=None, flavor=None): 100 if addresses is None: 101 if status == 'ACTIVE': 102 addresses = { 103 "private": [ 104 { 105 "OS-EXT-IPS-MAC:mac_addr": "fa:16:3e:df:b0:8d", 106 "version": 6, 107 "addr": "fddb:b018:307:0:f816:3eff:fedf:b08d", 108 "OS-EXT-IPS:type": "fixed"}, 109 { 110 "OS-EXT-IPS-MAC:mac_addr": "fa:16:3e:df:b0:8d", 111 "version": 4, 112 "addr": "10.1.0.9", 113 "OS-EXT-IPS:type": "fixed"}, 114 { 115 "OS-EXT-IPS-MAC:mac_addr": "fa:16:3e:df:b0:8d", 116 "version": 4, 117 "addr": "172.24.5.5", 118 "OS-EXT-IPS:type": "floating"}]} 119 else: 120 addresses = {} 121 if image is None: 122 image = {"id": "217f3ab1-03e0-4450-bf27-63d52b421e9e", 123 "links": []} 124 if flavor is None: 125 flavor = {"id": "64", 126 "links": []} 127 128 server = { 129 "OS-EXT-STS:task_state": None, 130 "addresses": addresses, 131 "links": [], 132 "image": image, 133 "OS-EXT-STS:vm_state": "active", 134 "OS-SRV-USG:launched_at": "2017-03-23T23:57:38.000000", 135 "flavor": flavor, 136 "id": server_id, 137 "security_groups": [{"name": "default"}], 138 "user_id": "9c119f4beaaa438792ce89387362b3ad", 139 "OS-DCF:diskConfig": "MANUAL", 140 "accessIPv4": "", 141 "accessIPv6": "", 142 "progress": 0, 143 "OS-EXT-STS:power_state": 1, 144 "OS-EXT-AZ:availability_zone": "nova", 145 "metadata": {}, 146 "status": status, 147 "updated": "2017-03-23T23:57:39Z", 148 "hostId": "89d165f04384e3ffa4b6536669eb49104d30d6ca832bba2684605dbc", 149 "OS-SRV-USG:terminated_at": None, 150 "key_name": None, 151 "name": name, 152 "created": "2017-03-23T23:57:12Z", 153 "tenant_id": PROJECT_ID, 154 "os-extended-volumes:volumes_attached": [], 155 "config_drive": "True"} 156 if admin_pass: 157 server['adminPass'] = admin_pass 158 return json.loads(json.dumps(server)) 159 160 161def make_fake_keypair(name): 162 # Note: this is literally taken from: 163 # https://docs.openstack.org/api-ref/compute/ 164 return { 165 "fingerprint": "7e:eb:ab:24:ba:d1:e1:88:ae:9a:fb:66:53:df:d3:bd", 166 "name": name, 167 "type": "ssh", 168 "public_key": FAKE_PUBLIC_KEY, 169 "created_at": datetime.datetime.now().isoformat(), 170 } 171 172 173def make_fake_stack(id, name, description=None, status='CREATE_COMPLETE'): 174 return { 175 'creation_time': '2017-03-23T23:57:12Z', 176 'deletion_time': '2017-03-23T23:57:12Z', 177 'description': description, 178 'id': id, 179 'links': [], 180 'parent': None, 181 'stack_name': name, 182 'stack_owner': None, 183 'stack_status': status, 184 'stack_user_project_id': PROJECT_ID, 185 'tags': None, 186 'updated_time': '2017-03-23T23:57:12Z', 187 } 188 189 190def make_fake_stack_event( 191 id, name, status='CREATE_COMPLETED', resource_name='id'): 192 event_id = uuid.uuid4().hex 193 self_url = "{endpoint}/stacks/{name}/{id}/resources/{name}/events/{event}" 194 resource_url = "{endpoint}/stacks/{name}/{id}/resources/{name}" 195 return { 196 "resource_name": id if resource_name == 'id' else name, 197 "event_time": "2017-03-26T19:38:18", 198 "links": [ 199 { 200 "href": self_url.format( 201 endpoint=ORCHESTRATION_ENDPOINT, 202 name=name, id=id, event=event_id), 203 "rel": "self" 204 }, { 205 "href": resource_url.format( 206 endpoint=ORCHESTRATION_ENDPOINT, 207 name=name, id=id), 208 "rel": "resource" 209 }, { 210 "href": "{endpoint}/stacks/{name}/{id}".format( 211 endpoint=ORCHESTRATION_ENDPOINT, 212 name=name, id=id), 213 "rel": "stack" 214 }], 215 "logical_resource_id": name, 216 "resource_status": status, 217 "resource_status_reason": "", 218 "physical_resource_id": id, 219 "id": event_id, 220 } 221 222 223def make_fake_image( 224 image_id=None, md5=NO_MD5, sha256=NO_SHA256, status='active', 225 image_name=u'fake_image', 226 data=None, 227 checksum=u'ee36e35a297980dee1b514de9803ec6d'): 228 if data: 229 md5 = utils.md5(usedforsecurity=False) 230 sha256 = hashlib.sha256() 231 with open(data, 'rb') as file_obj: 232 for chunk in iter(lambda: file_obj.read(8192), b''): 233 md5.update(chunk) 234 sha256.update(chunk) 235 md5 = md5.hexdigest() 236 sha256 = sha256.hexdigest() 237 return { 238 u'image_state': u'available', 239 u'container_format': u'bare', 240 u'min_ram': 0, 241 u'ramdisk_id': 'fake_ramdisk_id', 242 u'updated_at': u'2016-02-10T05:05:02Z', 243 u'file': '/v2/images/' + image_id + '/file', 244 u'size': 3402170368, 245 u'image_type': u'snapshot', 246 u'disk_format': u'qcow2', 247 u'id': image_id, 248 u'schema': u'/v2/schemas/image', 249 u'status': status, 250 u'tags': [], 251 u'visibility': u'private', 252 u'locations': [{ 253 u'url': u'http://127.0.0.1/images/' + image_id, 254 u'metadata': {}}], 255 u'min_disk': 40, 256 u'virtual_size': None, 257 u'name': image_name, 258 u'checksum': md5 or checksum, 259 u'created_at': u'2016-02-10T05:03:11Z', 260 u'owner_specified.openstack.md5': md5 or NO_MD5, 261 u'owner_specified.openstack.sha256': sha256 or NO_SHA256, 262 u'owner_specified.openstack.object': 'images/{name}'.format( 263 name=image_name), 264 u'protected': False} 265 266 267def make_fake_machine(machine_name, machine_id=None): 268 if not machine_id: 269 machine_id = uuid.uuid4().hex 270 return meta.obj_to_munch(FakeMachine( 271 id=machine_id, 272 name=machine_name)) 273 274 275def make_fake_port(address, node_id=None, port_id=None): 276 if not node_id: 277 node_id = uuid.uuid4().hex 278 if not port_id: 279 port_id = uuid.uuid4().hex 280 return meta.obj_to_munch(FakeMachinePort( 281 id=port_id, 282 address=address, 283 node_id=node_id)) 284 285 286class FakeFloatingIP: 287 def __init__(self, id, pool, ip, fixed_ip, instance_id): 288 self.id = id 289 self.pool = pool 290 self.ip = ip 291 self.fixed_ip = fixed_ip 292 self.instance_id = instance_id 293 294 295def make_fake_server_group(id, name, policies): 296 return json.loads(json.dumps({ 297 'id': id, 298 'name': name, 299 'policies': policies, 300 'members': [], 301 'metadata': {}, 302 })) 303 304 305def make_fake_hypervisor(id, name): 306 return json.loads(json.dumps({ 307 'id': id, 308 'hypervisor_hostname': name, 309 'state': 'up', 310 'status': 'enabled', 311 "cpu_info": { 312 "arch": "x86_64", 313 "model": "Nehalem", 314 "vendor": "Intel", 315 "features": [ 316 "pge", 317 "clflush" 318 ], 319 "topology": { 320 "cores": 1, 321 "threads": 1, 322 "sockets": 4 323 } 324 }, 325 "current_workload": 0, 326 "status": "enabled", 327 "state": "up", 328 "disk_available_least": 0, 329 "host_ip": "1.1.1.1", 330 "free_disk_gb": 1028, 331 "free_ram_mb": 7680, 332 "hypervisor_type": "fake", 333 "hypervisor_version": 1000, 334 "local_gb": 1028, 335 "local_gb_used": 0, 336 "memory_mb": 8192, 337 "memory_mb_used": 512, 338 "running_vms": 0, 339 "service": { 340 "host": "host1", 341 "id": 7, 342 "disabled_reason": None 343 }, 344 "vcpus": 1, 345 "vcpus_used": 0 346 })) 347 348 349class FakeVolume: 350 def __init__( 351 self, id, status, name, attachments=[], 352 size=75): 353 self.id = id 354 self.status = status 355 self.name = name 356 self.attachments = attachments 357 self.size = size 358 self.snapshot_id = 'id:snapshot' 359 self.description = 'description' 360 self.volume_type = 'type:volume' 361 self.availability_zone = 'az1' 362 self.created_at = '1900-01-01 12:34:56' 363 self.source_volid = '12345' 364 self.metadata = {} 365 366 367class FakeVolumeSnapshot: 368 def __init__( 369 self, id, status, name, description, size=75): 370 self.id = id 371 self.status = status 372 self.name = name 373 self.description = description 374 self.size = size 375 self.created_at = '1900-01-01 12:34:56' 376 self.volume_id = '12345' 377 self.metadata = {} 378 379 380class FakeMachine: 381 def __init__(self, id, name=None, driver=None, driver_info=None, 382 chassis_uuid=None, instance_info=None, instance_uuid=None, 383 properties=None, reservation=None, last_error=None, 384 provision_state='available'): 385 self.uuid = id 386 self.name = name 387 self.driver = driver 388 self.driver_info = driver_info 389 self.chassis_uuid = chassis_uuid 390 self.instance_info = instance_info 391 self.instance_uuid = instance_uuid 392 self.properties = properties 393 self.reservation = reservation 394 self.last_error = last_error 395 self.provision_state = provision_state 396 397 398class FakeMachinePort: 399 def __init__(self, id, address, node_id): 400 self.uuid = id 401 self.address = address 402 self.node_uuid = node_id 403 404 405def make_fake_neutron_security_group( 406 id, name, description, rules, stateful=True, project_id=None): 407 if not rules: 408 rules = [] 409 if not project_id: 410 project_id = PROJECT_ID 411 return json.loads(json.dumps({ 412 'id': id, 413 'name': name, 414 'description': description, 415 'stateful': stateful, 416 'project_id': project_id, 417 'tenant_id': project_id, 418 'security_group_rules': rules, 419 })) 420 421 422def make_fake_nova_security_group_rule( 423 id, from_port, to_port, ip_protocol, cidr): 424 return json.loads(json.dumps({ 425 'id': id, 426 'from_port': int(from_port), 427 'to_port': int(to_port), 428 'ip_protcol': 'tcp', 429 'ip_range': { 430 'cidr': cidr 431 } 432 })) 433 434 435def make_fake_nova_security_group(id, name, description, rules): 436 if not rules: 437 rules = [] 438 return json.loads(json.dumps({ 439 'id': id, 440 'name': name, 441 'description': description, 442 'tenant_id': PROJECT_ID, 443 'rules': rules, 444 })) 445 446 447class FakeNovaSecgroupRule: 448 def __init__(self, id, from_port=None, to_port=None, ip_protocol=None, 449 cidr=None, parent_group_id=None): 450 self.id = id 451 self.from_port = from_port 452 self.to_port = to_port 453 self.ip_protocol = ip_protocol 454 if cidr: 455 self.ip_range = {'cidr': cidr} 456 self.parent_group_id = parent_group_id 457 458 459class FakeHypervisor: 460 def __init__(self, id, hostname): 461 self.id = id 462 self.hypervisor_hostname = hostname 463 464 465class FakeZone: 466 def __init__(self, id, name, type_, email, description, 467 ttl, masters): 468 self.id = id 469 self.name = name 470 self.type_ = type_ 471 self.email = email 472 self.description = description 473 self.ttl = ttl 474 self.masters = masters 475 476 477class FakeRecordset: 478 def __init__(self, zone, id, name, type_, description, 479 ttl, records): 480 self.zone = zone 481 self.id = id 482 self.name = name 483 self.type_ = type_ 484 self.description = description 485 self.ttl = ttl 486 self.records = records 487 488 489def make_fake_aggregate(id, name, availability_zone='nova', 490 metadata=None, hosts=None): 491 if not metadata: 492 metadata = {} 493 if not hosts: 494 hosts = [] 495 return json.loads(json.dumps({ 496 "availability_zone": availability_zone, 497 "created_at": datetime.datetime.now().isoformat(), 498 "deleted": False, 499 "deleted_at": None, 500 "hosts": hosts, 501 "id": int(id), 502 "metadata": { 503 "availability_zone": availability_zone, 504 }, 505 "name": name, 506 "updated_at": None, 507 })) 508