Skip to content

Commit 91e85dc

Browse files
committed
Implement embed=process_instances
Process instances can be embedded into process resources; the parameter embed=process_instances is available for the following API endpoints: - GET /v3/processes/:guid?embed=process_instances - GET /v3/apps/:guid/processes/:type?embed=process_instances - GET /v3/processes?embed=process_instances - GET /v3/apps/:guid/processes?embed=process_instances A new ProcessShowMessage has been introduced; ProcessesListMessage has been extended. Both messages allow the 'embed' key that is checked with the EmbedParamValidator. The process output is enhanced by the EmbedProcessInstancesDecorator that fetches the required information from Diego and adds a field 'process_instances' to the resource.
1 parent 61483b2 commit 91e85dc

File tree

9 files changed

+315
-5
lines changed

9 files changed

+315
-5
lines changed

app/controllers/v3/processes_controller.rb

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
require 'presenters/v3/process_presenter'
33
require 'presenters/v3/process_stats_presenter'
44
require 'presenters/v3/process_instances_presenter'
5+
require 'decorators/embed_process_instances_decorator'
56
require 'cloud_controller/paging/pagination_options'
67
require 'actions/process_delete'
78
require 'fetchers/process_list_fetcher'
@@ -10,6 +11,7 @@
1011
require 'actions/process_terminate'
1112
require 'actions/process_update'
1213
require 'messages/process_scale_message'
14+
require 'messages/process_show_message'
1315
require 'messages/process_update_message'
1416
require 'messages/processes_list_message'
1517
require 'controllers/v3/mixins/app_sub_resource'
@@ -41,17 +43,30 @@ def index
4143
end
4244
end
4345

46+
decorators = []
47+
decorators << EmbedProcessInstancesDecorator if EmbedProcessInstancesDecorator.match?(message.embed)
48+
4449
render status: :ok, json: Presenters::V3::PaginatedListPresenter.new(
4550
presenter: Presenters::V3::ProcessPresenter,
4651
paginated_result: SequelPaginator.new.get_page(dataset, message.try(:pagination_options)),
4752
path: base_url(resource: 'processes'),
48-
message: message
53+
message: message,
54+
decorators: decorators
4955
)
5056
end
5157

5258
def show
53-
# TODO
54-
render status: :ok, json: Presenters::V3::ProcessPresenter.new(@process, show_secrets: permission_queryer.can_read_secrets_in_space?(@space.id, @space.organization_id))
59+
message = ProcessShowMessage.from_params(query_params)
60+
invalid_param!(message.errors.full_messages) unless message.valid?
61+
62+
decorators = []
63+
decorators << EmbedProcessInstancesDecorator if EmbedProcessInstancesDecorator.match?(message.embed)
64+
65+
render status: :ok, json: Presenters::V3::ProcessPresenter.new(
66+
@process,
67+
show_secrets: permission_queryer.can_read_secrets_in_space?(@space.id, @space.organization_id),
68+
decorators: decorators
69+
)
5570
end
5671

5772
def update
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
module VCAP::CloudController
2+
class EmbedProcessInstancesDecorator
3+
class << self
4+
def match?(embed)
5+
embed&.include?('process_instances')
6+
end
7+
8+
def decorate(hash, processes)
9+
instances_reporters = CloudController::DependencyLocator.instance.instances_reporters
10+
instances = instances_reporters.instances_for_processes(processes)
11+
12+
if hash.key?(:resources)
13+
# Decorate PaginatedListPresenter
14+
processes.each do |process|
15+
resource_index = hash[:resources].find_index { |resource| resource[:guid] == process.guid }
16+
next unless resource_index # Should not happen...
17+
18+
hash[:resources][resource_index] = embed_process_instances(hash[:resources][resource_index], process_instances(instances, process.guid))
19+
end
20+
else
21+
# Decorate ProcessPresenter
22+
hash = embed_process_instances(hash, process_instances(instances, hash[:guid]))
23+
end
24+
25+
hash
26+
end
27+
28+
private
29+
30+
def process_instances(instances, process_guid)
31+
instances[process_guid].map do |index, instance|
32+
{
33+
index: index,
34+
state: instance[:state],
35+
since: instance[:since]
36+
}
37+
end
38+
end
39+
40+
def embed_process_instances(resource_hash, process_instances)
41+
hash_as_array = resource_hash.to_a
42+
before_relationships = hash_as_array.index { |k, _| k == :relationships } || hash_as_array.length
43+
hash_as_array.insert(before_relationships, [:process_instances, process_instances])
44+
hash_as_array.to_h
45+
end
46+
end
47+
end
48+
end

app/messages/base_message.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,22 @@ def validate(record)
139139
end
140140
end
141141

142+
class EmbedParamValidator < ActiveModel::Validator
143+
def validate(record)
144+
return unless record.requested?(:embed)
145+
146+
key_counts = Hash.new(0)
147+
record.embed.each do |embed_candidate|
148+
if options[:valid_values].member?(embed_candidate)
149+
key_counts[embed_candidate] += 1
150+
record.errors.add(:base, message: "Duplicate embedded resource: '#{embed_candidate}'") if key_counts[embed_candidate] == 2
151+
else
152+
record.errors.add(:base, message: "Invalid embedded resource: '#{embed_candidate}'. Valid embedded resources are: '#{options[:valid_values].join("', '")}'")
153+
end
154+
end
155+
end
156+
end
157+
142158
class LifecycleTypeParamValidator < ActiveModel::Validator
143159
def validate(record)
144160
return unless record.requested?(:lifecycle_type)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
require 'messages/base_message'
2+
3+
module VCAP::CloudController
4+
class ProcessShowMessage < BaseMessage
5+
register_allowed_keys [:embed]
6+
7+
validates_with NoAdditionalParamsValidator
8+
validates_with EmbedParamValidator, valid_values: ['process_instances']
9+
10+
def self.from_params(params)
11+
super(params, %w[embed])
12+
end
13+
end
14+
end

app/messages/processes_list_message.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,19 @@ class ProcessesListMessage < MetadataListMessage
88
space_guids
99
organization_guids
1010
app_guids
11+
embed
1112
]
1213

1314
validates_with NoAdditionalParamsValidator # from BaseMessage
15+
validates_with EmbedParamValidator, valid_values: ['process_instances']
1416

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

2022
def self.from_params(params)
21-
super(params, %w[types space_guids organization_guids app_guids])
23+
super(params, %w[types space_guids organization_guids app_guids embed])
2224
end
2325

2426
def to_param_hash

app/presenters/v3/process_presenter.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ def to_hash
1414

1515
readiness_health_check_data = { invocation_timeout: process.readiness_health_check_invocation_timeout, interval: process.readiness_health_check_interval }
1616
readiness_health_check_data[:endpoint] = process.readiness_health_check_http_endpoint if process.readiness_health_check_type == HealthCheckTypes::HTTP
17-
{
17+
18+
hash = {
1819
guid: process.guid,
1920
created_at: process.created_at,
2021
updated_at: process.updated_at,
@@ -44,6 +45,8 @@ def to_hash
4445
},
4546
links: build_links
4647
}
48+
49+
@decorators.reduce(hash) { |memo, d| d.decorate(memo, [process]) }
4750
end
4851

4952
private

0 commit comments

Comments
 (0)