ManageIQ/manageiq-providers-ovirt

View on GitHub
app/models/manageiq/providers/ovirt/infra_manager.rb

Summary

Maintainability
A
1 hr
Test Coverage
C
75%
class ManageIQ::Providers::Ovirt::InfraManager < ManageIQ::Providers::InfraManager
include ApiIntegration
include AdminUI
 
has_many :cloud_tenants, :foreign_key => :ems_id, :dependent => :destroy
has_many :vm_and_template_ems_custom_fields, :through => :vms_and_templates, :source => :ems_custom_attributes
has_many :external_distributed_virtual_switches, :dependent => :destroy, :foreign_key => :ems_id, :inverse_of => :ext_management_system
has_many :external_distributed_virtual_lans, -> { distinct }, :through => :external_distributed_virtual_switches, :source => :lans
has_many :iso_datastores, :dependent => :destroy, :foreign_key => :ems_id, :inverse_of => :ext_management_system
has_many :iso_images, :through => :storages
 
include HasNetworkManagerMixin
 
has_one :network_manager,
:foreign_key => :parent_ems_id,
:class_name => "ManageIQ::Providers::Ovirt::NetworkManager",
:autosave => true,
:inverse_of => :parent_manager,
:dependent => :destroy
 
supports :catalog
supports :create
supports :metrics
supports :provisioning
 
supports :admin_ui do
# Link to oVirt Admin UI is supported for Engine version 4.1.8 or better.
# See https://bugzilla.redhat.com/1512989 for details.
_('Admin UI is supported on version >= 4.1.8') unless version_at_least?('4.1.8')
end
 
supports :create_iso_datastore do
_("Already has an ISO datastore") unless iso_datastores.empty?
end
 
def ensure_managers
return unless enabled
ensure_network_manager
if network_manager
network_manager.name = "#{name} Network Manager"
network_manager.zone_id = zone_id
network_manager.provider_region = provider_region
network_manager.tenant_id = tenant_id
network_manager.save!
end
end
 
Method `ensure_network_manager` has a Cognitive Complexity of 16 (exceeds 11 allowed). Consider refactoring.
def ensure_network_manager
providers = ovirt_services.collect_external_network_providers
 
unless providers.blank?
providers = providers.sort_by(&:name)
auth_url = providers.first.authentication_url
end
 
if auth_url
if network_manager.nil?
ems_was_removed = false
 
if id # before update
ems = ExtManagementSystem.find_by(:id => id)
ems_was_removed = ems.nil? || !ems.enabled
end
 
build_network_manager unless ems_was_removed
end
 
if network_manager
populate_network_manager_connectivity(auth_url)
end
elsif network_manager
network_manager.destroy_queue
end
end
 
def populate_network_manager_connectivity(auth_url)
uri = URI.parse(auth_url)
network_manager.hostname = uri.host
network_manager.port = uri.port
 
network_manager.api_version = uri.path.split('/').last.split('.').first
 
if uri.instance_of?(URI::HTTPS)
network_manager.security_protocol = "ssl"
elsif uri.instance_of?(URI::HTTP)
network_manager.security_protocol = "non-ssl"
end
end
 
def self.ems_type
@ems_type ||= "ovirt".freeze
end
 
def self.description
@description ||= "oVirt".freeze
end
 
def self.vm_vendor
"ovirt".freeze
end
 
def self.host_vendor
"ovirt".freeze
end
 
def self.without_iso_datastores
includes(:iso_datastore).where(:iso_datastores => {:id => nil})
end
 
def self.any_without_iso_datastores?
without_iso_datastores.count > 0
end
 
def self.event_monitor_class
self::EventCatcher
end
 
def self.ems_settings
::Settings.ems.ems_ovirt
end
 
def self.ems_refresh_settings
::Settings.ems_refresh.ovirt
end
 
def self.params_for_create
{
:fields => [
{
:component => 'sub-form',
:id => 'endpoints-subform',
:name => 'endpoints-subform',
:title => _("Endpoints"),
:fields => [
:component => 'tabs',
:name => 'tabs',
:fields => [
{
:component => 'tab-item',
:id => 'default-tab',
:name => 'default-tab',
:title => _('Default'),
:fields => [
{
:component => 'validate-provider-credentials',
:id => 'endpoints.default.valid',
:name => 'endpoints.default.valid',
:skipSubmit => true,
:validationDependencies => %w[type zone_id],
:isRequired => true,
:fields => [
{
:component => "text-field",
:id => "endpoints.default.hostname",
:name => "endpoints.default.hostname",
:label => _("Hostname (or IPv4 or IPv6 address)"),
:isRequired => true,
:validate => [{:type => "required"}]
},
{
:component => "select",
:id => "endpoints.default.verify_ssl",
:name => "endpoints.default.verify_ssl",
:label => _("SSL verification"),
:dataType => "integer",
:isRequired => true,
:initialValue => OpenSSL::SSL::VERIFY_PEER,
:options => [
{
:label => _('Do not verify'),
:value => OpenSSL::SSL::VERIFY_NONE,
},
{
:label => _('Verify'),
:value => OpenSSL::SSL::VERIFY_PEER,
},
]
},
{
:component => "textarea",
:name => "endpoints.default.certificate_authority",
:id => "endpoints.default.certificate_authority",
:label => _("Trusted CA Certificates"),
:rows => 10,
:isRequired => true,
:helperText => _('Paste here the trusted CA certificates, in PEM format.'),
:validate => [{:type => "required"}],
:condition => {
:when => 'endpoints.default.verify_ssl',
:is => OpenSSL::SSL::VERIFY_PEER,
},
},
{
:component => "text-field",
:id => "endpoints.default.port",
:name => "endpoints.default.port",
:label => _("API Port"),
:type => "number",
:isRequired => true,
:validate => [{:type => "required"}],
:initialValue => 443,
},
{
:component => "text-field",
:id => "authentications.default.userid",
:name => "authentications.default.userid",
:label => _("Username"),
:isRequired => true,
:validate => [{:type => "required"}]
},
{
:component => "password-field",
:id => "authentications.default.password",
:name => "authentications.default.password",
:label => _("Password"),
:type => "password",
:isRequired => true,
:validate => [{:type => "required"}]
},
],
},
],
},
{
:component => 'tab-item',
:id => 'metrics-tab',
:name => 'metrics-tab',
:title => _('Metrics'),
:fields => [
Similar blocks of code found in 2 locations. Consider refactoring.
{
:component => 'protocol-selector',
:id => 'metricsEnable',
:name => 'metricsEnable',
:skipSubmit => true,
:initialValue => 'disabled',
:label => _('Enabled'),
:options => [
{
:label => _('Disabled'),
:value => 'disabled'
},
{
:label => _('Enabled'),
:value => 'enabled',
:pivot => 'endpoints.metrics.hostname'
},
],
},
{
:component => 'validate-provider-credentials',
:id => 'endpoints.metrics.valid',
:name => 'endpoints.metrics.valid',
:skipSubmit => true,
:validationDependencies => %w[type zone_id],
:condition => {
:when => 'metricsEnable',
:is => 'enabled',
},
:fields => [
{
:component => "text-field",
:id => "endpoints.metrics.hostname",
:name => "endpoints.metrics.hostname",
:isRequired => true,
:validate => [{:type => "required"}],
:label => _("Hostname (or IPv4 or IPv6 address)"),
},
{
:component => "text-field",
:id => "endpoints.metrics.port",
:name => "endpoints.metrics.port",
:label => _("API Port"),
:type => "number",
:initialValue => 5432,
},
{
:component => "text-field",
:id => "authentications.metrics.userid",
:name => "authentications.metrics.userid",
:label => _("Username"),
},
{
:component => "password-field",
:id => "authentications.metrics.password",
:name => "authentications.metrics.password",
:label => _("Password"),
:type => "password",
},
{
:component => "text-field",
:id => "endpoints.metrics.path",
:name => "endpoints.metrics.path",
:label => _("Database name"),
:initialValue => 'ovirt_engine_history',
},
],
}
],
},
{
:component => 'tab-item',
:id => 'keypair-tab',
:name => 'keypair-tab',
:title => _('RSA key pair'),
:fields => [
Similar blocks of code found in 2 locations. Consider refactoring.
{
:component => 'protocol-selector',
:id => 'keypairEnable',
:name => 'keypairEnable',
:skipSubmit => true,
:initialValue => 'disabled',
:label => _('Enabled'),
:options => [
{
:label => _('Disabled'),
:value => 'disabled'
},
{
:label => _('Enabled'),
:value => 'enabled',
:pivot => 'authentications.ssh_keypair.userid'
},
],
},
{
:component => 'validate-provider-credentials',
:id => 'endpoints.ssh_keypair.valid',
:name => 'endpoints.ssh_keypair.valid',
:skipSubmit => true,
:validationDependencies => %w[type zone_id],
:condition => {
:when => 'keypairEnable',
:is => 'enabled',
},
:fields => [
{
:component => "text-field",
:id => "authentications.ssh_keypair.userid",
:name => "authentications.ssh_keypair.userid",
:isRequired => true,
:validate => [{:type => "required"}],
:label => _("Username"),
},
{
:component => "password-field",
:id => "authentications.ssh_keypair.auth_key",
:name => "authentications.ssh_keypair.auth_key",
:componentClass => 'textarea',
:rows => 10,
:label => _("Private Key"),
},
],
}
],
},
]
]
},
]
}.freeze
end
 
def host_quick_stats(host)
qs = {}
with_provider_connection do |connection|
stats_list = connection.system_service.hosts_service.host_service(host.uid_ems)
.statistics_service.list
qs["overallMemoryUsage"] = stats_list.detect { |x| x.name == "memory.used" }
.values.first.datum
qs["overallCpuUsage"] = stats_list.detect { |x| x.name == "cpu.load.avg.5m" }
.values.first.datum
end
qs
end
 
def self.provision_class(via)
case via
when "iso" then self::ProvisionViaIso
when "pxe" then self::ProvisionViaPxe
else self::Provision
end
end
 
def self.catalog_types
{"ovirt" => N_("oVirt")}
end
 
def vm_reconfigure(vm, options = {})
ovirt_services.vm_reconfigure(vm, options)
end
 
def vm_set_memory(vm, options = {})
spec = { 'memoryMB' => options[:value] }
vm_reconfigure(vm, :spec => spec)
end
 
def vm_set_num_cpus(vm, options = {})
cpu_total = options[:value]
spec = { 'numCPUs' => cpu_total }
cpu_sockets = cpu_total / vm.cpu_cores_per_socket
spec['numCoresPerSocket'] = cpu_total if cpu_sockets < 1
vm_reconfigure(vm, :spec => spec)
end
 
def add_disks(add_disks_spec, vm)
storage = add_disks_spec[:storage]
with_disk_attachments_service(vm) do |service|
add_disks_spec[:disks].each { |disk_spec| service.add(prepare_disk(disk_spec, storage)) }
end
end
 
# prepare disk attachment request payload of adding disk for reconfigure vm
def prepare_disk(disk_spec, storage)
disk_spec = disk_spec.symbolize_keys
da_options = {
:size_in_mb => disk_spec[:disk_size_in_mb],
:storage => storage,
:name => disk_spec[:disk_name],
:thin_provisioned => disk_spec[:thin_provisioned],
:bootable => disk_spec[:bootable],
}
 
disk_attachment_builder = DiskAttachmentBuilder.new(da_options)
disk_attachment_builder.disk_attachment
end
 
# add disk to a virtual machine for a request arrived from an automation call
def vm_add_disk(vm, options = {})
storage = options[:datastore] || vm.storage
raise _("Datastore does not exist, unable to add disk") unless storage
 
da_options = {
:size_in_mb => options[:diskSize],
:storage => storage,
:name => options[:diskName],
:thin_provisioned => options[:thinProvisioned],
:bootable => options[:bootable],
:interface => options[:interface]
}
 
disk_attachment_builder = DiskAttachmentBuilder.new(da_options)
with_disk_attachments_service(vm) do |service|
service.add(disk_attachment_builder.disk_attachment)
end
end
 
def vm_migrate(vm, options = {}, timeout = 30, limit = 100)
host_id = URI(options[:host]).path.split('/').last
 
migration_options = {
:host => {
:id => host_id
}
}
 
started_time = Time.zone.now
with_vm_service(vm) do |service|
service.migrate(migration_options)
end
 
finished_event = nil
times = 0
while finished_event.nil?
times += 1
sleep timeout
finished_event = vm.ems_events.where(:event_type => %w[VM_MIGRATION_FAILED_FROM_TO VM_MIGRATION_DONE])
.find_by(EventStream.arel_table[:timestamp].gt(started_time))
if times == limit
_log.error("Migration event no received failing the request")
raise ManageIQ::Providers::Ovirt::InfraManager::OvirtServices::Error
end
end
 
raise ManageIQ::Providers::Ovirt::InfraManager::OvirtServices::Error if finished_event.event_type == "VM_MIGRATION_FAILED_FROM_TO"
end
 
def unsupported_migration_options
[:storage, :respool, :folder, :datacenter, :host_filter, :cluster]
end
 
# Migrations are supposed to work only in one cluster. If more VMs are going
# to be migrated, all have to live on the same cluster, otherwise they can
# not be migrated together.
def supports_migrate_for_all?(vms)
vms.map(&:ems_cluster).uniq.compact.size == 1
end
 
def version_at_least?(version)
return false if api_version.nil?
 
ems_version = api_version[/\d+\.\d+\.?\d*/x]
Gem::Version.new(ems_version) >= Gem::Version.new(version)
end
 
def self.display_name(number = 1)
n_('Infrastructure Provider (oVirt)', 'Infrastructure Providers (oVirt)', number)
end
end