summaryrefslogtreecommitdiff
path: root/cloudinit/util.py
diff options
context:
space:
mode:
Diffstat (limited to 'cloudinit/util.py')
-rw-r--r--cloudinit/util.py99
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