dockmeister 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.travis.yml +7 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +21 -0
- data/README.md +74 -0
- data/bin/dockmeister +38 -0
- data/dockmeister.gemspec +27 -0
- data/lib/dockmeister.rb +7 -0
- data/lib/dockmeister/cli.rb +69 -0
- data/lib/dockmeister/composer.rb +15 -0
- data/lib/dockmeister/script_runner.rb +58 -0
- data/lib/dockmeister/service_config.rb +43 -0
- data/lib/dockmeister/version.rb +15 -0
- data/spec/fixtures/bar/scripts/post-a.sh +0 -0
- data/spec/fixtures/bar/scripts/post-b.rb +0 -0
- data/spec/fixtures/bar/scripts/pre-a.sh +0 -0
- data/spec/fixtures/bar/scripts/pre-b.rb +0 -0
- data/spec/fixtures/broken_service/scripts/post +2 -0
- data/spec/fixtures/broken_service/scripts/pre +2 -0
- data/spec/fixtures/foo/scripts/post +0 -0
- data/spec/fixtures/foo/scripts/pre +0 -0
- data/spec/lib/dockmeister/cli_spec.rb +128 -0
- data/spec/lib/dockmeister/composer_spec.rb +68 -0
- data/spec/lib/dockmeister/script_runner_spec.rb +118 -0
- data/spec/lib/dockmeister/service_config_spec.rb +58 -0
- data/spec/spec_helper.rb +3 -0
- metadata +158 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a5f3353434b0a73614217332ff4e96984d4dfb9d
|
4
|
+
data.tar.gz: e872b11f80d3861bef29260e7d981a463ad284cf
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bf70f4c43c8d822619feeecd0548f4d2225e218c3058140ef7d8069f8efd8d879b61ca4fc6ed70bd22385b1035758652bcbc5d67521dd69095dc4c6800dbc545
|
7
|
+
data.tar.gz: 6ae8d2f6f2c515ce8ca075fa7bc259fe9f98f58c3b0abc111d40081837b7a0174e0f558e175e2303e5d105b0a98a9c9520e5da4f0ecad7d086874b9c89e3a21d
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Lesson Nine GmbH
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Dockmeister
|
2
|
+
|
3
|
+
Orchestrates several `docker-compose`-based services into one.
|
4
|
+
|
5
|
+
Dockmeister will facilitate the integration of several `docker-compose`-based services by concatenating their `docker-compose.yml` configurations into one.
|
6
|
+
|
7
|
+
In addition, Dockmeister allows you to specify scripts that are executed before or after building a particular service, which can be used for steps such as seeding a database.
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
Create a `dockmeister.yml` file at the root level of where your services reside. This file will contain the names of all the services you wish to bootstrap:
|
12
|
+
|
13
|
+
```yaml
|
14
|
+
services:
|
15
|
+
- foo
|
16
|
+
- bar
|
17
|
+
- baz
|
18
|
+
```
|
19
|
+
|
20
|
+
A service is defined by a directory that contains a `docker-compose.yml` specifying its dependencies. Pre- and post-build scripts reside in the `scripts/` sub-directory.
|
21
|
+
|
22
|
+
```
|
23
|
+
foo/
|
24
|
+
docker-compose.yml
|
25
|
+
appserver/
|
26
|
+
Dockerfile
|
27
|
+
database/
|
28
|
+
Dockerfile
|
29
|
+
filesystem/
|
30
|
+
Dockerfile
|
31
|
+
scripts/
|
32
|
+
pre_do_something.sh
|
33
|
+
post_seed_the_database.rb
|
34
|
+
```
|
35
|
+
|
36
|
+
### Dockmeister commands
|
37
|
+
|
38
|
+
```bash
|
39
|
+
dockmeister [COMMAND]
|
40
|
+
```
|
41
|
+
|
42
|
+
#### compose
|
43
|
+
|
44
|
+
Prepares a composition of each services' `docker-compose.yml` file into a single `docker-compose.yml` file. All `build` and `volume` paths are adjusted to be relative to the root directory.
|
45
|
+
|
46
|
+
#### build
|
47
|
+
|
48
|
+
- Runs the pre-build scripts for each service
|
49
|
+
- Builds all docker containers using `docker-compose build`.
|
50
|
+
- Runs the post-build scripts for each service
|
51
|
+
|
52
|
+
Pre- and post-build scripts reside in the `scripts/` sub-directory.
|
53
|
+
The filenames of the scripts are required to have a `pre` or `post` prefix.
|
54
|
+
The scripts will be run from the service folder.
|
55
|
+
|
56
|
+
All extra arguments and flags are passed down to the `docker-compose build` command (ie. useful when building with `--no-cache`).
|
57
|
+
|
58
|
+
#### up
|
59
|
+
|
60
|
+
Starts the containers using `docker-compose up`
|
61
|
+
|
62
|
+
All extra arguments and flags are passed down to the `docker-compose up` command.
|
63
|
+
|
64
|
+
## Contributing
|
65
|
+
|
66
|
+
1. Fork it ( https://github.com/[my-github-username]/dockmeister/fork )
|
67
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
68
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
69
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
70
|
+
5. Create a new Pull Request
|
71
|
+
|
72
|
+
## License
|
73
|
+
|
74
|
+
Dockmeister is released under the [MIT License](http://www.opensource.org/licenses/MIT).
|
data/bin/dockmeister
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:.unshift(File.dirname("../lib"))
|
3
|
+
|
4
|
+
require "dockmeister"
|
5
|
+
|
6
|
+
COMMANDS = ["compose", "build", "up"]
|
7
|
+
|
8
|
+
command = ARGV.first
|
9
|
+
options = ARGV.slice(1..-1)
|
10
|
+
|
11
|
+
if COMMANDS.include?(command)
|
12
|
+
Dockmeister::Cli.new(".").public_send(command, options)
|
13
|
+
else
|
14
|
+
puts <<-eos
|
15
|
+
USAGE
|
16
|
+
dockmeister [COMMAND]
|
17
|
+
|
18
|
+
COMMANDS:
|
19
|
+
|
20
|
+
#### compose
|
21
|
+
|
22
|
+
Prepares a composition of each services' `docker-compose.yml` file into a single `docker-compose.yml` file. All `build` and `volume` paths are adjusted to be relative to the root directory.
|
23
|
+
|
24
|
+
#### build
|
25
|
+
|
26
|
+
- Runs the pre-build scripts for each service
|
27
|
+
- Builds all docker containers using `docker-compose build`.
|
28
|
+
- Runs the post-build scripts for each service
|
29
|
+
|
30
|
+
Pre- and post-build scripts reside in the `scripts/` sub-directory.
|
31
|
+
The filenames of the scripts are required to have a `pre` or `post` prefix.
|
32
|
+
The scripts will be run from the service folder.
|
33
|
+
|
34
|
+
#### up
|
35
|
+
|
36
|
+
Starts the containers using `docker-compose up`
|
37
|
+
eos
|
38
|
+
end
|
data/dockmeister.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'dockmeister/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "dockmeister"
|
8
|
+
spec.version = Dockmeister::VERSION
|
9
|
+
spec.platform = Gem::Platform::RUBY
|
10
|
+
spec.license = "MIT"
|
11
|
+
spec.authors = ["Bruno Abrantes", "Laurens Nienhaus", "Henning Staib"]
|
12
|
+
spec.email = ["babrantes@babbel.com", "hstaib@babbel.com"]
|
13
|
+
spec.description = "Orchestrates several Docker-based applications into one."
|
14
|
+
spec.summary = "Orchestrates several Docker-based applications into one."
|
15
|
+
spec.homepage = "https://github.com/babbel/dockmeister"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0")
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
spec.add_development_dependency "rspec", "~> 3.2.0"
|
25
|
+
spec.add_development_dependency 'mute', '~> 1.1.0'
|
26
|
+
spec.add_development_dependency "pry-byebug"
|
27
|
+
end
|
data/lib/dockmeister.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
module Dockmeister
|
2
|
+
|
3
|
+
class Cli
|
4
|
+
|
5
|
+
DOCKMEISTER_CONFIGURATION_FILE = "dockmeister.yml"
|
6
|
+
DOCKER_COMPOSE_FILENAME = "docker-compose.yml"
|
7
|
+
|
8
|
+
def initialize(base_path)
|
9
|
+
@base_path = base_path
|
10
|
+
@services = load_config["services"]
|
11
|
+
end
|
12
|
+
|
13
|
+
def compose(*options)
|
14
|
+
composed = Dockmeister::Composer.new(@base_path, @services).compose
|
15
|
+
File.open(compose_file_path, "w") { |f| f.write(composed.to_yaml) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def build(*options)
|
19
|
+
compose
|
20
|
+
|
21
|
+
Dockmeister::ScriptRunner.new(@base_path, @services).pre_build!
|
22
|
+
|
23
|
+
unless Kernel.system(command_with_options("build", options))
|
24
|
+
puts "Failed to build the Docker containers."
|
25
|
+
exit 1
|
26
|
+
end
|
27
|
+
|
28
|
+
Dockmeister::ScriptRunner.new(@base_path, @services).post_build!
|
29
|
+
end
|
30
|
+
|
31
|
+
def up(*options)
|
32
|
+
Kernel.exec(command_with_options("up", options))
|
33
|
+
end
|
34
|
+
|
35
|
+
def compose_command
|
36
|
+
"docker-compose --file #{compose_file_path}"
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def compose_file_path
|
42
|
+
File.join(@base_path, DOCKER_COMPOSE_FILENAME)
|
43
|
+
end
|
44
|
+
|
45
|
+
def command_with_options(command, options)
|
46
|
+
"#{compose_command} #{command} #{options.join(" ")}".strip
|
47
|
+
end
|
48
|
+
|
49
|
+
def load_config
|
50
|
+
file = File.join(@base_path, DOCKMEISTER_CONFIGURATION_FILE)
|
51
|
+
|
52
|
+
unless File.exists?(file)
|
53
|
+
puts "Missing dockmeister.yml configuration file"
|
54
|
+
exit 1
|
55
|
+
end
|
56
|
+
|
57
|
+
config = ::YAML.load_file(file)
|
58
|
+
|
59
|
+
unless config
|
60
|
+
puts "Invalid dockmeister.yml configuration file"
|
61
|
+
exit 1
|
62
|
+
end
|
63
|
+
|
64
|
+
config
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Dockmeister
|
2
|
+
|
3
|
+
class Composer
|
4
|
+
|
5
|
+
def initialize(base_path, services)
|
6
|
+
@service_configs = services.map { |service| ServiceConfig.new(base_path, service).config }
|
7
|
+
end
|
8
|
+
|
9
|
+
def compose
|
10
|
+
@service_configs.inject({}) { |memo, config| memo.merge!(config) }
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Dockmeister
|
2
|
+
|
3
|
+
class ScriptRunner
|
4
|
+
|
5
|
+
DOCKMEISTER_COMPOSE_FILE = "docker-compose.yml"
|
6
|
+
|
7
|
+
def initialize(base_path, services)
|
8
|
+
@base_path = File.expand_path(base_path)
|
9
|
+
@services = services
|
10
|
+
end
|
11
|
+
|
12
|
+
def run_script(script, working_directory = ".")
|
13
|
+
puts "Running #{script}"
|
14
|
+
success = Kernel.system(script_env_vars, script, chdir: working_directory)
|
15
|
+
|
16
|
+
unless success
|
17
|
+
STDERR.puts <<-eos
|
18
|
+
|
19
|
+
A dockmeister init script failed.
|
20
|
+
eos
|
21
|
+
exit(1)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def pre_build!
|
26
|
+
run_with_prefix("pre")
|
27
|
+
end
|
28
|
+
|
29
|
+
def post_build!
|
30
|
+
run_with_prefix("post")
|
31
|
+
end
|
32
|
+
|
33
|
+
def script_env_vars
|
34
|
+
{
|
35
|
+
"DOCKMEISTER_COMPOSE_FILE" => dockmeister_compose_file_path
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def run_with_prefix(prefix)
|
42
|
+
pattern = "#{prefix}*"
|
43
|
+
|
44
|
+
@services.each do |service_name|
|
45
|
+
service_directory = File.join(@base_path, service_name)
|
46
|
+
Dir.glob(File.join(service_directory, "scripts", pattern)).each do |script|
|
47
|
+
run_script(File.expand_path(script), service_directory)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def dockmeister_compose_file_path
|
53
|
+
File.join(@base_path, DOCKMEISTER_COMPOSE_FILE)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Dockmeister
|
2
|
+
|
3
|
+
class ServiceConfig
|
4
|
+
|
5
|
+
DOCKER_COMPOSE_FILENAME = "docker-compose.yml"
|
6
|
+
|
7
|
+
attr_reader :config
|
8
|
+
|
9
|
+
def initialize(base_path, service)
|
10
|
+
@base_path = base_path
|
11
|
+
@service = service
|
12
|
+
@config = convert(load_file)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def load_file
|
18
|
+
YAML.load_file(File.join(@base_path, @service, DOCKER_COMPOSE_FILENAME))
|
19
|
+
end
|
20
|
+
|
21
|
+
def convert(config)
|
22
|
+
config.values.each do |value|
|
23
|
+
if value["build"]
|
24
|
+
value["build"] = adjust_relative_path(@service, value["build"])
|
25
|
+
end
|
26
|
+
|
27
|
+
if value["volumes"]
|
28
|
+
value["volumes"] = value["volumes"].map do |volume|
|
29
|
+
adjust_relative_path(@service, volume)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
config
|
35
|
+
end
|
36
|
+
|
37
|
+
def adjust_relative_path(service, path)
|
38
|
+
path.sub(/^\.\//, "./#{service}/")
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Dockmeister::Cli do
|
4
|
+
|
5
|
+
let(:base_path) { File.join(".", "spec", "fixtures") }
|
6
|
+
let(:cli) { Dockmeister::Cli.new(base_path) }
|
7
|
+
|
8
|
+
before :each do
|
9
|
+
allow_any_instance_of(Dockmeister::Cli).to receive(:load_config) { { services: [] } }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#compose" do
|
13
|
+
|
14
|
+
subject { cli.compose(nil) }
|
15
|
+
|
16
|
+
let(:file_path) { File.join(base_path, "docker-compose.yml") }
|
17
|
+
let(:composer_double) { double("Dockmeister::Composer") }
|
18
|
+
let(:composition) { { foo: "bar" } }
|
19
|
+
|
20
|
+
before :each do
|
21
|
+
allow(Dockmeister::Composer).to receive(:new) { composer_double }
|
22
|
+
allow(composer_double).to receive(:compose) { composition }
|
23
|
+
end
|
24
|
+
|
25
|
+
after :each do
|
26
|
+
File.delete(file_path)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'writes a "docker-compose.yml" file with the yaml version of the return from Dockmeister::Composer#compose' do
|
30
|
+
subject
|
31
|
+
expect(YAML.load_file(file_path)).to eq(composition)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#build" do
|
37
|
+
|
38
|
+
subject { cli.build(options) }
|
39
|
+
|
40
|
+
let(:script_runner) { double("Dockmeister::ScriptRunner") }
|
41
|
+
let(:options) { [] }
|
42
|
+
|
43
|
+
before :each do
|
44
|
+
allow(Dockmeister::ScriptRunner).to receive(:new) { script_runner }
|
45
|
+
allow(script_runner).to receive(:pre_build!)
|
46
|
+
allow(script_runner).to receive(:post_build!)
|
47
|
+
allow(cli).to receive(:compose)
|
48
|
+
allow(cli).to receive(:load_config) { { services: [] } }
|
49
|
+
allow(Kernel).to receive(:system) { true }
|
50
|
+
end
|
51
|
+
|
52
|
+
it "runs #compose" do
|
53
|
+
expect(cli).to receive(:compose)
|
54
|
+
subject
|
55
|
+
end
|
56
|
+
|
57
|
+
context "when options are passed" do
|
58
|
+
|
59
|
+
let(:options) { ["--no-cache", "--some-other-flag"] }
|
60
|
+
|
61
|
+
it 'runs "docker-compose build" with options' do
|
62
|
+
command = "#{cli.compose_command} build #{options.join(" ")}"
|
63
|
+
expect(Kernel).to receive(:system).with(command) { true }
|
64
|
+
subject
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
context "when options are nil" do
|
70
|
+
|
71
|
+
let(:options) { nil }
|
72
|
+
|
73
|
+
it 'runs "docker-compose build"' do
|
74
|
+
command = "#{cli.compose_command} build"
|
75
|
+
expect(Kernel).to receive(:system).with(command) { true }
|
76
|
+
subject
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "#up" do
|
84
|
+
|
85
|
+
subject { cli.up(options) }
|
86
|
+
|
87
|
+
before :each do
|
88
|
+
allow(Kernel).to receive(:exec) { true }
|
89
|
+
end
|
90
|
+
|
91
|
+
context "when options are passed" do
|
92
|
+
|
93
|
+
let(:options) { ["--no-cache", "--some-other-flag"] }
|
94
|
+
|
95
|
+
it 'runs "docker-compose up" with options' do
|
96
|
+
command = "#{cli.compose_command} up #{options.join(" ")}"
|
97
|
+
expect(Kernel).to receive(:exec).with(command) { true }
|
98
|
+
subject
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
context "when options are nil" do
|
104
|
+
|
105
|
+
let(:options) { nil }
|
106
|
+
|
107
|
+
it 'runs "docker-compose up"' do
|
108
|
+
command = "#{cli.compose_command} up"
|
109
|
+
expect(Kernel).to receive(:exec).with(command) { true }
|
110
|
+
subject
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
describe "#compose_command" do
|
118
|
+
|
119
|
+
subject { cli.compose_command }
|
120
|
+
|
121
|
+
let(:compose_file_path) { File.join(base_path, Dockmeister::Cli::DOCKER_COMPOSE_FILENAME) }
|
122
|
+
let(:command) { "docker-compose --file #{compose_file_path}" }
|
123
|
+
|
124
|
+
it { is_expected.to eq(command) }
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Dockmeister::Composer do
|
4
|
+
|
5
|
+
describe "#compose" do
|
6
|
+
|
7
|
+
subject { Dockmeister::Composer.new(base_path, services).compose }
|
8
|
+
|
9
|
+
let(:base_path) { "." }
|
10
|
+
|
11
|
+
let(:foo_configuration) do
|
12
|
+
{
|
13
|
+
"fooservice" => {
|
14
|
+
"build" => "./service/",
|
15
|
+
"ports" => [
|
16
|
+
"8080"
|
17
|
+
],
|
18
|
+
"volumes" => [
|
19
|
+
"./service/foo:/root/worker"
|
20
|
+
]
|
21
|
+
},
|
22
|
+
"fooredis" => {
|
23
|
+
"build" => "./redis/",
|
24
|
+
"ports" => [
|
25
|
+
"6379:6379"
|
26
|
+
]
|
27
|
+
}
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
let(:bar_configuration) do
|
32
|
+
{
|
33
|
+
"barservice" => {
|
34
|
+
"build" => "./service/",
|
35
|
+
"ports" => [
|
36
|
+
"8080"
|
37
|
+
],
|
38
|
+
"volumes" => [
|
39
|
+
"./service/bar:/root/worker"
|
40
|
+
]
|
41
|
+
},
|
42
|
+
"barredis" => {
|
43
|
+
"image" => "redis",
|
44
|
+
"ports" => [
|
45
|
+
"6379:6379"
|
46
|
+
]
|
47
|
+
}
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
let(:services) { ["foo", "bar"] }
|
52
|
+
|
53
|
+
before :each do
|
54
|
+
allow(Dockmeister::ServiceConfig).to receive(:new).with(base_path, "foo") {
|
55
|
+
double("Dockmeister::ServiceConfig", config: foo_configuration)
|
56
|
+
}
|
57
|
+
allow(Dockmeister::ServiceConfig).to receive(:new).with(base_path, "bar") {
|
58
|
+
double("Dockmeister::ServiceConfig", config: bar_configuration)
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
it "concatenates services\' compose configurations" do
|
63
|
+
expect(subject.keys).to eq(foo_configuration.keys + bar_configuration.keys)
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Dockmeister::ScriptRunner do
|
4
|
+
|
5
|
+
let(:script_runner) { Dockmeister::ScriptRunner.new(base_path, services) }
|
6
|
+
let(:base_path) { File.join(".", "spec", "fixtures") }
|
7
|
+
let(:services) { ["foo", "bar"] }
|
8
|
+
|
9
|
+
describe "#pre_build!" do
|
10
|
+
|
11
|
+
subject { script_runner.pre_build! }
|
12
|
+
|
13
|
+
let(:pre_build_scripts) do
|
14
|
+
{
|
15
|
+
"foo" => [ "pre" ],
|
16
|
+
"bar" => [ "pre-a.sh", "pre-b.rb" ]
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'runs all scripts starting with "pre" ordered by filename' do
|
21
|
+
pre_build_scripts.each do |service_name, script_names|
|
22
|
+
script_names.each do |script_name|
|
23
|
+
script_path = File.expand_path(File.join(base_path, service_name, "scripts", script_name))
|
24
|
+
working_directory = File.expand_path(File.join(base_path, service_name))
|
25
|
+
|
26
|
+
expect(script_runner).to receive(:run_script).once.ordered.with(script_path, working_directory)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
subject
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#post_build!" do
|
35
|
+
|
36
|
+
subject { script_runner.post_build! }
|
37
|
+
|
38
|
+
let(:post_build_scripts) do
|
39
|
+
{
|
40
|
+
"foo" => [ "post" ],
|
41
|
+
"bar" => [ "post-a.sh", "post-b.rb" ]
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'runs all scripts starting with "post" ordered by filename' do
|
46
|
+
post_build_scripts.each do |service_name, script_names|
|
47
|
+
script_names.each do |script_name|
|
48
|
+
script_path = File.expand_path(File.join(base_path, service_name, "scripts", script_name))
|
49
|
+
working_directory = File.expand_path(File.join(base_path, service_name))
|
50
|
+
|
51
|
+
expect(script_runner).to receive(:run_script).once.ordered.with(script_path, working_directory)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
subject
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#run_script" do
|
60
|
+
|
61
|
+
subject { script_runner.run_script(File.join(base_path, service, script)) }
|
62
|
+
|
63
|
+
before :each do
|
64
|
+
allow(STDERR).to receive(:puts)
|
65
|
+
end
|
66
|
+
|
67
|
+
context "for a successful script" do
|
68
|
+
|
69
|
+
let(:service) { "foo" }
|
70
|
+
let(:script) { "./scripts/post" }
|
71
|
+
|
72
|
+
it "does not exit" do
|
73
|
+
Mute::IO.capture_stdout do
|
74
|
+
expect { subject }.to_not raise_error
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
context "for a broken script" do
|
81
|
+
|
82
|
+
let(:service) { "broken_service" }
|
83
|
+
let(:script) { "./scripts/post" }
|
84
|
+
|
85
|
+
it "exits" do
|
86
|
+
Mute::IO.capture_stdout do
|
87
|
+
expect { subject }.to raise_error(SystemExit)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
context "environment variables" do
|
94
|
+
|
95
|
+
let(:service) { "foo" }
|
96
|
+
let(:script) { "./scripts/post" }
|
97
|
+
let(:env_vars) do
|
98
|
+
{
|
99
|
+
"DOCKMEISTER_COMPOSE_FILE" => "docker-compose.yml"
|
100
|
+
}
|
101
|
+
end
|
102
|
+
|
103
|
+
before :each do
|
104
|
+
allow(script_runner).to receive(:script_env_vars) { env_vars }
|
105
|
+
end
|
106
|
+
|
107
|
+
it "populates the DOCKER_COMPOSE_FILE env var" do
|
108
|
+
expect(Kernel).to receive(:system).with(env_vars, anything, anything) { true }
|
109
|
+
Mute::IO.capture_stdout do
|
110
|
+
subject
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Dockmeister::ServiceConfig do
|
4
|
+
|
5
|
+
describe "#config" do
|
6
|
+
|
7
|
+
subject { Dockmeister::ServiceConfig.new(base_path, service).config }
|
8
|
+
|
9
|
+
let(:base_path) { "." }
|
10
|
+
let(:service) { "foo" }
|
11
|
+
let(:foo_configuration) do
|
12
|
+
{
|
13
|
+
"fooservice" => {
|
14
|
+
"build" => "./service/",
|
15
|
+
"ports" => [
|
16
|
+
"8080"
|
17
|
+
],
|
18
|
+
"volumes" => [
|
19
|
+
"./service/foo:/root/worker",
|
20
|
+
"~/service/foo:/root/worker"
|
21
|
+
]
|
22
|
+
},
|
23
|
+
"fooredis" => {
|
24
|
+
"build" => "./redis/",
|
25
|
+
"ports" => [
|
26
|
+
"6379:6379"
|
27
|
+
]
|
28
|
+
}
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
before :each do
|
33
|
+
allow(YAML).to receive(:load_file).with("#{base_path}/#{service}/docker-compose.yml") { foo_configuration }
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'replaces path references for "build" keys' do
|
37
|
+
build_values = subject.map { |service, config| config["build"] }.compact
|
38
|
+
|
39
|
+
expect(build_values).to eq(["./foo/service/", "./foo/redis/"])
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'replaces path references for "volumes" keys' do
|
43
|
+
volumes_values = subject.map { |service, config| config["volumes"] }.compact
|
44
|
+
|
45
|
+
expect(volumes_values).to eq([["./foo/service/foo:/root/worker", "~/service/foo:/root/worker"]])
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'does not replace paths that do not start with "."' do
|
49
|
+
ignored_volumes = subject.flat_map { |service, config| config["volumes"] }
|
50
|
+
.compact
|
51
|
+
.select { |volume| volume.chars.first != "." }
|
52
|
+
|
53
|
+
expect(ignored_volumes.size).to eq(1)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dockmeister
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bruno Abrantes
|
8
|
+
- Laurens Nienhaus
|
9
|
+
- Henning Staib
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2015-07-29 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: bundler
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - "~>"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.7'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - "~>"
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '1.7'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: rake
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - "~>"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '10.0'
|
36
|
+
type: :development
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '10.0'
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: rspec
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 3.2.0
|
50
|
+
type: :development
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - "~>"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 3.2.0
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: mute
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - "~>"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 1.1.0
|
64
|
+
type: :development
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - "~>"
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 1.1.0
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: pry-byebug
|
73
|
+
requirement: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
type: :development
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
description: Orchestrates several Docker-based applications into one.
|
86
|
+
email:
|
87
|
+
- babrantes@babbel.com
|
88
|
+
- hstaib@babbel.com
|
89
|
+
executables:
|
90
|
+
- dockmeister
|
91
|
+
extensions: []
|
92
|
+
extra_rdoc_files: []
|
93
|
+
files:
|
94
|
+
- ".gitignore"
|
95
|
+
- ".travis.yml"
|
96
|
+
- Gemfile
|
97
|
+
- MIT-LICENSE
|
98
|
+
- README.md
|
99
|
+
- bin/dockmeister
|
100
|
+
- dockmeister.gemspec
|
101
|
+
- lib/dockmeister.rb
|
102
|
+
- lib/dockmeister/cli.rb
|
103
|
+
- lib/dockmeister/composer.rb
|
104
|
+
- lib/dockmeister/script_runner.rb
|
105
|
+
- lib/dockmeister/service_config.rb
|
106
|
+
- lib/dockmeister/version.rb
|
107
|
+
- spec/fixtures/bar/scripts/post-a.sh
|
108
|
+
- spec/fixtures/bar/scripts/post-b.rb
|
109
|
+
- spec/fixtures/bar/scripts/pre-a.sh
|
110
|
+
- spec/fixtures/bar/scripts/pre-b.rb
|
111
|
+
- spec/fixtures/broken_service/scripts/post
|
112
|
+
- spec/fixtures/broken_service/scripts/pre
|
113
|
+
- spec/fixtures/foo/scripts/post
|
114
|
+
- spec/fixtures/foo/scripts/pre
|
115
|
+
- spec/lib/dockmeister/cli_spec.rb
|
116
|
+
- spec/lib/dockmeister/composer_spec.rb
|
117
|
+
- spec/lib/dockmeister/script_runner_spec.rb
|
118
|
+
- spec/lib/dockmeister/service_config_spec.rb
|
119
|
+
- spec/spec_helper.rb
|
120
|
+
homepage: https://github.com/babbel/dockmeister
|
121
|
+
licenses:
|
122
|
+
- MIT
|
123
|
+
metadata: {}
|
124
|
+
post_install_message:
|
125
|
+
rdoc_options: []
|
126
|
+
require_paths:
|
127
|
+
- lib
|
128
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
requirements: []
|
139
|
+
rubyforge_project:
|
140
|
+
rubygems_version: 2.4.5
|
141
|
+
signing_key:
|
142
|
+
specification_version: 4
|
143
|
+
summary: Orchestrates several Docker-based applications into one.
|
144
|
+
test_files:
|
145
|
+
- spec/fixtures/bar/scripts/post-a.sh
|
146
|
+
- spec/fixtures/bar/scripts/post-b.rb
|
147
|
+
- spec/fixtures/bar/scripts/pre-a.sh
|
148
|
+
- spec/fixtures/bar/scripts/pre-b.rb
|
149
|
+
- spec/fixtures/broken_service/scripts/post
|
150
|
+
- spec/fixtures/broken_service/scripts/pre
|
151
|
+
- spec/fixtures/foo/scripts/post
|
152
|
+
- spec/fixtures/foo/scripts/pre
|
153
|
+
- spec/lib/dockmeister/cli_spec.rb
|
154
|
+
- spec/lib/dockmeister/composer_spec.rb
|
155
|
+
- spec/lib/dockmeister/script_runner_spec.rb
|
156
|
+
- spec/lib/dockmeister/service_config_spec.rb
|
157
|
+
- spec/spec_helper.rb
|
158
|
+
has_rdoc:
|