Refactored code and change return error code to exceptions.
authorbayramov <mbayramov@vmware.com>
Wed, 28 Sep 2016 07:50:56 +0000 (11:50 +0400)
committermbayramov <mbayramov@vmware.com>
Wed, 28 Sep 2016 13:01:59 +0000 (15:01 +0200)
Adjusted class now it inherited from base.

In vmwarecli added
 - 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

Signed-off-by: bayramov <mbayramov@vmware.com>
vimconn_vmware.py
vmwarerecli.py

index 99f5043..ff457ce 100644 (file)
@@ -104,6 +104,37 @@ flavorlist = {}
 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
@@ -202,14 +233,15 @@ class vimconnector(vimconn.vimconnector):
             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,
@@ -235,22 +267,24 @@ class vimconnector(vimconn.vimconnector):
                 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
 
@@ -283,12 +317,8 @@ class vimconnector(vimconn.vimconnector):
 
                 # 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
@@ -299,7 +329,6 @@ class vimconnector(vimconn.vimconnector):
                         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:
@@ -316,11 +345,16 @@ class vimconnector(vimconn.vimconnector):
             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:
@@ -336,16 +370,15 @@ class vimconnector(vimconn.vimconnector):
         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']
 
@@ -353,25 +386,29 @@ class vimconnector(vimconn.vimconnector):
         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))
@@ -430,7 +467,7 @@ class vimconnector(vimconn.vimconnector):
         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
@@ -444,7 +481,7 @@ class vimconnector(vimconn.vimconnector):
         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:
@@ -480,11 +517,14 @@ class vimconnector(vimconn.vimconnector):
                 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")
@@ -662,13 +702,26 @@ class vimconnector(vimconn.vimconnector):
                 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,
@@ -795,28 +848,68 @@ class vimconnector(vimconn.vimconnector):
         # 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")
@@ -827,9 +920,8 @@ class vimconnector(vimconn.vimconnector):
         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))
 
@@ -838,10 +930,10 @@ class vimconnector(vimconn.vimconnector):
             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:
@@ -858,10 +950,10 @@ class vimconnector(vimconn.vimconnector):
         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())
 
@@ -873,13 +965,9 @@ class vimconnector(vimconn.vimconnector):
             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
@@ -950,7 +1038,7 @@ class vimconnector(vimconn.vimconnector):
             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
@@ -989,42 +1077,61 @@ class vimconnector(vimconn.vimconnector):
         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))
@@ -1055,7 +1162,7 @@ class vimconnector(vimconn.vimconnector):
                             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')
@@ -1329,10 +1436,10 @@ class vimconnector(vimconn.vimconnector):
                         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:
@@ -1503,15 +1610,16 @@ class vimconnector(vimconn.vimconnector):
         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")
@@ -1670,7 +1778,7 @@ class vimconnector(vimconn.vimconnector):
 
     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
 
@@ -1694,23 +1802,21 @@ class vimconnector(vimconn.vimconnector):
         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
 
@@ -1999,7 +2105,6 @@ class vimconnector(vimconn.vimconnector):
 
         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:
@@ -2025,8 +2130,6 @@ class vimconnector(vimconn.vimconnector):
         """
 
         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")
@@ -2096,7 +2199,6 @@ class vimconnector(vimconn.vimconnector):
         """
 
         self.logger.info("Creating new vdc {}".format(vdc_name))
-        print ("Creating new vdc {}".format(vdc_name))
 
         vca = self.connect_as_admin()
         if not vca:
@@ -2135,7 +2237,6 @@ class vimconnector(vimconn.vimconnector):
                     return None
 
                 response = self.get_provider_rest(vca=vca)
-                print response
                 try:
                     vm_list_xmlroot = XmlElementTree.fromstring(response)
                     for child in vm_list_xmlroot:
@@ -2147,8 +2248,6 @@ class vimconnector(vimconn.vimconnector):
                     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>
@@ -2163,14 +2262,11 @@ class vimconnector(vimconn.vimconnector):
                                                                                                   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
index c28a1bc..547abf9 100755 (executable)
 # 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)
 
@@ -63,7 +81,7 @@ __author__ = "Mustafa Bayramov"
 __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
@@ -110,7 +128,8 @@ def print_vapp(vapp_dict=None):
     #  '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'}
@@ -118,24 +137,25 @@ def print_vapp(vapp_dict=None):
     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)
 
@@ -167,7 +187,7 @@ def print_vm_list(vm_dict=None):
     """ 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
@@ -197,7 +217,7 @@ def print_vm_list(vm_dict=None):
         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:
@@ -209,36 +229,73 @@ def print_org_details(org_dict=None):
     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:
@@ -264,6 +321,27 @@ def delete_actions(vim=None, action=None, namespace=None):
 
 
 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)
@@ -271,19 +349,58 @@ def list_actions(vim=None, action=None, namespace=None):
         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
@@ -303,16 +420,21 @@ def view_actions(vim=None, action=None, namespace=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':
@@ -321,14 +443,19 @@ def view_actions(vim=None, action=None, namespace=None):
         # 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):
@@ -359,26 +486,159 @@ 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':
@@ -401,6 +661,11 @@ def vmwarecli(command=None, action=None, namespace=None):
         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',
@@ -423,11 +688,17 @@ if __name__ == '__main__':
     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')
@@ -492,11 +763,18 @@ if __name__ == '__main__':
                           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
@@ -520,4 +798,3 @@ if __name__ == '__main__':
 
     # main entry point.
     vmwarecli(namespace=namespace)
-