#!/usr/bin/env python
#
#   ConVirt   -  Copyright (c) 2008 Convirture Corp.
#   ======
#
# ConVirt is a Virtualization management tool with a graphical user
# interface that allows for performing the standard set of VM operations
# (start, stop, pause, kill, shutdown, reboot, snapshot, etc...). It
# also attempts to simplify various aspects of VM lifecycle management.
#
#
# This software is subject to the GNU General Public License, Version 2 (GPLv2)
# and for details, please consult it at:
#
#    http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
#
#
#
# Description : Command line interface of Convirt Desktop Application
#               All cammands are mapped to functions using a dictionary

#===================================================================
# Modifications histroy
#===================================================================



import getopt, sys,getpass
sys.path.append('.')
from convirt.core.model.storage import StorageManager
import datetime
import traceback
from convirt.core.utils import constants
from convirt.core.model.ManagedNode import *
from convirt.core.utils.utils import *
from convirt.core.utils import *
from convirt.core.utils.NodeProxy import Node

from convirt.core.model.ImageStore import ImageStore
from convirt.core.model.PlatformRegistry import PlatformRegistry
from convirt.core.model.GridManager import GridManager
from convirt.core.model.ManagedNode import ManagedNode
from convirt.core.model.Groups import ServerGroup
from convirt.cli.messages import *


# Copy old print deals
old_printerators=[sys.stdout,sys.stderr,sys.stdin,sys.__stdout__,sys.__stderr__,sys.__stdin__][:]
# redirect all print deals
sys.stdout,sys.stderr,sys.stdin,sys.__stdout__,sys.__stderr__,sys.__stdin__=dummyStream(),dummyStream(),dummyStream(),dummyStream(),dummyStream(),dummyStream()

# Initialisation
local_node = ManagedNode(hostname = constants.LOCALHOST, isRemote = False, helper = None)
client_config = local_node.config
store = client_config
registry = PlatformRegistry(client_config, store, {})

image_store = ImageStore(local_node.config, registry)
manager = GridManager(store, client_config, registry, None)
storage_manager=StorageManager(store)


# Mapping of cli command - function,arg_required,vmstate
cmddict = {
            "add_server":["addNode", 4, "group_operation"],
            "add_server_pool":["addGroup", 1, "data_center"],
            "delete_vm":["cleanupQCDomain",3,"vm_operation","[VM_NOT_RUNNING_STATE]"],
            "kill":["_destroy",3,"vm_operation","[VM_RUNNING_STATE,VM_BLOCKED_STATE,VM_PAUSED_STATE]"],
            "edit_server":["addNode", 1, "server_operation"],
             "kill_all_vms":["_destroy",2,"server_operation"],
            "list_images":["get_images",0,"image_operation"],
            "list_servers":["getNodeList",1,"group_operation"],
            "list_server_pools":["getGroupNames",0,"group_operation"],
            "list_vms":["get_dom_names",2,"server_operation"],
            "migrate_vm":["migrateDomain",5,"vm_operation","[VM_RUNNING_STATE,VM_BLOCKED_STATE]"],
             "migrate_all":["migrateNode",4,"server_operation"],
            "os_info":["get_os_info",2,"server_operation"],
            "pause":["_pause",3,"vm_operation","[VM_RUNNING_STATE,VM_BLOCKED_STATE]"],
            "provision_vm":["",3,"server_operation"],
            "reboot":["_reboot",3,"vm_operation","[VM_RUNNING_STATE,VM_PAUSED_STATE,VM_BLOCKED_STATE]"],
            "remove_server":["removeNode",2,"server_operation"],
            "remove_server_pool":["removeGroup",1,"group_operation"],
            "resume":["_unpause",3,"vm_operation","[VM_PAUSED_STATE]"],
            "set_boot_device":["",4,"vm_operation","[VM_RUNNING_STATE,VM_PAUSED_STATE,VM_BLOCKED_STATE]"],
            "start":["_start",3,"vm_operation","[VM_NOT_RUNNING_STATE]"],
            "start_all_vms":["_start",2,"server_operation"],
            "shutdown":["_shutdown",3,"vm_operation","[VM_RUNNING_STATE,VM_PAUSED_STATE,VM_BLOCKED_STATE]"],
            "shutdown_all_vms":["_shutdown",2,"server_operation"],
            "restore":["restore_dom",3,"server_operation"],
            "snapshot":["",3,"vm_operation","[ VM_RUNNING_STATE, VM_PAUSED_STATE,VM_BLOCKED_STATE ]"],
          }

# Mapping of help utilty for cli
cmdhelpdict = {
                "add_server":["add_server <server pool> <server> <username> <platform> -p <sshport> -k <use keys>[y/n] ] "],
                "add_server_pool":["add_server_pool <serverpoolname> "],
                "delete_vm":["delete_vm  <server pool>  <server>  <vmname> "],
                "edit_server":["edit_server <server pool> <server> -u <username> -p <password> -s <sshport> -k <usekeys>[y/n]"],
                "kill":["kill <server pool>  <server>  <vmname> | --vm <vmname> <username> <password>"],
               "kill_all_vms":["kill_all_vms <server pool>  <server>"],
                "list_images":["list_images"],
               "list_servers":["list_servers <server pool>"],
               "list_server_pools":["list_server_pools"],
               "list_vms":["list_vms <server pool>  <server> -u <username> -p <password> [ --l ]"],
               "migrate_vm":["migrate_vm <src pool> <src server> <src vm> <dest pool> <dest server> "],
               "migrate_all":["migrate_all <src pool> <src server> <dest pool> <dest server> "],
               "os_info":["os_info <server pool>  <server> "],
               "pause":["pause <server pool>  <server>  <vmname> | --vm <vmname> <username> <password>"],
               "provision_vm":["provision_vm  <server pool> <vmname>  <image> -s <server> -m <memory> -c <cpu>"],
               "reboot":["reboot <server pool>  <server>  <vmname>| --vm <vmname> <username> <password>"],
               "remove_server":["remove_server <server pool>  <server>"],
               "remove_server_pool":["remove_server_pool <serverpoolname>"],
               "resume":["resume <server pool>  <server>  <vmname> | --vm <vmname> <username> <password>"],
               "set_boot_device":["set_boot_device <server pool> <server> <vmname> cd-rom/disk"],
               "start":["start <server pool>  <server>  <vmname>  | --vm <vmname> <username> <password>"],
               "start_all_vms":["start_all_vms <server pool>  <server>"],
               "shutdown":["shutdown <server pool>  <server>  <vmname> | --vm <vmname> <username> <password>"],
               "shutdown_all_vms":["shutdown_all_vms <server pool>  <server>"],
               "restore":["restore <server pool>  <server> <snapshotfile> -p <path>"],
               "snapshot":["snapshot <server pool>  <server> <vname> -f <filename> -p <path> "],
           }


# Displays the help menu
def usage():
    usage = """
Usage: convirt-cli [<operation> | help ] --noheader

    help                                                     Prints this
    --noheader                                               For no cli header

    server pool operations:
        list_server_pools                                    Lists all server pool names
        add_server_pool <serverpoolname>                     Adds a server pool
        remove_server_pool <serverpoolname>                  Removes a server pool

    server operations:
        add_server <server pool> <server> <username>
             <platform> -p <sshport> -k <usekeys>[y/n]       Adds a server
        edit_server <server pool> <server> -u <username>
        -p <password> -s <sshport> -k <usekeys>[y/n]         Edits server details
        kill_all_vms <server pool>  <server>                 Kill all vms
        list_servers  <server pool>                          Lists all hosts
        list_vms <server pool>  <server>  |
         -u <username> -p <password> [ --l ]                 Shows all vms
        migrate_all <src pool> <src server>
                    <dest pool> <dest server>                Migrates all vms
        os_info  <server pool>  <server>                     managed server info
        provision_vm  <server pool> <vmname>  <image>
                -s <server> -m <memory> -c <cpu>             Creates a vm
        remove_server <server pool>  <server>                Removes a server
        start_all_vms   <server pool>  <server>              Start all vms
        shutdown_all_vms  <server pool>  <server>            Shutdown all vms
        restore  <server pool> <server> <snapshotfile>
                            -p <path>                        Restores a vm

    vm operations:
        delete_vm <server pool>  <server>  <vmname>          Deletes a vm
        kill <server pool>  <server>  <vmname>               Kills a vm
        migrate_vm <src pool> <src server> <src vm>
                          <dest pool> <dest server>          Migrates a vm
        pause  <server pool>  <server>  <vmname>             Pauses a vm
        reboot  <server pool>  <server>  <vmname>            Reboots a  vm
        resume  <server pool>  <server>  <vmname>            Resumes a paused vm
        set_boot_device <server pool> <server>
                    <vmname> cd-rom/disk                     Sets boot device for vm
        start   <server pool>  <server>  <vmname>            Starts a vm
        shutdown  <server pool>  <server>  <vmname>          Shuts a vm down
        snapshot  <server pool>  <server> <vmname>
                -f <filename> -p <path>                      Takes Snapshot

         Note : The server pool and server names can be omitted and the 
                following shortcut can be used to specify a vm.  ConVirt 
                will search for the VM and perform the action.

        --vm <vmname> <username> <password>            

        For example, 
          pause --vm <vmname> <username> <password>           Pause a vm
          reboot --vm <vmname> <username> <password>          Reboots a vm
          resume --vm <vmname> <username> <password>          Resumes a vm
          start --vm <vmname> <username> <password>           Starts a vm
          shutdown --vm <vmname> <username> <password>        Shuts a vm down

    image operations:
        list_images                                           Lists all images
    """
    print_helper(usage)


# Process all commands
def proc_cmd(cmd,args):
    cmdarglist = cmddict[cmd]
    numargs=cmdarglist[1]
    type=cmdarglist[2]

    if len(args) == numargs:
        if type=="data_center":
            data_center_operation(cmd,args[0])
        elif type=="group_operation":
            group_operation(cmd, args)
        elif  type == "server_operation":
            server_operation(cmd,args)
        elif type =="vm_operation":
            vm_operation(cmd,args)
        elif type =="image_operation":
            img_operation(cmd)
    elif len(args) > numargs:
        exception_operations(cmd,args)
    else:
        command_usage(cmd)


#
# Do data center operations
#
def data_center_operation(cmd,serverpoolname):
    cmdarglist = cmddict[cmd]
    func_cmd=cmdarglist[0]
    if cmd=="add_server_pool":
        add_serverpool(serverpoolname,func_cmd)


# Adds a serverpool
def add_serverpool(server_pool_name,func_cmd):
    grp_names=manager.getGroupNames()
    if server_pool_name not in grp_names:
        group = ServerGroup(server_pool_name)
        eval('manager.'+func_cmd+'(group)')
        print_helper(server_pool_name," : "+SERVER_POOL_ADDED)
    else:
        print_helper(server_pool_name," : "+SERVERPOOL_NAME_EXIST)



#
# Do group operations
#
def group_operation(cmd,args):
    cmdarglist = cmddict[cmd]
    func_cmd=cmdarglist[0]
    if cmd=="list_server_pools":
         list_groups(func_cmd)
    elif cmd == "add_server":
         add_server(args,func_cmd)
    elif cmd=="remove_server_pool":
        remove_serverpool(args[0],func_cmd)
    elif cmd =="list_servers":
         list_host_oper(args[0],func_cmd)



# Adds a server to a serverpool
def add_server(args,func_cmd):

    use_keys="n"
    ssh_port=22
    password=None
    usekeys=False
    try:
        (options, params) = getopt.gnu_getopt(args, "p:k:")
        for (k, v) in options:
           if k in ["-p"]:
               ssh_port=int(v)
           elif k in ["-k"]:
               use_keys=v
    except Exception,e:
        raise e
    grp_names=manager.getGroupNames()
    if args[0] not in grp_names:
        print_helper(args[0]," : "+NO_SERVERPOOL_NAME)
        return 0

    server_list=list(manager.getNodeList(args[0]))
    if args[1] in server_list:
        print_helper(args[1]," : "+SERVER_NAME_EXIST)
        return 0

    use_keys=use_keys.lower()
    isRemote = is_host_remote(args[1])
    if use_keys in ("n"):
        password = getpass.getpass("Enter password: ")
        usekeys = False
    elif use_keys in ("y"):
        password=None
        usekeys = True

    address =None
    if address is None:
        address = args[1]

    platform=args[3].lower()

    try:
        factory = manager.getFactory(platform)
    except Exception, (e):
       print_helper(SERVER_ERR," : No factory for %s platform." % platform)
       return

    try:
        node = factory.create_node(platform=platform,
            hostname=args[1],
            username=args[2],
            password=password,
            is_remote=isRemote,
            ssh_port=int(ssh_port),
            use_keys=usekeys,
            address=address)
        node.connect()
        eval('manager.'+func_cmd+'(node, args[0])')
        print_helper(args[1]," : "+SERVER_ADDED)
    except Exception, (strerror):
        print_helper(SERVER_ERR," : "+ str(strerror))


# Removes a serverpool
def remove_serverpool(server_pool_name,func_cmd):
    grp_names=manager.getGroupNames()
    if server_pool_name in grp_names:
        eval('manager.'+func_cmd+'(server_pool_name)')
        print_helper(server_pool_name," : "+SERVER_POOL_REMOVED)
    else:
        print_helper(server_pool_name," : "+NO_SERVERPOOL_NAME)



# Lists groups
def list_groups(func_cmd):
    grp_names=eval('manager.'+func_cmd+'()')
    format_output("Group Names",grp_names)

# Lists hosts or groups
def list_host_oper(arg,func_cmd):
   grp_names=manager.getGroupNames()
   if arg in grp_names:
       server_list=eval('manager.'+func_cmd+'(arg)')
       if len(server_list) >0:
            format_output("Hosts",list(server_list))
       else:
           print_helper(NO_SERVER_FOUND)
   else:
        print_helper(arg," : "+NO_SERVERPOOL_NAME)

#
# All server level operations are handled
#
def server_operation(cmd,args):
    cmdarglist = cmddict[cmd]
    func_cmd=cmdarglist[0]

    serverobj=None
    if cmd=="provision_vm":
        do_provisioning(args)
    elif cmd=="remove_server":
        remove_server(args[0], args[1],func_cmd)
    elif cmd=="list_vms":
        list_all_vms(cmd,func_cmd,args)
    else:
        serverobj=server_obj(args[0], args[1])
        if type(serverobj) is int:
            return 0

    if cmd=="restore":
        do_restore(args,func_cmd,serverobj)
    elif cmd=="migrate_all":
        do_all_migration(serverobj,args[2],args[3],func_cmd)
    elif cmd=="os_info":
        show_os_info(serverobj,func_cmd)
    elif cmd in ["start_all_vms","shutdown_all_vms","kill_all_vms"]:
        vm_all_oper(cmd,serverobj,func_cmd)


# Removes a server
def remove_server(group,server,func_cmd):
    try:
        grp_names=manager.getGroupNames()
        if group in grp_names:
            host_list=list(manager.getNodeList(group))
            if server in host_list:
                eval('manager.'+func_cmd+'(server, group)')
                print_helper(server," : "+SERVER_REMOVED)
            else:
                 print_helper(server," : "+NO_SERVER_NAME)
        else:
            print_helper(group," : "+NO_SERVERPOOL_NAME)
    except Exception,(e):
         raise e

# Lists all vms in a node
def list_vm_det(serverobj,func_cmd,grpname,hostname):

        try:
            vm_names=eval('serverobj.'+func_cmd+'()')
            result=serverobj.get_metric_snapshot()
            list_vmdet=[]
            list_vmdet.append(print_line)
            list_vmdet.append("NAME                  STATE                 CPU(%)                MEM(%)                NETWORK               I/O")
            list_vmdet.append(print_line)
            for key in result.keys():
                   vm_data=result[key]
                   if type(vm_data)==type({}):
                        vm_content=""
                        value,network,io=add_stat(serverobj,key,vm_data)
                        vm_content=value+"%-15s       "%(network)+"%-15s       "%(io)
                        list_vmdet.append(vm_content)
            for vm in  vm_names:
                 if serverobj.get_state(vm)==VM_NOT_RUNNING_STATE:
                         vm_content="%-15s %15s %13s %21s %25s %23s"%(vm,"Not Running","0","0","0/0/0","0/0/0/0")
                         list_vmdet.append(vm_content)

            list_vmdet.append(print_line)
            vm_title=" [ GroupName: "+grpname+" ] [ Server: "+hostname+" ] "
            if len(list_vmdet)>4:
                format_output(vm_title,list_vmdet)
        except Exception,e:
            raise e

def add_stat(serverobj,key,vm_data):
     value=""
     network=""
     io=""
     for inkey in vm_data.keys():
         try:
               if inkey=="NAME" or inkey=="CPU(%)" or inkey=="MEM(%)"  :
                    value+="%-15s       "%(str(vm_data[inkey]))
               elif inkey=="STATE":
                   value+="%-15s       "%(vm_obj(serverobj,key).get_state_string())

               elif inkey=="NETRX(k)" :
                    network+=str(vm_data[inkey])+"/"
               elif  inkey=="NETTX(k)":
                    network+=str(vm_data[inkey])+"/"
               elif  inkey=="NETS":
                    network+=str(vm_data[inkey])

               elif inkey=="VBDS":
                    io+=str(vm_data[inkey])+"/"
               elif inkey=="VBD_OO":
                    io+=str(vm_data[inkey])+"/"
               elif inkey=="VBD_RD":
                    io+=str(vm_data[inkey])+"/"
               elif inkey=="VBD_WR":
                    io+=str(vm_data[inkey])
         except Exception,(e):
            raise e
     return  value,network,io

# lists all vmname and servers
list_vmname=[]
def list_vm_name(serverobj,func_cmd,hostname):
        try:
            vm_content=""
            vm_names=eval('serverobj.'+func_cmd+'()')
            result=serverobj.get_metric_snapshot()
            for key in result.keys():
                   vm_data=result[key]
                   if type(vm_data)==type({}):
                            for inkey in vm_data.keys():
                               if inkey=="NAME":
                                    name="%-15s "%(str(vm_data[inkey]))
                               elif inkey=="STATE":
                                    state="%-15s "%(vm_obj(serverobj,key).get_state_string())
                            vm_content=name+"%-15s %-15s"%(state,hostname)
                            vm_ob= vm_obj(serverobj,str(vm_data["NAME"]))
                            if not vm_ob.isDom0():
                                list_vmname.append(vm_content)
            for vm in  vm_names:
                 if serverobj.get_state(vm)==VM_NOT_RUNNING_STATE:
                          vm_content="%-15s %-16s %-15s"%(vm,"Not Running",hostname)
                          list_vmname.append(vm_content)
        except Exception,(e):
            raise e

# Migrate all vms under a node
def do_all_migration(source_node,d_group,d_server,func_cmd):
    dest_node=server_obj(d_group,d_server)
    vm_obj_list=[]
    vm_name_dic={}

    vms=source_node.get_dom_names()
    for vm in vms:
        vm_obj_list.append(vm_obj(source_node,vm))

    for vm in vms:
        vm_name_dic[vm]=vm_obj(source_node,vm)


    if source_node.hostname == dest_node.hostname:
         print_helper(MIGRATION_ERROR)
         return 0
    try:
        error_list,warning_list=source_node.migration_checks(vm_obj_list, dest_node, True)
        if len(error_list)>0 or len(warning_list)>0 :
             if len(error_list)>0:
                format_output("Error", error_list)
             if len(warning_list)>0:
                format_output("Warning", error_list)

             value=raw_input("y to continue and n to quit:")
             if value=="y":
                 eval('manager.'+func_cmd+'(source_node, dest_node, True,force=True)')
             elif value=="n":
                 print_helper(MIGRATION_QUIT)
                 return 0
        else:
           eval('manager.'+func_cmd+'(source_node, dest_node, True,True)')

        cmd="kill"
        func_cmd=cmddict[cmd][0]

        for key in vm_name_dic.keys():
            if vm_name_dic[key].get_state() in eval(cmddict[cmd][3]):
                try:
                    eval('vm_name_dic[key].'+func_cmd+'()')
                except Exception , (strerror):
                    pass
        print_helper(VMS_MIGRATED)
    except Exception(e):
        raise e


# Restores a vm
def do_restore(args,func_cmd,serverobj):
    if serverobj is None:
        restore_node=server_obj(args[0], args[1])
    else:
        restore_node=serverobj
    if type(restore_node) is int:
        return 0

    path=None
    file=args[2]
    try:
        (options, params) = getopt.gnu_getopt(args, "p:")
        for (k, v) in options:
           if k in ["-p"]:
               path=v
    except Exception , e:
        raise e

    if path is None:
        path=SNAPSHOT_FILE_LOCATION

    location=path+file
    try:
         eval('restore_node.'+func_cmd+'(location)')
         print_helper(VM_RESTORED)
    except Exception,(e):
        raise e


# Creates a vm in a specified node
def do_provisioning(args):

    memory=None
    cpu=None
    server_host=None
    managed_node=None
    try:
        (options, params) = getopt.gnu_getopt(args, "s:m:c:")
        for (k, v) in options:
           if k in ["-m"]:
               memory=int(v)
           elif k in ["-c"]:
               cpu=int(v)
           elif k in ["-s"]:
               server_host=v
    except Exception , e:
        raise e

    if server_host is None:
        grpobj = manager.getGroup(args[0])
        server_list=list(manager.getNodeList(args[0]))
        for server in server_list:
            server_obj(args[0], server).connect()
        target_node = grpobj.getAllocationCandidate(None)
        if target_node is not None:
            managed_node=target_node
        else:
            print_helper(NO_SERVER_FOUND)
    else:
        managed_node=server_obj(args[0], server_host)

    if type(managed_node) is int:
        return 0
    if not vm_not_exist(managed_node,args[1]):
        print_helper(args[1]," : "+VM_NAME_EXIST)
        return 0

    images=image_store.get_images()
    image=None
    for id in images.keys():
        img=images[id]
        if args[2]==img.name:
            image=img
            break
    if managed_node.is_image_compatible(image):
        eGroup = manager.getGroup(args[0])
        try:
            provision_vm(image_store,args[2],eGroup,managed_node,storage_manager,args[1],memory,cpu)
            print_helper(args[1]," : "+VM_PROVISIONED)
        except Exception,(e):
            raise e
    else:
        print_helper(args[2]," : Image is not compatible")

# Retrives the os info
def show_os_info(serverobj,func_cmd):

     os_info=eval('serverobj.'+func_cmd+'()')
     format_output("Os-Info",os_info)


# Process startall, shutdownall, killall
def vm_all_oper(cmd,serverobj,func_cmd):
    vms=serverobj.get_dom_names()
    for vm in vms:
        vm_oper(cmd[:-8],serverobj,vm,func_cmd)


#
# All vm level operations are handled
#
def vm_operation(cmd,args):
    cmdarglist = cmddict[cmd]
    func_cmd=cmdarglist[0]
    serverobj=server_obj(args[0], args[1])
    if type(serverobj) is int:
        return 0
    if vm_not_exist(serverobj,args[2]):
        print_helper(args[2]," : "+VM_NOT_FOUND)
        return 0

    if cmd=="migrate_vm":
        do_vm_migration(cmd,serverobj,args[2],args[3],args[4],func_cmd)
    elif cmd=="snapshot":
        do_snapshot(cmd,args,serverobj)
    elif cmd=="delete_vm":
        do_delete(cmd,serverobj,args[2],func_cmd)
    elif cmd in ["start","shutdown","pause","resume","kill","reboot"]:
        vm_oper(cmd,serverobj,args[2],func_cmd)
    elif cmd=="set_boot_device":
        set_boot_device(cmd,serverobj,args)


# Migration of vm
def do_vm_migration(cmd,source_node,vname,d_group,d_server,func_cmd):
    dest_node=server_obj(d_group,d_server)
    if vm_state(source_node,vname) in  eval(cmddict[cmd][3]):
          vm_ob= vm_obj(source_node,vname)

          if source_node.hostname == dest_node.hostname:
              print_helper(MIGRATION_ERROR)
              return 0

          error_list,warning_list=source_node.migration_checks([vm_ob], dest_node, True)

          try:
              if len(error_list)>0 or len(warning_list)>0 :
                 if len(error_list)>0:
                    format_output("Error", error_list)
                 if len(warning_list)>0:
                    format_output("Warning", error_list)

                 value=raw_input("y to continue and n to quit:")
                 if value=="y":
                     eval('manager.'+func_cmd+'(vname, source_node, dest_node, True,force=True)')
                 elif value=="n":
                     print_helper(vname," : "+MIGRATION_QUIT)
                     return 0
              else:
                  eval('manager.'+func_cmd+'(vname, source_node, dest_node, True,True)')

              func_cmd=cmddict["kill"][0]
              eval('vm_ob.'+func_cmd+'()')
              print_helper(vname," : "+VM_MIGRATED)
          except Exception(e):
              raise e
    else:
        print_helper(vname," : "+VM_NOT_RUNNING)


# Takes snapshot of a vm
def do_snapshot(cmd,args,serverobj):
    if serverobj is None:
        snap_nodeobj=server_obj(args[0], args[1])
    else:
        snap_nodeobj=serverobj

    file=None
    location=None
    try:
        (options, params) = getopt.gnu_getopt(args, "f:p:")
        for (k, v) in options:
           if k in ["-f"]:
               file=v
           elif k in ["-p"]:
               location=v
    except Exception , e:
        raise e

    if vm_not_exist(snap_nodeobj,args[2]):
        print_helper(args[2]," : "+VM_NOT_FOUND)
        return 0

    vname=args[2]
    if file is None:
        file=vname+SNAPSHOT_FILE_EXT

    if location is None:
        location=SNAPSHOT_FILE_LOCATION

    fname=location+file
    dom=vm_obj(snap_nodeobj,vname)
    if vm_state(snap_nodeobj,vname) in eval(cmddict[cmd][3]):
       try:
            dom._save(fname)
            func_cmd=cmddict["kill"][0]
            eval('dom.'+func_cmd+'()')
            print_helper(vname," : "+SNAPSHOT_CREATED+" in "+location)
       except Exception,(e):
           raise e
    else:
       print_helper(vname," : "+VM_NOT_RUNNING)


# Deletes a vm
def do_delete(cmd,serverobj,vname,func_cmd):
    if vm_state(serverobj,vname) in eval(cmddict[cmd][3]):
        try:
            eval(func_cmd+'(serverobj,vname)')
            print_helper(vname," : "+VM_DELETED)
        except Exception,(e):
           raise e
    else:
        print_helper(vname," : "+VM_RUNNING)



# Process start,shutdown,kill,pause,resume & reboot
def vm_oper(cmd,serverobj,v_name,func_cmd):
    try:
        vm_ob= vm_obj(serverobj,v_name)
        if not vm_ob.isDom0():
            (status,status_msg)=check_vm_state(cmd,serverobj,v_name)
            if status:
                    eval('vm_ob.'+func_cmd+'()')
                    print_helper(v_name," : "+status_msg)
            else:
                print_helper(v_name," : "+status_msg)
    except Exception,(e):
        print_helper(v_name," : "+str(e))


# set boot deivce for vm
def set_boot_device(cmd,serverobj,args):
    
        dom = serverobj.get_dom(args[2])
        vm_config = dom.get_config()
        boot_device=args[3].lower()
        if boot_device=="cd-rom":
            boot_image="d"
        elif boot_device=="disk":
            boot_image="c"
        try:
            vm_config['boot'] = boot_image
            vm_config.write()
            print_helper(args[2]," : "+BOOT_DEVICE+" "+boot_device)
            if vm_state(serverobj,args[2]) in eval(cmddict[cmd][3]):
                 print_helper(VM_RUNNING,", "+VM_BOOT_RESTART)
        except Exception,e:
            raise e

# list all images
def img_operation(cmd):
    cmdarglist = cmddict[cmd]
    func_cmd=cmdarglist[0]
    img_name_list=[]
    images=eval('image_store.'+func_cmd+'()')
    for id in images.keys():
        img=images[id]
        img_name_list.append(img.name)
    format_output("Images", img_name_list)

#
# Exceptional_operations
#
def exception_operations(cmd,args):
    cmdarglist = cmddict[cmd]
    func_cmd=cmdarglist[0]

    if len(args)==4 and args[0]=="--vm" and cmd in ["start","shutdown","kill","pause","resume","reboot"]:
        vm_general_oper(cmd,args,func_cmd)
    elif cmd=="snapshot":
        do_snapshot(cmd,args,None)
    elif cmd=="provision_vm":
        do_provisioning(args)
    elif cmd=="list_vms":
        list_all_vms(cmd,func_cmd,args)
    elif cmd=="add_server":
        add_server(args,func_cmd)
    elif cmd=="restore":
         do_restore(args,func_cmd,None)
    elif cmd=="edit_server" and len(args)>2:
        do_edit_server(args,func_cmd)
    else:
        command_usage(cmd)


# Do operations like:start --vm
def  vm_general_oper(cmd,args,func_cmd):

    chk_dup_vm_list=check_duplicate_vm(args)
    if len(chk_dup_vm_list)==1:
         args=chk_dup_vm_list[0].split(",")
         sobj=manager.getNode(args[1], args[0])
         vm_oper(cmd,sobj,args[2],func_cmd)
    elif len(chk_dup_vm_list)>1:
        format_output("Vms found",chk_dup_vm_list)
        return 0
    else:
        print_helper(args[1]," : "+VM_NOT_FOUND)
        return 0

def list_vm_header():
    list_vmname.append("VM              STATUS            SERVER ")
    list_vmname.append("----------------------------------------------")

# Lists all vms details are handled here
def list_all_vms(cmd,func_cmd,args):

    list_all=False
    username = None
    password=None
    try:
        (options, params) = getopt.gnu_getopt(args, "u:p:",["l"])
        for (k, v) in options:
           if k in ["-u"]:
               username=v
           elif k in ["-p"]:
               password=v
           elif k in ["--l"]:
               list_all=True
    except Exception,e:
        raise e
    if username is None and password is None:
        serverobj=server_obj(args[0], args[1])
        if type(serverobj) is int:
            return 0
        if list_all==True:
            list_vm_det(serverobj,func_cmd,args[0],args[1])
        else:
            list_vm_header()
            list_vm_name(serverobj,func_cmd,args[1])
            if len(list_vmname)>2:
                format_output("VM List", list_vmname)

    elif username is not None and password is not None:
        if list_all==True:
            grp_names=manager.getGroupNames()
            for grp in grp_names:
                server_list=list(manager.getNodeList(grp))
                for server in server_list:
                     m_node=manager.getNode(server, grp)
                     m_node.set_credentials(username, password)
                     try:
                        m_node.connect()
                        list_vm_det(m_node,func_cmd,grp,server)
                     except Exception,e:
                         error_log(e)
                         print_helper("Error in "+grp+" - "+server," : "+str(e))
        else:
            grp_names=manager.getGroupNames()
            list_vm_header()
            for grp in grp_names:
                server_list=list(manager.getNodeList(grp))
                for server in server_list:
                     m_node=manager.getNode(server, grp)
                     m_node.set_credentials(username, password)
                     try:
                        m_node.connect()
                        list_vm_name(m_node,func_cmd,server)
                     except Exception,e:
                         error_log(e)
                         print_helper("Error in "+grp+" - "+server," : "+str(e))
            if len(list_vmname)>2:
                format_output("VM List", list_vmname)
    else:
        print_helper(cmdhelpdict[cmd])


# Checks the vmname unique or not
def check_duplicate_vm(args):
    vm_info_list=[]
    counter=0

    grop_names=manager.getGroupNames()
    for group in grop_names:
        server_list= list(manager.getNodeList(group))
        for server in server_list:
            sobj=manager.getNode(server, group)
            sobj.set_credentials(args[2], args[3])
            try:
                sobj.connect()
                vms=sobj.get_dom_names()
                for vm in vms:
                    if vm==args[1]:
                        vm_info=group+","+server+","+vm
                        vm_info_list.insert(counter,vm_info)
                        counter=counter+1
            except Exception,(e):
                error_log(e)
                print_helper(group+" - "+server," : "+NOT_AUTHENTICATED)

    return vm_info_list


#edits server details
def do_edit_server(args,func_cmd):
    existing_node=server_obj(args[0], args[1])
    if type(existing_node) is int:
        return 0

    platform=existing_node.platform
    username=existing_node.username
    ssh_port=existing_node.ssh_port
    usekeys=existing_node.use_keys
    password=existing_node.password
    isRemote=existing_node.isRemote
    address=args[1]
    new_pass = None

    if usekeys==False:
        use_keys="n"
    else:
        use_keys="y"
        
    try:
        (options, params) = getopt.gnu_getopt(args, "u:p:k:s:")
        for (k, v) in options:
           if k in ["-s"]:
               ssh_port=int(v)
           elif k in ["-k"]:
               use_keys=v
           elif k in ["-u"]:
               username=v
           elif k in ["-p"]:
               new_pass=v
               
    except Exception,e:
        raise e

    if new_pass is None:
        use_keys=use_keys.lower()
        if use_keys =="n":
            usekeys=False
            password=getpass.getpass("Enter password of "+args[1]+": ")
        elif use_keys =="y":
            usekeys=True
            password=None
    else:
        password=new_pass
        usekeys=False

    try:
        factory = manager.getFactory(platform)
        node = factory.create_node(platform=platform,
            hostname=args[1],
            username=username,
            password=password,
            is_remote=isRemote,
            ssh_port=int(ssh_port),
            use_keys=usekeys,
            address=address)
        node.connect()
        manager.removeNode(existing_node.hostname,args[0])
        if existing_node is not None and existing_node._node_proxy is not None:
             Node.clean_locals(existing_node.node_proxy)

        eval('manager.'+func_cmd+'(node, args[0])')
        print_helper(args[1]," : "+SERVER_EDITED)
    except Exception, (strerror):
        print_helper(SERVER_EDIT_ERR," : "+ str(strerror))
    

# Checks the state of a vm
def check_vm_state(cmd,serverobj,v_name):
    status=False
    status_msg=""
    if cmd=="start":
         if vm_state(serverobj,v_name) in eval(cmddict[cmd][3]):
             status=True
             status_msg=VM_STARTED
         else:
             status_msg= VM_RUNNING
    elif cmd in ["shutdown","reboot","kill"] :
         if vm_state(serverobj,v_name) in eval(cmddict[cmd][3]):
             status=True
             status_msg=" "+cmd+" in progress"
         else:
             status_msg=VM_NOT_RUNNING
    elif cmd=="pause":
         if vm_state(serverobj,v_name) in eval(cmddict[cmd][3]):
             status=True
             status_msg=VM_PAUSED
         else:
             status_msg=VM_NOT_RUNNING
    elif cmd=="resume":
         if vm_state(serverobj,v_name) in eval(cmddict[cmd][3]):
             status=True
             status_msg=VM_RESUME
         else:
             status_msg=VM_NOT_PAUSED

    return (status,status_msg)

# Creates a node object
def server_obj(group,server):

    grp_names=manager.getGroupNames()
    if group in grp_names:
        server_list=list(manager.getNodeList(group))
        if server not in server_list:
            print_helper(server," : "+NO_SERVER_NAME)
            return 0
    else:
        print_helper(group," : "+NO_SERVERPOOL_NAME)
        return 0


    serverobj=manager.getNode(server, group)
    if serverobj.isRemote:
        if serverobj.use_keys == False:
            serverobj.password = getpass.getpass("Enter password to connect to "+server+": ")
        serverobj.connect()
    return serverobj

# Creates a vm object
def vm_obj(serverobj,vmname):
    return serverobj.get_dom(vmname)


# Returns state of a vm
def vm_state(serverobj,v_name):
    return serverobj.get_state(v_name)

def vm_not_exist(serverobj,v_name):
     vms=serverobj.get_dom_names()
     if v_name in vms:
         return False
     else:
         return True

# Print the result statement
def print_helper(first_data,second_data=""):

    first_data=str(first_data)
    second_data==str(second_data)

    print_stmt=first_data+second_data
    print print_stmt


# Formats the output display
def format_output(title,value):

    print_helper("["+title+"]","\n")

# checks dictionary or list
    if type(value)==type({}):
        for key in value.keys():
            print_helper("%-20s  -  %2s" % (key,value[key]))
    elif type(value)==type([]):
        for data in value:
            print_helper(data)

# Cli header
def cli_header():
    #print_helper("*******************************************")
    print_helper("Convirt %s CLI (preview) run on " % (constants._version,),
                 str(datetime.date.today()))
    #print_helper( "*******************************************")

# Prints the cli command usage
def command_usage(cmd):

   #print_helper("==========================================")
   print_helper("Usage: ", str(cmdhelpdict[cmd]))
   #print_helper("==========================================")

# All exceptions are written
def error_log(exception):
    enable_log = client_config.get(utils.XMConfig.CLIENT_CONFIG,prop_enable_log)
    if enable_log:
        cli_log_file = client_config.get(utils.XMConfig.CLIENT_CONFIG,
                             prop_cli_log_file)
        if cli_log_file and cli_log_file is not '':
            if cli_log_file != "console":
                if cli_log_file[0] != '/' and (cli_log_file.find("./") != 0):
                    # assume path relative to log_dir
                    log_location = client_config.get(utils.XMConfig.PATHS,
                                                     prop_log_dir)
                    cli_log_file = os.path.join(log_location,cli_log_file)
                try:
                    if not os.path.exists(log_location):
                        utils.mkdir2(local_node,log_location)
                    f = open(cli_log_file, "w")
                    f.write(str(exception))
                except Exception, ex:
                    raise ex
            else:
                # do nothing
                pass


def main(argv=sys.argv):
#    print "Length of args is ",len(argv)
    if len(argv) ==1 :
       usage()
    else:
         inpcmd=argv[1]
         if len(argv)==2 and argv[1] == "help":
             usage()
         elif not cmddict.has_key(inpcmd):
            print_helper(INVALID_CMD," : "+inpcmd)
            usage()
         elif len(argv)>2 and argv[2] == "help":
            command_usage(argv[1])
         else:
             try:
                 header=0
                 inpcmd=argv[1]
                 inpargs=argv[2:]
                 (options, params) = getopt.gnu_getopt(argv, "pkfsmcu",["noheader","l","vm"])
                 for (k, v) in options:
                    if k in ["--noheader"] :
                        header=1
                        inpargs.remove("--noheader")
                 if  header==0:
                    cli_header()
                 proc_cmd(inpcmd,inpargs)
             except Exception, e:
                 raise e

if __name__ == "__main__":
   sys.stdout,sys.stderr,sys.stdin,sys.__stdout__,sys.__stderr__,sys.__stdin__=old_printerators
   try:
       main()
   except Exception, e:
        error_log(e)
        print_helper(UNEXPECTED_ERROR," : "+str(e))

# let manager shutdown
if manager is not None:
    manager.shutdown()

   #print "end of __main__"

