summaryrefslogtreecommitdiff
path: root/cloudinit/config/cc_runcmd.py
diff options
context:
space:
mode:
authorChad Smith <chad.smith@canonical.com>2017-08-22 20:06:20 -0600
committerChad Smith <chad.smith@canonical.com>2017-08-22 20:06:20 -0600
commitcc9762a2d737ead386ffb9f067adc5e543224560 (patch)
treef8a4bf64b401ed50e53cb807ee12c22fc7f907ab /cloudinit/config/cc_runcmd.py
parent3395a331c014dd7b83e93a1e2b66bb55b1966d83 (diff)
downloadvyos-cloud-init-cc9762a2d737ead386ffb9f067adc5e543224560.tar.gz
vyos-cloud-init-cc9762a2d737ead386ffb9f067adc5e543224560.zip
schema cli: Add schema subcommand to cloud-init cli and cc_runcmd schema
This branch does a few things: - Add 'schema' subcommand to cloud-init CLI for validating cloud-config files against strict module jsonschema definitions - Add --annotate parameter to 'cloud-init schema' to annotate existing cloud-config file content with validation errors - Add jsonschema definition to cc_runcmd - Add unit test coverage for cc_runcmd - Update CLI capabilities documentation This branch only imports development (and analyze) subparsers when the specific subcommand is provided on the CLI to avoid adding costly unused file imports during cloud-init system boot. The schema command allows a person to quickly validate a cloud-config text file against cloud-init's known module schemas to avoid costly roundtrips deploying instances in their cloud of choice. As of this branch, only cc_ntp and cc_runcmd cloud-config modules define schemas. Schema validation will ignore all undefined config keys until all modules define a strict schema. To perform validation of runcmd and ntp sections of a cloud-config file: $ cat > cloud.cfg <<EOF runcmd: bogus EOF $ python -m cloudinit.cmd.main schema --config-file cloud.cfg $ python -m cloudinit.cmd.main schema --config-file cloud.cfg \ --annotate Once jsonschema is defined for all ~55 cc modules, we will move this schema subcommand up as a proper subcommand of the cloud-init CLI.
Diffstat (limited to 'cloudinit/config/cc_runcmd.py')
-rw-r--r--cloudinit/config/cc_runcmd.py82
1 files changed, 54 insertions, 28 deletions
diff --git a/cloudinit/config/cc_runcmd.py b/cloudinit/config/cc_runcmd.py
index dfa8cb3d..7c3ccd41 100644
--- a/cloudinit/config/cc_runcmd.py
+++ b/cloudinit/config/cc_runcmd.py
@@ -6,41 +6,66 @@
#
# This file is part of cloud-init. See LICENSE file for license information.
-"""
-Runcmd
-------
-**Summary:** run commands
+"""Runcmd: run arbitrary commands at rc.local with output to the console"""
-Run arbitrary commands at a rc.local like level with output to the console.
-Each item can be either a list or a string. If the item is a list, it will be
-properly executed as if passed to ``execve()`` (with the first arg as the
-command). If the item is a string, it will be written to a file and interpreted
-using ``sh``.
-
-.. note::
- all commands must be proper yaml, so you have to quote any characters yaml
- would eat (':' can be problematic)
-
-**Internal name:** ``cc_runcmd``
-
-**Module frequency:** per instance
+from cloudinit.config.schema import validate_cloudconfig_schema
+from cloudinit.settings import PER_INSTANCE
+from cloudinit import util
-**Supported distros:** all
+import os
+from textwrap import dedent
-**Config keys**::
- runcmd:
- - [ ls, -l, / ]
- - [ sh, -xc, "echo $(date) ': hello world!'" ]
- - [ sh, -c, echo "=========hello world'=========" ]
- - ls -l /root
- - [ wget, "http://example.org", -O, /tmp/index.html ]
-"""
+# The schema definition for each cloud-config module is a strict contract for
+# describing supported configuration parameters for each cloud-config section.
+# It allows cloud-config to validate and alert users to invalid or ignored
+# configuration options before actually attempting to deploy with said
+# configuration.
+distros = ['all']
-import os
+schema = {
+ 'id': 'cc_runcmd',
+ 'name': 'Runcmd',
+ 'title': 'Run arbitrary commands',
+ 'description': dedent("""\
+ Run arbitrary commands at a rc.local like level with output to the
+ console. Each item can be either a list or a string. If the item is a
+ list, it will be properly executed as if passed to ``execve()`` (with
+ the first arg as the command). If the item is a string, it will be
+ written to a file and interpreted
+ using ``sh``.
-from cloudinit import util
+ .. note::
+ all commands must be proper yaml, so you have to quote any characters
+ yaml would eat (':' can be problematic)"""),
+ 'distros': distros,
+ 'examples': [dedent("""\
+ runcmd:
+ - [ ls, -l, / ]
+ - [ sh, -xc, "echo $(date) ': hello world!'" ]
+ - [ sh, -c, echo "=========hello world'=========" ]
+ - ls -l /root
+ - [ wget, "http://example.org", -O, /tmp/index.html ]
+ """)],
+ 'frequency': PER_INSTANCE,
+ 'type': 'object',
+ 'properties': {
+ 'runcmd': {
+ 'type': 'array',
+ 'items': {
+ 'oneOf': [
+ {'type': 'array', 'items': {'type': 'string'}},
+ {'type': 'string'}]
+ },
+ 'additionalItems': False, # Reject items of non-string non-list
+ 'additionalProperties': False,
+ 'minItems': 1,
+ 'required': [],
+ 'uniqueItems': True
+ }
+ }
+}
def handle(name, cfg, cloud, log, _args):
@@ -49,6 +74,7 @@ def handle(name, cfg, cloud, log, _args):
" no 'runcmd' key in configuration"), name)
return
+ validate_cloudconfig_schema(cfg, schema)
out_fn = os.path.join(cloud.get_ipath('scripts'), "runcmd")
cmd = cfg["runcmd"]
try: