Revision 63af9c37

b/image_creator/os_type/windows.py
38 38

  
39 39
from image_creator.os_type import OSBase, sysprep
40 40
from image_creator.util import FatalError, check_guestfs_version, get_command
41
from image_creator.winexe import WinEXE, WinexeTimeout
41 42

  
42 43
import hivex
43 44
import tempfile
......
685 686
    def _guest_exec(self, command, fatal=True):
686 687
        """Execute a command on a windows VM"""
687 688

  
688
        user = "Administrator%" + self.sysprep_params['password']
689
        addr = 'localhost'
690
        runas = '--runas=%s' % user
691
        winexe = subprocess.Popen(
692
            ['winexe', '-U', user, runas, "--uninstall", "//%s" % addr,
693
             command], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
689
        passwd = self.sysprep_params['password']
694 690

  
695
        stdout, stderr = winexe.communicate()
696
        rc = winexe.poll()
691
        winexe = WinEXE('Administrator', passwd, 'localhost')
692
        winexe.runas('Administrator', passwd).uninstall()
693

  
694
        try:
695
            (stdout, stderr, rc) = winexe.run(command)
696
        except WinexeTimeout:
697
            FatalError("Command: `%s' timeout out." % command)
697 698

  
698 699
        if rc != 0 and fatal:
699 700
            reason = stderr if len(stderr) else stdout
b/image_creator/winexe.py
1
# -*- coding: utf-8 -*-
2
#
3
# Copyright 2013 GRNET S.A. All rights reserved.
4
#
5
# Redistribution and use in source and binary forms, with or
6
# without modification, are permitted provided that the following
7
# conditions are met:
8
#
9
#   1. Redistributions of source code must retain the above
10
#      copyright notice, this list of conditions and the following
11
#      disclaimer.
12
#
13
#   2. Redistributions in binary form must reproduce the above
14
#      copyright notice, this list of conditions and the following
15
#      disclaimer in the documentation and/or other materials
16
#      provided with the distribution.
17
#
18
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
# POSSIBILITY OF SUCH DAMAGE.
30
#
31
# The views and conclusions contained in the software and
32
# documentation are those of the authors and should not be
33
# interpreted as representing official policies, either expressed
34
# or implied, of GRNET S.A.
35

  
36
"""This module provides an interface for the WinEXE utility"""
37

  
38
import subprocess
39
import time
40
import signal
41

  
42
from image_creator.util import FatalError
43

  
44

  
45
class WinexeTimeout(FatalError):
46
    """Raised when a WinExE command times-out"""
47
    pass
48

  
49

  
50
class WinEXE:
51
    """Wrapper class for the winexe command"""
52

  
53
    def __init__(self, username, password, hostname, program='winexe'):
54
        self._host = hostname
55
        self._user = username
56
        self._pass = password
57
        self._prog = program
58

  
59
        # -U USERNAME[%PASSWORD]
60
        user = '%s%s' % (self._user, '%%%s' % self._pass if self._pass else "")
61
        self._opts = ['-U', user]
62

  
63
    def reset(self):
64
        """Reset all winexe options"""
65

  
66
        # -U USERNAME[%PASSWORD]
67
        user = '%s%s' % (self._user, '%%%s' % self._pass if self._pass else "")
68
        self._opts = ['-U', user]
69

  
70
    def runas(self, username, password):
71
        """Run command as this user"""
72
        self._opts.append('--runas=%s%%%s' % (username, password))
73
        return self
74

  
75
    def system(self):
76
        """Use SYSTEM account"""
77
        self._opts.append('--system')
78
        return self
79

  
80
    def uninstall(self):
81
        """Uninstall winexe service after remote execution"""
82
        self._opts.append('--uninstall')
83
        return self
84

  
85
    def reinstall(self):
86
        """Reinstall winexe service before remote execution"""
87
        self._opts.append('--reinstall')
88
        return self
89

  
90
    def debug(self, level):
91
        """Set debug level"""
92
        self._opts.append('--debuglevel=%d' % level)
93
        return self
94

  
95
    def debug_stderr(self):
96
        """Send debug output to STDERR"""
97
        self._opts.append('--debug-stderr')
98

  
99
    def run(self, command, timeout=0):
100
        """Run a command on a remote windows system"""
101

  
102
        args = [self._prog] + self._opts + ["//%s" % self._host] + [command]
103
        run = subprocess.Popen(args, stdout=subprocess.PIPE,
104
                               stderr=subprocess.PIPE)
105

  
106
        def handler(signum, frame):
107
            run.terminate()
108
            time.sleep(1)
109
            run.poll()
110
            if run.returncode is None:
111
                run.kill()
112
            run.wait()
113
            raise WinexeTimeout("Command: `%s' timed-out" % " ".join(args))
114

  
115
        signal.signal(signal.SIGALRM, handler)
116
        signal.alarm(timeout)
117
        stdout, stderr = run.communicate()
118
        rc = run.poll()
119
        signal.alarm(0)
120

  
121
        return (stdout, stderr, rc)
122

  
123
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :

Also available in: Unified diff