cfn-bridge 0.0.9 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +50 -0
- data/lib/cloud_formation/bridge/cli.rb +4 -0
- data/lib/cloud_formation/bridge/executor.rb +10 -1
- data/lib/cloud_formation/bridge/names.rb +10 -0
- data/lib/cloud_formation/bridge/request.rb +7 -1
- data/lib/cloud_formation/bridge/resources/base.rb +14 -3
- data/lib/cloud_formation/bridge/resources/base_elasti_cache_resource.rb +58 -0
- data/lib/cloud_formation/bridge/resources/elasti_cache_node_urls.rb +35 -0
- data/lib/cloud_formation/bridge/resources/elasti_cache_replica_cluster.rb +66 -0
- data/lib/cloud_formation/bridge/resources/elasti_cache_replication_group.rb +67 -0
- data/lib/cloud_formation/bridge/util.rb +6 -0
- data/lib/cloud_formation/bridge/version.rb +1 -1
- data/spec/files/create-cache-node-urls-message.json +12 -0
- data/spec/files/create-redis-cache-node-urls-message.json +12 -0
- data/spec/files/create-replica-cluster-message.json +13 -0
- data/spec/files/create-replication-group-message.json +14 -0
- data/spec/files/delete-replica-cluster-message.json +14 -0
- data/spec/files/delete-replication-group-message.json +15 -0
- data/spec/files/describe-cache-cluster-primary.json +57 -0
- data/spec/files/describe-cache-cluster-replica-done.json +68 -0
- data/spec/files/describe-cache-cluster-replica.json +46 -0
- data/spec/files/describe-memcached-cluster.json +73 -0
- data/spec/files/describe-replication-group-primary-and-replica.json +49 -0
- data/spec/files/describe-replication-group-primary-only.json +38 -0
- data/spec/files/outputs-formation.json +0 -4
- data/spec/files/sample-replica-cluster.json +51 -0
- data/spec/files/sample-replication-group.json +34 -0
- data/spec/lib/cloud_formation/bridge/executor_spec.rb +1 -1
- data/spec/lib/cloud_formation/bridge/request_spec.rb +17 -5
- data/spec/lib/cloud_formation/bridge/resources/elasti_cache_node_urls_spec.rb +61 -0
- data/spec/lib/cloud_formation/bridge/resources/elasti_cache_replica_cluster_spec.rb +67 -0
- data/spec/lib/cloud_formation/bridge/resources/elasti_cache_replication_group_spec.rb +65 -0
- data/spec/support/file_support.rb +6 -0
- metadata +40 -2
@@ -0,0 +1,68 @@
|
|
1
|
+
{
|
2
|
+
"cache_clusters": [
|
3
|
+
{
|
4
|
+
"cache_security_groups": [
|
5
|
+
{
|
6
|
+
"cache_security_group_name": "redis-group",
|
7
|
+
"status": "active"
|
8
|
+
}
|
9
|
+
],
|
10
|
+
"cache_nodes": [
|
11
|
+
{
|
12
|
+
"parameter_group_status": "in-sync",
|
13
|
+
"cache_node_status": "available",
|
14
|
+
"cache_node_create_time": "2014-09-10 02:25:13 UTC",
|
15
|
+
"cache_node_id": "0001",
|
16
|
+
"customer_availability_zone": "us-east-1a",
|
17
|
+
"endpoint": {
|
18
|
+
"port": 6379,
|
19
|
+
"address": "dev-redis-replica.mzufvw.0001.use1.cache.amazonaws.com"
|
20
|
+
}
|
21
|
+
},
|
22
|
+
{
|
23
|
+
"parameter_group_status": "in-sync",
|
24
|
+
"cache_node_status": "available",
|
25
|
+
"cache_node_create_time": "2014-09-10 02:25:13 UTC",
|
26
|
+
"cache_node_id": "0001",
|
27
|
+
"customer_availability_zone": "us-east-1a",
|
28
|
+
"endpoint": {
|
29
|
+
"port": 6379,
|
30
|
+
"address": "dev-redis-replica.mzufvw.0002.use1.cache.amazonaws.com"
|
31
|
+
}
|
32
|
+
}
|
33
|
+
],
|
34
|
+
"security_groups": [
|
35
|
+
|
36
|
+
],
|
37
|
+
"cache_cluster_id": "dev-redis-replica",
|
38
|
+
"cache_parameter_group": {
|
39
|
+
"cache_node_ids_to_reboot": [
|
40
|
+
|
41
|
+
],
|
42
|
+
"cache_parameter_group_name": "default.redis2.8",
|
43
|
+
"parameter_apply_status": "in-sync"
|
44
|
+
},
|
45
|
+
"cache_cluster_status": "available",
|
46
|
+
"replication_group_id": "dev-redis-rep-group",
|
47
|
+
"cache_node_type": "cache.m1.small",
|
48
|
+
"engine": "redis",
|
49
|
+
"pending_modified_values": {
|
50
|
+
"cache_node_ids_to_remove": [
|
51
|
+
|
52
|
+
]
|
53
|
+
},
|
54
|
+
"preferred_availability_zone": "us-east-1a",
|
55
|
+
"cache_cluster_create_time": "2014-09-10 02:25:13 UTC",
|
56
|
+
"engine_version": "2.8.6",
|
57
|
+
"auto_minor_version_upgrade": true,
|
58
|
+
"preferred_maintenance_window": "thu:10:00-thu:11:00",
|
59
|
+
"client_download_landing_page": "https://console.aws.amazon.com/elasticache/home#client-download:",
|
60
|
+
"snapshot_retention_limit": 0,
|
61
|
+
"num_cache_nodes": 1,
|
62
|
+
"snapshot_window": "09:00-10:00"
|
63
|
+
}
|
64
|
+
],
|
65
|
+
"response_metadata": {
|
66
|
+
"request_id": "3913b189-3892-11e4-8c6b-f3805709d592"
|
67
|
+
}
|
68
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
{
|
2
|
+
"cache_clusters": [
|
3
|
+
{
|
4
|
+
"cache_security_groups": [
|
5
|
+
{
|
6
|
+
"cache_security_group_name": "redis-group",
|
7
|
+
"status": "active"
|
8
|
+
}
|
9
|
+
],
|
10
|
+
"cache_nodes": [
|
11
|
+
|
12
|
+
],
|
13
|
+
"security_groups": [
|
14
|
+
|
15
|
+
],
|
16
|
+
"cache_cluster_id": "dev-redis-replica",
|
17
|
+
"cache_parameter_group": {
|
18
|
+
"cache_node_ids_to_reboot": [
|
19
|
+
|
20
|
+
],
|
21
|
+
"parameter_apply_status": "in-sync",
|
22
|
+
"cache_parameter_group_name": "default.redis2.8"
|
23
|
+
},
|
24
|
+
"cache_cluster_status": "creating",
|
25
|
+
"replication_group_id": "dev-redis-rep-group",
|
26
|
+
"cache_node_type": "cache.m1.small",
|
27
|
+
"engine": "redis",
|
28
|
+
"pending_modified_values": {
|
29
|
+
"cache_node_ids_to_remove": [
|
30
|
+
|
31
|
+
]
|
32
|
+
},
|
33
|
+
"preferred_availability_zone": "us-east-1a",
|
34
|
+
"engine_version": "2.8.6",
|
35
|
+
"auto_minor_version_upgrade": true,
|
36
|
+
"preferred_maintenance_window": "thu:10:00-thu:11:00",
|
37
|
+
"client_download_landing_page": "https://console.aws.amazon.com/elasticache/home#client-download:",
|
38
|
+
"snapshot_retention_limit": 0,
|
39
|
+
"num_cache_nodes": 1,
|
40
|
+
"snapshot_window": "09:00-10:00"
|
41
|
+
}
|
42
|
+
],
|
43
|
+
"response_metadata": {
|
44
|
+
"request_id": "3d98e0e9-3891-11e4-8fa2-cfebce712279"
|
45
|
+
}
|
46
|
+
}
|
@@ -0,0 +1,73 @@
|
|
1
|
+
{ "cache_clusters": [
|
2
|
+
{
|
3
|
+
"auto_minor_version_upgrade": true,
|
4
|
+
"cache_cluster_create_time": "2013-05-28 07:42:19 UTC",
|
5
|
+
"cache_cluster_id": "somecache",
|
6
|
+
"cache_cluster_status": "available",
|
7
|
+
"cache_node_type": "cache.t1.micro",
|
8
|
+
"cache_nodes": [
|
9
|
+
{
|
10
|
+
"cache_node_create_time": "2013-05-28 07:42:19 UTC",
|
11
|
+
"cache_node_id": "0001",
|
12
|
+
"cache_node_status": "available",
|
13
|
+
"customer_availability_zone": "us-east-1a",
|
14
|
+
"endpoint": {
|
15
|
+
"address": "somecache.tgbhomz.0001.use1.cache.amazonaws.com",
|
16
|
+
"port": 11211
|
17
|
+
},
|
18
|
+
"parameter_group_status": "in-sync"
|
19
|
+
},
|
20
|
+
{
|
21
|
+
"cache_node_create_time": "2013-05-28 07:42:19 UTC",
|
22
|
+
"cache_node_id": "0002",
|
23
|
+
"cache_node_status": "available",
|
24
|
+
"customer_availability_zone": "us-east-1a",
|
25
|
+
"endpoint": {
|
26
|
+
"address": "somecache.tgbhomz.0002.use1.cache.amazonaws.com",
|
27
|
+
"port": 11211
|
28
|
+
},
|
29
|
+
"parameter_group_status": "in-sync"
|
30
|
+
},
|
31
|
+
{
|
32
|
+
"cache_node_create_time": "2013-05-28 07:42:19 UTC",
|
33
|
+
"cache_node_id": "0003",
|
34
|
+
"cache_node_status": "available",
|
35
|
+
"customer_availability_zone": "us-east-1a",
|
36
|
+
"endpoint": {
|
37
|
+
"address": "somecache.tgbhomz.0003.use1.cache.amazonaws.com",
|
38
|
+
"port": 11211
|
39
|
+
},
|
40
|
+
"parameter_group_status": "in-sync"
|
41
|
+
}
|
42
|
+
],
|
43
|
+
"cache_parameter_group": {
|
44
|
+
"cache_node_ids_to_reboot": [ ],
|
45
|
+
"cache_parameter_group_name": "default.memcached1.4",
|
46
|
+
"parameter_apply_status": "in-sync"
|
47
|
+
},
|
48
|
+
"cache_security_groups": [
|
49
|
+
{
|
50
|
+
"cache_security_group_name": "cache_security_group",
|
51
|
+
"status": "active"
|
52
|
+
}
|
53
|
+
],
|
54
|
+
"client_download_landing_page": "https://console.aws.amazon.com/elasticache/home#client-download:",
|
55
|
+
"configuration_endpoint": {
|
56
|
+
"address": "somecache.tgbhomz.cfg.use1.cache.amazonaws.com",
|
57
|
+
"port": 11211
|
58
|
+
},
|
59
|
+
"engine": "memcached",
|
60
|
+
"engine_version": "1.4.14",
|
61
|
+
"num_cache_nodes": 3,
|
62
|
+
"pending_modified_values": {
|
63
|
+
"cache_node_ids_to_remove": [ ]
|
64
|
+
},
|
65
|
+
"preferred_availability_zone": "us-east-1a",
|
66
|
+
"preferred_maintenance_window": "sun:07:30-sun:08:30",
|
67
|
+
"security_groups": [ ]
|
68
|
+
}
|
69
|
+
],
|
70
|
+
"response_metadata": {
|
71
|
+
"request_id": "585fd79c-3dd2-11e4-bf11-4b077bcebe02"
|
72
|
+
}
|
73
|
+
}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
{
|
2
|
+
"replication_groups": [
|
3
|
+
{
|
4
|
+
"member_clusters": [
|
5
|
+
"red-re-1uptio9f2ytdi",
|
6
|
+
"rn-redisclu-a7392cba"
|
7
|
+
],
|
8
|
+
"node_groups": [
|
9
|
+
{
|
10
|
+
"node_group_members": [
|
11
|
+
{
|
12
|
+
"cache_cluster_id": "red-re-1uptio9f2ytdi",
|
13
|
+
"read_endpoint": {
|
14
|
+
"port": 6379,
|
15
|
+
"address": "red-re-1uptio9f2ytdi.mzufvw.0001.use1.cache.amazonaws.com"
|
16
|
+
},
|
17
|
+
"preferred_availability_zone": "us-east-1c",
|
18
|
+
"cache_node_id": "0001",
|
19
|
+
"current_role": "primary"
|
20
|
+
},
|
21
|
+
{
|
22
|
+
"cache_cluster_id": "rn-redisclu-a7392cba",
|
23
|
+
"read_endpoint": {
|
24
|
+
"port": 6379,
|
25
|
+
"address": "rn-redisclu-a7392cba.mzufvw.0001.use1.cache.amazonaws.com"
|
26
|
+
},
|
27
|
+
"preferred_availability_zone": "us-east-1a",
|
28
|
+
"cache_node_id": "0001",
|
29
|
+
"current_role": "replica"
|
30
|
+
}
|
31
|
+
],
|
32
|
+
"primary_endpoint": {
|
33
|
+
"port": 6379,
|
34
|
+
"address": "rg-redisclu-2ffb4776.mzufvw.ng.0001.use1.cache.amazonaws.com"
|
35
|
+
},
|
36
|
+
"node_group_id": "0001",
|
37
|
+
"status": "available"
|
38
|
+
}
|
39
|
+
],
|
40
|
+
"replication_group_id": "rg-redisclu-2ffb4776",
|
41
|
+
"status": "available",
|
42
|
+
"description": "Sample replication group for the redis instances",
|
43
|
+
"pending_modified_values": null
|
44
|
+
}
|
45
|
+
],
|
46
|
+
"response_metadata": {
|
47
|
+
"request_id": "d9700c9d-3891-11e4-9cb8-252ab83f5b14"
|
48
|
+
}
|
49
|
+
}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
{
|
2
|
+
"replication_groups": [
|
3
|
+
{
|
4
|
+
"member_clusters": [
|
5
|
+
"cluster-id-here"
|
6
|
+
],
|
7
|
+
"node_groups": [
|
8
|
+
{
|
9
|
+
"node_group_members": [
|
10
|
+
{
|
11
|
+
"cache_cluster_id": "cluster-id-here",
|
12
|
+
"read_endpoint": {
|
13
|
+
"port": 6379,
|
14
|
+
"address": "cluster-id-here.mzufvw.0001.use1.cache.amazonaws.com"
|
15
|
+
},
|
16
|
+
"preferred_availability_zone": "us-east-1c",
|
17
|
+
"cache_node_id": "0001",
|
18
|
+
"current_role": "primary"
|
19
|
+
}
|
20
|
+
],
|
21
|
+
"node_group_id": "0001",
|
22
|
+
"primary_endpoint": {
|
23
|
+
"port": 6379,
|
24
|
+
"address": "cluster-id-here.mzufvw.ng.0001.use1.cache.amazonaws.com"
|
25
|
+
},
|
26
|
+
"status": "available"
|
27
|
+
}
|
28
|
+
],
|
29
|
+
"replication_group_id": "dev-redis-rep",
|
30
|
+
"status": "available",
|
31
|
+
"pending_modified_values": null,
|
32
|
+
"description": "Sample replication group for the redis instances"
|
33
|
+
}
|
34
|
+
],
|
35
|
+
"response_metadata": {
|
36
|
+
"request_id": "a4a0eaab-3891-11e4-8cb6-9f87081a8ee3"
|
37
|
+
}
|
38
|
+
}
|
@@ -0,0 +1,51 @@
|
|
1
|
+
{
|
2
|
+
"AWSTemplateFormatVersion": "2010-09-09",
|
3
|
+
"Description": "AWS CloudFormation template for standing a redis cluster.",
|
4
|
+
|
5
|
+
"Parameters": {
|
6
|
+
"EntryTopic": {
|
7
|
+
"Description": "SNS topic that will be used no notify custom resource creation",
|
8
|
+
"Type": "String"
|
9
|
+
}
|
10
|
+
},
|
11
|
+
|
12
|
+
"Resources": {
|
13
|
+
"RedisClusterReplicationGroup": {
|
14
|
+
"Type": "Custom::ElastiCacheReplicationGroup",
|
15
|
+
"Properties": {
|
16
|
+
"ServiceToken": {
|
17
|
+
"Ref": "EntryTopic"
|
18
|
+
},
|
19
|
+
"ClusterId": "cluster-id-here",
|
20
|
+
"ReplicationGroupId": "dev-redis-rep-group",
|
21
|
+
"Description": "Sample replication group for the redis instances"
|
22
|
+
}
|
23
|
+
},
|
24
|
+
"RedisReplicaCluster": {
|
25
|
+
"Type": "Custom::ElastiCacheReplicaCluster",
|
26
|
+
"Properties": {
|
27
|
+
"ServiceToken": {
|
28
|
+
"Ref": "EntryTopic"
|
29
|
+
},
|
30
|
+
"ReplicaClusterId": "dev-redis-replica",
|
31
|
+
"ReplicationGroupId": {
|
32
|
+
"Fn::GetAtt": ["RedisClusterReplicationGroup", "ReplicationGroupId"]
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
},
|
37
|
+
|
38
|
+
"Outputs": {
|
39
|
+
"ReplicationGroupId": {
|
40
|
+
"Value": {
|
41
|
+
"Fn::GetAtt": ["RedisClusterReplicationGroup", "ReplicationGroupId"]
|
42
|
+
}
|
43
|
+
},
|
44
|
+
"ReplicaClusterURLs": {
|
45
|
+
"Value": {
|
46
|
+
"Fn::GetAtt": [ "RedisReplicaCluster", "NodeURLs" ]
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
{
|
2
|
+
"AWSTemplateFormatVersion": "2010-09-09",
|
3
|
+
"Description": "AWS CloudFormation template for standing a redis cluster.",
|
4
|
+
|
5
|
+
"Parameters": {
|
6
|
+
"EntryTopic": {
|
7
|
+
"Description": "SNS topic that will be used no notify custom resource creation",
|
8
|
+
"Type": "String"
|
9
|
+
}
|
10
|
+
},
|
11
|
+
|
12
|
+
"Resources": {
|
13
|
+
"RedisClusterReplicationGroup": {
|
14
|
+
"Type": "Custom::ElastiCacheReplicationGroup",
|
15
|
+
"Properties": {
|
16
|
+
"ServiceToken": {
|
17
|
+
"Ref": "EntryTopic"
|
18
|
+
},
|
19
|
+
"ClusterId": "cluster-id-here",
|
20
|
+
"ReplicationGroupId" : "dev-redis-rep",
|
21
|
+
"Description": "Sample replication group for the redis instances"
|
22
|
+
}
|
23
|
+
}
|
24
|
+
},
|
25
|
+
|
26
|
+
"Outputs": {
|
27
|
+
"ReplicaURLs": {
|
28
|
+
"Value": {
|
29
|
+
"Fn::GetAtt": ["RedisClusterReplicationGroup", "ReplicationGroupId"]
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
}
|
@@ -54,7 +54,7 @@ describe CloudFormation::Bridge::Executor do
|
|
54
54
|
message = "This should not have been called"
|
55
55
|
expect(custom_resource).to receive(:create).and_raise(ArgumentError.new(message))
|
56
56
|
|
57
|
-
expect(request).to receive(:fail!).with(message)
|
57
|
+
expect(request).to receive(:fail!).with("ArgumentError - #{message}")
|
58
58
|
|
59
59
|
executor = CloudFormation::Bridge::Executor.new(registry)
|
60
60
|
executor.execute(request)
|
@@ -63,11 +63,11 @@ describe CloudFormation::Bridge::Request do
|
|
63
63
|
response = request.build_response
|
64
64
|
|
65
65
|
expect(response).to include(
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
66
|
+
FIELDS::STATUS => RESULTS::SUCCESS,
|
67
|
+
FIELDS::STACK_ID => request.stack_id,
|
68
|
+
FIELDS::REQUEST_ID => request.request_id,
|
69
|
+
FIELDS::LOGICAL_RESOURCE_ID => request.logical_resource_id,
|
70
|
+
)
|
71
71
|
|
72
72
|
expect(response[FIELDS::PHYSICAL_RESOURCE_ID]).not_to be_empty
|
73
73
|
end
|
@@ -102,6 +102,18 @@ describe CloudFormation::Bridge::Request do
|
|
102
102
|
request.succeed!(base)
|
103
103
|
end
|
104
104
|
|
105
|
+
it "ignores the provided response if it is not a hash" do
|
106
|
+
expect(CloudFormation::Bridge::HttpBridge).to receive(:put) do |url, options|
|
107
|
+
expect(url).to eq(request.request_url)
|
108
|
+
|
109
|
+
expected_response = request.build_response
|
110
|
+
expected_response.delete(FIELDS::PHYSICAL_RESOURCE_ID)
|
111
|
+
|
112
|
+
expect(options).to include(expected_response)
|
113
|
+
end
|
114
|
+
request.succeed!(true)
|
115
|
+
end
|
116
|
+
|
105
117
|
end
|
106
118
|
|
107
119
|
context 'when failing' do
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'cloud_formation/bridge/names'
|
2
|
+
require 'cloud_formation/bridge/request'
|
3
|
+
require 'cloud_formation/bridge/resources/elasti_cache_node_urls'
|
4
|
+
|
5
|
+
describe CloudFormation::Bridge::Resources::ElastiCacheNodeUrls do
|
6
|
+
|
7
|
+
FIELDS = CloudFormation::Bridge::Names::FIELDS
|
8
|
+
ELASTI_CACHE = CloudFormation::Bridge::Names::ELASTI_CACHE
|
9
|
+
|
10
|
+
include FileSupport
|
11
|
+
|
12
|
+
context '#create' do
|
13
|
+
|
14
|
+
it 'produces the node URLs for a memcached cluster' do
|
15
|
+
cluster_id = "samplecache"
|
16
|
+
|
17
|
+
expect(subject.client).to receive(:describe_cache_clusters).
|
18
|
+
with(cache_cluster_id: cluster_id,
|
19
|
+
show_cache_node_info: true).twice.and_return(parse_json("describe-memcached-cluster"))
|
20
|
+
|
21
|
+
request = CloudFormation::Bridge::Request.new(parse_json("create-cache-node-urls-message", false))
|
22
|
+
|
23
|
+
outputs = subject.create(request)
|
24
|
+
|
25
|
+
expect(outputs).to eq(
|
26
|
+
{
|
27
|
+
FIELDS::DATA => {
|
28
|
+
ELASTI_CACHE::REPLICA_CLUSTER_ID => cluster_id,
|
29
|
+
ELASTI_CACHE::NODE_URLS => "somecache.tgbhomz.cfg.use1.cache.amazonaws.com:11211",
|
30
|
+
},
|
31
|
+
FIELDS::PHYSICAL_RESOURCE_ID => cluster_id,
|
32
|
+
}
|
33
|
+
)
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'produces the node URLs for a redis cluster' do
|
38
|
+
cluster_id = "dev-redis-replica"
|
39
|
+
expect(subject.client).to receive(:describe_cache_clusters).
|
40
|
+
with(cache_cluster_id: cluster_id,
|
41
|
+
show_cache_node_info: true).twice.and_return(parse_json("describe-cache-cluster-replica-done"))
|
42
|
+
|
43
|
+
request = CloudFormation::Bridge::Request.new(parse_json("create-redis-cache-node-urls-message", false))
|
44
|
+
|
45
|
+
outputs = subject.create(request)
|
46
|
+
|
47
|
+
expect(outputs).to eq(
|
48
|
+
{
|
49
|
+
FIELDS::DATA => {
|
50
|
+
ELASTI_CACHE::REPLICA_CLUSTER_ID => cluster_id,
|
51
|
+
ELASTI_CACHE::NODE_URLS => "dev-redis-replica.mzufvw.0001.use1.cache.amazonaws.com:6379,dev-redis-replica.mzufvw.0002.use1.cache.amazonaws.com:6379",
|
52
|
+
},
|
53
|
+
FIELDS::PHYSICAL_RESOURCE_ID => cluster_id,
|
54
|
+
}
|
55
|
+
)
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'cloud_formation/bridge/names'
|
2
|
+
require 'cloud_formation/bridge/resources/elasti_cache_replica_cluster'
|
3
|
+
|
4
|
+
describe CloudFormation::Bridge::Resources::ElastiCacheReplicaCluster do
|
5
|
+
|
6
|
+
FIELDS = CloudFormation::Bridge::Names::FIELDS
|
7
|
+
ELASTI_CACHE = CloudFormation::Bridge::Names::ELASTI_CACHE
|
8
|
+
|
9
|
+
include FileSupport
|
10
|
+
|
11
|
+
let(:creating) { parse_json("describe-cache-cluster-replica") }
|
12
|
+
let(:available) { parse_json("describe-cache-cluster-replica-done") }
|
13
|
+
let(:replication_group_id) { "dev-redis-rep-group" }
|
14
|
+
let(:replica_cluster_id) { "dev-redis-replica" }
|
15
|
+
|
16
|
+
context '#create' do
|
17
|
+
|
18
|
+
let(:request) { CloudFormation::Bridge::Request.new(parse_json("create-replica-cluster-message", false)) }
|
19
|
+
|
20
|
+
it 'creates the cluster' do
|
21
|
+
expect(subject.client).to receive(:create_cache_cluster).
|
22
|
+
with(cache_cluster_id: replica_cluster_id, replication_group_id: replication_group_id)
|
23
|
+
expect(subject.client).to receive(:describe_cache_clusters).
|
24
|
+
with(cache_cluster_id: replica_cluster_id,
|
25
|
+
show_cache_node_info: true).twice.and_return(available)
|
26
|
+
|
27
|
+
outputs = subject.create(request)
|
28
|
+
|
29
|
+
expect(outputs).to eq(
|
30
|
+
{
|
31
|
+
FIELDS::DATA => {
|
32
|
+
ELASTI_CACHE::REPLICA_CLUSTER_ID => replica_cluster_id,
|
33
|
+
ELASTI_CACHE::NODE_URLS => "dev-redis-replica.mzufvw.0001.use1.cache.amazonaws.com:6379,dev-redis-replica.mzufvw.0002.use1.cache.amazonaws.com:6379",
|
34
|
+
},
|
35
|
+
FIELDS::PHYSICAL_RESOURCE_ID => replica_cluster_id,
|
36
|
+
}
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
context '#delete' do
|
43
|
+
|
44
|
+
let(:request) { CloudFormation::Bridge::Request.new(parse_json("delete-replica-cluster-message", false)) }
|
45
|
+
|
46
|
+
it 'deletes the cluster' do
|
47
|
+
expect(subject.client).to receive(:delete_cache_cluster).with(cache_cluster_id: replica_cluster_id)
|
48
|
+
|
49
|
+
count = 0
|
50
|
+
|
51
|
+
expect(subject.client).to receive(:describe_cache_clusters).
|
52
|
+
with(cache_cluster_id: replica_cluster_id,
|
53
|
+
show_cache_node_info: true).at_least(:once) do
|
54
|
+
if count == 0
|
55
|
+
count += 1
|
56
|
+
available
|
57
|
+
else
|
58
|
+
raise AWS::ElastiCache::Errors::CacheClusterNotFound
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
subject.delete(request)
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'cloud_formation/bridge/request'
|
2
|
+
require 'cloud_formation/bridge/names'
|
3
|
+
require 'cloud_formation/bridge/resources/elasti_cache_replication_group'
|
4
|
+
|
5
|
+
describe CloudFormation::Bridge::Resources::ElastiCacheReplicationGroup do
|
6
|
+
|
7
|
+
include FileSupport
|
8
|
+
|
9
|
+
FIELDS = CloudFormation::Bridge::Names::FIELDS
|
10
|
+
ELASTI_CACHE = CloudFormation::Bridge::Names::ELASTI_CACHE
|
11
|
+
|
12
|
+
let(:replication_group_id) { "dev-redis-rep" }
|
13
|
+
|
14
|
+
def stub_describe_replication_group
|
15
|
+
expect(subject.client).to receive(:describe_replication_groups).
|
16
|
+
with(replication_group_id: replication_group_id).
|
17
|
+
and_return(parse_json("describe-replication-group-primary-only"))
|
18
|
+
end
|
19
|
+
|
20
|
+
context "#create" do
|
21
|
+
|
22
|
+
let(:request) { CloudFormation::Bridge::Request.new(parse_json("create-replication-group-message", false)) }
|
23
|
+
|
24
|
+
it 'creates the replication group' do
|
25
|
+
expect(subject.client).to receive(:create_replication_group).with(
|
26
|
+
replication_group_id: replication_group_id,
|
27
|
+
primary_cluster_id: "cluster-id-here",
|
28
|
+
replication_group_description: "Sample replication group for the redis instances",
|
29
|
+
)
|
30
|
+
|
31
|
+
stub_describe_replication_group
|
32
|
+
|
33
|
+
outputs = subject.create(request)
|
34
|
+
|
35
|
+
expect(outputs).to eq(
|
36
|
+
FIELDS::DATA => {
|
37
|
+
ELASTI_CACHE::REPLICATION_GROUP_ID => replication_group_id,
|
38
|
+
},
|
39
|
+
FIELDS::PHYSICAL_RESOURCE_ID => replication_group_id,
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
context "#delete" do
|
46
|
+
|
47
|
+
let(:request) { CloudFormation::Bridge::Request.new(parse_json("delete-replication-group-message", false)) }
|
48
|
+
|
49
|
+
it 'should delete the group' do
|
50
|
+
stub_describe_replication_group
|
51
|
+
expect(subject.client).to receive(:delete_replication_group).with(
|
52
|
+
replication_group_id: replication_group_id,
|
53
|
+
retain_primary_cluster: true,
|
54
|
+
)
|
55
|
+
subject.delete(request)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should ignore if the replication group does not exist' do
|
59
|
+
expect(subject).to receive(:replication_group_available?).and_raise(AWS::ElastiCache::Errors::ReplicationGroupNotFoundFault)
|
60
|
+
expect { subject.delete(request) }.not_to raise_error
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -1,7 +1,13 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
1
3
|
module FileSupport
|
2
4
|
|
3
5
|
def read_file(name)
|
4
6
|
IO.read(File.join(File.dirname(__FILE__), '..', 'files', name))
|
5
7
|
end
|
6
8
|
|
9
|
+
def parse_json(name, symbolize_names = true)
|
10
|
+
JSON.parse(read_file("#{name}.json"), symbolize_names: symbolize_names)
|
11
|
+
end
|
12
|
+
|
7
13
|
end
|