84
84
- Comment for security group.
85
85
- Only needed when creating group.
86
86
type: str
87
+ aliases:
88
+ description:
89
+ - List of aliases
90
+ - Alias can only be created/updated/deleted at cluster or VM level
91
+ type: list
92
+ elements: dict
93
+ suboptions:
94
+ name:
95
+ description: Alias name
96
+ type: str
97
+ required: true
98
+ cidr:
99
+ description:
100
+ - CIDR for alias
101
+ - only needed when O(state=present) or O(state=update)
102
+ type: str
103
+ required: false
104
+ comment:
105
+ description: Comment for Alias
106
+ type: str
107
+ required: false
87
108
rules:
88
109
description:
89
110
- List of individual rules to be applied.
273
294
group_conf: True
274
295
state: absent
275
296
group: test
297
+
298
+ - name: Create FW aliases
299
+ community.proxmox.proxmox_firewall:
300
+ api_user: "{{ pc.proxmox.api_user }}"
301
+ api_token_id: "{{ pc.proxmox.api_token_id }}"
302
+ api_token_secret: "{{ vault.proxmox.api_token_secret }}"
303
+ api_host: "{{ pc.proxmox.api_host }}"
304
+ validate_certs: no
305
+ state: present
306
+ aliases:
307
+ - name: test1
308
+ cidr: '10.10.1.0/24'
309
+ - name: test2
310
+ cidr: '10.10.2.0/24'
311
+
312
+ - name: Update FW aliases
313
+ community.proxmox.proxmox_firewall:
314
+ api_user: "{{ pc.proxmox.api_user }}"
315
+ api_token_id: "{{ pc.proxmox.api_token_id }}"
316
+ api_token_secret: "{{ vault.proxmox.api_token_secret }}"
317
+ api_host: "{{ pc.proxmox.api_host }}"
318
+ validate_certs: no
319
+ state: update
320
+ aliases:
321
+ - name: test1
322
+ cidr: '10.10.1.0/28'
323
+ - name: test2
324
+ cidr: '10.10.2.0/28'
325
+
326
+ - name: Delete FW aliases
327
+ community.proxmox.proxmox_firewall:
328
+ api_user: "{{ pc.proxmox.api_user }}"
329
+ api_token_id: "{{ pc.proxmox.api_token_id }}"
330
+ api_token_secret: "{{ vault.proxmox.api_token_secret }}"
331
+ api_host: "{{ pc.proxmox.api_host }}"
332
+ validate_certs: no
333
+ state: absent
334
+ aliases:
335
+ - name: test1
336
+ - name: test2
276
337
"""
277
338
278
339
RETURN = r"""
291
352
sample:
292
353
[ "test" ]
293
354
355
+ aliases:
356
+ description:
357
+ - list of alias present at given level
358
+ - aliases are only available for cluster and VM level so if any other level it'll be empty list
359
+ returned: on success
360
+ type: list
361
+ elements: dict
362
+ sample:
363
+ [
364
+ {
365
+ "cidr": "10.10.1.0/24",
366
+ "digest": "978391f460484e8d4fb3ca785cfe5a9d16fe8b1f",
367
+ "ipversion": 4,
368
+ "name": "test1"
369
+ },
370
+ {
371
+ "cidr": "10.10.2.0/24",
372
+ "digest": "978391f460484e8d4fb3ca785cfe5a9d16fe8b1f",
373
+ "ipversion": 4,
374
+ "name": "test2"
375
+ },
376
+ {
377
+ "cidr": "10.10.3.0/24",
378
+ "digest": "978391f460484e8d4fb3ca785cfe5a9d16fe8b1f",
379
+ "ipversion": 4,
380
+ "name": "test3"
381
+ }
382
+ ]
383
+
294
384
firewall_rules:
295
385
description: List of firewall rules.
296
386
returned: on success
@@ -416,6 +506,16 @@ def get_proxmox_args():
416
506
group_conf = dict (type = "bool" , default = False ),
417
507
group = dict (type = "str" , required = False ),
418
508
comment = dict (type = "str" , required = False ),
509
+ aliases = dict (
510
+ type = "list" ,
511
+ elements = "dict" ,
512
+ required = False ,
513
+ options = dict (
514
+ name = dict (type = "str" , required = True ),
515
+ cidr = dict (type = "str" , required = False ),
516
+ comment = dict (type = "str" , required = False )
517
+ )
518
+ ),
419
519
rules = dict (
420
520
type = "list" ,
421
521
elements = "dict" ,
@@ -455,6 +555,9 @@ def get_ansible_module():
455
555
('level' , 'node' , ['node' ]),
456
556
('level' , 'vnet' , ['vnet' ]),
457
557
('level' , 'group' , ['group' ]),
558
+ ],
559
+ mutually_exclusive = [
560
+ ('aliases' , 'rules' ),
458
561
]
459
562
)
460
563
@@ -466,18 +569,18 @@ def __init__(self, module):
466
569
467
570
def validate_params (self ):
468
571
if self .params .get ('state' ) in ['present' , 'update' ]:
469
- if self .params .get ('group_conf' ) != bool (self .params .get ('rules' )):
572
+ if self .params .get ('group_conf' ) != bool (self .params .get ('rules' ) or self . params . get ( 'aliases' ) ):
470
573
return True
471
574
else :
472
575
self .module .fail_json (
473
- msg = "When state is present either group_conf should be true or rules must be present but not both"
576
+ msg = "When state is present either group_conf should be true or rules/aliases must be present but not both"
474
577
)
475
578
elif self .params .get ('state' ) == 'absent' :
476
- if self .params .get ('group_conf' ) != bool (self .params .get ('pos' )):
579
+ if self .params .get ('group_conf' ) != bool (self .params .get ('pos' ) or self . params . get ( 'aliases' ) ):
477
580
return True
478
581
else :
479
582
self .module .fail_json (
480
- msg = "When State is absent either group_conf should be true or pos must be present but not both"
583
+ msg = "When State is absent either group_conf should be true or pos/aliases must be present but not both"
481
584
)
482
585
else :
483
586
return True
@@ -488,6 +591,7 @@ def run(self):
488
591
state = self .params .get ("state" )
489
592
force = self .params .get ("force" )
490
593
level = self .params .get ("level" )
594
+ aliases = self .params .get ("aliases" )
491
595
rules = self .params .get ("rules" )
492
596
group = self .params .get ("group" )
493
597
group_conf = self .params .get ("group_conf" )
@@ -517,6 +621,7 @@ def run(self):
517
621
rules_obj = firewall_obj ().rules
518
622
519
623
elif level == "group" :
624
+ firewall_obj = None
520
625
rules_obj = getattr (self .proxmox_api .cluster ().firewall ().groups (), group )
521
626
522
627
else :
@@ -528,26 +633,140 @@ def run(self):
528
633
self .create_group (group = group , comment = self .params .get ('comment' ))
529
634
if rules is not None :
530
635
self .create_fw_rules (rules_obj = rules_obj , rules = rules , force = force )
636
+ if aliases is not None :
637
+ self .create_aliases (firewall_obj = firewall_obj , level = level , aliases = aliases , force = force )
531
638
elif state == "update" :
532
639
if group_conf :
533
640
self .create_group (group = group , comment = self .params .get ('comment' ))
534
641
if rules is not None :
535
642
self .update_fw_rules (rules_obj = rules_obj , rules = rules , force = force )
643
+ if aliases is not None :
644
+ self .update_aliases (firewall_obj = firewall_obj , level = level , aliases = aliases , force = force )
536
645
elif state == "absent" :
537
646
if self .params .get ('pos' ):
538
647
self .delete_fw_rule (rules_obj = rules_obj , pos = self .params .get ('pos' ))
539
648
if group_conf :
540
649
self .delete_group (group_name = group )
650
+ if aliases is not None :
651
+ self .delete_aliases (firewall_obj = firewall_obj , level = level , aliases = aliases )
541
652
else :
542
653
rules = self .get_fw_rules (rules_obj , pos = self .params .get ('pos' ))
543
654
groups = self .get_groups ()
655
+ aliases = self .get_aliases (firewall_obj = firewall_obj , level = level )
544
656
self .module .exit_json (
545
657
changed = False ,
546
658
firewall_rules = rules ,
547
659
groups = groups ,
660
+ aliases = aliases ,
548
661
msg = 'successfully retrieved firewall rules and groups'
549
662
)
550
663
664
+ def get_aliases (self , firewall_obj , level ):
665
+ if firewall_obj is None or level not in ['cluster' , 'vm' ]:
666
+ return list ()
667
+ try :
668
+ return firewall_obj ().aliases ().get ()
669
+ except Exception as e :
670
+ self .module .fail_json (
671
+ msg = 'Failed to retrieve aliases'
672
+ )
673
+
674
+ def create_aliases (self , firewall_obj , level , aliases , force = False ):
675
+ if firewall_obj is None or level not in ['cluster' , 'vm' ]:
676
+ self .module .fail_json (
677
+ msg = 'Aliases can only be created at cluster or VM level'
678
+ )
679
+
680
+ aliases_to_create , aliases_to_update = compare_list_of_dicts (
681
+ existing_list = self .get_aliases (firewall_obj = firewall_obj , level = level ),
682
+ new_list = aliases ,
683
+ uid = 'name' ,
684
+ params_to_ignore = ['digest' , 'ipversion' ]
685
+ )
686
+
687
+ if len (aliases_to_create ) == 0 and len (aliases_to_update ) == 0 :
688
+ self .module .exit_json (
689
+ changed = False ,
690
+ msg = 'No need to create/update any aliases'
691
+ )
692
+ elif len (aliases_to_update ) > 0 and not force :
693
+ self .module .fail_json (
694
+ msg = f"Need to update aliases - { [x ['name' ] for x in aliases_to_update ]} but force is false"
695
+ )
696
+
697
+ for alias in aliases_to_create :
698
+ try :
699
+ firewall_obj ().aliases ().post (** alias )
700
+ except Exception as e :
701
+ self .module .fail_json (
702
+ msg = f"Failed to create Alias { alias ['name' ]} - { e } "
703
+ )
704
+ if len (aliases_to_update ) > 0 and force :
705
+ self .update_aliases (firewall_obj = firewall_obj , level = level , aliases = aliases_to_update , force = False )
706
+ else :
707
+ self .module .exit_json (
708
+ changed = True ,
709
+ msg = "Aliases created"
710
+ )
711
+
712
+ def update_aliases (self , firewall_obj , level , aliases , force = False ):
713
+ aliases_to_create , aliases_to_update = compare_list_of_dicts (
714
+ existing_list = self .get_aliases (firewall_obj = firewall_obj , level = level ),
715
+ new_list = aliases ,
716
+ uid = 'name' ,
717
+ params_to_ignore = ['digest' , 'ipversion' ]
718
+ )
719
+
720
+ if len (aliases_to_update ) == 0 and len (aliases_to_create ) == 0 :
721
+ self .module .exit_json (
722
+ changed = False ,
723
+ msg = 'No need to create/update any alias.'
724
+
725
+ )
726
+ elif len (aliases_to_create ) > 0 and not force :
727
+ self .module .fail_json (
728
+ msg = f"Need to create new alias - { [x ['name' ] for x in aliases_to_create ]} But force is false"
729
+ )
730
+
731
+ for alias in aliases_to_update :
732
+ try :
733
+ alias_obj = getattr (firewall_obj ().aliases (), alias ['name' ])
734
+ alias_obj ().put (** alias )
735
+ except Exception as e :
736
+ self .module .fail_json (
737
+ msg = f"Failed to update Alias { alias ['name' ]} - { e } "
738
+ )
739
+ if len (aliases_to_update ) > 0 and force :
740
+ self .update_aliases (firewall_obj = firewall_obj , level = level , aliases = aliases_to_update , force = False )
741
+ else :
742
+ self .module .exit_json (
743
+ changed = True ,
744
+ msg = "Aliases updated"
745
+ )
746
+
747
+ def delete_aliases (self , firewall_obj , level , aliases ):
748
+ existing_aliases = set ([x .get ('name' ) for x in self .get_aliases (firewall_obj = firewall_obj , level = level )])
749
+ aliases = set ([x .get ('name' ) for x in aliases ])
750
+ aliases_to_delete = list (existing_aliases .intersection (aliases ))
751
+
752
+ if len (aliases_to_delete ) == 0 :
753
+ self .module .exit_json (
754
+ changed = False ,
755
+ msg = "No need to delete any alias"
756
+ )
757
+ for alias_name in aliases_to_delete :
758
+ try :
759
+ alias_obj = getattr (firewall_obj ().aliases (), alias_name )
760
+ alias_obj ().delete ()
761
+ except Exception as e :
762
+ self .module .fail_json (
763
+ msg = f"Failed to delete alias { alias_name } - { e } "
764
+ )
765
+ self .module .exit_json (
766
+ changed = True ,
767
+ msg = "Successfully deleted aliases"
768
+ )
769
+
551
770
def create_group (self , group , comment = None ):
552
771
if group in self .get_groups ():
553
772
self .module .exit_json (
0 commit comments