Fix Py27 cloud-config ordering

On Py27, the yaml module implementation uses a normal dictionary for
implementation, resulting in arbitrary order for the parsed yaml.

If the config option cloud_config_plugins is not set or empty, fallback
to the default order defined in the factory.

Config option `cloud_config_plugins` is now used for filtering the cloud
config plugins to be executed, which was the original intended behaviour.

Change-Id: I59ea56e473ab343a826ff8c38787cb7f11cebd27
This commit is contained in:
Adrian Vladu 2020-02-05 17:23:49 +02:00
parent a77477e16e
commit 75c6a0e0f8
3 changed files with 34 additions and 6 deletions

View File

@ -42,11 +42,14 @@ class CloudConfigPluginExecutor(object):
def __init__(self, **plugins):
def _lookup_priority(plugin):
all_plugins = (CONF.cloud_config_plugins or
list(factory.PLUGINS.keys()))
# return the order from the config or default list
try:
return CONF.cloud_config_plugins.index(plugin)
return all_plugins.index(plugin)
except ValueError:
# If the plugin was not specified in the order
# list, then default to a sane and unreachable value.
# If plugin is not supported or does not exist
# default to a sane and unreachable value.
return DEFAULT_ORDER_VALUE
self._expected_plugins = sorted(
@ -67,10 +70,17 @@ class CloudConfigPluginExecutor(object):
return cls(**content)
def execute(self):
"""Call each plugin, in the order requested by the user."""
"""Call each plugin, in the order defined by _lookup_priority"""
reboot = execcmd.NO_REBOOT
plugins = factory.load_plugins()
for plugin_name, value in self._expected_plugins:
if CONF.cloud_config_plugins:
try:
CONF.cloud_config_plugins.index(plugin_name)
except ValueError:
LOG.info("Plugin %r is disabled", plugin_name)
continue
method = plugins.get(plugin_name)
if not method:
LOG.error("Plugin %r is currently not supported", plugin_name)

View File

@ -51,6 +51,23 @@ class CloudConfigPluginTests(unittest.TestCase):
finally:
CONF.cloud_config_plugins = orig
def test_default_priority(self):
expected = [
('write_files', 0),
('hostname', 3),
('runcmd', 1),
('invalid1', 1),
('invalid2', 2),
]
executor = cloudconfig.CloudConfigPluginExecutor(
runcmd=1,
invalid1=1,
hostname=3,
invalid2=2,
write_files=0)
self.assertEqual(expected, executor._expected_plugins)
def test_executor_from_yaml(self):
for invalid in (mock.sentinel.yaml, None, 1, int, '{}'):
with self.assertRaises(cloudconfig.CloudConfigError):

View File

@ -247,8 +247,9 @@ The following cloud-config directives are supported:
- ['echo', '1']
The cloud-config directives are executed in the following order: write_files, set_timezone,
set_hostname, ntp, runcmd.
The cloud-config directives are executed by default in the following order: write_files,
set_timezone, set_hostname, ntp, groups, users, runcmd. Use config option `cloud_config_plugins`
to filter or to change the order of the cloud config plugins.
The execution of set_hostname or runcmd can request a reboot if needed. The reboot
is performed at the end of the cloud-config execution (after all the directives have been