New version of salt-formula from Saltstack
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

248 lines
6.6KB

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