Merge lp:~cprov/charms/trusty/logstash/heap_size into lp:~tanuki/charms/trusty/logstash/trunk

Proposed by Celso Providelo
Status: Superseded
Proposed branch: lp:~cprov/charms/trusty/logstash/heap_size
Merge into: lp:~tanuki/charms/trusty/logstash/trunk
Diff against target: 736 lines (+451/-85)
13 files modified
README.md (+0/-21)
config.yaml (+34/-4)
files/nrpe/check_e2e_output.py (+59/-0)
files/nrpe/check_lumberjack_e2e.py (+265/-0)
files/upstart/logstash-indexer.conf (+2/-1)
hooks/client-relation-changed (+13/-29)
hooks/config-changed (+27/-10)
hooks/nrpe-external-master-relation-changed (+43/-2)
templates/e2e-cron.tmpl (+4/-0)
templates/input-file-syslog.conf (+1/-1)
templates/input-python-logging.conf (+0/-14)
templates/input-redis.conf (+1/-1)
templates/output-elasticsearch.conf (+2/-2)
To merge this branch: bzr merge lp:~cprov/charms/trusty/logstash/heap_size
Reviewer Review Type Date Requested Status
Michael Nelson (community) Approve
Guillermo Gonzalez Needs Information
Review via email: mp+311665@code.launchpad.net

This proposal has been superseded by a proposal from 2016-11-23.

Commit message

Allowing changing the logstash maximum heap size as a configuration.

Description of the change

Allowing changing the logstash maximum heap size as a configuration.

Defaults to 1000m instead of the application 500m default value and allow adjustments.

To post a comment you must log in.
59. By Celso Providelo

Adding heap_size config option.

Revision history for this message
Guillermo Gonzalez (verterok) wrote :

Celso,

If this is to apply it to the OLS ELK, it's using a a different charm:

lp:~canonical-is-sa/charms/trusty/logstash/logstash2;revno=61,overwrite=true

the spec in use (for both staging and production) is: is/mojo-is-logging-kibana/ @ lp:canonical-mojo-specs.

review: Needs Information
Revision history for this message
Michael Nelson (michael.nelson) wrote :
review: Approve
60. By Celso Providelo

merge right branch (lp:~canonical-is-sa/charms/trusty/logstash/logstash2).

61. By Celso Providelo

Special (no-) limits configuration for logstash, so it can eat as much memory it is configured too.

Unmerged revisions

61. By Celso Providelo

Special (no-) limits configuration for logstash, so it can eat as much memory it is configured too.

60. By Celso Providelo

merge right branch (lp:~canonical-is-sa/charms/trusty/logstash/logstash2).

59. By Celso Providelo

Adding heap_size config option.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'README.md'
2--- README.md 2015-06-30 16:42:53 +0000
3+++ README.md 2016-11-23 22:25:27 +0000
4@@ -54,27 +54,6 @@
5 juju add-relation logstash-agent logstash-indexer:input
6
7
8-example 4 - python-logstash + Indexer + 2x ElasticSearch + Kibana
9-==================================================================
10-
11- juju deploy cs:trusty/elasticsearch
12- juju add-unit elasticsearch
13- juju deploy cs:trusty/logstash-indexer
14- juju add-relation elasticsearch:cluster logstash-indexer
15- juju deploy cs:trusty/kibana
16- juju add-relation elasticsearch:rest kibana
17- juju expose kibana
18-
19- juju expose logstash-indexer
20- $ python3
21- >>> import logging, logstash
22- >>> logger = logging.getLogger()
23- >>> logger.addHandler(
24- ... logstash.LogstashHandler('<ip-of-indexer>', port=5959, version=1))
25- >>> logger.info('Hello Logstash!!!')
26-
27-http://ip-of-kibana
28-
29 ### Caveats
30
31 The charm will fetch the logstash complete archive every time.
32
33=== modified file 'config.yaml'
34--- config.yaml 2015-09-29 19:30:00 +0000
35+++ config.yaml 2016-11-23 22:25:27 +0000
36@@ -1,11 +1,11 @@
37 options:
38 logstash-source:
39 type: string
40- default: "https://download.elasticsearch.org/logstash/logstash/logstash-1.4.2.tar.gz"
41+ default: "https://download.elastic.co/logstash/logstash/logstash-2.0.0.tar.gz"
42 description: The logstash binary file to install to this charm.
43 logstash-sum:
44 type: string
45- default: "d59ef579c7614c5df9bd69cfdce20ed371f728ff"
46+ default: "f0961520dd9590d3b600c877be66f79f94a05f80"
47 description: The checksum value for the logstash file.
48 extra-packages:
49 type: string
50@@ -22,7 +22,29 @@
51 extra-config:
52 type: string
53 default: ''
54- description: "Base64-encoded custom configuration content."
55+ description: |
56+ Base64-encoded custom configuration content. If you have a directory of
57+ logstash filters, you can set this with:
58+ juju set logstash extra-config="$(cat filters/* | base64)"
59+ extra-patterns:
60+ type: string
61+ default: ''
62+ description: |
63+ Base64-encoded custom grok patterns for your logstash filters. If you
64+ have a directory of patterns, you can set this with:
65+ juju set logstash extra-patterns="$(cat patterns/* | base64)"
66+ These will be placed into the /opt/logstash/patterns directory and so can be
67+ referenced in a grok filter with:
68+ grok {
69+ patterns_dir => "./patterns"
70+ match => { ... }
71+ }
72+ More info at https://www.elastic.co/guide/en/logstash/current/plugins-filters-grok.html#_custom_patterns
73+ heap_size:
74+ default: "1000m"
75+ type: string
76+ description: |
77+ Maximum Java heap size for the logstash process.
78 nagios_context:
79 default: "juju"
80 type: string
81@@ -40,7 +62,7 @@
82 A comma-separated list of nagios servicegroups.
83 If left empty, the nagios_context will be used as the servicegroup
84 nagios_check_procs_params:
85- default: "-a /opt/logstash/lib/logstash/runner.rb -c 1:1"
86+ default: "-a logstash/runner.rb -c 1:1"
87 type: string
88 description: The parameters to pass to the nrpe plugin check_procs.
89 nagios_check_tcp_params:
90@@ -51,3 +73,11 @@
91 default: "-D 30,14 -H 127.0.0.1 -p 5043"
92 type: string
93 description: The parameters to pass to the nrpe plugin "check_tcp --ssl" to check certificate expiration date.
94+ nagios_check_e2e_params:
95+ default: "-w 30 -c 60"
96+ type: string
97+ description: The parameters to pass to the nrpe plugin "check_lumberjack_e2e.py" to do a E2E check.
98+ nagios_check_e2e_cron:
99+ default: ""
100+ type: string
101+ description: cron interval
102
103=== added directory 'files/nrpe'
104=== added file 'files/nrpe/check_e2e_output.py'
105--- files/nrpe/check_e2e_output.py 1970-01-01 00:00:00 +0000
106+++ files/nrpe/check_e2e_output.py 2016-11-23 22:25:27 +0000
107@@ -0,0 +1,59 @@
108+#!/usr/bin/env python2
109+"""Script to check the output of check_lumberjack_e2e.py"""
110+
111+# Copyright (C) 2016 Guillermo Gonzalez <guillermo.gonzalez@canonical.com>
112+
113+from __future__ import unicode_literals
114+from __future__ import print_function
115+
116+import os
117+import sys
118+import time
119+import traceback
120+
121+
122+def main():
123+ import argparse
124+ parser = argparse.ArgumentParser()
125+ parser.add_argument('-f', dest="e2e_file", required=True)
126+ parser.add_argument('-w', dest="warn", type=int, default=450,
127+ help="file age warning threshold.")
128+ parser.add_argument('-c', dest="critical", type=int, default=600,
129+ help="file age critical threshold")
130+ args = parser.parse_args()
131+
132+ if os.path.exists(args.e2e_file):
133+ # check file age
134+ file_age = time.time() - os.path.getmtime(args.e2e_file)
135+ if file_age > args.critical:
136+ print("ERROR: e2e output file is too old (%s)" % (file_age))
137+ return 2
138+ elif file_age < args.critical and file_age > args.warn:
139+ print("WARNING: e2e output file is old (%s)" % (file_age))
140+ return 1
141+ # the file is recent enough
142+ else:
143+ with open(args.e2e_file, 'r') as fd:
144+ lines = fd.readlines()
145+ output = lines[-1]
146+ if output.startswith("OK"):
147+ print(output)
148+ return 0
149+ elif output.startswith("WARNING"):
150+ print(output)
151+ return 1
152+ elif output.startswith("ERROR"):
153+ print(output)
154+ return 2
155+ else:
156+ print("ERROR: e2e output file (%s) is missing" % (args.e2e_file,))
157+ return 2
158+
159+
160+if __name__ == "__main__":
161+ try:
162+ sys.exit(main())
163+ except Exception, e:
164+ print("ERROR: Unhandled error: %s" % (str(e),))
165+ traceback.print_exc()
166+ sys.exit(3)
167
168=== added file 'files/nrpe/check_lumberjack_e2e.py'
169--- files/nrpe/check_lumberjack_e2e.py 1970-01-01 00:00:00 +0000
170+++ files/nrpe/check_lumberjack_e2e.py 2016-11-23 22:25:27 +0000
171@@ -0,0 +1,265 @@
172+#!/usr/bin/env python3
173+"""
174+This is very simple lumbjerjack client to run a e2e check against logstash+elasticsearch.
175+
176+All the lumberjack protocol code was adapted from Matt Johnson: https://pypi.python.org/pypi/stashward/0.1.4
177+"""
178+
179+import traceback
180+import datetime
181+import struct
182+import errno
183+import socket
184+import sys
185+import urllib.request
186+import json
187+import time
188+import uuid
189+import random
190+
191+from logging import INFO
192+
193+from ssl import wrap_socket, CERT_NONE, CERT_REQUIRED, SSLError
194+from ssl import match_hostname, CertificateError
195+
196+
197+class ErrorCode:
198+ """
199+ We use some random numbers for error codes to make unit testing a little
200+ easier, and for greppability
201+ """
202+ GENERIC_SSL_FAILURE = 42218
203+ CN_MISMATCH = 34624
204+ FILE_NOT_FOUND = 17253
205+
206+
207+class LumberjackClient(object):
208+ """Single threaded Lumberjack client to send events"""
209+
210+ # The sequence number is 32 bits, so it should rollover to 0 when it gets there
211+ MAX_SEQUENCE_NUMBER = 2**32-1
212+
213+ def __init__(self, host, port, ca_certs=None, message_type="logstash-e2e"):
214+ """
215+ Specify the host, port, and file path to the concatenated list of CAs
216+ """
217+ self.host = host
218+ self.port = port
219+ self.ca_certs = ca_certs
220+ self.sequence_number = 0
221+ self.message_type = message_type
222+ self.sock = None
223+
224+ # immediately send a packet setting the windows size to something huge
225+ # since we don't care about ACKs
226+ self.send(struct.pack(b"!ssI", b"1", b"W", self.MAX_SEQUENCE_NUMBER))
227+
228+ def format_message(self, record):
229+ """Create a dict from the logging record"""
230+ message = {
231+ '@version': 1,
232+ 'message': record['message'],
233+
234+ # Extra Fields
235+ 'levelname': record['levelname'],
236+ 'logger': record['name'],
237+ 'type': self.message_type,
238+ 'path': '',
239+
240+ # required for logstash forwarder to work
241+ 'host': self.host,
242+ "line": 0,
243+ "offset": 0, # this is completely meaningless, but required
244+ "request_id": record['request_id']
245+ }
246+
247+ return message
248+
249+ def make_socket(self, timeout=1):
250+ """Make the socket and wrap it with SSL. A valid certificate is required from a trusted CA"""
251+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
252+ if hasattr(s, 'settimeout'):
253+ s.settimeout(timeout)
254+ s.connect((self.host, self.port))
255+
256+ try:
257+ if self.host != "127.0.0.1" and self.ca_certs:
258+ s = wrap_socket(s, cert_reqs=CERT_REQUIRED, ca_certs=self.ca_certs)
259+ else:
260+ s = wrap_socket(s, cert_reqs=CERT_NONE)
261+ except SSLError as e:
262+ # the ssl certificate was probably bad
263+ # since logging doesn't work, print to stderr
264+ traceback.print_exc()
265+ print("ERROR %d: This is likely caused by a CN mismatch, an invalid certificate file at %s, or a verification failure based on your CA file" % (ErrorCode.GENERIC_SSL_FAILURE, self.ca_certs), file=sys.stderr)
266+ s.close()
267+ raise
268+ except OSError as e:
269+ s.close()
270+ # if we get an ENOENT, that's because the ca_file is bad
271+ if e.errno == errno.ENOENT:
272+ traceback.print_exc()
273+ print("ERROR %d: This error is probably caused by a bad CA file at %s" % (ErrorCode.FILE_NOT_FOUND, self.ca_certs), file=sys.stderr)
274+ s.close()
275+ raise
276+
277+ # some python versions do not do a CN match check, so we have to do it
278+ try:
279+ if self.host != "127.0.0.1":
280+ # only check if this isn't executed from logstash server
281+ match_hostname(s.getpeercert(), self.host)
282+ except CertificateError as e:
283+ traceback.print_exc()
284+ print("ERROR %d: The CN provided by the server didn't match the host you connected to" % ErrorCode.CN_MISMATCH, file=sys.stderr)
285+ s.close()
286+ raise socket.error("CN Mismatch")
287+
288+ return s
289+
290+ def send(self, s):
291+ """
292+ Send a pickled string to the socket.
293+
294+ This function allows for partial sends which can happen when the
295+ network is busy.
296+ """
297+ if self.sock is None:
298+ self.sock = self.make_socket()
299+ try:
300+ if hasattr(self.sock, "sendall"):
301+ self.sock.sendall(s)
302+ else:
303+ sentsofar = 0
304+ left = len(s)
305+ while left > 0:
306+ sent = self.sock.send(s[sentsofar:])
307+ sentsofar = sentsofar + sent
308+ left = left - sent
309+ except socket.error:
310+ self.sock.close()
311+ self.sock = None # so we can call make_socket next time
312+
313+ def emit(self, record):
314+ """Format the record, and turn it into a logstash compatible packet"""
315+ packet = self.packetize(self.format_message(record), self.sequence_number)
316+ # critical section here for incremeting the sequence_number. Notice, we
317+ # don't have to wrap a lock around this, as this is single threaded
318+ self.sequence_number = self.sequence_number + 1 if self.sequence_number < self.MAX_SEQUENCE_NUMBER else 0
319+ self.send(packet)
320+
321+ def packetize(self, data, sequence_number):
322+ """
323+ Turn a dict into a byte stream that is compatible with logstash-forwarder's protocol
324+
325+ The packet looks like this:
326+
327+ Header "1D" - the version and frame type (data) in ascii
328+ 32 bit unsigned, big-endian, integer sequence number
329+ 32 bit unsigned, big-endian, integer count of the number of (key, value) pairs
330+ For each key, value pair:
331+ 32 bit unsigned, big-endian, integer number for the key length
332+ the key (raw bytes)
333+ 32 bit unsigned, big-endian, integer number for the value length
334+ the value (raw bytes)
335+
336+
337+ The data *MUST* include a key/value pair for "host", "line" and
338+ "offset". That fact isn't documented anywhere but here. You're welcome.
339+ """
340+ format_string = [b"!ssII"]
341+ string = [b"1", b"D", sequence_number, len(data)]
342+
343+ for key, value in data.items():
344+ # encode the keys and values as utf8-encoded bytestrings
345+ key = key.encode('utf-8')
346+ value = str(value).encode('utf-8')
347+
348+ # tack on the key length
349+ format_string.append(b"I")
350+ string.append(len(key))
351+ # tack on the key itself
352+ format_string.append(("%ds" % (len(key))).encode('utf-8'))
353+ string.append(key)
354+ # tack on the value length
355+ format_string.append(b"I")
356+ string.append(len(value))
357+ # tack on the value
358+ format_string.append(("%ds" % (len(value))).encode('utf-8'))
359+ string.append(value)
360+
361+ return struct.pack(b"".join(format_string), *string)
362+
363+
364+def main(args):
365+ req_id = str(uuid.uuid4())
366+ c = LumberjackClient(args.host, args.port, ca_certs=args.ca_certs,
367+ message_type=args.message_type)
368+ c.emit(dict(name="logstash-e2e", levelname=INFO,
369+ message='testing logstash e2e {}'.format(req_id),
370+ request_id=req_id))
371+ ts = time.time()
372+
373+ index = "logstash-%s" % datetime.datetime.utcnow().strftime("%Y.%m.%d")
374+ get_body = {"query": {"match": {"request_id": req_id}},
375+ "sort": [{"_timestamp": {"order": "desc"}}]
376+ }
377+
378+ ok = False
379+ elapsed = 0
380+ retry = 0
381+ es_hosts = args.es_host_port.split(',')
382+ while not ok or elapsed >= args.critical:
383+ es_host = es_hosts[random.randint(0, len(es_hosts)-1)]
384+ try:
385+ resp = urllib.request.urlopen("http://%s/%s/_search?size=1" % (es_host, index),
386+ data=json.dumps(get_body).encode('utf-8'),
387+ timeout=args.es_timeout)
388+ except Exception as e:
389+ print("Elasticsearch unreachable: %s" % str(e))
390+ return 2
391+ results = json.loads(resp.read().decode('utf-8'))
392+ elapsed = time.time()-ts
393+ for result in results['hits']['hits']:
394+ if 'request_id' in result['_source'] and req_id == result['_source']['request_id']:
395+ ok = True
396+ break
397+ if not ok:
398+ # trivial retry with backoff
399+ time.sleep((retry**0.5)+(random.randint(0, 1000) / 1000))
400+ retry = retry + 1
401+
402+ with open(args.e2e_file, 'w') as fd:
403+ if not ok or elapsed >= args.critical:
404+ fd.write("ERROR: Taking longer than %ss to reach ES, aborting\n" % (args.critical,))
405+ elif elapsed >= args.warn and elapsed < args.critical:
406+ fd.write("WARNING: Took longer than %ss to reach ES\n" % (args.warn,))
407+ else:
408+ fd.write("OK: took: %s\n" % (elapsed,))
409+ fd.flush()
410+
411+
412+if __name__ == "__main__":
413+ import argparse
414+ parser = argparse.ArgumentParser()
415+ parser.add_argument('-H', dest="host", default="127.0.0.1")
416+ parser.add_argument('-p', dest="port", default=5043, type=int)
417+ parser.add_argument('--ca-certs', dest="ca_certs", default=None)
418+ parser.add_argument('-m', dest="message_type", default="logstash-e2e")
419+ parser.add_argument('-w', dest="warn", type=int, default=60)
420+ parser.add_argument('-c', dest="critical", type=int, default=120)
421+ parser.add_argument('--es', dest="es_host_port", required=True,
422+ help="Comma separated list of elasticsearch " + \
423+ "host:port, e.g: host:port,host1:port1..")
424+ parser.add_argument('-t', dest="es_timeout", type=int, default=5,
425+ help="timeout for ES http request")
426+ parser.add_argument('-f', dest="e2e_file", required=True,
427+ help="path to the output file")
428+ args = parser.parse_args()
429+ try:
430+ sys.exit(main(args))
431+ except Exception as e:
432+ with open(args.e2e_file, 'w') as fd:
433+ fd.write("ERROR: Unhandled error: %s\n" % (str(e),))
434+ fd.flush()
435+ traceback.print_exc()
436+ sys.exit(1)
437
438=== modified file 'files/upstart/logstash-indexer.conf'
439--- files/upstart/logstash-indexer.conf 2014-09-23 12:11:08 +0000
440+++ files/upstart/logstash-indexer.conf 2016-11-23 22:25:27 +0000
441@@ -11,6 +11,7 @@
442 respawn
443 respawn limit 5 30
444 env HOME={{BASEPATH}}
445+env LS_HEAP_SIZE={{HEAP_SIZE}}
446 chdir {{BASEPATH}}
447 setuid logstash
448 setgid adm
449@@ -18,4 +19,4 @@
450
451 script
452 {{BASEPATH}}/bin/logstash agent -f {{BASEPATH}}/conf.d/
453-end script
454\ No newline at end of file
455+end script
456
457=== modified file 'hooks/client-relation-changed'
458--- hooks/client-relation-changed 2015-09-08 19:45:13 +0000
459+++ hooks/client-relation-changed 2016-11-23 22:25:27 +0000
460@@ -1,6 +1,9 @@
461 #!/usr/bin/python
462
463+import json
464 import os
465+import shlex
466+import subprocess
467 import sys
468
469 sys.path.insert(0, os.path.join(os.environ['CHARM_DIR'], 'lib'))
470@@ -19,45 +22,26 @@
471 BASEPATH = os.path.join(os.path.sep, 'opt', 'logstash')
472
473
474-@hooks.hook('client-relation-changed')
475+@hooks.hook('client-relation-changed', 'client-relation-departed')
476 def rest_changed():
477- cache_hosts()
478 write_config()
479 host.service_restart(SERVICE) or host.service_start(SERVICE)
480
481
482 def write_config():
483- with open('host_cache', 'r') as f:
484- hosts = f.readlines()
485- if not hosts:
486- sys.exit(0)
487-
488- # Use last host in list as it will be the most recently added
489- # and first host in list may not exist anymore! TODO fix that.
490- opts = {'hosts': hosts[-1].rstrip()}
491-
492- out = os.path.join(BASEPATH, 'conf.d', 'output-elasticsearch.conf')
493- with open(out, 'w') as p:
494- p.write(render(os.path.basename(out), opts))
495-
496-
497-def cache_hosts():
498 rels = hookenv.relations_of_type("client")
499 if not rels:
500 log('No client relations. Assuming nothing to do.')
501 sys.exit(0)
502- if not os.path.exists('host_cache'):
503- open('host_cache', 'a').close()
504- for rel in rels:
505- host = rel.get('host')
506- if not host:
507- log('No host received for relation: {}.'.format(rel))
508- continue
509- with open('host_cache', 'r') as f:
510- hosts = f.readlines()
511- if host not in hosts:
512- with open('host_cache', 'a') as f:
513- f.write('{}\n'.format(host))
514+ hosts = json.dumps(
515+ ["%s:%s" % (client['host'], client['port']) for client in rels
516+ if 'host' in client])
517+
518+ out = os.path.join(BASEPATH, 'conf.d', 'output-elasticsearch.conf')
519+ with open(out, 'w') as p:
520+ p.write(render(os.path.basename(out), dict(hosts=hosts)))
521+ # update nrpe now that we have client relations
522+ subprocess.check_output(shlex.split('hooks/nrpe-external-master-relation-changed'))
523
524
525 if __name__ == "__main__":
526
527=== added symlink 'hooks/client-relation-departed'
528=== target is u'client-relation-changed'
529=== modified file 'hooks/config-changed'
530--- hooks/config-changed 2015-09-08 19:05:34 +0000
531+++ hooks/config-changed 2016-11-23 22:25:27 +0000
532@@ -38,15 +38,20 @@
533
534 # This only actually opens the port if we've exposed the service in juju
535 hookenv.open_port(5043)
536- hookenv.open_port(5959, protocol='UDP')
537- hookenv.open_port(5959, protocol='TCP')
538-
539- # The install hook is idempotent, so re-run it.
540- # XXX: no, it's not idempotent. it fails if the tarball was already
541- # extracted
542- # subprocess.check_output(shlex.split('hooks/install'))
543-
544- # Restart the service when configuration has changed.
545+
546+ # Verify the config to get a decent error message for bad configuration.
547+ try:
548+ subprocess.check_output([
549+ '/opt/logstash/bin/logstash', 'agent', '-f',
550+ '/opt/logstash/conf.d/', '--configtest'
551+ ])
552+ except subprocess.CalledProcessError, e:
553+ # The exception doesn't print the output, by default.
554+ print(e.output)
555+ raise
556+
557+ # Restart the service when configuration has changed
558+ # and the config is valid.
559 subprocess.check_output(shlex.split('hooks/start'))
560
561 subprocess.check_output(shlex.split('hooks/nrpe-external-master-relation-changed'))
562@@ -61,6 +66,8 @@
563 key_file = os.path.join(cert_dir, 'logstash.key')
564
565 for f in files:
566+ if not f.endswith(".conf"):
567+ continue
568 # skip output-elasticsearch.conf, is managed by
569 # hooks/client-relation-changed
570 if os.path.basename(f) == "output-elasticsearch.conf":
571@@ -75,6 +82,12 @@
572 if config_data['extra-config']:
573 with open(os.path.join(BASEPATH, 'conf.d', 'extra.conf'), 'w') as f:
574 f.write(str(base64.b64decode(config_data['extra-config'])))
575+ if config_data['extra-patterns']:
576+ patterns_dir = os.path.join(BASEPATH, 'patterns')
577+ if not os.path.exists(patterns_dir):
578+ os.mkdir(patterns_dir)
579+ with open(os.path.join(patterns_dir, 'extra-patterns'), 'w') as f:
580+ f.write(str(base64.b64decode(config_data['extra-patterns'])))
581
582 # Only setup lumberjack protocol if ssl cert and key are configured
583 if config_data['ssl_cert'] and config_data['ssl_key']:
584@@ -100,7 +113,11 @@
585 def place_upstart_template():
586 out = os.path.join(os.path.sep, 'etc', 'init', '{}.conf'.format(SERVICE))
587 templ = os.path.join('files', 'upstart')
588- opts = {'BASEPATH': BASEPATH}
589+ config_data = hookenv.config()
590+ opts = {
591+ 'BASEPATH': BASEPATH,
592+ 'HEAP_SIZE': config_data['heap_size'],
593+ }
594
595 with open(out, 'w') as p:
596 p.write(render('{}.conf'.format(SERVICE), opts, template_dir=templ))
597
598=== modified file 'hooks/nrpe-external-master-relation-changed'
599--- hooks/nrpe-external-master-relation-changed 2015-09-29 19:43:29 +0000
600+++ hooks/nrpe-external-master-relation-changed 2016-11-23 22:25:27 +0000
601@@ -1,13 +1,14 @@
602 #!/usr/bin/python
603
604+import glob
605 import os
606+import shutil
607 import sys
608
609 sys.path.insert(0, os.path.join(os.environ['CHARM_DIR'], 'lib'))
610
611-from charmhelpers.core import hookenv
612+from charmhelpers.core import hookenv, templating
613 from charmhelpers.contrib.charmsupport import nrpe
614-from charmhelpers.contrib.charmsupport.nrpe import NRPE
615
616 hooks = hookenv.Hooks()
617 log = hookenv.log
618@@ -47,8 +48,21 @@
619 self.service_template = CustomIntervalCheck.service_template % intervals_config
620
621
622+def install_nrpe_scripts():
623+ # copy the scripts
624+ scripts_src = os.path.join(os.environ["CHARM_DIR"], "files",
625+ "nrpe")
626+ scripts_dst = "/usr/lib/nagios/plugins"
627+ if not os.path.exists(scripts_dst):
628+ os.makedirs(scripts_dst)
629+ for fname in glob.glob(os.path.join(scripts_src, "*.py")):
630+ shutil.copy2(fname,
631+ os.path.join(scripts_dst, os.path.basename(fname)))
632+
633+
634 @hooks.hook('nrpe-external-master-relation-changed')
635 def update_nrpe_checks():
636+ install_nrpe_scripts()
637 nrpe_compat = nrpe.NRPE()
638 conf = nrpe_compat.config
639 check_procs_params = conf.get('nagios_check_procs_params')
640@@ -60,6 +74,8 @@
641 )
642 check_tcp_params = conf.get('nagios_check_tcp_params')
643 check_cert_params = conf.get('nagios_check_cert_params')
644+ check_e2e_params = conf.get('nagios_check_e2e_params')
645+ check_e2e_cron = conf.get('nagios_check_e2e_cron')
646 config_data = hookenv.config()
647 # Only setup lumberjack protocol if ssl cert and key are configured
648 if config_data['ssl_cert'] and config_data['ssl_key']:
649@@ -79,6 +95,31 @@
650 retry_check_interval=120, # minutes
651 )
652 nrpe_compat.checks.append(cert_check)
653+ # add e2e check using lumberjack protocol
654+ rels = hookenv.relations_of_type("client")
655+ if rels and check_e2e_cron:
656+ # delete old check
657+ if os.path.exists('/etc/nagios/nrpe.d/check_e2e-check.cfg'):
658+ os.unlink('/etc/nagios/nrpe.d/check_e2e-check.cfg')
659+ es_ips = ','.join(["%s:%s" % (client['host'], client['port'])
660+ for client in rels if 'host' in client])
661+ e2e_output_file = "/var/lib/nagios/logstash-e2e-check.output"
662+ charm_dir = hookenv.charm_dir()
663+ # write cronjob to run e2e script every 5mins
664+ context = {'es_ips': es_ips,
665+ 'e2e_file': e2e_output_file,
666+ 'e2e_params': check_e2e_params,
667+ 'cron_expression': check_e2e_cron,
668+ 'charm_dir': charm_dir}
669+ templating.render('e2e-cron.tmpl', '/etc/cron.d/e2e-check',
670+ context=context, perms=0554)
671+ nrpe_compat.add_check(
672+ shortname='e2e_output',
673+ description='Check E2E script output',
674+ check_cmd='check_e2e_output.py -f {}'.format(e2e_output_file)
675+ )
676+ else:
677+ log('No client relations. Not adding e2e check.')
678
679 nrpe_compat.write()
680
681
682=== added file 'templates/e2e-cron.tmpl'
683--- templates/e2e-cron.tmpl 1970-01-01 00:00:00 +0000
684+++ templates/e2e-cron.tmpl 2016-11-23 22:25:27 +0000
685@@ -0,0 +1,4 @@
686+# Cron job to run e2e check
687+MAILTO=""
688+{{ cron_expression }} nagios run-this-one python3 {{ charm_dir }}/files/nrpe/check_lumberjack_e2e.py --es {{ es_ips }} -f {{ e2e_file }} {{ e2e_params }}
689+
690
691=== modified file 'templates/input-file-syslog.conf'
692--- templates/input-file-syslog.conf 2014-09-23 12:12:45 +0000
693+++ templates/input-file-syslog.conf 2016-11-23 22:25:27 +0000
694@@ -1,1 +1,1 @@
695-input { file { type => 'syslog' path => ['/var/log/syslog','/var/log/kern.log','/var/log/auth.log','/var/log/dpkg.log'] sincedb_path => '{{BASEPATH}}' } }
696\ No newline at end of file
697+input { file { type => 'syslog' path => ['/var/log/syslog','/var/log/kern.log','/var/log/auth.log','/var/log/dpkg.log'] } }
698
699=== removed file 'templates/input-python-logging.conf'
700--- templates/input-python-logging.conf 2015-06-30 16:42:53 +0000
701+++ templates/input-python-logging.conf 1970-01-01 00:00:00 +0000
702@@ -1,14 +0,0 @@
703-# Input for python-logstash [[https://pypi.python.org/pypi/python-logstash]]
704-# via udp:5959.
705-input {
706- udp {
707- # The port to listen on.
708- port => 5959
709-
710- # Receives plain JSON objects.
711- codec => "json"
712-
713- # Just an identifier, change it to whatever makes more sense.
714- type => "python-logstash"
715- }
716-}
717
718=== modified file 'templates/input-redis.conf'
719--- templates/input-redis.conf 2014-09-23 12:12:45 +0000
720+++ templates/input-redis.conf 2016-11-23 22:25:27 +0000
721@@ -1,1 +1,1 @@
722-input { redis { host => "127.0.0.1" data_type => "list" type => "redis" tags => ["redis"] key => "logstash" message_format => "json_event" } }
723\ No newline at end of file
724+input { redis { host => "127.0.0.1" data_type => "list" type => "redis" tags => ["redis"] key => "logstash" } }
725
726=== modified file 'templates/output-elasticsearch.conf'
727--- templates/output-elasticsearch.conf 2014-09-23 16:59:13 +0000
728+++ templates/output-elasticsearch.conf 2016-11-23 22:25:27 +0000
729@@ -1,5 +1,5 @@
730 output {
731- elasticsearch_http {
732- host => "{{hosts}}"
733+ elasticsearch {
734+ hosts => {{ hosts }}
735 }
736 }

Subscribers

People subscribed via source and target branches

to all changes: