# 
#   Copyright 2016 RIFT.IO Inc
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
#
# 

import os,sys,platform
import socket
import time
import re
import logging

from pprint import pprint
import argparse

from gi.repository import RwcalYang
from gi.repository.RwTypes import RwStatus
import rw_peas
import rwlogger
import time

global nova
nova = None

def wait_till_active(driver, account, vm_id_list, timeout):                                                                                                              
    """
    Wait until VM reaches ACTIVE state. 
    """
    # Wait while VM goes to required state

    start = time.time()
    end = time.time() + timeout
    done = False;

    while ( time.time() < end ) and not done:
       done = True      
       for vm_id in vm_id_list:
           rc, rs = driver.get_vm(account, vm_id)
           assert rc == RwStatus.SUCCESS
           if rs.state != 'ACTIVE':
               done = False		   
               time.sleep(2)


def get_image_name(node):
    images = driver.list_images()
    for i in images:
        if i.id == node.extra['imageId']:
            return i.name
    return None

def get_flavor_name(flavorid):
    global nova
    if nova is None:
        nova = ra_nova_connect(project='admin')
    for f in nova.flavors.list(True):
         if f.id == flavorid: 
             return f.name
    return None

def hostname():
    return socket.gethostname().split('.')[0]

def vm_register(id, driver, account, cmdargs, header=True):
    if testbed is None:
        print("Cannot register VM without reservation system")
        return False

    if cmdargs.reserve_new_vms:
        user=os.environ['USER']
    else:
        user=None
    fmt="%-28s %-12s %-12s %-15s"
    if header:
        print('VM                           controller   compute      mgmt ip')
        print('---------------------------- ------------ ------------ ---------------')
    rc, nodes = driver.get_vm_list(account)
    assert rc == RwStatus.SUCCESS
    for node in nodes.vminfo_list:
        if id == 'all' or node.vm_id == id:
            flavor = driver.get_flavor(account, node.flavor_id)
            assert rc == RwStatus.SUCCESS
            ip = node.management_ip
            
            huge = 'DISABLED'	    
            if flavor.guest_epa.mempage_size == 'LARGE':
                huge = flavor.guest_epa.mempage_size							    	    
            #compute = utils.find_resource(nova.servers, node.id)
            #compute_name = compute._info['OS-EXT-SRV-ATTR:hypervisor_hostname'].split('.')[0]
            compute_name = hostname()	    
            try:
                testbed.add_resource(node.vm_name, hostname(), ip, flavor.vm_flavor.memory_mb, flavor.vm_flavor.vcpu_count, user, flavor.name, compute=compute_name, huge_pages=huge )
                print(fmt % ( node.vm_name, hostname(), compute_name, ip )) 
            except Exception as e:
                print("WARNING: Error \"%s\"adding resource to reservation system" % e)

class OFromDict(object):
  def __init__(self, d):
    self.__dict__ = d


def vm_create_subcommand(driver, account, cmdargs):
    """Process the VM create subcommand."""
    if cmdargs.name and cmdargs.count != 1:
        sys.exit("Error: when VM name is specified, the count must be 1")

    rc, sizes = driver.get_flavor_list(account)
    assert rc == RwStatus.SUCCESS

    try:
        size = [s for s in sizes.flavorinfo_list if s.name == cmdargs.flavor][0]
    except IndexError:
        sys.exit("Error: Failed to create VM, couldn't find flavor %s" % \
                 cmdargs.flavor)
    print(size)
    rc, images = driver.get_image_list(account)
    assert rc == RwStatus.SUCCESS
    if images is None:
    	sys.exit("Error: No images found")
    try:
        image = [i for i in images.imageinfo_list if cmdargs.image in i.name][0]
    except IndexError:
        sys.exit("Error: Failed to create VM, couldn't find image %s" % \
                 cmdargs.image)
    print(image)

    # VM name is not specified, so determine a unique VM name
    # VM name should have the following format:
    #     rwopenstack_<host>_vm<id>, e.g., rwopenstack_grunt16_vm1
    # The following code gets the list of existing VMs and determines
    # a unique id for the VM name construction.
    rc, nodes = driver.get_vm_list(account)
    assert rc == RwStatus.SUCCESS
    prefix = 'rwopenstack_%s_vm' % hostname()
    vmid = 0;
    for n in nodes.vminfo_list:
        if n.vm_name.startswith(prefix):
            temp_str = n.vm_name[len(prefix):]
            if temp_str == '':
                temp = 1
            else:
                temp = int(n.vm_name[len(prefix):])

            if (temp > vmid):
                vmid = temp

    nodelist = []
    for i in range(0, cmdargs.count):
            if cmdargs.name:
                vm_name = cmdargs.name
            else:
                vm_name = '%s%d' % (prefix, vmid+i+1)
 
            rc, netlist = driver.get_network_list(account)
            assert rc == RwStatus.SUCCESS	
            for network in netlist.networkinfo_list:
                 print(network)    

            vm = RwcalYang.VMInfoItem()
            vm.vm_name = vm_name
            vm.flavor_id = size.id
            vm.image_id  = image.id
            vm.cloud_init.userdata = ''

            nets = dict()
            for network in netlist.networkinfo_list:
                if network.network_name != "public":
                    nwitem = RwcalYang.VMInfoItem_NetworkList()			
                    nwitem.network_id = network.network_id		    
                    nets[network.network_name] = nwitem
                     
            logger.debug('creating VM using nets %s' % cmdargs.networks )
            for net in cmdargs.networks.split(','):
                if not net in nets:
                    print(("Invalid network name '%s'" % net))
                    print(('available nets are %s' % ','.join(list(nets.keys())) ))
                    sys.exit(1)
                if net != cmdargs.mgmt_network:
                    vm.network_list.append(nets[net])

            print(vm.network_list)
            rc, node_id = driver.create_vm(account, vm) 

            # wait for 1 to be up before starting the rest
            # this is an attempt to make sure the image is cached
            nodelist.append(node_id)
            if i == 0 or cmdargs.wait_after_create is True:
                #wait_until_running([node], timeout=300)
                wait_till_active(driver, account, nodelist, timeout=300)		
            print(node_id)
    if cmdargs.reservation_server_url is not None:
            if not cmdargs.wait_after_create:
                print("Waiting for VMs to start")
                wait_till_active(driver, account, nodelist, timeout=300)		
                print("VMs are up")
            header=True
            for node in nodelist:
                vm_register(node, driver, account, cmdargs, header)
                header=False
                

def vm_destroy_subcommand(driver, account, cmdargs):
    rc, nodes = driver.get_vm_list(account)
    assert rc == RwStatus.SUCCESS	
    ct = len(nodes.vminfo_list)
    if cmdargs.destroy_all or cmdargs.wait:
        rc=0
        for n in nodes.vminfo_list:
            if testbed is not None:
                try:
                    testbed.remove_resource(n.vm_name)
                except:
                    print("WARNING: error deleting resource from reservation system")
            if RwStatus.SUCCESS != driver.delete_vm(account, n.vm_id):
                print('Error: failed to destroy node %s' % n.vm_name)
                rc=1
        if rc:
            sys.exit(1)
        if cmdargs.wait:
            while ct > 0:
                sys.stderr.write("waiting for %d VMs to exit...\n" % ct)
                time.sleep(1)
                try:
                    rc, nodesnw = driver.get_vm_list(account)
                    assert rc == RwStatus.SUCCESS	
                    ct = len(nodesnw.vminfo_list )
                except:
                    pass
        
    else:
        vm_re = re.compile('^%s$' % cmdargs.vm_name)
        ct = 0
        for n in nodes.vminfo_list:
            if vm_re.match(n.vm_name):
                ct += 1
                if testbed is not None:
                    try:
                        testbed.remove_resource(n.vm_name)
                    except:
                        print("WARNING: error deleting resource from reservation system")
                if RwStatus.SUCCESS != driver.delete_vm(account, n.vm_id):
                    print('Error: failed to destroy node %s' % n.vm_name)
                    return
                print('destroyed %s' % n.vm_name)
        if ct == 0:
            print("No VMs matching \"%s\" found" % ( cmdargs.vm_name ))
        
                    
def vm_rebuild_subcommand(driver, account, cmdargs):
    images = driver.list_images()
    found=0
    for i in images:
        if i.name == cmdargs.image_name:
            found=1
            break
    if found != 1:
        print('Error: Rebuild failed - image %s not found' % cmdargs.image_name)
        sys.exit(1)
    image=i
    nodes = driver.list_nodes()
    if cmdargs.rebuild_all:
        rc=0
        for n in nodes:
            if not driver.ex_rebuild(n,image):
                print('Error: failed to rebuild node %s' % n.name)
                rc=1
            if rc:
               sys.exit(1)
            rebuilt=0
            while rebuilt != 1:
                time.sleep(10)
                nw_nodes = driver.list_nodes()
                for nw in nw_nodes:
                    if nw.name == n.name:
                        if nw.state == n.state:
                            rebuilt=1
                        break  
    else:
        vm_re = re.compile('^%s$' % cmdargs.vm_name)
        ct = 0
        for n in nodes:
            if vm_re.match(n.name):
                ct += 1
                if not driver.ex_rebuild(n,image):
                    print('Error: failed to rebuild node %s' % n.name)
                    return
                print('Rebuilt %s' % n.name)
                rebuilt=0
                while rebuilt != 1:
                    time.sleep(10)
                    nw_nodes = driver.list_nodes()
                    for nw in nw_nodes:
                        if nw.name == n.name:
                            if nw.state == n.state:
                                rebuilt=1
                            break  
        if ct == 0:
            print("No VMs matching \"%s\" found" % ( cmdargs.vm_name ))
        
                    

def vm_reboot_subcommand(driver, account, cmdargs):
    rc, nodes = driver.get_vm_list(account)
    assert rc == RwStatus.SUCCESS	
    if cmdargs.reboot_all:
        for n in nodes.vminfo_list:
            '''
            if not n.reboot():
                print 'Error: failed to reboot node %s' % n.name
            else:
                print "rebooted %s" % n.name
            '''
            time.sleep(cmdargs.sleep_time)
    else:
        for n in nodes.vminfo_list:
            if n.vm_name == cmdargs.vm_name:
                if RwStatus.SUCCESS !=  driver.reboot_vm(account,n.vm_id):
                    print('Error: failed to reboot node %s' % n.vm_name)
                else:
                    print("rebooted %s" % n.vm_name)
                    

def vm_start_subcommand(driver, account, cmdargs):
    rc, nodes = driver.get_vm_list(account)
    assert rc == RwStatus.SUCCESS	
    if cmdargs.start_all:
        for n in nodes.vminfo_list:
            print(dir(n))
            if RwStatus.SUCCESS != driver.start_vm(account, n.vm_id):
                print('Error: failed to start node %s' % n.vm_name)
            else:
                print("started %s" % n.vm_name)
    else:
        for n in nodes.vminfo_list:
            if n.vm_name == cmdargs.vm_name:
                if RwStatus.SUCCESS != driver.start_vm(account, n.vm_id):
                    print('Error: failed to start node %s' % n.vm_name)
                else:
                    print("started %s" % n.vm_name)
                    
def vm_subcommand(driver, account, cmdargs):
    """Process the vm subcommand"""

    if cmdargs.which == 'list':
        rc, nodes = driver.get_vm_list(account)
        assert rc == RwStatus.SUCCESS	
        for n in nodes.vminfo_list:
            print(n)		
            if n.state == 4:
                if not cmdargs.ipsonly:
                    print("%s is shutoff" % n.vm_name)
            elif cmdargs.ipsonly:
                i = n.management_ip
                if i is not None:
                    print(i)
            else: 
                if n.management_ip is not None:
                    if len(n.private_ip_list) > 0:
                        print("%s %s,%s" % (n.vm_name, n.management_ip, ",".join([i.get_ip_address() for i in n.private_ip_list])))
                    else:
                        print("%s %s" % (n.vm_name, n.management_ip))
                else:
                    print("%s NO IP" % n.vm_name)

    elif cmdargs.which == 'create':
        vm_create_subcommand(driver, account, cmdargs)

    elif cmdargs.which == 'reboot':
        vm_reboot_subcommand(driver, account, cmdargs)
    elif cmdargs.which == 'start':
        vm_start_subcommand(driver, account, cmdargs)
    elif cmdargs.which == 'destroy':
        vm_destroy_subcommand(driver, account, cmdargs)
    #elif cmdargs.which == 'rebuild':
    #    vm_rebuild_subcommand(driver, account, cmdargs)

def image_delete_subcommand(driver, account, cmdargs):
    rc,images = driver.get_image_list(account)
    assert rc == RwStatus.SUCCESS
    account.openstack.key          = 'admin'
    if cmdargs.delete_all:
        for i in images.imageinfo_list:
            if RwStatus.SUCCESS != driver.delete_image(account, i.id):
                print('Error: failed to delete image %s' % i.name)
    else:
        for i in images.imageinfo_list:
            if i.name == cmdargs.image_name:
                if RwStatus.SUCCESS != driver.delete_image(account, i.id):
                    print('Error: failed to delete image %s' % i.name)

def image_subcommand(driver, account, cmdargs):
    """Process the image subcommand"""
    if cmdargs.which == 'list':
        rc, images = driver.get_image_list(account)
        assert rc == RwStatus.SUCCESS

        for i in images.imageinfo_list:
            print(i)

    elif cmdargs.which == 'delete':
        image_delete_subcommand(driver, account, cmdargs)

    elif cmdargs.which == 'create':
        account.openstack.key          = 'admin'
        rc, images = driver.get_image_list(account)
        assert rc == RwStatus.SUCCESS
        for i in images.imageinfo_list:
            if i.name == cmdargs.image_name:
                print("FATAL: image \"%s\" already exists" % cmdargs.image_name)
                return 1
        
        print("creating image \"%s\" using %s ..." % \
              (cmdargs.image_name, cmdargs.file_name))
        img = RwcalYang.ImageInfoItem()
        img.name = cmdargs.image_name
        img.location = cmdargs.file_name
        img.disk_format = "qcow2"
        img.container_format = "bare"
        rc, img_id = driver.create_image(account, img)	
        print("... done. image_id is %s" % img_id)
        return img_id

    elif cmdargs.which == 'getid':
        rc, images = driver.get_image_list(account)
        assert rc == RwStatus.SUCCESS
        found=0
        for i in images.imageinfo_list:
            if i.name == cmdargs.image_name:
                print(i.id)
                found += 1
        if found != 1:
            sys.exit(1)
        
def flavor_subcommand(driver, account, cmdargs):
    """Process the flavor subcommand"""
    if cmdargs.which == 'list':
        rc, sizes = driver.get_flavor_list(account)
        assert rc == RwStatus.SUCCESS
        for f in sizes.flavorinfo_list:
            rc, flv = driver.get_flavor(account, f.id)	    
            print(flv)	    
    elif cmdargs.which == 'create':
        account.openstack.key          = 'admin'    
        flavor                                     = RwcalYang.FlavorInfoItem()
        flavor.name                                = cmdargs.flavor_name
        flavor.vm_flavor.memory_mb                 = cmdargs.memory_size
        flavor.vm_flavor.vcpu_count                = cmdargs.vcpu_count
        flavor.vm_flavor.storage_gb                = cmdargs.disc_size
        if cmdargs.hugepages_kilo:
            flavor.guest_epa.mempage_size              = cmdargs.hugepages_kilo
        if cmdargs.numa_nodes:
            flavor.guest_epa.numa_node_policy.node_cnt = cmdargs.numa_nodes
        if cmdargs.dedicated_cpu:
            flavor.guest_epa.cpu_pinning_policy        = 'DEDICATED'
        if cmdargs.pci_count:
            dev = flavor.guest_epa.pcie_device.add()
            dev.device_id = 'PCI_%dG_ALIAS' % (cmdargs.pci_speed)
            dev.count = cmdargs.pci_count 
        if cmdargs.colleto:
            dev = flavor.guest_epa.pcie_device.add()
            dev.device_id = 'COLETO_VF_ALIAS'
            dev.count = cmdargs.colleto 
        if cmdargs.trusted_host:
            flavor.guest_epa.trusted_execution = True 

        rc, flavor_id = driver.create_flavor(account, flavor)
        assert rc == RwStatus.SUCCESS

        print("created flavor %s id %s" % (cmdargs.flavor_name, flavor_id)) 

    elif cmdargs.which == 'delete':
        account.openstack.key          = 'admin'    
        rc, sizes = driver.get_flavor_list(account)
        assert rc == RwStatus.SUCCESS
        for f in sizes.flavorinfo_list:
            if f.name == cmdargs.flavor_name:
                rc = driver.delete_flavor(account, f.id)
                assert rc == RwStatus.SUCCESS

def hostagg_subcommand(driver, account, cmdargs):
    """Process the hostagg subcommand"""
    if cmdargs.which == 'list':
        nova = ra_nova_connect(project='admin')
        for f in nova.aggregates.list():
            print("%-12s %-12s" % \
                  (f.name, f.availability_zone))
                
    elif cmdargs.which == 'create':
        nova = ra_nova_connect(project='admin')
        hostagg = nova.aggregates.create(cmdargs.hostagg_name, 
                                     cmdargs.avail_zone)
        print("created hostagg %s in %s" % (hostagg.name, hostagg.availability_zone)) 

    elif cmdargs.which == 'delete':
        nova = ra_nova_connect(project='admin')
        for f in nova.aggregates.list():
            if f.name == cmdargs.hostagg_name:
                if cmdargs.force_delete_hosts:
                    for h in f.hosts:
                        f.remove_host(h)

                f.delete()

    elif cmdargs.which == 'addhost':
        nova = ra_nova_connect(project='admin')
        for f in nova.aggregates.list():
            if f.name == cmdargs.hostagg_name:
                f.add_host(cmdargs.host_name)

    elif cmdargs.which == 'delhost':
        nova = ra_nova_connect(project='admin')
        for f in nova.aggregates.list():
            if f.name == cmdargs.hostagg_name:
                f.remove_host(cmdargs.host_name)

    elif cmdargs.which == 'setmetadata':
        nova = ra_nova_connect(project='admin')
        for f in nova.aggregates.list():
            if f.name == cmdargs.hostagg_name:
                d = dict([cmdargs.extra_specs.split("="),])		    
                f.set_metadata(d)

def quota_subcommand(driver, account, cmdargs):
    """Process the quota subcommand"""
    nova = ra_nova_connect(project='admin')
    cfgfile = get_openstack_file(None,  cmdargs.project)
    kwargs = load_params(cfgfile)

    keystone = keystone_client.Client(username=kwargs.get('OS_USERNAME'),
                               password=kwargs.get('OS_PASSWORD'),
                               tenant_name=kwargs.get('OS_TENANT_NAME'),
                               auth_url=kwargs.get('OS_AUTH_URL'))
    if cmdargs.which == 'set':
        nova.quotas.update(keystone.tenant_id, 
                           ram=cmdargs.memory, 
                           floating_ips=cmdargs.ips, 
                           instances=cmdargs.vms, 
                           cores=cmdargs.vcpus)
    elif cmdargs.which == 'get':
        print("get quotas for tenant %s %s" % \
              (cmdargs.project, keystone.tenant_id))
        q = nova.quotas.get(keystone.tenant_id)
        for att in [ 'ram', 'floating_ips', 'instances', 'cores' ]: 
            print("%12s: %6d" % ( att, getattr(q, att) ))
        
def rules_subcommand(driver, account, cmdargs):
    nova = ra_nova_connect(project='demo')
    group=nova.security_groups.find(name='default')
    if cmdargs.which == 'set':
        try:
            nova.security_group_rules.create(group.id,ip_protocol='tcp', from_port=1, to_port=65535 )
        except BadRequest:
            pass
        try: 
            nova.security_group_rules.create(group.id, ip_protocol='icmp',from_port=-1, to_port=-1 )
        except BadRequest:
            pass
            
    elif cmdargs.which == 'list':
        for r in group.rules:
            if r['from_port'] == -1:
                print("rule %d proto %s from IP %s" % ( r['id'], r['ip_protocol'], r['ip_range']['cidr'] ))
            else:
                print("rule %d proto %s from port %d to %d from IP %s" % ( r['id'], r['ip_protocol'], r['from_port'], r['to_port'], r['ip_range']['cidr'] ))


def register_subcommand(driver, account, cmdargs):
    cmdargs.reserve_new_vms = False
    vm_register('all', driver, account, cmdargs)       
           
##
# Command line argument specification
##
desc="""This tool is used to manage the VMs"""
kilo=platform.dist()[1]=='21'
parser = argparse.ArgumentParser(description=desc)
subparsers = parser.add_subparsers()
ipaddr = socket.gethostbyname(socket.getfqdn())
reservation_server_url = os.environ.get('RESERVATION_SERVER', 'http://reservation.eng.riftio.com:80')
# ipaddr = netifaces.ifaddresses('br0')[netifaces.AF_INET][0]['addr']
#default_auth_url = 'http://%s:5000/v3/' % ipaddr
default_auth_url = 'http://10.66.4.27:5000/v3/'

parser.add_argument('-t', '--provider-type', dest='provider_type',
                    type=str, default='OPENSTACK', 
                    help='Cloud provider type (default: %(default)s)')
parser.add_argument('-u', '--user-name', dest='user', 
                    type=str, default='demo', 
                    help='User name (default: %(default)s)')
parser.add_argument('-p', '--password', dest='passwd', 
                    type=str, default='mypasswd', 
                    help='Password (default: %(default)s)')
parser.add_argument('-m', '--mgmt-nw', dest='mgmt_network', 
                    type=str, default='private', 
                    help='mgmt-network (default: %(default)s)')
parser.add_argument('-a', '--auth-url', dest='auth_url', 
                    type=str, default=default_auth_url, 
                    help='Password (default: %(default)s)')
parser.add_argument('-r', '--reservation_server_url', dest='reservation_server_url', 
                    type=str, default=reservation_server_url, 
                    help='reservation server url, use None to disable (default %(default)s)' )
parser.add_argument('-d', '--debug', dest='debug', action='store_true', help='raise the logging level')

##
# Subparser for VM
##
vm_parser = subparsers.add_parser('vm')
vm_subparsers = vm_parser.add_subparsers()

# Create VM subparser
vm_create_parser = vm_subparsers.add_parser('create')
vm_create_parser.add_argument('-c', '--count',
                              type=int, default=1,
                              help='The number of VMs to launch '
                                   '(default: %(default)d)')
vm_create_parser.add_argument('-i', '--image', 
							  default='rwopenstack_vm',
                              help='Specify the image for the VM  (default: %(default)s)')
vm_create_parser.add_argument('-n', '--name',
                              help='Specify the name of the VM')
vm_create_parser.add_argument('-f', '--flavor',
                              help='Specify the flavor for the VM')
vm_create_parser.add_argument('-R', '--reserve', dest='reserve_new_vms', 
                    action='store_true', help='reserve any newly created VMs')
vm_create_parser.add_argument('-s', '--single', dest='wait_after_create', 
                    action='store_true', help='wait for each VM to start before creating the next')
vm_create_parser.add_argument('-N', '--networks', dest='networks', type=str, 
                                default='private,private2,private3,private4',
                                help='comma separated list of networks to connect these VMs to (default: %(default)s)' )

vm_create_parser.set_defaults(which='create')
# Reboot VM subparser
vm_reboot_parser = vm_subparsers.add_parser('reboot')
group = vm_reboot_parser.add_mutually_exclusive_group()
group.add_argument('-n', '--vm-name', dest='vm_name',
                   type=str,
                   help='Specify the name of the VM')
group.add_argument('-a', '--reboot-all', 
                   dest='reboot_all', action='store_true',
                   help='Reboot all VMs')
vm_reboot_parser.add_argument('-s', '--sleep', dest='sleep_time', type=int, default=4, help='time in seconds to sleep between reboots')
vm_reboot_parser.set_defaults(which='reboot')


"""
# start VM subparser
vm_start_parser = vm_subparsers.add_parser('start')
group = vm_start_parser.add_mutually_exclusive_group()
group.add_argument('-n', '--vm-name', dest='vm_name',
                   type=str,
                   help='Specify the name of the VM')
group.add_argument('-a', '--start-all', 
                   dest='start_all', action='store_true',
                   help='Start all VMs')
vm_start_parser.set_defaults(which='start')
"""

# Destroy VM subparser
vm_destroy_parser = vm_subparsers.add_parser('destroy')
group = vm_destroy_parser.add_mutually_exclusive_group()
group.add_argument('-n', '--vm-name', dest='vm_name',
                   type=str,
                   help='Specify the name of the VM (accepts regular expressions)')
group.add_argument('-a', '--destroy-all', 
                   dest='destroy_all', action='store_true',
                   help='Delete all VMs')
group.add_argument('-w', '--wait', 
                   dest='wait', action='store_true',
                   help='destroy all and wait until all VMs have exited')
vm_destroy_parser.set_defaults(which='destroy')

# Rebuild VM subparser
vm_rebuild_parser = vm_subparsers.add_parser('rebuild')
group = vm_rebuild_parser.add_mutually_exclusive_group()
group.add_argument('-n', '--vm-name', dest='vm_name',
                   type=str,
                   help='Specify the name of the VM (accepts regular expressions)')
group.add_argument('-a', '--rebuild-all', 
                   dest='rebuild_all', action='store_true',
                   help='Rebuild all VMs')
vm_rebuild_parser.add_argument('-i', '--image-name', dest='image_name',
                              type=str,
                              help='Specify the name of the image')
vm_rebuild_parser.set_defaults(which='rebuild')

# List VM subparser
vm_list_parser = vm_subparsers.add_parser('list')
vm_list_parser.set_defaults(which='list')
vm_list_parser.add_argument('-i', '--ips_only', dest='ipsonly', 
                            action='store_true', 
                            help='only list IP addresses')

vm_parser.set_defaults(func=vm_subcommand)

##
# Subparser for image
##
image_parser = subparsers.add_parser('image')
image_subparsers = image_parser.add_subparsers()

# List image subparser
image_list_parser = image_subparsers.add_parser('list')
image_list_parser.set_defaults(which='list')

# Delete image subparser
image_destroy_parser = image_subparsers.add_parser('delete')
group = image_destroy_parser.add_mutually_exclusive_group()
group.add_argument('-n', '--image-name', dest='image_name',
                   type=str,
                   help='Specify the name of the image')
group.add_argument('-a', '--delete-all', 
                   dest='delete_all', action='store_true',
                   help='Delete all images')
image_destroy_parser.set_defaults(which='delete')

# create image
image_create_parser = image_subparsers.add_parser('create')
image_create_parser.set_defaults(which='create')
image_create_parser.add_argument('-n', '--image-name', dest='image_name',
                                  type=str,
                                  default="rwopenstack_vm",
                                  help='Specify the name of the image')
image_create_parser.add_argument('-f', '--filename', dest='file_name',
                                  type=str, 
                                  default='/net/sharedfiles/home1/common/vm/rift-root-current.qcow2',
                                  help='name of the existing qcow2 image file')


image_create_parser = image_subparsers.add_parser('getid')
image_create_parser.set_defaults(which='getid')
image_create_parser.add_argument('-n', '--image-name', dest='image_name',
                                  type=str,
                                  default="rwopenstack_vm",
                                  help='Specify the name of the image')
image_parser.set_defaults(func=image_subcommand)

##
# Subparser for flavor
##
flavor_parser = subparsers.add_parser('flavor')
flavor_subparsers = flavor_parser.add_subparsers()

# List flavor subparser
flavor_list_parser = flavor_subparsers.add_parser('list')
flavor_list_parser.set_defaults(which='list')

# Create flavor subparser
flavor_create_parser = flavor_subparsers.add_parser('create')
flavor_create_parser.set_defaults(which='create')
flavor_create_parser.add_argument('-n', '--flavor-name', dest='flavor_name',
                                  type=str,
                                  help='Specify the name of the flavor')
flavor_create_parser.add_argument('-m', '--memory-size', dest='memory_size',
                                  type=int, default=1024,
                                  help='Specify the size of the memory in MB '
                                       '(default: %(default)d)')
flavor_create_parser.add_argument('-d', '--disc-size', dest='disc_size',
                                  type=int, default=16,
                                  help='Specify the size of the disc in GB '
                                       '(default: %(default)d)')
flavor_create_parser.add_argument('-v', '--vcpu-count', dest='vcpu_count',
                                  type=int, default=1,
                                  help='Specify the number of VCPUs '
                                       '(default: %(default)d)')
flavor_create_parser.add_argument('-p', '--pci-count', dest='pci_count',
                                  type=int, default=0,
                                  help='Specify the number of PCI devices '
                                       '(default: %(default)d)')
flavor_create_parser.add_argument('-s', '--pci-speed', dest='pci_speed',
                                  type=int, default=10,
                                  help='Specify the speed of the PCI devices in Gbps (default: %(default)d)')
flavor_create_parser.add_argument('-e', '--hostagg-extra-specs', dest='extra_specs',
                                  type=str, 
                                  help='Specify the extra spec ')
flavor_create_parser.add_argument('-b', '--back-with-hugepages', dest='enable_hugepages',
                                  action='store_true',
                                  help='Enable memory backing with hugepages')
flavor_create_parser.add_argument('-B', '--back-with-hugepages-kilo', dest='hugepages_kilo',
                                  type=str,
                                  help='Enable memory backing with hugepages for kilo')
flavor_create_parser.add_argument('-D', '--dedicated_cpu', dest='dedicated_cpu',
                                  action='store_true',
                                  help='Dedicated CPU usage')
flavor_create_parser.add_argument('-T', '--cpu_threads', dest='cpu_threads',
                                  type=str, 
                                  help='CPU threads usage')
flavor_create_parser.add_argument('-N', '--numa_nodes', dest='numa_nodes',
                                  type=int, 
                                  help='Configure numa nodes')
flavor_create_parser.add_argument('-t', '--trusted-host', dest='trusted_host',  action='store_true', help='restrict instances to trusted hosts')
flavor_create_parser.add_argument('-c', '--crypto-cards', dest='colleto',  type=int, default=0,  \
                                    help='how many colleto creek VFs should be passed thru to the VM')

# Delete flavor subparser
flavor_delete_parser = flavor_subparsers.add_parser('delete')
flavor_delete_parser.set_defaults(which='delete')
flavor_delete_parser.add_argument('-n', '--flavor-name', dest='flavor_name',
                                  type=str,
                                  help='Specify the name of the flavor')

flavor_parser.set_defaults(func=flavor_subcommand)

##
# Subparser for host-aggregate 
##
hostagg_parser = subparsers.add_parser('hostagg')
hostagg_subparsers = hostagg_parser.add_subparsers()

# List host-aggregate subparser
hostagg_list_parser = hostagg_subparsers.add_parser('list')
hostagg_list_parser.set_defaults(which='list')

# Create hostagg subparser
hostagg_create_parser = hostagg_subparsers.add_parser('create')
hostagg_create_parser.set_defaults(which='create')
hostagg_create_parser.add_argument('-n', '--hostagg-name', dest='hostagg_name',
                                  type=str,
                                  help='Specify the name of the hostagg')
hostagg_create_parser.add_argument('-a', '--avail-zone', dest='avail_zone',
                                  type=str,
                                  help='Specify the name of the availability zone')
# Delete hostagg subparser
hostagg_delete_parser = hostagg_subparsers.add_parser('delete')
hostagg_delete_parser.set_defaults(which='delete')
hostagg_delete_parser.add_argument('-n', '--hostagg-name', dest='hostagg_name',
                                  type=str,
                                  help='Specify the name of the hostagg')
hostagg_delete_parser.add_argument('-f', '--force-delete-hosts', dest='force_delete_hosts',
                                  action='store_true',
                                  help='Delete the existing hosts')

# Add host subparser
hostagg_addhost_parser = hostagg_subparsers.add_parser('addhost')
hostagg_addhost_parser.set_defaults(which='addhost')
hostagg_addhost_parser.add_argument('-n', '--hostagg-name', dest='hostagg_name',
                                  type=str,
                                  help='Specify the name of the hostagg')
hostagg_addhost_parser.add_argument('-c', '--compute-host-name', dest='host_name',
                                  type=str,
                                  help='Specify the name of the host to be added')

# Remove host subparser
hostagg_delhost_parser = hostagg_subparsers.add_parser('delhost')
hostagg_delhost_parser.set_defaults(which='delhost')
hostagg_delhost_parser.add_argument('-n', '--hostagg-name', dest='hostagg_name',
                                  type=str,
                                  help='Specify the name of the hostagg')
hostagg_delhost_parser.add_argument('-c', '--compute-host-name', dest='host_name',
                                  type=str,
                                  help='Specify the name of the host to be removed')

# Set meta-data subparser
hostagg_setdata_parser = hostagg_subparsers.add_parser('setmetadata')
hostagg_setdata_parser.set_defaults(which='setmetadata')
hostagg_setdata_parser.add_argument('-n', '--hostagg-name', dest='hostagg_name',
                                  type=str,
                                  help='Specify the name of the hostagg')
hostagg_setdata_parser.add_argument('-d', '--meta-data', dest='extra_specs',
                                  type=str,
                                  help='Specify the meta-data to be associated to this host aggregate')

hostagg_parser.set_defaults(func=hostagg_subcommand)

##
# Subparser for quota
##
quota_parser = subparsers.add_parser('quota')
quota_subparser = quota_parser.add_subparsers()
quota_set_parser = quota_subparser.add_parser('set')

# quota set subparser
quota_set_parser.set_defaults(which='set')
quota_set_parser.add_argument('-p', '--project', dest='project', 
                              type=str, default='demo', 
                              help='project name that you wish to set '
                                   'the quotas for')
quota_set_parser.add_argument('-c', '--vcpus', dest='vcpus', 
                              type=int, default=48, 
                              help='Maximum number of virtual CPUs that can '
                                   'be assigned to all VMs in aggregate')
quota_set_parser.add_argument('-v', '--vms', dest='vms', 
                              type=int, default=24, 
                              help='Maximum number of VMs that can be created ' 
                                   'on this openstack instance '
                                   '(which may be more than 1 machine)')
quota_set_parser.add_argument('-i', '--ips', dest='ips', 
                              type=int, default=250, 
                              help='Maximum number of Floating IP Addresses '
                                   'that can be assigned to all VMs '
                                   'in aggregate')
quota_set_parser.add_argument('-m', '--memory', dest='memory', 
                              type=int, default=122880, 
                              help='Maximum amount of RAM in MB that can be '
                                   'assigned to all VMs in aggregate')

# quota get subparser
quota_get_parser = quota_subparser.add_parser('get')
quota_get_parser.add_argument('-p', '--project', dest='project', 
                              type=str, default='demo', 
                              help='project name that you wish to get '
                                   'the quotas for')
quota_get_parser.set_defaults(which='get')
quota_parser.set_defaults(func=quota_subcommand)

##
# rules subparser
##
rules_parser = subparsers.add_parser('rules')
rules_parser.set_defaults(func=rules_subcommand)
rules_subparser = rules_parser.add_subparsers()
rules_set_parser = rules_subparser.add_parser('set')
rules_set_parser.set_defaults(which='set')
rules_list_parser = rules_subparser.add_parser('list')
rules_list_parser.set_defaults(which='list')

register_parser = subparsers.add_parser('register')
register_parser.set_defaults(func=register_subcommand)
 
cmdargs = parser.parse_args()


if __name__ == "__main__":
    logger=logging.getLogger(__name__)
    if cmdargs.debug:
        logging.basicConfig(format='%(asctime)-15s %(levelname)s %(message)s', level=logging.DEBUG) 
    else:
        logging.basicConfig(format='%(asctime)-15s %(levelname)s %(message)s', level=logging.WARNING) 

    if cmdargs.provider_type == 'OPENSTACK':
        #cls = get_driver(Provider.OPENSTACK)
        pass
    elif cmdargs.provider_type == 'VSPHERE':
        cls = get_driver(Provider.VSPHERE)
    else:
        sys.exit("Cloud provider %s is NOT supported yet" % cmdargs.provider_type)

    if cmdargs.reservation_server_url == "None" or cmdargs.reservation_server_url == "":
        cmdargs.reservation_server_url = None
    if cmdargs.reservation_server_url is not None:
        sys.path.append('/usr/rift/lib')
        try:
            import ndl
        except Exception as e:
            logger.warning("Error loading Reservation library")
            testbed=None
        else:
            testbed=ndl.Testbed()
            testbed.set_server(cmdargs.reservation_server_url)
            


    if cmdargs.provider_type == 'OPENSTACK':
        account                        = RwcalYang.CloudAccount()
        account.account_type           = "openstack"
        account.openstack.key          = cmdargs.user
        account.openstack.secret       = cmdargs.passwd
        account.openstack.auth_url     = cmdargs.auth_url
        account.openstack.tenant       = cmdargs.user
        account.openstack.mgmt_network = cmdargs.mgmt_network

        plugin = rw_peas.PeasPlugin('rwcal_openstack', 'RwCal-1.0')
        engine, info, extension = plugin()
        driver = plugin.get_interface("Cloud")
        # Get the RwLogger context
        rwloggerctx = rwlogger.RwLog.Ctx.new("Cal-Log")
        try:
            rc = driver.init(rwloggerctx)
            assert rc == RwStatus.SUCCESS
        except:
            logger.error("ERROR:Cal plugin instantiation failed. Aborting tests")
        else:
            logger.info("Openstack Cal plugin successfully instantiated")

        cmdargs.func(driver, account, cmdargs)

    elif cmdargs.provider_type == 'VSPHERE':
        driver = cls(cmdargs.user, cmdargs.passwd, host='vcenter' )
        cmdargs.func(driver, cmdargs)
