centurion 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+ require 'centurion/docker_server'
3
+
4
+ describe Centurion::DockerServer do
5
+ let(:host) { 'host1' }
6
+ let(:docker_path) { 'docker' }
7
+ let(:server) { Centurion::DockerServer.new(host, docker_path) }
8
+
9
+ it 'knows its hostname' do
10
+ expect(server.hostname).to eq('host1')
11
+ end
12
+
13
+ it 'knows its port' do
14
+ expect(server.port).to eq('4243')
15
+ end
16
+
17
+ describe 'when host includes a port' do
18
+ let(:host) { 'host2:4321' }
19
+ it 'knows that port' do
20
+ expect(server.port).to eq('4321')
21
+ end
22
+ end
23
+
24
+ { docker_via_api: [:create_container, :inspect_container, :inspect_image,
25
+ :ps, :start_container, :stop_container],
26
+ docker_via_cli: [:pull, :tail] }.each do |delegate, methods|
27
+ methods.each do |method|
28
+ it "delegates '#{method}' to #{delegate}" do
29
+ dummy_result = double
30
+ dummy_delegate = double(method => dummy_result)
31
+ server.stub(delegate => dummy_delegate)
32
+ expect(dummy_delegate).to receive(method)
33
+ expect(server.send(method)).to be(dummy_result)
34
+ end
35
+ end
36
+ end
37
+
38
+ it 'returns tags associated with an image' do
39
+ image_names = %w[target:latest target:production other:latest]
40
+ server.stub(ps: image_names.map {|name| { 'Image' => name } })
41
+ expect(server.current_tags_for('target')).to eq(%w[latest production])
42
+ end
43
+ end
@@ -0,0 +1,111 @@
1
+ require 'spec_helper'
2
+ require 'centurion/docker_via_api'
3
+
4
+ describe Centurion::DockerViaApi do
5
+ let(:hostname) { 'example.com' }
6
+ let(:port) { '4243' }
7
+ let(:api) { Centurion::DockerViaApi.new(hostname, port) }
8
+ let(:excon_uri) { "http://#{hostname}:#{port}/v1.7" }
9
+ let(:json_string) { '[{ "Hello": "World" }]' }
10
+ let(:json_value) { JSON.load(json_string) }
11
+ let(:inspected_containers) do
12
+ [
13
+ {"Id" => "123", "Status" => "Exit 0"},
14
+ {"Id" => "456", "Status" => "Running blah blah"},
15
+ {"Id" => "789", "Status" => "Exit 1"},
16
+ ]
17
+ end
18
+
19
+ it 'lists processes' do
20
+ expect(Excon).to receive(:get).
21
+ with(excon_uri + "/containers/json").
22
+ and_return(double(body: json_string, status: 200))
23
+ expect(api.ps).to eq(json_value)
24
+ end
25
+
26
+ it 'lists all processes' do
27
+ expect(Excon).to receive(:get).
28
+ with(excon_uri + "/containers/json?all=1").
29
+ and_return(double(body: json_string, status: 200))
30
+ expect(api.ps(all: true)).to eq(json_value)
31
+ end
32
+
33
+ it 'inspects an image' do
34
+ expect(Excon).to receive(:get).
35
+ with(excon_uri + "/images/foo:bar/json",
36
+ headers: {'Accept' => 'application/json'}).
37
+ and_return(double(body: json_string, status: 200))
38
+ expect(api.inspect_image('foo', 'bar')).to eq(json_value)
39
+ end
40
+
41
+ it 'creates a container' do
42
+ configuration_as_json = double
43
+ configuration = double(:to_json => configuration_as_json)
44
+ expect(Excon).to receive(:post).
45
+ with(excon_uri + "/containers/create",
46
+ body: configuration_as_json,
47
+ headers: {'Content-Type' => 'application/json'}).
48
+ and_return(double(body: json_string, status: 201))
49
+ api.create_container(configuration)
50
+ end
51
+
52
+ it 'starts a container' do
53
+ configuration_as_json = double
54
+ configuration = double(:to_json => configuration_as_json)
55
+ expect(Excon).to receive(:post).
56
+ with(excon_uri + "/containers/12345/start",
57
+ body: configuration_as_json,
58
+ headers: {'Content-Type' => 'application/json'}).
59
+ and_return(double(body: json_string, status: 204))
60
+ api.start_container('12345', configuration)
61
+ end
62
+
63
+ it 'stops a container' do
64
+ expect(Excon).to receive(:post).
65
+ with(excon_uri + "/containers/12345/stop?t=30").
66
+ and_return(double(status: 204))
67
+ api.stop_container('12345')
68
+ end
69
+
70
+ it 'inspects a container' do
71
+ expect(Excon).to receive(:get).
72
+ with(excon_uri + "/containers/12345/json").
73
+ and_return(double(body: json_string, status: 200))
74
+ expect(api.inspect_container('12345')).to eq(json_value)
75
+ end
76
+
77
+ it 'removes a container' do
78
+ expect(Excon).to receive(:delete).
79
+ with(excon_uri + "/containers/12345").
80
+ and_return(double(status: 204))
81
+ expect(api.remove_container('12345')).to eq(true)
82
+ end
83
+
84
+ it 'lists old containers for a port' do
85
+ expect(Excon).to receive(:get).
86
+ with(excon_uri + "/containers/json?all=1").
87
+ and_return(double(body: inspected_containers.to_json, status: 200))
88
+ expect(Excon).to receive(:get).
89
+ with(excon_uri + "/containers/123/json").
90
+ and_return(double(body: inspected_container_on_port("123", 8485).to_json, status: 200))
91
+ expect(Excon).to receive(:get).
92
+ with(excon_uri + "/containers/789/json").
93
+ and_return(double(body: inspected_container_on_port("789", 8486).to_json, status: 200))
94
+
95
+ expect(api.old_containers_for_port(8485)).to eq([{"Id" => "123", "Status" => "Exit 0"}])
96
+ end
97
+
98
+ def inspected_container_on_port(id, port)
99
+ {
100
+ "Id" => id.to_s,
101
+ "HostConfig" => {
102
+ "PortBindings" => {
103
+ "80/tcp" => [
104
+ "HostIp" => "0.0.0.0",
105
+ "HostPort" => port.to_s
106
+ ]
107
+ }
108
+ }
109
+ }
110
+ end
111
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+ require 'centurion/docker_via_cli'
3
+
4
+ describe Centurion::DockerViaCli do
5
+ let(:docker_path) { 'docker' }
6
+ let(:docker_via_cli) { Centurion::DockerViaCli.new('host1', 4243, docker_path) }
7
+
8
+ it 'pulls the latest image given its name' do
9
+ expect(docker_via_cli).to receive(:echo).
10
+ with("docker -H=tcp://host1:4243 pull foo:latest")
11
+ docker_via_cli.pull('foo')
12
+ end
13
+
14
+ it 'pulls an image given its name & tag' do
15
+ expect(docker_via_cli).to receive(:echo).
16
+ with("docker -H=tcp://host1:4243 pull foo:bar")
17
+ docker_via_cli.pull('foo', 'bar')
18
+ end
19
+
20
+ it 'tails logs on a container' do
21
+ id = '12345abcdef'
22
+ expect(docker_via_cli).to receive(:echo).
23
+ with("docker -H=tcp://host1:4243 logs -f #{id}")
24
+ docker_via_cli.tail(id)
25
+ end
26
+
27
+ it 'should print all chars when one thread is running' do
28
+ expect(docker_via_cli).to receive(:run_with_echo)
29
+
30
+ allow(Thread).to receive(:list) {[double(:status => 'run')]}
31
+
32
+ docker_via_cli.pull('foo')
33
+ end
34
+
35
+ it 'should only print lines when multiple threads are running' do
36
+ expect(docker_via_cli).to receive(:run_without_echo)
37
+
38
+ allow(Thread).to receive(:list) {[double(:status => 'run'), double(:status => 'run')]}
39
+
40
+ docker_via_cli.pull('foo')
41
+ end
42
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+ require 'centurion/logging'
3
+
4
+ class TestLogging
5
+ extend Centurion::Logging
6
+ def self.logger
7
+ log
8
+ end
9
+ end
10
+
11
+ describe Centurion::Logging do
12
+ let(:message) { %w{ something something_else } }
13
+
14
+ context '#info' do
15
+ it 'passes through to Logger' do
16
+ expect(TestLogging.logger).to receive(:info).with(message.join(' '))
17
+ TestLogging.info(*message)
18
+ end
19
+ end
20
+
21
+ context '#warn' do
22
+ it 'passes through to Logger' do
23
+ expect(TestLogging.logger).to receive(:warn).with(message.join(' '))
24
+ TestLogging.warn(*message)
25
+ end
26
+ end
27
+
28
+ context '#debug' do
29
+ it 'passes through to Logger' do
30
+ expect(TestLogging.logger).to receive(:debug).with(message.join(' '))
31
+ TestLogging.debug(*message)
32
+ end
33
+ end
34
+
35
+ context '#error' do
36
+ it 'passes through to Logger' do
37
+ expect(TestLogging.logger).to receive(:error).with(message.join(' '))
38
+ TestLogging.error(*message)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,7 @@
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_filter '/spec'
4
+ end
5
+
6
+ $: << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ Dir[File.dirname(__FILE__) + '/support/**/*.rb'].each {|f| require f}
@@ -0,0 +1,13 @@
1
+ RSpec::Matchers.define :have_key_and_value do |expected_key, expected_value|
2
+ match do |actual|
3
+ actual.env[actual.current_environment].has_key?(expected_key.to_sym) && (actual.fetch(expected_key.to_sym) == expected_value)
4
+ end
5
+
6
+ failure_message_for_should do |actual|
7
+ "expected that #{actual.env[actual.current_environment].keys.inspect} would include #{expected_key.inspect} with value #{expected_value.inspect}"
8
+ end
9
+
10
+ failure_message_for_should_not do |actual|
11
+ "expected that #{actual.env[actual.current_environment].keys.join(', ')} would not include #{expected_key.inspect} with value #{expected_value.inspect}"
12
+ end
13
+ end
metadata ADDED
@@ -0,0 +1,243 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: centurion
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.6
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Nic Benders
9
+ - Karl Matthias
10
+ - Andrew Bloomgarden
11
+ - Aaron Bento
12
+ - Paul Showalter
13
+ - David Kerr
14
+ - Jonathan Owens
15
+ - Jon Guymon
16
+ - Merlyn Albery-Speyer
17
+ - Amjith Ramanujam
18
+ - David Celis
19
+ - Emily Hyland
20
+ - Bryan Stearns
21
+ autorequire:
22
+ bindir: bin
23
+ cert_chain: []
24
+ date: 2014-06-08 00:00:00.000000000 Z
25
+ dependencies:
26
+ - !ruby/object:Gem::Dependency
27
+ name: trollop
28
+ requirement: !ruby/object:Gem::Requirement
29
+ none: false
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
+ none: false
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: excon
44
+ requirement: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ~>
48
+ - !ruby/object:Gem::Version
49
+ version: '0.33'
50
+ type: :runtime
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ~>
56
+ - !ruby/object:Gem::Version
57
+ version: '0.33'
58
+ - !ruby/object:Gem::Dependency
59
+ name: logger-colors
60
+ requirement: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ - !ruby/object:Gem::Dependency
75
+ name: bundler
76
+ requirement: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ - !ruby/object:Gem::Dependency
91
+ name: rake
92
+ requirement: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ! '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ type: :development
99
+ prerelease: false
100
+ version_requirements: !ruby/object:Gem::Requirement
101
+ none: false
102
+ requirements:
103
+ - - ! '>='
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ - !ruby/object:Gem::Dependency
107
+ name: rspec
108
+ requirement: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ! '>='
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ type: :development
115
+ prerelease: false
116
+ version_requirements: !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ! '>='
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ - !ruby/object:Gem::Dependency
123
+ name: pry
124
+ requirement: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ! '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ type: :development
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ none: false
134
+ requirements:
135
+ - - ! '>='
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ - !ruby/object:Gem::Dependency
139
+ name: simplecov
140
+ requirement: !ruby/object:Gem::Requirement
141
+ none: false
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
+ none: false
150
+ requirements:
151
+ - - ! '>='
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ description:
155
+ email:
156
+ - nic@newrelic.com
157
+ - kmatthias@newrelic.com
158
+ - andrew@newrelic.com
159
+ - aaron@newrelic.com
160
+ - poeslacker@gmail.com
161
+ - dkerr@newrelic.com
162
+ - jonathan@newrelic.com
163
+ - jon@newrelic.com
164
+ - merlyn@newrelic.com
165
+ - amjith@newrelic.com
166
+ - dcelis@newrelic.com
167
+ - ehyland@newrelic.com
168
+ - bryan@newrelic.com
169
+ executables:
170
+ - centurion
171
+ - centurionize
172
+ extensions: []
173
+ extra_rdoc_files: []
174
+ files:
175
+ - .gitignore
176
+ - CONTRIBUTORS.md
177
+ - Gemfile
178
+ - LICENSE
179
+ - README.md
180
+ - Rakefile
181
+ - bin/centurion
182
+ - bin/centurionize
183
+ - centurion.gemspec
184
+ - lib/capistrano_dsl.rb
185
+ - lib/centurion.rb
186
+ - lib/centurion/deploy.rb
187
+ - lib/centurion/deploy_dsl.rb
188
+ - lib/centurion/docker_registry.rb
189
+ - lib/centurion/docker_server.rb
190
+ - lib/centurion/docker_server_group.rb
191
+ - lib/centurion/docker_via_api.rb
192
+ - lib/centurion/docker_via_cli.rb
193
+ - lib/centurion/logging.rb
194
+ - lib/centurion/version.rb
195
+ - lib/tasks/deploy.rake
196
+ - lib/tasks/info.rake
197
+ - lib/tasks/list.rake
198
+ - spec/capistrano_dsl_spec.rb
199
+ - spec/deploy_dsl_spec.rb
200
+ - spec/deploy_spec.rb
201
+ - spec/docker_server_group_spec.rb
202
+ - spec/docker_server_spec.rb
203
+ - spec/docker_via_api_spec.rb
204
+ - spec/docker_via_cli_spec.rb
205
+ - spec/logging_spec.rb
206
+ - spec/spec_helper.rb
207
+ - spec/support/matchers/capistrano_dsl_matchers.rb
208
+ homepage: https://github.com/newrelic/centurion
209
+ licenses:
210
+ - MIT
211
+ post_install_message:
212
+ rdoc_options: []
213
+ require_paths:
214
+ - lib
215
+ required_ruby_version: !ruby/object:Gem::Requirement
216
+ none: false
217
+ requirements:
218
+ - - ! '>='
219
+ - !ruby/object:Gem::Version
220
+ version: 1.9.3
221
+ required_rubygems_version: !ruby/object:Gem::Requirement
222
+ none: false
223
+ requirements:
224
+ - - ! '>='
225
+ - !ruby/object:Gem::Version
226
+ version: '0'
227
+ requirements: []
228
+ rubyforge_project:
229
+ rubygems_version: 1.8.23
230
+ signing_key:
231
+ specification_version: 3
232
+ summary: Deploy images to a fleet of Docker servers
233
+ test_files:
234
+ - spec/capistrano_dsl_spec.rb
235
+ - spec/deploy_dsl_spec.rb
236
+ - spec/deploy_spec.rb
237
+ - spec/docker_server_group_spec.rb
238
+ - spec/docker_server_spec.rb
239
+ - spec/docker_via_api_spec.rb
240
+ - spec/docker_via_cli_spec.rb
241
+ - spec/logging_spec.rb
242
+ - spec/spec_helper.rb
243
+ - spec/support/matchers/capistrano_dsl_matchers.rb