docker-compose 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a85e6cd467f9c5c4a6704724d9429a4f681d065a
4
- data.tar.gz: a5f85af19b15c215b68a01e7004bf0c0cb05587e
3
+ metadata.gz: 04a52fb98e79311b5e3c771d24d41d434ab08e53
4
+ data.tar.gz: d1a04e25f5164edff5e2651ceed331fd58a20eb4
5
5
  SHA512:
6
- metadata.gz: 1a9143db8626ea989d500c29a802c79b84c50ebd66674daf9bfff474f413353a9d3203bd1860d5dce3dbefa2301fc44521db597fd56b4cdf95d9ff295d11be57
7
- data.tar.gz: f2f68bd762d659926ec4880423db394e75ef03ea72f7ee0cf7af65e06639be902f0f0d9819128f64d6dc8e4d56d06b5ceb05795ed3e800ac1383f23b3939947d
6
+ metadata.gz: 52a9df711b6120701e3359fb30c3b22bc3c87abaa7823724c39e0efb462bc288b091efbce6eb77561b42f0ab112b9ea5568ac856de18ac7511d5a08292d60c30
7
+ data.tar.gz: ecd93e2c5c33b10acde0b8bd7c15c025676a53ff43f5b5df020e07f103961ccd5833e2096e965bd0766be2f768d0abdcb55b0b0ccab27572411f8f6fa07ec7e4
@@ -0,0 +1,19 @@
1
+ 0.6
2
+ ---
3
+
4
+ #### Interface-breaking changes
5
+
6
+ - Replaced `docker:compose:server` Rake task with more general `docker:compose:host`
7
+ - Replaced `server_env` option with `host_env`
8
+ - Replaced `extra_server_env` option with `extra_host_env`
9
+ - Stopped mapping values in `extra_host_env`; they are now exported verbatim
10
+
11
+ #### New features
12
+
13
+ Produce `docker:compose:env` output that is compatible with user's login shell.
14
+
15
+ 0.5
16
+ ---
17
+
18
+ Initial public release of prototype. Features work well, but there is no test
19
+ coverage.
data/README.md CHANGED
@@ -7,7 +7,7 @@ In addition to wrapping the CLI, this gem provides an environment-variable mappi
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
9
  your host for quicker and easier development, but run all of its architectural
10
- dependencies -- database, cache, adjacent microservices -- in containers. The
10
+ dependencies -- database, cache, adjacent services -- in containers. The
11
11
  dependencies can even be running on another machine, e.g. a cloud instance or a
12
12
  container cluster, provided your development machine has TCP connectivity on every
13
13
  port exposed by a container.
@@ -62,29 +62,26 @@ end
62
62
  ```
63
63
 
64
64
  Notice that `rake -T` now has a few additional tasks for invoking gem
65
- functionality. You can `docker:compose:env` to print bash export statements
66
- for host-to-container environment mapping; you can `docker:compose:up` or
67
- `docker:compose:stop` to start and stop containers.
65
+ functionality. You can `docker:compose:env` print shell exports for
66
+ host-to-container environment mapping, or you can `docker:compose:host[foo]`.
68
67
 
69
- The `docker-compose` command is a perfectly valid way to start
70
- and stop containers, but the gem provides some env-substitution functionality
71
- for your YML files that will be built into docker-compose 1.5 but is not
72
- released yet. If your YML contains `${ENV}` references, i.e. in order to
73
- point your containers at network services running on the host, then you must
74
- invoke docker-compose through Rake in order to peform the substitution.
68
+ ### Hosting a Command
75
69
 
76
- ### Mapping container IPs and ports
70
+ To run a process on your host and allow it to talk to containers, use
71
+ the `docker:compose:host` task. For example, I could enter a shell
72
+ with `rake docker:compose:host[bash]`.
73
+
74
+ Before "hosting" your command, the Rake task export ssome environment
75
+ variables that your command can use to discover services running in
76
+ containers. Your Rakefile specifies which variables your app needs
77
+ (the `host_env` option) and which container information each variable should
78
+ map to.
77
79
 
78
- Assuming that your app accepts its configuration in the form of environment
79
- variables, you can use the `docker:compose:env` to export environment values
80
- into your bash shell that point to services running inside containers. This
81
- allows you to run the app on your host (for easier debugging and code editing)
82
- but let it communicate with services running inside containers.
80
+ By hosting commands, you benefit from easier debugging and code editing of
81
+ the app you're working on, but still get to rely on containers to provide
82
+ the companion services your app requires to run.
83
83
 
84
- Docker::Compose uses a heuristic to figure out which IP your services
85
- are actually reachable at; the heuristic works regardless whether you are
86
- running "bare" docker daemon on localhost, communicating with a docker-machine
87
- instance, or even using a cloud-hosted docker machine!
84
+ ### Mapping container IPs and ports
88
85
 
89
86
  As a trivial example, let's say that your `docker-compose.yml` contains one
90
87
  service, the database that your app needs in order to run.
@@ -101,30 +98,27 @@ db:
101
98
  ```
102
99
 
103
100
  Your app needs two inputs, `DATABASE_HOST` and `DATABASE_PORT`. You can specify
104
- this in the env section of the Rake task:
101
+ this with the host_env option of the Rake task:
105
102
 
106
103
  ```ruby
107
104
  Docker::Compose::RakeTasks.new do |tasks|
108
- tasks.env = {
109
- 'DATABASE_HOST' => 'db:[3306]'
110
- 'DATABASE_PORT' => '[db]:3306'
105
+ tasks.host_env = {
106
+ 'DATABASE_HOST' => 'db:[3306]',
107
+ 'DATABASE_PORT' => '[db]:3306',
111
108
  }
112
109
  end
113
110
  ```
114
111
 
115
- (If I had a `DATABASE_URL` input, I could provide a URL such as
116
- `mysql://db/myapp_development`; Docker::Compose would parse the URL and replace
117
- the hostname and port appropriately.)
118
-
119
112
  Now, I can run my services, ask Docker::Compose to map the environment values
120
113
  to the actual IP and port that `db` has been published to, and run my app:
121
114
 
122
115
  ```bash
116
+ # First, bring up the containers we will be interested in
123
117
  user@machine$ docker-compose up -d
124
118
 
125
- # This prints bash code resembling the following:
126
- # export DATABASE_HOST=127.0.0.1
127
- # export DATABASE_PORT=34387
119
+ # The rake task prints bash code resembling the following:
120
+ # export DATABASE_HOST='127.0.0.1'
121
+ # export DATABASE_PORT='34387'
128
122
  # We eval it, which makes the variables available to our shell and to all
129
123
  # subprocesses.
130
124
  user@machine$ eval "$(bundle exec rake docker:compose:env)"
@@ -132,6 +126,24 @@ user@machine$ eval "$(bundle exec rake docker:compose:env)"
132
126
  user@machine$ bundle exec rackup
133
127
  ```
134
128
 
129
+ The `host_env` option also handles substitution of URLs, and arrays of values
130
+ (which are serialized back to the environment as JSON)
131
+ For example:
132
+
133
+ ```ruby
134
+ tasks.host_env = {
135
+ 'DATABASE_URL' => 'mysql://db:3306/myapp_development',
136
+ 'MIXED_FRUIT' => ['db:[3306]', '[db]:3306']
137
+ }
138
+ ```
139
+
140
+ This would result in the following exports:
141
+
142
+ ```bash
143
+ export DATABASE_URL='mysql://127.0.0.1:34387/myapp_development'
144
+ export MIXED_FRUIT='["127.0.0.1", "34387"]'
145
+ ```
146
+
135
147
  To learn more about mapping, read the class documentation for
136
148
  `Docker::Compose::Mapper`.
137
149
 
@@ -15,11 +15,10 @@ module Docker::Compose
15
15
  # Instantiate a mapper; map some environment variables; yield to caller for
16
16
  # additional processing.
17
17
  #
18
- # @param [Boolean] strict
19
18
  # @param [Session] session
20
19
  # @param [NetInfo] net_info
21
20
  # @yield yields with each substituted (key, value) pair
22
- def self.map(env, strict:true, session:Session.new, net_info:NetInfo.new)
21
+ def self.map(env, session:Session.new, net_info:NetInfo.new)
23
22
  # TODO: encapsulate this trickiness better ... inside NetInfo perhaps?
24
23
  docker_host = ENV['DOCKER_HOST']
25
24
  if docker_host.nil? || docker_host =~ /^(\/|unix|file)/
@@ -32,7 +31,7 @@ module Docker::Compose
32
31
  override_host = net_info.docker_routable_ip
33
32
  end
34
33
 
35
- mapper = self.new(session, override_host, strict:strict)
34
+ mapper = self.new(session, override_host)
36
35
  env.each_pair do |k, v|
37
36
  begin
38
37
  v = mapper.map(v)
@@ -47,13 +46,9 @@ module Docker::Compose
47
46
  # @param [Docker::Compose::Session] session
48
47
  # @param [String] override_host forcible address or DNS hostname to use;
49
48
  # leave nil to trust docker-compose output.
50
- # @param [Boolean] strict if true, raise BadSubstitution when unrecognized
51
- # syntax is passed to #map; if false, simply return unrecognized
52
- # values without substituting anything
53
- def initialize(session, override_host=nil, strict:true)
49
+ def initialize(session, override_host=nil)
54
50
  @session = session
55
51
  @override_host = override_host
56
- @strict = strict
57
52
  end
58
53
 
59
54
  # Substitute service hostnames and ports that appear in a URL or a
@@ -133,10 +128,8 @@ module Docker::Compose
133
128
  host, port = host_and_port(pair.first, pair.last)
134
129
  return "#{host}:#{port}"
135
130
  end
136
- elsif @strict
137
- raise BadSubstitution, "Can't understand '#{value}'"
138
131
  else
139
- return value
132
+ raise BadSubstitution, "Can't understand '#{value}'"
140
133
  end
141
134
  end
142
135
  end
@@ -5,6 +5,9 @@ require 'shellwords'
5
5
  # In case this file is required directly
6
6
  require 'docker/compose'
7
7
 
8
+ # Only used here, so only required here
9
+ require 'docker/compose/shell_printer'
10
+
8
11
  module Docker::Compose
9
12
  class RakeTasks < Rake::TaskLib
10
13
  # Set the directory in which docker-compose commands will be run. Default
@@ -17,32 +20,33 @@ module Docker::Compose
17
20
  # @return [String]
18
21
  attr_accessor :file
19
22
 
20
- # Provide a mapping of environment variables that should be set in the
21
- # _host_ shell for docker:compose:env or docker:compose:server.
23
+ # Provide a mapping of environment variables that should be set in
24
+ # _host_ processes, e.g. when running docker:compose:env or
25
+ # docker:compose:host.
26
+ #
22
27
  # The values of the environment variables can refer to names of services
23
- # and ports defined in the docker-compose file, and this gem will query
24
- # docker-compose to find out which host IP and port the services are
25
- # reachable on. This allows components running on the host to connect to
26
- # services running inside containers.
28
+ # and ports defined in the docker-compose file, and this gem will substitute
29
+ # the actual IP and port that the containers are reachable on. This allows
30
+ # commands invoked via "docker:compose:host" to reach services running
31
+ # inside containers.
27
32
  #
28
33
  # @see Docker::Compose::Mapper for information about the substitution syntax
29
- attr_accessor :server_env
30
-
31
- # Extra environment variables that should be set before invoking the command
32
- # specified for docker:compose:server. These are set _in addition_ to server_env
33
- # (and should be disjoint from server_env), and do not necessarily need to map the
34
- # location of a container; they are simply extra environment values that are
35
- # useful to change the server's behavior when it runs in cooperation
36
- # with containers.
34
+ attr_accessor :host_env
35
+
36
+ # Extra environment variables to set before invoking host processes. These
37
+ # are set _in addition_ to server_env, but are not substituted in any way
38
+ # and must not contain any service information.
37
39
  #
38
- # If there is overlap between server_env and extra_server_env, then keys
39
- # of extra_server_env will "win"; they are set last.
40
- attr_accessor :extra_server_env
40
+ # Extra host env should be disjoint from host_env; if there is overlap
41
+ # between the two, then extra_host_env will "win."
42
+ attr_accessor :extra_host_env
41
43
 
42
- # Command to exec on the _host_ when someone invokes docker:compose:server.
43
- # This is used to start up all containers and then run a server that
44
- # depends on them and is properly linked to them.
45
- attr_accessor :server
44
+ # Services to bring up with `docker-compose up` before running any hosted
45
+ # command. This is useful if your `docker-compose.yml` contains a service
46
+ # definition for the app you will be hosting; if you host the app, you
47
+ # want to specify all of the _other_ services, but not the app itself, since
48
+ # that will run on the host.
49
+ attr_accessor :host_services
46
50
 
47
51
  # Namespace to define the rake tasks under. Defaults to "docker:compose'.
48
52
  attr_accessor :rake_namespace
@@ -53,14 +57,15 @@ module Docker::Compose
53
57
  def initialize
54
58
  self.dir = Rake.application.original_dir
55
59
  self.file = 'docker-compose.yml'
56
- self.server_env = {}
57
- self.extra_server_env = {}
60
+ self.host_env = {}
61
+ self.extra_host_env = {}
58
62
  self.rake_namespace = 'docker:compose'
59
63
  yield self if block_given?
60
64
 
61
65
  @shell = Backticks::Runner.new
62
66
  @session = Docker::Compose::Session.new(@shell, dir:dir, file:file)
63
67
  @net_info = Docker::Compose::NetInfo.new
68
+ @shell_printer = Docker::Compose::ShellPrinter.new
64
69
 
65
70
  @shell.interactive = true
66
71
 
@@ -73,41 +78,22 @@ module Docker::Compose
73
78
  task :env do
74
79
  @shell.interactive = false # suppress useless 'port' output
75
80
 
76
- if Rake.application.top_level_tasks.include? 'docker:compose:env'
77
- # This task is being run as top-level task; set process
78
- # environment _and_ print bash export commands to stdout.
79
- # Also print usage hints if user invoked rake directly vs.
80
- # eval'ing it's output
81
- print_usage
82
- export_env(print:true)
83
- else
84
- # This task is a dependency of something else; just export the
85
- # environment variables for use in-process by other Rake tasks.
86
- export_env(print:false)
87
- end
81
+ print_usage if STDOUT.tty?
82
+ export_env(print:true)
88
83
 
89
84
  @shell.interactive = true
90
85
  end
91
86
 
92
- desc 'Launch services (ONLY=a,b,...)'
93
- task :up do
94
- only = (ENV['ONLY'] || '').split(',').compact.uniq
95
- @session.up(*only, detached:true)
96
- end
97
-
98
- desc 'Tail logs of all running services'
99
- task :logs do
100
- @session.logs
101
- end
87
+ desc 'Run command on host, linked to services in containers'
88
+ task :host, [:command] => ['docker:compose:env'] do |task, args|
102
89
 
103
- desc 'Stop services'
104
- task :stop do
105
- @session.stop
106
- end
90
+ if self.host_services
91
+ @session.up(*self.host_services, detached:true)
92
+ else
93
+ @session.up(detached:true)
94
+ end
107
95
 
108
- desc 'Run application on the host, linked to services in containers'
109
- task :server => ['docker:compose:up', 'docker:compose:env'] do
110
- exec(self.server)
96
+ exec(args[:command])
111
97
  end
112
98
  end
113
99
  end
@@ -116,17 +102,14 @@ module Docker::Compose
116
102
  # published by docker-compose services. Optionally also print bash export
117
103
  # statements so this information can be made available to a user's shell.
118
104
  private def export_env(print:)
119
- Docker::Compose::Mapper.map(self.server_env,
105
+ Docker::Compose::Mapper.map(self.host_env,
120
106
  session:@session,
121
107
  net_info:@net_info) do |k, v|
122
108
  ENV[k] = serialize_for_env(v)
123
109
  print_env(k, ENV[k]) if print
124
110
  end
125
111
 
126
- Docker::Compose::Mapper.map(self.extra_server_env,
127
- strict:false,
128
- session:@session,
129
- net_info:@net_info) do |k, v|
112
+ self.extra_host_env.each do |k, v|
130
113
  ENV[k] = serialize_for_env(v)
131
114
  print_env(k, ENV[k]) if print
132
115
  end
@@ -148,19 +131,21 @@ module Docker::Compose
148
131
  end
149
132
  end
150
133
 
151
- # Print a bash export or unset statement
134
+ # Print an export or unset statement suitable for user's shell
152
135
  private def print_env(k, v)
153
136
  if v
154
- puts format('export %s=%s', k, Shellwords.escape(v))
137
+ puts @shell_printer.export(k, v)
155
138
  else
156
- puts format('unset %s # service not running', k)
139
+ puts @shell_printer.unset(k)
157
140
  end
158
141
  end
159
142
 
143
+
160
144
  private def print_usage
161
- be = 'bundle exec ' if defined?(Bundler)
162
- puts %Q{# To export these variables to your shell, run:}
163
- puts %Q{# eval "$(#{be}rake docker:compose:env)"}
145
+ command = "rake #{rake_namespace}:env"
146
+ command = "bundle exec " + command if defined?(Bundler)
147
+ puts @shell_printer.comment('To export these variables to your shell, run:')
148
+ puts @shell_printer.comment(@shell_printer.eval_output(command))
164
149
  end
165
150
  end
166
151
  end
@@ -0,0 +1,21 @@
1
+ require 'etc'
2
+
3
+ module Docker::Compose
4
+ module ShellPrinter
5
+ def self.new
6
+ shell = Etc.getpwuid(Process.uid).shell
7
+ basename = File.basename(shell)
8
+
9
+ # Crappy titleize (bash -> Bash)
10
+ basename[0] = basename[0].upcase
11
+
12
+ # Find adapter class named after shell; default to posix if nothing found
13
+ klass = const_get(basename.to_sym) rescue Posix
14
+
15
+ klass.new
16
+ end
17
+ end
18
+ end
19
+
20
+ require_relative 'shell_printer/posix'
21
+ require_relative 'shell_printer/fish'
@@ -0,0 +1,16 @@
1
+ module Docker::Compose::ShellPrinter
2
+ # Printer that works with the Friendly Interactive Shell (fish).
3
+ class Fish < Posix
4
+ def eval_output(command)
5
+ format('eval (%s)', command)
6
+ end
7
+
8
+ def export(name, value)
9
+ format('set -gx %s %s; ', name, single_quoted_escaped(value))
10
+ end
11
+
12
+ def unset(name)
13
+ format('set -ex %s; ', name)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,32 @@
1
+ module Docker::Compose::ShellPrinter
2
+ # Printer that works with any POSIX-compliant shell e.g. sh, bash, zsh
3
+ class Posix
4
+ def comment(value)
5
+ format('# %s', value)
6
+ end
7
+
8
+ def eval_output(command)
9
+ format('eval "$(%s)"', command)
10
+ end
11
+
12
+ def export(name, value)
13
+ format('export %s=%s', name, single_quoted_escaped(value))
14
+ end
15
+
16
+ def unset(name)
17
+ format('unset %s', name)
18
+ end
19
+
20
+ protected def single_quoted_escaped(value)
21
+ # "escape" any occurrences of ' in value by closing the single-quoted
22
+ # string, concatenating a single backslash-escaped ' character, and reopening
23
+ # the single-quoted string.
24
+ #
25
+ # This relies on the shell's willingness to concatenate adjacent string
26
+ # literals. Tested under sh, bash and zsh; should work elsewhere.
27
+ escaped = value.gsub("'") { "'\\''" }
28
+
29
+ "'#{escaped}'"
30
+ end
31
+ end
32
+ end
@@ -1,5 +1,5 @@
1
1
  module Docker
2
2
  module Compose
3
- VERSION = "0.5.1"
3
+ VERSION = "0.6.0"
4
4
  end
5
5
  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.5.1
4
+ version: 0.6.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-04-13 00:00:00.000000000 Z
11
+ date: 2016-05-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backticks
@@ -78,6 +78,7 @@ files:
78
78
  - ".rspec"
79
79
  - ".ruby-version"
80
80
  - ".travis.yml"
81
+ - CHANGELOG.md
81
82
  - CODE_OF_CONDUCT.md
82
83
  - Gemfile
83
84
  - LICENSE.txt
@@ -92,6 +93,9 @@ files:
92
93
  - lib/docker/compose/net_info.rb
93
94
  - lib/docker/compose/rake_tasks.rb
94
95
  - lib/docker/compose/session.rb
96
+ - lib/docker/compose/shell_printer.rb
97
+ - lib/docker/compose/shell_printer/fish.rb
98
+ - lib/docker/compose/shell_printer/posix.rb
95
99
  - lib/docker/compose/version.rb
96
100
  homepage: https://github.com/xeger/docker-compose
97
101
  licenses: