Update version.py and ChangeLog for 0.6.1
[snf-image-creator] / 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 import distutils
42
43 from image_creator.util import FatalError
44
45
46 class WinexeTimeout(FatalError):
47     """Raised when a WinExE command times-out"""
48     pass
49
50
51 class WinEXE:
52     """Wrapper class for the winexe command"""
53
54     @staticmethod
55     def is_installed(program='winexe'):
56         return distutils.spawn.find_executable(program) is not None
57
58     def __init__(self, username, password, hostname, program='winexe'):
59         self._host = hostname
60         self._user = username
61         self._pass = password
62         self._prog = program
63
64         # -U USERNAME[%PASSWORD]
65         user = '%s%s' % (self._user, '%%%s' % self._pass if self._pass else "")
66         self._opts = ['-U', user]
67
68     def reset(self):
69         """Reset all winexe options"""
70
71         # -U USERNAME[%PASSWORD]
72         user = '%s%s' % (self._user, '%%%s' % self._pass if self._pass else "")
73         self._opts = ['-U', user]
74
75     def runas(self, username, password):
76         """Run command as this user"""
77         self._opts.append('--runas=%s%%%s' % (username, password))
78         return self
79
80     def system(self):
81         """Use SYSTEM account"""
82         self._opts.append('--system')
83         return self
84
85     def uninstall(self):
86         """Uninstall winexe service after remote execution"""
87         self._opts.append('--uninstall')
88         return self
89
90     def reinstall(self):
91         """Reinstall winexe service before remote execution"""
92         self._opts.append('--reinstall')
93         return self
94
95     def debug(self, level):
96         """Set debug level"""
97         self._opts.append('--debuglevel=%d' % level)
98         return self
99
100     def debug_stderr(self):
101         """Send debug output to STDERR"""
102         self._opts.append('--debug-stderr')
103
104     def run(self, command, timeout=0):
105         """Run a command on a remote windows system"""
106
107         args = [self._prog] + self._opts + ["//%s" % self._host] + [command]
108         run = subprocess.Popen(args, stdout=subprocess.PIPE,
109                                stderr=subprocess.PIPE)
110
111         def handler(signum, frame):
112             run.terminate()
113             time.sleep(1)
114             run.poll()
115             if run.returncode is None:
116                 run.kill()
117             run.wait()
118             raise WinexeTimeout("Command: `%s' timed-out" % " ".join(args))
119
120         signal.signal(signal.SIGALRM, handler)
121         signal.alarm(timeout)
122         stdout, stderr = run.communicate()
123         rc = run.poll()
124         signal.alarm(0)
125
126         return (stdout, stderr, rc)
127
128 # vim: set sta sts=4 shiftwidth=4 sw=4 et ai :