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 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