@ -56,6 +56,18 @@ options:
description :
description :
- ID of Security group to link ( exclusive with remote_ip_prefix )
- ID of Security group to link ( exclusive with remote_ip_prefix )
required : false
required : false
ethertype :
description :
- Must be IPv4 or IPv6 , and addresses represented in CIDR must
match the ingress or egress rules . Not all providers support IPv6 .
choices : [ ' IPv4 ' , ' IPv6 ' ]
default : IPv4
direction :
description :
- The direction in which the security group rule is applied . Not
all providers support egress .
choices : [ ' egress ' , ' ingress ' ]
default : ingress
state :
state :
description :
description :
- Should the resource be present or absent .
- Should the resource be present or absent .
@ -78,80 +90,113 @@ EXAMPLES = '''
'''
'''
def _security_group_rule ( module , nova_client , action = ' create ' , * * kwargs ) :
def _find_matching_rule ( module , secgroup ) :
f = getattr ( nova_client . security_group_rules , action )
"""
try :
Find a rule in the group that matches the module parameters .
secgroup = f ( * * kwargs )
except Exception , e :
module . fail_json ( msg = ' Failed to %s security group rule: %s ' %
( action , e . message ) )
: returns : The matching rule dict , or None if no matches .
"""
protocol = module . params [ ' protocol ' ]
port_range_min = module . params [ ' port_range_min ' ]
port_range_max = module . params [ ' port_range_max ' ]
remote_ip_prefix = module . params [ ' remote_ip_prefix ' ]
ethertype = module . params [ ' ethertype ' ]
direction = module . params [ ' direction ' ]
def _get_rule_from_group ( module , secgroup ) :
for rule in secgroup [ ' security_group_rules ' ] :
for rule in secgroup [ ' security_group_rules ' ] :
# No port, or -1, will be returned as None
# No port, or -1, will be returned from shade as None
port_range_min = rule [ ' port_range_min ' ] or - 1
rule_port_range_min = rule [ ' port_range_min ' ] or - 1
port_range_max = rule [ ' port_range_max ' ] or - 1
rule_port_range_max = rule [ ' port_range_max ' ] or - 1
if ( rule [ ' protocol ' ] == module . params [ ' protocol ' ] and
port_range_min == module . params [ ' port_range_min ' ] and
if ( protocol == rule [ ' protocol ' ]
port_range_max == module . params [ ' port_range_max ' ] and
and port_range_min == rule_port_range_min
rule [ ' remote_ip_prefix ' ] == module . params [ ' remote_ip_prefix ' ] ) :
and port_range_max == rule_port_range_max
and remote_ip_prefix == rule [ ' remote_ip_prefix ' ]
and ethertype == rule [ ' ethertype ' ]
and direction == rule [ ' direction ' ] ) :
return rule
return rule
return None
return None
def _system_state_change ( module , secgroup ) :
state = module . params [ ' state ' ]
if secgroup :
rule_exists = _find_matching_rule ( module , secgroup )
else :
return False
if state == ' present ' and not rule_exists :
return True
if state == ' absent ' and rule_exists :
return True
return False
def main ( ) :
def main ( ) :
argument_spec = openstack_full_argument_spec (
argument_spec = openstack_full_argument_spec (
security_group = dict ( required = True ) ,
security_group = dict ( required = True ) ,
protocol = dict ( default = ' tcp ' , choices = [ ' tcp ' , ' udp ' , ' icmp ' ] ) ,
protocol = dict ( default = ' tcp ' ,
choices = [ ' tcp ' , ' udp ' , ' icmp ' ] ) ,
port_range_min = dict ( required = True ) ,
port_range_min = dict ( required = True ) ,
port_range_max = dict ( required = True ) ,
port_range_max = dict ( required = True ) ,
remote_ip_prefix = dict ( required = False , default = None ) ,
remote_ip_prefix = dict ( required = False , default = None ) ,
# TODO(mordred): Make remote_group handle name and id
# TODO(mordred): Make remote_group handle name and id
remote_group = dict ( required = False , default = None ) ,
remote_group = dict ( required = False , default = None ) ,
state = dict ( default = ' present ' , choices = [ ' absent ' , ' present ' ] ) ,
ethertype = dict ( default = ' IPv4 ' ,
choices = [ ' IPv4 ' , ' IPv6 ' ] ) ,
direction = dict ( default = ' ingress ' ,
choices = [ ' egress ' , ' ingress ' ] ) ,
state = dict ( default = ' present ' ,
choices = [ ' absent ' , ' present ' ] ) ,
)
)
module_kwargs = openstack_module_kwargs (
module_kwargs = openstack_module_kwargs (
mutually_exclusive = [
mutually_exclusive = [
[ ' remote_ip_prefix ' , ' remote_group ' ] ,
[ ' remote_ip_prefix ' , ' remote_group ' ] ,
]
]
)
)
module = AnsibleModule ( argument_spec , * * module_kwargs )
module = AnsibleModule ( argument_spec ,
supports_check_mode = True ,
* * module_kwargs )
state = module . params [ ' state ' ]
security_group = module . params [ ' security_group ' ]
changed = False
try :
try :
cloud = shade . openstack_cloud ( * * module . params )
cloud = shade . openstack_cloud ( * * module . params )
nova_client = cloud . nova_client
secgroup = cloud . get_security_group ( security_group )
changed = False
secgroup = cloud . get_security_group ( module . params [ ' security_group ' ] )
if module . check_mode :
module . exit_json ( changed = _system_state_change ( module , secgroup ) )
if module. params [ ' state' ] == ' present ' :
if state == ' present ' :
if not secgroup :
if not secgroup :
module . fail_json ( msg = ' Could not find security group %s ' %
module . fail_json ( msg = ' Could not find security group %s ' %
module. params [ ' security_group' ] )
security_group)
if not _ get _rule_from_group ( module , secgroup ) :
if not _ find_matchin g_rule( module , secgroup ) :
_security_group_rule( module , nova_client , ' create ' ,
cloud. create _security_group_rule(
parent_group_id = secgroup [ ' id ' ] ,
secgroup [ ' id ' ] ,
ip_protocol = module . params [ ' protocol ' ] ,
port_range_min = module . params [ ' port_range_min ' ] ,
from_ port= module . params [ ' port_range_m in ' ] ,
port_range_max = module . params [ ' port_range_m ax ' ] ,
to_ po rt= module . params [ ' p ort_range_max ' ] ,
pro tocol = module . params [ ' p rotocol ' ] ,
cidr = module . params [ ' remote_ip_prefix ' ]
remote_ip_prefix = module . params [ ' remote_ip_prefix ' ] ,
if ' remote_ip_prefix ' in module . params else None ,
remote_group_id = module . params [ ' remote_group ' ] ,
group_id = module . params [ ' remote_group ' ]
direction = module . params [ ' direction ' ] ,
if ' remote_group ' in module . params else None
ethertype = module . params [ ' ethertype ' ]
)
)
changed = True
changed = True
if state == ' absent ' and secgroup :
if module . params [ ' state ' ] == ' absent ' and secgroup :
rule = _find_matching_rule ( module , secgroup )
rule = _get_rule_from_group ( module , secgroup )
if rule :
if secgroup and rule :
cloud . delete_security_group_rule ( rule [ ' id ' ] )
_security_group_rule ( module , nova_client , ' delete ' ,
rule = rule [ ' id ' ] )
changed = True
changed = True
module . exit_json ( changed = changed , result = " success " )
module . exit_json ( changed = changed )
except shade . OpenStackCloudException as e :
except shade . OpenStackCloudException as e :
module . fail_json ( msg = e . message )
module . fail_json ( msg = e . message )