summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Requires4
-rw-r--r--cloudinit/config/cc_seed_random.py94
-rw-r--r--cloudinit/distros/__init__.py10
-rw-r--r--cloudinit/exceptions.py21
4 files changed, 107 insertions, 22 deletions
diff --git a/Requires b/Requires
index f19c9691..b00dd58e 100644
--- a/Requires
+++ b/Requires
@@ -34,3 +34,7 @@ boto
# For patching pieces of cloud-config together
jsonpatch
+
+# For validating that a config modules needed configuration specified
+# in a correct format that the module can understand
+jsonschema
diff --git a/cloudinit/config/cc_seed_random.py b/cloudinit/config/cc_seed_random.py
index 5d9890d5..acacb8f7 100644
--- a/cloudinit/config/cc_seed_random.py
+++ b/cloudinit/config/cc_seed_random.py
@@ -16,21 +16,91 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import base64
+from StringIO import StringIO
+
+import jsonschema
+from jsonschema import exceptions as js_exc
+
+from cloudinit import exceptions as exc
from cloudinit.settings import PER_INSTANCE
+from cloudinit import util
frequency = PER_INSTANCE
+schema = {
+ 'type': 'object',
+ 'properties': {
+ "random_seed": {
+ "type": "object",
+ "oneOf": [
+ {"$ref": "#/definitions/random_seed"},
+ ],
+ },
+ },
+ "required": ["random_seed"],
+ "additionalProperties": True,
+ "definitions": {
+ 'random_seed': {
+ 'type': 'object',
+ "properties" : {
+ 'data': {
+ 'type': "string",
+ },
+ 'file': {
+ 'type': 'string',
+ },
+ 'encoding': {
+ "enum": ["base64", 'gzip', 'b64', 'gz', ''],
+ },
+ },
+ "additionalProperties": True,
+ },
+ },
+}
+
+
+def validate(cfg):
+ """Method that can be used to ask if the given configuration will be
+ accepted as valid by this module, without having to actually activate this
+ module."""
+ try:
+ jsonschema.validate(cfg, schema)
+ except js_exc.ValidationError as e:
+ raise exc.FormatValidationError("Invalid configuration: %s" % str(e))
+
+
+def _decode(data, encoding=None):
+ if not encoding:
+ return data
+ if not data:
+ return ''
+ if encoding.lower() in ['base64', 'b64']:
+ return base64.b64decode(data)
+ elif encoding.lower() in ['gzip', 'gz']:
+ return util.decomp_gzip(data, quiet=False)
+ else:
+ raise IOError("Unknown random_seed encoding: %s" % (encoding))
def handle(name, cfg, cloud, log, _args):
- random_seed = None
- # Prefer metadata over cfg for random_seed
- for src in (cloud.datasource.metadata, cfg):
- if not src:
- continue
- tmp_random_seed = src.get('random_seed')
- if tmp_random_seed and isinstance(tmp_random_seed, (str, basestring)):
- random_seed = tmp_random_seed
- break
- if random_seed:
- log.debug("%s: setting random seed", name)
- cloud.distro.set_random_seed(random_seed)
+ if not cfg or "random_seed" not in cfg:
+ log.debug(("Skipping module named %s, "
+ "no 'random_seed' configuration found"), name)
+ return
+
+ validate(cfg)
+ my_cfg = cfg['random_seed']
+ seed_path = my_cfg.get('file', '/dev/urandom')
+ seed_buf = StringIO()
+ seed_buf.write(_decode(my_cfg.get('data', ''),
+ encoding=my_cfg.get('encoding')))
+
+ metadata = cloud.datasource.metadata
+ if metadata and 'random_seed' in metadata:
+ seed_buf.write(metadata['random_seed'])
+
+ seed_data = seed_buf.getvalue()
+ if len(seed_data):
+ log.debug("%s: adding %s bytes of random seed entrophy to %s", name,
+ len(seed_data), seed_path)
+ util.append_file(seed_path, seed_data)
diff --git a/cloudinit/distros/__init__.py b/cloudinit/distros/__init__.py
index 5642b529..74e95797 100644
--- a/cloudinit/distros/__init__.py
+++ b/cloudinit/distros/__init__.py
@@ -52,7 +52,6 @@ class Distro(object):
ci_sudoers_fn = "/etc/sudoers.d/90-cloud-init-users"
hostname_conf_fn = "/etc/hostname"
tz_zone_dir = "/usr/share/zoneinfo"
- random_seed_fn = '/dev/urandom'
def __init__(self, name, cfg, paths):
self._paths = paths
@@ -170,15 +169,6 @@ class Distro(object):
distros.extend(OSFAMILIES[family])
return distros
- def set_random_seed(self, seed):
- if not self.random_seed_fn or not os.path.exists(self.random_seed_fn):
- raise IOError("No random seed filename provided for %s"
- % (self.name))
- if not seed:
- raise IOError("Unable to set empty random seed")
- # Ensure we only write 512 bytes worth
- util.append_file(self.random_seed_fn, seed[0:512])
-
def update_hostname(self, hostname, fqdn, prev_hostname_fn):
applying_hostname = hostname
diff --git a/cloudinit/exceptions.py b/cloudinit/exceptions.py
new file mode 100644
index 00000000..c09d15b1
--- /dev/null
+++ b/cloudinit/exceptions.py
@@ -0,0 +1,21 @@
+# vi: ts=4 expandtab
+#
+# Copyright (C) 2013 Yahoo! Inc.
+#
+# Author: Joshua Harlow <harlowja@yahoo-inc.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 3, as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+class FormatValidationError(Exception):
+ pass