Package VMBuilder :: Module util
[frames] | no frames]

Source Code for Module VMBuilder.util

  1  # 
  2  #    Uncomplicated VM Builder 
  3  #    Copyright (C) 2007-2008 Canonical Ltd. 
  4  #     
  5  #    See AUTHORS for list of contributors 
  6  # 
  7  #    This program is free software: you can redistribute it and/or modify 
  8  #    it under the terms of the GNU General Public License as published by 
  9  #    the Free Software Foundation, either version 3 of the License, or 
 10  #    (at your option) any later version. 
 11  # 
 12  #    This program is distributed in the hope that it will be useful, 
 13  #    but WITHOUT ANY WARRANTY; without even the implied warranty of 
 14  #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 15  #    GNU General Public License for more details. 
 16  # 
 17  #    You should have received a copy of the GNU General Public License 
 18  #    along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 19  # 
 20  #    Various utility functions 
 21  import logging 
 22  import os 
 23  import os.path 
 24  import pwd 
 25  import select 
 26  import subprocess 
 27  import sys 
 28  import time 
 29  from   exception        import VMBuilderException, VMBuilderUserError 
 30   
31 -class NonBufferedFile():
32 - def __init__(self, file):
33 self.file = file 34 self.buf = ''
35
36 - def __getattr__(self, attr):
37 if attr == 'closed': 38 return self.file.closed 39 else: 40 raise AttributeError()
41
42 - def __iter__(self):
43 return self
44
45 - def read_will_block(self):
46 (ins, foo, bar) = select.select([self.file], [], [], 1) 47 48 if self.file not in ins: 49 return True 50 return False
51
52 - def next(self):
53 if self.file.closed: 54 raise StopIteration() 55 56 while not self.read_will_block(): 57 c = self.file.read(1) 58 if not c: 59 self.file.close() 60 if self.buf: 61 return self.buf 62 else: 63 raise StopIteration 64 else: 65 self.buf += c 66 if self.buf.endswith('\n'): 67 ret = self.buf 68 self.buf = '' 69 return ret 70 raise StopIteration()
71
72 -def run_cmd(*argv, **kwargs):
73 """ 74 Runs a command. 75 76 Locale is reset to C to make parsing error messages possible. 77 78 @type stdin: string 79 @param stdin: input to provide to the process on stdin. If None, process' 80 stdin will be attached to /dev/null 81 @type ignore_fail: boolean 82 @param ignore_fail: If True, a non-zero exit code from the command will not 83 cause an exception to be raised. 84 @type env: dict 85 @param env: Dictionary of extra environment variables to set in the new process 86 87 @rtype: string 88 @return: string containing the stdout of the process 89 """ 90 91 env = kwargs.get('env', {}) 92 stdin = kwargs.get('stdin', None) 93 ignore_fail = kwargs.get('ignore_fail', False) 94 stdout = stderr = '' 95 args = [str(arg) for arg in argv] 96 logging.debug(args.__repr__()) 97 if stdin: 98 logging.debug('stdin was set and it was a string: %s' % (stdin,)) 99 stdin_arg = subprocess.PIPE 100 else: 101 stdin_arg = file('/dev/null', 'w') 102 proc_env = dict(os.environ) 103 proc_env['LANG'] = 'C' 104 proc_env['LC_ALL'] = 'C' 105 proc_env.update(env) 106 proc = subprocess.Popen(args, stdin=stdin_arg, stderr=subprocess.PIPE, stdout=subprocess.PIPE, env=proc_env) 107 108 if stdin: 109 proc.stdin.write(stdin) 110 proc.stdin.close() 111 112 mystdout = NonBufferedFile(proc.stdout) 113 mystderr = NonBufferedFile(proc.stderr) 114 115 while not (mystdout.closed and mystderr.closed): 116 # Block until either of them has something to offer 117 select.select([x.file for x in [mystdout, mystderr] if not x.closed], [], []) 118 for buf in mystderr: 119 stderr += buf 120 (ignore_fail and logging.debug or logging.info)(buf.rstrip()) 121 122 for buf in mystdout: 123 logging.debug(buf.rstrip()) 124 stdout += buf 125 126 status = proc.wait() 127 if not ignore_fail and status != 0: 128 raise VMBuilderException, "Process (%s) returned %d. stdout: %s, stderr: %s" % (args.__repr__(), status, stdout, stderr) 129 return stdout
130
131 -def give_to_caller(path):
132 """ 133 Change ownership of file to $SUDO_USER. 134 135 @type path: string 136 @param path: file or directory to give to $SUDO_USER 137 """ 138 139 if 'SUDO_USER' in os.environ: 140 logging.debug('Changing ownership of %s to %s' % (path, os.environ['SUDO_USER'])) 141 (uid, gid) = pwd.getpwnam(os.environ['SUDO_USER'])[2:4] 142 os.chown(path, uid, gid)
143
144 -def checkroot():
145 """ 146 Check if we're running as root, and bail out if we're not. 147 """ 148 149 if os.geteuid() != 0: 150 raise VMBuilderUserError("This script must be run as root (e.g. via sudo)")
151
152 -def fix_ownership(files):
153 """ 154 Goes through files and fixes their ownership of them. 155 156 @type files: list 157 @param files: files whose ownership should be fixed up (currently 158 simply calls L{give_to_caller}) 159 160 """ 161 for file in files: 162 give_to_caller(file)
163
164 -def render_template(plugin, vm, tmplname, context=None):
165 # Import here to avoid having to build-dep on python-cheetah 166 from Cheetah.Template import Template 167 searchList = [] 168 if context: 169 searchList.append(context) 170 searchList.append(vm) 171 172 tmpldirs = ['VMBuilder/plugins/%s/templates', 173 os.path.expanduser('~/.vmbuilder/%s'), 174 '/etc/vmbuilder/%s'] 175 176 if vm.templates: 177 tmpldirs.insert(0,'%s/%%s' % vm.templates) 178 179 tmpldirs = [dir % plugin for dir in tmpldirs] 180 181 for dir in tmpldirs: 182 tmplfile = '%s/%s.tmpl' % (dir, tmplname) 183 if os.path.exists(tmplfile): 184 t = Template(file=tmplfile, searchList=searchList) 185 output = t.respond() 186 logging.debug('Output from template \'%s\': %s' % (tmplfile, output)) 187 return output 188 189 raise VMBuilderException('Template %s.tmpl not found in any of %s' % (tmplname, ', '.join(tmpldirs)))
190