foreman/app/models/compute_resources/foreman/model/ovirt.rb @ 6a85948c
85ed3c3f | Dominic Cleal | require 'uri'
|
|
334d0359 | Amos Benari | module Foreman::Model
|
|
class Ovirt < ComputeResource
|
|||
f2c78d4a | Joseph Magen | validates :url, :format => { :with => URI.regexp }
|
|
validates :user, :password, :presence => true
|
|||
7e031001 | Ohad Levy | ||
334d0359 | Amos Benari | def self.model_name
|
|
ComputeResource.model_name
|
|||
end
|
|||
dd42df0a | Ohad Levy | def capabilities
|
|
[:build]
|
|||
end
|
|||
a6a6b703 | David Swift | def supports_update?
|
|
true
|
|||
end
|
|||
dd42df0a | Ohad Levy | def provided_attributes
|
|
super.merge({:mac => :mac})
|
|||
end
|
|||
334d0359 | Amos Benari | #FIXME
|
|
def max_cpu_count
|
|||
8
|
|||
end
|
|||
def max_memory
|
|||
16*1024*1024*1024
|
|||
end
|
|||
180d7f43 | Jason Montleon | def quotas
|
|
client.quotas
|
|||
end
|
|||
def ovirt_quota=(ovirt_quota_id)
|
|||
self.attrs[:ovirt_quota_id] = ovirt_quota_id
|
|||
end
|
|||
def ovirt_quota
|
|||
self.attrs[:ovirt_quota_id]
|
|||
end
|
|||
334d0359 | Amos Benari | def hardware_profiles(opts={})
|
|
client.templates
|
|||
end
|
|||
def hardware_profile(id)
|
|||
client.templates.get(id) || raise(ActiveRecord::RecordNotFound)
|
|||
end
|
|||
def clusters
|
|||
client.clusters
|
|||
end
|
|||
85ed3c3f | Dominic Cleal | # Check if HTTPS is mandatory, since rest_client will fail with a POST
|
|
def test_https_required
|
|||
RestClient.post url, {} if URI(url).scheme == 'http'
|
|||
true
|
|||
rescue => e
|
|||
case e.message
|
|||
when /406/
|
|||
true
|
|||
else
|
|||
raise e
|
|||
end
|
|||
end
|
|||
private :test_https_required
|
|||
025ab6bc | Dominic Cleal | def test_connection options = {}
|
|
334d0359 | Amos Benari | super
|
|
85ed3c3f | Dominic Cleal | errors[:url].empty? && datacenters && test_https_required
|
|
334d0359 | Amos Benari | rescue => e
|
|
case e.message
|
|||
when /404/
|
|||
errors[:url] << e.message
|
|||
85ed3c3f | Dominic Cleal | when /302/
|
|
errors[:url] << 'HTTPS URL is required for API access'
|
|||
334d0359 | Amos Benari | when /401/
|
|
errors[:user] << e.message
|
|||
else
|
|||
errors[:base] << e.message
|
|||
end
|
|||
end
|
|||
def datacenters(options={})
|
|||
client.datacenters(options).map { |dc| [dc[:name], dc[:id]] }
|
|||
end
|
|||
def networks(opts ={})
|
|||
if opts[:cluster_id]
|
|||
client.clusters.get(opts[:cluster_id]).networks
|
|||
else
|
|||
[]
|
|||
end
|
|||
end
|
|||
96ede451 | Amos Benari | def storage_domains(opts ={})
|
|
client.storage_domains({:role => 'data'}.merge(opts))
|
|||
end
|
|||
def start_vm(uuid)
|
|||
334d0359 | Amos Benari | find_vm_by_uuid(uuid).start(:blocking => true)
|
|
end
|
|||
96ede451 | Amos Benari | def create_vm(args = {})
|
|
334d0359 | Amos Benari | #ovirt doesn't accept '.' in vm name.
|
|
args[:name] = args[:name].parameterize
|
|||
180d7f43 | Jason Montleon | vm = super({ :first_boot_dev => 'network', :quota => ovirt_quota }.merge(args))
|
|
334d0359 | Amos Benari | begin
|
|
96ede451 | Amos Benari | create_interfaces(vm, args[:interfaces_attributes])
|
|
create_volumes(vm, args[:volumes_attributes])
|
|||
334d0359 | Amos Benari | rescue => e
|
|
destroy_vm vm.id
|
|||
raise e
|
|||
end
|
|||
vm
|
|||
end
|
|||
96ede451 | Amos Benari | def new_vm(attr={})
|
|
95be0963 | Amos Benari | vm = super
|
|
96ede451 | Amos Benari | 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)}
|
|||
334d0359 | Amos Benari | vm
|
|
end
|
|||
96ede451 | Amos Benari | def new_interface(attr={})
|
|
334d0359 | Amos Benari | Fog::Compute::Ovirt::Interface.new(attr)
|
|
end
|
|||
96ede451 | Amos Benari | def new_volume(attr={})
|
|
Fog::Compute::Ovirt::Volume.new(attr)
|
|||
end
|
|||
def save_vm(uuid, attr)
|
|||
334d0359 | Amos Benari | vm = find_vm_by_uuid(uuid)
|
|
vm.attributes.merge!(attr.symbolize_keys)
|
|||
update_interfaces(vm, attr[:interfaces_attributes])
|
|||
96ede451 | Amos Benari | update_volumes(vm, attr[:volumes_attributes])
|
|
334d0359 | Amos Benari | vm.interfaces
|
|
96ede451 | Amos Benari | vm.volumes
|
|
334d0359 | Amos Benari | vm.save
|
|
end
|
|||
96ede451 | Amos Benari | def destroy_vm(uuid)
|
|
334d0359 | Amos Benari | begin
|
|
find_vm_by_uuid(uuid).destroy
|
|||
rescue OVIRT::OvirtException => e
|
|||
#404 error are ignored on delete.
|
|||
raise e unless e.message =~ /404/
|
|||
end
|
|||
true
|
|||
end
|
|||
b43fa642 | Ohad Levy | def console(uuid)
|
|
vm = find_vm_by_uuid(uuid)
|
|||
raise "VM is not running!" if vm.status == "down"
|
|||
057d4974 | Amos Benari | if vm.display[:type] =~ /spice/i
|
|
36a6345d | Jason Montleon | xpi_opts = {:name => vm.name, :address => vm.display[:address], :secure_port => vm.display[:secure_port], :ca_cert => cacert, :subject => vm.display[:subject] }
|
|
8ffd9aee | Ohad Levy | 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(xpi_opts).merge(:type => 'spice')
|
|||
057d4974 | Amos Benari | else
|
|
8ffd9aee | Ohad Levy | WsProxy.start(:host => vm.display[:address], :host_port => vm.display[:port], :password => vm.ticket).merge(:name => vm.name, :type => 'vnc')
|
|
057d4974 | Amos Benari | end
|
|
b43fa642 | Ohad Levy | end
|
|
0e5696d3 | Amos Benari | 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 if new_attrs[:interfaces_attributes]
|
|||
new_attrs[:volumes_attributes].each do |key, volume|
|
|||
return true if (volume[:id].blank? || volume[:_delete] == '1') && key != 'new_volumes' #ignore the template
|
|||
end if new_attrs[:volumes_attributes]
|
|||
false
|
|||
end
|
|||
805358df | Jason Montleon | def associated_host(vm)
|
|
Host.my_hosts.where(:mac => vm.mac).first
|
|||
end
|
|||
334d0359 | Amos Benari | protected
|
|
96ede451 | Amos Benari | def bootstrap(args)
|
|
334d0359 | Amos Benari | client.servers.bootstrap vm_instance_defaults.merge(args.to_hash)
|
|
rescue Fog::Errors::Error => e
|
|||
errors.add(:base, e.to_s)
|
|||
false
|
|||
end
|
|||
def client
|
|||
@client ||= ::Fog::Compute.new(
|
|||
:provider => "ovirt",
|
|||
:ovirt_username => user,
|
|||
:ovirt_password => password,
|
|||
:ovirt_url => url,
|
|||
:ovirt_datacenter => uuid
|
|||
)
|
|||
end
|
|||
55f8636a | Amos Benari | def api_version
|
|
@api_version ||= client.send(:client).api_version
|
|||
end
|
|||
057d4974 | Amos Benari | def cacert
|
|
ca_url = URI.parse(url)
|
|||
ca_url.path = "/ca.crt"
|
|||
6a85948c | Jimmi Dyson | http = Net::HTTP.new(ca_url.host, ca_url.port)
|
|
http.use_ssl = (ca_url.scheme == 'https')
|
|||
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|||
request = Net::HTTP::Get.new(ca_url.path)
|
|||
http.request(request).to_s
|
|||
057d4974 | Amos Benari | end
|
|
334d0359 | Amos Benari | private
|
|
96ede451 | Amos Benari | def create_interfaces(vm, attrs)
|
|
334d0359 | Amos Benari | #first remove all existing interfaces
|
|
vm.interfaces.each do |interface|
|
|||
#The blocking true is a work-around for ovirt bug, it should be removed.
|
|||
vm.destroy_interface(:id => interface.id, :blocking => true)
|
|||
end if vm.interfaces
|
|||
#add interfaces
|
|||
96ede451 | Amos Benari | interfaces = nested_attributes_for :interfaces, attrs
|
|
interfaces.map{ |i| vm.add_interface(i)}
|
|||
334d0359 | Amos Benari | vm.interfaces.reload
|
|
end
|
|||
96ede451 | Amos Benari | def create_volumes(vm, attrs)
|
|
#add volumes
|
|||
volumes = nested_attributes_for :volumes, attrs
|
|||
55f8636a | Amos Benari | #The blocking true is a work-around for ovirt bug fixed in ovirt version 3.1.
|
|
180d7f43 | Jason Montleon | volumes.map{ |vol| vm.add_volume({:bootable => 'false', :quota => ovirt_quota, :blocking => api_version.to_f < 3.1}.merge(vol)) if vol[:id].blank?}
|
|
96ede451 | Amos Benari | vm.volumes.reload
|
|
end
|
|||
334d0359 | Amos Benari | def update_interfaces(vm, attrs)
|
|
2a08c26b | Amos Benari | interfaces = nested_attributes_for :interfaces, attrs
|
|
interfaces.each do |interface|
|
|||
334d0359 | Amos Benari | vm.destroy_interface(:id => interface[:id]) if interface[:_delete] == '1' && interface[:id]
|
|
2a08c26b | Amos Benari | vm.add_interface(interface) if interface[:id].blank?
|
|
end
|
|||
334d0359 | Amos Benari | end
|
|
96ede451 | Amos Benari | def update_volumes(vm, attrs)
|
|
2a08c26b | Amos Benari | volumes = nested_attributes_for :volumes, attrs
|
|
volumes.each do |volume|
|
|||
55f8636a | Amos Benari | vm.destroy_volume(:id => volume[:id], :blocking => api_version.to_f < 3.1) if volume[:_delete] == '1' && volume[:id].present?
|
|
180d7f43 | Jason Montleon | vm.add_volume({:bootable => 'false', :quota => ovirt_quota, :blocking => api_version.to_f < 3.1}.merge(volume)) if volume[:id].blank?
|
|
2a08c26b | Amos Benari | end
|
|
96ede451 | Amos Benari | end
|
|
334d0359 | Amos Benari | end
|
|
end
|