Как передать атрибут объекта Troposphere условно?

Я использую Troposphere для создания стеков CloudFormation и хотел бы пройти Elastic Load Balancer ConnectionSettings атрибут, только если он установлен в моей конфигурации, иначе я не хочу его указывать.

Если я установлю его по умолчанию None тогда я получаю ошибку о значении, не являющемся ожидаемым типом troposphere.elasticloadbalancing.ConnectionSettings,

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

В идеале я хотел бы иметь возможность добавлять атрибуты к существующему объекту, например:

lb = template.add_resource(elb.LoadBalancer(
  ...
))

if condition:
  lb.add_attribute(ConnectionSettings = elb.ConnectionSettings(
    ...
  ))

Есть ли способ достичь этого?

ОБНОВЛЕНИЕ: я достиг этого, используя скрытый Troposphere метод, который работает, но я не доволен:

if condition:
  lb.__setattr__('ConnectionSettings', elb.ConnectionSettings(
    ....
  ))

Я по-прежнему заинтересован в решении, которое не предусматривает использование частного метода извне модуля.

3 ответа

Решение

Основной README ускользает от использования имен атрибутов, например:

from troposphere import Template
import troposphere.elasticloadbalancing as elb

template = Template()
webelb = elb.LoadBalancer(
    'ElasticLoadBalancer',
    Listeners=[
        elb.Listener(
            LoadBalancerPort="80",
            InstancePort="80",
            Protocol="HTTP",
        ),
    ],
)

if True:
    webelb.ConnectionSettings = elb.ConnectionSettings(IdleTimeout=30)
elasticLB = template.add_resource(webelb)
print(template.to_json())

Таким образом, большой вопрос - откуда берется конфигурация для ConnectionSettings? Внутри самой Облачной информации (и тропосферы) есть Условия, Параметры и Ссылка AWS::NoValue. Я использую это довольно интенсивно в шаблонах RDS:

Вот этот параметр: https://github.com/remind101/stacker/blob/master/stacker/blueprints/rds/base.py Вот условие: https://github.com/remind101/stacker/blob/master/stacker/blueprints/rds/base.py А вот как он используется в ресурсе позже, опционально - если параметр StorageType пуст, мы используем AWS::NoValue, который является псевдо Ref для фактической установки чего-либо: (Извините, я не могу опубликовать более 2 ссылок - перейдите к строке 304 в том же файле, чтобы увидеть, о чем я говорю)

Однако, если вы не используете Parameters и вместо этого выполняете все свои условия в python, вы можете сделать что-то подобное. Что-то вроде:

connection_setting = condition and <actual connection setting code> or Ref("AWS::NoValue")

Другой вариант - сделать это полностью на python, что в основном является вашим примером. Надеюсь, это поможет, есть много способов справиться с этим, в том числе создать два различных объекта ELB (один с настройками соединения, другой без), а затем выбрать любой из них с кодом Python (если условие) или условиями облачной среды.

Если значение известно в Python (т. Е. Оно не происходит из параметра CloudFormation), вы можете использовать словарь для добавления дополнительных атрибутов к ресурсам в шаблоне Troposphere:

from troposphere import Template
import troposphere.elasticloadbalancing as elb

template = Template()

my_idle_timeout = 30  # replace this with your method for determining the value

my_elb_params = {}
if my_idle_timeout is not None:
    my_elb_params['ConnectionSettings'] = elb.ConnectionSettings(
        IdleTimeout=my_idle_timeout,
    )

my_elb = template.add_resource(elb.LoadBalancer(
    'ElasticLoadBalancer',
    Listeners=[
        elb.Listener(
            LoadBalancerPort="80",
            InstancePort="80",
            Protocol="HTTP",
        ),
    ],
    **my_elb_params,
))

print(template.to_json())

Если значение происходит из параметра CloudFormation, вам необходимо создать Condition проверить значение параметра и использовать Ref("AWS::NoValue") если значение не было предоставлено для параметра, например:

from troposphere import Template, Parameter, Equals, Ref, If
import troposphere.elasticloadbalancing as elb

template = Template()

my_idle_timeout = template.add_parameter(Parameter(
    "ElbIdleTimeout",
    Description="Idle timeout for the Elastic Load Balancer",
    Type="Number",
))

no_idle_timeout = "NoIdleTimeout"
template.add_condition(
    no_idle_timeout,
    Equals(Ref(my_idle_timeout), ""),
)

my_elb = template.add_resource(elb.LoadBalancer(
    'ElasticLoadBalancer',
    Listeners=[
        elb.Listener(
            LoadBalancerPort="80",
            InstancePort="80",
            Protocol="HTTP",
        ),
    ],
    ConnectionSettings=If(
        no_idle_timeout,
        Ref("AWS::NoValue"),
        elb.ConnectionSettings(
            IdleTimeout=Ref(my_idle_timeout),
        ),
    ),
))

print(template.to_json())
Другие вопросы по тегам