diff --git a/plugins/lookup/supported.py b/plugins/lookup/supported.py new file mode 100644 index 00000000..9c56a2fc --- /dev/null +++ b/plugins/lookup/supported.py @@ -0,0 +1,157 @@ +# -*- coding: utf-8 -*- + +# Copyright 2025 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 __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = """ +name: supported +short_description: Get support matrix details +description: + - Retrieve support matrix details for Cloudera Manager, Runtime, or Data Services versions. +author: Cloudera Labs +version_added: 3.0.0 +options: + _terms: + description: + - The categories to return from the support matrix. + - All category entries will be flattened into a single list. + - If undefined, all categories will be returned. + type: str + required: false + choices: + - browsers + - databases + - jdks + - kubernetes + - operating_systems + - processor + - products + version: + description: The version of the product + type: str + required: true + product: + description: The anchor product for the support matrix. + type: str + required: true + choices: + - cloudera_manager + - cloudera_runtime + - cloudera_data_services + timeout: + description: Query timeout (seconds) + type: int + required: false + default: 30 +""" + +EXAMPLES = """ +""" + +RETURN = """ +_value: + description: + - The contents of the license. + type: list + elements: list + contains: {} +""" + +import json +from urllib.error import HTTPError, URLError + +from ansible.errors import AnsibleLookupError +from ansible.module_utils.common.text.converters import to_native +from ansible.module_utils.common.dict_transformations import _snake_to_camel +from ansible.module_utils.urls import open_url, ConnectionError, SSLValidationError +from ansible.plugins.lookup import LookupBase +from ansible.utils.display import Display + +from ansible_collections.cloudera.exe.plugins.module_utils.cldr_supported import ( + parse_support_entries, + support_matrix_url, +) + +display = Display() + + +class LookupModule(LookupBase): + def run(self, terms, variables=None, **kwargs): + self.set_options(var_options=variables, direct=kwargs) + + product = self.get_option("product") + version = self.get_option("version") + timeout = self.get_option("timeout") + + matrix_url, filters = support_matrix_url({product: version}) + + display.v(f"[DEBUG] Support Matrix URL: {matrix_url}") + + ret = [] + + try: + response = open_url( + matrix_url, + headers={ + "Accept": "*/*", + "Content-Type": "application/json", + }, + http_agent="Ansible/cloudera.cluster", + timeout=timeout, + follow_redirects="false", + ) + except HTTPError as e: + if e.status == 302: + msg = " ".join({f"{key}-{value}" for key, value in filters.items()}) + display.warning(f"{msg} does not exist.") + return [] + raise AnsibleLookupError( + "Received HTTP error for %s : %s" % (matrix_url, to_native(e)), + ) + except URLError as e: + raise AnsibleLookupError( + "Failed lookup url for %s : %s" % (matrix_url, to_native(e)), + ) + except SSLValidationError as e: + raise AnsibleLookupError( + "Error validating the server's certificate for %s: %s" + % (matrix_url, to_native(e)), + ) + except ConnectionError as e: + raise AnsibleLookupError( + "Error connecting to %s: %s" % (matrix_url, to_native(e)), + ) + + try: + matrix = json.loads(response.read()) + + if terms: + for t in terms: + ret.extend( + parse_support_entries(matrix.get(_snake_to_camel(t), [])), + ) + else: + for _, v in matrix.items(): + if v: + ret.extend(parse_support_entries(v)) + except json.JSONDecodeError as e: + raise AnsibleLookupError( + "Error parsing support matrix JSON: %s" % to_native(e), + ) + + return ret diff --git a/plugins/module_utils/cldr_supported.py b/plugins/module_utils/cldr_supported.py new file mode 100644 index 00000000..2bd201a7 --- /dev/null +++ b/plugins/module_utils/cldr_supported.py @@ -0,0 +1,99 @@ +# -*- coding: utf-8 -*- + +# Copyright 2025 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 typing import Tuple +from urllib.parse import quote + +from ansible.module_utils.common.dict_transformations import _camel_to_snake + +BASE_URL = "https://supportmatrix.cloudera.com/supportmatrices/cldr" + +# Mapping of parameter names to actual product names in the API +PRODUCT_NAME_MAPPING = { + "cloudera_manager": "Cloudera Manager", + "cloudera_runtime": "CDP Private Cloud Base", + "cloudera_data_services": "CDP Private Cloud Data Services", +} + + +def support_matrix_url(product_versions: dict[str, str]) -> Tuple[str, dict[str, str]]: + """Construct the URL to the Support Matrix server. + + Args: + product_versions (dict[str, str]): product short names and version strings + + Returns: + Tuple[str, dict[str, str]]: URL and dictionary of mapped product full names and version strings + """ + conditions = [] + filters = {} + + # Build single PRODUCT condition with comma-separated values + if product_versions: + products = [] + for short_name, version in product_versions.items(): + product_name = PRODUCT_NAME_MAPPING[short_name] + # URL encode spaces in both product name and version + # Use urllib.parse.quote for proper URL encoding + product_version_string = f"{product_name}-{version}" + encoded_product_version = quote(product_version_string) + + products.append(encoded_product_version) + filters[product_name] = version + + if products: + # Join products with commas for a single PRODUCT parameter + product_condition = f"PRODUCT={','.join(products)}" + conditions.append(product_condition) + + if conditions: + # Add trailing semicolon as shown in the curl example + # Don't URL encode the entire condition string, only spaces are encoded + api_url = "%s?condition=%s;" % (BASE_URL, ";".join(conditions)) + else: + api_url = BASE_URL + + return api_url, filters + + +ENTRY_KEYS = set( + [ + "description", + "family", + "id", + "version", + "group", + "org", + "productName", + "release_date", + "name", + ], +) + + +def parse_support_entries(entries: list[dict]) -> list[dict]: + """Constrain support matrix entries to a known set of keys. + + Args: + entries (list[dict]): Support matrix entries + + Returns: + list[dict]: Entries with only 'description', 'family', 'id', 'version', 'group', 'org', 'product_name', and 'release_date'. + """ + return [ + {_camel_to_snake(k): v for k, v in d.items() if k in ENTRY_KEYS} + for d in entries + ] diff --git a/plugins/modules/supported.py b/plugins/modules/supported.py index 1c42388f..9b6e1081 100755 --- a/plugins/modules/supported.py +++ b/plugins/modules/supported.py @@ -20,28 +20,28 @@ short_description: Retrieve Cloudera Support Matrix information description: - Retrieve product compatibility and support information from the Cloudera Support Matrix API. - - Supports filtering by Cloudera Runtime, Manager and Data Service product versions. + - Supports filtering by Cloudera Runtime, Manager or Data Service product versions. - Returns comprehensive support matrix data including compatibility information across different Cloudera products. author: - "Jim Enright (@jimright)" version_added: "3.0.0" options: - cloudera_manager_version: + cloudera_manager: description: - Filter by specific Cloudera Manager version. - - Mutually exclusive with the O(cloudera_runtime_version) and O(cloudera_data_services_version) parameters. + - Mutually exclusive with the O(cloudera_runtime) and O(cloudera_data_services) parameters. type: str required: false - cloudera_runtime_version: + cloudera_runtime: description: - Filter by specific CDP Private Cloud Base (Cloudera Runtime) version. - - Mutually exclusive with the O(cloudera_manager_version) and O(cloudera_data_services_version) parameters. + - Mutually exclusive with the O(cloudera_manager) and O(cloudera_data_services) parameters. type: str required: false - cloudera_data_services_version: + cloudera_data_services: description: - Filter by specific CDP Private Cloud Data Services version. - - Mutually exclusive with the O(cloudera_manager_version) and O(cloudera_runtime_version) parameters. + - Mutually exclusive with the O(cloudera_manager) and O(cloudera_runtime) parameters. type: str required: false timeout: @@ -50,7 +50,7 @@ type: int default: 30 notes: - - Only one of the O(cloudera_manager_version), O(cloudera_runtime_version) or O(cloudera_data_services_version) parameters can be specified. + - Only one of the O(cloudera_manager), O(cloudera_runtime) or O(cloudera_data_services) parameters can be specified. """ EXAMPLES = r""" @@ -60,17 +60,17 @@ - name: Get support matrix for Cloudera Manager version cloudera.exe.supported: - cloudera_manager_version: "7.13.1" + cloudera_manager: "7.13.1" register: cm_support - name: Get support matrix for Cloudera Runtime version cloudera.exe.supported: - cloudera_runtime_version: "7.1.9 SP1" + cloudera_runtime: "7.1.9 SP1" register: base_support - name: Get support matrix for Cloudera Data Services version cloudera.exe.supported: - cloudera_data_services_version: "1.5.4" + cloudera_data_services: "1.5.4" register: ds_support """ @@ -83,11 +83,30 @@ browsers: description: Browser support information type: list - returned: always + elements: dict + returned: when supported databases: description: Database compatibility information type: list - returned: always + elements: dict + returned: when supported + contains: + description: + description: Description of the database + type: str + returned: always + family: + description: Database family identifier + type: str + returned: always + id: + description: Support matrix ID for the entry + type: int + returned: always + version: + description: Version of the database + type: str + returned: always sample: [ { "version": "13", @@ -99,7 +118,25 @@ jdks: description: JDK compatibility information type: list - returned: always + elements: dict + returned: when supported + contains: + description: + description: Description of the JDK + type: str + returned: always + family: + description: JDK family identifier + type: str + returned: always + id: + description: Support matrix ID for the entry + type: int + returned: always + version: + description: Version of the JDK + type: str + returned: always sample: [ { "version": "JDK11", @@ -111,7 +148,37 @@ products: description: Cloudera product information type: list - returned: always + elements: dict + returned: when supported + contains: + description: + description: Description of the product + type: str + returned: always + group: + description: Group identifier + type: str + returned: always + id: + description: Support matrix ID for the entry + type: int + returned: always + org: + description: Support matrix organization + type: str + returned: always + product_name: + description: Full product name + type: str + returned: always + release_date: + description: Release date of the product (DD-MM-YYY) + type: str + returned: when supported + version: + description: Version of the product + type: str + returned: always sample: [ { "version": "7.13.1", @@ -128,11 +195,55 @@ processor: description: Processor architecture compatibility type: list - returned: always - operatingSystems: + elements: dict + returned: when supported + contains: + description: + description: Description of the architecture + type: str + returned: always + family: + description: Architecture family identifier + type: str + returned: always + id: + description: Support matrix ID for the entry + type: int + returned: always + name: + description: Name of the architecture + type: int + returned: always + version: + description: Version of the architecture + type: str + returned: always + operating_systems: description: Operating system compatibility type: list - returned: always + elements: dict + returned: when supported + contains: + description: + description: Description of the OS + type: str + returned: always + family: + description: OS family identifier + type: str + returned: always + group: + description: Group identifier + type: str + returned: always + id: + description: Support matrix ID for the entry + type: int + returned: always + version: + description: Version of the OS + type: str + returned: always sample: [ { "version": "9.4", @@ -142,30 +253,29 @@ "group": "9" } ] -filters_applied: +filters: description: Summary of filters that were applied to the API request type: dict returned: always contains: - cloudera_manager_version: - description: Cloudera Manager version filter applied - type: str - returned: when filter applied - cloudera_runtime_version: - description: CDP Private Cloud Base version filter applied - type: str - returned: when filter applied - cloudera_data_services_version: - description: CDP Private Cloud Data Services version filter applied + _product full name_: + description: Full name and version of the supplied product type: str returned: when filter applied """ import json + from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.common.text.converters import to_native +from ansible.module_utils.common.dict_transformations import _camel_to_snake from ansible.module_utils.urls import fetch_url, to_text -from urllib.parse import quote + +from ansible_collections.cloudera.exe.plugins.module_utils.cldr_supported import ( + PRODUCT_NAME_MAPPING, + parse_support_entries, + support_matrix_url, +) class ClouderaSupportMatrix: @@ -176,15 +286,6 @@ class ClouderaSupportMatrix: and processing of responses from the Cloudera Support Matrix API. """ - BASE_URL = "https://supportmatrix.cloudera.com/supportmatrices/cldr" - - # Mapping of parameter names to actual product names in the API - PRODUCT_NAME_MAPPING = { - "cloudera_manager_version": "Cloudera Manager", - "cloudera_runtime_version": "CDP Private Cloud Base", - "cloudera_data_services_version": "CDP Private Cloud Data Services", - } - def __init__(self, module): """ Initialize the ClouderaSupportMatrix class. @@ -196,7 +297,7 @@ def __init__(self, module): # Extract product version parameters self.product_versions = {} - for param_name in self.PRODUCT_NAME_MAPPING.keys(): + for param_name in PRODUCT_NAME_MAPPING.keys(): version = module.params.get(param_name) if version: self.product_versions[param_name] = version @@ -205,57 +306,11 @@ def __init__(self, module): # Initialize return values self.support_matrix_data = {} - self.filters_applied = {} + self.filters = {} # Execute the logic self.process() - def _build_query_conditions(self): - """ - Build query conditions for API filtering. - - Returns: - str: Query conditions string for the API request - """ - conditions = [] - - # Build single PRODUCT condition with comma-separated values - if self.product_versions: - products = [] - for param_name, version in self.product_versions.items(): - product_name = self.PRODUCT_NAME_MAPPING[param_name] - # URL encode spaces in both product name and version - # Use urllib.parse.quote for proper URL encoding - product_version_string = f"{product_name}-{version}" - encoded_product_version = quote(product_version_string) - products.append(encoded_product_version) - self.filters_applied[param_name] = version - - if products: - # Join products with commas for a single PRODUCT parameter - product_condition = f"PRODUCT={','.join(products)}" - conditions.append(product_condition) - - return ";".join(conditions) - - def _build_api_url(self): - """ - Build the complete API URL with query parameters. - - Returns: - str: Complete API URL - """ - conditions = self._build_query_conditions() - - if conditions: - # Add trailing semicolon as shown in the curl example - # Don't URL encode the entire condition string, only spaces are encoded - api_url = f"{self.BASE_URL}?condition={conditions};" - else: - api_url = self.BASE_URL - - return api_url - def process(self): """ Fetch support matrix data from the Cloudera API using Ansible's fetch_url. @@ -263,7 +318,7 @@ def process(self): try: # Build the API URL - api_url = self._build_api_url() + api_url, self.filters = support_matrix_url(self.product_versions) # Prepare headers headers = { @@ -280,12 +335,16 @@ def process(self): timeout=self.timeout, ) - if info.get("status") != 200: + if info.get("status") == 302: + self.module.fail_json( + msg=f"Product(s) not found: {', '.join(f"{key}-{value}" for key, value in self.filters.items())}", + ) + elif info.get("status") != 200: self.module.fail_json( msg=f"HTTP error occurred: {info.get('msg', 'Unknown error')}", - api_url=api_url, - http_status=info.get("status"), - http_reason=info.get("msg"), + url=api_url, + status=info.get("status"), + reason=info.get("msg"), ) if response: @@ -298,7 +357,11 @@ def process(self): # Parse JSON response try: - self.support_matrix_data = json.loads(response_text) + matrix = json.loads(response_text) + for k, v in matrix.items(): + self.support_matrix_data[_camel_to_snake(k)] = ( + parse_support_entries(v) + ) except json.JSONDecodeError as e: self.module.fail_json( msg=f"Failed to parse JSON response: {to_native(e)}", @@ -321,16 +384,16 @@ def main(): # Define module arguments module = AnsibleModule( argument_spec=dict( - cloudera_manager_version=dict(type="str", required=False), - cloudera_runtime_version=dict(type="str", required=False), - cloudera_data_services_version=dict(type="str", required=False), + cloudera_manager=dict(type="str", required=False), + cloudera_runtime=dict(type="str", required=False), + cloudera_data_services=dict(type="str", required=False), timeout=dict(type="int", default=30), ), mutually_exclusive=[ ( - "cloudera_manager_version", - "cloudera_runtime_version", - "cloudera_data_services_version", + "cloudera_manager", + "cloudera_runtime", + "cloudera_data_services", ), ], ) @@ -342,7 +405,7 @@ def main(): output = dict( changed=False, support_matrix_data=result.support_matrix_data, - filters_applied=result.filters_applied, + filters=result.filters, ) module.exit_json(**output) diff --git a/roles/prereq_supported/README.md b/roles/prereq_supported/README.md index 1ba4b7ab..86614417 100644 --- a/roles/prereq_supported/README.md +++ b/roles/prereq_supported/README.md @@ -2,18 +2,17 @@ Verify configuration against support matrix -This role verifies various system and configuration settings on a target host against the official Cloudera on-premises support matrix, which is available at [supportmatrix.cloudera.com/](https://supportmatrix.cloudera.com). It is designed to be run early in a deployment pipeline to ensure that the environment meets all prerequisites before proceeding with the installation of Cloudera products. Additionally, the role defines and makes available a `support_matrix` variable that can be imported and utilized by other roles for their own specific verification needs. +This role verifies various system and configuration settings on a target host against the official Cloudera on-premises support matrix, which is available at [supportmatrix.cloudera.com/](https://supportmatrix.cloudera.com). It is designed to be run early in a deployment pipeline to ensure that the environment meets all prerequisites before proceeding with the installation of Cloudera products. The role will: - Collect system facts about the target host (OS version, kernel, etc.). -- Compare these facts against the requirements defined in the internal `support_matrix` data structure for the specified versions of Cloudera Manager, Cloudera Runtime, and Data Services. +- Compare these facts against the requirements defined by the support matrix at [supportmatrix.cloudera.com/](https://supportmatrix.cloudera.com) for the specified versions of Cloudera Manager, Cloudera Runtime, and Data Services. - Log any discrepancies or unsupported configurations. -- The `support_matrix` variable will be available for use in subsequent tasks or roles within the same playbook. # Requirements - This role is intended to be run on the target hosts to gather accurate system facts. -- It requires a well-defined `support_matrix` data structure in its internal variables that corresponds to the official Cloudera support matrix. +- Access to the [supportmatrix.cloudera.com/](https://supportmatrix.cloudera.com) site. # Dependencies @@ -25,7 +24,7 @@ None. | --- | --- | --- | --- | --- | | `cloudera_manager_version` | `str` | `True` | | The version of Cloudera Manager to validate against. | | `cloudera_runtime_version` | `str` | `True` | | The version of Cloudera Runtime to validate against. | -| `data_services_version` | `str` | `False` | | The version of Cloudera Data Services to validate against. This is an optional parameter. | +| `cloudera_data_services_version` | `str` | `False` | | The version of Cloudera Data Services to validate against. | # Example Playbook @@ -38,17 +37,13 @@ None. vars: cloudera_manager_version: "7.11.3" cloudera_runtime_version: "7.1.9" - data_services_version: "1.0.0" # Optional parameter - - - name: Use the support matrix variable in a subsequent task - ansible.builtin.debug: - msg: "The supported Python version is {{ support_matrix.python_version }}" + cloudera_data_services_version: "1.0.0" # Optional parameter ``` # License ``` -Copyright 2024 Cloudera, Inc. +Copyright 2025 Cloudera, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/roles/prereq_supported/defaults/main.yml b/roles/prereq_supported/defaults/main.yml index 5a76601a..b293a1fd 100644 --- a/roles/prereq_supported/defaults/main.yml +++ b/roles/prereq_supported/defaults/main.yml @@ -1,4 +1,5 @@ -# Copyright 2024 Cloudera, Inc. +--- +# Copyright 2025 Cloudera, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,8 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. ---- -cloudera_manager_version: "{{ undef(hint='Cloudera Manager Version') }}" -cloudera_runtime_version: "{{ undef(hint='Cloudera Runtime Version') }}" - -data_services_version: +cloudera_manager_version: "{{ undef(hint='Please specify the Cloudera Manager version') }}" +cloudera_runtime_version: "{{ undef(hint='Please specify the Cloudera Runtime version') }}" +# cloudera_data_services_version: diff --git a/roles/prereq_supported/meta/argument_specs.yml b/roles/prereq_supported/meta/argument_specs.yml index 7b02ea7b..14ff8eeb 100644 --- a/roles/prereq_supported/meta/argument_specs.yml +++ b/roles/prereq_supported/meta/argument_specs.yml @@ -17,21 +17,22 @@ argument_specs: main: short_description: Verify configuration against support matrix description: - - Verification of various system and configuration settings against the Cloudera on premise support matrix available at supportmatrix.cloudera.com. - - Additionally, the I(support_matrix) variable defined in this role can be imported and used in other roles. + - Verification of various system and configuration settings against the Cloudera on premise + support matrix available at L(Cloudera Support Matrix,https://supportmatrix.cloudera.com). author: - "Jim Enright " + - "Webster Mudge " version_added: "3.0.0" options: cloudera_manager_version: description: Version of Cloudera Manager - type: "str" + type: str required: true cloudera_runtime_version: description: Version of Cloudera Runtime - type: "str" + type: str required: true - data_services_version: + cloudera_data_services_version: description: Version of Cloudera Runtime - type: "str" + type: str required: false diff --git a/roles/prereq_supported/tasks/main.yml b/roles/prereq_supported/tasks/main.yml index 6343c485..a3d5de92 100644 --- a/roles/prereq_supported/tasks/main.yml +++ b/roles/prereq_supported/tasks/main.yml @@ -1,4 +1,5 @@ -# Copyright 2024 Cloudera, Inc. +--- +# Copyright 2025 Cloudera, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,54 +13,55 @@ # See the License for the specific language governing permissions and # limitations under the License. ---- -- name: Load support matrix variables for OS - ansible.builtin.include_vars: "{{ item }}" - with_first_found: - - "{{ ansible_facts['distribution'] }}-{{ ansible_facts['distribution_version'] }}.yml" - - "{{ ansible_facts['distribution'] }}-{{ ansible_facts['distribution_major_version'] }}.yml" - - "{{ ansible_facts['distribution'] }}.yml" - - "{{ ansible_facts['os_family'] }}-{{ ansible_facts['distribution_version'] }}.yml" - - "{{ ansible_facts['os_family'] }}-{{ ansible_facts['distribution_major_version'] }}.yml" - - "{{ ansible_facts['os_family'] }}.yml" - - "default.yml" +- name: Gather distribution details + ansible.builtin.setup: + gather_subset: distribution -- name: Print discovered support matrix based on manager and runtime version - ansible.builtin.debug: - var: support_matrix | selectattr('manager_version', '==', (cm_version.major + '.' + cm_version.minor + '.' + cm_version.patch)) | - selectattr('runtime_version', '==', cloudera_runtime_version | regex_search('(\\d+\\.\\d+\\.\\d+)')) - verbosity: 2 - vars: - cm_version: "{{ cloudera_manager_version | cloudera.exe.cm_version }}" - -# Validation 1 - Operating Supported OS for given inputs -- name: Assert that OS is supported for Cloudera Runtime and Manager versions +- name: Assert OS support for Cloudera Runtime and Manager versions ansible.builtin.assert: that: - - support_matrix | selectattr('manager_version', '==', (cm_version.major + '.' + cm_version.minor + '.' + cm_version.patch)) | - selectattr('runtime_version', '==', cloudera_runtime_version | regex_search('(\\d+\\.\\d+\\.\\d+)')) | length > 0 + - supported_cms | + selectattr('family', 'eq', prereq_supported_distribution_map[ansible_facts['distribution']] | default(ansible_facts['distribution'])) | + selectattr('version', 'eq', ansible_facts['distribution_version']) | + length > 0 + - supported_runtime | + selectattr('family', 'eq', prereq_supported_distribution_map[ansible_facts['distribution']] | default(ansible_facts['distribution'])) | + selectattr('version', 'eq', ansible_facts['distribution_version']) | + length > 0 fail_msg: "OS {{ ansible_facts['distribution'] }}-{{ ansible_facts['distribution_version'] }} not supported." vars: - cm_version: "{{ cloudera_manager_version | cloudera.exe.cm_version }}" + supported_cms: "{{ lookup('cloudera.exe.supported', 'operating_systems', product='cloudera_manager', version=cloudera_manager_version) }}" + supported_runtime: "{{ lookup('cloudera.exe.supported', 'operating_systems', product='cloudera_runtime', version=cloudera_runtime_version) }}" -# Validation 2 - Check if ECS is defined and supported -- name: Data Services validations - when: data_services_version != None +- name: Assert OS, Cloudera Manager, and Cloudera Runtime support for Cloudera Data Services version + when: cloudera_data_services_version is defined + vars: + supported_ecs: "{{ lookup('cloudera.exe.supported', 'products', 'operating_systems', product='cloudera_data_services', version=cloudera_data_services_version) }}" block: - - name: Asset that OS is supported for Data Services + - name: Assert OS support for Cloudera Data Services version ansible.builtin.assert: that: - - ansible_os_family in ecs_supported_os_families - fail_msg: "ECS '{{ data_services_version }}' is not supported on OS family '{{ ansible_os_family }}'." + - supported_ecs | + selectattr('family', 'defined') | + selectattr('family', 'eq', prereq_supported_distribution_map[ansible_facts['distribution']] | default(ansible_facts['distribution'])) | + selectattr('version', 'eq', ansible_facts['distribution_version']) | + length > 0 + fail_msg: "OS {{ ansible_facts['distribution'] }}-{{ ansible_facts['distribution_version'] }} not supported." - - name: Assert that Data Services Version is supported for Cloudera Runtime and Manager versions + - name: Assert Cloudera Runtime and Manager support for Cloudera Data Services version ansible.builtin.assert: that: - - support_matrix | selectattr('manager_version', '==', (cm_version.major + '.' + cm_version.minor + '.' + cm_version.patch)) | - selectattr('runtime_version', '==', cloudera_runtime_version) | selectattr('data_services_version', 'version', data_services_version, operator='le', - version_type='semver') | length > 0 - fail_msg: >- - Data Services version '{{ data_services_version }}' not supported for runtime '{{ cloudera_runtime_version }}' and manager version '{{ cloudera_manager_version - }}'. - vars: - cm_version: "{{ cloudera_manager_version | cloudera.exe.cm_version }}" + - supported_ecs | + selectattr('product_name', 'defined') | + selectattr('product_name', 'eq', 'CDP Private Cloud Base') | + selectattr('version', 'eq', cloudera_runtime_version) | + length > 0 + - supported_ecs | + selectattr('product_name', 'defined') | + selectattr('product_name', 'eq', 'Cloudera Manager') | + selectattr('version', 'eq', cloudera_manager_version) | + length > 0 + fail_msg: > + Data Services {{ cloudera_data_services_version }} not supported for + Runtime {{ cloudera_runtime_version }} and/or + Manager {{ cloudera_manager_version }} diff --git a/roles/prereq_supported/vars/RedHat-8.yml b/roles/prereq_supported/vars/RedHat-8.yml deleted file mode 100644 index 1d7cfaf8..00000000 --- a/roles/prereq_supported/vars/RedHat-8.yml +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2025 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. - ---- -# Support matrix definition for given operating system family -# Format of each list item: -# manager_version: -# runtime_version: -# python_version: -# python2: # Optional, if required -# data_services_version: # Optional, if required - -# TODO: Support qualifiers for minimum versions -support_matrix: - - manager_version: "7.13.1" - runtime_version: "7.3.1" - python_version: "3.9.14" - - manager_version: "7.11.3" - runtime_version: "7.1.9" - python_version: "3.8.0" - data_services_version: "1.5.4" diff --git a/roles/prereq_supported/vars/RedHat-9.yml b/roles/prereq_supported/vars/RedHat-9.yml deleted file mode 100644 index 2fec417f..00000000 --- a/roles/prereq_supported/vars/RedHat-9.yml +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2025 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. - ---- -# Support matrix definition for given operating system family -# Format of each list item: -# manager_version: -# runtime_version: -# python_version: -# python2: # Optional, if required -# data_services_version: # Optional, if required - -# TODO: Support qualifiers for minimum versions -support_matrix: - - manager_version: "7.13.1" - runtime_version: "7.3.1" - python_version: "3.9.14" - - manager_version: "7.13.1" - runtime_version: "7.1.9" - python_version: "3.9.14" - data_services_version: "1.5.5" - - manager_version: "7.11.3" - runtime_version: "7.1.9" - python_version: "3.9.14" - data_services_version: "1.5.4" - - manager_version: "7.11.3" - runtime_version: "7.1.7" - python_version: "3.9.14" - python2: "2.7" diff --git a/roles/prereq_supported/vars/Ubuntu-20.04.yml b/roles/prereq_supported/vars/Ubuntu-20.04.yml deleted file mode 100644 index ddffd9aa..00000000 --- a/roles/prereq_supported/vars/Ubuntu-20.04.yml +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2025 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. - ---- -# Support matrix definition for given operating system family -# Format of each list item: -# manager_version: -# runtime_version: -# python_version: -# python2: # Optional, if required - -# TODO: Support qualifiers for minimum versions - -support_matrix: - - manager_version: "7.13.1" - runtime_version: "7.3.1" - python_version: "3.8.12" - - manager_version: "7.11.3" - runtime_version: "7.1.9" - python_version: "3.8.12" - - manager_version: "7.11.3" - runtime_version: "7.1.7" - python_version: "3.8.12" - python2: "2.7" diff --git a/roles/prereq_supported/vars/default.yml b/roles/prereq_supported/vars/default.yml deleted file mode 100644 index e64db561..00000000 --- a/roles/prereq_supported/vars/default.yml +++ /dev/null @@ -1,25 +0,0 @@ -# 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. - ---- -# Support matrix definition for given operating system family -# Format of each list item: -# manager_version: -# runtime_version: -# python_version: -# python2: # Optional, if required -# data_services_version: # Optional, if required - -# TODO: Support qualifiers for minimum versions -support_matrix: [] diff --git a/roles/prereq_supported/vars/main.yml b/roles/prereq_supported/vars/main.yml index 0cbb421e..c150b141 100644 --- a/roles/prereq_supported/vars/main.yml +++ b/roles/prereq_supported/vars/main.yml @@ -14,5 +14,6 @@ --- -ecs_supported_os_families: - - "RedHat" +# Map of ansible_distribution -> support matrix 'family' +prereq_supported_distribution_map: + RedHat: RHEL diff --git a/tests/unit/plugins/lookup/test_lookup_supported.py b/tests/unit/plugins/lookup/test_lookup_supported.py new file mode 100644 index 00000000..842a22ce --- /dev/null +++ b/tests/unit/plugins/lookup/test_lookup_supported.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- + +# Copyright 2025 Cloudera, Inc. All Rights Reserved. +# +# 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 +# +# http://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 __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import pytest + +from ansible.plugins.loader import lookup_loader + + +@pytest.mark.skip("Unable to load non-builtin collection resources") +def test_lookup_supported(): + supported_lookup = lookup_loader.get( + "cloudera.exe.supported", + ) # , collection_list=[request.config.rootdir] + + # lookup('cloudera.exe.supported', "7.1.9", type="cloudera_manager", categories=["jdks", "products"]) + # lookup('cloudera.exe.supported', ["jdks", "products"], version="7.1.9", type="cloudera_manager") + # lookup('cloudera.exe.supported', version="7.1.9", type="cloudera_manager") + # lookup('cloudera.exe.supported', "jdks", version="7.3.1 SP2", type="cloudera_runtime") + actual = supported_lookup.run(["7.1.9"], type="cloudera_manager")