diff --git a/HISTORY.rst b/HISTORY.rst index 5e2c74a..be58f1b 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,9 +1,12 @@ Changelog ========= -1.3.2 - Unreleased +1.4.0 - Unreleased ------------------ +* Add ``-g/--group`` option to ``configure`` command to configure all instances + in a group. + [fschulze] 1.3.1 - 2015-09-03 diff --git a/README.rst b/README.rst index ffd9ab2..604b807 100644 --- a/README.rst +++ b/README.rst @@ -26,6 +26,7 @@ The plugin adds the following commands to ploy. Applying the roles given by the ``roles`` option of an instance, a playbook set by the ``playbook`` option or a playbook with the unique name of the instance found in the ``playbooks-directory``. Using ``roles`` or a playbook is mutually exclusive. If you specify a playbook and there is also a playbook in the default location, you will get a warning. + Alternatively you can specify the ``-g/--group`` option to configure all members of the given group. ``inventory`` Lists all known groups and their associated hosts, including regular default groups, such as ``all`` but also implicit, ``ploy_ansible`` groups such as instances of a particular ``master`` (i.e. all ``ez-instances`` of an ``ez-master``) diff --git a/ploy_ansible/__init__.py b/ploy_ansible/__init__.py index 80e266b..919d380 100644 --- a/ploy_ansible/__init__.py +++ b/ploy_ansible/__init__.py @@ -648,6 +648,8 @@ def get_completion(self): return sorted(instances) def __call__(self, argv, help): + inventory = _get_ansible_inventory(self.ctrl, self.ctrl.config) + groups = inventory.groups_list() parser = argparse.ArgumentParser( prog="%s configure" % self.ctrl.progname, description=help) @@ -669,26 +671,39 @@ def __call__(self, argv, help): action="append", default=[], help="set additional variables as key=value or YAML/JSON") - parser.add_argument( + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument( + '-g', '--group', + nargs='?', + metavar="group", + help="Name of an ansible group.", + choices=list(groups)) + group.add_argument( "instance", - nargs=1, + nargs='?', metavar="instance", help="Name of the instance from the config.", choices=self.get_completion()) args = parser.parse_args(argv) - instance = self.ctrl.instances[args.instance[0]] + instances = [] + if args.instance is not None: + instances.append(self.ctrl.instances[args.instance]) + else: + for name in groups[args.group]: + instances.append(self.ctrl.instances[name]) only_tags = args.only_tags.split(",") skip_tags = args.skip_tags if skip_tags is not None: skip_tags = skip_tags.split(",") extra_vars = parse_extra_vars(args.extra_vars) - instance.hooks.before_ansible_configure(instance) - instance.configure( - only_tags=only_tags, - skip_tags=skip_tags, - extra_vars=extra_vars, - verbosity=args.verbose) - instance.hooks.after_ansible_configure(instance) + for instance in instances: + instance.hooks.before_ansible_configure(instance) + instance.configure( + only_tags=only_tags, + skip_tags=skip_tags, + extra_vars=extra_vars, + verbosity=args.verbose) + instance.hooks.after_ansible_configure(instance) class AnsibleInventoryCmd(object): diff --git a/ploy_ansible/test_ansible.py b/ploy_ansible/test_ansible.py index f107bb4..4c5b98f 100644 --- a/ploy_ansible/test_ansible.py +++ b/ploy_ansible/test_ansible.py @@ -16,7 +16,7 @@ def test_configure_without_args(ctrl): ctrl(['./bin/ploy', 'configure']) output = "".join(x[0][0] for x in StdErrMock.write.call_args_list) assert 'usage: ploy configure' in output - assert 'too few arguments' in output + assert 'one of the arguments -g/--group instance is required' in output def test_configure_with_nonexisting_instance(ctrl): @@ -159,6 +159,25 @@ def test_configure_with_extra_vars(ctrl, monkeypatch, tempdir): assert runmock.call_args[0][0].extra_vars == dict(foo='bar', bar='foo') +def test_configure_group(ctrl, monkeypatch, ployconf, tempdir): + import ansible.playbook + ployconf.fill([ + '[dummy-instance:bar]', + '[dummy-instance:foo]']) + tempdir['default-foo.yml'].fill([ + '---', + '- hosts: default-foo']) + tempdir['default-bar.yml'].fill([ + '---', + '- hosts: default-bar']) + with patch.object(ansible.playbook.PlayBook, "run", autospec=True) as runmock: + ctrl(['./bin/ploy', 'configure', '-g', 'all']) + assert runmock.called + hosts = [x[0][0].playbook[0]['hosts'] for x in runmock.call_args_list] + assert [len(x) for x in hosts] == [1, 1] + assert sorted([x[0] for x in hosts]) == ['default-bar', 'default-foo'] + + def test_playbook_without_args(ctrl): with patch('sys.stderr') as StdErrMock: StdErrMock.encoding = 'utf-8' diff --git a/setup.py b/setup.py index fe33567..fd28c76 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ HISTORY = open(os.path.join(here, 'HISTORY.rst')).read() -version = "1.3.2.dev0" +version = "1.4.0.dev0" install_requires = [