Bug 194 - Openstack API v3.3
[osm/RO.git] / vimconn_openstack.py
index c5b4ce1..a114641 100644 (file)
@@ -33,8 +33,10 @@ import yaml
 import logging
 import netaddr
 import time
+import yaml
 
-from novaclient import client as nClient_v2, exceptions as nvExceptions, api_versions as APIVersion
+from novaclient import client as nClient_v2, exceptions as nvExceptions
+from novaclient import api_versions
 import keystoneclient.v2_0.client as ksClient_v2
 from novaclient.v2.client import Client as nClient
 import keystoneclient.v3.client as ksClient
@@ -66,7 +68,7 @@ server_timeout = 60
 
 class vimconnector(vimconn.vimconnector):
     def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None, log_level=None, config={}):
-        '''using common constructor parameters. In this case 
+        '''using common constructor parameters. In this case
         'url' is the keystone authorization url,
         'url_admin' is not use
         '''
@@ -96,6 +98,9 @@ class vimconnector(vimconn.vimconnector):
         if self.osc_api_version == 'v3.3':
             self.k_creds['project_name'] = tenant_name
             self.k_creds['project_id'] = tenant_id
+        if config.get('region_name'):
+            self.k_creds['region_name'] = config.get('region_name')
+            self.n_creds['region_name'] = config.get('region_name')
 
         self.reload_client       = True
         self.logger = logging.getLogger('openmano.vim.openstack')
@@ -179,14 +184,14 @@ class vimconnector(vimconn.vimconnector):
             if len(self.n_creds) <4:
                 raise ksExceptions.ClientException("Not enough parameters to connect to openstack")
             if self.osc_api_version == 'v3.3':
-                self.nova = nClient(APIVersion(version_str='2'), **self.n_creds)
+                self.nova = nClient(api_version=api_versions.APIVersion(version_str='2.0'), **self.n_creds)
                 #TODO To be updated for v3
                 #self.cinder = cClient.Client(**self.n_creds)
                 self.keystone = ksClient.Client(**self.k_creds)
                 self.ne_endpoint=self.keystone.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
-                self.neutron = neClient.Client(APIVersion(version_str='2'), endpoint_url=self.ne_endpoint, token=self.keystone.auth_token, **self.k_creds)
+                self.neutron = neClient.Client(api_version=api_versions.APIVersion(version_str='2.0'), endpoint_url=self.ne_endpoint, token=self.keystone.auth_token, **self.k_creds)
             else:
-                self.nova = nClient_v2.Client('2', **self.n_creds)
+                self.nova = nClient_v2.Client(version='2', **self.n_creds)
                 self.cinder = cClient_v2.Client(**self.n_creds)
                 self.keystone = ksClient_v2.Client(**self.k_creds)
                 self.ne_endpoint=self.keystone.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
@@ -562,7 +567,7 @@ class vimconnector(vimconn.vimconnector):
                 #determine format  http://docs.openstack.org/developer/glance/formats.html
                 if "disk_format" in image_dict:
                     disk_format=image_dict["disk_format"]
-                else: #autodiscover base on extention
+                else: #autodiscover based on extension
                     if image_dict['location'][-6:]==".qcow2":
                         disk_format="qcow2"
                     elif image_dict['location'][-4:]==".vhd":
@@ -653,8 +658,8 @@ class vimconnector(vimconn.vimconnector):
             filtered_list = []
             for image in image_list:
                 image_dict=self.glance.images.get(image.id)
-                if image_dict['checksum']==filter_dict.get('checksum'):
-                    filtered_list.append(image)
+                if 'checksum' not in filter_dict or image_dict['checksum']==filter_dict.get('checksum'):
+                    filtered_list.append(image_dict)
             return filtered_list
         except (ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError, ConnectionError) as e:
             self._format_exception(e)
@@ -706,7 +711,7 @@ class vimconnector(vimconn.vimconnector):
                         port_dict["name"]=name
                     if net.get("mac_address"):
                         port_dict["mac_address"]=net["mac_address"]
-                    if "port_security" in net:
+                    if net.get("port_security") == False:
                         port_dict["port_security_enabled"]=net["port_security"]
                     new_port = self.neutron.create_port({"port": port_dict })
                     net["mac_adress"] = new_port["port"]["mac_address"]
@@ -733,26 +738,55 @@ class vimconnector(vimconn.vimconnector):
             security_groups   = self.config.get('security_groups')
             if type(security_groups) is str:
                 security_groups = ( security_groups, )
+            #cloud config
+            userdata=None
+            config_drive = None
             if isinstance(cloud_config, dict):
-                userdata="#cloud-config\nusers:\n"
-                #default user
-                if "key-pairs" in cloud_config:
-                    userdata += "  - default:\n    ssh-authorized-keys:\n"
-                    for key in cloud_config["key-pairs"]:
-                        userdata += "      - '{key}'\n".format(key=key)
-                for user in cloud_config.get("users",[]):
-                    userdata += "  - name: {name}\n    sudo: ALL=(ALL) NOPASSWD:ALL\n".format(name=user["name"])
-                    if "user-info" in user:
-                        userdata += "    gecos: {}'\n".format(user["user-info"])
-                    if user.get("key-pairs"):
-                        userdata += "    ssh-authorized-keys:\n"
-                        for key in user["key-pairs"]:
-                            userdata += "      - '{key}'\n".format(key=key)
+                if cloud_config.get("user-data"):
+                    userdata=cloud_config["user-data"]
+                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"):
+                    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 cloud_config:
+                            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
-            else:
-                userdata=None
 
             #Create additional volumes in case these are present in disk_list
             block_device_mapping = None
@@ -790,7 +824,7 @@ class vimconnector(vimconn.vimconnector):
                     #delete ports we just created
                     for net_item  in net_list_vim:
                         if 'port-id' in net_item:
-                            self.neutron.delete_port(net_item['port_id'])
+                            self.neutron.delete_port(net_item['port-id'])
 
                     raise vimconn.vimconnException('Timeout creating volumes for instance ' + name,
                                                    http_code=vimconn.HTTP_Request_Timeout)
@@ -800,10 +834,10 @@ class vimconnector(vimconn.vimconnector):
                                               availability_zone=self.config.get('availability_zone'),
                                               key_name=self.config.get('keypair'),
                                               userdata=userdata,
+                                              config_drive = config_drive,
                                               block_device_mapping = block_device_mapping
                                               )  # , description=description)
             #print "DONE :-)", server
-            
             pool_id = None
             floating_ips = self.neutron.list_floatingips().get("floatingips", ())
             for floating_network in external_network:
@@ -880,7 +914,7 @@ class vimconnector(vimconn.vimconnector):
             # delete ports we just created
             for net_item in net_list_vim:
                 if 'port-id' in net_item:
-                    self.neutron.delete_port(net_item['port_id'])
+                    self.neutron.delete_port(net_item['port-id'])
             self._format_exception(e)
         except TypeError as e:
             raise vimconn.vimconnException(type(e).__name__ + ": "+  str(e), http_code=vimconn.HTTP_Bad_Request)