Skip to content

Commit

Permalink
Allow to pass the host info for retrieving a value.
Browse files Browse the repository at this point in the history
  • Loading branch information
felixfontein committed Dec 2, 2023
1 parent b94fdda commit 036d166
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 28 deletions.
12 changes: 10 additions & 2 deletions plugins/module_utils/module_container/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ class Engine(object):
min_api_version_obj = None # LooseVersion object or None

@abc.abstractmethod
def get_value(self, module, container, api_version, options, image):
def get_value(self, module, container, api_version, options, image, host_info):
pass

def compare_value(self, option, param_value, container_value):
Expand All @@ -186,7 +186,7 @@ def set_value(self, module, data, api_version, options, values):
pass

@abc.abstractmethod
def get_expected_values(self, module, client, api_version, options, image, values):
def get_expected_values(self, module, client, api_version, options, image, values, host_info):
pass

@abc.abstractmethod
Expand All @@ -213,6 +213,10 @@ def can_update_value(self, api_version):
def needs_container_image(self, values):
pass

@abc.abstractmethod
def needs_host_info(self, values):
pass


class EngineDriver(object):
name = None # string
Expand All @@ -222,6 +226,10 @@ def setup(self, argument_spec, mutually_exclusive=None, required_together=None,
# Return (module, active_options, client)
pass

@abc.abstractmethod
def get_host_info(self, client):
pass

@abc.abstractmethod
def get_api_version(self, client):
pass
Expand Down
33 changes: 19 additions & 14 deletions plugins/module_utils/module_container/docker_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ def setup(self, argument_spec, mutually_exclusive=None, required_together=None,

return client.module, active_options, client

def get_host_info(self, client):
return client.info()

def get_api_version(self, client):
return client.docker_api_version

Expand Down Expand Up @@ -389,19 +392,21 @@ def __init__(
min_api_version=None,
compare_value=None,
needs_container_image=None,
needs_host_info=None,
):
self.min_api_version = min_api_version
self.min_api_version_obj = None if min_api_version is None else LooseVersion(min_api_version)
self.get_value = get_value
self.set_value = set_value
self.get_expected_values = get_expected_values or (lambda module, client, api_version, options, image, values: values)
self.get_expected_values = get_expected_values or (lambda module, client, api_version, options, image, values, host_info: values)
self.ignore_mismatching_result = ignore_mismatching_result or \
(lambda module, client, api_version, option, image, container_value, expected_value: False)
self.preprocess_value = preprocess_value or (lambda module, client, api_version, options, values: values)
self.update_value = update_value
self.can_set_value = can_set_value or (lambda api_version: set_value is not None)
self.can_update_value = can_update_value or (lambda api_version: update_value is not None)
self.needs_container_image = needs_container_image or (lambda values: False)
self.needs_host_info = needs_host_info or (lambda values: False)
if compare_value is not None:
self.compare_value = compare_value

Expand All @@ -428,7 +433,7 @@ def preprocess_value_(module, client, api_version, options, values):
values[options[0].name] = value
return values

def get_value(module, container, api_version, options, image):
def get_value(module, container, api_version, options, image, host_info):
if len(options) != 1:
raise AssertionError('config_value can only be used for a single option')
value = container['Config'].get(config_name, _SENTRY)
Expand All @@ -440,7 +445,7 @@ def get_value(module, container, api_version, options, image):

get_expected_values_ = None
if get_expected_value:
def get_expected_values_(module, client, api_version, options, image, values):
def get_expected_values_(module, client, api_version, options, image, values, host_info):
if len(options) != 1:
raise AssertionError('host_config_value can only be used for a single option')
value = values.get(options[0].name, _SENTRY)
Expand Down Expand Up @@ -504,7 +509,7 @@ def preprocess_value_(module, client, api_version, options, values):
values[options[0].name] = value
return values

def get_value(module, container, api_version, options, get_value):
def get_value(module, container, api_version, options, get_value, host_info):
if len(options) != 1:
raise AssertionError('host_config_value can only be used for a single option')
value = container['HostConfig'].get(host_config_name, _SENTRY)
Expand All @@ -516,7 +521,7 @@ def get_value(module, container, api_version, options, get_value):

get_expected_values_ = None
if get_expected_value:
def get_expected_values_(module, client, api_version, options, image, values):
def get_expected_values_(module, client, api_version, options, image, values, host_info):
if len(options) != 1:
raise AssertionError('host_config_value can only be used for a single option')
value = values.get(options[0].name, _SENTRY)
Expand Down Expand Up @@ -590,7 +595,7 @@ def _get_default_host_ip(module, client):
return ip


def _get_value_detach_interactive(module, container, api_version, options, image):
def _get_value_detach_interactive(module, container, api_version, options, image, host_info):
attach_stdin = container['Config'].get('OpenStdin')
attach_stderr = container['Config'].get('AttachStderr')
attach_stdout = container['Config'].get('AttachStdout')
Expand Down Expand Up @@ -841,7 +846,7 @@ def _get_network_id(module, client, network_name):
client.fail("Error getting network id for %s - %s" % (network_name, to_native(exc)))


def _get_values_network(module, container, api_version, options, image):
def _get_values_network(module, container, api_version, options, image, host_info):
value = container['HostConfig'].get('NetworkMode', _SENTRY)
if value is _SENTRY:
return {}
Expand All @@ -857,7 +862,7 @@ def _set_values_network(module, data, api_version, options, values):
data['HostConfig']['NetworkMode'] = value


def _get_values_mounts(module, container, api_version, options, image):
def _get_values_mounts(module, container, api_version, options, image, host_info):
volumes = container['Config'].get('Volumes')
binds = container['HostConfig'].get('Binds')
# According to https://github.com/moby/moby/, support for HostConfig.Mounts
Expand Down Expand Up @@ -921,7 +926,7 @@ def _get_image_binds(volumes):
return results


def _get_expected_values_mounts(module, client, api_version, options, image, values):
def _get_expected_values_mounts(module, client, api_version, options, image, values, host_info):
expected_values = {}

# binds
Expand Down Expand Up @@ -1022,7 +1027,7 @@ def _set_values_mounts(module, data, api_version, options, values):
data['HostConfig']['Binds'] = values['volume_binds']


def _get_values_log(module, container, api_version, options, image):
def _get_values_log(module, container, api_version, options, image, host_info):
log_config = container['HostConfig'].get('LogConfig') or {}
return {
'log_driver': log_config.get('Type'),
Expand All @@ -1042,7 +1047,7 @@ def _set_values_log(module, data, api_version, options, values):
data['HostConfig']['LogConfig'] = log_config


def _get_values_platform(module, container, api_version, options, image):
def _get_values_platform(module, container, api_version, options, image, host_info):
return {
'platform': container.get('Platform'),
}
Expand All @@ -1053,7 +1058,7 @@ def _set_values_platform(module, data, api_version, options, values):
data['platform'] = values['platform']


def _get_values_restart(module, container, api_version, options, image):
def _get_values_restart(module, container, api_version, options, image, host_info):
restart_policy = container['HostConfig'].get('RestartPolicy') or {}
return {
'restart_policy': restart_policy.get('Name'),
Expand Down Expand Up @@ -1082,7 +1087,7 @@ def _update_value_restart(module, data, api_version, options, values):
}


def _get_values_ports(module, container, api_version, options, image):
def _get_values_ports(module, container, api_version, options, image, host_info):
host_config = container['HostConfig']
config = container['Config']

Expand All @@ -1099,7 +1104,7 @@ def _get_values_ports(module, container, api_version, options, image):
}


def _get_expected_values_ports(module, client, api_version, options, image, values):
def _get_expected_values_ports(module, client, api_version, options, image, values, host_info):
expected_values = {}

if 'published_ports' in values:
Expand Down
32 changes: 20 additions & 12 deletions plugins/module_utils/module_container/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,13 @@ def _needs_container_image(self):
return True
return False

def _needs_host_info(self):
for options, values in self.parameters:
engine = options.get_engine(self.engine_driver.name)
if engine.needs_host_info(values):
return True
return False

def present(self, state):
self.parameters = self._collect_params(self.options)
container = self._get_container(self.param_name)
Expand All @@ -290,6 +297,7 @@ def present(self, state):
image, container_image, comparison_image = self._get_image(
container, needs_container_image=self._needs_container_image())
self.log(image, pretty_print=True)
host_info = self.engine_driver.get_host_info(self.client) if self._needs_host_info() else None
if not container.exists or container.removing:
# New container
if container.removing:
Expand All @@ -309,7 +317,7 @@ def present(self, state):
container_created = True
else:
# Existing container
different, differences = self.has_different_configuration(container, container_image, comparison_image)
different, differences = self.has_different_configuration(container, container_image, comparison_image, host_info)
image_different = False
if self.all_options['image'].comparison == 'strict':
image_different = self._image_is_different(image, container)
Expand Down Expand Up @@ -341,7 +349,7 @@ def present(self, state):
comparison_image = image

if container and container.exists:
container = self.update_limits(container, container_image, comparison_image)
container = self.update_limits(container, container_image, comparison_image, host_info)
container = self.update_networks(container, container_created)

if state == 'started' and not container.running:
Expand Down Expand Up @@ -469,11 +477,11 @@ def _compose_create_parameters(self, image):
params['Image'] = image
return params

def _record_differences(self, differences, options, param_values, engine, container, container_image, image):
def _record_differences(self, differences, options, param_values, engine, container, container_image, image, host_info):
container_values = engine.get_value(
self.module, container.raw, self.engine_driver.get_api_version(self.client), options.options, container_image)
self.module, container.raw, self.engine_driver.get_api_version(self.client), options.options, container_image, host_info)
expected_values = engine.get_expected_values(
self.module, self.client, self.engine_driver.get_api_version(self.client), options.options, image, param_values.copy())
self.module, self.client, self.engine_driver.get_api_version(self.client), options.options, image, param_values.copy(), host_info)
for option in options.options:
if option.name in expected_values:
param_value = expected_values[option.name]
Expand Down Expand Up @@ -512,28 +520,28 @@ def sort_key_fn(x):
c = sorted(c, key=sort_key_fn)
differences.add(option.name, parameter=p, active=c)

def has_different_configuration(self, container, container_image, image):
def has_different_configuration(self, container, container_image, image, host_info):
differences = DifferenceTracker()
update_differences = DifferenceTracker()
for options, param_values in self.parameters:
engine = options.get_engine(self.engine_driver.name)
if engine.can_update_value(self.engine_driver.get_api_version(self.client)):
self._record_differences(update_differences, options, param_values, engine, container, container_image, image)
self._record_differences(update_differences, options, param_values, engine, container, container_image, image, host_info)
else:
self._record_differences(differences, options, param_values, engine, container, container_image, image)
self._record_differences(differences, options, param_values, engine, container, container_image, image, host_info)
has_differences = not differences.empty
# Only consider differences of properties that can be updated when there are also other differences
if has_differences:
differences.merge(update_differences)
return has_differences, differences

def has_different_resource_limits(self, container, container_image, image):
def has_different_resource_limits(self, container, container_image, image, host_info):
differences = DifferenceTracker()
for options, param_values in self.parameters:
engine = options.get_engine(self.engine_driver.name)
if not engine.can_update_value(self.engine_driver.get_api_version(self.client)):
continue
self._record_differences(differences, options, param_values, engine, container, container_image, image)
self._record_differences(differences, options, param_values, engine, container, container_image, image, host_info)
has_differences = not differences.empty
return has_differences, differences

Expand All @@ -546,8 +554,8 @@ def _compose_update_parameters(self):
engine.update_value(self.module, result, self.engine_driver.get_api_version(self.client), options.options, values)
return result

def update_limits(self, container, container_image, image):
limits_differ, different_limits = self.has_different_resource_limits(container, container_image, image)
def update_limits(self, container, container_image, image, host_info):
limits_differ, different_limits = self.has_different_resource_limits(container, container_image, image, host_info)
if limits_differ:
self.log("limit differences:")
self.log(different_limits.get_legacy_docker_container_diffs(), pretty_print=True)
Expand Down

0 comments on commit 036d166

Please sign in to comment.