Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CM service config module and reconciliation utilities #257

Merged
merged 9 commits into from
Dec 18, 2024
31 changes: 24 additions & 7 deletions plugins/module_utils/cm_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,23 +104,37 @@ def parse_role_config_group_result(role_config_group: ApiRoleConfigGroup) -> dic


def normalize_values(add: dict) -> dict:
"""Normalize whitespace of parameter values.
"""Normalize parameter values. Strings have whitespace trimmed, integers are
converted to strings, and Boolean values are converted their string representation
and lowercased.

Args:
add (dict): Parameters to review

Returns:
dict: Normalized parameters
"""
return {k: (v.strip() if isinstance(v, str) else v) for k, v in add.items()}

def _normalize(value):
if isinstance(value, str):
return value.strip()
elif isinstance(value, int):
return str(value)
elif isinstance(value, bool):
return str(value).lower()
else:
return value

return {k: _normalize(v) for k, v in add.items()}


def resolve_parameter_updates(
current: dict, incoming: dict, purge: bool = False
) -> dict:
"""Produce a change set between two parameter dictionaries.

The function will normalize parameter values to remove whitespace.
The function will normalize parameter values to remove whitespace from strings,
convert integers and Booleans to their string representations.

Args:
current (dict): Existing parameters
Expand All @@ -131,20 +145,23 @@ def resolve_parameter_updates(
dict: A change set of the updates
"""
updates = {}
diff = recursive_diff(current, incoming)

diff = recursive_diff(current, normalize_values(incoming))

if diff is not None:
updates = {
k: v
for k, v in normalize_values(diff[1]).items()
for k, v in diff[1].items()
if k in current or (k not in current and v is not None)
}

if purge:
# Add the other non-defaults
# Add the remaining non-default values for removal
updates = {
**updates,
**{k: None for k in diff[0].keys() if k not in diff[1]},
}

return updates


Expand Down Expand Up @@ -384,7 +401,7 @@ def initialize_client(self):
"""Creates the CM API client"""
config = Configuration()

# If provided a CML endpoint URL, use it directly
# If provided a CM endpoint URL, use it directly
if self.url:
config.host = str(self.url).rstrip(" /")
# Otherwise, run discovery on missing parts
Expand Down
28 changes: 26 additions & 2 deletions plugins/module_utils/service_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,19 @@
# limitations under the License.

"""
A common functions for Cloudera Manager service management
A common functions for service management
"""

from ansible_collections.cloudera.cluster.plugins.module_utils.cm_utils import (
_parse_output,
resolve_parameter_updates,
)

from cm_client import ApiService
from cm_client import (
ApiConfig,
ApiService,
ApiServiceConfig,
)

SERVICE_OUTPUT = [
"client_config_staleness_status",
Expand All @@ -44,3 +49,22 @@ def parse_service_result(service: ApiService) -> dict:
output = dict(cluster_name=service.cluster_ref.cluster_name)
output.update(_parse_output(service.to_dict(), SERVICE_OUTPUT))
return output


class ServiceConfigUpdates(object):
def __init__(self, existing: ApiServiceConfig, updates: dict, purge: bool) -> None:
current = {r.name: r.value for r in existing.items}
changeset = resolve_parameter_updates(current, updates, purge)

self.diff = dict(
before={k: current[k] if k in current else None for k in changeset.keys()},
after=changeset,
)

self.config = ApiServiceConfig(
items=[ApiConfig(name=k, value=v) for k, v in changeset.items()]
)

@property
def changed(self) -> bool:
return bool(self.config.items)
Loading
Loading