gv-valley 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +24 -0
- data/README.md +38 -0
- data/Rakefile +9 -0
- data/bin/gv-valley +6 -0
- data/bin/valley +319 -0
- data/gv-valley.gemspec +27 -0
- data/lib/gv/addons/etcd.rb +41 -0
- data/lib/gv/addons/memcached.rb +34 -0
- data/lib/gv/addons/postgresql.rb +42 -0
- data/lib/gv/tasks/install.rake +116 -0
- data/lib/gv/valley/addon.rb +62 -0
- data/lib/gv/valley/app.rb +108 -0
- data/lib/gv/valley/balancer.rb +61 -0
- data/lib/gv/valley/deployer.rb +104 -0
- data/lib/gv/valley/etcd.rb +40 -0
- data/lib/gv/valley/file_server.rb +115 -0
- data/lib/gv/valley/runner.rb +138 -0
- data/lib/gv/valley/version.rb +5 -0
- data/lib/gv/valley.rb +10 -0
- data/scripts/haproxy.cfg +47 -0
- data/scripts/receiver +22 -0
- data/test/gv/test_app.rb +64 -0
- data/test/gv/test_etcd.rb +39 -0
- data/test/minitest_helper.rb +7 -0
- metadata +174 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'gv/bedrock/service'
|
2
|
+
require 'gv/bedrock/config'
|
3
|
+
require 'gv/common/docker_helper'
|
4
|
+
require 'gv/common/host_helper'
|
5
|
+
|
6
|
+
module GV
|
7
|
+
module Valley
|
8
|
+
|
9
|
+
##
|
10
|
+
# Addon Service
|
11
|
+
#
|
12
|
+
|
13
|
+
class Addon < GV::Bedrock::Service
|
14
|
+
|
15
|
+
include GV::Common::HostHelper
|
16
|
+
include GV::Common::DockerHelper
|
17
|
+
|
18
|
+
PORT = nil
|
19
|
+
|
20
|
+
attr_reader :image, :params, :cmd
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
super
|
24
|
+
|
25
|
+
pull_image_if_does_not_exists self.image
|
26
|
+
|
27
|
+
@home = GV::Bedrock::Config.service.get("home")
|
28
|
+
@name ||= File.basename(self.image)
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
def create app_name
|
33
|
+
@app_name = app_name
|
34
|
+
addon_name = "#{@name}.#{app_name}"
|
35
|
+
return nil if ps? addon_name
|
36
|
+
pipe "docker run --name #{addon_name} -d -p #{self.external_ip}::#{self.class::PORT} -e PORT=#{self.class::PORT} #{self.params} #{self.image} #{self.cmd}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def destroy app_name
|
40
|
+
@app_name = app_name
|
41
|
+
addon_name = "#{@name}.#{app_name}"
|
42
|
+
batch addon_name, "stop", true
|
43
|
+
batch addon_name, "rm", true
|
44
|
+
end
|
45
|
+
|
46
|
+
def info app_name
|
47
|
+
@app_name = app_name
|
48
|
+
addon_name = "#{@name}.#{app_name}"
|
49
|
+
info(container_id(addon_name))
|
50
|
+
end
|
51
|
+
|
52
|
+
def port app_name
|
53
|
+
@app_name = app_name
|
54
|
+
addon_name = "#{@name}.#{app_name}"
|
55
|
+
container_port addon_name, self.external_ip, self.class::PORT
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'gv/bedrock/config'
|
2
|
+
require 'gv/valley/etcd'
|
3
|
+
require 'gv/valley/file_server'
|
4
|
+
require 'gv/common/docker_helper'
|
5
|
+
require 'json'
|
6
|
+
require 'etcd'
|
7
|
+
|
8
|
+
module GV
|
9
|
+
module Valley
|
10
|
+
|
11
|
+
class App
|
12
|
+
|
13
|
+
PORT = 5000
|
14
|
+
|
15
|
+
class << self
|
16
|
+
|
17
|
+
def etcd_clt
|
18
|
+
@@etcd_clt ||= begin
|
19
|
+
server = GV::Valley::Etcd.service
|
20
|
+
::Etcd.client(config = {
|
21
|
+
host: server.external_ip,
|
22
|
+
port: server.port
|
23
|
+
})
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def all
|
28
|
+
etcd_clt.get("/apps").children.map{ |node| find(File.basename(node.key)) }
|
29
|
+
end
|
30
|
+
|
31
|
+
def find name
|
32
|
+
begin
|
33
|
+
find! name
|
34
|
+
rescue ::Etcd::KeyNotFound
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def find! name
|
40
|
+
value = etcd_clt.get("/apps/#{name}").value
|
41
|
+
new(ensure_defaults(JSON.load(value)))
|
42
|
+
end
|
43
|
+
|
44
|
+
def create name
|
45
|
+
save name, {"name" => name, "config" => default_config(name), "ps" => {}, "domains" => [default_domain(name)]}
|
46
|
+
find name
|
47
|
+
end
|
48
|
+
|
49
|
+
def save name, data
|
50
|
+
etcd_clt.set("/apps/#{name}", { value: JSON.dump(ensure_defaults(data)) })
|
51
|
+
end
|
52
|
+
|
53
|
+
def delete name
|
54
|
+
etcd_clt.delete("/apps/#{name}",{recursive: true}) rescue nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def domain
|
58
|
+
GV::Bedrock::Config.service.get("domain")
|
59
|
+
end
|
60
|
+
|
61
|
+
def default_config name
|
62
|
+
config = {
|
63
|
+
"SLUG_URL" => "#{GV::Valley::FileServer.service.url}/#{name}/slug.tgz",
|
64
|
+
"PORT" => PORT
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
def default_domain name
|
69
|
+
"#{name}.#{self.domain}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def ensure_defaults data
|
73
|
+
data["config"] ||= {}
|
74
|
+
data["config"].update(default_config(data["name"]))
|
75
|
+
|
76
|
+
data["domains"] ||= []
|
77
|
+
data["domains"] << default_domain(data["name"]) unless data["domains"].include? default_domain(data["name"])
|
78
|
+
data
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
def initialize attributes = {}
|
84
|
+
@attributes = attributes
|
85
|
+
@name = @attributes['name']
|
86
|
+
@attributes = attributes
|
87
|
+
end
|
88
|
+
|
89
|
+
def save
|
90
|
+
self.class.save(@name,@attributes)
|
91
|
+
end
|
92
|
+
|
93
|
+
def delete
|
94
|
+
self.class.delete @name
|
95
|
+
end
|
96
|
+
|
97
|
+
def [](key)
|
98
|
+
@attributes[key]
|
99
|
+
end
|
100
|
+
|
101
|
+
def []=(key,value)
|
102
|
+
@attributes[key]=value
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'gv/bedrock/service'
|
2
|
+
require 'gv/valley/app'
|
3
|
+
require 'gv/common/pipe_helper'
|
4
|
+
|
5
|
+
module GV
|
6
|
+
module Valley
|
7
|
+
|
8
|
+
class Balancer < GV::Bedrock::Service
|
9
|
+
|
10
|
+
include GV::Common::PipeHelper
|
11
|
+
INDENT = " "
|
12
|
+
|
13
|
+
##
|
14
|
+
# reloads haproxy config
|
15
|
+
|
16
|
+
def reload &block
|
17
|
+
|
18
|
+
@block = block
|
19
|
+
|
20
|
+
indicate "Loading Haproxy config"
|
21
|
+
|
22
|
+
config = File.read("#{GV::Valley.root}/scripts/haproxy.cfg")
|
23
|
+
target_file = "/etc/haproxy/haproxy.cfg"
|
24
|
+
acl = ""
|
25
|
+
backend = ""
|
26
|
+
|
27
|
+
App.all.each do |app|
|
28
|
+
|
29
|
+
app["domains"].each do |domain|
|
30
|
+
acl << "#{INDENT}use_backend b_#{app["name"]} if { hdr(host) -i #{domain} }\n"
|
31
|
+
end
|
32
|
+
|
33
|
+
backend << "backend b_#{app["name"]}\n"
|
34
|
+
app["ps"]["web"]["containers"].each do |container|
|
35
|
+
host = container['HostConfig']['PortBindings']["#{App::PORT}/tcp"].first
|
36
|
+
backend << "#{INDENT}server srv_#{container['ID'][0..6]} #{host['HostIp']}:#{host['HostPort']}\n"
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
config.gsub!(/^\#FRONT$/,acl)
|
42
|
+
config.gsub!(/^\#BACK$/,backend)
|
43
|
+
|
44
|
+
pipe "rm #{target_file}"
|
45
|
+
File.open(target_file,File::RDWR|File::CREAT){|f| f.puts config }
|
46
|
+
|
47
|
+
pipe "chmod 0770 #{target_file}"
|
48
|
+
pipe "chgrp haproxy #{target_file}"
|
49
|
+
pipe "service haproxy reload", &block
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'gv/bedrock/service'
|
3
|
+
require 'gv/valley/app'
|
4
|
+
require 'gv/valley/runner'
|
5
|
+
require 'gv/common/pipe_helper'
|
6
|
+
|
7
|
+
|
8
|
+
module GV
|
9
|
+
module Valley
|
10
|
+
|
11
|
+
class Deployer < GV::Bedrock::Service
|
12
|
+
|
13
|
+
include GV::Common::PipeHelper
|
14
|
+
|
15
|
+
##
|
16
|
+
# deploys app
|
17
|
+
|
18
|
+
def deploy name, &block
|
19
|
+
|
20
|
+
# find or create app
|
21
|
+
unless app = App.find(name)
|
22
|
+
app = App.create(name)
|
23
|
+
end
|
24
|
+
|
25
|
+
# set block for output helpers
|
26
|
+
@block = block
|
27
|
+
|
28
|
+
indicate "Deploying App"
|
29
|
+
|
30
|
+
# read procfile
|
31
|
+
host = GV::Valley::Runner.random_service
|
32
|
+
procfile = host.run(app["name"], "cat /app/Procfile")
|
33
|
+
procfile_types = YAML.load(procfile).keys
|
34
|
+
|
35
|
+
stop app
|
36
|
+
|
37
|
+
# add new Procfile process types or reset jobs array for existing types
|
38
|
+
procfile_types.each do |type|
|
39
|
+
unless app["ps"].keys.include? type
|
40
|
+
app["ps"][type] = {"scale" => 1, "containers" => []}
|
41
|
+
else
|
42
|
+
app["ps"][type]["containers"] = []
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
app.save
|
47
|
+
|
48
|
+
# remove the old types
|
49
|
+
app["ps"].keys.each do |type|
|
50
|
+
unless procfile_types.include? type
|
51
|
+
app["ps"].delete(type)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
app.save
|
56
|
+
|
57
|
+
start app
|
58
|
+
|
59
|
+
app.save
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# stops all running procfile processes
|
65
|
+
|
66
|
+
def stop app, &block
|
67
|
+
# stop and remove all running procfile processes
|
68
|
+
tuple = [:ps, /#{app['name']}\./, nil, nil ]
|
69
|
+
while (self.class.space.read(tuple,0) rescue nil) do
|
70
|
+
if host = (self.class.space.take(tuple,0)[2] rescue nil)
|
71
|
+
host.remove app["name"]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
##
|
77
|
+
# starts all procfile processes
|
78
|
+
|
79
|
+
def start app, &block
|
80
|
+
# run available process types
|
81
|
+
app["ps"].each do |type,ps|
|
82
|
+
ps["scale"].times do |index|
|
83
|
+
host = GV::Valley::Runner.random_service
|
84
|
+
app["ps"][type]["containers"] << host.start(app["name"], type, index, &block)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def indicate string
|
92
|
+
say %(-----> #{string}), &@block
|
93
|
+
end
|
94
|
+
|
95
|
+
def say string
|
96
|
+
pipe %(echo '\e[1G#{string}'), &@block
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'gv/bedrock/service'
|
2
|
+
require 'gv/bedrock/config'
|
3
|
+
require 'gv/common/docker_helper'
|
4
|
+
require 'gv/common/host_helper'
|
5
|
+
|
6
|
+
module GV
|
7
|
+
module Valley
|
8
|
+
|
9
|
+
##
|
10
|
+
# Etcd Service
|
11
|
+
#
|
12
|
+
|
13
|
+
class Etcd < GV::Bedrock::Service
|
14
|
+
|
15
|
+
include GV::Common::HostHelper
|
16
|
+
include GV::Common::DockerHelper
|
17
|
+
|
18
|
+
PORT = 4001
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
super
|
22
|
+
|
23
|
+
pull_image_if_does_not_exists "flynn/etcd"
|
24
|
+
|
25
|
+
home = GV::Bedrock::Config.service.get("home")
|
26
|
+
|
27
|
+
unless ps? 'etcd'
|
28
|
+
cleanup
|
29
|
+
pipe "docker run --name etcd -d -p #{self.external_ip}::#{PORT} -v #{home}/etcd:/data/db:rw flynn/etcd --name=greenvalley -data-dir=/data/db"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def port
|
34
|
+
container_port 'etcd', self.external_ip, PORT
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'gv/bedrock/service'
|
2
|
+
require 'gv/bedrock/config'
|
3
|
+
require 'gv/common/host_helper'
|
4
|
+
require 'goliath/api'
|
5
|
+
require 'goliath/runner'
|
6
|
+
require 'uri'
|
7
|
+
|
8
|
+
module GV
|
9
|
+
module Valley
|
10
|
+
|
11
|
+
class FileServer < GV::Bedrock::Service
|
12
|
+
|
13
|
+
include GV::Common::HostHelper
|
14
|
+
|
15
|
+
class FileSystem
|
16
|
+
CHUNKSIZE = 65536
|
17
|
+
|
18
|
+
def initialize(path)
|
19
|
+
@path = path
|
20
|
+
end
|
21
|
+
|
22
|
+
def get
|
23
|
+
open(@path, 'rb') do |file|
|
24
|
+
yield file.read(CHUNKSIZE) until file.eof?
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
class Api < Goliath::API
|
31
|
+
|
32
|
+
use Goliath::Rack::DefaultMimeType
|
33
|
+
use Goliath::Rack::Render, 'json'
|
34
|
+
use Goliath::Rack::Heartbeat
|
35
|
+
|
36
|
+
use Goliath::Rack::Validation::RequestMethod, %w(GET PUT DELETE)
|
37
|
+
|
38
|
+
def on_headers(env, headers)
|
39
|
+
env['async-headers'] = headers
|
40
|
+
end
|
41
|
+
|
42
|
+
def on_body(env, data)
|
43
|
+
(env['async-body'] ||= '') << data
|
44
|
+
end
|
45
|
+
|
46
|
+
def response(env)
|
47
|
+
|
48
|
+
path = "#{ENV['GV_HOME']}/#{env['REQUEST_PATH']}"
|
49
|
+
|
50
|
+
case env['REQUEST_METHOD']
|
51
|
+
|
52
|
+
when 'GET'
|
53
|
+
|
54
|
+
headers = {'X-filename' => path}
|
55
|
+
|
56
|
+
raise Goliath::Validation::NotFoundError unless File.file?(path)
|
57
|
+
|
58
|
+
operation = proc do
|
59
|
+
FileSystem.new(path).get { |chunk| env.chunked_stream_send(chunk) }
|
60
|
+
end
|
61
|
+
|
62
|
+
callback = proc do |result|
|
63
|
+
env.chunked_stream_close
|
64
|
+
end
|
65
|
+
|
66
|
+
EM.defer operation, callback
|
67
|
+
|
68
|
+
headers.merge!( 'X-Stream' => 'Goliath')
|
69
|
+
chunked_streaming_response(200, headers)
|
70
|
+
|
71
|
+
when 'PUT'
|
72
|
+
|
73
|
+
File.delete(path) rescue nil
|
74
|
+
result = File.open(path, File::RDWR|File::CREAT){ |f| f.puts env['async-body'] }
|
75
|
+
[ 200, {}, {body: "OK"} ]
|
76
|
+
|
77
|
+
when 'DELETE'
|
78
|
+
result = File.delete(path)
|
79
|
+
[ 200, {}, {body: result } ]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
def url
|
86
|
+
"http://#{self.external_ip}:#{self.port}"
|
87
|
+
end
|
88
|
+
|
89
|
+
def port
|
90
|
+
ENV['PORT'] ||= '9000'
|
91
|
+
end
|
92
|
+
|
93
|
+
def initialize
|
94
|
+
super
|
95
|
+
ENV['GV_HOME'] ||= GV::Bedrock::Config.service.get("home")
|
96
|
+
runner = Goliath::Runner.new(ARGV, nil)
|
97
|
+
runner.api = Api.new
|
98
|
+
runner.app = Goliath::Rack::Builder.build(Api, runner.api)
|
99
|
+
runner.port = self.port
|
100
|
+
runner.log_file = "/var/log/gv-file_server.log"
|
101
|
+
runner.pid_file = "/var/run/gv-file_server.pid"
|
102
|
+
runner.daemonize = true
|
103
|
+
runner.run
|
104
|
+
at_exit {
|
105
|
+
pid = File.read("/var/run/gv-file_server.pid").chomp.to_i
|
106
|
+
Process.kill("TERM",pid)
|
107
|
+
File.delete("/var/run/gv-file_server.pid")
|
108
|
+
File.delete("/var/log/gv-file_server.log")
|
109
|
+
File.delete("/var/log/gv-file_server.log_stdout.log")
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'gv/bedrock/service'
|
2
|
+
require 'gv/common/host_helper'
|
3
|
+
require 'gv/common/docker_helper'
|
4
|
+
require 'gv/valley/app'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
module GV
|
8
|
+
module Valley
|
9
|
+
|
10
|
+
class Runner < GV::Bedrock::Service
|
11
|
+
|
12
|
+
include GV::Common::HostHelper
|
13
|
+
include GV::Common::DockerHelper
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
super
|
17
|
+
pull_image_if_does_not_exists "flynn/slugrunner"
|
18
|
+
register_all
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
##
|
23
|
+
# runs one-off job
|
24
|
+
|
25
|
+
def run name, cmd, &block
|
26
|
+
app = App.find!(name)
|
27
|
+
|
28
|
+
cleanup
|
29
|
+
|
30
|
+
params = %(--rm -a stdout -a stderr ) #note that space at the end!
|
31
|
+
params << %(-i -a stdin) if cmd =~ Sticks::Pipe::INTERACTIVE_COMMANDS
|
32
|
+
cmd = %(docker run --name=#{app[:name]}.run.#{genuuid()} #{params} #{getenv(app)} flynn/slugrunner #{cmd})
|
33
|
+
|
34
|
+
debug "Runner#run name:#{name}, cmd:#{cmd}"
|
35
|
+
|
36
|
+
result = pipe cmd, &block
|
37
|
+
|
38
|
+
sleep 2
|
39
|
+
|
40
|
+
cleanup
|
41
|
+
result
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
##
|
46
|
+
# force removes all matching jobs
|
47
|
+
|
48
|
+
def remove name, type = nil, &block
|
49
|
+
debug "Runner#remove name:#{name}, type:#{type}"
|
50
|
+
|
51
|
+
batch "#{name}.#{type}", "kill", true
|
52
|
+
batch "#{name}.#{type}", "rm", true
|
53
|
+
unregister_all(/#{name}\.#{type}\./)
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
##
|
58
|
+
# starts process
|
59
|
+
|
60
|
+
def start name, type, index, &block
|
61
|
+
raise "AppNotFound" unless app = App.find(name)
|
62
|
+
|
63
|
+
info "Starting #{name}.#{type}.#{index}"
|
64
|
+
|
65
|
+
cleanup
|
66
|
+
|
67
|
+
params = %(-d -p #{self.external_ip}::#{App::PORT})
|
68
|
+
cmd = %(docker run --name=#{name}.#{type}.#{index} #{params} #{getenv(app)} flynn/slugrunner start #{type})
|
69
|
+
|
70
|
+
debug "Runner#start name:#{name}, type:#{type} index:#{index}"
|
71
|
+
|
72
|
+
container_id = pipe(cmd)
|
73
|
+
|
74
|
+
if container_id =~ /^[a-zA-Z0-9]{64}$/
|
75
|
+
|
76
|
+
register "#{name}.#{type}.#{index}"
|
77
|
+
info(container_id)
|
78
|
+
|
79
|
+
elsif container_id.include? "Error: Conflict"
|
80
|
+
error "Container name conflict: #{name}.#{type}.#{index}, docker service reloading..."
|
81
|
+
|
82
|
+
restart_docker!
|
83
|
+
|
84
|
+
remove name, type
|
85
|
+
start name, type, index, &block
|
86
|
+
else
|
87
|
+
raise container_id
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
##
|
94
|
+
# retrives logs
|
95
|
+
|
96
|
+
def logs name, follow = false, &block
|
97
|
+
debug "Runner#logs name:#{name}, follow:#{follow}"
|
98
|
+
|
99
|
+
pipe "docker logs #{follow ? "-f" : nil} #{container_id(name)}", &block
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def getenv app
|
106
|
+
app['config'].map{ |k,v| "-e #{k}=#{v}" }.join(" ")
|
107
|
+
end
|
108
|
+
|
109
|
+
def genuuid
|
110
|
+
rand(2**64).to_s(36) # from heroku/slugcompiler
|
111
|
+
end
|
112
|
+
|
113
|
+
def register_all
|
114
|
+
pipe("docker ps | grep runner/init").chomp.split("\n").each{|l|
|
115
|
+
cols = l.split(/\s{3,}/)
|
116
|
+
name = cols.last
|
117
|
+
unregister_all(/#{name}/)
|
118
|
+
register name
|
119
|
+
}
|
120
|
+
end
|
121
|
+
|
122
|
+
def unregister_all name
|
123
|
+
unregister name while (self.class.space.read([:ps, name, nil, self.external_ip],0) rescue nil)
|
124
|
+
end
|
125
|
+
|
126
|
+
def register name
|
127
|
+
self.class.space.write [:ps, name, self, self.external_ip ]
|
128
|
+
end
|
129
|
+
|
130
|
+
def unregister name
|
131
|
+
self.class.space.take([:ps, name, nil, self.external_ip],0) rescue nil
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
end
|
data/lib/gv/valley.rb
ADDED
data/scripts/haproxy.cfg
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
global
|
2
|
+
log /dev/log local0
|
3
|
+
log /dev/log local1 notice
|
4
|
+
chroot /var/lib/haproxy
|
5
|
+
user haproxy
|
6
|
+
group haproxy
|
7
|
+
daemon
|
8
|
+
|
9
|
+
defaults
|
10
|
+
log global
|
11
|
+
mode http
|
12
|
+
|
13
|
+
contimeout 5000
|
14
|
+
clitimeout 50000
|
15
|
+
srvtimeout 50000
|
16
|
+
|
17
|
+
option httplog
|
18
|
+
option dontlognull
|
19
|
+
option redispatch
|
20
|
+
option abortonclose
|
21
|
+
option httpclose
|
22
|
+
option forwardfor
|
23
|
+
|
24
|
+
stats enable
|
25
|
+
stats auth admin:password
|
26
|
+
stats uri /monitor
|
27
|
+
stats refresh 5s
|
28
|
+
retries 5
|
29
|
+
|
30
|
+
balance roundrobin
|
31
|
+
|
32
|
+
errorfile 400 /etc/haproxy/errors/400.http
|
33
|
+
errorfile 403 /etc/haproxy/errors/403.http
|
34
|
+
errorfile 408 /etc/haproxy/errors/408.http
|
35
|
+
errorfile 500 /etc/haproxy/errors/500.http
|
36
|
+
errorfile 502 /etc/haproxy/errors/502.http
|
37
|
+
errorfile 503 /etc/haproxy/errors/503.http
|
38
|
+
errorfile 504 /etc/haproxy/errors/504.http
|
39
|
+
|
40
|
+
|
41
|
+
frontend http
|
42
|
+
bind *:80
|
43
|
+
monitor-uri /haproxy
|
44
|
+
|
45
|
+
#FRONT
|
46
|
+
|
47
|
+
#BACK
|