Bug fixed in install-openmano.sh to run config scripts from the appropriate base...
[osm/RO.git] / vimconn_openstack.py
index 76e7e4c..80f47f5 100644 (file)
@@ -31,6 +31,7 @@ import vimconn
 import json
 import yaml
 import logging
+import netaddr
 
 from novaclient import client as nClient, exceptions as nvExceptions
 import keystoneclient.v2_0.client as ksClient
@@ -81,7 +82,7 @@ class vimconnector(vimconn.vimconnector):
             self.k_creds['password'] = passwd
             self.n_creds['api_key']  = passwd
         self.reload_client       = True
-        self.logger = logging.getLogger('mano.vim.openstack')
+        self.logger = logging.getLogger('openmano.vim.openstack')
     
     def __setitem__(self,index, value):
         '''Set individuals parameters 
@@ -223,7 +224,7 @@ class vimconnector(vimconn.vimconnector):
         except (ksExceptions.ConnectionError, ksExceptions.ClientException)  as e:
             self._format_exception(e)
         
-    def new_network(self,net_name,net_type, shared=False, cidr=None, vlan=None):
+    def new_network(self,net_name, net_type, ip_profile=None, shared=False, vlan=None):
         '''Adds a tenant network to VIM. Returns the network identifier'''
         self.logger.debug("Adding a new network to VIM name '%s', type '%s'", net_name, net_type)
         try:
@@ -239,14 +240,38 @@ class vimconnector(vimconn.vimconnector):
             network_dict["shared"]=shared
             new_net=self.neutron.create_network({'network':network_dict})
             #print new_net
-            #create fake subnetwork
-            if not cidr:
-                cidr="192.168.111.0/24"
+            #create subnetwork, even if there is no profile
+            if not ip_profile:
+                ip_profile = {}
+            if 'subnet_address' not in ip_profile:
+                #Fake subnet is required 
+                ip_profile['subnet_address'] = "192.168.111.0/24"
+            if 'ip_version' not in ip_profile: 
+                ip_profile['ip_version'] = "IPv4"
             subnet={"name":net_name+"-subnet",
                     "network_id": new_net["network"]["id"],
-                    "ip_version": 4,
-                    "cidr": cidr
+                    "ip_version": 4 if ip_profile['ip_version']=="IPv4" else 6,
+                    "cidr": ip_profile['subnet_address']
                     }
+            if 'gateway_address' in ip_profile:
+                subnet['gateway_ip'] = ip_profile['gateway_address']
+            if 'dns_address' in ip_profile:
+                #TODO: manage dns_address as a list of addresses separated by commas 
+                subnet['dns_nameservers'] = []
+                subnet['dns_nameservers'].append(ip_profile['dns_address'])
+            if 'dhcp_enabled' in ip_profile:
+                subnet['enable_dhcp'] = False if ip_profile['dhcp_enabled']=="false" else True
+            if 'dhcp_start_address' in ip_profile:
+                subnet['allocation_pools']=[]
+                subnet['allocation_pools'].append(dict())
+                subnet['allocation_pools'][0]['start'] = ip_profile['dhcp_start_address']
+            if 'dhcp_count' in ip_profile:
+                #parts = ip_profile['dhcp_start_address'].split('.')
+                #ip_int = (int(parts[0]) << 24) + (int(parts[1]) << 16) + (int(parts[2]) << 8) + int(parts[3])
+                ip_int = int(netaddr.IPAddress(ip_profile['dhcp_start_address']))
+                ip_int += ip_profile['dhcp_count']
+                ip_str = str(netaddr.IPAddress(ip_int))
+                subnet['allocation_pools'][0]['end'] = ip_str
             self.neutron.create_subnet({"subnet": subnet} )
             return new_net["network"]["id"]
         except (neExceptions.ConnectionFailed, ksExceptions.ClientException, neExceptions.NeutronException) as e:
@@ -421,7 +446,7 @@ class vimconnector(vimconn.vimconnector):
                                 numa_properties["hw:cpu_policy"] = "isolated"
                             for interface in numa.get("interfaces",() ):
                                 if interface["dedicated"]=="yes":
-                                    raise vimconn.HTTP_Service_Unavailable("Passthrough interfaces are not supported for the openstack connector")
+                                    raise vimconn.vimconnException("Passthrough interfaces are not supported for the openstack connector", http_code=vimconn.HTTP_Service_Unavailable)
                                 #TODO, add the key 'pci_passthrough:alias"="<label at config>:<number ifaces>"' when a way to connect it is available
                                 
                 #create flavor                 
@@ -544,7 +569,7 @@ class vimconnector(vimconn.vimconnector):
         except (ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError) as e: 
             self._format_exception(e)
         
-    def new_vminstance(self,name,description,start,image_id,flavor_id,net_list):
+    def new_vminstance(self,name,description,start,image_id,flavor_id,net_list,cloud_config=None):
         '''Adds a VM instance to VIM
         Params:
             start: indicates if VM must start or boot in pause mode. Ignored
@@ -563,7 +588,7 @@ class vimconnector(vimconn.vimconnector):
         '''
         self.logger.debug("Creating VM image '%s' flavor '%s' nics='%s'",image_id, flavor_id,str(net_list))
         try:
-            metadata=[]
+            metadata={}
             net_list_vim=[]
             self._reload_connection()
             metadata_vpci={} #For a specific neutron plugin 
@@ -602,6 +627,11 @@ class vimconnector(vimconn.vimconnector):
                     net_list_vim.append({"port-id": new_port["port"]["id"]})
             if metadata_vpci:
                 metadata = {"pci_assignement": json.dumps(metadata_vpci)}
+                if len(metadata["pci_assignement"]) >255:
+                    #limit the metadata size
+                    #metadata["pci_assignement"] = metadata["pci_assignement"][0:255]
+                    self.logger.warn("Metadata deleted since it exceeds the expected length (255) ")
+                    metadata = {}
             
             self.logger.debug("name '%s' image_id '%s'flavor_id '%s' net_list_vim '%s' description '%s' metadata %s",
                               name, image_id, flavor_id, str(net_list_vim), description, str(metadata))
@@ -609,10 +639,32 @@ class vimconnector(vimconn.vimconnector):
             security_groups   = self.config.get('security_groups')
             if type(security_groups) is str:
                 security_groups = ( security_groups, )
+            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)
+                self.logger.debug("userdata: %s", userdata)
+            elif isinstance(cloud_config, str):
+                userdata = cloud_config
+            else:
+                userdata=None    
+            
             server = self.nova.servers.create(name, image_id, flavor_id, nics=net_list_vim, meta=metadata,
                                               security_groups   = security_groups,
                                               availability_zone = self.config.get('availability_zone'),
                                               key_name          = self.config.get('keypair'),
+                                              userdata=userdata
                                         ) #, description=description)