Merge "Support Ansible diff mode"

This commit is contained in:
Zuul 2021-10-21 16:31:56 +00:00 committed by Gerrit Code Review
commit bf440c5dd2
6 changed files with 55 additions and 7 deletions

View File

@ -69,3 +69,13 @@ playbooks to be limited to matching plays and tasks. The ``--kolla-tags
limited to matching plays and tasks. The ``--skip-tags <TAGS>`` and limited to matching plays and tasks. The ``--skip-tags <TAGS>`` and
``--kolla-skip-tags <TAGS>`` arguments allow for avoiding execution of matching ``--kolla-skip-tags <TAGS>`` arguments allow for avoiding execution of matching
plays and tasks. plays and tasks.
Check and diff mode
-------------------
Ansible supports `check and diff modes
<https://docs.ansible.com/ansible/latest/user_guide/playbooks_checkmode.html>`_,
which can be used to improve visibility into changes that would be made on
target systems. The Kayobe CLI supports the ``--check`` argument, and since
11.0.0, the ``--diff`` argument. Note that these modes are not always
guaranteed to work, when some tasks are dependent on earlier ones.

View File

@ -48,6 +48,10 @@ def add_args(parser):
help="path to Kayobe configuration. " help="path to Kayobe configuration. "
"(default=$%s or %s)" % "(default=$%s or %s)" %
(CONFIG_PATH_ENV, DEFAULT_CONFIG_PATH)) (CONFIG_PATH_ENV, DEFAULT_CONFIG_PATH))
parser.add_argument("-D", "--diff", action="store_true",
help="when changing (small) files and templates, show "
"the differences in those files; works great "
"with --check")
parser.add_argument("--environment", default=default_environment, parser.add_argument("--environment", default=default_environment,
help="specify environment name (default=$%s or None)" % help="specify environment name (default=$%s or None)" %
ENVIRONMENT_ENV) ENVIRONMENT_ENV)
@ -161,7 +165,7 @@ def _get_vars_files(vars_paths):
def build_args(parsed_args, playbooks, def build_args(parsed_args, playbooks,
extra_vars=None, limit=None, tags=None, verbose_level=None, extra_vars=None, limit=None, tags=None, verbose_level=None,
check=None, ignore_limit=False, list_tasks=None): check=None, ignore_limit=False, list_tasks=None, diff=None):
"""Build arguments required for running Ansible playbooks.""" """Build arguments required for running Ansible playbooks."""
cmd = ["ansible-playbook"] cmd = ["ansible-playbook"]
if verbose_level: if verbose_level:
@ -193,6 +197,8 @@ def build_args(parsed_args, playbooks,
cmd += ["--become"] cmd += ["--become"]
if check or (parsed_args.check and check is None): if check or (parsed_args.check and check is None):
cmd += ["--check"] cmd += ["--check"]
if diff or (parsed_args.diff and diff is None):
cmd += ["--diff"]
if not ignore_limit and (parsed_args.limit or limit): if not ignore_limit and (parsed_args.limit or limit):
limit_arg = utils.intersect_limits(parsed_args.limit, limit) limit_arg = utils.intersect_limits(parsed_args.limit, limit)
cmd += ["--limit", limit_arg] cmd += ["--limit", limit_arg]
@ -227,13 +233,14 @@ def _get_environment(parsed_args):
def run_playbooks(parsed_args, playbooks, def run_playbooks(parsed_args, playbooks,
extra_vars=None, limit=None, tags=None, quiet=False, extra_vars=None, limit=None, tags=None, quiet=False,
check_output=False, verbose_level=None, check=None, check_output=False, verbose_level=None, check=None,
ignore_limit=False, list_tasks=None): ignore_limit=False, list_tasks=None, diff=None):
"""Run a Kayobe Ansible playbook.""" """Run a Kayobe Ansible playbook."""
_validate_args(parsed_args, playbooks) _validate_args(parsed_args, playbooks)
cmd = build_args(parsed_args, playbooks, cmd = build_args(parsed_args, playbooks,
extra_vars=extra_vars, limit=limit, tags=tags, extra_vars=extra_vars, limit=limit, tags=tags,
verbose_level=verbose_level, check=check, verbose_level=verbose_level, check=check,
ignore_limit=ignore_limit, list_tasks=list_tasks) ignore_limit=ignore_limit, list_tasks=list_tasks,
diff=diff)
env = _get_environment(parsed_args) env = _get_environment(parsed_args)
try: try:
utils.run_command(cmd, check_output=check_output, quiet=quiet, env=env) utils.run_command(cmd, check_output=check_output, quiet=quiet, env=env)
@ -269,7 +276,7 @@ def config_dump(parsed_args, host=None, hosts=None, var_name=None,
run_playbook(parsed_args, playbook_path, run_playbook(parsed_args, playbook_path,
extra_vars=extra_vars, tags=tags, check_output=True, extra_vars=extra_vars, tags=tags, check_output=True,
verbose_level=verbose_level, check=False, verbose_level=verbose_level, check=False,
list_tasks=False) list_tasks=False, diff=False)
hostvars = {} hostvars = {}
for path in os.listdir(dump_dir): for path in os.listdir(dump_dir):
LOG.debug("Found dump file %s", path) LOG.debug("Found dump file %s", path)

View File

@ -157,6 +157,14 @@ def _get_environment(parsed_args):
ansible_cfg_path = os.path.join(parsed_args.config_path, "ansible.cfg") ansible_cfg_path = os.path.join(parsed_args.config_path, "ansible.cfg")
if utils.is_readable_file(ansible_cfg_path)["result"]: if utils.is_readable_file(ansible_cfg_path)["result"]:
env.setdefault("ANSIBLE_CONFIG", ansible_cfg_path) env.setdefault("ANSIBLE_CONFIG", ansible_cfg_path)
# kolla-ansible allows passing additional arguments to ansible-playbook via
# EXTRA_OPTS.
if parsed_args.check or parsed_args.diff:
extra_opts = env.setdefault("EXTRA_OPTS", "")
if parsed_args.check and "--check" not in extra_opts:
env["EXTRA_OPTS"] += " --check"
if parsed_args.diff and "--diff" not in extra_opts:
env["EXTRA_OPTS"] += " --diff"
return env return env

View File

@ -68,6 +68,7 @@ class TestCase(unittest.TestCase):
"-b", "-b",
"-C", "-C",
"--config-path", "/path/to/config", "--config-path", "/path/to/config",
"-D",
"--environment", "test-env", "--environment", "test-env",
"-e", "ev_name1=ev_value1", "-e", "ev_name1=ev_value1",
"-i", "/path/to/inventory", "-i", "/path/to/inventory",
@ -88,6 +89,7 @@ class TestCase(unittest.TestCase):
"-e", "ev_name1=ev_value1", "-e", "ev_name1=ev_value1",
"--become", "--become",
"--check", "--check",
"--diff",
"--limit", "group1:host", "--limit", "group1:host",
"--tags", "tag1,tag2", "--tags", "tag1,tag2",
"playbook1.yml", "playbook1.yml",
@ -117,6 +119,7 @@ class TestCase(unittest.TestCase):
"--become", "--become",
"--check", "--check",
"--config-path", "/path/to/config", "--config-path", "/path/to/config",
"--diff",
"--environment", "test-env", "--environment", "test-env",
"--extra-vars", "ev_name1=ev_value1", "--extra-vars", "ev_name1=ev_value1",
"--inventory", "/path/to/inventory", "--inventory", "/path/to/inventory",
@ -138,6 +141,7 @@ class TestCase(unittest.TestCase):
"-e", "ev_name1=ev_value1", "-e", "ev_name1=ev_value1",
"--become", "--become",
"--check", "--check",
"--diff",
"--limit", "group1:host1", "--limit", "group1:host1",
"--skip-tags", "tag3,tag4", "--skip-tags", "tag3,tag4",
"--tags", "tag1,tag2", "--tags", "tag1,tag2",
@ -249,6 +253,7 @@ class TestCase(unittest.TestCase):
"tags": "tag3,tag4", "tags": "tag3,tag4",
"verbose_level": 0, "verbose_level": 0,
"check": True, "check": True,
"diff": True,
} }
ansible.run_playbooks(parsed_args, ["playbook1.yml", "playbook2.yml"], ansible.run_playbooks(parsed_args, ["playbook1.yml", "playbook2.yml"],
**kwargs) **kwargs)
@ -260,6 +265,7 @@ class TestCase(unittest.TestCase):
"-e", "ev_name1=ev_value1", "-e", "ev_name1=ev_value1",
"-e", "ev_name2='ev_value2'", "-e", "ev_name2='ev_value2'",
"--check", "--check",
"--diff",
"--limit", "group1:host1:&group2:host2", "--limit", "group1:host1:&group2:host2",
"--tags", "tag1,tag2,tag3,tag4", "--tags", "tag1,tag2,tag3,tag4",
"playbook1.yml", "playbook1.yml",
@ -426,7 +432,7 @@ class TestCase(unittest.TestCase):
}, },
check_output=True, tags=None, check_output=True, tags=None,
verbose_level=None, check=False, verbose_level=None, check=False,
list_tasks=False) list_tasks=False, diff=False)
mock_rmtree.assert_called_once_with(dump_dir) mock_rmtree.assert_called_once_with(dump_dir)
mock_listdir.assert_any_call(dump_dir) mock_listdir.assert_any_call(dump_dir)
mock_read.assert_has_calls([ mock_read.assert_has_calls([

View File

@ -54,6 +54,8 @@ class TestCase(unittest.TestCase):
kolla_ansible.add_args(parser) kolla_ansible.add_args(parser)
vault.add_args(parser) vault.add_args(parser)
args = [ args = [
"-C",
"-D",
"--kolla-config-path", "/path/to/config", "--kolla-config-path", "/path/to/config",
"-ke", "ev_name1=ev_value1", "-ke", "ev_name1=ev_value1",
"-ki", "/path/to/inventory", "-ki", "/path/to/inventory",
@ -73,8 +75,9 @@ class TestCase(unittest.TestCase):
"--tags", "tag1,tag2", "--tags", "tag1,tag2",
] ]
expected_cmd = " ".join(expected_cmd) expected_cmd = " ".join(expected_cmd)
expected_env = {"EXTRA_OPTS": " --check --diff"}
mock_run.assert_called_once_with(expected_cmd, shell=True, quiet=False, mock_run.assert_called_once_with(expected_cmd, shell=True, quiet=False,
env={}) env=expected_env)
@mock.patch.object(utils, "run_command") @mock.patch.object(utils, "run_command")
@mock.patch.object(kolla_ansible, "_validate_args") @mock.patch.object(kolla_ansible, "_validate_args")
@ -87,6 +90,8 @@ class TestCase(unittest.TestCase):
mock_ask.return_value = "test-pass" mock_ask.return_value = "test-pass"
args = [ args = [
"--ask-vault-pass", "--ask-vault-pass",
"--check",
"--diff",
"--kolla-config-path", "/path/to/config", "--kolla-config-path", "/path/to/config",
"--kolla-extra-vars", "ev_name1=ev_value1", "--kolla-extra-vars", "ev_name1=ev_value1",
"--kolla-inventory", "/path/to/inventory", "--kolla-inventory", "/path/to/inventory",
@ -110,7 +115,8 @@ class TestCase(unittest.TestCase):
"--tags", "tag1,tag2", "--tags", "tag1,tag2",
] ]
expected_cmd = " ".join(expected_cmd) expected_cmd = " ".join(expected_cmd)
expected_env = {"KAYOBE_VAULT_PASSWORD": "test-pass"} expected_env = {"EXTRA_OPTS": " --check --diff",
"KAYOBE_VAULT_PASSWORD": "test-pass"}
expected_calls = [ expected_calls = [
mock.call(["which", "kayobe-vault-password-helper"], mock.call(["which", "kayobe-vault-password-helper"],
check_output=True, universal_newlines=True), check_output=True, universal_newlines=True),

View File

@ -0,0 +1,11 @@
---
features:
- |
Adds a ``--diff`` argument to kayobe CLI commands. This is passed through
to ``ansible-playbook`` for Kayobe and Kolla Ansible playbooks, and can be
used with the ``--check`` argument to see changes that would be made to
files.
upgrade:
- |
The ``--check`` argument to kayobe CLI commands is now passed through to
Kolla Ansible playbooks.