Files
gce-api/gceapi/tests/unit/api/fake_nova_client.py
Andrey Pavlov 75905790e5 update gce api to current OpenStack
- add devstack plugin
- update openstack common
- move unit tests to unit folder
- update infrastructural files

Change-Id: Id72006f70110dbd1762f42b582470ac5f3439f2a
2015-09-03 17:16:30 +03:00

797 lines
24 KiB
Python

# Copyright 2014
# The Cloudscaling Group, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import copy
import inspect
import uuid
from novaclient import client as novaclient
from gceapi.api import base_api
from gceapi.i18n import _
from gceapi.tests.unit.api import fake_request
from gceapi.tests.unit.api import utils
FAKE_DETAILED_ZONES = [utils.FakeObject({
"zoneState": {
"available": True},
"hosts": {
"grizzly": {
"nova-conductor": {
"available": True,
"active": True,
"updated_at": "2013-12-24T14:14:47.000000"},
"nova-consoleauth": {
"available": True,
"active": True,
"updated_at": "2013-12-24T14:14:49.000000"},
"nova-scheduler": {
"available": True,
"active": True,
"updated_at": "2013-12-24T14:14:48.000000"},
"nova-cert": {
"available": True,
"active": True,
"updated_at": "2013-12-24T14:14:49.000000"}}},
"zoneName": "internal"
}), utils.FakeObject({
"zoneState": {
"available": True},
"hosts": {
"grizzly": {
"nova-compute": {
"available": True,
"active": True,
"updated_at": "2013-12-24T14:14:47.000000"}}},
"zoneName": "nova"
})]
FAKE_SIMPLE_ZONES = [utils.FakeObject({
"zoneState": {
"available": True},
"hosts": None,
"zoneName": "nova"
})]
FAKE_FLAVORS = [utils.FakeObject({
"name": "m1.small",
"links": [],
"ram": 2048,
"OS-FLV-DISABLED:disabled": False,
"vcpus": 1,
"swap": "",
"os-flavor-access:is_public": True,
"rxtx_factor": 1.0,
"OS-FLV-EXT-DATA:ephemeral": 0,
"disk": 20,
"id": "2"
}), utils.FakeObject({
"name": "m1.large",
"links": [],
"ram": 8192,
"OS-FLV-DISABLED:disabled": False,
"vcpus": 4,
"swap": "",
"os-flavor-access:is_public": True,
"rxtx_factor": 1.0,
"OS-FLV-EXT-DATA:ephemeral": 870,
"disk": 80,
"id": "4"
})]
FAKE_SECURITY_GROUPS = [
utils.FakeObject({
"rules": [
{
"from_port": None,
"ip_protocol": None,
"to_port": None,
"ip_range": {},
"id": "3f8a140e-8d34-49c5-8cf2-5bec936b6c5c",
},
{
"from_port": None,
"ip_protocol": None,
"to_port": None,
"ip_range": {},
"id": "9b0006c7-5e58-4b8e-a081-f0381c44bb2f",
},
],
"project_id": "6678c02984ce4df8b26912db30481637",
"id": "2cfdbf3a-0564-4b3b-bb85-00eb8d518f0c",
"name": "default",
"description": "default",
}),
utils.FakeObject({
"rules": [
{
"from_port": 223,
"ip_protocol": "udp",
"to_port": 322,
"ip_range": {"cidr": "55.0.0.0/24"},
"id": "26f6c9e4-d8ca-4a96-b752-b848716f05f5",
},
{
"from_port": -1,
"ip_protocol": "icmp",
"to_port": -1,
"ip_range": {"cidr": "44.0.0.0/24"},
"id": "4a2f2805-cde0-4515-9910-f2f8e77ba5f7",
},
{
"from_port": 1234,
"ip_protocol": "tcp",
"to_port": 1234,
"ip_range": {"cidr": "44.0.0.0/24"},
"id": "e137dae4-ea4e-401d-8941-96a207e435b9",
},
{
"from_port": -1,
"ip_protocol": "icmp",
"to_port": -1,
"ip_range": {"cidr": "55.0.0.0/24"},
"id": "e6a866a8-969a-41d9-b621-964a50f46381",
},
{
"from_port": 223,
"ip_protocol": "udp",
"to_port": 322,
"ip_range": {"cidr": "44.0.0.0/24"},
"id": "f830670e-f90f-477f-9605-e871640cf8c2",
},
{
"from_port": 1234,
"ip_protocol": "tcp",
"to_port": 1234,
"ip_range": {"cidr": "55.0.0.0/24"},
"id": "fbd2ada0-c5fc-4047-9558-2fb90874c8b3",
},
],
"project_id": "6678c02984ce4df8b26912db30481637",
"id": "a4ab9c5f-f0b5-4952-8e76-6a8ca0d0a402",
"name": "fake-firewall-1",
"description": "simple firewall",
}),
utils.FakeObject({
"rules": [],
"project_id": "6678c02984ce4df8b26912db30481637",
"id": "c3859194-f111-4f24-b93b-095b056f38e2",
"name": "fake-firewall-2",
"description": "openstack sg w/o rules",
}),
utils.FakeObject({
"rules": [
{
"from_port": 1000,
"ip_protocol": "tcp",
"to_port": 2000,
"ip_range": {"cidr": "77.0.0.0/24"},
"id": "01ecc4c4-41be-4af1-9a64-e2f866176001",
},
{
"from_port": 1000,
"ip_protocol": "tcp",
"to_port": 2000,
"ip_range": {},
"id": "8709247a-afd8-4673-aac4-e22d8432a31e",
},
{
"from_port": 1000,
"ip_protocol": "tcp",
"to_port": 2000,
"ip_range": {"cidr": "78.0.0.0/24"},
"id": "d67e8103-b32b-428b-bd20-8337b95456f1",
},
],
"project_id": "6678c02984ce4df8b26912db30481637",
"id": "b599598d-41b9-4075-a47e-019ba785c243",
"name": "fake-firewall-3",
"description": ("openstack sg with cidr & secgroup rules"),
}),
utils.FakeObject({
"rules": [
{
"from_port": 5678,
"ip_protocol": "tcp",
"to_port": 5678,
"ip_range": {"cidr": "66.0.0.0/24"},
"id": "0642de5e-3c59-4c1c-8816-be6998c3c8a2",
},
{
"from_port": 1234,
"ip_protocol": "tcp",
"to_port": 1234,
"ip_range": {"cidr": "66.0.0.0/24"},
"id": "b1a2b159-76e5-4baf-926a-a4ce09098377",
},
{
"from_port": 1234,
"ip_protocol": "tcp",
"to_port": 1234,
"ip_range": {"cidr": "88.0.0.0/24"},
"id": "f7abbaab-f4fe-49fb-ac7f-bd8c49e60c61",
},
],
"project_id": "6678c02984ce4df8b26912db30481637",
"id": "fac84db7-aded-4152-a29e-5db00e052233",
"name": "fake-firewall-4",
"description": ("openstack sg too complex to translate into gce "
"rules"),
}),
utils.FakeObject({
"rules": [
{
"from_port": 6666,
"ip_protocol": "tcp",
"to_port": 6666,
"ip_range": {"cidr": "111.0.0.0/24"},
"id": "634a199e-fb97-41d2-b12f-273c23a1c065"
},
{
"from_port": 5555,
"ip_protocol": "tcp",
"to_port": 5555,
"ip_range": {"cidr": "222.0.0.0/24"},
"id": "bf34b3b0-29aa-4abf-a686-f29d9fb342d8"
},
{
"from_port": -1,
"ip_protocol": "icmp",
"to_port": -1,
"ip_range": {},
"id": "fdf5dbe1-e824-46a6-a4d3-d2e37843a6d2"
},
],
"project_id": "6678c02984ce4df8b26912db30481637",
"id": "03060521-fe0b-425f-bf33-d5061d58bae9",
"name": "fake-firewall-5",
"description": "openstack sg with combined & too complex rules",
}),
utils.FakeObject({
"rules": [
{
"from_port": 0,
"ip_protocol": "icmp",
"to_port": 8,
"ip_range": {"cidr": "100.0.0.0/24"},
"id": "ae452a08-af3b-4d6a-b38e-2f4acad63331",
},
],
"project_id": "6678c02984ce4df8b26912db30481637",
"id": "d4c41e39-159c-4f96-8176-86c7b177880f",
"name": "fake-firewall-6",
"description": "openstack sg with too complex icmp rule",
}),
utils.FakeObject({
"rules": [
{
"from_port": -1,
"ip_protocol": "icmp",
"to_port": -1,
"ip_range": {"cidr": "110.0.0.0/24"},
"id": "e2bc37af-529e-4ab3-8f41-358f3f9e62ab",
},
],
"project_id": "6678c02984ce4df8b26912db30481637",
"id": "1aaa637b-87f4-4e27-bc86-ff63d30264b2",
"name": "to-delete-firewall",
"description": "firewall to delete test",
}),
]
FAKE_INSTANCES = [{
"OS-DCF:diskConfig": "MANUAL",
"OS-EXT-AZ:availability_zone": "nova",
"OS-EXT-SRV-ATTR:host": "apavlov-VirtualBox",
"OS-EXT-SRV-ATTR:hypervisor_hostname": "apavlov-VirtualBox",
"OS-EXT-SRV-ATTR:instance_name": "instance-00000001",
"OS-EXT-STS:task_state": None,
"OS-EXT-STS:vm_state": "active",
"OS-EXT-STS:power_state": 1,
"OS-SRV-USG:launched_at": "2013-08-14T13:46:23.000000",
"OS-SRV-USG:terminated_at": None,
"addresses": {
"private": [{
"OS-EXT-IPS-MAC:mac_addr": "fa:16:3e:ea:ae:56",
"version": 4,
"addr": "10.0.1.3",
"OS-EXT-IPS:type": "fixed"
}, {
"OS-EXT-IPS-MAC:mac_addr": "fa:16:3e:ea:ae:56",
"version": 4,
"addr": "192.168.138.196",
"OS-EXT-IPS:type": "floating"
}]
},
"image": None,
"flavor": {
"id": "2",
},
"id": "d6957005-3ce7-4727-91d2-ae37fe5a199a",
"security_groups": [{
"name": "default"
}],
"name": "i1",
"status": "ACTIVE",
"created": "2013-08-14T13:45:32Z",
"updated": "2013-08-14T13:46:23Z",
"user_id": "0ed9ed7b2004443f802142ecf364738b",
"accessIPv4": "",
"accessIPv6": "",
"progress": 0,
"config_drive": "",
"hostId": "cbf5e76abf66aa4363dbf17cfe0305093d903fe10389210856d85585",
"key_name": "admin",
"networks": {
u'private': [u'10.0.1.3', u'192.168.138.196']
},
"tenant_id": fake_request.PROJECT_ID,
"os-extended-volumes:volumes_attached": [{
"id": "ab8829ad-eec1-44a2-8068-d7f00c53ee90"
}],
"metadata": {}
}, {
"OS-DCF:diskConfig": "MANUAL",
"OS-EXT-AZ:availability_zone": "nova",
"OS-EXT-SRV-ATTR:host": "apavlov-VirtualBox",
"OS-EXT-SRV-ATTR:hypervisor_hostname": "apavlov-VirtualBox",
"OS-EXT-SRV-ATTR:instance_name": "instance-00000001",
"OS-EXT-STS:task_state": None,
"OS-EXT-STS:vm_state": "active",
"OS-EXT-STS:power_state": 4,
"OS-SRV-USG:terminated_at": None,
"OS-SRV-USG:launched_at": "2013-08-14T13:47:11.000000",
"addresses": {
"default": [{
"OS-EXT-IPS-MAC:mac_addr": "fa:16:3e:ea:ae:50",
"version": 4,
"addr": "10.100.0.3",
"OS-EXT-IPS:type": "fixed"
}]
},
"image": {
"id": "60ff30c2-64b6-4a97-9c17-322eebc8bd60",
},
"flavor": {
"id": "4",
},
"id": "6472359b-d46b-4629-83a9-d2ec8d99468c",
"security_groups": [{
"name": "default"
}],
"name": "i2",
"status": "SUSPENDED",
"created": "2013-08-14T13:46:36Z",
"updated": "2013-08-14T13:47:11Z",
"user_id": "0ed9ed7b2004443f802142ecf364738b",
"accessIPv4": "",
"accessIPv6": "",
"progress": 0,
"config_drive": "",
"hostId": "cbf5e76abf66aa4363dbf17cfe0305093d903fe10389210856d85585",
"key_name": None,
"networks": {
"default": ["10.100.0.3"]
},
"tenant_id": fake_request.PROJECT_ID,
"os-extended-volumes:volumes_attached": [],
"metadata": {}
}]
FAKE_NEW_INSTANCE = {
"OS-DCF:diskConfig": "MANUAL",
"OS-EXT-AZ:availability_zone": "nova",
"OS-EXT-SRV-ATTR:host": "apavlov-VirtualBox",
"OS-EXT-SRV-ATTR:hypervisor_hostname": "apavlov-VirtualBox",
"OS-EXT-SRV-ATTR:instance_name": "instance-00000003",
"OS-EXT-STS:task_state": None,
"OS-EXT-STS:vm_state": "active",
"OS-EXT-STS:power_state": 1,
"OS-SRV-USG:terminated_at": None,
"OS-SRV-USG:launched_at": "2013-08-14T13:47:11.000000",
"addresses": {
"private": [{
"OS-EXT-IPS-MAC:mac_addr": "fa:16:3e:ea:ae:55",
"version": 4,
"addr": "10.100.0.4",
"OS-EXT-IPS:type": "fixed"
}]
},
"flavor": {
"id": "4",
},
"id": "6472359b-3333-3333-3333-d2ec8d99468c",
"security_groups": [{
"name": "default"
}],
"name": "i2",
"status": "ACTIVE",
"created": "2013-08-14T13:46:36Z",
"updated": "2013-08-14T13:47:11Z",
"user_id": "0ed9ed7b2004443f802142ecf364738b",
"accessIPv4": "",
"accessIPv6": "",
"progress": 0,
"config_drive": "",
"hostId": "cbf5e76abf66aa4363dbf17cfe0305093d903fe10389210856d85585",
"key_name": None,
"networks": {
"default": ["10.100.0.3"]
},
"tenant_id": fake_request.PROJECT_ID,
"os-extended-volumes:volumes_attached": [],
"metadata": {}
}
FAKE_FLOATING_IPS = [utils.FakeObject({
"instance_id": None,
"ip": "192.168.138.195",
}), utils.FakeObject({
"instance_id": "d6957005-3ce7-4727-91d2-ae37fe5a199a",
"ip": "192.168.138.196",
})]
FAKE_LIMITS = utils.FakeObject({
"rate": [],
"human_id": None,
"NAME_ATTR": "name",
"HUMAN_ID": False,
"absolute": [
utils.FakeObject({"name": "maxServerMeta", "value": 128}),
utils.FakeObject({"name": "maxPersonality", "value": 5}),
utils.FakeObject({"name": "maxImageMeta", "value": 128}),
utils.FakeObject({"name": "maxPersonalitySize", "value": 10240}),
utils.FakeObject({"name": "maxTotalRAMSize", "value": 41000}),
utils.FakeObject({"name": "maxSecurityGroupRules", "value": 20}),
utils.FakeObject({"name": "maxTotalKeypairs", "value": 100}),
utils.FakeObject({"name": "maxSecurityGroups", "value": 10}),
utils.FakeObject({"name": "maxTotalFloatingIps", "value": 10}),
utils.FakeObject({"name": "maxTotalInstances", "value": 10}),
utils.FakeObject({"name": "maxTotalCores", "value": 17}),
utils.FakeObject({"name": "totalRAMUsed", "value": 512}),
utils.FakeObject({"name": "totalFloatingIpsUsed", "value": 3}),
utils.FakeObject({"name": "totalInstancesUsed", "value": 4}),
utils.FakeObject({"name": "totalSecurityGroupsUsed", "value": 2}),
utils.FakeObject({"name": "totalCoresUsed", "value": 1}),
]
})
class FakeClassWithFind(object):
def list(self):
pass
def find(self, **kwargs):
matches = self.findall(**kwargs)
num_matches = len(matches)
if num_matches == 0:
msg = "No %s matching %s." % (self.__class__.__name__, kwargs)
raise novaclient.exceptions.NotFound(404, msg)
elif num_matches > 1:
raise novaclient.exceptions.NoUniqueMatch
else:
return matches[0]
def findall(self, **kwargs):
found = []
searches = kwargs.items()
detailed = True
list_kwargs = {}
list_argspec = inspect.getargspec(self.list)
if "detailed" in list_argspec.args:
detailed = ("human_id" not in kwargs and
"name" not in kwargs and
"display_name" not in kwargs)
list_kwargs["detailed"] = detailed
if "is_public" in list_argspec.args and "is_public" in kwargs:
is_public = kwargs["is_public"]
list_kwargs["is_public"] = is_public
if is_public is None:
tmp_kwargs = kwargs.copy()
del tmp_kwargs["is_public"]
searches = tmp_kwargs.items()
listing = self.list(**list_kwargs)
for obj in listing:
try:
if all(getattr(obj, attr) == value
for (attr, value) in searches):
if detailed:
found.append(obj)
else:
found.append(self.get(obj.id))
except AttributeError:
continue
return found
class FakeAvailabilityZones(object):
def list(self, detailed=True):
if detailed:
return FAKE_DETAILED_ZONES
return FAKE_SIMPLE_ZONES
class FakeFlavors(FakeClassWithFind):
def list(self, detailed=True, is_public=True):
return FAKE_FLAVORS
def get(self, flavor):
flavor_id = utils.get_id(flavor)
for flavor in FAKE_FLAVORS:
if flavor.id == flavor_id:
return flavor
raise novaclient.exceptions.NotFound(
novaclient.exceptions.NotFound.http_status)
class FakeKeypairs(object):
def get(self, keypair):
raise novaclient.exceptions.NotFound(
novaclient.exceptions.NotFound.http_status)
def create(self, name, public_key=None):
pass
def delete(self, key):
raise novaclient.exceptions.NotFound(
novaclient.exceptions.NotFound.http_status)
def list(self):
return []
class FakeServer(utils.FakeObject):
_manager = None
def __init__(self, manager, obj_dict):
super(FakeServer, self).__init__(obj_dict)
self._manager = manager
def reboot(self, reboot_type):
self._manager.reboot(self, reboot_type)
def add_security_group(self, security_group):
pass
def remove_security_group(self, security_group):
pass
def delete(self):
self._manager.delete(self)
def add_floating_ip(self, address, fixed_address=None):
pass
def remove_floating_ip(self, address):
pass
class FakeServers(object):
_fake_instances = None
def __init__(self):
self._fake_instances = [FakeServer(self, i)
for i in FAKE_INSTANCES]
def get(self, server):
server_id = utils.get_id(server)
for server in self._fake_instances:
if server.id == server_id:
return server
raise novaclient.exceptions.NotFound(
novaclient.exceptions.NotFound.http_status)
def list(self, detailed=True, search_opts=None,
marker=None, limit=None):
result = self._fake_instances
if search_opts and "name" in search_opts:
name = search_opts["name"]
result = [i for i in result if i.name == name]
if search_opts and "fixed_ip" in search_opts:
name = search_opts["fixed_ip"]
filtered = []
for i in result:
for network in i.addresses:
for address in i.addresses[network]:
atype = address["OS-EXT-IPS:type"]
if atype == "fixed":
filtered.append(i)
break
result = filtered
return result
def create(self, name, image, flavor, meta=None, files=None,
reservation_id=None, min_count=None,
max_count=None, security_groups=None, userdata=None,
key_name=None, availability_zone=None,
block_device_mapping=None, block_device_mapping_v2=None,
nics=None, scheduler_hints=None,
config_drive=None, disk_config=None, **kwargs):
instance = copy.deepcopy(FakeServer(self, FAKE_NEW_INSTANCE))
instance.name = name
self._fake_instances.append(instance)
return instance
def add_floating_ip(self, server, address, fixed_address=None):
self.get(server)
def remove_floating_ip(self, server, address):
self.get(server)
def delete(self, server):
self.get(server)
def reboot(self, server, reboot_type):
if reboot_type != "HARD":
msg = _("Argument 'type' for reboot is not HARD or SOFT")
raise novaclient.exceptions.BadRequest(message=msg)
self.get(server)
class FakeSecurityGroups(FakeClassWithFind):
_secgroups = FAKE_SECURITY_GROUPS
def list(self):
return self._secgroups
def get(self, sg_id):
secgroup = next((secgroup
for secgroup in self._secgroups
if secgroup.id == sg_id), None)
if secgroup is None:
raise novaclient.exceptions.NotFound(
404, "Security group %s not found" % sg_id)
return secgroup
def create(self, name, description):
secgroup = utils.FakeObject({
"name": name,
"description": description,
"rules": [],
"project_id": "6678c02984ce4df8b26912db30481637",
"id": "5707a6f0-799d-4739-8740-3efc73f122aa",
})
self._secgroups = copy.deepcopy(self._secgroups)
self._secgroups.append(secgroup)
return secgroup
def delete(self, security_group):
pass
def add_rule(self, sg_id, ip_protocol, from_port, to_port, cidr):
secgroup = self.get(sg_id)
rule = {
"id": uuid.uuid4(),
"ip_protocol": ip_protocol,
"from_port": from_port,
"to_port": to_port,
"ip_range": {"cidr": cidr},
}
secgroup.rules.append(rule)
class FakeSecurityGroupRules(object):
def __init__(self, nova_client):
self.security_groups = nova_client.security_groups
def create(self, sg_id, ip_protocol, from_port, to_port, cidr):
self.security_groups.add_rule(sg_id, ip_protocol, from_port,
to_port, cidr)
class FakeFloatingIps(object):
def list(self):
return FAKE_FLOATING_IPS
class FakeLimits(object):
def get(self, tenant_id):
return FAKE_LIMITS
class FakeVolumes(object):
def get_server_volumes(self, instance_id):
return []
def create_server_volume(self, instance_id, volume_id, device):
instance = FakeServers().get(instance_id)
volumes = getattr(instance, "os-extended-volumes:volumes_attached")
volumes = [v["id"] for v in volumes]
if volume_id in volumes:
raise novaclient.exceptions.NotFound(
novaclient.exceptions.NotFound.http_status)
def delete_server_volume(self, instance_id, volume_id):
instance = FakeServers().get(instance_id)
volumes = getattr(instance, "os-extended-volumes:volumes_attached")
volumes = [v["id"] for v in volumes]
if volume_id not in volumes:
raise novaclient.exceptions.NotFound(
novaclient.exceptions.NotFound.http_status)
class FakeNovaClient(object):
KIND = "fake_novaclient"
__metaclass__ = base_api.Singleton
def __init__(self, version, *args, **kwargs):
self._servers = None
self._security_group = None
@property
def client(self):
return self
@property
def availability_zones(self):
return FakeAvailabilityZones()
@property
def flavors(self):
return FakeFlavors()
@property
def keypairs(self):
return FakeKeypairs()
@property
def servers(self):
if self._servers is None:
self._servers = FakeServers()
return self._servers
@property
def security_groups(self):
if self._security_group is None:
self._security_group = FakeSecurityGroups()
return self._security_group
@property
def security_group_rules(self):
return FakeSecurityGroupRules(self)
@property
def floating_ips(self):
return FakeFloatingIps()
@property
def limits(self):
return FakeLimits()
@property
def volumes(self):
return FakeVolumes()
def fake_discover_extensions(self, version):
return list()