Completed
Pull Request — master (#502)
by
unknown
03:06
created

_post_event_to_st2()   A

Complexity

Conditions 3

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
dl 0
loc 18
rs 9.4285
c 0
b 0
f 0
1
#!/usr/bin/env python
2
3
import httplib
4
try:
5
    import simplejson as json
6
except ImportError:
7
    import json
8
import os
9
import sys
10
import traceback
11
from urlparse import urljoin
12
13
try:
14
    import requests
15
except ImportError:
16
    raise ImportError('Missing dependency requests. \
17
                      Do ``pip install requests``.')
18
19
try:
20
    import yaml
21
except ImportError:
22
    raise ImportError('Missing dependency pyyaml. \
23
                      Do ``pip install pyyaml``.')
24
25
# ST2 configuration
26
27
ST2_CONFIG_FILE = './config.yaml'
28
29
ST2_API_BASE_URL = 'http://localhost/api/v1/'
30
ST2_AUTH_BASE_URL = 'http://localhost/auth/v1/'
31
ST2_USERNAME = None
32
ST2_PASSWORD = None
33
ST2_AUTH_TOKEN = None
34
ST2_SSL_VERIFY = False
35
36
ST2_AUTH_PATH = 'tokens'
37
ST2_WEBHOOKS_PATH = 'webhooks/st2'
38
ST2_TRIGGERS_PATH = 'triggertypes'
39
ST2_TRIGGERTYPE_PACK = 'nagios'
40
ST2_TRIGGERTYPE_NAME = 'service-state-change'
41
ST2_TRIGGERTYPE_REF = '.'.join([ST2_TRIGGERTYPE_PACK, ST2_TRIGGERTYPE_NAME])
42
43
STATE_MESSAGE = {
44
    'OK': 'All is well on the Western front.',
45
    'WARNING': 'We gots a warning yo!',
46
    'UNKNOWN': 'It be unknown...',
47
    'CRITICAL': 'Critical!'
48
}
49
50
REGISTERED_WITH_ST2 = False
51
UNAUTHED = False
52
IS_API_KEY_AUTH = False
53
54
OK_CODES = [httplib.OK, httplib.CREATED, httplib.ACCEPTED, httplib.CONFLICT]
55
UNREACHABLE_CODES = [httplib.NOT_FOUND]
56
57
TOKEN_AUTH_HEADER = 'X-Auth-Token'
58
API_KEY_AUTH_HEADER = 'St2-Api-Key'
59
verbose = True
60
61
62
def _create_trigger_type(verbose=False):
63
    try:
64
        url = _get_st2_triggers_url()
65
        payload = {
66
            'name': ST2_TRIGGERTYPE_NAME,
67
            'pack': ST2_TRIGGERTYPE_PACK,
68
            'description': 'Trigger type for nagios event handler.'
69
        }
70
        sys.stdout.write('POST: %s: Body: %s\n' % (url, payload))
71
72
        headers = _get_st2_request_headers()
73
        headers['Content-Type'] = 'application/json; charset=utf-8'
74
75
        if verbose:
76
            print('POST to URL %s for registering trigger. Body = %s, \
77
                  headers = %s.' % (url, payload, headers))
78
79
        post_resp = requests.post(url, data=json.dumps(payload),
80
                                  headers=headers,
81
                                  verify=ST2_SSL_VERIFY)
82
    except:
83
        traceback.print_exc(limit=20)
84
        raise Exception('Unable to connect to st2 endpoint %s.' % url)
85
    else:
86
        status = post_resp.status_code
87
        if status in UNREACHABLE_CODES:
88
            msg = 'Got response %s. Invalid triggers endpoint %s. \
89
                Check configuration!' % (status, url)
90
            raise Exception(msg)
91
92
        if status not in OK_CODES:
93
            msg = 'Failed to register trigger type %s.%s with st2. HTTP_CODE: \
94
                %s' % (ST2_TRIGGERTYPE_PACK, ST2_TRIGGERTYPE_NAME, status)
95
            raise Exception(msg)
96
        else:
97
            print('Registered trigger type with st2.')
98
99
100
def _get_auth_url():
101
    return urljoin(ST2_AUTH_BASE_URL, ST2_AUTH_PATH)
102
103
104
def _get_auth_token(verbose=False):
105
    # global ST2_AUTH_TOKEN
106
    auth_url = _get_auth_url()
107
108
    if verbose:
109
        print('Will POST to URL %s to get auth token.' % auth_url)
110
111
    try:
112
        print "get_auth_token"
113
        resp = requests.post(auth_url,
114
                            json.dumps({'ttl': 5 * 60}),
115
                            auth=(ST2_USERNAME, ST2_PASSWORD),
116
                            verify=ST2_SSL_VERIFY)
117
        print "resp is:", resp
118
    except:
119
        traceback.print_exc(limit=20)
120
        raise Exception('Unable to connect to st2 endpoint %s.' % auth_url)
121
    else:
122
        if resp.status_code in UNREACHABLE_CODES:
123
            msg = 'Got response %s. Invalid auth endpoint %s. \
124
                   Check configuration!' % (resp.status_code,
125
                                            auth_url)
126
            raise Exception(msg)
127
        if resp.status_code not in OK_CODES:
128
            msg = 'Cannot get a valid auth token from %s. HTTP_CODE: %s' % (
129
                    auth_url,
130
                    resp.status_code
131
                    )
132
            raise Exception(msg)
133
        return resp.json()['token']
134
135
136
def _get_st2_request_headers():
137
    headers = {}
138
139
    if not UNAUTHED:
140
        if IS_API_KEY_AUTH:
141
            headers[API_KEY_AUTH_HEADER] = ST2_API_KEY
142
        else:
143
            if ST2_AUTH_TOKEN:
144
                headers[TOKEN_AUTH_HEADER] = ST2_AUTH_TOKEN
145
            else:
146
                pass
147
148
    return headers
149
150
151
def _register_with_st2(verbose=False):
152
    global REGISTERED_WITH_ST2
153
    try:
154
        if not REGISTERED_WITH_ST2:
155
            if verbose:
156
                print('Checking if trigger %s registered with st2.'
157
                      % ST2_TRIGGERTYPE_REF)
158
            _register_trigger_with_st2(verbose=verbose)
159
            REGISTERED_WITH_ST2 = True
160
    except:
161
        traceback.print_exc(limit=20)
162
        sys.stderr.write(
163
            'Failed registering with st2. Won\'t post event.\n')
164
        sys.exit(2)
165
166
167
def _register_trigger_with_st2(verbose=False):
168
    url = urljoin(_get_st2_triggers_url(), ST2_TRIGGERTYPE_REF)
169
    sys.stdout.write('GET: %s\n' % url)
170
171
    try:
172
        headers = _get_st2_request_headers()
173
        if verbose:
174
            print('Will GET from URL %s for detecting trigger %s.' %
175
                  (url, ST2_TRIGGERTYPE_REF))
176
            print('Request headers: %s' % headers)
177
        get_resp = requests.get(url, headers=headers, verify=ST2_SSL_VERIFY)
178
        # else:
179
        #    get_resp = requests.get(url)
180
        if get_resp.status_code != httplib.OK:
181
            _create_trigger_type(verbose=verbose)
182
        else:
183
            body = json.loads(get_resp.text)
184
            if len(body) == 0:
185
                _create_trigger_type(verbose=verbose)
186
    except:
187
        traceback.print_exc(limit=20)
188
        raise Exception('Unable to connect to st2 endpoint %s.' % url)
189
    else:
190
        if verbose:
191
            print('Successfully registered trigger %s with st2.'
192
                  % ST2_TRIGGERTYPE_REF)
193
194
195
def _get_st2_triggers_url():
196
    url = urljoin(ST2_API_BASE_URL, ST2_TRIGGERS_PATH)
197
    return url
198
199
200
def _get_st2_webhooks_url():
201
    url = urljoin(ST2_API_BASE_URL, ST2_WEBHOOKS_PATH)
202
    return url
203
204
205
def _post_webhook(url, body, verbose=False):
206
    headers = _get_st2_request_headers()
207
    headers['X-ST2-Integration'] = 'nagios.'
208
    headers['St2-Trace-Tag'] = body['payload']['id']
209
    headers['Content-Type'] = 'application/json; charset=utf-8'
210
211
    try:
212
        if verbose:
213
            print('Webhook POST: url: %s, headers: %s, body: %s\n'
214
                  % (url, headers, body))
215
        r = requests.post(url, data=json.dumps(body), headers=headers,
216
                          verify=False)
217
    except:
218
        raise Exception('Cannot connect to st2 endpoint %s.' % url)
219
    else:
220
        status = r.status_code
221
222
        if status in UNREACHABLE_CODES:
223
            msg = 'Webhook URL %s does not exist. Check StackStorm \
224
                installation!'
225
            raise Exception(msg)
226
227
        if status not in OK_CODES:
228
            sys.stderr.write('Failed posting nagio event to st2. HTTP_CODE: \
229
                %d\n' % status)
230
        else:
231
            sys.stdout.write('Sent nagio event to st2. HTTP_CODE: \
232
                %d\n' % status)
233
234
235
def _post_event_to_st2(payload, verbose=False):
236
    body = {}
237
    body['trigger'] = ST2_TRIGGERTYPE_REF
238
239
    try:
240
        body['payload'] = json.loads(payload)
241
    except:
242
        print('Invalid JSON payload %s.' % payload)
243
        sys.exit(3)
244
245
    try:
246
        _post_webhook(url=_get_st2_webhooks_url(), body=body, verbose=verbose)
247
        return True
248
    except:
249
        traceback.print_exc(limit=20)
250
        print('Cannot send event to st2.')
251
        # sys.exit(4)
252
        return False
253
254
255
def _get_payload(host, service, event_id, state, state_type, attempt):
256
    payload = {}
257
    payload['host'] = host
258
    payload['service'] = service
259
    payload['event_id'] = event_id
260
    payload['state'] = state
261
    payload['state_type'] = state_type
262
    payload['attempt'] = attempt
263
    payload['msg'] = STATE_MESSAGE.get(state, 'Undefined state.')
264
    return payload
265
266
267
def main(args):
268
    event_id = args[1]
269
    service = args[2]
270
    state = args[3]
271
    state_type = args[4]
272
    attempt = args[5]
273
    host = args[6]
274
275
    payload = _get_payload(host, service, event_id, state, state_type, attempt)
276
    body = {}
277
    body['trigger'] = ST2_TRIGGERTYPE_REF
278
    body['payload'] = payload
279
    _post_event_to_st2(payload, verbose=verbose)
280
281
282
if __name__ == '__main__':
283
    try:
284
        if not os.path.exists(ST2_CONFIG_FILE):
285
            sys.stderr.write('Configuration file not found. Exiting.\n')
286
            sys.exit(1)
287
288
        with open(ST2_CONFIG_FILE) as f:
289
            config = yaml.safe_load(f)
290
            ST2_USERNAME = config['st2_username']
291
            ST2_PASSWORD = config['st2_password']
292
            ST2_API_BASE_URL = config['st2_api_base_url']
293
            ST2_AUTH_BASE_URL = config['st2_auth_base_url']
294
        try:
295
            if not ST2_AUTH_TOKEN:
296
                print('No auth token found. Let\'s get one from StackStorm!')
297
                ST2_AUTH_TOKEN = _get_auth_token(verbose=verbose)
298
        except:
299
            traceback.print_exc(limit=20)
300
            print('Unable to negotiate an auth token. Exiting!')
301
            sys.exit(1)
302
303
        if not REGISTERED_WITH_ST2:
304
            _register_with_st2(verbose=verbose)
305
    except:
306
        sys.stderr.write('Failed registering with st2. Won\'t post event.\n')
307
    else:
308
        main(sys.argv)
309