Convert check_guestfs_version into an Image method
[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
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 :