cf_light_api 2.6.0 → 3.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f127e7dd8c7c4b60f024d4e7bb68b5486b600087
4
- data.tar.gz: 1aad85e99f737e39c93bb9fea8819661e6698f51
3
+ metadata.gz: 3d374bcb2bda0fd2db6302a99752f4ffe46438ad
4
+ data.tar.gz: 02301b70a44ba3d2376828040f407f8c46597a0f
5
5
  SHA512:
6
- metadata.gz: 1b2aa1e7f16ccd9fe899941ab36765b2f705bb949d83e7176f83007069007781d5b910c8cfec3e2e6dbc20ae777b5c7b446bf6c89a6bce830ad63d65e521d50f
7
- data.tar.gz: 2993f6ffcaa1f04c05020f4aa4c79b9d922cdd1935e91caded16d7ab86a92e7bd93f4b7056696dde74600c6eb948925bd7417bdb7b0097c9a915bbfc9b66c476
6
+ metadata.gz: 5535e198e1e5531135cb259529079a91c1c5f91aeafa93a4ef65b8a8f7fbbbf4da142d4a0c755d6fdcda221841666d1425561f64d2b230c89ba60542e9ce97f2
7
+ data.tar.gz: 79e6852453c97727dba30d4877aa2503757e95b467a94ad7bc2562324aec5e29519119d02c522704898acac4620cdc199c84d5211361016fa7e5d842f5d353ad
data/bin/cf_light_api CHANGED
@@ -15,6 +15,7 @@ if ENV['NEW_RELIC_APP_NAME'] or ENV['NEW_RELIC_LICENSE_KEY']
15
15
  end
16
16
 
17
17
  require_relative '../lib/cf_light_api/redis.rb'
18
+ require_relative '../lib/cf_light_api/cf_response_error.rb'
18
19
  require_relative '../lib/cf_light_api/worker.rb'
19
20
 
20
21
  require 'sinatra'
@@ -0,0 +1,2 @@
1
+ class CFResponseError < StandardError
2
+ end
@@ -18,6 +18,13 @@ class CFLightAPIWorker
18
18
 
19
19
  def initialize
20
20
  @logger = Logger.new(STDOUT)
21
+
22
+ if ENV['DEBUG']
23
+ @logger.level = Logger::DEBUG
24
+ else
25
+ @logger.level = Logger::INFO
26
+ end
27
+
21
28
  @logger.formatter = proc do |severity, datetime, progname, msg|
22
29
  "#{datetime} [cf_light_api:worker]: #{msg}\n"
23
30
  end
@@ -34,7 +41,7 @@ class CFLightAPIWorker
34
41
  if ENV['GRAPHITE_HOST'] or ENV['GRAPHITE_PORT']
35
42
  ['GRAPHITE_HOST', 'GRAPHITE_PORT', 'CF_ENV_NAME'].each do |env|
36
43
  unless ENV[env]
37
- @logger.info "Error: please set the '#{env}' environment variable to enable exporting to Graphite."
44
+ @logger.info "Error: please also set the '#{env}' environment variable to enable exporting to Graphite."
38
45
  exit 1
39
46
  end
40
47
  end
@@ -61,30 +68,43 @@ class CFLightAPIWorker
61
68
  @scheduler.every update_interval, :first_in => '5s', :overlap => false, :timeout => update_timeout do
62
69
  update_cf_data
63
70
  end
64
-
65
- end
66
-
67
- def formatted_instance_stats_for_app app
68
- instances = cf_rest("/v2/apps/#{app['metadata']['guid']}/stats")[0]
69
- raise "Unable to retrieve app instance stats: '#{instances['error_code']}'" if instances['error_code']
70
- instances.map{|key,value|value}
71
71
  end
72
72
 
73
73
  def cf_rest(path, method='GET')
74
- @logger.info "Making #{method} request for #{path}..."
74
+ @logger.debug "Making #{method} request for #{path}..."
75
75
 
76
76
  resources = []
77
- options = {:accept => :json}
78
- response = @cf_client.base.rest_client.request(method, path, options)[1][:body]
77
+ options = {:accept => :json}
78
+ response = @cf_client.base.rest_client.request(method, path, options)[1][:body]
79
79
 
80
80
  begin
81
81
  response = JSON.parse(response)
82
+ if response['error_code']
83
+ raise CFResponseError.new("Code #{response['code']}, #{response['error_code']} - #{response['description']}")
84
+ end
85
+
82
86
  rescue Rufus::Scheduler::TimeoutError => e
83
87
  raise e
88
+ rescue JSON::ParserError => e
89
+ @logger.error "Error parsing JSON response from #{method} #{path}: #{e.message}"
90
+ @logger.trace e.backtrace
91
+ @logger.trace response
92
+ raise e
93
+ rescue CFoundry => e
94
+ @logger.error "CFoundry error making #{method} #{path}: #{e.message}"
95
+ @logger.trace e.backtrace
96
+ @logger.trace response
97
+ raise e
98
+ rescue CFResponseError => e
99
+ @logger.error "CF API returned a response with an error document for #{method} #{path}: #{e.message}"
100
+ @logger.trace e.backtrace
101
+ @logger.trace response
102
+ raise e
84
103
  rescue StandardError => e
85
- @logger.info "Error parsing JSON response from #{method} request for #{path}: #{e.message}"
86
- @logger.error e.backtrace
87
- raise "Invalid JSON response from CF for #{method} #{path}"
104
+ @logger.error "General error making #{method} #{path}: #{e.message}"
105
+ @logger.trace e.backtrace
106
+ @logger.trace response
107
+ raise e
88
108
  end
89
109
 
90
110
  # Some endpoints return a 'resources' array, others are flat, depending on the path.
@@ -111,33 +131,36 @@ class CFLightAPIWorker
111
131
 
112
132
  instance_stats.each_with_index do |instance_data, index|
113
133
  graphite_base_key = "cf_apps.#{ENV['CF_ENV_NAME']}.#{org}.#{space}.#{sanitised_app_name}.#{index}"
114
- @logger.info " Exporting app instance \##{index} usage statistics to Graphite, path '#{graphite_base_key}'"
134
+ @logger.debug " Exporting app instance \##{index} usage statistics to Graphite, path '#{graphite_base_key}'"
115
135
 
116
136
  # Quota data
117
137
  ['mem_quota', 'disk_quota'].each do |key|
118
- @graphite.metrics "#{graphite_base_key}.#{key}" => instance_data['stats'][key]
138
+ @logger.trace "#{graphite_base_key}.#{key} => #{instance_data['stats'][key]}"
139
+ # @graphite.metrics "#{graphite_base_key}.#{key}" => instance_data['stats'][key]
119
140
  end
120
141
 
121
142
  # Usage data
122
143
  ['mem', 'disk', 'cpu'].each do |key|
123
- @graphite.metrics "#{graphite_base_key}.#{key}" => instance_data['stats']['usage'][key]
144
+ @logger.trace "#{graphite_base_key}.#{key} => #{instance_data['stats']['usage'][key]}"
145
+ # @graphite.metrics "#{graphite_base_key}.#{key}" => instance_data['stats']['usage'][key]
124
146
  end
125
147
  end
126
148
  end
127
149
 
128
150
  def send_org_quota_data_to_graphite(org_name, quota)
129
151
  graphite_base_key = "cf_orgs.#{ENV['CF_ENV_NAME']}.#{org_name}"
130
- @logger.info " Exporting org quota statistics to Graphite, path '#{graphite_base_key}'"
152
+ @logger.debug " Exporting org quota statistics to Graphite, path '#{graphite_base_key}'"
131
153
 
132
154
  quota.keys.each do |key|
133
- @graphite.metrics "#{graphite_base_key}.quota.#{key}" => quota[key]
155
+ @logger.trace "#{graphite_base_key}.quota.#{key} => #{quota[key]}"
156
+ # @graphite.metrics "#{graphite_base_key}.quota.#{key}" => quota[key]
134
157
  end
135
158
  end
136
159
 
137
160
  def send_cf_light_api_update_time_to_graphite seconds
138
161
  graphite_key = "cf_light_api.#{ENV['CF_ENV_NAME']}.update_duration"
139
- @logger.info "Exporting CF Light API update time to Graphite, path '#{graphite_key}'=>'#{seconds.round}'"
140
- @graphite.metrics "#{graphite_key}" => seconds.round
162
+ @logger.info "Exporting CF Light API update time to Graphite, path #{graphite_key} => #{seconds.round}"
163
+ # @graphite.metrics "#{graphite_key}" => seconds.round
141
164
  end
142
165
 
143
166
  def put_in_redis(key, data)
@@ -151,28 +174,62 @@ class CFLightAPIWorker
151
174
  format("%02d hrs, %02d mins, %02d secs", hours, minutes, seconds)
152
175
  end
153
176
 
177
+ def update_domains
178
+ @domains = cf_rest('/v2/domains?results-per-page=100')
179
+ end
180
+
181
+ def find_domain_for_route route
182
+ return @domains.find{|a_domain| a_domain['metadata']['guid'] == route['entity']['domain_guid']}
183
+ end
184
+
154
185
  def format_routes_for_app app
155
- routes = cf_rest app['entity']['routes_url']
186
+ # The app object passed in here should contain a "routes" attribute, fetched as part of the original request to CF (with inline-relation gathering enabled)
187
+ # and it will look something like this:
188
+ # "routes"=>
189
+ # [{"metadata"=>{"guid"=>"afea5690-fb93-451a-9610-2d524d36e35f", "url"=>"/v2/routes/afea5690-fb93-451a-9610-2d524d36e35f", "created_at"=>"2015-03-11T12:20:22Z", "updated_at"=>"2015-03-11T12:20:22Z"},
190
+ # "entity"=>
191
+ # {"host"=>"hostname_here",
192
+ # "path"=>"",
193
+ # "domain_guid"=>"f13e6864-537e-41bb-b46c-f3810dbf7c84",
194
+ # "space_guid"=>"c0af44b8-8b51-4db5-927e-ccad2e6dab54",
195
+ # "service_instance_guid"=>nil,
196
+ # "port"=>nil,
197
+ # "domain_url"=>"/v2/shared_domains/f13e6864-537e-41bb-b46c-f3810dbf7c84",
198
+ # "space_url"=>"/v2/spaces/c0af44b8-8b51-4db5-927e-ccad2e6dab54",
199
+ # "apps_url"=>"/v2/routes/afea5690-fb93-451a-9610-2d524d36e35f/apps",
200
+ # "route_mappings_url"=>"/v2/routes/afea5690-fb93-451a-9610-2d524d36e35f/route_mappings"}},
201
+ # If we don't receive that child attribute, (perhaps the app was being staged or didn't have any routes yet) we make another request to CF to try
202
+ # and fetch them before giving up and just returning an empty array.
203
+
204
+ routes = []
205
+ if app['entity']['routes'] == nil
206
+ # We have no routes data inlined with the app entity, so let's try to retrieve them directly from CF
207
+ routes = cf_rest(app['entity']['routes_url'])
208
+ else
209
+ # Routes were already retrieved as an inline-relation, so just use those...
210
+ routes = app['entity']['routes']
211
+ end
212
+
156
213
  routes.collect do |route|
157
214
  host = route['entity']['host']
158
215
  path = route['entity']['path']
159
216
 
160
- domain = ''
161
- begin
162
- domain = @domains.find{|a_domain| a_domain['metadata']['guid'] == route['entity']['domain_guid']}
163
- domain = domain['entity']['name']
164
- rescue Rufus::Scheduler::TimeoutError => e
165
- raise e
166
- rescue StandardError => e
167
- raise "Unable to determine domain for route #{route['metadata']['url']}"
217
+ domain = find_domain_for_route(route)
218
+ if domain == nil
219
+ # The domain doesn't exist, this could be due to a race condition, so let's update the list and try again
220
+ update_domains()
221
+ domain = find_domain_for_route(route)
222
+ if domain == nil
223
+ # If we can't determine the domain associated with this route, raise an error as we can't guarantee the state is correct here,
224
+ # it shouldn't be possible to get a route back from CF with a domain GUID that doesn't exist, as that route would be invalid.
225
+ raise "Unable to find domain #{route['entity']['domain_guid']} for route #{route['metadata']['guid']}."
226
+ end
168
227
  end
169
-
170
- "#{host}.#{domain}#{path}"
228
+ "#{host}.#{domain['entity']['name']}#{path}"
171
229
  end
172
230
  end
173
231
 
174
232
  def filtered_environment_variables env_vars
175
-
176
233
  if ENVIRONMENT_VARIABLES_WHITELIST.any?
177
234
  return ENVIRONMENT_VARIABLES_WHITELIST.inject({}) do |filtered, key|
178
235
  filtered[key] = env_vars[key] if env_vars[key]
@@ -182,7 +239,49 @@ class CFLightAPIWorker
182
239
  else
183
240
  return env_vars
184
241
  end
242
+ end
243
+
244
+ def format_orgs orgs
245
+ return orgs.map do |org|
246
+ quota = @quotas.find{|a_quota| a_quota['metadata']['guid'] == org['entity']['quota_definition_guid']}
185
247
 
248
+ quota = {
249
+ :total_services => quota['entity']['total_services'],
250
+ :total_routes => quota['entity']['total_routes'],
251
+ :memory_limit => quota['entity']['memory_limit'] * 1024 * 1024
252
+ }
253
+
254
+ send_org_quota_data_to_graphite(org['entity']['name'], quota) if @graphite
255
+
256
+ {
257
+ :guid => org['metadata']['guid'],
258
+ :name => org['entity']['name'],
259
+ :quota => quota
260
+ }
261
+ end
262
+ end
263
+
264
+ def get_v1_base_data app
265
+ # Format the app data in the expected format for the /v1/apps endpoint, to remain compatible.
266
+
267
+ # Find the org for this app, using the org GUID from the space. Relationship: Apps belong to spaces, and spaces belong to orgs.
268
+ space = @spaces.find{|a_space| a_space['metadata']['guid'] == app['entity']['space_guid']}
269
+ org = @orgs.find{|an_org| an_org['metadata']['guid'] == space['entity']['organization_guid']}
270
+
271
+ {
272
+ :buildpack => app['entity']['buildpack'],
273
+ :data_from => Time.now.to_i,
274
+ :diego => app['entity']['diego'],
275
+ :docker => app['entity']['docker_image'] ? true : false,
276
+ :docker_image => app['entity']['docker_image'],
277
+ :guid => app['metadata']['guid'],
278
+ :last_uploaded => app['metadata']['updated_at'] ? DateTime.parse(app['metadata']['updated_at']).strftime('%Y-%m-%d %T %z') : nil,
279
+ :name => app['entity']['name'],
280
+ :org => org['entity']['name'],
281
+ :space => space['entity']['name'],
282
+ :stack => app['entity']['stack']['entity']['name'],
283
+ :state => app['entity']['state']
284
+ }
186
285
  end
187
286
 
188
287
  def update_cf_data
@@ -193,115 +292,113 @@ class CFLightAPIWorker
193
292
  @lock_manager.lock("#{ENV['REDIS_KEY_PREFIX']}:lock", 5*60*1000) do |lock|
194
293
  if lock
195
294
  start_time = Time.now
196
-
197
295
  @logger.info "Updating data..."
198
-
199
296
  @cf_client = get_client() # Ensure we have a fresh auth token...
200
297
 
201
- @apps = cf_rest('/v2/apps?results-per-page=100')
202
- @orgs = cf_rest('/v2/organizations?results-per-page=100')
203
- @quotas = cf_rest('/v2/quota_definitions?results-per-page=100')
298
+ @cf_info = cf_rest('/v2/info').first
299
+
300
+ @apps = cf_rest('/v2/apps?results-per-page=100&inline-relations-depth=1&include-relations=routes,stack')
204
301
  @spaces = cf_rest('/v2/spaces?results-per-page=100')
205
- @stacks = cf_rest('/v2/stacks?results-per-page=100')
206
- @domains = cf_rest('/v2/domains?results-per-page=100')
207
- cf_info = cf_rest('/v2/info').first
208
-
209
- formatted_orgs = @orgs.map do |org|
210
- quota = @quotas.find{|a_quota| a_quota['metadata']['guid'] == org['entity']['quota_definition_guid']}
211
-
212
- quota = {
213
- :total_services => quota['entity']['total_services'],
214
- :total_routes => quota['entity']['total_routes'],
215
- :memory_limit => quota['entity']['memory_limit'] * 1024 * 1024
216
- }
217
-
218
- send_org_quota_data_to_graphite(org['entity']['name'], quota) if @graphite
219
-
220
- {
221
- :guid => org['metadata']['guid'],
222
- :name => org['entity']['name'],
223
- :quota => quota
224
- }
225
- end
226
302
 
227
- formatted_apps = Parallel.map(@apps, :in_threads => @update_threads) do |app|
228
- # TODO: This is a bit repetative, could maybe improve?
229
- space = @spaces.find{|a_space| a_space['metadata']['guid'] == app['entity']['space_guid']}
230
- org = @orgs.find{|an_org| an_org['metadata']['guid'] == space['entity']['organization_guid']}
231
- stack = @stacks.find{|a_stack| a_stack['metadata']['guid'] == app['entity']['stack_guid']}
232
-
233
- running = (app['entity']['state'] == "STARTED")
234
-
235
- base_data = {
236
- :buildpack => app['entity']['buildpack'],
237
- :data_from => Time.now.to_i,
238
- :diego => app['entity']['diego'],
239
- :docker => app['entity']['docker_image'] ? true : false,
240
- :docker_image => app['entity']['docker_image'],
241
- :guid => app['metadata']['guid'],
242
- :last_uploaded => app['metadata']['updated_at'] ? DateTime.parse(app['metadata']['updated_at']).strftime('%Y-%m-%d %T %z') : nil,
243
- :name => app['entity']['name'],
244
- :org => org['entity']['name'],
245
- :space => space['entity']['name'],
246
- :stack => stack['entity']['name'],
247
- :state => app['entity']['state']
248
- }
249
-
250
- if ENV['EXPOSE_ENVIRONMENT_VARIABLES'] == 'true' then
251
- base_data[:environment_variables] = filtered_environment_variables( app['entity']['environment_json'] )
252
- end
303
+ update_domains() # Sets @domain by hitting the CF API
253
304
 
254
- # Add additional data, such as instance usage statistics - but this is only possible if the instances are running.
255
- additional_data = {}
305
+ # Orgs
306
+ @orgs = cf_rest('/v2/organizations?results-per-page=100')
307
+ @quotas = cf_rest('/v2/quota_definitions?results-per-page=100')
308
+ formatted_orgs = format_orgs @orgs
256
309
 
310
+ v1_data = []
311
+ v2_data = []
312
+
313
+ Parallel.each(@apps, :in_threads => @update_threads) do |app|
257
314
  begin
258
- instance_stats = []
259
- if running
260
- instance_stats = formatted_instance_stats_for_app(app)
261
- running_instances = instance_stats.select{|instance| instance['stats']['uris'] if instance['state'] == 'RUNNING'}
262
- raise "There are no running instances of this app." if running_instances.empty?
263
-
264
- if @graphite
265
- send_instance_usage_data_to_graphite(instance_stats, org['entity']['name'], space['entity']['name'], app['entity']['name'])
266
- end
315
+ # Formats the base data compatible with the v1 endpoint
316
+ v1_document = get_v1_base_data(app)
317
+
318
+ # New format base data for the v2 endpoint
319
+ v2_document = app['entity'].dup
320
+ v2_document['environment_json'] = {} # The environment JSON will have been duplicated from the app entity, so we need to blank it here, as it will be re-populated later if EXPOSE_ENVIRONMENT_VARIABLES is true.
321
+ v2_document['created_at'] = app['metadata']['created_at']
322
+ v2_document['updated_at'] = app['metadata']['updated_at']
323
+ v2_document['guid'] = app['metadata']['guid']
324
+ v2_document['instances'] = []
325
+ v2_document['routes'] = []
326
+ v2_document['meta'] = { 'error' => false }
327
+
328
+ # Add space, stack and org names as a top level string attribute for ease of use:
329
+ v2_document['stack'] = app['entity']['stack']['entity']['name']
330
+
331
+ # Get the org name from the app's space - relationship: an app belongs to a space, and a space belongs to an org.
332
+ space = @spaces.find{|a_space| a_space['metadata']['guid'] == app['entity']['space_guid']}
333
+ org = @orgs.find{|an_org| an_org['metadata']['guid'] == space['entity']['organization_guid']}
334
+
335
+ v2_document['space'] = space['entity']['name']
336
+ v1_document['org'] = org['entity']['name']
337
+ v2_document['org'] = org['entity']['name']
338
+
339
+ # Gather and filter environment variable JSON if the feature is enabled:
340
+ if ENV['EXPOSE_ENVIRONMENT_VARIABLES'] == 'true' then
341
+ env_vars = filtered_environment_variables( app['entity']['environment_json'] )
342
+ v1_document['environment_variables'] = env_vars
343
+ v2_document['environment_json'] = env_vars
267
344
  end
268
345
 
269
346
  routes = format_routes_for_app(app)
347
+ v1_document['routes'] = routes
348
+ v2_document['routes'] = routes
349
+
350
+ response = cf_rest("/v2/apps/#{app['metadata']['guid']}/stats")
351
+ instances = response.first.map{|key,value|value}
352
+ v1_document['instances'] = instances
353
+ v2_document['instances'] = instances
354
+
355
+ running = false
356
+ if instances.any?
357
+ if instances.select{|instance| instance['state'] == 'RUNNING'}.any?
358
+ running = true
359
+ end
360
+ end
361
+ v1_document['running'] = running
362
+ v2_document['running'] = running
270
363
 
271
- additional_data = {
272
- :running => running,
273
- :instances => instance_stats,
274
- :routes => routes,
275
- :error => nil
276
- }
364
+ if @graphite
365
+ send_instance_usage_data_to_graphite(instances, org['entity']['name'], app['entity']['space']['entity']['name'], app['entity']['name'])
366
+ end
277
367
 
278
368
  rescue Rufus::Scheduler::TimeoutError => e
279
369
  raise e
280
- rescue StandardError => e
281
- # Most exceptions here will be caused by the app or one of the instances being in a non-standard state,
282
- # for example, trying to query an app which was present when the worker began updating, but was stopped
283
- # before we reached this section, so we just catch all exceptions, log the reason and move on.
284
- @logger.info " #{org['entity']['name']} #{space['entity']['name']}: '#{app['entity']['name']}' error: #{e.message}"
285
- @logger.error e.backtrace
286
- additional_data = {
287
- :running => 'error',
288
- :instances => [],
289
- :routes => [],
290
- :error => e.message
291
- }
370
+ rescue CFoundry, CFResponseError, StandardError => e
371
+ v1_document['running'] = "error"
372
+ v1_document['error'] = "#{e.message}"
373
+
374
+ v2_document['meta'] = {}
375
+ v2_document['meta']['error'] = true
376
+ v2_document['meta']['type'] = e.class
377
+ v2_document['meta']['message'] = e.message
378
+ v2_document['meta']['backtrace'] = e.backtrace
292
379
  end
293
380
 
294
- base_data.merge additional_data
381
+ v1_data << v1_document
382
+ v2_data << v2_document
383
+ end
384
+
385
+ # Sanity check - do we have the expected quantity of data? This shouldn't happen as the `parallel` gem should handle
386
+ # sharing and modifying variables for us when using threads.
387
+ if @apps.count != v1_data.count or @apps.count != v2_data.count
388
+ raise "V1 and V2 app counts don't match after processing!"
295
389
  end
296
390
 
297
- put_in_redis "#{ENV['REDIS_KEY_PREFIX']}:info", cf_info
391
+ put_in_redis "#{ENV['REDIS_KEY_PREFIX']}:info", @cf_info
298
392
  put_in_redis "#{ENV['REDIS_KEY_PREFIX']}:orgs", formatted_orgs
299
- put_in_redis "#{ENV['REDIS_KEY_PREFIX']}:apps", formatted_apps
393
+ put_in_redis "#{ENV['REDIS_KEY_PREFIX']}:apps", v1_data
394
+ put_in_redis "#{ENV['REDIS_KEY_PREFIX']}:apps:v2", v2_data
395
+
300
396
  put_in_redis "#{ENV['REDIS_KEY_PREFIX']}:last_updated", {:last_updated => Time.now}
301
397
 
302
398
  elapsed_seconds = Time.now.to_f - start_time.to_f
303
- @logger.info "Update completed in #{format_duration(elapsed_seconds)}..."
399
+
304
400
  send_cf_light_api_update_time_to_graphite(elapsed_seconds) if @graphite
401
+ @logger.info "Update completed in #{format_duration(elapsed_seconds)}..."
305
402
 
306
403
  @lock_manager.unlock(lock)
307
404
  @cf_client.logout
@@ -310,9 +407,13 @@ class CFLightAPIWorker
310
407
  end
311
408
  end
312
409
  rescue Rufus::Scheduler::TimeoutError
410
+ Parallel::Kill
411
+ @cf_client.logout
313
412
  @logger.info 'Data update took too long and was aborted, waiting for the lock to expire before trying again...'
314
413
  send_cf_light_api_update_time_to_graphite(0) if @graphite
315
- @cf_client.logout
414
+ rescue StandardError => e
415
+ @logger.info "Unable to complete update due to #{e.class}: #{e.message}"
416
+ @logger.error e.backtrace
316
417
  end
317
418
  end
318
419
 
@@ -21,6 +21,17 @@ module Sinatra
21
21
  return all_apps.to_json
22
22
  end
23
23
 
24
+ app.get '/v2/apps/?:org?' do
25
+ content_type :json
26
+ all_apps = JSON.parse(REDIS.get("#{ENV['REDIS_KEY_PREFIX']}:apps:v2"))
27
+
28
+ if params[:org]
29
+ return all_apps.select{|an_app| an_app['org'] == params[:org]}.to_json
30
+ end
31
+
32
+ return all_apps.to_json
33
+ end
34
+
24
35
  app.get '/v1/orgs/?:guid?' do
25
36
  content_type :json
26
37
  all_orgs = JSON.parse(REDIS.get("#{ENV['REDIS_KEY_PREFIX']}:orgs"))
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cf_light_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.0
4
+ version: 3.0.0.pre1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Springer Platform Engineering
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-04 00:00:00.000000000 Z
11
+ date: 2018-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cfoundry
@@ -130,6 +130,7 @@ executables:
130
130
  extensions: []
131
131
  extra_rdoc_files: []
132
132
  files:
133
+ - "./lib/cf_light_api/cf_response_error.rb"
133
134
  - "./lib/cf_light_api/redis.rb"
134
135
  - "./lib/cf_light_api/worker.rb"
135
136
  - "./lib/sinatra/cf_light_api.rb"
@@ -149,9 +150,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
149
150
  version: '0'
150
151
  required_rubygems_version: !ruby/object:Gem::Requirement
151
152
  requirements:
152
- - - ">="
153
+ - - ">"
153
154
  - !ruby/object:Gem::Version
154
- version: '0'
155
+ version: 1.3.1
155
156
  requirements: []
156
157
  rubyforge_project:
157
158
  rubygems_version: 2.5.1