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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/cf_light_api/worker.rb +212 -91
  3. metadata +4 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3067cac56cd133c9fc4fd246f29e0874335f2998
4
- data.tar.gz: 4fb42dd6f9e61ee969b6d966c15ac5bfc636cc6d
3
+ metadata.gz: bdbf36a622784f98ea2133973966ae40eb500572
4
+ data.tar.gz: 8b12c0cec0408a0f16d31392836eea9286f62fd7
5
5
  SHA512:
6
- metadata.gz: 348c46fd0ae464fb196b78598a713ed1b620a989757bdb1d8dcdf61d542df19b8d7edf5bd985e921b4cd5b61ad3c05ded7831c5f49ec6c4b458c85043ea4fbf9
7
- data.tar.gz: 64723974aad403fb3cff89385976ce7f7a8c2bb4214a3a5fd325f9ff65c8734a6fba658dde1496ca2f6c1e5e123c1ec3bdafa795ad208f5c54a9c2e1bc37ca97
6
+ metadata.gz: 6d65857061da6b5b87dd19928b5386ef2d339649bae6989cec2a981607cc09d28b3f8be72a2d2c97039517a5151e53ec9e50a55e290618e4c9e918bb27eaeb12
7
+ data.tar.gz: c5f6a83db24dbe514f9ce1272824274ac052f71b4f1296462793b4925ad290053273be7e60b21a6715e3555cca98b58823607b9679a2e1b880bc2451dd77f6e3
@@ -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 in parallel..."
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
- cf_client = get_client()
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
- org_data = get_org_data(cf_client)
48
- app_data = get_app_data(cf_client, graphite)
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
- put_in_redis "#{ENV['REDIS_KEY_PREFIX']}:orgs", org_data
51
- put_in_redis "#{ENV['REDIS_KEY_PREFIX']}:apps", app_data
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
- org = data[:org]
75
- space = data[:space]
76
- name = data[:name].sub ".", "_" # Some apps have dots in the app name
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
- data[:instances].each_with_index do |instance_data, index|
79
- graphite_base_key = "cf_apps.#{org}.#{space}.#{name}.#{index}"
193
+ # data[:instances].each_with_index do |instance_data, index|
194
+ # graphite_base_key = "cf_apps.#{org}.#{space}.#{name}.#{index}"
80
195
 
81
- # Quota data
82
- [:mem_quota, :disk_quota].each do |key|
83
- graphite.metrics "#{graphite_base_key}.#{key}" => instance_data[:stats][key]
84
- end
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
- # Usage data
87
- [:mem, :disk, :cpu].each do |key|
88
- graphite.metrics "#{graphite_base_key}.#{key}" => instance_data[:stats][:usage][key]
89
- end
90
- end
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
- Parallel.map(cf_client.organizations, :in_threads=> PARALLEL_MAPS) do |org|
95
- org_name = org.name
96
- Parallel.map(org.spaces, :in_threads => PARALLEL_MAPS) do |space|
97
- space_name = space.name
98
- @logger.info "Getting app data for apps in #{org_name}:#{space_name}..."
99
- Parallel.map(space.apps, :in_threads=> PARALLEL_MAPS) do |app|
100
- begin
101
- # It's possible for an app to have been terminated before this stage is reached.
102
- formatted_app_data = format_app_data(app, org_name, space_name)
103
- if graphite
104
- send_data_to_graphite(formatted_app_data, graphite)
105
- end
106
- formatted_app_data
107
- rescue CFoundry::AppNotFound
108
- next
109
- end
110
- end
111
- end
112
- end.flatten.compact
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
- Parallel.map( cf_client.organizations, :in_threads=> PARALLEL_MAPS) do |org|
117
- @logger.info "Getting org data for #{org.name}..."
118
- # The CFoundry client returns memory_limit in MB, so we need to normalise to bytes to match the Apps.
119
- {
120
- :guid => org.guid,
121
- :name => org.name,
122
- :quota => {
123
- :total_services => org.quota_definition.total_services,
124
- :memory_limit => org.quota_definition.memory_limit * 1024 * 1024
125
- }
126
- }
127
- end.flatten.compact
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
- last_uploaded = (app.manifest[:entity][:package_updated_at] ||= nil)
247
+ # last_uploaded = (app.manifest[:entity][:package_updated_at] ||= nil)
133
248
 
134
- base_data = {
135
- :guid => app.guid,
136
- :name => app.name,
137
- :org => org_name,
138
- :space => space_name,
139
- :stack => app.stack.name,
140
- :buildpack => app.buildpack,
141
- :routes => app.routes.map {|route| route.name},
142
- :data_from => Time.now.to_i,
143
- :last_uploaded => last_uploaded ? DateTime.parse(last_uploaded).strftime('%Y-%m-%d %T %z') : nil
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
- additional_data = {}
147
- begin
148
- additional_data = {
149
- :running => app.running?,
150
- :instances => app.running? ? app.stats.map{|key, value| value} : [],
151
- :error => nil
152
- }
153
- rescue => e
154
- @logger.info " #{org_name} #{space_name}: '#{app.name}'' error: #{e.message}"
155
- additional_data = {
156
- :running => 'error',
157
- :instances => [],
158
- :error => e.message
159
- }
160
- end
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
- base_data.merge additional_data
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: 1.7.0
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-04-22 00:00:00.000000000 Z
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: '0'
140
+ version: 1.3.1
141
141
  requirements: []
142
142
  rubyforge_project:
143
143
  rubygems_version: 2.0.14