Skip to content

Commit 4a66b6c

Browse files
author
Atanas Todorov
committed
TNZ-69318 Persist and present broker_provided_metadata
TNZ-69318 Persist and present broker_provided_metadata TNZ-69318 Persist and present broker_provided_metadata TNZ-69318 Persist and present broker_provided_metadata TNZ-69318 Persist and present broker_provided_metadata TNZ-69318 Persist and present broker_provided_metadata Add unit tests Add unit tests Remove Trailing spaces TNZ-70252 Apply code review comments TNZ-70252 Revert back column type to text TNZ-70252 add text column size constraint TNZ-70252 add text column size constraint
1 parent 2c4f25c commit 4a66b6c

File tree

12 files changed

+413
-3
lines changed

12 files changed

+413
-3
lines changed

app/actions/v3/service_instance_update_managed.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ def complete_instance_and_save(instance, broker_response)
159159
u[:maintenance_info] = maintenance_info if maintenance_info_updated?
160160
end
161161
updates[:dashboard_url] = broker_response[:dashboard_url] if broker_response.key?(:dashboard_url)
162+
updates[:broker_provided_metadata] = broker_response[:broker_provided_metadata] if broker_response.key?(:broker_provided_metadata)
162163

163164
ManagedServiceInstance.db.transaction do
164165
service_instance.save_with_new_operation(
@@ -174,6 +175,7 @@ def complete_instance_and_save(instance, broker_response)
174175
def save_incomplete_instance(instance, broker_response)
175176
attributes_to_update = {}
176177
attributes_to_update[:dashboard_url] = broker_response[:dashboard_url] if broker_response.key?(:dashboard_url)
178+
attributes_to_update[:broker_provided_metadata] = broker_response[:broker_provided_metadata] if broker_response.key?(:broker_provided_metadata)
177179

178180
instance.save_with_new_operation(
179181
attributes_to_update,

app/models/services/managed_service_instance.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class ManagedServiceInstance < ServiceInstance
2121

2222
plugin :after_initialize
2323

24-
serialize_attributes :json, :maintenance_info
24+
serialize_attributes :json, :maintenance_info, :broker_provided_metadata
2525

2626
def validation_policies
2727
if space

app/presenters/v3/service_instance_presenter.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def hash_common
7777
end
7878

7979
def hash_additions_managed
80-
{
80+
base_hash = {
8181
type: 'managed',
8282
maintenance_info: maintenance_info,
8383
upgrade_available: upgrade_available,
@@ -101,6 +101,10 @@ def hash_additions_managed
101101
}
102102
}
103103
}
104+
105+
base_hash[:broker_provided_metadata] = service_instance.broker_provided_metadata if service_instance.broker_provided_metadata.present?
106+
107+
base_hash
104108
end
105109

106110
def hash_additions_user_provided
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Sequel.migration do
2+
change do
3+
# rubocop:disable Migration/IncludeStringSize
4+
add_column :service_instances, :broker_provided_metadata, String, size: 4096, text: true, null: true
5+
# rubocop:enable Migration/IncludeStringSize
6+
end
7+
end

docs/v3/source/includes/api_resources/_service_instances.erb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@
4343
},
4444
"upgrade_available": false,
4545
"dashboard_url": "https://service-broker.example.org/dashboard",
46+
"broker_provided_metadata": {
47+
"labels": {
48+
"service_engine_version": "16.6"
49+
},
50+
"attributes": {
51+
"max_connections": "100"
52+
}
53+
},
4654
"last_operation": {
4755
"type": "create",
4856
"state": "succeeded",
@@ -152,6 +160,14 @@
152160
},
153161
"upgrade_available": false,
154162
"dashboard_url": "https://service-broker.example.org/dashboard",
163+
"broker_provided_metadata": {
164+
"labels": {
165+
"service_engine_version": "16.6"
166+
},
167+
"attributes": {
168+
"max_connections": "100"
169+
}
170+
},
155171
"last_operation": {
156172
"type": <%= metadata.fetch(:operation, "create").to_json %>,
157173
"state": "succeeded",

docs/v3/source/includes/resources/service_instances/_object.md.erb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Name | Type | Description
2727
**maintenance_info** | _[maintenance_info object](#the-maintenance-info-object-for-service-instances)_ | Information about the version of this service instance; only shown when type is `managed`
2828
**upgrade_available** | _bool_ | Whether or not an upgrade of this service instance is available on the current Service Plan; details are available in the maintenance_info object; Only shown when type is `managed`
2929
**dashboard_url** | _string_ | The URL to the service instance dashboard (or null if there is none); only shown when type is `managed`
30+
**broker_provided_metadata** | _[broker provided metadata object](#the-broker-provided-metadata-object-for-service-instances)_ | Metadata provided by the service broker about this service instance; only shown when type is `managed`
3031
**last_operation** | _[last operation object](#the-last-operation-object-for-service-instances)_ | The last operation of this service instance
3132
**relationships.service_plan** | [_to-one relationship_](#to-one-relationships) | The service plan the service instance relates to; only shown when type is `managed`
3233
**relationships.space** | [_to-one relationship_](#to-one-relationships) | The space the service instance is contained in
@@ -43,6 +44,14 @@ Name | Type | Description
4344
**description** | _string_ | A textual explanation associated with this version
4445

4546

47+
#### The broker provided metadata object for service instances
48+
49+
Name | Type | Description
50+
---- | ---- | -----------
51+
**labels** | _object_ | Broker-specified key-value pairs specifying attributes of Service Instances that do not directly imply behavior changes
52+
**attributes** | _object_ | Broker-specific key-value pairs generated by the Broker that MAY imply behavior changes by the Platform
53+
54+
4655
#### The last operation object for service instances
4756

4857
Name | Type | Description

lib/services/service_brokers/v2/client.rb

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ def provision(instance, arbitrary_parameters: {}, accepts_incomplete: false, mai
5656
return_values = {
5757
instance: {
5858
credentials: {},
59-
dashboard_url: parsed_response['dashboard_url']
59+
dashboard_url: parsed_response['dashboard_url'],
60+
broker_provided_metadata: extract_broker_provided_metadata(parsed_response)
6061
},
6162
last_operation: {
6263
type: 'create',
@@ -204,6 +205,9 @@ def update(instance, plan, accepts_incomplete: false, arbitrary_parameters: nil,
204205

205206
attributes[:dashboard_url] = dashboard_url if dashboard_url
206207

208+
# Add broker_provided_metadata extraction
209+
attributes[:broker_provided_metadata] = extract_broker_provided_metadata(parsed_response)
210+
207211
if state == 'in progress'
208212
proposed_changes = { service_plan_guid: plan.guid }
209213
proposed_changes[:maintenance_info] = maintenance_info if maintenance_info
@@ -417,5 +421,11 @@ def hashified_public_annotations(annotations)
417421
end
418422
hashified_annotations(public_annotations)
419423
end
424+
425+
def extract_broker_provided_metadata(parsed_response)
426+
return nil unless parsed_response['metadata'].present? && parsed_response['metadata'].is_a?(Hash)
427+
428+
parsed_response['metadata']
429+
end
420430
end
421431
end

lib/services/service_brokers/v2/response_parser.rb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,17 @@ def provision_response_schema
263263
'operation' => {
264264
'type' => 'string',
265265
'maxLength' => 10_000
266+
},
267+
'metadata' => {
268+
'type' => 'object',
269+
'properties' => {
270+
'labels' => {
271+
'type' => 'object'
272+
},
273+
'attributes' => {
274+
'type' => 'object'
275+
}
276+
}
266277
}
267278
}
268279
}]
@@ -292,6 +303,17 @@ def update_response_schema
292303
'operation' => {
293304
'type' => 'string',
294305
'maxLength' => 10_000
306+
},
307+
'metadata' => {
308+
'type' => 'object',
309+
'properties' => {
310+
'labels' => {
311+
'type' => 'object'
312+
},
313+
'attributes' => {
314+
'type' => 'object'
315+
}
316+
}
295317
}
296318
}
297319
}]
@@ -313,6 +335,17 @@ def fetch_service_instance_response_schema
313335
},
314336
'parameters' => {
315337
'type' => 'object'
338+
},
339+
'metadata' => {
340+
'type' => 'object',
341+
'properties' => {
342+
'labels' => {
343+
'type' => 'object'
344+
},
345+
'attributes' => {
346+
'type' => 'object'
347+
}
348+
}
316349
}
317350
}
318351
}]
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Migration test for adding broker_provided_metadata column to service_instances table
2+
#
3+
# This test verifies that the migration correctly adds the broker_provided_metadata
4+
# column to the service_instances table with the correct properties (text type, nullable).
5+
6+
require 'spec_helper'
7+
require 'migrations/helpers/migration_shared_context'
8+
9+
RSpec.describe 'migration to add broker_provided_metadata column to service_instances table', isolation: :truncation, type: :migration do
10+
include_context 'migration' do
11+
let(:migration_filename) { '20251121174647_add_broker_provided_metadata_to_service_instances.rb' }
12+
end
13+
14+
describe 'service_instances table' do
15+
subject(:run_migration) { Sequel::Migrator.run(db, migrations_path, target: current_migration_index, allow_missing_migration_files: true) }
16+
17+
let(:space) { VCAP::CloudController::Space.make }
18+
19+
it 'adds a column `broker_provided_metadata`' do
20+
expect(db[:service_instances].columns).not_to include(:broker_provided_metadata)
21+
run_migration
22+
expect(db[:service_instances].columns).to include(:broker_provided_metadata)
23+
end
24+
25+
it 'allows null values for broker_provided_metadata' do
26+
run_migration
27+
# Insert a service instance without broker_provided_metadata
28+
db[:service_instances].insert(
29+
guid: 'test-service-instance-guid',
30+
name: 'test-instance',
31+
space_id: space.id,
32+
broker_provided_metadata: nil
33+
)
34+
# Verify the insert succeeded and the column is null
35+
instance = db[:service_instances].first(guid: 'test-service-instance-guid')
36+
expect(instance[:broker_provided_metadata]).to be_nil
37+
end
38+
39+
it 'accepts text values for broker_provided_metadata' do
40+
run_migration
41+
# Insert a service instance with broker_provided_metadata
42+
metadata_json = '{"labels": {"version": "1.0"}, "attributes": {"engine": "postgresql"}}'
43+
db[:service_instances].insert(
44+
guid: 'test-service-instance-with-metadata',
45+
name: 'test-instance-with-metadata',
46+
space_id: space.id,
47+
broker_provided_metadata: metadata_json
48+
)
49+
# Verify the metadata was stored correctly
50+
instance = db[:service_instances].first(guid: 'test-service-instance-with-metadata')
51+
expect(instance[:broker_provided_metadata]).to eq(metadata_json)
52+
end
53+
54+
it 'preserves existing service instances after migration' do
55+
# Insert a service instance before migration
56+
db[:service_instances].insert(
57+
guid: 'existing-service-instance-guid',
58+
name: 'existing-instance',
59+
space_id: space.id
60+
)
61+
run_migration
62+
# Verify the existing instance still exists and has null metadata
63+
instance = db[:service_instances].first(guid: 'existing-service-instance-guid')
64+
expect(instance).not_to be_nil
65+
expect(instance[:broker_provided_metadata]).to be_nil
66+
end
67+
end
68+
end

spec/unit/actions/v3/service_instance_update_managed_spec.rb

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,48 @@ module V3
939939
{ prefix: nil, key_name: 'release', value: 'stable' })
940940
end
941941

942+
context 'when broker returns broker_provided_metadata' do
943+
let(:broker_metadata) do
944+
{
945+
'labels' => {
946+
'service_engine_version' => 'postgresql 16.6'
947+
},
948+
'attributes' => {
949+
'attr_key' => 'attr_value'
950+
}
951+
}
952+
end
953+
954+
let(:update_response) do
955+
{
956+
dashboard_url: updated_dashboard_url,
957+
broker_provided_metadata: broker_metadata,
958+
last_operation: {
959+
type: 'update',
960+
state: 'succeeded'
961+
}
962+
}
963+
end
964+
965+
it 'saves the broker_provided_metadata to the instance' do
966+
action.update(accepts_incomplete: true)
967+
968+
instance = original_instance.reload
969+
expect(instance.broker_provided_metadata).to eq(broker_metadata)
970+
end
971+
end
972+
973+
context 'when broker does not return broker_provided_metadata' do
974+
it 'does not modify existing broker_provided_metadata' do
975+
original_instance.update(broker_provided_metadata: { 'old' => 'metadata' })
976+
977+
action.update(accepts_incomplete: true)
978+
979+
instance = original_instance.reload
980+
expect(instance.broker_provided_metadata).to eq({ 'old' => 'metadata' })
981+
end
982+
end
983+
942984
it 'logs an audit event' do
943985
action.update(accepts_incomplete: true)
944986

@@ -1219,6 +1261,36 @@ module V3
12191261
)
12201262
end
12211263

1264+
context 'when broker returns broker_provided_metadata during async update' do
1265+
let(:broker_metadata) do
1266+
{
1267+
'labels' => {
1268+
'version' => '17.2'
1269+
}
1270+
}
1271+
end
1272+
1273+
let(:update_response) do
1274+
{
1275+
dashboard_url: updated_dashboard_url,
1276+
broker_provided_metadata: broker_metadata,
1277+
last_operation: {
1278+
type: 'update',
1279+
state: 'in progress',
1280+
description: 'some description',
1281+
broker_provided_operation: broker_provided_operation
1282+
}
1283+
}
1284+
end
1285+
1286+
it 'saves the broker_provided_metadata to the instance' do
1287+
action.update(accepts_incomplete: true)
1288+
1289+
instance = original_instance.reload
1290+
expect(instance.broker_provided_metadata).to eq(broker_metadata)
1291+
end
1292+
end
1293+
12221294
context 'when update does not return dashboard_url' do
12231295
let(:update_response) do
12241296
{

0 commit comments

Comments
 (0)