vcap_services_base 0.2.10
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 +7 -0
- data/lib/base/abstract.rb +11 -0
- data/lib/base/api/message.rb +31 -0
- data/lib/base/asynchronous_service_gateway.rb +529 -0
- data/lib/base/backup.rb +206 -0
- data/lib/base/barrier.rb +54 -0
- data/lib/base/base.rb +159 -0
- data/lib/base/base_async_gateway.rb +164 -0
- data/lib/base/base_job.rb +5 -0
- data/lib/base/catalog_manager_base.rb +67 -0
- data/lib/base/catalog_manager_v1.rb +225 -0
- data/lib/base/catalog_manager_v2.rb +291 -0
- data/lib/base/cloud_controller_services.rb +75 -0
- data/lib/base/datamapper_l.rb +148 -0
- data/lib/base/gateway.rb +167 -0
- data/lib/base/gateway_service_catalog.rb +68 -0
- data/lib/base/http_handler.rb +101 -0
- data/lib/base/job/async_job.rb +71 -0
- data/lib/base/job/config.rb +27 -0
- data/lib/base/job/lock.rb +153 -0
- data/lib/base/job/package.rb +112 -0
- data/lib/base/job/serialization.rb +365 -0
- data/lib/base/job/snapshot.rb +354 -0
- data/lib/base/node.rb +471 -0
- data/lib/base/node_bin.rb +154 -0
- data/lib/base/plan.rb +63 -0
- data/lib/base/provisioner.rb +1120 -0
- data/lib/base/provisioner_v1.rb +125 -0
- data/lib/base/provisioner_v2.rb +193 -0
- data/lib/base/service.rb +93 -0
- data/lib/base/service_advertiser.rb +184 -0
- data/lib/base/service_error.rb +122 -0
- data/lib/base/service_message.rb +94 -0
- data/lib/base/service_plan_change_set.rb +11 -0
- data/lib/base/simple_aop.rb +63 -0
- data/lib/base/snapshot_v2/snapshot.rb +227 -0
- data/lib/base/snapshot_v2/snapshot_client.rb +158 -0
- data/lib/base/snapshot_v2/snapshot_job.rb +95 -0
- data/lib/base/utils.rb +63 -0
- data/lib/base/version.rb +7 -0
- data/lib/base/warden/instance_utils.rb +161 -0
- data/lib/base/warden/node_utils.rb +205 -0
- data/lib/base/warden/service.rb +426 -0
- data/lib/base/worker_bin.rb +76 -0
- data/lib/vcap_services_base.rb +16 -0
- metadata +364 -0
data/lib/base/backup.rb
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'optparse'
|
4
|
+
require 'timeout'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'yaml'
|
7
|
+
require 'pathname'
|
8
|
+
require 'steno'
|
9
|
+
|
10
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
|
11
|
+
require 'vcap/common'
|
12
|
+
|
13
|
+
$:.unshift File.dirname(__FILE__)
|
14
|
+
require 'abstract'
|
15
|
+
|
16
|
+
module VCAP
|
17
|
+
module Services
|
18
|
+
module Base
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
#@config_file Full path to config file
|
24
|
+
#@config Config hash for config file
|
25
|
+
#@logger
|
26
|
+
#@nfs_base NFS base path
|
27
|
+
class VCAP::Services::Base::Backup
|
28
|
+
abstract :default_config_file
|
29
|
+
abstract :backup_db
|
30
|
+
|
31
|
+
def initialize
|
32
|
+
@run_lock = Mutex.new
|
33
|
+
@shutdown = false
|
34
|
+
trap("TERM") { exit_fun }
|
35
|
+
trap("INT") { exit_fun }
|
36
|
+
end
|
37
|
+
|
38
|
+
def script_file
|
39
|
+
$0
|
40
|
+
end
|
41
|
+
|
42
|
+
def exit_fun
|
43
|
+
@shutdown = true
|
44
|
+
Thread.new do
|
45
|
+
@run_lock.synchronize { exit }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def single_app(&blk)
|
50
|
+
if File.open(script_file).flock(File::LOCK_EX|File::LOCK_NB)
|
51
|
+
blk.call
|
52
|
+
else
|
53
|
+
echo "Script #{ script_file } is already running",true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def start
|
58
|
+
single_app do
|
59
|
+
echo "#{File.basename(script_file)} starts"
|
60
|
+
@config_file = default_config_file
|
61
|
+
parse_options
|
62
|
+
|
63
|
+
echo "Load config file"
|
64
|
+
# load conf file
|
65
|
+
begin
|
66
|
+
@config = YAML.load(File.open(@config_file))
|
67
|
+
rescue => e
|
68
|
+
echo "Could not read configuration file: #{e}",true
|
69
|
+
exit
|
70
|
+
end
|
71
|
+
|
72
|
+
# Setup logger
|
73
|
+
echo @config["logging"]
|
74
|
+
logging_config = Steno::Config.from_hash(@config["logging"])
|
75
|
+
Steno.init(logging_config)
|
76
|
+
# Use running binary name for logger identity name.
|
77
|
+
@logger = Steno.logger(File.basename(script_file))
|
78
|
+
|
79
|
+
# Make pidfile
|
80
|
+
if @config["pid"]
|
81
|
+
pf = VCAP::PidFile.new(@config["pid"])
|
82
|
+
pf.unlink_at_exit
|
83
|
+
end
|
84
|
+
|
85
|
+
echo "Check mount points"
|
86
|
+
check_mount_points
|
87
|
+
|
88
|
+
# make sure backup dir on nfs storage exists
|
89
|
+
@nfs_base = @config["backup_base_dir"] + "/backups/" + @config["service_name"]
|
90
|
+
echo "Check NFS base"
|
91
|
+
if File.directory? @nfs_base
|
92
|
+
echo @nfs_base + " exists"
|
93
|
+
else
|
94
|
+
echo @nfs_base + " does not exist, create it"
|
95
|
+
begin
|
96
|
+
FileUtils.mkdir_p @nfs_base
|
97
|
+
rescue => e
|
98
|
+
echo "Could not create dir on nfs!",true
|
99
|
+
exit
|
100
|
+
end
|
101
|
+
end
|
102
|
+
echo "Run backup task"
|
103
|
+
@run_lock.synchronize { backup_db }
|
104
|
+
echo "#{File.basename(script_file)} task is completed"
|
105
|
+
end
|
106
|
+
rescue => e
|
107
|
+
echo "Error: #{e.message}\n #{e.backtrace}",true
|
108
|
+
rescue Interrupt => it
|
109
|
+
echo "Backup is interrupted!"
|
110
|
+
end
|
111
|
+
|
112
|
+
def get_dump_path(name, options={})
|
113
|
+
name = name.sub(/^(mongodb|redis)-/,'')
|
114
|
+
mode = options[:mode] || 0
|
115
|
+
time = options[:time] || Time.now
|
116
|
+
case mode
|
117
|
+
when 1
|
118
|
+
File.join(@config['backup_base_dir'], 'backups', @config['service_name'],name, time.to_i.to_s,@config['node_id'])
|
119
|
+
else
|
120
|
+
File.join(@config['backup_base_dir'], 'backups', @config['service_name'], name[0,2], name[2,2], name[4,2], name, time.to_i.to_s)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def check_mount_points
|
125
|
+
# make sure the backup base dir is mounted
|
126
|
+
pn = Pathname.new(@config["backup_base_dir"])
|
127
|
+
if !@tolerant && !pn.mountpoint?
|
128
|
+
echo @config["backup_base_dir"] + " is not mounted, exit",true
|
129
|
+
exit
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def echo(output, err=false)
|
134
|
+
if err
|
135
|
+
$stderr.puts(output) unless @logger
|
136
|
+
@logger.error(output) if @logger
|
137
|
+
else
|
138
|
+
$stdout.puts(output) unless @logger
|
139
|
+
@logger.info(output) if @logger
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def parse_options
|
144
|
+
OptionParser.new do |opts|
|
145
|
+
opts.banner = "Usage: #{File.basename(script_file)} [options]"
|
146
|
+
opts.on("-c", "--config [ARG]", "Node configuration File") do |opt|
|
147
|
+
@config_file = opt
|
148
|
+
end
|
149
|
+
opts.on("-h", "--help", "Help") do
|
150
|
+
puts opts
|
151
|
+
exit
|
152
|
+
end
|
153
|
+
opts.on("-t", "--tolerant", "Tolerant mode") do
|
154
|
+
@tolerant = true
|
155
|
+
end
|
156
|
+
more_options(opts)
|
157
|
+
end.parse!
|
158
|
+
end
|
159
|
+
|
160
|
+
def more_options(opts)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
class CMDHandle
|
165
|
+
|
166
|
+
def initialize(cmd, timeout=nil, &blk)
|
167
|
+
@cmd = cmd
|
168
|
+
@timeout = timeout
|
169
|
+
@errback = blk
|
170
|
+
end
|
171
|
+
|
172
|
+
def run
|
173
|
+
pid = fork
|
174
|
+
if pid
|
175
|
+
# parent process
|
176
|
+
success = false
|
177
|
+
begin
|
178
|
+
success = Timeout::timeout(@timeout) do
|
179
|
+
Process.waitpid(pid)
|
180
|
+
value = $?.exitstatus
|
181
|
+
@errback.call(@cmd, value, "No message.") if value != 0 && @errback
|
182
|
+
return value == 0
|
183
|
+
end
|
184
|
+
rescue Timeout::Error
|
185
|
+
Process.detach(pid)
|
186
|
+
Process.kill("KILL", pid)
|
187
|
+
@errback.call(@cmd, -1, "Killed due to timeout.") if @errback
|
188
|
+
return false
|
189
|
+
end
|
190
|
+
else
|
191
|
+
begin
|
192
|
+
# child process
|
193
|
+
exec(@cmd)
|
194
|
+
rescue => e
|
195
|
+
exit!
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def self.execute(cmd, timeout = nil, *args)
|
201
|
+
errb = args.pop if args.last.is_a? Proc
|
202
|
+
instance = self.new(cmd, timeout, &errb)
|
203
|
+
instance.run
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
data/lib/base/barrier.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# Copyright (c) 2009-2011 VMware, Inc.
|
2
|
+
require "eventmachine"
|
3
|
+
require "thread"
|
4
|
+
|
5
|
+
module VCAP
|
6
|
+
module Services
|
7
|
+
module Base
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class VCAP::Services::Base::Barrier
|
13
|
+
|
14
|
+
def initialize(options = {}, &callback)
|
15
|
+
raise ArgumentError unless options[:timeout] || options[:callbacks]
|
16
|
+
@lock = Mutex.new
|
17
|
+
@callback = callback
|
18
|
+
@expected_callbacks = options[:callbacks]
|
19
|
+
@timer = EM.add_timer(options[:timeout]) {on_timeout} if options[:timeout]
|
20
|
+
@callback_fired = false
|
21
|
+
@responses = []
|
22
|
+
@barrier_callback = Proc.new {|*args| call(*args)}
|
23
|
+
end
|
24
|
+
|
25
|
+
def on_timeout
|
26
|
+
@lock.synchronize do
|
27
|
+
unless @callback_fired
|
28
|
+
@callback_fired = true
|
29
|
+
@callback.call(@responses)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def call(*args)
|
35
|
+
@lock.synchronize do
|
36
|
+
unless @callback_fired
|
37
|
+
@responses << args
|
38
|
+
if @expected_callbacks
|
39
|
+
@expected_callbacks -= 1
|
40
|
+
if @expected_callbacks <= 0
|
41
|
+
EM.cancel_timer(@timer) if @timer
|
42
|
+
@callback_fired = true
|
43
|
+
@callback.call(@responses)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def callback
|
51
|
+
@barrier_callback
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/lib/base/base.rb
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
# Copyright (c) 2009-2011 VMware, Inc.
|
2
|
+
require 'eventmachine'
|
3
|
+
require 'vcap/common'
|
4
|
+
require 'vcap/component'
|
5
|
+
require 'nats/client'
|
6
|
+
|
7
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
8
|
+
require 'abstract'
|
9
|
+
require 'service_error'
|
10
|
+
|
11
|
+
module VCAP
|
12
|
+
module Services
|
13
|
+
module Base
|
14
|
+
class Base
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Object
|
21
|
+
def deep_dup
|
22
|
+
Marshal::load(Marshal.dump(self))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class VCAP::Services::Base::Base
|
27
|
+
|
28
|
+
include VCAP::Services::Base::Error
|
29
|
+
|
30
|
+
attr_reader :closing
|
31
|
+
|
32
|
+
def initialize(options)
|
33
|
+
@logger = options[:logger]
|
34
|
+
@options = options
|
35
|
+
@local_ip = VCAP.local_ip(options[:ip_route])
|
36
|
+
@logger.info("#{service_description}: Initializing")
|
37
|
+
@closing = false
|
38
|
+
|
39
|
+
@node_nats = nil
|
40
|
+
if options[:mbus]
|
41
|
+
NATS.on_error do |e|
|
42
|
+
# p $!
|
43
|
+
# puts $!.backtrace.join("\n")
|
44
|
+
@logger.error("Exiting due to NATS error: #{e}")
|
45
|
+
shutdown
|
46
|
+
exit
|
47
|
+
end
|
48
|
+
@logger.debug("Connecting with NATS")
|
49
|
+
@node_nats = NATS.connect(:uri => options[:mbus]) do
|
50
|
+
status_port = status_user = status_password = nil
|
51
|
+
if not options[:status].nil?
|
52
|
+
status_port = options[:status][:port]
|
53
|
+
status_user = options[:status][:user]
|
54
|
+
status_password = options[:status][:password]
|
55
|
+
end
|
56
|
+
|
57
|
+
@logger.debug("Registering with NATS")
|
58
|
+
VCAP::Component.register(
|
59
|
+
:nats => @node_nats,
|
60
|
+
:type => service_description,
|
61
|
+
:host => @local_ip,
|
62
|
+
:index => options[:index] || 0,
|
63
|
+
:config => options,
|
64
|
+
:port => status_port,
|
65
|
+
:user => status_user,
|
66
|
+
:password => status_password
|
67
|
+
)
|
68
|
+
on_connect_node
|
69
|
+
end
|
70
|
+
else
|
71
|
+
@logger.info("NATS is disabled")
|
72
|
+
end
|
73
|
+
|
74
|
+
@max_nats_payload = options[:max_nats_payload] || 1024 * 1024
|
75
|
+
end
|
76
|
+
|
77
|
+
def service_description()
|
78
|
+
return "#{service_name}-#{flavor}"
|
79
|
+
end
|
80
|
+
|
81
|
+
def publish(reply, msg)
|
82
|
+
# nats publish are only allowed to be called in reactor thread.
|
83
|
+
EM.schedule do
|
84
|
+
@node_nats.publish(reply, msg) if @node_nats
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def update_varz()
|
89
|
+
vz = varz_details
|
90
|
+
vz.each { |k,v|
|
91
|
+
VCAP::Component.varz[k] = v
|
92
|
+
} if vz
|
93
|
+
end
|
94
|
+
|
95
|
+
def shutdown()
|
96
|
+
@closing = true
|
97
|
+
@logger.info("#{service_description}: Shutting down")
|
98
|
+
@node_nats.close if @node_nats
|
99
|
+
end
|
100
|
+
|
101
|
+
def group_handles_in_json(instances_list, bindings_list, size_limit)
|
102
|
+
while instances_list.count > 0 or bindings_list.count > 0
|
103
|
+
ins_list = []
|
104
|
+
bind_list = []
|
105
|
+
send_len = 0
|
106
|
+
idx_ins = 0
|
107
|
+
idx_bind = 0
|
108
|
+
|
109
|
+
instances_list.each do |ins|
|
110
|
+
len = ins.to_json.size + 1
|
111
|
+
if send_len + len < size_limit
|
112
|
+
send_len += len
|
113
|
+
idx_ins += 1
|
114
|
+
ins_list << ins
|
115
|
+
else
|
116
|
+
break
|
117
|
+
end
|
118
|
+
end
|
119
|
+
instances_list.slice!(0, idx_ins) if idx_ins > 0
|
120
|
+
|
121
|
+
bindings_list.each do |bind|
|
122
|
+
len = bind.to_json.size + 1
|
123
|
+
if send_len + len < size_limit
|
124
|
+
send_len += len
|
125
|
+
idx_bind += 1
|
126
|
+
bind_list << bind
|
127
|
+
else
|
128
|
+
break
|
129
|
+
end
|
130
|
+
end
|
131
|
+
bindings_list.slice!(0, idx_bind) if idx_bind > 0
|
132
|
+
|
133
|
+
# Generally, the size_limit is far more bigger than the length
|
134
|
+
# of any handles. If there's a huge handle or the size_limit is too
|
135
|
+
# small that the size_limit can't contain one handle the in one batch,
|
136
|
+
# we have to break the loop if no handle can be stuffed into batch.
|
137
|
+
if ins_list.count == 0 and bind_list.count == 0
|
138
|
+
@logger.warn("NATS message limit #{size_limit} is too small.")
|
139
|
+
break
|
140
|
+
else
|
141
|
+
yield ins_list, bind_list
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# Subclasses VCAP::Services::Base::{Node,Provisioner} implement the
|
147
|
+
# following methods. (Note that actual service Provisioner or Node
|
148
|
+
# implementations should NOT need to touch these!)
|
149
|
+
|
150
|
+
# TODO on_connect_node should be on_connect_nats
|
151
|
+
abstract :on_connect_node
|
152
|
+
abstract :flavor # "Provisioner" or "Node"
|
153
|
+
abstract :varz_details
|
154
|
+
|
155
|
+
# Service Provisioner and Node classes must implement the following
|
156
|
+
# method
|
157
|
+
abstract :service_name
|
158
|
+
|
159
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
# Copyright (c) 2009-2011 VMware, Inc.
|
2
|
+
# XXX(mjp)
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
require 'eventmachine'
|
6
|
+
require 'em-http-request'
|
7
|
+
require 'json'
|
8
|
+
require 'sinatra/base'
|
9
|
+
require 'uri'
|
10
|
+
require 'thread'
|
11
|
+
require 'json_message'
|
12
|
+
require 'services/api'
|
13
|
+
require 'services/api/const'
|
14
|
+
|
15
|
+
$:.unshift(File.dirname(__FILE__))
|
16
|
+
require 'service_error'
|
17
|
+
|
18
|
+
module VCAP
|
19
|
+
module Services
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# A simple service gateway that proxies requests onto an asynchronous service provisioners.
|
24
|
+
# NB: Do not use this with synchronous provisioners, it will produce unexpected results.
|
25
|
+
#
|
26
|
+
# TODO(mjp): This needs to handle unknown routes
|
27
|
+
class VCAP::Services::BaseAsynchronousServiceGateway < Sinatra::Base
|
28
|
+
|
29
|
+
include VCAP::Services::Base::Error
|
30
|
+
|
31
|
+
# Allow our exception handlers to take over
|
32
|
+
set :raise_errors, Proc.new {false}
|
33
|
+
set :show_exceptions, false
|
34
|
+
|
35
|
+
def initialize(opts)
|
36
|
+
super
|
37
|
+
|
38
|
+
@logger = opts[:logger]
|
39
|
+
|
40
|
+
setup(opts)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Validate the incoming request
|
44
|
+
before do
|
45
|
+
Steno.config.context.data["request_guid"] = env['HTTP_X_VCAP_REQUEST_ID']
|
46
|
+
|
47
|
+
validate_incoming_request
|
48
|
+
|
49
|
+
content_type :json
|
50
|
+
end
|
51
|
+
|
52
|
+
after do
|
53
|
+
Steno.config.context.data.delete("request_guid")
|
54
|
+
end
|
55
|
+
|
56
|
+
# Handle errors that result from malformed requests
|
57
|
+
error [JsonMessage::ValidationError, JsonMessage::ParseError] do
|
58
|
+
error_msg = ServiceError.new(ServiceError::MALFORMATTED_REQ).to_hash
|
59
|
+
abort_request(error_msg)
|
60
|
+
end
|
61
|
+
|
62
|
+
# setup the environment
|
63
|
+
def setup(opts)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Custom request validation
|
67
|
+
def validate_incoming_request
|
68
|
+
end
|
69
|
+
|
70
|
+
#################### Helpers ####################
|
71
|
+
|
72
|
+
helpers do
|
73
|
+
|
74
|
+
# Aborts the request with the supplied errs
|
75
|
+
#
|
76
|
+
# +errs+ Hash of section => err
|
77
|
+
def abort_request(error_msg)
|
78
|
+
err_body = error_msg['msg'].to_json()
|
79
|
+
halt(error_msg['status'], {'Content-Type' => Rack::Mime.mime_type('.json')}, err_body)
|
80
|
+
end
|
81
|
+
|
82
|
+
def auth_token
|
83
|
+
@auth_token ||= request_header(VCAP::Services::Api::GATEWAY_TOKEN_HEADER)
|
84
|
+
@auth_token
|
85
|
+
end
|
86
|
+
|
87
|
+
def request_body
|
88
|
+
request.body.rewind
|
89
|
+
request.body.read
|
90
|
+
end
|
91
|
+
|
92
|
+
def request_header(header)
|
93
|
+
# This is pretty ghetto but Rack munges headers, so we need to munge them as well
|
94
|
+
rack_hdr = "HTTP_" + header.upcase.gsub(/-/, '_')
|
95
|
+
env[rack_hdr]
|
96
|
+
end
|
97
|
+
|
98
|
+
def async_mode(timeout=@node_timeout)
|
99
|
+
request.env['__async_timer'] = EM.add_timer(timeout) do
|
100
|
+
@logger.warn("Request timeout in #{timeout} seconds.")
|
101
|
+
error_msg = ServiceError.new(ServiceError::SERVICE_UNAVAILABLE).to_hash
|
102
|
+
err_body = error_msg['msg'].to_json()
|
103
|
+
request.env['async.callback'].call(
|
104
|
+
[
|
105
|
+
error_msg['status'],
|
106
|
+
{'Content-Type' => Rack::Mime.mime_type('.json')},
|
107
|
+
err_body
|
108
|
+
]
|
109
|
+
)
|
110
|
+
end unless request.env['done'] ||= false
|
111
|
+
throw :async
|
112
|
+
end
|
113
|
+
|
114
|
+
def async_reply(resp='{}')
|
115
|
+
async_reply_raw(200, {'Content-Type' => Rack::Mime.mime_type('.json')}, resp)
|
116
|
+
end
|
117
|
+
|
118
|
+
def async_reply_raw(status, headers, body)
|
119
|
+
@logger.debug("Reply status:#{status}, headers:#{headers}, body:#{body}")
|
120
|
+
@provisioner.update_responses_metrics(status) if @provisioner
|
121
|
+
request.env['done'] = true
|
122
|
+
EM.cancel_timer(request.env['__async_timer']) if request.env['__async_timer']
|
123
|
+
request.env['async.callback'].call([status, headers, body])
|
124
|
+
end
|
125
|
+
|
126
|
+
def async_reply_error(error_msg)
|
127
|
+
err_body = error_msg['msg'].to_json()
|
128
|
+
async_reply_raw(error_msg['status'], {'Content-Type' => Rack::Mime.mime_type('.json')}, err_body)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def add_proxy_opts(req)
|
135
|
+
req[:proxy] = @proxy_opts
|
136
|
+
# this is a workaround for em-http-requesr 0.3.0 so that headers are not lost
|
137
|
+
# more info: https://github.com/igrigorik/em-http-request/issues/130
|
138
|
+
req[:proxy][:head] = req[:head]
|
139
|
+
end
|
140
|
+
|
141
|
+
def create_http_request(args)
|
142
|
+
req = {
|
143
|
+
:head => args[:head],
|
144
|
+
:body => args[:body],
|
145
|
+
}
|
146
|
+
|
147
|
+
if (@proxy_opts)
|
148
|
+
add_proxy_opts(req)
|
149
|
+
end
|
150
|
+
|
151
|
+
req
|
152
|
+
end
|
153
|
+
|
154
|
+
def make_logger(level=Logger::INFO)
|
155
|
+
logger = Logger.new(STDOUT)
|
156
|
+
logger.level = level
|
157
|
+
logger
|
158
|
+
end
|
159
|
+
|
160
|
+
def http_uri(uri)
|
161
|
+
uri = "http://#{uri}" unless (uri.index('http://') == 0 || uri.index('https://') == 0)
|
162
|
+
uri
|
163
|
+
end
|
164
|
+
end
|