Saltar al contenido

AWS CloudFormation: variables personalizadas en plantillas

Nuestro grupo de redactores ha estado mucho tiempo buscando para dar espuestas a tu búsqueda, te brindamos la respuestas y nuestro deseo es servirte de mucha ayuda.

Solución:

Solución 1:

No tengo una respuesta, pero quería señalar que puedes ahorrarte mucho dolor usando Fn::Sub en lugar de Fn::Join

 "Fn::Sub": "$ELBHostName"-1.$EnvironmentVersioned.$HostedZone"

Reemplaza

"Fn::Join": [
    ".", [
         "Fn::Join": [ "", [  "Ref": "ELBHostName" , "-1" ] ] ,
         "Ref": "EnvironmentVersioned" ,
         "Ref": "HostedZone" 
    ]
]

Solucion 2:

No. Lo intenté, pero no me salió nada. La forma en que tuvo sentido para mí fue crear una entrada de Mapeos llamada “CustomVariables” y tener todas mis variables. Funciona para cadenas simples, pero no puede usar intrínsecos (Refs, Fn :: Joins, etc.) dentro de Mappings.

Obras:

"Mappings" : 
  "CustomVariables" : 
    "Variable1" :  "Value" : "foo" ,
    "Variable2" :  "Value" : "bar" 
  

No funcionará:

  "Variable3" :  "Value" :  "Ref" : "AWS::Region"  

Eso es solo un ejemplo. No pondría una referencia independiente en una variable.


Solución 3:

Buscaba la misma funcionalidad. Me vino a la mente usar una pila anidada como sugirió SpoonMeiser, pero luego me di cuenta de que lo que realmente necesitaba eran funciones personalizadas. Afortunadamente, CloudFormation permite el uso de AWS :: CloudFormation :: CustomResource que, con un poco de trabajo, permite hacer precisamente eso. Esto se siente como una exageración solo para las variables (algo que yo diría que debería haber estado en CloudFormation en primer lugar), pero hace el trabajo y, además, permite toda la flexibilidad de (elija python / node /Java). Cabe señalar que las funciones lambda cuestan dinero, pero estamos hablando de centavos aquí a menos que cree / elimine sus pilas varias veces por hora.

El primer paso es crear una función lambda en esta página que no haga más que tomar el valor de entrada y copiarlo en la salida. Podríamos hacer que la función lambda haga todo tipo de locuras, pero una vez que tenemos la función de identidad, cualquier otra cosa es fácil. Alternativamente, podríamos crear la función lambda en la propia pila. Como uso muchas pilas en 1 cuenta, tendría un montón de funciones y roles lambda sobrantes (y todas las pilas deben crearse con --capabilities=CAPABILITY_IAM, ya que también necesita un papel.

Crear función lambda

  • Vaya a la página de inicio de lambda y seleccione su región favorita
  • Seleccione “Función en blanco” como plantilla
  • Haga clic en “Siguiente” (no configure ningún activador)
  • Llenar:
    • Nombre: CloudFormationIdentity
    • Descripción: Devuelve lo que obtiene, soporte variable en Cloud Formation
    • Tiempo de ejecución: python2.7
    • Tipo de entrada de código: Editar código en línea
    • Código: ver más abajo
    • Manipulador: index.handler
    • Rol: cree un rol personalizado. En este punto, se abre una ventana emergente que le permite crear un nuevo rol. Acepte todo en esta página y haga clic en “Permitir”. Creará un rol con permisos para publicar en los registros de Cloudwatch.
    • Memoria: 128 (este es el mínimo)
    • Tiempo de espera: 3 segundos (debería ser suficiente)
    • VPC: Sin VPC

Luego copie y pegue el código a continuación en el campo de código. La parte superior de la función es el código del módulo de python cfn-response, que solo se instala automáticamente si la función lambda se crea a través de CloudFormation, por alguna extraña razón. los handler la función es bastante autoexplicativa.

from __future__ import print_function
import json

try:
    from urllib2 import HTTPError, build_opener, HTTPHandler, Request
except ImportError:
    from urllib.error import HTTPError
    from urllib.request import build_opener, HTTPHandler, Request


SUCCESS = "SUCCESS"
FAILED = "FAILED"


def send(event, context, response_status, reason=None, response_data=None, physical_resource_id=None):
    response_data = response_data or 
    response_body = json.dumps(
        
            'Status': response_status,
            'Reason': reason or "See the details in CloudWatch Log Stream: " + context.log_stream_name,
            'PhysicalResourceId': physical_resource_id or context.log_stream_name,
            'StackId': event['StackId'],
            'RequestId': event['RequestId'],
            'LogicalResourceId': event['LogicalResourceId'],
            'Data': response_data
        
    )
    if event["ResponseURL"] == "http://pre-signed-S3-url-for-response":
        print("Would send back the following values to Cloud Formation:")
        print(response_data)
        return

    opener = build_opener(HTTPHandler)
    request = Request(event['ResponseURL'], data=response_body)
    request.add_header('Content-Type', '')
    request.add_header('Content-Length', len(response_body))
    request.get_method = lambda: 'PUT'
    try:
        response = opener.open(request)
        print("Status code: ".format(response.getcode()))
        print("Status message: ".format(response.msg))
        return True
    except HTTPError as exc:
        print("Failed executing HTTP request: ".format(exc.code))
        return False

def handler(event, context):
    responseData = event['ResourceProperties']
    send(event, context, SUCCESS, None, responseData, "CustomResourcePhysicalID")
  • Haga clic en Siguiente”
  • Haga clic en “Crear función”

Ahora puede probar la función lambda seleccionando el botón “Probar” y seleccionando “Solicitud de creación de CloudFormation” como plantilla de muestra. Debería ver en su registro que se devuelven las variables que se le enviaron.

Use variable en su plantilla de CloudFormation

Ahora que tenemos esta función lambda, podemos usarla en las plantillas de CloudFormation. Primero tome nota de la función lambda Arn (vaya a la página de inicio de lambda, haga clic en la función recién creada, Arn debería estar en la parte superior derecha, algo así como arn:aws:lambda:region:12345:function:CloudFormationIdentity).

Ahora en su plantilla, en la sección de recursos, especifique sus variables como:

Identity:
  Type: "Custom::Variable"
  Properties:
    ServiceToken: "arn:aws:lambda:region:12345:function:CloudFormationIdentity"
    Arn: "arn:aws:lambda:region:12345:function:CloudFormationIdentity"

ClientBucketVar:
  Type: "Custom::Variable"
  Properties:
    ServiceToken: !GetAtt [Identity, Arn]
    Name: !Join ["-", [my-client-bucket, !Ref ClientName]]
    Arn: !Join [":", [arn, aws, s3, "", "", !Join ["-", [my-client-bucket, !Ref ClientName]]]]

ClientBackupBucketVar:
  Type: "Custom::Variable"
  Properties:
    ServiceToken: !GetAtt [Identity, Arn]
    Name: !Join ["-", [my-client-bucket, !Ref ClientName, backup]]
    Arn: !Join [":", [arn, aws, s3, "", "", !Join ["-", [my-client-bucket, !Ref ClientName, backup]]]]

Primero especifico un Identity variable que contiene Arn para la función lambda. Poner esto en una variable aquí, significa que solo tengo que especificarlo una vez. Hago todas mis variables de tipo Custom::Variable. CloudFormation le permite usar cualquier nombre de tipo que comience con Custom:: para recursos personalizados.

Tenga en cuenta que el Identity La variable contiene el Arn para la función lambda dos veces. Una vez para especificar la función lambda a usar. La segunda vez como valor de la variable.

Ahora que tengo el Identity variable, puedo definir nuevas variables usando ServiceToken: !GetAtt [Identity, Arn] (Creo que el código JSON debería ser algo así como "ServiceToken": "Fn::GetAtt": ["Identity", "Arn"]). Creo 2 nuevas variables, cada una con 2 campos: Nombre y Arn. En el resto de mi plantilla puedo usar !GetAtt [ClientBucketVar, Name] o !GetAtt [ClientBucketVar, Arn] siempre que lo necesite.

Advertencia

Cuando se trabaja con recursos personalizados, si la función lambda falla, está atascado entre 1 y 2 horas, porque CloudFormation espera una respuesta de la función (bloqueada) durante una hora antes de darse por vencido. Por lo tanto, podría ser bueno especificar un tiempo de espera corto para la pila mientras desarrolla su función lambda.


Solución 4:

Puede usar una pila anidada que resuelve todas sus variables en sus salidas y luego usar Fn::GetAtt para leer las salidas de esa pila


Solución 5:

Puede usar plantillas anidadas en las que “resuelve” todas sus variables en la plantilla externa y las pasa a otra plantilla.

Puntuaciones y reseñas

Si aceptas, tienes la habilidad dejar una reseña acerca de qué le añadirías a este ensayo.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *