# contact with: nfvlabs@tid.es
##
-'''
+"""
vimconn_vmware implementation an Abstract class in order to interact with VMware vCloud Director.
mbayramov@vmware.com
-'''
+"""
from progressbar import Percentage, Bar, ETA, FileTransferSpeed, ProgressBar
import vimconn
import logging
import json
-import vimconn
import time
import uuid
import httplib
+import hashlib
+import socket
+import struct
+import netaddr
# global variable for vcd connector type
STANDALONE = 'standalone'
-# global variable for number of retry
-DELETE_INSTANCE_RETRY = 3
+# key for flavor dicts
+FLAVOR_RAM_KEY = 'ram'
+FLAVOR_VCPUS_KEY = 'vcpus'
+
+DEFAULT_IP_PROFILE = {'gateway_address':"192.168.1.1",
+ 'dhcp_count':50,
+ 'subnet_address':"192.168.1.0/24",
+ 'dhcp_enabled':True,
+ 'dhcp_start_address':"192.168.1.3",
+ 'ip_version':"IPv4",
+ 'dns_address':"192.168.1.2"
+ }
+# global variable for wait time
+INTERVAL_TIME = 5
+MAX_WAIT_TIME = 1800
VCAVERSION = '5.9'
-__author__ = "Mustafa Bayramov"
-__date__ = "$26-Aug-2016 11:09:29$"
+__author__ = "Mustafa Bayramov, Arpita Kate, Sachin Bhangare"
+__date__ = "$23-Dec-2016 11:09:29$"
__version__ = '0.1'
# -1: "Could not be created",
vimconn.vimconnector.__init__(self, uuid, name, tenant_id, tenant_name, url,
url_admin, user, passwd, log_level, config)
- self.id = uuid
+
+ self.logger = logging.getLogger('openmano.vim.vmware')
+ self.logger.setLevel(10)
+
self.name = name
- self.org_name = name
+ self.id = uuid
self.url = url
self.url_admin = url_admin
self.tenant_id = tenant_id
self.config = config
self.admin_password = None
self.admin_user = None
+ self.org_name = ""
- self.logger = logging.getLogger('openmano.vim.vmware')
- self.logger.setLevel(10)
+ if tenant_name is not None:
+ orgnameandtenant = tenant_name.split(":")
+ if len(orgnameandtenant) == 2:
+ self.tenant_name = orgnameandtenant[1]
+ self.org_name = orgnameandtenant[0]
+ else:
+ self.tenant_name = tenant_name
+ elif "orgname" in config:
+ self.org_name = config['orgname']
if log_level:
- self.logger.setLevel( getattr(logging, log_level) )
+ self.logger.setLevel(getattr(logging, log_level))
try:
self.admin_user = config['admin_username']
self.vca = None
if not url:
- raise TypeError, 'url param can not be NoneType'
+ raise vimconn.vimconnException('url param can not be NoneType')
if not self.url_admin: # try to use normal url
self.url_admin = self.url
- logging.debug("Calling constructor with following paramters")
- logging.debug("UUID: {} name: {} tenant_id: {} tenant name {}".format(self.id, self.name,
+ logging.debug("UUID: {} name: {} tenant_id: {} tenant name {}".format(self.id, self.org_name,
self.tenant_id, self.tenant_name))
logging.debug("vcd url {} vcd username: {} vcd password: {}".format(self.url, self.user, self.passwd))
logging.debug("vcd admin username {} vcd admin passowrd {}".format(self.admin_user, self.admin_password))
self.init_organization()
def __getitem__(self, index):
+ if index == 'name':
+ return self.name
if index == 'tenant_id':
return self.tenant_id
if index == 'tenant_name':
return self.tenant_name
elif index == 'id':
return self.id
- elif index == 'name':
- return self.name
elif index == 'org_name':
return self.org_name
elif index == 'org_uuid':
raise KeyError("Invalid key '%s'" % str(index))
def __setitem__(self, index, value):
+ if index == 'name':
+ self.name = value
if index == 'tenant_id':
self.tenant_id = value
if index == 'tenant_name':
self.tenant_name = value
elif index == 'id':
self.id = value
- # we use name = org #TODO later refactor
- elif index == 'name':
- self.name = value
- self.org = value
elif index == 'org_name':
self.org_name = value
- self.name = value
elif index == 'org_uuid':
- self.org_name = value
+ self.org_uuid = value
elif index == 'user':
self.user = value
elif index == 'passwd':
The return vca object that letter can be used to connect to vcloud direct as admin for provider vdc
"""
- self.logger.debug("Logging in to a vca {} as admin.".format(self.name))
+ self.logger.debug("Logging in to a vca {} as admin.".format(self.org_name))
vca_admin = VCA(host=self.url,
username=self.admin_user,
"""
try:
- self.logger.debug("Logging in to a vca {} as {} to datacenter {}.".format(self.name, self.user, self.name))
+ self.logger.debug("Logging in to a vca {} as {} to datacenter {}.".format(self.org_name,
+ self.user,
+ self.org_name))
vca = VCA(host=self.url,
username=self.user,
service_type=STANDALONE,
verify=False,
log=False)
- result = vca.login(password=self.passwd, org=self.name)
+ result = vca.login(password=self.passwd, org=self.org_name)
if not result:
raise vimconn.vimconnConnectionException("Can't connect to a vCloud director as: {}".format(self.user))
- result = vca.login(token=vca.token, org=self.name, org_url=vca.vcloud_session.org_url)
+ result = vca.login(token=vca.token, org=self.org_name, org_url=vca.vcloud_session.org_url)
if result is True:
self.logger.info(
- "Successfully logged to a vcloud direct org: {} as user: {}".format(self.name, self.user))
+ "Successfully logged to a vcloud direct org: {} as user: {}".format(self.org_name, self.user))
except:
- raise vimconn.vimconnConnectionException("Can't connect to a vCloud director as: {}".format(self.user))
+ raise vimconn.vimconnConnectionException("Can't connect to a vCloud director org: "
+ "{} as user: {}".format(self.org_name, self.user))
return vca
self.org_uuid = org
self.logger.debug("Setting organization UUID {}".format(self.org_uuid))
break
-
else:
raise vimconn.vimconnException("Vcloud director organization {} not found".format(self.org_name))
# we have two case if we want to initialize VDC ID or VDC name at run time
# tenant_name provided but no tenant id
- if self.tenant_id is None and self.tenant_name is not None and org_details_dict.has_key('vdcs'):
+ if self.tenant_id is None and self.tenant_name is not None and 'vdcs' in org_details_dict:
vdcs_dict = org_details_dict['vdcs']
for vdc in vdcs_dict:
if vdcs_dict[vdc] == self.tenant_name:
self.tenant_id = vdc
self.logger.debug("Setting vdc uuid {} for organization UUID {}".format(self.tenant_id,
- self.name))
+ self.org_name))
break
else:
raise vimconn.vimconnException("Tenant name indicated but not present in vcloud director.")
# case two we have tenant_id but we don't have tenant name so we find and set it.
- if self.tenant_id is not None and self.tenant_name is None and org_details_dict.has_key('vdcs'):
+ if self.tenant_id is not None and self.tenant_name is None and 'vdcs' in org_details_dict:
vdcs_dict = org_details_dict['vdcs']
for vdc in vdcs_dict:
if vdc == self.tenant_id:
self.tenant_name = vdcs_dict[vdc]
self.logger.debug("Setting vdc uuid {} for organization UUID {}".format(self.tenant_id,
- self.name))
+ self.org_name))
break
else:
raise vimconn.vimconnException("Tenant id indicated but not present in vcloud director")
def new_network(self, net_name, net_type, ip_profile=None, shared=False):
"""Adds a tenant network to VIM
net_name is the name
- net_type can be 'bridge','data'.'ptp'. TODO: this need to be revised
+ net_type can be 'bridge','data'.'ptp'.
ip_profile is a dict containing the IP parameters of the network
shared is a boolean
Returns the network identifier"""
- self.logger.debug(
- "new_network tenant {} net_type {} ip_profile {} shared {}".format(net_name, net_type, ip_profile, shared))
+ self.logger.debug("new_network tenant {} net_type {} ip_profile {} shared {}"
+ .format(net_name, net_type, ip_profile, shared))
isshared = 'false'
if shared:
isshared = 'true'
- network_uuid = self.create_network(network_name=net_name, isshared=isshared)
+ network_uuid = self.create_network(network_name=net_name, net_type=net_type,
+ ip_profile=ip_profile, isshared=isshared)
if network_uuid is not None:
return network_uuid
else:
The return vca object that letter can be used to connect to vcloud direct as admin
"""
- self.logger.debug("get_vcd_network_list(): retrieving network list for vcd")
+ self.logger.debug("get_vcd_network_list(): retrieving network list for vcd {}".format(self.tenant_name))
vca = self.connect()
if not vca:
raise vimconn.vimconnConnectionException("self.connect() is failed.")
+ if not self.tenant_name:
+ raise vimconn.vimconnConnectionException("Tenant name is empty.")
+
vdc = vca.get_vdc(self.tenant_name)
+ if vdc is None:
+ raise vimconn.vimconnConnectionException("Can't retrieve information for a VDC {}".format(self.tenant_name))
+
vdc_uuid = vdc.get_id().split(":")[3]
networks = vca.get_networks(vdc.get_name())
network_list = []
List can be empty
"""
+ self.logger.debug("get_vcd_network_list(): retrieving network list for vcd {}".format(self.tenant_name))
vca = self.connect()
if not vca:
- raise vimconn.vimconnConnectionException("self.connect() is failed")
+ raise vimconn.vimconnConnectionException("self.connect() is failed.")
+
+ if not self.tenant_name:
+ raise vimconn.vimconnConnectionException("Tenant name is empty.")
vdc = vca.get_vdc(self.tenant_name)
- vdcid = vdc.get_id().split(":")[3]
+ if vdc is None:
+ raise vimconn.vimconnConnectionException("Can't retrieve information for a VDC {}.".format(self.tenant_name))
+ vdcid = vdc.get_id().split(":")[3]
networks = vca.get_networks(vdc.get_name())
network_list = []
errormsg = ''
vcd_network = self.get_vcd_network(network_uuid=net)
if vcd_network is not None and vcd_network:
- if vcd_network['status'] == 1:
+ if vcd_network['status'] == '1':
status = 'ACTIVE'
else:
status = 'DOWN'
errormsg = 'Network not found.'
dict_entry[net] = {'status': status, 'error_msg': errormsg,
- 'vm_info': yaml.safe_dump(vcd_network)}
+ 'vim_info': yaml.safe_dump(vcd_network)}
except:
self.logger.debug("Error in refresh_nets_status")
self.logger.debug(traceback.format_exc())
"""Obtain flavor details from the VIM
Returns the flavor dict details {'id':<>, 'name':<>, other vim specific } #TODO to concrete
"""
- if not flavorlist.has_key(flavor_id):
+ if flavor_id not in flavorlist:
raise vimconn.vimconnNotFoundException("Flavor not found.")
return flavorlist[flavor_id]
Returns the used id or raise an exception
"""
- if not flavorlist.has_key(flavor_id):
+ if flavor_id not in flavorlist:
raise vimconn.vimconnNotFoundException("Flavor not found.")
flavorlist.pop(flavor_id, None)
return flavor_id
def new_image(self, image_dict):
- '''
+ """
Adds a tenant image to VIM
Returns:
200, image-id if the image is created
<0, message if there is an error
- '''
+ """
return self.get_image_id_from_path(image_dict['location'])
:param image_id:
:return:
"""
- self.vca;
raise vimconn.vimconnNotImplemented("Should have implemented this")
return False
return self.catalog_exists(catalog_name, catalogs)
+ # noinspection PyIncorrectDocstring
def upload_ovf(self, vca=None, catalog_name=None, image_name=None, media_file_name=None,
description='', progress=False, chunk_bytes=128 * 1024):
"""
Uploads a OVF file to a vCloud catalog
+ :param chunk_bytes:
+ :param progress:
+ :param description:
+ :param image_name:
+ :param vca:
:param catalog_name: (str): The name of the catalog to upload the media.
- :param item_name: (str): The name of the media file in the catalog.
:param media_file_name: (str): The name of the local media file to upload.
:return: (bool) True if the media file was successfully uploaded, false otherwise.
"""
os.path.isfile(media_file_name)
statinfo = os.stat(media_file_name)
- statinfo.st_size
# find a catalog entry where we upload OVF.
# create vApp Template and check the status if vCD able to read OVF it will respond with appropirate
link.get_rel() == 'add', catalog.get_Link())
assert len(link) == 1
data = """
- <UploadVAppTemplateParams name="%s Template" xmlns="http://www.vmware.com/vcloud/v1.5" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"><Description>%s vApp Template</Description></UploadVAppTemplateParams>
- """ % (escape(image_name), escape(description))
+ <UploadVAppTemplateParams name="%s" xmlns="http://www.vmware.com/vcloud/v1.5" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"><Description>%s vApp Template</Description></UploadVAppTemplateParams>
+ """ % (escape(catalog_name), escape(description))
headers = vca.vcloud_session.get_vcloud_headers()
headers['Content-Type'] = 'application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml'
response = Http.post(link[0].get_href(), headers=headers, data=data, verify=vca.verify, logger=self.logger)
# TODO fix this with aync block
time.sleep(5)
- self.logger.debug("Failed create vApp template for catalog name {} and image {}".
- format(catalog_name, media_file_name))
+ self.logger.debug("vApp template for catalog name {} and image {}".format(catalog_name, media_file_name))
# uploading VMDK file
# check status of OVF upload and upload remaining files.
if not vca:
raise vimconn.vimconnConnectionException("self.connect() is failed.")
- if path is None:
+ if not path:
raise vimconn.vimconnException("Image path can't be None.")
if not os.path.isfile(path):
if file_extension != '.ovf':
self.logger.debug("Wrong file extension {} connector support only OVF container.".format(file_extension))
raise vimconn.vimconnException("Wrong container. vCloud director supports only OVF.")
+
catalog_name = os.path.splitext(filename)[0]
- self.logger.debug("File name {} Catalog Name {} file path {}".format(filename, catalog_name, path))
+ catalog_md5_name = hashlib.md5(path).hexdigest()
+ self.logger.debug("File name {} Catalog Name {} file path {} "
+ "vdc catalog name {}".format(filename, catalog_name, path, catalog_md5_name))
catalogs = vca.get_catalogs()
if len(catalogs) == 0:
self.logger.info("Creating a new catalog entry {} in vcloud director".format(catalog_name))
- result = self.create_vimcatalog(vca, catalog_name)
+ result = self.create_vimcatalog(vca, catalog_md5_name)
if not result:
- raise vimconn.vimconnException("Failed create new catalog {} ".format(catalog_name))
- result = self.upload_vimimage(vca=vca, catalog_name=catalog_name,
+ raise vimconn.vimconnException("Failed create new catalog {} ".format(catalog_md5_name))
+ result = self.upload_vimimage(vca=vca, catalog_name=catalog_md5_name,
media_name=filename, medial_file_name=path, progress=progress)
if not result:
raise vimconn.vimconnException("Failed create vApp template for catalog {} ".format(catalog_name))
for catalog in catalogs:
# search for existing catalog if we find same name we return ID
# TODO optimize this
- if catalog.name == catalog_name:
- self.logger.debug("Found existing catalog entry for {} catalog id {}".format(catalog_name,
- self.get_catalogid(
- catalog_name,
- catalogs)))
- return self.get_catalogid(catalog_name, vca.get_catalogs())
+ if catalog.name == catalog_md5_name:
+ self.logger.debug("Found existing catalog entry for {} "
+ "catalog id {}".format(catalog_name,
+ self.get_catalogid(catalog_md5_name, catalogs)))
+ return self.get_catalogid(catalog_md5_name, vca.get_catalogs())
# if we didn't find existing catalog we create a new one and upload image.
- self.logger.debug("Creating new catalog entry".format(catalog_name))
- result = self.create_vimcatalog(vca, catalog_name)
+ self.logger.debug("Creating new catalog entry {} - {}".format(catalog_name, catalog_md5_name))
+ result = self.create_vimcatalog(vca, catalog_md5_name)
if not result:
- raise vimconn.vimconnException("Failed create new catalog {} ".format(catalog_name))
+ raise vimconn.vimconnException("Failed create new catalog {} ".format(catalog_md5_name))
- result = self.upload_vimimage(vca=vca, catalog_name=catalog_name,
+ result = self.upload_vimimage(vca=vca, catalog_name=catalog_md5_name,
media_name=filename, medial_file_name=path, progress=progress)
if not result:
- raise vimconn.vimconnException("Failed create vApp template for catalog {} ".format(catalog_name))
+ raise vimconn.vimconnException("Failed create vApp template for catalog {} ".format(catalog_md5_name))
- return self.get_catalogid(catalog_name, vca.get_catalogs())
+ return self.get_catalogid(catalog_md5_name, vca.get_catalogs())
def get_vappid(self, vdc=None, vapp_name=None):
""" Method takes vdc object and vApp name and returns vapp uuid or None
Args:
- vca: Connector to VCA
vdc: The VDC object.
vapp_name: is application vappp name identifier
Returns:
The return True if vApp deployed
+ :param vdc:
+ :param vapp_uuid:
"""
try:
refs = filter(lambda ref:
return None
def new_vminstance(self, name=None, description="", start=False, image_id=None, flavor_id=None, net_list={},
- cloud_config=None):
+ cloud_config=None, disk_list=None):
"""Adds a VM instance to VIM
Params:
start: indicates if VM must start or boot in pause mode. Ignored
<0, error_text
"""
- self.logger.info("Creating new instance for entry".format(name))
+ self.logger.info("Creating new instance for entry {}".format(name))
self.logger.debug("desc {} boot {} image_id: {} flavor_id: {} net_list: {} cloud_config {}".
format(description, start, image_id, flavor_id, net_list, cloud_config))
vca = self.connect()
if not vca:
raise vimconn.vimconnConnectionException("self.connect() is failed.")
+ #new vm name = vmname + tenant_id + uuid
+ new_vm_name = [name, '-', str(uuid.uuid4())]
+ vmname_andid = ''.join(new_vm_name)
+
# if vm already deployed we return existing uuid
- vapp_uuid = self.get_vappid(vca.get_vdc(self.tenant_name), name)
- if vapp_uuid is not None:
- return vapp_uuid
+ # vapp_uuid = self.get_vappid(vca.get_vdc(self.tenant_name), name)
+ # if vapp_uuid is not None:
+ # return vapp_uuid
# we check for presence of VDC, Catalog entry and Flavor.
vdc = vca.get_vdc(self.tenant_name)
catalogs = vca.get_catalogs()
if catalogs is None:
raise vimconn.vimconnNotFoundException(
- "new_vminstance(): Failed create vApp {}: Failed create vApp {}: "
- "(Failed retrieve catalog information)".format(name))
+ "new_vminstance(): Failed create vApp {}: (Failed retrieve catalogs list)".format(name))
+
+ catalog_hash_name = self.get_catalogbyid(catalog_uuid=image_id, catalogs=catalogs)
+ if catalog_hash_name:
+ self.logger.info("Found catalog entry {} for image id {}".format(catalog_hash_name, image_id))
+ else:
+ raise vimconn.vimconnNotFoundException("new_vminstance(): Failed create vApp {}: "
+ "(Failed retrieve catalog information {})".format(name, image_id))
+
+ # Set vCPU and Memory based on flavor.
+ #
vm_cpus = None
vm_memory = None
if flavor_id is not None:
- flavor = flavorlist[flavor_id]
- if flavor is None:
- raise vimconn.vimconnNotFoundException(
- "new_vminstance(): Failed create vApp {}: (Failed retrieve flavor information)".format(name))
+ if flavor_id not in flavorlist:
+ raise vimconn.vimconnNotFoundException("new_vminstance(): Failed create vApp {}: "
+ "Failed retrieve flavor information "
+ "flavor id {}".format(name, flavor_id))
else:
try:
- vm_cpus = flavor['vcpus']
- vm_memory = flavor['ram']
+ flavor = flavorlist[flavor_id]
+ vm_cpus = flavor[FLAVOR_VCPUS_KEY]
+ vm_memory = flavor[FLAVOR_RAM_KEY]
except KeyError:
raise vimconn.vimconnException("Corrupted flavor. {}".format(flavor_id))
# image upload creates template name as catalog name space Template.
- templateName = self.get_catalogbyid(catalog_uuid=image_id, catalogs=catalogs) + ' Template'
+ templateName = self.get_catalogbyid(catalog_uuid=image_id, catalogs=catalogs)
power_on = 'false'
if start:
power_on = 'true'
# client must provide at least one entry in net_list if not we report error
+ #If net type is mgmt, then configure it as primary net & use its NIC index as primary NIC
+ #If no mgmt, then the 1st NN in netlist is considered as primary net.
primary_net = None
- primary_net_name = None
+ primary_netname = None
+ network_mode = 'bridged'
if net_list is not None and len(net_list) > 0:
- primary_net = net_list[0]
+ for net in net_list:
+ if 'use' in net and net['use'] == 'mgmt':
+ primary_net = net
if primary_net is None:
- raise vimconn.vimconnUnexpectedResponse("new_vminstance(): Failed network list is empty.".format(name))
+ primary_net = net_list[0]
- else:
- try:
- primary_net_id = primary_net['net_id']
- primary_net_name = self.get_network_name_by_id(primary_net_id)
- network_mode = primary_net['use']
- except KeyError:
- raise vimconn.vimconnException("Corrupted flavor. {}".format(primary_net))
+ try:
+ primary_net_id = primary_net['net_id']
+ network_dict = self.get_vcd_network(network_uuid=primary_net_id)
+ if 'name' in network_dict:
+ primary_netname = network_dict['name']
+
+ except KeyError:
+ raise vimconn.vimconnException("Corrupted flavor. {}".format(primary_net))
+ else:
+ raise vimconn.vimconnUnexpectedResponse("new_vminstance(): Failed network list is empty.".format(name))
# use: 'data', 'bridge', 'mgmt'
# create vApp. Set vcpu and ram based on flavor id.
- vapptask = vca.create_vapp(self.tenant_name, name, templateName,
+ vapptask = vca.create_vapp(self.tenant_name, vmname_andid, templateName,
self.get_catalogbyid(image_id, catalogs),
- network_name=primary_net_name, # can be None if net_list None
- network_mode='bridged',
- vm_name=name,
+ network_name=None, # None while creating vapp
+ network_mode=network_mode,
+ vm_name=vmname_andid,
vm_cpus=vm_cpus, # can be None if flavor is None
vm_memory=vm_memory) # can be None if flavor is None
if vapptask is None or vapptask is False:
- raise vimconn.vimconnUnexpectedResponse("new_vminstance(): failed deploy vApp {}".format(name))
+ raise vimconn.vimconnUnexpectedResponse("new_vminstance(): failed deploy vApp {}".format(vmname_andid))
if type(vapptask) is VappTask:
vca.block_until_completed(vapptask)
# we should have now vapp in undeployed state.
- vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), name)
+ vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vmname_andid)
if vapp is None:
raise vimconn.vimconnUnexpectedResponse(
- "new_vminstance(): Failed failed retrieve vApp {} after we deployed".format(name))
+ "new_vminstance(): Failed failed retrieve vApp {} after we deployed".format(vmname_andid))
- # add first NIC
+ # add NICs & connect to networks in netlist
try:
+ self.logger.info("Request to connect VM to a network: {}".format(net_list))
nicIndex = 0
+ primary_nic_index = 0
for net in net_list:
# openmano uses network id in UUID format.
# vCloud Director need a name so we do reverse operation from provided UUID we lookup a name
+ # [{'use': 'bridge', 'net_id': '527d4bf7-566a-41e7-a9e7-ca3cdd9cef4f', 'type': 'virtual',
+ # 'vpci': '0000:00:11.0', 'name': 'eth0'}]
+
+ if 'net_id' not in net:
+ continue
+
interface_net_id = net['net_id']
- interface_net_name = self.get_network_name_by_id(interface_net_id)
+ interface_net_name = self.get_network_name_by_id(network_uuid=interface_net_id)
interface_network_mode = net['use']
- if primary_net_name is not None:
+ if interface_network_mode == 'mgmt':
+ primary_nic_index = nicIndex
+
+ """- POOL (A static IP address is allocated automatically from a pool of addresses.)
+ - DHCP (The IP address is obtained from a DHCP service.)
+ - MANUAL (The IP address is assigned manually in the IpAddress element.)
+ - NONE (No IP addressing mode specified.)"""
+
+ if primary_netname is not None:
nets = filter(lambda n: n.name == interface_net_name, vca.get_networks(self.tenant_name))
if len(nets) == 1:
+ self.logger.info("new_vminstance(): Found requested network: {}".format(nets[0].name))
task = vapp.connect_to_network(nets[0].name, nets[0].href)
if type(task) is GenericTask:
vca.block_until_completed(task)
- # connect network to VM
- # TODO figure out mapping between openmano representation to vCloud director.
- # one idea use first nic as management DHCP all remaining in bridge mode
- task = vapp.connect_vms(nets[0].name, connection_index=nicIndex,
- connections_primary_index=nicIndex,
+ # connect network to VM - with all DHCP by default
+ self.logger.info("new_vminstance(): Connecting VM to a network {}".format(nets[0].name))
+ task = vapp.connect_vms(nets[0].name,
+ connection_index=nicIndex,
+ connections_primary_index=primary_nic_index,
ip_allocation_mode='DHCP')
if type(task) is GenericTask:
vca.block_until_completed(task)
- nicIndex += 1
+ nicIndex += 1
except KeyError:
# it might be a case if specific mandatory entry in dict is empty
self.logger.debug("Key error {}".format(KeyError.message))
vca.block_until_completed(deploytask)
# check if vApp deployed and if that the case return vApp UUID otherwise -1
- vapp_uuid = self.get_vappid(vca.get_vdc(self.tenant_name), name)
+ wait_time = 0
+ vapp_uuid = None
+ while wait_time <= MAX_WAIT_TIME:
+ vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vmname_andid)
+ if vapp and vapp.me.deployed:
+ vapp_uuid = self.get_vappid(vca.get_vdc(self.tenant_name), vmname_andid)
+ break
+ else:
+ self.logger.debug("new_vminstance(): Wait for vApp {} to deploy".format(name))
+ time.sleep(INTERVAL_TIME)
+
+ wait_time +=INTERVAL_TIME
+
if vapp_uuid is not None:
return vapp_uuid
else:
# interfaces: …
#
def get_vminstance(self, vim_vm_uuid=None):
- '''Returns the VM instance information from VIM'''
+ """Returns the VM instance information from VIM"""
self.logger.debug("Client requesting vm instance {} ".format(vim_vm_uuid))
vca = self.connect()
'error_msg': error,
'vim_info': yaml.safe_dump(vm_info_dict), 'interfaces': []}
- if vm_info_dict.has_key('interfaces'):
+ if 'interfaces' in vm_info_dict:
vm_dict['interfaces'] = vm_info_dict['interfaces']
else:
vm_dict['interfaces'] = []
self.logger.info("Deleting vApp {} and UUID {}".format(vapp_name, vm__vim_uuid))
# Delete vApp and wait for status change if task executed and vApp is None.
- # We successfully delete vApp from vCloud
vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
- # poweroff vapp / undeploy and delete
- power_off_task = vapp.poweroff()
- if type(power_off_task) is GenericTask:
- vca.block_until_completed(power_off_task)
- else:
- if not power_off_task:
- self.logger.debug("delete_vminstance(): Failed power off VM uuid {} ".format(vm__vim_uuid))
-
- # refresh status
- if vapp.me.deployed:
- undeploy_task = vapp.undeploy()
- if type(undeploy_task) is GenericTask:
- retry = 0
- while retry <= DELETE_INSTANCE_RETRY:
- result = vca.block_until_completed(undeploy_task)
- if result:
- break
- retry += 1
- else:
- return -1
- # delete vapp
- vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
- if vapp is not None:
- delete_task = vapp.delete()
- retry = 0
- while retry <= DELETE_INSTANCE_RETRY:
- task = vapp.delete()
- if type(task) is GenericTask:
- vca.block_until_completed(delete_task)
- if not delete_task:
+ if vapp:
+ if vapp.me.deployed:
+ self.logger.info("Powering off vApp {}".format(vapp_name))
+ #Power off vApp
+ powered_off = False
+ wait_time = 0
+ while wait_time <= MAX_WAIT_TIME:
+ vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
+ if not vapp:
+ self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
+ return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
+
+ power_off_task = vapp.poweroff()
+ if type(power_off_task) is GenericTask:
+ result = vca.block_until_completed(power_off_task)
+ if result:
+ powered_off = True
+ break
+ else:
+ self.logger.info("Wait for vApp {} to power off".format(vapp_name))
+ time.sleep(INTERVAL_TIME)
+
+ wait_time +=INTERVAL_TIME
+ if not powered_off:
+ self.logger.debug("delete_vminstance(): Failed to power off VM instance {} ".format(vm__vim_uuid))
+ else:
+ self.logger.info("delete_vminstance(): Powered off VM instance {} ".format(vm__vim_uuid))
+
+ #Undeploy vApp
+ self.logger.info("Undeploy vApp {}".format(vapp_name))
+ wait_time = 0
+ undeployed = False
+ while wait_time <= MAX_WAIT_TIME:
+ vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
+ if not vapp:
+ self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
+ return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
+ undeploy_task = vapp.undeploy(action='powerOff')
+
+ if type(undeploy_task) is GenericTask:
+ result = vca.block_until_completed(undeploy_task)
+ if result:
+ undeployed = True
+ break
+ else:
+ self.logger.debug("Wait for vApp {} to undeploy".format(vapp_name))
+ time.sleep(INTERVAL_TIME)
+
+ wait_time +=INTERVAL_TIME
+
+ if not undeployed:
+ self.logger.debug("delete_vminstance(): Failed to undeploy vApp {} ".format(vm__vim_uuid))
+
+ # delete vapp
+ self.logger.info("Start deletion of vApp {} ".format(vapp_name))
+ vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
+
+ if vapp is not None:
+ wait_time = 0
+ result = False
+
+ while wait_time <= MAX_WAIT_TIME:
+ vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
+ if not vapp:
+ self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
+ return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
+
+ delete_task = vapp.delete()
+
+ if type(delete_task) is GenericTask:
+ vca.block_until_completed(delete_task)
+ result = vca.block_until_completed(delete_task)
+ if result:
+ break
+ else:
+ self.logger.debug("Wait for vApp {} to delete".format(vapp_name))
+ time.sleep(INTERVAL_TIME)
+
+ wait_time +=INTERVAL_TIME
+
+ if not result:
self.logger.debug("delete_vminstance(): Failed delete uuid {} ".format(vm__vim_uuid))
- retry += 1
except:
self.logger.debug(traceback.format_exc())
raise vimconn.vimconnException("delete_vminstance(): Failed delete vm instance {}".format(vm__vim_uuid))
if vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name) is None:
+ self.logger.info("Deleted vm instance {} sccessfully".format(vm__vim_uuid))
return vm__vim_uuid
else:
raise vimconn.vimconnException("delete_vminstance(): Failed delete vm instance {}".format(vm__vim_uuid))
vm_info = the_vapp.get_vms_details()
vm_status = vm_info[0]['status']
- vm_dict = {'status': None, 'error_msg': None, 'vim_info': None, 'interfaces': []}
- vm_dict['status'] = vcdStatusCode2manoFormat[the_vapp.me.get_status()]
- vm_dict['error_msg'] = vcdStatusCode2manoFormat[the_vapp.me.get_status()]
- vm_dict['vim_info'] = yaml.safe_dump(the_vapp.get_vms_details())
+ vm_dict = {'status': vcdStatusCode2manoFormat[the_vapp.me.get_status()],
+ 'error_msg': vcdStatusCode2manoFormat[the_vapp.me.get_status()],
+ 'vim_info': yaml.safe_dump(the_vapp.get_vms_details()), 'interfaces': []}
# get networks
try:
for vapp_network in vm_app_networks:
for vm_network in vapp_network:
if vm_network['name'] == vmname:
- interface = {}
+ interface = {"mac_address": vm_network['mac'],
+ "vim_net_id": self.get_network_id_by_name(vm_network['network_name']),
+ "vim_interface_id": self.get_network_id_by_name(vm_network['network_name']),
+ 'ip_address': vm_network['ip']}
# interface['vim_info'] = yaml.safe_dump(vm_network)
- interface["mac_address"] = vm_network['mac']
- interface["vim_net_id"] = self.get_network_name_by_id(vm_network['network_name'])
- interface["vim_interface_id"] = vm_network['network_name']
- interface['ip_address'] = vm_network['ip']
vm_dict["interfaces"].append(interface)
# add a vm to vm dict
vms_dict.setdefault(vmuuid, vm_dict)
# NOT USED METHODS in current version
def host_vim2gui(self, host, server_dict):
- '''Transform host dictionary from VIM format to GUI format,
+ """Transform host dictionary from VIM format to GUI format,
and append to the server_dict
- '''
+ """
raise vimconn.vimconnNotImplemented("Should have implemented this")
def get_hosts_info(self):
- '''Get the information of deployed hosts
- Returns the hosts content'''
+ """Get the information of deployed hosts
+ Returns the hosts content"""
raise vimconn.vimconnNotImplemented("Should have implemented this")
def get_hosts(self, vim_tenant):
- '''Get the hosts and deployed instances
- Returns the hosts content'''
+ """Get the hosts and deployed instances
+ Returns the hosts content"""
raise vimconn.vimconnNotImplemented("Should have implemented this")
def get_processor_rankings(self):
- '''Get the processor rankings in the VIM database'''
+ """Get the processor rankings in the VIM database"""
raise vimconn.vimconnNotImplemented("Should have implemented this")
def new_host(self, host_data):
- '''Adds a new host to VIM'''
+ """Adds a new host to VIM"""
'''Returns status code of the VIM response'''
raise vimconn.vimconnNotImplemented("Should have implemented this")
def new_external_port(self, port_data):
- '''Adds a external port to VIM'''
+ """Adds a external port to VIM"""
'''Returns the port identifier'''
raise vimconn.vimconnNotImplemented("Should have implemented this")
def new_external_network(self, net_name, net_type):
- '''Adds a external network to VIM (shared)'''
+ """Adds a external network to VIM (shared)"""
'''Returns the network identifier'''
raise vimconn.vimconnNotImplemented("Should have implemented this")
def connect_port_network(self, port_id, network_id, admin=False):
- '''Connects a external port to a network'''
+ """Connects a external port to a network"""
'''Returns status code of the VIM response'''
raise vimconn.vimconnNotImplemented("Should have implemented this")
def new_vminstancefromJSON(self, vm_data):
- '''Adds a VM instance to VIM'''
+ """Adds a VM instance to VIM"""
'''Returns the instance identifier'''
raise vimconn.vimconnNotImplemented("Should have implemented this")
- def get_network_name_by_id(self, network_name=None):
+ def get_network_name_by_id(self, network_uuid=None):
"""Method gets vcloud director network named based on supplied uuid.
Args:
- network_name: network_id
+ network_uuid: network_id
Returns:
The return network name.
vca = self.connect()
if not vca:
- raise vimconn.vimconnConnectionException("self.connect() is failed")
+ raise vimconn.vimconnConnectionException("self.connect() is failed.")
- if network_name is None:
+ if not network_uuid:
return None
try:
- org_network_dict = self.get_org(self.org_uuid)['networks']
- for net_uuid in org_network_dict:
- if org_network_dict[net_uuid] == network_name:
- return net_uuid
+ org_dict = self.get_org(self.org_uuid)
+ if 'networks' in org_dict:
+ org_network_dict = org_dict['networks']
+ for net_uuid in org_network_dict:
+ if net_uuid == network_uuid:
+ return org_network_dict[net_uuid]
except:
self.logger.debug("Exception in get_network_name_by_id")
self.logger.debug(traceback.format_exc())
return None
+ def get_network_id_by_name(self, network_name=None):
+ """Method gets vcloud director network uuid based on supplied name.
+
+ Args:
+ network_name: network_name
+ Returns:
+ The return network uuid.
+ network_uuid: network_id
+ """
+
+ vca = self.connect()
+ if not vca:
+ raise vimconn.vimconnConnectionException("self.connect() is failed.")
+
+ if not network_name:
+ self.logger.debug("get_network_id_by_name() : Network name is empty")
+ return None
+
+ try:
+ org_dict = self.get_org(self.org_uuid)
+ if org_dict and 'networks' in org_dict:
+ org_network_dict = org_dict['networks']
+ for net_uuid,net_name in org_network_dict.iteritems():
+ if net_name == network_name:
+ return net_uuid
+
+ except KeyError as exp:
+ self.logger.debug("get_network_id_by_name() : KeyError- {} ".format(exp))
+
+ return None
+
def list_org_action(self):
"""
Method leverages vCloud director and query for available organization for particular user
return False
- def create_network(self, network_name=None, parent_network_uuid=None, isshared='true'):
+ def create_network(self, network_name=None, net_type='bridge', parent_network_uuid=None,
+ ip_profile=None, isshared='true'):
"""
Method create network in vCloud director
Args:
network_name - is network name to be created.
+ net_type - can be 'bridge','data','ptp','mgmt'.
+ ip_profile is a dict containing the IP parameters of the network
+ isshared - is a boolean
parent_network_uuid - is parent provider vdc network that will be used for mapping.
It optional attribute. by default if no parent network indicate the first available will be used.
The return network uuid or return None
"""
- content = self.create_network_rest(network_name=network_name,
+ new_network_name = [network_name, '-', str(uuid.uuid4())]
+ content = self.create_network_rest(network_name=''.join(new_network_name),
+ ip_profile=ip_profile,
+ net_type=net_type,
parent_network_uuid=parent_network_uuid,
isshared=isshared)
if content is None:
self.logger.debug("Failed create network {}".format(network_name))
return None
- def create_network_rest(self, network_name=None, parent_network_uuid=None, isshared='true'):
+ def create_network_rest(self, network_name=None, net_type='bridge', parent_network_uuid=None,
+ ip_profile=None, isshared='true'):
"""
Method create network in vCloud director
Args:
network_name - is network name to be created.
+ net_type - can be 'bridge','data','ptp','mgmt'.
+ ip_profile is a dict containing the IP parameters of the network
+ isshared - is a boolean
parent_network_uuid - is parent provider vdc network that will be used for mapping.
It optional attribute. by default if no parent network indicate the first available will be used.
vca = self.connect_as_admin()
if not vca:
- raise vimconn.vimconnConnectionException("self.connect() is failed")
+ raise vimconn.vimconnConnectionException("self.connect() is failed.")
if network_name is None:
return None
except:
return None
+ #Configure IP profile of the network
+ ip_profile = ip_profile if ip_profile is not None else DEFAULT_IP_PROFILE
+
+ gateway_address=ip_profile['gateway_address']
+ dhcp_count=int(ip_profile['dhcp_count'])
+ subnet_address=self.convert_cidr_to_netmask(ip_profile['subnet_address'])
+
+ if ip_profile['dhcp_enabled']==True:
+ dhcp_enabled='true'
+ else:
+ dhcp_enabled='false'
+ dhcp_start_address=ip_profile['dhcp_start_address']
+
+ #derive dhcp_end_address from dhcp_start_address & dhcp_count
+ end_ip_int = int(netaddr.IPAddress(dhcp_start_address))
+ end_ip_int += dhcp_count - 1
+ dhcp_end_address = str(netaddr.IPAddress(end_ip_int))
+
+ ip_version=ip_profile['ip_version']
+ dns_address=ip_profile['dns_address']
+
# either use client provided UUID or search for a first available
# if both are not defined we return none
if parent_network_uuid is not None:
url_list = [vca.host, '/api/admin/network/', parent_network_uuid]
add_vdc_rest_url = ''.join(url_list)
- # return response.content
- data = """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
- <Description>Openmano created</Description>
- <Configuration>
- <ParentNetwork href="{1:s}"/>
- <FenceMode>{2:s}</FenceMode>
- </Configuration>
- <IsShared>{3:s}</IsShared>
- </OrgVdcNetwork> """.format(escape(network_name), available_networks, "bridged", isshared)
+ if net_type=='ptp':
+ fence_mode="isolated"
+ isshared='false'
+ is_inherited='false'
+ data = """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
+ <Description>Openmano created</Description>
+ <Configuration>
+ <IpScopes>
+ <IpScope>
+ <IsInherited>{1:s}</IsInherited>
+ <Gateway>{2:s}</Gateway>
+ <Netmask>{3:s}</Netmask>
+ <Dns1>{4:s}</Dns1>
+ <IsEnabled>{5:s}</IsEnabled>
+ <IpRanges>
+ <IpRange>
+ <StartAddress>{6:s}</StartAddress>
+ <EndAddress>{7:s}</EndAddress>
+ </IpRange>
+ </IpRanges>
+ </IpScope>
+ </IpScopes>
+ <FenceMode>{8:s}</FenceMode>
+ </Configuration>
+ <IsShared>{9:s}</IsShared>
+ </OrgVdcNetwork> """.format(escape(network_name), is_inherited, gateway_address,
+ subnet_address, dns_address, dhcp_enabled,
+ dhcp_start_address, dhcp_end_address, fence_mode, isshared)
+
+ else:
+ fence_mode="bridged"
+ is_inherited='false'
+ data = """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
+ <Description>Openmano created</Description>
+ <Configuration>
+ <IpScopes>
+ <IpScope>
+ <IsInherited>{1:s}</IsInherited>
+ <Gateway>{2:s}</Gateway>
+ <Netmask>{3:s}</Netmask>
+ <Dns1>{4:s}</Dns1>
+ <IsEnabled>{5:s}</IsEnabled>
+ <IpRanges>
+ <IpRange>
+ <StartAddress>{6:s}</StartAddress>
+ <EndAddress>{7:s}</EndAddress>
+ </IpRange>
+ </IpRanges>
+ </IpScope>
+ </IpScopes>
+ <ParentNetwork href="{8:s}"/>
+ <FenceMode>{9:s}</FenceMode>
+ </Configuration>
+ <IsShared>{10:s}</IsShared>
+ </OrgVdcNetwork> """.format(escape(network_name), is_inherited, gateway_address,
+ subnet_address, dns_address, dhcp_enabled,
+ dhcp_start_address, dhcp_end_address, available_networks,
+ fence_mode, isshared)
headers = vca.vcloud_session.get_vcloud_headers()
headers['Content-Type'] = 'application/vnd.vmware.vcloud.orgVdcNetwork+xml'
- response = Http.post(url=add_vdc_rest_url, headers=headers, data=data, verify=vca.verify, logger=vca.logger)
+ try:
+ response = Http.post(url=add_vdc_rest_url,
+ headers=headers,
+ data=data,
+ verify=vca.verify,
+ logger=vca.logger)
+
+ if response.status_code != 201:
+ self.logger.debug("Create Network POST REST API call failed. Return status code {}"
+ .format(response.status_code))
+ else:
+ network = networkType.parseString(response.content, True)
+ create_nw_task = network.get_Tasks().get_Task()[0]
+
+ # if we all ok we respond with content after network creation completes
+ # otherwise by default return None
+ if create_nw_task is not None:
+ self.logger.debug("Create Network REST : Waiting for Nw creation complete")
+ status = vca.block_until_completed(create_nw_task)
+ if status:
+ return response.content
+ else:
+ self.logger.debug("create_network_rest task failed. Network Create response : {}"
+ .format(response.content))
+ except Exception as exp:
+ self.logger.debug("create_network_rest : Exception : {} ".format(exp))
- # if we all ok we respond with content otherwise by default None
- if response.status_code == 201:
- return response.content
+ return None
+
+ def convert_cidr_to_netmask(self, cidr_ip=None):
+ """
+ Method sets convert CIDR netmask address to normal IP format
+ Args:
+ cidr_ip : CIDR IP address
+ Returns:
+ netmask : Converted netmask
+ """
+ if cidr_ip is not None:
+ if '/' in cidr_ip:
+ network, net_bits = cidr_ip.split('/')
+ netmask = socket.inet_ntoa(struct.pack(">I", (0xffffffff << (32 - int(net_bits))) & 0xffffffff))
+ else:
+ netmask = cidr_ip
+ return netmask
return None
def get_provider_rest(self, vca=None):
parsed_respond['created'] = created_section.text
network_section = xmlroot_respond.find('vm:NetworkConfigSection/vm:NetworkConfig', namespace_vm)
- if network_section is not None and network_section.attrib.has_key('networkName'):
+ if network_section is not None and 'networkName' in network_section.attrib:
parsed_respond['networkname'] = network_section.attrib['networkName']
ipscopes_section = \
parsed_respond['primarynetwork'] = adapters.text
if adapter_key == 'NetworkConnection':
vnic = {}
- if adapters.attrib.has_key('network'):
+ if 'network' in adapters.attrib:
vnic['network'] = adapters.attrib['network']
for adapter in adapters:
setting_key = adapter.tag.split("}")[1]
nic_list.append(vnic)
for link in children_section:
- if link.tag.split("}")[1] == 'Link' and link.attrib.has_key('rel'):
+ if link.tag.split("}")[1] == 'Link' and 'rel' in link.attrib:
if link.attrib['rel'] == 'screen:acquireTicket':
parsed_respond['acquireTicket'] = link.attrib
if link.attrib['rel'] == 'screen:acquireMksTicket':
return parsed_respond
- def acuireConsole(self, vm_uuid=None):
+ def acuire_console(self, vm_uuid=None):
vca = self.connect()
if not vca:
return None
if not (not vca.vcloud_session or not vca.vcloud_session.organization):
- vm_dict = self.get_vapp_details_rest(self, vm_uuid=vm_uuid)
+ vm_dict = self.get_vapp_details_rest(self, vapp_uuid=vm_uuid)
console_dict = vm_dict['acquireTicket']
console_rest_call = console_dict['href']
verify=vca.verify,
logger=vca.logger)
- if response.status_code != requests.codes.ok:
- return None
+ if response.status_code == requests.codes.ok:
+ return response.content
+
+ return None
+
- return response.content