11require 'jobs/v3/delete_service_instance_job'
2+ require 'actions/services/locks/deleter_lock'
3+ require 'cloud_controller/errors/api_error'
24
35module VCAP ::CloudController
46 module V3
57 class ServiceInstanceDelete
6- class AssociationNotEmptyError < StandardError ; end
8+ class AssociationNotEmptyError < StandardError
9+ end
10+
11+ class InstanceSharedError < StandardError
12+ end
13+
14+ class DeleteFailed < StandardError
15+ end
716
8- class InstanceSharedError < StandardError ; end
17+ DeleteStatus = Struct . new ( :finished , :operation ) . freeze
18+ DeleteStarted = -> ( operation ) { DeleteStatus . new ( false , operation ) }
19+ DeleteComplete = DeleteStatus . new ( true , nil ) . freeze
920
10- def initialize ( event_repo )
21+ PollingStatus = Struct . new ( :finished , :retry_after ) . freeze
22+ PollingFinished = PollingStatus . new ( true , nil ) . freeze
23+ ContinuePolling = -> ( retry_after ) { PollingStatus . new ( false , retry_after ) }
24+
25+ def initialize ( service_instance , event_repo )
26+ @service_instance = service_instance
1127 @service_event_repository = event_repo
1228 end
1329
14- def delete ( service_instance )
15- association_not_empty! if service_instance . has_bindings? || service_instance . has_keys? || service_instance . has_routes?
30+ def delete
31+ operation_in_progress! if service_instance . operation_in_progress? && service_instance . last_operation . type != 'create'
32+
33+ result = send_deprovison_to_broker
34+ if result [ :finished ]
35+ destroy
36+ record_delete_event
37+ else
38+ update_last_operation_with_operation_id ( result [ :operation ] )
39+ record_start_delete_event
40+ end
1641
42+ result
43+ rescue => e
44+ update_last_operation_with_failure ( e . message ) unless service_instance . operation_in_progress?
45+ raise e
46+ end
47+
48+ def delete_checks
49+ association_not_empty! if service_instance . has_bindings? || service_instance . has_keys? || service_instance . has_routes?
1750 cannot_delete_shared_instances! if service_instance . shared?
51+ end
1852
19- lock = DeleterLock . new ( service_instance )
53+ def poll
54+ result = client . fetch_service_instance_last_operation ( service_instance )
55+ case result [ :last_operation ] [ :state ]
56+ when 'in progress'
57+ update_last_operation_with_description ( result [ :last_operation ] [ :description ] )
58+ ContinuePolling . call ( result [ :retry_after ] )
59+ when 'succeeded'
60+ destroy
61+ PollingFinished
62+ else
63+ delete_failed! ( result [ :last_operation ] [ :description ] )
64+ end
65+ rescue DeleteFailed => e
66+ update_last_operation_with_failure ( e . message )
67+ raise CloudController ::Errors ::ApiError . new_from_details ( 'UnableToPerform' , 'delete' , e . message )
68+ rescue => e
69+ update_last_operation_with_failure ( e . message )
70+ ContinuePolling . call ( nil )
71+ end
72+
73+ def update_last_operation_with_failure ( message )
74+ service_instance . save_with_new_operation (
75+ { } ,
76+ {
77+ type : 'delete' ,
78+ state : 'failed' ,
79+ description : message ,
80+ }
81+ )
82+ end
2083
84+ private
85+
86+ attr_reader :service_event_repository , :service_instance
87+
88+ def client
89+ VCAP ::Services ::ServiceClientProvider . provide ( instance : service_instance )
90+ end
91+
92+ def send_deprovison_to_broker
93+ result = client . deprovision ( service_instance , accepts_incomplete : true )
94+ return DeleteComplete if result [ :last_operation ] [ :state ] == 'succeeded'
95+
96+ DeleteStarted . call ( result [ :last_operation ] [ :broker_provided_operation ] )
97+ end
98+
99+ def record_delete_event
21100 case service_instance
22- when ManagedServiceInstance
23- return false
24- when UserProvidedServiceInstance
25- lock . lock!
26- synchronous_destroy ( service_instance , lock )
27- return true
101+ when VCAP ::CloudController ::ManagedServiceInstance
102+ service_event_repository . record_service_instance_event ( :delete , service_instance )
103+ when VCAP ::CloudController ::UserProvidedServiceInstance
104+ service_event_repository . record_user_provided_service_instance_event ( :delete , service_instance )
28105 end
29106 end
30107
31- private
108+ def record_start_delete_event
109+ service_event_repository . record_service_instance_event ( :start_delete , service_instance )
110+ end
32111
33- def synchronous_destroy ( service_instance , lock )
34- lock . unlock_and_destroy!
35- service_event_repository . record_user_provided_service_instance_event ( :delete , service_instance )
36- nil
112+ def destroy
113+ ServiceInstance . db . transaction do
114+ service_instance . lock!
115+ service_instance . last_operation &.destroy
116+ service_instance . destroy
117+ end
118+ end
119+
120+ def update_last_operation_with_operation_id ( operation_id )
121+ service_instance . save_with_new_operation (
122+ { } ,
123+ {
124+ type : 'delete' ,
125+ state : 'in progress' ,
126+ broker_provided_operation : operation_id
127+ }
128+ )
129+ end
130+
131+ def update_last_operation_with_description ( description )
132+ lo = service_instance . last_operation . to_hash
133+ lo [ :broker_provided_operation ] = service_instance . last_operation . broker_provided_operation
134+ lo [ :description ] = description
135+ service_instance . save_with_new_operation ( { } , lo )
37136 end
38137
39138 def association_not_empty!
@@ -44,7 +143,13 @@ def cannot_delete_shared_instances!
44143 raise InstanceSharedError
45144 end
46145
47- attr_reader :service_event_repository
146+ def operation_in_progress!
147+ raise CloudController ::Errors ::ApiError . new_from_details ( 'AsyncServiceInstanceOperationInProgress' , service_instance . name )
148+ end
149+
150+ def delete_failed! ( message )
151+ raise DeleteFailed . new ( message )
152+ end
48153 end
49154 end
50155end
0 commit comments