[Ovirt-devel] [PATCH server] network integration into ovirt server db and wui
Mohammed Morsi
mmorsi at redhat.com
Fri Oct 31 01:27:35 UTC 2008
---
src/app/controllers/host_controller.rb | 12 +-
src/app/controllers/network_controller.rb | 427 ++++++++++++++++++++
src/app/helpers/application_helper.rb | 28 +-
src/app/helpers/network_helper.rb | 2 +
src/app/models/bonding.rb | 27 +-
src/app/models/ip_address.rb | 27 ++
src/app/models/ip_v4_address.rb | 48 +++
src/app/models/ip_v6_address.rb | 44 ++
src/app/models/network.rb | 37 ++
src/app/models/nic.rb | 16 +-
src/app/models/physical_network.rb | 27 ++
src/app/models/usage.rb | 21 +
src/app/models/vlan.rb | 30 ++
src/app/views/dashboard/index.html.erb | 7 +
src/app/views/host/edit_network.rhtml | 85 ++++
src/app/views/host/show.rhtml | 4 +
src/app/views/network/_bonding_form.rhtml | 46 +++
src/app/views/network/_form.rhtml | 31 ++
src/app/views/network/_grid.rhtml | 37 ++
src/app/views/network/_ip_address_form.rhtml | 62 +++
src/app/views/network/_ip_addresses_form.rhtml | 50 +++
src/app/views/network/_select.rhtml | 32 ++
src/app/views/network/edit.rhtml | 34 ++
src/app/views/network/edit_bonding.rhtml | 52 +++
src/app/views/network/edit_ip_address.rhtml | 66 +++
.../views/network/edit_network_ip_addresses.rhtml | 13 +
src/app/views/network/edit_nic.rhtml | 62 +++
src/app/views/network/list.html.erb | 72 ++++
src/app/views/network/new.rhtml | 28 ++
src/app/views/network/new_bonding.rhtml | 32 ++
src/app/views/network/new_ip_address.rhtml | 33 ++
src/app/views/network/show.rhtml | 30 ++
src/app/views/nic/_list.rhtml | 2 -
src/db/migrate/028_refactor_networking_model.rb | 271 +++++++++++++
src/public/javascripts/ovirt.js | 29 ++-
src/public/stylesheets/components.css | 50 +++-
36 files changed, 1849 insertions(+), 25 deletions(-)
create mode 100644 src/app/controllers/network_controller.rb
create mode 100644 src/app/helpers/network_helper.rb
create mode 100644 src/app/models/ip_address.rb
create mode 100644 src/app/models/ip_v4_address.rb
create mode 100644 src/app/models/ip_v6_address.rb
create mode 100644 src/app/models/network.rb
create mode 100644 src/app/models/physical_network.rb
create mode 100644 src/app/models/usage.rb
create mode 100644 src/app/models/vlan.rb
create mode 100644 src/app/views/host/edit_network.rhtml
create mode 100644 src/app/views/network/_bonding_form.rhtml
create mode 100644 src/app/views/network/_form.rhtml
create mode 100644 src/app/views/network/_grid.rhtml
create mode 100644 src/app/views/network/_ip_address_form.rhtml
create mode 100644 src/app/views/network/_ip_addresses_form.rhtml
create mode 100644 src/app/views/network/_select.rhtml
create mode 100644 src/app/views/network/edit.rhtml
create mode 100644 src/app/views/network/edit_bonding.rhtml
create mode 100644 src/app/views/network/edit_ip_address.rhtml
create mode 100644 src/app/views/network/edit_network_ip_addresses.rhtml
create mode 100644 src/app/views/network/edit_nic.rhtml
create mode 100644 src/app/views/network/list.html.erb
create mode 100644 src/app/views/network/new.rhtml
create mode 100644 src/app/views/network/new_bonding.rhtml
create mode 100644 src/app/views/network/new_ip_address.rhtml
create mode 100644 src/app/views/network/show.rhtml
create mode 100644 src/db/migrate/028_refactor_networking_model.rb
diff --git a/src/app/controllers/host_controller.rb b/src/app/controllers/host_controller.rb
index a40d297..120fe2a 100644
--- a/src/app/controllers/host_controller.rb
+++ b/src/app/controllers/host_controller.rb
@@ -30,7 +30,7 @@ class HostController < ApplicationController
end
end
- before_filter :pre_action, :only => [:host_action, :enable, :disable, :clear_vms]
+ before_filter :pre_action, :only => [:host_action, :enable, :disable, :clear_vms, :edit_network]
# GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
verify :method => [:post, :put], :only => [ :create, :update ],
@@ -156,6 +156,16 @@ class HostController < ApplicationController
render :json => @json_hash
end
+ def edit_network
+ render :layout => 'popup'
+ end
+
+ def bondings_json
+ bondings = Host.find(params[:id]).bondings
+ bondings_json = []
+ bondings.each{ |x| bondings_json.push({:id => x.id, :name => x.name}) }
+ render :json => bondings_json
+ end
private
#filter methods
diff --git a/src/app/controllers/network_controller.rb b/src/app/controllers/network_controller.rb
new file mode 100644
index 0000000..b7f8b6d
--- /dev/null
+++ b/src/app/controllers/network_controller.rb
@@ -0,0 +1,427 @@
+# Copyright (C) 2008 Red Hat, Inc.
+# Written by Mohammed Morsi <mmorsi at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA. A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+#
+
+class NetworkController < ApplicationController
+ ########################## Networks related actions
+
+ def network_permissions
+ # TODO more robust permission system
+ # either by subclassing network from pool
+ # or by extending permission model to accomodate
+ # any object
+ @default_pool = HardwarePool.get_default_pool
+ set_perms(@default_pool)
+ unless @can_modify
+ flash[:notice] = 'You do not have permission to view networks'
+ redirect_to :controller => 'dashboard'
+ end
+ end
+
+ def list
+ @networks = Network.find(:all)
+ network_permissions
+ end
+
+ def networks_json
+ json_list(Network.find(:all), [:id, :name, :type, [:boot_type, :label]])
+ end
+
+ def show
+ @network = Network.find(params[:id])
+ network_permissions
+ respond_to do |format|
+ format.html { render :layout => 'selection' }
+ format.xml { render :xml => @network.to_xml }
+ end
+ end
+
+ def new
+ @boot_types = BootType.find(:all)
+ render :layout => 'popup'
+ end
+
+ def create
+ begin
+ @network = PhysicalNetwork.new(params[:network]) if params[:network][:type] == 'PhysicalNetwork'
+ @network = Vlan.new(params[:network]) if params[:network][:type] == 'Vlan'
+ @network.save!
+ alert = "Network was successfully created."
+ render :json => { :object => "network", :success => true,
+ :alert => alert }
+ rescue
+ render :json => { :object => "network", :success => false,
+ :errors =>
+ @network.errors.localize_error_messages.to_a }
+ end
+ end
+
+ def edit
+ @network = Network.find(params[:id])
+ @boot_types = BootType.find(:all)
+ render :layout => 'popup'
+ end
+
+ def update
+ begin
+ @network = Network.find(params[:id])
+
+ # special case if we are switching types
+ if @network.type != params[:network][:type]
+ if ! @network.conversion_valid?
+ render :json => { :object => "network", :success => false,
+ :alert =>
+ 'Can not change type of network with associated nics/bondings'}
+ return
+ end
+
+ if params[:network][:type] == 'PhysicalNetwork'
+ Vlan.destroy(params[:id])
+ @network = PhysicalNetwork.create(params[:network])
+ else
+ PhysicalNetwork.destroy(params[:id])
+ @network = Vlan.create(params[:network])
+ end
+ else
+ @network = PhysicalNetwork.find(params[:id]) if @network.type == 'PhysicalNetwork'
+ @network = Vlan.find(params[:id]) if @network.type == 'Vlan'
+ @network.update_attributes!(params[:network])
+ end
+
+ alert = "Network was successfully updated."
+ render :json => { :object => "network", :success => true,
+ :alert => alert }
+ rescue Exception => e
+ render :json => { :object => "network", :success => false,
+ :errors =>
+ @network.errors.localize_error_messages.to_a }
+ end
+ end
+
+ def delete
+ failed_networks = []
+ networks_ids_str = params[:network_ids]
+ network_ids = networks_ids_str.split(",").collect {|x| x.to_i}
+ network_ids.each{ |x|
+ network = Network.find(x)
+ if network.conversion_valid?
+ begin
+ Network.destroy(x)
+ rescue
+ failed_networks.push x
+ end
+ else
+ failed_networks.push x
+ end
+ }
+ if failed_networks.size == 0
+ render :json => { :object => "network",
+ :success => true,
+ :alert => "Successfully deleted networks" }
+ else
+ render :json => { :object => "network",
+ :success => false,
+ :alert => "Failed deleting " +
+ failed_networks.size.to_s +
+ " networks due to existing bondings/nics" }
+ end
+ end
+
+ def edit_network_ip_addresses
+ @network = Network.find(params[:id])
+ render :layout => 'popup'
+ end
+
+
+ ########################## Ip Address related actions
+
+ def ip_addresses_json
+ @parent_type = params[:parent_type]
+ if @parent_type == 'network'
+ ip_addresses = Network.find(params[:id]).ip_addresses
+ elsif @parent_type == 'nic'
+ ip_addresses = Nic.find(params[:id]).ip_addresses
+ elsif @parent_type == 'bonding' and params[:id]
+ ip_addresses = Bonding.find(params[:id]).ip_addresses
+ else
+ ip_addresses = []
+ end
+
+ ip_addresses_json = []
+ ip_addresses.each{ |x|
+ ip_addresses_json.push({:id => x.id, :name => x.address}) }
+ render :json => ip_addresses_json
+ end
+
+ def new_ip_address
+ @parent_type = params[:parent_type]
+ @network = Network.find(params[:id]) if @parent_type == 'network'
+ @nic = Nic.find(params[:id]) if @parent_type == 'nic'
+ @bonding = Bonding.find(params[:id]) if @parent_type == 'bonding' and params[:id]
+
+ render :layout => false
+ end
+
+ def _create_ip_address
+ if params[:ip_address][:type] == "IpV4Address"
+ @ip_address = IpV4Address.new(params[:ip_address])
+ else
+ @ip_address = IpV6Address.new(params[:ip_address])
+ end
+ @ip_address.save!
+ end
+
+ def create_ip_address
+ begin
+ _create_ip_address
+ alert = "Ip Address was successfully created."
+ render :json => { :object => "ip_address", :success => true,
+ :alert => alert }
+ rescue
+ render :json => { :object => "ip_address", :success => false,
+ :errors =>
+ @ip_address.errors.localize_error_messages.to_a }
+ end
+ end
+
+ def edit_ip_address
+ @ip_address = IpAddress.find(params[:id])
+
+ @parent_type = params[:parent_type]
+ @network = @ip_address.network if @ip_address.network_id
+ @nic = @ip_address.nic if @ip_address.nic_id
+ @bonding = @ip_address.bonding if @ip_address.bonding_id
+
+ render :layout => false
+ end
+
+ def _update_ip_address(id)
+ @ip_address = IpAddress.find(id)
+
+ # special case if we are switching types
+ if @ip_address.type != params[:ip_address][:type]
+ if params[:ip_address][:type] == 'IpV4Address'
+ @ip_address = IpV4Address.new(params[:ip_address])
+ @ip_address.save!
+ IpV6Address.delete(id)
+ else
+ @ip_address = IpV6Address.new(params[:ip_address])
+ @ip_address.save!
+ IpV4Address.delete(id)
+ end
+ else
+ if @ip_address.type == 'IpV4Address'
+ @ip_address = IpV4Address.find(id)
+ else
+ @ip_address = IpV6Address.find(id)
+ end
+ @ip_address.update_attributes!(params[:ip_address])
+ end
+
+ end
+
+ def update_ip_address
+ begin
+ _update_ip_address(params[:id])
+ alert = "IpAddress was successfully updated."
+ render :json => { :object => "network", :success => true,
+ :alert => alert }
+ rescue
+ render :json => { :object => "ip_address", :success => false,
+ :errors =>
+ @ip_address.errors.localize_error_messages.to_a }
+ end
+ end
+
+ def destroy_ip_address
+ begin
+ IpAddress.delete(params[:id])
+ alert = "Ip Address was successfully deleted."
+ render :json => { :object => "ip_address", :success => true,
+ :alert => alert }
+ rescue
+ render :json => { :object => "ip_address", :success => false,
+ :alert => 'Ip Address Deletion Failed' }
+ end
+ end
+
+
+ ########################## NICs related actions
+
+ def edit_nic
+ @nic = Nic.find(params[:id])
+ @network = @nic.physical_network
+
+ @networks = PhysicalNetwork.find(:all)
+ network_options
+
+ render :layout => false
+ end
+
+ def update_nic
+ begin
+ network_options
+ @network = Network.find(params[:nic][:physical_network_id])
+
+ if @network.boot_type.id == @static_boot_type.id
+ if params[:ip_address][:id] == "New"
+ _create_ip_address
+ elsif params[:ip_address][:id] != ""
+ _update_ip_address(params[:ip_address][:id])
+ end
+ end
+
+ @nic = Nic.find(params[:id])
+ @nic.update_attributes!(params[:nic])
+
+ alert = "Nic was successfully updated."
+ render :json => { :object => "nic", :success => true,
+ :alert => alert }
+ rescue Exception => e
+ if @ip_address and @ip_address.errors.size != 0
+ render :json => { :object => "ip_address", :success => false,
+ :errors =>
+ @ip_address.errors.localize_error_messages.to_a}
+ else
+ render :json => { :object => "nic", :success => false,
+ :errors =>
+ @nic.errors.localize_error_messages.to_a }
+ end
+ end
+ end
+
+ ########################## Bonding related actions
+
+ def new_bonding
+ unless params[:host_id]
+ flash[:notice] = "Host is required."
+ redirect_to :controller => 'dashboard'
+ end
+
+ @host = Host.find(params[:host_id])
+ @networks = Vlan.find(:all)
+ network_options
+
+ render :layout => false
+ end
+
+ def create_bonding
+ begin
+ network_options
+ @network = Network.find(params[:bonding][:vlan_id])
+
+ if @network.boot_type.id == @static_boot_type.id
+ if params[:ip_address][:id] == "New"
+ _create_ip_address
+ elsif params[:ip_address][:id] != ""
+ _update_ip_address(params[:ip_address][:id])
+ end
+ end
+
+ @bonding = Bonding.new(params[:bonding])
+ @bonding.save!
+
+ if @ip_address
+ @ip_address.bonding_id = @bonding.id
+ @ip_address.save!
+ end
+
+ alert = "Bonding was successfully created."
+ render :json => { :object => "bonding", :success => true,
+ :alert => alert }
+ rescue
+ if @ip_address and @ip_address.errors.size != 0
+ render :json => { :object => "ip_address", :success => false,
+ :errors =>
+ @ip_address.errors.localize_error_messages.to_a}
+ else
+ render :json => { :object => "bonding", :success => false,
+ :errors =>
+ @bonding.errors.localize_error_messages.to_a }
+ end
+ end
+ end
+
+ def edit_bonding
+ @bonding = Bonding.find(params[:id])
+ @network = @bonding.vlan
+
+ @host = @bonding.host
+ @networks = Vlan.find(:all)
+ network_options
+
+ render :layout => false
+ end
+
+ def update_bonding
+ begin
+ network_options
+ @network = Network.find(params[:bonding][:vlan_id])
+
+ if @network.boot_type.id == @static_boot_type.id
+ if params[:ip_address][:id] == "New"
+ _create_ip_address
+ elsif params[:ip_address][:id] != ""
+ _update_ip_address(params[:ip_address][:id])
+ end
+ end
+
+ @bonding = Bonding.find(params[:id])
+ @bonding.nics.each { |nic| @bonding.nics.delete(nic) }
+ @bonding.update_attributes!(params[:bonding])
+
+ alert = "Bonding was successfully updated."
+ render :json => { :object => "bonding", :success => true,
+ :alert => alert }
+ rescue
+ if @ip_address and @ip_address.errors.size != 0
+ render :json => { :object => "ip_address", :success => false,
+ :errors =>
+ @ip_address.errors.localize_error_messages.to_a}
+ else
+ render :json => { :object => "bonding", :success => false,
+ :errors =>
+ @bonding.errors.localize_error_messages.to_a }
+ end
+ end
+ end
+
+ def destroy_bonding
+ begin
+ Bonding.destroy(params[:id])
+ alert = "Bonding was successfully deleted."
+ render :json => { :object => "bonding", :success => true,
+ :alert => alert }
+ rescue
+ render :json => { :object => "bonding", :success => false,
+ :alert => 'Bonding Deletion Failed' }
+ end
+
+ end
+
+
+ ########################## Misc methods
+
+ protected
+ def network_options
+ @bonding_types = BondingType.find(:all)
+ @static_boot_type = BootType.find(:first,
+ :conditions => { :proto => 'static' })
+ end
+
+end
diff --git a/src/app/helpers/application_helper.rb b/src/app/helpers/application_helper.rb
index d7b6628..0178ad0 100644
--- a/src/app/helpers/application_helper.rb
+++ b/src/app/helpers/application_helper.rb
@@ -84,21 +84,31 @@ module ApplicationHelper
}
end
- def popup_footer(action, label)
- %{
- <div style="background: url(#{image_path "fb_footer.jpg"}) repeat-x; height: 37px; text-align:right; padding: 9px 9px 0 0;">
+ # expects hash of labels => actions
+ def multi_button_popup_footer(buttons = {})
+ buttons_html = ""
+ buttons.each{ |label, action|
+ buttons_html+="<div class=\"button\">" +
+ " <div class=\"button_left_blue\"></div>" +
+ " <div class=\"button_middle_blue\"><a href=\"#\" onclick=\"#{action}\">#{label}</a></div>" +
+ " <div class=\"button_right_blue\"></div>" +
+ "</div>"
+ }
+
+ %{
+ <div style="background: url(#{image_path "fb_footer.jpg"}) repeat-x; height: 37px; text-align:right; padding: 9px 9px 0 0; float: left; width: 97%;">
<div class="button">
<div class="button_left_grey"></div>
<div class="button_middle_grey"><a href="#" onclick="$(document).trigger('close.facebox')">Cancel</a></div>
<div class="button_right_grey"></div>
</div>
- <div class="button">
- <div class="button_left_blue"></div>
- <div class="button_middle_blue"><a href="#" onclick="#{action}">#{label}</a></div>
- <div class="button_right_blue"></div>
- </div>
+ #{buttons_html}
</div>
- }
+ }
+ end
+
+ def popup_footer(action, label)
+ multi_button_popup_footer({label => action})
end
def ok_footer
diff --git a/src/app/helpers/network_helper.rb b/src/app/helpers/network_helper.rb
new file mode 100644
index 0000000..ebbce0b
--- /dev/null
+++ b/src/app/helpers/network_helper.rb
@@ -0,0 +1,2 @@
+module NetworkHelper
+end
diff --git a/src/app/models/bonding.rb b/src/app/models/bonding.rb
index 006c261..a3ad150 100644
--- a/src/app/models/bonding.rb
+++ b/src/app/models/bonding.rb
@@ -30,6 +30,16 @@
# interface. They can be ignored if not used.
#
class Bonding < ActiveRecord::Base
+ belongs_to :host
+ belongs_to :bonding_type
+ belongs_to :vlan
+ has_many :ip_addresses, :dependent => :destroy
+
+ has_and_belongs_to_many :nics,
+ :join_table => 'bondings_nics',
+ :foreign_key => :bonding_id
+
+
validates_presence_of :name,
:message => 'A name is required.'
@@ -42,18 +52,17 @@ class Bonding < ActiveRecord::Base
validates_presence_of :interface_name,
:message => 'An interface name is required.'
- validates_presence_of :boot_type_id,
- :message => 'A boot type must be specified.'
-
validates_presence_of :bonding_type_id,
:message => 'A bonding type must be specified.'
- belongs_to :host
- belongs_to :bonding_type
- belongs_to :boot_type
+ protected
+ def validate
+ errors.add("name", "must be specified") unless name
+ errors.add("interface_name", "must be specified") unless interface_name
+ errors.add("bonding_type_id", "must be specified") unless bonding_type_id
+ errors.add("host_id", "must be specified") unless host_id
+ errors.add("vlan_id", "must be specified") unless vlan_id
+ end
- has_and_belongs_to_many :nics,
- :join_table => 'bondings_nics',
- :foreign_key => :bonding_id
end
diff --git a/src/app/models/ip_address.rb b/src/app/models/ip_address.rb
new file mode 100644
index 0000000..5d2e6af
--- /dev/null
+++ b/src/app/models/ip_address.rb
@@ -0,0 +1,27 @@
+# ip_address.rb
+# Copyright (C) 2008 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA. A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+# +IpAddress+ is the base class for all address related classes.
+#
+class IpAddress < ActiveRecord::Base
+ # one of these 3 will apply for each address
+ belongs_to :network
+ belongs_to :nic
+ belongs_to :bonding
+end
diff --git a/src/app/models/ip_v4_address.rb b/src/app/models/ip_v4_address.rb
new file mode 100644
index 0000000..40e8cf9
--- /dev/null
+++ b/src/app/models/ip_v4_address.rb
@@ -0,0 +1,48 @@
+# ip_v4_address.rb
+#
+# Copyright (C) 2008 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>,
+# Mohammed Morsi <mmorsi at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA. A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+# +IpV4Address+ represents a single IPv4 address.
+#
+class IpV4Address < IpAddress
+ ADDRESS_TEST = %r{^(\d{1,3}\.){3}\d{1,3}$}
+
+ validates_presence_of :address,
+ :message => 'An address must be supplied.'
+ validates_format_of :address,
+ :with => ADDRESS_TEST
+
+ protected
+ def validate
+ unless address and address =~ ADDRESS_TEST
+ errors.add("address", "is of incorrect format")
+ end
+ unless !netmask or netmask == "" or netmask =~ ADDRESS_TEST
+ errors.add("netmask", "is of incorrect format")
+ end
+ unless !gateway or gateway == "" or gateway =~ ADDRESS_TEST
+ errors.add("gateway", "is of incorrect format")
+ end
+ unless !broadcast or broadcast == "" or broadcast =~ ADDRESS_TEST
+ errors.add("broadcast", "is of incorrect format")
+ end
+ end
+
+end
diff --git a/src/app/models/ip_v6_address.rb b/src/app/models/ip_v6_address.rb
new file mode 100644
index 0000000..9720179
--- /dev/null
+++ b/src/app/models/ip_v6_address.rb
@@ -0,0 +1,44 @@
+# ip_v6_address.rb
+#
+# Copyright (C) 2008 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>,
+# Mohammed Morsi <mmorsi at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA. A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+# +IpV6Address+ represents a single IPv6 address.
+#
+class IpV6Address < IpAddress
+ ADDRESS_TEST = %r{^([0-9a-fA-F]{0,4}|0)(\:([0-9a-fA-F]{0,4}|0)){7}$}
+
+ validates_presence_of :address,
+ :message => 'An address must be provided.'
+ validates_format_of :address,
+ :with => ADDRESS_TEST
+
+ protected
+ def validate
+ unless address =~ ADDRESS_TEST
+ errors.add("address", "is of incorrect format")
+ end
+ unless !prefix or prefix == "" or prefix =~ ADDRESS_TEST
+ errors.add("prefix", "is of incorrect format")
+ end
+ unless !gateway or gateway == "" or gateway =~ ADDRESS_TEST
+ errors.add("gateway", "is of incorrect format")
+ end
+ end
+end
diff --git a/src/app/models/network.rb b/src/app/models/network.rb
new file mode 100644
index 0000000..99e1a94
--- /dev/null
+++ b/src/app/models/network.rb
@@ -0,0 +1,37 @@
+# Copyright (C) 2008 Red Hat, Inc.
+# Written by Mohammed Morsi <mmorsi at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA. A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+class Network < ActiveRecord::Base
+ belongs_to :boot_type
+ has_many :ip_addresses, :dependent => :destroy
+
+ has_and_belongs_to_many :usages, :join_table => 'networks_usages'
+
+ validates_presence_of :type
+ validates_presence_of :name
+ validates_presence_of :boot_type_id
+
+ def conversion_valid?
+ return false if type.to_s == 'Vlan' &&
+ Vlan.find(id).bondings.size != 0 ||
+ type.to_s == 'PhysicalNetwork' &&
+ PhysicalNetwork.find(id).nics.size != 0
+ return true
+ end
+
+end
diff --git a/src/app/models/nic.rb b/src/app/models/nic.rb
index baf7095..25d3ac2 100644
--- a/src/app/models/nic.rb
+++ b/src/app/models/nic.rb
@@ -19,7 +19,19 @@
class Nic < ActiveRecord::Base
belongs_to :host
- belongs_to :boot_type
+ belongs_to :physical_network
+ has_many :ip_addresses, :dependent => :destroy
- has_and_belongs_to_many :bonding, :join_table => 'bondings_nics'
+ has_and_belongs_to_many :bondings, :join_table => 'bondings_nics'
+
+ protected
+ def validate
+ errors.add("host_id", "must be specified") unless host_id
+ errors.add("physical_network_id", "must be specified") unless physical_network_id
+ if physical_network.boot_type.id ==
+ BootType.find(:first, :conditions => { :proto => 'static' }).id and
+ ip_addresses.size == 0
+ errors.add("ip_address_id", "must be specified")
+ end
+ end
end
diff --git a/src/app/models/physical_network.rb b/src/app/models/physical_network.rb
new file mode 100644
index 0000000..cba696a
--- /dev/null
+++ b/src/app/models/physical_network.rb
@@ -0,0 +1,27 @@
+# Copyright (C) 2008 Red Hat, Inc.
+# Written by Mohammed Morsi <mmorsi at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA. A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+class PhysicalNetwork < Network
+ has_many :nics
+
+ protected
+ def validate
+ errors.add("name", "must be specified") unless name
+ errors.add("boot_type_id", "must be specified") unless boot_type_id
+ end
+end
diff --git a/src/app/models/usage.rb b/src/app/models/usage.rb
new file mode 100644
index 0000000..353e8f4
--- /dev/null
+++ b/src/app/models/usage.rb
@@ -0,0 +1,21 @@
+# Copyright (C) 2008 Red Hat, Inc.
+# Written by Mohammed Morsi <mmorsi at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA. A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+class Usage < ActiveRecord::Base
+ has_and_belongs_to_many :networks, :join_table => 'networks_usages'
+end
diff --git a/src/app/models/vlan.rb b/src/app/models/vlan.rb
new file mode 100644
index 0000000..2b96502
--- /dev/null
+++ b/src/app/models/vlan.rb
@@ -0,0 +1,30 @@
+# Copyright (C) 2008 Red Hat, Inc.
+# Written by Mohammed Morsi <mmorsi at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA. A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+class Vlan < Network
+ has_many :bondings
+
+ validates_presence_of :number
+
+ protected
+ def validate
+ errors.add("name", "must be specified") unless name
+ errors.add("number", "must be specified") unless number
+ errors.add("boot_type_id", "must be specified") unless boot_type_id
+ end
+end
diff --git a/src/app/views/dashboard/index.html.erb b/src/app/views/dashboard/index.html.erb
index 92cb4da..8815ebc 100644
--- a/src/app/views/dashboard/index.html.erb
+++ b/src/app/views/dashboard/index.html.erb
@@ -13,6 +13,13 @@
</table>
</div>
+ <% if @can_modify %>
+ <h3>Networks</h3>
+ <a href="<%= url_for :controller => 'network', :action => 'list' %>">
+ View / Edit
+ </a>
+ <% end %>
+
</div> <!-- end #tools -->
</td>
diff --git a/src/app/views/host/edit_network.rhtml b/src/app/views/host/edit_network.rhtml
new file mode 100644
index 0000000..7ec3180
--- /dev/null
+++ b/src/app/views/host/edit_network.rhtml
@@ -0,0 +1,85 @@
+<%- content_for :title do -%>
+ Edit <%= @host.hostname %> Network Devices
+<%- end -%>
+
+<%- content_for :description do -%>
+ Select and edit nics and bonded interfaces on <%= @host.hostname %>
+<%- end -%>
+
+<div id="select-host-nic" class="popup-content-selection">
+<%= select_with_label "NICs", "nic", "id",
+ @host.nics.
+ collect{ |nic| [nic.mac, nic.id] }.
+ insert(0, "") %>
+</div>
+
+<div id="select-host-bonding" class="popup-content-selection">
+<%= select_with_label "Bonded Interfaces", "bonding", "id", [] %>
+</div>
+
+<div style="clear: both;"></div>
+
+<div id="selected_nic_bonding" class="selected_popup_content"></div>
+
+<div id="host_network_footer" class="popup-content-footer">
+ <%= ok_footer %>
+</div>
+
+<script type="text/javascript">
+function reset_nics_bonding_detail(){
+ var data='Select NIC or Bonded Interface<br/>';
+
+ $("#selected_nic_bonding").html(data);
+ $("#host_network_footer").show();
+};
+
+reset_nics_bonding_detail(); // run it once for inital content
+
+function reset_nics_select(){
+ $("#nic_id option:first").attr("selected", true);
+};
+
+function reset_bonding_select(){
+ // incase of new additions / deletions, repopulate select box
+ $.getJSON(
+ "<%= url_for :action => 'bondings_json', :id => @host.id %>",
+ {},
+ function(j){
+ var options = "<option value=''></option>" +
+ "<option value='New'>New</option>";
+ for(var i = 0; i < j.length; i++){
+ options += '<option value="' + j[i].id + '">' + j[i].name +
+ '</option>';
+ }
+ $("#bonding_id").html(options);
+ });
+
+ $("#bonding_id option:first").attr("selected", true);
+};
+
+reset_bonding_select(); // run it once for initial content
+
+$("#nic_id").change(function () {
+ reset_bonding_select();
+ if($('#nic_id').val() != ""){
+ $("#selected_nic_bonding").load("<%= url_for :controller => 'network',
+ :action => 'edit_nic'%>/" + $('#nic_id').val());
+ $("#host_network_footer").hide();
+ }else{
+ reset_nics_bonding_detail();
+ }
+});
+
+$("#bonding_id").change(function () {
+ reset_nics_select();
+ if($('#bonding_id').val() == "New"){
+ $("#selected_nic_bonding").load("<%= url_for :controller => 'network', :action => 'new_bonding', :host_id => @host.id %>");
+ $("#host_network_footer").hide();
+ }else if($('#bonding_id').val() != ""){
+ $("#selected_nic_bonding").load("<%= url_for :controller => 'network', :action => 'edit_bonding'%>/" + $('#bonding_id').val());
+ $("#host_network_footer").hide();
+ }else{
+ reset_nics_bonding_detail();
+ }
+});
+</script>
diff --git a/src/app/views/host/show.rhtml b/src/app/views/host/show.rhtml
index d1b05ad..bc39a62 100644
--- a/src/app/views/host/show.rhtml
+++ b/src/app/views/host/show.rhtml
@@ -17,6 +17,10 @@
<%= image_tag "icon_x.png" %> Clear VMs
</a>
<% end -%>
+ <%= link_to image_tag("icon_edit.png") +"Edit Network",
+ {:controller => 'host',
+ :action => 'edit_network', :id => @host.id},
+ :rel=>"facebox[.bolder]", :class=>"selection_facebox" %>
<%- end -%>
<%- end -%>
<script type="text/javascript">
diff --git a/src/app/views/network/_bonding_form.rhtml b/src/app/views/network/_bonding_form.rhtml
new file mode 100644
index 0000000..4ec0df1
--- /dev/null
+++ b/src/app/views/network/_bonding_form.rhtml
@@ -0,0 +1,46 @@
+ <%= error_messages_for 'bonding' %>
+ <%= error_messages_for 'ip_address' %>
+
+<div id="selected_popup_content_expanded" class="dialog_form">
+ <%= hidden_field_tag 'bonding[host_id]', @host.id %>
+
+ <div class="selected_popup_content_left">Name</div>
+ <div class="selected_popup_content_right">
+ <%= text_field_with_label "", "bonding", "name" %>
+ </div>
+
+ <div class="selected_popup_content_left">Interface Name</div>
+ <div class="selected_popup_content_right">
+ <%= text_field_with_label "", "bonding", "interface_name" %>
+ </div>
+
+ <div class="selected_popup_content_left">Bonding Type</div>
+ <div class="selected_popup_content_right">
+ <%= select "bonding", "bonding_type_id",
+ @bonding_types.collect { |bt| [bt.label, bt.id ] } %>
+ </div>
+
+ <% if @host.nics.size != 0 %>
+ <div class="selected_popup_content_left">NICs</div>
+ <div class="selected_popup_content_right">
+ <select id="bonding_nic_ids" name="bonding[nic_ids][]" multiple="true">
+ <%= options_from_collection_for_select @host.nics, "id", "mac",
+ @bonding ? @bonding.nics.collect{ |x| x.nic_id.to_i } : [] %>
+ </select>
+ </div>
+ <% end %>
+
+ <%= render :partial => 'select', :locals => { :target => 'bonding' } %>
+
+<div id="static_ip_options"
+ style="<% unless ((@network && @network.boot_type_id == @static_boot_type.id) ||
+ (!@network && @networks.size > 0 &&
+ @networks[0].boot_type_id == @static_boot_type.id)) %>
+ display: none;<%end %>">
+ <%= render :partial => 'ip_addresses_form',
+ :locals => { :parent_type => 'bonding',
+ :parent_id => @bonding ? @bonding.id : nil } %>
+</div>
+
+
+</div>
diff --git a/src/app/views/network/_form.rhtml b/src/app/views/network/_form.rhtml
new file mode 100644
index 0000000..3f393f7
--- /dev/null
+++ b/src/app/views/network/_form.rhtml
@@ -0,0 +1,31 @@
+<%= error_messages_for 'network' %>
+
+<!--[form:network]-->
+<%= hidden_field 'network', 'id' if @create %>
+
+<%= text_field_with_label "Name:", "network", "name",
+ {:style=>"width:250px;"} %>
+
+<%= select_with_label "Boot Type:", 'network', 'boot_type_id',
+ @boot_types.collect{ |bt| [bt.label, bt.id] },
+ :style=>"width:250px;" %>
+
+<%= select_with_label "Type", "network", "type",
+ [[ "Physical Network", "PhysicalNetwork" ],
+ [ "VLAN", "Vlan" ] ] %>
+
+<div id="vlan_options" style="display: none;">
+<%= text_field_with_label "Number:", "network", "number",
+ {:style=>"width:250px;"} %>
+</div>
+
+
+<script type="text/javascript">
+$("#network_type").change(function () {
+ if($('#network_type').val() == "Vlan"){
+ $("#vlan_options").show();
+ }else{
+ $("#vlan_options").hide();
+ }
+}).trigger('change');
+</script>
diff --git a/src/app/views/network/_grid.rhtml b/src/app/views/network/_grid.rhtml
new file mode 100644
index 0000000..6af0c05
--- /dev/null
+++ b/src/app/views/network/_grid.rhtml
@@ -0,0 +1,37 @@
+<% networks_per_page = 40 unless (defined? networks_per_page) and !(networks_per_page.nil?) %>
+<% usepager = @networks.size > networks_per_page %>
+
+<div id="<%= table_id %>_div">
+<form id="<%= table_id %>_form">
+<table id="<%= table_id %>" style="display:none"></table>
+</form>
+</div>
+<script type="text/javascript">
+ $("#<%= table_id %>").flexigrid
+ (
+ {
+ url: '<%= url_for :action => "networks_json" %>',
+ dataType: 'json',
+ colModel : [
+ {display: '', width : 20, align: 'left', process: <%= table_id %>checkbox},
+ {display: 'Name', name: 'name', width : 180, align: 'left'},
+ {display: 'Type', name: 'type', width : 180, align: 'left'},
+ {display: 'Boot Type', name: 'boot_type', width : 180, align: 'left'}
+ ],
+ sortname: "name",
+ sortorder: "asc",
+ usepager: <%= usepager %>,
+ useRp: <%= usepager %>,
+ rp: <%= networks_per_page %>,
+ showTableToggleBtn: true,
+ onSelect: <%= on_select %>
+ }
+ );
+ function <%= table_id %>checkbox(celDiv)
+ {
+ $(celDiv).html('<input type="checkbox" name="grid_checkbox'+$(celDiv).html()+'" class="grid_checkbox" value="'+$(celDiv).html()+'"/>');
+ }
+
+</script>
+
+
diff --git a/src/app/views/network/_ip_address_form.rhtml b/src/app/views/network/_ip_address_form.rhtml
new file mode 100644
index 0000000..b952807
--- /dev/null
+++ b/src/app/views/network/_ip_address_form.rhtml
@@ -0,0 +1,62 @@
+<%= error_messages_for 'ip_address' %>
+
+<div id="selected_popup_content_expanded" class="dialog_form">
+ <%= hidden_field_tag 'parent_type', @parent_type%>
+ <%= hidden_field_tag 'ip_address[id]', @ip_address.id if @ip_address%>
+ <%= hidden_field_tag 'ip_address[network_id]', @network.id if @network %>
+ <%= hidden_field_tag 'ip_address[nic_id]', @nic.id if @nic %>
+ <%= hidden_field_tag 'ip_address[bonding_id]', @bonding.id if @bonding %>
+
+ <div class="selected_nic_bonding_left">Type:</div>
+ <div class="selected_nic_bonding_right">
+ <%= select_with_label "", "ip_address", "type",
+ [[ "ipv4", "IpV4Address" ], [ "ipv6", "IpV6Address" ] ] %>
+ </div>
+
+
+ <div class="static_ip_common_options">
+ <div class="selected_nic_bonding_left">IP Address</div>
+ <div class="selected_nic_bonding_right">
+ <%= text_field_with_label "", "ip_address", "address" %>
+ </div>
+ </div>
+
+ <div id="static_ip_v4_options">
+ <div class="selected_nic_bonding_left">Netmask</div>
+ <div class="selected_nic_bonding_right">
+ <%= text_field_with_label "", "ip_address", "netmask" %>
+ </div>
+
+ <div class="selected_nic_bonding_left">Broadcast</div>
+ <div class="selected_nic_bonding_right">
+ <%= text_field_with_label "", "ip_address", "broadcast" %>
+ </div>
+ </div>
+
+ <div id="static_ip_v6_options" style="display: none;">
+ <div class="selected_nic_bonding_left">Prefix</div>
+ <div class="selected_nic_bonding_right">
+ <%= text_field_with_label "", "ip_address", "prefix" %>
+ </div>
+ </div>
+
+ <div class="static_ip_common_options">
+ <div class="selected_nic_bonding_left">Gateway</div>
+ <div class="selected_nic_bonding_right">
+ <%= text_field_with_label "", "ip_address", "gateway" %>
+ </div>
+ </div>
+
+</div>
+
+<script type="text/javascript">
+ $("#ip_address_type").change(function () {
+ if($("#ip_address_type").val() == 'IpV4Address'){
+ $("#static_ip_v4_options").show();
+ $("#static_ip_v6_options").hide();
+ }else{
+ $("#static_ip_v4_options").hide();
+ $("#static_ip_v6_options").show();
+ }
+ }).trigger('change');
+</script>
diff --git a/src/app/views/network/_ip_addresses_form.rhtml b/src/app/views/network/_ip_addresses_form.rhtml
new file mode 100644
index 0000000..f833b2a
--- /dev/null
+++ b/src/app/views/network/_ip_addresses_form.rhtml
@@ -0,0 +1,50 @@
+<div id="select_ip_address" class="popup-content-selection">
+<%= select_with_label "IP Addresses", "ip_address", "id", [] %>
+</div>
+
+<div id="selected_ip_address" class="selected_popup_content"></div>
+
+<script type="text/javascript">
+function reset_selected_ip_address(){
+ var data='Select IP Address<br/>';
+
+ $("#selected_ip_address").html(data);
+ $("#ip_addresses_footer").show();
+};
+
+reset_selected_ip_address(); // run it once for inital content
+
+function reset_ip_address_select(){
+ // incase of new additions / deletions, repopulate select box
+ $.getJSON(
+ "<%= url_for :action => 'ip_addresses_json', :id => parent_id, :parent_type => parent_type %>",
+ {},
+ function(j){
+ var options = "<option value=''></option>" +
+ "<option value='New'>New</option>";
+ for(var i = 0; i < j.length; i++){
+ options += '<option value="' + j[i].id + '">' + j[i].name +
+ '</option>';
+ }
+ $("#ip_address_id").html(options);
+ });
+
+ $("#ip_address_id option:first").attr("selected", true);
+};
+
+reset_ip_address_select(); // run it once for initial content
+
+$("#ip_address_id").change(function () {
+ if($('#ip_address_id').val() == "New"){
+ $("#selected_ip_address").load("<%= url_for :action => 'new_ip_address', :id => parent_id, :parent_type => parent_type %>");
+ $("#ip_addresses_footer").hide();
+ }else if($('#ip_address_id').val() != ""){
+ $("#selected_ip_address").load("<%= url_for :action => 'edit_ip_address'%>/" + $('#ip_address_id').val() + "?parent_type=<%= parent_type %>");
+ $("#ip_addresses_footer").hide();
+ }else{
+ reset_selected_ip_address();
+ }
+});
+
+</script>
+
diff --git a/src/app/views/network/_select.rhtml b/src/app/views/network/_select.rhtml
new file mode 100644
index 0000000..e69d9b0
--- /dev/null
+++ b/src/app/views/network/_select.rhtml
@@ -0,0 +1,32 @@
+<% target = 'nic' unless target
+ network_id = 'physical_network_id' if target == 'nic'
+ network_id = 'vlan_id' if target == 'bonding'
+
+ %>
+
+<div class="selected_popup_content_left">Network:</div>
+<div class="selected_popup_content_right">
+ <%= select_with_label "", target, network_id,
+ @networks.collect { |n| [n.name + ' - ' + n.boot_type.label, n.id ] } %>
+
+</div>
+
+<script type="text/javascript">
+ var static_network_ids=<%= static_network_ids = '['
+ @networks.each { |n|
+ static_network_ids += ',' if static_network_ids != '['
+ static_network_ids += n.id.to_s if n.boot_type_id == @static_boot_type.id
+ }
+ static_network_ids += ']'
+ static_network_ids %>;
+
+ $("#<%=target %>_<%= network_id %>").change(function () {
+ $("#static_ip_options").hide();
+ for(i=0; i<static_network_ids.length; ++i){
+ if($("#<%= target %>_<%= network_id %>").val() == static_network_ids[i]){
+ $("#static_ip_options").show();
+ break;
+ }
+ };
+ });
+</script>
diff --git a/src/app/views/network/edit.rhtml b/src/app/views/network/edit.rhtml
new file mode 100644
index 0000000..6360b3f
--- /dev/null
+++ b/src/app/views/network/edit.rhtml
@@ -0,0 +1,34 @@
+<%- content_for :title do -%>
+ Edit Network
+<%- end -%>
+<%- content_for :description do -%>
+<%- end -%>
+
+ <!-- DIALOG BODY -->
+ <form method="POST" action="<%= url_for :action => 'update' %>" id="network_form" >
+ <div class="dialog_form">
+ <%= hidden_field_tag 'id', @network.id %>
+ <%= render :partial => 'form', :locals => { :create => false } %>
+ </div>
+ <!-- DIALOG FOOTER -->
+ <%= popup_footer("$('#network_form').submit()", "Edit Network") %>
+ </form>
+
+<script type="text/javascript">
+$(function() {
+ var networkoptions = {
+ target: '<%= url_for :action => 'update' %>',
+ dataType: 'json',
+ success: function(response, status) {
+ afterNetwork(response, status);
+ refresh_summary_static('networks_selection',
+ '<div class="selection_left"><div>Select a network.</div></div>');
+ }
+ };
+
+ // bind form using 'ajaxForm'
+ $('#network_form').ajaxForm(networkoptions);
+});
+</script>
+
+
diff --git a/src/app/views/network/edit_bonding.rhtml b/src/app/views/network/edit_bonding.rhtml
new file mode 100644
index 0000000..645e469
--- /dev/null
+++ b/src/app/views/network/edit_bonding.rhtml
@@ -0,0 +1,52 @@
+<form method="POST"
+ action="<%= url_for :action => 'update_bonding' %>" id="edit_bonding_form" >
+ <div id="selected_popup_content_header">
+ Editing Bonded Interface
+ </div>
+
+ <%= hidden_field_tag('id', @bonding.id) %>
+ <%= render :partial => 'bonding_form' %>
+
+</form>
+
+<form method="POST" action="<%= url_for :action => 'destroy_bonding' %>" id="delete_bonding_form" >
+ <%= hidden_field_tag('id', @bonding.id) %>
+</form>
+
+<%= multi_button_popup_footer({"Edit Bonding" =>
+ "$('#edit_bonding_form').submit()",
+ "Delete Bonding" =>
+ "$('#delete_bonding_form').submit()"}) %>
+
+<script type="text/javascript">
+$(function() {
+ var edit_bonding_options = {
+ target: '<%= url_for :action => 'update_bonding' %>',
+ dataType: 'json',
+ success: function(response, status) {
+ ajax_validation(response, status);
+ if (response.success) {
+ reset_bonding_select();
+ reset_nics_bonding_detail();
+ }
+ }
+ };
+
+ var delete_bonding_options = {
+ target: '<%= url_for :action => 'destroy_bonding' %>',
+ dataType: 'json',
+ success: function(response, status) {
+ ajax_validation(response, status);
+ if (response.success) {
+ reset_bonding_select();
+ reset_nics_bonding_detail();
+ }
+ }
+ };
+
+ // bind forms using 'ajaxForm'
+ $('#edit_bonding_form').ajaxForm(edit_bonding_options);
+ $('#delete_bonding_form').ajaxForm(delete_bonding_options);
+
+});
+</script>
diff --git a/src/app/views/network/edit_ip_address.rhtml b/src/app/views/network/edit_ip_address.rhtml
new file mode 100644
index 0000000..5a3cc18
--- /dev/null
+++ b/src/app/views/network/edit_ip_address.rhtml
@@ -0,0 +1,66 @@
+<% if @parent_type == 'network' %>
+<form method="POST"
+ action="<%= url_for :action => 'update_ip_address' %>"
+ id="edit_ip_address_form" >
+<% end %>
+
+ <div id="selected_popup_content_header">
+ Editing IP Address
+ </div>
+
+ <% if @parent_type != 'network' %>
+ <a href="#" onClick="$('#delete_ip_address_form').submit()" style="color: blue;">Delete</a>
+ <% end %>
+
+ <%= hidden_field_tag('id', @ip_address.id) %>
+ <%= render :partial => 'ip_address_form' %>
+
+<% if @parent_type == 'network' %>
+</form>
+<% end %>
+
+<form method="POST"
+ action="<%= url_for :action => 'destroy_ip_address' %>"
+ id="delete_ip_address_form" >
+ <%= hidden_field_tag('id', @ip_address.id) %>
+</form>
+
+<% if @parent_type == 'network' %>
+<%= multi_button_popup_footer({" Edit IP Address" =>
+ "$('#edit_ip_address_form').submit()",
+ "Delete IP Address" =>
+ "$('#delete_ip_address_form').submit()"}) %>
+<% end %>
+
+<script type="text/javascript">
+$(function() {
+ var edit_ip_address_options = {
+ target: '<%= url_for :action => 'update_ip_address' %>', // target element to update
+ dataType: 'json',
+ success: function(response, status) {
+ ajax_validation(response, status);
+ if (response.success) {
+ reset_selected_ip_address();
+ reset_ip_address_select();
+ }
+ }
+ };
+
+ var delete_ip_address_options = {
+ target: '<%= url_for :action => 'delete_ip_address' %>', // target element to update
+ dataType: 'json',
+ success: function(response, status) {
+ ajax_validation(response, status);
+ if (response.success) {
+ reset_selected_ip_address();
+ reset_ip_address_select();
+ }
+ }
+ };
+
+ // bind forms using 'ajaxForm'
+ $('#edit_ip_address_form').ajaxForm(edit_ip_address_options);
+ $('#delete_ip_address_form').ajaxForm(delete_ip_address_options);
+
+});
+</script>
diff --git a/src/app/views/network/edit_network_ip_addresses.rhtml b/src/app/views/network/edit_network_ip_addresses.rhtml
new file mode 100644
index 0000000..7a1e4cb
--- /dev/null
+++ b/src/app/views/network/edit_network_ip_addresses.rhtml
@@ -0,0 +1,13 @@
+<%- content_for :title do -%>
+ Edit Network IP Addresses
+<%- end -%>
+<%- content_for :description do -%>
+<%- end -%>
+
+<%= render :partial => 'ip_addresses_form',
+ :locals => { :parent_type => 'network',
+ :parent_id => @network.id } %>
+
+<div id="ip_addresses_footer" class="popup-content-footer">
+ <%= ok_footer %>
+</div>
diff --git a/src/app/views/network/edit_nic.rhtml b/src/app/views/network/edit_nic.rhtml
new file mode 100644
index 0000000..75af6fb
--- /dev/null
+++ b/src/app/views/network/edit_nic.rhtml
@@ -0,0 +1,62 @@
+<form method="POST"
+ action="<%= url_for :action => 'update_nic' %>" id="nic_form" >
+ <div id="selected_popup_content_header">
+ Editing NIC
+ </div>
+
+ <%= error_messages_for 'nic' %>
+
+ <div id="selected_popup_content_expanded" class="dialog_form">
+ <%= hidden_field_tag 'id', @nic.id %>
+ <%= hidden_field_tag 'nic_host_id', @nic.host.id %>
+ <%= hidden_field_tag 'nic_network_id', @nic.physical_network.id %>
+
+ <div class="selected_popup_content_left">MAC:</div>
+ <div class="selected_popup_content_right"><%= @nic.mac %></div>
+
+ <% if @nic.host.bondings.size != 0 %>
+ <div class="selected_popup_content_left">Bonded Interfaces</div>
+ <div class="selected_popup_content_right">
+ <select id="nic_bonding_ids" name="nic[bonding_ids][]">
+ <option value="" />
+ <%= options_from_collection_for_select @nic.host.bondings,
+ "id", "name",
+ @nic.bondings.size > 0 ? @nic.bondings[0].bonding_id.to_i : "" %>
+ </select>
+ </div>
+ <% end %>
+
+
+ <%= render :partial => 'select' %>
+
+ <div id="static_ip_options"
+ style="<% if @network.boot_type_id != @static_boot_type.id %>
+ display: none;<%end %>">
+ <%= render :partial => 'ip_addresses_form',
+ :locals => { :parent_type => 'nic',
+ :parent_id => @nic.id } %>
+ </div>
+
+
+ </div>
+ <%= popup_footer("$('#nic_form').submit()", "Edit NIC") %>
+</form>
+
+<script type="text/javascript">
+$(function() {
+ var nicoptions = {
+ target: '<%= url_for :action => 'update_nic' %>',
+ dataType: 'json',
+ success: function(response, status) {
+ ajax_validation(response, status);
+ if (response.success) {
+ reset_nics_select();
+ reset_nics_bonding_detail();
+ }
+ }
+ };
+
+ // bind form using 'ajaxForm'
+ $('#nic_form').ajaxForm(nicoptions);
+});
+</script>
diff --git a/src/app/views/network/list.html.erb b/src/app/views/network/list.html.erb
new file mode 100644
index 0000000..9a304cf
--- /dev/null
+++ b/src/app/views/network/list.html.erb
@@ -0,0 +1,72 @@
+<div id="toolbar_nav">
+<ul>
+ <li><a href="<%= url_for :action => 'new' %>" rel="facebox[.bolder]"><%= image_tag "icon_addstorage.png", :style => "vertical-align:middle;" %> Add Network</a></li>
+ <li>
+ <a href="#" onClick="delete_networks();" >
+ <%= image_tag "icon_remove.png", :style=>"vertical-align:middle;" %>
+ Remove
+ </a>
+ </li>
+ </ul>
+</div>
+
+<script type="text/javascript">
+ function delete_networks(){
+ var networks = get_selected_networks();
+ if (validate_selected(get_selected_networks(), 'networks')) {
+ $.post('<%= url_for :action => 'delete' %>',
+ { network_ids: networks.toString() },
+ function(data,status){
+ if (data.alert) {
+ $.jGrowl(data.alert);
+ }
+ grid = $("#networks_grid");
+ if (grid.size()>0 && grid != null) {
+ grid.flexReload();
+ }
+ empty_summary('networks_selection', 'Network');
+ }, 'json');
+ }
+ }
+
+ function networks_select(selected_rows)
+ {
+ var selected_ids = new Array();
+ for(i=0; i<selected_rows.length; i++) {
+ selected_ids[i] = selected_rows[i].id;
+ }
+ if (selected_ids.length == 1)
+ {
+ $('#networks_selection').load('<%= url_for :action => "show" %>',
+ { id: parseInt(selected_ids[0].substring(3))});
+ }
+ }
+
+</script>
+
+<div class="panel_header"></div>
+<% if @networks.size != 0 %>
+ <div class="data_section">
+ <%= render :partial => "grid", :locals => { :table_id => "networks_grid",
+ :networks => @networks,
+ :on_select => "networks_select"} %>
+ </div>
+
+ <div class="selection_detail" id="networks_selection">
+ <div class="selection_left">
+ <div>Select a network.</div>
+ </div>
+ </div>
+<% else %>
+ <div class="data_section">
+ <div class="no-grid-items">
+ <%= image_tag 'no-grid-items.png', :style => 'float: left;' %>
+
+ <div class="no-grid-items-text">
+ No networks found. <br/><br/>
+ <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>
+ <a href="<%= url_for :action => 'new' %>" rel="facebox[.bolder]">Add first network</a>
+ </div>
+ </div>
+ </div>
+<% end %>
diff --git a/src/app/views/network/new.rhtml b/src/app/views/network/new.rhtml
new file mode 100644
index 0000000..15b7304
--- /dev/null
+++ b/src/app/views/network/new.rhtml
@@ -0,0 +1,28 @@
+<%- content_for :title do -%>
+ Add Network
+<%- end -%>
+<%- content_for :description do -%>
+<%- end -%>
+
+ <!-- DIALOG BODY -->
+ <form method="POST" action="<%= url_for :action => 'create' %>" id="network_form" >
+ <div class="dialog_form">
+ <%= render :partial => 'form', :locals => { :create => true } %>
+ </div>
+ <!-- DIALOG FOOTER -->
+ <%= popup_footer("$('#network_form').submit()", "Add Network") %>
+ </form>
+
+<script type="text/javascript">
+$(function() {
+ var networkoptions = {
+ target: '<%= url_for :action => 'create' %>',
+ dataType: 'json',
+ success: afterNetwork // post-submit callback
+ };
+
+ // bind form using 'ajaxForm'
+ $('#network_form').ajaxForm(networkoptions);
+});
+</script>
+
diff --git a/src/app/views/network/new_bonding.rhtml b/src/app/views/network/new_bonding.rhtml
new file mode 100644
index 0000000..9ee6994
--- /dev/null
+++ b/src/app/views/network/new_bonding.rhtml
@@ -0,0 +1,32 @@
+<form method="POST"
+ action="<%= url_for :action => 'create_bonding' %>" id="bonding_form" >
+
+ <div id="selected_popup_content_header">
+ Create Bonded Interface
+ </div>
+
+ <%= render :partial => 'bonding_form' %>
+</form>
+
+<%= multi_button_popup_footer({"Create Bonding" =>
+ "$('#bonding_form').submit()"}) %>
+
+<script type="text/javascript">
+$(function() {
+ var bonding_options = {
+ target: '<%= url_for :action => 'create_bonding' %>',
+ dataType: 'json',
+ success: function(response, status) {
+ ajax_validation(response, status);
+ if (response.success) {
+ reset_bonding_select();
+ reset_nics_bonding_detail();
+ }
+ }
+ };
+
+ // bind forms using 'ajaxForm'
+ $('#bonding_form').ajaxForm(bonding_options);
+
+});
+</script>
diff --git a/src/app/views/network/new_ip_address.rhtml b/src/app/views/network/new_ip_address.rhtml
new file mode 100644
index 0000000..6167a76
--- /dev/null
+++ b/src/app/views/network/new_ip_address.rhtml
@@ -0,0 +1,33 @@
+<% if @parent_type == 'network' %>
+<form method="POST"
+ action="<%= url_for :action => 'create_ip_address' %>"
+ id="ip_address_form" >
+<% end %>
+
+ <div id="selected_popup_content_header">
+ Create Ip Address
+ </div>
+
+ <%= render :partial => 'ip_address_form' %>
+
+<% if @parent_type == 'network' %>
+</form>
+<% end %>
+
+<% if @parent_type == 'network' %>
+<%= multi_button_popup_footer({"Create IP Address" =>
+ "$('#ip_address_form').submit()"}) %>
+<% end %>
+
+<script type="text/javascript">
+$(function() {
+ var ip_address_options = {
+ target: '<%= url_for :action => 'create_ip_address' %>',
+ dataType: 'json',
+ success: afterIpAddress
+ };
+
+ // bind forms using 'ajaxForm'
+ $('#ip_address_form').ajaxForm(ip_address_options);
+});
+</script>
diff --git a/src/app/views/network/show.rhtml b/src/app/views/network/show.rhtml
new file mode 100644
index 0000000..a56c41d
--- /dev/null
+++ b/src/app/views/network/show.rhtml
@@ -0,0 +1,30 @@
+<%- content_for :title do -%>
+ <%=h @network.name %>
+<%- end -%>
+
+<%- content_for :action_links do -%>
+ <%= link_to image_tag("icon_edit.png") + "Edit",
+ {:action => 'edit', :id => @network.id },
+ :rel=>"facebox[.bolder]", :class=>"selection_facebox" %>
+
+ <%= link_to image_tag("icon_edit.png") + "Edit IP Addresses",
+ {:action => 'edit_network_ip_addresses', :id => @network.id },
+ :rel=>"facebox[.bolder]", :class=>"selection_facebox" %>
+<%- end -%>
+
+<div id="hosts_selection_id" style="display:none"><%= @host.id %></div>
+<div class="selection_key">
+ Name:<br/>
+ Type:<br/>
+ Boot Type:<br/>
+ IP Addresses:<br/>
+</div>
+<div class="selection_value">
+ <%=h @network.name %><br/>
+ <%=h @network.type %><br/>
+ <%=h @network.boot_type.label %><br/>
+ <%=h @network.ip_addresses.size %><br/>
+</div>
+
+<%- content_for :right do -%>
+<%- end -%>
diff --git a/src/app/views/nic/_list.rhtml b/src/app/views/nic/_list.rhtml
index 07f7e44..eb3a4a7 100644
--- a/src/app/views/nic/_list.rhtml
+++ b/src/app/views/nic/_list.rhtml
@@ -1,7 +1,6 @@
<table class='listing'>
<thead>
<tr>
- <th class="empty">IP</th>
<th>MAC</th>
<th>Bridge</th>
<th>Usage Type</th>
@@ -11,7 +10,6 @@
</thead>
<% for nic in nics %>
<tr class="<%= cycle('odd','even', :name => nics) %>">
- <td><%= link_to nic.ip_addr, { :controller => "nic", :action => 'show', :id => nic }, { :class => "show" } %></td>
<td><%= nic.mac %></td>
<td><%= nic.bridge %></td>
<td><%= nic.usage_type %></td>
diff --git a/src/db/migrate/028_refactor_networking_model.rb b/src/db/migrate/028_refactor_networking_model.rb
new file mode 100644
index 0000000..946b976
--- /dev/null
+++ b/src/db/migrate/028_refactor_networking_model.rb
@@ -0,0 +1,271 @@
+# Copyright (C) 2008 Red Hat, Inc.
+# Written by Mohammed Morsi <mmorsi at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA. A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+# introduce networks and ip_addresses tables, refactor relationships
+class RefactorNetworkingModel < ActiveRecord::Migration
+ def self.up
+
+ ####################################################
+ # bugfix, bridge tables shouldn't have their own ids
+ remove_column :bondings_nics, :id
+
+ ##################################################################
+ # add networks, usages tables and networks_usage_types bridge
+ create_table :networks do |t|
+ t.string :type, :null => false
+ t.string :name, :null => false
+ t.integer :boot_type_id, :null => false
+
+ # attributes for Vlan (type=Vlan)
+ t.integer :number
+ end
+
+ create_table :usages do |t|
+ t.string :label, :null => false
+ t.string :usage, :null => false
+ end
+
+ create_table :networks_usages, :id => false do |t|
+ t.integer :network_id, :null => false
+ t.integer :usage_id, :null => false
+ end
+
+ add_index :networks_usages, [:network_id, :usage_id], :unique => true
+
+ # create usages
+ Usage.create(:label => 'Guest', :usage => 'guest')
+ Usage.create(:label => 'Management', :usage => 'management')
+ Usage.create(:label => 'Storage', :usage => 'storage')
+
+ # referential integrity for networks tables
+ execute "alter table networks add constraint
+ fk_network_boot_types
+ foreign key (boot_type_id) references
+ boot_types(id)"
+ execute "alter table networks_usages add constraint
+ fk_networks_usages_network_id
+ foreign key (network_id) references
+ networks(id)"
+ execute "alter table networks_usages add constraint
+ fk_networks_usages_usage_id
+ foreign key (usage_id) references
+ usages(id)"
+
+ # add foreign keys to nics / bondings table
+ add_column :nics, :physical_network_id, :integer
+ add_column :bondings, :vlan_id, :integer
+
+ # referential integrity for nic/bondings network ids
+ execute "alter table nics add constraint
+ fk_nic_networks
+ foreign key (physical_network_id) references
+ networks(id)"
+ execute "alter table bondings add constraint
+ fk_bonding_networks
+ foreign key (vlan_id) references
+ networks(id)"
+
+ ####################################################
+ # create ip_addresses table
+ create_table :ip_addresses do |t|
+ t.string :type
+
+ # foreign keys to associated entities
+ t.integer :nic_id
+ t.integer :bonding_id
+ t.integer :network_id
+
+ # common attributes
+ t.string :address, :limit => 39, :null => false
+ t.string :gateway, :limit => 39
+
+ # attributes for IPv4 (type=IpV4Address)
+ t.string :netmask, :limit => 15
+ t.string :broadcast, :limit => 15
+
+ # attributes for IPv6 (type=IpV6Address)
+ t.string :prefix, :limit => 39
+ t.timestamps
+ end
+
+ # referential integrity for ip_addresses table
+ execute "alter table ip_addresses add constraint
+ fk_nic_ip_addresses
+ foreign key (nic_id) references nics(id)"
+ execute "alter table ip_addresses add constraint
+ fk_bonding_ip_addresses
+ foreign key (bonding_id) references bondings(id)"
+ execute "alter table ip_addresses add constraint
+ fk_network_ip_addresses
+ foreign key (network_id) references networks(id)"
+
+ ###################################################################
+ static_boot_type_id =
+ BootType.find(:first,
+ :conditions => {:proto => 'static'} ).id
+
+ # migrate nic ip_addresses to networks / ip_addresses table
+ i = 0
+ Nic.find(:all).each do |nic|
+ if nic.boot_type_id == static_boot_type_id
+ IpV4Address.new(:nic_id => nic.id,
+ :address => nic.ip_addr).save!
+
+ end
+ network = PhysicalNetwork.new(
+ :name => 'Physical Network ' + i.to_s,
+ :boot_type_id => nic.boot_type_id)
+ network.save!
+
+ ip_address = IpV4Address.new(:address => nic.ip_addr ? nic.ip_addr : '0.0.0.0',
+ :netmask => nic.netmask,
+ :broadcast => nic.broadcast,
+ :gateway => nic.ip_addr)
+ ip_address.network = network
+ ip_address.save!
+
+ nic.physical_network = network
+ nic.save!
+
+ i += 1
+ end
+
+ # migrate bonding ip_addresses to networks / ip_addresses table
+ i = 0
+ Bonding.find(:all).each do |bonding|
+ if bonding.boot_type_id == static_boot_type_id
+ IpV4Address.new(:bonding_id => bonding.id,
+ :address => bonding.ip_addr).save!
+ end
+ network = Vlan.new(
+ :name => 'VLAN ' + i.to_s,
+ :number => i,
+ :boot_type_id => bonding.boot_type_id)
+ network.save!
+
+ ip_address = IpV4Address.new(:address => bonding.ip_addr ? bonding.ip_addr : '0.0.0.0',
+ :netmask => bonding.netmask,
+ :broadcast => bonding.broadcast,
+ :gateway => bonding.ip_addr)
+ ip_address.network = network
+ ip_address.save!
+
+ bonding.vlan = network
+ bonding.save!
+
+ i += 1
+ end
+
+ ##############################################################
+ # remove nics / bonding ip address and network related columns
+ remove_column :nics, :ip_addr
+ remove_column :nics, :netmask
+ remove_column :nics, :broadcast
+ remove_column :nics, :boot_type_id
+ remove_column :bondings, :ip_addr
+ remove_column :bondings, :netmask
+ remove_column :bondings, :broadcast
+ remove_column :bondings, :boot_type_id
+
+
+ end
+
+ def self.down
+ ##############################################################
+ # readd nics / bonding ip address related columns
+ add_column :nics, :ip_addr, :string, :limit => 16
+ add_column :nics, :netmask, :string, :limit => 16
+ add_column :nics, :broadcast, :string, :limit => 16
+ add_column :nics, :boot_type_id, :integer
+ add_column :bondings, :ip_addr, :string, :limit => 16
+ add_column :bondings, :netmask, :string, :limit => 16
+ add_column :bondings, :broadcast, :string, :limit => 16
+ add_column :bondings, :boot_type_id, :integer
+
+ execute "alter table nics add constraint
+ fk_nic_boot_types
+ foreign key (boot_type_id) references
+ boot_types(id)"
+ execute "alter table bondings add constraint
+ fk_bonding_boot_types
+ foreign key (boot_type_id) references
+ boot_types(id)"
+
+ ##############################################################
+ # attempt to migrate ip information back into nics table.
+ # because a nic can have multiple ips (if statically
+ # assigned) as well as its network, just use the 1st
+ # found
+ Nic.find(:all).each do |nic|
+ if nic.physical_network.ip_addresses.size > 0
+ # use the 1st configured network ip
+ nic.ip_addr = nic.physical_network.ip_addresses[0].address
+ nic.netmask = nic.physical_network.ip_addresses[0].netmask
+ nic.broadcast = nic.physical_network.ip_addresses[0].broadcast
+ end
+
+ if nic.ip_addresses.size > 0
+ # use the 1st assigned static ip
+ nic.ip_addr = nic.ip_addresses[0].address
+ end
+
+ nic.boot_type_id = nic.physical_network.boot_type_id
+
+ nic.save!
+ end
+
+ # attempt to migrate ip information back into bondings table.
+ # because a bonding can have multiple ips (if statically
+ # assigned) as well as its network, just use the 1st
+ # found
+ Bonding.find(:all).each do |bonding|
+ if bonding.vlan.ip_addresses.size > 0
+ # use the 1st configured network ip
+ bonding.ip_addr = bonding.vlan.ip_addresses[0].address
+ bonding.netmask = bonding.vlan.ip_addresses[0].netmask
+ bonding.broadcast = bonding.vlan.ip_addresses[0].broadcast
+ end
+
+ if bonding.ip_addresses.size > 0
+ # use the 1st assigned static ip
+ bonding.ip_addr = bonding.ip_addresses[0].address
+ end
+
+ bonding.boot_type_id = bonding.vlan.boot_type_id
+
+ bonding.save!
+ end
+
+ ##############################################################
+ # drop ip_addresses table
+ drop_table :ip_addresses
+
+ # drop network ids from nics / bondings table
+ remove_column :nics, :physical_network_id
+ remove_column :bondings, :vlan_id
+
+ # drop networks tables
+ drop_table :networks_usages
+ drop_table :usages
+ drop_table :networks
+
+ ##############################################################
+ # undo bugfix above
+ add_column :bondings_nics, :id, :integer
+ end
+end
diff --git a/src/public/javascripts/ovirt.js b/src/public/javascripts/ovirt.js
index 4579c80..818b862 100644
--- a/src/public/javascripts/ovirt.js
+++ b/src/public/javascripts/ovirt.js
@@ -297,4 +297,31 @@ function delete_pool(delete_url, id)
$.jGrowl(data.alert);
}
}, 'json');
-}
\ No newline at end of file
+}
+
+
+function get_selected_networks()
+{
+ return get_selected_checkboxes("networks_grid_form");
+}
+
+function afterNetwork(response, status){
+ ajax_validation(response, status);
+ if (response.success) {
+ $(document).trigger('close.facebox');
+ grid = $("#networks_grid");
+ if (grid.size()>0 && grid != null) {
+ grid.flexReload();
+ } else {
+ $tabs.tabs("load",$tabs.data('selected.tabs'));
+ }
+ }
+}
+
+function afterIpAddress(response, status){
+ ajax_validation(response, status);
+ if (response.success) {
+ reset_selected_ip_address();
+ reset_ip_address_select();
+ }
+}
diff --git a/src/public/stylesheets/components.css b/src/public/stylesheets/components.css
index 16eaf62..228ff7b 100644
--- a/src/public/stylesheets/components.css
+++ b/src/public/stylesheets/components.css
@@ -267,4 +267,52 @@
.detail-pane-chart {
height: 50px;
width: 375px;
-};
+}
+
+
+/*************************
+ * new popup components
+ *************************/
+.popup-content-selection {
+ float: left;
+ width: 45%;
+ padding-left: 20px;
+ padding-top: 10px;
+}
+
+.popup-content-selection select{
+ min-width: 200px;
+}
+
+.popup-content-footer{
+ width: 99%;
+ float: left;
+}
+
+.selected_popup_content {
+ padding-left: 20px;
+ min-height: 50px;
+ float: left;
+ width: 96%;
+}
+
+#selected_popup_content_header {
+ padding-bottom: 5px;
+ font-weight: bold;
+}
+
+#selected_popup_content_expanded{
+ padding-bottom: 50px;
+}
+
+.selected_popup_content_left {
+ float: left;
+ width: 40%;
+ padding-bottom: 15px;
+}
+
+.selected_popup_content_right {
+ float: left;
+ width: 40%;
+ padding-bottom: 15px;
+}
--
1.5.6.5
More information about the ovirt-devel
mailing list