import logging
import netaddr
import time
+import yaml
from novaclient import client as nClient_v2, exceptions as nvExceptions, api_versions as APIVersion
import keystoneclient.v2_0.client as ksClient_v2
#global var to have a timeout creating and deleting volumes
volume_timeout = 60
+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={}):
self.k_creds={}
self.n_creds={}
+ if self.config.get("insecure"):
+ self.k_creds["insecure"] = True
+ self.n_creds["insecure"] = True
if not url:
raise TypeError, 'url param can not be NoneType'
self.k_creds['auth_url'] = url
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')
#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":
#Then we filter by the rest of filter fields: checksum
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)
+ image_class=self.glance.images.get(image.id)
+ if 'checksum' not in filter_dict or image_class['checksum']==filter_dict.get('checksum'):
+ filtered_list.append(image_class.copy())
return filtered_list
except (ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError, ConnectionError) as e:
self._format_exception(e)
port_dict["name"]=name
if net.get("mac_address"):
port_dict["mac_address"]=net["mac_address"]
+ 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"]
net["vim_id"] = new_port["port"]["id"]
self.logger.warn("new_vminstance: Warning, can not connect a passthrough interface ")
#TODO insert this when openstack consider passthrough ports as openstack neutron ports
if net.get('floating_ip', False):
+ net['exit_on_floating_ip_error'] = True
+ external_network.append(net)
+ elif net['use'] == 'mgmt' and self.config.get('use_floating_ip'):
+ net['exit_on_floating_ip_error'] = False
external_network.append(net)
-
+
if metadata_vpci:
metadata = {"pci_assignement": json.dumps(metadata_vpci)}
if len(metadata["pci_assignement"]) >255:
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
#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)
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:
- assigned = False
- while(assigned == False):
- if floating_ips:
- ip = floating_ips.pop(0)
- if not ip.get("port_id", False):
- free_floating_ip = ip.get("floating_ip_address")
+ try:
+ # wait until vm is active
+ elapsed_time = 0
+ while elapsed_time < server_timeout:
+ status = self.nova.servers.get(server.id).status
+ if status == 'ACTIVE':
+ break
+ time.sleep(1)
+ elapsed_time += 1
+
+ #if we exceeded the timeout rollback
+ if elapsed_time >= server_timeout:
+ raise vimconn.vimconnException('Timeout creating instance ' + name,
+ http_code=vimconn.HTTP_Request_Timeout)
+
+ assigned = False
+ while(assigned == False):
+ if floating_ips:
+ ip = floating_ips.pop(0)
+ if not ip.get("port_id", False) and ip.get('tenant_id') == server.tenant_id:
+ free_floating_ip = ip.get("floating_ip_address")
+ try:
+ fix_ip = floating_network.get('ip')
+ server.add_floating_ip(free_floating_ip, fix_ip)
+ assigned = True
+ except Exception as e:
+ raise vimconn.vimconnException(type(e).__name__ + ": Cannot create floating_ip "+ str(e), http_code=vimconn.HTTP_Conflict)
+ else:
+ #Find the external network
+ external_nets = list()
+ for net in self.neutron.list_networks()['networks']:
+ if net['router:external']:
+ external_nets.append(net)
+
+ if len(external_nets) == 0:
+ raise vimconn.vimconnException("Cannot create floating_ip automatically since no external "
+ "network is present",
+ http_code=vimconn.HTTP_Conflict)
+ if len(external_nets) > 1:
+ raise vimconn.vimconnException("Cannot create floating_ip automatically since multiple "
+ "external networks are present",
+ http_code=vimconn.HTTP_Conflict)
+
+ pool_id = external_nets[0].get('id')
+ param = {'floatingip': {'floating_network_id': pool_id, 'tenant_id': server.tenant_id}}
try:
+ #self.logger.debug("Creating floating IP")
+ new_floating_ip = self.neutron.create_floatingip(param)
+ free_floating_ip = new_floating_ip['floatingip']['floating_ip_address']
fix_ip = floating_network.get('ip')
server.add_floating_ip(free_floating_ip, fix_ip)
- assigned = True
+ assigned=True
except Exception as e:
- self.delete_vminstance(server.id)
- raise vimconn.vimconnException(type(e).__name__ + ": Cannot create floating_ip "+ str(e), http_code=vimconn.HTTP_Conflict)
- else:
- pool_id = floating_network.get('net_id')
- param = {'floatingip': {'floating_network_id': pool_id}}
- try:
- #self.logger.debug("Creating floating IP")
- new_floating_ip = self.neutron.create_floatingip(param)
- free_floating_ip = new_floating_ip['floatingip']['floating_ip_address']
- fix_ip = floating_network.get('ip')
- server.add_floating_ip(free_floating_ip, fix_ip)
- assigned=True
- except Exception as e:
- self.delete_vminstance(server.id)
- raise vimconn.vimconnException(type(e).__name__ + ": Cannot create floating_ip "+ str(e), http_code=vimconn.HTTP_Conflict)
-
+ raise vimconn.vimconnException(type(e).__name__ + ": Cannot assign floating_ip "+ str(e), http_code=vimconn.HTTP_Conflict)
+ except Exception as e:
+ if not floating_network['exit_on_floating_ip_error']:
+ self.logger.warn("Cannot create floating_ip. %s", str(e))
+ continue
+ self.delete_vminstance(server.id)
+ raise
+
return server.id
# except nvExceptions.NotFound as e:
# error_value=-vimconn.HTTP_Not_Found
# error_text= "vm instance %s not found" % vm_id
- except (ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError
- ) as e:
+ except (ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e:
+ # delete the volumes we just created
+ if block_device_mapping != None:
+ for volume_id in block_device_mapping.itervalues():
+ self.cinder.volumes.delete(volume_id)
+
+ # 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._format_exception(e)
except TypeError as e:
raise vimconn.vimconnException(type(e).__name__ + ": "+ str(e), http_code=vimconn.HTTP_Bad_Request)