Class: ForemanOvirt::Ovirt
- Inherits:
-
ComputeResource
- Object
- ComputeResource
- ForemanOvirt::Ovirt
- Defined in:
- app/models/foreman_ovirt/ovirt.rb
Constant Summary collapse
- ALLOWED_DISPLAY_TYPES =
%w(vnc spice)
Class Method Summary collapse
Instance Method Summary collapse
- #associated_host(vm) ⇒ Object
- #available_clusters ⇒ Object
- #available_images ⇒ Object
- #available_networks(cluster_id = nil) ⇒ Object
- #available_operating_systems ⇒ Object
- #available_storage_domains(cluster_id = nil) ⇒ Object
- #capabilities ⇒ Object
- #connect(options = {}) ⇒ Object
- #connection_properties_valid? ⇒ Boolean
- #console(uuid) ⇒ Object
- #create_vm(args = {}) ⇒ Object
- #datacenters(options = {}) ⇒ Object
- #destroy_vm(uuid) ⇒ Object
- #determine_os_type(host) ⇒ Object
- #display_type ⇒ Object
- #display_type=(display) ⇒ Object
- #display_types ⇒ Object
- #editable_network_interfaces? ⇒ Boolean
- #find_vm_by_uuid(uuid) ⇒ Object
- #get_datacenter_uuid(datacenter) ⇒ Object
- #get_ovirt_id(argument_list, argument_key, argument_value) ⇒ Object
- #host_compute_attrs(host) ⇒ Object
- #image_exists?(image) ⇒ Boolean
- #instance_type(id) ⇒ Object
- #keyboard_layout ⇒ Object
- #keyboard_layout=(layout) ⇒ Object
- #networks(opts = {}) ⇒ Object
- #new_interface(attr = {}) ⇒ Object
- #new_vm(attr = {}) ⇒ Object
- #new_volume(attr = {}) ⇒ Object
- #nictypes ⇒ Object
- #normalize_vm_attrs(vm_attrs) ⇒ Object
- #ovirt_quota ⇒ Object
- #ovirt_quota=(ovirt_quota_id) ⇒ Object
- #parse_vms_list_params(params) ⇒ Object
- #preallocate_and_clone_disks(args, template) ⇒ Object
- #provided_attributes ⇒ Object
- #public_key ⇒ Object
- #public_key=(key) ⇒ Object
- #sanitize_inherited_vm_attributes(args, template, instance_type) ⇒ Object
- #save_vm(uuid, attr) ⇒ Object
- #start_vm(uuid) ⇒ Object
- #start_with_cloudinit(uuid, user_data = nil) ⇒ Object
- #storage_domains(opts = {}) ⇒ Object
- #supports_operating_systems? ⇒ Boolean
- #supports_update? ⇒ Boolean
- #supports_vms_pagination? ⇒ Boolean
- #template(id) ⇒ Object
- #test_connection(options = {}) ⇒ Object
- #update_required?(old_attrs, new_attrs) ⇒ Boolean
- #user_data_supported? ⇒ Boolean
- #validate_quota ⇒ Object
- #vm_instance_defaults ⇒ Object
- #vnic_profiles ⇒ Object
Class Method Details
.available? ⇒ Boolean
20 21 22 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 20 def self.available? Fog::Compute.providers.include?(:ovirt) end |
.model_name ⇒ Object
24 25 26 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 24 def self.model_name ComputeResource.model_name end |
.provider_friendly_name ⇒ Object
433 434 435 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 433 def self.provider_friendly_name "oVirt" end |
Instance Method Details
#associated_host(vm) ⇒ Object
429 430 431 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 429 def associated_host(vm) associate_by("mac", vm.interfaces.map(&:mac)) end |
#available_clusters ⇒ Object
230 231 232 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 230 def available_clusters clusters end |
#available_images ⇒ Object
129 130 131 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 129 def available_images templates end |
#available_networks(cluster_id = nil) ⇒ Object
234 235 236 237 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 234 def available_networks(cluster_id = nil) raise ::Foreman::Exception.new(N_('Cluster ID is required to list available networks')) if cluster_id.nil? networks({:cluster_id => cluster_id}) end |
#available_operating_systems ⇒ Object
109 110 111 112 113 114 115 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 109 def if attrs.key?(:available_operating_systems) attrs[:available_operating_systems] else raise Foreman::Exception.new("Listing operating systems is not supported by the current version") end end |
#available_storage_domains(cluster_id = nil) ⇒ Object
239 240 241 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 239 def available_storage_domains(cluster_id = nil) storage_domains end |
#capabilities ⇒ Object
38 39 40 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 38 def capabilities [:build, :image, :new_volume] end |
#connect(options = {}) ⇒ Object
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 174 def connect( = {}) return unless connection_properties_valid? update_public_key datacenters && test_https_required rescue => e case e. when /404/ errors.add(:url, e.) when /302/ errors.add(:url, _('HTTPS URL is required for API access')) when /401/ errors.add(:user, e.) else errors.add(:base, e.) end end |
#connection_properties_valid? ⇒ Boolean
192 193 194 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 192 def connection_properties_valid? errors[:url].empty? && errors[:username].empty? && errors[:password].empty? end |
#console(uuid) ⇒ Object
404 405 406 407 408 409 410 411 412 413 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 404 def console(uuid) vm = find_vm_by_uuid(uuid) raise "VM is not running!" if vm.status == "down" opts = if vm.display[:secure_port] { :host_port => vm.display[:secure_port], :ssl_target => true } else { :host_port => vm.display[:port] } end WsProxy.start(opts.merge(:host => vm.display[:address], :password => vm.ticket)).merge(:name => vm.name, :type => vm.display[:type]) end |
#create_vm(args = {}) ⇒ Object
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 282 def create_vm(args = {}) args[:comment] = args[:user_data] if args[:user_data] args[:template] = args[:image_id] if args[:image_id] template = template(args[:template]) if args[:template] instance_type = instance_type(args[:instance_type]) unless args[:instance_type].empty? args[:cluster] = get_ovirt_id(clusters, 'cluster', args[:cluster]) args[:template] = args.delete(:vm_template) if args.key?(:vm_template) sanitize_inherited_vm_attributes(args, template, instance_type) preallocate_and_clone_disks(args, template) if args[:volumes_attributes].present? && template.present? vm = super({ :first_boot_dev => 'network', :quota => ovirt_quota }.merge(args)) begin create_interfaces(vm, args[:interfaces_attributes], args[:cluster]) unless args[:interfaces_attributes].empty? create_volumes(vm, args[:volumes_attributes]) unless args[:volumes_attributes].empty? rescue => e destroy_vm vm.id raise e end vm end |
#datacenters(options = {}) ⇒ Object
196 197 198 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 196 def datacenters( = {}) client.datacenters().map { |dc| [dc[:name], dc[:id]] } end |
#destroy_vm(uuid) ⇒ Object
384 385 386 387 388 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 384 def destroy_vm(uuid) find_vm_by_uuid(uuid).destroy rescue ActiveRecord::RecordNotFound true end |
#determine_os_type(host) ⇒ Object
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 74 def determine_os_type(host) return nil unless host return host.params['ovirt_ostype'] if host.params['ovirt_ostype'] ret = "other_linux" return ret unless host. os_name = os_name_mapping(host) arch_name = arch_name_mapping(host) available = .select { |os| os[:name].present? } match_found = false best_matches = available.sort_by do |os| = 0.0 if os[:name].include?(os_name) match_found = true += 100 # prefer the shorter names a bit in case we have not found more important some specifics += (1.0 / os[:name].length) # bonus for major or major_minor += 10 if os[:name].include?("#{os_name}_#{host.operatingsystem.major}") += 5 if os[:name].include?("#{os_name}_#{host.operatingsystem.major}_#{host.operatingsystem.minor}") # bonus for architecture += 10 if arch_name && os[:name].include?(arch_name) end end unless match_found logger.debug { "No oVirt OS type found, returning other OS" } return available.first[:name] end logger.debug { "Available oVirt OS types: #{best_matches.map { |x| x[:name] }.join(',')}" } best_matches.last[:name] if best_matches.last end |
#display_type ⇒ Object
437 438 439 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 437 def display_type attrs[:display].presence || 'vnc' end |
#display_type=(display) ⇒ Object
441 442 443 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 441 def display_type=(display) attrs[:display] = display.downcase end |
#display_types ⇒ Object
151 152 153 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 151 def display_types ALLOWED_DISPLAY_TYPES end |
#editable_network_interfaces? ⇒ Boolean
212 213 214 215 216 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 212 def editable_network_interfaces? # we can't decide whether the networks are available when we # don't know the cluster_id, assuming it's possible true end |
#find_vm_by_uuid(uuid) ⇒ Object
42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 42 def find_vm_by_uuid(uuid) vm = super return unless vm vm.define_singleton_method(:vm_template) do self.template end vm rescue Fog::Ovirt::Errors::OvirtEngineError raise(ActiveRecord::RecordNotFound) end |
#get_datacenter_uuid(datacenter) ⇒ Object
200 201 202 203 204 205 206 207 208 209 210 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 200 def get_datacenter_uuid(datacenter) return @datacenter_uuid if @datacenter_uuid if Foreman.is_uuid?(datacenter) @datacenter_uuid = datacenter else @datacenter_uuid = datacenters.select { |dc| dc[0] == datacenter } raise ::Foreman::Exception.new(N_('Datacenter was not found')) if @datacenter_uuid.empty? @datacenter_uuid = @datacenter_uuid.first[1] end @datacenter_uuid end |
#get_ovirt_id(argument_list, argument_key, argument_value) ⇒ Object
307 308 309 310 311 312 313 314 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 307 def get_ovirt_id(argument_list, argument_key, argument_value) return argument_value if argument_value.blank? if argument_list.none? { |a| a.name == argument_value || a.id == argument_value } raise Foreman::Exception.new("The #{argument_key} #{argument_value} is not valid, enter a correct id or name") else argument_list.detect { |a| a.name == argument_value }.try(:id) || argument_value end end |
#host_compute_attrs(host) ⇒ Object
32 33 34 35 36 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 32 def host_compute_attrs(host) super.tap do |attrs| attrs[:os] = { :type => determine_os_type(host) } if end end |
#image_exists?(image) ⇒ Boolean
133 134 135 136 137 138 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 133 def image_exists?(image) client.templates.get(image).present? rescue => e Foreman::Logging.exception("Error while checking if image exists", e) false end |
#instance_type(id) ⇒ Object
147 148 149 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 147 def instance_type(id) client.instance_types.get(id) || raise(ActiveRecord::RecordNotFound) end |
#keyboard_layout ⇒ Object
445 446 447 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 445 def keyboard_layout attrs[:keyboard_layout].presence || 'en-us' end |
#keyboard_layout=(layout) ⇒ Object
449 450 451 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 449 def keyboard_layout=(layout) attrs[:keyboard_layout] = layout.downcase end |
#networks(opts = {}) ⇒ Object
222 223 224 225 226 227 228 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 222 def networks(opts = {}) if opts[:cluster_id] client.clusters.get(opts[:cluster_id]).networks else [] end end |
#new_interface(attr = {}) ⇒ Object
364 365 366 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 364 def new_interface(attr = {}) Fog::Ovirt::Compute::Interface.new(attr) end |
#new_vm(attr = {}) ⇒ Object
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 346 def new_vm(attr = {}) vm = super vm.define_singleton_method(:vm_template) do self.template end vm.define_singleton_method(:vm_template=) do |value| self.template = value end interfaces = nested_attributes_for :interfaces, attr[:interfaces_attributes] interfaces.map { |i| vm.interfaces << new_interface(i) } volumes = nested_attributes_for :volumes, attr[:volumes_attributes] volumes.map { |v| vm.volumes << new_volume(v) } vm end |
#new_volume(attr = {}) ⇒ Object
368 369 370 371 372 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 368 def new_volume(attr = {}) set_preallocated_attributes!(attr, attr[:preallocate]) raise ::Foreman::Exception.new(N_('VM volume attributes are not set properly')) unless attr.all? { |key, value| value.is_a? String } Fog::Ovirt::Compute::Volume.new(attr) end |
#nictypes ⇒ Object
492 493 494 495 496 497 498 499 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 492 def nictypes [ OpenStruct.new({:id => 'virtio', :name => 'VirtIO'}), OpenStruct.new({:id => 'rtl8139', :name => 'rtl8139'}), OpenStruct.new({:id => 'e1000', :name => 'e1000'}), OpenStruct.new({:id => 'pci_passthrough', :name => 'PCI Passthrough'}), ] end |
#normalize_vm_attrs(vm_attrs) ⇒ Object
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 461 def normalize_vm_attrs(vm_attrs) normalized = slice_vm_attributes(vm_attrs, ['cores', 'interfaces_attributes', 'memory']) normalized['cluster_id'] = get_ovirt_id(clusters, 'cluster', vm_attrs['cluster']) normalized['cluster_name'] = clusters.detect { |c| c.id == normalized['cluster_id'] }.try(:name) normalized['template_id'] = get_ovirt_id(templates, 'template', vm_attrs['template']) normalized['template_name'] = templates.detect { |t| t.id == normalized['template_id'] }.try(:name) cluster_networks = networks(:cluster_id => normalized['cluster_id']) interface_attrs = vm_attrs['interfaces_attributes'] || {} normalized['interfaces_attributes'] = interface_attrs.inject({}) do |interfaces, (key, nic)| interfaces.update(key => { 'name' => nic['name'], 'network_id' => nic['network'], 'network_name' => cluster_networks.detect { |n| n.id == nic['network'] }.try(:name), }) end volume_attrs = vm_attrs['volumes_attributes'] || {} normalized['volumes_attributes'] = volume_attrs.inject({}) do |volumes, (key, vol)| volumes.update(key => { 'size' => memory_gb_to_bytes(vol['size_gb']).to_s, 'storage_domain_id' => vol['storage_domain'], 'storage_domain_name' => storage_domains.detect { |d| d.id == vol['storage_domain'] }.try(:name), 'preallocate' => to_bool(vol['preallocate']), 'bootable' => to_bool(vol['bootable']), }) end normalized end |
#ovirt_quota ⇒ Object
125 126 127 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 125 def ovirt_quota attrs[:ovirt_quota_id].presence end |
#ovirt_quota=(ovirt_quota_id) ⇒ Object
121 122 123 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 121 def ovirt_quota=(ovirt_quota_id) attrs[:ovirt_quota_id] = ovirt_quota_id end |
#parse_vms_list_params(params) ⇒ Object
394 395 396 397 398 399 400 401 402 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 394 def parse_vms_list_params(params) max = (params['length'] || 10).to_i { :search => params['search']['value'] || '', :max => max, :page => (params['start'].to_i / max) + 1, :without_details => true, } end |
#preallocate_and_clone_disks(args, template) ⇒ Object
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 316 def preallocate_and_clone_disks(args, template) volumes_to_change = args[:volumes_attributes].values.select { |x| x[:id].present? } return unless volumes_to_change.present? template_disks = template.volumes disks = volumes_to_change.map do |volume| if volume[:preallocate] == '1' {:id => volume[:id], :sparse => 'false', :format => 'raw', :storage_domain => volume[:storage_domain]} else template_volume = template_disks.detect { |v| v.id == volume["id"] } {:id => volume["id"], :storage_domain => volume["storage_domain"]} if template_volume.storage_domain != volume["storage_domain"] end end.compact args.merge!(:clone => true, :disks => disks) if disks.present? end |
#provided_attributes ⇒ Object
117 118 119 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 117 def provided_attributes super.merge({:mac => :mac}) end |
#public_key ⇒ Object
453 454 455 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 453 def public_key attrs[:public_key] end |
#public_key=(key) ⇒ Object
457 458 459 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 457 def public_key=(key) attrs[:public_key] = key end |
#sanitize_inherited_vm_attributes(args, template, instance_type) ⇒ Object
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 262 def sanitize_inherited_vm_attributes(args, template, instance_type) # Override memory an cores values if template and/or instance type is/are provided. # Take template values if blank values for VM attributes, because oVirt will fail if empty values are present in VM definition # Instance type values always take precedence on templates or vm provided values if template template_cores = template.cores.to_i if template.cores.present? template_memory = template.memory.to_i if template.memory.present? args[:cores] = template_cores if template_cores && args[:cores].blank? args[:memory] = template_memory if template_memory && args[:memory].blank? end if instance_type instance_type_cores = instance_type.cores.to_i if instance_type.cores.present? instance_type_sockets = instance_type.sockets.to_i if instance_type.sockets.present? instance_type_memory = instance_type.memory.to_i if instance_type.memory.present? args[:cores] = instance_type_cores if instance_type_cores args[:sockets] = instance_type_sockets if instance_type_sockets args[:memory] = instance_type_memory if instance_type_memory end end |
#save_vm(uuid, attr) ⇒ Object
374 375 376 377 378 379 380 381 382 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 374 def save_vm(uuid, attr) vm = find_vm_by_uuid(uuid) vm.attributes.deep_merge!(attr.deep_symbolize_keys).deep_symbolize_keys update_interfaces(vm, attr[:interfaces_attributes]) update_volumes(vm, attr[:volumes_attributes]) vm.interfaces vm.volumes vm.save end |
#start_vm(uuid) ⇒ Object
247 248 249 250 251 252 253 254 255 256 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 247 def start_vm(uuid) vm = find_vm_by_uuid(uuid) if vm.comment.to_s =~ %r{cloud-config|^#!/} vm.start_with_cloudinit(:blocking => true, :user_data => vm.comment, :use_custom_script => true) vm.comment = '' vm.save else vm.start(:blocking => true) end end |
#start_with_cloudinit(uuid, user_data = nil) ⇒ Object
258 259 260 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 258 def start_with_cloudinit(uuid, user_data = nil) find_vm_by_uuid(uuid).start_with_cloudinit(:blocking => true, :user_data => user_data, :use_custom_script => true) end |
#storage_domains(opts = {}) ⇒ Object
243 244 245 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 243 def storage_domains(opts = {}) client.storage_domains({:role => ['data', 'volume']}.merge(opts)) end |
#supports_operating_systems? ⇒ Boolean
59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 59 def if client.respond_to?(:operating_systems) unless attrs.key?(:available_operating_systems) save end attrs[:available_operating_systems] != :unsupported else false end rescue Foreman::FingerprintException logger.info "Unable to verify OS capabilities, SSL certificate verification failed" false end |
#supports_update? ⇒ Boolean
55 56 57 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 55 def supports_update? true end |
#supports_vms_pagination? ⇒ Boolean
390 391 392 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 390 def supports_vms_pagination? true end |
#template(id) ⇒ Object
140 141 142 143 144 145 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 140 def template(id) compute = client.templates.get(id) || raise(ActiveRecord::RecordNotFound) compute.interfaces compute.volumes compute end |
#test_connection(options = {}) ⇒ Object
169 170 171 172 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 169 def test_connection( = {}) super connect() end |
#update_required?(old_attrs, new_attrs) ⇒ Boolean
415 416 417 418 419 420 421 422 423 424 425 426 427 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 415 def update_required?(old_attrs, new_attrs) return true if super(old_attrs, new_attrs) new_attrs[:interfaces_attributes]&.each do |key, interface| return true if (interface[:id].blank? || interface[:_delete] == '1') && key != 'new_interfaces' # ignore the template end new_attrs[:volumes_attributes]&.each do |key, volume| return true if (volume[:id].blank? || volume[:_delete] == '1') && key != 'new_volumes' # ignore the template end false end |
#user_data_supported? ⇒ Boolean
28 29 30 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 28 def user_data_supported? true end |
#validate_quota ⇒ Object
501 502 503 504 505 506 507 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 501 def validate_quota if attrs[:ovirt_quota_id].nil? attrs[:ovirt_quota_id] = client.quotas.first.id else attrs[:ovirt_quota_id] = get_ovirt_id(client.quotas, 'quota', attrs[:ovirt_quota_id]) end end |
#vm_instance_defaults ⇒ Object
334 335 336 337 338 339 340 341 342 343 344 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 334 def vm_instance_defaults super.merge( :memory => 1024.megabytes, :cores => '1', :sockets => '1', :display => { :type => display_type, :keyboard_layout => keyboard_layout, :port => -1, :monitors => 1 } ) end |
#vnic_profiles ⇒ Object
218 219 220 |
# File 'app/models/foreman_ovirt/ovirt.rb', line 218 def vnic_profiles client.list_vnic_profiles end |