From 16fd813d8543dd629346e81c4043411c32b7d9d1 Mon Sep 17 00:00:00 2001 From: Jeff Bauer Date: Sat, 11 Feb 2012 09:27:14 -0600 Subject: add support for salt minions --- cloudinit/CloudConfig/cc_salt_minion.py | 55 +++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 cloudinit/CloudConfig/cc_salt_minion.py (limited to 'cloudinit/CloudConfig') diff --git a/cloudinit/CloudConfig/cc_salt_minion.py b/cloudinit/CloudConfig/cc_salt_minion.py new file mode 100644 index 00000000..9a710e72 --- /dev/null +++ b/cloudinit/CloudConfig/cc_salt_minion.py @@ -0,0 +1,55 @@ +# vi: ts=4 expandtab +# +# Author: Jeff Bauer +# +# 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 . + +import os +import os.path +import subprocess +import cloudinit.CloudConfig as cc +import yaml + +def handle(_name, cfg, cloud, log, _args): + # If there isn't a salt key in the configuration don't do anything + if 'salt_minion' not in cfg: + return + salt_cfg = cfg['salt_minion'] + # Start by installing the salt package ... + cc.install_packages(("salt",)) + config_dir = '/etc/salt' + if not os.path.isdir(config_dir): + os.makedirs(config_dir) + # ... and then update the salt configuration + if 'conf' in salt_cfg: + # Add all sections from the conf object to /etc/salt/minion + minion_config = os.path.join(config_dir, 'minion') + yaml.dump(salt_cfg['conf'], + file(minion_config, 'w'), + default_flow_style=False) + # ... copy the key pair if specified + if 'public_key' in salt_cfg and 'private_key' in salt_cfg: + pki_dir = '/etc/salt/pki' + cumask = os.umask(077) + if not os.path.isdir(pki_dir): + os.makedirs(pki_dir) + pub_name = os.path.join(pki_dir, 'minion.pub') + pem_name = os.path.join(pki_dir, 'minion.pem') + with open(pub_name, 'w') as f: + f.write(salt_cfg['public_key']) + with open(pem_name, 'w') as f: + f.write(salt_cfg['private_key']) + os.umask(cumask) + + # Start salt-minion + subprocess.check_call(['service', 'salt-minion', 'start']) -- cgit v1.2.3 From fcefeb469261bf19ffa249ceddf1ca003e520e5d Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Wed, 15 Feb 2012 13:49:41 -0500 Subject: fix update-etc-hosts, 'manage_etc_hosts' is not a boolean, but a string --- cloudinit/CloudConfig/cc_update_etc_hosts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cloudinit/CloudConfig') diff --git a/cloudinit/CloudConfig/cc_update_etc_hosts.py b/cloudinit/CloudConfig/cc_update_etc_hosts.py index 572e6750..6ad2fca8 100644 --- a/cloudinit/CloudConfig/cc_update_etc_hosts.py +++ b/cloudinit/CloudConfig/cc_update_etc_hosts.py @@ -28,7 +28,7 @@ frequency = per_always def handle(_name, cfg, cloud, log, _args): (hostname, fqdn) = util.get_hostname_fqdn(cfg, cloud) - manage_hosts = util.get_cfg_option_bool(cfg, "manage_etc_hosts", False) + manage_hosts = util.get_cfg_option_str(cfg, "manage_etc_hosts", False) if manage_hosts in ("True", "true", True, "template"): # render from template file try: -- cgit v1.2.3 From fb43a1cc3d40b540411f9565e848d32598cf4b3f Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 17 Feb 2012 10:04:49 -0500 Subject: fix pylint warnings --- cloudinit/CloudConfig/cc_salt_minion.py | 3 ++- cloudinit/util.py | 21 +++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) (limited to 'cloudinit/CloudConfig') diff --git a/cloudinit/CloudConfig/cc_salt_minion.py b/cloudinit/CloudConfig/cc_salt_minion.py index 9a710e72..1a3b5039 100644 --- a/cloudinit/CloudConfig/cc_salt_minion.py +++ b/cloudinit/CloudConfig/cc_salt_minion.py @@ -20,7 +20,8 @@ import subprocess import cloudinit.CloudConfig as cc import yaml -def handle(_name, cfg, cloud, log, _args): + +def handle(_name, cfg, _cloud, _log, _args): # If there isn't a salt key in the configuration don't do anything if 'salt_minion' not in cfg: return diff --git a/cloudinit/util.py b/cloudinit/util.py index 0a691dcf..780578e2 100644 --- a/cloudinit/util.py +++ b/cloudinit/util.py @@ -632,6 +632,7 @@ def close_stdin(): with open(os.devnull) as fp: os.dup2(fp.fileno(), sys.stdin.fileno()) + def find_devs_with(criteria): """ find devices matching given criteria (via blkid) @@ -641,15 +642,16 @@ def find_devs_with(criteria): UUID= """ try: - (out,err) = subp(['blkid','-t%s' % criteria,'-odevice']) - except subprocess.CalledProcessError as exc: + (out, _err) = subp(['blkid', '-t%s' % criteria, '-odevice']) + except subprocess.CalledProcessError: return([]) - return(out.splitlines()) + return(str(out).splitlines()) class mountFailedError(Exception): pass - + + def mount_callback_umount(device, callback, data=None): """ mount the device, call method 'callback' passing the directory @@ -657,15 +659,15 @@ def mount_callback_umount(device, callback, data=None): returned. If data != None, also pass data to callback. """ - def _cleanup(mountpoint, tmpd): + def _cleanup(umount, tmpd): if umount: try: subp(["umount", '-l', umount]) - except subprocess.CalledProcessError as exc: + except subprocess.CalledProcessError: raise if tmpd: os.rmdir(tmpd) - + # go through mounts to see if it was already mounted fp = open("/proc/mounts") mounts = fp.readlines() @@ -684,15 +686,14 @@ def mount_callback_umount(device, callback, data=None): mountpoint = "%s/" % mounted[device][2] else: tmpd = tempfile.mkdtemp() - + mountcmd = ["mount", "-o", "ro", device, tmpd] try: - (out, err) = subp(mountcmd) + (_out, _err) = subp(mountcmd) umount = tmpd except subprocess.CalledProcessError as exc: _cleanup(umount, tmpd) - print exc.output[1] raise mountFailedError(exc.output[1]) mountpoint = "%s/" % tmpd -- cgit v1.2.3 From dd628f06f9661ae3b9a72a95d744dfbb5244c173 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Tue, 28 Feb 2012 18:34:04 -0500 Subject: address change in name of lxc-is-container to running-in-container Also improves the logic in is_container following ubuntu's /etc/init/container-detect.conf . LP: #941955 --- cloudinit/CloudConfig/cc_resizefs.py | 4 +-- cloudinit/util.py | 67 ++++++++++++++++++++++++++++-------- 2 files changed, 55 insertions(+), 16 deletions(-) (limited to 'cloudinit/CloudConfig') diff --git a/cloudinit/CloudConfig/cc_resizefs.py b/cloudinit/CloudConfig/cc_resizefs.py index 0186d4d2..c76cc664 100644 --- a/cloudinit/CloudConfig/cc_resizefs.py +++ b/cloudinit/CloudConfig/cc_resizefs.py @@ -49,8 +49,8 @@ def handle(_name, cfg, _cloud, log, args): dev = os.makedev(os.major(st_dev), os.minor(st_dev)) os.mknod(devpth, 0400 | stat.S_IFBLK, dev) except: - if util.islxc(): - log.debug("inside lxc, ignoring mknod failure in resizefs") + if util.is_container(): + log.debug("inside container, ignoring mknod failure in resizefs") return log.warn("Failed to make device node to resize /") raise diff --git a/cloudinit/util.py b/cloudinit/util.py index 780578e2..c93a17c4 100644 --- a/cloudinit/util.py +++ b/cloudinit/util.py @@ -516,30 +516,69 @@ def dos2unix(string): return(string.replace('\r\n', '\n')) -def islxc(): - # is this host running lxc? +def is_container(): + # is this running in a cgroup other than / + for helper in ('running-in-container', 'lxc-is-container'): + try: + # try to run a helper program. if it returns true + # then we're inside a container. otherwise, no + sp = subprocess.Popen(helper, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + sp.communicate(None) + return(sp.returncode == 0) + except OSError as e: + if e.errno != errno.ENOENT: + raise + + # this code is largely from the logic in + # ubuntu's /etc/init/container-detect.conf try: - with open("/proc/1/cgroup") as f: - if f.read() == "/": - return True + # Detect old-style libvirt + # Detect OpenVZ containers + pid1env = get_proc_env(1) + if "container" in pid1env: + return True + + if "LIBVIRT_LXC_UUID" in pid1env: + return True + except IOError as e: if e.errno != errno.ENOENT: - raise + pass + + # Detect OpenVZ containers + if os.path.isdir("/proc/vz") and not os.path.isdir("/proc/bc"): + return True try: - # try to run a program named 'lxc-is-container'. if it returns true, - # then we're inside a container. otherwise, no - sp = subprocess.Popen(['lxc-is-container'], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - sp.communicate(None) - return(sp.returncode == 0) - except OSError as e: + # Detect Vserver containers + with open("/proc/self/status") as fp: + lines = fp.read().splitlines() + for line in lines: + if line.startswith("VxID:"): + (_key, val) = line.strip().split(":", 1) + if val != "0": + return True + except IOError as e: if e.errno != errno.ENOENT: - raise + pass return False +def get_proc_env(pid): + # return the environment in a dict that a given process id was started with + env = {} + with open("/proc/%s/environ" % pid) as fp: + toks = fp.read().split("\0") + for tok in toks: + if tok == "": + continue + (name, val) = tok.split("=", 1) + env[name] = val + return env + + 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 -- cgit v1.2.3