blob: bf847d61779fcdd9088d977b2cb97c4a228d4fe0 [file] [log] [blame]
from __future__ import absolute_import
# Let's not allow PyLint complain about string substitution
# pylint: disable=W1321,E1321
# Import python libs
import logging
# Import Salt libs
import salt.returners
# Import third party libs
try:
import psycopg2
import psycopg2.extras
HAS_POSTGRES = True
except ImportError:
HAS_POSTGRES = False
__virtualname__ = 'saltresource'
LOG = logging.getLogger(__name__)
def __virtual__():
if not HAS_POSTGRES:
return False, 'Could not import saltresource module; psycopg2 is not installed.'
return __virtualname__
def _get_options(ret=None):
'''
Get the postgres options from salt.
'''
defaults = {'host': '127.0.0.1',
'user': 'salt',
'passwd': 'salt',
'db': 'salt',
'port': '5432'}
_options = {}
for key, default in defaults.items():
_options[key] = __salt__['config.get']('%s.%s' % (__virtualname__, key), default)
return _options
def _get_conn(ret=None):
'''
Return a postgres connection.
'''
_options = _get_options(ret)
host = _options.get('host')
user = _options.get('user')
passwd = _options.get('passwd')
datab = _options.get('db')
port = _options.get('port')
return psycopg2.connect(
host=host,
user=user,
password=passwd,
database=datab,
port=port)
def _close_conn(conn):
'''
Close the Postgres connection
'''
conn.commit()
conn.close()
def graph_data(*args, **kwargs):
'''
Returns graph data for visualization app
CLI Examples:
.. code-block:: bash
salt '*' saltresource.graph_data
'''
conn = _get_conn()
cur_dict = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
cur_dict.execute('SELECT host, service, status FROM salt_resources')
resources_db = [dict(res) for res in cur_dict]
db_dict = {}
for resource in resources_db:
host = resource.get('host')
service = '.'.join(resource.get('service').split('.')[:2])
status = resource.get('status')
if db_dict.get(host, None):
if db_dict[host].get(service, None):
service_data = db_dict[host][service]
service_data.append(status)
else:
db_dict[host][service] = [status]
else:
db_dict[host] = {service: []}
graph = []
for host, services in db_dict.items():
for service, statuses in services.items():
status = 'unknown'
if 'failed' in statuses:
status = 'failed'
elif 'success' in statuses and not ('failed' in statuses or 'unknown' in statuses):
status = 'success'
datum = {'host': host, 'service': service, 'status': status}
graph.append(datum)
_close_conn(conn)
return {'graph': graph}
def host_data(host, **kwargs):
'''
Returns data describing single host
CLI Examples:
.. code-block:: bash
salt-call saltresource.host_data '<minion_id>'
'''
conn = _get_conn()
cur_dict = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
sql = 'SELECT host, service, resource_id, last_ret, status FROM salt_resources WHERE host=%s'
cur_dict.execute(sql, (host,))
resources_db = [dict(res) for res in cur_dict]
db_dict = {}
for resource in resources_db:
host = resource.get('host')
service = '.'.join(resource.get('service').split('.')[:2])
status = resource.get('status')
if db_dict.get(host, None):
if db_dict[host].get(service, None):
service_data = db_dict[host][service]
service_data.append(status)
else:
db_dict[host][service] = [status]
else:
db_dict[host] = {service: []}
graph = []
for host, services in db_dict.items():
for service, statuses in services.items():
status = 'unknown'
if 'failed' in statuses:
status = 'failed'
elif 'success' in statuses and not ('failed' in statuses or 'unknown' in statuses):
status = 'success'
resources = [{'service': r.get('service', ''), 'resource_id': r.get('resource_id', ''), 'last_ret': r.get('last_ret', None), 'status': r.get('status', '')}
for r
in resources_db
if r.get('service', '').startswith(service)]
datum = {'host': host, 'service': service, 'status': status, 'resources': resources}
graph.append(datum)
_close_conn(conn)
return {'graph': graph}
def sync_db(*args, **kwargs):
conn = _get_conn()
cur = conn.cursor()
resources_sql = '''
CREATE TABLE IF NOT EXISTS salt_resources (
id varchar(255) NOT NULL UNIQUE,
resource_id varchar(255) NOT NULL,
host varchar(255) NOT NULL,
service varchar(255) NOT NULL,
module varchar(50) NOT NULL,
fun varchar(50) NOT NULL,
status varchar(50) NOT NULL,
options json NULL,
last_ret text NULL,
alter_time TIMESTAMP WITH TIME ZONE DEFAULT now()
);
'''
cur.execute(resources_sql)
conn.commit()
resources_meta_sql = '''
CREATE TABLE IF NOT EXISTS salt_resources_meta (
id varchar(255) NOT NULL UNIQUE,
options json NULL,
alter_time TIMESTAMP WITH TIME ZONE DEFAULT now()
);
'''
cur.execute(resources_meta_sql)
_close_conn(conn)
return True
def flush_db(*args, **kwargs):
conn = _get_conn()
cur = conn.cursor()
result = True
resources_sql = 'DELETE FROM salt_resources'
try:
cur.execute(resources_sql)
conn.commit()
except Exception as e:
LOG.warning(repr(e))
result = False
resources_meta_sql = 'DELETE FROM salt_resources_meta'
try:
cur.execute(resources_meta_sql)
_close_conn(conn)
except Exception as e:
LOG.warning(repr(e))
result = False
return result
def destroy_db(*args, **kwargs):
conn = _get_conn()
cur = conn.cursor()
resources_sql = 'DROP TABLE IF EXISTS salt_resources;'
cur.execute(resources_sql)
conn.commit()
resources_meta_sql = 'DROP TABLE IF EXISTS salt_resources_meta;'
cur.execute(resources_meta_sql)
_close_conn(conn)
return True