#!/usr/bin/env python
# vsphere-guest-command --- run command in virtual machine via guest tools

# Author: Noah Friedman <friedman@splode.com>
# Created: 2018-08-20
# Public domain

# $Id: vsphere-guest-command,v 1.6 2018/10/04 15:51:05 friedman Exp $

# Commentary:
# Code:

from   __future__ import print_function
import vspherelib     as vsl

import os
import sys

def get_args():
    p = vsl.ArgumentParser( loadrc=True )
    p.add( '-U', '--guest-username',  required=True )
    p.add( '-P', '--guest-password',  required=True )
    p.add( '-F', '--script-file',                    default=None )
    p.add( '-O', '--no-output',       dest='output', default=True,   action='store_false' )
    p.add( '-E', '--separate-stderr',                default=False,  action='store_true' )
    p.add( '-W', '--no-wait',         dest='wait',   default=True,   action='store_false' )
    p.add( '-C', '--cwd',                            default=None )
    p.add( '-v', '--verbose',                        default=False,  action='store_true' )
    p.add( '-L', '--local-environ',                  default=False,  action='store_true' )
    p.add( '-m', '--multi-command',   dest='multi',  default=False,  action='store_true' )
    p.add( 'vm',   nargs=1,                          help='VM name' )
    p.add( 'cmd',  nargs='*',                        help='Commands (one per arg)' )
    return p.parse()


def output_fixup( vop, s ):
    # Some windows commands (e.g. wmic) output utf16.
    # Unfortunately this can be mixed with ascii,
    # so we can't convert the entire output using a proper codec.
    if vop.ostype is vsl.WinNT:
        fixups = [ ('\ufeff', ''),
                   ('\0',     ''),
                   ('\r\n',   '\n'), ]
        for f in fixups:
            s = s.replace( *f )
    return s

def main():
    args = get_args()
    vsi  = vsl.vmomiConnect( args )
    vm   = vsi.find_vm( args.vm )[0]
    vop  = vsi.vmguest_ops( vm,
                            username=args.guest_username,
                            password=args.guest_password )

    if (args.output or args.separate_stderr) and not args.wait:
        vsl.printerr( 'cannot use --no-wait unless output is disabled' )
        sys.exit( 1 )

    join_char = '\n' if args.multi else ' '
    pargs = { 'wait'            : args.wait,
              'script_file'     : args.script_file,
              'script'          : join_char.join( args.cmd ),
              'output'          : args.output,
              'separate_stderr' : args.separate_stderr,
              'cwd'             : args.cwd, }
    if args.local_environ:
        pargs[ 'environ' ] = os.environ

    proc = vop.run( **pargs )
    if not args.wait:
        sys.exit( 0 )

    res = proc.result
    if res.get( 'output' ):
        print( output_fixup( vop, res.output ))
    if res.get( 'stderr' ):
        print( output_fixup( vop, res.stderr ), file=sys.stderr )
    if args.verbose:
        print( '[Exit {}]'.format( str( res.exit )), file=sys.stderr )
        print( 'Started:', res.startTime, file=sys.stderr )
        print( 'Ended:  ', res.endTime,   file=sys.stderr )
    sys.exit( res.exit )


if __name__ == '__main__':
    main()

# eof
