mcrain 0.1.4 → 0.2.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: a1c033a9e832b8d1e2e30052bef3528c766e349e
4
- data.tar.gz: 4393f78f710d1d29ddff5df9629fb0db7ab9a1d8
3
+ metadata.gz: d07708c123940b6ae6e2fa57fd8aa76590439d36
4
+ data.tar.gz: b8ef280372ad693c31b52e8f62f38f7dba9cab80
5
5
  SHA512:
6
- metadata.gz: 3ad8e53db4f4e784b50d7ad1175c9955e651e675d9ee2a645c524d3e348ddaf09f2095b7cbac312c4912c1d30c607078bd9c7e5a200ebb4823bc7ed328851f5c
7
- data.tar.gz: 9dc9ebfbbff97677cf93d921c42e9af2b18da60ca84fda297501f229d05706a8c5e6590809529cd268b494ba83d2a15978a31eb4c05ea76b7eae0c51d50d5dda
6
+ metadata.gz: a26b6d8f4dab3aa1a0e6b087df9a3af12dc7a0b0690551e38aa06e6252b61524b59c0a8ddd515e88037683f26a317f5f3b9c7fb26e8eb83207cc7145eb113591
7
+ data.tar.gz: f67ce63e4b1d2dcc5d6f3020b56cda0a672bbfb946abeb977d60a12da59b94c9488cb12757c2df34aea4ec0714bc77c8d64de467880c2c190327cfadb0298b1c
data/.gitmodules CHANGED
@@ -1,3 +0,0 @@
1
- [submodule "spec/support/docker-riak"]
2
- path = spec/support/docker-riak
3
- url = git@github.com:hectcastro/docker-riak.git
data/README.md CHANGED
@@ -3,9 +3,43 @@
3
3
  Mcrain helps you to use docker container in test cases.
4
4
  It supports redis, rabbitmq and riak (stand alone node or clustering) currently.
5
5
 
6
- ## prerequisite
6
+ ## Prerequisite
7
+
8
+ ### With boot2docker
9
+
10
+ - [install docker into Mac](https://docs.docker.com/installation/mac/)
11
+ - [install docker into Windows](https://docs.docker.com/installation/windows/)
12
+
13
+
14
+ ### Without boot2docker
15
+
16
+ The docker daemon must be started with tcp socket option like `-H tcp://0.0.0.0:2375`.
17
+ Because mcrain uses [Docker Remote API](https://docs.docker.com/reference/api/docker_remote_api/).
18
+
19
+ After [installing docker](https://docs.docker.com/installation/#installation),
20
+ edit the configuration file `/etc/default/docker` for Debian or Ubuntu,
21
+ or `/etc/sysconfig/docker` for CentOS.
22
+
23
+ And add tcp option to DOCKER_OPTS like this:
24
+
25
+ ```
26
+ DOCKER_OPTS="-H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375"
27
+ ```
28
+
29
+ Then restart the docker daemon.
30
+
31
+
32
+ Set `DOCKER_HOST` environment variable for mcrain.
33
+ ```
34
+ export DOCKER_HOST='tcp://127.0.0.1:2375'
35
+ ```
36
+
37
+ The port num must be equal to the port of tcp option in DOCKER_OPTS.
38
+
39
+ See the following documents for more information:
40
+ - https://docs.docker.com/reference/commandline/daemon/
41
+ - https://docs.docker.com/articles/networking/
7
42
 
8
- - [docker](https://docs.docker.com/installation/#installation)
9
43
 
10
44
  ## Installation
11
45
 
data/exe/mcrain CHANGED
@@ -4,8 +4,8 @@
4
4
  require "mcrain"
5
5
 
6
6
  action, service, *args = *ARGV
7
+ verbose = ARGV.include?('-V') || ARGV.include?('--verbose')
7
8
  if action.nil? || service.nil?
8
-
9
9
  $stderr.puts(<<MESSAGE)
10
10
  #{$PROGRAM_NAME} <action> <target> [n] [-v or --verbose]
11
11
  action: start or stop
@@ -41,6 +41,7 @@ begin
41
41
  end
42
42
  rescue => e
43
43
  $stderr.puts "\e[31m[#{e.class}] #{e.message}\e[0m"
44
+ $stderr.puts e.backtrace.join("\n ") if verbose
44
45
  exit(1)
45
46
  else
46
47
  $stderr.puts "\e[32mOK\e[0m"
data/lib/mcrain/base.rb CHANGED
@@ -6,63 +6,33 @@ require 'timeout'
6
6
  require 'socket'
7
7
 
8
8
  require 'logger_pipe'
9
+ require 'docker'
9
10
 
10
11
  module Mcrain
11
12
  class Base
13
+ include ContainerController
14
+ include ClientProvider
12
15
 
13
- class << self
14
- attr_writer :server_name
15
- def server_name
16
- @server_name ||= self.name.split(/::/).last.underscore.to_sym
17
- end
18
-
19
- attr_accessor :container_image, :port
16
+ def logger
17
+ Mcrain.logger
20
18
  end
21
19
 
22
- attr_accessor :skip_reset_after_stop
20
+ attr_accessor :skip_reset_after_teardown
23
21
  def reset
24
22
  instance_variables.each do |var|
25
23
  instance_variable_set(var, nil)
26
24
  end
27
25
  end
28
26
 
29
- def container_image
30
- self.class.container_image or raise "No container_image for #{self.class.name}"
31
- end
32
-
33
- def container_name
34
- "test-#{self.class.server_name}"
35
- end
36
-
37
- def host
38
- @host ||= URI.parse(ENV["DOCKER_HOST"] || "tcp://localhost").host
39
- end
40
-
41
- def find_portno
42
- # 未使用のポートをシステムに割り当てさせてすぐ閉じてそれを利用する
43
- tmpserv = TCPServer.new(0)
44
- portno = tmpserv.local_address.ip_port
45
- tmpserv.close
46
- portno
47
- end
48
-
49
- def port
50
- @port ||= find_portno
51
- end
52
-
53
- def url
54
- @url ||= "#{self.class.server_name}://#{host}:#{port}"
55
- end
56
-
57
27
  def start
58
- clear_old_container
59
- run_container
28
+ setup
60
29
  if block_given?
61
30
  begin
31
+ wait_port
62
32
  wait
63
33
  return yield(self)
64
34
  ensure
65
- stop
35
+ teardown
66
36
  end
67
37
  else
68
38
  wait
@@ -70,37 +40,22 @@ module Mcrain
70
40
  end
71
41
  end
72
42
 
73
- def clear_old_container
74
- LoggerPipe.run(logger, "docker rm #{container_name}", timeout: 10)
75
- rescue => e
76
- logger.warn("[#{e.class}] #{e.message}")
77
- end
78
-
79
- def run_container
80
- LoggerPipe.run(logger, build_docker_command, timeout: 10)
81
- end
82
-
83
- def build_docker_command
84
- "docker run #{build_docker_command_options} #{container_image}"
85
- end
86
-
87
- def build_docker_command_options
88
- r = "-d -p #{port}:#{self.class.port} --name #{container_name}"
89
- if ext = docker_extra_options
90
- r << ext
43
+ def setup
44
+ Timeout.timeout(30) do
45
+ Boot2docker.setup_docker_options
46
+ container.start!
91
47
  end
92
- r
48
+ return container
93
49
  end
94
50
 
95
- def docker_extra_options
96
- nil
51
+ # ポートがLISTENされるまで待つ
52
+ def wait_port
53
+ Mcrain.wait_port_opened(host, port, interval: 0.5, timeout: 30)
97
54
  end
98
55
 
56
+ # ポートはdockerがまずLISTENしておいて、その後コンテナ内のミドルウェアが起動するので、
57
+ # 実際にそのAPIを叩いてみて例外が起きないことを確認します。
99
58
  def wait
100
- # ポートがLISTENされるまで待つ
101
- Mcrain.wait_port_opened(host, port, interval: 0.5, timeout: 30)
102
- # ポートはdockerがまずLISTENしておいて、その後コンテナ内のredisが起動するので、
103
- # 実際にAPIを叩いてみて例外が起きないことを確認します。
104
59
  Timeout.timeout(30) do
105
60
  begin
106
61
  wait_for_ready
@@ -116,40 +71,18 @@ module Mcrain
116
71
  raise NotImplementedError
117
72
  end
118
73
 
119
- def client
120
- @client ||= build_client
121
- end
122
-
123
- def build_client
124
- require client_require
125
- yield if block_given?
126
- client_class.new(*client_init_args)
127
- end
128
-
129
- def client_require
130
- raise NotImplementedError
131
- end
132
-
133
- def client_class
134
- raise NotImplementedError
74
+ def teardown
75
+ stop_or_kill_and_remove
76
+ reset unless skip_reset_after_teardown
135
77
  end
136
78
 
137
- def client_init_args
138
- raise NotImplementedError
139
- end
140
-
141
- def client_script
142
- client
143
- "#{client_class.name}.new(*#{client_init_args.inspect})"
144
- end
145
-
146
- def stop
147
- LoggerPipe.run(logger, "docker kill #{container_name}", timeout: 10)
148
- reset unless skip_reset_after_stop
149
- end
150
-
151
- def logger
152
- Mcrain.logger
79
+ def stop_or_kill_and_remove
80
+ begin
81
+ container.stop!
82
+ rescue => e
83
+ container.kill!
84
+ end
85
+ container.remove
153
86
  end
154
87
 
155
88
  end
@@ -0,0 +1,32 @@
1
+ module Mcrain
2
+ module ClientProvider
3
+
4
+ def client
5
+ @client ||= build_client
6
+ end
7
+
8
+ def build_client
9
+ require client_require
10
+ yield if block_given?
11
+ client_class.new(*client_init_args)
12
+ end
13
+
14
+ def client_require
15
+ raise NotImplementedError
16
+ end
17
+
18
+ def client_class
19
+ raise NotImplementedError
20
+ end
21
+
22
+ def client_init_args
23
+ raise NotImplementedError
24
+ end
25
+
26
+ def client_script
27
+ client
28
+ "#{client_class.name}.new(*#{client_init_args.inspect})"
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,64 @@
1
+ # -*- coding: utf-8 -*-
2
+ module Mcrain
3
+ module ContainerController
4
+
5
+ def self.included(klass)
6
+ klass.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+ attr_writer :server_name
11
+ def server_name
12
+ @server_name ||= self.name.split(/::/).last.underscore.to_sym
13
+ end
14
+
15
+ attr_accessor :container_image, :port
16
+ end
17
+
18
+ # @return [Docker::Container]
19
+ def container
20
+ unless @container
21
+ options = build_docker_options
22
+ Mcrain.logger.info("#{self.class.name}#container Docker::Container.create(#{options.inspect})")
23
+ @container = Docker::Container.create(options)
24
+ end
25
+ @container
26
+ end
27
+
28
+ def container_image
29
+ self.class.container_image or raise "No container_image for #{self.class.name}"
30
+ end
31
+
32
+ def host
33
+ @host ||= URI.parse(ENV["DOCKER_HOST"] || "tcp://localhost").host
34
+ end
35
+
36
+ def find_portno
37
+ # 未使用のポートをシステムに割り当てさせてすぐ閉じてそれを利用する
38
+ tmpserv = TCPServer.new(0)
39
+ portno = tmpserv.local_address.ip_port
40
+ tmpserv.close
41
+ portno
42
+ end
43
+
44
+ def port
45
+ @port ||= find_portno
46
+ end
47
+
48
+ def url
49
+ @url ||= "#{self.class.server_name}://#{host}:#{port}"
50
+ end
51
+
52
+ def build_docker_options
53
+ {
54
+ 'Image' => container_image,
55
+ 'HostConfig' => {
56
+ 'PortBindings' => {
57
+ "#{self.class.port}/tcp" => [{ 'HostPort' => port.to_s }]
58
+ }
59
+ }
60
+ }
61
+ end
62
+
63
+ end
64
+ end
data/lib/mcrain/mysql.rb CHANGED
@@ -37,17 +37,20 @@ module Mcrain
37
37
  attr_accessor :database
38
38
  attr_accessor :username, :password
39
39
 
40
- def docker_extra_options
41
- opts = ['']
40
+ def build_docker_options
41
+ r = super
42
+
42
43
  username = self.username || "root" # overwrite locally
43
44
  key_user = (username == "root") ? nil : "MYSQL_USER"
44
45
  key_pw = (username == "root") ? "MYSQL_ROOT_PASSWORD" : "MYSQL_PASSWORD"
45
-
46
- opts << (password.blank? ? "-e MYSQL_ALLOW_EMPTY_PASSWORD=yes" : "-e #{key_pw}=#{password}")
47
- opts << (key_user ? "-e #{key_user}=#{username}" : nil)
48
- opts << "-e MYSQL_DATABASE=#{database}" if database
49
- opts << "-v #{File.expand_path(db_dir)}:/var/lib/mysql" if db_dir
50
- opts.compact.join(' ')
46
+ envs = []
47
+ envs << (password.blank? ? "MYSQL_ALLOW_EMPTY_PASSWORD=yes" : "#{key_pw}=#{password}")
48
+ envs << "#{key_user}=#{username}" if key_user
49
+ envs << "MYSQL_DATABASE=#{database}" if database
50
+ envs << "#{File.expand_path(db_dir)}:/var/lib/mysql" if db_dir
51
+ r['Env'] = envs unless envs.empty?
52
+ return r
51
53
  end
54
+
52
55
  end
53
56
  end
@@ -8,9 +8,12 @@ module Mcrain
8
8
  self.server_name = :rabbitmq
9
9
 
10
10
  self.container_image = "rabbitmq:3.4.4-management"
11
+ self.port = 15672
11
12
 
12
- def build_docker_command_options
13
- "-d -p #{runtime_port}:5672 -p #{port}:15672 --name #{container_name}"
13
+ def build_docker_options
14
+ r = super
15
+ r['HostConfig']['PortBindings']["5672/tcp"] = [{ 'HostPort' => runtime_port.to_s }]
16
+ return r
14
17
  end
15
18
 
16
19
  def runtime_port
data/lib/mcrain/redis.rb CHANGED
@@ -28,8 +28,13 @@ module Mcrain
28
28
 
29
29
  attr_accessor :db_dir
30
30
 
31
- def docker_extra_options
32
- db_dir ? " -v #{File.expand_path(db_dir)}:/data" : nil
31
+ def build_docker_options
32
+ r = super
33
+ if db_dir
34
+ r['Volumes'] ||= {}
35
+ r['Volumes']["/data"] = File.expand_path(db_dir)
36
+ end
37
+ return r
33
38
  end
34
39
  end
35
40
  end
data/lib/mcrain/riak.rb CHANGED
@@ -1,27 +1,84 @@
1
+ # -*- coding: utf-8 -*-
1
2
  require 'mcrain'
2
3
 
3
4
  # require 'riak'
5
+ require 'net/http'
4
6
 
5
7
  module Mcrain
6
8
  class Riak < Base
7
9
 
8
- class << self
9
- # path to clone of https://github.com/hectcastro/docker-riak
10
- attr_accessor :docker_riak_path
10
+ self.server_name = :riak
11
+
12
+ self.container_image = "hectcastro/riak"
13
+
14
+ attr_accessor :automatic_clustering
15
+ attr_writer :cluster_size, :backend
16
+ def cluster_size
17
+ @cluster_size ||= 1
18
+ end
19
+ def backend
20
+ @backend ||= "bitcask" # "leveldb"
11
21
  end
12
22
 
13
- self.server_name = :riak
23
+ # docker run -e "DOCKER_RIAK_CLUSTER_SIZE=${DOCKER_RIAK_CLUSTER_SIZE}" \
24
+ # -e "DOCKER_RIAK_AUTOMATIC_CLUSTERING=${DOCKER_RIAK_AUTOMATIC_CLUSTERING}" \
25
+ # -e "DOCKER_RIAK_BACKEND=${DOCKER_RIAK_BACKEND}" \
26
+ # -p $publish_http_port \
27
+ # -p $publish_pb_port \
28
+ # --link "riak01:seed" \
29
+ # --name "riak${index}" \
30
+ # -d hectcastro/riak > /dev/null 2>&1
31
+ class Node
32
+ include ContainerController
33
+
34
+ self.container_image = "hectcastro/riak"
35
+
36
+ self.port = 8087 # protocol buffer
37
+ # self.http_port = 8098 # HTTP
38
+
39
+ attr_reader :owner
40
+ attr_accessor :primary_node
41
+ def initialize(owner)
42
+ @owner = owner
43
+ end
44
+
45
+ def http_port
46
+ @http_port ||= find_portno
47
+ end
14
48
 
15
- self.container_image = nil # not use docker directly
16
- self.port = 8087
49
+ def build_docker_options
50
+ r = super
51
+ r['HostConfig']['PortBindings']["8098/tcp"] = [{ 'HostPort' => http_port.to_s }]
52
+ envs = []
53
+ envs << "RIAK_CLUSTER_SIZE=#{owner.cluster_size}"
54
+ envs << "DOCKER_RIAK_AUTOMATIC_CLUSTERING=#{owner.automatic_clustering ? 1 : 0}"
55
+ envs << "DOCKER_RIAK_BACKEND=#{owner.backend}"
56
+ r['Env'] = envs unless envs.empty?
57
+ if primary_node
58
+ r['HostConfig']['Links'] = ["#{primary_node.container.name}:seed"]
59
+ end
60
+ return r
61
+ end
17
62
 
18
- def wait
19
- build_uris
20
- super
63
+ def ping
64
+ owner.logger.debug("sending a ping http://#{host}:#{http_port}/stats")
65
+ res = Net::HTTP.start(host, http_port) {|http| http.get('/stats') }
66
+ r = res.is_a?(Net::HTTPSuccess)
67
+ owner.logger.debug("#{res.inspect} #=> #{r}")
68
+ return r
69
+ rescue => e
70
+ return false
71
+ end
21
72
  end
22
73
 
23
- def build_client
24
- super{ build_uris }
74
+ def nodes
75
+ unless @nodes
76
+ @nodes = (cluster_size || 1).times.map{ Node.new(self) }
77
+ array = @nodes.dup
78
+ primary_node = array.shift
79
+ array.each{|node| node.primary_node = primary_node}
80
+ end
81
+ @nodes
25
82
  end
26
83
 
27
84
  def client_class
@@ -29,53 +86,20 @@ module Mcrain
29
86
  end
30
87
 
31
88
  def client_init_args
32
- options = {
33
- nodes: uris.map{|uri| {host: uri.host, pb_port: uri.port} }
34
- }
35
- if uri = uris.first
36
- if !uri.user.blank? or !uri.password.blank?
37
- options[:authentication] = {user: uri.user, password: uri.password}
38
- end
39
- end
40
- [options]
89
+ return [
90
+ {
91
+ nodes: nodes.map{|node| {host: node.host, pb_port: node.port} }
92
+ }
93
+ ]
41
94
  end
42
95
 
43
96
  def client_require
44
97
  'riak'
45
98
  end
46
99
 
47
- def build_uris
48
- # https://github.com/hectcastro/docker-riak/blob/develop/bin/test-cluster.sh#L9
49
-
50
- # http://docs.docker.com/reference/api/docker_remote_api/
51
- # https://github.com/boot2docker/boot2docker#ssh-into-vm
52
- Boot2docker.setup_docker_options
53
-
54
- uri = URI.parse(ENV["DOCKER_HOST"])
55
- @host = (uri.scheme == "unix") ? "localhost" : uri.host
56
- list = Docker::Container.all
57
- riak_containers = list.select{|r| r.info['Image'] =~ /\Ahectcastro\/riak(\:.+)?\z/}
58
- @cids = riak_containers.map(&:id)
59
- @pb_ports = riak_containers.map do |r|
60
- map = r.info['Ports'].each_with_object({}){|rr,d| d[ rr['PrivatePort'] ] = rr['PublicPort']}
61
- map[8087]
62
- end
63
- @port = @pb_ports.first
64
- @admin_uris = @cids.map do |cid|
65
- r = Docker::Container.get(cid)
66
- host = r.info["NetworkSettings"]["IPAddress"]
67
- # login with insecure_key
68
- # https://github.com/phusion/baseimage-docker#using-the-insecure-key-for-one-container-only
69
- "ssh://root@#{host}:22"
70
- end
71
- @uris = @pb_ports.map do |port|
72
- URI::Generic.build(scheme: "riak", host: @host, port: port)
73
- end
74
- end
75
-
76
100
  def wait_for_ready
77
101
  c = client
78
- logger.debug("sending a ping")
102
+ logger.debug("sending a ping from client")
79
103
  begin
80
104
  r = c.ping
81
105
  raise "Ping failure with #{c.inspect}" unless r
@@ -105,54 +129,42 @@ module Mcrain
105
129
  end
106
130
  end
107
131
 
108
- def clear_old_container
109
- end
110
-
111
- attr_reader :host, :cids, :pb_ports, :uris, :admin_uris
112
- attr_accessor :automatic_clustering, :cluster_size
113
-
114
132
  def setup
115
- w = @work_dir = Mcrain::Riak.docker_riak_path
116
- raise "#{self.class.name}.docker_riak_path is blank. You have to set it to use the class" if w.blank?
117
- raise "#{w}/Makefile not found" unless File.readable?(File.join(w, "Makefile"))
118
- @prepare_cmd = Boot2docker.preparing_command
119
- @automatic_clustering = false
120
- @cluster_size = 1
121
- end
122
-
123
- def build_command
124
- "DOCKER_RIAK_AUTOMATIC_CLUSTERING=#{automatic_clustering ? 1 : 0} DOCKER_RIAK_CLUSTER_SIZE=#{cluster_size} make start-cluster"
133
+ Boot2docker.setup_docker_options
134
+ nodes.map(&:container).each(&:start!)
135
+ # http://basho.co.jp/riak-quick-start-with-docker/
136
+ #
137
+ # "Please wait approximately 30 seconds for the cluster to stabilize"
138
+ # from https://gist.github.com/agutow/11133143#file-docker3-sh-L12
139
+ sleep(30)
140
+ nodes.each do |node|
141
+ success = false
142
+ 20.times do
143
+ success = node.ping
144
+ break if success
145
+ sleep(3)
146
+ end
147
+ raise "failed to run a riak server" unless success
148
+ end
125
149
  end
126
150
 
127
- def run_container
128
- setup
129
- logger.debug("cd #{@work_dir.inspect}")
130
- Dir.chdir(@work_dir) do
131
- # http://basho.co.jp/riak-quick-start-with-docker/
132
- #
133
- # "Please wait approximately 30 seconds for the cluster to stabilize"
134
- # from https://gist.github.com/agutow/11133143#file-docker3-sh-L12
135
- LoggerPipe.run(logger, "#{@prepare_cmd} #{build_command}")
136
- sleep(1)
137
- 20.times do
138
- begin
139
- LoggerPipe.run(logger, "#{@prepare_cmd} make test-cluster")
140
- sleep(5)
141
- return
142
- rescue
143
- sleep(0.5)
144
- retry
145
- end
151
+ def teardown
152
+ nodes.map(&:container).each do |c|
153
+ begin
154
+ c.stop!
155
+ rescue => e
156
+ c.kill!
146
157
  end
147
- raise "failed to run a riak server"
158
+ c.remove
148
159
  end
160
+ reset unless skip_reset_after_teardown
149
161
  end
150
162
 
151
- def stop
152
- Dir.chdir(@work_dir) do
153
- LoggerPipe.run(logger, "#{@prepare_cmd} make stop-cluster")
163
+ # ポートがLISTENされるまで待つ
164
+ def wait_port
165
+ nodes.each do |node|
166
+ Mcrain.wait_port_opened(node.host, node.port, interval: 0.5, timeout: 30)
154
167
  end
155
- reset unless skip_reset_after_stop
156
168
  end
157
169
 
158
170
  end
@@ -1,3 +1,3 @@
1
1
  module Mcrain
2
- VERSION = "0.1.4"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/mcrain.rb CHANGED
@@ -77,6 +77,8 @@ module Mcrain
77
77
 
78
78
  autoload :Base, 'mcrain/base'
79
79
  autoload :Boot2docker, 'mcrain/boot2docker'
80
+ autoload :ContainerController, 'mcrain/container_controller'
81
+ autoload :ClientProvider, 'mcrain/client_provider'
80
82
 
81
83
  autoload :Riak, 'mcrain/riak'
82
84
  autoload :Redis, 'mcrain/redis'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mcrain
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - akm
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-06-19 00:00:00.000000000 Z
11
+ date: 2015-07-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: logger_pipe
@@ -122,6 +122,8 @@ files:
122
122
  - lib/mcrain.rb
123
123
  - lib/mcrain/base.rb
124
124
  - lib/mcrain/boot2docker.rb
125
+ - lib/mcrain/client_provider.rb
126
+ - lib/mcrain/container_controller.rb
125
127
  - lib/mcrain/mysql.rb
126
128
  - lib/mcrain/rabbitmq.rb
127
129
  - lib/mcrain/redis.rb