summaryrefslogtreecommitdiff
path: root/cloudinit/config/cc_snap.py
diff options
context:
space:
mode:
Diffstat (limited to 'cloudinit/config/cc_snap.py')
-rw-r--r--cloudinit/config/cc_snap.py181
1 files changed, 104 insertions, 77 deletions
diff --git a/cloudinit/config/cc_snap.py b/cloudinit/config/cc_snap.py
index 20ed7d2f..9f343df0 100644
--- a/cloudinit/config/cc_snap.py
+++ b/cloudinit/config/cc_snap.py
@@ -8,24 +8,26 @@ import sys
from textwrap import dedent
from cloudinit import log as logging
+from cloudinit import subp, util
from cloudinit.config.schema import (
- get_schema_doc, validate_cloudconfig_schema)
+ MetaSchema,
+ get_meta_doc,
+ validate_cloudconfig_schema,
+)
from cloudinit.settings import PER_INSTANCE
from cloudinit.subp import prepend_base_command
-from cloudinit import subp
-from cloudinit import util
-
-distros = ['ubuntu']
+distros = ["ubuntu"]
frequency = PER_INSTANCE
LOG = logging.getLogger(__name__)
-schema = {
- 'id': 'cc_snap',
- 'name': 'Snap',
- 'title': 'Install, configure and manage snapd and snap packages',
- 'description': dedent("""\
+meta: MetaSchema = {
+ "id": "cc_snap",
+ "name": "Snap",
+ "title": "Install, configure and manage snapd and snap packages",
+ "description": dedent(
+ """\
This module provides a simple configuration namespace in cloud-init to
both setup snapd and install snaps.
@@ -56,9 +58,12 @@ schema = {
**Development only**: The ``squashfuse_in_container`` boolean can be
set true to install squashfuse package when in a container to enable
snap installs. Default is false.
- """),
- 'distros': distros,
- 'examples': [dedent("""\
+ """
+ ),
+ "distros": distros,
+ "examples": [
+ dedent(
+ """\
snap:
assertions:
00: |
@@ -69,14 +74,20 @@ schema = {
00: snap create-user --sudoer --known <snap-user>@mydomain.com
01: snap install canonical-livepatch
02: canonical-livepatch enable <AUTH_TOKEN>
- """), dedent("""\
+ """
+ ),
+ dedent(
+ """\
# LXC-based containers require squashfuse before snaps can be installed
snap:
commands:
00: apt-get install squashfuse -y
11: snap install emoj
- """), dedent("""\
+ """
+ ),
+ dedent(
+ """\
# Convenience: the snap command can be omitted when specifying commands
# as a list and 'snap' will automatically be prepended.
# The following commands are equivalent:
@@ -86,7 +97,10 @@ schema = {
01: ['snap', 'install', 'vlc']
02: snap install vlc
03: 'snap install vlc'
- """), dedent("""\
+ """
+ ),
+ dedent(
+ """\
# You can use a list of commands
snap:
commands:
@@ -94,58 +108,64 @@ schema = {
- ['snap', 'install', 'vlc']
- snap install vlc
- 'snap install vlc'
- """), dedent("""\
+ """
+ ),
+ dedent(
+ """\
# You can use a list of assertions
snap:
assertions:
- signed_assertion_blob_here
- |
signed_assertion_blob_here
- """)],
- 'frequency': PER_INSTANCE,
- 'type': 'object',
- 'properties': {
- 'snap': {
- 'type': 'object',
- 'properties': {
- 'assertions': {
- 'type': ['object', 'array'], # Array of strings or dict
- 'items': {'type': 'string'},
- 'additionalItems': False, # Reject items non-string
- 'minItems': 1,
- 'minProperties': 1,
- 'uniqueItems': True,
- 'additionalProperties': {'type': 'string'},
+ """
+ ),
+ ],
+ "frequency": PER_INSTANCE,
+}
+
+schema = {
+ "type": "object",
+ "properties": {
+ "snap": {
+ "type": "object",
+ "properties": {
+ "assertions": {
+ "type": ["object", "array"], # Array of strings or dict
+ "items": {"type": "string"},
+ "additionalItems": False, # Reject items non-string
+ "minItems": 1,
+ "minProperties": 1,
+ "uniqueItems": True,
+ "additionalProperties": {"type": "string"},
},
- 'commands': {
- 'type': ['object', 'array'], # Array of strings or dict
- 'items': {
- 'oneOf': [
- {'type': 'array', 'items': {'type': 'string'}},
- {'type': 'string'}]
+ "commands": {
+ "type": ["object", "array"], # Array of strings or dict
+ "items": {
+ "oneOf": [
+ {"type": "array", "items": {"type": "string"}},
+ {"type": "string"},
+ ]
},
- 'additionalItems': False, # Reject non-string & non-list
- 'minItems': 1,
- 'minProperties': 1,
- 'additionalProperties': {
- 'oneOf': [
- {'type': 'string'},
- {'type': 'array', 'items': {'type': 'string'}},
+ "additionalItems": False, # Reject non-string & non-list
+ "minItems": 1,
+ "minProperties": 1,
+ "additionalProperties": {
+ "oneOf": [
+ {"type": "string"},
+ {"type": "array", "items": {"type": "string"}},
],
},
},
- 'squashfuse_in_container': {
- 'type': 'boolean'
- }
+ "squashfuse_in_container": {"type": "boolean"},
},
- 'additionalProperties': False, # Reject keys not in schema
- 'required': [],
- 'minProperties': 1
+ "additionalProperties": False, # Reject keys not in schema
+ "minProperties": 1,
}
- }
+ },
}
-__doc__ = get_schema_doc(schema) # Supplement python help()
+__doc__ = get_meta_doc(meta, schema) # Supplement python help()
SNAP_CMD = "snap"
ASSERTIONS_FILE = "/var/lib/cloud/instance/snapd.assertions"
@@ -161,45 +181,49 @@ def add_assertions(assertions):
"""
if not assertions:
return
- LOG.debug('Importing user-provided snap assertions')
+ LOG.debug("Importing user-provided snap assertions")
if isinstance(assertions, dict):
assertions = assertions.values()
elif not isinstance(assertions, list):
raise TypeError(
- 'assertion parameter was not a list or dict: {assertions}'.format(
- assertions=assertions))
+ "assertion parameter was not a list or dict: {assertions}".format(
+ assertions=assertions
+ )
+ )
- snap_cmd = [SNAP_CMD, 'ack']
+ snap_cmd = [SNAP_CMD, "ack"]
combined = "\n".join(assertions)
for asrt in assertions:
- LOG.debug('Snap acking: %s', asrt.split('\n')[0:2])
+ LOG.debug("Snap acking: %s", asrt.split("\n")[0:2])
- util.write_file(ASSERTIONS_FILE, combined.encode('utf-8'))
+ util.write_file(ASSERTIONS_FILE, combined.encode("utf-8"))
subp.subp(snap_cmd + [ASSERTIONS_FILE], capture=True)
def run_commands(commands):
"""Run the provided commands provided in snap:commands configuration.
- Commands are run individually. Any errors are collected and reported
- after attempting all commands.
+ Commands are run individually. Any errors are collected and reported
+ after attempting all commands.
- @param commands: A list or dict containing commands to run. Keys of a
- dict will be used to order the commands provided as dict values.
- """
+ @param commands: A list or dict containing commands to run. Keys of a
+ dict will be used to order the commands provided as dict values.
+ """
if not commands:
return
- LOG.debug('Running user-provided snap commands')
+ LOG.debug("Running user-provided snap commands")
if isinstance(commands, dict):
# Sort commands based on dictionary key
commands = [v for _, v in sorted(commands.items())]
elif not isinstance(commands, list):
raise TypeError(
- 'commands parameter was not a list or dict: {commands}'.format(
- commands=commands))
+ "commands parameter was not a list or dict: {commands}".format(
+ commands=commands
+ )
+ )
- fixed_snap_commands = prepend_base_command('snap', commands)
+ fixed_snap_commands = prepend_base_command("snap", commands)
cmd_failures = []
for command in fixed_snap_commands:
@@ -209,8 +233,9 @@ def run_commands(commands):
except subp.ProcessExecutionError as e:
cmd_failures.append(str(e))
if cmd_failures:
- msg = 'Failures running snap commands:\n{cmd_failures}'.format(
- cmd_failures=cmd_failures)
+ msg = "Failures running snap commands:\n{cmd_failures}".format(
+ cmd_failures=cmd_failures
+ )
util.logexc(LOG, msg)
raise RuntimeError(msg)
@@ -226,23 +251,25 @@ def maybe_install_squashfuse(cloud):
util.logexc(LOG, "Package update failed")
raise
try:
- cloud.distro.install_packages(['squashfuse'])
+ cloud.distro.install_packages(["squashfuse"])
except Exception:
util.logexc(LOG, "Failed to install squashfuse")
raise
def handle(name, cfg, cloud, log, args):
- cfgin = cfg.get('snap', {})
+ cfgin = cfg.get("snap", {})
if not cfgin:
- LOG.debug(("Skipping module named %s,"
- " no 'snap' key in configuration"), name)
+ LOG.debug(
+ "Skipping module named %s, no 'snap' key in configuration", name
+ )
return
validate_cloudconfig_schema(cfg, schema)
- if util.is_true(cfgin.get('squashfuse_in_container', False)):
+ if util.is_true(cfgin.get("squashfuse_in_container", False)):
maybe_install_squashfuse(cloud)
- add_assertions(cfgin.get('assertions', []))
- run_commands(cfgin.get('commands', []))
+ add_assertions(cfgin.get("assertions", []))
+ run_commands(cfgin.get("commands", []))
+
# vi: ts=4 expandtab