Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4df1dcd
Update pytest marker for 'service_config'
wmudge Dec 17, 2024
4d0dea7
Update message for cms_service_config changes
wmudge Dec 17, 2024
c9798f1
Move role and role config group result parsing to separate modules. U…
wmudge Dec 17, 2024
e72cb3b
Enable service-wide configuration management. Update return object.
wmudge Dec 17, 2024
7612a7e
Update to use pytest fixtures for Cloudera Manager Service
wmudge Dec 17, 2024
0b5c98f
Update conn object from fixture
wmudge Dec 17, 2024
a91c59f
Create generic configuration list reconcilation utility
wmudge Dec 18, 2024
fdfbfb1
Add cm_service_role_config module
wmudge Dec 18, 2024
c0a82f9
Add utilities for discovering base role config group for a given role…
wmudge Dec 18, 2024
eab3d18
Add utilities for getting roles by role type
wmudge Dec 18, 2024
6191de9
Add utility to set Cloudera Manager Service role config group configu…
wmudge Dec 18, 2024
8f6334e
Add cm_service_role_config_group module and tests
wmudge Dec 18, 2024
a4e6394
Add 'config' dictionary to parsed Role Config Group results
wmudge Dec 19, 2024
1a275f2
Update utlity function for Role Config Group tests to handle all para…
wmudge Dec 19, 2024
44af849
Move host_monitor and host_monitor_config fixtures and update pytest …
wmudge Dec 19, 2024
72418dc
Update to use reworked host_monitor_config fixture
wmudge Dec 19, 2024
c7602e5
Add cm_service_role_config_group module and tests
wmudge Dec 19, 2024
f7835a8
Add host utilities
wmudge Dec 20, 2024
e4f5e9f
Add utility function for role config group retrieval
wmudge Dec 20, 2024
e287cbf
Add config parameters to parse_role_result. Add utility for role data…
wmudge Dec 20, 2024
6904d89
Rename Host Monitor fixtures. Add host_monitor_state for general role…
wmudge Dec 20, 2024
26402b2
Add cm_service_role and tests
wmudge Dec 20, 2024
092d3dc
Add 'role' marker
wmudge Dec 20, 2024
904b9c2
Consolidate host_monitor role
wmudge Dec 29, 2024
44e0fc0
Fix invalid fixture references
wmudge Jan 3, 2025
159d0d0
Update testing requirements.txt
wmudge Jan 3, 2025
516af16
Fix name of Cloudera Manager client library
wmudge Jan 3, 2025
4a446ac
Add pytest comment and update formatting
wmudge Jan 3, 2025
3558133
Update docstrings and add missing imports for fixtures and fixture ut…
wmudge Jan 3, 2025
7c5aa31
Remove unused imports
wmudge Jan 3, 2025
b3c5556
Update cm_service_role and tests to support role override configurati…
wmudge Jan 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions plugins/module_utils/cluster_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"""

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

from cm_client import ApiCluster
Expand All @@ -42,5 +42,5 @@
def parse_cluster_result(cluster: ApiCluster) -> dict:
# Retrieve full_version as version
output = dict(version=cluster.full_version)
output.update(_parse_output(cluster.to_dict(), CLUSTER_OUTPUT))
output.update(normalize_output(cluster.to_dict(), CLUSTER_OUTPUT))
return output
70 changes: 22 additions & 48 deletions plugins/module_utils/cm_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@
from cm_client import (
ApiClient,
ApiCommand,
ApiConfig,
ApiConfigList,
ApiRole,
ApiRoleConfigGroup,
Configuration,
)
from cm_client.rest import ApiException, RESTClientObject
Expand All @@ -47,34 +46,8 @@
__credits__ = ["[email protected]"]
__maintainer__ = ["[email protected]"]

ROLE_OUTPUT = [
"commission_state",
"config_staleness_status",
"ha_status",
"health_checks",
"health_summary",
# "host_ref",
"maintenance_mode",
"maintenance_owners",
"name",
# "role_config_group_ref",
"role_state",
# "service_ref",
"tags",
"type",
"zoo_keeper_server_mode",
]

ROLE_CONFIG_GROUP = [
"name",
"role_type",
"base",
"display_name",
# "service_ref",
]


def _parse_output(entity: dict, filter: list) -> dict:

def normalize_output(entity: dict, filter: list) -> dict:
output = {}
for k in filter:
if k == "tags":
Expand All @@ -85,24 +58,6 @@ def _parse_output(entity: dict, filter: list) -> dict:
return output


def parse_role_result(role: ApiRole) -> dict:
# Retrieve only the host_id, role_config_group, and service identifiers
output = dict(
host_id=role.host_ref.host_id,
role_config_group_name=role.role_config_group_ref.role_config_group_name,
service_name=role.service_ref.service_name,
)
output.update(_parse_output(role.to_dict(), ROLE_OUTPUT))
return output


def parse_role_config_group_result(role_config_group: ApiRoleConfigGroup) -> dict:
# Retrieve only the service identifier
output = dict(service_name=role_config_group.service_ref.service_name)
output.update(_parse_output(role_config_group.to_dict(), ROLE_CONFIG_GROUP))
return output


def normalize_values(add: dict) -> dict:
"""Normalize parameter values. Strings have whitespace trimmed, integers are
converted to strings, and Boolean values are converted their string representation
Expand Down Expand Up @@ -191,6 +146,25 @@ def resolve_tag_updates(
return (delta_add, delta_del)


class ConfigListUpdates(object):
def __init__(self, existing: ApiConfigList, 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 = ApiConfigList(
items=[ApiConfig(name=k, value=v) for k, v in changeset.items()]
)

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


class ClusterTemplate(object):
IDEMPOTENT_IDS = frozenset(
["refName", "name", "clusterName", "hostName", "product"]
Expand Down
6 changes: 3 additions & 3 deletions plugins/module_utils/data_context_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"""

from ansible_collections.cloudera.cluster.plugins.module_utils.cm_utils import (
_parse_output,
normalize_output,
)
from cm_client import ApiDataContextList

Expand All @@ -38,9 +38,9 @@
]


def _parse_output(data: dict, keys: list) -> dict:
def normalize_output(data: dict, keys: list) -> dict:
return {key: data[key] for key in keys if key in data}


def parse_data_context_result(data_contexts: ApiDataContextList) -> list:
return [_parse_output(item, DATA_CONTEXT_OUTPUT) for item in data_contexts.items]
return [normalize_output(item, DATA_CONTEXT_OUTPUT) for item in data_contexts.items]
57 changes: 57 additions & 0 deletions plugins/module_utils/host_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Copyright 2024 Cloudera, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
A common functions for Cloudera Manager hosts
"""

from cm_client import (
ApiClient,
ApiHost,
ApiHostRef,
HostsResourceApi,
)
from cm_client.rest import ApiException


def get_host(
api_client: ApiClient, hostname: str = None, host_id: str = None
) -> ApiHost:
if hostname:
return next(
(
h
for h in HostsResourceApi(api_client).read_hosts().items
if h.hostname == hostname
),
None,
)
else:
try:
return HostsResourceApi(api_client).read_host(host_id)
except ApiException as ex:
if ex.status != 404:
raise ex
else:
return None


def get_host_ref(
api_client: ApiClient, hostname: str = None, host_id: str = None
) -> ApiHostRef:
host = get_host(api_client, hostname, host_id)
if host is not None:
return ApiHostRef(host.host_id, host.hostname)
else:
return None
4 changes: 2 additions & 2 deletions plugins/module_utils/parcel_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from cm_client import ApiParcel, ParcelResourceApi

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


Expand Down Expand Up @@ -138,5 +138,5 @@ def activate(self):
def parse_parcel_result(parcel: ApiParcel) -> dict:
# Retrieve only the cluster identifier
output = dict(cluster_name=parcel.cluster_ref.cluster_name)
output.update(_parse_output(parcel.to_dict(), PARCEL))
output.update(normalize_output(parcel.to_dict(), PARCEL))
return output
107 changes: 107 additions & 0 deletions plugins/module_utils/role_config_group_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Copyright 2024 Cloudera, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

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

from cm_client import (
ApiClient,
ApiRoleConfigGroup,
ApiRoleConfigGroupRef,
RoleConfigGroupsResourceApi,
MgmtRoleConfigGroupsResourceApi,
)

ROLE_CONFIG_GROUP = [
"name",
"role_type",
"base",
"display_name",
# "service_ref",
]


class BaseRoleConfigGroupDiscoveryException(Exception):
pass


class RoleConfigGroupDiscoveryException(Exception):
pass


def parse_role_config_group_result(role_config_group: ApiRoleConfigGroup) -> dict:
"""Parse a Role Config Group into a normalized dictionary.

Returns the following:
- name (str)
- role_type (str)
- base (bool)
- display_name (str)
- config (dict)

Args:
role_config_group (ApiRoleConfigGroup): Role Config Group

Returns:
dict: Normalized dictionary of returned values
"""
# Retrieve only the service identifier
output = dict(service_name=role_config_group.service_ref.service_name)
output.update(normalize_output(role_config_group.to_dict(), ROLE_CONFIG_GROUP))
output.update(config={c.name: c.value for c in role_config_group.config.items})
return output


def get_base_role_config_group(
api_client: ApiClient, cluster_name: str, service_name: str, role_type: str
) -> ApiRoleConfigGroup:
rcg_api = RoleConfigGroupsResourceApi(api_client)
rcgs = [
r
for r in rcg_api.read_role_config_groups(cluster_name, service_name).items
if r.role_type == role_type and r.base
]
if len(rcgs) != 1:
raise BaseRoleConfigGroupDiscoveryException(role_count=len(rcgs))
else:
return rcgs[0]


def get_mgmt_base_role_config_group(
api_client: ApiClient, role_type: str
) -> ApiRoleConfigGroup:
rcg_api = MgmtRoleConfigGroupsResourceApi(api_client)
rcgs = [
r
for r in rcg_api.read_role_config_groups().items
if r.role_type == role_type and r.base
]
if len(rcgs) != 1:
raise BaseRoleConfigGroupDiscoveryException(role_count=len(rcgs))
else:
return rcgs[0]


def get_role_config_group(
api_client: ApiClient, cluster_name: str, service_name: str, name: str
) -> ApiRoleConfigGroup:
rcg_api = RoleConfigGroupsResourceApi(api_client)

rcg = rcg_api.read_role_config_group(cluster_name, name, service_name)

if rcg is None:
raise RoleConfigGroupDiscoveryException(name)
else:
return rcg
Loading
Loading