Merge "Update firewall role to use an action plugin" into stable/train
This commit is contained in:
commit
83adfcd99d
|
@ -0,0 +1,320 @@
|
|||
# Copyright 2019 Red Hat, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: tripleo_iptables
|
||||
author:
|
||||
- Kevin Carter (@cloudnull) <kecarter@redhat.com>
|
||||
version_added: '2.8'
|
||||
short_description: Runs iptables module commands in bulk.
|
||||
notes: []
|
||||
description:
|
||||
- This module accepts iptables rules in list format and batches their
|
||||
creation to speed up the creation of rules at scale.
|
||||
options:
|
||||
tripleo_rules:
|
||||
description:
|
||||
- List of rules to batch, rules have been constructed using the tripleo
|
||||
spec and will be formatted to match the input values of the core
|
||||
iptables module.
|
||||
required: True
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
- name: Run Package Installation
|
||||
tripleo_iptables:
|
||||
tripleo_rules:
|
||||
- '1 rule special':
|
||||
dport:
|
||||
- 1234
|
||||
- 4321
|
||||
- '2 rule special also':
|
||||
dport:
|
||||
- 2345
|
||||
- 5432
|
||||
"""
|
||||
|
||||
|
||||
from ansible.plugins.action import ActionBase
|
||||
from ansible.plugins.filter import ipaddr
|
||||
from ansible.utils.display import Display
|
||||
|
||||
|
||||
DISPLAY = Display()
|
||||
RULE_STATES = {
|
||||
'enabled': 'present',
|
||||
'present': 'present',
|
||||
'absent': 'absent',
|
||||
'disabled': 'absent'
|
||||
}
|
||||
IPTABLES_BIN = {
|
||||
'ipv4': 'iptables',
|
||||
'ipv6': 'ip6tables'
|
||||
}
|
||||
IPTABLES_CHAIN_CMD = """
|
||||
if ! {cmd} --list "{chain}"; then
|
||||
{cmd} -N "{chain}"
|
||||
fi
|
||||
"""
|
||||
IPTABLES_CHAINS = ('INPUT', 'OUTPUT', 'FORWARD')
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
"""Batch iptables rules for faster rule creation."""
|
||||
|
||||
def _run_module(self, name, args, task_vars):
|
||||
"""Runs an ansible module and collects return information.
|
||||
|
||||
:returns: boolean
|
||||
"""
|
||||
|
||||
module_return = self._execute_module(
|
||||
module_name=name,
|
||||
module_args=args,
|
||||
task_vars=task_vars
|
||||
)
|
||||
changed = module_return.get('changed')
|
||||
if changed:
|
||||
self.return_data['changed'] = True
|
||||
|
||||
self.return_data['stdout'] = module_return.get('stdout')
|
||||
self.return_data['stderr'] = module_return.get('stderr')
|
||||
self.return_data['msg'] = module_return.get('msg')
|
||||
self.return_data['cmd'] = module_return.get('cmd')
|
||||
self.return_data['rc'] = module_return.get('rc', 0)
|
||||
fatal = self.return_data['failed'] = module_return.get(
|
||||
'failed',
|
||||
False
|
||||
)
|
||||
DISPLAY.vv('Module name: {}'.format(name))
|
||||
DISPLAY.vv('Module args: {}'.format(args))
|
||||
if fatal:
|
||||
DISPLAY.error('Failed, module return: {}'.format(module_return))
|
||||
DISPLAY.error('Failed, return data: {}'.format(self.return_data))
|
||||
|
||||
return fatal
|
||||
|
||||
@staticmethod
|
||||
def _check_rule_data(rule_data, ipversion):
|
||||
"""Check the rule data for compatible ip version information.
|
||||
|
||||
This function uses the ansible ipaddr filter to validate IP
|
||||
information when a source or destination has been provided.
|
||||
|
||||
:returns: boolean
|
||||
"""
|
||||
|
||||
kwargs_hash = {
|
||||
'ipv6': {
|
||||
'version': 6,
|
||||
'query': 'ipv6',
|
||||
'alias': 'ipv6'
|
||||
},
|
||||
'ipv4': {
|
||||
'version': 4,
|
||||
'query': 'ipv4',
|
||||
'alias': 'ipv4'
|
||||
}
|
||||
}
|
||||
|
||||
for arg in ('source', 'destination'):
|
||||
ip_data = rule_data.get(arg)
|
||||
if ip_data:
|
||||
DISPLAY.v(
|
||||
'Checking "{}" against "{}" with ip version "{}"'.format(
|
||||
arg,
|
||||
ip_data,
|
||||
ipversion
|
||||
)
|
||||
)
|
||||
ip_data_check = ipaddr.ipaddr(
|
||||
value=ip_data,
|
||||
**kwargs_hash[ipversion]
|
||||
)
|
||||
DISPLAY.vvv('ipaddr filter return "{}"'.format(ip_data_check))
|
||||
if not ip_data_check:
|
||||
DISPLAY.v(
|
||||
'Rule has a "{}" but the value "{}" is not applicable'
|
||||
' to ip version "{}"'.format(
|
||||
arg,
|
||||
ip_data,
|
||||
ipversion
|
||||
|
||||
)
|
||||
)
|
||||
DISPLAY.vvv('Rule data: "{}"'.format(rule_data))
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def queue_rules(self):
|
||||
"""Add chains and rules to the required queues."""
|
||||
|
||||
for item in self._task.args['tripleo_rules']:
|
||||
rule_data = dict()
|
||||
rule = item['rule']
|
||||
|
||||
ipversions = rule.get('ipversion', ['ipv4', 'ipv6'])
|
||||
if not isinstance(ipversions, list):
|
||||
ipversions = [ipversions]
|
||||
|
||||
state = rule.get('extras', dict()).get('ensure', 'enabled')
|
||||
rule_data['state'] = RULE_STATES[state]
|
||||
|
||||
action = rule_data['action'] = rule.get('action', 'insert')
|
||||
if action == 'drop':
|
||||
rule_data['action'] = 'insert'
|
||||
rule_data['state'] = 'absent'
|
||||
|
||||
rule_data['chain'] = rule.get('chain', 'INPUT')
|
||||
rule_data['jump'] = rule.get('jump', 'ACCEPT')
|
||||
rule_data['protocol'] = rule.get('proto', 'tcp')
|
||||
if 'table' in rule:
|
||||
rule_data['table'] = rule['table']
|
||||
|
||||
if 'interface' in rule:
|
||||
rule_data['in_interface'] = rule['interface']
|
||||
|
||||
if 'sport' in rule:
|
||||
rule_data['source_port'] = rule['sport']
|
||||
|
||||
if 'source' in rule:
|
||||
rule_data['source'] = rule['source']
|
||||
|
||||
if rule_data['protocol'] != 'gre':
|
||||
rule_data['ctstate'] = rule.get('state', 'NEW')
|
||||
|
||||
if 'limit' in rule:
|
||||
rule_data['limit'] = rule['limit']
|
||||
|
||||
if 'limit_burst' in rule:
|
||||
rule_data['limit_burst'] = rule['limit_burst']
|
||||
|
||||
if 'destination' in rule:
|
||||
rule_data['destination'] = rule['destination']
|
||||
|
||||
for ipversion in ipversions:
|
||||
if not self._check_rule_data(rule_data=rule_data,
|
||||
ipversion=ipversion):
|
||||
continue
|
||||
|
||||
versioned_rule_data = rule_data.copy()
|
||||
versioned_rule_data['ip_version'] = ipversion
|
||||
if 'rule_name' in item:
|
||||
versioned_rule_data['comment'] = '{} {}'.format(
|
||||
item['rule_name'],
|
||||
ipversion
|
||||
)
|
||||
|
||||
if not versioned_rule_data['chain'] in IPTABLES_CHAINS:
|
||||
chain = versioned_rule_data['chain']
|
||||
DISPLAY.v(
|
||||
'Queueing chain: {}, ip version {}'.format(
|
||||
chain, ipversion
|
||||
)
|
||||
)
|
||||
self.iptables_chains.append(
|
||||
{
|
||||
'ipv': ipversion,
|
||||
'chain': chain,
|
||||
'command': IPTABLES_CHAIN_CMD.format(
|
||||
cmd=IPTABLES_BIN[ipversion],
|
||||
chain=chain
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
if 'dport' in rule:
|
||||
dport_rule_data = versioned_rule_data.copy()
|
||||
dports = rule['dport']
|
||||
if not isinstance(dports, list):
|
||||
dports = [dports]
|
||||
|
||||
for dport in dports:
|
||||
if isinstance(dport, int):
|
||||
dport_rule_data['destination_port'] = dport
|
||||
else:
|
||||
dport = dport.replace('-', ':')
|
||||
dport_rule_data['destination_port'] = dport
|
||||
|
||||
DISPLAY.v(
|
||||
'Queueing port rule: {},'
|
||||
' ip version: {},'
|
||||
' dport: {}'.format(
|
||||
dport_rule_data.get('comment', None),
|
||||
ipversion,
|
||||
dport_rule_data['destination_port']
|
||||
)
|
||||
)
|
||||
self.iptables_rules.append(dport_rule_data.copy())
|
||||
else:
|
||||
DISPLAY.v(
|
||||
'Queueing service rule: {},'
|
||||
' ip version: {}'.format(
|
||||
versioned_rule_data.get('comment', None),
|
||||
ipversion
|
||||
)
|
||||
)
|
||||
self.iptables_rules.append(versioned_rule_data.copy())
|
||||
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
"""Run the iptables firewall rule batcher.
|
||||
|
||||
When rules are batched, the chains will be created before the rules.
|
||||
"""
|
||||
|
||||
self.return_data = dict()
|
||||
self.iptables_rules = list()
|
||||
self.iptables_chains = list()
|
||||
|
||||
self.queue_rules()
|
||||
|
||||
for iptables_chain in self.iptables_chains:
|
||||
DISPLAY.v(
|
||||
'Managing chain: {} for version {}'.format(
|
||||
iptables_chain['chain'],
|
||||
iptables_chain['ipv']
|
||||
)
|
||||
)
|
||||
return_data = self._low_level_execute_command(
|
||||
iptables_chain['command'],
|
||||
executable='/bin/bash'
|
||||
)
|
||||
if return_data['rc'] > 0:
|
||||
DISPLAY.error(msg='Failed command: {}'.format(iptables_chain))
|
||||
DISPLAY.error(msg='Failed chain data: {}'.format(return_data))
|
||||
return return_data
|
||||
|
||||
for iptables_rule in self.iptables_rules:
|
||||
DISPLAY.v(
|
||||
'Managing rule: {},'
|
||||
' dport: {},'
|
||||
' ip version: {}'.format(
|
||||
iptables_rule.get('comment', 'undefined'),
|
||||
iptables_rule.get('destination_port', 'undefined'),
|
||||
iptables_rule['ip_version'],
|
||||
)
|
||||
)
|
||||
fatal = self._run_module(
|
||||
name='iptables',
|
||||
args=iptables_rule,
|
||||
task_vars=task_vars
|
||||
)
|
||||
if fatal:
|
||||
return self.return_data
|
||||
|
||||
return self.return_data
|
|
@ -47,3 +47,11 @@
|
|||
dport: 2211
|
||||
'006 ironic-inspector':
|
||||
dport: 2212
|
||||
'124 snmp':
|
||||
dport: 2212
|
||||
source: '192.168.24.1/24'
|
||||
chain: test-chain2
|
||||
'125 snmp':
|
||||
dport: 2212
|
||||
destination: '::'
|
||||
chain: test-chain2
|
||||
|
|
|
@ -61,3 +61,13 @@
|
|||
dport: 2212
|
||||
extras:
|
||||
ensure: 'absent'
|
||||
'124 snmp':
|
||||
dport: 2212
|
||||
source: '192.168.24.1/24'
|
||||
extras:
|
||||
ensure: 'absent'
|
||||
'125 snmp':
|
||||
dport: 2212
|
||||
destination: '::'
|
||||
extras:
|
||||
ensure: 'absent'
|
||||
|
|
|
@ -39,18 +39,6 @@
|
|||
list
|
||||
}}"
|
||||
|
||||
- name: Check rule set
|
||||
fail:
|
||||
msg: >-
|
||||
`{{ item['rule_name'] }}` firewall rule cannot be created. TCP or UDP rules
|
||||
for INPUT or OUTPUT need sport or dport defined.
|
||||
when:
|
||||
- ((item['rule']['proto'] | default('tcp')) in ['tcp', 'udp']) and
|
||||
(item['rule']['dport'] is undefined) and
|
||||
((item['rule']['chain'] | default('INPUT')) != 'FORWARD') and
|
||||
((item['rule']['table'] | default('filter')) != 'nat')
|
||||
loop: "{{ firewall_rules_sorted }}"
|
||||
|
||||
- name: Firewall add block
|
||||
become: true
|
||||
block:
|
||||
|
@ -65,6 +53,8 @@
|
|||
state: started
|
||||
enabled: true
|
||||
|
||||
- name: Enable filewall port config
|
||||
include_tasks: tripleo_firewall_add.yml
|
||||
loop: "{{ firewall_rules_sorted }}"
|
||||
- name: Manage firewall rules
|
||||
tripleo_iptables:
|
||||
tripleo_rules: "{{ firewall_rules_sorted }}"
|
||||
notify:
|
||||
- Save firewall rules
|
||||
|
|
|
@ -1,156 +0,0 @@
|
|||
---
|
||||
# Copyright 2019 Red Hat, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
# NOTE(Cloudnull): This task exists because the iptables module will not
|
||||
# create a chain. There is a feature request open for this
|
||||
# [ https://github.com/ansible/ansible/issues/25099 ].
|
||||
# A change has been added to support this functionality but
|
||||
# it is awaiting review and merge.
|
||||
# [ https://github.com/ansible/ansible/pull/32158 ]. When
|
||||
# this change is merged this task should be removed.
|
||||
- name: Ensure chains exist
|
||||
shell: |-
|
||||
EXIT_CODE=0
|
||||
if ! iptables --list "{{ item['rule']['chain'] }}"; then
|
||||
iptables -N "{{ item['rule']['chain'] }}"
|
||||
EXIT_CODE=99
|
||||
fi
|
||||
if ! ip6tables --list "{{ item['rule']['chain'] }}"; then
|
||||
ip6tables -N "{{ item['rule']['chain'] }}"
|
||||
EXIT_CODE=99
|
||||
fi
|
||||
exit ${EXIT_CODE}
|
||||
when:
|
||||
- (item['rule']['chain'] | default('INPUT')) != 'INPUT'
|
||||
- tripleo_firewall_port_states[(item['rule']['extras'] | default({}))['ensure'] | default('enabled')] == "present"
|
||||
register: iptables_chain
|
||||
changed_when: iptables_chain.rc == 99
|
||||
failed_when: not (iptables_chain.rc in [0, 99])
|
||||
|
||||
- include_tasks: tripleo_firewall_state.yml
|
||||
|
||||
# NOTE(Cloudnull): This task adds multiport rules using a loop instead of using
|
||||
# the multiport key word. While multiport is perfectly functional
|
||||
# using raw iptables rules, it is not supported in the ansible
|
||||
# module. The use of the loop will be revised just as soon as the
|
||||
# pull request [ https://github.com/ansible/ansible/pull/21071 ]
|
||||
# is merged.
|
||||
- name: Firewall port rule (ipv4)
|
||||
iptables:
|
||||
action: insert
|
||||
table: "{{ item['rule']['table'] | default(omit) }}"
|
||||
chain: "{{ item['rule']['chain'] | default('INPUT') }}"
|
||||
in_interface: "{{ item['rule']['interface'] | default(omit) }}"
|
||||
protocol: "{{ item['rule']['proto'] | default('tcp') }}"
|
||||
destination_port: "{{ port | replace('-', ':') }}"
|
||||
destination: "{{ item['rule']['destination'] | default(omit) }}"
|
||||
source_port: "{{ item['rule']['sport'] | default(omit) | replace('-', ':') }}"
|
||||
source: "{{ item['rule']['source'] | default(omit) }}"
|
||||
comment: "{{ item['rule_name'] }} ipv4"
|
||||
jump: "{{ item['rule']['jump'] | default('ACCEPT') }}"
|
||||
ctstate: "{{ tripleo_ctstate }}"
|
||||
limit: "{{ item['rule']['limit'] | default(omit) }}"
|
||||
limit_burst: "{{ item['rule']['limit_burst'] | default(omit) }}"
|
||||
ip_version: ipv4
|
||||
state: "{{ tripleo_firewall_port_states[(item['rule']['extras'] | default({}))['ensure'] | default('enabled')] }}"
|
||||
when:
|
||||
- item['rule']['dport'] is defined
|
||||
- (item['rule']['ipversion'] | default('ipv4')) != 'ipv6'
|
||||
- item['rule']['source'] | default('127.0.0.1') | ipv4
|
||||
- item['rule']['destination'] | default('127.0.0.1') | ipv4
|
||||
loop: "{{ ((item['rule']['dport'] is iterable) and (item['rule']['dport'] is not string)) | ternary(item['rule']['dport'], [item['rule']['dport']]) }}"
|
||||
loop_control:
|
||||
loop_var: port
|
||||
notify:
|
||||
- Save firewall rules
|
||||
|
||||
# NOTE(Cloudnull): This task adds multiport rules using a loop instead of using
|
||||
# the multiport key word. While multiport is perfectly functional
|
||||
# using raw iptables rules, it is not supported in the ansible
|
||||
# module. The use of the loop will be revised just as soon as the
|
||||
# pull request [ https://github.com/ansible/ansible/pull/21071 ]
|
||||
# is merged.
|
||||
- name: Firewall port rule (ipv6)
|
||||
iptables:
|
||||
action: insert
|
||||
table: "{{ item['rule']['table'] | default(omit) }}"
|
||||
chain: "{{ item['rule']['chain'] | default('INPUT') }}"
|
||||
in_interface: "{{ item['rule']['interface'] | default(omit) }}"
|
||||
protocol: "{{ item['rule']['proto'] | default('tcp') }}"
|
||||
destination_port: "{{ port | replace('-', ':') }}"
|
||||
destination: "{{ item['rule']['destination'] | default(omit) }}"
|
||||
source_port: "{{ item['rule']['sport'] | default(omit) | replace('-', ':') }}"
|
||||
source: "{{ item['rule']['source'] | default(omit) }}"
|
||||
comment: "{{ item['rule_name'] }} ipv6"
|
||||
jump: "{{ item['rule']['jump'] | default('ACCEPT') }}"
|
||||
ctstate: "{{ tripleo_ctstate }}"
|
||||
limit: "{{ item['rule']['limit'] | default(omit) }}"
|
||||
limit_burst: "{{ item['rule']['limit_burst'] | default(omit) }}"
|
||||
ip_version: ipv6
|
||||
state: "{{ tripleo_firewall_port_states[(item['rule']['extras'] | default({}))['ensure'] | default('enabled')] }}"
|
||||
when:
|
||||
- item['rule']['dport'] is defined
|
||||
- (item['rule']['ipversion'] | default('ipv6')) != 'ipv4'
|
||||
- item['rule']['source'] | default('::') | ipv6
|
||||
- item['rule']['destination'] | default('::') | ipv6
|
||||
loop: "{{ ((item['rule']['dport'] is iterable) and (item['rule']['dport'] is not string)) | ternary(item['rule']['dport'], [item['rule']['dport']]) }}"
|
||||
loop_control:
|
||||
loop_var: port
|
||||
notify:
|
||||
- Save firewall rules
|
||||
|
||||
- name: Firewall protocol rule (ipv4)
|
||||
iptables:
|
||||
action: insert
|
||||
table: "{{ item['rule']['table'] | default(omit) }}"
|
||||
chain: "{{ item['rule']['chain'] | default('INPUT') }}"
|
||||
in_interface: "{{ item['rule']['interface'] | default(omit) }}"
|
||||
protocol: "{{ item['rule']['proto'] | default(omit) }}"
|
||||
source_port: "{{ item['rule']['sport'] | default(omit) | replace('-', ':') }}"
|
||||
source: "{{ item['rule']['source'] | default(omit) }}"
|
||||
comment: "{{ item['rule_name'] }} ipv4"
|
||||
jump: "{{ item['rule']['jump'] | default('ACCEPT') }}"
|
||||
ctstate: "{{ tripleo_ctstate }}"
|
||||
limit: "{{ item['rule']['limit'] | default(omit) }}"
|
||||
limit_burst: "{{ item['rule']['limit_burst'] | default(omit) }}"
|
||||
ip_version: ipv4
|
||||
state: "{{ tripleo_firewall_port_states[(item['rule']['extras'] | default({}))['ensure'] | default('enabled')] }}"
|
||||
when:
|
||||
- (item['rule']['ipversion'] | default('ipv4')) != 'ipv6'
|
||||
- item['rule']['proto'] is defined
|
||||
- item['rule']['dport'] is undefined
|
||||
|
||||
- name: Firewall protocol rule (ipv6)
|
||||
iptables:
|
||||
action: insert
|
||||
table: "{{ item['rule']['table'] | default(omit) }}"
|
||||
chain: "{{ item['rule']['chain'] | default('INPUT') }}"
|
||||
in_interface: "{{ item['rule']['interface'] | default(omit) }}"
|
||||
protocol: "{{ item['rule']['proto'] | default(omit) }}"
|
||||
source_port: "{{ item['rule']['sport'] | default(omit) | replace('-', ':') }}"
|
||||
source: "{{ item['rule']['source'] | default(omit) }}"
|
||||
comment: "{{ item['rule_name'] }} ipv6"
|
||||
jump: "{{ item['rule']['jump'] | default('ACCEPT') }}"
|
||||
ctstate: "{{ tripleo_ctstate }}"
|
||||
limit: "{{ item['rule']['limit'] | default(omit) }}"
|
||||
limit_burst: "{{ item['rule']['limit_burst'] | default(omit) }}"
|
||||
ip_version: ipv6
|
||||
state: "{{ tripleo_firewall_port_states[(item['rule']['extras'] | default({}))['ensure'] | default('enabled')] }}"
|
||||
when:
|
||||
- (item['rule']['ipversion'] | default('ipv6')) != 'ipv4'
|
||||
- item['rule']['proto'] is defined
|
||||
- item['rule']['dport'] is undefined
|
|
@ -1,28 +0,0 @@
|
|||
---
|
||||
# Copyright 2019 Red Hat, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
- name: Set gre state fact
|
||||
set_fact:
|
||||
tripleo_ctstate: []
|
||||
when:
|
||||
- (item['rule']['proto'] | default('tcp')) == 'gre'
|
||||
|
||||
- name: Set general state fact
|
||||
set_fact:
|
||||
tripleo_ctstate: "{{ item['rule']['ctstate'] | default(item['rule']['state'] | default('NEW')) }}"
|
||||
when:
|
||||
- (item['rule']['proto'] | default('tcp')) != 'gre'
|
Loading…
Reference in New Issue