vcap_common 2.0.11 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/bin/fetch_gems +63 -0
- data/bin/transform_git_source +161 -0
- data/lib/cf/version.rb +3 -0
- data/lib/json_message.rb +2 -4
- data/lib/services/api/clients/service_gateway_client.rb +90 -75
- data/lib/services/api/messages.rb +28 -23
- data/lib/vcap/common.rb +20 -3
- data/lib/vcap/component.rb +37 -34
- data/lib/vcap/stats.rb +106 -0
- metadata +112 -51
- data/lib/vcap/user_pools/user_ops.rb +0 -47
- data/lib/vcap/user_pools/user_pool.rb +0 -45
- data/lib/vcap/user_pools/user_pool_util.rb +0 -107
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MTdhMGU2ZWM5ZGJkZGFmODY3NjE0NzUzMWY4NTRiNjMyM2I2OTEzMw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MGJlYjExMzJiMjEyYjRmMGMwZTczYTU3YzA2NmI0MGY0NTI2NGM4MA==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
Mjc0MmI5NzczZmYyOGE1YTY0ZTI4MTJjYjdjN2EwOWJlMTFjMzc5NDczNGU0
|
10
|
+
MDc4ZTRiMWEzYTZjMjFiMzhhZGY1OTJkZTIxZDlhN2VkMjRhZDA4NDNkZDEz
|
11
|
+
OGU4ZGFkNmI3NjNjNjcyMWE4MzdmMTQ0MjBlYjNjZTFjZjRiODQ=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YWUxZmU5OTMxNjE3MWI4MWQ5MTkxZTBkMDJmOGI5NTlmYTRkNjVhNjUyZGVi
|
14
|
+
NDAyM2U2MjRlZWIxOTEwMDQ3OTRhNjhmNzhjYjBjNDA0NjAyNzIyZDk1NmEz
|
15
|
+
OTk0Yjg2NDdkYmUzMGRiZjliNjU3MGRmMDdlNmFhOTM2YjU5NDI=
|
data/bin/fetch_gems
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'logger'
|
7
|
+
|
8
|
+
# Provides functionality similar to `bundle package`, but without needing
|
9
|
+
# to install any gems.
|
10
|
+
|
11
|
+
unless ARGV.length == 3
|
12
|
+
puts "Usage: fetch_gems [/path/to/Gemfile] [/path/to/Gemfile.lock] [/path/to/store]"
|
13
|
+
exit 1
|
14
|
+
end
|
15
|
+
|
16
|
+
gemfile_path, lockfile_path, gem_store_dir = ARGV.map {|path| File.expand_path(path) }
|
17
|
+
|
18
|
+
ENV['BUNDLE_GEMFILE'] = gemfile_path
|
19
|
+
|
20
|
+
lockfile_contents = File.read(lockfile_path)
|
21
|
+
parser = Bundler::LockfileParser.new(lockfile_contents)
|
22
|
+
|
23
|
+
logger = Logger.new(STDOUT)
|
24
|
+
|
25
|
+
if parser.specs.empty?
|
26
|
+
logger.info("No gems found")
|
27
|
+
exit 0
|
28
|
+
end
|
29
|
+
|
30
|
+
FileUtils.mkdir_p(gem_store_dir)
|
31
|
+
|
32
|
+
to_fetch = []
|
33
|
+
parser.specs.each do |spec|
|
34
|
+
gem_basename = "#{spec.name}-#{spec.version}.gem"
|
35
|
+
dst_path = File.join(gem_store_dir, gem_basename)
|
36
|
+
if spec.source.kind_of?(Bundler::Source::Path) && (spec.source.path.to_s == '.')
|
37
|
+
logger.info("Skipping '#{gem_basename}', Gemfile.lock appears to belong to it")
|
38
|
+
elsif File.exist?(dst_path)
|
39
|
+
logger.info("Skipping '#{gem_basename}', found in '#{gem_store_dir}'")
|
40
|
+
else
|
41
|
+
logger.info("Need to download '#{gem_basename}'")
|
42
|
+
to_fetch << gem_basename
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
unless to_fetch.empty?
|
47
|
+
urls = to_fetch.map do |gem_basename|
|
48
|
+
"http://production.s3.rubygems.org/gems/#{gem_basename}"
|
49
|
+
end.join(' ')
|
50
|
+
|
51
|
+
cmd = "wget --quiet --retry-connrefused --connect-timeout=5"
|
52
|
+
cmd += " --no-check-certificate --directory-prefix #{gem_store_dir} #{urls}"
|
53
|
+
|
54
|
+
logger.info("Fetching #{to_fetch.join(', ')} from rubygems")
|
55
|
+
logger.info("Executing '#{cmd}'")
|
56
|
+
|
57
|
+
unless system(cmd)
|
58
|
+
logger.error("#{cmd} failed with status #{$?}!")
|
59
|
+
exit $?.exitstatus
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
logger.info("Done")
|
@@ -0,0 +1,161 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# vim: fileencoding=utf-8
|
3
|
+
# vim: ts=2 sw=2 sts=2 et
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'bundler'
|
7
|
+
require 'fileutils'
|
8
|
+
require 'logger'
|
9
|
+
|
10
|
+
# Rewrite git sources in Gemfile and lock files to paths
|
11
|
+
#
|
12
|
+
# Usage: transform_git_source path/to/dir_w_Gemfile path/to/git/checkout
|
13
|
+
|
14
|
+
def `(cmd)
|
15
|
+
@logger.debug "executing #{cmd}"
|
16
|
+
result = super
|
17
|
+
raise RuntimeError, "error while attempting to execute #{cmd}" unless $?.exitstatus == 0
|
18
|
+
result
|
19
|
+
end
|
20
|
+
|
21
|
+
def checkout(spec, path)
|
22
|
+
unless path.join('.git').exist?
|
23
|
+
path.parent.mkpath
|
24
|
+
path.rmtree if path.exist?
|
25
|
+
%x(git clone --no-checkout #{spec.source.uri} #{path})
|
26
|
+
end
|
27
|
+
Dir.chdir(path) do
|
28
|
+
%x(git fetch --quiet --tags #{spec.source.uri})
|
29
|
+
# This is gross, but why do they keep this private?
|
30
|
+
revision = spec.source.send(:revision)
|
31
|
+
%x(git reset --hard #{revision})
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Derived from Bundler::Definition#to_lock
|
36
|
+
# Copyright Bundler contributors
|
37
|
+
# Portions copyright (c) 2010 André Arko
|
38
|
+
# Portions copyright (c) 2009 Engine Yard
|
39
|
+
def to_lock(specs, platforms, dependencies)
|
40
|
+
out = ""
|
41
|
+
|
42
|
+
specs.map {|s| s.source}.sort_by { |s| s.class.to_s }.uniq.each do |source|
|
43
|
+
# Add the source header
|
44
|
+
out << source.to_lock
|
45
|
+
# Find all specs for this source
|
46
|
+
specs.
|
47
|
+
select { |s| s.source == source }.
|
48
|
+
# This needs to be sorted by full name so that
|
49
|
+
# gems with the same name, but different platform
|
50
|
+
# are ordered consistantly
|
51
|
+
sort_by { |s| s.full_name }.
|
52
|
+
each do |spec|
|
53
|
+
next if spec.name == 'bundler'
|
54
|
+
out << spec.to_lock
|
55
|
+
end
|
56
|
+
out << "\n"
|
57
|
+
end
|
58
|
+
|
59
|
+
out << "PLATFORMS\n"
|
60
|
+
|
61
|
+
platforms.map { |p| p.to_s }.sort.each do |p|
|
62
|
+
out << " #{p}\n"
|
63
|
+
end
|
64
|
+
|
65
|
+
out << "\n"
|
66
|
+
out << "DEPENDENCIES\n"
|
67
|
+
|
68
|
+
handled = []
|
69
|
+
dependencies.
|
70
|
+
sort_by { |d| d.to_s }.
|
71
|
+
each do |dep|
|
72
|
+
next if handled.include?(dep.name)
|
73
|
+
out << dep.to_lock
|
74
|
+
handled << dep.name
|
75
|
+
end
|
76
|
+
|
77
|
+
out
|
78
|
+
end
|
79
|
+
|
80
|
+
def rewrite_lockfile(lockfile, checkout_base)
|
81
|
+
parser = Bundler::LockfileParser.new(lockfile.read)
|
82
|
+
|
83
|
+
candidates = parser.specs.select { |s| Bundler::Source::Git === s.source }
|
84
|
+
if candidates.empty?
|
85
|
+
@logger.info 'Nothing to see here, move along'
|
86
|
+
return
|
87
|
+
end
|
88
|
+
|
89
|
+
gemsrc = parser.sources.find { |s| Bundler::Source::Rubygems === s } ||
|
90
|
+
Bundler::Source::Rubygems.from_lock('remote' => 'http://rubygems.org')
|
91
|
+
lockfile.parent.join('vendor', 'cache').mkpath
|
92
|
+
candidates.each do |spec|
|
93
|
+
# TODO: shall i sanitize spec.name?
|
94
|
+
checkout_dir = checkout_base.join(spec.name)
|
95
|
+
checkout(spec, checkout_dir)
|
96
|
+
# TODO error handling
|
97
|
+
gem_dir = Pathname.glob("#{checkout_dir}/**/#{spec.name}.gemspec")[0].parent
|
98
|
+
Dir.chdir(gem_dir) do |dir|
|
99
|
+
%x(gem build #{spec.name}.gemspec)
|
100
|
+
gempath = gem_dir.join("#{spec.name}-#{spec.version}.gem")
|
101
|
+
FileUtils.link([gempath.to_s], lockfile.parent.join('vendor', 'cache').to_s, :verbose => true)
|
102
|
+
end
|
103
|
+
spec.source = gemsrc
|
104
|
+
# make the dependency have "no specified source"
|
105
|
+
parser.dependencies.find { |d| d.name == spec.name }.source = nil
|
106
|
+
end
|
107
|
+
|
108
|
+
lockfile.open('w') do |f|
|
109
|
+
f.puts to_lock(parser.specs, parser.platforms, parser.dependencies)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# We don't attempt to be a full ruby parser, only rewrite Gemfiles we wrote
|
114
|
+
def rewrite_gemfile(gemfile, checkout_base)
|
115
|
+
out = ''
|
116
|
+
probe = Object.new
|
117
|
+
class << probe
|
118
|
+
attr_reader :name, :version, :options, :path
|
119
|
+
def gem(name, *args)
|
120
|
+
@name = name
|
121
|
+
@options = args.last.is_a?(Hash) ? args.pop : {}
|
122
|
+
@version = args
|
123
|
+
unless @options.include?(:git)
|
124
|
+
raise ArgumentError, ':git option expected, none found'
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
gemfile.each_line do |line|
|
130
|
+
case line
|
131
|
+
when /^\s*gem.*:git/
|
132
|
+
if line =~ /#.*:git/ && line !~ /^[^#]+:git/
|
133
|
+
out << line
|
134
|
+
next
|
135
|
+
end
|
136
|
+
probe.instance_eval(line)
|
137
|
+
out << "gem #{probe.name.inspect}"
|
138
|
+
out << ", #{probe.version.map(&:inspect).join(', ')}" unless probe.version.empty?
|
139
|
+
out << "\n"
|
140
|
+
else
|
141
|
+
out << line
|
142
|
+
end
|
143
|
+
end
|
144
|
+
gemfile.open('w') { |f| f.write(out) }
|
145
|
+
end
|
146
|
+
|
147
|
+
if __FILE__ == $0
|
148
|
+
unless ARGV.length == 2
|
149
|
+
puts <<-USAGE
|
150
|
+
Incorrect number of arguments! Usage:
|
151
|
+
#{File.basename(__FILE__)} path/to/dir_with_Gemfile path/to/place/git/checkouts
|
152
|
+
USAGE
|
153
|
+
exit 1
|
154
|
+
end
|
155
|
+
|
156
|
+
@logger = Logger.new(STDERR)
|
157
|
+
project_dir, checkout_base = ARGV.map { |x| Pathname.new(x).expand_path }
|
158
|
+
ENV['BUNDLE_GEMFILE'] = project_dir.join('Gemfile').to_s
|
159
|
+
rewrite_lockfile(project_dir.join('Gemfile.lock'), checkout_base)
|
160
|
+
rewrite_gemfile(project_dir.join('Gemfile'), checkout_base)
|
161
|
+
end
|
data/lib/cf/version.rb
ADDED
data/lib/json_message.rb
CHANGED
@@ -167,9 +167,7 @@ class JsonMessage
|
|
167
167
|
name = name.to_sym
|
168
168
|
field = self.class.fields[name]
|
169
169
|
|
170
|
-
unless field
|
171
|
-
raise ValidationError.new( { name => "Unknown field: #{name}" } )
|
172
|
-
end
|
170
|
+
return unless field
|
173
171
|
|
174
172
|
field.validate(value)
|
175
173
|
@msg[name] = value
|
@@ -185,7 +183,7 @@ class JsonMessage
|
|
185
183
|
unless @msg.has_key?(name)
|
186
184
|
field = self.class.fields[name]
|
187
185
|
if field
|
188
|
-
@msg[name] = field.default
|
186
|
+
@msg[name] = field.default unless field.default.nil?
|
189
187
|
end
|
190
188
|
end
|
191
189
|
end
|
@@ -15,13 +15,6 @@ end
|
|
15
15
|
|
16
16
|
module VCAP::Services::Api
|
17
17
|
class ServiceGatewayClient
|
18
|
-
METHODS_MAP = {
|
19
|
-
:get => Net::HTTP::Get,
|
20
|
-
:post=> Net::HTTP::Post,
|
21
|
-
:put => Net::HTTP::Put,
|
22
|
-
:delete => Net::HTTP::Delete,
|
23
|
-
}
|
24
|
-
|
25
18
|
# Public: Indicate gateway client encounter an unexpected error,
|
26
19
|
# such as can't connect to gateway or can't decode response.
|
27
20
|
#
|
@@ -41,7 +34,16 @@ module VCAP::Services::Api
|
|
41
34
|
end
|
42
35
|
|
43
36
|
def to_s
|
44
|
-
"
|
37
|
+
"#{self.class.name}: #{error.description}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_h
|
41
|
+
{
|
42
|
+
'error' => error.extract(stringify_keys: true).merge(
|
43
|
+
'backtrace' => backtrace,
|
44
|
+
'types' => self.class.ancestors.map(&:name) - Exception.ancestors.map(&:name)
|
45
|
+
)
|
46
|
+
}
|
45
47
|
end
|
46
48
|
end
|
47
49
|
|
@@ -57,127 +59,140 @@ module VCAP::Services::Api
|
|
57
59
|
end
|
58
60
|
end
|
59
61
|
|
60
|
-
attr_reader :
|
61
|
-
|
62
|
-
def initialize(url, token, timeout,
|
63
|
-
@
|
64
|
-
@timeout = timeout
|
65
|
-
@token = token
|
66
|
-
@hdrs = {
|
67
|
-
'Content-Type' => 'application/json',
|
68
|
-
GATEWAY_TOKEN_HEADER => @token
|
69
|
-
}
|
70
|
-
# contract: @requester.responds_to? :request(url, token, timeout, [msg])
|
71
|
-
# contract @requester.request(url, token, timeout, [msg]) => [code, body]
|
72
|
-
@requester = opts[:requester] || AsyncHttpRequest
|
62
|
+
attr_reader :http_client
|
63
|
+
|
64
|
+
def initialize(url, token, timeout, request_id)
|
65
|
+
@http_client = HttpClient.new(url, token, timeout, request_id)
|
73
66
|
end
|
74
67
|
|
75
68
|
def provision(args)
|
76
69
|
msg = GatewayProvisionRequest.new(args)
|
77
|
-
resp = perform_request(:post, '/gateway/v1/configurations', msg)
|
70
|
+
resp = http_client.perform_request(:post, '/gateway/v1/configurations', msg)
|
78
71
|
GatewayHandleResponse.decode(resp)
|
79
72
|
end
|
80
73
|
|
81
74
|
def unprovision(args)
|
82
|
-
|
75
|
+
http_client.perform_request(:delete, "/gateway/v1/configurations/#{args[:service_id]}")
|
83
76
|
EMPTY_REQUEST
|
84
77
|
end
|
85
78
|
|
79
|
+
def bind(args)
|
80
|
+
msg = GatewayBindRequest.new(args)
|
81
|
+
resp = http_client.perform_request(:post, "/gateway/v1/configurations/#{msg.service_id}/handles", msg)
|
82
|
+
GatewayHandleResponse.decode(resp)
|
83
|
+
end
|
84
|
+
|
85
|
+
def unbind(args)
|
86
|
+
msg = GatewayUnbindRequest.new(args)
|
87
|
+
http_client.perform_request(:delete, "/gateway/v1/configurations/#{msg.service_id}/handles/#{msg.handle_id}", msg)
|
88
|
+
EMPTY_REQUEST
|
89
|
+
end
|
90
|
+
|
91
|
+
#------------------
|
92
|
+
# Snapshotting has never been enabled in production - we can probably remove these
|
93
|
+
#------------------
|
94
|
+
|
95
|
+
def job_info(args)
|
96
|
+
resp = http_client.perform_request(:get, "/gateway/v1/configurations/#{args[:service_id]}/jobs/#{args[:job_id]}")
|
97
|
+
Job.decode(resp)
|
98
|
+
end
|
99
|
+
|
86
100
|
def create_snapshot(args)
|
87
|
-
resp = perform_request(:post, "/gateway/v1/configurations/#{args[:service_id]}/snapshots")
|
101
|
+
resp = http_client.perform_request(:post, "/gateway/v1/configurations/#{args[:service_id]}/snapshots")
|
88
102
|
Job.decode(resp)
|
89
103
|
end
|
90
104
|
|
91
105
|
def enum_snapshots(args)
|
92
|
-
resp = perform_request(:get, "/gateway/v1/configurations/#{args[:service_id]}/snapshots")
|
106
|
+
resp = http_client.perform_request(:get, "/gateway/v1/configurations/#{args[:service_id]}/snapshots")
|
93
107
|
SnapshotList.decode(resp)
|
94
108
|
end
|
95
109
|
|
96
110
|
def snapshot_details(args)
|
97
|
-
resp = perform_request(:get, "/gateway/v1/configurations/#{args[:service_id]}/snapshots/#{args[:snapshot_id]}")
|
111
|
+
resp = http_client.perform_request(:get, "/gateway/v1/configurations/#{args[:service_id]}/snapshots/#{args[:snapshot_id]}")
|
98
112
|
Snapshot.decode(resp)
|
99
113
|
end
|
100
114
|
|
101
115
|
def update_snapshot_name(args)
|
102
|
-
perform_request(:post, "/gateway/v1/configurations/#{args[:service_id]}/snapshots/#{args[:snapshot_id]}/name", args[:msg])
|
116
|
+
http_client.perform_request(:post, "/gateway/v1/configurations/#{args[:service_id]}/snapshots/#{args[:snapshot_id]}/name", args[:msg])
|
103
117
|
EMPTY_REQUEST
|
104
118
|
end
|
105
119
|
|
106
120
|
def rollback_snapshot(args)
|
107
|
-
resp = perform_request(:put, "/gateway/v1/configurations/#{args[:service_id]}/snapshots/#{args[:snapshot_id]}")
|
121
|
+
resp = http_client.perform_request(:put, "/gateway/v1/configurations/#{args[:service_id]}/snapshots/#{args[:snapshot_id]}")
|
108
122
|
Job.decode(resp)
|
109
123
|
end
|
110
124
|
|
111
125
|
def delete_snapshot(args)
|
112
|
-
resp = perform_request(:delete, "/gateway/v1/configurations/#{args[:service_id]}/snapshots/#{args[:snapshot_id]}")
|
126
|
+
resp = http_client.perform_request(:delete, "/gateway/v1/configurations/#{args[:service_id]}/snapshots/#{args[:snapshot_id]}")
|
113
127
|
Job.decode(resp)
|
114
128
|
end
|
115
129
|
|
116
130
|
def create_serialized_url(args)
|
117
|
-
resp = perform_request(:post, "/gateway/v1/configurations/#{args[:service_id]}/serialized/url/snapshots/#{args[:snapshot_id]}")
|
131
|
+
resp = http_client.perform_request(:post, "/gateway/v1/configurations/#{args[:service_id]}/serialized/url/snapshots/#{args[:snapshot_id]}")
|
118
132
|
Job.decode(resp)
|
119
133
|
end
|
120
134
|
|
121
135
|
def serialized_url(args)
|
122
|
-
resp = perform_request(:get, "/gateway/v1/configurations/#{args[:service_id]}/serialized/url/snapshots/#{args[:snapshot_id]}")
|
136
|
+
resp = http_client.perform_request(:get, "/gateway/v1/configurations/#{args[:service_id]}/serialized/url/snapshots/#{args[:snapshot_id]}")
|
123
137
|
SerializedURL.decode(resp)
|
124
138
|
end
|
125
139
|
|
126
140
|
def import_from_url(args)
|
127
|
-
resp = perform_request(:put, "/gateway/v1/configurations/#{args[:service_id]}/serialized/url", args[:msg])
|
141
|
+
resp = http_client.perform_request(:put, "/gateway/v1/configurations/#{args[:service_id]}/serialized/url", args[:msg])
|
128
142
|
Job.decode(resp)
|
129
143
|
end
|
130
144
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
145
|
+
class HttpClient
|
146
|
+
METHODS_MAP = {
|
147
|
+
get: Net::HTTP::Get,
|
148
|
+
post: Net::HTTP::Post,
|
149
|
+
put: Net::HTTP::Put,
|
150
|
+
delete: Net::HTTP::Delete,
|
151
|
+
}
|
135
152
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
153
|
+
attr_reader :uri, :timeout, :token, :headers
|
154
|
+
|
155
|
+
def initialize(uri, token, timeout, request_id)
|
156
|
+
@uri = URI.parse(uri)
|
157
|
+
@timeout = timeout
|
158
|
+
@token = token
|
159
|
+
@headers = {
|
160
|
+
'Content-Type' => 'application/json',
|
161
|
+
GATEWAY_TOKEN_HEADER => token,
|
162
|
+
"X-VCAP-Request-ID" => request_id.to_s
|
163
|
+
}
|
164
|
+
end
|
141
165
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
end
|
166
|
+
def perform_request(http_method, path, msg = EMPTY_REQUEST)
|
167
|
+
klass = METHODS_MAP[http_method]
|
168
|
+
request = klass.new(path, headers)
|
169
|
+
request.body = msg.encode
|
147
170
|
|
148
|
-
|
171
|
+
opts = {}
|
172
|
+
if uri.scheme == "https"
|
173
|
+
opts[:use_ssl] = true
|
174
|
+
end
|
175
|
+
|
176
|
+
response = Net::HTTP.start(uri.host, uri.port, opts) do |http|
|
177
|
+
http.request(request)
|
178
|
+
end
|
179
|
+
|
180
|
+
code = response.code.to_i
|
181
|
+
body = response.body
|
182
|
+
|
183
|
+
return body if code == 200
|
149
184
|
|
150
|
-
def perform_request(http_method, path, msg=VCAP::Services::Api::EMPTY_REQUEST)
|
151
|
-
result = nil
|
152
|
-
uri = URI.parse(@url)
|
153
|
-
if EM.reactor_running?
|
154
|
-
url = URI.parse(uri.to_s + path)
|
155
|
-
code, body = requester.request(url, @token, http_method, @timeout, msg)
|
156
|
-
else
|
157
|
-
klass = METHODS_MAP[http_method]
|
158
|
-
req = klass.new(path, initheader=@hdrs)
|
159
|
-
req.body = msg.encode
|
160
|
-
resp = Net::HTTP.new(uri.host, uri.port).start {|http| http.request(req)}
|
161
|
-
code = resp.code.to_i
|
162
|
-
body = resp.body
|
163
|
-
end
|
164
|
-
case code
|
165
|
-
when 200
|
166
|
-
body
|
167
|
-
when 404
|
168
|
-
err = ServiceErrorResponse.decode(body)
|
169
|
-
raise NotFoundResponse.new(err)
|
170
|
-
when 503
|
171
|
-
err = ServiceErrorResponse.decode(body)
|
172
|
-
raise GatewayInternalResponse.new(err)
|
173
|
-
else
|
174
185
|
begin
|
175
|
-
# try to decode the response
|
176
186
|
err = ServiceErrorResponse.decode(body)
|
177
|
-
rescue
|
178
|
-
raise UnexpectedResponse, "Can't decode gateway response. status code
|
187
|
+
rescue JsonMessage::Error
|
188
|
+
raise UnexpectedResponse, "Can't decode gateway response. status code: #{code}, response body: #{body}"
|
189
|
+
end
|
190
|
+
|
191
|
+
case code
|
192
|
+
when 404 then raise NotFoundResponse.new(err)
|
193
|
+
when 503 then raise GatewayInternalResponse.new(err)
|
194
|
+
else raise ErrorResponse.new(code, err)
|
179
195
|
end
|
180
|
-
raise ErrorResponse.new(code, err)
|
181
196
|
end
|
182
197
|
end
|
183
198
|
end
|
@@ -82,9 +82,9 @@ module VCAP
|
|
82
82
|
# NB: Unprovision takes all args in the url
|
83
83
|
#
|
84
84
|
class CloudControllerProvisionRequest < JsonMessage
|
85
|
-
required :label,
|
86
|
-
required :name,
|
87
|
-
required :plan,
|
85
|
+
required :label, SERVICE_LABEL_REGEX
|
86
|
+
required :name, String
|
87
|
+
required :plan, String
|
88
88
|
required :version, String
|
89
89
|
|
90
90
|
optional :plan_option
|
@@ -92,10 +92,10 @@ module VCAP
|
|
92
92
|
end
|
93
93
|
|
94
94
|
class GatewayProvisionRequest < JsonMessage
|
95
|
-
required :unique_id,
|
96
|
-
required :name,
|
97
|
-
required :email, String
|
95
|
+
required :unique_id, String
|
96
|
+
required :name, String
|
98
97
|
|
98
|
+
optional :email, String
|
99
99
|
optional :provider, String
|
100
100
|
optional :label, String
|
101
101
|
optional :plan, String
|
@@ -107,10 +107,12 @@ module VCAP
|
|
107
107
|
|
108
108
|
# Provision and bind response use the same format
|
109
109
|
class GatewayHandleResponse < JsonMessage
|
110
|
-
required :service_id,
|
110
|
+
required :service_id, String
|
111
111
|
required :configuration
|
112
112
|
required :credentials
|
113
|
-
|
113
|
+
|
114
|
+
optional :dashboard_url, String
|
115
|
+
optional :syslog_drain_url, String
|
114
116
|
end
|
115
117
|
|
116
118
|
#
|
@@ -127,6 +129,8 @@ module VCAP
|
|
127
129
|
required :label, String
|
128
130
|
required :email, String
|
129
131
|
required :binding_options
|
132
|
+
|
133
|
+
optional :app_id, String
|
130
134
|
end
|
131
135
|
|
132
136
|
class GatewayUnbindRequest < JsonMessage
|
@@ -152,10 +156,10 @@ module VCAP
|
|
152
156
|
end
|
153
157
|
|
154
158
|
class Snapshot < JsonMessage
|
155
|
-
required :snapshot_id,
|
156
|
-
required :date,
|
157
|
-
required :size,
|
158
|
-
required :name,
|
159
|
+
required :snapshot_id, String
|
160
|
+
required :date, String
|
161
|
+
required :size, Integer
|
162
|
+
required :name, String
|
159
163
|
end
|
160
164
|
|
161
165
|
class SnapshotList < JsonMessage
|
@@ -167,10 +171,10 @@ module VCAP
|
|
167
171
|
end
|
168
172
|
|
169
173
|
class SnapshotV2 < JsonMessage
|
170
|
-
required :snapshot_id,
|
171
|
-
required :name,
|
172
|
-
required :state,
|
173
|
-
required :size,
|
174
|
+
required :snapshot_id, String
|
175
|
+
required :name, String
|
176
|
+
required :state, String
|
177
|
+
required :size, Integer
|
174
178
|
|
175
179
|
optional :created_time, String
|
176
180
|
optional :restored_time, String
|
@@ -185,12 +189,12 @@ module VCAP
|
|
185
189
|
end
|
186
190
|
|
187
191
|
class Job < JsonMessage
|
188
|
-
required :job_id,
|
189
|
-
required :status,
|
190
|
-
required :start_time,
|
191
|
-
optional :description,
|
192
|
+
required :job_id, String
|
193
|
+
required :status, String
|
194
|
+
required :start_time, String
|
195
|
+
optional :description, String
|
192
196
|
optional :complete_time, String
|
193
|
-
optional :result,
|
197
|
+
optional :result, Object
|
194
198
|
end
|
195
199
|
|
196
200
|
class SerializedURL < JsonMessage
|
@@ -198,12 +202,13 @@ module VCAP
|
|
198
202
|
end
|
199
203
|
|
200
204
|
class SerializedData < JsonMessage
|
201
|
-
required :data,
|
205
|
+
required :data, String
|
202
206
|
end
|
203
207
|
|
204
208
|
class ServiceErrorResponse < JsonMessage
|
205
|
-
required :code,
|
209
|
+
required :code, Integer
|
206
210
|
required :description, String
|
211
|
+
optional :error, Hash
|
207
212
|
end
|
208
213
|
end
|
209
214
|
end
|
data/lib/vcap/common.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
# Copyright (c) 2009-2011 VMware, Inc.
|
2
2
|
require 'fileutils'
|
3
3
|
require 'socket'
|
4
|
+
require 'uuidtools'
|
4
5
|
|
5
6
|
# VMware's Cloud Application Platform
|
6
7
|
|
7
8
|
module VCAP
|
8
9
|
|
10
|
+
WINDOWS = RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
|
9
11
|
A_ROOT_SERVER = '198.41.0.4'
|
10
12
|
|
11
13
|
def self.local_ip(route = A_ROOT_SERVER)
|
@@ -17,16 +19,18 @@ module VCAP
|
|
17
19
|
end
|
18
20
|
|
19
21
|
def self.secure_uuid
|
20
|
-
result =
|
22
|
+
result = UUIDTools::UUID.random_create.to_s.delete('-')
|
21
23
|
end
|
22
24
|
|
23
25
|
def self.grab_ephemeral_port
|
24
26
|
socket = TCPServer.new('0.0.0.0', 0)
|
25
27
|
socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
|
26
|
-
Socket.do_not_reverse_lookup = true
|
28
|
+
orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true
|
27
29
|
port = socket.addr[1]
|
28
30
|
socket.close
|
29
31
|
return port
|
32
|
+
ensure
|
33
|
+
Socket.do_not_reverse_lookup = orig
|
30
34
|
end
|
31
35
|
|
32
36
|
def self.uptime_string(delta)
|
@@ -40,6 +44,13 @@ module VCAP
|
|
40
44
|
"#{days}d:#{hours}h:#{minutes}m:#{num_seconds}s"
|
41
45
|
end
|
42
46
|
|
47
|
+
def self.uptime_string_to_seconds(string)
|
48
|
+
parts = string.split(":", 4).map { |i| i.to_i}
|
49
|
+
raise ArgumentError.new("Invalid format") unless parts.size == 4
|
50
|
+
days, hours, mins, secs = parts
|
51
|
+
secs + (mins * 60) + (hours * 3600) + (days * 24 * 3600)
|
52
|
+
end
|
53
|
+
|
43
54
|
def self.num_cores
|
44
55
|
if RUBY_PLATFORM =~ /linux/
|
45
56
|
return `cat /proc/cpuinfo | grep processor | wc -l`.to_i
|
@@ -47,6 +58,8 @@ module VCAP
|
|
47
58
|
`hwprefs cpu_count`.strip.to_i
|
48
59
|
elsif RUBY_PLATFORM =~ /freebsd|netbsd/
|
49
60
|
`sysctl hw.ncpu`.strip.to_i
|
61
|
+
elsif WINDOWS
|
62
|
+
(ENV['NUMBER_OF_PROCESSORS'] || 1).to_i
|
50
63
|
else
|
51
64
|
return 1 # unknown..
|
52
65
|
end
|
@@ -92,7 +105,11 @@ module VCAP
|
|
92
105
|
|
93
106
|
def self.process_running?(pid)
|
94
107
|
return false unless pid && (pid > 0)
|
95
|
-
|
108
|
+
if WINDOWS
|
109
|
+
output = %x[tasklist /nh /fo csv /fi "pid eq #{pid}"]
|
110
|
+
else
|
111
|
+
output = %x[ps -o rss= -p #{pid}]
|
112
|
+
end
|
96
113
|
return true if ($? == 0 && !output.empty?)
|
97
114
|
# fail otherwise..
|
98
115
|
return false
|