Mini Shell
"""
Manage Glassfish/Payara server
.. versionadded:: 2016.11.0
Management of glassfish using its RESTful API
You can setup connection parameters like this
.. code-block:: yaml
- server:
- ssl: true
- url: localhost
- port: 4848
- user: admin
- password: changeit
"""
import salt.utils.json
from salt.exceptions import CommandExecutionError
try:
import requests
HAS_LIBS = True
except ImportError:
HAS_LIBS = False
def __virtual__():
"""
Only load if glassfish module is available
"""
if "glassfish.enum_connector_c_pool" in __salt__ and HAS_LIBS:
return True
return (False, "glassfish module could not be loaded")
def _json_to_unicode(data):
"""
Encode json values in unicode to match that of the API
"""
ret = {}
for key, value in data.items():
if not isinstance(value, str):
if isinstance(value, dict):
ret[key] = _json_to_unicode(value)
else:
ret[key] = str(value).lower()
else:
ret[key] = value
return ret
def _is_updated(old_conf, new_conf):
"""
Compare the API results to the current statefile data
"""
changed = {}
# Dirty json hacking to get parameters in the same format
new_conf = _json_to_unicode(
salt.utils.json.loads(salt.utils.json.dumps(new_conf, ensure_ascii=False))
)
old_conf = salt.utils.json.loads(
salt.utils.json.dumps(old_conf, ensure_ascii=False)
)
for key, value in old_conf.items():
oldval = str(value).lower()
if key in new_conf:
newval = str(new_conf[key]).lower()
if oldval == "null" or oldval == "none":
oldval = ""
if key in new_conf and newval != oldval:
changed[key] = {"old": oldval, "new": newval}
return changed
def _do_element_present(name, elem_type, data, server=None):
"""
Generic function to create or update an element
"""
ret = {"changes": {}, "update": False, "create": False, "error": None}
try:
elements = __salt__[f"glassfish.enum_{elem_type}"]()
except requests.ConnectionError as error:
if __opts__["test"]:
ret["changes"] = {"Name": name, "Params": data}
ret["create"] = True
return ret
else:
ret["error"] = "Can't connect to the server"
return ret
if not elements or name not in elements:
ret["changes"] = {"Name": name, "Params": data}
ret["create"] = True
if not __opts__["test"]:
try:
__salt__[f"glassfish.create_{elem_type}"](name, server=server, **data)
except CommandExecutionError as error:
ret["error"] = error
return ret
elif elements and any(data):
current_data = __salt__[f"glassfish.get_{elem_type}"](name, server=server)
data_diff = _is_updated(current_data, data)
if data_diff:
ret["update"] = True
ret["changes"] = data_diff
if not __opts__["test"]:
try:
__salt__[f"glassfish.update_{elem_type}"](
name, server=server, **data
)
except CommandExecutionError as error:
ret["error"] = error
return ret
def _do_element_absent(name, elem_type, data, server=None):
"""
Generic function to delete an element
"""
ret = {"delete": False, "error": None}
try:
elements = __salt__[f"glassfish.enum_{elem_type}"]()
except requests.ConnectionError as error:
if __opts__["test"]:
ret["create"] = True
return ret
else:
ret["error"] = "Can't connect to the server"
return ret
if elements and name in elements:
ret["delete"] = True
if not __opts__["test"]:
try:
__salt__[f"glassfish.delete_{elem_type}"](name, server=server, **data)
except CommandExecutionError as error:
ret["error"] = error
return ret
def connection_factory_present(
name,
restype="connection_factory",
description="",
enabled=True,
min_size=1,
max_size=250,
resize_quantity=2,
idle_timeout=300,
wait_timeout=60,
reconnect_on_failure=False,
transaction_support="",
connection_validation=False,
server=None,
):
"""
Ensures that the Connection Factory is present
name
Name of the connection factory
restype
Type of the connection factory, can be either ``connection_factory``,
``queue_connection_factory` or ``topic_connection_factory``,
defaults to ``connection_factory``
description
Description of the connection factory
enabled
Is the connection factory enabled? defaults to ``true``
min_size
Minimum and initial number of connections in the pool, defaults to ``1``
max_size
Maximum number of connections that can be created in the pool, defaults to ``250``
resize_quantity
Number of connections to be removed when idle_timeout expires, defaults to ``2``
idle_timeout
Maximum time a connection can remain idle in the pool, in seconds, defaults to ``300``
wait_timeout
Maximum time a caller can wait before timeout, in seconds, defaults to ``60``
reconnect_on_failure
Close all connections and reconnect on failure (or reconnect only when used), defaults to ``false``
transaction_support
Level of transaction support, can be either ``XATransaction``, ``LocalTransaction`` or ``NoTransaction``
connection_validation
Connection validation is required, defaults to ``false``
"""
ret = {"name": name, "result": None, "comment": None, "changes": {}}
# Manage parameters
pool_data = {}
res_data = {}
pool_name = f"{name}-Connection-Pool"
if restype == "topic_connection_factory":
pool_data["connectionDefinitionName"] = "javax.jms.TopicConnectionFactory"
elif restype == "queue_connection_factory":
pool_data["connectionDefinitionName"] = "javax.jms.QueueConnectionFactory"
elif restype == "connection_factory":
pool_data["connectionDefinitionName"] = "javax.jms.ConnectionFactory"
else:
ret["result"] = False
ret["comment"] = "Invalid restype"
return ret
pool_data["description"] = description
res_data["description"] = description
res_data["enabled"] = enabled
res_data["poolName"] = pool_name
pool_data["steadyPoolSize"] = min_size
pool_data["maxPoolSize"] = max_size
pool_data["poolResizeQuantity"] = resize_quantity
pool_data["idleTimeoutInSeconds"] = idle_timeout
pool_data["maxWaitTimeInMillis"] = wait_timeout * 1000
pool_data["failAllConnections"] = reconnect_on_failure
if transaction_support:
if transaction_support == "xa_transaction":
pool_data["transactionSupport"] = "XATransaction"
elif transaction_support == "local_transaction":
pool_data["transactionSupport"] = "LocalTransaction"
elif transaction_support == "no_transaction":
pool_data["transactionSupport"] = "NoTransaction"
else:
ret["result"] = False
ret["comment"] = "Invalid transaction_support"
return ret
pool_data["isConnectionValidationRequired"] = connection_validation
pool_ret = _do_element_present(pool_name, "connector_c_pool", pool_data, server)
res_ret = _do_element_present(name, "connector_resource", res_data, server)
if not pool_ret["error"] and not res_ret["error"]:
if not __opts__["test"]:
ret["result"] = True
if pool_ret["create"] or res_ret["create"]:
ret["changes"]["pool"] = pool_ret["changes"]
ret["changes"]["resource"] = res_ret["changes"]
if __opts__["test"]:
ret["comment"] = "Connection factory set to be created"
else:
ret["comment"] = "Connection factory created"
elif pool_ret["update"] or res_ret["update"]:
ret["changes"]["pool"] = pool_ret["changes"]
ret["changes"]["resource"] = res_ret["changes"]
if __opts__["test"]:
ret["comment"] = "Connection factory set to be updated"
else:
ret["comment"] = "Connection factory updated"
else:
ret["result"] = True
ret["changes"] = {}
ret["comment"] = "Connection factory is already up-to-date"
else:
ret["result"] = False
ret["comment"] = "ERROR: {} // {}".format(pool_ret["error"], res_ret["error"])
return ret
def connection_factory_absent(name, both=True, server=None):
"""
Ensures the transaction factory is absent.
name
Name of the connection factory
both
Delete both the pool and the resource, defaults to ``true``
"""
ret = {"name": name, "result": None, "comment": None, "changes": {}}
pool_name = f"{name}-Connection-Pool"
pool_ret = _do_element_absent(
pool_name, "connector_c_pool", {"cascade": both}, server
)
if not pool_ret["error"]:
if __opts__["test"] and pool_ret["delete"]:
ret["comment"] = "Connection Factory set to be deleted"
elif pool_ret["delete"]:
ret["result"] = True
ret["comment"] = "Connection Factory deleted"
else:
ret["result"] = True
ret["comment"] = "Connection Factory doesn't exist"
else:
ret["result"] = False
ret["comment"] = "Error: {}".format(pool_ret["error"])
return ret
def destination_present(
name, physical, restype="queue", description="", enabled=True, server=None
):
"""
Ensures that the JMS Destination Resource (queue or topic) is present
name
The JMS Queue/Topic name
physical
The Physical destination name
restype
The JMS Destination resource type, either ``queue`` or ``topic``, defaults is ``queue``
description
A description of the resource
enabled
Defaults to ``True``
"""
ret = {"name": name, "result": None, "comment": None, "changes": {}}
params = {}
# Set parameters dict
if restype == "queue":
params["resType"] = "javax.jms.Queue"
params["className"] = "com.sun.messaging.Queue"
elif restype == "topic":
params["resType"] = "javax.jms.Topic"
params["className"] = "com.sun.messaging.Topic"
else:
ret["result"] = False
ret["comment"] = "Invalid restype"
return ret
params["properties"] = {"Name": physical}
params["description"] = description
params["enabled"] = enabled
jms_ret = _do_element_present(name, "admin_object_resource", params, server)
if not jms_ret["error"]:
if not __opts__["test"]:
ret["result"] = True
if jms_ret["create"] and __opts__["test"]:
ret["comment"] = "JMS Queue set to be created"
elif jms_ret["create"]:
ret["changes"] = jms_ret["changes"]
ret["comment"] = "JMS queue created"
elif jms_ret["update"] and __opts__["test"]:
ret["comment"] = "JMS Queue set to be updated"
elif jms_ret["update"]:
ret["changes"] = jms_ret["changes"]
ret["comment"] = "JMS Queue updated"
else:
ret["result"] = True
ret["comment"] = "JMS Queue already up-to-date"
else:
ret["result"] = False
ret["comment"] = "Error from API: {}".format(jms_ret["error"])
return ret
def destination_absent(name, server=None):
"""
Ensures that the JMS Destination doesn't exists
name
Name of the JMS Destination
"""
ret = {"name": name, "result": None, "comment": None, "changes": {}}
jms_ret = _do_element_absent(name, "admin_object_resource", {}, server)
if not jms_ret["error"]:
if __opts__["test"] and jms_ret["delete"]:
ret["comment"] = "JMS Queue set to be deleted"
elif jms_ret["delete"]:
ret["result"] = True
ret["comment"] = "JMS Queue deleted"
else:
ret["result"] = True
ret["comment"] = "JMS Queue doesn't exist"
else:
ret["result"] = False
ret["comment"] = "Error: {}".format(jms_ret["error"])
return ret
def jdbc_datasource_present(
name,
description="",
enabled=True,
restype="datasource",
vendor="mysql",
sql_url="",
sql_user="",
sql_password="",
min_size=8,
max_size=32,
resize_quantity=2,
idle_timeout=300,
wait_timeout=60,
non_transactional=False,
transaction_isolation="",
isolation_guaranteed=True,
server=None,
):
"""
Ensures that the JDBC Datasource exists
name
Name of the datasource
description
Description of the datasource
enabled
Is the datasource enabled? defaults to ``true``
restype
Resource type, can be ``datasource``, ``xa_datasource``,
``connection_pool_datasource`` or ``driver``, defaults to ``datasource``
vendor
SQL Server type, currently supports ``mysql``,
``postgresql`` and ``mssql``, defaults to ``mysql``
sql_url
URL of the server in jdbc form
sql_user
Username for the server
sql_password
Password for that username
min_size
Minimum and initial number of connections in the pool, defaults to ``8``
max_size
Maximum number of connections that can be created in the pool, defaults to ``32``
resize_quantity
Number of connections to be removed when idle_timeout expires, defaults to ``2``
idle_timeout
Maximum time a connection can remain idle in the pool, in seconds, defaults to ``300``
wait_timeout
Maximum time a caller can wait before timeout, in seconds, defaults to ``60``
non_transactional
Return non-transactional connections
transaction_isolation
Defaults to the JDBC driver default
isolation_guaranteed
All connections use the same isolation level
"""
ret = {"name": name, "result": None, "comment": None, "changes": {}}
# Manage parameters
res_name = f"jdbc/{name}"
pool_data = {}
pool_data_properties = {}
res_data = {}
if restype == "datasource":
pool_data["resType"] = "javax.sql.DataSource"
elif restype == "xa_datasource":
pool_data["resType"] = "javax.sql.XADataSource"
elif restype == "connection_pool_datasource":
pool_data["resType"] = "javax.sql.ConnectionPoolDataSource"
elif restype == "driver":
pool_data["resType"] = "javax.sql.Driver"
datasources = {}
datasources["mysql"] = {
"driver": "com.mysql.jdbc.Driver",
"datasource": "com.mysql.jdbc.jdbc2.optional.MysqlDataSource",
"xa_datasource": "com.mysql.jdbc.jdbc2.optional.MysqlXADataSource",
"connection_pool_datasource": (
"com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource"
),
}
datasources["postgresql"] = {
"driver": "org.postgresql.Driver",
"datasource": "org.postgresql.ds.PGSimpleDataSource",
"xa_datasource": "org.postgresql.xa.PGXADataSource",
"connection_pool_datasource": "org.postgresql.ds.PGConnectionPoolDataSource",
}
datasources["mssql"] = {
"driver": "com.microsoft.sqlserver.jdbc.SQLServerDriver",
"datasource": "com.microsoft.sqlserver.jdbc.SQLServerDataSource",
"xa_datasource": "com.microsoft.sqlserver.jdbc.SQLServerXADataSource",
"connection_pool_datasource": (
"com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource"
),
}
if restype == "driver":
pool_data["driverClassname"] = datasources[vendor]["driver"]
else:
pool_data["datasourceClassname"] = datasources[vendor][restype]
pool_data_properties["url"] = sql_url
pool_data_properties["user"] = sql_user
pool_data_properties["password"] = sql_password
pool_data["properties"] = pool_data_properties
pool_data["description"] = description
res_data["description"] = description
res_data["poolName"] = name
res_data["enabled"] = enabled
pool_data["steadyPoolSize"] = min_size
pool_data["maxPoolSize"] = max_size
pool_data["poolResizeQuantity"] = resize_quantity
pool_data["idleTimeoutInSeconds"] = idle_timeout
pool_data["maxWaitTimeInMillis"] = wait_timeout * 1000
pool_data["nonTransactionalConnections"] = non_transactional
pool_data["transactionIsolationLevel"] = transaction_isolation
pool_data["isIsolationLevelGuaranteed"] = isolation_guaranteed
pool_ret = _do_element_present(name, "jdbc_connection_pool", pool_data, server)
res_ret = _do_element_present(res_name, "jdbc_resource", res_data, server)
if not pool_ret["error"] and not res_ret["error"]:
if not __opts__["test"]:
ret["result"] = True
if pool_ret["create"] or res_ret["create"]:
ret["changes"]["pool"] = pool_ret["changes"]
ret["changes"]["resource"] = res_ret["changes"]
if __opts__["test"]:
ret["comment"] = "JDBC Datasource set to be created"
else:
ret["comment"] = "JDBC Datasource created"
elif pool_ret["update"] or res_ret["update"]:
ret["changes"]["pool"] = pool_ret["changes"]
ret["changes"]["resource"] = res_ret["changes"]
if __opts__["test"]:
ret["comment"] = "JDBC Datasource set to be updated"
else:
ret["comment"] = "JDBC Datasource updated"
else:
ret["result"] = True
ret["changes"] = {}
ret["comment"] = "JDBC Datasource is already up-to-date"
else:
ret["result"] = False
ret["comment"] = "ERROR: {} // {}".format(pool_ret["error"], res_ret["error"])
return ret
def jdbc_datasource_absent(name, both=True, server=None):
"""
Ensures the JDBC Datasource doesn't exists
name
Name of the datasource
both
Delete both the pool and the resource, defaults to ``true``
"""
ret = {"name": name, "result": None, "comment": None, "changes": {}}
pool_ret = _do_element_absent(
name, "jdbc_connection_pool", {"cascade": both}, server
)
if not pool_ret["error"]:
if __opts__["test"] and pool_ret["delete"]:
ret["comment"] = "JDBC Datasource set to be deleted"
elif pool_ret["delete"]:
ret["result"] = True
ret["comment"] = "JDBC Datasource deleted"
else:
ret["result"] = True
ret["comment"] = "JDBC Datasource doesn't exist"
else:
ret["result"] = False
ret["comment"] = "Error: {}".format(pool_ret["error"])
return ret
def system_properties_present(server=None, **kwargs):
"""
Ensures that the system properties are present
properties
The system properties
"""
ret = {"name": "", "result": None, "comment": None, "changes": {}}
del kwargs["name"]
try:
data = __salt__["glassfish.get_system_properties"](server=server)
except requests.ConnectionError as error:
if __opts__["test"]:
ret["changes"] = kwargs
ret["result"] = None
return ret
else:
ret["error"] = "Can't connect to the server"
return ret
ret["changes"] = {"data": data, "kwargs": kwargs}
if not data == kwargs:
data.update(kwargs)
if not __opts__["test"]:
try:
__salt__["glassfish.update_system_properties"](data, server=server)
ret["changes"] = kwargs
ret["result"] = True
ret["comment"] = "System properties updated"
except CommandExecutionError as error:
ret["comment"] = error
ret["result"] = False
else:
ret["result"] = None
ret["changes"] = kwargs
ret["coment"] = "System properties would have been updated"
else:
ret["changes"] = {}
ret["result"] = True
ret["comment"] = "System properties are already up-to-date"
return ret
def system_properties_absent(name, server=None):
"""
Ensures that the system property doesn't exists
name
Name of the system property
"""
ret = {"name": "", "result": None, "comment": None, "changes": {}}
try:
data = __salt__["glassfish.get_system_properties"](server=server)
except requests.ConnectionError as error:
if __opts__["test"]:
ret["changes"] = {"Name": name}
ret["result"] = None
return ret
else:
ret["error"] = "Can't connect to the server"
return ret
if name in data:
if not __opts__["test"]:
try:
__salt__["glassfish.delete_system_properties"](name, server=server)
ret["result"] = True
ret["comment"] = "System properties deleted"
except CommandExecutionError as error:
ret["comment"] = error
ret["result"] = False
else:
ret["result"] = None
ret["comment"] = "System properties would have been deleted"
ret["changes"] = {"Name": name}
else:
ret["result"] = True
ret["comment"] = "System properties are already absent"
return ret
Zerion Mini Shell 1.0