Skip to content

Commit 42ead72

Browse files
committed
feat: Add offline mode to firewall_lib_facts
When calling this role with `offline: false`, collect the facts using `firewall-offline-cmd`, which will work during container builds. Don't implement `detailed` mode yet -- there isn't much use of that during container builds, as there should be zero surprise about the current state. It is possible to implement if we ever need it, but let's only spend that time if/when we need it.
1 parent faed1e4 commit 42ead72

File tree

1 file changed

+73
-13
lines changed

1 file changed

+73
-13
lines changed

library/firewall_lib_facts.py

Lines changed: 73 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@
4040
type: bool
4141
required: false
4242
default: false
43+
online:
44+
description:
45+
When true, use the D-Bus API to query the status from the running system.
46+
Otherwise, use firewall-offline-cmd(1). Offline mode is (currently)
47+
incompatible with "detailed" mode.
48+
type: bool
49+
required: false
50+
default: true
4351
author: Brennan Paciorek (@BrennanPaciorek)
4452
"""
4553

@@ -92,35 +100,84 @@
92100
HAS_POLICIES = False
93101

94102

103+
def offline_cmd(module, args, defaults=False):
104+
# get the defaults by disabling the --system-config dir (ETC_FIREWALLD)
105+
conf_args = ["--system-config=/nonexisting"] if defaults else []
106+
return module.run_command(
107+
["firewall-offline-cmd"] + conf_args + args,
108+
check_rc=True,
109+
)[1].strip()
110+
111+
95112
def config_to_dict(module):
96113
detailed = module.params.get("detailed", False)
114+
online = module.params.get("online", True)
97115
config = {}
98116
defaults = {}
99117
custom = {}
100118
setting_list = ["zones", "services", "icmptypes", "helpers", "ipsets"]
101119

120+
if detailed and not online:
121+
module.fail_json(msg="detailed information not available in offline mode")
122+
102123
if HAS_POLICIES:
103124
setting_list.append("policies")
104125

105-
fw = FirewallClient()
126+
if online:
127+
fw = FirewallClient()
128+
129+
for setting in setting_list:
130+
default_setting_dir = os.path.join(
131+
firewall.config.USR_LIB_FIREWALLD, setting
132+
)
133+
custom_setting_dir = os.path.join(firewall.config.ETC_FIREWALLD, setting)
106134

107-
for setting in setting_list:
108-
default_setting_dir = os.path.join(firewall.config.USR_LIB_FIREWALLD, setting)
109-
custom_setting_dir = os.path.join(firewall.config.ETC_FIREWALLD, setting)
135+
settings = fetch_settings_from_dir(default_setting_dir, detailed, fw)
136+
if settings:
137+
defaults[setting] = settings
138+
settings = fetch_settings_from_dir(custom_setting_dir, True, fw)
139+
if settings:
140+
custom[setting] = settings
110141

111-
settings = fetch_settings_from_dir(default_setting_dir, detailed, fw)
112-
if settings:
113-
defaults[setting] = settings
114-
settings = fetch_settings_from_dir(custom_setting_dir, True, fw)
115-
if settings:
116-
custom[setting] = settings
142+
config["default_zone"] = fw.getDefaultZone()
143+
else:
144+
# get the default settings
145+
for setting in setting_list:
146+
values = offline_cmd(module, ["--get-" + setting], defaults=True).split()
147+
# zone services are important, so make them a dict, not a plain list (same as with online mode)
148+
if setting == "zones":
149+
for zone in values:
150+
services = offline_cmd(
151+
module, ["--zone", zone, "--list-services"], defaults=True
152+
).split()
153+
defaults.setdefault("zones", {})[zone] = {"services": services}
154+
else:
155+
defaults[setting] = values
156+
157+
# compute the custom settings by diffing with defaults
158+
for setting in setting_list:
159+
values = offline_cmd(module, ["--get-" + setting]).split()
160+
if setting == "zones":
161+
for zone in values:
162+
services = offline_cmd(
163+
module, ["--zone", zone, "--list-services"]
164+
).split()
165+
# add zone to custom if the whole zone is new or its services changed
166+
if zone not in defaults["zones"] or (
167+
set(services) - set(defaults["zones"][zone]["services"])
168+
):
169+
custom.setdefault("zones", {})[zone] = {"services": services}
170+
else:
171+
diff = set(values) - set(defaults[setting])
172+
if diff:
173+
custom[setting] = sorted(diff)
174+
175+
config["default_zone"] = offline_cmd(module, ["--get-default-zone"])
117176

118177
if defaults:
119178
config["default"] = defaults
120179
if custom:
121180
config["custom"] = custom
122-
config["default_zone"] = fw.getDefaultZone()
123-
124181
return config
125182

126183

@@ -198,7 +255,10 @@ def fetch_settings_from_dir(directory, detailed=False, fw=None):
198255

199256
def main():
200257

201-
module_args = dict(detailed=dict(type="bool", default=False, required=False))
258+
module_args = dict(
259+
detailed=dict(type="bool", default=False, required=False),
260+
online=dict(type="bool", default=True, required=False),
261+
)
202262

203263
results = dict(changed=False, firewall_config=dict())
204264

0 commit comments

Comments
 (0)