Skip to content

Commit

Permalink
WIP: Enable access to available plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
ssbarnea committed May 23, 2023
1 parent 34c1459 commit 5be6c80
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 6 deletions.
71 changes: 65 additions & 6 deletions src/ansible_compat/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,63 @@ def __init__(self, version: str) -> None:
super().__init__(version)


@dataclass
class Plugins: # pylint: disable=too-many-instance-attributes
"""Dataclass to access installed Ansible plugins, uses ansible-doc to retrive them."""

runtime: "Runtime"
become: Optional[dict[str, str]] = None
cache: Optional[dict[str, str]] = None
callback: Optional[dict[str, str]] = None
cliconf: Optional[dict[str, str]] = None
connection: Optional[dict[str, str]] = None
httpapi: Optional[dict[str, str]] = None
inventory: Optional[dict[str, str]] = None
lookup: Optional[dict[str, str]] = None
netconf: Optional[dict[str, str]] = None
shell: Optional[dict[str, str]] = None
vars: Optional[dict[str, str]] = None
module: Optional[dict[str, str]] = None
strategy: Optional[dict[str, str]] = None
test: Optional[dict[str, str]] = None
filter: Optional[dict[str, str]] = None
role: Optional[dict[str, str]] = None
keyword: Optional[dict[str, str]] = None

def __getattribute__(self, attr: str) -> Any:
"""Get attribute."""
result = super().__getattribute__(attr)
if result is None and attr in {
"become",
"cache",
"callback",
"cliconf",
"connection",
"httpapi",
"inventory",
"lookup",
"netconf",
"shell",
"vars",
"module",
"strategy",
"test",
"filter",
"role",
"keyword",
}:
proc = self.runtime.run(
["ansible-doc", "--json", "-l", "-t", attr],
)
data = json.loads(proc.stdout)
if not isinstance(data, dict):
msg = "Unexpected output from ansible-doc"
raise AnsibleCompatError(msg)
result = data

return result


# pylint: disable=too-many-instance-attributes
class Runtime:
"""Ansible Runtime manager."""
Expand All @@ -83,6 +140,7 @@ class Runtime:
# Used to track if we have already initialized the Ansible runtime as attempts
# to do it multiple tilmes will cause runtime warnings from within ansible-core
initialized: bool = False
plugins: Plugins

def __init__(
self,
Expand Down Expand Up @@ -119,6 +177,7 @@ def __init__(
self.isolated = isolated
self.max_retries = max_retries
self.environ = environ or os.environ.copy()
self.plugins = Plugins(runtime=self)
# Reduce noise from paramiko, unless user already defined PYTHONWARNINGS
# paramiko/transport.py:236: CryptographyDeprecationWarning: Blowfish has been deprecated
# https://github.com/paramiko/paramiko/issues/2038
Expand All @@ -143,10 +202,10 @@ def __init__(

# pylint: disable=unused-argument
def warning(
self: Display, # noqa: ARG001
self: Display,
msg: str,
*,
formatted: bool = False, # noqa: ARG001
formatted: bool = False,
) -> None:
"""Override ansible.utils.display.Display.warning to avoid printing warnings."""
warnings.warn(
Expand Down Expand Up @@ -231,10 +290,10 @@ def _ensure_module_available(self) -> None:
# noinspection PyProtectedMember
# pylint: disable=protected-access
col_path += self.config.collections_paths
col_path += os.path.dirname( # noqa: PTH120
col_path += os.path.dirname(
os.environ.get(ansible_collections_path(), "."),
).split(":")
_AnsibleCollectionFinder( # noqa: SLF001
_AnsibleCollectionFinder(
paths=col_path,
)._install() # pylint: disable=protected-access
Runtime.initialized = True
Expand Down Expand Up @@ -395,7 +454,7 @@ def install_collection_from_disk(
)

# pylint: disable=too-many-branches
def install_requirements( # noqa: C901
def install_requirements(
self,
requirement: Path,
*,
Expand Down Expand Up @@ -477,7 +536,7 @@ def install_requirements( # noqa: C901
_logger.error(result.stderr)
raise AnsibleCommandError(result)

def prepare_environment( # noqa: C901
def prepare_environment(
self,
required_collections: Optional[dict[str, str]] = None,
*,
Expand Down
20 changes: 20 additions & 0 deletions test/test_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -747,3 +747,23 @@ def test_runtime_exec_env(runtime: Runtime) -> None:
runtime.environ["FOO"] = "bar"
result = runtime.run(["printenv", "FOO"])
assert result.stdout.rstrip() == "bar"


def test_runtime_plugins(runtime: Runtime) -> None:
assert "ansible.builtin.sudo" in runtime.plugins.become
assert "ansible.builtin.memory" in runtime.plugins.cache
assert "ansible.builtin.default" in runtime.plugins.callback
assert len(runtime.plugins.cliconf) == 0
assert "ansible.builtin.local" in runtime.plugins.connection
assert "ansible.netcommon.restconf" in runtime.plugins.httpapi
assert "ansible.builtin.ini" in runtime.plugins.inventory
assert "ansible.builtin.env" in runtime.plugins.lookup
assert "ansible.netcommon.default" in runtime.plugins.netconf
assert "ansible.builtin.sh" in runtime.plugins.shell
assert "ansible.builtin.host_group_vars" in runtime.plugins.vars
assert "ansible.builtin.file" in runtime.plugins.module
assert "ansible.builtin.free" in runtime.plugins.strategy
assert "ansible.builtin.is_abs" in runtime.plugins.test
assert "ansible.builtin.bool" in runtime.plugins.filter
assert isinstance(runtime.plugins.role, dict)
assert "become" in runtime.plugins.keyword

0 comments on commit 5be6c80

Please sign in to comment.