shipitron 1.2.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.buildkite/pipeline.yml +94 -0
  3. data/.dockerignore +1 -0
  4. data/.gitattributes +1 -0
  5. data/.gitignore +1 -0
  6. data/.rspec +1 -0
  7. data/Deskfile +15 -0
  8. data/Dockerfile +40 -15
  9. data/Dockerfile.release +29 -6
  10. data/Dockerfile.staging +70 -0
  11. data/Gemfile +2 -0
  12. data/README.md +53 -15
  13. data/docker-compose.yml +54 -0
  14. data/lib/shipitron.rb +19 -2
  15. data/lib/shipitron/cli.rb +42 -42
  16. data/lib/shipitron/client.rb +9 -0
  17. data/lib/shipitron/client/bootstrap_application.rb +1 -0
  18. data/lib/shipitron/client/create_ecs_services.rb +7 -7
  19. data/lib/shipitron/client/deploy_application.rb +2 -0
  20. data/lib/shipitron/client/ensure_deploy_not_running.rb +2 -1
  21. data/lib/shipitron/client/fetch_clusters.rb +1 -0
  22. data/lib/shipitron/client/force_deploy.rb +1 -0
  23. data/lib/shipitron/client/generate_deploy.rb +41 -0
  24. data/lib/shipitron/client/load_application_config.rb +17 -0
  25. data/lib/shipitron/client/load_templates.rb +1 -0
  26. data/lib/shipitron/client/register_ecs_task_definitions.rb +5 -5
  27. data/lib/shipitron/client/run_ecs_tasks.rb +101 -72
  28. data/lib/shipitron/docker_image.rb +4 -1
  29. data/lib/shipitron/find_docker_volume_name.rb +68 -0
  30. data/lib/shipitron/git_info.rb +57 -0
  31. data/lib/shipitron/mustache_yaml_parser.rb +12 -8
  32. data/lib/shipitron/s3_copy.rb +46 -0
  33. data/lib/shipitron/server/deploy_application.rb +2 -0
  34. data/lib/shipitron/server/docker/build_image.rb +4 -1
  35. data/lib/shipitron/server/docker/configure.rb +46 -10
  36. data/lib/shipitron/server/docker/push_image.rb +3 -0
  37. data/lib/shipitron/server/docker/run_build_script.rb +17 -10
  38. data/lib/shipitron/server/download_build_cache.rb +11 -3
  39. data/lib/shipitron/server/fetch_deploy.rb +50 -0
  40. data/lib/shipitron/server/git/clone_local_copy.rb +4 -5
  41. data/lib/shipitron/server/git/update_cache.rb +2 -1
  42. data/lib/shipitron/server/run_post_build.rb +40 -1
  43. data/lib/shipitron/server/transform_cli_args.rb +4 -0
  44. data/lib/shipitron/server/update_ecs_task_definitions.rb +2 -1
  45. data/lib/shipitron/server/upload_build_cache.rb +10 -9
  46. data/lib/shipitron/version.rb +1 -1
  47. data/scripts/docker-entrypoint.sh +37 -3
  48. data/scripts/release-entrypoint.sh +20 -0
  49. data/shipitron.gemspec +11 -8
  50. data/test.yml +5 -0
  51. metadata +78 -25
  52. data/build_dev.sh +0 -27
@@ -31,6 +31,8 @@ module Shipitron
31
31
  optional :build_script
32
32
  optional :post_builds
33
33
  optional :repository_branch
34
+ optional :skip_push, default: false
35
+ optional :registry
34
36
 
35
37
  around do |interactor|
36
38
  if ENV['CONSUL_HOST'].nil?
@@ -12,7 +12,10 @@ module Shipitron
12
12
 
13
13
  required :application
14
14
  required :docker_image
15
- required :git_sha
15
+ required :git_info
16
+ required :named_tag
17
+ required :region
18
+ optional :registry
16
19
 
17
20
  organize [
18
21
  DownloadBuildCache,
@@ -1,5 +1,6 @@
1
1
  require 'shipitron'
2
2
  require 'shipitron/consul_keys'
3
+ require 'json'
3
4
 
4
5
  module Shipitron
5
6
  module Server
@@ -9,22 +10,48 @@ module Shipitron
9
10
  include ConsulKeys
10
11
 
11
12
  required :application
13
+ optional :registry
12
14
 
13
15
  before do
14
16
  configure_consul_client!
15
17
  end
16
18
 
17
19
  def call
18
- docker_auth = begin
19
- key = fetch_key(key: "shipitron/#{application}/docker_auth")
20
- key = fetch_key!(key: 'shipitron/docker_auth') if key.nil?
21
- key
22
- end
23
- auth_file = Pathname.new('/home/shipitron/.docker/config.json')
24
- auth_file.parent.mkpath
25
- auth_file.open('wb') do |file|
26
- file.puts(docker_auth.to_s)
27
- file.chmod(0600)
20
+ username = fetch_scoped_key('docker_user')
21
+ password = fetch_scoped_key('docker_password')
22
+
23
+ if username && password
24
+ Logger.info `docker login --username #{username} --password #{password}`
25
+ if $? != 0
26
+ fail_with_error!(message: 'Docker login failed.')
27
+ end
28
+ end
29
+
30
+ if registry
31
+ case registry
32
+ when /docker\.io/
33
+ # do nothing
34
+ when /\d+\.dkr\.ecr\.us-east-1\.amazonaws\.com/
35
+ # ECR
36
+ config_file = Pathname.new('/home/shipitron/.docker/config.json')
37
+ config_file.parent.mkpath
38
+
39
+ config_hash = {}
40
+ if config_file.file?
41
+ config_file.open('rb') do |file|
42
+ json = file.read
43
+ config_hash = JSON.parse(json) rescue {}
44
+ end
45
+ end
46
+
47
+ config_hash['credHelpers'] ||= {}
48
+ config_hash['credHelpers'][registry] = 'ecr-login'
49
+
50
+ config_file.open('wb') do |file|
51
+ file.puts(JSON.generate(config_hash))
52
+ file.chmod(0600)
53
+ end
54
+ end
28
55
  end
29
56
  end
30
57
 
@@ -33,6 +60,15 @@ module Shipitron
33
60
  context.application
34
61
  end
35
62
 
63
+ def registry
64
+ context.registry
65
+ end
66
+
67
+ def fetch_scoped_key(key)
68
+ value = fetch_key(key: "shipitron/#{application}/#{key}")
69
+ value = fetch_key(key: "shipitron/#{key}") if value.nil?
70
+ value
71
+ end
36
72
  end
37
73
  end
38
74
  end
@@ -8,8 +8,11 @@ module Shipitron
8
8
 
9
9
  required :docker_image
10
10
  required :named_tag
11
+ optional :skip_push, default: false
11
12
 
12
13
  def call
14
+ return if context.skip_push
15
+
13
16
  Logger.info "Pushing docker image #{docker_image} and #{docker_image.name_with_tag(named_tag)}"
14
17
 
15
18
  Logger.info `docker tag #{docker_image} #{docker_image.name_with_tag(named_tag)}`
@@ -9,17 +9,16 @@ module Shipitron
9
9
 
10
10
  required :application
11
11
  required :docker_image
12
- required :git_sha
13
- optional :build_script
14
-
15
- before do
16
- context.build_script ||= 'shipitron/build.sh'
17
- end
12
+ required :git_info
13
+ required :named_tag
14
+ optional :build_script, default: 'shipitron/build.sh'
15
+ optional :registry
18
16
 
19
17
  def call
20
18
  Logger.info 'Building docker image'
21
19
 
22
- docker_image.tag = git_sha
20
+ docker_image.registry = registry if registry != nil
21
+ docker_image.tag = git_info.short_sha
23
22
 
24
23
  FileUtils.cd("/home/shipitron/#{application}") do
25
24
  unless Pathname.new(build_script).exist?
@@ -27,7 +26,7 @@ module Shipitron
27
26
  end
28
27
 
29
28
  cmd = TTY::Command.new
30
- result = cmd.run!("#{build_script} #{docker_image}")
29
+ result = cmd.run!("#{build_script} #{docker_image} #{named_tag}")
31
30
 
32
31
  if result.failure?
33
32
  fail_with_error!(message: "build script exited with non-zero code: #{result.exit_status}")
@@ -44,13 +43,21 @@ module Shipitron
44
43
  context.docker_image
45
44
  end
46
45
 
47
- def git_sha
48
- context.git_sha
46
+ def git_info
47
+ context.git_info
48
+ end
49
+
50
+ def named_tag
51
+ context.named_tag
49
52
  end
50
53
 
51
54
  def build_script
52
55
  context.build_script
53
56
  end
57
+
58
+ def registry
59
+ context.registry
60
+ end
54
61
  end
55
62
  end
56
63
  end
@@ -1,5 +1,6 @@
1
1
  require 'shipitron'
2
2
  require 'shipitron/fetch_bucket'
3
+ require 'shipitron/s3_copy'
3
4
 
4
5
  module Shipitron
5
6
  module Server
@@ -9,11 +10,12 @@ module Shipitron
9
10
  required :application
10
11
  required :s3_cache_bucket
11
12
  required :build_cache_location
13
+ required :region
12
14
 
13
15
  def call
14
16
  Logger.info "Downloading build cache from bucket #{s3_cache_bucket}"
15
17
 
16
- s3_file = bucket.files.get("#{application}.build-cache.archive")
18
+ s3_file = bucket.files.head("#{application}.build-cache.archive")
17
19
  if s3_file.nil?
18
20
  Logger.warn 'Build cache not found.'
19
21
  return
@@ -21,8 +23,14 @@ module Shipitron
21
23
 
22
24
  build_cache = Pathname.new("/home/shipitron/#{application}/#{build_cache_location}")
23
25
  build_cache.parent.mkpath
24
- build_cache.open('wb') do |local_file|
25
- local_file.write(s3_file.body)
26
+
27
+ result = S3Copy.call(
28
+ source: "s3://#{s3_cache_bucket}/#{application}.build-cache.archive",
29
+ destination: build_cache.to_s,
30
+ region: context.region
31
+ )
32
+ if result.failure?
33
+ fail_with_error!(message: 'Failed to download build cache!')
26
34
  end
27
35
 
28
36
  Logger.info 'Download complete.'
@@ -0,0 +1,50 @@
1
+ require 'shipitron'
2
+ require 'aws-sdk-s3'
3
+ require 'json'
4
+
5
+ module Shipitron
6
+ module Server
7
+ class FetchDeploy
8
+ include Metaractor
9
+
10
+ required :deploy_bucket
11
+ required :deploy_bucket_region
12
+ required :deploy_id
13
+
14
+ def call
15
+ s3_key = "#{Shipitron::DEPLOY_BUCKET_PREFIX}#{context.deploy_id}"
16
+ Logger.info "Fetching deploy config from s3://#{deploy_bucket}/#{s3_key}"
17
+
18
+ response = client.get_object(
19
+ bucket: deploy_bucket,
20
+ key: s3_key
21
+ )
22
+
23
+ context.deploy_options =
24
+ JSON.parse(response.body.read)
25
+ .transform_keys {|k| k.to_sym }
26
+ end
27
+
28
+ private
29
+
30
+ def client
31
+ Aws::S3::Client.new(
32
+ region: deploy_bucket_region,
33
+ **client_opts
34
+ )
35
+ end
36
+
37
+ def client_opts
38
+ {}
39
+ end
40
+
41
+ def deploy_bucket
42
+ context.deploy_bucket
43
+ end
44
+
45
+ def deploy_bucket_region
46
+ context.deploy_bucket_region
47
+ end
48
+ end
49
+ end
50
+ end
@@ -1,5 +1,6 @@
1
1
  require 'shipitron'
2
2
  require 'shellwords'
3
+ require 'shipitron/git_info'
3
4
 
4
5
  module Shipitron
5
6
  module Server
@@ -12,7 +13,7 @@ module Shipitron
12
13
  optional :repository_branch
13
14
 
14
15
  before do
15
- context.repository_branch ||= 'master'
16
+ context.repository_branch ||= 'main'
16
17
  end
17
18
 
18
19
  def call
@@ -22,10 +23,8 @@ module Shipitron
22
23
  end
23
24
 
24
25
  Logger.info 'Using this git commit:'
25
- FileUtils.cd("/home/shipitron/#{application}") do
26
- context.git_sha = `git rev-parse --short=12 HEAD`.chomp
27
- Logger.info `git --no-pager log --format='%aN (%h): %s' -n 1`.chomp
28
- end
26
+ context.git_info = GitInfo.from_path(path: "/home/shipitron/#{application}")
27
+ Logger.info context.git_info.one_liner
29
28
  end
30
29
 
31
30
  private
@@ -13,7 +13,7 @@ module Shipitron
13
13
  optional :repository_branch
14
14
 
15
15
  before do
16
- context.repository_branch ||= 'master'
16
+ context.repository_branch ||= 'main'
17
17
  end
18
18
 
19
19
  def call
@@ -25,6 +25,7 @@ module Shipitron
25
25
  else
26
26
  Logger.info 'Fetching new git commits'
27
27
  FileUtils.cd('/home/shipitron/git-cache') do
28
+ `git gc --auto`
28
29
  `git fetch -f #{Shellwords.escape repository_url} #{Shellwords.escape repository_branch}:#{Shellwords.escape repository_branch}`
29
30
  end
30
31
  end
@@ -9,6 +9,7 @@ module Shipitron
9
9
 
10
10
  required :region
11
11
  required :clusters
12
+ required :git_info
12
13
  optional :post_builds
13
14
 
14
15
  def call
@@ -26,7 +27,41 @@ module Shipitron
26
27
  container_overrides: [
27
28
  {
28
29
  name: post_build.container_name,
29
- command: post_build.command_ary
30
+ command: post_build.command_ary,
31
+ environment: [
32
+ {
33
+ name: "GIT_SHA",
34
+ value: git_info.sha
35
+ },
36
+ {
37
+ name: "GIT_SHORT_SHA",
38
+ value: git_info.short_sha
39
+ },
40
+ {
41
+ name: "GIT_EMAIL",
42
+ value: git_info.email
43
+ },
44
+ {
45
+ name: "GIT_NAME",
46
+ value: git_info.name
47
+ },
48
+ {
49
+ name: "GIT_MESSAGE",
50
+ value: git_info.summary
51
+ },
52
+ {
53
+ name: "GIT_TIMESTAMP",
54
+ value: git_info.timestamp
55
+ },
56
+ {
57
+ name: "GIT_BRANCH",
58
+ value: git_info.branch
59
+ },
60
+ {
61
+ name: "GIT_TAG",
62
+ value: git_info.tag
63
+ }
64
+ ]
30
65
  }
31
66
  ]
32
67
  },
@@ -75,6 +110,10 @@ module Shipitron
75
110
  def clusters
76
111
  context.clusters
77
112
  end
113
+
114
+ def git_info
115
+ context.git_info
116
+ end
78
117
  end
79
118
  end
80
119
  end
@@ -12,6 +12,7 @@ module Shipitron
12
12
  required :application
13
13
  required :repository_url
14
14
  optional :repository_branch
15
+ optional :registry
15
16
  required :s3_cache_bucket
16
17
  required :build_cache_location
17
18
  required :image_name
@@ -23,6 +24,7 @@ module Shipitron
23
24
  optional :ecs_services
24
25
  optional :ecs_service_templates
25
26
  optional :build_script
27
+ optional :skip_push, default: false
26
28
  optional :post_builds
27
29
 
28
30
  before do
@@ -37,6 +39,7 @@ module Shipitron
37
39
  application
38
40
  repository_url
39
41
  repository_branch
42
+ registry
40
43
  s3_cache_bucket
41
44
  build_cache_location
42
45
  named_tag
@@ -44,6 +47,7 @@ module Shipitron
44
47
  clusters
45
48
  ecs_services
46
49
  build_script
50
+ skip_push
47
51
  ].each_with_object(cli_args) { |k, args| args[k] = context[k] }
48
52
 
49
53
  cli_args.docker_image = DockerImage.new(name: context.image_name)
@@ -14,11 +14,12 @@ module Shipitron
14
14
  required :docker_image
15
15
  required :ecs_task_defs
16
16
  optional :ecs_task_def_templates
17
+ optional :registry
17
18
 
18
19
  before do
19
20
  context.ecs_task_def_templates ||= []
20
21
  context.templates = context.ecs_task_def_templates
21
- context.template_context = { tag: docker_image.tag }
22
+ context.template_context = { tag: docker_image.tag, registry: context.registry }
22
23
  end
23
24
 
24
25
  organize [
@@ -9,6 +9,7 @@ module Shipitron
9
9
  required :application
10
10
  required :s3_cache_bucket
11
11
  required :build_cache_location
12
+ required :region
12
13
 
13
14
  def call
14
15
  Logger.info "Uploading build cache to bucket #{s3_cache_bucket}"
@@ -19,11 +20,15 @@ module Shipitron
19
20
  return
20
21
  end
21
22
 
22
- build_cache.open('rb') do |local_file|
23
- bucket.files.create(
24
- key: "#{application}.build-cache.archive",
25
- body: local_file.read
26
- )
23
+ result = S3Copy.call(
24
+ source: build_cache.to_s,
25
+ destination: "s3://#{s3_cache_bucket}/#{application}.build-cache.archive",
26
+ region: context.region
27
+ )
28
+ if result.failure?
29
+ Logger.warn 'Failed to upload build cache!'
30
+ else
31
+ Logger.info 'Upload complete.'
27
32
  end
28
33
  end
29
34
 
@@ -39,10 +44,6 @@ module Shipitron
39
44
  def build_cache_location
40
45
  context.build_cache_location
41
46
  end
42
-
43
- def bucket
44
- @bucket ||= FetchBucket.call!(name: s3_cache_bucket).bucket
45
- end
46
47
  end
47
48
  end
48
49
  end