shipitron 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/.dockerignore +4 -0
- data/.gitignore +4 -0
- data/.rspec +3 -0
- data/Dockerfile +60 -0
- data/Dockerfile.release +49 -0
- data/README.md +44 -10
- data/build_dev.sh +39 -0
- data/exe/shipitron +5 -0
- data/lib/shipitron/cli.rb +132 -0
- data/lib/shipitron/client/bootstrap_application.rb +35 -0
- data/lib/shipitron/client/create_ecs_services.rb +81 -0
- data/lib/shipitron/client/deploy_application.rb +34 -0
- data/lib/shipitron/client/ensure_deploy_not_running.rb +54 -0
- data/lib/shipitron/client/load_application_config.rb +41 -0
- data/lib/shipitron/client/load_templates.rb +45 -0
- data/lib/shipitron/client/register_ecs_task_definitions.rb +75 -0
- data/lib/shipitron/client/run_ecs_tasks.rb +141 -0
- data/lib/shipitron/consul_keys.rb +34 -0
- data/lib/shipitron/consul_lock.rb +28 -0
- data/lib/shipitron/docker_image.rb +23 -0
- data/lib/shipitron/ecs_client.rb +22 -0
- data/lib/shipitron/ecs_task_def.rb +17 -0
- data/lib/shipitron/fetch_bucket.rb +26 -0
- data/lib/shipitron/logger.rb +33 -0
- data/lib/shipitron/mustache_yaml_parser.rb +22 -0
- data/lib/shipitron/parse_templates.rb +32 -0
- data/lib/shipitron/post_build.rb +32 -0
- data/lib/shipitron/server/deploy_application.rb +75 -0
- data/lib/shipitron/server/docker/build_image.rb +25 -0
- data/lib/shipitron/server/docker/configure.rb +35 -0
- data/lib/shipitron/server/docker/push_image.rb +37 -0
- data/lib/shipitron/server/docker/run_build_script.rb +53 -0
- data/lib/shipitron/server/download_build_cache.rb +44 -0
- data/lib/shipitron/server/ecs_task_defs/map_parsed_templates.rb +31 -0
- data/lib/shipitron/server/ecs_task_defs/update_from_params.rb +42 -0
- data/lib/shipitron/server/ecs_task_defs/update_in_place.rb +68 -0
- data/lib/shipitron/server/git/clone_local_copy.rb +46 -0
- data/lib/shipitron/server/git/configure.rb +40 -0
- data/lib/shipitron/server/git/download_cache.rb +56 -0
- data/lib/shipitron/server/git/pull_repo.rb +30 -0
- data/lib/shipitron/server/git/update_cache.rb +52 -0
- data/lib/shipitron/server/git/upload_cache.rb +61 -0
- data/lib/shipitron/server/run_post_build.rb +79 -0
- data/lib/shipitron/server/transform_cli_args.rb +85 -0
- data/lib/shipitron/server/update_ecs_services.rb +105 -0
- data/lib/shipitron/server/update_ecs_task_definitions.rb +47 -0
- data/lib/shipitron/server/upload_build_cache.rb +43 -0
- data/lib/shipitron/smash.rb +10 -0
- data/lib/shipitron/version.rb +1 -1
- data/lib/shipitron.rb +38 -0
- data/scripts/docker-entrypoint.sh +18 -0
- data/scripts/fetch-bundler-data.sh +16 -0
- data/shipitron.gemspec +14 -0
- metadata +236 -4
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require 'shipitron'
|
|
2
|
+
|
|
3
|
+
module Shipitron
|
|
4
|
+
module Server
|
|
5
|
+
module Docker
|
|
6
|
+
class RunBuildScript
|
|
7
|
+
include Metaractor
|
|
8
|
+
|
|
9
|
+
required :application
|
|
10
|
+
required :docker_image
|
|
11
|
+
required :git_sha
|
|
12
|
+
optional :build_script
|
|
13
|
+
|
|
14
|
+
before do
|
|
15
|
+
context.build_script ||= 'shipitron/build.sh'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def call
|
|
19
|
+
Logger.info 'Building docker image'
|
|
20
|
+
|
|
21
|
+
docker_image.tag = git_sha
|
|
22
|
+
|
|
23
|
+
FileUtils.cd("/home/shipitron/#{application}") do
|
|
24
|
+
unless Pathname.new(build_script).exist?
|
|
25
|
+
fail_with_error!(message: "#{build_script} does not exist")
|
|
26
|
+
end
|
|
27
|
+
Logger.info `#{build_script} #{docker_image}`
|
|
28
|
+
if $? != 0
|
|
29
|
+
fail_with_error!(message: "build script exited with non-zero code: #{$?}")
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
def application
|
|
36
|
+
context.application
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def docker_image
|
|
40
|
+
context.docker_image
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def git_sha
|
|
44
|
+
context.git_sha
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def build_script
|
|
48
|
+
context.build_script
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require 'shipitron'
|
|
2
|
+
require 'shipitron/fetch_bucket'
|
|
3
|
+
|
|
4
|
+
module Shipitron
|
|
5
|
+
module Server
|
|
6
|
+
class DownloadBuildCache
|
|
7
|
+
include Metaractor
|
|
8
|
+
|
|
9
|
+
required :application
|
|
10
|
+
required :s3_cache_bucket
|
|
11
|
+
|
|
12
|
+
def call
|
|
13
|
+
Logger.info "Downloading build cache from bucket #{s3_cache_bucket}"
|
|
14
|
+
|
|
15
|
+
s3_file = bucket.files.get("#{application}.build-cache.tar.gz")
|
|
16
|
+
if s3_file.nil?
|
|
17
|
+
Logger.warn 'Build cache not found.'
|
|
18
|
+
return
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
build_cache = Pathname.new("/home/shipitron/#{application}/tmp/build-cache.tar.gz")
|
|
22
|
+
build_cache.parent.mkpath
|
|
23
|
+
build_cache.open('wb') do |local_file|
|
|
24
|
+
local_file.write(s3_file.body)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
Logger.info 'Download complete.'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
def application
|
|
32
|
+
context.application
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def s3_cache_bucket
|
|
36
|
+
context.s3_cache_bucket
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def bucket
|
|
40
|
+
@bucket ||= FetchBucket.call!(name: s3_cache_bucket).bucket
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require 'shipitron'
|
|
2
|
+
|
|
3
|
+
module Shipitron
|
|
4
|
+
module Server
|
|
5
|
+
module EcsTaskDefs
|
|
6
|
+
class MapParsedTemplates
|
|
7
|
+
include Metaractor
|
|
8
|
+
|
|
9
|
+
required :ecs_task_defs
|
|
10
|
+
required :parsed_templates
|
|
11
|
+
|
|
12
|
+
def call
|
|
13
|
+
parsed_templates.each do |parsed|
|
|
14
|
+
task_def = ecs_task_defs.find {|t| t.name == parsed.family }
|
|
15
|
+
next if task_def.nil?
|
|
16
|
+
task_def.params = parsed
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
def ecs_task_defs
|
|
22
|
+
context.ecs_task_defs
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def parsed_templates
|
|
26
|
+
context.parsed_templates
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
require 'shipitron'
|
|
2
|
+
require 'shipitron/ecs_client'
|
|
3
|
+
|
|
4
|
+
module Shipitron
|
|
5
|
+
module Server
|
|
6
|
+
module EcsTaskDefs
|
|
7
|
+
class UpdateFromParams
|
|
8
|
+
include Metaractor
|
|
9
|
+
include EcsClient
|
|
10
|
+
|
|
11
|
+
required :region
|
|
12
|
+
required :ecs_task_defs
|
|
13
|
+
|
|
14
|
+
def call
|
|
15
|
+
ecs_task_defs.each do |ecs_task_def|
|
|
16
|
+
next if ecs_task_def.params.nil?
|
|
17
|
+
|
|
18
|
+
ecs_task_def.revision = ecs_client(region: region).register_task_definition(
|
|
19
|
+
ecs_task_def.params.to_h
|
|
20
|
+
).task_definition.revision
|
|
21
|
+
|
|
22
|
+
Logger.info "Created task definition #{ecs_task_def}"
|
|
23
|
+
end
|
|
24
|
+
rescue Aws::ECS::Errors::ServiceError => e
|
|
25
|
+
fail_with_errors!(messages: [
|
|
26
|
+
"Error: #{e.message}",
|
|
27
|
+
e.backtrace.join("\n")
|
|
28
|
+
])
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
def region
|
|
33
|
+
context.region
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def ecs_task_defs
|
|
37
|
+
context.ecs_task_defs
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require 'shipitron'
|
|
2
|
+
require 'shipitron/ecs_client'
|
|
3
|
+
|
|
4
|
+
module Shipitron
|
|
5
|
+
module Server
|
|
6
|
+
module EcsTaskDefs
|
|
7
|
+
class UpdateInPlace
|
|
8
|
+
include Metaractor
|
|
9
|
+
include EcsClient
|
|
10
|
+
|
|
11
|
+
required :region
|
|
12
|
+
required :ecs_task_defs
|
|
13
|
+
|
|
14
|
+
def call
|
|
15
|
+
ecs_task_defs.each do |ecs_task_def|
|
|
16
|
+
next if ecs_task_def.params != nil
|
|
17
|
+
|
|
18
|
+
existing_task = ecs_client(region: region).describe_task_definition(
|
|
19
|
+
task_definition: ecs_task_def.name
|
|
20
|
+
).task_definition
|
|
21
|
+
|
|
22
|
+
updated_image = false
|
|
23
|
+
existing_task.container_definitions.each do |container_def|
|
|
24
|
+
container_def.image.match(/([^:]+)(?::.+)?/) do |m|
|
|
25
|
+
if m[1] == docker_image.name
|
|
26
|
+
container_def.image = docker_image.name_with_tag
|
|
27
|
+
updated_image = true
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
unless updated_image
|
|
33
|
+
fail_with_error!(
|
|
34
|
+
message: "Unable to update ECS task definition; #{docker_image.name} not found in task family #{ecs_task_def.name}."
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
existing_task = existing_task.to_h
|
|
39
|
+
|
|
40
|
+
ecs_task_def.revision = ecs_client(region: region).register_task_definition(
|
|
41
|
+
[
|
|
42
|
+
:family,
|
|
43
|
+
:container_definitions,
|
|
44
|
+
:volumes
|
|
45
|
+
].each_with_object({}) { |k, hash| hash[k] = existing_task[k] if existing_task.has_key?(k) }
|
|
46
|
+
).task_definition.revision
|
|
47
|
+
|
|
48
|
+
Logger.info "Created task definition #{ecs_task_def}"
|
|
49
|
+
end
|
|
50
|
+
rescue Aws::ECS::Errors::ServiceError => e
|
|
51
|
+
fail_with_errors!(messages: [
|
|
52
|
+
"Error: #{e.message}",
|
|
53
|
+
e.backtrace.join("\n")
|
|
54
|
+
])
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
def region
|
|
59
|
+
context.region
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def ecs_task_defs
|
|
63
|
+
context.ecs_task_defs
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'shipitron'
|
|
2
|
+
require 'shellwords'
|
|
3
|
+
|
|
4
|
+
module Shipitron
|
|
5
|
+
module Server
|
|
6
|
+
module Git
|
|
7
|
+
class CloneLocalCopy
|
|
8
|
+
include Metaractor
|
|
9
|
+
|
|
10
|
+
required :application
|
|
11
|
+
required :repository_url
|
|
12
|
+
optional :repository_branch
|
|
13
|
+
|
|
14
|
+
before do
|
|
15
|
+
context.repository_branch ||= 'master'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def call
|
|
19
|
+
Logger.info "Using this branch: #{repository_branch}"
|
|
20
|
+
FileUtils.cd('/home/shipitron') do
|
|
21
|
+
`git clone git-cache #{Shellwords.escape application} --recursive --branch #{Shellwords.escape repository_branch}`
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
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
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
def application
|
|
33
|
+
context.application
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def repository_url
|
|
37
|
+
context.repository_url
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def repository_branch
|
|
41
|
+
context.repository_branch
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require 'shipitron'
|
|
2
|
+
require 'shipitron/consul_keys'
|
|
3
|
+
|
|
4
|
+
module Shipitron
|
|
5
|
+
module Server
|
|
6
|
+
module Git
|
|
7
|
+
class Configure
|
|
8
|
+
include Metaractor
|
|
9
|
+
include ConsulKeys
|
|
10
|
+
|
|
11
|
+
required :application
|
|
12
|
+
required :repository_url
|
|
13
|
+
required :s3_cache_bucket
|
|
14
|
+
|
|
15
|
+
before do
|
|
16
|
+
configure_consul_client!
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def call
|
|
20
|
+
host_key = fetch_key!(key: "shipitron/#{application}/git_host_key")
|
|
21
|
+
Pathname.new('/home/shipitron/.ssh/known_hosts').open('a') do |file|
|
|
22
|
+
file.puts(host_key.to_s)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
deploy_key = fetch_key!(key: "shipitron/#{application}/git_deploy_key")
|
|
26
|
+
Pathname.new('/home/shipitron/.ssh/id_rsa').open('w') do |file|
|
|
27
|
+
file.puts(deploy_key.to_s)
|
|
28
|
+
file.chmod(0600)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
def application
|
|
34
|
+
context.application
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require 'shipitron'
|
|
2
|
+
require 'shipitron/fetch_bucket'
|
|
3
|
+
require 'archive/tar/minitar'
|
|
4
|
+
|
|
5
|
+
module Shipitron
|
|
6
|
+
module Server
|
|
7
|
+
module Git
|
|
8
|
+
class DownloadCache
|
|
9
|
+
include Metaractor
|
|
10
|
+
|
|
11
|
+
required :application
|
|
12
|
+
required :s3_cache_bucket
|
|
13
|
+
|
|
14
|
+
def call
|
|
15
|
+
Logger.info "Downloading git cache from bucket #{s3_cache_bucket}"
|
|
16
|
+
|
|
17
|
+
s3_file = bucket.files.get("#{application}.git.tar.gz")
|
|
18
|
+
if s3_file.nil?
|
|
19
|
+
Logger.warn 'Git cache not found.'
|
|
20
|
+
return
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
Pathname.new("/tmp/#{application}.git.tar.gz").open('wb') do |local_file|
|
|
24
|
+
local_file.write(s3_file.body)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
extract_tarball(filename: "/tmp/#{application}.git.tar.gz", directory: '/home/shipitron')
|
|
28
|
+
|
|
29
|
+
Logger.info 'Download complete.'
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
def application
|
|
34
|
+
context.application
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def s3_cache_bucket
|
|
38
|
+
context.s3_cache_bucket
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def bucket
|
|
42
|
+
@bucket ||= FetchBucket.call!(name: s3_cache_bucket).bucket
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def extract_tarball(filename:, directory:)
|
|
46
|
+
Pathname.new(filename).open('rb') do |tarball|
|
|
47
|
+
Zlib::GzipReader.wrap(tarball) do |gz|
|
|
48
|
+
Archive::Tar::Minitar.unpack(gz, directory)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'shipitron'
|
|
2
|
+
require 'shipitron/server/git/configure'
|
|
3
|
+
require 'shipitron/server/git/download_cache'
|
|
4
|
+
require 'shipitron/server/git/update_cache'
|
|
5
|
+
require 'shipitron/server/git/upload_cache'
|
|
6
|
+
require 'shipitron/server/git/clone_local_copy'
|
|
7
|
+
|
|
8
|
+
module Shipitron
|
|
9
|
+
module Server
|
|
10
|
+
module Git
|
|
11
|
+
class PullRepo
|
|
12
|
+
include Metaractor
|
|
13
|
+
include Interactor::Organizer
|
|
14
|
+
|
|
15
|
+
required :application
|
|
16
|
+
required :repository_url
|
|
17
|
+
required :s3_cache_bucket
|
|
18
|
+
optional :repository_branch
|
|
19
|
+
|
|
20
|
+
organize [
|
|
21
|
+
Configure,
|
|
22
|
+
DownloadCache,
|
|
23
|
+
UpdateCache,
|
|
24
|
+
UploadCache,
|
|
25
|
+
CloneLocalCopy
|
|
26
|
+
]
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'shipitron'
|
|
2
|
+
require 'shellwords'
|
|
3
|
+
|
|
4
|
+
module Shipitron
|
|
5
|
+
module Server
|
|
6
|
+
module Git
|
|
7
|
+
class UpdateCache
|
|
8
|
+
include Metaractor
|
|
9
|
+
|
|
10
|
+
required :application
|
|
11
|
+
required :repository_url
|
|
12
|
+
required :s3_cache_bucket
|
|
13
|
+
optional :repository_branch
|
|
14
|
+
|
|
15
|
+
before do
|
|
16
|
+
context.repository_branch ||= 'master'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def call
|
|
20
|
+
if !Pathname.new('/home/shipitron/git-cache/objects').directory?
|
|
21
|
+
Logger.info 'Cloning the git repository'
|
|
22
|
+
FileUtils.cd('/home/shipitron') do
|
|
23
|
+
`git clone --bare #{Shellwords.escape repository_url} git-cache`
|
|
24
|
+
end
|
|
25
|
+
else
|
|
26
|
+
Logger.info 'Fetching new git commits'
|
|
27
|
+
FileUtils.cd('/home/shipitron/git-cache') do
|
|
28
|
+
`git fetch #{Shellwords.escape repository_url} #{Shellwords.escape repository_branch}:#{Shellwords.escape repository_branch}`
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
def application
|
|
35
|
+
context.application
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def repository_url
|
|
39
|
+
context.repository_url
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def s3_cache_bucket
|
|
43
|
+
context.s3_cache_bucket
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def repository_branch
|
|
47
|
+
context.repository_branch
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require 'shipitron'
|
|
2
|
+
require 'shipitron/fetch_bucket'
|
|
3
|
+
require 'find'
|
|
4
|
+
require 'archive/tar/minitar'
|
|
5
|
+
|
|
6
|
+
module Shipitron
|
|
7
|
+
module Server
|
|
8
|
+
module Git
|
|
9
|
+
class UploadCache
|
|
10
|
+
include Metaractor
|
|
11
|
+
|
|
12
|
+
required :application
|
|
13
|
+
required :s3_cache_bucket
|
|
14
|
+
|
|
15
|
+
def call
|
|
16
|
+
Logger.info "Uploading git cache to bucket #{s3_cache_bucket}"
|
|
17
|
+
create_tarball(filename: "/tmp/#{application}.git.tar.gz", directory: '/home/shipitron/git-cache')
|
|
18
|
+
|
|
19
|
+
Pathname.new("/tmp/#{application}.git.tar.gz").open('rb') do |local_file|
|
|
20
|
+
bucket.files.create(
|
|
21
|
+
key: "#{application}.git.tar.gz",
|
|
22
|
+
body: local_file.read
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
def application
|
|
29
|
+
context.application
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def s3_cache_bucket
|
|
33
|
+
context.s3_cache_bucket
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def create_tarball(filename:, directory:)
|
|
37
|
+
base_dir = Pathname.new(directory).parent
|
|
38
|
+
Logger.debug 'Creating tarball'
|
|
39
|
+
FileUtils.cd(base_dir) do
|
|
40
|
+
Pathname.new(filename).open('wb') do |tarball|
|
|
41
|
+
Zlib::GzipWriter.wrap(tarball) do |gz|
|
|
42
|
+
Archive::Tar::Minitar::Output.open(gz) do |tar|
|
|
43
|
+
Find.find(directory) do |path|
|
|
44
|
+
pn = Pathname.new(path)
|
|
45
|
+
name = pn.relative_path_from(base_dir)
|
|
46
|
+
Logger.debug(name)
|
|
47
|
+
Archive::Tar::Minitar.pack_file(name.to_s, tar)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def bucket
|
|
56
|
+
@bucket ||= FetchBucket.call!(name: s3_cache_bucket).bucket
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
require 'shipitron'
|
|
2
|
+
require 'shipitron/ecs_client'
|
|
3
|
+
|
|
4
|
+
module Shipitron
|
|
5
|
+
module Server
|
|
6
|
+
class RunPostBuild
|
|
7
|
+
include Metaractor
|
|
8
|
+
include EcsClient
|
|
9
|
+
|
|
10
|
+
required :region
|
|
11
|
+
required :cluster_name
|
|
12
|
+
optional :post_builds
|
|
13
|
+
|
|
14
|
+
def call
|
|
15
|
+
return if post_builds.nil? || post_builds.empty?
|
|
16
|
+
|
|
17
|
+
Logger.info 'Running post build commands'
|
|
18
|
+
|
|
19
|
+
begin
|
|
20
|
+
post_builds.each do |post_build|
|
|
21
|
+
Logger.info "Running #{post_build.command}"
|
|
22
|
+
response = ecs_client(region: region).run_task(
|
|
23
|
+
cluster: cluster_name,
|
|
24
|
+
task_definition: post_build.ecs_task,
|
|
25
|
+
overrides: {
|
|
26
|
+
container_overrides: [
|
|
27
|
+
{
|
|
28
|
+
name: post_build.container_name,
|
|
29
|
+
command: [post_build.command]
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
count: 1,
|
|
34
|
+
started_by: 'shipitron'
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
if !response.failures.empty?
|
|
38
|
+
response.failures.each do |failure|
|
|
39
|
+
fail_with_error! message: "ECS run_task failure: #{failure.arn}: #{failure.reason}"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
task_arn = response.tasks.first.task_arn
|
|
44
|
+
|
|
45
|
+
Logger.info 'Waiting for task to finish'
|
|
46
|
+
loop do
|
|
47
|
+
response = ecs_client(region: region).describe_tasks(
|
|
48
|
+
cluster: cluster_name,
|
|
49
|
+
tasks: [task_arn]
|
|
50
|
+
)
|
|
51
|
+
Logger.info "Task status: #{response.tasks.first.last_status}"
|
|
52
|
+
break if response.tasks.first.last_status == 'STOPPED'.freeze
|
|
53
|
+
sleep 1
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
rescue Aws::ECS::Errors::ServiceError => e
|
|
58
|
+
fail_with_errors!(messages: [
|
|
59
|
+
"Error: #{e.message}",
|
|
60
|
+
e.backtrace.join("\n")
|
|
61
|
+
])
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
def post_builds
|
|
67
|
+
context.post_builds
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def region
|
|
71
|
+
context.region
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def cluster_name
|
|
75
|
+
context.cluster_name
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
require 'shipitron'
|
|
2
|
+
require 'shipitron/docker_image'
|
|
3
|
+
require 'shipitron/ecs_task_def'
|
|
4
|
+
require 'shipitron/post_build'
|
|
5
|
+
require 'base64'
|
|
6
|
+
|
|
7
|
+
module Shipitron
|
|
8
|
+
module Server
|
|
9
|
+
class TransformCliArgs
|
|
10
|
+
include Metaractor
|
|
11
|
+
|
|
12
|
+
required :application
|
|
13
|
+
required :repository_url
|
|
14
|
+
optional :repository_branch
|
|
15
|
+
required :s3_cache_bucket
|
|
16
|
+
required :image_name
|
|
17
|
+
required :region
|
|
18
|
+
required :cluster_name
|
|
19
|
+
required :ecs_task_defs
|
|
20
|
+
optional :ecs_task_def_templates
|
|
21
|
+
required :ecs_services
|
|
22
|
+
optional :ecs_service_templates
|
|
23
|
+
optional :build_script
|
|
24
|
+
optional :post_builds
|
|
25
|
+
|
|
26
|
+
before do
|
|
27
|
+
context.ecs_task_def_templates ||= []
|
|
28
|
+
context.ecs_service_templates ||= []
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def call
|
|
32
|
+
cli_args = Smash.new
|
|
33
|
+
|
|
34
|
+
%i[
|
|
35
|
+
application
|
|
36
|
+
repository_url
|
|
37
|
+
repository_branch
|
|
38
|
+
s3_cache_bucket
|
|
39
|
+
region
|
|
40
|
+
cluster_name
|
|
41
|
+
ecs_services
|
|
42
|
+
build_script
|
|
43
|
+
].each_with_object(cli_args) { |k, args| args[k] = context[k] }
|
|
44
|
+
|
|
45
|
+
cli_args.docker_image = DockerImage.new(name: context.image_name)
|
|
46
|
+
|
|
47
|
+
cli_args.ecs_task_defs = []
|
|
48
|
+
ecs_task_defs.each do |task_def|
|
|
49
|
+
cli_args.ecs_task_defs << EcsTaskDef.new(name: task_def)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
cli_args.ecs_task_def_templates = []
|
|
53
|
+
context.ecs_task_def_templates.each do |template|
|
|
54
|
+
cli_args.ecs_task_def_templates << Base64.urlsafe_decode64(template)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
cli_args.ecs_service_templates = []
|
|
58
|
+
context.ecs_service_templates.each do |template|
|
|
59
|
+
cli_args.ecs_service_templates << Base64.urlsafe_decode64(template)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
Logger.debug "task_def_templates: #{cli_args.ecs_task_def_templates}"
|
|
63
|
+
Logger.debug "service_templates: #{cli_args.ecs_service_templates}"
|
|
64
|
+
|
|
65
|
+
if post_builds != nil && !post_builds.empty?
|
|
66
|
+
cli_args.post_builds = []
|
|
67
|
+
post_builds.each do |post_build_str|
|
|
68
|
+
cli_args.post_builds << PostBuild.parse(post_build_str)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
context.cli_args = cli_args
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
def ecs_task_defs
|
|
77
|
+
context.ecs_task_defs
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def post_builds
|
|
81
|
+
context.post_builds
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|