Skip to content

Commit bcf4446

Browse files
committed
proxmox_firewall: Add method to create rule at cluster level
1 parent 5185516 commit bcf4446

File tree

1 file changed

+102
-14
lines changed

1 file changed

+102
-14
lines changed

plugins/modules/proxmox_firewall.py

Lines changed: 102 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,31 @@ def get_proxmox_args():
3030
level=dict(type="str", choices=["cluster", "node", "vm", "vnet", "group"], default="cluster", required=False),
3131
node=dict(type="str", required=False),
3232
vmid=dict(type="int", required=False),
33-
vnet=dict(type="str", required=False)
33+
vnet=dict(type="str", required=False),
34+
rules=dict(
35+
type="list",
36+
elements="dict",
37+
required=False,
38+
options=dict(
39+
action=dict(type="str", required=True),
40+
type=dict(type="str", choices=["in", "out", "forward", "group"], required=True),
41+
comment=dict(type="str", required=False),
42+
dest=dict(type="str", required=False),
43+
digest=dict(type="str", required=False),
44+
dport=dict(type="str", required=False),
45+
enable=dict(type="bool", required=False),
46+
icmp_type=dict(type="str", required=False),
47+
iface=dict(type="str", required=False),
48+
log=dict(type="str",
49+
choices=["emerg", "alert", "crit", "err", "warning", "notice", "info", "debug", "nolog"],
50+
required=False),
51+
macro=dict(type="str", required=False),
52+
pos=dict(type="int", required=False),
53+
proto=dict(type="str", required=False),
54+
source=dict(type="str", required=False),
55+
sport=dict(type="str", required=False)
56+
)
57+
)
3458
)
3559

3660

@@ -54,20 +78,37 @@ def run(self):
5478
state = self.params.get("state")
5579
force = self.params.get("force")
5680
level = self.params.get("level")
57-
58-
if level == "vm":
59-
rules = self.get_vmid_fw_rules(vmid=self.params['vmid'])
60-
elif level == "node":
61-
rules = self.get_node_fw_rules(node=self.params['node'])
62-
elif level == "vnet":
63-
rules = self.get_vnet_fw_rules(vnet=self.params['vnet'])
64-
elif level == "group":
65-
rules = self.get_group_fw_rules(group=self.params['group'])
81+
rules =self.params.get("rules")
82+
83+
# if rules is not None:
84+
# rules = [rules.get('icmp_type')
85+
86+
if state == "present":
87+
if level == "vm":
88+
pass
89+
elif level == "node":
90+
pass
91+
elif level == "vnet":
92+
pass
93+
elif level == "group":
94+
pass
95+
else:
96+
if rules is not None:
97+
self.create_cluster_fw_rules(rules=rules)
6698
else:
67-
rules = self.get_cluster_fw_rules()
68-
self.module.exit_json(
69-
changed=False, firewall_rules=rules, msg=f'successfully retrieved firewall rules'
70-
)
99+
if level == "vm":
100+
rules = self.get_vmid_fw_rules(vmid=self.params['vmid'])
101+
elif level == "node":
102+
rules = self.get_node_fw_rules(node=self.params['node'])
103+
elif level == "vnet":
104+
rules = self.get_vnet_fw_rules(vnet=self.params['vnet'])
105+
elif level == "group":
106+
rules = self.get_group_fw_rules(group=self.params['group'])
107+
else:
108+
rules = self.get_cluster_fw_rules()
109+
self.module.exit_json(
110+
changed=False, firewall_rules=rules, msg=f'successfully retrieved firewall rules'
111+
)
71112

72113
def get_group_fw_rules(self, group, pos=None):
73114
try:
@@ -118,6 +159,53 @@ def get_vmid_fw_rules(self, vmid, pos=None):
118159
msg=f'Failed to retrieve firewall rules for vmid - {vmid}: {e}'
119160
)
120161

162+
def create_cluster_fw_rules(self, rules):
163+
for rule in rules:
164+
rule['icmp-type'] = rule.get('icmp_type')
165+
rule['enable'] = ansible_to_proxmox_bool(rule.get('enable'))
166+
del rule['icmp_type']
167+
try:
168+
firewall_obj = self.proxmox_api.cluster().firewall
169+
firewall_obj().rules().post(**rule)
170+
self.move_rule_to_correct_pos(firewall_obj, rule)
171+
172+
except Exception as e:
173+
self.module.fail_json(
174+
msg=f'Failed to create firewall rule {rule}: {e}'
175+
)
176+
else:
177+
self.module.exit_json(
178+
changed=True, msg=f'successfully created firewall rules'
179+
)
180+
181+
def move_rule_to_correct_pos(self, firewall_obj, rule):
182+
##################################################################################################
183+
# TODO: Once below mentioned issue is fixed. Remove this workaround. #
184+
# Currently Proxmox API doesn't honor pos. All new rules are created at pos 0 #
185+
# https://forum.proxmox.com/threads/issue-when-creating-a-firewall-rule.135878/ #
186+
# Not able to find it in BUGZILLA. So maybe this is expected behaviour. #
187+
# To workaround this issue we will check rule at pos 0 and if needed move it to correct position #
188+
##################################################################################################
189+
190+
pos = rule.get('pos')
191+
rule = {k: v for k, v in rule.items() if v is not None}
192+
if pos is not None and pos != 0:
193+
try:
194+
fw_rule_at0 = getattr(firewall_obj().rules(), str(0))
195+
for param, value, in fw_rule_at0.get().items():
196+
if param in rule.keys() and param != 'pos' and value != rule.get(param):
197+
self.module.warn(
198+
msg=f'Skipping workaround for rule placement. '
199+
f'Verify rule is at correct pos '
200+
f'provided - {rule} rule_at0 - {fw_rule_at0.get()}')
201+
break # No need to move this. Potentially the issue is resolved.
202+
else:
203+
fw_rule_at0.put(moveto=pos+1) # `moveto` moves rule to one position before the value
204+
except Exception as e:
205+
self.module.fail_json(
206+
msg=f'Rule created but failed to move it to correct pos. {e}'
207+
)
208+
121209

122210
def main():
123211
module = get_ansible_module()

0 commit comments

Comments
 (0)