Extend multipart file to other vim connectors 81/5481/5
authortierno <alfonso.tiernosepulveda@telefonica.com>
Sun, 1 Oct 2017 22:17:43 +0000 (00:17 +0200)
committertierno <alfonso.tiernosepulveda@telefonica.com>
Mon, 2 Oct 2017 16:13:33 +0000 (18:13 +0200)
Change-Id: I6cfae7c08801266387a2d11ce9e97dd799efeb05
Signed-off-by: tierno <alfonso.tiernosepulveda@telefonica.com>
openmanod
osm_ro/vimconn.py
osm_ro/vimconn_aws.py
osm_ro/vimconn_openstack.py

index 841fb7f..4a11b8d 100755 (executable)
--- a/openmanod
+++ b/openmanod
@@ -48,8 +48,8 @@ import osm_ro
 
 __author__ = "Alfonso Tierno, Gerardo Garcia, Pablo Montes"
 __date__ = "$26-aug-2014 11:09:29$"
 
 __author__ = "Alfonso Tierno, Gerardo Garcia, Pablo Montes"
 __date__ = "$26-aug-2014 11:09:29$"
-__version__ = "0.5.25-r535"
-version_date = "Sep 2017"
+__version__ = "0.5.26-r536"
+version_date = "Oct 2017"
 database_version = 27      # expected database schema version
 
 
 database_version = 27      # expected database schema version
 
 
index ea3117d..1f6c4d1 100644 (file)
@@ -32,6 +32,9 @@ import logging
 import paramiko
 import socket
 import StringIO
 import paramiko
 import socket
 import StringIO
+import yaml
+from email.mime.multipart import MIMEMultipart
+from email.mime.text import MIMEText
 
 #Error variables 
 HTTP_Bad_Request = 400
 
 #Error variables 
 HTTP_Bad_Request = 400
@@ -167,7 +170,116 @@ class vimconnector():
             self.url_admin = value
         else:
             raise KeyError("Invalid key '%s'" %str(index))
             self.url_admin = value
         else:
             raise KeyError("Invalid key '%s'" %str(index))
-        
+
+    @staticmethod
+    def _create_mimemultipart(content_list):
+        """Creates a MIMEmultipart text combining the content_list
+        :param content_list: list of text scripts to be combined
+        :return: str of the created MIMEmultipart. If the list is empty returns None, if the list contains only one
+        element MIMEmultipart is not created and this content is returned
+        """
+        if not content_list:
+            return None
+        elif len(content_list) == 1:
+            return content_list[0]
+        combined_message = MIMEMultipart()
+        for content in content_list:
+            if content.startswith('#include'):
+                format = 'text/x-include-url'
+            elif content.startswith('#include-once'):
+                format = 'text/x-include-once-url'
+            elif content.startswith('#!'):
+                format = 'text/x-shellscript'
+            elif content.startswith('#cloud-config'):
+                format = 'text/cloud-config'
+            elif content.startswith('#cloud-config-archive'):
+                format = 'text/cloud-config-archive'
+            elif content.startswith('#upstart-job'):
+                format = 'text/upstart-job'
+            elif content.startswith('#part-handler'):
+                format = 'text/part-handler'
+            elif content.startswith('#cloud-boothook'):
+                format = 'text/cloud-boothook'
+            else:  # by default
+                format = 'text/x-shellscript'
+            sub_message = MIMEText(content, format, sys.getdefaultencoding())
+            combined_message.attach(sub_message)
+        return combined_message.as_string()
+
+    def _create_user_data(self, cloud_config):
+        """
+        Creates a script user database on cloud_config info
+        :param cloud_config: 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)
+        :return: config_drive, userdata. The first is a boolean or None, the second a string or None
+        """
+        config_drive = None
+        userdata = None
+        userdata_list = []
+        if isinstance(cloud_config, dict):
+            if cloud_config.get("user-data"):
+                if isinstance(cloud_config["user-data"], str):
+                    userdata_list.append(cloud_config["user-data"])
+                else:
+                    for u in cloud_config["user-data"]:
+                        userdata_list.append(u)
+            if cloud_config.get("boot-data-drive") != None:
+                config_drive = cloud_config["boot-data-drive"]
+            if cloud_config.get("config-files") or cloud_config.get("users") or cloud_config.get("key-pairs"):
+                userdata_dict = {}
+                # default user
+                if cloud_config.get("key-pairs"):
+                    userdata_dict["ssh-authorized-keys"] = cloud_config["key-pairs"]
+                    userdata_dict["users"] = [{"default": None, "ssh-authorized-keys": cloud_config["key-pairs"]}]
+                if cloud_config.get("users"):
+                    if "users" not in userdata_dict:
+                        userdata_dict["users"] = ["default"]
+                    for user in cloud_config["users"]:
+                        user_info = {
+                            "name": user["name"],
+                            "sudo": "ALL = (ALL)NOPASSWD:ALL"
+                        }
+                        if "user-info" in user:
+                            user_info["gecos"] = user["user-info"]
+                        if user.get("key-pairs"):
+                            user_info["ssh-authorized-keys"] = user["key-pairs"]
+                        userdata_dict["users"].append(user_info)
+
+                if cloud_config.get("config-files"):
+                    userdata_dict["write_files"] = []
+                    for file in cloud_config["config-files"]:
+                        file_info = {
+                            "path": file["dest"],
+                            "content": file["content"]
+                        }
+                        if file.get("encoding"):
+                            file_info["encoding"] = file["encoding"]
+                        if file.get("permissions"):
+                            file_info["permissions"] = file["permissions"]
+                        if file.get("owner"):
+                            file_info["owner"] = file["owner"]
+                        userdata_dict["write_files"].append(file_info)
+                userdata_list.append("#cloud-config\n" + yaml.safe_dump(userdata_dict, indent=4,
+                                                                        default_flow_style=False))
+            userdata = self._create_mimemultipart(userdata_list)
+            self.logger.debug("userdata: %s", userdata)
+        elif isinstance(cloud_config, str):
+            userdata = cloud_config
+        return config_drive, userdata
+
     def check_vim_connectivity(self):
         """Checks VIM can be reached and user credentials are ok.
         Returns None if success or raised vimconnConnectionException, vimconnAuthException, ...
     def check_vim_connectivity(self):
         """Checks VIM can be reached and user credentials are ok.
         Returns None if success or raised vimconnConnectionException, vimconnAuthException, ...
index 3cccbfc..5ee75e4 100644 (file)
@@ -641,52 +641,7 @@ class vimconnector(vimconn.vimconnector):
         try:
             self._reload_connection()
             instance = None
         try:
             self._reload_connection()
             instance = None
-            userdata = None
-            if isinstance(cloud_config, dict):
-                if cloud_config.get("user-data"):
-                    userdata = cloud_config["user-data"]
-                if cloud_config.get("config-files") or cloud_config.get("users") or cloud_config.get("key-pairs"):
-                    if userdata:
-                        raise vimconn.vimconnConflictException(
-                            "Cloud-config cannot contain both 'userdata' and 'config-files'/'users'/'key-pairs'")
-                    userdata_dict = {}
-                    # default user
-                    if cloud_config.get("key-pairs"):
-                        userdata_dict["ssh-authorized-keys"] = cloud_config["key-pairs"]
-                        userdata_dict["users"] = [{"default": None, "ssh-authorized-keys": cloud_config["key-pairs"]}]
-                    if cloud_config.get("users"):
-                        if "users" not in userdata_dict:
-                            userdata_dict["users"] = ["default"]
-                        for user in cloud_config["users"]:
-                            user_info = {
-                                "name": user["name"],
-                                "sudo": "ALL = (ALL)NOPASSWD:ALL"
-                            }
-                            if "user-info" in user:
-                                user_info["gecos"] = user["user-info"]
-                            if user.get("key-pairs"):
-                                user_info["ssh-authorized-keys"] = user["key-pairs"]
-                            userdata_dict["users"].append(user_info)
-
-                    if cloud_config.get("config-files"):
-                        userdata_dict["write_files"] = []
-                        for file in cloud_config["config-files"]:
-                            file_info = {
-                                "path": file["dest"],
-                                "content": file["content"]
-                            }
-                            if file.get("encoding"):
-                                file_info["encoding"] = file["encoding"]
-                            if file.get("permissions"):
-                                file_info["permissions"] = file["permissions"]
-                            if file.get("owner"):
-                                file_info["owner"] = file["owner"]
-                            userdata_dict["write_files"].append(file_info)
-                    userdata = "#cloud-config\n"
-                    userdata += yaml.safe_dump(userdata_dict, indent=4, default_flow_style=False)
-                self.logger.debug("userdata: %s", userdata)
-            elif isinstance(cloud_config, str):
-                userdata = cloud_config
+            _, userdata = self._create_user_data(cloud_config)
 
             if not net_list:
                 reservation = self.conn.run_instances(
 
             if not net_list:
                 reservation = self.conn.run_instances(
index e3d3334..c839d65 100644 (file)
@@ -60,8 +60,6 @@ from httplib import HTTPException
 from neutronclient.neutron import client as neClient
 from neutronclient.common import exceptions as neExceptions
 from requests.exceptions import ConnectionError
 from neutronclient.neutron import client as neClient
 from neutronclient.common import exceptions as neExceptions
 from requests.exceptions import ConnectionError
-from email.mime.multipart import MIMEMultipart
-from email.mime.text import MIMEText
 
 
 """contain the openstack virtual machine status to openmano status"""
 
 
 """contain the openstack virtual machine status to openmano status"""
@@ -635,7 +633,6 @@ class vimconnector(vimconn.vimconnector):
         except (nvExceptions.NotFound, nvExceptions.ClientException, ksExceptions.ClientException, ConnectionError) as e:
             self._format_exception(e)
 
         except (nvExceptions.NotFound, nvExceptions.ClientException, ksExceptions.ClientException, ConnectionError) as e:
             self._format_exception(e)
 
-
     def new_flavor(self, flavor_data, change_name_if_used=True):
         '''Adds a tenant flavor to openstack VIM
         if change_name_if_used is True, it will change name in case of conflict, because it is not supported name repetition
     def new_flavor(self, flavor_data, change_name_if_used=True):
         '''Adds a tenant flavor to openstack VIM
         if change_name_if_used is True, it will change name in case of conflict, because it is not supported name repetition
@@ -848,41 +845,6 @@ class vimconnector(vimconn.vimconnector):
         except (ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError, ConnectionError) as e:
             self._format_exception(e)
 
         except (ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError, ConnectionError) as e:
             self._format_exception(e)
 
-    @staticmethod
-    def _create_mimemultipart(content_list):
-        """Creates a MIMEmultipart text combining the content_list
-        :param content_list: list of text scripts to be combined
-        :return: str of the created MIMEmultipart. If the list is empty returns None, if the list contains only one
-        element MIMEmultipart is not created and this content is returned
-        """
-        if not content_list:
-            return None
-        elif len(content_list) == 1:
-            return content_list[0]
-        combined_message = MIMEMultipart()
-        for content in content_list:
-            if content.startswith('#include'):
-                format = 'text/x-include-url'
-            elif content.startswith('#include-once'):
-                format = 'text/x-include-once-url'
-            elif content.startswith('#!'):
-                format = 'text/x-shellscript'
-            elif content.startswith('#cloud-config'):
-                format = 'text/cloud-config'
-            elif content.startswith('#cloud-config-archive'):
-                format = 'text/cloud-config-archive'
-            elif content.startswith('#upstart-job'):
-                format = 'text/upstart-job'
-            elif content.startswith('#part-handler'):
-                format = 'text/part-handler'
-            elif content.startswith('#cloud-boothook'):
-                format = 'text/cloud-boothook'
-            else:  # by default
-                format = 'text/x-shellscript'
-            sub_message = MIMEText(content, format, sys.getdefaultencoding())
-            combined_message.attach(sub_message)
-        return combined_message.as_string()
-
     def __wait_for_vm(self, vm_id, status):
         """wait until vm is in the desired status and return True.
         If the VM gets in ERROR status, return false.
     def __wait_for_vm(self, vm_id, status):
         """wait until vm is in the desired status and return True.
         If the VM gets in ERROR status, return false.
@@ -1091,58 +1053,7 @@ class vimconnector(vimconn.vimconnector):
             if type(security_groups) is str:
                 security_groups = ( security_groups, )
             #cloud config
             if type(security_groups) is str:
                 security_groups = ( security_groups, )
             #cloud config
-            userdata=None
-            config_drive = None
-            userdata_list = []
-            if isinstance(cloud_config, dict):
-                if cloud_config.get("user-data"):
-                    if isinstance(cloud_config["user-data"], str):
-                        userdata_list.append(cloud_config["user-data"])
-                    else:
-                        for u in cloud_config["user-data"]:
-                            userdata_list.append(u)
-                if cloud_config.get("boot-data-drive") != None:
-                    config_drive = cloud_config["boot-data-drive"]
-                if cloud_config.get("config-files") or cloud_config.get("users") or cloud_config.get("key-pairs"):
-                    userdata_dict={}
-                    #default user
-                    if cloud_config.get("key-pairs"):
-                        userdata_dict["ssh-authorized-keys"] = cloud_config["key-pairs"]
-                        userdata_dict["users"] = [{"default": None, "ssh-authorized-keys": cloud_config["key-pairs"] }]
-                    if cloud_config.get("users"):
-                        if "users" not in userdata_dict:
-                            userdata_dict["users"] = [ "default" ]
-                        for user in cloud_config["users"]:
-                            user_info = {
-                                "name" : user["name"],
-                                "sudo": "ALL = (ALL)NOPASSWD:ALL"
-                            }
-                            if "user-info" in user:
-                                user_info["gecos"] = user["user-info"]
-                            if user.get("key-pairs"):
-                                user_info["ssh-authorized-keys"] = user["key-pairs"]
-                            userdata_dict["users"].append(user_info)
-
-                    if cloud_config.get("config-files"):
-                        userdata_dict["write_files"] = []
-                        for file in cloud_config["config-files"]:
-                            file_info = {
-                                "path" : file["dest"],
-                                "content": file["content"]
-                            }
-                            if file.get("encoding"):
-                                file_info["encoding"] = file["encoding"]
-                            if file.get("permissions"):
-                                file_info["permissions"] = file["permissions"]
-                            if file.get("owner"):
-                                file_info["owner"] = file["owner"]
-                            userdata_dict["write_files"].append(file_info)
-                    userdata_list.append("#cloud-config\n" + yaml.safe_dump(userdata_dict, indent=4,
-                                                                              default_flow_style=False))
-                    userdata = self._create_mimemultipart(userdata_list)
-                self.logger.debug("userdata: %s", userdata)
-            elif isinstance(cloud_config, str):
-                userdata = cloud_config
+            config_drive, userdata = self._create_user_data(cloud_config)
 
             #Create additional volumes in case these are present in disk_list
             base_disk_index = ord('b')
 
             #Create additional volumes in case these are present in disk_list
             base_disk_index = ord('b')