From 180620470ba9aae4aac804b8bd66d3af8bd71ee4 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Wed, 7 Nov 2012 10:29:20 -0500 Subject: adjust documentation to account for apt/package aliases --- doc/examples/cloud-config.txt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'doc') diff --git a/doc/examples/cloud-config.txt b/doc/examples/cloud-config.txt index 56a6c35a..04bb5df1 100644 --- a/doc/examples/cloud-config.txt +++ b/doc/examples/cloud-config.txt @@ -3,15 +3,20 @@ # (ie run apt-get update) # # Default: true -# -apt_update: false +# Aliases: apt_update +package_update: false # Upgrade the instance on first boot # (ie run apt-get upgrade) # # Default: false -# -apt_upgrade: true +# Aliases: apt_upgrade +package_upgrade: true + +# Reboot after package install/update if necessary +# Default: false +# Aliases: apt_reboot_if_required +package_reboot_if_required: true # Add apt repositories # -- cgit v1.2.3 From 7ea02ab1d8ee0f400a84ee2d688e67ffbc449bf0 Mon Sep 17 00:00:00 2001 From: Joshua Harlow Date: Wed, 7 Nov 2012 21:00:33 -0800 Subject: Add a makefile yaml checking target and fix the cases where the cc yaml is not correct. --- Makefile | 9 ++++++++- doc/examples/cloud-config.txt | 3 +-- tests/configs/sample1.yaml | 1 - tools/validate-yaml.py | 20 ++++++++++++++++++++ 4 files changed, 29 insertions(+), 4 deletions(-) create mode 100755 tools/validate-yaml.py (limited to 'doc') diff --git a/Makefile b/Makefile index 88c90b9b..2a6be961 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,10 @@ CWD=$(shell pwd) PY_FILES=$(shell find cloudinit bin tests tools -name "*.py" -type f ) PY_FILES+="bin/cloud-init" +YAML_FILES=$(shell find cloudinit bin tests tools -name "*.yaml" -type f ) +YAML_FILES+=$(shell find doc/examples -name "cloud-config*.txt" -type f ) + + all: test pep8: @@ -23,11 +27,14 @@ clean: rm -rf /var/log/cloud-init.log \ /var/lib/cloud/ +yaml: + @$(CWD)/tools/validate-yaml.py $(YAML_FILES) + rpm: ./packages/brpm deb: ./packages/bddeb -.PHONY: test pylint pyflakes 2to3 clean pep8 rpm deb +.PHONY: test pylint pyflakes 2to3 clean pep8 rpm deb yaml diff --git a/doc/examples/cloud-config.txt b/doc/examples/cloud-config.txt index 04bb5df1..12bf2c91 100644 --- a/doc/examples/cloud-config.txt +++ b/doc/examples/cloud-config.txt @@ -355,8 +355,7 @@ rsyslog: - ':syslogtag, isequal, "[CLOUDINIT]" /var/log/cloud-foo.log' - content: "*.* @@192.0.2.1:10514" - filename: 01-examplecom.conf - content: | - *.* @@syslogd.example.com + content: "*.* @@syslogd.example.com" # resize_rootfs should the / filesytem be resized on first boot # this allows you to launch an instance with a larger disk / partition diff --git a/tests/configs/sample1.yaml b/tests/configs/sample1.yaml index 24e874ee..6231f293 100644 --- a/tests/configs/sample1.yaml +++ b/tests/configs/sample1.yaml @@ -50,4 +50,3 @@ runcmd: byobu_by_default: user -output: {all: '| tee -a /var/log/cloud-init-output.log'} diff --git a/tools/validate-yaml.py b/tools/validate-yaml.py new file mode 100755 index 00000000..d3218e40 --- /dev/null +++ b/tools/validate-yaml.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +"""Try to read a YAML file and report any errors. +""" + +import sys + +import yaml + + +if __name__ == "__main__": + for fn in sys.argv[1:]: + sys.stdout.write("%s" % (fn)) + try: + fh = open(fn, 'r') + yaml.safe_load(fh.read()) + fh.close() + sys.stdout.write(" - ok\n") + except Exception, e: + sys.stdout.write(" - bad (%s)\n" % (e)) -- cgit v1.2.3 From 949e1759342b1e60c100855aaf250165bcb9997e Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Mon, 12 Nov 2012 22:15:29 -0500 Subject: add 'finalcmd' module for running code after cloud-init-final This allows the user to easily run stuff even after cloud-init-final has finished. The initial reason for it is to be able to run /sbin/poweroff and not have cloud-init complain loudly that it is being killed. LP: #1064665 --- ChangeLog | 2 + cloudinit/config/cc_finalcmd.py | 139 ++++++++++++++++++++++++++++++++++++++++ config/cloud.cfg | 1 + doc/examples/cloud-config.txt | 18 ++++++ 4 files changed, 160 insertions(+) create mode 100644 cloudinit/config/cc_finalcmd.py (limited to 'doc') diff --git a/ChangeLog b/ChangeLog index 4cae8b32..93c3af04 100644 --- a/ChangeLog +++ b/ChangeLog @@ -46,6 +46,8 @@ dictionary and force it to full expand so that if cloud-init blocks the ec2 metadata port the lazy loaded dictionary will continue working properly instead of trying to make additional url calls which will fail (LP: #1068801) + - add 'finalcmd' config module to execute 'finalcmd' entries like + 'runcmd' but detached from cloud-init (LP: #1064665) 0.7.0: - add a 'exception_cb' argument to 'wait_for_url'. If provided, this method will be called back with the exception received and the message. diff --git a/cloudinit/config/cc_finalcmd.py b/cloudinit/config/cc_finalcmd.py new file mode 100644 index 00000000..442ad12b --- /dev/null +++ b/cloudinit/config/cc_finalcmd.py @@ -0,0 +1,139 @@ +# vi: ts=4 expandtab +# +# Copyright (C) 2011 Canonical Ltd. +# +# Author: Scott Moser +# +# 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 . + +from cloudinit.settings import PER_INSTANCE +from cloudinit import util + +import errno +import os +import subprocess +import sys +import time + +frequency = PER_INSTANCE + + +def handle(_name, cfg, _cloud, log, _args): + + finalcmds = cfg.get("finalcmd") + + if not finalcmds: + log.debug("No final commands") + return + + mypid = os.getpid() + cmdline = util.load_file("/proc/%s/cmdline") + + if not cmdline: + log.warn("Failed to get cmdline of current process") + return + + try: + timeout = float(cfg.get("finalcmd_timeout", 30.0)) + except ValueError: + log.warn("failed to convert finalcmd_timeout '%s' to float" % + cfg.get("finalcmd_timeout", 30.0)) + return + + devnull_fp = open("/dev/null", "w") + + shellcode = util.shellify(finalcmds) + + # note, after the fork, we do not use any of cloud-init's functions + # that would attempt to log. The primary reason for that is + # to allow the 'finalcmd' the ability to do just about anything + # and not depend on syslog services. + # Basically, it should "just work" to have finalcmd of: + # - sleep 30 + # - /sbin/poweroff + finalcmd_d = os.path.join(cloud.get_ipath_cur(), "finalcmds") + + util.fork_cb(run_after_pid_gone, mypid, cmdline, timeout, + runfinal, (shellcode, finalcmd_d, devnull_fp)) + + +def execmd(exe_args, data_in=None, output=None): + try: + proc = subprocess.Popen(exe_args, stdin=subprocess.PIPE, + stdout=output, stderr=subprocess.STDERR) + proc.communicate(data_in) + except Exception as e: + return 254 + return proc.returncode() + + +def runfinal(shellcode, finalcmd_d, output=None): + ret = execmd(("/bin/sh",), data_in=shellcode, output=output) + if not (finalcmd_d and os.path.isdir(finalcmd_d)): + sys.exit(ret) + + fails = 0 + if ret != 0: + fails = 1 + + # now runparts the final command dir + for exe_name in sorted(os.listdir(finalcmd_d)): + exe_path = os.path.join(finalcmd_d, exe_name) + if os.path.isfile(exe_path) and os.access(exe_path, os.X_OK): + ret = execmd(exe_path, data_in=None, output=output) + if ret != 0: + fails += 1 + sys.exit(fails) + + +def run_after_pid_gone(pid, pidcmdline, timeout, func, args): + # wait until pid, with /proc/pid/cmdline contents of pidcmdline + # is no longer alive. After it is gone, or timeout has passed + # execute func(args) + msg = "ERROR: Uncaught error" + end_time = time.time() + timeout + + cmdline_f = "/proc/%s/cmdline" % pid + + while True: + if time.time() > end_time: + msg = "timeout reached before %s ended" % pid + break + + try: + cmdline = "" + with open(cmdline_f) as fp: + cmdline = fp.read() + if cmdline != pidcmdline: + msg = "cmdline changed for %s [now: %s]" % (pid, cmdline) + break + + except IOError as ioerr: + if ioerr.errno == errno.ENOENT: + msg = "pidfile '%s' gone" % cmdline_f + else: + msg = "ERROR: IOError: %s" % ioerr + raise + break + + except Exception as e: + msg = "ERROR: Exception: %s" % e + raise + + if msg.startswith("ERROR:"): + sys.stderr.write(msg) + sys.stderr.write("Not executing finalcmd") + sys.exit(1) + + sys.stderr.write("calling %s with %s\n" % (func, args)) + sys.exit(func(*args)) diff --git a/config/cloud.cfg b/config/cloud.cfg index ad100fff..249a593d 100644 --- a/config/cloud.cfg +++ b/config/cloud.cfg @@ -69,6 +69,7 @@ cloud_final_modules: - keys-to-console - phone-home - final-message + - finalcmd # System and/or distro specific settings # (not accessible to handlers/transforms) diff --git a/doc/examples/cloud-config.txt b/doc/examples/cloud-config.txt index 12bf2c91..4fc5f351 100644 --- a/doc/examples/cloud-config.txt +++ b/doc/examples/cloud-config.txt @@ -256,6 +256,24 @@ bootcmd: - echo 192.168.1.130 us.archive.ubuntu.com > /etc/hosts - [ cloud-init-per, once, mymkfs, mkfs, /dev/vdb ] +# final commands +# default: none +# This can be used to execute commands after and fully detached from +# a cloud-init stage. The initial purpose of it was to allow 'poweroff' +# detached from cloud-init. If poweroff was run from 'runcmd' or userdata +# then messages may be spewed from cloud-init about logging failing or other +# issues as a result of the system being turned off. +# +# You probably are better off using 'runcmd' for this. +# +# The output of finalcmd will redirected redirected to /dev/null +# If you want output to be seen, take care to do so in your commands +# themselves. See example. +finalcmd: + - sleep 30 + - "echo $(date -R): powering off > /dev/console" + - /sbin/poweroff + # cloud_config_modules: # default: # cloud_config_modules: -- cgit v1.2.3 From 2113e89b6816d2c9d442103698414cd189ca3412 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Tue, 13 Nov 2012 11:18:22 -0500 Subject: implement power_state with tests. --- ChangeLog | 4 +- cloudinit/config/cc_power_state_change.py | 122 +++++++++++---------- doc/examples/cloud-config.txt | 39 ++++--- .../test_handler/test_handler_power_state.py | 88 +++++++++++++++ 4 files changed, 175 insertions(+), 78 deletions(-) create mode 100644 tests/unittests/test_handler/test_handler_power_state.py (limited to 'doc') diff --git a/ChangeLog b/ChangeLog index 57bfc1a4..23612228 100644 --- a/ChangeLog +++ b/ChangeLog @@ -43,8 +43,8 @@ - Added dependency on distribute's python-pkg-resources - use a set of helper/parsing classes to perform system configuration for easier test. (/etc/sysconfig, /etc/hostname, resolv.conf, /etc/hosts) - - add 'finalcmd' config module to execute 'finalcmd' entries like - 'runcmd' but detached from cloud-init (LP: #1064665) + - add power_state_change config module for shutting down stystem after + cloud-init finishes. (LP: #1064665) 0.7.0: - add a 'exception_cb' argument to 'wait_for_url'. If provided, this method will be called back with the exception received and the message. diff --git a/cloudinit/config/cc_power_state_change.py b/cloudinit/config/cc_power_state_change.py index 67e0316b..07de548c 100644 --- a/cloudinit/config/cc_power_state_change.py +++ b/cloudinit/config/cc_power_state_change.py @@ -21,6 +21,7 @@ from cloudinit import util import errno import os +import re import subprocess import sys import time @@ -28,83 +29,91 @@ import time frequency = PER_INSTANCE -def handle(_name, cfg, cloud, log, _args): +def handle(_name, cfg, _cloud, log, _args): - finalcmds = cfg.get("finalcmd") - - if not finalcmds: - log.debug("No final commands") + try: + (args, timeout) = load_power_state(cfg) + if args is None: + log.debug("no power_state provided. doing nothing") + return + except Exception as e: + log.warn("%s Not performing power state change!" % str(e)) return mypid = os.getpid() cmdline = util.load_file("/proc/%s/cmdline") if not cmdline: - log.warn("Failed to get cmdline of current process") - return - - try: - timeout = float(cfg.get("finalcmd_timeout", 30.0)) - except ValueError: - log.warn("failed to convert finalcmd_timeout '%s' to float" % - cfg.get("finalcmd_timeout", 30.0)) + log.warn("power_state: failed to get cmdline of current process") return devnull_fp = open("/dev/null", "w") - shellcode = util.shellify(finalcmds) + log.debug("After pid %s ends, will execute: %s" % (mypid, ' '.join(args))) + + util.fork_cb(run_after_pid_gone, mypid, cmdline, timeout, log, execmd, + [args, devnull_fp]) + + +def load_power_state(cfg): + # returns a tuple of shutdown_command, timeout + # shutdown_command is None if no config found + pstate = cfg.get('power_state') + + if pstate is None: + return (None, None) + + if not isinstance(pstate, dict): + raise TypeError("power_state is not a dict.") - # note, after the fork, we do not use any of cloud-init's functions - # that would attempt to log. The primary reason for that is - # to allow the 'finalcmd' the ability to do just about anything - # and not depend on syslog services. - # Basically, it should "just work" to have finalcmd of: - # - sleep 30 - # - /sbin/poweroff - finalcmd_d = os.path.join(cloud.get_ipath_cur(), "finalcmds") + opt_map = {'halt': '-H', 'poweroff': '-P', 'reboot': '-r'} - util.fork_cb(run_after_pid_gone, mypid, cmdline, timeout, - runfinal, (shellcode, finalcmd_d, devnull_fp)) + mode = pstate.get("mode") + if mode not in opt_map: + raise TypeError("power_state[mode] required, must be one of: %s." % + ','.join(opt_map.keys())) + delay = pstate.get("delay", "now") + if delay != "now" and not re.match("\+[0-9]+", delay): + raise TypeError("power_state[delay] must be 'now' or '+m' (minutes).") -def execmd(exe_args, data_in=None, output=None): + args = ["shutdown", opt_map[mode], delay] + if pstate.get("message"): + args.append(pstate.get("message")) + + try: + timeout = float(pstate.get('timeout', 30.0)) + except ValueError: + raise ValueError("failed to convert timeout '%s' to float." % + pstate['timeout']) + + return (args, timeout) + + +def execmd(exe_args, output=None, data_in=None): try: proc = subprocess.Popen(exe_args, stdin=subprocess.PIPE, stdout=output, stderr=subprocess.STDOUT) proc.communicate(data_in) except Exception: - return 254 - return proc.returncode() + sys.exit(254) + sys.exit(proc.returncode()) -def runfinal(shellcode, finalcmd_d, output=None): - ret = execmd(["/bin/sh"], data_in=shellcode, output=output) - if not (finalcmd_d and os.path.isdir(finalcmd_d)): - sys.exit(ret) - - fails = 0 - if ret != 0: - fails = 1 - - # now runparts the final command dir - for exe_name in sorted(os.listdir(finalcmd_d)): - exe_path = os.path.join(finalcmd_d, exe_name) - if os.path.isfile(exe_path) and os.access(exe_path, os.X_OK): - ret = execmd([exe_path], data_in=None, output=output) - if ret != 0: - fails += 1 - sys.exit(fails) - - -def run_after_pid_gone(pid, pidcmdline, timeout, func, args): +def run_after_pid_gone(pid, pidcmdline, timeout, log, func, args): # wait until pid, with /proc/pid/cmdline contents of pidcmdline # is no longer alive. After it is gone, or timeout has passed # execute func(args) - msg = "ERROR: Uncaught error" + msg = None end_time = time.time() + timeout cmdline_f = "/proc/%s/cmdline" % pid + def fatal(msg): + if log: + log.warn(msg) + sys.exit(254) + while True: if time.time() > end_time: msg = "timeout reached before %s ended" % pid @@ -122,18 +131,15 @@ def run_after_pid_gone(pid, pidcmdline, timeout, func, args): if ioerr.errno == errno.ENOENT: msg = "pidfile '%s' gone" % cmdline_f else: - msg = "ERROR: IOError: %s" % ioerr - raise + fatal("IOError during wait: %s" % ioerr) break except Exception as e: - msg = "ERROR: Exception: %s" % e - raise + fatal("Unexpected Exception: %s" % e) - if msg.startswith("ERROR:"): - sys.stderr.write(msg) - sys.stderr.write("Not executing finalcmd") - sys.exit(1) + if not msg: + fatal("Unexpected error in run_after_pid_gone") - sys.stderr.write("calling %s with %s\n" % (func, args)) - sys.exit(func(*args)) + if log: + log.debug(msg) + func(*args) diff --git a/doc/examples/cloud-config.txt b/doc/examples/cloud-config.txt index 4fc5f351..09298655 100644 --- a/doc/examples/cloud-config.txt +++ b/doc/examples/cloud-config.txt @@ -256,24 +256,6 @@ bootcmd: - echo 192.168.1.130 us.archive.ubuntu.com > /etc/hosts - [ cloud-init-per, once, mymkfs, mkfs, /dev/vdb ] -# final commands -# default: none -# This can be used to execute commands after and fully detached from -# a cloud-init stage. The initial purpose of it was to allow 'poweroff' -# detached from cloud-init. If poweroff was run from 'runcmd' or userdata -# then messages may be spewed from cloud-init about logging failing or other -# issues as a result of the system being turned off. -# -# You probably are better off using 'runcmd' for this. -# -# The output of finalcmd will redirected redirected to /dev/null -# If you want output to be seen, take care to do so in your commands -# themselves. See example. -finalcmd: - - sleep 30 - - "echo $(date -R): powering off > /dev/console" - - /sbin/poweroff - # cloud_config_modules: # default: # cloud_config_modules: @@ -596,3 +578,24 @@ manual_cache_clean: False # A list of key types (first token of a /etc/ssh/ssh_key_*.pub file) # that should be skipped when outputting key fingerprints and keys # to the console respectively. + +## poweroff or reboot system after finished +# default: none +# +# power_state can be used to make the system shutdown, reboot or +# halt after boot is finished. This same thing can be acheived by +# user-data scripts or by runcmd by simply invoking 'shutdown'. +# +# Doing it this way ensures that cloud-init is entirely finished with +# modules that would be executed, and avoids any error/log messages +# that may go to the console as a result of system services like +# syslog being taken down while cloud-init is running. +# +# delay: form accepted by shutdown. default is 'now'. other format +# accepted is +m (m in minutes) +# mode: required. must be one of 'poweroff', 'halt', 'reboot' +# message: provided as the message argument to 'shutdown'. default is none. +power_state: + delay: 30 + mode: poweroff + message: Bye Bye diff --git a/tests/unittests/test_handler/test_handler_power_state.py b/tests/unittests/test_handler/test_handler_power_state.py new file mode 100644 index 00000000..1149fedc --- /dev/null +++ b/tests/unittests/test_handler/test_handler_power_state.py @@ -0,0 +1,88 @@ +from unittest import TestCase + +from cloudinit.config import cc_power_state_change as psc + + +class TestLoadPowerState(TestCase): + def setUp(self): + super(self.__class__, self).setUp() + + def test_no_config(self): + # completely empty config should mean do nothing + (cmd, _timeout) = psc.load_power_state({}) + self.assertEqual(cmd, None) + + def test_irrelevant_config(self): + # no power_state field in config should return None for cmd + (cmd, _timeout) = psc.load_power_state({'foo': 'bar'}) + self.assertEqual(cmd, None) + + def test_invalid_mode(self): + cfg = {'power_state': {'mode': 'gibberish'}} + self.assertRaises(TypeError, psc.load_power_state, cfg) + + cfg = {'power_state': {'mode': ''}} + self.assertRaises(TypeError, psc.load_power_state, cfg) + + def test_empty_mode(self): + cfg = {'power_state': {'message': 'goodbye'}} + self.assertRaises(TypeError, psc.load_power_state, cfg) + + def test_valid_modes(self): + cfg = {'power_state': {}} + for mode in ('halt', 'poweroff', 'reboot'): + cfg['power_state']['mode'] = mode + check_lps_ret(psc.load_power_state(cfg), mode=mode) + + def test_invalid_delay(self): + cfg = {'power_state': {'mode': 'poweroff', 'delay': 'goodbye'}} + self.assertRaises(TypeError, psc.load_power_state, cfg) + + def test_valid_delay(self): + cfg = {'power_state': {'mode': 'poweroff', 'delay': ''}} + for delay in ("now", "+1", "+30"): + cfg['power_state']['delay'] = delay + check_lps_ret(psc.load_power_state(cfg)) + + def test_message_present(self): + cfg = {'power_state': {'mode': 'poweroff', 'message': 'GOODBYE'}} + ret = psc.load_power_state(cfg) + check_lps_ret(psc.load_power_state(cfg)) + self.assertIn(cfg['power_state']['message'], ret[0]) + + def test_no_message(self): + # if message is not present, then no argument should be passed for it + cfg = {'power_state': {'mode': 'poweroff'}} + (cmd, _timeout) = psc.load_power_state(cfg) + self.assertNotIn("", cmd) + check_lps_ret(psc.load_power_state(cfg)) + self.assertTrue(len(cmd) == 3) + + +def check_lps_ret(psc_return, mode=None): + if len(psc_return) != 2: + raise TypeError("length returned = %d" % len(psc_return)) + + errs = [] + cmd = psc_return[0] + timeout = psc_return[1] + + if not 'shutdown' in psc_return[0][0]: + errs.append("string 'shutdown' not in cmd") + + if mode is not None: + opt = {'halt': '-H', 'poweroff': '-P', 'reboot': '-r'}[mode] + if opt not in psc_return[0]: + errs.append("opt '%s' not in cmd: %s" % (opt, cmd)) + + if len(cmd) != 3 and len(cmd) != 4: + errs.append("Invalid command length: %s" % len(cmd)) + + try: + float(timeout) + except: + errs.append("timeout failed convert to float") + + if len(errs): + lines = ["Errors in result: %s" % str(psc_return)] + errs + raise Exception('\n'.join(lines)) -- cgit v1.2.3 From cbd1ca764ed265460c3a79729a27ca8e3841390c Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Wed, 12 Dec 2012 10:39:43 -0500 Subject: add 'omnibus' as an install type for chef. Thanks to Anatoliy Dobrosynets --- ChangeLog | 1 + cloudinit/config/cc_chef.py | 15 ++++++++++++++- doc/examples/cloud-config-chef.txt | 9 ++++++++- 3 files changed, 23 insertions(+), 2 deletions(-) (limited to 'doc') diff --git a/ChangeLog b/ChangeLog index fbfd3385..af1e024d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,7 @@ - fix sudoers writing when entry is a string (LP: #1079002) - tools/write-ssh-key-fingerprints: use '-s' rather than '--stderr' option (LP: #1083715) + - support omnibus installer for chef [Anatoliy Dobrosynets] 0.7.1: - sysvinit: fix missing dependency in cloud-init job for RHEL 5.6 - config-drive: map hostname to local-hostname (LP: #1061964) diff --git a/cloudinit/config/cc_chef.py b/cloudinit/config/cc_chef.py index 7a3d6a31..607f789e 100644 --- a/cloudinit/config/cc_chef.py +++ b/cloudinit/config/cc_chef.py @@ -22,6 +22,7 @@ import json import os from cloudinit import templater +from cloudinit import url_helper from cloudinit import util RUBY_VERSION_DEFAULT = "1.8" @@ -35,6 +36,8 @@ CHEF_DIRS = [ '/var/run/chef', ] +OMNIBUS_URL = "https://www.opscode.com/chef/install.sh" + def handle(name, cfg, cloud, log, _args): @@ -83,7 +86,9 @@ def handle(name, cfg, cloud, log, _args): util.write_file('/etc/chef/firstboot.json', json.dumps(initial_json)) # If chef is not installed, we install chef based on 'install_type' - if not os.path.isfile('/usr/bin/chef-client'): + if (not os.path.isfile('/usr/bin/chef-client') or + util.get_cfg_option_bool(chef_cfg, 'force_install', default=False)): + install_type = util.get_cfg_option_str(chef_cfg, 'install_type', 'packages') if install_type == "gems": @@ -99,6 +104,14 @@ def handle(name, cfg, cloud, log, _args): elif install_type == 'packages': # this will install and run the chef-client from packages cloud.distro.install_packages(('chef',)) + elif install_type == 'omnibus': + url = util.get_cfg_option_str(chef_cfg, "omnibus_url", OMNIBUS_URL) + content = url_helper.readurl(url=url, retries=5) + with util.tempdir() as tmpd: + # use tmpd over tmpfile to avoid 'Text file busy' on execute + tmpf = "%s/chef-omnibus-install" % tmpd + util.write_file(tmpf, content, mode=0700) + util.subp([tmpf], capture=False) else: log.warn("Unknown chef install type %s", install_type) diff --git a/doc/examples/cloud-config-chef.txt b/doc/examples/cloud-config-chef.txt index f87472ec..4edad653 100644 --- a/doc/examples/cloud-config-chef.txt +++ b/doc/examples/cloud-config-chef.txt @@ -47,9 +47,13 @@ apt_sources: chef: - # Valid values are 'gems' and 'packages' + # Valid values are 'gems' and 'packages' and 'omnibus' install_type: "packages" + # Boolean: run 'install_type' code even if chef-client + # appears already installed. + force_install: false + # Chef settings server_url: "https://chef.yourorg.com:4000" @@ -80,6 +84,9 @@ chef: maxclients: 100 keepalive: "off" + # if install_type is 'omnibus', change the url to download + omnibus_url: "https://www.opscode.com/chef/install.sh" + # Capture all subprocess output into a logfile # Useful for troubleshooting cloud-init issues -- cgit v1.2.3 From 6fb6fe24d5ba185d42f2d7a82c3c54d26fea3392 Mon Sep 17 00:00:00 2001 From: Joshua Harlow Date: Thu, 24 Jan 2013 18:41:26 -0800 Subject: Add docs which can be used on readthedocs.org Include a new set of docs that can be used to create a readthedocs.org site, which includes examples, directory layout, capabilities and such. This in-code documentation then allows for readthedocs.org to create a website directly from the cloud-init codebase. --- doc/examples/cloud-config-add-apt-repos.txt | 34 ++++++ doc/examples/cloud-config-boot-cmds.txt | 15 +++ doc/examples/cloud-config-final-message.txt | 7 ++ doc/examples/cloud-config-install-packages.txt | 11 ++ doc/examples/cloud-config-mount-points.txt | 39 ++++++ doc/examples/cloud-config-phone-home.txt | 14 +++ doc/examples/cloud-config-power-state.txt | 22 ++++ doc/examples/cloud-config-run-cmds.txt | 21 ++++ doc/examples/cloud-config-ssh-keys.txt | 46 +++++++ doc/examples/cloud-config-update-apt.txt | 7 ++ doc/examples/cloud-config-update-packages.txt | 8 ++ doc/rtd/conf.py | 73 ++++++++++++ doc/rtd/index.rst | 29 +++++ doc/rtd/logo.png | Bin 0 -> 4477 bytes doc/rtd/topics/availability.rst | 20 ++++ doc/rtd/topics/capabilities.rst | 24 ++++ doc/rtd/topics/dir_layout.rst | 81 +++++++++++++ doc/rtd/topics/examples.rst | 121 +++++++++++++++++++ doc/rtd/topics/format.rst | 159 +++++++++++++++++++++++++ doc/rtd/topics/modules.rst | 3 + doc/rtd/topics/moreinfo.rst | 12 ++ 21 files changed, 746 insertions(+) create mode 100644 doc/examples/cloud-config-add-apt-repos.txt create mode 100644 doc/examples/cloud-config-boot-cmds.txt create mode 100644 doc/examples/cloud-config-final-message.txt create mode 100644 doc/examples/cloud-config-install-packages.txt create mode 100644 doc/examples/cloud-config-mount-points.txt create mode 100644 doc/examples/cloud-config-phone-home.txt create mode 100644 doc/examples/cloud-config-power-state.txt create mode 100644 doc/examples/cloud-config-run-cmds.txt create mode 100644 doc/examples/cloud-config-ssh-keys.txt create mode 100644 doc/examples/cloud-config-update-apt.txt create mode 100644 doc/examples/cloud-config-update-packages.txt create mode 100644 doc/rtd/conf.py create mode 100644 doc/rtd/index.rst create mode 100644 doc/rtd/logo.png create mode 100644 doc/rtd/topics/availability.rst create mode 100644 doc/rtd/topics/capabilities.rst create mode 100644 doc/rtd/topics/dir_layout.rst create mode 100644 doc/rtd/topics/examples.rst create mode 100644 doc/rtd/topics/format.rst create mode 100644 doc/rtd/topics/modules.rst create mode 100644 doc/rtd/topics/moreinfo.rst (limited to 'doc') diff --git a/doc/examples/cloud-config-add-apt-repos.txt b/doc/examples/cloud-config-add-apt-repos.txt new file mode 100644 index 00000000..be9d5472 --- /dev/null +++ b/doc/examples/cloud-config-add-apt-repos.txt @@ -0,0 +1,34 @@ +#cloud-config + +# Add apt repositories +# +# Default: auto select based on cloud metadata +# in ec2, the default is .archive.ubuntu.com +# apt_mirror: +# use the provided mirror +# apt_mirror_search: +# search the list for the first mirror. +# this is currently very limited, only verifying that +# the mirror is dns resolvable or an IP address +# +# if neither apt_mirror nor apt_mirror search is set (the default) +# then use the mirror provided by the DataSource found. +# In EC2, that means using .ec2.archive.ubuntu.com +# +# if no mirror is provided by the DataSource, and 'apt_mirror_search_dns' is +# true, then search for dns names '-mirror' in each of +# - fqdn of this host per cloud metadata +# - localdomain +# - no domain (which would search domains listed in /etc/resolv.conf) +# If there is a dns entry for -mirror, then it is assumed that there +# is a distro mirror at http://-mirror./ +# +# That gives the cloud provider the opportunity to set mirrors of a distro +# up and expose them only by creating dns entries. +# +# if none of that is found, then the default distro mirror is used +apt_mirror: http://us.archive.ubuntu.com/ubuntu/ +apt_mirror_search: + - http://local-mirror.mydomain + - http://archive.ubuntu.com +apt_mirror_search_dns: False diff --git a/doc/examples/cloud-config-boot-cmds.txt b/doc/examples/cloud-config-boot-cmds.txt new file mode 100644 index 00000000..b281d327 --- /dev/null +++ b/doc/examples/cloud-config-boot-cmds.txt @@ -0,0 +1,15 @@ +#cloud-config + +# boot commands +# default: none +# this is very similar to runcmd, but commands run very early +# in the boot process, only slightly after a 'boothook' would run. +# bootcmd should really only be used for things that could not be +# done later in the boot process. bootcmd is very much like +# boothook, but possibly with more friendly. +# * bootcmd will run on every boot +# * the INSTANCE_ID variable will be set to the current instance id. +# * you can use 'cloud-init-boot-per' command to help only run once +bootcmd: + - echo 192.168.1.130 us.archive.ubuntu.com > /etc/hosts + - [ cloud-init-per, once, mymkfs, mkfs, /dev/vdb ] diff --git a/doc/examples/cloud-config-final-message.txt b/doc/examples/cloud-config-final-message.txt new file mode 100644 index 00000000..0ce31467 --- /dev/null +++ b/doc/examples/cloud-config-final-message.txt @@ -0,0 +1,7 @@ +#cloud-config + +# final_message +# default: cloud-init boot finished at $TIMESTAMP. Up $UPTIME seconds +# this message is written by cloud-final when the system is finished +# its first boot +final_message: "The system is finally up, after $UPTIME seconds" diff --git a/doc/examples/cloud-config-install-packages.txt b/doc/examples/cloud-config-install-packages.txt new file mode 100644 index 00000000..4984818f --- /dev/null +++ b/doc/examples/cloud-config-install-packages.txt @@ -0,0 +1,11 @@ +#cloud-config + +# Install additional packages on first boot +# +# Default: none +# +# if packages are specified, this apt_update will be set to true +# +packages: + - pwgen + - pastebinit diff --git a/doc/examples/cloud-config-mount-points.txt b/doc/examples/cloud-config-mount-points.txt new file mode 100644 index 00000000..416006db --- /dev/null +++ b/doc/examples/cloud-config-mount-points.txt @@ -0,0 +1,39 @@ +#cloud-config + +# set up mount points +# 'mounts' contains a list of lists +# the inner list are entries for an /etc/fstab line +# ie : [ fs_spec, fs_file, fs_vfstype, fs_mntops, fs-freq, fs_passno ] +# +# default: +# mounts: +# - [ ephemeral0, /mnt ] +# - [ swap, none, swap, sw, 0, 0 ] +# +# in order to remove a previously listed mount (ie, one from defaults) +# list only the fs_spec. For example, to override the default, of +# mounting swap: +# - [ swap ] +# or +# - [ swap, null ] +# +# - if a device does not exist at the time, an entry will still be +# written to /etc/fstab. +# - '/dev' can be ommitted for device names that begin with: xvd, sd, hd, vd +# - if an entry does not have all 6 fields, they will be filled in +# with values from 'mount_default_fields' below. +# +# Note, that you should set 'nobootwait' (see man fstab) for volumes that may +# not be attached at instance boot (or reboot) +# +mounts: + - [ ephemeral0, /mnt, auto, "defaults,noexec" ] + - [ sdc, /opt/data ] + - [ xvdh, /opt/data, "auto", "defaults,nobootwait", "0", "0" ] + - [ dd, /dev/zero ] + +# mount_default_fields +# These values are used to fill in any entries in 'mounts' that are not +# complete. This must be an array, and must have 7 fields. +mount_default_fields: [ None, None, "auto", "defaults,nobootwait", "0", "2" ] + diff --git a/doc/examples/cloud-config-phone-home.txt b/doc/examples/cloud-config-phone-home.txt new file mode 100644 index 00000000..7f2b69f7 --- /dev/null +++ b/doc/examples/cloud-config-phone-home.txt @@ -0,0 +1,14 @@ +#cloud-config + +# phone_home: if this dictionary is present, then the phone_home +# cloud-config module will post specified data back to the given +# url +# default: none +# phone_home: +# url: http://my.foo.bar/$INSTANCE/ +# post: all +# tries: 10 +# +phone_home: + url: http://my.example.com/$INSTANCE_ID/ + post: [ pub_key_dsa, pub_key_rsa, pub_key_ecdsa, instance_id ] diff --git a/doc/examples/cloud-config-power-state.txt b/doc/examples/cloud-config-power-state.txt new file mode 100644 index 00000000..59f062d0 --- /dev/null +++ b/doc/examples/cloud-config-power-state.txt @@ -0,0 +1,22 @@ +#cloud-config + +## poweroff or reboot system after finished +# default: none +# +# power_state can be used to make the system shutdown, reboot or +# halt after boot is finished. This same thing can be acheived by +# user-data scripts or by runcmd by simply invoking 'shutdown'. +# +# Doing it this way ensures that cloud-init is entirely finished with +# modules that would be executed, and avoids any error/log messages +# that may go to the console as a result of system services like +# syslog being taken down while cloud-init is running. +# +# delay: form accepted by shutdown. default is 'now'. other format +# accepted is +m (m in minutes) +# mode: required. must be one of 'poweroff', 'halt', 'reboot' +# message: provided as the message argument to 'shutdown'. default is none. +power_state: + delay: 30 + mode: poweroff + message: Bye Bye diff --git a/doc/examples/cloud-config-run-cmds.txt b/doc/examples/cloud-config-run-cmds.txt new file mode 100644 index 00000000..61b3bd63 --- /dev/null +++ b/doc/examples/cloud-config-run-cmds.txt @@ -0,0 +1,21 @@ +#cloud-config + +# run commands +# default: none +# runcmd contains a list of either lists or a string +# each item will be executed in order at rc.local like level with +# output to the console +# - if the item is a list, the items will be properly executed as if +# passed to execve(3) (with the first arg as the command). +# - if the item is a string, it will be simply written to the file and +# will be interpreted by 'sh' +# +# Note, that the list has to be proper yaml, so you have to escape +# any characters yaml would eat (':' can be problematic) +runcmd: + - [ ls, -l, / ] + - [ sh, -xc, "echo $(date) ': hello world!'" ] + - [ sh, -c, echo "=========hello world'=========" ] + - ls -l /root + - [ wget, "http://slashdot.org", -O, /tmp/index.html ] + diff --git a/doc/examples/cloud-config-ssh-keys.txt b/doc/examples/cloud-config-ssh-keys.txt new file mode 100644 index 00000000..235a114f --- /dev/null +++ b/doc/examples/cloud-config-ssh-keys.txt @@ -0,0 +1,46 @@ +#cloud-config + +# add each entry to ~/.ssh/authorized_keys for the configured user or the +# first user defined in the user definition directive. +ssh_authorized_keys: + - ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAGEA3FSyQwBI6Z+nCSjUUk8EEAnnkhXlukKoUPND/RRClWz2s5TCzIkd3Ou5+Cyz71X0XmazM3l5WgeErvtIwQMyT1KjNoMhoJMrJnWqQPOt5Q8zWd9qG7PBl9+eiH5qV7NZ mykey@host + - ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA3I7VUf2l5gSn5uavROsc5HRDpZdQueUq5ozemNSj8T7enqKHOEaFoU2VoPgGEWC9RyzSQVeyD6s7APMcE82EtmW4skVEgEGSbDc1pvxzxtchBj78hJP6Cf5TCMFSXw+Fz5rF1dR23QDbN1mkHs7adr8GW4kSWqU7Q7NDwfIrJJtO7Hi42GyXtvEONHbiRPOe8stqUly7MvUoN+5kfjBM8Qqpfl2+FNhTYWpMfYdPUnE7u536WqzFmsaqJctz3gBxH9Ex7dFtrxR4qiqEr9Qtlu3xGn7Bw07/+i1D+ey3ONkZLN+LQ714cgj8fRS4Hj29SCmXp5Kt5/82cD/VN3NtHw== smoser@brickies + +# Send pre-generated ssh private keys to the server +# If these are present, they will be written to /etc/ssh and +# new random keys will not be generated +# in addition to 'rsa' and 'dsa' as shown below, 'ecdsa' is also supported +ssh_keys: + rsa_private: | + -----BEGIN RSA PRIVATE KEY----- + MIIBxwIBAAJhAKD0YSHy73nUgysO13XsJmd4fHiFyQ+00R7VVu2iV9Qcon2LZS/x + 1cydPZ4pQpfjEha6WxZ6o8ci/Ea/w0n+0HGPwaxlEG2Z9inNtj3pgFrYcRztfECb + 1j6HCibZbAzYtwIBIwJgO8h72WjcmvcpZ8OvHSvTwAguO2TkR6mPgHsgSaKy6GJo + PUJnaZRWuba/HX0KGyhz19nPzLpzG5f0fYahlMJAyc13FV7K6kMBPXTRR6FxgHEg + L0MPC7cdqAwOVNcPY6A7AjEA1bNaIjOzFN2sfZX0j7OMhQuc4zP7r80zaGc5oy6W + p58hRAncFKEvnEq2CeL3vtuZAjEAwNBHpbNsBYTRPCHM7rZuG/iBtwp8Rxhc9I5w + ixvzMgi+HpGLWzUIBS+P/XhekIjPAjA285rVmEP+DR255Ls65QbgYhJmTzIXQ2T9 + luLvcmFBC6l35Uc4gTgg4ALsmXLn71MCMGMpSWspEvuGInayTCL+vEjmNBT+FAdO + W7D4zCpI43jRS9U06JVOeSc9CDk2lwiA3wIwCTB/6uc8Cq85D9YqpM10FuHjKpnP + REPPOyrAspdeOAV+6VKRavstea7+2DZmSUgE + -----END RSA PRIVATE KEY----- + + rsa_public: ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAGEAoPRhIfLvedSDKw7XdewmZ3h8eIXJD7TRHtVW7aJX1ByifYtlL/HVzJ09nilCl+MSFrpbFnqjxyL8Rr/DSf7QcY/BrGUQbZn2Kc22PemAWthxHO18QJvWPocKJtlsDNi3 smoser@localhost + + dsa_private: | + -----BEGIN DSA PRIVATE KEY----- + MIIBuwIBAAKBgQDP2HLu7pTExL89USyM0264RCyWX/CMLmukxX0Jdbm29ax8FBJT + pLrO8TIXVY5rPAJm1dTHnpuyJhOvU9G7M8tPUABtzSJh4GVSHlwaCfycwcpLv9TX + DgWIpSj+6EiHCyaRlB1/CBp9RiaB+10QcFbm+lapuET+/Au6vSDp9IRtlQIVAIMR + 8KucvUYbOEI+yv+5LW9u3z/BAoGBAI0q6JP+JvJmwZFaeCMMVxXUbqiSko/P1lsa + LNNBHZ5/8MOUIm8rB2FC6ziidfueJpqTMqeQmSAlEBCwnwreUnGfRrKoJpyPNENY + d15MG6N5J+z81sEcHFeprryZ+D3Ge9VjPq3Tf3NhKKwCDQ0240aPezbnjPeFm4mH + bYxxcZ9GAoGAXmLIFSQgiAPu459rCKxT46tHJtM0QfnNiEnQLbFluefZ/yiI4DI3 + 8UzTCOXLhUA7ybmZha+D/csj15Y9/BNFuO7unzVhikCQV9DTeXX46pG4s1o23JKC + /QaYWNMZ7kTRv+wWow9MhGiVdML4ZN4XnifuO5krqAybngIy66PMEoQCFEIsKKWv + 99iziAH0KBMVbxy03Trz + -----END DSA PRIVATE KEY----- + + dsa_public: ssh-dss AAAAB3NzaC1kc3MAAACBAM/Ycu7ulMTEvz1RLIzTbrhELJZf8Iwua6TFfQl1ubb1rHwUElOkus7xMhdVjms8AmbV1Meem7ImE69T0bszy09QAG3NImHgZVIeXBoJ/JzByku/1NcOBYilKP7oSIcLJpGUHX8IGn1GJoH7XRBwVub6Vqm4RP78C7q9IOn0hG2VAAAAFQCDEfCrnL1GGzhCPsr/uS1vbt8/wQAAAIEAjSrok/4m8mbBkVp4IwxXFdRuqJKSj8/WWxos00Ednn/ww5QibysHYULrOKJ1+54mmpMyp5CZICUQELCfCt5ScZ9GsqgmnI80Q1h3Xkwbo3kn7PzWwRwcV6muvJn4PcZ71WM+rdN/c2EorAINDTbjRo97NueM94WbiYdtjHFxn0YAAACAXmLIFSQgiAPu459rCKxT46tHJtM0QfnNiEnQLbFluefZ/yiI4DI38UzTCOXLhUA7ybmZha+D/csj15Y9/BNFuO7unzVhikCQV9DTeXX46pG4s1o23JKC/QaYWNMZ7kTRv+wWow9MhGiVdML4ZN4XnifuO5krqAybngIy66PMEoQ= smoser@localhost + + diff --git a/doc/examples/cloud-config-update-apt.txt b/doc/examples/cloud-config-update-apt.txt new file mode 100644 index 00000000..a83ce3f7 --- /dev/null +++ b/doc/examples/cloud-config-update-apt.txt @@ -0,0 +1,7 @@ +#cloud-config +# Update apt database on first boot +# (ie run apt-get update) +# +# Default: true +# Aliases: apt_update +package_update: false diff --git a/doc/examples/cloud-config-update-packages.txt b/doc/examples/cloud-config-update-packages.txt new file mode 100644 index 00000000..56b72c63 --- /dev/null +++ b/doc/examples/cloud-config-update-packages.txt @@ -0,0 +1,8 @@ +#cloud-config + +# Upgrade the instance on first boot +# (ie run apt-get upgrade) +# +# Default: false +# Aliases: apt_upgrade +package_upgrade: true diff --git a/doc/rtd/conf.py b/doc/rtd/conf.py new file mode 100644 index 00000000..56ec912f --- /dev/null +++ b/doc/rtd/conf.py @@ -0,0 +1,73 @@ +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('../../')) +sys.path.insert(0, os.path.abspath('../')) +sys.path.insert(0, os.path.abspath('./')) +sys.path.insert(0, os.path.abspath('.')) + +from cloudinit import version + +# Supress warnings for docs that aren't used yet +#unused_docs = [ +#] + +# General information about the project. +project = 'Cloud-Init' + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [ + 'sphinx.ext.intersphinx', +] + +intersphinx_mapping = { + 'sphinx': ('http://sphinx.pocoo.org', None) +} + +# The suffix of source filenames. +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +version = version.version_string() + +# Set the default Pygments syntax +highlight_language = 'python' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [] + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +show_authors = False + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +html_theme_options = { + "bodyfont": "Arial, sans-serif", + "headfont": "Arial, sans-serif" +} + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +html_logo = 'logo.png' diff --git a/doc/rtd/index.rst b/doc/rtd/index.rst new file mode 100644 index 00000000..f878dbd4 --- /dev/null +++ b/doc/rtd/index.rst @@ -0,0 +1,29 @@ +.. _index: + +===================== +Documentation +===================== + +.. rubric:: Everything about cloud-init, a set of **python** scripts and utilities to make your cloud images be all they can be! + +Summary +----------------- + +`Cloud-init`_ is the *defacto* multi-distribution package that handles early initialization of a cloud instance. + + +---- + +.. toctree:: + :maxdepth: 2 + + topics/capabilities + topics/availability + topics/format + topics/dir_layout + topics/examples + topics/modules + topics/moreinfo + + +.. _Cloud-init: https://launchpad.net/cloud-init diff --git a/doc/rtd/logo.png b/doc/rtd/logo.png new file mode 100644 index 00000000..ed1b0a91 Binary files /dev/null and b/doc/rtd/logo.png differ diff --git a/doc/rtd/topics/availability.rst b/doc/rtd/topics/availability.rst new file mode 100644 index 00000000..2d58f808 --- /dev/null +++ b/doc/rtd/topics/availability.rst @@ -0,0 +1,20 @@ +============ +Availability +============ + +It is currently installed in the `Ubuntu Cloud Images`_ and also in the official `Ubuntu`_ images available on EC2. + +Versions for other systems can be (or have been) created for the following distributions: + +- Ubuntu +- Fedora +- Debian +- RHEL +- CentOS +- *and more...* + +So ask your distribution provider where you can obtain an image with it built-in if one is not already available ☺ + + +.. _Ubuntu Cloud Images: http://cloud-images.ubuntu.com/ +.. _Ubuntu: http://www.ubuntu.com/ diff --git a/doc/rtd/topics/capabilities.rst b/doc/rtd/topics/capabilities.rst new file mode 100644 index 00000000..63b34270 --- /dev/null +++ b/doc/rtd/topics/capabilities.rst @@ -0,0 +1,24 @@ +===================== +Capabilities +===================== + +- Setting a default locale +- Setting a instance hostname +- Generating instance ssh private keys +- Adding ssh keys to a users ``.ssh/authorized_keys`` so they can log in +- Setting up ephemeral mount points + +User configurability +-------------------- + +`Cloud-init`_ 's behavior can be configured via user-data. + + User-data can be given by the user at instance launch time. + +This is done via the ``--user-data`` or ``--user-data-file`` argument to ec2-run-instances for example. + +* Check your local clients documentation for how to provide a `user-data` string + or `user-data` file for usage by cloud-init on instance creation. + + +.. _Cloud-init: https://launchpad.net/cloud-init diff --git a/doc/rtd/topics/dir_layout.rst b/doc/rtd/topics/dir_layout.rst new file mode 100644 index 00000000..f072c585 --- /dev/null +++ b/doc/rtd/topics/dir_layout.rst @@ -0,0 +1,81 @@ +========= +Directory layout +========= + +Cloudinits's directory structure is somewhat different from a regular application:: + + /var/lib/cloud/ + - data/ + - instance-id + - previous-instance-id + - datasource + - previous-datasource + - previous-hostname + - handlers/ + - instance + - instances/ + i-00000XYZ/ + - boot-finished + - cloud-config.txt + - datasource + - handlers/ + - obj.pkl + - scripts/ + - sem/ + - user-data.txt + - user-data.txt.i + - scripts/ + - per-boot/ + - per-instance/ + - per-once/ + - seed/ + - sem/ + +``/var/lib/cloud`` + + The main directory containing the cloud-init specific subdirectories. + It is typically located at ``/var/lib`` but there are certain configuration + scenarios where this can be altered. + + TBD, describe this overriding more. + +``data/`` + + Contains information releated to instance ids, datasources and hostnames of the previous + and current instance if they are different. These can be examined as needed to + determine any information releated to a previous boot (if applicable). + +``handlers/`` + + Custom ``part-handlers`` code is written out here. Files that end up here are written + out with in the scheme of ``part-handler-XYZ`` where ``XYZ`` is the handler number (the + first handler found starts at 0). + + +``instance`` + + A symlink to the current ``instances/`` subdirectory that points to the currently + active instance (which is active is dependent on the datasource loaded). + +``instances/`` + + All instances that were created using this image end up with instance identifer + subdirectories (and corresponding data for each instance). The currently active + instance will be symlinked the the ``instance`` symlink file defined previously. + +``scripts/`` + + Scripts that are downloaded/created by the corresponding ``part-handler`` will end up + in one of these subdirectories. + +``seed/`` + + TBD + +``sem/`` + + Cloud-init has a concept of a module sempahore, which basically consists + of the module name and its frequency. These files are used to ensure a module + is only ran `per-once`, `per-instance`, `per-always`. This folder contains + sempaphore `files` which are only supposed to run `per-once` (not tied to the instance id). + diff --git a/doc/rtd/topics/examples.rst b/doc/rtd/topics/examples.rst new file mode 100644 index 00000000..9bbc33cc --- /dev/null +++ b/doc/rtd/topics/examples.rst @@ -0,0 +1,121 @@ +.. _yaml_examples: + +========= +Cloud config examples +========= + +Including users and groups +--------------------------- + +.. literalinclude:: ../../examples/cloud-config-user-groups.txt + :language: yaml + :linenos: + + +Writing out arbitrary files +--------------------------- + +.. literalinclude:: ../../examples/cloud-config-write-files.txt + :language: yaml + :linenos: + + +Adding a yum repository +--------------------------- + +.. literalinclude:: ../../examples/cloud-config-yum-repo.txt + :language: yaml + :linenos: + +Configure an instance's trusted CA certificates +------------------------------------------------------ + +.. literalinclude:: ../../examples/cloud-config-ca-certs.txt + :language: yaml + :linenos: + +Install and run `chef`_ recipes +------------------------------------------------------ + +.. literalinclude:: ../../examples/cloud-config-chef.txt + :language: yaml + :linenos: + +Setup and run `puppet`_ +------------------------------------------------------ + +.. literalinclude:: ../../examples/cloud-config-puppet.txt + :language: yaml + :linenos: + +Add apt repositories +--------------------------- + +.. literalinclude:: ../../examples/cloud-config-add-apt-repos.txt + :language: yaml + :linenos: + +Run commands on first boot +--------------------------- + +.. literalinclude:: ../../examples/cloud-config-boot-cmds.txt + :language: yaml + :linenos: + +.. literalinclude:: ../../examples/cloud-config-run-cmds.txt + :language: yaml + :linenos: + + +Alter the completion message +--------------------------- + +.. literalinclude:: ../../examples/cloud-config-final-message.txt + :language: yaml + :linenos: + +Install arbitrary packages +--------------------------- + +.. literalinclude:: ../../examples/cloud-config-install-packages.txt + :language: yaml + :linenos: + +Run apt or yum upgrade +--------------------------- + +.. literalinclude:: ../../examples/cloud-config-update-packages.txt + :language: yaml + :linenos: + +Adjust mount points mounted +--------------------------- + +.. literalinclude:: ../../examples/cloud-config-mount-points.txt + :language: yaml + :linenos: + +Call a url when finished +--------------------------- + +.. literalinclude:: ../../examples/cloud-config-phone-home.txt + :language: yaml + :linenos: + +Reboot/poweroff when finished +--------------------------- + +.. literalinclude:: ../../examples/cloud-config-power-state.txt + :language: yaml + :linenos: + +Configure instances ssh-keys +--------------------------- + +.. literalinclude:: ../../examples/cloud-config-ssh-keys.txt + :language: yaml + :linenos: + + +.. _chef: http://www.opscode.com/chef/ +.. _puppet: http://puppetlabs.com/ diff --git a/doc/rtd/topics/format.rst b/doc/rtd/topics/format.rst new file mode 100644 index 00000000..eba9533f --- /dev/null +++ b/doc/rtd/topics/format.rst @@ -0,0 +1,159 @@ +========= +Formats +========= + +User data that will be acted upon by cloud-init must be in one of the following types. + +Gzip Compressed Content +------------------------ + +Content found to be gzip compressed will be uncompressed. +The uncompressed data will then be used as if it were not compressed. +This is typically is useful because user-data is limited to ~16384 [#]_ bytes. + +Mime Multi Part Archive +------------------------ + +This list of rules is applied to each part of this multi-part file. +Using a mime-multi part file, the user can specify more than one type of data. + +For example, both a user data script and a cloud-config type could be specified. + +Supported content-types: + +- text/x-include-once-url +- text/x-include-url +- text/cloud-config-archive +- text/upstart-job +- text/cloud-config +- text/part-handler +- text/x-shellscript +- text/cloud-boothook + +Helper script to generate mime messages +~~~~~~~~~~~~~~~~ + +.. code-block:: python + + #!/usr/bin/python + + import sys + + from email.mime.multipart import MIMEMultipart + from email.mime.text import MIMEText + + if len(sys.argv) == 1: + print("%s input-file:type ..." % (sys.argv[0])) + sys.exit(1) + + combined_message = MIMEMultipart() + for i in sys.argv[1:]: + (filename, format_type) = i.split(":", 1) + with open(filename) as fh: + contents = fh.read() + sub_message = MIMEText(contents, format_type, sys.getdefaultencoding()) + sub_message.add_header('Content-Disposition', 'attachment; filename="%s"' % (filename)) + combined_message.attach(sub_message) + + print(combined_message) + + +User-Data Script +------------------------ + +Typically used by those who just want to execute a shell script. + +Begins with: ``#!`` or ``Content-Type: text/x-shellscript`` when using a MIME archive. + +Example +~~~~~~~ + +:: + + $ cat myscript.sh + + #!/bin/sh + echo "Hello World. The time is now $(date -R)!" | tee /root/output.txt + + $ euca-run-instances --key mykey --user-data-file myscript.sh ami-a07d95c9 + +Include File +------------ + +This content is a ``include`` file. + +The file contains a list of urls, one per line. +Each of the URLs will be read, and their content will be passed through this same set of rules. +Ie, the content read from the URL can be gzipped, mime-multi-part, or plain text. + +Begins with: ``#include`` or ``Content-Type: text/x-include-url`` when using a MIME archive. + +Cloud Config Data +----------------- + +Cloud-config is the simplest way to accomplish some things +via user-data. Using cloud-config syntax, the user can specify certain things in a human friendly format. + +These things include: + +- apt upgrade should be run on first boot +- a different apt mirror should be used +- additional apt sources should be added +- certain ssh keys should be imported +- *and many more...* + +**Note:** The file must be valid yaml syntax. + +See the :ref:`yaml_examples` section for a commented set of examples of supported cloud config formats. + +Begins with: ``#cloud-config`` or ``Content-Type: text/cloud-config`` when using a MIME archive. + +Upstart Job +----------- + +Content is placed into a file in ``/etc/init``, and will be consumed by upstart as any other upstart job. + +Begins with: ``#upstart-job`` or ``Content-Type: text/upstart-job`` when using a MIME archive. + +Cloud Boothook +-------------- + +This content is ``boothook`` data. It is stored in a file under ``/var/lib/cloud`` and then executed immediately. +This is the earliest ``hook`` available. Note, that there is no mechanism provided for running only once. The boothook must take care of this itself. +It is provided with the instance id in the environment variable ``INSTANCE_I``. This could be made use of to provide a 'once-per-instance' type of functionality. + +Begins with: ``#cloud-boothook`` or ``Content-Type: text/cloud-boothook`` when using a MIME archive. + +Part Handler +------------ + +This is a ``part-handler``. It will be written to a file in ``/var/lib/cloud/data`` based on its filename (which is generated). +This must be python code that contains a ``list_types`` method and a ``handle_type`` method. +Once the section is read the ``list_types`` method will be called. It must return a list of mime-types that this part-handler handles. + +The ``handle_type`` method must be like: + +.. code-block:: python + + def handle_part(data, ctype, filename, payload): + # data = the cloudinit object + # ctype = "__begin__", "__end__", or the mime-type of the part that is being handled. + # filename = the filename of the part (or a generated filename if none is present in mime data) + # payload = the parts' content + +Cloud-init will then call the ``handle_type`` method once at begin, once per part received, and once at end. +The ``begin`` and ``end`` calls are to allow the part handler to do initialization or teardown. + +Begins with: ``#part-handler`` or ``Content-Type: text/part-handler`` when using a MIME archive. + +Example +~~~~~~~ + +.. literalinclude:: ../../examples/part-handler.txt + :language: python + :linenos: + +Also this `blog`_ post offers another example for more advanced usage. + +.. [#] See your cloud provider for applicable user-data size limitations... +.. _blog: http://foss-boss.blogspot.com/2011/01/advanced-cloud-init-custom-handlers.html diff --git a/doc/rtd/topics/modules.rst b/doc/rtd/topics/modules.rst new file mode 100644 index 00000000..d4dd55df --- /dev/null +++ b/doc/rtd/topics/modules.rst @@ -0,0 +1,3 @@ +========= +Modules +========= diff --git a/doc/rtd/topics/moreinfo.rst b/doc/rtd/topics/moreinfo.rst new file mode 100644 index 00000000..2e436c3c --- /dev/null +++ b/doc/rtd/topics/moreinfo.rst @@ -0,0 +1,12 @@ +========= +More information +========= + +Useful external references +---------------- + +- `The beauty of cloudinit`_ +- `Introduction to cloud-init`_ (video) + +.. _Introduction to cloud-init: http://www.youtube.com/watch?v=-zL3BdbKyGY +.. _The beauty of cloudinit: http://brandon.fuller.name/archives/2011/05/02/06.40.57/ -- cgit v1.2.3 From 465994f10efbc1d82d667027a6f9dd72d8bc7c6f Mon Sep 17 00:00:00 2001 From: harlowja Date: Thu, 24 Jan 2013 23:30:41 -0800 Subject: Make the logo better. --- doc/rtd/conf.py | 3 +- doc/rtd/logo.png | Bin 4477 -> 0 bytes doc/rtd/static/logo.png | Bin 0 -> 16031 bytes doc/rtd/static/logo.svg | 14356 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 14358 insertions(+), 1 deletion(-) delete mode 100644 doc/rtd/logo.png create mode 100644 doc/rtd/static/logo.png create mode 100755 doc/rtd/static/logo.svg (limited to 'doc') diff --git a/doc/rtd/conf.py b/doc/rtd/conf.py index 56ec912f..b3ca2b07 100644 --- a/doc/rtd/conf.py +++ b/doc/rtd/conf.py @@ -42,6 +42,7 @@ master_doc = 'index' # |version| and |release|, also used in various other places throughout the # built documents. version = version.version_string() +release = versions # Set the default Pygments syntax highlight_language = 'python' @@ -70,4 +71,4 @@ html_theme_options = { # The name of an image file (relative to this directory) to place at the top # of the sidebar. -html_logo = 'logo.png' +html_logo = 'static/logo.png' diff --git a/doc/rtd/logo.png b/doc/rtd/logo.png deleted file mode 100644 index ed1b0a91..00000000 Binary files a/doc/rtd/logo.png and /dev/null differ diff --git a/doc/rtd/static/logo.png b/doc/rtd/static/logo.png new file mode 100644 index 00000000..893b7e3b Binary files /dev/null and b/doc/rtd/static/logo.png differ diff --git a/doc/rtd/static/logo.svg b/doc/rtd/static/logo.svg new file mode 100755 index 00000000..b22ce2a0 --- /dev/null +++ b/doc/rtd/static/logo.svg @@ -0,0 +1,14356 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + Layer 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CloudInit + + -- cgit v1.2.3 From eedc6fb4963e9cfe6d99845ba1aff78447e480e8 Mon Sep 17 00:00:00 2001 From: harlowja Date: Thu, 24 Jan 2013 23:36:43 -0800 Subject: Fix the release variable. --- doc/rtd/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'doc') diff --git a/doc/rtd/conf.py b/doc/rtd/conf.py index b3ca2b07..87fc40ab 100644 --- a/doc/rtd/conf.py +++ b/doc/rtd/conf.py @@ -42,7 +42,7 @@ master_doc = 'index' # |version| and |release|, also used in various other places throughout the # built documents. version = version.version_string() -release = versions +release = version # Set the default Pygments syntax highlight_language = 'python' -- cgit v1.2.3 From e9d7caed3e2c7d86ab05d0e2280a796914e274b5 Mon Sep 17 00:00:00 2001 From: harlowja Date: Thu, 24 Jan 2013 23:50:31 -0800 Subject: Remove the release for now. --- doc/rtd/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'doc') diff --git a/doc/rtd/conf.py b/doc/rtd/conf.py index 87fc40ab..766f9e93 100644 --- a/doc/rtd/conf.py +++ b/doc/rtd/conf.py @@ -42,7 +42,7 @@ master_doc = 'index' # |version| and |release|, also used in various other places throughout the # built documents. version = version.version_string() -release = version +# release = version # Set the default Pygments syntax highlight_language = 'python' -- cgit v1.2.3 From 94c37c074aed4036160881f4f3a28d35f868d006 Mon Sep 17 00:00:00 2001 From: ctracey Date: Fri, 25 Jan 2013 17:27:06 -0500 Subject: Adding a doc example for resolv_conf handler. As per harlowja's suggestion addding an example to the doc directory for cc_resolv_conf.py --- doc/examples/cloud-config-resolv-conf.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 doc/examples/cloud-config-resolv-conf.txt (limited to 'doc') diff --git a/doc/examples/cloud-config-resolv-conf.txt b/doc/examples/cloud-config-resolv-conf.txt new file mode 100644 index 00000000..37ffc91a --- /dev/null +++ b/doc/examples/cloud-config-resolv-conf.txt @@ -0,0 +1,20 @@ +#cloud-config +# +# This is an example file to automatically configure resolv.conf when the +# instance boots for the first time. +# +# Ensure that your yaml is valid and pass this as user-data when starting +# the instance. Also be sure that your cloud.cfg file includes this +# configuration module in the appropirate section. +# +manage-resolv-conf: true + +resolv_conf: + nameservers: ['8.8.4.4', '8.8.8.8'] + searchdomains: + - foo.example.com + - bar.example.com + domain: example.com + options: + rotate: true + timeout: 1 -- cgit v1.2.3 From 3ed65a8030713a18e2fb541f14b77fd5c45b383e Mon Sep 17 00:00:00 2001 From: Joshua Harlow Date: Fri, 25 Jan 2013 17:51:24 -0800 Subject: Integreate HACKING into the rtd site. --- HACKING | 49 +++++++++++++++++++++++++++++---------------- doc/rtd/conf.py | 2 +- doc/rtd/index.rst | 2 +- doc/rtd/topics/moreinfo.rst | 2 +- 4 files changed, 35 insertions(+), 20 deletions(-) (limited to 'doc') diff --git a/HACKING b/HACKING index 433738da..66bf7c90 100644 --- a/HACKING +++ b/HACKING @@ -4,30 +4,45 @@ Hacking on cloud-init To get changes into cloud-init, the process to follow is: - * If you have not already, be sure to sign the CCA: - - `Canonical Contributor Agreement`_ +* If you have not already, be sure to sign the CCA: - * Get your changes into a local bzr branch. Initialize a repo, and checkout trunk (init repo is to share bzr info across multiple checkouts, its different than git): - - ``bzr init-repo cloud-init`` - - ``bzr branch lp:cloud-init trunk.dist`` - - ``bzr branch trunk.dist my-topic-branch`` + - `Canonical Contributor Agreement`_ - * Commit your changes (note, you can make multiple commits, fixes, more commits.): - - ``bzr commit`` +* Get your changes into a local bzr branch. + Initialize a repo, and checkout trunk (init repo is to share bzr info across multiple checkouts, its different than git): - * Check pylint and pep8 and test, and address any issues: - - ``make test pylint pep8`` + - ``bzr init-repo cloud-init`` + - ``bzr branch lp:cloud-init trunk.dist`` + - ``bzr branch trunk.dist my-topic-branch`` - * Push to launchpad to a personal branch: - - ``bzr push lp:~/cloud-init/`` +* Commit your changes (note, you can make multiple commits, fixes, more commits.): - * Propose that for a merge into lp:cloud-init via web browser. Open the branch in `Launchpad`_, it will be at https://code.launchpad.net/// (ie. https://code.launchpad.net/~smoser/cloud-init/mybranch): - - Click 'Propose for merging' - - Select 'lp:cloud-init' as the target branch + - ``bzr commit`` -Then, someone on cloud-init-dev (currently Scott Moser and Joshua Harlow) will review your changes and follow up in the merge request. +* Check pylint and pep8 and test, and address any issues: -Feel free to ping #cloud-init on freenode if you have any questions. + - ``make test pylint pep8`` + +* Push to launchpad to a personal branch: + + - ``bzr push lp:~/cloud-init/`` + +* Propose that for a merge into lp:cloud-init via web browser. + + - Open the branch in `Launchpad`_ + + - It will typically be at ``https://code.launchpad.net///`` + - ie. https://code.launchpad.net/~smoser/cloud-init/mybranch + +* Click 'Propose for merging' +* Select 'lp:cloud-init' as the target branch + +Then, someone on cloud-init-dev (currently `Scott Moser`_ and `Joshua Harlow`_) will +review your changes and follow up in the merge request. + +Feel free to ping and/or join #cloud-init on freenode (irc) if you have any questions. .. _Launchpad: https://launchpad.net .. _Canonical Contributor Agreement: http://www.canonical.com/contributors +.. _Scott Moser: https://launchpad.net/~smoser +.. _Joshua Harlow: https://launchpad.net/~harlowja diff --git a/doc/rtd/conf.py b/doc/rtd/conf.py index 766f9e93..87fc40ab 100644 --- a/doc/rtd/conf.py +++ b/doc/rtd/conf.py @@ -42,7 +42,7 @@ master_doc = 'index' # |version| and |release|, also used in various other places throughout the # built documents. version = version.version_string() -# release = version +release = version # Set the default Pygments syntax highlight_language = 'python' diff --git a/doc/rtd/index.rst b/doc/rtd/index.rst index f878dbd4..53b39a31 100644 --- a/doc/rtd/index.rst +++ b/doc/rtd/index.rst @@ -24,6 +24,6 @@ Summary topics/examples topics/modules topics/moreinfo - + topics/hacking .. _Cloud-init: https://launchpad.net/cloud-init diff --git a/doc/rtd/topics/moreinfo.rst b/doc/rtd/topics/moreinfo.rst index 2e436c3c..19e96af0 100644 --- a/doc/rtd/topics/moreinfo.rst +++ b/doc/rtd/topics/moreinfo.rst @@ -3,7 +3,7 @@ More information ========= Useful external references ----------------- +------------------------- - `The beauty of cloudinit`_ - `Introduction to cloud-init`_ (video) -- cgit v1.2.3 From cabd9653546586d2370d9c1d81f14e12dd28b94b Mon Sep 17 00:00:00 2001 From: Joshua Harlow Date: Fri, 25 Jan 2013 17:53:33 -0800 Subject: Don't forget the hacking 'inclusion' file. --- doc/rtd/topics/hacking.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/rtd/topics/hacking.rst (limited to 'doc') diff --git a/doc/rtd/topics/hacking.rst b/doc/rtd/topics/hacking.rst new file mode 100644 index 00000000..350265eb --- /dev/null +++ b/doc/rtd/topics/hacking.rst @@ -0,0 +1 @@ +.. include:: ../../../HACKING -- cgit v1.2.3 From 62f0f1745677e3422b12a9aaa96ba3e5452db94d Mon Sep 17 00:00:00 2001 From: Joshua Harlow Date: Mon, 28 Jan 2013 10:28:09 -0800 Subject: Include the resolv.conf example. --- doc/rtd/topics/examples.rst | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'doc') diff --git a/doc/rtd/topics/examples.rst b/doc/rtd/topics/examples.rst index 9bbc33cc..36508bde 100644 --- a/doc/rtd/topics/examples.rst +++ b/doc/rtd/topics/examples.rst @@ -27,13 +27,25 @@ Adding a yum repository :language: yaml :linenos: -Configure an instance's trusted CA certificates +Configure an instances trusted CA certificates ------------------------------------------------------ .. literalinclude:: ../../examples/cloud-config-ca-certs.txt :language: yaml :linenos: +Configure an instances resolv.conf +------------------------------------------------------ + +*Note:* when using a config drive and a RHEL like system resolv.conf +will also be managed 'automatically' due to the available information +provided for dns servers in the config drive network format. For those +that wish to have different settings use this module. + +.. literalinclude:: ../../examples/cloud-config-resolv-conf.txt + :language: yaml + :linenos: + Install and run `chef`_ recipes ------------------------------------------------------ -- cgit v1.2.3 From 9ced60371239eb961e9919f13bda8b496e077411 Mon Sep 17 00:00:00 2001 From: ctracey Date: Wed, 30 Jan 2013 19:21:37 -0500 Subject: Support package versions for the generic package config module Augmenting the package version support to be available when specifying extra packages to be installed at boot via the 'packages:' yaml key. This change also improves type checking and add a configuration example to the docs. --- cloudinit/util.py | 23 +++++++++++++---------- doc/examples/cloud-config-install-packages.txt | 4 ++++ 2 files changed, 17 insertions(+), 10 deletions(-) (limited to 'doc') diff --git a/cloudinit/util.py b/cloudinit/util.py index c9c5f794..ffe844b2 100644 --- a/cloudinit/util.py +++ b/cloudinit/util.py @@ -402,10 +402,9 @@ def get_cfg_option_list(yobj, key, default=None): return [] val = yobj[key] if isinstance(val, (list)): - # Should we ensure they are all strings?? - cval = [str(v) for v in val] + cval = [v for v in val] return cval - if not isinstance(val, (str, basestring)): + if not isinstance(val, (basestring)): val = str(val) return [val] @@ -1569,17 +1568,21 @@ def expand_package_list(version_fmt, pkgs): pkglist = [] for pkg in pkgs: - if isinstance(pkg, str): + if isinstance(pkg, basestring): pkglist.append(pkg) continue - if len(pkg) < 1 or len(pkg) > 2: - raise RuntimeError("Invalid package_command tuple.") + if isinstance(pkg, (tuple, list)): + if len(pkg) < 1 or len(pkg) > 2: + raise RuntimeError("Invalid package & version tuple.") - if len(pkg) == 2 and pkg[1]: - pkglist.append(version_fmt % pkg) - continue + if len(pkg) == 2 and pkg[1]: + pkglist.append(version_fmt % tuple(pkg)) + continue - pkglist.append(pkg[0]) + pkglist.append(pkg[0]) + + else: + raise RuntimeError("Invalid package type.") return pkglist diff --git a/doc/examples/cloud-config-install-packages.txt b/doc/examples/cloud-config-install-packages.txt index 4984818f..2edc63da 100644 --- a/doc/examples/cloud-config-install-packages.txt +++ b/doc/examples/cloud-config-install-packages.txt @@ -6,6 +6,10 @@ # # if packages are specified, this apt_update will be set to true # +# packages may be supplied as a single package name or as a list +# with the format [, ] wherein the specifc +# package version will be installed. packages: - pwgen - pastebinit + - [libpython2.7, 2.7.3-0ubuntu3.1] -- cgit v1.2.3 From 50222a4a387e5e013bc48df7a7a208698368a527 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Thu, 31 Jan 2013 08:14:54 -0500 Subject: doc: fix example in cloud-config-write-files.txt The write_files documentation incorrectly used 'perms' rather than 'permissions'. LP: #1111205 --- ChangeLog | 2 ++ doc/examples/cloud-config-write-files.txt | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'doc') diff --git a/ChangeLog b/ChangeLog index e1b08d30..3a688ad0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -34,6 +34,8 @@ debian, fedora, rhel) (LP: #1100029) - fix /etc/hosts writing when templates are used (LP: #1100036) - add package versioning logic to package installation functionality (LP: #1108047) + - fix documentation for write_files to correctly list 'permissions' + rather than 'perms' (LP: #1111205) 0.7.1: - sysvinit: fix missing dependency in cloud-init job for RHEL 5.6 - config-drive: map hostname to local-hostname (LP: #1061964) diff --git a/doc/examples/cloud-config-write-files.txt b/doc/examples/cloud-config-write-files.txt index 9c4e3998..ec98bc93 100644 --- a/doc/examples/cloud-config-write-files.txt +++ b/doc/examples/cloud-config-write-files.txt @@ -12,7 +12,7 @@ write_files: content: CiMgVGhpcyBmaWxlIGNvbnRyb2xzIHRoZSBzdGF0ZSBvZiBTRUxpbnV4... owner: root:root path: /etc/sysconfig/selinux - perms: '0644' + permissions: '0644' - content: | # My new /etc/sysconfig/samba file @@ -24,10 +24,10 @@ write_files: AAAAAAAAAwAAAAQAAAAAAgAAAAAAAAACQAAAAAAAAAJAAAAAAAAcAAAAAAAAABwAAAAAAAAAAQAA .... path: /bin/arch - perms: '0555' + permissions: '0555' - encoding: gzip content: !!binary | H4sIAIDb/U8C/1NW1E/KzNMvzuBKTc7IV8hIzcnJVyjPL8pJ4QIA6N+MVxsAAAA= path: /usr/bin/hello - perms: '0755' + permissions: '0755' -- cgit v1.2.3 From f3b25e68ac6d28cdacf7408c91da6e9a215ad1e6 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Mon, 4 Feb 2013 22:23:42 -0500 Subject: make config of nocloud datasource able to specify meta-data and user-data LP: #1115833 --- cloudinit/sources/DataSourceNoCloud.py | 72 ++++++++++++++++++------------- doc/examples/cloud-config-datasources.txt | 11 +++++ 2 files changed, 52 insertions(+), 31 deletions(-) (limited to 'doc') diff --git a/cloudinit/sources/DataSourceNoCloud.py b/cloudinit/sources/DataSourceNoCloud.py index bed500a2..d8484437 100644 --- a/cloudinit/sources/DataSourceNoCloud.py +++ b/cloudinit/sources/DataSourceNoCloud.py @@ -77,37 +77,47 @@ class DataSourceNoCloud(sources.DataSource): found.append("ds_config") md["seedfrom"] = self.ds_cfg['seedfrom'] - fslist = util.find_devs_with("TYPE=vfat") - fslist.extend(util.find_devs_with("TYPE=iso9660")) - - label_list = util.find_devs_with("LABEL=cidata") - devlist = list(set(fslist) & set(label_list)) - devlist.sort(reverse=True) - - for dev in devlist: - try: - LOG.debug("Attempting to use data from %s", dev) - - (newmd, newud) = util.mount_cb(dev, util.read_seeded) - md = util.mergedict(newmd, md) - ud = newud - - # For seed from a device, the default mode is 'net'. - # that is more likely to be what is desired. - # If they want dsmode of local, then they must - # specify that. - if 'dsmode' not in md: - md['dsmode'] = "net" - - LOG.debug("Using data from %s", dev) - found.append(dev) - break - except OSError as e: - if e.errno != errno.ENOENT: - raise - except util.MountFailedError: - util.logexc(LOG, ("Failed to mount %s" - " when looking for data"), dev) + # if ds_cfg has 'user-data' and 'meta-data' + if 'user-data' in self.ds_cfg and 'meta-data' in self.ds_cfg: + if self.ds_cfg['user-data']: + ud = util.mergedict(md, self.ds_cfg['user-data']) + if self.ds_cfg['meta-data'] is not False: + md = util.mergedict(md, self.ds_cfg['meta-data']) + if 'ds_config' not in found: + found.append("ds_config") + + if self.ds_cfg.get('fs_label', "cidata"): + fslist = util.find_devs_with("TYPE=vfat") + fslist.extend(util.find_devs_with("TYPE=iso9660")) + + label = self.ds_cfg.get('fs_label') + label_list = util.find_devs_with("LABEL=%s" % label) + devlist = list(set(fslist) & set(label_list)) + devlist.sort(reverse=True) + + for dev in devlist: + try: + LOG.debug("Attempting to use data from %s", dev) + + (newmd, newud) = util.mount_cb(dev, util.read_seeded) + md = util.mergedict(newmd, md) + ud = newud + + # For seed from a device, the default mode is 'net'. + # that is more likely to be what is desired. If they want + # dsmode of local, then they must specify that. + if 'dsmode' not in md: + md['dsmode'] = "net" + + LOG.debug("Using data from %s", dev) + found.append(dev) + break + except OSError as e: + if e.errno != errno.ENOENT: + raise + except util.MountFailedError: + util.logexc(LOG, ("Failed to mount %s" + " when looking for data"), dev) # There was no indication on kernel cmdline or data # in the seeddir suggesting this handler should be used. diff --git a/doc/examples/cloud-config-datasources.txt b/doc/examples/cloud-config-datasources.txt index d10dde05..fc8c22d4 100644 --- a/doc/examples/cloud-config-datasources.txt +++ b/doc/examples/cloud-config-datasources.txt @@ -31,3 +31,14 @@ datasource: # /user-data and /meta-data # seedfrom: http://my.example.com/i-abcde seedfrom: None + + # fs_label: the label on filesystems to be searched for NoCloud source + fs_label: cidata + + # these are optional, but allow you to basically provide a datasource + # right here + user-data: | + # This is the user-data verbatum + meta-data: + instance-id: i-87018aed + local-hostname: myhost.internal -- cgit v1.2.3 From bedf5ae6d1e81209acff81fc688f98267f9b7cf2 Mon Sep 17 00:00:00 2001 From: harlowja Date: Mon, 4 Feb 2013 23:10:36 -0800 Subject: Add initial docs about datasources. Start moving the current README for datasources to a RST format and include those files in the rtd site. LP: #1113650 --- HACKING | 48 --------------- HACKING.rst | 48 +++++++++++++++ doc/rtd/index.rst | 1 + doc/rtd/topics/datasources.rst | 99 +++++++++++++++++++++++++++++ doc/rtd/topics/dir_layout.rst | 6 +- doc/rtd/topics/hacking.rst | 2 +- doc/sources/altcloud/README | 65 -------------------- doc/sources/altcloud/README.rst | 87 ++++++++++++++++++++++++++ doc/sources/configdrive/README | 118 ----------------------------------- doc/sources/configdrive/README.rst | 123 +++++++++++++++++++++++++++++++++++++ doc/sources/nocloud/README | 55 ----------------- doc/sources/nocloud/README.rst | 71 +++++++++++++++++++++ 12 files changed, 433 insertions(+), 290 deletions(-) delete mode 100644 HACKING create mode 100644 HACKING.rst create mode 100644 doc/rtd/topics/datasources.rst delete mode 100644 doc/sources/altcloud/README create mode 100644 doc/sources/altcloud/README.rst delete mode 100644 doc/sources/configdrive/README create mode 100644 doc/sources/configdrive/README.rst delete mode 100644 doc/sources/nocloud/README create mode 100644 doc/sources/nocloud/README.rst (limited to 'doc') diff --git a/HACKING b/HACKING deleted file mode 100644 index 66bf7c90..00000000 --- a/HACKING +++ /dev/null @@ -1,48 +0,0 @@ -===================== -Hacking on cloud-init -===================== - -To get changes into cloud-init, the process to follow is: - -* If you have not already, be sure to sign the CCA: - - - `Canonical Contributor Agreement`_ - -* Get your changes into a local bzr branch. - Initialize a repo, and checkout trunk (init repo is to share bzr info across multiple checkouts, its different than git): - - - ``bzr init-repo cloud-init`` - - ``bzr branch lp:cloud-init trunk.dist`` - - ``bzr branch trunk.dist my-topic-branch`` - -* Commit your changes (note, you can make multiple commits, fixes, more commits.): - - - ``bzr commit`` - -* Check pylint and pep8 and test, and address any issues: - - - ``make test pylint pep8`` - -* Push to launchpad to a personal branch: - - - ``bzr push lp:~/cloud-init/`` - -* Propose that for a merge into lp:cloud-init via web browser. - - - Open the branch in `Launchpad`_ - - - It will typically be at ``https://code.launchpad.net///`` - - ie. https://code.launchpad.net/~smoser/cloud-init/mybranch - -* Click 'Propose for merging' -* Select 'lp:cloud-init' as the target branch - -Then, someone on cloud-init-dev (currently `Scott Moser`_ and `Joshua Harlow`_) will -review your changes and follow up in the merge request. - -Feel free to ping and/or join #cloud-init on freenode (irc) if you have any questions. - -.. _Launchpad: https://launchpad.net -.. _Canonical Contributor Agreement: http://www.canonical.com/contributors -.. _Scott Moser: https://launchpad.net/~smoser -.. _Joshua Harlow: https://launchpad.net/~harlowja diff --git a/HACKING.rst b/HACKING.rst new file mode 100644 index 00000000..66bf7c90 --- /dev/null +++ b/HACKING.rst @@ -0,0 +1,48 @@ +===================== +Hacking on cloud-init +===================== + +To get changes into cloud-init, the process to follow is: + +* If you have not already, be sure to sign the CCA: + + - `Canonical Contributor Agreement`_ + +* Get your changes into a local bzr branch. + Initialize a repo, and checkout trunk (init repo is to share bzr info across multiple checkouts, its different than git): + + - ``bzr init-repo cloud-init`` + - ``bzr branch lp:cloud-init trunk.dist`` + - ``bzr branch trunk.dist my-topic-branch`` + +* Commit your changes (note, you can make multiple commits, fixes, more commits.): + + - ``bzr commit`` + +* Check pylint and pep8 and test, and address any issues: + + - ``make test pylint pep8`` + +* Push to launchpad to a personal branch: + + - ``bzr push lp:~/cloud-init/`` + +* Propose that for a merge into lp:cloud-init via web browser. + + - Open the branch in `Launchpad`_ + + - It will typically be at ``https://code.launchpad.net///`` + - ie. https://code.launchpad.net/~smoser/cloud-init/mybranch + +* Click 'Propose for merging' +* Select 'lp:cloud-init' as the target branch + +Then, someone on cloud-init-dev (currently `Scott Moser`_ and `Joshua Harlow`_) will +review your changes and follow up in the merge request. + +Feel free to ping and/or join #cloud-init on freenode (irc) if you have any questions. + +.. _Launchpad: https://launchpad.net +.. _Canonical Contributor Agreement: http://www.canonical.com/contributors +.. _Scott Moser: https://launchpad.net/~smoser +.. _Joshua Harlow: https://launchpad.net/~harlowja diff --git a/doc/rtd/index.rst b/doc/rtd/index.rst index 53b39a31..619bb5dc 100644 --- a/doc/rtd/index.rst +++ b/doc/rtd/index.rst @@ -22,6 +22,7 @@ Summary topics/format topics/dir_layout topics/examples + topics/datasources topics/modules topics/moreinfo topics/hacking diff --git a/doc/rtd/topics/datasources.rst b/doc/rtd/topics/datasources.rst new file mode 100644 index 00000000..c2354ace --- /dev/null +++ b/doc/rtd/topics/datasources.rst @@ -0,0 +1,99 @@ +.. _datasources: + +========= +Datasources +========= +---------- + What is a datasource? +---------- + +Datasources are sources of configuration data for cloud-init that typically come +from the user (aka userdata) or come from the stack that created the configuration +drive (aka metadata). Typical userdata would include files, yaml, and shell scripts +while typical metadata would include server name, instance id, display name and other +cloud specific details. Since there are multiple ways to provide this data (each cloud +solution seems to prefer its own way) internally a datasource abstract class was +created to allow for a single way to access the different cloud systems methods +to provide this data through the typical usage of subclasses. + +The current interface that a datasource object must provide is the following: + +.. sourcecode:: python + + def get_userdata(self, apply_filter=False) + + @property + def launch_index(self) + + @property + def is_disconnected(self) + + def get_userdata_raw(self) + + # the data sources' config_obj is a cloud-config formated + # object that came to it from ways other than cloud-config + # because cloud-config content would be handled elsewhere + def get_config_obj(self) + + def get_public_ssh_keys(self) + + def device_name_to_device(self, name) + + def get_locale(self) + + @property + def availability_zone(self) + + def get_instance_id(self) + + def get_hostname(self, fqdn=False) + + def get_package_mirror_info(self) + +--------------------------- +EC2 +--------------------------- + +TBD + +--------------------------- +Config Drive +--------------------------- + +.. include:: ../../sources/configdrive/README.rst + +--------------------------- +Alt cloud +--------------------------- + +.. include:: ../../sources/altcloud/README.rst + +--------------------------- +No cloud +--------------------------- + +.. include:: ../../sources/nocloud/README.rst + +--------------------------- +MAAS +--------------------------- + +TBD + +--------------------------- +CloudStack +--------------------------- + +TBD + +--------------------------- +OVF +--------------------------- + +See: https://bazaar.launchpad.net/~cloud-init-dev/cloud-init/trunk/files/head:/doc/sources/ovf/ + +--------------------------- +Fallback/None +--------------------------- + +TBD diff --git a/doc/rtd/topics/dir_layout.rst b/doc/rtd/topics/dir_layout.rst index f072c585..8815d33d 100644 --- a/doc/rtd/topics/dir_layout.rst +++ b/doc/rtd/topics/dir_layout.rst @@ -25,9 +25,9 @@ Cloudinits's directory structure is somewhat different from a regular applicatio - user-data.txt - user-data.txt.i - scripts/ - - per-boot/ - - per-instance/ - - per-once/ + - per-boot/ + - per-instance/ + - per-once/ - seed/ - sem/ diff --git a/doc/rtd/topics/hacking.rst b/doc/rtd/topics/hacking.rst index 350265eb..96ab88ef 100644 --- a/doc/rtd/topics/hacking.rst +++ b/doc/rtd/topics/hacking.rst @@ -1 +1 @@ -.. include:: ../../../HACKING +.. include:: ../../../HACKING.rst diff --git a/doc/sources/altcloud/README b/doc/sources/altcloud/README deleted file mode 100644 index 87d7949a..00000000 --- a/doc/sources/altcloud/README +++ /dev/null @@ -1,65 +0,0 @@ -Data souce AltCloud will be used to pick up user data on -RHEVm and vSphere. - -RHEVm: -====== -For REHVm v3.0 the userdata is injected into the VM using floppy -injection via the RHEVm dashboard "Custom Properties". The format -of the Custom Properties entry must be: -"floppyinject=user-data.txt:" - -e.g.: To pass a simple bash script - -% cat simple_script.bash -#!/bin/bash -echo "Hello Joe!" >> /tmp/JJV_Joe_out.txt - -% base64 < simple_script.bash -IyEvYmluL2Jhc2gKZWNobyAiSGVsbG8gSm9lISIgPj4gL3RtcC9KSlZfSm9lX291dC50eHQK - -To pass this example script to cloud-init running in a RHEVm v3.0 VM -set the "Custom Properties" when creating the RHEMv v3.0 VM to: -floppyinject=user-data.txt:IyEvYmluL2Jhc2gKZWNobyAiSGVsbG8gSm9lISIgPj4gL3RtcC9KSlZfSm9lX291dC50eHQK - -NOTE: The prefix with file name must be: "floppyinject=user-data.txt:" - -It is also possible to launch a RHEVm v3.0 VM and pass optional user -data to it using the Delta Cloud. -For more inforation on Delta Cloud see: http://deltacloud.apache.org - -vSphere: -======== -For VMWare's vSphere the userdata is injected into the VM an ISO -via the cdrom. This can be done using the vSphere dashboard -by connecting an ISO image to the CD/DVD drive. - -To pass this example script to cloud-init running in a vSphere VM -set the CD/DVD drive when creating the vSphere VM to point to an -ISO on the data store. - -The ISO must contain the user data: - -For example, to pass the same simple_script.bash to vSphere: - -Create the ISO: -=============== -% mkdir my-iso - -NOTE: The file name on the ISO must be: "user-data.txt" -% cp simple_scirpt.bash my-iso/user-data.txt - -% genisoimage -o user-data.iso -r my-iso - -Verify the ISO: -=============== -% sudo mkdir /media/vsphere_iso -% sudo mount -o loop JoeV_CI_02.iso /media/vsphere_iso -% cat /media/vsphere_iso/user-data.txt -% sudo umount /media/vsphere_iso - -Then, launch the vSphere VM the ISO user-data.iso attached as a CDrom. - -It is also possible to launch a vSphere VM and pass optional user -data to it using the Delta Cloud. - -For more inforation on Delta Cloud see: http://deltacloud.apache.org diff --git a/doc/sources/altcloud/README.rst b/doc/sources/altcloud/README.rst new file mode 100644 index 00000000..b5d72ebb --- /dev/null +++ b/doc/sources/altcloud/README.rst @@ -0,0 +1,87 @@ +The datasource altcloud will be used to pick up user data on `RHEVm`_ and `vSphere`_. + +RHEVm +~~~~~~ + +For `RHEVm`_ v3.0 the userdata is injected into the VM using floppy +injection via the `RHEVm`_ dashboard "Custom Properties". + +The format of the Custom Properties entry must be: + +:: + + floppyinject=user-data.txt: + +For example to pass a simple bash script: + +:: + + % cat simple_script.bash + #!/bin/bash + echo "Hello Joe!" >> /tmp/JJV_Joe_out.txt + + % base64 < simple_script.bash + IyEvYmluL2Jhc2gKZWNobyAiSGVsbG8gSm9lISIgPj4gL3RtcC9KSlZfSm9lX291dC50eHQK + +To pass this example script to cloud-init running in a `RHEVm`_ v3.0 VM +set the "Custom Properties" when creating the RHEMv v3.0 VM to: + +:: + + floppyinject=user-data.txt:IyEvYmluL2Jhc2gKZWNobyAiSGVsbG8gSm9lISIgPj4gL3RtcC9KSlZfSm9lX291dC50eHQK + +**NOTE:** The prefix with file name must be: ``floppyinject=user-data.txt:`` + +It is also possible to launch a `RHEVm`_ v3.0 VM and pass optional user +data to it using the Delta Cloud. + +For more information on Delta Cloud see: http://deltacloud.apache.org + +vSphere +~~~~~~~~ + +For VMWare's `vSphere`_ the userdata is injected into the VM as an ISO +via the cdrom. This can be done using the `vSphere`_ dashboard +by connecting an ISO image to the CD/DVD drive. + +To pass this example script to cloud-init running in a `vSphere`_ VM +set the CD/DVD drive when creating the vSphere VM to point to an +ISO on the data store. + +**Note:** The ISO must contain the user data. + +For example, to pass the same ``simple_script.bash`` to vSphere: + +Create the ISO +----------------- + +:: + + % mkdir my-iso + +NOTE: The file name on the ISO must be: ``user-data.txt`` + +:: + + % cp simple_scirpt.bash my-iso/user-data.txt + % genisoimage -o user-data.iso -r my-iso + +Verify the ISO +----------------- + +:: + + % sudo mkdir /media/vsphere_iso + % sudo mount -o loop JoeV_CI_02.iso /media/vsphere_iso + % cat /media/vsphere_iso/user-data.txt + % sudo umount /media/vsphere_iso + +Then, launch the `vSphere`_ VM the ISO user-data.iso attached as a CDROM. + +It is also possible to launch a `vSphere`_ VM and pass optional user +data to it using the Delta Cloud. + +For more information on Delta Cloud see: http://deltacloud.apache.org + +.. _RHEVm: https://www.redhat.com/virtualization/rhev/desktop/rhevm/ +.. _vSphere: https://www.vmware.com/products/datacenter-virtualization/vsphere/overview.html diff --git a/doc/sources/configdrive/README b/doc/sources/configdrive/README deleted file mode 100644 index ed9033c9..00000000 --- a/doc/sources/configdrive/README +++ /dev/null @@ -1,118 +0,0 @@ -The 'ConfigDrive' DataSource supports the OpenStack configdrive disk. -See doc/source/api_ext/ext_config_drive.rst in the nova source code for -more information on config drive. - -The following criteria are required to be identified by -DataSourceConfigDrive as a config drive: - * must be formated with vfat filesystem - * must be a un-partitioned block device (/dev/vdb, not /dev/vdb1) - * must contain one of the following files: - * etc/network/interfaces - * root/.ssh/authorized_keys - * meta.js - -By default, cloud-init does not consider this source to be a full-fledged -datasource. Instead, the default behavior is to assume it is really only -present to provide networking information. Cloud-init will copy off the -network information, apply it to the system, and then continue on. The -"full" datasource would then be found in the EC2 metadata service. - -== Content of config-drive == - * etc/network/interfaces - This file is laid down by nova in order to pass static networking - information to the guest. Cloud-init will copy it off of the config-drive - and into /etc/network/interfaces as soon as it can, and then attempt to - bring up all network interfaces. - - * root/.ssh/authorized_keys - This file is laid down by nova, and contains the keys that were - provided to it on instance creation (nova-boot --key ....) - - Cloud-init will copy those keys and put them into the configured user - ('ubuntu') .ssh/authorized_keys. - - * meta.js - meta.js is populated on the config-drive in response to the user passing - "meta flags" (nova boot --meta key=value ...). It is expected to be json - formated. - -== Configuration == -Cloud-init's behavior can be modified by keys found in the meta.js file in -the following ways: - * dsmode: - values: local, net, pass - default: pass - - This is what indicates if configdrive is a final data source or not. - By default it is 'pass', meaning this datasource should not be read. - Set it to 'local' or 'net' to stop cloud-init from continuing on to - search for other data sources after network config. - - The difference between 'local' and 'net' is that local will not require - networking to be up before user-data actions (or boothooks) are run. - - * instance-id: - default: iid-dsconfigdrive - This is utilized as the metadata's instance-id. It should generally - be unique, as it is what is used to determine "is this a new instance". - - * public-keys: - default: None - if present, these keys will be used as the public keys for the - instance. This value overrides the content in authorized_keys. - Note: it is likely preferable to provide keys via user-data - - * user-data: - default: None - This provides cloud-init user-data. See other documentation for what - all can be present here. - -== Example == -Here is an example using the nova client (python-novaclien) - -Assuming the following variables set up: - * img_id : set to the nova image id (uuid from image-list) - * flav_id : set to numeric flavor_id (nova flavor-list) - * keyname : set to name of key for this instance (nova keypair-list) - -$ cat my-user-data -#!/bin/sh -echo ==== USER_DATA FROM EC2 MD ==== | tee /ud.log - -$ ud_value=$(sed 's,EC2 MD,META KEY,') - -## Now, 'ud_value' has same content of my-user-data file, but -## with the string "USER_DATA FROM META KEY" - -## launch an instance with dsmode=pass -## This will really not use the configdrive for anything as the mode -## for the datasource is 'pass', meaning it will still expect some -## other data source (DataSourceEc2). - -$ nova boot --image=$img_id --config-drive=1 --flavor=$flav_id \ - --key_name=$keyname \ - --user_data=my-user-data \ - "--meta=instance-id=iid-001 \ - "--meta=user-data=${ud_keyval}" \ - "--meta=dsmode=pass" cfgdrive-dsmode-pass - -$ euca-get-console-output i-0000001 | grep USER_DATA -echo ==== USER_DATA FROM EC2 MD ==== | tee /ud.log - -## Now, launch an instance with dsmode=local -## This time, the only metadata and userdata available to cloud-init -## are on the config-drive -$ nova boot --image=$img_id --config-drive=1 --flavor=$flav_id \ - --key_name=$keyname \ - --user_data=my-user-data \ - "--meta=instance-id=iid-001 \ - "--meta=user-data=${ud_keyval}" \ - "--meta=dsmode=local" cfgdrive-dsmode-local - -$ euca-get-console-output i-0000002 | grep USER_DATA -echo ==== USER_DATA FROM META KEY ==== | tee /ud.log - --- -[1] https://github.com/openstack/nova/blob/master/doc/source/api_ext/ext_config_drive.rst for more if - - diff --git a/doc/sources/configdrive/README.rst b/doc/sources/configdrive/README.rst new file mode 100644 index 00000000..797872ad --- /dev/null +++ b/doc/sources/configdrive/README.rst @@ -0,0 +1,123 @@ +The configuration drive datasource supports the `OpenStack`_ configuration drive disk. + + See `the config drive extension`_ and `introduction`_ in the public + documentation for more information. + +By default, cloud-init does *always* consider this source to be a full-fledged +datasource. Instead, the typical behavior is to assume it is really only +present to provide networking information. Cloud-init will copy off the +network information, apply it to the system, and then continue on. The +"full" datasource could then be found in the EC2 metadata service. If this is +not the case then the files contained on the located drive must provide equivalents +to what the EC2 metadata service would provide (which is typical of the version +2 support listed below) + +Version 1 +~~~~~~~~~ + +The following criteria are required to as a config drive: + +1. Must be formatted with `vfat`_ filesystem +2. Must be a un-partitioned block device (/dev/vdb, not /dev/vdb1) +3. Must contain *one* of the following files + +:: + + /etc/network/interfaces + /root/.ssh/authorized_keys + /meta.js + +``/etc/network/interfaces`` + + This file is laid down by nova in order to pass static networking + information to the guest. Cloud-init will copy it off of the config-drive + and into /etc/network/interfaces (or convert it to RH format) as soon as it can, + and then attempt to bring up all network interfaces. + +``/root/.ssh/authorized_keys`` + + This file is laid down by nova, and contains the ssk keys that were + provided to nova on instance creation (nova-boot --key ....) + +``/meta.js`` + + meta.js is populated on the config-drive in response to the user passing + "meta flags" (nova boot --meta key=value ...). It is expected to be json + formatted. + +Version 2 +~~~~~~~~~~~ + +The following criteria are required to as a config drive: + +1. Must be formatted with `vfat`_ or `iso9660`_ filesystem + or have a *filesystem* label of **config-2** +2. Must be a un-partitioned block device (/dev/vdb, not /dev/vdb1) +3. The files that will typically be present in the config drive are: + +:: + + openstack/ + - 2012-08-10/ or latest/ + - meta_data.json + - user_data (not mandatory) + - content/ + - 0000 (referenced content files) + - 0001 + - .... + ec2 + - latest/ + - meta-data.json (not mandatory) + +Keys and values +~~~~~~~~~~~ + +Cloud-init's behavior can be modified by keys found in the meta.js (version 1 only) file in the following ways. + +:: + + dsmode: + values: local, net, pass + default: pass + + +This is what indicates if configdrive is a final data source or not. +By default it is 'pass', meaning this datasource should not be read. +Set it to 'local' or 'net' to stop cloud-init from continuing on to +search for other data sources after network config. + +The difference between 'local' and 'net' is that local will not require +networking to be up before user-data actions (or boothooks) are run. + +:: + + instance-id: + default: iid-dsconfigdrive + +This is utilized as the metadata's instance-id. It should generally +be unique, as it is what is used to determine "is this a new instance". + +:: + + public-keys: + default: None + +If present, these keys will be used as the public keys for the +instance. This value overrides the content in authorized_keys. + +Note: it is likely preferable to provide keys via user-data + +:: + + user-data: + default: None + +This provides cloud-init user-data. See :ref:`examples ` for +what all can be present here. + +.. _OpenStack: http://www.openstack.org/ +.. _introduction: http://docs.openstack.org/trunk/openstack-compute/admin/content/config-drive.html +.. _python-novaclient: https://github.com/openstack/python-novaclient +.. _iso9660: https://en.wikipedia.org/wiki/ISO_9660 +.. _vfat: https://en.wikipedia.org/wiki/File_Allocation_Table +.. _the config drive extension: http://docs.openstack.org/developer/nova/api_ext/ext_config_drive.html diff --git a/doc/sources/nocloud/README b/doc/sources/nocloud/README deleted file mode 100644 index c94b206a..00000000 --- a/doc/sources/nocloud/README +++ /dev/null @@ -1,55 +0,0 @@ -The data source 'NoCloud' and 'NoCloudNet' allow the user to provide user-data -and meta-data to the instance without running a network service (or even without -having a network at all) - -You can provide meta-data and user-data to a local vm boot via files on a vfat -or iso9660 filesystem. These user-data and meta-data files are expected to be -in the format described in doc/example/seed/README . Basically, user-data is -simply user-data and meta-data is a yaml formated file representing what you'd -find in the EC2 metadata service. - -Given a disk 12.04 cloud image in 'disk.img', you can create a sufficient disk -by following the example below. - -## create user-data and meta-data files that will be used -## to modify image on first boot -$ { echo instance-id: iid-local01; echo local-hostname: cloudimg; } > meta-data - -$ printf "#cloud-config\npassword: passw0rd\nchpasswd: { expire: False }\nssh_pwauth: True\n" > user-data - -## create a disk to attach with some user-data and meta-data -$ genisoimage -output seed.iso -volid cidata -joliet -rock user-data meta-data - -## alternatively, create a vfat filesystem with same files -## $ truncate --size 2M seed.img -## $ mkfs.vfat -n cidata seed.img -## $ mcopy -oi seed.img user-data meta-data :: - -## create a new qcow image to boot, backed by your original image -$ qemu-img create -f qcow2 -b disk.img boot-disk.img - -## boot the image and login as 'ubuntu' with password 'passw0rd' -## note, passw0rd was set as password through the user-data above, -## there is no password set on these images. -$ kvm -m 256 \ - -net nic -net user,hostfwd=tcp::2222-:22 \ - -drive file=boot-disk.img,if=virtio \ - -drive file=seed.iso,if=virtio - -Note, that the instance-id provided ('iid-local01' above) is what is used to -determine if this is "first boot". So if you are making updates to user-data -you will also have to change that, or start the disk fresh. - - -Also, you can inject an /etc/network/interfaces file by providing the content -for that file in the 'network-interfaces' field of metadata. Example metadata: - instance-id: iid-abcdefg - network-interfaces: | - iface eth0 inet static - address 192.168.1.10 - network 192.168.1.0 - netmask 255.255.255.0 - broadcast 192.168.1.255 - gateway 192.168.1.254 - hostname: myhost - diff --git a/doc/sources/nocloud/README.rst b/doc/sources/nocloud/README.rst new file mode 100644 index 00000000..aa3cf1a3 --- /dev/null +++ b/doc/sources/nocloud/README.rst @@ -0,0 +1,71 @@ +The data source ``NoCloud`` and ``NoCloudNet`` allow the user to provide user-data +and meta-data to the instance without running a network service (or even without +having a network at all). + +You can provide meta-data and user-data to a local vm boot via files on a `vfat`_ +or `iso9660`_ filesystem. + +These user-data and meta-data files are expected to be +in the following format. + +:: + + /user-data + /meta-data + +Basically, user-data is simply user-data and meta-data is a yaml formatted file +representing what you'd find in the EC2 metadata service. + +Given a disk ubuntu 12.04 cloud image in 'disk.img', you can create a sufficient disk +by following the example below. + +:: + + ## create user-data and meta-data files that will be used + ## to modify image on first boot + $ { echo instance-id: iid-local01; echo local-hostname: cloudimg; } > meta-data + + $ printf "#cloud-config\npassword: passw0rd\nchpasswd: { expire: False }\nssh_pwauth: True\n" > user-data + + ## create a disk to attach with some user-data and meta-data + $ genisoimage -output seed.iso -volid cidata -joliet -rock user-data meta-data + + ## alternatively, create a vfat filesystem with same files + ## $ truncate --size 2M seed.img + ## $ mkfs.vfat -n cidata seed.img + ## $ mcopy -oi seed.img user-data meta-data :: + + ## create a new qcow image to boot, backed by your original image + $ qemu-img create -f qcow2 -b disk.img boot-disk.img + + ## boot the image and login as 'ubuntu' with password 'passw0rd' + ## note, passw0rd was set as password through the user-data above, + ## there is no password set on these images. + $ kvm -m 256 \ + -net nic -net user,hostfwd=tcp::2222-:22 \ + -drive file=boot-disk.img,if=virtio \ + -drive file=seed.iso,if=virtio + +**Note:** that the instance-id provided (``iid-local01`` above) is what is used to +determine if this is "first boot". So if you are making updates to user-data +you will also have to change that, or start the disk fresh. + +Also, you can inject an ``/etc/network/interfaces`` file by providing the content +for that file in the ``network-interfaces`` field of metadata. + +Example metadata: + +:: + + instance-id: iid-abcdefg + network-interfaces: | + iface eth0 inet static + address 192.168.1.10 + network 192.168.1.0 + netmask 255.255.255.0 + broadcast 192.168.1.255 + gateway 192.168.1.254 + hostname: myhost + +.. _iso9660: https://en.wikipedia.org/wiki/ISO_9660 +.. _vfat: https://en.wikipedia.org/wiki/File_Allocation_Table -- cgit v1.2.3 From abe6ca57cd74e68959e7839c7abf6073631f3b49 Mon Sep 17 00:00:00 2001 From: harlowja Date: Tue, 5 Feb 2013 23:58:49 -0800 Subject: Continue adding datasource docs. Add a base set for ec2 and datasource none. --- doc/rtd/topics/datasources.rst | 113 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 103 insertions(+), 10 deletions(-) (limited to 'doc') diff --git a/doc/rtd/topics/datasources.rst b/doc/rtd/topics/datasources.rst index c2354ace..59c58805 100644 --- a/doc/rtd/topics/datasources.rst +++ b/doc/rtd/topics/datasources.rst @@ -20,32 +20,52 @@ The current interface that a datasource object must provide is the following: .. sourcecode:: python + # returns a mime multipart message that contains + # all the various fully-expanded components that + # were found from processing the raw userdata string + # - when filtering only the mime messages targeting + # this instance id will be returned (or messages with + # no instance id) def get_userdata(self, apply_filter=False) - @property - def launch_index(self) + # returns the raw userdata string (or none) + def get_userdata_raw(self) + # returns a integer (or none) which can be used to identify + # this instance in a group of instances which are typically + # created from a single command, thus allowing programatic + # filtering on this launch index (or other selective actions) @property - def is_disconnected(self) - - def get_userdata_raw(self) + def launch_index(self) # the data sources' config_obj is a cloud-config formated # object that came to it from ways other than cloud-config # because cloud-config content would be handled elsewhere def get_config_obj(self) + #returns a list of public ssh keys def get_public_ssh_keys(self) + # translates a device 'short' name into the actual physical device + # fully qualified name (or none if said physical device is not attached + # or does not exist) def device_name_to_device(self, name) + # gets the locale string this instance should be applying + # which typically used to adjust the instances locale settings files def get_locale(self) @property def availability_zone(self) + # gets the instance id that was assigned to this instance by the + # cloud provider or when said instance id does not exist in the backing + # metadata this will return 'iid-datasource' def get_instance_id(self) + # gets the fully qualified domain name that this host should be using + # when configuring network or hostname releated settings, typically + # assigned either by the cloud provider or the user creating the vm def get_hostname(self, fqdn=False) def get_package_mirror_info(self) @@ -54,7 +74,65 @@ The current interface that a datasource object must provide is the following: EC2 --------------------------- -TBD +The EC2 datasource is the oldest and most widely used datasource that cloud-init +supports. This datasource interacts with a *magic* ip that is provided to the +instance by the cloud provider. Typically this ip is ``169.254.169.254`` of which +at this ip a http server is provided to the instance so that the instance can make +calls to get instance userdata and instance metadata. + +Metadata is accessible via the following URL: + +:: + + GET http://169.254.169.254/2009-04-04/meta-data/ + ami-id + ami-launch-index + ami-manifest-path + block-device-mapping/ + hostname + instance-id + instance-type + local-hostname + local-ipv4 + placement/ + public-hostname + public-ipv4 + public-keys/ + reservation-id + security-groups + +Userdata is accessible via the following URL: + +:: + + GET http://169.254.169.254/2009-04-04/user-data + 1234,fred,reboot,true | 4512,jimbo, | 173,,, + +Note that there are multiple versions of this data provided, cloud-init +by default uses **2009-04-04** but newer versions can be supported with +relative ease (newer versions have more data exposed, while maintaining +backward compatibility with the previous versions). + +To see which versions are supported from your cloud provider use the following URL: + +:: + + GET http://169.254.169.254/ + 1.0 + 2007-01-19 + 2007-03-01 + 2007-08-29 + 2007-10-10 + 2007-12-15 + 2008-02-01 + 2008-09-01 + 2009-04-04 + ... + latest + +**Note:** internally in cloudinit the `boto`_ library used to fetch the instance +userdata and instance metadata, feel free to check that library out, it provides +many other useful EC2 functionality. --------------------------- Config Drive @@ -78,22 +156,37 @@ No cloud MAAS --------------------------- -TBD +*TODO* + +For now see: http://maas.ubuntu.com/ --------------------------- CloudStack --------------------------- -TBD +*TODO* --------------------------- OVF --------------------------- -See: https://bazaar.launchpad.net/~cloud-init-dev/cloud-init/trunk/files/head:/doc/sources/ovf/ +*TODO* + +For now see: https://bazaar.launchpad.net/~cloud-init-dev/cloud-init/trunk/files/head:/doc/sources/ovf/ --------------------------- Fallback/None --------------------------- -TBD +This is the fallback datasource when no other datasource can be selected. It is +the equivalent of a *empty* datasource in that it provides a empty string as userdata +and a empty dictionary as metadata. It is useful for testing as well as for when +you do not have a need to have an actual datasource to meet your instance +requirements (ie you just want to run modules that are not concerned with any +external data). It is typically put at the end of the datasource search list +so that if all other datasources are not matched, then this one will be so that +the user is not left with an inaccessible instance. + +**Note:** the instance id that this datasource provides is ``iid-datasource-none``. + +.. _boto: http://docs.pythonboto.org/en/latest/ -- cgit v1.2.3