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 getattr(plugin, func, log_no_such_method)(*args, **kwargs)
159
160 for f in context.hooks.get(func, []):
161 logging.debug('Calling %r.' % (f,))
162 f(*args, **kwargs)
163
164 logging.debug('Calling %s method in context plugin %s.' % (func, context.__module__))
165 getattr(context, func, log_no_such_method)(*args, **kwargs)
166
168 logging.debug('No such method')
169 return
170
172
173
174 return tempfile.mktemp(suffix=suffix, dir=tmp_root)
175
176 -def tmpdir(suffix='', tmp_root=None):
177 return tempfile.mkdtemp(suffix=suffix, dir=tmp_root)
178
180 """Sets up a tmpfs storage under `tmp_root` with the size of `size` MB.
181
182 `tmp_root` defaults to tempfile.gettempdir().
183 """
184 mount_point = tmpdir('tmpfs', tmp_root)
185 mount_cmd = ["mount", "-t", "tmpfs",
186 "-o", "size=%dM,mode=0770" % int(size),
187 "tmpfs", mount_point ]
188 logging.info('Mounting tmpfs under %s' % mount_point)
189 logging.debug('Executing: %s' % mount_cmd)
190 run_cmd(*mount_cmd)
191
192 return mount_point
193
195 """Unmounts a tmpfs storage under `mount_point`."""
196 umount_cmd = ["umount", "-t", "tmpfs", mount_point ]
197 logging.info('Unmounting tmpfs from %s' % mount_point)
198 logging.debug('Executing: %s' % umount_cmd)
199 run_cmd(*umount_cmd)
200
201
203 confvalue = None
204 try:
205 confvalue = confparser.get('DEFAULT', key)
206 except ConfigParser.NoSectionError:
207 pass
208 except ConfigParser.NoOptionError:
209 pass
210
211 if confparser.has_option(context.arg, key):
212 confvalue = confparser.get(context.arg, key)
213
214 logging.debug('Returning value %s for configuration key %s' % (repr(confvalue), key))
215 return confvalue
216
217 -def apply_config_files_to_context(config_files, context):
218 confparser = ConfigParser.SafeConfigParser()
219 confparser.read(config_files)
220
221 for (key, setting) in context._config.iteritems():
222 confvalue = get_conf_value(context, confparser, key)
223 if confvalue:
224 setting.set_value_fuzzy(confvalue)
225