# Copyright 2011-2012 Amazon.com, Inc. or its affiliates. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"). You # may not use this file except in compliance with the License. A copy of # the License is located at # # http://aws.amazon.com/apache2.0/ # # or in the "license" file accompanying this file. This file 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. require 'aws/core' require 'aws/cloud_formation/config' module AWS # = AWS::CloudFormation # # Provides an expressive, object-oriented interface to AWS CloudFormation. # # == Credentials # # You can setup default credentials for all AWS services via # AWS.config: # # AWS.config( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # Or you can set them directly on the CloudFormation interface: # # cf = AWS::CloudFormation.new( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # = Stacks # # This is the starting point for working with CloudFormation. # # == Creating a Stack # # You can create a CloudFormation stack with a name and a template. # # template = <<-TEMPLATE # { # "AWSTemplateFormatVersion" : "2010-09-09", # "Description": "A simple template", # "Resources": { # "web": { # "Type": "AWS::EC2::Instance", # "Properties": { # "ImageId": "ami-41814f28" # } # } # } # } # TEMPLATE # # cfm = AWS::CloudFormation.new # stack = cfm.stacks.create('stack-name', template) # # See {StackCollection#create} for more information on creating templates # with capabilities and parameters. # # == Getting a Stack # # Given a name, you can fetch a {Stack}. # # stack = cfm.stacks['stack-name'] # # == Enumerating Stacks # # You can enumerate stacks in two ways. You can enumerate {Stack} # objects or stack summaries (simple hashes). You can filter the stack # summary collection by a status. # # # enumerating all stack objects # cfm.stacks.each do |stack| # # ... # end # # # enumerating stack summaries (hashes) # cfm.stack_summaries.each do |stack_summary| # # ... # end # # # filtering stack summaries by status # cfm.stack_summaries.with_status(:create_failed).each do |summary| # puts summary.to_yaml # end # # == Template # # You can fetch the template body for a stack as a JSON string. # # cfm.stacks['stack-name'].template # #=> "{...}" # # You can update the template for a {Stack} with the {Stack#update} method: # # cfm.stacks['stack-name'].update(:template => new_template) # # == Stack Events # # You can enumerate events for a stack. # # stack.events.each do |event| # puts "#{event.physical_resource_id}: #{event.resource_status}" # end # # See {StackEvent} for a complete list of event attributes. # # == Stack Resources # # You can enumerate stack resources or request a stack resource by its # logical resource id. # # # enumerating stack resources # stack.resources.each do |resource| # # ... # end # # # getting a resource by its logical id # res = stack.resources['logical-resource-id'] # puts res.physical_resource_id # # If you need a stack resource, but only have its physical resource # id, then you can call {CloudFormation#stack_resource}. # # stack_resource = cfm.stack_resource('physical-resource-id') # # == Stack Resource Summaries # # As an alternative to stack resources, you can enumerate stack # resource summaries (hashes). # # # enumerate all resources, this collection can not be filtered # stack.resource_summaries.each do |summary| # # ... # end # class CloudFormation AWS.register_autoloads(self, 'aws/cloud_formation') do autoload :Client, 'client' autoload :Errors, 'errors' autoload :Request, 'request' autoload :Stack, 'stack' autoload :StackCollection, 'stack_collection' autoload :StackEvent, 'stack_event' autoload :StackEventCollection, 'stack_event_collection' autoload :StackOptions, 'stack_options' autoload :StackOutput, 'stack_output' autoload :StackSummaryCollection, 'stack_summary_collection' autoload :StackResource, 'stack_resource' autoload :StackResourceCollection, 'stack_resource_collection' autoload :StackResourceSummaryCollection, 'stack_resource_summary_collection' end include Core::ServiceInterface include StackOptions # @return [StackCollection] def stacks StackCollection.new(:config => config) end # @return [StackSummaryCollection] def stack_summaries StackSummaryCollection.new(:config => config) end # Returns a stack resource with the given physical resource # id. # # resource = cfm.stack_resource('i-123456789') # # Alternatively, you may pass a stack name and logical resource id: # # resource = cfm.stack_resource('stack-name', 'logical-resource-id') # # @overload stack_resource(physical_resource_id) # @param [String] physical_resource_id The physical resource id # of the stack resource you want returned. # # @overload stack_resource(stack_name, logical_resource_id) # @param [String] stack_name # @param [String] logical_resource_id # # @return [StackResource] Returns the stack resource with the # given physical resource id. # def stack_resource *args client_opts = {} if args.size == 1 client_opts[:physical_resource_id] = args.first else client_opts[:stack_name] = args[0] client_opts[:logical_resource_id] = args[1] end response = client.describe_stack_resources(client_opts) details = response.stack_resources.first StackResource.new_from( :describe_stack_resource, details, Stack.new(details.stack_name, :config => config), details.logical_resource_id) end # Validates the template and returns a hash. If the template is valid, # the returned hash may/will contain the following keys (actual # key list depends on the template). # # * +:description+ # * +:capabilities+ # * +:capabilities_reason+ # * +:parameters+ # # If the template is not parseable, then a hash will the following # keys will be returned: # # * +:code+ # * +:message+ # # @return [Hash] # def validate_template template begin client_opts = {} client_opts[:template] = template apply_template(client_opts) resp = client.validate_template(client_opts) results = {} [ :capabilities, :capabilities_reason, :description, ].each do |method| if resp.respond_to?(method) results[method] = resp.send(method) end end if resp.respond_to?(:parameters) results[:parameters] = resp.parameters.collect(&:to_hash) end results rescue CloudFormation::Errors::ValidationError => e results = {} results[:code] = e.code results[:message] = e.message results end end # @param (see Stack#template=) # # @param [Hash] parameters A hash that specifies the input # parameters for the template. # # @return [String] Returns a URL to the AWS Simple Monthly Calculator # with a query string that describes the resources required to run # the template. # def estimate_template_cost template, parameters = {} client_opts = {} client_opts[:template] = template apply_template(client_opts) apply_parameters(client_opts) client.estimate_template_cost(client_opts).url end end end