vcap_common 2.0.11 → 3.0.0
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 +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
|