jets 2.1.1 → 2.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.codebuild/README.md +10 -60
  3. data/.codebuild/docs/bin/build.sh +6 -0
  4. data/.codebuild/docs/bin/cli_docs.sh +5 -0
  5. data/.codebuild/docs/bin/git_commit.sh +27 -0
  6. data/.codebuild/docs/bin/git_setup.sh +19 -0
  7. data/.codebuild/docs/bin/subnav.sh +14 -0
  8. data/.codebuild/docs/buildspec.yml +8 -0
  9. data/.codebuild/docs/project.rb +10 -0
  10. data/.gitignore +5 -5
  11. data/CHANGELOG.md +8 -0
  12. data/jets.gemspec +5 -5
  13. data/lib/jets/aws_services/stack_status.rb +5 -1
  14. data/lib/jets/cfn/builders/api_gateway_builder.rb +10 -19
  15. data/lib/jets/cfn/builders/api_resources_builder.rb +46 -0
  16. data/lib/jets/cfn/builders/parent_builder.rb +15 -0
  17. data/lib/jets/cfn/built_template.rb +15 -0
  18. data/lib/jets/commands/clean/log.rb +18 -1
  19. data/lib/jets/commands/delete.rb +14 -1
  20. data/lib/jets/commands/deploy.rb +43 -12
  21. data/lib/jets/commands/help/build.md +1 -1
  22. data/lib/jets/commands/help/{destroy.md → degenerate.md} +1 -1
  23. data/lib/jets/commands/help/upgrade.md +2 -0
  24. data/lib/jets/commands/main.rb +2 -1
  25. data/lib/jets/commands/templates/skeleton/Gemfile.tt +1 -0
  26. data/lib/jets/naming.rb +4 -0
  27. data/lib/jets/resource/api_gateway/resource.rb +7 -3
  28. data/lib/jets/resource/api_gateway/rest_api/change_detection.rb +0 -32
  29. data/lib/jets/resource/api_gateway/rest_api/routes/change.rb +9 -1
  30. data/lib/jets/resource/api_gateway/rest_api/routes/change/base.rb +26 -5
  31. data/lib/jets/resource/api_gateway/rest_api/routes/change/media_types.rb +36 -0
  32. data/lib/jets/resource/api_gateway/rest_api/routes/change/page.rb +93 -0
  33. data/lib/jets/resource/api_gateway/rest_api/routes/change/to.rb +0 -4
  34. data/lib/jets/resource/api_gateway/rest_api/routes/change/variable.rb +0 -4
  35. data/lib/jets/resource/child_stack/api_resource.rb +60 -0
  36. data/lib/jets/resource/child_stack/api_resource/page.rb +20 -0
  37. data/lib/jets/resource/child_stack/app_class.rb +14 -3
  38. data/lib/jets/router.rb +57 -40
  39. data/lib/jets/router/method_creator/code.rb +3 -1
  40. data/lib/jets/router/method_creator/edit.rb +6 -1
  41. data/lib/jets/router/method_creator/index.rb +9 -3
  42. data/lib/jets/router/method_creator/new.rb +6 -1
  43. data/lib/jets/router/method_creator/show.rb +6 -1
  44. data/lib/jets/router/route.rb +1 -0
  45. data/lib/jets/version.rb +1 -1
  46. metadata +22 -17
  47. data/.codebuild/bin/jets +0 -3
  48. data/.codebuild/buildspec-base.yml +0 -14
  49. data/.codebuild/integration.sh +0 -72
  50. data/.codebuild/jets.postman_collection.json +0 -323
  51. data/.codebuild/scripts/install-docker.sh +0 -12
  52. data/.codebuild/scripts/install-dynamodb-local.sh +0 -22
  53. data/.codebuild/scripts/install-java.sh +0 -22
  54. data/.codebuild/scripts/install-node.sh +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 82e56d77408579a757373a115134668315a2c47fdbcd297f8eae827951274f6a
4
- data.tar.gz: 0152fbf8fe291033319761e987667026a77958b67398ba237d9152cc70a00615
3
+ metadata.gz: bdc43f68b08d9c92593eeb3ccfc2477a1080af2cd4430e32f4766c2756c70b23
4
+ data.tar.gz: f842a52a1c9a448545f3a7ade22e1c14c8ce2a4d556169c574b4f5a58675c450
5
5
  SHA512:
6
- metadata.gz: f638230df0a341ee7b4e0a73355a89a650a78178d7ebb46326c4215d40ea4d33d6648a3d0909a98789e416b4c03c59bae8b5c8e5a94e254c45de78915e5214c4
7
- data.tar.gz: 5a9e606725ae25d18c3ce4b1ea901780d7062245035c20a9d5139566b0e92ab998d9c3e6d2bb14081a5e77c04bfa5bb871ed95db51ac48467c42f186292b82ab
6
+ metadata.gz: e4efe902131423d3aa95b2e9e42e9b7cdefc78871d0c6eedbc1bbc98ee5cb2771ce7e9ba6c908c00f018960ddbba6aa1e3d5ea745b31c3cb1593770f20bb1ebc
7
+ data.tar.gz: 363c2292150bf101d9ee5196de2bf82465d59cbb255d3c541c4fc3e44e08421b83bafe52c797a6ef07a7bdae63a727cc476000eadc914397243d1a587ad9824d
data/.codebuild/README.md CHANGED
@@ -1,68 +1,18 @@
1
- # Code Build Commands
1
+ ## Update Project
2
2
 
3
- ## The code definitions are stored in the codebuild s3 bucket.
3
+ To update the CodeBuild project:
4
4
 
5
- aws s3 cp .codebuild/definitions/jets_base.json s3://$S3_BUCKET/codebuild/definitions/jets_base.json
6
- aws s3 cp .codebuild/definitions/jets_main.json s3://$S3_BUCKET/codebuild/definitions/jets_main.json
5
+ Main services:
7
6
 
8
- ## JetsBase
7
+ export AWS_PROFILE=bolt-oss
8
+ cb deploy jets --type docs # mainly cli docs and subnav update
9
9
 
10
- The JetsBase codebuild project projects builds the Docker base image and pushes it to Docker hub. Here are the commands to manage the codebuild project.
10
+ ## Start a Deploy
11
11
 
12
- aws codebuild create-project --cli-input-json file://.codebuild/definitions/jets_base.json
13
- aws codebuild update-project --cli-input-json file://.codebuild/definitions/jets_base.json
12
+ To start a CodeBuild build which kicks off a deploy:
14
13
 
15
- aws codebuild start-build --project-name JetsBase --source-version codebuild
14
+ cb start jets --type docs
16
15
 
17
- aws codebuild batch-get-projects --names JetsBase
18
- aws codebuild list-builds-for-project --project-name JetsBase
16
+ To specify a branch:
19
17
 
20
- BUILD_ID=$(aws codebuild list-builds-for-project --project-name JetsBase | jq -r '.ids[0]')
21
- aws codebuild batch-get-builds --ids $BUILD_ID
22
-
23
- STREAM=$(aws codebuild batch-get-builds --ids $BUILD_ID | jq -r '.builds[0].logs.streamName')
24
- cw tail -f /aws/codebuild/JetsBase $STREAM
25
-
26
- If you want to manually build the Docker base image. Run:
27
-
28
- docker build -t tongueroo/jets:base -f Dockerfile.base .
29
- docker push tongueroo/jets:base
30
-
31
- ## JetsMain
32
-
33
- aws codebuild create-project --cli-input-json file://.codebuild/definitions/jets_main.json
34
- aws codebuild update-project --cli-input-json file://.codebuild/definitions/jets_main.json
35
-
36
- aws codebuild start-build --project-name JetsMain --source-version codebuild
37
-
38
- aws codebuild batch-get-projects --names JetsMain
39
- aws codebuild list-builds-for-project --project-name JetsMain
40
-
41
- BUILD_ID=$(aws codebuild list-builds-for-project --project-name JetsMain | jq -r '.ids[0]')
42
- aws codebuild batch-get-builds --ids $BUILD_ID
43
-
44
- STREAM=$(aws codebuild batch-get-builds --ids $BUILD_ID | jq -r '.builds[0].logs.streamName')
45
- cw tail -f /aws/codebuild/JetsMain $STREAM
46
-
47
- ## Run CodeBuild Locally
48
-
49
- time docker run -it -v /var/run/docker.sock:/var/run/docker.sock \
50
- -e "IMAGE_NAME=tongueroo/jets:base" \
51
- -e "ARTIFACTS=/tmp/artifacts" \
52
- -e "SOURCE=/home/ec2-user/environment/jets" \
53
- -e "DB_USER=$DB_USER" \
54
- -e "DB_PASS=$DB_PASS" \
55
- -e "DB_HOST=$DB_HOST" \
56
- amazon/aws-codebuild-local
57
-
58
- ## Run ingreration.sh
59
-
60
- Can run the integration.sh test locally by running:
61
-
62
- export DB_NAME=demo
63
- export DB_USER=dbuser
64
- export DB_PASS=dbpass
65
- export DB_HOST=rdshost
66
- .codebuild/integration.sh
67
-
68
- Note, you'll need to use a real RDS db instance. Make sure DATABASE_URL is not set, this is working with the DB_* vars.
18
+ cb start jets --type docs --branch codebuild
@@ -0,0 +1,6 @@
1
+ #!/bin/bash -eux
2
+
3
+ .codebuild/docs/bin/git_setup.sh
4
+ .codebuild/docs/bin/cli_docs.sh
5
+ .codebuild/docs/bin/subnav.sh
6
+ .codebuild/docs/bin/git_commit.sh
@@ -0,0 +1,5 @@
1
+ #!/bin/bash -eux
2
+
3
+ # Generate docs
4
+ bundle
5
+ rake docs
@@ -0,0 +1,27 @@
1
+ #!/bin/bash -eux
2
+
3
+ out=$(git status docs)
4
+ if [[ "$out" = *"nothing to commit"* ]]; then
5
+ exit
6
+ fi
7
+
8
+ COMMIT_MESSAGE="docs updated by codebuild"
9
+
10
+ # If the last commit already updated the docs, then exit.
11
+ # Preventable measure to avoid infinite loop.
12
+ if git log -1 --pretty=oneline | grep "$COMMIT_MESSAGE" ; then
13
+ exit
14
+ fi
15
+
16
+ # If reach here, we have some changes on docs that we should commit.
17
+ git add docs
18
+ git commit -m "$COMMIT_MESSAGE"
19
+
20
+ # SSH_KEY_S3_PATH set as codebuild environment variable
21
+ aws s3 cp $SSH_KEY_S3_PATH ~/.ssh/id_rsa
22
+ chmod 400 ~/.ssh/id_rsa
23
+ sed -i -- 's|https://github.com/|git@github.com:|g' .git/config
24
+
25
+ # https://makandracards.com/makandra/12107-git-show-current-branch-name-only
26
+ current_branch=$(git rev-parse --abbrev-ref HEAD)
27
+ git push origin "$current_branch"
@@ -0,0 +1,19 @@
1
+ #!/bin/bash -eux
2
+
3
+ # git push:
4
+ # CODEBUILD_WEBHOOK_HEAD_REF=refs/heads/codebuild
5
+ # CODEBUILD_WEBHOOK_TRIGGER=branch/codebuild
6
+ # CODEBUILD_SOURCE_VERSION=f0eb542 # resolved sha
7
+ # cb start:
8
+ # CODEBUILD_SOURCE_VERSION=codebuild
9
+
10
+ set +u # cb start will not have CODEBUILD_WEBHOOK_TRIGGER set
11
+ if [ -n "$CODEBUILD_WEBHOOK_TRIGGER" ]; then # git push
12
+ BRANCH=$(echo $CODEBUILD_WEBHOOK_TRIGGER | sed "s/.*\///")
13
+ elif [ -n "$CODEBUILD_SOURCE_VERSION" ]; then # cb start
14
+ BRANCH=$CODEBUILD_SOURCE_VERSION # contains the actual branch
15
+ else
16
+ BRANCH=UNKNOWN-BRANCH
17
+ fi
18
+ git checkout $BRANCH
19
+ set -u
@@ -0,0 +1,14 @@
1
+ #!/bin/bash -eux
2
+
3
+ cd docs
4
+ # Unsure why but if cli_docs.sh runs bundle first, then bundle wont use the right bundler file
5
+ export BUNDLE_GEMFILE=$(pwd)/Gemfile
6
+ bundle
7
+ bundle exec jekyll serve --detach
8
+
9
+ # Error: front_matter_parser-0.2.1/lib/front_matter_parser/syntax_parser/multi_line_comment.rb:19:in `match': invalid byte sequence in US-ASCII (ArgumentError)
10
+ # Workaround: https://stackoverflow.com/questions/17031651/invalid-byte-sequence-in-us-ascii-argument-error-when-i-run-rake-dbseed-in-ra
11
+ export RUBYOPT="-KU -E utf-8:utf-8" # fixes front_matter_parser error within the `jekyll-sort reorder` call
12
+
13
+ gem install jekyll-sort
14
+ jekyll-sort reorder # Updates nav_order front matter of pages that are in the nav
@@ -0,0 +1,8 @@
1
+ version: 0.2
2
+
3
+ phases:
4
+ build:
5
+ commands:
6
+ - git config --global user.email "tongueroo@gmail.com"
7
+ - git config --global user.name "Tung Nguyen"
8
+ - .codebuild/docs/bin/build.sh
@@ -0,0 +1,10 @@
1
+ github_url("https://github.com/tongueroo/jets.git")
2
+ linux_image("aws/codebuild/ruby:2.5.3-1.7.0")
3
+ triggers(
4
+ webhook: true,
5
+ filter_groups: [[{type: "HEAD_REF", pattern: "master"}, {type: "EVENT", pattern: "PUSH"}]]
6
+ )
7
+
8
+ environment_variables(
9
+ SSH_KEY_S3_PATH: "ssm:/codebuild/jets/ssh_key_s3_path"
10
+ )
data/.gitignore CHANGED
@@ -1,12 +1,13 @@
1
1
  *.gem
2
2
  *.rbc
3
3
  .bundle
4
+ .byebug_history
4
5
  .config
5
6
  .yardoc
6
- InstalledFiles
7
7
  _yardoc
8
8
  coverage
9
9
  doc/
10
+ InstalledFiles
10
11
  lib/bundler/man
11
12
  pkg
12
13
  rdoc
@@ -15,10 +16,9 @@ test/tmp
15
16
  test/version_tmp
16
17
  tmp
17
18
 
18
- spec/fixtures/project/handlers
19
19
  .codebuild/definitions
20
- demo*
21
20
  /html
21
+ /demo
22
+ Gemfile.lock
22
23
  spec/fixtures/apps/franky/dynamodb/migrate
23
- Gemfile.lock
24
- .byebug_history
24
+ spec/fixtures/project/handlers
data/CHANGELOG.md CHANGED
@@ -3,6 +3,14 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  This project *loosely tries* to adhere to [Semantic Versioning](http://semver.org/).
5
5
 
6
+ ## [2.1.2]
7
+ - improve start .env.development example for postgres
8
+ - #351 Update Turbine documentation
9
+ - #355 improve jets routes command to also validate routes
10
+ - #356 improvements to named route helpers
11
+ - #357 paginate api gateway resources to support more routes
12
+ - #358 rate limit backoff
13
+
6
14
  ## [2.1.1]
7
15
  - #347 Add documentation about torch vs. warm
8
16
  - #348 Provide another minimal privileges example
data/jets.gemspec CHANGED
@@ -7,11 +7,11 @@ require "jets/rdoc"
7
7
  Gem::Specification.new do |spec|
8
8
  spec.name = "jets"
9
9
  spec.version = Jets::VERSION
10
- spec.authors = ["Tung Nguyen"]
11
- spec.email = ["tongueroo@gmail.com"]
12
- spec.summary = "Ruby Serverless Framework on AWS Lambda"
13
- spec.description = "Jets is a framework that allows you to create serverless applications with a beautiful language: Ruby. It includes everything required to build an application and deploy it to AWS Lambda. Jets makes serverless accessible to everyone."
14
- spec.homepage = "http://rubyonjets.com"
10
+ spec.author = "Tung Nguyen"
11
+ spec.email = "tongueroo@gmail.com"
12
+ spec.summary = "Ruby Serverless Framework"
13
+ spec.description = "Jets is a framework that allows you to create serverless applications with a beautiful language: Ruby. It includes everything required to build and deploy an application. Jets leverages the power of Ruby to make serverless joyful for everyone."
14
+ spec.homepage = "https://rubyonjets.com"
15
15
  spec.license = "MIT"
16
16
 
17
17
  spec.required_ruby_version = '~> 2.5'
@@ -1,13 +1,17 @@
1
1
  module Jets::AwsServices
2
2
  module StackStatus
3
+ # Only cache if it is true because the initial deploy checks live status until a stack exists.
4
+ @@stack_exists_cache = [] # helps with CloudFormation rate limit
3
5
  def stack_exists?(stack_name)
4
6
  return false if ENV['TEST']
7
+ return true if @@stack_exists_cache.include?(stack_name)
5
8
 
6
9
  exist = nil
7
10
  begin
8
11
  # When the stack does not exist an exception is raised. Example:
9
12
  # Aws::CloudFormation::Errors::ValidationError: Stack with id blah does not exist
10
- resp = cfn.describe_stacks(stack_name: stack_name)
13
+ cfn.describe_stacks(stack_name: stack_name)
14
+ @@stack_exists_cache << stack_name
11
15
  exist = true
12
16
  rescue Aws::CloudFormation::Errors::ValidationError => e
13
17
  if e.message =~ /does not exist/
@@ -12,9 +12,9 @@ module Jets::Cfn::Builders
12
12
  def compose
13
13
  return unless @options[:templates] || @options[:stack_type] != :minimal
14
14
 
15
- add_gateway_rest_api
16
- add_custom_domain
17
- add_gateway_routes
15
+ add_gateway_routes # "child template": build before add_gateway_rest_api. RestApi logical id and change detection is dependent on it.
16
+ add_gateway_rest_api # changes parent template
17
+ add_custom_domain # changes parent template
18
18
  end
19
19
 
20
20
  # template_path is an interface method
@@ -57,23 +57,14 @@ module Jets::Cfn::Builders
57
57
  end
58
58
 
59
59
  # Adds route related Resources and Outputs
60
+ # Delegates to ApiResourcesBuilder
61
+ PAGE_LIMIT = Integer(ENV['JETS_AWS_OUTPUTS_LIMIT'] || 60) # Allow override for testing
60
62
  def add_gateway_routes
61
- # The routes required a Gateway Resource to contain them.
62
- # TODO: Support more routes. Right now outputing all routes in 1 template will hit the 60 routes limit.
63
- # Will have to either output them as a joined string or break this up to multiple templates.
64
- # http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-limits.html
65
- # Outputs: Maximum number of outputs that you can declare in your AWS CloudFormation template. 60 outputs
66
- # Output name: Maximum size of an output name. 255 characters.
67
- #
68
- # Note we must use .all_paths, not .routes here because we need to
69
- # build the parent ApiGateway::Resource nodes also
70
- Jets::Router.all_paths.each do |path|
71
- homepage = path == ''
72
- next if homepage # handled by RootResourceId output already
73
-
74
- resource = Jets::Resource::ApiGateway::Resource.new(path, internal: true)
75
- add_resource(resource)
76
- add_outputs(resource.outputs)
63
+ # Reject homepage. Otherwise we have 60 - 1 resources on the first page.
64
+ # There's a next call in ApiResources.add_gateway_resources to skip the homepage.
65
+ all_paths = Jets::Router.all_paths.reject { |p| p == '' }
66
+ all_paths.each_slice(PAGE_LIMIT).each_with_index do |paths, i|
67
+ ApiResourcesBuilder.new(@options, paths, i+1).build
77
68
  end
78
69
  end
79
70
  end
@@ -0,0 +1,46 @@
1
+ module Jets::Cfn::Builders
2
+ class ApiResourcesBuilder
3
+ include Interface
4
+ include Jets::AwsServices
5
+
6
+ def initialize(options={}, paths=[], page)
7
+ @options, @paths, @page = options, paths, page
8
+ @template = ActiveSupport::HashWithIndifferentAccess.new(Resources: {})
9
+ end
10
+
11
+ # compose is an interface method
12
+ def compose
13
+ return unless @options[:templates] || @options[:stack_type] != :minimal
14
+
15
+ add_rest_api_parameter
16
+ add_gateway_routes
17
+ end
18
+
19
+ # template_path is an interface method
20
+ def template_path
21
+ Jets::Naming.api_resources_template_path(@page)
22
+ end
23
+
24
+ def add_rest_api_parameter
25
+ add_parameter("RestApi", Description: "RestApi")
26
+ end
27
+
28
+ def add_gateway_routes
29
+ @paths.each do |path|
30
+ homepage = path == ''
31
+ next if homepage # handled by RootResourceId output already
32
+
33
+ resource = Jets::Resource::ApiGateway::Resource.new(path)
34
+ add_resource(resource)
35
+ add_outputs(resource.outputs)
36
+
37
+ parent_path = resource.parent_path_parameter
38
+ add_parameter(parent_path) unless part_of_template?(parent_path)
39
+ end
40
+ end
41
+
42
+ def part_of_template?(parent_path)
43
+ @template["Resources"].key?(parent_path)
44
+ end
45
+ end
46
+ end
@@ -57,6 +57,7 @@ module Jets::Cfn::Builders
57
57
 
58
58
  if full? and !Jets::Router.routes.empty?
59
59
  add_api_gateway
60
+ add_api_resources
60
61
  add_api_deployment
61
62
  end
62
63
  end
@@ -80,6 +81,20 @@ module Jets::Cfn::Builders
80
81
  add_child_resources(resource)
81
82
  end
82
83
 
84
+ def add_api_resources
85
+ expression = "#{Jets::Naming.template_path_prefix}-api-resources-*"
86
+ # IE: path: #{Jets.build_root}/templates/demo-dev-2-api-resources-1.yml"
87
+ Dir.glob(expression).sort.each do |path|
88
+ next unless File.file?(path)
89
+
90
+ regexp = Regexp.new("#{Jets.config.project_namespace}-api-resources-(\\d+).yml") # tricky to escape \d pattern
91
+ md = path.match(regexp)
92
+ page = md[1]
93
+ resource = Jets::Resource::ChildStack::ApiResource.new(@options[:s3_bucket], page: page)
94
+ add_child_resources(resource)
95
+ end
96
+ end
97
+
83
98
  def add_api_deployment
84
99
  resource = Jets::Resource::ChildStack::ApiDeployment.new(@options[:s3_bucket])
85
100
  add_child_resources(resource)
@@ -0,0 +1,15 @@
1
+ module Jets::Cfn
2
+ # Caches the built template to reduce filesystem IO calls.
3
+ class BuiltTemplate
4
+ class << self
5
+ @@cache = {}
6
+ def get(path)
7
+ if @@cache[path]
8
+ @@cache[path] # using cache
9
+ else
10
+ @@cache[path] = YAML.load_file(path) # setting and using cache
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -19,12 +19,29 @@ class Jets::Commands::Clean
19
19
  say "Removing CloudWatch logs for #{prefix_guess}..."
20
20
  log_groups.each do |g|
21
21
  next if keep_log_group?(g.log_group_name)
22
- logs.delete_log_group(log_group_name: g.log_group_name) unless @options[:noop]
22
+ delete_log_group(g.log_group_name) unless @options[:noop]
23
23
  say "Removed log group: #{g.log_group_name}"
24
24
  end
25
25
  say "Removed CloudWatch logs for #{prefix_guess}"
26
26
  end
27
27
 
28
+ def delete_log_group(log_group_name)
29
+ retries = 0
30
+ logs.delete_log_group(log_group_name: log_group_name)
31
+ rescue Aws::CloudWatchLogs::Errors::ThrottlingException => e
32
+ retries += 1
33
+ seconds = 2 ** retries
34
+
35
+ puts "WARN: delete_log_group #{e.class} #{e.message}".color(:yellow)
36
+ puts "Backing off and will retry in #{seconds} seconds."
37
+ sleep(seconds)
38
+ if seconds > 90 # 2 ** 6 is 64 so will give up after 6 retries
39
+ puts "Giving up after #{retries} retries"
40
+ else
41
+ retry
42
+ end
43
+ end
44
+
28
45
  def clean_deploys
29
46
  groups = deploy_log_groups.sort_by do |g|
30
47
  g.log_group_name