Exemplo n.º 1
0
    def __init__(self,
                 locator='127.0.0.1:7447',
                 sysid=Constants.default_system_id,
                 tenantid=Constants.default_tenant_id):

        self.connector = Yaks_Connector(locator)
        self.sysid = sysid
        self.tenantid = tenantid
        self.entity = self.EntityAPI(self.connector, self.sysid, self.tenantid)
Exemplo n.º 2
0
    def __init__(self, locator='127.0.0.1:7447',
                 sysid=Constants.default_system_id,
                 tenantid=Constants.default_tenant_id):

        self.connector = Yaks_Connector(locator)
        self.sysid = sysid
        self.tenantid = tenantid
        self.descriptor = self.Descriptor()
        self.node = self.Node(self.connector, self.sysid, self.tenantid)
        self.plugin = self.Plugin(self.connector, self.sysid, self.tenantid)
        self.network = self.Network(self.connector, self.sysid, self.tenantid)
        self.fdu  = self.FDUAPI(self.connector, self.sysid, self.tenantid)
        self.image = self.Image(self.connector, self.sysid, self.tenantid)
        self.flavor = self.Flavor(self.connector, self.sysid, self.tenantid)
Exemplo n.º 3
0
class FEOAPI(object):
    '''
        This class allow the interaction with fog05 FIM
    '''
    def __init__(self,
                 locator='127.0.0.1:7447',
                 sysid=Constants.default_system_id,
                 tenantid=Constants.default_tenant_id):

        self.connector = Yaks_Connector(locator)
        self.sysid = sysid
        self.tenantid = tenantid
        self.entity = self.EntityAPI(self.connector, self.sysid, self.tenantid)

    def close(self):
        self.connector.close()

    class EntityAPI(object):
        def __init__(self,
                     connector=None,
                     sysid=Constants.default_system_id,
                     tenantid=Constants.default_tenant_id):

            if connector is None:
                raise RuntimeError('Yaks connector cannot be none in API!')
            self.connector = connector
            self.sysid = sysid
            self.tenantid = tenantid

        def onboard(self, descriptor):
            if not isinstance(descriptor, Entity):
                raise ValueError("descriptor should be of type Entity")
            nodes = self.connector.glob.actual.get_all_nodes(
                self.sysid, self.tenantid)
            if len(nodes) == 0:
                raise SystemError("No nodes in the system!")
            n = random.choice(nodes)
            res = self.connector.glob.actual.onboard_entity_from_node(
                self.sysid, self.tenantid, n, descriptor.to_json())
            if res.get('result') is None:
                raise SystemError('Error during onboarding {} - {}'.format(
                    res['error'], res['error_msg']))
            return Entity(res['result'])

        def instantiate(self, e_id):
            nodes = self.connector.glob.actual.get_all_nodes(
                self.sysid, self.tenantid)
            if len(nodes) == 0:
                raise SystemError("No nodes in the system!")
            n = random.choice(nodes)
            res = self.connector.glob.actual.instantiate_entity_from_node(
                self.sysid, self.tenantid, n, e_id)
            if res.get('result') is None:
                raise SystemError('Error during instantiation {} - {}'.format(
                    res['error'], res['error_msg']))
            return EntityRecord(res['result'])

        def offload(self, e_id):
            nodes = self.connector.glob.actual.get_all_nodes(
                self.sysid, self.tenantid)
            if len(nodes) == 0:
                raise SystemError("No nodes in the system!")
            n = random.choice(nodes)
            res = self.connector.glob.actual.offload_entity_from_node(
                self.sysid, self.tenantid, n, e_id)
            if res.get('result') is None:
                raise SystemError('Error during offloading {} - {}'.format(
                    res['error'], res['error_msg']))
            return Entity(res['result'])

        def terminate(self, e_instance_id):
            nodes = self.connector.glob.actual.get_all_nodes(
                self.sysid, self.tenantid)
            if len(nodes) == 0:
                raise SystemError("No nodes in the system!")
            n = random.choice(nodes)
            res = self.connector.glob.actual.terminate_entity_from_node(
                self.sysid, self.tenantid, n, e_instance_id)
            if res.get('result') is None:
                raise SystemError('Error during termination {} - {}'.format(
                    res['error'], res['error_msg']))
            return EntityRecord(res['result'])

        def get_entity_descriptor(self, e_id):
            res = self.connector.glob.actual.get_catalog_entity_info(
                self.sysid, self.tenantid, e_id)
            return Entity(res)

        def get_entity_instance_info(self, instance_id):
            res = self.connector.glob.actual.get_records_entity_info(
                self.sysid, self.tenantid, "*", instance_id)
            return EntityRecord(res)

        def list(self):
            return self.connector.glob.actual.get_catalog_all_entities(
                self.sysid, self.tenantid)

        def instance_list(self, entity_id):
            return self.connector.glob.actual.get_records_all_entity_instances(
                self.sysid, self.tenantid, entity_id)
Exemplo n.º 4
0
class FIMAPI(object):
    '''
        This class allow the interaction with fog05 FIM
    '''
    def __init__(self,
                 locator='127.0.0.1:7887',
                 sysid=Constants.default_system_id,
                 tenantid=Constants.default_tenant_id):

        self.connector = Yaks_Connector(locator)
        self.sysid = sysid
        self.tenantid = tenantid
        self.manifest = self.Manifest()
        self.node = self.Node(self.connector, self.sysid, self.tenantid)
        self.plugin = self.Plugin(self.connector, self.sysid, self.tenantid)
        self.network = self.Network(self.connector, self.sysid, self.tenantid)
        self.fdu = self.FDU(self.connector, self.sysid, self.tenantid)
        self.image = self.Image(self.connector, self.sysid, self.tenantid)
        self.flavor = self.Flavor(self.connector, self.sysid, self.tenantid)

    def close(self):
        self.connector.close()

    class Manifest(object):
        '''
        This class encapsulates API for manifests

        '''
        def __init__(self):
            pass

        def check(self, manifest, manifest_type):
            '''

            This method allow you to check a manifest

            :param manifest: a dictionary rapresenting the JSON manifest
            :param manifest_type: the manifest type from API.Manifest.Type
            :return: boolean
            '''
            # if manifest_type == self.Type.ENTITY:
            #     t = manifest.get('type')
            #     try:
            #         if t == 'vm':
            #             validate(manifest.get('entity_data'),
            #                      Schemas.vm_schema)
            #         elif t == 'container':
            #             validate(manifest.get('entity_data'),
            #                      Schemas.container_schema)
            #         elif t == 'native':
            #             validate(manifest.get('entity_data'),
            #                      Schemas.native_schema)
            #         elif t == 'ros2':
            #             validate(manifest.get('entity_data'),
            #                      Schemas.ros2_schema)
            #         elif t == 'usvc':
            #             return False
            #         else:
            #             return False
            #     except ValidationError as ve:
            #         return False
            # if manifest_type == self.Type.NETWORK:
            #     try:
            #         validate(manifest, Schemas.network_schema)
            #     except ValidationError as ve:
            #         return False
            # if manifest_type == self.Type.ENTITY:
            #     try:
            #         validate(manifest, Schemas.entity_schema)
            #     except ValidationError as ve:
            #         return False

            return True

        # class Type(Enum):
        #     '''
        #     Manifest types
        #     '''
        #     ENTITY = 0
        #     IMAGE = 1
        #     FLAVOR = 3
        #     NETWORK = 4
        #     PLUGIN = 5

    class Node(object):
        '''

        This class encapsulates the command for Node interaction

        '''
        def __init__(self,
                     connector=None,
                     sysid=Constants.default_system_id,
                     tenantid=Constants.default_tenant_id):

            if connector is None:
                raise RuntimeError('Yaks connector cannot be none in API!')
            self.connector = connector
            self.sysid = sysid
            self.tenantid = tenantid

        def list(self):
            '''
            Get all nodes in the current system/tenant

            :return: list of tuples (uuid, hostname)
            '''
            nodes = self.connector.glob.actual.get_all_nodes(
                self.sysid, self.tenantid)
            return nodes

        def info(self, node_uuid):
            """
            Provide all information about a specific node

            :param node_uuid: the uuid of the node you want info
            :return: a dictionary with all information about the node
            """
            if node_uuid is None:
                return None
            node_info = self.connector.glob.actual.get_node_info(
                self.sysid, self.tenantid, node_uuid)
            return node_info

        def status(self, node_uuid):
            """
            Provide all status information about a specific node,
            including network neighbors

            :param node_uuid: the uuid of the node you want info
            :return: a dictionary with all information about the node
            """
            if node_uuid is None:
                return None
            node_status = self.connector.glob.actual.get_node_status(
                self.sysid, self.tenantid, node_uuid)
            return node_status

        def plugins(self, node_uuid):
            '''

            Get the list of plugin installed on the specified node

            :param node_uuid: the uuid of the node you want info
            :return: a list of the plugins installed in the node with
            detailed informations

            '''
            plugins = self.connector.glob.actual.get_all_plugins_ids(
                self.sysid, self.tenantid, node_uuid)
            return plugins

        def search(self, search_dict):
            '''

            Will search for a node that match information provided
             in the parameter

            :param search_dict: dictionary contains all information to match
            :return: a list of node matching the dictionary
            '''
            pass

    class Plugin(object):
        '''
        This class encapsulates the commands for Plugin interaction

        '''
        def __init__(self,
                     connector=None,
                     sysid=Constants.default_system_id,
                     tenantid=Constants.default_tenant_id):

            if connector is None:
                raise RuntimeError('Yaks connector cannot be none in API!')
            self.connector = connector
            self.sysid = sysid
            self.tenantid = tenantid

        def add(self, manifest, node_uuid=None):
            '''

            Add a plugin to a node or to all node in the system/tenant

            :param manifest: the dictionary representing the plugin manifest
            :param node_uuid: optional the node in which add the plugin
            :return: boolean
            '''

            # manifest.update({'status': 'add'})
            # plugins = {"plugins": [manifest]}
            # plugins = json.dumps(plugins)
            # if node_uuid is None:
            #     uri = '{}/*/plugins'.format(self.store.droot)
            # else:
            #     uri = '{}/{}/plugins'.format(self.store.droot, node_uuid)

            # res = self.store.desired.dput(uri, plugins)
            # if res:
            #     return True
            # else:
            #     return False
            pass

        def remove(self, plugin_uuid, node_uuid=None):
            '''

            Will remove a plugin for a node or all nodes

            :param plugin_uuid: the plugin you want to remove
            :param node_uuid: optional the node that will remove the plugin
            :return: boolean
            '''
            pass

        def info(self, node_uuid, pluginid):
            '''

            Same as API.Node.Plugins but can work for all node un the system,
            \return a dictionary with key node uuid and value the plugin list

            :param node_uuid: can be none
            :return: dictionary {node_uuid, plugin list }
            '''
            if node_uuid is not None:
                return self.connector.glob.actual.get_plugin_info(
                    self.sysid, self.tenantid, node_uuid, pluginid)
            return None

        def search(self, search_dict, node_uuid=None):
            '''

            Will search for a plugin matching the dictionary in a
             single node or in all nodes

            :param search_dict: dictionary contains all information to match
            :param node_uuid: optional node uuid in which search
            :return: a dictionary with {node_uuid, plugin uuid list} with
             matches
            '''
            pass

    class Network(object):
        '''

        This class encapsulates the command for Network element interaction

        '''
        def __init__(self,
                     connector=None,
                     sysid=Constants.default_system_id,
                     tenantid=Constants.default_tenant_id):

            if connector is None:
                raise RuntimeError('Yaks connector cannot be none in API!')
            self.connector = connector
            self.sysid = sysid
            self.tenantid = tenantid

        def __get_all_node_plugin(self, node_uuid):
            pass
            # uri = '{}/{}/plugins'.format(self.store.aroot, node_uuid)
            # response = self.store.actual.resolve(uri)
            # if response is not None and response != '':
            #     return json.loads(response).get('plugins')
            # else:
            #     return None

        def add_network(self, manifest):
            '''

            Add a network element to a node o to all nodes


            :param manifest: dictionary representing the manifest of
             that network element
            :param node_uuid: optional the node uuid in which add
            the network element
            :return: boolean
            '''

            manifest.update({'status': 'add'})
            net_id = manifest.get('uuid')

            self.connector.glob.desired.add_network(self.sysid, self.tenantid,
                                                    net_id, manifest)

        def remove_network(self, net_uuid):
            '''

            Remove a network element form one or all nodes

            :param net_uuid: uuid of the network you want to remove
            :param node_uuid: optional node from which remove
             the network element
            :return: boolean
            '''
            manifest = self.connector.glob.actual.get_network(
                self.sysid, self.tenantid, net_uuid)
            manifest.update({'status': 'remove'})
            self.connector.glob.desired.remove_network(self.sysid,
                                                       self.tenantid, net_uuid)

        def add_connection_point(self, cp_descriptor):
            cp_descriptor.update({'status': 'add'})
            cp_id = cp_descriptor.get('uuid')
            self.connector.glob.desired.add_network_port(
                self.sysid, self.tenantid, cp_id, cp_descriptor)

        def delete_connection_point(self, cp_uuid):
            manifest = self.connector.glob.actual.get_network_port(
                self.sysid, self.tenantid, cp_uuid)
            manifest.update({'status': 'remove'})
            self.connector.glob.desired.add_network_port(
                self.sysid, self.tenantid, cp_uuid, manifest)

        def connect_cp_to_network(self, cp_uuid, net_uuid):
            pass

        def disconnect_cp(self, cp_uuid):
            pass

        def list(self):
            '''

            List all network element available in the system/teneant or in a
             specified node

            :param node_uuid: optional node uuid
            :return: dictionary {network uuid:
             {network manifest dictionary, pluginid, nodes}}
            '''
            return self.connector.glob.actual.get_all_networks(
                self.sysid, self.tenantid)

        def search(self, search_dict, node_uuid=None):
            '''

            Will search for a network element matching the dictionary in a
             single node or in all nodes

            :param search_dict: dictionary contains all information to match
            :param node_uuid: optional node uuid in which search
            :return: a dictionary
            {node_uuid, network element uuid list} with matches
            '''
            pass

    class FDU(object):
        '''

        This class encapsulates the api for interaction with entities

        '''
        def __init__(self,
                     connector=None,
                     sysid=Constants.default_system_id,
                     tenantid=Constants.default_tenant_id):

            if connector is None:
                raise RuntimeError('Yaks connector cannot be none in API!')
            self.connector = connector
            self.sysid = sysid
            self.tenantid = tenantid

        def __wait_node_fdu_state_change(self, instanceid, state):
            '''

            Function used to wait if an instance changest state
             (eg. configured -> run) or goes to error state

            :param node_uuid
            :param fdu_uuid
            :param state the new expected state

            :return dict {'status':<new status>,
                            'fdu_uuid':fdu_uuid}

            '''

            fdu_info = self.connector.glob.actual.get_node_fdu_instance(
                self.sysid, self.tenantid, '*', instanceid)
            while fdu_info is None:
                fdu_info = self.connector.glob.actual.get_node_fdu_instance(
                    self.sysid, self.tenantid, '*', instanceid)
            es = fdu_info.get('status')
            while es.upper() not in [state, 'ERROR']:
                fdu_info = self.connector.glob.actual.get_node_fdu_instance(
                    self.sysid, self.tenantid, '*', instanceid)
                es = fdu_info.get('status')

            if es.upper() == 'ERROR':
                raise ValueError(
                    'Unable to change state to {} for FDU Instance: {} Errno: {} Msg: {}'
                    .format(state, instanceid, fdu_info.get('error_code'),
                            fdu_info.get('error_msg')))
            return fdu_info

        def __wait_fdu(self, fdu_uuid):
            '''

            Function used to wait if an instance changest state
             (eg. configured -> run) or goes to error state

            :param node_uuid
            :param fdu_uuid
            :param state the new expected state

            :return dict {'status':<new status>,
                            'fdu_uuid':fdu_uuid}

            '''

            local_var = MVar()

            def cb(fdu_info):
                local_var.put(fdu_info)

            fdu_info = self.connector.glob.actual.get_fdu_info(
                self.sysid, self.tenantid, fdu_uuid)
            while fdu_info is None:
                fdu_info = self.connector.glob.actual.get_fdu_info(
                    self.sysid, self.tenantid, fdu_uuid)
            # while fdu_info is None:
            #     fdu_info = local_var.get()
            res = {'fdu_uuid': fdu_uuid}
            return res

        def onboard(self, descriptor, wait=True):
            '''

            Onboard the FDU descriptor in the Catalog
            :param descriptor: the fdu descriptor
            :param wait: make the call wait for completio
            :return the fdu uuid

            '''
            fduid = descriptor.get('uuid')
            if fduid is None:
                fduid = '{}'.format(uuid.uuid4())
            self.connector.glob.desired.add_fdu_info(self.sysid, self.tenantid,
                                                     fduid, descriptor)
            if wait:
                self.__wait_fdu(fduid)
            return fduid

        def offload(self, fdu_uuid, wait=True):
            '''

            Offload the FDU descriptor from the Catalog
            :param fdu_uuid: fdu uuid you want to remove
            :param wait: make the call wait for completion
            :return the fdu uuid

            '''
            res = self.connector.glob.desired.remove_fdu_info(
                self.sysid, self.tenantid, fdu_uuid)
            return fdu_uuid

        def define(self, fduid, node_uuid, wait=True):
            '''

            Defines an FDU instance in a node, this method will check
             the descriptor before sending the definition to the node

            :param fduid: id of the fdu you want to instantiate
            :param node_uuid: destination node uuid
            :param wait: if wait that the definition is complete before
             returning
            :return: instance id
            '''
            desc = self.connector.glob.actual.get_fdu_info(
                self.sysid, self.tenantid, fduid)
            if desc is None:
                raise ValueError('FDU with this UUID not found in the catalog')
            inst_id = '{}'.format(uuid.uuid4())
            record = {
                'fdu_uuid': fduid,
                'node': node_uuid,
                'uuid': inst_id,
                'status': 'DEFINE',
                'interfaces': [],
                'io_ports': [],
                'accelerators': {
                    'fpga': [],
                    'gpu': []
                },
                'connection_points': [],
                'hypervisor_info': {}
            }
            res = self.connector.glob.desired.add_node_fdu(
                self.sysid, self.tenantid, node_uuid, fduid, inst_id, record)
            if wait:
                self.__wait_node_fdu_state_change(inst_id, 'DEFINE')
            return inst_id

        def undefine(self, instanceid, wait=True):
            '''

            This method undefine an FDU instance from a None

            :param instanceid: FDU instance you want to undefine
            :param wait: if wait before returning that the entity is undefined
            :return: instanceid
            '''
            node = self.connector.glob.actual.get_fdu_instance_node(
                self.sysid, self.tenantid, instanceid)
            if node is None:
                raise ValueError('Unable to find node for this instanceid')

            record = self.connector.glob.actual.get_node_fdu_instance(
                self.sysid, self.tenantid, node, instanceid)
            record.update({'status': 'UNDEFINE'})

            fduid = record.get('fdu_uuid')
            self.connector.glob.desired.add_node_fdu(self.sysid, self.tenantid,
                                                     node, fduid, instanceid,
                                                     record)
            return instanceid

        def configure(self, instanceid, wait=True):
            '''

            Configure an FDU instance

            :param instanceid: FDU instance you want to configure
            :param wait: make the function blocking
            :return: instanceid
            '''
            node = self.connector.glob.actual.get_fdu_instance_node(
                self.sysid, self.tenantid, instanceid)
            if node is None:
                raise ValueError('Unable to find node for this instanceid')

            record = self.connector.glob.actual.get_node_fdu_instance(
                self.sysid, self.tenantid, node, instanceid)
            record.update({'status': 'CONFIGURE'})
            fduid = record.get('fdu_uuid')
            res = self.connector.glob.desired.add_node_fdu(
                self.sysid, self.tenantid, node, fduid, instanceid, record)
            if wait:
                self.__wait_node_fdu_state_change(instanceid, 'CONFIGURE')
            return res

        def clean(self, instanceid, wait=True):
            '''

            Clean an FDU instance

            :param instanceid: FDU instance you want to clean
            :param wait: make the function blocking
            :return: instanceid
            '''

            node = self.connector.glob.actual.get_fdu_instance_node(
                self.sysid, self.tenantid, instanceid)
            if node is None:
                raise ValueError('Unable to find node for this instanceid')

            record = self.connector.glob.actual.get_node_fdu_instance(
                self.sysid, self.tenantid, node, instanceid)
            record.update({'status': 'CLEAN'})
            fduid = record.get('fdu_uuid')
            res = self.connector.glob.desired.add_node_fdu(
                self.sysid, self.tenantid, node, fduid, instanceid, record)
            if wait:
                self.__wait_node_fdu_state_change(instanceid, 'DEFINE')
            return res

        def start(self, instanceid, wait=True):
            '''

            Start an FDU instance

            :param instanceid: FDU instance you want to start
            :param wait: make the function blocking
            :return: instanceid
            '''

            node = self.connector.glob.actual.get_fdu_instance_node(
                self.sysid, self.tenantid, instanceid)
            if node is None:
                raise ValueError('Unable to find node for this instanceid')

            record = self.connector.glob.actual.get_node_fdu_instance(
                self.sysid, self.tenantid, node, instanceid)
            record.update({'status': 'RUN'})
            fduid = record.get('fdu_uuid')
            res = self.connector.glob.desired.add_node_fdu(
                self.sysid, self.tenantid, node, fduid, instanceid, record)
            if wait:
                self.__wait_node_fdu_state_change(instanceid, 'RUN')
            return res

        def stop(self, instanceid, wait=True):
            '''

            Stop an FDU instance

            :param instanceid: FDU instance you want to stop
            :param wait: make the function blocking
            :return: instanceid
            '''

            node = self.connector.glob.actual.get_fdu_instance_node(
                self.sysid, self.tenantid, instanceid)
            if node is None:
                raise ValueError('Unable to find node for this instanceid')

            record = self.connector.glob.actual.get_node_fdu_instance(
                self.sysid, self.tenantid, node, instanceid)
            record.update({'status': 'STOP'})
            fduid = record.get('fdu_uuid')
            res = self.connector.glob.desired.add_node_fdu(
                self.sysid, self.tenantid, node, fduid, instanceid, record)
            if wait:
                self.__wait_node_fdu_state_change(instanceid, 'CONFIGURE')
            return res

        def pause(self, instanceid, wait=True):
            '''

            Pause an FDU instance

            :param instanceid: FDU instance you want to pause
            :param wait: make the function blocking
            :return: instanceid
            '''

            node = self.connector.glob.actual.get_fdu_instance_node(
                self.sysid, self.tenantid, instanceid)
            if node is None:
                raise ValueError('Unable to find node for this instanceid')

            record = self.connector.glob.actual.get_node_fdu_instance(
                self.sysid, self.tenantid, node, instanceid)
            record.update({'status': 'PAUSE'})
            fduid = record.get('fdu_uuid')
            res = self.connector.glob.desired.add_node_fdu(
                self.sysid, self.tenantid, node, fduid, instanceid, record)
            if wait:
                self.__wait_node_fdu_state_change(instanceid, 'PAUSE')
            return res

        def resume(self, instanceid, wait=True):
            '''

            Resume an FDU instance

            :param instanceid: FDU instance you want to resume
            :param wait: make the function blocking
            :return: instanceid
            '''

            node = self.connector.glob.actual.get_fdu_instance_node(
                self.sysid, self.tenantid, instanceid)
            if node is None:
                raise ValueError('Unable to find node for this instanceid')

            record = self.connector.glob.actual.get_node_fdu_instance(
                self.sysid, self.tenantid, node, instanceid)
            record.update({'status': 'RESUME'})
            fduid = record.get('fdu_uuid')
            res = self.connector.glob.desired.add_node_fdu(
                self.sysid, self.tenantid, node, fduid, instanceid, record)
            if wait:
                self.__wait_node_fdu_state_change(instanceid, 'RUN')
            return res

        def migrate(self, instanceid, destination_node_uuid, wait=True):
            '''

            Live migrate an instance between two nodes

            The migration is issued when this command is sended,
             there is a little overhead for the copy of the base image and the disk image


            :param instanceid: fdu you want to migrate
            :param destination_node_uuid: destination node
            :param wait: optional wait before returning
            :return: instanceid
            '''

            node = self.connector.glob.actual.get_fdu_instance_node(
                self.sysid, self.tenantid, instanceid)
            if node is None:
                raise ValueError('Unable to find node for this instanceid')
            record = self.connector.glob.actual.get_node_fdu_instance(
                self.sysid, self.tenantid, node, instanceid)
            fduid = record.get('fdu_uuid')
            src_record = record.copy()
            dst_record = record.copy()
            migr_properties = {
                'destination': destination_node_uuid,
                'source': node
            }

            src_record.update({'status': 'TAKE_OFF'})
            dst_record.update({'status': 'LAND'})
            src_record.update({'migration_properties': migr_properties})
            dst_record.update({'migration_properties': migr_properties})

            self.connector.glob.desired.add_node_fdu(self.sysid, self.tenantid,
                                                     destination_node_uuid,
                                                     fduid, instanceid,
                                                     dst_record)
            self.connector.glob.desired.add_node_fdu(self.sysid, self.tenantid,
                                                     node, fduid, instanceid,
                                                     src_record)

            if wait:
                self.__wait_node_fdu_state_change(instanceid, 'RUN')
            return instanceid

        def instantiate(self, fduid, nodeid, wait=True):
            '''
            Instantiate (define, configure, start) an fdu in a node

            :param fduid: id of the fdu to instantiate
            :param nodeid: node where instantiate
            :return instance uuid
            '''
            instance_id = self.define(fduid, nodeid)
            self.configure(instance_id)
            self.start(instance_id)
            return instance_id

        def terminate(self, instanceid, wait=True):
            '''
            Terminate (stop, clean, undefine) an instance

            :param instanceid: instance you want to terminate
            :return instance uuid
            '''

            self.stop(instanceid)
            self.clean(instanceid)
            return self.undefine(instanceid)

        def search(self, search_dict, node_uuid=None):
            pass

        def info(self, fdu_uuid):
            # uri = '{}/*/runtime/*/entity/{}/instance/**'.format(self.store.aroot, entity_uuid)
            # info = self.store.actual.getAll(uri)
            # if info is None or len(info) == 0:
            #     return {}
            # i = {}
            # for e in info:
            #     k = e[0]
            #     v = e[1]
            #     i_uuid = k.split('/')[-1]
            #     i.update({i_uuid: v})
            # return {entity_uuid: i}
            return self.connector.glob.actual.get_fdu_info(
                self.sysid, self.tenantid, fdu_uuid)

        def instance_info(self, instanceid):
            '''
            Information about an instance

            :param instanceid: instance id

            :return dict containing the fdu record and hypervisor informations

            '''
            return self.connector.glob.actual.get_node_fdu_instance(
                self.sysid, self.tenantid, "*", instanceid)

        def get_nodes(self, fdu_uuid):
            '''

                List of nodes where the fdu is running
                :param fdu_uuid fdu you want to find the nodes
                :return: node_uuid list

            '''
            return self.connector.glob.actual.get_fdu_nodes(
                self.sysid, self.tenantid, fdu_uuid)

        def list_node(self, node_uuid):
            '''

                List of fdu in the node
                :param node_uuid node you want to list the fdus
                :return: fdu_uuid list

            '''
            return self.connector.glob.actual.get_node_fdus(
                self.sysid, self.tenantid, node_uuid)

        def instance_list(self, fduid):
            '''
                List of instances for an FDU

                :param fduid
                :return dictionary of {node_id: [instances list]}
            '''
            infos = self.connector.glob.actual.get_node_fdu_instances(
                self.sysid, self.tenantid, "*", fduid)
            nodes = list(dict.fromkeys(list(map(lambda x: x[0], infos))))
            res = {}
            for n in nodes:
                insts = []
                for ii in infos:
                    if ii[0] == n:
                        insts.append(ii[2])
                res.update({n: insts})
            return res

        def list(self, node_uuid='*'):
            '''

            List all entity element available in the system/teneant
             or in a specified node

            :param node_uuid: optional node uuid
            :return: dictionary {node uuid: {entity uuid: instance list} list}
            '''
            return self.connector.glob.actual.get_all_fdus(
                self.sysid, self.tenantid)

    class Image(object):
        '''

        This class encapsulates the action on images


        '''
        def __init__(self,
                     connector=None,
                     sysid=Constants.default_system_id,
                     tenantid=Constants.default_tenant_id):

            if connector is None:
                raise RuntimeError('Yaks connector cannot be none in API!')
            self.connector = connector
            self.sysid = sysid
            self.tenantid = tenantid

        def __search_plugin_by_name(self, name, node_uuid):
            # uri = '{}/{}/plugins'.format(self.store.aroot, node_uuid)
            # all_plugins = self.store.actual.resolve(uri)
            # if all_plugins is None or all_plugins == '':
            #     print('Cannot get plugin')
            #     return None
            # all_plugins = json.loads(all_plugins).get('plugins')
            # search = [x for x in all_plugins if name.upper() in x.get('name').upper()]
            # if len(search) == 0:
            #     return None
            # else:
            #     return search[0]
            pass

        def __get_entity_handler_by_uuid(self, node_uuid, entity_uuid):
            # uri = '{}/{}/runtime/*/entity/{}'.format(self.store.aroot, node_uuid, entity_uuid)
            # all = self.store.actual.resolveAll(uri)
            # for i in all:
            #     k = i[0]
            #     if fnmatch.fnmatch(k, uri):
            #         # print('MATCH {0}'.format(k))
            #         # print('Extracting uuid...')
            #         regex = uri.replace('/', '\/')
            #         regex = regex.replace('*', '(.*)')
            #         reobj = re.compile(regex)
            #         mobj = reobj.match(k)
            #         uuid = mobj.group(1)
            #         # print('UUID {0}'.format(uuid))

            #         return uuid
            pass

        def __get_entity_handler_by_type(self, node_uuid, t):
            # handler = None
            # handler = self.__search_plugin_by_name(t, node_uuid)
            # if handler is None:
            #     print('type not yet supported')
            # return handler
            pass

        def add(self, descriptor):
            '''

            Adding an image to a node or to all nodes

            :param manifest: dictionary representing the manifest for the image
            :param node_uuid: optional node in which add the image
            :return: boolean
            '''
            # manifest.update({'status': 'add'})
            # json_data = json.dumps(manifest)
            # if node_uuid is None:
            #     uri = '{}/*/runtime/*/image/{}'.format(
            #         self.store.droot, manifest.get('uuid'))
            # else:
            #     handler = None
            #     t = manifest.get('type')
            #     if t in ['kvm', 'xen']:
            #         handler = self.__search_plugin_by_name(t, node_uuid)
            #     elif t in ['container', 'lxd', 'docker']:
            #         handler = self.__search_plugin_by_name(t, node_uuid)
            #     else:
            #         print('type not recognized')
            #     if handler is None or handler == 'None':
            #         print('Handler not found!! (Is none)')
            #         return False
            #     if handler.get('uuid') is None:
            #         print('Handler not found!! (Cannot get handler uuid)')
            #         return False
            #     uri = '{}/{}/runtime/{}/image/{}'.format(
            #         self.store.droot, node_uuid, handler.get('uuid'), manifest.get('uuid'))
            # res = self.store.desired.put(uri, json_data)
            # if res:
            #     return True
            # else:
            #     return False
            img_id = descriptor.get('uuid')
            res = self.connector.glob.desired.add_image(
                self.sysid, self.tenantid, img_id, descriptor)
            return img_id

        def add_from_rest(self, descriptor):
            '''

            Registering an image in yaks

            :param descriptor: dictionary representing the manifest for the image
            :return: image uuid
            '''

            img_id = descriptor.get('uuid')
            res = self.connector.glob.actual.add_image(self.sysid,
                                                       self.tenantid, img_id,
                                                       descriptor)
            return img_id

        def get(self, image_uuid):
            return self.connector.glob.actual.get_image(
                self.sysid, self.tenantid, image_uuid)

        def remove(self, image_uuid):
            '''

            Remove an image for a node or all nodes

            :param image_uuid: image you want to remove
            :param node_uuid: optional node from which remove the image
            :return: boolean
            '''

            # if node_uuid is None:
            #     uri = '{}/*/runtime/*/image/{}#status=undefine'.format(
            #         self.store.droot, image_uuid)
            # else:
            #     uri = '{}/{}/runtime/*/image/{}#status=undefine'.format(
            #         self.store.droot, node_uuid, image_uuid)
            # res = self.store.desired.dput(uri)
            # if res:
            #     return True
            # else:
            #     return False
            ret = self.connector.glob.desired.remove_image(
                self.sysid, self.tenantid, image_uuid)
            return image_uuid

        def search(self, search_dict, node_uuid=None):
            pass

        def list(self):
            '''

            List available entity images

            :param node_uuid: optional node id
            :return: dictionaty {nodeid: {runtimeid: [images list]}}
            '''

            # uri = '{}/*/runtime/*/image/**'.format(self.store.aroot)
            # if node_uuid:
            #     uri = '{}/{}/runtime/*/image/**'.format(
            #         self.store.aroot, node_uuid)
            # data = self.store.actual.getAll(uri)
            # images = {}
            # for i in data:
            #     nodeid = i[0].split('/')[3]
            #     pluginid = i[0].split('/')[5]
            #     img_data = json.loads(i[1])
            #     imgs = images.get(nodeid, None)
            #     if imgs is None:
            #         images.update({nodeid: {pluginid: [img_data]}})
            #     else:
            #         if pluginid not in imgs.keys():
            #             images.update({nodeid: {pluginid: [img_data]}})
            #         else:
            #             images.get(nodeid).get(pluginid).append(img_data)
            # return images
            return self.connector.glob.actual.get_all_images(
                self.sysid, self.tenantid)

    class Flavor(object):
        '''
          This class encapsulates the action on flavors

        '''
        def __init__(self,
                     connector=None,
                     sysid=Constants.default_system_id,
                     tenantid=Constants.default_tenant_id):

            if connector is None:
                raise RuntimeError('Yaks connector cannot be none in API!')
            self.connector = connector
            self.sysid = sysid
            self.tenantid = tenantid

        def add(self, descriptor):
            '''

            Add a computing flavor to a node or all nodes

            :param manifest: dictionary representing the manifest
             for the flavor
            :param node_uuid: optional node in which add the flavor
            :return: boolean
            '''
            # manifest.update({'status': 'add'})
            # json_data = json.dumps(manifest)
            # if node_uuid is None:
            #     uri = '{}/*/runtime/*/flavor/{}'.format(
            #         self.store.droot, manifest.get('uuid'))
            # else:
            #     uri = '{}/{}/runtime/*/flavor/{}'.format(
            #         self.store.droot, node_uuid, manifest.get('uuid'))
            # res = self.store.desired.put(uri, json_data)
            # if res:
            #     return True
            # else:
            #     return False
            flv_id = descriptor.get('uuid')
            res = self.connector.glob.desired.add_flavor(
                self.sysid, self.tenantid, flv_id, descriptor)
            return flv_id

        def add_from_rest(self, descriptor):
            flv_id = descriptor.get('uuid')
            res = self.connector.glob.actual.add_flavor(
                self.sysid, self.tenantid, flv_id, descriptor)
            return flv_id

        def get(self, flavor_uuid):
            '''

            Add a computing flavor to a node or all nodes

            :param manifest: dictionary representing the manifest
             for the flavor
            :param node_uuid: optional node in which add the flavor
            :return: boolean
            '''
            # manifest.update({'status': 'add'})
            # json_data = json.dumps(manifest)
            # if node_uuid is None:
            #     uri = '{}/*/runtime/*/flavor/{}'.format(
            #         self.store.droot, manifest.get('uuid'))
            # else:
            #     uri = '{}/{}/runtime/*/flavor/{}'.format(
            #         self.store.droot, node_uuid, manifest.get('uuid'))
            # res = self.store.desired.put(uri, json_data)
            # if res:
            #     return True
            # else:
            #     return False
            return self.connector.glob.actual.get_flavor(
                self.sysid, self.tenantid, flavor_uuid)

        def remove(self, flavor_uuid):
            '''

            Remove a flavor from all nodes or a specified node

            :param flavor_uuid: flavor to remove
            :param node_uuid: optional node from which remove the flavor
            :return: boolean
            '''
            # if node_uuid is None:
            #     uri = '{}/*/runtime/*/flavor/{}#status=undefine'.format(
            #         self.store.droot, flavor_uuid)
            # else:
            #     uri = '{}/{}/runtime/*/flavor/{}#status=undefine'.format(
            #         self.store.droot, node_uuid, flavor_uuid)
            # res = self.store.desired.dput(uri)
            # if res:
            #     return True
            # else:
            #     return False
            ret = self.connector.glob.desired.remove_flavor(
                self.sysid, self.tenantid, flavor_uuid)
            return flavor_uuid

        def list(self):
            '''

            List available entity flavors

            :param node_uuid: optional node id
            :return: dictionaty {nodeid: {runtimeid: [flavor list]}}
            '''
            # uri = '{}/*/runtime/*/flavor/**'.format(self.store.aroot)
            # if node_uuid:
            #     uri = '{}/{}/runtime/*/flavor/**'.format(
            #         self.store.aroot, node_uuid)
            # data = self.store.actual.getAll(uri)
            # flavors = {}
            # for i in data:
            #     nodeid = i[0].split('/')[3]
            #     pluginid = i[0].split('/')[5]
            #     flv_data = json.loads(i[1])
            #     flvs = flavors.get(nodeid, None)
            #     if flvs is None:
            #         flavors.update({nodeid: {pluginid: [flv_data]}})
            #     else:
            #         if pluginid not in flvs.keys():
            #             flavors.update({nodeid: {pluginid: [flv_data]}})
            #         else:
            #             flavors.get(nodeid).get(pluginid).append(flv_data)
            # return flavors
            return self.connector.glob.actual.get_all_flavors(
                self.sysid, self.tenantid)

        def search(self, search_dict, node_uuid=None):
            pass
Exemplo n.º 5
0
class FIMAPI(object):
    '''
    Class: FIMAPI

    This class implements the API to interact with Eclipse fog05 FIM

    attributes
    ----------
    descriptor : Descriptor
        Gives access to the descriptor API
    node : Node
        Gives access to the node API
    plugin : Plugin
        Gives access to the plugin API
    network : Network
        Gives access to the descriptor API
    fdu : FDUAPI
        Gives access to the FDU API
    image : Image
        Gives access to the image API
    flavor : Flavor
        Gives access to the flavor API

    '''

    def __init__(self, locator='127.0.0.1:7447',
                 sysid=Constants.default_system_id,
                 tenantid=Constants.default_tenant_id):

        self.connector = Yaks_Connector(locator)
        self.sysid = sysid
        self.tenantid = tenantid
        self.descriptor = self.Descriptor()
        self.node = self.Node(self.connector, self.sysid, self.tenantid)
        self.plugin = self.Plugin(self.connector, self.sysid, self.tenantid)
        self.network = self.Network(self.connector, self.sysid, self.tenantid)
        self.fdu  = self.FDUAPI(self.connector, self.sysid, self.tenantid)
        self.image = self.Image(self.connector, self.sysid, self.tenantid)
        self.flavor = self.Flavor(self.connector, self.sysid, self.tenantid)


    def close(self):
        '''
        Closes the FIMAPI
        '''
        self.connector.close()

    class Descriptor(object):
        '''
        Class: Descriptor

        This class encapsulates API for descriptors
        '''

        def __init__(self):
            pass

        def check(self, descriptor, descriptor_type):
            '''

            Checks the given descriptor

            parameters
            ----------
            descriptor : dictionary
                the descriptor to be checked
            descriptor_type : API.Descriptor.Type
                type of descriptor

            returns
            -------
            bool
            '''
            # if descriptor_type == self.Type.ENTITY:
            #     t = descriptor.get('type')
            #     try:
            #         if t == 'vm':
            #             validate(descriptor.get('entity_data'),
            #                      Schemas.vm_schema)
            #         elif t == 'container':
            #             validate(descriptor.get('entity_data'),
            #                      Schemas.container_schema)
            #         elif t == 'native':
            #             validate(descriptor.get('entity_data'),
            #                      Schemas.native_schema)
            #         elif t == 'ros2':
            #             validate(descriptor.get('entity_data'),
            #                      Schemas.ros2_schema)
            #         elif t == 'usvc':
            #             return False
            #         else:
            #             return False
            #     except ValidationError as ve:
            #         return False
            # if descriptor_type == self.Type.NETWORK:
            #     try:
            #         validate(descriptor, Schemas.network_schema)
            #     except ValidationError as ve:
            #         return False
            # if descriptor_type == self.Type.ENTITY:
            #     try:
            #         validate(descriptor, Schemas.entity_schema)
            #     except ValidationError as ve:
            #         return False

            return True

        class Type(Enum):
            '''
            Descriptor types
            '''
            ENTITY = 0
            IMAGE = 1
            FLAVOR = 3
            NETWORK = 4
            PLUGIN = 5

    class Node(object):
        '''
        Class: Node
        This class encapsulates API for Nodes
        '''

        def __init__(self, connector=None, sysid=Constants.default_system_id,
                     tenantid=Constants.default_tenant_id):

            if connector is None:
                raise RuntimeError('Yaks connector cannot be none in API!')
            self.connector = connector
            self.sysid = sysid
            self.tenantid = tenantid

        def list(self):
            '''
            Gets all nodes in the current system/tenant

            returns
            -------
            string list

            '''
            nodes = self.connector.glob.actual.get_all_nodes(
                self.sysid, self.tenantid)
            return nodes

        def info(self, node_uuid):
            '''
            Provides all information about the given node

            parameters
            ----------
            node_uuid : string
                UUID of the node

            returns
            -------
            dictionary
            '''
            if node_uuid is None:
                return None
            node_info = self.connector.glob.actual.get_node_info(
                self.sysid, self.tenantid, node_uuid)
            return node_info

        def status(self, node_uuid):
            '''
            Provides all status information about the given node,

            parameters
            ----------
            node_uuid : string
                UUID of the node

            returns
            -------
            dictionary
            '''
            if node_uuid is None:
                return None
            node_status = self.connector.glob.actual.get_node_status(
                self.sysid, self.tenantid, node_uuid)
            return node_status

        def plugins(self, node_uuid):
            '''
            Gets the list of plugins in the given node

            parameters
            ----------
            node_uuid : string
                UUID of the node

            returns
            -------
            string list
            '''
            plugins = self.connector.glob.actual.get_all_plugins_ids(
                self.sysid, self.tenantid, node_uuid)
            return plugins

        def search(self, search_dict):
            '''
            Searches for nodes that satisfies the parameter

            parameters
            ----------
            search_dict : dictionary
                search parameters

            returns
            -------
            string list
            '''
            raise NotImplementedError("Not yet...")

    class Plugin(object):
        '''
        Class: Plugin
        This class encapsulates API for Plugins
        '''

        def __init__(self, connector=None, sysid=Constants.default_system_id,
                     tenantid=Constants.default_tenant_id):

            if connector is None:
                raise RuntimeError('Yaks connector cannot be none in API!')
            self.connector = connector
            self.sysid = sysid
            self.tenantid = tenantid

        def add(self, descriptor, node_uuid):
            '''
            Adds the given plugin to the given node

            parameters
            ----------
            descriptor : dictionary
                the plugin descriptor
            node_uuid : string
                UUID of the node

            returns
            -------
            bool
            '''

            # descriptor.update({'status': 'add'})
            # plugins = {'plugins': [descriptor]}
            # plugins = json.dumps(plugins)
            # if node_uuid is None:
            #     uri = '{}/*/plugins'.format(self.store.droot)
            # else:
            #     uri = '{}/{}/plugins'.format(self.store.droot, node_uuid)

            # res = self.store.desired.dput(uri, plugins)
            # if res:
            #     return True
            # else:
            #     return False
            raise NotImplementedError("Not yet...")

        def remove(self, plugin_uuid, node_uuid):
            '''
            Removes the given plugin from the given node

            parameters
            ----------
            plugin_uuid : string
                UUID of the plugin
            node_uuid : string
                UUID of the node

            returns
            -------
            bool
            '''
            raise NotImplementedError("Not yet...")

        def info(self, plugin_uuid, node_uuid):
            '''
            Gets information about the given plugin in the given node

            parameters
            ----------
            plugin_uuid : string
                UUID of the plugin
            node_uuid : string
                UUID of the node

            returns
            -------
            dictionary
            '''
            return self.connector.glob.actual.get_plugin_info(
                self.sysid, self.tenantid, node_uuid, plugin_uuid)

        def search(self, search_dict, node_uuid=None):
            '''
            Searches for plugin that satisfies the parameter

            parameters
            ----------
            search_dict : dictionary
                search parameters
            node_uuid : string
                optional node UUID where search

            returns
            -------
            string list
            '''
            raise NotImplementedError("Not yet...")

    class Network(object):
        '''
        Class: Plugin
        This class encapsulates API for networks
        '''

        def __init__(self, connector=None, sysid=Constants.default_system_id,
                     tenantid=Constants.default_tenant_id):

            if connector is None:
                raise RuntimeError('Yaks connector cannot be none in API!')
            self.connector = connector
            self.sysid = sysid
            self.tenantid = tenantid

        def add_network(self, descriptor):
            '''
            Registers a network in the system catalog

            Needs at least one node in the system!

            parameters
            ----------
            descriptor : dictionary
                network descriptor

            returns
            -------
            bool
            '''

            descriptor.update({'status': 'add'})
            net_id = descriptor.get('uuid')

            self.connector.glob.desired.add_network(
                self.sysid, self.tenantid, net_id, descriptor)

        def remove_network(self, net_uuid):
            '''
            Removes the given network from the system catalog
            Needs at least one node in the system!

            parameters
            ----------
            net_uuid : string
                UUID of network

            returns
            -------
            bool
            '''
            descriptor = self.connector.glob.actual.get_network(
                self.sysid, self.tenantid, net_uuid)
            if descriptor is None:
                return
            descriptor.update({'status': 'remove'})
            self.connector.glob.desired.remove_network(
                self.sysid, self.tenantid, net_uuid)

        def add_network_to_node(self, descriptor, nodeid):
            '''
            Creates the given virtual network in the given node

            parameters
            ----------
            descriptor : dictionary
                network descriptor
            nodeid : string
                UUID of node

            returns
            -------
            dictionary
            '''
            net_id = descriptor.get('uuid')
            net = self.connector.glob.actual.get_node_network(self.sysid, self.tenantid, nodeid, net_id)
            if net is not None:
                return net
            res = self.connector.glob.actual.create_network_in_node(self.sysid, self.tenantid, nodeid, descriptor)
            if res.get('error') is not None:
                raise ValueError('Got Error {}'.format(res['error']))
            return res['result']

        def remove_network_from_node(self, netid, nodeid):
            '''
            Removes the given virtual network from the given node

            parameters
            ----------
            netid : string
                network uuid
            nodeid : string
                UUID of node

            returns
            -------
            dictionary
            '''
            res = self.connector.glob.actual.remove_network_from_node(self.sysid, self.tenantid, nodeid, netid)
            if res.get('error') is not None:
                raise ValueError('Got Error {}'.format(res['error']))
            return res['result']


        def add_connection_point(self, cp_descriptor):
            '''
            Registers a connection point in the system catalog

            Needs at least one node in the system!

            parameters
            ----------
            descriptor : dictionary
                connection descriptor

            returns
            -------
            bool
            '''
            cp_descriptor.update({'status': 'add'})
            cp_id = cp_descriptor.get('uuid')
            self.connector.glob.desired.add_network_port(
                self.sysid, self.tenantid, cp_id, cp_descriptor)

        def delete_connection_point(self, cp_uuid):
            '''
            Removes the given connection point from the system catalog
            Needs at least one node in the system!

            parameters
            ----------
            cp_uuid : string
                UUID of connection point

            returns
            -------
            bool
            '''
            descriptor = self.connector.glob.actual.get_network_port(
                self.sysid, self.tenantid, cp_uuid)
            descriptor.update({'status': 'remove'})
            self.connector.glob.desired.add_network_port(
                self.sysid, self.tenantid, cp_uuid, descriptor)

        def connect_cp_to_network(self, cp_uuid, net_uuid):
            '''
            Connects the given connection point to the given network

            parameters
            ----------
            cp_uuid : string
                UUID of the connection point
            net_uuid : string
                UUID of the virtual network

            returns
            -------
            string
            '''
            ports = self.connector.glob.actual.get_all_nodes_network_ports(self.sysid, self.tenantid)
            node = None
            port_info = None
            for p in ports:
                n, pid = p
                if pid == cp_uuid:
                    port_info = self.connector.glob.actual.get_node_network_port(self. sysid, self.tenantid, n, pid)
                    node = n
            if node is None or port_info is None:
                raise ValueError('Connection point {} not found'.format(cp_uuid))
            res = self.connector.glob.actual.add_node_port_to_network(self.sysid, self.tenantid, node, port_info['uuid'], net_uuid)
            if res.get('result') is not None:
                return cp_uuid
            raise ValueError('Error connecting: {}'.format(res['error']))

        def disconnect_cp(self, cp_uuid):
            '''
            Disconnects the given connection point

            parameters
            ----------
            cp_uuid : string
                UUID of connection point

            returns
            -------
            string
            '''
            ports = self.connector.glob.actual.get_all_nodes_network_ports(self.sysid, self.tenantid)
            node = None
            port_info = None
            for p in ports:
                n, pid = p
                if pid == cp_uuid:
                    port_info = self.connector.glob.actual.get_node_network_port(self. sysid, self.tenantid, n, pid)
                    node = n
            if node is None or port_info is None:
                raise ValueError('Connection point {} not found'.format(cp_uuid))
            res = self.connector.glob.actual.remove_node_port_from_network(self.sysid, self.tenantid, node, port_info['uuid'])
            if res.get('result') is not None:
                return cp_uuid
            raise ValueError('Error connecting: {}'.format(res['error']))

        def add_router(self, nodeid, descriptor):
            '''
            Creates the given virtual router in the given node

            parameters
            ----------
            descriptor : dictionary
                descriptor of the router
            nodeid : string
                UUID of the node

            returns
            -------
            dictionary
            '''
            router_id = descriptor.get('uuid')
            self.connector.glob.desired.add_node_network_router(
                self.sysid, self.tenantid, nodeid, router_id, descriptor)
            router_info = self.connector.glob.actual.get_node_network_router(
                self.sysid, self.tenantid, nodeid, router_id)
            while router_info is None:
                    router_info = self.connector.glob.actual.get_node_network_router(
                self.sysid, self.tenantid, nodeid, router_id)
            return router_info


        def remove_router(self, node_id, router_id):
            '''
            Removes the given virtual router in the given node

            parameters
            ----------
            router_id : string
                UUID of the router
            node_id : string
                UUID of the node

            returns
            -------
            dictionary
            '''
            self.connector.glob.desired.remove_node_network_router(
                self.sysid, self.tenantid, node_id, router_id)

        def add_router_port(self, nodeid, router_id, port_type, vnet_id=None, ip_address=None):
            '''
            Adds a port to the given virtual router

            parameters
            ----------
            nodeid : string
                UUID of the node
            router_id : string
                UUID of the virtual router
            port_type : string
                kind of the port to be added (INTERNAL, EXTERNAL)
            vnet_id : string
                eventual network to be connected
            ip_address : string
                eventual address for the new router port

            returns
            -------
            dictionary
            '''
            if port_type.upper() not in ['EXTERNAL', 'INTERNAL']:
                raise ValueError('port_type can be only one of : INTERNAL, EXTERNAL')

            port_type = port_type.upper()
            return self.connector.glob.actual.add_port_to_router(self.sysid, self.tenantid, nodeid, router_id, port_type, vnet_id, ip_address)

        def remove_router_port(self, nodeid, router_id, vnet_id):
            '''
            Removes a port from the given router

            parameters
            ----------
            nodeid : string
                UUID of the node
            router_id : string
                UUID of the virtual router
            vnet_id : string
                network to be disconnected

            returns
            -------
            dictionary

            '''
            return self.connector.glob.actual.remove_port_from_router(self.sysid, self.tenantid, nodeid, router_id, vnet_id)



        def create_floating_ip(self, nodeid):
            '''
            Creates a floating IP in the given node

            parameters
            ----------
            nodeid : string
                UUID of the node

            returns
            -------
            dictionary
            '''
            return self.connector.glob.actual.add_node_floatingip(self.sysid, self.tenantid, nodeid)

        def delete_floating_ip(self, nodeid, ip_id):
            '''
            Deletes the given floating IP from the given node

            parameters
            ----------
            nodeid : string
                UUID of the node
            ip_id : string
                UUID of the floating IP

            returns
            -------
            dictionary

            '''
            return self.connector.glob.actual.remove_node_floatingip(self.sysid, self.tenantid, nodeid, ip_id)


        def assign_floating_ip(self, nodeid, ip_id, cp_id):
            '''
            Assigns the given floating IP to the given conncetion point in the given node

            parameters
            ----------
            nodeid : string
                UUID of the node
            ip_id : string
                UUID of the floating IP
            cp_id : string
                UUID of the connection point

            returns
            -------
            dictionary
            '''
            return self.connector.glob.actual.assign_node_floating_ip(self.sysid, self.tenantid, nodeid, ip_id, cp_id)

        def retain_floating_ip(self, nodeid, ip_id, cp_id):
            '''
            Retains the given floating IP from the given connection point in the given node

            parameters
            ----------
            nodeid : string
                UUID of the node
            ip_id : string
                UUID of the floating IP
            cp_id : string
                UUID of the connection point

            returns
            -------
            dictionary
            '''
            return self.connector.glob.actual.retain_node_floating_ip(self.sysid, self.tenantid, nodeid, ip_id, cp_id)

        def list(self):
            '''
            Gets all networks registered in the system catalog

            returns
            -------
            string list
            '''
            return self.connector.glob.actual.get_all_networks(
                self.sysid, self.tenantid)

        def search(self, search_dict, node_uuid=None):
            '''
            Searches for plugin that satisfies the parameter

            parameters
            ----------
            search_dict : dictionary
                search parameters
            node_uuid : string
                optional node UUID where search

            returns
            -------
            string list
            '''
            raise NotImplementedError("Not yet...")

    class FDUAPI(object):
        '''
        Class: FDUAPI
        This class encapsulates API for FDUs
        '''

        def __init__(self, connector=None, sysid=Constants.default_system_id,
                     tenantid=Constants.default_tenant_id):

            if connector is None:
                raise RuntimeError('Yaks connector cannot be none in API!')
            self.connector = connector
            self.sysid = sysid
            self.tenantid = tenantid

        def __wait_node_fdu_state_change(self, instanceid, state):
            '''
            Waits an FDU instance state to change

            parameters
            ----------
            instanceid : string
                UUID of instance
            state : string
                new state

            returns
            --------
            dictionary

            '''

            fdu_info = self.connector.glob.actual.get_node_fdu_instance(
                self.sysid, self.tenantid, '*', instanceid)
            while fdu_info is None:
                    fdu_info = self.connector.glob.actual.get_node_fdu_instance(
                self.sysid, self.tenantid, '*', instanceid)
            fdu = InfraFDU(fdu_info)
            es = fdu.get_status()
            while es.upper() not in [state, 'ERROR']:
                fdu_info = self.connector.glob.actual.get_node_fdu_instance(
                self.sysid, self.tenantid, '*', instanceid)
                fdu = InfraFDU(fdu_info)
                es = fdu.get_status()

            if es.upper() == 'ERROR':
                raise ValueError('Unable to change state to {} for FDU Instance: {} Errno: {} Msg: {}'.format(
                    state, instanceid,fdu_info.get('error_code'), fdu_info.get('error_msg')))
            return fdu_info

        def onboard(self, descriptor):
            '''
            Registers an FDU descriptor in the system catalog
            Needs at least one node in the system!

            parameters
            ----------
            descriptor : FDU
                FDU descriptor

            returns
            -------
            FDU
            '''
            if not isinstance(descriptor, FDU):
                raise ValueError('descriptor should be of type FDU')
            nodes = self.connector.glob.actual.get_all_nodes(self.sysid, self.tenantid)
            if len(nodes) == 0:
                raise SystemError('No nodes in the system!')
            n = random.choice(nodes)

            res = self.connector.glob.actual.onboard_fdu_from_node(self.sysid, self.tenantid, n, descriptor.get_uuid(), descriptor.to_json())
            if res.get('result') is None:
                raise SystemError('Error during onboarding {}'.format(res['error']))
            return FDU(res['result'])


        def offload(self, fdu_uuid):
            '''
            Removes the given FDU from the system catalog
            Needs at least one node in the system!

            parameters
            ----------
            fdu_uuid : string
                UUID of fdu

            returns
            --------
            string
            '''
            res = self.connector.glob.desired.remove_catalog_fdu_info(
                self.sysid, self.tenantid, fdu_uuid)
            # if res.get('result') is None:
            #     raise SystemError('Error during onboarding {}'.format(res['error']))

            return fdu_uuid

        def define(self, fduid, node_uuid, wait=True):
            '''
            Defines the given fdu in the given node

            Instance UUID is system-wide unique

            parameters
            ----------
            fduid : string
                UUID of the FDU
            node_uuid : string
                UUID of the node
            wait : bool
                optional, call will block until FDU is defined
            returns
            -------
            InfraFDU
            '''
            desc = self.connector.glob.actual.get_catalog_fdu_info(
                self.sysid, self.tenantid, fduid)
            if desc is None:
                raise ValueError('FDU with this UUID not found in the catalog')

            res = self.connector.glob.actual.define_fdu_in_node(self.sysid, self.tenantid, node_uuid, fduid)
            if res.get('error') is not None:
                raise ValueError('Got Error {}'.format(res['error']))
            if wait:
                self.__wait_node_fdu_state_change(res['result']['uuid'],'DEFINE')
            return InfraFDU(res['result'])


        def undefine(self, instanceid):
            '''
            Undefines the given instance

            paremeters
            ----------
            instanceid : string
                UUID of instance


            returns
            -------
            string
            '''
            node = self.connector.glob.actual.get_fdu_instance_node(self.sysid, self.tenantid, instanceid)
            if node is None:
                raise ValueError('Unable to find node for this instanceid')

            record = self.connector.glob.actual.get_node_fdu_instance(
                self.sysid, self.tenantid, node, instanceid)

            record = InfraFDU(record)

            record.set_status('UNDEFINE')
            fduid = record.get_fdu_id()

            self.connector.glob.desired.add_node_fdu(self.sysid, self.tenantid, node, fduid, instanceid, record.to_json())
            return instanceid

        def configure(self, instanceid, wait=True):
            '''
            Configures the given instance

            paremeters
            ----------
            instanceid : string
                UUID of instance
            wait : bool
                optional, call will block until FDU is configured

            returns
            -------
            string
            '''
            node = self.connector.glob.actual.get_fdu_instance_node(
                self.sysid, self.tenantid, instanceid)
            if node is None:
                raise ValueError('Unable to find node for this instanceid')

            record = self.connector.glob.actual.get_node_fdu_instance(
                self.sysid, self.tenantid, node, instanceid)

            record = InfraFDU(record)

            record.set_status('CONFIGURE')
            fduid = record.get_fdu_id()

            res = self.connector.glob.desired.add_node_fdu(self.sysid, self.tenantid, node, fduid, instanceid, record.to_json())
            if wait:
                self.__wait_node_fdu_state_change(instanceid,  'CONFIGURE')
            return instanceid

        def clean(self, instanceid, wait=True):
            '''
            Cleans the given instance

            paremeters
            ----------
            instanceid : string
                UUID of instance
            wait : bool
                optional, call will block until FDU is cleaned

            returns
            -------
            string
            '''

            node = self.connector.glob.actual.get_fdu_instance_node(
                self.sysid, self.tenantid, instanceid)
            if node is None:
                raise ValueError('Unable to find node for this instanceid')

            record = self.connector.glob.actual.get_node_fdu_instance(
                self.sysid, self.tenantid, node, instanceid)

            record = InfraFDU(record)

            record.set_status('CLEAN')
            fduid = record.get_fdu_id()

            res = self.connector.glob.desired.add_node_fdu(self.sysid, self.tenantid, node, fduid, instanceid, record.to_json())
            if wait:
                self.__wait_node_fdu_state_change(instanceid,  'DEFINE')
            return instanceid

        def start(self, instanceid, wait=True):
            '''
            Starts the given instance

            paremeters
            ----------
            instanceid : string
                UUID of instance
            wait : bool
                optional, call will block until FDU is started

            returns
            -------
            string
            '''

            node = self.connector.glob.actual.get_fdu_instance_node(
                self.sysid, self.tenantid, instanceid)
            if node is None:
                raise ValueError('Unable to find node for this instanceid')

            record = self.connector.glob.actual.get_node_fdu_instance(
                self.sysid, self.tenantid, node, instanceid)

            record = InfraFDU(record)

            record.set_status('RUN')
            fduid = record.get_fdu_id()

            res = self.connector.glob.desired.add_node_fdu(self.sysid, self.tenantid, node, fduid, instanceid, record.to_json())
            if wait:
                self.__wait_node_fdu_state_change(instanceid,  'RUN')
            return instanceid

        def stop(self, instanceid, wait=True):
            '''
            Stops the given instance

            paremeters
            ----------
            instanceid : string
                UUID of instance
            wait : bool
                optional, call will block until FDU is stopeed

            returns
            -------
            string
            '''

            node = self.connector.glob.actual.get_fdu_instance_node(
                self.sysid, self.tenantid, instanceid)
            if node is None:
                raise ValueError('Unable to find node for this instanceid')

            record = self.connector.glob.actual.get_node_fdu_instance(
                self.sysid, self.tenantid, node, instanceid)

            record = InfraFDU(record)

            record.set_status('STOP')
            fduid = record.get_fdu_id()

            res = self.connector.glob.desired.add_node_fdu(self.sysid, self.tenantid, node, fduid, instanceid, record.to_json())
            if wait:
                self.__wait_node_fdu_state_change(instanceid,  'CONFIGURE')
            return instanceid

        def pause(self, instanceid, wait=True):
            '''
            Pauses the given instance

            paremeters
            ----------
            instanceid : string
                UUID of instance
            wait : bool
                optional, call will block until FDU is paused

            returns
            -------
            string
            '''

            node = self.connector.glob.actual.get_fdu_instance_node(
                self.sysid, self.tenantid, instanceid)
            if node is None:
                raise ValueError('Unable to find node for this instanceid')

            record = self.connector.glob.actual.get_node_fdu_instance(
                self.sysid, self.tenantid, node, instanceid)

            record = InfraFDU(record)

            record.set_status('PAUSE')
            fduid = record.get_fdu_id()

            res = self.connector.glob.desired.add_node_fdu(self.sysid, self.tenantid, node, fduid, instanceid, record.to_json())
            if wait:
                self.__wait_node_fdu_state_change(instanceid,  'PAUSE')
            return instanceid

        def resume(self, instanceid, wait=True):
            '''
            Resumes the given instance

            paremeters
            ----------
            instanceid : string
                UUID of instance
            wait : bool
                optional, call will block until FDU is resumed

            returns
            -------
            string
            '''

            node = self.connector.glob.actual.get_fdu_instance_node(
                self.sysid, self.tenantid, instanceid)
            if node is None:
                raise ValueError('Unable to find node for this instanceid')


            record = self.connector.glob.actual.get_node_fdu_instance(
                self.sysid, self.tenantid, node, instanceid)

            record = InfraFDU(record)

            record.set_status('RESUME')
            fduid = record.get_fdu_id()

            res = self.connector.glob.desired.add_node_fdu(self.sysid, self.tenantid, node, fduid, instanceid, record.to_json())
            if wait:
                self.__wait_node_fdu_state_change(instanceid,  'RUN')
            return instanceid

        def migrate(self, instanceid, destination_node_uuid, wait=True):
            '''
            Migrates the given instance

            paremeters
            ----------
            instanceid : string
                UUID of instance
            destination_node_uuid : string
                UUID of destination node
            wait : bool
                optional, call will block until FDU is migrated

            returns
            -------
            string
            '''

            node = self.connector.glob.actual.get_fdu_instance_node(
                self.sysid, self.tenantid, instanceid)
            if node is None:
                raise ValueError('Unable to find node for this instanceid')
            record = self.connector.glob.actual.get_node_fdu_instance(
                self.sysid, self.tenantid, node, instanceid)

            src_record = InfraFDU(record)
            dst_record = InfraFDU(record)

            fduid = record.get_fdu_id()

            src_record.set_status('TAKE_OFF')
            dst_record.set_status('LAND')

            src_record.set_migration_properties(node, destination_node_uuid)
            dst_record.set_migration_properties(node, destination_node_uuid)


            self.connector.glob.desired.add_node_fdu(self.sysid, self.tenantid,
                                                destination_node_uuid,
                                                fduid, instanceid, dst_record.to_json())
            self.connector.glob.desired.add_node_fdu(self.sysid, self.tenantid,
                                                node, fduid, instanceid, src_record.to_json())

            if wait:
                self.__wait_node_fdu_state_change(instanceid, 'RUN')
            return instanceid


        def instantiate(self, fduid, nodeid, wait=True):
            '''
            Instantiates the given fdu in the given node

            This functions calls: define, configure, start

            Instance UUID is system-wide unique

            parameters
            ----------
            fduid : string
                UUID of the FDU
            node_uuid : string
                UUID of the node
            wait : bool
                optional, call will block until FDU is defined

            returns
            -------
            InfraFDU
            '''
            instance_info = self.define(fduid, nodeid)
            time.sleep(0.5)
            instance_id = instance_info.get_uuid()
            self.configure(instance_id)
            time.sleep(0.5)
            self.start(instance_id)
            return instance_info

        def terminate(self, instanceid, wait=True):
            '''
            Terminates the given instance

            This function calls: stop, clean, undefine

            paremeters
            ----------
            instanceid : string
                UUID of instance


            returns
            -------
            string
            '''

            self.stop(instanceid)
            self.clean(instanceid)
            return self.undefine(instanceid)


        def search(self, search_dict, node_uuid=None):
            '''
            Searches for flavors that satisfies the parameter

            parameters
            ----------
            search_dict : dictionary
                search parameters
            node_uuid : string
                optional node UUID where search

            returns
            -------
            string list
            '''
            raise NotImplementedError("Not yet...")

        def info(self, fdu_uuid):
            '''
            Gets information about the given FDU from the catalog

            parameters
            ----------
            fdu_uuid : string
                UUID of the FDU

            returns
            -------
            FDU
            '''
            data = self.connector.glob.actual.get_catalog_fdu_info(self.sysid, self.tenantid, fdu_uuid)
            fdu = FDU(data)
            return fdu

        def instance_info(self, instanceid):
            '''
            Gets information about the given instance

            parameters
            ----------
            instanceid : string
                UUID of the instance

            returns
            -------
            InfraFDU
            '''

            data = self.connector.glob.actual.get_node_fdu_instance(self.sysid, self.tenantid, '*', instanceid)
            fdu = InfraFDU(data)
            return fdu

        def get_nodes(self, fdu_uuid):
            '''
            Gets all the node in which the given FDU is running

            parameters
            ----------
            fdu_uuid : string
                UUID of the FDU

            returns
            -------
            string list

            '''
            return self.connector.glob.actual.get_fdu_nodes(self.sysid, self.tenantid, fdu_uuid)

        def list_node(self, node_uuid):
            '''
            Gets all the FDUs running in the given node

            parameters
            ---------
            node_uuid : string
                UUID of the node

            returns
            -------
            string list
            '''
            return self.connector.glob.actual.get_node_fdus(self.sysid, self.tenantid, node_uuid)


        def instance_list(self, fduid):
            '''
            Gets all the instances of a given FDU

            parameters
            ----------
            fduid : string
                UUID of the FDU

            returns
            -------
            dictionary
                {node_id: [instances list]}
            '''

            infos = self.connector.glob.actual.get_node_fdu_instances(
                self.sysid, self.tenantid, '*', fduid)
            nodes = list(dict.fromkeys(list(map( lambda x: x[0], infos))))
            res = {}
            for n in nodes:
                insts = []
                for ii in infos:
                    if ii[0] == n:
                        insts.append(ii[2])
                res.update({n:insts})
            return res


        def list(self):
            '''
            Gets all the FDUs registered in the catalog

            returns
            -------
            string list
            '''
            return self.connector.glob.actual.get_catalog_all_fdus(self.sysid, self.tenantid)



    class Image(object):
        '''
        Class: Image
        This class encapsulates API for Images
        '''

        def __init__(self, connector=None, sysid=Constants.default_system_id,
                     tenantid=Constants.default_tenant_id):

            if connector is None:
                raise RuntimeError('Yaks connector cannot be none in API!')
            self.connector = connector
            self.sysid = sysid
            self.tenantid = tenantid


        def add(self, descriptor):
            '''
            Registers an image in the system catalog
            Needs at least one not in the system

            parameters
            ----------
            descriptor : dictionary
                image descriptor

            returns
            -------
            string
            '''

            img_id = descriptor.get('uuid')
            res = self.connector.glob.desired.add_image(self.sysid,
             self.tenantid,img_id, descriptor)
            return img_id

        def get(self, image_uuid):
            '''
            Gets the information about the given image

            parameters
            ----------
            image_uuid : string
                UUID of image

            returns
            -------
            dictionary
            '''
            return self.connector.glob.desired.get_image(self.sysid,
             self.tenantid,image_uuid)

        def remove(self, image_uuid):
            '''
            Removes the given image from the system catalog
            Needs at least one not in the system

            parameters
            ----------
            image_uuid : string

            returns
            -------
            string
            '''

            ret = self.connector.glob.desired.remove_image(self.sysid,
             self.tenantid, image_uuid)
            return image_uuid

        def search(self, search_dict, node_uuid=None):
            '''
            Searches for images that satisfies the parameter

            parameters
            ----------
            search_dict : dictionary
                search parameters
            node_uuid : string
                optional node UUID where search

            returns
            -------
            string list
            '''
            raise NotImplementedError("Not yet...")

        def list(self):
            '''
            Gets all the images registered in the system catalog

            returns
            -------
            string list
            '''

            return self.connector.glob.actual.get_all_images(self.sysid,
             self.tenantid)

    class Flavor(object):
        '''
        Class: Flavor
        This class encapsulates API for Flavors
        '''

        def __init__(self, connector=None, sysid=Constants.default_system_id,
                     tenantid=Constants.default_tenant_id):

            if connector is None:
                raise RuntimeError('Yaks connector cannot be none in API!')
            self.connector = connector
            self.sysid = sysid
            self.tenantid = tenantid

        def add(self, descriptor):
            '''
            Registers a flavor in the system catalog
            Needs at least one node in the system

            parameters
            ----------
            descriptor : dictionary
                flavor descriptor

            returns
            -------
            string
            '''

            flv_id = descriptor.get('uuid')
            res = self.connector.glob.desired.add_flavor(self.sysid,
             self.tenantid,flv_id, descriptor)
            return flv_id

        def get(self, flavor_uuid):
            '''
            Gets information about the given flavor

            parameters
            ----------
            flavor_uuid : string
                UUID of flavor

            returns
            -------
            dictionary

            '''

            return self.connector.glob.desired.get_flavor(self.sysid,
             self.tenantid,flavor_uuid)

        def remove(self, flavor_uuid):
            '''
            Removes the given flavor from the system catalog
            Needs at least one node in the system

            parameters
            ----------

            flavor_uuid : string
                UUID of flavor

            returns
            -------
            string
            '''

            ret = self.connector.glob.desired.remove_flavor(self.sysid,
             self.tenantid, flavor_uuid)
            return flavor_uuid

        def list(self):
            '''
            Gets all the flavors registered in the system catalog

            returns
            -------
            string list
            '''

            return self.connector.glob.actual.get_all_flavors(self.sysid,
             self.tenantid)

        def search(self, search_dict, node_uuid=None):
            '''
            Searches for flavors that satisfies the parameter

            parameters
            ----------
            search_dict : dictionary
                search parameters
            node_uuid : string
                optional node UUID where search

            returns
            -------
            string list
            '''
            raise NotImplementedError("Not yet...")