diff --git a/heat/engine/parser.py b/heat/engine/parser.py index 4a10b9ae04..0fbcd0baff 100644 --- a/heat/engine/parser.py +++ b/heat/engine/parser.py @@ -70,6 +70,8 @@ class Stack(object): self.resources[r] = resources.ElasticIp(r, self.t['Resources'][r], self) elif type == 'AWS::EC2::EIPAssociation': self.resources[r] = resources.ElasticIpAssociation(r, self.t['Resources'][r], self) + elif type == 'AWS::EC2::SecurityGroup': + self.resources[r] = resources.SecurityGroup(r, self.t['Resources'][r], self) else: self.resources[r] = resources.GenericResource(r, self.t['Resources'][r], self) diff --git a/heat/engine/resources.py b/heat/engine/resources.py index 66c7577c6e..20480365b8 100644 --- a/heat/engine/resources.py +++ b/heat/engine/resources.py @@ -140,6 +140,54 @@ class GenericResource(Resource): super(GenericResource, self).create() print 'creating GenericResource %s' % self.name +class SecurityGroup(Resource): + + def __init__(self, name, json_snippet, stack): + super(SecurityGroup, self).__init__(name, json_snippet, stack) + self.instance_id = '' + + if self.t['Properties'].has_key('GroupDescription'): + self.description = self.t['Properties']['GroupDescription'] + else: + self.description = '' + + def create(self): + if self.state != None: + return + self.state_set(self.CREATE_IN_PROGRESS) + Resource.create(self) + + sec = self.nova().security_groups.create(self.name, self.description) + self.instance_id = sec.id + + if self.t['Properties'].has_key('SecurityGroupIngress'): + for i in self.t['Properties']['SecurityGroupIngress']: + rule = self.nova().security_group_rules.create(sec.id, + i['IpProtocol'], + i['FromPort'], + i['ToPort'], + i['CidrIp']) + + def delete(self): + if self.state == self.DELETE_IN_PROGRESS or self.state == self.DELETE_COMPLETE: + return + + self.state_set(self.DELETE_IN_PROGRESS) + Resource.delete(self) + + if self.instance_id != None: + sec = self.nova().security_groups.get(self.instance_id) + + for rule in sec.rules: + self.nova().security_group_rules.delete(rule['id']) + + self.nova().security_groups.delete(sec) + self.instance_id = None + + self.state_set(self.DELETE_COMPLETE) + + def FnGetRefId(self): + return unicode(self.name) class ElasticIp(Resource): def __init__(self, name, json_snippet, stack): diff --git a/templates/WordPress_Single_Instance_With_EIP.template b/templates/WordPress_Single_Instance_With_EIP.template index 1e25a38d18..cc0f85d4c1 100644 --- a/templates/WordPress_Single_Instance_With_EIP.template +++ b/templates/WordPress_Single_Instance_With_EIP.template @@ -132,6 +132,7 @@ { "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "InstanceType" }, "Arch" ] } ] }, "InstanceType" : { "Ref" : "InstanceType" }, "KeyName" : { "Ref" : "KeyName" }, + "SecurityGroups" : [ {"Ref" : "WebServerSecurityGroup"} ], "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [ "#!/bin/bash -v\n", "# Setup MySQL root password and create a user\n", @@ -148,6 +149,17 @@ "cp /usr/share/wordpress/wp-config.php /usr/share/wordpress/wp-config.orig\n" ]]}} } + }, + "WebServerSecurityGroup" : { + "Type" : "AWS::EC2::SecurityGroup", + "Properties" : { + "GroupDescription" : "Enable HTTP access via port 80 plus SSH access", + "SecurityGroupIngress" : [ + {"IpProtocol" : "icmp", "FromPort" : "-1", "ToPort" : "-1", "CidrIp" : "0.0.0.0/0"}, + {"IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0"}, + {"IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : "0.0.0.0/0"} + ] + } } },