shipitron 1.0.1 → 1.3.1
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.
- checksums.yaml +4 -4
- data/.dockerignore +1 -0
- data/.gitattributes +1 -0
- data/.gitignore +1 -0
- data/Dockerfile +28 -8
- data/Dockerfile.release +25 -3
- data/Gemfile +1 -0
- data/README.md +48 -9
- data/build_dev.sh +1 -1
- data/docker-compose.yml +24 -0
- data/lib/shipitron/cli.rb +33 -3
- data/lib/shipitron/client.rb +9 -0
- data/lib/shipitron/client/bootstrap_application.rb +1 -0
- data/lib/shipitron/client/create_ecs_services.rb +1 -0
- data/lib/shipitron/client/deploy_application.rb +1 -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 +58 -0
- data/lib/shipitron/client/load_application_config.rb +4 -0
- data/lib/shipitron/client/load_templates.rb +1 -0
- data/lib/shipitron/client/register_ecs_task_definitions.rb +1 -0
- data/lib/shipitron/client/run_ecs_tasks.rb +14 -1
- 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/s3_copy.rb +46 -0
- data/lib/shipitron/server/deploy_application.rb +3 -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 +17 -4
- data/lib/shipitron/server/git/clone_local_copy.rb +3 -4
- data/lib/shipitron/server/git/update_cache.rb +1 -0
- data/lib/shipitron/server/run_post_build.rb +40 -1
- data/lib/shipitron/server/transform_cli_args.rb +6 -0
- data/lib/shipitron/server/update_ecs_task_definitions.rb +2 -1
- data/lib/shipitron/server/upload_build_cache.rb +14 -8
- data/lib/shipitron/version.rb +1 -1
- data/scripts/docker-entrypoint.sh +9 -0
- data/shipitron.gemspec +8 -6
- metadata +50 -16
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'shipitron'
|
2
|
+
require 'shipitron/client'
|
2
3
|
require 'shipitron/ecs_client'
|
3
4
|
require 'shellwords'
|
4
5
|
require 'base64'
|
@@ -16,6 +17,7 @@ module Shipitron
|
|
16
17
|
required :shipitron_task
|
17
18
|
required :repository_url
|
18
19
|
required :s3_cache_bucket
|
20
|
+
required :build_cache_location
|
19
21
|
required :image_name
|
20
22
|
required :named_tag
|
21
23
|
required :ecs_task_defs
|
@@ -23,9 +25,11 @@ module Shipitron
|
|
23
25
|
optional :ecs_services
|
24
26
|
optional :ecs_service_templates
|
25
27
|
optional :build_script
|
28
|
+
optional :skip_push
|
26
29
|
optional :post_builds
|
27
30
|
optional :simulate
|
28
31
|
optional :repository_branch
|
32
|
+
optional :registry
|
29
33
|
|
30
34
|
before do
|
31
35
|
context.post_builds ||= []
|
@@ -72,7 +76,7 @@ module Shipitron
|
|
72
76
|
]
|
73
77
|
},
|
74
78
|
count: 1,
|
75
|
-
started_by:
|
79
|
+
started_by: Shipitron::Client::STARTED_BY
|
76
80
|
)
|
77
81
|
|
78
82
|
if !response.failures.empty?
|
@@ -108,6 +112,7 @@ module Shipitron
|
|
108
112
|
'--name', context.application,
|
109
113
|
'--repository', context.repository_url,
|
110
114
|
'--bucket', context.s3_cache_bucket,
|
115
|
+
'--build-cache-location', context.build_cache_location,
|
111
116
|
'--image-name', context.image_name,
|
112
117
|
'--named-tag', context.named_tag,
|
113
118
|
'--region', cluster.region,
|
@@ -123,10 +128,18 @@ module Shipitron
|
|
123
128
|
ary.concat(context.ecs_services)
|
124
129
|
end
|
125
130
|
|
131
|
+
if context.registry != nil
|
132
|
+
ary.concat ['--registry', context.registry]
|
133
|
+
end
|
134
|
+
|
126
135
|
if context.build_script != nil
|
127
136
|
ary.concat ['--build-script', context.build_script]
|
128
137
|
end
|
129
138
|
|
139
|
+
if context.skip_push != nil
|
140
|
+
ary.concat ['--skip-push', context.skip_push.to_s]
|
141
|
+
end
|
142
|
+
|
130
143
|
if !context.post_builds.empty?
|
131
144
|
ary << '--post-builds'
|
132
145
|
ary.concat(context.post_builds.map(&:to_s))
|
@@ -2,6 +2,7 @@ require 'shipitron'
|
|
2
2
|
|
3
3
|
module Shipitron
|
4
4
|
class DockerImage < Hashie::Dash
|
5
|
+
property :registry
|
5
6
|
property :name
|
6
7
|
property :tag
|
7
8
|
|
@@ -13,7 +14,9 @@ module Shipitron
|
|
13
14
|
tag_str = tag_str.dup.prepend(':')
|
14
15
|
end
|
15
16
|
|
16
|
-
|
17
|
+
name_with_registry = [registry, name].compact.join('/')
|
18
|
+
|
19
|
+
"#{name_with_registry}#{tag_str}"
|
17
20
|
end
|
18
21
|
|
19
22
|
def to_s
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'excon'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Shipitron
|
5
|
+
class FindDockerVolumeName
|
6
|
+
include Metaractor
|
7
|
+
|
8
|
+
required :container_name
|
9
|
+
required :volume_search
|
10
|
+
|
11
|
+
def call
|
12
|
+
volumes = container_volumes(container_name: container_name)
|
13
|
+
|
14
|
+
volume_metadata = volumes.find do |volume|
|
15
|
+
volume['DockerName'] =~ volume_search
|
16
|
+
end
|
17
|
+
|
18
|
+
if volume_metadata.nil?
|
19
|
+
raise 'Unable to find shipitron-home volume!'
|
20
|
+
end
|
21
|
+
|
22
|
+
context.volume_name = volume_metadata['DockerName']
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def container_name
|
27
|
+
context.container_name
|
28
|
+
end
|
29
|
+
|
30
|
+
def volume_search
|
31
|
+
context.volume_search
|
32
|
+
end
|
33
|
+
|
34
|
+
def container_volumes(container_name:)
|
35
|
+
container_metadata = self.task_metadata['Containers'].find do |container|
|
36
|
+
container['Name'] == container_name
|
37
|
+
end
|
38
|
+
|
39
|
+
return {} if container_metadata.nil?
|
40
|
+
|
41
|
+
container_metadata['Volumes']
|
42
|
+
end
|
43
|
+
|
44
|
+
def task_metadata
|
45
|
+
return @task_metadata if defined?(@task_metadata)
|
46
|
+
|
47
|
+
begin
|
48
|
+
response = Excon.get(
|
49
|
+
"#{ENV['ECS_CONTAINER_METADATA_URI_V4']}/task",
|
50
|
+
expects: [200],
|
51
|
+
connect_timeout: 5,
|
52
|
+
read_timeout: 5,
|
53
|
+
write_timeout: 5,
|
54
|
+
tcp_nodelay: true
|
55
|
+
)
|
56
|
+
|
57
|
+
Logger.debug "Metadata result:"
|
58
|
+
Logger.debug(response.body)
|
59
|
+
Logger.debug "\n"
|
60
|
+
|
61
|
+
@task_metadata = JSON.parse(response.body)
|
62
|
+
rescue
|
63
|
+
Logger.info "Metadata uri failed"
|
64
|
+
{}
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'shipitron'
|
2
|
+
require 'rugged'
|
3
|
+
|
4
|
+
module Shipitron
|
5
|
+
class GitInfo < Hashie::Dash
|
6
|
+
property :sha
|
7
|
+
property :short_sha
|
8
|
+
property :email
|
9
|
+
property :name
|
10
|
+
property :summary
|
11
|
+
property :timestamp
|
12
|
+
property :branch
|
13
|
+
property :tag
|
14
|
+
|
15
|
+
def one_liner
|
16
|
+
"#{name} (#{short_sha}): #{summary}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.from_path(path:)
|
20
|
+
repo = Rugged::Repository.new(path)
|
21
|
+
commit = repo.last_commit
|
22
|
+
self.new(
|
23
|
+
sha: commit.oid,
|
24
|
+
short_sha: commit.oid[0, 12],
|
25
|
+
email: commit.author.dig(:email),
|
26
|
+
name: commit.author.dig(:name),
|
27
|
+
summary: commit.summary,
|
28
|
+
timestamp: commit.epoch_time.to_s,
|
29
|
+
branch: branch_name(repo: repo),
|
30
|
+
tag: tag_name(repo: repo)
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.branch_name(repo:)
|
35
|
+
ref = repo.head
|
36
|
+
ref.branch? ? ref.name.sub('refs/heads/', '') : nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.tag_name(repo:)
|
40
|
+
ref = repo.head
|
41
|
+
tags = repo.tags
|
42
|
+
|
43
|
+
tags.each do |tag|
|
44
|
+
target_id =
|
45
|
+
if tag.annotated?
|
46
|
+
tag.annotation.target_id
|
47
|
+
else
|
48
|
+
tag.target.oid
|
49
|
+
end
|
50
|
+
|
51
|
+
return tag.name if ref.target_id == target_id
|
52
|
+
end
|
53
|
+
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'shipitron'
|
2
|
+
require 'shipitron/find_docker_volume_name'
|
3
|
+
|
4
|
+
module Shipitron
|
5
|
+
class S3Copy
|
6
|
+
include Metaractor
|
7
|
+
|
8
|
+
required :source
|
9
|
+
required :destination
|
10
|
+
required :region
|
11
|
+
|
12
|
+
def call
|
13
|
+
if ENV['FOG_LOCAL']
|
14
|
+
Logger.info `cp #{source.gsub('s3://', '/fog/')} #{destination.gsub('s3://', '/fog/')}`
|
15
|
+
if $? != 0
|
16
|
+
fail_with_error!(message: 'Failed to transfer to/from s3 (mocked).')
|
17
|
+
end
|
18
|
+
else
|
19
|
+
Logger.info "S3 Copy from #{source} to #{destination}"
|
20
|
+
|
21
|
+
shipitron_home_volume = FindDockerVolumeName.call!(
|
22
|
+
container_name: 'shipitron',
|
23
|
+
volume_search: /shipitron-home/
|
24
|
+
).volume_name
|
25
|
+
|
26
|
+
Logger.info `docker run --rm -t -v #{shipitron_home_volume}:/home/shipitron -e AWS_CONTAINER_CREDENTIALS_RELATIVE_URI amazon/aws-cli:latest --region #{region} s3 cp #{source} #{destination} --quiet --only-show-errors`
|
27
|
+
if $? != 0
|
28
|
+
fail_with_error!(message: 'Failed to transfer to/from s3.')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def source
|
35
|
+
context.source
|
36
|
+
end
|
37
|
+
|
38
|
+
def destination
|
39
|
+
context.destination
|
40
|
+
end
|
41
|
+
|
42
|
+
def region
|
43
|
+
context.region
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -19,6 +19,7 @@ module Shipitron
|
|
19
19
|
required :application
|
20
20
|
required :repository_url
|
21
21
|
required :s3_cache_bucket
|
22
|
+
required :build_cache_location
|
22
23
|
required :docker_image
|
23
24
|
required :named_tag
|
24
25
|
required :region
|
@@ -30,6 +31,8 @@ module Shipitron
|
|
30
31
|
optional :build_script
|
31
32
|
optional :post_builds
|
32
33
|
optional :repository_branch
|
34
|
+
optional :skip_push, default: false
|
35
|
+
optional :registry
|
33
36
|
|
34
37
|
around do |interactor|
|
35
38
|
if ENV['CONSUL_HOST'].nil?
|
@@ -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
|