Skip to content

Commit 48984fd

Browse files
authored
List enabled and available features
1 parent 5a2eb8b commit 48984fd

File tree

6 files changed

+118
-0
lines changed

6 files changed

+118
-0
lines changed

src/ansible.cfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@
22
host_key_checking = False
33
roles_path = ./roles
44
filter_plugins = ./filter_plugins
5+
callback_plugins = ./callback_plugins
56
callback_result_format = yaml
7+
stdout_callback = foremanctl

src/callback_plugins/foremanctl.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from ansible.plugins.callback.default import CallbackModule as DefaultCallbackModule
2+
3+
DOCUMENTATION = """
4+
name: foremanctl
5+
type: stdout
6+
short_description: foremanctl stdout callback
7+
description:
8+
- Suppresses default Ansible output for plays tagged with
9+
foremanctl_suppress_default_output, displaying only task msg rather than ansible default output.
10+
extends_documentation_fragment:
11+
- default_callback
12+
- result_format_callback
13+
requirements:
14+
- set as stdout in configuration
15+
"""
16+
17+
class CallbackModule(DefaultCallbackModule):
18+
"""Foremanctl callback."""
19+
20+
CALLBACK_VERSION = 2.0
21+
CALLBACK_TYPE = 'stdout'
22+
CALLBACK_NAME = 'foremanctl'
23+
24+
FALLBACK_TO_DEFAULT = True
25+
26+
def v2_playbook_on_start(self, playbook):
27+
plays = playbook.get_plays()
28+
tags = plays[0].tags
29+
if 'foremanctl_suppress_default_output' in tags:
30+
self.FALLBACK_TO_DEFAULT = False
31+
if self.FALLBACK_TO_DEFAULT:
32+
super().v2_playbook_on_start(playbook)
33+
34+
def v2_playbook_on_play_start(self, play):
35+
if self.FALLBACK_TO_DEFAULT:
36+
super().v2_playbook_on_play_start(play)
37+
38+
def v2_playbook_on_task_start(self, task, is_conditional):
39+
if self.FALLBACK_TO_DEFAULT:
40+
super().v2_playbook_on_task_start(task, is_conditional)
41+
42+
def v2_runner_on_ok(self, result):
43+
if self.FALLBACK_TO_DEFAULT:
44+
super().v2_runner_on_ok(result)
45+
else:
46+
if msg := result._result.get('msg'):
47+
self._display.display(msg)
48+
49+
def v2_playbook_on_stats(self, stats):
50+
if self.FALLBACK_TO_DEFAULT:
51+
super().v2_playbook_on_stats(stats)

src/filter_plugins/foremanctl.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,23 @@ def available_foreman_plugins(_value):
5555
plugins = [FEATURE_MAP.get(feature).get('foreman', {}).get('plugin_name') for feature in FEATURE_MAP.keys()]
5656
return compact_list(plugins)
5757

58+
def list_all_features(enabled_features, only_enabled=False):
59+
enabled_list = []
60+
available_list = []
61+
for name, meta in FEATURE_MAP.items():
62+
if meta.get('internal', False):
63+
continue
64+
description = meta.get('description', '')
65+
if name in enabled_features:
66+
enabled_list.append((name, 'enabled', description))
67+
elif not only_enabled:
68+
available_list.append((name, 'available', description))
69+
70+
output = [f"{'FEATURE':<25} {'STATE':<12} DESCRIPTION"]
71+
for name, state, description in enabled_list + available_list:
72+
output.append(f"{name:<25} {state:<12} {description}")
73+
74+
return "\n".join(output)
5875

5976
def foreman_proxy_plugins(value):
6077
dependencies = list(get_dependencies(filter_features(value)))
@@ -76,4 +93,5 @@ def filters(self):
7693
'available_foreman_plugins': available_foreman_plugins,
7794
'features_to_foreman_proxy_plugins': foreman_proxy_plugins,
7895
'available_foreman_proxy_plugins': available_foreman_proxy_plugins,
96+
'list_all_features': list_all_features,
7997
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
- name: List features
3+
hosts: quadlet
4+
gather_facts: false
5+
tags:
6+
- foremanctl_suppress_default_output
7+
vars:
8+
list_enabled: false
9+
vars_files:
10+
- "../../vars/defaults.yml"
11+
- "../../vars/flavors/{{ flavor }}.yml"
12+
- "../../vars/base.yaml"
13+
tasks:
14+
- name: Print features
15+
ansible.builtin.debug:
16+
msg: "{{ enabled_features | list_all_features(list_enabled) }}"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
help: List all enabled and available features
3+
4+
variables:
5+
list_enabled:
6+
parameter: --list-enabled
7+
help: List only enabled features
8+
action: store_true
9+
persist: false

tests/features_test.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import subprocess
2+
3+
def test_foremanctl_features():
4+
command = ['./foremanctl', 'features']
5+
result = subprocess.run(command, capture_output=True, text=True)
6+
7+
assert result.returncode == 0
8+
9+
for noise in ['PLAY [', 'TASK [', 'ok:', 'changed:', 'PLAY RECAP']:
10+
assert noise not in result.stdout, f"Ansible output not suppressed: found '{noise}'"
11+
12+
for feature in ['foreman', 'foreman-proxy', 'azure-rm']:
13+
assert feature in result.stdout, f"Expected feature '{feature}' in output"
14+
15+
def test_foremanctl_features_list_enabled():
16+
command = ['./foremanctl', 'features', '--list-enabled']
17+
result = subprocess.run(command, capture_output=True, text=True)
18+
19+
assert result.returncode == 0
20+
21+
assert 'enabled' in result.stdout
22+
assert 'available' not in result.stdout

0 commit comments

Comments
 (0)