-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: kksat <[email protected]>
- Loading branch information
Showing
8 changed files
with
945 additions
and
73 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,7 +24,7 @@ namespace: sap | |
|
||
name: sap_operations | ||
|
||
version: 1.28.0 | ||
version: 1.29.0 | ||
|
||
readme: README.md | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <https://www.gnu.org/licenses/>. | ||
|
||
|
||
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 | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <https://www.gnu.org/licenses/>. | ||
|
||
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 |
Oops, something went wrong.