Skip to content

Commit 8516e29

Browse files
committed
Convert IncompatibleBindings error to UnprocessableEntity (ApiError)
The ServiceBindingFilesBuilder can raise an IncompatibleBindings exception in case of entries violating the specification for file names or if the overall file size is too big. When pushing an app these errors were shown as StagerErrors (with the correct error message); for other operations - i.e. restart, restage - an UnknownError was returned. This change ensures that in any case an UnprocessableEntity (ApiError) is returned (with the concrete error message).
1 parent f697c21 commit 8516e29

File tree

4 files changed

+93
-69
lines changed

4 files changed

+93
-69
lines changed

lib/cloud_controller/diego/app_recipe_builder.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ def app_lrp_arguments
105105
image_password: process.desired_droplet.docker_receipt_password,
106106
volume_mounted_files: ServiceBindingFilesBuilder.build(process)
107107
}.compact
108+
rescue ServiceBindingFilesBuilder::IncompatibleBindings => e
109+
raise CloudController::Errors::ApiError.new_from_details('UnprocessableEntity', "Cannot build service binding files - #{e.message}")
108110
end
109111

110112
def metric_tags(process)

lib/cloud_controller/diego/task_recipe_builder.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ def build_app_task(config, task)
5656
image_password: task.droplet.docker_receipt_password,
5757
volume_mounted_files: ServiceBindingFilesBuilder.build(task.app)
5858
}.compact)
59+
rescue ServiceBindingFilesBuilder::IncompatibleBindings => e
60+
raise CloudController::Errors::ApiError.new_from_details('UnprocessableEntity', "Cannot build service binding files - #{e.message}")
5961
end
6062

6163
def build_staging_task(config, staging_details)
@@ -95,6 +97,8 @@ def build_staging_task(config, staging_details)
9597
image_password: staging_details.package.docker_password,
9698
volume_mounted_files: ServiceBindingFilesBuilder.build(staging_details.package.app)
9799
}.compact)
100+
rescue ServiceBindingFilesBuilder::IncompatibleBindings => e
101+
raise CloudController::Errors::ApiError.new_from_details('UnprocessableEntity', "Cannot build service binding files - #{e.message}")
98102
end
99103

100104
private

spec/unit/lib/cloud_controller/diego/app_recipe_builder_spec.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,20 @@ module Diego
5757
end
5858
end
5959

60+
shared_examples 'IncompatibleBindings error handling' do
61+
let(:incompatible_bindings_error) { VCAP::CloudController::Diego::ServiceBindingFilesBuilder::IncompatibleBindings.new('something is wrong') }
62+
63+
context 'when an IncompatibleBindings error is raised' do
64+
before do
65+
allow_any_instance_of(VCAP::CloudController::Diego::ServiceBindingFilesBuilder).to receive(:build).and_raise(incompatible_bindings_error)
66+
end
67+
68+
it 'results in an UnprocessableEntity error' do
69+
expect { _build }.to raise_error(CloudController::Errors::ApiError, /Cannot build service binding files - something is wrong/)
70+
end
71+
end
72+
end
73+
6074
shared_examples 'k8s service bindings' do
6175
context 'when k8s service bindings are enabled' do
6276
before do
@@ -69,6 +83,10 @@ module Diego
6983
lrp = builder.build_app_lrp
7084
expect(lrp.volume_mounted_files.size).to be > 1
7185
end
86+
87+
include_examples 'IncompatibleBindings error handling' do
88+
let(:_build) { builder.build_app_lrp }
89+
end
7290
end
7391
end
7492

@@ -85,6 +103,10 @@ module Diego
85103
expect(lrp.volume_mounted_files.size).to eq(1)
86104
expect(lrp.volume_mounted_files[0].path).to eq('vcap_services')
87105
end
106+
107+
include_examples 'IncompatibleBindings error handling' do
108+
let(:_build) { builder.build_app_lrp }
109+
end
88110
end
89111
end
90112

spec/unit/lib/cloud_controller/diego/task_recipe_builder_spec.rb

Lines changed: 65 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,53 @@ module Diego
88
let(:space) { Space.make(name: 'MySpace', guid: 'space-guid', organization: org) }
99
let(:app) { AppModel.make(name: 'MyApp', guid: 'banana-guid', space: space) }
1010

11+
shared_examples 'IncompatibleBindings error handling' do
12+
let(:incompatible_bindings_error) { VCAP::CloudController::Diego::ServiceBindingFilesBuilder::IncompatibleBindings.new('something is wrong') }
13+
14+
context 'when an IncompatibleBindings error is raised' do
15+
before do
16+
allow_any_instance_of(VCAP::CloudController::Diego::ServiceBindingFilesBuilder).to receive(:build).and_raise(incompatible_bindings_error)
17+
end
18+
19+
it 'results in an UnprocessableEntity error' do
20+
expect { _build }.to raise_error(CloudController::Errors::ApiError, /Cannot build service binding files - something is wrong/)
21+
end
22+
end
23+
end
24+
25+
shared_examples 'k8s service bindings' do
26+
context 'when k8s service bindings are enabled' do
27+
before do
28+
_app.update(service_binding_k8s_enabled: true)
29+
VCAP::CloudController::ServiceBinding.make(service_instance: ManagedServiceInstance.make(space: _app.space), app: _app)
30+
end
31+
32+
it 'includes volume mounted files' do
33+
result = _build
34+
expect(result.volume_mounted_files.size).to be > 1
35+
end
36+
37+
include_examples 'IncompatibleBindings error handling'
38+
end
39+
end
40+
41+
shared_examples 'file-based VCAP service bindings' do
42+
context 'when file-based VCAP service bindings are enabled' do
43+
before do
44+
_app.update(file_based_vcap_services_enabled: true)
45+
VCAP::CloudController::ServiceBinding.make(service_instance: ManagedServiceInstance.make(space: _app.space), app: _app)
46+
end
47+
48+
it 'includes the vcap_services file' do
49+
result = _build
50+
expect(result.volume_mounted_files.size).to eq(1)
51+
expect(result.volume_mounted_files[0].path).to eq('vcap_services')
52+
end
53+
54+
include_examples 'IncompatibleBindings error handling'
55+
end
56+
end
57+
1158
describe '#build_staging_task' do
1259
let(:staging_details) do
1360
Diego::StagingDetails.new.tap do |details|
@@ -201,31 +248,14 @@ module Diego
201248
end
202249
end
203250

204-
context 'when k8s service bindings are enabled' do
205-
before do
206-
app = staging_details.package.app
207-
app.update(service_binding_k8s_enabled: true)
208-
VCAP::CloudController::ServiceBinding.make(service_instance: ManagedServiceInstance.make(space: app.space), app: app)
209-
end
210-
211-
it 'includes volume mounted files' do
212-
result = task_recipe_builder.build_staging_task(config, staging_details)
213-
expect(result.volume_mounted_files.size).to be > 1
214-
end
251+
include_examples 'k8s service bindings' do
252+
let(:_app) { staging_details.package.app }
253+
let(:_build) { task_recipe_builder.build_staging_task(config, staging_details) }
215254
end
216255

217-
context 'when file-based VCAP service bindings are enabled' do
218-
before do
219-
app = staging_details.package.app
220-
app.update(file_based_vcap_services_enabled: true)
221-
VCAP::CloudController::ServiceBinding.make(service_instance: ManagedServiceInstance.make(space: app.space), app: app)
222-
end
223-
224-
it 'includes volume mounted files' do
225-
result = task_recipe_builder.build_staging_task(config, staging_details)
226-
expect(result.volume_mounted_files.size).to eq(1)
227-
expect(result.volume_mounted_files[0].path).to eq('vcap_services')
228-
end
256+
include_examples 'file-based VCAP service bindings' do
257+
let(:_app) { staging_details.package.app }
258+
let(:_build) { task_recipe_builder.build_staging_task(config, staging_details) }
229259
end
230260
end
231261

@@ -615,31 +645,14 @@ module Diego
615645
end
616646
end
617647

618-
context 'when k8s service bindings are enabled' do
619-
before do
620-
app = task.app
621-
app.update(service_binding_k8s_enabled: true)
622-
VCAP::CloudController::ServiceBinding.make(service_instance: ManagedServiceInstance.make(space: app.space), app: app)
623-
end
624-
625-
it 'includes volume mounted files' do
626-
result = task_recipe_builder.build_app_task(config, task)
627-
expect(result.volume_mounted_files.size).to be > 1
628-
end
648+
include_examples 'k8s service bindings' do
649+
let(:_app) { task.app }
650+
let(:_build) { task_recipe_builder.build_app_task(config, task) }
629651
end
630652

631-
context 'when file-based VCAP service bindings are enabled' do
632-
before do
633-
app = task.app
634-
app.update(file_based_vcap_services_enabled: true)
635-
VCAP::CloudController::ServiceBinding.make(service_instance: ManagedServiceInstance.make(space: app.space), app: app)
636-
end
637-
638-
it 'includes volume mounted files' do
639-
result = task_recipe_builder.build_app_task(config, task)
640-
expect(result.volume_mounted_files.size).to eq(1)
641-
expect(result.volume_mounted_files[0].path).to eq('vcap_services')
642-
end
653+
include_examples 'file-based VCAP service bindings' do
654+
let(:_app) { task.app }
655+
let(:_build) { task_recipe_builder.build_app_task(config, task) }
643656
end
644657
end
645658

@@ -797,31 +810,14 @@ module Diego
797810
end
798811
end
799812

800-
context 'when k8s service bindings are enabled' do
801-
before do
802-
app = task.app
803-
app.update(service_binding_k8s_enabled: true)
804-
VCAP::CloudController::ServiceBinding.make(service_instance: ManagedServiceInstance.make(space: app.space), app: app)
805-
end
806-
807-
it 'includes volume mounted files' do
808-
result = task_recipe_builder.build_app_task(config, task)
809-
expect(result.volume_mounted_files.size).to be > 1
810-
end
813+
include_examples 'k8s service bindings' do
814+
let(:_app) { task.app }
815+
let(:_build) { task_recipe_builder.build_app_task(config, task) }
811816
end
812817

813-
context 'when file-based VCAP service bindings are enabled' do
814-
before do
815-
app = task.app
816-
app.update(file_based_vcap_services_enabled: true)
817-
VCAP::CloudController::ServiceBinding.make(service_instance: ManagedServiceInstance.make(space: app.space), app: app)
818-
end
819-
820-
it 'includes volume mounted files' do
821-
result = task_recipe_builder.build_app_task(config, task)
822-
expect(result.volume_mounted_files.size).to eq(1)
823-
expect(result.volume_mounted_files[0].path).to eq('vcap_services')
824-
end
818+
include_examples 'file-based VCAP service bindings' do
819+
let(:_app) { task.app }
820+
let(:_build) { task_recipe_builder.build_app_task(config, task) }
825821
end
826822
end
827823
end

0 commit comments

Comments
 (0)