--- /dev/null
+# -*- coding: utf-8 -*-
+
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openmano
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+
+'''
+vimconn_vmware implementation an Abstract class in order to interact with VMware vCloud Director.
+mbayramov@vmware.com
+'''
+import os
+import requests
+
+
+from xml.etree import ElementTree as ET
+
+from pyvcloud import Http
+from pyvcloud.vcloudair import VCA
+from pyvcloud.schema.vcd.v1_5.schemas.vcloud import sessionType, organizationType, \
+ vAppType, organizationListType, vdcType, catalogType, queryRecordViewType, \
+ networkType, vcloudType, taskType, diskType, vmsType, vdcTemplateListType, mediaType
+from xml.sax.saxutils import escape
+
+import logging
+import json
+import vimconn
+import time
+import uuid
+import httplib
+
+
+__author__="Mustafa Bayramov"
+__date__ ="$26-Aug-2016 11:09:29$"
+
+
+#Error variables
+HTTP_Bad_Request = 400
+HTTP_Unauthorized = 401
+HTTP_Not_Found = 404
+HTTP_Method_Not_Allowed = 405
+HTTP_Request_Timeout = 408
+HTTP_Conflict = 409
+HTTP_Not_Implemented = 501
+HTTP_Service_Unavailable = 503
+HTTP_Internal_Server_Error = 500
+
+class vimconnException(Exception):
+ '''Common and base class Exception for all vimconnector exceptions'''
+ def __init__(self, message, http_code=HTTP_Bad_Request):
+ Exception.__init__(self, message)
+ self.http_code = http_code
+
+class vimconnConnectionException(vimconnException):
+ '''Connectivity error with the VIM'''
+ def __init__(self, message, http_code=HTTP_Service_Unavailable):
+ vimconnException.__init__(self, message, http_code)
+
+class vimconnUnexpectedResponse(vimconnException):
+ '''Get an wrong response from VIM'''
+ def __init__(self, message, http_code=HTTP_Service_Unavailable):
+ vimconnException.__init__(self, message, http_code)
+
+class vimconnAuthException(vimconnException):
+ '''Invalid credentials or authorization to perform this action over the VIM'''
+ def __init__(self, message, http_code=HTTP_Unauthorized):
+ vimconnException.__init__(self, message, http_code)
+
+class vimconnNotFoundException(vimconnException):
+ '''The item is not found at VIM'''
+ def __init__(self, message, http_code=HTTP_Not_Found):
+ vimconnException.__init__(self, message, http_code)
+
+class vimconnConflictException(vimconnException):
+ '''There is a conflict, e.g. more item found than one'''
+ def __init__(self, message, http_code=HTTP_Conflict):
+ vimconnException.__init__(self, message, http_code)
+
+class vimconnNotImplemented(vimconnException):
+ '''The method is not implemented by the connected'''
+ def __init__(self, message, http_code=HTTP_Not_Implemented):
+ vimconnException.__init__(self, message, http_code)
+
+
+flavorlist = {}
+
+class vimconnector():
+ '''Vmware VIM Connector base class
+ '''
+ def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None, log_level="ERROR", config={}):
+ self.id = uuid
+ self.name = name
+ self.url = url
+ self.url_admin = url_admin
+ self.tenant_id = tenant_id
+ self.tenant_name = tenant_name
+ self.user = user
+ self.passwd = passwd
+ self.config = config
+ self.logger = logging.getLogger('mano.vim.vmware')
+
+ formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+ ch = logging.StreamHandler()
+ ch.setLevel(log_level)
+ ch.setFormatter(formatter)
+ self.logger.addHandler(ch)
+ self.logger.setLevel( getattr(logging, log_level))
+
+# self.logger = logging.getLogger('mano.vim.vmware')
+
+ self.logger.debug("Vmware tenant from VIM filter: '%s'", user)
+ self.logger.debug("Vmware tenant from VIM filter: '%s'", passwd)
+
+ if not url:
+ raise TypeError, 'url param can not be NoneType'
+
+ if not self.url_admin: #try to use normal url
+ self.url_admin = self.url
+
+ self.vcaversion = '5.6'
+
+ print "Calling constructor with following paramters"
+ print " UUID: {} ".format(uuid)
+ print " name: {} ".format(name)
+ print " tenant_id: {} ".format(tenant_id)
+ print " tenant_name: {} ".format(tenant_name)
+ print " url: {} ".format(url)
+ print " url_admin: {} ".format(url_admin)
+ print " user: {} ".format(user)
+ print " passwd: {} ".format(passwd)
+ print " debug: {} ".format(log_level)
+
+ def __getitem__(self,index):
+ 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=='user':
+ return self.user
+ elif index=='passwd':
+ return self.passwd
+ elif index=='url':
+ return self.url
+ elif index=='url_admin':
+ return self.url_admin
+ elif index=="config":
+ return self.config
+ else:
+ raise KeyError("Invalid key '%s'" %str(index))
+
+ def __setitem__(self,index, value):
+ if index=='tenant_id':
+ self.tenant_id = value
+ if index=='tenant_name':
+ self.tenant_name = value
+ elif index=='id':
+ self.id = value
+ elif index=='name':
+ self.name = value
+ elif index=='user':
+ self.user = value
+ elif index=='passwd':
+ self.passwd = value
+ elif index=='url':
+ self.url = value
+ elif index=='url_admin':
+ self.url_admin = value
+ else:
+ raise KeyError("Invalid key '%s'" %str(index))
+
+ def connect(self):
+
+ service_type = 'standalone'
+ version = '5.6'
+
+ self.logger.debug("Logging in to a VCA '%s'", self.name)
+
+ vca = VCA(host=self.url, username=self.user, service_type=service_type, version=version, verify=False, log=True)
+ result = vca.login(password=self.passwd, org=self.name)
+ if not result:
+ raise KeyError("Can't connect to a vCloud director.")
+ result = vca.login(token=vca.token, org=self.name, org_url=vca.vcloud_session.org_url)
+ if result is True:
+ self.logger.debug("Successfully logged to a VCA '%s'", self.name)
+
+ # vca = VCA(host='172.16.254.206', username=self.user, service_type='standalone', version='5.6', verify=False, log=True)
+ # vca.login(password=self.passwd, org=self.name)
+ # vca.login(token=vca.token, org=self.name, org_url=vca.vcloud_session.org_url)
+
+ # if not result:
+ # result = vca.login(token=vca.token, org=self.name, org_url=vca.vcloud_session.org_url)
+ # if not result:
+ # raise KeyError("Can't connect to a vcloud director")
+ # else:
+ # print "Logged to VCA via existing token"
+ # else:
+ # print "Logged to VCA"
+
+ return vca
+
+
+ def new_tenant(self,tenant_name,tenant_description):
+ '''Adds a new tenant to VIM with this name and description,
+ returns the tenant identifier'''
+ raise vimconnNotImplemented( "Should have implemented this" )
+
+ def delete_tenant(self,tenant_id,):
+ '''Delete a tenant from VIM'''
+ '''Returns the tenant identifier'''
+ raise vimconnNotImplemented( "Should have implemented this" )
+
+ def get_tenant_list(self, filter_dict={}):
+ '''Obtain tenants of VIM
+ filter_dict can contain the following keys:
+ name: filter by tenant name
+ id: filter by tenant uuid/id
+ <other VIM specific>
+ Returns the tenant list of dictionaries:
+ [{'name':'<name>, 'id':'<id>, ...}, ...]
+ '''
+ raise vimconnNotImplemented( "Should have implemented this" )
+
+ 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
+ ip_profile is a dict containing the IP parameters of the network
+ shared is a boolean
+ Returns the network identifier'''
+
+ self.logger.debug("Vmware tenant from VIM filter: '%s'", net_name)
+ self.logger.debug("Vmware tenant from VIM filter: '%s'", net_type)
+ self.logger.debug("Vmware tenant from VIM filter: '%s'", ip_profile)
+ self.logger.debug("Vmware tenant from VIM filter: '%s'", shared)
+
+ raise vimconnNotImplemented( "Should have implemented this" )
+
+ def get_network_list(self, filter_dict={}):
+ '''Obtain tenant networks of VIM
+ Filter_dict can be:
+ name: network name
+ id: network uuid
+ shared: boolean
+ tenant_id: tenant
+ admin_state_up: boolean
+ status: 'ACTIVE'
+ Returns the network list of dictionaries:
+ [{<the fields at Filter_dict plus some VIM specific>}, ...]
+ List can be empty
+ '''
+
+ vca = self.connect()
+ if not vca:
+ raise vimconn.vimconnConnectionException("self.connect() is failed")
+
+ vdc = vca.get_vdc(self.tenant_name)
+ vdcid = vdc.get_id().split(":")
+
+ networks = vca.get_networks(vdc.get_name())
+ network_list = []
+ for network in networks:
+ filter_dict = {}
+ netid = network.get_id().split(":")
+ self.logger.debug ("Adding {} to a list".format(netid[3]))
+ self.logger.debug ("VDC ID {} to a list".format(vdcid[3]))
+ self.logger.debug ("Network {} to a list".format(network.get_name()))
+
+ filter_dict["name"] = network.get_name()
+ filter_dict["id"] = netid[3]
+ filter_dict["shared"] = network.get_IsShared()
+ filter_dict["tenant_id"] = vdcid[3]
+ if network.get_status() == 1:
+ filter_dict["admin_state_up"] = True
+ else:
+ filter_dict["admin_state_up"] = False
+ filter_dict["status"] = "ACTIVE"
+ filter_dict["type"] = "bridge"
+ network_list.append(filter_dict)
+
+ self.logger.debug("Returning {}".format(network_list))
+ return network_list
+
+ def get_network(self, net_id):
+ '''Obtain network details of net_id VIM network'
+ Return a dict with the fields at filter_dict (see get_network_list) plus some VIM specific>}, ...]'''
+ raise vimconnNotImplemented( "Should have implemented this" )
+
+ def delete_network(self, net_id):
+ '''Deletes a tenant network from VIM, provide the network id.
+ Returns the network identifier or raise an exception'''
+ raise vimconnNotImplemented( "Should have implemented this" )
+
+ def refresh_nets_status(self, net_list):
+ '''Get the status of the networks
+ Params: the list of network identifiers
+ Returns a dictionary with:
+ net_id: #VIM id of this network
+ status: #Mandatory. Text with one of:
+ # DELETED (not found at vim)
+ # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
+ # OTHER (Vim reported other status not understood)
+ # ERROR (VIM indicates an ERROR status)
+ # ACTIVE, INACTIVE, DOWN (admin down),
+ # BUILD (on building process)
+ #
+ error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
+ vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
+
+ '''
+ raise vimconnNotImplemented( "Should have implemented this" )
+
+ def get_flavor(self, flavor_id):
+ '''Obtain flavor details from the VIM
+ Returns the flavor dict details {'id':<>, 'name':<>, other vim specific } #TODO to concrete
+ '''
+
+ print " get_flavor contains {}".format(flavor_id)
+
+ vca = self.connect()
+ if not vca:
+ raise vimconn.vimconnConnectionException("self.connect() is failed.")
+
+ def new_flavor(self, flavor_data):
+ '''Adds a tenant flavor to VIM
+ flavor_data contains a dictionary with information, keys:
+ name: flavor name
+ ram: memory (cloud type) in MBytes
+ vpcus: cpus (cloud type)
+ extended: EPA parameters
+ - numas: #items requested in same NUMA
+ memory: number of 1G huge pages memory
+ paired-threads|cores|threads: number of paired hyperthreads, complete cores OR individual threads
+ interfaces: # passthrough(PT) or SRIOV interfaces attached to this numa
+ - name: interface name
+ dedicated: yes|no|yes:sriov; for PT, SRIOV or only one SRIOV for the physical NIC
+ bandwidth: X Gbps; requested guarantee bandwidth
+ vpci: requested virtual PCI address
+ disk: disk size
+ is_public:
+
+
+
+ #TODO to concrete
+ Returns the flavor identifier'''
+
+ flavor_uuid = uuid.uuid4()
+ flavorlist[flavor_uuid] = flavor_data
+
+ print " new_flavor contains {}".format(flavor_data)
+ print " flavor list contains {}".format(flavorlist)
+
+ return flavor_uuid
+
+ def delete_flavor(self, flavor_id):
+ '''Deletes a tenant flavor from VIM identify by its id
+ Returns the used id or raise an exception'''
+ raise vimconnNotImplemented( "Should have implemented this" )
+
+ 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
+ '''
+
+ print " ################################################################### "
+ print " new_image contains {}".format(image_dict)
+ print " ################################################################### "
+
+
+ def delete_image(self, image_id):
+ '''Deletes a tenant image from VIM'''
+ '''Returns the HTTP response code and a message indicating details of the success or fail'''
+
+ print " ################################################################### "
+ print " delete_image contains {}".format(image_id)
+ print " ################################################################### "
+
+ raise vimconnNotImplemented( "Should have implemented this" )
+
+ def catalog_exists(self, catalog_name, catalogs):
+ for catalog in catalogs:
+ if catalog.name == catalog_name:
+ return True
+ return False
+
+ def create_vimcatalog(self, vca, catalog_name):
+ """Create Catalog entry in VIM"""
+ task = vca.create_catalog(catalog_name, catalog_name)
+ result = vca.block_until_completed(task)
+ if not result:
+ return False
+ catalogs = vca.get_catalogs()
+ return self.catalog_exists(catalog_name, catalogs)
+
+
+ def upload_ovf(self, vca, catalog_name, item_name, media_file_name, description='', display_progress=False,
+ chunk_bytes=128 * 1024):
+ """
+ Uploads a OVF file to a vCloud catalog
+
+ :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
+ # status change.
+ # if VCD can parse OVF we upload VMDK file
+ for catalog in vca.get_catalogs():
+ if catalog_name != catalog.name:
+ continue
+ link = filter(lambda link: link.get_type() == "application/vnd.vmware.vcloud.media+xml" and
+ 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(item_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)
+ if response.status_code == requests.codes.created:
+ catalogItem = ET.fromstring(response.content)
+ entity = [child for child in catalogItem if
+ child.get("type") == "application/vnd.vmware.vcloud.vAppTemplate+xml"][0]
+ href = entity.get('href')
+ template = href
+ response = Http.get(href, headers=vca.vcloud_session.get_vcloud_headers(),
+ verify=vca.verify, logger=self.logger)
+
+ if response.status_code == requests.codes.ok:
+ media = mediaType.parseString(response.content, True)
+ link = filter(lambda link: link.get_rel() == 'upload:default', media.get_Files().get_File()[0].get_Link())[0]
+ headers = vca.vcloud_session.get_vcloud_headers()
+ headers['Content-Type'] = 'Content-Type text/xml'
+ response = Http.put(link.get_href(), data=open(media_file_name, 'rb'), headers=headers, verify=vca.verify,logger=self.logger)
+ if response.status_code != requests.codes.ok:
+ self.logger.debug("Failed create vApp template for catalog name {} and image {}".format(catalog_name, media_file_name))
+ return False
+
+ time.sleep(5)
+
+ self.logger.debug("Failed create vApp template for catalog name {} and image {}".
+ format(catalog_name, media_file_name))
+
+ # uploading VMDK file
+ # check status of OVF upload
+ response = Http.get(template, headers=vca.vcloud_session.get_vcloud_headers(), verify=vca.verify, logger=self.logger)
+ if response.status_code == requests.codes.ok:
+ media = mediaType.parseString(response.content, True)
+ link = filter(lambda link: link.get_rel() == 'upload:default', media.get_Files().get_File()[0].get_Link())[0]
+
+ # The OVF file and VMDK must be in a same directory
+ head, tail = os.path.split(media_file_name)
+ filevmdk = head + '/' + os.path.basename(link.get_href())
+
+ os.path.isfile(filevmdk)
+ statinfo = os.stat(filevmdk)
+
+ # TODO debug output remove it
+ #print media.get_Files().get_File()[0].get_Link()[0].get_href()
+ #print media.get_Files().get_File()[1].get_Link()[0].get_href()
+ #print link.get_href()
+
+ # in case first element is pointer to OVF.
+ hrefvmdk = link.get_href().replace("descriptor.ovf","Cirros-disk1.vmdk")
+
+ f = open(filevmdk, 'rb')
+ bytes_transferred = 0
+ while bytes_transferred < statinfo.st_size:
+ my_bytes = f.read(chunk_bytes)
+ if len(my_bytes) <= chunk_bytes:
+ headers = vca.vcloud_session.get_vcloud_headers()
+ headers['Content-Range'] = 'bytes %s-%s/%s' % (bytes_transferred, len(my_bytes) - 1, statinfo.st_size)
+ headers['Content-Length'] = str(len(my_bytes))
+ response = Http.put(hrefvmdk, headers=headers, data=my_bytes, verify=vca.verify,logger=None)
+ if response.status_code == requests.codes.ok:
+ bytes_transferred += len(my_bytes)
+ self.logger.debug('transferred %s of %s bytes' % (str(bytes_transferred),
+ str(statinfo.st_size)))
+ else:
+ self.logger.debug('file upload failed with error: [%s] %s' % (response.status_code,
+ response.content))
+ return False
+ f.close()
+ return True
+ else:
+ self.logger.debug("Failed retrieve vApp template for catalog name {} for OVF {}".
+ format(catalog_name, media_file_name))
+ return False
+
+ self.logger.debug("Failed retrieve catalog name {} for OVF file {}".format(catalog_name, media_file_name))
+ return False
+
+ def upload_vimimage(self,vca, catalog_name, media_name, medial_file_name):
+ """Upload media file"""
+ return self.upload_ovf(vca, catalog_name, media_name.split(".")[0], medial_file_name, medial_file_name, True)
+
+ def get_catalogid(self, catalog_name, catalogs):
+ for catalog in catalogs:
+ if catalog.name == catalog_name:
+ print catalog.name
+ catalog_id = catalog.get_id().split(":")
+ return catalog_id[3]
+ return None
+
+ def get_catalogbyid(self, catalog_id, catalogs):
+ for catalog in catalogs:
+ catalogid = catalog.get_id().split(":")[3]
+ if catalogid == catalog_id:
+ return catalog.name
+ return None
+
+ def get_image_id_from_path(self, path):
+ '''Get the image id from image path in the VIM database'''
+ '''Returns:
+ 0,"Image not found" if there are no images with that path
+ 1,image-id if there is one image with that path
+ <0,message if there was an error (Image not found, error contacting VIM, more than 1 image with that path, etc.)
+ '''
+
+ vca = self.connect()
+ if not vca:
+ raise vimconn.vimconnConnectionException("self.connect() is failed")
+
+ self.logger.debug("get_image_id_from_path path {}".format(path))
+
+ dirpath, filename = os.path.split(path)
+ flname, file_extension = os.path.splitext(path)
+ if file_extension != '.ovf':
+ self.logger.debug("Wrong file extension {}".format(file_extension))
+ return -1, "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))
+ self.logger.debug("Catalog name {}".format(catalog_name))
+
+ catalogs = vca.get_catalogs()
+ if len(catalogs) == 0:
+ self.logger.info("Creating new catalog entry {} in vcloud director".format(catalog_name))
+ result = self.create_vimcatalog(vca, catalog_name)
+ if not result:
+ return -1, "Failed create new catalog {} ".format(catalog_name)
+ result = self.upload_vimimage(vca, catalog_name, filename, path)
+ if not result:
+ return -1, "Failed create vApp template for catalog {} ".format(catalog_name)
+ return self.get_catalogid(catalog_name, vca.get_catalogs())
+ else:
+ 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 we didn't find existing catalog we create a new one.
+ self.logger.debug("Creating new catalog entry".format(catalog_name))
+ result = self.create_vimcatalog(vca, catalog_name)
+ if not result:
+ return -1, "Failed create new catalog {} ".format(catalog_name)
+ result = self.upload_vimimage(vca, catalog_name, filename, path)
+ if not result:
+ return -1, "Failed create vApp template for catalog {} ".format(catalog_name)
+
+ return self.get_catalogid(catalog_name, vca.get_catalogs())
+
+ def get_vappid(self, vdc, vapp_name):
+ """ Take vdc object and vApp name and returns vapp uuid or None
+ """
+ #UUID has following format https://host/api/vApp/vapp-30da58a3-e7c7-4d09-8f68-d4c8201169cf
+
+ try:
+ refs = filter(lambda ref: ref.name == vapp_name and ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml',
+ vdc.ResourceEntities.ResourceEntity)
+
+ if len(refs) == 1:
+ return refs[0].href.split("vapp")[1][1:]
+ except:
+ return None
+ return None
+
+ def get_vappbyid(self, vdc, vapp_id):
+ refs = filter(lambda ref: ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml',
+ vdc.ResourceEntities.ResourceEntity)
+ for ref in refs:
+ print ref.href
+
+ if len(refs) == 1:
+ return refs[0].href.split("vapp")[1][1:]
+
+ 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
+ image_id,flavor_id: image and flavor uuid
+ net_list: list of interfaces, each one is a dictionary with:
+ name:
+ net_id: network uuid to connect
+ vpci: virtual vcpi to assign
+ model: interface model, virtio, e2000, ...
+ mac_address:
+ use: 'data', 'bridge', 'mgmt'
+ type: 'virtual', 'PF', 'VF', 'VFnotShared'
+ vim_id: filled/added by this function
+ cloud_config: can be a text script to be passed directly to cloud-init,
+ or an object to inject users and ssh keys with format:
+ key-pairs: [] list of keys to install to the default user
+ users: [{ name, key-pairs: []}] list of users to add with their key-pair
+ #TODO ip, security groups
+ Returns >=0, the instance identifier
+ <0, error_text
+ """
+
+ 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.")
+
+ # TODO following attribute need be featched from flavor / OVF file must contain same data.
+ # task = self.vca.create_vapp(vdc_name, vapp_name, template, catalog,
+ # vm_name=vm_name,
+ # vm_cpus=cpu,
+ # vm_memory=memory)
+ #
+
+ catalogs = vca.get_catalogs()
+ #image upload creates template name as catalog name space Template.
+ templateName = self.get_catalogbyid(image_id, catalogs) + ' Template'
+ task = vca.create_vapp(self.tenant_name, name, templateName, self.get_catalogbyid(image_id,catalogs), vm_name=name)
+ if task is False:
+ return -1, " Failed deploy vApp {}".format(name)
+
+ result = vca.block_until_completed(task)
+ if result:
+ vappID = self.get_vappid(vca.get_vdc(self.tenant_name), name)
+ if vappID is None:
+ return -1, " Failed featch UUID for vApp {}".format(name)
+ else:
+ return vappID
+
+ return -1, " Failed create vApp {}".format(name)
+
+ def get_vminstance(self,vm_id):
+ '''Returns the VM instance information from VIM'''
+
+ vca = self.connect()
+ if not vca:
+ raise vimconn.vimconnConnectionException("self.connect() is failed.")
+
+
+ raise vimconnNotImplemented( "Should have implemented this" )
+
+ def delete_vminstance(self, vm_id):
+ '''Removes a VM instance from VIM'''
+ '''Returns the instance identifier'''
+
+ print " ###### {} ".format(vm_id)
+
+ vca = self.connect()
+ if not vca:
+ raise vimconn.vimconnConnectionException("self.connect() is failed.")
+
+ thevdc = vca.get_vdc(self.tenant_name)
+ self.get_vappid(vca.get_vdc(self.tenant_name), name)
+
+
+
+
+ def refresh_vms_status(self, vm_list):
+ '''Get the status of the virtual machines and their interfaces/ports
+ Params: the list of VM identifiers
+ Returns a dictionary with:
+ vm_id: #VIM id of this Virtual Machine
+ status: #Mandatory. Text with one of:
+ # DELETED (not found at vim)
+ # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
+ # OTHER (Vim reported other status not understood)
+ # ERROR (VIM indicates an ERROR status)
+ # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
+ # CREATING (on building process), ERROR
+ # ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
+ #
+ error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
+ vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
+ interfaces:
+ - vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
+ mac_address: #Text format XX:XX:XX:XX:XX:XX
+ vim_net_id: #network id where this interface is connected
+ vim_interface_id: #interface/port VIM id
+ ip_address: #null, or text with IPv4, IPv6 address
+ '''
+ raise vimconnNotImplemented( "Should have implemented this" )
+
+ def action_vminstance(self, vm_id, action_dict):
+ '''Send and action over a VM instance from VIM
+ Returns the vm_id if the action was successfully sent to the VIM'''
+ raise vimconnNotImplemented( "Should have implemented this" )
+
+ def get_vminstance_console(self,vm_id, console_type="vnc"):
+ '''
+ Get a console for the virtual machine
+ Params:
+ vm_id: uuid of the VM
+ console_type, can be:
+ "novnc" (by default), "xvpvnc" for VNC types,
+ "rdp-html5" for RDP types, "spice-html5" for SPICE types
+ Returns dict with the console parameters:
+ protocol: ssh, ftp, http, https, ...
+ server: usually ip address
+ port: the http, ssh, ... port
+ suffix: extra text, e.g. the http path and query string
+ '''
+ raise vimconnNotImplemented( "Should have implemented this" )
+
+#NOT USED METHODS in current version
+
+ def host_vim2gui(self, host, server_dict):
+ '''Transform host dictionary from VIM format to GUI format,
+ and append to the server_dict
+ '''
+ raise vimconnNotImplemented( "Should have implemented this" )
+
+ def get_hosts_info(self):
+ '''Get the information of deployed hosts
+ Returns the hosts content'''
+ raise vimconnNotImplemented( "Should have implemented this" )
+
+ def get_hosts(self, vim_tenant):
+ '''Get the hosts and deployed instances
+ Returns the hosts content'''
+ raise vimconnNotImplemented( "Should have implemented this" )
+
+ def get_processor_rankings(self):
+ '''Get the processor rankings in the VIM database'''
+ raise vimconnNotImplemented( "Should have implemented this" )
+
+ def new_host(self, host_data):
+ '''Adds a new host to VIM'''
+ '''Returns status code of the VIM response'''
+ raise vimconnNotImplemented( "Should have implemented this" )
+
+ def new_external_port(self, port_data):
+ '''Adds a external port to VIM'''
+ '''Returns the port identifier'''
+ raise vimconnNotImplemented( "Should have implemented this" )
+
+ def new_external_network(self,net_name,net_type):
+ '''Adds a external network to VIM (shared)'''
+ '''Returns the network identifier'''
+ raise vimconnNotImplemented( "Should have implemented this" )
+
+ def connect_port_network(self, port_id, network_id, admin=False):
+ '''Connects a external port to a network'''
+ '''Returns status code of the VIM response'''
+ raise vimconnNotImplemented( "Should have implemented this" )
+
+ def new_vminstancefromJSON(self, vm_data):
+ '''Adds a VM instance to VIM'''
+ '''Returns the instance identifier'''
+ raise vimconnNotImplemented( "Should have implemented this" )
+