1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 import ConfigParser
21 import errno
22 import fcntl
23 import logging
24 import os.path
25 import select
26 import subprocess
27 import tempfile
28 from exception import VMBuilderException, VMBuilderUserError
29
32 self.file = fp
33 self.set_non_blocking()
34 self.buf = ''
35 self.logbuf = ''
36 self.logfunc = logfunc
37
39 flags = fcntl.fcntl(self.file, fcntl.F_GETFL)
40 flags = flags | os.O_NONBLOCK
41 fcntl.fcntl(self.file, fcntl.F_SETFL, flags)
42
44 if attr == 'closed':
45 return self.file.closed
46 else:
47 raise AttributeError()
48
61
63 """
64 Runs a command.
65
66 Locale is reset to C to make parsing error messages possible.
67
68 @type stdin: string
69 @param stdin: input to provide to the process on stdin. If None, process'
70 stdin will be attached to /dev/null
71 @type ignore_fail: boolean
72 @param ignore_fail: If True, a non-zero exit code from the command will not
73 cause an exception to be raised.
74 @type env: dict
75 @param env: Dictionary of extra environment variables to set in the new process
76
77 @rtype: string
78 @return: string containing the stdout of the process
79 """
80
81 env = kwargs.get('env', {})
82 stdin = kwargs.get('stdin', None)
83 ignore_fail = kwargs.get('ignore_fail', False)
84 args = [str(arg) for arg in argv]
85 logging.debug(args.__repr__())
86 if stdin:
87 logging.debug('stdin was set and it was a string: %s' % (stdin,))
88 stdin_arg = subprocess.PIPE
89 else:
90 stdin_arg = file('/dev/null', 'r')
91 proc_env = dict(os.environ)
92 proc_env['LANG'] = 'C'
93 proc_env['LC_ALL'] = 'C'
94 proc_env.update(env)
95
96 try:
97 proc = subprocess.Popen(args, stdin=stdin_arg, stderr=subprocess.PIPE, stdout=subprocess.PIPE, env=proc_env)
98 except OSError, error:
99 if error.errno == errno.ENOENT:
100 raise VMBuilderUserError, "Couldn't find the program '%s' on your system" % (argv[0])
101 else:
102 raise VMBuilderUserError, "Couldn't launch the program '%s': %s" % (argv[0], error)
103
104 if stdin:
105 proc.stdin.write(stdin)
106 proc.stdin.close()
107
108 mystdout = NonBlockingFile(proc.stdout, logfunc=logging.debug)
109 mystderr = NonBlockingFile(proc.stderr, logfunc=(ignore_fail and logging.debug or logging.info))
110
111 while not (mystdout.closed and mystderr.closed):
112
113 fds = select.select([x.file for x in [mystdout, mystderr] if not x.closed], [], [])[0]
114 for fp in [mystderr, mystdout]:
115 if fp.file in fds:
116 fp.process_input()
117
118 status = proc.wait()
119 if not ignore_fail and status != 0:
120 raise VMBuilderException, "Process (%s) returned %d. stdout: %s, stderr: %s" % (args.__repr__(), status, mystdout.buf, mystderr.buf)
121 return mystdout.buf
122
124 """
125 Check if we're running as root, and bail out if we're not.
126 """
127
128 if os.geteuid() != 0:
129 raise VMBuilderUserError("This script must be run as root (e.g. via sudo)")
130
132
133 from Cheetah.Template import Template
134 searchList = []
135 if context:
136 searchList.append(extra_context)
137 searchList.append(context)
138
139
140
141 tmpldirs = [dir % plugin for dir in context.template_dirs]
142
143 for dir in tmpldirs:
144 tmplfile = '%s/%s.tmpl' % (dir, tmplname)
145 if os.path.exists(tmplfile):
146 t = Template(file=tmplfile, searchList=searchList)
147 output = t.respond()
148 logging.debug('Output from template \'%s\': %s' % (tmplfile, output))
149 return output
150
151 raise VMBuilderException('Template %s.tmpl not found in any of %s' % (tmplname, ', '.join(tmpldirs)))
152
154 logging.info('Calling hook: %s' % func)
155 logging.debug('(args=%r, kwargs=%r)' % (args, kwargs))
156 for plugin in context.plugins:
157 logging.debug('Calling %s method in %s plugin.' % (func, plugin.__module__))
158 try:
159 getattr(plugin, func)(*args, **kwargs)
160 except AttributeError as e:
161 logging.debug('No such method ({}) in context plugin ({})'.format(
162 func, plugin.__module__))
163
164 for f in context.hooks.get(func, []):
165 logging.debug('Calling %r.' % (f,))
166 f(*args, **kwargs)
167
168 logging.debug('Calling %s method in context plugin %s.' % (func, context.__module__))
169 try:
170 getattr(context, func)(*args, **kwargs)
171 except AttributeError as e:
172 logging.debug('No such method ({}) in context plugin ({})'.format(
173 func, plugin.__module__))
174
176
177
178 return tempfile.mktemp(suffix=suffix, dir=tmp_root)
179
180 -def tmpdir(suffix='', tmp_root=None):
181 return tempfile.mkdtemp(suffix=suffix, dir=tmp_root)
182
184 """Sets up a tmpfs storage under `tmp_root` with the size of `size` MB.
185
186 `tmp_root` defaults to tempfile.gettempdir().
187 """
188 mount_point = tmpdir('tmpfs', tmp_root)
189 mount_cmd = ["mount", "-t", "tmpfs",
190 "-o", "size=%dM,mode=0770" % int(size),
191 "tmpfs", mount_point ]
192 logging.info('Mounting tmpfs under %s' % mount_point)
193 logging.debug('Executing: %s' % mount_cmd)
194 run_cmd(*mount_cmd)
195
196 return mount_point
197
199 """Unmounts a tmpfs storage under `mount_point`."""
200 umount_cmd = ["umount", "-t", "tmpfs", mount_point ]
201 logging.info('Unmounting tmpfs from %s' % mount_point)
202 logging.debug('Executing: %s' % umount_cmd)
203 run_cmd(*umount_cmd)
204
205
207 confvalue = None
208 try:
209 confvalue = confparser.get('DEFAULT', key)
210 except ConfigParser.NoSectionError:
211 pass
212 except ConfigParser.NoOptionError:
213 pass
214
215 if confparser.has_option(context.arg, key):
216 confvalue = confparser.get(context.arg, key)
217
218 logging.debug('Returning value %s for configuration key %s' % (repr(confvalue), key))
219 return confvalue
220
221 -def apply_config_files_to_context(config_files, context):
222 confparser = ConfigParser.SafeConfigParser()
223 confparser.read(config_files)
224
225 for (key, setting) in context._config.iteritems():
226 confvalue = get_conf_value(context, confparser, key)
227 if confvalue:
228 setting.set_value_fuzzy(confvalue)
229