sumomo 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 19a7b13c51abbddeff61c5b0b23eb1163dd70bd8
4
- data.tar.gz: fbe8f61d32f2d6acd41b6437fa8f8ac84773f4c3
3
+ metadata.gz: 1840367c723c373796e9a822b5c5e148a35bd609
4
+ data.tar.gz: f9a20e064f13018ce49868289243eb95c893dd96
5
5
  SHA512:
6
- metadata.gz: a12275c78d5ee20bcd911f678607003f6c1681570243d1a8772d702dc1950b8180474cfdfbd10440813d05d8d370b260c6c235c476d15de96c16dbf1dc225b2e
7
- data.tar.gz: a13a1e7840147f9e70948256b81ecd8f0baf25b7bc58bc53e938e641663a8040e5ca00d949dae36de3333a0f3fc54b99da0c592bb95f33323a03d78940194265
6
+ metadata.gz: cdfdedee63e23f076103f0de8a0e7c2f945830d254c57587668d8a0065d04ff7894205210b0c45f54c941303f6e3e5af75f8b44e0a9b8bfa47a1c8ce2a9ff087
7
+ data.tar.gz: 56333dd662ec58d5c426d40a8b2d1837aa78c0547f523bd175cc611fbdf79d59f5bd54fecb86ecfd3e7d6634fe675faff12bb09e1490c22f6a89afd7b08067a6
@@ -1,4 +1,3 @@
1
-
2
1
  if (request.RequestType == "Create")
3
2
  {
4
3
  Cloudformation.send(request, context, Cloudformation.SUCCESS, {}, "Success", String((new Date).getTime()));
@@ -12,4 +11,4 @@ if (request.RequestType == "Update")
12
11
  if (request.RequestType == "Delete")
13
12
  {
14
13
  Cloudformation.send(request, context, Cloudformation.SUCCESS, {}, "Success", String((new Date).getTime()));
15
- }
14
+ }
@@ -0,0 +1,115 @@
1
+
2
+ var cloudfront = new aws.CloudFront({region: request.ResourceProperties.Region});
3
+
4
+ function randomIntInc (low, high)
5
+ {
6
+ return Math.floor(Math.random() * (high - low + 1) + low);
7
+ }
8
+
9
+ function randomNumber()
10
+ {
11
+ var numbers = new Array(10);
12
+ for (var i = 0; i < numbers.length; i++)
13
+ {
14
+ numbers[i] = randomIntInc(1,10);
15
+ }
16
+ return numbers.join("");
17
+ }
18
+
19
+ function request_identity(ref, onSuccess, onError)
20
+ {
21
+ var params = {
22
+ CloudFrontOriginAccessIdentityConfig: {
23
+ CallerReference: ref,
24
+ Comment: request.ResourceProperties.Comment || "No Comment Specified"
25
+ }
26
+ }
27
+
28
+ cloudfront.createCloudFrontOriginAccessIdentity(params, function(err, data) {
29
+ if (err)
30
+ {
31
+ onError(err);
32
+ }
33
+ else
34
+ {
35
+ onSuccess(data);
36
+ }
37
+ });
38
+ }
39
+
40
+ if (request.RequestType == "Create")
41
+ {
42
+ var ref = randomNumber();
43
+ store.put("oai_ref", ref, function() {
44
+ request_identity(ref,
45
+ function(data)
46
+ {
47
+ console.log(data);
48
+ Cloudformation.send(request, context, Cloudformation.SUCCESS, {
49
+ Id: data.CloudFrontOriginAccessIdentity.Id,
50
+ S3CanonicalUserId: data.CloudFrontOriginAccessIdentity.S3CanonicalUserId
51
+ }, "Success", "origin-access-identity/cloudfront/" + data.CloudFrontOriginAccessIdentity.Id);
52
+
53
+ }, function(err)
54
+ {
55
+ console.log(err, err.stack);
56
+ Cloudformation.send(request, context, Cloudformation.FAILED, {}, "Error: " + err);
57
+ });
58
+ }, function(err) {
59
+ Cloudformation.send(request, context, Cloudformation.FAILED, {}, "Cannot Store OAI Reference");
60
+ });
61
+ }
62
+
63
+ if (request.RequestType == "Update")
64
+ {
65
+ store.get("oai_ref", function(ref) {
66
+ request_identity(ref,
67
+ function(data)
68
+ {
69
+ console.log(data);
70
+ Cloudformation.send(request, context, Cloudformation.SUCCESS, {
71
+ Id: data.CloudFrontOriginAccessIdentity.Id,
72
+ S3CanonicalUserId: data.CloudFrontOriginAccessIdentity.S3CanonicalUserId
73
+ }, "Success", "origin-access-identity/cloudfront/" + data.CloudFrontOriginAccessIdentity.Id);
74
+
75
+ }, function(err)
76
+ {
77
+ console.log(err, err.stack);
78
+ Cloudformation.send(request, context, Cloudformation.FAILED, {}, "Error: " + err);
79
+ });
80
+ }, function(err) {
81
+ Cloudformation.send(request, context, Cloudformation.FAILED, {}, "Cannot Load OAI Reference");
82
+ });
83
+ }
84
+
85
+ if (request.RequestType == "Delete")
86
+ {
87
+ store.get("oai_ref", function(ref) {
88
+ request_identity(ref,
89
+ function(data)
90
+ {
91
+ var params = {
92
+ Id: data.CloudFrontOriginAccessIdentity.Id,
93
+ };
94
+ cloudfront.deleteCloudFrontOriginAccessIdentity(params, function(err, data) {
95
+ if (err)
96
+ {
97
+ console.log(err, err.stack);
98
+ Cloudformation.send(request, context, Cloudformation.FAILED, {}, "Error: " + err);
99
+ }
100
+ else
101
+ {
102
+ Cloudformation.send(request, context, Cloudformation.SUCCESS, {}, "Success", "" );
103
+ }
104
+ });
105
+
106
+ }, function(err)
107
+ {
108
+ console.log(err, err.stack);
109
+ Cloudformation.send(request, context, Cloudformation.FAILED, {}, "Error: " + err);
110
+ });
111
+
112
+ }, function(err) {
113
+ Cloudformation.send(request, context, Cloudformation.FAILED, {}, "Cannot Load OAI Reference");
114
+ });
115
+ }
data/exe/sumomo CHANGED
@@ -13,10 +13,16 @@ global_opts = Trollop::options do
13
13
  USAGE
14
14
 
15
15
  opt :region, "AWS region to use", type: :string, default: "ap-northeast-1"
16
+ opt :profile, "AWS credential profile to use", type: :string, default: "default"
16
17
 
17
18
  stop_on SUB_COMMANDS
18
19
  end
19
20
 
21
+ ENV["AWS_PROFILE"] = global_opts[:profile]
22
+
23
+ puts "Using profile:"
24
+ p ENV["AWS_PROFILE"]
25
+
20
26
  cmd = ARGV.shift # get the subcommand
21
27
 
22
28
  cmd_opts = case cmd
@@ -91,6 +91,8 @@ module Sumomo
91
91
 
92
92
  end.templatize
93
93
 
94
+
95
+
94
96
  #puts JSON.parse(template).to_yaml
95
97
 
96
98
  store.set_raw("cloudformation/template", template)
@@ -10,7 +10,7 @@ module Sumomo
10
10
  end)
11
11
  end
12
12
 
13
- def allow(thing)
13
+ def allow_port(thing)
14
14
  if (thing == :all)
15
15
  {
16
16
  "IpProtocol" => "-1",
@@ -270,6 +270,7 @@ sudo aws s3 cp s3://#{@bucket_name}/uploads/#{name} #{local_path}
270
270
  docker_email:"",
271
271
  docker_password: "",
272
272
  eip:nil,
273
+ policies:[],
273
274
  &block)
274
275
 
275
276
  if ami_name == nil
@@ -290,8 +291,8 @@ sudo aws s3 cp s3://#{@bucket_name}/uploads/#{name} #{local_path}
290
291
 
291
292
  task_script = tasks.script
292
293
 
293
- ingress ||= [ allow(:all) ]
294
- egress ||= [ allow(:all) ]
294
+ ingress ||= [ allow_port(:all) ]
295
+ egress ||= [ allow_port(:all) ]
295
296
  machine_tag ||= ref("AWS::StackName")
296
297
  name ||= make_default_resource_name("AutoScalingGroup")
297
298
  script ||= ""
@@ -393,7 +394,7 @@ aws ec2 associate-address --region `cat /etc/aws_region` --instance-id `curl htt
393
394
  "logs:PutLogEvents"
394
395
  ],
395
396
  "Resource": "*"
396
- }]
397
+ }] + policies
397
398
  }
398
399
  }]
399
400
  end
@@ -6,21 +6,67 @@ module Sumomo
6
6
  str.gsub(/[^0-9a-zA-Z]/, "_")
7
7
  end
8
8
 
9
- def make_ecs_cluster(name:"ECSCluster",services:[],machine_config:{},log_retention:30)
9
+ def make_ecs_role
10
+ make "AWS::IAM::Role", name: "ECSServiceRole" do
11
+
12
+ role_policy_doc = {
13
+ "Version" => "2012-10-17",
14
+ "Statement" => [{
15
+ "Effect" => "Allow",
16
+ "Principal" => {"Service" => ["ecs.amazonaws.com"]},
17
+ "Action" => ["sts:AssumeRole"]
18
+ }]
19
+ }
10
20
 
11
- ecs = make "AWS::ECS::Cluster", name: "#{name}"
21
+ AssumeRolePolicyDocument role_policy_doc
22
+ Path "/"
23
+ Policies [
24
+ {
25
+ "PolicyName" => "ecs-service",
26
+ "PolicyDocument" => {
27
+ "Version" => "2012-10-17",
28
+ "Statement" => [{
29
+ "Effect" => "Allow",
30
+ "Action" => [
31
+ "ec2:AuthorizeSecurityGroupIngress",
32
+ "ec2:Describe*",
33
+ "elasticloadbalancing:DeregisterInstancesFromLoadBalancer",
34
+ "elasticloadbalancing:DeregisterTargets",
35
+ "elasticloadbalancing:Describe*",
36
+ "elasticloadbalancing:RegisterInstancesWithLoadBalancer",
37
+ "elasticloadbalancing:RegisterTargets"
38
+ ],
39
+ "Resource" => "*"
40
+ }]
41
+ }
42
+ }
43
+ ]
44
+ end
45
+ end
46
+
47
+ def make_ecs_cluster(name:make_default_resource_name("ECSCluster"),services:[],machine_config:{},network:,log_retention:30,dependencies:[])
48
+
49
+ ecs = make "AWS::ECS::Cluster", name: "#{name}" do
50
+ dependencies.each do |x|
51
+ depends_on x
52
+ end
53
+ end
12
54
 
13
55
  volumes = []
14
56
  machine_volume_locations = {}
15
57
 
16
- service_count = 0
58
+ service_number = 0
17
59
 
18
60
  services.each do |service|
19
61
 
20
- service_count += 1
62
+ alb = service[:alb]
63
+ certificate = service[:certificate]
64
+ alb_ports = {}
65
+
66
+ service_number += 1
21
67
 
22
68
  containers = service[:containers]
23
- service_name = service[:name] || "Service#{service_count}"
69
+ service_name = service[:name] || "Service#{service_number}"
24
70
  service_count = service[:count] || 1
25
71
 
26
72
  container_defs = containers.map do |container|
@@ -29,7 +75,7 @@ module Sumomo
29
75
  definition["Name"] = "#{sluggify(container[:image]).camelize}"
30
76
  definition["Name"] = container[:name] if container[:name]
31
77
 
32
- definition["Memory"] = 1024
78
+ definition["Memory"] = container[:memory] || 1024
33
79
 
34
80
  loggroup = make "AWS::Logs::LogGroup", name: "#{name}#{definition["Name"]}Logs" do
35
81
  LogGroupName "#{definition["Name"].underscore}_logs"
@@ -68,11 +114,68 @@ module Sumomo
68
114
  end
69
115
 
70
116
  if container[:ports]
71
- definition["PortMappings"] = container[:ports].map do |from_port, to_port|
72
- {
73
- "ContainerPort" => from_port,
74
- "HostPort" => to_port
75
- }
117
+ if !alb
118
+ definition["PortMappings"] = container[:ports].map do |from_port, to_port|
119
+ {
120
+ "ContainerPort" => from_port,
121
+ "HostPort" => to_port
122
+ }
123
+ end
124
+
125
+ else
126
+ definition["PortMappings"] = container[:ports].map do |from_port, to_port|
127
+ {
128
+ "ContainerPort" => from_port
129
+ }
130
+ end
131
+
132
+ container[:ports].each do |container_port, host_port|
133
+
134
+ if alb_ports[host_port.to_i]
135
+ raise "Container #{alb_ports[host_port][:name]} is already using #{host_port}"
136
+ end
137
+
138
+ alb_target = make "AWS::ElasticLoadBalancingV2::TargetGroup", name: "#{name}#{definition["Name"]}Target" do
139
+ HealthCheckIntervalSeconds 60
140
+ UnhealthyThresholdCount 10
141
+ HealthCheckPath "/"
142
+ Name "#{name}Port#{host_port}Target"
143
+ Port container_port
144
+ Protocol "HTTP"
145
+ VpcId network[:vpc]
146
+ end
147
+
148
+ alb_action = {
149
+ "Type" => "forward",
150
+ "TargetGroupArn" => alb_target
151
+ }
152
+
153
+ if certificate
154
+ alb_listener = make "AWS::ElasticLoadBalancingV2::Listener", name: "#{name}#{definition["Name"]}Listener" do
155
+ Certificates [{ CertificateArn: certificate }]
156
+ DefaultActions [ alb_action ]
157
+ LoadBalancerArn alb
158
+ Port host_port
159
+ Protocol "HTTPS"
160
+ end
161
+ else
162
+ alb_listener = make "AWS::ElasticLoadBalancingV2::Listener", name: "#{name}#{definition["Name"]}Listener" do
163
+ DefaultActions [ alb_action ]
164
+ LoadBalancerArn alb
165
+ Port host_port
166
+ Protocol "HTTP"
167
+ end
168
+ end
169
+
170
+ alb_ports[host_port.to_i] = {
171
+ listener: alb_listener,
172
+ target: alb_target,
173
+ port: container_port,
174
+ name: definition["Name"]
175
+ }
176
+
177
+ end
178
+
76
179
  end
77
180
  container.delete(:ports)
78
181
  end
@@ -87,13 +190,12 @@ module Sumomo
87
190
  container.delete(:envvars)
88
191
  end
89
192
 
90
-
91
193
  container.each do |key, value|
92
194
  definition["#{key}".camelize] = value
93
195
  end
94
196
 
95
197
  definition
96
- end
198
+ end
97
199
 
98
200
 
99
201
  deployment_config = {
@@ -106,13 +208,31 @@ module Sumomo
106
208
  Volumes volumes
107
209
  end
108
210
 
211
+ stack = self
212
+
109
213
  ecs_service = make "AWS::ECS::Service", name: "#{name}#{service_name}" do
214
+ alb_ports.each do |host_port, info|
215
+ depends_on info[:listener]
216
+ end
217
+
110
218
  Cluster ecs
111
219
  DesiredCount service_count
112
220
  TaskDefinition ecs_task
113
221
  DeploymentConfiguration deployment_config
222
+
223
+ if alb_ports.keys.count != 0
224
+ Role stack.make_ecs_role
225
+ LoadBalancers alb_ports.values.map { |info|
226
+ {
227
+ "TargetGroupArn" => info[:target],
228
+ "ContainerPort" => info[:port],
229
+ "ContainerName" => info[:name]
230
+ }
231
+ }
232
+ end
233
+
114
234
  end
115
- end
235
+ end #services
116
236
 
117
237
  machine_config[:methods].each do |method_name|
118
238
  parameters = {ecs_cluster: ecs}
@@ -121,6 +241,8 @@ module Sumomo
121
241
  parameters[param[1]] = machine_config[param[1]] if (param[0] == :keyreq or param[0] == :key) and machine_config[param[1]]
122
242
  end
123
243
 
244
+ parameters[:network] = network if !parameters[:network]
245
+
124
246
  method(method_name).call(parameters) do
125
247
  machine_volume_locations.each do |s3_loc, machine_loc|
126
248
  mkdir File.dirname(machine_loc)
@@ -38,9 +38,47 @@ module Sumomo
38
38
  GatewayId gateway
39
39
  end
40
40
 
41
+ last_unused_number = 0
42
+
43
+ subnet_numbers = []
44
+
45
+ #load current config
46
+ number_hash = {}
47
+ subnet_hash = {}
48
+
49
+ ec2 = Aws::EC2::Client.new(region: @region)
50
+ ec2_subnets = ec2.describe_subnets().subnets
51
+ ec2_subnets.each do |subnet|
52
+ if subnet.tags.select {|x| x.key == "aws:cloudformation:stack-name" && x.value == @bucket_name}.length == 1
53
+ layer = /^#{@bucket_name}-(?<layer_name>.+)-[a-z]+$/.match(subnet.tags.select{|x| x.key == "Name"}.first.value)[:layer_name]
54
+ zone = subnet.availability_zone
55
+ number = /^10.0.(?<num>[0-9]+).0/.match(subnet.cidr_block)[:num].to_i
56
+
57
+ key = "#{layer}/#{zone}"
58
+ number_hash[number] = key
59
+ subnet_hash[key] = number
60
+ end
61
+ end
62
+
63
+ # assign numbers to unassigned subnets
64
+ layers.product(zones).each do |e|
65
+ key = "#{e[0]}/#{e[1]}"
66
+ if !subnet_hash.has_key?(key)
67
+ loop do
68
+ break if !number_hash.has_key?(last_unused_number)
69
+ last_unused_number += 1
70
+ end
71
+ number_hash[last_unused_number] = key
72
+ subnet_hash[key] = last_unused_number
73
+ subnet_numbers << [e, last_unused_number]
74
+ else
75
+ subnet_numbers << [e, subnet_hash[key]]
76
+ end
77
+ end
78
+
41
79
  subnets = {}
42
80
 
43
- layers.product(zones).each_with_index do |e, subnet_number|
81
+ subnet_numbers.each do |e, subnet_number|
44
82
  layer = e[0]
45
83
  zone = e[1]
46
84
 
@@ -17,6 +17,7 @@ module Sumomo
17
17
  end
18
18
 
19
19
  def upload_file(name,content)
20
+ puts "Uploaded #{name}"
20
21
  @store.set_raw("uploads/#{name}", content)
21
22
  end
22
23
 
@@ -139,6 +140,11 @@ module Sumomo
139
140
  "Effect" => "Allow",
140
141
  "Action" => ["s3:DeleteObject", "s3:GetObject", "s3:PutObject"],
141
142
  "Resource" => "arn:aws:s3:::#{bucket_name}/*"
143
+ },
144
+ {
145
+ "Effect" => "Allow",
146
+ "Action" => ["cloudfront:CreateCloudFrontOriginAccessIdentity", "cloudfront:DeleteCloudFrontOriginAccessIdentity"],
147
+ "Resource" => "*"
142
148
  }]
143
149
  }
144
150
  }
@@ -1,3 +1,3 @@
1
1
  module Sumomo
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sumomo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Siaw
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-01-02 00:00:00.000000000 Z
11
+ date: 2017-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -171,6 +171,7 @@ files:
171
171
  - data/sumomo/custom_resources/AvailabilityZones.js
172
172
  - data/sumomo/custom_resources/CloudflareCNAME.js
173
173
  - data/sumomo/custom_resources/DeployTime.js
174
+ - data/sumomo/custom_resources/OriginAccessIdentity.js
174
175
  - data/sumomo/custom_resources/SelectSpot.js
175
176
  - data/sumomo/sources/spot-watcher-poller.sh
176
177
  - data/sumomo/sources/spot-watcher.sh