Skip to content

Commit 2541410

Browse files
philippthunSven Krieger
andcommitted
Implement GET /v3/processes/:guid/instances
This endpoint returns information for all instances (= actual LRPs) for the given process. Per instance the following information is shown: index, state, since. The data is retrieved from Diego via the endpoint '/v1/actual_lrps/list_by_process_guids'. The InstancesStatsReporter processes this data as follows: - group by process guid - sort / group by index - keep only the newest LRP per index - fill missing instances (i.e. less actual LRPs than desired) with DOWN state Additional changes: - BbsInstancesClient: handle_diego_errors needs check for ResourceNotFound only when calling desired_lrp_by_process_guid. The other methods return an empty list. - BuildpackPresenter, ProcessPresenter: remove useless method Co-authored-by: Sven Krieger <sven.krieger@sap.com>
1 parent 1709fd2 commit 2541410

File tree

17 files changed

+463
-32
lines changed

17 files changed

+463
-32
lines changed

.rubocop_todo.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,6 @@ Lint/UnusedMethodArgument:
8585
Lint/UselessMethodDefinition:
8686
Exclude:
8787
- 'app/messages/route_destination_update_message.rb'
88-
- 'app/presenters/v3/buildpack_presenter.rb'
89-
- 'app/presenters/v3/process_presenter.rb'
9088
- 'spec/support/fake_front_controller.rb'
9189

9290
# Offense count: 791

app/controllers/v3/processes_controller.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require 'presenters/v3/paginated_list_presenter'
22
require 'presenters/v3/process_presenter'
33
require 'presenters/v3/process_stats_presenter'
4+
require 'presenters/v3/process_instances_presenter'
45
require 'cloud_controller/paging/pagination_options'
56
require 'actions/process_delete'
67
require 'fetchers/process_list_fetcher'
@@ -106,6 +107,12 @@ def stats
106107
render status: :ok, json: Presenters::V3::ProcessStatsPresenter.new(@process.type, process_stats)
107108
end
108109

110+
def instances
111+
instances = instances_reporters.instances_for_processes([@process])
112+
113+
render status: :ok, json: Presenters::V3::ProcessInstancesPresenter.new(@process, instances[@process.guid])
114+
end
115+
109116
private
110117

111118
def find_process_and_space

app/messages/processes_list_message.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ class ProcessesListMessage < MetadataListMessage
1212

1313
validates_with NoAdditionalParamsValidator # from BaseMessage
1414

15+
# validates :space_guids, array: true, allow_nil: true
16+
# validates :organization_guids, array: true, allow_nil: true
1517
validates :app_guids, array: true, allow_nil: true
1618
validate :app_nested_request, if: -> { app_guid.present? }
1719

app/presenters/v3/buildpack_presenter.rb

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,6 @@ def to_hash
2626
}
2727
end
2828

29-
class << self
30-
# :labels and :annotations come from MetadataPresentationHelpers
31-
def associated_resources
32-
super
33-
end
34-
end
35-
3629
private
3730

3831
def buildpack
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
require 'presenters/v3/base_presenter'
2+
require 'presenters/mixins/metadata_presentation_helpers'
3+
4+
module VCAP::CloudController
5+
module Presenters
6+
module V3
7+
class ProcessInstancesPresenter < BasePresenter
8+
attr_reader :instances
9+
10+
def initialize(process, instances)
11+
super(process)
12+
@instances = instances
13+
end
14+
15+
def to_hash
16+
{
17+
resources: build_instances,
18+
links: build_links
19+
}
20+
end
21+
22+
private
23+
24+
def process
25+
@resource
26+
end
27+
28+
def build_instances
29+
instances.map do |index, instance|
30+
{
31+
index: index,
32+
state: instance[:state],
33+
since: instance[:since]
34+
}
35+
end
36+
end
37+
38+
def build_links
39+
{
40+
self: { href: url_builder.build_url(path: "/v3/processes/#{process.guid}/instances") },
41+
process: { href: url_builder.build_url(path: "/v3/processes/#{process.guid}") }
42+
}
43+
end
44+
end
45+
end
46+
end
47+
end

app/presenters/v3/process_presenter.rb

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,6 @@ module V3
88
class ProcessPresenter < BasePresenter
99
include VCAP::CloudController::Presenters::Mixins::MetadataPresentationHelpers
1010

11-
class << self
12-
# :labels and :annotations come from MetadataPresentationHelpers
13-
def associated_resources
14-
super
15-
end
16-
end
17-
1811
def to_hash
1912
health_check_data = { timeout: process.health_check_timeout, invocation_timeout: process.health_check_invocation_timeout, interval: process.health_check_interval }
2013
health_check_data[:endpoint] = process.health_check_http_endpoint if process.health_check_type == HealthCheckTypes::HTTP

config/routes.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
get '/processes', to: 'processes#index'
5656
get '/processes/:process_guid', to: 'processes#show'
5757
patch '/processes/:process_guid', to: 'processes#update'
58+
get '/processes/:process_guid/instances', to: 'processes#instances'
5859
delete '/processes/:process_guid/instances/:index', to: 'processes#terminate'
5960
post '/processes/:process_guid/actions/scale', to: 'processes#scale'
6061
get '/processes/:process_guid/stats', to: 'processes#stats'

lib/cloud_controller/backends/instances_reporters.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def stats_for_app(app)
2828
end
2929

3030
delegate :number_of_starting_and_running_instances_for_processes, :instance_count_summary, to: :diego_reporter
31+
delegate :instances_for_processes, to: :diego_stats_reporter
3132

3233
private
3334

lib/cloud_controller/diego/bbs_instances_client.rb

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def lrp_instances(process)
1111
process_guid = ProcessGuid.from_process(process)
1212
logger.info('lrp.instances.request', process_guid:)
1313

14-
actual_lrps_response = handle_diego_errors(process_guid) do
14+
actual_lrps_response = handle_diego_errors do
1515
response = @client.actual_lrps_by_process_guid(process_guid)
1616
logger.info('lrp.instances.response', process_guid: process_guid, error: response.error)
1717
response
@@ -20,30 +20,42 @@ def lrp_instances(process)
2020
actual_lrps_response.actual_lrps
2121
end
2222

23+
def actual_lrps_by_processes(processes)
24+
process_guids = processes.map { |process| ProcessGuid.from_process(process) }
25+
logger.info('actual.lrps.by.processes.request', process_guids:)
26+
27+
actual_lrps_response = handle_diego_errors do
28+
response = @client.actual_lrps_by_process_guids(process_guids)
29+
logger.info('actual.lrps.by.processes.response', process_guids: process_guids, error: response.error)
30+
response
31+
end
32+
33+
actual_lrps_response.actual_lrps
34+
end
35+
2336
def desired_lrp_instance(process)
2437
process_guid = ProcessGuid.from_process(process)
25-
response = handle_diego_errors(process_guid) do
38+
response = handle_diego_errors(handle_resource_not_found: true, process_guid: process_guid) do
2639
@client.desired_lrp_by_process_guid(process_guid)
2740
end
2841
response.desired_lrp
2942
end
3043

3144
private
3245

33-
def handle_diego_errors(process_guid)
46+
def handle_diego_errors(handle_resource_not_found: false, process_guid: nil)
3447
begin
3548
response = yield
3649
rescue ::Diego::Error => e
3750
raise CloudController::Errors::InstancesUnavailable.new(e)
3851
end
3952

4053
if response.error
41-
if response.error.type == ::Diego::Bbs::ErrorTypes::ResourceNotFound
54+
if handle_resource_not_found && response.error.type == ::Diego::Bbs::ErrorTypes::ResourceNotFound
4255
raise CloudController::Errors::NoRunningInstances.new("No running instances found for process guid #{process_guid}")
4356
end
4457

4558
raise CloudController::Errors::InstancesUnavailable.new(response.error.message)
46-
4759
end
4860

4961
response

lib/cloud_controller/diego/reporters/instances_stats_reporter.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,41 @@ def stats_for_app(process)
2929
raise exception
3030
end
3131

32+
def instances_for_processes(processes)
33+
logger.debug('instances_for_processes.fetching_actual_lrps')
34+
35+
# Fetch actual_lrps for all processes
36+
actual_lrps = bbs_instances_client.actual_lrps_by_processes(processes)
37+
38+
lrps_by_process_guid = actual_lrps.group_by { |lrp| (pg = lrp.actual_lrp_key&.process_guid) && ProcessGuid.cc_process_guid(pg) }
39+
40+
current_time_since_epoch_ns = Time.now.to_f * 1e9
41+
results = {}
42+
processes.each do |process|
43+
newest_lrp_by_index = (lrps_by_process_guid[process.guid] || []).
44+
group_by { |lrp| lrp.actual_lrp_key&.index }.
45+
transform_values { |lrps| lrps.max_by { |lrp| lrp.since || 0 } }
46+
47+
instances = {}
48+
# Fill in the instances up to the max of desired instances and actual instances
49+
[process.instances, newest_lrp_by_index.length].max.times do |idx|
50+
lrp = newest_lrp_by_index[idx]
51+
instances[idx] = if lrp
52+
{
53+
state: LrpStateTranslator.translate_lrp_state(lrp),
54+
since: nanoseconds_to_seconds(current_time_since_epoch_ns - lrp.since)
55+
}
56+
else
57+
{ state: VCAP::CloudController::Diego::LRP_DOWN }
58+
end
59+
end
60+
61+
results[process.guid] = instances
62+
end
63+
64+
results
65+
end
66+
3267
private
3368

3469
attr_reader :bbs_instances_client

0 commit comments

Comments
 (0)