jets 0.10.4 → 1.0.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.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/Gemfile.lock +12 -12
  4. data/README.md +4 -2
  5. data/exe/jets +2 -2
  6. data/lib/jets/application.rb +41 -5
  7. data/lib/jets/aws_info.rb +20 -0
  8. data/lib/jets/builders/code_builder.rb +201 -296
  9. data/lib/jets/builders/gem_replacer.rb +1 -1
  10. data/lib/jets/builders/handler_generator.rb +62 -43
  11. data/lib/jets/builders/md5.rb +55 -0
  12. data/lib/jets/builders/md5_zip.rb +60 -0
  13. data/lib/jets/builders/rack_packager.rb +29 -0
  14. data/lib/jets/builders/rackup_wrappers/rackup +23 -0
  15. data/lib/jets/builders/rackup_wrappers/rackup.rb +7 -0
  16. data/lib/jets/builders/reconfigure_rails/config/initializers/jets.rb +14 -0
  17. data/lib/jets/builders/reconfigure_rails.rb +99 -0
  18. data/lib/jets/builders/ruby_packager.rb +198 -0
  19. data/lib/jets/builders/{deducer.rb → shim_vars/app.rb} +14 -10
  20. data/lib/jets/builders/shim_vars/base.rb +24 -0
  21. data/lib/jets/builders/{shared_deducer.rb → shim_vars/shared.rb} +4 -3
  22. data/lib/jets/builders/shim_vars.rb +5 -0
  23. data/lib/jets/builders/templates/handler.js +9 -0
  24. data/lib/jets/builders/templates/shim.js +271 -0
  25. data/lib/jets/builders/tidy.rb +80 -0
  26. data/lib/jets/builders/util.rb +28 -0
  27. data/lib/jets/builders.rb +8 -2
  28. data/lib/jets/cfn/builders/function_builder.rb +0 -10
  29. data/lib/jets/cfn/builders/parent_builder.rb +7 -6
  30. data/lib/jets/cfn/ship.rb +9 -103
  31. data/lib/jets/cfn/upload.rb +139 -0
  32. data/lib/jets/cfn.rb +1 -0
  33. data/lib/jets/commands/build.rb +17 -19
  34. data/lib/jets/commands/deploy.rb +2 -0
  35. data/lib/jets/commands/help/deploy.md +2 -2
  36. data/lib/jets/commands/help/import/rack.md +13 -0
  37. data/lib/jets/commands/help/import/rails.md +11 -0
  38. data/lib/jets/commands/import/base.rb +39 -0
  39. data/lib/jets/commands/import/rack.rb +16 -0
  40. data/lib/jets/commands/import/rail.rb +68 -0
  41. data/lib/jets/commands/import/sequence.rb +68 -0
  42. data/lib/jets/commands/import.rb +14 -0
  43. data/lib/jets/commands/main.rb +2 -1
  44. data/lib/jets/commands/new.rb +1 -1
  45. data/lib/jets/commands/sequence.rb +26 -22
  46. data/lib/jets/commands/templates/skeleton/Gemfile.tt +5 -2
  47. data/lib/jets/commands/templates/skeleton/README.md +11 -2
  48. data/lib/jets/commands/templates/skeleton/app/jobs/application_job.rb +1 -1
  49. data/lib/jets/commands/templates/skeleton/app/views/layouts/application.html.erb.tt +1 -1
  50. data/lib/jets/commands/templates/skeleton/config/application.rb.tt +12 -5
  51. data/lib/jets/commands/templates/skeleton/config/database.yml.tt +5 -1
  52. data/lib/jets/commands/templates/skeleton/config/environments/development.rb +3 -0
  53. data/lib/jets/commands/templates/skeleton/config/environments/production.rb +5 -0
  54. data/lib/jets/commands/templates/skeleton/public/{images/favicon.ico → favicon.ico} +0 -0
  55. data/lib/jets/commands/templates/skeleton/spec/controllers/posts_controller_spec.rb +1 -3
  56. data/lib/jets/commands.rb +1 -0
  57. data/lib/jets/controller/base.rb +1 -1
  58. data/lib/jets/controller/layout.rb +3 -0
  59. data/lib/jets/controller/params.rb +3 -2
  60. data/lib/jets/controller/request.rb +4 -0
  61. data/lib/jets/core.rb +20 -18
  62. data/lib/jets/core_ext/kernel.rb +9 -5
  63. data/lib/jets/default/application.rb +1 -1
  64. data/lib/jets/inflections.rb +16 -8
  65. data/lib/jets/internal/app/controllers/jets/public_controller.rb +17 -22
  66. data/lib/jets/internal/app/controllers/jets/rack_controller.rb +15 -0
  67. data/lib/jets/naming.rb +0 -23
  68. data/lib/jets/rack/hash_converter.rb +25 -0
  69. data/lib/jets/rack/request.rb +71 -0
  70. data/lib/jets/rack/server.rb +47 -0
  71. data/lib/jets/rack.rb +7 -0
  72. data/lib/jets/rails_overrides/asset_tag_helper.rb +12 -11
  73. data/lib/jets/resource/function.rb +13 -5
  74. data/lib/jets/router.rb +1 -1
  75. data/lib/jets/ruby_server.rb +63 -18
  76. data/lib/jets/server/api_gateway.rb +1 -1
  77. data/lib/jets/stack/resource.rb +3 -1
  78. data/lib/jets/version.rb +1 -1
  79. data/lib/jets.rb +3 -5
  80. metadata +34 -9
  81. data/lib/jets/builders/node-hello.js +0 -73
  82. data/lib/jets/builders/node-shim.js +0 -182
  83. data/lib/jets/internal/app/controllers/jets/public_controller/python/show.py +0 -47
  84. data/lib/jets/internal/app/controllers/jets/public_controller/python/show.pyc +0 -0
@@ -0,0 +1,24 @@
1
+ module Jets::Builders::ShimVars
2
+ class Base
3
+ include Jets::AwsServices
4
+ extend Memoist
5
+
6
+ def s3_bucket
7
+ Jets.aws.s3_bucket
8
+ end
9
+
10
+ def rack_zip
11
+ checksum = Jets::Builders::Md5.checksums["stage/rack"]
12
+ "rack-#{checksum}.zip"
13
+ end
14
+
15
+ def bundled_zip
16
+ checksum = Jets::Builders::Md5.checksums["stage/bundled"]
17
+ "bundled-#{checksum}.zip"
18
+ end
19
+
20
+ def stage_area
21
+ "#{Jets.build_root}/stage"
22
+ end
23
+ end
24
+ end
@@ -1,4 +1,4 @@
1
- # Deducer.new(path)
1
+ # Jets::Builders::ShimVars::Shared.new(fun)
2
2
  #
3
3
  # @deducer.functions.each do |function_name|
4
4
  # @deducer.handler_for(function_name)
@@ -10,8 +10,9 @@
10
10
  # handler_for(function_name)
11
11
  # js_path
12
12
  #
13
- class Jets::Builders
14
- class SharedDeducer < Deducer
13
+ module Jets::Builders::ShimVars
14
+ class Shared < Base
15
+ # fun is a Jets::Stack::Function
15
16
  def initialize(fun)
16
17
  @fun = fun
17
18
  end
@@ -0,0 +1,5 @@
1
+ module Jets::Builders::ShimVars
2
+ autoload :App, "jets/builders/shim_vars/app"
3
+ autoload :Base, "jets/builders/shim_vars/base"
4
+ autoload :Shared, "jets/builders/shim_vars/shared"
5
+ end
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ const shim = require("handlers/shim.js");
4
+
5
+ shim.once(); // runs in lambda execution context
6
+
7
+ <% @vars.functions.each do |function_name| -%>
8
+ exports.<%= function_name %> = shim.handler("<%= @vars.handler_for(function_name) %>");
9
+ <% end -%>
@@ -0,0 +1,271 @@
1
+ const TMP_LOG_PATH = '/tmp/shim-subprocess.log';
2
+ const JETS_DEBUG = process.env.JETS_DEBUG; // set JETS_DEBUG=1 to see more debugging info
3
+ const JETS_OUTPUT = '/tmp/jets-output.log';
4
+ const S3_BUCKET = '<%= @vars.s3_bucket %>';
5
+ <% if Jets.rack? -%>
6
+ const RACK_ZIP = '<%= @vars.rack_zip %>'; // jets/code/rack-checksum.zip
7
+ <% end -%>
8
+ <% if Jets.lazy_load? -%>
9
+ const BUNDLED_ZIP = '<%= @vars.bundled_zip %>'; // /tmp/bundled-checksum.zip
10
+ <% end -%>
11
+
12
+
13
+ const spawn = require('child_process').spawn;
14
+ const fs = require('fs');
15
+ const readline = require('readline');
16
+ const subprocess_out = fs.openSync(TMP_LOG_PATH, 'a');
17
+ const subprocess_err = fs.openSync(TMP_LOG_PATH, 'a');
18
+ const { exec } = require('child_process');
19
+ const AWS = require('aws-sdk/global');
20
+ const S3 = require('aws-sdk/clients/s3'); // import individual service
21
+ const net = require('net');
22
+
23
+ ////////////////////////////////////////////////////////////////////////////////
24
+ // util methods
25
+ const sh = async (command, args) => {
26
+ var promise = new Promise(function(resolve, reject) {
27
+ log(`=> ${command}`);
28
+ exec(command, (err, stdout, stderr) => {
29
+ log(`stdout: ${stdout}`);
30
+ log(`stderr: ${stderr}`);
31
+ if (err) {
32
+ resolve({success: false, command: command});
33
+ } else {
34
+ resolve({success: true, command: command});
35
+ }
36
+ });
37
+ });
38
+ return promise;
39
+ };
40
+
41
+ const download = async (key, dest) => {
42
+ var promise = new Promise(function(resolve, reject) {
43
+ var s3 = new AWS.S3();
44
+ var params = {Bucket: S3_BUCKET, Key: key};
45
+ var file = require('fs').createWriteStream(dest);
46
+ var stream = s3.getObject(params).createReadStream();
47
+ var pipe = stream.pipe(file);
48
+ file.on('finish', function () {
49
+ resolve({success: true, pipe: pipe});
50
+ });
51
+ });
52
+ return promise;
53
+ };
54
+
55
+ const downloadAndExtract = async (zip_file, folder_dest) => {
56
+ var s3_key = `jets/code/${zip_file}`; // jets/code/bundled-checksum.zip
57
+ var download_path = `/tmp/${zip_file}`; // /tmp/bundled-checksum.zip
58
+
59
+ await download(s3_key, download_path);
60
+ await sh(`unzip -qo ${download_path} -d ${folder_dest}`);
61
+ // await sh(`ls ${folder_dest}*`);
62
+ };
63
+
64
+ // Clean out files to prevent confusing double output when debugging.
65
+ // Also clean out the file whenever done printing out the output.
66
+ function truncate(path) {
67
+ if (fs.existsSync(path)) {
68
+ fs.truncateSync(path);
69
+ }
70
+ }
71
+
72
+ // Produces an Error object that displays in the AWS Lambda test console nicely.
73
+ // The backtrace are the ruby lines, not the nodejs shim error lines.
74
+ // The json payload in the Lambda console looks something like this:
75
+ //
76
+ // {
77
+ // "errorMessage": "RubyError: RuntimeError: error in submethod",
78
+ // "errorType": "RubyError",
79
+ // "stackTrace": [
80
+ // [
81
+ // "line1",
82
+ // "line2",
83
+ // "line3"
84
+ // ]
85
+ // ]
86
+ // }
87
+ //
88
+ function rubyError(resp) {
89
+ var name = resp["errorType"];
90
+ var message = resp["errorMessage"];
91
+ var stack = resp["stackTrace"];
92
+ stack.unshift(message); // JS error includes the error message at the top of the stacktrac also
93
+ stack = stack.join("\n");
94
+
95
+ var error = new Error(message);
96
+ error.name = name;
97
+ error.stack = stack;
98
+ return error;
99
+ }
100
+
101
+ // On AWS Lambda, we can log to either stdout or stderr and we're okay.
102
+ // But locally when we're testing the shim, the log output can mess up piping
103
+ // to jq. So not logging to stdout because when testing this shim locally the
104
+ // stdout output messes up a pipe to jq.
105
+ function log(text, level="info") {
106
+ if (level == "info" && JETS_DEBUG) {
107
+ // only log if JETS_DEBUG is set
108
+ console.error(text);
109
+ } else if (level == "debug") {
110
+ // always log if "debug" passed into method
111
+ console.error(text);
112
+ }
113
+ }
114
+
115
+ ////////////////////////////////////////////////////////////////////////////////
116
+ // Logic that runs once in the lambda execution context
117
+
118
+ const downloadTmp = async () => {
119
+ var start = Date.now();
120
+
121
+ <% if Jets.lazy_load? -%>
122
+ var bundled = downloadAndExtract(BUNDLED_ZIP, '/tmp/bundled');
123
+ <% end -%>
124
+ <% if Jets.rack? -%>
125
+ var rack = downloadAndExtract(RACK_ZIP, '/tmp/rack');
126
+ <% end -%>
127
+ <% if Jets.lazy_load? -%>
128
+ // Interestingly, doesnt seem to speed up download with parallization below.
129
+ // Think this is because node does not take advantage of multiple cores?
130
+ // Leaving this in place because speed seems the same as doing the await
131
+ // in serial and hope it is fast in the future.
132
+ await bundled;
133
+ <% end -%>
134
+ <% if Jets.rack? -%>
135
+ await rack;
136
+ <% end -%>
137
+
138
+ var took = Date.now() - start;
139
+ log(`Download /tmp time: ${took}`);
140
+ };
141
+
142
+ const rubyServer = () => {
143
+ // start tcp server and detach
144
+ const subprocess = spawn('bin/ruby_server', {
145
+ detached: true,
146
+ stdio: [ 'ignore', subprocess_out, subprocess_err ]
147
+ });
148
+ subprocess.on('error', function(err) {
149
+ log('bin/ruby_server error', err);
150
+ });
151
+
152
+ subprocess.on('close', function(exit_code) {
153
+ log("Subprocess was shut down or deattached!");
154
+ });
155
+
156
+ // prevent the parent from waiting for a subprocess to exit
157
+ // https://nodejs.org/api/child_process.html
158
+ subprocess.unref();
159
+ };
160
+
161
+ // once runs in lambda execution context
162
+ const once = async () => {
163
+ // Uncomment fake run once locally. No need to do this on real lambda environment.
164
+ // var filename = '/tmp/once.txt';
165
+ // if (fs.existsSync(filename)) {
166
+ // log("fake run only once. /tmp/once.txt exists. remove to run once again.");
167
+ // return;
168
+ // }
169
+ // fs.closeSync(fs.openSync(filename, 'w'));
170
+
171
+ <% if Jets.rack? || Jets.lazy_load? -%>
172
+ await downloadTmp();
173
+ <% end -%>
174
+ // The server related methods are fire and forget.
175
+ // Not using await here because had trouble resolving the promise on client.connect
176
+ rubyServer(); // no await
177
+ };
178
+
179
+ // currying function to make handler code prettier
180
+ function handler(full_handler_name) {
181
+ return function(event, context, callback) {
182
+ request(event, full_handler_name, callback);
183
+ };
184
+ }
185
+
186
+ ////////////////////////////////////////////////////////////////////////////////
187
+ // main logic for handler
188
+ function request(event, handler, callback) {
189
+ truncate(JETS_OUTPUT);
190
+ truncate(TMP_LOG_PATH);
191
+
192
+ log("event:");
193
+ log(event);
194
+ var client = new net.Socket();
195
+ client.connect(8080, '127.0.0.01', function() {
196
+ log('Connected to socket');
197
+ client.write(JSON.stringify(event));
198
+ client.write("\r\n"); // important: \r\n is how server knows input is done
199
+ client.write(handler);
200
+ client.write("\r\n"); // important: \r\n is how server knows input is done
201
+ });
202
+
203
+ // string concatation in javascript is faster than array concatation
204
+ // http://bit.ly/2gBMDs6
205
+ var response_buffer = ""; // response buffer
206
+ client.on('data', function(buffer) {
207
+ log('Received data from socket: ' + buffer);
208
+ response_buffer += buffer;
209
+ });
210
+
211
+ client.on('close', function() {
212
+ log('Socket connection closed');
213
+ // If server is not yet running, socket immediately closes and response_buffer
214
+ // is still empty. Return right away for this case, so request can retry.
215
+ if (response_buffer == "") {
216
+ return;
217
+ }
218
+
219
+ if (fs.existsSync(JETS_OUTPUT)) {
220
+ // Thanks: https://stackoverflow.com/questions/6156501/read-a-file-one-line-at-a-time-in-node-js
221
+ var rd = readline.createInterface({
222
+ input: fs.createReadStream(JETS_OUTPUT),
223
+ // output: process.stdout,
224
+ console: false
225
+ });
226
+
227
+ rd.on('line', (line) => {
228
+ // Important to use console.error in case locally testing shim or we see
229
+ // stdout "twice", once from here and once from ruby-land and it's confusing.
230
+ // AWS lambda will write console.error and console.log to CloudWatch.
231
+ console.error(line); // output to AWS Lambda Logs
232
+ }).on('close', () => {
233
+ truncate(JETS_OUTPUT); // done reporting output, clear out file again
234
+ });
235
+ }
236
+
237
+ var resp = JSON.parse(response_buffer);
238
+ if (resp && resp["errorMessage"]) {
239
+ // Customize error object for lambda format
240
+ var error = rubyError(resp);
241
+ callback(error);
242
+ } else {
243
+ callback(null, resp);
244
+ }
245
+ client.destroy(); // kill client after server's response
246
+ });
247
+
248
+ client.on('error', function(error) {
249
+ log("Socket error:");
250
+ log(error);
251
+ log("Retrying request");
252
+ setTimeout(function() {
253
+ if (fs.existsSync(TMP_LOG_PATH)) {
254
+ var contents = fs.readFileSync(TMP_LOG_PATH, 'utf8');
255
+ if (contents != "") {
256
+ log("subprocess output:", "debug");
257
+ log(contents, "debug");
258
+ }
259
+ }
260
+ truncate(TMP_LOG_PATH);
261
+
262
+ log("Retrying request NOW");
263
+ request(event, handler, callback);
264
+ }, 500);
265
+ });
266
+ }
267
+
268
+ module.exports = {
269
+ handler: handler,
270
+ once: once
271
+ };
@@ -0,0 +1,80 @@
1
+ class Jets::Builders
2
+ class Tidy
3
+ def initialize(project_root, noop: false)
4
+ @project_root = project_root
5
+ @noop = noop
6
+ end
7
+
8
+ def cleanup!
9
+ removals.each do |removal|
10
+ removal = removal.sub(%r{^/},'') # remove leading slash
11
+ path = "#{@project_root}/#{removal}"
12
+ rm_rf(path)
13
+ end
14
+
15
+ tidy_bundled
16
+ end
17
+
18
+ def removals
19
+ removals = always_removals
20
+ removals += get_removals("#{@project_root}/.gitignore")
21
+ removals += get_removals("#{@project_root}/.dockerignore")
22
+ removals = removals.reject do |p|
23
+ jetskeep.find do |keep|
24
+ p.include?(keep)
25
+ end
26
+ end
27
+ removals.uniq
28
+ end
29
+
30
+ def get_removals(file)
31
+ path = file
32
+ return [] unless File.exist?(path)
33
+
34
+ removal = File.read(path).split("\n")
35
+ removal.map {|i| i.strip}.reject {|i| i =~ /^#/ || i.empty?}
36
+ # IE: ["/handlers", "/bundled*", "/vendor/jets]
37
+ end
38
+
39
+ # We clean out ignored files pretty aggressively. So provide
40
+ # a way for users to keep files from being cleaned out.
41
+ def jetskeep
42
+ defaults = %w[.bundle bundled pack handlers public/assets]
43
+ path = "#{@project_root}/.jetskeep"
44
+ return defaults unless File.exist?(path)
45
+
46
+ keep = IO.readlines(path)
47
+ keep = keep.map {|i| i.strip}.reject { |i| i =~ /^#/ || i.empty? }
48
+ (defaults + keep).uniq
49
+ end
50
+
51
+ # folders to remove in the bundled folder regardless of the level of the folder
52
+ def tidy_bundled
53
+ Dir.glob("#{@project_root}/bundled/**/*").each do |path|
54
+ next unless File.directory?(path)
55
+ dir = File.basename(path)
56
+ next unless always_removals.include?(dir)
57
+
58
+ rm_rf(path)
59
+ end
60
+ end
61
+
62
+ def rm_rf(path)
63
+ exists = File.exist?("#{path}/.gitkeep") || File.exist?("#{path}/.keep")
64
+ return if exists
65
+
66
+ # say " rm -rf #{path}".colorize(:yellow) # uncomment to debug
67
+ system("rm -rf #{path}") unless @noop
68
+ end
69
+
70
+ # These directories will be removed regardless of dir level
71
+ def always_removals
72
+ %w[.git spec tmp]
73
+ end
74
+
75
+ def say(message)
76
+ message = "NOOP #{message}" if @noop
77
+ puts message
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,28 @@
1
+ class Jets::Builders
2
+ module Util
3
+ def sh(command)
4
+ puts "=> #{command}".colorize(:green)
5
+ success = system(command)
6
+ abort("#{command} failed to run") unless success
7
+ success
8
+ end
9
+
10
+ def headline(message)
11
+ puts "=> #{message}".colorize(:cyan)
12
+ end
13
+
14
+ # Provide pretty clear way to desinate full path.
15
+ # full("bundled") => /tmp/jets/demo/bundled
16
+ def full(relative_path)
17
+ "#{Jets.build_root}/#{relative_path}"
18
+ end
19
+
20
+ # Finds out of the app has polymorphic functions only and zero ruby functions.
21
+ # In this case, we can skip a lot of the ruby related building and speed up the
22
+ # deploy process.
23
+ def poly_only?
24
+ return true if ENV['POLY_ONLY'] # bypass to allow rapid development of handlers
25
+ Jets::Commands::Build.poly_only?
26
+ end
27
+ end
28
+ end
data/lib/jets/builders.rb CHANGED
@@ -1,7 +1,13 @@
1
1
  class Jets::Builders
2
2
  autoload :CodeBuilder, "jets/builders/code_builder"
3
- autoload :Deducer, "jets/builders/deducer"
4
3
  autoload :GemReplacer, "jets/builders/gem_replacer"
5
4
  autoload :HandlerGenerator, "jets/builders/handler_generator"
6
- autoload :SharedDeducer, "jets/builders/shared_deducer"
5
+ autoload :Md5, "jets/builders/md5"
6
+ autoload :Md5Zip, "jets/builders/md5_zip"
7
+ autoload :RackPackager, "jets/builders/rack_packager"
8
+ autoload :ReconfigureRails, "jets/builders/reconfigure_rails"
9
+ autoload :RubyPackager, "jets/builders/ruby_packager"
10
+ autoload :ShimVars, "jets/builders/shim_vars"
11
+ autoload :Tidy, "jets/builders/tidy"
12
+ autoload :Util, "jets/builders/util"
7
13
  end
@@ -10,15 +10,5 @@ class Jets::Cfn::Builders
10
10
  add_common_parameters
11
11
  add_functions
12
12
  end
13
-
14
- # For function stacks, ensure there's a _function.yml at the end of the
15
- # template_path name for easy identification.
16
- def template_path
17
- path = super
18
- unless path.include?("function.yml")
19
- path = path.sub(".yml", "_function.yml")
20
- end
21
- path
22
- end
23
13
  end
24
14
  end
@@ -12,10 +12,8 @@ class Jets::Cfn::Builders
12
12
 
13
13
  # compose is an interface method
14
14
  def compose
15
- puts "Building parent CloudFormation template."
16
-
17
15
  build_minimal_resources
18
- build_child_resources if @options[:templates] || @options[:stack_type] == :full
16
+ build_child_resources if full?
19
17
  end
20
18
 
21
19
  # template_path is an interface method
@@ -29,6 +27,7 @@ class Jets::Cfn::Builders
29
27
  add_resource(resource)
30
28
  add_outputs(resource.outputs)
31
29
 
30
+ return unless full?
32
31
  # Add application-wide IAM policy from Jets.config.iam_role
33
32
  resource = Jets::Resource::Iam::ApplicationRole.new
34
33
  add_resource(resource)
@@ -36,8 +35,6 @@ class Jets::Cfn::Builders
36
35
  end
37
36
 
38
37
  def build_child_resources
39
- puts "Building child CloudFormation templates."
40
-
41
38
  expression = "#{Jets::Naming.template_path_prefix}-app-*"
42
39
  # IE: path: #{Jets.build_root}/templates/demo-dev-2-comments_controller.yml
43
40
  Dir.glob(expression).each do |path|
@@ -53,12 +50,16 @@ class Jets::Cfn::Builders
53
50
  add_shared_resources(path)
54
51
  end
55
52
 
56
- if (@options[:templates] || @options[:stack_type] == :full) and !Jets::Router.routes.empty?
53
+ if full? and !Jets::Router.routes.empty?
57
54
  add_api_gateway
58
55
  add_api_deployment
59
56
  end
60
57
  end
61
58
 
59
+ def full?
60
+ @options[:templates] || @options[:stack_type] == :full
61
+ end
62
+
62
63
  def add_app_class_stack(path)
63
64
  resource = Jets::Resource::ChildStack::AppClass.new(@options[:s3_bucket], path: path)
64
65
  add_child_resources(resource)
data/lib/jets/cfn/ship.rb CHANGED
@@ -1,10 +1,7 @@
1
- require 'action_view'
2
-
3
1
  class Jets::Cfn
4
2
  class Ship
5
3
  include Jets::Timing
6
4
  include Jets::AwsServices
7
- include ActionView::Helpers::NumberHelper # number_to_human_size
8
5
 
9
6
  def initialize(options)
10
7
  @options = options
@@ -13,8 +10,8 @@ class Jets::Cfn
13
10
  end
14
11
 
15
12
  def run
16
- upload_to_s3 if @options[:stack_type] == :full # s3 bucket is available
17
- # only when stack_type is full
13
+ # s3 bucket is available only when stack_type is full
14
+ upload_to_s3 if @options[:stack_type] == :full
18
15
 
19
16
  stack_in_progress?(@parent_stack_name)
20
17
 
@@ -81,11 +78,15 @@ class Jets::Cfn
81
78
  time :wait_for_stack
82
79
 
83
80
  def prewarm
81
+ if ENV['SKIP_PREWARMING']
82
+ puts "Skipping prewarming" # useful for testing
83
+ return
84
+ end
84
85
  return unless @options[:stack_type] == :full # s3 bucket is available
85
86
  return unless Jets.config.prewarm.enable
86
87
  return if Jets::Commands::Build.poly_only?
87
88
 
88
- puts "Prewarming application..."
89
+ puts "Prewarming application."
89
90
  if Jets::PreheatJob::CONCURRENCY > 1
90
91
  Jets::PreheatJob.perform_now(:torch, {quiet: true})
91
92
  else
@@ -143,104 +144,9 @@ class Jets::Cfn
143
144
  def upload_to_s3
144
145
  raise "Did not specify @options[:s3_bucket] #{@options[:s3_bucket].inspect}" unless @options[:s3_bucket]
145
146
 
146
- upload_cfn_templates
147
- upload_code
148
- upload_assets
147
+ uploader = Upload.new(@options[:s3_bucket])
148
+ uploader.upload
149
149
  end
150
150
  time :upload_to_s3
151
-
152
- def bucket_name
153
- @options[:s3_bucket]
154
- end
155
-
156
- def upload_cfn_templates
157
- puts "Uploading child CloudFormation templates to S3"
158
- expression = "#{Jets::Naming.template_path_prefix}-*"
159
- Dir.glob(expression).each do |path|
160
- next unless File.file?(path)
161
-
162
- key = "jets/cfn-templates/#{File.basename(path)}"
163
- obj = s3_resource.bucket(bucket_name).object(key)
164
- obj.upload_file(path)
165
- end
166
- end
167
-
168
- def upload_code
169
- md5_code_zipfile = Jets::Naming.md5_code_zipfile
170
- file_size = number_to_human_size(File.size(md5_code_zipfile))
171
-
172
- puts "Uploading #{md5_code_zipfile} (#{file_size}) to S3"
173
- start_time = Time.now
174
- key = Jets::Naming.code_s3_key
175
- obj = s3_resource.bucket(bucket_name).object(key)
176
- obj.upload_file(md5_code_zipfile)
177
- puts "Time to upload code to s3: #{pretty_time(Time.now-start_time).colorize(:green)}"
178
- end
179
-
180
- def upload_assets
181
- puts "Uploading public assets"
182
- start_time = Time.now
183
- asset_folders = Jets.config.assets.folders
184
- asset_folders.each do |folder|
185
- upload_asset_folder(folder)
186
- end
187
- puts "Time to upload public assets to s3: #{pretty_time(Time.now-start_time).colorize(:green)}"
188
- end
189
-
190
- def upload_asset_folder(folder)
191
- expression = "#{Jets.root}public/#{folder}/**/*"
192
- group_size = 10
193
- Dir.glob(expression).each_slice(group_size) do |paths|
194
- threads = []
195
- paths.each do |path|
196
- next unless File.file?(path)
197
-
198
- regexp = Regexp.new(".*/#{folder}/")
199
- relative_path = path.sub(regexp,'')
200
- file = "#{folder}/#{relative_path}"
201
-
202
- threads << Thread.new do
203
- upload_asset_file(file)
204
- end
205
- end
206
- threads.each(&:join)
207
- end
208
- end
209
-
210
- def upload_asset_file(file)
211
- path = "#{Jets.root}public/#{file}"
212
- key = "jets/public/#{file}"
213
- puts "Uploading s3://#{bucket_name}/#{key}" # uncomment to see and debug
214
- obj = s3_resource.bucket(bucket_name).object(key)
215
- obj.upload_file(path, acl: "public-read", cache_control: cache_control)
216
- end
217
-
218
- # If cache_control is provided, then it will set the entire cache-control header.
219
- # If only max_age is provided, then we'll generate a cache_control header.
220
- # Using max_age is the shorter and simply way of setting the cache_control header.
221
- def cache_control
222
- cache_control = Jets.config.assets.cache_control
223
- unless cache_control
224
- max_age = Jets.config.assets.max_age # defaults to 3600 in jets/application.rb
225
- cache_control = "public, max-age=#{max_age}"
226
- end
227
- cache_control
228
- end
229
-
230
- def s3_bucket
231
- @options[:s3_bucket]
232
- end
233
-
234
- # http://stackoverflow.com/questions/4175733/convert-duration-to-hoursminutesseconds-or-similar-in-rails-3-or-ruby
235
- def pretty_time(total_seconds)
236
- minutes = (total_seconds / 60) % 60
237
- seconds = total_seconds % 60
238
- if total_seconds < 60
239
- "#{seconds.to_i}s"
240
- else
241
- "#{minutes.to_i}m #{seconds.to_i}s"
242
- end
243
- end
244
-
245
151
  end
246
152
  end