From: Nikos Skalkotos Date: Wed, 24 Jul 2013 09:30:22 +0000 (+0300) Subject: Add a new winexe module X-Git-Tag: 0.5~1^2~13^2~10 X-Git-Url: https://code.grnet.gr/git/snf-image-creator/commitdiff_plain/f5873ed0b623823b6bd2e2bac2c9a841a235eae0 Add a new winexe module This contains a wrapper class for winexe utility --- diff --git a/image_creator/os_type/windows.py b/image_creator/os_type/windows.py index c999950..5732d6b 100644 --- a/image_creator/os_type/windows.py +++ b/image_creator/os_type/windows.py @@ -38,6 +38,7 @@ Windows OSs.""" from image_creator.os_type import OSBase, sysprep from image_creator.util import FatalError, check_guestfs_version, get_command +from image_creator.winexe import WinEXE, WinexeTimeout import hivex import tempfile @@ -685,15 +686,15 @@ class Windows(OSBase): def _guest_exec(self, command, fatal=True): """Execute a command on a windows VM""" - user = "Administrator%" + self.sysprep_params['password'] - addr = 'localhost' - runas = '--runas=%s' % user - winexe = subprocess.Popen( - ['winexe', '-U', user, runas, "--uninstall", "//%s" % addr, - command], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + passwd = self.sysprep_params['password'] - stdout, stderr = winexe.communicate() - rc = winexe.poll() + winexe = WinEXE('Administrator', passwd, 'localhost') + winexe.runas('Administrator', passwd).uninstall() + + try: + (stdout, stderr, rc) = winexe.run(command) + except WinexeTimeout: + FatalError("Command: `%s' timeout out." % command) if rc != 0 and fatal: reason = stderr if len(stderr) else stdout diff --git a/image_creator/winexe.py b/image_creator/winexe.py new file mode 100644 index 0000000..ebac409 --- /dev/null +++ b/image_creator/winexe.py @@ -0,0 +1,123 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2013 GRNET S.A. All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# The views and conclusions contained in the software and +# documentation are those of the authors and should not be +# interpreted as representing official policies, either expressed +# or implied, of GRNET S.A. + +"""This module provides an interface for the WinEXE utility""" + +import subprocess +import time +import signal + +from image_creator.util import FatalError + + +class WinexeTimeout(FatalError): + """Raised when a WinExE command times-out""" + pass + + +class WinEXE: + """Wrapper class for the winexe command""" + + def __init__(self, username, password, hostname, program='winexe'): + self._host = hostname + self._user = username + self._pass = password + self._prog = program + + # -U USERNAME[%PASSWORD] + user = '%s%s' % (self._user, '%%%s' % self._pass if self._pass else "") + self._opts = ['-U', user] + + def reset(self): + """Reset all winexe options""" + + # -U USERNAME[%PASSWORD] + user = '%s%s' % (self._user, '%%%s' % self._pass if self._pass else "") + self._opts = ['-U', user] + + def runas(self, username, password): + """Run command as this user""" + self._opts.append('--runas=%s%%%s' % (username, password)) + return self + + def system(self): + """Use SYSTEM account""" + self._opts.append('--system') + return self + + def uninstall(self): + """Uninstall winexe service after remote execution""" + self._opts.append('--uninstall') + return self + + def reinstall(self): + """Reinstall winexe service before remote execution""" + self._opts.append('--reinstall') + return self + + def debug(self, level): + """Set debug level""" + self._opts.append('--debuglevel=%d' % level) + return self + + def debug_stderr(self): + """Send debug output to STDERR""" + self._opts.append('--debug-stderr') + + def run(self, command, timeout=0): + """Run a command on a remote windows system""" + + args = [self._prog] + self._opts + ["//%s" % self._host] + [command] + run = subprocess.Popen(args, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + + def handler(signum, frame): + run.terminate() + time.sleep(1) + run.poll() + if run.returncode is None: + run.kill() + run.wait() + raise WinexeTimeout("Command: `%s' timed-out" % " ".join(args)) + + signal.signal(signal.SIGALRM, handler) + signal.alarm(timeout) + stdout, stderr = run.communicate() + rc = run.poll() + signal.alarm(0) + + return (stdout, stderr, rc) + +# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :