# 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
+import sys
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
def delete_network_action(vca=None, network_uuid=None):
"""
Method leverages vCloud director and query network based on network uuid
"""
# following key available to print
-
# {'status': 'POWERED_OFF', 'storageProfileName': '*', 'hardwareVersion': '7', 'vmToolsVersion': '0',
# 'memoryMB': '384',
# '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:
+ 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_dict = vim.get_vapp(vdc_name=namespace.vcdvdc, vapp_name=vappid, isuuid=True)
- print_vapp(vapp_dict=vapp_dict)
+ 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
+
+ print " namespace {}".format(namespace)
+ if vapp_dict is not None and namespace.osm:
+ vm_info_dict = vim.get_vminstance(vim_vm_uuid=vapp_uuid)
+ print vm_info_dict
+ if vapp_dict is not None and namespace.osm != True:
+ vapp_dict = vim.get_vapp(vdc_name=namespace.vcdvdc, vapp_name=vapp_uuid, isuuid=True)
+ 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):
- print namespace
+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, progress=True)
+ if catalog_uuid is not None and validate_uuid4(catalog_uuid):
+ print("Image uploaded and uuid {}".format(catalog_uuid))
+ return True
+ except vimconn.vimconnException as upload_exception:
+ print("Failed uploaded {} image".format(image_file))
+ print("Error Reason: {}".format(upload_exception.message))
+ 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:
+ vim - vim connector
+ image_name - image identified by UUID or text string.
+ vm_name - vmname
+
+
+ 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
+
+ print (" Booting {} image id {} ".format(vm_name, vim_catalog))
+ 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 vimconn.vimconnNotFoundException as notFound:
+ print("Failed boot {} image".format(image_name))
+ print(notFound.message)
+ except vimconn.vimconnException as vimconError:
+ print("Failed boot {} image".format(image_name))
+ print(vimconError.message)
+ except:
+ print("Failed boot {} image".format(image_name))
+
+
+ return False
+
+
+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()
- vim = vimconnector('0cd19677-7517-11e6-aa08-000c29db3077',
- 'test',
- 'a5056f85-418c-4bfd-8041-adb0f48be9d9',
- namespace.vcdvdc,
- 'https://172.16.254.206',
- 'https://172.16.254.206',
- 'admin',
- 'qwerty123',
- "DEBUG", config={'admin_username': 'Administrator', 'admin_password': 'qwerty123'})
-
- vim.vca = vim.connect()
- #
- # "{'status': 'ACTIVE'}
- # 2016-09-26 13:06:33,989 - mano.vim.vmware - DEBUG - Adding 4d2e9ec6-e3d8-4014-a1ab-8b622524bd9c to a list vcd id a5056f85-418c-4bfd-8041-adb0f48be9d9 network tefexternal
- # Dict contains {'status': 'ACTIVE'}
- # 2016-09-26 13:06:33,989 - mano.vim.vmware - DEBUG - Adding 93729eaa-4159-4d18-ac28-b000f91bd331 to a list vcd id a5056f85-418c-4bfd-8041-adb0f48be9d9 network default
- # Dict contains {'status': 'ACTIVE'}
-
- vim.get_network_list(filter_dict={'status': 'ACTIVE', 'type': 'bridge'})
- # vim.get_network_list(filter_dict={'status' : 'ACTIVE'})
-
- # print vim.get_vminstance('7e06889a-50c4-4b08-8877-c1ef001eb030')
- # vim.get_network_name_by_id()
-
- # exit()
- # get_network_action(vca=vca, network_uuid="123")
+
+ 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:
+ while True:
+ vcdpasword = input("Please enter vcd password: ")
+ if vcdpasword is not None and len(vcdpasword) > 0:
+ break
+ else:
+ vcdpasword = namespace.vcdpassword
+
+ 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)
-# def get_vappid(vdc, vapp_name):
-# 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:]
-# return None
if __name__ == '__main__':
defaults = {'vcdvdc': 'default',
parser = argparse.ArgumentParser()
parser.add_argument('-u', '--vcduser', help='vcloud director username', type=str)
parser.add_argument('-p', '--vcdpassword', help='vcloud director password', type=str)
+ parser.add_argument('-U', '--vcdamdin', help='vcloud director password', type=str)
+ parser.add_argument('-P', '--vcdadminpassword', help='vcloud director password', type=str)
parser.add_argument('-c', '--vcdhost', help='vcloud director host', type=str)
parser.add_argument('-o', '--vcdorg', help='vcloud director org', type=str)
parser.add_argument('-v', '--vcdvdc', help='vcloud director vdc', type=str)
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')
view_vapp_parser.add_argument('vapp_name', action='store',
help='- view vapp for specific vapp name in vcloud director')
view_vapp_parser.add_argument('-u', '--uuid', default=False, action='store_true', help='view vapp based on uuid')
+ view_vapp_parser.add_argument('-o', '--osm', default=False, action='store_true', help='provide view in OSM format')
# view network
view_network = view_sub_subparsers.add_parser('network')
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
"Connecting {} username: {} org: {} vdc: {} ".format(d['vcdhost'], d['vcduser'], d['vcdorg'], d['vcdvdc']))
logger.debug("command: \"{}\" actio: \"{}\"".format(d['command'], d['action']))
- vmwarecli(namespace=namespace)
+ # main entry point.
+ vmwarecli(namespace=namespace)