bigrig 0.0.0 → 0.0.7
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/.gitignore +1 -0
- data/.rspec +3 -0
- data/.rubocop.yml +20 -0
- data/.travis.yml +3 -0
- data/CHANGELOG.md +19 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +84 -0
- data/LICENSE +28 -0
- data/README.md +191 -0
- data/Rakefile +10 -0
- data/bigrig.gemspec +29 -0
- data/bin/bigrig +113 -0
- data/lib/bigrig/actions/destroy_action.rb +21 -0
- data/lib/bigrig/actions/dev_action.rb +19 -0
- data/lib/bigrig/actions/log_action.rb +45 -0
- data/lib/bigrig/actions/run_action.rb +14 -0
- data/lib/bigrig/actions/ship_action.rb +51 -0
- data/lib/bigrig/actions.rb +5 -0
- data/lib/bigrig/dependency_graph.rb +21 -0
- data/lib/bigrig/descriptor.rb +43 -0
- data/lib/bigrig/docker_adapter.rb +129 -0
- data/lib/bigrig/models/application.rb +22 -0
- data/lib/bigrig/models/base_model.rb +7 -0
- data/lib/bigrig/models/container.rb +40 -0
- data/lib/bigrig/models.rb +3 -0
- data/lib/bigrig/output_parser.rb +52 -0
- data/lib/bigrig/runner.rb +94 -0
- data/lib/bigrig/version.rb +3 -0
- data/lib/bigrig.rb +8 -0
- data/spec/bigrig/actions/destroy_action_spec.rb +55 -0
- data/spec/bigrig/actions/dev_action_spec.rb +17 -0
- data/spec/bigrig/actions/log_action_spec.rb +33 -0
- data/spec/bigrig/actions/run_action_spec.rb +270 -0
- data/spec/bigrig/actions/ship_action_spec.rb +82 -0
- data/spec/bigrig/dependency_graph_spec.rb +19 -0
- data/spec/bigrig/descriptor_spec.rb +56 -0
- data/spec/bigrig/docker_adapter_spec.rb +409 -0
- data/spec/bigrig/models/application_spec.rb +32 -0
- data/spec/bigrig/models/container_spec.rb +115 -0
- data/spec/bigrig/output_parser_spec.rb +71 -0
- data/spec/bigrig_spec.rb +249 -0
- data/spec/data/addscontainer.json +24 -0
- data/spec/data/build/Dockerfile +2 -0
- data/spec/data/build/test +0 -0
- data/spec/data/dev.json +26 -0
- data/spec/data/duplicate.json +13 -0
- data/spec/data/env.json +12 -0
- data/spec/data/hosts_ip.json +12 -0
- data/spec/data/hosts_name.json +11 -0
- data/spec/data/links.json +13 -0
- data/spec/data/log.json +8 -0
- data/spec/data/multiple.json +13 -0
- data/spec/data/path.json +5 -0
- data/spec/data/ports.json +9 -0
- data/spec/data/profiles.json +24 -0
- data/spec/data/ship.json +5 -0
- data/spec/data/single.json +8 -0
- data/spec/data/tagandpath.json +24 -0
- data/spec/data/tiny-image.tar +0 -0
- data/spec/data/volumes.json +13 -0
- data/spec/spec_helper.rb +104 -0
- data/spec/support/bigrig_vcr +8 -0
- data/spec/support/vcr.rb +15 -0
- data/spec/vcr/Bigrig_DestroyAction/_perform/given_json_with_a_single_container/and_the_container_has_exited/should_remove_the_container.yml +392 -0
- data/spec/vcr/Bigrig_DestroyAction/_perform/given_json_with_a_single_container/and_the_container_is_running/kills_and_removes_the_container.yml +418 -0
- data/spec/vcr/Bigrig_DockerAdapter/_build/builds_the_given_directory.yml +63 -0
- data/spec/vcr/Bigrig_DockerAdapter/_build/passes_build_input_to_a_block.yml +35 -0
- data/spec/vcr/Bigrig_DockerAdapter/_container_exists_/when_the_container_does_not_exist/is_false.yml +115 -0
- data/spec/vcr/Bigrig_DockerAdapter/_container_exists_/when_the_container_exists/is_true.yml +82 -0
- data/spec/vcr/Bigrig_DockerAdapter/_image_id_by_tag/when_the_image_does_not_exist/raise_a_ImageNotFoundError.yml +172 -0
- data/spec/vcr/Bigrig_DockerAdapter/_image_id_by_tag/when_the_image_exists/returns_the_image_id.yml +148 -0
- data/spec/vcr/Bigrig_DockerAdapter/_kill/given_the_container_does_not_exist/should_raise_an_error.yml +115 -0
- data/spec/vcr/Bigrig_DockerAdapter/_kill/given_the_container_is_running/should_kill_the_container.yml +200 -0
- data/spec/vcr/Bigrig_DockerAdapter/_logs/streams_logs_to_a_block.yml +163 -0
- data/spec/vcr/Bigrig_DockerAdapter/_pull/given_a_block_to_capture_output/should_capture_output.yml +64 -0
- data/spec/vcr/Bigrig_DockerAdapter/_pull/given_the_repo_does_not_exist/raises_a_RepoNotFoundError.yml +30 -0
- data/spec/vcr/Bigrig_DockerAdapter/_pull/given_the_repo_exists/returns_the_image_id.yml +92 -0
- data/spec/vcr/Bigrig_DockerAdapter/_push/given_credentials/will_pass_login_and_password.yml +254 -0
- data/spec/vcr/Bigrig_DockerAdapter/_push/should_push_the_image.yml +482 -0
- data/spec/vcr/Bigrig_DockerAdapter/_remove_container/when_the_container_does_not_exist/raises_a_ContainerNotFoundError.yml +227 -0
- data/spec/vcr/Bigrig_DockerAdapter/_remove_container/when_the_container_exists/should_remove_the_container.yml +222 -0
- data/spec/vcr/Bigrig_DockerAdapter/_remove_container/when_the_container_is_running/raises_a_ContainerRunningError.yml +80 -0
- data/spec/vcr/Bigrig_DockerAdapter/_remove_image/when_the_image_doesnt_exist/raises_an_error.yml +115 -0
- data/spec/vcr/Bigrig_DockerAdapter/_remove_image/when_the_image_exists/removes_the_image.yml +199 -0
- data/spec/vcr/Bigrig_DockerAdapter/_run/given_an_image_id_that_exists/and_a_name/starts_the_container_with_the_right_name.yml +204 -0
- data/spec/vcr/Bigrig_DockerAdapter/_run/given_an_image_id_that_exists/and_a_name_and_env_variables/starts_the_container_with_env_set.yml +204 -0
- data/spec/vcr/Bigrig_DockerAdapter/_run/given_an_image_id_that_exists/and_a_name_and_ports/starts_the_container_with_ports_exposed.yml +230 -0
- data/spec/vcr/Bigrig_DockerAdapter/_running_/when_the_container_does_not_exist/returns_false.yml +115 -0
- data/spec/vcr/Bigrig_DockerAdapter/_running_/when_the_container_is_not_running/returns_false.yml +82 -0
- data/spec/vcr/Bigrig_DockerAdapter/_running_/when_the_container_is_running/returns_true.yml +103 -0
- data/spec/vcr/Bigrig_DockerAdapter/_tag/should_tag_the_image.yml +290 -0
- data/spec/vcr/Bigrig_LogAction/_perform/follows_the_log.yml +163 -0
- data/spec/vcr/Bigrig_RunAction/_perform/given_a_file_with_a_path/builds_the_image_before_starting_it.yml +310 -0
- data/spec/vcr/Bigrig_RunAction/_perform/given_a_file_with_hosts_by_ip/should_pass_hosts_to_container.yml +430 -0
- data/spec/vcr/Bigrig_RunAction/_perform/given_a_file_with_hosts_by_name/should_lookup_ips_for_hosts_with_a_hostname.yml +430 -0
- data/spec/vcr/Bigrig_RunAction/_perform/given_a_file_with_links/should_pass_links_to_the_right_container.yml +805 -0
- data/spec/vcr/Bigrig_RunAction/_perform/given_a_file_with_multiple_containers/launches_both_containers_in_parallel.yml +731 -0
- data/spec/vcr/Bigrig_RunAction/_perform/given_a_file_with_multiple_containers/spins_up_multiple_containers.yml +805 -0
- data/spec/vcr/Bigrig_RunAction/_perform/given_a_file_with_one_container/should_spin_up_a_single_container.yml +404 -0
- data/spec/vcr/Bigrig_RunAction/_perform/given_a_file_with_one_container/when_a_dead_container_exists/should_remove_existing_containers.yml +329 -0
- data/spec/vcr/Bigrig_RunAction/_perform/given_a_file_with_volumes_from/should_pass_volumes_from_to_the_right_container.yml +805 -0
- data/spec/vcr/Bigrig_RunAction/_perform/given_a_file_with_volumes_from/starts_the_dependant_container_last.yml +731 -0
- data/spec/vcr/Bigrig_RunAction/_perform/when_activating_profiles_that_do_not_exist/ignores_the_missing_profile.yml +409 -0
- data/spec/vcr/Bigrig_RunAction/_perform/with_a_file_with_active_profiles/uses_the_overridden_image.yml +432 -0
- data/spec/vcr/bigrig/destroy/spec/data/single_json/kills_the_container.yml +166 -0
- data/spec/vcr/bigrig/dev/spec/data/dev_json/activates_the_dev_profile.yml +37 -0
- data/spec/vcr/bigrig/dev/spec/data/dev_json/destroys_containers_on_exit.yml +227 -0
- data/spec/vcr/bigrig/dev/spec/data/dev_json/starts_the_containers.yml +107 -0
- data/spec/vcr/bigrig/logs/spec/data/log_json/tails_the_logs.yml +163 -0
- data/spec/vcr/bigrig/run/spec/data/profiles_json_-p_qa/leaves_existing_env_values_alone.yml +110 -0
- data/spec/vcr/bigrig/run/spec/data/profiles_json_-p_qa/overrides_the_env.yml +110 -0
- data/spec/vcr/bigrig/run/spec/data/profiles_json_-p_qa/overrides_the_tag.yml +103 -0
- data/spec/vcr/bigrig/run/spec/data/single_json/sends_the_name_of_the_container_to_stdout.yml +75 -0
- data/spec/vcr/bigrig/run/spec/data/single_json/starts_the_container.yml +101 -0
- data/spec/vcr/bigrig/ship/spec/data/ship_json/with_a_version/-c/cleans_the_image_when_its_done.yml +212 -0
- data/spec/vcr/bigrig/ship/spec/data/ship_json/with_a_version/builds_and_pushes_the_image.yml +128 -0
- data/spec/vcr/bigrig_bin_bigrig_destroy_spec/data/single_json_kills_the_container.yml +179 -0
- data/spec/vcr/bigrig_bin_bigrig_dev_spec/data/dev_json_activates_the_dev_profile.yml +1068 -0
- data/spec/vcr/bigrig_bin_bigrig_dev_spec/data/dev_json_destroys_containers_on_exit.yml +1070 -0
- data/spec/vcr/bigrig_bin_bigrig_dev_spec/data/dev_json_starts_the_containers.yml +1068 -0
- data/spec/vcr/bigrig_bin_bigrig_dev_spec/data/dev_json_tails_the_logs.yml +1075 -0
- data/spec/vcr/bigrig_bin_bigrig_logs_spec/data/log_json_tails_the_logs.yml +69 -0
- data/spec/vcr/bigrig_bin_bigrig_run_spec/data/profiles_json_-p_qa_leaves_existing_env_values_alone.yml +306 -0
- data/spec/vcr/bigrig_bin_bigrig_run_spec/data/profiles_json_-p_qa_overrides_the_env.yml +306 -0
- data/spec/vcr/bigrig_bin_bigrig_run_spec/data/profiles_json_-p_qa_overrides_the_tag.yml +306 -0
- data/spec/vcr/bigrig_bin_bigrig_run_spec/data/single_json_sends_the_name_of_the_container_to_stdout.yml +306 -0
- data/spec/vcr/bigrig_bin_bigrig_run_spec/data/single_json_starts_the_container.yml +306 -0
- data/spec/vcr/bigrig_bin_bigrig_ship_spec/data/ship_json_with_a_version_-c_cleans_the_image_when_its_done.yml +335 -0
- data/spec/vcr/bigrig_bin_bigrig_ship_spec/data/ship_json_with_a_version_builds_and_pushes_the_image.yml +285 -0
- data/test/dev/shipper.json +24 -0
- data/test/logs/bigrig.json +6 -0
- data/test/logs/container1/Dockerfile +4 -0
- data/test/logs/container1/run.sh +7 -0
- data/test/logs/container2/Dockerfile +4 -0
- data/test/logs/container2/run.sh +7 -0
- data/test/ship/bigrig-1.2.3.json +1 -0
- data/test/ship/bigrig.json +5 -0
- data/test/ship/registry.json +11 -0
- data/test/ship/ship/Dockerfile +4 -0
- data/test/ship/ship/run.sh +6 -0
- data/test/volumes_from/exports_volumes/Dockerfile +8 -0
- data/test/volumes_from/exports_volumes/index.html +8 -0
- data/test/volumes_from/exports_volumes/run.sh +7 -0
- data/test/volumes_from/shipper.json +14 -0
- metadata +278 -8
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
require 'pry'
|
|
2
|
+
module Bigrig
|
|
3
|
+
describe DockerAdapter do
|
|
4
|
+
|
|
5
|
+
describe '::build' do
|
|
6
|
+
subject { described_class.build path }
|
|
7
|
+
let(:path) { test_file 'build' }
|
|
8
|
+
let(:image_id) { subject }
|
|
9
|
+
|
|
10
|
+
it 'builds the given directory', :vcr do
|
|
11
|
+
expect { Docker::Image.get(image_id) }.to_not raise_error
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'passes build input to a block', :vcr do
|
|
15
|
+
described_class.build path do |chunk|
|
|
16
|
+
puts "chunk: #{chunk}"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe '::container_exists?' do
|
|
22
|
+
subject { described_class.container_exists?(name) }
|
|
23
|
+
|
|
24
|
+
context 'when the container exists' do
|
|
25
|
+
let!(:container) { Docker::Container.create 'name' => name, 'Image' => 'hawknewton/true' }
|
|
26
|
+
let(:name) { 'container_exists' }
|
|
27
|
+
|
|
28
|
+
after { container.remove }
|
|
29
|
+
|
|
30
|
+
it 'is true', :vcr do
|
|
31
|
+
is_expected.to be true
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context 'when the container does not exist' do
|
|
36
|
+
let(:name) { 'container_does_not_exist' }
|
|
37
|
+
|
|
38
|
+
it 'is false', :vcr do
|
|
39
|
+
is_expected.to be false
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
describe '::image_id_by_tag' do
|
|
45
|
+
subject { DockerAdapter.image_id_by_tag(tag) }
|
|
46
|
+
|
|
47
|
+
context 'when the image exists' do
|
|
48
|
+
let(:tag) { 'image_exists' }
|
|
49
|
+
let!(:image) { Docker::Image.create 'fromImage' => 'hawknewton/true' }
|
|
50
|
+
|
|
51
|
+
# Get the long id
|
|
52
|
+
let(:image_id) { Docker::Image.get(image.id).id }
|
|
53
|
+
|
|
54
|
+
before { image.tag 'repo' => tag }
|
|
55
|
+
after { image.remove name: tag }
|
|
56
|
+
|
|
57
|
+
it 'returns the image id', :vcr do
|
|
58
|
+
is_expected.to eq image_id
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
context 'when the image does not exist' do
|
|
63
|
+
let(:tag) { 'hawknewton/true:not_exist' }
|
|
64
|
+
|
|
65
|
+
before do
|
|
66
|
+
begin
|
|
67
|
+
image = Docker::Image.get tag
|
|
68
|
+
image.remove name: tag
|
|
69
|
+
rescue Docker::Error::NotFoundError # rubocop:disable Lint/HandleExceptions
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it 'raise a ImageNotFoundError', :vcr do
|
|
74
|
+
expect { subject }.to raise_error ImageNotFoundError
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
describe '::kill' do
|
|
80
|
+
subject { described_class.kill container_id }
|
|
81
|
+
|
|
82
|
+
context 'given the container is running' do
|
|
83
|
+
let(:container) { Docker::Container.create('Image' => image.id).tap(&:start) }
|
|
84
|
+
let(:container_id) { container.id }
|
|
85
|
+
let(:image) { Docker::Image.create 'fromImage' => 'hawknewton/show-env' }
|
|
86
|
+
let(:running?) { container.json['State']['Running'] }
|
|
87
|
+
let!(:kill) { subject }
|
|
88
|
+
|
|
89
|
+
after { container.delete force: true }
|
|
90
|
+
|
|
91
|
+
it 'should kill the container', :vcr do
|
|
92
|
+
expect(running?).to be false
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
context 'given the container does not exist' do
|
|
97
|
+
let(:container_id) { 'doesnotexist' }
|
|
98
|
+
|
|
99
|
+
it 'should raise an error', :vcr do
|
|
100
|
+
expect { subject }.to raise_error ContainerNotFoundError
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
describe '::logs' do
|
|
106
|
+
subject { described_class.logs(container.id) { |s, c| logs << [s, c] } }
|
|
107
|
+
let(:logs) { [] }
|
|
108
|
+
let(:image) { Docker::Image.create 'fromImage' => 'hawknewton/log-test:0.0.1' }
|
|
109
|
+
let(:container) { Docker::Container.get 'log-test' }
|
|
110
|
+
|
|
111
|
+
before do
|
|
112
|
+
Docker::Container.create('Image' => image.id, 'name' => 'log-test').start
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
after { container.kill.delete }
|
|
116
|
+
|
|
117
|
+
it 'streams logs to a block', :vcr do
|
|
118
|
+
allow(Docker::Container).to receive(:get).with(container.id, {}, anything).
|
|
119
|
+
and_return container
|
|
120
|
+
expect(container).to receive(:streaming_logs).
|
|
121
|
+
with(follow: true, stdout: true, stderr: true).
|
|
122
|
+
and_yield('stream #1', 'I am log message #1').
|
|
123
|
+
and_yield('stream #2', 'I am log message #2')
|
|
124
|
+
|
|
125
|
+
subject
|
|
126
|
+
expect(logs).to include ['stream #1', 'I am log message #1']
|
|
127
|
+
expect(logs).to include ['stream #2', 'I am log message #2']
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
describe '::push' do
|
|
132
|
+
subject { described_class.push tag, credentials }
|
|
133
|
+
let(:credentials) { nil }
|
|
134
|
+
let(:host) { URI.parse(Docker.connection.url).host }
|
|
135
|
+
let(:image) { Docker::Image.import test_file 'tiny-image.tar' }
|
|
136
|
+
let(:repo) { "#{host}:5000/test/push-me" }
|
|
137
|
+
let(:version) { '1.2.3' }
|
|
138
|
+
let(:tag) { "#{repo}:#{version}" }
|
|
139
|
+
let(:registry) do
|
|
140
|
+
Docker::Image.create 'fromImage' => 'registry:latest'
|
|
141
|
+
Docker::Container.create(
|
|
142
|
+
'name' => 'registry',
|
|
143
|
+
'Image' => 'registry',
|
|
144
|
+
'Env' => ['GUNICORN_OPTS=[--preload]'],
|
|
145
|
+
'ExposedPorts' => {
|
|
146
|
+
'5000/tcp' => {}
|
|
147
|
+
},
|
|
148
|
+
'HostConfig' => {
|
|
149
|
+
'PortBindings' => { '5000/tcp' => [{ 'HostPort' => '5000' }] }
|
|
150
|
+
}
|
|
151
|
+
)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
before do
|
|
155
|
+
registry.start
|
|
156
|
+
image.tag 'repo' => repo, 'tag' => version
|
|
157
|
+
sleep 1
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
after do
|
|
161
|
+
registry.kill.delete
|
|
162
|
+
image.remove 'force' => true
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
it 'should push the image', :vcr do
|
|
166
|
+
subject
|
|
167
|
+
Docker::Image.get(tag).remove 'force' => true
|
|
168
|
+
expect { Docker::Image.create 'fromImage' => tag }.to_not raise_error
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
context 'given credentials' do
|
|
172
|
+
let(:credentials) do
|
|
173
|
+
{
|
|
174
|
+
'username' => 'username',
|
|
175
|
+
'password' => 'pass',
|
|
176
|
+
'email' => 'email@email.com',
|
|
177
|
+
'serveraddress' => 'https://index.docker.io/v1'
|
|
178
|
+
}
|
|
179
|
+
end
|
|
180
|
+
# I don't have the energy to set one of these up for real
|
|
181
|
+
|
|
182
|
+
it 'will pass login and password', :vcr do
|
|
183
|
+
creds = {
|
|
184
|
+
'username' => 'username',
|
|
185
|
+
'password' => 'pass',
|
|
186
|
+
'serveraddress' => 'https://index.docker.io/v1',
|
|
187
|
+
'email' => 'email@email.com'
|
|
188
|
+
}
|
|
189
|
+
expect_any_instance_of(Docker::Image).to receive(:push).
|
|
190
|
+
with(creds, {})
|
|
191
|
+
subject
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
describe '::pull' do
|
|
197
|
+
subject { described_class.pull repo }
|
|
198
|
+
|
|
199
|
+
context 'given the repo exists' do
|
|
200
|
+
let(:repo) { 'hawknewton/true:latest' }
|
|
201
|
+
let(:image_id) { Docker::Image.get(repo).id }
|
|
202
|
+
|
|
203
|
+
it 'returns the image id', :vcr do
|
|
204
|
+
is_expected.to eq image_id
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
context 'given the repo does not exist' do
|
|
209
|
+
let(:repo) { 'hawknewton/doesnotexist' }
|
|
210
|
+
|
|
211
|
+
it 'raises a RepoNotFoundError', :vcr do
|
|
212
|
+
expect { subject }.to raise_error RepoNotFoundError
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
context 'given a block to capture output' do
|
|
217
|
+
let(:repo) { 'hawknewton/true' }
|
|
218
|
+
let(:output) { '' }
|
|
219
|
+
let(:block) { proc { |chunk| output << chunk } }
|
|
220
|
+
let!(:image_id) { described_class.pull repo, &block }
|
|
221
|
+
|
|
222
|
+
it 'should capture output', :vcr do
|
|
223
|
+
expect(output).to match(/Pulling repository hawknewton\/true/)
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
describe '::remove_container' do
|
|
229
|
+
subject { described_class.remove_container container_id }
|
|
230
|
+
|
|
231
|
+
context 'when the container exists' do
|
|
232
|
+
let(:container_id) { Docker::Container.create('Image' => 'hawknewton/true').id }
|
|
233
|
+
let!(:remove) { subject }
|
|
234
|
+
|
|
235
|
+
it 'should remove the container', :vcr do
|
|
236
|
+
expect { Docker::Container.get container_id }.
|
|
237
|
+
to raise_error { Docker::Error::NotFoundError }
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
context 'when the container does not exist' do
|
|
242
|
+
let(:container_id) { 'doesnotexist' }
|
|
243
|
+
|
|
244
|
+
it 'raises a ContainerNotFoundError', :vcr do
|
|
245
|
+
expect { subject }.to raise_error ContainerNotFoundError
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
context 'when the container is running' do
|
|
250
|
+
let(:container_id) do
|
|
251
|
+
Docker::Container.create('Image' => 'hawknewton/true').tap(&:start).id
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
it 'raises a ContainerRunningError', :vcr do
|
|
255
|
+
expect { subject }.to raise_error ContainerRunningError
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
describe '::remove_image' do
|
|
261
|
+
subject { described_class.remove_image image_id }
|
|
262
|
+
|
|
263
|
+
context 'when the image exists' do
|
|
264
|
+
let(:image_id) { Docker::Image.import(test_file 'tiny-image.tar').id }
|
|
265
|
+
|
|
266
|
+
it 'removes the image', :vcr do
|
|
267
|
+
subject
|
|
268
|
+
expect { Docker::Image.get(image_id) }.to raise_error(/404 Not Found/)
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
context 'when the image doesn''t exist' do
|
|
273
|
+
let(:image_id) { 'does_not_exist' }
|
|
274
|
+
|
|
275
|
+
it 'raises an error', :vcr do
|
|
276
|
+
expect { subject }.to raise_error ImageNotFoundError
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
describe '::run' do
|
|
282
|
+
subject { DockerAdapter.run({ image_id: image_id }.merge opts) }
|
|
283
|
+
|
|
284
|
+
context 'given an image_id that exists' do
|
|
285
|
+
let(:image_id) { 'hawknewton/show-env' }
|
|
286
|
+
let(:container_id) { subject }
|
|
287
|
+
let(:container) { Docker::Container.get container_id }
|
|
288
|
+
let(:running?) { container.json['State']['Running'] }
|
|
289
|
+
|
|
290
|
+
context 'and a name' do
|
|
291
|
+
let(:opts) { { name: name } }
|
|
292
|
+
let(:name) { 'and_a_name' }
|
|
293
|
+
|
|
294
|
+
# strip the leading '/' from the json name
|
|
295
|
+
let(:container_name) { container.json['Name'][1..-1] }
|
|
296
|
+
|
|
297
|
+
after { Docker::Container.get(name).kill!.delete }
|
|
298
|
+
|
|
299
|
+
it 'starts the container with the right name', :vcr do
|
|
300
|
+
expect(running?).to be true
|
|
301
|
+
expect(container_name).to eq name
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
context 'and a name and ports' do
|
|
306
|
+
let(:free_port) { TCPServer.new('0.0.0.0', 0).addr[1] }
|
|
307
|
+
let(:opts) { { name: name, ports: ["#{free_port}:80", '70'] } }
|
|
308
|
+
let(:name) { 'with_ports' }
|
|
309
|
+
let(:exposed_ports) { container.json['Config']['ExposedPorts'].map { |k, _| k } }
|
|
310
|
+
let(:mapped_ports) do
|
|
311
|
+
container.json['NetworkSettings']['Ports'].each_with_object({}) do |arr, hash|
|
|
312
|
+
hash[arr[0]] = arr[1][0]['HostPort']
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
after { Docker::Container.get(name).kill!.delete }
|
|
317
|
+
|
|
318
|
+
it 'starts the container with ports exposed', :vcr do
|
|
319
|
+
expect(running?).to be true
|
|
320
|
+
expect(exposed_ports).to eq ['70/tcp', '80/tcp']
|
|
321
|
+
expect(mapped_ports).to include '80/tcp'
|
|
322
|
+
expect(mapped_ports).to include '70/tcp'
|
|
323
|
+
|
|
324
|
+
# Because the free port will move around under VCR we can't actually
|
|
325
|
+
# assert anything
|
|
326
|
+
expect(mapped_ports['80/tcp'].to_i).to be_a Fixnum
|
|
327
|
+
expect(mapped_ports['70/tcp'].to_i).to be_a Fixnum
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
context 'and a name and env variables' do
|
|
332
|
+
let(:name) { 'with_env' }
|
|
333
|
+
let(:opts) { { name: name, env: { 'NAME1' => 'VALUE1', 'NAME2' => 'VALUE2' } } }
|
|
334
|
+
let(:envs) { container.json['Config']['Env'] }
|
|
335
|
+
|
|
336
|
+
after { Docker::Container.get(name).kill!.delete }
|
|
337
|
+
|
|
338
|
+
it 'starts the container with env set', :vcr do
|
|
339
|
+
expect(running?).to be true
|
|
340
|
+
expect(envs).to include 'NAME1=VALUE1'
|
|
341
|
+
expect(envs).to include 'NAME2=VALUE2'
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
describe '::running?' do
|
|
348
|
+
subject { described_class.running? container_id }
|
|
349
|
+
let(:result) { subject }
|
|
350
|
+
|
|
351
|
+
context 'when the container is running' do
|
|
352
|
+
let(:container) do
|
|
353
|
+
Docker::Container.create('Image' => 'hawknewton/show-env')
|
|
354
|
+
end
|
|
355
|
+
let(:container_id) { container.id }
|
|
356
|
+
|
|
357
|
+
before { container.start }
|
|
358
|
+
after { container.delete force: true }
|
|
359
|
+
|
|
360
|
+
it 'returns true', :vcr do
|
|
361
|
+
expect(result).to be true
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
context 'when the container is not running' do
|
|
366
|
+
let(:container) do
|
|
367
|
+
Docker::Container.create('Image' => 'hawknewton/show-env')
|
|
368
|
+
end
|
|
369
|
+
let(:container_id) { container.id }
|
|
370
|
+
|
|
371
|
+
after { container.delete force: true }
|
|
372
|
+
|
|
373
|
+
it 'returns false', :vcr do
|
|
374
|
+
expect(result).to be false
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
context 'when the container does not exist', :vcr do
|
|
379
|
+
let(:container_id) { 'doesnotexist' }
|
|
380
|
+
|
|
381
|
+
it 'returns false' do
|
|
382
|
+
expect(result).to be false
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
describe '::tag' do
|
|
388
|
+
subject { described_class.tag id, tag }
|
|
389
|
+
let(:id) { Docker::Image.create('fromImage' => 'hawknewton/true').id }
|
|
390
|
+
let(:tag) { 'test/tag:1.2.3' }
|
|
391
|
+
|
|
392
|
+
before do
|
|
393
|
+
begin
|
|
394
|
+
Docker::Image.get(tag).remove 'force' => true
|
|
395
|
+
rescue Docker::Error::NotFoundError # rubocop:disable Lint/HandleExceptions
|
|
396
|
+
end
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
after do
|
|
400
|
+
Docker::Image.get(tag).remove 'force' => true
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
it 'should tag the image', :vcr do
|
|
404
|
+
subject
|
|
405
|
+
expect { Docker::Image.get 'test/tag:1.2.3' }.to_not raise_error
|
|
406
|
+
end
|
|
407
|
+
end
|
|
408
|
+
end
|
|
409
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Bigrig
|
|
2
|
+
describe Application do
|
|
3
|
+
it { is_expected.to respond_to :name }
|
|
4
|
+
it { is_expected.to respond_to :name= }
|
|
5
|
+
|
|
6
|
+
it { is_expected.to respond_to :containers }
|
|
7
|
+
it { is_expected.to respond_to :containers= }
|
|
8
|
+
|
|
9
|
+
describe '::from_json' do
|
|
10
|
+
subject { described_class.from_json json }
|
|
11
|
+
|
|
12
|
+
context 'given a simple file' do
|
|
13
|
+
let(:file) { 'single.json' }
|
|
14
|
+
let(:json) { Descriptor.read(test_file(file)).as_json }
|
|
15
|
+
|
|
16
|
+
its('containers.size') { is_expected.to eq 1 }
|
|
17
|
+
|
|
18
|
+
it 'should set the container name' do
|
|
19
|
+
expect(subject.containers[0].name).to eq 'single-test'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'should set the container tag' do
|
|
23
|
+
expect(subject.containers[0].tag).to eq '0.0.1'
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'should set the container repo' do
|
|
27
|
+
expect(subject.containers[0].repo).to eq 'hawknewton/show-env'
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
module Bigrig
|
|
2
|
+
describe Container do
|
|
3
|
+
it { is_expected.to respond_to :hosts= }
|
|
4
|
+
it { is_expected.to respond_to :hosts }
|
|
5
|
+
it { is_expected.to respond_to :links= }
|
|
6
|
+
it { is_expected.to respond_to :links }
|
|
7
|
+
it { is_expected.to respond_to :name }
|
|
8
|
+
it { is_expected.to respond_to :name= }
|
|
9
|
+
it { is_expected.to respond_to :path }
|
|
10
|
+
it { is_expected.to respond_to :path= }
|
|
11
|
+
it { is_expected.to respond_to :ports }
|
|
12
|
+
it { is_expected.to respond_to :ports= }
|
|
13
|
+
it { is_expected.to respond_to :repo }
|
|
14
|
+
it { is_expected.to respond_to :repo= }
|
|
15
|
+
it { is_expected.to respond_to :tag }
|
|
16
|
+
it { is_expected.to respond_to :tag= }
|
|
17
|
+
it { is_expected.to respond_to :volumes_from }
|
|
18
|
+
it { is_expected.to respond_to :volumes_from= }
|
|
19
|
+
|
|
20
|
+
it 'accepts volumes_from as an array' do
|
|
21
|
+
expect(Container.from_json(nil, 'volumes_from' => ['test']).volumes_from).to be_kind_of Array
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'wraps a single volumes_from in an array' do
|
|
25
|
+
expect(Container.from_json(nil, 'volumes_from' => 'test').volumes_from).to be_kind_of Array
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'accepts links as an array' do
|
|
29
|
+
expect(Container.from_json(nil, 'links' => ['machine:alias']).links).to be_kind_of Array
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'wraps a single links in an array' do
|
|
33
|
+
expect(Container.from_json(nil, 'links' => 'machine:alias').links).to be_kind_of Array
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'accepts hosts as an array' do
|
|
37
|
+
expect(Container.from_json(nil, 'links' => ['host:alias']).links).to be_kind_of Array
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'wraps a single links in an array' do
|
|
41
|
+
expect(Container.from_json(nil, 'hosts' => 'host:alias').links).to be_kind_of Array
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'depends on containers it mounts volumes from' do
|
|
45
|
+
expect(Container.from_json(nil, 'volumes_from' => 'test').dependencies).to eq ['test']
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'depends on containers it links to' do
|
|
49
|
+
expect(Container.from_json(nil, 'links' => 'machine:alias').dependencies).to eq ['machine']
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
describe '#dependencies' do
|
|
53
|
+
it 'returns an empty array when no dependencies are present' do
|
|
54
|
+
expect(Container.from_json(nil, {}).dependencies).to eq []
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
describe '::from_json' do
|
|
59
|
+
subject { Container.from_json name, json }
|
|
60
|
+
let(:name) { 'name' }
|
|
61
|
+
|
|
62
|
+
context 'with an empty json document' do
|
|
63
|
+
let(:json) { {} }
|
|
64
|
+
|
|
65
|
+
its(:env) { is_expected.to be_empty }
|
|
66
|
+
its(:env) { is_expected.to be_a Hash }
|
|
67
|
+
|
|
68
|
+
its(:volumes_from) { is_expected.to be_empty }
|
|
69
|
+
its(:volumes_from) { is_expected.to be_a Array }
|
|
70
|
+
|
|
71
|
+
its(:ports) { is_expected.to be_a Array }
|
|
72
|
+
its(:ports) { is_expected.to be_empty }
|
|
73
|
+
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
context 'given json with a path' do
|
|
77
|
+
let(:json) { { 'path' => '/path/to/Dockerfile' } }
|
|
78
|
+
|
|
79
|
+
it 'sets the path' do
|
|
80
|
+
expect(subject.path).to eq '/path/to/Dockerfile'
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
context 'given json with env params' do
|
|
85
|
+
let(:json) { { 'env' => { 'NAME1' => 'VALUE1', 'NAME2' => 'VALUE2' } } }
|
|
86
|
+
|
|
87
|
+
it 'parses the environment variables' do
|
|
88
|
+
expect(subject.env).to include(
|
|
89
|
+
'NAME1' => 'VALUE1',
|
|
90
|
+
'NAME2' => 'VALUE2'
|
|
91
|
+
)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
context 'that reference environment variables' do
|
|
95
|
+
let(:json) { { 'env' => { 'NAME1' => "\#{ENV['NAME1']}" } } }
|
|
96
|
+
|
|
97
|
+
before { ENV['NAME1'] = 'ENV1' }
|
|
98
|
+
after { ENV['NAME1'] = nil }
|
|
99
|
+
|
|
100
|
+
it 'retrieves the variable from the environemnt' do
|
|
101
|
+
expect(subject.env).to include('NAME1' => 'ENV1')
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
context 'given json with ports' do
|
|
107
|
+
let(:json) { { 'ports' => ['80:8080', '12345'] } }
|
|
108
|
+
|
|
109
|
+
it 'has ports' do
|
|
110
|
+
expect(subject.ports).to eq ['80:8080', '12345']
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module Bigrig
|
|
2
|
+
describe OutputParser do
|
|
3
|
+
describe '#parse' do
|
|
4
|
+
subject do
|
|
5
|
+
parser = described_class.new
|
|
6
|
+
[input].flatten.map { |i| parser.parse i }.last
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
let(:mock_io) { double IO }
|
|
10
|
+
let(:output) { subject }
|
|
11
|
+
|
|
12
|
+
context 'with input that has a stream' do
|
|
13
|
+
let(:input) { '{"stream": "value"}' }
|
|
14
|
+
|
|
15
|
+
it 'returns the value of stream' do
|
|
16
|
+
expect(output).to eq 'value'
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
context 'with input that has no id and a status' do
|
|
21
|
+
let(:input) { '{"status": "status_value"}' }
|
|
22
|
+
|
|
23
|
+
it 'returns the value of status with a linefeed' do
|
|
24
|
+
expect(output).to eq "status_value\n"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
context 'with input that has an id, status, and progress' do
|
|
29
|
+
let(:input) { '{"id": "id", "status": "status", "progress" : "progress" }' }
|
|
30
|
+
|
|
31
|
+
it 'formats the output with a trailing carrage return' do
|
|
32
|
+
expect(output).to eq "id: status progress\r"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
context 'when the id changes' do
|
|
37
|
+
let(:input) do
|
|
38
|
+
['{"id": "id", "status": "status", "progress" : "progress" }',
|
|
39
|
+
'{"id": "new_id", "status": "status", "progress" : "progress" }']
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'prints a linefeed' do
|
|
43
|
+
expect(output).to eq "\nnew_id: status progress\r"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
context 'when the id noralizes after changing' do
|
|
48
|
+
let(:input) do
|
|
49
|
+
['{"id": "id", "status": "status", "progress" : "progress" }',
|
|
50
|
+
'{"id": "new_id", "status": "status", "progress" : "progress" }',
|
|
51
|
+
'{"id": "new_id", "status": "status", "progress" : "progress" }']
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'does not print a linefeed' do
|
|
55
|
+
expect(output).to eq "new_id: status progress\r"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
context 'when a shorter message is returned with the same id' do
|
|
60
|
+
let(:input) do
|
|
61
|
+
['{"id": "id", "status": "status", "progress" : "i am a much longer message" }',
|
|
62
|
+
'{"id": "id", "status": "status", "progress" : "progress" }']
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'pads the output' do
|
|
66
|
+
expect(output).to eq "id: status progress \r"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|