Mini Shell
"""
Spacewalk Runner
================
.. versionadded:: 2016.3.0
Runner to interact with Spacewalk using Spacewalk API
:codeauthor: Nitin Madhok <nmadhok@g.clemson.edu>, Joachim Werner <joe@suse.com>, Benedikt Werner <1benediktwerner@gmail.com>
:maintainer: Benedikt Werner <1benediktwerner@gmail.com>
To use this runner, set up the Spacewalk URL, username and password in the
master configuration at ``/etc/salt/master`` or ``/etc/salt/master.d/spacewalk.conf``:
.. code-block:: yaml
spacewalk:
spacewalk01.domain.com:
username: 'testuser'
password: 'verybadpass'
spacewalk02.domain.com:
username: 'testuser'
password: 'verybadpass'
.. note::
Optionally, ``protocol`` can be specified if the spacewalk server is
not using the defaults. Default is ``protocol: https``.
"""
import atexit
import logging
import xmlrpc.client # nosec
log = logging.getLogger(__name__)
_sessions = {}
def __virtual__():
"""
Check for spacewalk configuration in master config file
or directory and load runner only if it is specified
"""
if not _get_spacewalk_configuration():
return False, "No spacewalk configuration found"
return True
def _get_spacewalk_configuration(spacewalk_url=""):
"""
Return the configuration read from the master configuration
file or directory
"""
spacewalk_config = __opts__["spacewalk"] if "spacewalk" in __opts__ else None
if spacewalk_config:
try:
for spacewalk_server, service_config in spacewalk_config.items():
username = service_config.get("username", None)
password = service_config.get("password", None)
protocol = service_config.get("protocol", "https")
if not username or not password:
log.error(
"Username or Password has not been specified in the master "
"configuration for %s",
spacewalk_server,
)
return False
ret = {
"api_url": f"{protocol}://{spacewalk_server}/rpc/api",
"username": username,
"password": password,
}
if (not spacewalk_url) or (spacewalk_url == spacewalk_server):
return ret
except Exception as exc: # pylint: disable=broad-except
log.error("Exception encountered: %s", exc)
return False
if spacewalk_url:
log.error(
"Configuration for %s has not been specified in the master "
"configuration",
spacewalk_url,
)
return False
return False
def _get_client_and_key(url, user, password, verbose=0):
"""
Return the client object and session key for the client
"""
session = {}
session["client"] = xmlrpc.client.Server(url, verbose=verbose, use_datetime=True)
session["key"] = session["client"].auth.login(user, password)
return session
def _disconnect_session(session):
"""
Disconnect API connection
"""
session["client"].auth.logout(session["key"])
def _get_session(server):
"""
Get session and key
"""
if server in _sessions:
return _sessions[server]
config = _get_spacewalk_configuration(server)
if not config:
raise Exception(f"No config for '{server}' found on master")
session = _get_client_and_key(
config["api_url"], config["username"], config["password"]
)
atexit.register(_disconnect_session, session)
client = session["client"]
key = session["key"]
_sessions[server] = (client, key)
return client, key
def api(server, command, *args, **kwargs):
"""
Call the Spacewalk xmlrpc api.
CLI Example:
.. code-block:: bash
salt-run spacewalk.api spacewalk01.domain.com systemgroup.create MyGroup Description
salt-run spacewalk.api spacewalk01.domain.com systemgroup.create arguments='["MyGroup", "Description"]'
State Example:
.. code-block:: yaml
create_group:
salt.runner:
- name: spacewalk.api
- server: spacewalk01.domain.com
- command: systemgroup.create
- arguments:
- MyGroup
- Description
"""
if "arguments" in kwargs:
arguments = kwargs["arguments"]
else:
arguments = args
call = f"{command} {arguments}"
try:
client, key = _get_session(server)
except Exception as exc: # pylint: disable=broad-except
err_msg = (
"Exception raised when connecting to spacewalk server ({}): {}".format(
server, exc
)
)
log.error(err_msg)
return {call: err_msg}
namespace, _, method = command.rpartition(".")
if not namespace:
return {
call: "Error: command must use the following format: 'namespace.method'"
}
endpoint = getattr(getattr(client, namespace), method)
try:
output = endpoint(key, *arguments)
except Exception as e: # pylint: disable=broad-except
output = f"API call failed: {e}"
return {call: output}
def addGroupsToKey(server, activation_key, groups):
"""
Add server groups to a activation key
CLI Example:
.. code-block:: bash
salt-run spacewalk.addGroupsToKey spacewalk01.domain.com 1-my-key '[group1, group2]'
"""
try:
client, key = _get_session(server)
except Exception as exc: # pylint: disable=broad-except
err_msg = (
"Exception raised when connecting to spacewalk server ({}): {}".format(
server, exc
)
)
log.error(err_msg)
return {"Error": err_msg}
all_groups = client.systemgroup.listAllGroups(key)
groupIds = []
for group in all_groups:
if group["name"] in groups:
groupIds.append(group["id"])
if client.activationkey.addServerGroups(key, activation_key, groupIds) == 1:
return {activation_key: groups}
else:
return {activation_key: "Failed to add groups to activation key"}
def deleteAllGroups(server):
"""
Delete all server groups from Spacewalk
"""
try:
client, key = _get_session(server)
except Exception as exc: # pylint: disable=broad-except
err_msg = (
"Exception raised when connecting to spacewalk server ({}): {}".format(
server, exc
)
)
log.error(err_msg)
return {"Error": err_msg}
groups = client.systemgroup.listAllGroups(key)
deleted_groups = []
failed_groups = []
for group in groups:
if client.systemgroup.delete(key, group["name"]) == 1:
deleted_groups.append(group["name"])
else:
failed_groups.append(group["name"])
ret = {"deleted": deleted_groups}
if failed_groups:
ret["failed"] = failed_groups
return ret
def deleteAllSystems(server):
"""
Delete all systems from Spacewalk
CLI Example:
.. code-block:: bash
salt-run spacewalk.deleteAllSystems spacewalk01.domain.com
"""
try:
client, key = _get_session(server)
except Exception as exc: # pylint: disable=broad-except
err_msg = (
"Exception raised when connecting to spacewalk server ({}): {}".format(
server, exc
)
)
log.error(err_msg)
return {"Error": err_msg}
systems = client.system.listSystems(key)
ids = []
names = []
for system in systems:
ids.append(system["id"])
names.append(system["name"])
if client.system.deleteSystems(key, ids) == 1:
return {"deleted": names}
else:
return {"Error": "Failed to delete all systems"}
def deleteAllActivationKeys(server):
"""
Delete all activation keys from Spacewalk
CLI Example:
.. code-block:: bash
salt-run spacewalk.deleteAllActivationKeys spacewalk01.domain.com
"""
try:
client, key = _get_session(server)
except Exception as exc: # pylint: disable=broad-except
err_msg = (
"Exception raised when connecting to spacewalk server ({}): {}".format(
server, exc
)
)
log.error(err_msg)
return {"Error": err_msg}
activation_keys = client.activationkey.listActivationKeys(key)
deleted_keys = []
failed_keys = []
for aKey in activation_keys:
if client.activationkey.delete(key, aKey["key"]) == 1:
deleted_keys.append(aKey["key"])
else:
failed_keys.append(aKey["key"])
ret = {"deleted": deleted_keys}
if failed_keys:
ret["failed"] = failed_keys
return ret
def unregister(name, server_url):
"""
Unregister specified server from Spacewalk
CLI Example:
.. code-block:: bash
salt-run spacewalk.unregister my-test-vm spacewalk01.domain.com
"""
try:
client, key = _get_session(server_url)
except Exception as exc: # pylint: disable=broad-except
err_msg = (
"Exception raised when connecting to spacewalk server ({}): {}".format(
server_url, exc
)
)
log.error(err_msg)
return {name: err_msg}
systems_list = client.system.getId(key, name)
if systems_list:
for system in systems_list:
out = client.system.deleteSystem(key, system["id"])
if out == 1:
return {name: f"Successfully unregistered from {server_url}"}
else:
return {name: f"Failed to unregister from {server_url}"}
else:
return {name: f"System does not exist in spacewalk server ({server_url})"}
Zerion Mini Shell 1.0