docker-compose 0.6.1 → 0.7.0
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/.rubocop.yml +35 -0
- data/Gemfile +4 -1
- data/README.md +12 -7
- data/Rakefile +4 -3
- data/bin/console +15 -11
- data/docker-compose.gemspec +13 -13
- data/docker-compose.yml +6 -0
- data/lib/docker/compose.rb +5 -0
- data/lib/docker/compose/collection.rb +13 -0
- data/lib/docker/compose/container.rb +70 -0
- data/lib/docker/compose/error.rb +12 -2
- data/lib/docker/compose/mapper.rb +11 -6
- data/lib/docker/compose/net_info.rb +4 -3
- data/lib/docker/compose/rake_tasks.rb +14 -15
- data/lib/docker/compose/session.rb +84 -10
- data/lib/docker/compose/shell_printer.rb +6 -1
- data/lib/docker/compose/shell_printer/fish.rb +1 -0
- data/lib/docker/compose/shell_printer/posix.rb +2 -1
- data/lib/docker/compose/version.rb +2 -1
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 76d9302ebcd4e76f964dd3f7b85b65cfe6ab0f22
|
|
4
|
+
data.tar.gz: 0d62eabe174c7b93d7a80d120287550e48031457
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ea304f03ad24a904e99af6ce03241f4553cb05cef8876b508c641cc69e05ff7cf7b055dcb7e8ab599069736f3eb597933d97daa1c8915cdea73b0bf9bc40b102
|
|
7
|
+
data.tar.gz: ee9da68c8abe02a2430959bc238c4d79c456da0ae7c7089daf01e5f3db00049afa11f84e597cad3e53b77feae55b9686f00d4c46f1fdeabf0ea56d010cca1c4a
|
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# CODING CONVENTIONS
|
|
2
|
+
# - any cop that can be auto-corrected with `rubocop -a` is mandatory
|
|
3
|
+
# - other cops may be enabled if committer fixes all issues
|
|
4
|
+
AllCops:
|
|
5
|
+
Exclude:
|
|
6
|
+
- features/**/*
|
|
7
|
+
- spec/**/*
|
|
8
|
+
Style/Encoding:
|
|
9
|
+
Enabled: true
|
|
10
|
+
Style/FormatString:
|
|
11
|
+
Enabled: false
|
|
12
|
+
Style/GuardClause:
|
|
13
|
+
Enabled: false
|
|
14
|
+
Lint/AmbiguousRegexpLiteral:
|
|
15
|
+
Enabled: false
|
|
16
|
+
Metrics/AbcSize:
|
|
17
|
+
Enabled: false
|
|
18
|
+
Metrics/ClassLength:
|
|
19
|
+
Enabled: false
|
|
20
|
+
Metrics/LineLength:
|
|
21
|
+
Enabled: false
|
|
22
|
+
Metrics/MethodLength:
|
|
23
|
+
Enabled: false
|
|
24
|
+
Metrics/CyclomaticComplexity:
|
|
25
|
+
Enabled: false
|
|
26
|
+
Metrics/PerceivedComplexity:
|
|
27
|
+
Enabled: false
|
|
28
|
+
Style/ClassAndModuleChildren:
|
|
29
|
+
Enabled: false
|
|
30
|
+
Style/Documentation:
|
|
31
|
+
Enabled: false
|
|
32
|
+
Style/RaiseArgs:
|
|
33
|
+
Enabled: false
|
|
34
|
+
Style/Semicolon:
|
|
35
|
+
Enabled: false
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -6,11 +6,10 @@ container orchestration tool from Docker Inc.
|
|
|
6
6
|
In addition to wrapping the CLI, this gem provides an environment-variable mapping
|
|
7
7
|
feature that allows you to export environment variables into your _host_ that point
|
|
8
8
|
to network services exposed by containers. This allows you to run an application on
|
|
9
|
-
your host for quicker and easier development, but run all of its
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
port exposed by a container.
|
|
9
|
+
your host for quicker and easier development, but run all of its dependencies --
|
|
10
|
+
database, cache, adjacent services -- in containers. The dependencies can even run
|
|
11
|
+
on another machine, e.g. a cloud instance or a container cluster, provided your
|
|
12
|
+
development machine has TCP connectivity to every port exposed by a container.
|
|
14
13
|
|
|
15
14
|
Throughout this documentation we will refer to this gem as `Docker::Compose`
|
|
16
15
|
as opposed to the `docker-compose` tool that this gem wraps.
|
|
@@ -45,6 +44,12 @@ compose = Docker::Compose.new
|
|
|
45
44
|
compose.version
|
|
46
45
|
|
|
47
46
|
compose.up(detached:true)
|
|
47
|
+
|
|
48
|
+
exited = compose.ps.where { |c| !c.up? }
|
|
49
|
+
puts "We have some exited containers: " + exited.join(', ')
|
|
50
|
+
|
|
51
|
+
sum = compose.ps.inject(0) { |a,c| a + c.size }
|
|
52
|
+
puts format("Composition is using %.1f MiB disk space", sum/1024.0**2)
|
|
48
53
|
```
|
|
49
54
|
|
|
50
55
|
### Invoking from Rake
|
|
@@ -62,7 +67,7 @@ end
|
|
|
62
67
|
```
|
|
63
68
|
|
|
64
69
|
Notice that `rake -T` now has a few additional tasks for invoking gem
|
|
65
|
-
functionality. You can `docker:compose:env` print shell exports for
|
|
70
|
+
functionality. You can `docker:compose:env` to print shell exports for
|
|
66
71
|
host-to-container environment mapping, or you can `docker:compose:host[foo]`.
|
|
67
72
|
|
|
68
73
|
### Hosting a Command
|
|
@@ -71,7 +76,7 @@ To run a process on your host and allow it to talk to containers, use
|
|
|
71
76
|
the `docker:compose:host` task. For example, I could enter a shell
|
|
72
77
|
with `rake docker:compose:host[bash]`.
|
|
73
78
|
|
|
74
|
-
Before "hosting" your command, the Rake task
|
|
79
|
+
Before "hosting" your command, the Rake task exports some environment
|
|
75
80
|
variables that your command can use to discover services running in
|
|
76
81
|
containers. Your Rakefile specifies which variables your app needs
|
|
77
82
|
(the `host_env` option) and which container information each variable should
|
data/Rakefile
CHANGED
data/bin/console
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
#! /usr/bin/env ruby
|
|
2
|
+
# encoding: utf-8
|
|
2
3
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
4
|
+
require 'bundler/setup'
|
|
5
|
+
require 'docker/compose'
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
# with your gem easier. You can also use a different console, if you like.
|
|
7
|
+
@session = Docker::Compose::Session.new
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
require
|
|
14
|
-
IRB.
|
|
9
|
+
begin
|
|
10
|
+
require 'pry'
|
|
11
|
+
Pry.start(@session)
|
|
12
|
+
rescue LoadError
|
|
13
|
+
require 'irb'
|
|
14
|
+
IRB.setup nil
|
|
15
|
+
IRB.conf[:MAIN_CONTEXT] = IRB::Irb.new.context
|
|
16
|
+
require 'irb/ext/multi-irb'
|
|
17
|
+
IRB.irb nil, @session
|
|
18
|
+
end
|
data/docker-compose.gemspec
CHANGED
|
@@ -4,24 +4,24 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
|
4
4
|
require 'docker/compose/version'
|
|
5
5
|
|
|
6
6
|
Gem::Specification.new do |spec|
|
|
7
|
-
spec.name =
|
|
7
|
+
spec.name = 'docker-compose'
|
|
8
8
|
spec.version = Docker::Compose::VERSION
|
|
9
|
-
spec.authors = [
|
|
10
|
-
spec.email = [
|
|
9
|
+
spec.authors = ['Tony Spataro']
|
|
10
|
+
spec.email = ['xeger@xeger.net']
|
|
11
11
|
|
|
12
|
-
spec.summary =
|
|
13
|
-
spec.description =
|
|
14
|
-
spec.homepage =
|
|
15
|
-
spec.license =
|
|
12
|
+
spec.summary = 'Wrapper docker-compose with added Rake smarts.'
|
|
13
|
+
spec.description = 'Provides an OOP interface to docker-compose and facilitates container-to-host and host-to-container networking.'
|
|
14
|
+
spec.homepage = 'https://github.com/xeger/docker-compose'
|
|
15
|
+
spec.license = 'MIT'
|
|
16
16
|
|
|
17
17
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
18
|
-
spec.bindir =
|
|
18
|
+
spec.bindir = 'exe'
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
20
|
-
spec.require_paths = [
|
|
20
|
+
spec.require_paths = ['lib']
|
|
21
21
|
|
|
22
|
-
spec.add_dependency
|
|
22
|
+
spec.add_dependency 'backticks', '~> 0.4'
|
|
23
23
|
|
|
24
|
-
spec.add_development_dependency
|
|
25
|
-
spec.add_development_dependency
|
|
26
|
-
spec.add_development_dependency
|
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1.10'
|
|
25
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
|
26
|
+
spec.add_development_dependency 'rspec'
|
|
27
27
|
end
|
data/docker-compose.yml
ADDED
data/lib/docker/compose.rb
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
require 'net/http'
|
|
3
|
+
|
|
1
4
|
require_relative 'compose/version'
|
|
2
5
|
require_relative 'compose/error'
|
|
6
|
+
require_relative 'compose/container'
|
|
7
|
+
require_relative 'compose/collection'
|
|
3
8
|
require_relative 'compose/session'
|
|
4
9
|
require_relative 'compose/net_info'
|
|
5
10
|
require_relative 'compose/mapper'
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Docker::Compose
|
|
2
|
+
class Collection < Array
|
|
3
|
+
# @example find containers that are up
|
|
4
|
+
# who_is_up = coll.where { |c| c.up? }
|
|
5
|
+
# @example count space taken by all containers
|
|
6
|
+
# coll.map { |c| c.size }.inject(0) { |a, x| a + x }
|
|
7
|
+
def where
|
|
8
|
+
hits = Collection.new
|
|
9
|
+
self.each { |c| hits << c if yield(c) }
|
|
10
|
+
hits
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module Docker::Compose
|
|
2
|
+
class Container
|
|
3
|
+
# Format string for `docker ps`
|
|
4
|
+
PS_FMT = '({{.ID}}) ({{.Image}}) ({{.Size}}) ({{.Status}}) ({{.Names}}) ({{.Labels}}) ({{.Ports}})'
|
|
5
|
+
# Number of template substitutions in PS_FMT
|
|
6
|
+
PS_FMT_LEN = PS_FMT.count('.')
|
|
7
|
+
# Pattern that parses human-readable values from ps .Status
|
|
8
|
+
PS_STATUS = /^([A-Za-z]+) ?\(?([0-9]*)\)? ?(.*)$/i
|
|
9
|
+
|
|
10
|
+
attr_reader :id, :image, :size, :status, :exitstatus
|
|
11
|
+
attr_reader :names, :labels, :ports
|
|
12
|
+
|
|
13
|
+
# @param [String] id
|
|
14
|
+
# @param [String] image
|
|
15
|
+
# @param [String,Numeric] size
|
|
16
|
+
# @param [String,#map] status e.g. ['Exited', '0', '3 minutes ago']
|
|
17
|
+
# @param [String,Array] names list of container names (CSV)
|
|
18
|
+
# @param [String,Array] labels list of container labels (CSV)
|
|
19
|
+
# @param [String,Array] ports list of exposed ports (CSV)
|
|
20
|
+
def initialize(id, image, size, status, names, labels, ports)
|
|
21
|
+
if size.is_a?(String)
|
|
22
|
+
scalar, units = size.split(' ')
|
|
23
|
+
scalar = size[0].to_i # lazy: invalid --> 0
|
|
24
|
+
mult = case units.downcase
|
|
25
|
+
when 'b' then 1
|
|
26
|
+
when 'kb' then 1_024
|
|
27
|
+
when 'mb' then 1_024^2
|
|
28
|
+
when 'gb' then 1_024^3
|
|
29
|
+
when 'tb' then 1_024^4
|
|
30
|
+
else
|
|
31
|
+
raise Error.new('Service#new', units, 'Impossibly large unit')
|
|
32
|
+
end
|
|
33
|
+
size = scalar * mult
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
if status.is_a?(String)
|
|
37
|
+
status = PS_STATUS.match(status)
|
|
38
|
+
raise Error.new('Service#new', status, 'Unrecognized status') unless status
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
names = names.split(',') if names.is_a?(String)
|
|
42
|
+
labels = labels.split(',') if labels.is_a?(String)
|
|
43
|
+
ports = ports.split(',') if ports.is_a?(String)
|
|
44
|
+
|
|
45
|
+
@id = id
|
|
46
|
+
@image = image
|
|
47
|
+
@size = size
|
|
48
|
+
@status = status[1].downcase.to_sym
|
|
49
|
+
@exitstatus = !status[2].empty? && status[2].to_i # sloppy!
|
|
50
|
+
@names = names
|
|
51
|
+
@labels = labels
|
|
52
|
+
@ports = ports
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# static sanity checking ftw!
|
|
56
|
+
unless ( initarity = instance_method(:initialize).arity ) == ( psfmtcnt = PS_FMT.count('.') )
|
|
57
|
+
raise LoadError.new("#{__FILE__}:#{__LINE__} - arity(\#initialize) != len(PS_FMT); #{initarity} != #{psfmtcnt}")
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# @return [String]
|
|
61
|
+
def name
|
|
62
|
+
names.first
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# @return [Boolean]
|
|
66
|
+
def up?
|
|
67
|
+
self.status == :up
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
data/lib/docker/compose/error.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
1
2
|
module Docker::Compose
|
|
2
3
|
class Error < RuntimeError
|
|
3
4
|
attr_reader :status, :detail
|
|
@@ -8,9 +9,18 @@ module Docker::Compose
|
|
|
8
9
|
def initialize(cmd, status, detail)
|
|
9
10
|
@status = status
|
|
10
11
|
@detail = detail
|
|
12
|
+
|
|
11
13
|
brief = detail.split("\n").first || '(no output)'
|
|
12
|
-
|
|
14
|
+
|
|
15
|
+
case status
|
|
16
|
+
when Numeric
|
|
17
|
+
status = status.to_s
|
|
18
|
+
else
|
|
19
|
+
status = "'#{status}'"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
message = format("'%s' failed with status %s: %s", cmd, status, brief)
|
|
13
23
|
super(message)
|
|
14
24
|
end
|
|
15
25
|
end
|
|
16
|
-
end
|
|
26
|
+
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
1
2
|
module Docker::Compose
|
|
2
3
|
# Uses a Session to discover information about services' IP addresses and
|
|
3
4
|
# ports as reachable from the host, then
|
|
@@ -31,7 +32,7 @@ module Docker::Compose
|
|
|
31
32
|
override_host = net_info.docker_routable_ip
|
|
32
33
|
end
|
|
33
34
|
|
|
34
|
-
mapper =
|
|
35
|
+
mapper = new(session, override_host)
|
|
35
36
|
env.each_pair do |k, v|
|
|
36
37
|
begin
|
|
37
38
|
v = mapper.map(v)
|
|
@@ -46,7 +47,7 @@ module Docker::Compose
|
|
|
46
47
|
# @param [Docker::Compose::Session] session
|
|
47
48
|
# @param [String] override_host forcible address or DNS hostname to use;
|
|
48
49
|
# leave nil to trust docker-compose output.
|
|
49
|
-
def initialize(session, override_host=nil)
|
|
50
|
+
def initialize(session, override_host = nil)
|
|
50
51
|
@session = session
|
|
51
52
|
@override_host = override_host
|
|
52
53
|
end
|
|
@@ -93,7 +94,7 @@ module Docker::Compose
|
|
|
93
94
|
host, port = result.split(':')
|
|
94
95
|
host = @override_host if @override_host
|
|
95
96
|
[host, Integer(port)]
|
|
96
|
-
rescue RuntimeError
|
|
97
|
+
rescue RuntimeError, TypeError
|
|
97
98
|
raise NoService, "Service '#{service}' not running, or does not publish port '#{port}'"
|
|
98
99
|
end
|
|
99
100
|
|
|
@@ -102,7 +103,11 @@ module Docker::Compose
|
|
|
102
103
|
# @param [String] value
|
|
103
104
|
# @return [String]
|
|
104
105
|
private def map_scalar(value)
|
|
105
|
-
uri =
|
|
106
|
+
uri = begin
|
|
107
|
+
URI.parse(value)
|
|
108
|
+
rescue
|
|
109
|
+
nil
|
|
110
|
+
end
|
|
106
111
|
pair = value.split(':')
|
|
107
112
|
|
|
108
113
|
if uri && uri.scheme && uri.host
|
|
@@ -121,7 +126,7 @@ module Docker::Compose
|
|
|
121
126
|
# the service is running.
|
|
122
127
|
service = pair.first
|
|
123
128
|
port = pair.last.gsub(REMOVE_ELIDED, '')
|
|
124
|
-
host,
|
|
129
|
+
host, = host_and_port(service, port)
|
|
125
130
|
return host
|
|
126
131
|
else
|
|
127
132
|
# output port:hostname pair
|
|
@@ -129,7 +134,7 @@ module Docker::Compose
|
|
|
129
134
|
return "#{host}:#{port}"
|
|
130
135
|
end
|
|
131
136
|
else
|
|
132
|
-
|
|
137
|
+
fail BadSubstitution, "Can't understand '#{value}'"
|
|
133
138
|
end
|
|
134
139
|
end
|
|
135
140
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
1
2
|
module Docker::Compose
|
|
2
3
|
# Utility that gathers information about the relationship between the host
|
|
3
4
|
# on which the Ruby VM is running and the docker host, then makes an
|
|
@@ -23,8 +24,8 @@ module Docker::Compose
|
|
|
23
24
|
# Create a new instance of this class.
|
|
24
25
|
# @param [String] docker_host a URI pointing to the docker host
|
|
25
26
|
# @param [Array] list of String dotted-quad IPv4 addresses of local host
|
|
26
|
-
def initialize(docker_host=ENV['DOCKER_HOST'],
|
|
27
|
-
my_ips=self.class.ipv4_interfaces)
|
|
27
|
+
def initialize(docker_host = ENV['DOCKER_HOST'],
|
|
28
|
+
my_ips = self.class.ipv4_interfaces)
|
|
28
29
|
docker_host ||= 'unix:/var/run/docker.sock'
|
|
29
30
|
@docker_url = URI.parse(docker_host)
|
|
30
31
|
@my_ips = my_ips
|
|
@@ -39,7 +40,7 @@ module Docker::Compose
|
|
|
39
40
|
#
|
|
40
41
|
# @return [String] IPv4 address of host machine that _may_ be reachable from
|
|
41
42
|
# Docker machine
|
|
42
|
-
def host_routable_ip(target_ip=docker_routable_ip)
|
|
43
|
+
def host_routable_ip(target_ip = docker_routable_ip)
|
|
43
44
|
best_match = ''
|
|
44
45
|
best_prefix = 0
|
|
45
46
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
1
2
|
require 'json'
|
|
2
3
|
require 'rake/tasklib'
|
|
3
4
|
require 'shellwords'
|
|
@@ -63,7 +64,7 @@ module Docker::Compose
|
|
|
63
64
|
yield self if block_given?
|
|
64
65
|
|
|
65
66
|
@shell = Backticks::Runner.new
|
|
66
|
-
@session = Docker::Compose::Session.new(@shell, dir:dir, file:file)
|
|
67
|
+
@session = Docker::Compose::Session.new(@shell, dir: dir, file: file)
|
|
67
68
|
@net_info = Docker::Compose::NetInfo.new
|
|
68
69
|
@shell_printer = Docker::Compose::ShellPrinter.new
|
|
69
70
|
|
|
@@ -73,7 +74,7 @@ module Docker::Compose
|
|
|
73
74
|
end
|
|
74
75
|
|
|
75
76
|
private def define
|
|
76
|
-
namespace
|
|
77
|
+
namespace rake_namespace do
|
|
77
78
|
desc 'Print bash exports with IP/ports of running services'
|
|
78
79
|
task :env do
|
|
79
80
|
@shell.interactive = false # suppress useless 'port' output
|
|
@@ -85,18 +86,17 @@ module Docker::Compose
|
|
|
85
86
|
# how we intend it to be used.
|
|
86
87
|
print_usage if tty && tlt
|
|
87
88
|
|
|
88
|
-
export_env(print:tlt)
|
|
89
|
+
export_env(print: tlt)
|
|
89
90
|
|
|
90
91
|
@shell.interactive = true
|
|
91
92
|
end
|
|
92
93
|
|
|
93
94
|
desc 'Run command on host, linked to services in containers'
|
|
94
|
-
task :host, [:command] => ['docker:compose:env'] do |
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
@session.up(*self.host_services, detached:true)
|
|
95
|
+
task :host, [:command] => ['docker:compose:env'] do |_task, args|
|
|
96
|
+
if host_services
|
|
97
|
+
@session.up(*host_services, detached: true)
|
|
98
98
|
else
|
|
99
|
-
@session.up(detached:true)
|
|
99
|
+
@session.up(detached: true)
|
|
100
100
|
end
|
|
101
101
|
|
|
102
102
|
exec(args[:command])
|
|
@@ -108,14 +108,14 @@ module Docker::Compose
|
|
|
108
108
|
# published by docker-compose services. Optionally also print bash export
|
|
109
109
|
# statements so this information can be made available to a user's shell.
|
|
110
110
|
private def export_env(print:)
|
|
111
|
-
Docker::Compose::Mapper.map(
|
|
112
|
-
session
|
|
113
|
-
net_info
|
|
111
|
+
Docker::Compose::Mapper.map(host_env,
|
|
112
|
+
session: @session,
|
|
113
|
+
net_info: @net_info) do |k, v|
|
|
114
114
|
ENV[k] = serialize_for_env(v)
|
|
115
115
|
print_env(k, ENV[k]) if print
|
|
116
116
|
end
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
extra_host_env.each do |k, v|
|
|
119
119
|
ENV[k] = serialize_for_env(v)
|
|
120
120
|
print_env(k, ENV[k]) if print
|
|
121
121
|
end
|
|
@@ -133,7 +133,7 @@ module Docker::Compose
|
|
|
133
133
|
when Array
|
|
134
134
|
JSON.dump(v)
|
|
135
135
|
else
|
|
136
|
-
|
|
136
|
+
fail ArgumentError, "Can't represent a #{v.class} in the environment"
|
|
137
137
|
end
|
|
138
138
|
end
|
|
139
139
|
|
|
@@ -146,10 +146,9 @@ module Docker::Compose
|
|
|
146
146
|
end
|
|
147
147
|
end
|
|
148
148
|
|
|
149
|
-
|
|
150
149
|
private def print_usage
|
|
151
150
|
command = "rake #{rake_namespace}:env"
|
|
152
|
-
command =
|
|
151
|
+
command = 'bundle exec ' + command if defined?(Bundler)
|
|
153
152
|
puts @shell_printer.comment('To export these variables to your shell, run:')
|
|
154
153
|
puts @shell_printer.comment(@shell_printer.eval_output(command))
|
|
155
154
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
1
2
|
require 'backticks'
|
|
2
3
|
require 'yaml'
|
|
3
4
|
|
|
@@ -16,7 +17,7 @@ module Docker::Compose
|
|
|
16
17
|
class Session
|
|
17
18
|
attr_reader :dir, :file
|
|
18
19
|
|
|
19
|
-
def initialize(shell=Backticks::Runner.new(interactive:true),
|
|
20
|
+
def initialize(shell = Backticks::Runner.new(interactive: true),
|
|
20
21
|
dir:Dir.pwd, file:'docker-compose.yml')
|
|
21
22
|
@shell = shell
|
|
22
23
|
@dir = dir
|
|
@@ -40,6 +41,23 @@ module Docker::Compose
|
|
|
40
41
|
true
|
|
41
42
|
end
|
|
42
43
|
|
|
44
|
+
def ps()
|
|
45
|
+
inter = @shell.interactive
|
|
46
|
+
@shell.interactive = false
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
lines = run!('ps', q:true).split(/[\r\n]+/)
|
|
50
|
+
containers = Collection.new
|
|
51
|
+
|
|
52
|
+
lines.each do |id|
|
|
53
|
+
containers << docker_ps(id)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
containers
|
|
57
|
+
ensure
|
|
58
|
+
@shell.interactive = inter
|
|
59
|
+
end
|
|
60
|
+
|
|
43
61
|
# Idempotently up the given services in the project.
|
|
44
62
|
# @param [Array] services list of String service names to run
|
|
45
63
|
# @param [Boolean] detached if true, to start services in the background;
|
|
@@ -54,12 +72,16 @@ module Docker::Compose
|
|
|
54
72
|
def up(*services,
|
|
55
73
|
detached:false, timeout:10, no_build:false, no_deps:false)
|
|
56
74
|
run!('up',
|
|
57
|
-
{d:detached, timeout:timeout, no_build:no_build, no_deps:no_deps},
|
|
75
|
+
{ d: detached, timeout: timeout, no_build: no_build, no_deps: no_deps },
|
|
58
76
|
services)
|
|
59
77
|
true
|
|
60
78
|
end
|
|
61
79
|
|
|
62
|
-
|
|
80
|
+
def rm(*services, force:false, volumes:false, all:true)
|
|
81
|
+
run!('rm', { f: force, v: volumes, a: all }, services)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Idempotently run an arbitrary command with a service container.
|
|
63
85
|
# @param [String] service name to run
|
|
64
86
|
# @param [String] cmd command statement to run
|
|
65
87
|
# @param [Boolean] detached if true, to start services in the background;
|
|
@@ -70,9 +92,9 @@ module Docker::Compose
|
|
|
70
92
|
# @param [Boolean] rm remove the container when done
|
|
71
93
|
# @raise [Error] if command fails
|
|
72
94
|
def run(service, *cmd, detached:false, no_deps:false, env_vars:[], rm:false)
|
|
73
|
-
formated_vars = env_vars.map{|v| {e: v}}
|
|
95
|
+
formated_vars = env_vars.map { |v| { e: v } }
|
|
74
96
|
run!('run',
|
|
75
|
-
{d:detached, no_deps:no_deps, rm:rm}, *formated_vars, service, cmd)
|
|
97
|
+
{ d: detached, no_deps: no_deps, rm: rm }, *formated_vars, service, cmd)
|
|
76
98
|
end
|
|
77
99
|
|
|
78
100
|
# Stop running services.
|
|
@@ -80,7 +102,7 @@ module Docker::Compose
|
|
|
80
102
|
# @param [Integer] timeout how long to wait for each service to stop
|
|
81
103
|
# @raise [Error] if command fails
|
|
82
104
|
def stop(*services, timeout:10)
|
|
83
|
-
run!('stop', {timeout:timeout}, services)
|
|
105
|
+
run!('stop', { timeout: timeout }, services)
|
|
84
106
|
end
|
|
85
107
|
|
|
86
108
|
# Figure out which host a port a given service port has been published to.
|
|
@@ -90,7 +112,7 @@ module Docker::Compose
|
|
|
90
112
|
# @param [Integer] index of container (if multiple instances running)
|
|
91
113
|
# @raise [Error] if command fails
|
|
92
114
|
def port(service, port, protocol:'tcp', index:1)
|
|
93
|
-
run!('port', {protocol:protocol, index:index}, service, port)
|
|
115
|
+
run!('port', { protocol: protocol, index: index }, service, port)
|
|
94
116
|
end
|
|
95
117
|
|
|
96
118
|
# Determine the installed version of docker-compose.
|
|
@@ -99,7 +121,7 @@ module Docker::Compose
|
|
|
99
121
|
# otherwise, returns a Hash of component-name strings to version strings
|
|
100
122
|
# @raise [Error] if command fails
|
|
101
123
|
def version(short:false)
|
|
102
|
-
result = run!('version', short:short, file:false, dir:false)
|
|
124
|
+
result = run!('version', short: short, file: false, dir: false)
|
|
103
125
|
|
|
104
126
|
if short
|
|
105
127
|
result.strip
|
|
@@ -129,10 +151,62 @@ module Docker::Compose
|
|
|
129
151
|
|
|
130
152
|
Dir.chdir(@dir) do
|
|
131
153
|
cmd = @shell.run('docker-compose', project_opts, *args).join
|
|
132
|
-
status
|
|
133
|
-
|
|
154
|
+
status = cmd.status
|
|
155
|
+
out = cmd.captured_output
|
|
156
|
+
err = cmd.captured_error
|
|
157
|
+
status.success? || fail(Error.new(args.first, status, err))
|
|
134
158
|
out
|
|
135
159
|
end
|
|
136
160
|
end
|
|
161
|
+
|
|
162
|
+
private
|
|
163
|
+
|
|
164
|
+
def docker_ps(id)
|
|
165
|
+
cmd = @shell.run('docker', 'ps', a:true, f:"id=#{id}", format:Container::PS_FMT).join
|
|
166
|
+
status, out, err = cmd.status, cmd.captured_output, cmd.captured_error
|
|
167
|
+
raise Error.new('docker ps', status, "Unexpected output") unless status.success?
|
|
168
|
+
lines = out.split(/[\r\n]+/)
|
|
169
|
+
return nil if lines.empty?
|
|
170
|
+
l = lines.shift
|
|
171
|
+
m = parse(l)
|
|
172
|
+
raise Error.new('docker ps', status, "Cannot parse output: '#{l}'") unless m
|
|
173
|
+
return Container.new(*m)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# parse values enclosed within parentheses; values may contain nested
|
|
177
|
+
# matching pairs of parentheses
|
|
178
|
+
def parse(str)
|
|
179
|
+
fields = []
|
|
180
|
+
nest = 0
|
|
181
|
+
field = ''
|
|
182
|
+
str.each_char do |ch|
|
|
183
|
+
got = false
|
|
184
|
+
if nest == 0
|
|
185
|
+
if ch == '('
|
|
186
|
+
nest += 1
|
|
187
|
+
end
|
|
188
|
+
else
|
|
189
|
+
if ch == '('
|
|
190
|
+
nest += 1
|
|
191
|
+
elsif ch == ')'
|
|
192
|
+
nest -= 1
|
|
193
|
+
if nest == 0
|
|
194
|
+
got = true
|
|
195
|
+
else
|
|
196
|
+
field << ch
|
|
197
|
+
end
|
|
198
|
+
else
|
|
199
|
+
field << ch
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
if got
|
|
204
|
+
fields << field
|
|
205
|
+
field = ''
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
fields
|
|
210
|
+
end
|
|
137
211
|
end
|
|
138
212
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
1
2
|
require 'etc'
|
|
2
3
|
|
|
3
4
|
module Docker::Compose
|
|
@@ -10,7 +11,11 @@ module Docker::Compose
|
|
|
10
11
|
basename[0] = basename[0].upcase
|
|
11
12
|
|
|
12
13
|
# Find adapter class named after shell; default to posix if nothing found
|
|
13
|
-
klass =
|
|
14
|
+
klass = begin
|
|
15
|
+
const_get(basename.to_sym)
|
|
16
|
+
rescue
|
|
17
|
+
Posix
|
|
18
|
+
end
|
|
14
19
|
|
|
15
20
|
klass.new
|
|
16
21
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: docker-compose
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tony Spataro
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2016-
|
|
11
|
+
date: 2016-06-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: backticks
|
|
@@ -76,6 +76,7 @@ extra_rdoc_files: []
|
|
|
76
76
|
files:
|
|
77
77
|
- ".gitignore"
|
|
78
78
|
- ".rspec"
|
|
79
|
+
- ".rubocop.yml"
|
|
79
80
|
- ".ruby-version"
|
|
80
81
|
- ".travis.yml"
|
|
81
82
|
- CHANGELOG.md
|
|
@@ -87,7 +88,10 @@ files:
|
|
|
87
88
|
- bin/console
|
|
88
89
|
- bin/setup
|
|
89
90
|
- docker-compose.gemspec
|
|
91
|
+
- docker-compose.yml
|
|
90
92
|
- lib/docker/compose.rb
|
|
93
|
+
- lib/docker/compose/collection.rb
|
|
94
|
+
- lib/docker/compose/container.rb
|
|
91
95
|
- lib/docker/compose/error.rb
|
|
92
96
|
- lib/docker/compose/mapper.rb
|
|
93
97
|
- lib/docker/compose/net_info.rb
|