orchestration 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +14 -0
- data/.rubocop.yml +14 -0
- data/Gemfile +4 -2
- data/Makefile +5 -0
- data/README.md +82 -16
- data/Rakefile +5 -3
- data/TODO +2 -0
- data/bin/rspec +29 -0
- data/bin/rubocop +29 -0
- data/config/locales/en.yml +16 -0
- data/lib/orchestration/docker_compose/database_service.rb +51 -0
- data/lib/orchestration/docker_compose/mongo_service.rb +27 -0
- data/lib/orchestration/docker_compose/rabbitmq_service.rb +23 -0
- data/lib/orchestration/docker_compose/services.rb +48 -0
- data/lib/orchestration/docker_compose.rb +11 -0
- data/lib/orchestration/environment.rb +47 -0
- data/lib/orchestration/errors.rb +7 -0
- data/lib/orchestration/file_helpers.rb +88 -0
- data/lib/orchestration/healthcheck_base.rb +21 -0
- data/lib/orchestration/install_generator.rb +95 -0
- data/lib/orchestration/railtie.rb +9 -0
- data/lib/orchestration/service_check.rb +81 -0
- data/lib/orchestration/services/database/adapters/mysql2.rb +27 -0
- data/lib/orchestration/services/database/adapters/postgresql.rb +27 -0
- data/lib/orchestration/services/database/adapters/sqlite3.rb +23 -0
- data/lib/orchestration/services/database/adapters.rb +14 -0
- data/lib/orchestration/services/database/configuration.rb +114 -0
- data/lib/orchestration/services/database/healthcheck.rb +30 -0
- data/lib/orchestration/services/database.rb +15 -0
- data/lib/orchestration/services/mongo/configuration.rb +55 -0
- data/lib/orchestration/services/mongo/healthcheck.rb +34 -0
- data/lib/orchestration/services/mongo.rb +12 -0
- data/lib/orchestration/services/rabbitmq/configuration.rb +36 -0
- data/lib/orchestration/services/rabbitmq/healthcheck.rb +37 -0
- data/lib/orchestration/services/rabbitmq.rb +12 -0
- data/lib/orchestration/services.rb +10 -0
- data/lib/orchestration/settings.rb +43 -0
- data/lib/orchestration/templates/Dockerfile.tt +11 -0
- data/lib/orchestration/templates/Makefile.tt +53 -0
- data/lib/orchestration/terminal.rb +44 -0
- data/lib/orchestration/version.rb +3 -1
- data/lib/orchestration.rb +25 -2
- data/lib/tasks/orchestration.rake +39 -0
- data/orchestration.gemspec +34 -17
- metadata +213 -7
- data/CODE_OF_CONDUCT.md +0 -74
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9c1480a6241a2ea71eaa7a9c9fc3ad4d098a180b
|
4
|
+
data.tar.gz: 352354aef228f577185908ea06f9aa332cee5ec9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c0ac0ad8b6f5a780a8f9dce28f528175b1d4894b9d18db365035efdb5088b98d6d4665dc327a43dfd8030d278ec4dfbecc88877a080b2e12fda513427ab2316
|
7
|
+
data.tar.gz: 985e17427df0c2347892f628ae14fccb144aa6a1767d5a0f0351d73b4cb7f23faf24072d1fd8f924db83a47fcf8333232c2968b506ae5181f541507b1a4ca4a2
|
data/.gitignore
CHANGED
@@ -9,3 +9,17 @@
|
|
9
9
|
|
10
10
|
# rspec failure tracking
|
11
11
|
.rspec_status
|
12
|
+
|
13
|
+
Gemfile.lock
|
14
|
+
|
15
|
+
*.swp
|
16
|
+
*.swo
|
17
|
+
|
18
|
+
spec/dummy/log/*
|
19
|
+
!spec/dummy/log/.keep
|
20
|
+
spec/dummy/.gitignore
|
21
|
+
spec/dummy/Makefile
|
22
|
+
spec/dummy/docker/*
|
23
|
+
spec/dummy/docker-compose.yml
|
24
|
+
|
25
|
+
.byebug_history
|
data/.rubocop.yml
ADDED
data/Gemfile
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
4
6
|
|
5
7
|
# Specify your gem's dependencies in orchestration.gemspec
|
6
8
|
gemspec
|
data/Makefile
ADDED
data/README.md
CHANGED
@@ -1,39 +1,105 @@
|
|
1
1
|
# Orchestration
|
2
2
|
|
3
|
-
|
3
|
+
## Overview
|
4
4
|
|
5
|
-
|
5
|
+
_Orchestration_ provides a toolkit for building and launching _Rails_ applications and dependencies in _Docker_.
|
6
|
+
|
7
|
+
A suite of tools is provided to assist in creating configuration files, launching service dependencies, verifying that dependencies have launched successfully (e.g. for running tests in contiuous integration tools), and building, tagging, and pushing _Docker_ images.
|
8
|
+
|
9
|
+
Containers are automatically created for the following dependencies:
|
10
|
+
|
11
|
+
* MySQL
|
12
|
+
* MongoDB
|
13
|
+
* PostgreSQL
|
14
|
+
* RabbitMQ
|
6
15
|
|
7
16
|
## Installation
|
8
17
|
|
9
18
|
Add this line to your application's Gemfile:
|
10
19
|
|
11
20
|
```ruby
|
12
|
-
gem 'orchestration'
|
21
|
+
gem 'orchestration', '~> 0.2.0'
|
13
22
|
```
|
14
23
|
|
15
|
-
And then
|
24
|
+
And then build your bundle:
|
25
|
+
``` bash
|
26
|
+
$ bundle install
|
27
|
+
```
|
16
28
|
|
17
|
-
|
29
|
+
## Usage
|
18
30
|
|
19
|
-
|
31
|
+
### Generating configuration files
|
20
32
|
|
21
|
-
|
33
|
+
A _Rake_ task is provided to generate the following files:
|
22
34
|
|
23
|
-
|
35
|
+
* `Makefile` - provides easy access to all _Orchestration_ utilities.
|
36
|
+
* `.gitignore` - ensures any unwanted files created by _Orchestration_ do not clutter your project's version control system.
|
37
|
+
* `docker/Dockerfile` - a ready-to-use _Docker_ build script which should need minimal (if any) modification to build your _Rails_ project.
|
38
|
+
* `docker-compose.yml` - a custom-made set of services to allow you to run your application's dependencies locally.
|
39
|
+
* `.orchestration.yml` - _Orchestration_ internal configuration, e.g. _Docker_ username.
|
24
40
|
|
25
|
-
|
41
|
+
### Building and pushing your project as a _Docker_ image
|
26
42
|
|
27
|
-
|
43
|
+
#### Private Git repository authentication
|
28
44
|
|
29
|
-
|
45
|
+
If your project has any dependencies on private _Git_ repositories then you will need to create an authentication token. See the relevant documentation for your _Git_ host:
|
30
46
|
|
31
|
-
|
47
|
+
* [GitHub](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/)
|
48
|
+
* [Bitbucket](https://confluence.atlassian.com/bitbucket/app-passwords-828781300.html)
|
32
49
|
|
33
|
-
|
50
|
+
Create a file named `.env` in the same directory as your `docker-compose.yml` and add one or both of the following (note that _Bitbucket_ and _GitHub_ use a different format):
|
34
51
|
|
35
|
-
|
52
|
+
```bash
|
53
|
+
BUNDLE_BITBUCKET__ORG=<bitbucket-username>:<app-password>
|
54
|
+
BUNDLE_GITHUB__COM=x-oauth-basic:<auth-token>
|
55
|
+
```
|
36
56
|
|
37
|
-
|
57
|
+
#### Docker installation
|
58
|
+
_Docker_ must be installed on your system. See the [_Docker_ getting started guide](https://www.docker.com/get-started) for instructions.
|
59
|
+
|
60
|
+
#### DockerHub account
|
61
|
+
|
62
|
+
You will need an account with _Docker Hub_ (or your preferred _Docker_ image host) to push your images. Visit the [_Docker Hub_ webpage](https://hub.docker.com/) to sign up, then run the following command and enter your credentials when prompted to log in to your new account:
|
63
|
+
```bash
|
64
|
+
$ docker login
|
65
|
+
```
|
66
|
+
|
67
|
+
#### Using provided `Makefile`
|
68
|
+
|
69
|
+
To build and push your image run:
|
70
|
+
```bash
|
71
|
+
$ make docker
|
72
|
+
```
|
73
|
+
|
74
|
+
Or run the two steps separately:
|
75
|
+
```bash
|
76
|
+
$ make docker-build
|
77
|
+
$ make docker-push
|
78
|
+
```
|
79
|
+
|
80
|
+
### Starting and waiting for services when running your tests
|
81
|
+
|
82
|
+
To start services:
|
83
|
+
|
84
|
+
```bash
|
85
|
+
$ make start
|
86
|
+
```
|
87
|
+
|
88
|
+
This will launch any dependencies your project needs (e.g. _MySQL_, _MongoDB_, etc.).
|
89
|
+
|
90
|
+
To wait for all services to be ready:
|
91
|
+
```bash
|
92
|
+
$ make wait
|
93
|
+
```
|
94
|
+
|
95
|
+
It is recommended that you create a `test` command in your `Makefile` which will launch all dependencies and wait for them to be ready before running all tests. For example:
|
96
|
+
|
97
|
+
```Makefile
|
98
|
+
test: start wait
|
99
|
+
bundle exec rspec
|
100
|
+
yarn test app/javascript
|
101
|
+
bundle exec rubocop
|
102
|
+
yarn run eslint app/javascript
|
103
|
+
```
|
38
104
|
|
39
|
-
|
105
|
+
This is especially useful for continuous integration as it provides a uniform command (`make test`) that can be run by your CI tool without any extra setup.
|
data/Rakefile
CHANGED
data/TODO
ADDED
data/bin/rspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rspec' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("rspec-core", "rspec")
|
data/bin/rubocop
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rubocop' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("rubocop", "rubocop")
|
@@ -0,0 +1,16 @@
|
|
1
|
+
en:
|
2
|
+
orchestration:
|
3
|
+
unknown_scheme: "Unrecognised database adapter for URL scheme: %{scheme}"
|
4
|
+
attempt_limit: "Unable to reconnect after %{limit} attempts. Aborting."
|
5
|
+
database:
|
6
|
+
waiting: "Waiting for database: %{config}"
|
7
|
+
ready: "Database is ready."
|
8
|
+
missing_default: "database.yml must define a `default` section."
|
9
|
+
mongo:
|
10
|
+
waiting: "Waiting for Mongo: %{config}"
|
11
|
+
ready: "Mongo is ready."
|
12
|
+
rabbitmq:
|
13
|
+
waiting: "Waiting for RabbitMQ: %{config}"
|
14
|
+
ready: "RabbitMQ is ready."
|
15
|
+
docker:
|
16
|
+
username_request: "Enter your Docker registry username (used for tagging images)"
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orchestration
|
4
|
+
module DockerCompose
|
5
|
+
class DatabaseService
|
6
|
+
# We dictate which port all database services will run on in their
|
7
|
+
# container to simplify port mapping.
|
8
|
+
PORT = 3354
|
9
|
+
|
10
|
+
def initialize(config)
|
11
|
+
@config = config
|
12
|
+
end
|
13
|
+
|
14
|
+
def definition
|
15
|
+
return nil if @config.settings.nil?
|
16
|
+
|
17
|
+
adapter = @config.settings.fetch('adapter')
|
18
|
+
return nil if adapter == 'sqlite3'
|
19
|
+
|
20
|
+
port = @config.settings.fetch('port')
|
21
|
+
{
|
22
|
+
'image' => image_from_adapter(adapter),
|
23
|
+
'environment' => environment_from_adapter(adapter),
|
24
|
+
'ports' => ["#{port}:#{PORT}"]
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def image_from_adapter(adapter)
|
31
|
+
{
|
32
|
+
'postgresql' => 'library/postgres',
|
33
|
+
'mysql2' => 'library/mysql'
|
34
|
+
}.fetch(adapter)
|
35
|
+
end
|
36
|
+
|
37
|
+
def environment_from_adapter(adapter)
|
38
|
+
{
|
39
|
+
'postgresql' => {
|
40
|
+
'PGPORT' => PORT.to_s,
|
41
|
+
'POSTGRES_PASSWORD' => 'password'
|
42
|
+
},
|
43
|
+
'mysql2' => {
|
44
|
+
'MYSQL_ROOT_PASSWORD' => 'password',
|
45
|
+
'MYSQL_TCP_PORT' => PORT.to_s
|
46
|
+
}
|
47
|
+
}.fetch(adapter)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orchestration
|
4
|
+
module DockerCompose
|
5
|
+
class MongoService
|
6
|
+
def initialize(config)
|
7
|
+
@config = config
|
8
|
+
end
|
9
|
+
|
10
|
+
def definition
|
11
|
+
return nil if @config.settings.nil?
|
12
|
+
|
13
|
+
# REVIEW: If the host application defines multiple mongo hosts then we
|
14
|
+
# create one service instance and point them all at the same service.
|
15
|
+
# Instead we should probably create a separate service for each.
|
16
|
+
ports = @config.ports.map do |port|
|
17
|
+
"#{port}:#{Orchestration::Services::Mongo::PORT}"
|
18
|
+
end
|
19
|
+
|
20
|
+
{
|
21
|
+
'image' => 'library/mongo',
|
22
|
+
'ports' => ports
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orchestration
|
4
|
+
module DockerCompose
|
5
|
+
class RabbitMQService
|
6
|
+
def initialize(config)
|
7
|
+
@config = config
|
8
|
+
end
|
9
|
+
|
10
|
+
def definition
|
11
|
+
return nil if @config.settings.nil?
|
12
|
+
|
13
|
+
host_port = @config.settings.fetch('port', 5672)
|
14
|
+
container_port = Orchestration::Services::RabbitMQ::PORT
|
15
|
+
|
16
|
+
{
|
17
|
+
'image' => 'library/rabbitmq',
|
18
|
+
'ports' => ["#{host_port}:#{container_port}"]
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orchestration
|
4
|
+
module DockerCompose
|
5
|
+
class Services
|
6
|
+
def initialize(options = {})
|
7
|
+
@configurations = {
|
8
|
+
'database' => options.fetch(:database, nil),
|
9
|
+
'mongo' => options.fetch(:mongo, nil),
|
10
|
+
'rabbitmq' => options.fetch(:rabbitmq, nil)
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
def structure
|
15
|
+
{ 'version' => '3.7', 'services' => services }
|
16
|
+
end
|
17
|
+
|
18
|
+
def services
|
19
|
+
Hash[filtered_services]
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def filtered_services
|
25
|
+
services_enabled.compact.reject { |_name, definition| definition.nil? }
|
26
|
+
end
|
27
|
+
|
28
|
+
def services_available
|
29
|
+
[
|
30
|
+
{ name: 'database', class: DatabaseService },
|
31
|
+
{ name: 'mongo', class: MongoService },
|
32
|
+
{ name: 'rabbitmq', class: RabbitMQService }
|
33
|
+
]
|
34
|
+
end
|
35
|
+
|
36
|
+
def services_enabled
|
37
|
+
services_available.map do |service|
|
38
|
+
config = @configurations[service[:name]]
|
39
|
+
# REVIEW: This is mostly here for testing - we may not need it once
|
40
|
+
# everything's implemented.
|
41
|
+
next if config.nil?
|
42
|
+
|
43
|
+
[service[:name], service[:class].new(config).definition]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orchestration
|
4
|
+
module DockerCompose
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'orchestration/docker_compose/services'
|
9
|
+
require 'orchestration/docker_compose/database_service'
|
10
|
+
require 'orchestration/docker_compose/mongo_service'
|
11
|
+
require 'orchestration/docker_compose/rabbitmq_service'
|