%PDF- %PDF-
Direktori : /usr/lib/python2.7/site-packages/salt/modules/ |
Current File : //usr/lib/python2.7/site-packages/salt/modules/glassfish.py |
# -*- coding: utf-8 -*- ''' Module for working with the Glassfish/Payara 4.x management API .. versionadded:: Carbon :depends: requests ''' from __future__ import absolute_import, print_function, unicode_literals try: # python2 from urllib import quote, unquote except ImportError: # python3 from urllib.parse import quote, unquote try: import requests import salt.defaults.exitcodes import salt.utils.json from salt.exceptions import CommandExecutionError HAS_LIBS = True except ImportError: HAS_LIBS = False __virtualname__ = 'glassfish' # Default server DEFAULT_SERVER = {'ssl': False, 'url': 'localhost', 'port': 4848, 'user': None, 'password': None} def __virtual__(): ''' Only load if requests is installed ''' if HAS_LIBS: return __virtualname__ else: return False, 'The "{0}" module could not be loaded: ' \ '"requests" is not installed.'.format(__virtualname__) def _get_headers(): ''' Return fixed dict with headers (JSON data + mandatory "Requested by" header) ''' return { 'Accept': 'application/json', 'Content-Type': 'application/json', 'X-Requested-By': 'GlassFish REST HTML interface' } def _get_auth(username, password): ''' Returns the HTTP auth header ''' if username and password: return requests.auth.HTTPBasicAuth(username, password) else: return None def _get_url(ssl, url, port, path): ''' Returns the URL of the endpoint ''' if ssl: return 'https://{0}:{1}/management/domain/{2}'.format(url, port, path) else: return 'http://{0}:{1}/management/domain/{2}'.format(url, port, path) def _get_server(server): ''' Returns the server information if provided, or the defaults ''' return server if server else DEFAULT_SERVER def _clean_data(data): ''' Removes SaltStack params from **kwargs ''' for key in list(data): if key.startswith('__pub'): del data[key] return data def _api_response(response): ''' Check response status code + success_code returned by glassfish ''' if response.status_code == 404: __context__['retcode'] = salt.defaults.exitcodes.SALT_BUILD_FAIL raise CommandExecutionError('Element doesn\'t exists') if response.status_code == 401: __context__['retcode'] = salt.defaults.exitcodes.SALT_BUILD_FAIL raise CommandExecutionError('Bad username or password') elif response.status_code == 200 or response.status_code == 500: try: data = salt.utils.json.loads(response.content) if data['exit_code'] != 'SUCCESS': __context__['retcode'] = salt.defaults.exitcodes.SALT_BUILD_FAIL raise CommandExecutionError(data['message']) return data except ValueError: __context__['retcode'] = salt.defaults.exitcodes.SALT_BUILD_FAIL raise CommandExecutionError('The server returned no data') else: response.raise_for_status() def _api_get(path, server=None): ''' Do a GET request to the API ''' server = _get_server(server) response = requests.get( url=_get_url(server['ssl'], server['url'], server['port'], path), auth=_get_auth(server['user'], server['password']), headers=_get_headers(), verify=False ) return _api_response(response) def _api_post(path, data, server=None): ''' Do a POST request to the API ''' server = _get_server(server) response = requests.post( url=_get_url(server['ssl'], server['url'], server['port'], path), auth=_get_auth(server['user'], server['password']), headers=_get_headers(), data=salt.utils.json.dumps(data), verify=False ) return _api_response(response) def _api_delete(path, data, server=None): ''' Do a DELETE request to the API ''' server = _get_server(server) response = requests.delete( url=_get_url(server['ssl'], server['url'], server['port'], path), auth=_get_auth(server['user'], server['password']), headers=_get_headers(), params=data, verify=False ) return _api_response(response) # "Middle layer": uses _api_* functions to enum/get/create/update/delete elements def _enum_elements(name, server=None): ''' Enum elements ''' elements = [] data = _api_get(name, server) if any(data['extraProperties']['childResources']): for element in data['extraProperties']['childResources']: elements.append(element) return elements return None def _get_element_properties(name, element_type, server=None): ''' Get an element's properties ''' properties = {} data = _api_get('{0}/{1}/property'.format(element_type, name), server) # Get properties into a dict if any(data['extraProperties']['properties']): for element in data['extraProperties']['properties']: properties[element['name']] = element['value'] return properties return {} def _get_element(name, element_type, server=None, with_properties=True): ''' Get an element with or without properties ''' element = {} name = quote(name, safe='') data = _api_get('{0}/{1}'.format(element_type, name), server) # Format data, get properties if asked, and return the whole thing if any(data['extraProperties']['entity']): for key, value in data['extraProperties']['entity'].items(): element[key] = value if with_properties: element['properties'] = _get_element_properties(name, element_type) return element return None def _create_element(name, element_type, data, server=None): ''' Create a new element ''' # Define property and id from name and properties + remove SaltStack parameters if 'properties' in data: data['property'] = '' for key, value in data['properties'].items(): if not data['property']: data['property'] += '{0}={1}'.format(key, value.replace(':', '\\:')) else: data['property'] += ':{0}={1}'.format(key, value.replace(':', '\\:')) del data['properties'] # Send request _api_post(element_type, _clean_data(data), server) return unquote(name) def _update_element(name, element_type, data, server=None): ''' Update an element, including it's properties ''' # Urlencode the name (names may have slashes) name = quote(name, safe='') # Update properties first if 'properties' in data: properties = [] for key, value in data['properties'].items(): properties.append({'name': key, 'value': value}) _api_post('{0}/{1}/property'.format(element_type, name), properties, server) del data['properties'] # If the element only contained properties if not data: return unquote(name) # Get the current data then merge updated data into it update_data = _get_element(name, element_type, server, with_properties=False) if update_data: update_data.update(data) else: __context__['retcode'] = salt.defaults.exitcodes.SALT_BUILD_FAIL raise CommandExecutionError('Cannot update {0}'.format(name)) # Finally, update the element _api_post('{0}/{1}'.format(element_type, name), _clean_data(update_data), server) return unquote(name) def _delete_element(name, element_type, data, server=None): ''' Delete an element ''' _api_delete('{0}/{1}'.format(element_type, quote(name, safe='')), data, server) return name # Connector connection pools def enum_connector_c_pool(server=None): ''' Enum connection pools ''' return _enum_elements('resources/connector-connection-pool', server) def get_connector_c_pool(name, server=None): ''' Get a specific connection pool ''' return _get_element(name, 'resources/connector-connection-pool', server) def create_connector_c_pool(name, server=None, **kwargs): ''' Create a connection pool ''' defaults = { 'connectionDefinitionName': 'javax.jms.ConnectionFactory', 'resourceAdapterName': 'jmsra', 'associateWithThread': False, 'connectionCreationRetryAttempts': 0, 'connectionCreationRetryIntervalInSeconds': 0, 'connectionLeakReclaim': False, 'connectionLeakTimeoutInSeconds': 0, 'description': '', 'failAllConnections': False, 'id': name, 'idleTimeoutInSeconds': 300, 'isConnectionValidationRequired': False, 'lazyConnectionAssociation': False, 'lazyConnectionEnlistment': False, 'matchConnections': True, 'maxConnectionUsageCount': 0, 'maxPoolSize': 32, 'maxWaitTimeInMillis': 60000, 'ping': False, 'poolResizeQuantity': 2, 'pooling': True, 'steadyPoolSize': 8, 'target': 'server', 'transactionSupport': '', 'validateAtmostOncePeriodInSeconds': 0 } # Data = defaults + merge kwargs + remove salt data = defaults data.update(kwargs) # Check TransactionSupport against acceptable values if data['transactionSupport'] and data['transactionSupport'] not in ( 'XATransaction', 'LocalTransaction', 'NoTransaction' ): raise CommandExecutionError('Invalid transaction support') return _create_element(name, 'resources/connector-connection-pool', data, server) def update_connector_c_pool(name, server=None, **kwargs): ''' Update a connection pool ''' if 'transactionSupport' in kwargs and kwargs['transactionSupport'] not in ( 'XATransaction', 'LocalTransaction', 'NoTransaction' ): raise CommandExecutionError('Invalid transaction support') return _update_element(name, 'resources/connector-connection-pool', kwargs, server) def delete_connector_c_pool(name, target='server', cascade=True, server=None): ''' Delete a connection pool ''' data = {'target': target, 'cascade': cascade} return _delete_element(name, 'resources/connector-connection-pool', data, server) # Connector resources def enum_connector_resource(server=None): ''' Enum connection resources ''' return _enum_elements('resources/connector-resource', server) def get_connector_resource(name, server=None): ''' Get a specific connection resource ''' return _get_element(name, 'resources/connector-resource', server) def create_connector_resource(name, server=None, **kwargs): ''' Create a connection resource ''' defaults = { 'description': '', 'enabled': True, 'id': name, 'poolName': '', 'objectType': 'user', 'target': 'server' } # Data = defaults + merge kwargs + poolname data = defaults data.update(kwargs) if not data['poolName']: raise CommandExecutionError('No pool name!') # Fix for lowercase vs camelCase naming differences for key, value in list(data.items()): del data[key] data[key.lower()] = value return _create_element(name, 'resources/connector-resource', data, server) def update_connector_resource(name, server=None, **kwargs): ''' Update a connection resource ''' # You're not supposed to update jndiName, if you do so, it will crash, silently if 'jndiName' in kwargs: del kwargs['jndiName'] return _update_element(name, 'resources/connector-resource', kwargs, server) def delete_connector_resource(name, target='server', server=None): ''' Delete a connection resource ''' return _delete_element(name, 'resources/connector-resource', {'target': target}, server) # JMS Destinations def enum_admin_object_resource(server=None): ''' Enum JMS destinations ''' return _enum_elements('resources/admin-object-resource', server) def get_admin_object_resource(name, server=None): ''' Get a specific JMS destination ''' return _get_element(name, 'resources/admin-object-resource', server) def create_admin_object_resource(name, server=None, **kwargs): ''' Create a JMS destination ''' defaults = { 'description': '', 'className': 'com.sun.messaging.Queue', 'enabled': True, 'id': name, 'resAdapter': 'jmsra', 'resType': 'javax.jms.Queue', 'target': 'server' } # Data = defaults + merge kwargs + poolname data = defaults data.update(kwargs) # ClassName isn't optional, even if the API says so if data['resType'] == 'javax.jms.Queue': data['className'] = 'com.sun.messaging.Queue' elif data['resType'] == 'javax.jms.Topic': data['className'] = 'com.sun.messaging.Topic' else: raise CommandExecutionError('resType should be "javax.jms.Queue" or "javax.jms.Topic"!') if data['resAdapter'] != 'jmsra': raise CommandExecutionError('resAdapter should be "jmsra"!') # Fix for lowercase vs camelCase naming differences if 'resType' in data: data['restype'] = data['resType'] del data['resType'] if 'className' in data: data['classname'] = data['className'] del data['className'] return _create_element(name, 'resources/admin-object-resource', data, server) def update_admin_object_resource(name, server=None, **kwargs): ''' Update a JMS destination ''' if 'jndiName' in kwargs: del kwargs['jndiName'] return _update_element(name, 'resources/admin-object-resource', kwargs, server) def delete_admin_object_resource(name, target='server', server=None): ''' Delete a JMS destination ''' return _delete_element(name, 'resources/admin-object-resource', {'target': target}, server) # JDBC Pools def enum_jdbc_connection_pool(server=None): ''' Enum JDBC pools ''' return _enum_elements('resources/jdbc-connection-pool', server) def get_jdbc_connection_pool(name, server=None): ''' Get a specific JDBC pool ''' return _get_element(name, 'resources/jdbc-connection-pool', server) def create_jdbc_connection_pool(name, server=None, **kwargs): ''' Create a connection resource ''' defaults = { 'allowNonComponentCallers': False, 'associateWithThread': False, 'connectionCreationRetryAttempts': '0', 'connectionCreationRetryIntervalInSeconds': '10', 'connectionLeakReclaim': False, 'connectionLeakTimeoutInSeconds': '0', 'connectionValidationMethod': 'table', 'datasourceClassname': '', 'description': '', 'driverClassname': '', 'failAllConnections': False, 'idleTimeoutInSeconds': '300', 'initSql': '', 'isConnectionValidationRequired': False, 'isIsolationLevelGuaranteed': True, 'lazyConnectionAssociation': False, 'lazyConnectionEnlistment': False, 'matchConnections': False, 'maxConnectionUsageCount': '0', 'maxPoolSize': '32', 'maxWaitTimeInMillis': 60000, 'name': name, 'nonTransactionalConnections': False, 'ping': False, 'poolResizeQuantity': '2', 'pooling': True, 'resType': '', 'sqlTraceListeners': '', 'statementCacheSize': '0', 'statementLeakReclaim': False, 'statementLeakTimeoutInSeconds': '0', 'statementTimeoutInSeconds': '-1', 'steadyPoolSize': '8', 'target': 'server', 'transactionIsolationLevel': '', 'validateAtmostOncePeriodInSeconds': '0', 'validationClassname': '', 'validationTableName': '', 'wrapJdbcObjects': True } # Data = defaults + merge kwargs + poolname data = defaults data.update(kwargs) # Check resType against acceptable values if data['resType'] not in ( 'javax.sql.DataSource', 'javax.sql.XADataSource', 'javax.sql.ConnectionPoolDataSource', 'java.sql.Driver' ): raise CommandExecutionError('Invalid resource type') # Check connectionValidationMethod against acceptable velues if data['connectionValidationMethod'] not in ( 'auto-commit', 'meta-data', 'table', 'custom-validation' ): raise CommandExecutionError('Invalid connection validation method') if data['transactionIsolationLevel'] \ and data['transactionIsolationLevel'] not in ( 'read-uncommitted', 'read-committed', 'repeatable-read', 'serializable' ): raise CommandExecutionError('Invalid transaction isolation level') if not data['datasourceClassname'] \ and data['resType'] in ( 'javax.sql.DataSource', 'javax.sql.ConnectionPoolDataSource', 'javax.sql.XADataSource' ): raise CommandExecutionError('No datasource class name while using datasource resType') if not data['driverClassname'] and data['resType'] == 'java.sql.Driver': raise CommandExecutionError('No driver class nime while using driver resType') return _create_element(name, 'resources/jdbc-connection-pool', data, server) def update_jdbc_connection_pool(name, server=None, **kwargs): ''' Update a JDBC pool ''' return _update_element(name, 'resources/jdbc-connection-pool', kwargs, server) def delete_jdbc_connection_pool(name, target='server', cascade=False, server=None): ''' Delete a JDBC pool ''' data = {'target': target, 'cascade': cascade} return _delete_element(name, 'resources/jdbc-connection-pool', data, server) # JDBC resources def enum_jdbc_resource(server=None): ''' Enum JDBC resources ''' return _enum_elements('resources/jdbc-resource', server) def get_jdbc_resource(name, server=None): ''' Get a specific JDBC resource ''' return _get_element(name, 'resources/jdbc-resource', server) def create_jdbc_resource(name, server=None, **kwargs): ''' Create a JDBC resource ''' defaults = { 'description': '', 'enabled': True, 'id': name, 'poolName': '', 'target': 'server' } # Data = defaults + merge kwargs + poolname data = defaults data.update(kwargs) if not data['poolName']: raise CommandExecutionError('No pool name!') return _create_element(name, 'resources/jdbc-resource', data, server) def update_jdbc_resource(name, server=None, **kwargs): ''' Update a JDBC resource ''' # You're not supposed to update jndiName, if you do so, it will crash, silently if 'jndiName' in kwargs: del kwargs['jndiName'] return _update_element(name, 'resources/jdbc-resource', kwargs, server) def delete_jdbc_resource(name, target='server', server=None): ''' Delete a JDBC resource ''' return _delete_element(name, 'resources/jdbc-resource', {'target': target}, server) # System properties def get_system_properties(server=None): ''' Get system properties ''' properties = {} data = _api_get('system-properties', server) # Get properties into a dict if any(data['extraProperties']['systemProperties']): for element in data['extraProperties']['systemProperties']: properties[element['name']] = element['value'] return properties return {} def update_system_properties(data, server=None): ''' Update system properties ''' _api_post('system-properties', _clean_data(data), server) return data def delete_system_properties(name, server=None): ''' Delete a system property ''' _api_delete('system-properties/{0}'.format(name), None, server)