Codebase list bundlewrap / debian/3.1.0-1
Imported Debian patch 3.1.0-1 Jonathan Carter 6 years ago
18 changed file(s) with 257 addition(s) and 5 deletion(s). Raw diff Collapse all Expand all
0 # 3.1.0
1
2 2017-10-10
3
4 * added pkg_opkg items
5 * added `bw test -s`
6 * improved error messages for unknown reverse triggers
7 * fixed hash_method md5 on user items
8 * fixed cursor sometimes not being restored
9
10
011 # 3.0.3
112
213 2017-10-04
00 # -*- coding: utf-8 -*-
11 from __future__ import unicode_literals
22
3 VERSION = (3, 0, 3)
3 VERSION = (3, 1, 0)
44 VERSION_STRING = ".".join([str(v) for v in VERSION])
66 from os.path import abspath, dirname
77 from pipes import quote
88 from sys import argv, exit, stderr, stdout
9 from traceback import print_exc
9 from traceback import format_exc, print_exc
1010
1111
1212 from ..exceptions import NoSuchRepository, MissingRepoDependency
132132 "{x} {path} "
133133 "is not a BundleWrap repository."
134134 ).format(path=quote(abspath(pargs.repo_path)), x=red("!!!")))
135 io.deactivate()
135136 exit(1)
136137 else:
137138 path = dirname(path)
138139 except MissingRepoDependency as exc:
139140 io.stderr(str(exc))
141 io.deactivate()
142 exit(1)
143 except Exception:
144 io.stderr(format_exc())
145 io.deactivate()
140146 exit(1)
141147
142148 # convert all string args into text
851851 help=_("check for bundles not assigned to any node"),
852852 )
853853 parser_test.add_argument(
854 "-s",
855 "--secret-rotation",
856 default=None,
857 dest='ignore_secret_identifiers',
858 help=_("ensure every string passed to repo.vault.[human_]password_for() is used at least "
859 "twice (using it only once means you're probably managing only one end of an "
860 "authentication, making it dangerous to rotate your .secrets.cfg); PATTERNS is a "
861 "comma-separated list of regex patterns for strings to ignore in this check "
862 "(just pass an empty string if you don't need to ignore anything)"),
863 metavar="PATTERNS",
864 type=str,
865 )
866 parser_test.add_argument(
854867 "-S",
855868 "--subgroup-loops",
856869 action='store_true',
11 from __future__ import unicode_literals
22
33 from copy import copy
4 from re import compile as compile_regex
45 from sys import exit
56
67 from ..deps import DummyItem
119120 exit(1)
120121
121122
123 def test_secret_identifiers(repo, ignore_patterns):
124 # create a new object to make sure we don't double-count any calls
125 # from previous tests
126 pristine_repo = Repository(repo.path)
127 pristine_repo.hash() # shortest way to create all configuration
128 patterns = set()
129 for raw_pattern in ignore_patterns.split(","):
130 if raw_pattern:
131 patterns.add(compile_regex(raw_pattern))
132 found_something = False
133 for identifier, call_count in pristine_repo.vault._call_log.items():
134 if call_count == 1:
135 ignore = False
136 for pattern in patterns:
137 if pattern.search(identifier):
138 ignore = True
139 break
140 if not ignore:
141 io.stderr(_(
142 "{x} identifier passed only once to repo.vault.[human_]password_for(): {i}"
143 ).format(
144 i=bold(identifier),
145 x=red("✘"),
146 ))
147 found_something = True
148 if found_something:
149 exit(1)
150 else:
151 io.stdout(_(
152 "{x} all arguments to repo.vault.[human_]password_for() used at least twice"
153 ).format(x=green("✓")))
154
155
122156 def test_empty_groups(repo):
123157 empty_groups = set()
124158 for group in repo.groups:
248282 args['determinism_metadata'] > 1 or
249283 args['hooks_node'] or
250284 args['hooks_repo'] or
285 args['ignore_secret_identifiers'] is not None or
251286 args['items'] or
252287 args['metadata_collisions'] or
253288 args['orphaned_bundles'] or
270305 args['metadata_collisions'] = True
271306 args['subgroup_loops'] = True
272307
308 if args['ignore_secret_identifiers'] is not None and not QUIT_EVENT.is_set():
309 test_secret_identifiers(repo, args['ignore_secret_identifiers'])
310
273311 if args['plugin_conflicts'] and not QUIT_EVENT.is_set():
274312 test_plugin_conflicts(repo)
275313
440440 """
441441 for item in items.values():
442442 for triggering_item_id in item.triggered_by:
443 triggering_item = items[triggering_item_id]
443 try:
444 triggering_item = items[triggering_item_id]
445 except KeyError:
446 raise ItemDependencyError(_(
447 "'{item}' in bundle '{bundle}' has a reverse trigger (triggered_by) "
448 "on '{dep}', which doesn't exist"
449 ).format(
450 item=item.id,
451 bundle=item.bundle.name,
452 dep=triggering_item_id,
453 ))
444454 if triggering_item.id.startswith("bundle:"): # bundle items
445455 bundle_name = triggering_item.id.split(":")[1]
446456 for actual_triggering_item in items.values():
458468 else:
459469 triggering_item.triggers.append(item.id)
460470 for preceded_item_id in item.precedes:
461 preceded_item = items[preceded_item_id]
471 try:
472 preceded_item = items[preceded_item_id]
473 except KeyError:
474 raise ItemDependencyError(_(
475 "'{item}' in bundle '{bundle}' has a reverse trigger (precedes) "
476 "on '{dep}', which doesn't exist"
477 ).format(
478 item=item.id,
479 bundle=item.bundle.name,
480 dep=preceded_item_id,
481 ))
462482 if preceded_item.id.startswith("bundle:"): # bundle items
463483 bundle_name = preceded_item.id.split(":")[1]
464484 for actual_preceded_item in items.values():
0 # -*- coding: utf-8 -*-
1 from __future__ import unicode_literals
2
3 from pipes import quote
4
5 from bundlewrap.items.pkg import Pkg
6
7
8 class OpkgPkg(Pkg):
9 """
10 A package installed by opkg.
11 """
12 BUNDLE_ATTRIBUTE_NAME = "pkg_opkg"
13 ITEM_TYPE_NAME = "pkg_opkg"
14
15 @classmethod
16 def block_concurrent(cls, node_os, node_os_version):
17 return ["pkg_opkg"]
18
19 def pkg_all_installed(self):
20 result = self.node.run("opkg list-installed")
21 for line in result.stdout.decode('utf-8').strip().split("\n"):
22 if line:
23 yield "{}:{}".format(self.ITEM_TYPE_NAME, line.split()[0])
24
25 def pkg_install(self):
26 self.node.run("opkg install {}".format(quote(self.name)), may_fail=True)
27
28 def pkg_installed(self):
29 result = self.node.run(
30 "opkg status {} | grep ^Status: | grep installed".format(quote(self.name)),
31 may_fail=True,
32 )
33 return result.return_code == 0
34
35 def pkg_remove(self):
36 self.node.run("opkg remove {}".format(quote(self.name)), may_fail=True)
243243 rounds=8, # default rounds for OpenBSD accounts
244244 salt=_DEFAULT_BCRYPT_SALT if salt is None else salt,
245245 )
246 elif attributes.get('hash_method') == 'md5':
247 attributes['password_hash'] = hash_method.encrypt(
248 force_text(attributes['password']),
249 salt=_DEFAULT_SALT if salt is None else salt,
250 )
246251 else:
247252 attributes['password_hash'] = hash_method.encrypt(
248253 force_text(attributes['password']),
327327 'amazonlinux',
328328 'arch',
329329 'opensuse',
330 'openwrt',
330331 'gentoo',
331332 'linux',
332333 ) + \
7474 def __init__(self, repo):
7575 self.repo = repo
7676 self.keys = self._load_keys()
77 self._call_log = {}
7778
7879 def _decrypt(self, cryptotext=None, key='encrypt'):
7980 """
310311 def human_password_for(
311312 self, identifier, digits=2, key='generate', per_word=3, words=4,
312313 ):
314 self._call_log.setdefault(identifier, 0)
315 self._call_log[identifier] += 1
313316 return Fault(
314317 self._generate_human_password,
315318 identifier=identifier,
320323 )
321324
322325 def password_for(self, identifier, key='generate', length=32, symbols=False):
326 self._call_log.setdefault(identifier, 0)
327 self._call_log[identifier] += 1
323328 return Fault(
324329 self._generate_password,
325330 identifier=identifier,
383383 except ProcessLookupError:
384384 pass
385385 self._clear_last_job()
386 if TTY:
387 write_to_stream(STDOUT_WRITER, SHOW_CURSOR)
386388 _exit(1)
387389 else:
388390 if SHUTDOWN_EVENT_SOFT.wait(0.1):
0 bundlewrap (3.1.0-1) unstable; urgency=medium
1
2 * New upstream release
3
4 -- Jonathan Carter <jcc@debian.org> Tue, 10 Oct 2017 14:39:46 +0200
5
06 bundlewrap (3.0.3-1) unstable; urgency=medium
17
28 * New upstream release
0 # opkg package items
1
2 Handles packages installed by `opkg` on OpenWRT/LEDE.
3
4 pkg_opkg = {
5 "foopkg": {
6 "installed": True, # default
7 },
8 "bar": {
9 "installed": False,
10 },
11 }
12
13 <br><br>
14
15 # Attribute reference
16
17 See also: [The list of generic builtin item attributes](../repo/items.py.md#builtin-item-attributes)
18
19 <hr>
20
21 ## installed
22
23 `True` when the package is expected to be present on the system; `False` if it should be removed.
4141 <tr><td><a href="../../items/group">group</a></td><td><code>groups</code></td><td>Manages groups by wrapping <code>groupadd</code>, <code>groupmod</code> and <code>groupdel</code></td></tr>
4242 <tr><td><a href="../../items/pkg_apt">pkg_apt</a></td><td><code>pkg_apt</code></td><td>Installs and removes packages with APT</td></tr>
4343 <tr><td><a href="../../items/pkg_dnf">pkg_dnf</a></td><td><code>pkg_dnf</code></td><td>Installs and removes packages with dnf</td></tr>
44 <tr><td><a href="../../items/pkg_opkg">pkg_opkg</a></td><td><code>pkg_opkg</code></td><td>Installs and removes packages with opkg</td></tr>
4445 <tr><td><a href="../../items/pkg_pacman">pkg_pacman</a></td><td><code>pkg_pacman</code></td><td>Installs and removes packages with pacman</td></tr>
4546 <tr><td><a href="../../items/pkg_pip">pkg_pip</a></td><td><code>pkg_pip</code></td><td>Installs and removes Python packages with pip</td></tr>
4647 <tr><td><a href="../../items/pkg_snap">pkg_snap</a></td><td><code>pkg_snap</code></td><td>Installs and removes packages with snap</td></tr>
3939 - group: items/group.md
4040 - pkg_apt: items/pkg_apt.md
4141 - pkg_dnf: items/pkg_dnf.md
42 - pkg_opkg: items/pkg_opkg.md
4243 - pkg_pacman: items/pkg_pacman.md
4344 - pkg_pip: items/pkg_pip.md
4445 - pkg_snap: items/pkg_snap.md
1515
1616 setup(
1717 name="bundlewrap",
18 version="3.0.3",
18 version="3.1.0",
1919 description="Config management with Python",
2020 long_description=(
2121 "By allowing for easy and low-overhead config management, BundleWrap fills the gap between complex deployments using Chef or Puppet and old school system administration over SSH.\n"
0 from bundlewrap.utils.testing import host_os, make_repo, run
1
2
3 def test_run_ok(tmpdir):
4 make_repo(
5 tmpdir,
6 nodes={
7 "localhost": {
8 'os': host_os(),
9 },
10 },
11 )
12 stdout, stderr, rcode = run("BW_TABLE_STYLE=grep bw run localhost true", path=str(tmpdir))
13 assert rcode == 0
14 assert b"localhost\t0" in stdout
15 assert stderr == b""
16
17
18 def test_run_fail(tmpdir):
19 make_repo(
20 tmpdir,
21 nodes={
22 "localhost": {
23 'os': host_os(),
24 },
25 },
26 )
27 stdout, stderr, rcode = run("BW_TABLE_STYLE=grep bw run localhost false", path=str(tmpdir))
28 assert rcode == 0
29 assert b"localhost\t1" in stdout
30 assert stderr == b""
583583 },
584584 )
585585 assert run("bw test -I", path=str(tmpdir))[2] == 1
586
587
588 def test_secret_identifier_only_once(tmpdir):
589 make_repo(
590 tmpdir,
591 nodes={
592 "node1": {
593 'bundles': ["bundle1"],
594 },
595 },
596 bundles={
597 "bundle1": {
598 'files': {
599 "/test": {
600 'content': "${repo.vault.password_for('testing')}",
601 'content_type': 'mako',
602 },
603 },
604 },
605 },
606 )
607 assert run("bw test -s ''", path=str(tmpdir))[2] == 1
608 assert run("bw test -s 'test'", path=str(tmpdir))[2] == 0
609 assert run("bw test -s 'test,foo'", path=str(tmpdir))[2] == 0
610
611
612 def test_secret_identifier_twice(tmpdir):
613 make_repo(
614 tmpdir,
615 nodes={
616 "node1": {
617 'bundles': ["bundle1"],
618 },
619 "node2": {
620 'bundles': ["bundle1"],
621 },
622 },
623 bundles={
624 "bundle1": {
625 'files': {
626 "/test": {
627 'content': "${repo.vault.password_for('testing')}",
628 'content_type': 'mako',
629 },
630 },
631 },
632 },
633 )
634 assert run("bw test -s ''", path=str(tmpdir))[2] == 0
635 assert run("bw test -s 'test'", path=str(tmpdir))[2] == 0
636 assert run("bw test -s 'test,foo'", path=str(tmpdir))[2] == 0