Merge branch 'puppet_instances'

Conflicts:
	heat/api/v1/__init__.py
	heat/engine/parser.py
This commit is contained in:
Chris Alfonso 2012-05-21 15:39:11 -04:00
commit af8dab4570
7 changed files with 577 additions and 10 deletions

View File

@ -139,8 +139,9 @@ class CommandRunner(object):
Helper class to run a command and store the output.
"""
def __init__(self, command):
def __init__(self, command, nextcommand=None):
self._command = command
self._next = nextcommand
self._stdout = None
self._stderr = None
self._status = None
@ -172,7 +173,8 @@ class CommandRunner(object):
self._status = subproc.returncode
self._stdout = output[0]
self._stderr = output[1]
if self._next:
self._next.run()
return self
@property
@ -579,18 +581,31 @@ class SourcesHandler(object):
def _decompress(self, archive, dest_dir):
cmd_str = ''
logger.debug("Decompressing")
(r, ext) = os.path.splitext(archive)
if ext == '.tar.gz' or ext == '.tgz':
if ext == '.tgz':
cmd_str = 'tar -C %s -xzf %s' % (dest_dir, archive)
elif ext == '.tar.bz2' or ext == '.tbz2':
elif ext == '.tbz2':
cmd_str = 'tar -C %s -xjf %s' % (dest_dir, archive)
elif ext == '.zip':
cmd_str = 'unzip -d %s %s' % (dest_dir, archive)
elif ext == '.tar':
cmd_str = 'tar -C %s -xf %s' % (dest_dir, archive)
elif ext == '.gz':
(r, ext) = os.path.splitext(r)
if ext:
cmd_str = 'tar -C %s -xzf %s' % (dest_dir, archive)
else:
cmd_str = 'gunzip -c %s > %s' % (archive, dest_dir)
elif ext == 'bz2':
(r, ext) = os.path.splitext(r)
if ext:
cmd_str = 'tar -C %s -xjf %s' % (dest_dir, archive)
else:
cmd_str = 'bunzip2 -c %s > %s' % (archive, dest_dir)
else:
pass
CommandRunner(cmd_str).run()
return CommandRunner(cmd_str)
def apply_sources(self):
if not self._sources:
@ -598,7 +613,8 @@ class SourcesHandler(object):
for dest, url in self._sources.iteritems():
tmp_name = self._url_to_tmp_filename(url)
cmd_str = 'wget -O %s %s' % (tmp_name, url)
CommandRunner(cmd_str).run()
decompress_command = self._decompress(tmp_name, dest)
CommandRunner(cmd_str, decompress_command).run()
try:
os.makedirs(dest)
except OSError as e:
@ -606,7 +622,6 @@ class SourcesHandler(object):
logger.debug(str(e))
else:
logger.exception(e)
self._decompress(tmp_name, dest)
class ServicesHandler(object):

View File

@ -75,6 +75,8 @@ class Instance(Resource):
res = self.t['Properties']['AvailabilityZone']
elif key == 'PublicIp':
res = self.ipaddress
elif key == 'PrivateDnsName':
res = self.ipaddress
else:
raise exception.InvalidTemplateAttribute(resource=self.name,
key=key)

View File

@ -17,13 +17,13 @@ import eventlet
import json
import logging
import sys
from heat.common import exception
from heat.engine import resources
from heat.engine import instance
from heat.engine import volume
from heat.engine import eip
from heat.engine import security_group
from heat.engine import user
from heat.engine import wait_condition
from heat.db import api as db_api

View File

@ -16,7 +16,6 @@
import eventlet
import logging
import os
from novaclient.exceptions import BadRequest
from heat.common import exception
from heat.engine.resources import Resource
@ -53,7 +52,6 @@ class SecurityGroup(Resource):
self.description)
self.instance_id_set(sec.id)
if 'SecurityGroupIngress' in self.t['Properties']:
rules_client = self.nova().security_group_rules
for i in self.t['Properties']['SecurityGroupIngress']:

67
heat/engine/user.py Normal file
View File

@ -0,0 +1,67 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import eventlet
import logging
import os
from novaclient.exceptions import BadRequest
from heat.common import exception
from heat.engine.resources import Resource
logger = logging.getLogger(__file__)
class User(Resource):
def __init__(self, name, json_snippet, stack):
super(User, self).__init__(name, json_snippet, stack)
self.instance_id = ''
def create(self):
self.state_set(self.CREATE_COMPLETE)
def FnGetAtt(self, key):
res = None
if key == 'Policies':
res = self.t['Properties']['Policies']
else:
raise exception.InvalidTemplateAttribute(resource=self.name,
key=key)
logger.info('%s.GetAtt(%s) == %s' % (self.name, key, res))
return unicode(res)
class AccessKey(Resource):
def __init__(self, name, json_snippet, stack):
super(AccessKey, self).__init__(name, json_snippet, stack)
def create(self):
self.state_set(self.CREATE_COMPLETE)
def FnGetRefId(self):
return unicode(self.name)
def FnGetAtt(self, key):
res = None
if key == 'UserName':
res = self.t['Properties']['UserName']
if key == 'SecretAccessKey':
res = 'TODO-Add-Real-SecreateAccessKey'
else:
raise exception.InvalidTemplateAttribute(resource=self.name,
key=key)
logger.info('%s.GetAtt(%s) == %s' % (self.name, key, res))
return unicode(res)

View File

@ -0,0 +1,240 @@
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description": "Sample template to bring up Puppet Master instance that can be used to bootstrap and manage Puppet Clients. The Puppet Master is populated from an embedded template that defines the set of applications to load. **WARNING** This template creates one or more Amazon EC2 instances. You will be billed for the AWS resources used if you create a stack from this template.",
"Parameters" : {
"InstanceType" : {
"Description" : "WebServer EC2 instance type",
"Type" : "String",
"Default" : "m1.large",
"AllowedValues" : [ "t1.micro","m1.small","m1.medium","m1.large","m1.xlarge","m2.xlarge","m2.2xlarge","m2.4xlarge","c1.medium","c1.xlarge","cc1.4xlarge","cc2.8xlarge","cg1.4xlarge"],
"ConstraintDescription" : "must be a valid EC2 instance type."
},
"KeyName" : {
"Description" : "Name of an existing EC2 KeyPair to enable SSH access to the PuppetMaster",
"Type" : "String"
},
"ContentManifest" : {
"Default" : "/wordpress/: { include wordpress }",
"Description" : "Manifest of roles to add to nodes.pp",
"Type" : "String"
},
"ContentLocation" : {
"Default" : "https://s3.amazonaws.com/cloudformation-examples/wordpress-puppet-config.tar.gz",
"Description" : "Location of package (Zip, GZIP or Git repository URL) that includes the PuppetMaster content",
"Type" : "String"
},
"LinuxDistribution": {
"Default": "F16",
"Description" : "Distribution of choice",
"Type": "String",
"AllowedValues" : [ "F16", "F17", "U10", "RHEL-6.1", "RHEL-6.2", "RHEL-6.3" ]
}
},
"Mappings" : {
"AWSInstanceType2Arch" : {
"t1.micro" : { "Arch" : "32" },
"m1.small" : { "Arch" : "32" },
"m1.large" : { "Arch" : "64" },
"m1.xlarge" : { "Arch" : "64" },
"m2.xlarge" : { "Arch" : "64" },
"m2.2xlarge" : { "Arch" : "64" },
"m2.4xlarge" : { "Arch" : "64" },
"c1.medium" : { "Arch" : "32" },
"c1.xlarge" : { "Arch" : "64" },
"cc1.4xlarge" : { "Arch" : "64" }
},
"DistroArch2AMI": {
"F16" : { "32" : "F16-i386-cfntools", "64" : "F16-x86_64-cfntools" },
"F17" : { "32" : "F17-i386-cfntools", "64" : "F17-x86_64-cfntools" },
"U10" : { "32" : "U10-i386-cfntools", "64" : "U10-x86_64-cfntools" },
"RHEL-6.1" : { "32" : "rhel61-i386-cfntools", "64" : "rhel61-x86_64-cfntools" },
"RHEL-6.2" : { "32" : "rhel62-i386-cfntools", "64" : "rhel62-x86_64-cfntools" },
"RHEL-6.3" : { "32" : "rhel63-i386-cfntools", "64" : "rhel63-x86_64-cfntools" }
}
},
"Resources" : {
"CFNInitUser" : {
"Type" : "AWS::IAM::User",
"Properties" : {
"Policies": [{
"PolicyName": "AccessForCFNInit",
"PolicyDocument" : {
"Statement": [{
"Effect" : "Allow",
"Action" : "cloudformation:DescribeStackResource",
"Resource" : "*"
}]
}
}]
}
},
"CFNKeys" : {
"Type" : "AWS::IAM::AccessKey",
"Properties" : {
"UserName" : { "Ref": "CFNInitUser" }
}
},
"PuppetMasterInstance" : {
"Type" : "AWS::EC2::Instance",
"Metadata" : {
"AWS::CloudFormation::Init" : {
"config" : {
"packages" : {
"yum" : {
"puppet" : [],
"puppet-server" : [],
"ruby-devel" : [],
"gcc" : [],
"make" : [],
"rubygems" : []
},
"rubygems" : {
"json" : []
}
},
"sources" : {
"/etc/puppet" : { "Ref" : "ContentLocation" }
},
"files" : {
"/etc/yum.repos.d/epel.repo" : {
"source" : "https://s3.amazonaws.com/cloudformation-examples/enable-epel-on-amazon-linux-ami",
"mode" : "000644",
"owner" : "root",
"group" : "root"
},
"/etc/puppet/autosign.conf" : {
"content" : "*.internal\n",
"mode" : "100644",
"owner" : "root",
"group" : "wheel"
},
"/etc/puppet/fileserver.conf" : {
"content" : "[modules]\n allow *.internal\n",
"mode" : "100644",
"owner" : "root",
"group" : "wheel"
},
"/etc/puppet/puppet.conf" : {
"content" : { "Fn::Join" : ["", [
"[main]\n",
" logdir=/var/log/puppet\n",
" rundir=/var/run/puppet\n",
" ssldir=$vardir/ssl\n",
" pluginsync=true\n",
"[agent]\n",
" classfile=$vardir/classes.txt\n",
" localconfig=$vardir/localconfig\n"]] },
"mode" : "000644",
"owner" : "root",
"group" : "root"
},
"/etc/puppet/modules/cfn/manifests/init.pp" : {
"content" : "class cfn {}",
"mode" : "100644",
"owner" : "root",
"group" : "wheel"
},
"/etc/puppet/modules/cfn/lib/facter/cfn.rb" : {
"source" : "https://s3.amazonaws.com/cloudformation-examples/cfn-facter-plugin.rb",
"mode" : "100644",
"owner" : "root",
"group" : "wheel"
},
"/etc/puppet/manifests/nodes.pp" : {
"content" : {"Fn::Join" : ["", [
"node basenode {\n",
" include cfn\n",
"}\n",
"node /^.*internal$/ inherits basenode {\n",
" case $cfn_roles {\n",
" ", { "Ref" : "ContentManifest" }, "\n",
" }\n",
"}\n"]]},
"mode" : "100644",
"owner" : "root",
"group" : "wheel"
},
"/etc/puppet/manifests/site.pp" : {
"content" : "import \"nodes\"\n",
"mode" : "100644",
"owner" : "root",
"group" : "wheel"
}
},
"services" : {
"sysvinit" : {
"puppetmaster" : {
"enabled" : "true",
"ensureRunning" : "true"
}
}
}
}
}
},
"Properties" : {
"InstanceType" : { "Ref" : "InstanceType" },
"SecurityGroups" : [ { "Ref" : "PuppetGroup" } ],
"ImageId" : { "Fn::FindInMap" : [ "DistroArch2AMI", { "Ref" : "LinuxDistribution" },
{ "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "InstanceType" }, "Arch" ] } ] },
"KeyName" : { "Ref" : "KeyName" },
"UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
"#!/bin/bash\n",
"yum update -y aws-cfn-bootstrap\n",
"/opt/aws/bin/cfn-init --region ", { "Ref" : "AWS::Region" },
" -s ", { "Ref" : "AWS::StackName" }, " -r PuppetMasterInstance ",
" --access-key ", { "Ref" : "CFNKeys" },
" --secret-key ", { "Fn::GetAtt" : ["CFNKeys", "SecretAccessKey"]}, "\n",
"/opt/aws/bin/cfn-signal -e $? '", { "Ref" : "PuppetMasterWaitHandle" }, "'\n"]]}}
}
},
"EC2SecurityGroup" : {
"Type" : "AWS::EC2::SecurityGroup",
"Properties" : {
"GroupDescription" : "Group for clients to communicate with Puppet Master"
}
},
"PuppetGroup" : {
"Type" : "AWS::EC2::SecurityGroup",
"Properties" : {
"GroupDescription" : "Group for puppet communication",
"SecurityGroupIngress" : [
{ "IpProtocol" : "tcp", "FromPort" : "8140", "ToPort" : "8140", "CidrIp": "0.0.0.0/0"},
{ "IpProtocol" : "tcp", "FromPort": "22", "ToPort": "22", "CidrIp": "0.0.0.0/0" }
]
}
},
"PuppetMasterWaitHandle" : {
"Type" : "AWS::CloudFormation::WaitConditionHandle"
},
"PuppetMasterWaitCondition" : {
"Type" : "AWS::CloudFormation::WaitCondition",
"DependsOn" : "PuppetMasterInstance",
"Properties" : {
"Handle" : { "Ref" : "PuppetMasterWaitHandle" },
"Timeout" : "600"
}
}
},
"Outputs" : {
"PuppetMasterDNSName" : {
"Value" : { "Fn::GetAtt" : [ "PuppetMasterInstance", "PrivateDnsName" ] },
"Description" : "DNS Name of PuppetMaster"
},
"PuppetClientSecurityGroup" : {
"Value" : { "Ref" : "EC2SecurityGroup" },
"Description" : "Clients of the Puppet Master should be part of this security group"
}
}
}

View File

@ -0,0 +1,245 @@
TemplateFormatVersion" : "2010-09-09",
"Description": "Sample template to bring up WordPress using the Puppet client to install server roles. A WaitCondition is used to hold up the stack creation until the application is deployed. **WARNING** This template creates one or more Amazon EC2 instances and CloudWatch alarms. You will be billed for the AWS resources used if you create a stack from this template.",
"Parameters" : {
"KeyName": {
"Type": "String",
"Description" : "Name of an existing EC2 KeyPair to enable SSH access to the web server"
},
"PuppetClientSecurityGroup": {
"Description" : "The EC2 security group for the instances",
"Type": "String"
},
"PuppetMasterDNSName": {
"Description" : "The PuppetMaster DNS name",
"Type": "String"
},
"InstanceType" : {
"Description" : "WebServer EC2 instance type",
"Type" : "String",
"Default" : "m1.small",
"AllowedValues" : [ "t1.micro","m1.small","m1.medium","m1.large","m1.xlarge","m2.xlarge","m2.2xlarge","m2.4xlarge","c1.medium","c1.xlarge","cc1.4xlarge","cc2.8xlarge","cg1.4xlarge"],
"ConstraintDescription" : "must be a valid EC2 instance type."
},
"DatabaseType": {
"Default": "db.m1.small",
"Description" : "The database instance type",
"Type": "String",
"AllowedValues" : [ "db.m1.small", "db.m1.large", "db.m1.xlarge", "db.m2.xlarge", "db.m2.2xlarge", "db.m2.4xlarge" ],
"ConstraintDescription" : "must contain only alphanumeric characters."
},
"DatabaseUser": {
"Default" : "admin",
"NoEcho": "true",
"Type": "String",
"Description" : "Test database admin account name",
"MinLength": "1",
"MaxLength": "16",
"AllowedPattern" : "[a-zA-Z][a-zA-Z0-9]*",
"ConstraintDescription" : "must begin with a letter and contain only alphanumeric characters."
},
"DatabasePassword": {
"Default" : "admin",
"NoEcho": "true",
"Type": "String",
"Description" : "Test database admin account password",
"MinLength": "1",
"MaxLength": "41",
"AllowedPattern" : "[a-zA-Z0-9]*",
"ConstraintDescription" : "must contain only alphanumeric characters."
}
},
"Mappings" : {
"AWSInstanceType2Arch" : {
"t1.micro" : { "Arch" : "64" },
"m1.small" : { "Arch" : "64" },
"m1.medium" : { "Arch" : "64" },
"m1.large" : { "Arch" : "64" },
"m1.xlarge" : { "Arch" : "64" },
"m2.xlarge" : { "Arch" : "64" },
"m2.2xlarge" : { "Arch" : "64" },
"m2.4xlarge" : { "Arch" : "64" },
"c1.medium" : { "Arch" : "64" },
"c1.xlarge" : { "Arch" : "64" },
"cc1.4xlarge" : { "Arch" : "64HVM" },
"cc2.8xlarge" : { "Arch" : "64HVM" },
"cg1.4xlarge" : { "Arch" : "64HVM" }
},
"AWSRegionArch2AMI" : {
"us-east-1" : { "32" : "ami-31814f58", "64" : "ami-1b814f72", "64HVM" : "ami-0da96764" },
"us-west-2" : { "32" : "ami-38fe7308", "64" : "ami-30fe7300", "64HVM" : "NOT_YET_SUPPORTED" },
"us-west-1" : { "32" : "ami-11d68a54", "64" : "ami-1bd68a5e", "64HVM" : "NOT_YET_SUPPORTED" },
"eu-west-1" : { "32" : "ami-973b06e3", "64" : "ami-953b06e1", "64HVM" : "NOT_YET_SUPPORTED" },
"ap-southeast-1" : { "32" : "ami-b4b0cae6", "64" : "ami-beb0caec", "64HVM" : "NOT_YET_SUPPORTED" },
"ap-northeast-1" : { "32" : "ami-0644f007", "64" : "ami-0a44f00b", "64HVM" : "NOT_YET_SUPPORTED" },
"sa-east-1" : { "32" : "ami-3e3be423", "64" : "ami-3c3be421", "64HVM" : "NOT_YET_SUPPORTED" }
}
},
"Resources" : {
"CFNInitUser" : {
"Type" : "AWS::IAM::User",
"Properties" : {
"Policies": [{
"PolicyName": "AccessForCFNInit",
"PolicyDocument" : {
"Statement": [{
"Effect" : "Allow",
"Action" : "cloudformation:DescribeStackResource",
"Resource" : "*"
}]
}
}]
}
},
"CFNKeys" : {
"Type" : "AWS::IAM::AccessKey",
"Properties" : {
"UserName" : { "Ref": "CFNInitUser" }
}
},
"WebServer": {
"Type": "AWS::EC2::Instance",
"Metadata" : {
"AWS::CloudFormation::Init" : {
"config" : {
"packages" : {
"yum" : {
"puppet" : [],
"ruby-devel" : [],
"gcc" : [],
"make" : [],
"rubygems" : []
},
"rubygems" : {
"json" : []
}
},
"files" : {
"/etc/yum.repos.d/epel.repo" : {
"source" : "https://s3.amazonaws.com/cloudformation-examples/enable-epel-on-amazon-linux-ami",
"mode" : "000644",
"owner" : "root",
"group" : "root"
},
"/etc/puppet/puppet.conf" : {
"content" : { "Fn::Join" : ["", [
"[main]\n",
" logdir=/var/log/puppet\n",
" rundir=/var/run/puppet\n",
" ssldir=$vardir/ssl\n",
" pluginsync=true\n",
"[agent]\n",
" classfile=$vardir/classes.txt\n",
" localconfig=$vardir/localconfig\n",
" server=",{ "Ref" : "PuppetMasterDNSName" },"\n"
]] },
"mode" : "000644",
"owner" : "root",
"group" : "root"
}
},
"services" : {
"sysvinit" : {
"puppet" : {
"enabled" : "true",
"ensureRunning" : "true"
}
}
}
}
},
"Puppet" : {
"roles" : [ "wordpress" ],
"host" : {"Fn::GetAtt" : ["WordPressDatabase", "Endpoint.Address"]},
"database" : "WordPressDB",
"user" : {"Ref" : "DatabaseUser"},
"password" : {"Ref" : "DatabasePassword" }
}
},
"Properties": {
"SecurityGroups": [ { "Ref": "PuppetClientSecurityGroup" }, { "Ref" : "EC2SecurityGroup" } ],
"ImageId": { "Fn::FindInMap": [ "AWSRegionArch2AMI", { "Ref": "AWS::Region" }, { "Fn::FindInMap": [ "AWSInstanceType2Arch", { "Ref": "InstanceType" }, "Arch" ] } ]
},
"UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
"#!/bin/bash\n",
"yum update -y aws-cfn-bootstrap\n",
"/opt/aws/bin/cfn-init --region ", { "Ref" : "AWS::Region" },
" -s ", { "Ref" : "AWS::StackName" }, " -r WebServer ",
" --access-key ", { "Ref" : "CFNKeys" },
" --secret-key ", { "Fn::GetAtt" : ["CFNKeys", "SecretAccessKey"]}, "\n",
"/opt/aws/bin/cfn-signal -e $? '", { "Ref" : "ApplicationWaitHandle" }, "'\n"
]]}},
"KeyName": { "Ref": "KeyName" },
"InstanceType": { "Ref": "InstanceType" }
}
},
"EC2SecurityGroup" : {
"Type" : "AWS::EC2::SecurityGroup",
"Properties" : {
"GroupDescription" : "Enable HTTP access for Wordpress plus SSH access via port 22",
"SecurityGroupIngress" : [
{"IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : "0.0.0.0/0" },
{"IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0" }
]
}
},
"ApplicationWaitHandle" : {
"Type" : "AWS::CloudFormation::WaitConditionHandle"
},
"ApplicationWaitCondition" : {
"Type" : "AWS::CloudFormation::WaitCondition",
"DependsOn" : "WebServer",
"Properties" : {
"Handle" : { "Ref" : "ApplicationWaitHandle" },
"Timeout" : "600"
}
},
"WordPressDatabase" : {
"Type" : "AWS::RDS::DBInstance",
"Properties" : {
"AllocatedStorage" : "5",
"DBName" : "WordPressDB",
"Engine" : "MySQL",
"DBInstanceClass" : { "Ref" : "DatabaseType" },
"DBSecurityGroups" : [ { "Ref": "DBSecurityGroup" } ],
"MasterUsername" : { "Ref" : "DatabaseUser" },
"MasterUserPassword" : { "Ref" : "DatabasePassword" }
}
},
"DBSecurityGroup": {
"Type": "AWS::RDS::DBSecurityGroup",
"Properties": {
"DBSecurityGroupIngress": {
"EC2SecurityGroupName": { "Ref": "EC2SecurityGroup" }
},
"GroupDescription": "database access"
}
}
},
"Outputs": {
"WebsiteURL": {
"Value": { "Fn::Join": [ "", [ "http://", { "Fn::GetAtt": [ "WebServer", "PublicDnsName" ] }, "/wordpress" ] ] },
"Description" : "URL of the WordPress website"
},
"InstallURL": {
"Value": { "Fn::Join": [ "", [ "http://", { "Fn::GetAtt": [ "WebServer", "PublicDnsName" ] }, "/wordpress/wp-admin/install.php" ] ] },
"Description" : "URL to install WordPress"
}
}
}