使用 Troposphere 动态创建 n 个 ec2 实例
Dynamically create n number of ec2 instances with Troposphere
我刚开始接触 EC2、CloudFormation(和 Troposphere)等。我试图从一个简单的 Selenium Grid 开始,每晚 运行。现在,我们在需要时使用旋转 12 个 selenium 节点(每个节点在它自己的 EC2 实例上)。堆栈一次只能使用几个小时。很有可能我们将来需要更多,所以我不是静态设置节点数,而是尝试设置它以便 Jenkins 可以动态增加节点数。
现在,我有一个简单的 for 循环,看起来应该可以正常工作 - 特别是在查看了一堆示例之后:
for i in range(numNodes):
instance = ec2.Instance("Node{}".format(str(i)))
instance.ImageId = Ref(Image)
instance.UserData = Base64(Join("", userData))
instance.InstanceType = Ref(NodeSize)
instance.KeyName = Ref(SSHKey)
instance.SecurityGroups = [Ref("NodeSecurityGroup")]
instance.IamInstanceProfile = "SeleniumNode"
template.add_resource(instance)
完整堆栈跟踪:
Traceback (most recent call last):
File "C:/dev/source/admin/scripts/troposphere/seleniumGrid.py", line 171, in <module>
print(template.to_json())
File "C:\Users\Sathed\AppData\Local\Programs\Python\Python35-32\lib\site-packages\troposphere\__init__.py", line 543, in to_json
sort_keys=sort_keys, separators=separators)
File "C:\Users\Sathed\AppData\Local\Programs\Python\Python35-32\lib\json\__init__.py", line 237, in dumps
**kw).encode(obj)
File "C:\Users\Sathed\AppData\Local\Programs\Python\Python35-32\lib\json\encoder.py", line 200, in encode
chunks = list(chunks)
File "C:\Users\Sathed\AppData\Local\Programs\Python\Python35-32\lib\json\encoder.py", line 429, in _iterencode
yield from _iterencode_dict(o, _current_indent_level)
File "C:\Users\Sathed\AppData\Local\Programs\Python\Python35-32\lib\json\encoder.py", line 403, in _iterencode_dict
yield from chunks
File "C:\Users\Sathed\AppData\Local\Programs\Python\Python35-32\lib\json\encoder.py", line 403, in _iterencode_dict
yield from chunks
File "C:\Users\Sathed\AppData\Local\Programs\Python\Python35-32\lib\json\encoder.py", line 436, in _iterencode
o = _default(o)
File "C:\Users\Sathed\AppData\Local\Programs\Python\Python35-32\lib\site-packages\troposphere\__init__.py", line 440, in default
return obj.JSONrepr()
File "C:\Users\Sathed\AppData\Local\Programs\Python\Python35-32\lib\site-packages\troposphere\__init__.py", line 223, in JSONrepr
"Resource %s required in type %s" % (k, rtype))
ValueError: Resource ImageId required in type AWS::EC2::Instance
我的图像参数如下所示:
Image = template.add_parameter(Parameter(
"Image",
Type="AWS::EC2::Image::Id", # I even tried setting this to "String"
Description="AMI To use for all windows grid instances.",
Default="ami-c06b24a0"
))
我什至尝试将所有内容传递给构造函数。
for i in range(numNodes):
instance = ec2.Instance("Node{}".format(str(i)),
ImageId=Ref(Image),
UserData=Base64(Join("", userData)),
InstanceType=Ref(NodeSize),
KeyName=Ref(SSHKey),
SecurityGroups=[Ref("NodeSecurityGroup")],
DependsOn=["NodeSecurityGroup", "WindowsHub"],
IamInstanceProfile="SeleniumNode")
template.add_resource(instance)
但我仍然遇到同样的错误。我确定这是愚蠢的事情,但它变得非常烦人。有什么想法吗?
此外,当我尝试打印 JSON 模板时出现错误。
print(template.to_json())
对流层 1.8.2
Python 3.5.2
这里是对流层维护者。你在什么时候得到 ValueError?你能分享完整的堆栈跟踪吗?
有一件事可能无法解决这个问题,但我想我要指出的是,您不需要在创建对象后指定实例的每个单独属性。相反,您通常会改用此代码:
for i in range(numNodes):
instance = ec2.Instance(
"Node{}".format(str(i)),
ImageId=Ref(Image)
UserData=Base64(Join("", userData)),
InstanceType=Ref(NodeSize),
KeyName=Ref(SSHKey),
SecurityGroups=[Ref("NodeSecurityGroup")],
IamInstanceProfile="SeleniumNode",
)
template.add_resource(instance)
您甚至可以将其缩短为:
for i in range(numNodes):
instance = template.add_resource(
ec2.Instance(
"Node{}".format(str(i)),
ImageId=Ref(Image)
UserData=Base64(Join("", userData)),
InstanceType=Ref(NodeSize),
KeyName=Ref(SSHKey),
SecurityGroups=[Ref("NodeSecurityGroup")],
IamInstanceProfile="SeleniumNode",
)
)
无论如何,这似乎不是您的问题 - 因此,如果您可以分享完整的堆栈跟踪信息以了解有帮助的错误,以及 python 和 troposphere 的版本使用.
好吧,一旦我发现自己是个笨蛋,我就打算删除这个问题......但是关于为了全人类而删除 "answered questions" 的小消息,yadda yadda yadda 让我觉得有罪的。希望其他人可以从我的错误中吸取教训。
至于答案...
事实证明对流层没有任何问题(我认为这是我的错)。我完全忘记了 Selenium Hub,它是它自己的实例,但不是根据所需节点的数量动态设置的。我只为中心添加了部分资源。你猜对了——我忘了指定 ImageId kwarg。一旦我添加了它(以及其他一些 kwargs),一切都完美无缺。
向@phobologic 和所有其他对流层维护者大声疾呼。多亏了您,我才能够将 2500 多行 JSON 的对象转换为 ~175 行 python 的脚本,这样维护起来就容易多了!
我刚开始接触 EC2、CloudFormation(和 Troposphere)等。我试图从一个简单的 Selenium Grid 开始,每晚 运行。现在,我们在需要时使用旋转 12 个 selenium 节点(每个节点在它自己的 EC2 实例上)。堆栈一次只能使用几个小时。很有可能我们将来需要更多,所以我不是静态设置节点数,而是尝试设置它以便 Jenkins 可以动态增加节点数。
现在,我有一个简单的 for 循环,看起来应该可以正常工作 - 特别是在查看了一堆示例之后:
for i in range(numNodes):
instance = ec2.Instance("Node{}".format(str(i)))
instance.ImageId = Ref(Image)
instance.UserData = Base64(Join("", userData))
instance.InstanceType = Ref(NodeSize)
instance.KeyName = Ref(SSHKey)
instance.SecurityGroups = [Ref("NodeSecurityGroup")]
instance.IamInstanceProfile = "SeleniumNode"
template.add_resource(instance)
完整堆栈跟踪:
Traceback (most recent call last):
File "C:/dev/source/admin/scripts/troposphere/seleniumGrid.py", line 171, in <module>
print(template.to_json())
File "C:\Users\Sathed\AppData\Local\Programs\Python\Python35-32\lib\site-packages\troposphere\__init__.py", line 543, in to_json
sort_keys=sort_keys, separators=separators)
File "C:\Users\Sathed\AppData\Local\Programs\Python\Python35-32\lib\json\__init__.py", line 237, in dumps
**kw).encode(obj)
File "C:\Users\Sathed\AppData\Local\Programs\Python\Python35-32\lib\json\encoder.py", line 200, in encode
chunks = list(chunks)
File "C:\Users\Sathed\AppData\Local\Programs\Python\Python35-32\lib\json\encoder.py", line 429, in _iterencode
yield from _iterencode_dict(o, _current_indent_level)
File "C:\Users\Sathed\AppData\Local\Programs\Python\Python35-32\lib\json\encoder.py", line 403, in _iterencode_dict
yield from chunks
File "C:\Users\Sathed\AppData\Local\Programs\Python\Python35-32\lib\json\encoder.py", line 403, in _iterencode_dict
yield from chunks
File "C:\Users\Sathed\AppData\Local\Programs\Python\Python35-32\lib\json\encoder.py", line 436, in _iterencode
o = _default(o)
File "C:\Users\Sathed\AppData\Local\Programs\Python\Python35-32\lib\site-packages\troposphere\__init__.py", line 440, in default
return obj.JSONrepr()
File "C:\Users\Sathed\AppData\Local\Programs\Python\Python35-32\lib\site-packages\troposphere\__init__.py", line 223, in JSONrepr
"Resource %s required in type %s" % (k, rtype))
ValueError: Resource ImageId required in type AWS::EC2::Instance
我的图像参数如下所示:
Image = template.add_parameter(Parameter(
"Image",
Type="AWS::EC2::Image::Id", # I even tried setting this to "String"
Description="AMI To use for all windows grid instances.",
Default="ami-c06b24a0"
))
我什至尝试将所有内容传递给构造函数。
for i in range(numNodes):
instance = ec2.Instance("Node{}".format(str(i)),
ImageId=Ref(Image),
UserData=Base64(Join("", userData)),
InstanceType=Ref(NodeSize),
KeyName=Ref(SSHKey),
SecurityGroups=[Ref("NodeSecurityGroup")],
DependsOn=["NodeSecurityGroup", "WindowsHub"],
IamInstanceProfile="SeleniumNode")
template.add_resource(instance)
但我仍然遇到同样的错误。我确定这是愚蠢的事情,但它变得非常烦人。有什么想法吗?
此外,当我尝试打印 JSON 模板时出现错误。
print(template.to_json())
对流层 1.8.2
Python 3.5.2
这里是对流层维护者。你在什么时候得到 ValueError?你能分享完整的堆栈跟踪吗?
有一件事可能无法解决这个问题,但我想我要指出的是,您不需要在创建对象后指定实例的每个单独属性。相反,您通常会改用此代码:
for i in range(numNodes):
instance = ec2.Instance(
"Node{}".format(str(i)),
ImageId=Ref(Image)
UserData=Base64(Join("", userData)),
InstanceType=Ref(NodeSize),
KeyName=Ref(SSHKey),
SecurityGroups=[Ref("NodeSecurityGroup")],
IamInstanceProfile="SeleniumNode",
)
template.add_resource(instance)
您甚至可以将其缩短为:
for i in range(numNodes):
instance = template.add_resource(
ec2.Instance(
"Node{}".format(str(i)),
ImageId=Ref(Image)
UserData=Base64(Join("", userData)),
InstanceType=Ref(NodeSize),
KeyName=Ref(SSHKey),
SecurityGroups=[Ref("NodeSecurityGroup")],
IamInstanceProfile="SeleniumNode",
)
)
无论如何,这似乎不是您的问题 - 因此,如果您可以分享完整的堆栈跟踪信息以了解有帮助的错误,以及 python 和 troposphere 的版本使用.
好吧,一旦我发现自己是个笨蛋,我就打算删除这个问题......但是关于为了全人类而删除 "answered questions" 的小消息,yadda yadda yadda 让我觉得有罪的。希望其他人可以从我的错误中吸取教训。
至于答案...
事实证明对流层没有任何问题(我认为这是我的错)。我完全忘记了 Selenium Hub,它是它自己的实例,但不是根据所需节点的数量动态设置的。我只为中心添加了部分资源。你猜对了——我忘了指定 ImageId kwarg。一旦我添加了它(以及其他一些 kwargs),一切都完美无缺。
向@phobologic 和所有其他对流层维护者大声疾呼。多亏了您,我才能够将 2500 多行 JSON 的对象转换为 ~175 行 python 的脚本,这样维护起来就容易多了!