--- /dev/null
+
+#
+# Copyright 2016 RIFT.IO 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 random
+import socket
+import struct
+import collections
+import hashlib
+import logging
+import os
+import uuid
+
+from gi import require_version
+require_version('RwCal', '1.0')
+
+from gi.repository import (
+ GObject,
+ RwCal,
+ RwTypes,
+ RwcalYang)
+
+import rw_status
+import rift.cal.rwcal_status as rwcal_status
+import rwlogger
+
+logger = logging.getLogger('rwcal.mock')
+
+
+class UnknownAccountError(Exception):
+ pass
+
+
+class MissingFileError(Exception):
+ pass
+
+
+class ImageLocationError(Exception):
+ pass
+
+
+rwstatus_exception_map = { IndexError: RwTypes.RwStatus.NOTFOUND,
+ KeyError: RwTypes.RwStatus.NOTFOUND,
+ NotImplementedError: RwTypes.RwStatus.NOT_IMPLEMENTED,
+ UnknownAccountError: RwTypes.RwStatus.NOTFOUND,
+ MissingFileError: RwTypes.RwStatus.NOTFOUND,
+}
+
+rwstatus = rw_status.rwstatus_from_exc_map(rwstatus_exception_map)
+rwcalstatus = rwcal_status.rwcalstatus_from_exc_map(rwstatus_exception_map)
+
+class Resources(object):
+ def __init__(self):
+ self.images = dict()
+ self.vlinks = dict()
+ self.vdus = dict()
+ self.flavors = dict()
+
+class MockPlugin(GObject.Object, RwCal.Cloud):
+ """This class implements the abstract methods in the Cloud class.
+ Mock is used for unit testing."""
+
+ def __init__(self):
+ GObject.Object.__init__(self)
+ self.resources = collections.defaultdict(Resources)
+
+ @staticmethod
+ def get_uuid(name):
+ if name == None:
+ raise ValueError("Name can not be None")
+ return str(uuid.uuid3(uuid.NAMESPACE_DNS, name))
+
+ @rwstatus
+ def do_init(self, rwlog_ctx):
+ if not any(isinstance(h, rwlogger.RwLogger) for h in logger.handlers):
+ logger.addHandler(
+ rwlogger.RwLogger(
+ category="rw-cal-log",
+ subcategory="rwcal.mock",
+ log_hdl=rwlog_ctx,
+ )
+ )
+
+ account = RwcalYang.CloudAccount()
+ account.name = 'mock_account'
+ account.account_type = 'mock'
+ account.mock.username = 'mock_user'
+ self.create_default_resources(account)
+ account.name = 'mock_account1'
+ self.create_default_resources(account)
+
+ @rwstatus(ret_on_failure=[None])
+ def do_validate_cloud_creds(self, account):
+ """
+ Validates the cloud account credentials for the specified account.
+ If creds are not valid, returns an error code & reason string
+ Arguments:
+ account - a cloud account to validate
+
+ Returns:
+ Validation Code and Details String
+ """
+ status = RwcalYang.CloudConnectionStatus(
+ status="success",
+ details=""
+ )
+
+ return status
+
+ @rwstatus(ret_on_failure=[None])
+ def do_get_management_network(self, account):
+ """
+ Returns the management network
+
+ @param account - a cloud account
+
+ """
+ raise NotImplementedError()
+
+ @rwstatus
+ def do_create_tenant(self, account, name):
+ """
+ Create a new tenant.
+
+ @param name - name to assign to the tenant.
+ """
+ raise NotImplementedError()
+
+ @rwstatus
+ def do_delete_tenant(self, account, tenant_id):
+ """
+ delete a tenant.
+
+ @param tenant_id - id of tenant to be deleted.
+ """
+ raise NotImplementedError()
+
+ @rwstatus(ret_on_failure=[[]])
+ def do_get_tenant_list(self, account):
+ """
+ List tenants.
+
+ """
+ raise NotImplementedError()
+
+ @rwstatus
+ def do_create_role(self, account, name):
+ """
+ Create a new role.
+
+ @param name - name to assign to the role.
+ """
+ raise NotImplementedError()
+
+ @rwstatus
+ def do_delete_role(self, account, role_id):
+ """
+ delete a role.
+
+ @param role_id - id of role to be deleted.
+ """
+ raise NotImplementedError()
+
+ @rwstatus(ret_on_failure=[[]])
+ def do_get_role_list(self, account):
+ """
+ List roles.
+
+ """
+ raise NotImplementedError()
+
+ @rwstatus(ret_on_failure=[None])
+ def do_create_image(self, account, image):
+ """
+ Create a VM image
+
+ @param account - cloud account information
+ @param image - information about the image
+ """
+ if image.location is None:
+ raise ImageLocationError("uninitialized image location")
+
+ if not os.path.exists(image.location):
+ raise MissingFileError("{} does not exist".format(image.location))
+
+ image.id = self.get_uuid(image.name)
+
+ self.resources[account.name].images[image.id] = image
+ logger.debug('created image: {}'.format(image.id))
+ return image.id
+
+ @rwstatus
+ def do_delete_image(self, account, image_id):
+ """
+ delete a vm image.
+
+ @param image_id - Instance id of VM image to be deleted.
+ """
+ if account.name not in self.resources:
+ raise UnknownAccountError()
+
+ del self.resources[account.name].images[image_id]
+
+ @rwstatus(ret_on_failure=[None])
+ def do_get_image(self, account, image_id):
+ return self.resources[account.name].images[image_id]
+
+ @rwstatus(ret_on_failure=[[]])
+ def do_get_image_list(self, account):
+ """
+ Return a list of the names of all available images.
+ """
+ boxed_image_list = RwcalYang.VimResources()
+ for image in self.resources[account.name].images.values():
+ image_entry = RwcalYang.ImageInfoItem()
+ image_entry.id = image.id
+ image_entry.name = image.name
+ if image.has_field('checksum'):
+
+ image_entry.checksum = image.checksum
+ boxed_image_list.imageinfo_list.append(image_entry)
+
+ logger.debug("Image list for {}: {}".format(account.name, boxed_image_list.imageinfo_list))
+ return boxed_image_list
+
+ @rwstatus
+ def do_create_vm(self, account, vm):
+ """
+ Create a new virtual machine.
+
+ @param name - name to assign to the VM. This does not have to be unique.
+ @param image - name of image to load on the VM.
+ @param size - name of the size of the VM to create.
+ @param location - name of the location to launch the VM in.
+ """
+ raise NotImplementedError()
+
+ @rwstatus
+ def do_start_vm(self, account, vm_id):
+ """
+ Start a virtual machine.
+
+ @param vm_id - id of VM to start
+ """
+ raise NotImplementedError()
+
+ @rwstatus
+ def do_stop_vm(self, account, vm_id):
+ """
+ Stop a virtual machine.
+
+ @param vm_id - id of VM to stop
+ """
+ raise NotImplementedError()
+
+ @rwstatus
+ def do_delete_vm(self, account, vm_id):
+ """
+ delete a virtual machine.
+
+ @param vm_id - Instance id of VM to be deleted.
+ """
+ raise NotImplementedError()
+
+ @rwstatus
+ def do_reboot_vm(self, account, vm_id):
+ """
+ reboot a virtual machine.
+
+ @param vm_id - Instance id of VM to be deleted.
+ """
+ raise NotImplementedError()
+
+ @rwstatus(ret_on_failure=[[]])
+ def do_get_vm_list(self, account):
+ raise NotImplementedError()
+
+ @rwstatus
+ def do_create_flavor(self, account, flavor):
+ """
+ create new flavor.
+
+ @param flavor - Flavor object
+ """
+ flavor_id = self.get_uuid(flavor.name)
+ self.resources[account.name].flavors[flavor_id] = flavor
+ logger.debug('Created flavor: {}'.format(flavor_id))
+ return flavor_id
+
+ @rwstatus
+ def do_delete_flavor(self, account, flavor_id):
+ """
+ Delete flavor.
+
+ @param flavor_id - Flavor id to be deleted.
+ """
+ logger.debug('Deleted flavor: {}'.format(flavor_id))
+ self.resources[account.name].flavors.pop(flavor_id)
+
+ @rwstatus(ret_on_failure=[None])
+ def do_get_flavor(self, account, flavor_id):
+ """
+ Return the specified flavor
+
+ @param flavor_id - the id of the flavor to return
+ """
+ flavor = self.resources[account.name].flavors[flavor_id]
+ logger.debug('Returning flavor-info for : {}'.format(flavor_id))
+ return flavor
+
+ @rwstatus(ret_on_failure=[[]])
+ def do_get_flavor_list(self, account):
+ """
+ Return a list of flavors
+ """
+ vim_resources = RwcalYang.VimResources()
+ for flavor in self.resources[account.name].flavors.values():
+ f = RwcalYang.FlavorInfoItem()
+ f.copy_from(flavor)
+ vim_resources.flavorinfo_list.append(f)
+ logger.debug("Returning list of flavor-info of size: %d", len(vim_resources.flavorinfo_list))
+ return vim_resources
+
+
+ @rwstatus
+ def do_add_host(self, account, host):
+ raise NotImplementedError()
+
+ @rwstatus
+ def do_remove_host(self, account, host_id):
+ raise NotImplementedError()
+
+ @rwstatus(ret_on_failure=[None])
+ def do_get_host(self, account, host_id):
+ raise NotImplementedError()
+
+ @rwstatus(ret_on_failure=[[]])
+ def do_get_host_list(self, account):
+ raise NotImplementedError()
+
+ @rwstatus
+ def do_create_port(self, account, port):
+ raise NotImplementedError()
+
+ @rwstatus
+ def do_delete_port(self, account, port_id):
+ raise NotImplementedError()
+
+ @rwstatus(ret_on_failure=[None])
+ def do_get_port(self, account, port_id):
+ raise NotImplementedError()
+
+ @rwstatus(ret_on_failure=[[]])
+ def do_get_port_list(self, account):
+ raise NotImplementedError()
+
+ @rwstatus
+ def do_create_network(self, account, network):
+ raise NotImplementedError()
+
+ @rwstatus
+ def do_delete_network(self, account, network_id):
+ raise NotImplementedError()
+
+ @rwstatus(ret_on_failure=[None])
+ def do_get_network(self, account, network_id):
+ raise NotImplementedError()
+
+ @rwstatus(ret_on_failure=[[]])
+ def do_get_network_list(self, account):
+ raise NotImplementedError()
+
+ def create_default_resources(self, account):
+ """
+ Create default resources
+ """
+ link_list = []
+ ### Add virtual links
+ #for i in range(1):
+ # vlink = RwcalYang.VirtualLinkReqParams()
+ # vlink.name = 'link-'+str(i)
+ # vlink.subnet = '10.0.0.0/24'
+ # rs, vlink_id = self.do_create_virtual_link(account, vlink)
+ # assert vlink_id != ''
+ # logger.debug("Creating static virtual-link with name: %s", vlink.name)
+ # link_list.append(vlink_id)
+
+ #### Add VDUs
+ #for i in range(8):
+ # vdu = RwcalYang.VDUInitParams()
+ # vdu.name = 'vdu-'+str(i)
+ # vdu.node_id = str(i)
+ # vdu.image_id = self.get_uuid('image-'+str(i))
+ # vdu.flavor_id = self.get_uuid('flavor'+str(i))
+ # vdu.vm_flavor.vcpu_count = 4
+ # vdu.vm_flavor.memory_mb = 4096*2
+ # vdu.vm_flavor.storage_gb = 40
+ # for j in range(2):
+ # c = vdu.connection_points.add()
+ # c.name = vdu.name+'-port-'+str(j)
+ # c.virtual_link_id = link_list[j]
+ # rs, vdu_id = self.do_create_vdu(account, vdu)
+ # assert vdu_id != ''
+ # logger.debug("Creating static VDU with name: %s", vdu.name)
+
+ for i in range(2):
+ flavor = RwcalYang.FlavorInfoItem()
+ flavor.name = 'flavor-'+str(i)
+ flavor.vm_flavor.vcpu_count = 4
+ flavor.vm_flavor.memory_mb = 4096*2
+ flavor.vm_flavor.storage_gb = 40
+ rc, flavor_id = self.do_create_flavor(account, flavor)
+
+ for i in range(2):
+ image = RwcalYang.ImageInfoItem()
+ image.name = "rwimage"
+ image.id = self.get_uuid('image-'+str(i))
+ image.checksum = self.get_uuid('rwimage'+str(i))
+ image.location = "/dev/null"
+ rc, image_id = self.do_create_image(account, image)
+
+ image = RwcalYang.ImageInfoItem()
+ image.name = "Fedora-x86_64-20-20131211.1-sda.qcow2"
+ image.id = self.get_uuid(image.name)
+ image.checksum = self.get_uuid(image.name)
+ image.location = "/dev/null"
+ rc, image_id = self.do_create_image(account, image)
+
+ image = RwcalYang.ImageInfoItem()
+ image.name = "Fedora-x86_64-20-20131211.1-sda-ping.qcow2"
+ image.id = self.get_uuid(image.name)
+ image.checksum = "a6ffaa77f949a9e4ebb082c6147187cf"#self.get_uuid(image.name)
+ image.location = "/dev/null"
+ rc, image_id = self.do_create_image(account, image)
+
+ image = RwcalYang.ImageInfoItem()
+ image.name = "Fedora-x86_64-20-20131211.1-sda-pong.qcow2"
+ image.id = self.get_uuid(image.name)
+ image.checksum = "977484d95575f80ef8399c9cf1d45ebd"#self.get_uuid(image.name)
+ image.location = "/dev/null"
+ rc, image_id = self.do_create_image(account, image)
+
+
+ @rwcalstatus(ret_on_failure=[""])
+ def do_create_virtual_link(self, account, link_params):
+ vlink_id = self.get_uuid("%s_%s" % (link_params.name, len(self.resources[account.name].vlinks)))
+ vlink = RwcalYang.VirtualLinkInfoParams()
+ vlink.name = link_params.name
+ vlink.state = 'active'
+ vlink.virtual_link_id = vlink_id
+ vlink.subnet = link_params.subnet
+ vlink.connection_points = []
+ for field in link_params.provider_network.fields:
+ if link_params.provider_network.has_field(field):
+ setattr(vlink.provider_network, field, getattr(link_params.provider_network, field))
+
+ self.resources[account.name].vlinks[vlink_id] = vlink
+ logger.debug('created virtual-link: {}'.format(vlink_id))
+ return vlink_id
+
+ @rwstatus
+ def do_delete_virtual_link(self, account, link_id):
+ self.resources[account.name].vlinks.pop(link_id)
+ logger.debug('deleted virtual-link: {}'.format(link_id))
+
+
+ @rwstatus(ret_on_failure=[None])
+ def do_get_virtual_link(self, account, link_id):
+ vlink = self.resources[account.name].vlinks[link_id]
+ logger.debug('Returning virtual-link-info for : {}'.format(link_id))
+ return vlink
+
+ @rwstatus(ret_on_failure=[""])
+ def do_get_virtual_link_list(self, account):
+ vnf_resources = RwcalYang.VNFResources()
+ for r in self.resources[account.name].vlinks.values():
+ vlink = RwcalYang.VirtualLinkInfoParams()
+ vlink.copy_from(r)
+ vnf_resources.virtual_link_info_list.append(vlink)
+ logger.debug("Returning list of virtual-link-info of size: %d", len(vnf_resources.virtual_link_info_list))
+ return vnf_resources
+
+ @rwcalstatus(ret_on_failure=[""])
+ def do_create_vdu(self, account, vdu_init):
+ vdu_id = self.get_uuid("%s_%s" % (vdu_init.name, len(self.resources[account.name].vdus)))
+ vdu = RwcalYang.VDUInfoParams()
+ vdu.vdu_id = vdu_id
+ vdu.name = vdu_init.name
+ vdu.node_id = vdu_init.node_id
+ vdu.image_id = vdu_init.image_id
+ if vdu_init.has_field('flavor_id'):
+ vdu.flavor_id = vdu_init.flavor_id
+
+ if vdu_init.has_field('vm_flavor'):
+ xx = vdu.vm_flavor.new()
+ xx.from_pbuf(vdu_init.vm_flavor.to_pbuf())
+ vdu.vm_flavor = xx
+
+ if vdu_init.has_field('guest_epa'):
+ xx = vdu.guest_epa.new()
+ xx.from_pbuf(vdu_init.guest_epa.to_pbuf())
+ vdu.guest_epa = xx
+
+ if vdu_init.has_field('vswitch_epa'):
+ xx = vdu.vswitch_epa.new()
+ xx.from_pbuf(vdu_init.vswitch_epa.to_pbuf())
+ vdu.vswitch_epa = xx
+
+ if vdu_init.has_field('hypervisor_epa'):
+ xx = vdu.hypervisor_epa.new()
+ xx.from_pbuf(vdu_init.hypervisor_epa.to_pbuf())
+ vdu.hypervisor_epa = xx
+
+ if vdu_init.has_field('host_epa'):
+ xx = vdu.host_epa.new()
+ xx.from_pbuf(vdu_init.host_epa.to_pbuf())
+ vdu.host_epa = xx
+
+ vdu.state = 'active'
+ vdu.management_ip = socket.inet_ntoa(struct.pack('>I', random.randint(1, 0xffffffff)))
+ vdu.public_ip = vdu.management_ip
+
+ for c in vdu_init.connection_points:
+ p = vdu.connection_points.add()
+ p.connection_point_id = self.get_uuid(c.name)
+ p.name = c.name
+ p.vdu_id = vdu_id
+ p.state = 'active'
+ p.ip_address = socket.inet_ntoa(struct.pack('>I', random.randint(1, 0xffffffff)))
+ p.virtual_link_id = c.virtual_link_id
+ # Need to add this connection_point to virtual link
+ vlink = self.resources[account.name].vlinks[c.virtual_link_id]
+ v = vlink.connection_points.add()
+ for field in p.fields:
+ if p.has_field(field):
+ setattr(v, field, getattr(p, field))
+
+ self.resources[account.name].vdus[vdu_id] = vdu
+ logger.debug('Created vdu: {}'.format(vdu_id))
+ return vdu_id
+
+
+ @rwstatus
+ def do_modify_vdu(self, account, vdu_modify):
+ vdu = self.resources[account.name].vdus[vdu_modify.vdu_id]
+ for c in vdu_modify.connection_points_add:
+ p = vdu.connection_points.add()
+ p.connection_point_id = self.get_uuid(c.name)
+ p.name = c.name
+ p.vdu_id = vdu.vdu_id
+ p.state = 'active'
+ p.ip_address = socket.inet_ntoa(struct.pack('>I', random.randint(1, 0xffffffff)))
+ p.virtual_link_id = c.virtual_link_id
+ # Need to add this connection_point to virtual link
+ vlink = self.resources[account.name].vlinks[c.virtual_link_id]
+ aa = RwcalYang.VirtualLinkInfoParams_ConnectionPoints()
+ aa.connection_point_id = p.connection_point_id
+ aa.name = p.name
+ aa.virtual_link_id = vlink.virtual_link_id
+ aa.state = 'active'
+ aa.ip_address = p.ip_address
+ aa.vdu_id = p.vdu_id
+ vlink.connection_points.append(aa)
+
+ for c in vdu_modify.connection_points_remove:
+ for d in vdu.connection_points:
+ if c.connection_point_id == d.connection_point_id:
+ vdu.connection_points.remove(d)
+ break
+ for k, vlink in self.resources[account.name].vlinks.items():
+ for z in vlink.connection_points:
+ if z.connection_point_id == c.connection_point_id:
+ vlink.connection_points.remove(z)
+ break
+ logger.debug('modified vdu: {}'.format(vdu_modify.vdu_id))
+
+ @rwstatus
+ def do_delete_vdu(self, account, vdu_id):
+ vdu = self.resources[account.name].vdus.pop(vdu_id)
+ for c in vdu.connection_points:
+ vlink = self.resources[account.name].vlinks[c.virtual_link_id]
+ z = [p for p in vlink.connection_points if p.connection_point_id == c.connection_point_id]
+ assert len(z) == 1
+ vlink.connection_points.remove(z[0])
+
+ logger.debug('deleted vdu: {}'.format(vdu_id))
+
+ @rwstatus(ret_on_failure=[None])
+ def do_get_vdu(self, account, vdu_id):
+ vdu = self.resources[account.name].vdus[vdu_id]
+ logger.debug('Returning vdu-info for : {}'.format(vdu_id))
+ return vdu.copy()
+
+ @rwstatus(ret_on_failure=[""])
+ def do_get_vdu_list(self, account):
+ vnf_resources = RwcalYang.VNFResources()
+ for r in self.resources[account.name].vdus.values():
+ vdu = RwcalYang.VDUInfoParams()
+ vdu.copy_from(r)
+ vnf_resources.vdu_info_list.append(vdu)
+ logger.debug("Returning list of vdu-info of size: %d", len(vnf_resources.vdu_info_list))
+ return vnf_resources
+