class vimconnector(vimconn.vimconnector):
def __init__(self, uuid=None, name=None, tenant_id=None, tenant_name=None,
url=None, url_admin=None, user=None, passwd=None, log_level="ERROR", config={}):
+ """
+ Constructor create vmware connector to vCloud director.
+
+ By default construct doesn't validate connection state. So client can create object with None arguments.
+ If client specified username , password and host and VDC name. Connector initialize other missing attributes.
+
+ a) It initialize organization UUID
+ b) Initialize tenant_id/vdc ID. (This information derived from tenant name)
+
+ Args:
+ uuid - is organization uuid.
+ name - is organization name that must be presented in vCloud director.
+ tenant_id - is VDC uuid it must be presented in vCloud director
+ tenant_name - is VDC name.
+ url - is hostname or ip address of vCloud director
+ url_admin - same as above.
+ user - is user that administrator for organization. Caller must make sure that
+ username has right privileges.
+
+ password - is password for a user.
+
+ VMware connector also requires PVDC administrative privileges and separate account.
+ This variables must be passed via config argument dict contains keys
+
+ dict['admin_username']
+ dict['admin_password']
+
+ Returns:
+ Nothing.
+ """
+
vimconn.vimconnector.__init__(self, uuid, name, tenant_id, tenant_name, url,
url_admin, user, passwd, log_level, config)
self.id = uuid
raise KeyError("Invalid key '%s'" % str(index))
def connect_as_admin(self):
- """ Method connect as admin user to vCloud director.
+ """ Method connect as pvdc admin user to vCloud director.
+ There are certain action that can be done only by provider vdc admin user.
+ Organization creation / provider network creation etc.
Returns:
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))
- service_type = STANDALONE
vca_admin = VCA(host=self.url,
username=self.admin_user,
The return vca object that letter can be used to connect to vCloud director as admin for VDC
"""
- service_type = 'standalone'
- version = '5.9'
-
- self.logger.debug("Logging in to a vca {} as {} to datacenter {}.".format(self.name, self.user, self.name))
- vca = VCA(host=self.url,
- username=self.user,
- service_type=STANDALONE,
- version=VCAVERSION,
- verify=False,
- log=False)
- result = vca.login(password=self.passwd, org=self.name)
- if not result:
+ try:
+ self.logger.debug("Logging in to a vca {} as {} to datacenter {}.".format(self.name, self.user, self.name))
+ vca = VCA(host=self.url,
+ username=self.user,
+ service_type=STANDALONE,
+ version=VCAVERSION,
+ verify=False,
+ log=False)
+
+ result = vca.login(password=self.passwd, org=self.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)
+ if result is True:
+ self.logger.info("Successfully logged to a vcloud direct org: {} as user: {}".format(self.name, self.user))
+
+ except:
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)
- if result is True:
- self.logger.info("Successfully logged to a vcloud direct org: {} as user: {}".format(self.name, self.user))
return vca
# we have two case if we want to initialize VDC ID or VDC name at run time
# tenant_name provided but no tenant id
- print ("Setting vdc from name {} {} {} {}".format(self.tenant_id, self.tenant_name,
- org_details_dict.has_key('vdcs'), org_details_dict))
if self.tenant_id is None and self.tenant_name is not None and org_details_dict.has_key('vdcs'):
- print ("Setting vdc from name")
vdcs_dict = org_details_dict['vdcs']
- print ("Searching vdc UUUID")
for vdc in vdcs_dict:
if vdcs_dict[vdc] == self.tenant_name:
self.tenant_id = vdc
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'):
- print ("setting vdc from id")
vdcs_dict = org_details_dict['vdcs']
for vdc in vdcs_dict:
if vdc == self.tenant_id:
self.org_uuid = None
def new_tenant(self, tenant_name=None, tenant_description=None):
- """Adds a new tenant to VIM with this name and description
+ """ Method adds a new tenant to VIM with this name.
+ This action requires access to create VDC action in vCloud director.
- :param tenant_name:
- :param tenant_description:
- :return: returns the tenant identifier
+ Args:
+ tenant_name is tenant_name to be created.
+ tenant_description not used for this call
+
+ Return:
+ returns the tenant identifier in UUID format.
+ If action is failed method will throw vimconn.vimconnException method
"""
vdc_task = self.create_vdc(vdc_name=tenant_name)
if vdc_task is not None:
raise vimconn.vimconnNotImplemented("Should have implemented this")
def get_tenant_list(self, filter_dict={}):
- '''Obtain tenants of VIM
+ """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:
+ Returns the tenant list of dictionaries:
[{'name':'<name>, 'id':'<id>, ...}, ...]
- '''
-
+ """
org_dict = self.get_org(self.org_uuid)
vdcs_dict = org_dict['vdcs']
try:
for k in vdcs_dict:
entry = {'name': vdcs_dict[k], 'id': k}
- filtered_entry = entry.copy()
- filtered_dict = set(entry.keys()) - set(filter_dict)
- for unwanted_key in filtered_dict: del entry[unwanted_key]
- if filter_dict == entry:
- vdclist.append(filtered_entry)
+ # if caller didn't specify dictionary we return all tenants.
+ if filter_dict is not None and filter_dict:
+ filtered_entry = entry.copy()
+ filtered_dict = set(entry.keys()) - set(filter_dict)
+ for unwanted_key in filtered_dict: del entry[unwanted_key]
+ if filter_dict == entry:
+ vdclist.append(filtered_entry)
+ else:
+ vdclist.append(entry)
except:
self.logger.debug("Error in get_tenant_list()")
self.logger.debug(traceback.format_exc())
- pass
+ raise vimconn.vimconnException("Incorrect state. {}")
return vdclist
def new_network(self, net_name, net_type, ip_profile=None, shared=False):
- '''Adds a tenant network to VIM
+ """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
+ ip_profile is a dict containing the IP parameters of the network
shared is a boolean
- Returns the network identifier'''
+ Returns the network identifier"""
self.logger.debug(
"new_network tenant {} net_type {} ip_profile {} shared {}".format(net_name, net_type, ip_profile, shared))
return network_list
def get_network_list(self, filter_dict={}):
- '''Obtain tenant networks of VIM
+ """Obtain tenant networks of VIM
Filter_dict can be:
name: network name OR/AND
id: network uuid OR/AND
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:
filter_entry["type"] = "bridge"
filtered_entry = filter_entry.copy()
- # we remove all the key : value we dont' care and match only
- # respected field
- filtered_dict = set(filter_entry.keys()) - set(filter_dict)
- for unwanted_key in filtered_dict: del filter_entry[unwanted_key]
- if filter_dict == filter_entry:
+ if filter_dict is not None and filter_dict:
+ # we remove all the key : value we don't care and match only
+ # respected field
+ filtered_dict = set(filter_entry.keys()) - set(filter_dict)
+ for unwanted_key in filtered_dict: del filter_entry[unwanted_key]
+ if filter_dict == filter_entry:
+ network_list.append(filtered_entry)
+ else:
network_list.append(filtered_entry)
except:
self.logger.debug("Error in get_vcd_network_list")
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:
+ def create_vimcatalog(self, vca=None, catalog_name=None):
+ """ Create new catalog entry in vcloud director.
+
+
+ Args
+ vca: vCloud director.
+ catalog_name catalog that client wish to create. Note no validation done for a name.
+ Client must make sure that provide valid string representation.
+
+ Return (bool) True if catalog created.
+
+ """
+ try:
+ task = vca.create_catalog(catalog_name, catalog_name)
+ result = vca.block_until_completed(task)
+ if not result:
+ return False
+ catalogs = vca.get_catalogs()
+ except:
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,
# TODO add named parameters for readbility
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):
+ def validate_uuid4(self, uuid_string=None):
+ """ Method validate correct format of UUID.
+
+ Return: true if string represent valid uuid
+ """
+ try:
+ val = uuid.UUID(uuid_string, version=4)
+ except ValueError:
+ return False
+ return True
+
+ def get_catalogid(self, catalog_name=None, catalogs=None):
+ """ Method check catalog and return catalog ID in UUID format.
+
+ Args
+ catalog_name: catalog name as string
+ catalogs: list of catalogs.
+
+ Return: catalogs uuid
+ """
+
for catalog in catalogs:
if catalog.name == catalog_name:
catalog_id = catalog.get_id().split(":")
return catalog_id[3]
return None
- def get_catalogbyid(self, catalog_id, catalogs):
+ def get_catalogbyid(self, catalog_uuid=None, catalogs=None):
+ """ Method check catalog and return catalog name lookup done by catalog UUID.
+
+ Args
+ catalog_name: catalog name as string
+ catalogs: list of catalogs.
+
+ Return: catalogs name or None
+ """
+
+ if not self.validate_uuid4(uuid_string=catalog_uuid):
+ return None
+
for catalog in catalogs:
- catalogid = catalog.get_id().split(":")[3]
- if catalogid == catalog_id:
+ catalog_id = catalog.get_id().split(":")[3]
+ if catalog_id == catalog_uuid:
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.)
- '''
+ def get_image_id_from_path(self, path=None):
+ """ Method upload OVF image to vCloud director.
+
+ Each OVF image represented as single catalog entry in vcloud director.
+ The method check for existing catalog entry. The check done by file name without file extension.
+
+ if given catalog name already present method will respond with existing catalog uuid otherwise
+ it will create new catalog entry and upload OVF file to newly created catalog.
+
+ If method can't create catalog entry or upload a file it will throw exception.
+ Args
+ path: valid path to OVF file.
+
+ Return: if image uploaded correct method will provide image catalog UUID.
+ """
vca = self.connect()
if not vca:
raise vimconn.vimconnConnectionException("self.connect() is failed")
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."
+ 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))
self.logger.debug("Catalog name {}".format(catalog_name))
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)
+ raise vimconn.vimconnException("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)
+ raise vimconn.vimconnException("Failed create vApp template for catalog {} ".format(catalog_name))
return self.get_catalogid(catalog_name, vca.get_catalogs())
else:
for catalog in catalogs:
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)
+ raise vimconn.vimconnException("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)
+ raise vimconn.vimconnException("Failed create vApp template for catalog {} ".format(catalog_name))
return self.get_catalogid(catalog_name, vca.get_catalogs())
vdc: The VDC object.
vapp_name: is application vappp name identifier
- Returns:
+ Returns:
The return vApp name otherwise None
"""
-
- """ Take vdc object and vApp name and returns vapp uuid or None
- """
-
if vdc is None or vapp_name is None:
return None
# UUID has following format https://host/api/vApp/vapp-30da58a3-e7c7-4d09-8f68-d4c8201169cf
return None
return None
- def new_vminstance(self, name, description, start, image_id, flavor_id, net_list, cloud_config=None):
+ def new_vminstance(self, name=None, description="", start=False, image_id=None, flavor_id=None, net_list={}, cloud_config=None):
"""Adds a VM instance to VIM
Params:
start: indicates if VM must start or boot in pause mode. Ignored
vdc = vca.get_vdc(self.tenant_name)
if vdc is None:
raise vimconn.vimconnUnexpectedResponse(
- "new_vminstance(): Failed create vApp {}: (Failed reprieve VDC information)".format(name))
+ "new_vminstance(): Failed create vApp {}: (Failed retrieve VDC information)".format(name))
catalogs = vca.get_catalogs()
if catalogs is None:
raise vimconn.vimconnUnexpectedResponse(
- "new_vminstance(): Failed create vApp {}: Failed create vApp {}: (Failed reprieve Catalog information)".format(
- name))
-
- flavor = flavorlist[flavor_id]
- if catalogs is None:
- raise vimconn.vimconnUnexpectedResponse(
- "new_vminstance(): Failed create vApp {}: (Failed reprieve Flavor information)".format(name))
+ "new_vminstance(): Failed create vApp {}: Failed create vApp {}: "
+ "(Failed retrieve catalog information)".format(name))
+
+ vm_cpus = None
+ vm_memory = None
+ if flavor_id is not None:
+ flavor = flavorlist[flavor_id]
+ if flavor is None:
+ raise vimconn.vimconnUnexpectedResponse(
+ "new_vminstance(): Failed create vApp {}: (Failed retrieve flavor information)".format(name))
+ else:
+ try:
+ vm_cpus = flavor['vcpus']
+ vm_memory= flavor['ram']
+ except KeyError:
+ raise vimconn.vimconnException("Corrupted flavor. {}".format(flavor_id))
# image upload creates template name as catalog name space Template.
- templateName = self.get_catalogbyid(image_id, catalogs) + ' Template'
+
+ print image_id
+
+ templateName = self.get_catalogbyid(catalog_uuid=image_id, catalogs=catalogs) + ' Template'
power_on = 'false'
if start:
power_on = 'true'
# client must provide at least one entry in net_list if not we report error
- primary_net = net_list[0]
- if primary_net is None:
- raise vimconn.vimconnUnexpectedResponse("new_vminstance(): Failed network list is empty.".format(name))
+ primary_net = None
+ primary_net_name = None
+ if net_list is not None and len(net_list) > 0:
+ primary_net = net_list[0]
+ if primary_net is None:
+ raise vimconn.vimconnUnexpectedResponse("new_vminstance(): Failed network list is empty.".format(name))
- primary_net_id = primary_net['net_id']
- primary_net_name = self.get_network_name_by_id(primary_net_id)
- network_mode = primary_net['use']
+ 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))
# use: 'data', 'bridge', 'mgmt'
# create vApp. Set vcpu and ram based on flavor id.
vapptask = vca.create_vapp(self.tenant_name, name, templateName,
self.get_catalogbyid(image_id, catalogs),
- network_name=primary_net_name,
+ network_name=primary_net_name, # can be None if net_list None
network_mode='bridged',
vm_name=name,
- vm_cpus=flavor['vcpus'],
- vm_memory=flavor['ram'])
+ 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))
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 managment DHCP all remaining in bridge mode
+ # 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,
ip_allocation_mode='DHCP')
the_vapp.poweron()
elif "pause" in action_dict:
pass
- ##server.pause()
+ ## server.pause()
elif "resume" in action_dict:
pass
- ##server.resume()
+ ## server.resume()
elif "shutoff" in action_dict or "shutdown" in action_dict:
the_vapp.shutdown()
elif "forceOff" in action_dict:
Method retrieves available organization in vCloud Director
Args:
- vca - is active VCA connection.
- vdc_name - is a vdc name that will be used to query vms action
+ org_uuid - is a organization uuid.
Returns:
- The return dictionary and key for each entry vapp UUID
+ The return dictionary with following key
+ "network" - for network list under the org
+ "catalogs" - for network list under the org
+ "vdcs" - for vdc list under org
"""
org_dict = {}
-
vca = self.connect()
if not vca:
raise vimconn.vimconnConnectionException("self.connect() is failed")
def get_vapp(self, vdc_name=None, vapp_name=None, isuuid=False):
"""
- Method retrieves VM's list deployed vCloud director. It returns a dictionary
+ Method retrieves VM deployed vCloud director. It returns VM attribute as dictionary
contains a list of all VM's deployed for queried VDC.
The key for a dictionary is VM UUID
try:
vm_list_xmlroot = XmlElementTree.fromstring(content)
for vm_xml in vm_list_xmlroot:
- if vm_xml.tag.split("}")[1] == 'VMRecord':
+ if vm_xml.tag.split("}")[1] == 'VMRecord' and vm_xml.attrib['isVAppTemplate'] == 'false':
+ # lookup done by UUID
if isuuid:
- # lookup done by UUID
if vapp_name in vm_xml.attrib['container']:
rawuuid = vm_xml.attrib['href'].split('/')[-1:]
if 'vm-' in rawuuid[0]:
- # vm in format vm-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
- # vm and use raw UUID as key
vm_dict[rawuuid[0][3:]] = vm_xml.attrib
- # lookup done by Name
- else:
- if vapp_name in vm_xml.attrib['name']:
- rawuuid = vm_xml.attrib['href'].split('/')[-1:]
- if 'vm-' in rawuuid[0]:
- vm_dict[rawuuid[0][3:]] = vm_xml.attrib
- # vm in format vm-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
- # vm and use raw UUID as key
+ break
+ # lookup done by Name
+ else:
+ if vapp_name in vm_xml.attrib['name']:
+ rawuuid = vm_xml.attrib['href'].split('/')[-1:]
+ if 'vm-' in rawuuid[0]:
+ vm_dict[rawuuid[0][3:]] = vm_xml.attrib
+ break
except:
pass
xml_content = self.create_vdc_from_tmpl_rest(vdc_name=vdc_name)
if xml_content is not None:
- print xml_content
try:
task_resp_xmlroot = XmlElementTree.fromstring(xml_content)
for child in task_resp_xmlroot:
"""
self.logger.info("Creating new vdc {}".format(vdc_name))
- print ("Creating new vdc {}".format(vdc_name))
-
vca = self.connect()
if not vca:
raise vimconn.vimconnConnectionException("self.connect() is failed")
"""
self.logger.info("Creating new vdc {}".format(vdc_name))
- print ("Creating new vdc {}".format(vdc_name))
vca = self.connect_as_admin()
if not vca:
return None
response = self.get_provider_rest(vca=vca)
- print response
try:
vm_list_xmlroot = XmlElementTree.fromstring(response)
for child in vm_list_xmlroot:
self.logger.debug("Respond body {}".format(response))
return None
- print "Add vdc {}".format(add_vdc_rest_url)
- print "Provider ref {}".format(provider_vdc_ref)
if add_vdc_rest_url is not None and provider_vdc_ref is not None:
data = """ <CreateVdcParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5"><Description>{1:s}</Description>
<AllocationModel>ReservationPool</AllocationModel>
escape(vdc_name),
provider_vdc_ref)
- print data
headers = vca.vcloud_session.get_vcloud_headers()
headers['Content-Type'] = 'application/vnd.vmware.admin.createVdcParams+xml'
response = Http.post(url=add_vdc_rest_url, headers=headers, data=data, verify=vca.verify,
logger=vca.logger)
- print response.status_code
- print response.content
# if we all ok we respond with content otherwise by default None
if response.status_code == 201:
return response.content
# contact with: mbayramov@vmware.com
##
-'''
+"""
-Provide standalone application to work with vCloud director rest api.
+Standalone application that leverage openmano vmware connector work with vCloud director rest api.
+ - Provides capability to create and delete VDC for specific organization.
+ - Create, delete and manage network for specific VDC
+ - List deployed VM's , VAPPs, VDSs, Organization
+ - View detail information about VM / Vapp , Organization etc
+ - Operate with images upload / boot / power on etc
+
+ Usage example.
+
+ List organization created in vCloud director
+ vmwarecli.py -u admin -p qwerty123 -c 172.16.254.206 -U Administrator -P qwerty123 -o test -v TEF list org
+
+ List VDC for particular organization
+ vmwarecli.py -u admin -p qwerty123 -c 172.16.254.206 -U Administrator -P qwerty123 -o test -v TEF list vdc
+
+ Upload image
+ python vmwarerecli.py image upload /Users/spyroot/Developer/Openmano/Ro/vnfs/cirros/cirros.ovf
+
+ Boot Image
+ python vmwarerecli.py -u admin -p qwerty123 -c 172.16.254.206 -o test -v TEF image boot cirros cirros
+
+ View vApp
+ python vmwarerecli.py -u admin -p qwerty123 -c 172.16.254.206 -o test -v TEF view vapp 90bd2b4e-f782-46cf-b5e2-c3817dcf6633 -u
+
+ List VMS
+ python vmwarerecli.py -u admin -p qwerty123 -c 172.16.254.206 -o test -v TEF list vms
+
+ List VDC in OSM format
+ python vmwarerecli.py -u admin -p qwerty123 -c 172.16.254.206 -o test -v TEF list vdc -o
+
+Mustaafa Bayramov
mbayramov@vmware.com
-'''
+"""
import os
-import requests
-import logging
-import sys
import argparse
import traceback
+import uuid
from xml.etree import ElementTree as ET
from pyvcloud import Http
-from pyvcloud.vcloudair import VCA
-from pyvcloud.schema.vcd.v1_5.schemas.vcloud.networkType import *
-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
import urllib3
import requests
from vimconn_vmware import vimconnector
from requests.packages.urllib3.exceptions import InsecureRequestWarning
from prettytable import PrettyTable
-from xml.etree import ElementTree as XmlElementTree
-from prettytable import PrettyTable
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
__date__ = "$16-Sep-2016 11:09:29$"
-#TODO move to main vim
+# TODO move to main vim
def delete_network_action(vca=None, network_uuid=None):
"""
Method leverages vCloud director and query network based on network uuid
# 'href': 'https://172.16.254.206/api/vAppTemplate/vm-129e22e8-08dc-4cb6-8358-25f635e65d3b',
# 'isBusy': 'false', 'isDeployed': 'false', 'isInMaintenanceMode': 'false', 'isVAppTemplate': 'true',
# 'networkName': 'nat', 'isDeleted': 'false', 'catalogName': 'Cirros',
- # 'containerName': 'Cirros Template', # 'container': 'https://172.16.254.206/api/vAppTemplate/vappTemplate-b966453d-c361-4505-9e38-ccef45815e5d',
+ # 'containerName': 'Cirros Template', # 'container':
+ # 'https://172.16.254.206/api/vAppTemplate/vappTemplate-b966453d-c361-4505-9e38-ccef45815e5d',
# 'name': 'Cirros', 'pvdcHighestSupportedHardwareVersion': '11', 'isPublished': 'false',
# 'numberOfCpus': '1', 'vdc': 'https://172.16.254.206/api/vdc/a5056f85-418c-4bfd-8041-adb0f48be9d9',
# 'guestOs': 'Other (32-bit)', 'isVdcEnabled': 'true'}
if vapp_dict is None:
return
- vm_table = PrettyTable(['vapp uuid',
+ vm_table = PrettyTable(['vm uuid',
'vapp name',
- 'vdc uuid',
+ 'vapp uuid',
'network name',
- 'category name',
- 'storageProfileName',
- 'vcpu', 'memory', 'hw ver'])
+ 'storage name',
+ 'vcpu', 'memory', 'hw ver','deployed','status'])
for k in vapp_dict:
entry = []
entry.append(k)
entry.append(vapp_dict[k]['containerName'])
- entry.append(vapp_dict[k]['vdc'].split('/')[-1:][0])
+ # vm-b1f5cd4c-2239-4c89-8fdc-a41ff18e0d61
+ entry.append(vapp_dict[k]['container'].split('/')[-1:][0][5:])
entry.append(vapp_dict[k]['networkName'])
- entry.append(vapp_dict[k]['catalogName'])
entry.append(vapp_dict[k]['storageProfileName'])
entry.append(vapp_dict[k]['numberOfCpus'])
entry.append(vapp_dict[k]['memoryMB'])
entry.append(vapp_dict[k]['pvdcHighestSupportedHardwareVersion'])
+ entry.append(vapp_dict[k]['isDeployed'])
+ entry.append(vapp_dict[k]['status'])
vm_table.add_row(entry)
""" Method takes vapp_dict and print in tabular format
Args:
- org_dict: dictionary of organization where key is org uuid.
+ vm_dict: dictionary of organization where key is org uuid.
Returns:
The return nothing
pass
-def print_org_details(org_dict=None):
+def print_vdc_list(org_dict=None):
""" Method takes vapp_dict and print in tabular format
Args:
if org_dict is None:
return
try:
- network_dict = {}
- catalogs_dict = {}
vdcs_dict = {}
-
- if org_dict.has_key('networks'):
- network_dict = org_dict['networks']
-
if org_dict.has_key('vdcs'):
vdcs_dict = org_dict['vdcs']
-
- if org_dict.has_key('catalogs'):
- catalogs_dict = org_dict['catalogs']
-
vdc_table = PrettyTable(['vdc uuid', 'vdc name'])
for k in vdcs_dict:
entry = [k, vdcs_dict[k]]
vdc_table.add_row(entry)
+ print vdc_table
+ except KeyError:
+ logger.error("wrong key {}".format(KeyError.message))
+ logger.logger.debug(traceback.format_exc())
+
+
+def print_network_list(org_dict=None):
+ """ Method print network list.
+
+ Args:
+ org_dict: dictionary of organization that contain key networks with a list of all
+ network for for specific VDC
+
+ Returns:
+ The return nothing
+ """
+ if org_dict is None:
+ return
+ try:
+ network_dict = {}
+ if org_dict.has_key('networks'):
+ network_dict = org_dict['networks']
network_table = PrettyTable(['network uuid', 'network name'])
for k in network_dict:
entry = [k, network_dict[k]]
network_table.add_row(entry)
+ print network_table
+
+ except KeyError:
+ logger.error("wrong key {}".format(KeyError.message))
+ logger.logger.debug(traceback.format_exc())
+
+
+def print_org_details(org_dict=None):
+ """ Method takes vapp_dict and print in tabular format
+
+ Args:
+ org_dict: dictionary of organization where key is org uuid.
+
+ Returns:
+ The return nothing
+ """
+ if org_dict is None:
+ return
+ try:
+ catalogs_dict = {}
+
+ print_vdc_list(org_dict=org_dict)
+ print_network_list(org_dict=org_dict)
+
+ if org_dict.has_key('catalogs'):
+ catalogs_dict = org_dict['catalogs']
+
catalog_table = PrettyTable(['catalog uuid', 'catalog name'])
for k in catalogs_dict:
entry = [k, catalogs_dict[k]]
catalog_table.add_row(entry)
- print vdc_table
- print network_table
print catalog_table
except KeyError:
def list_actions(vim=None, action=None, namespace=None):
+ """ Method provide list object from VDC action
+
+ Args:
+ vim - is vcloud director vim connector.
+ action - is action for list ( vdc / org etc)
+ namespace - must contain VDC / Org information.
+
+ Returns:
+ The return nothing
+ """
+
+ org_id = None
+ myorgs = vim.get_org_list()
+ for org in myorgs:
+ if myorgs[org] == namespace.vcdorg:
+ org_id = org
+ break
+ else:
+ print(" Invalid organization.")
+ return
+
if action == 'vms' or namespace.action == 'vms':
vm_dict = vim.get_vm_list(vdc_name=namespace.vcdvdc)
print_vm_list(vm_dict=vm_dict)
vapp_dict = vim.get_vapp_list(vdc_name=namespace.vcdvdc)
print_vapp(vapp_dict=vapp_dict)
elif action == 'networks' or namespace.action == 'networks':
- print "Requesting networks"
- # var = OrgVdcNetworkType.get_status()
+ if namespace.osm:
+ osm_print(vim.get_network_list(filter_dict={}))
+ else:
+ print_network_list(vim.get_org(org_uuid=org_id))
elif action == 'vdc' or namespace.action == 'vdc':
- vm_dict = vim.get_vm_list(vdc_name=namespace.vcdvdc)
- print_vm_list(vm_dict=vm_dict)
+ if namespace.osm:
+ osm_print(vim.get_tenant_list(filter_dict=None))
+ else:
+ print_vdc_list(vim.get_org(org_uuid=org_id))
elif action == 'org' or namespace.action == 'org':
- logger.debug("Listing avaliable orgs")
print_org(org_dict=vim.get_org_list())
else:
return None
+def print_network_details(network_dict=None):
+ try:
+ network_table = PrettyTable(network_dict.keys())
+ entry = [network_dict.values()]
+ network_table.add_row(entry[0])
+ print network_table
+ except KeyError:
+ logger.error("wrong key {}".format(KeyError.message))
+ logger.logger.debug(traceback.format_exc())
+
+
+def osm_print(generic_dict=None):
+
+ try:
+ for element in generic_dict:
+ table = PrettyTable(element.keys())
+ entry = [element.values()]
+ table.add_row(entry[0])
+ print table
+ except KeyError:
+ logger.error("wrong key {}".format(KeyError.message))
+ logger.logger.debug(traceback.format_exc())
+
+
def view_actions(vim=None, action=None, namespace=None):
+ org_id = None
+ orgs = vim.get_org_list()
+ for org in orgs:
+ if orgs[org] == namespace.vcdorg:
+ org_id = org
+ break
+ else:
+ print(" Invalid organization.")
+ return
+
+ myorg = vim.get_org(org_uuid=org_id)
+
# view org
if action == 'org' or namespace.action == 'org':
org_id = None
# view vapp action
if action == 'vapp' or namespace.action == 'vapp':
- if namespace.vapp_name is not None and namespace.uuid == False:
+ print namespace.vapp_name
+ if namespace.vapp_name is not None and namespace.uuid:
logger.debug("Requesting vapp {} for vdc {}".format(namespace.vapp_name, namespace.vcdvdc))
-
vapp_dict = {}
+ vapp_uuid = namespace.vapp_name
# if request based on just name we need get UUID
if not namespace.uuid:
- vappid = vim.get_vappid(vdc=namespace.vcdvdc, vapp_name=namespace.vapp_name)
+ vapp_uuid = vim.get_vappid(vdc=namespace.vcdvdc, vapp_name=namespace.vapp_name)
+ if vapp_uuid is None:
+ print("Can't find vapp by given name {}".format(namespace.vapp_name))
+ return
- vapp_dict = vim.get_vapp(vdc_name=namespace.vcdvdc, vapp_name=vappid, isuuid=True)
- print_vapp(vapp_dict=vapp_dict)
+ vapp_dict = vim.get_vapp(vdc_name=namespace.vcdvdc, vapp_name=vapp_uuid, isuuid=True)
+ if vapp_dict is not None:
+ print_vapp(vapp_dict=vapp_dict)
# view network
if action == 'network' or namespace.action == 'network':
# if request name based we need find UUID
# TODO optimize it or move to external function
if not namespace.uuid:
- org_dict = vim.get_org_list()
- for org in org_dict:
- org_net = vim.get_org(org)['networks']
- for network in org_net:
- if org_net[network] == namespace.network_name:
- network_uuid = network
+ if not myorg.has_key('networks'):
+ print("Network {} is undefined in vcloud director for org {} vdc {}".format(namespace.network_name,
+ vim.name,
+ vim.tenant_name))
+ return
+
+ my_org_net = myorg['networks']
+ for network in my_org_net:
+ if my_org_net[network] == namespace.network_name:
+ network_uuid = network
+ break
- print vim.get_vcd_network(network_uuid=network_uuid)
+ print print_network_details(network_dict=vim.get_vcd_network(network_uuid=network_uuid))
def create_actions(vim=None, action=None, namespace=None):
return None
-def vmwarecli(command=None, action=None, namespace=None):
+def validate_uuid4(uuid_string):
+ """Function validate that string contain valid uuid4
+
+ Args:
+ uuid_string - valid UUID string
+
+ Returns:
+ The return true if string contain valid UUID format
+ """
+ try:
+ val = uuid.UUID(uuid_string, version=4)
+ except ValueError:
+ return False
+ return True
+
+
+def upload_image(vim=None, image_file=None):
+ """Function upload image to vcloud director
+
+ Args:
+ image_file - valid UUID string
+ Returns:
+ The return true if image uploaded correctly
+ """
+ try:
+ catalog_uuid = vim.get_image_id_from_path(path=image_file)
+ if catalog_uuid is not None and validate_uuid4(catalog_uuid):
+ print("Image uploaded and uuid {}".format(catalog_uuid))
+ return True
+ except:
+ print("Failed uploaded {} image".format(image_file))
+
+ return False
+
+
+def boot_image(vim=None, image_name=None, vm_name=None):
+ """ Function boot image that resided in vcloud director.
+ The image name can be UUID of name.
+
+ Args:
+ image_name - image identified by UUID or text string.
+ vm_name
+
+ Returns:
+ The return true if image uploaded correctly
+ """
+
+ vim_catalog = None
+ try:
+ catalogs = vim.vca.get_catalogs()
+ if not validate_uuid4(image_name):
+ vim_catalog = vim.get_catalogid(catalog_name=image_name, catalogs=catalogs)
+ if vim_catalog is None:
+ return None
+ else:
+ vim_catalog = vim.get_catalogid(catalog_name=image_name, catalogs=catalogs)
+ if vim_catalog is None:
+ return None
+
+ vm_uuid = vim.new_vminstance(name=vm_name, image_id=vim_catalog)
+ if vm_uuid is not None and validate_uuid4(vm_uuid):
+ print("Image booted and vm uuid {}".format(vm_uuid))
+ vapp_dict = vim.get_vapp(vdc_name=namespace.vcdvdc, vapp_name=vm_uuid, isuuid=True)
+ if vapp_dict is not None:
+ print_vapp(vapp_dict=vapp_dict)
+ return True
+ except:
+ print("Failed uploaded {} image".format(image_name))
+
+
+def image_action(vim=None, action=None, namespace=None):
+ """ Function present set of action to manipulate with image.
+ - upload image
+ - boot image.
+ - delete image ( not yet done )
+
+ Args:
+ vim - vcloud director connector
+ action - string (upload/boot etc)
+ namespace - contain other attributes image name etc
+
+ Returns:
+ The return nothing
+ """
+
+ if action == 'upload' or namespace.action == 'upload':
+ upload_image(vim=vim, image_file=namespace.image)
+ elif action == 'boot' or namespace.action == 'boot':
+ boot_image(vim=vim, image_name=namespace.image, vm_name=namespace.vmname)
+ else:
+ return None
+
+
+def vmwarecli(command=None, action=None, namespace=None):
logger.debug("Namespace {}".format(namespace))
urllib3.disable_warnings()
+ vcduser = None
+ vcdpasword = None
+ vcdhost = None
+ vcdorg = None
+
+ if hasattr(__builtins__, 'raw_input'):
+ input = raw_input
+
+ if namespace.vcdvdc is None:
+ while True:
+ vcduser = input("Enter vcd username: ")
+ if vcduser is not None and len(vcduser) > 0:
+ break
+ else:
+ vcduser = namespace.vcduser
+
if namespace.vcdpassword is None:
- vcdpasword = input("vcd password ")
+ while True:
+ vcdpasword = input("Please enter vcd password: ")
+ if vcdpasword is not None and len(vcdpasword) > 0:
+ break
else:
vcdpasword = namespace.vcdpassword
- vim = vimconnector(uuid=None,
- name=namespace.org_name,
- tenant_id=None,
- tenant_name=namespace.vcdvdc,
- url=namespace.vcdhost,
- url_admin=namespace.vcdhost,
- user=namespace.vcduser,
- passwd=namespace.vcdpassword,
- log_level="DEBUG",
- config={'admin_username': namespace.vcdamdin, 'admin_password': namespace.vcdadminpassword})
- vim.vca = vim.connect()
+
+ if namespace.vcdhost is None:
+ while True:
+ vcdhost = input("Please enter vcd host name or ip: ")
+ if vcdhost is not None and len(vcdhost) > 0:
+ break
+ else:
+ vcdhost = namespace.vcdhost
+
+ if namespace.vcdorg is None:
+ while True:
+ vcdorg = input("Please enter vcd organization name: ")
+ if vcdorg is not None and len(vcdorg) > 0:
+ break
+ else:
+ vcdorg = namespace.vcdorg
+
+ try:
+ vim = vimconnector(uuid=None,
+ name=vcdorg,
+ tenant_id=None,
+ tenant_name=namespace.vcdvdc,
+ url=vcdhost,
+ url_admin=vcdhost,
+ user=vcduser,
+ passwd=vcdpasword,
+ log_level="DEBUG",
+ config={'admin_username': namespace.vcdamdin, 'admin_password': namespace.vcdadminpassword})
+ vim.vca = vim.connect()
+ except vimconn.vimconnConnectionException:
+ print("Failed connect to vcloud director. Please check credential and hostname.")
+ return
# list
if command == 'list' or namespace.command == 'list':
logger.debug("Client requested create action")
create_actions(vim=vim, action=action, namespace=namespace)
+ # image action
+ if command == 'image' or namespace.command == 'image':
+ logger.debug("Client requested create action")
+ image_action(vim=vim, action=action, namespace=namespace)
+
if __name__ == '__main__':
defaults = {'vcdvdc': 'default',
parser_subparsers = parser.add_subparsers(help='commands', dest='command')
sub = parser_subparsers.add_parser('list', help='List objects (VMs, vApps, networks)')
sub_subparsers = sub.add_subparsers(dest='action')
- view_vms = sub_subparsers.add_parser('vms', help='list - all vm deployed in vCloud director')
- view_vapps = sub_subparsers.add_parser('vapps', help='list - all vapps deployed in vCloud director')
- view_network = sub_subparsers.add_parser('networks', help='list - all networks deployed')
- view_vdc = sub_subparsers.add_parser('vdc', help='list - list all vdc for organization accessible to you')
- view_vdc = sub_subparsers.add_parser('org', help='list - list of organizations accessible to you.')
+
+ list_vms = sub_subparsers.add_parser('vms', help='list - all vm deployed in vCloud director')
+ list_vapps = sub_subparsers.add_parser('vapps', help='list - all vapps deployed in vCloud director')
+ list_network = sub_subparsers.add_parser('networks', help='list - all networks deployed')
+ list_network.add_argument('-o', '--osm', default=False, action='store_true', help='provide view in OSM format')
+
+ #list vdc
+ list_vdc = sub_subparsers.add_parser('vdc', help='list - list all vdc for organization accessible to you')
+ list_vdc.add_argument('-o', '--osm', default=False, action='store_true', help='provide view in OSM format')
+
+ list_org = sub_subparsers.add_parser('org', help='list - list of organizations accessible to you.')
create_sub = parser_subparsers.add_parser('create')
create_sub_subparsers = create_sub.add_subparsers(dest='action')
help='- View VDC based and action based on provided vdc uuid')
view_org.add_argument('-u', '--uuid', default=False, action='store_true', help='view org based on uuid')
- #
- # view_org.add_argument('uuid', default=False, action='store',
- # help='- View Organization and action based on provided uuid.')
- # view_org.add_argument('name', default=False, action='store_true',
- # help='- View Organization and action based on provided name')
+ # upload image action
+ image_sub = parser_subparsers.add_parser('image')
+ image_subparsers = image_sub.add_subparsers(dest='action')
+ upload_parser = image_subparsers.add_parser('upload')
+ upload_parser.add_argument('image', default=False, action='store', help='- valid path to OVF image ')
+ upload_parser.add_argument('catalog', default=False, action='store_true', help='- catalog name')
+
+ # boot vm action
+ boot_parser = image_subparsers.add_parser('boot')
+ boot_parser.add_argument('image', default=False, action='store', help='- Image name')
+ boot_parser.add_argument('vmname', default=False, action='store', help='- VM name')
+ boot_parser.add_argument('-u', '--uuid', default=False, action='store_true', help='view org based on uuid')
namespace = parser.parse_args()
# put command_line args to mapping
# main entry point.
vmwarecli(namespace=namespace)
-