在CloudFormation模板中自动设置ListenerRule优先级

问题描述 投票:0回答:1

我有一个包含应用程序负载均衡器 ListenerRule 的 CloudFormation 模板。 ListenerRule 的必需属性之一是其优先级(1 到 50000 之间的数字)。每个 ListenerRule 的优先级必须是唯一的。

我需要多次部署相同的模板。每次启动模板时,ListenerRule 的优先级都应该更改。

目前,我已将优先级变成了启动堆栈时可以设置的参数,效果很好。有没有办法自动将 ListenerRule 的优先级设置为下一个可用优先级?

amazon-web-services aws-cloudformation elastic-load-balancer
1个回答
22
投票

不,目前无法仅使用

AWS::ElasticLoadBalancingV2::ListenerRule
资源自动分配它。但是,可以使用自定义资源来实现。

首先让我们创建实际的自定义资源 Lambda 代码。

allocate_alb_rule_priority.py:

import json
import os
import random
import uuid

import boto3
import urllib3

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(json.dumps(event))

    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']

    http = urllib3.PoolManager()

    body = {
        'Status': response_status,
        'Reason': reason or '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,
    }
    encoded_body = json.dumps(body).encode('utf-8')
    headers = {
        'content-type': '',
        'content-length': str(len(encoded_body)),
    }

    http.request('PUT', response_url, body=encoded_body, headers=headers)

根据您的问题,您需要使用相同的模板创建多个堆栈。因此,我建议将自定义资源放置在仅部署一次的模板中。然后让另一个模板导入其

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.8
      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
      [...]

这些是片段,可能无法按原样工作,尽管它们取自工作代码。我希望它能让您大致了解如何实现这一目标。如果您需要更多帮助,请告诉我。

© www.soinside.com 2019 - 2024. All rights reserved.