docker-compose 0.0.0 → 0.1.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 +5 -5
- data/.ruby-version +1 -1
- data/.travis.yml +1 -5
- data/Gemfile +1 -9
- data/README.md +44 -60
- data/Rakefile +3 -4
- data/bin/console +11 -15
- data/docker-compose.gemspec +12 -16
- data/lib/docker/compose/future/session.rb +90 -0
- data/lib/docker/compose/mapper.rb +35 -99
- data/lib/docker/compose/net_info.rb +5 -6
- data/lib/docker/compose/rake_tasks.rb +98 -111
- data/lib/docker/compose/session.rb +39 -280
- data/lib/docker/compose/shell.rb +165 -0
- data/lib/docker/compose/version.rb +1 -2
- data/lib/docker/compose.rb +2 -7
- metadata +9 -34
- data/.coveralls.yml +0 -1
- data/.github/workflows/publish.yml +0 -42
- data/.rubocop.yml +0 -38
- data/CHANGELOG.md +0 -32
- data/docker-compose.yml +0 -11
- data/lib/docker/compose/collection.rb +0 -13
- data/lib/docker/compose/container.rb +0 -80
- data/lib/docker/compose/error.rb +0 -26
- data/lib/docker/compose/shell_printer/fish.rb +0 -17
- data/lib/docker/compose/shell_printer/posix.rb +0 -33
- data/lib/docker/compose/shell_printer.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a06d21989982bb658ca42414f0a20e6e511263f6
|
4
|
+
data.tar.gz: 94d12b911c12197da022fe880548d68f80225182
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 400d618d335ebb064edccbb21f074c66d1b5e82ba4b6f5a93b69ac1227cab19438df7e23ea94529f40f5598405fcd4834234881ffdc011a7c00f0d00d0467919
|
7
|
+
data.tar.gz: 180aac4998d6a1ed559f006a617a987e0ea61aa0904c9030de8ba9698f23f254b08ee907aa613b12ca79f1863a61e761668388f1e4f6d8efa816bf6b13d7b6d9
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.2.2
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,17 +1,18 @@
|
|
1
|
-
[](https://travis-ci.org/xeger/docker-compose) [](https://coveralls.io/github/xeger/docker-compose?branch=coveralls) [](http://www.rubydoc.info/gems/docker-compose)
|
2
|
-
|
3
1
|
# Docker::Compose
|
4
2
|
|
5
3
|
This is a Ruby OOP wrapper for the [docker-compose](https://github.com/docker/compose)
|
6
|
-
container orchestration tool from Docker Inc.
|
4
|
+
container orchestration tool from Docker Inc. It also contains some features that
|
5
|
+
layer nicely on top of docker-compose to enhance your productivity.
|
6
|
+
|
7
|
+
Distinctive features of this gem:
|
8
|
+
|
9
|
+
1) Simulates environment-variable substitution in the style of docker-compose
|
10
|
+
1.5; sequences such as ${FOO} in your YML will be replaced with the
|
11
|
+
corresponding environment variable. (This feature will go away once 1.5
|
12
|
+
is released.)
|
7
13
|
|
8
|
-
|
9
|
-
|
10
|
-
to network services exposed by containers. This allows you to run an application on
|
11
|
-
your host for quicker and easier development, but run all of its dependencies --
|
12
|
-
database, cache, adjacent services -- in containers. The dependencies can even run
|
13
|
-
on another machine, e.g. a cloud instance or a container cluster, provided your
|
14
|
-
development machine has TCP connectivity to every port exposed by a container.
|
14
|
+
2) Environment-variable mapping that allows you to export environment variables
|
15
|
+
into your _host_ that point to network services published by containers.
|
15
16
|
|
16
17
|
Throughout this documentation we will refer to this gem as `Docker::Compose`
|
17
18
|
as opposed to the `docker-compose` tool that this gem wraps.
|
@@ -39,19 +40,13 @@ Or install it yourself as:
|
|
39
40
|
```ruby
|
40
41
|
require 'docker/compose'
|
41
42
|
|
42
|
-
# Create a new session in Dir.pwd using the file "docker-compose.yml"
|
43
|
-
#
|
43
|
+
# Create a new session in Dir.pwd using the file "docker-compose.yml"
|
44
|
+
# for fine-grained control over options, see Docker::Compose::Session#new
|
44
45
|
compose = Docker::Compose.new
|
45
46
|
|
46
47
|
compose.version
|
47
48
|
|
48
49
|
compose.up(detached:true)
|
49
|
-
|
50
|
-
exited = compose.ps.where { |c| !c.up? }
|
51
|
-
puts "We have some exited containers: " + exited.join(', ')
|
52
|
-
|
53
|
-
sum = compose.ps.inject(0) { |a,c| a + c.size }
|
54
|
-
puts format("Composition is using %.1f MiB disk space", sum/1024.0**2)
|
55
50
|
```
|
56
51
|
|
57
52
|
### Invoking from Rake
|
@@ -69,26 +64,29 @@ end
|
|
69
64
|
```
|
70
65
|
|
71
66
|
Notice that `rake -T` now has a few additional tasks for invoking gem
|
72
|
-
functionality. You can `docker:compose:env` to print
|
73
|
-
host-to-container environment mapping
|
67
|
+
functionality. You can `docker:compose:env` to print bash export statements
|
68
|
+
for host-to-container environment mapping; you can `docker:compose:up` or
|
69
|
+
`docker:compose:stop` to start and stop containers.
|
74
70
|
|
75
|
-
|
71
|
+
The `docker-compose` command is a perfectly valid way to start
|
72
|
+
and stop containers, but the gem provides some env-substitution functionality
|
73
|
+
for your YML files that will be built into docker-compose 1.5 but is not
|
74
|
+
released yet. If your YML contains `${ENV}` references, i.e. in order to
|
75
|
+
point your containers at network services running on the host, then you must
|
76
|
+
invoke docker-compose through Rake in order to peform the substitution.
|
76
77
|
|
77
|
-
|
78
|
-
the `docker:compose:host` task. For example, I could enter a shell
|
79
|
-
with `rake docker:compose:host[bash]`.
|
80
|
-
|
81
|
-
Before "hosting" your command, the Rake task exports some environment
|
82
|
-
variables that your command can use to discover services running in
|
83
|
-
containers. Your Rakefile specifies which variables your app needs
|
84
|
-
(the `host_env` option) and which container information each variable should
|
85
|
-
map to.
|
78
|
+
### Mapping container IPs and ports
|
86
79
|
|
87
|
-
|
88
|
-
|
89
|
-
|
80
|
+
Assuming that your app accepts its configuration in the form of environment
|
81
|
+
variables, you can use the `docker:compose:env` to export environment values
|
82
|
+
into your bash shell that point to services running inside containers. This
|
83
|
+
allows you to run the app on your host (for easier debugging and code editing)
|
84
|
+
but let it communicate with services running inside containers.
|
90
85
|
|
91
|
-
|
86
|
+
Docker::Compose uses a heuristic to figure out which IP your services
|
87
|
+
are actually reachable at; the heuristic works regardless whether you are
|
88
|
+
running "bare" docker daemon on localhost, communicating with a docker-machine
|
89
|
+
instance, or even using a cloud-hosted docker machine!
|
92
90
|
|
93
91
|
As a trivial example, let's say that your `docker-compose.yml` contains one
|
94
92
|
service, the database that your app needs in order to run.
|
@@ -105,27 +103,30 @@ db:
|
|
105
103
|
```
|
106
104
|
|
107
105
|
Your app needs two inputs, `DATABASE_HOST` and `DATABASE_PORT`. You can specify
|
108
|
-
this
|
106
|
+
this in the env section of the Rake task:
|
109
107
|
|
110
108
|
```ruby
|
111
109
|
Docker::Compose::RakeTasks.new do |tasks|
|
112
|
-
tasks.
|
113
|
-
'DATABASE_HOST' => 'db:[3306]'
|
114
|
-
'DATABASE_PORT' => '[db]:3306'
|
110
|
+
tasks.env = {
|
111
|
+
'DATABASE_HOST' => 'db:[3306]'
|
112
|
+
'DATABASE_PORT' => '[db]:3306'
|
115
113
|
}
|
116
114
|
end
|
117
115
|
```
|
118
116
|
|
117
|
+
(If I had a `DATABASE_URL` input, I could provide a URL such as
|
118
|
+
`mysql://db/myapp_development`; Docker::Compose would parse the URL and replace
|
119
|
+
the hostname and port appropriately.)
|
120
|
+
|
119
121
|
Now, I can run my services, ask Docker::Compose to map the environment values
|
120
122
|
to the actual IP and port that `db` has been published to, and run my app:
|
121
123
|
|
122
124
|
```bash
|
123
|
-
# First, bring up the containers we will be interested in
|
124
125
|
user@machine$ docker-compose up -d
|
125
126
|
|
126
|
-
#
|
127
|
-
# export DATABASE_HOST=
|
128
|
-
# export DATABASE_PORT=
|
127
|
+
# This prints bash code resembling the following:
|
128
|
+
# export DATABASE_HOST=127.0.0.1
|
129
|
+
# export DATABASE_PORT=34387
|
129
130
|
# We eval it, which makes the variables available to our shell and to all
|
130
131
|
# subprocesses.
|
131
132
|
user@machine$ eval "$(bundle exec rake docker:compose:env)"
|
@@ -133,24 +134,6 @@ user@machine$ eval "$(bundle exec rake docker:compose:env)"
|
|
133
134
|
user@machine$ bundle exec rackup
|
134
135
|
```
|
135
136
|
|
136
|
-
The `host_env` option also handles substitution of URLs, and arrays of values
|
137
|
-
(which are serialized back to the environment as JSON)
|
138
|
-
For example:
|
139
|
-
|
140
|
-
```ruby
|
141
|
-
tasks.host_env = {
|
142
|
-
'DATABASE_URL' => 'mysql://db:3306/myapp_development',
|
143
|
-
'MIXED_FRUIT' => ['db:[3306]', '[db]:3306']
|
144
|
-
}
|
145
|
-
```
|
146
|
-
|
147
|
-
This would result in the following exports:
|
148
|
-
|
149
|
-
```bash
|
150
|
-
export DATABASE_URL='mysql://127.0.0.1:34387/myapp_development'
|
151
|
-
export MIXED_FRUIT='["127.0.0.1", "34387"]'
|
152
|
-
```
|
153
|
-
|
154
137
|
To learn more about mapping, read the class documentation for
|
155
138
|
`Docker::Compose::Mapper`.
|
156
139
|
|
@@ -168,3 +151,4 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/xeger/
|
|
168
151
|
## License
|
169
152
|
|
170
153
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
154
|
+
|
data/Rakefile
CHANGED
data/bin/console
CHANGED
@@ -1,18 +1,14 @@
|
|
1
|
-
|
2
|
-
# encoding: utf-8
|
1
|
+
#!/usr/bin/env ruby
|
3
2
|
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require "bundler/setup"
|
4
|
+
require "docker/compose"
|
6
5
|
|
7
|
-
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
IRB.conf[:MAIN_CONTEXT] = IRB::Irb.new.context
|
16
|
-
require 'irb/ext/multi-irb'
|
17
|
-
IRB.irb nil, @session
|
18
|
-
end
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/docker-compose.gemspec
CHANGED
@@ -4,26 +4,22 @@ $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 = %q{Wrapper docker-compose with added Rake smarts.}
|
13
|
+
spec.description = %q{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.
|
23
|
-
|
24
|
-
spec.
|
25
|
-
|
26
|
-
spec.add_development_dependency 'bundler', '~> 2.3'
|
27
|
-
spec.add_development_dependency 'rake', '~> 10.0'
|
28
|
-
spec.add_development_dependency 'rspec'
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
spec.add_development_dependency "rspec"
|
29
25
|
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Docker::Compose::Future
|
4
|
+
module Session
|
5
|
+
# Pattern that matches an environment substitution in a docker-compose YML
|
6
|
+
# file.
|
7
|
+
# @see #substitute
|
8
|
+
SUBSTITUTION = /\$\{([A-Z0-9:_-]+)\}/
|
9
|
+
|
10
|
+
# Hook in env-var substitution by aliasing a method chain for run!
|
11
|
+
def self.included(host)
|
12
|
+
done = host.instance_methods.include?(:run_without_substitution!)
|
13
|
+
host.instance_eval do
|
14
|
+
alias_method :run_without_substitution!, :run!
|
15
|
+
alias_method :run!, :run_with_substitution!
|
16
|
+
end unless done
|
17
|
+
end
|
18
|
+
|
19
|
+
# Read docker-compose YML; perform environment variable substitution;
|
20
|
+
# write a temp file; invoke run! with the new file; delete the temp
|
21
|
+
# file afterward.
|
22
|
+
#
|
23
|
+
# This is a complete reimplementation of run! and we only alias the original
|
24
|
+
# to be good citizens.
|
25
|
+
def run_with_substitution!(*cmd)
|
26
|
+
temp = nil
|
27
|
+
project = File.basename(@dir)
|
28
|
+
|
29
|
+
# Find and purge the 'file' flag if it exists; otherwise assume we will
|
30
|
+
# substitute our default (session) file.
|
31
|
+
fn = nil
|
32
|
+
cmd.each do |item|
|
33
|
+
fn ||= item.delete(:file) if item.is_a?(Hash)
|
34
|
+
end
|
35
|
+
fn ||= @file
|
36
|
+
|
37
|
+
# Rewrite YML if the file exists and the file:false "flag" wasn't
|
38
|
+
# explicitly passed to us.
|
39
|
+
Dir.chdir(@dir) do
|
40
|
+
yml = YAML.load(File.read(fn))
|
41
|
+
yml = substitute(yml)
|
42
|
+
temp = Tempfile.new(fn, @dir)
|
43
|
+
temp.write(YAML.dump(yml))
|
44
|
+
temp.close
|
45
|
+
|
46
|
+
project_opts = {
|
47
|
+
file: temp.path,
|
48
|
+
project: File.basename(@dir)
|
49
|
+
}
|
50
|
+
|
51
|
+
result, output =
|
52
|
+
@shell.command('docker-compose', project_opts, *cmd)
|
53
|
+
(result == 0) || raise(RuntimeError,
|
54
|
+
"#{cmd.first} failed with status #{result}")
|
55
|
+
output
|
56
|
+
end
|
57
|
+
ensure
|
58
|
+
temp.unlink if temp
|
59
|
+
end
|
60
|
+
|
61
|
+
# Simulate the behavior of docker-compose 1.5: replace "${VAR}" sequences
|
62
|
+
# with the values of environment variables. Perform this recursively if
|
63
|
+
# data is a Hash or Array.
|
64
|
+
#
|
65
|
+
#
|
66
|
+
# @param [Hash,Array,String,Object] data
|
67
|
+
# @return [Hash,Array,String,Object] data with all ${ENV} references substituted
|
68
|
+
private def substitute(data)
|
69
|
+
case data
|
70
|
+
when Hash
|
71
|
+
result = {}
|
72
|
+
data.each_pair { |k, v| result[k] = substitute(v) }
|
73
|
+
when Array
|
74
|
+
result = []
|
75
|
+
data.each { |v| result << substitute(v) }
|
76
|
+
when String
|
77
|
+
result = data
|
78
|
+
while (match = SUBSTITUTION.match(result))
|
79
|
+
var = match[1]
|
80
|
+
repl = format("${%s}", var)
|
81
|
+
result.gsub!(repl, ENV[var])
|
82
|
+
end
|
83
|
+
else
|
84
|
+
result = data
|
85
|
+
end
|
86
|
+
|
87
|
+
result
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -1,16 +1,6 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
module Docker::Compose
|
3
2
|
# Uses a Session to discover information about services' IP addresses and
|
4
|
-
# ports as reachable from
|
5
|
-
# address formats so they point to the right host and port.
|
6
|
-
#
|
7
|
-
# **NOTE**: this class uses some heuristics to deal with cases where the
|
8
|
-
# Docker client is talking to a remote server because the `DOCKER_HOST`
|
9
|
-
# environment variable is set. In those cases, Mapper tries to determine
|
10
|
-
# the IP address of the exposed services as reachable from localhost;
|
11
|
-
# it generally makes a correct guess, but in certain super-complex networking
|
12
|
-
# scenarios it may guess wrong. Please open a GitHub issue if you find
|
13
|
-
# a situation where Mapper provides a wrong answer.
|
3
|
+
# ports as reachable from the host, then
|
14
4
|
class Mapper
|
15
5
|
# Pattern that matches an "elided" host or port that should be omitted from
|
16
6
|
# output, but is needed to identify a specific container and port.
|
@@ -22,44 +12,18 @@ module Docker::Compose
|
|
22
12
|
BadSubstitution = Class.new(StandardError)
|
23
13
|
NoService = Class.new(RuntimeError)
|
24
14
|
|
25
|
-
# Instantiate a mapper; map some environment variables; yield to caller for
|
26
|
-
# additional processing.
|
27
|
-
#
|
28
|
-
# @param [Hash] env a set of keys/values whose values will be mapped
|
29
|
-
# @param [Session] session
|
30
|
-
# @param [NetInfo] net_info
|
31
|
-
# @yield yields with each substituted (key, value) pair
|
32
|
-
def self.map(env, session:Session.new, net_info:NetInfo.new)
|
33
|
-
mapper = new(session, net_info)
|
34
|
-
env.each_pair do |k, v|
|
35
|
-
begin
|
36
|
-
v = mapper.map(v)
|
37
|
-
yield(k, v)
|
38
|
-
rescue NoService
|
39
|
-
yield(k, nil)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
15
|
# Create an instance of Mapper
|
45
|
-
#
|
46
16
|
# @param [Docker::Compose::Session] session
|
47
|
-
# @param [
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
else
|
55
|
-
# If DOCKER_HOST is present, assume that containers have bound to
|
56
|
-
# whatever IP we reach it at; don't fall victim to docker-compose's
|
57
|
-
# dirty lies!
|
58
|
-
override_host = net_info.docker_routable_ip
|
59
|
-
end
|
60
|
-
|
17
|
+
# @param [String] host_ip IPv4 address of the host that is publishing
|
18
|
+
# Docker services (i.e. the `DOCKER_HOST` hostname or IP if you are using
|
19
|
+
# a non-clustered Docker environment)
|
20
|
+
# @param [Boolean] strict if true, raise BadSubstitution when unrecognized
|
21
|
+
# syntax is passed to #map; if false, simply return the value without
|
22
|
+
# substituting anything
|
23
|
+
def initialize(session, host_ip, strict:true)
|
61
24
|
@session = session
|
62
|
-
@
|
25
|
+
@host_ip = host_ip
|
26
|
+
@strict = strict
|
63
27
|
end
|
64
28
|
|
65
29
|
# Substitute service hostnames and ports that appear in a URL or a
|
@@ -76,84 +40,56 @@ module Docker::Compose
|
|
76
40
|
# @example map just the port of MySQL on local docker host
|
77
41
|
# map("[db]:3306") # => "13847"
|
78
42
|
#
|
79
|
-
# @
|
80
|
-
# map(["[db1]:3306", "[db2]:3306"])
|
81
|
-
#
|
82
|
-
# @param [String,#map] value a URI, host:port pair, or an array of either
|
83
|
-
#
|
84
|
-
# @return [String,Array] the mapped value with container-names and ports substituted
|
43
|
+
# @param [String] value a URI or a host:port pair
|
85
44
|
#
|
86
45
|
# @raise [BadSubstitution] if a substitution string can't be parsed
|
87
46
|
# @raise [NoService] if service is not up or does not publish port
|
88
47
|
def map(value)
|
89
|
-
|
90
|
-
value.map { |e| map_scalar(e) }
|
91
|
-
else
|
92
|
-
map_scalar(value)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
# Figure out which host port a given service's port has been published to,
|
97
|
-
# and/or whether that service is running. Cannot distinguish between the
|
98
|
-
# "service not running" case and the "container port not published" case!
|
99
|
-
#
|
100
|
-
# @raise [NoService] if service is not up or does not publish port
|
101
|
-
# @return [Array] (String, Integer) pair of host address and port number
|
102
|
-
def host_and_port(service, port)
|
103
|
-
result = @session.port(service, port.to_s)
|
104
|
-
if result
|
105
|
-
result.chomp!
|
106
|
-
else
|
107
|
-
raise NoService,
|
108
|
-
"Service '#{service}' not running, or does not " \
|
109
|
-
"publish port '#{port}'"
|
110
|
-
end
|
111
|
-
|
112
|
-
host, port = result.split(':')
|
113
|
-
host = @override_host if @override_host
|
114
|
-
|
115
|
-
[host, Integer(port)]
|
116
|
-
end
|
117
|
-
|
118
|
-
# Map a single string, replacing service names with IPs and container ports
|
119
|
-
# with the host ports that they have been mapped to.
|
120
|
-
# @param [String] value
|
121
|
-
# @return [String]
|
122
|
-
def map_scalar(value)
|
123
|
-
uri = begin
|
124
|
-
URI.parse(value)
|
125
|
-
rescue
|
126
|
-
nil
|
127
|
-
end
|
48
|
+
uri = URI.parse(value) rescue nil
|
128
49
|
pair = value.split(':')
|
129
50
|
|
130
51
|
if uri && uri.scheme && uri.host
|
131
52
|
# absolute URI with scheme, authority, etc
|
132
|
-
uri.
|
53
|
+
uri.port = published_port(uri.host, uri.port)
|
54
|
+
uri.host = @host_ip
|
133
55
|
return uri.to_s
|
134
56
|
elsif pair.size == 2
|
135
57
|
# "host:port" pair; three sub-cases...
|
136
58
|
if pair.first =~ ELIDED
|
137
59
|
# output only the port
|
138
60
|
service = pair.first.gsub(REMOVE_ELIDED, '')
|
139
|
-
|
61
|
+
port = published_port(service, pair.last)
|
140
62
|
return port.to_s
|
141
63
|
elsif pair.last =~ ELIDED
|
142
64
|
# output only the hostname; resolve the port anyway to ensure that
|
143
65
|
# the service is running.
|
144
66
|
service = pair.first
|
145
67
|
port = pair.last.gsub(REMOVE_ELIDED, '')
|
146
|
-
|
147
|
-
return
|
68
|
+
published_port(service, port)
|
69
|
+
return @host_ip
|
148
70
|
else
|
149
71
|
# output port:hostname pair
|
150
|
-
|
151
|
-
return "#{
|
72
|
+
port = published_port(pair.first, pair.last)
|
73
|
+
return "#{@host_ip}:#{port}"
|
152
74
|
end
|
75
|
+
elsif @strict
|
76
|
+
raise BadSubstitution, "Can't understand '#{value}'"
|
153
77
|
else
|
154
|
-
|
78
|
+
return value
|
155
79
|
end
|
156
80
|
end
|
157
|
-
|
81
|
+
|
82
|
+
# Figure out which host port a given service's port has been published to,
|
83
|
+
# and/or whether that service is running. Cannot distinguish between the
|
84
|
+
# "service not running" case and the "container port not published" case!
|
85
|
+
#
|
86
|
+
# @raise [NoService] if service is not up or does not publish port
|
87
|
+
# @return [Integer] host port number, or nil if port not published
|
88
|
+
def published_port(service, port)
|
89
|
+
result = @session.port(service, port)
|
90
|
+
Integer(result.split(':').last.gsub("\n", ""))
|
91
|
+
rescue RuntimeError
|
92
|
+
raise NoService, "Service '#{service}' not running, or does not publish port '#{port}'"
|
93
|
+
end
|
158
94
|
end
|
159
95
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
module Docker::Compose
|
3
2
|
# Utility that gathers information about the relationship between the host
|
4
3
|
# on which the Ruby VM is running and the docker host, then makes an
|
@@ -24,8 +23,8 @@ module Docker::Compose
|
|
24
23
|
# Create a new instance of this class.
|
25
24
|
# @param [String] docker_host a URI pointing to the docker host
|
26
25
|
# @param [Array] list of String dotted-quad IPv4 addresses of local host
|
27
|
-
def initialize(docker_host
|
28
|
-
my_ips
|
26
|
+
def initialize(docker_host=ENV['DOCKER_HOST'],
|
27
|
+
my_ips=self.class.ipv4_interfaces)
|
29
28
|
docker_host ||= 'unix:/var/run/docker.sock'
|
30
29
|
@docker_url = URI.parse(docker_host)
|
31
30
|
@my_ips = my_ips
|
@@ -40,7 +39,7 @@ module Docker::Compose
|
|
40
39
|
#
|
41
40
|
# @return [String] IPv4 address of host machine that _may_ be reachable from
|
42
41
|
# Docker machine
|
43
|
-
def host_routable_ip(target_ip
|
42
|
+
def host_routable_ip(target_ip=docker_routable_ip)
|
44
43
|
best_match = ''
|
45
44
|
best_prefix = 0
|
46
45
|
|
@@ -73,8 +72,8 @@ module Docker::Compose
|
|
73
72
|
docker_dns = @docker_url.host
|
74
73
|
docker_port = @docker_url.port || 2376
|
75
74
|
else
|
76
|
-
# Cheap trick: for unix
|
77
|
-
#
|
75
|
+
# Cheap trick: for unix or other protocols, assume docker daemon
|
76
|
+
# is listening on 127.0.0.1:2376
|
78
77
|
docker_dns = 'localhost'
|
79
78
|
docker_port = 2376
|
80
79
|
end
|