diff --git a/lib/fog/aws/elasticache.rb b/lib/fog/aws/elasticache.rb index 9fb76ddd5..b448f9bea 100644 --- a/lib/fog/aws/elasticache.rb +++ b/lib/fog/aws/elasticache.rb @@ -9,9 +9,9 @@ module Fog request_path 'fog/aws/requests/elasticache' - #request :create_cache_cluster + request :create_cache_cluster #request :delete_cache_cluster - #request :describe_cache_clusters + request :describe_cache_clusters #request :modify_cache_cluster #request :reboot_cache_cluster diff --git a/lib/fog/aws/parsers/elasticache/cache_cluster_parser.rb b/lib/fog/aws/parsers/elasticache/cache_cluster_parser.rb new file mode 100644 index 000000000..8ac2998f3 --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/cache_cluster_parser.rb @@ -0,0 +1,53 @@ +module Fog + module Parsers + module AWS + module Elasticache + require 'fog/aws/parsers/elasticache/base' + + class CacheClusterParser < Base + + def reset + super + reset_cache_cluster + end + + def reset_cache_cluster + @cache_cluster = { + 'CacheSecurityGroups' => [], + 'CacheParameterGroup' => {} + } + end + + def start_element(name, attrs = []) + super + case name + when 'CacheSecurityGroup'; then @security_group = {} + end + + end + + def end_element(name) + case name + when 'AutoMinorVersionUpgrade', 'CacheClusterId', + 'CacheClusterStatus', 'CacheNodeType', 'Engine', 'EngineVersion', + 'PreferredAvailabilityZone', 'PreferredMaintenanceWindow' + @cache_cluster[name] = value + when 'NumCacheNodes' + @cache_cluster[name] = value.to_i + when 'CacheClusterCreateTime' + @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 'CacheNodeIdsToReboots', 'CacheParameterGroupName', 'ParameterApplyStatus' + @cache_cluster['CacheParameterGroup'][name] = value + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/describe_cache_clusters.rb b/lib/fog/aws/parsers/elasticache/describe_cache_clusters.rb new file mode 100644 index 000000000..56a57bac9 --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/describe_cache_clusters.rb @@ -0,0 +1,27 @@ +module Fog + module Parsers + module AWS + module Elasticache + require 'fog/aws/parsers/elasticache/cache_cluster_parser' + + class DescribeCacheClusters < CacheClusterParser + + def reset + super + @response['CacheClusters'] = [] + end + + def end_element(name) + case name + when 'CacheCluster' + @response["#{name}s"] << @cache_cluster + reset_cache_cluster + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/parsers/elasticache/single_cache_cluster.rb b/lib/fog/aws/parsers/elasticache/single_cache_cluster.rb new file mode 100644 index 000000000..49673c742 --- /dev/null +++ b/lib/fog/aws/parsers/elasticache/single_cache_cluster.rb @@ -0,0 +1,22 @@ +module Fog + module Parsers + module AWS + module Elasticache + require 'fog/aws/parsers/elasticache/cache_cluster_parser' + + class SingleCacheCluster < CacheClusterParser + + def end_element(name) + case name + when 'CacheCluster' + @response[name] = @cache_cluster + reset_cache_cluster + else + super + end + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/create_cache_cluster.rb b/lib/fog/aws/requests/elasticache/create_cache_cluster.rb new file mode 100644 index 000000000..e6fbe0572 --- /dev/null +++ b/lib/fog/aws/requests/elasticache/create_cache_cluster.rb @@ -0,0 +1,56 @@ +module Fog + module AWS + class Elasticache + class Real + + require 'fog/aws/parsers/elasticache/single_cache_cluster' + # creates a cache cluster + # + # === Required Parameters + # * options <~Hash> - The all parameters should be set in this Hash: + # * :cluster_id <~String> - The name of the Cache Cluster + # * :node_type <~String> - The size (flavor) of the cache Nodes + # * :security_group_names <~Array> - Array of Elasticache::SecurityGroup names + # * :num_nodes <~Integer> - The number of nodes in the Cluster + # === Optional Parameters (also set in the options hash) + # * :auto_minor_version_upgrade <~TrueFalseClass> + # * :parameter_group_name <~String> - Name of the Cluster's ParameterGroup + # * :engine <~String> - The Cluster's caching software (memcached) + # * :engine_version <~String> - The Cluster's caching software version + # * :notification_topic_arn <~String> - Amazon SNS Resource Name + # * :cluster_id <~String> - The name of the Cache Cluster + # * :port <~Integer> - The memcached port number + # * :preferred_availablility_zone <~String> + # * :preferred_maintenance_window <~String> + # === Returns + # * response <~Excon::Response>: + # * body <~Hash> + def create_cache_cluster(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( + 'Action' => 'CreateCacheCluster', + 'CacheClusterId' => options[:cluster_id], + 'CacheNodeType' => options[:node_type] || 'cache.m1.large', + 'Engine' => options[:engine] || 'memcached', + 'NumCacheNodes' => options[:num_nodes] || 1 , + :parser => Fog::Parsers::AWS::Elasticache::SingleCacheCluster.new + )) + end + end + + class Mock + def create_cache_cluster(options) + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/aws/requests/elasticache/describe_cache_clusters.rb b/lib/fog/aws/requests/elasticache/describe_cache_clusters.rb new file mode 100644 index 000000000..4c61c6035 --- /dev/null +++ b/lib/fog/aws/requests/elasticache/describe_cache_clusters.rb @@ -0,0 +1,35 @@ +module Fog + module AWS + class Elasticache + class Real + + require 'fog/aws/parsers/elasticache/describe_cache_clusters' + + # Returns a list of CacheCluster descriptions + # + # === Parameters + # * options <~Hash> (optional): + # * CacheClusterId<~String> - The name of the cache security group + # * Marker <~String> - marker provided in the previous request + # * MaxRecords <~String> - the maximum number of records to include + # * ShowCacheNodeInfo <~Boolean> - whether to show node info + # === Returns + # * response <~Excon::Response>: + # * body <~Hash> + def describe_cache_clusters(options = {}) + request({ + 'Action' => 'DescribeCacheClusters', + :parser => Fog::Parsers::AWS::Elasticache::DescribeCacheClusters.new + }.merge(options)) + end + + end + + class Mock + def describe_cache_clusters + Fog::Mock.not_implemented + end + end + end + end +end diff --git a/lib/fog/bin/aws.rb b/lib/fog/bin/aws.rb index cb746a5df..950079537 100644 --- a/lib/fog/bin/aws.rb +++ b/lib/fog/bin/aws.rb @@ -3,8 +3,6 @@ class AWS < Fog::Bin def class_for(key) case key - when :elasticache - Fog::AWS::Elasticache when :auto_scaling Fog::AWS::AutoScaling when :cdn @@ -17,6 +15,8 @@ class AWS < Fog::Bin Fog::Compute::AWS when :dns Fog::DNS::AWS + when :elasticache + Fog::AWS::Elasticache when :elb Fog::AWS::ELB when :iam @@ -44,8 +44,6 @@ class AWS < Fog::Bin def [](service) @@connections ||= Hash.new do |hash, key| hash[key] = case key - when :elasticache - Fog::AWS::Elasticache.new when :auto_scaling Fog::AWS::AutoScaling.new when :cdn @@ -61,6 +59,8 @@ class AWS < Fog::Bin when :dns Fog::Logger.warning("AWS[:dns] is deprecated, use DNS[:aws] instead") Fog::DNS.new(:provider => 'AWS') + when :elasticache + Fog::AWS::Elasticache.new when :elb Fog::AWS::ELB.new when :iam diff --git a/tests/aws/requests/elasticache/cache_cluster_tests.rb b/tests/aws/requests/elasticache/cache_cluster_tests.rb new file mode 100644 index 000000000..e84755210 --- /dev/null +++ b/tests/aws/requests/elasticache/cache_cluster_tests.rb @@ -0,0 +1,65 @@ +Shindo.tests('AWS::Elasticache | cache cluster requests', ['aws', 'elasticache']) do + + tests('success') do + pending if Fog.mocking? + + cluster_id = 'fog-test-cluster' + + tests( + '#create_cache_cluster' + ).formats(AWS::Elasticache::Formats::SINGLE_CACHE_CLUSTER) do + body = AWS[:elasticache].create_cache_cluster( + :cluster_id => cluster_id + ).body + cluster = body['CacheCluster'] + returns(cluster_id) { cluster['CacheClusterId'] } + returns('creating') { cluster['CacheClusterStatus'] } + body + end + + tests( + '#describe_cache_clusters without options' + ).formats(AWS::Elasticache::Formats::DESCRIBE_CACHE_CLUSTERS) do + body = AWS[:elasticache].describe_cache_clusters.body + returns(true, "has #{cluster_id}") do + body['CacheClusters'].any? do |cluster| + cluster['CacheClusterId'] == cluster_id + end + end + body + end + + tests( + '#describe_cache_clusters with cluster ID' + ).formats(AWS::Elasticache::Formats::DESCRIBE_CACHE_CLUSTERS) do + body = AWS[:elasticache].describe_cache_clusters( + 'CacheClusterId' => cluster_id + ).body + returns(1, "size of 1") { body['CacheClusters'].size } + returns(cluster_id, "has #{cluster_id}") do + body['CacheClusters'].first['CacheClusterId'] + end + body + end + + #cluster = AWS[:elasticache].clusters.get(cluster_id) + #cluster.wait_for {ready?} + # + #tests( + #'#delete_cache_security_group' + #).formats(AWS::Elasticache::Formats::SINGLE_CACHE_CLUSTER) do + # body = AWS[:elasticache].delete_cache_security_group(cluster_id).body + #cluster = body['CacheCluster'] + #returns(cluster_id) { cluster['CacheClusterId'] } + #returns('deleting') { cluster['CacheClusterStatus'] } + #body + #end + end + + tests('failure') do + # TODO: + # Create a duplicate cluster ID + # List a missing cache cluster + # Delete a missing cache cluster + end +end diff --git a/tests/aws/requests/elasticache/helper.rb b/tests/aws/requests/elasticache/helper.rb index bc10d55b9..38b6c0d22 100644 --- a/tests/aws/requests/elasticache/helper.rb +++ b/tests/aws/requests/elasticache/helper.rb @@ -6,17 +6,40 @@ class AWS 'ResponseMetadata' => {'RequestId' => String} } + # Cache Security Groups SECURITY_GROUP = { - 'EC2SecurityGroups' => Array, - 'CacheSecurityGroupName' => String, - 'Description' => String, - 'OwnerId' => String + 'EC2SecurityGroups' => Array, + 'CacheSecurityGroupName' => String, + 'Description' => String, + 'OwnerId' => String, } - SINGLE_SECURITY_GROUP = BASIC.merge('CacheSecurityGroup' => SECURITY_GROUP) DESCRIBE_SECURITY_GROUPS = BASIC.merge('CacheSecurityGroups' => [SECURITY_GROUP]) - + # Cache Clusters - more parameters get added as the lifecycle progresses + CACHE_CLUSTER = { + 'AutoMinorVersionUpgrade' => String, # actually TrueClass or FalseClass + 'CacheSecurityGroups' => Array, + 'CacheClusterId' => String, + 'CacheClusterStatus' => String, + 'CacheNodeType' => String, + 'Engine' => String, + 'EngineVersion' => String, + 'CacheParameterGroup' => Hash, + 'NumCacheNodes' => Integer, + 'PreferredMaintenanceWindow' => String, + } + CACHE_CLUSTER_RUNNING = CACHE_CLUSTER.merge( + 'CacheClusterCreateTime' => DateTime, + 'PreferredAvailabilityZone' => String, + 'CacheNodes' => Array + ) + CACHE_CLUSTER_MODIFIED = CACHE_CLUSTER_RUNNING.merge( + 'NotificationConfiguration' => Hash, + 'PendingModifiedValues' => Hash + ) + SINGLE_CACHE_CLUSTER = BASIC.merge('CacheCluster' => CACHE_CLUSTER) + DESCRIBE_CACHE_CLUSTERS = BASIC.merge('CacheClusters' => [CACHE_CLUSTER]) end end end