New version of salt-formula from Saltstack
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

248 lines
6.5KB

  1. from __future__ import absolute_import
  2. # Let's not allow PyLint complain about string substitution
  3. # pylint: disable=W1321,E1321
  4. # Import python libs
  5. import logging
  6. # Import Salt libs
  7. import salt.returners
  8. # Import third party libs
  9. try:
  10. import psycopg2
  11. import psycopg2.extras
  12. HAS_POSTGRES = True
  13. except ImportError:
  14. HAS_POSTGRES = False
  15. __virtualname__ = 'saltresource'
  16. LOG = logging.getLogger(__name__)
  17. def __virtual__():
  18. if not HAS_POSTGRES:
  19. return False, 'Could not import saltresource module; psycopg2 is not installed.'
  20. return __virtualname__
  21. def _get_options(ret=None):
  22. '''
  23. Get the postgres options from salt.
  24. '''
  25. defaults = {'host': '127.0.0.1',
  26. 'user': 'salt',
  27. 'passwd': 'salt',
  28. 'db': 'salt',
  29. 'port': '5432'}
  30. _options = {}
  31. for key, default in defaults.items():
  32. _options[key] = __salt__['config.get']('%s.%s' % (__virtualname__, key), default)
  33. return _options
  34. def _get_conn(ret=None):
  35. '''
  36. Return a postgres connection.
  37. '''
  38. _options = _get_options(ret)
  39. host = _options.get('host')
  40. user = _options.get('user')
  41. passwd = _options.get('passwd')
  42. datab = _options.get('db')
  43. port = _options.get('port')
  44. return psycopg2.connect(
  45. host=host,
  46. user=user,
  47. password=passwd,
  48. database=datab,
  49. port=port)
  50. def _close_conn(conn):
  51. '''
  52. Close the Postgres connection
  53. '''
  54. conn.commit()
  55. conn.close()
  56. def graph_data(*args, **kwargs):
  57. '''
  58. Returns graph data for visualization app
  59. CLI Examples:
  60. .. code-block:: bash
  61. salt '*' saltresource.graph_data
  62. '''
  63. conn = _get_conn()
  64. cur_dict = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
  65. cur_dict.execute('SELECT host, service, status FROM salt_resources')
  66. resources_db = [dict(res) for res in cur_dict]
  67. db_dict = {}
  68. for resource in resources_db:
  69. host = resource.get('host')
  70. service = '.'.join(resource.get('service').split('.')[:2])
  71. status = resource.get('status')
  72. if db_dict.get(host, None):
  73. if db_dict[host].get(service, None):
  74. service_data = db_dict[host][service]
  75. service_data.append(status)
  76. else:
  77. db_dict[host][service] = [status]
  78. else:
  79. db_dict[host] = {service: []}
  80. graph = []
  81. for host, services in db_dict.items():
  82. for service, statuses in services.items():
  83. status = 'unknown'
  84. if 'failed' in statuses:
  85. status = 'failed'
  86. elif 'success' in statuses and not ('failed' in statuses or 'unknown' in statuses):
  87. status = 'success'
  88. datum = {'host': host, 'service': service, 'status': status}
  89. graph.append(datum)
  90. _close_conn(conn)
  91. return {'graph': graph}
  92. def host_data(host, **kwargs):
  93. '''
  94. Returns data describing single host
  95. CLI Examples:
  96. .. code-block:: bash
  97. salt-call saltresource.host_data '<minion_id>'
  98. '''
  99. conn = _get_conn()
  100. cur_dict = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
  101. sql = 'SELECT host, service, resource_id, last_ret, status FROM salt_resources WHERE host=%s'
  102. cur_dict.execute(sql, (host,))
  103. resources_db = [dict(res) for res in cur_dict]
  104. db_dict = {}
  105. for resource in resources_db:
  106. host = resource.get('host')
  107. service = '.'.join(resource.get('service').split('.')[:2])
  108. status = resource.get('status')
  109. if db_dict.get(host, None):
  110. if db_dict[host].get(service, None):
  111. service_data = db_dict[host][service]
  112. service_data.append(status)
  113. else:
  114. db_dict[host][service] = [status]
  115. else:
  116. db_dict[host] = {service: []}
  117. graph = []
  118. for host, services in db_dict.items():
  119. for service, statuses in services.items():
  120. status = 'unknown'
  121. if 'failed' in statuses:
  122. status = 'failed'
  123. elif 'success' in statuses and not ('failed' in statuses or 'unknown' in statuses):
  124. status = 'success'
  125. resources = [{'service': r.get('service', ''), 'resource_id': r.get('resource_id', ''), 'last_ret': r.get('last_ret', None), 'status': r.get('status', '')}
  126. for r
  127. in resources_db
  128. if r.get('service', '').startswith(service)]
  129. datum = {'host': host, 'service': service, 'status': status, 'resources': resources}
  130. graph.append(datum)
  131. _close_conn(conn)
  132. return {'graph': graph}
  133. def sync_db(*args, **kwargs):
  134. conn = _get_conn()
  135. cur = conn.cursor()
  136. resources_sql = '''
  137. CREATE TABLE IF NOT EXISTS salt_resources (
  138. id varchar(255) NOT NULL UNIQUE,
  139. resource_id varchar(255) NOT NULL,
  140. host varchar(255) NOT NULL,
  141. service varchar(255) NOT NULL,
  142. module varchar(50) NOT NULL,
  143. fun varchar(50) NOT NULL,
  144. status varchar(50) NOT NULL,
  145. options json NULL,
  146. last_ret text NULL,
  147. alter_time TIMESTAMP WITH TIME ZONE DEFAULT now()
  148. );
  149. '''
  150. cur.execute(resources_sql)
  151. conn.commit()
  152. resources_meta_sql = '''
  153. CREATE TABLE IF NOT EXISTS salt_resources_meta (
  154. id varchar(255) NOT NULL UNIQUE,
  155. options json NULL,
  156. alter_time TIMESTAMP WITH TIME ZONE DEFAULT now()
  157. );
  158. '''
  159. cur.execute(resources_meta_sql)
  160. _close_conn(conn)
  161. return True
  162. def flush_db(*args, **kwargs):
  163. conn = _get_conn()
  164. cur = conn.cursor()
  165. result = True
  166. resources_sql = 'DELETE FROM salt_resources'
  167. try:
  168. cur.execute(resources_sql)
  169. conn.commit()
  170. except Exception as e:
  171. LOG.warning(repr(e))
  172. result = False
  173. resources_meta_sql = 'DELETE FROM salt_resources_meta'
  174. try:
  175. cur.execute(resources_meta_sql)
  176. _close_conn(conn)
  177. except Exception as e:
  178. LOG.warning(repr(e))
  179. result = False
  180. return result
  181. def destroy_db(*args, **kwargs):
  182. conn = _get_conn()
  183. cur = conn.cursor()
  184. resources_sql = 'DROP TABLE IF EXISTS salt_resources;'
  185. cur.execute(resources_sql)
  186. conn.commit()
  187. resources_meta_sql = 'DROP TABLE IF EXISTS salt_resources_meta;'
  188. cur.execute(resources_meta_sql)
  189. _close_conn(conn)
  190. return True