summaryrefslogtreecommitdiff
path: root/cloudinit/util.py
diff options
context:
space:
mode:
Diffstat (limited to 'cloudinit/util.py')
-rw-r--r--cloudinit/util.py216
1 files changed, 74 insertions, 142 deletions
diff --git a/cloudinit/util.py b/cloudinit/util.py
index cf9e349f..769f3425 100644
--- a/cloudinit/util.py
+++ b/cloudinit/util.py
@@ -62,12 +62,6 @@ TRUE_STRINGS = ('true', '1', 'on', 'yes')
FALSE_STRINGS = ('off', '0', 'no', 'false')
-# Helper utils to see if running in a container
-CONTAINER_TESTS = (['systemd-detect-virt', '--quiet', '--container'],
- ['running-in-container'],
- ['lxc-is-container'])
-
-
def kernel_version():
return tuple(map(int, os.uname().release.split('.')[:2]))
@@ -159,32 +153,6 @@ def fully_decoded_payload(part):
return cte_payload
-# Path for DMI Data
-DMI_SYS_PATH = "/sys/class/dmi/id"
-
-# dmidecode and /sys/class/dmi/id/* use different names for the same value,
-# this allows us to refer to them by one canonical name
-DMIDECODE_TO_DMI_SYS_MAPPING = {
- 'baseboard-asset-tag': 'board_asset_tag',
- 'baseboard-manufacturer': 'board_vendor',
- 'baseboard-product-name': 'board_name',
- 'baseboard-serial-number': 'board_serial',
- 'baseboard-version': 'board_version',
- 'bios-release-date': 'bios_date',
- 'bios-vendor': 'bios_vendor',
- 'bios-version': 'bios_version',
- 'chassis-asset-tag': 'chassis_asset_tag',
- 'chassis-manufacturer': 'chassis_vendor',
- 'chassis-serial-number': 'chassis_serial',
- 'chassis-version': 'chassis_version',
- 'system-manufacturer': 'sys_vendor',
- 'system-product-name': 'product_name',
- 'system-serial-number': 'product_serial',
- 'system-uuid': 'product_uuid',
- 'system-version': 'product_version',
-}
-
-
class SeLinuxGuard(object):
def __init__(self, path, recursive=False):
# Late import since it might not always
@@ -418,6 +386,11 @@ def multi_log(text, console=True, stderr=True,
@lru_cache()
+def is_Linux():
+ return 'Linux' in platform.system()
+
+
+@lru_cache()
def is_BSD():
return 'BSD' in platform.system()
@@ -761,8 +734,9 @@ def del_dir(path):
# 'meta-data' entries
def read_optional_seed(fill, base="", ext="", timeout=5):
try:
- (md, ud) = read_seeded(base, ext, timeout)
+ (md, ud, vd) = read_seeded(base, ext, timeout)
fill['user-data'] = ud
+ fill['vendor-data'] = vd
fill['meta-data'] = md
return True
except url_helper.UrlError as e:
@@ -840,9 +814,11 @@ def load_yaml(blob, default=None, allowed=(dict,)):
def read_seeded(base="", ext="", timeout=5, retries=10, file_retries=0):
if base.find("%s") >= 0:
ud_url = base % ("user-data" + ext)
+ vd_url = base % ("vendor-data" + ext)
md_url = base % ("meta-data" + ext)
else:
ud_url = "%s%s%s" % (base, "user-data", ext)
+ vd_url = "%s%s%s" % (base, "vendor-data", ext)
md_url = "%s%s%s" % (base, "meta-data", ext)
md_resp = url_helper.read_file_or_url(md_url, timeout=timeout,
@@ -857,7 +833,19 @@ def read_seeded(base="", ext="", timeout=5, retries=10, file_retries=0):
if ud_resp.ok():
ud = ud_resp.contents
- return (md, ud)
+ vd = None
+ try:
+ vd_resp = url_helper.read_file_or_url(vd_url, timeout=timeout,
+ retries=retries)
+ except url_helper.UrlError as e:
+ LOG.debug("Error in vendor-data response: %s", e)
+ else:
+ if vd_resp.ok():
+ vd = vd_resp.contents
+ else:
+ LOG.debug("Error in vendor-data response")
+
+ return (md, ud, vd)
def read_conf_d(confd):
@@ -1646,16 +1634,17 @@ def mount_cb(device, callback, data=None, mtype=None,
_type=type(mtype)))
# clean up 'mtype' input a bit based on platform.
- platsys = platform.system().lower()
- if platsys == "linux":
+ if is_Linux():
if mtypes is None:
mtypes = ["auto"]
- elif platsys.endswith("bsd"):
+ elif is_BSD():
if mtypes is None:
- mtypes = ['ufs', 'cd9660', 'vfat']
+ mtypes = ['ufs', 'cd9660', 'msdos']
for index, mtype in enumerate(mtypes):
if mtype == "iso9660":
mtypes[index] = "cd9660"
+ if mtype in ["vfat", "msdosfs"]:
+ mtypes[index] = "msdos"
else:
# we cannot do a smart "auto", so just call 'mount' once with no -t
mtypes = ['']
@@ -1789,8 +1778,12 @@ def append_file(path, content):
write_file(path, content, omode="ab", mode=None)
-def ensure_file(path, mode=0o644):
- write_file(path, content='', omode="ab", mode=mode)
+def ensure_file(
+ path, mode: int = 0o644, *, preserve_mode: bool = False
+) -> None:
+ write_file(
+ path, content='', omode="ab", mode=mode, preserve_mode=preserve_mode
+ )
def safe_int(possible_int):
@@ -1929,19 +1922,52 @@ def strip_prefix_suffix(line, prefix=None, suffix=None):
return line
+def _cmd_exits_zero(cmd):
+ if subp.which(cmd[0]) is None:
+ return False
+ try:
+ subp.subp(cmd)
+ except subp.ProcessExecutionError:
+ return False
+ return True
+
+
+def _is_container_systemd():
+ return _cmd_exits_zero(["systemd-detect-virt", "--quiet", "--container"])
+
+
+def _is_container_upstart():
+ return _cmd_exits_zero(["running-in-container"])
+
+
+def _is_container_old_lxc():
+ return _cmd_exits_zero(["lxc-is-container"])
+
+
+def _is_container_freebsd():
+ if not is_FreeBSD():
+ return False
+ cmd = ["sysctl", "-qn", "security.jail.jailed"]
+ if subp.which(cmd[0]) is None:
+ return False
+ out, _ = subp.subp(cmd)
+ return out.strip() == "1"
+
+
+@lru_cache()
def is_container():
"""
Checks to see if this code running in a container of some sort
"""
-
- for helper in CONTAINER_TESTS:
- try:
- # try to run a helper program. if it returns true/zero
- # then we're inside a container. otherwise, no
- subp.subp(helper)
+ checks = (
+ _is_container_systemd,
+ _is_container_freebsd,
+ _is_container_upstart,
+ _is_container_old_lxc)
+
+ for helper in checks:
+ if helper():
return True
- except (IOError, OSError):
- pass
# this code is largely from the logic in
# ubuntu's /etc/init/container-detect.conf
@@ -2396,57 +2422,6 @@ def human2bytes(size):
return int(num * mpliers[mplier])
-def _read_dmi_syspath(key):
- """
- Reads dmi data with from /sys/class/dmi/id
- """
- if key not in DMIDECODE_TO_DMI_SYS_MAPPING:
- return None
- mapped_key = DMIDECODE_TO_DMI_SYS_MAPPING[key]
- dmi_key_path = "{0}/{1}".format(DMI_SYS_PATH, mapped_key)
- LOG.debug("querying dmi data %s", dmi_key_path)
- try:
- if not os.path.exists(dmi_key_path):
- LOG.debug("did not find %s", dmi_key_path)
- return None
-
- key_data = load_file(dmi_key_path, decode=False)
- if not key_data:
- LOG.debug("%s did not return any data", dmi_key_path)
- return None
-
- # uninitialized dmi values show as all \xff and /sys appends a '\n'.
- # in that event, return a string of '.' in the same length.
- if key_data == b'\xff' * (len(key_data) - 1) + b'\n':
- key_data = b""
-
- str_data = key_data.decode('utf8').strip()
- LOG.debug("dmi data %s returned %s", dmi_key_path, str_data)
- return str_data
-
- except Exception:
- logexc(LOG, "failed read of %s", dmi_key_path)
- return None
-
-
-def _call_dmidecode(key, dmidecode_path):
- """
- Calls out to dmidecode to get the data out. This is mostly for supporting
- OS's without /sys/class/dmi/id support.
- """
- try:
- cmd = [dmidecode_path, "--string", key]
- (result, _err) = subp.subp(cmd)
- result = result.strip()
- LOG.debug("dmidecode returned '%s' for '%s'", result, key)
- if result.replace(".", "") == "":
- return ""
- return result
- except (IOError, OSError) as e:
- LOG.debug('failed dmidecode cmd: %s\n%s', cmd, e)
- return None
-
-
def is_x86(uname_arch=None):
"""Return True if platform is x86-based"""
if uname_arch is None:
@@ -2457,49 +2432,6 @@ def is_x86(uname_arch=None):
return x86_arch_match
-def read_dmi_data(key):
- """
- Wrapper for reading DMI data.
-
- If running in a container return None. This is because DMI data is
- assumed to be not useful in a container as it does not represent the
- container but rather the host.
-
- This will do the following (returning the first that produces a
- result):
- 1) Use a mapping to translate `key` from dmidecode naming to
- sysfs naming and look in /sys/class/dmi/... for a value.
- 2) Use `key` as a sysfs key directly and look in /sys/class/dmi/...
- 3) Fall-back to passing `key` to `dmidecode --string`.
-
- If all of the above fail to find a value, None will be returned.
- """
-
- if is_container():
- return None
-
- syspath_value = _read_dmi_syspath(key)
- if syspath_value is not None:
- return syspath_value
-
- # running dmidecode can be problematic on some arches (LP: #1243287)
- uname_arch = os.uname()[4]
- if not (is_x86(uname_arch) or
- uname_arch == 'aarch64' or
- uname_arch == 'amd64'):
- LOG.debug("dmidata is not supported on %s", uname_arch)
- return None
-
- print("hi, now its: %s\n", subp)
- dmidecode_path = subp.which('dmidecode')
- if dmidecode_path:
- return _call_dmidecode(key, dmidecode_path)
-
- LOG.warning("did not find either path %s or dmidecode command",
- DMI_SYS_PATH)
- return None
-
-
def message_from_string(string):
if sys.version_info[:2] < (2, 7):
return email.message_from_file(io.StringIO(string))