Skip to content

Commit 7747e5c

Browse files
authored
Merge pull request #69 from sap-linuxlab/dev
Merge dev to main for release 1.6.0
2 parents e551e82 + e7c4d80 commit 7747e5c

21 files changed

+927
-28
lines changed

CHANGELOG.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,20 @@ Community SAP Release Notes
44

55
.. contents:: Topics
66

7+
v1.6.0
8+
======
9+
10+
Release Summary
11+
---------------
12+
13+
This release adds new module `sap_hostctrl_exec` that allows executing `SAPHostcontrol` functions.
14+
New contributors readme is added to show our appreciation to contributors.
15+
16+
Minor Changes
17+
-------------
18+
- sap_control_exec - Add local socket support (https://github.com/sap-linuxlab/community.sap_libs/pull/66)
19+
- sap_hostctrl_exec - Add new module and tests (https://github.com/sap-linuxlab/community.sap_libs/pull/67)
20+
721
v1.5.0
822
======
923

CONTRIBUTORS.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Contributors to community.sap_libs
2+
3+
Thank you to all contributors who have helped make this project possible!
4+
5+
We welcome contributions! Please see our [contributing guidelines](https://sap-linuxlab.github.io/initiative_contributions/) to get started.
6+
7+
## Maintainers
8+
9+
The following people are the maintainers of this collection:
10+
11+
### SUSE
12+
13+
- [Marcel Mamula](https://github.com/marcelmamula)
14+
15+
16+
For specific role maintainers, see the `README.md` file in the corresponding role's directory.
17+
18+
## All Contributors
19+
20+
| Name | Commits | Lines Changed | Last Commit |
21+
| ---- | ------- | ------------- | ----------- |
22+
| [Rainer Leber](https://github.com/rainerleber) | 23 | 11921 | 2025-09-22 |
23+
| ydouvry | 8 | 892 | 2025-12-09 |
24+
| Nicolas Bettembourg | 7 | 265 | 2025-10-27 |
25+
| [Marcel Mamula](https://github.com/marcelmamula) | 4 | 1404 | 2025-10-16 |
26+
| stm85 | 1 | 4 | 2024-04-29 |
27+
| [Sean Freeman](https://github.com/sean-freeman) | 1 | 3 | 2022-11-11 |
28+
29+
## Contributions by Module
30+
31+
### Module: sap_control_exec.py
32+
33+
| Name | Commits | Lines Changed | Last Commit |
34+
| ---- | ------- | ------------- | ----------- |
35+
| Nicolas Bettembourg | 4 | 221 | 2025-10-27 |
36+
| [Rainer Leber](https://github.com/rainerleber) | 4 | 555 | 2025-09-22 |
37+
38+
### Module: sap_pyrfc.py
39+
40+
| Name | Commits | Lines Changed | Last Commit |
41+
| ---- | ------- | ------------- | ----------- |
42+
| [Rainer Leber](https://github.com/rainerleber) | 4 | 191 | 2023-03-08 |
43+
44+
### Module: sap_snote.py
45+
46+
| Name | Commits | Lines Changed | Last Commit |
47+
| ---- | ------- | ------------- | ----------- |
48+
| [Rainer Leber](https://github.com/rainerleber) | 3 | 269 | 2022-12-05 |
49+
50+
### Module: sap_system_facts.py
51+
52+
| Name | Commits | Lines Changed | Last Commit |
53+
| ---- | ------- | ------------- | ----------- |
54+
| [Rainer Leber](https://github.com/rainerleber) | 2 | 215 | 2022-09-09 |
55+
56+
### Module: sap_task_list_execute.py
57+
58+
| Name | Commits | Lines Changed | Last Commit |
59+
| ---- | ------- | ------------- | ----------- |
60+
| [Rainer Leber](https://github.com/rainerleber) | 3 | 352 | 2022-12-05 |
61+
62+
### Module: sap_hostctrl_exec.py
63+
64+
| Name | Commits | Lines Changed | Last Commit |
65+
| ---- | ------- | ------------- | ----------- |
66+
| ydouvry | 8 | 506 | 2025-12-09 |
67+
68+
### Module: sapcar_extract.py
69+
70+
| Name | Commits | Lines Changed | Last Commit |
71+
| ---- | ------- | ------------- | ----------- |
72+
| [Rainer Leber](https://github.com/rainerleber) | 2 | 230 | 2022-09-09 |
73+
74+
### Module: sap_hdbsql.py
75+
76+
| Name | Commits | Lines Changed | Last Commit |
77+
| ---- | ------- | ------------- | ----------- |
78+
| [Marcel Mamula](https://github.com/marcelmamula) | 1 | 2 | 2025-09-25 |
79+
| stm85 | 1 | 2 | 2024-04-29 |
80+
| [Rainer Leber](https://github.com/rainerleber) | 1 | 246 | 2022-09-09 |
81+
82+
### Module: sap_user.py
83+
84+
| Name | Commits | Lines Changed | Last Commit |
85+
| ---- | ------- | ------------- | ----------- |
86+
| [Rainer Leber](https://github.com/rainerleber) | 3 | 510 | 2022-12-05 |
87+
88+
### Module: sap_company.py
89+
90+
| Name | Commits | Lines Changed | Last Commit |
91+
| ---- | ------- | ------------- | ----------- |
92+
| [Rainer Leber](https://github.com/rainerleber) | 3 | 337 | 2022-12-05 |
93+

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ modules where we are able to execute integration test we decided to disable thes
9292
You can find more information about maintainers of this Ansible Collection at [MAINTAINERS.md](https://github.com/sap-linuxlab/community.sap_libs/blob/main/MAINTAINERS.md).
9393

9494
## Contributing
95-
You can find more information about ways you can contribute at [sap-linuxlab website](https://sap-linuxlab.github.io/initiative_contributions/).
95+
We welcome contributions to this collection. For a list of all contributors and information on how you can get involved, please see our [CONTRIBUTORS document](./CONTRIBUTORS.md).
9696

9797
## Support
9898
You can report any issues using [Issues](https://github.com/sap-linuxlab/community.sap_libs/issues) section.

changelogs/changelog.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,11 @@ releases:
136136
release_summary: This release removes `Python 2` support and updates `ansible-test` workflow to validate latest versions.
137137
Documentation was updated to reflect supported and tested versions.
138138
release_date: '2025-09-25'
139+
1.6.0:
140+
changes:
141+
minor_changes:
142+
- sap_control_exec - Add local socket support (https://github.com/sap-linuxlab/community.sap_libs/pull/66)
143+
- sap_hostctrl_exec - Add new module and tests (https://github.com/sap-linuxlab/community.sap_libs/pull/67)
144+
release_summary: This release adds new module `sap_hostctrl_exec` that allows executing `SAPHostcontrol` functions.
145+
New contributors readme is added to show our appreciation to contributors.
146+
release_date: '2025-12-10'

galaxy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace: community
44
name: sap_libs
5-
version: 1.5.0
5+
version: 1.6.0
66
readme: README.md
77
authors:
88
- Rainer Leber (github.com/rainerleber)

plugins/modules/sap_control_exec.py

Lines changed: 127 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
- Provides support for sapstartsrv formaly known as sapcontrol
2727
- A complete information of all functions and the parameters can be found here
2828
U(https://www.sap.com/documents/2016/09/0a40e60d-8b7c-0010-82c7-eda71af511fa.html)
29+
- When hostname is 'localhost', sysnr is set and no username/password are provided, the module will attempt
30+
to use local Unix socket authentication (which works with 'become' privilege escalation).
2931
3032
options:
3133
sysnr:
@@ -36,6 +38,7 @@
3638
port:
3739
description:
3840
- The port number of the sapstartsrv.
41+
- If provided, the module will use always use http connection instead of local socket.
3942
required: false
4043
type: int
4144
username:
@@ -157,14 +160,27 @@
157160
function: GetProcessList
158161
port: 50113
159162
160-
- name: ParameterValue
163+
- name: ParameterValue with authentication
161164
community.sap_libs.sap_control_exec:
162165
hostname: 192.168.8.15
163166
sysnr: "01"
164167
username: hdbadm
165-
password: test1234#
168+
password: test1234
166169
function: ParameterValue
167170
parameter: ztta
171+
172+
- name: GetVersionInfo using local Unix socket (requires become)
173+
community.sap_libs.sap_control_exec:
174+
sysnr: "00"
175+
function: GetVersionInfo
176+
become: true
177+
178+
- name: GetProcessList using local Unix socket as SAP admin user
179+
community.sap_libs.sap_control_exec:
180+
sysnr: "00"
181+
function: GetProcessList
182+
become: true
183+
become_user: "{{ sap_sid | lower }}adm"
168184
"""
169185

170186
RETURN = r'''
@@ -213,15 +229,73 @@
213229

214230
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
215231
import traceback
232+
import socket
233+
import os
234+
235+
try:
236+
from urllib.request import HTTPHandler
237+
except ImportError:
238+
from ansible.module_utils.urls import (
239+
UnixHTTPHandler as HTTPHandler,
240+
)
241+
242+
try:
243+
from http.client import HTTPConnection
244+
except ImportError:
245+
from httplib import HTTPConnection
246+
216247
try:
217248
from suds.client import Client
218249
from suds.sudsobject import asdict
250+
from suds.transport.http import HttpAuthenticated, HttpTransport
251+
HAS_SUDS_LIBRARY = True
252+
SUDS_LIBRARY_IMPORT_ERROR = None
253+
254+
class LocalSocketHttpAuthenticated(HttpAuthenticated):
255+
"""Authenticated HTTP transport using Unix domain sockets."""
256+
def __init__(self, socketpath, **kwargs):
257+
HttpAuthenticated.__init__(self, **kwargs)
258+
self._socketpath = socketpath
259+
260+
def u2handlers(self):
261+
handlers = HttpTransport.u2handlers(self)
262+
handlers.append(LocalSocketHandler(socketpath=self._socketpath))
263+
return handlers
264+
219265
except ImportError:
220266
HAS_SUDS_LIBRARY = False
221267
SUDS_LIBRARY_IMPORT_ERROR = traceback.format_exc()
222-
else:
223-
SUDS_LIBRARY_IMPORT_ERROR = None
224-
HAS_SUDS_LIBRARY = True
268+
269+
# Define dummy class when suds is not available
270+
class LocalSocketHttpAuthenticated(object):
271+
def __init__(self, socketpath, **kwargs):
272+
pass
273+
274+
def u2handlers(self):
275+
return []
276+
277+
278+
class LocalSocketHttpConnection(HTTPConnection):
279+
"""HTTP connection class that uses Unix domain sockets."""
280+
def __init__(self, host, port=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
281+
source_address=None, socketpath=None):
282+
super(LocalSocketHttpConnection, self).__init__(host, port, timeout, source_address)
283+
self.socketpath = socketpath
284+
285+
def connect(self):
286+
"""Connect to Unix domain socket."""
287+
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
288+
self.sock.connect(self.socketpath)
289+
290+
291+
class LocalSocketHandler(HTTPHandler):
292+
"""HTTP handler for Unix domain sockets."""
293+
def __init__(self, debuglevel=0, socketpath=None):
294+
self._debuglevel = debuglevel
295+
self._socketpath = socketpath
296+
297+
def http_open(self, req):
298+
return self.do_open(LocalSocketHttpConnection, req, socketpath=self._socketpath)
225299

226300

227301
def choices():
@@ -260,9 +334,27 @@ def recursive_dict(suds_object):
260334
return out
261335

262336

263-
def connection(hostname, port, username, password, function, parameter):
264-
url = 'http://{0}:{1}/sapcontrol?wsdl'.format(hostname, port)
265-
client = Client(url, username=username, password=password)
337+
def connection(hostname, port, username, password, function, parameter, sysnr=None, use_local=False):
338+
if use_local and sysnr is not None:
339+
# Use Unix domain socket for local connection
340+
unix_socket = "/tmp/.sapstream5{0}13".format(str(sysnr).zfill(2))
341+
342+
# Check if socket exists
343+
if not os.path.exists(unix_socket):
344+
raise Exception("SAP control Unix socket not found: {0}".format(unix_socket))
345+
346+
url = "http://localhost/sapcontrol?wsdl"
347+
348+
try:
349+
localsocket = LocalSocketHttpAuthenticated(unix_socket)
350+
client = Client(url, transport=localsocket)
351+
except Exception as e:
352+
raise Exception("Failed to connect via Unix socket: {0}".format(str(e)))
353+
else:
354+
# Use HTTP connection (original behavior)
355+
url = 'http://{0}:{1}/sapcontrol?wsdl'.format(hostname, port)
356+
client = Client(url, username=username, password=password)
357+
266358
_function = getattr(client.service, function)
267359
if parameter is not None:
268360
result = _function(parameter)
@@ -288,6 +380,7 @@ def main():
288380
parameter=dict(type='str', required=False),
289381
force=dict(type='bool', default=False),
290382
),
383+
# Remove strict requirements to allow local mode
291384
required_one_of=[('sysnr', 'port')],
292385
mutually_exclusive=[('sysnr', 'port')],
293386
supports_check_mode=False,
@@ -309,26 +402,46 @@ def main():
309402
msg=missing_required_lib('suds'),
310403
exception=SUDS_LIBRARY_IMPORT_ERROR)
311404

405+
# Validate arguments
406+
if sysnr is None and port is None:
407+
module.fail_json(msg="Either 'sysnr' or 'port' must be provided")
408+
409+
if sysnr is not None and port is not None:
410+
module.fail_json(msg="'sysnr' and 'port' are mutually exclusive")
411+
312412
if function == "Stop":
313413
if force is False:
314414
module.fail_json(msg="Stop function requires force: True")
315415

416+
# Determine if we should use local Unix socket connection
417+
# Use local if hostname is localhost and no username/password provided
418+
use_local = (hostname == "localhost" and
419+
username is None and
420+
password is None and
421+
sysnr is not None)
422+
316423
if port is None:
317424
try:
318-
try:
319-
conn = connection(hostname, "5{0}14".format((sysnr).zfill(2)), username, password, function, parameter)
320-
except Exception:
321-
conn = connection(hostname, "5{0}13".format((sysnr).zfill(2)), username, password, function, parameter)
425+
if use_local:
426+
# Try local connection first
427+
conn = connection(hostname, None, username, password, function, parameter, sysnr, use_local=True)
428+
else:
429+
# Try HTTP ports
430+
try:
431+
conn = connection(hostname, "5{0}14".format((sysnr).zfill(2)), username, password, function, parameter, sysnr)
432+
except Exception:
433+
conn = connection(hostname, "5{0}13".format((sysnr).zfill(2)), username, password, function, parameter, sysnr)
322434
except Exception as err:
323435
result['error'] = str(err)
324436
else:
325437
try:
326-
conn = connection(hostname, port, username, password, function, parameter)
438+
conn = connection(hostname, port, username, password, function, parameter, sysnr, use_local=False)
327439
except Exception as err:
328440
result['error'] = str(err)
329441

330442
if result['error'] != '':
331-
result['msg'] = 'Something went wrong connecting to the SAPCONTROL SOAP API.'
443+
connection_type = "Unix socket" if use_local else "SOAP API"
444+
result['msg'] = 'Something went wrong connecting to the {0}.'.format(connection_type)
332445
module.fail_json(**result)
333446

334447
if conn is not None:

0 commit comments

Comments
 (0)