diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 462155a..d84033e 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -2,115 +2,133 @@ **Topics** -- v1\.28\.0 +- v1\.29\.0 - Release Summary + - New Modules +- v1\.28\.0 + - Release Summary - Major Changes - Minor Changes - v1\.27\.0 - - Release Summary + - Release Summary - Minor Changes - v1\.26\.0 - - Release Summary -- v1\.25\.0 - Release Summary -- v1\.24\.0 +- v1\.25\.0 - Release Summary -- v1\.23\.1 +- v1\.24\.0 - Release Summary +- v1\.23\.1 + - Release Summary - Major Changes - v1\.23\.0 - - Release Summary + - Release Summary - Major Changes - v1\.22\.1 - - Release Summary + - Release Summary - Minor Changes - v1\.22\.0 - - Release Summary + - Release Summary - v1\.21\.0 - v1\.20\.0 - - Release Summary + - Release Summary - Major Changes - v1\.19\.0 - - Release Summary + - Release Summary - Major Changes - v1\.18\.0 - v1\.17\.0 - - Release Summary + - Release Summary - Major Changes - v1\.16\.0 - v1\.15\.1 - - Release Summary + - Release Summary - Minor Changes - v1\.15\.0 - - Release Summary + - Release Summary - Major Changes - v1\.14\.1 - - Release Summary + - Release Summary - Minor Changes - v1\.14\.0 - v1\.13\.0 - - Release Summary + - Release Summary - Major Changes - v1\.12\.0 - - Release Summary -- v1\.11\.0 - Release Summary +- v1\.11\.0 + - Release Summary - Minor Changes - v1\.10\.0 - - Release Summary -- v1\.9\.1 - Release Summary +- v1\.9\.1 + - Release Summary - Minor Changes - v1\.9\.0 - - Release Summary + - Release Summary - Major Changes - v1\.3\.2 - - Release Summary + - Release Summary - Minor Changes - v1\.3\.1 - - Release Summary + - Release Summary - Minor Changes - v1\.3\.0 - - Release Summary + - Release Summary - Minor Changes - v1\.2\.2 - - Release Summary + - Release Summary - Minor Changes - v1\.2\.1 - - Release Summary + - Release Summary - Minor Changes - v1\.2\.0 - - Release Summary + - Release Summary - Major Changes - v1\.1\.2 - - Release Summary + - Release Summary - Minor Changes - v1\.1\.1 - - Release Summary + - Release Summary - Minor Changes - v1\.1\.0 - - Release Summary -- v1\.0\.5 - Release Summary +- v1\.0\.5 + - Release Summary - Minor Changes - v1\.0\.4 - - Release Summary + - Release Summary - Major Changes - Minor Changes - v1\.0\.3 - - Release Summary + - Release Summary - Minor Changes - v1\.0\.2 - - Release Summary + - Release Summary - Major Changes - v1\.0\.0 - - Release Summary + - Release Summary - Major Changes + +## v1\.29\.0 + + +### Release Summary + +Feature release + + +### New Modules + +* sap\.sap\_operations\.enq\_admin\_info \- Get information from enq\_admin tool for ENSA2 systems +* sap\.sap\_operations\.enq\_admin\_lock \- Manage enque server locks for ENSA2 SAP instances +* sap\.sap\_operations\.enq\_admin\_locks\_info \- Get information about enque server locks for ENSA2 SAP instances + ## v1\.28\.0 - + ### Release Summary Feature and bugfix release @@ -131,7 +149,7 @@ Feature and bugfix release ## v1\.27\.0 - + ### Release Summary Feature release @@ -145,7 +163,7 @@ Feature release ## v1\.26\.0 - + ### Release Summary Feature release @@ -153,7 +171,7 @@ Feature release ## v1\.25\.0 - + ### Release Summary Feature release @@ -161,7 +179,7 @@ Feature release ## v1\.24\.0 - + ### Release Summary Feature release @@ -169,7 +187,7 @@ Feature release ## v1\.23\.1 - + ### Release Summary Documentation release @@ -182,7 +200,7 @@ Documentation release ## v1\.23\.0 - + ### Release Summary Maintenance release @@ -195,7 +213,7 @@ Maintenance release ## v1\.22\.1 - + ### Release Summary Documentation release @@ -209,7 +227,7 @@ Documentation release ## v1\.22\.0 - + ### Release Summary Feature release @@ -220,7 +238,7 @@ Feature release ## v1\.20\.0 - + ### Release Summary Feature release @@ -233,7 +251,7 @@ Feature release ## v1\.19\.0 - + ### Release Summary Feature release @@ -249,7 +267,7 @@ Feature release ## v1\.17\.0 - + ### Release Summary Feature release @@ -265,7 +283,7 @@ Feature release ## v1\.15\.1 - + ### Release Summary Bugfix release @@ -278,7 +296,7 @@ Bugfix release ## v1\.15\.0 - + ### Release Summary Feature release @@ -291,7 +309,7 @@ Feature release ## v1\.14\.1 - + ### Release Summary Bug fix release @@ -308,7 +326,7 @@ Bug fix release ## v1\.13\.0 - + ### Release Summary Feature release @@ -321,7 +339,7 @@ Feature release ## v1\.12\.0 - + ### Release Summary Feature release @@ -329,7 +347,7 @@ Feature release ## v1\.11\.0 - + ### Release Summary Feature release @@ -342,7 +360,7 @@ Feature release ## v1\.10\.0 - + ### Release Summary Feature release @@ -350,7 +368,7 @@ Feature release ## v1\.9\.1 - + ### Release Summary Bug fix release @@ -364,7 +382,7 @@ Bug fix release ## v1\.9\.0 - + ### Release Summary Lifecycle release @@ -382,7 +400,7 @@ Lifecycle release ## v1\.3\.2 - + ### Release Summary Bugfix release @@ -395,7 +413,7 @@ Bugfix release ## v1\.3\.1 - + ### Release Summary Bugfix release @@ -408,7 +426,7 @@ Bugfix release ## v1\.3\.0 - + ### Release Summary Feature release @@ -423,7 +441,7 @@ Feature release ## v1\.2\.2 - + ### Release Summary Feature release @@ -436,7 +454,7 @@ Feature release ## v1\.2\.1 - + ### Release Summary Feature release @@ -449,7 +467,7 @@ Feature release ## v1\.2\.0 - + ### Release Summary Feature release @@ -462,7 +480,7 @@ Feature release ## v1\.1\.2 - + ### Release Summary Bug Fix Release @@ -475,7 +493,7 @@ Bug Fix Release ## v1\.1\.1 - + ### Release Summary Bug Fix Release @@ -491,7 +509,7 @@ Bug Fix Release ## v1\.1\.0 - + ### Release Summary Feature Release @@ -499,7 +517,7 @@ Feature Release ## v1\.0\.5 - + ### Release Summary Bug fix release @@ -512,7 +530,7 @@ Bug fix release ## v1\.0\.4 - + ### Release Summary Two roles are added hana\_update and prepare @@ -531,7 +549,7 @@ Two roles are added hana\_update and ## v1\.0\.3 - + ### Release Summary Using changelog fragments to build collection changelog\. @@ -545,7 +563,7 @@ Using changelog fragments to build collection changelog\. ## v1\.0\.2 - + ### Release Summary First release of SAP Operations collection\. @@ -562,7 +580,7 @@ First release of SAP Operations collection\. ## v1\.0\.0 - + ### Release Summary First release of SAP Operations collection\. diff --git a/galaxy.yml b/galaxy.yml index 7af77c9..c12e3d5 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -24,7 +24,7 @@ namespace: sap name: sap_operations -version: 1.28.0 +version: 1.29.0 readme: README.md diff --git a/meta/runtime.yml b/meta/runtime.yml index 3d4b6cb..b188618 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -22,8 +22,7 @@ --- requires_ansible: ">=2.15.0" action_groups: - "sap.sap_operations.cf": - # TODO: action groups do not work - reason not clear + cf: - cf_marketplace_info - cf_service_instance - cf_service_instance_info @@ -32,3 +31,7 @@ action_groups: - cf_spaces_info - cf_service_instance_keys_info - cf_service_instance_key + enq_admin: + - enq_admin_info + - enq_admin_locks_info + - enq_admin_lock diff --git a/plugins/doc_fragments/enq_admin.py b/plugins/doc_fragments/enq_admin.py new file mode 100644 index 0000000..d623ec5 --- /dev/null +++ b/plugins/doc_fragments/enq_admin.py @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: GPL-3.0-only +# SPDX-FileCopyrightText: 2024 Red Hat, Project Atmosphere +# +# Copyright 2024 Red Hat, Project Atmosphere +# +# This program is free software: you can redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU General Public License for more details. +# +# 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. +# +# You should have received a copy of the GNU General Public License along with this program. +# If not, see . + + +class ModuleDocFragment(object): + DOCUMENTATION = r""" +--- +requirements: + - only for ENSA2 instances with enq_admin tool installed + +author: + - Kirill Satarin (@kksat) + +options: + profile_filepath: + description: + - A path to the profile file + - Either I(profile_filepath) or I(sid), I(hostname) and I(port) required + - I(sid), I(hostname) and I(port) are required together + required: false + type: path + aliases: + - pf + - profile + sid: + description: SAP system id + required: false + type: str + hostname: + description: hostname where enque process is running + required: false + type: str + aliases: + - host + port: + description: Port where enque process is running + required: false + type: int + +seealso: + - name: Architecture of the Standalone Enqueue Server 2 + description: Architecture of the Standalone Enqueue Server 2 + link: https://help.sap.com/docs/latest/e458064e3077486994caaf9a85c4aa23/902412f09e134f5bb875adb6db585c92.html + - name: Parameter Reference of Standalone Enqueue Server 2 + description: Parameter Reference of Standalone Enqueue Server 2 + link: https://help.sap.com/docs/latest/e458064e3077486994caaf9a85c4aa23/1ca2eab4fca04d2696b7185f470b51aa.html +""" diff --git a/plugins/module_utils/enq_admin.py b/plugins/module_utils/enq_admin.py new file mode 100644 index 0000000..f4f1065 --- /dev/null +++ b/plugins/module_utils/enq_admin.py @@ -0,0 +1,228 @@ +# SPDX-License-Identifier: GPL-3.0-only +# SPDX-FileCopyrightText: 2024 Red Hat, Project Atmosphere +# +# Copyright 2024 Red Hat, Project Atmosphere +# +# This program is free software: you can redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU General Public License for more details. +# +# 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. +# +# You should have received a copy of the GNU General Public License along with this program. +# If not, see . + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + + +from ansible.module_utils.basic import AnsibleModule + + +class AnsibleModuleEnqAdmin(AnsibleModule): + def __init__( + self, + argument_spec=None, + required_together=None, + mutually_exclusive=None, + required_one_of=None, + supports_check_mode=False, + required_if=None, + required_by=None, + ): + """Custom AnsibleModule for enq_admin tool.""" + enq_admin_argument_spec = dict( + profile_filepath=dict( + type="path", required=False, aliases=["pf", "profile"] + ), + sid=dict(type="str", required=False), + hostname=dict(type="str", required=False, aliases=["host"]), + port=dict(type="int", required=False), + ) + enq_admin_required_together = [["sid", "hostname", "port"]] + enq_admin_mutually_exclusive = [ + ["profile_filepath", "sid"], + ["profile_filepath", "hostname"], + ["profile_filepath", "port"], + ] + enq_admin_required_one_of = [["profile_filepath", "sid", "hostname", "port"]] + + if argument_spec is not None: + argument_spec = { + k: v + for d in (argument_spec, enq_admin_argument_spec) + for k, v in d.items() + } + else: + argument_spec = enq_admin_argument_spec + required_together = [] if required_together is None else required_together + mutually_exclusive = [] if mutually_exclusive is None else mutually_exclusive + required_one_of = [] if required_one_of is None else required_one_of + required_if = [] if required_if is None else required_if + required_by = {} if required_by is None else required_by + + super(AnsibleModuleEnqAdmin, self).__init__( + argument_spec=argument_spec, + mutually_exclusive=mutually_exclusive + enq_admin_mutually_exclusive, + required_together=required_together + enq_admin_required_together, + required_one_of=required_one_of + enq_admin_required_one_of, + supports_check_mode=supports_check_mode, + required_if=required_if, + required_by=required_by, + ) + + +def run_enq_admin(args, module=None): + if module is None: + return (0, "", "module is required") + + profile_filepath = module.params.get("profile_filepath") + sid = module.params.get("sid") + hostname = module.params.get("hostname") + port = module.params.get("port") + + enq_admin_path = module.get_bin_path("enq_admin") + + if profile_filepath: + default_args = [enq_admin_path, "pf={0}".format(profile_filepath)] + else: + default_args = [ + enq_admin_path, + "--sid={0}".format(sid), + "--host={0}".format(hostname), + "--port={0}".format(port), + ] + + return module.run_command(default_args + args) + + +def convert_string2bool(value): + if value.lower() == "true": + return True + if value.lower() == "false": + return False + return value + + +def get_table_from_csv_data(data): + data_lines = data.split("\n") + table_name = data_lines[0].strip().strip(":") + column_names = data_lines[1].split(";") + column_names = [name.strip() for name in column_names if name != ""] + table = [] + for row in data_lines[2:]: + values = row.split(";") + values = [convert_string2bool(value) for value in values] + table.append(dict(zip(column_names, values))) + + return dict( + table=table, + table_name=table_name, + ) + + +def enq_admin_process_stdout(stdout): + [header, data, footer] = stdout.split("\n\n") + table = get_table_from_csv_data(data) + return dict( + header=header, + data=data, + footer=footer, + table=table["table"], + table_name=table["table_name"], + ) + + +long_lock_type = { + "X": "Exclusive", + "E": "Write", + "S": "Read", + "O": "Optimistic", +} + + +def lock_has_same_attributes(lock, lock_type, owner1, owner2, name, argument): + return ( + lock["Type"] == long_lock_type[lock_type] and + lock["Owner 1"] == owner1 and + lock["Owner 2"] == owner2 and + lock["Name"] == name and + lock["Argument"] == argument + ) + + +def exclusive_lock_with_same_attributes_exists( + lock, lock_type, owner1, owner2, name, argument +): + return ( + lock["Type"] == long_lock_type["X"] and + lock["Owner 1"] == owner1 and + lock["Owner 2"] == owner2 and + lock["Name"] == name and + lock["Argument"] == argument + ) + + +def find_locks_in_locks_list(locks, lock_type, owner1, owner2, name, argument): + return [ + lock + for lock in locks + if lock_has_same_attributes(lock, lock_type, owner1, owner2, name, argument) or + exclusive_lock_with_same_attributes_exists( + lock, lock_type, owner1, owner2, name, argument + ) + ] + + +def lock_exists_in_locks_list(locks, lock_type, owner1, owner2, name, argument): + return ( + len(find_locks_in_locks_list(locks, lock_type, owner1, owner2, name, argument)) > 0 + ) + + +def get_enq_admin_locks_info( + module, run_enq_admin, n="*", client="*", user="*", name="*", argument="*" +): + args = [ + "--csv", + "--no_color", + "--locks={0}:{1}:{2}:{3}:{4}".format(n, client, user, name, argument), + ] + + rc, stdout, stderr = run_enq_admin(module=module, args=args) + + if rc == 0: + data = enq_admin_process_stdout(stdout) + return dict(changed=False, stdout=stdout, enq_admin_locks_info=data["table"]) + return dict( + failed=True, + msg="Failed to get information from enq_admin tool", + stderr=stderr, + stdout=stdout, + rc=rc, + ) + + +def ensure_locks( + state, lock_type, owner1, owner2, name, argument, run_enq_admin, module +): + lock_command = "--set_locks" if state == "present" else "--release_locks" + args = [ + "--csv", + "--no_color", + "{0}=1:{1}:{2}:{3}:{4}:{5}".format( + lock_command, lock_type, owner1, owner2, name, argument + ), + ] + + rc, stdout, stderr = run_enq_admin(module=module, args=args) + return rc, stdout, stderr diff --git a/plugins/modules/enq_admin_info.py b/plugins/modules/enq_admin_info.py new file mode 100644 index 0000000..1c0ba48 --- /dev/null +++ b/plugins/modules/enq_admin_info.py @@ -0,0 +1,111 @@ +#!/usr/bin/python + +# SPDX-License-Identifier: GPL-3.0-only +# SPDX-FileCopyrightText: 2024 Red Hat, Project Atmosphere +# +# Copyright 2024 Red Hat, Project Atmosphere +# +# This program is free software: you can redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU General Public License for more details. +# +# 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. +# +# You should have received a copy of the GNU General Public License along with this program. +# If not, see . + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +--- +module: enq_admin_info + +extends_documentation_fragment: +- sap.sap_operations.community +- sap.sap_operations.enq_admin + +author: + - Kirill Satarin (@kksat) + +short_description: Get information from enq_admin tool for ENSA2 systems + +description: Get information from enq_admin tool for ENSA2 systems + +version_added: 1.29.0 + +options: {} +""" + +EXAMPLES = r""" +--- +- name: Get information from enq_admin tool for ENSA2 systems + sap.sap_operations.enq_admin_info: + pf: /usr/sap/S4H/SYS/profile/S4H_ASCS20_s4ascsa +""" + +RETURN = r""" +--- +stdout: + description: Standard output from enq_admin tool + returned: success + type: str + sample: | + Enqueue Server 2 + Server Status : STATUS_RUNNING + Repl.State : REPLICATION_ON + Repl.Type : REPLICATION_REPLICATOR + Process ID : 17591 + Start Time : 2024-04-30 11:12:13 + Release : 789 + Patch Level : 100 + Compiled On : Linux GNU SLES-15 x86_64 cc10.3.0 use-pr230217 + Compiled At : Feb 17 2023 18:43:20 + Number Clients: 38 + Dev.Trc. Level: 1 + Req.Trc. Level: 0 + + 2024-05-03 15:35:11; OK; 'Process Information'; Response=281 usec + =================================================================================================== +""" + + +from ansible_collections.sap.sap_operations.plugins.module_utils.enq_admin import ( + AnsibleModuleEnqAdmin, + run_enq_admin, +) + + +def run_module(module, run_enq_admin): + rc, stdout, stderr = run_enq_admin(module=module, args=["--info", "--no_color"]) + + if rc == 0: + return dict(changed=False, stdout=stdout) + return dict( + failed=True, + msg="Failed to get information from enq_admin tool", + stderr=stderr, + ) + + +def main(): + + module = AnsibleModuleEnqAdmin( + argument_spec={}, + supports_check_mode=True, + ) + result = run_module(module, run_enq_admin=run_enq_admin) + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/enq_admin_lock.py b/plugins/modules/enq_admin_lock.py new file mode 100644 index 0000000..185690d --- /dev/null +++ b/plugins/modules/enq_admin_lock.py @@ -0,0 +1,274 @@ +#!/usr/bin/python + +# SPDX-License-Identifier: GPL-3.0-only +# SPDX-FileCopyrightText: 2024 Red Hat, Project Atmosphere +# +# Copyright 2024 Red Hat, Project Atmosphere +# +# This program is free software: you can redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU General Public License for more details. +# +# 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. +# +# You should have received a copy of the GNU General Public License along with this program. +# If not, see . + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +--- +module: enq_admin_lock + +extends_documentation_fragment: + - sap.sap_operations.community + - sap.sap_operations.enq_admin + +author: + - Kirill Satarin (@kksat) + +short_description: Manage enque server locks for ENSA2 SAP instances +version_added: 1.29.0 +description: + - Manage enque server locks for ENSA2 SAP instances + - This module will set/release only one lock at a time (parameter n for enq_admin equals 1, see documentation) + - If several locks are needed, use this module several times or in loop, see examples + - If exclusive lock is set, other locks will not be created, information about existing exclusive lock will be created + - Module is idempotent, new locks will not be created if this type of lock or exclusive lock already exists with the same parameters + - | + Value '%u' for parameters is not supported - because only one lock is set/released at a time, + this is not handled by this module. Use ansible loops for this. + +options: + state: + description: State of the lock (present or absent) + required: false + type: str + default: "present" + choices: + - absent + - present + lock_type: + description: + - Lock type + - X - Exclusive lock ("Exclusive") + - E - Exclusive non cumulative lock ("Write") + - S - Shared lock ("Read") + - O - Optimistic lock ("Optimistic") + - if exclusive lock is set, other locks are not allowed + required: true + type: str + aliases: + - type + choices: + - X + - E + - S + - O + owner1: + description: Pattern for dialog lock owner + required: false + type: str + default: "" + owner2: + description: Pattern for update lock owner + required: false + type: str + default: "" + name: + description: Pattern for lock name + required: false + type: str + default: "" + argument: + description: + - Pattern for lock argument + required: false + type: str + default: "" +""" + +EXAMPLES = r""" +--- +- name: Set lock + sap.sap_operations.enq_admin_lock: + pf: /usr/sap/S4H/SYS/profile/S4H_ASCS20_s4ascsa + state: present + lock_type: E + owner1: DIAG + owner2: "" + name: ANSIBLE + argument: ANSIBLE + +- name: Release lock + sap.sap_operations.enq_admin_lock: + pf: /usr/sap/S4H/SYS/profile/S4H_ASCS20_s4ascsa + state: absent + lock_type: E + owner1: DIAG + owner2: "" + name: ANSIBLE + argument: ANSIBLE +""" + +RETURN = r""" +--- +enq_admin_lock: + description: Lock information + returned: if state is present and execution was successful + type: dict + sample: + Argument: ANSIBLE + BCK: false + Client: '000' + Count 1: '1' + Count 2: '0' + Name: ANSIBLE + Object: E_FILL + Owner 1: DIAG + Owner 2: '' + TCODE: SFILL + Type: Write + User: FILL_USER +""" + + +from ansible_collections.sap.sap_operations.plugins.module_utils.enq_admin import ( + AnsibleModuleEnqAdmin, + find_locks_in_locks_list, + run_enq_admin, + get_enq_admin_locks_info, + ensure_locks, +) + + +def run_module(module, run_enq_admin): + lock_type = module.params.get("lock_type") + owner1 = module.params.get("owner1") + owner2 = module.params.get("owner2") + name = module.params.get("name") + argument = module.params.get("argument") + state = module.params.get("state", "present") + + existing_locks = get_enq_admin_locks_info( + module=module, run_enq_admin=run_enq_admin + ) + if existing_locks.get("failed"): + return dict( + failed=True, + msg="Failed to get existing locks from enq_admin tool", + stdout=existing_locks.get("stdout"), + stderr=existing_locks.get("stderr"), + rc=existing_locks.get("rc"), + ) + + existing_locks = find_locks_in_locks_list( + locks=existing_locks.get("enq_admin_locks_info", []), + lock_type=lock_type, + owner1=owner1, + owner2=owner2, + name=name, + argument=argument, + ) + if state == "present" and existing_locks: + return dict( + changed=False, + enq_admin_lock=existing_locks[0], + ) + elif state == "present" and not existing_locks: + rc, stdout, stderr = ensure_locks( + state, lock_type, owner1, owner2, name, argument, run_enq_admin, module + ) + + if rc == 0: + created_locks = get_enq_admin_locks_info( + module=module, run_enq_admin=run_enq_admin + ) + if created_locks.get("failed"): + return dict( + failed=True, + msg="Failed to get locks from enq_admin tool", + stdout=created_locks.get("stdout"), + stderr=created_locks.get("stderr"), + rc=created_locks.get("rc"), + ) + + created_locks = find_locks_in_locks_list( + locks=created_locks.get("enq_admin_locks_info", []), + lock_type=lock_type, + owner1=owner1, + owner2=owner2, + name=name, + argument=argument, + ) + if not created_locks: + return dict( + failed=True, + msg="Failed to get created lock from enq_admin tool", + stdout=created_locks.get("stdout"), + stderr=created_locks.get("stderr"), + rc=created_locks.get("rc"), + ) + + return dict(changed=True, enq_admin_lock=created_locks[0]) + else: + return dict( + failed=True, + msg="Failed to get information from enq_admin tool", + stderr=stderr, + ) + + if state == "absent" and not existing_locks: + return dict( + changed=False, + enq_admin_lock=[], + ) + + if state == "absent" and existing_locks: + rc, stdout, stderr = ensure_locks( + state, lock_type, owner1, owner2, name, argument, run_enq_admin, module + ) + if rc == 0: + return dict(changed=True, enq_admin_lock=[]) + else: + return dict( + failed=True, + msg="Failed to release enq_admin tool", + stderr=stderr, + stdout=stdout, + rc=rc, + ) + + +def main(): + argument_spec = dict( + state=dict(type="str", choices=["absent", "present"], default="present"), + lock_type=dict( + type="str", choices=["X", "E", "S", "O"], aliases=["type"], required=True + ), + owner1=dict(type="str", default=""), + owner2=dict(type="str", default=""), + name=dict(type="str", default=""), + argument=dict(type="str", default=""), + ) + + module = AnsibleModuleEnqAdmin( + argument_spec=argument_spec, + supports_check_mode=True, + ) + result = run_module(module, run_enq_admin=run_enq_admin) + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/enq_admin_locks_info.py b/plugins/modules/enq_admin_locks_info.py new file mode 100644 index 0000000..199ff74 --- /dev/null +++ b/plugins/modules/enq_admin_locks_info.py @@ -0,0 +1,173 @@ +#!/usr/bin/python + +# SPDX-License-Identifier: GPL-3.0-only +# SPDX-FileCopyrightText: 2024 Red Hat, Project Atmosphere +# +# Copyright 2024 Red Hat, Project Atmosphere +# +# This program is free software: you can redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU General Public License for more details. +# +# 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. +# +# You should have received a copy of the GNU General Public License along with this program. +# If not, see . + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +--- +module: enq_admin_locks_info + +extends_documentation_fragment: +- sap.sap_operations.community +- sap.sap_operations.enq_admin + +author: + - Kirill Satarin (@kksat) + +short_description: Get information about enque server locks for ENSA2 SAP instances + +description: Get information about enque server locks for ENSA2 SAP instances + +version_added: 1.29.0 + +options: + n: + description: Number of locks to retrieve + required: false + type: str + default: '*' + aliases: + - number + client: + description: Pattern for client + required: false + type: str + default: '*' + user: + description: Pattern for user name + required: false + type: str + default: '*' + name: + description: Pattern for lock name + required: false + type: str + default: '*' + argument: + description: Pattern for lock argument + required: false + type: str + default: '*' +""" + +EXAMPLES = r""" +--- +- name: Get information about locks from enq_admin tool for ENSA2 systems + sap.sap_operations.enq_admin_locks_info: + pf: /usr/sap/S4H/SYS/profile/S4H_ASCS20_s4ascsa +""" + +RETURN = r""" +--- +enq_admin_locks_info: + description: List of locks, filtered by provided parameters + returned: success + type: list + elements: dict + sample: + - Argument: "0" + BCK: false + Client: "000" + Count 1: "1" + Count 2: "0" + Name: ANSIBLE2 + Object: E_FILL + Owner 1: DIAG + Owner 2: "" + TCODE: SFILL + Type: Exclusive + User: FILL_USER + - Argument: O + BCK: false + Client: "000" + Count 1: "1" + Count 2: "0" + Name: ANSIBLE + Object: E_FILL + Owner 1: DIAG + Owner 2: "" + TCODE: SFILL + Type: Optimistic + User: FILL_USER +stdout: + description: Standard output of the enq_admin tool + returned: always + type: str + sample: | + Enqueue Server 2 + LID=(17591/1714468346); RN=(300151); Current=20; Peak=30; Maximum=250000 + + Locks: + Type;Count 1;Count 2;BCK;Object;User;Client;TCODE;Owner 1;Owner 2;Name;Argument; + Exclusive;1;0;false;E_FILL;FILL_USER;000;SFILL;DIAG;;ANSIBLE2;0; + Optimistic;1;0;false;E_FILL;FILL_USER;000;SFILL;DIAG;;ANSIBLE;O; + + 2024-05-03 15:36:25; OK; 'Lock List'; Response=578 usec + =================================================================================================== +""" + + +from ansible_collections.sap.sap_operations.plugins.module_utils.enq_admin import ( + AnsibleModuleEnqAdmin, + run_enq_admin, + get_enq_admin_locks_info, +) + + +def main(): + argument_spec = dict( + n=dict(type="str", default="*", aliases=["number"]), + client=dict(type="str", default="*"), + user=dict(type="str", default="*"), + name=dict(type="str", default="*"), + argument=dict(type="str", default="*"), + ) + + module = AnsibleModuleEnqAdmin( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + n = module.params.get("n", "*") + client = module.params.get("client", "*") + user = module.params.get("user", "*") + name = module.params.get("name", "*") + argument = module.params.get("argument", "*") + + result = get_enq_admin_locks_info( + module=module, + run_enq_admin=run_enq_admin, + n=n, + client=client, + user=user, + name=name, + argument=argument, + ) + + module.exit_json(**result) + + +if __name__ == "__main__": + main()