Merge pull request #40263 from deuscapturus/boto_elbv2

Add boto_elbv2 states and modules for de/registering targets and chec…
This commit is contained in:
Mike Place 2017-03-28 11:15:38 -06:00 committed by GitHub
commit 9d11993f38
2 changed files with 395 additions and 0 deletions

200
salt/modules/boto_elbv2.py Normal file
View File

@ -0,0 +1,200 @@
# -*- coding: utf-8 -*-
'''
Connection module for Amazon ALB
.. versionadded:: TBD
:configuration: This module accepts explicit elb credentials but can also utilize
IAM roles assigned to the instance through Instance Profiles. Dynamic
credentials are then automatically obtained from AWS API and no further
configuration is necessary. More Information available at:
.. code-block:: text
http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html
If IAM roles are not used you need to specify them either in a pillar or
in the minion's config file:
.. code-block:: yaml
elbv2.keyid: GKTADJGHEIQSXMKKRBJ08H
elbv2.key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs
elbv2.region: us-west-2
If a region is not specified, the default is us-east-1.
It's also possible to specify key, keyid and region via a profile, either
as a passed in dict, or as a string to pull from pillars or minion config:
.. code-block:: yaml
myprofile:
keyid: GKTADJGHEIQSXMKKRBJ08H
key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs
region: us-east-1
'''
# keep lint from choking on _get_conn and _cache_id
# pylint: disable=E0602
from __future__ import absolute_import
# Import Python libs
import logging
log = logging.getLogger(__name__)
# Import Salt libs
# Import third party libs
import salt.ext.six as six
try:
# pylint: disable=unused-import
import salt.utils.boto3
# pylint: enable=unused-import
# TODO Version check using salt.utils.versions
from botocore.exceptions import ClientError
logging.getLogger('boto3').setLevel(logging.CRITICAL)
HAS_BOTO = True
except ImportError:
HAS_BOTO = False
def __virtual__():
'''
Only load if boto3 libraries exist.
'''
if not HAS_BOTO:
return (False, "The boto_elbv2 module cannot be loaded: boto3 library not found")
__utils__['boto3.assign_funcs'](__name__, 'elbv2')
return True
def target_group_exists(name, region=None, key=None, keyid=None, profile=None):
'''
Check to see if an target group exists.
CLI example:
.. code-block:: bash
salt myminion boto_elbv2.exists arn:aws:elasticloadbalancing:us-west-2:644138682826:targetgroup/learn1give1-api/414788a16b5cf163
'''
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
try:
alb = conn.describe_target_groups(TargetGroupArns=[name])
if alb:
return True
else:
log.warning('The target group does not exist in region {0}'.format(region))
return False
except ClientError as error:
log.warning(error)
return False
def describe_target_health(name, targets=None, region=None, key=None, keyid=None, profile=None):
'''
Get the curret health check status for targets in a target group.
CLI example:
.. code-block:: bash
salt myminion boto_elbv2.describe_target_health arn:aws:elasticloadbalancing:us-west-2:644138682826:targetgroup/learn1give1-api/414788a16b5cf163 targets=["i-isdf23ifjf"]
'''
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
try:
if targets:
targetsdict = []
for target in targets:
targetsdict.append({"Id": target})
instances = conn.describe_target_health(TargetGroupArn=name, Targets=targetsdict)
else:
instances = conn.describe_target_health(TargetGroupArn=name)
ret = {}
for instance in instances['TargetHealthDescriptions']:
ret.update({instance['Target']['Id']: instance['TargetHealth']['State']})
return ret
except ClientError as error:
log.warning(error)
return {}
def register_targets(name, targets, region=None, key=None, keyid=None,
profile=None):
'''
Register targets to a target froup of an ALB. ``targets`` is either a
instance id string or a list of instance id's.
Returns:
- ``True``: instance(s) registered successfully
- ``False``: instance(s) failed to be registered
CLI example:
.. code-block:: bash
salt myminion boto_elbv2.register_targets myelb instance_id
salt myminion boto_elbv2.register_targets myelb "[instance_id,instance_id]"
'''
targetsdict = []
if isinstance(targets, str) or isinstance(targets, six.text_type):
targetsdict.append({"Id": targets})
else:
for target in targets:
targetsdict.append({"Id": target})
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
try:
registered_targets = conn.register_targets(TargetGroupArn=name, Targets=targetsdict)
if registered_targets:
return True
else:
return False
except ClientError as error:
log.warning(error)
return False
def deregister_targets(name, targets, region=None, key=None, keyid=None,
profile=None):
'''
Deregister targets to a target froup of an ALB. ``targets`` is either a
instance id string or a list of instance id's.
Returns:
- ``True``: instance(s) deregistered successfully
- ``False``: instance(s) failed to be deregistered
CLI example:
.. code-block:: bash
salt myminion boto_elbv2.deregister_targets myelb instance_id
salt myminion boto_elbv2.deregister_targets myelb "[instance_id,instance_id]"
'''
targetsdict = []
if isinstance(targets, str) or isinstance(targets, six.text_type):
targetsdict.append({"Id": targets})
else:
for target in targets:
targetsdict.append({"Id": target})
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
try:
registered_targets = conn.deregister_targets(TargetGroupArn=name, Targets=targetsdict)
if registered_targets:
return True
else:
return False
except ClientError as error:
log.warning(error)
return False

195
salt/states/boto_elbv2.py Normal file
View File

@ -0,0 +1,195 @@
# -*- coding: utf-8 -*-
'''
Manage AWS Application Load Balancer
.. versionadded:: TBD
Add and remove targets from an ALB target group.
This module uses ``boto3``, which can be installed via package, or pip.
This module accepts explicit alb credentials but can also utilize
IAM roles assigned to the instance through Instance Profiles. Dynamic
credentials are then automatically obtained from AWS API and no further
configuration is necessary. More information available `here
<http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html>`_.
If IAM roles are not used you need to specify them either in a pillar file or
in the minion's config file:
.. code-block:: yaml
elbv2.keyid: GKTADJGHEIQSXMKKRBJ08H
elbv2.key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs
elbv2.region: us-west-2
It's also possible to specify ``key``, ``keyid`` and ``region`` via a profile, either
passed in as a dict, or as a string to pull from pillars or minion config:
.. code-block:: yaml
myprofile:
keyid: GKTADJGHEIQSXMKKRBJ08H
key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs
region: us-east-1
'''
from __future__ import absolute_import
# Import Python Libs
import logging
import copy
# Import Salt Libs
log = logging.getLogger(__name__)
def __virtual__():
'''
Only load if boto is available.
'''
return 'boto_elbv2' if 'boto_elbv2.target_group_exists' in __salt__ else False
def targets_registered(name, targets, region=None, key=None, keyid=None,
profile=None):
'''
Add targets to an Application Load Balancer target group. This state will not remove targets.
name
The ARN of the Application Load Balancer Target Group to add targets to.
targets
A list of target IDs or a string of a single target that this target group should
distribute traffic to.
.. versionadded:: TBD
.. code-block:: yaml
add-targets:
boto_elb.targets_registered:
- name: arn:myloadbalancer
- targets:
- instance-id1
- instance-id2
'''
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
tg = __salt__['boto_elbv2.target_group_exists'](name, region, key, keyid, profile)
if tg:
health = __salt__['boto_elbv2.describe_target_health'](name, region=region, key=key, keyid=keyid, profile=profile)
failure = False
changes = False
newhealth_mock = copy.copy(health)
if isinstance(targets, str):
targets = [targets]
for target in targets:
if target in health and health.get(target) != "draining":
ret['comment'] = ret['comment'] + 'Target/s {0} already registered and is {1}.\n'.format(target, health[target])
ret['result'] = True
else:
if __opts__['test']:
changes = True
newhealth_mock.update({target: "initial"})
else:
state = __salt__['boto_elbv2.register_targets'](name,
targets,
region,
key,
keyid,
profile)
if state:
changes = True
ret['result'] = True
else:
ret['comment'] = 'Target Group {0} failed to add targets'.format(name)
failure = True
if failure:
ret['result'] = False
if changes:
ret['changes']['old'] = health
if __opts__['test']:
ret['comment'] = 'Target Group {0} would be changed'.format(name)
ret['result'] = None
ret['changes']['new'] = newhealth_mock
else:
ret['comment'] = 'Target Group {0} has been changed'.format(name)
newhealth = __salt__['boto_elbv2.describe_target_health'](name, region=region, key=key, keyid=keyid, profile=profile)
ret['changes']['new'] = newhealth
return ret
else:
ret['comment'] = 'Could not find target group {0}'.format(name)
return ret
def targets_deregistered(name, targets, region=None, key=None, keyid=None,
profile=None):
'''
Remove targets to an Application Load Balancer target group.
name
The ARN of the Application Load Balancer Target Group to remove targets from.
targets
A list of target IDs or a string of a single target registered to the target group to be removed
.. versionadded:: Unknown
.. code-block:: yaml
remove-targets:
boto_elb.targets_deregistered:
- name: arn:myloadbalancer
- targets:
- instance-id1
- instance-id2
'''
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
tg = __salt__['boto_elbv2.target_group_exists'](name, region, key, keyid, profile)
if tg:
health = __salt__['boto_elbv2.describe_target_health'](name, region, key, keyid, profile)
failure = False
changes = False
newhealth_mock = copy.copy(health)
if isinstance(targets, str):
targets = [targets]
for target in targets:
if target not in health or health.get(target) == "draining":
ret['comment'] = ret['comment'] + 'Target/s {0} already deregistered\n'.format(target)
ret['result'] = True
else:
if __opts__['test']:
changes = True
newhealth_mock.update({target: "draining"})
else:
state = __salt__['boto_elbv2.deregister_targets'](name,
targets,
region,
key,
keyid,
profile)
if state:
changes = True
ret['result'] = True
else:
ret['comment'] = 'Target Group {0} failed to remove targets'.format(name)
failure = True
if failure:
ret['result'] = False
if changes:
ret['changes']['old'] = health
if __opts__['test']:
ret['comment'] = 'Target Group {0} would be changed'.format(name)
ret['result'] = None
ret['changes']['new'] = newhealth_mock
else:
ret['comment'] = 'Target Group {0} has been changed'.format(name)
newhealth = __salt__['boto_elbv2.describe_target_health'](name, region, key, keyid, profile)
ret['changes']['new'] = newhealth
return ret
else:
ret['comment'] = 'Could not find target group {0}'.format(name)
return ret