cf_light_api 2.1.0 → 2.2.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|