mcrain 0.1.4 → 0.2.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 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