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 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
@@ -0,0 +1,3 @@
1
+ module Cf
2
+ VERSION = "3.0.0".freeze
3
+ end
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 if 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
- "Reponse status:#{status},error:[#{error.extract}]"
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 :host, :port, :token
61
- attr_reader :requester
62
- def initialize(url, token, timeout, opts={})
63
- @url = url
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
- resp = perform_request(:delete, "/gateway/v1/configurations/#{args[:service_id]}")
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
- def job_info(args)
132
- resp = perform_request(:get, "/gateway/v1/configurations/#{args[:service_id]}/jobs/#{args[:job_id]}")
133
- Job.decode(resp)
134
- end
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
- def bind(args)
137
- msg = GatewayBindRequest.new(args)
138
- resp = perform_request(:post, "/gateway/v1/configurations/#{msg.service_id}/handles", msg)
139
- GatewayHandleResponse.decode(resp)
140
- end
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
- def unbind(args)
143
- msg = GatewayUnbindRequest.new(args)
144
- perform_request(:delete, "/gateway/v1/configurations/#{msg.service_id}/handles/#{msg.handle_id}", msg)
145
- EMPTY_REQUEST
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
- protected
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 => e
178
- raise UnexpectedResponse, "Can't decode gateway response. status code:#{code}, response body:#{body}"
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, SERVICE_LABEL_REGEX
86
- required :name, String
87
- required :plan, String
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, String
96
- required :name, String
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, String
110
+ required :service_id, String
111
111
  required :configuration
112
112
  required :credentials
113
- optional :dashboard_url, String
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, String
156
- required :date, String
157
- required :size, Integer
158
- required :name, String
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, String
171
- required :name, String
172
- required :state, String
173
- required :size, Integer
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, String
189
- required :status, String
190
- required :start_time, String
191
- optional :description, String
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, Object
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, String
205
+ required :data, String
202
206
  end
203
207
 
204
208
  class ServiceErrorResponse < JsonMessage
205
- required :code, Integer
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 = File.open('/dev/urandom') { |x| x.read(16).unpack('H*')[0] }
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
- output = %x[ps -o rss= -p #{pid}]
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