Bez popisu

circusd.py 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. from __future__ import absolute_import
  2. import os
  3. import difflib
  4. import six
  5. import json
  6. from salt.exceptions import SaltInvocationError
  7. """
  8. Interaction with the circusd daemon
  9. ===================================
  10. .. code-block:: yaml
  11. my_watcher:
  12. circusd.watcher_running:
  13. - watch:
  14. - file: /etc/circusd/conf.d/my_watcher.ini
  15. """
  16. def _parse_output(ouptput):
  17. try:
  18. result = json.loads(ouptput)
  19. except ValueError:
  20. return None
  21. if isinstance(result, dict) and ('status' in result):
  22. return result
  23. else:
  24. return None
  25. def _error(ret, error_msg):
  26. ret['result'] = False
  27. ret['comment'] = error_msg
  28. return ret
  29. def watcher_running(name,
  30. endpoint=None,
  31. ssh=None,
  32. ssh_keyfile=None,
  33. timeout=None,
  34. bin_env=None,
  35. restart=None):
  36. """
  37. Ensure that a circus watcher is running.
  38. name
  39. The name of the watcher as it appears in 'circusctl status'
  40. endpoint
  41. circusctl connection endpoint
  42. ssh
  43. circusctl SSH connection details in the form user@host:port
  44. ssh_keyfile
  45. circusctl SSH keyfile path
  46. timeout
  47. circusctl timeout
  48. bin_env
  49. path to circusctl binary or path to virtualenv with circusctl
  50. installed
  51. """
  52. ret = {'name': name, 'changes': {}, 'result': False, 'comment': ''}
  53. is_test = True if __opts__['test'] else False
  54. output = __salt__['circusd.status'](name, json=True, endpoint=endpoint, ssh=ssh, ssh_keyfile=ssh_keyfile, timeout=timeout, bin_env=bin_env)
  55. result = _parse_output(output)
  56. if result is None:
  57. return _error(ret, 'circusctl: {0}'.format(output))
  58. # Known status values at the time of writing:
  59. # - error
  60. # - stopping
  61. # - stopped
  62. # - starting
  63. # - active
  64. if result['status'] == 'error':
  65. return _error(ret, 'circusctl: watcher {0} not found'.format(name))
  66. is_stopped = result['status'] in ('stopping', 'stopped')
  67. start_prefix = '' if is_stopped else 're'
  68. verb = 'is set to be' if is_test else 'was'
  69. if is_stopped:
  70. ret['comment'] = 'Watcher {0} {1} started'.format(name, verb)
  71. ret['changes'][name] = True
  72. elif restart:
  73. ret['comment'] = 'Watcher {0} {1} restarted'.format(name, verb)
  74. ret['changes'][name] = True
  75. else:
  76. ret['comment'] = 'Watcher {0} is already running'.format(name)
  77. ret['result'] = True
  78. return ret
  79. if is_test:
  80. ret['result'] = None
  81. return ret
  82. output = __salt__['circusd.{0}start'.format(start_prefix)](name, json=True, waiting=True, endpoint=endpoint, ssh=ssh, ssh_keyfile=ssh_keyfile, timeout=timeout, bin_env=bin_env)
  83. result = _parse_output(output)
  84. if result is None:
  85. return _error(ret, 'circusctl: {0}'.format(output))
  86. if result['status'] == 'error':
  87. return _error(ret, 'circusctl: {0}'.format(result['reason']))
  88. if result['status'] != 'ok':
  89. return _error(ret, 'circusctl: {0}'.format(output))
  90. if not result['info']['started'] and not result['info']['kept']:
  91. return _error(ret, 'Watcher {0} failed to start'.format(name))
  92. ret['result'] = True
  93. return ret
  94. # NOTE: As of Salt version 2016.3.2, mod_watch is not called if both
  95. # watcher_running and the watched state report changes, even though the
  96. # documenation states that mod_watch is called whenever the watched state
  97. # report changes. This means we cannot do a 'circusctl reloadconfig' in
  98. # mod_watch as it won't be called if the watcher wasn't running and
  99. # watcher_running has to start it (thereby causing it to return changes).
  100. # Instead, we get reloadconfig to run before this state using a combination
  101. # of 'onchanges' requisites and 'test.succeed_with(out)_changes' states.
  102. def mod_watch(name,
  103. endpoint=None,
  104. ssh=None,
  105. ssh_keyfile=None,
  106. timeout=None,
  107. bin_env=None,
  108. **kwargs):
  109. # Always restart the watcher on changes.
  110. return watcher_running(name=name,
  111. endpoint=endpoint,
  112. ssh=ssh,
  113. ssh_keyfile=ssh_keyfile,
  114. timeout=timeout,
  115. bin_env=bin_env,
  116. restart=True)