cf_light_api 2.6.0 → 3.0.0.pre1

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