docker-client 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +22 -0
- data/MIT-LICENSE +21 -0
- data/README.md +87 -0
- data/Rakefile +15 -0
- data/docker.gemspec +40 -0
- data/lib/docker.rb +10 -0
- data/lib/docker/api.rb +32 -0
- data/lib/docker/connection.rb +83 -0
- data/lib/docker/error.rb +9 -0
- data/lib/docker/error/bad_parameter_error.rb +7 -0
- data/lib/docker/error/container_not_found.rb +7 -0
- data/lib/docker/error/internal_server_error.rb +7 -0
- data/lib/docker/error/not_found_error.rb +7 -0
- data/lib/docker/resource.rb +8 -0
- data/lib/docker/resource/base.rb +23 -0
- data/lib/docker/resource/container.rb +131 -0
- data/lib/docker/resource/image.rb +10 -0
- data/lib/docker/version.rb +3 -0
- data/spec/cassettes/Docker_Connection/returns_a_valid_response_for_a_basic_request.yml +40 -0
- data/spec/cassettes/Docker_Connection/returns_a_valid_response_for_get_request.yml +105 -0
- data/spec/cassettes/Docker_Connection/returns_a_valid_response_for_post_request.yml +30 -0
- data/spec/cassettes/Docker_Connection/returns_status_404_for_non_existent_path.yml +31 -0
- data/spec/cassettes/Docker_Connection/sets_given_query_parameters.yml +31 -0
- data/spec/cassettes/Docker_Connection/sets_given_request_headers.yml +33 -0
- data/spec/cassettes/Docker_Resource_Container/changes/inspects_the_container_s_filesystem_changes.yml +33 -0
- data/spec/cassettes/Docker_Resource_Container/create/raises_an_exception_when_called_with_invalid_options.yml +34 -0
- data/spec/cassettes/Docker_Resource_Container/create/with_many_settings.yml +36 -0
- data/spec/cassettes/Docker_Resource_Container/create/with_minimal_settings.yml +34 -0
- data/spec/cassettes/Docker_Resource_Container/kill/raises_an_exception_for_an_unknow_container.yml +31 -0
- data/spec/cassettes/Docker_Resource_Container/kill/the_container.yml +30 -0
- data/spec/cassettes/Docker_Resource_Container/lists/all_running_containers.yml +46 -0
- data/spec/cassettes/Docker_Resource_Container/lists/limit_last_created_containers.yml +34 -0
- data/spec/cassettes/Docker_Resource_Container/lists/non-running_processes_too.yml +114 -0
- data/spec/cassettes/Docker_Resource_Container/lists/processes_before_a_certain_created_container.yml +110 -0
- data/spec/cassettes/Docker_Resource_Container/lists/processes_since_a_certain_created_container.yml +34 -0
- data/spec/cassettes/Docker_Resource_Container/logs/returns_the_stderr_of_a_container.yml +25 -0
- data/spec/cassettes/Docker_Resource_Container/logs/returns_the_stdout_of_a_container.yml +25 -0
- data/spec/cassettes/Docker_Resource_Container/remove/deletes_the_container.yml +30 -0
- data/spec/cassettes/Docker_Resource_Container/remove/raises_an_exception_with_an_invalid_container.yml +31 -0
- data/spec/cassettes/Docker_Resource_Container/restarts/raises_an_exception_for_an_unknown_container.yml +31 -0
- data/spec/cassettes/Docker_Resource_Container/restarts/the_container.yml +30 -0
- data/spec/cassettes/Docker_Resource_Container/shows/the_low_level_details.yml +48 -0
- data/spec/cassettes/Docker_Resource_Container/start/brings_a_container_into_state_running.yml +30 -0
- data/spec/cassettes/Docker_Resource_Container/start/raises_an_exception_for_an_unknown_container.yml +31 -0
- data/spec/cassettes/Docker_Resource_Container/stop/halts_a_container.yml +30 -0
- data/spec/cassettes/Docker_Resource_Container/stop/raises_an_exception_for_an_unknown_container.yml +31 -0
- data/spec/cassettes/Docker_Resource_Container/wait/blocks_until_the_container_stops.yml +31 -0
- data/spec/cassettes/Docker_Resource_Container/wait/raises_an_exception_for_an_unknown_container.yml +31 -0
- data/spec/cassettes/test_setup/create_container_connection_post.yml +33 -0
- data/spec/cassettes/test_setup/create_container_container_changes.yml +33 -0
- data/spec/cassettes/test_setup/create_container_container_kill.yml +34 -0
- data/spec/cassettes/test_setup/create_container_container_lists1.yml +34 -0
- data/spec/cassettes/test_setup/create_container_container_lists2.yml +33 -0
- data/spec/cassettes/test_setup/create_container_container_logs.yml +33 -0
- data/spec/cassettes/test_setup/create_container_container_remove.yml +33 -0
- data/spec/cassettes/test_setup/create_container_container_restarts.yml +34 -0
- data/spec/cassettes/test_setup/create_container_container_shows.yml +33 -0
- data/spec/cassettes/test_setup/create_container_container_start.yml +33 -0
- data/spec/cassettes/test_setup/create_container_container_stop.yml +34 -0
- data/spec/cassettes/test_setup/create_container_container_wait.yml +33 -0
- data/spec/cassettes/test_setup/delete_container.yml +405 -0
- data/spec/cassettes/test_setup/start_container.yml +235 -0
- data/spec/cassettes/test_setup/wait_on_container.yml +63 -0
- data/spec/docker/api_spec.rb +37 -0
- data/spec/docker/connection_spec.rb +81 -0
- data/spec/docker/resource/container_spec.rb +288 -0
- data/spec/helpers.rb +48 -0
- data/spec/spec_helper.rb +31 -0
- metadata +361 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use ruby-1.9.3-p327@octo
|
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Georg Kunz
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 Georg Kunz.
|
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,87 @@
|
|
1
|
+
# Docker Client
|
2
|
+
|
3
|
+
Docker client library to access the Docker remote API.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'docker-client'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install docker-client
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
So far only the containers resource is supported. The images resource and endpoints in category Mics according to the Docker [Remote API documentation](http://docs.docker.io/en/latest/api/docker_remote_api.html) are not yet implemented.
|
22
|
+
|
23
|
+
|
24
|
+
````ruby
|
25
|
+
require 'docker'
|
26
|
+
require 'awesome_print'
|
27
|
+
|
28
|
+
docker = Docker::API.new(base_url: 'http://localhost:4243')
|
29
|
+
containers = docker.containers
|
30
|
+
|
31
|
+
# Create a new container
|
32
|
+
result = containers.create(['/bin/sh', '-c', 'while true; do echo hello world; sleep 1; done'], 'base')
|
33
|
+
container_id = result["Id"]
|
34
|
+
ap result
|
35
|
+
|
36
|
+
# Start created container
|
37
|
+
containers.start(container_id)
|
38
|
+
|
39
|
+
# Get container details (inspect)
|
40
|
+
details = containers.show(container_id)
|
41
|
+
ap details
|
42
|
+
|
43
|
+
# Get file system changes of container
|
44
|
+
changes = containers.changes(container_id)
|
45
|
+
ap changes
|
46
|
+
|
47
|
+
# Attach to container for 3 seconds
|
48
|
+
options = {stdout: true, stderr: false}
|
49
|
+
containers.attach(container_id, options, 3) do |data|
|
50
|
+
puts ">> #{data}"
|
51
|
+
end
|
52
|
+
|
53
|
+
# Get all output since container is started
|
54
|
+
output = containers.logs(container_id)
|
55
|
+
ap output
|
56
|
+
|
57
|
+
# List all running containers
|
58
|
+
running_containers = containers.list
|
59
|
+
ap running_containers
|
60
|
+
|
61
|
+
# Stop container
|
62
|
+
containers.stop(container_id)
|
63
|
+
|
64
|
+
# Remove container
|
65
|
+
containers.remove(container_id)
|
66
|
+
|
67
|
+
````
|
68
|
+
|
69
|
+
## Development
|
70
|
+
|
71
|
+
### Run tests
|
72
|
+
|
73
|
+
All tests are stubbed with VCR. You can edit the setting `config.default_cassette_options` in `spec_helper.rb` to run the tests against the docker API. Set it to `{:record => :all}`. This will alos re-record all VCR request/response. To run the tests stubbed again uncomment the before mentioned setting.
|
74
|
+
|
75
|
+
## Contributing
|
76
|
+
|
77
|
+
1. Fork it
|
78
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
79
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
80
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
81
|
+
5. Create new Pull Request
|
82
|
+
|
83
|
+
|
84
|
+
## License
|
85
|
+
|
86
|
+
MIT License. Copyright 2013 Georg Kunz.
|
87
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
|
4
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
5
|
+
# Documentation output
|
6
|
+
# Disable live tests
|
7
|
+
t.rspec_opts = "-f d -t ~live"
|
8
|
+
end
|
9
|
+
|
10
|
+
# Only run focus examples
|
11
|
+
RSpec::Core::RakeTask.new(:focus) do |t|
|
12
|
+
t.rspec_opts = "-f d -t focus"
|
13
|
+
end
|
14
|
+
|
15
|
+
task :default => :spec
|
data/docker.gemspec
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'docker/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'docker-client'
|
8
|
+
spec.version = Docker::VERSION
|
9
|
+
spec.authors = ['Georg Kunz']
|
10
|
+
spec.email = ['kwd@gmx.ch']
|
11
|
+
spec.description = %q{Docker client}
|
12
|
+
spec.summary = %q{Docker client library to access the Docker remote API.}
|
13
|
+
spec.homepage = 'https://github.com/geku/docker-client'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
spec.required_ruby_version = '>= 1.9'
|
16
|
+
|
17
|
+
spec.files = `git ls-files`.split($/)
|
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.3'
|
23
|
+
spec.add_development_dependency 'rake'
|
24
|
+
spec.add_development_dependency 'rspec', '~> 2.13'
|
25
|
+
spec.add_development_dependency 'vcr', '~> 2.5'
|
26
|
+
spec.add_development_dependency 'webmock', '~> 1.11'
|
27
|
+
spec.add_development_dependency 'activesupport', '~> 3.2.13'
|
28
|
+
|
29
|
+
spec.add_runtime_dependency 'multi_json'
|
30
|
+
spec.add_runtime_dependency 'json'
|
31
|
+
spec.add_runtime_dependency 'curb'
|
32
|
+
spec.add_runtime_dependency 'guard'
|
33
|
+
spec.add_runtime_dependency 'guard-rspec'
|
34
|
+
spec.add_runtime_dependency 'awesome_print'
|
35
|
+
|
36
|
+
# interesting GEMs
|
37
|
+
# https://github.com/intridea/hashie
|
38
|
+
# https://github.com/tcocca/rash
|
39
|
+
|
40
|
+
end
|
data/lib/docker.rb
ADDED
data/lib/docker/api.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'docker/connection'
|
2
|
+
|
3
|
+
module Docker
|
4
|
+
end
|
5
|
+
|
6
|
+
class Docker::API
|
7
|
+
|
8
|
+
attr_reader :connection
|
9
|
+
|
10
|
+
def initialize(options)
|
11
|
+
@debug = options[:debug]
|
12
|
+
@ssl = options[:ssl] || { :verify => false }
|
13
|
+
base_url = options[:base_url]
|
14
|
+
@connection = Docker::Connection.new(base_url: base_url)
|
15
|
+
# @faraday_adapter = options[:faraday_adapter] || Faraday.default_adapter
|
16
|
+
# @faraday = options[:faraday] || default_faraday
|
17
|
+
end
|
18
|
+
|
19
|
+
def containers
|
20
|
+
Docker::Resource::Container.new(@connection)
|
21
|
+
end
|
22
|
+
|
23
|
+
def images
|
24
|
+
Docker::Resource::Image.new(@connection)
|
25
|
+
end
|
26
|
+
|
27
|
+
def system
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'curb'
|
2
|
+
require 'multi_json'
|
3
|
+
|
4
|
+
module Docker
|
5
|
+
end
|
6
|
+
|
7
|
+
class Docker::Connection
|
8
|
+
|
9
|
+
class Response < Struct.new(:body, :status, :content_type, :timeout)
|
10
|
+
def body_as_json
|
11
|
+
MultiJson.load(body)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(options = {})
|
16
|
+
@curl = Curl::Easy.new
|
17
|
+
@base_url = options[:base_url]
|
18
|
+
raise(ArgumentError, ':base_url missing') unless @base_url
|
19
|
+
end
|
20
|
+
|
21
|
+
def get(path, params = {}, headers = {})
|
22
|
+
resp = perform_request(:GET, path, params, nil, headers)
|
23
|
+
raise(Docker::Error::InternalServerError, resp.body) if resp.status == 500
|
24
|
+
resp
|
25
|
+
end
|
26
|
+
|
27
|
+
def post(path, params = {}, body = '', headers = {})
|
28
|
+
resp = perform_request(:POST, path, params, body, headers)
|
29
|
+
raise(Docker::Error::InternalServerError, resp.body) if resp.status == 500
|
30
|
+
resp
|
31
|
+
end
|
32
|
+
|
33
|
+
def delete(path, params = {}, headers = {})
|
34
|
+
resp = perform_request(:DELETE, path, params, nil, headers)
|
35
|
+
raise(Docker::Error::InternalServerError, resp.body) if resp.status == 500
|
36
|
+
resp
|
37
|
+
end
|
38
|
+
|
39
|
+
def stream(path, params = {}, timeout = nil, headers = {}, &block)
|
40
|
+
raise(ArgumentError, 'Block required to handle streaming response') if block.nil?
|
41
|
+
begin
|
42
|
+
timeout_raised = false
|
43
|
+
set_url(path, params)
|
44
|
+
set_headers(headers)
|
45
|
+
@curl.timeout = timeout if timeout
|
46
|
+
@curl.on_body {|data| block.call(data); data.size }
|
47
|
+
@curl.http(:POST)
|
48
|
+
rescue Curl::Err::TimeoutError => e
|
49
|
+
timeout_raised = true
|
50
|
+
end
|
51
|
+
Response.new(@curl.body_str, @curl.response_code, @curl.content_type, timeout_raised)
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def perform_request(verb, path, query_params, body, headers)
|
58
|
+
set_url(path, query_params)
|
59
|
+
set_headers(headers)
|
60
|
+
set_body(body)
|
61
|
+
@curl.http(verb)
|
62
|
+
Response.new(@curl.body_str, @curl.response_code, @curl.content_type)
|
63
|
+
end
|
64
|
+
|
65
|
+
def set_body(body)
|
66
|
+
@curl.post_body = body if body
|
67
|
+
end
|
68
|
+
|
69
|
+
def set_url(path, query_params)
|
70
|
+
params = query_params.collect do |key, value|
|
71
|
+
"#{@curl.escape(key)}=#{@curl.escape(value)}"
|
72
|
+
end
|
73
|
+
param_str = params.empty? ? '' : "?#{params.join('&')}"
|
74
|
+
@curl.url = "#{@base_url}#{path}#{param_str}"
|
75
|
+
end
|
76
|
+
|
77
|
+
def set_headers(headers)
|
78
|
+
headers.each do |key, value|
|
79
|
+
@curl.headers[key] = value
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
data/lib/docker/error.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Docker
|
2
|
+
module Resource
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
class Docker::Resource::Base
|
7
|
+
def initialize(connection)
|
8
|
+
@connection = connection
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
# TODO add all methods to gather all HTTP calls in this superclass
|
14
|
+
# Than it should be easier to replaces it for streaming support
|
15
|
+
def get
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
|
@@ -0,0 +1,131 @@
|
|
1
|
+
|
2
|
+
module Docker
|
3
|
+
module Resource
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
class Docker::Resource::Container < Docker::Resource::Base
|
8
|
+
# TODO set 'Content-Type: application/json'
|
9
|
+
|
10
|
+
# Options
|
11
|
+
# all
|
12
|
+
# limit
|
13
|
+
# since
|
14
|
+
# before
|
15
|
+
def list(options = {})
|
16
|
+
@connection.get('/containers/ps', options).body_as_json
|
17
|
+
end
|
18
|
+
|
19
|
+
def create(command, image = 'base', options = {})
|
20
|
+
command = [command] if command.is_a?(String)
|
21
|
+
body = {'Cmd' => command, 'Image' => image}
|
22
|
+
body = options.merge(body)
|
23
|
+
json_body = MultiJson.dump(body)
|
24
|
+
|
25
|
+
response = @connection.post("/containers/create", {}, json_body, {'Content-Type' => 'application/json'})
|
26
|
+
raise(Docker::Error::NotFoundError) if response.status == 404
|
27
|
+
response.body_as_json
|
28
|
+
end
|
29
|
+
|
30
|
+
# inspect is a Ruby internal method that should not be overwritten
|
31
|
+
# therefore we use show as it displays the container details
|
32
|
+
def show(container_id)
|
33
|
+
@connection.get("/containers/#{container_id}/json").body_as_json
|
34
|
+
end
|
35
|
+
|
36
|
+
def changes(container_id)
|
37
|
+
@connection.get("/containers/#{container_id}/changes").body_as_json
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns a stream
|
41
|
+
def export
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
def start(container_id)
|
46
|
+
status = @connection.post("/containers/#{container_id}/start").status
|
47
|
+
raise_if_container_not_found(status)
|
48
|
+
status == 204
|
49
|
+
end
|
50
|
+
|
51
|
+
def stop(container_id, timeout = nil)
|
52
|
+
params = {}
|
53
|
+
params['t'] = timeout if timeout
|
54
|
+
status = @connection.post("/containers/#{container_id}/stop", params).status
|
55
|
+
raise_if_container_not_found(status)
|
56
|
+
status == 204
|
57
|
+
end
|
58
|
+
|
59
|
+
def restart(container_id, timeout = nil)
|
60
|
+
params = {}
|
61
|
+
params['t'] = timeout if timeout
|
62
|
+
status = @connection.post("/containers/#{container_id}/restart", params).status
|
63
|
+
raise_if_container_not_found(status)
|
64
|
+
status == 204
|
65
|
+
end
|
66
|
+
|
67
|
+
def kill(container_id)
|
68
|
+
status = @connection.post("/containers/#{container_id}/kill").status
|
69
|
+
raise_if_container_not_found(status)
|
70
|
+
status == 204
|
71
|
+
end
|
72
|
+
|
73
|
+
# Valid options:
|
74
|
+
# stdout true default is false
|
75
|
+
# stderr true default is false
|
76
|
+
def attach(container_id, options = {}, timeout = nil, &block)
|
77
|
+
raise(ArgumentError, "Block must be given to handle streamed data") if block.nil?
|
78
|
+
options = {stdout: true, stderr: true} if options.empty?
|
79
|
+
options = options.merge(stream: true, logs: false)
|
80
|
+
|
81
|
+
response = @connection.stream("/containers/#{container_id}/attach", options, timeout, {}, &block)
|
82
|
+
raise_if_container_not_found(response.status)
|
83
|
+
raise(BadParameterError) if response.status == 400
|
84
|
+
response
|
85
|
+
end
|
86
|
+
|
87
|
+
def logs(container_id, options = {})
|
88
|
+
options = {stdout: true, stderr: true} if options.empty?
|
89
|
+
options = options.merge(logs: true, stream: false)
|
90
|
+
|
91
|
+
response = @connection.post("/containers/#{container_id}/attach", options)
|
92
|
+
raise_if_container_not_found(response.status)
|
93
|
+
raise(BadParameterError) if response.status == 400
|
94
|
+
response.body
|
95
|
+
end
|
96
|
+
|
97
|
+
# Blocks until container exits
|
98
|
+
def wait(container_id)
|
99
|
+
response = @connection.post("/containers/#{container_id}/wait")
|
100
|
+
raise_if_container_not_found(response.status)
|
101
|
+
response.body_as_json
|
102
|
+
end
|
103
|
+
|
104
|
+
# Options:
|
105
|
+
# v remove volumes of container
|
106
|
+
def remove(container_id, delete_volumes = false)
|
107
|
+
params = {v: delete_volumes}
|
108
|
+
status = @connection.delete("/containers/#{container_id}", params).status
|
109
|
+
raise_if_container_not_found(status)
|
110
|
+
status == 204
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def raise_if_container_not_found(status)
|
116
|
+
raise(Docker::Error::ContainerNotFound) if status == 404
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
|
124
|
+
|
125
|
+
|
126
|
+
|
127
|
+
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
|