vcap_services_base 0.2.10
Sign up to get free protection for your applications and to get access to all the features.
- 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
|