0

我正在使用Troposphere构建 CloudFormation 堆栈,并且希望ConnectionSettings仅在我的配置中设置了 Elastic Load Balancer 属性时才传递它,否则我不想指定它。

如果我将其设置为默认值,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(
    ....
  ))

我仍然对不涉及从模块外部使用私有方法的解决方案感兴趣。

4

3 回答 3

1

主要的 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())
于 2015-11-27T01:22:46.040 回答
0

所以最大的问题是 - ConnectionSettings 的配置来自哪里?Cloudformation 本身(和对流层)内部有条件、参数和 AWS::NoValue Ref。我在 stacker 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,实际上没有设置一些东西:(抱歉,不能发布超过 2 个链接 - 转到同一文件中的第 304 行,看看我在说什么)

但是,如果您不使用参数,而是在 python 中执行所有条件,则可以执行类似的操作。就像是:

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

另一种选择是完全在 python 中完成,这基本上是你的例子。希望这会有所帮助,有很多方法可以解决这个问题,包括创建两个不同的 ELB 对象(一个有连接设置,一个没有),然后使用 python 代码(如果有条件)或 cloudformation 条件选择一个。

于 2015-11-26T06:10:29.277 回答
0

如果该值在 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())
于 2017-10-01T13:35:25.240 回答