# Copyright (c) 2017 StackHPC Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import unittest

import cliff.app
import cliff.commandmanager
import mock

from kayobe.cli import commands
from kayobe import utils


class TestApp(cliff.app.App):

    def __init__(self):
        super(TestApp, self).__init__(
            description='Test app',
            version='0.1',
            command_manager=cliff.commandmanager.CommandManager('kayobe.cli'))


class TestCase(unittest.TestCase):

    @mock.patch.object(utils, "galaxy_install", spec=True)
    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    def test_control_host_bootstrap(self, mock_run, mock_install):
        command = commands.ControlHostBootstrap(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])
        result = command.run(parsed_args)
        self.assertEqual(0, result)
        mock_install.assert_called_once_with("requirements.yml",
                                             "ansible/roles")
        expected_calls = [
            mock.call(mock.ANY, ["ansible/bootstrap.yml"]),
            mock.call(mock.ANY, ["ansible/kolla-ansible.yml"],
                      tags="install"),
        ]
        self.assertEqual(expected_calls, mock_run.call_args_list)

    @mock.patch.object(utils, "galaxy_install", spec=True)
    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    def test_control_host_upgrade(self, mock_run, mock_install):
        command = commands.ControlHostUpgrade(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])
        result = command.run(parsed_args)
        self.assertEqual(0, result)
        mock_install.assert_called_once_with("requirements.yml",
                                             "ansible/roles", force=True)
        expected_calls = [
            mock.call(mock.ANY, ["ansible/bootstrap.yml"]),
            mock.call(mock.ANY, ["ansible/kolla-ansible.yml"],
                      tags="install"),
        ]
        self.assertEqual(expected_calls, mock_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    def test_network_connectivity_check(self, mock_run):
        command = commands.NetworkConnectivityCheck(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])
        result = command.run(parsed_args)
        self.assertEqual(0, result)
        expected_calls = [
            mock.call(mock.ANY, ["ansible/network-connectivity.yml"]),
        ]
        self.assertEqual(expected_calls, mock_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_config_dump")
    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    def test_seed_hypervisor_host_configure(self, mock_run, mock_dump):
        command = commands.SeedHypervisorHostConfigure(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])
        mock_dump.return_value = "stack"

        result = command.run(parsed_args)
        self.assertEqual(0, result)

        expected_calls = [
            mock.call(mock.ANY, host="seed-hypervisor",
                      var_name="kayobe_ansible_user", tags="dump-config")
        ]
        self.assertEqual(expected_calls, mock_dump.call_args_list)

        expected_calls = [
            mock.call(
                mock.ANY,
                [
                    "ansible/ip-allocation.yml",
                    "ansible/ssh-known-host.yml",
                    "ansible/kayobe-ansible-user.yml",
                    "ansible/kayobe-target-venv.yml",
                    "ansible/users.yml",
                    "ansible/yum.yml",
                    "ansible/dev-tools.yml",
                    "ansible/network.yml",
                    "ansible/sysctl.yml",
                    "ansible/ntp.yml",
                    "ansible/seed-hypervisor-libvirt-host.yml",
                ],
                limit="seed-hypervisor",
            ),
        ]
        self.assertEqual(expected_calls, mock_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    def test_seed_hypervisor_host_upgrade(self, mock_run):
        command = commands.SeedHypervisorHostUpgrade(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])

        result = command.run(parsed_args)
        self.assertEqual(0, result)

        expected_calls = [
            mock.call(
                mock.ANY,
                [
                    "ansible/kayobe-target-venv.yml",
                    "ansible/kolla-target-venv.yml",
                ],
                limit="seed-hypervisor",
            ),
        ]
        self.assertEqual(expected_calls, mock_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_config_dump")
    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    @mock.patch.object(commands.KollaAnsibleMixin,
                       "run_kolla_ansible_seed")
    def test_seed_host_configure(self, mock_kolla_run, mock_run, mock_dump):
        command = commands.SeedHostConfigure(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])
        mock_dump.return_value = {
            "seed": {"kayobe_ansible_user": "stack"}
        }

        result = command.run(parsed_args)
        self.assertEqual(0, result)

        expected_calls = [
            mock.call(mock.ANY, hosts="seed", tags="dump-config")
        ]
        self.assertEqual(expected_calls, mock_dump.call_args_list)

        expected_calls = [
            mock.call(
                mock.ANY,
                [
                    "ansible/ip-allocation.yml",
                    "ansible/ssh-known-host.yml",
                    "ansible/kayobe-ansible-user.yml",
                    "ansible/kayobe-target-venv.yml",
                    "ansible/users.yml",
                    "ansible/yum.yml",
                    "ansible/dev-tools.yml",
                    "ansible/disable-selinux.yml",
                    "ansible/network.yml",
                    "ansible/sysctl.yml",
                    "ansible/ip-routing.yml",
                    "ansible/snat.yml",
                    "ansible/disable-glean.yml",
                    "ansible/ntp.yml",
                    "ansible/lvm.yml",
                ],
                limit="seed",
            ),
            mock.call(
                mock.ANY,
                ["ansible/kolla-ansible.yml"],
                tags="config",
            ),
            mock.call(
                mock.ANY,
                [
                    "ansible/kolla-target-venv.yml",
                    "ansible/kolla-host.yml",
                    "ansible/docker.yml",
                ],
                limit="seed",
            ),
        ]
        self.assertEqual(expected_calls, mock_run.call_args_list)

        expected_calls = [
            mock.call(
                mock.ANY,
                "bootstrap-servers",
                extra_vars={"ansible_user": "stack"},
            ),
        ]
        self.assertEqual(expected_calls, mock_kolla_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_config_dump")
    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    @mock.patch.object(commands.KollaAnsibleMixin,
                       "run_kolla_ansible_seed")
    def test_seed_host_configure_kayobe_venv(self, mock_kolla_run, mock_run,
                                             mock_dump):
        command = commands.SeedHostConfigure(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])
        mock_dump.return_value = {
            "seed": {
                "ansible_python_interpreter": "/kayobe/venv/bin/python",
                "kayobe_ansible_user": "stack",
            }
        }

        result = command.run(parsed_args)
        self.assertEqual(0, result)

        expected_calls = [
            mock.call(
                mock.ANY,
                "bootstrap-servers",
                extra_vars={
                    "ansible_python_interpreter": "/kayobe/venv/bin/python",
                    "ansible_user": "stack",
                },
            ),
        ]
        self.assertEqual(expected_calls, mock_kolla_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_config_dump")
    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    @mock.patch.object(commands.KollaAnsibleMixin,
                       "run_kolla_ansible_seed")
    def test_seed_host_configure_kolla_venv(self, mock_kolla_run, mock_run,
                                            mock_dump):
        command = commands.SeedHostConfigure(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])
        mock_dump.return_value = {
            "seed": {
                "kayobe_ansible_user": "stack",
                "kolla_ansible_target_venv": "/kolla/venv/bin/python",
            }
        }

        result = command.run(parsed_args)
        self.assertEqual(0, result)

        expected_calls = [
            mock.call(
                mock.ANY,
                "bootstrap-servers",
                extra_vars={
                    "ansible_python_interpreter": "/usr/bin/python",
                    "ansible_user": "stack",
                    "virtualenv": "/kolla/venv/bin/python",
                },
            ),
        ]
        self.assertEqual(expected_calls, mock_kolla_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_config_dump")
    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    @mock.patch.object(commands.KollaAnsibleMixin,
                       "run_kolla_ansible_seed")
    def test_seed_host_configure_both_venvs(self, mock_kolla_run, mock_run,
                                            mock_dump):
        command = commands.SeedHostConfigure(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])
        mock_dump.return_value = {
            "seed": {
                "ansible_python_interpreter": "/kayobe/venv/bin/python",
                "kayobe_ansible_user": "stack",
                "kolla_ansible_target_venv": "/kolla/venv/bin/python",
            }
        }

        result = command.run(parsed_args)
        self.assertEqual(0, result)

        expected_calls = [
            mock.call(
                mock.ANY,
                "bootstrap-servers",
                extra_vars={
                    "ansible_python_interpreter": "/kayobe/venv/bin/python",
                    "ansible_user": "stack",
                    "virtualenv": "/kolla/venv/bin/python",
                },
            ),
        ]
        self.assertEqual(expected_calls, mock_kolla_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    def test_seed_host_upgrade(self, mock_run):
        command = commands.SeedHostUpgrade(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])

        result = command.run(parsed_args)
        self.assertEqual(0, result)

        expected_calls = [
            mock.call(
                mock.ANY,
                [
                    "ansible/kayobe-target-venv.yml",
                    "ansible/kolla-target-venv.yml",
                ],
                limit="seed",
            ),
        ]
        self.assertEqual(expected_calls, mock_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    def test_seed_container_image_build(self, mock_run):
        command = commands.SeedContainerImageBuild(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])
        result = command.run(parsed_args)
        self.assertEqual(0, result)
        expected_calls = [
            mock.call(
                mock.ANY,
                [
                    "ansible/container-image-builders-check.yml",
                    "ansible/kolla-build.yml",
                    "ansible/container-image-build.yml"
                ],
                extra_vars={
                    "container_image_sets": (
                        "{{ seed_container_image_sets }}"),
                    "push_images": False,
                }
            ),
        ]
        self.assertEqual(expected_calls, mock_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    def test_seed_container_image_build_with_regex(self, mock_run):
        command = commands.SeedContainerImageBuild(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args(["--push", "^regex1$", "^regex2$"])
        result = command.run(parsed_args)
        self.assertEqual(0, result)
        expected_calls = [
            mock.call(
                mock.ANY,
                [
                    "ansible/container-image-builders-check.yml",
                    "ansible/kolla-build.yml",
                    "ansible/container-image-build.yml"
                ],
                extra_vars={
                    "container_image_regexes": "'^regex1$ ^regex2$'",
                    "push_images": True,
                }
            ),
        ]
        self.assertEqual(expected_calls, mock_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    @mock.patch.object(commands.KollaAnsibleMixin,
                       "run_kolla_ansible_seed")
    def test_service_deploy(self, mock_kolla_run, mock_run):
        command = commands.SeedServiceDeploy(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])

        result = command.run(parsed_args)
        self.assertEqual(0, result)

        expected_calls = [
            mock.call(
                mock.ANY,
                ["ansible/kolla-ansible.yml"],
                tags="config",
            ),
            mock.call(
                mock.ANY,
                ["ansible/kolla-bifrost.yml"],
            ),
            mock.call(
                mock.ANY,
                [
                    "ansible/overcloud-host-image-workaround-resolv.yml",
                    "ansible/seed-introspection-rules.yml",
                    "ansible/dell-switch-bmp.yml",
                ],
            ),
        ]
        self.assertEqual(expected_calls, mock_run.call_args_list)

        expected_calls = [
            mock.call(
                mock.ANY,
                "deploy-bifrost",
            ),
        ]
        self.assertEqual(expected_calls, mock_kolla_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_config_dump")
    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    @mock.patch.object(commands.KollaAnsibleMixin,
                       "run_kolla_ansible_overcloud")
    def test_overcloud_host_configure(self, mock_kolla_run, mock_run,
                                      mock_dump):
        command = commands.OvercloudHostConfigure(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])
        mock_dump.return_value = {
            "controller0": {"kayobe_ansible_user": "stack"}
        }

        result = command.run(parsed_args)
        self.assertEqual(0, result)

        expected_calls = [
            mock.call(mock.ANY, hosts="overcloud", tags="dump-config")
        ]
        self.assertEqual(expected_calls, mock_dump.call_args_list)

        expected_calls = [
            mock.call(
                mock.ANY,
                [
                    "ansible/ip-allocation.yml",
                    "ansible/ssh-known-host.yml",
                    "ansible/kayobe-ansible-user.yml",
                    "ansible/kayobe-target-venv.yml",
                    "ansible/users.yml",
                    "ansible/yum.yml",
                    "ansible/dev-tools.yml",
                    "ansible/disable-selinux.yml",
                    "ansible/network.yml",
                    "ansible/sysctl.yml",
                    "ansible/disable-glean.yml",
                    "ansible/disable-cloud-init.yml",
                    "ansible/ntp.yml",
                    "ansible/lvm.yml",
                ],
                limit="overcloud",
            ),
            mock.call(
                mock.ANY,
                ["ansible/kolla-ansible.yml"],
                tags="config",
            ),
            mock.call(
                mock.ANY,
                [
                    "ansible/kolla-target-venv.yml",
                    "ansible/kolla-host.yml",
                    "ansible/docker.yml",
                    "ansible/ceph-block-devices.yml",
                ],
                limit="overcloud",
            ),
        ]
        self.assertEqual(expected_calls, mock_run.call_args_list)

        expected_calls = [
            mock.call(
                mock.ANY,
                "bootstrap-servers",
                extra_vars={"ansible_user": "stack"},
            ),
        ]
        self.assertEqual(expected_calls, mock_kolla_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_config_dump")
    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    @mock.patch.object(commands.KollaAnsibleMixin,
                       "run_kolla_ansible_overcloud")
    def test_overcloud_host_configure_kayobe_venv(self, mock_kolla_run,
                                                  mock_run, mock_dump):
        command = commands.OvercloudHostConfigure(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])
        mock_dump.return_value = {
            "controller0": {
                "ansible_python_interpreter": "/kayobe/venv/bin/python",
                "kayobe_ansible_user": "stack",
            }
        }

        result = command.run(parsed_args)
        self.assertEqual(0, result)

        expected_calls = [
            mock.call(
                mock.ANY,
                "bootstrap-servers",
                extra_vars={
                    "ansible_python_interpreter": "/kayobe/venv/bin/python",
                    "ansible_user": "stack",
                }
            ),
        ]
        self.assertEqual(expected_calls, mock_kolla_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_config_dump")
    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    @mock.patch.object(commands.KollaAnsibleMixin,
                       "run_kolla_ansible_overcloud")
    def test_overcloud_host_configure_kolla_venv(self, mock_kolla_run,
                                                 mock_run, mock_dump):
        command = commands.OvercloudHostConfigure(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])
        mock_dump.return_value = {
            "controller0": {
                "kayobe_ansible_user": "stack",
                "kolla_ansible_target_venv": "/kolla/venv/bin/python",
            }
        }

        result = command.run(parsed_args)
        self.assertEqual(0, result)

        expected_calls = [
            mock.call(
                mock.ANY,
                "bootstrap-servers",
                extra_vars={
                    "ansible_python_interpreter": "/usr/bin/python",
                    "ansible_user": "stack",
                    "virtualenv": "/kolla/venv/bin/python",
                }
            ),
        ]
        self.assertEqual(expected_calls, mock_kolla_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_config_dump")
    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    @mock.patch.object(commands.KollaAnsibleMixin,
                       "run_kolla_ansible_overcloud")
    def test_overcloud_host_configure_both_venvs(self, mock_kolla_run,
                                                 mock_run, mock_dump):
        command = commands.OvercloudHostConfigure(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])
        mock_dump.return_value = {
            "controller0": {
                "ansible_python_interpreter": "/kayobe/venv/bin/python",
                "kayobe_ansible_user": "stack",
                "kolla_ansible_target_venv": "/kolla/venv/bin/python",
            }
        }

        result = command.run(parsed_args)
        self.assertEqual(0, result)

        expected_calls = [
            mock.call(
                mock.ANY,
                "bootstrap-servers",
                extra_vars={
                    "ansible_python_interpreter": "/kayobe/venv/bin/python",
                    "ansible_user": "stack",
                    "virtualenv": "/kolla/venv/bin/python",
                }
            ),
        ]
        self.assertEqual(expected_calls, mock_kolla_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    def test_overcloud_host_upgrade(self, mock_run):
        command = commands.OvercloudHostUpgrade(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])

        result = command.run(parsed_args)
        self.assertEqual(0, result)

        expected_calls = [
            mock.call(
                mock.ANY,
                [
                    "ansible/kayobe-target-venv.yml",
                    "ansible/kolla-target-venv.yml",
                    "ansible/overcloud-docker-sdk-upgrade.yml",
                    "ansible/overcloud-etc-hosts-fixup.yml",
                ],
                limit="overcloud",
            ),
        ]
        self.assertEqual(expected_calls, mock_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    def test_overcloud_container_image_build(self, mock_run):
        command = commands.OvercloudContainerImageBuild(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])
        result = command.run(parsed_args)
        self.assertEqual(0, result)
        expected_calls = [
            mock.call(
                mock.ANY,
                [
                    "ansible/container-image-builders-check.yml",
                    "ansible/kolla-build.yml",
                    "ansible/container-image-build.yml"
                ],
                extra_vars={
                    "container_image_sets": (
                        "{{ overcloud_container_image_sets }}"),
                    "push_images": False,
                }
            ),
        ]
        self.assertEqual(expected_calls, mock_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    def test_overcloud_container_image_build_with_regex(self, mock_run):
        command = commands.OvercloudContainerImageBuild(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args(["--push", "^regex1$", "^regex2$"])
        result = command.run(parsed_args)
        self.assertEqual(0, result)
        expected_calls = [
            mock.call(
                mock.ANY,
                [
                    "ansible/container-image-builders-check.yml",
                    "ansible/kolla-build.yml",
                    "ansible/container-image-build.yml"
                ],
                extra_vars={
                    "container_image_regexes": "'^regex1$ ^regex2$'",
                    "push_images": True,
                }
            ),
        ]
        self.assertEqual(expected_calls, mock_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    def test_overcloud_post_configure(self, mock_run):
        command = commands.OvercloudPostConfigure(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])

        result = command.run(parsed_args)
        self.assertEqual(0, result)

        expected_calls = [
            mock.call(
                mock.ANY,
                [
                    'ansible/overcloud-ipa-images.yml',
                    'ansible/overcloud-introspection-rules.yml',
                    'ansible/overcloud-introspection-rules-dell-lldp-workaround.yml',  # noqa
                    'ansible/provision-net.yml',
                    'ansible/overcloud-grafana-configure.yml'
                ],
            ),
        ]
        self.assertEqual(expected_calls, mock_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    def test_baremetal_compute_inspect(self, mock_run):
        command = commands.BaremetalComputeInspect(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])
        result = command.run(parsed_args)
        self.assertEqual(0, result)
        expected_calls = [
            mock.call(
                mock.ANY,
                [
                    "ansible/baremetal-compute-inspect.yml",
                ],
            ),
        ]
        self.assertEqual(expected_calls, mock_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    def test_baremetal_compute_manage(self, mock_run):
        command = commands.BaremetalComputeManage(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])
        result = command.run(parsed_args)
        self.assertEqual(0, result)
        expected_calls = [
            mock.call(
                mock.ANY,
                [
                    "ansible/baremetal-compute-manage.yml",
                ],
            ),
        ]
        self.assertEqual(expected_calls, mock_run.call_args_list)

    @mock.patch.object(commands.KayobeAnsibleMixin,
                       "run_kayobe_playbooks")
    def test_baremetal_compute_provide(self, mock_run):
        command = commands.BaremetalComputeProvide(TestApp(), [])
        parser = command.get_parser("test")
        parsed_args = parser.parse_args([])
        result = command.run(parsed_args)
        self.assertEqual(0, result)
        expected_calls = [
            mock.call(
                mock.ANY,
                [
                    "ansible/baremetal-compute-provide.yml",
                ],
            ),
        ]
        self.assertEqual(expected_calls, mock_run.call_args_list)

[((36, 5, 36, 58), 'mock.patch.object', 'mock.patch.object', (), '', False, 'import mock\n'), ((37, 5, 38, 46), 'mock.patch.object', 'mock.patch.object', ({(37, 23, 37, 50): 'commands.KayobeAnsibleMixin', (38, 23, 38, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((54, 5, 54, 58), 'mock.patch.object', 'mock.patch.object', (), '', False, 'import mock\n'), ((55, 5, 56, 46), 'mock.patch.object', 'mock.patch.object', ({(55, 23, 55, 50): 'commands.KayobeAnsibleMixin', (56, 23, 56, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((72, 5, 73, 46), 'mock.patch.object', 'mock.patch.object', ({(72, 23, 72, 50): 'commands.KayobeAnsibleMixin', (73, 23, 73, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((85, 5, 86, 48), 'mock.patch.object', 'mock.patch.object', ({(85, 23, 85, 50): 'commands.KayobeAnsibleMixin', (86, 23, 86, 47): '"""run_kayobe_config_dump"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_config_dump')", False, 'import mock\n'), ((87, 5, 88, 46), 'mock.patch.object', 'mock.patch.object', ({(87, 23, 87, 50): 'commands.KayobeAnsibleMixin', (88, 23, 88, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((125, 5, 126, 46), 'mock.patch.object', 'mock.patch.object', ({(125, 23, 125, 50): 'commands.KayobeAnsibleMixin', (126, 23, 126, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((147, 5, 148, 48), 'mock.patch.object', 'mock.patch.object', ({(147, 23, 147, 50): 'commands.KayobeAnsibleMixin', (148, 23, 148, 47): '"""run_kayobe_config_dump"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_config_dump')", False, 'import mock\n'), ((149, 5, 150, 46), 'mock.patch.object', 'mock.patch.object', ({(149, 23, 149, 50): 'commands.KayobeAnsibleMixin', (150, 23, 150, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((151, 5, 152, 48), 'mock.patch.object', 'mock.patch.object', ({(151, 23, 151, 49): 'commands.KollaAnsibleMixin', (152, 23, 152, 47): '"""run_kolla_ansible_seed"""'}, {}), "(commands.KollaAnsibleMixin, 'run_kolla_ansible_seed')", False, 'import mock\n'), ((217, 5, 218, 48), 'mock.patch.object', 'mock.patch.object', ({(217, 23, 217, 50): 'commands.KayobeAnsibleMixin', (218, 23, 218, 47): '"""run_kayobe_config_dump"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_config_dump')", False, 'import mock\n'), ((219, 5, 220, 46), 'mock.patch.object', 'mock.patch.object', ({(219, 23, 219, 50): 'commands.KayobeAnsibleMixin', (220, 23, 220, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((221, 5, 222, 48), 'mock.patch.object', 'mock.patch.object', ({(221, 23, 221, 49): 'commands.KollaAnsibleMixin', (222, 23, 222, 47): '"""run_kolla_ansible_seed"""'}, {}), "(commands.KollaAnsibleMixin, 'run_kolla_ansible_seed')", False, 'import mock\n'), ((250, 5, 251, 48), 'mock.patch.object', 'mock.patch.object', ({(250, 23, 250, 50): 'commands.KayobeAnsibleMixin', (251, 23, 251, 47): '"""run_kayobe_config_dump"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_config_dump')", False, 'import mock\n'), ((252, 5, 253, 46), 'mock.patch.object', 'mock.patch.object', ({(252, 23, 252, 50): 'commands.KayobeAnsibleMixin', (253, 23, 253, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((254, 5, 255, 48), 'mock.patch.object', 'mock.patch.object', ({(254, 23, 254, 49): 'commands.KollaAnsibleMixin', (255, 23, 255, 47): '"""run_kolla_ansible_seed"""'}, {}), "(commands.KollaAnsibleMixin, 'run_kolla_ansible_seed')", False, 'import mock\n'), ((284, 5, 285, 48), 'mock.patch.object', 'mock.patch.object', ({(284, 23, 284, 50): 'commands.KayobeAnsibleMixin', (285, 23, 285, 47): '"""run_kayobe_config_dump"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_config_dump')", False, 'import mock\n'), ((286, 5, 287, 46), 'mock.patch.object', 'mock.patch.object', ({(286, 23, 286, 50): 'commands.KayobeAnsibleMixin', (287, 23, 287, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((288, 5, 289, 48), 'mock.patch.object', 'mock.patch.object', ({(288, 23, 288, 49): 'commands.KollaAnsibleMixin', (289, 23, 289, 47): '"""run_kolla_ansible_seed"""'}, {}), "(commands.KollaAnsibleMixin, 'run_kolla_ansible_seed')", False, 'import mock\n'), ((319, 5, 320, 46), 'mock.patch.object', 'mock.patch.object', ({(319, 23, 319, 50): 'commands.KayobeAnsibleMixin', (320, 23, 320, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((341, 5, 342, 46), 'mock.patch.object', 'mock.patch.object', ({(341, 23, 341, 50): 'commands.KayobeAnsibleMixin', (342, 23, 342, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((366, 5, 367, 46), 'mock.patch.object', 'mock.patch.object', ({(366, 23, 366, 50): 'commands.KayobeAnsibleMixin', (367, 23, 367, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((390, 5, 391, 46), 'mock.patch.object', 'mock.patch.object', ({(390, 23, 390, 50): 'commands.KayobeAnsibleMixin', (391, 23, 391, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((392, 5, 393, 48), 'mock.patch.object', 'mock.patch.object', ({(392, 23, 392, 49): 'commands.KollaAnsibleMixin', (393, 23, 393, 47): '"""run_kolla_ansible_seed"""'}, {}), "(commands.KollaAnsibleMixin, 'run_kolla_ansible_seed')", False, 'import mock\n'), ((431, 5, 432, 48), 'mock.patch.object', 'mock.patch.object', ({(431, 23, 431, 50): 'commands.KayobeAnsibleMixin', (432, 23, 432, 47): '"""run_kayobe_config_dump"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_config_dump')", False, 'import mock\n'), ((433, 5, 434, 46), 'mock.patch.object', 'mock.patch.object', ({(433, 23, 433, 50): 'commands.KayobeAnsibleMixin', (434, 23, 434, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((435, 5, 436, 53), 'mock.patch.object', 'mock.patch.object', ({(435, 23, 435, 49): 'commands.KollaAnsibleMixin', (436, 23, 436, 52): '"""run_kolla_ansible_overcloud"""'}, {}), "(commands.KollaAnsibleMixin, 'run_kolla_ansible_overcloud')", False, 'import mock\n'), ((502, 5, 503, 48), 'mock.patch.object', 'mock.patch.object', ({(502, 23, 502, 50): 'commands.KayobeAnsibleMixin', (503, 23, 503, 47): '"""run_kayobe_config_dump"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_config_dump')", False, 'import mock\n'), ((504, 5, 505, 46), 'mock.patch.object', 'mock.patch.object', ({(504, 23, 504, 50): 'commands.KayobeAnsibleMixin', (505, 23, 505, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((506, 5, 507, 53), 'mock.patch.object', 'mock.patch.object', ({(506, 23, 506, 49): 'commands.KollaAnsibleMixin', (507, 23, 507, 52): '"""run_kolla_ansible_overcloud"""'}, {}), "(commands.KollaAnsibleMixin, 'run_kolla_ansible_overcloud')", False, 'import mock\n'), ((535, 5, 536, 48), 'mock.patch.object', 'mock.patch.object', ({(535, 23, 535, 50): 'commands.KayobeAnsibleMixin', (536, 23, 536, 47): '"""run_kayobe_config_dump"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_config_dump')", False, 'import mock\n'), ((537, 5, 538, 46), 'mock.patch.object', 'mock.patch.object', ({(537, 23, 537, 50): 'commands.KayobeAnsibleMixin', (538, 23, 538, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((539, 5, 540, 53), 'mock.patch.object', 'mock.patch.object', ({(539, 23, 539, 49): 'commands.KollaAnsibleMixin', (540, 23, 540, 52): '"""run_kolla_ansible_overcloud"""'}, {}), "(commands.KollaAnsibleMixin, 'run_kolla_ansible_overcloud')", False, 'import mock\n'), ((569, 5, 570, 48), 'mock.patch.object', 'mock.patch.object', ({(569, 23, 569, 50): 'commands.KayobeAnsibleMixin', (570, 23, 570, 47): '"""run_kayobe_config_dump"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_config_dump')", False, 'import mock\n'), ((571, 5, 572, 46), 'mock.patch.object', 'mock.patch.object', ({(571, 23, 571, 50): 'commands.KayobeAnsibleMixin', (572, 23, 572, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((573, 5, 574, 53), 'mock.patch.object', 'mock.patch.object', ({(573, 23, 573, 49): 'commands.KollaAnsibleMixin', (574, 23, 574, 52): '"""run_kolla_ansible_overcloud"""'}, {}), "(commands.KollaAnsibleMixin, 'run_kolla_ansible_overcloud')", False, 'import mock\n'), ((604, 5, 605, 46), 'mock.patch.object', 'mock.patch.object', ({(604, 23, 604, 50): 'commands.KayobeAnsibleMixin', (605, 23, 605, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((628, 5, 629, 46), 'mock.patch.object', 'mock.patch.object', ({(628, 23, 628, 50): 'commands.KayobeAnsibleMixin', (629, 23, 629, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((653, 5, 654, 46), 'mock.patch.object', 'mock.patch.object', ({(653, 23, 653, 50): 'commands.KayobeAnsibleMixin', (654, 23, 654, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((677, 5, 678, 46), 'mock.patch.object', 'mock.patch.object', ({(677, 23, 677, 50): 'commands.KayobeAnsibleMixin', (678, 23, 678, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((701, 5, 702, 46), 'mock.patch.object', 'mock.patch.object', ({(701, 23, 701, 50): 'commands.KayobeAnsibleMixin', (702, 23, 702, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((719, 5, 720, 46), 'mock.patch.object', 'mock.patch.object', ({(719, 23, 719, 50): 'commands.KayobeAnsibleMixin', (720, 23, 720, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((737, 5, 738, 46), 'mock.patch.object', 'mock.patch.object', ({(737, 23, 737, 50): 'commands.KayobeAnsibleMixin', (738, 23, 738, 45): '"""run_kayobe_playbooks"""'}, {}), "(commands.KayobeAnsibleMixin, 'run_kayobe_playbooks')", False, 'import mock\n'), ((48, 12, 48, 58), 'mock.call', 'mock.call', ({(48, 22, 48, 30): 'mock.ANY', (48, 32, 48, 57): "['ansible/bootstrap.yml']"}, {}), "(mock.ANY, ['ansible/bootstrap.yml'])", False, 'import mock\n'), ((49, 12, 50, 37), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((66, 12, 66, 58), 'mock.call', 'mock.call', ({(66, 22, 66, 30): 'mock.ANY', (66, 32, 66, 57): "['ansible/bootstrap.yml']"}, {}), "(mock.ANY, ['ansible/bootstrap.yml'])", False, 'import mock\n'), ((67, 12, 68, 37), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((81, 12, 81, 69), 'mock.call', 'mock.call', ({(81, 22, 81, 30): 'mock.ANY', (81, 32, 81, 68): "['ansible/network-connectivity.yml']"}, {}), "(mock.ANY, ['ansible/network-connectivity.yml'])", False, 'import mock\n'), ((99, 12, 100, 73), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((105, 12, 121, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((136, 12, 143, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((165, 12, 165, 65), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((170, 12, 190, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((191, 12, 195, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((196, 12, 204, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((209, 12, 213, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((239, 12, 246, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((272, 12, 280, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((307, 12, 315, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((330, 12, 337, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((350, 12, 362, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((375, 12, 386, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((403, 12, 407, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((408, 12, 411, 13), 'mock.call', 'mock.call', ({(409, 16, 409, 24): 'mock.ANY', (410, 16, 410, 45): "['ansible/kolla-bifrost.yml']"}, {}), "(mock.ANY, ['ansible/kolla-bifrost.yml'])", False, 'import mock\n'), ((412, 12, 419, 13), 'mock.call', 'mock.call', ({(413, 16, 413, 24): 'mock.ANY', (414, 16, 418, 17): "['ansible/overcloud-host-image-workaround-resolv.yml',\n    'ansible/seed-introspection-rules.yml', 'ansible/dell-switch-bmp.yml']"}, {}), "(mock.ANY, ['ansible/overcloud-host-image-workaround-resolv.yml',\n    'ansible/seed-introspection-rules.yml', 'ansible/dell-switch-bmp.yml'])", False, 'import mock\n'), ((424, 12, 427, 13), 'mock.call', 'mock.call', ({(425, 16, 425, 24): 'mock.ANY', (426, 16, 426, 32): '"""deploy-bifrost"""'}, {}), "(mock.ANY, 'deploy-bifrost')", False, 'import mock\n'), ((450, 12, 450, 70), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((455, 12, 474, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((475, 12, 479, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((480, 12, 489, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((494, 12, 498, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((524, 12, 531, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((557, 12, 565, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((592, 12, 600, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((615, 12, 624, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((637, 12, 649, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((662, 12, 673, 13), 'mock.call', 'mock.call', (), '', False, 'import mock\n'), ((688, 12, 697, 13), 'mock.call', 'mock.call', ({(689, 16, 689, 24): 'mock.ANY', (690, 16, 696, 17): "['ansible/overcloud-ipa-images.yml',\n    'ansible/overcloud-introspection-rules.yml',\n    'ansible/overcloud-introspection-rules-dell-lldp-workaround.yml',\n    'ansible/provision-net.yml', 'ansible/overcloud-grafana-configure.yml']"}, {}), "(mock.ANY, ['ansible/overcloud-ipa-images.yml',\n    'ansible/overcloud-introspection-rules.yml',\n    'ansible/overcloud-introspection-rules-dell-lldp-workaround.yml',\n    'ansible/provision-net.yml', 'ansible/overcloud-grafana-configure.yml'])", False, 'import mock\n'), ((710, 12, 715, 13), 'mock.call', 'mock.call', ({(711, 16, 711, 24): 'mock.ANY', (712, 16, 714, 17): "['ansible/baremetal-compute-inspect.yml']"}, {}), "(mock.ANY, ['ansible/baremetal-compute-inspect.yml'])", False, 'import mock\n'), ((728, 12, 733, 13), 'mock.call', 'mock.call', ({(729, 16, 729, 24): 'mock.ANY', (730, 16, 732, 17): "['ansible/baremetal-compute-manage.yml']"}, {}), "(mock.ANY, ['ansible/baremetal-compute-manage.yml'])", False, 'import mock\n'), ((746, 12, 751, 13), 'mock.call', 'mock.call', ({(747, 16, 747, 24): 'mock.ANY', (748, 16, 750, 17): "['ansible/baremetal-compute-provide.yml']"}, {}), "(mock.ANY, ['ansible/baremetal-compute-provide.yml'])", False, 'import mock\n')]