Как передать атрибут объекта 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())