-
Notifications
You must be signed in to change notification settings - Fork 897
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add lock to retire_now start #17280
Add lock to retire_now start #17280
Conversation
c3248ab
to
8612ffa
Compare
@miq-bot add_label retirement |
@miq_bot assign @gmcculloug |
end | ||
else | ||
_log.info("#{retirement_object_title}: [#{name}] has already started retirement") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@d-m-u
Should we log what the current state is, it might help us debugging.
Can we add some spec for the retirement_state = initializing
8612ffa
to
ff94364
Compare
raise_retirement_event(event_name, requester) | ||
rescue => err | ||
_log.log_backtrace(err) | ||
elsif retirement_state != "initializing" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tinaafitz doesn't this check also need to test for all the other states -- like retiring -- that a vm/service that is in the process of being retired could be?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
retiring needs check here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if retired
is already handled at the top of this condition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@d-m-u Right, as we discussed, "retiring" needs to be checked here. We should add a constant "initializing" with the other retirement_states.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed that if we are adding the "initializing" state it should be a constant. In addition, the retiring?
method should be updated to account for both RETIRING
and RETIREMENT_INITIALIZING
There are also two methods that call retired?
that should also be checking for retiring?
: retirement_check
and start_retirement
.
The current logic around the lock
is not preventing multiple from running since it is not reloading and checking the retirement_state
after the lock is freed.
I would purpose a flow like this:
if retired?
log existing "already retired" message
elsif retiring?
log retirement in-progress message
else
lock do
reload object # in case object was updated in separate process while waiting for lock to be released
if retirement_state is blank or "error"
process retirement
else
log that retirement_state was updated while waiting to lock to be released and log current retirement_state value. No further action.
end
end
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gmcculloug Yes, I agree that:
- The
retiring?
method should include both theRETIRING
andRETIREMENT_INITIALIZING
retirement_states. - The
retirement_check
andstart_retirement
methods should check forretiring?
I propose that we add one more method, retirement_initialized
to check for the retirement_state of RETIREMENT_INITIALIZING
for the start_retirement Automate method to check that the object has been initialized for retirement. The start_retirement Automate method currently checks for retired?
and retiring?
. The retiring?
check should be replaced with retirement_initialized
method to prevent the retirement state machine from processing an object that was not "initialized" for retirement.(This could happen if someone directly called the retirement state machine without having gone through retire_now
.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@d-m-u We'll have to modify the start_retirement Automate methods to check for the retirement_state of "initializing".
@@ -27,6 +27,7 @@ | |||
expect(@service.retirement_state).to be_nil | |||
expect(MiqEvent).to receive(:raise_evm_event).once | |||
@service.retire_now | |||
expect(@service.retirement_state).to eq('initializing') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@d-m-u Can we add more tests for the various possible retirement_states?
@@ -29,6 +29,7 @@ | |||
expect(MiqEvent).to receive(:raise_evm_event).once | |||
|
|||
@vm.retire_now | |||
expect(@vm.retirement_state).to eq('initializing') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@d-m-u same here.
raise_retirement_event(event_name, requester) | ||
rescue => err | ||
_log.log_backtrace(err) | ||
elsif retirement_state != "initializing" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@d-m-u Right, as we discussed, "retiring" needs to be checked here. We should add a constant "initializing" with the other retirement_states.
6244b3f
to
4822937
Compare
4822937
to
9f9fca9
Compare
@@ -110,7 +111,7 @@ def raise_retire_audit_event(message) | |||
end | |||
|
|||
def retirement_check | |||
return if self.retired? | |||
return if retired? || retiring? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@d-m-u We should check for retirement_initialized
here as well.
9f9fca9
to
4cc59b1
Compare
RETIRED = 'retired'.freeze | ||
RETIRING = 'retiring'.freeze | ||
ERROR_RETIRING = 'error'.freeze | ||
RETIREMENT_INITIALIZING = 'initializing'.freeze |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do these constants get used outside of this module? If not it would be nice to standardize on naming and sort them. I would suggest something like:
RETIREMENT_ERROR = 'error'.freeze
RETIREMENT_INITIALIZING = 'initializing'.freeze
RETIREMENT_RETIRED = 'retired'.freeze
RETIREMENT_RETIRING = 'retiring'.freeze
@@ -170,6 +180,10 @@ def retirement_base_model_name | |||
@retirement_base_model_name ||= self.class.base_model.name | |||
end | |||
|
|||
def retirement_initialized |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be def retirement_initialized?
_log.log_backtrace(err) | ||
lock do | ||
reload | ||
if retirement_state == '' || retirement_state == 'error' || retirement_state.nil? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simplify to: if error_retiring? || retirement_state.blank?
4cc59b1
to
10be4c6
Compare
@tinaafitz can you re-review please? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gmcculloug can you give this another 👀 please? |
expect(MiqEvent).to receive(:raise_evm_event).once | ||
@service.retire_now | ||
@service.retire_now | ||
@service.retire_now |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can I be a pain and ask this to be 3.times { @service.retire_now }
? 😬
|
||
@vm.retire_now | ||
@vm.retire_now | ||
@vm.retire_now |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
@vm.update_attributes(:retirement_state => 'retiring') | ||
expect(MiqEvent).to receive(:raise_evm_event).exactly(0).times | ||
@vm.retire_now | ||
@vm.reload |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are these reload
calls needed at the end of many of these tests?
10be4c6
to
d6b63e1
Compare
Checked commits d-m-u/manageiq@7bbd902~...d6b63e1 with ruby 2.3.3, rubocop 0.52.1, haml-lint 0.20.0, and yamllint 1.10.0 app/models/mixins/retirement_mixin.rb
|
@gmcculloug can you add the gaprindashvili/yes and fine/yes labels if this can be back-ported. |
Add lock to retire_now start (cherry picked from commit 2deffa5) Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1570950
Gaprindashvili backport details:
|
Add lock to retire_now start (cherry picked from commit 2deffa5) Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1570951
Fine backport details:
|
Add lock to retire_now start (cherry picked from commit 2deffa5) Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1570951
This is a solution for the fact that in a multi-appliance setup we can have multiple workers start retirement for the same service or vm.
(this needs to be backported but the following doesn't):
DO NOT BACKPORT THE RELATED CONTENT PR PLEASE
related to:
ManageIQ/manageiq-content#281
Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1563627