cf_light_api 1.7.0 → 2.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 +4 -4
- data/lib/cf_light_api/worker.rb +212 -91
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bdbf36a622784f98ea2133973966ae40eb500572
|
4
|
+
data.tar.gz: 8b12c0cec0408a0f16d31392836eea9286f62fd7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d65857061da6b5b87dd19928b5386ef2d339649bae6989cec2a981607cc09d28b3f8be72a2d2c97039517a5151e53ec9e50a55e290618e4c9e918bb27eaeb12
|
7
|
+
data.tar.gz: c5f6a83db24dbe514f9ce1272824274ac052f71b4f1296462793b4925ad290053273be7e60b21a6715e3555cca98b58823607b9679a2e1b880bc2451dd77f6e3
|
data/lib/cf_light_api/worker.rb
CHANGED
@@ -31,36 +31,151 @@ scheduler = Rufus::Scheduler.new
|
|
31
31
|
@logger.info "Update timeout: '#{UPDATE_TIMEOUT}'"
|
32
32
|
@logger.info "Graphite server: #{ENV['GRAPHITE']}" if ENV['GRAPHITE']
|
33
33
|
|
34
|
+
#@domains = {}
|
35
|
+
# @domains = cf_rest('/v2/domains?results-per-page=100') # We're retrieving this from the app instance 'uris' key instead.
|
36
|
+
# @routes = cf_rest('/v2/routes?results-per-page=100')
|
37
|
+
|
38
|
+
# def formatted_routes_for_app app
|
39
|
+
# routes = cf_rest(app['entity']['routes_url'])
|
40
|
+
|
41
|
+
# routes.collect do |route|
|
42
|
+
# domain = @domains.find{|a_domain| a_domain['metadata']['guid'] == route['entity']['domain_guid']}['entity']['name']
|
43
|
+
# # Suffix the hostname with a period for concatenation, unless it's blank (which can happen for apex routes).
|
44
|
+
# host = route['entity']['host'] != '' ? "#{route['entity']['host']}." : ''
|
45
|
+
# path = route['entity']['path']
|
46
|
+
# "#{host}#{domain}#{path}"
|
47
|
+
# end
|
48
|
+
# end
|
49
|
+
|
50
|
+
def formatted_instance_stats_for_app app
|
51
|
+
instances = cf_rest("/v2/apps/#{app['metadata']['guid']}/stats")[0]
|
52
|
+
raise "Unable to retrieve app instance stats: '#{instances['error_code']}'" if instances['error_code']
|
53
|
+
instances.map{|key,value|value}
|
54
|
+
end
|
55
|
+
|
56
|
+
def cf_rest(path, method='GET')
|
57
|
+
@logger.info "Making #{method} request for #{path}..."
|
58
|
+
|
59
|
+
resources = []
|
60
|
+
response = JSON.parse(@cf_client.base.rest_client.request(method, path)[1][:body])
|
61
|
+
|
62
|
+
# Some endpoints return a 'resources' array, others are flat, depending on the path.
|
63
|
+
if response['resources']
|
64
|
+
resources << response['resources']
|
65
|
+
else
|
66
|
+
resources << response
|
67
|
+
end
|
68
|
+
|
69
|
+
# Handle the pagination by recursing over myself until we get a response which doesn't contain a 'next_url'
|
70
|
+
# at which point all the resources are returned up the stack and flattened.
|
71
|
+
resources << cf_rest(response['next_url'], method) unless response['next_url'] == nil
|
72
|
+
resources.flatten
|
73
|
+
end
|
74
|
+
|
34
75
|
scheduler.every UPDATE_INTERVAL, :first_in => '5s', :overlap => false, :timeout => UPDATE_TIMEOUT do
|
35
|
-
cf_client = nil
|
36
|
-
graphite = GraphiteAPI.new(graphite: ENV['GRAPHITE']) if ENV['GRAPHITE']
|
76
|
+
@cf_client = nil
|
77
|
+
# graphite = GraphiteAPI.new(graphite: ENV['GRAPHITE']) if ENV['GRAPHITE']
|
37
78
|
|
38
79
|
begin
|
39
80
|
lock_manager.lock("#{ENV['REDIS_KEY_PREFIX']}:lock", 5*60*1000) do |lock|
|
40
81
|
if lock
|
41
82
|
start_time = Time.now
|
42
83
|
|
43
|
-
@logger.info "Updating data
|
84
|
+
@logger.info "Updating data..."
|
85
|
+
|
86
|
+
@cf_client = get_client() # Ensure we have a fresh auth token...
|
87
|
+
|
88
|
+
@apps = cf_rest('/v2/apps?results-per-page=100')
|
89
|
+
@orgs = cf_rest('/v2/organizations?results-per-page=100')
|
90
|
+
@quotas = cf_rest('/v2/quota_definitions?results-per-page=100')
|
91
|
+
@spaces = cf_rest('/v2/spaces?results-per-page=100')
|
92
|
+
@stacks = cf_rest('/v2/stacks?results-per-page=100')
|
93
|
+
|
94
|
+
# org_data = get_org_data(@cf_client)
|
95
|
+
# app_data = get_app_data(@cf_client, graphite)
|
96
|
+
|
97
|
+
formatted_orgs = @orgs.map do |org|
|
98
|
+
quota = @quotas.find{|a_quota| a_quota['metadata']['guid'] == org['entity']['quota_definition_guid']}
|
99
|
+
|
100
|
+
{
|
101
|
+
:guid => org['metadata']['guid'],
|
102
|
+
:name => org['entity']['name'],
|
103
|
+
:quota => {
|
104
|
+
:name => quota['entity']['name'],
|
105
|
+
:total_services => quota['entity']['total_services'],
|
106
|
+
:total_routes => quota['entity']['total_routes'],
|
107
|
+
:memory_limit => quota['entity']['memory_limit'] * 1024 * 1024
|
108
|
+
}
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
formatted_apps = @apps.map do |app|
|
113
|
+
# TODO: This is a bit repetative, could improve.
|
114
|
+
space = @spaces.find{|a_space| a_space['metadata']['guid'] == app['entity']['space_guid']}
|
115
|
+
org = @orgs.find{|an_org| an_org['metadata']['guid'] == space['entity']['organization_guid']}
|
116
|
+
stack = @stacks.find{|a_stack| a_stack['metadata']['guid'] == app['entity']['stack_guid']}
|
117
|
+
|
118
|
+
running = (app['entity']['state'] == "STARTED")
|
44
119
|
|
45
|
-
|
120
|
+
base_data = {
|
121
|
+
:guid => app['metadata']['guid'],
|
122
|
+
:name => app['entity']['name'],
|
123
|
+
:org => org['entity']['name'],
|
124
|
+
:space => space['entity']['name'],
|
125
|
+
:stack => stack['entity']['name'],
|
126
|
+
:buildpack => app['entity']['buildpack'],
|
127
|
+
# This requires a call to /v2/apps/[guid]/routes for each app, or we can just use the 'uris' key from /v2/apps/[guid]/stats
|
128
|
+
# which we have to call anyway, to get app instance usage stats..
|
129
|
+
# :routes => running ? formatted_routes_for_app(app) : [],
|
130
|
+
:data_from => Time.now.to_i,
|
131
|
+
:last_uploaded => app['metadata']['updated_at'] ? DateTime.parse(app['metadata']['updated_at']).strftime('%Y-%m-%d %T %z') : nil
|
132
|
+
}
|
46
133
|
|
47
|
-
|
48
|
-
|
134
|
+
additional_data = {}
|
135
|
+
begin
|
136
|
+
instance_stats = []
|
137
|
+
routes = []
|
138
|
+
if running
|
139
|
+
instance_stats = formatted_instance_stats_for_app(app)
|
140
|
+
# Finds the first running app instance that has a set of routes, in case there are stopped/crashed app instances that don't have any.
|
141
|
+
running_instances = instance_stats.select{|instance| instance['stats']['uris'] if instance['state'] == 'RUNNING'}
|
142
|
+
raise "Unable to retrieve app routes - no app instances are running." if running_instances.empty?
|
143
|
+
routes = running_instances.first['stats']['uris']
|
144
|
+
end
|
49
145
|
|
50
|
-
|
51
|
-
|
146
|
+
additional_data = {
|
147
|
+
:running => running,
|
148
|
+
:instances => instance_stats,
|
149
|
+
:routes => routes,
|
150
|
+
:error => nil
|
151
|
+
}
|
152
|
+
rescue => e
|
153
|
+
@logger.info " #{org['entity']['name']} #{space['entity']['name']}: '#{app['entity']['name']}' error: #{e.message}"
|
154
|
+
additional_data = {
|
155
|
+
:running => 'error',
|
156
|
+
:instances => [],
|
157
|
+
:routes => [],
|
158
|
+
:error => e.message
|
159
|
+
}
|
160
|
+
end
|
161
|
+
|
162
|
+
base_data.merge additional_data
|
163
|
+
end
|
164
|
+
|
165
|
+
put_in_redis "#{ENV['REDIS_KEY_PREFIX']}:orgs", formatted_orgs
|
166
|
+
put_in_redis "#{ENV['REDIS_KEY_PREFIX']}:apps", formatted_apps
|
52
167
|
put_in_redis "#{ENV['REDIS_KEY_PREFIX']}:last_updated", {:last_updated => Time.now}
|
53
168
|
|
54
169
|
@logger.info "Update completed in #{format_duration(Time.now.to_f - start_time.to_f)}..."
|
55
170
|
lock_manager.unlock(lock)
|
56
|
-
cf_client.logout
|
171
|
+
@cf_client.logout
|
57
172
|
else
|
58
173
|
@logger.info "Update already running in another instance!"
|
59
174
|
end
|
60
175
|
end
|
61
176
|
rescue Rufus::Scheduler::TimeoutError
|
62
177
|
@logger.info 'Data update took too long and was aborted, waiting for the lock to expire before trying again...'
|
63
|
-
cf_client.logout
|
178
|
+
@cf_client.logout
|
64
179
|
end
|
65
180
|
end
|
66
181
|
|
@@ -70,97 +185,103 @@ def get_client(cf_api=ENV['CF_API'], cf_user=ENV['CF_USER'], cf_password=ENV['CF
|
|
70
185
|
client
|
71
186
|
end
|
72
187
|
|
73
|
-
def send_data_to_graphite(data, graphite)
|
74
|
-
|
75
|
-
|
76
|
-
|
188
|
+
# def send_data_to_graphite(data, graphite)
|
189
|
+
# org = data[:org]
|
190
|
+
# space = data[:space]
|
191
|
+
# name = data[:name].sub ".", "_" # Some apps have dots in the app name
|
77
192
|
|
78
|
-
|
79
|
-
|
193
|
+
# data[:instances].each_with_index do |instance_data, index|
|
194
|
+
# graphite_base_key = "cf_apps.#{org}.#{space}.#{name}.#{index}"
|
80
195
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
196
|
+
# # Quota data
|
197
|
+
# [:mem_quota, :disk_quota].each do |key|
|
198
|
+
# graphite.metrics "#{graphite_base_key}.#{key}" => instance_data[:stats][key]
|
199
|
+
# end
|
85
200
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
end
|
201
|
+
# # Usage data
|
202
|
+
# [:mem, :disk, :cpu].each do |key|
|
203
|
+
# graphite.metrics "#{graphite_base_key}.#{key}" => instance_data[:stats][:usage][key]
|
204
|
+
# end
|
205
|
+
# end
|
206
|
+
# end
|
92
207
|
|
93
|
-
def get_app_data(cf_client, graphite)
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
end
|
208
|
+
# def get_app_data(cf_client, graphite)
|
209
|
+
# Parallel.map(cf_client.organizations, :in_threads=> PARALLEL_MAPS) do |org|
|
210
|
+
# org_name = org.name
|
211
|
+
# Parallel.map(org.spaces, :in_threads => PARALLEL_MAPS) do |space|
|
212
|
+
# space_name = space.name
|
213
|
+
# @logger.info "Getting app data for apps in #{org_name}:#{space_name}..."
|
214
|
+
# Parallel.map(space.apps, :in_threads=> PARALLEL_MAPS) do |app|
|
215
|
+
# begin
|
216
|
+
# # It's possible for an app to have been terminated before this stage is reached.
|
217
|
+
# formatted_app_data = format_app_data(app, org_name, space_name)
|
218
|
+
# if graphite
|
219
|
+
# send_data_to_graphite(formatted_app_data, graphite)
|
220
|
+
# end
|
221
|
+
# formatted_app_data
|
222
|
+
# rescue CFoundry::AppNotFound
|
223
|
+
# next
|
224
|
+
# end
|
225
|
+
# end
|
226
|
+
# end
|
227
|
+
# end.flatten.compact
|
228
|
+
# end
|
114
229
|
|
115
|
-
def get_org_data(cf_client)
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
end
|
230
|
+
# def get_org_data(cf_client)
|
231
|
+
# Parallel.map( cf_client.organizations, :in_threads=> PARALLEL_MAPS) do |org|
|
232
|
+
# @logger.info "Getting org data for #{org.name}..."
|
233
|
+
# # The CFoundry client returns memory_limit in MB, so we need to normalise to bytes to match the Apps.
|
234
|
+
# {
|
235
|
+
# :guid => org.guid,
|
236
|
+
# :name => org.name,
|
237
|
+
# :quota => {
|
238
|
+
# :total_services => org.quota_definition.total_services,
|
239
|
+
# :memory_limit => org.quota_definition.memory_limit * 1024 * 1024
|
240
|
+
# }
|
241
|
+
# }
|
242
|
+
# end.flatten.compact
|
243
|
+
# end
|
129
244
|
|
130
|
-
def format_app_data(app, org_name, space_name)
|
245
|
+
# def format_app_data(app, org_name, space_name)
|
131
246
|
|
132
|
-
|
247
|
+
# last_uploaded = (app.manifest[:entity][:package_updated_at] ||= nil)
|
133
248
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
249
|
+
# base_data = {
|
250
|
+
# :guid => app.guid,
|
251
|
+
# :name => app.name,
|
252
|
+
# :org => org_name,
|
253
|
+
# :space => space_name,
|
254
|
+
# :stack => app.stack.name,
|
255
|
+
# :buildpack => app.buildpack,
|
256
|
+
# :routes => app.running? ? routes_for_app(app) : [],
|
257
|
+
# :data_from => Time.now.to_i,
|
258
|
+
# :last_uploaded => last_uploaded ? DateTime.parse(last_uploaded).strftime('%Y-%m-%d %T %z') : nil
|
259
|
+
# }
|
145
260
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
261
|
+
# additional_data = {}
|
262
|
+
# begin
|
263
|
+
# additional_data = {
|
264
|
+
# :running => app.running?,
|
265
|
+
# :instances => app.running? ? app.stats.map{|key, value| value} : [],
|
266
|
+
# :error => nil
|
267
|
+
# }
|
268
|
+
# rescue => e
|
269
|
+
# @logger.info " #{org_name} #{space_name}: '#{app.name}'' error: #{e.message}"
|
270
|
+
# additional_data = {
|
271
|
+
# :running => 'error',
|
272
|
+
# :instances => [],
|
273
|
+
# :error => e.message
|
274
|
+
# }
|
275
|
+
# end
|
161
276
|
|
162
|
-
|
163
|
-
end
|
277
|
+
# base_data.merge additional_data
|
278
|
+
# end
|
279
|
+
|
280
|
+
# def routes_for_app app
|
281
|
+
# guids = space.apps.first.routes.collect{|route| route.guid}
|
282
|
+
# guids.collect{|guid| @domains.select{|domain| domain[:guid] == guid}}
|
283
|
+
# @domains.collect
|
284
|
+
# end
|
164
285
|
|
165
286
|
def put_in_redis(key, data)
|
166
287
|
REDIS.set key, data.to_json
|
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:
|
4
|
+
version: 2.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: 2016-
|
11
|
+
date: 2016-05-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cfoundry
|
@@ -135,9 +135,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
135
135
|
version: '0'
|
136
136
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
137
|
requirements:
|
138
|
-
- - '
|
138
|
+
- - '>'
|
139
139
|
- !ruby/object:Gem::Version
|
140
|
-
version:
|
140
|
+
version: 1.3.1
|
141
141
|
requirements: []
|
142
142
|
rubyforge_project:
|
143
143
|
rubygems_version: 2.0.14
|