# Existing code that overrides a strategy does not work in Ansible 6+

**URL:** <https://forum.ansible.com/t/existing-code-that-overrides-a-strategy-does-not-work-in-ansible-6/4845>\
**Category:** Get Help\
**Tags:** strategy, ansible-core\
**Created:** [April 9, 2024, 4:32pm UTC](https://forum.ansible.com/t/existing-code-that-overrides-a-strategy-does-not-work-in-ansible-6/4845 "2024-04-09T16:32:15Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![mbutton77](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/mbutton77/32/2432_2.png) [@mbutton77](https://forum.ansible.com/u/mbutton77)\
**Post date:** [April 9, 2024, 4:32pm UTC](https://forum.ansible.com/t/existing-code-that-overrides-a-strategy-does-not-work-in-ansible-6/4845/1 "2024-04-09T16:32:15Z")

</div>

Hi,

**I’m trying to override a base strategy in Ansible 6+.  
So far, my code works perfectly fine on Ansible 5 and less, but as soon as I try it on a more recent version, it fails.**

To illustrate my problem, I made a small reproducer.  
A dumb playbook (which targets the default strategy, linear):

```auto
---
- hosts: localhost
  gather_facts: no
  tasks:
    - ansible.builtin.debug:
        msg: "Hello"

```

The overriding strategy (located in **/usr/share/ansible/plugins/strategy/linear.py** ) :

```auto
#!/usr/bin/python
# -*- coding: utf-8 -*-

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

import os
import sys

from ansible.plugins.strategy.linear import StrategyModule

class StrategyModule(StrategyModule):

    def __init__ (self, tqm):
        super(StrategyModule, self). __init__ (tqm)

    def run(self, iterator, play_context):
        print("Customizing the linear strategy")
        return super(StrategyModule, self).run(iterator, play_context)

```

(the code is very similar to what we can find in the debug strategy)

Executing this code in a Ansible 5 Venv :

```auto
(ansible5) [root@max-rhel8 ~]# ansible-playbook main.yml
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [localhost] ************************************************************************************************************************************
Customizing the linear strategy

TASK [debug] ****************************************************************************************************************************************
ok: [localhost] => {
    "msg": "Hello"
}

PLAY RECAP ******************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

```

Executing the very same code in a Ansible 6 Venv :

```auto
(ansible6) [root@max-rhel8 ~]# ansible-playbook main.yml
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [localhost] ************************************************************************************************************************************
ERROR! Unexpected Exception, this is probably a bug: cannot import name 'StrategyModule' from 'ansible.plugins.strategy.linear' (/usr/share/ansible/plugins/strategy/linear.py)
to see the full traceback, use -vvv

```

I read in a Mitogen issue stating that calling the ansible.plugins.strategy package is generally a bad idea :

> ```
> Regardless it's probably common across versions - "ansible.plugins.strategy.*" is a magic namespace managed by Ansible's PluginLoader.
> The solution is probably to avoid direct import, but asking PluginLoader to do it for us.
> 
> ```

**Source** : [ansible: 'module' object has no attribute 'linear' when first play doesn't use mitogen · Issue #294 · mitogen-hq/mitogen · GitHub](https://github.com/mitogen-hq/mitogen/issues/294#issuecomment-403283920)

I then try to read about the **PluginLoader** and especially the **strategy\_loader** , but I don’t think it’s the same usage and on top of that I don’t know how to use it.  
I’ve found very few usecases and that kind of code doesn’t help me much.

```auto
    from ansible.plugins.loader import strategy_loader
    from ansible.plugins.strategy import StrategyBase
[...]
    strategy = strategy_loader.get(new_play.strategy, self)

```

If anyone has some insight on that one, I would be grateful.  
Thanks.

---

<div class="post-metadata">

**Author:** ![Denney-tech](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/denney-tech/32/1556_2.png) [@Denney-tech](https://forum.ansible.com/u/Denney-tech)\
**Post date:** [April 9, 2024, 4:50pm UTC](https://forum.ansible.com/t/existing-code-that-overrides-a-strategy-does-not-work-in-ansible-6/4845/2 "2024-04-09T16:50:31Z")

</div>

I’m _not a python developer_ so take this with a grain of salt.

It looks to me like you’re _replacing_ the linear strategy, not overriding/customizing it. You’re trying to import a class that doesn’t exist because you didn’t define it in _your_ ansible.plugins.strategy.linear library.

I think the solution would be to create a new strategy by a different name that piggybacks off the linear strategy, so that your custom\_linear strategy does not replace it. Then set your ansible.cfg to use your strategy by default.

Then again, I’m no python expert. I wouldn’t have thought what you’re doing would have worked in older versions of Ansible either.

---

<div class="post-metadata">

**Author:** ![mbutton77](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/mbutton77/32/2432_2.png) [@mbutton77](https://forum.ansible.com/u/mbutton77)\
**Post date:** [April 10, 2024, 12:32pm UTC](https://forum.ansible.com/t/existing-code-that-overrides-a-strategy-does-not-work-in-ansible-6/4845/3 "2024-04-10T12:32:29Z")

</div>

Hey Caleb, thanks for your reply.

I’m not a Python develop either, but I thought I understood the Python classpath mechanism. Ansible is built upon Python and therefore uses the Python mechanisms.

What I don’t get is how changing the Ansible version could lead to a loading behavior change whereas I’m using the same Python version (3.8.6) in my virtual environments. Moreover, if I try to import the class in a Python prompt, it works just fine.

Else, your proposal is similar to the one I got from ChatGPT 🙂  
But I do want to “override” the default strategies, for security reasons (I want all the playbooks to get through a verification process before starting).

For now, I have two workarounds and the most elegant one is to simply make a symbolic link on the final strategy and refering to that one in my overriding strategy.

But I would love to understand what changed between Ansible 5 and 6. I diffed several files ( **\_\_init\_\_py** in the strategy folder, the **plugin loader** , …) but I could not get a clear explanation.  
I’m not stuck but a little bit confused.
