Soru AWS CloudFormation - Şablonlarda özel değişkenler


CloudFormation şablon parametrelerinden türetilen sık kullanılan değerler için kısayolları tanımlamanın bir yolu var mı?

Örneğin - ELB adıyla bir Multi-AZ Proje yığını oluşturan bir komut dosyası var. project ve ELB'nin arkasındaki iki örnek project-1 ve project-2. Sadece geçiyorum ELBHostName şablona parametre ve daha sonra oluşturmak için kullanın:

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

Bu yapı veya çok benzer şablon boyunca birçok kez tekrarlanır - EC2 ana bilgisayar adı, Route53 kayıtları, vb oluşturmak için

Bunu tekrar tekrar tekrarlamak yerine bunun çıktısını vermek istiyorum. Fn::Join bir çeşit değişkene ve sadece şunu söyleyebilirim, tıpkı benim gibi "Ref": Beyan.

İdeal olarak şöyle bir şey:

Var::HostNameFull = "Fn::Join": [ ... ]
...
{ "Name": { "Ref": "Var::HostNameFull" } }

ya da benzer şekilde basit bir şey.

Amazon CloudFormation ile bu mümkün mü?


15
2017-09-02 03:41


Menşei


ELBHostName, Cloudformation'a açıkça ilettiğiniz bir parametredir mi? Eğer öyleyse, neden Ref kullanıyorsunuz? Şablonunuza değişkenler eklemek ve bunu Cloudformation'a göndermeden önce JSON'a dönüştürmek için Bıyık kullanabilir. Temel hazırlık sürecinizin neye benzediğine bağlı olarak değişir. - Canuteson


Cevaplar:


Aynı işlevsellikten bakıyordum. SpoonMeiser'ın önerdiği gibi iç içe geçmiş bir yığın kullanmak akla geldi, ama sonra gerçekten ihtiyacım olan şeyin özel işlevler olduğunu fark ettim. Neyse ki CloudFormation kullanımına izin veriyor AWS :: CloudFormation :: CustomResource Bu, biraz iş ile, sadece bunu yapmak için izin verir. Bu sadece değişkenler için çok fazla bir şey gibi hissettiriyor (ilk etapta CloudFormation'da olması gerektiğini savunulacağım bir şey), ama işi tamamlıyor, ve ek olarak, tüm esnekliğe izin veriyor (python / node'u seçtiniz) / java). Lambda fonksiyonlarının paraya mal olduğu unutulmamalıdır, ancak yığınlarınızı saatte birden çok kez oluşturmadan / silmediğiniz sürece burada pennies konuşuyoruz.

İlk adım lambda fonksiyonu yapmaktır bu sayfada Bu hiçbir şey yapmaz ama giriş değerini alır ve çıktıya kopyalar. Her çeşit çılgın şeyi lambda işlevine sokabilirdik, ama bir kez kimlik fonksiyonuna sahip olduğumuzda, başka hiçbir şey kolay değildir. Alternatif olarak, yığının kendisinde yaratılan lambda fonksiyonuna sahip olabilirdik. 1 hesapta çok sayıda yığın kullandığım için, bir sürü artık lambda fonksiyonu ve rolleri olurdu (ve tüm yığınlar ile oluşturulmalıdır. --capabilities=CAPABILITY_IAMAyrıca bir rol ihtiyacı olduğu için.

Lambda işlevi oluştur

  • Git lambda ana sayfave favori bölgenizi seçin
  • Şablon olarak "Boş İşlev" i seçin
  • "İleri" ye tıklayın (herhangi bir tetikleyici yapılandırmayın)
  • Doldurun:
    • İsim: CloudFormationIdentity
    • Açıklama: Ne elde ettiğini, Cloud Formasyonunda değişken desteği döndürür
    • Çalışma zamanı: python2.7
    • Kod Giriş Türü: Kodu Düzenle
    • Kod: aşağıya bakın
    • işleyici: index.handler
    • Rol: Özel Rol Oluşturun. Bu noktada, yeni bir rol oluşturmanıza olanak veren bir açılır pencere açılır. Bu sayfadaki her şeyi kabul edin ve "İzin Ver" e tıklayın. Cloudwatch günlüklerine gönderilecek izinlerle bir rol oluşturacaktır.
    • Bellek: 128 (bu minimum)
    • Zaman aşımı: 3 saniye (bol olmalı)
    • VPC: VPC Yok

Daha sonra aşağıdaki kodları kopyalayıp kod alanına yapıştırın. İşlev en üstteki koddur. cfn-tepki piton modülüBu, lambda işlevi CloudFormation aracılığıyla oluşturulduysa, sadece bazı otomatik olarak yüklenir, bazı garip nedenlerden dolayı. handler İşlev oldukça açıklayıcıdır.

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")
  • Sonrakine tıkla"
  • "İşlev Oluştur" u tıklayın

Şimdi "Test" düğmesini seçerek lambda fonksiyonunu test edebilir ve örnek şablon olarak "CloudFormation Create Request" öğesini seçebilirsiniz. Günlüğünüzde, kendisine verilen değişkenlerin döndüğünü görmelisiniz.

CloudFormation şablonunuzda değişken kullanın

Şimdi bu lambda fonksiyonumuz var, CloudFormation şablonlarında kullanabiliriz. Önce lambda fonksiyonunu not et Arn ( lambda ana sayfa, sadece oluşturulan işlevi tıklayın, Arn sağ üstte olmalı, gibi bir şey arn:aws:lambda:region:12345:function:CloudFormationIdentity).

Şimdi şablonunuzda, kaynak bölümünde, değişkenlerinizi şu şekilde belirtin:

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

İlk önce bir Identity lambda fonksiyonu için Arn içeren değişken. Bunu burada bir değişkene koymak, sadece bir kez belirtmek zorunda olduğum anlamına gelir. Tüm değişkenlerimi türden yaparım Custom::Variable. CloudFormation, ile başlayan herhangi bir ad kullanmanıza olanak tanır. Custom:: özel kaynaklar için.

Unutmayın ki Identity değişken lambda fonksiyonu için iki kez Arn içerir. Kullanılacak lambda işlevini belirtmek için bir kez. Değişkenin değeri olarak ikinci kez.

Şimdi sahip olduğum Identity Değişkeni kullanarak yeni değişkenleri tanımlayabilirim ServiceToken: !GetAtt [Identity, Arn] (Bence JSON kodu gibi bir şey olmalı "ServiceToken": {"Fn::GetAtt": ["Identity", "Arn"]}). Her biri 2 alana sahip 2 yeni değişken oluşturuyorum: İsim ve Arn. Şablonumun geri kalanında kullanabilirim !GetAtt [ClientBucketVar, Name] veya !GetAtt [ClientBucketVar, Arn] ne zaman ihtiyacım olursa.

Dikkat kelimesi

Özel kaynaklar ile çalışırken, lambda işlevi çökerse, 1 ila 2 saat arasında kalırsınız, çünkü CloudFormation (çöktü) işlevinden vazgeçmeden bir saat önce yanıt bekler. Bu nedenle, lambda işlevinizi geliştirirken yığın için kısa bir zaman aşımı belirtmek iyi olabilir.


4
2017-10-29 13:17



Harika cevap! Okudum ve yığınlarımda koştum, ama benim için, lambda fonksiyonlarının çoğalması konusunda endişelenmiyorum ve ben de bağımsız olan şablonları seviyorum. cloudformation-tool gem), bu yüzden lambda oluşturma şablon içine paketi ve daha sonra doğrudan oluşturmak yerine kullanabilirsiniz Identity özel kaynak. Kodum için buraya bakın: gist.github.com/guss77/2471e8789a644cac96992c4102936fb3 - Guss
@Claude Bu harika bir hile, teşekkürler! - MLu


Bir cevabım yok, ama kullanarak kendinizi çok fazla acı çekebileceğinizi belirtmek istedim. Fn::Sub yerine Fn::Join

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

Yerini

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

8
2017-10-18 17:59





Hayır. Denedim, ama boş çıktı. Bana mantıklı gelen yol, "CustomVariables" adlı bir Mappings girişi oluşturmak ve tüm değişkenlerime sahip olmaktı. Basit Dizeler için çalışıyor, ama sen Eşlemelerde İçsel (Refs, Fn :: Joins, vb.) kullanamaz.

Eserleri:

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

İşe yaramazsa:

  "Variable3" : { "Value" : { "Ref" : "AWS::Region" } }

Bu sadece bir örnek. Değişkende bağımsız bir Ref koyamazsın.


2
2017-09-05 17:17



Belgeler, haritalama değerlerinin gerçek dizeler olması gerektiğini söylüyor. - Ivan Anishchuk


Dış şablonda tüm değişkenlerinizi "çözdüğünüz" ve bunları başka bir şablona ilettiğiniz iç içe geçmiş şablonları kullanabilirsiniz.


2
2017-10-31 21:38





Tüm değişkenlerinizi çıktılarında çözen yuvalanmış bir yığın kullanabilir ve daha sonra kullanabilirsiniz. Fn::GetAtt çıktıları bu yığından okumak için


2
2017-08-30 10:55