X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=osm_ro%2Fvimconn.py;h=ea3117d5ab8083e49e277ec1864ecc763f9ca339;hb=a9d51fd27207a54c839192577a921d8623124e77;hp=a9bd9be6c53fe50164db3dbac2758d293ec25594;hpb=2c290ca4088492a3c32bb6ab218d0004da68f6ea;p=osm%2FRO.git diff --git a/osm_ro/vimconn.py b/osm_ro/vimconn.py index a9bd9be6..ea3117d5 100644 --- a/osm_ro/vimconn.py +++ b/osm_ro/vimconn.py @@ -25,10 +25,13 @@ vimconn implement an Abstract class for the vim connector plugins with the definition of the method to be implemented. """ -__author__="Alfonso Tierno" -__date__ ="$16-oct-2015 11:09:29$" +__author__="Alfonso Tierno, Igor D.C." +__date__ ="$14-aug-2017 23:59:59$" import logging +import paramiko +import socket +import StringIO #Error variables HTTP_Bad_Request = 400 @@ -82,6 +85,7 @@ class vimconnNotImplemented(vimconnException): def __init__(self, message, http_code=HTTP_Not_Implemented): vimconnException.__init__(self, message, http_code) + class vimconnector(): """Abstract base class for all the VIM connector plugins These plugins must implement a vimconnector class derived from this @@ -115,6 +119,7 @@ class vimconnector(): self.user = user self.passwd = passwd self.config = config + self.availability_zone = None self.logger = logging.getLogger('openmano.vim') if log_level: self.logger.setLevel( getattr(logging, log_level) ) @@ -232,6 +237,8 @@ class vimconnector(): 'id': (mandatory) VIM network id 'name': (mandatory) VIM network name 'status': (mandatory) can be 'ACTIVE', 'INACTIVE', 'DOWN', 'BUILD', 'ERROR', 'VIM_ERROR', 'OTHER' + 'network_type': (optional) can be 'vxlan', 'vlan' or 'flat' + 'segmentation_id': (optional) in case network_type is vlan or vxlan this field contains the segmentation id 'error_msg': (optional) text that explains the ERROR status other VIM specific fields: (optional) whenever possible using the same naming of filter_dict param List can be empty if no network map the filter_dict. Raise an exception only upon VIM connectivity, @@ -351,8 +358,8 @@ class vimconnector(): """ raise vimconnNotImplemented( "Should have implemented this" ) - def new_vminstance(self, name, description, start, image_id, flavor_id, net_list, cloud_config=None, - disk_list=None): + def new_vminstance(self, name, description, start, image_id, flavor_id, net_list, cloud_config=None, disk_list=None, + availability_zone_index=None, availability_zone_list=None): """Adds a VM instance to VIM Params: 'start': (boolean) indicates if VM must start or created in pause mode. @@ -383,7 +390,8 @@ class vimconnector(): 'users': (optional) list of users to be inserted, each item is a dict with: 'name': (mandatory) user name, 'key-pairs': (optional) list of strings with the public key to be inserted to the user - 'user-data': (optional) string is a text script to be passed directly to cloud-init + 'user-data': (optional) can be a string with the text script to be passed directly to cloud-init, + or a list of strings, each one contains a script to be passed, usually with a MIMEmultipart file 'config-files': (optional). List of files to be transferred. Each item is a dict with: 'dest': (mandatory) string with the destination absolute path 'encoding': (optional, by default text). Can be one of: @@ -395,6 +403,9 @@ class vimconnector(): 'disk_list': (optional) list with additional disks to the VM. Each item is a dict with: 'image_id': (optional). VIM id of an existing image. If not provided an empty disk must be mounted 'size': (mandatory) string with the size of the disk in GB + availability_zone_index: Index of availability_zone_list to use for this this VM. None if not AV required + availability_zone_list: list of availability zones given by user in the VNFD descriptor. Ignore if + availability_zone_index is None Returns the instance identifier or raises an exception on error """ raise vimconnNotImplemented( "Should have implemented this" ) @@ -430,9 +441,9 @@ class vimconnector(): vim_net_id: #network id where this interface is connected, if provided at creation vim_interface_id: #interface/port VIM id ip_address: #null, or text with IPv4, IPv6 address - physical_compute: #identification of compute node where PF,VF interface is allocated - physical_pci: #PCI address of the NIC that hosts the PF,VF - physical_vlan: #physical VLAN used for VF + compute_node: #identification of compute node where PF,VF interface is allocated + pci: #PCI address of the NIC that hosts the PF,VF + vlan: #physical VLAN used for VF """ raise vimconnNotImplemented( "Should have implemented this" ) @@ -456,8 +467,246 @@ class vimconnector(): suffix: extra text, e.g. the http path and query string """ raise vimconnNotImplemented( "Should have implemented this" ) - -#NOT USED METHODS in current version + + def new_classification(self, name, ctype, definition): + """Creates a traffic classification in the VIM + Params: + 'name': name of this classification + 'ctype': type of this classification + 'definition': definition of this classification (type-dependent free-form text) + Returns the VIM's classification ID on success or raises an exception on failure + """ + raise vimconnNotImplemented( "SFC support not implemented" ) + + def get_classification(self, classification_id): + """Obtain classification details of the VIM's classification with ID='classification_id' + Return a dict that contains: + 'id': VIM's classification ID (same as classification_id) + 'name': VIM's classification name + 'type': type of this classification + 'definition': definition of the classification + 'status': 'ACTIVE', 'INACTIVE', 'DOWN', 'BUILD', 'ERROR', 'VIM_ERROR', 'OTHER' + 'error_msg': (optional) text that explains the ERROR status + other VIM specific fields: (optional) whenever possible + Raises an exception upon error or when classification is not found + """ + raise vimconnNotImplemented( "SFC support not implemented" ) + + def get_classification_list(self, filter_dict={}): + """Obtain classifications from the VIM + Params: + 'filter_dict' (optional): contains the entries to filter the classifications on and only return those that match ALL: + id: string => returns classifications with this VIM's classification ID, which implies a return of one classification at most + name: string => returns only classifications with this name + type: string => returns classifications of this type + definition: string => returns classifications that have this definition + tenant_id: string => returns only classifications that belong to this tenant/project + Returns a list of classification dictionaries, each dictionary contains: + 'id': (mandatory) VIM's classification ID + 'name': (mandatory) VIM's classification name + 'type': type of this classification + 'definition': definition of the classification + other VIM specific fields: (optional) whenever possible using the same naming of filter_dict param + List can be empty if no classification matches the filter_dict. Raise an exception only upon VIM connectivity, + authorization, or some other unspecific error + """ + raise vimconnNotImplemented( "SFC support not implemented" ) + + def delete_classification(self, classification_id): + """Deletes a classification from the VIM + Returns the classification ID (classification_id) or raises an exception upon error or when classification is not found + """ + raise vimconnNotImplemented( "SFC support not implemented" ) + + def new_sfi(self, name, ingress_ports, egress_ports, sfc_encap=True): + """Creates a service function instance in the VIM + Params: + 'name': name of this service function instance + 'ingress_ports': set of ingress ports (VIM's port IDs) + 'egress_ports': set of egress ports (VIM's port IDs) + 'sfc_encap': boolean stating whether this specific instance supports IETF SFC Encapsulation + Returns the VIM's service function instance ID on success or raises an exception on failure + """ + raise vimconnNotImplemented( "SFC support not implemented" ) + + def get_sfi(self, sfi_id): + """Obtain service function instance details of the VIM's service function instance with ID='sfi_id' + Return a dict that contains: + 'id': VIM's sfi ID (same as sfi_id) + 'name': VIM's sfi name + 'ingress_ports': set of ingress ports (VIM's port IDs) + 'egress_ports': set of egress ports (VIM's port IDs) + 'status': 'ACTIVE', 'INACTIVE', 'DOWN', 'BUILD', 'ERROR', 'VIM_ERROR', 'OTHER' + 'error_msg': (optional) text that explains the ERROR status + other VIM specific fields: (optional) whenever possible + Raises an exception upon error or when service function instance is not found + """ + raise vimconnNotImplemented( "SFC support not implemented" ) + + def get_sfi_list(self, filter_dict={}): + """Obtain service function instances from the VIM + Params: + 'filter_dict' (optional): contains the entries to filter the sfis on and only return those that match ALL: + id: string => returns sfis with this VIM's sfi ID, which implies a return of one sfi at most + name: string => returns only service function instances with this name + tenant_id: string => returns only service function instances that belong to this tenant/project + Returns a list of service function instance dictionaries, each dictionary contains: + 'id': (mandatory) VIM's sfi ID + 'name': (mandatory) VIM's sfi name + 'ingress_ports': set of ingress ports (VIM's port IDs) + 'egress_ports': set of egress ports (VIM's port IDs) + other VIM specific fields: (optional) whenever possible using the same naming of filter_dict param + List can be empty if no sfi matches the filter_dict. Raise an exception only upon VIM connectivity, + authorization, or some other unspecific error + """ + raise vimconnNotImplemented( "SFC support not implemented" ) + + def delete_sfi(self, sfi_id): + """Deletes a service function instance from the VIM + Returns the service function instance ID (sfi_id) or raises an exception upon error or when sfi is not found + """ + raise vimconnNotImplemented( "SFC support not implemented" ) + + def new_sf(self, name, sfis, sfc_encap=True): + """Creates (an abstract) service function in the VIM + Params: + 'name': name of this service function + 'sfis': set of service function instances of this (abstract) service function + 'sfc_encap': boolean stating whether this service function supports IETF SFC Encapsulation + Returns the VIM's service function ID on success or raises an exception on failure + """ + raise vimconnNotImplemented( "SFC support not implemented" ) + + def get_sf(self, sf_id): + """Obtain service function details of the VIM's service function with ID='sf_id' + Return a dict that contains: + 'id': VIM's sf ID (same as sf_id) + 'name': VIM's sf name + 'sfis': VIM's sf's set of VIM's service function instance IDs + 'sfc_encap': boolean stating whether this service function supports IETF SFC Encapsulation + 'status': 'ACTIVE', 'INACTIVE', 'DOWN', 'BUILD', 'ERROR', 'VIM_ERROR', 'OTHER' + 'error_msg': (optional) text that explains the ERROR status + other VIM specific fields: (optional) whenever possible + Raises an exception upon error or when sf is not found + """ + + def get_sf_list(self, filter_dict={}): + """Obtain service functions from the VIM + Params: + 'filter_dict' (optional): contains the entries to filter the sfs on and only return those that match ALL: + id: string => returns sfs with this VIM's sf ID, which implies a return of one sf at most + name: string => returns only service functions with this name + tenant_id: string => returns only service functions that belong to this tenant/project + Returns a list of service function dictionaries, each dictionary contains: + 'id': (mandatory) VIM's sf ID + 'name': (mandatory) VIM's sf name + 'sfis': VIM's sf's set of VIM's service function instance IDs + 'sfc_encap': boolean stating whether this service function supports IETF SFC Encapsulation + other VIM specific fields: (optional) whenever possible using the same naming of filter_dict param + List can be empty if no sf matches the filter_dict. Raise an exception only upon VIM connectivity, + authorization, or some other unspecific error + """ + raise vimconnNotImplemented( "SFC support not implemented" ) + + def delete_sf(self, sf_id): + """Deletes (an abstract) service function from the VIM + Returns the service function ID (sf_id) or raises an exception upon error or when sf is not found + """ + raise vimconnNotImplemented( "SFC support not implemented" ) + + + def new_sfp(self, name, classifications, sfs, sfc_encap=True, spi=None): + """Creates a service function path + Params: + 'name': name of this service function path + 'classifications': set of traffic classifications that should be matched on to get into this sfp + 'sfs': list of every service function that constitutes this path , from first to last + 'sfc_encap': whether this is an SFC-Encapsulated chain (i.e using NSH), True by default + 'spi': (optional) the Service Function Path identifier (SPI: Service Path Identifier) for this path + Returns the VIM's sfp ID on success or raises an exception on failure + """ + raise vimconnNotImplemented( "SFC support not implemented" ) + + def get_sfp(self, sfp_id): + """Obtain service function path details of the VIM's sfp with ID='sfp_id' + Return a dict that contains: + 'id': VIM's sfp ID (same as sfp_id) + 'name': VIM's sfp name + 'classifications': VIM's sfp's list of VIM's classification IDs + 'sfs': VIM's sfp's list of VIM's service function IDs + 'status': 'ACTIVE', 'INACTIVE', 'DOWN', 'BUILD', 'ERROR', 'VIM_ERROR', 'OTHER' + 'error_msg': (optional) text that explains the ERROR status + other VIM specific fields: (optional) whenever possible + Raises an exception upon error or when sfp is not found + """ + raise vimconnNotImplemented( "SFC support not implemented" ) + + def get_sfp_list(self, filter_dict={}): + """Obtain service function paths from VIM + Params: + 'filter_dict' (optional): contains the entries to filter the sfps on, and only return those that match ALL: + id: string => returns sfps with this VIM's sfp ID , which implies a return of one sfp at most + name: string => returns only sfps with this name + tenant_id: string => returns only sfps that belong to this tenant/project + Returns a list of service function path dictionaries, each dictionary contains: + 'id': (mandatory) VIM's sfp ID + 'name': (mandatory) VIM's sfp name + 'classifications': VIM's sfp's list of VIM's classification IDs + 'sfs': VIM's sfp's list of VIM's service function IDs + other VIM specific fields: (optional) whenever possible using the same naming of filter_dict param + List can be empty if no sfp matches the filter_dict. Raise an exception only upon VIM connectivity, + authorization, or some other unspecific error + """ + raise vimconnNotImplemented( "SFC support not implemented" ) + + def delete_sfp(self, sfp_id): + """Deletes a service function path from the VIM + Returns the sfp ID (sfp_id) or raises an exception upon error or when sf is not found + """ + raise vimconnNotImplemented( "SFC support not implemented" ) + + def inject_user_key(self, ip_addr=None, user=None, key=None, ro_key=None, password=None): + """ + Inject a ssh public key in a VM + Params: + ip_addr: ip address of the VM + user: username (default-user) to enter in the VM + key: public key to be injected in the VM + ro_key: private key of the RO, used to enter in the VM if the password is not provided + password: password of the user to enter in the VM + The function doesn't return a value: + """ + if not ip_addr or not user: + raise vimconnNotSupportedException("All parameters should be different from 'None'") + elif not ro_key and not password: + raise vimconnNotSupportedException("All parameters should be different from 'None'") + else: + commands = {'mkdir -p ~/.ssh/', 'echo "%s" >> ~/.ssh/authorized_keys' % key, + 'chmod 644 ~/.ssh/authorized_keys', 'chmod 700 ~/.ssh/'} + client = paramiko.SSHClient() + try: + if ro_key: + pkey = paramiko.RSAKey.from_private_key(StringIO.StringIO(ro_key)) + else: + pkey = None + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + client.connect(ip_addr, username=user, password=password, pkey=pkey, timeout=10) + for command in commands: + (i, o, e) = client.exec_command(command, timeout=10) + returncode = o.channel.recv_exit_status() + output = o.read() + outerror = e.read() + if returncode != 0: + text = "run_command='{}' Error='{}'".format(command, outerror) + raise vimconnUnexpectedResponse("Cannot inject ssh key in VM: '{}'".format(text)) + return + except (socket.error, paramiko.AuthenticationException, paramiko.SSHException) as message: + raise vimconnUnexpectedResponse( + "Cannot inject ssh key in VM: '{}' - {}".format(ip_addr, str(message))) + return + + +#NOT USED METHODS in current version def host_vim2gui(self, host, server_dict): """Transform host dictionary from VIM format to GUI format,