Szukałem tej samej funkcjonalności. Przyszło mi na myśl użycie zagnieżdżonego stosu, jak sugerował SpoonMeiser, ale potem zdałem sobie sprawę, że tak naprawdę potrzebowałem funkcji niestandardowych. Na szczęście CloudFormation pozwala na użycie AWS :: CloudFormation :: CustomResource, który przy odrobinie pracy pozwala to zrobić. To wydaje się przesadne w przypadku samych zmiennych (coś, co argumentowałbym, że powinno być w CloudFormation w pierwszej kolejności), ale wykonuje zadanie, a ponadto pozwala na całą elastyczność (wybierz Python / node) /Jawa). Należy zauważyć, że funkcje lambda kosztują pieniądze, ale mówimy tutaj o pensach, chyba że utworzysz / usuniesz swoje stosy wiele razy na godzinę.
Pierwszym krokiem jest utworzenie funkcji lambda na tej stronie , która nie robi nic poza pobraniem wartości wejściowej i skopiowaniem jej na wyjście. Moglibyśmy sprawić, aby funkcja lambda robiła różne szalone rzeczy, ale kiedy już mamy funkcję tożsamości, wszystko inne jest łatwe. Alternatywnie możemy stworzyć funkcję lambda w samym stosie. Ponieważ używam wielu stosów na jednym koncie, miałbym całą resztę funkcji i ról lambda (i wszystkie stosy muszą zostać utworzone za pomocą --capabilities=CAPABILITY_IAM
, ponieważ również potrzebuje roli.
Utwórz funkcję lambda
- Przejdź do strony głównej lambda i wybierz swój ulubiony region
- Wybierz „Pustą funkcję” jako szablon
- Kliknij „Dalej” (nie konfiguruj żadnych wyzwalaczy)
- Wypełnić:
- Nazwa: CloudFormationIdentity
- Opis: Zwraca to, co dostaje, zmienne wsparcie w Cloud Formation
- Środowisko wykonawcze: python2.7
- Typ wpisu kodu: Edytuj kod w tekście
- Kod: patrz poniżej
- Treser:
index.handler
- Rola: Utwórz niestandardową rolę. W tym momencie otwiera się okno, które pozwala utworzyć nową rolę. Zaakceptuj wszystko na tej stronie i kliknij „Zezwól”. Stworzy rolę z uprawnieniami do publikowania w dziennikach cloudwatch.
- Pamięć: 128 (to minimum)
- Limit czasu: 3 sekundy (powinno wystarczyć)
- VPC: Brak VPC
Następnie skopiuj i wklej poniższy kod w polu kodu. Na górze tej funkcji znajduje się kod z modułu python-odpowiedź cfn , który jest instalowany automatycznie tylko wtedy, gdy funkcja lambda została utworzona za pomocą CloudFormation, z jakiegoś dziwnego powodu. Ta handler
funkcja jest dość oczywista.
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")
- Kliknij Następny"
- Kliknij „Utwórz funkcję”
Możesz teraz przetestować funkcję lambda, wybierając przycisk „Test”, a następnie „Próbka tworzenia CloudFormation” jako przykładowy szablon. Powinieneś zobaczyć w swoim dzienniku, że zmienne wprowadzone do niego są zwracane.
Użyj zmiennej w szablonie CloudFormation
Teraz, gdy mamy tę funkcję lambda, możemy jej używać w szablonach CloudFormation. Najpierw zanotuj funkcję lambda Arn (przejdź do strony głównej lambda , kliknij właśnie utworzoną funkcję, Arn powinien być w prawym górnym rogu, coś w stylu arn:aws:lambda:region:12345:function:CloudFormationIdentity
).
Teraz w swoim szablonie, w sekcji zasobów, podaj swoje zmienne, takie jak:
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]]]]
Najpierw określam Identity
zmienną zawierającą Arn dla funkcji lambda. Umieszczenie tego w zmiennej tutaj oznacza, że muszę to określić tylko raz. Robię wszystkie moje zmienne typu Custom::Variable
. CloudFormation pozwala na użycie dowolnej nazwy typu zaczynającej się na Custom::
dla niestandardowych zasobów.
Zauważ, że Identity
zmienna zawiera dwa razy Arn dla funkcji lambda. Raz, aby określić funkcję lambda do użycia. Drugi raz jako wartość zmiennej.
Teraz, gdy mam Identity
zmienną, mogę definiować nowe zmienne za pomocą ServiceToken: !GetAtt [Identity, Arn]
(myślę, że kod JSON powinien być podobny "ServiceToken": {"Fn::GetAtt": ["Identity", "Arn"]}
). Tworzę 2 nowe zmienne, każda z 2 polami: Nazwa i Arn. Z pozostałej części mojego szablonu mogę korzystać !GetAtt [ClientBucketVar, Name]
lub !GetAtt [ClientBucketVar, Arn]
kiedykolwiek będę go potrzebować.
Słowo ostrzeżenia
Podczas pracy z niestandardowymi zasobami, jeśli funkcja lambda ulegnie awarii, utkniesz na 1 do 2 godzin, ponieważ CloudFormation czeka godzinę na odpowiedź z (zawieszonej) funkcji przed poddaniem się. Dlatego dobrze jest określić krótki limit czasu dla stosu podczas rozwijania funkcji lambda.