summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cloudinit/config/cc_landscape.py3
-rw-r--r--cloudinit/config/cc_mounts.py3
-rw-r--r--cloudinit/distros/__init__.py15
-rw-r--r--cloudinit/handlers/__init__.py3
-rw-r--r--cloudinit/handlers/cloud_config.py15
-rw-r--r--cloudinit/helpers.py3
-rw-r--r--cloudinit/mergers/__init__.py13
-rw-r--r--cloudinit/sources/DataSourceAltCloud.py5
-rw-r--r--cloudinit/sources/DataSourceCloudStack.py3
-rw-r--r--cloudinit/sources/DataSourceConfigDrive.py4
-rw-r--r--cloudinit/sources/DataSourceEc2.py3
-rw-r--r--cloudinit/sources/DataSourceMAAS.py3
-rw-r--r--cloudinit/sources/DataSourceNoCloud.py5
-rw-r--r--cloudinit/sources/DataSourceNone.py3
-rw-r--r--cloudinit/sources/DataSourceOVF.py3
-rw-r--r--cloudinit/sources/__init__.py10
-rw-r--r--cloudinit/stages.py9
-rw-r--r--cloudinit/type_utils.py34
-rw-r--r--cloudinit/util.py33
-rw-r--r--tests/unittests/test_userdata.py4
20 files changed, 104 insertions, 70 deletions
diff --git a/cloudinit/config/cc_landscape.py b/cloudinit/config/cc_landscape.py
index 02610dd0..6734efee 100644
--- a/cloudinit/config/cc_landscape.py
+++ b/cloudinit/config/cc_landscape.py
@@ -24,6 +24,7 @@ from StringIO import StringIO
from configobj import ConfigObj
+from cloudinit import type_utils
from cloudinit import util
from cloudinit.settings import PER_INSTANCE
@@ -58,7 +59,7 @@ def handle(_name, cfg, cloud, log, _args):
if not isinstance(ls_cloudcfg, (dict)):
raise RuntimeError(("'landscape' key existed in config,"
" but not a dictionary type,"
- " is a %s instead"), util.obj_name(ls_cloudcfg))
+ " is a %s instead"), type_utils.obj_name(ls_cloudcfg))
if not ls_cloudcfg:
return
diff --git a/cloudinit/config/cc_mounts.py b/cloudinit/config/cc_mounts.py
index cb772c86..6ebe563d 100644
--- a/cloudinit/config/cc_mounts.py
+++ b/cloudinit/config/cc_mounts.py
@@ -22,6 +22,7 @@ from string import whitespace # pylint: disable=W0402
import re
+from cloudinit import type_utils
from cloudinit import util
# Shortname matches 'sda', 'sda1', 'xvda', 'hda', 'sdb', xvdb, vda, vdd1
@@ -60,7 +61,7 @@ def handle(_name, cfg, cloud, log, _args):
# skip something that wasn't a list
if not isinstance(cfgmnt[i], list):
log.warn("Mount option %s not a list, got a %s instead",
- (i + 1), util.obj_name(cfgmnt[i]))
+ (i + 1), type_utils.obj_name(cfgmnt[i]))
continue
startname = str(cfgmnt[i][0])
diff --git a/cloudinit/distros/__init__.py b/cloudinit/distros/__init__.py
index 6a684b89..eeea6af1 100644
--- a/cloudinit/distros/__init__.py
+++ b/cloudinit/distros/__init__.py
@@ -31,6 +31,7 @@ import re
from cloudinit import importer
from cloudinit import log as logging
from cloudinit import ssh_util
+from cloudinit import type_utils
from cloudinit import util
from cloudinit.distros.parsers import hosts
@@ -427,7 +428,7 @@ class Distro(object):
lines.append("%s %s" % (user, rules))
else:
msg = "Can not create sudoers rule addition with type %r"
- raise TypeError(msg % (util.obj_name(rules)))
+ raise TypeError(msg % (type_utils.obj_name(rules)))
content = "\n".join(lines)
content += "\n" # trailing newline
@@ -550,7 +551,7 @@ def _normalize_groups(grp_cfg):
c_grp_cfg[k] = [v]
else:
raise TypeError("Bad group member type %s" %
- util.obj_name(v))
+ type_utils.obj_name(v))
else:
if isinstance(v, (list)):
c_grp_cfg[k].extend(v)
@@ -558,13 +559,13 @@ def _normalize_groups(grp_cfg):
c_grp_cfg[k].append(v)
else:
raise TypeError("Bad group member type %s" %
- util.obj_name(v))
+ type_utils.obj_name(v))
elif isinstance(i, (str, basestring)):
if i not in c_grp_cfg:
c_grp_cfg[i] = []
else:
raise TypeError("Unknown group name type %s" %
- util.obj_name(i))
+ type_utils.obj_name(i))
grp_cfg = c_grp_cfg
groups = {}
if isinstance(grp_cfg, (dict)):
@@ -573,7 +574,7 @@ def _normalize_groups(grp_cfg):
else:
raise TypeError(("Group config must be list, dict "
" or string types only and not %s") %
- util.obj_name(grp_cfg))
+ type_utils.obj_name(grp_cfg))
return groups
@@ -604,7 +605,7 @@ def _normalize_users(u_cfg, def_user_cfg=None):
ad_ucfg.append(v)
else:
raise TypeError(("Unmappable user value type %s"
- " for key %s") % (util.obj_name(v), k))
+ " for key %s") % (type_utils.obj_name(v), k))
u_cfg = ad_ucfg
elif isinstance(u_cfg, (str, basestring)):
u_cfg = util.uniq_merge_sorted(u_cfg)
@@ -629,7 +630,7 @@ def _normalize_users(u_cfg, def_user_cfg=None):
else:
raise TypeError(("User config must be dictionary/list "
" or string types only and not %s") %
- util.obj_name(user_config))
+ type_utils.obj_name(user_config))
# Ensure user options are in the right python friendly format
if users:
diff --git a/cloudinit/handlers/__init__.py b/cloudinit/handlers/__init__.py
index 63fdb948..924463ce 100644
--- a/cloudinit/handlers/__init__.py
+++ b/cloudinit/handlers/__init__.py
@@ -27,6 +27,7 @@ from cloudinit.settings import (PER_ALWAYS, PER_INSTANCE, FREQUENCIES)
from cloudinit import importer
from cloudinit import log as logging
+from cloudinit import type_utils
from cloudinit import util
LOG = logging.getLogger(__name__)
@@ -76,7 +77,7 @@ class Handler(object):
self.frequency = frequency
def __repr__(self):
- return "%s: [%s]" % (util.obj_name(self), self.list_types())
+ return "%s: [%s]" % (type_utils.obj_name(self), self.list_types())
@abc.abstractmethod
def list_types(self):
diff --git a/cloudinit/handlers/cloud_config.py b/cloudinit/handlers/cloud_config.py
index d458dee2..5f519f78 100644
--- a/cloudinit/handlers/cloud_config.py
+++ b/cloudinit/handlers/cloud_config.py
@@ -29,8 +29,8 @@ from cloudinit.settings import (PER_ALWAYS)
LOG = logging.getLogger(__name__)
-DEF_MERGE_TYPE = "list(extend)+dict()+str(append)"
MERGE_HEADER = 'Merge-Type'
+DEF_MERGERS = mergers.default_mergers()
class CloudConfigPartHandler(handlers.Handler):
@@ -39,9 +39,7 @@ class CloudConfigPartHandler(handlers.Handler):
self.cloud_buf = None
self.cloud_fn = paths.get_ipath("cloud_config")
self.file_names = []
- self.mergers = [
- mergers.string_extract_mergers(DEF_MERGE_TYPE),
- ]
+ self.mergers = [DEF_MERGERS]
def list_types(self):
return [
@@ -59,6 +57,7 @@ class CloudConfigPartHandler(handlers.Handler):
file_lines.append("# %s" % (fn))
file_lines.append("")
if self.cloud_buf is not None:
+ # Something was actually gathered....
lines = [
"#cloud-config",
'',
@@ -86,7 +85,7 @@ class CloudConfigPartHandler(handlers.Handler):
all_mergers.extend(mergers_yaml)
all_mergers.extend(mergers_header)
if not all_mergers:
- all_mergers = mergers.string_extract_mergers(DEF_MERGE_TYPE)
+ all_mergers = DEF_MERGERS
return all_mergers
def _merge_part(self, payload, headers):
@@ -94,7 +93,7 @@ class CloudConfigPartHandler(handlers.Handler):
# Use the merger list from the last call, since it is the one
# that will be defining how to merge with the next payload.
curr_mergers = list(self.mergers[-1])
- LOG.debug("Merging with %s", curr_mergers)
+ LOG.debug("Merging by applying %s", curr_mergers)
self.mergers.append(next_mergers)
merger = mergers.construct(curr_mergers)
if self.cloud_buf is None:
@@ -106,9 +105,7 @@ class CloudConfigPartHandler(handlers.Handler):
def _reset(self):
self.file_names = []
self.cloud_buf = None
- self.mergers = [
- mergers.string_extract_mergers(DEF_MERGE_TYPE),
- ]
+ self.mergers = [DEF_MERGERS]
def handle_part(self, _data, ctype, filename, payload, _freq, headers):
if ctype == handlers.CONTENT_START:
diff --git a/cloudinit/helpers.py b/cloudinit/helpers.py
index 2077401c..a4e6fb03 100644
--- a/cloudinit/helpers.py
+++ b/cloudinit/helpers.py
@@ -32,6 +32,7 @@ from cloudinit.settings import (PER_INSTANCE, PER_ALWAYS, PER_ONCE,
CFG_ENV_NAME)
from cloudinit import log as logging
+from cloudinit import type_utils
from cloudinit import util
LOG = logging.getLogger(__name__)
@@ -68,7 +69,7 @@ class FileLock(object):
self.fn = fn
def __str__(self):
- return "<%s using file %r>" % (util.obj_name(self), self.fn)
+ return "<%s using file %r>" % (type_utils.obj_name(self), self.fn)
def canon_sem_name(name):
diff --git a/cloudinit/mergers/__init__.py b/cloudinit/mergers/__init__.py
index 4a112165..453426af 100644
--- a/cloudinit/mergers/__init__.py
+++ b/cloudinit/mergers/__init__.py
@@ -20,11 +20,12 @@ import re
from cloudinit import importer
from cloudinit import log as logging
-from cloudinit import util
+from cloudinit import type_utils
NAME_MTCH = re.compile(r"(^[a-zA-Z_][A-Za-z0-9_]*)\((.*?)\)$")
LOG = logging.getLogger(__name__)
+DEF_MERGE_TYPE = "list(extend)+dict()+str(append)"
class UnknownMerger(object):
@@ -42,7 +43,7 @@ class UnknownMerger(object):
# If not found the merge will be given to a '_handle_unknown'
# function which can decide what to do wit the 2 values.
def merge(self, source, merge_with):
- type_name = util.obj_name(source)
+ type_name = type_utils.obj_name(source)
type_name = type_name.lower()
method_name = "_on_%s" % (type_name)
meth = None
@@ -127,6 +128,10 @@ def string_extract_mergers(merge_how):
return parsed_mergers
+def default_mergers():
+ return tuple(string_extract_mergers(DEF_MERGE_TYPE))
+
+
def construct(parsed_mergers):
mergers_to_be = []
for (m_name, m_ops) in parsed_mergers:
@@ -145,4 +150,6 @@ def construct(parsed_mergers):
root = LookupMerger(mergers)
for (attr, opts) in mergers_to_be:
mergers.append(attr(root, opts))
- return root \ No newline at end of file
+ return root
+
+
diff --git a/cloudinit/sources/DataSourceAltCloud.py b/cloudinit/sources/DataSourceAltCloud.py
index 9812bdcb..64548d43 100644
--- a/cloudinit/sources/DataSourceAltCloud.py
+++ b/cloudinit/sources/DataSourceAltCloud.py
@@ -30,6 +30,7 @@ import os.path
from cloudinit import log as logging
from cloudinit import sources
from cloudinit import util
+
from cloudinit.util import ProcessExecutionError
LOG = logging.getLogger(__name__)
@@ -91,8 +92,8 @@ class DataSourceAltCloud(sources.DataSource):
self.supported_seed_starts = ("/", "file://")
def __str__(self):
- mstr = "%s [seed=%s]" % (util.obj_name(self), self.seed)
- return mstr
+ root = sources.DataSource.__str__(self)
+ return "%s [seed=%s]" % (root, self.seed)
def get_cloud_type(self):
'''
diff --git a/cloudinit/sources/DataSourceCloudStack.py b/cloudinit/sources/DataSourceCloudStack.py
index 076dba5a..c0e1a23c 100644
--- a/cloudinit/sources/DataSourceCloudStack.py
+++ b/cloudinit/sources/DataSourceCloudStack.py
@@ -59,9 +59,6 @@ class DataSourceCloudStack(sources.DataSource):
return gw
return None
- def __str__(self):
- return util.obj_name(self)
-
def _get_url_settings(self):
mcfg = self.ds_cfg
if not mcfg:
diff --git a/cloudinit/sources/DataSourceConfigDrive.py b/cloudinit/sources/DataSourceConfigDrive.py
index c7826851..46abd772 100644
--- a/cloudinit/sources/DataSourceConfigDrive.py
+++ b/cloudinit/sources/DataSourceConfigDrive.py
@@ -51,7 +51,9 @@ class DataSourceConfigDrive(sources.DataSource):
self.ec2_metadata = None
def __str__(self):
- mstr = "%s [%s,ver=%s]" % (util.obj_name(self), self.dsmode,
+ root = sources.DataSource.__str__(self)
+ mstr = "%s [%s,ver=%s]" % (root,
+ self.dsmode,
self.version)
mstr += "[source=%s]" % (self.source)
return mstr
diff --git a/cloudinit/sources/DataSourceEc2.py b/cloudinit/sources/DataSourceEc2.py
index 2db53446..f010e640 100644
--- a/cloudinit/sources/DataSourceEc2.py
+++ b/cloudinit/sources/DataSourceEc2.py
@@ -49,9 +49,6 @@ class DataSourceEc2(sources.DataSource):
self.seed_dir = os.path.join(paths.seed_dir, "ec2")
self.api_ver = DEF_MD_VERSION
- def __str__(self):
- return util.obj_name(self)
-
def get_data(self):
seed_ret = {}
if util.read_optional_seed(seed_ret, base=(self.seed_dir + "/")):
diff --git a/cloudinit/sources/DataSourceMAAS.py b/cloudinit/sources/DataSourceMAAS.py
index b55d8a21..612d8ffa 100644
--- a/cloudinit/sources/DataSourceMAAS.py
+++ b/cloudinit/sources/DataSourceMAAS.py
@@ -50,7 +50,8 @@ class DataSourceMAAS(sources.DataSource):
self.oauth_clockskew = None
def __str__(self):
- return "%s [%s]" % (util.obj_name(self), self.base_url)
+ root = sources.DataSource.__str__(self)
+ return "%s [%s]" % (root, self.base_url)
def get_data(self):
mcfg = self.ds_cfg
diff --git a/cloudinit/sources/DataSourceNoCloud.py b/cloudinit/sources/DataSourceNoCloud.py
index bed500a2..9a770d38 100644
--- a/cloudinit/sources/DataSourceNoCloud.py
+++ b/cloudinit/sources/DataSourceNoCloud.py
@@ -40,9 +40,8 @@ class DataSourceNoCloud(sources.DataSource):
self.supported_seed_starts = ("/", "file://")
def __str__(self):
- mstr = "%s [seed=%s][dsmode=%s]" % (util.obj_name(self),
- self.seed, self.dsmode)
- return mstr
+ root = sources.DataSource.__str__(self)
+ return "%s [seed=%s][dsmode=%s]" % (root, self.seed, self.dsmode)
def get_data(self):
defaults = {
diff --git a/cloudinit/sources/DataSourceNone.py b/cloudinit/sources/DataSourceNone.py
index c2125bee..e2175e1f 100644
--- a/cloudinit/sources/DataSourceNone.py
+++ b/cloudinit/sources/DataSourceNone.py
@@ -41,9 +41,6 @@ class DataSourceNone(sources.DataSource):
def get_instance_id(self):
return 'iid-datasource-none'
- def __str__(self):
- return util.obj_name(self)
-
@property
def is_disconnected(self):
return True
diff --git a/cloudinit/sources/DataSourceOVF.py b/cloudinit/sources/DataSourceOVF.py
index e90150c6..ae139074 100644
--- a/cloudinit/sources/DataSourceOVF.py
+++ b/cloudinit/sources/DataSourceOVF.py
@@ -43,7 +43,8 @@ class DataSourceOVF(sources.DataSource):
self.supported_seed_starts = ("/", "file://")
def __str__(self):
- return "%s [seed=%s]" % (util.obj_name(self), self.seed)
+ root = sources.DataSource.__str__(self)
+ return "%s [seed=%s]" % (root, self.seed)
def get_data(self):
found = []
diff --git a/cloudinit/sources/__init__.py b/cloudinit/sources/__init__.py
index 96baff90..d8fbacdd 100644
--- a/cloudinit/sources/__init__.py
+++ b/cloudinit/sources/__init__.py
@@ -25,6 +25,7 @@ import os
from cloudinit import importer
from cloudinit import log as logging
+from cloudinit import type_utils
from cloudinit import user_data as ud
from cloudinit import util
@@ -52,7 +53,7 @@ class DataSource(object):
self.userdata = None
self.metadata = None
self.userdata_raw = None
- name = util.obj_name(self)
+ name = type_utils.obj_name(self)
if name.startswith(DS_PREFIX):
name = name[len(DS_PREFIX):]
self.ds_cfg = util.get_cfg_by_path(self.sys_cfg,
@@ -62,6 +63,9 @@ class DataSource(object):
else:
self.ud_proc = ud_proc
+ def __str__(self):
+ return type_utils.obj_name(self)
+
def get_userdata(self, apply_filter=False):
if self.userdata is None:
self.userdata = self.ud_proc.process(self.get_userdata_raw())
@@ -214,7 +218,7 @@ def normalize_pubkey_data(pubkey_data):
def find_source(sys_cfg, distro, paths, ds_deps, cfg_list, pkg_list):
ds_list = list_sources(cfg_list, ds_deps, pkg_list)
- ds_names = [util.obj_name(f) for f in ds_list]
+ ds_names = [type_utils.obj_name(f) for f in ds_list]
LOG.debug("Searching for data source in: %s", ds_names)
for cls in ds_list:
@@ -222,7 +226,7 @@ def find_source(sys_cfg, distro, paths, ds_deps, cfg_list, pkg_list):
LOG.debug("Seeing if we can get any data from %s", cls)
s = cls(sys_cfg, distro, paths)
if s.get_data():
- return (s, util.obj_name(cls))
+ return (s, type_utils.obj_name(cls))
except Exception:
util.logexc(LOG, "Getting data from %s failed", cls)
diff --git a/cloudinit/stages.py b/cloudinit/stages.py
index 94a267df..531e7997 100644
--- a/cloudinit/stages.py
+++ b/cloudinit/stages.py
@@ -43,6 +43,7 @@ from cloudinit import helpers
from cloudinit import importer
from cloudinit import log as logging
from cloudinit import sources
+from cloudinit import type_utils
from cloudinit import util
LOG = logging.getLogger(__name__)
@@ -220,7 +221,7 @@ class Init(object):
# Any config provided???
pkg_list = self.cfg.get('datasource_pkg_list') or []
# Add the defaults at the end
- for n in ['', util.obj_name(sources)]:
+ for n in ['', type_utils.obj_name(sources)]:
if n not in pkg_list:
pkg_list.append(n)
cfg_list = self.cfg.get('datasource_list') or []
@@ -280,7 +281,7 @@ class Init(object):
dp = self.paths.get_cpath('data')
# Write what the datasource was and is..
- ds = "%s: %s" % (util.obj_name(self.datasource), self.datasource)
+ ds = "%s: %s" % (type_utils.obj_name(self.datasource), self.datasource)
previous_ds = None
ds_fn = os.path.join(idir, 'datasource')
try:
@@ -497,7 +498,7 @@ class Modules(object):
else:
raise TypeError(("Failed to read '%s' item in config,"
" unknown type %s") %
- (item, util.obj_name(item)))
+ (item, type_utils.obj_name(item)))
return module_list
def _fixup_modules(self, raw_mods):
@@ -515,7 +516,7 @@ class Modules(object):
# Reset it so when ran it will get set to a known value
freq = None
mod_locs = importer.find_module(mod_name,
- ['', util.obj_name(config)],
+ ['', type_utils.obj_name(config)],
['handle'])
if not mod_locs:
LOG.warn("Could not find module named %s", mod_name)
diff --git a/cloudinit/type_utils.py b/cloudinit/type_utils.py
new file mode 100644
index 00000000..2decbfc5
--- /dev/null
+++ b/cloudinit/type_utils.py
@@ -0,0 +1,34 @@
+# vi: ts=4 expandtab
+#
+# Copyright (C) 2012 Canonical Ltd.
+# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
+# Copyright (C) 2012 Yahoo! Inc.
+#
+# Author: Scott Moser <scott.moser@canonical.com>
+# Author: Juerg Haefliger <juerg.haefliger@hp.com>
+# Author: Joshua Harlow <harlowja@yahoo-inc.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 3, as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# pylint: disable=C0302
+
+import types
+
+
+def obj_name(obj):
+ if isinstance(obj, (types.TypeType,
+ types.ModuleType,
+ types.FunctionType,
+ types.LambdaType)):
+ return str(obj.__name__)
+ return obj_name(obj.__class__)
diff --git a/cloudinit/util.py b/cloudinit/util.py
index ab918433..73bf6304 100644
--- a/cloudinit/util.py
+++ b/cloudinit/util.py
@@ -43,14 +43,15 @@ import subprocess
import sys
import tempfile
import time
-import types
import urlparse
import yaml
from cloudinit import importer
from cloudinit import log as logging
+from cloudinit import mergers
from cloudinit import safeyaml
+from cloudinit import type_utils
from cloudinit import url_helper as uhelp
from cloudinit import version
@@ -194,11 +195,12 @@ def fork_cb(child_cb, *args):
os._exit(0) # pylint: disable=W0212
except:
logexc(LOG, ("Failed forking and"
- " calling callback %s"), obj_name(child_cb))
+ " calling callback %s"),
+ type_utils.obj_name(child_cb))
os._exit(1) # pylint: disable=W0212
else:
LOG.debug("Forked child %s who will run callback %s",
- fid, obj_name(child_cb))
+ fid, type_utils.obj_name(child_cb))
def is_true(val, addons=None):
@@ -513,15 +515,6 @@ def make_url(scheme, host, port=None,
return urlparse.urlunparse(pieces)
-def obj_name(obj):
- if isinstance(obj, (types.TypeType,
- types.ModuleType,
- types.FunctionType,
- types.LambdaType)):
- return str(obj.__name__)
- return obj_name(obj.__class__)
-
-
def mergemanydict(srcs, reverse=False):
if reverse:
srcs = reversed(srcs)
@@ -538,13 +531,9 @@ def mergedict(src, cand):
If C{src} has a key C{cand} will not override.
Nested dictionaries are merged recursively.
"""
- if isinstance(src, dict) and isinstance(cand, dict):
- for (k, v) in cand.iteritems():
- if k not in src:
- src[k] = v
- else:
- src[k] = mergedict(src[k], v)
- return src
+ raw_mergers = mergers.default_mergers()
+ merger = mergers.construct(raw_mergers)
+ return merger.merge(src, cand)
@contextlib.contextmanager
@@ -645,7 +634,7 @@ def load_yaml(blob, default=None, allowed=(dict,)):
# Yes this will just be caught, but thats ok for now...
raise TypeError(("Yaml load allows %s root types,"
" but got %s instead") %
- (allowed, obj_name(converted)))
+ (allowed, type_utils.obj_name(converted)))
loaded = converted
except (yaml.YAMLError, TypeError, ValueError):
if len(blob) == 0:
@@ -714,7 +703,7 @@ def read_conf_with_confd(cfgfile):
if not isinstance(confd, (str, basestring)):
raise TypeError(("Config file %s contains 'conf_d' "
"with non-string type %s") %
- (cfgfile, obj_name(confd)))
+ (cfgfile, type_utils.obj_name(confd)))
else:
confd = str(confd).strip()
elif os.path.isdir("%s.d" % cfgfile):
@@ -1472,7 +1461,7 @@ def shellify(cmdlist, add_header=True):
else:
raise RuntimeError(("Unable to shellify type %s"
" which is not a list or string")
- % (obj_name(args)))
+ % (type_utils.obj_name(args)))
LOG.debug("Shellified %s commands.", cmds_made)
return content
diff --git a/tests/unittests/test_userdata.py b/tests/unittests/test_userdata.py
index 9e1fed7e..ef0dd7b8 100644
--- a/tests/unittests/test_userdata.py
+++ b/tests/unittests/test_userdata.py
@@ -74,7 +74,7 @@ run:
- morestuff
'''
message2 = MIMEBase("text", "cloud-config")
- message2['Merge-Type'] = 'dict()+list(extend)+str()'
+ message2['X-Merge-Type'] = 'dict()+list(extend)+str()'
message2.set_payload(blob2)
blob3 = '''
@@ -83,6 +83,7 @@ e:
- 1
- 2
- 3
+p: 1
'''
message3 = MIMEBase("text", "cloud-config")
message3['Merge-Type'] = 'dict()+list()+str()'
@@ -109,6 +110,7 @@ e:
self.assertEquals(contents['run'], ['b', 'c', 'stuff', 'morestuff'])
self.assertEquals(contents['a'], 'be')
self.assertEquals(contents['e'], 'fg')
+ self.assertEquals(contents['p'], 1)
def test_unhandled_type_warning(self):
"""Raw text without magic is ignored but shows warning."""