1#!/usr/bin/python 2 3# Copyright: (c) 2015, VMware, Inc. All Rights Reserved. 4# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 5 6from __future__ import absolute_import, division, print_function 7__metaclass__ = type 8 9ANSIBLE_METADATA = {'metadata_version': '1.1', 10 'status': ['preview'], 11 'supported_by': 'community'} 12 13DOCUMENTATION = ''' 14--- 15module: vca_fw 16short_description: add remove firewall rules in a gateway in a vca 17description: 18 - Adds or removes firewall rules from a gateway in a vca environment 19version_added: "2.0" 20author: 21- Peter Sprygada (@privateip) 22options: 23 fw_rules: 24 description: 25 - A list of firewall rules to be added to the gateway, Please see examples on valid entries 26 required: True 27 default: false 28extends_documentation_fragment: vca.documentation 29''' 30 31EXAMPLES = ''' 32 33#Add a set of firewall rules 34 35- hosts: localhost 36 connection: local 37 tasks: 38 - vca_fw: 39 instance_id: 'b15ff1e5-1024-4f55-889f-ea0209726282' 40 vdc_name: 'benz_ansible' 41 state: 'absent' 42 fw_rules: 43 - description: "ben testing" 44 source_ip: "Any" 45 dest_ip: 192.0.2.23 46 - description: "ben testing 2" 47 source_ip: 192.0.2.50 48 source_port: "Any" 49 dest_port: "22" 50 dest_ip: 192.0.2.101 51 is_enable: "true" 52 enable_logging: "false" 53 protocol: "Tcp" 54 policy: "allow" 55 56''' 57 58try: 59 from pyvcloud.schema.vcd.v1_5.schemas.vcloud.networkType import FirewallRuleType 60 from pyvcloud.schema.vcd.v1_5.schemas.vcloud.networkType import ProtocolsType 61except ImportError: 62 # normally set a flag here but it will be caught when testing for 63 # the existence of pyvcloud (see module_utils/vca.py). This just 64 # protects against generating an exception at runtime 65 pass 66 67from ansible.module_utils.basic import AnsibleModule 68from ansible.module_utils.vca import VcaError, vca_argument_spec, vca_login 69 70 71VALID_PROTO = ['Tcp', 'Udp', 'Icmp', 'Other', 'Any'] 72VALID_RULE_KEYS = ['policy', 'is_enable', 'enable_logging', 'description', 73 'dest_ip', 'dest_port', 'source_ip', 'source_port', 74 'protocol'] 75 76 77def protocol_to_tuple(protocol): 78 return (protocol.get_Tcp(), 79 protocol.get_Udp(), 80 protocol.get_Icmp(), 81 protocol.get_Other(), 82 protocol.get_Any()) 83 84 85def protocol_to_string(protocol): 86 protocol = protocol_to_tuple(protocol) 87 if protocol[0] is True: 88 return 'Tcp' 89 elif protocol[1] is True: 90 return 'Udp' 91 elif protocol[2] is True: 92 return 'Icmp' 93 elif protocol[3] is True: 94 return 'Other' 95 elif protocol[4] is True: 96 return 'Any' 97 98 99def protocol_to_type(protocol): 100 try: 101 protocols = ProtocolsType() 102 setattr(protocols, protocol, True) 103 return protocols 104 except AttributeError: 105 raise VcaError("The value in protocol is not valid") 106 107 108def validate_fw_rules(fw_rules): 109 for rule in fw_rules: 110 for k in rule.keys(): 111 if k not in VALID_RULE_KEYS: 112 raise VcaError("%s is not a valid key in fw rules, please " 113 "check above.." % k, valid_keys=VALID_RULE_KEYS) 114 115 rule['dest_port'] = str(rule.get('dest_port', 'Any')).lower() 116 rule['dest_ip'] = rule.get('dest_ip', 'Any').lower() 117 rule['source_port'] = str(rule.get('source_port', 'Any')).lower() 118 rule['source_ip'] = rule.get('source_ip', 'Any').lower() 119 rule['protocol'] = rule.get('protocol', 'Any').lower() 120 rule['policy'] = rule.get('policy', 'allow').lower() 121 rule['is_enable'] = rule.get('is_enable', True) 122 rule['enable_logging'] = rule.get('enable_logging', False) 123 rule['description'] = rule.get('description', 'rule added by Ansible') 124 125 return fw_rules 126 127 128def fw_rules_to_dict(rules): 129 fw_rules = list() 130 for rule in rules: 131 fw_rules.append( 132 dict( 133 dest_port=rule.get_DestinationPortRange().lower(), 134 dest_ip=rule.get_DestinationIp().lower().lower(), 135 source_port=rule.get_SourcePortRange().lower(), 136 source_ip=rule.get_SourceIp().lower(), 137 protocol=protocol_to_string(rule.get_Protocols()).lower(), 138 policy=rule.get_Policy().lower(), 139 is_enable=rule.get_IsEnabled(), 140 enable_logging=rule.get_EnableLogging(), 141 description=rule.get_Description() 142 ) 143 ) 144 return fw_rules 145 146 147def create_fw_rule(is_enable, description, policy, protocol, dest_port, 148 dest_ip, source_port, source_ip, enable_logging): 149 150 return FirewallRuleType(IsEnabled=is_enable, 151 Description=description, 152 Policy=policy, 153 Protocols=protocol_to_type(protocol), 154 DestinationPortRange=dest_port, 155 DestinationIp=dest_ip, 156 SourcePortRange=source_port, 157 SourceIp=source_ip, 158 EnableLogging=enable_logging) 159 160 161def main(): 162 argument_spec = vca_argument_spec() 163 argument_spec.update( 164 dict( 165 fw_rules=dict(required=True, type='list'), 166 gateway_name=dict(default='gateway'), 167 state=dict(default='present', choices=['present', 'absent']) 168 ) 169 ) 170 171 module = AnsibleModule(argument_spec, supports_check_mode=True) 172 173 fw_rules = module.params.get('fw_rules') 174 gateway_name = module.params.get('gateway_name') 175 vdc_name = module.params['vdc_name'] 176 177 vca = vca_login(module) 178 179 gateway = vca.get_gateway(vdc_name, gateway_name) 180 if not gateway: 181 module.fail_json(msg="Not able to find the gateway %s, please check " 182 "the gateway_name param" % gateway_name) 183 184 fwservice = gateway._getFirewallService() 185 186 rules = gateway.get_fw_rules() 187 current_rules = fw_rules_to_dict(rules) 188 189 try: 190 desired_rules = validate_fw_rules(fw_rules) 191 except VcaError as e: 192 module.fail_json(msg=e.message) 193 194 result = dict(changed=False) 195 result['current_rules'] = current_rules 196 result['desired_rules'] = desired_rules 197 198 updates = list() 199 additions = list() 200 deletions = list() 201 202 for (index, rule) in enumerate(desired_rules): 203 try: 204 if rule != current_rules[index]: 205 updates.append((index, rule)) 206 except IndexError: 207 additions.append(rule) 208 209 eol = len(current_rules) - len(desired_rules) 210 if eol > 0: 211 for rule in current_rules[eol:]: 212 deletions.append(rule) 213 214 for rule in additions: 215 if not module.check_mode: 216 rule['protocol'] = rule['protocol'].capitalize() 217 gateway.add_fw_rule(**rule) 218 result['changed'] = True 219 220 for index, rule in updates: 221 if not module.check_mode: 222 rule = create_fw_rule(**rule) 223 fwservice.replace_FirewallRule_at(index, rule) 224 result['changed'] = True 225 226 keys = ['protocol', 'dest_port', 'dest_ip', 'source_port', 'source_ip'] 227 for rule in deletions: 228 if not module.check_mode: 229 kwargs = dict([(k, v) for k, v in rule.items() if k in keys]) 230 kwargs['protocol'] = protocol_to_string(kwargs['protocol']) 231 gateway.delete_fw_rule(**kwargs) 232 result['changed'] = True 233 234 if not module.check_mode and result['changed'] is True: 235 task = gateway.save_services_configuration() 236 if task: 237 vca.block_until_completed(task) 238 239 result['rules_updated'] = len(updates) 240 result['rules_added'] = len(additions) 241 result['rules_deleted'] = len(deletions) 242 243 return module.exit_json(**result) 244 245 246if __name__ == '__main__': 247 main() 248