mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Initial commit of ELB policy management for boto_elb.
This commit is contained in:
parent
281e4fd966
commit
2f715803b2
2 changed files with 404 additions and 91 deletions
|
@ -130,26 +130,48 @@ def get_elb_config(name, region=None, key=None, keyid=None, profile=None):
|
|||
ret['availability_zones'] = lb.availability_zones
|
||||
listeners = []
|
||||
for _listener in lb.listeners:
|
||||
# Making this a list makes our life easier and is also the only way
|
||||
# to include the certificate.
|
||||
complex_listener = list(_listener.get_complex_tuple())
|
||||
# boto, you're *killing* me with this. boto doesn't include the
|
||||
# certificate when calling get_complex_tuple, so you need to also
|
||||
# get the certificate. So. Much. Hate.
|
||||
listener_dict = {}
|
||||
listener_dict['elb_port'] = _listener.load_balancer_port
|
||||
listener_dict['elb_protocol'] = _listener.protocol
|
||||
listener_dict['instance_port'] = _listener.instance_port
|
||||
listener_dict['instance_protocol'] = _listener.instance_protocol
|
||||
listener_dict['policies'] = _listener.policy_names
|
||||
if _listener.ssl_certificate_id:
|
||||
complex_listener.append(_listener.ssl_certificate_id)
|
||||
listeners.append(complex_listener)
|
||||
listener_dict['certificate'] = _listener.ssl_certificate_id
|
||||
listeners.append(listener_dict)
|
||||
ret['listeners'] = listeners
|
||||
ret['subnets'] = lb.subnets
|
||||
ret['security_groups'] = lb.security_groups
|
||||
ret['scheme'] = lb.scheme
|
||||
ret['dns_name'] = lb.dns_name
|
||||
lb_policy_lists = [
|
||||
lb.policies.app_cookie_stickiness_policies,
|
||||
lb.policies.lb_cookie_stickiness_policies,
|
||||
lb.policies.other_policies
|
||||
]
|
||||
policies = []
|
||||
for policy_list in lb_policy_lists:
|
||||
policies += [p.policy_name for p in policy_list]
|
||||
ret['policies'] = policies
|
||||
return ret
|
||||
except boto.exception.BotoServerError as error:
|
||||
log.debug(error)
|
||||
return []
|
||||
|
||||
|
||||
def listener_dict_to_tuple(listener):
|
||||
# We define all listeners as complex listeners.
|
||||
if 'instance_protocol' not in listener:
|
||||
instance_protocol = listener['elb_protocol'].upper()
|
||||
else:
|
||||
instance_protocol = listener['instance_protocol'].upper()
|
||||
listener_tuple = [listener['elb_port'], listener['instance_port'],
|
||||
listener['elb_protocol'], instance_protocol]
|
||||
if 'certificate' in listener:
|
||||
listener_tuple.append(listener['certificate'])
|
||||
return tuple(listener_tuple)
|
||||
|
||||
|
||||
def create(name, availability_zones, listeners=None, subnets=None,
|
||||
security_groups=None, scheme='internet-facing',
|
||||
region=None, key=None, keyid=None,
|
||||
|
@ -159,31 +181,20 @@ def create(name, availability_zones, listeners=None, subnets=None,
|
|||
|
||||
CLI example to create an ELB::
|
||||
|
||||
salt myminion boto_elb.create myelb '["us-east-1a", "us-east-1e"]' listeners='[[443, 80, "HTTPS", "HTTP", "arn:aws:iam::1111111:server-certificate/mycert"]]' region=us-east-1
|
||||
salt myminion boto_elb.create myelb '["us-east-1a", "us-east-1e"]' listeners='{"elb_port": 443, "elb_protocol": "HTTPS", ...}' region=us-east-1
|
||||
'''
|
||||
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
|
||||
|
||||
if __salt__['boto_elb.exists'](name, region, key, keyid, profile):
|
||||
if exists(name, region, key, keyid, profile):
|
||||
return True
|
||||
if isinstance(availability_zones, string_types):
|
||||
availability_zones = json.loads(availability_zones)
|
||||
if isinstance(listeners, string_types):
|
||||
listeners = json.loads(listeners)
|
||||
# Combining listeners and complex_listeners together makes our lives
|
||||
# easier in some ways, especially since during introspection you can
|
||||
# only get a combined set of listeners back from boto; however, boto
|
||||
# requires us to send in separate listeners and complex listeners and
|
||||
# the only real difference is the size. It feels like amazon/boto hate
|
||||
# developers and wish to make us suffer.
|
||||
_listeners = []
|
||||
_complex_listeners = []
|
||||
for listener in listeners:
|
||||
if len(listener) <= 3:
|
||||
_listeners.append(listener)
|
||||
else:
|
||||
_complex_listeners.append(listener)
|
||||
_complex_listeners.append(listener_dict_to_tuple(listener))
|
||||
try:
|
||||
lb = conn.create_load_balancer(name, availability_zones, _listeners,
|
||||
lb = conn.create_load_balancer(name, availability_zones, [],
|
||||
subnets, security_groups, scheme,
|
||||
_complex_listeners)
|
||||
if lb:
|
||||
|
@ -210,7 +221,7 @@ def delete(name, region=None, key=None, keyid=None, profile=None):
|
|||
'''
|
||||
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
|
||||
|
||||
if not __salt__['boto_elb.exists'](name, region, key, keyid, profile):
|
||||
if not exists(name, region, key, keyid, profile):
|
||||
return True
|
||||
try:
|
||||
conn.delete_load_balancer(name)
|
||||
|
@ -237,22 +248,11 @@ def create_listeners(name, listeners=None, region=None, key=None, keyid=None,
|
|||
|
||||
if isinstance(listeners, string_types):
|
||||
listeners = json.loads(listeners)
|
||||
# Combining listeners and complex_listeners together makes our lives
|
||||
# easier in some ways, especially since during introspection you can
|
||||
# only get a combined set of listeners back from boto; however, boto
|
||||
# requires us to send in separate listeners and complex listeners and
|
||||
# the only real difference is the size. It feels like amazon/boto hate
|
||||
# developers and wish to make us suffer.
|
||||
_listeners = []
|
||||
_complex_listeners = []
|
||||
for listener in listeners:
|
||||
if len(listener) <= 3:
|
||||
_listeners.append(listener)
|
||||
else:
|
||||
_complex_listeners.append(listener)
|
||||
_complex_listeners.append(listener_dict_to_tuple(listener))
|
||||
try:
|
||||
conn.create_load_balancer_listeners(name, _listeners,
|
||||
_complex_listeners)
|
||||
conn.create_load_balancer_listeners(name, [], _complex_listeners)
|
||||
msg = 'Created ELB listeners on {0}'.format(name)
|
||||
log.info(msg)
|
||||
return True
|
||||
|
@ -686,3 +686,60 @@ def get_instance_health(name, region=None, key=None, keyid=None, profile=None, i
|
|||
except boto.exception.BotoServerError as error:
|
||||
log.debug(error)
|
||||
return []
|
||||
|
||||
|
||||
def create_policy(name, policy_name, policy_type, policy, region=None,
|
||||
key=None, keyid=None, profile=None):
|
||||
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
|
||||
|
||||
if not exists(name, region, key, keyid, profile):
|
||||
return False
|
||||
try:
|
||||
success = conn.create_lb_policy(name, policy_name, policy_type, policy)
|
||||
if success:
|
||||
log.info('Created policy {0} on ELB {1}'.format(policy_name, name))
|
||||
return True
|
||||
else:
|
||||
msg = 'Failed to create policy {0} on ELB {1}'.format(policy_name, name)
|
||||
log.error(msg)
|
||||
return False
|
||||
except boto.exception.BotoServerError as e:
|
||||
log.debug(e)
|
||||
msg = 'Failed to create policy {0} on ELB {1}: {2}'.format(policy_name, name, e.message)
|
||||
log.error(msg)
|
||||
return False
|
||||
|
||||
|
||||
def delete_policy(name, policy_name, region=None, key=None, keyid=None,
|
||||
profile=None):
|
||||
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
|
||||
|
||||
if not exists(name, region, key, keyid, profile):
|
||||
return True
|
||||
try:
|
||||
conn.delete_lb_policy(name, policy_name)
|
||||
log.info('Deleted policy {0} on ELB {1}'.format(policy_name, name))
|
||||
return True
|
||||
except boto.exception.BotoServerError as e:
|
||||
log.debug(e)
|
||||
msg = 'Failed to delete policy {0} on ELB {1}: {2}'.format(policy_name, name, e.message)
|
||||
log.error(msg)
|
||||
return False
|
||||
|
||||
|
||||
def set_listener_policy(name, port, policies=None, region=None, key=None,
|
||||
keyid=None, profile=None):
|
||||
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
|
||||
|
||||
if not exists(name, region, key, keyid, profile):
|
||||
return True
|
||||
if policies is None:
|
||||
policies = []
|
||||
try:
|
||||
conn.set_lb_policies_of_listener(name, port, policies)
|
||||
log.info('Set policies {0} on ELB {1} listener {2}'.format(policies, name, port))
|
||||
except boto.exception.BotoServerError as e:
|
||||
log.debug(e)
|
||||
log.info('Failed to set policy {0} on ELB {1} listener {2}: {3}'.format(policies, name, port, e.message))
|
||||
return False
|
||||
return True
|
||||
|
|
|
@ -51,6 +51,9 @@ passed in as a dict, or as a string to pull from pillars or minion config:
|
|||
elb_protocol: HTTPS
|
||||
instance_protocol: HTTP
|
||||
certificate: 'arn:aws:iam::1111111:server-certificate/mycert'
|
||||
policies:
|
||||
- my-ssl-policy
|
||||
- cookie-policy
|
||||
- elb_port: 8210
|
||||
instance_port: 8210
|
||||
elb_protocol: TCP
|
||||
|
@ -70,6 +73,17 @@ passed in as a dict, or as a string to pull from pillars or minion config:
|
|||
ttl: 60
|
||||
- name: myothercname.example.com.
|
||||
zone: example.com.
|
||||
- policies:
|
||||
- policy_name: my-ssl-policy
|
||||
policy_type: SSLNegotiationPolicyType
|
||||
policy:
|
||||
Protocol-TLSv1.2: true
|
||||
Protocol-SSLv3: false
|
||||
Server-Defined-Cipher-Order: true
|
||||
ECDHE-ECDSA-AES128-GCM-SHA256: true
|
||||
- policy_name: cookie-policy
|
||||
policy_type: LBCookieStickinessPolicyType
|
||||
policy: {} # no policy means this is a session cookie
|
||||
|
||||
# Using a profile from pillars
|
||||
Ensure myelb ELB exists:
|
||||
|
@ -198,11 +212,12 @@ Overriding the alarm values on the resource:
|
|||
from __future__ import absolute_import
|
||||
|
||||
# Import Salt Libs
|
||||
import hashlib
|
||||
import re
|
||||
import salt.utils.dictupdate as dictupdate
|
||||
from salt.exceptions import SaltInvocationError
|
||||
import salt.ext.six as six
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
Only load if boto is available.
|
||||
|
@ -223,6 +238,8 @@ def present(
|
|||
cnames=None,
|
||||
alarms=None,
|
||||
alarms_from_pillar="boto_elb_alarms",
|
||||
policies=None,
|
||||
policies_from_pillar="boto_elb_policies",
|
||||
region=None,
|
||||
key=None,
|
||||
keyid=None,
|
||||
|
@ -356,6 +373,14 @@ def present(
|
|||
_ret = _alarms_present(name, alarms, alarms_from_pillar, region, key, keyid, profile)
|
||||
ret['changes'] = dictupdate.update(ret['changes'], _ret['changes'])
|
||||
ret['comment'] = ' '.join([ret['comment'], _ret['comment']])
|
||||
if not _ret['result']:
|
||||
ret['result'] = _ret['result']
|
||||
if ret['result'] is False:
|
||||
return ret
|
||||
_ret = _policies_present(name, policies, policies_from_pillar, listeners, region, key,
|
||||
keyid, profile)
|
||||
ret['changes'] = dictupdate.update(ret['changes'], _ret['changes'])
|
||||
ret['comment'] = ' '.join([ret['comment'], _ret['comment']])
|
||||
if not _ret['result']:
|
||||
ret['result'] = _ret['result']
|
||||
if ret['result'] is False:
|
||||
|
@ -425,6 +450,8 @@ def register_instances(name, instances, region=None, key=None, keyid=None,
|
|||
return ret
|
||||
|
||||
|
||||
DEFAULT_PILLAR_LISTENER_POLICY_KEY = 'boto_elb_listener_policies'
|
||||
|
||||
def _elb_present(
|
||||
name,
|
||||
availability_zones,
|
||||
|
@ -445,33 +472,36 @@ def _elb_present(
|
|||
' exclusive arguments.')
|
||||
if not listeners:
|
||||
listeners = []
|
||||
_listeners = []
|
||||
for listener in listeners:
|
||||
if len(listener) < 3:
|
||||
raise SaltInvocationError('Listeners must have at minimum port,'
|
||||
' instance_port and protocol values in'
|
||||
' the provided list.')
|
||||
for config in ('elb_port', 'instance_port', 'elb_protocol'):
|
||||
if not listener.get(config):
|
||||
raise SaltInvocationError(
|
||||
'{0} is a required value for listeners.'.format(config)
|
||||
)
|
||||
|
||||
if 'elb_port' not in listener:
|
||||
raise SaltInvocationError('elb_port is a required value for'
|
||||
' listeners.')
|
||||
if 'instance_port' not in listener:
|
||||
raise SaltInvocationError('instance_port is a required value for'
|
||||
' listeners.')
|
||||
if 'elb_protocol' not in listener:
|
||||
raise SaltInvocationError('elb_protocol is a required value for'
|
||||
' listeners.')
|
||||
listener['elb_protocol'] = listener['elb_protocol'].upper()
|
||||
if listener['elb_protocol'] == 'HTTPS' and 'certificate' not in listener:
|
||||
raise SaltInvocationError('certificate is a required value for'
|
||||
' listeners if HTTPS is set for'
|
||||
' elb_protocol.')
|
||||
# We define all listeners as complex listeners.
|
||||
if not listener.get('instance_protocol'):
|
||||
listener['instance_protocol'] = listener['elb_protocol'].upper()
|
||||
else:
|
||||
listener['instance_protocol'] = listener['instance_protocol'].upper()
|
||||
_listener = [listener['elb_port'], listener['instance_port'],
|
||||
listener['elb_protocol'], listener['instance_protocol']]
|
||||
if 'certificate' in listener:
|
||||
_listener.append(listener['certificate'])
|
||||
_listeners.append(_listener)
|
||||
|
||||
# best attempt at principle of least surprise here:
|
||||
# only use the default pillar in cases where we don't explicitly
|
||||
# define policies OR policies_from_pillar on a listener
|
||||
policies = listener.setdefault('policies', [])
|
||||
policies_pillar = listener.get('policies_from_pillar', None)
|
||||
if not policies and policies_pillar is None:
|
||||
policies_pillar = DEFAULT_PILLAR_LISTENER_POLICY_KEY
|
||||
if policies_pillar:
|
||||
policies += __salt__['pillar.get'](policies_pillar, {}).get(listener['elb_protocol'], [])
|
||||
|
||||
if subnets:
|
||||
vpc_id = __salt__['boto_vpc.get_subnet_association'](
|
||||
subnets, region, key, keyid, profile
|
||||
|
@ -493,7 +523,7 @@ def _elb_present(
|
|||
ret['result'] = None
|
||||
return ret
|
||||
created = __salt__['boto_elb.create'](name, availability_zones,
|
||||
_listeners, subnets,
|
||||
listeners, subnets,
|
||||
security_groups, scheme, region,
|
||||
key, keyid, profile)
|
||||
if created:
|
||||
|
@ -514,7 +544,7 @@ def _elb_present(
|
|||
ret['result'] = _ret['result']
|
||||
if ret['result'] is False:
|
||||
return ret
|
||||
_ret = _listeners_present(name, _listeners, region, key, keyid,
|
||||
_ret = _listeners_present(name, listeners, region, key, keyid,
|
||||
profile)
|
||||
ret['changes'] = dictupdate.update(ret['changes'], _ret['changes'])
|
||||
ret['comment'] = ' '.join([ret['comment'], _ret['comment']])
|
||||
|
@ -557,45 +587,75 @@ def _listeners_present(
|
|||
return ret
|
||||
if not listeners:
|
||||
listeners = []
|
||||
|
||||
expected_listeners_by_tuple = {}
|
||||
for l in listeners:
|
||||
key = __salt__['boto_elb.listener_dict_to_tuple'](l)
|
||||
expected_listeners_by_tuple[key] = l
|
||||
actual_listeners_by_tuple = {}
|
||||
for l in lb['listeners']:
|
||||
key = __salt__['boto_elb.listener_dict_to_tuple'](l)
|
||||
actual_listeners_by_tuple[key] = l
|
||||
|
||||
to_delete = []
|
||||
to_create = []
|
||||
for listener in listeners:
|
||||
if listener not in lb['listeners']:
|
||||
to_create.append(listener)
|
||||
for listener in lb['listeners']:
|
||||
if listener not in listeners:
|
||||
to_delete.append(listener[0])
|
||||
if to_create or to_delete:
|
||||
if __opts__['test']:
|
||||
msg = 'ELB {0} set to have listeners modified.'.format(name)
|
||||
|
||||
for t, l in expected_listeners_by_tuple.iteritems():
|
||||
if t not in actual_listeners_by_tuple:
|
||||
to_create.append(l)
|
||||
for t, l in actual_listeners_by_tuple.iteritems():
|
||||
if t not in expected_listeners_by_tuple:
|
||||
to_delete.append(l)
|
||||
|
||||
if __opts__['test']:
|
||||
msg = []
|
||||
if to_create or to_delete:
|
||||
msg.append('ELB {0} set to have listeners modified:'.format(name))
|
||||
for listener in to_create:
|
||||
msg.append('Listener {} added.'.format(
|
||||
__salt__['boto_elb.listener_dict_to_tuple'](listener)))
|
||||
for listener in to_delete:
|
||||
msg.append('Listener {} deleted.'.format(
|
||||
__salt__['boto_elb.listener_dict_to_tuple'](listener)))
|
||||
else:
|
||||
msg.append('Listeners already set on ELB {0}.'.format(name))
|
||||
ret['comment'] = ' '.join(msg)
|
||||
ret['result'] = None
|
||||
return ret
|
||||
|
||||
if to_delete:
|
||||
ports = [l['elb_port'] for l in to_delete]
|
||||
deleted = __salt__['boto_elb.delete_listeners'](name, ports,
|
||||
region, key, keyid,
|
||||
profile)
|
||||
if deleted:
|
||||
ret['comment'] = 'Deleted listeners on {0} ELB.'.format(name)
|
||||
else:
|
||||
msg = 'Failed to delete listeners on {0} ELB.'.format(name)
|
||||
ret['comment'] = msg
|
||||
ret['result'] = None
|
||||
return ret
|
||||
if to_delete:
|
||||
deleted = __salt__['boto_elb.delete_listeners'](name, to_delete,
|
||||
region, key, keyid,
|
||||
profile)
|
||||
if deleted:
|
||||
ret['comment'] = 'Deleted listeners on {0} ELB.'.format(name)
|
||||
else:
|
||||
msg = 'Failed to delete listeners on {0} ELB.'.format(name)
|
||||
ret['comment'] = msg
|
||||
ret['result'] = False
|
||||
if to_create:
|
||||
created = __salt__['boto_elb.create_listeners'](name, to_create,
|
||||
region, key, keyid,
|
||||
profile)
|
||||
if created:
|
||||
msg = 'Created listeners on {0} ELB.'
|
||||
ret['comment'] = ' '.join([ret['comment'], msg.format(name)])
|
||||
else:
|
||||
msg = 'Failed to create listeners on {0} ELB.'
|
||||
ret['comment'] = ' '.join([ret['comment'], msg.format(name)])
|
||||
ret['result'] = False
|
||||
ret['changes']['old'] = {'listeners': lb['listeners']}
|
||||
ret['result'] = False
|
||||
|
||||
if to_create:
|
||||
created = __salt__['boto_elb.create_listeners'](name, to_create,
|
||||
region, key, keyid,
|
||||
profile)
|
||||
if created:
|
||||
msg = 'Created listeners on {0} ELB.'
|
||||
ret['comment'] = ' '.join([ret['comment'], msg.format(name)])
|
||||
else:
|
||||
msg = 'Failed to create listeners on {0} ELB.'
|
||||
ret['comment'] = ' '.join([ret['comment'], msg.format(name)])
|
||||
ret['result'] = False
|
||||
|
||||
if to_create or to_delete:
|
||||
ret['changes']['listeners'] = {}
|
||||
ret['changes']['listeners']['old'] = lb['listeners']
|
||||
lb = __salt__['boto_elb.get_elb_config'](name, region, key, keyid,
|
||||
profile)
|
||||
ret['changes']['new'] = {'listeners': lb['listeners']}
|
||||
ret['changes']['listeners']['new'] = lb['listeners']
|
||||
else:
|
||||
ret['comment'] = 'Listeners already set on ELB {0}.'.format(name)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
|
@ -919,6 +979,202 @@ def _alarms_present(name, alarms, alarms_from_pillar, region, key, keyid, profil
|
|||
return merged_return_value
|
||||
|
||||
|
||||
def _policies_present(
|
||||
name,
|
||||
policies,
|
||||
policies_from_pillar,
|
||||
listeners,
|
||||
region,
|
||||
key,
|
||||
keyid,
|
||||
profile):
|
||||
'''helper method for present. ensure that ELB policies are set'''
|
||||
if policies is None:
|
||||
policies = []
|
||||
pillar_policies = __salt__['config.option'](policies_from_pillar, [])
|
||||
policies = policies + pillar_policies
|
||||
|
||||
# check for policy name uniqueness and correct type
|
||||
policy_names = set()
|
||||
for p in policies:
|
||||
if 'policy_name' not in p:
|
||||
raise SaltInvocationError('policy_name is a required value for '
|
||||
'policies.')
|
||||
if 'policy_type' not in p:
|
||||
raise SaltInvocationError('policy_type is a required value for '
|
||||
'policies.')
|
||||
if 'policy' not in p:
|
||||
raise SaltInvocationError('policy is a required value for '
|
||||
'listeners.')
|
||||
# check for unique policy names
|
||||
if p['policy_name'] in policy_names:
|
||||
raise SaltInvocationError('Policy names must be unique: policy {}'
|
||||
' is declared twice.'.format(p['policy_name']))
|
||||
policy_names.add(p['policy_name'])
|
||||
|
||||
# check that listeners refer to valid policy names
|
||||
for l in listeners:
|
||||
for p in l.get('policies', []):
|
||||
if p not in policy_names:
|
||||
raise SaltInvocationError('Listener {} on ELB {} refers to '
|
||||
'undefined policy {}.'.format(l['elb_port'], name, p))
|
||||
|
||||
ret = {'result': True, 'comment': '', 'changes': {}}
|
||||
|
||||
lb = __salt__['boto_elb.get_elb_config'](name, region, key, keyid, profile)
|
||||
if not lb:
|
||||
msg = '{} ELB configuration could not be retrieved.'.format(name)
|
||||
ret['comment'] = msg
|
||||
ret['result'] = False
|
||||
return ret
|
||||
|
||||
# Policies have two names:
|
||||
# - a short name ('name') that's only the policy name (e.g. testpolicy)
|
||||
# - a canonical name ('cname') that contains the policy type and hash
|
||||
# (e.g. SSLNegotiationPolicy-testpolicy-14b32f668639cc8ea1391e062af98524)
|
||||
|
||||
policies_by_cname = {_policy_cname(p): p for p in policies}
|
||||
cnames_by_name = {p['policy_name']: _policy_cname(p) for p in policies}
|
||||
|
||||
expected_policy_names = policies_by_cname.keys()
|
||||
actual_policy_names = lb['policies']
|
||||
|
||||
# This is sadly a huge hack to get around the fact that AWS assigns a
|
||||
# default SSLNegotiationPolicyType policy (with the naming scheme
|
||||
# ELBSecurityPolicy-YYYY-MM) to all ELBs terminating SSL without an
|
||||
# explicit policy set. If we don't keep track of the default policies and
|
||||
# explicitly exclude them from deletion, orchestration will fail because we
|
||||
# attempt to delete the default policy that's being used by listeners that
|
||||
# were created with no explicit policy.
|
||||
default_aws_policies = set()
|
||||
|
||||
expected_policies_by_listener = {}
|
||||
for l in listeners:
|
||||
expected_policies_by_listener[l['elb_port']] = set(
|
||||
[cnames_by_name[p] for p in l.get('policies', [])])
|
||||
|
||||
actual_policies_by_listener = {}
|
||||
for l in lb['listeners']:
|
||||
listener_policies = set(l.get('policies', []))
|
||||
actual_policies_by_listener[l['elb_port']] = listener_policies
|
||||
# Determine if any actual listener policies look like default policies,
|
||||
# so we can exclude them from deletion below (see note about this hack
|
||||
# above).
|
||||
for p in listener_policies:
|
||||
if re.match(r'^ELBSecurityPolicy-\d{4}-\d{2}$', p):
|
||||
default_aws_policies.add(p)
|
||||
|
||||
to_delete = []
|
||||
to_create = []
|
||||
|
||||
for policy_name in expected_policy_names:
|
||||
if policy_name not in actual_policy_names:
|
||||
to_create.append(policy_name)
|
||||
for policy_name in actual_policy_names:
|
||||
if policy_name not in expected_policy_names:
|
||||
if policy_name not in default_aws_policies:
|
||||
to_delete.append(policy_name)
|
||||
|
||||
listeners_to_update = set()
|
||||
for port, policies in expected_policies_by_listener.iteritems():
|
||||
if policies != actual_policies_by_listener.get(port, set()):
|
||||
listeners_to_update.add(port)
|
||||
for port, policies in actual_policies_by_listener.iteritems():
|
||||
if policies != expected_policies_by_listener.get(port, set()):
|
||||
listeners_to_update.add(port)
|
||||
|
||||
if __opts__['test']:
|
||||
msg = []
|
||||
if to_create or to_delete:
|
||||
msg.append('ELB {0} set to have policies modified:'.format(name))
|
||||
for policy in to_create:
|
||||
msg.append('Policy {} added.'.format(policy))
|
||||
for policy in to_delete:
|
||||
msg.append('Policy {} deleted.'.format(policy))
|
||||
for listener in listeners_to_update:
|
||||
msg.append('Listener {} policies updated.'.format(listener))
|
||||
else:
|
||||
msg.append('Policies already set on ELB {0}.'.format(name))
|
||||
ret['comment'] = ' '.join(msg)
|
||||
ret['result'] = None
|
||||
return ret
|
||||
|
||||
if to_create:
|
||||
for policy_name in to_create:
|
||||
created = __salt__['boto_elb.create_policy'](
|
||||
name=name,
|
||||
policy_name=policy_name,
|
||||
policy_type=policies_by_cname[policy_name]['policy_type'],
|
||||
policy=policies_by_cname[policy_name]['policy'],
|
||||
region=region,
|
||||
key=key,
|
||||
keyid=keyid,
|
||||
profile=profile)
|
||||
if created:
|
||||
ret['changes'].setdefault(policy_name, {})['new'] = policy_name
|
||||
comment = "Policy {} was created on ELB {}".format(
|
||||
policy_name, name)
|
||||
ret['comment'] = ' '.join([ret['comment'], comment])
|
||||
ret['result'] = True
|
||||
else:
|
||||
ret['result'] = False
|
||||
return ret
|
||||
|
||||
for port in listeners_to_update:
|
||||
policy_set = __salt__['boto_elb.set_listener_policy'](
|
||||
name=name,
|
||||
port=port,
|
||||
policies=list(expected_policies_by_listener.get(port, [])),
|
||||
region=region,
|
||||
key=key,
|
||||
keyid=keyid,
|
||||
profile=profile)
|
||||
if policy_set:
|
||||
policy_key = 'listener_{}_policy'.format(port)
|
||||
ret['changes'][policy_key] = {
|
||||
'old': list(actual_policies_by_listener.get(port, [])),
|
||||
'new': list(expected_policies_by_listener.get(port, [])),
|
||||
}
|
||||
comment = "Policy {} was created on ELB {} listener {}".format(
|
||||
expected_policies_by_listener[port], name, port)
|
||||
ret['comment'] = ' '.join([ret['comment'], comment])
|
||||
ret['result'] = True
|
||||
else:
|
||||
ret['result'] = False
|
||||
return ret
|
||||
|
||||
if to_delete:
|
||||
for policy_name in to_delete:
|
||||
deleted = __salt__['boto_elb.delete_policy'](
|
||||
name=name,
|
||||
policy_name=policy_name,
|
||||
region=region,
|
||||
key=key,
|
||||
keyid=keyid,
|
||||
profile=profile)
|
||||
if deleted:
|
||||
ret['changes'].setdefault(policy_name, {})['old'] = policy_name
|
||||
comment = "Policy {} was deleted from ELB {}".format(
|
||||
policy_name, name)
|
||||
ret['comment'] = ' '.join([ret['comment'], comment])
|
||||
ret['result'] = True
|
||||
else:
|
||||
ret['result'] = False
|
||||
return ret
|
||||
return ret
|
||||
|
||||
|
||||
def _policy_cname(policy_dict):
|
||||
policy_name = policy_dict['policy_name']
|
||||
policy_type = policy_dict['policy_type']
|
||||
policy = policy_dict['policy']
|
||||
canonical_policy_repr = str(sorted(list(policy.iteritems()), key=lambda x: str(x[0])))
|
||||
policy_hash = hashlib.md5(str(canonical_policy_repr)).hexdigest()
|
||||
if policy_type.endswith('Type'):
|
||||
policy_type = policy_type[:-4]
|
||||
return "{}-{}-{}".format(policy_type, policy_name, policy_hash)
|
||||
|
||||
|
||||
def absent(
|
||||
name,
|
||||
region=None,
|
||||
|
|
Loading…
Add table
Reference in a new issue