From 7b2fc4e014e6b7a43e6b8fc719d82c3d0b0a8bed Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Wed, 4 Apr 2012 21:35:32 -0400 Subject: initial checkin of kernel commandline cloud-config url support --- cloudinit/__init__.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ cloudinit/util.py | 13 +++++++++++++ 2 files changed, 57 insertions(+) (limited to 'cloudinit') diff --git a/cloudinit/__init__.py b/cloudinit/__init__.py index 6d276d84..0b46dde9 100644 --- a/cloudinit/__init__.py +++ b/cloudinit/__init__.py @@ -137,7 +137,27 @@ class CloudInit: if ds_deps != None: self.ds_deps = ds_deps + self.sysconfig = sysconfig + + if DataSource.DEP_NETWORK in self.ds_deps: + target = "%s.d/%s" % (self.sysconfig, "91_kernel_cmdline_url.cfg") + if os.path.exists(target): + log.debug("cmdline: %s existed" % target) + else: + try: + (key, url, content) = get_cmdline_url() + if key and content: + util.write_file(target, content, mode=0600) + log.debug("cmdline: wrote %s from %s, %s" % + (target, key, url)) + elif key: + log.debug("cmdline: %s, %s had no cloud-config" % + (key, url)) + except Exception: + util.logexc(log) + log.warn("cmdline: exception occurred while reading") + self.cfg = self.read_cfg() def read_cfg(self): @@ -639,3 +659,27 @@ class InternalPartHandler: def handle_part(self, data, ctype, filename, payload, frequency): return(self.handler(data, ctype, filename, payload, frequency)) + + +def get_cmdline_url(names=('cloud-config-url', 'url'), + starts="#cloud-config", cmdline=None): + + if cmdline == None: + cmdline = util.get_cmdline() + + data = util.keyval_str_to_dict(cmdline) + url = None + key = None + for key in names: + if key in data: + url = data[key] + break + if url == None: + return (None, None, None) + + contents = util.readurl(url) + + if contents.startswith(starts): + return (key, url, contents) + + return (key, url, None) diff --git a/cloudinit/util.py b/cloudinit/util.py index 9133426c..47397418 100644 --- a/cloudinit/util.py +++ b/cloudinit/util.py @@ -840,3 +840,16 @@ def wait_for_url(urls, max_wait=None, timeout=None, time.sleep(sleeptime) return False + + +def keyval_str_to_dict(kvstring): + ret = {} + for tok in kvstring.split(): + try: + (key, val) = tok.split("=", 1) + except ValueError: + key = tok + val = True + ret[key] = val + + return(ret) -- cgit v1.2.3 From e105bfb7b3bf352244a73fc3a7e08a12a102f477 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Wed, 4 Apr 2012 22:05:17 -0400 Subject: add reading of 'seedfrom' via DataSourceNoCloud's DataSourceConfig What this does is provide an second DataSource that could use the kernel command line url=. For example: ro root=/dev/vda url=http://example.com/i-abcdefg/ http://example.com/i-abcdefg/ would contain: datasource: NoCloud: # default seedfrom is None # if found, then it should contain a url with: # /user-data and /meta-data # seedfrom: http://my.example.com/i-abcde seedfrom: http://example.com/i-abcdefg/ Then, the NoCloudNet DataSource would find that seedfrom config and consume data at http://example.com/i-abcdefg/user-data and http://example.com/i-abcdefg/meta-data --- cloudinit/DataSourceNoCloud.py | 7 +++++++ doc/examples/cloud-config-datasources.txt | 7 +++++++ 2 files changed, 14 insertions(+) (limited to 'cloudinit') diff --git a/cloudinit/DataSourceNoCloud.py b/cloudinit/DataSourceNoCloud.py index 62ecc088..fe649513 100644 --- a/cloudinit/DataSourceNoCloud.py +++ b/cloudinit/DataSourceNoCloud.py @@ -67,6 +67,13 @@ class DataSourceNoCloud(DataSource.DataSource): found.append(self.seeddir) log.debug("using seeded cache data in %s" % self.seeddir) + # if the datasource config had a 'seedfrom' entry, then that takes + # precedence over a 'seedfrom' that was found in a filesystem + # but not over external medi + if 'seedfrom' in self.ds_cfg and self.ds_cfg['seedfrom']: + 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")) diff --git a/doc/examples/cloud-config-datasources.txt b/doc/examples/cloud-config-datasources.txt index 63a6cfc4..d10dde05 100644 --- a/doc/examples/cloud-config-datasources.txt +++ b/doc/examples/cloud-config-datasources.txt @@ -24,3 +24,10 @@ datasource: consumer_key: Xh234sdkljf token_key: kjfhgb3n token_secret: 24uysdfx1w4 + + NoCloud: + # default seedfrom is None + # if found, then it should contain a url with: + # /user-data and /meta-data + # seedfrom: http://my.example.com/i-abcde + seedfrom: None -- cgit v1.2.3 From 166edf79d06fb94856c7c7401914c94149cecbc6 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Wed, 4 Apr 2012 23:10:31 -0400 Subject: fix issue found in real test --- cloudinit/DataSourceNoCloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cloudinit') diff --git a/cloudinit/DataSourceNoCloud.py b/cloudinit/DataSourceNoCloud.py index fe649513..e8c56b8f 100644 --- a/cloudinit/DataSourceNoCloud.py +++ b/cloudinit/DataSourceNoCloud.py @@ -71,7 +71,7 @@ class DataSourceNoCloud(DataSource.DataSource): # precedence over a 'seedfrom' that was found in a filesystem # but not over external medi if 'seedfrom' in self.ds_cfg and self.ds_cfg['seedfrom']: - found.append(["ds_config"]) + found.append("ds_config") md["seedfrom"] = self.ds_cfg['seedfrom'] fslist = util.find_devs_with("TYPE=vfat") -- cgit v1.2.3 From 67fe09104cb347c03ea608c72a1382e8ea252b1d Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Thu, 5 Apr 2012 00:08:42 -0400 Subject: move the reading of the cmdline cloud-config url to cloud-init.py The reason for moving this from cloudinit/__init__.py was that it was running too late there. The cloudinit.parsed_cfgs variable was already filled by cloud-init.py's reading of cloud config. I'm sure I had done this so that it would not have to re-parse configs. I think the right way to handle this is to move that logic back to cloudinit/__init__.py and add some function like 'reread_configs()' that would re-read all releavent cofnigs and re-setup logging. That seemed more error prone at the moment, with limited time. --- cloud-init.py | 26 ++++++++++++++++++++++++++ cloudinit/__init__.py | 18 ------------------ 2 files changed, 26 insertions(+), 18 deletions(-) (limited to 'cloudinit') diff --git a/cloud-init.py b/cloud-init.py index 9e0a0405..db620502 100755 --- a/cloud-init.py +++ b/cloud-init.py @@ -28,6 +28,7 @@ import cloudinit.CloudConfig as CC import cloudinit.DataSource as ds import cloudinit.netinfo as netinfo import time +import traceback import logging import errno import os @@ -67,6 +68,26 @@ def main(): warn("unable to open /proc/uptime\n") uptime = "na" + cmdline_msg = None + cmdline_exc = None + if cmd == "start": + target = "%s.d/%s" % (cloudinit.system_config, + "91_kernel_cmdline_url.cfg") + if os.path.exists(target): + cmdline_msg = "cmdline: %s existed" % target + else: + try: + (key, url, content) = cloudinit.get_cmdline_url() + if key and content: + util.write_file(target, content, mode=0600) + cmdline_msg = ("cmdline: wrote %s from %s, %s" % + (target, key, url)) + elif key: + cmdline_msg = ("cmdline: %s, %s had no cloud-config" % + (key, url)) + except Exception: + cmdline_exc = traceback.format_exc() + try: cfg = cloudinit.get_base_cfg(cfg_path) except Exception as e: @@ -86,6 +107,11 @@ def main(): cloudinit.logging_set_from_cfg(cfg) log = logging.getLogger() + if cmdline_exc: + log.warn(cmdline_exc) + elif cmdline_msg: + log.debug(cmdline_msg) + try: cloudinit.initfs() except Exception as e: diff --git a/cloudinit/__init__.py b/cloudinit/__init__.py index 0b46dde9..85c6fd1b 100644 --- a/cloudinit/__init__.py +++ b/cloudinit/__init__.py @@ -140,24 +140,6 @@ class CloudInit: self.sysconfig = sysconfig - if DataSource.DEP_NETWORK in self.ds_deps: - target = "%s.d/%s" % (self.sysconfig, "91_kernel_cmdline_url.cfg") - if os.path.exists(target): - log.debug("cmdline: %s existed" % target) - else: - try: - (key, url, content) = get_cmdline_url() - if key and content: - util.write_file(target, content, mode=0600) - log.debug("cmdline: wrote %s from %s, %s" % - (target, key, url)) - elif key: - log.debug("cmdline: %s, %s had no cloud-config" % - (key, url)) - except Exception: - util.logexc(log) - log.warn("cmdline: exception occurred while reading") - self.cfg = self.read_cfg() def read_cfg(self): -- cgit v1.2.3