-
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
Allow adding disks to vm provision via api and automation #13318
Allow adding disks to vm provision via api and automation #13318
Conversation
@miq-bot add_label providers/rhevm |
@miq-bot add_label automate |
@borod108 please review |
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 think its good, nice test coverage. Please look at the builder comment, except for that I think its good to go.
} | ||
# prepare disk attachment request payload of adding disk for reconfigure vm | ||
def prepare_disk(disk_spec, storage) | ||
disk_attachment_builder = DiskAttachmentBuilder.new |
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 think you should just pass options to the attachment builder (in the initializer) and encapsulate dealing with them there
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 - you're right. what's the point on having options in c'tor if not using them...
storage = options[:datastore] || vm.storage | ||
raise _("Data Store does not exist, unable to add disk") unless storage | ||
|
||
disk_attachment_builder = DiskAttachmentBuilder.new |
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 think you should just pass options to the attachment builder (in the initializer) and encapsulate dealing with them there
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
raise MiqException::MiqProvisionError, "Unable to find storage: <#{storage_name}> for disk: <#{disk_spec.inspect}>" | ||
end | ||
|
||
disk_attachment_builder = ManageIQ::Providers::Redhat::InfraManager::DiskAttachmentBuilder.new |
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
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
c0291cc
to
f6a9e41
Compare
@durandom @gmcculloug could you review ? |
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 or somebody from your team have a look at the automate/statemachine part?
Besides some minor questions this LGTM, and 👍 for adding many specs.
Maybe you want to revisit them though and check if you can use FactoryGirl.build
instead of create
in some places to save some DB calls
disks = system_service.vms_service.vm_service(destination.uid_ems).disk_attachments_service.list | ||
disks.each do |disk| | ||
fetched_disk = system_service.disks_service.disk_service(disk.id).get | ||
return true unless fetched_disk&.status == "ok" |
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.
please use fetched_disk.try(:status)
until we made the switch to 2.3
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
# prepare disk attachment request payload of adding disk for reconfigure vm | ||
def prepare_disk(disk_spec, storage) | ||
da_options = { | ||
:size_in_mb => disk_spec["disk_size_in_mb"], |
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 disk_spec
containing symbols and strings as keys? Maybe call symbolize_keys
on it?
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
@@ -103,24 +103,44 @@ def vm_reconfigure(vm, options = {}) | |||
end | |||
|
|||
def add_disks(add_disks_spec, vm) | |||
ems_storage_uid = add_disks_spec["ems_storage_uid"] |
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.
how about backwards compatablity of this method?
I'm not sure from where it get's called though
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 method was added recently for the sake of reconfigure vm - the disk spec is created internally only from app/models/manageiq/providers/redhat/infra_manager/vm/reconfigure.rb:
def build_config_spec(task_options)
{
"numCoresPerSocket" => (task_options[:cores_per_socket].to_i if task_options[:cores_per_socket]),
"memoryMB" => (task_options[:vm_memory].to_i if task_options[:vm_memory]),
"numCPUs" => (task_options[:number_of_cpus].to_i if task_options[:number_of_cpus]),
"disksRemove" => task_options[:disk_remove],
"disksAdd" => (spec_for_added_disks(task_options[:disk_add]) if task_options[:disk_add])
}
end
Therefore this is a legit spec change, without any risk to backward compatibility
end | ||
|
||
def self.true?(obj) | ||
obj.to_s == "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.
is this validating text input? This feels non ruby idiomatic to me.
The ?
methods are mostly inquiring the object it is called upon. So something like @thin_provisioned.true?
Would present?
work 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.
present? won't work since the value might be string 'true' or boolean true or false/'false'.
I'll suggest an alternative on the next patch to comply with @thin_provisioned.true? / @bootable.true?
end | ||
|
||
def self.mb_to_gb(size) | ||
size.to_i * 1024 * 1024 |
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.
maybe you can leverage http://api.rubyonrails.org/classes/Numeric.html#method-i-megabyte and inline that method?
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.
size.to_i * 1024 * 1024 | ||
end | ||
|
||
FILE_STORAGE_TYPE = %w(NFS GLUSTERFS VMFS).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.
if its just for lookup I tend to %w(A B).to_set.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.
done
signal :customize_guest | ||
else | ||
add_disks(requested_disks) | ||
signal :poll_add_disks_complete |
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 not sure, but shouldnt the signals be consistent across providers? Or somehow defined at a base class?
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, this does not need to be consistent across providers. VMware supports adding disks which happens when the initial config spec is built. Here it is happening as a post-creations step. If we add support for another provider we could possible refactor this logic then.
@masayag I have two suggests:
- Moving this method to the
state_machine.rb
file to keep thesignal
logic together. - Mark most of the methods in this file as
private
.
let(:service_vm) { MiqAeMethodService::MiqAeServiceManageIQ_Providers_Redhat_InfraManager_Vm.find(vm.id) } | ||
|
||
before do | ||
allow_any_instance_of(Vm).to receive(:my_zone).and_return('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.
Can you get rid of allow_any_instance_of
and only mock vm
and service_vm
if needed?
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
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 replaced as much FactoryGirl.create with FactoryGirl.build as I could.
I've addressed the comments. Thanks for the review.
@@ -103,24 +103,44 @@ def vm_reconfigure(vm, options = {}) | |||
end | |||
|
|||
def add_disks(add_disks_spec, vm) | |||
ems_storage_uid = add_disks_spec["ems_storage_uid"] |
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 method was added recently for the sake of reconfigure vm - the disk spec is created internally only from app/models/manageiq/providers/redhat/infra_manager/vm/reconfigure.rb:
def build_config_spec(task_options)
{
"numCoresPerSocket" => (task_options[:cores_per_socket].to_i if task_options[:cores_per_socket]),
"memoryMB" => (task_options[:vm_memory].to_i if task_options[:vm_memory]),
"numCPUs" => (task_options[:number_of_cpus].to_i if task_options[:number_of_cpus]),
"disksRemove" => task_options[:disk_remove],
"disksAdd" => (spec_for_added_disks(task_options[:disk_add]) if task_options[:disk_add])
}
end
Therefore this is a legit spec change, without any risk to backward compatibility
# prepare disk attachment request payload of adding disk for reconfigure vm | ||
def prepare_disk(disk_spec, storage) | ||
da_options = { | ||
:size_in_mb => disk_spec["disk_size_in_mb"], |
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
end | ||
|
||
def self.true?(obj) | ||
obj.to_s == "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.
present? won't work since the value might be string 'true' or boolean true or false/'false'.
I'll suggest an alternative on the next patch to comply with @thin_provisioned.true? / @bootable.true?
end | ||
|
||
def self.mb_to_gb(size) | ||
size.to_i * 1024 * 1024 |
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.
size.to_i * 1024 * 1024 | ||
end | ||
|
||
FILE_STORAGE_TYPE = %w(NFS GLUSTERFS VMFS).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.
done
disks = system_service.vms_service.vm_service(destination.uid_ems).disk_attachments_service.list | ||
disks.each do |disk| | ||
fetched_disk = system_service.disks_service.disk_service(disk.id).get | ||
return true unless fetched_disk&.status == "ok" |
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
let(:service_vm) { MiqAeMethodService::MiqAeServiceManageIQ_Providers_Redhat_InfraManager_Vm.find(vm.id) } | ||
|
||
before do | ||
allow_any_instance_of(Vm).to receive(:my_zone).and_return('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.
done
eefaf91
to
41d8a9a
Compare
signal :customize_guest | ||
else | ||
add_disks(requested_disks) | ||
signal :poll_add_disks_complete |
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, this does not need to be consistent across providers. VMware supports adding disks which happens when the initial config spec is built. Here it is happening as a post-creations step. If we add support for another provider we could possible refactor this logic then.
@masayag I have two suggests:
- Moving this method to the
state_machine.rb
file to keep thesignal
logic together. - Mark most of the methods in this file as
private
.
false | ||
end | ||
|
||
def poll_add_disks_complete |
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 method should also move to the state_machine.rb
file.
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.
Restful AP: ---------- Provisioning of RHV vm via provision restful request is extended to support disks creation. The request format is detailed below: diskscsi##=<controller_#>:<controller_position_#>:<size_in_mb> - The controller number and position are ignored for RHV. diskscsi##.datastore=<datastore name> Optional: diskscsi##.filename = <filename> diskscsi##.bootable = <true/false> Default: false diskscsi##.backing.thinProvisioned = <true/false> Default: false diskscsi##.interface = <VIRTIO/IDE/VIRTIO_SCSI/SPAPR_VSCSI> Default: VIRTIO An example of the disks section as part of the provision request: "vm_fields" : { ... "diskscsi1" : "0:0:200", "diskscsi1.datastore" : "data-40", "diskscsi1.backing.thinProvisioned" : "true", "diskscsi1.bootable" : "true", "diskscsi1.filename" : "prov_disk_1", "diskscsi1.interface": "IDE", } The result is creating a bootable disk named 'prov_disk_1' on datastore 'data-40' with size of 200MB, thinly provisioned and controlled via 'IDE' driver. Automation: ---------- Same support is added for the automation as well to allow adding disks to vm. The signature of adding disk to a vm is exposed via MiqAeServiceManageIQ_Providers_Redhat_InfraManager_Vm#add_disk(disk_name, disk_size_mb, options = {}) Where the 'options' expects: thin_provisioned - <true/false> Default: false bootable - <true/false> Default: false datastore - the storage name to create the disk on. If not specified, the VM's storage is used. interface - <VIRTIO/IDE/VIRTIO_SCSI/SPAPR_VSCSI> Default: VIRTIO
41d8a9a
to
c07d1d3
Compare
Checked commit masayag@c07d1d3 with ruby 2.2.5, rubocop 0.37.2, and haml-lint 0.16.1 app/models/manageiq/providers/redhat/infra_manager/provision/disk.rb
spec/lib/miq_automation_engine/service_methods/miq_ae_service_manageiq-providers-redhat-infra_manager-vm_spec.rb
|
@gmcculloug I've incorporated your comments into the PR, could you have a look ? I verified this via provision request, vm reconfigure via the UI and via automation request. |
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.
looks good from the provider side
@gmcculloug merge at your discretion
@miq-bot add_label euwe/yes |
@masayag Can you please create a BZ if it doesn't already exist? |
@simaishi bug url added to commit message |
…n_vm_for_rhevm Allow adding disks to vm provision via api and automation (cherry picked from commit b1ded2f) https://bugzilla.redhat.com/show_bug.cgi?id=1414893
Euwe backport details:
|
PR ManageIQ#13318 introduced a new class to handle disk attachments. A disk should be added to RHV as 'active' since there is no method to modify it afterward. DiskAttachmentBuilder class will set the 'active' as the default status of the new disk, so any scenario which adds disks (vm reconfigure, automation request, provision request) will share the same behavior. https://bugzilla.redhat.com/show_bug.cgi?id=1422145
Hello @masayag What am I missing here?
|
@psachin My guess is you are not running with these PR changes. The |
@gmcculloug Thanks. You were right, the changes were not merged. This PR has made adding additional disk to RHV so much easy using button. 👍 @masayag |
Restful AP:
Provisioning of RHV vm via provision restful request is extended
to support disks creation.
The request format is detailed below:
diskscsi##=<controller_#>:<controller_position_#>:<size_in_mb>
- The controller number and position are ignored for RHV.diskscsi##.datastore=<datastore name>
Optional:
diskscsi##.filename = <filename>
diskscsi##.bootable = <true/false> Default: false
diskscsi##.backing.thinProvisioned = <true/false> Default: false
diskscsi##.interface = <VIRTIO/IDE/VIRTIO_SCSI/SPAPR_VSCSI> Default: VIRTIO
An example of the disks section as part of the provision request:
"vm_fields" : {
...
"diskscsi1" : "0:0:200",
"diskscsi1.datastore" : "data-40",
"diskscsi1.backing.thinProvisioned" : "true",
"diskscsi1.bootable" : "true",
"diskscsi1.filename" : "prov_disk_1",
"diskscsi1.interface": "IDE",
}
The result is creating a bootable disk named 'prov_disk_1' on datastore 'data-40'
with size of 200MB, thinly provisioned and controlled via 'IDE' driver.
Automation:
Same support is added for the automation as well to allow adding disks
to vm.
The signature of adding disk to a vm is exposed via
MiqAeServiceManageIQ_Providers_Redhat_InfraManager_Vm#add_disk(disk_name, disk_size_mb, options = {})
Where the 'options' expects:
thin_provisioned - <true/false> Default: false
bootable - <true/false> Default: false
datastore - the storage name to create the disk on. If not specified, the VM's storage is used.
interface - <VIRTIO/IDE/VIRTIO_SCSI/SPAPR_VSCSI> Default: VIRTIO
https://bugzilla.redhat.com/show_bug.cgi?id=1123068