Merge lp:~mbruzek/charms/trusty/fail2ban/trunk into lp:~lazypower/charms/trusty/fail2ban/trunk

Proposed by Matt Bruzek
Status: Needs review
Proposed branch: lp:~mbruzek/charms/trusty/fail2ban/trunk
Merge into: lp:~lazypower/charms/trusty/fail2ban/trunk
Diff against target: 584 lines (+121/-71)
12 files modified
lib/charmhelpers/core/fstab.py (+10/-8)
lib/charmhelpers/core/hookenv.py (+9/-7)
lib/charmhelpers/core/host.py (+12/-11)
lib/charmhelpers/core/services/helpers.py (+9/-5)
lib/charmhelpers/core/templating.py (+2/-1)
lib/charmhelpers/fetch/__init__.py (+20/-16)
lib/charmhelpers/fetch/archiveurl.py (+44/-16)
lib/charmhelpers/fetch/bzrurl.py (+5/-1)
lib/charmhelpers/fetch/giturl.py (+6/-2)
metadata.yaml (+2/-2)
templates/jail.local (+1/-1)
tests/00-setup (+1/-1)
To merge this branch: bzr merge lp:~mbruzek/charms/trusty/fail2ban/trunk
Reviewer Review Type Date Requested Status
Charles Butler Pending
Review via email: mp+242671@code.launchpad.net

Description of the change

Found some things that needed to be updated in trusty.

jail.local template
metadata.yaml
00-setup
sync charm-tools

To post a comment you must log in.

Unmerged revisions

5. By Matt Bruzek

Added maxretries to the ssh section in template, updated the metadata with the security tag, synchronized charm helpers.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/charmhelpers/core/fstab.py'
2--- lib/charmhelpers/core/fstab.py 2014-10-22 04:18:26 +0000
3+++ lib/charmhelpers/core/fstab.py 2014-11-24 15:36:56 +0000
4@@ -3,10 +3,11 @@
5
6 __author__ = 'Jorge Niedbalski R. <jorge.niedbalski@canonical.com>'
7
8+import io
9 import os
10
11
12-class Fstab(file):
13+class Fstab(io.FileIO):
14 """This class extends file in order to implement a file reader/writer
15 for file `/etc/fstab`
16 """
17@@ -24,8 +25,8 @@
18 options = "defaults"
19
20 self.options = options
21- self.d = d
22- self.p = p
23+ self.d = int(d)
24+ self.p = int(p)
25
26 def __eq__(self, o):
27 return str(self) == str(o)
28@@ -45,7 +46,7 @@
29 self._path = path
30 else:
31 self._path = self.DEFAULT_PATH
32- file.__init__(self, self._path, 'r+')
33+ super(Fstab, self).__init__(self._path, 'rb+')
34
35 def _hydrate_entry(self, line):
36 # NOTE: use split with no arguments to split on any
37@@ -58,8 +59,9 @@
38 def entries(self):
39 self.seek(0)
40 for line in self.readlines():
41+ line = line.decode('us-ascii')
42 try:
43- if not line.startswith("#"):
44+ if line.strip() and not line.startswith("#"):
45 yield self._hydrate_entry(line)
46 except ValueError:
47 pass
48@@ -75,14 +77,14 @@
49 if self.get_entry_by_attr('device', entry.device):
50 return False
51
52- self.write(str(entry) + '\n')
53+ self.write((str(entry) + '\n').encode('us-ascii'))
54 self.truncate()
55 return entry
56
57 def remove_entry(self, entry):
58 self.seek(0)
59
60- lines = self.readlines()
61+ lines = [l.decode('us-ascii') for l in self.readlines()]
62
63 found = False
64 for index, line in enumerate(lines):
65@@ -97,7 +99,7 @@
66 lines.remove(line)
67
68 self.seek(0)
69- self.write(''.join(lines))
70+ self.write(''.join(lines).encode('us-ascii'))
71 self.truncate()
72 return True
73
74
75=== modified file 'lib/charmhelpers/core/hookenv.py'
76--- lib/charmhelpers/core/hookenv.py 2014-10-22 04:18:26 +0000
77+++ lib/charmhelpers/core/hookenv.py 2014-11-24 15:36:56 +0000
78@@ -9,9 +9,11 @@
79 import yaml
80 import subprocess
81 import sys
82-import UserDict
83 from subprocess import CalledProcessError
84
85+import six
86+from six.moves import UserDict
87+
88 CRITICAL = "CRITICAL"
89 ERROR = "ERROR"
90 WARNING = "WARNING"
91@@ -67,12 +69,12 @@
92 subprocess.call(command)
93
94
95-class Serializable(UserDict.IterableUserDict):
96+class Serializable(UserDict):
97 """Wrapper, an object that can be serialized to yaml or json"""
98
99 def __init__(self, obj):
100 # wrap the object
101- UserDict.IterableUserDict.__init__(self)
102+ UserDict.__init__(self)
103 self.data = obj
104
105 def __getattr__(self, attr):
106@@ -218,7 +220,7 @@
107 prev_keys = []
108 if self._prev_dict is not None:
109 prev_keys = self._prev_dict.keys()
110- return list(set(prev_keys + dict.keys(self)))
111+ return list(set(prev_keys + list(dict.keys(self))))
112
113 def load_previous(self, path=None):
114 """Load previous copy of config from disk.
115@@ -269,7 +271,7 @@
116
117 """
118 if self._prev_dict:
119- for k, v in self._prev_dict.iteritems():
120+ for k, v in six.iteritems(self._prev_dict):
121 if k not in self:
122 self[k] = v
123 with open(self.path, 'w') as f:
124@@ -306,7 +308,7 @@
125 return json.loads(subprocess.check_output(_args))
126 except ValueError:
127 return None
128- except CalledProcessError, e:
129+ except CalledProcessError as e:
130 if e.returncode == 2:
131 return None
132 raise
133@@ -318,7 +320,7 @@
134 relation_cmd_line = ['relation-set']
135 if relation_id is not None:
136 relation_cmd_line.extend(('-r', relation_id))
137- for k, v in (relation_settings.items() + kwargs.items()):
138+ for k, v in (list(relation_settings.items()) + list(kwargs.items())):
139 if v is None:
140 relation_cmd_line.append('{}='.format(k))
141 else:
142
143=== modified file 'lib/charmhelpers/core/host.py'
144--- lib/charmhelpers/core/host.py 2014-10-22 04:18:26 +0000
145+++ lib/charmhelpers/core/host.py 2014-11-24 15:36:56 +0000
146@@ -14,11 +14,12 @@
147 import subprocess
148 import hashlib
149 from contextlib import contextmanager
150-
151 from collections import OrderedDict
152
153-from hookenv import log
154-from fstab import Fstab
155+import six
156+
157+from .hookenv import log
158+from .fstab import Fstab
159
160
161 def service_start(service_name):
162@@ -130,7 +131,7 @@
163 subprocess.check_call(cmd)
164
165
166-def mkdir(path, owner='root', group='root', perms=0555, force=False):
167+def mkdir(path, owner='root', group='root', perms=0o555, force=False):
168 """Create a directory"""
169 log("Making dir {} {}:{} {:o}".format(path, owner, group,
170 perms))
171@@ -146,7 +147,7 @@
172 os.chown(realpath, uid, gid)
173
174
175-def write_file(path, content, owner='root', group='root', perms=0444):
176+def write_file(path, content, owner='root', group='root', perms=0o444):
177 """Create or overwrite a file with the contents of a string"""
178 log("Writing file {} {}:{} {:o}".format(path, owner, group, perms))
179 uid = pwd.getpwnam(owner).pw_uid
180@@ -177,7 +178,7 @@
181 cmd_args.extend([device, mountpoint])
182 try:
183 subprocess.check_output(cmd_args)
184- except subprocess.CalledProcessError, e:
185+ except subprocess.CalledProcessError as e:
186 log('Error mounting {} at {}\n{}'.format(device, mountpoint, e.output))
187 return False
188
189@@ -191,7 +192,7 @@
190 cmd_args = ['umount', mountpoint]
191 try:
192 subprocess.check_output(cmd_args)
193- except subprocess.CalledProcessError, e:
194+ except subprocess.CalledProcessError as e:
195 log('Error unmounting {}\n{}'.format(mountpoint, e.output))
196 return False
197
198@@ -218,8 +219,8 @@
199 """
200 if os.path.exists(path):
201 h = getattr(hashlib, hash_type)()
202- with open(path, 'r') as source:
203- h.update(source.read()) # IGNORE:E1101 - it does have update
204+ with open(path, 'rb') as source:
205+ h.update(source.read())
206 return h.hexdigest()
207 else:
208 return None
209@@ -297,7 +298,7 @@
210 if length is None:
211 length = random.choice(range(35, 45))
212 alphanumeric_chars = [
213- l for l in (string.letters + string.digits)
214+ l for l in (string.ascii_letters + string.digits)
215 if l not in 'l0QD1vAEIOUaeiou']
216 random_chars = [
217 random.choice(alphanumeric_chars) for _ in range(length)]
218@@ -306,7 +307,7 @@
219
220 def list_nics(nic_type):
221 '''Return a list of nics of given type(s)'''
222- if isinstance(nic_type, basestring):
223+ if isinstance(nic_type, six.string_types):
224 int_types = [nic_type]
225 else:
226 int_types = nic_type
227
228=== modified file 'lib/charmhelpers/core/services/helpers.py'
229--- lib/charmhelpers/core/services/helpers.py 2014-10-22 04:18:26 +0000
230+++ lib/charmhelpers/core/services/helpers.py 2014-11-24 15:36:56 +0000
231@@ -196,7 +196,7 @@
232 if not os.path.isabs(file_name):
233 file_name = os.path.join(hookenv.charm_dir(), file_name)
234 with open(file_name, 'w') as file_stream:
235- os.fchmod(file_stream.fileno(), 0600)
236+ os.fchmod(file_stream.fileno(), 0o600)
237 yaml.dump(config_data, file_stream)
238
239 def read_context(self, file_name):
240@@ -211,15 +211,19 @@
241
242 class TemplateCallback(ManagerCallback):
243 """
244- Callback class that will render a Jinja2 template, for use as a ready action.
245-
246- :param str source: The template source file, relative to `$CHARM_DIR/templates`
247+ Callback class that will render a Jinja2 template, for use as a ready
248+ action.
249+
250+ :param str source: The template source file, relative to
251+ `$CHARM_DIR/templates`
252+
253 :param str target: The target to write the rendered template to
254 :param str owner: The owner of the rendered file
255 :param str group: The group of the rendered file
256 :param int perms: The permissions of the rendered file
257 """
258- def __init__(self, source, target, owner='root', group='root', perms=0444):
259+ def __init__(self, source, target,
260+ owner='root', group='root', perms=0o444):
261 self.source = source
262 self.target = target
263 self.owner = owner
264
265=== modified file 'lib/charmhelpers/core/templating.py'
266--- lib/charmhelpers/core/templating.py 2014-10-22 04:18:26 +0000
267+++ lib/charmhelpers/core/templating.py 2014-11-24 15:36:56 +0000
268@@ -4,7 +4,8 @@
269 from charmhelpers.core import hookenv
270
271
272-def render(source, target, context, owner='root', group='root', perms=0444, templates_dir=None):
273+def render(source, target, context, owner='root', group='root',
274+ perms=0o444, templates_dir=None):
275 """
276 Render a template.
277
278
279=== modified file 'lib/charmhelpers/fetch/__init__.py'
280--- lib/charmhelpers/fetch/__init__.py 2014-11-20 21:55:44 +0000
281+++ lib/charmhelpers/fetch/__init__.py 2014-11-24 15:36:56 +0000
282@@ -5,10 +5,6 @@
283 from charmhelpers.core.host import (
284 lsb_release
285 )
286-from urlparse import (
287- urlparse,
288- urlunparse,
289-)
290 import subprocess
291 from charmhelpers.core.hookenv import (
292 config,
293@@ -16,6 +12,9 @@
294 )
295 import os
296
297+import six
298+from six.moves.urllib.parse import urlparse, urlunparse
299+
300
301 CLOUD_ARCHIVE = """# Ubuntu Cloud Archive
302 deb http://ubuntu-cloud.archive.canonical.com/ubuntu {} main
303@@ -69,11 +68,16 @@
304
305 # The order of this list is very important. Handlers should be listed in from
306 # least- to most-specific URL matching.
307-FETCH_HANDLERS = (
308- 'charmhelpers.fetch.archiveurl.ArchiveUrlFetchHandler',
309- 'charmhelpers.fetch.bzrurl.BzrUrlFetchHandler',
310- 'charmhelpers.fetch.giturl.GitUrlFetchHandler',
311-)
312+if six.PY2:
313+ FETCH_HANDLERS = (
314+ 'charmhelpers.fetch.archiveurl.ArchiveUrlFetchHandler',
315+ 'charmhelpers.fetch.bzrurl.BzrUrlFetchHandler',
316+ 'charmhelpers.fetch.giturl.GitUrlFetchHandler',
317+ )
318+else:
319+ FETCH_HANDLERS = (
320+ 'charmhelpers.fetch.archiveurl.ArchiveUrlFetchHandler',
321+ )
322
323 APT_NO_LOCK = 100 # The return code for "couldn't acquire lock" in APT.
324 APT_NO_LOCK_RETRY_DELAY = 10 # Wait 10 seconds between apt lock checks.
325@@ -149,7 +153,7 @@
326 cmd = ['apt-get', '--assume-yes']
327 cmd.extend(options)
328 cmd.append('install')
329- if isinstance(packages, basestring):
330+ if isinstance(packages, six.string_types):
331 cmd.append(packages)
332 else:
333 cmd.extend(packages)
334@@ -182,7 +186,7 @@
335 def apt_purge(packages, fatal=False):
336 """Purge one or more packages"""
337 cmd = ['apt-get', '--assume-yes', 'purge']
338- if isinstance(packages, basestring):
339+ if isinstance(packages, six.string_types):
340 cmd.append(packages)
341 else:
342 cmd.extend(packages)
343@@ -193,7 +197,7 @@
344 def apt_hold(packages, fatal=False):
345 """Hold one or more packages"""
346 cmd = ['apt-mark', 'hold']
347- if isinstance(packages, basestring):
348+ if isinstance(packages, six.string_types):
349 cmd.append(packages)
350 else:
351 cmd.extend(packages)
352@@ -260,7 +264,7 @@
353
354 if key:
355 if '-----BEGIN PGP PUBLIC KEY BLOCK-----' in key:
356- with NamedTemporaryFile() as key_file:
357+ with NamedTemporaryFile('w+') as key_file:
358 key_file.write(key)
359 key_file.flush()
360 key_file.seek(0)
361@@ -297,14 +301,14 @@
362 sources = safe_load((config(sources_var) or '').strip()) or []
363 keys = safe_load((config(keys_var) or '').strip()) or None
364
365- if isinstance(sources, basestring):
366+ if isinstance(sources, six.string_types):
367 sources = [sources]
368
369 if keys is None:
370 for source in sources:
371 add_source(source, None)
372 else:
373- if isinstance(keys, basestring):
374+ if isinstance(keys, six.string_types):
375 keys = [keys]
376
377 if len(sources) != len(keys):
378@@ -401,7 +405,7 @@
379 while result is None or result == APT_NO_LOCK:
380 try:
381 result = subprocess.check_call(cmd, env=env)
382- except subprocess.CalledProcessError, e:
383+ except subprocess.CalledProcessError as e:
384 retry_count = retry_count + 1
385 if retry_count > APT_NO_LOCK_RETRY_COUNT:
386 raise
387
388=== modified file 'lib/charmhelpers/fetch/archiveurl.py'
389--- lib/charmhelpers/fetch/archiveurl.py 2014-10-22 04:18:26 +0000
390+++ lib/charmhelpers/fetch/archiveurl.py 2014-11-24 15:36:56 +0000
391@@ -1,8 +1,14 @@
392 import os
393-import urllib2
394-from urllib import urlretrieve
395-import urlparse
396 import hashlib
397+import re
398+
399+import six
400+from six.moves.urllib.request import (
401+ build_opener, install_opener, urlopen, urlretrieve,
402+ HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler,
403+)
404+from six.moves.urllib.parse import urlparse, urlunparse, parse_qs
405+from six.moves.urllib.error import URLError
406
407 from charmhelpers.fetch import (
408 BaseFetchHandler,
409@@ -15,6 +21,24 @@
410 from charmhelpers.core.host import mkdir, check_hash
411
412
413+def splituser(host):
414+ '''urllib.splituser(), but six's support of this seems broken'''
415+ _userprog = re.compile('^(.*)@(.*)$')
416+ match = _userprog.match(host)
417+ if match:
418+ return match.group(1, 2)
419+ return None, host
420+
421+
422+def splitpasswd(user):
423+ '''urllib.splitpasswd(), but six's support of this is missing'''
424+ _passwdprog = re.compile('^([^:]*):(.*)$', re.S)
425+ match = _passwdprog.match(user)
426+ if match:
427+ return match.group(1, 2)
428+ return user, None
429+
430+
431 class ArchiveUrlFetchHandler(BaseFetchHandler):
432 """
433 Handler to download archive files from arbitrary URLs.
434@@ -42,20 +66,20 @@
435 """
436 # propogate all exceptions
437 # URLError, OSError, etc
438- proto, netloc, path, params, query, fragment = urlparse.urlparse(source)
439+ proto, netloc, path, params, query, fragment = urlparse(source)
440 if proto in ('http', 'https'):
441- auth, barehost = urllib2.splituser(netloc)
442+ auth, barehost = splituser(netloc)
443 if auth is not None:
444- source = urlparse.urlunparse((proto, barehost, path, params, query, fragment))
445- username, password = urllib2.splitpasswd(auth)
446- passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
447+ source = urlunparse((proto, barehost, path, params, query, fragment))
448+ username, password = splitpasswd(auth)
449+ passman = HTTPPasswordMgrWithDefaultRealm()
450 # Realm is set to None in add_password to force the username and password
451 # to be used whatever the realm
452 passman.add_password(None, source, username, password)
453- authhandler = urllib2.HTTPBasicAuthHandler(passman)
454- opener = urllib2.build_opener(authhandler)
455- urllib2.install_opener(opener)
456- response = urllib2.urlopen(source)
457+ authhandler = HTTPBasicAuthHandler(passman)
458+ opener = build_opener(authhandler)
459+ install_opener(opener)
460+ response = urlopen(source)
461 try:
462 with open(dest, 'w') as dest_file:
463 dest_file.write(response.read())
464@@ -91,17 +115,21 @@
465 url_parts = self.parse_url(source)
466 dest_dir = os.path.join(os.environ.get('CHARM_DIR'), 'fetched')
467 if not os.path.exists(dest_dir):
468- mkdir(dest_dir, perms=0755)
469+ mkdir(dest_dir, perms=0o755)
470 dld_file = os.path.join(dest_dir, os.path.basename(url_parts.path))
471 try:
472 self.download(source, dld_file)
473- except urllib2.URLError as e:
474+ except URLError as e:
475 raise UnhandledSource(e.reason)
476 except OSError as e:
477 raise UnhandledSource(e.strerror)
478- options = urlparse.parse_qs(url_parts.fragment)
479+ options = parse_qs(url_parts.fragment)
480 for key, value in options.items():
481- if key in hashlib.algorithms:
482+ if six.PY2:
483+ algorithms = hashlib.algorithms
484+ else:
485+ algorithms = hashlib.algorithms_available
486+ if key in algorithms:
487 check_hash(dld_file, value, key)
488 if checksum:
489 check_hash(dld_file, checksum, hash_type)
490
491=== modified file 'lib/charmhelpers/fetch/bzrurl.py'
492--- lib/charmhelpers/fetch/bzrurl.py 2014-10-22 04:18:26 +0000
493+++ lib/charmhelpers/fetch/bzrurl.py 2014-11-24 15:36:56 +0000
494@@ -5,6 +5,10 @@
495 )
496 from charmhelpers.core.host import mkdir
497
498+import six
499+if six.PY3:
500+ raise ImportError('bzrlib does not support Python3')
501+
502 try:
503 from bzrlib.branch import Branch
504 except ImportError:
505@@ -42,7 +46,7 @@
506 dest_dir = os.path.join(os.environ.get('CHARM_DIR'), "fetched",
507 branch_name)
508 if not os.path.exists(dest_dir):
509- mkdir(dest_dir, perms=0755)
510+ mkdir(dest_dir, perms=0o755)
511 try:
512 self.branch(source, dest_dir)
513 except OSError as e:
514
515=== modified file 'lib/charmhelpers/fetch/giturl.py'
516--- lib/charmhelpers/fetch/giturl.py 2014-10-22 04:18:26 +0000
517+++ lib/charmhelpers/fetch/giturl.py 2014-11-24 15:36:56 +0000
518@@ -5,6 +5,10 @@
519 )
520 from charmhelpers.core.host import mkdir
521
522+import six
523+if six.PY3:
524+ raise ImportError('GitPython does not support Python 3')
525+
526 try:
527 from git import Repo
528 except ImportError:
529@@ -17,7 +21,7 @@
530 """Handler for git branches via generic and github URLs"""
531 def can_handle(self, source):
532 url_parts = self.parse_url(source)
533- #TODO (mattyw) no support for ssh git@ yet
534+ # TODO (mattyw) no support for ssh git@ yet
535 if url_parts.scheme not in ('http', 'https', 'git'):
536 return False
537 else:
538@@ -36,7 +40,7 @@
539 dest_dir = os.path.join(os.environ.get('CHARM_DIR'), "fetched",
540 branch_name)
541 if not os.path.exists(dest_dir):
542- mkdir(dest_dir, perms=0755)
543+ mkdir(dest_dir, perms=0o755)
544 try:
545 self.clone(source, dest_dir, branch)
546 except OSError as e:
547
548=== modified file 'metadata.yaml'
549--- metadata.yaml 2014-11-21 16:00:12 +0000
550+++ metadata.yaml 2014-11-24 15:36:56 +0000
551@@ -13,8 +13,8 @@
552 file. All filters and actions are given in the config files, thus
553 fail2ban can be adopted to be used with a variety of files and
554 firewalls.
555-categories:
556- - misc
557+tags:
558+ - security
559 subordinate: true
560 requires:
561 juju-info:
562
563=== modified file 'templates/jail.local'
564--- templates/jail.local 2014-10-22 04:18:26 +0000
565+++ templates/jail.local 2014-11-24 15:36:56 +0000
566@@ -95,7 +95,7 @@
567 port = ssh
568 filter = sshd
569 logpath = /var/log/auth.log
570-maxretry = 6
571+maxretry = {{maxretry}}
572
573 [dropbear]
574
575
576=== modified file 'tests/00-setup'
577--- tests/00-setup 2014-11-20 21:55:44 +0000
578+++ tests/00-setup 2014-11-24 15:36:56 +0000
579@@ -2,4 +2,4 @@
580
581 sudo add-apt-repository ppa:juju/stable -y
582 sudo apt-get update -qq
583-sudo apt-get install amulet python3-requests -y
584+sudo apt-get install amulet -y

Subscribers

People subscribed via source and target branches

to all changes: