mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge pull request #24199 from lyft/route53-fix-elb
Various fixes for boto_route53 and boto_elb
This commit is contained in:
commit
ce8e43b774
3 changed files with 114 additions and 167 deletions
|
@ -71,6 +71,14 @@ def _is_valid_resource(_type):
|
|||
return False
|
||||
|
||||
|
||||
def _encode_name(name):
|
||||
return name.replace('*', r'\052')
|
||||
|
||||
|
||||
def _decode_name(name):
|
||||
return name.replace(r'\052', '*')
|
||||
|
||||
|
||||
def get_record(name, zone, record_type, fetch_all=False, region=None, key=None,
|
||||
keyid=None, profile=None):
|
||||
'''
|
||||
|
@ -94,6 +102,7 @@ def get_record(name, zone, record_type, fetch_all=False, region=None, key=None,
|
|||
if not _is_valid_resource(_type):
|
||||
return None
|
||||
|
||||
name = _encode_name(name)
|
||||
if _type == 'A':
|
||||
_record = _zone.get_a(name, fetch_all)
|
||||
elif _type == 'CNAME':
|
||||
|
@ -102,7 +111,7 @@ def get_record(name, zone, record_type, fetch_all=False, region=None, key=None,
|
|||
_record = _zone.get_mx(name, fetch_all)
|
||||
|
||||
if _record:
|
||||
ret['name'] = _record.name
|
||||
ret['name'] = _decode_name(_record.name)
|
||||
ret['value'] = _record.to_print()
|
||||
ret['record_type'] = _record.type
|
||||
ret['ttl'] = _record.ttl
|
||||
|
|
|
@ -317,13 +317,31 @@ def present(
|
|||
ret['result'] = _ret['result']
|
||||
if ret['result'] is False:
|
||||
return ret
|
||||
_ret = _cnames_present(name, cnames, 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
|
||||
if cnames:
|
||||
lb = __salt__['boto_elb.get_elb_config'](
|
||||
name, region, key, keyid, profile
|
||||
)
|
||||
for cname in cnames:
|
||||
_ret = __salt__['state.single'](
|
||||
'boto_route53.present',
|
||||
name=cname.get('name'),
|
||||
value=lb['dns_name'],
|
||||
zone=cname.get('zone'),
|
||||
record_type='CNAME',
|
||||
identifier=cname.get('identifier', None),
|
||||
ttl=cname.get('ttl', None),
|
||||
region=region,
|
||||
key=key,
|
||||
keyid=keyid,
|
||||
profile=profile
|
||||
)
|
||||
_ret = _ret.values()[0]
|
||||
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 = _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']])
|
||||
|
@ -741,108 +759,6 @@ def _subnets_present(
|
|||
return ret
|
||||
|
||||
|
||||
def _cnames_present(
|
||||
name,
|
||||
cnames,
|
||||
region,
|
||||
key,
|
||||
keyid,
|
||||
profile):
|
||||
ret = {'result': True, 'comment': '', 'changes': {}}
|
||||
if not cnames:
|
||||
cnames = []
|
||||
lb = __salt__['boto_elb.get_elb_config'](name, region, key, keyid, profile)
|
||||
if not lb:
|
||||
if not __opts__['test']:
|
||||
ret['result'] = False
|
||||
msg = 'Failed to retrieve ELB {0}.'.format(name)
|
||||
ret['comment'] = msg
|
||||
return ret
|
||||
to_create = []
|
||||
to_update = []
|
||||
for cname in cnames:
|
||||
_name = cname.get('name', None)
|
||||
_zone = cname.get('zone', None)
|
||||
if not _name or not _zone:
|
||||
raise SaltInvocationError('cnames must provide name and zone'
|
||||
' attributes.')
|
||||
record = __salt__['boto_route53.get_record'](_name, _zone, 'CNAME',
|
||||
False, region, key,
|
||||
keyid, profile)
|
||||
if not record:
|
||||
to_create.append(cname)
|
||||
elif record['value'].rstrip('.') != lb['dns_name'].rstrip('.'):
|
||||
to_update.append(cname)
|
||||
if to_create or to_update:
|
||||
if __opts__['test']:
|
||||
msg = 'ELB {0} to have cnames modified.'.format(name)
|
||||
ret['comment'] = msg
|
||||
ret['result'] = None
|
||||
return ret
|
||||
if to_create:
|
||||
created = []
|
||||
not_created = []
|
||||
for cname in to_create:
|
||||
_name = cname.get('name')
|
||||
_zone = cname.get('zone')
|
||||
_iden = cname.get('identifier', None)
|
||||
_ttl = cname.get('ttl', None)
|
||||
_created = __salt__['boto_route53.add_record'](
|
||||
_name, lb['dns_name'], _zone, 'CNAME', _iden, _ttl, region,
|
||||
key, keyid, profile)
|
||||
if _created:
|
||||
created.append(_name)
|
||||
else:
|
||||
not_created.append(_name)
|
||||
if created:
|
||||
msg = 'Created cnames {0}.'.format(','.join(created))
|
||||
ret['comment'] = msg
|
||||
if not_created:
|
||||
msg = 'Failed to create cnames {0}.'
|
||||
msg = msg.format(','.join(not_created))
|
||||
if 'comment' in ret:
|
||||
ret['comment'] = ret['comment'] + ' ' + msg
|
||||
else:
|
||||
ret['comment'] = msg
|
||||
ret['result'] = False
|
||||
if to_update:
|
||||
updated = []
|
||||
not_updated = []
|
||||
for cname in to_update:
|
||||
_name = cname.get('name')
|
||||
_zone = cname.get('zone')
|
||||
_iden = cname.get('identifier', None)
|
||||
_ttl = cname.get('ttl', None)
|
||||
_updated = __salt__['boto_route53.update_record'](
|
||||
_name, lb['dns_name'], _zone, 'CNAME', _iden, _ttl, region,
|
||||
key, keyid, profile)
|
||||
if _updated:
|
||||
updated.append(_name)
|
||||
else:
|
||||
not_updated.append(_name)
|
||||
if updated:
|
||||
msg = 'Updated cnames {0}.'.format(','.join(updated))
|
||||
if 'comment' in ret:
|
||||
ret['comment'] = ret['comment'] + ' ' + msg
|
||||
else:
|
||||
ret['comment'] = msg
|
||||
if not_updated:
|
||||
msg = 'Failed to update cnames {0}.'
|
||||
msg = msg.format(','.join(not_updated))
|
||||
if 'comment' in ret:
|
||||
ret['comment'] = ret['comment'] + ' ' + msg
|
||||
else:
|
||||
ret['comment'] = msg
|
||||
ret['result'] = False
|
||||
# We can't track old, since we'd need to know the zone to
|
||||
# search for the ELB in the value.
|
||||
ret['changes']['new'] = {'cnames': to_create + to_update}
|
||||
else:
|
||||
msg = 'cnames already set on ELB {0}.'.format(name)
|
||||
ret['comment'] = msg
|
||||
return ret
|
||||
|
||||
|
||||
def _alarms_present(name, alarms, alarms_from_pillar, region, key, keyid, profile):
|
||||
'''helper method for present. ensure that cloudwatch_alarms are set'''
|
||||
# load data from alarms_from_pillar
|
||||
|
@ -870,7 +786,7 @@ def _alarms_present(name, alarms, alarms_from_pillar, region, key, keyid, profil
|
|||
ret = __salt__["state.single"]('boto_cloudwatch_alarm.present', **kwargs)
|
||||
results = ret.values()[0]
|
||||
if not results["result"]:
|
||||
merged_return_value["result"] = False
|
||||
merged_return_value["result"] = results["result"]
|
||||
if results.get("changes", {}) != {}:
|
||||
merged_return_value["changes"][info["name"]] = results["changes"]
|
||||
if "comment" in results:
|
||||
|
|
|
@ -39,78 +39,100 @@ class BotoElbTestCase(TestCase):
|
|||
name = 'myelb'
|
||||
listeners = [{'elb_port': 'ELBPORT', 'instance_port': 'PORT',
|
||||
'elb_protocol': 'HTTPS', 'certificate': 'A'}]
|
||||
attributes = {'alarm_actions': ['arn:aws:sns:us-east-1:12345:myalarm'],
|
||||
'insufficient_data_actions': [],
|
||||
'ok_actions': ['arn:aws:sns:us-east-1:12345:myalarm']}
|
||||
alarms = {'MyAlarm': {'name': name,
|
||||
'attributes': {'description': 'A'}}}
|
||||
attrs = {'alarm_actions': ['arn:aws:sns:us-east-1:12345:myalarm'],
|
||||
'insufficient_data_actions': [],
|
||||
'ok_actions': ['arn:aws:sns:us-east-1:12345:myalarm']}
|
||||
health_check = {'target:': 'HTTP:80/'}
|
||||
avail_zones = ['us-east-1a', 'us-east-1c', 'us-east-1d']
|
||||
alarms = {'alarm_actions': {'name': name,
|
||||
'attributes': {'description': 'A'}}}
|
||||
cnames = [{'name': 'www.test.com', 'zone': 'test.com', 'ttl': 60}]
|
||||
|
||||
ret = {'name': name,
|
||||
'result': False,
|
||||
'result': True,
|
||||
'changes': {},
|
||||
'comment': ''}
|
||||
ret1 = copy.deepcopy(ret)
|
||||
|
||||
mock = MagicMock(return_value={})
|
||||
mock_bool = MagicMock(return_value=False)
|
||||
with patch.dict(boto_elb.__salt__,
|
||||
{'config.option': mock,
|
||||
'boto_elb.exists': mock_bool,
|
||||
'boto_elb.create': mock_bool,
|
||||
'boto_elb.get_attributes': mock}):
|
||||
with patch.dict(boto_elb.__opts__, {'test': False}):
|
||||
comt = (' Failed to create myelb ELB.')
|
||||
ret.update({'comment': comt})
|
||||
self.assertDictEqual(boto_elb.present
|
||||
(name, listeners, attributes=attributes,
|
||||
availability_zones=avail_zones), ret)
|
||||
mock_false_bool = MagicMock(return_value=False)
|
||||
mock_true_bool = MagicMock(return_value=True)
|
||||
mock_attributes = MagicMock(return_value=attrs)
|
||||
mock_health_check = MagicMock(return_value=health_check)
|
||||
mock_ret = MagicMock(return_value={'myelb': ret1})
|
||||
|
||||
mock = MagicMock(return_value={})
|
||||
mock_ret = MagicMock(return_value={'result': {'result': False}})
|
||||
comt1 = (' Failed to retrieve health_check for ELB myelb.')
|
||||
with patch.dict(boto_elb.__salt__,
|
||||
{'config.option': mock,
|
||||
'boto_elb.get_attributes': mock,
|
||||
'boto_elb.get_health_check': mock,
|
||||
'boto_elb.exists': mock_false_bool,
|
||||
'boto_elb.create': mock_false_bool}):
|
||||
with patch.dict(boto_elb.__opts__, {'test': False}):
|
||||
ret = boto_elb.present(
|
||||
name,
|
||||
listeners,
|
||||
availability_zones=avail_zones
|
||||
)
|
||||
self.assertTrue(boto_elb.__salt__['boto_elb.exists'].called)
|
||||
self.assertTrue(boto_elb.__salt__['boto_elb.create'].called)
|
||||
self.assertIn('Failed to create myelb ELB.', ret['comment'])
|
||||
self.assertFalse(ret['result'])
|
||||
|
||||
mock = MagicMock(return_value={})
|
||||
mock_ret = MagicMock(return_value={'myelb': ret1})
|
||||
with patch.dict(boto_elb.__salt__,
|
||||
{'config.option': mock,
|
||||
'boto_elb.exists': mock_false_bool,
|
||||
'boto_elb.create': mock_true_bool,
|
||||
'boto_elb.get_attributes': mock_attributes,
|
||||
'boto_elb.get_health_check': mock_health_check,
|
||||
'boto_elb.get_elb_config': mock,
|
||||
'state.single': mock_ret}):
|
||||
with patch.dict(boto_elb.__opts__, {'test': False}):
|
||||
ret1.update({'result': True})
|
||||
mock_elb_present = MagicMock(return_value=ret1)
|
||||
with patch.object(boto_elb, '_elb_present', mock_elb_present):
|
||||
comt = (' Failed to retrieve attributes for ELB myelb.')
|
||||
ret.update({'comment': comt})
|
||||
self.assertDictEqual(boto_elb.present
|
||||
(name, listeners), ret)
|
||||
ret = boto_elb.present(
|
||||
name,
|
||||
listeners,
|
||||
availability_zones=avail_zones,
|
||||
health_check=health_check,
|
||||
alarms=alarms
|
||||
)
|
||||
self.assertTrue(boto_elb.__salt__['boto_elb.exists'].called)
|
||||
self.assertTrue(boto_elb.__salt__['boto_elb.create'].called)
|
||||
self.assertTrue(boto_elb.__salt__['state.single'].called)
|
||||
self.assertTrue(
|
||||
boto_elb.__salt__['boto_elb.get_attributes'].called
|
||||
)
|
||||
self.assertTrue(
|
||||
boto_elb.__salt__['boto_elb.get_health_check'].called
|
||||
)
|
||||
self.assertIn('ELB myelb created.', ret['comment'])
|
||||
self.assertTrue(ret['result'])
|
||||
|
||||
with patch.object(boto_elb, '_attributes_present',
|
||||
mock_elb_present):
|
||||
ret.update({'comment': comt1})
|
||||
self.assertDictEqual(boto_elb.present
|
||||
(name, listeners), ret)
|
||||
|
||||
with patch.object(boto_elb, '_health_check_present',
|
||||
mock_elb_present):
|
||||
comt = (' Failed to retrieve ELB myelb.')
|
||||
ret.update({'comment': comt})
|
||||
self.assertDictEqual(boto_elb.present
|
||||
(name, listeners), ret)
|
||||
|
||||
with patch.object(boto_elb, '_cnames_present',
|
||||
mock_elb_present):
|
||||
comt = (' ')
|
||||
ret.update({'comment': comt})
|
||||
self.assertDictEqual(boto_elb.present
|
||||
(name, listeners,
|
||||
alarms=alarms), ret)
|
||||
|
||||
with patch.object(boto_elb, '_alarms_present',
|
||||
mock_elb_present):
|
||||
ret.update({'result': True})
|
||||
self.assertDictEqual(boto_elb.present
|
||||
(name, listeners,
|
||||
alarms=alarms), ret)
|
||||
mock = MagicMock(return_value={})
|
||||
mock_elb = MagicMock(return_value={'dns_name': 'myelb.amazon.com'})
|
||||
mock_ret = MagicMock(return_value={'myelb': ret1})
|
||||
with patch.dict(boto_elb.__salt__,
|
||||
{'config.option': mock,
|
||||
'boto_elb.exists': mock_false_bool,
|
||||
'boto_elb.create': mock_true_bool,
|
||||
'boto_elb.get_attributes': mock_attributes,
|
||||
'boto_elb.get_health_check': mock_health_check,
|
||||
'boto_elb.get_elb_config': mock_elb,
|
||||
'state.single': mock_ret}):
|
||||
with patch.dict(boto_elb.__opts__, {'test': False}):
|
||||
ret = boto_elb.present(
|
||||
name,
|
||||
listeners,
|
||||
availability_zones=avail_zones,
|
||||
health_check=health_check,
|
||||
cnames=cnames
|
||||
)
|
||||
self.assertTrue(boto_elb.__salt__['state.single'].called)
|
||||
cname_call = boto_elb.__salt__['state.single'].mock_calls[0]
|
||||
self.assertEqual(
|
||||
cname_call[1][0],
|
||||
'boto_route53.present'
|
||||
)
|
||||
self.assertTrue(ret['result'])
|
||||
|
||||
# 'absent' function tests: 1
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue