@@ -30,7 +30,31 @@ def get_proxmox_args():
30
30
level = dict (type = "str" , choices = ["cluster" , "node" , "vm" , "vnet" , "group" ], default = "cluster" , required = False ),
31
31
node = dict (type = "str" , required = False ),
32
32
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
+ )
34
58
)
35
59
36
60
@@ -54,20 +78,37 @@ def run(self):
54
78
state = self .params .get ("state" )
55
79
force = self .params .get ("force" )
56
80
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 )
66
98
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
+ )
71
112
72
113
def get_group_fw_rules (self , group , pos = None ):
73
114
try :
@@ -118,6 +159,53 @@ def get_vmid_fw_rules(self, vmid, pos=None):
118
159
msg = f'Failed to retrieve firewall rules for vmid - { vmid } : { e } '
119
160
)
120
161
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
+
121
209
122
210
def main ():
123
211
module = get_ansible_module ()
0 commit comments