container_ship 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: dd33f056d20c82975db4c69f44ded7b30125549032afca7d836792eda460bd4f
4
+ data.tar.gz: 7e86a7a3f8990bc2768e1705df852780d1f731bde97832d35d38227dc0e88512
5
+ SHA512:
6
+ metadata.gz: 9f5acd9cd7f5232eddf69661e7c961c6869518dfea10f8e148fbc4e4c0fe5f6270b420d6766286af0ece908fffef0f34224fe3bd4f8d230860db2fe8c3acf298
7
+ data.tar.gz: 0becf5d69d45bdd794b8b287f2d9c7f263e52ead5a3d0ead6050031fe8860b0526c87d20b3c03a0eb09705e72ed93442a74605cfdae25abd81b98b9cc52259b0
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.3
7
+ before_install: gem install bundler -v 2.0.2
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at unhappychoice@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in container_ship.gemspec
4
+ gemspec
@@ -0,0 +1,162 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ container_ship (0.1.0)
5
+ aws-sdk-cloudwatchlogs
6
+ aws-sdk-ecs
7
+ thor
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ activesupport (6.0.0)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 0.7, < 2)
15
+ minitest (~> 5.1)
16
+ tzinfo (~> 1.1)
17
+ zeitwerk (~> 2.1, >= 2.1.8)
18
+ addressable (2.7.0)
19
+ public_suffix (>= 2.0.2, < 5.0)
20
+ ast (2.4.0)
21
+ aws-eventstream (1.0.3)
22
+ aws-partitions (1.226.0)
23
+ aws-sdk-cloudwatchlogs (1.25.0)
24
+ aws-sdk-core (~> 3, >= 3.61.1)
25
+ aws-sigv4 (~> 1.1)
26
+ aws-sdk-core (3.69.1)
27
+ aws-eventstream (~> 1.0, >= 1.0.2)
28
+ aws-partitions (~> 1.0)
29
+ aws-sigv4 (~> 1.1)
30
+ jmespath (~> 1.0)
31
+ aws-sdk-ecs (1.51.0)
32
+ aws-sdk-core (~> 3, >= 3.61.1)
33
+ aws-sigv4 (~> 1.1)
34
+ aws-sigv4 (1.1.0)
35
+ aws-eventstream (~> 1.0, >= 1.0.2)
36
+ codecov (0.1.15)
37
+ json
38
+ simplecov
39
+ url
40
+ coderay (1.1.2)
41
+ concurrent-ruby (1.1.5)
42
+ diff-lcs (1.3)
43
+ docile (1.3.2)
44
+ faraday (0.17.0)
45
+ multipart-post (>= 1.2, < 3)
46
+ faraday-http-cache (2.0.0)
47
+ faraday (~> 0.8)
48
+ ffi (1.11.1)
49
+ formatador (0.2.5)
50
+ github_changelog_generator (1.14.3)
51
+ activesupport
52
+ faraday-http-cache
53
+ multi_json
54
+ octokit (~> 4.6)
55
+ rainbow (>= 2.1)
56
+ rake (>= 10.0)
57
+ retriable (~> 2.1)
58
+ guard (2.15.1)
59
+ formatador (>= 0.2.4)
60
+ listen (>= 2.7, < 4.0)
61
+ lumberjack (>= 1.0.12, < 2.0)
62
+ nenv (~> 0.1)
63
+ notiffany (~> 0.0)
64
+ pry (>= 0.9.12)
65
+ shellany (~> 0.0)
66
+ thor (>= 0.18.1)
67
+ guard-compat (1.2.1)
68
+ guard-rspec (4.7.3)
69
+ guard (~> 2.1)
70
+ guard-compat (~> 1.1)
71
+ rspec (>= 2.99.0, < 4.0)
72
+ guard-rubocop (1.3.0)
73
+ guard (~> 2.0)
74
+ rubocop (~> 0.20)
75
+ i18n (1.7.0)
76
+ concurrent-ruby (~> 1.0)
77
+ jaro_winkler (1.5.3)
78
+ jmespath (1.4.0)
79
+ json (2.2.0)
80
+ listen (3.2.0)
81
+ rb-fsevent (~> 0.10, >= 0.10.3)
82
+ rb-inotify (~> 0.9, >= 0.9.10)
83
+ lumberjack (1.0.13)
84
+ method_source (0.9.2)
85
+ minitest (5.12.2)
86
+ multi_json (1.14.1)
87
+ multipart-post (2.1.1)
88
+ nenv (0.3.0)
89
+ notiffany (0.1.3)
90
+ nenv (~> 0.1)
91
+ shellany (~> 0.0)
92
+ octokit (4.14.0)
93
+ sawyer (~> 0.8.0, >= 0.5.3)
94
+ parallel (1.18.0)
95
+ parser (2.6.5.0)
96
+ ast (~> 2.4.0)
97
+ pry (0.12.2)
98
+ coderay (~> 1.1.0)
99
+ method_source (~> 0.9.0)
100
+ public_suffix (4.0.1)
101
+ rainbow (3.0.0)
102
+ rake (13.0.0)
103
+ rb-fsevent (0.10.3)
104
+ rb-inotify (0.10.0)
105
+ ffi (~> 1.0)
106
+ retriable (2.1.0)
107
+ rspec (3.9.0)
108
+ rspec-core (~> 3.9.0)
109
+ rspec-expectations (~> 3.9.0)
110
+ rspec-mocks (~> 3.9.0)
111
+ rspec-core (3.9.0)
112
+ rspec-support (~> 3.9.0)
113
+ rspec-expectations (3.9.0)
114
+ diff-lcs (>= 1.2.0, < 2.0)
115
+ rspec-support (~> 3.9.0)
116
+ rspec-mocks (3.9.0)
117
+ diff-lcs (>= 1.2.0, < 2.0)
118
+ rspec-support (~> 3.9.0)
119
+ rspec-support (3.9.0)
120
+ rubocop (0.75.1)
121
+ jaro_winkler (~> 1.5.1)
122
+ parallel (~> 1.10)
123
+ parser (>= 2.6)
124
+ rainbow (>= 2.2.2, < 4.0)
125
+ ruby-progressbar (~> 1.7)
126
+ unicode-display_width (>= 1.4.0, < 1.7)
127
+ ruby-progressbar (1.10.1)
128
+ sawyer (0.8.2)
129
+ addressable (>= 2.3.5)
130
+ faraday (> 0.8, < 2.0)
131
+ shellany (0.0.1)
132
+ simplecov (0.17.1)
133
+ docile (~> 1.1)
134
+ json (>= 1.8, < 3)
135
+ simplecov-html (~> 0.10.0)
136
+ simplecov-html (0.10.2)
137
+ thor (0.20.3)
138
+ thread_safe (0.3.6)
139
+ tzinfo (1.2.5)
140
+ thread_safe (~> 0.1)
141
+ unicode-display_width (1.6.0)
142
+ url (0.3.2)
143
+ zeitwerk (2.2.0)
144
+
145
+ PLATFORMS
146
+ ruby
147
+
148
+ DEPENDENCIES
149
+ bundler
150
+ codecov
151
+ container_ship!
152
+ github_changelog_generator
153
+ guard
154
+ guard-rspec
155
+ guard-rubocop
156
+ rake
157
+ rspec
158
+ rubocop
159
+ simplecov
160
+
161
+ BUNDLED WITH
162
+ 2.0.2
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Seibii, Inc
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,87 @@
1
+ # container_ship
2
+ [![Gem Version](https://badge.fury.io/rb/container_ship.svg)](https://badge.fury.io/rb/container_ship)
3
+ [![Circle CI](https://circleci.com/gh/seibii/container_ship.svg?style=shield)](https://circleci.com/gh/seibii/container_ship)
4
+ [![Code Climate](https://codeclimate.com/github/seibii/container_ship/badges/gpa.svg)](https://codeclimate.com/github/seibii/container_ship)
5
+ [![Libraries.io dependency status for GitHub repo](https://img.shields.io/librariesio/github/seibii/container_ship.svg)](https://libraries.io/github/seibii/container_ship)
6
+ ![](http://ruby-gem-downloads-badge.herokuapp.com/container_ship?type=total)
7
+ ![GitHub](https://img.shields.io/github/license/seibii/container_ship.svg)
8
+
9
+ `container_ship` is yet another ECS deployment tool.
10
+
11
+ Key features are:
12
+
13
+ - Using raw `task_definition.json` file not a template file with complex state or variables
14
+ - Convention over configuration
15
+
16
+ ## Installation
17
+ ```ruby
18
+ gem 'container_ship'
19
+ ```
20
+
21
+ ## Usage
22
+ ### Prepare task_definition.json
23
+ `container_ship init YOUR_CLUSTER_NAME` will create empty directory for you.
24
+ And you must put `task_definition.json` file in directories like below.
25
+
26
+ ```
27
+ your_app
28
+ |-- .container_ship
29
+ | |-- your_cluster_name
30
+ | | |-- services // ECS services
31
+ | | | |-- your_service_name // like server or api
32
+ | | | | |-- your_envrionment_name // like production or staging
33
+ | | | | | |-- task_definition.json
34
+ | | | | |
35
+ | | | | +-- your_other_environment_name
36
+ | | | | |-- task_definition.json
37
+ | | | |
38
+ | | | +-- your_other_service_name
39
+ | | |
40
+ | | |
41
+ | | +-- tasks // ECS tasks
42
+ | | |-- your_task_name ( like db-migrate or
43
+ | | | |-- your_envrionment_name // like production or staging
44
+ | | | | |-- task_definition.json
45
+ | | | |
46
+ | | | +-- your_other_environment_name
47
+ | | | |-- task_definition.json
48
+ | | +-- your_task_name ( like db-migrate or
49
+ | |
50
+ | +-- your_other_cluster_name
51
+ |--...
52
+ ```
53
+
54
+ ### Prepare ECS resources
55
+ You must obey `convention over configuration` concept. So, naming convention is presented below.
56
+
57
+ - ECS cluster: "#{cluster_name}-#{environment}"
58
+ - ECS service: "#{cluster_name}-#{service_name}-#{environment}"
59
+ - ECS task: "#{cluster_name}-#{task_name}-#{environment}"
60
+
61
+ And export your ECR repository root uri.
62
+
63
+ ```
64
+ export ECR_REPOSITORY=xxxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/
65
+ ```
66
+
67
+ ### Deploy a service
68
+ ```
69
+ container_ship ship CLUSTER_NAME SERVICE_NAME ENVIRONMENT BUILD_NUMBER
70
+ ```
71
+
72
+ ### Run a task
73
+ ```
74
+ container_ship exec CLUSTER_NAME TASK_NAME ENVIRONMENT BUILD_NUMBER
75
+ ```
76
+
77
+ ## Contributing
78
+
79
+ Bug reports and pull requests are welcome on GitHub at https://github.com/seibii/container_ship. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
80
+
81
+ ## License
82
+
83
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
84
+
85
+ ## Code of Conduct
86
+
87
+ Everyone interacting in the ContainerShip project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/seibii/container_ship/blob/master/CODE_OF_CONDUCT.md).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,43 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "container_ship/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'container_ship'
7
+ spec.version = ContainerShip::VERSION
8
+ spec.authors = ['Yuji Ueki']
9
+ spec.email = ['unhappychoice@gmail.com']
10
+
11
+ spec.summary = %q{Yet another ECS deployment tool}
12
+ spec.description = %q{container_ship is a simple ECS deployment tool. You only need to prepare Dockerfile and task_definition.json}
13
+ spec.homepage = 'https://github.com/seibii/container_ship'
14
+ spec.license = 'MIT'
15
+
16
+ spec.metadata['homepage_uri'] = spec.homepage
17
+ spec.metadata['source_code_uri'] = 'https://github.com/seibii/container_ship'
18
+ spec.metadata['changelog_uri'] = 'https://github.com/seibii/container_ship'
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
23
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
+ end
25
+ spec.bindir = 'exe'
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ['lib']
28
+
29
+ spec.add_dependency 'aws-sdk-cloudwatchlogs'
30
+ spec.add_dependency 'aws-sdk-ecs'
31
+ spec.add_dependency 'thor'
32
+
33
+ spec.add_development_dependency 'bundler'
34
+ spec.add_development_dependency 'codecov'
35
+ spec.add_development_dependency 'github_changelog_generator'
36
+ spec.add_development_dependency 'guard'
37
+ spec.add_development_dependency 'guard-rspec'
38
+ spec.add_development_dependency 'guard-rubocop'
39
+ spec.add_development_dependency 'rake'
40
+ spec.add_development_dependency 'rspec'
41
+ spec.add_development_dependency 'rubocop'
42
+ spec.add_development_dependency 'simplecov'
43
+ end
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'container_ship'
5
+
6
+ ContainerShip::CLI.start
@@ -0,0 +1,7 @@
1
+ require 'container_ship/cli'
2
+ require 'container_ship/command'
3
+ require 'container_ship/task_definition'
4
+ require 'container_ship/version'
5
+
6
+ module ContainerShip
7
+ end
@@ -0,0 +1,26 @@
1
+ require 'fileutils'
2
+ require 'thor'
3
+
4
+ module ContainerShip
5
+ class CLI < Thor
6
+ desc 'init CLUSTER_NAME', 'create container_ship directory with ECS cluster name'
7
+ def init(cluster_name)
8
+ Command::InitCommand.new.run(cluster_name)
9
+ end
10
+
11
+ desc 'ship CLUSTER_NAME SERVICE_NAME ENVIRONMENT BUILD_NUMBER', 'deploy specified service'
12
+ def ship(cluster_name, service_name, environment, build_number)
13
+ Command::ShipCommand.new.run(cluster_name, service_name, environment, build_number)
14
+ end
15
+
16
+ desc 'exec CLUSTER_NAME SERVICE_NAME ENVIRONMENT BUILD_NUMBER', 'exec specified task'
17
+ def exec(cluster_name, service_name, environment, build_number)
18
+ Command::ExecCommand.new.run(cluster_name, service_name, environment, build_number)
19
+ end
20
+
21
+ desc 'version', 'display gem version'
22
+ def version
23
+ say ContainerShip::VERSION
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,8 @@
1
+ require 'container_ship/command/exec_command'
2
+ require 'container_ship/command/init_command'
3
+ require 'container_ship/command/ship_command'
4
+
5
+ module ContainerShip
6
+ module Command
7
+ end
8
+ end
@@ -0,0 +1,41 @@
1
+ require 'aws-sdk-ecs'
2
+ require 'json'
3
+ require 'open3'
4
+
5
+ require 'container_ship/command/modules/cloudwatch'
6
+ require 'container_ship/command/modules/docker'
7
+ require 'container_ship/command/modules/ecs'
8
+ require 'container_ship/command/modules/print_task'
9
+
10
+ module ContainerShip
11
+ module Command
12
+ class ExecCommand
13
+ include Modules::Cloudwatch
14
+ include Modules::Docker
15
+ include Modules::Ecs
16
+ include Modules::PrintTask
17
+
18
+ def run(cluster_name, task_name, environment, build_number)
19
+ task_definition = TaskDefinition.new(cluster_name, 'tasks', task_name, environment, build_number)
20
+
21
+ push_image task_definition
22
+
23
+ revision = print_around_task("Registering task definition... ") do
24
+ register task_definition
25
+ end
26
+
27
+ task_arn = print_around_task("Sending task request... ") do
28
+ run_task task_definition, revision
29
+ end
30
+
31
+ exit_status = print_around_task("Waiting task is completed... ") do
32
+ wait_task task_definition, task_arn
33
+ end
34
+
35
+ show_log task_definition, task_arn
36
+
37
+ exit exit_status
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,14 @@
1
+ module ContainerShip
2
+ module Command
3
+ class InitCommand
4
+ def run(cluster_name)
5
+ FileUtils.mkdir_p(".container_ship/#{cluster_name}/tasks")
6
+ puts "Created .container_ship/#{cluster_name}/tasks directory"
7
+ FileUtils.mkdir_p(".container_ship/#{cluster_name}/services")
8
+ puts "Created .container_ship/#{cluster_name}/services directory"
9
+
10
+ puts "Next: Create tasks_definition.json file to deploy in tasks or services directory 🖖🏻"
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,18 @@
1
+ require 'aws-sdk-cloudwatchlogs'
2
+
3
+ module ContainerShip
4
+ module Command
5
+ module Modules
6
+ module Cloudwatch
7
+ def show_log(task_definition, task_arn)
8
+ return if task_definition.log_group_name.nil? || task_definition.log_stream_name(task_arn).nil?
9
+
10
+ Aws::CloudWatchLogs::Client.new.get_log_events(
11
+ log_group_name: task_definition.log_group_name,
12
+ log_stream_name: task_definition.log_stream_name(task_arn)
13
+ ).events.map(&:message).each(&method(:puts))
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ module ContainerShip
2
+ module Command
3
+ module Modules
4
+ module Docker
5
+ def push_image(task_definition)
6
+ sh "docker build -t \"#{task_definition.image_name}:#{task_definition.build_number}\" ."
7
+ sh "docker push #{task_definition.image_name}:#{task_definition.build_number}"
8
+ end
9
+
10
+ private
11
+
12
+ def sh(command)
13
+ status = nil
14
+ Open3.popen3(command) do |_i, o, _e, w|
15
+ o.each { |line| puts line }
16
+ status = w.value
17
+ end
18
+ exit(status.exit_status) unless status.success?
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,63 @@
1
+ module ContainerShip
2
+ module Command
3
+ module Modules
4
+ module Ecs
5
+ def register(task_definition)
6
+ aws_ecs_client
7
+ .register_task_definition(task_definition.to_h)
8
+ .task_definition
9
+ .revision
10
+ end
11
+
12
+ def update_service(task_definition, revision)
13
+ aws_ecs_client.update_service(
14
+ cluster: task_definition.full_cluster_name,
15
+ service: task_definition.full_name,
16
+ task_definition: "#{task_definition.full_name}:#{revision}"
17
+ )
18
+ end
19
+
20
+ def run_task(task_definition, revision)
21
+ aws_ecs_client
22
+ .run_task(
23
+ cluster: task_definition.full_cluster_name,
24
+ task_definition: "#{task_definition.full_name}:#{revision}"
25
+ )
26
+ .tasks
27
+ .first
28
+ .task_arn
29
+ end
30
+
31
+ def wait_task(task_definition, task_arn)
32
+ do_every_5_seconds do
33
+ aws_ecs_client.describe_tasks(cluster: task_definition.full_cluster_name, tasks: [task_arn])
34
+ .tasks
35
+ .first
36
+ .containers
37
+ .first
38
+ .exit_code
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def aws_ecs_client
45
+ @aws_ecs_client ||= Aws::ECS::Client.new
46
+ end
47
+
48
+ def do_every_5_seconds
49
+ count = 0
50
+ while true
51
+ sleep 3
52
+ print '.'
53
+ exit_status = yield
54
+ count += 1
55
+ next if exit_status.nil?
56
+ return 124 if count > 60
57
+ return exit_status
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,16 @@
1
+ module ContainerShip
2
+ module Command
3
+ module Modules
4
+ module PrintTask
5
+ private
6
+
7
+ def print_around_task(message)
8
+ print message
9
+ result = yield
10
+ puts "Done"
11
+ result
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,37 @@
1
+ require 'aws-sdk-ecs'
2
+ require 'json'
3
+ require 'open3'
4
+
5
+ require 'container_ship/command/modules/docker'
6
+ require 'container_ship/command/modules/ecs'
7
+ require 'container_ship/command/modules/print_task'
8
+
9
+ module ContainerShip
10
+ module Command
11
+ class ShipCommand
12
+ include Modules::Docker
13
+ include Modules::Ecs
14
+ include Modules::PrintTask
15
+
16
+ def run(cluster_name, service_name, environment, build_number)
17
+ task_definition = TaskDefinition.new(
18
+ cluster_name,
19
+ 'services',
20
+ service_name,
21
+ environment,
22
+ build_number
23
+ )
24
+
25
+ push_image task_definition
26
+
27
+ revision = print_around_task('Registering task definition... ') do
28
+ register task_definition
29
+ end
30
+
31
+ print_around_task('Updating service... ') do
32
+ update_service task_definition, revision
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,64 @@
1
+ module ContainerShip
2
+ class TaskDefinition
3
+ attr_reader :cluster_name, :name, :environment, :build_number
4
+
5
+ def initialize(cluster_name, type, name, environment, build_number)
6
+ @cluster_name = cluster_name
7
+ @type = type
8
+ @name = name
9
+ @environment = environment
10
+ @build_number = build_number
11
+ end
12
+
13
+ def to_h
14
+ task_definition_hash
15
+ .merge(
16
+ family: full_name,
17
+ container_definitions: task_definition_hash[:container_definitions].map do |d|
18
+ next d unless d[:essential]
19
+
20
+ d.merge(name: full_name, image: "#{image_name}:#{@build_number}")
21
+ end
22
+ )
23
+ end
24
+
25
+ def full_cluster_name
26
+ "#{@cluster_name}-#{@environment}"
27
+ end
28
+
29
+ def full_name
30
+ "#{@cluster_name}-#{@name}-#{@environment}"
31
+ end
32
+
33
+ def image_name
34
+ ENV.fetch('ECR_REPOSITORY') + full_cluster_name
35
+ end
36
+
37
+ def log_group_name
38
+ return nil unless main_container_definition.dig(:log_configuration, :log_driver).to_s == 'awslogs'
39
+
40
+ main_container_definition.dig(:log_configuration, :options, :'awslogs-group')
41
+ end
42
+
43
+ def log_stream_name(task_arn)
44
+ return nil unless main_container_definition.dig(:log_configuration, :log_driver).to_s == 'awslogs'
45
+
46
+ prefix = main_container_definition.dig(:log_configuration, :options, :'awslogs-stream-prefix')
47
+ "#{prefix}/#{full_name}/#{task_arn.split('/').last}"
48
+ end
49
+
50
+ private
51
+
52
+ def task_definition_hash
53
+ @task_definition_hash ||= JSON.parse(File.read(task_definition_path), symbolize_names: true)
54
+ end
55
+
56
+ def task_definition_path
57
+ File.join('.container_ship', @cluster_name, @type, @name, @environment, 'task_definition.json')
58
+ end
59
+
60
+ def main_container_definition
61
+ task_definition_hash[:container_definitions].find { |definition| definition[:essential] }
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,3 @@
1
+ module ContainerShip
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,252 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: container_ship
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Yuji Ueki
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-10-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aws-sdk-cloudwatchlogs
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: aws-sdk-ecs
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: thor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: codecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: github_changelog_generator
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: guard
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: guard-rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: guard-rubocop
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rake
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rspec
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: rubocop
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: simplecov
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ description: container_ship is a simple ECS deployment tool. You only need to prepare
196
+ Dockerfile and task_definition.json
197
+ email:
198
+ - unhappychoice@gmail.com
199
+ executables:
200
+ - container_ship
201
+ extensions: []
202
+ extra_rdoc_files: []
203
+ files:
204
+ - ".gitignore"
205
+ - ".travis.yml"
206
+ - CODE_OF_CONDUCT.md
207
+ - Gemfile
208
+ - Gemfile.lock
209
+ - LICENSE.txt
210
+ - README.md
211
+ - Rakefile
212
+ - container_ship.gemspec
213
+ - exe/container_ship
214
+ - lib/container_ship.rb
215
+ - lib/container_ship/cli.rb
216
+ - lib/container_ship/command.rb
217
+ - lib/container_ship/command/exec_command.rb
218
+ - lib/container_ship/command/init_command.rb
219
+ - lib/container_ship/command/modules/cloudwatch.rb
220
+ - lib/container_ship/command/modules/docker.rb
221
+ - lib/container_ship/command/modules/ecs.rb
222
+ - lib/container_ship/command/modules/print_task.rb
223
+ - lib/container_ship/command/ship_command.rb
224
+ - lib/container_ship/task_definition.rb
225
+ - lib/container_ship/version.rb
226
+ homepage: https://github.com/seibii/container_ship
227
+ licenses:
228
+ - MIT
229
+ metadata:
230
+ homepage_uri: https://github.com/seibii/container_ship
231
+ source_code_uri: https://github.com/seibii/container_ship
232
+ changelog_uri: https://github.com/seibii/container_ship
233
+ post_install_message:
234
+ rdoc_options: []
235
+ require_paths:
236
+ - lib
237
+ required_ruby_version: !ruby/object:Gem::Requirement
238
+ requirements:
239
+ - - ">="
240
+ - !ruby/object:Gem::Version
241
+ version: '0'
242
+ required_rubygems_version: !ruby/object:Gem::Requirement
243
+ requirements:
244
+ - - ">="
245
+ - !ruby/object:Gem::Version
246
+ version: '0'
247
+ requirements: []
248
+ rubygems_version: 3.0.3
249
+ signing_key:
250
+ specification_version: 4
251
+ summary: Yet another ECS deployment tool
252
+ test_files: []