X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=rwcal%2Fplugins%2Fvala%2Frwcal_mock%2Frwcal_mock.py;fp=rwcal%2Fplugins%2Fvala%2Frwcal_mock%2Frwcal_mock.py;h=a1776d11da74e3138f53255c1166f933b67e5a59;hb=6f07e6f33f751ab4ffe624f6037f887b243bece2;hp=0000000000000000000000000000000000000000;hpb=72a563886272088feb7cb52e4aafbe6d2c580ff9;p=osm%2FSO.git diff --git a/rwcal/plugins/vala/rwcal_mock/rwcal_mock.py b/rwcal/plugins/vala/rwcal_mock/rwcal_mock.py new file mode 100644 index 00000000..a1776d11 --- /dev/null +++ b/rwcal/plugins/vala/rwcal_mock/rwcal_mock.py @@ -0,0 +1,616 @@ + +# +# 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 +