cf_light_api 2.1.0 → 2.2.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 +4 -4
- data/bin/cf_light_api +10 -0
- data/lib/cf_light_api/worker.rb +223 -128
- data/lib/sinatra/cf_light_api.rb +6 -0
- metadata +18 -5
- data/lib/cf_light_api/lib.rb +0 -73
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2285895d68ee80832326dad1a0e06ceb60630145
|
4
|
+
data.tar.gz: 6dafdfd47ebf9583f97eb8f8cfa0e2a1a5c8a891
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d45598db25a9a7b54729a3b5caa0364b5c8cb21819549c1031f5ad042180fe0ae3e2211cda599f8cde9d9bfcc4fa22babfa56291d7d5f3c8cd1c04fe1e9a598
|
7
|
+
data.tar.gz: f1ba0ad880904e5c2bc36a2927468376ca6cd1c68169dd8ff09bc6e2aa10585ebd54b152fb807464353903de1335e9f647faa822bb0db307a90f9cb61479bcbe
|
data/bin/cf_light_api
CHANGED
@@ -4,6 +4,16 @@ $stdout.sync = true
|
|
4
4
|
|
5
5
|
puts '[cf_light_api] Starting CF Light API and worker...'
|
6
6
|
|
7
|
+
# If either of the minimum required New Relic settings are present, verify that they are both set, or exit with an error.
|
8
|
+
if ENV['NEW_RELIC_APP_NAME'] or ENV['NEW_RELIC_LICENSE_KEY']
|
9
|
+
['NEW_RELIC_APP_NAME', 'NEW_RELIC_LICENSE_KEY'].each do |env|
|
10
|
+
unless ENV[env]
|
11
|
+
puts "[cf_light_api] Error: please set the '#{env}' environment variable to enable New Relic integration."
|
12
|
+
exit 1
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
7
17
|
require_relative '../lib/cf_light_api/redis.rb'
|
8
18
|
require_relative '../lib/cf_light_api/worker.rb'
|
9
19
|
|
data/lib/cf_light_api/worker.rb
CHANGED
@@ -6,154 +6,249 @@ require 'logger'
|
|
6
6
|
require 'graphite-api'
|
7
7
|
require 'date'
|
8
8
|
|
9
|
-
|
9
|
+
class CFLightAPIWorker
|
10
|
+
if ENV['NEW_RELIC_LICENSE_KEY']
|
11
|
+
require 'newrelic_rpm'
|
12
|
+
include NewRelic::Agent::Instrumentation::ControllerInstrumentation
|
13
|
+
include NewRelic::Agent::MethodTracer
|
14
|
+
end
|
10
15
|
|
11
|
-
|
12
|
-
@logger
|
13
|
-
|
14
|
-
|
16
|
+
def initialize
|
17
|
+
@logger = Logger.new(STDOUT)
|
18
|
+
@logger.formatter = proc do |severity, datetime, progname, msg|
|
19
|
+
"#{datetime} [cf_light_api:worker]: #{msg}\n"
|
20
|
+
end
|
21
|
+
|
22
|
+
['CF_API', 'CF_USER', 'CF_PASSWORD'].each do |env|
|
23
|
+
unless ENV[env]
|
24
|
+
@logger.info "Error: please set the '#{env}' environment variable."
|
25
|
+
exit 1
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# If either of the Graphite settings are set, verify that they are both set, or exit with an error.
|
30
|
+
if ENV['GRAPHITE_HOST'] or ENV['GRAPHITE_PORT']
|
31
|
+
['GRAPHITE_HOST', 'GRAPHITE_PORT'].each do |env|
|
32
|
+
unless ENV[env]
|
33
|
+
@logger.info "Error: please set the '#{env}' environment variable to enable exporting to Graphite."
|
34
|
+
exit 1
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
update_interval = (ENV['UPDATE_INTERVAL'] || '5m').to_s # If you change the default '5m' here, also remember to change the default age validity in sinatra/cf_light_api.rb:31
|
40
|
+
update_timeout = (ENV['UPDATE_TIMEOUT'] || '5m').to_s
|
41
|
+
|
42
|
+
@lock_manager = Redlock::Client.new([ENV['REDIS_URI']])
|
43
|
+
@scheduler = Rufus::Scheduler.new
|
44
|
+
|
45
|
+
@logger.info "Update interval: '#{@update_interval}'"
|
46
|
+
@logger.info "Update timeout: '#{@update_timeout}'"
|
47
|
+
|
48
|
+
if ENV['GRAPHITE_HOST'] and ENV['GRAPHITE_PORT']
|
49
|
+
@logger.info "Graphite server: #{ENV['GRAPHITE_HOST']}:#{ENV['GRAPHITE_PORT']}"
|
50
|
+
else
|
51
|
+
@logger.info 'Graphite server: Disabled'
|
52
|
+
end
|
53
|
+
|
54
|
+
@scheduler.every update_interval, :first_in => '5s', :overlap => false, :timeout => update_timeout do
|
55
|
+
update_cf_data
|
56
|
+
end
|
15
57
|
|
16
|
-
['CF_API', 'CF_USER', 'CF_PASSWORD'].each do |env|
|
17
|
-
unless ENV[env]
|
18
|
-
@logger.info "Error: please set the '#{env}' environment variable."
|
19
|
-
exit 1
|
20
58
|
end
|
21
|
-
end
|
22
59
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
60
|
+
def formatted_instance_stats_for_app app
|
61
|
+
instances = cf_rest("/v2/apps/#{app['metadata']['guid']}/stats")[0]
|
62
|
+
raise "Unable to retrieve app instance stats: '#{instances['error_code']}'" if instances['error_code']
|
63
|
+
instances.map{|key,value|value}
|
64
|
+
end
|
65
|
+
|
66
|
+
def cf_rest(path, method='GET')
|
67
|
+
@logger.info "Making #{method} request for #{path}..."
|
68
|
+
|
69
|
+
resources = []
|
70
|
+
response = JSON.parse(@cf_client.base.rest_client.request(method, path)[1][:body])
|
71
|
+
|
72
|
+
# Some endpoints return a 'resources' array, others are flat, depending on the path.
|
73
|
+
if response['resources']
|
74
|
+
resources << response['resources']
|
75
|
+
else
|
76
|
+
resources << response
|
29
77
|
end
|
78
|
+
|
79
|
+
# Handle the pagination by recursing over myself until we get a response which doesn't contain a 'next_url'
|
80
|
+
# at which point all the resources are returned up the stack and flattened.
|
81
|
+
resources << cf_rest(response['next_url'], method) unless response['next_url'] == nil
|
82
|
+
resources.flatten
|
30
83
|
end
|
31
|
-
end
|
32
84
|
|
33
|
-
|
34
|
-
|
85
|
+
def get_client(cf_api=ENV['CF_API'], cf_user=ENV['CF_USER'], cf_password=ENV['CF_PASSWORD'])
|
86
|
+
client = CFoundry::Client.get(cf_api)
|
87
|
+
client.login({:username => cf_user, :password => cf_password})
|
88
|
+
client
|
89
|
+
end
|
35
90
|
|
36
|
-
|
37
|
-
|
91
|
+
def send_instance_usage_data_to_graphite(instance_stats, org, space, app_name)
|
92
|
+
app_name.gsub! ".", "_" # Some apps have dots in the app name
|
38
93
|
|
39
|
-
|
40
|
-
|
94
|
+
instance_stats.each_with_index do |instance_data, index|
|
95
|
+
graphite_base_key = "cf_apps.#{org}.#{space}.#{app_name}.#{index}"
|
96
|
+
@logger.info " Exporting app instance \##{index} usage statistics to Graphite, path '#{graphite_base_key}'"
|
41
97
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
98
|
+
# Quota data
|
99
|
+
['mem_quota', 'disk_quota'].each do |key|
|
100
|
+
@graphite.metrics "#{graphite_base_key}.#{key}" => instance_data['stats'][key]
|
101
|
+
end
|
47
102
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
if lock
|
55
|
-
start_time = Time.now
|
56
|
-
|
57
|
-
@logger.info "Updating data..."
|
58
|
-
|
59
|
-
@cf_client = get_client() # Ensure we have a fresh auth token...
|
60
|
-
|
61
|
-
@apps = cf_rest('/v2/apps?results-per-page=100')
|
62
|
-
@orgs = cf_rest('/v2/organizations?results-per-page=100')
|
63
|
-
@quotas = cf_rest('/v2/quota_definitions?results-per-page=100')
|
64
|
-
@spaces = cf_rest('/v2/spaces?results-per-page=100')
|
65
|
-
@stacks = cf_rest('/v2/stacks?results-per-page=100')
|
66
|
-
@domains = cf_rest('/v2/domains?results-per-page=100')
|
67
|
-
|
68
|
-
formatted_orgs = @orgs.map do |org|
|
69
|
-
quota = @quotas.find{|a_quota| a_quota['metadata']['guid'] == org['entity']['quota_definition_guid']}
|
70
|
-
|
71
|
-
{
|
72
|
-
:guid => org['metadata']['guid'],
|
73
|
-
:name => org['entity']['name'],
|
74
|
-
:quota => {
|
75
|
-
:name => quota['entity']['name'],
|
76
|
-
:total_services => quota['entity']['total_services'],
|
77
|
-
:total_routes => quota['entity']['total_routes'],
|
78
|
-
:memory_limit => quota['entity']['memory_limit'] * 1024 * 1024
|
79
|
-
}
|
80
|
-
}
|
81
|
-
end
|
103
|
+
# Usage data
|
104
|
+
['mem', 'disk', 'cpu'].each do |key|
|
105
|
+
@graphite.metrics "#{graphite_base_key}.#{key}" => instance_data['stats']['usage'][key]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
82
109
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
org = @orgs.find{|an_org| an_org['metadata']['guid'] == space['entity']['organization_guid']}
|
87
|
-
stack = @stacks.find{|a_stack| a_stack['metadata']['guid'] == app['entity']['stack_guid']}
|
88
|
-
routes = format_routes_for_app(app)
|
89
|
-
|
90
|
-
running = (app['entity']['state'] == "STARTED")
|
91
|
-
|
92
|
-
base_data = {
|
93
|
-
:buildpack => app['entity']['buildpack'],
|
94
|
-
:data_from => Time.now.to_i,
|
95
|
-
:diego => app['entity']['diego'],
|
96
|
-
:docker => app['entity']['docker_image'] ? true : false,
|
97
|
-
:docker_image => app['entity']['docker_image'],
|
98
|
-
:guid => app['metadata']['guid'],
|
99
|
-
:last_uploaded => app['metadata']['updated_at'] ? DateTime.parse(app['metadata']['updated_at']).strftime('%Y-%m-%d %T %z') : nil,
|
100
|
-
:name => app['entity']['name'],
|
101
|
-
:org => org['entity']['name'],
|
102
|
-
:routes => routes,
|
103
|
-
:space => space['entity']['name'],
|
104
|
-
:stack => stack['entity']['name'],
|
105
|
-
:state => app['entity']['state']
|
106
|
-
}
|
107
|
-
|
108
|
-
# Add additional data, such as instance usage statistics - but this is only possible if the instances are running.
|
109
|
-
additional_data = {}
|
110
|
-
|
111
|
-
begin
|
112
|
-
instance_stats = []
|
113
|
-
if running
|
114
|
-
instance_stats = formatted_instance_stats_for_app(app)
|
115
|
-
running_instances = instance_stats.select{|instance| instance['stats']['uris'] if instance['state'] == 'RUNNING'}
|
116
|
-
raise "There are no running instances of this app." if running_instances.empty?
|
117
|
-
|
118
|
-
if @graphite
|
119
|
-
send_instance_usage_data_to_graphite(instance_stats, org['entity']['name'], space['entity']['name'], app['entity']['name'])
|
120
|
-
end
|
121
|
-
end
|
110
|
+
def put_in_redis(key, data)
|
111
|
+
REDIS.set key, data.to_json
|
112
|
+
end
|
122
113
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
114
|
+
def format_duration(elapsed_seconds)
|
115
|
+
seconds = elapsed_seconds % 60
|
116
|
+
minutes = (elapsed_seconds / 60) % 60
|
117
|
+
hours = elapsed_seconds / (60 * 60)
|
118
|
+
format("%02d hrs, %02d mins, %02d secs", hours, minutes, seconds)
|
119
|
+
end
|
120
|
+
|
121
|
+
def format_routes_for_app app
|
122
|
+
routes = cf_rest app['entity']['routes_url']
|
123
|
+
routes.collect do |route|
|
124
|
+
host = route['entity']['host']
|
125
|
+
path = route['entity']['path']
|
126
|
+
|
127
|
+
domain = @domains.find{|a_domain| a_domain['metadata']['guid'] == route['entity']['domain_guid']}
|
128
|
+
domain = domain['entity']['name']
|
129
|
+
|
130
|
+
"#{host}.#{domain}#{path}"
|
131
|
+
end
|
132
|
+
end
|
128
133
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
134
|
+
def update_cf_data
|
135
|
+
@cf_client = nil
|
136
|
+
@graphite = GraphiteAPI.new(graphite: "#{ENV['GRAPHITE_HOST']}:#{ENV['GRAPHITE_PORT']}") if ENV['GRAPHITE_HOST'] and ENV['GRAPHITE_PORT']
|
137
|
+
|
138
|
+
begin
|
139
|
+
@lock_manager.lock("#{ENV['REDIS_KEY_PREFIX']}:lock", 5*60*1000) do |lock|
|
140
|
+
if lock
|
141
|
+
start_time = Time.now
|
142
|
+
|
143
|
+
@logger.info "Updating data..."
|
144
|
+
|
145
|
+
@cf_client = get_client() # Ensure we have a fresh auth token...
|
146
|
+
|
147
|
+
@apps = cf_rest('/v2/apps?results-per-page=100')
|
148
|
+
@orgs = cf_rest('/v2/organizations?results-per-page=100')
|
149
|
+
@quotas = cf_rest('/v2/quota_definitions?results-per-page=100')
|
150
|
+
@spaces = cf_rest('/v2/spaces?results-per-page=100')
|
151
|
+
@stacks = cf_rest('/v2/stacks?results-per-page=100')
|
152
|
+
@domains = cf_rest('/v2/domains?results-per-page=100')
|
153
|
+
|
154
|
+
formatted_orgs = @orgs.map do |org|
|
155
|
+
quota = @quotas.find{|a_quota| a_quota['metadata']['guid'] == org['entity']['quota_definition_guid']}
|
156
|
+
|
157
|
+
{
|
158
|
+
:guid => org['metadata']['guid'],
|
159
|
+
:name => org['entity']['name'],
|
160
|
+
:quota => {
|
161
|
+
:name => quota['entity']['name'],
|
162
|
+
:total_services => quota['entity']['total_services'],
|
163
|
+
:total_routes => quota['entity']['total_routes'],
|
164
|
+
:memory_limit => quota['entity']['memory_limit'] * 1024 * 1024
|
165
|
+
}
|
138
166
|
}
|
139
167
|
end
|
140
168
|
|
141
|
-
|
142
|
-
|
169
|
+
formatted_apps = @apps.map do |app|
|
170
|
+
# TODO: This is a bit repetative, could maybe improve?
|
171
|
+
space = @spaces.find{|a_space| a_space['metadata']['guid'] == app['entity']['space_guid']}
|
172
|
+
org = @orgs.find{|an_org| an_org['metadata']['guid'] == space['entity']['organization_guid']}
|
173
|
+
stack = @stacks.find{|a_stack| a_stack['metadata']['guid'] == app['entity']['stack_guid']}
|
174
|
+
routes = format_routes_for_app(app)
|
175
|
+
|
176
|
+
running = (app['entity']['state'] == "STARTED")
|
177
|
+
|
178
|
+
base_data = {
|
179
|
+
:buildpack => app['entity']['buildpack'],
|
180
|
+
:data_from => Time.now.to_i,
|
181
|
+
:diego => app['entity']['diego'],
|
182
|
+
:docker => app['entity']['docker_image'] ? true : false,
|
183
|
+
:docker_image => app['entity']['docker_image'],
|
184
|
+
:guid => app['metadata']['guid'],
|
185
|
+
:last_uploaded => app['metadata']['updated_at'] ? DateTime.parse(app['metadata']['updated_at']).strftime('%Y-%m-%d %T %z') : nil,
|
186
|
+
:name => app['entity']['name'],
|
187
|
+
:org => org['entity']['name'],
|
188
|
+
:routes => routes,
|
189
|
+
:space => space['entity']['name'],
|
190
|
+
:stack => stack['entity']['name'],
|
191
|
+
:state => app['entity']['state']
|
192
|
+
}
|
193
|
+
|
194
|
+
# Add additional data, such as instance usage statistics - but this is only possible if the instances are running.
|
195
|
+
additional_data = {}
|
196
|
+
|
197
|
+
begin
|
198
|
+
instance_stats = []
|
199
|
+
if running
|
200
|
+
instance_stats = formatted_instance_stats_for_app(app)
|
201
|
+
running_instances = instance_stats.select{|instance| instance['stats']['uris'] if instance['state'] == 'RUNNING'}
|
202
|
+
raise "There are no running instances of this app." if running_instances.empty?
|
203
|
+
|
204
|
+
if @graphite
|
205
|
+
send_instance_usage_data_to_graphite(instance_stats, org['entity']['name'], space['entity']['name'], app['entity']['name'])
|
206
|
+
end
|
207
|
+
end
|
143
208
|
|
144
|
-
|
145
|
-
|
146
|
-
|
209
|
+
additional_data = {
|
210
|
+
:running => running,
|
211
|
+
:instances => instance_stats,
|
212
|
+
:error => nil
|
213
|
+
}
|
214
|
+
|
215
|
+
rescue => e
|
216
|
+
# Most exceptions here will be caused by the app or one of the instances being in a non-standard state,
|
217
|
+
# for example, trying to query an app which was present when the worker began updating, but was stopped
|
218
|
+
# before we reached this section, so we just catch all exceptions, log the reason and move on.
|
219
|
+
@logger.info " #{org['entity']['name']} #{space['entity']['name']}: '#{app['entity']['name']}' error: #{e.message}"
|
220
|
+
additional_data = {
|
221
|
+
:running => 'error',
|
222
|
+
:instances => [],
|
223
|
+
:error => e.message
|
224
|
+
}
|
225
|
+
end
|
226
|
+
|
227
|
+
base_data.merge additional_data
|
228
|
+
end
|
147
229
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
230
|
+
put_in_redis "#{ENV['REDIS_KEY_PREFIX']}:orgs", formatted_orgs
|
231
|
+
put_in_redis "#{ENV['REDIS_KEY_PREFIX']}:apps", formatted_apps
|
232
|
+
put_in_redis "#{ENV['REDIS_KEY_PREFIX']}:last_updated", {:last_updated => Time.now}
|
233
|
+
|
234
|
+
@logger.info "Update completed in #{format_duration(Time.now.to_f - start_time.to_f)}..."
|
235
|
+
@lock_manager.unlock(lock)
|
236
|
+
@cf_client.logout
|
237
|
+
else
|
238
|
+
@logger.info "Update already running in another instance!"
|
239
|
+
end
|
153
240
|
end
|
241
|
+
rescue Rufus::Scheduler::TimeoutError
|
242
|
+
@logger.info 'Data update took too long and was aborted, waiting for the lock to expire before trying again...'
|
243
|
+
@cf_client.logout
|
154
244
|
end
|
155
|
-
rescue Rufus::Scheduler::TimeoutError
|
156
|
-
@logger.info 'Data update took too long and was aborted, waiting for the lock to expire before trying again...'
|
157
|
-
@cf_client.logout
|
158
245
|
end
|
246
|
+
|
247
|
+
if ENV['NEW_RELIC_LICENSE_KEY']
|
248
|
+
add_transaction_tracer :update_cf_data, category: :task
|
249
|
+
add_method_tracer :update_cf_data
|
250
|
+
end
|
251
|
+
|
159
252
|
end
|
253
|
+
|
254
|
+
CFLightAPIWorker.new
|
data/lib/sinatra/cf_light_api.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
1
|
require 'json'
|
2
2
|
|
3
|
+
if ENV['NEW_RELIC_LICENSE_KEY']
|
4
|
+
require 'newrelic_rpm'
|
5
|
+
NewRelic::Agent.manual_start
|
6
|
+
end
|
7
|
+
|
3
8
|
module Sinatra
|
4
9
|
module CfLightAPI
|
5
10
|
|
6
11
|
def self.registered(app)
|
12
|
+
|
7
13
|
app.get '/v1/apps/?:org?' do
|
8
14
|
content_type :json
|
9
15
|
all_apps = JSON.parse(REDIS.get("#{ENV['REDIS_KEY_PREFIX']}:apps"))
|
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.
|
4
|
+
version: 2.2.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: 2016-
|
11
|
+
date: 2016-11-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cfoundry
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - ~>
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: 0.1.6
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: newrelic_rpm
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ~>
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 3.17.1
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 3.17.1
|
97
111
|
description: A super lightweight API for reading App and Org data from CloudFoundry,
|
98
112
|
cached in Redis.
|
99
113
|
email: ''
|
@@ -103,7 +117,6 @@ extensions: []
|
|
103
117
|
extra_rdoc_files: []
|
104
118
|
files:
|
105
119
|
- ./lib/sinatra/cf_light_api.rb
|
106
|
-
- ./lib/cf_light_api/lib.rb
|
107
120
|
- ./lib/cf_light_api/redis.rb
|
108
121
|
- ./lib/cf_light_api/worker.rb
|
109
122
|
- bin/cf_light_api
|
@@ -122,9 +135,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
122
135
|
version: '0'
|
123
136
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
124
137
|
requirements:
|
125
|
-
- - '
|
138
|
+
- - '>'
|
126
139
|
- !ruby/object:Gem::Version
|
127
|
-
version:
|
140
|
+
version: 1.3.1
|
128
141
|
requirements: []
|
129
142
|
rubyforge_project:
|
130
143
|
rubygems_version: 2.0.14
|
data/lib/cf_light_api/lib.rb
DELETED
@@ -1,73 +0,0 @@
|
|
1
|
-
def formatted_instance_stats_for_app app
|
2
|
-
instances = cf_rest("/v2/apps/#{app['metadata']['guid']}/stats")[0]
|
3
|
-
raise "Unable to retrieve app instance stats: '#{instances['error_code']}'" if instances['error_code']
|
4
|
-
instances.map{|key,value|value}
|
5
|
-
end
|
6
|
-
|
7
|
-
def cf_rest(path, method='GET')
|
8
|
-
@logger.info "Making #{method} request for #{path}..."
|
9
|
-
|
10
|
-
resources = []
|
11
|
-
response = JSON.parse(@cf_client.base.rest_client.request(method, path)[1][:body])
|
12
|
-
|
13
|
-
# Some endpoints return a 'resources' array, others are flat, depending on the path.
|
14
|
-
if response['resources']
|
15
|
-
resources << response['resources']
|
16
|
-
else
|
17
|
-
resources << response
|
18
|
-
end
|
19
|
-
|
20
|
-
# Handle the pagination by recursing over myself until we get a response which doesn't contain a 'next_url'
|
21
|
-
# at which point all the resources are returned up the stack and flattened.
|
22
|
-
resources << cf_rest(response['next_url'], method) unless response['next_url'] == nil
|
23
|
-
resources.flatten
|
24
|
-
end
|
25
|
-
|
26
|
-
def get_client(cf_api=ENV['CF_API'], cf_user=ENV['CF_USER'], cf_password=ENV['CF_PASSWORD'])
|
27
|
-
client = CFoundry::Client.get(cf_api)
|
28
|
-
client.login({:username => cf_user, :password => cf_password})
|
29
|
-
client
|
30
|
-
end
|
31
|
-
|
32
|
-
def send_instance_usage_data_to_graphite(instance_stats, org, space, app_name)
|
33
|
-
app_name.gsub! ".", "_" # Some apps have dots in the app name
|
34
|
-
|
35
|
-
instance_stats.each_with_index do |instance_data, index|
|
36
|
-
graphite_base_key = "cf_apps.#{org}.#{space}.#{app_name}.#{index}"
|
37
|
-
@logger.info " Exporting app instance \##{index} usage statistics to Graphite, path '#{graphite_base_key}'"
|
38
|
-
|
39
|
-
# Quota data
|
40
|
-
['mem_quota', 'disk_quota'].each do |key|
|
41
|
-
@graphite.metrics "#{graphite_base_key}.#{key}" => instance_data['stats'][key]
|
42
|
-
end
|
43
|
-
|
44
|
-
# Usage data
|
45
|
-
['mem', 'disk', 'cpu'].each do |key|
|
46
|
-
@graphite.metrics "#{graphite_base_key}.#{key}" => instance_data['stats']['usage'][key]
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def put_in_redis(key, data)
|
52
|
-
REDIS.set key, data.to_json
|
53
|
-
end
|
54
|
-
|
55
|
-
def format_duration(elapsed_seconds)
|
56
|
-
seconds = elapsed_seconds % 60
|
57
|
-
minutes = (elapsed_seconds / 60) % 60
|
58
|
-
hours = elapsed_seconds / (60 * 60)
|
59
|
-
format("%02d hrs, %02d mins, %02d secs", hours, minutes, seconds)
|
60
|
-
end
|
61
|
-
|
62
|
-
def format_routes_for_app app
|
63
|
-
routes = cf_rest app['entity']['routes_url']
|
64
|
-
routes.collect do |route|
|
65
|
-
host = route['entity']['host']
|
66
|
-
path = route['entity']['path']
|
67
|
-
|
68
|
-
domain = @domains.find{|a_domain| a_domain['metadata']['guid'] == route['entity']['domain_guid']}
|
69
|
-
domain = domain['entity']['name']
|
70
|
-
|
71
|
-
"#{host}.#{domain}#{path}"
|
72
|
-
end
|
73
|
-
end
|