X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=osm_ro%2Fvimconn_vmware.py;h=ad4584476fa29472a92ad4c14a05e1de5fb456db;hb=a15c4b97ee155f7ad78077abed9ec9a5fe88ee10;hp=9faf8b40044d3d6579c237e51d66869a06247303;hpb=5461675ac6705ee92916ed741da1914bd2162482;p=osm%2FRO.git diff --git a/osm_ro/vimconn_vmware.py b/osm_ro/vimconn_vmware.py index 9faf8b40..ad458447 100644 --- a/osm_ro/vimconn_vmware.py +++ b/osm_ro/vimconn_vmware.py @@ -1372,30 +1372,56 @@ class vimconnector(vimconn.vimconnector): return None return None - def new_vminstance(self, name=None, description="", start=False, image_id=None, flavor_id=None, net_list={}, + def new_vminstance(self, name=None, description="", start=False, image_id=None, flavor_id=None, net_list=[], cloud_config=None, disk_list=None, availability_zone_index=None, availability_zone_list=None): """Adds a VM instance to VIM Params: - start: indicates if VM must start or boot in pause mode. Ignored - image_id,flavor_id: image and flavor uuid - net_list: list of interfaces, each one is a dictionary with: - name: - net_id: network uuid to connect - vpci: virtual vcpi to assign - model: interface model, virtio, e2000, ... - mac_address: - use: 'data', 'bridge', 'mgmt' - type: 'virtual', 'PF', 'VF', 'VFnotShared' - vim_id: filled/added by this function - cloud_config: can be a text script to be passed directly to cloud-init, - or an object to inject users and ssh keys with format: - key-pairs: [] list of keys to install to the default user - users: [{ name, key-pairs: []}] list of users to add with their key-pair - #TODO ip, security groups - Returns >=0, the instance identifier - <0, error_text + 'start': (boolean) indicates if VM must start or created in pause mode. + 'image_id','flavor_id': image and flavor VIM id to use for the VM + 'net_list': list of interfaces, each one is a dictionary with: + 'name': (optional) name for the interface. + 'net_id': VIM network id where this interface must be connect to. Mandatory for type==virtual + 'vpci': (optional) virtual vPCI address to assign at the VM. Can be ignored depending on VIM capabilities + 'model': (optional and only have sense for type==virtual) interface model: virtio, e2000, ... + 'mac_address': (optional) mac address to assign to this interface + #TODO: CHECK if an optional 'vlan' parameter is needed for VIMs when type if VF and net_id is not provided, + the VLAN tag to be used. In case net_id is provided, the internal network vlan is used for tagging VF + 'type': (mandatory) can be one of: + 'virtual', in this case always connected to a network of type 'net_type=bridge' + 'PF' (passthrough): depending on VIM capabilities it can be connected to a data/ptp network ot it + can created unconnected + 'VF' (SRIOV with VLAN tag): same as PF for network connectivity. + 'VFnotShared'(SRIOV without VLAN tag) same as PF for network connectivity. VF where no other VFs + are allocated on the same physical NIC + 'bw': (optional) only for PF/VF/VFnotShared. Minimal Bandwidth required for the interface in GBPS + 'port_security': (optional) If False it must avoid any traffic filtering at this interface. If missing + or True, it must apply the default VIM behaviour + After execution the method will add the key: + 'vim_id': must be filled/added by this method with the VIM identifier generated by the VIM for this + interface. 'net_list' is modified + 'cloud_config': (optional) dictionary with: + 'key-pairs': (optional) list of strings with the public key to be inserted to the default user + '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) 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: + 'b64', 'base64', 'gz', 'gz+b64', 'gz+base64', 'gzip+b64', 'gzip+base64' + 'content' (mandatory): string with the content of the file + 'permissions': (optional) string with file permissions, typically octal notation '0644' + 'owner': (optional) file owner, string with the format 'owner:group' + 'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk) + '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 """ - self.logger.info("Creating new instance for entry {}".format(name)) self.logger.debug("desc {} boot {} image_id: {} flavor_id: {} net_list: {} cloud_config {} disk_list {}".format( description, start, image_id, flavor_id, net_list, cloud_config, disk_list)) @@ -1469,7 +1495,7 @@ class vimconnector(vimconn.vimconnector): network_mode = 'bridged' if net_list is not None and len(net_list) > 0: for net in net_list: - if 'use' in net and net['use'] == 'mgmt': + if 'use' in net and net['use'] == 'mgmt' and not primary_net: primary_net = net if primary_net is None: primary_net = net_list[0] @@ -1613,6 +1639,8 @@ class vimconnector(vimconn.vimconnector): if 'net_id' not in net: continue + net_list['vim_id'] = net_list['net_id'] # Provide the same VIM identifier as the VIM network + interface_net_id = net['net_id'] interface_net_name = self.get_network_name_by_id(network_uuid=interface_net_id) interface_network_mode = net['use'] @@ -1696,11 +1724,11 @@ class vimconnector(vimconn.vimconnector): task = vm_obj.ReconfigVM_Task(spec=spec) if task: result = self.wait_for_vcenter_task(task, vcenter_conect) - self.logger.info("Reserved memmoery {} MB for "\ - "VM VM status: {}".format(str(memReserve),result)) + self.logger.info("Reserved memory {} MB for " + "VM VM status: {}".format(str(memReserve), result)) else: - self.logger.info("Fail to reserved memmoery {} to VM {}".format( - str(memReserve),str(vm_obj))) + self.logger.info("Fail to reserved memory {} to VM {}".format( + str(memReserve), str(vm_obj))) self.logger.debug("new_vminstance(): power on vApp {} ".format(name)) @@ -4014,7 +4042,6 @@ class vimconnector(vimconn.vimconnector): "affinity".format(exp)) - def cloud_init(self, vapp, cloud_config): """ Method to inject ssh-key @@ -4035,9 +4062,10 @@ class vimconnector(vimconn.vimconnector): 'owner': (optional) file owner, string with the format 'owner:group' 'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk """ - try: - if isinstance(cloud_config, dict): + if not isinstance(cloud_config, dict): + raise Exception("cloud_init : parameter cloud_config is not a dictionary") + else: key_pairs = [] userdata = [] if "key-pairs" in cloud_config: @@ -4046,68 +4074,94 @@ class vimconnector(vimconn.vimconnector): if "users" in cloud_config: userdata = cloud_config["users"] - for key in key_pairs: - for user in userdata: - if 'name' in user: user_name = user['name'] - if 'key-pairs' in user and len(user['key-pairs']) > 0: - for user_key in user['key-pairs']: - customize_script = """ - #!/bin/bash - echo performing customization tasks with param $1 at `date "+DATE: %Y-%m-%d - TIME: %H:%M:%S"` >> /root/customization.log - if [ "$1" = "precustomization" ];then - echo performing precustomization tasks on `date "+DATE: %Y-%m-%d - TIME: %H:%M:%S"` >> /root/customization.log - if [ ! -d /root/.ssh ];then - mkdir /root/.ssh - chown root:root /root/.ssh - chmod 700 /root/.ssh - touch /root/.ssh/authorized_keys - chown root:root /root/.ssh/authorized_keys - chmod 600 /root/.ssh/authorized_keys - # make centos with selinux happy - which restorecon && restorecon -Rv /root/.ssh - echo '{key}' >> /root/.ssh/authorized_keys - else - touch /root/.ssh/authorized_keys - chown root:root /root/.ssh/authorized_keys - chmod 600 /root/.ssh/authorized_keys - echo '{key}' >> /root/.ssh/authorized_keys - fi - if [ -d /home/{user_name} ];then - if [ ! -d /home/{user_name}/.ssh ];then - mkdir /home/{user_name}/.ssh - chown {user_name}:{user_name} /home/{user_name}/.ssh - chmod 700 /home/{user_name}/.ssh - touch /home/{user_name}/.ssh/authorized_keys - chown {user_name}:{user_name} /home/{user_name}/.ssh/authorized_keys - chmod 600 /home/{user_name}/.ssh/authorized_keys - # make centos with selinux happy - which restorecon && restorecon -Rv /home/{user_name}/.ssh - echo '{user_key}' >> /home/{user_name}/.ssh/authorized_keys - else - touch /home/{user_name}/.ssh/authorized_keys - chown {user_name}:{user_name} /home/{user_name}/.ssh/authorized_keys - chmod 600 /home/{user_name}/.ssh/authorized_keys - echo '{user_key}' >> /home/{user_name}/.ssh/authorized_keys - fi - fi - fi""".format(key=key, user_name=user_name, user_key=user_key) - - for vm in vapp._get_vms(): - vm_name = vm.name - task = vapp.customize_guest_os(vm_name, customization_script=customize_script) - if isinstance(task, GenericTask): - self.vca.block_until_completed(task) - self.logger.info("cloud_init : customized guest os task "\ - "completed for VM {}".format(vm_name)) - else: - self.logger.error("cloud_init : task for customized guest os"\ - "failed for VM {}".format(vm_name)) + self.logger.debug("cloud_init : Guest os customization started..") + customize_script = self.format_script(key_pairs=key_pairs, users_list=userdata) + self.guest_customization(vapp, customize_script) + except Exception as exp: self.logger.error("cloud_init : exception occurred while injecting "\ "ssh-key") raise vimconn.vimconnException("cloud_init : Error {} failed to inject "\ "ssh-key".format(exp)) + def format_script(self, key_pairs=[], users_list=[]): + bash_script = """ + #!/bin/bash + echo performing customization tasks with param $1 at `date "+DATE: %Y-%m-%d - TIME: %H:%M:%S"` >> /root/customization.log + if [ "$1" = "precustomization" ];then + echo performing precustomization tasks on `date "+DATE: %Y-%m-%d - TIME: %H:%M:%S"` >> /root/customization.log + """ + + keys = "\n".join(key_pairs) + if keys: + keys_data = """ + if [ ! -d /root/.ssh ];then + mkdir /root/.ssh + chown root:root /root/.ssh + chmod 700 /root/.ssh + touch /root/.ssh/authorized_keys + chown root:root /root/.ssh/authorized_keys + chmod 600 /root/.ssh/authorized_keys + # make centos with selinux happy + which restorecon && restorecon -Rv /root/.ssh + else + touch /root/.ssh/authorized_keys + chown root:root /root/.ssh/authorized_keys + chmod 600 /root/.ssh/authorized_keys + fi + echo '{key}' >> /root/.ssh/authorized_keys + """.format(key=keys) + + bash_script+= keys_data + + for user in users_list: + if 'name' in user: user_name = user['name'] + if 'key-pairs' in user: + user_keys = "\n".join(user['key-pairs']) + else: + user_keys = None + + add_user_name = """ + useradd -d /home/{user_name} -m -g users -s /bin/bash {user_name} + """.format(user_name=user_name) + + bash_script+= add_user_name + + if user_keys: + user_keys_data = """ + mkdir /home/{user_name}/.ssh + chown {user_name}:{user_name} /home/{user_name}/.ssh + chmod 700 /home/{user_name}/.ssh + touch /home/{user_name}/.ssh/authorized_keys + chown {user_name}:{user_name} /home/{user_name}/.ssh/authorized_keys + chmod 600 /home/{user_name}/.ssh/authorized_keys + # make centos with selinux happy + which restorecon && restorecon -Rv /home/{user_name}/.ssh + echo '{user_key}' >> /home/{user_name}/.ssh/authorized_keys + """.format(user_name=user_name,user_key=user_keys) + + bash_script+= user_keys_data + + return bash_script+"\n\tfi" + + def guest_customization(self, vapp, customize_script): + """ + Method to customize guest os + vapp - Vapp object + customize_script - Customize script to be run at first boot of VM. + """ + for vm in vapp._get_vms(): + vm_name = vm.name + task = vapp.customize_guest_os(vm_name, customization_script=customize_script) + if isinstance(task, GenericTask): + self.vca.block_until_completed(task) + self.logger.info("guest_customization : customized guest os task "\ + "completed for VM {}".format(vm_name)) + else: + self.logger.error("guest_customization : task for customized guest os"\ + "failed for VM {}".format(vm_name)) + raise vimconn.vimconnException("guest_customization : failed to perform"\ + "guest os customization on VM {}".format(vm_name)) def add_new_disk(self, vapp_uuid, disk_size): """