mcrain 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c1a06ee8da82a778eea1700f2366af6a025a6456
4
+ data.tar.gz: 77b113a4873c5acd9d2f6ed093e56092c6648929
5
+ SHA512:
6
+ metadata.gz: 8af73c32ed5d7e65b217be6cd30c35c72b1e9778812344b04b03b1e0e96957b08dbc0146a23694c62c7d7c34711ee6969b6664ad66732005d438779c5069f1db
7
+ data.tar.gz: 2895f8d1a5df7e7020045e798badc8290f3d112e3191256b5e4f112ecbd751fe96feae65cda8f8bbdd0e8e32475e2d4ebef1a166ea5ee16c7e19057c41259d8b
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /log/*.log
data/.gitmodules ADDED
@@ -0,0 +1,3 @@
1
+ [submodule "spec/support/docker-riak"]
2
+ path = spec/support/docker-riak
3
+ url = git@github.com:hectcastro/docker-riak.git
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.0
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,24 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in mcrain.gemspec
4
+ gemspec
5
+
6
+ group :development do
7
+ # for redis
8
+ gem "redis"
9
+
10
+ # for rabbitmq
11
+ gem 'rabbitmq_http_api_client', '>= 1.6.0'
12
+
13
+ # for riak
14
+ gem "docker-api", "~> 1.21.1"
15
+ gem "riak-client"
16
+ end
17
+
18
+ group :development do
19
+ gem "pry"
20
+ gem "pry-byebug"
21
+ gem "pry-stack_explorer"
22
+ gem "simplecov"
23
+ gem "fuubar"
24
+ end
data/README.md ADDED
@@ -0,0 +1,150 @@
1
+ # Mcrain
2
+
3
+ Mcrain helps you to use docker container in test cases.
4
+ It supports redis, rabbitmq and riak (stand alone node or clustering) currently.
5
+
6
+ ## prerequisite
7
+
8
+ - [docker](https://docs.docker.com/installation/#installation)
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'mcrain'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install mcrain
25
+
26
+ ### with redis
27
+
28
+ Add this line also to your application's Gemfile
29
+ ```ruby
30
+ gem 'redis'
31
+ ```
32
+
33
+ ### with rabbitmq
34
+
35
+ Add this line also to your application's Gemfile
36
+ ```ruby
37
+ gem 'rabbitmq_http_api_client', '>= 1.6.0'
38
+ ```
39
+
40
+ ### with riak
41
+
42
+ Add this line also to your application's Gemfile
43
+ ```ruby
44
+ gem 'docker-api', '~> 1.21.1'
45
+ gem 'riak-client'
46
+ ```
47
+
48
+ ## Usage
49
+
50
+ ### redis in code
51
+
52
+ ```ruby
53
+ Mcrain[:redis].start do |s|
54
+ c = s.client # Redis::Client object
55
+ c.ping
56
+ end
57
+ ```
58
+
59
+ ### rabbitmq in code
60
+
61
+ ```ruby
62
+ Mcrain[:rabbitmq].start do |s|
63
+ c = s.client # RabbitMQ::HTTP::Client object
64
+ c.list_nodes
65
+ end
66
+ ```
67
+
68
+ ### riak in code
69
+
70
+ Mcrain::Riak uses [docker-riak](https://github.com/hectcastro/docker-riak).
71
+ So set the path to `Mcrain.docker_riak_path` .
72
+
73
+ ```ruby
74
+ Mcrain.docker_riak_path = "path/to/docker-riak"
75
+ Mcrain[:riak].start do |s|
76
+ c = s.client # Riak::Client object
77
+ obj = c.bucket("bucket1").get_or_new("foo")
78
+ obj.data = data
79
+ obj.store
80
+ end
81
+ ```
82
+
83
+
84
+ ### redis in terminal
85
+
86
+ ```
87
+ $ mcrain start redis
88
+ To connect:
89
+ require 'redis'
90
+ client = Redis.new({:host=>"192.168.59.103", :port=>50669})
91
+ OK
92
+
93
+ $ mcrain stop redis
94
+ OK
95
+ ```
96
+
97
+ ### rabbitmq in terminal
98
+
99
+ ```
100
+ $ mcrain start rabbitmq
101
+ To connect:
102
+ require 'rabbitmq/http/client'
103
+ client = RabbitMQ::HTTP::Client.new(*["http://192.168.59.103:50684", {:username=>"guest", :password=>"guest"}])
104
+ OK
105
+
106
+ $ mcrain stop rabbitmq
107
+ OK
108
+ ```
109
+
110
+ ### riak in terminal
111
+
112
+ ```
113
+ $ export DOCKER_RIAK_PATH=/path/to/docker-riak
114
+ $ mcrain start riak
115
+ To connect:
116
+ require 'riak'
117
+ client = Riak::Client.new({:nodes=>[{:host=>"192.168.59.103", :pb_port=>33152}]})
118
+ OK
119
+
120
+ $ mcrain stop riak
121
+ OK
122
+ ```
123
+
124
+
125
+ ```
126
+ $ export DOCKER_RIAK_PATH=/path/to/docker-riak
127
+ $ mcrain start riak 5
128
+ To connect:
129
+ require 'riak'
130
+ client = Riak::Client.new({:nodes=>[{:host=>"192.168.59.103", :pb_port=>33162}, {:host=>"192.168.59.103", :pb_port=>33160}, {:host=>"192.168.59.103", :pb_port=>33158}, {:host=>"192.168.59.103", :pb_port=>33157}, {:host=>"192.168.59.103", :pb_port=>33155}]})
131
+ OK
132
+
133
+ $ mcrain stop riak 5
134
+ OK
135
+ ```
136
+
137
+
138
+ ## Development
139
+
140
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment. Run `bundle exec mcrain` to use the code located in this directory, ignoring other installed copies of this gem.
141
+
142
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
143
+
144
+ ## Contributing
145
+
146
+ 1. Fork it ( https://github.com/groovenauts/mcrain/fork )
147
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
148
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
149
+ 4. Push to the branch (`git push origin my-new-feature`)
150
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "mcrain"
5
+
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
+
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/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
data/exe/mcrain ADDED
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+ # coding: utf-8
3
+
4
+ require "mcrain"
5
+
6
+ action, service, *args = *ARGV
7
+ if action.nil? || service.nil?
8
+
9
+ $stderr.puts(<<MESSAGE)
10
+ #{$PROGRAM_NAME} <action> <target> [n] [-v or --verbose]
11
+ action: start or stop
12
+ service: redis, rabbitmq or riak
13
+ n: cluster size for riak
14
+ MESSAGE
15
+
16
+ exit(1)
17
+ end
18
+
19
+ unless args.include?("-v") || args.include?("--verbose")
20
+ require 'logger'
21
+ Mcrain.logger = Logger.new("/dev/null")
22
+ end
23
+
24
+ begin
25
+ options = {}
26
+ case service
27
+ when "riak" then
28
+ raise "DOCKER_RIAK_PATH is blank. Set it the path to docker-riak repository." unless ENV['DOCKER_RIAK_PATH']
29
+ Mcrain::Riak.docker_riak_path = ENV['DOCKER_RIAK_PATH']
30
+ cluster_size = args.shift.to_i
31
+ cluster_size = 1 if cluster_size == 0
32
+ options = {cluster_size: cluster_size, automatic_clustering: cluster_size > 1}
33
+ end
34
+
35
+ server = Mcrain.lookup(service.to_sym, options)
36
+ server.send(action)
37
+
38
+ case action
39
+ when "start" then
40
+ puts "To connect:\nrequire '#{server.client_require}'\nclient = #{server.client_script}"
41
+ end
42
+ rescue => e
43
+ $stderr.puts "\e[31m[#{e.class}] #{e.message}\e[0m"
44
+ exit(1)
45
+ else
46
+ $stderr.puts "\e[32mOK\e[0m"
47
+ exit(0)
48
+ end
@@ -0,0 +1,133 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'mcrain'
3
+
4
+ require 'uri'
5
+ require 'timeout'
6
+
7
+ require 'logger_pipe'
8
+
9
+ module Mcrain
10
+ class Base
11
+
12
+ class << self
13
+ attr_writer :server_name
14
+ def server_name
15
+ @server_name ||= self.name.split(/::/).last.underscore.to_sym
16
+ end
17
+
18
+ attr_accessor :container_image, :port
19
+ end
20
+
21
+ def container_image
22
+ self.class.container_image or raise "No container_image for #{self.class.name}"
23
+ end
24
+
25
+ def container_name
26
+ "test-#{self.class.server_name}"
27
+ end
28
+
29
+ def host
30
+ @host ||= URI.parse(ENV["DOCKER_HOST"] || "tcp://localhost").host
31
+ end
32
+
33
+ def find_portno
34
+ # 未使用のポートをシステムに割り当てさせてすぐ閉じてそれを利用する
35
+ tmpserv = TCPServer.new(0)
36
+ portno = tmpserv.local_address.ip_port
37
+ tmpserv.close
38
+ portno
39
+ end
40
+
41
+ def port
42
+ @port ||= find_portno
43
+ end
44
+
45
+ def url
46
+ @url ||= "#{self.class.server_name}://#{host}:#{port}"
47
+ end
48
+
49
+ def start
50
+ clear_old_container
51
+ run_container
52
+ if block_given?
53
+ begin
54
+ wait
55
+ return yield(self)
56
+ ensure
57
+ stop
58
+ end
59
+ else
60
+ wait
61
+ return self
62
+ end
63
+ end
64
+
65
+ def clear_old_container
66
+ LoggerPipe.run(logger, "docker rm #{container_name}", timeout: 10)
67
+ rescue => e
68
+ logger.warn("[#{e.class}] #{e.message}")
69
+ end
70
+
71
+ def run_container
72
+ s = LoggerPipe.run(logger, build_docker_command, timeout: 10)
73
+
74
+ end
75
+
76
+ def build_docker_command
77
+ "docker run #{build_docker_command_options} #{container_image}"
78
+ end
79
+
80
+ def build_docker_command_options
81
+ r = "-d -p #{port}:#{self.class.port} --name #{container_name}"
82
+ if ext = docker_extra_options
83
+ r << ext
84
+ end
85
+ r
86
+ end
87
+
88
+ def docker_extra_options
89
+ nil
90
+ end
91
+
92
+ def wait
93
+ # ポートがLISTENされるまで待つ
94
+ Mcrain.wait_port_opened(host, port, interval: 0.5, timeout: 30)
95
+ # ポートはdockerがまずLISTENしておいて、その後コンテナ内のredisが起動するので、
96
+ # 実際にAPIを叩いてみて例外が起きないことを確認します。
97
+ Timeout.timeout(30) do
98
+ begin
99
+ wait_for_ready
100
+ rescue => e
101
+ # $stderr.puts "[#{e.class}] #{e.message}"
102
+ sleep(1)
103
+ retry
104
+ end
105
+ end
106
+ end
107
+
108
+ def wait_for_ready
109
+ raise NotImplementedError
110
+ end
111
+
112
+ def client
113
+ raise NotImplementedError
114
+ end
115
+
116
+ def client_require
117
+ raise NotImplementedError
118
+ end
119
+
120
+ def client_script
121
+ raise NotImplementedError
122
+ end
123
+
124
+ def stop
125
+ LoggerPipe.run(logger, "docker kill #{container_name}", timeout: 10)
126
+ end
127
+
128
+ def logger
129
+ Mcrain.logger
130
+ end
131
+
132
+ end
133
+ end
@@ -0,0 +1,72 @@
1
+ require 'mcrain'
2
+
3
+ require 'uri'
4
+ require 'fileutils'
5
+ require 'rbconfig'
6
+
7
+ require 'net/scp'
8
+ require 'docker'
9
+
10
+ module Mcrain
11
+ module Boot2docker
12
+
13
+ class << self
14
+ attr_accessor :certs_dir
15
+ end
16
+ self.certs_dir = File.expand_path('.boot2docker/certs/boot2docker-vm', ENV["HOME"])
17
+
18
+ module_function
19
+
20
+ def used?
21
+ RbConfig::CONFIG["host_os"] =~ /darwin/
22
+ end
23
+
24
+ def preparing_command
25
+ return "" unless used?
26
+ unless `boot2docker status`.strip == "running"
27
+ raise "boot2docker is not running. Please `boot2docker start`"
28
+ end
29
+ "%s && " % `boot2docker shellinit`.strip.split(/\n/).join(" && ")
30
+ end
31
+
32
+ def setup_docker_options
33
+ if RbConfig::CONFIG["host_os"] =~ /darwin/
34
+ require 'docker'
35
+ uri = URI.parse(ENV["DOCKER_HOST"])
36
+ Excon.defaults[:ssl_verify_peer] = false
37
+ Docker.options = build_docker_options(uri)
38
+ elsif ENV["DOCKER_HOST"].nil?
39
+ ENV["DOCKER_HOST"] = "http://localhost:2375"
40
+ end
41
+ end
42
+
43
+ def build_docker_options(uri)
44
+ d = Boot2docker.certs_dir
45
+ cert_path = File.join(d, "cert.pem")
46
+ key_path = File.join(d, "key.pem")
47
+ files = {
48
+ ".docker/cert.pem" => cert_path,
49
+ ".docker/key.pem" => key_path,
50
+ }
51
+ download_files_from_vm(uri.host, files)
52
+ return {
53
+ client_cert: cert_path,
54
+ client_key: key_path,
55
+ scheme: 'https',
56
+ }
57
+ end
58
+
59
+ # http://docs.docker.com/reference/api/docker_remote_api/
60
+ # https://github.com/boot2docker/boot2docker#ssh-into-vm
61
+ def download_files_from_vm(host, files)
62
+ return if files.values.all?{|f| File.readable?(f)}
63
+ files.values.each{|f| FileUtils.mkdir_p(File.dirname(f))}
64
+ Net::SCP.start(host, "docker", :password => "tcuser") do |scp|
65
+ files.each do |src, dest|
66
+ scp.download(src, dest)
67
+ end
68
+ end
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,57 @@
1
+ require 'mcrain'
2
+
3
+ # don't require 'rabbitmq/http/client' here in order to use mcrain without 'rabbitmq_http_api_client' gem
4
+ # require 'rabbitmq/http/client'
5
+
6
+ module Mcrain
7
+ class Rabbitmq < Base
8
+ self.server_name = :rabbitmq
9
+
10
+ self.container_image = "rabbitmq:3.4.4-management"
11
+
12
+ def build_docker_command_options
13
+ "-d -p #{runtime_port}:5672 -p #{port}:15672 --name #{container_name}"
14
+ end
15
+
16
+ def runtime_port
17
+ @runtime_port ||= find_portno
18
+ end
19
+
20
+ def url
21
+ "http://#{username}:#{password}@#{host}:#{port}"
22
+ end
23
+
24
+ def runtime_url
25
+ "rabbitmq://#{host}:#{runtime_port}"
26
+ end
27
+
28
+ def username
29
+ "guest"
30
+ end
31
+ def password
32
+ "guest"
33
+ end
34
+
35
+ def client
36
+ require client_require
37
+ @client ||= RabbitMQ::HTTP::Client.new(*build_client_args)
38
+ end
39
+
40
+ def build_client_args
41
+ ["http://#{host}:#{port}", {username: username, password: password}]
42
+ end
43
+
44
+ def client_require
45
+ 'rabbitmq/http/client'
46
+ end
47
+
48
+ def client_script
49
+ client
50
+ "RabbitMQ::HTTP::Client.new(*#{build_client_args.inspect})"
51
+ end
52
+
53
+ def wait_for_ready
54
+ client.list_users
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,41 @@
1
+ require 'mcrain'
2
+
3
+ # don't require 'redis' here in order to use mcrain without 'redis' gem
4
+ # require 'redis'
5
+
6
+ module Mcrain
7
+ class Redis < Base
8
+ self.server_name = :redis
9
+
10
+ self.container_image = "redis:2.8.19"
11
+ self.port = 6379
12
+
13
+ def client
14
+ require client_require
15
+ @client ||= ::Redis.new(build_client_options)
16
+ end
17
+
18
+ def build_client_options
19
+ {host: host, port: port}
20
+ end
21
+
22
+ def client_require
23
+ 'redis'
24
+ end
25
+
26
+ def client_script
27
+ client
28
+ "Redis.new(#{build_client_options.inspect})"
29
+ end
30
+
31
+ def wait_for_ready
32
+ client.keys
33
+ end
34
+
35
+ attr_accessor :db_dir
36
+
37
+ def docker_extra_options
38
+ db_dir ? " -v #{File.expand_path(db_dir)}:/data" : nil
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,155 @@
1
+ require 'mcrain'
2
+
3
+ # require 'riak'
4
+
5
+ module Mcrain
6
+ class Riak < Base
7
+
8
+ class << self
9
+ # path to clone of https://github.com/hectcastro/docker-riak
10
+ attr_accessor :docker_riak_path
11
+ end
12
+
13
+ self.server_name = :riak
14
+
15
+ self.container_image = nil # not use docker directly
16
+ self.port = 8087
17
+
18
+ def wait
19
+ build_uris
20
+ super
21
+ end
22
+
23
+ def client
24
+ unless @client
25
+ require client_require
26
+ build_uris
27
+ @client = ::Riak::Client.new(build_client_options)
28
+ end
29
+ @client
30
+ end
31
+
32
+ def build_client_options
33
+ options = {
34
+ nodes: uris.map{|uri| {host: uri.host, pb_port: uri.port} }
35
+ }
36
+ if uri = uris.first
37
+ if !uri.user.blank? or !uri.password.blank?
38
+ options[:authentication] = {user: uri.user, password: uri.password}
39
+ end
40
+ end
41
+ options
42
+ end
43
+
44
+ def client_require
45
+ 'riak'
46
+ end
47
+
48
+ def client_script
49
+ client
50
+ "Riak::Client.new(#{build_client_options.inspect})"
51
+ end
52
+
53
+ def build_uris
54
+ # https://github.com/hectcastro/docker-riak/blob/develop/bin/test-cluster.sh#L9
55
+
56
+ # http://docs.docker.com/reference/api/docker_remote_api/
57
+ # https://github.com/boot2docker/boot2docker#ssh-into-vm
58
+ Boot2docker.setup_docker_options
59
+
60
+ uri = URI.parse(ENV["DOCKER_HOST"])
61
+ @host = (uri.scheme == "unix") ? "localhost" : uri.host
62
+ list = Docker::Container.all
63
+ riak_containers = list.select{|r| r.info['Image'] == "hectcastro/riak:latest"}
64
+ @cids = riak_containers.map(&:id)
65
+ @pb_ports = riak_containers.map do |r|
66
+ map = r.info['Ports'].each_with_object({}){|rr,d| d[ rr['PrivatePort'] ] = rr['PublicPort']}
67
+ map[8087]
68
+ end
69
+ @port = @pb_ports.first
70
+ @admin_uris = @cids.map do |cid|
71
+ r = Docker::Container.get(cid)
72
+ host = r.info["NetworkSettings"]["IPAddress"]
73
+ # login with insecure_key
74
+ # https://github.com/phusion/baseimage-docker#using-the-insecure-key-for-one-container-only
75
+ "ssh://root@#{host}:22"
76
+ end
77
+ @uris = @pb_ports.map do |port|
78
+ URI::Generic.build(scheme: "riak", host: @host, port: port)
79
+ end
80
+ end
81
+
82
+ def wait_for_ready
83
+ c = client
84
+ logger.debug("sending a ping")
85
+ r = c.ping
86
+ raise "Ping failure with #{c.inspect}" unless r
87
+ 20.times do |i|
88
+ begin
89
+ logger.debug("get and store ##{i}")
90
+ o1 = c.bucket("test").get_or_new("foo")
91
+ o1.data = {"bar" => 100}
92
+ o1.store
93
+ o2 = c.bucket("test").get_or_new("foo")
94
+ raise "Something wrong!" unless o2.data == o1.data
95
+ break
96
+ rescue => e
97
+ if e.message =~ /Expected success from Riak but received 0/
98
+ sleep(0.5)
99
+ logger.debug("retrying [#{e.class}] #{e.message}")
100
+ retry
101
+ else
102
+ logger.warn(e)
103
+ raise
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ def clear_old_container
110
+ end
111
+
112
+ attr_reader :host, :cids, :pb_ports, :uris, :admin_uris
113
+ attr_accessor :automatic_clustering, :cluster_size
114
+
115
+ def initialize
116
+ w = @work_dir = Mcrain::Riak.docker_riak_path
117
+ raise "#{self.class.name}.docker_riak_path is blank. You have to set it to use the class" if w.blank?
118
+ raise "#{w}/Makefile not found" unless File.readable?(File.join(w, "Makefile"))
119
+ @prepare_cmd = Boot2docker.preparing_command
120
+ @automatic_clustering = false
121
+ @cluster_size = 1
122
+ end
123
+
124
+ def build_command
125
+ "DOCKER_RIAK_AUTOMATIC_CLUSTERING=#{automatic_clustering ? 1 : 0} DOCKER_RIAK_CLUSTER_SIZE=#{cluster_size} make start-cluster"
126
+ end
127
+
128
+ def run_container
129
+ logger.debug("cd #{@work_dir.inspect}")
130
+ Dir.chdir(@work_dir) do
131
+ # http://basho.co.jp/riak-quick-start-with-docker/
132
+ LoggerPipe.run(logger, "#{@prepare_cmd} #{build_command}")
133
+ sleep(1)
134
+ 20.times do
135
+ begin
136
+ LoggerPipe.run(logger, "#{@prepare_cmd} make test-cluster")
137
+ sleep(45) # Please wait approximately 30 seconds for the cluster to stabilize
138
+ return
139
+ rescue
140
+ sleep(0.5)
141
+ retry
142
+ end
143
+ end
144
+ raise "failed to run a riak server"
145
+ end
146
+ end
147
+
148
+ def stop
149
+ Dir.chdir(@work_dir) do
150
+ LoggerPipe.run(logger, "#{@prepare_cmd} make stop-cluster")
151
+ end
152
+ end
153
+
154
+ end
155
+ end
@@ -0,0 +1,3 @@
1
+ module Mcrain
2
+ VERSION = "0.1.0"
3
+ end
data/lib/mcrain.rb ADDED
@@ -0,0 +1,88 @@
1
+ require "mcrain/version"
2
+
3
+ require 'timeout'
4
+ require 'logger'
5
+
6
+ require 'logger_pipe'
7
+
8
+ require 'active_support/inflector/inflections'
9
+ require 'active_support/core_ext/class/subclasses'
10
+ require 'active_support/core_ext/object/blank'
11
+
12
+ module Mcrain
13
+ class << self
14
+ def [](name)
15
+ lookup(name)
16
+ end
17
+
18
+ def lookup(name, options = {})
19
+ klass = class_for(name.to_sym)
20
+ r = instances[name] ||= klass.new
21
+ options.each{|k,v| r.send("#{k}=", v)}
22
+ r
23
+ end
24
+
25
+ def class_names
26
+ @class_names ||= {}
27
+ end
28
+
29
+ def class_for(name)
30
+ if class_name = class_names[name]
31
+ class_name.constantize
32
+ else
33
+ if klass = Mcrain::Base.descendants.detect{|c| c.server_name == name}
34
+ class_names[name] = klass.name
35
+ end
36
+ klass
37
+ end
38
+ end
39
+
40
+ def register(name, class_name)
41
+ class_names[name] = class_name
42
+ end
43
+
44
+ def instances
45
+ @instances ||= {}
46
+ end
47
+
48
+ def pull_images
49
+ Mcrain::Base.descendants.each do |klass|
50
+ Timeout.timeout(10.minutes) do
51
+ LoggerPipe.run(logger, "docker pull #{klass.container_image}")
52
+ end
53
+ end
54
+ end
55
+
56
+ attr_writer :logger
57
+ def logger
58
+ @logger ||= Logger.new($stderr)
59
+ end
60
+
61
+ def wait_port_opened(host, port, options = {})
62
+ logger.debug("wait_port_opened(#{host.inspect}, #{port.inspect}, #{options.inspect})")
63
+ interval = options[:interval] || 10 # second
64
+ Timeout.timeout(options[:timeout] || 60) do
65
+ begin
66
+ s = TCPSocket.open(host, port)
67
+ s.close
68
+ return true
69
+ rescue Errno::ECONNREFUSED
70
+ sleep(interval)
71
+ retry
72
+ end
73
+ end
74
+ end
75
+
76
+ end
77
+
78
+ autoload :Base, 'mcrain/base'
79
+ autoload :Boot2docker, 'mcrain/boot2docker'
80
+
81
+ autoload :Riak, 'mcrain/riak'
82
+ autoload :Redis, 'mcrain/redis'
83
+ autoload :Rabbitmq, 'mcrain/rabbitmq'
84
+
85
+ register :riak, "Mcrain::Riak"
86
+ register :redis, "Mcrain::Redis"
87
+ register :rabbitmq, "Mcrain::Rabbitmq"
88
+ end
data/mcrain.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mcrain/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "mcrain"
8
+ spec.version = Mcrain::VERSION
9
+ spec.authors = ["akm"]
10
+ spec.email = ["t-akima@groovenauts.jp"]
11
+
12
+ spec.summary = %q{mcrain supports to run docker container for test.}
13
+ spec.description = %q{mcrain supports to run docker container for test.}
14
+ spec.homepage = "https://github.com/groovenauts/mcrain"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_runtime_dependency "logger_pipe", "~> 0.3.1"
23
+ spec.add_runtime_dependency "net-scp", "~> 1.2.1"
24
+ spec.add_runtime_dependency "activesupport", ">= 3.0", "< 5.0"
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.9"
27
+ spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "rspec"
29
+ end
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mcrain
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - akm
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-05-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: logger_pipe
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.3.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.3.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: net-scp
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.2.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.2.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: activesupport
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ - - "<"
49
+ - !ruby/object:Gem::Version
50
+ version: '5.0'
51
+ type: :runtime
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '3.0'
58
+ - - "<"
59
+ - !ruby/object:Gem::Version
60
+ version: '5.0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: bundler
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.9'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.9'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rake
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '10.0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '10.0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: rspec
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ description: mcrain supports to run docker container for test.
104
+ email:
105
+ - t-akima@groovenauts.jp
106
+ executables:
107
+ - mcrain
108
+ extensions: []
109
+ extra_rdoc_files: []
110
+ files:
111
+ - ".gitignore"
112
+ - ".gitmodules"
113
+ - ".rspec"
114
+ - ".travis.yml"
115
+ - CODE_OF_CONDUCT.md
116
+ - Gemfile
117
+ - README.md
118
+ - Rakefile
119
+ - bin/console
120
+ - bin/setup
121
+ - exe/mcrain
122
+ - lib/mcrain.rb
123
+ - lib/mcrain/base.rb
124
+ - lib/mcrain/boot2docker.rb
125
+ - lib/mcrain/rabbitmq.rb
126
+ - lib/mcrain/redis.rb
127
+ - lib/mcrain/riak.rb
128
+ - lib/mcrain/version.rb
129
+ - mcrain.gemspec
130
+ homepage: https://github.com/groovenauts/mcrain
131
+ licenses:
132
+ - MIT
133
+ metadata: {}
134
+ post_install_message:
135
+ rdoc_options: []
136
+ require_paths:
137
+ - lib
138
+ required_ruby_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ required_rubygems_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ requirements: []
149
+ rubyforge_project:
150
+ rubygems_version: 2.4.5
151
+ signing_key:
152
+ specification_version: 4
153
+ summary: mcrain supports to run docker container for test.
154
+ test_files: []