docker-compose 0.0.0 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![Build Status](https://travis-ci.org/xeger/docker-compose.svg)](https://travis-ci.org/xeger/docker-compose) [![Coverage Status](https://coveralls.io/repos/github/xeger/docker-compose/badge.svg?branch=coveralls)](https://coveralls.io/github/xeger/docker-compose?branch=coveralls) [![Docs](https://img.shields.io/badge/docs-rubydoc-blue.svg)](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
|