-
Notifications
You must be signed in to change notification settings - Fork 898
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
Provider to orchestrate_destroy managers first #16614
Conversation
47f9751
to
19448cf
Compare
app/models/ext_management_system.rb
Outdated
@@ -473,7 +473,11 @@ def orchestrate_destroy | |||
before_destroy :assert_no_queues_present | |||
|
|||
def assert_no_queues_present | |||
throw(:abort) if MiqWorker.find_alive.where(:queue_name => queue_name).any? | |||
if enabled? | |||
orchestrate_destroy |
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.
The method name doesn't sound like it would lead to the manager being destroyed...
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.
@bdunne I have a different approach now.
19448cf
to
575f053
Compare
575f053
to
c51285e
Compare
@miq-bot add_label blocker |
c51285e
to
935ac6f
Compare
app/models/provider.rb
Outdated
return destroy | ||
end | ||
|
||
if managers.collect(&:enabled).any? |
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.
managers.where(:enabled => true).any?
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.
done
spec/models/provider_spec.rb
Outdated
end | ||
|
||
it "call orchestrate_destroy its managers first" do | ||
expect(manager).to receive(:enabled) { true } |
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.
Don't do this, just manager = FactoryGirl.create(:ext_management_system, :enabled => true)
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.
done
spec/models/provider_spec.rb
Outdated
end | ||
|
||
it "doesn't orchestrate_destroy its managers when they are disabled" do | ||
expect(manager).to receive(:enabled) { false } |
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: manager = FactoryGirl.create(:ext_management_system, :enabled => false)
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.
done
spec/models/provider_spec.rb
Outdated
|
||
it "queues itself for orchestrate_destroy when managers exists" do | ||
allow(Time).to receive(:now).and_return(Time.zone.now) | ||
provider.managers = [manager] |
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.
Should this be an enabled manager or are you depending on default_value_for
? If so, why not depend on it above?
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.
I've combined this test with the others
spec/models/provider_spec.rb
Outdated
provider.managers = [manager] | ||
expect(manager).to receive(:destroy_queue) | ||
expect(provider).not_to receive(:destroy) | ||
expect(described_class).to receive(:_queue_task).with(:destroy_queue, provider.id.to_miq_a, 15.seconds.from_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.
Typically we expect(MiqQueue.find_by(:class_name =>"X", instance_id => n, ...).to have_attributes(…)
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.
I'd like to keep these tests remains in the scope of this destroy_queue
. Testing of resulting effect in MiqQueue
would belong to those for _queue_task
method (or the subsequently called MiqQueue.put
.
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.
@Fryguy what do you think?
05de14e
to
2723561
Compare
spec/models/provider_spec.rb
Outdated
|
||
context "#destroy_queue" do | ||
before do | ||
allow(Time).to receive(:now).and_return(Time.zone.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.
Is this necessary?
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.
yes, so that the 15.seconds.from_now
check would be matched.
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.
Using the MiqQueue.where(…).to have_attributes()
would solve this.
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.
ok, just did what you've requested
spec/models/provider_spec.rb
Outdated
manager = FactoryGirl.create(:ext_management_system, :enabled => false) | ||
provider.managers = [manager] | ||
expect(manager).not_to receive(:destroy_queue) | ||
expect(provider).not_to receive(:destroy) |
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.
Won't this case sit in a loop forever?
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 is the case when managers are already in the process of being destroyed. Manager are being disabled first to signal to their workers to go down. Refer to 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.
I feel like there are edge cases that aren't covered here. (A provider added but it's disabled for some reason)
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 you elaborate a bit more? You mean test cases?
Provider
doesn't have enabled/disabled
state.
I'm still of the opinion that the UI should queue a |
ExtManagementSystem's existing before_destroy will block it from being destroyed because it takes time between the manager being set as And the provider will remain. |
2723561
to
fd1a0fe
Compare
app/models/provider.rb
Outdated
@@ -63,4 +63,20 @@ def refresh_ems(opts = {}) | |||
end | |||
managers.flat_map { |manager| EmsRefresh.queue_refresh(manager, nil, opts) } | |||
end | |||
|
|||
def self.destroy_queue(ids) | |||
find(Array.wrap(ids)).each(&:destroy_queue) |
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.
You should not need the Array.wrap...
Vm.find(21000000005058, 21000000005063, 21000000005064).size
# => 3
Vm.find([21000000005058, 21000000005063, 21000000005064]).size
# => 3
Unless there's some other edge condition I'm not seeing?
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.
modeled after ext_management_system
I will remove Array.wrap
then.
app/models/provider.rb
Outdated
def destroy_queue | ||
if managers.empty? | ||
return destroy | ||
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.
inline the conditional for readability.
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.
done
app/models/provider.rb
Outdated
end | ||
|
||
_log.info("Queuing destroy of managers of provider: #{self.class.name} with id: #{id}") | ||
managers.flat_map(&:destroy_queue) |
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 you flat_map
ping and then not using the return value... just use .each
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.
haha, it was before
using .each
now. thanks!
app/models/provider.rb
Outdated
managers.flat_map(&:destroy_queue) | ||
|
||
_log.info("Queuing destroy of provider: #{self.class.name} with id: #{id}") | ||
self.class._queue_task(:destroy_queue, id.to_miq_a, 15.seconds.from_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.
No need for the .to_miq_a
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.
Or more specifically, it might be cleaner to use Array.wrap
in the _queue_task
method itself.
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.
done
spec/models/provider_spec.rb
Outdated
it "destroy when has no managers" do | ||
expect(provider).to receive(:destroy) | ||
provider.destroy_queue | ||
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.
What? If we are asking the provider to destroy something over the queue, then we would expect the provider to_not receive destroy.
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 is when there's NO manager. Provider will be destroyed.
Probably I can add an explicit provider.managers =[]
to make it more obvious.
spec/models/provider_spec.rb
Outdated
end | ||
|
||
it "to destroy_queue its managers and itself" do | ||
manager = FactoryGirl.create(:ext_management_system, :zone => EvmSpecHelper.local_miq_server.zone) |
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.
I thought an EMS factory uses the local zone by default?
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.
It's not, I have to add this :zone
in order not to fail at nil
zone
100% agree with this. The UI should just queue up a provider destroy, perhaps with a task so the user can see the progress. cc @blomquisg |
@Fryguy UI is already queuing Or am I missing something? |
fd1a0fe
to
c096d2a
Compare
@jameswnl https://github.com/ManageIQ/manageiq/pull/16614/files#diff-eeaf9199fba4aed486bc440604e87bf9R72 |
155ac43
to
b70929e
Compare
#16755 - a bit different implementation using |
Checked commit jameswnl@4a87a55 with ruby 2.3.3, rubocop 0.47.1, haml-lint 0.20.0, and yamllint 1.10.0 |
|
||
def destroy(task_id = nil) | ||
_log.info("To destroy managers of provider: #{self.class.name} with id: #{id}") | ||
managers.each(&:destroy) |
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.
@Fryguy @blomquisg @bdunne need some help here. This manager
destroy
is not triggering the destroy of managers' associated resources e.g. configured_system
etc.
That is failing the corresponding Tower PR. If revert the [Tower PR], the spec would pass and I can observe in debug that the configued_system
resources are being destroyed in the subsequent super().tap
call.
Not sure if this has to do with the fact that :dependent => destroy
between ems
and configured_system
is being defined in the subclasses (in AutomationManager
namespace 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.
@jameswnl Do you have a test that fails that you can share with us?
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.
Closing this and pursuit in #16755 |
https://bugzilla.redhat.com/show_bug.cgi?id=1491704
https://bugzilla.redhat.com/show_bug.cgi?id=1510179
Destroying Ansible Tower Provider and Foreman Provider is being rolled back because the associated manager is being held up by workers (introduced by #14675)
Implemented
destroy_queue
for Provider:managers
, invoke destroy and doneorchestrate_destroy
of managers if they are notdisabled
yetdestroy_queue