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

Proposed by Kevin W Monroe
Status: Merged
Merged at revision: 2
Proposed branch: lp:~bigdata-dev/charms/trusty/apache-flume-hdfs/trunk
Merge into: lp:charms/trusty/apache-flume-hdfs
Diff against target: 1797 lines (+1670/-0) (has conflicts)
20 files modified
LICENSE (+177/-0)
README.md (+80/-0)
config.yaml (+41/-0)
copyright (+16/-0)
dist.yaml (+16/-0)
hooks/callbacks.py (+140/-0)
hooks/common.py (+89/-0)
hooks/config-changed (+15/-0)
hooks/flume-agent-relation-changed (+15/-0)
hooks/hadoop-plugin-relation-changed (+15/-0)
hooks/install (+17/-0)
hooks/setup.py (+33/-0)
hooks/start (+15/-0)
hooks/stop (+15/-0)
icon.svg (+863/-0)
metadata.yaml (+12/-0)
resources.yaml (+12/-0)
templates/flume.conf.j2 (+32/-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-hdfs/trunk
Reviewer Review Type Date Requested Status
Kevin W Monroe Approve
Review via email: mp+268658@code.launchpad.net
To post a comment you must log in.
20. 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:27 +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:27 +0000
187@@ -0,0 +1,80 @@
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 ingest events into the shared
198+filesystem (HDFS) of a connected Hadoop cluster. It is meant to relate to
199+other Flume agents such as `apache-flume-syslog` and `apache-flume-twitter`.
200+
201+
202+## Usage
203+
204+This charm leverages our pluggable Hadoop model with the `hadoop-plugin`
205+interface. This means that you will need to deploy a base Apache Hadoop cluster
206+to run Flume. The suggested deployment method is to use the
207+[apache-ingestion-flume](https://jujucharms.com/u/bigdata-dev/apache-ingestion-flume/)
208+bundle. This will deploy the Apache Hadoop platform with a single Apache Flume
209+unit that communicates with the cluster by relating to the
210+`apache-hadoop-plugin` subordinate charm:
211+
212+ juju quickstart u/bigdata-dev/apache-ingestion-flume
213+
214+Alternatively, you may manually deploy the recommended environment as follows:
215+
216+ juju deploy apache-hadoop-hdfs-master hdfs-master
217+ juju deploy apache-hadoop-yarn-master yarn-master
218+ juju deploy apache-hadoop-compute-slave compute-slave
219+ juju deploy apache-hadoop-plugin plugin
220+ juju deploy apache-flume-hdfs flume-hdfs
221+
222+ juju add-relation yarn-master hdfs-master
223+ juju add-relation compute-slave yarn-master
224+ juju add-relation compute-slave hdfs-master
225+ juju add-relation plugin yarn-master
226+ juju add-relation plugin hdfs-master
227+ juju add-relation flume-hdfs plugin
228+
229+The deployment at this stage isn't very exciting, as the `flume-hdfs` service
230+is waiting for other Flume agents to connect and send data. You'll probably
231+want to check out
232+[apache-flume-syslog](https://jujucharms.com/apache-flume-syslog)
233+or
234+[apache-flume-twitter](https://jujucharms.com/apache-flume-twitter)
235+to provide additional functionality for this deployment.
236+
237+When `flume-hdfs` receives data, it is stored in a `/user/flume/<event_dir>`
238+HDFS subdirectory (configured by the connected Flume charm). You can quickly
239+verify the data written to HDFS using the command line. SSH to the `flume-hdfs`
240+unit, locate an event, and cat it:
241+
242+ juju ssh flume-hdfs/0
243+ hdfs dfs -ls /user/flume/<event_dir> # <-- find a date
244+ hdfs dfs -ls /user/flume/<event_dir>/yy-mm-dd # <-- find an hour
245+ hdfs dfs -ls /user/flume/<event_dir>/yy-mm-dd/HH # <-- find an event
246+ hdfs dfs -cat /user/flume/<event_dir>/yy-mm-dd/HH/FlumeData.<id>
247+
248+This process works well for data serialized in `text` format (the default).
249+For data serialized in `avro` format, you'll need to copy the file locally
250+and use the `dfs -text` command. For example, replace the `dfs -cat` command
251+from above with the following to view files stored in `avro` format:
252+
253+ hdfs dfs -copyToLocal /user/flume/<event_dir>/yy-mm-dd/HH/FlumeData.<id> /home/ubuntu/myFile.txt
254+ hdfs dfs -text file:///home/ubuntu/myFile.txt
255+
256+
257+## Contact Information
258+
259+- <bigdata-dev@lists.launchpad.net>
260+
261+
262+## Help
263+
264+- [Apache Flume home page](http://flume.apache.org/)
265+- [Apache Flume bug tracker](https://issues.apache.org/jira/browse/flume)
266+- [Apache Flume mailing lists](https://flume.apache.org/mailinglists.html)
267+- `#juju` on `irc.freenode.net`
268
269=== renamed file 'README.md' => 'README.md.moved'
270=== added file 'config.yaml'
271--- config.yaml 1970-01-01 00:00:00 +0000
272+++ config.yaml 2015-08-21 21:55:27 +0000
273@@ -0,0 +1,41 @@
274+options:
275+ resources_mirror:
276+ type: string
277+ default: ''
278+ description: |
279+ URL from which to fetch resources (e.g., Hadoop binaries) instead
280+ of Launchpad.
281+ channel_capacity:
282+ type: string
283+ default: '1000'
284+ description: |
285+ The maximum number of events stored in the channel.
286+ channel_transaction_capacity:
287+ type: string
288+ default: '100'
289+ description: |
290+ The maximum number of events the channel will take from a source or
291+ give to a sink per transaction.
292+ protocol:
293+ type: string
294+ default: 'avro'
295+ description: |
296+ Ingestion protocol for the agent source. Currently only 'avro' is supported.
297+ sink_compression:
298+ type: string
299+ default: ''
300+ description: |
301+ Compression codec for the agent sink. An empty value will write events
302+ to HDFS uncompressed. You may specify 'snappy' here to compress written
303+ events using the snappy codec.
304+ sink_serializer:
305+ type: string
306+ default: 'text'
307+ description: |
308+ Specify the serializer used when the sink writes to HDFS. Either
309+ 'avro_event' or 'text' are supported.
310+ source_port:
311+ type: string
312+ default: '4141'
313+ description: |
314+ Port on which the agent source is listening.
315
316=== renamed file 'config.yaml' => 'config.yaml.moved'
317=== added file 'copyright'
318--- copyright 1970-01-01 00:00:00 +0000
319+++ copyright 2015-08-21 21:55:27 +0000
320@@ -0,0 +1,16 @@
321+Format: http://dep.debian.net/deps/dep5/
322+
323+Files: *
324+Copyright: Copyright 2015, Canonical Ltd., All Rights Reserved.
325+License: Apache License 2.0
326+ Licensed under the Apache License, Version 2.0 (the "License");
327+ you may not use this file except in compliance with the License.
328+ You may obtain a copy of the License at
329+ .
330+ http://www.apache.org/licenses/LICENSE-2.0
331+ .
332+ Unless required by applicable law or agreed to in writing, software
333+ distributed under the License is distributed on an "AS IS" BASIS,
334+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
335+ See the License for the specific language governing permissions and
336+ limitations under the License.
337
338=== renamed file 'copyright' => 'copyright.moved'
339=== added file 'dist.yaml'
340--- dist.yaml 1970-01-01 00:00:00 +0000
341+++ dist.yaml 2015-08-21 21:55:27 +0000
342@@ -0,0 +1,16 @@
343+# This file contains values that are likely to change per distribution.
344+# The aim is to make it easier to update / extend the charms with
345+# minimal changes to the shared code in charmhelpers.
346+groups:
347+ - 'hadoop'
348+users:
349+ flume:
350+ groups: ['hadoop']
351+dirs:
352+ flume:
353+ path: '/usr/lib/flume-hdfs'
354+ flume_conf:
355+ path: '/etc/flume-hdfs/conf'
356+ flume_logs:
357+ path: '/var/log/flume-hdfs'
358+ owner: 'flume'
359
360=== renamed file 'dist.yaml' => 'dist.yaml.moved'
361=== added directory 'hooks'
362=== renamed directory 'hooks' => 'hooks.moved'
363=== added file 'hooks/callbacks.py'
364--- hooks/callbacks.py 1970-01-01 00:00:00 +0000
365+++ hooks/callbacks.py 2015-08-21 21:55:27 +0000
366@@ -0,0 +1,140 @@
367+import os
368+import signal
369+from subprocess import Popen
370+
371+
372+import jujuresources
373+from charmhelpers.core import hookenv
374+from charmhelpers.core import host
375+from charmhelpers.core import unitdata
376+from jujubigdata import utils
377+from jujubigdata.relations import HadoopPlugin
378+
379+
380+# Extended status support
381+# We call update_blocked_status from the "requires" section of our service
382+# block, so be sure to return True. Otherwise, we'll block the "requires"
383+# and never move on to callbacks. The other status update methods are called
384+# from the "callbacks" section and therefore don't need to return True.
385+def update_blocked_status():
386+ if unitdata.kv().get('charm.active', False):
387+ return True
388+ if not HadoopPlugin().connected_units():
389+ hookenv.status_set('blocked', 'Waiting for relation to apache-hadoop-plugin')
390+ elif not HadoopPlugin().is_ready():
391+ hookenv.status_set('waiting', 'Waiting for Hadoop Plugin to become ready')
392+ return True
393+
394+
395+def update_working_status():
396+ if unitdata.kv().get('charm.active', False):
397+ hookenv.status_set('maintenance', 'Updating configuration')
398+ return
399+ hookenv.status_set('maintenance', 'Setting up Apache Flume')
400+
401+
402+def update_active_status():
403+ unitdata.kv().set('charm.active', True)
404+ hookenv.status_set('active', 'Ready')
405+
406+
407+# Main Flume class for callbacks
408+class Flume(object):
409+ def __init__(self, dist_config):
410+ self.dist_config = dist_config
411+ self.resources = {
412+ 'flume': 'flume-%s' % host.cpu_arch(),
413+ }
414+ self.verify_resources = utils.verify_resources(*self.resources.values())
415+
416+ def is_installed(self):
417+ return unitdata.kv().get('flume.installed')
418+
419+ def install(self, force=False):
420+ if not force and self.is_installed():
421+ return
422+ jujuresources.install(self.resources['flume'],
423+ destination=self.dist_config.path('flume'),
424+ skip_top_level=True)
425+ self.dist_config.add_users()
426+ self.dist_config.add_dirs()
427+ self.setup_flume_config()
428+ self.configure_flume()
429+ unitdata.kv().set('flume.installed', True)
430+
431+ def setup_flume_config(self):
432+ '''
433+ copy the default configuration files to flume_conf property
434+ defined in dist.yaml
435+ '''
436+ default_conf = self.dist_config.path('flume') / 'conf'
437+ flume_conf = self.dist_config.path('flume_conf')
438+ flume_conf.rmtree_p()
439+ default_conf.copytree(flume_conf)
440+ # Now remove the conf included in the tarball and symlink our real conf
441+ default_conf.rmtree_p()
442+ flume_conf.symlink(default_conf)
443+
444+ flume_env = self.dist_config.path('flume_conf') / 'flume-env.sh'
445+ if not flume_env.exists():
446+ (self.dist_config.path('flume_conf') / 'flume-env.sh.template').copy(flume_env)
447+
448+ flume_conf = self.dist_config.path('flume_conf') / 'flume.conf'
449+ if not flume_conf.exists():
450+ (self.dist_config.path('flume_conf') / 'flume-conf.properties.template').copy(flume_conf)
451+
452+ flume_log4j = self.dist_config.path('flume_conf') / 'log4j.properties'
453+ utils.re_edit_in_place(flume_log4j, {
454+ r'^flume.log.dir.*': 'flume.log.dir={}'.format(self.dist_config.path('flume_logs')),
455+ })
456+
457+ def configure_flume(self):
458+ flume_bin = self.dist_config.path('flume') / 'bin'
459+ with utils.environment_edit_in_place('/etc/environment') as env:
460+ if flume_bin not in env['PATH']:
461+ env['PATH'] = ':'.join([env['PATH'], flume_bin])
462+ env['FLUME_CONF_DIR'] = self.dist_config.path('flume_conf')
463+ env['FLUME_CLASSPATH'] = self.dist_config.path('flume') / 'lib'
464+ env['FLUME_HOME'] = self.dist_config.path('flume')
465+
466+ # flume_env = self.dist_config.path('flume_conf') / 'flume-env.sh'
467+ # utils.re_edit_in_place(flume_env, {
468+ # })
469+ utils.run_as('flume', 'hdfs', 'dfs', '-mkdir', '-p', '/user/flume')
470+
471+ def run_bg(self, user, command, *args):
472+ """
473+ Start a Flume agent as the given user in the background.
474+
475+ :param str user: User to run flume agent
476+ :param str command: Command to run
477+ :param list args: Additional args to pass to the command
478+ """
479+ parts = [command] + list(args)
480+ quoted = ' '.join("'%s'" % p for p in parts)
481+ e = utils.read_etc_env()
482+ Popen(['su', user, '-c', quoted], env=e)
483+
484+ def restart(self):
485+ # check for a java process with our flume dir in the classpath
486+ if utils.jps(r'-cp .*{}'.format(self.dist_config.path('flume'))):
487+ self.stop()
488+ self.start()
489+
490+ def start(self):
491+ self.run_bg(
492+ 'flume',
493+ self.dist_config.path('flume') / 'bin/flume-ng',
494+ 'agent',
495+ '-c', self.dist_config.path('flume_conf'),
496+ '-f', self.dist_config.path('flume_conf') / 'flume.conf',
497+ '-n', 'a1')
498+
499+ def stop(self):
500+ flume_pids = utils.jps(r'-cp .*{}'.format(self.dist_config.path('flume')))
501+ for pid in flume_pids:
502+ os.kill(int(pid), signal.SIGKILL)
503+
504+ def cleanup(self):
505+ self.dist_config.remove_users()
506+ self.dist_config.remove_dirs()
507
508=== added file 'hooks/common.py'
509--- hooks/common.py 1970-01-01 00:00:00 +0000
510+++ hooks/common.py 2015-08-21 21:55:27 +0000
511@@ -0,0 +1,89 @@
512+#!/usr/bin/env python
513+# Licensed under the Apache License, Version 2.0 (the "License");
514+# you may not use this file except in compliance with the License.
515+# You may obtain a copy of the License at
516+#
517+# http://www.apache.org/licenses/LICENSE-2.0
518+#
519+# Unless required by applicable law or agreed to in writing, software
520+# distributed under the License is distributed on an "AS IS" BASIS,
521+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
522+# See the License for the specific language governing permissions and
523+# limitations under the License.
524+"""
525+Common implementation for all hooks.
526+"""
527+
528+import jujuresources
529+from charmhelpers.core import hookenv
530+from charmhelpers.core import unitdata
531+from charmhelpers.core import charmframework
532+
533+
534+def bootstrap_resources():
535+ """
536+ Install required resources defined in resources.yaml
537+ """
538+ if unitdata.kv().get('charm.bootstrapped', False):
539+ return True
540+ hookenv.status_set('maintenance', 'Installing base resources')
541+ mirror_url = jujuresources.config_get('resources_mirror')
542+ if not jujuresources.fetch(mirror_url=mirror_url):
543+ missing = jujuresources.invalid()
544+ hookenv.status_set('blocked', 'Unable to fetch required resource%s: %s' % (
545+ 's' if len(missing) > 1 else '',
546+ ', '.join(missing),
547+ ))
548+ return False
549+ jujuresources.install(['pathlib', 'jujubigdata'])
550+ unitdata.kv().set('charm.bootstrapped', True)
551+ return True
552+
553+
554+def manage():
555+ if not bootstrap_resources():
556+ # defer until resources are available, since charmhelpers, and thus
557+ # the framework, are required (will require manual intervention)
558+ return
559+
560+ import jujubigdata
561+ import callbacks
562+
563+ flume_reqs = ['groups', 'users', 'dirs']
564+ hook_config = hookenv.config()
565+ dist_config = jujubigdata.utils.DistConfig(filename='dist.yaml',
566+ required_keys=flume_reqs)
567+ flume = callbacks.Flume(dist_config)
568+ manager = charmframework.Manager([
569+ {
570+ 'name': 'flume',
571+ 'provides': [
572+ jujubigdata.relations.FlumeAgent(port=hook_config['source_port']),
573+ ],
574+ 'requires': [
575+ flume.verify_resources,
576+ jujubigdata.relations.HadoopPlugin(hdfs_only=True),
577+ callbacks.update_blocked_status, # not really a requirement, but best way to fit into framework
578+ ],
579+ 'callbacks': [
580+ callbacks.update_working_status,
581+ flume.install,
582+ charmframework.helpers.render_template(
583+ source='flume.conf.j2',
584+ target=flume.dist_config.path('flume_conf') / 'flume.conf',
585+ context={'dist_config': dist_config}
586+ ),
587+ flume.restart,
588+ callbacks.update_active_status,
589+ ],
590+ 'cleanup': [
591+ flume.stop,
592+ flume.cleanup,
593+ ],
594+ },
595+ ])
596+ manager.manage()
597+
598+
599+if __name__ == '__main__':
600+ manage()
601
602=== added file 'hooks/config-changed'
603--- hooks/config-changed 1970-01-01 00:00:00 +0000
604+++ hooks/config-changed 2015-08-21 21:55:27 +0000
605@@ -0,0 +1,15 @@
606+#!/usr/bin/env python
607+# Licensed under the Apache License, Version 2.0 (the "License");
608+# you may not use this file except in compliance with the License.
609+# You may obtain a copy of the License at
610+#
611+# http://www.apache.org/licenses/LICENSE-2.0
612+#
613+# Unless required by applicable law or agreed to in writing, software
614+# distributed under the License is distributed on an "AS IS" BASIS,
615+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
616+# See the License for the specific language governing permissions and
617+# limitations under the License.
618+
619+import common
620+common.manage()
621
622=== added file 'hooks/flume-agent-relation-changed'
623--- hooks/flume-agent-relation-changed 1970-01-01 00:00:00 +0000
624+++ hooks/flume-agent-relation-changed 2015-08-21 21:55:27 +0000
625@@ -0,0 +1,15 @@
626+#!/usr/bin/env python
627+# Licensed under the Apache License, Version 2.0 (the "License");
628+# you may not use this file except in compliance with the License.
629+# You may obtain a copy of the License at
630+#
631+# http://www.apache.org/licenses/LICENSE-2.0
632+#
633+# Unless required by applicable law or agreed to in writing, software
634+# distributed under the License is distributed on an "AS IS" BASIS,
635+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
636+# See the License for the specific language governing permissions and
637+# limitations under the License.
638+
639+import common
640+common.manage()
641
642=== added file 'hooks/hadoop-plugin-relation-changed'
643--- hooks/hadoop-plugin-relation-changed 1970-01-01 00:00:00 +0000
644+++ hooks/hadoop-plugin-relation-changed 2015-08-21 21:55:27 +0000
645@@ -0,0 +1,15 @@
646+#!/usr/bin/env python
647+# Licensed under the Apache License, Version 2.0 (the "License");
648+# you may not use this file except in compliance with the License.
649+# You may obtain a copy of the License at
650+#
651+# http://www.apache.org/licenses/LICENSE-2.0
652+#
653+# Unless required by applicable law or agreed to in writing, software
654+# distributed under the License is distributed on an "AS IS" BASIS,
655+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
656+# See the License for the specific language governing permissions and
657+# limitations under the License.
658+
659+import common
660+common.manage()
661
662=== added file 'hooks/install'
663--- hooks/install 1970-01-01 00:00:00 +0000
664+++ hooks/install 2015-08-21 21:55:27 +0000
665@@ -0,0 +1,17 @@
666+#!/usr/bin/python
667+# Licensed under the Apache License, Version 2.0 (the "License");
668+# you may not use this file except in compliance with the License.
669+# You may obtain a copy of the License at
670+#
671+# http://www.apache.org/licenses/LICENSE-2.0
672+#
673+# Unless required by applicable law or agreed to in writing, software
674+# distributed under the License is distributed on an "AS IS" BASIS,
675+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
676+# See the License for the specific language governing permissions and
677+# limitations under the License.
678+import setup
679+setup.pre_install()
680+
681+import common
682+common.manage()
683
684=== added file 'hooks/setup.py'
685--- hooks/setup.py 1970-01-01 00:00:00 +0000
686+++ hooks/setup.py 2015-08-21 21:55:27 +0000
687@@ -0,0 +1,33 @@
688+# Licensed under the Apache License, Version 2.0 (the "License");
689+# you may not use this file except in compliance with the License.
690+# You may obtain a copy of the License at
691+#
692+# http://www.apache.org/licenses/LICENSE-2.0
693+#
694+# Unless required by applicable law or agreed to in writing, software
695+# distributed under the License is distributed on an "AS IS" BASIS,
696+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
697+# See the License for the specific language governing permissions and
698+# limitations under the License.
699+import subprocess
700+from glob import glob
701+
702+
703+def pre_install():
704+ """
705+ Do any setup required before the install hook.
706+ """
707+ install_pip()
708+ install_bundled_resources()
709+
710+
711+def install_pip():
712+ subprocess.check_call(['apt-get', 'install', '-yq', 'python-pip', 'bzr'])
713+
714+
715+def install_bundled_resources():
716+ """
717+ Install the bundled resources libraries.
718+ """
719+ archives = glob('resources/python/*')
720+ subprocess.check_call(['pip', 'install'] + archives)
721
722=== added file 'hooks/start'
723--- hooks/start 1970-01-01 00:00:00 +0000
724+++ hooks/start 2015-08-21 21:55:27 +0000
725@@ -0,0 +1,15 @@
726+#!/usr/bin/env python
727+# Licensed under the Apache License, Version 2.0 (the "License");
728+# you may not use this file except in compliance with the License.
729+# You may obtain a copy of the License at
730+#
731+# http://www.apache.org/licenses/LICENSE-2.0
732+#
733+# Unless required by applicable law or agreed to in writing, software
734+# distributed under the License is distributed on an "AS IS" BASIS,
735+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
736+# See the License for the specific language governing permissions and
737+# limitations under the License.
738+
739+import common
740+common.manage()
741
742=== added file 'hooks/stop'
743--- hooks/stop 1970-01-01 00:00:00 +0000
744+++ hooks/stop 2015-08-21 21:55:27 +0000
745@@ -0,0 +1,15 @@
746+#!/usr/bin/env python
747+# Licensed under the Apache License, Version 2.0 (the "License");
748+# you may not use this file except in compliance with the License.
749+# You may obtain a copy of the License at
750+#
751+# http://www.apache.org/licenses/LICENSE-2.0
752+#
753+# Unless required by applicable law or agreed to in writing, software
754+# distributed under the License is distributed on an "AS IS" BASIS,
755+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
756+# See the License for the specific language governing permissions and
757+# limitations under the License.
758+
759+import common
760+common.manage()
761
762=== added file 'icon.svg'
763--- icon.svg 1970-01-01 00:00:00 +0000
764+++ icon.svg 2015-08-21 21:55:27 +0000
765@@ -0,0 +1,863 @@
766+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
767+<!-- Created with Inkscape (http://www.inkscape.org/) -->
768+
769+<svg
770+ xmlns:dc="http://purl.org/dc/elements/1.1/"
771+ xmlns:cc="http://creativecommons.org/ns#"
772+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
773+ xmlns:svg="http://www.w3.org/2000/svg"
774+ xmlns="http://www.w3.org/2000/svg"
775+ xmlns:xlink="http://www.w3.org/1999/xlink"
776+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
777+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
778+ width="96"
779+ height="96"
780+ id="svg6517"
781+ version="1.1"
782+ inkscape:version="0.48.4 r9939"
783+ sodipodi:docname="icon-template.svg">
784+ <defs
785+ id="defs6519">
786+ <linearGradient
787+ id="Background">
788+ <stop
789+ id="stop4178"
790+ offset="0"
791+ style="stop-color:#b8b8b8;stop-opacity:1" />
792+ <stop
793+ id="stop4180"
794+ offset="1"
795+ style="stop-color:#c9c9c9;stop-opacity:1" />
796+ </linearGradient>
797+ <filter
798+ style="color-interpolation-filters:sRGB;"
799+ inkscape:label="Inner Shadow"
800+ id="filter1121">
801+ <feFlood
802+ flood-opacity="0.59999999999999998"
803+ flood-color="rgb(0,0,0)"
804+ result="flood"
805+ id="feFlood1123" />
806+ <feComposite
807+ in="flood"
808+ in2="SourceGraphic"
809+ operator="out"
810+ result="composite1"
811+ id="feComposite1125" />
812+ <feGaussianBlur
813+ in="composite1"
814+ stdDeviation="1"
815+ result="blur"
816+ id="feGaussianBlur1127" />
817+ <feOffset
818+ dx="0"
819+ dy="2"
820+ result="offset"
821+ id="feOffset1129" />
822+ <feComposite
823+ in="offset"
824+ in2="SourceGraphic"
825+ operator="atop"
826+ result="composite2"
827+ id="feComposite1131" />
828+ </filter>
829+ <filter
830+ style="color-interpolation-filters:sRGB;"
831+ inkscape:label="Drop Shadow"
832+ id="filter950">
833+ <feFlood
834+ flood-opacity="0.25"
835+ flood-color="rgb(0,0,0)"
836+ result="flood"
837+ id="feFlood952" />
838+ <feComposite
839+ in="flood"
840+ in2="SourceGraphic"
841+ operator="in"
842+ result="composite1"
843+ id="feComposite954" />
844+ <feGaussianBlur
845+ in="composite1"
846+ stdDeviation="1"
847+ result="blur"
848+ id="feGaussianBlur956" />
849+ <feOffset
850+ dx="0"
851+ dy="1"
852+ result="offset"
853+ id="feOffset958" />
854+ <feComposite
855+ in="SourceGraphic"
856+ in2="offset"
857+ operator="over"
858+ result="composite2"
859+ id="feComposite960" />
860+ </filter>
861+ <clipPath
862+ clipPathUnits="userSpaceOnUse"
863+ id="clipPath873">
864+ <g
865+ transform="matrix(0,-0.66666667,0.66604479,0,-258.25992,677.00001)"
866+ id="g875"
867+ inkscape:label="Layer 1"
868+ style="fill:#ff00ff;fill-opacity:1;stroke:none;display:inline">
869+ <path
870+ style="fill:#ff00ff;fill-opacity:1;stroke:none;display:inline"
871+ 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"
872+ id="path877"
873+ inkscape:connector-curvature="0"
874+ sodipodi:nodetypes="sssssssss" />
875+ </g>
876+ </clipPath>
877+ <filter
878+ inkscape:collect="always"
879+ id="filter891"
880+ inkscape:label="Badge Shadow">
881+ <feGaussianBlur
882+ inkscape:collect="always"
883+ stdDeviation="0.71999962"
884+ id="feGaussianBlur893" />
885+ </filter>
886+ </defs>
887+ <sodipodi:namedview
888+ id="base"
889+ pagecolor="#ffffff"
890+ bordercolor="#666666"
891+ borderopacity="1.0"
892+ inkscape:pageopacity="0.0"
893+ inkscape:pageshadow="2"
894+ inkscape:zoom="3.4719894"
895+ inkscape:cx="18.514671"
896+ inkscape:cy="49.018169"
897+ inkscape:document-units="px"
898+ inkscape:current-layer="layer1"
899+ showgrid="false"
900+ fit-margin-top="0"
901+ fit-margin-left="0"
902+ fit-margin-right="0"
903+ fit-margin-bottom="0"
904+ inkscape:window-width="1366"
905+ inkscape:window-height="744"
906+ inkscape:window-x="0"
907+ inkscape:window-y="24"
908+ inkscape:window-maximized="1"
909+ showborder="true"
910+ showguides="true"
911+ inkscape:guide-bbox="true"
912+ inkscape:showpageshadow="false">
913+ <inkscape:grid
914+ type="xygrid"
915+ id="grid821" />
916+ <sodipodi:guide
917+ orientation="1,0"
918+ position="16,48"
919+ id="guide823" />
920+ <sodipodi:guide
921+ orientation="0,1"
922+ position="64,80"
923+ id="guide825" />
924+ <sodipodi:guide
925+ orientation="1,0"
926+ position="80,40"
927+ id="guide827" />
928+ <sodipodi:guide
929+ orientation="0,1"
930+ position="64,16"
931+ id="guide829" />
932+ </sodipodi:namedview>
933+ <metadata
934+ id="metadata6522">
935+ <rdf:RDF>
936+ <cc:Work
937+ rdf:about="">
938+ <dc:format>image/svg+xml</dc:format>
939+ <dc:type
940+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
941+ <dc:title></dc:title>
942+ </cc:Work>
943+ </rdf:RDF>
944+ </metadata>
945+ <g
946+ inkscape:label="BACKGROUND"
947+ inkscape:groupmode="layer"
948+ id="layer1"
949+ transform="translate(268,-635.29076)"
950+ style="display:inline">
951+ <path
952+ style="fill:#e6e6e6;fill-opacity:1;stroke:none;display:inline;filter:url(#filter1121)"
953+ 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"
954+ id="path6455"
955+ inkscape:connector-curvature="0"
956+ sodipodi:nodetypes="sssssssss" />
957+ <image
958+ y="651.29077"
959+ x="-252"
960+ id="image3185"
961+ xlink:href="data:image/png;base64,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
1021+whezv3RtIEiTZfeqAWF8ajpvCNIop5IpkKqEflsowt7tklxGIAHLypjbd1/786U9r32fSHBVX6QH
1022+58HfELye8M+j2ScZxxNEvtnQrRUtg7lixtSlo7BD573WI+b9g410UVLToBePvE9znCS4zy0724r5
1023+7Gds29oaZg9BujHo+mlttUp1rdaXXijmMQwDy7IYKhfSdWVjvbSfAsAkAJw2huKy0hMBSe4bAzhS
1024+AYJLyVmrSPwn+0wlpVbAhxMqggrUgH07FIenBG1Hx87mstt27f+o57oLK8ce/UIYcKKkRKiEoz/J
1025+KSNnfswxZeJayFmTLqorQeZGIL20RZ/mwCmOcImY0TT3SBtiyXvPLztDOTvzh8V89obgdnJZScbe
1026+WNwvL67QaLQAcF0Xr7FGu14lpztkcDCJJyyk0lglA0DbFQjdIJMvUS4VMAsjjG2ZJGOZl2E8JUHa
1027+k94H0kGctPdaGqS+YRbfIwOQxvUJ3FYqbFevvhqCWjFUggM7FS+cFjgeFEqVysSWHR9z3deeXzn2
1028+6KFeV1MyrjROSxpQ4Rqu2OCK1YD4Jf1uaaAZooQEPdCRZMwFIBDzUqY7KtlhasCAhCKrF6Qy6f+D
1029+5CI7pcAw9F8qFXJvCfNnM5KMvXEMwvHDx/FWp9GdKq7wuYJQCk8qTNMgn036rxS6psjRASCXUbRd
1030+QXVljeYyoNsszy0yuW8/wyPl+K4NQJruiTif4nI4aXJ6NsE5VU/pIacdwEl7uXdslMUgDR9dLiuu
1031+3QHPnvLLHJ7Yuqder/57b89d71458UQjmtdPhu4luGrSBeVf89NSHoDQ6r9C7qk+1qSURGoxSCPW
1032+HnSmEiIGIyQ6LH7LowEJMkTuiughwZsXnao+kJ5fcq4tFnL/VNc1A0DXJHZuY5AePXwKVk9TooFt
1033+6rhK0RUSL3jRWp6g2nZ6ah1VCICsaTBRyJIxdJRok22dYeb5b/Dct55hdaV6UZD2hiOC34dJTpq8
1034+azBI4xJ9wMkIZInCEzljdeFyQOrrrH5Q+viopFyIQb9157432bnizwoZW/3JCCsVzukH+qofBxAv
1035+u5Yp3TReVSCukI6qua6b6ugNRT1cVkje5UTe//e/nnlv1xVf/rkf3D5LSo/y81xY6g7l8/bXS4Xc
1036+DeA79AsFNTDIueu4nD05hVqZIkcrda3ueDQcL2DofuF506CSCzlrP4iCEaUrBC1XULF9obMu83i5
1037+TWzft4fR0WFgMEhD4ITt1hJASnsD/F+owqlkWgDwlN4ecq3kk1XsBXCF/xJqmoEQDhKJhq/He8IJ
1038+6qJFYllDo9kwOXRCsVST6Arc9vrK9Mnnf2T2+S8/oqRv4fdx0TAoJfCfp+b1VZrbhucnTp7qG7eX
1039+Smayk3tBeimD6VLheH38J+CirpDPbx4pPIiSd0XPDfMohW4Y/6qQy10XAiif2zgS/9TRE9i1M1h0
1040++66VMibFjEnXE3RcQUcIWp4g5xnYZm8sgAq4v5+Q0TX0jEG146BpoFQH0V7m8JNnKYzsYOe+PYyN
1041+D6d0sF6dPQRbeC0J0lh3j9NDMRmDO3xvfM4qpIem63heF0/4DKbrtVH44+N4vhqja3rgz/TQNA0N
1042+DSED3VxpaJrmc0kDJjeZvDit0ewqPCFGzbH9PzFxR+Xx2Sf/zE0aSr1xpingKqLZqvQ9V3ApiuN0
1043+X3Jgcyzmk6I+PL2YLhreK/nCU+uHHdebedf3jt4XD4rk3KJzw3Cl+Hg2Y1VQYBiSofJgkJ48fgaW
1044+jzNku2imjvQknuvvBhJHaMU1We+4NB2PjKkzmsskKpgUoSTQ66c3HY+m4+EIgRCKvKWj2yO4uQl2
1045+X7uPkbEKSincThsrm0txxKgvU/2V9IeGol6m6wJ40kVJQcdtopTCkw6ecNE0H3ixihGCQUbATrYl
1046+ehUSYis5HqfO6jz8TJTqKMXbgK/O/M1vq5iL9lr1MYBDoCaDUJKc9uzZswPH76WQueEUKAxeHkKs
1047+T/oVUnHygHn9QSAFWG90vnhw19gH//SrCx/5sTdu+lDYwFw283t2xqoo5UdC5VILSXxqNjucPTUF
1048+tQsUVYtOC3RDx7R08kNZdF2jXe/idNzUfXnL8AHnSRwhyRh6uu1pHSDStXOmQdYIxaik43l0OytU
1049+VJWjT57DymaQ3RqddpMbXvNmRrbuSPVCGqSqD6Qx1/X1wo7bQCqF67URSiTEfiBuE3WOQRrroS8F
1050+pADX7JI8d0pnoQZKkQH+LfCEkLIdTZ+GxlGfCyoB4N6/6kpOofYYCKHBNAikySnQ8C2KOiTSn8Jy
1051+0gbTx//6wnv/6KHzt4f91eq6/wvg4K6xD/7p3y58BODckvPOXM5+daiAZ22B2bO2aXFhhdPPfpNC
1052+7SRF1YjrLSROx8PteKAUuWIGM5N0aihMXcPQfD1tveNS6zjUui5N18MV8YAnQeofS/8FUxJTg4Jp
1053+0HRcZmttRHeFVnWOTrsBUnLkm39LbWkuqnM/SFUCoj7QPOnScRo0OuusNRdoO006bgNPeoRO/KQJ
1054+FZaXBGkI/ORLtxFIe12CKPjemxVGJLjUHaB+IjKMop8P2KTfNF4aHQa3pPfDulLxqFq75RsgF4sZ
1055+DYEY0kWXhjCIi/od+dnHVx4GqLec//lT92154JnTIrrtyNnlj973qvE3DxXzty7XXDYNW5TL9NGh
1056+J59i1JvduEE6lEbyQT0UrfV2EHbmX290PWpdJ6qzCixuTYOxnE3GiLle5NOM/sZpy60uja4bQ076
1057+wJBSYucKXHPHfYxuGo96JgZ9CFSFEA4tp4GUrj9/Hkkkmcrvp4XH4Rr/NEiTXPZSIE2RitOOntZ5
1058+9Pno+mngjlOf//BaiquqHuNqEDdFxdOqUjI7N7fheF0u6aHbCZmYfou6Nxy0OFLq4iBVaZDKgBMF
1059+3fbO147eB3Dj3omPP3NaqPML69+sNjpLSsHBnWMfXG/rNwFYhk4uO1hk6G5jYHrEVaTCc3xpoOka
1060+diGT4sjFjMGWYpaRXIZixkDTYvG11GzT9YQf9xCqKUmABZxNKkXO1CNRnIzJVErRadV58fG/4clH
1061+vs7iwkoEOhkAyPHatLo11lvLuF4HT3hRLyat/36QKtI4i8uNRuFyQRq9g/EzDuwVFELVXam9KPWL
1062+yS1/pEyubE2nx7GsYYxAHLN6JUhrNpopgCY3fthoCjTmDFGjUue9xlYykEWh+JOH59+bzZh3/73X
1063+j71PScmffGXhrbfs2/xFANPUKeQ09mw1yBf8zUx0LXb3Pvd3X2VYT06FqsRfX3YZpk62kMGwDFCK
1064+xlob4Yng+XFdAKodh0bXjax3S/edy37Qt8QVkoJlULbNYLBlyIqZb3QBSdsVkVGhZKxLbi1lqTNE
1065+x55g18H9jE2U6HoNPCkQwiUGXgzi5EsR9HTUb2m9NAZuZDy9FJAm0mJ3F5w5r/M334nuOwa89uj/
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
1126+Oq5HreOglKLa6aJpFpamYWoaZuDvkDKxgYOM3VZuu8HazAnW5s6i6/C82sff+9H/8yAVbova9GPk
1127+Jm4kO7T9ZZUxXim9ZC46CKAhlYuSxHcQDkbjHHBRpWk+SEO/NcmgyytDZlLUE0UKhRX2A2Cj0KSA
1128+Q4Uuh8jtdMlVj4pPPrJ8+w17N/+bkXI2MzFsMzW7jutJLEOP1islpDATI3kqQxkcCVlLp153OH56
1129+FaUUQ3kLISTbxrNMzXaQKCyxTuwXVWR1Dds2MfCXjSilWG12/TxBeF5G19hashMg9dO9Tpu1C8ep
1130+zp0G4KSzhbvf8pYrBtLmwnN01k5R2fv9GFY+Sm+tnGD95P9kaPJ2WnPfftlALRayrK+2GBr2/cIv
1131+F6BhWikHEfSU2qkpBXoQNKSFn1QK45nVd/lxpMGkpwym5HHoJ40qErgctHATA188hmFeobiMuGi0
1132++4lfbjZjvjGTsTJCKGqt2FoOVYDEZiEoFKalYw/nMA0N1RVcOLsW1aHadKm2XByhKBX8WRpduST9
1133+pv5aeD86fzRrBXUOdStf+e+4HivNbgzSoCLLZ56jOj+FlJIWWTbf8kbedd91AzvQbS8j3NbAaxtR
1134+e+kZMlmd6qm/AqBTO8/cUx+mu/Q4w7u/FyOTR8lLlyncFvULT/alv/HufTz20LeorbUvYizFIB3k
1135+U03+bFuRuGHc557S10lDXEQmXHwE2sDnvxzSk34wv5KJiJewIgnREW5/+Cdfmb/94UPtw595ovqR
1136+foMpXiclAxAXcvabAMYrNqsJPTTkolpCfZAKml1/Db2hadTXu7heaJ2DaWiMlmzytkmr46GLNpao
1137+xi9LWG9JAFadrKlF6UmXylrHoeV6/tIJz2H57AtU588ig2CKaWeMH37zjQM7T7gtlp/7L6y88Pt0
1138+auc37OTea8pdwcqV0bUGS89/nNqpT1PecRe54d1RHq+5cXnhs1cOP4BonWLtVPLLeIqt43l+5b1v
1139+4NBXD/Hw556k3XSi8dvQxdhznjzWDSLwKbAhca5iK78Xkv3fK3j5pCdBmZptGuTEjUSz5CfeOPH0
1140+hcXam/dOjnzgscPO2U/+7fLt4Q4aUSMSUSu5rLUfwDL9PU2zltHHRZNxrlsqWUoZnULGwPN8P2to
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
1291+8mIu1DHv6k+hxRV29MaZmygwX7Y4UnYordQ1mnB5WichCuxti9HTGWXbYIoMAqfzFm4AGztjnS9W
1292+7Qdl11ucYHVxTvaAm7ZL3/etie/XZsKmBhl83rI5oG/rZUPlWqCenSjTktIomQ6tLZn+MyULd7H1
1293+6eKDWUrIwg1FIqIqYgSwfn2GwryBoMr4gOV49bKVAMvx6WzRGJ2zyZcsZsomriTg1ydxiOihlakF
1294+cOTYHD88MUPBdjmaXxrSdmSiVJ0AARECGDd8Lu2MUHI8trREOZEziCY28NRzh3j/bRsJAp9Idjvl
1295+8X141hiyGiGS7sYXBUBAPAdhBUHG911EcbnlK7B25pNjG4iyTrLvmmXLfddElJcTbP74t6iRatxL
1296+1a+gRdtCz0DDsgtWVoisgu/6mNUarivhWHnk6OqeAqdmTGaFfrpjKgnH57/vbienCIzYLiBi1A2/
1297+jCLQ686Ri29hoCdJhXCurPe2aFy+LoHleuGEb5Nlpg0bQ1O5OiMS1xQ6YjInyi4/ma81pDWEumlE
1298+k6BNw02qTJsuXT1RfkkV+d+HFhAlBoAD8spZ15b7PpumZfE89h85/Zvrsi2/E48lt6uqRKXqIAkC
1299+PTGFeTNsYe4GYLg+qiwiClB1vJC0YqizarKEq8tYVmFkaKwcTaQyWaPm1GdzhlLNQSmK9LbGqNZs
1300+ZEGgqzfD1HSZeL1xbkSXcWyPH56YWfPhlG2Pj75tB3/0r6Fr6fdv2UyAi3osx7W72rguqSO6Ad6r
1301+42GZje/joxHpvBrf9zBzI+TGDpPq2oikSPhwTrKuJClApiVLdc7GE5an/fnIGLOHUVO9yFoapzrN
1302+3Inv4qISq0tm26rheyZFwyMQwincfS9A8G3UaCuLXgff91+TpIEXYBo1apUaIODZq6eQr9kB//yj
1303+IUq33YtleVy/s40xBWquhy4KmPWEHsXzcU8O8VLJINESh4rNuONzZVuUakrlR69Mk3Q8FuartCU0
1304+XMdnXUeE0myJnOnQkmlB1yErC8w6oUrRFVfZNJhi1PEax8nbHgNRhfaUSloTSSZVgKeke++5p0HQ
1305+RZJ6q0gaxu1lt3hw8/qOkXLV2tPTns7m87mRdDqRdryAtCYTkQU0SaA7phCRIa1KuEHYnTmtSxRs
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
1548+"
1549+ height="63.999981"
1550+ width="64" />
1551+ </g>
1552+ <g
1553+ inkscape:groupmode="layer"
1554+ id="layer3"
1555+ inkscape:label="PLACE YOUR PICTOGRAM HERE"
1556+ style="display:inline" />
1557+ <g
1558+ inkscape:groupmode="layer"
1559+ id="layer2"
1560+ inkscape:label="BADGE"
1561+ style="display:none"
1562+ sodipodi:insensitive="true">
1563+ <g
1564+ style="display:inline"
1565+ transform="translate(-340.00001,-581)"
1566+ id="g4394"
1567+ clip-path="none">
1568+ <g
1569+ id="g855">
1570+ <g
1571+ inkscape:groupmode="maskhelper"
1572+ id="g870"
1573+ clip-path="url(#clipPath873)"
1574+ style="opacity:0.6;filter:url(#filter891)">
1575+ <path
1576+ transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-237.54282)"
1577+ 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"
1578+ sodipodi:ry="12"
1579+ sodipodi:rx="12"
1580+ sodipodi:cy="552.36218"
1581+ sodipodi:cx="252"
1582+ id="path844"
1583+ 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"
1584+ sodipodi:type="arc" />
1585+ </g>
1586+ <g
1587+ id="g862">
1588+ <path
1589+ sodipodi:type="arc"
1590+ 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"
1591+ id="path4398"
1592+ sodipodi:cx="252"
1593+ sodipodi:cy="552.36218"
1594+ sodipodi:rx="12"
1595+ sodipodi:ry="12"
1596+ 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"
1597+ transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-238.54282)" />
1598+ <path
1599+ transform="matrix(1.25,0,0,1.25,33,-100.45273)"
1600+ 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"
1601+ sodipodi:ry="12"
1602+ sodipodi:rx="12"
1603+ sodipodi:cy="552.36218"
1604+ sodipodi:cx="252"
1605+ id="path4400"
1606+ 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"
1607+ sodipodi:type="arc" />
1608+ <path
1609+ sodipodi:type="star"
1610+ 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"
1611+ id="path4459"
1612+ sodipodi:sides="5"
1613+ sodipodi:cx="666.19574"
1614+ sodipodi:cy="589.50385"
1615+ sodipodi:r1="7.2431178"
1616+ sodipodi:r2="4.3458705"
1617+ sodipodi:arg1="1.0471976"
1618+ sodipodi:arg2="1.6755161"
1619+ inkscape:flatsided="false"
1620+ inkscape:rounded="0.1"
1621+ inkscape:randomized="0"
1622+ 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"
1623+ transform="matrix(1.511423,-0.16366377,0.16366377,1.511423,-755.37346,-191.93651)" />
1624+ </g>
1625+ </g>
1626+ </g>
1627+ </g>
1628+</svg>
1629
1630=== renamed file 'icon.svg' => 'icon.svg.moved'
1631=== added file 'metadata.yaml'
1632--- metadata.yaml 1970-01-01 00:00:00 +0000
1633+++ metadata.yaml 2015-08-21 21:55:27 +0000
1634@@ -0,0 +1,12 @@
1635+name: apache-flume-hdfs
1636+summary: Ingest data into HDFS
1637+maintainer: Kevin Monroe <kevin.monroe@canonical.com>
1638+description: |
1639+ Collect, aggregate, and move large amounts of data into HDFS.
1640+tags: ["applications", "bigdata", "hadoop", "apache"]
1641+provides:
1642+ hadoop-plugin:
1643+ interface: hadoop-plugin
1644+ scope: container
1645+ flume-agent:
1646+ interface: flume-agent
1647
1648=== renamed file 'metadata.yaml' => 'metadata.yaml.moved'
1649=== added directory 'resources'
1650=== renamed directory 'resources' => 'resources.moved'
1651=== added file 'resources.yaml'
1652--- resources.yaml 1970-01-01 00:00:00 +0000
1653+++ resources.yaml 2015-08-21 21:55:27 +0000
1654@@ -0,0 +1,12 @@
1655+options:
1656+ output_dir: /home/ubuntu/resources
1657+resources:
1658+ pathlib:
1659+ pypi: path.py>=7.0
1660+ jujubigdata:
1661+ pypi: jujubigdata>=4.0.0,<5.0.0
1662+optional_resources:
1663+ flume-x86_64:
1664+ url: https://git.launchpad.net/bigdata-data/plain/apache/x86_64/apache-flume-1.6.0-bin.tar.gz?id=c34a21c939f5fce9ab89b95d65fe2df50e7bbab0
1665+ hash: defd21ad8d2b6f28cc0a16b96f652099
1666+ hash_type: md5
1667
1668=== renamed file 'resources.yaml' => 'resources.yaml.moved'
1669=== added directory 'resources/python'
1670=== added file 'resources/python/PyYAML-3.11.tar.gz'
1671Binary 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:27 +0000 differ
1672=== added file 'resources/python/charmhelpers-0.3.1.tar.gz'
1673Binary 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:27 +0000 differ
1674=== added file 'resources/python/jujuresources-0.2.9.tar.gz'
1675Binary 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:27 +0000 differ
1676=== added file 'resources/python/pyaml-15.5.7.tar.gz'
1677Binary 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:27 +0000 differ
1678=== added file 'resources/python/six-1.9.0-py2.py3-none-any.whl'
1679Binary 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:27 +0000 differ
1680=== added directory 'templates'
1681=== renamed directory 'templates' => 'templates.moved'
1682=== added file 'templates/flume.conf.j2'
1683--- templates/flume.conf.j2 1970-01-01 00:00:00 +0000
1684+++ templates/flume.conf.j2 2015-08-21 21:55:27 +0000
1685@@ -0,0 +1,32 @@
1686+# list sources, sinks, and channels in the agent
1687+a1.sources = r1
1688+a1.sinks = k1
1689+a1.channels = c1
1690+
1691+# source properties
1692+a1.sources.r1.type = {{ config['protocol'] }}
1693+a1.sources.r1.channels = c1
1694+a1.sources.r1.bind = 0.0.0.0
1695+a1.sources.r1.port = {{ config['source_port'] }}
1696+{# use the following configuration if setting the port in dist.yaml
1697+a1.sources.r1.port = {{ dist_config['ports']['avro'].values()[0] }}
1698+#}
1699+
1700+# channel properties
1701+a1.channels.c1.type = memory
1702+a1.channels.c1.capacity = {{ config['channel_capacity']}}
1703+a1.channels.c1.transactionCapacity = {{ config['channel_transaction_capacity']}}
1704+
1705+# sink properties
1706+a1.sinks.k1.type = hdfs
1707+a1.sinks.k1.channel = c1
1708+a1.sinks.k1.hdfs.fileType = DataStream
1709+a1.sinks.k1.hdfs.writeFormat = Text
1710+a1.sinks.k1.hdfs.path = /user/flume/%{event_dir}/%y-%m-%d/%H
1711+a1.sinks.k1.hdfs.useLocalTimeStamp = true
1712+a1.sinks.k1.serializer = {{ config['sink_serializer'] }}
1713+a1.sinks.k1.serializer.compressionCodec = {{ config['sink_compression'] }}
1714+{% if config['sink_serializer'] == 'avro_event' %}
1715+# suffix must be .avro for MapRed jobs to work with AVRO serialized files
1716+a1.sinks.k1.hdfs.fileSuffix = .avro
1717+{% endif %}
1718
1719=== added directory 'tests'
1720=== renamed directory 'tests' => 'tests.moved'
1721=== added file 'tests/00-setup'
1722--- tests/00-setup 1970-01-01 00:00:00 +0000
1723+++ tests/00-setup 2015-08-21 21:55:27 +0000
1724@@ -0,0 +1,5 @@
1725+#!/bin/bash
1726+
1727+sudo add-apt-repository ppa:juju/stable -y
1728+sudo apt-get update
1729+sudo apt-get install python3 amulet -y
1730
1731=== added directory 'tests/remote'
1732=== added file 'tests/remote/test_dist_config.py'
1733--- tests/remote/test_dist_config.py 1970-01-01 00:00:00 +0000
1734+++ tests/remote/test_dist_config.py 2015-08-21 21:55:27 +0000
1735@@ -0,0 +1,62 @@
1736+#!/usr/bin/env python
1737+
1738+import grp
1739+import pwd
1740+import unittest
1741+
1742+from charmhelpers.contrib import bigdata
1743+
1744+
1745+class TestDistConfig(unittest.TestCase):
1746+ """
1747+ Test that the ``dist.yaml`` settings were applied properly, such as users, groups, and dirs.
1748+
1749+ This is done as a remote test on the deployed unit rather than a regular
1750+ test under ``tests/`` because filling in the ``dist.yaml`` requires Juju
1751+ context (e.g., config).
1752+ """
1753+ @classmethod
1754+ def setUpClass(cls):
1755+ cls.hadoop = bigdata.handlers.apache.HadoopBase()
1756+
1757+ def test_groups(self):
1758+ for name in self.hadoop.groups:
1759+ try:
1760+ grp.getgrnam(name)
1761+ except KeyError:
1762+ self.fail('Group {} is missing'.format(name))
1763+
1764+ def test_users(self):
1765+ for username, details in self.hadoop.users.items():
1766+ try:
1767+ user = pwd.getpwnam(username)
1768+ except KeyError:
1769+ self.fail('User {} is missing'.format(username))
1770+ for groupname in details['groups']:
1771+ try:
1772+ group = grp.getgrnam(groupname)
1773+ except KeyError:
1774+ self.fail('Group {} referenced by user {} does not exist'.format(
1775+ groupname, username))
1776+ if group.gr_gid != user.pw_gid:
1777+ self.assertIn(username, group.gr_mem, 'User {} not in group {}'.format(
1778+ username, groupname))
1779+
1780+ def test_dirs(self):
1781+ for name, details in self.hadoop.managed_dirs.items():
1782+ dirpath = details['path']
1783+ self.assertTrue(dirpath.isdir(), 'Dir {} is missing'.format(name))
1784+ stat = dirpath.stat()
1785+ owner = pwd.getpwuid(stat.st_uid).pw_name
1786+ group = grp.getgrgid(stat.st_gid).gr_name
1787+ perms = stat.st_mode & ~0o40000
1788+ self.assertEqual(owner, details.get('owner', 'root'),
1789+ 'Dir {} ({}) has wrong owner: {}'.format(name, dirpath, owner))
1790+ self.assertEqual(group, details.get('group', 'root'),
1791+ 'Dir {} ({}) has wrong group: {}'.format(name, dirpath, group))
1792+ self.assertEqual(perms, details.get('perms', 0o744),
1793+ 'Dir {} ({}) has wrong perms: 0o{:o}'.format(name, dirpath, perms))
1794+
1795+
1796+if __name__ == '__main__':
1797+ unittest.main()

Subscribers

People subscribed via source and target branches