shipitron 1.2.0 → 1.4.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 (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
@@ -0,0 +1,54 @@
1
+ version: '3.8'
2
+ services:
3
+ shipitron:
4
+ build: .
5
+ image: outstand/shipitron:dev
6
+ environment:
7
+ FIXUID:
8
+ FIXGID:
9
+ volumes:
10
+ - bundler-data:/usr/local/bundle
11
+ - ~/dev/app:/app # Set this to the application to be shipitron'd
12
+ - shipitron-home:/home/shipitron
13
+ - ~/.config/shipitron:/home/shipitron/.config/shipitron
14
+ - .:/shipitron
15
+
16
+ specs:
17
+ build: .
18
+ image: outstand/shipitron:dev
19
+ command: rspec
20
+ environment:
21
+ FOG_LOCAL: 'true'
22
+ FIXUID:
23
+ FIXGID:
24
+ BUILDKITE:
25
+ BUILDKITE_BUILD_URL:
26
+ BUILDKITE_JOB_ID:
27
+ BUILDKITE_AGENT_ACCESS_TOKEN:
28
+ working_dir: /shipitron
29
+ volumes:
30
+ - bundler-data:/usr/local/bundle
31
+ - fog:/fog
32
+ - shipitron-home:/home/shipitron
33
+ - .:/shipitron
34
+
35
+ release_gem:
36
+ image: outstand/shipitron:dev
37
+ command: rake release
38
+ working_dir: /shipitron
39
+ environment:
40
+ FIXUID:
41
+ FIXGID:
42
+ volumes:
43
+ - bundler-data:/usr/local/bundle
44
+ - shipitron-home:/home/shipitron
45
+ - .:/shipitron
46
+ - ~/.dotfiles/gitconfig:/root/.gitconfig
47
+ - ~/.dotfiles/gitconfig.user:/root/.gitconfig.user
48
+ - ~/.ssh/id_rsa:/root/.ssh/id_rsa
49
+ - ~/.gem:/root/.gem
50
+
51
+ volumes:
52
+ fog:
53
+ shipitron-home:
54
+ bundler-data:
data/lib/shipitron.rb CHANGED
@@ -7,6 +7,8 @@ require 'shipitron/smash'
7
7
  module Shipitron
8
8
  CONFIG_FILE = 'shipitron/config.yml'.freeze
9
9
  SECRETS_FILE = '~/.config/shipitron/secrets.yml'.freeze
10
+ GLOBAL_CONFIG_FILE = '~/.config/shipitron/config.yml'.freeze
11
+ DEPLOY_BUCKET_PREFIX = "deploys/"
10
12
 
11
13
  class << self
12
14
  def config_file
@@ -18,10 +20,10 @@ module Shipitron
18
20
  end
19
21
 
20
22
  def config
21
- @config ||= Smash.load(Pathname.new(config_file).expand_path.to_s).merge(secrets)
23
+ @config ||= Smash.load(Pathname.new(config_file).expand_path.to_s).merge(secrets).merge(global_config)
22
24
  rescue ArgumentError
23
25
  Logger.warn "Config file '#{config_file}' does not exist"
24
- @config = secrets
26
+ @config = secrets.merge(global_config)
25
27
  end
26
28
 
27
29
  def secrets_file
@@ -38,5 +40,20 @@ module Shipitron
38
40
  Logger.warn "Secrets file '#{secrets_file}' does not exist"
39
41
  @secrets = Smash.new
40
42
  end
43
+
44
+ def global_config_file
45
+ @global_config_file ||= GLOBAL_CONFIG_FILE
46
+ end
47
+
48
+ def global_config_file=(file)
49
+ @global_config_file = file
50
+ end
51
+
52
+ def global_config
53
+ @global_config ||= Smash.load(Pathname.new(global_config_file).expand_path.to_s)
54
+ rescue ArgumentError
55
+ Logger.warn "Global config file '#{global_config_file}' does not exist"
56
+ @global_config = Smash.new
57
+ end
41
58
  end
42
59
  end
data/lib/shipitron/cli.rb CHANGED
@@ -12,22 +12,26 @@ module Shipitron
12
12
  desc 'deploy <app>', 'Deploys the app'
13
13
  option :config_file, default: 'shipitron/config.yml'
14
14
  option :secrets_file, default: '~/.config/shipitron/secrets.yml'
15
+ option :global_config_file, default: '~/.config/shipitron/config.yml'
15
16
  option :debug, type: :boolean, default: false
16
17
  option :simulate, type: :boolean, default: false
18
+ option :simulate_store_deploy, type: :boolean, default: false, desc: "Simulate and store deploy config in S3"
17
19
  def deploy(app)
18
20
  setup(
19
21
  config_file: options[:config_file],
20
- secrets_file: options[:secrets_file]
22
+ secrets_file: options[:secrets_file],
23
+ global_config_file: options[:global_config_file]
21
24
  )
22
25
 
23
26
  require 'shipitron/client/deploy_application'
24
27
  result = Client::DeployApplication.call(
25
28
  application: app,
26
- simulate: options[:simulate]
29
+ simulate: options[:simulate],
30
+ simulate_store_deploy: options[:simulate_store_deploy]
27
31
  )
28
32
 
29
33
  if result.failure?
30
- result.errors.each do |error|
34
+ result.error_messages.each do |error|
31
35
  Logger.fatal error
32
36
  end
33
37
  Logger.fatal 'Deploy failed.'
@@ -50,7 +54,7 @@ module Shipitron
50
54
  )
51
55
 
52
56
  if result.failure?
53
- result.errors.each do |error|
57
+ result.error_messages.each do |error|
54
58
  Logger.fatal error
55
59
  end
56
60
  Logger.fatal 'Deploy failed.'
@@ -59,45 +63,40 @@ module Shipitron
59
63
 
60
64
 
61
65
  desc 'server_deploy', 'Server-side component of deploy'
62
- option :name, required: true
63
- option :repository, required: true
64
- option :repository_branch, default: 'master'
65
- option :bucket, required: true
66
- option :build_cache_location, default: 'tmp/build-cache.tar.gz'
67
- option :image_name, required: true
68
- option :named_tag, default: 'latest'
69
- option :region, required: true
70
- option :clusters, type: :array, required: true
71
- option :ecs_task_defs, type: :array, required: true
72
- option :ecs_task_def_templates, type: :array, default: []
73
- option :ecs_services, type: :array, default: []
74
- option :ecs_service_templates, type: :array, default: []
75
- option :build_script, default: nil
76
- option :post_builds, type: :array
77
- option :secrets_file, default: '~/.config/shipitron/secrets.yml'
78
- option :debug, type: :boolean, default: false
66
+ option :deploy_id, required: true
79
67
  def server_deploy
80
- setup(
81
- secrets_file: options[:secrets_file]
82
- )
68
+ setup
69
+
70
+ if !ENV.key?("SHIPITRON_DEPLOY_BUCKET") || !ENV.key?("SHIPITRON_DEPLOY_BUCKET_REGION")
71
+ raise "Missing shipitron deploy bucket env vars!"
72
+ end
73
+
74
+ require 'shipitron/server/fetch_deploy'
75
+ deploy_options = Server::FetchDeploy.call!(
76
+ deploy_bucket: ENV["SHIPITRON_DEPLOY_BUCKET"],
77
+ deploy_bucket_region: ENV["SHIPITRON_DEPLOY_BUCKET_REGION"],
78
+ deploy_id: options[:deploy_id]
79
+ ).deploy_options
83
80
 
84
81
  require 'shipitron/server/transform_cli_args'
85
82
  cli_args = Server::TransformCliArgs.call!(
86
- application: options[:name],
87
- repository_url: options[:repository],
88
- repository_branch: options[:repository_branch],
89
- s3_cache_bucket: options[:bucket],
90
- build_cache_location: options[:build_cache_location],
91
- image_name: options[:image_name],
92
- named_tag: options[:named_tag],
93
- region: options[:region],
94
- clusters: options[:clusters],
95
- ecs_task_defs: options[:ecs_task_defs],
96
- ecs_task_def_templates: options[:ecs_task_def_templates],
97
- ecs_services: options[:ecs_services],
98
- ecs_service_templates: options[:ecs_service_templates],
99
- build_script: options[:build_script],
100
- post_builds: options[:post_builds]
83
+ application: deploy_options[:name],
84
+ repository_url: deploy_options[:repository],
85
+ repository_branch: deploy_options[:repository_branch],
86
+ registry: deploy_options[:registry],
87
+ s3_cache_bucket: deploy_options[:bucket],
88
+ build_cache_location: deploy_options[:build_cache_location],
89
+ image_name: deploy_options[:image_name],
90
+ named_tag: deploy_options[:named_tag],
91
+ skip_push: deploy_options[:skip_push],
92
+ region: deploy_options[:region],
93
+ clusters: deploy_options[:clusters],
94
+ ecs_task_defs: deploy_options[:ecs_task_defs],
95
+ ecs_task_def_templates: deploy_options[:ecs_task_def_templates],
96
+ ecs_services: deploy_options[:ecs_services],
97
+ ecs_service_templates: deploy_options[:ecs_service_templates],
98
+ build_script: deploy_options[:build_script],
99
+ post_builds: deploy_options[:post_builds]
101
100
  ).cli_args
102
101
 
103
102
  require 'shipitron/server/deploy_application'
@@ -106,7 +105,7 @@ module Shipitron
106
105
  )
107
106
 
108
107
  if result.failure?
109
- result.errors.each do |error|
108
+ result.error_messages.each do |error|
110
109
  Logger.fatal error
111
110
  end
112
111
  Logger.fatal 'Deploy failed.'
@@ -137,7 +136,7 @@ module Shipitron
137
136
  )
138
137
 
139
138
  if result.failure?
140
- result.errors.each do |error|
139
+ result.error_messages.each do |error|
141
140
  Logger.fatal error
142
141
  end
143
142
  Logger.fatal 'Bootstrap failed.'
@@ -145,7 +144,7 @@ module Shipitron
145
144
  end
146
145
 
147
146
  private
148
- def setup(config_file:nil, secrets_file:nil)
147
+ def setup(config_file:nil, secrets_file:nil, global_config_file:nil)
149
148
  $stdout.sync = true
150
149
  if options[:debug] == false
151
150
  Logger.level = :info
@@ -153,6 +152,7 @@ module Shipitron
153
152
 
154
153
  Shipitron.config_file = config_file unless config_file.nil?
155
154
  Shipitron.secrets_file = secrets_file unless secrets_file.nil?
155
+ Shipitron.global_config_file = global_config_file unless global_config_file.nil?
156
156
  end
157
157
  end
158
158
  end
@@ -0,0 +1,9 @@
1
+ require 'shipitron'
2
+
3
+ module Shipitron
4
+ module Client
5
+ def self.started_by
6
+ ENV.fetch("SHIPITRON_STARTED_BY", "shipitron")
7
+ end
8
+ end
9
+ end
@@ -1,4 +1,5 @@
1
1
  require 'shipitron'
2
+ require 'shipitron/client'
2
3
  require 'shipitron/client/register_ecs_task_definitions'
3
4
  require 'shipitron/client/create_ecs_services'
4
5
 
@@ -1,4 +1,5 @@
1
1
  require 'shipitron'
2
+ require 'shipitron/client'
2
3
  require 'shipitron/ecs_client'
3
4
  require 'shipitron/mustache_yaml_parser'
4
5
  require 'securerandom'
@@ -29,13 +30,12 @@ module Shipitron
29
30
 
30
31
  service_def = Smash.load(
31
32
  path.to_s,
32
- parser: MustacheYamlParser.new(
33
- context: {
34
- cluster: cluster_name,
35
- revision: nil, # ECS will default to latest ACTIVE
36
- count: service_count
37
- }
38
- )
33
+ parser: MustacheYamlParser,
34
+ context: {
35
+ cluster: cluster_name,
36
+ revision: nil, # ECS will default to latest ACTIVE
37
+ count: service_count
38
+ }
39
39
  ).merge(
40
40
  client_token: SecureRandom.uuid
41
41
  )
@@ -1,4 +1,5 @@
1
1
  require 'shipitron'
2
+ require 'shipitron/client'
2
3
  require 'shipitron/client/load_application_config'
3
4
  require 'shipitron/client/load_templates'
4
5
  require 'shipitron/client/fetch_clusters'
@@ -13,6 +14,7 @@ module Shipitron
13
14
 
14
15
  required :application
15
16
  optional :simulate
17
+ optional :simulate_store_deploy
16
18
 
17
19
  organize [
18
20
  LoadApplicationConfig,
@@ -1,4 +1,5 @@
1
1
  require 'shipitron'
2
+ require 'shipitron/client'
2
3
  require 'shipitron/ecs_client'
3
4
 
4
5
  # Note: This is a best effort client side check to make sure there
@@ -21,7 +22,7 @@ module Shipitron
21
22
  begin
22
23
  response = ecs_client(region: cluster.region).list_tasks(
23
24
  cluster: cluster.name,
24
- started_by: 'shipitron',
25
+ started_by: Shipitron::Client.started_by,
25
26
  max_results: 1,
26
27
  desired_status: status
27
28
  )
@@ -1,4 +1,5 @@
1
1
  require 'shipitron'
2
+ require 'shipitron/client'
2
3
  require 'resolv'
3
4
 
4
5
  module Shipitron
@@ -1,4 +1,5 @@
1
1
  require 'shipitron'
2
+ require 'shipitron/client'
2
3
  require 'shipitron/ecs_client'
3
4
  require 'shipitron/client/load_application_config'
4
5
  require 'shipitron/client/fetch_clusters'
@@ -0,0 +1,41 @@
1
+ require 'shipitron'
2
+ require 'shipitron/client'
3
+ require 'shipitron/fetch_bucket'
4
+ require 'aws-sdk-s3'
5
+ require 'pastel'
6
+
7
+ module Shipitron
8
+ module Client
9
+ class GenerateDeploy
10
+ include Metaractor
11
+
12
+ required :server_deploy_opts
13
+ required :deploy_id
14
+
15
+ def call
16
+ s3_key = "#{Shipitron::DEPLOY_BUCKET_PREFIX}#{context.deploy_id}"
17
+ pastel = Pastel.new
18
+ Logger.info "Uploading deploy config to #{pastel.blue("s3://#{deploy_bucket}/#{s3_key}")}"
19
+
20
+ client = Aws::S3::Client.new(region: deploy_bucket_region)
21
+
22
+ client.put_object(
23
+ bucket: deploy_bucket,
24
+ key: s3_key,
25
+ body: context.server_deploy_opts.to_json,
26
+ acl: "private"
27
+ )
28
+ end
29
+
30
+ private
31
+
32
+ def deploy_bucket
33
+ Shipitron.config.deploy_bucket
34
+ end
35
+
36
+ def deploy_bucket_region
37
+ Shipitron.config.deploy_bucket_region
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,5 +1,7 @@
1
1
  require 'shipitron'
2
+ require 'shipitron/client'
2
3
  require 'shipitron/post_build'
4
+ require 'aws-sdk-core'
3
5
 
4
6
  module Shipitron
5
7
  module Client
@@ -11,6 +13,7 @@ module Shipitron
11
13
  def call
12
14
  context.repository_url = config.repository
13
15
  context.repository_branch = config.repository_branch
16
+ context.registry = config.registry
14
17
  context.s3_cache_bucket = config.cache_bucket
15
18
  context.build_cache_location = config.build_cache_location
16
19
  context.image_name = config.image_name
@@ -21,6 +24,7 @@ module Shipitron
21
24
  config.named_tag
22
25
  end
23
26
  end
27
+ context.skip_push = config.skip_push
24
28
  context.build_script = config.build_script
25
29
  context.post_builds = begin
26
30
  if config.post_builds.nil?
@@ -35,6 +39,19 @@ module Shipitron
35
39
  context.ecs_services = config.ecs_services
36
40
  context.ecs_task_def_dir = config.ecs_task_def_dir
37
41
  context.ecs_service_dir = config.ecs_service_dir
42
+
43
+ if Shipitron.config.aws_access_key_id? && Shipitron.config.aws_secret_access_key?
44
+ Aws.config.update(
45
+ credentials: Aws::Credentials.new(
46
+ Shipitron.config.aws_access_key_id,
47
+ Shipitron.config.aws_secret_access_key
48
+ )
49
+ )
50
+ end
51
+
52
+ if !Shipitron.config.deploy_bucket? || !Shipitron.config.deploy_bucket_region?
53
+ raise "Missing required deploy bucket configuration!"
54
+ end
38
55
  end
39
56
 
40
57
  private
@@ -1,4 +1,5 @@
1
1
  require 'shipitron'
2
+ require 'shipitron/client'
2
3
 
3
4
  module Shipitron
4
5
  module Client
@@ -1,4 +1,5 @@
1
1
  require 'shipitron'
2
+ require 'shipitron/client'
2
3
  require 'shipitron/ecs_client'
3
4
  require 'shipitron/mustache_yaml_parser'
4
5
 
@@ -26,11 +27,10 @@ module Shipitron
26
27
 
27
28
  task_def = Smash.load(
28
29
  path.to_s,
29
- parser: MustacheYamlParser.new(
30
- context: {
31
- tag: 'latest'
32
- }
33
- )
30
+ parser: MustacheYamlParser,
31
+ context: {
32
+ tag: 'latest'
33
+ }
34
34
  )
35
35
 
36
36
  begin