Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 0 additions & 33 deletions app/controllers/internal/staging_completion_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,39 +16,6 @@ def inject_dependencies(dependencies)
@stagers = dependencies.fetch(:stagers)
end

post '/internal/v3/staging/:staging_guid/droplet_completed', :droplet_completed # NOT USED, only for rolling deploys
def droplet_completed(staging_guid)
staging_response = read_body
droplet = DropletModel.find(guid: staging_guid)
raise CloudController::Errors::ApiError.new_from_details('ResourceNotFound', 'Droplet not found') if droplet.nil?

build = BuildModel.create(package: droplet.package, app: droplet.app, state: DropletModel::STAGING_STATE)

BuildModel.db.transaction do
build.lock!
build.update(
droplet: droplet,
buildpack_lifecycle_data: droplet.buildpack_lifecycle_data
)
end

if staging_response.key?(:failed)
report_metrics(staging_response)
staging_response = parse_bbs_task_callback(staging_response)
end

begin
stagers.stager_for_build(build).staging_complete(build, staging_response, params['start'] == 'true')
rescue CloudController::Errors::ApiError => e
raise e
rescue StandardError => e
logger.error('diego.staging.completion-controller-error', error: e)
raise CloudController::Errors::ApiError.new_from_details('ServerError')
end

[200, '{}']
end

post '/internal/v3/staging/:staging_guid/build_completed', :build_completed
def build_completed(staging_guid)
staging_response = read_body
Expand Down
151 changes: 0 additions & 151 deletions spec/unit/controllers/internal/staging_completion_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,157 +52,6 @@ module VCAP::CloudController
allow(VCAP::CloudController::Metrics::PrometheusUpdater).to receive(:new).and_return(prometheus_updater)
end

context 'staging a package through /droplet_completed (legacy for rolling deploy)' do
let(:url) { "/internal/v3/staging/#{staging_guid}/droplet_completed" }
let(:staged_app) { create(:app_model) }
let(:package) { create(:package_model, state: 'READY', app_guid: staged_app.guid) }
let(:droplet) { create(:droplet_model, package_guid: package.guid, app_guid: staged_app.guid, state: DropletModel::STAGING_STATE) }
let(:staging_guid) { droplet.guid }

context 'when it is a docker app' do
let(:staged_app) { create(:app_model, :docker) }
let(:package) { create(:package_model, :docker, state: 'READY', app_guid: staged_app.guid) }
let(:droplet) { create(:droplet_model, :docker, package_guid: package.guid, app_guid: staged_app.guid, state: DropletModel::STAGING_STATE) }

it 'calls the stager with a build created from the droplet and the response' do
expect_any_instance_of(Diego::Stager).to receive(:staging_complete).with(instance_of(BuildModel), staging_response, false)

post url, Oj.dump(staging_response)

build = BuildModel.last
expect(build).not_to be_nil
expect(build.lifecycle_type).to eq('docker')

expect(last_response.status).to eq(200)
end
end

context 'when it is a buildpack app' do
it 'calls the stager with a build created from the droplet and the response' do
expect_any_instance_of(Diego::Stager).to receive(:staging_complete).with(instance_of(BuildModel), staging_response, false)

post url, Oj.dump(staging_response)

build = BuildModel.last
expect(build).not_to be_nil
expect(build.lifecycle_type).to eq('buildpack')

expect(last_response.status).to eq(200)
end
end

it 'propagates api errors from staging_response' do
expect_any_instance_of(Diego::Stager).to receive(:staging_complete).and_raise(CloudController::Errors::ApiError.new_from_details('JobTimeout'))

post url, Oj.dump(staging_response)
expect(last_response.status).to eq(524)
expect(last_response.body).to match(/JobTimeout/)
end

context 'when receiving the callback directly from BBS' do
let(:staging_result) do
{
lifecycle_type: 'buildpack',
lifecycle_metadata: {
buildpack_key:,
detected_buildpack:
},
execution_metadata: execution_metadata,
process_types: { web: 'start me' }
}
end
let(:failure_reason) { '' }
let(:sanitized_failure_reason) { double(:sanitized_failure_reason) }
let(:staging_result_json) { Oj.dump(staging_result) }
let(:staging_response) do
{
failed: failure_reason.present?,
failure_reason: failure_reason,
result: staging_result_json,
created_at: (Time.now.utc.to_i - one_hour) * 1e9
}
end

before do
allow(Diego::FailureReasonSanitizer).to receive(:sanitize).with(failure_reason).and_return(sanitized_failure_reason)
end

it 'calls the stager with a build for the droplet and response' do
expect_any_instance_of(Diego::Stager).to receive(:staging_complete).with(instance_of(BuildModel), { result: staging_result }, false)

post url, Oj.dump(staging_response)
expect(last_response.status).to eq(200)
end

it 'propagates api errors from staging_response' do
expect_any_instance_of(Diego::Stager).to receive(:staging_complete).and_raise(CloudController::Errors::ApiError.new_from_details('JobTimeout'))

post url, Oj.dump(staging_response)
expect(last_response.status).to eq(524)
expect(last_response.body).to match(/JobTimeout/)
end

it 'emits metrics for staging success' do
one_hour_in_nanoseconds = (1.hour.to_i * 1e9).to_i
expect(statsd_updater).to receive(:report_staging_success_metrics).with(one_hour_in_nanoseconds)
expect(prometheus_updater).to receive(:report_staging_success_metrics).with(one_hour_in_nanoseconds)
Timecop.freeze(Time.now) do
post url, Oj.dump(staging_response)
end
end

context 'when staging failed' do
let(:failure_reason) { 'something went wrong' }
let(:staging_result_json) { nil }

it 'passes down the sanitized version of the error to the diego stager' do
expect_any_instance_of(Diego::Stager).to receive(:staging_complete).with(instance_of(BuildModel), { error: sanitized_failure_reason }, false)

post url, Oj.dump(staging_response)
end

it 'emits metrics for staging failure' do
one_hour_in_nanoseconds = (1.hour.to_i * 1e9).to_i
expect(statsd_updater).to receive(:report_staging_failure_metrics).with(one_hour_in_nanoseconds)
expect(prometheus_updater).to receive(:report_staging_failure_metrics).with(one_hour_in_nanoseconds)
Timecop.freeze(Time.now) do
post url, Oj.dump(staging_response)
end
end
end
end

context 'when the droplet does not exist' do
let(:staging_guid) { 'asdf' }

it 'returns 404' do
post url, Oj.dump(staging_response)
expect(last_response.status).to eq(404)
expect(last_response.body).to match(/Droplet not found/)
end
end

context 'when the start query param has a true value' do
it 'requests staging_complete with start' do
expect_any_instance_of(Diego::Stager).to receive(:staging_complete).with(instance_of(BuildModel), staging_response, true)

post "#{url}?start=true", Oj.dump(staging_response)
expect(last_response.status).to eq(200)
end
end

describe 'validation' do
context 'when sending invalid json' do
it 'fails with a 400' do
post url, 'this is not json'

expect(last_response.status).to eq(400)
expect(last_response.body).to match(/MessageParseError/)
end
end
end
end

describe '/build_completed' do
let(:url) { "/internal/v3/staging/#{staging_guid}/build_completed" }
let(:staged_app) { create(:app_model) }
Expand Down
Loading