如何有条件地传递对流层对象属性?
How to pass a Troposphere object attribute conditionally?
我正在使用 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(
....
))
我仍然对不涉及从模块外部使用私有方法的解决方案感兴趣。
所以最大的问题是 - ConnectionSettings 的配置从何而来?在 Cloudformation 本身(和对流层)内部,有条件、参数和 AWS::NoValue 参考。我在堆垛机 RDS 模板中大量使用它:
这是参数:https://github.com/remind101/stacker/blob/master/stacker/blueprints/rds/base.py#L126
这是条件:https://github.com/remind101/stacker/blob/master/stacker/blueprints/rds/base.py#L243
这是稍后在资源中使用它的方式,可选 - 如果 StorageType 参数为空,我们使用 AWS::NoValue,这是一个伪 Ref,用于实际不设置某些东西:(抱歉,不能 post 更多超过 2 个链接 - 转到同一文件中的第 304 行,看看我在说什么)
但是,如果您不使用参数,而是在 python 中执行所有条件,则可以执行类似的操作。类似于:
connection_setting = condition and <actual connection setting code> or Ref("AWS::NoValue")
另一种选择是完全在 python 中完成,这基本上就是您的示例。希望这会有所帮助,有很多方法可以解决这个问题,包括创建两个不同的 ELB 对象(一个有连接设置,一个没有),然后选择一个带有 python 代码(如果有条件)或 cloudformation 条件的对象.
主要的 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())
如果值在 Python 中已知(即,它 不是 来自 CloudFormation 参数),您可以使用字典向资源添加可选属性在对流层模板中:
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())
我正在使用 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(
....
))
我仍然对不涉及从模块外部使用私有方法的解决方案感兴趣。
所以最大的问题是 - ConnectionSettings 的配置从何而来?在 Cloudformation 本身(和对流层)内部,有条件、参数和 AWS::NoValue 参考。我在堆垛机 RDS 模板中大量使用它:
这是参数:https://github.com/remind101/stacker/blob/master/stacker/blueprints/rds/base.py#L126 这是条件:https://github.com/remind101/stacker/blob/master/stacker/blueprints/rds/base.py#L243 这是稍后在资源中使用它的方式,可选 - 如果 StorageType 参数为空,我们使用 AWS::NoValue,这是一个伪 Ref,用于实际不设置某些东西:(抱歉,不能 post 更多超过 2 个链接 - 转到同一文件中的第 304 行,看看我在说什么)
但是,如果您不使用参数,而是在 python 中执行所有条件,则可以执行类似的操作。类似于:
connection_setting = condition and <actual connection setting code> or Ref("AWS::NoValue")
另一种选择是完全在 python 中完成,这基本上就是您的示例。希望这会有所帮助,有很多方法可以解决这个问题,包括创建两个不同的 ELB 对象(一个有连接设置,一个没有),然后选择一个带有 python 代码(如果有条件)或 cloudformation 条件的对象.
主要的 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())
如果值在 Python 中已知(即,它 不是 来自 CloudFormation 参数),您可以使用字典向资源添加可选属性在对流层模板中:
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())