vcap_common 1.0.10 → 2.0.8
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.
- data/lib/json_message.rb +98 -45
- data/lib/services/api.rb +1 -0
- data/lib/services/api/async_requests.rb +45 -1
- data/lib/services/api/clients/sds_client.rb +84 -0
- data/lib/services/api/clients/service_gateway_client.rb +150 -73
- data/lib/services/api/const.rb +1 -0
- data/lib/services/api/messages.rb +35 -21
- data/lib/services/api/multipart.rb +191 -0
- data/lib/vcap/component.rb +1 -1
- data/lib/vcap/config.rb +3 -4
- data/lib/vcap/sorted_set_utils.rb +42 -0
- data/lib/vcap/spec/forked_component/base.rb +8 -3
- metadata +118 -37
- data/lib/json_schema.rb +0 -84
- data/lib/vcap/json_schema.rb +0 -202
data/lib/services/api/const.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
require 'uri'
|
3
3
|
|
4
4
|
require 'services/api/const'
|
5
|
+
require 'membrane'
|
5
6
|
require 'json_message'
|
6
7
|
|
7
8
|
module VCAP
|
@@ -17,21 +18,26 @@ module VCAP
|
|
17
18
|
# NB: Deleting an offering takes all args in the url
|
18
19
|
#
|
19
20
|
class ServiceOfferingRequest < JsonMessage
|
20
|
-
required :label,
|
21
|
-
required :url,
|
21
|
+
required :label, SERVICE_LABEL_REGEX
|
22
|
+
required :url, URI::regexp(%w(http https))
|
23
|
+
required :supported_versions, [String]
|
24
|
+
required :version_aliases, Hash
|
22
25
|
|
23
|
-
optional :description,
|
24
|
-
optional :info_url,
|
25
|
-
optional :tags,
|
26
|
-
optional :plans,
|
26
|
+
optional :description, String
|
27
|
+
optional :info_url, URI::regexp(%w(http https))
|
28
|
+
optional :tags, [String]
|
29
|
+
optional :plans, [String]
|
30
|
+
optional :cf_plan_id
|
27
31
|
optional :plan_options
|
28
32
|
optional :binding_options
|
29
33
|
optional :acls
|
30
34
|
optional :active
|
31
|
-
optional :timeout,
|
35
|
+
optional :timeout, Integer
|
36
|
+
optional :provider, String
|
37
|
+
optional :default_plan, String
|
32
38
|
end
|
33
39
|
|
34
|
-
class
|
40
|
+
class ProxiedServiceOfferingRequest < JsonMessage
|
35
41
|
required :label, SERVICE_LABEL_REGEX
|
36
42
|
required :options, [{"name" => String, "credentials" => Hash}]
|
37
43
|
optional :description, String
|
@@ -44,11 +50,11 @@ module VCAP
|
|
44
50
|
end
|
45
51
|
|
46
52
|
class ListHandlesResponse < JsonMessage
|
47
|
-
required :handles, [
|
53
|
+
required :handles, [Object]
|
48
54
|
end
|
49
55
|
|
50
|
-
class
|
51
|
-
required :
|
56
|
+
class ListProxiedServicesResponse < JsonMessage
|
57
|
+
required :proxied_services, [{"label" => String, "description" => String, "acls" => {"users" => [String], "wildcards" => [String]}}]
|
52
58
|
end
|
53
59
|
|
54
60
|
#
|
@@ -59,8 +65,10 @@ module VCAP
|
|
59
65
|
required :label, SERVICE_LABEL_REGEX
|
60
66
|
required :name, String
|
61
67
|
required :plan, String
|
68
|
+
required :version, String
|
62
69
|
|
63
70
|
optional :plan_option
|
71
|
+
optional :provider, String
|
64
72
|
end
|
65
73
|
|
66
74
|
class GatewayProvisionRequest < JsonMessage
|
@@ -68,13 +76,15 @@ module VCAP
|
|
68
76
|
required :name, String
|
69
77
|
required :plan, String
|
70
78
|
required :email, String
|
79
|
+
required :version, String
|
71
80
|
|
72
81
|
optional :plan_option
|
73
82
|
end
|
74
83
|
|
75
|
-
|
84
|
+
# Provision and bind response use the same format
|
85
|
+
class GatewayHandleResponse < JsonMessage
|
76
86
|
required :service_id, String
|
77
|
-
required :
|
87
|
+
required :configuration
|
78
88
|
required :credentials
|
79
89
|
end
|
80
90
|
|
@@ -105,12 +115,6 @@ module VCAP
|
|
105
115
|
required :binding_token, String
|
106
116
|
end
|
107
117
|
|
108
|
-
class GatewayBindResponse < JsonMessage
|
109
|
-
required :service_id, String
|
110
|
-
required :configuration
|
111
|
-
required :credentials
|
112
|
-
end
|
113
|
-
|
114
118
|
# Bind app_name using binding_token
|
115
119
|
class BindExternalRequest < JsonMessage
|
116
120
|
required :binding_token, String
|
@@ -126,10 +130,15 @@ module VCAP
|
|
126
130
|
required :snapshot_id, String
|
127
131
|
required :date, String
|
128
132
|
required :size, Integer
|
133
|
+
required :name, String
|
129
134
|
end
|
130
135
|
|
131
136
|
class SnapshotList < JsonMessage
|
132
|
-
required :snapshots, [
|
137
|
+
required :snapshots, [Object]
|
138
|
+
end
|
139
|
+
|
140
|
+
class UpdateSnapshotNameRequest < JsonMessage
|
141
|
+
required :name, String
|
133
142
|
end
|
134
143
|
|
135
144
|
class Job < JsonMessage
|
@@ -138,7 +147,7 @@ module VCAP
|
|
138
147
|
required :start_time, String
|
139
148
|
optional :description, String
|
140
149
|
optional :complete_time, String
|
141
|
-
optional :result,
|
150
|
+
optional :result, Object
|
142
151
|
end
|
143
152
|
|
144
153
|
class SerializedURL < JsonMessage
|
@@ -148,6 +157,11 @@ module VCAP
|
|
148
157
|
class SerializedData < JsonMessage
|
149
158
|
required :data, String
|
150
159
|
end
|
160
|
+
|
161
|
+
class ServiceErrorResponse < JsonMessage
|
162
|
+
required :code, Integer
|
163
|
+
required :description, String
|
164
|
+
end
|
151
165
|
end
|
152
166
|
end
|
153
167
|
end
|
@@ -0,0 +1,191 @@
|
|
1
|
+
# Copyright (c) 2009-2011 VMware, Inc.
|
2
|
+
require 'eventmachine'
|
3
|
+
require 'em-http-request'
|
4
|
+
|
5
|
+
# monkey-patch for em-http-request to support multipart file upload
|
6
|
+
|
7
|
+
module EventMachine
|
8
|
+
class StreamUploadIO
|
9
|
+
attr_reader :args, :filename, :basename, :size, :content_type
|
10
|
+
def initialize(filename, content_type, args={})
|
11
|
+
# disable http chunking
|
12
|
+
@args = args.merge({:http_chunks => false})
|
13
|
+
@filename = filename
|
14
|
+
# FIXME how to catch exception and log it
|
15
|
+
begin
|
16
|
+
@basename = File.basename(filename)
|
17
|
+
@size = File.size(filename)
|
18
|
+
rescue => e
|
19
|
+
# size == 0, the part will be injected
|
20
|
+
@size = 0
|
21
|
+
end
|
22
|
+
@content_type = content_type
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_extra_size(extra_size)
|
26
|
+
@size += extra_size
|
27
|
+
end
|
28
|
+
|
29
|
+
def length
|
30
|
+
@size
|
31
|
+
end
|
32
|
+
|
33
|
+
def stream_file_data
|
34
|
+
true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module Part
|
39
|
+
def self.create(boundary, k, v)
|
40
|
+
if v.respond_to?(:stream_file_data)
|
41
|
+
FilePart.new(boundary, k, v)
|
42
|
+
else
|
43
|
+
ParamPart.new(boundary, k, v)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_io
|
48
|
+
@io
|
49
|
+
end
|
50
|
+
|
51
|
+
def length
|
52
|
+
@io.size
|
53
|
+
end
|
54
|
+
|
55
|
+
def send_part(conn, parts, idx)
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_next_part(parts, idx)
|
59
|
+
next_idx = idx.to_i + 1
|
60
|
+
if parts && next_idx < parts.size && next_idx >=0
|
61
|
+
next_part = parts[next_idx]
|
62
|
+
else
|
63
|
+
nil
|
64
|
+
end
|
65
|
+
next_part
|
66
|
+
end
|
67
|
+
|
68
|
+
def send_next_part(conn, parts, idx)
|
69
|
+
next_part = get_next_part(parts, idx)
|
70
|
+
next_part.send_part(conn, parts, idx+1) if next_part
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
class ParamPart
|
76
|
+
include Part
|
77
|
+
def initialize(boundary, name, value)
|
78
|
+
@boundary = boundary
|
79
|
+
@name = name
|
80
|
+
part = ''
|
81
|
+
part << "--#{@boundary}\r\n"
|
82
|
+
part << "Content-Disposition: form-data; name=\"#{@name.to_s}\"\r\n"
|
83
|
+
part << "\r\n"
|
84
|
+
part << "#{value.to_s}\r\n"
|
85
|
+
@io = StringIO.new(part)
|
86
|
+
end
|
87
|
+
|
88
|
+
def send_part(conn, parts, idx)
|
89
|
+
conn.send_data @io.string if conn
|
90
|
+
send_next_part(conn, parts, idx)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class EpiloguePart
|
95
|
+
include Part
|
96
|
+
def initialize(boundary)
|
97
|
+
@io = StringIO.new("--#{boundary}--\r\n") #\r\n or \r\n\r\n
|
98
|
+
end
|
99
|
+
|
100
|
+
def send_part(conn, parts, idx)
|
101
|
+
conn.send_data @io.string if conn
|
102
|
+
# this part should be the last part
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class FilePart
|
107
|
+
include Part
|
108
|
+
def initialize(boundary, name, upload_io)
|
109
|
+
@boundary = boundary
|
110
|
+
@name = name
|
111
|
+
@io = upload_io
|
112
|
+
@part = ''
|
113
|
+
@part << "--#{boundary}\r\n"
|
114
|
+
@part << "Content-Disposition: form-data; name=\"#{name.to_s}\"; filename=\"#{@io.filename}\"\r\n"
|
115
|
+
@part << "Content-Length: #{@io.size}\r\n"
|
116
|
+
@part << "Content-Type: #{@io.content_type}\r\n"
|
117
|
+
@part << "Content-Transfer-Encoding: binary\r\n"
|
118
|
+
@part << "\r\n"
|
119
|
+
@end_part ="\r\n"
|
120
|
+
@io.add_extra_size(@part.size + @end_part.size)
|
121
|
+
end
|
122
|
+
|
123
|
+
def send_part(conn, parts, idx)
|
124
|
+
conn.send_data @part
|
125
|
+
streamer = EM::FileStreamer.new(conn, @io.filename, @io.args)
|
126
|
+
streamer.callback {
|
127
|
+
conn.send_data @end_part
|
128
|
+
send_next_part(conn, parts, idx)
|
129
|
+
}
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class Multipart
|
134
|
+
DEFAULT_BOUNDARY = "-----------RubyEMMultiPartPost"
|
135
|
+
attr_reader :parts, :ps, :content_type, :content_length, :boundary, :headers
|
136
|
+
def initialize(params, headers={}, boundary=DEFAULT_BOUNDARY)
|
137
|
+
@parts = params.map{ |k,v| Part.create(boundary, k, v) }
|
138
|
+
@parts << EpiloguePart.new(boundary)
|
139
|
+
# inject the part with length = 0
|
140
|
+
@ps = @parts.select{ |part| part.length > 0 }
|
141
|
+
@content_type = "multipart/form-data; boundary=#{boundary}"
|
142
|
+
@content_length = 0
|
143
|
+
@parts.each do |part|
|
144
|
+
@content_length += part.length
|
145
|
+
end
|
146
|
+
@boundary = boundary
|
147
|
+
@headers = headers
|
148
|
+
end
|
149
|
+
|
150
|
+
def send_body(conn)
|
151
|
+
if conn && conn.error.nil? && @parts.size > 0
|
152
|
+
part = @parts.first
|
153
|
+
part.send_part(conn, @parts, 0)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
## Support to streaming the file when sending body
|
160
|
+
## TODO FIXME this patch whether depends on specified version???
|
161
|
+
module EventMachine
|
162
|
+
class HttpClient
|
163
|
+
alias_method :original_send_request, :send_request
|
164
|
+
def multipart_request?
|
165
|
+
(@req.method == 'POST' or @req.method == 'PUT') and @options[:multipart]
|
166
|
+
end
|
167
|
+
|
168
|
+
def send_request(head, body)
|
169
|
+
unless multipart_request?
|
170
|
+
original_send_request(head, body)
|
171
|
+
else
|
172
|
+
body = normalize_body(body)
|
173
|
+
multipart = @options[:multipart]
|
174
|
+
query = @options[:query]
|
175
|
+
|
176
|
+
head['content-length'] = multipart.content_length
|
177
|
+
head['content-type'] = multipart.content_type
|
178
|
+
extra_headers = {}
|
179
|
+
extra_headers = multipart.headers.reject { |k, v| %w(content-length content-type).include?(k.to_s.downcase) }
|
180
|
+
head.merge! extra_headers
|
181
|
+
|
182
|
+
request_header ||= encode_request(@req.method, @req.uri, query, @conn.opts.proxy)
|
183
|
+
request_header << encode_headers(head)
|
184
|
+
request_header << CRLF
|
185
|
+
@conn.send_data request_header
|
186
|
+
|
187
|
+
multipart.send_body(@conn)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
data/lib/vcap/component.rb
CHANGED
@@ -45,7 +45,7 @@ module VCAP
|
|
45
45
|
class Component
|
46
46
|
|
47
47
|
# We will suppress these from normal varz reporting by default.
|
48
|
-
CONFIG_SUPPRESS = Set.new([:mbus, :service_mbus, :keys, :database_environment, :
|
48
|
+
CONFIG_SUPPRESS = Set.new([:mbus, :service_mbus, :keys, :database_environment, :password, :pass, :token])
|
49
49
|
|
50
50
|
class << self
|
51
51
|
|
data/lib/vcap/config.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
require 'yaml'
|
3
3
|
|
4
4
|
require 'vcap/common'
|
5
|
-
require '
|
5
|
+
require 'membrane'
|
6
6
|
|
7
7
|
module VCAP
|
8
8
|
class Config
|
@@ -10,13 +10,13 @@ module VCAP
|
|
10
10
|
attr_reader :schema
|
11
11
|
|
12
12
|
def define_schema(&blk)
|
13
|
-
@schema =
|
13
|
+
@schema = Membrane::SchemaParser.parse(&blk)
|
14
14
|
end
|
15
15
|
|
16
16
|
def from_file(filename, symbolize_keys=true)
|
17
17
|
config = YAML.load_file(filename)
|
18
|
-
@schema.validate(config)
|
19
18
|
config = VCAP.symbolize_keys(config) if symbolize_keys
|
19
|
+
@schema.validate(config)
|
20
20
|
config
|
21
21
|
end
|
22
22
|
|
@@ -27,6 +27,5 @@ module VCAP
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
30
|
-
|
31
30
|
end
|
32
31
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
#
|
3
|
+
# These two methods provide support for transfering an integer sorted set to/from
|
4
|
+
# array. When encoded into JSON format, the to_int_array method is space efficient
|
5
|
+
# comparing to the native to_a method of sorted set.
|
6
|
+
#
|
7
|
+
# For example, the following set
|
8
|
+
# [12345, 12456, 13457, 13567, 14203, 14214]
|
9
|
+
#
|
10
|
+
# After encoded by to_int_array, it becomes
|
11
|
+
# [12345, 111, 1, 90, 636, 11]
|
12
|
+
#
|
13
|
+
# The JSON format will save lots of space
|
14
|
+
#
|
15
|
+
|
16
|
+
require 'set'
|
17
|
+
|
18
|
+
class SortedSet
|
19
|
+
def to_int_array
|
20
|
+
array = []
|
21
|
+
|
22
|
+
former = 0
|
23
|
+
self.each do |i|
|
24
|
+
array << i - former
|
25
|
+
former = i
|
26
|
+
end
|
27
|
+
|
28
|
+
array
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.from_int_array(array)
|
32
|
+
set = SortedSet.new
|
33
|
+
|
34
|
+
current = 0
|
35
|
+
array.each do |i|
|
36
|
+
current += i
|
37
|
+
set << current
|
38
|
+
end
|
39
|
+
|
40
|
+
set
|
41
|
+
end
|
42
|
+
end
|
@@ -11,7 +11,7 @@ end
|
|
11
11
|
class VCAP::Spec::ForkedComponent::Base
|
12
12
|
attr_reader :pid, :pid_filename, :output_basedir, :name, :cmd
|
13
13
|
|
14
|
-
attr_accessor :reopen_stdio
|
14
|
+
attr_accessor :reopen_stdio, :daemon
|
15
15
|
|
16
16
|
# @param cmd String Command to run
|
17
17
|
# @param name String Short name for this component (e.g. 'redis')
|
@@ -25,6 +25,7 @@ class VCAP::Spec::ForkedComponent::Base
|
|
25
25
|
@pid_filename = pid_filename
|
26
26
|
|
27
27
|
@reopen_stdio = true
|
28
|
+
@daemon = false
|
28
29
|
|
29
30
|
end
|
30
31
|
|
@@ -53,8 +54,12 @@ class VCAP::Spec::ForkedComponent::Base
|
|
53
54
|
|
54
55
|
def stop
|
55
56
|
return unless @pid && VCAP.process_running?(@pid)
|
56
|
-
|
57
|
-
|
57
|
+
if @daemon
|
58
|
+
Process.kill('KILL', @pid)
|
59
|
+
else
|
60
|
+
Process.kill('TERM', @pid)
|
61
|
+
Process.waitpid(@pid, 0)
|
62
|
+
end
|
58
63
|
FileUtils.rm_f(@pid_filename) if @pid_filename
|
59
64
|
@pid = nil
|
60
65
|
|