Ver código fonte

Initial revision.

Andrew Klopper 8 anos atrás
commit
d4712976a5
2 arquivos alterados com 234 adições e 0 exclusões
  1. 90 0
      modules/circusd.py
  2. 144 0
      states/circusd.py

+ 90 - 0
modules/circusd.py

@@ -0,0 +1,90 @@
1
+from __future__ import absolute_import
2
+import os
3
+from salt.exceptions import CommandNotFoundError
4
+
5
+def __virtual__():
6
+    return True
7
+
8
+def _get_circusctl_bin(bin_env):
9
+    '''
10
+    Return circusctl command to call, either from a virtualenv, an argument
11
+    passed in, or from the global modules options
12
+    '''
13
+    cmd = 'circusctl'
14
+    if not bin_env:
15
+        which_result = __salt__['cmd.which_bin']([cmd])
16
+        if which_result is None:
17
+            raise CommandNotFoundError(
18
+                'Could not find a `{0}` binary'.format(cmd)
19
+            )
20
+        return which_result
21
+
22
+    # try to get binary from env
23
+    if os.path.isdir(bin_env):
24
+        cmd_bin = os.path.join(bin_env, 'bin', cmd)
25
+        if os.path.isfile(cmd_bin):
26
+            return cmd_bin
27
+        raise CommandNotFoundError('Could not find a `{0}` binary'.format(cmd))
28
+
29
+    return bin_env
30
+
31
+def _ctl_cmd(cmd, args, endpoint, json, prettify, ssh, ssh_keyfile, timeout, bin_env):
32
+    '''
33
+    Return the command list to use
34
+    '''
35
+    ret = [_get_circusctl_bin(bin_env)]
36
+    if endpoint is not None:
37
+        ret += ['--endpoint', endpoint]
38
+    if json:
39
+        ret.append('--json')
40
+    if prettify:
41
+        ret.append('--prettify')
42
+    if ssh is not None:
43
+        ret += ['--ssh', ssh]
44
+    if ssh_keyfile is not None:
45
+        ret += ['--ssh_keyfile', ssh_keyfile]
46
+    if timeout is not None:
47
+        ret += ['--timeout', timeout]
48
+    ret.append(cmd)
49
+    if args is not None:
50
+        ret += args
51
+    return ' ' .join(ret)
52
+
53
+def _get_return(ret):
54
+    if ret['retcode'] == 0:
55
+        return ret['stdout']
56
+    else:
57
+        return ret['stderr']
58
+
59
+def _run_ctl_cmd(cmd, args, endpoint, json, prettify, ssh, ssh_keyfile, timeout, bin_env):
60
+    ret = __salt__['cmd.run_all'](
61
+        _ctl_cmd(cmd, args, endpoint, json, prettify, ssh, ssh_keyfile, timeout, bin_env),
62
+        python_shell=False
63
+    )
64
+    return _get_return(ret)
65
+
66
+def _signal_watcher(signal, name, waiting, endpoint, json, prettify, ssh, ssh_keyfile, timeout, bin_env):
67
+    args = []
68
+    if name is not None:
69
+        args.append(name)
70
+    if waiting:
71
+        args.append('--waiting')
72
+    return _run_ctl_cmd(signal, args, endpoint, json, prettify, ssh, ssh_keyfile, timeout, bin_env)
73
+
74
+def start(name=None, waiting=True, endpoint=None, json=False, prettify=False, ssh=None, ssh_keyfile=None, timeout=None, bin_env=None):
75
+    return _signal_watcher('start', name, waiting, endpoint, json, prettify, ssh, ssh_keyfile, timeout, bin_env)
76
+
77
+def stop(name=None, waiting=True, endpoint=None, json=False, prettify=False, ssh=None, ssh_keyfile=None, timeout=None, bin_env=None):
78
+    return _signal_watcher('stop', name, waiting, endpoint, json, prettify, ssh, ssh_keyfile, timeout, bin_env)
79
+
80
+def restart(name=None, waiting=True, endpoint=None, json=False, prettify=False, ssh=None, ssh_keyfile=None, timeout=None, bin_env=None):
81
+    return _signal_watcher('restart', name, waiting, endpoint, json, prettify, ssh, ssh_keyfile, timeout, bin_env)
82
+
83
+def reloadconfig(waiting=True, endpoint=None, json=False, prettify=False, ssh=None, ssh_keyfile=None, timeout=None, bin_env=None):
84
+    return _signal_watcher('reloadconfig', None, waiting, endpoint, json, prettify, ssh, ssh_keyfile, timeout, bin_env)
85
+
86
+def status(name=None, endpoint=None, json=False, prettify=False, ssh=None, ssh_keyfile=None, timeout=None, bin_env=None):
87
+    return _signal_watcher('status', name, False, endpoint, json, prettify, ssh, ssh_keyfile, timeout, bin_env)
88
+
89
+def dstats(endpoint=None, json=False, prettify=False, ssh=None, ssh_keyfile=None, timeout=None, bin_env=None):
90
+    return _run_ctl_cmd('dstats', None, endpoint, json, prettify, ssh, ssh_keyfile, timeout, bin_env)

+ 144 - 0
states/circusd.py

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