def test_01_setup(self, dev, state_map): state = state_map.setdefault(dev) state.err = True state.fail_func = pytest.skip state.parent = dev state.tmpl = None state.name = None state.obj = None state.targets = [testlib.random_name() for x in range(2)] if self.FUNC is None: pytest.skip('{0}.FUNC must be defined'.format( self.__class__.__name__)) elif self.CLASS is None: pytest.skip('{0}.CLASS must be defined'.format( self.__class__.__name__)) elif self.PARAM is None: pytest.skip('{0}.PARAM must be defined'.format( self.__class__.__name__)) if isinstance(state.parent, Panorama): tmpl = Template(testlib.random_name()) state.parent.add(tmpl) v = Vsys('vsys2') tmpl.add(v) state.parent = v tmpl.create() state.tmpl = tmpl else: vsys_list = [ x.name for x in Vsys.refreshall(dev, add=False, name_only=True) ] if 'vsys2' not in vsys_list: pytest.skip('Firewall needs vsys2 to exist') cls_args = {} eth_args = {'mode': 'layer3'} if self.CLASS == Vlan: eth_args['mode'] = 'layer2' elif self.CLASS == Zone: cls_args['mode'] = 'layer3' state.name = testlib.get_available_interfaces(state.parent)[0] state.obj = EthernetInterface(state.name, **eth_args) state.parent.add(state.obj) if state.tmpl is None: dev.vsys = 'vsys2' instances = [ self.CLASS(state.targets[x], **cls_args) for x in range(2) ] for x in instances: state.parent.add(x) x.create() state.err = False
def populate_facts(self): # Get session usage XML session_root = self.parent.op('show session meter') # Loop through all VSYS virtual_systems = [] vsys_list = Vsys.refreshall(self.parent, name_only=True) for vsys in vsys_list: for var in ('display_name', 'interface', 'virtual_routers'): vsys.refresh_variable(var) zones = [x.name for x in Zone.refreshall(vsys, name_only=True)] vsys_id = vsys.name[4:] vsys_sessions = session_root.find(".//entry/[vsys='" + vsys_id + "']") vsys_currentsessions = vsys_sessions.find('.//current').text vsys_maxsessions = vsys_sessions.find('.//maximum').text virtual_systems.append({ 'vsys_id': vsys_id, 'vsys_name': vsys.name, 'vsys_description': vsys.display_name, 'vsys_iflist': vsys.interface, 'vsys_vrlist': vsys.virtual_routers, 'vsys_zonelist': zones, 'vsys_maxsessions': vsys_maxsessions, 'vsys_currentsessions': vsys_currentsessions, }) self.facts.update({ 'virtual-systems': virtual_systems })
def test_01_setup(self, dev, state_map): state = state_map.setdefault(dev) state.err = True state.fail_func = pytest.skip state.parent = dev state.name = None state.delete_parent = False state.obj = None if self.CLASS is None: pytest.skip('{0}.CLASS must be defined'.format( self.__class__.__name__)) elif self.VSYS_PARAM is None: pytest.skip('{0}.VSYS_PARAM must be defined'.format( self.__class__.__name__)) if isinstance(state.parent, Panorama): tmpl = Template(testlib.random_name()) state.parent.add(tmpl) state.parent = tmpl state.parent.add(Vsys('vsys1')) state.parent.add(Vsys('vsys2')) state.parent.add(Vsys('vsys3')) state.parent.create() state.delete_parent = True else: vsys_list = [ x.name for x in Vsys.refreshall(dev, add=False, name_only=True) ] if not all('vsys{0}'.format(x) in vsys_list for x in range(1, 4)): pytest.skip('Firewall needs vsys1 - vsys3 to exist') args = {} if self.CLASS == EthernetInterface: state.name = testlib.get_available_interfaces(state.parent)[0] args = {'mode': 'layer3'} else: state.name = testlib.random_name() state.obj = self.CLASS(state.name, **args) state.parent.add(state.obj) state.err = False
def test_01_setup(self, dev, state_map): state = state_map.setdefault(dev) state.err = True state.fail_func = pytest.skip state.parent = dev state.tmpl = None state.name = None state.obj = None state.targets = [testlib.random_name() for x in range(2)] if self.FUNC is None: pytest.skip('{0}.FUNC must be defined'.format( self.__class__.__name__)) elif self.CLASS is None: pytest.skip('{0}.CLASS must be defined'.format( self.__class__.__name__)) elif self.PARAM is None: pytest.skip('{0}.PARAM must be defined'.format( self.__class__.__name__)) if isinstance(state.parent, Panorama): tmpl = Template(testlib.random_name()) state.parent.add(tmpl) v = Vsys('vsys2') tmpl.add(v) state.parent = v tmpl.create() state.tmpl = tmpl else: vsys_list = [x.name for x in Vsys.refreshall(dev, add=False, name_only=True)] if 'vsys2' not in vsys_list: pytest.skip('Firewall needs vsys2 to exist') cls_args = {} eth_args = {'mode': 'layer3'} if self.CLASS == Vlan: eth_args['mode'] = 'layer2' elif self.CLASS == Zone: cls_args['mode'] = 'layer3' state.name = testlib.get_available_interfaces(state.parent)[0] state.obj = EthernetInterface(state.name, **eth_args) state.parent.add(state.obj) if state.tmpl is None: dev.vsys = 'vsys2' instances = [self.CLASS(state.targets[x], **cls_args) for x in range(2)] for x in instances: state.parent.add(x) x.create() state.err = False
def sanity(self, dev, state_map, fw_test=False): state = state_map.setdefault(dev) if state.err: state.fail_func('prereq failed') if fw_test: if not isinstance(dev, Firewall): pytest.skip('Skipping firewall-only test') dev.removeall() dev.add(state.obj) vsys_list = Vsys.refreshall(dev, name_only=True) for v in vsys_list: v.refresh_variable(self.VSYS_PARAM) return state
def assert_imported_into(self, vsys, state): found = False vsys_list = Vsys.refreshall(state.parent, add=False, name_only=True) for v in vsys_list: v.refresh_variable(self.VSYS_PARAM) if getattr(v, self.VSYS_PARAM) is None: setattr(v, self.VSYS_PARAM, []) if vsys == v.name: found = True assert state.name in getattr(v, self.VSYS_PARAM) else: assert state.name not in getattr(v, self.VSYS_PARAM) if vsys is not None: assert found
def test_01_setup(self, dev, state_map): state = state_map.setdefault(dev) state.err = True state.fail_func = pytest.skip state.parent = dev state.name = None state.delete_parent = False state.obj = None if self.CLASS is None: pytest.skip('{0}.CLASS must be defined'.format( self.__class__.__name__)) elif self.VSYS_PARAM is None: pytest.skip('{0}.VSYS_PARAM must be defined'.format( self.__class__.__name__)) if isinstance(state.parent, Panorama): tmpl = Template(testlib.random_name()) state.parent.add(tmpl) state.parent = tmpl state.parent.add(Vsys('vsys1')) state.parent.add(Vsys('vsys2')) state.parent.add(Vsys('vsys3')) state.parent.create() state.delete_parent = True else: vsys_list = [x.name for x in Vsys.refreshall(dev, add=False, name_only=True)] if not all('vsys{0}'.format(x) in vsys_list for x in range(1, 4)): pytest.skip('Firewall needs vsys1 - vsys3 to exist') args = {} if self.CLASS == EthernetInterface: state.name = testlib.get_available_interfaces(state.parent)[0] args = {'mode': 'layer3'} else: state.name = testlib.random_name() state.obj = self.CLASS(state.name, **args) state.parent.add(state.obj) state.err = False
def get_pandevice_parent(self, module, timeout=0): """Builds the pandevice object tree, returning the parent object. If pandevice is not installed, then module.fail_json() will be invoked. Arguments: * module(AnsibleModule): the ansible module. * timeout(int): Number of seconds to retry opening the connection to PAN-OS. Returns: * The parent pandevice object based on the spec given to get_connection(). """ # Sanity check. if not HAS_PANDEVICE: module.fail_json(msg='Missing required library "pandevice".') # Verify pandevice minimum version. if self.min_pandevice_version is not None: pdv = tuple(int(x) for x in pandevice.__version__.split('.')) if pdv < self.min_pandevice_version: module.fail_json(msg=_MIN_VERSION_ERROR.format( 'pandevice', pandevice.__version__, _vstr(self.min_pandevice_version))) pan_device_auth, serial_number = None, None if module.params['provider'] and module.params['provider'][ 'ip_address']: pan_device_auth = ( module.params['provider']['ip_address'], module.params['provider']['username'], module.params['provider']['password'], module.params['provider']['api_key'], module.params['provider']['port'], ) serial_number = module.params['provider']['serial_number'] elif module.params.get('ip_address', None) is not None: pan_device_auth = ( module.params['ip_address'], module.params['username'], module.params['password'], module.params['api_key'], module.params['port'], ) msg = 'Classic provider params are deprecated; use "provider" instead' module.deprecate(msg, '2.12') else: module.fail_json(msg='Provider params are required.') # Create the connection object. if not isinstance(timeout, int): raise ValueError('Timeout must be an int') elif timeout < 0: raise ValueError('Timeout must greater than or equal to 0') end_time = time.time() + timeout while True: try: self.device = PanDevice.create_from_device(*pan_device_auth) except PanDeviceError as e: if timeout == 0: module.fail_json(msg='Failed connection: {0}'.format(e)) elif time.time() >= end_time: module.fail_json(msg='Connection timeout: {0}'.format(e)) else: break # Verify PAN-OS minimum version. if self.min_panos_version is not None: if self.device._version_info < self.min_panos_version: module.fail_json(msg=_MIN_VERSION_ERROR.format( 'PAN-OS', _vstr(self.device._version_info), _vstr(self.min_panos_version))) # Optional: Firewall via Panorama connectivity specified. if hasattr(self.device, 'refresh_devices') and serial_number: fw = Firewall(serial=serial_number) self.device.add(fw) self.device = fw parent = self.device no_shared = 'Scope "shared" is not allowed' not_found = '{0} "{1}" is not present.' pano_mia_param = 'Param "{0}" is required for Panorama but not specified.' ts_error = 'Specify either the template or the template stack{0}.' if hasattr(self.device, 'refresh_devices'): # Panorama connection. templated = False # Error if Panorama is not supported. if self.panorama_error is not None: module.fail_json(msg=self.panorama_error) # Spec: template stack. tmpl_required = False added_template = False if self.template_stack is not None: name = module.params[self.template_stack] if name is not None: templated = True stacks = TemplateStack.refreshall(parent, name_only=True) for ts in stacks: if ts.name == name: parent = ts added_template = True break else: module.fail_json(msg=not_found.format( 'Template stack', name, )) elif self.template is not None: tmpl_required = True else: module.fail_json( msg=pano_mia_param.format(self.template_stack)) # Spec: template. if self.template is not None: name = module.params[self.template] if name is not None: templated = True if added_template: module.fail_json(msg=ts_error.format(', not both')) templates = Template.refreshall(parent, name_only=True) for t in templates: if t.name == name: parent = t break else: module.fail_json(msg=not_found.format( 'Template', name, )) elif tmpl_required: module.fail_json(msg=ts_error.format('')) elif not added_template: module.fail_json(msg=pano_mia_param.format(self.template)) # Spec: vsys_dg or device_group. dg_name = self.vsys_dg or self.device_group if dg_name is not None: name = module.params[dg_name] if name not in (None, 'shared'): groups = DeviceGroup.refreshall(parent, name_only=True) for dg in groups: if dg.name == name: parent = dg break else: module.fail_json(msg=not_found.format( 'Device group', name, )) elif self.error_on_shared: module.fail_json(msg=no_shared) # Spec: vsys importable. vsys_name = self.vsys_importable or self.vsys or self.vsys_shared if dg_name is None and templated and vsys_name is not None: name = module.params[vsys_name] if name not in (None, 'shared'): vo = Vsys(name) parent.add(vo) parent = vo # Spec: rulebase. if self.rulebase is not None: if module.params[self.rulebase] in (None, 'pre-rulebase'): rb = PreRulebase() parent.add(rb) parent = rb elif module.params[self.rulebase] == 'rulebase': rb = Rulebase() parent.add(rb) parent = rb elif module.params[self.rulebase] == 'post-rulebase': rb = PostRulebase() parent.add(rb) parent = rb else: module.fail_json(msg=not_found.format( 'Rulebase', module.params[self.rulebase])) else: # Firewall connection. # Error if firewalls are not supported. if self.firewall_error is not None: module.fail_json(msg=self.firewall_error) # Spec: vsys or vsys_dg or vsys_importable. vsys_name = self.vsys_dg or self.vsys or self.vsys_importable or self.vsys_shared if vsys_name is not None: parent.vsys = module.params[vsys_name] if parent.vsys == 'shared' and self.error_on_shared: module.fail_json(msg=no_shared) # Spec: rulebase. if self.rulebase is not None: rb = Rulebase() parent.add(rb) parent = rb # Done. return parent
def main(): argument_spec = dict( ip_address=dict(required=True), password=dict(no_log=True), username=dict(default='admin'), api_key=dict(no_log=True), operation=dict(default='add', choices=['add', 'update', 'delete']), state=dict(choices=['present', 'absent']), if_name=dict(required=True), ip=dict(type='list'), ipv6_enabled=dict(), management_profile=dict(), mtu=dict(), netflow_profile=dict(), comment=dict(), zone_name=dict(required=True), vr_name=dict(default='default'), vsys_dg=dict(default='vsys1'), commit=dict(type='bool', default=True), ) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, required_one_of=[['api_key', 'password']]) if not HAS_LIB: module.fail_json(msg='Missing required libraries.') # Get the firewall / panorama auth. auth = [ module.params[x] for x in ('ip_address', 'username', 'password', 'api_key') ] # Get the object params. spec = { 'name': module.params['if_name'], 'ip': module.params['ip'], 'ipv6_enabled': module.params['ipv6_enabled'], 'management_profile': module.params['management_profile'], 'mtu': module.params['mtu'], 'netflow_profile': module.params['netflow_profile'], 'comment': module.params['comment'], } # Get other info. operation = module.params['operation'] state = module.params['state'] zone_name = module.params['zone_name'] vr_name = module.params['vr_name'] vsys_dg = module.params['vsys_dg'] commit = module.params['commit'] if_name = module.params['if_name'] # Open the connection to the PANOS device. con = PanDevice.create_from_device(*auth) # Set vsys if firewall, device group if panorama. if hasattr(con, 'refresh_devices'): # Panorama # Normally we want to set the device group here, but there are no # interfaces on Panorama. So if we're given a Panorama device, then # error out. ''' groups = panorama.DeviceGroup.refreshall(con, add=False) for parent in groups: if parent.name == vsys_dg: con.add(parent) break else: module.fail_json(msg="'{0}' device group is not present".format(vsys_dg)) ''' module.fail_json(msg="Ethernet interfaces don't exist on Panorama") else: # Firewall # Normally we should set the vsys here, but since interfaces are # vsys importables, we'll use organize_into_vsys() to help find and # cleanup when the interface is imported into an undesired vsys. # con.vsys = vsys_dg pass # Retrieve the current config. try: interfaces = TunnelInterface.refreshall(con, add=False, name_only=True) zones = Zone.refreshall(con) routers = VirtualRouter.refreshall(con) vsys_list = Vsys.refreshall(con) except PanDeviceError: e = get_exception() module.fail_json(msg=e.message) # Build the object based on the user spec. tun = TunnelInterface(**spec) con.add(tun) # Which action should we take on the interface? changed = False if state == 'present': if tun.name in [x.name for x in interfaces]: i = TunnelInterface(tun.name) con.add(i) try: i.refresh() except PanDeviceError as e: module.fail_json(msg='Failed "present" refresh: {0}'.format(e)) if not i.equal(tun, compare_children=False): tun.extend(i.children) try: tun.apply() changed = True except PanDeviceError as e: module.fail_json( msg='Failed "present" apply: {0}'.format(e)) else: try: tun.create() changed = True except PanDeviceError as e: module.fail_json(msg='Failed "present" create: {0}'.format(e)) try: changed |= set_zone(con, tun, zone_name, zones) changed |= set_virtual_router(con, tun, vr_name, routers) except PanDeviceError as e: module.fail_json(msg='Failed zone/vr assignment: {0}'.format(e)) elif state == 'absent': try: changed |= set_zone(con, tun, None, zones) changed |= set_virtual_router(con, tun, None, routers) except PanDeviceError as e: module.fail_json( msg='Failed "absent" zone/vr cleanup: {0}'.format(e)) changed = True if tun.name in [x.name for x in interfaces]: try: tun.delete() changed = True except PanDeviceError as e: module.fail_json(msg='Failed "absent" delete: {0}'.format(e)) elif operation == 'delete': if tun.name not in [x.name for x in interfaces]: module.fail_json( msg='Interface {0} does not exist, and thus cannot be deleted'. format(tun.name)) try: con.organize_into_vsys() set_zone(con, tun, None, zones) set_virtual_router(con, tun, None, routers) tun.delete() changed = True except (PanDeviceError, ValueError): e = get_exception() module.fail_json(msg=e.message) elif operation == 'add': if tun.name in [x.name for x in interfaces]: module.fail_json( msg='Interface {0} is already present; use operation "update"'. format(tun.name)) con.vsys = vsys_dg # Create the interface. try: tun.create() set_zone(con, tun, zone_name, zones) set_virtual_router(con, tun, vr_name, routers) changed = True except (PanDeviceError, ValueError): e = get_exception() module.fail_json(msg=e.message) elif operation == 'update': if tun.name not in [x.name for x in interfaces]: module.fail_json( msg= 'Interface {0} is not present; use operation "add" to create it' .format(tun.name)) # If the interface is in the wrong vsys, remove it from the old vsys. try: con.organize_into_vsys() except PanDeviceError: e = get_exception() module.fail_json(msg=e.message) if tun.vsys != vsys_dg: try: tun.delete_import() except PanDeviceError: e = get_exception() module.fail_json(msg=e.message) # Move the ethernet object to the correct vsys. for vsys in vsys_list: if vsys.name == vsys_dg: vsys.add(tun) break else: module.fail_json(msg='Vsys {0} does not exist'.format(vsys)) # Update the interface. try: tun.apply() set_zone(con, tun, zone_name, zones) set_virtual_router(con, tun, vr_name, routers) changed = True except (PanDeviceError, ValueError): e = get_exception() module.fail_json(msg=e.message) else: module.fail_json(msg="Unsupported operation '{0}'".format(operation)) # Commit if we were asked to do so. if changed and commit: try: con.commit(sync=True) except PanDeviceError: e = get_exception() module.fail_json(msg='Performed {0} but commit failed: {1}'.format( operation, e.message)) # Done! module.exit_json(changed=changed, msg='okey dokey')
def main(): argument_spec = dict( ip_address=dict(required=True), username=dict(default='admin'), password=dict(no_log=True), api_key=dict(no_log=True), rule_name=dict(required=True), source_zone=dict(type='list', default=['any']), source_ip=dict(type='list', default=["any"]), source_user=dict(type='list', default=['any']), hip_profiles=dict(type='list', default=['any']), destination_zone=dict(type='list', default=['any']), destination_ip=dict(type='list', default=["any"]), application=dict(type='list', default=['any']), service=dict(type='list', default=['application-default']), category=dict(type='list', default=['any']), action=dict(default='allow', choices=[ 'allow', 'deny', 'drop', 'reset-client', 'reset-server', 'reset-both' ]), log_setting=dict(), log_start=dict(type='bool', default=False), log_end=dict(type='bool', default=True), description=dict(default=''), rule_type=dict(default='universal', choices=['universal', 'intrazone', 'interzone']), tag_name=dict(type='list'), negate_source=dict(type='bool', default=False), negate_destination=dict(type='bool', default=False), disabled=dict(type='bool', default=False), schedule=dict(), icmp_unreachable=dict(type='bool'), disable_server_response_inspection=dict(type='bool', default=False), group_profile=dict(), antivirus=dict(), spyware=dict(), vulnerability=dict(), url_filtering=dict(), file_blocking=dict(), wildfire_analysis=dict(), data_filtering=dict(), target=dict(type='list'), negate_target=dict(type='bool', default=False), location=dict(choices=['top', 'bottom', 'before', 'after']), existing_rule=dict(), devicegroup=dict(), rulebase=dict(default='pre-rulebase', choices=['pre-rulebase', 'post-rulebase']), vsys=dict(default='vsys1'), state=dict(choices=['present', 'absent']), operation=dict(default='add', choices=['add', 'update', 'delete', 'find']), commit=dict(type='bool', default=True)) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, required_one_of=[['api_key', 'password']]) if not HAS_LIB: module.fail_json(msg='Missing required libraries.') elif not hasattr(SecurityRule, 'move'): module.fail_json(msg='Python library pandevice needs to be updated.') # Get the firewall / panorama auth. auth = ( module.params['ip_address'], module.params['username'], module.params['password'], module.params['api_key'], ) # Set the SecurityRule object params rule_spec = { 'name': module.params['rule_name'], 'fromzone': module.params['source_zone'], 'tozone': module.params['destination_zone'], 'source': module.params['source_ip'], 'source_user': module.params['source_user'], 'hip_profiles': module.params['hip_profiles'], 'destination': module.params['destination_ip'], 'application': module.params['application'], 'service': module.params['service'], 'category': module.params['category'], 'action': module.params['action'], 'log_setting': module.params['log_setting'], 'log_start': module.params['log_start'], 'log_end': module.params['log_end'], 'description': module.params['description'], 'type': module.params['rule_type'], 'tag': module.params['tag_name'], 'negate_source': module.params['negate_source'], 'negate_destination': module.params['negate_destination'], 'disabled': module.params['disabled'], 'schedule': module.params['schedule'], 'icmp_unreachable': module.params['icmp_unreachable'], 'disable_server_response_inspection': module.params['disable_server_response_inspection'], 'group': module.params['group_profile'], 'virus': module.params['antivirus'], 'spyware': module.params['spyware'], 'vulnerability': module.params['vulnerability'], 'url_filtering': module.params['url_filtering'], 'file_blocking': module.params['file_blocking'], 'wildfire_analysis': module.params['wildfire_analysis'], 'data_filtering': module.params['data_filtering'], } # Get other info location = module.params['location'] existing_rule = module.params['existing_rule'] devicegroup = module.params['devicegroup'] rulebase = module.params['rulebase'] vsys = module.params['vsys'] state = module.params['state'] operation = module.params['operation'] commit = module.params['commit'] # Sanity check the location / existing_rule params. if location in ('before', 'after') and not existing_rule: module.fail_json( msg= "'existing_rule' must be specified if location is 'before' or 'after'." ) # Open the connection to the PAN-OS device device = None try: device = PanDevice.create_from_device(*auth) except PanDeviceError: e = get_exception() module.fail_json(msg=e.message) # Add some additional rule params if device is Panorama if isinstance(device, Panorama): rule_spec['target'] = module.params['target'] rule_spec['negate_target'] = module.params['negate_target'] # Set the attachment point for the RuleBase object parent = device if isinstance(parent, Firewall): if vsys is not None: vsys_list = Vsys.refreshall(parent) parent = get_vsys(vsys, vsys_list) if parent is None: module.fail_json(msg='VSYS not found: {0}'.format(vsys)) parent = parent.add(Rulebase()) elif isinstance(parent, Panorama): if devicegroup == 'shared': devicegroup = None if devicegroup is not None: parent = parent.add(Rulebase()) else: parent = get_devicegroup(parent, devicegroup) if parent is None: module.fail_json( msg='Device group not found: {0}'.format(devicegroup)) if rulebase == 'pre-rulebase': parent = parent.add(PreRulebase()) elif rulebase == 'post-rulebase': parent = parent.add(PostRulebase()) # Now that we have the rulebase let's grab its security rules rules = SecurityRule.refreshall(parent) # Create new rule object from the params and add to rulebase new_rule = SecurityRule(**rule_spec) parent.add(new_rule) # Which action shall we take on the rule object? changed = False if state == 'present': match = find_rule(rules, new_rule) if match: # Change an existing rule if not match.equal(new_rule): try: if not module.check_mode: new_rule.apply() except PanDeviceError as e: module.fail_json( msg='Failed "present" apply: {0}'.format(e)) else: changed = True else: # Add a new rule try: if not module.check_mode: new_rule.create() except PanDeviceError as e: module.fail_json(msg='Failed "present" apply: {0}'.format(e)) else: changed = True # Move the rule if location is defined if location: try: if not module.check_mode: new_rule.move(location, existing_rule) except PanDeviceError as e: if '{0}'.format(e) not in ACCEPTABLE_MOVE_ERRORS: module.fail_json(msg='Failed move: {0}'.format(e)) else: changed = True elif state == 'absent': match = find_rule(rules, new_rule) if match: # Delete an existing rule try: if not module.check_mode: new_rule.delete() except PanDeviceError as e: module.fail_json(msg='Failed "absent" delete: {0}'.format(e)) else: changed = True elif operation == "find": # Search for the rule match = find_rule(rules, new_rule) # If found, format and return the result if match: module.exit_json(stdout_lines=match.about(), msg='Rule matched') else: module.fail_json( msg='Rule \'%s\' not found. Is the name correct?' % new_rule.name) elif operation == "delete": # Search for the object match = find_rule(rules, new_rule) if match is None: module.fail_json( msg='Rule \'%s\' not found. Is the name correct?' % new_rule.name) try: if not module.check_mode: new_rule.delete() except PanDeviceError as e: module.fail_json(msg='Failed "delete" delete: {0}'.format(e)) else: changed = True elif operation == "add": # Search for the rule. Fail if found. match = find_rule(rules, new_rule) if match: module.fail_json( msg= 'Rule \'%s\' already exists. Use operation: \'update\' to change it.' % new_rule.name) try: if not module.check_mode: new_rule.create() except PanDeviceError as e: module.fail_json(msg='Failed "add" create: {0}'.format(e)) else: changed = True if location: try: if not module.check_mode: new_rule.move(location, existing_rule) except PanDeviceError as e: if '{0}'.format(e) not in ACCEPTABLE_MOVE_ERRORS: module.fail_json(msg='Failed move: {0}'.format(e)) elif operation == 'update': # Search for the rule. Update if found. match = find_rule(rulebase, new_rule.name) if not match: module.fail_json( msg= 'Rule \'%s\' does not exist. Use operation: \'add\' to add it.' % new_rule.name) try: if not module.check_mode: new_rule.apply() except PanDeviceError as e: module.fail_json(msg='Failed "update" apply: {0}'.format(e)) else: changed = True if location: try: if not module.check_mode: new_rule.move(location, existing_rule) except PanDeviceError as e: if '{0}'.format(e) not in ACCEPTABLE_MOVE_ERRORS: module.fail_json(msg='Failed move: {0}'.format(e)) # Optional commit. # FIXME: Commits should be done using the separate commit module if changed and commit: try: device.commit(sync=True) except PanDeviceError as e: module.fail_json(msg='Failed commit: {0}'.format(e)) module.exit_json(changed=changed, msg='Done')
def main(): argument_spec = dict(ip_address=dict(required=True), password=dict(no_log=True), username=dict(default='admin'), api_key=dict(no_log=True), zone=dict(required=True), mode=dict(choices=[ 'tap', 'virtual-wire', 'layer2', 'layer3', 'external' ], default='layer3'), interface=dict(type='list'), zone_profile=dict(), log_setting=dict(), enable_userid=dict(type='bool', default=False), include_acl=dict(type='list'), exclude_acl=dict(type='list'), vsys=dict(default='vsys1'), template=dict(), state=dict(choices=['present', 'absent'], default='present')) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, required_one_of=[['api_key', 'password']]) if not HAS_LIB: module.fail_json(msg='Missing required libraries.') # Get the firewall / panorama auth. auth = ( module.params['ip_address'], module.params['username'], module.params['password'], module.params['api_key'], ) # Set the Zone object params zone_spec = { 'name': module.params['zone'], 'mode': module.params['mode'], 'interface': module.params['interface'], 'zone_profile': module.params['zone_profile'], 'log_setting': module.params['log_setting'], 'enable_user_identification': module.params['enable_userid'], 'include_acl': module.params['include_acl'], 'exclude_acl': module.params['exclude_acl'] } # Get other info vsys = module.params['vsys'] template = module.params['template'] state = module.params['state'] # Open the connection to the PAN-OS device device = None try: device = PanDevice.create_from_device(*auth) except PanDeviceError: e = get_exception() module.fail_json(msg=e.message) # Set the attachment point for the Zone object parent = None if isinstance(device, Firewall): parent = device elif isinstance(device, Panorama): if template is not None: template_list = Template.refreshall(device) parent = get_template(template, template_list) if parent is None: module.fail_json( msg='Template not found: {0}'.format(template)) else: module.fail_json( msg= 'A template parameter is required when device type is Panorama' ) if vsys is not None: v = Vsys(vsys) parent.add(v) parent = v # Retrieve the current list of zones try: zones = Zone.refreshall(parent) except PanDeviceError: e = get_exception() module.fail_json(msg=e.message) # Build the zone and attach to the parent new_zone = Zone(**zone_spec) parent.add(new_zone) # Which action shall we take on the Zone object? changed = False if state == 'present': match = find_zone(zones, new_zone) if match: # Change an existing zone if not match.equal(new_zone): try: if not module.check_mode: new_zone.create() except PanDeviceError as e: module.fail_json( msg='Failed "present" create: {0}'.format(e)) else: changed = True else: # Add a new zone try: if not module.check_mode: new_zone.apply() except PanDeviceError as e: module.fail_json(msg='Failed "present" apply: {0}'.format(e)) else: changed = True elif state == 'absent': match = find_zone(zones, new_zone) if match: # Delete an existing zone try: if not module.check_mode: new_zone.delete() except PanDeviceError as e: module.fail_json(msg='Failed "absent" delete: {0}'.format(e)) else: changed = True # Done! module.exit_json(changed=changed, msg='Done')
def get_pandevice_parent(self, module): """Builds the pandevice object tree, returning the parent object. If pandevice is not installed, then module.fail_json() will be invoked. Arguments: * module(AnsibleModule): the ansible module. Returns: * The parent pandevice object based on the spec given to get_connection(). """ # Sanity check. if not HAS_PANDEVICE: module.fail_json(msg='Missing required library "pandevice".') d, host_arg = None, None if module.params['provider'] and module.params['provider']['host']: d = module.params['provider'] host_arg = 'host' elif module.params['ip_address'] is not None: d = module.params host_arg = 'ip_address' else: module.fail_json(msg='New or classic provider params are required.') # Create the connection object. try: self.device = PanDevice.create_from_device( d[host_arg], d['username'], d['password'], d['api_key']) except PanDeviceError as e: module.fail_json(msg='Failed connection: {0}'.format(e)) parent = self.device not_found = '{0} "{1}" is not present.' if hasattr(self.device, 'refresh_devices'): # Panorama connection. # Error if Panorama is not supported. if self.panorama_error is not None: module.fail_json(msg=self.panorama_error) # Spec: template stack. if self.template_stack is not None: name = module.params[self.template_stack] stacks = TemplateStack.refreshall(parent) for ts in stacks: if ts.name == name: parent = ts break else: module.fail_json(msg=not_found.format( 'Template stack', name, )) # Spec: template. if self.template is not None: name = module.params[self.template] templates = Template.refreshall(parent) for t in templates: if t.name == name: parent = t break else: module.fail_json(msg=not_found.format( 'Template', name, )) # Spec: vsys importable. if self.vsys_importable is not None: name = module.params[self.vsys_importable] if name is not None: vo = Vsys(name) parent.add(vo) parent = vo # Spec: vsys_dg or device_group. dg_name = self.vsys_dg or self.device_group if dg_name is not None: name = module.params[dg_name] if name not in (None, 'shared'): groups = DeviceGroup.refreshall(parent) for dg in groups: if dg.name == name: parent = dg break else: module.fail_json(msg=not_found.format( 'Device group', name, )) # Spec: rulebase. if self.rulebase is not None: if module.params[self.rulebase] in (None, 'pre-rulebase'): rb = PreRulebase() parent.add(rb) parent = rb elif module.params[self.rulebase] == 'post-rulebase': rb = PostRulebase() parent.add(rb) parent = rb else: module.fail_json(msg=not_found.format( 'Rulebase', module.params[self.rulebase])) else: # Firewall connection. # Error if firewalls are not supported. if self.firewall_error is not None: module.fail_json(msg=self.firewall_error) # Spec: vsys or vsys_dg or vsys_importable. vsys_name = self.vsys_dg or self.vsys or self.vsys_importable if vsys_name is not None: self.con.vsys = module.params[vsys_name] # Spec: rulebase. if self.rulebase is not None: rb = Rulebase() parent.add(rb) parent = rb # Done. return parent
def get_pandevice_parent(self, module): """Builds the pandevice object tree, returning the parent object. If pandevice is not installed, then module.fail_json() will be invoked. Arguments: * module(AnsibleModule): the ansible module. Returns: * The parent pandevice object based on the spec given to get_connection(). """ # Sanity check. if not HAS_PANDEVICE: module.fail_json(msg='Missing required library "pandevice".') # Verify pandevice minimum version. if self.min_pandevice_version is not None: pdv = tuple(int(x) for x in pandevice.__version__.split('.')) if pdv < self.min_pandevice_version: module.fail_json(msg=_MIN_VERSION_ERROR.format( 'pandevice', pandevice.__version__, _vstr(self.min_pandevice_version))) d, host_arg = None, None if module.params['provider'] and module.params['provider']['host']: d = module.params['provider'] host_arg = 'host' elif module.params['ip_address'] is not None: d = module.params host_arg = 'ip_address' else: module.fail_json( msg='New or classic provider params are required.') # Create the connection object. try: self.device = PanDevice.create_from_device(d[host_arg], d['username'], d['password'], d['api_key'], d['port']) except PanDeviceError as e: module.fail_json(msg='Failed connection: {0}'.format(e)) # Verify PAN-OS minimum version. if self.min_panos_version is not None: if self.device._version_info < self.min_panos_version: module.fail_json(msg=_MIN_VERSION_ERROR.format( 'PAN-OS', _vstr(self.device._version_info), _vstr(self.min_panos_version))) parent = self.device not_found = '{0} "{1}" is not present.' pano_mia_param = 'Param "{0}" is required for Panorama but not specified.' ts_error = 'Specify either the template or the template stack{0}.' if hasattr(self.device, 'refresh_devices'): # Panorama connection. # Error if Panorama is not supported. if self.panorama_error is not None: module.fail_json(msg=self.panorama_error) # Spec: template stack. tmpl_required = False added_template = False if self.template_stack is not None: name = module.params[self.template_stack] if name is not None: stacks = TemplateStack.refreshall(parent, name_only=True) for ts in stacks: if ts.name == name: parent = ts added_template = True break else: module.fail_json(msg=not_found.format( 'Template stack', name, )) elif self.template is not None: tmpl_required = True else: module.fail_json( msg=pano_mia_param.format(self.template_stack)) # Spec: template. if self.template is not None: name = module.params[self.template] if name is not None: if added_template: module.fail_json(msg=ts_error.format(', not both')) templates = Template.refreshall(parent, name_only=True) for t in templates: if t.name == name: parent = t break else: module.fail_json(msg=not_found.format( 'Template', name, )) elif tmpl_required: module.fail_json(msg=ts_error.format('')) else: module.fail_json(msg=pano_mia_param.format(self.template)) # Spec: vsys importable. vsys_name = self.vsys_importable or self.vsys if vsys_name is not None: name = module.params[vsys_name] if name not in (None, 'shared'): vo = Vsys(name) parent.add(vo) parent = vo # Spec: vsys_dg or device_group. dg_name = self.vsys_dg or self.device_group if dg_name is not None: name = module.params[dg_name] if name not in (None, 'shared'): groups = DeviceGroup.refreshall(parent, name_only=True) for dg in groups: if dg.name == name: parent = dg break else: module.fail_json(msg=not_found.format( 'Device group', name, )) # Spec: rulebase. if self.rulebase is not None: if module.params[self.rulebase] in (None, 'pre-rulebase'): rb = PreRulebase() parent.add(rb) parent = rb elif module.params[self.rulebase] == 'rulebase': rb = Rulebase() parent.add(rb) parent = rb elif module.params[self.rulebase] == 'post-rulebase': rb = PostRulebase() parent.add(rb) parent = rb else: module.fail_json(msg=not_found.format( 'Rulebase', module.params[self.rulebase])) else: # Firewall connection. # Error if firewalls are not supported. if self.firewall_error is not None: module.fail_json(msg=self.firewall_error) # Spec: vsys or vsys_dg or vsys_importable. vsys_name = self.vsys_dg or self.vsys or self.vsys_importable if vsys_name is not None: self.device.vsys = module.params[vsys_name] # Spec: rulebase. if self.rulebase is not None: rb = Rulebase() parent.add(rb) parent = rb # Done. return parent
def main(): argument_spec = dict( ip_address=dict(required=True), password=dict(no_log=True), username=dict(default='admin'), api_key=dict(no_log=True), operation=dict(default='add', choices=['add', 'update', 'delete']), state=dict(choices=['present', 'absent']), if_name=dict(required=True), mode=dict(default='layer3', choices=[ 'layer3', 'layer2', 'virtual-wire', 'tap', 'ha', 'decrypt-mirror', 'aggregate-group' ]), ip=dict(type='list'), ipv6_enabled=dict(), management_profile=dict(), mtu=dict(), adjust_tcp_mss=dict(), netflow_profile=dict(), lldp_enabled=dict(), lldp_profile=dict(), netflow_profile_l2=dict(), link_speed=dict(), link_duplex=dict(), link_state=dict(), aggregate_group=dict(), comment=dict(), ipv4_mss_adjust=dict(), ipv6_mss_adjust=dict(), enable_dhcp=dict(type='bool', default=True), create_default_route=dict(type='bool', default=False), create_dhcp_default_route=dict(type='bool', default=False), dhcp_default_route_metric=dict(), dhcp_default_route=dict(type='str', default="no"), zone_name=dict(required=True), vr_name=dict(default='default'), vsys_dg=dict(default='vsys1'), commit=dict(type='bool', default=True), ) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, required_one_of=[['api_key', 'password']]) if not HAS_LIB: module.fail_json(msg='Missing required libraries.') # Get the firewall / panorama auth. auth = [ module.params[x] for x in ('ip_address', 'username', 'password', 'api_key') ] # Get the object params. spec = { 'name': module.params['if_name'], 'mode': module.params['mode'], 'ip': module.params['ip'], 'ipv6_enabled': module.params['ipv6_enabled'], 'management_profile': module.params['management_profile'], 'mtu': module.params['mtu'], 'adjust_tcp_mss': module.params['adjust_tcp_mss'], 'netflow_profile': module.params['netflow_profile'], 'lldp_enabled': module.params['lldp_enabled'], 'lldp_profile': module.params['lldp_profile'], 'netflow_profile_l2': module.params['netflow_profile_l2'], 'link_speed': module.params['link_speed'], 'link_duplex': module.params['link_duplex'], 'link_state': module.params['link_state'], 'aggregate_group': module.params['aggregate_group'], 'comment': module.params['comment'], 'ipv4_mss_adjust': module.params['ipv4_mss_adjust'], 'ipv6_mss_adjust': module.params['ipv6_mss_adjust'], 'enable_dhcp': module.params['enable_dhcp'] or None, 'create_dhcp_default_route': module.params['create_default_route'] or None, 'dhcp_default_route_metric': module.params['dhcp_default_route_metric'], } # Get other info. enable_dhcp = module.params['enable_dhcp'] operation = module.params['operation'] state = module.params['state'] zone_name = module.params['zone_name'] vr_name = module.params['vr_name'] vsys_dg = module.params['vsys_dg'] commit = module.params['commit'] dhcp_default_route = module.params['dhcp_default_route'] management_profile = module.params['management_profile'] if_name = module.params['if_name'] dhcpe = ( '<entry name="%s"><layer3><dhcp-client><enable>yes</enable><create-default-route>%s</create-default-route>' '</dhcp-client><interface-management-profile>%s</interface-management-profile></layer3></entry>' % (if_name, dhcp_default_route, management_profile)) dhcpx = ( "/config/devices/entry[@name='localhost.localdomain']/network/interface/ethernet/entry[@name='%s']" % (if_name)) # Open the connection to the PANOS device. con = PanDevice.create_from_device(*auth) # Set vsys if firewall, device group if panorama. if hasattr(con, 'refresh_devices'): # Panorama # Normally we want to set the device group here, but there are no # interfaces on Panorama. So if we're given a Panorama device, then # error out. ''' groups = panorama.DeviceGroup.refreshall(con, add=False) for parent in groups: if parent.name == vsys_dg: con.add(parent) break else: module.fail_json(msg="'{0}' device group is not present".format(vsys_dg)) ''' module.fail_json(msg="Ethernet interfaces don't exist on Panorama") else: # Firewall # Normally we should set the vsys here, but since interfaces are # vsys importables, we'll use organize_into_vsys() to help find and # cleanup when the interface is imported into an undesired vsys. # con.vsys = vsys_dg pass # Retrieve the current config. try: interfaces = EthernetInterface.refreshall(con, add=False, name_only=True) zones = Zone.refreshall(con) routers = VirtualRouter.refreshall(con) vsys_list = Vsys.refreshall(con) except PanDeviceError: e = get_exception() module.fail_json(msg=e.message) # Build the object based on the user spec. eth = EthernetInterface(**spec) con.add(eth) # Which action should we take on the interface? changed = False if state == 'present': if eth.name in [x.name for x in interfaces]: i = EthernetInterface(eth.name) con.add(i) try: i.refresh() except PanDeviceError as e: module.fail_json(msg='Failed "present" refresh: {0}'.format(e)) if not i.equal(eth, compare_children=False): eth.extend(i.children) try: eth.apply() changed = True except PanDeviceError as e: module.fail_json( msg='Failed "present" apply: {0}'.format(e)) else: try: eth.create() changed = True except PanDeviceError as e: module.fail_json(msg='Failed "present" create: {0}'.format(e)) try: changed |= set_zone(con, eth, zone_name, zones) changed |= set_virtual_router(con, eth, vr_name, routers) if enable_dhcp is True: con.xapi.edit(xpath=dhcpx, element=dhcpe) except PanDeviceError as e: module.fail_json(msg='Failed zone/vr assignment: {0}'.format(e)) elif state == 'absent': try: changed |= set_zone(con, eth, None, zones) changed |= set_virtual_router(con, eth, None, routers) except PanDeviceError as e: module.fail_json( msg='Failed "absent" zone/vr cleanup: {0}'.format(e)) changed = True if eth.name in [x.name for x in interfaces]: try: eth.delete() changed = True except PanDeviceError as e: module.fail_json(msg='Failed "absent" delete: {0}'.format(e)) elif operation == 'delete': if eth.name not in [x.name for x in interfaces]: module.fail_json( msg='Interface {0} does not exist, and thus cannot be deleted'. format(eth.name)) try: con.organize_into_vsys() set_zone(con, eth, None, zones) set_virtual_router(con, eth, None, routers) eth.delete() changed = True except (PanDeviceError, ValueError): e = get_exception() module.fail_json(msg=e.message) elif operation == 'add': if eth.name in [x.name for x in interfaces]: module.fail_json( msg='Interface {0} is already present; use operation "update"'. format(eth.name)) con.vsys = vsys_dg # Create the interface. try: eth.create() set_zone(con, eth, zone_name, zones) set_virtual_router(con, eth, vr_name, routers) changed = True except (PanDeviceError, ValueError): e = get_exception() module.fail_json(msg=e.message) elif operation == 'update': if eth.name not in [x.name for x in interfaces]: module.fail_json( msg= 'Interface {0} is not present; use operation "add" to create it' .format(eth.name)) # If the interface is in the wrong vsys, remove it from the old vsys. try: con.organize_into_vsys() except PanDeviceError: e = get_exception() module.fail_json(msg=e.message) if eth.vsys != vsys_dg: try: eth.delete_import() except PanDeviceError: e = get_exception() module.fail_json(msg=e.message) # Move the ethernet object to the correct vsys. for vsys in vsys_list: if vsys.name == vsys_dg: vsys.add(eth) break else: module.fail_json(msg='Vsys {0} does not exist'.format(vsys)) # Update the interface. try: eth.apply() set_zone(con, eth, zone_name, zones) set_virtual_router(con, eth, vr_name, routers) changed = True except (PanDeviceError, ValueError): e = get_exception() module.fail_json(msg=e.message) else: module.fail_json(msg="Unsupported operation '{0}'".format(operation)) # Commit if we were asked to do so. if changed and commit: try: con.commit(sync=True, exceptions=True) except PanDeviceError: e = get_exception() module.fail_json(msg='Performed {0} but commit failed: {1}'.format( operation, e.message)) # Done! module.exit_json(changed=changed, msg='okey dokey')