shipitron 1.2.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.buildkite/pipeline.yml +94 -0
- data/.dockerignore +1 -0
- data/.gitattributes +1 -0
- data/.gitignore +1 -0
- data/.rspec +1 -0
- data/Deskfile +15 -0
- data/Dockerfile +40 -15
- data/Dockerfile.release +29 -6
- data/Dockerfile.staging +70 -0
- data/Gemfile +2 -0
- data/README.md +53 -15
- data/docker-compose.yml +54 -0
- data/lib/shipitron.rb +19 -2
- data/lib/shipitron/cli.rb +42 -42
- data/lib/shipitron/client.rb +9 -0
- data/lib/shipitron/client/bootstrap_application.rb +1 -0
- data/lib/shipitron/client/create_ecs_services.rb +7 -7
- data/lib/shipitron/client/deploy_application.rb +2 -0
- data/lib/shipitron/client/ensure_deploy_not_running.rb +2 -1
- data/lib/shipitron/client/fetch_clusters.rb +1 -0
- data/lib/shipitron/client/force_deploy.rb +1 -0
- data/lib/shipitron/client/generate_deploy.rb +41 -0
- data/lib/shipitron/client/load_application_config.rb +17 -0
- data/lib/shipitron/client/load_templates.rb +1 -0
- data/lib/shipitron/client/register_ecs_task_definitions.rb +5 -5
- data/lib/shipitron/client/run_ecs_tasks.rb +101 -72
- data/lib/shipitron/docker_image.rb +4 -1
- data/lib/shipitron/find_docker_volume_name.rb +68 -0
- data/lib/shipitron/git_info.rb +57 -0
- data/lib/shipitron/mustache_yaml_parser.rb +12 -8
- data/lib/shipitron/s3_copy.rb +46 -0
- data/lib/shipitron/server/deploy_application.rb +2 -0
- data/lib/shipitron/server/docker/build_image.rb +4 -1
- data/lib/shipitron/server/docker/configure.rb +46 -10
- data/lib/shipitron/server/docker/push_image.rb +3 -0
- data/lib/shipitron/server/docker/run_build_script.rb +17 -10
- data/lib/shipitron/server/download_build_cache.rb +11 -3
- data/lib/shipitron/server/fetch_deploy.rb +50 -0
- data/lib/shipitron/server/git/clone_local_copy.rb +4 -5
- data/lib/shipitron/server/git/update_cache.rb +2 -1
- data/lib/shipitron/server/run_post_build.rb +40 -1
- data/lib/shipitron/server/transform_cli_args.rb +4 -0
- data/lib/shipitron/server/update_ecs_task_definitions.rb +2 -1
- data/lib/shipitron/server/upload_build_cache.rb +10 -9
- data/lib/shipitron/version.rb +1 -1
- data/scripts/docker-entrypoint.sh +37 -3
- data/scripts/release-entrypoint.sh +20 -0
- data/shipitron.gemspec +11 -8
- data/test.yml +5 -0
- metadata +78 -25
- data/build_dev.sh +0 -27
@@ -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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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 :
|
13
|
-
|
14
|
-
|
15
|
-
|
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.
|
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
|
48
|
-
context.
|
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.
|
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
|
-
|
25
|
-
|
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 ||= '
|
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
|
-
|
26
|
-
|
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 ||= '
|
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
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|