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

Source Code for Module VMBuilder.util

  1  # 
  2  #    Uncomplicated VM Builder 
  3  #    Copyright (C) 2007-2009 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 version 3, as 
  9  #    published by the Free Software Foundation. 
 10  # 
 11  #    This program is distributed in the hope that it will be useful, 
 12  #    but WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 14  #    GNU General Public License for more details. 
 15  # 
 16  #    You should have received a copy of the GNU General Public License 
 17  #    along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 18  # 
 19  #    Various utility functions 
 20  import errno 
 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', 'r') 102 proc_env = dict(os.environ) 103 proc_env['LANG'] = 'C' 104 proc_env['LC_ALL'] = 'C' 105 proc_env.update(env) 106 107 try: 108 proc = subprocess.Popen(args, stdin=stdin_arg, stderr=subprocess.PIPE, stdout=subprocess.PIPE, env=proc_env) 109 except OSError, error: 110 if error.errno == errno.ENOENT: 111 raise VMBuilderUserError, "Couldn't find the program '%s' on your system" % (argv[0]) 112 else: 113 raise VMBuilderUserError, "Couldn't launch the program '%s': %s" % (argv[0], error) 114 115 if stdin: 116 proc.stdin.write(stdin) 117 proc.stdin.close() 118 119 mystdout = NonBufferedFile(proc.stdout) 120 mystderr = NonBufferedFile(proc.stderr) 121 122 while not (mystdout.closed and mystderr.closed): 123 # Block until either of them has something to offer 124 select.select([x.file for x in [mystdout, mystderr] if not x.closed], [], []) 125 for buf in mystderr: 126 stderr += buf 127 (ignore_fail and logging.debug or logging.info)(buf.rstrip()) 128 129 for buf in mystdout: 130 logging.debug(buf.rstrip()) 131 stdout += buf 132 133 status = proc.wait() 134 if not ignore_fail and status != 0: 135 raise VMBuilderException, "Process (%s) returned %d. stdout: %s, stderr: %s" % (args.__repr__(), status, stdout, stderr) 136 return stdout
137
138 -def give_to_caller(path):
139 """ 140 Change ownership of file to $SUDO_USER. 141 142 @type path: string 143 @param path: file or directory to give to $SUDO_USER 144 """ 145 146 if 'SUDO_USER' in os.environ: 147 logging.debug('Changing ownership of %s to %s' % (path, os.environ['SUDO_USER'])) 148 (uid, gid) = pwd.getpwnam(os.environ['SUDO_USER'])[2:4] 149 os.chown(path, uid, gid)
150
151 -def checkroot():
152 """ 153 Check if we're running as root, and bail out if we're not. 154 """ 155 156 if os.geteuid() != 0: 157 raise VMBuilderUserError("This script must be run as root (e.g. via sudo)")
158
159 -def fix_ownership(files):
160 """ 161 Goes through files and fixes their ownership of them. 162 163 @type files: list 164 @param files: files whose ownership should be fixed up (currently 165 simply calls L{give_to_caller}) 166 167 """ 168 for file in files: 169 give_to_caller(file)
170
171 -def render_template(plugin, vm, tmplname, context=None):
172 # Import here to avoid having to build-dep on python-cheetah 173 from Cheetah.Template import Template 174 searchList = [] 175 if context: 176 searchList.append(context) 177 searchList.append(vm) 178 179 tmpldirs = [os.path.expanduser('~/.vmbuilder/%s'), 180 os.path.dirname(__file__) + '/plugins/%s/templates', 181 '/etc/vmbuilder/%s'] 182 183 if vm.templates: 184 tmpldirs.insert(0,'%s/%%s' % vm.templates) 185 186 tmpldirs = [dir % plugin for dir in tmpldirs] 187 188 for dir in tmpldirs: 189 tmplfile = '%s/%s.tmpl' % (dir, tmplname) 190 if os.path.exists(tmplfile): 191 t = Template(file=tmplfile, searchList=searchList) 192 output = t.respond() 193 logging.debug('Output from template \'%s\': %s' % (tmplfile, output)) 194 return output 195 196 raise VMBuilderException('Template %s.tmpl not found in any of %s' % (tmplname, ', '.join(tmpldirs)))
197