Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
99711ca
Adding local sucket support
nbttmbrg Oct 22, 2025
a76cb15
Add changelog fragment
nbttmbrg Oct 22, 2025
3f313d7
Fix CI (#1)
nbttmbrg Oct 27, 2025
520cada
Sapcontrol local socket testing (#2)
nbttmbrg Oct 27, 2025
cac0bce
Fixing white space issues
nbttmbrg Oct 27, 2025
60103c4
Merge branch 'sapcontrol-local-socket' of https://github.com/oxya-dev…
nbttmbrg Oct 27, 2025
a5fb928
* Sanity: Fix a couple of empty lines
nbttmbrg Oct 27, 2025
7539796
*Unit test : Add suds mocking in tests for sap_control_exec module
nbttmbrg Oct 27, 2025
0755bd4
* Sanity : Fix indent
nbttmbrg Oct 27, 2025
f5ebfac
Merge pull request #66 from oxya-dev/sapcontrol-local-socket
marcelmamula Oct 30, 2025
3c867c2
Add sap_hostctrl_exec module and tests
ydouvry Dec 1, 2025
9b1ba06
corrections for sanity checks
ydouvry Dec 8, 2025
a066de9
Removing exclusive python 3 command for EOL sanity checks compliance,
ydouvry Dec 8, 2025
0bd867a
Rewriting DOCUMENTATION block for compliance.
ydouvry Dec 8, 2025
088f39e
Revelation on what was expected concerning the authors.
ydouvry Dec 8, 2025
2d05343
Rethinking on the right to remove the former authors..
ydouvry Dec 8, 2025
80c8617
More documentation and examples
ydouvry Dec 9, 2025
b3804ad
Lint fix for DOCUMENTATION in sap_hostctrl_exec module
ydouvry Dec 9, 2025
abca918
Merge pull request #67 from oxya-dev/saphostctrl
marcelmamula Dec 10, 2025
16c20c6
update for release 1.6.0
marcelmamula Dec 10, 2025
e7c4d80
Merge pull request #68 from marcelmamula/1.6.0
marcelmamula Dec 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ Community SAP Release Notes

.. contents:: Topics

v1.6.0
======

Release Summary
---------------

This release adds new module `sap_hostctrl_exec` that allows executing `SAPHostcontrol` functions.
New contributors readme is added to show our appreciation to contributors.

Minor Changes
-------------
- sap_control_exec - Add local socket support (https://github.com/sap-linuxlab/community.sap_libs/pull/66)
- sap_hostctrl_exec - Add new module and tests (https://github.com/sap-linuxlab/community.sap_libs/pull/67)

v1.5.0
======

Expand Down
93 changes: 93 additions & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Contributors to community.sap_libs

Thank you to all contributors who have helped make this project possible!

We welcome contributions! Please see our [contributing guidelines](https://sap-linuxlab.github.io/initiative_contributions/) to get started.

## Maintainers

The following people are the maintainers of this collection:

### SUSE

- [Marcel Mamula](https://github.com/marcelmamula)


For specific role maintainers, see the `README.md` file in the corresponding role's directory.

## All Contributors

| Name | Commits | Lines Changed | Last Commit |
| ---- | ------- | ------------- | ----------- |
| [Rainer Leber](https://github.com/rainerleber) | 23 | 11921 | 2025-09-22 |
| ydouvry | 8 | 892 | 2025-12-09 |
| Nicolas Bettembourg | 7 | 265 | 2025-10-27 |
| [Marcel Mamula](https://github.com/marcelmamula) | 4 | 1404 | 2025-10-16 |
| stm85 | 1 | 4 | 2024-04-29 |
| [Sean Freeman](https://github.com/sean-freeman) | 1 | 3 | 2022-11-11 |

## Contributions by Module

### Module: sap_control_exec.py

| Name | Commits | Lines Changed | Last Commit |
| ---- | ------- | ------------- | ----------- |
| Nicolas Bettembourg | 4 | 221 | 2025-10-27 |
| [Rainer Leber](https://github.com/rainerleber) | 4 | 555 | 2025-09-22 |

### Module: sap_pyrfc.py

| Name | Commits | Lines Changed | Last Commit |
| ---- | ------- | ------------- | ----------- |
| [Rainer Leber](https://github.com/rainerleber) | 4 | 191 | 2023-03-08 |

### Module: sap_snote.py

| Name | Commits | Lines Changed | Last Commit |
| ---- | ------- | ------------- | ----------- |
| [Rainer Leber](https://github.com/rainerleber) | 3 | 269 | 2022-12-05 |

### Module: sap_system_facts.py

| Name | Commits | Lines Changed | Last Commit |
| ---- | ------- | ------------- | ----------- |
| [Rainer Leber](https://github.com/rainerleber) | 2 | 215 | 2022-09-09 |

### Module: sap_task_list_execute.py

| Name | Commits | Lines Changed | Last Commit |
| ---- | ------- | ------------- | ----------- |
| [Rainer Leber](https://github.com/rainerleber) | 3 | 352 | 2022-12-05 |

### Module: sap_hostctrl_exec.py

| Name | Commits | Lines Changed | Last Commit |
| ---- | ------- | ------------- | ----------- |
| ydouvry | 8 | 506 | 2025-12-09 |

### Module: sapcar_extract.py

| Name | Commits | Lines Changed | Last Commit |
| ---- | ------- | ------------- | ----------- |
| [Rainer Leber](https://github.com/rainerleber) | 2 | 230 | 2022-09-09 |

### Module: sap_hdbsql.py

| Name | Commits | Lines Changed | Last Commit |
| ---- | ------- | ------------- | ----------- |
| [Marcel Mamula](https://github.com/marcelmamula) | 1 | 2 | 2025-09-25 |
| stm85 | 1 | 2 | 2024-04-29 |
| [Rainer Leber](https://github.com/rainerleber) | 1 | 246 | 2022-09-09 |

### Module: sap_user.py

| Name | Commits | Lines Changed | Last Commit |
| ---- | ------- | ------------- | ----------- |
| [Rainer Leber](https://github.com/rainerleber) | 3 | 510 | 2022-12-05 |

### Module: sap_company.py

| Name | Commits | Lines Changed | Last Commit |
| ---- | ------- | ------------- | ----------- |
| [Rainer Leber](https://github.com/rainerleber) | 3 | 337 | 2022-12-05 |

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ modules where we are able to execute integration test we decided to disable thes
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).

## Contributing
You can find more information about ways you can contribute at [sap-linuxlab website](https://sap-linuxlab.github.io/initiative_contributions/).
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).

## Support
You can report any issues using [Issues](https://github.com/sap-linuxlab/community.sap_libs/issues) section.
Expand Down
8 changes: 8 additions & 0 deletions changelogs/changelog.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,11 @@ releases:
release_summary: This release removes `Python 2` support and updates `ansible-test` workflow to validate latest versions.
Documentation was updated to reflect supported and tested versions.
release_date: '2025-09-25'
1.6.0:
changes:
minor_changes:
- sap_control_exec - Add local socket support (https://github.com/sap-linuxlab/community.sap_libs/pull/66)
- sap_hostctrl_exec - Add new module and tests (https://github.com/sap-linuxlab/community.sap_libs/pull/67)
release_summary: This release adds new module `sap_hostctrl_exec` that allows executing `SAPHostcontrol` functions.
New contributors readme is added to show our appreciation to contributors.
release_date: '2025-12-10'
2 changes: 1 addition & 1 deletion galaxy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace: community
name: sap_libs
version: 1.5.0
version: 1.6.0
readme: README.md
authors:
- Rainer Leber (github.com/rainerleber)
Expand Down
141 changes: 127 additions & 14 deletions plugins/modules/sap_control_exec.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
- Provides support for sapstartsrv formaly known as sapcontrol
- A complete information of all functions and the parameters can be found here
U(https://www.sap.com/documents/2016/09/0a40e60d-8b7c-0010-82c7-eda71af511fa.html)
- When hostname is 'localhost', sysnr is set and no username/password are provided, the module will attempt
to use local Unix socket authentication (which works with 'become' privilege escalation).

options:
sysnr:
Expand All @@ -36,6 +38,7 @@
port:
description:
- The port number of the sapstartsrv.
- If provided, the module will use always use http connection instead of local socket.
required: false
type: int
username:
Expand Down Expand Up @@ -157,14 +160,27 @@
function: GetProcessList
port: 50113

- name: ParameterValue
- name: ParameterValue with authentication
community.sap_libs.sap_control_exec:
hostname: 192.168.8.15
sysnr: "01"
username: hdbadm
password: test1234#
password: test1234
function: ParameterValue
parameter: ztta

- name: GetVersionInfo using local Unix socket (requires become)
community.sap_libs.sap_control_exec:
sysnr: "00"
function: GetVersionInfo
become: true

- name: GetProcessList using local Unix socket as SAP admin user
community.sap_libs.sap_control_exec:
sysnr: "00"
function: GetProcessList
become: true
become_user: "{{ sap_sid | lower }}adm"
"""

RETURN = r'''
Expand Down Expand Up @@ -213,15 +229,73 @@

from ansible.module_utils.basic import AnsibleModule, missing_required_lib
import traceback
import socket
import os

try:
from urllib.request import HTTPHandler
except ImportError:
from ansible.module_utils.urls import (
UnixHTTPHandler as HTTPHandler,
)

try:
from http.client import HTTPConnection
except ImportError:
from httplib import HTTPConnection

try:
from suds.client import Client
from suds.sudsobject import asdict
from suds.transport.http import HttpAuthenticated, HttpTransport
HAS_SUDS_LIBRARY = True
SUDS_LIBRARY_IMPORT_ERROR = None

class LocalSocketHttpAuthenticated(HttpAuthenticated):
"""Authenticated HTTP transport using Unix domain sockets."""
def __init__(self, socketpath, **kwargs):
HttpAuthenticated.__init__(self, **kwargs)
self._socketpath = socketpath

def u2handlers(self):
handlers = HttpTransport.u2handlers(self)
handlers.append(LocalSocketHandler(socketpath=self._socketpath))
return handlers

except ImportError:
HAS_SUDS_LIBRARY = False
SUDS_LIBRARY_IMPORT_ERROR = traceback.format_exc()
else:
SUDS_LIBRARY_IMPORT_ERROR = None
HAS_SUDS_LIBRARY = True

# Define dummy class when suds is not available
class LocalSocketHttpAuthenticated(object):
def __init__(self, socketpath, **kwargs):
pass

def u2handlers(self):
return []


class LocalSocketHttpConnection(HTTPConnection):
"""HTTP connection class that uses Unix domain sockets."""
def __init__(self, host, port=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
source_address=None, socketpath=None):
super(LocalSocketHttpConnection, self).__init__(host, port, timeout, source_address)
self.socketpath = socketpath

def connect(self):
"""Connect to Unix domain socket."""
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
self.sock.connect(self.socketpath)


class LocalSocketHandler(HTTPHandler):
"""HTTP handler for Unix domain sockets."""
def __init__(self, debuglevel=0, socketpath=None):
self._debuglevel = debuglevel
self._socketpath = socketpath

def http_open(self, req):
return self.do_open(LocalSocketHttpConnection, req, socketpath=self._socketpath)


def choices():
Expand Down Expand Up @@ -260,9 +334,27 @@ def recursive_dict(suds_object):
return out


def connection(hostname, port, username, password, function, parameter):
url = 'http://{0}:{1}/sapcontrol?wsdl'.format(hostname, port)
client = Client(url, username=username, password=password)
def connection(hostname, port, username, password, function, parameter, sysnr=None, use_local=False):
if use_local and sysnr is not None:
# Use Unix domain socket for local connection
unix_socket = "/tmp/.sapstream5{0}13".format(str(sysnr).zfill(2))

# Check if socket exists
if not os.path.exists(unix_socket):
raise Exception("SAP control Unix socket not found: {0}".format(unix_socket))

url = "http://localhost/sapcontrol?wsdl"

try:
localsocket = LocalSocketHttpAuthenticated(unix_socket)
client = Client(url, transport=localsocket)
except Exception as e:
raise Exception("Failed to connect via Unix socket: {0}".format(str(e)))
else:
# Use HTTP connection (original behavior)
url = 'http://{0}:{1}/sapcontrol?wsdl'.format(hostname, port)
client = Client(url, username=username, password=password)

_function = getattr(client.service, function)
if parameter is not None:
result = _function(parameter)
Expand All @@ -288,6 +380,7 @@ def main():
parameter=dict(type='str', required=False),
force=dict(type='bool', default=False),
),
# Remove strict requirements to allow local mode
required_one_of=[('sysnr', 'port')],
mutually_exclusive=[('sysnr', 'port')],
supports_check_mode=False,
Expand All @@ -309,26 +402,46 @@ def main():
msg=missing_required_lib('suds'),
exception=SUDS_LIBRARY_IMPORT_ERROR)

# Validate arguments
if sysnr is None and port is None:
module.fail_json(msg="Either 'sysnr' or 'port' must be provided")

if sysnr is not None and port is not None:
module.fail_json(msg="'sysnr' and 'port' are mutually exclusive")

if function == "Stop":
if force is False:
module.fail_json(msg="Stop function requires force: True")

# Determine if we should use local Unix socket connection
# Use local if hostname is localhost and no username/password provided
use_local = (hostname == "localhost" and
username is None and
password is None and
sysnr is not None)

if port is None:
try:
try:
conn = connection(hostname, "5{0}14".format((sysnr).zfill(2)), username, password, function, parameter)
except Exception:
conn = connection(hostname, "5{0}13".format((sysnr).zfill(2)), username, password, function, parameter)
if use_local:
# Try local connection first
conn = connection(hostname, None, username, password, function, parameter, sysnr, use_local=True)
else:
# Try HTTP ports
try:
conn = connection(hostname, "5{0}14".format((sysnr).zfill(2)), username, password, function, parameter, sysnr)
except Exception:
conn = connection(hostname, "5{0}13".format((sysnr).zfill(2)), username, password, function, parameter, sysnr)
except Exception as err:
result['error'] = str(err)
else:
try:
conn = connection(hostname, port, username, password, function, parameter)
conn = connection(hostname, port, username, password, function, parameter, sysnr, use_local=False)
except Exception as err:
result['error'] = str(err)

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

if conn is not None:
Expand Down
Loading