2015-11-26 22 views
0

我正在使用Troposphere构建CloudFormation堆栈,并且只有在设置中配置了Elastic Load Balancer ConnectionSettings属性,否则我不想指定它。如何有条件地传递对流层对象属性?

如果我将它设置为默认None,那么我得到一个关于该值不是预期类型troposphere.elasticloadbalancing.ConnectionSettings的错误。

我宁愿尽量避免在调用中设置显式的默认值,因为它可能会覆盖其他设置。

Idealy,我希望能够将属性添加到现有的对象,例如:

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

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

有没有办法做到这一点?

更新:我实现它使用隐藏Troposphere方法,它的作品,但我不是很满意:

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

我仍然有兴趣在一个解决方案,不涉及使用私有方法从模块外部。

回答

1

主自述逃避,只是用这样的属性名称:

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()) 
+0

谢谢。这样可行。在经过仔细阅读(设置'instance.ImageId')之后,我在README文件中只找到了这个特性的参考,也许文档可以更突出地突出这一点。 –

0

所以最大的问题是 - ConnectionSettings的配置从哪里来? Cloudformation内部(和对流层)有条件,参数和AWS :: NoValue Ref。我使用的是相当严重的堆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,这是一个伪参考没有实际设置的东西:(对不起,不能发布超过2个链接 - 去同一个文件中的304行看我在说什么)

如果你'不要使用参数,而是在Python中执行所有条件,你可以做类似的事情。例如:

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

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

+0

谢谢。条件来自外部。yaml文件,由Python脚本读取。我宁愿保持模板简单,尽可能在Python代码中做出尽可能多的决策。我将测试回退到'Ref(“AWS :: NoValue”)'看看它是如何发生的。 –

+0

我测试了'IdleTimeout'值设置为'AWS :: NoValue',但得到错误'Property IdleTimeout不能为空.'。所以这似乎并不奏效。 –

+0

您希望ELB的ConnectionSettings属性为AWS :: NoValue,而不是IdleTimeout,因为这是ConnectionSettings对象的必需属性。 – phobologic

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()) 
+0

查看接受的答案。它已经完成了我以后的工作。谢谢。 –