Автоматически устанавливать приоритет ListenerRule в шаблоне CloudFormation - PullRequest
0 голосов
/ 24 апреля 2018

У меня есть шаблон CloudFormation, который содержит Application Load Balancer ListenerRule.Одним из обязательных свойств ListenerRule является его приоритет (число от 1 до 50000).Приоритет каждого ListenerRule должен быть уникальным.

Мне нужно развернуть один и тот же шаблон несколько раз.Приоритет для ListenerRule должен меняться каждый раз, когда я запускаю шаблон.

На данный момент я превратил Приоритет в параметр, который можно установить при запуске стека, и это работает нормально.Есть ли способ, которым я могу автоматически установить приоритет ListenerRule на следующий доступный приоритет?

1 Ответ

0 голосов
/ 24 апреля 2018

Нет, в настоящее время невозможно автоматически выделить его, используя только ресурс AWS::ElasticLoadBalancingV2::ListenerRule. Однако это может быть достигнуто с помощью пользовательского ресурса.

Сначала давайте создадим реальный пользовательский код лямбда-ресурса.

allocate_alb_rule_priority.py:

import json
import os
import random
import uuid

import boto3
from botocore.vendored import requests

SUCCESS = "SUCCESS"
FAILED = "FAILED"
# Member must have value less than or equal to 50000
ALB_RULE_PRIORITY_RANGE = 1, 50000


def lambda_handler(event, context):
    try:
        _lambda_handler(event, context)
    except Exception as e:
        # Must raise, otherwise the Lambda will be marked as successful, and the exception
        # will not be logged to CloudWatch logs.
        # Always send a response otherwise custom resource creation/update/deletion will be stuck
        send(
            event,
            context,
            response_status=FAILED if event['RequestType'] != 'Delete' else SUCCESS,
            # Do not fail on delete to avoid rollback failure
            response_data=None,
            physical_resource_id=uuid.uuid4(),
            reason=e,
        )
        raise


def _lambda_handler(event, context):
    print("Received event: " + json.dumps(event, indent=2))

    physical_resource_id = event.get('PhysicalResourceId', str(uuid.uuid4()))
    response_data = {}

    if event['RequestType'] == 'Create':
        elbv2_client = boto3.client('elbv2')
        result = elbv2_client.describe_rules(ListenerArn=os.environ['ListenerArn'])

        in_use = list(filter(lambda s: s.isdecimal(), [r['Priority'] for r in result['Rules']]))

        priority = None
        while not priority or priority in in_use:
            priority = str(random.randint(*ALB_RULE_PRIORITY_RANGE))

        response_data = {
            'Priority': priority
        }

    send(event, context, SUCCESS, response_data, physical_resource_id)


def send(event, context, response_status, response_data, physical_resource_id, reason=None):
    response_url = event['ResponseURL']

    response_body = {
        'Status': response_status,
        'Reason': str(reason) if reason else 'See the details in CloudWatch Log Stream: ' + context.log_stream_name,
        'PhysicalResourceId': physical_resource_id,
        'StackId': event['StackId'],
        'RequestId': event['RequestId'],
        'LogicalResourceId': event['LogicalResourceId'],
        'Data': response_data,
    }

    json_response_body = json.dumps(response_body)

    headers = {
        'content-type': '',
        'content-length': str(len(json_response_body))
    }

    try:
        requests.put(
            response_url,
            data=json_response_body,
            headers=headers
        )
    except Exception as e:
        print("send(..) failed executing requests.put(..): " + str(e))

Согласно вашему вопросу, вам нужно создать несколько стеков с одним шаблоном. По этой причине я предлагаю использовать пользовательский ресурс в шаблоне, который развертывается только один раз. Затем другой шаблон импортирует его ServiceToken.

allocate_alb_rule_priority_custom_resouce.yml:

Resources:
  AllocateAlbRulePriorityCustomResourceLambdaRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Sid: ''
          Effect: Allow
          Principal:
            Service: lambda.amazonaws.com
          Action: sts:AssumeRole
      Path: /
      Policies:
      - PolicyName: DescribeRulesPolicy
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
          - Effect: Allow
            Action:
            - elasticloadbalancing:DescribeRules
            Resource: "*"
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

  AllocateAlbRulePriorityCustomResourceLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      Handler: allocate_alb_rule_priority.lambda_handler
      Role: !GetAtt AllocateAlbRulePriorityCustomResourceLambdaRole.Arn
      Code: allocate_alb_rule_priority.py
      Runtime: python3.6
      Timeout: '30'
      Environment:
        Variables:
          ListenerArn: !Ref LoadBalancerListener

Outputs:
  AllocateAlbRulePriorityCustomResourceLambdaArn:
    Value: !GetAtt AllocateAlbRulePriorityCustomResourceLambdaFunction.Arn
    Export:
      Name: AllocateAlbRulePriorityCustomResourceLambdaArn

Вы можете заметить, что мы передаем ListenerArn в функцию Lambda. Это потому, что мы хотим избежать коллизии приоритетов при новом распределении.

Наконец, теперь мы можем использовать наш новый пользовательский ресурс в шаблоне, который должен быть развернут несколько раз.

template_meant_to_be_deployed_multiple_times.yml

  AllocateAlbRulePriorityCustomResource:
    Type: Custom::AllocateAlbRulePriority
    Condition: AutoAllocateAlbPriority
    Properties:
      ServiceToken:
        Fn::ImportValue: AllocateAlbRulePriorityCustomResourceLambdaArn

  ListenerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Priority: !GetAtt AllocateAlbRulePriorityCustomResource.Priority
      [...]

Это фрагменты и могут не работать как есть, хотя они были взяты из рабочего кода. Я надеюсь, что это дает вам общее представление о том, как этого можно достичь. Дай мне знать, если тебе еще понадобится помощь.

...