Merge lp:~bigdata-dev/charms/trusty/apache-flume-syslog/trunk into lp:charms/trusty/apache-flume-syslog

Proposed by Kevin W Monroe
Status: Merged
Merged at revision: 2
Proposed branch: lp:~bigdata-dev/charms/trusty/apache-flume-syslog/trunk
Merge into: lp:charms/trusty/apache-flume-syslog
Diff against target: 1831 lines (+1704/-0) (has conflicts)
20 files modified
LICENSE (+177/-0)
README.md (+99/-0)
config.yaml (+35/-0)
copyright (+16/-0)
dist.yaml (+18/-0)
hooks/callbacks.py (+160/-0)
hooks/common.py (+91/-0)
hooks/config-changed (+15/-0)
hooks/flume-agent-relation-changed (+15/-0)
hooks/install (+17/-0)
hooks/setup.py (+33/-0)
hooks/start (+15/-0)
hooks/stop (+15/-0)
hooks/syslog-relation-changed (+15/-0)
icon.svg (+863/-0)
metadata.yaml (+13/-0)
resources.yaml (+12/-0)
templates/flume.conf.j2 (+28/-0)
tests/00-setup (+5/-0)
tests/remote/test_dist_config.py (+62/-0)
Conflict adding file LICENSE.  Moved existing file to LICENSE.moved.
Conflict adding file README.md.  Moved existing file to README.md.moved.
Conflict adding file config.yaml.  Moved existing file to config.yaml.moved.
Conflict adding file copyright.  Moved existing file to copyright.moved.
Conflict adding file dist.yaml.  Moved existing file to dist.yaml.moved.
Conflict adding file hooks.  Moved existing file to hooks.moved.
Conflict adding file icon.svg.  Moved existing file to icon.svg.moved.
Conflict adding file metadata.yaml.  Moved existing file to metadata.yaml.moved.
Conflict adding file resources.  Moved existing file to resources.moved.
Conflict adding file resources.yaml.  Moved existing file to resources.yaml.moved.
Conflict adding file templates.  Moved existing file to templates.moved.
Conflict adding file tests.  Moved existing file to tests.moved.
To merge this branch: bzr merge lp:~bigdata-dev/charms/trusty/apache-flume-syslog/trunk
Reviewer Review Type Date Requested Status
Kevin W Monroe Approve
Review via email: mp+268663@code.launchpad.net
To post a comment you must log in.
11. By Cory Johns

Fixed permissions on test_dist_config.py

Revision history for this message
Kevin W Monroe (kwmonroe) wrote :

Realtime syslog analytics bundle test looked good. Merged.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'LICENSE'
2--- LICENSE 1970-01-01 00:00:00 +0000
3+++ LICENSE 2015-08-21 21:55:32 +0000
4@@ -0,0 +1,177 @@
5+
6+ Apache License
7+ Version 2.0, January 2004
8+ http://www.apache.org/licenses/
9+
10+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
11+
12+ 1. Definitions.
13+
14+ "License" shall mean the terms and conditions for use, reproduction,
15+ and distribution as defined by Sections 1 through 9 of this document.
16+
17+ "Licensor" shall mean the copyright owner or entity authorized by
18+ the copyright owner that is granting the License.
19+
20+ "Legal Entity" shall mean the union of the acting entity and all
21+ other entities that control, are controlled by, or are under common
22+ control with that entity. For the purposes of this definition,
23+ "control" means (i) the power, direct or indirect, to cause the
24+ direction or management of such entity, whether by contract or
25+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
26+ outstanding shares, or (iii) beneficial ownership of such entity.
27+
28+ "You" (or "Your") shall mean an individual or Legal Entity
29+ exercising permissions granted by this License.
30+
31+ "Source" form shall mean the preferred form for making modifications,
32+ including but not limited to software source code, documentation
33+ source, and configuration files.
34+
35+ "Object" form shall mean any form resulting from mechanical
36+ transformation or translation of a Source form, including but
37+ not limited to compiled object code, generated documentation,
38+ and conversions to other media types.
39+
40+ "Work" shall mean the work of authorship, whether in Source or
41+ Object form, made available under the License, as indicated by a
42+ copyright notice that is included in or attached to the work
43+ (an example is provided in the Appendix below).
44+
45+ "Derivative Works" shall mean any work, whether in Source or Object
46+ form, that is based on (or derived from) the Work and for which the
47+ editorial revisions, annotations, elaborations, or other modifications
48+ represent, as a whole, an original work of authorship. For the purposes
49+ of this License, Derivative Works shall not include works that remain
50+ separable from, or merely link (or bind by name) to the interfaces of,
51+ the Work and Derivative Works thereof.
52+
53+ "Contribution" shall mean any work of authorship, including
54+ the original version of the Work and any modifications or additions
55+ to that Work or Derivative Works thereof, that is intentionally
56+ submitted to Licensor for inclusion in the Work by the copyright owner
57+ or by an individual or Legal Entity authorized to submit on behalf of
58+ the copyright owner. For the purposes of this definition, "submitted"
59+ means any form of electronic, verbal, or written communication sent
60+ to the Licensor or its representatives, including but not limited to
61+ communication on electronic mailing lists, source code control systems,
62+ and issue tracking systems that are managed by, or on behalf of, the
63+ Licensor for the purpose of discussing and improving the Work, but
64+ excluding communication that is conspicuously marked or otherwise
65+ designated in writing by the copyright owner as "Not a Contribution."
66+
67+ "Contributor" shall mean Licensor and any individual or Legal Entity
68+ on behalf of whom a Contribution has been received by Licensor and
69+ subsequently incorporated within the Work.
70+
71+ 2. Grant of Copyright License. Subject to the terms and conditions of
72+ this License, each Contributor hereby grants to You a perpetual,
73+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
74+ copyright license to reproduce, prepare Derivative Works of,
75+ publicly display, publicly perform, sublicense, and distribute the
76+ Work and such Derivative Works in Source or Object form.
77+
78+ 3. Grant of Patent License. Subject to the terms and conditions of
79+ this License, each Contributor hereby grants to You a perpetual,
80+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
81+ (except as stated in this section) patent license to make, have made,
82+ use, offer to sell, sell, import, and otherwise transfer the Work,
83+ where such license applies only to those patent claims licensable
84+ by such Contributor that are necessarily infringed by their
85+ Contribution(s) alone or by combination of their Contribution(s)
86+ with the Work to which such Contribution(s) was submitted. If You
87+ institute patent litigation against any entity (including a
88+ cross-claim or counterclaim in a lawsuit) alleging that the Work
89+ or a Contribution incorporated within the Work constitutes direct
90+ or contributory patent infringement, then any patent licenses
91+ granted to You under this License for that Work shall terminate
92+ as of the date such litigation is filed.
93+
94+ 4. Redistribution. You may reproduce and distribute copies of the
95+ Work or Derivative Works thereof in any medium, with or without
96+ modifications, and in Source or Object form, provided that You
97+ meet the following conditions:
98+
99+ (a) You must give any other recipients of the Work or
100+ Derivative Works a copy of this License; and
101+
102+ (b) You must cause any modified files to carry prominent notices
103+ stating that You changed the files; and
104+
105+ (c) You must retain, in the Source form of any Derivative Works
106+ that You distribute, all copyright, patent, trademark, and
107+ attribution notices from the Source form of the Work,
108+ excluding those notices that do not pertain to any part of
109+ the Derivative Works; and
110+
111+ (d) If the Work includes a "NOTICE" text file as part of its
112+ distribution, then any Derivative Works that You distribute must
113+ include a readable copy of the attribution notices contained
114+ within such NOTICE file, excluding those notices that do not
115+ pertain to any part of the Derivative Works, in at least one
116+ of the following places: within a NOTICE text file distributed
117+ as part of the Derivative Works; within the Source form or
118+ documentation, if provided along with the Derivative Works; or,
119+ within a display generated by the Derivative Works, if and
120+ wherever such third-party notices normally appear. The contents
121+ of the NOTICE file are for informational purposes only and
122+ do not modify the License. You may add Your own attribution
123+ notices within Derivative Works that You distribute, alongside
124+ or as an addendum to the NOTICE text from the Work, provided
125+ that such additional attribution notices cannot be construed
126+ as modifying the License.
127+
128+ You may add Your own copyright statement to Your modifications and
129+ may provide additional or different license terms and conditions
130+ for use, reproduction, or distribution of Your modifications, or
131+ for any such Derivative Works as a whole, provided Your use,
132+ reproduction, and distribution of the Work otherwise complies with
133+ the conditions stated in this License.
134+
135+ 5. Submission of Contributions. Unless You explicitly state otherwise,
136+ any Contribution intentionally submitted for inclusion in the Work
137+ by You to the Licensor shall be under the terms and conditions of
138+ this License, without any additional terms or conditions.
139+ Notwithstanding the above, nothing herein shall supersede or modify
140+ the terms of any separate license agreement you may have executed
141+ with Licensor regarding such Contributions.
142+
143+ 6. Trademarks. This License does not grant permission to use the trade
144+ names, trademarks, service marks, or product names of the Licensor,
145+ except as required for reasonable and customary use in describing the
146+ origin of the Work and reproducing the content of the NOTICE file.
147+
148+ 7. Disclaimer of Warranty. Unless required by applicable law or
149+ agreed to in writing, Licensor provides the Work (and each
150+ Contributor provides its Contributions) on an "AS IS" BASIS,
151+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
152+ implied, including, without limitation, any warranties or conditions
153+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
154+ PARTICULAR PURPOSE. You are solely responsible for determining the
155+ appropriateness of using or redistributing the Work and assume any
156+ risks associated with Your exercise of permissions under this License.
157+
158+ 8. Limitation of Liability. In no event and under no legal theory,
159+ whether in tort (including negligence), contract, or otherwise,
160+ unless required by applicable law (such as deliberate and grossly
161+ negligent acts) or agreed to in writing, shall any Contributor be
162+ liable to You for damages, including any direct, indirect, special,
163+ incidental, or consequential damages of any character arising as a
164+ result of this License or out of the use or inability to use the
165+ Work (including but not limited to damages for loss of goodwill,
166+ work stoppage, computer failure or malfunction, or any and all
167+ other commercial damages or losses), even if such Contributor
168+ has been advised of the possibility of such damages.
169+
170+ 9. Accepting Warranty or Additional Liability. While redistributing
171+ the Work or Derivative Works thereof, You may choose to offer,
172+ and charge a fee for, acceptance of support, warranty, indemnity,
173+ or other liability obligations and/or rights consistent with this
174+ License. However, in accepting such obligations, You may act only
175+ on Your own behalf and on Your sole responsibility, not on behalf
176+ of any other Contributor, and only if You agree to indemnify,
177+ defend, and hold each Contributor harmless for any liability
178+ incurred by, or claims asserted against, such Contributor by reason
179+ of your accepting any such warranty or additional liability.
180+
181+ END OF TERMS AND CONDITIONS
182
183=== renamed file 'LICENSE' => 'LICENSE.moved'
184=== added file 'README.md'
185--- README.md 1970-01-01 00:00:00 +0000
186+++ README.md 2015-08-21 21:55:32 +0000
187@@ -0,0 +1,99 @@
188+## Overview
189+
190+Flume is a distributed, reliable, and available service for efficiently
191+collecting, aggregating, and moving large amounts of log data. It has a simple
192+and flexible architecture based on streaming data flows. It is robust and fault
193+tolerant with tunable reliability mechanisms and many failover and recovery
194+mechanisms. It uses a simple extensible data model that allows for online
195+analytic application. Learn more at [flume.apache.org](http://flume.apache.org).
196+
197+This charm provides a Flume agent designed to receive remote syslog events and
198+send them to the `apache-flume-hdfs` agent for storage into the shared
199+filesystem (HDFS) of a connected Hadoop cluster. Think of this charm as a
200+replacement for `rsyslog`, sending syslog events to HDFS instead of writing
201+them to a local filesystem.
202+
203+
204+## Usage
205+
206+This charm leverages our pluggable Hadoop model with the `hadoop-plugin`
207+interface. This means that you will need to deploy a base Apache Hadoop cluster
208+to run Flume. The suggested deployment method is to use the
209+[apache-ingestion-flume](https://jujucharms.com/u/bigdata-dev/apache-ingestion-flume/)
210+bundle. This will deploy the Apache Hadoop platform with a single Apache Flume
211+unit that communicates with the cluster by relating to the
212+`apache-hadoop-plugin` subordinate charm:
213+
214+ juju quickstart u/bigdata-dev/apache-ingestion-flume
215+
216+Alternatively, you may manually deploy the recommended environment as follows:
217+
218+ juju deploy apache-hadoop-hdfs-master hdfs-master
219+ juju deploy apache-hadoop-yarn-master yarn-master
220+ juju deploy apache-hadoop-compute-slave compute-slave
221+ juju deploy apache-hadoop-plugin plugin
222+ juju deploy apache-flume-hdfs flume-hdfs
223+
224+ juju add-relation yarn-master hdfs-master
225+ juju add-relation compute-slave yarn-master
226+ juju add-relation compute-slave hdfs-master
227+ juju add-relation plugin yarn-master
228+ juju add-relation plugin hdfs-master
229+ juju add-relation flume-hdfs plugin
230+
231+Once the bundle has been deployed, add the `apache-flume-syslog` charm and
232+relate it to the `flume-hdfs` agent:
233+
234+ juju deploy apache-flume-syslog flume-syslog
235+ juju add-relation flume-syslog flume-hdfs
236+
237+You are now ready to ingest remote syslog events! Note the deployment at this
238+stage isn't very useful. You'll need to relate this charm to any other service
239+that is configured to send data via the `syslog` interface.
240+
241+As an example, let's ingest our `hdfs-master` syslog events into HDFS. Deploy
242+the `rsyslog-forwarder-ha` subordinate charm, relate it to `hdfs-master`, and
243+then link the `syslog` interfaces:
244+
245+ juju deploy rsyslog-forwarder-ha
246+ juju add-relation rsyslog-forwarder-ha hdfs-master
247+ juju add-relation rsyslog-forwarder-ha flume-syslog
248+
249+Any syslog data generated on the `hdfs-master` unit will now be ingested into
250+HDFS via the `flume-syslog` and `flume-hdfs` charms. These events will be stored
251+by year-month-day/hour here: `/user/flume/flume-syslog/%y-%m-%d/%H`.
252+
253+
254+## Test the deployment
255+
256+To verify this charm is working as intended, trigger a syslog event on the
257+monitored unit (`hdfs-master` in our deployment scenario):
258+
259+ juju ssh hdfs-master
260+ exit
261+
262+Now SSH to the `flume-hdfs` unit, locate the event, and cat it:
263+
264+ juju ssh flume-hdfs/0
265+ hdfs dfs -ls /user/flume/flume-syslog # <-- find a date
266+ hdfs dfs -ls /user/flume/flume-syslog/yy-mm-dd # <-- find an hour
267+ hdfs dfs -ls /user/flume/flume-syslog/yy-mm-dd/HH # <-- find an event
268+ hdfs dfs -cat /user/flume/flume-syslog/yy-mm-dd/HH/FlumeData.<id>
269+
270+You should be able to find a timestamped message about SSH'ing into the
271+`hdfs-master` unit that corresponds to the trigger you issued above. Note that
272+this deployment isn't limited to ssh-related events. You'll get every syslog
273+event from the `hdfs-master` unit. Happy logging!
274+
275+
276+## Contact Information
277+
278+- <bigdata-dev@lists.launchpad.net>
279+
280+
281+## Help
282+
283+- [Apache Flume home page](http://flume.apache.org/)
284+- [Apache Flume bug tracker](https://issues.apache.org/jira/browse/flume)
285+- [Apache Flume mailing lists](https://flume.apache.org/mailinglists.html)
286+- `#juju` on `irc.freenode.net`
287
288=== renamed file 'README.md' => 'README.md.moved'
289=== added file 'config.yaml'
290--- config.yaml 1970-01-01 00:00:00 +0000
291+++ config.yaml 2015-08-21 21:55:32 +0000
292@@ -0,0 +1,35 @@
293+options:
294+ resources_mirror:
295+ type: string
296+ default: ''
297+ description: |
298+ URL from which to fetch resources (e.g., Hadoop binaries) instead
299+ of Launchpad.
300+ channel_capacity:
301+ type: string
302+ default: '1000'
303+ description: |
304+ The maximum number of events stored in the channel.
305+ channel_transaction_capacity:
306+ type: string
307+ default: '100'
308+ description: |
309+ The maximum number of events the channel will take from a source or
310+ give to a sink per transaction.
311+ event_dir:
312+ type: string
313+ default: 'flume-syslog'
314+ description: |
315+ The HDFS subdirectory under /user/flume where events will be stored.
316+ source_port:
317+ type: string
318+ default: '514'
319+ description: |
320+ Port on which the agent source is listening. If relating to the
321+ 'rsyslog-forwarder-ha' charm, this must be '514'.
322+ source_type:
323+ type: string
324+ default: 'syslogudp'
325+ description: |
326+ Agent source type. Can be 'syslogudp' or 'syslogtcp'. If
327+ relating to the 'rsyslog-forwarder-ha' charm, this must be 'syslogudp'.
328
329=== renamed file 'config.yaml' => 'config.yaml.moved'
330=== added file 'copyright'
331--- copyright 1970-01-01 00:00:00 +0000
332+++ copyright 2015-08-21 21:55:32 +0000
333@@ -0,0 +1,16 @@
334+Format: http://dep.debian.net/deps/dep5/
335+
336+Files: *
337+Copyright: Copyright 2015, Canonical Ltd., All Rights Reserved.
338+License: Apache License 2.0
339+ Licensed under the Apache License, Version 2.0 (the "License");
340+ you may not use this file except in compliance with the License.
341+ You may obtain a copy of the License at
342+ .
343+ http://www.apache.org/licenses/LICENSE-2.0
344+ .
345+ Unless required by applicable law or agreed to in writing, software
346+ distributed under the License is distributed on an "AS IS" BASIS,
347+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
348+ See the License for the specific language governing permissions and
349+ limitations under the License.
350
351=== renamed file 'copyright' => 'copyright.moved'
352=== added file 'dist.yaml'
353--- dist.yaml 1970-01-01 00:00:00 +0000
354+++ dist.yaml 2015-08-21 21:55:32 +0000
355@@ -0,0 +1,18 @@
356+# This file contains values that are likely to change per distribution.
357+# The aim is to make it easier to update / extend the charms with
358+# minimal changes to the shared code in charmhelpers.
359+packages:
360+ - 'openjdk-7-jre'
361+groups:
362+ - 'hadoop'
363+users:
364+ flume:
365+ groups: ['hadoop']
366+dirs:
367+ flume:
368+ path: '/usr/lib/flume-syslog'
369+ flume_conf:
370+ path: '/etc/flume-syslog/conf'
371+ flume_logs:
372+ path: '/var/log/flume-syslog'
373+ owner: 'flume'
374
375=== renamed file 'dist.yaml' => 'dist.yaml.moved'
376=== added directory 'hooks'
377=== renamed directory 'hooks' => 'hooks.moved'
378=== added file 'hooks/callbacks.py'
379--- hooks/callbacks.py 1970-01-01 00:00:00 +0000
380+++ hooks/callbacks.py 2015-08-21 21:55:32 +0000
381@@ -0,0 +1,160 @@
382+import os
383+import re
384+import signal
385+from subprocess import Popen, check_output
386+
387+import jujuresources
388+from charmhelpers.core import hookenv
389+from charmhelpers.core import host
390+from charmhelpers.core import unitdata
391+from charmhelpers.core.charmframework.helpers import Relation
392+from jujubigdata import utils
393+from jujubigdata.relations import FlumeAgent
394+
395+
396+# Extended status support
397+# We call update_blocked_status from the "requires" section of our service
398+# block, so be sure to return True. Otherwise, we'll block the "requires"
399+# and never move on to callbacks. The other status update methods are called
400+# from the "callbacks" section and therefore don't need to return True.
401+def update_blocked_status():
402+ if unitdata.kv().get('charm.active', False):
403+ return True
404+ if not FlumeAgent().connected_units():
405+ hookenv.status_set('blocked', 'Waiting for relation to apache-flume-hdfs')
406+ elif not FlumeAgent().is_ready():
407+ hookenv.status_set('waiting', 'Waiting for Flume/HDFS to become ready')
408+ return True
409+
410+
411+def update_working_status():
412+ if unitdata.kv().get('charm.active', False):
413+ hookenv.status_set('maintenance', 'Updating configuration')
414+ return
415+ hookenv.status_set('maintenance', 'Setting up Flume/Syslog')
416+
417+
418+def update_active_status():
419+ unitdata.kv().set('charm.active', True)
420+ hookenv.status_set('active', 'Ready')
421+
422+
423+# Main Flume Syslog class for callbacks
424+class Flume(object):
425+ def __init__(self, dist_config):
426+ self.dist_config = dist_config
427+ self.resources = {
428+ 'flume': 'flume-%s' % host.cpu_arch(),
429+ }
430+ self.verify_resources = utils.verify_resources(*self.resources.values())
431+
432+ def is_installed(self):
433+ return unitdata.kv().get('flume.installed')
434+
435+ def install(self, force=False):
436+ if not force and self.is_installed():
437+ return
438+ jujuresources.install(self.resources['flume'],
439+ destination=self.dist_config.path('flume'),
440+ skip_top_level=True)
441+ self.dist_config.add_users()
442+ self.dist_config.add_dirs()
443+ self.dist_config.add_packages()
444+ self.setup_flume_config()
445+ self.configure_flume()
446+ unitdata.kv().set('flume.installed', True)
447+
448+ def setup_flume_config(self):
449+ '''
450+ copy the default configuration files to flume_conf property
451+ defined in dist.yaml
452+ '''
453+ default_conf = self.dist_config.path('flume') / 'conf'
454+ flume_conf = self.dist_config.path('flume_conf')
455+ flume_conf.rmtree_p()
456+ default_conf.copytree(flume_conf)
457+ # Now remove the conf included in the tarball and symlink our real conf
458+ default_conf.rmtree_p()
459+ flume_conf.symlink(default_conf)
460+
461+ flume_env = self.dist_config.path('flume_conf') / 'flume-env.sh'
462+ if not flume_env.exists():
463+ (self.dist_config.path('flume_conf') / 'flume-env.sh.template').copy(flume_env)
464+
465+ flume_conf = self.dist_config.path('flume_conf') / 'flume.conf'
466+ if not flume_conf.exists():
467+ (self.dist_config.path('flume_conf') / 'flume-conf.properties.template').copy(flume_conf)
468+
469+ flume_log4j = self.dist_config.path('flume_conf') / 'log4j.properties'
470+ utils.re_edit_in_place(flume_log4j, {
471+ r'^flume.log.dir.*': 'flume.log.dir={}'.format(self.dist_config.path('flume_logs')),
472+ })
473+
474+ def configure_flume(self):
475+ flume_bin = self.dist_config.path('flume') / 'bin'
476+ java_symlink = check_output(["readlink", "-f", "/usr/bin/java"])
477+ java_home = re.sub('/bin/java', '', java_symlink).rstrip()
478+ with utils.environment_edit_in_place('/etc/environment') as env:
479+ if flume_bin not in env['PATH']:
480+ env['PATH'] = ':'.join([env['PATH'], flume_bin])
481+ env['FLUME_CONF_DIR'] = self.dist_config.path('flume_conf')
482+ env['FLUME_CLASSPATH'] = self.dist_config.path('flume') / 'lib'
483+ env['FLUME_HOME'] = self.dist_config.path('flume')
484+ env['JAVA_HOME'] = java_home
485+
486+ def run_bg(self, user, command, *args):
487+ """
488+ Run a command as the given user in the background.
489+
490+ :param str user: User to run flume agent
491+ :param str command: Command to run
492+ :param list args: Additional args to pass to the command
493+ """
494+ parts = [command] + list(args)
495+ quoted = ' '.join("'%s'" % p for p in parts)
496+ e = utils.read_etc_env()
497+ Popen(['su', user, '-c', quoted], env=e)
498+
499+ def restart(self):
500+ # check for a java process with our flume dir in the classpath
501+ if utils.jps(r'-cp .*{}'.format(self.dist_config.path('flume'))):
502+ self.stop()
503+ self.start()
504+
505+ def start(self):
506+ # syslogudp needs to be run as root
507+ self.run_bg(
508+ 'root',
509+ self.dist_config.path('flume') / 'bin/flume-ng',
510+ 'agent',
511+ '-c', self.dist_config.path('flume_conf'),
512+ '-f', self.dist_config.path('flume_conf') / 'flume.conf',
513+ '-n', 'a1')
514+
515+ def stop(self):
516+ flume_pids = utils.jps(r'-cp .*{}'.format(self.dist_config.path('flume')))
517+ for pid in flume_pids:
518+ os.kill(int(pid), signal.SIGKILL)
519+
520+ def cleanup(self):
521+ self.dist_config.remove_users()
522+ self.dist_config.remove_dirs()
523+
524+
525+class FlumeSyslog(Relation):
526+ """
527+ Relation which communicates ip / port data to syslog-related units.
528+ """
529+ relation_name = 'syslog'
530+ required_keys = ['private-address', 'port']
531+
532+ def __init__(self, port=None, *args, **kwargs):
533+ self.port = port # only needed for provides
534+ super(FlumeSyslog, self).__init__(*args, **kwargs)
535+
536+ def provide(self, remote_service, all_ready):
537+ data = super(FlumeSyslog, self).provide(remote_service, all_ready)
538+ data.update({
539+ 'port': self.port,
540+ })
541+ return data
542
543=== added file 'hooks/common.py'
544--- hooks/common.py 1970-01-01 00:00:00 +0000
545+++ hooks/common.py 2015-08-21 21:55:32 +0000
546@@ -0,0 +1,91 @@
547+#!/usr/bin/env python
548+# Licensed under the Apache License, Version 2.0 (the "License");
549+# you may not use this file except in compliance with the License.
550+# You may obtain a copy of the License at
551+#
552+# http://www.apache.org/licenses/LICENSE-2.0
553+#
554+# Unless required by applicable law or agreed to in writing, software
555+# distributed under the License is distributed on an "AS IS" BASIS,
556+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
557+# See the License for the specific language governing permissions and
558+# limitations under the License.
559+"""
560+Common implementation for all hooks.
561+"""
562+
563+import jujuresources
564+from charmhelpers.core import hookenv
565+from charmhelpers.core import unitdata
566+from charmhelpers.core import charmframework
567+
568+
569+def bootstrap_resources():
570+ """
571+ Install required resources defined in resources.yaml
572+ """
573+ if unitdata.kv().get('charm.bootstrapped', False):
574+ return True
575+ hookenv.status_set('maintenance', 'Installing base resources')
576+ mirror_url = jujuresources.config_get('resources_mirror')
577+ if not jujuresources.fetch(mirror_url=mirror_url):
578+ missing = jujuresources.invalid()
579+ hookenv.status_set('blocked', 'Unable to fetch required resource%s: %s' % (
580+ 's' if len(missing) > 1 else '',
581+ ', '.join(missing),
582+ ))
583+ return False
584+ jujuresources.install(['pathlib', 'jujubigdata'])
585+ unitdata.kv().set('charm.bootstrapped', True)
586+ return True
587+
588+
589+def manage():
590+ if not bootstrap_resources():
591+ # defer until resources are available, since charmhelpers, and thus
592+ # the framework, are required (will require manual intervention)
593+ return
594+
595+ import jujubigdata
596+ import callbacks
597+
598+ flume_reqs = ['packages', 'groups', 'users', 'dirs']
599+ dist_config = jujubigdata.utils.DistConfig(filename='dist.yaml',
600+ required_keys=flume_reqs)
601+ flume = callbacks.Flume(dist_config)
602+ manager = charmframework.Manager([
603+ {
604+ 'name': 'flume',
605+ 'provides': [
606+ # port is hard-coded to 514 because that's what rsyslog-forwarder
607+ # expects. Make this a config opt once rsyslog-fwd supports
608+ # changing this.
609+ callbacks.FlumeSyslog(port='514'),
610+ ],
611+ 'requires': [
612+ flume.verify_resources,
613+ jujubigdata.relations.FlumeAgent(),
614+ callbacks.update_blocked_status, # not really a requirement, but best way to fit into framework
615+ ],
616+ 'callbacks': [
617+ callbacks.update_working_status,
618+ flume.install,
619+ charmframework.helpers.render_template(
620+ source='flume.conf.j2',
621+ target=flume.dist_config.path('flume_conf') / 'flume.conf',
622+ context={'dist_config': dist_config}
623+ ),
624+ flume.restart,
625+ callbacks.update_active_status,
626+ ],
627+ 'cleanup': [
628+ flume.stop,
629+ flume.cleanup,
630+ ],
631+ },
632+ ])
633+ manager.manage()
634+
635+
636+if __name__ == '__main__':
637+ manage()
638
639=== added file 'hooks/config-changed'
640--- hooks/config-changed 1970-01-01 00:00:00 +0000
641+++ hooks/config-changed 2015-08-21 21:55:32 +0000
642@@ -0,0 +1,15 @@
643+#!/usr/bin/env python
644+# Licensed under the Apache License, Version 2.0 (the "License");
645+# you may not use this file except in compliance with the License.
646+# You may obtain a copy of the License at
647+#
648+# http://www.apache.org/licenses/LICENSE-2.0
649+#
650+# Unless required by applicable law or agreed to in writing, software
651+# distributed under the License is distributed on an "AS IS" BASIS,
652+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
653+# See the License for the specific language governing permissions and
654+# limitations under the License.
655+
656+import common
657+common.manage()
658
659=== added file 'hooks/flume-agent-relation-changed'
660--- hooks/flume-agent-relation-changed 1970-01-01 00:00:00 +0000
661+++ hooks/flume-agent-relation-changed 2015-08-21 21:55:32 +0000
662@@ -0,0 +1,15 @@
663+#!/usr/bin/env python
664+# Licensed under the Apache License, Version 2.0 (the "License");
665+# you may not use this file except in compliance with the License.
666+# You may obtain a copy of the License at
667+#
668+# http://www.apache.org/licenses/LICENSE-2.0
669+#
670+# Unless required by applicable law or agreed to in writing, software
671+# distributed under the License is distributed on an "AS IS" BASIS,
672+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
673+# See the License for the specific language governing permissions and
674+# limitations under the License.
675+
676+import common
677+common.manage()
678
679=== added file 'hooks/install'
680--- hooks/install 1970-01-01 00:00:00 +0000
681+++ hooks/install 2015-08-21 21:55:32 +0000
682@@ -0,0 +1,17 @@
683+#!/usr/bin/python
684+# Licensed under the Apache License, Version 2.0 (the "License");
685+# you may not use this file except in compliance with the License.
686+# You may obtain a copy of the License at
687+#
688+# http://www.apache.org/licenses/LICENSE-2.0
689+#
690+# Unless required by applicable law or agreed to in writing, software
691+# distributed under the License is distributed on an "AS IS" BASIS,
692+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
693+# See the License for the specific language governing permissions and
694+# limitations under the License.
695+import setup
696+setup.pre_install()
697+
698+import common
699+common.manage()
700
701=== added file 'hooks/setup.py'
702--- hooks/setup.py 1970-01-01 00:00:00 +0000
703+++ hooks/setup.py 2015-08-21 21:55:32 +0000
704@@ -0,0 +1,33 @@
705+# Licensed under the Apache License, Version 2.0 (the "License");
706+# you may not use this file except in compliance with the License.
707+# You may obtain a copy of the License at
708+#
709+# http://www.apache.org/licenses/LICENSE-2.0
710+#
711+# Unless required by applicable law or agreed to in writing, software
712+# distributed under the License is distributed on an "AS IS" BASIS,
713+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
714+# See the License for the specific language governing permissions and
715+# limitations under the License.
716+import subprocess
717+from glob import glob
718+
719+
720+def pre_install():
721+ """
722+ Do any setup required before the install hook.
723+ """
724+ install_pip()
725+ install_bundled_resources()
726+
727+
728+def install_pip():
729+ subprocess.check_call(['apt-get', 'install', '-yq', 'python-pip', 'bzr'])
730+
731+
732+def install_bundled_resources():
733+ """
734+ Install the bundled resources libraries.
735+ """
736+ archives = glob('resources/python/*')
737+ subprocess.check_call(['pip', 'install'] + archives)
738
739=== added file 'hooks/start'
740--- hooks/start 1970-01-01 00:00:00 +0000
741+++ hooks/start 2015-08-21 21:55:32 +0000
742@@ -0,0 +1,15 @@
743+#!/usr/bin/env python
744+# Licensed under the Apache License, Version 2.0 (the "License");
745+# you may not use this file except in compliance with the License.
746+# You may obtain a copy of the License at
747+#
748+# http://www.apache.org/licenses/LICENSE-2.0
749+#
750+# Unless required by applicable law or agreed to in writing, software
751+# distributed under the License is distributed on an "AS IS" BASIS,
752+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
753+# See the License for the specific language governing permissions and
754+# limitations under the License.
755+
756+import common
757+common.manage()
758
759=== added file 'hooks/stop'
760--- hooks/stop 1970-01-01 00:00:00 +0000
761+++ hooks/stop 2015-08-21 21:55:32 +0000
762@@ -0,0 +1,15 @@
763+#!/usr/bin/env python
764+# Licensed under the Apache License, Version 2.0 (the "License");
765+# you may not use this file except in compliance with the License.
766+# You may obtain a copy of the License at
767+#
768+# http://www.apache.org/licenses/LICENSE-2.0
769+#
770+# Unless required by applicable law or agreed to in writing, software
771+# distributed under the License is distributed on an "AS IS" BASIS,
772+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
773+# See the License for the specific language governing permissions and
774+# limitations under the License.
775+
776+import common
777+common.manage()
778
779=== added file 'hooks/syslog-relation-changed'
780--- hooks/syslog-relation-changed 1970-01-01 00:00:00 +0000
781+++ hooks/syslog-relation-changed 2015-08-21 21:55:32 +0000
782@@ -0,0 +1,15 @@
783+#!/usr/bin/env python
784+# Licensed under the Apache License, Version 2.0 (the "License");
785+# you may not use this file except in compliance with the License.
786+# You may obtain a copy of the License at
787+#
788+# http://www.apache.org/licenses/LICENSE-2.0
789+#
790+# Unless required by applicable law or agreed to in writing, software
791+# distributed under the License is distributed on an "AS IS" BASIS,
792+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
793+# See the License for the specific language governing permissions and
794+# limitations under the License.
795+
796+import common
797+common.manage()
798
799=== added file 'icon.svg'
800--- icon.svg 1970-01-01 00:00:00 +0000
801+++ icon.svg 2015-08-21 21:55:32 +0000
802@@ -0,0 +1,863 @@
803+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
804+<!-- Created with Inkscape (http://www.inkscape.org/) -->
805+
806+<svg
807+ xmlns:dc="http://purl.org/dc/elements/1.1/"
808+ xmlns:cc="http://creativecommons.org/ns#"
809+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
810+ xmlns:svg="http://www.w3.org/2000/svg"
811+ xmlns="http://www.w3.org/2000/svg"
812+ xmlns:xlink="http://www.w3.org/1999/xlink"
813+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
814+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
815+ width="96"
816+ height="96"
817+ id="svg6517"
818+ version="1.1"
819+ inkscape:version="0.48.4 r9939"
820+ sodipodi:docname="icon-template.svg">
821+ <defs
822+ id="defs6519">
823+ <linearGradient
824+ id="Background">
825+ <stop
826+ id="stop4178"
827+ offset="0"
828+ style="stop-color:#b8b8b8;stop-opacity:1" />
829+ <stop
830+ id="stop4180"
831+ offset="1"
832+ style="stop-color:#c9c9c9;stop-opacity:1" />
833+ </linearGradient>
834+ <filter
835+ style="color-interpolation-filters:sRGB;"
836+ inkscape:label="Inner Shadow"
837+ id="filter1121">
838+ <feFlood
839+ flood-opacity="0.59999999999999998"
840+ flood-color="rgb(0,0,0)"
841+ result="flood"
842+ id="feFlood1123" />
843+ <feComposite
844+ in="flood"
845+ in2="SourceGraphic"
846+ operator="out"
847+ result="composite1"
848+ id="feComposite1125" />
849+ <feGaussianBlur
850+ in="composite1"
851+ stdDeviation="1"
852+ result="blur"
853+ id="feGaussianBlur1127" />
854+ <feOffset
855+ dx="0"
856+ dy="2"
857+ result="offset"
858+ id="feOffset1129" />
859+ <feComposite
860+ in="offset"
861+ in2="SourceGraphic"
862+ operator="atop"
863+ result="composite2"
864+ id="feComposite1131" />
865+ </filter>
866+ <filter
867+ style="color-interpolation-filters:sRGB;"
868+ inkscape:label="Drop Shadow"
869+ id="filter950">
870+ <feFlood
871+ flood-opacity="0.25"
872+ flood-color="rgb(0,0,0)"
873+ result="flood"
874+ id="feFlood952" />
875+ <feComposite
876+ in="flood"
877+ in2="SourceGraphic"
878+ operator="in"
879+ result="composite1"
880+ id="feComposite954" />
881+ <feGaussianBlur
882+ in="composite1"
883+ stdDeviation="1"
884+ result="blur"
885+ id="feGaussianBlur956" />
886+ <feOffset
887+ dx="0"
888+ dy="1"
889+ result="offset"
890+ id="feOffset958" />
891+ <feComposite
892+ in="SourceGraphic"
893+ in2="offset"
894+ operator="over"
895+ result="composite2"
896+ id="feComposite960" />
897+ </filter>
898+ <clipPath
899+ clipPathUnits="userSpaceOnUse"
900+ id="clipPath873">
901+ <g
902+ transform="matrix(0,-0.66666667,0.66604479,0,-258.25992,677.00001)"
903+ id="g875"
904+ inkscape:label="Layer 1"
905+ style="fill:#ff00ff;fill-opacity:1;stroke:none;display:inline">
906+ <path
907+ style="fill:#ff00ff;fill-opacity:1;stroke:none;display:inline"
908+ d="m 46.702703,898.22775 50.594594,0 C 138.16216,898.22775 144,904.06497 144,944.92583 l 0,50.73846 c 0,40.86071 -5.83784,46.69791 -46.702703,46.69791 l -50.594594,0 C 5.8378378,1042.3622 0,1036.525 0,995.66429 L 0,944.92583 C 0,904.06497 5.8378378,898.22775 46.702703,898.22775 Z"
909+ id="path877"
910+ inkscape:connector-curvature="0"
911+ sodipodi:nodetypes="sssssssss" />
912+ </g>
913+ </clipPath>
914+ <filter
915+ inkscape:collect="always"
916+ id="filter891"
917+ inkscape:label="Badge Shadow">
918+ <feGaussianBlur
919+ inkscape:collect="always"
920+ stdDeviation="0.71999962"
921+ id="feGaussianBlur893" />
922+ </filter>
923+ </defs>
924+ <sodipodi:namedview
925+ id="base"
926+ pagecolor="#ffffff"
927+ bordercolor="#666666"
928+ borderopacity="1.0"
929+ inkscape:pageopacity="0.0"
930+ inkscape:pageshadow="2"
931+ inkscape:zoom="3.4719894"
932+ inkscape:cx="18.514671"
933+ inkscape:cy="49.018169"
934+ inkscape:document-units="px"
935+ inkscape:current-layer="layer1"
936+ showgrid="false"
937+ fit-margin-top="0"
938+ fit-margin-left="0"
939+ fit-margin-right="0"
940+ fit-margin-bottom="0"
941+ inkscape:window-width="1366"
942+ inkscape:window-height="744"
943+ inkscape:window-x="0"
944+ inkscape:window-y="24"
945+ inkscape:window-maximized="1"
946+ showborder="true"
947+ showguides="true"
948+ inkscape:guide-bbox="true"
949+ inkscape:showpageshadow="false">
950+ <inkscape:grid
951+ type="xygrid"
952+ id="grid821" />
953+ <sodipodi:guide
954+ orientation="1,0"
955+ position="16,48"
956+ id="guide823" />
957+ <sodipodi:guide
958+ orientation="0,1"
959+ position="64,80"
960+ id="guide825" />
961+ <sodipodi:guide
962+ orientation="1,0"
963+ position="80,40"
964+ id="guide827" />
965+ <sodipodi:guide
966+ orientation="0,1"
967+ position="64,16"
968+ id="guide829" />
969+ </sodipodi:namedview>
970+ <metadata
971+ id="metadata6522">
972+ <rdf:RDF>
973+ <cc:Work
974+ rdf:about="">
975+ <dc:format>image/svg+xml</dc:format>
976+ <dc:type
977+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
978+ <dc:title></dc:title>
979+ </cc:Work>
980+ </rdf:RDF>
981+ </metadata>
982+ <g
983+ inkscape:label="BACKGROUND"
984+ inkscape:groupmode="layer"
985+ id="layer1"
986+ transform="translate(268,-635.29076)"
987+ style="display:inline">
988+ <path
989+ style="fill:#e6e6e6;fill-opacity:1;stroke:none;display:inline;filter:url(#filter1121)"
990+ d="m -268,700.15563 0,-33.72973 c 0,-27.24324 3.88785,-31.13513 31.10302,-31.13513 l 33.79408,0 c 27.21507,0 31.1029,3.89189 31.1029,31.13513 l 0,33.72973 c 0,27.24325 -3.88783,31.13514 -31.1029,31.13514 l -33.79408,0 C -264.11215,731.29077 -268,727.39888 -268,700.15563 Z"
991+ id="path6455"
992+ inkscape:connector-curvature="0"
993+ sodipodi:nodetypes="sssssssss" />
994+ <image
995+ y="651.29077"
996+ x="-252"
997+ id="image3185"
998+ xlink:href="data:image/png;base64,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
1058+whezv3RtIEiTZfeqAWF8ajpvCNIop5IpkKqEflsowt7tklxGIAHLypjbd1/786U9r32fSHBVX6QH
1059+58HfELye8M+j2ScZxxNEvtnQrRUtg7lixtSlo7BD573WI+b9g410UVLToBePvE9znCS4zy0724r5
1060+7Gds29oaZg9BujHo+mlttUp1rdaXXijmMQwDy7IYKhfSdWVjvbSfAsAkAJw2huKy0hMBSe4bAzhS
1061+AYJLyVmrSPwn+0wlpVbAhxMqggrUgH07FIenBG1Hx87mstt27f+o57oLK8ce/UIYcKKkRKiEoz/J
1062+KSNnfswxZeJayFmTLqorQeZGIL20RZ/mwCmOcImY0TT3SBtiyXvPLztDOTvzh8V89obgdnJZScbe
1063+WNwvL67QaLQAcF0Xr7FGu14lpztkcDCJJyyk0lglA0DbFQjdIJMvUS4VMAsjjG2ZJGOZl2E8JUHa
1064+k94H0kGctPdaGqS+YRbfIwOQxvUJ3FYqbFevvhqCWjFUggM7FS+cFjgeFEqVysSWHR9z3deeXzn2
1065+6KFeV1MyrjROSxpQ4Rqu2OCK1YD4Jf1uaaAZooQEPdCRZMwFIBDzUqY7KtlhasCAhCKrF6Qy6f+D
1066+5CI7pcAw9F8qFXJvCfNnM5KMvXEMwvHDx/FWp9GdKq7wuYJQCk8qTNMgn036rxS6psjRASCXUbRd
1067+QXVljeYyoNsszy0yuW8/wyPl+K4NQJruiTif4nI4aXJ6NsE5VU/pIacdwEl7uXdslMUgDR9dLiuu
1068+3QHPnvLLHJ7Yuqder/57b89d71458UQjmtdPhu4luGrSBeVf89NSHoDQ6r9C7qk+1qSURGoxSCPW
1069+HnSmEiIGIyQ6LH7LowEJMkTuiughwZsXnao+kJ5fcq4tFnL/VNc1A0DXJHZuY5AePXwKVk9TooFt
1070+6rhK0RUSL3jRWp6g2nZ6ah1VCICsaTBRyJIxdJRok22dYeb5b/Dct55hdaV6UZD2hiOC34dJTpq8
1071+azBI4xJ9wMkIZInCEzljdeFyQOrrrH5Q+viopFyIQb9157432bnizwoZW/3JCCsVzukH+qofBxAv
1072+u5Yp3TReVSCukI6qua6b6ugNRT1cVkje5UTe//e/nnlv1xVf/rkf3D5LSo/y81xY6g7l8/bXS4Xc
1073+DeA79AsFNTDIueu4nD05hVqZIkcrda3ueDQcL2DofuF506CSCzlrP4iCEaUrBC1XULF9obMu83i5
1074+TWzft4fR0WFgMEhD4ITt1hJASnsD/F+owqlkWgDwlN4ecq3kk1XsBXCF/xJqmoEQDhKJhq/He8IJ
1075+6qJFYllDo9kwOXRCsVST6Arc9vrK9Mnnf2T2+S8/oqRv4fdx0TAoJfCfp+b1VZrbhucnTp7qG7eX
1076+Smayk3tBeimD6VLheH38J+CirpDPbx4pPIiSd0XPDfMohW4Y/6qQy10XAiif2zgS/9TRE9i1M1h0
1077++66VMibFjEnXE3RcQUcIWp4g5xnYZm8sgAq4v5+Q0TX0jEG146BpoFQH0V7m8JNnKYzsYOe+PYyN
1078+D6d0sF6dPQRbeC0J0lh3j9NDMRmDO3xvfM4qpIem63heF0/4DKbrtVH44+N4vhqja3rgz/TQNA0N
1079+DSED3VxpaJrmc0kDJjeZvDit0ewqPCFGzbH9PzFxR+Xx2Sf/zE0aSr1xpingKqLZqvQ9V3ApiuN0
1080+X3Jgcyzmk6I+PL2YLhreK/nCU+uHHdebedf3jt4XD4rk3KJzw3Cl+Hg2Y1VQYBiSofJgkJ48fgaW
1081+jzNku2imjvQknuvvBhJHaMU1We+4NB2PjKkzmsskKpgUoSTQ66c3HY+m4+EIgRCKvKWj2yO4uQl2
1082+X7uPkbEKSincThsrm0txxKgvU/2V9IeGol6m6wJ40kVJQcdtopTCkw6ecNE0H3ixihGCQUbATrYl
1083+ehUSYis5HqfO6jz8TJTqKMXbgK/O/M1vq5iL9lr1MYBDoCaDUJKc9uzZswPH76WQueEUKAxeHkKs
1084+T/oVUnHygHn9QSAFWG90vnhw19gH//SrCx/5sTdu+lDYwFw283t2xqoo5UdC5VILSXxqNjucPTUF
1085+tQsUVYtOC3RDx7R08kNZdF2jXe/idNzUfXnL8AHnSRwhyRh6uu1pHSDStXOmQdYIxaik43l0OytU
1086+VJWjT57DymaQ3RqddpMbXvNmRrbuSPVCGqSqD6Qx1/X1wo7bQCqF67URSiTEfiBuE3WOQRrroS8F
1087+pADX7JI8d0pnoQZKkQH+LfCEkLIdTZ+GxlGfCyoB4N6/6kpOofYYCKHBNAikySnQ8C2KOiTSn8Jy
1088+0gbTx//6wnv/6KHzt4f91eq6/wvg4K6xD/7p3y58BODckvPOXM5+daiAZ22B2bO2aXFhhdPPfpNC
1089+7SRF1YjrLSROx8PteKAUuWIGM5N0aihMXcPQfD1tveNS6zjUui5N18MV8YAnQeofS/8FUxJTg4Jp
1090+0HRcZmttRHeFVnWOTrsBUnLkm39LbWkuqnM/SFUCoj7QPOnScRo0OuusNRdoO006bgNPeoRO/KQJ
1091+FZaXBGkI/ORLtxFIe12CKPjemxVGJLjUHaB+IjKMop8P2KTfNF4aHQa3pPfDulLxqFq75RsgF4sZ
1092+DYEY0kWXhjCIi/od+dnHVx4GqLec//lT92154JnTIrrtyNnlj973qvE3DxXzty7XXDYNW5TL9NGh
1093+J59i1JvduEE6lEbyQT0UrfV2EHbmX290PWpdJ6qzCixuTYOxnE3GiLle5NOM/sZpy60uja4bQ076
1094+wJBSYucKXHPHfYxuGo96JgZ9CFSFEA4tp4GUrj9/Hkkkmcrvp4XH4Rr/NEiTXPZSIE2RitOOntZ5
1095+9Pno+mngjlOf//BaiquqHuNqEDdFxdOqUjI7N7fheF0u6aHbCZmYfou6Nxy0OFLq4iBVaZDKgBMF
1096+3fbO147eB3Dj3omPP3NaqPML69+sNjpLSsHBnWMfXG/rNwFYhk4uO1hk6G5jYHrEVaTCc3xpoOka
1097+diGT4sjFjMGWYpaRXIZixkDTYvG11GzT9YQf9xCqKUmABZxNKkXO1CNRnIzJVErRadV58fG/4clH
1098+vs7iwkoEOhkAyPHatLo11lvLuF4HT3hRLyat/36QKtI4i8uNRuFyQRq9g/EzDuwVFELVXam9KPWL
1099+yS1/pEyubE2nx7GsYYxAHLN6JUhrNpopgCY3fthoCjTmDFGjUue9xlYykEWh+JOH59+bzZh3/73X
1100+j71PScmffGXhrbfs2/xFANPUKeQ09mw1yBf8zUx0LXb3Pvd3X2VYT06FqsRfX3YZpk62kMGwDFCK
1101+xlob4Yng+XFdAKodh0bXjax3S/edy37Qt8QVkoJlULbNYLBlyIqZb3QBSdsVkVGhZKxLbi1lqTNE
1102+x55g18H9jE2U6HoNPCkQwiUGXgzi5EsR9HTUb2m9NAZuZDy9FJAm0mJ3F5w5r/M334nuOwa89uj/
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
1163+Oq5HreOglKLa6aJpFpamYWoaZuDvkDKxgYOM3VZuu8HazAnW5s6i6/C82sff+9H/8yAVbova9GPk
1164+Jm4kO7T9ZZUxXim9ZC46CKAhlYuSxHcQDkbjHHBRpWk+SEO/NcmgyytDZlLUE0UKhRX2A2Cj0KSA
1165+Q4Uuh8jtdMlVj4pPPrJ8+w17N/+bkXI2MzFsMzW7jutJLEOP1islpDATI3kqQxkcCVlLp153OH56
1166+FaUUQ3kLISTbxrNMzXaQKCyxTuwXVWR1Dds2MfCXjSilWG12/TxBeF5G19hashMg9dO9Tpu1C8ep
1167+zp0G4KSzhbvf8pYrBtLmwnN01k5R2fv9GFY+Sm+tnGD95P9kaPJ2WnPfftlALRayrK+2GBr2/cIv
1168+F6BhWikHEfSU2qkpBXoQNKSFn1QK45nVd/lxpMGkpwym5HHoJ40qErgctHATA188hmFeobiMuGi0
1169++4lfbjZjvjGTsTJCKGqt2FoOVYDEZiEoFKalYw/nMA0N1RVcOLsW1aHadKm2XByhKBX8WRpduST9
1170+pv5aeD86fzRrBXUOdStf+e+4HivNbgzSoCLLZ56jOj+FlJIWWTbf8kbedd91AzvQbS8j3NbAaxtR
1171+e+kZMlmd6qm/AqBTO8/cUx+mu/Q4w7u/FyOTR8lLlyncFvULT/alv/HufTz20LeorbUvYizFIB3k
1172+U03+bFuRuGHc557S10lDXEQmXHwE2sDnvxzSk34wv5KJiJewIgnREW5/+Cdfmb/94UPtw595ovqR
1173+foMpXiclAxAXcvabAMYrNqsJPTTkolpCfZAKml1/Db2hadTXu7heaJ2DaWiMlmzytkmr46GLNpao
1174+xi9LWG9JAFadrKlF6UmXylrHoeV6/tIJz2H57AtU588ig2CKaWeMH37zjQM7T7gtlp/7L6y88Pt0
1175+auc37OTea8pdwcqV0bUGS89/nNqpT1PecRe54d1RHq+5cXnhs1cOP4BonWLtVPLLeIqt43l+5b1v
1176+4NBXD/Hw556k3XSi8dvQxdhznjzWDSLwKbAhca5iK78Xkv3fK3j5pCdBmZptGuTEjUSz5CfeOPH0
1177+hcXam/dOjnzgscPO2U/+7fLt4Q4aUSMSUSu5rLUfwDL9PU2zltHHRZNxrlsqWUoZnULGwPN8P2to
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
1328+8mIu1DHv6k+hxRV29MaZmygwX7Y4UnYordQ1mnB5WichCuxti9HTGWXbYIoMAqfzFm4AGztjnS9W
1329+7Qdl11ucYHVxTvaAm7ZL3/etie/XZsKmBhl83rI5oG/rZUPlWqCenSjTktIomQ6tLZn+MyULd7H1
1330+6eKDWUrIwg1FIqIqYgSwfn2GwryBoMr4gOV49bKVAMvx6WzRGJ2zyZcsZsomriTg1ydxiOihlakF
1331+cOTYHD88MUPBdjmaXxrSdmSiVJ0AARECGDd8Lu2MUHI8trREOZEziCY28NRzh3j/bRsJAp9Idjvl
1332+8X141hiyGiGS7sYXBUBAPAdhBUHG911EcbnlK7B25pNjG4iyTrLvmmXLfddElJcTbP74t6iRatxL
1333+1a+gRdtCz0DDsgtWVoisgu/6mNUarivhWHnk6OqeAqdmTGaFfrpjKgnH57/vbienCIzYLiBi1A2/
1334+jCLQ686Ri29hoCdJhXCurPe2aFy+LoHleuGEb5Nlpg0bQ1O5OiMS1xQ6YjInyi4/ma81pDWEumlE
1335+k6BNw02qTJsuXT1RfkkV+d+HFhAlBoAD8spZ15b7PpumZfE89h85/Zvrsi2/E48lt6uqRKXqIAkC
1336+PTGFeTNsYe4GYLg+qiwiClB1vJC0YqizarKEq8tYVmFkaKwcTaQyWaPm1GdzhlLNQSmK9LbGqNZs
1337+ZEGgqzfD1HSZeL1xbkSXcWyPH56YWfPhlG2Pj75tB3/0r6Fr6fdv2UyAi3osx7W72rguqSO6Ad6r
1338+42GZje/joxHpvBrf9zBzI+TGDpPq2oikSPhwTrKuJClApiVLdc7GE5an/fnIGLOHUVO9yFoapzrN
1339+3Inv4qISq0tm26rheyZFwyMQwincfS9A8G3UaCuLXgff91+TpIEXYBo1apUaIODZq6eQr9kB//yj
1340+IUq33YtleVy/s40xBWquhy4KmPWEHsXzcU8O8VLJINESh4rNuONzZVuUakrlR69Mk3Q8FuartCU0
1341+XMdnXUeE0myJnOnQkmlB1yErC8w6oUrRFVfZNJhi1PEax8nbHgNRhfaUSloTSSZVgKeke++5p0HQ
1342+RZJ6q0gaxu1lt3hw8/qOkXLV2tPTns7m87mRdDqRdryAtCYTkQU0SaA7phCRIa1KuEHYnTmtSxRs
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
1585+"
1586+ height="63.999981"
1587+ width="64" />
1588+ </g>
1589+ <g
1590+ inkscape:groupmode="layer"
1591+ id="layer3"
1592+ inkscape:label="PLACE YOUR PICTOGRAM HERE"
1593+ style="display:inline" />
1594+ <g
1595+ inkscape:groupmode="layer"
1596+ id="layer2"
1597+ inkscape:label="BADGE"
1598+ style="display:none"
1599+ sodipodi:insensitive="true">
1600+ <g
1601+ style="display:inline"
1602+ transform="translate(-340.00001,-581)"
1603+ id="g4394"
1604+ clip-path="none">
1605+ <g
1606+ id="g855">
1607+ <g
1608+ inkscape:groupmode="maskhelper"
1609+ id="g870"
1610+ clip-path="url(#clipPath873)"
1611+ style="opacity:0.6;filter:url(#filter891)">
1612+ <path
1613+ transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-237.54282)"
1614+ d="m 264,552.36218 c 0,6.62742 -5.37258,12 -12,12 -6.62742,0 -12,-5.37258 -12,-12 0,-6.62741 5.37258,-12 12,-12 6.62742,0 12,5.37259 12,12 z"
1615+ sodipodi:ry="12"
1616+ sodipodi:rx="12"
1617+ sodipodi:cy="552.36218"
1618+ sodipodi:cx="252"
1619+ id="path844"
1620+ style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
1621+ sodipodi:type="arc" />
1622+ </g>
1623+ <g
1624+ id="g862">
1625+ <path
1626+ sodipodi:type="arc"
1627+ style="color:#000000;fill:#f5f5f5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
1628+ id="path4398"
1629+ sodipodi:cx="252"
1630+ sodipodi:cy="552.36218"
1631+ sodipodi:rx="12"
1632+ sodipodi:ry="12"
1633+ d="m 264,552.36218 c 0,6.62742 -5.37258,12 -12,12 -6.62742,0 -12,-5.37258 -12,-12 0,-6.62741 5.37258,-12 12,-12 6.62742,0 12,5.37259 12,12 z"
1634+ transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-238.54282)" />
1635+ <path
1636+ transform="matrix(1.25,0,0,1.25,33,-100.45273)"
1637+ d="m 264,552.36218 c 0,6.62742 -5.37258,12 -12,12 -6.62742,0 -12,-5.37258 -12,-12 0,-6.62741 5.37258,-12 12,-12 6.62742,0 12,5.37259 12,12 z"
1638+ sodipodi:ry="12"
1639+ sodipodi:rx="12"
1640+ sodipodi:cy="552.36218"
1641+ sodipodi:cx="252"
1642+ id="path4400"
1643+ style="color:#000000;fill:#dd4814;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
1644+ sodipodi:type="arc" />
1645+ <path
1646+ sodipodi:type="star"
1647+ style="color:#000000;fill:#f5f5f5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
1648+ id="path4459"
1649+ sodipodi:sides="5"
1650+ sodipodi:cx="666.19574"
1651+ sodipodi:cy="589.50385"
1652+ sodipodi:r1="7.2431178"
1653+ sodipodi:r2="4.3458705"
1654+ sodipodi:arg1="1.0471976"
1655+ sodipodi:arg2="1.6755161"
1656+ inkscape:flatsided="false"
1657+ inkscape:rounded="0.1"
1658+ inkscape:randomized="0"
1659+ d="m 669.8173,595.77657 c -0.39132,0.22593 -3.62645,-1.90343 -4.07583,-1.95066 -0.44938,-0.0472 -4.05653,1.36297 -4.39232,1.06062 -0.3358,-0.30235 0.68963,-4.03715 0.59569,-4.47913 -0.0939,-0.44198 -2.5498,-3.43681 -2.36602,-3.8496 0.18379,-0.41279 4.05267,-0.59166 4.44398,-0.81759 0.39132,-0.22593 2.48067,-3.48704 2.93005,-3.4398 0.44938,0.0472 1.81505,3.67147 2.15084,3.97382 0.3358,0.30236 4.08294,1.2817 4.17689,1.72369 0.0939,0.44198 -2.9309,2.86076 -3.11469,3.27355 -0.18379,0.41279 0.0427,4.27917 -0.34859,4.5051 z"
1660+ transform="matrix(1.511423,-0.16366377,0.16366377,1.511423,-755.37346,-191.93651)" />
1661+ </g>
1662+ </g>
1663+ </g>
1664+ </g>
1665+</svg>
1666
1667=== renamed file 'icon.svg' => 'icon.svg.moved'
1668=== added file 'metadata.yaml'
1669--- metadata.yaml 1970-01-01 00:00:00 +0000
1670+++ metadata.yaml 2015-08-21 21:55:32 +0000
1671@@ -0,0 +1,13 @@
1672+name: apache-flume-syslog
1673+summary: Ingest syslog events with Apache Flume
1674+maintainer: Kevin Monroe <kevin.monroe@canonical.com>
1675+description: |
1676+ Uses a Syslog source, memory channel, and Avro sink in Apache Flume
1677+ to ingest log data.
1678+tags: ["applications", "bigdata", "apache"]
1679+provides:
1680+ syslog:
1681+ interface: syslog
1682+requires:
1683+ flume-agent:
1684+ interface: flume-agent
1685
1686=== renamed file 'metadata.yaml' => 'metadata.yaml.moved'
1687=== added directory 'resources'
1688=== renamed directory 'resources' => 'resources.moved'
1689=== added file 'resources.yaml'
1690--- resources.yaml 1970-01-01 00:00:00 +0000
1691+++ resources.yaml 2015-08-21 21:55:32 +0000
1692@@ -0,0 +1,12 @@
1693+options:
1694+ output_dir: /home/ubuntu/resources
1695+resources:
1696+ pathlib:
1697+ pypi: path.py>=7.0
1698+ jujubigdata:
1699+ pypi: jujubigdata>=4.0.0,<5.0.0
1700+optional_resources:
1701+ flume-x86_64:
1702+ url: https://git.launchpad.net/bigdata-data/plain/apache/x86_64/apache-flume-1.6.0-bin.tar.gz?id=c34a21c939f5fce9ab89b95d65fe2df50e7bbab0
1703+ hash: defd21ad8d2b6f28cc0a16b96f652099
1704+ hash_type: md5
1705
1706=== renamed file 'resources.yaml' => 'resources.yaml.moved'
1707=== added directory 'resources/python'
1708=== added file 'resources/python/PyYAML-3.11.tar.gz'
1709Binary files resources/python/PyYAML-3.11.tar.gz 1970-01-01 00:00:00 +0000 and resources/python/PyYAML-3.11.tar.gz 2015-08-21 21:55:32 +0000 differ
1710=== added file 'resources/python/charmhelpers-0.3.1.tar.gz'
1711Binary files resources/python/charmhelpers-0.3.1.tar.gz 1970-01-01 00:00:00 +0000 and resources/python/charmhelpers-0.3.1.tar.gz 2015-08-21 21:55:32 +0000 differ
1712=== added file 'resources/python/jujuresources-0.2.9.tar.gz'
1713Binary files resources/python/jujuresources-0.2.9.tar.gz 1970-01-01 00:00:00 +0000 and resources/python/jujuresources-0.2.9.tar.gz 2015-08-21 21:55:32 +0000 differ
1714=== added file 'resources/python/pyaml-15.5.7.tar.gz'
1715Binary files resources/python/pyaml-15.5.7.tar.gz 1970-01-01 00:00:00 +0000 and resources/python/pyaml-15.5.7.tar.gz 2015-08-21 21:55:32 +0000 differ
1716=== added file 'resources/python/six-1.9.0-py2.py3-none-any.whl'
1717Binary files resources/python/six-1.9.0-py2.py3-none-any.whl 1970-01-01 00:00:00 +0000 and resources/python/six-1.9.0-py2.py3-none-any.whl 2015-08-21 21:55:32 +0000 differ
1718=== added directory 'templates'
1719=== renamed directory 'templates' => 'templates.moved'
1720=== added file 'templates/flume.conf.j2'
1721--- templates/flume.conf.j2 1970-01-01 00:00:00 +0000
1722+++ templates/flume.conf.j2 2015-08-21 21:55:32 +0000
1723@@ -0,0 +1,28 @@
1724+# list sources, sinks, and channels in the agent
1725+a1.sources = r1
1726+a1.sinks = k1
1727+a1.channels = c1
1728+
1729+# source properties
1730+a1.sources.r1.type = {{ config['source_type'] }}
1731+a1.sources.r1.channels = c1
1732+a1.sources.r1.host = 0.0.0.0
1733+a1.sources.r1.keepFields = true
1734+a1.sources.r1.port = {{ config['source_port'] }}
1735+
1736+# inject our configured subdir
1737+a1.sources.r1.interceptors = i1
1738+a1.sources.r1.interceptors.i1.type = static
1739+a1.sources.r1.interceptors.i1.key = event_dir
1740+a1.sources.r1.interceptors.i1.value = {{ config['event_dir'] }}
1741+
1742+# channel properties
1743+a1.channels.c1.type = memory
1744+a1.channels.c1.capacity = {{ config['channel_capacity'] }}
1745+a1.channels.c1.transactionCapacity = {{ config['channel_transaction_capacity'] }}
1746+
1747+# sink properties
1748+a1.sinks.k1.type = {{ any_ready_unit('flume-agent')[1]['protocol'] }}
1749+a1.sinks.k1.channel = c1
1750+a1.sinks.k1.hostname = {{ any_ready_unit('flume-agent')[1]['private-address'] }}
1751+a1.sinks.k1.port = {{ any_ready_unit('flume-agent')[1]['port'] }}
1752
1753=== added directory 'tests'
1754=== renamed directory 'tests' => 'tests.moved'
1755=== added file 'tests/00-setup'
1756--- tests/00-setup 1970-01-01 00:00:00 +0000
1757+++ tests/00-setup 2015-08-21 21:55:32 +0000
1758@@ -0,0 +1,5 @@
1759+#!/bin/bash
1760+
1761+sudo add-apt-repository ppa:juju/stable -y
1762+sudo apt-get update
1763+sudo apt-get install python3 amulet -y
1764
1765=== added directory 'tests/remote'
1766=== added file 'tests/remote/test_dist_config.py'
1767--- tests/remote/test_dist_config.py 1970-01-01 00:00:00 +0000
1768+++ tests/remote/test_dist_config.py 2015-08-21 21:55:32 +0000
1769@@ -0,0 +1,62 @@
1770+#!/usr/bin/env python
1771+
1772+import grp
1773+import pwd
1774+import unittest
1775+
1776+from charmhelpers.contrib import bigdata
1777+
1778+
1779+class TestDistConfig(unittest.TestCase):
1780+ """
1781+ Test that the ``dist.yaml`` settings were applied properly, such as users, groups, and dirs.
1782+
1783+ This is done as a remote test on the deployed unit rather than a regular
1784+ test under ``tests/`` because filling in the ``dist.yaml`` requires Juju
1785+ context (e.g., config).
1786+ """
1787+ @classmethod
1788+ def setUpClass(cls):
1789+ cls.hadoop = bigdata.handlers.apache.HadoopBase()
1790+
1791+ def test_groups(self):
1792+ for name in self.hadoop.groups:
1793+ try:
1794+ grp.getgrnam(name)
1795+ except KeyError:
1796+ self.fail('Group {} is missing'.format(name))
1797+
1798+ def test_users(self):
1799+ for username, details in self.hadoop.users.items():
1800+ try:
1801+ user = pwd.getpwnam(username)
1802+ except KeyError:
1803+ self.fail('User {} is missing'.format(username))
1804+ for groupname in details['groups']:
1805+ try:
1806+ group = grp.getgrnam(groupname)
1807+ except KeyError:
1808+ self.fail('Group {} referenced by user {} does not exist'.format(
1809+ groupname, username))
1810+ if group.gr_gid != user.pw_gid:
1811+ self.assertIn(username, group.gr_mem, 'User {} not in group {}'.format(
1812+ username, groupname))
1813+
1814+ def test_dirs(self):
1815+ for name, details in self.hadoop.managed_dirs.items():
1816+ dirpath = details['path']
1817+ self.assertTrue(dirpath.isdir(), 'Dir {} is missing'.format(name))
1818+ stat = dirpath.stat()
1819+ owner = pwd.getpwuid(stat.st_uid).pw_name
1820+ group = grp.getgrgid(stat.st_gid).gr_name
1821+ perms = stat.st_mode & ~0o40000
1822+ self.assertEqual(owner, details.get('owner', 'root'),
1823+ 'Dir {} ({}) has wrong owner: {}'.format(name, dirpath, owner))
1824+ self.assertEqual(group, details.get('group', 'root'),
1825+ 'Dir {} ({}) has wrong group: {}'.format(name, dirpath, group))
1826+ self.assertEqual(perms, details.get('perms', 0o744),
1827+ 'Dir {} ({}) has wrong perms: 0o{:o}'.format(name, dirpath, perms))
1828+
1829+
1830+if __name__ == '__main__':
1831+ unittest.main()

Subscribers

People subscribed via source and target branches