We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
destroy steps do not run when tests fail and tags are used in provisioner options
# Issue Type

- Bug report

# Molecule and Ansible details

```
pipenv run ansible --version && pipenv run molecule --version
ansible 2.7.10
  config file = /Users/deric/.ansible.cfg
  configured module search path = ['/Users/deric/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /Users/deric/.local/share/virtualenvs/molecule-destroy-cLlJrhaP/lib/python3.7/site-packages/ansible
  executable location = /Users/deric/.local/share/virtualenvs/molecule-destroy-cLlJrhaP/bin/ansible
  python version = 3.7.3 (default, Apr  7 2019, 11:57:41) [Clang 10.0.0 (clang-1000.11.45.5)]
molecule, version 2.20.1.dev18
```

Molecule installation method (one of):

- pipenv (see `Pipfile` in [example repo](https://github.com/dericcrago/molecule-destroy) and `README.md` for usage)

Ansible installation method (one of):

- pipenv (see `Pipfile` in [example repo](https://github.com/dericcrago/molecule-destroy) and `README.md` for usage)

Detail any linters or test runners used:

# Desired Behavior

Destroy steps run when tests fail and `tags` are used in `provisioner: options`.

# Actual Behaviour

Destroy steps do not run and PLAY RECAP details are missing when tests fail and `tags` are used in `provisioner: options`.

See [example repo](https://github.com/dericcrago/molecule-destroy).

```yaml
provisioner:
  name: ansible
  lint:
    name: ansible-lint
  options:
    tags: no-op
```

```
    PLAYBOOK: destroy.yml **********************************************************
    1 plays in /Users/deric/.local/share/virtualenvs/molecule-destroy-cLlJrhaP/src/molecule/molecule/provisioner/ansible/playbooks/docker/destroy.yml
    
    PLAY [Destroy] *****************************************************************
    META: ran handlers
    META: ran handlers
    META: ran handlers
    
    PLAY RECAP *********************************************************************
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `molecule/command/base.py`
Content:
```
1 #  Copyright (c) 2015-2018 Cisco Systems, Inc.
2 #
3 #  Permission is hereby granted, free of charge, to any person obtaining a copy
4 #  of this software and associated documentation files (the "Software"), to
5 #  deal in the Software without restriction, including without limitation the
6 #  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 #  sell copies of the Software, and to permit persons to whom the Software is
8 #  furnished to do so, subject to the following conditions:
9 #
10 #  The above copyright notice and this permission notice shall be included in
11 #  all copies or substantial portions of the Software.
12 #
13 #  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 #  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 #  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 #  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 #  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 #  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 #  DEALINGS IN THE SOFTWARE.
20 
21 import abc
22 import collections
23 import glob
24 import os
25 
26 import six
27 
28 import molecule.command
29 import molecule.scenarios
30 from molecule import config
31 from molecule import logger
32 from molecule import util
33 
34 LOG = logger.get_logger(__name__)
35 MOLECULE_GLOB = os.environ.get('MOLECULE_GLOB', 'molecule/*/molecule.yml')
36 MOLECULE_DEFAULT_SCENARIO_NAME = 'default'
37 
38 
39 @six.add_metaclass(abc.ABCMeta)
40 class Base(object):
41     """
42     An abstract base class used to define the command interface.
43     """
44 
45     def __init__(self, c):
46         """
47         Base initializer for all :ref:`Command` classes.
48 
49         :param c: An instance of a Molecule config.
50         :returns: None
51         """
52         self._config = c
53         self._setup()
54 
55     @abc.abstractmethod
56     def execute(self):  # pragma: no cover
57         pass
58 
59     def print_info(self):
60         msg = "Scenario: '{}'".format(self._config.scenario.name)
61         LOG.info(msg)
62         msg = "Action: '{}'".format(util.underscore(self.__class__.__name__))
63         LOG.info(msg)
64 
65     def _setup(self):
66         """
67         Prepare Molecule's provisioner and returns None.
68 
69         :return: None
70         """
71         self._config.provisioner.write_config()
72         self._config.provisioner.manage_inventory()
73 
74 
75 def execute_cmdline_scenarios(scenario_name, args, command_args):
76     """
77     Execute scenario sequences based on parsed command-line arguments.
78 
79     This is useful for subcommands that run scenario sequences, which
80     excludes subcommands such as ``list``, ``login``, and ``matrix``.
81 
82     ``args`` and ``command_args`` are combined using :func:`get_configs`
83     to generate the scenario(s) configuration.
84 
85     :param scenario_name: Name of scenario to run, or ``None`` to run all.
86     :param args: ``args`` dict from ``click`` command context
87     :param command_args: dict of command argumentss, including the target
88                          subcommand to execute
89     :returns: None
90 
91     """
92     scenarios = molecule.scenarios.Scenarios(
93         get_configs(args, command_args), scenario_name)
94     scenarios.print_matrix()
95     for scenario in scenarios:
96         try:
97             execute_scenario(scenario)
98         except SystemExit:
99             # if the command has a 'destroy' arg, like test does,
100             # handle that behavior here.
101             if command_args.get('destroy') == 'always':
102                 msg = ('An error occurred during the {} sequence action: '
103                        "'{}'. Cleaning up.").format(scenario.config.subcommand,
104                                                     scenario.config.action)
105                 LOG.warn(msg)
106                 execute_subcommand(scenario.config, 'cleanup')
107                 execute_subcommand(scenario.config, 'destroy')
108                 # always prune ephemeral dir if destroying on failure
109                 scenario.prune()
110                 util.sysexit()
111             else:
112                 raise
113 
114 
115 def execute_subcommand(config, subcommand):
116     command_module = getattr(molecule.command, subcommand)
117     command = getattr(command_module, util.camelize(subcommand))
118 
119     return command(config).execute()
120 
121 
122 def execute_scenario(scenario):
123     """
124     Execute each command in the given scenario's configured sequence.
125 
126     :param scenario: The scenario to execute.
127     :returns: None
128 
129     """
130 
131     for action in scenario.sequence:
132         # knowledge of the current action is used by some provisioners
133         # to ensure they behave correctly during certain sequence steps,
134         # and is also used for reporting in execute_cmdline_scenarios
135         scenario.config.action = action
136         execute_subcommand(scenario.config, action)
137 
138     # pruning only if a 'destroy' step was in the sequence allows for normal
139     # debugging by manually stepping through a scenario sequence
140     if 'destroy' in scenario.sequence:
141         scenario.prune()
142 
143 
144 def get_configs(args, command_args, ansible_args=()):
145     """
146     Glob the current directory for Molecule config files, instantiate config
147     objects, and returns a list.
148 
149     :param args: A dict of options, arguments and commands from the CLI.
150     :param command_args: A dict of options passed to the subcommand from
151      the CLI.
152     :param ansible_args: An optional tuple of arguments provided to the
153      `ansible-playbook` command.
154     :return: list
155     """
156     configs = [
157         config.Config(
158             molecule_file=util.abs_path(c),
159             args=args,
160             command_args=command_args,
161             ansible_args=ansible_args,
162         ) for c in glob.glob(MOLECULE_GLOB)
163     ]
164     _verify_configs(configs)
165 
166     return configs
167 
168 
169 def _verify_configs(configs):
170     """
171     Verify a Molecule config was found and returns None.
172 
173     :param configs: A list containing absolute paths to Molecule config files.
174     :return: None
175     """
176     if configs:
177         scenario_names = [c.scenario.name for c in configs]
178         for scenario_name, n in collections.Counter(scenario_names).items():
179             if n > 1:
180                 msg = ("Duplicate scenario name '{}' found.  "
181                        'Exiting.').format(scenario_name)
182                 util.sysexit_with_message(msg)
183 
184     else:
185         msg = "'{}' glob failed.  Exiting.".format(MOLECULE_GLOB)
186         util.sysexit_with_message(msg)
187 
188 
189 def _get_subcommand(string):
190     return string.split('.')[-1]
191
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/molecule/command/base.py b/molecule/command/base.py
--- a/molecule/command/base.py
+++ b/molecule/command/base.py
@@ -115,6 +115,11 @@
 def execute_subcommand(config, subcommand):
     command_module = getattr(molecule.command, subcommand)
     command = getattr(command_module, util.camelize(subcommand))
+    # knowledge of the current action is used by some provisioners
+    # to ensure they behave correctly during certain sequence steps,
+    # particulary the setting of ansible options in create/destroy,
+    # and is also used for reporting in execute_cmdline_scenarios
+    config.action = subcommand
 
     return command(config).execute()
 
@@ -129,10 +134,6 @@
     """
 
     for action in scenario.sequence:
-        # knowledge of the current action is used by some provisioners
-        # to ensure they behave correctly during certain sequence steps,
-        # and is also used for reporting in execute_cmdline_scenarios
-        scenario.config.action = action
         execute_subcommand(scenario.config, action)
 
     # pruning only if a 'destroy' step was in the sequence allows for normal

{"golden_diff": "diff --git a/molecule/command/base.py b/molecule/command/base.py\n--- a/molecule/command/base.py\n+++ b/molecule/command/base.py\n@@ -115,6 +115,11 @@\n def execute_subcommand(config, subcommand):\n     command_module = getattr(molecule.command, subcommand)\n     command = getattr(command_module, util.camelize(subcommand))\n+    # knowledge of the current action is used by some provisioners\n+    # to ensure they behave correctly during certain sequence steps,\n+    # particulary the setting of ansible options in create/destroy,\n+    # and is also used for reporting in execute_cmdline_scenarios\n+    config.action = subcommand\n \n     return command(config).execute()\n \n@@ -129,10 +134,6 @@\n     \"\"\"\n \n     for action in scenario.sequence:\n-        # knowledge of the current action is used by some provisioners\n-        # to ensure they behave correctly during certain sequence steps,\n-        # and is also used for reporting in execute_cmdline_scenarios\n-        scenario.config.action = action\n         execute_subcommand(scenario.config, action)\n \n     # pruning only if a 'destroy' step was in the sequence allows for normal\n", "issue": "destroy steps do not run when tests fail and tags are used in provisioner options\n# Issue Type\r\n\r\n- Bug report\r\n\r\n# Molecule and Ansible details\r\n\r\n```\r\npipenv run ansible --version && pipenv run molecule --version\r\nansible 2.7.10\r\n  config file = /Users/deric/.ansible.cfg\r\n  configured module search path = ['/Users/deric/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']\r\n  ansible python module location = /Users/deric/.local/share/virtualenvs/molecule-destroy-cLlJrhaP/lib/python3.7/site-packages/ansible\r\n  executable location = /Users/deric/.local/share/virtualenvs/molecule-destroy-cLlJrhaP/bin/ansible\r\n  python version = 3.7.3 (default, Apr  7 2019, 11:57:41) [Clang 10.0.0 (clang-1000.11.45.5)]\r\nmolecule, version 2.20.1.dev18\r\n```\r\n\r\nMolecule installation method (one of):\r\n\r\n- pipenv (see `Pipfile` in [example repo](https://github.com/dericcrago/molecule-destroy) and `README.md` for usage)\r\n\r\nAnsible installation method (one of):\r\n\r\n- pipenv (see `Pipfile` in [example repo](https://github.com/dericcrago/molecule-destroy) and `README.md` for usage)\r\n\r\nDetail any linters or test runners used:\r\n\r\n# Desired Behavior\r\n\r\nDestroy steps run when tests fail and `tags` are used in `provisioner: options`.\r\n\r\n# Actual Behaviour\r\n\r\nDestroy steps do not run and PLAY RECAP details are missing when tests fail and `tags` are used in `provisioner: options`.\r\n\r\nSee [example repo](https://github.com/dericcrago/molecule-destroy).\r\n\r\n```yaml\r\nprovisioner:\r\n  name: ansible\r\n  lint:\r\n    name: ansible-lint\r\n  options:\r\n    tags: no-op\r\n```\r\n\r\n```\r\n    PLAYBOOK: destroy.yml **********************************************************\r\n    1 plays in /Users/deric/.local/share/virtualenvs/molecule-destroy-cLlJrhaP/src/molecule/molecule/provisioner/ansible/playbooks/docker/destroy.yml\r\n    \r\n    PLAY [Destroy] *****************************************************************\r\n    META: ran handlers\r\n    META: ran handlers\r\n    META: ran handlers\r\n    \r\n    PLAY RECAP *********************************************************************\r\n```\n", "before_files": [{"content": "#  Copyright (c) 2015-2018 Cisco Systems, Inc.\n#\n#  Permission is hereby granted, free of charge, to any person obtaining a copy\n#  of this software and associated documentation files (the \"Software\"), to\n#  deal in the Software without restriction, including without limitation the\n#  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n#  sell copies of the Software, and to permit persons to whom the Software is\n#  furnished to do so, subject to the following conditions:\n#\n#  The above copyright notice and this permission notice shall be included in\n#  all copies or substantial portions of the Software.\n#\n#  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n#  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n#  DEALINGS IN THE SOFTWARE.\n\nimport abc\nimport collections\nimport glob\nimport os\n\nimport six\n\nimport molecule.command\nimport molecule.scenarios\nfrom molecule import config\nfrom molecule import logger\nfrom molecule import util\n\nLOG = logger.get_logger(__name__)\nMOLECULE_GLOB = os.environ.get('MOLECULE_GLOB', 'molecule/*/molecule.yml')\nMOLECULE_DEFAULT_SCENARIO_NAME = 'default'\n\n\n@six.add_metaclass(abc.ABCMeta)\nclass Base(object):\n    \"\"\"\n    An abstract base class used to define the command interface.\n    \"\"\"\n\n    def __init__(self, c):\n        \"\"\"\n        Base initializer for all :ref:`Command` classes.\n\n        :param c: An instance of a Molecule config.\n        :returns: None\n        \"\"\"\n        self._config = c\n        self._setup()\n\n    @abc.abstractmethod\n    def execute(self):  # pragma: no cover\n        pass\n\n    def print_info(self):\n        msg = \"Scenario: '{}'\".format(self._config.scenario.name)\n        LOG.info(msg)\n        msg = \"Action: '{}'\".format(util.underscore(self.__class__.__name__))\n        LOG.info(msg)\n\n    def _setup(self):\n        \"\"\"\n        Prepare Molecule's provisioner and returns None.\n\n        :return: None\n        \"\"\"\n        self._config.provisioner.write_config()\n        self._config.provisioner.manage_inventory()\n\n\ndef execute_cmdline_scenarios(scenario_name, args, command_args):\n    \"\"\"\n    Execute scenario sequences based on parsed command-line arguments.\n\n    This is useful for subcommands that run scenario sequences, which\n    excludes subcommands such as ``list``, ``login``, and ``matrix``.\n\n    ``args`` and ``command_args`` are combined using :func:`get_configs`\n    to generate the scenario(s) configuration.\n\n    :param scenario_name: Name of scenario to run, or ``None`` to run all.\n    :param args: ``args`` dict from ``click`` command context\n    :param command_args: dict of command argumentss, including the target\n                         subcommand to execute\n    :returns: None\n\n    \"\"\"\n    scenarios = molecule.scenarios.Scenarios(\n        get_configs(args, command_args), scenario_name)\n    scenarios.print_matrix()\n    for scenario in scenarios:\n        try:\n            execute_scenario(scenario)\n        except SystemExit:\n            # if the command has a 'destroy' arg, like test does,\n            # handle that behavior here.\n            if command_args.get('destroy') == 'always':\n                msg = ('An error occurred during the {} sequence action: '\n                       \"'{}'. Cleaning up.\").format(scenario.config.subcommand,\n                                                    scenario.config.action)\n                LOG.warn(msg)\n                execute_subcommand(scenario.config, 'cleanup')\n                execute_subcommand(scenario.config, 'destroy')\n                # always prune ephemeral dir if destroying on failure\n                scenario.prune()\n                util.sysexit()\n            else:\n                raise\n\n\ndef execute_subcommand(config, subcommand):\n    command_module = getattr(molecule.command, subcommand)\n    command = getattr(command_module, util.camelize(subcommand))\n\n    return command(config).execute()\n\n\ndef execute_scenario(scenario):\n    \"\"\"\n    Execute each command in the given scenario's configured sequence.\n\n    :param scenario: The scenario to execute.\n    :returns: None\n\n    \"\"\"\n\n    for action in scenario.sequence:\n        # knowledge of the current action is used by some provisioners\n        # to ensure they behave correctly during certain sequence steps,\n        # and is also used for reporting in execute_cmdline_scenarios\n        scenario.config.action = action\n        execute_subcommand(scenario.config, action)\n\n    # pruning only if a 'destroy' step was in the sequence allows for normal\n    # debugging by manually stepping through a scenario sequence\n    if 'destroy' in scenario.sequence:\n        scenario.prune()\n\n\ndef get_configs(args, command_args, ansible_args=()):\n    \"\"\"\n    Glob the current directory for Molecule config files, instantiate config\n    objects, and returns a list.\n\n    :param args: A dict of options, arguments and commands from the CLI.\n    :param command_args: A dict of options passed to the subcommand from\n     the CLI.\n    :param ansible_args: An optional tuple of arguments provided to the\n     `ansible-playbook` command.\n    :return: list\n    \"\"\"\n    configs = [\n        config.Config(\n            molecule_file=util.abs_path(c),\n            args=args,\n            command_args=command_args,\n            ansible_args=ansible_args,\n        ) for c in glob.glob(MOLECULE_GLOB)\n    ]\n    _verify_configs(configs)\n\n    return configs\n\n\ndef _verify_configs(configs):\n    \"\"\"\n    Verify a Molecule config was found and returns None.\n\n    :param configs: A list containing absolute paths to Molecule config files.\n    :return: None\n    \"\"\"\n    if configs:\n        scenario_names = [c.scenario.name for c in configs]\n        for scenario_name, n in collections.Counter(scenario_names).items():\n            if n > 1:\n                msg = (\"Duplicate scenario name '{}' found.  \"\n                       'Exiting.').format(scenario_name)\n                util.sysexit_with_message(msg)\n\n    else:\n        msg = \"'{}' glob failed.  Exiting.\".format(MOLECULE_GLOB)\n        util.sysexit_with_message(msg)\n\n\ndef _get_subcommand(string):\n    return string.split('.')[-1]\n", "path": "molecule/command/base.py"}], "after_files": [{"content": "#  Copyright (c) 2015-2018 Cisco Systems, Inc.\n#\n#  Permission is hereby granted, free of charge, to any person obtaining a copy\n#  of this software and associated documentation files (the \"Software\"), to\n#  deal in the Software without restriction, including without limitation the\n#  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n#  sell copies of the Software, and to permit persons to whom the Software is\n#  furnished to do so, subject to the following conditions:\n#\n#  The above copyright notice and this permission notice shall be included in\n#  all copies or substantial portions of the Software.\n#\n#  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n#  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n#  DEALINGS IN THE SOFTWARE.\n\nimport abc\nimport collections\nimport glob\nimport os\n\nimport six\n\nimport molecule.command\nimport molecule.scenarios\nfrom molecule import config\nfrom molecule import logger\nfrom molecule import util\n\nLOG = logger.get_logger(__name__)\nMOLECULE_GLOB = os.environ.get('MOLECULE_GLOB', 'molecule/*/molecule.yml')\nMOLECULE_DEFAULT_SCENARIO_NAME = 'default'\n\n\n@six.add_metaclass(abc.ABCMeta)\nclass Base(object):\n    \"\"\"\n    An abstract base class used to define the command interface.\n    \"\"\"\n\n    def __init__(self, c):\n        \"\"\"\n        Base initializer for all :ref:`Command` classes.\n\n        :param c: An instance of a Molecule config.\n        :returns: None\n        \"\"\"\n        self._config = c\n        self._setup()\n\n    @abc.abstractmethod\n    def execute(self):  # pragma: no cover\n        pass\n\n    def print_info(self):\n        msg = \"Scenario: '{}'\".format(self._config.scenario.name)\n        LOG.info(msg)\n        msg = \"Action: '{}'\".format(util.underscore(self.__class__.__name__))\n        LOG.info(msg)\n\n    def _setup(self):\n        \"\"\"\n        Prepare Molecule's provisioner and returns None.\n\n        :return: None\n        \"\"\"\n        self._config.provisioner.write_config()\n        self._config.provisioner.manage_inventory()\n\n\ndef execute_cmdline_scenarios(scenario_name, args, command_args):\n    \"\"\"\n    Execute scenario sequences based on parsed command-line arguments.\n\n    This is useful for subcommands that run scenario sequences, which\n    excludes subcommands such as ``list``, ``login``, and ``matrix``.\n\n    ``args`` and ``command_args`` are combined using :func:`get_configs`\n    to generate the scenario(s) configuration.\n\n    :param scenario_name: Name of scenario to run, or ``None`` to run all.\n    :param args: ``args`` dict from ``click`` command context\n    :param command_args: dict of command argumentss, including the target\n                         subcommand to execute\n    :returns: None\n\n    \"\"\"\n    scenarios = molecule.scenarios.Scenarios(\n        get_configs(args, command_args), scenario_name)\n    scenarios.print_matrix()\n    for scenario in scenarios:\n        try:\n            execute_scenario(scenario)\n        except SystemExit:\n            # if the command has a 'destroy' arg, like test does,\n            # handle that behavior here.\n            if command_args.get('destroy') == 'always':\n                msg = ('An error occurred during the {} sequence action: '\n                       \"'{}'. Cleaning up.\").format(scenario.config.subcommand,\n                                                    scenario.config.action)\n                LOG.warn(msg)\n                execute_subcommand(scenario.config, 'cleanup')\n                execute_subcommand(scenario.config, 'destroy')\n                # always prune ephemeral dir if destroying on failure\n                scenario.prune()\n                util.sysexit()\n            else:\n                raise\n\n\ndef execute_subcommand(config, subcommand):\n    command_module = getattr(molecule.command, subcommand)\n    command = getattr(command_module, util.camelize(subcommand))\n    # knowledge of the current action is used by some provisioners\n    # to ensure they behave correctly during certain sequence steps,\n    # particulary the setting of ansible options in create/destroy,\n    # and is also used for reporting in execute_cmdline_scenarios\n    config.action = subcommand\n\n    return command(config).execute()\n\n\ndef execute_scenario(scenario):\n    \"\"\"\n    Execute each command in the given scenario's configured sequence.\n\n    :param scenario: The scenario to execute.\n    :returns: None\n\n    \"\"\"\n\n    for action in scenario.sequence:\n        execute_subcommand(scenario.config, action)\n\n    # pruning only if a 'destroy' step was in the sequence allows for normal\n    # debugging by manually stepping through a scenario sequence\n    if 'destroy' in scenario.sequence:\n        scenario.prune()\n\n\ndef get_configs(args, command_args, ansible_args=()):\n    \"\"\"\n    Glob the current directory for Molecule config files, instantiate config\n    objects, and returns a list.\n\n    :param args: A dict of options, arguments and commands from the CLI.\n    :param command_args: A dict of options passed to the subcommand from\n     the CLI.\n    :param ansible_args: An optional tuple of arguments provided to the\n     `ansible-playbook` command.\n    :return: list\n    \"\"\"\n    configs = [\n        config.Config(\n            molecule_file=util.abs_path(c),\n            args=args,\n            command_args=command_args,\n            ansible_args=ansible_args,\n        ) for c in glob.glob(MOLECULE_GLOB)\n    ]\n    _verify_configs(configs)\n\n    return configs\n\n\ndef _verify_configs(configs):\n    \"\"\"\n    Verify a Molecule config was found and returns None.\n\n    :param configs: A list containing absolute paths to Molecule config files.\n    :return: None\n    \"\"\"\n    if configs:\n        scenario_names = [c.scenario.name for c in configs]\n        for scenario_name, n in collections.Counter(scenario_names).items():\n            if n > 1:\n                msg = (\"Duplicate scenario name '{}' found.  \"\n                       'Exiting.').format(scenario_name)\n                util.sysexit_with_message(msg)\n\n    else:\n        msg = \"'{}' glob failed.  Exiting.\".format(MOLECULE_GLOB)\n        util.sysexit_with_message(msg)\n\n\ndef _get_subcommand(string):\n    return string.split('.')[-1]\n", "path": "molecule/command/base.py"}]}