diff options
Diffstat (limited to 'cloudinit/util.py')
-rw-r--r-- | cloudinit/util.py | 99 |
1 files changed, 67 insertions, 32 deletions
diff --git a/cloudinit/util.py b/cloudinit/util.py index 7df773ce..d8d735cc 100644 --- a/cloudinit/util.py +++ b/cloudinit/util.py @@ -37,6 +37,7 @@ try: except ImportError: HAVE_LIBSELINUX = False + def read_conf(fname): try: stream = open(fname, "r") @@ -45,12 +46,13 @@ def read_conf(fname): return conf except IOError as e: if e.errno == errno.ENOENT: - return { } + return {} raise + def get_base_cfg(cfgfile, cfg_builtin="", parsed_cfgs=None): - kerncfg = { } - syscfg = { } + kerncfg = {} + syscfg = {} if parsed_cfgs and cfgfile in parsed_cfgs: return(parsed_cfgs[cfgfile]) @@ -73,23 +75,26 @@ def get_base_cfg(cfgfile, cfg_builtin="", parsed_cfgs=None): parsed_cfgs[cfgfile] = fin return(fin) + def get_cfg_option_bool(yobj, key, default=False): - if not yobj.has_key(key): + if key not in yobj: return default val = yobj[key] if val is True: return True - if str(val).lower() in [ 'true', '1', 'on', 'yes']: + if str(val).lower() in ['true', '1', 'on', 'yes']: return True return False + def get_cfg_option_str(yobj, key, default=None): - if not yobj.has_key(key): + if key not in yobj: return default return yobj[key] + def get_cfg_option_list_or_str(yobj, key, default=None): - if not yobj.has_key(key): + if key not in yobj: return default if yobj[key] is None: return [] @@ -97,6 +102,7 @@ def get_cfg_option_list_or_str(yobj, key, default=None): return yobj[key] return([yobj[key]]) + # get a cfg entry by its path array # for f['a']['b']: get_cfg_by_path(mycfg,('a','b')) def get_cfg_by_path(yobj, keyp, default=None): @@ -107,6 +113,7 @@ def get_cfg_by_path(yobj, keyp, default=None): cur = cur[tok] return(cur) + # merge values from cand into source # if src has a key, cand will not override def mergedict(src, cand): @@ -118,6 +125,7 @@ def mergedict(src, cand): src[k] = mergedict(src[k], v) return src + def write_file(filename, content, mode=0644, omode="wb"): try: os.makedirs(os.path.dirname(filename)) @@ -132,10 +140,12 @@ def write_file(filename, content, mode=0644, omode="wb"): f.close() restorecon_if_possible(filename) + def restorecon_if_possible(path, recursive=False): if HAVE_LIBSELINUX and selinux.is_selinux_enabled(): selinux.restorecon(path, recursive=recursive) + # get keyid from keyserver def getkeybyid(keyid, keyserver): shcmd = """ @@ -153,21 +163,23 @@ def getkeybyid(keyid, keyserver): args = ['sh', '-c', shcmd, "export-gpg-keyid", keyid, keyserver] return(subp(args)[0]) + def runparts(dirp, skip_no_exist=True): if skip_no_exist and not os.path.isdir(dirp): return - + # per bug 857926, Fedora's run-parts will exit failure on empty dir if os.path.isdir(dirp) and os.listdir(dirp) == []: return - cmd = [ 'run-parts', '--regex', '.*', dirp ] + cmd = ['run-parts', '--regex', '.*', dirp] sp = subprocess.Popen(cmd) sp.communicate() if sp.returncode is not 0: raise subprocess.CalledProcessError(sp.returncode, cmd) return + def subp(args, input_=None): sp = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) @@ -176,6 +188,7 @@ def subp(args, input_=None): raise subprocess.CalledProcessError(sp.returncode, args, (out, err)) return(out, err) + def render_to_file(template, outfile, searchList): t = Template(file='/etc/cloud/templates/%s.tmpl' % template, searchList=[searchList]) @@ -183,6 +196,7 @@ def render_to_file(template, outfile, searchList): f.write(t.respond()) f.close() + def render_string(template, searchList): return(Template(template, searchList=[searchList]).respond()) @@ -201,7 +215,7 @@ def read_optional_seed(fill, base="", ext="", timeout=5): if e.errno == errno.ENOENT: return False raise - + # raise OSError with enoent if not found def read_seeded(base="", ext="", timeout=5, retries=10, file_retries=0): @@ -219,20 +233,22 @@ def read_seeded(base="", ext="", timeout=5, retries=10, file_retries=0): ud_url = "%s%s%s" % (base, "user-data", ext) md_url = "%s%s%s" % (base, "meta-data", ext) - raise_err = None - for attempt in range(0, retries+1): + no_exc = object() + raise_err = no_exc + for attempt in range(0, retries + 1): try: md_str = readurl(md_url, timeout=timeout) ud = readurl(ud_url, timeout=timeout) md = yaml.load(md_str) - + return(md, ud) except urllib2.HTTPError as e: raise_err = e except urllib2.URLError as e: raise_err = e - if isinstance(e.reason, OSError) and e.reason.errno == errno.ENOENT: - raise_err = e.reason + if (isinstance(e.reason, OSError) and + e.reason.errno == errno.ENOENT): + raise_err = e.reason if attempt == retries: break @@ -242,13 +258,16 @@ def read_seeded(base="", ext="", timeout=5, retries=10, file_retries=0): raise(raise_err) + def logexc(log, lvl=logging.DEBUG): log.log(lvl, traceback.format_exc()) + class RecursiveInclude(Exception): pass -def read_file_with_includes(fname, rel = ".", stack=None, patt = None): + +def read_file_with_includes(fname, rel=".", stack=None, patt=None): if stack is None: stack = [] if not fname.startswith("/"): @@ -293,27 +312,29 @@ def read_file_with_includes(fname, rel = ".", stack=None, patt = None): inc_contents = "" else: raise - contents = contents[0:loc] + inc_contents + contents[endl+1:] + contents = contents[0:loc] + inc_contents + contents[endl + 1:] cur = loc + len(inc_contents) stack.pop() return(contents) + def read_conf_d(confd): # get reverse sorted list (later trumps newer) confs = sorted(os.listdir(confd), reverse=True) - + # remove anything not ending in '.cfg' confs = [f for f in confs if f.endswith(".cfg")] # remove anything not a file confs = [f for f in confs if os.path.isfile("%s/%s" % (confd, f))] - cfg = { } + cfg = {} for conf in confs: cfg = mergedict(cfg, read_conf("%s/%s" % (confd, conf))) return(cfg) + def read_conf_with_confd(cfgfile): cfg = read_conf(cfgfile) confd = False @@ -345,7 +366,8 @@ def get_cmdline(): except: cmdline = "" return(cmdline) - + + def read_cc_from_cmdline(cmdline=None): # this should support reading cloud-config information from # the kernel command line. It is intended to support content of the @@ -363,18 +385,20 @@ def read_cc_from_cmdline(cmdline=None): begin_l = len(tag_begin) end_l = len(tag_end) clen = len(cmdline) - tokens = [ ] + tokens = [] begin = cmdline.find(tag_begin) while begin >= 0: end = cmdline.find(tag_end, begin + begin_l) if end < 0: end = clen - tokens.append(cmdline[begin+begin_l:end].lstrip().replace("\\n", "\n")) - + tokens.append(cmdline[begin + begin_l:end].lstrip().replace("\\n", + "\n")) + begin = cmdline.find(tag_begin, end + end_l) return('\n'.join(tokens)) + def ensure_dirs(dirlist, mode=0755): fixmodes = [] for d in dirlist: @@ -392,6 +416,7 @@ def ensure_dirs(dirlist, mode=0755): for d in fixmodes: os.chmod(d, mode) + def chownbyname(fname, user=None, group=None): uid = -1 gid = -1 @@ -406,8 +431,9 @@ def chownbyname(fname, user=None, group=None): os.chown(fname, uid, gid) + def readurl(url, data=None, timeout=None): - openargs = { } + openargs = {} if timeout != None: openargs['timeout'] = timeout @@ -420,37 +446,40 @@ def readurl(url, data=None, timeout=None): response = urllib2.urlopen(req, **openargs) return(response.read()) + # shellify, takes a list of commands # for each entry in the list # if it is an array, shell protect it (with single ticks) # if it is a string, do nothing def shellify(cmdlist): content = "#!/bin/sh\n" - escaped = "%s%s%s%s" % ( "'", '\\', "'", "'" ) + escaped = "%s%s%s%s" % ("'", '\\', "'", "'") for args in cmdlist: # if the item is a list, wrap all items in single tick # if its not, then just write it directly if isinstance(args, list): - fixed = [ ] + fixed = [] for f in args: fixed.append("'%s'" % str(f).replace("'", escaped)) - content = "%s%s\n" % ( content, ' '.join(fixed) ) + content = "%s%s\n" % (content, ' '.join(fixed)) else: - content = "%s%s\n" % ( content, str(args) ) + content = "%s%s\n" % (content, str(args)) return content + def dos2unix(string): # find first end of line pos = string.find('\n') - if pos <= 0 or string[pos-1] != '\r': + if pos <= 0 or string[pos - 1] != '\r': return(string) return(string.replace('\r\n', '\n')) + def islxc(): # is this host running lxc? try: with open("/proc/1/cgroup") as f: - if f.read() == "/": + if f.read() == "/": return True except IOError as e: if e.errno != errno.ENOENT: @@ -469,6 +498,7 @@ def islxc(): return False + def get_hostname_fqdn(cfg, cloud): # return the hostname and fqdn from 'cfg'. If not found in cfg, # then fall back to data from cloud @@ -483,7 +513,7 @@ def get_hostname_fqdn(cfg, cloud): fqdn = cfg['hostname'] hostname = cfg['hostname'][:fqdn.find('.')] else: - # no fqdn set, get fqdn from cloud. + # no fqdn set, get fqdn from cloud. # get hostname from cfg if available otherwise cloud fqdn = cloud.get_hostname(fqdn=True) if "hostname" in cfg: @@ -492,9 +522,10 @@ def get_hostname_fqdn(cfg, cloud): hostname = cloud.get_hostname() return(hostname, fqdn) + def get_fqdn_from_hosts(hostname, filename="/etc/hosts"): # this parses /etc/hosts to get a fqdn. It should return the same - # result as 'hostname -f <hostname>' if /etc/hosts.conf + # result as 'hostname -f <hostname>' if /etc/hosts.conf # did not have did not have 'bind' in the order attribute fqdn = None try: @@ -520,6 +551,7 @@ def get_fqdn_from_hosts(hostname, filename="/etc/hosts"): return fqdn + def is_resolvable(name): """ determine if a url is resolvable, return a boolean """ try: @@ -528,10 +560,12 @@ def is_resolvable(name): except socket.gaierror: return False + def is_resolvable_url(url): """ determine if this url is resolvable (existing or ip) """ return(is_resolvable(urlparse.urlparse(url).hostname)) + def search_for_mirror(candidates): """ Search through a list of mirror urls for one that works """ for cand in candidates: @@ -543,6 +577,7 @@ def search_for_mirror(candidates): return None + def close_stdin(): """ reopen stdin as /dev/null so even subprocesses or other os level things get |