Skip to content
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 conversion_host_id to miq_request_task #281

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
class AddConversionHostIdToMiqRequestTasks < ActiveRecord::Migration[5.0]
class MiqRequestTask < ActiveRecord::Base
self.inheritance_column = :_type_disabled
serialize :options, Hash
belongs_to :conversion_host, :class_name => "AddConversionHostIdToMiqRequestTasks::ConversionHost"
This conversation was marked as resolved.
Show resolved Hide resolved
end

class ServiceTemplateTransformationPlanTask < MiqRequestTask
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be removed ... See my other comments about STI and using the base class for querying.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

end

class ConversionHost < ActiveRecord::Base
self.inheritance_column = :_type_disabled
has_many :service_template_transformation_plan_tasks, :class_name => "AddConversionHostIdToMiqRequestTasks::MiqRequestTask"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This relation isn't being used in the migration, why define it here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. Removed.

end

class Host < ActiveRecord::Base
self.inheritance_column = :_type_disabled
has_many :tags, :class_name => "AddConversionHostIdToMiqRequestTasks::Tag"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this relation needed?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remnant of tests. Removed.

end

def up
add_column :miq_request_tasks, :conversion_host_id, :bigint

ServiceTemplateTransformationPlanTask.all.reject { |task| task.options[:transformation_host_id].nil? }.each do |task|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few things here ...
First, I don't think this query will work the way you're intending it to. STI is disabled so I think you would be better off using the base class and specifying the type in a where clause.

Also, instead of using reject here, can we make this a guard clause in the each block? That will simplify this and prevent us from iterating through the list of tasks twice.

So something like this:

MiqRequestTask.where(:type => "ServiceTemplateTransformationPlanTask").each do |task|
  next unless task.options[:transformation_host_id]
  ...
end

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the tip. Updated.

host = Host.find_by(:id => task.options[:transformation_host_id])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can use find rather than find_by. Also this entire block would be way easier to read if task.options[:transformation_host_id] was stored in a local variable (ideally before the guard clause).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably throw in a next if host.nil? since you're using host.name, host.type, ... below just in case the host was deleted and the task options weren't updated which given they aren't kept in sync by refresh is a distinct possibility.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, if that's a possibility @agrare then we should also keep the find_by (find raises if the record doesn't exist).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added test on host.nil?

task.conversion_host = ConversionHost.where(:id => task.options[:transformation_host_id]).first_or_create do |ch|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

find_or_create_by! would be better over .where(:id => ...).first_or_create

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, if options[:transformation_host_id] is a reference to the Host record id then it can't also be a reference to the ConversionHost id.

This where just looks wrong.

Copy link
Member

@agrare agrare Oct 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah good catch, @fdupont-redhat did you mean to ConversionHost.where(:id => host.conversion_host.try(:id)) or something?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed for find_or_create_by!.
The where was wrong. Now it checks the resource_id attribute against the host_id.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should check for the type also then, just checking for the id and not the type

ch.name = host.name
ch.resource_type = host.type
ch.resource_id = host.id
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be able to just do ch.resource = host here

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When using find_or_create_by! the resource_id attribute is already set, so now I simply add the resource_type.

ch.address = host.ipaddress
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're going to delegate ipaddress to the resource per #242 (comment) then we should leave this blank in the conversion_host record. That way if the host ip address changes it will be automatically picked up.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.

ch.vddk_transport_supported = true
ch.ssh_transport_supported = false
end
task.options.delete(:transformation_host_id)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing the delete here means that we will not remove this option from the existing hash if we can't find the host in the existing inventory. Is that the behavior we are expecting?

If it's okay to remove the host id from the hash either way, then you can replace the right hand side of the host_id assignment with this line.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think it's fixed, but please double-check.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so if this host is gone from db, removing it from options seems better.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fdupont-redhat you can probably move it up here and save a LOC

task.save!
end
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the #up method looks good to me now


def down
ServiceTemplateTransformationPlanTask.all.select { |task| task.conversion_host.present? }.each do |task|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, use the base class and you don't need to loop through the tasks twice.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

task.options[:transformation_host_id] = task.conversion_host.id
ConversionHost.find(task.conversion_host.id).destroy!
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just pass the id to destroy like ConversionHost.destroy(task.conversion_host.id)

For performance it might be better to .map the conversion host ids that you want to destroy and issue one query after the loop like conversion_host_ids = MiqRequestTask.where().map { |task| }; ConversionHost.destroy(conversion_host_ids)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

task.save!
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should .uniq also since there will be many tasks with the same conversion host. You can do end.uniq.compact or ConversionHost.destroy(conversion_host_ids.uniq.compact) your call


remove_column :miq_request_tasks, :conversion_host_id
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
require_migration

describe AddConversionHostIdToMiqRequestTasks do
let(:task_stub) { migration_stub(:MiqRequestTask) }
let(:host_stub) { migration_stub(:Host) }
let(:conversion_host_stub) { migration_stub(:ConversionHost) }

migration_context :up do
agrare marked this conversation as resolved.
Show resolved Hide resolved
it "creates conversion host" do
task = task_stub.create!
host = host_stub.create!
conversion_host = conversion_host_stub.create!(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just do .create!(:resource => host) no need to split up the id/type

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you creating a ConversionHost in a spec that should be testing that a conversion host is created?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question @carbonin. Probably, because I'm dumb 😄
Removed and spec updated.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@agrare It fails if I use :resource => host. The error message is:

ActiveModel::UnknownAttributeError:
       unknown attribute 'resource' for AddConversionHostIdToMiqRequestTasks::ConversionHost.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably need to add the relation to the stubbed model

:resource_id => host.id,
:resource_type => host.type
)
task.options = { :transformation_host_id => conversion_host.id }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can pass :options => {:trans....} into the create!() and then you don't need the extra save

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, shouldn't this be a Host reference, not a conversion_host reference?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

task.save

migrate
This conversation was marked as resolved.
Show resolved Hide resolved

task.reload
expect(task.options).to eq({})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add another dummy key in this options field and here check only that :transformation_host_id is removed?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

expect(task.conversion_host).to eq(conversion_host)
end
end

migration_context :down do
it "updates task.options" do
task = task_stub.create!
host = host_stub.create!
conversion_host = conversion_host_stub.create!(
:resource_id => host.id,
:resource_type => host.type
This conversation was marked as resolved.
Show resolved Hide resolved
)
conversion_host.save
task.conversion_host = conversion_host
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise just pass :conversion_host in to the .create!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

task.save

migrate

task.reload
expect(task.attributes).not_to include('conversion_host_id')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to check that ActiveRecord deleted the column, if that is broken we have bigger issues

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

expect(task.options[:transformation_host_id]).to eq(conversion_host.id)
expect { conversion_host.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
end
end