Skip to content

Commit

Permalink
schema: Add cc_landscape schema, example docs and tests
Browse files Browse the repository at this point in the history
Definition cc_landscape schema in into cloud-init-schema.json
Supplement schema defs with known typical landscape config options.
  • Loading branch information
blackboxsw committed Mar 26, 2022
1 parent 1b4f39b commit 839c13d
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 71 deletions.
110 changes: 63 additions & 47 deletions cloudinit/config/cc_landscape.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,38 @@
#
# This file is part of cloud-init. See LICENSE file for license information.

"""
Landscape
---------
**Summary:** install and configure landscape client
"""install and configure landscape client"""

import os
from io import BytesIO
from textwrap import dedent

from configobj import ConfigObj

from cloudinit import subp, type_utils, util
from cloudinit.config.schema import MetaSchema, get_meta_doc
from cloudinit.settings import PER_INSTANCE

LSC_CLIENT_CFG_FILE = "/etc/landscape/client.conf"
LS_DEFAULT_FILE = "/etc/default/landscape-client"

# defaults taken from stock client.conf in landscape-client 11.07.1.1-0ubuntu2
LSC_BUILTIN_CFG = {
"client": {
"log_level": "info",
"url": "https://landscape.canonical.com/message-system",
"ping_url": "http://landscape.canonical.com/ping",
"data_path": "/var/lib/landscape/client",
}
}

MODULE_DESCRIPTION = """\
This module installs and configures ``landscape-client``. The landscape client
will only be installed if the key ``landscape`` is present in config. Landscape
client configuration is given under the ``client`` key under the main
``landscape`` config key. The config parameters are not interpreted by
cloud-init, but rather are converted into a ConfigObj formatted file and
written out to ``/etc/landscape/client.conf``.
written out to the `[client]` section in ``/etc/landscape/client.conf``.
The following default client config is provided, but can be overridden::
Expand All @@ -33,53 +54,47 @@
.. note::
if ``tags`` is defined, its contents should be a string delimited with
``,`` rather than a list
**Internal name:** ``cc_landscape``
**Module frequency:** per instance
**Supported distros:** ubuntu
**Config keys**::
landscape:
client:
url: "https://landscape.canonical.com/message-system"
ping_url: "http://landscape.canonical.com/ping"
data_path: "/var/lib/landscape/client"
http_proxy: "http://my.proxy.com/foobar"
https_proxy: "https://my.proxy.com/foobar"
tags: "server,cloud"
computer_title: "footitle"
registration_key: "fookey"
account_name: "fooaccount"
"""

import os
from io import BytesIO

from configobj import ConfigObj

from cloudinit import subp, type_utils, util
from cloudinit.settings import PER_INSTANCE

frequency = PER_INSTANCE

LSC_CLIENT_CFG_FILE = "/etc/landscape/client.conf"
LS_DEFAULT_FILE = "/etc/default/landscape-client"

distros = ["ubuntu"]

# defaults taken from stock client.conf in landscape-client 11.07.1.1-0ubuntu2
LSC_BUILTIN_CFG = {
"client": {
"log_level": "info",
"url": "https://landscape.canonical.com/message-system",
"ping_url": "http://landscape.canonical.com/ping",
"data_path": "/var/lib/landscape/client",
}
meta: MetaSchema = {
"id": "cc_landscape",
"name": "Landscape",
"title": "Install and configure landscape client",
"description": MODULE_DESCRIPTION,
"distros": distros,
"examples": [
dedent(
"""\
# To discover additional supported client keys, run
# man landscape-config.
landscape:
client:
url: "https://landscape.canonical.com/message-system"
ping_url: "http://landscape.canonical.com/ping"
data_path: "/var/lib/landscape/client"
http_proxy: "http://my.proxy.com/foobar"
https_proxy: "https://my.proxy.com/foobar"
tags: "server,cloud"
computer_title: "footitle"
registration_key: "fookey"
account_name: "fooaccount"
"""
),
dedent(
"""\
# Any keys below `client` are optional and the default values will
# be used.
landscape:
client: {}
"""
),
],
"frequency": PER_INSTANCE,
}

__doc__ = get_meta_doc(meta)


def handle(_name, cfg, cloud, log, _args):
"""
Expand All @@ -102,6 +117,7 @@ def handle(_name, cfg, cloud, log, _args):

cloud.distro.install_packages(("landscape-client",))

# Later order config values override earlier values
merge_data = [
LSC_BUILTIN_CFG,
LSC_CLIENT_CFG_FILE,
Expand Down
64 changes: 63 additions & 1 deletion cloudinit/config/cloud-init-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1067,8 +1067,69 @@
}
}
},
"cc_locale": {
"cc_landscape": {
"type": "object",
"properties": {
"landscape": {
"type": "object",
"required": ["client"],
"properties": {
"client": {
"type": "object",
"properties": {
"url": {
"type": "string",
"default": "https://landscape.canonical.com/message-system",
"description": "The Landscape server URL to connect to. Default: ``https://landscape.canonical.com/message-system``."
},
"ping_url": {
"type": "string",
"default": "https://landscape.canonical.com/ping",
"description": "The URL to perform lightweight exchange initiation with. Default: ``https://landscape.canonical.com/ping``."
},
"data_path": {
"type": "string",
"default": "/var/lib/landscape/client",
"description": "The directory to store data files in. Default: ``/var/lib/land‐scape/client/``."
},
"log_level": {
"type": "string",
"default": "info",
"enum": ["debug", "info", "warning", "error", "critical"],
"description": "The log level for the client. Default: ``info``."
},
"computer_tite": {
"type": "string",
"description": "The title of this computer."
},
"account_name": {
"type": "string",
"description": "The account this computer belongs to."
},
"registration_key": {
"type": "string",
"description": "The account-wide key used for registering clients."
},
"tags": {
"type": "string",
"pattern": "^[-_0-9a-zA-Z]+(,[-_0-9a-zA-Z]+)*$",
"description": "Comma separated list of tag names to be sent to the server."
},
"http_proxy": {
"type": "string",
"description": "The URL of the HTTP proxy, if one is needed."
},
"https_proxy": {
"type": "string",
"description": "The URL of the HTTPS proxy, if one is needed."
}
}
}
}
}
}
},
"cc_locale": {
"properties": {
"locale": {
"type": "string",
Expand Down Expand Up @@ -1199,6 +1260,7 @@
{ "$ref": "#/$defs/cc_disk_setup" },
{ "$ref": "#/$defs/cc_keyboard" },
{ "$ref": "#/$defs/cc_keys_to_console" },
{ "$ref": "#/$defs/cc_landscape" },
{ "$ref": "#/$defs/cc_locale" },
{ "$ref": "#/$defs/cc_lxd" },
{ "$ref": "#/$defs/cc_package_update_upgrade_install" },
Expand Down
23 changes: 0 additions & 23 deletions doc/examples/cloud-config-landscape.txt

This file was deleted.

34 changes: 34 additions & 0 deletions tests/unittests/config/test_cc_landscape.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
# This file is part of cloud-init. See LICENSE file for license information.
import logging

import pytest
from configobj import ConfigObj

from cloudinit import util
from cloudinit.config import cc_landscape
from cloudinit.config.schema import (
SchemaValidationError,
get_schema,
validate_cloudconfig_schema,
)
from tests.unittests.helpers import (
FilesystemMockingTestCase,
mock,
skipUnlessJsonSchema,
wrap_and_call,
)
from tests.unittests.util import get_cloud
Expand Down Expand Up @@ -168,3 +175,30 @@ def test_handler_writes_merged_provided_cloudconfig_with_defaults(self):
"Wrote landscape config file to {0}".format(self.conf),
self.logs.getvalue(),
)


class TestLandscapeSchema:
@pytest.mark.parametrize(
"config, error_msg",
[
# Allow undocumented keys client keys without error
({"landscape": {"client": {"allow_additional_keys": 1}}}, None),
# tags are comma-delimited
({"landscape": {"client": {"tags": "1,2,3"}}}, None),
({"landscape": {"client": {"tags": "1"}}}, None),
# Require client key
({"landscape": {}}, "'client' is a required property"),
# tags are not whitespace-delimited
(
{"landscape": {"client": {"tags": "1, 2,3"}}},
"'1, 2,3' does not match",
),
],
)
@skipUnlessJsonSchema()
def test_schema_validation(self, config, error_msg):
if error_msg is None:
validate_cloudconfig_schema(config, get_schema(), strict=True)
else:
with pytest.raises(SchemaValidationError, match=error_msg):
validate_cloudconfig_schema(config, get_schema(), strict=True)
2 changes: 2 additions & 0 deletions tests/unittests/config/test_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ def test_get_schema_coalesces_known_schema(self):
"cc_install_hotplug",
"cc_keyboard",
"cc_keys_to_console",
"cc_landscape",
"cc_locale",
"cc_lxd",
"cc_ntp",
Expand Down Expand Up @@ -146,6 +147,7 @@ def test_get_schema_coalesces_known_schema(self):
{"$ref": "#/$defs/cc_disk_setup"},
{"$ref": "#/$defs/cc_keyboard"},
{"$ref": "#/$defs/cc_keys_to_console"},
{"$ref": "#/$defs/cc_landscape"},
{"$ref": "#/$defs/cc_locale"},
{"$ref": "#/$defs/cc_lxd"},
{"$ref": "#/$defs/cc_package_update_upgrade_install"},
Expand Down

0 comments on commit 839c13d

Please sign in to comment.