1
0
Fork 0
mirror of https://github.com/fog/fog.git synced 2022-11-09 13:51:43 -05:00

Merge pull request #2638 from sugarb/elasticache_create_cache_subnet_group

Tests and fixes for Elasticache VPC subnet groups
This commit is contained in:
Wesley Beary 2014-02-03 13:42:07 -08:00
commit 944f19a0e5
15 changed files with 490 additions and 16 deletions

View file

@ -33,6 +33,10 @@ module Fog
request :authorize_cache_security_group_ingress
request :revoke_cache_security_group_ingress
request :create_cache_subnet_group
request :describe_cache_subnet_groups
request :delete_cache_subnet_group
request :describe_events
model_path 'fog/aws/models/elasticache'
@ -42,6 +46,8 @@ module Fog
collection :security_groups
model :parameter_group
collection :parameter_groups
model :subnet_group
collection :subnet_groups
class Real
include Fog::AWS::CredentialFetcher::ConnectionMethods
@ -89,8 +95,7 @@ module Fog
:host => @host,
:path => @path,
:port => @port,
#:version => '2011-07-15'
:version => '2012-11-15'
:version => '2013-06-15'
}
)
@ -100,7 +105,6 @@ module Fog
:expects => 200,
:headers => { 'Content-Type' => 'application/x-www-form-urlencoded' },
:idempotent => idempotent,
:host => @host,
:method => 'POST',
:parser => parser
})
@ -132,6 +136,7 @@ module Fog
region_hash[key] = {
:clusters => {}, # cache cluster data, indexed by cluster ID
:security_groups => {}, # security groups
:subnet_groups => {},
}
end
end

View file

@ -28,6 +28,10 @@ module Fog
:aliases => 'CacheSecurityGroups', :type => :array
attribute :notification_config,
:aliases => 'NotificationConfiguration', :type => :hash
attribute :cache_subnet_group_name,
:aliases => 'CacheSubnetGroupName'
attribute :vpc_security_groups,
:aliases => 'VpcSecurityGroups', :type => :array
attr_accessor :parameter_group_name
@ -60,6 +64,8 @@ module Fog
:preferred_availablility_zone => zone,
:preferred_maintenance_window => maintenance_window,
:parameter_group_name => parameter_group_name || parameter_group['CacheParameterGroupName'],
:cache_subnet_group_name => cache_subnet_group_name,
:vpc_security_groups => vpc_security_groups,
}
)
end

View file

@ -0,0 +1,35 @@
require 'fog/core/model'
module Fog
module AWS
class Elasticache
class SubnetGroup < Fog::Model
identity :id, :aliases => ['CacheSubnetGroupName', :name]
attribute :description, :aliases => 'CacheSubnetGroupDescription'
attribute :vpc_id, :aliases => 'VpcId'
attribute :subnet_ids, :aliases => 'Subnets'
def ready?
# Just returning true, as Elasticache subnet groups
# seem to not have a status, unlike RDS subnet groups.
true
end
def save
requires :description, :id, :subnet_ids
service.create_cache_subnet_group(id, subnet_ids, description)
reload
end
def destroy
requires :id
service.delete_cache_subnet_group(id)
true
end
end
end
end
end

View file

@ -0,0 +1,27 @@
require 'fog/core/collection'
require 'fog/aws/models/elasticache/subnet_group'
module Fog
module AWS
class Elasticache
class SubnetGroups < Fog::Collection
model Fog::AWS::Elasticache::SubnetGroup
def all
data = service.describe_cache_subnet_groups.body['DescribeCacheSubnetGroupsResult']['CacheSubnetGroups']
load(data) # data is an array of attribute hashes
end
def get(identity)
data = service.describe_cache_subnet_groups(identity).body['DescribeCacheSubnetGroupsResult']['CacheSubnetGroups'].first
new(data) # data is an attribute hash
rescue Fog::AWS::Elasticache::NotFound
nil
end
end
end
end
end

View file

@ -51,8 +51,8 @@ module Fog
@cache_cluster[name] = DateTime.parse(value)
when 'CacheSecurityGroup'
@cache_cluster["#{name}s"] << @security_group unless @security_group.empty?
when 'CacheSecurityGroupName', 'Status'
@security_group[name] = value
when 'CacheSecurityGroupName', 'Status', 'CacheSubnetGroupName'
@cache_cluster[name] = value
when 'CacheNode'
@cache_cluster["#{name}s"] << @cache_node unless @cache_node.empty?
@cache_node = nil

View file

@ -0,0 +1,38 @@
module Fog
module Parsers
module AWS
module Elasticache
require 'fog/aws/parsers/elasticache/subnet_group_parser'
class CreateCacheSubnetGroup < Fog::Parsers::AWS::Elasticache::SubnetGroupParser
def reset
@response = { 'CreateCacheSubnetGroupResult' => {}, 'ResponseMetadata' => {} }
super
end
def start_element(name, attrs = [])
super
end
def end_element(name)
case name
when 'DBSubnetGroup' then
@response['CreateCacheSubnetGroupResult']['CacheSubnetGroup'] = @cache_subnet_group
@cache_subnet_group = fresh_subnet_group
when 'RequestId'
@response['ResponseMetadata'][name] = value
else
super
end
end
end
end
end
end
end

View file

@ -0,0 +1,38 @@
module Fog
module Parsers
module AWS
module Elasticache
require 'fog/aws/parsers/elasticache/subnet_group_parser'
class DescribeCacheSubnetGroups < Fog::Parsers::AWS::Elasticache::SubnetGroupParser
def reset
@response = { 'DescribeCacheSubnetGroupsResult' => {'CacheSubnetGroups' => []}, 'ResponseMetadata' => {} }
super
end
def start_element(name, attrs = [])
super
end
def end_element(name)
case name
when 'CacheSubnetGroup'
@response['DescribeCacheSubnetGroupsResult']['CacheSubnetGroups'] << @cache_subnet_group
@cache_subnet_group = fresh_subnet_group
when 'Marker'
@response['DescribeCacheSubnetGroupsResult']['Marker'] = value
when 'RequestId'
@response['ResponseMetadata'][name] = value
else
super
end
end
end
end
end
end
end

View file

@ -0,0 +1,38 @@
module Fog
module Parsers
module AWS
module Elasticache
class SubnetGroupParser < Fog::Parsers::Base
def reset
@cache_subnet_group = fresh_subnet_group
end
def start_element(name, attrs = [])
super
end
def end_element(name)
case name
when 'VpcId' then @cache_subnet_group['VpcId'] = value
when 'SubnetGroupStatus' then @cache_subnet_group['SubnetGroupStatus'] = value
when 'CacheSubnetGroupDescription' then @cache_subnet_group['CacheSubnetGroupDescription'] = value
when 'CacheSubnetGroupName' then @cache_subnet_group['CacheSubnetGroupName'] = value
when 'SubnetIdentifier' then @cache_subnet_group['Subnets'] << value
when 'Marker'
@response['DescribeCacheSubnetGroupsResult']['Marker'] = value
when 'RequestId'
@response['ResponseMetadata'][name] = value
end
end
def fresh_subnet_group
{'Subnets' => []}
end
end
end
end
end
end

View file

@ -12,6 +12,7 @@ module Fog
# * options <~Hash> - All optional parameters should be set in this Hash:
# * :node_type <~String> - The size (flavor) of the cache Nodes
# * :security_group_names <~Array> - Array of Elasticache::SecurityGroup names
# * :vpc_security_groups <~Array> - Array
# * :num_nodes <~Integer> - The number of nodes in the Cluster
# * :auto_minor_version_upgrade <~TrueFalseClass>
# * :parameter_group_name <~String> - Name of the Cluster's ParameterGroup
@ -21,20 +22,13 @@ module Fog
# * :port <~Integer> - The memcached port number
# * :preferred_availablility_zone <~String>
# * :preferred_maintenance_window <~String>
# * :cache_subnet_group_name <~String>
# === Returns
# * response <~Excon::Response>:
# * body <~Hash>
def create_cache_cluster(id, options = {})
# Construct Cache Security Group parameters in the format:
# CacheSecurityGroupNames.member.N => "security_group_name"
group_names = options[:security_group_names] || ['default']
sec_group_params = group_names.inject({}) do |group_hash, name|
index = group_names.index(name) + 1
group_hash["CacheSecurityGroupNames.member.#{index}"] = name
group_hash
end
# Merge the Cache Security Group parameters with the normal options
request(sec_group_params.merge(
req_options = {
'Action' => 'CreateCacheCluster',
'CacheClusterId' => id.strip,
'CacheNodeType' => options[:node_type] || 'cache.m1.large',
@ -42,13 +36,25 @@ module Fog
'NumCacheNodes' => options[:num_nodes] || 1,
'AutoMinorVersionUpgrade' => options[:auto_minor_version_upgrade],
'CacheParameterGroupName' => options[:parameter_group_name],
'CacheSubnetGroupName' => options[:cache_subnet_group_name],
'EngineVersion' => options[:engine_version],
'NotificationTopicArn' => options[:notification_topic_arn],
'Port' => options[:port],
'PreferredAvailabilityZone' => options[:preferred_availablility_zone],
'PreferredMaintenanceWindow' => options[:preferred_maintenance_window],
:parser => Fog::Parsers::AWS::Elasticache::SingleCacheCluster.new
))
}
if cache_security_groups = options.delete(:security_group_names)
req_options.merge!(Fog::AWS.indexed_param('CacheSecurityGroupNames.member.%d', [*cache_security_groups]))
end
if vpc_security_groups = options.delete(:vpc_security_groups)
req_options.merge!(Fog::AWS.indexed_param('SecurityGroupIds.member.%d', [*vpc_security_groups]))
end
request( req_options )
end
end
@ -66,6 +72,7 @@ module Fog
'CacheSecurityGroups' => [],
'CacheParameterGroup' => { 'CacheParameterGroupName' =>
options[:parameter_group_name] || 'default.memcached1.4' },
'CacheSubnetGroupName' => options[:cache_subnet_group_name],
'PendingModifiedValues' => {},
'AutoMinorVersionUpgrade' =>
options[:auto_minor_version_upgrade] || 'true',

View file

@ -0,0 +1,62 @@
module Fog
module AWS
class Elasticache
class Real
require 'fog/aws/parsers/elasticache/create_cache_subnet_group'
# Creates a cache subnet group
# http://docs.aws.amazon.com/AmazonElastiCache/latest/APIReference/API_CreateCacheSubnetGroup.html
#
# ==== Parameters
# * CacheSubnetGroupName <~String> - A name for the cache subnet group. This value is stored as a lowercase string. Must contain no more than 255 alphanumeric characters or hyphens.
# * SubnetIds <~Array> - The VPC subnet IDs for the cache subnet group.
# * CacheSubnetGroupDescription <~String> - A description for the cache subnet group.
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
def create_cache_subnet_group(name, subnet_ids, description = name)
params = {
'Action' => 'CreateCacheSubnetGroup',
'CacheSubnetGroupName' => name,
'CacheSubnetGroupDescription' => description,
:parser => Fog::Parsers::AWS::Elasticache::CreateCacheSubnetGroup.new
}
params.merge!(Fog::AWS.indexed_param("SubnetIds.member", Array(subnet_ids)))
request(params)
end
end
class Mock
def create_cache_subnet_group(name, subnet_ids, description = name)
response = Excon::Response.new
if self.data[:subnet_groups] && self.data[:subnet_groups][name]
raise Fog::AWS::Elasticache::IdentifierTaken.new("CacheSubnetGroupAlreadyExists => The subnet group '#{name}' already exists")
end
subnets = subnet_ids.map { |snid| Fog::Compute[:aws].subnets.get(snid) }
vpc_id = subnets.first.vpc_id
data = {
'CacheSubnetGroupName' => name,
'CacheSubnetGroupDescription' => description,
'SubnetGroupStatus' => 'Complete',
'Subnets' => subnet_ids,
'VpcId' => vpc_id
}
self.data[:subnet_groups][name] = data
response.body = {
"ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id },
'CreateCacheSubnetGroupResult' => { 'CacheSubnetGroup' => data }
}
response
end
end
end
end
end

View file

@ -0,0 +1,40 @@
module Fog
module AWS
class Elasticache
class Real
require 'fog/aws/parsers/elasticache/base'
# deletes a cache subnet group
#
# === Parameters
# * name <~String> - The name for the Cache Subnet Group
# === Returns
# * response <~Excon::Response>:
# * body <~Hash>
def delete_cache_subnet_group(name)
request({
'Action' => 'DeleteCacheSubnetGroup',
'CacheSubnetGroupName' => name,
:parser => Fog::Parsers::AWS::Elasticache::Base.new
})
end
end
class Mock
def delete_cache_subnet_group(name)
if self.data[:subnet_groups].delete(name)
Excon::Response.new(
{
:status => 200,
:body => { 'ResponseMetadata'=>{ 'RequestId'=> Fog::AWS::Mock.request_id } }
}
)
else
raise Fog::AWS::Elasticache::NotFound.new("CacheSubnetGroupNotFound => #{name} not found")
end
end
end
end
end
end

View file

@ -0,0 +1,63 @@
module Fog
module AWS
class Elasticache
class Real
require 'fog/aws/parsers/elasticache/describe_cache_subnet_groups'
# This API returns a list of CacheSubnetGroup descriptions. If a CacheSubnetGroupName is specified, the list will contain only
# the descriptions of the specified CacheSubnetGroup
# http://docs.aws.amazon.com/AmazonElastiCache/latest/APIReference/API_DescribeCacheSubnetGroups.html
# ==== Parameters
# * CacheSubnetGroupName <~String> - The name of a specific database subnet group to return details for.
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
def describe_cache_subnet_groups(name = nil, opts = {})
params = {}
if opts[:marker]
params['Marker'] = opts[:marker]
end
if name
params['CacheSubnetGroupName'] = name
end
if opts[:max_records]
params['MaxRecords'] = opts[:max_records]
end
request({
'Action' => 'DescribeCacheSubnetGroups',
:parser => Fog::Parsers::AWS::Elasticache::DescribeCacheSubnetGroups.new
}.merge(params))
end
end
class Mock
def describe_cache_subnet_groups(name = nil, opts = {})
response = Excon::Response.new
subnet_group_set = []
if name
if subnet_group = self.data[:subnet_groups][name]
subnet_group_set << subnet_group
else
raise Fog::AWS::Elasticache::NotFound.new("Subnet Group #{name} not found")
end
else
subnet_group_set = self.data[:subnet_groups].values
end
response.status = 200
response.body = {
"ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id },
"DescribeCacheSubnetGroupsResult" => { "CacheSubnetGroups" => subnet_group_set }
}
response
end
end
end
end
end

View file

@ -0,0 +1,44 @@
Shindo.tests('AWS::Elasticache | subnet group', ['aws', 'elasticache']) do
# random_differentiator
# Useful when rapidly re-running tests, so we don't have to wait
# serveral minutes for deleted VPCs/subnets to disappear
suffix = rand(65536).to_s(16)
@subnet_group_name = "fog-test-#{suffix}"
vpc_range = rand(245) + 10
@vpc = Fog::Compute[:aws].vpcs.create('cidr_block' => "10.#{vpc_range}.0.0/16")
# Create 4 subnets in this VPC, each one in a different AZ
subnet_az = 'us-east-1a'
subnet_range = 8
@subnets = (1..3).map do
result = Fog::Compute[:aws].create_subnet(@vpc.id, "10.#{vpc_range}.#{subnet_range}.0/24",
'AvailabilityZone' => subnet_az)
puts result
subnet = result.body['subnet']
subnet_az = subnet_az.succ
subnet_range *= 2
subnet
end
tests('success') do
group_name = 'fog-test'
description = 'Fog Test'
subnet_ids = @subnets.map { |sn| sn['subnetId'] }.to_a
model_tests(
AWS[:elasticache].subnet_groups,
{:name => group_name, :subnet_ids => subnet_ids, :description => description}, true
)
collection_tests(
AWS[:elasticache].subnet_groups,
{:name => group_name, :subnet_ids => subnet_ids, :description => description}, true
)
end
@subnets.each do |sn|
Fog::Compute[:aws].delete_subnet(sn['subnetId'])
end
@vpc.destroy
end

View file

@ -16,6 +16,25 @@ class AWS
SINGLE_SECURITY_GROUP = BASIC.merge('CacheSecurityGroup' => SECURITY_GROUP)
DESCRIBE_SECURITY_GROUPS = {'CacheSecurityGroups' => [SECURITY_GROUP]}
CACHE_SUBNET_GROUP = {
'CacheSubnetGroupName' => String,
'CacheSubnetGroupDescription' => String,
'VpcId' => String,
'Subnets' => [String]
}
CREATE_CACHE_SUBNET_GROUP = BASIC.merge({
'CreateCacheSubnetGroupResult' => {
'CacheSubnetGroup' => CACHE_SUBNET_GROUP
}
})
DESCRIBE_CACHE_SUBNET_GROUPS = BASIC.merge({
'DescribeCacheSubnetGroupsResult' => {
'CacheSubnetGroups' => [CACHE_SUBNET_GROUP]
}
})
# Cache Parameter Groups
PARAMETER_GROUP = {
'CacheParameterGroupFamily' => String,

View file

@ -0,0 +1,52 @@
Shindo.tests('AWS::Elasticache | subnet group requests', ['aws', 'elasticache']) do
# random_differentiator
# Useful when rapidly re-running tests, so we don't have to wait
# serveral minutes for deleted VPCs/subnets to disappear
suffix = rand(65536).to_s(16)
@subnet_group_name = "fog-test-#{suffix}"
vpc_range = rand(245) + 10
@vpc = Fog::Compute[:aws].vpcs.create('cidr_block' => "10.#{vpc_range}.0.0/16")
# Create 4 subnets in this VPC, each one in a different AZ
subnet_az = 'us-east-1a'
subnet_range = 8
@subnets = (1..4).map do
subnet = Fog::Compute[:aws].create_subnet(@vpc.id, "10.#{vpc_range}.#{subnet_range}.0/24",
'AvailabilityZone' => subnet_az).body['subnet']
subnet_az = subnet_az.succ
subnet_range *= 2
subnet
end
tests('success') do
subnet_ids = @subnets.map { |sn| sn['subnetId'] }.to_a
tests("#create_cache_subnet_group").formats(AWS::Elasticache::Formats::CREATE_CACHE_SUBNET_GROUP) do
result = Fog::AWS[:elasticache].create_cache_subnet_group(@subnet_group_name, subnet_ids, 'A subnet group').body
returns(@subnet_group_name) { result['CreateCacheSubnetGroupResult']['CacheSubnetGroup']['CacheSubnetGroupName'] }
returns('A subnet group') { result['CreateCacheSubnetGroupResult']['CacheSubnetGroup']['CacheSubnetGroupDescription'] }
returns(@vpc.id) { result['CreateCacheSubnetGroupResult']['CacheSubnetGroup']['VpcId'] }
returns(subnet_ids.sort) { result['CreateCacheSubnetGroupResult']['CacheSubnetGroup']['Subnets'].sort }
result
end
tests("#describe_cache_subnet_groups").formats(AWS::Elasticache::Formats::DESCRIBE_CACHE_SUBNET_GROUPS) do
Fog::AWS[:elasticache].describe_cache_subnet_groups.body
end
tests("#delete_cache_subnet_group").formats(AWS::Elasticache::Formats::BASIC) do
Fog::AWS[:elasticache].delete_cache_subnet_group(@subnet_group_name).body
end
end
@subnets.each do |sn|
Fog::Compute[:aws].delete_subnet(sn['subnetId'])
end
@vpc.destroy
end