naminori 0.1.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fc8b2a9badbab70707427fa9729edd14998a5079
4
+ data.tar.gz: d2f6668fd2bb6b4490963bc5b1e9aa785a2d8585
5
+ SHA512:
6
+ metadata.gz: dfbda96472f946e34904dcdf2579826fbdd594d87e8029116f3ef032e4384f574ac707b67d3d19c574dcfe6192da113971ded3682b69fb9b00477f6a5112030d
7
+ data.tar.gz: 237e0c47068e0b86d9d9017ad9cd6366196d60777148f95e200e92ea14a010ec43b5132c7586d8a4e795cb53a82af6e55f0c97461d01cafe7f55c1e9db5e0043
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 2.1.6
5
+ - 2.2.2
6
+ addons:
7
+ code_climate:
8
+ repo_token: 47135cdaac4078905036e9ec2506567cd244bd711794ed292b8f36fee6fa1f22
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in naminori.gemspec
4
+ gemspec
5
+ gem "codeclimate-test-reporter", group: :test, require: nil
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 kazuhiko yamahsita
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,91 @@
1
+ # Naminori
2
+ [![Build Status](https://travis-ci.org/pyama86/Naminori.svg)](https://travis-ci.org/pyama86/Naminori)
3
+ [![Code Climate](https://codeclimate.com/github/pyama86/Naminori/badges/gpa.svg)](https://codeclimate.com/github/pyama86/Naminori)
4
+ [![Test Coverage](https://codeclimate.com/github/pyama86/Naminori/badges/coverage.svg)](https://codeclimate.com/github/pyama86/Naminori/coverage)
5
+
6
+ Library to manage the load balancer using the Serf
7
+
8
+ ## Installation
9
+
10
+ ```ruby
11
+ gem 'naminori'
12
+ ```
13
+
14
+ Or install it yourself as:
15
+
16
+ $ gem install naminori
17
+
18
+ ## Usage
19
+
20
+ ### exemple
21
+
22
+ #### envent_example.rb
23
+ ```ruby
24
+ #! /usr/bin/env ruby
25
+ require 'rubygems'
26
+ require 'naminori'
27
+
28
+ notifier_options = {
29
+ webhook_url: "https://hooks.slack.com/services/XXXXXX",
30
+ channel: "#pyama"
31
+ }
32
+
33
+ service_options = {
34
+ vip:"192.168.77.9",
35
+ role: "dns",
36
+ notifier: Naminori::Notifier.get_notifier("slack" ,notifier_options)
37
+ }
38
+
39
+ case
40
+ when Naminori::Serf.role?("dns")
41
+ Naminori::Service.event("dns", "lvs", service_options)
42
+ when Naminori::Serf.role?("lb")
43
+ Naminori::Lb.health_check("dns", "lvs",service_options)
44
+ end
45
+
46
+ ```
47
+
48
+ #### health_check_example.rb
49
+ ```ruby
50
+ #! /usr/bin/env ruby
51
+ require 'rubygems'
52
+ require 'naminori'
53
+
54
+ service_options = { vip:"192.168.77.9", role: "dns" }
55
+
56
+ Naminori::Lb.health_check("dns", "lvs", service_options)
57
+ ```
58
+ ```zsh
59
+ # crontab -l
60
+ # Chef Name: health_check
61
+ PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
62
+ * * * * * for i in `seq 0 10 59`;do (sleep ${i}; /opt/serf/event_handlers/health_check_example.rb)& done;
63
+ ```
64
+
65
+
66
+
67
+
68
+ #### Service Event
69
+ ```
70
+ Naminori::Service.event(service_name, lb_name, options)
71
+ ```
72
+ * service_name:
73
+ dns or http
74
+ * lb_name:
75
+ lvs
76
+ * options(dns_default)
77
+ ```
78
+ {
79
+ role: "dns", # role name
80
+ port: "53", # service port
81
+ protocol: ["udp", "tcp"], # protocol(array)
82
+ vip: "192.168.77.9", # service vip
83
+ method: "gateway", # lvs_method gateway/ip/nat
84
+ query: "pepabo.com", # health_check_query
85
+ retry: 3, # health_check_retry_count
86
+ timeout: 3, # health_check_time_out
87
+ notifier: nil # notifier
88
+ }
89
+ ```
90
+ ## Author
91
+ * pyama
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ ENV['CODECLIMATE_REPO_TOKEN'] = "47135cdaac4078905036e9ec2506567cd244bd711794ed292b8f36fee6fa1f22"
4
+ ENV['PEC_TEST'] = "test"
5
+ RSpec::Core::RakeTask.new("spec")
6
+ task :default => :spec
@@ -0,0 +1,20 @@
1
+ require "naminori/version"
2
+ require 'naminori/serf'
3
+ require 'naminori/lb'
4
+ require 'naminori/lb/base'
5
+ require 'naminori/lb/lvs'
6
+ require 'naminori/service'
7
+ require 'naminori/service/base'
8
+ require 'naminori/service/configure'
9
+ require 'naminori/service/dns'
10
+ require 'naminori/notifier'
11
+ require 'naminori/notifier/base'
12
+ require 'naminori/notifier/configure'
13
+ require 'naminori/notifier/slack'
14
+ require 'resolv'
15
+ require 'slack-notifier'
16
+
17
+
18
+ module Naminori
19
+ # Your code goes here...
20
+ end
@@ -0,0 +1,31 @@
1
+ #! /usr/bin/env ruby
2
+ module Naminori
3
+ class Lb
4
+ class << self
5
+ def health_check(service_name, lb_name, options={})
6
+ service = Naminori::Service.get_service(service_name).new(options)
7
+ members = Naminori::Serf.get_alive_member_by_role(service.config.role)
8
+
9
+ members.each do |member|
10
+ ip = member_ip(member)
11
+ if service.healty?(ip)
12
+ get_lb(lb_name).add_member(ip, service)
13
+ elsif service.config.retry.times.all? { sleep 1; !service.healty?(ip) }
14
+ get_lb(lb_name).delete_member(ip, service)
15
+ end
16
+ end if members
17
+ end
18
+
19
+ def get_lb(lb_name)
20
+ case lb_name
21
+ when "lvs"
22
+ Naminori::Lb::Lvs
23
+ end
24
+ end
25
+
26
+ def member_ip(member)
27
+ member[:ip]
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,15 @@
1
+ #! /usr/bin/env ruby
2
+ module Naminori
3
+ class Lb
4
+ class Base
5
+ class << self
6
+ def add_member(rip, service)
7
+ raise "Called abstract method: add_member"
8
+ end
9
+ def delete_member(rip, service)
10
+ raise "Called abstract method: add_member"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,79 @@
1
+ #! /usr/bin/env ruby
2
+ module Naminori
3
+ class Lb
4
+ class Lvs < Naminori::Lb::Base
5
+ class << self
6
+ def add_member(rip, service)
7
+ transaction("add", lvs_option(rip, service)) if service.healty?(rip)
8
+ end
9
+
10
+ def delete_member(rip, service)
11
+ transaction("delete", lvs_option(rip, service))
12
+ end
13
+
14
+ def transaction(type, ops)
15
+ ops[:protocols].collect do |protocol|
16
+ merge_option = ops.merge({ protocol: protocol })
17
+ if self.send("#{type}?", merge_option) && system("ipvsadm #{command_option(type, merge_option)}")
18
+ notifier(type, merge_option)
19
+ true
20
+ end
21
+ end.all? {|res| res }
22
+ end
23
+
24
+ def add?(ops)
25
+ vip_exists?(ops) && !delete?(ops)
26
+ end
27
+
28
+ def delete?(ops)
29
+ fetch_service(ops).each do |line|
30
+ return true if line.match(/#{ops[:rip]}:/)
31
+ end
32
+ false
33
+ end
34
+
35
+ def vip_exists?(ops)
36
+ vips = fetch_service(ops)
37
+ vips.each do |line|
38
+ return true if line.match(/#{ops[:vip]}:/)
39
+ end if vips
40
+ false
41
+ end
42
+
43
+ def fetch_service(ops)
44
+ `ipvsadm -Ln --#{ops[:protocol]}-service #{ops[:vip]}:#{ops[:port]}`.split("\n")
45
+ end
46
+
47
+ def lvs_option(rip, service)
48
+ { service: service, vip: service.config.vip, rip: rip, protocols: service.config.protocol, port: service.config.port, method: service.config.method }
49
+ end
50
+
51
+ def command_option(type, ops)
52
+ case
53
+ when type == "add"
54
+ "--#{type}-server --#{ops[:protocol]}-service #{ops[:vip]}:#{ops[:port]} -r #{ops[:rip]}:#{ops[:port]} #{method_option(ops[:method])}"
55
+ when type == "delete"
56
+ "--#{type}-server --#{ops[:protocol]}-service #{ops[:vip]}:#{ops[:port]} -r #{ops[:rip]}:#{ops[:port]}"
57
+ end
58
+ end
59
+
60
+ def method_option(method)
61
+ case
62
+ when method == "gateway"
63
+ "-g"
64
+ when method == "nat"
65
+ "-m"
66
+ when method == "ip"
67
+ "-i"
68
+ end
69
+ end
70
+
71
+ def notifier(type, options)
72
+ message = "#{type} member ip:#{options[:rip]} protocol:#{options[:protocol]} in vip:#{options[:vip]}"
73
+ puts message
74
+ options[:service].config.notifier.send(type, message) if options[:service].config.notifier
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,11 @@
1
+ #! /usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/serf'
3
+ require File.dirname(__FILE__) + '/lb'
4
+ require File.dirname(__FILE__) + '/lb/base'
5
+ require File.dirname(__FILE__) + '/lb/lvs'
6
+ require File.dirname(__FILE__) + '/service'
7
+ require File.dirname(__FILE__) + '/service/base'
8
+ require File.dirname(__FILE__) + '/service/configure'
9
+ require File.dirname(__FILE__) + '/service/dns'
10
+ require 'resolv'
11
+
@@ -0,0 +1,13 @@
1
+ #! /usr/bin/env ruby
2
+ module Naminori
3
+ class Notifier
4
+ class << self
5
+ def get_notifier(notifier, options={})
6
+ case notifier
7
+ when "slack"
8
+ Naminori::Notifier::Slack.new(options)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,22 @@
1
+ #! /usr/bin/env ruby
2
+ module Naminori
3
+ class Notifier
4
+ class Base
5
+ attr_reader :config
6
+ def initialize(options={})
7
+ @config = Naminori::Notifier::Configure.new(
8
+ default_config.merge(options)
9
+ )
10
+ end
11
+
12
+ def send(type, message)
13
+ raise "Called abstract method: add_server"
14
+ end
15
+
16
+ def default_config
17
+ raise "Called abstract method: default_config"
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ #! /usr/bin/env ruby
2
+ module Naminori
3
+ class Notifier
4
+ class Configure
5
+ attr_reader :webhook_url, :channel, :user
6
+ def initialize(options)
7
+ @webhook_url = options[:webhook_url]
8
+ @channel = options[:channel]
9
+ @user = options[:user]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,22 @@
1
+ #! /usr/bin/env ruby
2
+ module Naminori
3
+ class Notifier
4
+ class Slack < Base
5
+ def send(type, message)
6
+ icon type == "add" ? ":white_check_mark:" : ":no_entry_sign:"
7
+ notifier = ::Slack::Notifier.new(config.webhook_url, { channel: config.channel, username: config.user})
8
+ notifier.ping icon + message, icon_emoji: ":sparkle:"
9
+ rescue => e
10
+ p e
11
+ end
12
+
13
+ def default_config
14
+ {
15
+ webhook_url: "",
16
+ channel: "general",
17
+ user: "naminori-notifier"
18
+ }
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,54 @@
1
+ #! /usr/bin/env ruby
2
+ module Naminori
3
+ class Serf
4
+ @@event = nil
5
+ class << self
6
+ def gets
7
+ @@event ||= STDIN.gets.chomp.match(/(?<node>.+?)\t(?<ip>.+?)\t(?<role>.+?)\t/)
8
+ end
9
+
10
+ def event_message
11
+ puts "event:#{ENV['SERF_EVENT']} value:#{get}"
12
+ end
13
+
14
+ def join?
15
+ ENV['SERF_EVENT'] == 'member-join'
16
+ end
17
+
18
+ def leave?
19
+ ENV['SERF_EVENT'] == 'member-leave'
20
+ end
21
+
22
+ def failed?
23
+ ENV['SERF_EVENT'] == 'member-failed'
24
+ end
25
+
26
+ def role?(role)
27
+ gets[:role] == role
28
+ end
29
+
30
+ def get_alive_member_by_role(role)
31
+ members.map do |line|
32
+ member = parse_member(line)
33
+ target_role?(member, role) && alive?(member) ? member : nil
34
+ end.compact if members
35
+ end
36
+
37
+ def target_role?(member, role)
38
+ member[:role] == role
39
+ end
40
+
41
+ def alive?(member)
42
+ member[:status] == "alive"
43
+ end
44
+
45
+ def members
46
+ `serf members`.split("\n")
47
+ end
48
+
49
+ def parse_member(member)
50
+ member.match(/(?<node>.+?)\s+(?<ip>.+?):[0-9]+\s+(?<status>\w+)+\s+role=(?<role>\w+)/)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,17 @@
1
+ #! /usr/bin/env ruby
2
+ module Naminori
3
+ class Service
4
+ class << self
5
+ def event(service_name, lb_name, options={})
6
+ get_service(service_name).event(lb_name, options)
7
+ end
8
+
9
+ def get_service(service_name)
10
+ case service_name
11
+ when "dns"
12
+ Naminori::Service::Dns
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,36 @@
1
+ #! /usr/bin/env ruby
2
+ module Naminori
3
+ class Service
4
+ class Base
5
+ attr_reader :config
6
+ class << self
7
+ def event(lb_name, options)
8
+ case
9
+ when Naminori::Serf.join?
10
+ Naminori::Lb.get_lb(lb_name).add_member(event_ip, self.new(options))
11
+ when Naminori::Serf.leave? || Naminori::Serf.failed?
12
+ Naminori::Lb.get_lb(lb_name).delete_member(event_ip, self.new(options))
13
+ end
14
+ end
15
+
16
+ def event_ip
17
+ Naminori::Serf.gets[:ip]
18
+ end
19
+ end
20
+
21
+ def initialize(options={})
22
+ @config = Naminori::Service::Configure.new(
23
+ default_config.merge(options)
24
+ )
25
+ end
26
+
27
+ def healty?(ip)
28
+ raise "Called abstract method: healty?"
29
+ end
30
+
31
+ def default_config
32
+ raise "Called abstract method: default_config"
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+ #! /usr/bin/env ruby
2
+ module Naminori
3
+ class Service
4
+ class Configure
5
+ attr_reader :role, :port, :protocol, :vip, :method, :query, :retry, :timeout, :notifier
6
+ def initialize(options)
7
+ @role = options[:role]
8
+ @port = options[:port]
9
+ @protocol = options[:protocol]
10
+ @vip = options[:vip]
11
+ @method = options[:method]
12
+ @query = options[:query]
13
+ @retry = options[:retry]
14
+ @timeout = options[:timeout]
15
+ @notifier = options[:notifier]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,31 @@
1
+ #! /usr/bin/env ruby
2
+ module Naminori
3
+ class Service
4
+ class Dns < Naminori::Service::Base
5
+
6
+ def healty?(ip)
7
+ dns = Resolv::DNS.new(:nameserver => ip )
8
+ dns.timeouts = config.timeout
9
+ begin
10
+ dns.getaddress(@config.query)
11
+ rescue => e
12
+ false
13
+ end
14
+ end
15
+
16
+ def default_config
17
+ {
18
+ role: "dns",
19
+ port: "53",
20
+ protocol: ["udp", "tcp"],
21
+ vip: "192.168.77.9",
22
+ method: "nat",
23
+ query: "pepabo.com",
24
+ retry: 3,
25
+ timeout: 3,
26
+ notifier: nil
27
+ }
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ module Naminori
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'naminori/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "naminori"
8
+ spec.version = Naminori::VERSION
9
+ spec.authors = ["kazuhiko yamahsita"]
10
+ spec.email = ["pyama@pepabo.com"]
11
+
12
+ spec.summary = %q{LoadBarancer library on Serf.}
13
+ spec.description = %q{Loadbarancer library on Serf.}
14
+ spec.homepage = "http://ten-snapon.com"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_dependency 'slack-notifier', "~> 1.2"
21
+ spec.add_development_dependency "bundler", "~> 1.9"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rspec", "~> 3.2"
24
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: naminori
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - kazuhiko yamahsita
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-06-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: slack-notifier
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.9'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.9'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.2'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.2'
69
+ description: Loadbarancer library on Serf.
70
+ email:
71
+ - pyama@pepabo.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".travis.yml"
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - lib/naminori.rb
83
+ - lib/naminori/lb.rb
84
+ - lib/naminori/lb/base.rb
85
+ - lib/naminori/lb/lvs.rb
86
+ - lib/naminori/naminori.rb
87
+ - lib/naminori/notifier.rb
88
+ - lib/naminori/notifier/base.rb
89
+ - lib/naminori/notifier/configure.rb
90
+ - lib/naminori/notifier/slack.rb
91
+ - lib/naminori/serf.rb
92
+ - lib/naminori/service.rb
93
+ - lib/naminori/service/base.rb
94
+ - lib/naminori/service/configure.rb
95
+ - lib/naminori/service/dns.rb
96
+ - lib/naminori/version.rb
97
+ - naminori.gemspec
98
+ homepage: http://ten-snapon.com
99
+ licenses:
100
+ - MIT
101
+ metadata: {}
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ requirements: []
117
+ rubyforge_project:
118
+ rubygems_version: 2.4.6
119
+ signing_key:
120
+ specification_version: 4
121
+ summary: LoadBarancer library on Serf.
122
+ test_files: []