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
@@ -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