Skip to content
Browse files

fixes #1574 - ovirt - add remove and show volumes

* volume and interface ordering is now working
* removed include blank because it is a duplicate of the Blank ovirt-template.
* bootable is disabled when editing a vm, because currently I don't handle volume updates. just add and remove of a volume.
* Volumes are created in the order that they where created in the gui. Bootable is set by default to the first volume.
* update to the latest rbovirt gem.
  • Loading branch information...
1 parent 1721eae commit 96ede451fc45d6d8e5786d62d4c92adc97c46ad3 @abenari abenari committed with ohadlevy Apr 9, 2012
View
2 Gemfile
@@ -15,7 +15,7 @@ gem "safemode", "~> 1.0.1"
group :virt do
gem "virt", ">= 0.2.1"
- gem "rbovirt", ">= 0.0.9"
+ gem "rbovirt", ">= 0.0.11"
gem "rbvmomi"
gem "fog", :git => "git://github.com/fog/fog.git"
#gem "fog", ">= 1.3.2"
View
1 app/controllers/compute_resources_controller.rb
@@ -65,6 +65,7 @@ def test_connection
def hardware_profile_selected
compute = @compute_resource.hardware_profile(params[:hwp_id])
compute.interfaces
+ compute.volumes
respond_to do |format|
format.json { render :json => compute }
end
View
15 app/models/compute_resource.rb
@@ -140,4 +140,19 @@ def random_password
(0...n).map { chars[rand(chars.length)].chr }.join
end
+ def nested_attributes_for type, opts
+ return [] unless opts
+ opts = opts.dup #duplicate to prevent changing the origin opts.
+ opts.delete("new_#{type}") # delete template
+ # convert our options hash into a sorted array (e.g. to preserve nic / disks order)
+ opts = opts.sort { |l, r| l[0].sub('new_','').to_i <=> r[0].sub('new_','').to_i }.map { |e| Hash[e[1]] }
+ opts.map do |v|
+ if v[:"_delete"] == '1' && v[:id].nil?
+ nil
+ else
+ v.symbolize_keys # convert to symbols deeper hashes
+ end
+ end.compact
+ end
+
end
View
16 app/views/compute_resources/vms/form/_ovirt.html.erb
@@ -7,7 +7,7 @@
:onchange => 'ovirt_clusterSelected(this);',
:help_inline => image_tag('spinner.gif', :id => 'cluster_indicator', :class => 'hide').html_safe } %>
<%= f.hidden_field :cluster if !new %>
-<%= select_f f, :template, compute_resource.hardware_profiles, :id, :name, { :include_blank => true },
+<%= select_f f, :template, compute_resource.hardware_profiles, :id, :name, {},
{ :disabled => !new, :'data-url' => hardware_profile_selected_compute_resource_path(compute_resource),
:onchange => 'ovirt_hwpSelected(this);',
:help_inline => image_tag('spinner.gif', :id => 'hwp_indicator', :class => 'hide').html_safe,
@@ -20,13 +20,23 @@
<div class="children_fields">
<%= new_child_fields_template(f, :interfaces, {
:object => compute_resource.new_interface,
- :partial => 'compute_resources/vms/form/network', :form_builder_attrs => { :clusters => clusters, :compute_resource => compute_resource } }) %>
+ :partial => 'compute_resources/vms/form/ovirt/network', :form_builder_attrs => { :clusters => clusters, :compute_resource => compute_resource } }) %>
<%= field_set_tag "Network interfaces", :id => "network_interfaces", :title => 'Networks' do -%>
<%= f.fields_for :interfaces do |i| %>
- <%= render 'compute_resources/vms/form/network', :f => i, :clusters => clusters, :compute_resource => compute_resource %>
+ <%= render 'compute_resources/vms/form/ovirt/network', :f => i, :clusters => clusters, :compute_resource => compute_resource %>
<% end -%>
<%= add_child_link "+", :interfaces, { :class => "info", :title => 'add new network interface' } %>
<% end -%>
+
+ <%= new_child_fields_template(f, :volumes, {
+ :object => compute_resource.new_volume,
+ :partial => 'compute_resources/vms/form/ovirt/volume', :form_builder_attrs => { :clusters => clusters, :compute_resource => compute_resource } }) %>
+ <%= field_set_tag "Volumes", :id => "volumes", :title => 'Volumes' do -%>
+ <%= f.fields_for :volumes do |i| %>
+ <%= render 'compute_resources/vms/form/ovirt/volume', :f => i, :compute_resource => compute_resource %>
+ <% end -%>
+ <%= add_child_link "+", :volumes, { :class => "info", :title => 'add new volume' } %>
+ <% end -%>
</div>
</div>
<% checked = params[:host]&&params[:host][:compute_attributes][:start] || '1' %>
View
2 ...pute_resources/vms/form/_network.html.erb → ...esources/vms/form/ovirt/_network.html.erb
@@ -3,7 +3,7 @@
<% disabled = (f.object.persisted? == "true" || f.object.persisted? == true) %>
<%= text_f f, :name, :disabled => disabled, :class => "span2" %>
<%= f.hidden_field :name if disabled %>
- <% selected_cluster = params[:host]&&params[:host][:compute_attributes][:cluster] %>
+ <% selected_cluster = params[:host] && params[:host][:compute_attributes] && params[:host][:compute_attributes][:cluster] %>
<% selected_cluster ||= clusters.size == 1 ? clusters.first.id : nil %>
<%= select_f f, :network, compute_resource.networks(selected_cluster ? { :cluster_id => selected_cluster } : { }), :id, :name,
{ }, :disabled => disabled, :class => "span2",
View
12 app/views/compute_resources/vms/form/ovirt/_volume.html.erb
@@ -0,0 +1,12 @@
+<div class="fields">
+ <% if f.object._delete != '1' -%>
+ <% disabled = (f.object.persisted? == "true" || f.object.persisted? == true) %>
+ <%= text_f f, :size_gb,:label => "Size GB", :disabled => disabled, :class => "span2" %>
+ <%= f.hidden_field :size_gb if disabled %>
+ <%= select_f f, :storage_domain, compute_resource.storage_domains, :id, :name,
+ { },:label => "Storage Domain", :disabled => disabled, :class => "span2",
+ :help_inline => remove_child_link("X", f, { :method => :'_delete', :title => 'remove volume', :class => 'label important' }) %>
+ <%= f.hidden_field :storage_domain if disabled %>
+ <%= checkbox_f f, :bootable, {:label => "Is Bootable", :disabled => disabled, :checked => (f.object.bootable == 'true'), :help_inline => "Note that only one volume is allowed to be bootable" } %>
+ <% end -%>
+</div>
View
15 lib/foreman/model/libvirt.rb
@@ -116,21 +116,6 @@ def vm_instance_defaults
}
end
- def nested_attributes_for type, opts
- return unless opts
- opts.delete("new_#{type}") # delete template
- # convert our options hash into a sorted array (e.g. to preserve nic / disks order)
- opts = opts.sort { |l, r| l[0][0] <=> r[0][0] }.map { |e| Hash[e[1]] }
- opts.map do |k, v|
- if v[:"_delete"] == '1'
- nil
- else
- v.delete(:"_delete")
- v.symbolize_keys # convert to symbols deeper hashes
- end
- end.compact
- end
-
def create_volumes args
vols = []
(volumes = args[:volumes]).each do |vol|
View
81 lib/foreman/model/ovirt.rb
@@ -25,10 +25,6 @@ def hardware_profile(id)
client.templates.get(id) || raise(ActiveRecord::RecordNotFound)
end
- def find_vm_by_uuid uuid
- client.servers.get(uuid) || raise(ActiveRecord::RecordNotFound)
- end
-
def clusters
client.clusters
end
@@ -60,45 +56,57 @@ def networks(opts ={})
end
- def start_vm uuid
+ def storage_domains(opts ={})
+ client.storage_domains({:role => 'data'}.merge(opts))
+ end
+
+ def start_vm(uuid)
find_vm_by_uuid(uuid).start(:blocking => true)
end
- def create_vm args = {}
+ def create_vm(args = {})
#ovirt doesn't accept '.' in vm name.
args[:name] = args[:name].parameterize
args[:display] = 'VNC'
- vm = super args
+ vm = super args
begin
- set_interfaces(vm, args[:interfaces_attributes])
+ create_interfaces(vm, args[:interfaces_attributes])
+ create_volumes(vm, args[:volumes_attributes])
rescue => e
destroy_vm vm.id
raise e
end
vm
end
- def new_vm attr={}
+ def new_vm(attr={})
vm = client.servers.new vm_instance_defaults.merge(attr)
- attr[:interfaces_attributes].each do |key, interface|
- vm.interfaces << new_interface(interface) unless (interface[:_delete] =='1' && interface[:id].nil?) || key == 'new_interfaces' #ignore the template
- end if attr[:interfaces_attributes]
+ 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
- def new_interface attr={}
+ def new_interface(attr={})
Fog::Compute::Ovirt::Interface.new(attr)
end
- def save_vm uuid, attr
+ def new_volume(attr={})
+ Fog::Compute::Ovirt::Volume.new(attr)
+ end
+
+ def save_vm(uuid, attr)
vm = find_vm_by_uuid(uuid)
vm.attributes.merge!(attr.symbolize_keys)
update_interfaces(vm, attr[:interfaces_attributes])
+ update_volumes(vm, attr[:volumes_attributes])
vm.interfaces
+ vm.volumes
vm.save
end
- def destroy_vm uuid
+ def destroy_vm(uuid)
begin
find_vm_by_uuid(uuid).destroy
rescue OVIRT::OvirtException => e
@@ -110,7 +118,7 @@ def destroy_vm uuid
protected
- def bootstrap args
+ def bootstrap(args)
client.servers.bootstrap vm_instance_defaults.merge(args.to_hash)
rescue Fog::Errors::Error => e
errors.add(:base, e.to_s)
@@ -134,30 +142,44 @@ def update_required?(old_attrs, new_attrs)
new_attrs[:interfaces_attributes].each do |key, interface|
return true if (interface[:id].nil? || 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].nil? || volume[:_delete] == '1') && key != 'new_volumes' #ignore the template
+ end if new_attrs[:volumes_attributes]
+
false
end
- def console uuid
- vm = find_vm_by_uuid(uuid)
- raise "VM is not running!" if vm.status == "down"
- raise "Spice display is not supported at the moment" if vm.display[:type] =~ /spice/i
- VNCProxy.start :host => vm.display[:address], :host_port => vm.display[:port], :password => vm.ticket
+ def console(uuid)
+ vm = find_vm_by_uuid(uuid)
+ raise "VM is not running!" if vm.status == "down"
+ raise "Spice display is not supported at the moment" if vm.display[:type] =~ /spice/i
+ VNCProxy.start(:host => vm.display[:address], :host_port => vm.display[:port], :password => vm.ticket)
end
private
- def set_interfaces(vm, attrs)
+ def create_interfaces(vm, attrs)
#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
- attrs.each do |key, interface|
- vm.add_interface(interface) if interface[:id].nil? && interface[:_delete] != '1' && key != 'new_interfaces'
- end if attrs
+ interfaces = nested_attributes_for :interfaces, attrs
+ interfaces.map{ |i| vm.add_interface(i)}
vm.interfaces.reload
end
+ def create_volumes(vm, attrs)
+ #add volumes
+ volumes = nested_attributes_for :volumes, attrs
+ #if no volume was set as bootable set the first volume.
+ volumes.first[:bootable] = true if volumes.first && volumes.map{|vol| true if vol[:bootable] == '1'}.compact().empty?
+ #The blocking true is a work-around for ovirt bug, it should be removed.
+ volumes.map{ |vol| vm.add_volume(vol.merge(:blocking => true)) if vol[:storage_domain]}
+ vm.volumes.reload
+ end
+
def update_interfaces(vm, attrs)
attrs.each do |key, interface|
unless key == 'new_interfaces' #ignore the template
@@ -167,5 +189,14 @@ def update_interfaces(vm, attrs)
end if attrs
end
+ def update_volumes(vm, attrs)
+ attrs.each do |key, volume|
+ unless key == 'new_volumes' #ignore the template
+ vm.destroy_volume(:id => volume[:id]) if volume[:_delete] == '1' && volume[:id]
+ vm.add_volume(volume) if volume[:id].nil?
+ end
+ end if attrs
+ end
+
end
end
View
15 lib/server_interfaces.rb
@@ -45,11 +45,22 @@ def memory
attributes[:memory_size].to_i * 1024
end
- def memory=mem
+ def memory= mem
attributes[:memory_size] = mem.to_i / 1024 if mem
end
end
end
+ class Ovirt
+
+ class Volume < Fog::Model
+
+ def as_json(options={})
+ size_gb
+ super options
+ end
+
+ end
+ end
end
-end
+end
View
15 public/javascripts/compute_resource.js
@@ -62,7 +62,9 @@ function ovirt_hwpSelected(item){
$('[id$=_memory]').val(result.memory);
$('[id$=_cores]').val(result.cores);
$('#network_interfaces').children('.fields').remove();
- $.each(result.interfaces, function() {add_network_interface(this);})
+ $.each(result.interfaces, function() {add_network_interface(this);});
+ $('#volumes').children('.fields').remove();
+ $.each(result.volumes, function() {add_volume(this);});
},
complete: function(result){
$('#hwp_indicator').hide();
@@ -72,11 +74,20 @@ function ovirt_hwpSelected(item){
}
// fill in the template interfaces.
function add_network_interface(item){
- var new_id = add_child_node($(".add_nested_fields"));
+ var new_id = add_child_node($("#network_interfaces .add_nested_fields"));
$('[id$='+new_id+'_name]').val(item.name);
$('[id$='+new_id+'_network]').val(item.network);
}
+// fill in the template volumes.
+function add_volume(item){
+ var new_id = add_child_node($("#volumes .add_nested_fields"));
+ $('[id$='+new_id+'_size_gb]').val(item.size_gb).attr('disabled', 'disabled');
+ $('[id$='+new_id+'_storage_domain]').val(item.storage_domain).attr('disabled', 'disabled');
+ $('[id$='+new_id+'_bootable]').attr('checked', item.bootable).attr('disabled', 'disabled');
+ $('[id$='+new_id+'_storage_domain]').next().hide();
+}
+
function ovirt_clusterSelected(item){
var cluster = $(item).val();
var url = $(item).attr('data-url');

0 comments on commit 96ede45

Please sign in to comment.
Something went wrong with that request. Please try again.