From mailing.lists at sapo.pt Mon Jan 5 12:22:59 2009 From: mailing.lists at sapo.pt (=?ISO-8859-1?Q?M=E1rcio_Miguel_da_Silva_Santos?=) Date: Mon, 05 Jan 2009 12:22:59 +0000 Subject: [Ovirt-devel] Information Request - Networking spanning multiple physical machines Message-ID: <4961FBA3.1040202@sapo.pt> Good morning I have been following oVirt development for some time now. I just wanted to make a quick question about networking. I came across a project called VDE, Virtual Distributed Ethernet. It creates virtual networks that span across multiple physical machines for use with virtual infrastructures. Is oVirt capable of doing the same? Would there be an interest in integrating VDE with oVirt to enhance the Network functions of oVirt? Thank you all for your time. M?rcio Santos From pmyers at redhat.com Mon Jan 5 13:54:56 2009 From: pmyers at redhat.com (Perry Myers) Date: Mon, 05 Jan 2009 08:54:56 -0500 Subject: [Ovirt-devel] Information Request - Networking spanning multiple physical machines In-Reply-To: <4961FBA3.1040202@sapo.pt> References: <4961FBA3.1040202@sapo.pt> Message-ID: <49621130.1010105@redhat.com> ? wrote: > Good morning > > I have been following oVirt development for some time now. > I just wanted to make a quick question about networking. > > I came across a project called VDE, Virtual Distributed Ethernet. > It creates virtual networks that span across multiple physical machines > for use with virtual infrastructures. > > Is oVirt capable of doing the same? > Would there be an interest in integrating VDE with oVirt to enhance the > Network functions of oVirt? > > Thank you all for your time. Thanks for your interest in oVirt :) Right now we don't have support for VLAN or VPN functionality, which is what this sounds like. We have discussed using open source tools like Openswan to create a virtual network between a set of oVirt Nodes and that is on the long term roadmap, but is still a while away. However, if you want to lend a hand to accelerate the process we would certainly welcome the help. Thanks, Perry From clalance at redhat.com Mon Jan 5 14:42:42 2009 From: clalance at redhat.com (Chris Lalancette) Date: Mon, 05 Jan 2009 15:42:42 +0100 Subject: [Ovirt-devel] ovirt-early script, scan_for_swap method In-Reply-To: <2be7262f0812230953g43f84337sc03d9831e0597178@mail.gmail.com> References: <20081223141842.GB6612@mcpierce-laptop.mcpierce.org> <2be7262f0812230953g43f84337sc03d9831e0597178@mail.gmail.com> Message-ID: <49621C62.8090400@redhat.com> Alan Pevec wrote: > On Tue, Dec 23, 2008 at 3:18 PM, Darryl L. Pierce wrote: >> In writing up the boot description wiki page[1] I found a method in >> ovirt-early called scan_for_swap. But I can't find any reference to >> this script anywhere, nothing seems to be invoking it. Is this >> unused and should be removed? >> >> [1] http://ovirt.org/wiki/index.php?title=Node_Boot_Sequence > > I moved swap scanning into a function recently and wanted to discuss > whether we want to do such scanning or use only swap area created by > ovirt-config-storage on /dev/HostVG/Swap > Chris, since you originally wrote that swap scanning, what do you > think - should we keep adding all swap areas in sight? I think this > could be problematic as we add clustered storage. I'm sort of on the fence about it. On the one hand, it is quite convenient to get swap for "free" if you happen to boot the PXE image on a machine that already has an OS on the hard drive. On the other hand, things like clustering and full administrator control are important, so we don't necessarily want to be doing things behind the admin's back. Can we disable the scanning by default, but add a PXE boot option to enable the scanning for developers? -- Chris Lalancette From pmyers at redhat.com Mon Jan 5 14:56:53 2009 From: pmyers at redhat.com (Perry Myers) Date: Mon, 05 Jan 2009 09:56:53 -0500 Subject: [Ovirt-devel] ovirt-early script, scan_for_swap method In-Reply-To: <49621C62.8090400@redhat.com> References: <20081223141842.GB6612@mcpierce-laptop.mcpierce.org> <2be7262f0812230953g43f84337sc03d9831e0597178@mail.gmail.com> <49621C62.8090400@redhat.com> Message-ID: <49621FB5.9070008@redhat.com> Chris Lalancette wrote: > Alan Pevec wrote: >> On Tue, Dec 23, 2008 at 3:18 PM, Darryl L. Pierce wrote: >>> In writing up the boot description wiki page[1] I found a method in >>> ovirt-early called scan_for_swap. But I can't find any reference to >>> this script anywhere, nothing seems to be invoking it. Is this >>> unused and should be removed? >>> >>> [1] http://ovirt.org/wiki/index.php?title=Node_Boot_Sequence >> I moved swap scanning into a function recently and wanted to discuss >> whether we want to do such scanning or use only swap area created by >> ovirt-config-storage on /dev/HostVG/Swap >> Chris, since you originally wrote that swap scanning, what do you >> think - should we keep adding all swap areas in sight? I think this >> could be problematic as we add clustered storage. > > I'm sort of on the fence about it. On the one hand, it is quite convenient to > get swap for "free" if you happen to boot the PXE image on a machine that > already has an OS on the hard drive. On the other hand, things like clustering > and full administrator control are important, so we don't necessarily want to be > doing things behind the admin's back. Can we disable the scanning by default, > but add a PXE boot option to enable the scanning for developers? > I agree with this approach... By default only use swap created by ovirt-config-storage unless a kernel param like use_existing_swap is passed in via PXE. Darryl can you create a patch for the function that Alan split out for swap scanning to do this? Thanks, Perry -- |=- Red Hat, Engineering, Emerging Technologies, Boston -=| |=- Email: pmyers at redhat.com -=| |=- Office: +1 412 474 3552 Mobile: +1 703 362 9622 -=| |=- GnuPG: E65E4F3D 88F9 F1C9 C2F3 1303 01FE 817C C5D2 8B91 E65E 4F3D -=| From dpierce at redhat.com Mon Jan 5 18:14:50 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 5 Jan 2009 13:14:50 -0500 Subject: [Ovirt-devel] [PATCH node] make ovirt-config-setup menu configurable In-Reply-To: <1230159599-4277-1-git-send-email-apevec@redhat.com> References: <1230159599-4277-1-git-send-email-apevec@redhat.com> Message-ID: <20090105181450.GB26941@mcpierce-laptop.rdu.redhat.com> On Wed, Dec 24, 2008 at 11:59:58PM +0100, Alan Pevec wrote: > custom menu option can be added using a symlink in > /etc/ovirt-config-setup.d/ pointing to the script to be executed > > implement default options using this method ACK. The patch works well. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From dpierce at redhat.com Mon Jan 5 18:56:34 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 5 Jan 2009 13:56:34 -0500 Subject: [Ovirt-devel] [PATCH node] add "Local install and reboot" option In-Reply-To: <1230159599-4277-2-git-send-email-apevec@redhat.com> References: <1230159599-4277-1-git-send-email-apevec@redhat.com> <1230159599-4277-2-git-send-email-apevec@redhat.com> Message-ID: <20090105185634.GA22793@mcpierce-laptop.rdu.redhat.com> On Wed, Dec 24, 2008 at 11:59:59PM +0100, Alan Pevec wrote: > ovirt-config-boot can be called without parameters, as an option > in ovirt-config-setup menu, defaults are taken from /etc/default/ovirt ACK. Works well. I did notice something we ought to fix WRT the install portion. If the script doesn't see any partitioning table then it should show an error message and return the user to the menu rather than continuing. Otherwise if someone tries to install and reboot they'll get a quick flash of text and then reboots without the user seeing the problem. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From dpierce at redhat.com Mon Jan 5 19:27:20 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 5 Jan 2009 14:27:20 -0500 Subject: [Ovirt-devel] [PATCH node] add "Local install and reboot" option In-Reply-To: <1230159599-4277-2-git-send-email-apevec@redhat.com> References: <1230159599-4277-1-git-send-email-apevec@redhat.com> <1230159599-4277-2-git-send-email-apevec@redhat.com> Message-ID: <20090105192720.GA24139@mcpierce-laptop.rdu.redhat.com> On Wed, Dec 24, 2008 at 11:59:59PM +0100, Alan Pevec wrote: > -ovirt_boot_setup "$1" "$2" "$3" > +disk=$1 > +live=$2 > +bootparams=$3 > +doreboot=$4 > +if [ -z "$disk" ]; then > + disk=$OVIRT_INIT > +fi > +if [ -z "$live" ]; then > + mount_live > + live=/live > +fi > +if [ -z "$bootparams" ]; then > + bootparams="$OVIRT_BOOTPARAMS" > +fi > + > +ovirt_boot_setup "$disk" "$live" "$bootparams" > > +if [ -z "$doreboot" -o "$doreboot" = "yes" ]; then > + disable_firstbot Missed this earlier. There's a typo here, should be "disable_firstboot" shouldn't it? -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From bkearney at redhat.com Mon Jan 5 19:52:28 2009 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 5 Jan 2009 14:52:28 -0500 Subject: [Ovirt-devel] [PATCH server] Add the installer files as a subpackage of the server package Message-ID: <1231185148-2729-1-git-send-email-bkearney@redhat.com> --- Makefile.am | 3 +- installer/bin/ovirt-installer | 273 ++++++++++++++++++++ installer/modules/ovirt/files/collectd.conf | 23 ++ installer/modules/ovirt/files/dns_entries.sh | 2 + installer/modules/ovirt/files/modules.conf | 96 +++++++ installer/modules/ovirt/files/qpidd.conf | 4 + installer/modules/ovirt/manifests/cobbler.pp | 126 +++++++++ installer/modules/ovirt/manifests/dhcp.pp | 34 +++ installer/modules/ovirt/manifests/dns.pp | 99 +++++++ installer/modules/ovirt/manifests/freeipa.pp | 103 ++++++++ installer/modules/ovirt/manifests/init.pp | 9 + installer/modules/ovirt/manifests/ovirt.pp | 154 +++++++++++ installer/modules/ovirt/manifests/postgres.pp | 114 ++++++++ installer/modules/ovirt/manifests/tftp.pp | 31 +++ installer/modules/ovirt/templates/digest_line.erb | 4 + .../modules/ovirt/templates/ovirt-dhcp.conf.erb | 9 + .../modules/ovirt/templates/ovirt-dns.conf.erb | 7 + .../modules/ovirt/templates/ovirt-tftp.conf.erb | 3 + ovirt-server.spec.in | 23 ++- 19 files changed, 1115 insertions(+), 2 deletions(-) create mode 100755 installer/bin/ovirt-installer create mode 100644 installer/modules/ovirt/files/collectd.conf create mode 100755 installer/modules/ovirt/files/dns_entries.sh create mode 100644 installer/modules/ovirt/files/modules.conf create mode 100644 installer/modules/ovirt/files/qpidd.conf create mode 100644 installer/modules/ovirt/manifests/cobbler.pp create mode 100644 installer/modules/ovirt/manifests/dhcp.pp create mode 100644 installer/modules/ovirt/manifests/dns.pp create mode 100644 installer/modules/ovirt/manifests/freeipa.pp create mode 100644 installer/modules/ovirt/manifests/init.pp create mode 100644 installer/modules/ovirt/manifests/ovirt.pp create mode 100644 installer/modules/ovirt/manifests/postgres.pp create mode 100644 installer/modules/ovirt/manifests/tftp.pp create mode 100644 installer/modules/ovirt/templates/digest_line.erb create mode 100644 installer/modules/ovirt/templates/ovirt-dhcp.conf.erb create mode 100644 installer/modules/ovirt/templates/ovirt-dns.conf.erb create mode 100644 installer/modules/ovirt/templates/ovirt-tftp.conf.erb diff --git a/Makefile.am b/Makefile.am index e11e636..f115c8f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -23,7 +23,8 @@ EXTRA_DIST = \ ovirt-server.spec.in \ scripts \ conf \ - src + src \ + installer DISTCLEANFILES = $(PACKAGE)-$(VERSION).tar.gz diff --git a/installer/bin/ovirt-installer b/installer/bin/ovirt-installer new file mode 100755 index 0000000..84604ef --- /dev/null +++ b/installer/bin/ovirt-installer @@ -0,0 +1,273 @@ +#!/usr/bin/ruby +#-- +## Copyright (C) 2008 Red Hat Inc. +## +## This library is free software; you can redistribute it and/or +## modify it under the terms of the GNU Lesser General Public +## License as published by the Free Software Foundation; either +## version 2.1 of the License, or (at your option) any later version. +## +## This library 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 +## Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public +## License along with this library; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +## +## Author: Joey Boggs +##-- +## oVirt Installation Script + +require 'socket' +require 'fileutils' + +if File.exist?("/usr/sbin/sestatus") +sestatus = `/usr/sbin/sestatus` +if sestatus !~ /(Current mode: permissive|Current mode: disabled|SELinux status: disabled|SELinux status: permissive)/ +puts "SELinux enabled, please disable or set in permissive mode permanently by editing" +puts "/etc/selinux/config and rebooting" +exit +end +end + +FileUtils.mkdir_p("/usr/share/ace/appliances/ovirt") +config_file = File.new("/usr/share/ace/appliances/ovirt/ovirt.pp", "w") +config_file.write "import 'ovirt'\n" +config_file.write "import 'firewall'\n\n" +config_file.write "firewall::setup{'setup': status => 'disabled'}\n\n" + +mgmt_dev = "" +prov_dev = "" + +dev_ct = 0 +net_devs = `hal-find-by-capability --capability net` +net_devs.each_line{ |dev| +dev_ct = dev_ct + 1 +} + +if dev_ct == 0 +puts "Unable to install without a network interface" +exit + +else +puts "" +get_net_devs = `hal-find-by-capability --capability net` +puts "Below are the detected networking devices\n\n" +puts "mac address interface ip address" +net_devs.each_line{ |dev| +dev = dev.chomp +interface = `hal-get-property --udi #{dev} --key net.interface` +mac = `hal-get-property --udi #{dev} --key net.address` +ip = `ifconfig #{interface}` +ipaddr = ip.scan(/\s*inet addr:([\d.]+)/) +puts mac.chop + " : " + interface.chop + " : " + ipaddr.to_s if interface.chop != "lo" +} +end + +if dev_ct > 1 +puts "\nDo you want separate management and provisioning networks? (y/n)" +sep_networks = gets.chomp +while sep_networks != "y" and sep_networks != "n" +puts "Invalid choice" +puts "Do you want separate management and provisioning networks? (y/n)" +sep_networks = gets.chomp +end + +if sep_networks == "y" +while mgmt_dev == "" +puts "Input your management interface (example: eth0)" +mgmt_dev = gets.chomp +end + +while prov_dev == "" +puts "Input your provisioning interface, this may also be your management interface (example: eth1)" +prov_dev = gets.chomp +end + +elsif sep_networks == "n" +while mgmt_dev == "" +puts "Input your management/provisioning interface (example: eth1)" +mgmt_dev = gets.chomp +prov_dev = mgmt_dev +end +end + +elsif dev_ct == 1 +while mgmt_dev == "" +puts "\nOnly one networking device detected" +puts "Input your management/provisioning interface (example: eth1)" +mgmt_dev = gets.chomp +prov_dev = mgmt_dev +puts "Need Management interface" +end +end + +puts "Enter the hostname of the oVirt management server (example: management.example.com)" +ovirt_host = gets.chomp +ipa_host = ovirt_host + +puts "\nUse this system's dns servers (y/n)" +File.open('/etc/resolv.conf').each_line{ |line| + line = line.chomp +puts line if line =~ /nameserver/ and line !~ /nameserver 127.0.0.1/ +} +dns_servers = gets.chomp + +while dns_servers != "y" and dns_servers != "n" +puts "Invalid choice" +dns_servers = gets.chomp +end + +mgmt_ip = `ifconfig #{mgmt_dev}` +mgmt_ipaddr= mgmt_ip.scan(/\s*inet addr:([\d.]+)/) +prov_ip = `ifconfig #{prov_dev}` +prov_ipaddr= prov_ip.scan(/\s*inet addr:([\d.]+)/) + +config_file.write "# dns configuration\n" +config_file.write "$mgmt_ipaddr = '#{mgmt_ipaddr}'\n" +config_file.write "$prov_ipaddr = '#{prov_ipaddr}'\n" +config_file.write "$ovirt_host = '#{ovirt_host}'\n" +config_file.write "$ipa_host = '#{ipa_host}'\n\n" + +if dns_servers == "n" +config_file.write "dns::bundled{setup: mgmt_ipaddr=> $mgmt_ipaddr, prov_ipaddr=> $prov_ipaddr, mgmt_dev => '#{mgmt_dev}', prov_dev => '#{prov_dev}'}\n\n" +end + +if dns_servers == "y" +config_file.write "dns::remote{setup: mgmt_ipaddr=> $mgmt_ipaddr, prov_ipaddr=> $prov_ipaddr, mgmt_dev => '#{mgmt_dev}', prov_dev => '#{prov_dev}'}\n\n" +host_lookup = Socket.getaddrinfo(ipa_host,nil) +hostip = host_lookup[1][3] +if hostip.to_s != mgmt_ipaddr.to_s +puts "Reverse dns lookup for #{ipa_host} failed, exiting" +exit +end +end + +puts "Does you provisioning network already have dhcp? (y/n)" +dhcp_setup = gets.chomp +while dhcp_setup != "y" and dhcp_setup != "n" +puts "Invalid choice" +dhcp_setup = gets.chomp +end + +if dhcp_setup == "n" + +puts "DHCP Configuration\n" +config_file.write "# dhcp configuration\n" +dhcp_interface = prov_dev +config_file.write "$dhcp_interface = '#{dhcp_interface}'\n" + +puts "Enter the first 3 octets of the dhcp network you wish to use (example: 192.168.50)" +dhcp_network = gets.chomp +config_file.write "$dhcp_network = '#{dhcp_network}'\n" + +puts "Enter the dhcp pool start address (example: 3)" +dhcp_start = gets.chomp +config_file.write "$dhcp_start = '#{dhcp_start}'\n" + +puts "Enter the dhcp pool end addess (example: 100)" +dhcp_stop = gets.chomp +config_file.write "$dhcp_stop = '#{dhcp_stop}'\n" + +puts "Enter the dhcp domain you wish to use (example: example.com)" +dhcp_domain = gets.chomp +config_file.write "$dhcp_domain = '#{dhcp_domain}'\n" + +config_file.write "$ntp_server = '#{mgmt_ipaddr}'\n\n" + +puts "Provide pxe/tftp capability? (y/n)" +tftp_setup = gets.chomp + +if sep_networks == "y" +prov_ip = `ifconfig #{prov_dev}` +prov_dns_server = prov_ip.scan(/\s*inet addr:([\d.]+)/) +config_file.write "$prov_dns_server = '#{prov_dns_server}'\n" + +puts "Enter the network gateway for your provisioning network (example: 192.168.50.254)" +prov_network_gateway = gets.chomp +config_file.write "$prov_network_gateway = '#{prov_network_gateway}'\n" +end +end + +# Cobbler Configuration +puts "Do you have a cobbler already that you wish to use? (y/n)" +cobbler_setup = gets.chomp + +while cobbler_setup != "y" and cobbler_setup != "n" +puts "Invalid choice" +cobbler_setup = gets.chomp +end + +cobbler_config = "n" + +if cobbler_setup == "y" +puts "Enter the hostname of your cobbler server" +cobbler_hostname = gets.chomp +puts "Enter your cobbler username" +cobbler_user_name= gets.chomp +puts "Enter your cobbler user password" +cobbler_user_password = gets.chomp + +elsif cobbler_setup == "n" +cobbler_hostname = "localhost" +puts "We will setup a cobbler instance, please provide the following information" +puts "Enter your cobbler username" +cobbler_user_name= gets.chomp +puts "Enter your cobbler user password" +cobbler_user_password = gets.chomp +end + +config_file.write "# cobbler configuration\n" +config_file.write "$cobbler_hostname = '#{cobbler_hostname}'\n" +config_file.write "$cobbler_user_name = '#{cobbler_user_name}'\n" +config_file.write "$cobbler_user_password = '#{cobbler_user_password}'\n\n" + + +# Postgres Configuration +puts "Enter a password for the ovirt postgres account" +db_username = "ovirt" +db_password = gets.chomp +config_file.write "# postgres configuration\n" +config_file.write "$db_username = '#{db_username}'\n" +config_file.write "$db_password = '#{db_password}'\n\n" + +# FreeIPA Configuration +config_file.write "# FreeIPA configuration\n" +puts "Enter your realm name (example: example.com)" +realm_name = gets.chomp +config_file.write "$realm_name = '#{realm_name}'\n" +puts "\nEnter an administrator password for FreeIPA " +puts "*** This will also be you ovirtadmin password for the web management login ***\n\n" +freeipa_password = gets.chomp +config_file.write "$freeipa_password = '#{freeipa_password}'\n" +ldap_dn = "cn=ipaConfig,cn=etc," +ldap_dn_temp = realm_name.split(".") +ldap_dn_temp.each do |i| +ldap_dn += "dc=#{i}," +end +ldap_dn = ldap_dn.chop +config_file.write "$ldap_dn = '#{ldap_dn}'\n\n" + + +if cobbler_setup == "y" +config_file.write "include cobbler::remote\n" +elsif cobbler_setup == "n" +config_file.write "include cobbler::bundled\n" +end + +if dhcp_setup == "n" +config_file.write "include dhcp::bundled\n" +end + +if tftp_setup == "y" +config_file.write "include tftp::bundled\n" +end + +config_file.write "include postgres::bundled\n" +config_file.write "include freeipa::bundled\n" +config_file.write "include ovirt::setup\n" +config_file.close + +puts "\n\nTo start the installation run: ace install ovirt" diff --git a/installer/modules/ovirt/files/collectd.conf b/installer/modules/ovirt/files/collectd.conf new file mode 100644 index 0000000..0b327de --- /dev/null +++ b/installer/modules/ovirt/files/collectd.conf @@ -0,0 +1,23 @@ +LoadPlugin network +LoadPlugin logfile +LoadPlugin rrdtool +LoadPlugin unixsock + + + LogLevel info + File STDOUT + + + + Listen "0.0.0.0" + + + + DataDir "/var/lib/collectd/rrd" + CacheTimeout 120 + CacheFlush 900 + + + + SocketFile "/var/lib/collectd/unixsock" + diff --git a/installer/modules/ovirt/files/dns_entries.sh b/installer/modules/ovirt/files/dns_entries.sh new file mode 100755 index 0000000..65662d5 --- /dev/null +++ b/installer/modules/ovirt/files/dns_entries.sh @@ -0,0 +1,2 @@ +#!/bin/bash +for i in `seq $1 $2` ; do echo $3.$i node$i.$4 >> /etc/hosts; done diff --git a/installer/modules/ovirt/files/modules.conf b/installer/modules/ovirt/files/modules.conf new file mode 100644 index 0000000..236ef4c --- /dev/null +++ b/installer/modules/ovirt/files/modules.conf @@ -0,0 +1,96 @@ +# specifies what cobbler modules to load. + +# what file/data formats to use for metadata +# +# choices: +# serializer_catalog (fast, uses .d directories in /var/lib/cobbler/config) +# serializer_yaml (original serializer, uses a few text files) +# +# for 99% or more of all installations, use serializer_catalog. +# +# NOTE: serializer changes may remove your ability to access old data. +# serializer_yaml users can change to serializer_catalog w/o manual +# migration steps. Other changes are for new installs only. + +[serializers] +settings = serializer_catalog +distro = serializer_catalog +profile = serializer_catalog +system = serializer_catalog +repo = serializer_catalog +image = serializer_catalog + +# policy: what users can log into the WebUI and Read-Write XMLRPC? +# +# choices: +# authn_denyall -- no one (default) +# authn_configfile -- use /etc/cobbler/users.digest (for basic setups) +# authn_passthru -- ask Apache to handle it (used for kerberos) +# authn_ldap -- authenticate against LDAP +# authn_spacewalk -- ask Spacewalk/Satellite (experimental) +# authn_testing -- username/password is always testing/testing (debug) +# (user supplied) -- you may write your own module +# +# WARNING: this is a security setting, do not choose an option blindly. +# +# for more information: +# https://fedorahosted.org/cobbler/wiki/CobblerWebInterface +# https://fedorahosted.org/cobbler/wiki/CustomizableSecurity +# https://fedorahosted.org/cobbler/wiki/CobblerWithKerberos +# https://fedorahosted.org/cobbler/wiki/CobblerWithLdap + +[authentication] +module = authn_configfile + +# policy: once a user has been cleared by the WebUI/XMLRPC, what can they do? +# +# choices: +# authz_allowall -- full access for all authneticated users (default) +# authz_configfile -- determined by /etc/cobbler/users.conf +# authz_ownership -- use users.conf, but add object ownership semantics +# (user supplied) -- you may write your own module +# +# WARNING: this is a security setting, do not choose an option blindly. +# +# for more information: +# https://fedorahosted.org/cobbler/wiki/CobblerWebInterface +# https://fedorahosted.org/cobbler/wiki/CustomizableSecurity +# https://fedorahosted.org/cobbler/wiki/CustomizableAuthorization +# https://fedorahosted.org/cobbler/wiki/AuthorizationWithOwnership + +[authorization] +module = authz_allowall + +# chooses the DNS management engine if manage_dns is enabled +# in /etc/cobbler/settings, which is off by default. +# +# choices: +# manage_bind -- default, uses BIND/named +# manage_dnsmasq -- uses dnsmasq, also must select dnsmasq for dhcp below +# +# NOTE: more configuration is still required in /etc/cobbler +# +# for more information: +# https://fedorahosted.org/cobbler/wiki/ManageDns + +[dns] +module = manage_bind + +# chooses the DHCP management engine if manage_dhcp is enabled +# in /etc/cobbler/settings, which is off by default. +# +# choices: +# manage_isc -- default, uses ISC dhcpd +# manage_dnsmasq -- uses dnsmasq, also must select dnsmasq for dns above +# +# NOTE: more configuration is still required in /etc/cobbler +# +# for more information: +# https://fedorahosted.org/cobbler/wiki/ManageDhcp + +[dhcp] +module = manage_isc + + + + diff --git a/installer/modules/ovirt/files/qpidd.conf b/installer/modules/ovirt/files/qpidd.conf new file mode 100644 index 0000000..014b23c --- /dev/null +++ b/installer/modules/ovirt/files/qpidd.conf @@ -0,0 +1,4 @@ +# Configuration file for qpidd. Entries are of the form: +# name = value +# Using default settings: "qpidd --help" or "man qpidd" for more details. +auth=no diff --git a/installer/modules/ovirt/manifests/cobbler.pp b/installer/modules/ovirt/manifests/cobbler.pp new file mode 100644 index 0000000..e509502 --- /dev/null +++ b/installer/modules/ovirt/manifests/cobbler.pp @@ -0,0 +1,126 @@ +#-- +# Copyright (C) 2008 Red Hat Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Author: Joey Boggs +#-- + +import "appliance_base" +#import "firewall" + + +define apache_htdigest($digest_file, $digest_username, $digest_password, $digest_realm="") +{ + file_append{"add_htdigest_for_$digest_username_in_$digest_realm": + file => $digest_file, + line => template("ovirt/digest_line.erb") + } + +} + + +define cobbler_user_config($cobbler_user_name="",$cobbler_user_password="",$cobbler_hostname="") { + + file_replacement{"cobbler_user_name_config": + file => "/usr/share/ovirt-server/config/cobbler.yml", + pattern => "^username.*$", + replacement => "username: $cobbler_user_name", + require => Package[ovirt-server] + } + + file_replacement{"cobbler_user_password_config": + file => "/usr/share/ovirt-server/config/cobbler.yml", + pattern => "^password.*$", + replacement => "password: $cobbler_user_password", + require => File_replacement[cobbler_user_name_config] + } + file_replacement{"cobbler_hostname_config": + file => "/usr/share/ovirt-server/config/cobbler.yml", + pattern => "^hostname.*$", + replacement => "hostname: $cobbler_hostname", + require => File_replacement[cobbler_user_name_config] + } + +} + +class cobbler::bundled { + package {"cobbler": + ensure => installed + } + + apache_htdigest{"cobbler_add_user": + digest_file => "/etc/cobbler/users.digest", + digest_username => "$cobbler_user_name", + digest_password => "$cobbler_user_password", + digest_realm => "Cobbler", + require => Package[cobbler] + } + + cobbler_user_config {"cobbler_bundled_user": + cobbler_user_name=> "$cobbler_user_name", + cobbler_user_password => "$cobbler_user_password", + cobbler_hostname => "localhost", + require => Package[cobbler] + } + + file_replacement{"settings_ip_address": + file => "/etc/cobbler/settings", + pattern => "127.0.0.1", + replacement => $ipaddress, + notify => Service[cobblerd], + require => Package[cobbler] + } + + file_replacement{"settings_xml_rpc": + file => "/etc/cobbler/settings", + pattern => "xmlrpc_rw_enabled: 0", + replacement => "xmlrpc_rw_enabled: 1", + require => File_replacement[settings_ip_address], + notify=> Service[cobblerd] + } + + service {"cobblerd" : + ensure => running, + enable => true, + require => File_replacement[settings_ip_address] + } + + file {"/etc/cobbler/modules.conf": + source => "puppet:///ovirt/modules.conf", + notify => Service[cobblerd], + require => Package["cobbler"] + } + +# firewall_rule{"69": destination_port => "69"} +# firewall_rule{"25150": destination_port => "25150"} +# firewall_rule{"25151": destination_port => "25151"} + +} + +class cobbler::remote { + +# On the remote cobbler server run the following command: +# htdigest /etc/cobbler/users.digest "Cobbler" $user_name +# Ensure the password is set to $cobbler_user_password + + + cobbler_user_config {"cobbler_remote_user": + cobbler_user_name => "$cobbler_user_name", + cobbler_user_password => "$cobbler_user_password", + cobbler_hostname => "$cobbler_hostname" + } +} + diff --git a/installer/modules/ovirt/manifests/dhcp.pp b/installer/modules/ovirt/manifests/dhcp.pp new file mode 100644 index 0000000..c5c8f9a --- /dev/null +++ b/installer/modules/ovirt/manifests/dhcp.pp @@ -0,0 +1,34 @@ +#-- +# Copyright (C) 2008 Red Hat Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Author: Joey Boggs +#-- + +class dhcp::bundled { + + file {"/etc/dnsmasq.d/ovirt-dhcp.conf": + content => template("ovirt/ovirt-dhcp.conf.erb"), + mode => 644, + notify => Service[dnsmasq], + require => Package[dnsmasq] + } + + single_exec {"dns_entries": + command => "/usr/share/ace/modules/ovirt/files/dns_entries.sh $dhcp_start $dhcp_stop $dhcp_network $dhcp_domain", + } + +} diff --git a/installer/modules/ovirt/manifests/dns.pp b/installer/modules/ovirt/manifests/dns.pp new file mode 100644 index 0000000..c16abfd --- /dev/null +++ b/installer/modules/ovirt/manifests/dns.pp @@ -0,0 +1,99 @@ +#-- +# Copyright (C) 2008 Red Hat Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Author: Joey Boggs +#-- + +# common featues +define dns::common($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") { + + package {"dnsmasq": + ensure => installed, + require => [Single_exec["add_dns_server_to_resolv.conf"]] + } + + service {"dnsmasq" : + ensure => running, + enable => true, + require => [File["/etc/dnsmasq.d/ovirt-dns.conf"], Package["dnsmasq"]] + } + + file {"/etc/dnsmasq.d/ovirt-dns.conf": + content => template("ovirt/ovirt-dns.conf.erb"), + mode => 644, + notify => Service[dnsmasq], + require => Package["dnsmasq"] + } + + single_exec {"add_dns_server_to_resolv.conf": + command => "/bin/sed -e '1i nameserver $prov_ipaddr' -i /etc/resolv.conf", + require => [Single_exec["set_hostname"]] + } + + + file_replacement {"dnsmasq_configdir": + file => "/etc/dnsmasq.conf", + pattern => "^#conf-dir=*$", + replacement => "conf-dir=/etc/dnsmasq.d", + notify => Service[dnsmasq], + require => Package["dnsmasq"] + } + + file {"/etc/dhclient.conf": + ensure => present + } + + file_append {"dhclient_config": + file => "/etc/dhclient.conf", + line => "prepend domain-name-servers $prov_ipaddr", + require => [Single_exec["set_hostname"], Package["dnsmasq"], File["/etc/dhclient.conf"]] , + notify => Service[dnsmasq], + } + +} + +define dns::bundled($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") { + + dns::common{"setup": mgmt_ipaddr=>$mgmt_ipaddr, prov_ipaddr=>$prov_ipaddr, mgmt_dev=>$mgmt_dev, prov_dev=>$prov_dev} + + single_exec {"add_mgmt_server_to_etc_hosts": + command => "/bin/echo $mgmt_ipaddr $ipa_host >> /etc/hosts", + notify => [Service[dnsmasq], Single_exec["add_dns_server_to_resolv.conf"]] + } +} + +define dns::remote($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") { + +# On the pxe server you will need to ensure that the +# next server option points to the ip address of the tftp server + +# The following SRV records must be present in the dns server for everything +# to function properly. Replace example.com with the appropriate domain + +# _ovirt._tcp.example.com. SRV 0 5 80 ovirtwuiserver.example.com. +# _ipa._tcp.example.com. SRV 0 5 80 ipaserver.example.com. +# _ldap._tcp.example.com. SRV 0 5 389 ldapserver.example.com. +# _collectd._tcp.example.com. SRV 0 5 25826 ovirtwuiserver.example.com. +# _qpidd._tcp.example.com. SRV 0 5 5672 ovirtwuiserver.example.com. +# _identify._tcp.example.com. SRV 0 5 12120 ovirtwuiserver.example.com. + +# Also A records must be present for each oVirt node. Without this they are unable +# to determine their hostname and locate the management server. + + dns::common{"setup": mgmt_ipaddr=>$mgmt_ipaddr, prov_ipaddr=>$prov_ipaddr, mgmt_dev=>$mgmt_dev, prov_dev=>$prov_dev} + +} diff --git a/installer/modules/ovirt/manifests/freeipa.pp b/installer/modules/ovirt/manifests/freeipa.pp new file mode 100644 index 0000000..1f292bf --- /dev/null +++ b/installer/modules/ovirt/manifests/freeipa.pp @@ -0,0 +1,103 @@ +#-- +# Copyright (C) 2008 Red Hat Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Author: Joey Boggs +#-- + +class freeipa::bundled{ + + package {"ipa-server": + ensure => installed, + require => [Exec[db_exists_file],Single_exec["set_hostname"]] + } + + single_exec {"set_hostname": + command => "/bin/hostname $ipa_host", + } + + exec {"set_kdc_defaults": + command => "/bin/sed -i '/\[kdcdefaults\]/a \ kdc_ports = 88' /usr/share/ipa/kdc.conf.template", + require => Package[ipa-server] + } + + exec {"replace_line_returns": + command => "/bin/sed -i -e 's/^/#/' /etc/httpd/conf.d/ipa-rewrite.conf", + require => Single_Exec[ipa_server_install] + } + + file_replacement{"ipa_proxy_config_1": + file => "/etc/httpd/conf.d/ipa.conf", + pattern => "^", + replacement => "", + require => Exec[replace_line_returns] + } + + file_replacement{"ipa_proxy_config_2": + file => "/etc/httpd/conf.d/ipa.conf", + pattern => "^", + replacement => "", + require => File_replacement[ipa_proxy_config_1], + notify => Service[httpd] + } + + single_exec {"dnsmasq_restart": + command => "/etc/init.d/dnsmasq restart", + require => Service["dnsmasq"] + } + + single_exec {"ipa_server_install": + command => "/usr/sbin/ipa-server-install -r $realm_name -p $freeipa_password -P $freeipa_password -a $freeipa_password --hostname $ipa_host -u dirsrv -U", + require => [Exec[set_kdc_defaults],Single_exec[dnsmasq_restart]] + } + + exec {"get_krb5_tkt": + command => "/bin/echo $freeipa_password|/usr/kerberos/bin/kinit admin", + require => Single_Exec[ipa_server_install] + } + + single_exec {"ipa_modify_username_length": + command => "/usr/sbin/ipa-defaultoptions --maxusername=12", + require => Exec["get_krb5_tkt"] + } + + single_exec {"ipa_add_ovirtadmin_user": + command => "/usr/sbin/ipa-adduser -f Ovirt -l Admin -p $freeipa_password ovirtadmin", + require => Single_exec[ipa_modify_username_length] + } + + single_exec {"ipa_ovirtadmin_group": + command => "/usr/sbin/ipa-modgroup -a ovirtadmin admins", + require => Single_exec[ipa_add_ovirtadmin_user] + } + + single_exec {"set_pw_expiration": + command => "/usr/sbin/ipa-moduser --setattr krbPasswordExpiration=19700101000000Z ovirtadmin", + require => Single_exec[ipa_ovirtadmin_group] + } + +# firewall_rule{"krb5": destination_port => "88"} +# firewall_rule {"ldap": destination_port => '389'} + +} + +class freeipa::remote { + +# oVirt is not configured at this time to support a remote freeipa server + +} + + diff --git a/installer/modules/ovirt/manifests/init.pp b/installer/modules/ovirt/manifests/init.pp new file mode 100644 index 0000000..87f6832 --- /dev/null +++ b/installer/modules/ovirt/manifests/init.pp @@ -0,0 +1,9 @@ +import "ovirt/cobbler.pp" +import "ovirt/dns.pp" +import "ovirt/dhcp.pp" +import "ovirt/tftp.pp" +import "ovirt/freeipa.pp" +import "ovirt/ovirt.pp" +import "ovirt/postgres.pp" +import "appliance_base/single_exec.pp" + diff --git a/installer/modules/ovirt/manifests/ovirt.pp b/installer/modules/ovirt/manifests/ovirt.pp new file mode 100644 index 0000000..809db8e --- /dev/null +++ b/installer/modules/ovirt/manifests/ovirt.pp @@ -0,0 +1,154 @@ +#-- +# Copyright (C) 2008 Red Hat Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Author: Joey Boggs +#-- + +class ovirt::setup { + + package {"ovirt-server": + ensure => installed, + require => Single_exec[set_pw_expiration] + } + + package {"httpd": + ensure => installed; + } + + package {"rubygem-rake": + ensure => installed; + } + + package {"qpidd": + ensure => installed; + } + + package {"collectd": + ensure => installed; + } + + package {"collectd-rrdtool": + ensure => installed; + } + + package {"libvirt": + ensure => installed; + } + + package {"ruby-qpid": + ensure => installed; + } + + package {"ntp": + ensure => installed; + } + + file {"/etc/collectd.conf": + source => "puppet:///ovirt/collectd.conf", + notify => Service[collectd], + require => Package["collectd-rrdtool"] + } + + file {"/etc/qpidd.conf": + source => "puppet:///ovirt/qpidd.conf", + notify => Service[qpidd] + } + + single_exec { "db_migrate" : + cwd => "/usr/share/ovirt-server/", + command => "/usr/bin/rake db:migrate", + require => [File["/usr/share/ovirt-server/log"],Package[ovirt-server],Package[rubygem-rake],Postgres_execute_command["ovirt_db_grant_permissions"]], + environment => "RAILS_ENV=production" + } + + file { "/usr/share/ovirt-server/log" : + ensure => directory, + require => Package[ovirt-server] + } + + single_exec { "create_ovirtadmin_acct" : + command => "/usr/share/ovirt-server/script/grant_admin_privileges ovirtadmin", + require => Single_Exec[db_migrate] + } + + single_exec { "add_host" : + command => "/usr/bin/ovirt-add-host $ipa_host /usr/share/ovirt-server/ovirt.keytab", + require => Package[ovirt-server] + } + + exec { "disable_selinux" : + command => "/usr/sbin/lokkit --selinux=disabled", + require => Package["ovirt-server"] + } + + service {"httpd" : + enable => true, + require => Package[httpd], + ensure => running + } + + service {"libvirt" : + enable => false, + require => Package[libvirt], + } + + service {"ovirt-host-browser" : + enable => true, + require => [Package[ovirt-server],Single_Exec[db_migrate]], + ensure => running + } + + service {"ovirt-host-collect" : + enable => true, + require => [Package[ovirt-server],Single_Exec[db_migrate]], + ensure => running + } + + service {"ovirt-mongrel-rails" : + enable => true, + require => [Package[ovirt-server],Single_Exec[db_migrate]], + ensure => running, + notify => Service[httpd] + } + + service {"ovirt-taskomatic" : + enable => true, + require => [Package[ovirt-server],Single_Exec[db_migrate]], + ensure => running + } + + service {"qpidd" : + enable => true, + ensure => running, + require => Package[qpidd] + } + + service {"collectd" : + enable => true, + ensure => running, + require => Package[collectd] + } + + service {"ntpd" : + enable => true, + ensure => running, + require => Package[ntp] + } + +# firewall_rule{"http": destination_port => "80"} + +} diff --git a/installer/modules/ovirt/manifests/postgres.pp b/installer/modules/ovirt/manifests/postgres.pp new file mode 100644 index 0000000..0bd71fa --- /dev/null +++ b/installer/modules/ovirt/manifests/postgres.pp @@ -0,0 +1,114 @@ +#-- +# Copyright (C) 2008 Red Hat Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Author: Joey Boggs +#-- + +import "postgres" +import "appliance_base/single_exec.pp" + +class postgres::bundled{ + + + package {"postgresql-server": + ensure => installed, + } + package {"ace-postgres": + ensure => installed, + require => Package[postgresql-server] + } + + single_exec {"initialize_db": + command => "/sbin/service postgresql initdb", + creates => "/var/lib/pgsql/data/pg_hba.conf", + require => Package[postgresql-server] + } + + service {"postgresql" : + ensure => running, + enable => true, + require => Single_exec[initialize_db] + } + + single_exec {"create_ovirt_db": + command => "/usr/bin/createdb ovirt", + require => [Exec[postgres_add_all_trust], Service[postgresql]], + user => "postgres" + } + + single_exec {"create_ovirt_development_db": + command => "/usr/bin/createdb ovirt_development", + require => [Exec[postgres_add_all_trust], Service[postgresql]], + user => "postgres" + } + + postgres_execute_command {"ovirt_db_create_role": + cmd => "CREATE ROLE ovirt LOGIN PASSWORD '$db_password' NOINHERIT VALID UNTIL 'infinity'", + database => "ovirt", + require => Single_Exec[create_ovirt_db] + } + + postgres_execute_command {"ovirt_db_grant_permissions": + cmd => "GRANT ALL ON DATABASE ovirt TO ovirt;", + database => "ovirt", + require => Postgres_execute_command[ovirt_db_create_role] + } + + exec {"postgres_add_all_trust": + command => "/bin/echo 'local all all trust' > /var/lib/pgsql/data/pg_hba.conf", + require => Single_exec[initialize_db], + notify => Service[postgresql] + } + + exec {"postgres_add_localhost_trust": + command => "/bin/echo 'host all all 127.0.0.1 255.255.255.0 trust' >> /var/lib/pgsql/data/pg_hba.conf", + require => Exec[postgres_add_all_trust], + notify => Service[postgresql] + } + + file { "/etc/ovirt-server/" : + ensure => directory, + require => Exec[postgres_add_localhost_trust] + } + + file { "/etc/ovirt-server/db/" : + ensure => directory, + require => File["/etc/ovirt-server"] + } + + exec {"touch_dbaccess_file": + command => "/bin/touch /etc/ovirt-server/db/dbaccess", + require => File["/etc/ovirt-server/db"] + } + + file_append {"db_password_file": + file => "/etc/ovirt-server/db/dbaccess", + line => "$db_password", + require => Exec[touch_dbaccess_file] + } + exec {"db_exists_file": + command => "/bin/touch /etc/ovirt-server/db/exists", + require => File_append[db_password_file] + } +} + +class postgres::remote{ + +# oVirt is not configured at this time to support a remote postgres connection + +} + diff --git a/installer/modules/ovirt/manifests/tftp.pp b/installer/modules/ovirt/manifests/tftp.pp new file mode 100644 index 0000000..4f41d00 --- /dev/null +++ b/installer/modules/ovirt/manifests/tftp.pp @@ -0,0 +1,31 @@ +#-- +# Copyright (C) 2008 Red Hat Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Author: Joey Boggs +#-- + +class tftp::bundled { + + file {"/etc/dnsmasq.d/ovirt-tftp.conf": + content => template("ovirt/ovirt-tftp.conf.erb"), + mode => 644, + notify => Service[dnsmasq], + require => Package[dnsmasq] + } +} + + diff --git a/installer/modules/ovirt/templates/digest_line.erb b/installer/modules/ovirt/templates/digest_line.erb new file mode 100644 index 0000000..4e98708 --- /dev/null +++ b/installer/modules/ovirt/templates/digest_line.erb @@ -0,0 +1,4 @@ +<% require 'digest/sha1' -%> +<% token = "#{digest_username}:#{digest_realm}:#{digest_password}" -%> +<% digested_password = Digest::MD5.hexdigest(token) -%> +<%= digest_username -%>:<%= digest_realm -%>:<%= digested_password -%> diff --git a/installer/modules/ovirt/templates/ovirt-dhcp.conf.erb b/installer/modules/ovirt/templates/ovirt-dhcp.conf.erb new file mode 100644 index 0000000..e10db40 --- /dev/null +++ b/installer/modules/ovirt/templates/ovirt-dhcp.conf.erb @@ -0,0 +1,9 @@ +interface=<%= dhcp_interface %> +dhcp-range=<%= dhcp_network %>.<%= dhcp_start %>,<%= dhcp_network%>.<%= dhcp_stop %> +domain=<%= dhcp_domain %> +dhcp-option=option:router,<%= prov_network_gateway %> +dhcp-option=option:ntp-server,<%= ntp_server %> +dhcp-option=12 +no-resolv +local=/<%= dhcp_domain %>/ +server=<%= prov_dns_server %> diff --git a/installer/modules/ovirt/templates/ovirt-dns.conf.erb b/installer/modules/ovirt/templates/ovirt-dns.conf.erb new file mode 100644 index 0000000..ae3eb48 --- /dev/null +++ b/installer/modules/ovirt/templates/ovirt-dns.conf.erb @@ -0,0 +1,7 @@ +srv-host=_ovirt._tcp,<%= ovirt_host %>,80 +srv-host=_ipa._tcp,<%= ipa_host %>,80 +srv-host=_ldap._tcp,<%= ipa_host %>,389 +srv-host=_collectd._tcp,<%= ovirt_host %>,25826 +srv-host=_qpidd._tcp,<%= ovirt_host %>,5672 +srv-host=_identify._tcp,<%= ovirt_host %>,12120 + diff --git a/installer/modules/ovirt/templates/ovirt-tftp.conf.erb b/installer/modules/ovirt/templates/ovirt-tftp.conf.erb new file mode 100644 index 0000000..3fa40f8 --- /dev/null +++ b/installer/modules/ovirt/templates/ovirt-tftp.conf.erb @@ -0,0 +1,3 @@ +enable-tftp +tftp-root=/var/lib/tftpboot +dhcp-boot=pxelinux.0 diff --git a/ovirt-server.spec.in b/ovirt-server.spec.in index 79a5adf..647794d 100644 --- a/ovirt-server.spec.in +++ b/ovirt-server.spec.in @@ -1,5 +1,6 @@ %define pbuild %{_builddir}/%{name}-%{version} %define app_root %{_datadir}/%{name} +%define acehome %{_datadir}/ace Summary: oVirt Server Suite Name: ovirt-server @@ -45,10 +46,19 @@ BuildArch: noarch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot URL: http://ovirt.org/ -%description +%package installer +Summary: Installer modules for the oVirt Server Suite +Requires: ruby(abi) = 1.8 +Requires: ace +Requires: ace-postgres +Requires: hal +%description The Server Suite for oVirt. +%description installer +The Installer for the ovirt server suite + %prep %setup -q @@ -59,6 +69,7 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT mkdir %{buildroot} %{__install} -d -m0755 %{buildroot}%{_bindir} +%{__install} -d -m0755 %{buildroot}%{_datadir} %{__install} -d -m0755 %{buildroot}%{_sbindir} %{__install} -d -m0755 %{buildroot}%{_initrddir} %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/sysconfig @@ -69,6 +80,7 @@ mkdir %{buildroot} %{__install} -d -m0755 %{buildroot}%{_localstatedir}/log/%{name} %{__install} -d -m0755 %{buildroot}%{_localstatedir}/run/%{name} %{__install} -d -m0755 %{buildroot}%{app_root} +%{__install} -d -m0755 %{buildroot}/%{acehome} touch %{buildroot}%{_localstatedir}/log/%{name}/mongrel.log touch %{buildroot}%{_localstatedir}/log/%{name}/rails.log @@ -114,6 +126,11 @@ touch %{buildroot}%{_localstatedir}/log/%{name}/db-omatic.log %{__mkdir} %{buildroot}%{_localstatedir}/lib/%{name}/tmp %{__ln_s} %{_localstatedir}/lib/%{name}/tmp %{buildroot}%{app_root}/tmp +# Set up the installer +%{__cp} -pr %{pbuild}/installer/modules %{buildroot}/%{acehome} +%{__cp} -pr %{pbuild}/installer/bin/ovirt-installer %{buildroot}%{_sbindir} + + %clean rm -rf $RPM_BUILD_ROOT @@ -193,6 +210,10 @@ fi %config(noreplace) %{_sysconfdir}/%{name}/production.rb %config(noreplace) %{_sysconfdir}/%{name}/test.rb +%files installer +%{_sbindir}/ovirt-installer +%{acehome} + %changelog * Thu May 29 2008 Alan Pevec - 0.0.5-0 - use rubygem-krb5-auth -- 1.6.0.4 From dpierce at redhat.com Mon Jan 5 20:21:06 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 5 Jan 2009 15:21:06 -0500 Subject: [Ovirt-devel] [PATCH node] make ovirt-config-setup menu configurable In-Reply-To: <20090105181450.GB26941@mcpierce-laptop.rdu.redhat.com> References: <1230159599-4277-1-git-send-email-apevec@redhat.com> <20090105181450.GB26941@mcpierce-laptop.rdu.redhat.com> Message-ID: <20090105202106.GA7335@mcpierce-laptop.rdu.redhat.com> On Mon, Jan 05, 2009 at 01:14:50PM -0500, Darryl L. Pierce wrote: > On Wed, Dec 24, 2008 at 11:59:58PM +0100, Alan Pevec wrote: > > custom menu option can be added using a symlink in > > /etc/ovirt-config-setup.d/ pointing to the script to be executed > > > > implement default options using this method > > ACK. The patch works well. Pushed into the repo. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From dpierce at redhat.com Mon Jan 5 20:21:30 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 5 Jan 2009 15:21:30 -0500 Subject: [Ovirt-devel] [PATCH node] add "Local install and reboot" option In-Reply-To: <20090105192720.GA24139@mcpierce-laptop.rdu.redhat.com> References: <1230159599-4277-1-git-send-email-apevec@redhat.com> <1230159599-4277-2-git-send-email-apevec@redhat.com> <20090105192720.GA24139@mcpierce-laptop.rdu.redhat.com> Message-ID: <20090105202130.GB7335@mcpierce-laptop.rdu.redhat.com> On Mon, Jan 05, 2009 at 02:27:20PM -0500, Darryl L. Pierce wrote: > Missed this earlier. There's a typo here, should be "disable_firstboot" > shouldn't it? I've fixed the typo and pushed this as well. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From dpierce at redhat.com Mon Jan 5 20:31:37 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 5 Jan 2009 15:31:37 -0500 Subject: [Ovirt-devel] [PATCH node] Adds a check for a partition table before installing. Message-ID: <1231187497-8383-1-git-send-email-dpierce@redhat.com> If no partition table is found then an error message is show to the user and the system will not continue nor reboot. Signed-off-by: Darryl L. Pierce --- scripts/ovirt-config-boot | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) diff --git a/scripts/ovirt-config-boot b/scripts/ovirt-config-boot index 8ddd46a..d971c5c 100755 --- a/scripts/ovirt-config-boot +++ b/scripts/ovirt-config-boot @@ -142,7 +142,15 @@ if [ -z "$bootparams" ]; then bootparams="$OVIRT_BOOTPARAMS" fi -ovirt_boot_setup "$disk" "$live" "$bootparams" +# ensure the disk is not blank +parted $disk -s "print all" > /dev/null + +if [ 0 -eq $? ]; then + ovirt_boot_setup "$disk" "$live" "$bootparams" +else + printf "Please configure $disk before attempting to install the node image.\n" + doreboot="no" +fi if [ -z "$doreboot" -o "$doreboot" = "yes" ]; then disable_firstbot -- 1.6.0.6 From bkearney at redhat.com Mon Jan 5 21:04:04 2009 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 5 Jan 2009 16:04:04 -0500 Subject: [Ovirt-devel] [PATCH server] Add a default ovirt installation recipe to be used by the appliance installer Message-ID: <1231189444-20727-1-git-send-email-bkearney@redhat.com> --- .../appliances/ovirt-appliance/ovirt-appliance.pp | 44 ++++++++++++++++++++ ovirt-server.spec.in | 1 + 2 files changed, 45 insertions(+), 0 deletions(-) create mode 100644 installer/appliances/ovirt-appliance/ovirt-appliance.pp diff --git a/installer/appliances/ovirt-appliance/ovirt-appliance.pp b/installer/appliances/ovirt-appliance/ovirt-appliance.pp new file mode 100644 index 0000000..630fa7f --- /dev/null +++ b/installer/appliances/ovirt-appliance/ovirt-appliance.pp @@ -0,0 +1,44 @@ +# Sample file as if the user had run the ovirt-installer program +import 'ovirt' +import 'firewall' + +firewall::setup{'setup': status => 'disabled'} + +# dns configuration +$mgmt_ipaddr = '192.168.222.211' +$prov_ipaddr = '' +$ovirt_host = 'management.priv.ovirt.org' +$ipa_host = 'management.priv.ovirt.org' + +dns::bundled{setup: mgmt_ipaddr=> $mgmt_ipaddr, prov_ipaddr=> $prov_ipaddr, mgmt_dev => 'eth0', prov_dev => 'eth1'} + +# dhcp configuration +$dhcp_interface = 'eth1' +$dhcp_network = '192.168.50' +$dhcp_start = '3' +$dhcp_stop = '10' +$dhcp_domain = 'priv.ovirt.org' +$ntp_server = '192.168.222.211' + +$prov_dns_server = '' +$prov_network_gateway = '192.168.50.1' +# cobbler configuration +$cobbler_hostname = 'localhost' +$cobbler_user_name = 'cobbler' +$cobbler_user_password = 'cobbler' + +# postgres configuration +$db_username = 'ovirt' +$db_password = 'cobbler' + +# FreeIPA configuration +$realm_name = 'priv.ovirt.org' +$freeipa_password = 'password' +$ldap_dn = 'cn=ipaConfig,cn=etc,dc=priv,dc=ovirt,dc=org' + +include cobbler::bundled +include dhcp::bundled +include tftp::bundled +include postgres::bundled +include freeipa::bundled +include ovirt::setup diff --git a/ovirt-server.spec.in b/ovirt-server.spec.in index 647794d..cbc4c1a 100644 --- a/ovirt-server.spec.in +++ b/ovirt-server.spec.in @@ -128,6 +128,7 @@ touch %{buildroot}%{_localstatedir}/log/%{name}/db-omatic.log # Set up the installer %{__cp} -pr %{pbuild}/installer/modules %{buildroot}/%{acehome} +\%{__cp} -pr %{pbuild}/installer/appliances %{buildroot}/%{acehome} %{__cp} -pr %{pbuild}/installer/bin/ovirt-installer %{buildroot}%{_sbindir} -- 1.6.0.4 From bkearney at redhat.com Mon Jan 5 21:05:08 2009 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 5 Jan 2009 16:05:08 -0500 Subject: [Ovirt-devel] [PATCH appliance] Modify the appliance building to use the installer rpm Message-ID: <1231189508-20804-1-git-send-email-bkearney@redhat.com> --- ovirt-appliance.ks | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ovirt-appliance.ks b/ovirt-appliance.ks index 81cb010..813a618 100644 --- a/ovirt-appliance.ks +++ b/ovirt-appliance.ks @@ -28,7 +28,7 @@ reboot %packages --excludedocs --nobase %include /usr/share/appliance-os/includes/base-pkgs.ks -ovirt-recipe +ovirt-server-installer lokkit %post @@ -40,7 +40,7 @@ lokkit # The ace stuff. mkdir /etc/sysconfig/ace - echo ovirt >> /etc/sysconfig/ace/appliancename + echo ovirt-appliance >> /etc/sysconfig/ace/appliancename %end %post -- 1.6.0.4 From bkearney at redhat.com Mon Jan 5 21:06:26 2009 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 05 Jan 2009 16:06:26 -0500 Subject: [Ovirt-devel] Re: [PATCH appliance] Modify the appliance building to use the installer rpm In-Reply-To: <1231189508-20804-1-git-send-email-bkearney@redhat.com> References: <1231189508-20804-1-git-send-email-bkearney@redhat.com> Message-ID: <49627652.6010202@redhat.com> This was the last of three pacthes which brought in Joey's installer code. The goal, once acked, is to deprecate the recipe repo so that the bare-metal installer is used by the appliance as well. -- bk Bryan Kearney wrote: > --- > ovirt-appliance.ks | 4 ++-- > 1 files changed, 2 insertions(+), 2 deletions(-) > > diff --git a/ovirt-appliance.ks b/ovirt-appliance.ks > index 81cb010..813a618 100644 > --- a/ovirt-appliance.ks > +++ b/ovirt-appliance.ks > @@ -28,7 +28,7 @@ reboot > > %packages --excludedocs --nobase > %include /usr/share/appliance-os/includes/base-pkgs.ks > -ovirt-recipe > +ovirt-server-installer > lokkit > > %post > @@ -40,7 +40,7 @@ lokkit > > # The ace stuff. > mkdir /etc/sysconfig/ace > - echo ovirt >> /etc/sysconfig/ace/appliancename > + echo ovirt-appliance >> /etc/sysconfig/ace/appliancename > %end > > %post From apevec at gmail.com Mon Jan 5 22:45:20 2009 From: apevec at gmail.com (Alan Pevec) Date: Mon, 5 Jan 2009 23:45:20 +0100 Subject: [Ovirt-devel] [PATCH node] Adds a check for a partition table before installing. In-Reply-To: <1231187497-8383-1-git-send-email-dpierce@redhat.com> References: <1231187497-8383-1-git-send-email-dpierce@redhat.com> Message-ID: <2be7262f0901051445o28a1ae2by82e56969ea19d0b2@mail.gmail.com> On Mon, Jan 5, 2009 at 9:31 PM, Darryl L. Pierce wrote: > If no partition table is found then an error message is show to the user > and the system will not continue nor reboot. > ACK + printf "Please configure $disk before attempting to install the node > image.\n" > to help the confused user, print the option name "Disk Partitioning" or even just run ovirt-config-storage here? -------------- next part -------------- An HTML attachment was scrubbed... URL: From clalance at redhat.com Tue Jan 6 09:39:05 2009 From: clalance at redhat.com (Chris Lalancette) Date: Tue, 06 Jan 2009 10:39:05 +0100 Subject: [Ovirt-devel] [PATCH server] Taskomatic Refactoring and Qpidification Take 3 In-Reply-To: <1229725173-18065-1-git-send-email-imain@redhat.com> References: <1229725173-18065-1-git-send-email-imain@redhat.com> Message-ID: <496326B9.9010305@redhat.com> Ian Main wrote: > This update adds a few small bugfixes, removes LVM storage pool/volume > scanning and reindents to 2 spaces. > > This patch reworks taskomatic quite a bit. This mostly just shifts > taskomatic to using the qpid interface in place of ruby-libvirt. It > also fixes a few bugs I discovered a long the way and adds new ones > I'm sure. The only other thing added was round-robin host selection > for VMs. > > Wherevery possible the hosts are queried directly using qpid rather than > relying on states from the database. > > This patch loses about 150 lines from the original taskomatic and moves > most of the task implementation into a central class. This was done to > provide access to the qpid session as well as providing for locking/task > ordering in future versions. > > This requires the latest libvirt-qpid (0.2.8) as it fixes a number of > bugs. It's in the ovirt repository now. > > Issues remaining: > > - libvirt-qpid migrate is broken. Since the migrate takes place on the > node instead of from the ovirt-appliance, the source node doesn't have > the ability to authenticate against the destination node. For this > reason I'm still using ruby-libvirt migrate. I talked to Chris about > this and we have a plan worked out. :) > > - I wanted to get threading into this but that will have to wait. I'll > post a thread about this to get the discussion started again. I think > the refactoring allows this to be put in pretty easily. > > Signed-off-by: Ian Main > --- > src/task-omatic/task_host.rb | 33 -- > src/task-omatic/task_storage.rb | 424 +++++++++----------- > src/task-omatic/task_vm.rb | 574 +-------------------------- > src/task-omatic/taskomatic.rb | 841 ++++++++++++++++++++++++++++++++++----- > src/task-omatic/utils.rb | 221 ---------- > 5 files changed, 933 insertions(+), 1160 deletions(-) > delete mode 100644 src/task-omatic/task_host.rb > delete mode 100644 src/task-omatic/utils.rb > > diff --git a/src/task-omatic/task_host.rb b/src/task-omatic/task_host.rb > deleted file mode 100644 > index 3d039fb..0000000 > --- a/src/task-omatic/task_host.rb > +++ /dev/null > @@ -1,33 +0,0 @@ > -# Copyright (C) 2008 Red Hat, Inc. > -# Written by Chris Lalancette > -# > -# 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. > - > -require 'utils' > - > -# FIXME: a little ugly to be including all of task_vm here, but > -# utils really isn't the right place for the migrate() method > -require 'task_vm' > - > -def clear_vms_host(task) > - puts "clear_vms_host" > - > - src_host = task.host > - > - src_host.vms.each do |vm| > - migrate(vm) > - end > -end > diff --git a/src/task-omatic/task_storage.rb b/src/task-omatic/task_storage.rb > index 19800fb..a5eb55d 100644 > --- a/src/task-omatic/task_storage.rb > +++ b/src/task-omatic/task_storage.rb > @@ -16,287 +16,231 @@ > # MA 02110-1301, USA. A copy of the GNU General Public License is > # also available at http://www.gnu.org/copyleft/gpl.html. > > -require 'utils' > - > require 'libvirt' > +require 'rexml/document' > +include REXML > + > +def String.random_alphanumeric(size=16) > + s = "" > + size.times { s << (i = Kernel.rand(62); i += ((i < 10) ? 48 : ((i < 36) ? 55 : 61 ))).chr } > + s > +end > + > +def get_libvirt_lvm_pool_from_volume(db_volume) > + phys_volume = StorageVolume.find(:first, :conditions => > + ["lvm_pool_id = ?", db_volume.storage_pool_id]) > + > + return LibvirtPool.factory(phys_volume.storage_pool) > +end > + > +class LibvirtPool > + > + attr_reader :remote_pool I've tried to avoid this before by trying to make accessor methods for the class; I think it is a little cleaner to not let external entities look into the class. What are you using this for now? > > -def add_volumes_to_db(db_pool, libvirt_pool, owner = nil, group = nil, mode = nil) > - # FIXME: this is currently broken if you do something like: > - # 1. Add an iscsi pool with 3 volumes (lun-1, lun-2, lun-3) > - # 2. Scan it in > - # 3. Remove lun-3 from the pool > - # 4. Re-scan it > - # What will happen is that you will still have lun-3 available in the > - # database, even though it's not available in the pool anymore. It's a > - # little tricky, though; we have to make sure that we don't pull the > - # database entry out from underneath a possibly running VM (or do we?) > - libvirt_pool.list_volumes.each do |volname| > - storage_volume = StorageVolume.factory(db_pool.get_type_label) > - > - # NOTE: it is safe (and, in fact, necessary) to use > - # #{storage_volume.volume_name} here without sanitizing it. This is > - # because this is *not* based on user modifiable data, but rather, on an > - # internal implementation detail > - existing_vol = StorageVolume.find(:first, :conditions => > - [ "storage_pool_id = ? AND #{storage_volume.volume_name} = ?", > - db_pool.id, volname]) > - if existing_vol != nil > - # in this case, this path already exists in the database; just skip > - next > + def initialize(type, name = nil) > + @remote_pool = nil > + @build_on_start = true > + @remote_pool_defined = false > + @remote_pool_started = false > + > + if name == nil > + @name = type + "-" + String.random_alphanumeric > + else > + @name = name > end > > - volptr = libvirt_pool.lookup_vol_by_name(volname) > + @xml = Document.new > + @xml.add_element("pool", {"type" => type}) > + > + @xml.root.add_element("name").add_text(@name) > > - volinfo = volptr.info > + @xml.root.add_element("source") > > - storage_volume = StorageVolume.factory(db_pool.get_type_label) > - storage_volume.path = volptr.path > - storage_volume.size = volinfo.capacity / 1024 > - storage_volume.storage_pool_id = db_pool.id > - storage_volume.write_attribute(storage_volume.volume_name, volname) > - storage_volume.lv_owner_perms = owner > - storage_volume.lv_group_perms = group > - storage_volume.lv_mode_perms = mode > - storage_volume.state = StorageVolume::STATE_AVAILABLE > - storage_volume.save! > + @xml.root.add_element("target") > + @xml.root.elements["target"].add_element("path") > end > -end > > -def storage_find_suitable_host(hardware_pool) > - conn = nil > - hardware_pool.hosts.each do |host| > - if not host.is_disabled.nil? and host.is_disabled == 0 \ > - and host.state == Host::STATE_AVAILABLE > - begin > - # FIXME: this can hang up taskomatic for quite some time. To see how, > - # make one of your remote servers do "iptables -I INPUT -j DROP" > - # and then try to run this; it will take TCP quite a while to give up. > - # Unfortunately the solution is probably to do some sort of threading > - conn = Libvirt::open("qemu+tcp://" + host.hostname + "/system") > - > - # if we didn't raise an exception, we connected; get out of here > + def connect(session, node) > + pools = session.objects(:class => 'pool', 'node' => node.object_id) > + pools.each do |pool| > + result = pool.getXMLDesc > + raise "Error getting xml description of pool: #{result.text}" unless result.status == 0 > + > + xml_desc = result.description > + if self.xmlequal?(Document.new(xml_desc).root) > + @remote_pool = pool > break > - rescue Libvirt::ConnectionError > - # if we couldn't connect for whatever reason, just try the next host > - next > end > end > - end > > - if conn == nil > - # last ditch effort; if we didn't find any hosts, just use ourselves. > - # this may or may not work > - begin > - conn = Libvirt::open("qemu:///system") > - rescue > + #XXX: I'm not sure.. it seems like there could be other things going on > + # with the storage pool state. State can be inactive, building, running > + # or degraded. I think some more thought should go here to make sure > + # we're doing things right in each state. Yes, there are definitely other things that could be going on with the pool, and they definitely need to be thought about. Two things, though; this comment doesn't belong here (it belongs near the "if @remote_pool.state == "inactive" section below), and please use "FIXME" to be consistent with the rest of the source code. > + if @remote_pool == nil > + result = node.storagePoolDefineXML(@xml.to_s) > + raise "Error creating pool: #{result.text}" unless result.status == 0 "Error defining pool" is a little more accurate. > + @remote_pool = session.object(:object_id => result.pool) > + raise "Error finding newly created remote pool." unless @remote_pool > + > + # we need this because we don't want to "build" LVM pools, which would > + # destroy existing data > + if @build_on_start > + result = @remote_pool.build > + raise "Error building pool: #{result.text}" unless result.status == 0 > + end > + @remote_pool_defined = true > + end > + > + if @remote_pool.state == "inactive" > + # only try to start the pool if it is currently inactive; in all other > + # states, assume it is already running > + result = @remote_pool.create > + raise "Error creating pool: #{result.text}" unless result.status == 0 > + > + # Refresh qpid object with new properties. > + @remote_pool.update > + > + @remote_pool_started = true > end > end > > - if conn == nil > - raise "Could not find a host to scan storage" > + def create_vol(type, name, size, owner, group, mode) > + @vol_xml = Document.new > + @vol_xml.add_element("volume", {"type" => type}) > + @vol_xml.root.add_element("name").add_text(name) > + @vol_xml.root.add_element("capacity", {"unit" => "K"}).add_text(size.to_s) > + @vol_xml.root.add_element("target") > + @vol_xml.root.elements["target"].add_element("permissions") > + @vol_xml.root.elements["target"].elements["permissions"].add_element("owner").add_text(owner) > + @vol_xml.root.elements["target"].elements["permissions"].add_element("group").add_text(group) > + @vol_xml.root.elements["target"].elements["permissions"].add_element("mode").add_text(mode) > end > > - return conn > -end > + def shutdown > + if @remote_pool_started > + result = @remote_pool.destroy > + end > + if @remote_pool_defined > + result = @remote_pool.undefine > + end > + end > > -# The words "pool" and "volume" are ridiculously overloaded in our context. > -# Therefore, the refresh_pool method adopts this convention: > -# phys_db_pool: The underlying physical storage pool, as it is represented in > -# the database > -# phys_libvirt_pool: The underlying physical storage, as it is represented in > -# libvirt > -# lvm_db_pool: The logical storage pool (if it exists), as it is represented > -# in the database > -# lvm_libvirt_pool: The logical storage pool (if it exists), as it is > -# represented in the database > - > -def refresh_pool(task) > - puts "refresh_pool" > - > - phys_db_pool = task.storage_pool > - if phys_db_pool == nil > - raise "Could not find storage pool" > + def xmlequal?(docroot) > + return false > end > > - conn = storage_find_suitable_host(phys_db_pool.hardware_pool) > - > - begin > - phys_libvirt_pool = LibvirtPool.factory(phys_db_pool) > - phys_libvirt_pool.connect(conn) > - > - begin > - # OK, the pool is all set. Add in all of the volumes > - add_volumes_to_db(phys_db_pool, phys_libvirt_pool) > - > - phys_db_pool.state = StoragePool::STATE_AVAILABLE > - phys_db_pool.save! > - > - # OK, now we've scanned the underlying hardware pool and added the > - # volumes. Next we scan for pre-existing LVM volumes > - logical_xml = conn.discover_storage_pool_sources("logical") > - > - Document.new(logical_xml).elements.each('sources/source') do |source| > - vgname = source.elements["name"].text > - > - begin > - source.elements.each("device") do |device| > - byid_device = phys_libvirt_pool.lookup_vol_by_path(device.attributes["path"]).path > - end > - rescue > - # If matching any of the sections in the LVM XML fails > - # against the storage pool, then it is likely that this is a storage > - # pool not associated with the one we connected above. Go on > - # FIXME: it would be nicer to catch the right exception here, and > - # fail on other exceptions > - puts "One of the logical volumes in #{vgname} is not part of the pool of type #{phys_db_pool[:type]} that we are scanning; ignore the previous error!" > - next > - end > - > - # if we make it here, then we were able to resolve all of the devices, > - # so we know we need to use a new pool > - lvm_db_pool = LvmStoragePool.find(:first, :conditions => > - [ "vg_name = ?", vgname ]) > - if lvm_db_pool == nil > - lvm_db_pool = LvmStoragePool.new > - lvm_db_pool[:type] = "LvmStoragePool" > - # set the LVM pool to the same hardware pool as the underlying storage > - lvm_db_pool.hardware_pool_id = phys_db_pool.hardware_pool_id > - lvm_db_pool.vg_name = vgname > - lvm_db_pool.save! > - end > - > - source.elements.each("device") do |device| > - byid_device = phys_libvirt_pool.lookup_vol_by_path(device.attributes["path"]).path > - physical_vol = StorageVolume.find(:first, :conditions => > - [ "path = ?", byid_device]) > - if physical_vol == nil > - # Hm. We didn't find the device in the storage volumes already. > - # something went wrong internally, and we have to bail > - raise "Storage internal physical volume error" > - end > - > - # OK, put the right lvm_pool_id in place > - physical_vol.lvm_pool_id = lvm_db_pool.id > - physical_vol.save! > - end > - > - lvm_libvirt_pool = LibvirtPool.factory(lvm_db_pool) > - lvm_libvirt_pool.connect(conn) > - > - begin > - add_volumes_to_db(lvm_db_pool, lvm_libvirt_pool, "0744", "0744", "0744") > - ensure > - lvm_libvirt_pool.shutdown > - end > - end > - ensure > - phys_libvirt_pool.shutdown > + def self.factory(pool) > + if pool[:type] == "IscsiStoragePool" > + return IscsiLibvirtPool.new(pool.ip_addr, pool[:target]) > + elsif pool[:type] == "NfsStoragePool" > + return NFSLibvirtPool.new(pool.ip_addr, pool.export_path) > + elsif pool[:type] == "LvmStoragePool" > + # OK, if this is LVM storage, there are two cases we need to care about: > + # 1) this is a LUN with LVM already on it. In this case, all we need to > + # do is to create a new LV (== libvirt volume), and be done with it > + # 2) this LUN is blank, so there is no LVM on it already. In this > + # case, we need to pvcreate, vgcreate first (== libvirt pool build), > + # and *then* create the new LV (== libvirt volume) on top of that. > + # > + # We can tell the difference between an LVM Pool that exists and one > + # that needs to be created based on the value of the pool.state; > + # if it is PENDING_SETUP, we need to create it first > + phys_volume = StorageVolume.find(:first, :conditions => > + [ "lvm_pool_id = ?", pool.id]) > + return LVMLibvirtPool.new(pool.vg_name, phys_volume.path, > + pool.state == StoragePool::STATE_PENDING_SETUP) > + else > + raise "Unknown storage pool type " + pool[:type].to_s > end > - ensure > - conn.close > end > end > > -def create_volume(task) > - puts "create_volume" > +class IscsiLibvirtPool < LibvirtPool > + def initialize(ip_addr, target) > + super('iscsi') > + > + @type = 'iscsi' > + @ipaddr = ip_addr > + @target = target > + > + @xml.root.elements["source"].add_element("host", {"name" => @ipaddr}) > + @xml.root.elements["source"].add_element("device", {"path" => @target}) > > - db_volume = task.storage_volume > - if db_volume == nil > - raise "Could not find storage volume to create" > + @xml.root.elements["target"].elements["path"].text = "/dev/disk/by-id" > end > > - db_pool = db_volume.storage_pool > - if db_pool == nil > - raise "Could not find storage pool" > + def xmlequal?(docroot) > + return (docroot.attributes['type'] == @type and > + docroot.elements['source'].elements['host'].attributes['name'] == @ipaddr and > + docroot.elements['source'].elements['device'].attributes['path'] == @target) > end > +end > > - conn = storage_find_suitable_host(db_pool.hardware_pool) > +class NFSLibvirtPool < LibvirtPool > + def initialize(ip_addr, export_path) > + super('netfs') > > - begin > - if db_volume[:type] == "LvmStorageVolume" > - phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(db_volume) > - phys_libvirt_pool.connect(conn) > - end > + @type = 'netfs' > + @host = ip_addr > + @remote_path = export_path > + @name = String.random_alphanumeric I'm not sure if this is a bug from my code before, or a new one, but @name is already set by super() (in a better way, in my opinion), so you don't need to re-do it here. > > - begin > - libvirt_pool = LibvirtPool.factory(db_pool) > + @xml.root.elements["source"].add_element("host", {"name" => @host}) > + @xml.root.elements["source"].add_element("dir", {"path" => @remote_path}) > + @xml.root.elements["source"].add_element("format", {"type" => "nfs"}) > > - begin > - libvirt_pool.connect(conn) > + @xml.root.elements["target"].elements["path"].text = "/mnt/" + @name > + end > > - libvirt_pool.create_vol(*db_volume.volume_create_params) > - db_volume.state = StorageVolume::STATE_AVAILABLE > - db_volume.save! > + def create_vol(name, size, owner, group, mode) > + # FIXME: this can actually take some time to complete (since we aren't > + # doing sparse allocations at the moment). During that time, whichever > + # libvirtd we chose to use is completely hung up. The solution is 3-fold: > + # 1. Allow sparse allocations in the WUI front-end > + # 2. Make libvirtd multi-threaded > + # 3. Make taskomatic multi-threaded > + super("netfs", name, size, owner, group, mode) > + > + # FIXME: we have to add the format as raw here because of a bug in libvirt; > + # if you specify a volume with no format, it will crash libvirtd > + @vol_xml.root.elements["target"].add_element("format", {"type" => "raw"}) > + result = @remote_pool.createVolumeXML(@vol_xml.to_s) > + raise "Error creating remote pool: #{result.text}" unless result.status == 0 > + return result.volume > + end > > - db_pool.state = StoragePool::STATE_AVAILABLE > - db_pool.save! > - ensure > - libvirt_pool.shutdown > - end > - ensure > - if db_volume[:type] == "LvmStorageVolume" > - phys_libvirt_pool.shutdown > - end > - end > - ensure > - conn.close > + def xmlequal?(docroot) > + return (docroot.attributes['type'] == @type and > + docroot.elements['source'].elements['host'].attributes['name'] == @host and > + docroot.elements['source'].elements['dir'].attributes['path'] == @remote_path) > end > end > > -def delete_volume(task) > - puts "delete_volume" > +class LVMLibvirtPool < LibvirtPool > + def initialize(vg_name, device, build_on_start) > + super('logical', vg_name) > > - db_volume = task.storage_volume > - if db_volume == nil > - raise "Could not find storage volume to create" > - end > + @type = 'logical' > + @build_on_start = build_on_start > > - db_pool = db_volume.storage_pool > - if db_pool == nil > - raise "Could not find storage pool" > + @xml.root.elements["source"].add_element("name").add_text(@name) > + @xml.root.elements["source"].add_element("device", {"path" => device}) > + @xml.root.elements["target"].elements["path"].text = "/dev/" + @name > end > > - conn = storage_find_suitable_host(db_pool.hardware_pool) > - > - begin > - if db_volume[:type] == "LvmStorageVolume" > - phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(db_volume) > - phys_libvirt_pool.connect(conn) > - end > + def create_vol(name, size, owner, group, mode) > + super("logical", name, size, owner, group, mode) > + result = @remote_pool.createVolumeXML(@vol_xml.to_s) > + raise "Error creating remote pool: #{result.text}" unless result.status == 0 > + return result.volume > + end > > - begin > - libvirt_pool = LibvirtPool.factory(db_pool) > - libvirt_pool.connect(conn) > - > - begin > - libvirt_volume = libvirt_pool.lookup_vol_by_name(db_volume.read_attribute(db_volume.volume_name)) > - # FIXME: we actually probably want to zero out the whole volume here, so > - # we aren't potentially leaking data from one user to another. There > - # are two problems, though: > - # 1) I'm not sure how I would go about zero'ing the data on a remote > - # machine, since there is no "libvirt_write_data" call > - # 2) This could potentially take quite a while, so we want to spawn > - # off another thread to do it > - libvirt_volume.delete > - > - # Note: we have to nil out the task_target because when we delete the > - # volume object, that also deletes all dependent tasks (including this > - # one), which leads to accessing stale tasks. Orphan the task, then > - # delete the object; we can clean up orphans later (or not, depending > - # on the audit policy) > - task.task_target = nil > - task.save! > - > - db_volume.destroy > - ensure > - libvirt_pool.shutdown > - end > - ensure > - if db_volume[:type] == "LvmStorageVolume" > - phys_libvirt_pool.shutdown > - end > - end > - ensure > - conn.close > + def xmlequal?(docroot) > + return (docroot.attributes['type'] == @type and > + docroot.elements['name'].text == @name and > + docroot.elements['source'].elements['name'] and > + docroot.elements['source'].elements['name'].text == @name) > end > end > + > diff --git a/src/task-omatic/task_vm.rb b/src/task-omatic/task_vm.rb > index c187287..46ef261 100644 > --- a/src/task-omatic/task_vm.rb > +++ b/src/task-omatic/task_vm.rb > @@ -19,35 +19,10 @@ > require 'rexml/document' > include REXML > > -require 'utils' > - > gem 'cobbler' > require 'cobbler' > > -def findHostSLA(vm) > - host = nil > - > - vm.vm_resource_pool.get_hardware_pool.hosts.each do |curr| > - # FIXME: we probably need to add in some notion of "load" into this check > - if curr.num_cpus >= vm.num_vcpus_allocated \ > - and curr.memory >= vm.memory_allocated \ > - and not curr.is_disabled.nil? and curr.is_disabled == 0 \ > - and curr.state == Host::STATE_AVAILABLE \ > - and (vm.host_id.nil? or (not vm.host_id.nil? and vm.host_id != curr.id)) > - host = curr > - break > - end > - end > - > - if host == nil > - # we couldn't find a host that matches this criteria > - raise "No host matching VM parameters could be found" > - end > - > - return host > -end > - > -def findHost(host_id) > +def find_host(host_id) > host = Host.find(:first, :conditions => [ "id = ?", host_id]) > > if host == nil > @@ -58,75 +33,6 @@ def findHost(host_id) > return host > end > > -def connect_storage_pools(conn, storage_volumes) > - storagedevs = [] > - storage_volumes.each do |volume| > - # here, we need to iterate through each volume and possibly attach it > - # to the host we are going to be using > - db_pool = volume.storage_pool > - if db_pool == nil > - # Hum. Specified by the VM description, but not in the storage pool? > - # continue on and hope for the best > - puts "Couldn't find pool for volume #{volume.path}; skipping" > - next > - end > - > - # we have to special case LVM pools. In that case, we need to first > - # activate the underlying physical device, and then do the logical one > - if volume[:type] == "LvmStorageVolume" > - phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(volume) > - phys_libvirt_pool.connect(conn) > - end > - > - libvirt_pool = LibvirtPool.factory(db_pool) > - libvirt_pool.connect(conn) > - > - # OK, the pool should be all set. The last thing we need to do is get > - # the path based on the volume name > - storagedevs << libvirt_pool.lookup_vol_by_name(volume.read_attribute(volume.volume_name)).path > - end > - > - return storagedevs > -end > - > -def remove_pools(conn, type = nil) > - all_storage_pools(conn).each do |remote_pool_name| > - pool = conn.lookup_storage_pool_by_name(remote_pool_name) > - > - if type == nil or type == Document.new(pool.xml_desc).root.attributes['type'] > - begin > - pool.destroy > - rescue > - end > - > - begin > - # if the destroy failed, we still try to undefine; it may be a pool > - # that was previously destroyed but not undefined for whatever reason > - pool.undefine > - rescue > - # do nothing if any of this failed; the worst that happens is that > - # we leave a pool configured > - puts "Could not teardown pool " + remote_pool_name + "; skipping" > - end > - end > - end > -end > - > -def teardown_storage_pools(conn) > - # FIXME: this needs to get a *lot* smarter. In particular, we want to make > - # sure we can tear down unused pools even when there are other guests running > - if conn.list_domains.empty? > - # OK, there are no running guests on this host anymore. We can teardown > - # any storage pools that are there without fear > - > - # we first have to tear-down LVM pools, because they might depend on the > - # underlying physical pools > - remove_pools(conn, "logical") > - > - # now tear down the rest of the pools > - remove_pools(conn) > - end > -end > > def create_vm_xml(name, uuid, memAllocated, memUsed, vcpus, bootDevice, > macAddr, bridge, diskDevices) > @@ -195,13 +101,13 @@ def create_vm_xml(name, uuid, memAllocated, memUsed, vcpus, bootDevice, > return doc > end > > -def setVmState(vm, state) > +def set_vm_state(vm, state) > vm.state = state > vm.save! > end > > -def setVmVncPort(vm, domain) > - doc = REXML::Document.new(domain.xml_desc) > +def set_vm_vnc_port(vm, xml_desc) > + doc = REXML::Document.new(xml_desc) > attrib = REXML::XPath.match(doc, "//graphics/@port") > if not attrib.empty?: > vm.vnc_port = attrib.to_s.to_i > @@ -209,32 +115,22 @@ def setVmVncPort(vm, domain) > vm.save! > end > > -def findVM(task, fail_on_nil_host_id = true) > +def find_vm(task, fail_on_nil_host_id = true) > # find the matching VM in the vms table > vm = task.vm > > if vm == nil > - raise "VM not found for task " + task.id > + raise "VM #{task.vm} not found for task #{task.id}" > end > > if vm.host_id == nil && fail_on_nil_host_id > - # in this case, we have no idea where the VM is. How can we handle this > - # gracefully? We don't necessarily want to just set the VM state to off; > - # if the machine does happen to be running somewhere and we set it to > - # disabled here, and then start it again, we could corrupt the disk > - > - # FIXME: the right thing to do here is probably to contact all of the > - # hosts we know about and ensure that the domain isn't running; then we > - # can mark it either as off (if we didn't find it), or mark the correct > - # vm.host_id if we did. However, if you have a large number of hosts > - # out there, this could take a while. > raise "No host_id for VM " + vm.id.to_s > end > > return vm > end > > -def setVmShutdown(vm) > +def set_vm_shut_down(vm) > vm.host_id = nil > vm.memory_used = nil > vm.num_vcpus_used = nil > @@ -244,459 +140,3 @@ def setVmShutdown(vm) > vm.save! > end > > -def create_vm(task) > - puts "create_vm" > - > - vm = findVM(task, false) > - > - if vm.state != Vm::STATE_PENDING > - raise "VM not pending" > - end > - setVmState(vm, Vm::STATE_CREATING) > - > - # create cobbler system profile > - begin > - # FIXME: Presently the wui handles all cobbler system creation. > - # This should be moved out of the wui into Taskomatic. Specifically > - # here, and in the edit_vm methods. > - > - setVmState(vm, Vm::STATE_STOPPED) > - rescue Exception => error > - setVmState(vm, Vm::STATE_CREATE_FAILED) > - raise "Unable to create system: #{error.message}" > - end > -end > - > -def shut_or_destroy_vm(task, which) > - # here, we are given an id for a VM to shutdown; we have to lookup which > - # physical host it is running on > - > - vm = findVM(task) > - > - if vm.state == Vm::STATE_STOPPED > - # the VM is already shutdown; just return success > - setVmShutdown(vm) > - return > - elsif vm.state == Vm::STATE_SUSPENDED > - raise "Cannot shutdown suspended domain" > - elsif vm.state == Vm::STATE_SAVED > - raise "Cannot shutdown saved domain" > - end > - > - vm_orig_state = vm.state > - setVmState(vm, Vm::STATE_STOPPING) > - > - begin > - conn = Libvirt::open("qemu+tcp://" + vm.host.hostname + "/system") > - dom = conn.lookup_domain_by_uuid(vm.uuid) > - dom.send(which) > - > - begin > - dom.undefine > - rescue > - # undefine can fail, for instance, if we live migrated from A -> B, and > - # then we are shutting down the VM on B (because it only has "transient" > - # XML). Therefore, just ignore undefine errors so we do the rest > - # FIXME: we really should have a marker in the database somehow so that > - # we can tell if this domain was migrated; that way, we can tell the > - # difference between a real undefine failure and one because of migration > - end > - > - teardown_storage_pools(conn) > - > - conn.close > - rescue => ex > - setVmState(vm, vm_orig_state) > - raise ex > - end > - > - setVmShutdown(vm) > -end > - > -def shutdown_vm(task) > - puts "shutdown_vm" > - shut_or_destroy_vm(task, "shutdown") > -end > - > -def poweroff_vm(task) > - puts "poweroff_vm" > - shut_or_destroy_vm(task, "destroy") > -end > - > -def start_vm(task) > - puts "start_vm" > - > - # here, we are given an id for a VM to start > - > - vm = findVM(task, false) > - > - if vm.state == Vm::STATE_RUNNING > - # the VM is already running; just return success > - return > - elsif vm.state == Vm::STATE_SUSPENDED > - raise "Cannot start suspended domain" > - elsif vm.state == Vm::STATE_SAVED > - raise "Cannot start saved domain" > - end > - > - # FIXME: Validate that the VM is still within quota > - > - vm_orig_state = vm.state > - setVmState(vm, Vm::STATE_STARTING) > - > - begin > - if vm.host_id != nil > - # OK, marked in the database as already running on a host; for now, we > - # will just fail the operation > - > - # FIXME: we probably want to go out to the host it is marked on and check > - # things out, just to make sure things are consistent > - raise "VM already running" > - end > - > - # OK, now that we found the VM, go looking in the hardware_pool > - # hosts to see if there is a host that will fit these constraints > - host = findHostSLA(vm) > - > - # if we're booting from a CDROM the VM is an image, > - # then we need to add the NFS mount as a storage volume for this > - # boot > - # > - if (vm.boot_device == Vm::BOOT_DEV_CDROM) && vm.uses_cobbler? && (vm.cobbler_type == Vm::IMAGE_PREFIX) > - details = Cobbler::Image.find_one(vm.cobbler_name) > - > - raise "Image #{vm.cobbler_name} not found in Cobbler server" unless details > - > - # extract the components of the image filename > - image_uri = details.file > - protocol = auth = ip_addr = export_path = filename = "" > - > - protocol, image_uri = image_uri.split("://") if image_uri.include?("://") > - auth, image_uri = image_uri.split("@") if image_uri.include?("@") > - # it's ugly, but string.split returns an empty string as the first > - # result here, so we'll just ignore it > - ignored, ip_addr, image_uri = > - image_uri.split(/^([^\/]+)(\/.*)/) unless image_uri =~ /^\// > - ignored, export_path, filename = > - image_uri.split(/^(.*)\/(.+)/) > - > - found = false > - > - vm.storage_volumes.each do |volume| > - if volume.filename == filename > - if (volume.storage_pool.ip_addr == ip_addr) && > - (volume.storage_pool.export_path == export_path) > - found = true > - end > - end > - end > - > - unless found > - # Create a new transient NFS storage volume > - # This volume is *not* persisted. > - image_volume = StorageVolume.factory("NFS", > - :filename => filename > - ) > - > - image_volume.storage_pool > - image_pool = StoragePool.factory(StoragePool::NFS) > - > - image_pool.ip_addr = ip_addr > - image_pool.export_path = export_path > - image_pool.storage_volumes << image_volume > - image_volume.storage_pool = image_pool > - end > - end > - > - volumes = [] > - volumes += vm.storage_volumes > - volumes << image_volume if image_volume > - > - conn = Libvirt::open("qemu+tcp://" + host.hostname + "/system") > - > - begin > - storagedevs = connect_storage_pools(conn, volumes) > - > - dom = nil > - begin > - # FIXME: get rid of the hardcoded bridge > - xml = create_vm_xml(vm.description, vm.uuid, vm.memory_allocated, > - vm.memory_used, vm.num_vcpus_allocated, > - vm.boot_device, vm.vnic_mac_addr, "ovirtbr0", > - storagedevs) > - dom = conn.define_domain_xml(xml.to_s) > - dom.create > - > - setVmVncPort(vm, dom) > - rescue > - if dom != nil > - dom.undefine > - end > - teardown_storage_pools(conn) > - raise ex > - end > - ensure > - conn.close > - end > - rescue => ex > - setVmState(vm, vm_orig_state) > - raise ex > - end > - > - vm.host_id = host.id > - vm.state = Vm::STATE_RUNNING > - vm.memory_used = vm.memory_allocated > - vm.num_vcpus_used = vm.num_vcpus_allocated > - vm.boot_device = Vm::BOOT_DEV_HD > - vm.save! > -end > - > -def save_vm(task) > - puts "save_vm" > - > - # here, we are given an id for a VM to suspend > - > - vm = findVM(task) > - > - if vm.state == Vm::STATE_SAVED > - # the VM is already saved; just return success > - return > - elsif vm.state == Vm::STATE_SUSPENDED > - raise "Cannot save suspended domain" > - elsif vm.state == Vm::STATE_STOPPED > - raise "Cannot save shutdown domain" > - end > - > - vm_orig_state = vm.state > - setVmState(vm, Vm::STATE_SAVING) > - > - begin > - conn = Libvirt::open("qemu+tcp://" + vm.host.hostname + "/system") > - dom = conn.lookup_domain_by_uuid(vm.uuid) > - dom.save("/tmp/" + vm.uuid + ".save") > - conn.close > - rescue => ex > - setVmState(vm, vm_orig_state) > - raise ex > - end > - > - # note that we do *not* reset the host_id here, since we stored the saved > - # vm state information locally. restore_vm will pick it up from here > - > - # FIXME: it would be much nicer to be able to save the VM and remove the > - # the host_id and undefine the XML; that way we could resume it on another > - # host later. This can be done once we have the storage APIs, but it will > - # need more work > - > - setVmState(vm, Vm::STATE_SAVED) > -end > - > -def restore_vm(task) > - puts "restore_vm" > - > - # here, we are given an id for a VM to start > - > - vm = findVM(task) > - > - if vm.state == Vm::STATE_RUNNING > - # the VM is already saved; just return success > - return > - elsif vm.state == Vm::STATE_SUSPENDED > - raise "Cannot restore suspended domain" > - elsif vm.state == Vm::STATE_STOPPED > - raise "Cannot restore shutdown domain" > - end > - > - vm_orig_state = vm.state > - setVmState(vm, Vm::STATE_RESTORING) > - > - begin > - # FIXME: we should probably go out to the host and check what it thinks > - # the state is > - > - conn = Libvirt::open("qemu+tcp://" + vm.host.hostname + "/system") > - dom = conn.lookup_domain_by_uuid(vm.uuid) > - dom.restore > - > - setVmVncPort(vm, dom) > - > - conn.close > - rescue => ex > - setVmState(vm, vm_orig_state) > - raise ex > - end > - > - setVmState(vm, Vm::STATE_RUNNING) > -end > - > -def suspend_vm(task) > - puts "suspend_vm" > - > - # here, we are given an id for a VM to suspend; we have to lookup which > - # physical host it is running on > - > - vm = findVM(task) > - > - if vm.state == Vm::STATE_SUSPENDED > - # the VM is already suspended; just return success > - return > - elsif vm.state == Vm::STATE_STOPPED > - raise "Cannot suspend stopped domain" > - elsif vm.state == Vm::STATE_SAVED > - raise "Cannot suspend saved domain" > - end > - > - vm_orig_state = vm.state > - setVmState(vm, Vm::STATE_SUSPENDING) > - > - begin > - conn = Libvirt::open("qemu+tcp://" + vm.host.hostname + "/system") > - dom = conn.lookup_domain_by_uuid(vm.uuid) > - dom.suspend > - conn.close > - rescue => ex > - setVmState(vm, vm_orig_state) > - raise ex > - end > - > - # note that we do *not* reset the host_id here, since we just suspended the VM > - # resume_vm will pick it up from here > - > - setVmState(vm, Vm::STATE_SUSPENDED) > -end > - > -def resume_vm(task) > - puts "resume_vm" > - > - # here, we are given an id for a VM to start > - > - vm = findVM(task) > - > - # OK, marked in the database as already running on a host; let's check it > - > - if vm.state == Vm::STATE_RUNNING > - # the VM is already suspended; just return success > - return > - elsif vm.state == Vm::STATE_STOPPED > - raise "Cannot resume stopped domain" > - elsif vm.state == Vm::STATE_SAVED > - raise "Cannot resume suspended domain" > - end > - > - vm_orig_state = vm.state > - setVmState(vm, Vm::STATE_RESUMING) > - > - begin > - conn = Libvirt::open("qemu+tcp://" + vm.host.hostname + "/system") > - dom = conn.lookup_domain_by_uuid(vm.uuid) > - dom.resume > - conn.close > - rescue => ex > - setVmState(vm, vm_orig_state) > - raise ex > - end > - > - setVmState(vm, Vm::STATE_RUNNING) > -end > - > -def update_state_vm(task) > - puts "update_state_vm" > - > - # NOTE: findVM() will only return a vm if all the host information is filled > - # in. So if a vm that we thought was stopped is running, this returns nil > - # and we don't update any information about it. The tricky part > - # is that we're still not sure what to do in this case :). - Ian > - # > - # Actually for migration it is necessary that it be able to update > - # the host and state of the VM once it is migrated. > - vm = findVM(task, false) > - new_vm_state, host_id_str = task.args.split(",") > - if (vm.host_id == nil) and host_id_str > - vm.host_id = host_id_str.to_i > - end > - > - > - vm_effective_state = Vm::EFFECTIVE_STATE[vm.state] > - task_effective_state = Vm::EFFECTIVE_STATE[new_vm_state] > - > - if vm_effective_state != task_effective_state > - vm.state = new_vm_state > - > - if task_effective_state == Vm::STATE_STOPPED > - setVmShutdown(vm) > - end > - vm.save! > - puts "Updated state to " + new_vm_state > - end > -end > - > -def migrate(vm, dest = nil) > - if vm.state == Vm::STATE_STOPPED > - raise "Cannot migrate stopped domain" > - elsif vm.state == Vm::STATE_SUSPENDED > - raise "Cannot migrate suspended domain" > - elsif vm.state == Vm::STATE_SAVED > - raise "Cannot migrate saved domain" > - end > - > - vm_orig_state = vm.state > - setVmState(vm, Vm::STATE_MIGRATING) > - > - begin > - src_host = findHost(vm.host_id) > - unless dest.nil? or dest.empty? > - if dest.to_i == vm.host_id > - raise "Cannot migrate from host " + src_host.hostname + " to itself!" > - end > - dst_host = findHost(dest.to_i) > - else > - dst_host = findHostSLA(vm) > - end > - > - src_conn = Libvirt::open("qemu+tcp://" + src_host.hostname + "/system") > - dst_conn = Libvirt::open("qemu+tcp://" + dst_host.hostname + "/system") > - > - connect_storage_pools(dst_conn, vm) > - > - dom = src_conn.lookup_domain_by_uuid(vm.uuid) > - dom.migrate(dst_conn, Libvirt::Domain::MIGRATE_LIVE) > - > - # if we didn't raise an exception, then the migration was successful. We > - # still have a pointer to the now-shutdown domain on the source side, so > - # undefine it > - begin > - dom.undefine > - rescue > - # undefine can fail, for instance, if we live migrated from A -> B, and > - # then we are shutting down the VM on B (because it only has "transient" > - # XML). Therefore, just ignore undefine errors so we do the rest > - # FIXME: we really should have a marker in the database somehow so that > - # we can tell if this domain was migrated; that way, we can tell the > - # difference between a real undefine failure and one because of migration > - end > - > - teardown_storage_pools(src_conn) > - dst_conn.close > - src_conn.close > - rescue => ex > - # FIXME: ug. We may have open connections that we need to close; not > - # sure how to handle that > - setVmState(vm, vm_orig_state) > - raise ex > - end > - > - setVmState(vm, Vm::STATE_RUNNING) > - vm.host_id = dst_host.id > - vm.save! > -end > - > -def migrate_vm(task) > - puts "migrate_vm" > - > - # here, we are given an id for a VM to migrate; we have to lookup which > - # physical host it is running on > - > - vm = findVM(task) > - > - migrate(vm, task.args) > -end > diff --git a/src/task-omatic/taskomatic.rb b/src/task-omatic/taskomatic.rb > index ce37058..3eefc5a 100755 > --- a/src/task-omatic/taskomatic.rb > +++ b/src/task-omatic/taskomatic.rb > @@ -1,7 +1,7 @@ > #!/usr/bin/ruby > -# > +# > # Copyright (C) 2008 Red Hat, Inc. > -# Written by Chris Lalancette > +# Written by Chris Lalancette and Ian Main > # > # 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 > @@ -22,122 +22,765 @@ $: << File.join(File.dirname(__FILE__), "../dutils") > $: << File.join(File.dirname(__FILE__), ".") > > require 'rubygems' > +require "qpid" Nit; use single-quotes for consistency > +require 'monitor' > +require 'dutils' > require 'optparse' > require 'daemons' > include Daemonize > > -$logfile = '/var/log/ovirt-server/taskomatic.log' > +require 'task_vm' > +require 'task_storage' > + > +class TaskOmatic > + > + include MonitorMixin > + > + $logfile = '/var/log/ovirt-server/taskomatic.log' > + > + def initialize() > + super() > + > + @sleeptime = 5 > + @nth_host = 0 > + > + @session = Qpid::Qmf::Session.new() > + # FIXME: Should come from some kind of config or DNS SRV or what have you. > + @broker = @session.add_broker("amqp://localhost:5672") > + > + do_daemon = true > + > + opts = OptionParser.new do |opts| > + opts.on("-h", "--help", "Print help message") do > + puts opts > + exit > + end > + opts.on("-n", "--nodaemon", "Run interactively (useful for debugging)") do |n| > + do_daemon = false > + end > + opts.on("-s N", Integer, "--sleep", "Seconds to sleep between iterations (default is 5 seconds)") do |s| > + sleeptime = s > + end > + end > + begin > + opts.parse!(ARGV) > + rescue OptionParser::InvalidOption > + puts opts > + exit > + end > > -do_daemon = true > -sleeptime = 5 > -opts = OptionParser.new do |opts| > - opts.on("-h", "--help", "Print help message") do > - puts opts > - exit > + if do_daemon > + # XXX: This gets around a problem with paths for the database stuff. > + # Normally daemonize would chdir to / but the paths for the database > + # stuff are relative so it breaks it.. It's either this or rearrange > + # things so the db stuff is included after daemonizing. Ugly, but fine. Really, just remove the XXX and just leave the comment in place; the code needs to be like this. > + pwd = Dir.pwd > + daemonize > + Dir.chdir(pwd) > + lf = open($logfile, 'a') > + $stdout = lf > + $stderr = lf > + end > end > - opts.on("-n", "--nodaemon", "Run interactively (useful for debugging)") do |n| > - do_daemon = !n > + > + def find_capable_host(db_vm) > + possible_hosts = [] > + > + vm = @session.object(:class => "domain", 'uuid' => db_vm.uuid) > + > + db_vm.vm_resource_pool.get_hardware_pool.hosts.each do |curr| > + # Now each of 'curr' is in the right hardware pool.. now we check them out. > + > + node = @session.object(:class => "node", 'hostname' => curr.hostname) > + next unless node > + > + # So now we expect if the node was found it's alive and well, then we check > + # to make sure there's enough real cores for the number of vcpus, the node > + # memory is adequate, the node is not disabled in the database, and if the > + # node id is nil or if it is already running (has a node id set) then it > + # is probably looking to migrate so we find a node that is not the current > + # node. > + # > + # In the future we could add load or similar checks here. > + > + #puts "checking node, #{node.cores} >= #{db_vm.num_vcpus_allocated}," > + #puts "and #{node.memory} >= #{db_vm.memory_allocated}" > + #puts "and not #{curr.is_disabled.nil?} and #{curr.is_disabled == 0}" > + #puts "and #{vm ? vm : 'nil'} or #{vm ? vm.active : 'nil'}) or #{vm ? vm.node : 'nil'} != #{node.object_id}" > + > + if node and node.cores >= db_vm.num_vcpus_allocated \ > + and node.memory >= db_vm.memory_allocated \ > + and not curr.is_disabled.nil? and curr.is_disabled == 0 \ > + and ((!vm or vm.active == 'false') or vm.node != node.object_id) > + possible_hosts.push(curr) > + end > + end > + > + #puts "possible_hosts.length = #{possible_hosts.length}" > + if possible_hosts.length == 0 > + # we couldn't find a host that matches this criteria > + raise "No host matching VM parameters could be found" > + end > + > + # XXX: Right now we're just picking the nth host, we could also look at > + # how many vms are already on it, or the load of the hosts etc. > + host = possible_hosts[@nth_host % possible_hosts.length] > + @nth_host += 1 > + > + return host > end > - opts.on("-s N", Integer, "--sleep", "Seconds to sleep between iterations (default is 5 seconds)") do |s| > - sleeptime = s > + > + def connect_storage_pools(node, storage_volumes) > + storagedevs = [] > + storage_volumes.each do |db_volume| > + # here, we need to iterate through each volume and possibly attach it > + # to the host we are going to be using > + db_pool = db_volume.storage_pool > + if db_pool == nil > + # Hum. Specified by the VM description, but not in the storage pool? > + # continue on and hope for the best > + puts "Couldn't find pool for volume #{db_volume.path}; skipping" > + next > + end > + > + # we have to special case LVM pools. In that case, we need to first > + # activate the underlying physical device, and then do the logical one > + if db_volume[:type] == "LvmStorageVolume" > + phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(db_volume) > + phys_libvirt_pool.connect(@session, node) > + end > + > + libvirt_pool = LibvirtPool.factory(db_pool) > + libvirt_pool.connect(@session, node) > + > + # OK, the pool should be all set. The last thing we need to do is get > + # the path based on the volume name > + > + volume_name = db_volume.read_attribute(db_volume.volume_name) > + pool = libvirt_pool.remote_pool > + volume = @session.object(:class => 'volume', > + 'name' => volume_name, > + 'storagePool' => pool.object_id) > + raise "Unable to find volume #{volume_name} attached to pool #{pool.name}." unless volume > + storagedevs << volume.path > + end > + > + return storagedevs > end > -end > -begin > - opts.parse!(ARGV) > -rescue OptionParser::InvalidOption > - puts opts > - exit > -end > > -if do_daemon > - daemonize > - STDOUT.reopen $logfile, 'a' > - STDERR.reopen STDOUT > -end > + def task_create_vm(task) > + # XXX: This is mostly just a place holder. > + vm = find_vm(task, false) > + if vm.state != Vm::STATE_PENDING > + raise "VM not pending" > + end > + vm.state = Vm::STATE_STOPPED > + vm.save! > + end > > -begin > - require 'dutils' > -rescue => ex > - puts "dutils require failed! #{ex.class}: #{ex.message}" > -end > + def teardown_storage_pools(node) > > -require 'task_vm' > -require 'task_storage' > -require 'task_host' > - > -loop do > - tasks = Array.new > - begin > - tasks = Task.find(:all, :conditions => [ "state = ?", Task::STATE_QUEUED ]) > - rescue => ex > - puts "1 #{ex.class}: #{ex.message}" > - if Task.connected? > - begin > - ActiveRecord::Base.connection.reconnect! > - rescue => norecon > - puts "2 #{norecon.class}: #{norecon.message}" > + # This is rather silly because we only destroy pools if there are no > + # more vms on the node. We should be reference counting the pools > + # somehow so we know when they are no longer in use. > + vms = @session.objects(:class => 'domain', 'node' => node.object_id) > + if vms.length > 0 > + return > + end > + pools = @session.objects(:class => 'pool', 'node' => node.object_id) > + > + # FIXME: I think we should be destroying/undefining logical volumes first. Yes, 100% correct. You must fix this for LVM pools to work properly, otherwise it will fail utterly. > + pools.each do |pool| > + result = pool.destroy > + result = pool.undefine > + end > + end > + > + > + def task_shutdown_or_destroy_vm(task, action) > + db_vm = task.vm > + vm = @session.object(:class => 'domain', 'uuid' => db_vm.uuid) > + if !vm > + puts "VM already shut down?" > + return > + end > + > + node = @session.object(:object_id => vm.node) > + raise "Unable to get node that vm is on??" unless node > + > + if vm.state == "shutdown" or vm.state == "shutoff" > + set_vm_shut_down(db_vm) > + return > + elsif vm.state == "suspended" > + raise "Cannot shutdown suspended domain" > + elsif vm.state == "saved" > + raise "Cannot shutdown saved domain" > + end > + > + if action == :shutdown > + result = vm.shutdown > + raise "Error shutting down VM: #{result.text}" unless result.status == 0 > + elsif action == :destroy > + result = vm.destroy > + raise "Error destroying VM: #{result.text}" unless result.status == 0 > + end > + > + # undefine can fail, for instance, if we live migrated from A -> B, and > + # then we are shutting down the VM on B (because it only has "transient" > + # XML). Therefore, just ignore undefine errors so we do the rest > + # FIXME: we really should have a marker in the database somehow so that > + # we can tell if this domain was migrated; that way, we can tell the > + # difference between a real undefine failure and one because of migration > + result = vm.undefine > + puts "Error undefining VM: #{result.text}" unless result.status == 0 How are you handling the above comment with this code? > + > + teardown_storage_pools(node) > + > + set_vm_shut_down(db_vm) > + end > + > + def task_start_vm(task) > + db_vm = find_vm(task, false) > + > + # XXX: Kinda silly? I dunno about these intermediate states.. > + set_vm_state(db_vm, Vm::STATE_STARTING) > + > + vm = @session.object(:class => "domain", 'uuid' => db_vm.uuid) > + > + if vm > + case vm.state > + when "running" > + return > + when "blocked" > + raise "Virtual machine state is blocked, cannot start VM." > + when "paused" > + raise "Virtual machine is currently paused, cannot start, must resume." > end > - else > - begin > - database_connect > - rescue => ex > - puts "3 #{ex.class}: #{ex.message}" > + end > + # FIXME: There's a bug here in that a host that's already running the vm won't be > + # returned. I think that's supposed to be for migration but it just breaks stuff. > + db_host = find_capable_host(db_vm) I'm not quite sure what this FIXME means. If we are here in task_start_vm, and the vm is already running, then we have some sort of logical error. Now, we should probably be robust to that error, but I think overloading find_capable_host() for that is the wrong way to go; we should just have another set of checks before this. Oh, and it doesn't have anything to do with migration, as far as I can remember. > + > + node = @session.object(:class => "node", 'hostname' => db_host.hostname) > + > + raise "Unable to find host #{db_host.hostname} to create VM on." unless node > + > + if (db_vm.boot_device == Vm::BOOT_DEV_CDROM) && db_vm.uses_cobbler? && (db_vm.cobbler_type == Vm::IMAGE_PREFIX) I know you didn't put this here, but since you are moving things around... It would seem like a good idea to make a helper method with the Cobbler stuff in it. I think that just makes it look cleaner, as the details in getting the Cobbler stuff isn't really interesting when you are reading the start_vm task. > + > + details = Cobbler::Image.find_one(db_vm.cobbler_name) > + raise "Image #{vm.cobbler_name} not found in Cobbler server" unless details > + > + # extract the components of the image filename > + image_uri = details.file > + protocol = auth = ip_addr = export_path = filename = "" > + > + protocol, image_uri = image_uri.split("://") if image_uri.include?("://") > + auth, image_uri = image_uri.split("@") if image_uri.include?("@") > + # it's ugly, but string.split returns an empty string as the first > + # result here, so we'll just ignore it > + ignored, ip_addr, image_uri = > + image_uri.split(/^([^\/]+)(\/.*)/) unless image_uri =~ /^\// > + ignored, export_path, filename = > + image_uri.split(/^(.*)\/(.+)/) > + > + found = false > + > + db_vm.storage_volumes.each do |volume| > + if volume.filename == filename > + if (volume.storage_pool.ip_addr == ip_addr) && > + (volume.storage_pool.export_path == export_path) > + found = true > + end > + end > + end > + > + unless found > + # Create a new transient NFS storage volume > + # This volume is *not* persisted. > + image_volume = StorageVolume.factory("NFS", :filename => filename) > + > + image_volume.storage_pool > + image_pool = StoragePool.factory(StoragePool::NFS) > + > + image_pool.ip_addr = ip_addr > + image_pool.export_path = export_path > + image_pool.storage_volumes << image_volume > + image_volume.storage_pool = image_pool > end > end > + > + # FIXME: I know this part is broken.. > + # > + # hrrm, who wrote this comment and why is it broken? - Ian Good question, I have no idea, I didn't write it. Darryl? > + volumes = [] > + volumes += db_vm.storage_volumes > + volumes << image_volume if image_volume > + storagedevs = connect_storage_pools(node, volumes) > + > + # FIXME: get rid of the hardcoded bridge > + xml = create_vm_xml(db_vm.description, db_vm.uuid, db_vm.memory_allocated, > + db_vm.memory_used, db_vm.num_vcpus_allocated, db_vm.boot_device, > + db_vm.vnic_mac_addr, "ovirtbr0", storagedevs) > + > + result = node.domainDefineXML(xml.to_s) > + raise "Error defining virtual machine: #{result.text}" unless result.status == 0 > + > + domain = @session.object(:object_id => result.domain) > + raise "Cannot find domain on host #{db_host.hostname}, cannot start virtual machine." unless domain > + > + result = domain.create > + if result.status != 0 > + domain.undefine > + raise "Error creating virtual machine: #{result.text}" > + end > + > + result = domain.getXMLDesc > + > + # Reget the db record or you can get 'dirty' errors. Out of curiosity, why? I'm not opposed to it, but this makes me think that there might be a problem lurking here. > + db_vm = find_vm(task, false) > + set_vm_vnc_port(db_vm, result.description) unless result.status != 0 > + > + # XXX: This information is not available via the libvirt interface. > + db_vm.memory_used = db_vm.memory_allocated > + db_vm.boot_device = Vm::BOOT_DEV_HD > + db_vm.host_id = db_host.id > + > + # We write the new state here even though dbomatic will set it soon anyway. > + # This is just to let the UI know that it's good to go right away and really > + # dbomatic will just write the same thing over top of it soon enough. > + db_vm.state = Vm::STATE_RUNNING Yep, good idea. > + db_vm.save! > + end > + > + def task_suspend_vm(task) > + db_vm = task.vm > + dom = @session.object(:class => 'domain', 'uuid' => db_vm.uuid) > + raise "Unable to locate VM to suspend" unless dom > + > + if dom.state == "shutdown" or dom.state == "shutoff" > + raise "Cannot suspend stopped domain" > + elsif dom.state == "paused" > + raise "Cannot suspend saved domain" > + end Actually, the original way I did this is kind of dumb. We should probably just do: if dom.state != "running" and dom.state != "blocked" raise "Cannot suspend domain in state #{dom.state}" end > + > + result = dom.suspend > + raise "Error suspending VM: #{result.text}" unless result.status == 0 > + > + db_vm.state = Vm::STATE_SUSPENDED > + db_vm.save! > end > - tasks.each do |task| > - # make sure we get our credentials up-front > - get_credentials > > - task.time_started = Time.now > - task.state = Task::STATE_RUNNING > - task.save! > + def task_resume_vm(task) > + db_vm = task.vm > + dom = @session.object(:class => 'domain', 'uuid' => db_vm.uuid) > + raise "Unable to locate VM to resume" unless dom > + > + if dom.state == "running" > + # the VM is already suspended; just return success > + return > + elsif dom.state == "shutoff" or dom.state == "shutdown" > + raise "Cannot resume stopped domain" > + elsif dom.state == "blocked" > + raise "Cannot resume suspended domain" > + end This logic is actually wrong (blocked == running for most practical purposes), but again we should just redo the logic as: if dom.state != "paused" raise "Cannot suspend domain in state #{dom.state}" end > + > + result = dom.resume > + raise "Error resuming VM: #{result.text}" unless result.status == 0 > + > + db_vm.state = Vm::STATE_RUNNING > + db_vm.save! > + end > + > + def task_save_vm(task) Put a comment here saying that this functionality is completely broken; that way ruby-lint (i.e. meyering) won't waste time cleaning this code up. Once we have a "save pool" defined, we can fix this whole thing up and remove the comment. > + db_vm = task.vm > + dom = @session.object(:class => 'domain', 'uuid' => db_vm.uuid) > + raise "Unable to locate VM to save" unless dom > + > + #XXX: I'm not checking states here. I want to see if libvirt gives back > + #decent error messages for different states. > + filename = "/tmp/#{dom.uuid}.save" > + puts "saving vm #{dom.name} to #{filename}" > + result = dom.save(filename) > + raise "Error saving VM: #{result.text}" unless result.status == 0 > + > + set_vm_state(db_vm, Vm::STATE_SAVED) > + end > + > + def task_restore_vm(task) Ditto. > + db_vm = task.vm > + dom = @session.object(:class => 'domain', 'uuid' => db_vm.uuid) > + raise "Unable to locate VM to restore" unless dom > + > + #XXX: I'm not checking states here. I want to see if libvirt gives back > + #decent error messages for different states. > + > + filename = "/tmp/#{dom.uuid}.save" > + puts "restoring vm #{dom.name} from #{filename}" > + result = dom.restore("/tmp/" + dom.uuid + ".save") > + raise "Error restoring VM: #{result.text}" unless result.status == 0 > + > + set_vm_state(db_vm, Vm::STATE_RUNNING) > + end > + > + def migrate(db_vm, dest = nil) > + > + vm = @session.object(:class => "domain", 'uuid' => db_vm.uuid) > + raise "Unable to find VM to migrate" unless vm > + src_node = @session.object(:object_id => vm.node) > + raise "Unable to find node that VM is on??" unless src_node > + > + puts "Migrating domain lookup complete, domain is #{vm}" > + > + case vm.state > + when "blocked" > + raise "Unable to migrate blocked VM." Again, blocked is basically the same as running, so you don't want to switch against it. > + when "paused" > + raise "Unable to migrate suspended VM." > + end And I'm actually not sure if this works or not. Quite possibly not, but I haven't tested so I'm not sure. > + > + vm_orig_state = db_vm.state > + set_vm_state(db_vm, Vm::STATE_MIGRATING) > > - state = Task::STATE_FINISHED > begin > - case task.action > - when VmTask::ACTION_CREATE_VM then create_vm(task) > - when VmTask::ACTION_SHUTDOWN_VM then shutdown_vm(task) > - when VmTask::ACTION_POWEROFF_VM then poweroff_vm(task) > - when VmTask::ACTION_START_VM then start_vm(task) > - when VmTask::ACTION_SUSPEND_VM then suspend_vm(task) > - when VmTask::ACTION_RESUME_VM then resume_vm(task) > - when VmTask::ACTION_SAVE_VM then save_vm(task) > - when VmTask::ACTION_RESTORE_VM then restore_vm(task) > - when VmTask::ACTION_UPDATE_STATE_VM then update_state_vm(task) > - when VmTask::ACTION_MIGRATE_VM then migrate_vm(task) > - when StorageTask::ACTION_REFRESH_POOL then refresh_pool(task) > - when StorageVolumeTask::ACTION_CREATE_VOLUME then create_volume(task) > - when StorageVolumeTask::ACTION_DELETE_VOLUME then delete_volume(task) > - when HostTask::ACTION_CLEAR_VMS then clear_vms_host(task) > + unless dest.nil? or dest.empty? > + if dest.to_i == db_vm.host_id > + raise "Cannot migrate from host " + src_node.hostname + " to itself!" > + end > + db_dst_host = find_host(dest.to_i) > else > - puts "unknown task " + task.action > - state = Task::STATE_FAILED > - task.message = "Unknown task type" > + db_dst_host = find_capable_host(db_vm) > end > + > + dest_node = @session.object(:class => 'node', 'hostname' => db_dst_host.hostname) > + raise "Unable to find host #{db_dst_host.hostname} to migrate to." unless dest_node > + > + volumes = [] > + volumes += db_vm.storage_volumes > + connect_storage_pools(dest_node, volumes) > + > + # Sadly migrate with qpid is broken because it requires a connection between > + # both nodes and currently that can't happen securely. For now we do it > + # the old fashioned way.. > + dst_uri = "qemu+tcp://#{dest_node.hostname}/system" > + src_uri = "qemu+tcp://#{src_node.hostname}/system" You can remove these above two; I don't think they are needed for anything, and it might be confusing for future readers. > + src_conn = Libvirt::open("qemu+tcp://" + src_node.hostname + "/system") > + dst_conn = Libvirt::open("qemu+tcp://" + dest_node.hostname + "/system") > + dom = src_conn.lookup_domain_by_uuid(vm.uuid) > + dom.migrate(dst_conn, Libvirt::Domain::MIGRATE_LIVE) > + src_conn.close > + dst_conn.close > + > + # undefine can fail, for instance, if we live migrated from A -> B, and > + # then we are shutting down the VM on B (because it only has "transient" > + # XML). Therefore, just ignore undefine errors so we do the rest > + # FIXME: we really should have a marker in the database somehow so that > + # we can tell if this domain was migrated; that way, we can tell the > + # difference between a real undefine failure and one because of migration > + result = vm.undefine > + puts "Error undefining old vm after migrate: #{result.text}" unless result.status == 0 Again, how are you handling the above comment with this code? > + > + # See if we can take down storage pools on the src host. > + teardown_storage_pools(src_node) > rescue => ex > - puts "Task action processing failed: #{ex.class}: #{ex.message}" > - puts ex.backtrace > - state = Task::STATE_FAILED > - task.message = ex.message > - end > - > - task.state = state > - task.time_ended = Time.now > - task.save! > - puts "done" > - end > - > - # FIXME: here, we clean up "orphaned" tasks. These are tasks that we had > - # to orphan (set task_target to nil) because we were deleting the object they > - # depended on. > - Task.find(:all, :conditions => [ "task_target_id IS NULL and task_target_type IS NULL" ]).each do |task| > - task.destroy > - end > - > - # we could destroy credentials, but another process might be using them (in > - # particular, host-browser). Just leave them around, it shouldn't hurt > - > - STDOUT.flush > - sleep sleeptime > + puts "Error: #{ex}" > + set_vm_state(db_vm, vm_orig_state) > + raise ex > + end > + > + db_vm.state = Vm::STATE_RUNNING > + db_vm.host_id = db_dst_host.id > + db_vm.save! > + end > + > + def task_migrate_vm(task) > + puts "migrate_vm" > + > + # here, we are given an id for a VM to migrate; we have to lookup which > + # physical host it is running on > + vm = find_vm(task) > + migrate(vm, task.args) > + end > + > + def storage_find_suitable_host(hardware_pool) > + # find all of the hosts in the same pool as the storage > + hardware_pool.hosts.each do |host| > + puts "storage_find_suitable_host: host #{host.hostname} uuid #{host.uuid}" > + node = @session.object(:class => 'node', 'hostname' => host.hostname) This isn't right; you need to use similar logic to what is in "find_capable_host" to make sure that you don't pick a host that has been disabled, etc. > + return node if node > + end > + > + raise "Could not find a host within this storage pool to scan the storage server." > + end > + > + def add_volumes_to_db(db_pool, libvirt_pool, owner = nil, group = nil, mode = nil) > + # FIXME: this is currently broken if you do something like: > + # 1. Add an iscsi pool with 3 volumes (lun-1, lun-2, lun-3) > + # 2. Scan it in > + # 3. Remove lun-3 from the pool > + # 4. Re-scan it > + # What will happen is that you will still have lun-3 available in the > + # database, even though it's not available in the pool anymore. It's a > + # little tricky, though; we have to make sure that we don't pull the > + # database entry out from underneath a possibly running VM (or do we?) > + volumes = @session.objects(:class => 'volume', 'storagePool' => libvirt_pool.remote_pool.object_id) > + volumes.each do |volume| > + storage_volume = StorageVolume.factory(db_pool.get_type_label) > + > + # NOTE: it is safe (and, in fact, necessary) to use > + # #{storage_volume.volume_name} here without sanitizing it. This is > + # because this is *not* based on user modifiable data, but rather, on an > + # internal implementation detail > + existing_vol = StorageVolume.find(:first, :conditions => > + ["storage_pool_id = ? AND #{storage_volume.volume_name} = ?", > + db_pool.id, volume.name]) > + > + # in this case, this path already exists in the database; just skip > + next if existing_vol > + > + storage_volume = StorageVolume.factory(db_pool.get_type_label) > + storage_volume.path = volume.path > + storage_volume.size = volume.capacity / 1024 > + storage_volume.storage_pool_id = db_pool.id > + storage_volume.write_attribute(storage_volume.volume_name, volume.name) > + storage_volume.lv_owner_perms = owner > + storage_volume.lv_group_perms = group > + storage_volume.lv_mode_perms = mode > + storage_volume.state = StorageVolume::STATE_AVAILABLE > + puts "saving storage volume to db." > + storage_volume.save! > + end > + end > + > + # The words "pool" and "volume" are ridiculously overloaded in our context. > + # Therefore, the refresh_pool method adopts this convention: > + # db_pool_phys: The underlying physical storage pool, as it is represented in > + # the database > + # phys_libvirt_pool: The underlying physical storage, as it is represented in > + # libvirt > + # db_lvm_pool: The logical storage pool (if it exists), as it is represented > + # in the database > + # lvm_libvirt_pool: The logical storage pool (if it exists), as it is > + # represented in the database > + > + def task_refresh_pool(task) > + puts "refresh_pool" > + > + db_pool_phys = task.storage_pool > + raise "Could not find storage pool" unless db_pool_phys > + > + node = storage_find_suitable_host(db_pool_phys.hardware_pool) > + > + # FIXME: We may want to scan through all the LVM volumes available > + # and just update the database with allocation information. > + # However afaict right now libvirt provides no way for us to know > + # where an LVM pool/volume sits in terms of its physical pool/volume > + # so we're kinda screwed for now for updating the database. This is true, except that this has to work. This gets into the whole LVM scanning thing, which I'll cover in my other "LVM Fun" response to you. > + # > + # Ian > + begin > + phys_libvirt_pool = LibvirtPool.factory(db_pool_phys) > + phys_libvirt_pool.connect(@session, node) > + > + begin > + # OK, the pool is all set. Add in all of the volumes > + add_volumes_to_db(db_pool_phys, phys_libvirt_pool) > + > + db_pool_phys.state = StoragePool::STATE_AVAILABLE > + db_pool_phys.save! > + end > + ensure > + phys_libvirt_pool.shutdown > + end > + end > + > + def task_create_volume(task) > + puts "create_volume" > + > + db_volume = task.storage_volume > + raise "Could not find storage volume to create" unless db_volume > + > + db_pool = db_volume.storage_pool > + raise "Could not find storage pool" unless db_pool > + > + node = storage_find_suitable_host(db_pool.hardware_pool) > + > + begin > + if db_volume[:type] == "LvmStorageVolume" > + phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(db_volume) > + phys_libvirt_pool.connect(@session, node) > + end > + > + begin > + libvirt_pool = LibvirtPool.factory(db_pool) > + > + begin > + libvirt_pool.connect(@session, node) > + volume_id = libvirt_pool.create_vol(*db_volume.volume_create_params) > + volume = @session.object(:object_id => volume_id) > + raise "Unable to find newly created volume" unless volume > + > + puts " volume:" > + for (key, val) in volume.properties > + puts " property: #{key}, #{val}" > + end > + > + # FIXME: Should have this too I think.. > + #db_volume.key = volume.key > + db_volume.path = volume.path > + db_volume.state = StorageVolume::STATE_AVAILABLE > + db_volume.save! > + > + db_pool.state = StoragePool::STATE_AVAILABLE > + db_pool.save! > + ensure > + libvirt_pool.shutdown > + end > + ensure > + if db_volume[:type] == "LvmStorageVolume" > + phys_libvirt_pool.shutdown > + end > + end > + end > + end > + > + def task_delete_volume(task) > + puts "delete_volume" > + > + db_volume = task.storage_volume > + raise "Could not find storage volume to create" unless db_volume > + > + db_pool = db_volume.storage_pool > + raise "Could not find storage pool" unless db_pool > + > + node = storage_find_suitable_host(db_pool.hardware_pool) > + > + begin > + if db_volume[:type] == "LvmStorageVolume" > + phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(db_volume) > + phys_libvirt_pool.connect(@session, node) > + puts "connected to lvm pool.." > + end > + > + begin > + libvirt_pool = LibvirtPool.factory(db_pool) > + libvirt_pool.connect(@session, node) > + > + begin > + volume = @session.object(:class => 'volume', > + 'storagePool' => libvirt_pool.remote_pool.object_id, > + 'path' => db_volume.path) > + puts "Unable to find volume to delete" unless volume > + > + # FIXME: we actually probably want to zero out the whole volume here, so > + # we aren't potentially leaking data from one user to another. There > + # are two problems, though: > + # 1) I'm not sure how I would go about zero'ing the data on a remote > + # machine, since there is no "libvirt_write_data" call > + # 2) This could potentially take quite a while, so we want to spawn > + # off another thread to do it > + result = volume.delete > + raise "Error deleting volume: #{result.text}" unless result.status == 0 > + > + # Note: we have to nil out the task_target because when we delete the > + # volume object, that also deletes all dependent tasks (including this > + # one), which leads to accessing stale tasks. Orphan the task, then > + # delete the object; we can clean up orphans later (or not, depending > + # on the audit policy) > + task.task_target = nil > + task.save! > + > + db_volume.destroy > + ensure > + libvirt_pool.shutdown > + end > + ensure > + if db_volume[:type] == "LvmStorageVolume" > + phys_libvirt_pool.shutdown > + end > + end > + end > + end > + > + def task_clear_vms_host(task) > + src_host = task.host > + > + src_host.vms.each do |vm| > + migrate(vm) > + end > + end > + > + def mainloop() > + loop do > + tasks = Array.new > + begin > + tasks = Task.find(:all, :conditions => [ "state = ?", Task::STATE_QUEUED ]) > + rescue => ex > + puts "1 #{ex.class}: #{ex.message}" > + if Task.connected? > + begin > + ActiveRecord::Base.connection.reconnect! > + rescue => norecon > + puts "2 #{norecon.class}: #{norecon.message}" > + end > + else > + begin > + database_connect > + rescue => ex > + puts "3 #{ex.class}: #{ex.message}" > + end > + end > + end > + > + tasks.each do |task| > + # make sure we get our credentials up-front > + get_credentials > + > + task.time_started = Time.now > + > + state = Task::STATE_FINISHED > + begin > + case task.action > + when VmTask::ACTION_CREATE_VM then task_create_vm(task) > + when VmTask::ACTION_SHUTDOWN_VM then task_shutdown_or_destroy_vm(task, :shutdown) > + when VmTask::ACTION_POWEROFF_VM then task_shutdown_or_destroy_vm(task, :destroy) > + when VmTask::ACTION_START_VM then task_start_vm(task) > + when VmTask::ACTION_SUSPEND_VM then task_suspend_vm(task) > + when VmTask::ACTION_RESUME_VM then task_resume_vm(task) > + when VmTask::ACTION_SAVE_VM then task_save_vm(task) > + when VmTask::ACTION_RESTORE_VM then task_restore_vm(task) > + when VmTask::ACTION_MIGRATE_VM then task_migrate_vm(task) > + when StorageTask::ACTION_REFRESH_POOL then task_refresh_pool(task) > + when StorageVolumeTask::ACTION_CREATE_VOLUME then task_create_volume(task) > + when StorageVolumeTask::ACTION_DELETE_VOLUME then task_delete_volume(task) > + when HostTask::ACTION_CLEAR_VMS then task_clear_vms_host(task) > + else > + puts "unknown task " + task.action > + state = Task::STATE_FAILED > + task.message = "Unknown task type" > + end > + rescue => ex > + puts "Task action processing failed: #{ex.class}: #{ex.message}" > + puts ex.backtrace > + state = Task::STATE_FAILED > + task.message = ex.message > + end > + > + task.state = state > + task.time_ended = Time.now > + task.save! > + puts "done" > + end > + # FIXME: here, we clean up "orphaned" tasks. These are tasks that we had > + # to orphan (set task_target to nil) because we were deleting the object they > + # depended on. > + Task.find(:all, :conditions => [ "task_target_id IS NULL and task_target_type IS NULL" ]).each do |task| > + task.destroy > + end > + sleep(1) You are ignoring the "sleeptime" command-line option here. It's fine to default it to 1, but you should let the user override it on the command-line. > + end > + end > end > + > +taskomatic = TaskOmatic.new() > +taskomatic.mainloop() > + > diff --git a/src/task-omatic/utils.rb b/src/task-omatic/utils.rb > deleted file mode 100644 > index e3005ed..0000000 > --- a/src/task-omatic/utils.rb > +++ /dev/null > @@ -1,221 +0,0 @@ > -require 'rexml/document' > -include REXML > - > -def String.random_alphanumeric(size=16) > - s = "" > - size.times { s << (i = Kernel.rand(62); i += ((i < 10) ? 48 : ((i < 36) ? 55 : 61 ))).chr } > - s > -end > - > -def all_storage_pools(conn) > - all_pools = conn.list_defined_storage_pools > - all_pools.concat(conn.list_storage_pools) > - return all_pools > -end > - > -def get_libvirt_lvm_pool_from_volume(db_volume) > - phys_volume = StorageVolume.find(:first, :conditions => > - [ "lvm_pool_id = ?", db_volume.storage_pool_id]) > - > - return LibvirtPool.factory(phys_volume.storage_pool) > -end > - > -class LibvirtPool > - def initialize(type, name = nil) > - @remote_pool = nil > - @build_on_start = true > - @remote_pool_defined = false > - @remote_pool_started = false > - > - if name == nil > - @name = type + "-" + String.random_alphanumeric > - else > - @name = name > - end > - > - @xml = Document.new > - @xml.add_element("pool", {"type" => type}) > - > - @xml.root.add_element("name").add_text(@name) > - > - @xml.root.add_element("source") > - > - @xml.root.add_element("target") > - @xml.root.elements["target"].add_element("path") > - end > - > - def connect(conn) > - all_storage_pools(conn).each do |remote_pool_name| > - tmppool = conn.lookup_storage_pool_by_name(remote_pool_name) > - > - if self.xmlequal?(Document.new(tmppool.xml_desc).root) > - @remote_pool = tmppool > - break > - end > - end > - > - if @remote_pool == nil > - @remote_pool = conn.define_storage_pool_xml(@xml.to_s) > - # we need this because we don't necessarily want to "build" LVM pools, > - # which might destroy existing data > - if @build_on_start > - @remote_pool.build > - end > - @remote_pool_defined = true > - end > - > - if @remote_pool.info.state == Libvirt::StoragePool::INACTIVE > - # only try to start the pool if it is currently inactive; in all other > - # states, assume it is already running > - @remote_pool.create > - @remote_pool_started = true > - end > - end > - > - def list_volumes > - return @remote_pool.list_volumes > - end > - > - def lookup_vol_by_path(dev) > - return @remote_pool.lookup_volume_by_path(dev) > - end > - > - def lookup_vol_by_name(name) > - return @remote_pool.lookup_volume_by_name(name) > - end > - > - def create_vol(type, name, size, owner, group, mode) > - @vol_xml = Document.new > - @vol_xml.add_element("volume", {"type" => type}) > - @vol_xml.root.add_element("name").add_text(name) > - @vol_xml.root.add_element("capacity", {"unit" => "K"}).add_text(size.to_s) > - @vol_xml.root.add_element("target") > - @vol_xml.root.elements["target"].add_element("permissions") > - @vol_xml.root.elements["target"].elements["permissions"].add_element("owner").add_text(owner) > - @vol_xml.root.elements["target"].elements["permissions"].add_element("group").add_text(group) > - @vol_xml.root.elements["target"].elements["permissions"].add_element("mode").add_text(mode) > - end > - > - def shutdown > - if @remote_pool_started > - @remote_pool.destroy > - end > - if @remote_pool_defined > - @remote_pool.undefine > - end > - end > - > - def xmlequal?(docroot) > - return false > - end > - > - def self.factory(pool) > - if pool[:type] == "IscsiStoragePool" > - return IscsiLibvirtPool.new(pool.ip_addr, pool[:target]) > - elsif pool[:type] == "NfsStoragePool" > - return NFSLibvirtPool.new(pool.ip_addr, pool.export_path) > - elsif pool[:type] == "LvmStoragePool" > - # OK, if this is LVM storage, there are two cases we need to care about: > - # 1) this is a LUN with LVM already on it. In this case, all we need to > - # do is to create a new LV (== libvirt volume), and be done with it > - # 2) this LUN is blank, so there is no LVM on it already. In this > - # case, we need to pvcreate, vgcreate first (== libvirt pool build), > - # and *then* create the new LV (== libvirt volume) on top of that. > - # > - # We can tell the difference between an LVM Pool that exists and one > - # that needs to be created based on the value of the pool.state; > - # if it is PENDING_SETUP, we need to create it first > - phys_volume = StorageVolume.find(:first, :conditions => > - [ "lvm_pool_id = ?", pool.id]) > - > - return LVMLibvirtPool.new(pool.vg_name, phys_volume.path, > - pool.state == StoragePool::STATE_PENDING_SETUP) > - else > - raise "Unknown storage pool type " + pool[:type].to_s > - end > - end > -end > - > -class IscsiLibvirtPool < LibvirtPool > - def initialize(ip_addr, target) > - super('iscsi') > - > - @type = 'iscsi' > - @ipaddr = ip_addr > - @target = target > - > - @xml.root.elements["source"].add_element("host", {"name" => @ipaddr}) > - @xml.root.elements["source"].add_element("device", {"path" => @target}) > - > - @xml.root.elements["target"].elements["path"].text = "/dev/disk/by-id" > - end > - > - def xmlequal?(docroot) > - return (docroot.attributes['type'] == @type and > - docroot.elements['source'].elements['host'].attributes['name'] == @ipaddr and > - docroot.elements['source'].elements['device'].attributes['path'] == @target) > - end > -end > - > -class NFSLibvirtPool < LibvirtPool > - def initialize(ip_addr, export_path) > - super('netfs') > - > - @type = 'netfs' > - @host = ip_addr > - @remote_path = export_path > - @name = String.random_alphanumeric > - > - @xml.root.elements["source"].add_element("host", {"name" => @host}) > - @xml.root.elements["source"].add_element("dir", {"path" => @remote_path}) > - @xml.root.elements["source"].add_element("format", {"type" => "nfs"}) > - > - @xml.root.elements["target"].elements["path"].text = "/mnt/" + @name > - end > - > - def create_vol(name, size, owner, group, mode) > - # FIXME: this can actually take some time to complete (since we aren't > - # doing sparse allocations at the moment). During that time, whichever > - # libvirtd we chose to use is completely hung up. The solution is 3-fold: > - # 1. Allow sparse allocations in the WUI front-end > - # 2. Make libvirtd multi-threaded > - # 3. Make taskomatic multi-threaded > - super("netfs", name, size, owner, group, mode) > - > - # FIXME: we have to add the format as raw here because of a bug in libvirt; > - # if you specify a volume with no format, it will crash libvirtd > - @vol_xml.root.elements["target"].add_element("format", {"type" => "raw"}) > - @remote_pool.create_vol_xml(@vol_xml.to_s) > - end > - > - def xmlequal?(docroot) > - return (docroot.attributes['type'] == @type and > - docroot.elements['source'].elements['host'].attributes['name'] == @host and > - docroot.elements['source'].elements['dir'].attributes['path'] == @remote_path) > - end > -end > - > -class LVMLibvirtPool < LibvirtPool > - def initialize(vg_name, device, build_on_start) > - super('logical', vg_name) > - > - @type = 'logical' > - @build_on_start = build_on_start > - > - @xml.root.elements["source"].add_element("name").add_text(@name) > - @xml.root.elements["source"].add_element("device", {"path" => device}) > - > - @xml.root.elements["target"].elements["path"].text = "/dev/" + @name > - end > - > - def create_vol(name, size, owner, group, mode) > - super("logical", name, size, owner, group, mode) > - @remote_pool.create_vol_xml(@vol_xml.to_s) > - end > - > - def xmlequal?(docroot) > - return (docroot.attributes['type'] == @type and > - docroot.elements['name'].text == @name and > - docroot.elements['source'].elements['name'] == @name) > - end > -end General comments: 1. Probably replace all of the XXX with FIXME, or vice-versa, so the whole thing is consistent. That way people looking for things to fix can just look for one string (I prefer FIXME, but it's up to you). 2. Try to make everything fit 80 columns again, just for ease of reading. 3. Despite what I said about it when we talked earlier, I find this kind of hard to read being all in one file. The problem is that it is not clear which methods are top-level methods (i.e. task_start_vm) and which one are helper methods from a quick glance. I think I would much prefer to have the helper methods in a separate file and/or separate class, but I'm not sure how difficult that would be. Thoughts? -- Chris Lalancette From clalance at redhat.com Tue Jan 6 13:46:29 2009 From: clalance at redhat.com (Chris Lalancette) Date: Tue, 06 Jan 2009 14:46:29 +0100 Subject: [Ovirt-devel] LVM Fun In-Reply-To: <20081223131327.5d1c675f@tp.mains.net> References: <20081219145911.1d364c26@tp.mains.net> <49512629.60102@redhat.com> <20081223131327.5d1c675f@tp.mains.net> Message-ID: <496360B5.1060709@redhat.com> Ian Main wrote: >>> Code from libvirt-ruby: >>> >>> /* * Call >>> +virStorageVolLookupByPath+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolLookupByPath] >>> */ VALUE libvirt_pool_lookup_vol_by_path(VALUE p, VALUE path) { >>> virStorageVolPtr vol; >>> >>> // FIXME: Why does this take a connection, not a pool ? vol = >>> virStorageVolLookupByPath(conn(p), StringValueCStr(path)); _E(vol == NULL, >>> create_error(e_RetrieveError, "virStorageVolLookupByPath", "", conn(p))); >>> >>> return vol_new(vol, conn_attr(p)); } >>> >>> As you can see in the FIXME comment and the usage of >>> virStorageVolLookupByPath(), it's not associated with a specific pool. > > This in turn opens up the possibility that another storage pool may be active > on the host we select to do the scanning, which would mean we'd pick up LVM volumes > from that other pool as well. From what I can tell, right now the only way to fill > the LVM volume/pool information in the DB correctly is by keeping track of it > during creation which defeats the purpose of the scan/refresh. Hence the removal. > > If I missed something (which is possible), let me know, but from what I can tell > this is the case. While I've done some playing with the API and have shown myself > that this is the case, it might be worth setting up a test case with two pools with > LVM volumes in each and see if it sorts them out right. I see what you mean about pool.lookup_vol_by_path() not doing what I expect. However, I'm not sure that is actually an issue. But let me go back and start at the beginning here. Your assertion that we should "rely on the database" for information just can't work. The database doesn't *have* the information at this point; it is depending on us (i.e. taskomatic) to get the information about whether there are existing LV's on the device or not. The database can't know this a-priori, so we have to scan it to find out. That's why this piece of functionality has to work; if you did something like: a) add an ISCSI pool b) create a few LV's on the LUN's from that ISCSI pool c) delete the ISCSI pool from ovirt d) add the ISCSI pool back to ovirt our only choice without LVM scanning would be to blow away the data that's already on the LUNs, which isn't usually desirable. So. That's why we want to do this. Next to define what exactly we are trying to do with the code, and then see if the code accomplishes it. At pool_refresh time, what we are essentially trying to do is get a list of all of the volumes available on the pool we are given. For NFS, this is easy; basically when we are adding a new NFS storage pool, we want to add all of the existing files on the share as NFS storage volumes. For iSCSI it's a lot more complicated. We want to scan all existing iSCSI LUNs, add them to the database as iSCSI volumes, and then additionally scan each LUN to see if it has LVM logical volumes already present. If so, we also want to add that volume group to the database as a LVM storage pool, and then each of the logical volumes in that volume group gets added as an LVM storage volume. Make sense? Now that we have that down, we can see what the current taskomatic code does for ISCSI. Basically, it starts by scanning the pool and adding all volumes (i.e. raw LUNS) to the database: # OK, the pool is all set. Add in all of the volumes add_volumes_to_db(phys_db_pool, phys_libvirt_pool) Fine. Next, it discovers all logical pool sources: # OK, now we've scanned the underlying hardware pool and added the # volumes. Next we scan for pre-existing LVM volumes logical_xml = conn.discover_storage_pool_sources("logical") Then it iterates through each logical pool source. This is where things get tricky. Each logical pool source equates to a volume group available. Basically, we iterate through each logical pool source, and see if that pool source is already in the database. If it is, we basically just rescan all of the LV's attached. If it isn't, we create a new logical pool in the database, then scan all of the LV's attached. I guess the key point here is that yes, we may add stuff to the database that wasn't *this* particular pool, but it *doesn't matter*. The only way that lookup_vol_by_path() will return a volume is if it is a libvirt defined volume, and the only way a libvirt defined volume can get started on an ovirt node is via ovirt. That just means that yes, we may unnecessarily rescan volumes that are already there, but we are always guaranteed to add the logical volumes (if they exist) on the iSCSI LUN that we just added. Does this make sense to you, or am I still talking crazy? The above still leaves this weird piece of code: begin source.elements.each("device") do |device| byid_device = phys_libvirt_pool.lookup_vol_by_path(device.attributes["path"]).path end rescue # If matching any of the sections in the LVM XML fails # against the storage pool, then it is likely that this is a storage # pool not associated with the one we connected above. Go on # FIXME: it would be nicer to catch the right exception here, and # fail on other exceptions puts "One of the logical volumes in #{vgname} is not part of the pool of type #{phys_db_pool[:type]} that we are scanning; ignore the previous error!" next end Which seems completely unnecessary given my above explanation, but is actually there to handle a corner case. Namely, it handles the case where you have an LVM partition defined already on the host, but it is *not* managed by libvirt. Because of the way storage pool discovery is done, it will return entries for *all* logical volumes on the host, even those that aren't managed by libvirt. However, lookup_vol_by_path() will only return a valid entry for a volume managed by libvirt. So the above basically ensures that any logical pools that are on the host, but not managed by libvirt, are skipped. Please go through the above logic, and see if it makes sense to you. We can talk about it more on IRC if there are still confusing things, or if I am completely off-base here. -- Chris Lalancette From dpierce at redhat.com Tue Jan 6 14:08:36 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Tue, 6 Jan 2009 09:08:36 -0500 Subject: [Ovirt-devel] [PATCH node] Adds a check for a partition table before installing. In-Reply-To: <2be7262f0901051445o28a1ae2by82e56969ea19d0b2@mail.gmail.com> References: <1231187497-8383-1-git-send-email-dpierce@redhat.com> <2be7262f0901051445o28a1ae2by82e56969ea19d0b2@mail.gmail.com> Message-ID: <20090106140836.GD3955@mcpierce-laptop.rdu.redhat.com> On Mon, Jan 05, 2009 at 11:45:20PM +0100, Alan Pevec wrote: > On Mon, Jan 5, 2009 at 9:31 PM, Darryl L. Pierce wrote: > > > If no partition table is found then an error message is show to the user > > and the system will not continue nor reboot. > > > > ACK > > + printf "Please configure $disk before attempting to install the node > > image.\n" > > > > to help the confused user, print the option name "Disk Partitioning" or even > just run ovirt-config-storage here? I'll change the message to the former. But in future it would make more sense, as you suggest, to run o-c-storage and then have o-c-boot rerun its entry point. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From jboggs at redhat.com Tue Jan 6 15:20:48 2009 From: jboggs at redhat.com (Joey Boggs) Date: Tue, 06 Jan 2009 10:20:48 -0500 Subject: [Ovirt-devel] [PATCH server] Add the installer files as a subpackage of the server package In-Reply-To: <1231185148-2729-1-git-send-email-bkearney@redhat.com> References: <1231185148-2729-1-git-send-email-bkearney@redhat.com> Message-ID: <496376D0.8070806@redhat.com> when testing the patches, all the should be executable files for me are set to 644 rather than 755 so I can't run ovirt-installer without permission issues. It's specified in the patches to create them as 755 though anyone seen this before? Bryan Kearney wrote: > --- > Makefile.am | 3 +- > installer/bin/ovirt-installer | 273 ++++++++++++++++++++ > installer/modules/ovirt/files/collectd.conf | 23 ++ > installer/modules/ovirt/files/dns_entries.sh | 2 + > installer/modules/ovirt/files/modules.conf | 96 +++++++ > installer/modules/ovirt/files/qpidd.conf | 4 + > installer/modules/ovirt/manifests/cobbler.pp | 126 +++++++++ > installer/modules/ovirt/manifests/dhcp.pp | 34 +++ > installer/modules/ovirt/manifests/dns.pp | 99 +++++++ > installer/modules/ovirt/manifests/freeipa.pp | 103 ++++++++ > installer/modules/ovirt/manifests/init.pp | 9 + > installer/modules/ovirt/manifests/ovirt.pp | 154 +++++++++++ > installer/modules/ovirt/manifests/postgres.pp | 114 ++++++++ > installer/modules/ovirt/manifests/tftp.pp | 31 +++ > installer/modules/ovirt/templates/digest_line.erb | 4 + > .../modules/ovirt/templates/ovirt-dhcp.conf.erb | 9 + > .../modules/ovirt/templates/ovirt-dns.conf.erb | 7 + > .../modules/ovirt/templates/ovirt-tftp.conf.erb | 3 + > ovirt-server.spec.in | 23 ++- > 19 files changed, 1115 insertions(+), 2 deletions(-) > create mode 100755 installer/bin/ovirt-installer > create mode 100644 installer/modules/ovirt/files/collectd.conf > create mode 100755 installer/modules/ovirt/files/dns_entries.sh > create mode 100644 installer/modules/ovirt/files/modules.conf > create mode 100644 installer/modules/ovirt/files/qpidd.conf > create mode 100644 installer/modules/ovirt/manifests/cobbler.pp > create mode 100644 installer/modules/ovirt/manifests/dhcp.pp > create mode 100644 installer/modules/ovirt/manifests/dns.pp > create mode 100644 installer/modules/ovirt/manifests/freeipa.pp > create mode 100644 installer/modules/ovirt/manifests/init.pp > create mode 100644 installer/modules/ovirt/manifests/ovirt.pp > create mode 100644 installer/modules/ovirt/manifests/postgres.pp > create mode 100644 installer/modules/ovirt/manifests/tftp.pp > create mode 100644 installer/modules/ovirt/templates/digest_line.erb > create mode 100644 installer/modules/ovirt/templates/ovirt-dhcp.conf.erb > create mode 100644 installer/modules/ovirt/templates/ovirt-dns.conf.erb > create mode 100644 installer/modules/ovirt/templates/ovirt-tftp.conf.erb > > diff --git a/Makefile.am b/Makefile.am > index e11e636..f115c8f 100644 > --- a/Makefile.am > +++ b/Makefile.am > @@ -23,7 +23,8 @@ EXTRA_DIST = \ > ovirt-server.spec.in \ > scripts \ > conf \ > - src > + src \ > + installer > > DISTCLEANFILES = $(PACKAGE)-$(VERSION).tar.gz > > diff --git a/installer/bin/ovirt-installer b/installer/bin/ovirt-installer > new file mode 100755 > index 0000000..84604ef > --- /dev/null > +++ b/installer/bin/ovirt-installer > @@ -0,0 +1,273 @@ > +#!/usr/bin/ruby > +#-- > +## Copyright (C) 2008 Red Hat Inc. > +## > +## This library is free software; you can redistribute it and/or > +## modify it under the terms of the GNU Lesser General Public > +## License as published by the Free Software Foundation; either > +## version 2.1 of the License, or (at your option) any later version. > +## > +## This library 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 > +## Lesser General Public License for more details. > +## > +## You should have received a copy of the GNU Lesser General Public > +## License along with this library; if not, write to the Free Software > +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > +## > +## Author: Joey Boggs > +##-- > +## oVirt Installation Script > + > +require 'socket' > +require 'fileutils' > + > +if File.exist?("/usr/sbin/sestatus") > +sestatus = `/usr/sbin/sestatus` > +if sestatus !~ /(Current mode: permissive|Current mode: disabled|SELinux status: disabled|SELinux status: permissive)/ > +puts "SELinux enabled, please disable or set in permissive mode permanently by editing" > +puts "/etc/selinux/config and rebooting" > +exit > +end > +end > + > +FileUtils.mkdir_p("/usr/share/ace/appliances/ovirt") > +config_file = File.new("/usr/share/ace/appliances/ovirt/ovirt.pp", "w") > +config_file.write "import 'ovirt'\n" > +config_file.write "import 'firewall'\n\n" > +config_file.write "firewall::setup{'setup': status => 'disabled'}\n\n" > + > +mgmt_dev = "" > +prov_dev = "" > + > +dev_ct = 0 > +net_devs = `hal-find-by-capability --capability net` > +net_devs.each_line{ |dev| > +dev_ct = dev_ct + 1 > +} > + > +if dev_ct == 0 > +puts "Unable to install without a network interface" > +exit > + > +else > +puts "" > +get_net_devs = `hal-find-by-capability --capability net` > +puts "Below are the detected networking devices\n\n" > +puts "mac address interface ip address" > +net_devs.each_line{ |dev| > +dev = dev.chomp > +interface = `hal-get-property --udi #{dev} --key net.interface` > +mac = `hal-get-property --udi #{dev} --key net.address` > +ip = `ifconfig #{interface}` > +ipaddr = ip.scan(/\s*inet addr:([\d.]+)/) > +puts mac.chop + " : " + interface.chop + " : " + ipaddr.to_s if interface.chop != "lo" > +} > +end > + > +if dev_ct > 1 > +puts "\nDo you want separate management and provisioning networks? (y/n)" > +sep_networks = gets.chomp > +while sep_networks != "y" and sep_networks != "n" > +puts "Invalid choice" > +puts "Do you want separate management and provisioning networks? (y/n)" > +sep_networks = gets.chomp > +end > + > +if sep_networks == "y" > +while mgmt_dev == "" > +puts "Input your management interface (example: eth0)" > +mgmt_dev = gets.chomp > +end > + > +while prov_dev == "" > +puts "Input your provisioning interface, this may also be your management interface (example: eth1)" > +prov_dev = gets.chomp > +end > + > +elsif sep_networks == "n" > +while mgmt_dev == "" > +puts "Input your management/provisioning interface (example: eth1)" > +mgmt_dev = gets.chomp > +prov_dev = mgmt_dev > +end > +end > + > +elsif dev_ct == 1 > +while mgmt_dev == "" > +puts "\nOnly one networking device detected" > +puts "Input your management/provisioning interface (example: eth1)" > +mgmt_dev = gets.chomp > +prov_dev = mgmt_dev > +puts "Need Management interface" > +end > +end > + > +puts "Enter the hostname of the oVirt management server (example: management.example.com)" > +ovirt_host = gets.chomp > +ipa_host = ovirt_host > + > +puts "\nUse this system's dns servers (y/n)" > +File.open('/etc/resolv.conf').each_line{ |line| > + line = line.chomp > +puts line if line =~ /nameserver/ and line !~ /nameserver 127.0.0.1/ > +} > +dns_servers = gets.chomp > + > +while dns_servers != "y" and dns_servers != "n" > +puts "Invalid choice" > +dns_servers = gets.chomp > +end > + > +mgmt_ip = `ifconfig #{mgmt_dev}` > +mgmt_ipaddr= mgmt_ip.scan(/\s*inet addr:([\d.]+)/) > +prov_ip = `ifconfig #{prov_dev}` > +prov_ipaddr= prov_ip.scan(/\s*inet addr:([\d.]+)/) > + > +config_file.write "# dns configuration\n" > +config_file.write "$mgmt_ipaddr = '#{mgmt_ipaddr}'\n" > +config_file.write "$prov_ipaddr = '#{prov_ipaddr}'\n" > +config_file.write "$ovirt_host = '#{ovirt_host}'\n" > +config_file.write "$ipa_host = '#{ipa_host}'\n\n" > + > +if dns_servers == "n" > +config_file.write "dns::bundled{setup: mgmt_ipaddr=> $mgmt_ipaddr, prov_ipaddr=> $prov_ipaddr, mgmt_dev => '#{mgmt_dev}', prov_dev => '#{prov_dev}'}\n\n" > +end > + > +if dns_servers == "y" > +config_file.write "dns::remote{setup: mgmt_ipaddr=> $mgmt_ipaddr, prov_ipaddr=> $prov_ipaddr, mgmt_dev => '#{mgmt_dev}', prov_dev => '#{prov_dev}'}\n\n" > +host_lookup = Socket.getaddrinfo(ipa_host,nil) > +hostip = host_lookup[1][3] > +if hostip.to_s != mgmt_ipaddr.to_s > +puts "Reverse dns lookup for #{ipa_host} failed, exiting" > +exit > +end > +end > + > +puts "Does you provisioning network already have dhcp? (y/n)" > +dhcp_setup = gets.chomp > +while dhcp_setup != "y" and dhcp_setup != "n" > +puts "Invalid choice" > +dhcp_setup = gets.chomp > +end > + > +if dhcp_setup == "n" > + > +puts "DHCP Configuration\n" > +config_file.write "# dhcp configuration\n" > +dhcp_interface = prov_dev > +config_file.write "$dhcp_interface = '#{dhcp_interface}'\n" > + > +puts "Enter the first 3 octets of the dhcp network you wish to use (example: 192.168.50)" > +dhcp_network = gets.chomp > +config_file.write "$dhcp_network = '#{dhcp_network}'\n" > + > +puts "Enter the dhcp pool start address (example: 3)" > +dhcp_start = gets.chomp > +config_file.write "$dhcp_start = '#{dhcp_start}'\n" > + > +puts "Enter the dhcp pool end addess (example: 100)" > +dhcp_stop = gets.chomp > +config_file.write "$dhcp_stop = '#{dhcp_stop}'\n" > + > +puts "Enter the dhcp domain you wish to use (example: example.com)" > +dhcp_domain = gets.chomp > +config_file.write "$dhcp_domain = '#{dhcp_domain}'\n" > + > +config_file.write "$ntp_server = '#{mgmt_ipaddr}'\n\n" > + > +puts "Provide pxe/tftp capability? (y/n)" > +tftp_setup = gets.chomp > + > +if sep_networks == "y" > +prov_ip = `ifconfig #{prov_dev}` > +prov_dns_server = prov_ip.scan(/\s*inet addr:([\d.]+)/) > +config_file.write "$prov_dns_server = '#{prov_dns_server}'\n" > + > +puts "Enter the network gateway for your provisioning network (example: 192.168.50.254)" > +prov_network_gateway = gets.chomp > +config_file.write "$prov_network_gateway = '#{prov_network_gateway}'\n" > +end > +end > + > +# Cobbler Configuration > +puts "Do you have a cobbler already that you wish to use? (y/n)" > +cobbler_setup = gets.chomp > + > +while cobbler_setup != "y" and cobbler_setup != "n" > +puts "Invalid choice" > +cobbler_setup = gets.chomp > +end > + > +cobbler_config = "n" > + > +if cobbler_setup == "y" > +puts "Enter the hostname of your cobbler server" > +cobbler_hostname = gets.chomp > +puts "Enter your cobbler username" > +cobbler_user_name= gets.chomp > +puts "Enter your cobbler user password" > +cobbler_user_password = gets.chomp > + > +elsif cobbler_setup == "n" > +cobbler_hostname = "localhost" > +puts "We will setup a cobbler instance, please provide the following information" > +puts "Enter your cobbler username" > +cobbler_user_name= gets.chomp > +puts "Enter your cobbler user password" > +cobbler_user_password = gets.chomp > +end > + > +config_file.write "# cobbler configuration\n" > +config_file.write "$cobbler_hostname = '#{cobbler_hostname}'\n" > +config_file.write "$cobbler_user_name = '#{cobbler_user_name}'\n" > +config_file.write "$cobbler_user_password = '#{cobbler_user_password}'\n\n" > + > + > +# Postgres Configuration > +puts "Enter a password for the ovirt postgres account" > +db_username = "ovirt" > +db_password = gets.chomp > +config_file.write "# postgres configuration\n" > +config_file.write "$db_username = '#{db_username}'\n" > +config_file.write "$db_password = '#{db_password}'\n\n" > + > +# FreeIPA Configuration > +config_file.write "# FreeIPA configuration\n" > +puts "Enter your realm name (example: example.com)" > +realm_name = gets.chomp > +config_file.write "$realm_name = '#{realm_name}'\n" > +puts "\nEnter an administrator password for FreeIPA " > +puts "*** This will also be you ovirtadmin password for the web management login ***\n\n" > +freeipa_password = gets.chomp > +config_file.write "$freeipa_password = '#{freeipa_password}'\n" > +ldap_dn = "cn=ipaConfig,cn=etc," > +ldap_dn_temp = realm_name.split(".") > +ldap_dn_temp.each do |i| > +ldap_dn += "dc=#{i}," > +end > +ldap_dn = ldap_dn.chop > +config_file.write "$ldap_dn = '#{ldap_dn}'\n\n" > + > + > +if cobbler_setup == "y" > +config_file.write "include cobbler::remote\n" > +elsif cobbler_setup == "n" > +config_file.write "include cobbler::bundled\n" > +end > + > +if dhcp_setup == "n" > +config_file.write "include dhcp::bundled\n" > +end > + > +if tftp_setup == "y" > +config_file.write "include tftp::bundled\n" > +end > + > +config_file.write "include postgres::bundled\n" > +config_file.write "include freeipa::bundled\n" > +config_file.write "include ovirt::setup\n" > +config_file.close > + > +puts "\n\nTo start the installation run: ace install ovirt" > diff --git a/installer/modules/ovirt/files/collectd.conf b/installer/modules/ovirt/files/collectd.conf > new file mode 100644 > index 0000000..0b327de > --- /dev/null > +++ b/installer/modules/ovirt/files/collectd.conf > @@ -0,0 +1,23 @@ > +LoadPlugin network > +LoadPlugin logfile > +LoadPlugin rrdtool > +LoadPlugin unixsock > + > + > + LogLevel info > + File STDOUT > + > + > + > + Listen "0.0.0.0" > + > + > + > + DataDir "/var/lib/collectd/rrd" > + CacheTimeout 120 > + CacheFlush 900 > + > + > + > + SocketFile "/var/lib/collectd/unixsock" > + > diff --git a/installer/modules/ovirt/files/dns_entries.sh b/installer/modules/ovirt/files/dns_entries.sh > new file mode 100755 > index 0000000..65662d5 > --- /dev/null > +++ b/installer/modules/ovirt/files/dns_entries.sh > @@ -0,0 +1,2 @@ > +#!/bin/bash > +for i in `seq $1 $2` ; do echo $3.$i node$i.$4 >> /etc/hosts; done > diff --git a/installer/modules/ovirt/files/modules.conf b/installer/modules/ovirt/files/modules.conf > new file mode 100644 > index 0000000..236ef4c > --- /dev/null > +++ b/installer/modules/ovirt/files/modules.conf > @@ -0,0 +1,96 @@ > +# specifies what cobbler modules to load. > + > +# what file/data formats to use for metadata > +# > +# choices: > +# serializer_catalog (fast, uses .d directories in /var/lib/cobbler/config) > +# serializer_yaml (original serializer, uses a few text files) > +# > +# for 99% or more of all installations, use serializer_catalog. > +# > +# NOTE: serializer changes may remove your ability to access old data. > +# serializer_yaml users can change to serializer_catalog w/o manual > +# migration steps. Other changes are for new installs only. > + > +[serializers] > +settings = serializer_catalog > +distro = serializer_catalog > +profile = serializer_catalog > +system = serializer_catalog > +repo = serializer_catalog > +image = serializer_catalog > + > +# policy: what users can log into the WebUI and Read-Write XMLRPC? > +# > +# choices: > +# authn_denyall -- no one (default) > +# authn_configfile -- use /etc/cobbler/users.digest (for basic setups) > +# authn_passthru -- ask Apache to handle it (used for kerberos) > +# authn_ldap -- authenticate against LDAP > +# authn_spacewalk -- ask Spacewalk/Satellite (experimental) > +# authn_testing -- username/password is always testing/testing (debug) > +# (user supplied) -- you may write your own module > +# > +# WARNING: this is a security setting, do not choose an option blindly. > +# > +# for more information: > +# https://fedorahosted.org/cobbler/wiki/CobblerWebInterface > +# https://fedorahosted.org/cobbler/wiki/CustomizableSecurity > +# https://fedorahosted.org/cobbler/wiki/CobblerWithKerberos > +# https://fedorahosted.org/cobbler/wiki/CobblerWithLdap > + > +[authentication] > +module = authn_configfile > + > +# policy: once a user has been cleared by the WebUI/XMLRPC, what can they do? > +# > +# choices: > +# authz_allowall -- full access for all authneticated users (default) > +# authz_configfile -- determined by /etc/cobbler/users.conf > +# authz_ownership -- use users.conf, but add object ownership semantics > +# (user supplied) -- you may write your own module > +# > +# WARNING: this is a security setting, do not choose an option blindly. > +# > +# for more information: > +# https://fedorahosted.org/cobbler/wiki/CobblerWebInterface > +# https://fedorahosted.org/cobbler/wiki/CustomizableSecurity > +# https://fedorahosted.org/cobbler/wiki/CustomizableAuthorization > +# https://fedorahosted.org/cobbler/wiki/AuthorizationWithOwnership > + > +[authorization] > +module = authz_allowall > + > +# chooses the DNS management engine if manage_dns is enabled > +# in /etc/cobbler/settings, which is off by default. > +# > +# choices: > +# manage_bind -- default, uses BIND/named > +# manage_dnsmasq -- uses dnsmasq, also must select dnsmasq for dhcp below > +# > +# NOTE: more configuration is still required in /etc/cobbler > +# > +# for more information: > +# https://fedorahosted.org/cobbler/wiki/ManageDns > + > +[dns] > +module = manage_bind > + > +# chooses the DHCP management engine if manage_dhcp is enabled > +# in /etc/cobbler/settings, which is off by default. > +# > +# choices: > +# manage_isc -- default, uses ISC dhcpd > +# manage_dnsmasq -- uses dnsmasq, also must select dnsmasq for dns above > +# > +# NOTE: more configuration is still required in /etc/cobbler > +# > +# for more information: > +# https://fedorahosted.org/cobbler/wiki/ManageDhcp > + > +[dhcp] > +module = manage_isc > + > + > + > + > diff --git a/installer/modules/ovirt/files/qpidd.conf b/installer/modules/ovirt/files/qpidd.conf > new file mode 100644 > index 0000000..014b23c > --- /dev/null > +++ b/installer/modules/ovirt/files/qpidd.conf > @@ -0,0 +1,4 @@ > +# Configuration file for qpidd. Entries are of the form: > +# name = value > +# Using default settings: "qpidd --help" or "man qpidd" for more details. > +auth=no > diff --git a/installer/modules/ovirt/manifests/cobbler.pp b/installer/modules/ovirt/manifests/cobbler.pp > new file mode 100644 > index 0000000..e509502 > --- /dev/null > +++ b/installer/modules/ovirt/manifests/cobbler.pp > @@ -0,0 +1,126 @@ > +#-- > +# Copyright (C) 2008 Red Hat Inc. > +# > +# This library is free software; you can redistribute it and/or > +# modify it under the terms of the GNU Lesser General Public > +# License as published by the Free Software Foundation; either > +# version 2.1 of the License, or (at your option) any later version. > +# > +# This library 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 > +# Lesser General Public License for more details. > +# > +# You should have received a copy of the GNU Lesser General Public > +# License along with this library; if not, write to the Free Software > +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > +# > +# Author: Joey Boggs > +#-- > + > +import "appliance_base" > +#import "firewall" > + > + > +define apache_htdigest($digest_file, $digest_username, $digest_password, $digest_realm="") > +{ > + file_append{"add_htdigest_for_$digest_username_in_$digest_realm": > + file => $digest_file, > + line => template("ovirt/digest_line.erb") > + } > + > +} > + > + > +define cobbler_user_config($cobbler_user_name="",$cobbler_user_password="",$cobbler_hostname="") { > + > + file_replacement{"cobbler_user_name_config": > + file => "/usr/share/ovirt-server/config/cobbler.yml", > + pattern => "^username.*$", > + replacement => "username: $cobbler_user_name", > + require => Package[ovirt-server] > + } > + > + file_replacement{"cobbler_user_password_config": > + file => "/usr/share/ovirt-server/config/cobbler.yml", > + pattern => "^password.*$", > + replacement => "password: $cobbler_user_password", > + require => File_replacement[cobbler_user_name_config] > + } > + file_replacement{"cobbler_hostname_config": > + file => "/usr/share/ovirt-server/config/cobbler.yml", > + pattern => "^hostname.*$", > + replacement => "hostname: $cobbler_hostname", > + require => File_replacement[cobbler_user_name_config] > + } > + > +} > + > +class cobbler::bundled { > + package {"cobbler": > + ensure => installed > + } > + > + apache_htdigest{"cobbler_add_user": > + digest_file => "/etc/cobbler/users.digest", > + digest_username => "$cobbler_user_name", > + digest_password => "$cobbler_user_password", > + digest_realm => "Cobbler", > + require => Package[cobbler] > + } > + > + cobbler_user_config {"cobbler_bundled_user": > + cobbler_user_name=> "$cobbler_user_name", > + cobbler_user_password => "$cobbler_user_password", > + cobbler_hostname => "localhost", > + require => Package[cobbler] > + } > + > + file_replacement{"settings_ip_address": > + file => "/etc/cobbler/settings", > + pattern => "127.0.0.1", > + replacement => $ipaddress, > + notify => Service[cobblerd], > + require => Package[cobbler] > + } > + > + file_replacement{"settings_xml_rpc": > + file => "/etc/cobbler/settings", > + pattern => "xmlrpc_rw_enabled: 0", > + replacement => "xmlrpc_rw_enabled: 1", > + require => File_replacement[settings_ip_address], > + notify=> Service[cobblerd] > + } > + > + service {"cobblerd" : > + ensure => running, > + enable => true, > + require => File_replacement[settings_ip_address] > + } > + > + file {"/etc/cobbler/modules.conf": > + source => "puppet:///ovirt/modules.conf", > + notify => Service[cobblerd], > + require => Package["cobbler"] > + } > + > +# firewall_rule{"69": destination_port => "69"} > +# firewall_rule{"25150": destination_port => "25150"} > +# firewall_rule{"25151": destination_port => "25151"} > + > +} > + > +class cobbler::remote { > + > +# On the remote cobbler server run the following command: > +# htdigest /etc/cobbler/users.digest "Cobbler" $user_name > +# Ensure the password is set to $cobbler_user_password > + > + > + cobbler_user_config {"cobbler_remote_user": > + cobbler_user_name => "$cobbler_user_name", > + cobbler_user_password => "$cobbler_user_password", > + cobbler_hostname => "$cobbler_hostname" > + } > +} > + > diff --git a/installer/modules/ovirt/manifests/dhcp.pp b/installer/modules/ovirt/manifests/dhcp.pp > new file mode 100644 > index 0000000..c5c8f9a > --- /dev/null > +++ b/installer/modules/ovirt/manifests/dhcp.pp > @@ -0,0 +1,34 @@ > +#-- > +# Copyright (C) 2008 Red Hat Inc. > +# > +# This library is free software; you can redistribute it and/or > +# modify it under the terms of the GNU Lesser General Public > +# License as published by the Free Software Foundation; either > +# version 2.1 of the License, or (at your option) any later version. > +# > +# This library 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 > +# Lesser General Public License for more details. > +# > +# You should have received a copy of the GNU Lesser General Public > +# License along with this library; if not, write to the Free Software > +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > +# > +# Author: Joey Boggs > +#-- > + > +class dhcp::bundled { > + > + file {"/etc/dnsmasq.d/ovirt-dhcp.conf": > + content => template("ovirt/ovirt-dhcp.conf.erb"), > + mode => 644, > + notify => Service[dnsmasq], > + require => Package[dnsmasq] > + } > + > + single_exec {"dns_entries": > + command => "/usr/share/ace/modules/ovirt/files/dns_entries.sh $dhcp_start $dhcp_stop $dhcp_network $dhcp_domain", > + } > + > +} > diff --git a/installer/modules/ovirt/manifests/dns.pp b/installer/modules/ovirt/manifests/dns.pp > new file mode 100644 > index 0000000..c16abfd > --- /dev/null > +++ b/installer/modules/ovirt/manifests/dns.pp > @@ -0,0 +1,99 @@ > +#-- > +# Copyright (C) 2008 Red Hat Inc. > +# > +# This library is free software; you can redistribute it and/or > +# modify it under the terms of the GNU Lesser General Public > +# License as published by the Free Software Foundation; either > +# version 2.1 of the License, or (at your option) any later version. > +# > +# This library 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 > +# Lesser General Public License for more details. > +# > +# You should have received a copy of the GNU Lesser General Public > +# License along with this library; if not, write to the Free Software > +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > +# > +# Author: Joey Boggs > +#-- > + > +# common featues > +define dns::common($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") { > + > + package {"dnsmasq": > + ensure => installed, > + require => [Single_exec["add_dns_server_to_resolv.conf"]] > + } > + > + service {"dnsmasq" : > + ensure => running, > + enable => true, > + require => [File["/etc/dnsmasq.d/ovirt-dns.conf"], Package["dnsmasq"]] > + } > + > + file {"/etc/dnsmasq.d/ovirt-dns.conf": > + content => template("ovirt/ovirt-dns.conf.erb"), > + mode => 644, > + notify => Service[dnsmasq], > + require => Package["dnsmasq"] > + } > + > + single_exec {"add_dns_server_to_resolv.conf": > + command => "/bin/sed -e '1i nameserver $prov_ipaddr' -i /etc/resolv.conf", > + require => [Single_exec["set_hostname"]] > + } > + > + > + file_replacement {"dnsmasq_configdir": > + file => "/etc/dnsmasq.conf", > + pattern => "^#conf-dir=*$", > + replacement => "conf-dir=/etc/dnsmasq.d", > + notify => Service[dnsmasq], > + require => Package["dnsmasq"] > + } > + > + file {"/etc/dhclient.conf": > + ensure => present > + } > + > + file_append {"dhclient_config": > + file => "/etc/dhclient.conf", > + line => "prepend domain-name-servers $prov_ipaddr", > + require => [Single_exec["set_hostname"], Package["dnsmasq"], File["/etc/dhclient.conf"]] , > + notify => Service[dnsmasq], > + } > + > +} > + > +define dns::bundled($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") { > + > + dns::common{"setup": mgmt_ipaddr=>$mgmt_ipaddr, prov_ipaddr=>$prov_ipaddr, mgmt_dev=>$mgmt_dev, prov_dev=>$prov_dev} > + > + single_exec {"add_mgmt_server_to_etc_hosts": > + command => "/bin/echo $mgmt_ipaddr $ipa_host >> /etc/hosts", > + notify => [Service[dnsmasq], Single_exec["add_dns_server_to_resolv.conf"]] > + } > +} > + > +define dns::remote($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") { > + > +# On the pxe server you will need to ensure that the > +# next server option points to the ip address of the tftp server > + > +# The following SRV records must be present in the dns server for everything > +# to function properly. Replace example.com with the appropriate domain > + > +# _ovirt._tcp.example.com. SRV 0 5 80 ovirtwuiserver.example.com. > +# _ipa._tcp.example.com. SRV 0 5 80 ipaserver.example.com. > +# _ldap._tcp.example.com. SRV 0 5 389 ldapserver.example.com. > +# _collectd._tcp.example.com. SRV 0 5 25826 ovirtwuiserver.example.com. > +# _qpidd._tcp.example.com. SRV 0 5 5672 ovirtwuiserver.example.com. > +# _identify._tcp.example.com. SRV 0 5 12120 ovirtwuiserver.example.com. > + > +# Also A records must be present for each oVirt node. Without this they are unable > +# to determine their hostname and locate the management server. > + > + dns::common{"setup": mgmt_ipaddr=>$mgmt_ipaddr, prov_ipaddr=>$prov_ipaddr, mgmt_dev=>$mgmt_dev, prov_dev=>$prov_dev} > + > +} > diff --git a/installer/modules/ovirt/manifests/freeipa.pp b/installer/modules/ovirt/manifests/freeipa.pp > new file mode 100644 > index 0000000..1f292bf > --- /dev/null > +++ b/installer/modules/ovirt/manifests/freeipa.pp > @@ -0,0 +1,103 @@ > +#-- > +# Copyright (C) 2008 Red Hat Inc. > +# > +# This library is free software; you can redistribute it and/or > +# modify it under the terms of the GNU Lesser General Public > +# License as published by the Free Software Foundation; either > +# version 2.1 of the License, or (at your option) any later version. > +# > +# This library 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 > +# Lesser General Public License for more details. > +# > +# You should have received a copy of the GNU Lesser General Public > +# License along with this library; if not, write to the Free Software > +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > +# > +# Author: Joey Boggs > +#-- > + > +class freeipa::bundled{ > + > + package {"ipa-server": > + ensure => installed, > + require => [Exec[db_exists_file],Single_exec["set_hostname"]] > + } > + > + single_exec {"set_hostname": > + command => "/bin/hostname $ipa_host", > + } > + > + exec {"set_kdc_defaults": > + command => "/bin/sed -i '/\[kdcdefaults\]/a \ kdc_ports = 88' /usr/share/ipa/kdc.conf.template", > + require => Package[ipa-server] > + } > + > + exec {"replace_line_returns": > + command => "/bin/sed -i -e 's/^/#/' /etc/httpd/conf.d/ipa-rewrite.conf", > + require => Single_Exec[ipa_server_install] > + } > + > + file_replacement{"ipa_proxy_config_1": > + file => "/etc/httpd/conf.d/ipa.conf", > + pattern => "^", > + replacement => "", > + require => Exec[replace_line_returns] > + } > + > + file_replacement{"ipa_proxy_config_2": > + file => "/etc/httpd/conf.d/ipa.conf", > + pattern => "^", > + replacement => "", > + require => File_replacement[ipa_proxy_config_1], > + notify => Service[httpd] > + } > + > + single_exec {"dnsmasq_restart": > + command => "/etc/init.d/dnsmasq restart", > + require => Service["dnsmasq"] > + } > + > + single_exec {"ipa_server_install": > + command => "/usr/sbin/ipa-server-install -r $realm_name -p $freeipa_password -P $freeipa_password -a $freeipa_password --hostname $ipa_host -u dirsrv -U", > + require => [Exec[set_kdc_defaults],Single_exec[dnsmasq_restart]] > + } > + > + exec {"get_krb5_tkt": > + command => "/bin/echo $freeipa_password|/usr/kerberos/bin/kinit admin", > + require => Single_Exec[ipa_server_install] > + } > + > + single_exec {"ipa_modify_username_length": > + command => "/usr/sbin/ipa-defaultoptions --maxusername=12", > + require => Exec["get_krb5_tkt"] > + } > + > + single_exec {"ipa_add_ovirtadmin_user": > + command => "/usr/sbin/ipa-adduser -f Ovirt -l Admin -p $freeipa_password ovirtadmin", > + require => Single_exec[ipa_modify_username_length] > + } > + > + single_exec {"ipa_ovirtadmin_group": > + command => "/usr/sbin/ipa-modgroup -a ovirtadmin admins", > + require => Single_exec[ipa_add_ovirtadmin_user] > + } > + > + single_exec {"set_pw_expiration": > + command => "/usr/sbin/ipa-moduser --setattr krbPasswordExpiration=19700101000000Z ovirtadmin", > + require => Single_exec[ipa_ovirtadmin_group] > + } > + > +# firewall_rule{"krb5": destination_port => "88"} > +# firewall_rule {"ldap": destination_port => '389'} > + > +} > + > +class freeipa::remote { > + > +# oVirt is not configured at this time to support a remote freeipa server > + > +} > + > + > diff --git a/installer/modules/ovirt/manifests/init.pp b/installer/modules/ovirt/manifests/init.pp > new file mode 100644 > index 0000000..87f6832 > --- /dev/null > +++ b/installer/modules/ovirt/manifests/init.pp > @@ -0,0 +1,9 @@ > +import "ovirt/cobbler.pp" > +import "ovirt/dns.pp" > +import "ovirt/dhcp.pp" > +import "ovirt/tftp.pp" > +import "ovirt/freeipa.pp" > +import "ovirt/ovirt.pp" > +import "ovirt/postgres.pp" > +import "appliance_base/single_exec.pp" > + > diff --git a/installer/modules/ovirt/manifests/ovirt.pp b/installer/modules/ovirt/manifests/ovirt.pp > new file mode 100644 > index 0000000..809db8e > --- /dev/null > +++ b/installer/modules/ovirt/manifests/ovirt.pp > @@ -0,0 +1,154 @@ > +#-- > +# Copyright (C) 2008 Red Hat Inc. > +# > +# This library is free software; you can redistribute it and/or > +# modify it under the terms of the GNU Lesser General Public > +# License as published by the Free Software Foundation; either > +# version 2.1 of the License, or (at your option) any later version. > +# > +# This library 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 > +# Lesser General Public License for more details. > +# > +# You should have received a copy of the GNU Lesser General Public > +# License along with this library; if not, write to the Free Software > +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > +# > +# Author: Joey Boggs > +#-- > + > +class ovirt::setup { > + > + package {"ovirt-server": > + ensure => installed, > + require => Single_exec[set_pw_expiration] > + } > + > + package {"httpd": > + ensure => installed; > + } > + > + package {"rubygem-rake": > + ensure => installed; > + } > + > + package {"qpidd": > + ensure => installed; > + } > + > + package {"collectd": > + ensure => installed; > + } > + > + package {"collectd-rrdtool": > + ensure => installed; > + } > + > + package {"libvirt": > + ensure => installed; > + } > + > + package {"ruby-qpid": > + ensure => installed; > + } > + > + package {"ntp": > + ensure => installed; > + } > + > + file {"/etc/collectd.conf": > + source => "puppet:///ovirt/collectd.conf", > + notify => Service[collectd], > + require => Package["collectd-rrdtool"] > + } > + > + file {"/etc/qpidd.conf": > + source => "puppet:///ovirt/qpidd.conf", > + notify => Service[qpidd] > + } > + > + single_exec { "db_migrate" : > + cwd => "/usr/share/ovirt-server/", > + command => "/usr/bin/rake db:migrate", > + require => [File["/usr/share/ovirt-server/log"],Package[ovirt-server],Package[rubygem-rake],Postgres_execute_command["ovirt_db_grant_permissions"]], > + environment => "RAILS_ENV=production" > + } > + > + file { "/usr/share/ovirt-server/log" : > + ensure => directory, > + require => Package[ovirt-server] > + } > + > + single_exec { "create_ovirtadmin_acct" : > + command => "/usr/share/ovirt-server/script/grant_admin_privileges ovirtadmin", > + require => Single_Exec[db_migrate] > + } > + > + single_exec { "add_host" : > + command => "/usr/bin/ovirt-add-host $ipa_host /usr/share/ovirt-server/ovirt.keytab", > + require => Package[ovirt-server] > + } > + > + exec { "disable_selinux" : > + command => "/usr/sbin/lokkit --selinux=disabled", > + require => Package["ovirt-server"] > + } > + > + service {"httpd" : > + enable => true, > + require => Package[httpd], > + ensure => running > + } > + > + service {"libvirt" : > + enable => false, > + require => Package[libvirt], > + } > + > + service {"ovirt-host-browser" : > + enable => true, > + require => [Package[ovirt-server],Single_Exec[db_migrate]], > + ensure => running > + } > + > + service {"ovirt-host-collect" : > + enable => true, > + require => [Package[ovirt-server],Single_Exec[db_migrate]], > + ensure => running > + } > + > + service {"ovirt-mongrel-rails" : > + enable => true, > + require => [Package[ovirt-server],Single_Exec[db_migrate]], > + ensure => running, > + notify => Service[httpd] > + } > + > + service {"ovirt-taskomatic" : > + enable => true, > + require => [Package[ovirt-server],Single_Exec[db_migrate]], > + ensure => running > + } > + > + service {"qpidd" : > + enable => true, > + ensure => running, > + require => Package[qpidd] > + } > + > + service {"collectd" : > + enable => true, > + ensure => running, > + require => Package[collectd] > + } > + > + service {"ntpd" : > + enable => true, > + ensure => running, > + require => Package[ntp] > + } > + > +# firewall_rule{"http": destination_port => "80"} > + > +} > diff --git a/installer/modules/ovirt/manifests/postgres.pp b/installer/modules/ovirt/manifests/postgres.pp > new file mode 100644 > index 0000000..0bd71fa > --- /dev/null > +++ b/installer/modules/ovirt/manifests/postgres.pp > @@ -0,0 +1,114 @@ > +#-- > +# Copyright (C) 2008 Red Hat Inc. > +# > +# This library is free software; you can redistribute it and/or > +# modify it under the terms of the GNU Lesser General Public > +# License as published by the Free Software Foundation; either > +# version 2.1 of the License, or (at your option) any later version. > +# > +# This library 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 > +# Lesser General Public License for more details. > +# > +# You should have received a copy of the GNU Lesser General Public > +# License along with this library; if not, write to the Free Software > +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > +# > +# Author: Joey Boggs > +#-- > + > +import "postgres" > +import "appliance_base/single_exec.pp" > + > +class postgres::bundled{ > + > + > + package {"postgresql-server": > + ensure => installed, > + } > + package {"ace-postgres": > + ensure => installed, > + require => Package[postgresql-server] > + } > + > + single_exec {"initialize_db": > + command => "/sbin/service postgresql initdb", > + creates => "/var/lib/pgsql/data/pg_hba.conf", > + require => Package[postgresql-server] > + } > + > + service {"postgresql" : > + ensure => running, > + enable => true, > + require => Single_exec[initialize_db] > + } > + > + single_exec {"create_ovirt_db": > + command => "/usr/bin/createdb ovirt", > + require => [Exec[postgres_add_all_trust], Service[postgresql]], > + user => "postgres" > + } > + > + single_exec {"create_ovirt_development_db": > + command => "/usr/bin/createdb ovirt_development", > + require => [Exec[postgres_add_all_trust], Service[postgresql]], > + user => "postgres" > + } > + > + postgres_execute_command {"ovirt_db_create_role": > + cmd => "CREATE ROLE ovirt LOGIN PASSWORD '$db_password' NOINHERIT VALID UNTIL 'infinity'", > + database => "ovirt", > + require => Single_Exec[create_ovirt_db] > + } > + > + postgres_execute_command {"ovirt_db_grant_permissions": > + cmd => "GRANT ALL ON DATABASE ovirt TO ovirt;", > + database => "ovirt", > + require => Postgres_execute_command[ovirt_db_create_role] > + } > + > + exec {"postgres_add_all_trust": > + command => "/bin/echo 'local all all trust' > /var/lib/pgsql/data/pg_hba.conf", > + require => Single_exec[initialize_db], > + notify => Service[postgresql] > + } > + > + exec {"postgres_add_localhost_trust": > + command => "/bin/echo 'host all all 127.0.0.1 255.255.255.0 trust' >> /var/lib/pgsql/data/pg_hba.conf", > + require => Exec[postgres_add_all_trust], > + notify => Service[postgresql] > + } > + > + file { "/etc/ovirt-server/" : > + ensure => directory, > + require => Exec[postgres_add_localhost_trust] > + } > + > + file { "/etc/ovirt-server/db/" : > + ensure => directory, > + require => File["/etc/ovirt-server"] > + } > + > + exec {"touch_dbaccess_file": > + command => "/bin/touch /etc/ovirt-server/db/dbaccess", > + require => File["/etc/ovirt-server/db"] > + } > + > + file_append {"db_password_file": > + file => "/etc/ovirt-server/db/dbaccess", > + line => "$db_password", > + require => Exec[touch_dbaccess_file] > + } > + exec {"db_exists_file": > + command => "/bin/touch /etc/ovirt-server/db/exists", > + require => File_append[db_password_file] > + } > +} > + > +class postgres::remote{ > + > +# oVirt is not configured at this time to support a remote postgres connection > + > +} > + > diff --git a/installer/modules/ovirt/manifests/tftp.pp b/installer/modules/ovirt/manifests/tftp.pp > new file mode 100644 > index 0000000..4f41d00 > --- /dev/null > +++ b/installer/modules/ovirt/manifests/tftp.pp > @@ -0,0 +1,31 @@ > +#-- > +# Copyright (C) 2008 Red Hat Inc. > +# > +# This library is free software; you can redistribute it and/or > +# modify it under the terms of the GNU Lesser General Public > +# License as published by the Free Software Foundation; either > +# version 2.1 of the License, or (at your option) any later version. > +# > +# This library 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 > +# Lesser General Public License for more details. > +# > +# You should have received a copy of the GNU Lesser General Public > +# License along with this library; if not, write to the Free Software > +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > +# > +# Author: Joey Boggs > +#-- > + > +class tftp::bundled { > + > + file {"/etc/dnsmasq.d/ovirt-tftp.conf": > + content => template("ovirt/ovirt-tftp.conf.erb"), > + mode => 644, > + notify => Service[dnsmasq], > + require => Package[dnsmasq] > + } > +} > + > + > diff --git a/installer/modules/ovirt/templates/digest_line.erb b/installer/modules/ovirt/templates/digest_line.erb > new file mode 100644 > index 0000000..4e98708 > --- /dev/null > +++ b/installer/modules/ovirt/templates/digest_line.erb > @@ -0,0 +1,4 @@ > +<% require 'digest/sha1' -%> > +<% token = "#{digest_username}:#{digest_realm}:#{digest_password}" -%> > +<% digested_password = Digest::MD5.hexdigest(token) -%> > +<%= digest_username -%>:<%= digest_realm -%>:<%= digested_password -%> > diff --git a/installer/modules/ovirt/templates/ovirt-dhcp.conf.erb b/installer/modules/ovirt/templates/ovirt-dhcp.conf.erb > new file mode 100644 > index 0000000..e10db40 > --- /dev/null > +++ b/installer/modules/ovirt/templates/ovirt-dhcp.conf.erb > @@ -0,0 +1,9 @@ > +interface=<%= dhcp_interface %> > +dhcp-range=<%= dhcp_network %>.<%= dhcp_start %>,<%= dhcp_network%>.<%= dhcp_stop %> > +domain=<%= dhcp_domain %> > +dhcp-option=option:router,<%= prov_network_gateway %> > +dhcp-option=option:ntp-server,<%= ntp_server %> > +dhcp-option=12 > +no-resolv > +local=/<%= dhcp_domain %>/ > +server=<%= prov_dns_server %> > diff --git a/installer/modules/ovirt/templates/ovirt-dns.conf.erb b/installer/modules/ovirt/templates/ovirt-dns.conf.erb > new file mode 100644 > index 0000000..ae3eb48 > --- /dev/null > +++ b/installer/modules/ovirt/templates/ovirt-dns.conf.erb > @@ -0,0 +1,7 @@ > +srv-host=_ovirt._tcp,<%= ovirt_host %>,80 > +srv-host=_ipa._tcp,<%= ipa_host %>,80 > +srv-host=_ldap._tcp,<%= ipa_host %>,389 > +srv-host=_collectd._tcp,<%= ovirt_host %>,25826 > +srv-host=_qpidd._tcp,<%= ovirt_host %>,5672 > +srv-host=_identify._tcp,<%= ovirt_host %>,12120 > + > diff --git a/installer/modules/ovirt/templates/ovirt-tftp.conf.erb b/installer/modules/ovirt/templates/ovirt-tftp.conf.erb > new file mode 100644 > index 0000000..3fa40f8 > --- /dev/null > +++ b/installer/modules/ovirt/templates/ovirt-tftp.conf.erb > @@ -0,0 +1,3 @@ > +enable-tftp > +tftp-root=/var/lib/tftpboot > +dhcp-boot=pxelinux.0 > diff --git a/ovirt-server.spec.in b/ovirt-server.spec.in > index 79a5adf..647794d 100644 > --- a/ovirt-server.spec.in > +++ b/ovirt-server.spec.in > @@ -1,5 +1,6 @@ > %define pbuild %{_builddir}/%{name}-%{version} > %define app_root %{_datadir}/%{name} > +%define acehome %{_datadir}/ace > > Summary: oVirt Server Suite > Name: ovirt-server > @@ -45,10 +46,19 @@ BuildArch: noarch > BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot > URL: http://ovirt.org/ > > -%description > +%package installer > +Summary: Installer modules for the oVirt Server Suite > +Requires: ruby(abi) = 1.8 > +Requires: ace > +Requires: ace-postgres > +Requires: hal > > +%description > The Server Suite for oVirt. > > +%description installer > +The Installer for the ovirt server suite > + > %prep > %setup -q > > @@ -59,6 +69,7 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT > mkdir %{buildroot} > > %{__install} -d -m0755 %{buildroot}%{_bindir} > +%{__install} -d -m0755 %{buildroot}%{_datadir} > %{__install} -d -m0755 %{buildroot}%{_sbindir} > %{__install} -d -m0755 %{buildroot}%{_initrddir} > %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/sysconfig > @@ -69,6 +80,7 @@ mkdir %{buildroot} > %{__install} -d -m0755 %{buildroot}%{_localstatedir}/log/%{name} > %{__install} -d -m0755 %{buildroot}%{_localstatedir}/run/%{name} > %{__install} -d -m0755 %{buildroot}%{app_root} > +%{__install} -d -m0755 %{buildroot}/%{acehome} > > touch %{buildroot}%{_localstatedir}/log/%{name}/mongrel.log > touch %{buildroot}%{_localstatedir}/log/%{name}/rails.log > @@ -114,6 +126,11 @@ touch %{buildroot}%{_localstatedir}/log/%{name}/db-omatic.log > %{__mkdir} %{buildroot}%{_localstatedir}/lib/%{name}/tmp > %{__ln_s} %{_localstatedir}/lib/%{name}/tmp %{buildroot}%{app_root}/tmp > > +# Set up the installer > +%{__cp} -pr %{pbuild}/installer/modules %{buildroot}/%{acehome} > +%{__cp} -pr %{pbuild}/installer/bin/ovirt-installer %{buildroot}%{_sbindir} > + > + > %clean > rm -rf $RPM_BUILD_ROOT > > @@ -193,6 +210,10 @@ fi > %config(noreplace) %{_sysconfdir}/%{name}/production.rb > %config(noreplace) %{_sysconfdir}/%{name}/test.rb > > +%files installer > +%{_sbindir}/ovirt-installer > +%{acehome} > + > %changelog > * Thu May 29 2008 Alan Pevec - 0.0.5-0 > - use rubygem-krb5-auth > From bkearney at redhat.com Tue Jan 6 17:16:39 2009 From: bkearney at redhat.com (Bryan Kearney) Date: Tue, 6 Jan 2009 12:16:39 -0500 Subject: [Ovirt-devel] [PATCH node] Add a hostname configurastion tool which can take user input or direct command line input from the kernel line Message-ID: <1231262199-18497-1-git-send-email-bkearney@redhat.com> --- Makefile.am | 1 + ovirt-node.spec.in | 3 ++ scripts/ovirt-config-hostname | 42 +++++++++++++++++++++++++++++++++++++++++ scripts/ovirt-early | 10 ++++++++- scripts/ovirt-firstboot | 1 + 5 files changed, 56 insertions(+), 1 deletions(-) create mode 100755 scripts/ovirt-config-hostname diff --git a/Makefile.am b/Makefile.am index 3e891c4..6847234 100644 --- a/Makefile.am +++ b/Makefile.am @@ -30,6 +30,7 @@ EXTRA_DIST = \ scripts/ovirt \ scripts/ovirt-awake \ scripts/ovirt-config-boot \ + scripts/ovirt-config-hostname \ scripts/ovirt-config-logging \ scripts/ovirt-config-networking \ scripts/ovirt-config-password \ diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in index e5031ad..72b35f2 100644 --- a/ovirt-node.spec.in +++ b/ovirt-node.spec.in @@ -132,6 +132,7 @@ cd - %{__install} -p -m0755 scripts/ovirt-awake %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-boot %{buildroot}%{_sbindir} +%{__install} -p -m0755 scripts/ovirt-config-hostname %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-logging %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-networking %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-password %{buildroot}%{_sbindir} @@ -187,6 +188,7 @@ install -p -m 644 images/syslinux-vesa-splash.jpg %{buildroot}/usr/lib/anaconda- %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/ovirt-config-setup.d %{__ln_s} ../..%{_sbindir}/ovirt-config-networking %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Networking Setup" %{__ln_s} ../..%{_sbindir}/ovirt-config-storage %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Disk Partitioning" +%{__ln_s} ../..%{_sbindir}/ovirt-config-hostname %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Set Hostname" %{__ln_s} ../..%{_sbindir}/ovirt-config-logging %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Logging Setup" %{__ln_s} ../..%{_sbindir}/ovirt-config-password %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Administrator Password" %{__ln_s} ../..%{_sbindir}/ovirt-config-boot %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Local install and reboot" @@ -251,6 +253,7 @@ fi %defattr(-,root,root,0755) %{_sbindir}/ovirt-awake %{_sbindir}/ovirt-config-boot +%{_sbindir}/ovirt-config-hostname %{_sbindir}/ovirt-config-logging %{_sbindir}/ovirt-config-networking %{_sbindir}/ovirt-config-password diff --git a/scripts/ovirt-config-hostname b/scripts/ovirt-config-hostname new file mode 100755 index 0000000..8ac46d3 --- /dev/null +++ b/scripts/ovirt-config-hostname @@ -0,0 +1,42 @@ +#!/bin/bash +# +# Configures the hostname file based on kernel cmdline or user prompt +# Source functions library +. /etc/init.d/functions +. /etc/init.d/ovirt-functions + +HOSTNAME_FILE="/etc/hostname" + +function set_hostname { + echo $1 > $HOSTNAME_FILE +} + +function prompt_user { + printf "\n" + read -p "What is the hostname for this node? " + + if [ -n "$REPLY" ]; then + set_hostname "$REPLY" + printf "\nHostname has been set\n" + else + if [ -e $HOSTNAME_FILE ]; then + rm $HOSTNAME_FILE + printf "\nRemoved old hostname configuration\n" + else + printf "\nAborting hostname configuration.\n" + fi + fi +} + +# AUTO for auto-install +if [ "$1" = "AUTO" ]; then + if [ -n "$OVIRT_HOSTNAME" ]; then + set_hostname "$OVIRT_HOSTNAME" + else + printf "\nHostname not provided. Skipping.\n" + fi +else + prompt_user +fi + +exit 0 diff --git a/scripts/ovirt-early b/scripts/ovirt-early index bf5f3d0..663e82c 100755 --- a/scripts/ovirt-early +++ b/scripts/ovirt-early @@ -133,6 +133,7 @@ start() { # anaconda format: ip= netmask= gateway= # ipv6=dhcp|auto # syslog=server[:port] + # hostname=fqdn # TBD logrotate maxsize # BOOTIF=link|eth*| (appended by pxelinux) @@ -180,6 +181,10 @@ start() { gateway= ipv6= + # hostname=fqdn + # hostname + hostname= + # syslog=server[:port] # default syslog server syslog_server= @@ -263,6 +268,9 @@ start() { ipv6=*) ipv6=${i#ipv6=} ;; + hostname=*) + hostname=${i#hostname=} + ;; syslog=*) i=${i#syslog=} eval $(printf $i|awk -F: '{print "syslog_server="$1; print "syslog_port="$2;}') @@ -280,7 +288,7 @@ start() { ip_gateway=$gateway fi # save boot parameters as defaults for ovirt-config-* - params="bootif init vol_boot_size vol_swap_size vol_root_size vol_config_size vol_logging_size local_boot standalone ip_address ip_netmask ip_gateway ipv6 syslog_server syslog_port bootparams" + params="bootif init vol_boot_size vol_swap_size vol_root_size vol_config_size vol_logging_size local_boot standalone ip_address ip_netmask ip_gateway ipv6 syslog_server syslog_port bootparams hostname" mount_config if [ -e $OVIRT_DEFAULTS ]; then echo "update ovirt defaults" diff --git a/scripts/ovirt-firstboot b/scripts/ovirt-firstboot index fe7723f..737dc52 100755 --- a/scripts/ovirt-firstboot +++ b/scripts/ovirt-firstboot @@ -33,6 +33,7 @@ start () ovirt-config-networking AUTO ovirt-config-storage AUTO ovirt-config-logging AUTO + ovirt-config-hostname AUTO if [ "$OVIRT_LOCAL_BOOT" = 1 ]; then ovirt-config-boot $OVIRT_INIT "" "$OVIRT_BOOTPARAMS" no disable_firstbot -- 1.6.0.4 From bkearney at redhat.com Tue Jan 6 19:03:42 2009 From: bkearney at redhat.com (Bryan Kearney) Date: Tue, 6 Jan 2009 14:03:42 -0500 Subject: [Ovirt-devel] [PATCH node] Add a hostname configurastion tool which can take user input or direct command line input from the kernel line Message-ID: <1231268622-30989-1-git-send-email-bkearney@redhat.com> --- Makefile.am | 1 + ovirt-node.spec.in | 3 ++ scripts/ovirt-config-hostname | 60 +++++++++++++++++++++++++++++++++++++++++ scripts/ovirt-early | 10 ++++++- scripts/ovirt-firstboot | 1 + 5 files changed, 74 insertions(+), 1 deletions(-) create mode 100755 scripts/ovirt-config-hostname diff --git a/Makefile.am b/Makefile.am index 3e891c4..6847234 100644 --- a/Makefile.am +++ b/Makefile.am @@ -30,6 +30,7 @@ EXTRA_DIST = \ scripts/ovirt \ scripts/ovirt-awake \ scripts/ovirt-config-boot \ + scripts/ovirt-config-hostname \ scripts/ovirt-config-logging \ scripts/ovirt-config-networking \ scripts/ovirt-config-password \ diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in index e5031ad..72b35f2 100644 --- a/ovirt-node.spec.in +++ b/ovirt-node.spec.in @@ -132,6 +132,7 @@ cd - %{__install} -p -m0755 scripts/ovirt-awake %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-boot %{buildroot}%{_sbindir} +%{__install} -p -m0755 scripts/ovirt-config-hostname %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-logging %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-networking %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-password %{buildroot}%{_sbindir} @@ -187,6 +188,7 @@ install -p -m 644 images/syslinux-vesa-splash.jpg %{buildroot}/usr/lib/anaconda- %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/ovirt-config-setup.d %{__ln_s} ../..%{_sbindir}/ovirt-config-networking %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Networking Setup" %{__ln_s} ../..%{_sbindir}/ovirt-config-storage %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Disk Partitioning" +%{__ln_s} ../..%{_sbindir}/ovirt-config-hostname %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Set Hostname" %{__ln_s} ../..%{_sbindir}/ovirt-config-logging %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Logging Setup" %{__ln_s} ../..%{_sbindir}/ovirt-config-password %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Administrator Password" %{__ln_s} ../..%{_sbindir}/ovirt-config-boot %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Local install and reboot" @@ -251,6 +253,7 @@ fi %defattr(-,root,root,0755) %{_sbindir}/ovirt-awake %{_sbindir}/ovirt-config-boot +%{_sbindir}/ovirt-config-hostname %{_sbindir}/ovirt-config-logging %{_sbindir}/ovirt-config-networking %{_sbindir}/ovirt-config-password diff --git a/scripts/ovirt-config-hostname b/scripts/ovirt-config-hostname new file mode 100755 index 0000000..179ead9 --- /dev/null +++ b/scripts/ovirt-config-hostname @@ -0,0 +1,60 @@ +#!/bin/bash +# +# Configures the hostname file based on kernel cmdline or user prompt +# Source functions library +. /etc/init.d/functions +. /etc/init.d/ovirt-functions + +HOSTNAME_FILE="/etc/sysconfig/network" + +function set_hostname { + augtool > /dev/null < /dev/null < netmask= gateway= # ipv6=dhcp|auto # syslog=server[:port] + # hostname=fqdn # TBD logrotate maxsize # BOOTIF=link|eth*| (appended by pxelinux) @@ -180,6 +181,10 @@ start() { gateway= ipv6= + # hostname=fqdn + # hostname + hostname= + # syslog=server[:port] # default syslog server syslog_server= @@ -263,6 +268,9 @@ start() { ipv6=*) ipv6=${i#ipv6=} ;; + hostname=*) + hostname=${i#hostname=} + ;; syslog=*) i=${i#syslog=} eval $(printf $i|awk -F: '{print "syslog_server="$1; print "syslog_port="$2;}') @@ -280,7 +288,7 @@ start() { ip_gateway=$gateway fi # save boot parameters as defaults for ovirt-config-* - params="bootif init vol_boot_size vol_swap_size vol_root_size vol_config_size vol_logging_size local_boot standalone ip_address ip_netmask ip_gateway ipv6 syslog_server syslog_port bootparams" + params="bootif init vol_boot_size vol_swap_size vol_root_size vol_config_size vol_logging_size local_boot standalone ip_address ip_netmask ip_gateway ipv6 syslog_server syslog_port bootparams hostname" mount_config if [ -e $OVIRT_DEFAULTS ]; then echo "update ovirt defaults" diff --git a/scripts/ovirt-firstboot b/scripts/ovirt-firstboot index fe7723f..737dc52 100755 --- a/scripts/ovirt-firstboot +++ b/scripts/ovirt-firstboot @@ -33,6 +33,7 @@ start () ovirt-config-networking AUTO ovirt-config-storage AUTO ovirt-config-logging AUTO + ovirt-config-hostname AUTO if [ "$OVIRT_LOCAL_BOOT" = 1 ]; then ovirt-config-boot $OVIRT_INIT "" "$OVIRT_BOOTPARAMS" no disable_firstbot -- 1.6.0.4 From dpierce at redhat.com Tue Jan 6 20:32:29 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Tue, 6 Jan 2009 15:32:29 -0500 Subject: [Ovirt-devel] [PATCH node] Small patch to find disks if hal doesn't return one. Message-ID: <1231273949-10010-1-git-send-email-dpierce@redhat.com> If hal does not return any devices with the storage capability, and that's of type disk and block, then the script will grab all devices that meets the pattern /dev/[shv]d? and show them. Signed-off-by: Darryl L. Pierce --- scripts/ovirt-config-storage | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage index 1c31a58..78e56dc 100755 --- a/scripts/ovirt-config-storage +++ b/scripts/ovirt-config-storage @@ -75,6 +75,9 @@ get_dev_name() || devices="$devices $block_dev" done + # if we didn't find any devices using HAL, so check for virtual devices + if [ -z $devices ]; then devices=$(ls -l /dev/[shv]d?); fi + # If there's only one device, use it. case $devices in '') warn "ERROR: found no usable block device"; return 1;; -- 1.6.0.6 From jboggs at redhat.com Tue Jan 6 21:40:51 2009 From: jboggs at redhat.com (Joey Boggs) Date: Tue, 06 Jan 2009 16:40:51 -0500 Subject: [Ovirt-devel] Re: [PATCH appliance] Modify the appliance building to use the installer rpm In-Reply-To: <49627652.6010202@redhat.com> References: <1231189508-20804-1-git-send-email-bkearney@redhat.com> <49627652.6010202@redhat.com> Message-ID: <4963CFE3.9070205@redhat.com> Figured out the permissions issues on my side, so ack from me Bryan Kearney wrote: > This was the last of three pacthes which brought in Joey's installer > code. The goal, once acked, is to deprecate the recipe repo so that > the bare-metal installer is used by the appliance as well. > > -- bk > > Bryan Kearney wrote: >> --- >> ovirt-appliance.ks | 4 ++-- >> 1 files changed, 2 insertions(+), 2 deletions(-) >> >> diff --git a/ovirt-appliance.ks b/ovirt-appliance.ks >> index 81cb010..813a618 100644 >> --- a/ovirt-appliance.ks >> +++ b/ovirt-appliance.ks >> @@ -28,7 +28,7 @@ reboot >> >> %packages --excludedocs --nobase >> %include /usr/share/appliance-os/includes/base-pkgs.ks >> -ovirt-recipe >> +ovirt-server-installer >> lokkit >> >> %post >> @@ -40,7 +40,7 @@ lokkit >> >> # The ace stuff. >> mkdir /etc/sysconfig/ace >> - echo ovirt >> /etc/sysconfig/ace/appliancename >> + echo ovirt-appliance >> /etc/sysconfig/ace/appliancename >> %end >> >> %post > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel From bkearney at redhat.com Tue Jan 6 21:43:34 2009 From: bkearney at redhat.com (Bryan Kearney) Date: Tue, 06 Jan 2009 16:43:34 -0500 Subject: [Ovirt-devel] Re: [PATCH appliance] Modify the appliance building to use the installer rpm In-Reply-To: <4963CFE3.9070205@redhat.com> References: <1231189508-20804-1-git-send-email-bkearney@redhat.com> <49627652.6010202@redhat.com> <4963CFE3.9070205@redhat.com> Message-ID: <4963D086.6010609@redhat.com> Joey Boggs wrote: > Figured out the permissions issues on my side, so ack from me Sorry.. I was supposed to send an RPM. What was the issue? -- bk From jboggs at redhat.com Tue Jan 6 21:50:06 2009 From: jboggs at redhat.com (Joey Boggs) Date: Tue, 06 Jan 2009 16:50:06 -0500 Subject: [Ovirt-devel] Re: [PATCH appliance] Modify the appliance building to use the installer rpm In-Reply-To: <4963D086.6010609@redhat.com> References: <1231189508-20804-1-git-send-email-bkearney@redhat.com> <49627652.6010202@redhat.com> <4963CFE3.9070205@redhat.com> <4963D086.6010609@redhat.com> Message-ID: <4963D20E.6090709@redhat.com> no worries on that, it was better for me to figure it out for future reference, I was using patch instead of git-apply and for some reason patch ignored the create modes on the files. Bryan Kearney wrote: > Joey Boggs wrote: >> Figured out the permissions issues on my side, so ack from me > Sorry.. I was supposed to send an RPM. What was the issue? > -- bk > From lutter at redhat.com Wed Jan 7 01:07:20 2009 From: lutter at redhat.com (David Lutterkort) Date: Tue, 06 Jan 2009 17:07:20 -0800 Subject: [Ovirt-devel] [PATCH server] Rake task to generate a dot drawing of the possible VM states Message-ID: <1231290440.23032.17.camel@localhost.localdomain> I was curious what all the VM state transitions taken together look like - below is a rake task that generates a dot drawing of the FSM of VM states. Attached is a picture of all that for everybody's amusement. David >From 08d72ae336afedcfa0dac9a57e5a79a2b6effac8 Mon Sep 17 00:00:00 2001 From: David Lutterkort Date: Tue, 6 Jan 2009 16:54:31 -0800 Subject: [PATCH server] Rake task to generate a dot drawing of the possible VM states --- src/lib/tasks/vm-states-dot.rake | 40 ++++++++++++++++++++++++++++++++++++++ 1 files changed, 40 insertions(+), 0 deletions(-) create mode 100644 src/lib/tasks/vm-states-dot.rake diff --git a/src/lib/tasks/vm-states-dot.rake b/src/lib/tasks/vm-states-dot.rake new file mode 100644 index 0000000..74f1f8e --- /dev/null +++ b/src/lib/tasks/vm-states-dot.rake @@ -0,0 +1,40 @@ +# -*- ruby -*- +require 'permission' +require 'task' +require 'vm' +require 'vm_task' + +desc "Generate a dot file for VM state transitions (pass output file in\nvariable 'output')" +task "vm:states:dot" do + out = $stdout + out = File::open(ENV['output'], 'w') if ENV['output'] + + # Classify states + states = {} + [:start, :running, :success, :failure].each do |tag| + VmTask::ACTIONS.values.each { |a| + states[a[tag]] ||= [] + states[a[tag]] << tag + } + end + + out.puts "digraph \"VM Task Transitions\" {" + states.each do |state, tags| + out.print " #{state} [" + if tags == [:running] + out.print("shape=box color=\"#666666\" fontcolor=\"#666666\"") + end + out.puts "];" + end + VmTask::ACTIONS.values.each do |a| + out.puts "#{a[:start]} -> #{a[:running]} [ label = \"#{a[:label]}\" ];" + out.puts "#{a[:running]} -> #{a[:success]} [ color = green ];" + out.puts "#{a[:running]} -> #{a[:failure]} [ color= red ];" + end + out.puts '":running" [shape=box color="#666666" fontcolor="#666666"];' + out.puts '":start" -> ":running" [ label = "Action" ];' + out.puts '":running" -> ":success" [ color = green ];' + out.puts '":running" -> ":failure" [ color= red ];' + out.puts "}" + out.close +end -- 1.6.0.6 -------------- next part -------------- A non-text attachment was scrubbed... Name: fsm.png Type: image/png Size: 93683 bytes Desc: not available URL: From dpierce at redhat.com Wed Jan 7 13:01:42 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 7 Jan 2009 08:01:42 -0500 Subject: [Ovirt-devel] Re: [PATCH node] Small patch to find disks if hal doesn't return one. In-Reply-To: <1231273949-10010-1-git-send-email-dpierce@redhat.com> References: <1231273949-10010-1-git-send-email-dpierce@redhat.com> Message-ID: <20090107130142.GA4726@mcpierce-laptop.rdu.redhat.com> On Tue, Jan 06, 2009 at 03:32:29PM -0500, Darryl L. Pierce wrote: > If hal does not return any devices with the storage capability, and > that's of type disk and block, then the script will grab all devices > that meets the pattern /dev/[shv]d? and show them. > > Signed-off-by: Darryl L. Pierce > --- > scripts/ovirt-config-storage | 3 +++ > 1 files changed, 3 insertions(+), 0 deletions(-) > > diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage > index 1c31a58..78e56dc 100755 > --- a/scripts/ovirt-config-storage > +++ b/scripts/ovirt-config-storage > @@ -75,6 +75,9 @@ get_dev_name() > || devices="$devices $block_dev" > done > > + # if we didn't find any devices using HAL, so check for virtual devices > + if [ -z $devices ]; then devices=$(ls -l /dev/[shv]d?); fi > + > # If there's only one device, use it. > case $devices in > '') warn "ERROR: found no usable block device"; return 1;; > -- > 1.6.0.6 We discussed this in IRC and I think the consensus was that it's fine. Can someone give me an ACK? -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From dpierce at redhat.com Wed Jan 7 13:02:21 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 7 Jan 2009 08:02:21 -0500 Subject: [Ovirt-devel] Re: [PATCH node] Moved functionality to o-process-config. In-Reply-To: <20081223131211.GA6612@mcpierce-laptop.mcpierce.org> References: <1229724703-21914-1-git-send-email-dpierce@redhat.com> <20081223131211.GA6612@mcpierce-laptop.mcpierce.org> Message-ID: <20090107130221.GB4726@mcpierce-laptop.rdu.redhat.com> On Tue, Dec 23, 2008 at 08:12:11AM -0500, Darryl L. Pierce wrote: > On Fri, Dec 19, 2008 at 05:11:43PM -0500, Darryl L. Pierce wrote: > > Code to copy the network configuration files to the config partition and > > to restart the network service have been moved out of ovirt-early and > > into ovirt-process-config. This will allow the script to be reuseable. > > Can I get some feedback or an ACK on this patch, please? Still waiting on an ACK here. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From pmyers at redhat.com Wed Jan 7 13:25:27 2009 From: pmyers at redhat.com (Perry Myers) Date: Wed, 07 Jan 2009 08:25:27 -0500 Subject: [Ovirt-devel] Re: [PATCH node] Small patch to find disks if hal doesn't return one. In-Reply-To: <20090107130142.GA4726@mcpierce-laptop.rdu.redhat.com> References: <1231273949-10010-1-git-send-email-dpierce@redhat.com> <20090107130142.GA4726@mcpierce-laptop.rdu.redhat.com> Message-ID: <4964AD47.6090902@redhat.com> Darryl L. Pierce wrote: > On Tue, Jan 06, 2009 at 03:32:29PM -0500, Darryl L. Pierce wrote: >> If hal does not return any devices with the storage capability, and >> that's of type disk and block, then the script will grab all devices >> that meets the pattern /dev/[shv]d? and show them. >> >> Signed-off-by: Darryl L. Pierce >> --- >> scripts/ovirt-config-storage | 3 +++ >> 1 files changed, 3 insertions(+), 0 deletions(-) >> >> diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage >> index 1c31a58..78e56dc 100755 >> --- a/scripts/ovirt-config-storage >> +++ b/scripts/ovirt-config-storage >> @@ -75,6 +75,9 @@ get_dev_name() >> || devices="$devices $block_dev" >> done >> >> + # if we didn't find any devices using HAL, so check for virtual devices >> + if [ -z $devices ]; then devices=$(ls -l /dev/[shv]d?); fi >> + >> # If there's only one device, use it. >> case $devices in >> '') warn "ERROR: found no usable block device"; return 1;; >> -- >> 1.6.0.6 > > We discussed this in IRC and I think the consensus was that it's fine. > Can someone give me an ACK? Conceptual Ack, though I have not applied/tested this. Darryl if you've tested this sufficiently and it works for you please commit. Perry From dpierce at redhat.com Wed Jan 7 13:29:57 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 7 Jan 2009 08:29:57 -0500 Subject: [Ovirt-devel] Re: [PATCH node] Small patch to find disks if hal doesn't return one. In-Reply-To: <4964AD47.6090902@redhat.com> References: <1231273949-10010-1-git-send-email-dpierce@redhat.com> <20090107130142.GA4726@mcpierce-laptop.rdu.redhat.com> <4964AD47.6090902@redhat.com> Message-ID: <20090107132957.GB7012@mcpierce-laptop.rdu.redhat.com> On Wed, Jan 07, 2009 at 08:25:27AM -0500, Perry Myers wrote: > Darryl L. Pierce wrote: >> On Tue, Jan 06, 2009 at 03:32:29PM -0500, Darryl L. Pierce wrote: >>> If hal does not return any devices with the storage capability, and >>> that's of type disk and block, then the script will grab all devices >>> that meets the pattern /dev/[shv]d? and show them. >>> >>> Signed-off-by: Darryl L. Pierce >>> --- >>> scripts/ovirt-config-storage | 3 +++ >>> 1 files changed, 3 insertions(+), 0 deletions(-) >>> >>> diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage >>> index 1c31a58..78e56dc 100755 >>> --- a/scripts/ovirt-config-storage >>> +++ b/scripts/ovirt-config-storage >>> @@ -75,6 +75,9 @@ get_dev_name() >>> || devices="$devices $block_dev" >>> done >>> + # if we didn't find any devices using HAL, so check for virtual >>> devices >>> + if [ -z $devices ]; then devices=$(ls -l /dev/[shv]d?); fi >>> + >>> # If there's only one device, use it. >>> case $devices in >>> '') warn "ERROR: found no usable block device"; return 1;; >>> -- >>> 1.6.0.6 >> >> We discussed this in IRC and I think the consensus was that it's fine. >> Can someone give me an ACK? > > Conceptual Ack, though I have not applied/tested this. Darryl if you've > tested this sufficiently and it works for you please commit. Pushed. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From berrange at redhat.com Wed Jan 7 14:12:55 2009 From: berrange at redhat.com (Daniel P. Berrange) Date: Wed, 7 Jan 2009 14:12:55 +0000 Subject: [Ovirt-devel] [PATCH node] Small patch to find disks if hal doesn't return one. In-Reply-To: <1231273949-10010-1-git-send-email-dpierce@redhat.com> References: <1231273949-10010-1-git-send-email-dpierce@redhat.com> Message-ID: <20090107141255.GB5360@redhat.com> On Tue, Jan 06, 2009 at 03:32:29PM -0500, Darryl L. Pierce wrote: > If hal does not return any devices with the storage capability, and > that's of type disk and block, then the script will grab all devices > that meets the pattern /dev/[shv]d? and show them. > > Signed-off-by: Darryl L. Pierce Errr, Why ? If HAL doesn't find the disk, then we need to fix HAL and not go poking around in /dev ourselves. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| From hbrock at redhat.com Wed Jan 7 14:40:17 2009 From: hbrock at redhat.com (Hugh O. Brock) Date: Wed, 7 Jan 2009 09:40:17 -0500 Subject: [Ovirt-devel] [PATCH server] Rake task to generate a dot drawing of the possible VM states In-Reply-To: <1231290440.23032.17.camel@localhost.localdomain> References: <1231290440.23032.17.camel@localhost.localdomain> Message-ID: <20090107144017.GK21522@redhat.com> On Tue, Jan 06, 2009 at 05:07:20PM -0800, David Lutterkort wrote: > I was curious what all the VM state transitions taken together look like > - below is a rake task that generates a dot drawing of the FSM of VM > states. > > Attached is a picture of all that for everybody's amusement. > > David > A flying spaghetti monster! Awesome! --Hugh From pmyers at redhat.com Wed Jan 7 14:41:41 2009 From: pmyers at redhat.com (Perry Myers) Date: Wed, 07 Jan 2009 09:41:41 -0500 Subject: [Ovirt-devel] [PATCH node] Small patch to find disks if hal doesn't return one. In-Reply-To: <20090107141255.GB5360@redhat.com> References: <1231273949-10010-1-git-send-email-dpierce@redhat.com> <20090107141255.GB5360@redhat.com> Message-ID: <4964BF25.9090305@redhat.com> Daniel P. Berrange wrote: > On Tue, Jan 06, 2009 at 03:32:29PM -0500, Darryl L. Pierce wrote: >> If hal does not return any devices with the storage capability, and >> that's of type disk and block, then the script will grab all devices >> that meets the pattern /dev/[shv]d? and show them. >> >> Signed-off-by: Darryl L. Pierce > > Errr, Why ? If HAL doesn't find the disk, then we need to fix > HAL and not go poking around in /dev ourselves. Agree, but this is a short term fix. This only happens for virtio based disks (i.e. vda) on the 'fake' Node. We can follow up and fix Hal as well. Perry From berrange at redhat.com Wed Jan 7 14:46:59 2009 From: berrange at redhat.com (Daniel P. Berrange) Date: Wed, 7 Jan 2009 14:46:59 +0000 Subject: [Ovirt-devel] [PATCH node] Small patch to find disks if hal doesn't return one. In-Reply-To: <4964BF25.9090305@redhat.com> References: <1231273949-10010-1-git-send-email-dpierce@redhat.com> <20090107141255.GB5360@redhat.com> <4964BF25.9090305@redhat.com> Message-ID: <20090107144659.GC5360@redhat.com> On Wed, Jan 07, 2009 at 09:41:41AM -0500, Perry Myers wrote: > Daniel P. Berrange wrote: > >On Tue, Jan 06, 2009 at 03:32:29PM -0500, Darryl L. Pierce wrote: > >>If hal does not return any devices with the storage capability, and > >>that's of type disk and block, then the script will grab all devices > >>that meets the pattern /dev/[shv]d? and show them. > >> > >>Signed-off-by: Darryl L. Pierce > > > >Errr, Why ? If HAL doesn't find the disk, then we need to fix > >HAL and not go poking around in /dev ourselves. > > Agree, but this is a short term fix. This only happens for virtio based > disks (i.e. vda) on the 'fake' Node. AFAIK HAL copes with VirtIO just fine - it has to because Anaconda asks HAL for list of disks when it installs an OS. What HAL version do you see failures on ? Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| From dpierce at redhat.com Wed Jan 7 14:49:50 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 7 Jan 2009 09:49:50 -0500 Subject: [Ovirt-devel] [PATCH node] Small patch to find disks if hal doesn't return one. In-Reply-To: <4964BF25.9090305@redhat.com> References: <1231273949-10010-1-git-send-email-dpierce@redhat.com> <20090107141255.GB5360@redhat.com> <4964BF25.9090305@redhat.com> Message-ID: <20090107144950.GA3983@mcpierce-laptop.rdu.redhat.com> On Wed, Jan 07, 2009 at 09:41:41AM -0500, Perry Myers wrote: > Daniel P. Berrange wrote: >> On Tue, Jan 06, 2009 at 03:32:29PM -0500, Darryl L. Pierce wrote: >>> If hal does not return any devices with the storage capability, and >>> that's of type disk and block, then the script will grab all devices >>> that meets the pattern /dev/[shv]d? and show them. >>> >>> Signed-off-by: Darryl L. Pierce >> >> Errr, Why ? If HAL doesn't find the disk, then we need to fix >> HAL and not go poking around in /dev ourselves. > > Agree, but this is a short term fix. This only happens for virtio based > disks (i.e. vda) on the 'fake' Node. > > We can follow up and fix Hal as well. I've already sent an email to someone on the HAL team asking if they have plans to better support virtual hardware. In the meantime I'll see about submitting a patch to do this if I can. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From bkearney at redhat.com Wed Jan 7 14:46:42 2009 From: bkearney at redhat.com (Bryan Kearney) Date: Wed, 07 Jan 2009 09:46:42 -0500 Subject: [Ovirt-devel] [Fwd: Release of ace-0.0.5] Message-ID: <4964C052.3030401@redhat.com> FYI: When this hits stable it will fix some of the comments for the installer and appliance. -- bk -------- Original Message -------- Subject: Release of ace-0.0.5 Date: Wed, 07 Jan 2009 09:41:00 -0500 From: Bryan Kearney To: Thincrust tooling devel list We are proud to announce the release of the 0.5 build of the appliance configuration engine. The main driver of this version is that puppet 24.7 is in testing, and includes the augeas type which was started as part of this project. The new code will use puppet's auges type if you have 24.7 installed, or will use the embedded (read deprecated) plugin if you have anything earlier installed. In addition, you the release adds usability improvements based on input from oVirt and the JBoss guys. Specifically: * Error codes are accurate, and failures are reported on the command line. * The init script reports this status consistently with other init scripts * Executing 'ace --verbose install FOO" will no provide you real time output, not delayed as in earlier versions. The packages are working their way through the build system now. If you want to look at them sooner rather then later, please see: https://admin.fedoraproject.org/updates/ace-0.0.5-1.fc10 https://admin.fedoraproject.org/updates/ace-0.0.5-1.fc9 Thanks! -- bk From dpierce at redhat.com Wed Jan 7 14:51:43 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 7 Jan 2009 09:51:43 -0500 Subject: [Ovirt-devel] [PATCH node] Small patch to find disks if hal doesn't return one. In-Reply-To: <20090107144659.GC5360@redhat.com> References: <1231273949-10010-1-git-send-email-dpierce@redhat.com> <20090107141255.GB5360@redhat.com> <4964BF25.9090305@redhat.com> <20090107144659.GC5360@redhat.com> Message-ID: <20090107145143.GB3983@mcpierce-laptop.rdu.redhat.com> On Wed, Jan 07, 2009 at 02:46:59PM +0000, Daniel P. Berrange wrote: > AFAIK HAL copes with VirtIO just fine - it has to because Anaconda asks > HAL for list of disks when it installs an OS. What HAL version do you > see failures on ? hal-0.5.12-12.20081027git -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From berrange at redhat.com Wed Jan 7 14:58:35 2009 From: berrange at redhat.com (Daniel P. Berrange) Date: Wed, 7 Jan 2009 14:58:35 +0000 Subject: [Ovirt-devel] [PATCH node] Small patch to find disks if hal doesn't return one. In-Reply-To: <20090107144950.GA3983@mcpierce-laptop.rdu.redhat.com> References: <1231273949-10010-1-git-send-email-dpierce@redhat.com> <20090107141255.GB5360@redhat.com> <4964BF25.9090305@redhat.com> <20090107144950.GA3983@mcpierce-laptop.rdu.redhat.com> Message-ID: <20090107145835.GD5360@redhat.com> On Wed, Jan 07, 2009 at 09:49:50AM -0500, Darryl L. Pierce wrote: > On Wed, Jan 07, 2009 at 09:41:41AM -0500, Perry Myers wrote: > > Daniel P. Berrange wrote: > >> On Tue, Jan 06, 2009 at 03:32:29PM -0500, Darryl L. Pierce wrote: > >>> If hal does not return any devices with the storage capability, and > >>> that's of type disk and block, then the script will grab all devices > >>> that meets the pattern /dev/[shv]d? and show them. > >>> > >>> Signed-off-by: Darryl L. Pierce > >> > >> Errr, Why ? If HAL doesn't find the disk, then we need to fix > >> HAL and not go poking around in /dev ourselves. > > > > Agree, but this is a short term fix. This only happens for virtio based > > disks (i.e. vda) on the 'fake' Node. > > > > We can follow up and fix Hal as well. > > I've already sent an email to someone on the HAL team asking if they > have plans to better support virtual hardware. In the meantime I'll see > about submitting a patch to do this if I can. HAL has supported VirtIO devices for almost a year already https://bugzilla.redhat.com/show_bug.cgi?id=435640 Hence we need to find out what has caused this regression, and not paper over it in oVirt Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| From dpierce at redhat.com Wed Jan 7 15:04:48 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 7 Jan 2009 10:04:48 -0500 Subject: [Ovirt-devel] [PATCH node] Small patch to find disks if hal doesn't return one. In-Reply-To: <20090107145835.GD5360@redhat.com> References: <1231273949-10010-1-git-send-email-dpierce@redhat.com> <20090107141255.GB5360@redhat.com> <4964BF25.9090305@redhat.com> <20090107144950.GA3983@mcpierce-laptop.rdu.redhat.com> <20090107145835.GD5360@redhat.com> Message-ID: <20090107150448.GC3983@mcpierce-laptop.rdu.redhat.com> On Wed, Jan 07, 2009 at 02:58:35PM +0000, Daniel P. Berrange wrote: > HAL has supported VirtIO devices for almost a year already > > https://bugzilla.redhat.com/show_bug.cgi?id=435640 > > Hence we need to find out what has caused this regression, and not paper > over it in oVirt Dave Z's the guy I emailed to ask about this. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From pmyers at redhat.com Wed Jan 7 15:06:55 2009 From: pmyers at redhat.com (Perry Myers) Date: Wed, 07 Jan 2009 10:06:55 -0500 Subject: [Ovirt-devel] [PATCH node] Small patch to find disks if hal doesn't return one. In-Reply-To: <20090107150448.GC3983@mcpierce-laptop.rdu.redhat.com> References: <1231273949-10010-1-git-send-email-dpierce@redhat.com> <20090107141255.GB5360@redhat.com> <4964BF25.9090305@redhat.com> <20090107144950.GA3983@mcpierce-laptop.rdu.redhat.com> <20090107145835.GD5360@redhat.com> <20090107150448.GC3983@mcpierce-laptop.rdu.redhat.com> Message-ID: <4964C50F.4030208@redhat.com> Darryl L. Pierce wrote: > On Wed, Jan 07, 2009 at 02:58:35PM +0000, Daniel P. Berrange wrote: >> HAL has supported VirtIO devices for almost a year already >> >> https://bugzilla.redhat.com/show_bug.cgi?id=435640 >> >> Hence we need to find out what has caused this regression, and not paper >> over it in oVirt We'll paper over it in oVirt until it is fixed in Hal since I don't want this issue blocking further development/testing of fake nodes. But yes, we need to fix the real problem in Hal and then we can revert this patch. On thought... Darryl, check to see what hal shows on the ovirt-appliance. That also uses virtio disks. If hal detects virtio disks in the appliance but not in the Node it could be something we broke. If it doesn't show up in the appliance either, then it's probably an upstream regression in hal. Perry From dpierce at redhat.com Wed Jan 7 15:41:42 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 7 Jan 2009 10:41:42 -0500 Subject: [Ovirt-devel] [PATCH node] Small patch to find disks if hal doesn't return one. In-Reply-To: <4964C50F.4030208@redhat.com> References: <1231273949-10010-1-git-send-email-dpierce@redhat.com> <20090107141255.GB5360@redhat.com> <4964BF25.9090305@redhat.com> <20090107144950.GA3983@mcpierce-laptop.rdu.redhat.com> <20090107145835.GD5360@redhat.com> <20090107150448.GC3983@mcpierce-laptop.rdu.redhat.com> <4964C50F.4030208@redhat.com> Message-ID: <20090107154142.GD3983@mcpierce-laptop.rdu.redhat.com> On Wed, Jan 07, 2009 at 10:06:55AM -0500, Perry Myers wrote: > We'll paper over it in oVirt until it is fixed in Hal since I don't want > this issue blocking further development/testing of fake nodes. > > But yes, we need to fix the real problem in Hal and then we can revert > this patch. > > On thought... Darryl, check to see what hal shows on the > ovirt-appliance. That also uses virtio disks. If hal detects virtio > disks in the appliance but not in the Node it could be something we > broke. If it doesn't show up in the appliance either, then it's probably > an upstream regression in hal. I think the problem might be that the virt disk has the property "volume.ignore" set to "true". Hal sees the partitions themselves and they do *not* have "volume.ignore" set. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From pmyers at redhat.com Wed Jan 7 17:20:22 2009 From: pmyers at redhat.com (Perry Myers) Date: Wed, 07 Jan 2009 12:20:22 -0500 Subject: [Ovirt-devel] [PATCH node] Moved functionality to o-process-config. In-Reply-To: <1229724703-21914-1-git-send-email-dpierce@redhat.com> References: <1229724703-21914-1-git-send-email-dpierce@redhat.com> Message-ID: <4964E456.10302@redhat.com> Darryl L. Pierce wrote: > Code to copy the network configuration files to the config partition and > to restart the network service have been moved out of ovirt-early and > into ovirt-process-config. This will allow the script to be reuseable. Conceptual Ack... If this has been adequately tested go ahead and push it. Perry > Signed-off-by: Darryl L. Pierce > --- > scripts/ovirt-early | 20 +++++--------------- > scripts/ovirt-process-config | 16 ++++++++++++++++ > 2 files changed, 21 insertions(+), 15 deletions(-) > > diff --git a/scripts/ovirt-early b/scripts/ovirt-early > index 8bf8928..2d2a96d 100755 > --- a/scripts/ovirt-early > +++ b/scripts/ovirt-early > @@ -44,21 +44,11 @@ configure_from_network() { > if [ $? -eq 0 ]; then > echo "Remote configuration bundle retrieved to $cfgdb" > ovirt-process-config $cfgdb $BONDING_MODCONF_FILE $AUGTOOL_CONFIG > - if [ -f $AUGTOOL_CONFIG ]; then > - echo "Loading remote config" > - # avoid bindmount issues with augeas > - umount_config /etc/sysconfig/network-scripts/ifcfg-eth* > - augtool < $AUGTOOL_CONFIG \ > - && echo "Remote config applied" \ > - || echo "Failed applying remote config" > - fi > - if ls /etc/sysconfig/network-scripts/ifcfg-eth* > /dev/null 2>&1; then > - echo "Network interfaces created from remote config" > - ovirt_store_config /etc/sysconfig/network-scripts/ifcfg-eth* > - return > - else > - echo "Remote config contained no network interfaces" > - fi > + if [ $? -eq 0 ]; then > + echo "Remote configuration retrieved and applied" > + else > + echo "Failure to retrieve or apply remote configuration" > + fi > else > echo "Failed to retrieve configuration bundle" > fi > diff --git a/scripts/ovirt-process-config b/scripts/ovirt-process-config > index 48068ef..8641fa0 100755 > --- a/scripts/ovirt-process-config > +++ b/scripts/ovirt-process-config > @@ -1,4 +1,9 @@ > #!/bin/bash > +# > +# Takes as input a reference to an encoded configuration file > +# and produces from that a kernel module file and a network > +# configuration file. It then restarts the networking service > +# and saves the configuration files. > > ME=$(basename "$0") > warn() { printf '%s: %s\n' "$ME" "$*" >&2; } > @@ -58,3 +63,14 @@ networking=$(awk '/^[ \t]*ifcfg=/ { > }' $CONFIG) > > echo "$networking" > $OVIRT_CONFIG_OUTPUT_FILE > + > +if [ -f $OVIRT_CONFIG_OUTPUT_FILE ]; then > + umount_config /etc/sysconfig/network-scripts/ifcfg* > + augtool < $OVIRT_CONFIG_OUTPUT_FILE \ > + && RESULT=0 || RESULT=1 > + if ls /etc/sysconfig/network-scripts/ifcfg* > /dev/null >2&1; then > + ovirt_store_config /etc/sysconfig/network-scripts/ifcfg* > + fi > +fi > + > +exit $RESULT -- |=- Red Hat, Engineering, Emerging Technologies, Boston -=| |=- Email: pmyers at redhat.com -=| |=- Office: +1 412 474 3552 Mobile: +1 703 362 9622 -=| |=- GnuPG: E65E4F3D 88F9 F1C9 C2F3 1303 01FE 817C C5D2 8B91 E65E 4F3D -=| From dpierce at redhat.com Wed Jan 7 18:52:57 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 7 Jan 2009 13:52:57 -0500 Subject: [Ovirt-devel] [PATCH node] Use gpt if running on Fedora, otherwise use msdos. Message-ID: <1231354377-6016-1-git-send-email-dpierce@redhat.com> When creating the label when partitioning a drive, o-c-storage looks to see if it's running in Fedora. If so then it uses gpt. Otherwise it defaults to using msdos to have an MBR. Signed-off-by: Darryl L. Pierce --- scripts/ovirt-config-storage | 14 ++++++++++++-- 1 files changed, 12 insertions(+), 2 deletions(-) diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage index 78e56dc..2167df7 100755 --- a/scripts/ovirt-config-storage +++ b/scripts/ovirt-config-storage @@ -190,15 +190,18 @@ perform_partitioning() # ensure minimal BOOT partition BOOT_SIZE=10 fi - parted $DRIVE -s "mklabel gpt" + parted $DRIVE -s "mklabel ${LABEL_TYPE}" parted $DRIVE -s "mkpartfs primary ext2 0M ${BOOT_SIZE}M" parted $DRIVE -s "mkpart primary ext2 ${BOOT_SIZE}M ${SPACE}M" parted $DRIVE -s "set 1 boot on" parted $DRIVE -s "set 2 lvm on" parted $DRIVE -s "print" udevadm settle 2> /dev/null || udevsettle + # sync GPT to the legacy MBR partitions - gptsync $DRIVE + if [ "gpt" == "$LABEL_TYPE" ]; then + gptsync $DRIVE + fi pvcreate "${DRIVE}2" pvck @@ -296,6 +299,13 @@ if [ -n "$OVIRT_INIT" ]; then get_selected_drive_size fi +# if the node is Fedora then use GPT, otherwise use MBR +if [ -f /etc/fedora-release ]; then + LABEL_TYPE="gpt" +else + LABEL_TYPE="msdos" +fi + if [ "$1" == "AUTO" ]; then check_partition_sizes printf "Partitioning hard disk..." -- 1.6.0.6 From dpierce at redhat.com Wed Jan 7 21:50:03 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 7 Jan 2009 16:50:03 -0500 Subject: [Ovirt-devel] [PATCH node] Fix o-c-networking to only show physical networking devices. Message-ID: <1231365003-19872-1-git-send-email-dpierce@redhat.com> Only those devices which have a physical layer are presented for configuration. Signed-off-by: Darryl L. Pierce --- scripts/ovirt-config-networking | 11 ++++++++++- 1 files changed, 10 insertions(+), 1 deletions(-) diff --git a/scripts/ovirt-config-networking b/scripts/ovirt-config-networking index 6609d0a..c322868 100755 --- a/scripts/ovirt-config-networking +++ b/scripts/ovirt-config-networking @@ -153,7 +153,16 @@ function configure_interface function setup_menu { - NICS=$(hal-device | awk '/net.interface/ {match($0, "= '"'"'(.*)'"'"' ", nic); printf("%s ", nic[1]); }') + udi_list=$(hal-device | awk '/net.interface/ {match($0, "= '"'"'(.*)'"'"' ", nic); printf("%s ", nic[1]); }') + udi_list=$(hal-find-by-capability --capability net.80203 && hal-find-by-capability --capability net.80211) + if [ -z "$udi_list" ]; then + warn "ERROR: no usable network devices were found" + exit 1 + fi + + NICS="" + for d in $udi_list; do NICS="$NICS $(hal-get-property --udi "$d" --key net.interface)"; done + NICS="$NICS Save Quit" PS3="Please select a network interface to configure: " } -- 1.6.0.6 From dpierce at redhat.com Wed Jan 7 21:55:42 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 7 Jan 2009 16:55:42 -0500 Subject: [Ovirt-devel] [PATCH node] Fix o-c-networking to only show physical networking devices. Message-ID: <1231365342-20400-1-git-send-email-dpierce@redhat.com> NOTE: This patch supercedes the previous one which had a line of code in it that, while not affecting functionality, didn't need to be there. Only those devices which have a physical layer are presented for configuration. Signed-off-by: Darryl L. Pierce --- scripts/ovirt-config-networking | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) diff --git a/scripts/ovirt-config-networking b/scripts/ovirt-config-networking index 6609d0a..8b8879e 100755 --- a/scripts/ovirt-config-networking +++ b/scripts/ovirt-config-networking @@ -153,7 +153,15 @@ function configure_interface function setup_menu { - NICS=$(hal-device | awk '/net.interface/ {match($0, "= '"'"'(.*)'"'"' ", nic); printf("%s ", nic[1]); }') + udi_list=$(hal-find-by-capability --capability net.80203 && hal-find-by-capability --capability net.80211) + if [ -z "$udi_list" ]; then + warn "ERROR: no usable network devices were found" + exit 1 + fi + + NICS="" + for d in $udi_list; do NICS="$NICS $(hal-get-property --udi "$d" --key net.interface)"; done + NICS="$NICS Save Quit" PS3="Please select a network interface to configure: " } -- 1.6.0.6 From dpierce at redhat.com Wed Jan 7 22:01:22 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 7 Jan 2009 17:01:22 -0500 Subject: [Ovirt-devel] [PATCH node] Fix o-c-networking to only show physical networking devices. Message-ID: <1231365682-20891-1-git-send-email-dpierce@redhat.com> NOTE: Removed the 802.11 iface portion. Now only wired NICs are reported. Only those devices which have a physical layer are presented for configuration. Signed-off-by: Darryl L. Pierce --- scripts/ovirt-config-networking | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) diff --git a/scripts/ovirt-config-networking b/scripts/ovirt-config-networking index 6609d0a..52af071 100755 --- a/scripts/ovirt-config-networking +++ b/scripts/ovirt-config-networking @@ -153,7 +153,15 @@ function configure_interface function setup_menu { - NICS=$(hal-device | awk '/net.interface/ {match($0, "= '"'"'(.*)'"'"' ", nic); printf("%s ", nic[1]); }') + udi_list=$(hal-find-by-capability --capability net.80203) + if [ -z "$udi_list" ]; then + warn "ERROR: no usable network devices were found" + exit 1 + fi + + NICS="" + for d in $udi_list; do NICS="$NICS $(hal-get-property --udi "$d" --key net.interface)"; done + NICS="$NICS Save Quit" PS3="Please select a network interface to configure: " } -- 1.6.0.6 From imain at redhat.com Wed Jan 7 23:53:02 2009 From: imain at redhat.com (Ian Main) Date: Wed, 7 Jan 2009 15:53:02 -0800 Subject: [Ovirt-devel] [PATCH server] Rake task to generate a dot drawing of the possible VM states In-Reply-To: <1231290440.23032.17.camel@localhost.localdomain> References: <1231290440.23032.17.camel@localhost.localdomain> Message-ID: <20090107155302.7afcfdf0@tp.mains.net> On Tue, 06 Jan 2009 17:07:20 -0800 David Lutterkort wrote: > I was curious what all the VM state transitions taken together look like > - below is a rake task that generates a dot drawing of the FSM of VM > states. > > Attached is a picture of all that for everybody's amusement. > > David Wow, that's pretty neat! Pretty graph. I must say however that these states don't really reflect the states provided by libvirt. Libvirt has no sense of intermediate states like 'starting', 'migrating' etc. There's also no distinction regarding 'saved' state vs stopped. 'saved' is merely a stopped vm that has had an image taken of it. I know the 'starting' etc. is mostly for user feedback and also to prevent race conditions where you can try to start a vm multiple times. However while testing the taskomatic changes I was able to queue 5 or so 'start_vm' tasks just because the UI was slow to update (I kept pressing the button and it lagged but queued them all). So anyway, I'm not sure about these intermediate states, and the 'saved' state is actually broken.. something we'll have to remember to fix. The intermediate states present a problem in that you can get out of sync with what db-omatic and even taskomatic know the real libvirt state to be if you are not careful. Ian From lutter at redhat.com Thu Jan 8 01:53:22 2009 From: lutter at redhat.com (David Lutterkort) Date: Wed, 07 Jan 2009 17:53:22 -0800 Subject: [Ovirt-devel] [PATCH server] Rake task to generate a dot drawing of the possible VM states In-Reply-To: <20090107155302.7afcfdf0@tp.mains.net> References: <1231290440.23032.17.camel@localhost.localdomain> <20090107155302.7afcfdf0@tp.mains.net> Message-ID: <1231379602.4106.72.camel@localhost.localdomain> On Wed, 2009-01-07 at 15:53 -0800, Ian Main wrote: > On Tue, 06 Jan 2009 17:07:20 -0800 > David Lutterkort wrote: > > > I was curious what all the VM state transitions taken together look like > > - below is a rake task that generates a dot drawing of the FSM of VM > > states. > > > > Attached is a picture of all that for everybody's amusement. > > > > David > > Wow, that's pretty neat! Pretty graph. > > I must say however that these states don't really reflect the states provided > by libvirt. Libvirt has no sense of intermediate states like 'starting', 'migrating' > etc. Yes, with moving to qpid, tracking the VM state will become even more difficult, even if it becomes more accurate, since VM state (in the UI sense) is composed of both the VM state reported from libvirt and some information in the DB. I've already seen at least one bug caused by this: if you start a VM ona node, then pull the power on that node, you can't start that VM again, since the DB still associates that VM with the dead node, and task-o-matic decides that that means that the VM is already running. Maybe we should simplify the VM model and get rid of the intermediate states ('stating', 'migrating', etc.) and just change the VM state to the success state for the action as soon as we send the message to start, migrate, etc. After all, the 'starting' -> 'running' transition is not very meaningful for the user - to them the VM is only running way after libvirt started the VM (e.g., when httpd or sshd starts in the boot sequence) > There's also no distinction regarding 'saved' state vs stopped. 'saved' is > merely a stopped vm that has had an image taken of it. That's one case where I don't see a good way to get away from determining state based on libvirt + other info .. maybe if we got rid of 'saved' in favor of 'stopped' and offered separate 'start VM from scratch' and 'start VM from saved image' actions ? > I know the 'starting' etc. is mostly for user feedback and also to prevent race > conditions where you can try to start a vm multiple times. However while testing > the taskomatic changes I was able to queue 5 or so 'start_vm' tasks just because > the UI was slow to update (I kept pressing the button and it lagged but queued > them all). It should be possible to provide user feedback with an additional flag, something like 'task_in_progress', though it makes task-o-matic's job a little harder, since it needs to maintain that. > So anyway, I'm not sure about these intermediate states, and the 'saved' state is > actually broken.. something we'll have to remember to fix. The intermediate states > present a problem in that you can get out of sync with what db-omatic and even > taskomatic know the real libvirt state to be if you are not careful. I agree. I think a model where VM states map directly to libvirt states together with additional flags to support the UI would simplify matters. David From ccurran at redhat.com Thu Jan 8 06:53:59 2009 From: ccurran at redhat.com (Christopher Curran) Date: Thu, 08 Jan 2009 16:53:59 +1000 Subject: [Ovirt-devel] [PATCH node] Updating menu labels Message-ID: <4965A307.1040009@redhat.com> Can we use the word 'stand-alone' over 'standalone'. I know google will disagree with me but style guides and dictionaries support the stand-alone spelling. This is mainly to make my life easier by sticking to one consistent style. Here is a patch to fix it. Chris --- ovirt-node.spec.in | 2 +- scripts/ovirt-config-setup | 4 ++-- scripts/ovirt-early | 2 +- scripts/ovirt-firstboot | 2 +- scripts/ovirt-functions | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in index 8133076..668d86e 100644 --- a/ovirt-node.spec.in +++ b/ovirt-node.spec.in @@ -281,7 +281,7 @@ fi * Thu Dec 11 2008 Perry Myers - 0.96 - Subpackage stateful/stateless to separate out functionality for embedded Node and Node running as part of already installed OS -- ovirt-config-* setup scripts for standalone mode +- ovirt-config-* setup scripts for stand-alone mode * Thu Sep 11 2008 Chris Lalancette - 0.92 0.7 - Add the ovirt-install- and ovirt-uninstall-node scripts, and refactor diff --git a/scripts/ovirt-config-setup b/scripts/ovirt-config-setup index 20dd5ae..a9d7893 100755 --- a/scripts/ovirt-config-setup +++ b/scripts/ovirt-config-setup @@ -1,6 +1,6 @@ #!/bin/bash # -# Entry point for configuring an oVirt node when running in standalone mode. +# Entry point for configuring an oVirt node when running in stand-alone mode. NETWORK="Networking Setup" STORAGE="Disk Partitioning" @@ -22,7 +22,7 @@ reset > /dev/null clear while true; do - printf "\n oVirt Node Standalone Configuration\n\n" + printf "\n oVirt Node stand-alone mode configuration menu\n\n" PS3="Please select an option: " diff --git a/scripts/ovirt-early b/scripts/ovirt-early index 8bf8928..21f98a4 100755 --- a/scripts/ovirt-early +++ b/scripts/ovirt-early @@ -166,7 +166,7 @@ start() { local_boot=0 # ovirt_standalone - # force oVirt Node standalone mode + # force oVirt Node stand-alone mode standalone=0 # pxelinux format: ip=::: diff --git a/scripts/ovirt-firstboot b/scripts/ovirt-firstboot index da03b98..509ed08 100755 --- a/scripts/ovirt-firstboot +++ b/scripts/ovirt-firstboot @@ -60,7 +60,7 @@ start () fi disable_firstboot - # persist config for standalone + # persist config for stand-alone mode ovirt_store_config \ /etc/sysconfig/network-scripts/ifcfg-* \ /etc/rsyslog.conf \ diff --git a/scripts/ovirt-functions b/scripts/ovirt-functions index e20bab9..1f440c4 100644 --- a/scripts/ovirt-functions +++ b/scripts/ovirt-functions @@ -14,13 +14,13 @@ OVIRT_STANDALONE=${OVIRT_STANDALONE:-0} OVIRT_BACKUP_DIR=/var/lib/ovirt-backup -# return 1 if oVirt Node is running in standalone mode +# return 1 if oVirt Node is running in stand-alone mode # return 0 if oVirt Node is managed by the oVirt Server is_managed() { return $OVIRT_STANDALONE } -# oVirt Node in standalone mode does not try to contact the oVirt Server +# oVirt Node in stand-alone mode does not try to contact the oVirt Server is_standalone() { if is_managed; then return 1; else return 0; fi } @@ -58,7 +58,7 @@ is_firstboot() { # if [ -n "$SRV_HOST" -a -n "$SRV_PORT" ]; then # echo "oVirt Server found" # else -# echo "no oVirt Server available, running standalone" +# echo "no oVirt Server available, running in stand-alone mode" # fi find_srv() { -- 1.6.0.6 From ccurran at redhat.com Thu Jan 8 06:59:14 2009 From: ccurran at redhat.com (Christopher Curran) Date: Thu, 08 Jan 2009 16:59:14 +1000 Subject: [Ovirt-devel] [PATCH node] Updating menu labels In-Reply-To: <4965A307.1040009@redhat.com> References: <4965A307.1040009@redhat.com> Message-ID: <4965A442.3090601@redhat.com> Christopher Curran wrote: > Can we use the word 'stand-alone' over 'standalone'. I know google > will disagree with me but style guides and dictionaries support the > stand-alone spelling. This is mainly to make my life easier by > sticking to one consistent style. Here is a patch to fix it. > > Stupid email clients... This one should work --- ovirt-node.spec.in | 2 +- scripts/ovirt-config-setup | 4 ++-- scripts/ovirt-early | 2 +- scripts/ovirt-firstboot | 2 +- scripts/ovirt-functions | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in index 8133076..668d86e 100644 --- a/ovirt-node.spec.in +++ b/ovirt-node.spec.in @@ -281,7 +281,7 @@ fi * Thu Dec 11 2008 Perry Myers - 0.96 - Subpackage stateful/stateless to separate out functionality for embedded Node and Node running as part of already installed OS -- ovirt-config-* setup scripts for standalone mode +- ovirt-config-* setup scripts for stand-alone mode * Thu Sep 11 2008 Chris Lalancette - 0.92 0.7 - Add the ovirt-install- and ovirt-uninstall-node scripts, and refactor diff --git a/scripts/ovirt-config-setup b/scripts/ovirt-config-setup index 20dd5ae..a9d7893 100755 --- a/scripts/ovirt-config-setup +++ b/scripts/ovirt-config-setup @@ -1,6 +1,6 @@ #!/bin/bash # -# Entry point for configuring an oVirt node when running in standalone mode. +# Entry point for configuring an oVirt node when running in stand-alone mode. NETWORK="Networking Setup" STORAGE="Disk Partitioning" @@ -22,7 +22,7 @@ reset > /dev/null clear while true; do - printf "\n oVirt Node Standalone Configuration\n\n" + printf "\n oVirt Node stand-alone mode configuration menu\n\n" PS3="Please select an option: " diff --git a/scripts/ovirt-early b/scripts/ovirt-early index 8bf8928..21f98a4 100755 --- a/scripts/ovirt-early +++ b/scripts/ovirt-early @@ -166,7 +166,7 @@ start() { local_boot=0 # ovirt_standalone - # force oVirt Node standalone mode + # force oVirt Node stand-alone mode standalone=0 # pxelinux format: ip=::: diff --git a/scripts/ovirt-firstboot b/scripts/ovirt-firstboot index da03b98..509ed08 100755 --- a/scripts/ovirt-firstboot +++ b/scripts/ovirt-firstboot @@ -60,7 +60,7 @@ start () fi disable_firstboot - # persist config for standalone + # persist config for stand-alone mode ovirt_store_config \ /etc/sysconfig/network-scripts/ifcfg-* \ /etc/rsyslog.conf \ diff --git a/scripts/ovirt-functions b/scripts/ovirt-functions index e20bab9..1f440c4 100644 --- a/scripts/ovirt-functions +++ b/scripts/ovirt-functions @@ -14,13 +14,13 @@ OVIRT_STANDALONE=${OVIRT_STANDALONE:-0} OVIRT_BACKUP_DIR=/var/lib/ovirt-backup -# return 1 if oVirt Node is running in standalone mode +# return 1 if oVirt Node is running in stand-alone mode # return 0 if oVirt Node is managed by the oVirt Server is_managed() { return $OVIRT_STANDALONE } -# oVirt Node in standalone mode does not try to contact the oVirt Server +# oVirt Node in stand-alone mode does not try to contact the oVirt Server is_standalone() { if is_managed; then return 1; else return 0; fi } @@ -58,7 +58,7 @@ is_firstboot() { # if [ -n "$SRV_HOST" -a -n "$SRV_PORT" ]; then # echo "oVirt Server found" # else -# echo "no oVirt Server available, running standalone" +# echo "no oVirt Server available, running in stand-alone mode" # fi find_srv() { -- 1.6.0.6 From berrange at redhat.com Thu Jan 8 10:36:56 2009 From: berrange at redhat.com (Daniel P. Berrange) Date: Thu, 8 Jan 2009 10:36:56 +0000 Subject: [Ovirt-devel] [PATCH server] Rake task to generate a dot drawing of the possible VM states In-Reply-To: <1231379602.4106.72.camel@localhost.localdomain> References: <1231290440.23032.17.camel@localhost.localdomain> <20090107155302.7afcfdf0@tp.mains.net> <1231379602.4106.72.camel@localhost.localdomain> Message-ID: <20090108103655.GA26474@redhat.com> On Wed, Jan 07, 2009 at 05:53:22PM -0800, David Lutterkort wrote: > > Yes, with moving to qpid, tracking the VM state will become even more > difficult, even if it becomes more accurate, since VM state (in the UI > sense) is composed of both the VM state reported from libvirt and some > information in the DB. > > I've already seen at least one bug caused by this: if you start a VM ona > node, then pull the power on that node, you can't start that VM again, > since the DB still associates that VM with the dead node, and > task-o-matic decides that that means that the VM is already running. Fundamentally any 'VM state' information is always potentially out of date, no matter where you got it from, because there's always some delay between the state being queried, and oVirt looking at the returned state data. Obviously getting it from libvirt directly every time will reduce the liklihood that its out of date, but you still have a non-negligle chance of it being out of date by time you act on it. Therefore, taskomatic needs to be aware of this potential inaccuracy and be able to take appropriate cleanup/workarounds upon failure if appropriate > > There's also no distinction regarding 'saved' state vs stopped. 'saved' is > > merely a stopped vm that has had an image taken of it. > > That's one case where I don't see a good way to get away from > determining state based on libvirt + other info .. maybe if we got rid > of 'saved' in favor of 'stopped' and offered separate 'start VM from > scratch' and 'start VM from saved image' actions ? As well as the explicit 'current' states you get from libvirt by querying th virDomainGetInfo method, you can also now get event notifications upon state transitions. These let you also get info on why the state transition has occurred. eg, you'll get a event notifying that the VM transitioned to the state 'stopped', and it'll tell you whether this was because - Graceful shutdown - Force VM destroy - Outgoing migration completed - Save to file operation completed - Device emulation (ie QEMU) failed unexpected Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| From bkearney at redhat.com Thu Jan 8 16:40:40 2009 From: bkearney at redhat.com (Bryan Kearney) Date: Thu, 8 Jan 2009 11:40:40 -0500 Subject: [Ovirt-devel] Installer Patch works off of earlier patches Message-ID: <1231432841-22601-1-git-send-email-bkearney@redhat.com> This patch works off the earlier installer patches. It adds better validation, default value, and makes use of the ruby built in templating. From bkearney at redhat.com Thu Jan 8 16:40:41 2009 From: bkearney at redhat.com (Bryan Kearney) Date: Thu, 8 Jan 2009 11:40:41 -0500 Subject: [Ovirt-devel] [PATCH server] Rework the installer to add validation, file generation by templates, and default values In-Reply-To: <1231432841-22601-1-git-send-email-bkearney@redhat.com> References: <1231432841-22601-1-git-send-email-bkearney@redhat.com> Message-ID: <1231432841-22601-2-git-send-email-bkearney@redhat.com> --- installer/bin/ovirt-installer | 421 ++++++++++++++++++++++------------------- 1 files changed, 226 insertions(+), 195 deletions(-) diff --git a/installer/bin/ovirt-installer b/installer/bin/ovirt-installer index 84604ef..7ae789d 100755 --- a/installer/bin/ovirt-installer +++ b/installer/bin/ovirt-installer @@ -22,252 +22,283 @@ require 'socket' require 'fileutils' +require 'erb' -if File.exist?("/usr/sbin/sestatus") -sestatus = `/usr/sbin/sestatus` -if sestatus !~ /(Current mode: permissive|Current mode: disabled|SELinux status: disabled|SELinux status: permissive)/ -puts "SELinux enabled, please disable or set in permissive mode permanently by editing" -puts "/etc/selinux/config and rebooting" -exit -end -end - -FileUtils.mkdir_p("/usr/share/ace/appliances/ovirt") -config_file = File.new("/usr/share/ace/appliances/ovirt/ovirt.pp", "w") -config_file.write "import 'ovirt'\n" -config_file.write "import 'firewall'\n\n" -config_file.write "firewall::setup{'setup': status => 'disabled'}\n\n" - -mgmt_dev = "" -prov_dev = "" - -dev_ct = 0 -net_devs = `hal-find-by-capability --capability net` -net_devs.each_line{ |dev| -dev_ct = dev_ct + 1 -} - -if dev_ct == 0 -puts "Unable to install without a network interface" -exit +# +# Input output controls +# -else -puts "" -get_net_devs = `hal-find-by-capability --capability net` -puts "Below are the detected networking devices\n\n" -puts "mac address interface ip address" -net_devs.each_line{ |dev| -dev = dev.chomp -interface = `hal-get-property --udi #{dev} --key net.interface` -mac = `hal-get-property --udi #{dev} --key net.address` -ip = `ifconfig #{interface}` -ipaddr = ip.scan(/\s*inet addr:([\d.]+)/) -puts mac.chop + " : " + interface.chop + " : " + ipaddr.to_s if interface.chop != "lo" -} +# Basic read logic +def read_user_input(prompt) + print("\n#{prompt} ") + return gets.chomp end -if dev_ct > 1 -puts "\nDo you want separate management and provisioning networks? (y/n)" -sep_networks = gets.chomp -while sep_networks != "y" and sep_networks != "n" -puts "Invalid choice" -puts "Do you want separate management and provisioning networks? (y/n)" -sep_networks = gets.chomp +# prompt a user for a non-blank answer +def prompt_for_answer(prompt, options={}) + default = options[:default] + allow_blanks = options[:allow_blanks] ? options[:allow_blanks] : false + expression = options[:regex] + validate = !expression.nil? + + if !default.nil? + prompt = "#{prompt} [#{default}]" + end + + answer = read_user_input(prompt) + answer = default if (!default.nil? && answer == "") + + if (answer == "" and ! allow_blanks) + puts("Plese enter a value") + answer = prompt_for_answer(prompt, options) + end + + if (validate && answer !~ expression) + puts("That is not in the correct format") + answer = prompt_for_answer(prompt, options) + end + + return answer end -if sep_networks == "y" -while mgmt_dev == "" -puts "Input your management interface (example: eth0)" -mgmt_dev = gets.chomp +# Allow a user to enter a Yes/No +# And repeat the prompt until they do +def prompt_yes_no(prompt, options={}) + default = options[:default] + + if default.nil? + prompt = "#{prompt} (y/n)" + else + prompt = "#{prompt} [#{default}]" + end + answer = read_user_input(prompt) + answer = default if (!default.nil? && answer == "") + answer = answer.downcase() + while answer != "y" and answer != "n" + puts("Invalid choice") + answer = read_user_input(prompt).downcase() + end + + return answer end -while prov_dev == "" -puts "Input your provisioning interface, this may also be your management interface (example: eth1)" -prov_dev = gets.chomp +# +# The real script begins here +# + +# These regular expressions will be used to +# validate the user input +IP = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ +THREE_OCTETS = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){2}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ +FQDN = /(?=^.{1,254}$)(^(?:(?!\d+\.)[a-zA-Z0-9_\-]{1,63}\.?)+(?:[a-zA-Z]{2,})$)/ +IP_OR_FQDN = /(?=^.{1,254}$)(^((?:(?!\d+\.)[a-zA-Z0-9_\-]{1,63}\.?)+(?:[a-zA-Z]{2,})|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))$)/ +OCTET = /^([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$/ + +# Print a friendly welcome message +welcome = "This installer will configure the ovirt installation based on a series\n\ +of questions. When complete, you will be asked to install oVirt or\n\ +do the installation manually. Would you like to continue?" + +if (prompt_yes_no(welcome, :default => "y") == "n") + exit(0) end -elsif sep_networks == "n" -while mgmt_dev == "" -puts "Input your management/provisioning interface (example: eth1)" -mgmt_dev = gets.chomp -prov_dev = mgmt_dev -end + +if File.exist?("/usr/sbin/sestatus") + sestatus = `/usr/sbin/sestatus` + if sestatus !~ /(Current mode: permissive|Current mode: disabled|SELinux status: disabled|SELinux status: permissive)/ + puts "SELinux enabled, please disable or set in permissive mode permanently by editing" + puts "/etc/selinux/config and rebooting" + exit + end end -elsif dev_ct == 1 -while mgmt_dev == "" -puts "\nOnly one networking device detected" -puts "Input your management/provisioning interface (example: eth1)" -mgmt_dev = gets.chomp -prov_dev = mgmt_dev -puts "Need Management interface" +# Networking Configuration +dev_ct = 0 +net_devs = `hal-find-by-capability --capability net` +net_devs.each_line do |dev| + dev_ct = dev_ct + 1 end + +if dev_ct == 0 + puts "Unable to install without a network interface" + exit +else + puts "" + get_net_devs = `hal-find-by-capability --capability net` + puts "Below are the detected networking devices\n\n" + puts "mac address interface ip address" + net_devs.each_line do |dev| + dev = dev.chomp + interface = `hal-get-property --udi #{dev} --key net.interface` + mac = `hal-get-property --udi #{dev} --key net.address` + ip = `ifconfig #{interface}` + ipaddr = ip.scan(/\s*inet addr:([\d.]+)/) + puts mac.chop + " : " + interface.chop + " : " + ipaddr.to_s if interface.chop != "lo" + end end -puts "Enter the hostname of the oVirt management server (example: management.example.com)" -ovirt_host = gets.chomp +mgmt_dev = prompt_for_answer("Enter your management interface (example: eth0):") +prov_dev = prompt_for_answer("Enter your provisioning interface, this may also be your management interface:", :default => mgmt_dev) + +sep_networks = (mgmt_dev == prov_dev) ? "n" : "y" + +ovirt_host = prompt_for_answer("Enter the hostname of the oVirt management server (example: management.example.com):", :regex => IP_OR_FQDN) ipa_host = ovirt_host -puts "\nUse this system's dns servers (y/n)" +# DNS Configuration +puts "\nThe following DNS servers were found:" File.open('/etc/resolv.conf').each_line{ |line| line = line.chomp -puts line if line =~ /nameserver/ and line !~ /nameserver 127.0.0.1/ + puts line if line =~ /nameserver/ and line !~ /nameserver 127.0.0.1/ } -dns_servers = gets.chomp - -while dns_servers != "y" and dns_servers != "n" -puts "Invalid choice" -dns_servers = gets.chomp -end +dns_servers = prompt_yes_no("Use this systems's dns servers?") mgmt_ip = `ifconfig #{mgmt_dev}` mgmt_ipaddr= mgmt_ip.scan(/\s*inet addr:([\d.]+)/) prov_ip = `ifconfig #{prov_dev}` prov_ipaddr= prov_ip.scan(/\s*inet addr:([\d.]+)/) -config_file.write "# dns configuration\n" -config_file.write "$mgmt_ipaddr = '#{mgmt_ipaddr}'\n" -config_file.write "$prov_ipaddr = '#{prov_ipaddr}'\n" -config_file.write "$ovirt_host = '#{ovirt_host}'\n" -config_file.write "$ipa_host = '#{ipa_host}'\n\n" - -if dns_servers == "n" -config_file.write "dns::bundled{setup: mgmt_ipaddr=> $mgmt_ipaddr, prov_ipaddr=> $prov_ipaddr, mgmt_dev => '#{mgmt_dev}', prov_dev => '#{prov_dev}'}\n\n" -end - if dns_servers == "y" -config_file.write "dns::remote{setup: mgmt_ipaddr=> $mgmt_ipaddr, prov_ipaddr=> $prov_ipaddr, mgmt_dev => '#{mgmt_dev}', prov_dev => '#{prov_dev}'}\n\n" -host_lookup = Socket.getaddrinfo(ipa_host,nil) -hostip = host_lookup[1][3] -if hostip.to_s != mgmt_ipaddr.to_s -puts "Reverse dns lookup for #{ipa_host} failed, exiting" -exit -end -end - -puts "Does you provisioning network already have dhcp? (y/n)" -dhcp_setup = gets.chomp -while dhcp_setup != "y" and dhcp_setup != "n" -puts "Invalid choice" -dhcp_setup = gets.chomp + host_lookup = Socket.getaddrinfo(ipa_host,nil) + hostip = host_lookup[1][3] + if hostip.to_s != mgmt_ipaddr.to_s + puts "Reverse dns lookup for #{ipa_host} failed, exiting" + exit + end end +# DHCP Configuration +dhcp_setup = prompt_yes_no("Does your provisioning network already have dhcp?") if dhcp_setup == "n" - -puts "DHCP Configuration\n" -config_file.write "# dhcp configuration\n" -dhcp_interface = prov_dev -config_file.write "$dhcp_interface = '#{dhcp_interface}'\n" - -puts "Enter the first 3 octets of the dhcp network you wish to use (example: 192.168.50)" -dhcp_network = gets.chomp -config_file.write "$dhcp_network = '#{dhcp_network}'\n" - -puts "Enter the dhcp pool start address (example: 3)" -dhcp_start = gets.chomp -config_file.write "$dhcp_start = '#{dhcp_start}'\n" - -puts "Enter the dhcp pool end addess (example: 100)" -dhcp_stop = gets.chomp -config_file.write "$dhcp_stop = '#{dhcp_stop}'\n" - -puts "Enter the dhcp domain you wish to use (example: example.com)" -dhcp_domain = gets.chomp -config_file.write "$dhcp_domain = '#{dhcp_domain}'\n" - -config_file.write "$ntp_server = '#{mgmt_ipaddr}'\n\n" - -puts "Provide pxe/tftp capability? (y/n)" -tftp_setup = gets.chomp - -if sep_networks == "y" -prov_ip = `ifconfig #{prov_dev}` -prov_dns_server = prov_ip.scan(/\s*inet addr:([\d.]+)/) -config_file.write "$prov_dns_server = '#{prov_dns_server}'\n" - -puts "Enter the network gateway for your provisioning network (example: 192.168.50.254)" -prov_network_gateway = gets.chomp -config_file.write "$prov_network_gateway = '#{prov_network_gateway}'\n" -end + dhcp_interface = prov_dev + dhcp_network = prompt_for_answer("Enter the first 3 octets of the dhcp network you wish to use (example: 192.168.50):", :regex => THREE_OCTETS) + dhcp_start = prompt_for_answer("Enter the dhcp pool start address (example: 3):", :regex => OCTET) + dhcp_stop = prompt_for_answer("Enter the dhcp pool end addess (example: 100):", :regex => OCTET) + dhcp_domain = prompt_for_answer("Enter the dhcp domain you wish to use (example: example.com):", :regex => IP_OR_FQDN) + tftp_setup = prompt_yes_no("Provide pxe/tftp capability?") + + if sep_networks == "y" + prov_ip = `ifconfig #{prov_dev}` + prov_dns_server = prov_ip.scan(/\s*inet addr:([\d.]+)/) + prov_network_gateway = prompt_for_answer("Enter the network gateway for your provisioning network (example: 192.168.50.254):", :regex => IP_OR_FQDN) + end end # Cobbler Configuration -puts "Do you have a cobbler already that you wish to use? (y/n)" -cobbler_setup = gets.chomp - -while cobbler_setup != "y" and cobbler_setup != "n" -puts "Invalid choice" -cobbler_setup = gets.chomp -end - -cobbler_config = "n" +cobbler_setup = prompt_yes_no("Do you have a cobbler already that you wish to use?") if cobbler_setup == "y" -puts "Enter the hostname of your cobbler server" -cobbler_hostname = gets.chomp -puts "Enter your cobbler username" -cobbler_user_name= gets.chomp -puts "Enter your cobbler user password" -cobbler_user_password = gets.chomp - + cobbler_hostname = prompt_for_answer("Enter the hostname of your cobbler server:", :regex => IP_OR_FQDN) elsif cobbler_setup == "n" -cobbler_hostname = "localhost" -puts "We will setup a cobbler instance, please provide the following information" -puts "Enter your cobbler username" -cobbler_user_name= gets.chomp -puts "Enter your cobbler user password" -cobbler_user_password = gets.chomp + cobbler_hostname = "localhost" + puts "\nWe will setup a cobbler instance, please provide the following information" end -config_file.write "# cobbler configuration\n" -config_file.write "$cobbler_hostname = '#{cobbler_hostname}'\n" -config_file.write "$cobbler_user_name = '#{cobbler_user_name}'\n" -config_file.write "$cobbler_user_password = '#{cobbler_user_password}'\n\n" - +cobbler_user_name= prompt_for_answer("Enter your cobbler username:") +cobbler_user_password = prompt_for_answer("Enter your cobbler user password:") # Postgres Configuration -puts "Enter a password for the ovirt postgres account" db_username = "ovirt" -db_password = gets.chomp -config_file.write "# postgres configuration\n" -config_file.write "$db_username = '#{db_username}'\n" -config_file.write "$db_password = '#{db_password}'\n\n" +db_password = prompt_for_answer("Enter a password for the ovirt postgres account:") # FreeIPA Configuration -config_file.write "# FreeIPA configuration\n" -puts "Enter your realm name (example: example.com)" -realm_name = gets.chomp -config_file.write "$realm_name = '#{realm_name}'\n" -puts "\nEnter an administrator password for FreeIPA " -puts "*** This will also be you ovirtadmin password for the web management login ***\n\n" -freeipa_password = gets.chomp -config_file.write "$freeipa_password = '#{freeipa_password}'\n" +realm_name = prompt_for_answer("Enter your realm name (example: example.com):", :regex => FQDN) + +freeipa_password = prompt_for_answer("NOTE: The following pasword will also be you ovirtadmin password for the web management login\n\ +Enter an administrator password for FreeIPA:") ldap_dn = "cn=ipaConfig,cn=etc," ldap_dn_temp = realm_name.split(".") ldap_dn_temp.each do |i| -ldap_dn += "dc=#{i}," + ldap_dn += "dc=#{i}," end ldap_dn = ldap_dn.chop -config_file.write "$ldap_dn = '#{ldap_dn}'\n\n" -if cobbler_setup == "y" -config_file.write "include cobbler::remote\n" -elsif cobbler_setup == "n" -config_file.write "include cobbler::bundled\n" -end +# +# Use ERB to spit out the puppet file whcih is used by ace. +# -if dhcp_setup == "n" -config_file.write "include dhcp::bundled\n" -end +# Create the template +template = < +# -if tftp_setup == "y" -config_file.write "include tftp::bundled\n" -end +import 'ovirt' +import 'firewall' +firewall::setup{'setup': + status => 'disabled' +} + +#DNS Configuration +$mgmt_ipaddr = '<%= mgmt_ipaddr %>' +$prov_ipaddr = '<%= prov_ipaddr %>' +$ovirt_host = '<%= ovirt_host %>' +$ipa_host = '<%= ipa_host %>' + +<% if dns_servers == "n" %> +dns::bundled{setup: +<% else %> +dns::remote{ +<% end %> + mgmt_ipaddr=> $mgmt_ipaddr, + prov_ipaddr=> $prov_ipaddr, + mgmt_dev => '<%= mgmt_dev %>', + prov_dev => '<%= prov_dev %>' +} + +# DHCP Configuration +<% if dhcp_setup == "n" %> +$dhcp_interface = '<%= dhcp_interface %>' +$dhcp_network = '<%= dhcp_network %>' +$dhcp_start = '<%= dhcp_start %>' +$dhcp_stop = '<%= dhcp_stop %>' +$dhcp_domain = '<%= dhcp_domain %>' +$ntp_server = '<%= mgmt_ipaddr %>' +<% if tftp_setup == "y" %> +include tftp::bundled +<% end %> +<% if sep_networks == "y" %> +$prov_dns_server = '<%= prov_dns_server %>' +$prov_network_gateway = '<%= prov_network_gateway %>' +<% end %> +<% end %> + + +# Cobbler configuration +$cobbler_hostname = '<%= cobbler_hostname %>' +$cobbler_user_name = '<%= cobbler_user_name %>' +$cobbler_user_password = '<%= cobbler_user_password %>' + +# Postgres Configuration +$db_username = '<%= db_username %>' +$db_password = '<%= db_password %>' + +# FreeIPA configuration +$realm_name = '<%= realm_name %>' +$freeipa_password = '<%= freeipa_password %>' +$ldap_dn = '<%= ldap_dn %>' + +<% if cobbler_setup == "n" %> +include cobbler::bundled +<% else %> +include cobbler::remote +<% end %> +<% if dhcp_setup == "n" %> +include dhcp::bundled +<% end %> +include postgres::bundled +include freeipa::bundled +include ovirt::setup +END_OF_TEMPLATE + +# Generate the file and output it. +FileUtils.mkdir_p("/usr/share/ace/appliances/ovirt") +config_file = File.new("/usr/share/ace/appliances/ovirt/ovirt.pp", "w") +config_file.write(ERB.new(template, 0, "%>").result) +config_file.close() -config_file.write "include postgres::bundled\n" -config_file.write "include freeipa::bundled\n" -config_file.write "include ovirt::setup\n" -config_file.close -puts "\n\nTo start the installation run: ace install ovirt" +# Give a friendly reminder about what to do next +puts "\nTo start the installation run: ace install ovirt" -- 1.6.0.6 From bkearney at redhat.com Thu Jan 8 18:30:27 2009 From: bkearney at redhat.com (Bryan Kearney) Date: Thu, 08 Jan 2009 13:30:27 -0500 Subject: [Ovirt-devel] [PATCH node] Updating menu labels In-Reply-To: <4965A442.3090601@redhat.com> References: <4965A307.1040009@redhat.com> <4965A442.3090601@redhat.com> Message-ID: <49664643.3050007@redhat.com> Christopher Curran wrote: > Christopher Curran wrote: >> Can we use the word 'stand-alone' over 'standalone'. I know google >> will disagree with me but style guides and dictionaries support the >> stand-alone spelling. This is mainly to make my life easier by >> sticking to one consistent style. Here is a patch to fix it. >> >> > Stupid email clients... This one should work ACK You may want to patch the kickstart in node-image as well.. so that the grub menu reflects your superior verbal style :) -- bk From sseago at redhat.com Thu Jan 8 18:43:29 2009 From: sseago at redhat.com (Scott Seago) Date: Thu, 8 Jan 2009 18:43:29 +0000 Subject: [Ovirt-devel] [PATCH] Add task list to dashboard Message-ID: <1231440209-26690-1-git-send-email-sseago@redhat.com> Refactored task list functionality to allow for the dashboard-level task list. The dashboard task list shows all tasks initiated by the logged-in user, and is filterable by task type and state. Signed-off-by: Scott Seago --- src/app/controllers/dashboard_controller.rb | 41 +++++++--- src/app/controllers/hardware_controller.rb | 12 +--- src/app/controllers/pool_controller.rb | 41 ++-------- src/app/controllers/task_actions.rb | 50 ++++++++++++ src/app/models/task.rb | 13 +++ src/app/views/dashboard/index.html.erb | 38 ++------- src/app/views/hardware/show_tasks.rhtml | 84 ++------------------ src/app/views/layouts/_navigation_tabs.rhtml | 20 ++++- src/app/views/resources/show_tasks.rhtml | 68 ++-------------- src/app/views/task/_grid.rhtml | 2 +- .../show_tasks.rhtml => task/_show.rhtml} | 57 +++++++------ 11 files changed, 169 insertions(+), 257 deletions(-) create mode 100644 src/app/controllers/task_actions.rb copy src/app/views/{hardware/show_tasks.rhtml => task/_show.rhtml} (59%) diff --git a/src/app/controllers/dashboard_controller.rb b/src/app/controllers/dashboard_controller.rb index c4830df..00398a5 100644 --- a/src/app/controllers/dashboard_controller.rb +++ b/src/app/controllers/dashboard_controller.rb @@ -18,19 +18,36 @@ # also available at http://www.gnu.org/copyleft/gpl.html. class DashboardController < ApplicationController + + include TaskActions + def tasks_query_obj + Task + end + def tasks_conditions + {:user => get_login_user} + end + def index - @default_pool = HardwarePool.get_default_pool - set_perms(@default_pool) - #remove these soon - @hardware_pools = HardwarePool.find(:all) - @available_hosts = Host.find(:all) - @available_storage_volumes = StorageVolume.find(:all) - @storage_pools = StoragePool.find(:all) - @hosts = Host.find(:all) - @storage_volumes = StorageVolume.find(:all) - @vms = Vm.find(:all) - if params[:ajax] - render :layout => 'tabs-and-content' #:template => 'hardware/show.html.erb' + @task_types = Task::TASK_TYPES_OPTIONS + show_tasks + end + + def show + respond_to do |format| + format.html { + render :layout => 'tabs-and-content' if params[:ajax] + render :layout => 'help-and-content' if params[:nolayout] + } + format.xml { + render :xml => @pool.to_xml(XML_OPTS) + } end end + + def tasks_internal + @task_type = params[:task_type] + @task_type ||="" + super + end + end diff --git a/src/app/controllers/hardware_controller.rb b/src/app/controllers/hardware_controller.rb index 4dda736..7be67cc 100644 --- a/src/app/controllers/hardware_controller.rb +++ b/src/app/controllers/hardware_controller.rb @@ -116,17 +116,7 @@ class HardwareController < PoolController end def show_tasks - @task_types = [["VM Task", "VmTask"], - ["Host Task", "HostTask"], - ["Storage Task", "StorageTask"], - ["Storage Volume Task", "StorageVolumeTask", "break"], - ["Show All", ""]] - super - end - - def tasks_internal - @task_type = params[:task_type] - @task_type ||="" + @task_types = Task::TASK_TYPES_OPTIONS super end diff --git a/src/app/controllers/pool_controller.rb b/src/app/controllers/pool_controller.rb index 03d1316..b8d0f10 100644 --- a/src/app/controllers/pool_controller.rb +++ b/src/app/controllers/pool_controller.rb @@ -31,6 +31,14 @@ class PoolController < ApplicationController :include => [ :storage_pools, :hosts, :quota ] } + include TaskActions + def tasks_query_obj + @pool.tasks + end + def tasks_conditions + {} + end + def show respond_to do |format| format.html { @@ -58,39 +66,6 @@ class PoolController < ApplicationController [:grid_id, :uid, :user_role, :source]) end - def show_tasks - @task_states = [["Queued", Task::STATE_QUEUED], - ["Running", Task::STATE_RUNNING], - ["Paused", Task::STATE_PAUSED], - ["Finished", Task::STATE_FINISHED], - ["Failed", Task::STATE_FAILED], - ["Canceled", Task::STATE_CANCELED, "break"], - ["Show All", ""]] - params[:page]=1 - params[:sortname]="tasks.created_at" - params[:sortorder]="desc" - @tasks = tasks_internal - show - end - - def tasks - render :json => tasks_internal.to_json - end - - def tasks_internal - @task_state = params[:task_state] - @task_state ||=Task::STATE_QUEUED - conditions = {} - conditions[:type] = @task_type unless @task_type.empty? - conditions[:state] = @task_state unless @task_state.empty? - find_opts = {:include => [:storage_pool, :host, :vm]} - find_opts[:conditions] = conditions unless conditions.empty? - attr_list = [] - attr_list << :id if params[:checkboxes] - attr_list += [:type_label, :task_obj, :action, :state, :user, :created_at, :args, :message] - json_hash(@pool.tasks, attr_list, [:all], find_opts) - end - def hosts_json(args) attr_list = [] attr_list << :id if params[:checkboxes] diff --git a/src/app/controllers/task_actions.rb b/src/app/controllers/task_actions.rb new file mode 100644 index 0000000..d71c11e --- /dev/null +++ b/src/app/controllers/task_actions.rb @@ -0,0 +1,50 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Scott Seago +# +# 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. +module TaskActions + def show_tasks + @task_states = Task::TASK_STATES_OPTIONS + params[:page]=1 + params[:sortname]="tasks.created_at" + params[:sortorder]="desc" + @tasks = tasks_internal + show + end + + def tasks + render :json => tasks_internal.to_json + end + + def tasks_internal + @task_state = params[:task_state] + @task_state ||=Task::STATE_QUEUED + @task_type = params[:task_type] + @task_type ||="" + conditions = tasks_conditions + conditions[:type] = @task_type unless @task_type.empty? + conditions[:state] = @task_state unless @task_state.empty? + find_opts = {:include => [:storage_pool, :host, :vm]} + find_opts[:conditions] = conditions unless conditions.empty? + attr_list = [] + attr_list << :id if params[:checkboxes] + attr_list += [:type_label, :task_obj, :action, :state, :user, :created_at, :args, :message] + json_hash(tasks_query_obj, attr_list, [:all], find_opts) + end + + +end diff --git a/src/app/models/task.rb b/src/app/models/task.rb index f231c18..4d16e01 100644 --- a/src/app/models/task.rb +++ b/src/app/models/task.rb @@ -45,6 +45,19 @@ class Task < ActiveRecord::Base COMPLETED_STATES = [STATE_FINISHED, STATE_FAILED, STATE_CANCELED] WORKING_STATES = [STATE_QUEUED, STATE_RUNNING, STATE_PAUSED] + TASK_TYPES_OPTIONS = [["VM Task", "VmTask"], + ["Host Task", "HostTask"], + ["Storage Task", "StorageTask"], + ["Storage Volume Task", "StorageVolumeTask", "break"], + ["Show All", ""]] + TASK_STATES_OPTIONS = [["Queued", Task::STATE_QUEUED], + ["Running", Task::STATE_RUNNING], + ["Paused", Task::STATE_PAUSED], + ["Finished", Task::STATE_FINISHED], + ["Failed", Task::STATE_FAILED], + ["Canceled", Task::STATE_CANCELED, "break"], + ["Show All", ""]] + def cancel self[:state] = STATE_CANCELED save! diff --git a/src/app/views/dashboard/index.html.erb b/src/app/views/dashboard/index.html.erb index 8815ebc..c361e55 100644 --- a/src/app/views/dashboard/index.html.erb +++ b/src/app/views/dashboard/index.html.erb @@ -1,31 +1,7 @@ - -
- -

Actions

- -
-
<%= link_to_if @can_set_perms, 'User Permissions', { :controller => 'permission', :action => 'new', :pool_id => @default_pool }, { :class => "edit" } %>
- - - - - -
<%= pluralize @default_pool.permissions.super_admins.size, "Super Admin" %>
<%= pluralize @default_pool.permissions.admins.size, "Administrator" %>
<%= pluralize @default_pool.permissions.users.size, "User" %>
<%= pluralize @default_pool.permissions.monitors.size, "Monitor" %>
-
- - <% if @can_modify %> -

Networks

- - View / Edit - - <% end %> - -
- - - - -<%- content_for :title do -%> -<%= _("Dashboard") %> -<%- end -%> - + <%= render :partial => "/task/show", :locals => { :task_types => @task_types, + :task_states => @task_states, + :task_type => @task_type, + :task_state => @task_state, + :tasks => @tasks, + :action => 'index', + :pool => nil } %> diff --git a/src/app/views/hardware/show_tasks.rhtml b/src/app/views/hardware/show_tasks.rhtml index e49086c..87ea13f 100644 --- a/src/app/views/hardware/show_tasks.rhtml +++ b/src/app/views/hardware/show_tasks.rhtml @@ -1,77 +1,7 @@ -
-
    -
  • - <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Type    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> -
      - <% @task_types.each_index { |index| %> -
    • - style="border-bottom: 1px solid #CCCCCC;" - <% end %> - > - - <%= @task_type == @task_types[index][1] ? "X" : "  " %> - <%=@task_types[index][0]%> -
    • - <% } %> -
    -
  • -
  • - <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  State    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> -
      - <% @task_states.each_index { |index| %> -
    • - style="border-bottom: 1px solid #CCCCCC;" - <% end %> - > - - <%= @task_state == @task_states[index][1] ? "X" : "  " %> - <%=@task_states[index][0]%> -
    • - <% } %> -
    -
  • -
-
- - - -
-<% if @tasks[:rows].size != 0 %> -
- <%= render :partial => "/task/grid", :locals => { :table_id => "tasks_grid", - :task_type => @task_type, - :task_state => @task_state, - :pool => @pool, - :checkboxes => false, - :on_select => "tasks_grid_select" } %> -
- -<% else %> -
-
- <%= image_tag 'no-grid-items.png', :style => 'float: left;' %> - -
- No tasks found.

- <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>   -
-
-
-<% end %> + <%= render :partial => "/task/show", :locals => { :task_types => @task_types, + :task_states => @task_states, + :task_type => @task_type, + :task_state => @task_state, + :tasks => @tasks, + :action => 'show_tasks', + :pool => @pool } %> diff --git a/src/app/views/layouts/_navigation_tabs.rhtml b/src/app/views/layouts/_navigation_tabs.rhtml index dd50820..7393262 100644 --- a/src/app/views/layouts/_navigation_tabs.rhtml +++ b/src/app/views/layouts/_navigation_tabs.rhtml @@ -3,7 +3,7 @@ $(document).ready(function(){ $tabs = $("#hardware_nav_tabs").tabs({ pool_type: "hardware", - selected: <%if params[:tab]%><%=params[:tab]%><%else%>1<%end%> + selected: <%if params[:tab]%><%=params[:tab]%><%else%>0<%end%> }); }); @@ -20,7 +20,7 @@ $(document).ready(function(){ $tabs = $("#resources_nav_tabs").tabs({ pool_type: "resource", - selected: <%if params[:tab]%><%=params[:tab]%><%else%>1<%end%> + selected: <%if params[:tab]%><%=params[:tab]%><%else%>0<%end%> }); }); @@ -35,7 +35,7 @@ $(document).ready(function(){ $tabs = $("#smart_pools_nav_tabs").tabs({ pool_type: "smart", - selected: <%if params[:tab]%><%=params[:tab]%><%else%>1<%end%> + selected: <%if params[:tab]%><%=params[:tab]%><%else%>0<%end%> }); }); @@ -48,7 +48,19 @@ <% elsif controller.controller_name == "search" %> -
    + +<% elsif controller.controller_name == "dashboard" %> + +
      + +
    <% end %> \ No newline at end of file diff --git a/src/app/views/resources/show_tasks.rhtml b/src/app/views/resources/show_tasks.rhtml index 6c92779..87ea13f 100644 --- a/src/app/views/resources/show_tasks.rhtml +++ b/src/app/views/resources/show_tasks.rhtml @@ -1,61 +1,7 @@ -
    -
      -
    • - <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  State    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> -
        - <% @task_states.each_index { |index| %> -
      • - style="border-bottom: 1px solid #CCCCCC;" - <% end %> - > - - <%= @task_state == @task_states[index][1] ? "X" : "  " %> - <%=@task_states[index][0]%> -
      • - <% } %> -
      -
    • -
    -
    - - - -
    -<% if @tasks[:rows].size != 0 %> -
    - <%= render :partial => "/task/grid", :locals => { :table_id => "vm_tasks_grid", - :task_type => nil, - :task_state => @task_state, - :pool => @pool, - :checkboxes => false, - :on_select => "vm_tasks_grid_select" } %> -
    - -<% else %> -
    -
    - <%= image_tag 'no-grid-items.png', :style => 'float: left;' %> - -
    - No tasks found.

    - <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>   -
    -
    -
    -<% end %> + <%= render :partial => "/task/show", :locals => { :task_types => @task_types, + :task_states => @task_states, + :task_type => @task_type, + :task_state => @task_state, + :tasks => @tasks, + :action => 'show_tasks', + :pool => @pool } %> diff --git a/src/app/views/task/_grid.rhtml b/src/app/views/task/_grid.rhtml index cab99e5..3c17ac5 100644 --- a/src/app/views/task/_grid.rhtml +++ b/src/app/views/task/_grid.rhtml @@ -9,7 +9,7 @@ ( { url: '<%= url_for :action => "tasks", - :id => pool.id %>', + :id => pool %>', params: [{name: "task_type", value: '<%=task_type%>'}, {name: "task_state", value: '<%=task_state%>'} <%=", {name: 'checkboxes', value: #{checkboxes}}" if checkboxes%>], diff --git a/src/app/views/hardware/show_tasks.rhtml b/src/app/views/task/_show.rhtml similarity index 59% copy from src/app/views/hardware/show_tasks.rhtml copy to src/app/views/task/_show.rhtml index e49086c..eff9334 100644 --- a/src/app/views/hardware/show_tasks.rhtml +++ b/src/app/views/task/_show.rhtml @@ -1,33 +1,36 @@
    -
      -
    • - <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Type    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> -
        - <% @task_types.each_index { |index| %> -
      • - style="border-bottom: 1px solid #CCCCCC;" - <% end %> - > - - <%= @task_type == @task_types[index][1] ? "X" : "  " %> - <%=@task_types[index][0]%> -
      • - <% } %> -
      -
    • +
        + <%if defined? task_types %> +
      • + <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Type    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> +
          + <% task_types.each_index { |index| %> +
        • + style="border-bottom: 1px solid #CCCCCC;" + <% end %> + > + + <%= task_type == task_types[index][1] ? "X" : "  " %> + <%=task_types[index][0]%> +
        • + <% } %> +
        +
      • + <% end %> +
      • <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  State    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %>
          - <% @task_states.each_index { |index| %> -
        • + <% task_states.each_index { |index| %> +
        • style="border-bottom: 1px solid #CCCCCC;" <% end %> > - <%= @task_state == @task_states[index][1] ? "X" : "  " %> - <%=@task_states[index][0]%> + <%= task_state == task_states[index][1] ? "X" : "  " %> + <%=task_states[index][0]%>
        • <% } %>
        @@ -40,7 +43,7 @@ function apply_task_filter(task_type, task_state) { $tabs.tabs("url", $tabs.data("selected.tabs"), - "<%= url_for :action => 'show_tasks', :id => @pool.id, + "<%= url_for :action => action, :id => pool, :nolayout => :true %>" + "&task_type=" + task_type + "&task_state=" + task_state); $tabs.tabs("load", $tabs.data("selected.tabs")); @@ -48,12 +51,12 @@
        -<% if @tasks[:rows].size != 0 %> +<% if tasks[:rows].size != 0 %>
        <%= render :partial => "/task/grid", :locals => { :table_id => "tasks_grid", - :task_type => @task_type, - :task_state => @task_state, - :pool => @pool, + :task_type => task_type, + :task_state => task_state, + :pool => pool, :checkboxes => false, :on_select => "tasks_grid_select" } %>
        -- 1.6.0.4 From bkearney at redhat.com Thu Jan 8 19:18:00 2009 From: bkearney at redhat.com (Bryan Kearney) Date: Thu, 8 Jan 2009 14:18:00 -0500 Subject: [Ovirt-devel] [PATCH node] Allow the menu to be ordered based on prepending XX_ onto the front of the symlinks Message-ID: <1231442280-1814-1-git-send-email-bkearney@redhat.com> --- ovirt-node.spec.in | 12 ++++++------ scripts/ovirt-config-setup | 6 ++++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in index 72b35f2..b292c3e 100644 --- a/ovirt-node.spec.in +++ b/ovirt-node.spec.in @@ -186,12 +186,12 @@ install -p -m 644 images/syslinux-vesa-splash.jpg %{buildroot}/usr/lib/anaconda- # default ovirt-config-setup menu options %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/ovirt-config-setup.d -%{__ln_s} ../..%{_sbindir}/ovirt-config-networking %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Networking Setup" -%{__ln_s} ../..%{_sbindir}/ovirt-config-storage %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Disk Partitioning" -%{__ln_s} ../..%{_sbindir}/ovirt-config-hostname %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Set Hostname" -%{__ln_s} ../..%{_sbindir}/ovirt-config-logging %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Logging Setup" -%{__ln_s} ../..%{_sbindir}/ovirt-config-password %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Administrator Password" -%{__ln_s} ../..%{_sbindir}/ovirt-config-boot %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Local install and reboot" +%{__ln_s} ../..%{_sbindir}/ovirt-config-networking %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"15_Networking Setup" +%{__ln_s} ../..%{_sbindir}/ovirt-config-storage %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"20_Disk Partitioning" +%{__ln_s} ../..%{_sbindir}/ovirt-config-hostname %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"10_Set Hostname" +%{__ln_s} ../..%{_sbindir}/ovirt-config-logging %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"30_Logging Setup" +%{__ln_s} ../..%{_sbindir}/ovirt-config-password %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"00_Administrator Password" +%{__ln_s} ../..%{_sbindir}/ovirt-config-boot %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"99_Local install and reboot" %clean diff --git a/scripts/ovirt-config-setup b/scripts/ovirt-config-setup index 9f97afc..9ee268f 100755 --- a/scripts/ovirt-config-setup +++ b/scripts/ovirt-config-setup @@ -13,10 +13,12 @@ declare -a OPTIONS for cfg in $CONFIG_DIR/*; do label=$(basename "$cfg") + # Assume label is actually XX_Some Text. So strip of the first 3 characters + label=${label:3} OPTIONS[${#OPTIONS[*]}]="$label" done -OPTIONS[${#OPTIONS[*]}]="$CONTINUE" OPTIONS[${#OPTIONS[*]}]="$DEBUG_SHELL" +OPTIONS[${#OPTIONS[*]}]="$CONTINUE" # reset tty, otherwise serial console is broken @@ -33,7 +35,7 @@ while true; do case "$OPTION" in "$DEBUG_SHELL") bash ; break ;; "$CONTINUE") exit 0 ;; - *) $CONFIG_DIR/"$OPTION" ;; + *) $CONFIG_DIR/*"$OPTION" ;; esac printf "\n" -- 1.6.0.6 From dpierce at redhat.com Thu Jan 8 19:58:02 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Thu, 8 Jan 2009 14:58:02 -0500 Subject: [Ovirt-devel] [PATCH node] Allow the menu to be ordered based on prepending XX_ onto the front of the symlinks In-Reply-To: <1231442280-1814-1-git-send-email-bkearney@redhat.com> References: <1231442280-1814-1-git-send-email-bkearney@redhat.com> Message-ID: <20090108195802.GA15952@mcpierce-laptop.rdu.redhat.com> On Thu, Jan 08, 2009 at 02:18:00PM -0500, Bryan Kearney wrote: > --- > ovirt-node.spec.in | 12 ++++++------ > scripts/ovirt-config-setup | 6 ++++-- > 2 files changed, 10 insertions(+), 8 deletions(-) > > diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in > index 72b35f2..b292c3e 100644 > --- a/ovirt-node.spec.in > +++ b/ovirt-node.spec.in > @@ -186,12 +186,12 @@ install -p -m 644 images/syslinux-vesa-splash.jpg %{buildroot}/usr/lib/anaconda- > > # default ovirt-config-setup menu options > %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/ovirt-config-setup.d > -%{__ln_s} ../..%{_sbindir}/ovirt-config-networking %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Networking Setup" > -%{__ln_s} ../..%{_sbindir}/ovirt-config-storage %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Disk Partitioning" > -%{__ln_s} ../..%{_sbindir}/ovirt-config-hostname %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Set Hostname" > -%{__ln_s} ../..%{_sbindir}/ovirt-config-logging %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Logging Setup" > -%{__ln_s} ../..%{_sbindir}/ovirt-config-password %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Administrator Password" > -%{__ln_s} ../..%{_sbindir}/ovirt-config-boot %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Local install and reboot" > +%{__ln_s} ../..%{_sbindir}/ovirt-config-networking %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"15_Networking Setup" > +%{__ln_s} ../..%{_sbindir}/ovirt-config-storage %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"20_Disk Partitioning" > +%{__ln_s} ../..%{_sbindir}/ovirt-config-hostname %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"10_Set Hostname" > +%{__ln_s} ../..%{_sbindir}/ovirt-config-logging %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"30_Logging Setup" > +%{__ln_s} ../..%{_sbindir}/ovirt-config-password %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"00_Administrator Password" > +%{__ln_s} ../..%{_sbindir}/ovirt-config-boot %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"99_Local install and reboot" ACK with one request: can we rearrange the above symlinks so that they're in order? -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From slinabery at redhat.com Thu Jan 8 20:48:44 2009 From: slinabery at redhat.com (Steve Linabery) Date: Thu, 8 Jan 2009 14:48:44 -0600 Subject: [Ovirt-devel] [PATCH server] Add audit trail for hosts joining/leaving hwpools with Rails observer class Message-ID: <1231447724-30339-1-git-send-email-slinabery@redhat.com> Modify graph_controller.rb to utilize new audit feature when generating data for flexchart --- src/app/controllers/graph_controller.rb | 65 +++++++++++++++++++++++++-- src/app/models/hardware_pool.rb | 2 +- src/app/models/host.rb | 9 ++++ src/app/models/host_observer.rb | 47 ++++++++++++++++++++ src/app/models/membership_audit_event.rb | 26 +++++++++++ src/app/models/pool.rb | 1 + src/config/environment.rb | 2 +- src/db/migrate/033_add_pool_audit_trail.rb | 32 ++++++++++++++ 8 files changed, 177 insertions(+), 7 deletions(-) create mode 100644 src/app/models/host_observer.rb create mode 100644 src/app/models/membership_audit_event.rb create mode 100644 src/db/migrate/033_add_pool_audit_trail.rb diff --git a/src/app/controllers/graph_controller.rb b/src/app/controllers/graph_controller.rb index ee9425f..df516f5 100644 --- a/src/app/controllers/graph_controller.rb +++ b/src/app/controllers/graph_controller.rb @@ -6,9 +6,9 @@ class GraphController < ApplicationController def flexchart_data @id = params[:id] target = params[:target] - startTime = params[:startTime].to_i - endTime = params[:endTime].to_i - duration = endTime - startTime + startTime = Time.at(params[:startTime].to_i) + endTime = Time.at(params[:endTime].to_i) + duration = endTime.to_i - startTime.to_i #the maximum number of data points we want in any chart maxPoints = 100 @@ -29,10 +29,30 @@ class GraphController < ApplicationController counter = DEV_KEY_COUNTERS[target] pool = Pool.find(@id) - hosts = pool.hosts + hosts = Host.find(:all, + :include=> :membership_audit_events, + :conditions => ['membership_audit_events.container_target_id = ?',pool]) + requestList = [ ] hosts.each{ |host| - requestList.push StatsRequest.new(host.hostname, devclass, 0, counter, startTime, duration, resolution, DataFunction::Peak) + eventsInRange = host.membership_audit_events.from_pool(pool, + startTime, + endTime) + priorAuditEvent = host.membership_audit_events.most_recent_prior_event_from_pool(pool,startTime) + timeRanges = get_ranges_from_event_list(eventsInRange, + priorAuditEvent, + startTime, + endTime) + timeRanges.each{ |range| + requestList.push StatsRequest.new(host.hostname, + devclass, + 0, + counter, + range[0].to_i, + range[1].to_i - range[0].to_i, + resolution, + DataFunction::Peak) + } } statsList = getAggregateStatsData?(requestList) @@ -51,6 +71,41 @@ class GraphController < ApplicationController render :json => graph end + def get_ranges_from_event_list(list, priorEvent, startTime, endTime) + + results = Array.new + range = [startTime,endTime] + + joined = false + if priorEvent + if priorEvent.action == MembershipAuditEvent::JOIN + joined = true + end + end + + list.each_with_index { |event,index| + if event.action == MembershipAuditEvent::JOIN + joined = true + range[0] = event.created_at + else + range[0] = startTime unless joined + joined = false + range[1] = event.created_at + results.push Array.new(range) + range = [startTime,endTime] + end + } + + if joined + range[1] = endTime + results.push Array.new(range) + ddebug(range) + end + + results + end + + # generate layout for availability bar graphs def availability_graph diff --git a/src/app/models/hardware_pool.rb b/src/app/models/hardware_pool.rb index d39d8e7..b72d485 100644 --- a/src/app/models/hardware_pool.rb +++ b/src/app/models/hardware_pool.rb @@ -54,7 +54,7 @@ class HardwarePool < Pool hosts = Host.find(:all, :conditions => "id in (#{host_ids.join(', ')})") transaction do hosts.each do |host| - host.hardware_pool_id = target_pool_id + host.hardware_pool = HardwarePool.find(target_pool_id) host.save! end end diff --git a/src/app/models/host.rb b/src/app/models/host.rb index 640782d..813bc1d 100644 --- a/src/app/models/host.rb +++ b/src/app/models/host.rb @@ -23,6 +23,15 @@ class Host < ActiveRecord::Base belongs_to :hardware_pool belongs_to :bonding_type + has_many :membership_audit_events, :as => :member_target, :dependent => :destroy, :order => "created_at ASC" do + def from_pool(pool,startTime,endTime) + find(:all, :conditions=> ['container_target_id = ? and created_at between ? and ?',pool,startTime,endTime]) + end + def most_recent_prior_event_from_pool(pool,startTime) + find(:last, :conditions=> ['container_target_id = ? and created_at < ?',pool,startTime]) + end + end + has_many :cpus, :dependent => :destroy has_many :nics, :dependent => :destroy has_many :bondings, :dependent => :destroy diff --git a/src/app/models/host_observer.rb b/src/app/models/host_observer.rb new file mode 100644 index 0000000..df5efa1 --- /dev/null +++ b/src/app/models/host_observer.rb @@ -0,0 +1,47 @@ +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Steve Linabery +# +# 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 HostObserver < ActiveRecord::Observer + + def after_create(a_host) + join = MembershipAuditEvent.new({ :member_target => a_host, + :container_target => a_host.hardware_pool, + :action => MembershipAuditEvent::JOIN }) + join.save! + end + + def before_update(a_host) + if a_host.changed? + change = a_host.changes['hardware_pool_id'] + if change + leave = MembershipAuditEvent.new({ :member_target => a_host, + :container_target => HardwarePool.find(change[0]), + :action => MembershipAuditEvent::LEAVE }) + leave.save! + + join = MembershipAuditEvent.new({ :member_target => a_host, + :container_target => HardwarePool.find(change[1]), + :action => MembershipAuditEvent::JOIN }) + join.save! + end + end + end +end + +HostObserver.instance diff --git a/src/app/models/membership_audit_event.rb b/src/app/models/membership_audit_event.rb new file mode 100644 index 0000000..b36cbee --- /dev/null +++ b/src/app/models/membership_audit_event.rb @@ -0,0 +1,26 @@ +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Steve Linabery +# +# 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 MembershipAuditEvent < ActiveRecord::Base + belongs_to :container_target, :polymorphic => true + belongs_to :member_target, :polymorphic => true + + JOIN = "join" + LEAVE = "leave" +end diff --git a/src/app/models/pool.rb b/src/app/models/pool.rb index 7034e79..614325a 100644 --- a/src/app/models/pool.rb +++ b/src/app/models/pool.rb @@ -20,6 +20,7 @@ class Pool < ActiveRecord::Base acts_as_nested_set + has_many :membership_audit_events, :as => :container_target, :dependent => :destroy # moved associations here so that nested set :include directives work # TODO: find a way to put this back into vm_resource_pool.rb has_many :vms, :dependent => :nullify, :order => "id ASC", :foreign_key => :vm_resource_pool_id diff --git a/src/config/environment.rb b/src/config/environment.rb index 53edfad..66cae90 100644 --- a/src/config/environment.rb +++ b/src/config/environment.rb @@ -82,7 +82,7 @@ Rails::Initializer.run do |config| # Activate observers that should always be running # config.active_record.observers = :cacher, :garbage_collector - + config.active_record.observers = :host_observer end # Add new inflection rules using the following format diff --git a/src/db/migrate/033_add_pool_audit_trail.rb b/src/db/migrate/033_add_pool_audit_trail.rb new file mode 100644 index 0000000..656ad87 --- /dev/null +++ b/src/db/migrate/033_add_pool_audit_trail.rb @@ -0,0 +1,32 @@ +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Steve Linabery +# +# 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 AddPoolAuditTrail < ActiveRecord::Migration + def self.up + create_table :membership_audit_events do |t| + t.timestamp :created_at + t.string :action + t.integer :container_target_id + t.string :container_target_type + t.integer :member_target_id + t.string :member_target_type + t.integer :lock_version, :default => 0 + end + end +end -- 1.6.0.6 From slinabery at redhat.com Thu Jan 8 20:52:14 2009 From: slinabery at redhat.com (Steve Linabery) Date: Thu, 8 Jan 2009 14:52:14 -0600 Subject: [Ovirt-devel] Re: [PATCH server] Add audit trail for hosts joining/leaving hwpools with Rails observer class In-Reply-To: <1231447724-30339-1-git-send-email-slinabery@redhat.com> References: <1231447724-30339-1-git-send-email-slinabery@redhat.com> Message-ID: <20090108205213.GF14957@redhat.com> Disregard this for the moment, folks. I have to add to the migration file. On Thu, Jan 08, 2009 at 02:48:44PM -0600, Steve Linabery wrote: > Modify graph_controller.rb to utilize new audit feature when generating data for flexchart > --- > src/app/controllers/graph_controller.rb | 65 +++++++++++++++++++++++++-- > src/app/models/hardware_pool.rb | 2 +- > src/app/models/host.rb | 9 ++++ > src/app/models/host_observer.rb | 47 ++++++++++++++++++++ > src/app/models/membership_audit_event.rb | 26 +++++++++++ > src/app/models/pool.rb | 1 + > src/config/environment.rb | 2 +- > src/db/migrate/033_add_pool_audit_trail.rb | 32 ++++++++++++++ > 8 files changed, 177 insertions(+), 7 deletions(-) > create mode 100644 src/app/models/host_observer.rb > create mode 100644 src/app/models/membership_audit_event.rb > create mode 100644 src/db/migrate/033_add_pool_audit_trail.rb > > diff --git a/src/app/controllers/graph_controller.rb b/src/app/controllers/graph_controller.rb > index ee9425f..df516f5 100644 > --- a/src/app/controllers/graph_controller.rb > +++ b/src/app/controllers/graph_controller.rb > @@ -6,9 +6,9 @@ class GraphController < ApplicationController > def flexchart_data > @id = params[:id] > target = params[:target] > - startTime = params[:startTime].to_i > - endTime = params[:endTime].to_i > - duration = endTime - startTime > + startTime = Time.at(params[:startTime].to_i) > + endTime = Time.at(params[:endTime].to_i) > + duration = endTime.to_i - startTime.to_i > > #the maximum number of data points we want in any chart > maxPoints = 100 > @@ -29,10 +29,30 @@ class GraphController < ApplicationController > counter = DEV_KEY_COUNTERS[target] > > pool = Pool.find(@id) > - hosts = pool.hosts > + hosts = Host.find(:all, > + :include=> :membership_audit_events, > + :conditions => ['membership_audit_events.container_target_id = ?',pool]) > + > requestList = [ ] > hosts.each{ |host| > - requestList.push StatsRequest.new(host.hostname, devclass, 0, counter, startTime, duration, resolution, DataFunction::Peak) > + eventsInRange = host.membership_audit_events.from_pool(pool, > + startTime, > + endTime) > + priorAuditEvent = host.membership_audit_events.most_recent_prior_event_from_pool(pool,startTime) > + timeRanges = get_ranges_from_event_list(eventsInRange, > + priorAuditEvent, > + startTime, > + endTime) > + timeRanges.each{ |range| > + requestList.push StatsRequest.new(host.hostname, > + devclass, > + 0, > + counter, > + range[0].to_i, > + range[1].to_i - range[0].to_i, > + resolution, > + DataFunction::Peak) > + } > } > statsList = getAggregateStatsData?(requestList) > > @@ -51,6 +71,41 @@ class GraphController < ApplicationController > render :json => graph > end > > + def get_ranges_from_event_list(list, priorEvent, startTime, endTime) > + > + results = Array.new > + range = [startTime,endTime] > + > + joined = false > + if priorEvent > + if priorEvent.action == MembershipAuditEvent::JOIN > + joined = true > + end > + end > + > + list.each_with_index { |event,index| > + if event.action == MembershipAuditEvent::JOIN > + joined = true > + range[0] = event.created_at > + else > + range[0] = startTime unless joined > + joined = false > + range[1] = event.created_at > + results.push Array.new(range) > + range = [startTime,endTime] > + end > + } > + > + if joined > + range[1] = endTime > + results.push Array.new(range) > + ddebug(range) > + end > + > + results > + end > + > + > > # generate layout for availability bar graphs > def availability_graph > diff --git a/src/app/models/hardware_pool.rb b/src/app/models/hardware_pool.rb > index d39d8e7..b72d485 100644 > --- a/src/app/models/hardware_pool.rb > +++ b/src/app/models/hardware_pool.rb > @@ -54,7 +54,7 @@ class HardwarePool < Pool > hosts = Host.find(:all, :conditions => "id in (#{host_ids.join(', ')})") > transaction do > hosts.each do |host| > - host.hardware_pool_id = target_pool_id > + host.hardware_pool = HardwarePool.find(target_pool_id) > host.save! > end > end > diff --git a/src/app/models/host.rb b/src/app/models/host.rb > index 640782d..813bc1d 100644 > --- a/src/app/models/host.rb > +++ b/src/app/models/host.rb > @@ -23,6 +23,15 @@ class Host < ActiveRecord::Base > belongs_to :hardware_pool > belongs_to :bonding_type > > + has_many :membership_audit_events, :as => :member_target, :dependent => :destroy, :order => "created_at ASC" do > + def from_pool(pool,startTime,endTime) > + find(:all, :conditions=> ['container_target_id = ? and created_at between ? and ?',pool,startTime,endTime]) > + end > + def most_recent_prior_event_from_pool(pool,startTime) > + find(:last, :conditions=> ['container_target_id = ? and created_at < ?',pool,startTime]) > + end > + end > + > has_many :cpus, :dependent => :destroy > has_many :nics, :dependent => :destroy > has_many :bondings, :dependent => :destroy > diff --git a/src/app/models/host_observer.rb b/src/app/models/host_observer.rb > new file mode 100644 > index 0000000..df5efa1 > --- /dev/null > +++ b/src/app/models/host_observer.rb > @@ -0,0 +1,47 @@ > +# > +# Copyright (C) 2008 Red Hat, Inc. > +# Written by Steve Linabery > +# > +# 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 HostObserver < ActiveRecord::Observer > + > + def after_create(a_host) > + join = MembershipAuditEvent.new({ :member_target => a_host, > + :container_target => a_host.hardware_pool, > + :action => MembershipAuditEvent::JOIN }) > + join.save! > + end > + > + def before_update(a_host) > + if a_host.changed? > + change = a_host.changes['hardware_pool_id'] > + if change > + leave = MembershipAuditEvent.new({ :member_target => a_host, > + :container_target => HardwarePool.find(change[0]), > + :action => MembershipAuditEvent::LEAVE }) > + leave.save! > + > + join = MembershipAuditEvent.new({ :member_target => a_host, > + :container_target => HardwarePool.find(change[1]), > + :action => MembershipAuditEvent::JOIN }) > + join.save! > + end > + end > + end > +end > + > +HostObserver.instance > diff --git a/src/app/models/membership_audit_event.rb b/src/app/models/membership_audit_event.rb > new file mode 100644 > index 0000000..b36cbee > --- /dev/null > +++ b/src/app/models/membership_audit_event.rb > @@ -0,0 +1,26 @@ > +# > +# Copyright (C) 2008 Red Hat, Inc. > +# Written by Steve Linabery > +# > +# 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 MembershipAuditEvent < ActiveRecord::Base > + belongs_to :container_target, :polymorphic => true > + belongs_to :member_target, :polymorphic => true > + > + JOIN = "join" > + LEAVE = "leave" > +end > diff --git a/src/app/models/pool.rb b/src/app/models/pool.rb > index 7034e79..614325a 100644 > --- a/src/app/models/pool.rb > +++ b/src/app/models/pool.rb > @@ -20,6 +20,7 @@ > class Pool < ActiveRecord::Base > acts_as_nested_set > > + has_many :membership_audit_events, :as => :container_target, :dependent => :destroy > # moved associations here so that nested set :include directives work > # TODO: find a way to put this back into vm_resource_pool.rb > has_many :vms, :dependent => :nullify, :order => "id ASC", :foreign_key => :vm_resource_pool_id > diff --git a/src/config/environment.rb b/src/config/environment.rb > index 53edfad..66cae90 100644 > --- a/src/config/environment.rb > +++ b/src/config/environment.rb > @@ -82,7 +82,7 @@ Rails::Initializer.run do |config| > > # Activate observers that should always be running > # config.active_record.observers = :cacher, :garbage_collector > - > + config.active_record.observers = :host_observer > end > > # Add new inflection rules using the following format > diff --git a/src/db/migrate/033_add_pool_audit_trail.rb b/src/db/migrate/033_add_pool_audit_trail.rb > new file mode 100644 > index 0000000..656ad87 > --- /dev/null > +++ b/src/db/migrate/033_add_pool_audit_trail.rb > @@ -0,0 +1,32 @@ > +# > +# Copyright (C) 2008 Red Hat, Inc. > +# Written by Steve Linabery > +# > +# 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 AddPoolAuditTrail < ActiveRecord::Migration > + def self.up > + create_table :membership_audit_events do |t| > + t.timestamp :created_at > + t.string :action > + t.integer :container_target_id > + t.string :container_target_type > + t.integer :member_target_id > + t.string :member_target_type > + t.integer :lock_version, :default => 0 > + end > + end > +end > -- > 1.6.0.6 > From bkearney at redhat.com Thu Jan 8 21:22:46 2009 From: bkearney at redhat.com (Bryan Kearney) Date: Thu, 8 Jan 2009 16:22:46 -0500 Subject: [Ovirt-devel] [PATCH node] Added a wrapper script around the boot menu item to warn the users about the reboot Message-ID: <1231449766-28155-1-git-send-email-bkearney@redhat.com> --- Makefile.am | 1 + ovirt-node.spec.in | 4 +++- scripts/ovirt-config-boot-wrapper | 16 ++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletions(-) create mode 100644 scripts/ovirt-config-boot-wrapper diff --git a/Makefile.am b/Makefile.am index 6847234..c62774f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -30,6 +30,7 @@ EXTRA_DIST = \ scripts/ovirt \ scripts/ovirt-awake \ scripts/ovirt-config-boot \ + scripts/ovirt-config-boot-wrapper \ scripts/ovirt-config-hostname \ scripts/ovirt-config-logging \ scripts/ovirt-config-networking \ diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in index 501bf4f..f30dd62 100644 --- a/ovirt-node.spec.in +++ b/ovirt-node.spec.in @@ -132,6 +132,7 @@ cd - %{__install} -p -m0755 scripts/ovirt-awake %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-boot %{buildroot}%{_sbindir} +%{__install} -p -m0755 scripts/ovirt-config-boot-wrapper %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-hostname %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-logging %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-networking %{buildroot}%{_sbindir} @@ -191,7 +192,7 @@ install -p -m 644 images/syslinux-vesa-splash.jpg %{buildroot}/usr/lib/anaconda- %{__ln_s} ../..%{_sbindir}/ovirt-config-networking %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"15_Networking Setup" %{__ln_s} ../..%{_sbindir}/ovirt-config-storage %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"20_Disk Partitioning" %{__ln_s} ../..%{_sbindir}/ovirt-config-logging %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"30_Logging Setup" -%{__ln_s} ../..%{_sbindir}/ovirt-config-boot %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"99_Local install and reboot" +%{__ln_s} ../..%{_sbindir}/ovirt-config-boot-wrapper %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"99_Local install and reboot" %clean @@ -253,6 +254,7 @@ fi %defattr(-,root,root,0755) %{_sbindir}/ovirt-awake %{_sbindir}/ovirt-config-boot +%{_sbindir}/ovirt-config-boot-wrapper %{_sbindir}/ovirt-config-hostname %{_sbindir}/ovirt-config-logging %{_sbindir}/ovirt-config-networking diff --git a/scripts/ovirt-config-boot-wrapper b/scripts/ovirt-config-boot-wrapper new file mode 100644 index 0000000..6876a30 --- /dev/null +++ b/scripts/ovirt-config-boot-wrapper @@ -0,0 +1,16 @@ +#!/bin/bash +# +# Wrapper function to make sure the user wishes to continue before +# rebooting the system + +while true; do + read -p "This option will exit the menu, and require a reboot. Do you wish to continue? (Y|N)? " + r=$(echo $REPLY|tr '[[:lower:]]' '[[:upper:]]') + if [ "$r" == "Y" ]; then + /usr/sbin/ovirt-config-boot + break + elif [ "$r" == "N" ]; then + printf "\nExiting back to the menu\n" + break + fi +done -- 1.6.0.6 From mmorsi at redhat.com Thu Jan 8 22:37:08 2009 From: mmorsi at redhat.com (Mohammed Morsi) Date: Thu, 08 Jan 2009 17:37:08 -0500 Subject: [Ovirt-devel] oVirt server wui console integration Message-ID: <49668014.6060706@redhat.com> Currently the idea for the console interface in the wui is that a user can navigate the the 'virtual machines' tab under a vm pool, click on a specific vm, click on 'console' in the details pane and will be presented with a console to that vm. There were a few ideas as to where the console should appear, * in a minimally themed popup window, most likely the first implementation as it is simplest, but may result in many popups when connected to several vms * in the dialog / popup box interface we have now, we will want to introduce a tabbing mechanism for access to multiple vm consoles * in another tab in the main content area, same vm-tab concept needed here * a rollover, eg the user rolls over 'console' in the vm details pane and the console appears so long as the user holds his mouse over it / the link Its currently looking like the console frontend and apache-proxied backend daemon will be driven by anyterm http://anyterm.org/ . We will use anyterm to launch ovirt-viewer or the virsh console to connect to the vm and then present the anyterm html / js / css ui to the user. A rough layout of the setup can be found here http://ovirt.org/page/Image:Anyterm.png Looking for thoughts / feedback / suggestions as to the interface placement of the console or the backend. Thanks alot, -Mo From jeremy.perry at redhat.com Thu Jan 8 23:23:30 2009 From: jeremy.perry at redhat.com (Jeremy Perry) Date: Thu, 8 Jan 2009 18:23:30 -0500 Subject: [Ovirt-devel] Re: oVirt server wui console integration In-Reply-To: <49668014.6060706@redhat.com> References: <49668014.6060706@redhat.com> Message-ID: <820A3B59-B2C2-4A9D-A48A-A4CB1F6F7B5E@redhat.com> On Jan 8, 2009, at 5:37 PM, Mohammed Morsi wrote: > Currently the idea for the console interface in the wui is that a user > can navigate the the 'virtual machines' tab under a vm pool, click > on a > specific vm, click on 'console' in the details pane and will be > presented with a console to that vm. There were a few ideas as to > where > the console should appear, > > * in a minimally themed popup window, most likely the first > implementation as it is simplest, but may result in many popups when > connected to several vms > * in the dialog / popup box interface we have now, we will want to > introduce a tabbing mechanism for access to multiple vm consoles > * in another tab in the main content area, same vm-tab concept > needed here > * a rollover, eg the user rolls over 'console' in the vm details pane > and the console appears so long as the user holds his mouse over it / > the link > I've taken the liberty of mocking some of these ideas up here: http://file.rdu.redhat.com/~jeperry/ovirt/terminal/round1.html I didnt mockup the new themed popup window yet, since its simple to imagine. I think its a decent approach, but wondering if we can eliminate the multiple popups issue by targeting our popup once there is at least one open. Subsequent terminals would nest via tabs in the one terminal window, so all you deal with is one window with tabs for each vm terminal. > Its currently looking like the console frontend and apache-proxied > backend daemon will be driven by anyterm http://anyterm.org/ . We will > use anyterm to launch ovirt-viewer or the virsh console to connect to > the vm and then present the anyterm html / js / css ui to the user. A > rough layout of the setup can be found here > http://ovirt.org/page/Image:Anyterm.png I based my mockups on their demos - let me know if the actions I included (like copy, paste) make sense or not. > > Looking for thoughts / feedback / suggestions as to the interface > placement of the console or the backend. Thanks alot, > > -Mo Finally, I wanted to propose we settle on the term "Terminal" instead of "Console" - at least in the UI - since that is what is used in Fedora. I know terminology consistency is a challenge for us, is this a place we can make a choice in the UI and be consistent? Thanks! - Jeremy From slinabery at redhat.com Fri Jan 9 01:35:37 2009 From: slinabery at redhat.com (Steve Linabery) Date: Thu, 8 Jan 2009 19:35:37 -0600 Subject: [Ovirt-devel] [PATCH server] Add audit trail for hosts joining/leaving hwpools with Rails observer class Message-ID: <1231464937-2324-1-git-send-email-slinabery@redhat.com> Modify graph_controller.rb to utilize new audit feature when generating data for flexchart --- src/app/controllers/graph_controller.rb | 65 +++++++++++++++++++++++++-- src/app/models/hardware_pool.rb | 2 +- src/app/models/host.rb | 9 ++++ src/app/models/host_observer.rb | 47 ++++++++++++++++++++ src/app/models/membership_audit_event.rb | 26 +++++++++++ src/app/models/pool.rb | 1 + src/config/environment.rb | 2 +- src/db/migrate/033_add_pool_audit_trail.rb | 44 +++++++++++++++++++ 8 files changed, 189 insertions(+), 7 deletions(-) create mode 100644 src/app/models/host_observer.rb create mode 100644 src/app/models/membership_audit_event.rb create mode 100644 src/db/migrate/033_add_pool_audit_trail.rb diff --git a/src/app/controllers/graph_controller.rb b/src/app/controllers/graph_controller.rb index ee9425f..df516f5 100644 --- a/src/app/controllers/graph_controller.rb +++ b/src/app/controllers/graph_controller.rb @@ -6,9 +6,9 @@ class GraphController < ApplicationController def flexchart_data @id = params[:id] target = params[:target] - startTime = params[:startTime].to_i - endTime = params[:endTime].to_i - duration = endTime - startTime + startTime = Time.at(params[:startTime].to_i) + endTime = Time.at(params[:endTime].to_i) + duration = endTime.to_i - startTime.to_i #the maximum number of data points we want in any chart maxPoints = 100 @@ -29,10 +29,30 @@ class GraphController < ApplicationController counter = DEV_KEY_COUNTERS[target] pool = Pool.find(@id) - hosts = pool.hosts + hosts = Host.find(:all, + :include=> :membership_audit_events, + :conditions => ['membership_audit_events.container_target_id = ?',pool]) + requestList = [ ] hosts.each{ |host| - requestList.push StatsRequest.new(host.hostname, devclass, 0, counter, startTime, duration, resolution, DataFunction::Peak) + eventsInRange = host.membership_audit_events.from_pool(pool, + startTime, + endTime) + priorAuditEvent = host.membership_audit_events.most_recent_prior_event_from_pool(pool,startTime) + timeRanges = get_ranges_from_event_list(eventsInRange, + priorAuditEvent, + startTime, + endTime) + timeRanges.each{ |range| + requestList.push StatsRequest.new(host.hostname, + devclass, + 0, + counter, + range[0].to_i, + range[1].to_i - range[0].to_i, + resolution, + DataFunction::Peak) + } } statsList = getAggregateStatsData?(requestList) @@ -51,6 +71,41 @@ class GraphController < ApplicationController render :json => graph end + def get_ranges_from_event_list(list, priorEvent, startTime, endTime) + + results = Array.new + range = [startTime,endTime] + + joined = false + if priorEvent + if priorEvent.action == MembershipAuditEvent::JOIN + joined = true + end + end + + list.each_with_index { |event,index| + if event.action == MembershipAuditEvent::JOIN + joined = true + range[0] = event.created_at + else + range[0] = startTime unless joined + joined = false + range[1] = event.created_at + results.push Array.new(range) + range = [startTime,endTime] + end + } + + if joined + range[1] = endTime + results.push Array.new(range) + ddebug(range) + end + + results + end + + # generate layout for availability bar graphs def availability_graph diff --git a/src/app/models/hardware_pool.rb b/src/app/models/hardware_pool.rb index d39d8e7..b72d485 100644 --- a/src/app/models/hardware_pool.rb +++ b/src/app/models/hardware_pool.rb @@ -54,7 +54,7 @@ class HardwarePool < Pool hosts = Host.find(:all, :conditions => "id in (#{host_ids.join(', ')})") transaction do hosts.each do |host| - host.hardware_pool_id = target_pool_id + host.hardware_pool = HardwarePool.find(target_pool_id) host.save! end end diff --git a/src/app/models/host.rb b/src/app/models/host.rb index 640782d..813bc1d 100644 --- a/src/app/models/host.rb +++ b/src/app/models/host.rb @@ -23,6 +23,15 @@ class Host < ActiveRecord::Base belongs_to :hardware_pool belongs_to :bonding_type + has_many :membership_audit_events, :as => :member_target, :dependent => :destroy, :order => "created_at ASC" do + def from_pool(pool,startTime,endTime) + find(:all, :conditions=> ['container_target_id = ? and created_at between ? and ?',pool,startTime,endTime]) + end + def most_recent_prior_event_from_pool(pool,startTime) + find(:last, :conditions=> ['container_target_id = ? and created_at < ?',pool,startTime]) + end + end + has_many :cpus, :dependent => :destroy has_many :nics, :dependent => :destroy has_many :bondings, :dependent => :destroy diff --git a/src/app/models/host_observer.rb b/src/app/models/host_observer.rb new file mode 100644 index 0000000..df5efa1 --- /dev/null +++ b/src/app/models/host_observer.rb @@ -0,0 +1,47 @@ +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Steve Linabery +# +# 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 HostObserver < ActiveRecord::Observer + + def after_create(a_host) + join = MembershipAuditEvent.new({ :member_target => a_host, + :container_target => a_host.hardware_pool, + :action => MembershipAuditEvent::JOIN }) + join.save! + end + + def before_update(a_host) + if a_host.changed? + change = a_host.changes['hardware_pool_id'] + if change + leave = MembershipAuditEvent.new({ :member_target => a_host, + :container_target => HardwarePool.find(change[0]), + :action => MembershipAuditEvent::LEAVE }) + leave.save! + + join = MembershipAuditEvent.new({ :member_target => a_host, + :container_target => HardwarePool.find(change[1]), + :action => MembershipAuditEvent::JOIN }) + join.save! + end + end + end +end + +HostObserver.instance diff --git a/src/app/models/membership_audit_event.rb b/src/app/models/membership_audit_event.rb new file mode 100644 index 0000000..b36cbee --- /dev/null +++ b/src/app/models/membership_audit_event.rb @@ -0,0 +1,26 @@ +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Steve Linabery +# +# 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 MembershipAuditEvent < ActiveRecord::Base + belongs_to :container_target, :polymorphic => true + belongs_to :member_target, :polymorphic => true + + JOIN = "join" + LEAVE = "leave" +end diff --git a/src/app/models/pool.rb b/src/app/models/pool.rb index 7034e79..614325a 100644 --- a/src/app/models/pool.rb +++ b/src/app/models/pool.rb @@ -20,6 +20,7 @@ class Pool < ActiveRecord::Base acts_as_nested_set + has_many :membership_audit_events, :as => :container_target, :dependent => :destroy # moved associations here so that nested set :include directives work # TODO: find a way to put this back into vm_resource_pool.rb has_many :vms, :dependent => :nullify, :order => "id ASC", :foreign_key => :vm_resource_pool_id diff --git a/src/config/environment.rb b/src/config/environment.rb index 53edfad..66cae90 100644 --- a/src/config/environment.rb +++ b/src/config/environment.rb @@ -82,7 +82,7 @@ Rails::Initializer.run do |config| # Activate observers that should always be running # config.active_record.observers = :cacher, :garbage_collector - + config.active_record.observers = :host_observer end # Add new inflection rules using the following format diff --git a/src/db/migrate/033_add_pool_audit_trail.rb b/src/db/migrate/033_add_pool_audit_trail.rb new file mode 100644 index 0000000..07d2433 --- /dev/null +++ b/src/db/migrate/033_add_pool_audit_trail.rb @@ -0,0 +1,44 @@ +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Steve Linabery +# +# 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 AddPoolAuditTrail < ActiveRecord::Migration + def self.up + create_table :membership_audit_events do |t| + t.timestamp :created_at + t.string :action + t.integer :container_target_id + t.string :container_target_type + t.integer :member_target_id + t.string :member_target_type + t.integer :lock_version, :default => 0 + end + + Host.transaction do + Host.find(:all).each do |host| + + if (! host.membership_audit_events) + event = MembershipAuditEvent.new(:action => MembershipAuditEvent::JOIN, + :container_target => host.hardware_pool, + :member_target => host) + event.save! + end + end + end + end +end -- 1.6.0.6 From slinabery at redhat.com Fri Jan 9 01:41:36 2009 From: slinabery at redhat.com (Steve Linabery) Date: Thu, 8 Jan 2009 19:41:36 -0600 Subject: [Ovirt-devel] Re: [PATCH server] Add audit trail for hosts joining/leaving hwpools with Rails observer class In-Reply-To: <1231464937-2324-1-git-send-email-slinabery@redhat.com> References: <1231464937-2324-1-git-send-email-slinabery@redhat.com> Message-ID: <20090109014135.GG14957@redhat.com> Sorry folks, I am having some serious operator error here. I sent the wrong file. Please disregard. Third time is the charm... --Steve From slinabery at redhat.com Fri Jan 9 01:50:53 2009 From: slinabery at redhat.com (Steve Linabery) Date: Thu, 8 Jan 2009 19:50:53 -0600 Subject: [Ovirt-devel] [PATCH server] (Legit) Add audit trl for hosts join/leaving hwpools w/Rails observer class Message-ID: <1231465853-2898-1-git-send-email-slinabery@redhat.com> Modify graph_controller.rb to utilize new audit feature when generating data for flexchart --- src/app/controllers/graph_controller.rb | 64 +++++++++++++++++++++++++-- src/app/models/hardware_pool.rb | 2 +- src/app/models/host.rb | 9 ++++ src/app/models/host_observer.rb | 47 ++++++++++++++++++++ src/app/models/membership_audit_event.rb | 26 +++++++++++ src/app/models/pool.rb | 1 + src/config/environment.rb | 2 +- src/db/migrate/033_add_pool_audit_trail.rb | 44 +++++++++++++++++++ 8 files changed, 188 insertions(+), 7 deletions(-) create mode 100644 src/app/models/host_observer.rb create mode 100644 src/app/models/membership_audit_event.rb create mode 100644 src/db/migrate/033_add_pool_audit_trail.rb diff --git a/src/app/controllers/graph_controller.rb b/src/app/controllers/graph_controller.rb index ee9425f..e8eea7e 100644 --- a/src/app/controllers/graph_controller.rb +++ b/src/app/controllers/graph_controller.rb @@ -6,9 +6,9 @@ class GraphController < ApplicationController def flexchart_data @id = params[:id] target = params[:target] - startTime = params[:startTime].to_i - endTime = params[:endTime].to_i - duration = endTime - startTime + startTime = Time.at(params[:startTime].to_i) + endTime = Time.at(params[:endTime].to_i) + duration = endTime.to_i - startTime.to_i #the maximum number of data points we want in any chart maxPoints = 100 @@ -29,10 +29,30 @@ class GraphController < ApplicationController counter = DEV_KEY_COUNTERS[target] pool = Pool.find(@id) - hosts = pool.hosts + hosts = Host.find(:all, + :include=> :membership_audit_events, + :conditions => ['membership_audit_events.container_target_id = ?',pool]) + requestList = [ ] hosts.each{ |host| - requestList.push StatsRequest.new(host.hostname, devclass, 0, counter, startTime, duration, resolution, DataFunction::Peak) + eventsInRange = host.membership_audit_events.from_pool(pool, + startTime, + endTime) + priorAuditEvent = host.membership_audit_events.most_recent_prior_event_from_pool(pool,startTime) + timeRanges = get_ranges_from_event_list(eventsInRange, + priorAuditEvent, + startTime, + endTime) + timeRanges.each{ |range| + requestList.push StatsRequest.new(host.hostname, + devclass, + 0, + counter, + range[0].to_i, + range[1].to_i - range[0].to_i, + resolution, + DataFunction::Peak) + } } statsList = getAggregateStatsData?(requestList) @@ -51,6 +71,40 @@ class GraphController < ApplicationController render :json => graph end + def get_ranges_from_event_list(list, priorEvent, startTime, endTime) + + results = Array.new + range = [startTime,endTime] + + joined = false + if priorEvent + if priorEvent.action == MembershipAuditEvent::JOIN + joined = true + end + end + + list.each_with_index { |event,index| + if event.action == MembershipAuditEvent::JOIN + joined = true + range[0] = event.created_at + else + range[0] = startTime unless joined + joined = false + range[1] = event.created_at + results.push Array.new(range) + range = [startTime,endTime] + end + } + + if joined + range[1] = endTime + results.push Array.new(range) + end + + results + end + + # generate layout for availability bar graphs def availability_graph diff --git a/src/app/models/hardware_pool.rb b/src/app/models/hardware_pool.rb index d39d8e7..b72d485 100644 --- a/src/app/models/hardware_pool.rb +++ b/src/app/models/hardware_pool.rb @@ -54,7 +54,7 @@ class HardwarePool < Pool hosts = Host.find(:all, :conditions => "id in (#{host_ids.join(', ')})") transaction do hosts.each do |host| - host.hardware_pool_id = target_pool_id + host.hardware_pool = HardwarePool.find(target_pool_id) host.save! end end diff --git a/src/app/models/host.rb b/src/app/models/host.rb index 640782d..813bc1d 100644 --- a/src/app/models/host.rb +++ b/src/app/models/host.rb @@ -23,6 +23,15 @@ class Host < ActiveRecord::Base belongs_to :hardware_pool belongs_to :bonding_type + has_many :membership_audit_events, :as => :member_target, :dependent => :destroy, :order => "created_at ASC" do + def from_pool(pool,startTime,endTime) + find(:all, :conditions=> ['container_target_id = ? and created_at between ? and ?',pool,startTime,endTime]) + end + def most_recent_prior_event_from_pool(pool,startTime) + find(:last, :conditions=> ['container_target_id = ? and created_at < ?',pool,startTime]) + end + end + has_many :cpus, :dependent => :destroy has_many :nics, :dependent => :destroy has_many :bondings, :dependent => :destroy diff --git a/src/app/models/host_observer.rb b/src/app/models/host_observer.rb new file mode 100644 index 0000000..df5efa1 --- /dev/null +++ b/src/app/models/host_observer.rb @@ -0,0 +1,47 @@ +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Steve Linabery +# +# 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 HostObserver < ActiveRecord::Observer + + def after_create(a_host) + join = MembershipAuditEvent.new({ :member_target => a_host, + :container_target => a_host.hardware_pool, + :action => MembershipAuditEvent::JOIN }) + join.save! + end + + def before_update(a_host) + if a_host.changed? + change = a_host.changes['hardware_pool_id'] + if change + leave = MembershipAuditEvent.new({ :member_target => a_host, + :container_target => HardwarePool.find(change[0]), + :action => MembershipAuditEvent::LEAVE }) + leave.save! + + join = MembershipAuditEvent.new({ :member_target => a_host, + :container_target => HardwarePool.find(change[1]), + :action => MembershipAuditEvent::JOIN }) + join.save! + end + end + end +end + +HostObserver.instance diff --git a/src/app/models/membership_audit_event.rb b/src/app/models/membership_audit_event.rb new file mode 100644 index 0000000..b36cbee --- /dev/null +++ b/src/app/models/membership_audit_event.rb @@ -0,0 +1,26 @@ +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Steve Linabery +# +# 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 MembershipAuditEvent < ActiveRecord::Base + belongs_to :container_target, :polymorphic => true + belongs_to :member_target, :polymorphic => true + + JOIN = "join" + LEAVE = "leave" +end diff --git a/src/app/models/pool.rb b/src/app/models/pool.rb index 7034e79..614325a 100644 --- a/src/app/models/pool.rb +++ b/src/app/models/pool.rb @@ -20,6 +20,7 @@ class Pool < ActiveRecord::Base acts_as_nested_set + has_many :membership_audit_events, :as => :container_target, :dependent => :destroy # moved associations here so that nested set :include directives work # TODO: find a way to put this back into vm_resource_pool.rb has_many :vms, :dependent => :nullify, :order => "id ASC", :foreign_key => :vm_resource_pool_id diff --git a/src/config/environment.rb b/src/config/environment.rb index 53edfad..66cae90 100644 --- a/src/config/environment.rb +++ b/src/config/environment.rb @@ -82,7 +82,7 @@ Rails::Initializer.run do |config| # Activate observers that should always be running # config.active_record.observers = :cacher, :garbage_collector - + config.active_record.observers = :host_observer end # Add new inflection rules using the following format diff --git a/src/db/migrate/033_add_pool_audit_trail.rb b/src/db/migrate/033_add_pool_audit_trail.rb new file mode 100644 index 0000000..d4b4338 --- /dev/null +++ b/src/db/migrate/033_add_pool_audit_trail.rb @@ -0,0 +1,44 @@ +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Steve Linabery +# +# 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 AddPoolAuditTrail < ActiveRecord::Migration + def self.up + create_table :membership_audit_events do |t| + t.timestamp :created_at + t.string :action + t.integer :container_target_id + t.string :container_target_type + t.integer :member_target_id + t.string :member_target_type + t.integer :lock_version, :default => 0 + end + + Host.transaction do + Host.find(:all).each do |host| + + if (! host.membership_audit_events) + event = MembershipAuditEvent.new(:action => MembershipAuditEvent::JOIN, + :container_target => host.hardware_pool, + :member_target => host) + event.save! + end + end + end + end +end -- 1.6.0.6 From jguiditt at redhat.com Fri Jan 9 03:04:14 2009 From: jguiditt at redhat.com (Jason Guiditta) Date: Thu, 08 Jan 2009 22:04:14 -0500 Subject: [Ovirt-devel] Re: oVirt server wui console integration In-Reply-To: <820A3B59-B2C2-4A9D-A48A-A4CB1F6F7B5E@redhat.com> References: <49668014.6060706@redhat.com> <820A3B59-B2C2-4A9D-A48A-A4CB1F6F7B5E@redhat.com> Message-ID: <1231470254.4174.19.camel@physical.priv.ovirt.org> On Thu, 2009-01-08 at 18:23 -0500, Jeremy Perry wrote: > On Jan 8, 2009, at 5:37 PM, Mohammed Morsi wrote: > > > Currently the idea for the console interface in the wui is that a user > > can navigate the the 'virtual machines' tab under a vm pool, click > > on a > > specific vm, click on 'console' in the details pane and will be > > presented with a console to that vm. There were a few ideas as to > > where > > the console should appear, > > > > * in a minimally themed popup window, most likely the first > > implementation as it is simplest, but may result in many popups when > > connected to several vms > > * in the dialog / popup box interface we have now, we will want to > > introduce a tabbing mechanism for access to multiple vm consoles > > * in another tab in the main content area, same vm-tab concept > > needed here > > * a rollover, eg the user rolls over 'console' in the vm details pane > > and the console appears so long as the user holds his mouse over it / > > the link > > > I've taken the liberty of mocking some of these ideas up. > > I didnt mockup the new themed popup window yet, since its simple to > imagine. I think its a decent approach, but wondering if we can > eliminate the multiple popups issue by targeting our popup once there > is at least one open. Subsequent terminals would nest via tabs in the > one terminal window, so all you deal with is one window with tabs for > each vm terminal. I like the idea of the popup window, then adding tabs to it as needed, and like the pop-out (thanks google!). My first choice is the design with the initial console on the right of the details in the same pane. The other with them stacked felt too squished. The tabbed one could work too, but I kind of think the terminal being in the detail pane is not super usable, since you can't see that much in the space allowed. I agree on the modal dialog thing, no need to force them to have only that accessible, but another idea could be a non-modal dialog that you could minimize somewhere w/in the application. If done right, I think this could be pretty slick, but perhaps not worth the effort, as the single popup window seems like a perfectly good way to go. > > > Its currently looking like the console frontend and apache-proxied > > backend daemon will be driven by anyterm http://anyterm.org/ . We will > > use anyterm to launch ovirt-viewer or the virsh console to connect to > > the vm and then present the anyterm html / js / css ui to the user. A > > rough layout of the setup can be found here > > http://ovirt.org/page/Image:Anyterm.png > > I based my mockups on their demos - let me know if the actions I > included (like copy, paste) make sense or not. > > > > Looking for thoughts / feedback / suggestions as to the interface > > placement of the console or the backend. Thanks alot, > > > > -Mo > > > Finally, I wanted to propose we settle on the term "Terminal" instead > of "Console" - at least in the UI - since that is what is used in > Fedora. I know terminology consistency is a challenge for us, is this > a place we can make a choice in the UI and be consistent? > Seems reasonable to me, matches more closely with the 'anyterm' name too. > Thanks! > - Jeremy From pmyers at redhat.com Fri Jan 9 05:07:02 2009 From: pmyers at redhat.com (Perry Myers) Date: Fri, 09 Jan 2009 00:07:02 -0500 Subject: [Ovirt-devel] [PATCH node] Updating menu labels In-Reply-To: <4965A442.3090601@redhat.com> References: <4965A307.1040009@redhat.com> <4965A442.3090601@redhat.com> Message-ID: <4966DB76.1090707@redhat.com> Christopher Curran wrote: > Christopher Curran wrote: >> Can we use the word 'stand-alone' over 'standalone'. I know google >> will disagree with me but style guides and dictionaries support the >> stand-alone spelling. This is mainly to make my life easier by >> sticking to one consistent style. Here is a patch to fix it. >> >> > Stupid email clients... This one should work I've no objection to this change as long as the patch catches all instances of it. Perry From ccurran at redhat.com Fri Jan 9 05:52:57 2009 From: ccurran at redhat.com (Christopher Curran) Date: Fri, 09 Jan 2009 15:52:57 +1000 Subject: [Ovirt-devel] [PATCH node] Updating menu labels In-Reply-To: <4966DB76.1090707@redhat.com> References: <4965A307.1040009@redhat.com> <4965A442.3090601@redhat.com> <4966DB76.1090707@redhat.com> Message-ID: <4966E639.6010706@redhat.com> Perry Myers wrote: > Christopher Curran wrote: >> Christopher Curran wrote: >>> Can we use the word 'stand-alone' over 'standalone'. I know google >>> will disagree with me but style guides and dictionaries support the >>> stand-alone spelling. This is mainly to make my life easier by >>> sticking to one consistent style. Here is a patch to fix it. >>> >>> >> Stupid email clients... This one should work > > I've no objection to this change as long as the patch catches all > instances of it. > > Perry everything except variable names. From pmyers at redhat.com Fri Jan 9 05:53:47 2009 From: pmyers at redhat.com (Perry Myers) Date: Fri, 09 Jan 2009 00:53:47 -0500 Subject: [Ovirt-devel] [PATCH node] Updating menu labels In-Reply-To: <4966E639.6010706@redhat.com> References: <4965A307.1040009@redhat.com> <4965A442.3090601@redhat.com> <4966DB76.1090707@redhat.com> <4966E639.6010706@redhat.com> Message-ID: <4966E66B.20503@redhat.com> Christopher Curran wrote: > Perry Myers wrote: >> Christopher Curran wrote: >>> Christopher Curran wrote: >>>> Can we use the word 'stand-alone' over 'standalone'. I know google >>>> will disagree with me but style guides and dictionaries support the >>>> stand-alone spelling. This is mainly to make my life easier by >>>> sticking to one consistent style. Here is a patch to fix it. >>>> >>>> >>> Stupid email clients... This one should work >> >> I've no objection to this change as long as the patch catches all >> instances of it. >> >> Perry > everything except variable names. That's fine. variable names can omit the hyphen. Perry -- |=- Red Hat, Engineering, Emerging Technologies, Boston -=| |=- Email: pmyers at redhat.com -=| |=- Office: +1 412 474 3552 Mobile: +1 703 362 9622 -=| |=- GnuPG: E65E4F3D 88F9 F1C9 C2F3 1303 01FE 817C C5D2 8B91 E65E 4F3D -=| From jeremy.perry at redhat.com Fri Jan 9 15:55:43 2009 From: jeremy.perry at redhat.com (Jeremy Perry) Date: Fri, 9 Jan 2009 10:55:43 -0500 Subject: [Ovirt-devel] Re: oVirt server wui console integration In-Reply-To: <1231470254.4174.19.camel@physical.priv.ovirt.org> References: <49668014.6060706@redhat.com> <820A3B59-B2C2-4A9D-A48A-A4CB1F6F7B5E@redhat.com> <1231470254.4174.19.camel@physical.priv.ovirt.org> Message-ID: <41FA0D09-2A71-4A17-B9D2-0078B2D40A8D@redhat.com> I've posted the mockups and descriptions mentioned here to the the ovirt.org wiki: http://ovirt.org/page/Terminal_UX one more comment below... On Jan 8, 2009, at 10:04 PM, Jason Guiditta wrote: > On Thu, 2009-01-08 at 18:23 -0500, Jeremy Perry wrote: >> On Jan 8, 2009, at 5:37 PM, Mohammed Morsi wrote: >> >>> Currently the idea for the console interface in the wui is that a >>> user >>> can navigate the the 'virtual machines' tab under a vm pool, click >>> on a >>> specific vm, click on 'console' in the details pane and will be >>> presented with a console to that vm. There were a few ideas as to >>> where >>> the console should appear, >>> >>> * in a minimally themed popup window, most likely the first >>> implementation as it is simplest, but may result in many popups when >>> connected to several vms >>> * in the dialog / popup box interface we have now, we will want to >>> introduce a tabbing mechanism for access to multiple vm consoles >>> * in another tab in the main content area, same vm-tab concept >>> needed here >>> * a rollover, eg the user rolls over 'console' in the vm details >>> pane >>> and the console appears so long as the user holds his mouse over >>> it / >>> the link >>> >> I've taken the liberty of mocking some of these ideas up. >> >> I didnt mockup the new themed popup window yet, since its simple to >> imagine. I think its a decent approach, but wondering if we can >> eliminate the multiple popups issue by targeting our popup once there >> is at least one open. Subsequent terminals would nest via tabs in the >> one terminal window, so all you deal with is one window with tabs for >> each vm terminal. > > I like the idea of the popup window, then adding tabs to it as needed, > and like the pop-out (thanks google!). My first choice is the design > with the initial console on the right of the details in the same pane. > The other with them stacked felt too squished. The tabbed one could > work too, but I kind of think the terminal being in the detail pane is > not super usable, since you can't see that much in the space > allowed. I > agree on the modal dialog thing, no need to force them to have only > that > accessible, but another idea could be a non-modal dialog that you > could > minimize somewhere w/in the application. If done right, I think this > could be pretty slick, but perhaps not worth the effort, as the single > popup window seems like a perfectly good way to go. I agree on the popup window, and will take a stab at it. As for the non-modal idea, this would be pretty cool to look at. Well executed examples in the wild is Google chat in gmail and the alerts/etc bar in facebook. > >> >>> Its currently looking like the console frontend and apache-proxied >>> backend daemon will be driven by anyterm http://anyterm.org/ . We >>> will >>> use anyterm to launch ovirt-viewer or the virsh console to connect >>> to >>> the vm and then present the anyterm html / js / css ui to the >>> user. A >>> rough layout of the setup can be found here >>> http://ovirt.org/page/Image:Anyterm.png >> >> I based my mockups on their demos - let me know if the actions I >> included (like copy, paste) make sense or not. >>> >>> Looking for thoughts / feedback / suggestions as to the interface >>> placement of the console or the backend. Thanks alot, >>> >>> -Mo >> >> >> Finally, I wanted to propose we settle on the term "Terminal" instead >> of "Console" - at least in the UI - since that is what is used in >> Fedora. I know terminology consistency is a challenge for us, is this >> a place we can make a choice in the UI and be consistent? >> > Seems reasonable to me, matches more closely with the 'anyterm' name > too. >> Thanks! >> - Jeremy > From mmorsi at redhat.com Fri Jan 9 17:15:45 2009 From: mmorsi at redhat.com (Mohammed Morsi) Date: Fri, 09 Jan 2009 12:15:45 -0500 Subject: [Ovirt-devel] Re: oVirt server wui console integration In-Reply-To: <41FA0D09-2A71-4A17-B9D2-0078B2D40A8D@redhat.com> References: <49668014.6060706@redhat.com> <820A3B59-B2C2-4A9D-A48A-A4CB1F6F7B5E@redhat.com> <1231470254.4174.19.camel@physical.priv.ovirt.org> <41FA0D09-2A71-4A17-B9D2-0078B2D40A8D@redhat.com> Message-ID: <49678641.4040504@redhat.com> Jeremy Perry wrote: > I've posted the mockups and descriptions mentioned here to the the > ovirt.org wiki: > http://ovirt.org/page/Terminal_UX > > one more comment below... > > On Jan 8, 2009, at 10:04 PM, Jason Guiditta wrote: > >> On Thu, 2009-01-08 at 18:23 -0500, Jeremy Perry wrote: >>> On Jan 8, 2009, at 5:37 PM, Mohammed Morsi wrote: >>> >>>> Currently the idea for the console interface in the wui is that a user >>>> can navigate the the 'virtual machines' tab under a vm pool, click >>>> on a >>>> specific vm, click on 'console' in the details pane and will be >>>> presented with a console to that vm. There were a few ideas as to >>>> where >>>> the console should appear, >>>> >>>> * in a minimally themed popup window, most likely the first >>>> implementation as it is simplest, but may result in many popups when >>>> connected to several vms >>>> * in the dialog / popup box interface we have now, we will want to >>>> introduce a tabbing mechanism for access to multiple vm consoles >>>> * in another tab in the main content area, same vm-tab concept >>>> needed here >>>> * a rollover, eg the user rolls over 'console' in the vm details pane >>>> and the console appears so long as the user holds his mouse over it / >>>> the link >>>> >>> I've taken the liberty of mocking some of these ideas up. >>> >>> I didnt mockup the new themed popup window yet, since its simple to >>> imagine. I think its a decent approach, but wondering if we can >>> eliminate the multiple popups issue by targeting our popup once there >>> is at least one open. Subsequent terminals would nest via tabs in the >>> one terminal window, so all you deal with is one window with tabs for >>> each vm terminal. >> >> I like the idea of the popup window, then adding tabs to it as needed, >> and like the pop-out (thanks google!). My first choice is the design >> with the initial console on the right of the details in the same pane. >> The other with them stacked felt too squished. The tabbed one could >> work too, but I kind of think the terminal being in the detail pane is >> not super usable, since you can't see that much in the space allowed. I >> agree on the modal dialog thing, no need to force them to have only that >> accessible, but another idea could be a non-modal dialog that you could >> minimize somewhere w/in the application. If done right, I think this >> could be pretty slick, but perhaps not worth the effort, as the single >> popup window seems like a perfectly good way to go. > > I agree on the popup window, and will take a stab at it. As for the > non-modal idea, this would be pretty cool to look at. Well executed > examples in the wild is Google chat in gmail and the alerts/etc bar in > facebook. I also agree that the terminal in the details pane seems a bit squished. I'm not sure if we'd be able to do this immediately, but I'd think we'd also want to support terminal resizing at some point in the future (size saved in the user preferences system when we have it). I also like the idea of the non-modal dialog, perhaps we can 'minimize' it to the dashboard so that a user can maintain active terminal sessions between uses of the ovirt wui. > >> >>> >>>> Its currently looking like the console frontend and apache-proxied >>>> backend daemon will be driven by anyterm http://anyterm.org/ . We will >>>> use anyterm to launch ovirt-viewer or the virsh console to connect to >>>> the vm and then present the anyterm html / js / css ui to the user. A >>>> rough layout of the setup can be found here >>>> http://ovirt.org/page/Image:Anyterm.png >>> >>> I based my mockups on their demos - let me know if the actions I >>> included (like copy, paste) make sense or not. Ya thats totally fine for the mockups, I might remove some of that stuff from the anyterm html that gets added to the project (its all gpl) depending of how it works and what we need. In any case 'Close' will definetly be staying, 'copy' and 'paste' might be removed depending on if we can get that functionality without it, 'Control Keys' will most likey be removed as they work without needing the drop down. I do like the 'pop out' action you added, and I'll look into seeing how the terminal location can be parametrized so that we could put it in multiple locations. >>>> >>>> Looking for thoughts / feedback / suggestions as to the interface >>>> placement of the console or the backend. Thanks alot, >>>> >>>> -Mo >>> >>> >>> Finally, I wanted to propose we settle on the term "Terminal" instead >>> of "Console" - at least in the UI - since that is what is used in >>> Fedora. I know terminology consistency is a challenge for us, is this >>> a place we can make a choice in the UI and be consistent? >>> >> Seems reasonable to me, matches more closely with the 'anyterm' name >> too. >>> Thanks! >>> - Jeremy >> > Sounds good to me too. -Mo From mdehaan at redhat.com Fri Jan 9 21:55:31 2009 From: mdehaan at redhat.com (Michael DeHaan) Date: Fri, 09 Jan 2009 16:55:31 -0500 Subject: [Ovirt-devel] Re: oVirt server wui console integration In-Reply-To: <49678641.4040504@redhat.com> References: <49668014.6060706@redhat.com> <820A3B59-B2C2-4A9D-A48A-A4CB1F6F7B5E@redhat.com> <1231470254.4174.19.camel@physical.priv.ovirt.org> <41FA0D09-2A71-4A17-B9D2-0078B2D40A8D@redhat.com> <49678641.4040504@redhat.com> Message-ID: <4967C7D3.9080004@redhat.com> Mohammed Morsi wrote: > Jeremy Perry wrote: > >> I've posted the mockups and descriptions mentioned here to the the >> ovirt.org wiki: >> http://ovirt.org/page/Terminal_UX >> >> one more comment below... >> >> On Jan 8, 2009, at 10:04 PM, Jason Guiditta wrote: >> >> >>> On Thu, 2009-01-08 at 18:23 -0500, Jeremy Perry wrote: >>> >>>> On Jan 8, 2009, at 5:37 PM, Mohammed Morsi wrote: >>>> >>>> >>>>> Currently the idea for the console interface in the wui is that a user >>>>> can navigate the the 'virtual machines' tab under a vm pool, click >>>>> on a >>>>> specific vm, click on 'console' in the details pane and will be >>>>> presented with a console to that vm. There were a few ideas as to >>>>> where >>>>> the console should appear, >>>>> >>>>> * in a minimally themed popup window, most likely the first >>>>> implementation as it is simplest, but may result in many popups when >>>>> connected to several vms >>>>> * in the dialog / popup box interface we have now, we will want to >>>>> introduce a tabbing mechanism for access to multiple vm consoles >>>>> * in another tab in the main content area, same vm-tab concept >>>>> needed here >>>>> * a rollover, eg the user rolls over 'console' in the vm details pane >>>>> and the console appears so long as the user holds his mouse over it / >>>>> the link >>>>> >>>>> >>>> I've taken the liberty of mocking some of these ideas up. >>>> >>>> I didnt mockup the new themed popup window yet, since its simple to >>>> imagine. I think its a decent approach, but wondering if we can >>>> eliminate the multiple popups issue by targeting our popup once there >>>> is at least one open. Subsequent terminals would nest via tabs in the >>>> one terminal window, so all you deal with is one window with tabs for >>>> each vm terminal. >>>> >>> I like the idea of the popup window, then adding tabs to it as needed, >>> and like the pop-out (thanks google!). My first choice is the design >>> with the initial console on the right of the details in the same pane. >>> The other with them stacked felt too squished. The tabbed one could >>> work too, but I kind of think the terminal being in the detail pane is >>> not super usable, since you can't see that much in the space allowed. I >>> agree on the modal dialog thing, no need to force them to have only that >>> accessible, but another idea could be a non-modal dialog that you could >>> minimize somewhere w/in the application. If done right, I think this >>> could be pretty slick, but perhaps not worth the effort, as the single >>> popup window seems like a perfectly good way to go. >>> >> I agree on the popup window, and will take a stab at it. As for the >> non-modal idea, this would be pretty cool to look at. Well executed >> examples in the wild is Google chat in gmail and the alerts/etc bar in >> facebook. >> > > I also agree that the terminal in the details pane seems a bit squished. > I'm not sure if we'd be able to do this immediately, but I'd think we'd > also want to support terminal resizing at some point in the future > (size saved in the user preferences system when we have it). I also like > the idea of the non-modal dialog, perhaps we can 'minimize' it to the > dashboard so that a user can maintain active terminal sessions between > uses of the ovirt wui. > > > >>>>> Its currently looking like the console frontend and apache-proxied >>>>> backend daemon will be driven by anyterm http://anyterm.org/ . We will >>>>> use anyterm to launch ovirt-viewer or the virsh console to connect to >>>>> the vm and then present the anyterm html / js / css ui to the user. A >>>>> rough layout of the setup can be found here >>>>> http://ovirt.org/page/Image:Anyterm.png >>>>> >>>> I based my mockups on their demos - let me know if the actions I >>>> included (like copy, paste) make sense or not. >>>> > > Ya thats totally fine for the mockups, I might remove some of that stuff > from the anyterm html that gets added to the project (its all gpl) > depending of how it works and what we need. > > In any case 'Close' will definetly be staying, 'copy' and 'paste' might > be removed depending on if we can get that functionality without it, > 'Control Keys' will most likey be removed as they work without needing > the drop down. I do like the 'pop out' action you added, and I'll look > into seeing how the terminal location can be parametrized so that we > could put it in multiple locations. > > > >>>>> Looking for thoughts / feedback / suggestions as to the interface >>>>> placement of the console or the backend. Thanks alot, >>>>> >>>>> -Mo >>>>> >>>> Finally, I wanted to propose we settle on the term "Terminal" instead >>>> of "Console" - at least in the UI - since that is what is used in >>>> Fedora. I know terminology consistency is a challenge for us, is this >>>> a place we can make a choice in the UI and be consistent? >>>> >>>> >>> Seems reasonable to me, matches more closely with the 'anyterm' name >>> too. >>> >>>> Thanks! >>>> - Jeremy >>>> > > Sounds good to me too. > > -Mo > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel > How about a link to just the terminal (no-popup) so someone can just do "New Tab" in Firefox and get a nice large terminal? Tabs across the top may also not scale if a user has a bit too many VMs open (perhaps a drop down to select the VM, or multiple firefox tabs?) --Michael From sseago at redhat.com Fri Jan 9 22:33:41 2009 From: sseago at redhat.com (Scott Seago) Date: Fri, 09 Jan 2009 17:33:41 -0500 Subject: [Ovirt-devel] [PATCH server] (Legit) Add audit trl for hosts join/leaving hwpools w/Rails observer class In-Reply-To: <1231465853-2898-1-git-send-email-slinabery@redhat.com> References: <1231465853-2898-1-git-send-email-slinabery@redhat.com> Message-ID: <4967D0C5.9050703@redhat.com> Steve Linabery wrote: > Modify graph_controller.rb to utilize new audit feature when generating data for flexchart > --- > src/app/controllers/graph_controller.rb | 64 +++++++++++++++++++++++++-- > src/app/models/hardware_pool.rb | 2 +- > src/app/models/host.rb | 9 ++++ > src/app/models/host_observer.rb | 47 ++++++++++++++++++++ > src/app/models/membership_audit_event.rb | 26 +++++++++++ > src/app/models/pool.rb | 1 + > src/config/environment.rb | 2 +- > src/db/migrate/033_add_pool_audit_trail.rb | 44 +++++++++++++++++++ > 8 files changed, 188 insertions(+), 7 deletions(-) > create mode 100644 src/app/models/host_observer.rb > create mode 100644 src/app/models/membership_audit_event.rb > create mode 100644 src/db/migrate/033_add_pool_audit_trail.rb > > diff --git a/src/db/migrate/033_add_pool_audit_trail.rb b/src/db/migrate/033_add_pool_audit_trail.rb > new file mode 100644 > index 0000000..d4b4338 > --- /dev/null > +++ b/src/db/migrate/033_add_pool_audit_trail.rb > @@ -0,0 +1,44 @@ > +class AddPoolAuditTrail < ActiveRecord::Migration > + def self.up > + create_table :membership_audit_events do |t| > + t.timestamp :created_at > + t.string :action > + t.integer :container_target_id > + t.string :container_target_type > + t.integer :member_target_id > + t.string :member_target_type > + t.integer :lock_version, :default => 0 > + end > + > + Host.transaction do > + Host.find(:all).each do |host| > + > + if (! host.membership_audit_events) > This line needs to be changed to if (host.membership_audit_events.empty?) > + event = MembershipAuditEvent.new(:action => MembershipAuditEvent::JOIN, > + :container_target => host.hardware_pool, > + :member_target => host) > + event.save! > + end > + end > + end > + end > +end > You should also probably write the self.down action to remove the table if a downgrade is attempted. But other than these two migration issues, ACK -- seems to work fine for me. Scott From my.nikkea at gmail.com Fri Jan 9 09:46:30 2009 From: my.nikkea at gmail.com (nikkea) Date: Fri, 09 Jan 2009 17:46:30 +0800 Subject: [Ovirt-devel] How to update ovirt based current version? Message-ID: <49671CF6.4010904@gmail.com> --Just as title. From pmyers at redhat.com Fri Jan 9 23:33:07 2009 From: pmyers at redhat.com (Perry Myers) Date: Fri, 09 Jan 2009 18:33:07 -0500 Subject: [Ovirt-devel] How to update ovirt based current version? In-Reply-To: <49671CF6.4010904@gmail.com> References: <49671CF6.4010904@gmail.com> Message-ID: <4967DEB3.4010004@redhat.com> nikkea wrote: > --Just as title. Right now we don't support upgrades from released versions since the API and database formats are still actively being updated. Starting with 1.0 we'll support upgrades between minor version release. But for the time being we recommend that users start fresh with each release. 0.96 is the latest release right now. Thanks, Perry From lutter at redhat.com Sat Jan 10 00:02:48 2009 From: lutter at redhat.com (David Lutterkort) Date: Fri, 09 Jan 2009 16:02:48 -0800 Subject: [Ovirt-devel] [PATCH] Add task list to dashboard In-Reply-To: <1231440209-26690-1-git-send-email-sseago@redhat.com> References: <1231440209-26690-1-git-send-email-sseago@redhat.com> Message-ID: <1231545768.434.31.camel@localhost.localdomain> On Thu, 2009-01-08 at 18:43 +0000, Scott Seago wrote: > Refactored task list functionality to allow for the dashboard-level task list. > The dashboard task list shows all tasks initiated by the logged-in user, and is > filterable by task type and state. This causes trouble for me when looking at the task list for a VM pool (see below) Some minor nits on the presentation: * When I look at the dashboard now, I have a single tab that says 'Dashboard' - shouldn't that say 'Tasks' ? * When there are no tasks to display, I get that empty splash screen with a '+' in it, as if I could add a task - that shouldn't be there * Some general comments on how task lists are displayed (nothing to do with this patch in particular): 1. Could we use an icon to indicate state ? Using a whole column is kinda bulky, and not as informative as a nice icon 2. The column 'Message' is only visible after scrolling, even though it's pretty important - that should be moved to a more prominent position (like right next to 'Action') 3. The column 'Args' is almost always empty - why not just drop it from the default view, or roll the info from that into another column, e.g. Action 4. It would be nice if you could combine several of the Type resp. State filters (like look at all Storage and Storage Volume tasks) - and as somebody else mentioned, a clearer indication of the currently active filters 5. Conceptually, do users really care about the distinction between 'Storage' and 'Storage Volume' tasks ? Why not just lump them all into 'Storage tasks' ? Some more comments; most of them are more todo type items, though it might be good to address as many of htem aspossible right away. > Signed-off-by: Scott Seago > --- > src/app/controllers/dashboard_controller.rb | 41 +++++++--- > src/app/controllers/hardware_controller.rb | 12 +--- > src/app/controllers/pool_controller.rb | 41 ++-------- > src/app/controllers/task_actions.rb | 50 ++++++++++++ > src/app/models/task.rb | 13 +++ > src/app/views/dashboard/index.html.erb | 38 ++------- > src/app/views/hardware/show_tasks.rhtml | 84 ++------------------ > src/app/views/layouts/_navigation_tabs.rhtml | 20 ++++- > src/app/views/resources/show_tasks.rhtml | 68 ++-------------- > src/app/views/task/_grid.rhtml | 2 +- > .../show_tasks.rhtml => task/_show.rhtml} | 57 +++++++------ > 11 files changed, 169 insertions(+), 257 deletions(-) > create mode 100644 src/app/controllers/task_actions.rb > copy src/app/views/{hardware/show_tasks.rhtml => task/_show.rhtml} (59%) > > diff --git a/src/app/controllers/dashboard_controller.rb b/src/app/controllers/dashboard_controller.rb > index c4830df..00398a5 100644 > --- a/src/app/controllers/dashboard_controller.rb > +++ b/src/app/controllers/dashboard_controller.rb > @@ -18,19 +18,36 @@ > # also available at http://www.gnu.org/copyleft/gpl.html. > > class DashboardController < ApplicationController Not directly a comment about this patch: it would be cleaner if we had a TaskController with an index action that accepts parameters to restrict the list of tasks to a certain object, e.g. a hw pool or a vm pool. The implementation with TaskActions and the index -> show_tasks -> show call sequence seems a little roundabout. > + > + include TaskActions > + def tasks_query_obj > + Task > + end > + def tasks_conditions > + {:user => get_login_user} > + end > + > def index > - @default_pool = HardwarePool.get_default_pool > - set_perms(@default_pool) > - #remove these soon > - @hardware_pools = HardwarePool.find(:all) > - @available_hosts = Host.find(:all) > - @available_storage_volumes = StorageVolume.find(:all) > - @storage_pools = StoragePool.find(:all) > - @hosts = Host.find(:all) > - @storage_volumes = StorageVolume.find(:all) > - @vms = Vm.find(:all) > - if params[:ajax] > - render :layout => 'tabs-and-content' #:template => 'hardware/show.html.erb' > + @task_types = Task::TASK_TYPES_OPTIONS > + show_tasks > + end > + > + def show > + respond_to do |format| > + format.html { > + render :layout => 'tabs-and-content' if params[:ajax] > + render :layout => 'help-and-content' if params[:nolayout] > + } > + format.xml { > + render :xml => @pool.to_xml(XML_OPTS) > + } > end > end Thanks for thinking of the API ;) It seems though that this is missing a route to really work - and for retrieving lists of items, the index action should be used, not show. > --- a/src/app/views/hardware/show_tasks.rhtml > +++ b/src/app/views/task/_show.rhtml > @@ -1,33 +1,36 @@ >
        > -
          > -
        • > - <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Type    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> > -
            > - <% @task_types.each_index { |index| %> > -
          • - <% if (index == @task_types.length - 1) or @task_types[index].length == 3 %> > - style="border-bottom: 1px solid #CCCCCC;" > - <% end %> > - > > - > - <%= @task_type == @task_types[index][1] ? "X" : "  " %> > - <%=@task_types[index][0]%> > -
          • > - <% } %> > -
          > -
        • > +
            > + <%if defined? task_types %> > +
          • > + <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Type    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> > +
              > + <% task_types.each_index { |index| %> When I look at the task list for a VM pool, this gives me ActionView::TemplateError (You have a nil object when you didn't expect it! You might have expected an instance of Array. The error occurred while evaluating nil.each_index) on line #7 of task/_show.rhtml: 4:
            • 5: <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Type    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> 6:
                7: <% @task_types.each_index { |index| %> 8:
              • 10: style="border-bottom: 1px solid #CCCCCC;" David From sseago at redhat.com Sat Jan 10 02:00:05 2009 From: sseago at redhat.com (Scott Seago) Date: Fri, 09 Jan 2009 21:00:05 -0500 Subject: [Ovirt-devel] [PATCH] Add task list to dashboard In-Reply-To: <1231545768.434.31.camel@localhost.localdomain> References: <1231440209-26690-1-git-send-email-sseago@redhat.com> <1231545768.434.31.camel@localhost.localdomain> Message-ID: <49680125.3090907@redhat.com> David Lutterkort wrote: > On Thu, 2009-01-08 at 18:43 +0000, Scott Seago wrote: > >> Refactored task list functionality to allow for the dashboard-level task list. >> The dashboard task list shows all tasks initiated by the logged-in user, and is >> filterable by task type and state. >> > > This causes trouble for me when looking at the task list for a VM pool > (see below) > > Some minor nits on the presentation: > > * When I look at the dashboard now, I have a single tab that says > 'Dashboard' - shouldn't that say 'Tasks' ? > It's still 'dashboard' since the fact that tasks is the only tab is temporary. Dashboard will eventually have alerts, user preferences, and other stuff -- but the rest of it isn't ready yet. Although I'd be fine w/ the tab saying 'Tasks' as long as the left nav still said 'Dashboard' > * When there are no tasks to display, I get that empty splash > screen with a '+' in it, as if I could add a task - that > shouldn't be there > Good point. I'll remove it -- it makes sense for VMs, hosts, etc but not here. > * Some general comments on how task lists are displayed (nothing > to do with this patch in particular): > 1. Could we use an icon to indicate state ? Using a whole > column is kinda bulky, and not as informative as a nice > icon > The icon would be useful, yes, but we may still want the column so we can sort and filter by it. Anyway perhaps it's a point to work through w/ Jeremy. > 2. The column 'Message' is only visible after scrolling, > even though it's pretty important - that should be moved > to a more prominent position (like right next to > 'Action') > Easy enough to do. > 3. The column 'Args' is almost always empty - why not just > drop it from the default view, or roll the info from > that into another column, e.g. Action > Hmm. Yeah it's empty for the basic VM actions, but migrate, etc can use it. Joining it w/ action might be just the right thing though. So for "start_vm" we still have just that. But for migrate_vm w/ the arg being the host w/ ID 5 it would say "migrate_vm 5". > 4. It would be nice if you could combine several of the > Type resp. State filters (like look at all Storage and > Storage Volume tasks) - and as somebody else mentioned, > a clearer indication of the currently active filters > Yeah redoing the filter setup is another task on the sprint list which will involve reworking filter display and adding date ranges. Perhaps, time permitting, we could look into filtering by groups as well, depending on how much work it is. > 5. Conceptually, do users really care about the distinction > between 'Storage' and 'Storage Volume' tasks ? Why not > just lump them all into 'Storage tasks' ? > > Well the task type distinction is more for the benefit of taskomatic than for users -- the task type determines the behavior of the task. Different object pointed to, different ruby class implementation, etc. If there's a need for a more human-friendly categorization of tasks, we could consider adding it, but we shouldn't mix that up w/ 'type' which has model and class implications. In addition, a category-like 'type' field would allow us to distinguish different types of VM tasks. Note that I won't hold up pushing this patch on the above 5 points, as they have more to do with the overall UI design of the existing task list rather than the dashboard refactoring, and in some cases we have UI design issues to work through before resolving them anyway. > Some more comments; most of them are more todo type items, though it > might be good to address as many of htem aspossible right away. > > >> Signed-off-by: Scott Seago >> --- >> src/app/controllers/dashboard_controller.rb | 41 +++++++--- >> src/app/controllers/hardware_controller.rb | 12 +--- >> src/app/controllers/pool_controller.rb | 41 ++-------- >> src/app/controllers/task_actions.rb | 50 ++++++++++++ >> src/app/models/task.rb | 13 +++ >> src/app/views/dashboard/index.html.erb | 38 ++------- >> src/app/views/hardware/show_tasks.rhtml | 84 ++------------------ >> src/app/views/layouts/_navigation_tabs.rhtml | 20 ++++- >> src/app/views/resources/show_tasks.rhtml | 68 ++-------------- >> src/app/views/task/_grid.rhtml | 2 +- >> .../show_tasks.rhtml => task/_show.rhtml} | 57 +++++++------ >> 11 files changed, 169 insertions(+), 257 deletions(-) >> create mode 100644 src/app/controllers/task_actions.rb >> copy src/app/views/{hardware/show_tasks.rhtml => task/_show.rhtml} (59%) >> >> diff --git a/src/app/controllers/dashboard_controller.rb b/src/app/controllers/dashboard_controller.rb >> index c4830df..00398a5 100644 >> --- a/src/app/controllers/dashboard_controller.rb >> +++ b/src/app/controllers/dashboard_controller.rb >> @@ -18,19 +18,36 @@ >> # also available at http://www.gnu.org/copyleft/gpl.html. >> >> class DashboardController < ApplicationController >> > > Not directly a comment about this patch: it would be cleaner if we had a > TaskController with an index action that accepts parameters to restrict > the list of tasks to a certain object, e.g. a hw pool or a vm pool. > > The implementation with TaskActions and the index -> show_tasks -> show > call sequence seems a little roundabout. > > I tried to pull all of the generic stuff (that applies to more than one of the 3 controllers that have task lists) into the task_actions module which is included by the controllers that have task lists. I suppose we could have a separate controller with 3 different actions relating to dashboard, vm, and hw pool, but it doesn't really match the model we're already using for VM pool and HW pool controllers -- where one controller handles the various UI tabs for an object type. So the bits common to all task lists are already pulled out into task_actions -- and on the view side in task/_show and task/_grid. Some of the roundabout nature here has to do with the way the flexigrid setup works -- we need one action to generate the page itself -- with navigation, filters, etc., and another action to return the json array for the table content. The index vs. show_tasks confusion will go away once we move the task list off the index action -- i.e. the dashboard index will be a portal-like page and the task list will be a separate tab called show_tasks just like elsewhere. >> + >> + include TaskActions >> + def tasks_query_obj >> + Task >> + end >> + def tasks_conditions >> + {:user => get_login_user} >> + end >> + >> def index >> - @default_pool = HardwarePool.get_default_pool >> - set_perms(@default_pool) >> - #remove these soon >> - @hardware_pools = HardwarePool.find(:all) >> - @available_hosts = Host.find(:all) >> - @available_storage_volumes = StorageVolume.find(:all) >> - @storage_pools = StoragePool.find(:all) >> - @hosts = Host.find(:all) >> - @storage_volumes = StorageVolume.find(:all) >> - @vms = Vm.find(:all) >> - if params[:ajax] >> - render :layout => 'tabs-and-content' #:template => 'hardware/show.html.erb' >> + @task_types = Task::TASK_TYPES_OPTIONS >> + show_tasks >> + end >> + >> + def show >> + respond_to do |format| >> + format.html { >> + render :layout => 'tabs-and-content' if params[:ajax] >> + render :layout => 'help-and-content' if params[:nolayout] >> + } >> + format.xml { >> + render :xml => @pool.to_xml(XML_OPTS) >> + } >> end >> end >> > > Thanks for thinking of the API ;) It seems though that this is missing a > route to really work - and for retrieving lists of items, the index > action should be used, not show. > > Yeah -- mostly I was pulling the show action from the other controllers -- in fact we're not really even using show directly -- it's mostly an artifact of the way that show_tasks works for the other instances ,and I wanted to reuse as much of this as possible. In general the 'index' action is used a lot for the API, but none of the web UI uses index in the current iteration (except dashboard) >> --- a/src/app/views/hardware/show_tasks.rhtml >> +++ b/src/app/views/task/_show.rhtml >> @@ -1,33 +1,36 @@ >>
                >> -
                  >> -
                • >> - <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Type    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> >> -
                    >> - <% @task_types.each_index { |index| %> >> -
                  • > - <% if (index == @task_types.length - 1) or @task_types[index].length == 3 %> >> - style="border-bottom: 1px solid #CCCCCC;" >> - <% end %> >> - > >> - >> - <%= @task_type == @task_types[index][1] ? "X" : "  " %> >> - <%=@task_types[index][0]%> >> -
                  • >> - <% } %> >> -
                  >> -
                • >> +
                    >> + <%if defined? task_types %> >> +
                  • >> + <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Type    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> >> +
                      >> + <% task_types.each_index { |index| %> >> > > When I look at the task list for a VM pool, this gives me > > ActionView::TemplateError (You have a nil object when you didn't expect it! > You might have expected an instance of Array. > The error occurred while evaluating nil.each_index) on line #7 of task/_show.rhtml: > 4:
                    • > 5: <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Type    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> > 6:
                        > 7: <% @task_types.each_index { |index| %> > 8:
                      • 9: <% if (index == task_types.length - 1) or task_types[index].length == 3 %> > 10: style="border-bottom: 1px solid #CCCCCC;" > > David > > Oops. Looks like I didn't follow through with enough testing at the end. I ran into a lot of refactoring bugs that broke either the dashboard view or the HW pool view and when I finally came up with something that worked for both I must have forgotten to re-test the VM pool UI again. OK so of the above issues, the ones that I will rework into an updated patch are as follows: 1) dashboard tab name changed to 'Tasks' (left nav is still 'dashboard') 2) fix the 'no tasks' view to remove the 'add' icon 3) Fix whatever's wrong with the VM pool template/controller in the current patch. Let me know if there's anything else in the above comments that ought to be handled before pushing. And, of course, for some of the above the discussion is ongoing :-) Scott From pronix.service at gmail.com Mon Jan 12 12:22:48 2009 From: pronix.service at gmail.com (pronix pronix) Date: Mon, 12 Jan 2009 15:22:48 +0300 Subject: [Ovirt-devel] are 'migration' between hosts working ? Message-ID: <639ce0480901120422j455be592oeb72ce3f3e2a2ac0@mail.gmail.com> when i try migrate vm from one host to another, i see error "Selected Migration Target: No migration target selected." but i haven't select menu whith hosts listing From pronix.service at gmail.com Mon Jan 12 13:37:27 2009 From: pronix.service at gmail.com (pronix pronix) Date: Mon, 12 Jan 2009 16:37:27 +0300 Subject: [Ovirt-devel] Re: are 'migration' between hosts working ? In-Reply-To: <639ce0480901120422j455be592oeb72ce3f3e2a2ac0@mail.gmail.com> References: <639ce0480901120422j455be592oeb72ce3f3e2a2ac0@mail.gmail.com> Message-ID: <639ce0480901120537k6adbe870leb85b77316a7de33@mail.gmail.com> found litle bug diff --git a/src/task-omatic/task_vm.rb b/src/task-omatic/task_vm.rb index c187287..cbeda20 100644 --- a/src/task-omatic/task_vm.rb +++ b/src/task-omatic/task_vm.rb @@ -656,7 +656,7 @@ def migrate(vm, dest = nil) src_conn = Libvirt::open("qemu+tcp://" + src_host.hostname + "/system") dst_conn = Libvirt::open("qemu+tcp://" + dst_host.hostname + "/system") - connect_storage_pools(dst_conn, vm) + connect_storage_pools(dst_conn, vm.storage_volumes) dom = src_conn.lookup_domain_by_uuid(vm.uuid) dom.migrate(dst_conn, Libvirt::Domain::MIGRATE_LIVE) 2009/1/12 pronix pronix : > when i try migrate vm from one host to another, i see error "Selected > Migration Target: > No migration target selected." > but i haven't select menu whith hosts listing > From jeremy.perry at redhat.com Mon Jan 12 15:00:56 2009 From: jeremy.perry at redhat.com (Jeremy Perry) Date: Mon, 12 Jan 2009 10:00:56 -0500 Subject: [Ovirt-devel] [PATCH] Add task list to dashboard In-Reply-To: <1231545768.434.31.camel@localhost.localdomain> References: <1231440209-26690-1-git-send-email-sseago@redhat.com> <1231545768.434.31.camel@localhost.localdomain> Message-ID: <89BF2C44-1110-4C39-8C70-3AA74520314F@redhat.com> On Jan 9, 2009, at 7:02 PM, David Lutterkort wrote: > On Thu, 2009-01-08 at 18:43 +0000, Scott Seago wrote: >> Refactored task list functionality to allow for the dashboard-level >> task list. >> The dashboard task list shows all tasks initiated by the logged-in >> user, and is >> filterable by task type and state. > Good comments David - I've got a page in the wiki now to start capturing UX for the Dashboard. http://ovirt.org/page/Dashboard_UX > This causes trouble for me when looking at the task list for a VM pool > (see below) > > Some minor nits on the presentation: > > * When I look at the dashboard now, I have a single tab that says > 'Dashboard' - shouldn't that say 'Tasks' ? If the dashboard is a singleton, I think it might be best to have no tab at all. But otherwise, Tasks seems to be a better label. > * When there are no tasks to display, I get that empty splash > screen with a '+' in it, as if I could add a task - that > shouldn't be there Agree > > * Some general comments on how task lists are displayed (nothing > to do with this patch in particular): > 1. Could we use an icon to indicate state ? Using a whole > column is kinda bulky, and not as informative as a nice > icon > 2. The column 'Message' is only visible after scrolling, > even though it's pretty important - that should be > moved > to a more prominent position (like right next to > 'Action') > 3. The column 'Args' is almost always empty - why not just > drop it from the default view, or roll the info from > that into another column, e.g. Action > 4. It would be nice if you could combine several of the > Type resp. State filters (like look at all Storage and > Storage Volume tasks) - and as somebody else mentioned, > a clearer indication of the currently active filters > 5. Conceptually, do users really care about the > distinction > between 'Storage' and 'Storage Volume' tasks ? Why not > just lump them all into 'Storage tasks' ? I agree with all the comments here - I think we should do all we can to make the Dashboard and specifically the task list more consumable at a glance. ... - Jeremy From sseago at redhat.com Mon Jan 12 15:19:09 2009 From: sseago at redhat.com (Scott Seago) Date: Mon, 12 Jan 2009 15:19:09 +0000 Subject: [Ovirt-devel] [PATCH] Add task list to dashboard (revised) Message-ID: <1231773549-13671-1-git-send-email-sseago@redhat.com> Refactored task list functionality to allow for the dashboard-level task list. The dashboard task list shows all tasks initiated by the logged-in user, and is filterable by task type and state. revised to fix a couple bugs found by lutter Signed-off-by: Scott Seago --- src/app/controllers/dashboard_controller.rb | 41 +++++++--- src/app/controllers/hardware_controller.rb | 12 +--- src/app/controllers/pool_controller.rb | 41 ++-------- src/app/controllers/task_actions.rb | 50 ++++++++++++ src/app/models/task.rb | 13 +++ src/app/views/dashboard/index.html.erb | 38 ++------- src/app/views/hardware/show_tasks.rhtml | 84 ++------------------ src/app/views/layouts/_navigation_tabs.rhtml | 20 ++++- src/app/views/resources/show_tasks.rhtml | 68 ++-------------- src/app/views/task/_grid.rhtml | 2 +- .../show_tasks.rhtml => task/_show.rhtml} | 60 +++++++------- 11 files changed, 170 insertions(+), 259 deletions(-) create mode 100644 src/app/controllers/task_actions.rb copy src/app/views/{hardware/show_tasks.rhtml => task/_show.rhtml} (56%) diff --git a/src/app/controllers/dashboard_controller.rb b/src/app/controllers/dashboard_controller.rb index c4830df..00398a5 100644 --- a/src/app/controllers/dashboard_controller.rb +++ b/src/app/controllers/dashboard_controller.rb @@ -18,19 +18,36 @@ # also available at http://www.gnu.org/copyleft/gpl.html. class DashboardController < ApplicationController + + include TaskActions + def tasks_query_obj + Task + end + def tasks_conditions + {:user => get_login_user} + end + def index - @default_pool = HardwarePool.get_default_pool - set_perms(@default_pool) - #remove these soon - @hardware_pools = HardwarePool.find(:all) - @available_hosts = Host.find(:all) - @available_storage_volumes = StorageVolume.find(:all) - @storage_pools = StoragePool.find(:all) - @hosts = Host.find(:all) - @storage_volumes = StorageVolume.find(:all) - @vms = Vm.find(:all) - if params[:ajax] - render :layout => 'tabs-and-content' #:template => 'hardware/show.html.erb' + @task_types = Task::TASK_TYPES_OPTIONS + show_tasks + end + + def show + respond_to do |format| + format.html { + render :layout => 'tabs-and-content' if params[:ajax] + render :layout => 'help-and-content' if params[:nolayout] + } + format.xml { + render :xml => @pool.to_xml(XML_OPTS) + } end end + + def tasks_internal + @task_type = params[:task_type] + @task_type ||="" + super + end + end diff --git a/src/app/controllers/hardware_controller.rb b/src/app/controllers/hardware_controller.rb index 4dda736..7be67cc 100644 --- a/src/app/controllers/hardware_controller.rb +++ b/src/app/controllers/hardware_controller.rb @@ -116,17 +116,7 @@ class HardwareController < PoolController end def show_tasks - @task_types = [["VM Task", "VmTask"], - ["Host Task", "HostTask"], - ["Storage Task", "StorageTask"], - ["Storage Volume Task", "StorageVolumeTask", "break"], - ["Show All", ""]] - super - end - - def tasks_internal - @task_type = params[:task_type] - @task_type ||="" + @task_types = Task::TASK_TYPES_OPTIONS super end diff --git a/src/app/controllers/pool_controller.rb b/src/app/controllers/pool_controller.rb index 03d1316..b8d0f10 100644 --- a/src/app/controllers/pool_controller.rb +++ b/src/app/controllers/pool_controller.rb @@ -31,6 +31,14 @@ class PoolController < ApplicationController :include => [ :storage_pools, :hosts, :quota ] } + include TaskActions + def tasks_query_obj + @pool.tasks + end + def tasks_conditions + {} + end + def show respond_to do |format| format.html { @@ -58,39 +66,6 @@ class PoolController < ApplicationController [:grid_id, :uid, :user_role, :source]) end - def show_tasks - @task_states = [["Queued", Task::STATE_QUEUED], - ["Running", Task::STATE_RUNNING], - ["Paused", Task::STATE_PAUSED], - ["Finished", Task::STATE_FINISHED], - ["Failed", Task::STATE_FAILED], - ["Canceled", Task::STATE_CANCELED, "break"], - ["Show All", ""]] - params[:page]=1 - params[:sortname]="tasks.created_at" - params[:sortorder]="desc" - @tasks = tasks_internal - show - end - - def tasks - render :json => tasks_internal.to_json - end - - def tasks_internal - @task_state = params[:task_state] - @task_state ||=Task::STATE_QUEUED - conditions = {} - conditions[:type] = @task_type unless @task_type.empty? - conditions[:state] = @task_state unless @task_state.empty? - find_opts = {:include => [:storage_pool, :host, :vm]} - find_opts[:conditions] = conditions unless conditions.empty? - attr_list = [] - attr_list << :id if params[:checkboxes] - attr_list += [:type_label, :task_obj, :action, :state, :user, :created_at, :args, :message] - json_hash(@pool.tasks, attr_list, [:all], find_opts) - end - def hosts_json(args) attr_list = [] attr_list << :id if params[:checkboxes] diff --git a/src/app/controllers/task_actions.rb b/src/app/controllers/task_actions.rb new file mode 100644 index 0000000..d71c11e --- /dev/null +++ b/src/app/controllers/task_actions.rb @@ -0,0 +1,50 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Scott Seago +# +# 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. +module TaskActions + def show_tasks + @task_states = Task::TASK_STATES_OPTIONS + params[:page]=1 + params[:sortname]="tasks.created_at" + params[:sortorder]="desc" + @tasks = tasks_internal + show + end + + def tasks + render :json => tasks_internal.to_json + end + + def tasks_internal + @task_state = params[:task_state] + @task_state ||=Task::STATE_QUEUED + @task_type = params[:task_type] + @task_type ||="" + conditions = tasks_conditions + conditions[:type] = @task_type unless @task_type.empty? + conditions[:state] = @task_state unless @task_state.empty? + find_opts = {:include => [:storage_pool, :host, :vm]} + find_opts[:conditions] = conditions unless conditions.empty? + attr_list = [] + attr_list << :id if params[:checkboxes] + attr_list += [:type_label, :task_obj, :action, :state, :user, :created_at, :args, :message] + json_hash(tasks_query_obj, attr_list, [:all], find_opts) + end + + +end diff --git a/src/app/models/task.rb b/src/app/models/task.rb index f231c18..4d16e01 100644 --- a/src/app/models/task.rb +++ b/src/app/models/task.rb @@ -45,6 +45,19 @@ class Task < ActiveRecord::Base COMPLETED_STATES = [STATE_FINISHED, STATE_FAILED, STATE_CANCELED] WORKING_STATES = [STATE_QUEUED, STATE_RUNNING, STATE_PAUSED] + TASK_TYPES_OPTIONS = [["VM Task", "VmTask"], + ["Host Task", "HostTask"], + ["Storage Task", "StorageTask"], + ["Storage Volume Task", "StorageVolumeTask", "break"], + ["Show All", ""]] + TASK_STATES_OPTIONS = [["Queued", Task::STATE_QUEUED], + ["Running", Task::STATE_RUNNING], + ["Paused", Task::STATE_PAUSED], + ["Finished", Task::STATE_FINISHED], + ["Failed", Task::STATE_FAILED], + ["Canceled", Task::STATE_CANCELED, "break"], + ["Show All", ""]] + def cancel self[:state] = STATE_CANCELED save! diff --git a/src/app/views/dashboard/index.html.erb b/src/app/views/dashboard/index.html.erb index 8815ebc..c361e55 100644 --- a/src/app/views/dashboard/index.html.erb +++ b/src/app/views/dashboard/index.html.erb @@ -1,31 +1,7 @@ - -
                        - -

                        Actions

                        - -
                        -
                        <%= link_to_if @can_set_perms, 'User Permissions', { :controller => 'permission', :action => 'new', :pool_id => @default_pool }, { :class => "edit" } %>
                        - - - - - -
                        <%= pluralize @default_pool.permissions.super_admins.size, "Super Admin" %>
                        <%= pluralize @default_pool.permissions.admins.size, "Administrator" %>
                        <%= pluralize @default_pool.permissions.users.size, "User" %>
                        <%= pluralize @default_pool.permissions.monitors.size, "Monitor" %>
                        -
                        - - <% if @can_modify %> -

                        Networks

                        - - View / Edit - - <% end %> - -
                        - - - - -<%- content_for :title do -%> -<%= _("Dashboard") %> -<%- end -%> - + <%= render :partial => "/task/show", :locals => { :task_types => @task_types, + :task_states => @task_states, + :task_type => @task_type, + :task_state => @task_state, + :tasks => @tasks, + :action => 'index', + :pool => nil } %> diff --git a/src/app/views/hardware/show_tasks.rhtml b/src/app/views/hardware/show_tasks.rhtml index e49086c..87ea13f 100644 --- a/src/app/views/hardware/show_tasks.rhtml +++ b/src/app/views/hardware/show_tasks.rhtml @@ -1,77 +1,7 @@ -
                        -
                          -
                        • - <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Type    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> -
                            - <% @task_types.each_index { |index| %> -
                          • - style="border-bottom: 1px solid #CCCCCC;" - <% end %> - > - - <%= @task_type == @task_types[index][1] ? "X" : "  " %> - <%=@task_types[index][0]%> -
                          • - <% } %> -
                          -
                        • -
                        • - <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  State    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> -
                            - <% @task_states.each_index { |index| %> -
                          • - style="border-bottom: 1px solid #CCCCCC;" - <% end %> - > - - <%= @task_state == @task_states[index][1] ? "X" : "  " %> - <%=@task_states[index][0]%> -
                          • - <% } %> -
                          -
                        • -
                        -
                        - - - -
                        -<% if @tasks[:rows].size != 0 %> -
                        - <%= render :partial => "/task/grid", :locals => { :table_id => "tasks_grid", - :task_type => @task_type, - :task_state => @task_state, - :pool => @pool, - :checkboxes => false, - :on_select => "tasks_grid_select" } %> -
                        - -<% else %> -
                        -
                        - <%= image_tag 'no-grid-items.png', :style => 'float: left;' %> - -
                        - No tasks found.

                        - <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>   -
                        -
                        -
                        -<% end %> + <%= render :partial => "/task/show", :locals => { :task_types => @task_types, + :task_states => @task_states, + :task_type => @task_type, + :task_state => @task_state, + :tasks => @tasks, + :action => 'show_tasks', + :pool => @pool } %> diff --git a/src/app/views/layouts/_navigation_tabs.rhtml b/src/app/views/layouts/_navigation_tabs.rhtml index dd50820..6619efc 100644 --- a/src/app/views/layouts/_navigation_tabs.rhtml +++ b/src/app/views/layouts/_navigation_tabs.rhtml @@ -3,7 +3,7 @@ $(document).ready(function(){ $tabs = $("#hardware_nav_tabs").tabs({ pool_type: "hardware", - selected: <%if params[:tab]%><%=params[:tab]%><%else%>1<%end%> + selected: <%if params[:tab]%><%=params[:tab]%><%else%>0<%end%> }); }); @@ -20,7 +20,7 @@ $(document).ready(function(){ $tabs = $("#resources_nav_tabs").tabs({ pool_type: "resource", - selected: <%if params[:tab]%><%=params[:tab]%><%else%>1<%end%> + selected: <%if params[:tab]%><%=params[:tab]%><%else%>0<%end%> }); }); @@ -35,7 +35,7 @@ $(document).ready(function(){ $tabs = $("#smart_pools_nav_tabs").tabs({ pool_type: "smart", - selected: <%if params[:tab]%><%=params[:tab]%><%else%>1<%end%> + selected: <%if params[:tab]%><%=params[:tab]%><%else%>0<%end%> }); }); @@ -48,7 +48,19 @@
                      <% elsif controller.controller_name == "search" %> -
                        + +<% elsif controller.controller_name == "dashboard" %> + +
                          + +
                        <% end %> \ No newline at end of file diff --git a/src/app/views/resources/show_tasks.rhtml b/src/app/views/resources/show_tasks.rhtml index 6c92779..87ea13f 100644 --- a/src/app/views/resources/show_tasks.rhtml +++ b/src/app/views/resources/show_tasks.rhtml @@ -1,61 +1,7 @@ -
                        -
                          -
                        • - <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  State    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> -
                            - <% @task_states.each_index { |index| %> -
                          • - style="border-bottom: 1px solid #CCCCCC;" - <% end %> - > - - <%= @task_state == @task_states[index][1] ? "X" : "  " %> - <%=@task_states[index][0]%> -
                          • - <% } %> -
                          -
                        • -
                        -
                        - - - -
                        -<% if @tasks[:rows].size != 0 %> -
                        - <%= render :partial => "/task/grid", :locals => { :table_id => "vm_tasks_grid", - :task_type => nil, - :task_state => @task_state, - :pool => @pool, - :checkboxes => false, - :on_select => "vm_tasks_grid_select" } %> -
                        - -<% else %> -
                        -
                        - <%= image_tag 'no-grid-items.png', :style => 'float: left;' %> - -
                        - No tasks found.

                        - <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>   -
                        -
                        -
                        -<% end %> + <%= render :partial => "/task/show", :locals => { :task_types => @task_types, + :task_states => @task_states, + :task_type => @task_type, + :task_state => @task_state, + :tasks => @tasks, + :action => 'show_tasks', + :pool => @pool } %> diff --git a/src/app/views/task/_grid.rhtml b/src/app/views/task/_grid.rhtml index cab99e5..3c17ac5 100644 --- a/src/app/views/task/_grid.rhtml +++ b/src/app/views/task/_grid.rhtml @@ -9,7 +9,7 @@ ( { url: '<%= url_for :action => "tasks", - :id => pool.id %>', + :id => pool %>', params: [{name: "task_type", value: '<%=task_type%>'}, {name: "task_state", value: '<%=task_state%>'} <%=", {name: 'checkboxes', value: #{checkboxes}}" if checkboxes%>], diff --git a/src/app/views/hardware/show_tasks.rhtml b/src/app/views/task/_show.rhtml similarity index 56% copy from src/app/views/hardware/show_tasks.rhtml copy to src/app/views/task/_show.rhtml index e49086c..340ce6c 100644 --- a/src/app/views/hardware/show_tasks.rhtml +++ b/src/app/views/task/_show.rhtml @@ -1,33 +1,36 @@
                        -
                          -
                        • - <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Type    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> -
                            - <% @task_types.each_index { |index| %> -
                          • - style="border-bottom: 1px solid #CCCCCC;" - <% end %> - > - - <%= @task_type == @task_types[index][1] ? "X" : "  " %> - <%=@task_types[index][0]%> -
                          • - <% } %> -
                          -
                        • +
                            + <%if task_types %> +
                          • + <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Type    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> +
                              + <% task_types.each_index { |index| %> +
                            • + style="border-bottom: 1px solid #CCCCCC;" + <% end %> + > + + <%= task_type == task_types[index][1] ? "X" : "  " %> + <%=task_types[index][0]%> +
                            • + <% } %> +
                            +
                          • + <% end %> +
                          • <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  State    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %>
                              - <% @task_states.each_index { |index| %> -
                            • + <% task_states.each_index { |index| %> +
                            • style="border-bottom: 1px solid #CCCCCC;" <% end %> > - <%= @task_state == @task_states[index][1] ? "X" : "  " %> - <%=@task_states[index][0]%> + <%= task_state == task_states[index][1] ? "X" : "  " %> + <%=task_states[index][0]%>
                            • <% } %>
                            @@ -40,7 +43,7 @@ function apply_task_filter(task_type, task_state) { $tabs.tabs("url", $tabs.data("selected.tabs"), - "<%= url_for :action => 'show_tasks', :id => @pool.id, + "<%= url_for :action => action, :id => pool, :nolayout => :true %>" + "&task_type=" + task_type + "&task_state=" + task_state); $tabs.tabs("load", $tabs.data("selected.tabs")); @@ -48,12 +51,12 @@
                            -<% if @tasks[:rows].size != 0 %> +<% if tasks[:rows].size != 0 %>
                            <%= render :partial => "/task/grid", :locals => { :table_id => "tasks_grid", - :task_type => @task_type, - :task_state => @task_state, - :pool => @pool, + :task_type => task_type, + :task_state => task_state, + :pool => pool, :checkboxes => false, :on_select => "tasks_grid_select" } %>
                            @@ -69,8 +72,7 @@ <%= image_tag 'no-grid-items.png', :style => 'float: left;' %>
                            - No tasks found.

                            - <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>   + No tasks found.
                -- 1.6.0.6 From clalance at redhat.com Mon Jan 12 15:44:51 2009 From: clalance at redhat.com (Chris Lalancette) Date: Mon, 12 Jan 2009 16:44:51 +0100 Subject: [Ovirt-devel] Re: are 'migration' between hosts working ? In-Reply-To: <639ce0480901120537k6adbe870leb85b77316a7de33@mail.gmail.com> References: <639ce0480901120422j455be592oeb72ce3f3e2a2ac0@mail.gmail.com> <639ce0480901120537k6adbe870leb85b77316a7de33@mail.gmail.com> Message-ID: <496B6573.3000300@redhat.com> pronix pronix wrote: > found litle bug > > diff --git a/src/task-omatic/task_vm.rb b/src/task-omatic/task_vm.rb > index c187287..cbeda20 100644 > --- a/src/task-omatic/task_vm.rb > +++ b/src/task-omatic/task_vm.rb > @@ -656,7 +656,7 @@ def migrate(vm, dest = nil) > src_conn = Libvirt::open("qemu+tcp://" + src_host.hostname + "/system") > dst_conn = Libvirt::open("qemu+tcp://" + dst_host.hostname + "/system") > > - connect_storage_pools(dst_conn, vm) > + connect_storage_pools(dst_conn, vm.storage_volumes) > > dom = src_conn.lookup_domain_by_uuid(vm.uuid) > dom.migrate(dst_conn, Libvirt::Domain::MIGRATE_LIVE) Arg! You are completely right; I don't know how that ever worked, although at some point it definitely did. With this fix in place, does it actually work for you? -- Chris Lalancette From jeremy.perry at redhat.com Mon Jan 12 15:47:58 2009 From: jeremy.perry at redhat.com (Jeremy Perry) Date: Mon, 12 Jan 2009 10:47:58 -0500 Subject: [Ovirt-devel] Re: oVirt server wui console integration In-Reply-To: <4967C7D3.9080004@redhat.com> References: <49668014.6060706@redhat.com> <820A3B59-B2C2-4A9D-A48A-A4CB1F6F7B5E@redhat.com> <1231470254.4174.19.camel@physical.priv.ovirt.org> <41FA0D09-2A71-4A17-B9D2-0078B2D40A8D@redhat.com> <49678641.4040504@redhat.com> <4967C7D3.9080004@redhat.com> Message-ID: <515EA981-1344-4DD4-929C-0A386C965C0C@redhat.com> On Jan 9, 2009, at 4:55 PM, Michael DeHaan wrote: > Mohammed Morsi wrote: >> Jeremy Perry wrote: >> >>> I've posted the mockups and descriptions mentioned here to the the >>> ovirt.org wiki: >>> http://ovirt.org/page/Terminal_UX >>> >>> one more comment below... >>> >>> On Jan 8, 2009, at 10:04 PM, Jason Guiditta wrote: >>> >>> >>>> On Thu, 2009-01-08 at 18:23 -0500, Jeremy Perry wrote: >>>> >>>>> On Jan 8, 2009, at 5:37 PM, Mohammed Morsi wrote: >>>>> >>>>> >>>>>> Currently the idea for the console interface in the wui is that >>>>>> a user >>>>>> can navigate the the 'virtual machines' tab under a vm pool, >>>>>> click >>>>>> on a >>>>>> specific vm, click on 'console' in the details pane and will be >>>>>> presented with a console to that vm. There were a few ideas as to >>>>>> where >>>>>> the console should appear, >>>>>> >>>>>> * in a minimally themed popup window, most likely the first >>>>>> implementation as it is simplest, but may result in many popups >>>>>> when >>>>>> connected to several vms >>>>>> * in the dialog / popup box interface we have now, we will want >>>>>> to >>>>>> introduce a tabbing mechanism for access to multiple vm consoles >>>>>> * in another tab in the main content area, same vm-tab concept >>>>>> needed here >>>>>> * a rollover, eg the user rolls over 'console' in the vm >>>>>> details pane >>>>>> and the console appears so long as the user holds his mouse >>>>>> over it / >>>>>> the link >>>>>> >>>>>> >>>>> I've taken the liberty of mocking some of these ideas up. >>>>> >>>>> I didnt mockup the new themed popup window yet, since its simple >>>>> to >>>>> imagine. I think its a decent approach, but wondering if we can >>>>> eliminate the multiple popups issue by targeting our popup once >>>>> there >>>>> is at least one open. Subsequent terminals would nest via tabs >>>>> in the >>>>> one terminal window, so all you deal with is one window with >>>>> tabs for >>>>> each vm terminal. >>>>> >>>> I like the idea of the popup window, then adding tabs to it as >>>> needed, >>>> and like the pop-out (thanks google!). My first choice is the >>>> design >>>> with the initial console on the right of the details in the same >>>> pane. >>>> The other with them stacked felt too squished. The tabbed one >>>> could >>>> work too, but I kind of think the terminal being in the detail >>>> pane is >>>> not super usable, since you can't see that much in the space >>>> allowed. I >>>> agree on the modal dialog thing, no need to force them to have >>>> only that >>>> accessible, but another idea could be a non-modal dialog that you >>>> could >>>> minimize somewhere w/in the application. If done right, I think >>>> this >>>> could be pretty slick, but perhaps not worth the effort, as the >>>> single >>>> popup window seems like a perfectly good way to go. >>>> >>> I agree on the popup window, and will take a stab at it. As for the >>> non-modal idea, this would be pretty cool to look at. Well executed >>> examples in the wild is Google chat in gmail and the alerts/etc >>> bar in >>> facebook. >>> >> >> I also agree that the terminal in the details pane seems a bit >> squished. >> I'm not sure if we'd be able to do this immediately, but I'd think >> we'd >> also want to support terminal resizing at some point in the future >> (size saved in the user preferences system when we have it). I also >> like >> the idea of the non-modal dialog, perhaps we can 'minimize' it to the >> dashboard so that a user can maintain active terminal sessions >> between >> uses of the ovirt wui. >> >> >> >>>>>> Its currently looking like the console frontend and apache- >>>>>> proxied >>>>>> backend daemon will be driven by anyterm http://anyterm.org/ . >>>>>> We will >>>>>> use anyterm to launch ovirt-viewer or the virsh console to >>>>>> connect to >>>>>> the vm and then present the anyterm html / js / css ui to the >>>>>> user. A >>>>>> rough layout of the setup can be found here >>>>>> http://ovirt.org/page/Image:Anyterm.png >>>>>> >>>>> I based my mockups on their demos - let me know if the actions I >>>>> included (like copy, paste) make sense or not. >>>>> >> >> Ya thats totally fine for the mockups, I might remove some of that >> stuff >> from the anyterm html that gets added to the project (its all gpl) >> depending of how it works and what we need. >> >> In any case 'Close' will definetly be staying, 'copy' and 'paste' >> might >> be removed depending on if we can get that functionality without it, >> 'Control Keys' will most likey be removed as they work without >> needing >> the drop down. I do like the 'pop out' action you added, and I'll >> look >> into seeing how the terminal location can be parametrized so that we >> could put it in multiple locations. >> >> >> >>>>>> Looking for thoughts / feedback / suggestions as to the interface >>>>>> placement of the console or the backend. Thanks alot, >>>>>> >>>>>> -Mo >>>>>> >>>>> Finally, I wanted to propose we settle on the term "Terminal" >>>>> instead >>>>> of "Console" - at least in the UI - since that is what is used in >>>>> Fedora. I know terminology consistency is a challenge for us, is >>>>> this >>>>> a place we can make a choice in the UI and be consistent? >>>>> >>>>> >>>> Seems reasonable to me, matches more closely with the 'anyterm' >>>> name >>>> too. >>>> >>>>> Thanks! >>>>> - Jeremy >>>>> >> >> Sounds good to me too. >> >> -Mo >> >> _______________________________________________ >> Ovirt-devel mailing list >> Ovirt-devel at redhat.com >> https://www.redhat.com/mailman/listinfo/ovirt-devel >> > > How about a link to just the terminal (no-popup) so someone can just > do "New Tab" in Firefox and get a nice large terminal? > > Tabs across the top may also not scale if a user has a bit too many > VMs open (perhaps a drop down to select the VM, or multiple firefox > tabs?) > > --Michael > That's reasonable, though I don't feel strongly about it. It seems one way or another it is nice to give the user the ability to have a dedicated tab or window per terminal if they want. I'm not sure you can have that AND smaller popups from the same link, which would be ideal. Looking at gmail's pop out for a mail message, you cant seem do a new regular window/tab, which is too bad. I also dont know how they get around popup blockers (but they do), which would be another concern for us - we do not want to require you to disable them. I guess the ultimate would be a new window link that behaves like this: - you click it and you get a new popup window. Additional terminals nest here - you can right click and choose new full browser window/tab. If we just have a normal link, the only issue is unintentional navigation away from the main UI. So I think this is a case where it makes sense to target a new window by default (used with caution - we should make it clear on the link label). This is even better if we can resize the terminal - right now it looks like you have to hard code the # of columns and rows for Anyterm. From jguiditt at redhat.com Mon Jan 12 19:15:22 2009 From: jguiditt at redhat.com (Jason Guiditta) Date: Mon, 12 Jan 2009 14:15:22 -0500 Subject: [Ovirt-devel] [PATCH] Add task list to dashboard (revised) In-Reply-To: <1231773549-13671-1-git-send-email-sseago@redhat.com> References: <1231773549-13671-1-git-send-email-sseago@redhat.com> Message-ID: <1231787722.4148.2.camel@physical.priv.ovirt.org> On Mon, 2009-01-12 at 15:19 +0000, Scott Seago wrote: > Refactored task list functionality to allow for the dashboard-level task list. > The dashboard task list shows all tasks initiated by the logged-in user, and is > filterable by task type and state. > > revised to fix a couple bugs found by lutter > Almost ACK. I have attached a few fixes. They correct both the 'double render', and fix the dashboard link so it doesn't reload the whole page (making you lose state on your nav tree). Also added a little cleanup bit making the correct thing show as current (blue background). -j -------------- next part -------------- A non-text attachment was scrubbed... Name: sseago-tasklist-update.patch Type: text/x-patch Size: 6571 bytes Desc: not available URL: From lutter at redhat.com Mon Jan 12 19:40:53 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 12 Jan 2009 11:40:53 -0800 Subject: [Ovirt-devel] [PATCH] Add task list to dashboard In-Reply-To: <49680125.3090907@redhat.com> References: <1231440209-26690-1-git-send-email-sseago@redhat.com> <1231545768.434.31.camel@localhost.localdomain> <49680125.3090907@redhat.com> Message-ID: <1231789253.7479.12.camel@localhost.localdomain> On Fri, 2009-01-09 at 21:00 -0500, Scott Seago wrote: > Note that I won't hold up pushing this patch on the above 5 points, as > they have more to do with the overall UI design of the existing task > list rather than the dashboard refactoring, and in some cases we have UI > design issues to work through before resolving them anyway. Agreed, except for the one outright bug I mentioned, it's fine to push as is for now. We can address the other points in subsequent commits. > > > > Not directly a comment about this patch: it would be cleaner if we had a > > TaskController with an index action that accepts parameters to restrict > > the list of tasks to a certain object, e.g. a hw pool or a vm pool. > > > > The implementation with TaskActions and the index -> show_tasks -> show > > call sequence seems a little roundabout. > > > > > I tried to pull all of the generic stuff (that applies to more than one > of the 3 controllers that have task lists) into the task_actions module > which is included by the controllers that have task lists. I suppose we > could have a separate controller with 3 different actions relating to > dashboard, vm, and hw pool, but it doesn't really match the model we're > already using for VM pool and HW pool controllers -- where one > controller handles the various UI tabs for an object type. So the bits > common to all task lists are already pulled out into task_actions -- and > on the view side in task/_show and task/_grid. What I specifically object to is the TaskActions module. Simply for data retrieval, the way to think about this is that there is a collection of tasks that gets filtered by various criteria - some of them user-supplied, and some of them context-dependant. I would simply have a TaskController with only an index action; to display tasks for a VM pool, pass in a vm_pool_id request param, for a hardware pool a hw_pool_id etc. Regardless of how this is done for the WUI, for the API, we'll need a TaskController to pull down lists of tasks. > Some of the roundabout > nature here has to do with the way the flexigrid setup works -- we need > one action to generate the page itself -- with navigation, filters, > etc., and another action to return the json array for the table content. To be clear: I was only talking about how the json array is generated. > OK so of the above issues, the ones that I will rework into an updated > patch are as follows: > 1) dashboard tab name changed to 'Tasks' (left nav is still 'dashboard') > 2) fix the 'no tasks' view to remove the 'add' icon > 3) Fix whatever's wrong with the VM pool template/controller in the > current patch. Sounds good. David From sseago at redhat.com Mon Jan 12 20:21:16 2009 From: sseago at redhat.com (Scott Seago) Date: Mon, 12 Jan 2009 15:21:16 -0500 Subject: [Ovirt-devel] [PATCH] Add task list to dashboard In-Reply-To: <1231789253.7479.12.camel@localhost.localdomain> References: <1231440209-26690-1-git-send-email-sseago@redhat.com> <1231545768.434.31.camel@localhost.localdomain> <49680125.3090907@redhat.com> <1231789253.7479.12.camel@localhost.localdomain> Message-ID: <496BA63C.4050305@redhat.com> David Lutterkort wrote: > > >>> Not directly a comment about this patch: it would be cleaner if we had a >>> TaskController with an index action that accepts parameters to restrict >>> the list of tasks to a certain object, e.g. a hw pool or a vm pool. >>> >>> The implementation with TaskActions and the index -> show_tasks -> show >>> call sequence seems a little roundabout. >>> >>> >>> >> I tried to pull all of the generic stuff (that applies to more than one >> of the 3 controllers that have task lists) into the task_actions module >> which is included by the controllers that have task lists. I suppose we >> could have a separate controller with 3 different actions relating to >> dashboard, vm, and hw pool, but it doesn't really match the model we're >> already using for VM pool and HW pool controllers -- where one >> controller handles the various UI tabs for an object type. So the bits >> common to all task lists are already pulled out into task_actions -- and >> on the view side in task/_show and task/_grid. >> > > What I specifically object to is the TaskActions module. Simply for data > retrieval, the way to think about this is that there is a collection of > tasks that gets filtered by various criteria - some of them > user-supplied, and some of them context-dependant. > > I would simply have a TaskController with only an index action; to > display tasks for a VM pool, pass in a vm_pool_id request param, for a > hardware pool a hw_pool_id etc. > > And a username for the dashboard task list -- i.e. for the dashboard we want all tasks initiated by a given user. > Regardless of how this is done for the WUI, for the API, we'll need a > TaskController to pull down lists of tasks. > > My concern is that this will be a little more convoluted to put all of this stuff in a single TaskController, since the behavior is slightly different in the three contexts. For the VM pool case, for example, we don't have a list of types to filter on (since they're only VM tasks). For the dashboard one, the query itself is different, since instead of calling (vm,hw)pool.tasks we have to call Task.find(...) with the username set in the conditions clause. Also for the WUI we're handling the permissions, etc. at the pool controller. On the other hand having an index api method on the Task controller makes perfect sense for the API case -- maybe the way to accomodate both uses would be to simply also include TaskActions in the task controller and make TaskController.index call the right methods to return exactly what you need. >> Some of the roundabout >> nature here has to do with the way the flexigrid setup works -- we need >> one action to generate the page itself -- with navigation, filters, >> etc., and another action to return the json array for the table content. >> > > To be clear: I was only talking about how the json array is generated. > > And it may be that we can find a way to put the json array stuff all into the TaskController but leave the rest of it where it is... Scott From jguiditt at redhat.com Mon Jan 12 20:29:33 2009 From: jguiditt at redhat.com (Jason Guiditta) Date: Mon, 12 Jan 2009 15:29:33 -0500 Subject: [Ovirt-devel] [PATCH server] Add task list to dashboard (revised) In-Reply-To: <1231787722.4148.2.camel@physical.priv.ovirt.org> References: <1231787722.4148.2.camel@physical.priv.ovirt.org> Message-ID: <1231792173-8924-1-git-send-email-jguiditt@redhat.com> From: Scott Seago Incorporated some js changes from jay. Refactored task list functionality to allow for the dashboard-level task list. The dashboard task list shows all tasks initiated by the logged-in user, and is filterable by task type and state. revised to fix a couple bugs found by lutter Signed-off-by: Scott Seago Signed-off-by: Jason Guiditta --- src/app/controllers/dashboard_controller.rb | 41 +++++++++---- src/app/controllers/hardware_controller.rb | 12 +---- src/app/controllers/pool_controller.rb | 41 +++---------- src/app/controllers/task_actions.rb | 50 +++++++++++++++ src/app/models/task.rb | 13 ++++ src/app/views/dashboard/index.html.erb | 38 ++---------- src/app/views/hardware/show_tasks.rhtml | 84 ++----------------------- src/app/views/layouts/_navigation_tabs.rhtml | 17 ++++- src/app/views/layouts/_tree.rhtml | 26 ++++++-- src/app/views/resources/show_tasks.rhtml | 68 ++------------------- src/app/views/task/_grid.rhtml | 2 +- src/app/views/task/_show.rhtml | 81 +++++++++++++++++++++++++ src/public/javascripts/ovirt.js | 5 ++ src/public/stylesheets/ovirt-tree/tree.css | 2 +- 14 files changed, 242 insertions(+), 238 deletions(-) create mode 100644 src/app/controllers/task_actions.rb create mode 100644 src/app/views/task/_show.rhtml diff --git a/src/app/controllers/dashboard_controller.rb b/src/app/controllers/dashboard_controller.rb index c4830df..00398a5 100644 --- a/src/app/controllers/dashboard_controller.rb +++ b/src/app/controllers/dashboard_controller.rb @@ -18,19 +18,36 @@ # also available at http://www.gnu.org/copyleft/gpl.html. class DashboardController < ApplicationController + + include TaskActions + def tasks_query_obj + Task + end + def tasks_conditions + {:user => get_login_user} + end + def index - @default_pool = HardwarePool.get_default_pool - set_perms(@default_pool) - #remove these soon - @hardware_pools = HardwarePool.find(:all) - @available_hosts = Host.find(:all) - @available_storage_volumes = StorageVolume.find(:all) - @storage_pools = StoragePool.find(:all) - @hosts = Host.find(:all) - @storage_volumes = StorageVolume.find(:all) - @vms = Vm.find(:all) - if params[:ajax] - render :layout => 'tabs-and-content' #:template => 'hardware/show.html.erb' + @task_types = Task::TASK_TYPES_OPTIONS + show_tasks + end + + def show + respond_to do |format| + format.html { + render :layout => 'tabs-and-content' if params[:ajax] + render :layout => 'help-and-content' if params[:nolayout] + } + format.xml { + render :xml => @pool.to_xml(XML_OPTS) + } end end + + def tasks_internal + @task_type = params[:task_type] + @task_type ||="" + super + end + end diff --git a/src/app/controllers/hardware_controller.rb b/src/app/controllers/hardware_controller.rb index 4dda736..7be67cc 100644 --- a/src/app/controllers/hardware_controller.rb +++ b/src/app/controllers/hardware_controller.rb @@ -116,17 +116,7 @@ class HardwareController < PoolController end def show_tasks - @task_types = [["VM Task", "VmTask"], - ["Host Task", "HostTask"], - ["Storage Task", "StorageTask"], - ["Storage Volume Task", "StorageVolumeTask", "break"], - ["Show All", ""]] - super - end - - def tasks_internal - @task_type = params[:task_type] - @task_type ||="" + @task_types = Task::TASK_TYPES_OPTIONS super end diff --git a/src/app/controllers/pool_controller.rb b/src/app/controllers/pool_controller.rb index 03d1316..b8d0f10 100644 --- a/src/app/controllers/pool_controller.rb +++ b/src/app/controllers/pool_controller.rb @@ -31,6 +31,14 @@ class PoolController < ApplicationController :include => [ :storage_pools, :hosts, :quota ] } + include TaskActions + def tasks_query_obj + @pool.tasks + end + def tasks_conditions + {} + end + def show respond_to do |format| format.html { @@ -58,39 +66,6 @@ class PoolController < ApplicationController [:grid_id, :uid, :user_role, :source]) end - def show_tasks - @task_states = [["Queued", Task::STATE_QUEUED], - ["Running", Task::STATE_RUNNING], - ["Paused", Task::STATE_PAUSED], - ["Finished", Task::STATE_FINISHED], - ["Failed", Task::STATE_FAILED], - ["Canceled", Task::STATE_CANCELED, "break"], - ["Show All", ""]] - params[:page]=1 - params[:sortname]="tasks.created_at" - params[:sortorder]="desc" - @tasks = tasks_internal - show - end - - def tasks - render :json => tasks_internal.to_json - end - - def tasks_internal - @task_state = params[:task_state] - @task_state ||=Task::STATE_QUEUED - conditions = {} - conditions[:type] = @task_type unless @task_type.empty? - conditions[:state] = @task_state unless @task_state.empty? - find_opts = {:include => [:storage_pool, :host, :vm]} - find_opts[:conditions] = conditions unless conditions.empty? - attr_list = [] - attr_list << :id if params[:checkboxes] - attr_list += [:type_label, :task_obj, :action, :state, :user, :created_at, :args, :message] - json_hash(@pool.tasks, attr_list, [:all], find_opts) - end - def hosts_json(args) attr_list = [] attr_list << :id if params[:checkboxes] diff --git a/src/app/controllers/task_actions.rb b/src/app/controllers/task_actions.rb new file mode 100644 index 0000000..d71c11e --- /dev/null +++ b/src/app/controllers/task_actions.rb @@ -0,0 +1,50 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Scott Seago +# +# 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. +module TaskActions + def show_tasks + @task_states = Task::TASK_STATES_OPTIONS + params[:page]=1 + params[:sortname]="tasks.created_at" + params[:sortorder]="desc" + @tasks = tasks_internal + show + end + + def tasks + render :json => tasks_internal.to_json + end + + def tasks_internal + @task_state = params[:task_state] + @task_state ||=Task::STATE_QUEUED + @task_type = params[:task_type] + @task_type ||="" + conditions = tasks_conditions + conditions[:type] = @task_type unless @task_type.empty? + conditions[:state] = @task_state unless @task_state.empty? + find_opts = {:include => [:storage_pool, :host, :vm]} + find_opts[:conditions] = conditions unless conditions.empty? + attr_list = [] + attr_list << :id if params[:checkboxes] + attr_list += [:type_label, :task_obj, :action, :state, :user, :created_at, :args, :message] + json_hash(tasks_query_obj, attr_list, [:all], find_opts) + end + + +end diff --git a/src/app/models/task.rb b/src/app/models/task.rb index f231c18..4d16e01 100644 --- a/src/app/models/task.rb +++ b/src/app/models/task.rb @@ -45,6 +45,19 @@ class Task < ActiveRecord::Base COMPLETED_STATES = [STATE_FINISHED, STATE_FAILED, STATE_CANCELED] WORKING_STATES = [STATE_QUEUED, STATE_RUNNING, STATE_PAUSED] + TASK_TYPES_OPTIONS = [["VM Task", "VmTask"], + ["Host Task", "HostTask"], + ["Storage Task", "StorageTask"], + ["Storage Volume Task", "StorageVolumeTask", "break"], + ["Show All", ""]] + TASK_STATES_OPTIONS = [["Queued", Task::STATE_QUEUED], + ["Running", Task::STATE_RUNNING], + ["Paused", Task::STATE_PAUSED], + ["Finished", Task::STATE_FINISHED], + ["Failed", Task::STATE_FAILED], + ["Canceled", Task::STATE_CANCELED, "break"], + ["Show All", ""]] + def cancel self[:state] = STATE_CANCELED save! diff --git a/src/app/views/dashboard/index.html.erb b/src/app/views/dashboard/index.html.erb index 8815ebc..c361e55 100644 --- a/src/app/views/dashboard/index.html.erb +++ b/src/app/views/dashboard/index.html.erb @@ -1,31 +1,7 @@ - -
                - -

                Actions

                - -
                -
                <%= link_to_if @can_set_perms, 'User Permissions', { :controller => 'permission', :action => 'new', :pool_id => @default_pool }, { :class => "edit" } %>
                - - - - - -
                <%= pluralize @default_pool.permissions.super_admins.size, "Super Admin" %>
                <%= pluralize @default_pool.permissions.admins.size, "Administrator" %>
                <%= pluralize @default_pool.permissions.users.size, "User" %>
                <%= pluralize @default_pool.permissions.monitors.size, "Monitor" %>
                -
                - - <% if @can_modify %> -

                Networks

                - - View / Edit - - <% end %> - -
                - - - - -<%- content_for :title do -%> -<%= _("Dashboard") %> -<%- end -%> - + <%= render :partial => "/task/show", :locals => { :task_types => @task_types, + :task_states => @task_states, + :task_type => @task_type, + :task_state => @task_state, + :tasks => @tasks, + :action => 'index', + :pool => nil } %> diff --git a/src/app/views/hardware/show_tasks.rhtml b/src/app/views/hardware/show_tasks.rhtml index e49086c..87ea13f 100644 --- a/src/app/views/hardware/show_tasks.rhtml +++ b/src/app/views/hardware/show_tasks.rhtml @@ -1,77 +1,7 @@ -
                -
                  -
                • - <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Type    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> -
                    - <% @task_types.each_index { |index| %> -
                  • - style="border-bottom: 1px solid #CCCCCC;" - <% end %> - > - - <%= @task_type == @task_types[index][1] ? "X" : "  " %> - <%=@task_types[index][0]%> -
                  • - <% } %> -
                  -
                • -
                • - <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  State    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> -
                    - <% @task_states.each_index { |index| %> -
                  • - style="border-bottom: 1px solid #CCCCCC;" - <% end %> - > - - <%= @task_state == @task_states[index][1] ? "X" : "  " %> - <%=@task_states[index][0]%> -
                  • - <% } %> -
                  -
                • -
                -
                - - - -
                -<% if @tasks[:rows].size != 0 %> -
                - <%= render :partial => "/task/grid", :locals => { :table_id => "tasks_grid", - :task_type => @task_type, - :task_state => @task_state, - :pool => @pool, - :checkboxes => false, - :on_select => "tasks_grid_select" } %> -
                - -<% else %> -
                -
                - <%= image_tag 'no-grid-items.png', :style => 'float: left;' %> - -
                - No tasks found.

                - <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>   -
                -
                -
                -<% end %> + <%= render :partial => "/task/show", :locals => { :task_types => @task_types, + :task_states => @task_states, + :task_type => @task_type, + :task_state => @task_state, + :tasks => @tasks, + :action => 'show_tasks', + :pool => @pool } %> diff --git a/src/app/views/layouts/_navigation_tabs.rhtml b/src/app/views/layouts/_navigation_tabs.rhtml index dd50820..8d9e36a 100644 --- a/src/app/views/layouts/_navigation_tabs.rhtml +++ b/src/app/views/layouts/_navigation_tabs.rhtml @@ -3,7 +3,7 @@ $(document).ready(function(){ $tabs = $("#hardware_nav_tabs").tabs({ pool_type: "hardware", - selected: <%if params[:tab]%><%=params[:tab]%><%else%>1<%end%> + selected: <%if params[:tab]%><%=params[:tab]%><%else%>0<%end%> }); }); @@ -20,7 +20,7 @@ $(document).ready(function(){ $tabs = $("#resources_nav_tabs").tabs({ pool_type: "resource", - selected: <%if params[:tab]%><%=params[:tab]%><%else%>1<%end%> + selected: <%if params[:tab]%><%=params[:tab]%><%else%>0<%end%> }); }); @@ -35,7 +35,7 @@ $(document).ready(function(){ $tabs = $("#smart_pools_nav_tabs").tabs({ pool_type: "smart", - selected: <%if params[:tab]%><%=params[:tab]%><%else%>1<%end%> + selected: <%if params[:tab]%><%=params[:tab]%><%else%>0<%end%> }); }); @@ -48,7 +48,16 @@
              <% elsif controller.controller_name == "search" %> -
                + +<% elsif controller.controller_name == "dashboard" %> + +
                  + +
                <% end %> \ No newline at end of file diff --git a/src/app/views/layouts/_tree.rhtml b/src/app/views/layouts/_tree.rhtml index fefd642..57a0203 100644 --- a/src/app/views/layouts/_tree.rhtml +++ b/src/app/views/layouts/_tree.rhtml @@ -14,6 +14,20 @@ tree_url = "<%= url_for :controller =>"/tree", :action => "return_filtered_list" %>"; processTree(); treeTimer = setInterval(processTree,15000); + $('div.nav-dashboard a').bind('click', function(e){ + if(this === e.target){ + var myURL = $(this).attr('href'); + $('.current').removeClass('current'); + $(this).parent().addClass('current'); + $.ajax({ + url: this.href, + dataType: 'html', + success: handleTabsAndContent, + error: function(xhr) {$.jGrowl(xhr.status + ' ' + xhr.statusText);} + }); + e.preventDefault(); + } + }) $('#nav_tree_form ul.ovirt-tree li').livequery( function(){ $(this) @@ -21,6 +35,7 @@ .bind('click',function(){ $('#nav_tree_form ul.ovirt-tree li div').removeClass('current'); var thisHref = (urlObj[$(this).attr('class')] !=null) ? urlObj[$(this).attr('class')] + '/' + this.id :null; + $('div.nav-dashboard').removeClass('current'); $(this).toggleClass('current'); currentNode = this.id; if ($tabs != null) { @@ -33,10 +48,7 @@ type: 'GET', data: {ajax:true,tab:selected_tab}, dataType: 'html', - success: function(data) { - $('#side-toolbar').html($(data).find('div.toolbar')); - $('#tabs-and-content-container').html($(data).not('div#side-toolbar')); - }, + success: handleTabsAndContent, error: function(xhr) {$.jGrowl(xhr.status + ' ' + xhr.statusText);} }); } @@ -71,9 +83,9 @@ - diff --git a/src/public/javascripts/ovirt.js b/src/public/javascripts/ovirt.js index a43f004..09d8bdc 100644 --- a/src/public/javascripts/ovirt.js +++ b/src/public/javascripts/ovirt.js @@ -173,7 +173,7 @@ function afterHwPool(response, status){ $tabs.tabs("load",$tabs.data('selected.tabs')); } } - + //FIXME: point all these refs at a widget so we dont need the functions in here processTree(); @@ -322,4 +322,61 @@ function afterNetwork(response, status){ function handleTabsAndContent(data) { $('#side-toolbar').html($(data).find('div.toolbar')); $('#tabs-and-content-container').html($(data).not('div#side-toolbar')); +} + +var VmCreator = { + checkedBoxesFromTree : [], + buildCheckboxList: function(id) { + var rawList = $('#'+ id + ' :checkbox:checked').parent('div'); + if (rawList.length >0) { + rawList.each(function(i) { + VmCreator.checkedBoxesFromTree.push(rawList.get(i).id); + }); + } else { + VmCreator.checkedBoxesFromTree.splice(0); + } + }, + clickCheckboxes: function() { + $.each(VmCreator.checkedBoxesFromTree, function(n, curBox){ + $('#' + curBox).children(':checkbox').click(); + }); + VmCreator.checkedBoxesFromTree = []; + }, + recreateTree: function(o){ + $('#storage_volumes_tree').tree({ + content: o.content, + template: "storage_volumes_template", + selectedNodes: o.selectedNodes, + clickHandler: VmCreator.goToCreateStorageHandler, + channel: 'STORAGE_VOLUME', + refresh: VmCreator.returnToVmForm + }); + }, + goToCreateStorageHandler: function goToCreateStorageHandler(e,elem){ + if ($(e.target).is('img') && $(e.target).parent().is('div')){ + //remove the temp form in case there is one hanging around for some reason + $('temp_create_vm_form').remove(); + VmCreator.buildCheckboxList(elem.element.get(0).id); + var storedOptions = $('#storage_volumes_tree').data('tree').options; + // copy/rename form + $('#window').clone(true).attr({style: 'display:none', id: 'temp_window'}).appendTo('body'); + $('#temp_window #vm_form').attr({id: 'temp_create_vm_form'}); + // continue standard calls to go to next step (create storage) + $(e.target).siblings('a').click(); + // empty tree + $('#temp_create_vm_form #storage_volumes_tree').empty(); + // reinitialize tree so it has data and is subscribed + VmCreator.recreateTree(storedOptions); + } + }, + returnToVmForm: function returnToVmForm(e,elem) { + //The item has now been added to the tree, now copy it into a facebox + var storedOptions = $('#storage_volumes_tree').data('tree').options; + $('#window').remove(); + $('#temp_window').clone(true).attr({style: 'display:block', id: 'window'}) + .appendTo('td.body > div.content').end().remove(); + $('#window #temp_create_vm_form').attr({id: 'vm_form'}); + VmCreator.recreateTree(storedOptions); + VmCreator.clickCheckboxes(); + } } \ No newline at end of file diff --git a/src/public/javascripts/ovirt.tree.js b/src/public/javascripts/ovirt.tree.js index 77d6c55..48f529c 100644 --- a/src/public/javascripts/ovirt.tree.js +++ b/src/public/javascripts/ovirt.tree.js @@ -75,60 +75,149 @@ function processChildren(list, templateObj){ this.setData('template', TrimPath.parseDOMTemplate(this.getData('template'))); }, init: function() { + var self = this, o = this.options; this.setTemplate(this.getTemplate()); - this.element.html(this.getTemplate().process(this.getData('content'))); - var self = this; + this.populate(); this.element - .find('li:has(ul)') - .children('span.hitarea') - .click(function(event){ - if (this == event.target) { - if($(this).siblings('ul').size() >0) { - if(self.getData('toggle') === 'toggle') { - self.toggle(event, this); //we need 'this' so we have the right element to toggle - } else { - self.element.triggerHandler('toggle',[event,this],self.getData('toggle')); - } - } - } + .bind('click', function(event){ + self.clickHandler(event, self); + if(self.getData('toggle') === 'toggle') { + self.toggle(event, this); + } else { + self.element.triggerHandler('toggle',[event,this],self.getData('toggle')); + } }); - this.element - .find('li > div') - .filter(':not(.unclickable)') - .bind('click', function(event) { - if (this == event.target) { - if(self.getData('clickHandler') === 'clickHandler') { - self.clickHandler(event, this); //we need 'this' so we have the right element to add click behavior to - } else { - self.element.triggerHandler('clickHandler',[event,this],self.getData('clickHandler')); - } - } + o.selectedNodes !== undefined? this.openToSelected() :o.selectedNodes=[]; + o.channel !== undefined? this.subscribe(o.channel): o.channel = ''; + if (o.cacheContent === true) this.buildLookup(); + }, + populate: function() { + var contentWithId = this.getData('content'); + contentWithId.id = this.element.get(0).id; + this.element.html(this.getTemplate().process(contentWithId)); + }, + buildLookup: function() { + this.setData('lookupList', this.walkTree(this.getData('content').pools, [], this)); + }, + walkTree: function(list, lookup, self) { + $.each(list, function(n,obj){ + lookup.push(obj); + if (obj.children.length > 0) self.walkTree(obj.children, lookup, self); }); - this.openToSelected(self); + return lookup; + }, + subscribe: function subscribe(channel) { + var self = this; + this.element.bind(channel, function(e,data){self.refresh(e,data);}); }, toggle: function(e, elem) { - $(elem) + if ($(e.target).is('span.hitarea')){ + $(e.target) .toggleClass('expanded') .toggleClass('expandable') .siblings('ul').slideToggle("normal"); + if ($(e.target).hasClass('expanded')) { + this.setSelectedNode(this.chop(e.target), true); + } else { + this.setSelectedNode(this.chop(e.target), false); + } + } + }, + chop: function(elem) { + var id = $(elem).siblings('div').get(0).id; + return id.substring(id.indexOf('-') +1); + }, + clickHandler: function(e,elem) { //TODO: make this a default impl if needed. + this.options.clickHandler !== undefined? this.element.triggerHandler('clickHandler',[e,this],this.getData('clickHandler')): null; + if ($(e.target).is('div') && $(e.target).parent().is('li')){} + }, + setSelectedNode: function(id, isOpen) { + if (isOpen) { + if($.inArray(id,this.getData('selectedNodes')) == -1){ + this.setData(this.getData('selectedNodes').push(id)); + } + } else { + if($.inArray(id,this.getData('selectedNodes')) != -1){ + this.setData(this.getData('selectedNodes').splice(this.getData('selectedNodes').indexOf(id),1)); + } + } + }, + openToSelected: function() { + for (var i = 0; i < this.getData('selectedNodes').length; i++){ + this.toggle($.event.fix({type: 'toggle', + target: this.element.find('#' +this.element.get(0).id + '-' + this.getData('selectedNodes')[i]).siblings('span').get(0)}) + , this); + } + }, + refresh: function(e, list) { + //NOTE: The widget expects the convention used elsewhere of {blah}-{ui_object} + //(where {blah} is the id of the container element, see above for an example soon), + //since there may be 2 items with the same db id. + var self = this; + list = $.makeArray(list); + $.each(list, function(n,data){ + switch(data.state) { + case 'deleted': { + self._delete(data); + break; + } + case 'changed': { + self._update(data); + break; + } + default: { + self._add(data); + break; + } + } + }); + self.options.refresh !== undefined? self.element.triggerHandler('refresh',[e,list],self.getData('refresh')): null; }, - clickHandler: function(e,elem) { - // make this a default impl if needed. + //methods meant to be called internally by widget + _add: function(data){ + var myLookupList = this.getData('lookupList'); + if (data.ui_parent !==null) { + var matchedItems = $.grep(myLookupList,function(value) {return value.ui_object == data.ui_parent;}); + var self = this; + $.each(matchedItems, function(n,obj){ + var existingObj = []; + if(obj.children.length >0) { + existingObj = $.grep(obj.children,function(value) {return value.ui_object == data.ui_object;}); + } + if (existingObj.length === 0){ + obj.children.push(data); + myLookupList.push(data); + self._addDomElem(data); + } else {} + }); + } else {myLookupList.push(data);} }, - openToSelected: function(self) { - //find 'selected' items and open tree accordingly. This may need to have a - //marker of some sort passed in since different trees may have different needs. + _delete: function(data){}, //TODO: implement + _update: function(data) {}, //TODO: implement + _addDomElem: function(data) { + var dataToInsert = this.getTemplate().process({"pools":[data], "id":this.element.get(0).id}); + if (data.ui_parent) { + var searchString = '#' + this.element.get(0).id + '-' + data.ui_parent; + var parentElem = this.element.find(searchString).siblings('ul'); + if (parentElem.size() === 0) { + this.element.find(searchString).parent().append('
                  ' + dataToInsert + '
                '); + this.element.find(searchString).siblings('span').addClass('expanded'); + } else { + parentElem.append(dataToInsert); + } + } else { + this.element.append(dataToInsert); + } }, - off: function() { - this.element.css({background: 'none'}); - this.destroy(); // use the predefined function - } + _deleteDomElem: function(data) {}, //TODO: implement + _updateDomElem: function(data) {} //TODO: implement }; $.yi = $.yi || {}; // create the namespace $.widget("yi.tree", Tree); $.yi.tree.defaults = { template: 'tree_template', toggle: 'toggle', - clickHandler: 'clickHandler' + clickHandler: 'clickHandler', + cacheContent: true }; })(jQuery); \ No newline at end of file diff --git a/src/public/javascripts/smart_nav_test_data.js b/src/public/javascripts/smart_nav_test_data.js deleted file mode 100644 index 43e7dbc..0000000 --- a/src/public/javascripts/smart_nav_test_data.js +++ /dev/null @@ -1,151 +0,0 @@ -var pools3 = { - "deleted" : {}, - "pools" :[ - { "name": "default", - "text": "default", - "children": - [{ "name": "Engineering", - "text": "Engineering", - "children": - [{ "name": "Development", - "text": "Development", - "children": - [{ "name": "Project X", - "text": "Project X", - "id": 19, - "type": "VmResourcePool"}, - { "name": "Project Y", - "text": "Project Y", - "id": 20, - "type": "VmResourcePool"}], - "id": 9, - "type": "HardwarePool"}, - { "name": "QA", - "text": "QA", - "children": - [{ "name": "Bob's Team", - "text": "Bob's Team", - "children": - [{ "name": "Bob's VMs", - "text": "Bob's VMs", - "id": 21, - "type": "VmResourcePool"}], - "id": 17, - "type": "HardwarePool"}, - { "name": "Jim's Team", - "text": "Jim's Team", - "children": - [{ "name": "Jim's VMs", - "text": "Jim's VMs", - "id": 22, - "type": "VmResourcePool"}], - "id": 18, - "type": "HardwarePool"}, - { "name": "Sally's Team", - "text": "Sally's Team", - "children": - [{ "name": "Sally's VMs", - "text": "Sally's VMs", - "id": 33, - "type": "VmResourcePool"}], - "id": 32, - "type": "HardwarePool"}], - "id": 10, - "type": "HardwarePool"}, - { "name": "Stage", - "text": "Stage", - "children": - [{ "name": "stage1", - "text": "stage1", - "id": 45, - "type": "HardwarePool"}, - { "name": "stage2", - "text": "stage2", - "id": 46, - "type": "HardwarePool"}], - "id": 44, - "type": "HardwarePool"}], - "id": 5, - "type": "HardwarePool"}, - { "name": "Finance", - "text": "Finance", - "children": - [{ "name": "Payroll", - "text": "Payroll", - "children": - [{ "name": "Payroll VMs", - "text": "Payroll VMs", - "id": 23, - "type": "VmResourcePool"}], - "id": 11, - "type": "HardwarePool"}, - { "name": "Accts. Receivable", - "text": "Accts. Receivable", - "children": - [{ "name": "our VMs", - "text": "our VMs", - "id": 24, - "type": "VmResourcePool"}], - "id": 12, - "type": "HardwarePool"}], - "id": 6, - "type": "HardwarePool"}, - { "name": "HR", - "text": "HR", - "children": - [{ "name": "Hiring Team", - "text": "Hiring Team", - "id": 13, - "type": "HardwarePool"}, - { "name": "Benefits", - "text": "Benefits", - "id": 14, - "type": "HardwarePool"}], - "id": 7, - "type": "HardwarePool"}, - { "name": "External (DMZ)", - "text": "External (DMZ)", - "children": - [{ "name": "VMs", - "text": "VMs", - "id": 25, - "type": "VmResourcePool"}, - { "name": "DB Cluster", - "text": "DB Cluster", - "children": - [{ "name": "VMs", - "text": "VMs", - "id": 27, - "type": "VmResourcePool"}], - "id": 26, - "type": "HardwarePool"}], - "id": 8, - "type": "HardwarePool"}], - "id": 1, - "type": "HardwarePool"}], -"smart_pools":[{ "name": "ovirtadmin", - "text": "ovirtadmin", - "children": - [{ "name": "not so smart", - "text": "not so smart", - "id": 39, - "type": "SmartPool"}, - { "name": "a little smarter", - "text": "a little smarter", - "id": 40, - "type": "SmartPool"}, - { "name": "arrrrr", - "text": "arrrrr", - "id": 41, - "type": "SmartPool"}, - { "name": "huh?", - "text": "huh?", - "id": 42, - "type": "SmartPool"}, - { "name": "booya", - "text": "booya", - "id": 43, - "type": "SmartPool"}], - "id": 37, - "type": "DirectoryPool"}] -} \ No newline at end of file diff --git a/src/public/javascripts/test/smart_nav_sample_data.js b/src/public/javascripts/test/smart_nav_sample_data.js new file mode 100644 index 0000000..43e7dbc --- /dev/null +++ b/src/public/javascripts/test/smart_nav_sample_data.js @@ -0,0 +1,151 @@ +var pools3 = { + "deleted" : {}, + "pools" :[ + { "name": "default", + "text": "default", + "children": + [{ "name": "Engineering", + "text": "Engineering", + "children": + [{ "name": "Development", + "text": "Development", + "children": + [{ "name": "Project X", + "text": "Project X", + "id": 19, + "type": "VmResourcePool"}, + { "name": "Project Y", + "text": "Project Y", + "id": 20, + "type": "VmResourcePool"}], + "id": 9, + "type": "HardwarePool"}, + { "name": "QA", + "text": "QA", + "children": + [{ "name": "Bob's Team", + "text": "Bob's Team", + "children": + [{ "name": "Bob's VMs", + "text": "Bob's VMs", + "id": 21, + "type": "VmResourcePool"}], + "id": 17, + "type": "HardwarePool"}, + { "name": "Jim's Team", + "text": "Jim's Team", + "children": + [{ "name": "Jim's VMs", + "text": "Jim's VMs", + "id": 22, + "type": "VmResourcePool"}], + "id": 18, + "type": "HardwarePool"}, + { "name": "Sally's Team", + "text": "Sally's Team", + "children": + [{ "name": "Sally's VMs", + "text": "Sally's VMs", + "id": 33, + "type": "VmResourcePool"}], + "id": 32, + "type": "HardwarePool"}], + "id": 10, + "type": "HardwarePool"}, + { "name": "Stage", + "text": "Stage", + "children": + [{ "name": "stage1", + "text": "stage1", + "id": 45, + "type": "HardwarePool"}, + { "name": "stage2", + "text": "stage2", + "id": 46, + "type": "HardwarePool"}], + "id": 44, + "type": "HardwarePool"}], + "id": 5, + "type": "HardwarePool"}, + { "name": "Finance", + "text": "Finance", + "children": + [{ "name": "Payroll", + "text": "Payroll", + "children": + [{ "name": "Payroll VMs", + "text": "Payroll VMs", + "id": 23, + "type": "VmResourcePool"}], + "id": 11, + "type": "HardwarePool"}, + { "name": "Accts. Receivable", + "text": "Accts. Receivable", + "children": + [{ "name": "our VMs", + "text": "our VMs", + "id": 24, + "type": "VmResourcePool"}], + "id": 12, + "type": "HardwarePool"}], + "id": 6, + "type": "HardwarePool"}, + { "name": "HR", + "text": "HR", + "children": + [{ "name": "Hiring Team", + "text": "Hiring Team", + "id": 13, + "type": "HardwarePool"}, + { "name": "Benefits", + "text": "Benefits", + "id": 14, + "type": "HardwarePool"}], + "id": 7, + "type": "HardwarePool"}, + { "name": "External (DMZ)", + "text": "External (DMZ)", + "children": + [{ "name": "VMs", + "text": "VMs", + "id": 25, + "type": "VmResourcePool"}, + { "name": "DB Cluster", + "text": "DB Cluster", + "children": + [{ "name": "VMs", + "text": "VMs", + "id": 27, + "type": "VmResourcePool"}], + "id": 26, + "type": "HardwarePool"}], + "id": 8, + "type": "HardwarePool"}], + "id": 1, + "type": "HardwarePool"}], +"smart_pools":[{ "name": "ovirtadmin", + "text": "ovirtadmin", + "children": + [{ "name": "not so smart", + "text": "not so smart", + "id": 39, + "type": "SmartPool"}, + { "name": "a little smarter", + "text": "a little smarter", + "id": 40, + "type": "SmartPool"}, + { "name": "arrrrr", + "text": "arrrrr", + "id": 41, + "type": "SmartPool"}, + { "name": "huh?", + "text": "huh?", + "id": 42, + "type": "SmartPool"}, + { "name": "booya", + "text": "booya", + "id": 43, + "type": "SmartPool"}], + "id": 37, + "type": "DirectoryPool"}] +} \ No newline at end of file diff --git a/src/public/javascripts/test/storage_tree_sample_data.js b/src/public/javascripts/test/storage_tree_sample_data.js new file mode 100644 index 0000000..f798a45 --- /dev/null +++ b/src/public/javascripts/test/storage_tree_sample_data.js @@ -0,0 +1,68 @@ +var storage_pools = {"pools": +[ + { + "selected":false, + "name":"iSCSI: 192.168.50.2:ovirtpriv:storage", + "available":false, + "children": + [ + { + "selected":false, + "name":"iSCSI: 192.168.50.2:ovirtpriv:storage:lun-2", + "available":true, + "children":[], + "create_volume":true, + "text":"iSCSI: 192.168.50.2:ovirtpriv:storage:lun-2", + "id":5, + "type":"IscsiStorageVolume", + "ui_object": "IscsiStorageVolume_5", + "ui_parent": "IscsiStoragePool_2" + }, + + { + "selected":false, + "name":"iSCSI: 192.168.50.2:ovirtpriv:storage:lun-3", + "available":true, + "children":[], + "create_volume":true, + "text":"iSCSI: 192.168.50.2:ovirtpriv:storage:lun-3", + "id":4, + "type":"IscsiStorageVolume", + "ui_object": "IscsiStorageVolume_4", + "ui_parent": "IscsiStoragePool_2" + } + ], + "create_volume":false, + "text":"iSCSI: 192.168.50.2:ovirtpriv:storage", + "id":2, + "type":"IscsiStoragePool", + "ui_object": "IscsiStoragePool_2", + "ui_parent": null + }, + + { + "selected":false, + "name":"iSCSI: 192.68.60.2:/fred", + "available":false, + "children":[], + "create_volume":false, + "text":"iSCSI: 192.68.60.2:/fred", + "id":7, + "type":"IscsiStoragePool", + "ui_object": "IscsiStoragePool_7", + "ui_parent": null + }, + + { + "selected":false, + "name":"iSCSI: 192.168.60.4:/mo", + "available":false, + "children":[], + "create_volume":false, + "text":"iSCSI: 192.168.60.4:/mo", + "id":6, + "type":"IscsiStoragePool", + "ui_object": "IscsiStoragePool_6", + "ui_parent": null + } +]} \ No newline at end of file diff --git a/src/test/fixtures/storage_volumes.yml b/src/test/fixtures/storage_volumes.yml index a3711bf..8e5b60a 100644 --- a/src/test/fixtures/storage_volumes.yml +++ b/src/test/fixtures/storage_volumes.yml @@ -19,6 +19,16 @@ ovirtpriv_storage_lun_3: storage_pool: corp_com_ovirtpriv_storage type: IscsiStorageVolume state: available + lvm_pool_id: corp_com_dev_lvm_ovirtlvm +ovirtpriv_lvm_volume_1: + size: 1048576 + path: /dev/disk/by-id/scsi-S_beaf321013 + storage_pool: corp_com_dev_lvm_ovirtlvm + type: LvmStorageVolume + state: available + lv_owner_perms: 0744 + lv_group_perms: 0744 + lv_mode_perms: 0744 ovirt_nfs_disk_1: size: 3145728 path: /mnt/a3q49Sj4Sfmae1bV/disk1.dsk diff --git a/src/test/unit/storage_volume_test.rb b/src/test/unit/storage_volume_test.rb index 3978685..16be0fb 100644 --- a/src/test/unit/storage_volume_test.rb +++ b/src/test/unit/storage_volume_test.rb @@ -1,4 +1,4 @@ -# +# # Copyright (C) 2008 Red Hat, Inc. # Written by Scott Seago # @@ -112,4 +112,23 @@ class StorageVolumeTest < Test::Unit::TestCase assert_equal @storage_volume.movable?, false, "Storage volume w/ vms should not be movable" end + def test_create_valid_lvm_volume +# FIXME: Write this test, using similer steps as in storage_controller#new_volume. +# Also add validation to model to make sure the lvm volume's lvm pool has a source volume + end + def test_return_correct_lvm_ui_parent + #test lvm volume values + assert_equal storage_volumes(:ovirtpriv_storage_lun_3).type.to_s + '_' +storage_volumes(:ovirtpriv_storage_lun_3).id.to_s, + storage_volumes(:ovirtpriv_lvm_volume_1).ui_parent, + 'Incorrect ui parent returned' + #test isci volume values + assert_equal storage_volumes(:corp_com_ovirtpriv_storage).type.to_s + '_' +storage_volumes(:corp_com_ovirtpriv_storage).id.to_s, + storage_volumes(:ovirtpriv_storage_lun_3).ui_parent, + 'Incorrect ui parent returned' + #test nfs volume values + assert_equal storage_volumes(:corp_com_nfs_ovirtnfs).type.to_s + '_' +storage_volumes(:corp_com_nfs_ovirtnfs).id.to_s, + storage_volumes(:ovirt_nfs_disk_3).ui_parent, + 'Incorrect ui parent returned' + end + end -- 1.5.6.6 From sseago at redhat.com Thu Jan 22 23:01:59 2009 From: sseago at redhat.com (Scott Seago) Date: Thu, 22 Jan 2009 23:01:59 +0000 Subject: [Ovirt-devel] [PATCH] more permissions validation for non-privileged users. Message-ID: <1232665319-23405-1-git-send-email-sseago@redhat.com> Fixed some of the error handling for popup and json ajax responses, and hid action links from non-privileged users where those actions were not appropriate for them. Signed-off-by: Scott Seago --- src/app/controllers/application.rb | 40 +++++++++++++-------- src/app/controllers/dashboard_controller.rb | 1 + src/app/controllers/hardware_controller.rb | 5 +-- src/app/controllers/host_controller.rb | 9 +++++ src/app/controllers/network_controller.rb | 25 ++++++++----- src/app/controllers/pool_controller.rb | 8 ++-- src/app/controllers/quota_controller.rb | 3 -- src/app/controllers/resources_controller.rb | 2 - src/app/controllers/smart_pools_controller.rb | 3 +- src/app/controllers/storage_controller.rb | 25 ++++--------- src/app/controllers/vm_controller.rb | 3 -- src/app/models/smart_pool.rb | 8 +++-- src/app/views/hardware/show_hosts.rhtml | 24 +++++++----- src/app/views/hardware/show_storage.rhtml | 28 +++++++++------ src/app/views/hardware/show_vms.rhtml | 14 +++++-- src/app/views/layouts/_side_toolbar.rhtml | 4 +- src/app/views/layouts/_tree.rhtml | 9 +++-- src/app/views/layouts/popup-error.rhtml | 5 +++ src/app/views/resources/show_vms.rhtml | 46 ++++++++++++++---------- src/app/views/user/_grid.rhtml | 11 ++++-- src/app/views/user/_show.rhtml | 9 +++-- src/public/stylesheets/ovirt-tree/tree.css | 8 ++--- 22 files changed, 167 insertions(+), 123 deletions(-) create mode 100644 src/app/views/layouts/popup-error.rhtml diff --git a/src/app/controllers/application.rb b/src/app/controllers/application.rb index 3f75979..1c3f99e 100644 --- a/src/app/controllers/application.rb +++ b/src/app/controllers/application.rb @@ -82,26 +82,36 @@ class ApplicationController < ActionController::Base def pre_show end - def authorize_user - authorize_action(false) + def authorize_user(msg=nil) + authorize_action(false,msg) end - def authorize_admin - authorize_action(true) + def authorize_admin(msg=nil) + authorize_action(true,msg) end - def authorize_action(is_modify_action) + def authorize_action(is_modify_action, msg=nil) + msg ||= 'You do not have permission to create or modify this item ' if @perm_obj set_perms(@perm_obj) unless (is_modify_action ? @can_modify : @can_control_vms) - @redir_obj = @perm_obj unless @redir_obj - flash[:notice] = 'You do not have permission to create or modify this item ' - if @json_hash - @json_hash[:success] = false - @json_hash[:alert] = flash[:notice] - render :json => @json_hash - elsif @redir_controller - redirect_to :controller => @redir_controller, :action => 'show', :id => @redir_obj - else - redirect_to :action => 'show', :id => @redir_obj + respond_to do |format| + format.html do + @title = "Access denied" + @errmsg = msg + if params[:ajax] + render :template => 'layouts/popup-error', :layout => 'tabs-and-content' + elsif params[:nolayout] + render :template => 'layouts/popup-error', :layout => 'help-and-content' + else + render :template => 'layouts/popup-error', :layout => 'popup' + end + end + format.json do + @json_hash ||= {} + @json_hash[:success] = false + @json_hash[:alert] = msg + render :json => @json_hash + end + format.xml { head :forbidden } end false end diff --git a/src/app/controllers/dashboard_controller.rb b/src/app/controllers/dashboard_controller.rb index 00398a5..821fb3f 100644 --- a/src/app/controllers/dashboard_controller.rb +++ b/src/app/controllers/dashboard_controller.rb @@ -29,6 +29,7 @@ class DashboardController < ApplicationController def index @task_types = Task::TASK_TYPES_OPTIONS + @user = get_login_user show_tasks end diff --git a/src/app/controllers/hardware_controller.rb b/src/app/controllers/hardware_controller.rb index 5c14eec..fc16a27 100644 --- a/src/app/controllers/hardware_controller.rb +++ b/src/app/controllers/hardware_controller.rb @@ -29,7 +29,8 @@ class HardwareController < PoolController before_filter :pre_modify, :only => [:add_hosts, :move_hosts, :add_storage, :move_storage, - :create_storage, :delete_storage] + :create_storage, :delete_storage, + :move, :removestorage] def index if params[:path] @@ -174,7 +175,6 @@ class HardwareController < PoolController end def move - pre_modify @resource_type = params[:resource_type] @id = params[:id] @pools = HardwarePool.get_default_pool.full_set_nested(:method => :json_hash_element, @@ -330,7 +330,6 @@ class HardwareController < PoolController end def removestorage - pre_modify render :layout => 'popup' end diff --git a/src/app/controllers/host_controller.rb b/src/app/controllers/host_controller.rb index da630f7..02ad8c9 100644 --- a/src/app/controllers/host_controller.rb +++ b/src/app/controllers/host_controller.rb @@ -31,6 +31,7 @@ class HostController < ApplicationController end before_filter :pre_action, :only => [:host_action, :enable, :disable, :clear_vms, :edit_network] + before_filter :pre_addhost, :only => [:addhost] # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html) verify :method => [:post, :put], :only => [ :create, :update ], @@ -85,6 +86,14 @@ class HostController < ApplicationController render :layout => 'popup' end + def pre_addhost + @pool = Pool.find(params[:hardware_pool_id]) + @parent = @pool.parent + @perm_obj = @pool + @current_pool_id=@pool.id + authorize_admin + end + def add_to_smart_pool @pool = SmartPool.find(params[:smart_pool_id]) render :layout => 'popup' diff --git a/src/app/controllers/network_controller.rb b/src/app/controllers/network_controller.rb index e4faf7b..7328e66 100644 --- a/src/app/controllers/network_controller.rb +++ b/src/app/controllers/network_controller.rb @@ -20,22 +20,24 @@ class NetworkController < ApplicationController ########################## Networks related actions - def network_permissions + before_filter :pre_list, :only => [:list] + + def authorize_admin # 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 + @perm_obj=@default_pool + super('You do not have permission to access networks') end - def list + def pre_list @networks = Network.find(:all) - network_permissions + authorize_admin + end + + def list respond_to do |format| format.html { render :layout => 'tabs-and-content' if params[:ajax] @@ -51,9 +53,12 @@ class NetworkController < ApplicationController json_list(Network.find(:all), [:id, :name, :type, [:boot_type, :label]]) end + def pre_show + @network = Network.find(params[:id]) + authorize_admin + 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 } diff --git a/src/app/controllers/pool_controller.rb b/src/app/controllers/pool_controller.rb index b8d0f10..2809d6d 100644 --- a/src/app/controllers/pool_controller.rb +++ b/src/app/controllers/pool_controller.rb @@ -62,8 +62,10 @@ class PoolController < ApplicationController end def users_json - json_list(@pool.permissions, - [:grid_id, :uid, :user_role, :source]) + attr_list = [] + attr_list << :grid_id if params[:checkboxes] + attr_list += [:uid, :user_role, :source] + json_list(@pool.permissions, attr_list) end def hosts_json(args) @@ -103,7 +105,6 @@ class PoolController < ApplicationController def pre_new @parent = Pool.find(params[:parent_id]) @perm_obj = @parent - @redir_controller = @perm_obj.get_controller @current_pool_id=@parent.id end def pre_create @@ -114,7 +115,6 @@ class PoolController < ApplicationController @parent = Pool.find(params[:parent_id]) end @perm_obj = @parent - @redir_controller = @perm_obj.get_controller @current_pool_id=@parent.id end def pre_show_pool diff --git a/src/app/controllers/quota_controller.rb b/src/app/controllers/quota_controller.rb index 58446d4..17fdc20 100644 --- a/src/app/controllers/quota_controller.rb +++ b/src/app/controllers/quota_controller.rb @@ -84,12 +84,10 @@ class QuotaController < ApplicationController def pre_new @quota = Quota.new( { :pool_id => params[:pool_id]}) @perm_obj = @quota.pool - @redir_controller = @perm_obj.get_controller end def pre_create @quota = Quota.new(params[:quota]) @perm_obj = @quota.pool - @redir_controller = @perm_obj.get_controller end def pre_show @quota = Quota.find(params[:id]) @@ -98,7 +96,6 @@ class QuotaController < ApplicationController def pre_edit @quota = Quota.find(params[:id]) @perm_obj = @quota.pool - @redir_controller = @perm_obj.get_controller end end diff --git a/src/app/controllers/resources_controller.rb b/src/app/controllers/resources_controller.rb index 3c6e3ee..7bed533 100644 --- a/src/app/controllers/resources_controller.rb +++ b/src/app/controllers/resources_controller.rb @@ -167,7 +167,6 @@ class ResourcesController < PoolController @pool = VmResourcePool.find(params[:id]) @parent = @pool.parent @perm_obj = @pool.parent - @redir_obj = @pool @current_pool_id=@pool.id end def pre_show @@ -179,7 +178,6 @@ class ResourcesController < PoolController @pool = VmResourcePool.find(params[:id]) @parent = @pool.parent @perm_obj = @pool - @redir_obj = @pool authorize_user end diff --git a/src/app/controllers/smart_pools_controller.rb b/src/app/controllers/smart_pools_controller.rb index 10dbf9a..cbfbd1c 100644 --- a/src/app/controllers/smart_pools_controller.rb +++ b/src/app/controllers/smart_pools_controller.rb @@ -24,7 +24,7 @@ class SmartPoolsController < PoolController :add_storage, :remove_storage, :add_vms, :remove_vms, :add_pools, :remove_pools, - :add_items] + :add_items, :add_pool_dialog] def show_vms show end @@ -65,7 +65,6 @@ class SmartPoolsController < PoolController end def add_pool_dialog - pre_modify @selected_pools = @pool.tagged_pools.collect {|pool| pool.id} render :layout => 'popup' end diff --git a/src/app/controllers/storage_controller.rb b/src/app/controllers/storage_controller.rb index e4b72f1..2b76f44 100644 --- a/src/app/controllers/storage_controller.rb +++ b/src/app/controllers/storage_controller.rb @@ -26,6 +26,7 @@ class StorageController < ApplicationController before_filter :pre_new2, :only => [:new2] before_filter :pre_json, :only => [:storage_volumes_json] before_filter :pre_create_volume, :only => [:create_volume] + before_filter :pre_add, :only => [:add, :addstorage] def index list @@ -258,27 +259,15 @@ class StorageController < ApplicationController end end - def add_internal - @hardware_pool = HardwarePool.find(params[:hardware_pool_id]) - @perm_obj = @hardware_pool - @redir_controller = @perm_obj.get_controller - authorize_admin - @storage_pools = @hardware_pool.storage_volumes - @storage_types = StoragePool::STORAGE_TYPE_PICKLIST - end - def addstorage - add_internal render :layout => 'popup' end def add - add_internal render :layout => false end def new - add_internal render :layout => false end @@ -396,7 +385,13 @@ class StorageController < ApplicationController def pre_new @hardware_pool = HardwarePool.find(params[:hardware_pool_id]) @perm_obj = @hardware_pool - @redir_controller = @perm_obj.get_controller + authorize_admin + @storage_pools = @hardware_pool.storage_volumes + @storage_types = StoragePool::STORAGE_TYPE_PICKLIST + end + + def pre_add + pre_new end def pre_new2 @@ -406,7 +401,6 @@ class StorageController < ApplicationController end @storage_pool = StoragePool.factory(params[:storage_type], new_params) @perm_obj = @storage_pool.hardware_pool - @redir_controller = @storage_pool.hardware_pool.get_controller authorize_admin end def pre_create @@ -416,12 +410,10 @@ class StorageController < ApplicationController end @storage_pool = StoragePool.factory(type, pool) @perm_obj = @storage_pool.hardware_pool - @redir_controller = @storage_pool.hardware_pool.get_controller end def pre_edit @storage_pool = StoragePool.find(params[:id]) @perm_obj = @storage_pool.hardware_pool - @redir_obj = @storage_pool end def pre_create_volume volume = params[:storage_volume] @@ -430,7 +422,6 @@ class StorageController < ApplicationController end @storage_volume = StorageVolume.factory(type, volume) @perm_obj = @storage_volume.storage_pool.hardware_pool - @redir_controller = @storage_volume.storage_pool.hardware_pool.get_controller authorize_admin end def pre_json diff --git a/src/app/controllers/vm_controller.rb b/src/app/controllers/vm_controller.rb index 701dea8..56501fd 100644 --- a/src/app/controllers/vm_controller.rb +++ b/src/app/controllers/vm_controller.rb @@ -332,7 +332,6 @@ class VmController < ApplicationController @vm.vm_resource_pool = @vm_resource_pool end @perm_obj = @vm.vm_resource_pool - @redir_controller = 'resources' @current_pool_id=@perm_obj.id _setup_provisioning_options end @@ -348,7 +347,6 @@ class VmController < ApplicationController end @vm = Vm.new(params[:vm]) @perm_obj = @vm.vm_resource_pool - @redir_controller = 'resources' @current_pool_id=@perm_obj.id end def pre_show @@ -359,7 +357,6 @@ class VmController < ApplicationController def pre_edit @vm = Vm.find(params[:id]) @perm_obj = @vm.vm_resource_pool - @redir_obj = @vm @current_pool_id=@perm_obj.id _setup_provisioning_options end diff --git a/src/app/models/smart_pool.rb b/src/app/models/smart_pool.rb index 772ffef..7df26fa 100644 --- a/src/app/models/smart_pool.rb +++ b/src/app/models/smart_pool.rb @@ -87,9 +87,11 @@ class SmartPool < Pool user_pools <<[child_pool.name, child_pool.id] end else - pool_element[:children].each do |child_element| - child_pool = child_element[:obj] - other_pools << [pool.name + " > " + child_pool.name, child_pool.id] + if pool_element.has_key?(:children) + pool_element[:children].each do |child_element| + child_pool = child_element[:obj] + other_pools << [pool.name + " > " + child_pool.name, child_pool.id] + end end end end diff --git a/src/app/views/hardware/show_hosts.rhtml b/src/app/views/hardware/show_hosts.rhtml index 2fd29bc..64e5d91 100644 --- a/src/app/views/hardware/show_hosts.rhtml +++ b/src/app/views/hardware/show_hosts.rhtml @@ -1,11 +1,13 @@
                @@ -111,8 +113,10 @@
                No hosts found in this pool.

                - <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>   - Add first host to this hardware pool + <%if @can_modify -%> + <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>   + Add first host to this hardware pool + <% end -%>
        diff --git a/src/app/views/hardware/show_storage.rhtml b/src/app/views/hardware/show_storage.rhtml index 5643c83..5180be6 100644 --- a/src/app/views/hardware/show_storage.rhtml +++ b/src/app/views/hardware/show_storage.rhtml @@ -1,10 +1,12 @@ @@ -141,8 +145,10 @@ ${htmlList(pools)}
        No storage Volumes found in this pool.

        - <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>   - Add first storage volume to this hardware pool + <%if @can_modify -%> + <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>   + Add first storage volume to this hardware pool + <% end -%>
    diff --git a/src/app/views/hardware/show_vms.rhtml b/src/app/views/hardware/show_vms.rhtml index 6a8ded5..a829611 100644 --- a/src/app/views/hardware/show_vms.rhtml +++ b/src/app/views/hardware/show_vms.rhtml @@ -1,6 +1,8 @@
    diff --git a/src/app/views/storage/show.rhtml b/src/app/views/storage/show.rhtml index 7e02f32..dd52d79 100644 --- a/src/app/views/storage/show.rhtml +++ b/src/app/views/storage/show.rhtml @@ -12,7 +12,7 @@ <%if @storage_pool.user_subdividable -%> <%= link_to image_tag("icon_addstorage.png") + " Add new Volume", - {:controller => 'storage', :action => 'new_volume', :storage_pool_id => @storage_pool.id}, + {:controller => 'storage_volume', :action => 'new', :storage_pool_id => @storage_pool.id}, :rel=>"facebox[.bolder]", :class=>"selection_facebox" %> <% end %> diff --git a/src/app/views/storage/show_volume.rhtml b/src/app/views/storage/show_volume.rhtml deleted file mode 100644 index f85feaa..0000000 --- a/src/app/views/storage/show_volume.rhtml +++ /dev/null @@ -1,87 +0,0 @@ -<%- content_for :title do -%> - <%=h @storage_volume.display_name %> -<%- end -%> - -<%- content_for :action_links do -%> - <%if @can_modify -%> - <%if @storage_volume.supports_lvm_subdivision and @storage_volume.vms.empty? -%> - <%= link_to image_tag("icon_addstorage.png") + " Add new Volume", - {:controller => 'storage', :action => 'new_volume', :source_volume_id => @storage_volume.id}, - :rel=>"facebox[.bolder]", :class=>"selection_facebox" %> - <% end %> - <%if @storage_volume.deletable -%> - - <%= image_tag "icon_x.png" %> Delete - - <%- end -%> - <%- end -%> -<%- end -%> -<%= confirmation_dialog("confirm_delete", "Are you sure?", "delete_volume()") %> - -
    - <% unless @storage_volume.storage_pool[:type] == "LvmStoragePool" %> - IP address:
    - <% end %> - <% if @storage_volume.storage_pool[:type] == "IscsiStoragePool" %> - Port:
    - Target:
    - <% elsif @storage_volume.storage_pool[:type] == "NfsStoragePool" %> - Export path:
    - <% end %> - Type:
    - State:
    - Path:
    - <% if @storage_volume[:type] == "IscsiStorageVolume" %> - LUN:
    - <% elsif @storage_volume[:type] == "NfsStorageVolume" %> - Filename:
    - <% elsif @storage_volume[:type] == "LvmStorageVolume" %> - Volume Group:
    - Logical Volume:
    - Permissions (owner/group/mode):
    - <% end %> - Size:
    -
    -
    - <% unless @storage_volume.storage_pool[:type] == "LvmStoragePool" %> - <%=h @storage_volume.storage_pool.ip_addr %>
    - <% end %> - <% if @storage_volume.storage_pool[:type] == "IscsiStoragePool" %> - <%=h @storage_volume.storage_pool.port %>
    - <%=h @storage_volume.storage_pool[:target] %>
    - <% elsif @storage_volume.storage_pool[:type] == "NfsStoragePool" %> - <%=h @storage_volume.storage_pool.export_path %>
    - <% end %> - <%=h @storage_volume.storage_pool.get_type_label %>
    - <%=h @storage_volume.state %>
    - <%=h @storage_volume.path %>
    - <% if @storage_volume[:type] == "IscsiStorageVolume" %> - <%=h @storage_volume.lun %>
    - <% elsif @storage_volume[:type] == "NfsStorageVolume" %> - <%=h @storage_volume.filename %>
    - <% elsif @storage_volume[:type] == "LvmStorageVolume" %> - <%=h @storage_volume.storage_pool.vg_name %>
    - <%=h @storage_volume.lv_name %>
    - <%=h @storage_volume.lv_owner_perms %>/<%=h @storage_volume.lv_group_perms %>/<%=h @storage_volume.lv_mode_perms %>
    - <% end %> - <%=h @storage_volume.size_in_gb %> GB
    -
    -<%- content_for :right do -%> - -<%- end -%> - - diff --git a/src/app/views/storage_volume/_new_volume_form.rhtml b/src/app/views/storage_volume/_new_volume_form.rhtml new file mode 100644 index 0000000..ae65e18 --- /dev/null +++ b/src/app/views/storage_volume/_new_volume_form.rhtml @@ -0,0 +1,24 @@ +<%= error_messages_for 'storage_volume' %> + + +<%= hidden_field 'storage_volume', 'storage_pool_id' %> +<%= hidden_field_tag 'storage_type', @storage_volume.get_type_label %> + +<%= text_field_with_label "Size (GB):", 'storage_volume', 'size_in_gb' %> + +<%if @storage_volume.get_type_label==StoragePool::LVM -%> + <%= text_field_with_label "LV Name:", 'storage_volume', 'lv_name' %> + + <%= text_field_with_label "Owner permissions:", 'storage_volume', 'lv_owner_perms' %> + + <%= text_field_with_label "Group permissions:", 'storage_volume', 'lv_group_perms' %> + + <%= text_field_with_label "Mode permissions:", 'storage_volume', 'lv_mode_perms' %> +<%- end -%> +<%= text_field_with_label "LUN:", 'storage_volume', 'lun' if @storage_volume.get_type_label==StoragePool::ISCSI %> + +<%= text_field_with_label "Filename:", 'storage_volume', 'filename' if @storage_volume.get_type_label==StoragePool::NFS %> + + + + diff --git a/src/app/views/storage_volume/new.rhtml b/src/app/views/storage_volume/new.rhtml new file mode 100644 index 0000000..4993642 --- /dev/null +++ b/src/app/views/storage_volume/new.rhtml @@ -0,0 +1,47 @@ +<%- content_for :title do -%> + <%= _("Add New Volume") %> +<%- end -%> +<%- content_for :description do -%> + Add a new Storage Volume to + <%= if @storage_volume.get_type_label==StoragePool::LVM + @source_volume.display_name + else + @storage_pool.display_name + end %>. +<%- end -%> +
    +
    +
    +
    +
    + <%= render :partial => 'new_volume_form' %> +
    +
    + + <%= popup_footer("$('#storage_volume_form').submit()", "New Storage Volume") %> +
    +
    + diff --git a/src/app/views/storage_volume/show.rhtml b/src/app/views/storage_volume/show.rhtml new file mode 100644 index 0000000..c2434aa --- /dev/null +++ b/src/app/views/storage_volume/show.rhtml @@ -0,0 +1,87 @@ +<%- content_for :title do -%> + <%=h @storage_volume.display_name %> +<%- end -%> + +<%- content_for :action_links do -%> + <%if @can_modify -%> + <%if @storage_volume.supports_lvm_subdivision and @storage_volume.vms.empty? -%> + <%= link_to image_tag("icon_addstorage.png") + " Add new Volume", + {:controller => 'storage_volume', :action => 'new', :source_volume_id => @storage_volume.id}, + :rel=>"facebox[.bolder]", :class=>"selection_facebox" %> + <% end %> + <%if @storage_volume.deletable -%> + + <%= image_tag "icon_x.png" %> Delete + + <%- end -%> + <%- end -%> +<%- end -%> +<%= confirmation_dialog("confirm_delete", "Are you sure?", "delete_volume()") %> + +
    + <% unless @storage_volume.storage_pool[:type] == "LvmStoragePool" %> + IP address:
    + <% end %> + <% if @storage_volume.storage_pool[:type] == "IscsiStoragePool" %> + Port:
    + Target:
    + <% elsif @storage_volume.storage_pool[:type] == "NfsStoragePool" %> + Export path:
    + <% end %> + Type:
    + State:
    + Path:
    + <% if @storage_volume[:type] == "IscsiStorageVolume" %> + LUN:
    + <% elsif @storage_volume[:type] == "NfsStorageVolume" %> + Filename:
    + <% elsif @storage_volume[:type] == "LvmStorageVolume" %> + Volume Group:
    + Logical Volume:
    + Permissions (owner/group/mode):
    + <% end %> + Size:
    +
    +
    + <% unless @storage_volume.storage_pool[:type] == "LvmStoragePool" %> + <%=h @storage_volume.storage_pool.ip_addr %>
    + <% end %> + <% if @storage_volume.storage_pool[:type] == "IscsiStoragePool" %> + <%=h @storage_volume.storage_pool.port %>
    + <%=h @storage_volume.storage_pool[:target] %>
    + <% elsif @storage_volume.storage_pool[:type] == "NfsStoragePool" %> + <%=h @storage_volume.storage_pool.export_path %>
    + <% end %> + <%=h @storage_volume.storage_pool.get_type_label %>
    + <%=h @storage_volume.state %>
    + <%=h @storage_volume.path %>
    + <% if @storage_volume[:type] == "IscsiStorageVolume" %> + <%=h @storage_volume.lun %>
    + <% elsif @storage_volume[:type] == "NfsStorageVolume" %> + <%=h @storage_volume.filename %>
    + <% elsif @storage_volume[:type] == "LvmStorageVolume" %> + <%=h @storage_volume.storage_pool.vg_name %>
    + <%=h @storage_volume.lv_name %>
    + <%=h @storage_volume.lv_owner_perms %>/<%=h @storage_volume.lv_group_perms %>/<%=h @storage_volume.lv_mode_perms %>
    + <% end %> + <%=h @storage_volume.size_in_gb %> GB
    +
    +<%- content_for :right do -%> + +<%- end -%> + + -- 1.6.0.6 From lutter at redhat.com Mon Jan 26 21:12:03 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 26 Jan 2009 13:12:03 -0800 Subject: [Ovirt-devel] [PATCH server 6/8] Remove delete_volumes, since it was not used In-Reply-To: <1233004325-18032-1-git-send-email-lutter@redhat.com> References: <1233004325-18032-1-git-send-email-lutter@redhat.com> Message-ID: <1233004325-18032-7-git-send-email-lutter@redhat.com> --- src/app/controllers/storage_volume_controller.rb | 49 ---------------------- src/app/views/storage_volume/show.rhtml | 2 +- 2 files changed, 1 insertions(+), 50 deletions(-) diff --git a/src/app/controllers/storage_volume_controller.rb b/src/app/controllers/storage_volume_controller.rb index 197864a..93eb68c 100644 --- a/src/app/controllers/storage_volume_controller.rb +++ b/src/app/controllers/storage_volume_controller.rb @@ -117,54 +117,6 @@ class StorageVolumeController < ApplicationController end def destroy - if params[:id] - delete_volume - else - delete_volumes - end - end - - def delete_volumes - storage_volume_ids_str = params[:storage_volume_ids] - storage_volume_ids = storage_volume_ids_str.split(",").collect {|x| x.to_i} - alerts = [] - status = true - begin - StorageVolume.transaction do - storage = StorageVolume.find(:all, :conditions => "id in (#{storage_volume_ids.join(', ')})") - unless storage.empty? - set_perms(storage[0].storage_pool.hardware_pool) - unless @can_modify and storage[0].storage_pool.user_subdividable - respond_to do |format| - format.json { render :json => { :object => "storage_volume", - :success => false, - :alert => "You do not have permission to delete this storage volume." } } - format.xml { head :forbidden } - end - else - storage.each do |storage_volume| - alert, success = delete_volume_internal(storage_volume) - alerts << alert - status = false unless success - end - respond_to do |format| - format.json { render :json => { :object => "storage_volume", - :success => status, :alert => alerts.join("\n") } } - format.xml { head(status ? :ok : :method_not_allowed) } - end - end - else - respond_to do |format| - format.json { render :json => { :object => "storage_volume", - :success => false, :alert => "no volumes selected" } } - format.xml { head(status ? :ok : :method_not_allowed) } - end - end - end - end - end - - def delete_volume @storage_volume = StorageVolume.find(params[:id]) set_perms(@storage_volume.storage_pool.hardware_pool) unless @can_modify and @storage_volume.storage_pool.user_subdividable @@ -182,7 +134,6 @@ class StorageVolumeController < ApplicationController format.xml { head(success ? :ok : :method_not_allowed) } end end - end def pre_create diff --git a/src/app/views/storage_volume/show.rhtml b/src/app/views/storage_volume/show.rhtml index c2434aa..3963a3c 100644 --- a/src/app/views/storage_volume/show.rhtml +++ b/src/app/views/storage_volume/show.rhtml @@ -75,7 +75,7 @@ { $(document).trigger('close.facebox'); $.post('<%= url_for :controller => "storage_volume", :action => "destroy" %>', - { storage_volume_ids: <%= @storage_volume.id %> }, + { id: <%= @storage_volume.id %> }, function(data,status) { // FIXME: reload tree if (data.alert) { -- 1.6.0.6 From lutter at redhat.com Mon Jan 26 21:12:04 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 26 Jan 2009 13:12:04 -0800 Subject: [Ovirt-devel] [PATCH server 7/8] Produce a human-readable error when deleting a pool fails In-Reply-To: <1233004325-18032-1-git-send-email-lutter@redhat.com> References: <1233004325-18032-1-git-send-email-lutter@redhat.com> Message-ID: <1233004325-18032-8-git-send-email-lutter@redhat.com> --- src/app/controllers/storage_controller.rb | 6 ++++-- src/app/views/errors/simple.xml.builder | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 src/app/views/errors/simple.xml.builder diff --git a/src/app/controllers/storage_controller.rb b/src/app/controllers/storage_controller.rb index 9674125..721cfc0 100644 --- a/src/app/controllers/storage_controller.rb +++ b/src/app/controllers/storage_controller.rb @@ -215,10 +215,12 @@ class StorageController < ApplicationController def destroy unless @storage_pool.movable? + @error = "Cannot delete storage with associated vms" respond_to do |format| format.json { render :json => { :object => "storage_pool", - :success => false, - :alert => "Cannot delete storage with associated vms" } } + :success => false, :alert => @error } } + format.xml { render :template => "errors/simple", :layout => false, + :status => :forbidden } end return end diff --git a/src/app/views/errors/simple.xml.builder b/src/app/views/errors/simple.xml.builder new file mode 100644 index 0000000..d8d3c5b --- /dev/null +++ b/src/app/views/errors/simple.xml.builder @@ -0,0 +1,3 @@ +xml.instruct! + +xml.error @error -- 1.6.0.6 From lutter at redhat.com Mon Jan 26 21:12:05 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 26 Jan 2009 13:12:05 -0800 Subject: [Ovirt-devel] [PATCH server 8/8] REST route for storage volumes In-Reply-To: <1233004325-18032-1-git-send-email-lutter@redhat.com> References: <1233004325-18032-1-git-send-email-lutter@redhat.com> Message-ID: <1233004325-18032-9-git-send-email-lutter@redhat.com> --- src/config/routes.rb | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/src/config/routes.rb b/src/config/routes.rb index 132072e..168ded5 100644 --- a/src/config/routes.rb +++ b/src/config/routes.rb @@ -53,6 +53,7 @@ ActionController::Routing::Routes.draw do |map| # REST work out of the box, and use these as the default routes map.resources :hosts, :controller => 'host' map.resources :storage_pools, :controller => 'storage' + map.resources :storage_volumes, :controller => 'storage_volume' map.resources :hardware_pools, :controller => 'hardware' do |hardware_pools| hardware_pools.resources :hosts, :controller => 'host' hardware_pools.resources :storage_pools, :controller => 'storage' -- 1.6.0.6 From lutter at redhat.com Mon Jan 26 21:20:30 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 26 Jan 2009 13:20:30 -0800 Subject: [Ovirt-devel] New client repo and start of a CLI Message-ID: <1233004841-18191-1-git-send-email-lutter@redhat.com> This series of patches makes changes to the new ovirt-client repo. The repo can be found at git://ovirt.org/ovirt-client; the same people that have commit access to the server repo have commit for this repo. Since I was so excited to establish a new repo, I already pushed all these patches to the new repo, but I would still appreciate comments/acks on these. The patch series has to be applied against the very first commit in the repo, which only copied files from the server to the client repo, though it's probably simpler to just check out ovirt-client and review the log of the next branch. Please read the README first before trying the ovirt CLI out - you need a very recent version of activeresource (>= 2.2.2) and the 'main' rubygem for the CLI to work. David From lutter at redhat.com Mon Jan 26 21:20:31 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 26 Jan 2009 13:20:31 -0800 Subject: [Ovirt-devel] [PATCH client 01/11] Indent with 2 spaces In-Reply-To: <1233004841-18191-1-git-send-email-lutter@redhat.com> References: <1233004841-18191-1-git-send-email-lutter@redhat.com> Message-ID: <1233004841-18191-2-git-send-email-lutter@redhat.com> Only whitespace changes, no functional changes --- examples/script.rb | 50 ++++++++++---------- lib/ovirt.rb | 126 ++++++++++++++++++++++++++-------------------------- 2 files changed, 88 insertions(+), 88 deletions(-) diff --git a/examples/script.rb b/examples/script.rb index 1485535..f6f6839 100755 --- a/examples/script.rb +++ b/examples/script.rb @@ -10,27 +10,27 @@ require 'optparse' require 'ovirt' def move_random_host(hosts, pool) - host = hosts[rand(hosts.size)] - puts "Move #{host.hostname} to #{pool.name}" - pool.hosts << host - pool.save + host = hosts[rand(hosts.size)] + puts "Move #{host.hostname} to #{pool.name}" + pool.hosts << host + pool.save end def element_path(obj) - "[#{obj.class.element_path(obj.id)}]" + "[#{obj.class.element_path(obj.id)}]" end def print_pool(pool) - puts "\n\nPool #{pool.name}: #{pool.hosts.size} hosts, #{pool.storage_pools.size} storage pools #{element_path(pool)} " - puts "=" * 75 - pool.hosts.each do |h| - printf "%-36s %s\n", h.hostname, element_path(h) - end - pool.storage_pools.each do |sp| - type = sp.nfs? ? "NFS" : "iSCSI" - printf "%-5s %-30s %s\n", type, sp.label, element_path(sp) - end - puts "-" * 75 + puts "\n\nPool #{pool.name}: #{pool.hosts.size} hosts, #{pool.storage_pools.size} storage pools #{element_path(pool)} " + puts "=" * 75 + pool.hosts.each do |h| + printf "%-36s %s\n", h.hostname, element_path(h) + end + pool.storage_pools.each do |sp| + type = sp.nfs? ? "NFS" : "iSCSI" + printf "%-5s %-30s %s\n", type, sp.label, element_path(sp) + end + puts "-" * 75 end # Plumbing so we can find the OVirt server @@ -45,17 +45,17 @@ opts.separator "Global options:" opts.on("-s", "--server=URL", "The OVirt server. Since there is no auth\n" + "#{" "*37}yet, must be the mongrel server port.\n" + "#{" "*37}Overrides env var OVIRT_SERVER") do |val| - OVirt::Base.site = val + OVirt::Base.site = val end opts.order(ARGV) unless OVirt::Base.site - $stderr.puts < defpool.id, - :name => "mypool" } ) + puts "Create mypool" + mypool = OVirt::HardwarePool.create( { :parent_id => defpool.id, + :name => "mypool" } ) end # Move some hosts around puts if defpool.hosts.size > 1 - move_random_host(defpool.hosts, mypool) + move_random_host(defpool.hosts, mypool) elsif mypool.hosts.size > 0 - move_random_host(mypool.hosts, defpool) + move_random_host(mypool.hosts, defpool) end # Delete all storage pools for mypool and add a new one mypool.storage_pools.each do |sp| - puts "Delete storage pool #{sp.id}" - sp.destroy + puts "Delete storage pool #{sp.id}" + sp.destroy end storage_pool = OVirt::StoragePool.create( { :storage_type => "NFS", diff --git a/lib/ovirt.rb b/lib/ovirt.rb index 15dc467..fc3ac2a 100644 --- a/lib/ovirt.rb +++ b/lib/ovirt.rb @@ -18,85 +18,85 @@ class ActiveResource::Connection end module OVirt - class Base < ActiveResource::Base - LOGIN_PATH = "login/login" - - def self.login - response = nil - begin - response = connection.get(prefix + LOGIN_PATH) - rescue ActiveResource::Redirection => e - response = e.response - end - unless connection.session = session_cookie(response) - raise "Authentication failed" - end + class Base < ActiveResource::Base + LOGIN_PATH = "login/login" + + def self.login + response = nil + begin + response = connection.get(prefix + LOGIN_PATH) + rescue ActiveResource::Redirection => e + response = e.response end + unless connection.session = session_cookie(response) + raise "Authentication failed" + end + end - private - def self.session_cookie(response) - if cookies = response.get_fields("Set-Cookie") - cookies.find { |cookie| - cookie.split(";")[0].split("=")[0] == "_ovirt_session_id" - } - end + private + def self.session_cookie(response) + if cookies = response.get_fields("Set-Cookie") + cookies.find { |cookie| + cookie.split(";")[0].split("=")[0] == "_ovirt_session_id" + } end + end + + end + + class HardwarePool < Base + def self.find_by_path(path) + find(:first, :params => { :path => path }) + end + def self.default_pool + find(:first, :params => { :path => "/default" }) end + end - class HardwarePool < Base - def self.find_by_path(path) - find(:first, :params => { :path => path }) - end + class StoragePool < Base + def iscsi? + attributes["type"] == "IscsiStoragePool" + end - def self.default_pool - find(:first, :params => { :path => "/default" }) - end + def nfs? + attributes["type"] == "NfsStoragePool" end - class StoragePool < Base - def iscsi? - attributes["type"] == "IscsiStoragePool" - end - - def nfs? - attributes["type"] == "NfsStoragePool" - end - - def label - if iscsi? - "#{ip_addr}:#{port}:#{target}" - elsif nfs? - "#{ip_addr}:#{export_path}" - else - raise "Unknown type #{attributes["type"]}" - end - end + def label + if iscsi? + "#{ip_addr}:#{port}:#{target}" + elsif nfs? + "#{ip_addr}:#{export_path}" + else + raise "Unknown type #{attributes["type"]}" + end end + end - class IscsiStoragePool < StoragePool - def initialize(attributes = {}) - super(attributes.update( "type" => "IscsiStoragePool" )) - end + class IscsiStoragePool < StoragePool + def initialize(attributes = {}) + super(attributes.update( "type" => "IscsiStoragePool" )) end + end - class NfsStoragePool < StoragePool - def initialize(attributes = {}) - super(attributes.update( "type" => "NfsStoragePool" )) - end + class NfsStoragePool < StoragePool + def initialize(attributes = {}) + super(attributes.update( "type" => "NfsStoragePool" )) end + end - class Host < Base - def self.find_by_uuid(uuid) - find(:first, :params => { :uuid => uuid }) - end + class Host < Base + def self.find_by_uuid(uuid) + find(:first, :params => { :uuid => uuid }) + end - def self.find_by_hostname(hostname) - find(:first, :params => { :hostname => hostname }) - end + def self.find_by_hostname(hostname) + find(:first, :params => { :hostname => hostname }) + end - def hardware_pool - HardwarePool.find(hardware_pool_id) - end + def hardware_pool + HardwarePool.find(hardware_pool_id) end + end end -- 1.6.0.6 From lutter at redhat.com Mon Jan 26 21:20:32 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 26 Jan 2009 13:20:32 -0800 Subject: [Ovirt-devel] [PATCH client 02/11] Fix paths for default pool In-Reply-To: <1233004841-18191-1-git-send-email-lutter@redhat.com> References: <1233004841-18191-1-git-send-email-lutter@redhat.com> Message-ID: <1233004841-18191-3-git-send-email-lutter@redhat.com> --- examples/script.rb | 4 ++-- lib/ovirt.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/script.rb b/examples/script.rb index f6f6839..522c883 100755 --- a/examples/script.rb +++ b/examples/script.rb @@ -69,7 +69,7 @@ defpool = OVirt::HardwarePool.default_pool print_pool(defpool) # Create a new hardware pool -mypool = OVirt::HardwarePool.find_by_path("/default/mypool") +mypool = OVirt::HardwarePool.find_by_path("/root/hardware/default/mypool") unless mypool puts "Create mypool" mypool = OVirt::HardwarePool.create( { :parent_id => defpool.id, @@ -97,5 +97,5 @@ storage_pool = OVirt::StoragePool.create( { :storage_type => "NFS", puts "Created storage pool #{storage_pool.id}" # For some reason, mypool.reload doesn't work here -mypool = OVirt::HardwarePool.find_by_path("/default/mypool") +mypool = OVirt::HardwarePool.find_by_path("/root/hardware/default/mypool") print_pool(mypool) diff --git a/lib/ovirt.rb b/lib/ovirt.rb index fc3ac2a..927efe3 100644 --- a/lib/ovirt.rb +++ b/lib/ovirt.rb @@ -50,7 +50,7 @@ module OVirt end def self.default_pool - find(:first, :params => { :path => "/default" }) + find(:first, :params => { :path => "/root/hardware/default" }) end end -- 1.6.0.6 From lutter at redhat.com Mon Jan 26 21:20:33 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 26 Jan 2009 13:20:33 -0800 Subject: [Ovirt-devel] [PATCH client 03/11] Add StoragePool.find_by_path In-Reply-To: <1233004841-18191-1-git-send-email-lutter@redhat.com> References: <1233004841-18191-1-git-send-email-lutter@redhat.com> Message-ID: <1233004841-18191-4-git-send-email-lutter@redhat.com> --- lib/ovirt.rb | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/lib/ovirt.rb b/lib/ovirt.rb index 927efe3..ea55feb 100644 --- a/lib/ovirt.rb +++ b/lib/ovirt.rb @@ -72,6 +72,12 @@ module OVirt raise "Unknown type #{attributes["type"]}" end end + + def self.find_by_path(path) + hw = HardwarePool.find_by_path(path) + hw.nil? ? nil : hw.storage_pools + end + end class IscsiStoragePool < StoragePool -- 1.6.0.6 From lutter at redhat.com Mon Jan 26 21:20:34 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 26 Jan 2009 13:20:34 -0800 Subject: [Ovirt-devel] [PATCH client 04/11] Add way to format size as human readable In-Reply-To: <1233004841-18191-1-git-send-email-lutter@redhat.com> References: <1233004841-18191-1-git-send-email-lutter@redhat.com> Message-ID: <1233004841-18191-5-git-send-email-lutter@redhat.com> --- lib/ovirt.rb | 31 +++++++++++++++++++++++++++++++ 1 files changed, 31 insertions(+), 0 deletions(-) diff --git a/lib/ovirt.rb b/lib/ovirt.rb index ea55feb..ce51e66 100644 --- a/lib/ovirt.rb +++ b/lib/ovirt.rb @@ -21,6 +21,31 @@ module OVirt class Base < ActiveResource::Base LOGIN_PATH = "login/login" + def to_human_readable(size) + size = size.to_f + unit = "kB" + if size > 512 + size /= 1024 + unit = "MB" + if size > 512 + size /= 1024 + unit = "GB" + if size > 512 + size /= 1024 + unit = "TB" + end + end + end + format "%5.2f %s", size, unit + end + + def self.human_readable(attr) + attr = attr.to_s + define_method("human_readable_#{attr}") do + to_human_readable(attributes[attr]) + end + end + def self.login response = nil begin @@ -92,7 +117,13 @@ module OVirt end end + class StorageVolume < Base + human_readable :size + end + class Host < Base + human_readable :memory + def self.find_by_uuid(uuid) find(:first, :params => { :uuid => uuid }) end -- 1.6.0.6 From lutter at redhat.com Mon Jan 26 21:20:35 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 26 Jan 2009 13:20:35 -0800 Subject: [Ovirt-devel] [PATCH client 05/11] Simple helper to format an error message In-Reply-To: <1233004841-18191-1-git-send-email-lutter@redhat.com> References: <1233004841-18191-1-git-send-email-lutter@redhat.com> Message-ID: <1233004841-18191-6-git-send-email-lutter@redhat.com> --- lib/ovirt.rb | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/lib/ovirt.rb b/lib/ovirt.rb index ce51e66..5ce64d5 100644 --- a/lib/ovirt.rb +++ b/lib/ovirt.rb @@ -136,4 +136,14 @@ module OVirt HardwarePool.find(hardware_pool_id) end end + + def self.format_remote_exception(msg, e) + err = Hash.from_xml(e.response.body)["error"] + unless err.nil? + "#{msg}: #{err}" + else + msg + end + end + end -- 1.6.0.6 From lutter at redhat.com Mon Jan 26 21:20:36 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 26 Jan 2009 13:20:36 -0800 Subject: [Ovirt-devel] [PATCH client 06/11] Command to list nodes in a hardware pool In-Reply-To: <1233004841-18191-1-git-send-email-lutter@redhat.com> References: <1233004841-18191-1-git-send-email-lutter@redhat.com> Message-ID: <1233004841-18191-7-git-send-email-lutter@redhat.com> --- lib/ovirt/command/node.rb | 32 ++++++++++++++++++++++++++++++++ 1 files changed, 32 insertions(+), 0 deletions(-) create mode 100644 lib/ovirt/command/node.rb diff --git a/lib/ovirt/command/node.rb b/lib/ovirt/command/node.rb new file mode 100644 index 0000000..0728616 --- /dev/null +++ b/lib/ovirt/command/node.rb @@ -0,0 +1,32 @@ +module OVirt::Command::Node + + module List + def execute(args) + pool = nil + begin + pool = OVirt::HardwarePool.find_by_path(args["pool"]) + rescue ActiveResource::ResourceNotFound + pool = nil + end + unless pool + puts_error "pool #{args["pool"]} not found" + return + end + puts "Pool #{args["pool"]}: #{pool.hosts.size} host(s)" + puts "=" * 75 + pool.hosts.each do |h| + printf "%-36s %s\n", h.hostname, h.state + if args["verbose"] + printf " uuid : %s\n", h.uuid + printf " enabled : %s\n", h.is_disabled == 0 ? "yes" : "no" + printf " arch : %s\n", h.arch + printf " hypervisor: %s\n", h.hypervisor_type + printf " memory : %s\n", h.human_readable_memory + printf " cpus : %d\n", h.cpus.size + puts "-" * 75 + end + end + end + end + +end -- 1.6.0.6 From lutter at redhat.com Mon Jan 26 21:20:37 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 26 Jan 2009 13:20:37 -0800 Subject: [Ovirt-devel] [PATCH client 07/11] Command to list storage in a hardware pool In-Reply-To: <1233004841-18191-1-git-send-email-lutter@redhat.com> References: <1233004841-18191-1-git-send-email-lutter@redhat.com> Message-ID: <1233004841-18191-8-git-send-email-lutter@redhat.com> --- lib/ovirt/command/storage.rb | 31 +++++++++++++++++++++++++++++++ 1 files changed, 31 insertions(+), 0 deletions(-) create mode 100644 lib/ovirt/command/storage.rb diff --git a/lib/ovirt/command/storage.rb b/lib/ovirt/command/storage.rb new file mode 100644 index 0000000..85577e9 --- /dev/null +++ b/lib/ovirt/command/storage.rb @@ -0,0 +1,31 @@ +module OVirt::Command::Storage + + module List + def execute(args) + begin + pools = OVirt::StoragePool.find_by_path(args["pool"]) + rescue ActiveResource::ResourceNotFound => e + puts_error "pool #{args["pool"]} not found" + return + end + puts "Pool #{args["pool"]}: #{pools.size} storage pool(s)" + puts "=" * 75 + pools.each do |sp| + type = sp.nfs? ? "NFS" : "iSCSI" + printf "%3d %-5s %-30s %s\n", sp.id, type, sp.label, sp.state + if args["verbose"] + sp = OVirt::StoragePool.find(sp.id) + sp.storage_volumes.sort_by { |vol| vol.filename }.each do |vol| + if sp.nfs? + printf " %3d %-30s %s\n", vol.id, vol.filename, vol.human_readable_size + else + printf "FIXME\n" + end + end + end + end + puts "-" * 75 + end + end + +end -- 1.6.0.6 From lutter at redhat.com Mon Jan 26 21:20:38 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 26 Jan 2009 13:20:38 -0800 Subject: [Ovirt-devel] [PATCH client 08/11] Load commands In-Reply-To: <1233004841-18191-1-git-send-email-lutter@redhat.com> References: <1233004841-18191-1-git-send-email-lutter@redhat.com> Message-ID: <1233004841-18191-9-git-send-email-lutter@redhat.com> --- lib/ovirt.rb | 2 ++ lib/ovirt/command.rb | 11 +++++++++++ 2 files changed, 13 insertions(+), 0 deletions(-) create mode 100644 lib/ovirt/command.rb diff --git a/lib/ovirt.rb b/lib/ovirt.rb index 5ce64d5..07a2c3b 100644 --- a/lib/ovirt.rb +++ b/lib/ovirt.rb @@ -147,3 +147,5 @@ module OVirt end end + +require 'ovirt/command' diff --git a/lib/ovirt/command.rb b/lib/ovirt/command.rb new file mode 100644 index 0000000..bf362f0 --- /dev/null +++ b/lib/ovirt/command.rb @@ -0,0 +1,11 @@ +module OVirt::Command + module Base + def puts_error(msg) + $stderr.puts "error: " + msg + exit_status exit_failure + end + end +end + +require 'ovirt/command/node' +require 'ovirt/command/storage' -- 1.6.0.6 From lutter at redhat.com Mon Jan 26 21:20:39 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 26 Jan 2009 13:20:39 -0800 Subject: [Ovirt-devel] [PATCH client 09/11] Command line driver In-Reply-To: <1233004841-18191-1-git-send-email-lutter@redhat.com> References: <1233004841-18191-1-git-send-email-lutter@redhat.com> Message-ID: <1233004841-18191-10-git-send-email-lutter@redhat.com> --- bin/ovirt | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 84 insertions(+), 0 deletions(-) create mode 100755 bin/ovirt diff --git a/bin/ovirt b/bin/ovirt new file mode 100755 index 0000000..42b7871 --- /dev/null +++ b/bin/ovirt @@ -0,0 +1,84 @@ +#! /usr/bin/ruby + +# FIXME: Remove this, only to ease testing +$:.unshift(File::join(File::dirname(File::dirname(__FILE__)), "lib")) + +# The main oVirt command line client. + +require 'rubygems' +require 'ovirt' +require 'main' + +require 'ruby-debug' + +# This is not really how we want the command line, but a temporary +# approximation + +Main { + mixin :command do + include OVirt::Command::Base + + def run + OVirt::Base::site = params["server"].value + OVirt::Base::login + + hash = params.to_options + ["server", "help"].each { |k| hash.delete(k) } + begin + execute(hash) + rescue ActiveResource::TimeoutError + puts_error "request timed out" + rescue ActiveResource::ServerError => e + puts_error "server error: #{e}" + rescue Errno::ECONNREFUSED => e + puts_error "connection refused" + end + end + end + + mixin :pool_argument do + argument("pool") { + description "the pool on which to perform the operation" + required + } + end + + description "Control an oVirt server from a distance" + + option("server=[SERVER]") { + validate { |val| ! val.nil? } + default ENV["OVIRT_SERVER"] + description < References: <1233004841-18191-1-git-send-email-lutter@redhat.com> Message-ID: <1233004841-18191-11-git-send-email-lutter@redhat.com> --- bin/ovirt | 25 +++++++++++++++++++++++++ lib/ovirt/command/storage.rb | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 0 deletions(-) diff --git a/bin/ovirt b/bin/ovirt index 42b7871..8c0bfcf 100755 --- a/bin/ovirt +++ b/bin/ovirt @@ -73,6 +73,31 @@ DESCR include OVirt::Command::Storage::List mixin :command end + + mode 'rm' do + option("pool=POOL", "p") { + description "the ID of the pool" + required + cast :int + } + # --all, --volume and --self are mutually exclusive + + # We identify storage pools and volumes by their ID + # - it would be much nicer if we had some sort of label + # for each, but that requires we change the WUI + option("all", "a") { + description "delete all volumes from the pool" + } + option("volume=VOLUME", "v") { + description "delete the volume with the given id" + cast :int + } + option("self") { + description "delete the pool itself and all its volumes" + } + include OVirt::Command::Storage::Remove + mixin :command + end end def run diff --git a/lib/ovirt/command/storage.rb b/lib/ovirt/command/storage.rb index 85577e9..7cbf78a 100644 --- a/lib/ovirt/command/storage.rb +++ b/lib/ovirt/command/storage.rb @@ -28,4 +28,38 @@ module OVirt::Command::Storage end end + module Remove + def execute(args) + pool, volume, slf, all = args.values_at 'pool', 'volume', 'self', 'all' + + begin + pool = OVirt::StoragePool::find(pool) + rescue ActiveResource::ResourceNotFound + puts_error "error: pool #{pool} not found" + return + end + + begin + if volume + vol = pool.storage_volumes.find { |vol| vol.id == volume } + if vol + vol.destroy + else + $stderr.puts "error: no volume #{volume} in pool #{pool.label}" + exit_status exit_failure + end + elsif all + pool.storage_volumes.each { |vol| vol.destroy } + elsif slf + pool.destroy + else + $stderr.puts "error: you must specify one of --volume, --all, or --self" + exit_status exit_failure + end + rescue ActiveResource::ForbiddenAccess => e + $stderr.puts OVirt::format_remote_exception("Removal denied", e) + exit_status exit_failure + end + end + end end -- 1.6.0.6 From lutter at redhat.com Mon Jan 26 21:20:41 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 26 Jan 2009 13:20:41 -0800 Subject: [Ovirt-devel] [PATCH client 11/11] Update the README In-Reply-To: <1233004841-18191-1-git-send-email-lutter@redhat.com> References: <1233004841-18191-1-git-send-email-lutter@redhat.com> Message-ID: <1233004841-18191-12-git-send-email-lutter@redhat.com> --- README | 42 ++++++++++++++++++++++++++++++++---------- 1 files changed, 32 insertions(+), 10 deletions(-) diff --git a/README b/README index ee1db15..ec874b4 100644 --- a/README +++ b/README @@ -1,17 +1,39 @@ -This is a very simple client library for accessing the OVirt API from Ruby. +ovirt-client is a simple command line interface and client library for the +OVirt Server Suite (http://ovirt.org) -The file examples/script.rb contains a script that shows how this is done -in some detail. +Prerequisites +============= -You must have ActiveResource installed, e.g. with 'yum install -rubygem-activeresource' +Before you can run the 'ovirt' command, you must have the activeresource +and main rubygems installed. The version of activeresource must be at least +2.2.2, earlier versions have bugs that make it unusable. -The server is specified with a URL of the form - http://USER:PASSWORD at HOST/ovirt +The simplest way to install these gems (if they are not packaged natively +for your distribution), is by setting up a separate gem repository: -This requires that the server is configured to allow HTTP authentication, -since there are no mechanisms in the API to forward krb5 tickets. + export GEM_HOME=~/gems # could be anywhere + export GEM_PATH=${GEM_HOME}:/usr/lib/ruby/gems/1.8 + mkdir $GEM_HOME + +and then install whatever you are missing, e.g. + + gem install activeresource + gem install main + +(this will all become much easier once we package the command line client) + +Usage +===== + +Run ./bin/ovirt --help + +API Hints +========= + +The client bits are in lib/ + +Before using any of them, you need to authenticate against the server by +calling -Before calling any other method on the API, you need to call OVirt::Base::site = "http://USER:PASSWORD at HOST/ovirt" OVirt::Base::login -- 1.6.0.6 From lutter at redhat.com Mon Jan 26 21:38:44 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 26 Jan 2009 13:38:44 -0800 Subject: [Ovirt-devel] [PATCH server] Add the installer files as a subpackage of the server package In-Reply-To: <497A2668.5050505@redhat.com> References: <1232488178-25739-1-git-send-email-bkearney@redhat.com> <1232666136.30455.63.camel@localhost.localdomain> <4979C117.800@redhat.com> <497A2668.5050505@redhat.com> Message-ID: <1233005924.19251.10.camel@localhost.localdomain> On Fri, 2009-01-23 at 15:19 -0500, Joey Boggs wrote: > Some comments/questions inline > > Bryan Kearney wrote: > > I will push the change below. Joey... can you pick up these comments > > from David? > > > > -- bk > > > > David Lutterkort wrote: > >> On Tue, 2009-01-20 at 16:49 -0500, Bryan Kearney wrote: > >>> > selinuxdisabled wasn't around in F9 :) makes it easier now in F10 Huh ? It's on my RHEL5 machine (and it's called selinuxenabled) > >>> +if dns_servers == "y" > >>> + host_lookup = Socket.getaddrinfo(ipa_host,nil) > >>> + hostip = host_lookup[1][3] > >>> + if hostip.to_s != mgmt_ipaddr.to_s > >>> + @cli.say("Reverse dns lookup for #{ipa_host} failed, exiting") > >> > >> That's a forward DNS lookup you're doing - but you should also check > >> that looking up mgmt_ipaddr gets you ipa_host. > I can switch this around to do reverse, just didnt catch it when I wrote > it. Or should both foward and reverse be there? Yeah, I'd do both forward and reverse lookup: forward to guard against typos, reverse to guard against broken DNS setup. > >> Strictly speaking, this doesn't have to be on a /24 network; maybe just > >> ask for full IP addresses ? > >> > start/stop would be easy to calculate but wouldn't we need to determine > the subnets as well or are we assuming 1 subnet? Not sure I understand - what I was getting at was that you asked for the first three octets for the network, and then start and stop as the fourth octet. There's no reason to assume that the netmask is always 255.255.255.0 - it could be smaller or larger; in all generality, you'd want to ask for the network in a format like '172.31.0.0/27' (or for network address and mask, '172.31.0.0' and '255.255.255.224' in this example) and full IP addresses for the start and stop address. > >>> + dhcp_domain = prompt_for_answer("Enter the dhcp domain you wish > >>> to use (example: example.com):", :regex => IP_OR_FQDN) > >> > >> Default to dnsdomainname ? (and use that for other places where we ask > >> for a domain) > I don't think we can trust dnsdomainname that's why it's explicity asked > for and hardcoded during the installation? I only meant to use it as a reasonable default when prompting the user - the user definitely needs a way to adjust it during installation. > >>> +# Generate the file and output it. > >>> +FileUtils.mkdir_p("/usr/share/ace/appliances/ovirt") > >>> +config_file = File.new("/usr/share/ace/appliances/ovirt/ovirt.pp", > >>> "w") > >>> +config_file.write(ERB.new(template, 0, "%>").result) > >>> +config_file.close() > >> > >> Why is the file written to /usr/share ? It should go into /var/lib, and > >> ideally would be configurable (so that I can run the installer as an > >> ordinary user) > >> > >> > The ace installer is looking for it in that spot, would a symlink from > /usr/share/ace/appliances/ovirt/ovirt.pp to var/lib/ovirt/ovirt.pp > suffice in this case? No, a symlink wouldn't serve any purpose. It's simply bad practice to write these things into /usr/share. But if ACE looks for it there and nowhere else, it's ok to leave it there (it's unlikely that anybody would run the installer with a readonly /usr/share) David From jguiditt at redhat.com Mon Jan 26 21:56:25 2009 From: jguiditt at redhat.com (Jason Guiditta) Date: Mon, 26 Jan 2009 16:56:25 -0500 Subject: [Ovirt-devel] [PATCH] more permissions validation for non-privileged users. In-Reply-To: <1232665319-23405-1-git-send-email-sseago@redhat.com> References: <1232665319-23405-1-git-send-email-sseago@redhat.com> Message-ID: <1233006985.4232.23.camel@physical.priv.ovirt.org> Overall ACK, there are two minor things I think should be fixed, and a couple thoughts inline. However, any of them could be addressed in a follow-up patch if that works better. -j On Thu, 2009-01-22 at 23:01 +0000, Scott Seago wrote: > Fixed some of the error handling for popup and json ajax responses, and hid action links from non-privileged users where those actions were not appropriate for them. > > Signed-off-by: Scott Seago > --- > src/app/controllers/application.rb | 40 +++++++++++++-------- > src/app/controllers/dashboard_controller.rb | 1 + > src/app/controllers/hardware_controller.rb | 5 +-- > src/app/controllers/host_controller.rb | 9 +++++ > src/app/controllers/network_controller.rb | 25 ++++++++----- > src/app/controllers/pool_controller.rb | 8 ++-- > src/app/controllers/quota_controller.rb | 3 -- > src/app/controllers/resources_controller.rb | 2 - > src/app/controllers/smart_pools_controller.rb | 3 +- > src/app/controllers/storage_controller.rb | 25 ++++--------- > src/app/controllers/vm_controller.rb | 3 -- > src/app/models/smart_pool.rb | 8 +++-- > src/app/views/hardware/show_hosts.rhtml | 24 +++++++----- > src/app/views/hardware/show_storage.rhtml | 28 +++++++++------ > src/app/views/hardware/show_vms.rhtml | 14 +++++-- > src/app/views/layouts/_side_toolbar.rhtml | 4 +- > src/app/views/layouts/_tree.rhtml | 9 +++-- > src/app/views/layouts/popup-error.rhtml | 5 +++ > src/app/views/resources/show_vms.rhtml | 46 ++++++++++++++---------- > src/app/views/user/_grid.rhtml | 11 ++++-- > src/app/views/user/_show.rhtml | 9 +++-- > src/public/stylesheets/ovirt-tree/tree.css | 8 ++--- > 22 files changed, 167 insertions(+), 123 deletions(-) > create mode 100644 src/app/views/layouts/popup-error.rhtml > > diff --git a/src/app/controllers/application.rb b/src/app/controllers/application.rb > index 3f75979..1c3f99e 100644 > --- a/src/app/controllers/application.rb > +++ b/src/app/controllers/application.rb > @@ -82,26 +82,36 @@ class ApplicationController < ActionController::Base > def pre_show > end > > - def authorize_user > - authorize_action(false) > + def authorize_user(msg=nil) > + authorize_action(false,msg) > end > - def authorize_admin > - authorize_action(true) > + def authorize_admin(msg=nil) > + authorize_action(true,msg) > end > - def authorize_action(is_modify_action) > + def authorize_action(is_modify_action, msg=nil) > + msg ||= 'You do not have permission to create or modify this item ' > if @perm_obj > set_perms(@perm_obj) > unless (is_modify_action ? @can_modify : @can_control_vms) > - @redir_obj = @perm_obj unless @redir_obj > - flash[:notice] = 'You do not have permission to create or modify this item ' > - if @json_hash > - @json_hash[:success] = false > - @json_hash[:alert] = flash[:notice] > - render :json => @json_hash > - elsif @redir_controller > - redirect_to :controller => @redir_controller, :action => 'show', :id => @redir_obj > - else > - redirect_to :action => 'show', :id => @redir_obj > + respond_to do |format| > + format.html do > + @title = "Access denied" > + @errmsg = msg > + if params[:ajax] > + render :template => 'layouts/popup-error', :layout => 'tabs-and-content' > + elsif params[:nolayout] > + render :template => 'layouts/popup-error', :layout => 'help-and-content' > + else > + render :template => 'layouts/popup-error', :layout => 'popup' > + end > + end > + format.json do > + @json_hash ||= {} > + @json_hash[:success] = false > + @json_hash[:alert] = msg > + render :json => @json_hash > + end > + format.xml { head :forbidden } > end > false > end > diff --git a/src/app/controllers/dashboard_controller.rb b/src/app/controllers/dashboard_controller.rb > index 00398a5..821fb3f 100644 > --- a/src/app/controllers/dashboard_controller.rb > +++ b/src/app/controllers/dashboard_controller.rb > @@ -29,6 +29,7 @@ class DashboardController < ApplicationController > > def index > @task_types = Task::TASK_TYPES_OPTIONS > + @user = get_login_user > show_tasks > end > > diff --git a/src/app/controllers/hardware_controller.rb b/src/app/controllers/hardware_controller.rb > index 5c14eec..fc16a27 100644 > --- a/src/app/controllers/hardware_controller.rb > +++ b/src/app/controllers/hardware_controller.rb > @@ -29,7 +29,8 @@ class HardwareController < PoolController > > before_filter :pre_modify, :only => [:add_hosts, :move_hosts, > :add_storage, :move_storage, > - :create_storage, :delete_storage] > + :create_storage, :delete_storage, > + :move, :removestorage] > > def index > if params[:path] > @@ -174,7 +175,6 @@ class HardwareController < PoolController > end > > def move > - pre_modify > @resource_type = params[:resource_type] > @id = params[:id] > @pools = HardwarePool.get_default_pool.full_set_nested(:method => :json_hash_element, > @@ -330,7 +330,6 @@ class HardwareController < PoolController > end > > def removestorage > - pre_modify > render :layout => 'popup' > end > > diff --git a/src/app/controllers/host_controller.rb b/src/app/controllers/host_controller.rb > index da630f7..02ad8c9 100644 > --- a/src/app/controllers/host_controller.rb > +++ b/src/app/controllers/host_controller.rb > @@ -31,6 +31,7 @@ class HostController < ApplicationController > end > > before_filter :pre_action, :only => [:host_action, :enable, :disable, :clear_vms, :edit_network] > + before_filter :pre_addhost, :only => [:addhost] > > # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html) > verify :method => [:post, :put], :only => [ :create, :update ], > @@ -85,6 +86,14 @@ class HostController < ApplicationController > render :layout => 'popup' > end > > + def pre_addhost > + @pool = Pool.find(params[:hardware_pool_id]) > + @parent = @pool.parent > + @perm_obj = @pool > + @current_pool_id=@pool.id > + authorize_admin > + end > + > def add_to_smart_pool > @pool = SmartPool.find(params[:smart_pool_id]) > render :layout => 'popup' > diff --git a/src/app/controllers/network_controller.rb b/src/app/controllers/network_controller.rb > index e4faf7b..7328e66 100644 > --- a/src/app/controllers/network_controller.rb > +++ b/src/app/controllers/network_controller.rb > @@ -20,22 +20,24 @@ > class NetworkController < ApplicationController > ########################## Networks related actions > > - def network_permissions > + before_filter :pre_list, :only => [:list] > + > + def authorize_admin > # 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 > + @perm_obj=@default_pool > + super('You do not have permission to access networks') > end > > - def list > + def pre_list > @networks = Network.find(:all) > - network_permissions > + authorize_admin > + end > + > + def list > respond_to do |format| > format.html { > render :layout => 'tabs-and-content' if params[:ajax] > @@ -51,9 +53,12 @@ class NetworkController < ApplicationController > json_list(Network.find(:all), [:id, :name, :type, [:boot_type, :label]]) > end > > + def pre_show > + @network = Network.find(params[:id]) > + authorize_admin > + 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 } > diff --git a/src/app/controllers/pool_controller.rb b/src/app/controllers/pool_controller.rb > index b8d0f10..2809d6d 100644 > --- a/src/app/controllers/pool_controller.rb > +++ b/src/app/controllers/pool_controller.rb > @@ -62,8 +62,10 @@ class PoolController < ApplicationController > end > > def users_json > - json_list(@pool.permissions, > - [:grid_id, :uid, :user_role, :source]) > + attr_list = [] > + attr_list << :grid_id if params[:checkboxes] > + attr_list += [:uid, :user_role, :source] > + json_list(@pool.permissions, attr_list) > end > > def hosts_json(args) > @@ -103,7 +105,6 @@ class PoolController < ApplicationController > def pre_new > @parent = Pool.find(params[:parent_id]) > @perm_obj = @parent > - @redir_controller = @perm_obj.get_controller > @current_pool_id=@parent.id > end > def pre_create > @@ -114,7 +115,6 @@ class PoolController < ApplicationController > @parent = Pool.find(params[:parent_id]) > end > @perm_obj = @parent > - @redir_controller = @perm_obj.get_controller > @current_pool_id=@parent.id > end > def pre_show_pool > diff --git a/src/app/controllers/quota_controller.rb b/src/app/controllers/quota_controller.rb > index 58446d4..17fdc20 100644 > --- a/src/app/controllers/quota_controller.rb > +++ b/src/app/controllers/quota_controller.rb > @@ -84,12 +84,10 @@ class QuotaController < ApplicationController > def pre_new > @quota = Quota.new( { :pool_id => params[:pool_id]}) > @perm_obj = @quota.pool > - @redir_controller = @perm_obj.get_controller > end > def pre_create > @quota = Quota.new(params[:quota]) > @perm_obj = @quota.pool > - @redir_controller = @perm_obj.get_controller > end > def pre_show > @quota = Quota.find(params[:id]) > @@ -98,7 +96,6 @@ class QuotaController < ApplicationController > def pre_edit > @quota = Quota.find(params[:id]) > @perm_obj = @quota.pool > - @redir_controller = @perm_obj.get_controller > end > > end > diff --git a/src/app/controllers/resources_controller.rb b/src/app/controllers/resources_controller.rb > index 3c6e3ee..7bed533 100644 > --- a/src/app/controllers/resources_controller.rb > +++ b/src/app/controllers/resources_controller.rb > @@ -167,7 +167,6 @@ class ResourcesController < PoolController > @pool = VmResourcePool.find(params[:id]) > @parent = @pool.parent > @perm_obj = @pool.parent > - @redir_obj = @pool > @current_pool_id=@pool.id > end > def pre_show > @@ -179,7 +178,6 @@ class ResourcesController < PoolController > @pool = VmResourcePool.find(params[:id]) > @parent = @pool.parent > @perm_obj = @pool > - @redir_obj = @pool > authorize_user > end > > diff --git a/src/app/controllers/smart_pools_controller.rb b/src/app/controllers/smart_pools_controller.rb > index 10dbf9a..cbfbd1c 100644 > --- a/src/app/controllers/smart_pools_controller.rb > +++ b/src/app/controllers/smart_pools_controller.rb > @@ -24,7 +24,7 @@ class SmartPoolsController < PoolController > :add_storage, :remove_storage, > :add_vms, :remove_vms, > :add_pools, :remove_pools, > - :add_items] > + :add_items, :add_pool_dialog] > def show_vms > show > end > @@ -65,7 +65,6 @@ class SmartPoolsController < PoolController > end > > def add_pool_dialog > - pre_modify > @selected_pools = @pool.tagged_pools.collect {|pool| pool.id} > render :layout => 'popup' > end > diff --git a/src/app/controllers/storage_controller.rb b/src/app/controllers/storage_controller.rb > index e4b72f1..2b76f44 100644 > --- a/src/app/controllers/storage_controller.rb > +++ b/src/app/controllers/storage_controller.rb > @@ -26,6 +26,7 @@ class StorageController < ApplicationController > before_filter :pre_new2, :only => [:new2] > before_filter :pre_json, :only => [:storage_volumes_json] > before_filter :pre_create_volume, :only => [:create_volume] > + before_filter :pre_add, :only => [:add, :addstorage] > > def index > list > @@ -258,27 +259,15 @@ class StorageController < ApplicationController > end > end > > - def add_internal > - @hardware_pool = HardwarePool.find(params[:hardware_pool_id]) > - @perm_obj = @hardware_pool > - @redir_controller = @perm_obj.get_controller > - authorize_admin > - @storage_pools = @hardware_pool.storage_volumes > - @storage_types = StoragePool::STORAGE_TYPE_PICKLIST > - end > - Add storage does not render the error popup if I revoke privileges once the form has rendered, but before submit. I think this is because the javascript form handler does not have anything set of on error, only success, so we might need a generic error function that we can call, as this is sure to come up elsewhere. > def addstorage > - add_internal > render :layout => 'popup' > end > > def add > - add_internal > render :layout => false > end > > def new > - add_internal > render :layout => false > end Is this going to replace 'new2'? That one kinda bugs me. > > @@ -396,7 +385,13 @@ class StorageController < ApplicationController > def pre_new > @hardware_pool = HardwarePool.find(params[:hardware_pool_id]) > @perm_obj = @hardware_pool > - @redir_controller = @perm_obj.get_controller > + authorize_admin > + @storage_pools = @hardware_pool.storage_volumes > + @storage_types = StoragePool::STORAGE_TYPE_PICKLIST > + end > + > + def pre_add > + pre_new > end pre_new is only ever called by pre_add, why not just make it one method, like maybe 'pre_modify', or even just pre_add? > > def pre_new2 > @@ -406,7 +401,6 @@ class StorageController < ApplicationController > end > @storage_pool = StoragePool.factory(params[:storage_type], new_params) > @perm_obj = @storage_pool.hardware_pool > - @redir_controller = @storage_pool.hardware_pool.get_controller > authorize_admin > end > def pre_create > @@ -416,12 +410,10 @@ class StorageController < ApplicationController > end > @storage_pool = StoragePool.factory(type, pool) > @perm_obj = @storage_pool.hardware_pool > - @redir_controller = @storage_pool.hardware_pool.get_controller > end > def pre_edit > @storage_pool = StoragePool.find(params[:id]) > @perm_obj = @storage_pool.hardware_pool > - @redir_obj = @storage_pool > end > def pre_create_volume > volume = params[:storage_volume] > @@ -430,7 +422,6 @@ class StorageController < ApplicationController > end > @storage_volume = StorageVolume.factory(type, volume) > @perm_obj = @storage_volume.storage_pool.hardware_pool > - @redir_controller = @storage_volume.storage_pool.hardware_pool.get_controller > authorize_admin > end > def pre_json > diff --git a/src/app/controllers/vm_controller.rb b/src/app/controllers/vm_controller.rb > index 701dea8..56501fd 100644 > --- a/src/app/controllers/vm_controller.rb > +++ b/src/app/controllers/vm_controller.rb > @@ -332,7 +332,6 @@ class VmController < ApplicationController > @vm.vm_resource_pool = @vm_resource_pool > end > @perm_obj = @vm.vm_resource_pool > - @redir_controller = 'resources' > @current_pool_id=@perm_obj.id > _setup_provisioning_options > end > @@ -348,7 +347,6 @@ class VmController < ApplicationController > end > @vm = Vm.new(params[:vm]) > @perm_obj = @vm.vm_resource_pool > - @redir_controller = 'resources' > @current_pool_id=@perm_obj.id > end > def pre_show > @@ -359,7 +357,6 @@ class VmController < ApplicationController > def pre_edit > @vm = Vm.find(params[:id]) > @perm_obj = @vm.vm_resource_pool > - @redir_obj = @vm > @current_pool_id=@perm_obj.id > _setup_provisioning_options > end > diff --git a/src/app/models/smart_pool.rb b/src/app/models/smart_pool.rb > index 772ffef..7df26fa 100644 > --- a/src/app/models/smart_pool.rb > +++ b/src/app/models/smart_pool.rb > @@ -87,9 +87,11 @@ class SmartPool < Pool > user_pools <<[child_pool.name, child_pool.id] > end > else > - pool_element[:children].each do |child_element| > - child_pool = child_element[:obj] > - other_pools << [pool.name + " > " + child_pool.name, child_pool.id] > + if pool_element.has_key?(:children) > + pool_element[:children].each do |child_element| > + child_pool = child_element[:obj] > + other_pools << [pool.name + " > " + child_pool.name, child_pool.id] > + end > end > end > end > diff --git a/src/app/views/hardware/show_hosts.rhtml b/src/app/views/hardware/show_hosts.rhtml > index 2fd29bc..64e5d91 100644 > --- a/src/app/views/hardware/show_hosts.rhtml > +++ b/src/app/views/hardware/show_hosts.rhtml > @@ -1,11 +1,13 @@ >
    > > @@ -111,8 +113,10 @@ > >
    > No hosts found in this pool.

    > - <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>   > - Add first host to this hardware pool > + <%if @can_modify -%> > + <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>   > + Add first host to this hardware pool > + <% end -%> >
    >
    > > diff --git a/src/app/views/hardware/show_storage.rhtml b/src/app/views/hardware/show_storage.rhtml > index 5643c83..5180be6 100644 > --- a/src/app/views/hardware/show_storage.rhtml > +++ b/src/app/views/hardware/show_storage.rhtml > @@ -1,10 +1,12 @@ >
    > >
    > > @@ -141,8 +145,10 @@ ${htmlList(pools)} > >
    > No storage Volumes found in this pool.

    > - <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>   > - Add first storage volume to this hardware pool > + <%if @can_modify -%> > + <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>   > + Add first storage volume to this hardware pool > + <% end -%> >
    > > > diff --git a/src/app/views/hardware/show_vms.rhtml b/src/app/views/hardware/show_vms.rhtml > index 6a8ded5..a829611 100644 > --- a/src/app/views/hardware/show_vms.rhtml > +++ b/src/app/views/hardware/show_vms.rhtml > @@ -1,6 +1,8 @@ >
    > >
    >
      @@ -74,5 +72,5 @@ $('#move_to_new_pool').click(function(){
      -
      + diff --git a/src/app/views/hardware/show_storage.rhtml b/src/app/views/hardware/show_storage.rhtml index 5180be6..07f5625 100644 --- a/src/app/views/hardware/show_storage.rhtml +++ b/src/app/views/hardware/show_storage.rhtml @@ -32,22 +32,22 @@ diff --git a/src/app/views/layouts/_tree.rhtml b/src/app/views/layouts/_tree.rhtml index 350908c..e3a0729 100644 --- a/src/app/views/layouts/_tree.rhtml +++ b/src/app/views/layouts/_tree.rhtml @@ -27,7 +27,7 @@ }); e.preventDefault(); } - }) + }); $('div.nav-networks a').bind('click', function(e){ if(this === e.target){ var myURL = $(this).attr('href'); @@ -41,7 +41,7 @@ }); e.preventDefault(); } - }) + }); $('#nav_tree_form ul.ovirt-tree li').livequery( function(){ $(this) diff --git a/src/app/views/layouts/components/standard_tree.rhtml b/src/app/views/layouts/components/standard_tree.rhtml new file mode 100644 index 0000000..02ea74e --- /dev/null +++ b/src/app/views/layouts/components/standard_tree.rhtml @@ -0,0 +1,202 @@ + + + + + + + <%= yield :title -%> + <%= stylesheet_link_tag 'ovirt-tree/tree' %> + <%= stylesheet_link_tag 'facebox' %> + + <%= javascript_include_tag "jquery-1.2.6.min.js" -%> + <%= javascript_include_tag "jquery.ui-1.5.2/ui/packed/ui.core.packed.js" -%> + <%= javascript_include_tag "test/storage_tree_sample_data.js" -%> + <%= javascript_include_tag "test/smart_nav_sample_data.js" -%> + <%= javascript_include_tag "jquery.form.js" -%> + <%= javascript_include_tag "trimpath-template-1.0.38.js" %> + <%= javascript_include_tag "ovirt.js" %> + <%= javascript_include_tag "ovirt.tree.js" %> + <%= javascript_include_tag "facebox.js" %> + + + + + + + + + + + + + +



      +
      +
        +
        + + +
        +
        + My Name: +
        +
          +
          +
          +
          + + + diff --git a/src/app/views/layouts/components/tree.rhtml b/src/app/views/layouts/components/tree.rhtml index 063a6df..402c6e3 100644 --- a/src/app/views/layouts/components/tree.rhtml +++ b/src/app/views/layouts/components/tree.rhtml @@ -6,10 +6,15 @@ <%= yield :title -%> + <%= stylesheet_link_tag 'ovirt-tree/tree' %> + <%= javascript_include_tag "jquery-1.2.6.min.js" -%> <%= javascript_include_tag "jquery.livequery.min.js" -%> - <%= javascript_include_tag "smart_nav_test_data.js" -%> + <%= javascript_include_tag "jquery.ui-1.5.2/ui/packed/ui.core.packed.js" -%> + <%= javascript_include_tag "test/smart_nav_sample_data.js" -%> <%= javascript_include_tag "jquery.form.js" -%> + <%= javascript_include_tag "trimpath-template-1.0.38.js" %> + <%= javascript_include_tag "ovirt.tree.js" %> <%= javascript_include_tag "ovirt.js" -%> diff --git a/src/app/views/storage/new_volume.rhtml b/src/app/views/storage/new_volume.rhtml index 958c463..2e49d16 100644 --- a/src/app/views/storage/new_volume.rhtml +++ b/src/app/views/storage/new_volume.rhtml @@ -18,20 +18,26 @@ - <%= popup_footer("$('#storage_volume_form').submit()", "New Storage Volume") %> + <% if @return_to_workflow %> + <%# TODO: update this method in application_helper to take an array, so we can include + a callback or trigger to to go previous step in flow. %> + <%= popup_footer("$('#storage_volume_form').submit()", "New Storage Volume") %> + <% else %> + <%= popup_footer("$('#storage_volume_form').submit()", "New Storage Volume") %> + <% end %> diff --git a/src/public/javascripts/ovirt.js b/src/public/javascripts/ovirt.js index fcceccb..19e41c2 100644 --- a/src/public/javascripts/ovirt.js +++ b/src/public/javascripts/ovirt.js @@ -171,7 +171,7 @@ function afterHwPool(response, status){ $tabs.tabs("load",$tabs.data('selected.tabs')); } } - + //FIXME: point all these refs at a widget so we dont need the functions in here processTree(); @@ -320,4 +320,65 @@ function afterNetwork(response, status){ function handleTabsAndContent(data) { $('#side-toolbar').html($(data).find('div.toolbar')); $('#tabs-and-content-container').html($(data).not('div#side-toolbar')); +} + +var VmCreator = { + checkedBoxesFromTree : [], + buildCheckboxList: function(id) { + var rawList = $('#'+ id + ' :checkbox:checked').parent('div'); + if (rawList.length >0) { + rawList.each(function(i) { + VmCreator.checkedBoxesFromTree.push(rawList.get(i).id); + }); + } else { + VmCreator.checkedBoxesFromTree.splice(0); + } + }, + clickCheckboxes: function() { + $.each(VmCreator.checkedBoxesFromTree, function(n, curBox){ + $('#' + curBox).children(':checkbox').click(); + }); + VmCreator.checkedBoxesFromTree = []; + }, + recreateTree: function(o){ + $('#storage_volumes_tree').tree({ + content: o.content, + template: "storage_volumes_template", + selectedNodes: o.selectedNodes, + clickHandler: VmCreator.goToCreateStorageHandler, + channel: 'STORAGE_VOLUME', + refresh: VmCreator.returnToVmForm + }); + }, + goToCreateStorageHandler: function goToCreateStorageHandler(e,elem){ + if ($(e.target).is('img') && $(e.target).parent().is('div')){ + //remove the temp form in case there is one hanging around for some reason + $('temp_create_vm_form').remove(); + VmCreator.buildCheckboxList(elem.element.get(0).id); + var storedOptions = $('#storage_volumes_tree').data('tree').options; + // copy/rename form + $('#window').clone(true).attr({style: 'display:none', id: 'temp_window'}).appendTo('body'); + $('#temp_window #vm_form').attr({id: 'temp_create_vm_form'}); + // continue standard calls to go to next step (create storage) + $('#window').fadeOut('fast'); + $("#window").empty().load($(e.target).siblings('a').attr('href')); + $('#window').fadeIn('fast'); + // empty tree + $('#temp_create_vm_form #storage_volumes_tree').empty(); + // reinitialize tree so it has data and is subscribed + VmCreator.recreateTree(storedOptions); + } + }, + returnToVmForm: function returnToVmForm(e,elem) { + //The item has now been added to the tree, now copy it into a facebox + var storedOptions = $('#storage_volumes_tree').data('tree').options; + $('#window').fadeOut('fast'); + $('#window').remove(); + $('#temp_window').clone(true).attr({style: 'display:block', id: 'window'}) + .appendTo('td.body > div.content').end().remove(); + $('#window #temp_create_vm_form').attr({id: 'vm_form'}); + $('#window').fadeIn('fast'); + VmCreator.recreateTree(storedOptions); + VmCreator.clickCheckboxes(); + } } \ No newline at end of file diff --git a/src/public/javascripts/ovirt.tree.js b/src/public/javascripts/ovirt.tree.js index 77d6c55..48f529c 100644 --- a/src/public/javascripts/ovirt.tree.js +++ b/src/public/javascripts/ovirt.tree.js @@ -75,60 +75,149 @@ function processChildren(list, templateObj){ this.setData('template', TrimPath.parseDOMTemplate(this.getData('template'))); }, init: function() { + var self = this, o = this.options; this.setTemplate(this.getTemplate()); - this.element.html(this.getTemplate().process(this.getData('content'))); - var self = this; + this.populate(); this.element - .find('li:has(ul)') - .children('span.hitarea') - .click(function(event){ - if (this == event.target) { - if($(this).siblings('ul').size() >0) { - if(self.getData('toggle') === 'toggle') { - self.toggle(event, this); //we need 'this' so we have the right element to toggle - } else { - self.element.triggerHandler('toggle',[event,this],self.getData('toggle')); - } - } - } + .bind('click', function(event){ + self.clickHandler(event, self); + if(self.getData('toggle') === 'toggle') { + self.toggle(event, this); + } else { + self.element.triggerHandler('toggle',[event,this],self.getData('toggle')); + } }); - this.element - .find('li > div') - .filter(':not(.unclickable)') - .bind('click', function(event) { - if (this == event.target) { - if(self.getData('clickHandler') === 'clickHandler') { - self.clickHandler(event, this); //we need 'this' so we have the right element to add click behavior to - } else { - self.element.triggerHandler('clickHandler',[event,this],self.getData('clickHandler')); - } - } + o.selectedNodes !== undefined? this.openToSelected() :o.selectedNodes=[]; + o.channel !== undefined? this.subscribe(o.channel): o.channel = ''; + if (o.cacheContent === true) this.buildLookup(); + }, + populate: function() { + var contentWithId = this.getData('content'); + contentWithId.id = this.element.get(0).id; + this.element.html(this.getTemplate().process(contentWithId)); + }, + buildLookup: function() { + this.setData('lookupList', this.walkTree(this.getData('content').pools, [], this)); + }, + walkTree: function(list, lookup, self) { + $.each(list, function(n,obj){ + lookup.push(obj); + if (obj.children.length > 0) self.walkTree(obj.children, lookup, self); }); - this.openToSelected(self); + return lookup; + }, + subscribe: function subscribe(channel) { + var self = this; + this.element.bind(channel, function(e,data){self.refresh(e,data);}); }, toggle: function(e, elem) { - $(elem) + if ($(e.target).is('span.hitarea')){ + $(e.target) .toggleClass('expanded') .toggleClass('expandable') .siblings('ul').slideToggle("normal"); + if ($(e.target).hasClass('expanded')) { + this.setSelectedNode(this.chop(e.target), true); + } else { + this.setSelectedNode(this.chop(e.target), false); + } + } + }, + chop: function(elem) { + var id = $(elem).siblings('div').get(0).id; + return id.substring(id.indexOf('-') +1); + }, + clickHandler: function(e,elem) { //TODO: make this a default impl if needed. + this.options.clickHandler !== undefined? this.element.triggerHandler('clickHandler',[e,this],this.getData('clickHandler')): null; + if ($(e.target).is('div') && $(e.target).parent().is('li')){} + }, + setSelectedNode: function(id, isOpen) { + if (isOpen) { + if($.inArray(id,this.getData('selectedNodes')) == -1){ + this.setData(this.getData('selectedNodes').push(id)); + } + } else { + if($.inArray(id,this.getData('selectedNodes')) != -1){ + this.setData(this.getData('selectedNodes').splice(this.getData('selectedNodes').indexOf(id),1)); + } + } + }, + openToSelected: function() { + for (var i = 0; i < this.getData('selectedNodes').length; i++){ + this.toggle($.event.fix({type: 'toggle', + target: this.element.find('#' +this.element.get(0).id + '-' + this.getData('selectedNodes')[i]).siblings('span').get(0)}) + , this); + } + }, + refresh: function(e, list) { + //NOTE: The widget expects the convention used elsewhere of {blah}-{ui_object} + //(where {blah} is the id of the container element, see above for an example soon), + //since there may be 2 items with the same db id. + var self = this; + list = $.makeArray(list); + $.each(list, function(n,data){ + switch(data.state) { + case 'deleted': { + self._delete(data); + break; + } + case 'changed': { + self._update(data); + break; + } + default: { + self._add(data); + break; + } + } + }); + self.options.refresh !== undefined? self.element.triggerHandler('refresh',[e,list],self.getData('refresh')): null; }, - clickHandler: function(e,elem) { - // make this a default impl if needed. + //methods meant to be called internally by widget + _add: function(data){ + var myLookupList = this.getData('lookupList'); + if (data.ui_parent !==null) { + var matchedItems = $.grep(myLookupList,function(value) {return value.ui_object == data.ui_parent;}); + var self = this; + $.each(matchedItems, function(n,obj){ + var existingObj = []; + if(obj.children.length >0) { + existingObj = $.grep(obj.children,function(value) {return value.ui_object == data.ui_object;}); + } + if (existingObj.length === 0){ + obj.children.push(data); + myLookupList.push(data); + self._addDomElem(data); + } else {} + }); + } else {myLookupList.push(data);} }, - openToSelected: function(self) { - //find 'selected' items and open tree accordingly. This may need to have a - //marker of some sort passed in since different trees may have different needs. + _delete: function(data){}, //TODO: implement + _update: function(data) {}, //TODO: implement + _addDomElem: function(data) { + var dataToInsert = this.getTemplate().process({"pools":[data], "id":this.element.get(0).id}); + if (data.ui_parent) { + var searchString = '#' + this.element.get(0).id + '-' + data.ui_parent; + var parentElem = this.element.find(searchString).siblings('ul'); + if (parentElem.size() === 0) { + this.element.find(searchString).parent().append('
            ' + dataToInsert + '
          '); + this.element.find(searchString).siblings('span').addClass('expanded'); + } else { + parentElem.append(dataToInsert); + } + } else { + this.element.append(dataToInsert); + } }, - off: function() { - this.element.css({background: 'none'}); - this.destroy(); // use the predefined function - } + _deleteDomElem: function(data) {}, //TODO: implement + _updateDomElem: function(data) {} //TODO: implement }; $.yi = $.yi || {}; // create the namespace $.widget("yi.tree", Tree); $.yi.tree.defaults = { template: 'tree_template', toggle: 'toggle', - clickHandler: 'clickHandler' + clickHandler: 'clickHandler', + cacheContent: true }; })(jQuery); \ No newline at end of file diff --git a/src/public/javascripts/smart_nav_test_data.js b/src/public/javascripts/smart_nav_test_data.js deleted file mode 100644 index 43e7dbc..0000000 --- a/src/public/javascripts/smart_nav_test_data.js +++ /dev/null @@ -1,151 +0,0 @@ -var pools3 = { - "deleted" : {}, - "pools" :[ - { "name": "default", - "text": "default", - "children": - [{ "name": "Engineering", - "text": "Engineering", - "children": - [{ "name": "Development", - "text": "Development", - "children": - [{ "name": "Project X", - "text": "Project X", - "id": 19, - "type": "VmResourcePool"}, - { "name": "Project Y", - "text": "Project Y", - "id": 20, - "type": "VmResourcePool"}], - "id": 9, - "type": "HardwarePool"}, - { "name": "QA", - "text": "QA", - "children": - [{ "name": "Bob's Team", - "text": "Bob's Team", - "children": - [{ "name": "Bob's VMs", - "text": "Bob's VMs", - "id": 21, - "type": "VmResourcePool"}], - "id": 17, - "type": "HardwarePool"}, - { "name": "Jim's Team", - "text": "Jim's Team", - "children": - [{ "name": "Jim's VMs", - "text": "Jim's VMs", - "id": 22, - "type": "VmResourcePool"}], - "id": 18, - "type": "HardwarePool"}, - { "name": "Sally's Team", - "text": "Sally's Team", - "children": - [{ "name": "Sally's VMs", - "text": "Sally's VMs", - "id": 33, - "type": "VmResourcePool"}], - "id": 32, - "type": "HardwarePool"}], - "id": 10, - "type": "HardwarePool"}, - { "name": "Stage", - "text": "Stage", - "children": - [{ "name": "stage1", - "text": "stage1", - "id": 45, - "type": "HardwarePool"}, - { "name": "stage2", - "text": "stage2", - "id": 46, - "type": "HardwarePool"}], - "id": 44, - "type": "HardwarePool"}], - "id": 5, - "type": "HardwarePool"}, - { "name": "Finance", - "text": "Finance", - "children": - [{ "name": "Payroll", - "text": "Payroll", - "children": - [{ "name": "Payroll VMs", - "text": "Payroll VMs", - "id": 23, - "type": "VmResourcePool"}], - "id": 11, - "type": "HardwarePool"}, - { "name": "Accts. Receivable", - "text": "Accts. Receivable", - "children": - [{ "name": "our VMs", - "text": "our VMs", - "id": 24, - "type": "VmResourcePool"}], - "id": 12, - "type": "HardwarePool"}], - "id": 6, - "type": "HardwarePool"}, - { "name": "HR", - "text": "HR", - "children": - [{ "name": "Hiring Team", - "text": "Hiring Team", - "id": 13, - "type": "HardwarePool"}, - { "name": "Benefits", - "text": "Benefits", - "id": 14, - "type": "HardwarePool"}], - "id": 7, - "type": "HardwarePool"}, - { "name": "External (DMZ)", - "text": "External (DMZ)", - "children": - [{ "name": "VMs", - "text": "VMs", - "id": 25, - "type": "VmResourcePool"}, - { "name": "DB Cluster", - "text": "DB Cluster", - "children": - [{ "name": "VMs", - "text": "VMs", - "id": 27, - "type": "VmResourcePool"}], - "id": 26, - "type": "HardwarePool"}], - "id": 8, - "type": "HardwarePool"}], - "id": 1, - "type": "HardwarePool"}], -"smart_pools":[{ "name": "ovirtadmin", - "text": "ovirtadmin", - "children": - [{ "name": "not so smart", - "text": "not so smart", - "id": 39, - "type": "SmartPool"}, - { "name": "a little smarter", - "text": "a little smarter", - "id": 40, - "type": "SmartPool"}, - { "name": "arrrrr", - "text": "arrrrr", - "id": 41, - "type": "SmartPool"}, - { "name": "huh?", - "text": "huh?", - "id": 42, - "type": "SmartPool"}, - { "name": "booya", - "text": "booya", - "id": 43, - "type": "SmartPool"}], - "id": 37, - "type": "DirectoryPool"}] -} \ No newline at end of file diff --git a/src/public/javascripts/test/smart_nav_sample_data.js b/src/public/javascripts/test/smart_nav_sample_data.js new file mode 100644 index 0000000..43e7dbc --- /dev/null +++ b/src/public/javascripts/test/smart_nav_sample_data.js @@ -0,0 +1,151 @@ +var pools3 = { + "deleted" : {}, + "pools" :[ + { "name": "default", + "text": "default", + "children": + [{ "name": "Engineering", + "text": "Engineering", + "children": + [{ "name": "Development", + "text": "Development", + "children": + [{ "name": "Project X", + "text": "Project X", + "id": 19, + "type": "VmResourcePool"}, + { "name": "Project Y", + "text": "Project Y", + "id": 20, + "type": "VmResourcePool"}], + "id": 9, + "type": "HardwarePool"}, + { "name": "QA", + "text": "QA", + "children": + [{ "name": "Bob's Team", + "text": "Bob's Team", + "children": + [{ "name": "Bob's VMs", + "text": "Bob's VMs", + "id": 21, + "type": "VmResourcePool"}], + "id": 17, + "type": "HardwarePool"}, + { "name": "Jim's Team", + "text": "Jim's Team", + "children": + [{ "name": "Jim's VMs", + "text": "Jim's VMs", + "id": 22, + "type": "VmResourcePool"}], + "id": 18, + "type": "HardwarePool"}, + { "name": "Sally's Team", + "text": "Sally's Team", + "children": + [{ "name": "Sally's VMs", + "text": "Sally's VMs", + "id": 33, + "type": "VmResourcePool"}], + "id": 32, + "type": "HardwarePool"}], + "id": 10, + "type": "HardwarePool"}, + { "name": "Stage", + "text": "Stage", + "children": + [{ "name": "stage1", + "text": "stage1", + "id": 45, + "type": "HardwarePool"}, + { "name": "stage2", + "text": "stage2", + "id": 46, + "type": "HardwarePool"}], + "id": 44, + "type": "HardwarePool"}], + "id": 5, + "type": "HardwarePool"}, + { "name": "Finance", + "text": "Finance", + "children": + [{ "name": "Payroll", + "text": "Payroll", + "children": + [{ "name": "Payroll VMs", + "text": "Payroll VMs", + "id": 23, + "type": "VmResourcePool"}], + "id": 11, + "type": "HardwarePool"}, + { "name": "Accts. Receivable", + "text": "Accts. Receivable", + "children": + [{ "name": "our VMs", + "text": "our VMs", + "id": 24, + "type": "VmResourcePool"}], + "id": 12, + "type": "HardwarePool"}], + "id": 6, + "type": "HardwarePool"}, + { "name": "HR", + "text": "HR", + "children": + [{ "name": "Hiring Team", + "text": "Hiring Team", + "id": 13, + "type": "HardwarePool"}, + { "name": "Benefits", + "text": "Benefits", + "id": 14, + "type": "HardwarePool"}], + "id": 7, + "type": "HardwarePool"}, + { "name": "External (DMZ)", + "text": "External (DMZ)", + "children": + [{ "name": "VMs", + "text": "VMs", + "id": 25, + "type": "VmResourcePool"}, + { "name": "DB Cluster", + "text": "DB Cluster", + "children": + [{ "name": "VMs", + "text": "VMs", + "id": 27, + "type": "VmResourcePool"}], + "id": 26, + "type": "HardwarePool"}], + "id": 8, + "type": "HardwarePool"}], + "id": 1, + "type": "HardwarePool"}], +"smart_pools":[{ "name": "ovirtadmin", + "text": "ovirtadmin", + "children": + [{ "name": "not so smart", + "text": "not so smart", + "id": 39, + "type": "SmartPool"}, + { "name": "a little smarter", + "text": "a little smarter", + "id": 40, + "type": "SmartPool"}, + { "name": "arrrrr", + "text": "arrrrr", + "id": 41, + "type": "SmartPool"}, + { "name": "huh?", + "text": "huh?", + "id": 42, + "type": "SmartPool"}, + { "name": "booya", + "text": "booya", + "id": 43, + "type": "SmartPool"}], + "id": 37, + "type": "DirectoryPool"}] +} \ No newline at end of file diff --git a/src/public/javascripts/test/storage_tree_sample_data.js b/src/public/javascripts/test/storage_tree_sample_data.js new file mode 100644 index 0000000..f798a45 --- /dev/null +++ b/src/public/javascripts/test/storage_tree_sample_data.js @@ -0,0 +1,68 @@ +var storage_pools = {"pools": +[ + { + "selected":false, + "name":"iSCSI: 192.168.50.2:ovirtpriv:storage", + "available":false, + "children": + [ + { + "selected":false, + "name":"iSCSI: 192.168.50.2:ovirtpriv:storage:lun-2", + "available":true, + "children":[], + "create_volume":true, + "text":"iSCSI: 192.168.50.2:ovirtpriv:storage:lun-2", + "id":5, + "type":"IscsiStorageVolume", + "ui_object": "IscsiStorageVolume_5", + "ui_parent": "IscsiStoragePool_2" + }, + + { + "selected":false, + "name":"iSCSI: 192.168.50.2:ovirtpriv:storage:lun-3", + "available":true, + "children":[], + "create_volume":true, + "text":"iSCSI: 192.168.50.2:ovirtpriv:storage:lun-3", + "id":4, + "type":"IscsiStorageVolume", + "ui_object": "IscsiStorageVolume_4", + "ui_parent": "IscsiStoragePool_2" + } + ], + "create_volume":false, + "text":"iSCSI: 192.168.50.2:ovirtpriv:storage", + "id":2, + "type":"IscsiStoragePool", + "ui_object": "IscsiStoragePool_2", + "ui_parent": null + }, + + { + "selected":false, + "name":"iSCSI: 192.68.60.2:/fred", + "available":false, + "children":[], + "create_volume":false, + "text":"iSCSI: 192.68.60.2:/fred", + "id":7, + "type":"IscsiStoragePool", + "ui_object": "IscsiStoragePool_7", + "ui_parent": null + }, + + { + "selected":false, + "name":"iSCSI: 192.168.60.4:/mo", + "available":false, + "children":[], + "create_volume":false, + "text":"iSCSI: 192.168.60.4:/mo", + "id":6, + "type":"IscsiStoragePool", + "ui_object": "IscsiStoragePool_6", + "ui_parent": null + } +]} \ No newline at end of file diff --git a/src/test/fixtures/storage_volumes.yml b/src/test/fixtures/storage_volumes.yml index a3711bf..8e5b60a 100644 --- a/src/test/fixtures/storage_volumes.yml +++ b/src/test/fixtures/storage_volumes.yml @@ -19,6 +19,16 @@ ovirtpriv_storage_lun_3: storage_pool: corp_com_ovirtpriv_storage type: IscsiStorageVolume state: available + lvm_pool_id: corp_com_dev_lvm_ovirtlvm +ovirtpriv_lvm_volume_1: + size: 1048576 + path: /dev/disk/by-id/scsi-S_beaf321013 + storage_pool: corp_com_dev_lvm_ovirtlvm + type: LvmStorageVolume + state: available + lv_owner_perms: 0744 + lv_group_perms: 0744 + lv_mode_perms: 0744 ovirt_nfs_disk_1: size: 3145728 path: /mnt/a3q49Sj4Sfmae1bV/disk1.dsk diff --git a/src/test/unit/storage_volume_test.rb b/src/test/unit/storage_volume_test.rb index 3978685..16be0fb 100644 --- a/src/test/unit/storage_volume_test.rb +++ b/src/test/unit/storage_volume_test.rb @@ -1,4 +1,4 @@ -# +# # Copyright (C) 2008 Red Hat, Inc. # Written by Scott Seago # @@ -112,4 +112,23 @@ class StorageVolumeTest < Test::Unit::TestCase assert_equal @storage_volume.movable?, false, "Storage volume w/ vms should not be movable" end + def test_create_valid_lvm_volume +# FIXME: Write this test, using similer steps as in storage_controller#new_volume. +# Also add validation to model to make sure the lvm volume's lvm pool has a source volume + end + def test_return_correct_lvm_ui_parent + #test lvm volume values + assert_equal storage_volumes(:ovirtpriv_storage_lun_3).type.to_s + '_' +storage_volumes(:ovirtpriv_storage_lun_3).id.to_s, + storage_volumes(:ovirtpriv_lvm_volume_1).ui_parent, + 'Incorrect ui parent returned' + #test isci volume values + assert_equal storage_volumes(:corp_com_ovirtpriv_storage).type.to_s + '_' +storage_volumes(:corp_com_ovirtpriv_storage).id.to_s, + storage_volumes(:ovirtpriv_storage_lun_3).ui_parent, + 'Incorrect ui parent returned' + #test nfs volume values + assert_equal storage_volumes(:corp_com_nfs_ovirtnfs).type.to_s + '_' +storage_volumes(:corp_com_nfs_ovirtnfs).id.to_s, + storage_volumes(:ovirt_nfs_disk_3).ui_parent, + 'Incorrect ui parent returned' + end + end -- 1.5.6.6 From sseago at redhat.com Tue Jan 27 21:58:51 2009 From: sseago at redhat.com (Scott Seago) Date: Tue, 27 Jan 2009 16:58:51 -0500 Subject: [Ovirt-devel] [PATCH server] Create VM/Storage integration w/ tree widget enhancements In-Reply-To: <1233088951-23275-1-git-send-email-jguiditt@redhat.com> References: <1233083398.4836.2.camel@physical.priv.ovirt.org> <1233088951-23275-1-git-send-email-jguiditt@redhat.com> Message-ID: <497F839B.3020105@redhat.com> Jason Guiditta wrote: > == Create VM/ Storage Flow == > * Can add as many storage volumes as you need to, flow allows you to > return to secondary form w/o limits. > * Create VM form, along with its state and state of tree are stored in > a temporary area and returned after create storage via pub/sub. > > == Tree enhancements == > * Now stores state of selected (open) nodes, so if we have a need to > reload or generate a new tree with certain nodes open, we now can. > * Has ability to subscribe to messages via the 'channel' option > * Added refresh method, which can be triggered by a message or fired > manually. > * Refresh adds newly returned items to tree, stubs in place for update > and delete. > * Added lookup object with references to all items in the tree to > allow for easy recreation of tree w/o another call to server. > * Added ui_parent and ui_object references (generated in model via a > convenience method) to simplify finding nodes to update/add/delete. > * Changed click behavior to use event delegation, which means we no > longer need to use livequery, which scans the dom for changes. Event > delegation is much faster and cleaner (can remove livequery entirely > once all trees use widget). > > == Widget tests/files == > * Adds the standard_tree (actual widget vs nav) test harness > * Cleans up the tree.rhtml to account for some previous restructuring > * Moves sample json data into a 'test' subfolder. > > I am looking into some more proper javascript testing systems, so this > will undoubtedly be changing again in the near future. > OK this works fine for me now except for the cacheContent issue we both ran into. ACK assuming you add that fix to the patch too. Scott From mmorsi at redhat.com Tue Jan 27 22:32:01 2009 From: mmorsi at redhat.com (Mohammed Morsi) Date: Tue, 27 Jan 2009 17:32:01 -0500 Subject: [Ovirt-devel] [PATCH server] allow admin to setup iptables port forwarding on server for a vm's vnc port In-Reply-To: <1233095522-11004-1-git-send-email-mmorsi@redhat.com> References: <1233095522-11004-1-git-send-email-mmorsi@redhat.com> Message-ID: <1233095522-11004-2-git-send-email-mmorsi@redhat.com> --- src/app/controllers/vm_controller.rb | 2 + src/app/models/vm.rb | 4 + src/app/views/vm/_form.rhtml | 15 ++++ src/app/views/vm/show.rhtml | 4 + src/db/migrate/034_add_vm_vnc.rb | 30 +++++++ src/task-omatic/taskomatic.rb | 4 + src/task-omatic/vnc.rb | 140 ++++++++++++++++++++++++++++++++++ 7 files changed, 199 insertions(+), 0 deletions(-) create mode 100644 src/db/migrate/034_add_vm_vnc.rb create mode 100644 src/task-omatic/vnc.rb diff --git a/src/app/controllers/vm_controller.rb b/src/app/controllers/vm_controller.rb index 56501fd..8e1cbee 100644 --- a/src/app/controllers/vm_controller.rb +++ b/src/app/controllers/vm_controller.rb @@ -116,6 +116,7 @@ class VmController < ApplicationController new_storage_ids = new_storage_ids.sort.collect {|x| x.to_i } needs_restart = true unless current_storage_ids == new_storage_ids end + params[:vm][:forward_vnc] = params[:forward_vnc] params[:vm][:needs_restart] = 1 if needs_restart @vm.update_attributes!(params[:vm]) _setup_vm_provision(params) @@ -345,6 +346,7 @@ class VmController < ApplicationController vm_resource_pool.create_with_parent(hardware_pool) params[:vm][:vm_resource_pool_id] = vm_resource_pool.id end + params[:vm][:forward_vnc] = params[:forward_vnc] @vm = Vm.new(params[:vm]) @perm_obj = @vm.vm_resource_pool @current_pool_id=@perm_obj.id diff --git a/src/app/models/vm.rb b/src/app/models/vm.rb index bf99e2d..15af463 100644 --- a/src/app/models/vm.rb +++ b/src/app/models/vm.rb @@ -40,6 +40,10 @@ class Vm < ActiveRecord::Base validates_format_of :uuid, :with => %r([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}) + validates_numericality_of :forward_vnc_port, + :greater_than => 0, + :if => Proc.new { |vm| vm.forward_vnc } + validates_numericality_of :needs_restart, :greater_than_or_equal_to => 0, :less_than_or_equal_to => 1, diff --git a/src/app/views/vm/_form.rhtml b/src/app/views/vm/_form.rhtml index 523e81e..486798f 100644 --- a/src/app/views/vm/_form.rhtml +++ b/src/app/views/vm/_form.rhtml @@ -51,6 +51,21 @@
          +
          + <%= check_box_tag_with_label "Forward vm's vnc port locally", "forward_vnc", 1, @vm.forward_vnc %> +
          +
          + <%= text_field_with_label "", "vm", "forward_vnc_port", { :style=>"width: 80px;", :size => 7, :disabled => ! @vm.forward_vnc } %> +
          +
          +
          + + + <%= check_box_tag_with_label "Start VM Now? (pending current resource availability)", "start_now", nil if create or @vm.state == Vm::STATE_STOPPED %> <%= check_box_tag_with_label "Restart VM Now? (pending current resource availability)", "restart_now", nil if @vm.state == Vm::STATE_RUNNING %> diff --git a/src/app/views/vm/show.rhtml b/src/app/views/vm/show.rhtml index f361131..add29b4 100644 --- a/src/app/views/vm/show.rhtml +++ b/src/app/views/vm/show.rhtml @@ -88,6 +88,7 @@
          Uuid:
          + <%= @vm.forward_vnc ? "VNC uri:
          " : "" %> Num vcpus allocated:
          Num vcpus used:
          Memory allocated:
          @@ -100,6 +101,9 @@
          <%=h @vm.uuid %>
          + <%= url = request.url + url = request.url[0..(url.index('/', 8) - 1)] + ":" + @vm.forward_vnc_port.to_s + @vm.forward_vnc ? (url + "
          ") : "" %> <%=h @vm.num_vcpus_allocated %>
          <%=h @vm.num_vcpus_used %>
          <%=h @vm.memory_allocated_in_mb %> MB
          diff --git a/src/db/migrate/034_add_vm_vnc.rb b/src/db/migrate/034_add_vm_vnc.rb new file mode 100644 index 0000000..a93e457 --- /dev/null +++ b/src/db/migrate/034_add_vm_vnc.rb @@ -0,0 +1,30 @@ +# Copyright (C) 2008 Red Hat, Inc. +# Written by Mohammed Morsi +# +# 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 AddVmVnc < ActiveRecord::Migration + def self.up + add_column :vms, :forward_vnc, :bool, :default => false + add_column :vms, :forward_vnc_port, :int, :default => 0 + end + + def self.down + drop_column :vms, :forward_vnc + drop_column :vms, :forward_vnc_port + end +end + diff --git a/src/task-omatic/taskomatic.rb b/src/task-omatic/taskomatic.rb index bcb9bd3..dca6fb7 100755 --- a/src/task-omatic/taskomatic.rb +++ b/src/task-omatic/taskomatic.rb @@ -32,6 +32,7 @@ include Daemonize require 'task_vm' require 'task_storage' +require 'vnc' class TaskOmatic @@ -232,6 +233,8 @@ class TaskOmatic raise "Error destroying VM: #{result.text}" unless result.status == 0 end + closeVmVncPort(vm) + # undefine can fail, for instance, if we live migrated from A -> B, and # then we are shutting down the VM on B (because it only has "transient" # XML). Therefore, just ignore undefine errors so we do the rest @@ -303,6 +306,7 @@ class TaskOmatic # of places so you'll see a lot of .reloads. db_vm.reload set_vm_vnc_port(db_vm, result.description) unless result.status != 0 + forwardVmVncPort(db_vm) # This information is not available via the libvirt interface. db_vm.memory_used = db_vm.memory_allocated diff --git a/src/task-omatic/vnc.rb b/src/task-omatic/vnc.rb new file mode 100644 index 0000000..3eb0ca6 --- /dev/null +++ b/src/task-omatic/vnc.rb @@ -0,0 +1,140 @@ +# Copyright (C) 2008 Red Hat, Inc. +# Written by Mohammed Morsi +# +# 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. + +# TODO no ruby/libiptc wrapper exists, when +# it does replace iptables command w/ calls to it + at iptables_cmd='/sbin/iptables ' + +# TODO replace this w/ dnsruby inclusion / call + at dns_lookup_cmd='/usr/bin/dig' + + at ip_forward_command='echo 1 > /proc/sys/net/ipv4/ip_forward' + + at vnc_debug = false + +# TODO can this be retreived in any way +# since machine will have both external +# and internal network interface + at local_ip = '192.168.50.2' + +############################## 'private' methods + +def _debug(msg) + puts "\n" + msg + "\n" if @vnc_debug +end + +def _findVmHostIp(vm) + cmdout='/tmp/ovirtvnc' + vm.forward_vnc_port.to_s + cmd=@dns_lookup_cmd + ' ' + vm.host.hostname + + ' +noall +answer +short > ' + cmdout + + system(cmd) + + result = File.read(cmdout).rstrip + _debug( "vm host hostname resolved to " + result.to_s ) + return result +end + +def _vncPortOpen?(port) + cmdout='/tmp/ovirtvnc' + port.to_s + cmd=@iptables_cmd + ' -t nat -nL | grep ' + port.to_s + + ' > ' + cmdout + _debug("vncPortOpen? iptables command: " + cmd + + " cmdout " + cmdout) + + system(cmd) + + return File.size(cmdout) != 0 +end + +def _forwardRules(vm) + ip = _findVmHostIp(vm) + return " -d " + ip + " -p tcp --dport " + vm.vnc_port.to_s + " -j ACCEPT", + " -s " + ip + " -p tcp --sport " + vm.vnc_port.to_s + " -j ACCEPT" +end + +def _natRules(vm) + ip = _findVmHostIp(vm) + + # TODO should a "-d external_server_ip" be added to DNAT? + return " -p tcp --dport " + vm.forward_vnc_port.to_s + " -j DNAT --to " + ip + ":" + vm.vnc_port.to_s, + " -d " + ip + " -p tcp --dport " + vm.vnc_port.to_s + " -j SNAT --to " + @local_ip +end + +############################## 'public' methods + + +def forwardVmVncPort(vm) + return unless vm.forward_vnc + unless vm.forward_vnc_port > 0 + raise "Must specify valid port to forward " + vm.forward_vnc_port.to_s + end + + if _vncPortOpen?(vm.forward_vnc_port) + raise "Port already open " + vm.forward_vnc_port.to_s + end + + forward_rule1, forward_rule2 = _forwardRules(vm) + forward_rule1 = @iptables_cmd + " -A FORWARD " + forward_rule1 + forward_rule2 = @iptables_cmd + " -A FORWARD " + forward_rule2 + + prerouting_rule, postrouting_rule = _natRules(vm) + prerouting_rule = @iptables_cmd + " -t nat -A PREROUTING " + prerouting_rule + postrouting_rule = @iptables_cmd + " -t nat -A POSTROUTING " + postrouting_rule + + _debug(" open\n forward rule 1: " + forward_rule1 + + "\n forward_rule 2: " + forward_rule2 + + "\n prerouting rule: " + prerouting_rule + + "\n postrouting rule: " + postrouting_rule) + + system(forward_rule1) + system(forward_rule2) + system(prerouting_rule) + system(postrouting_rule) + system(@ip_forward_command) +end + +def closeVmVncPort(vm) + # FIXME forward_vnc may have been changed while the vm is running + return unless vm.forward_vnc + unless vm.forward_vnc_port > 0 + raise "Must specify valid port to forward " + vm.forward_vnc_port.to_s + end + + unless _vncPortOpen?(vm.forward_vnc_port) + raise "Port not open " + vm.forward_vnc_port.to_s + end + + forward_rule1, forward_rule2 = _forwardRules(vm) + forward_rule1 = @iptables_cmd + " -D FORWARD " + forward_rule1 + forward_rule2 = @iptables_cmd + " -D FORWARD " + forward_rule2 + + prerouting_rule, postrouting_rule = _natRules(vm) + prerouting_rule = @iptables_cmd + " -t nat -D PREROUTING " + prerouting_rule + postrouting_rule = @iptables_cmd + " -t nat -D POSTROUTING " + postrouting_rule + + _debug(" close\n forward rule 1: " + forward_rule1 + + "\n forward_rule 2: " + forward_rule2 + + "\n prerouting rule: " + prerouting_rule + + "\n postrouting rule: " + postrouting_rule) + + system(forward_rule1) + system(forward_rule2) + system(prerouting_rule) + system(postrouting_rule) +end -- 1.6.0.6 From mmorsi at redhat.com Tue Jan 27 22:32:00 2009 From: mmorsi at redhat.com (Mohammed Morsi) Date: Tue, 27 Jan 2009 17:32:00 -0500 Subject: [Ovirt-devel] server and viewer changes to forward a vm's vnc port Message-ID: <1233095522-11004-1-git-send-email-mmorsi@redhat.com> This patch set contains two patches. The first updates the ovirt server to allow vm administrator to forward a vm's vnc port on a specific port on the server. Upon starting the vm, taskomatic will open and forward these ports, and will close them upon vm shutdown. The second patch updates the viewer to use the forward vnc port and to connect to the server when establishing a vnc connection with a vm From mmorsi at redhat.com Tue Jan 27 22:32:02 2009 From: mmorsi at redhat.com (Mohammed Morsi) Date: Tue, 27 Jan 2009 17:32:02 -0500 Subject: [Ovirt-devel] [PATCH viewer] changes to establish connection to ovirt server on vm's forward_vnc_port In-Reply-To: <1233095522-11004-2-git-send-email-mmorsi@redhat.com> References: <1233095522-11004-1-git-send-email-mmorsi@redhat.com> <1233095522-11004-2-git-send-email-mmorsi@redhat.com> Message-ID: <1233095522-11004-3-git-send-email-mmorsi@redhat.com> --- configure.ac | 4 +- internal.h | 1 + main.c | 92 +++++++++++++++++++++------------------------------------- wui_thread.c | 10 ++++++ 4 files changed, 46 insertions(+), 61 deletions(-) diff --git a/configure.ac b/configure.ac index e597939..13276ea 100644 --- a/configure.ac +++ b/configure.ac @@ -33,10 +33,10 @@ PKG_CHECK_MODULES([OVIRT_VIEWER], [gtk+-2.0 gtk-vnc-1.0 glib-2.0 libxml-2.0 gnutls gthread-2.0 libcurl]) dnl Header files. -AC_CHECK_HEADERS([sys/socket.h sys/un.h windows.h]) +AC_CHECK_HEADERS([netdb.h netinet/in.h sys/socket.h sys/un.h windows.h]) dnl Optional functions. -AC_CHECK_FUNCS([socketpair fork]) +AC_CHECK_FUNCS([socket gethostbyname htons connect]) dnl Default location for CA certificate bundle. AC_ARG_ENABLE([cainfo], diff --git a/internal.h b/internal.h index 9c39bef..950fd05 100644 --- a/internal.h +++ b/internal.h @@ -104,6 +104,7 @@ struct vm { int hostid; int id; int vnc_port; + int forward_vnc_port; char *uuid; /* Printable UUID. */ /* Only the fields above this point are required. The remainder may diff --git a/main.c b/main.c index f6e5e08..390046a 100644 --- a/main.c +++ b/main.c @@ -27,6 +27,14 @@ #include #include +#ifdef HAVE_NETDB_H +#include +#endif + +#ifdef HAVE_NETINET_IN_H +#include +#endif + #ifdef HAVE_SYS_SOCKET_H #include #endif @@ -69,7 +77,7 @@ static void viewer_connected (GtkWidget *vnc); static void viewer_initialized (GtkWidget *vnc, GtkWidget *data); static void viewer_disconnected (GtkWidget *vnc); static void viewer_credential (GtkWidget *vnc, GValueArray *credList); -static int viewer_open_tunnel_ssh (const char *sshhost, int sshport, const char *sshuser, int vncport); +static int viewer_open_vnc_socket (const char *vnchost, int vncport); /* For any widgets accessed from multiple functions. */ static GtkWidget *window; @@ -501,6 +509,7 @@ connect_to_vm (GtkWidget *widget, gpointer _vm) int i, uuidlen, len, fd; GtkWidget *child; const char *label; + const char* hostname; char *label2; DEBUG ("searching tabs for uuid %s", vm->uuid); @@ -523,10 +532,8 @@ connect_to_vm (GtkWidget *widget, gpointer _vm) DEBUG ("not found, creating new tab"); /* This VM isn't in the notebook already, so create a new console. */ - fd = viewer_open_tunnel_ssh (/*vm->host XXX*/ "192.168.50.6", - 0, /* Default SSH port. */ - "root", /* Root account. */ - vm->vnc_port); + hostname = gtk_entry_get_text (GTK_ENTRY (ca_hostname)); + fd = viewer_open_vnc_socket(hostname, vm->forward_vnc_port); if (fd == -1) return; /* We've already given an error. */ child = vnc_display_new (); @@ -740,70 +747,37 @@ viewer_credential (GtkWidget *vnc, GValueArray *credList) gtk_widget_destroy(GTK_WIDGET(dialog)); } -#if defined(HAVE_SOCKETPAIR) && defined(HAVE_FORK) +#if defined(HAVE_SOCKET) && defined(HAVE_CONNECT) && defined(HAVE_HTONS) && defined(HAVE_GETHOSTBYNAME) -static int viewer_open_tunnel(const char **cmd) +static int +viewer_open_vnc_socket(const char* vnchost, int vncport) { - int fd[2]; - pid_t pid; + int socketfd; + struct hostent *serv; + struct sockaddr_in serv_addr; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd) < 0) - return -1; + socketfd = socket(PF_INET, SOCK_STREAM, 0); + if(socketfd < 0){ + return -1; + } - pid = fork(); - if (pid == -1) { - close(fd[0]); - close(fd[1]); - return -1; - } + serv = gethostbyname(vnchost); + if(serv == NULL){ + return -1; + } - if (pid == 0) { /* child */ - close(fd[0]); - close(0); - close(1); - if (dup(fd[1]) < 0) - _exit(1); - if (dup(fd[1]) < 0) - _exit(1); - close(fd[1]); - execvp("ssh", (char *const*)cmd); - _exit(1); - } - close(fd[1]); - return fd[0]; -} + serv_addr.sin_family = PF_INET; + serv_addr.sin_port = htons(vncport); + serv_addr.sin_addr.s_addr = ((struct in_addr *)(serv->h_addr))->s_addr; -static int -viewer_open_tunnel_ssh (const char *sshhost, int sshport, const char *sshuser, - int vncport) -{ - const char *cmd[10]; - char portstr[50], portstr2[50]; - int n = 0; - - if (!sshport) - sshport = 22; - - snprintf (portstr, sizeof portstr, "%d", sshport); - snprintf (portstr2, sizeof portstr2, "%d", vncport); - - cmd[n++] = "ssh"; - cmd[n++] = "-p"; - cmd[n++] = portstr; - if (sshuser) { - cmd[n++] = "-l"; - cmd[n++] = sshuser; + if (connect(socketfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0){ + return -1; } - cmd[n++] = sshhost; - cmd[n++] = "nc"; - cmd[n++] = "localhost"; - cmd[n++] = portstr2; - cmd[n++] = NULL; - return viewer_open_tunnel(cmd); + return socketfd; } -#endif /* defined(HAVE_SOCKETPAIR) && defined(HAVE_FORK) */ +#endif /* defined(HAVE_SOCKET) && defined(HAVE_CONNECT) && defined(HAVE_HTONS) && defined(HAVE_GETHOSTBYNAME) */ /* Remove all menu items from the Connect menu. */ static void diff --git a/wui_thread.c b/wui_thread.c index 0585c89..9dab95c 100644 --- a/wui_thread.c +++ b/wui_thread.c @@ -977,6 +977,7 @@ parse_vm_from_xml (xmlNodePtr node) vm.hostid = -1; vm.id = -1; vm.vnc_port = -1; + vm.forward_vnc_port = -1; vm.mem_allocated = -1; vm.mem_used = -1; vm.vcpus_allocated = -1; @@ -1053,6 +1054,13 @@ parse_vm_from_xml (xmlNodePtr node) xmlFree (str); } } + else if (xmlStrcmp (p->name, (const xmlChar *) "forward-vnc-port") == 0) { + str = xmlNodeGetContent (p); + if (str != NULL) { + vm.forward_vnc_port = strtol ((char *) str, NULL, 10); + xmlFree (str); + } + } else if (xmlStrcmp (p->name, (const xmlChar *) "vnic-mac-addr") == 0) { str = xmlNodeGetContent (p); if (str != NULL) { @@ -1072,6 +1080,8 @@ parse_vm_from_xml (xmlNodePtr node) DEBUG ("required field \"description\" missing from structure"); else if (vm.vnc_port == -1) DEBUG ("required field \"vnc-port\" missing from structure"); + else if (vm.forward_vnc_port == -1) + DEBUG ("required field \"forward-vnc-port\" missing from structure"); else if (vm.uuid == NULL) DEBUG ("required field \"uuid\" missing from structure"); else -- 1.6.0.6 From lutter at redhat.com Tue Jan 27 23:01:13 2009 From: lutter at redhat.com (David Lutterkort) Date: Tue, 27 Jan 2009 23:01:13 +0000 Subject: [Ovirt-devel] [PATCH server] allow admin to setup iptables port forwarding on server for a vm's vnc port In-Reply-To: <1233095522-11004-2-git-send-email-mmorsi@redhat.com> References: <1233095522-11004-1-git-send-email-mmorsi@redhat.com> <1233095522-11004-2-git-send-email-mmorsi@redhat.com> Message-ID: <1233097273.32681.50.camel@localhost.localdomain> On Tue, 2009-01-27 at 17:32 -0500, Mohammed Morsi wrote: > diff --git a/src/app/views/vm/_form.rhtml b/src/app/views/vm/_form.rhtml > index 523e81e..486798f 100644 > --- a/src/app/views/vm/_form.rhtml > +++ b/src/app/views/vm/_form.rhtml > @@ -51,6 +51,21 @@ >
          >
          > > +
          > + <%= check_box_tag_with_label "Forward vm's vnc port locally", "forward_vnc", 1, @vm.forward_vnc %> > +
          > +
          > + <%= text_field_with_label "", "vm", "forward_vnc_port", { :style=>"width: 80px;", :size => 7, :disabled => ! @vm.forward_vnc } %> > +
          > +
          > +
          > + > + > + > <%= check_box_tag_with_label "Start VM Now? (pending current resource availability)", "start_now", nil if create or @vm.state == Vm::STATE_STOPPED %> > <%= check_box_tag_with_label "Restart VM Now? (pending current resource availability)", "restart_now", nil if @vm.state == Vm::STATE_RUNNING %> Why does the user need to allocate the port manually ? Couldn't we do that internally when the VM is started and release the allocation when it's taken down ? > diff --git a/src/task-omatic/taskomatic.rb b/src/task-omatic/taskomatic.rb > index bcb9bd3..dca6fb7 100755 > --- a/src/task-omatic/taskomatic.rb > +++ b/src/task-omatic/taskomatic.rb > @@ -32,6 +32,7 @@ include Daemonize > > require 'task_vm' > require 'task_storage' > +require 'vnc' > > class TaskOmatic > > @@ -232,6 +233,8 @@ class TaskOmatic > raise "Error destroying VM: #{result.text}" unless result.status == 0 > end > > + closeVmVncPort(vm) > + > # undefine can fail, for instance, if we live migrated from A -> B, and > # then we are shutting down the VM on B (because it only has "transient" > # XML). Therefore, just ignore undefine errors so we do the rest > @@ -303,6 +306,7 @@ class TaskOmatic > # of places so you'll see a lot of .reloads. > db_vm.reload > set_vm_vnc_port(db_vm, result.description) unless result.status != 0 > + forwardVmVncPort(db_vm) These methods should be called close_vm_vnc_port and forward_vm_vnc_port to stick with the standard Ruby style. > diff --git a/src/task-omatic/vnc.rb b/src/task-omatic/vnc.rb > new file mode 100644 > index 0000000..3eb0ca6 > --- /dev/null > +++ b/src/task-omatic/vnc.rb > @@ -0,0 +1,140 @@ > +# Copyright (C) 2008 Red Hat, Inc. > +# Written by Mohammed Morsi > +# > +# 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. > + > +# TODO no ruby/libiptc wrapper exists, when > +# it does replace iptables command w/ calls to it > + at iptables_cmd='/sbin/iptables ' > + > +# TODO replace this w/ dnsruby inclusion / call > + at dns_lookup_cmd='/usr/bin/dig' > + > + at ip_forward_command='echo 1 > /proc/sys/net/ipv4/ip_forward' All this should at least become a module, and not just random things in the toplevel. Also, please stay with the Ruby style of using '_' to separate words in identifiers instead of StudLyCaps. Also, use constants, not instance variables for those strings, i.e. IPTABLES_CMD = '/sbin/iptables' > + at vnc_debug = false > + > +# TODO can this be retreived in any way > +# since machine will have both external > +# and internal network interface > + at local_ip = '192.168.50.2' > + > +############################## 'private' methods If you make this a module or a class, you can actually mark the methods as private; for a module it requires a small amount of trickery: module Foo def self.pb; puts "public"; end def self.pr; puts "private"; end class << self private :pr end end > +def _debug(msg) > + puts "\n" + msg + "\n" if @vnc_debug > +end > + > +def _findVmHostIp(vm) > + cmdout='/tmp/ovirtvnc' + vm.forward_vnc_port.to_s > + cmd=@dns_lookup_cmd + ' ' + vm.host.hostname + > + ' +noall +answer +short > ' + cmdout > + > + system(cmd) > + > + result = File.read(cmdout).rstrip > + _debug( "vm host hostname resolved to " + result.to_s ) > + return result > +end This should use Socket::getaddrinfo instead of shelling out to dig. > +def _vncPortOpen?(port) > + cmdout='/tmp/ovirtvnc' + port.to_s > + cmd=@iptables_cmd + ' -t nat -nL | grep ' + port.to_s + > + ' > ' + cmdout > + _debug("vncPortOpen? iptables command: " + cmd + > + " cmdout " + cmdout) > + > + system(cmd) > + > + return File.size(cmdout) != 0 > +end You could save yourself the temp file if you used IO::popen or backticks: `#{IPTABLES_CMD} -t nat -nL`.each_line do |l| if l matches port return true end end return false David From mmorsi at redhat.com Tue Jan 27 23:28:35 2009 From: mmorsi at redhat.com (Mohammed Morsi) Date: Tue, 27 Jan 2009 18:28:35 -0500 Subject: [Ovirt-devel] [PATCH server] allow admin to setup iptables port forwarding on server for a vm's vnc port In-Reply-To: <1233097273.32681.50.camel@localhost.localdomain> References: <1233095522-11004-1-git-send-email-mmorsi@redhat.com> <1233095522-11004-2-git-send-email-mmorsi@redhat.com> <1233097273.32681.50.camel@localhost.localdomain> Message-ID: <497F98A3.6040503@redhat.com> David Lutterkort wrote: > On Tue, 2009-01-27 at 17:32 -0500, Mohammed Morsi wrote: > >> diff --git a/src/app/views/vm/_form.rhtml b/src/app/views/vm/_form.rhtml >> index 523e81e..486798f 100644 >> --- a/src/app/views/vm/_form.rhtml >> +++ b/src/app/views/vm/_form.rhtml >> @@ -51,6 +51,21 @@ >>
          >>
          >> >> +
          >> + <%= check_box_tag_with_label "Forward vm's vnc port locally", "forward_vnc", 1, @vm.forward_vnc %> >> +
          >> +
          >> + <%= text_field_with_label "", "vm", "forward_vnc_port", { :style=>"width: 80px;", :size => 7, :disabled => ! @vm.forward_vnc } %> >> +
          >> +
          >> +
          >> + >> + >> + >> <%= check_box_tag_with_label "Start VM Now? (pending current resource availability)", "start_now", nil if create or @vm.state == Vm::STATE_STOPPED %> >> <%= check_box_tag_with_label "Restart VM Now? (pending current resource availability)", "restart_now", nil if @vm.state == Vm::STATE_RUNNING %> >> > > Why does the user need to allocate the port manually ? Couldn't we do > that internally when the VM is started and release the allocation when > it's taken down ? > This is just allowing a vm admin to set the option via the wui. I'd think we'd want the ability not to forward the vnc for deployments when forwarding is unecessary. We could also simply use the vnc_port instead of adding the forward_vnc_port field, but I also figured it would be useful if this was administratively configurable. If this is not the case, it can be removed easily. Thanks for the ruby styling tips, I'll integrate your suggestions into the server and send out another patch. -Mo From lutter at redhat.com Tue Jan 27 23:51:02 2009 From: lutter at redhat.com (David Lutterkort) Date: Tue, 27 Jan 2009 23:51:02 +0000 Subject: [Ovirt-devel] [PATCH server] allow admin to setup iptables port forwarding on server for a vm's vnc port In-Reply-To: <497F98A3.6040503@redhat.com> References: <1233095522-11004-1-git-send-email-mmorsi@redhat.com> <1233095522-11004-2-git-send-email-mmorsi@redhat.com> <1233097273.32681.50.camel@localhost.localdomain> <497F98A3.6040503@redhat.com> Message-ID: <1233100262.32681.52.camel@localhost.localdomain> On Tue, 2009-01-27 at 18:28 -0500, Mohammed Morsi wrote: > David Lutterkort wrote: > > Why does the user need to allocate the port manually ? Couldn't we do > > that internally when the VM is started and release the allocation when > > it's taken down ? > > > This is just allowing a vm admin to set the option via the wui. I'd > think we'd want the ability not to forward the vnc for deployments when > forwarding is unecessary. Sorry, I was a litttle obtuse in my comment: what I meant was: the user should just have a check box 'Forward VNC port locally' to turn forwarding on/off, and we'll allocate the port when the VM is started, and report it on the VM details screen. Otherwise, the admin has to find some way to track assigned VNC ports to avoid collisions. David From mmorsi at redhat.com Wed Jan 28 02:42:38 2009 From: mmorsi at redhat.com (Mohammed Morsi) Date: Tue, 27 Jan 2009 21:42:38 -0500 Subject: [Ovirt-devel] [PATCH server] allow admin to setup iptables port forwarding on server for a vm's vnc port In-Reply-To: <1233100262.32681.52.camel@localhost.localdomain> References: <1233095522-11004-1-git-send-email-mmorsi@redhat.com> <1233095522-11004-2-git-send-email-mmorsi@redhat.com> <1233097273.32681.50.camel@localhost.localdomain> <497F98A3.6040503@redhat.com> <1233100262.32681.52.camel@localhost.localdomain> Message-ID: <497FC61E.8010208@redhat.com> David Lutterkort wrote: > On Tue, 2009-01-27 at 18:28 -0500, Mohammed Morsi wrote: > >> David Lutterkort wrote: >> >>> Why does the user need to allocate the port manually ? Couldn't we do >>> that internally when the VM is started and release the allocation when >>> it's taken down ? >>> >>> >> This is just allowing a vm admin to set the option via the wui. I'd >> think we'd want the ability not to forward the vnc for deployments when >> forwarding is unecessary. >> > > Sorry, I was a litttle obtuse in my comment: what I meant was: the user > should just have a check box 'Forward VNC port locally' to turn > forwarding on/off, and we'll allocate the port when the VM is started, > and report it on the VM details screen. Otherwise, the admin has to find > some way to track assigned VNC ports to avoid collisions. > > David > > > To allocate the port automatically we'd need to keep track internally of what ports are available, possibly doing something incremental (to what maximum?) or better yet, keeping track which ones have been used through the forward_vnc_column. We wouldn't just simply be able to use the vm's vnc port as there could be multiple vm's running on multiple hosts with the same vnc port. Besides a bit of added complexity, I don't see any reason we couldn't track which vnc port to use next from the ones already in the forward_vnc_port column. I could also just add a uniqueness constraint to the column and have the wui report it as being used upon and invalid entry. Doing both would probably work best, prefilling in the textbox with the next available value so that an administrator can still set it to a custom value if desired. -Mo From jboggs at redhat.com Wed Jan 28 15:48:19 2009 From: jboggs at redhat.com (Joey Boggs) Date: Wed, 28 Jan 2009 10:48:19 -0500 Subject: [Ovirt-devel] [PATCH server] dns forward/reverse lookup update / dnsdomainname is default for dhcp domain Message-ID: <1233157699-6542-1-git-send-email-jboggs@redhat.com> --- installer/bin/ovirt-installer | 20 ++++++++++++++------ 1 files changed, 14 insertions(+), 6 deletions(-) diff --git a/installer/bin/ovirt-installer b/installer/bin/ovirt-installer index 6fab09a..99601d4 100755 --- a/installer/bin/ovirt-installer +++ b/installer/bin/ovirt-installer @@ -149,22 +149,30 @@ prov_ip = `ifconfig #{prov_dev}` prov_ipaddr= prov_ip.scan(/\s*inet addr:([\d.]+)/) if dns_servers == "y" - host_lookup = Socket.getaddrinfo(ipa_host,nil) - hostip = host_lookup[1][3] - if hostip.to_s != mgmt_ipaddr.to_s - @cli.say("Reverse dns lookup for #{ipa_host} failed, exiting") - exit + mgmt_ipaddr_lookup = Socket.getaddrinfo(mgmt_ipaddr.to_s,nil) + mgmt_hostname = mgmt_ipaddr_lookup[1][2] + if mgmt_hostname.to_s != ipa_host.to_s + @cli.say("Reverse dns lookup for #{mgmt_ipaddr} failed, exiting") + exit(0) + end + + ipa_host_lookup = Socket.getaddrinfo(ipa_host,nil) + ipa_hostip = ipa_host_lookup[1][3] + if ipa_hostip.to_s != mgmt_ipaddr.to_s + @cli.say("Forward dns lookup for #{ipa_host} failed, exiting") + exit(0) end end # DHCP Configuration dhcp_setup = prompt_yes_no("Does your provisioning network already have dhcp?") if dhcp_setup == "n" + dnsdomainname = `/bin/dnsdomainname` dhcp_interface = prov_dev dhcp_network = prompt_for_answer("Enter the first 3 octets of the dhcp network you wish to use (example: 192.168.50):", :regex => THREE_OCTETS) dhcp_start = prompt_for_answer("Enter the dhcp pool start address (example: 3):", :regex => OCTET) dhcp_stop = prompt_for_answer("Enter the dhcp pool end addess (example: 100):", :regex => OCTET) - dhcp_domain = prompt_for_answer("Enter the dhcp domain you wish to use (example: example.com):", :regex => IP_OR_FQDN) + dhcp_domain = prompt_for_answer("Enter the dhcp domain you wish to use (example: example.com):", :default => dnsdomainname.chomp, :regex => IP_OR_FQDN) tftp_setup = prompt_yes_no("Provide pxe/tftp capability?") if sep_networks == "y" -- 1.6.0.6 From apevec at gmail.com Wed Jan 28 17:25:58 2009 From: apevec at gmail.com (Alan Pevec) Date: Wed, 28 Jan 2009 18:25:58 +0100 Subject: [Ovirt-devel] [PATCH] Fix a syntax error in the initscript In-Reply-To: <1232741335-19991-1-git-send-email-katzj@redhat.com> References: <1232741335-19991-1-git-send-email-katzj@redhat.com> Message-ID: <2be7262f0901280925q6c990826p280f2e89cca3cd08@mail.gmail.com> ACK and pushed, thanks! From jguiditt at redhat.com Wed Jan 28 18:47:50 2009 From: jguiditt at redhat.com (Jason Guiditta) Date: Wed, 28 Jan 2009 13:47:50 -0500 Subject: [Ovirt-devel] [PATCH server] Fix smart pools in nav. Message-ID: <1233168470-20596-1-git-send-email-jguiditt@redhat.com> They were not updating when you added a new one because We were only recursing down through children if an element was not changed, rather than always if there were children. If I recall correctly, this was originally to save processing time, but with recent changes, it is no longer accurate. Also realized that tree_controller was not splitting properly based on name, so if you had a name with '-'s in it, it would always return as 'changed'. In addition, the 'smart root' never changes (at least by the user) so make state='unchanged'. Signed-off-by: Jason Guiditta --- src/app/controllers/tree_controller.rb | 3 ++- src/public/javascripts/ovirt.tree.js | 8 +++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/app/controllers/tree_controller.rb b/src/app/controllers/tree_controller.rb index 2bd2928..b6e7404 100644 --- a/src/app/controllers/tree_controller.rb +++ b/src/app/controllers/tree_controller.rb @@ -21,7 +21,7 @@ class TreeController < ApplicationController @clientHash = {} if (params[:item]) params[:item].each { |item| - tempItem = item.split("-") + tempItem = item.split("-",2) itemHash = { :id => tempItem[0].to_s, :name =>tempItem[1] @@ -81,6 +81,7 @@ class TreeController < ApplicationController smart_root = list[0] smart_root[:name] = "Smart Pools" smart_root[:type] = "SmartPoolRoot" + smart_root[:state] = "unchanged" mySmartPools = Array.new otherSmartPools = Array.new if smart_root.has_key?(:children) diff --git a/src/public/javascripts/ovirt.tree.js b/src/public/javascripts/ovirt.tree.js index 77d6c55..b7f95f0 100644 --- a/src/public/javascripts/ovirt.tree.js +++ b/src/public/javascripts/ovirt.tree.js @@ -58,11 +58,9 @@ function processChildren(list, templateObj){ $('#' + data.parent_id).parent().append('
            ' + result + '
          '); $('#' + data.parent_id).siblings('span').addClass('expanded'); } - } - else { - if (data.children) { - processChildren(data.children, templateObj); - } + } + if (data.children) { + processChildren(data.children, templateObj); } }); } -- 1.5.6.6 From apevec at redhat.com Wed Jan 28 22:09:55 2009 From: apevec at redhat.com (Alan Pevec) Date: Wed, 28 Jan 2009 23:09:55 +0100 Subject: [Ovirt-devel] [PATCH node-image] improve boot menu configuration Message-ID: <1233180595-15503-1-git-send-email-apevec@redhat.com> fix parsing and add option for custom default boot parameters Signed-off-by: Alan Pevec --- ovirt-node-image.ks | 16 ++++++++++++---- 1 files changed, 12 insertions(+), 4 deletions(-) diff --git a/ovirt-node-image.ks b/ovirt-node-image.ks index 376acc9..f96fb38 100644 --- a/ovirt-node-image.ks +++ b/ovirt-node-image.ks @@ -57,11 +57,19 @@ echo "Fixing boot menu" # remove quiet from Node bootparams, added by livecd-creator sed -i -e 's/ quiet//' $LIVE_ROOT/isolinux/isolinux.cfg -# add standalone boot entry +# add stand-alone boot entry awk ' -/label linux0/ { linux0=1 } -linux0=1 && /append / { append0=$0 } -/label check0/ { +BEGIN { + # append additional default boot parameters + add_boot_params="" +} +/^label linux0/ { linux0=1 } +linux0==1 && $1=="append" { + $0=$0 " " add_boot_params + append0=$0 +} +linux0==1 && $1=="label" && $2!="linux0" { + linux0=2 print "label stand-alone" print " menu label Boot in stand-alone mode" print " kernel vmlinuz0" -- 1.6.0.6 From mmorsi at redhat.com Thu Jan 29 01:16:08 2009 From: mmorsi at redhat.com (Mohammed Morsi) Date: Wed, 28 Jan 2009 20:16:08 -0500 Subject: [Ovirt-devel] [PATCH server] allow admin to setup iptables port forwarding on server for a vm's vnc port Message-ID: <1233191768-9399-1-git-send-email-mmorsi@redhat.com> --- src/app/controllers/vm_controller.rb | 8 ++- src/app/models/vm.rb | 17 ++++ src/app/views/vm/_form.rhtml | 15 ++++ src/app/views/vm/show.rhtml | 4 + src/db/migrate/034_add_vm_vnc.rb | 30 ++++++++ src/task-omatic/taskomatic.rb | 4 + src/task-omatic/vnc.rb | 136 ++++++++++++++++++++++++++++++++++ src/test/fixtures/vms.yml | 2 + src/test/unit/vm_test.rb | 16 ++++ 9 files changed, 231 insertions(+), 1 deletions(-) create mode 100644 src/db/migrate/034_add_vm_vnc.rb create mode 100644 src/task-omatic/vnc.rb diff --git a/src/app/controllers/vm_controller.rb b/src/app/controllers/vm_controller.rb index 56501fd..e92d604 100644 --- a/src/app/controllers/vm_controller.rb +++ b/src/app/controllers/vm_controller.rb @@ -116,6 +116,8 @@ class VmController < ApplicationController new_storage_ids = new_storage_ids.sort.collect {|x| x.to_i } needs_restart = true unless current_storage_ids == new_storage_ids end + params[:vm][:forward_vnc] = params[:forward_vnc] + params[:vm][:forward_vnc_port] = nil unless params[:forward_vnc] params[:vm][:needs_restart] = 1 if needs_restart @vm.update_attributes!(params[:vm]) _setup_vm_provision(params) @@ -325,7 +327,8 @@ class VmController < ApplicationController newargs = { :vm_resource_pool_id => params[:vm_resource_pool_id], :vnic_mac_addr => mac.collect {|x| "%02x" % x}.join(":"), - :uuid => uuid + :uuid => uuid, + :forward_vnc_port => Vm.available_forward_vnc_port } @vm = Vm.new( newargs ) unless params[:vm_resource_pool_id] @@ -345,6 +348,8 @@ class VmController < ApplicationController vm_resource_pool.create_with_parent(hardware_pool) params[:vm][:vm_resource_pool_id] = vm_resource_pool.id end + params[:vm][:forward_vnc] = params[:forward_vnc] + params[:vm][:forward_vnc_port] = nil unless params[:forward_vnc] @vm = Vm.new(params[:vm]) @perm_obj = @vm.vm_resource_pool @current_pool_id=@perm_obj.id @@ -356,6 +361,7 @@ class VmController < ApplicationController end def pre_edit @vm = Vm.find(params[:id]) + @vm.forward_vnc_port = Vm.available_forward_vnc_port unless @vm.forward_vnc @perm_obj = @vm.vm_resource_pool @current_pool_id=@perm_obj.id _setup_provisioning_options diff --git a/src/app/models/vm.rb b/src/app/models/vm.rb index bf99e2d..63c9232 100644 --- a/src/app/models/vm.rb +++ b/src/app/models/vm.rb @@ -40,6 +40,15 @@ class Vm < ActiveRecord::Base validates_format_of :uuid, :with => %r([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}) + validates_numericality_of :forward_vnc_port, + :message => 'Forward vnc port must be >= 5900', + :greater_than_or_equal_to => 5900, + :if => Proc.new { |vm| vm.forward_vnc } + + validates_uniqueness_of :forward_vnc_port, + :message => 'Duplicate forward vnc port exists', + :if => Proc.new { |vm| vm.forward_vnc } + validates_numericality_of :needs_restart, :greater_than_or_equal_to => 0, :less_than_or_equal_to => 1, @@ -335,6 +344,14 @@ class Vm < ActiveRecord::Base super end + def self.available_forward_vnc_port + i = 5900 + until Vm.find(:first, :conditions => [ "forward_vnc_port = ?", i]).nil? + i += 1 + end + return i + end + protected def validate resources = vm_resource_pool.max_resources_for_vm(self) diff --git a/src/app/views/vm/_form.rhtml b/src/app/views/vm/_form.rhtml index 7cbe16d..2db6cb9 100644 --- a/src/app/views/vm/_form.rhtml +++ b/src/app/views/vm/_form.rhtml @@ -51,6 +51,21 @@
          +
          + <%= check_box_tag_with_label "Forward vm's vnc port locally", "forward_vnc", 1, @vm.forward_vnc %> +
          +
          + <%= text_field_with_label "", "vm", "forward_vnc_port", { :style=>"width: 80px;", :size => 7, :disabled => ! @vm.forward_vnc } %> +
          +
          +
          + + + <%= check_box_tag_with_label "Start VM Now? (pending current resource availability)", "start_now", nil if create or @vm.state == Vm::STATE_STOPPED %> <%= check_box_tag_with_label "Restart VM Now? (pending current resource availability)", "restart_now", nil if @vm.state == Vm::STATE_RUNNING %> diff --git a/src/app/views/vm/show.rhtml b/src/app/views/vm/show.rhtml index f361131..add29b4 100644 --- a/src/app/views/vm/show.rhtml +++ b/src/app/views/vm/show.rhtml @@ -88,6 +88,7 @@
          Uuid:
          + <%= @vm.forward_vnc ? "VNC uri:
          " : "" %> Num vcpus allocated:
          Num vcpus used:
          Memory allocated:
          @@ -100,6 +101,9 @@
          <%=h @vm.uuid %>
          + <%= url = request.url + url = request.url[0..(url.index('/', 8) - 1)] + ":" + @vm.forward_vnc_port.to_s + @vm.forward_vnc ? (url + "
          ") : "" %> <%=h @vm.num_vcpus_allocated %>
          <%=h @vm.num_vcpus_used %>
          <%=h @vm.memory_allocated_in_mb %> MB
          diff --git a/src/db/migrate/034_add_vm_vnc.rb b/src/db/migrate/034_add_vm_vnc.rb new file mode 100644 index 0000000..f23e24d --- /dev/null +++ b/src/db/migrate/034_add_vm_vnc.rb @@ -0,0 +1,30 @@ +# Copyright (C) 2008 Red Hat, Inc. +# Written by Mohammed Morsi +# +# 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 AddVmVnc < ActiveRecord::Migration + def self.up + add_column :vms, :forward_vnc, :bool, :default => false + add_column :vms, :forward_vnc_port, :int, :default => 0, :unique => true + end + + def self.down + drop_column :vms, :forward_vnc + drop_column :vms, :forward_vnc_port + end +end + diff --git a/src/task-omatic/taskomatic.rb b/src/task-omatic/taskomatic.rb index bcb9bd3..6db7832 100755 --- a/src/task-omatic/taskomatic.rb +++ b/src/task-omatic/taskomatic.rb @@ -32,6 +32,7 @@ include Daemonize require 'task_vm' require 'task_storage' +require 'vnc' class TaskOmatic @@ -232,6 +233,8 @@ class TaskOmatic raise "Error destroying VM: #{result.text}" unless result.status == 0 end + VmVnc.close(vm) + # undefine can fail, for instance, if we live migrated from A -> B, and # then we are shutting down the VM on B (because it only has "transient" # XML). Therefore, just ignore undefine errors so we do the rest @@ -303,6 +306,7 @@ class TaskOmatic # of places so you'll see a lot of .reloads. db_vm.reload set_vm_vnc_port(db_vm, result.description) unless result.status != 0 + VmVnc.forward(db_vm) # This information is not available via the libvirt interface. db_vm.memory_used = db_vm.memory_allocated diff --git a/src/task-omatic/vnc.rb b/src/task-omatic/vnc.rb new file mode 100644 index 0000000..bc3fd8f --- /dev/null +++ b/src/task-omatic/vnc.rb @@ -0,0 +1,136 @@ +# Copyright (C) 2008 Red Hat, Inc. +# Written by Mohammed Morsi +# +# 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. + +# provides static 'forward' and 'close' methods to forward a specified vm's vnc connections +class VmVnc + + private + + # TODO no ruby/libiptc wrapper exists, when + # it does replace iptables command w/ calls to it + IPTABLES_CMD='/sbin/iptables ' + + IP_FORWARD_CMD='echo 1 > /proc/sys/net/ipv4/ip_forward' + + VNC_DEBUG = false + + # FIXME can this be retreived in any way + # since machine will have both external + # and internal network interface + LOCAL_IP = '192.168.50.2' + + def self.debug(msg) + puts "\n" + msg + "\n" if VNC_DEBUG + end + + def self.find_host_ip(hostname) + # FIXME + addrinfo = Socket::getaddrinfo(hostname, nil) + unless addrinfo.size > 0 + raise "Could not retreive address for " + hostname + end + result = addrinfo[0][3] # return ip address of first entry + debug( "vm host hostname resolved to " + result.to_s ) + return result + end + + def self.port_open?(port) + cmd=IPTABLES_CMD + ' -t nat -nL ' + debug("vncPortOpen? iptables command: " + cmd) + + `#{cmd}`.each_line do |l| + return true if l =~ /.*#{port}.*/ + end + return false + end + + def self.get_forward_rules(vm) + ip = find_host_ip(vm.host.hostname) + return " -d " + ip + " -p tcp --dport " + vm.vnc_port.to_s + " -j ACCEPT", + " -s " + ip + " -p tcp --sport " + vm.vnc_port.to_s + " -j ACCEPT" + end + + def self.get_nat_rules(vm) + ip = find_host_ip(vm.host.hostname) + + return " -p tcp --dport " + vm.forward_vnc_port.to_s + " -j DNAT --to " + ip + ":" + vm.vnc_port.to_s, + " -d " + ip + " -p tcp --dport " + vm.vnc_port.to_s + " -j SNAT --to " + LOCAL_IP + end + + public + + def self.forward(vm) + return unless vm.forward_vnc + unless vm.forward_vnc_port > 0 + raise "Must specify valid port to forward " + vm.forward_vnc_port.to_s + end + + if port_open?(vm.forward_vnc_port) + raise "Port already open " + vm.forward_vnc_port.to_s + end + + forward_rule1, forward_rule2 = get_forward_rules(vm) + forward_rule1 = IPTABLES_CMD + " -A FORWARD " + forward_rule1 + forward_rule2 = IPTABLES_CMD + " -A FORWARD " + forward_rule2 + + prerouting_rule, postrouting_rule = get_nat_rules(vm) + prerouting_rule = IPTABLES_CMD + " -t nat -A PREROUTING " + prerouting_rule + postrouting_rule = IPTABLES_CMD + " -t nat -A POSTROUTING " + postrouting_rule + + debug(" open\n forward rule 1: " + forward_rule1 + + "\n forward_rule 2: " + forward_rule2 + + "\n prerouting rule: " + prerouting_rule + + "\n postrouting rule: " + postrouting_rule) + + system(forward_rule1) + system(forward_rule2) + system(prerouting_rule) + system(postrouting_rule) + system(IP_FORWARD_CMD) + end + + def self.close(vm) + # FIXME forward_vnc may have been changed while the vm is running + return unless vm.forward_vnc + unless vm.forward_vnc_port > 0 + raise "Must specify valid port to forward " + vm.forward_vnc_port.to_s + end + + unless port_open?(vm.forward_vnc_port) + raise "Port not open " + vm.forward_vnc_port.to_s + end + + forward_rule1, forward_rule2 = get_forward_rules(vm) + forward_rule1 = IPTABLES_CMD + " -D FORWARD " + forward_rule1 + forward_rule2 = IPTABLES_CMD + " -D FORWARD " + forward_rule2 + + prerouting_rule, postrouting_rule = get_nat_rules(vm) + prerouting_rule = IPTABLES_CMD + " -t nat -D PREROUTING " + prerouting_rule + postrouting_rule = IPTABLES_CMD + " -t nat -D POSTROUTING " + postrouting_rule + + debug(" close\n forward rule 1: " + forward_rule1 + + "\n forward_rule 2: " + forward_rule2 + + "\n prerouting rule: " + prerouting_rule + + "\n postrouting rule: " + postrouting_rule) + + system(forward_rule1) + system(forward_rule2) + system(prerouting_rule) + system(postrouting_rule) + end +end diff --git a/src/test/fixtures/vms.yml b/src/test/fixtures/vms.yml index ca0d63f..366f192 100644 --- a/src/test/fixtures/vms.yml +++ b/src/test/fixtures/vms.yml @@ -11,6 +11,8 @@ production_httpd_vm: boot_device: hd host: prod_corp_com vm_resource_pool: corp_com_production_vmpool + forward_vnc: true + forward_vnc_port: 1234 production_mysqld_vm: uuid: 89e62d32-04d9-4351-b573-b1a253397296 description: production mysqld appliance diff --git a/src/test/unit/vm_test.rb b/src/test/unit/vm_test.rb index cba3188..b868dfa 100644 --- a/src/test/unit/vm_test.rb +++ b/src/test/unit/vm_test.rb @@ -95,6 +95,22 @@ class VmTest < Test::Unit::TestCase flunk 'Vm must specify valid state' if @vm.valid? end + # ensure duplicate forward_vnc_ports cannot exist + def test_invalid_without_unique_forward_vnc_port + vm = vms(:production_mysqld_vm) + vm.forward_vnc = true + vm.forward_vnc_port = 1234 # duplicate + assert !vm.valid?, "forward vnc port must be unique" + end + + # ensure bad forward_vnc_ports cannot exist + def test_invalid_without_bad_forward_vnc_port + vm = vms(:production_mysqld_vm) + vm.forward_vnc = true + vm.forward_vnc_port = 1 # too small + assert !vm.valid?, "forward vnc port must be >= 5900" + end + # Ensures that, if the VM does not contain the Cobbler prefix, that it # does not claim to be a Cobbler VM. # -- 1.6.0.6 From sseago at redhat.com Thu Jan 29 14:35:09 2009 From: sseago at redhat.com (Scott Seago) Date: Thu, 29 Jan 2009 14:35:09 +0000 Subject: [Ovirt-devel] [PATCH] fixed a couple random smart pool UI bugs: Message-ID: <1233239709-13741-1-git-send-email-sseago@redhat.com> 1. the 'add storage' flexigrid for smart pools was broken due to an error in generating the :conditions block 2. the pulldown list for smart pools was showing the DirectoryPools for each user rather than the smart pools themselves. Signed-off-by: Scott Seago --- src/app/controllers/smart_pools_controller.rb | 7 ++++++- src/app/models/smart_pool.rb | 22 ++++++++++++---------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/app/controllers/smart_pools_controller.rb b/src/app/controllers/smart_pools_controller.rb index cbfbd1c..f5f3c9d 100644 --- a/src/app/controllers/smart_pools_controller.rb +++ b/src/app/controllers/smart_pools_controller.rb @@ -76,7 +76,12 @@ class SmartPoolsController < PoolController def storage_pools_json args = items_json_internal(StoragePool, :tagged_storage_pools) conditions = args[:find_opts][:conditions] - conditions[0] = "(storage_pools.type != 'LvmStoragePool') and (#{conditions[0]})" + storage_conditions = "storage_pools.type != 'LvmStoragePool'" + if conditions[0] + conditions[0] = "(#{storage_conditions}) and (#{conditions[0]})" + else + conditions[0] = storage_conditions + end super(args) end diff --git a/src/app/models/smart_pool.rb b/src/app/models/smart_pool.rb index 7df26fa..ca55a2e 100644 --- a/src/app/models/smart_pool.rb +++ b/src/app/models/smart_pool.rb @@ -75,22 +75,24 @@ class SmartPool < Pool def self.smart_pools_for_user(user) nested_pools = DirectoryPool.get_smart_root.full_set_nested( :privilege => Permission::PRIV_MODIFY, :user => user, - :smart_pool_set => true) + :smart_pool_set => true)[0][:children] user_pools = [] other_pools = [] - nested_pools.each do |pool_element| - pool = pool_element[:obj] - if pool.hasChildren - if pool.name == user + if nested_pools + nested_pools.each do |pool_element| + pool = pool_element[:obj] + if pool.hasChildren + if pool.name == user pool_element[:children].each do |child_element| child_pool = child_element[:obj] user_pools <<[child_pool.name, child_pool.id] end - else - if pool_element.has_key?(:children) - pool_element[:children].each do |child_element| - child_pool = child_element[:obj] - other_pools << [pool.name + " > " + child_pool.name, child_pool.id] + else + if pool_element.has_key?(:children) + pool_element[:children].each do |child_element| + child_pool = child_element[:obj] + other_pools << [pool.name + " > " + child_pool.name, child_pool.id] + end end end end -- 1.6.0.6 From imain at redhat.com Thu Jan 29 16:45:08 2009 From: imain at redhat.com (Ian Main) Date: Thu, 29 Jan 2009 08:45:08 -0800 Subject: [Ovirt-devel] gssapi/kerberos support for qpidd Message-ID: <20090129084508.04ad1ab2@tp.mains.net> This set of patches adds support gssapi/kerberos to qpidd. You'll note that it's still not secure as we allow 'plain' auth with a guest account for daemons that connect over localhost (taskomatic, dbomatic etc.) and unfortunately there's no way to constrain that to localhost connections at this time. The qpid team is putting out a new set of rpms in the next day or two which will add gssapi support to ruby at which point we can move those connections to gssapi as well and remove the plain auth with guest access. Ian From imain at redhat.com Thu Jan 29 13:36:47 2009 From: imain at redhat.com (Ian Main) Date: Thu, 29 Jan 2009 05:36:47 -0800 Subject: [Ovirt-devel] [PATCH node] Set up libvirt-qpid to use kerberos/gssapi authentication. In-Reply-To: <20090129084508.04ad1ab2@tp.mains.net> References: <20090129084508.04ad1ab2@tp.mains.net> Message-ID: <1233236207-7635-1-git-send-email-imain@redhat.com> This patch makes libvirt-qpid connect to qpidd using gssapi/kerberos authentication and encryption. A principal for qpidd is added to the libvirt keytab and kinit is used in cron to keep the ticket from expiring. Signed-off-by: Ian Main --- Makefile.am | 1 + kinit/ovirt-kinit | 10 ++++++++++ ovirt-node.spec.in | 3 +++ scripts/ovirt | 3 ++- 4 files changed, 16 insertions(+), 1 deletions(-) create mode 100644 kinit/ovirt-kinit diff --git a/Makefile.am b/Makefile.am index 0cdf430..733fef1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -46,6 +46,7 @@ EXTRA_DIST = \ scripts/ovirt-post \ scripts/ovirt-process-config \ scripts/ovirt-uninstall-node-stateful \ + kinit/ovirt-kinit \ logrotate/ovirt-logrotate \ logrotate/ovirt-logrotate.conf diff --git a/kinit/ovirt-kinit b/kinit/ovirt-kinit new file mode 100644 index 0000000..143b356 --- /dev/null +++ b/kinit/ovirt-kinit @@ -0,0 +1,10 @@ +#!/bin/sh + +/usr/kerberos/bin/kinit -k -t /etc/libvirt/krb5.tab qpidd/`hostname`@PRIV.OVIRT.ORG + +EXITVALUE=$? +if [ $EXITVALUE != 0 ]; then + /usr/bin/logger -t kinit "ALERT kinit failed abnormally with [$EXITVALUE]" +fi +exit $EXITVALUE + diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in index da5e5a1..287a29f 100644 --- a/ovirt-node.spec.in +++ b/ovirt-node.spec.in @@ -162,6 +162,8 @@ cd - %{__install} -p -m0644 scripts/collectd %{buildroot}%{_sysconfdir}/chkconfig.d %{__install} -p -m0644 scripts/collectd.conf.in %{buildroot}%{_sysconfdir} +%{__install} -p -m0755 kinit/ovirt-kinit %{buildroot}%{_sysconfdir}/cron.hourly + %{__install} -p -m0755 logrotate/ovirt-logrotate %{buildroot}%{_sysconfdir}/cron.hourly %{__install} -p -m0644 logrotate/ovirt-logrotate.conf %{buildroot}%{_sysconfdir}/logrotate.d @@ -278,6 +280,7 @@ fi %{_initrddir}/ovirt-firstboot %{_initrddir}/ovirt %{_initrddir}/ovirt-post +%config %{_sysconfdir}/cron.hourly/ovirt-kinit %config %{_sysconfdir}/logrotate.d/ovirt-logrotate.conf %config %{_sysconfdir}/cron.hourly/ovirt-logrotate %{_sysconfdir}/ovirt-config-setup.d diff --git a/scripts/ovirt b/scripts/ovirt index 8694db9..83fe2d7 100755 --- a/scripts/ovirt +++ b/scripts/ovirt @@ -63,7 +63,8 @@ start() { if [ -n "$SRV_HOST" -a -n "$SRV_PORT" ]; then libvirt_qpid_conf=/etc/sysconfig/libvirt-qpid if [ -f $libvirt_qpid_conf ]; then - echo "LIBVIRT_QPID_ARGS=\"--broker $SRV_HOST --port $SRV_PORT\"" >> $libvirt_qpid_conf + echo "LIBVIRT_QPID_ARGS=\"--broker $SRV_HOST --port $SRV_PORT --gssapi\"" >> $libvirt_qpid_conf + echo "/usr/kerberos/bin/kinit -k -t /etc/libvirt/krb5.tab qpidd/`hostname`@PRIV.OVIRT.ORG" >> $libvirt_qpid_conf fi else log "skipping libvirt-qpid configuration, could not find $libvirt_qpid_conf" -- 1.6.0.4 From imain at redhat.com Thu Jan 29 13:37:13 2009 From: imain at redhat.com (Ian Main) Date: Thu, 29 Jan 2009 05:37:13 -0800 Subject: [Ovirt-devel] [PATCH node-image] Add kinit to node In-Reply-To: <20090129084508.04ad1ab2@tp.mains.net> References: <20090129084508.04ad1ab2@tp.mains.net> Message-ID: <1233236233-7672-1-git-send-email-imain@redhat.com> This patch adds krb5-workstation package to the node, but then we remove all but kinit and klist (for debugging purposes). This is to support libvirt-qpid needing a kerberos ticket. Signed-off-by: Ian Main --- common-blacklist.ks | 8 +++++--- 1 files changed, 5 insertions(+), 3 deletions(-) diff --git a/common-blacklist.ks b/common-blacklist.ks index a507911..a295805 100644 --- a/common-blacklist.ks +++ b/common-blacklist.ks @@ -14,7 +14,7 @@ RPMS="$RPMS kpartx mkinitrd isomd5sum dmraid checkpolicy" # Remove additional RPMs forcefully RPMS="$RPMS gamin pm-utils kbd usermode vbetool ConsoleKit hdparm \ - efibootmgr krb5-workstation linux-atm-libs fedora-release-notes \ + efibootmgr linux-atm-libs fedora-release-notes \ slang psmisc gdbm cryptsetup-luks pciutils mtools syslinux \ wireless-tools radeontool libicu gnupg2 \ fedora-logos" @@ -85,7 +85,7 @@ blacklist="/boot /etc/alsa /etc/pki /usr/share/hwdata/MonitorsDB \ /usr/share/firstboot /usr/share/lua /usr/share/kde4 /usr/share/pixmaps \ /usr/share/hwdata/videodrivers /usr/share/icons /usr/share/fedora-release \ /usr/share/tabset /usr/share/libvirt /usr/share/augeas/lenses/tests \ - /usr/share/tc /usr/share/emacs /usr/share/info /usr/kerberos \ + /usr/share/tc /usr/share/emacs /usr/share/info \ /usr/src /usr/etc /usr/games /usr/include /usr/local \ /usr/sbin/{dell*,sasldblistusers2,build-locale-archive,glibc_post_upgrade.*}" blacklist_lib="/usr/lib{,64}/gconv \ @@ -131,6 +131,8 @@ drop /usr/lib64/libboost* keep /usr/lib64/libboost_program_options.so* keep /usr/lib64/libboost_filesystem.so* keep /usr/lib64/libboost_thread-mt.so* - +drop /usr/kerberos +keep /usr/kerberos/bin/kinit +keep /usr/kerberos/bin/klist %end -- 1.6.0.4 From imain at redhat.com Thu Jan 29 13:37:42 2009 From: imain at redhat.com (Ian Main) Date: Thu, 29 Jan 2009 05:37:42 -0800 Subject: [Ovirt-devel] [PATCH recipe] Configure qpidd to use gssapi In-Reply-To: <20090129084508.04ad1ab2@tp.mains.net> References: <20090129084508.04ad1ab2@tp.mains.net> Message-ID: <1233236262-7715-1-git-send-email-imain@redhat.com> This adds configuration files for qpidd to allow it to use gssapi for authentication of clients. Note that we still allow 'plain' authentication as well. This is only temporary and is required because there is currently no way to allow localhost connects to be anonymous. Once ruby has gssapi support we can remove the plain authentication. Signed-off-by: Ian Main --- Makefile.am | 1 + appliances/ovirt/files/qpidd.conf | 8 ++++- appliances/ovirt/files/sasl2_qpidd.conf | 47 +++++++++++++++++++++++++++++++ appliances/ovirt/ovirt.pp.in | 5 +++ ovirt-recipe.spec.in | 1 + 5 files changed, 61 insertions(+), 1 deletions(-) create mode 100644 appliances/ovirt/files/sasl2_qpidd.conf diff --git a/Makefile.am b/Makefile.am index 16d3867..8e1451b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -28,6 +28,7 @@ EXTRA_DIST = \ appliances/ovirt/files/cobbler-import \ appliances/ovirt/files/collectd.conf \ appliances/ovirt/files/qpidd.conf \ + appliances/ovirt/files/sasl2_qpidd.conf \ appliances/ovirt/files/ovirt-cfgdb \ appliances/ovirt/files/ovirt.repo \ appliances/ovirt/files/ovirt-dnsmasq.conf \ diff --git a/appliances/ovirt/files/qpidd.conf b/appliances/ovirt/files/qpidd.conf index a7e34bb..bf80918 100644 --- a/appliances/ovirt/files/qpidd.conf +++ b/appliances/ovirt/files/qpidd.conf @@ -1,5 +1,11 @@ # Configuration file for qpidd. Entries are of the form: # name = value # Using default settings: "qpidd --help" or "man qpidd" for more details. -auth=no + + +# This is where we want to be, but we can't actually do that yet because +# we have unencrypted db-omatic and taskomatic running over localhost. +# This will change shortly once we have gssapi support for ruby. +# +#require-encryption diff --git a/appliances/ovirt/files/sasl2_qpidd.conf b/appliances/ovirt/files/sasl2_qpidd.conf new file mode 100644 index 0000000..c61131f --- /dev/null +++ b/appliances/ovirt/files/sasl2_qpidd.conf @@ -0,0 +1,47 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# +# This configuation allows for either SASL PLAIN or ANONYMOUS +# authentication. The PLAIN authentication is done on a +# username+password, which is stored in the sasldb_path +# file. Usernames and passwords can be added to the file using the +# command: +# +# saslpasswd2 -f /var/lib/qpidd/qpidd.sasldb -u +# +# The REALM is important and should be the same as the --auth-realm +# option to the broker. This lets the broker properly find the user in +# the sasldb file. +# +# Existing user accounts may be listed with: +# +# sasldblistusers2 -f /var/lib/qpidd/qpidd.sasldb +# +# NOTE: The sasldb file must be readable by the user running the qpidd +# daemon, and should be readable only by that user. +# +pwcheck_method: auxprop +auxprop_plugin: sasldb +sasldb_path: /var/lib/qpidd/qpidd.sasldb + +# For now we allow plain auth too because the local daemons do not yet +# support kerberos. +mech_list: gssapi plain +keytab: /usr/share/ovirt-server/ovirt.keytab + diff --git a/appliances/ovirt/ovirt.pp.in b/appliances/ovirt/ovirt.pp.in index f409ee3..c61f2b2 100644 --- a/appliances/ovirt/ovirt.pp.in +++ b/appliances/ovirt/ovirt.pp.in @@ -88,6 +88,11 @@ file {"/etc/qpidd.conf": notify => Service["qpidd"] } +file {"/etc/sasl2/qpidd.conf": + source => "puppet:///ovirt/sasl2_qpidd.conf", + notify => Service["qpidd"] +} + file {"/var/www/html/ovirt-cfgdb": source => "puppet:///ovirt/ovirt-cfgdb" } diff --git a/ovirt-recipe.spec.in b/ovirt-recipe.spec.in index ea51c3a..e8aa596 100644 --- a/ovirt-recipe.spec.in +++ b/ovirt-recipe.spec.in @@ -38,6 +38,7 @@ Requires: syslinux Requires: lokkit Requires: curl Requires: qpidd +Requires: cyrus-sasl-plain Requires: rubygem-qpid Requires: qpidc Requires: qmf -- 1.6.0.4 From imain at redhat.com Thu Jan 29 13:38:04 2009 From: imain at redhat.com (Ian Main) Date: Thu, 29 Jan 2009 05:38:04 -0800 Subject: [Ovirt-devel] [PATCH] Set up kerberos authentication for qpidd In-Reply-To: <20090129084508.04ad1ab2@tp.mains.net> References: <20090129084508.04ad1ab2@tp.mains.net> Message-ID: <1233236284-7758-1-git-send-email-imain@redhat.com> This patch generates a kerberos principal for qpidd and adds it to the ovirt principal. It also changes the localhost qmf apps to use plain sasl auth as there's no way to configure qpidd to accept anonymous connections over localhost. Once gssapi is supported by ruby (any day now) we can change those over to using gssapi as well. Signed-off-by: Ian Main --- scripts/ovirt-add-host | 10 +++++++--- src/db-omatic/db_omatic.rb | 2 +- src/host-browser/host-browser.rb | 3 +++ src/qmf-libvirt-example.rb | 2 +- src/task-omatic/taskomatic.rb | 2 +- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/scripts/ovirt-add-host b/scripts/ovirt-add-host index 700e2ac..c6b7cd2 100755 --- a/scripts/ovirt-add-host +++ b/scripts/ovirt-add-host @@ -23,6 +23,8 @@ default_realm = krbV.Context().default_realm ipaddr = get_ip(sys.argv[1]) libvirt_princ = 'libvirt/' + sys.argv[1] + '@' + default_realm +qpidd_princ = 'qpidd/' + sys.argv[1] + '@' + default_realm + if len(sys.argv) > 2: outname = sys.argv[2] else: @@ -33,6 +35,8 @@ else: kadmin_local('addprinc -randkey +requires_preauth ' + libvirt_princ) kadmin_local('ktadd -k ' + outname + ' ' + libvirt_princ) -if len(sys.argv) <= 2: - # make sure it is readable by apache - os.chmod(outname, 0644) +kadmin_local('addprinc -randkey ' + qpidd_princ) +kadmin_local('ktadd -k ' + outname + ' ' + qpidd_princ) + +# make sure it is readable by apache and qpidd. +os.chmod(outname, 0644) diff --git a/src/db-omatic/db_omatic.rb b/src/db-omatic/db_omatic.rb index 4afffb1..2ba9456 100755 --- a/src/db-omatic/db_omatic.rb +++ b/src/db-omatic/db_omatic.rb @@ -326,7 +326,7 @@ def main() dbsync = DbOmatic.new() s = Qpid::Qmf::Session.new(:console => dbsync, :rcv_events => false) - b = s.add_broker("amqp://localhost:5672") + b = s.add_broker("amqp://guest:guest at localhost:5672") dbsync.db_init_cleanup() diff --git a/src/host-browser/host-browser.rb b/src/host-browser/host-browser.rb index 852d6bf..579f241 100755 --- a/src/host-browser/host-browser.rb +++ b/src/host-browser/host-browser.rb @@ -328,6 +328,7 @@ class HostBrowser krb5 = krb5_arg || Krb5.new default_realm = krb5.get_default_realm + qpidd_princ = 'qpidd/' + hostname + '@' + default_realm libvirt_princ = 'libvirt/' + hostname + '@' + default_realm outfile = ipaddress + '-libvirt.tab' @keytab_filename = @keytab_dir + outfile @@ -338,6 +339,8 @@ class HostBrowser puts "Writing keytab file: #{@keytab_filename}" unless defined?(TESTING) kadmin_local('addprinc -randkey ' + libvirt_princ) kadmin_local('ktadd -k ' + @keytab_filename + ' ' + libvirt_princ) + kadmin_local('addprinc -randkey ' + qpidd_princ) + kadmin_local('ktadd -k ' + @keytab_filename + ' ' + qpidd_princ) File.chmod(0644, at keytab_filename) end diff --git a/src/qmf-libvirt-example.rb b/src/qmf-libvirt-example.rb index 5bfe44d..8fac3c9 100644 --- a/src/qmf-libvirt-example.rb +++ b/src/qmf-libvirt-example.rb @@ -4,7 +4,7 @@ require "rubygems" require "qpid" s = Qpid::Qmf::Session.new() -b = s.add_broker("amqp://localhost:5672") +b = s.add_broker("amqp://guest:guest at localhost:5672") while true: nodes = s.objects(:class => "node") diff --git a/src/task-omatic/taskomatic.rb b/src/task-omatic/taskomatic.rb index bcb9bd3..0570246 100755 --- a/src/task-omatic/taskomatic.rb +++ b/src/task-omatic/taskomatic.rb @@ -47,7 +47,7 @@ class TaskOmatic @session = Qpid::Qmf::Session.new() # FIXME: Should come from some kind of config or DNS SRV or what have you. - @broker = @session.add_broker("amqp://localhost:5672") + @broker = @session.add_broker("amqp://guest:guest at localhost:5672") do_daemon = true -- 1.6.0.4 From berrange at redhat.com Thu Jan 29 16:56:10 2009 From: berrange at redhat.com (Daniel P. Berrange) Date: Thu, 29 Jan 2009 16:56:10 +0000 Subject: [Ovirt-devel] gssapi/kerberos support for qpidd In-Reply-To: <20090129084508.04ad1ab2@tp.mains.net> References: <20090129084508.04ad1ab2@tp.mains.net> Message-ID: <20090129165610.GQ22110@redhat.com> On Thu, Jan 29, 2009 at 08:45:08AM -0800, Ian Main wrote: > > This set of patches adds support gssapi/kerberos to qpidd. You'll > note that it's still not secure as we allow 'plain' auth with a > guest account for daemons that connect over localhost (taskomatic, > dbomatic etc.) and unfortunately there's no way to constrain that > to localhost connections at this time. Doesn't QPidd have UNIX domain socket support ? We shouldn't really use TCP over 'localhost' for local connections, since it is just unneccessarily increasing latency & overheads. Unless you really do need/want to authenticate local connections with GSSAPI too, there'd be no particular need to run GSSAPI over the UNIX domain socket, just rely on the filesystem permissioning on the socket to restrict access. Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| From imain at redhat.com Thu Jan 29 17:28:48 2009 From: imain at redhat.com (Ian Main) Date: Thu, 29 Jan 2009 09:28:48 -0800 Subject: [Ovirt-devel] gssapi/kerberos support for qpidd In-Reply-To: <20090129165610.GQ22110@redhat.com> References: <20090129084508.04ad1ab2@tp.mains.net> <20090129165610.GQ22110@redhat.com> Message-ID: <20090129092848.39dcff86@tp.mains.net> On Thu, 29 Jan 2009 16:56:10 +0000 "Daniel P. Berrange" wrote: > On Thu, Jan 29, 2009 at 08:45:08AM -0800, Ian Main wrote: > > > > This set of patches adds support gssapi/kerberos to qpidd. You'll > > note that it's still not secure as we allow 'plain' auth with a > > guest account for daemons that connect over localhost (taskomatic, > > dbomatic etc.) and unfortunately there's no way to constrain that > > to localhost connections at this time. > > Doesn't QPidd have UNIX domain socket support ? We shouldn't really > use TCP over 'localhost' for local connections, since it is just > unneccessarily increasing latency & overheads. > > Unless you really do need/want to authenticate local connections with GSSAPI > too, there'd be no particular need to run GSSAPI over the UNIX domain socket, > just rely on the filesystem permissioning on the socket to restrict access. Yeah that would be nice wouldn't it? :) Unfortunately it doesn't support domain sockets. OTOH though I think we do want to support having eg taskomatic on other machines so gssapi will be needed in the end anyway. I do agree it is very heavy for localhost but I think we can live with it. Ian From katzj at redhat.com Thu Jan 29 18:28:45 2009 From: katzj at redhat.com (Jeremy Katz) Date: Thu, 29 Jan 2009 13:28:45 -0500 Subject: [Ovirt-devel] [PATCH node-image] Add kinit to node In-Reply-To: <1233236233-7672-1-git-send-email-imain@redhat.com> References: <20090129084508.04ad1ab2@tp.mains.net> <1233236233-7672-1-git-send-email-imain@redhat.com> Message-ID: <20090129182844.GA33344@redhat.com> On Thursday, January 29 2009, Ian Main said: > This patch adds krb5-workstation package to the node, but then we > remove all but kinit and klist (for debugging purposes). This is > to support libvirt-qpid needing a kerberos ticket. Instead of calling kinit explicitly, why not use rubygem-krb5-auth? It looks like there should be support for initializing a ccache there already Jeremy From Brian.Carb at unisys.com Thu Jan 29 19:50:23 2009 From: Brian.Carb at unisys.com (Carb, Brian A) Date: Thu, 29 Jan 2009 13:50:23 -0600 Subject: [Ovirt-devel] Installing a VM in oVirt 0.96 In-Reply-To: <20090129164641.491FB8E0371@hormel.redhat.com> References: <20090129164641.491FB8E0371@hormel.redhat.com> Message-ID: <0AAE5AB84B013E45A7B61CB66943C17215B5DCF688@USEA-EXCH7.na.uis.unisys.com> Installing a VM in oVirt Appliance Host: Dell Optiplex 745, VT-capable, x86_64 Nodes: four cells of ES7000/one, each with 8x at 3.4GHz and 32GB memory Downloaded and installed 0.96 release on top of Fedora10 as indicated in the documentation. Successfully PXE booted 4 ES7000 nodes, and all show up in the oVirt dashboard. Defined a storage pool using the /ovirtnfs share from the appliance at 192.168.50.2 Created a Virtual Machine using one of the NFS disks, 4cpu and 1024mb However, I'm unable to install into that VM. If I launch the QEMU viewer as the VM launches, I can select the Fedora option from the PXE installer... but the fedora install always reports an error with the network interface. If I select retry, the install goes a little farther, downloading the install.img and running the installer. However the system hangs for a long time at "Retrieving installation information for f10-x86_64-updates..." and then fails at "Unable to read package metadata..." Any ideas? Also, I saw someone mentioned installation from an ISO - is this supported? Is it possible to use existing VM images? I might be able to specify "boot from HD" and then dd an existing image - but i was looking for a more official method :-) brian carb unisys corporation - malvern, pa brian.carb at unisys.com From sseago at redhat.com Thu Jan 29 20:33:05 2009 From: sseago at redhat.com (Scott Seago) Date: Thu, 29 Jan 2009 15:33:05 -0500 Subject: [Ovirt-devel] [PATCH server] Fix smart pools in nav. In-Reply-To: <1233168470-20596-1-git-send-email-jguiditt@redhat.com> References: <1233168470-20596-1-git-send-email-jguiditt@redhat.com> Message-ID: <49821281.3080203@redhat.com> Jason Guiditta wrote: > They were not updating when you added a new one because We were > only recursing down through children if an element was not changed, > rather than always if there were children. If I recall correctly, > this was originally to save processing time, but with recent > changes, it is no longer accurate. > > Also realized that tree_controller was not splitting properly based > on name, so if you had a name with '-'s in it, it would always return > as 'changed'. In addition, the 'smart root' never changes (at least by > the user) so make state='unchanged'. > > Signed-off-by: Jason Guiditta > --- > src/app/controllers/tree_controller.rb | 3 ++- > src/public/javascripts/ovirt.tree.js | 8 +++----- > 2 files changed, 5 insertions(+), 6 deletions(-) > > ACK, Works for me Scott From pmyers at redhat.com Fri Jan 30 00:50:18 2009 From: pmyers at redhat.com (Perry Myers) Date: Thu, 29 Jan 2009 19:50:18 -0500 Subject: [Ovirt-devel] [PATCH node-image] Only lock root account for production builds. For non-release builds leave it open Message-ID: <1233276618-29912-1-git-send-email-pmyers@redhat.com> This makes it easier for developers to do work Signed-off-by: Perry Myers --- common-post.ks | 9 ++++++--- 1 files changed, 6 insertions(+), 3 deletions(-) diff --git a/common-post.ks b/common-post.ks index ffc459c..08dd6c0 100644 --- a/common-post.ks +++ b/common-post.ks @@ -87,6 +87,9 @@ sed -i '/rm -f \/etc\/localtime/d' $DHSCRIPT sed -i '/rm -f \/etc\/ntp.conf/d' $DHSCRIPT sed -i '/rm -f \/etc\/yp.conf/d' $DHSCRIPT -# By default, lock the root account. It is only unlocked after the -# root password is set in the ovirt-config-password script. -passwd -l root +if rpm -q --qf '%{release}' ovirt-node | grep "0\..*" > /dev/null 2>&1 ; then + echo "Building in developer mode, leaving root account unlocked" +else + echo "Building in production mode, locking root account" + passwd -l root +fi -- 1.6.0.6 From imain at redhat.com Fri Jan 30 00:50:50 2009 From: imain at redhat.com (Ian Main) Date: Thu, 29 Jan 2009 16:50:50 -0800 Subject: [Ovirt-devel] [PATCH node-image] Add kinit to node In-Reply-To: <20090129182844.GA33344@redhat.com> References: <20090129084508.04ad1ab2@tp.mains.net> <1233236233-7672-1-git-send-email-imain@redhat.com> <20090129182844.GA33344@redhat.com> Message-ID: <20090129165050.5e3d18fc@tp.mains.net> On Thu, 29 Jan 2009 13:28:45 -0500 Jeremy Katz wrote: > On Thursday, January 29 2009, Ian Main said: > > This patch adds krb5-workstation package to the node, but then we > > remove all but kinit and klist (for debugging purposes). This is > > to support libvirt-qpid needing a kerberos ticket. > > Instead of calling kinit explicitly, why not use rubygem-krb5-auth? It > looks like there should be support for initializing a ccache there > already There is no ruby on the node.. no interpreted languages at all cept sh. I think this is the most expedient and smallest footprint way of achieving this.. kinit is only 24kB, klist is 20kB. My original intention was to incorporate key management into libvirt-qpid, but after looking at what was involved I figured this was easier and would work just fine. :) Ian From katzj at redhat.com Fri Jan 30 01:09:48 2009 From: katzj at redhat.com (Jeremy Katz) Date: Thu, 29 Jan 2009 20:09:48 -0500 Subject: [Ovirt-devel] [PATCH node-image] Only lock root account for production builds. For non-release builds leave it open In-Reply-To: <1233276618-29912-1-git-send-email-pmyers@redhat.com> References: <1233276618-29912-1-git-send-email-pmyers@redhat.com> Message-ID: <823342F3-1F83-432C-B0D8-436D213D1394@redhat.com> On Jan 29, 2009, at 7:50 PM, Perry Myers wrote: > This makes it easier for developers to do work This looks pretty fragile as the version of a -release package changes over time. Why not instead have it be more explicit as to whether or not the image is "devel" mode and then key off of that either with different snippets or based on something that's actually set in the image Jeremy From pmyers at redhat.com Fri Jan 30 01:14:10 2009 From: pmyers at redhat.com (Perry Myers) Date: Thu, 29 Jan 2009 20:14:10 -0500 Subject: [Ovirt-devel] Re: [PATCH node-image] Only lock root account for production builds. For non-release builds leave it open In-Reply-To: <1233276618-29912-1-git-send-email-pmyers@redhat.com> References: <1233276618-29912-1-git-send-email-pmyers@redhat.com> Message-ID: <49825462.8050209@redhat.com> Perry Myers wrote: > This makes it easier for developers to do work > > Signed-off-by: Perry Myers > --- > common-post.ks | 9 ++++++--- > 1 files changed, 6 insertions(+), 3 deletions(-) > > diff --git a/common-post.ks b/common-post.ks > index ffc459c..08dd6c0 100644 > --- a/common-post.ks > +++ b/common-post.ks > @@ -87,6 +87,9 @@ sed -i '/rm -f \/etc\/localtime/d' $DHSCRIPT > sed -i '/rm -f \/etc\/ntp.conf/d' $DHSCRIPT > sed -i '/rm -f \/etc\/yp.conf/d' $DHSCRIPT > > -# By default, lock the root account. It is only unlocked after the > -# root password is set in the ovirt-config-password script. > -passwd -l root > +if rpm -q --qf '%{release}' ovirt-node | grep "0\..*" > /dev/null 2>&1 ; then > + echo "Building in developer mode, leaving root account unlocked" > +else > + echo "Building in production mode, locking root account" > + passwd -l root > +fi This was acked by Alan and pushed with caveats that I change the grep to be: grep -q "^0\." Perry -- |=- Red Hat, Engineering, Emerging Technologies, Boston -=| |=- Email: pmyers at redhat.com -=| |=- Office: +1 412 474 3552 Mobile: +1 703 362 9622 -=| |=- GnuPG: E65E4F3D 88F9 F1C9 C2F3 1303 01FE 817C C5D2 8B91 E65E 4F3D -=| From pmyers at redhat.com Fri Jan 30 01:19:40 2009 From: pmyers at redhat.com (Perry Myers) Date: Thu, 29 Jan 2009 20:19:40 -0500 Subject: [Ovirt-devel] [PATCH node-image] Only lock root account for production builds. For non-release builds leave it open In-Reply-To: <823342F3-1F83-432C-B0D8-436D213D1394@redhat.com> References: <1233276618-29912-1-git-send-email-pmyers@redhat.com> <823342F3-1F83-432C-B0D8-436D213D1394@redhat.com> Message-ID: <498255AC.7070306@redhat.com> Jeremy Katz wrote: > On Jan 29, 2009, at 7:50 PM, Perry Myers wrote: > >> This makes it easier for developers to do work > > This looks pretty fragile as the version of a -release package changes > over time. Why not instead have it be more explicit as to whether or not > the image is "devel" mode and then key off of that either with different > snippets or based on something that's actually set in the image We have set our build scripts so that a release number of 0 (i.e. indicating a pre-release RPM) indicates that the package is a developer build. In our makefile we have: > # For Release: 0..., set _ovirt_dev=1 so that we get extra_release.GIT- > # annotated rpm version strings. > _ovirt_dev = \ > $(shell grep -q '^[[:space:]]*Release:[[:space:]]*0' \ > $(srcdir)/*.spec.in && echo 1 || :) This causes the following to happen: > GIT_RELEASE = $(shell date --utc +%Y%m%d%H%M%S)git$(git_head) > RPM_FLAGS += $(if $(_ovirt_dev),--define "extra_release .$(GIT_RELEASE)") This is how we tag development builds using the git hash and timestamp. So only when the spec.in file has Release: 0 in it will a 'develpment' build occur. My understanding for the Release field is that the convention is for production builds the field must be > 0 So not sure how this would be considered fragile? Perry From pmyers at redhat.com Fri Jan 30 01:38:08 2009 From: pmyers at redhat.com (Perry Myers) Date: Thu, 29 Jan 2009 20:38:08 -0500 Subject: [Ovirt-devel] Installing a VM in oVirt 0.96 In-Reply-To: <0AAE5AB84B013E45A7B61CB66943C17215B5DCF688@USEA-EXCH7.na.uis.unisys.com> References: <20090129164641.491FB8E0371@hormel.redhat.com> <0AAE5AB84B013E45A7B61CB66943C17215B5DCF688@USEA-EXCH7.na.uis.unisys.com> Message-ID: <49825A00.70209@redhat.com> Carb, Brian A wrote: > Installing a VM in oVirt > > Appliance Host: Dell Optiplex 745, VT-capable, x86_64 Nodes: four cells > of ES7000/one, each with 8x at 3.4GHz and 32GB memory > > Downloaded and installed 0.96 release on top of Fedora10 as indicated > in the documentation. Successfully PXE booted 4 ES7000 nodes, and all > show up in the oVirt dashboard. Defined a storage pool using the > /ovirtnfs share from the appliance at 192.168.50.2 Created a Virtual > Machine using one of the NFS disks, 4cpu and 1024mb > > However, I'm unable to install into that VM. If I launch the QEMU > viewer as the VM launches, I can select the Fedora option from the PXE > installer... but the fedora install always reports an error with the > network interface. If I select retry, the install goes a little > farther, downloading the install.img and running the installer. However > the system hangs for a long time at "Retrieving installation > information for f10-x86_64-updates..." and then fails at "Unable to > read package metadata..." The initial network error you get that is solved with a retry I have seen every time I try to provision Fedora from a kickstart in oVirt. Hitting retry has always fixed it for me. The problem is probably a transient network issue, like the network bridge not being fully up and forwarding traffic by the time the guest gets to this phase of the install. If you have bugzilla access and can file a bug at bugzilla.redhat.com under Other->Virtualization Tools->ovirt-node we'll hunt this down and try to fix it. After the retry though provisioning generally works for me... It could be a few things... The way we have the appliance set up, we provision from cobbler but the cobbler repos are just pointers to upstream Fedora mirrors. So first thing to check would be to make sure that from a Node you can access (ping) the internet. If not, that's probably the issue. If you can, it could be a mirror problem since sometimes mirrors are unreliable. > Any ideas? > > Also, I saw someone mentioned installation from an ISO - is this > supported? Is it possible to use existing VM images? I might be able to > specify "boot from HD" and then dd an existing image - but i was > looking for a more official method :-) We do support provisioning from ISO files. There should be something on the wiki about this, if not Darryl Pierce is the developer who set that up. The short of it is that you add an ISO image to the /cobblernfs directory on the Appliance. Once the ISO is there you need to use the cobbler image add command to add the ISO image to cobbler This will make the image ISO show up in the oVirt UI under the provisioning drop down. Try that out and let me know if it works. For disk image provisioning, we have plans to support that as well. Just not implemented yet... Perry From katzj at redhat.com Fri Jan 30 02:38:08 2009 From: katzj at redhat.com (Jeremy Katz) Date: Thu, 29 Jan 2009 21:38:08 -0500 Subject: [Ovirt-devel] [PATCH node-image] Only lock root account for production builds. For non-release builds leave it open In-Reply-To: <498255AC.7070306@redhat.com> References: <1233276618-29912-1-git-send-email-pmyers@redhat.com> <823342F3-1F83-432C-B0D8-436D213D1394@redhat.com> <498255AC.7070306@redhat.com> Message-ID: <20090130023808.GA33954@redhat.com> On Thursday, January 29 2009, Perry Myers said: > Jeremy Katz wrote: >> On Jan 29, 2009, at 7:50 PM, Perry Myers wrote: >>> This makes it easier for developers to do work >> This looks pretty fragile as the version of a -release package changes >> over time. Why not instead have it be more explicit as to whether or >> not the image is "devel" mode and then key off of that either with >> different snippets or based on something that's actually set in the >> image > > We have set our build scripts so that a release number of 0 (i.e. > indicating a pre-release RPM) indicates that the package is a developer > build. [snip] > This is how we tag development builds using the git hash and timestamp. > > So only when the spec.in file has Release: 0 in it will a 'develpment' > build occur. > > My understanding for the Release field is that the convention is for > production builds the field must be > 0 > > So not sure how this would be considered fragile? Other things can hit the release field including mass rebuilds, rebuilds for depchain changes, etc. Making developer image vs not an explicit setting will make it a lot more clear and a lot easier for other people who are working with the code to have a consistent experience. Jeremy From pmyers at redhat.com Fri Jan 30 02:51:43 2009 From: pmyers at redhat.com (Perry Myers) Date: Thu, 29 Jan 2009 21:51:43 -0500 Subject: [Ovirt-devel] [PATCH node-image] Only lock root account for production builds. For non-release builds leave it open In-Reply-To: <20090130023808.GA33954@redhat.com> References: <1233276618-29912-1-git-send-email-pmyers@redhat.com> <823342F3-1F83-432C-B0D8-436D213D1394@redhat.com> <498255AC.7070306@redhat.com> <20090130023808.GA33954@redhat.com> Message-ID: <49826B3F.6080000@redhat.com> Jeremy Katz wrote: > On Thursday, January 29 2009, Perry Myers said: >> Jeremy Katz wrote: >>> On Jan 29, 2009, at 7:50 PM, Perry Myers wrote: >>>> This makes it easier for developers to do work >>> This looks pretty fragile as the version of a -release package changes >>> over time. Why not instead have it be more explicit as to whether or >>> not the image is "devel" mode and then key off of that either with >>> different snippets or based on something that's actually set in the >>> image >> We have set our build scripts so that a release number of 0 (i.e. >> indicating a pre-release RPM) indicates that the package is a developer >> build. > [snip] >> This is how we tag development builds using the git hash and timestamp. >> >> So only when the spec.in file has Release: 0 in it will a 'develpment' >> build occur. >> >> My understanding for the Release field is that the convention is for >> production builds the field must be > 0 >> >> So not sure how this would be considered fragile? > > Other things can hit the release field including mass rebuilds, rebuilds > for depchain changes, etc. Making developer image vs not an explicit > setting will make it a lot more clear and a lot easier for other people > who are working with the code to have a consistent experience. Point taken. So what do you recommend as a standard way for indicating that an rpm is a development rpm without using the version or release fields? Should the rpm include an empty file like: /usr/share/ovirt-node/devel or something like that, that we can look for later? Or is there a better way to do this? Perry From pmyers at redhat.com Fri Jan 30 03:27:51 2009 From: pmyers at redhat.com (Perry Myers) Date: Thu, 29 Jan 2009 22:27:51 -0500 Subject: [Ovirt-devel] [PATCH appliance] Temporary hack so qpidd will start up properly Message-ID: <1233286071-26721-1-git-send-email-pmyers@redhat.com> I don't intend to apply this patch to the git repo, since this should be fixed by qpid folks. But I'll post this patch for people trying to do builds off of the next trees and are having failures due to qpid packages being broken. qpid project will fix this properly in qpid spec file Signed-off-by: Perry Myers --- ovirt-appliance.ks | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/ovirt-appliance.ks b/ovirt-appliance.ks index 3d03cf7..f7802be 100644 --- a/ovirt-appliance.ks +++ b/ovirt-appliance.ks @@ -55,6 +55,13 @@ ovirt-server-installer lokkit %post + echo "Adding qpidd user" + /usr/sbin/useradd qpidd + chown -vR qpidd /var/lib/qpidd + chown -vR qpidd /var/run/qpidd +%end + +%post # cleanup rpmdb to allow non-matching host and chroot RPM versions rm -f /var/lib/rpm/__db* -- 1.6.0.6 From katzj at redhat.com Fri Jan 30 03:30:09 2009 From: katzj at redhat.com (Jeremy Katz) Date: Thu, 29 Jan 2009 22:30:09 -0500 Subject: [Ovirt-devel] [PATCH node-image] Only lock root account for production builds. For non-release builds leave it open In-Reply-To: <49826B3F.6080000@redhat.com> References: <1233276618-29912-1-git-send-email-pmyers@redhat.com> <823342F3-1F83-432C-B0D8-436D213D1394@redhat.com> <498255AC.7070306@redhat.com> <20090130023808.GA33954@redhat.com> <49826B3F.6080000@redhat.com> Message-ID: <20090130033009.GB33954@redhat.com> On Thursday, January 29 2009, Perry Myers said: > Jeremy Katz wrote: >> On Thursday, January 29 2009, Perry Myers said: >>> Jeremy Katz wrote: >>>> On Jan 29, 2009, at 7:50 PM, Perry Myers wrote: >>>>> This makes it easier for developers to do work >>>> This looks pretty fragile as the version of a -release package >>>> changes over time. Why not instead have it be more explicit as to >>>> whether or not the image is "devel" mode and then key off of that >>>> either with different snippets or based on something that's >>>> actually set in the image >>> We have set our build scripts so that a release number of 0 (i.e. >>> indicating a pre-release RPM) indicates that the package is a >>> developer build. >> [snip] >>> This is how we tag development builds using the git hash and timestamp. >>> >>> So only when the spec.in file has Release: 0 in it will a >>> 'develpment' build occur. >>> >>> My understanding for the Release field is that the convention is for >>> production builds the field must be > 0 >>> >>> So not sure how this would be considered fragile? >> >> Other things can hit the release field including mass rebuilds, rebuilds >> for depchain changes, etc. Making developer image vs not an explicit >> setting will make it a lot more clear and a lot easier for other people >> who are working with the code to have a consistent experience. > > Point taken. So what do you recommend as a standard way for indicating > that an rpm is a development rpm without using the version or release > fields? > > Should the rpm include an empty file like: > /usr/share/ovirt-node/devel > > or something like that, that we can look for later? Or is there a better > way to do this? There's not any definitive way. What's done in anaconda, for example, is to set BETANAG in /usr/lib/anaconda/constants.py. Other apps end up using compile-time definitions. For something like the node, I'd probably lean towards a sysconfig file (/etc/ovirt-node.cfg or similar) and just set shell variable style variables like DEVMODE=1 or yes or similar. That way it's very clear what's going on and people can trivially toggle it accordingly in their own builds Jeremy From pmyers at redhat.com Fri Jan 30 04:11:06 2009 From: pmyers at redhat.com (Perry Myers) Date: Thu, 29 Jan 2009 23:11:06 -0500 Subject: [Ovirt-devel] ovirt-server-installer problems Message-ID: <49827DDA.4030300@redhat.com> I've applied the patches from Joey onto next: [PATCH server] RESEND - required changes to move from ovirt-recipe to ovirt-server-installer [PATCH appliance] RESEND - required changes to move from ovirt-recipe to ovirt-server-installer [PATCH release] RESEND - required changes to move from ovirt-recipe to ovirt-server-installer [PATCH server installer] freeipa_prompt cleanup, selinuxenabled prompt refactor, nameserver now lists 127.0.0.1 entry [PATCH server] dns forward/reverse lookup update / dnsdomainname is default for dhcp domain In conjunction with the temp qpid hack that I just posted: [PATCH appliance] Temporary hack so qpidd will start up properly This patch series should remove the need for ovirt-recipe repo and RPM and replaces appliance creation with use of ovirt-server-installer. Ran into a few problems with the appliance after applying these patches. First thing is that during ace processing the ovirt-rails-mongrel service is started, but later in init the normal ovirt-rails-mongrel service tries to start again and that causes errors on the console. Though I think they are harmless. No obvious errors in ace.log, but when you try to bring up Firefox to log into the UI it doesn't accept the standard ovirtadmin/ovirt authentication. Ah, that's because with the new installer the password changed to 'password'. Ok that's not a problem, but we should make people aware of the change. Also, on reboot after first install, ace fails to refresh the appliance. Log says: > Fri Jan 30 03:41:41 +0000 2009 //postgres::bundled/Single_exec[create_ovirt_development_db]/returns (err): change from notrun to 0 failed: /usr/bin/createdb ovirt_development returned 1 instead of 0 at /usr/share/ace/modules/ovirt/manifests/postgres.pp:57 Looks like on reboots the ace service is trying to update when it is not necessary to update. i.e. no new packages were installed, so why is is trying to update the installation? And if there were new packages installed, looks like the update would fail anyhow because the it's trying to create the ovirt db and since it already exists that fails. Another problem is that the /etc/dnsmasq.conf file needs to have: #conf-dir=/etc/dnsmasq.d uncommented otherwise it won't pick up any files in that directory to process. Also noticed that /etc/dnsmasq.d/ovirt-dhcp.conf on appliance contained: > interface=eth1 > dhcp-range=192.168.50.3,192.168.50.10 > domain=priv.ovirt.org > dhcp-option=option:router,192.168.50.1 > dhcp-option=option:ntp-server,192.168.222.211 > dhcp-option=12 > no-resolv > local=/priv.ovirt.org/ > server= This is wrong for a few reasons.... ntp-server should be 192.168.50.2, dhcp-range shouldn't be so restrictive. Open up at least to .50 so a few more hosts can be booted. And there is no eth1 interface on the appliance. Everything is on eth0 Next problem.... /var/lib/tftpboot is empty which means the cobbler-import script was never run. That script needs to be run on the appliance to create the ovirt node pxe boot images and install them for tftp. It also creates the Fedora cobbler distro so you can install Fedora from the appliance. That's as far as I got in testing, but it looks like there are a few things that need to be cleaned up in the ovirt-server-installer before the next round.... Perry -- |=- Red Hat, Engineering, Emerging Technologies, Boston -=| |=- Email: pmyers at redhat.com -=| |=- Office: +1 412 474 3552 Mobile: +1 703 362 9622 -=| |=- GnuPG: E65E4F3D 88F9 F1C9 C2F3 1303 01FE 817C C5D2 8B91 E65E 4F3D -=| From imain at redhat.com Fri Jan 30 06:08:30 2009 From: imain at redhat.com (Ian Main) Date: Thu, 29 Jan 2009 22:08:30 -0800 Subject: [Ovirt-devel] [PATCH node-image] Add kinit to node In-Reply-To: <20090129165050.5e3d18fc@tp.mains.net> References: <20090129084508.04ad1ab2@tp.mains.net> <1233236233-7672-1-git-send-email-imain@redhat.com> <20090129182844.GA33344@redhat.com> <20090129165050.5e3d18fc@tp.mains.net> Message-ID: <20090129220830.32d2a4c8@tp.mains.net> On Thu, 29 Jan 2009 16:50:50 -0800 Ian Main wrote: > On Thu, 29 Jan 2009 13:28:45 -0500 > Jeremy Katz wrote: > > > On Thursday, January 29 2009, Ian Main said: > > > This patch adds krb5-workstation package to the node, but then we > > > remove all but kinit and klist (for debugging purposes). This is > > > to support libvirt-qpid needing a kerberos ticket. > > > > Instead of calling kinit explicitly, why not use rubygem-krb5-auth? It > > looks like there should be support for initializing a ccache there > > already > > There is no ruby on the node.. no interpreted languages at all cept sh. > I think this is the most expedient and smallest footprint way of achieving > this.. kinit is only 24kB, klist is 20kB. My original intention was to > incorporate key management into libvirt-qpid, but after looking at what > was involved I figured this was easier and would work just fine. :) Sorry, actually I'm wrong, python is now on the node now because of vdsm. Ian From imain at redhat.com Fri Jan 30 06:13:24 2009 From: imain at redhat.com (Ian Main) Date: Thu, 29 Jan 2009 22:13:24 -0800 Subject: [Ovirt-devel] [PATCH appliance] Temporary hack so qpidd will start up properly In-Reply-To: <1233286071-26721-1-git-send-email-pmyers@redhat.com> References: <1233286071-26721-1-git-send-email-pmyers@redhat.com> Message-ID: <20090129221324.1c8f95b1@tp.mains.net> On Thu, 29 Jan 2009 22:27:51 -0500 Perry Myers wrote: > I don't intend to apply this patch to the git repo, since this should > be fixed by qpid folks. But I'll post this patch for people trying > to do builds off of the next trees and are having failures due to > qpid packages being broken. > > qpid project will fix this properly in qpid spec file > > Signed-off-by: Perry Myers [snip] Sorry Perry.. I should have done this sooner.. I uploaded the new qpid rpms out of koji and put them in the ovirt repo so that we can continue to do work/test while we wait for them to hit Fedora updates. Ian From ccurran at redhat.com Fri Jan 30 06:36:21 2009 From: ccurran at redhat.com (Christopher Curran) Date: Fri, 30 Jan 2009 16:36:21 +1000 Subject: [Ovirt-devel] [PATCH node-image] adding man pages for ovirt-flash and ovirt-pxe] Message-ID: <49829FE5.6090901@redhat.com> I should send this to the right list. Chris -------------- next part -------------- An embedded message was scrubbed... From: Chris Curran Subject: [PATCH] adding man pages for ovirt-flash and ovirt-pxe Date: Thu, 29 Jan 2009 18:00:38 +1000 Size: 4659 URL: From apevec at gmail.com Fri Jan 30 11:45:43 2009 From: apevec at gmail.com (Alan Pevec) Date: Fri, 30 Jan 2009 12:45:43 +0100 Subject: [Ovirt-devel] [PATCH node-image] adding man pages for ovirt-flash and ovirt-pxe] In-Reply-To: <49829FE5.6090901@redhat.com> References: <49829FE5.6090901@redhat.com> Message-ID: <2be7262f0901300345w2e08116ah2b404cca6b0f09cf@mail.gmail.com> > manuals/ovirt-flash.1 | 35 +++++++++++++++++++++++++++++++++++ this command should actually go away now that livecd-tools-021 (in ovirt.org YUM repo, run yum --enablerepo=ovirt update livecd-tools to get it) have added --format option It's just a convenience wrapper which was doing formatting of the USB storage. But please update the man page for livecd-iso-to-disk in upstream livecd-tools ( http://git.fedorahosted.org/git/?p=livecd;a=summary ) it's out of date: # livecd-iso-to-disk --help /usr/bin/livecd-iso-to-disk [--format] [--reset-mbr] [--noverify] [--overlay-size-mb ] [--home-size-mb ] [--unencrypted-home] [--skipcopy] # man livecd-iso-to-disk ... SYNOPSIS livecd-iso-to-disk [--reset-mbr] [--noverify] [--overlay-size-mb ] > manuals/ovirt-pxe.1 | 29 +++++++++++++++++++++++++++++ this one looks good, just replace the reference to ovirt-flash with livecd-iso-to-disk From apevec at gmail.com Fri Jan 30 11:48:39 2009 From: apevec at gmail.com (Alan Pevec) Date: Fri, 30 Jan 2009 12:48:39 +0100 Subject: [Ovirt-devel] [PATCH node-image] adding man pages for ovirt-flash and ovirt-pxe] In-Reply-To: <2be7262f0901300345w2e08116ah2b404cca6b0f09cf@mail.gmail.com> References: <49829FE5.6090901@redhat.com> <2be7262f0901300345w2e08116ah2b404cca6b0f09cf@mail.gmail.com> Message-ID: <2be7262f0901300348vaebcc32q70e0bb0ce50d7867@mail.gmail.com> On Fri, Jan 30, 2009 at 12:45 PM, Alan Pevec wrote: >> manuals/ovirt-pxe.1 | 29 +++++++++++++++++++++++++++++ > > this one looks good, just replace the reference to ovirt-flash with > livecd-iso-to-disk and I forgot:: please use POD, it's much easier to maintain: http://git.fedorahosted.org/git/?p=livecd;a=blob;f=docs/livecd-iso-to-disk.pod From pronix.service at gmail.com Fri Jan 30 14:43:41 2009 From: pronix.service at gmail.com (=?UTF-8?B?0JLQsNGB0LjQu9C10YYg0JTQvNC40YLRgNC40Lk=?=) Date: Fri, 30 Jan 2009 17:43:41 +0300 Subject: [Ovirt-devel] ovirt-server patch for vm failover and actual data set to db In-Reply-To: <639ce0480901271047l375c4d23i27e91256bf913b8@mail.gmail.com> References: <639ce0480901210751s5cd1991esa011e8776b530e48@mail.gmail.com> <20090127101817.1e544a60@tp.mains.net> <497F5532.6090602@redhat.com> <639ce0480901271047l375c4d23i27e91256bf913b8@mail.gmail.com> Message-ID: <639ce0480901300643o20c2e9a7wd4c13d6d06bed0dd@mail.gmail.com> i split patch and reformat it first part is for set actual data to db about vm second add wui button for enable/disable restart vm if crash host and code for do it (without fencing mechanism) if source corrupt by mail agent i attach both files *PATCH.1* diff --git a/src/db-omatic/db_omatic.rb b/src/db-omatic/db_omatic.rb index 4afffb1..c499610 100755 --- a/src/db-omatic/db_omatic.rb +++ b/src/db-omatic/db_omatic.rb @@ -74,6 +74,64 @@ class DbOmatic < Qpid::Qmf::Console domain[:synced] = true end + #find hostname from values['node'] where values['class_type'] == 'domain' + def get_host_id(abank,bbank) + begin + @cached_objects.keys.each do |objkey| + if @cached_objects[objkey][:agent_bank].to_s == abank and @cached_objects[objkey][:broker_bank].to_s == bbank and @cached_objects[objkey][:class_type].to_s == 'node' + return Host.find(:first, :conditions => ['hostname = ?', at cached_objects[objkey]["hostname"].to_s]).id + break + end + end + rescue => ex + log("error in get_host_id") + log(ex) + end + end + + def set_host(values,digit) + begin + vm = Vm.find(:first, :conditions => ['description = ?',values["name"].to_s]) + if vm and digit + vm.host_id = digit + vm.save! + else + log("this vm not exist #{values["name"]}") + end + rescue => ex + puts "error when set_host for #{values["name"]}" + puts ex + end + end + + def start_crashed_vm(vm) + task = VmTask.new( :user => 'db-omatic', :task_target => vm, :action => 'start_vm', :state => 'queued') + task.save! + log("set task for start crashed vm #{vm.id}") + end + + def set_domain_stopped(domain) + begin + vm = Vm.find(:first, :conditions => ['uuid = ?', domain['uuid']]) + if vm != nil + curstate = vm.state + vm.state = Vm::STATE_STOPPED + vm.host_id = nil + vm.save + domain['state'] = 'crashed' # and now i will use ipmi for reboot anavailable host - simple fencing + if curstate == Vm::STATE_RUNNING and vm.ha # vm.ha true or false + start_crashed_vm(vm) + end + else + log('vm == nil ') + end + log("domain #{domain['id']} already stopped") + rescue => ex + log("can\'t set domain #{domain['id']} stopped") + log(ex) + end + end + def update_host_state(host_info, state) db_host = Host.find(:first, :conditions => [ "hostname = ?", host_info['hostname'] ]) if db_host @@ -131,6 +189,7 @@ class DbOmatic < Qpid::Qmf::Console domain_state_change = false + change_node = false obj.properties.each do |key, newval| if values[key.to_s] != newval values[key.to_s] = newval @@ -138,12 +197,30 @@ class DbOmatic < Qpid::Qmf::Console if type == "domain" and key.to_s == "state" domain_state_change = true end + if type == "domain" and key.to_s == "node" + change_node = true + end + + end end if domain_state_change update_domain_state(values) end + if change_node + values.each do |key,val| + if key == 'state' and val == 'running' + abank = values['node'].to_s.split('-')[3] + bbank = values['node'].to_s.split('-')[4] + @@host_id = get_host_id(abank,bbank) + set_host(values,@@host_id) + log("update node data for #{values['name']}") + break + end + end + end + if new_object if type == "node" @@ -187,11 +264,6 @@ class DbOmatic < Qpid::Qmf::Console end end - - def del_agent(agent) - agent_disconnected(agent) - end - # This method marks objects associated with the given agent as timed out/invalid. Called either # when the agent heartbeats out, or we get a del_agent callback. def agent_disconnected(agent) @@ -205,8 +277,10 @@ class DbOmatic < Qpid::Qmf::Console if values[:class_type] == 'node' update_host_state(values, Host::STATE_UNAVAILABLE) elsif values[:class_type] == 'domain' - update_domain_state(values, Vm::STATE_UNREACHABLE) - end + set_domain_stopped(values) + values[:timed_out] = true + @cached_objects.delete(objkey) + end end values[:timed_out] = true end @@ -248,6 +322,7 @@ class DbOmatic < Qpid::Qmf::Console db_vm = Vm.find(:all) db_vm.each do |vm| log "Marking vm #{vm.description} as stopped." + vm.host_id = nil vm.state = Vm::STATE_STOPPED vm.save end *PATCH.2* diff --git a/src/app/controllers/vm_controller.rb b/src/app/controllers/vm_controller.rb index 56501fd..0f43680 100644 --- a/src/app/controllers/vm_controller.rb +++ b/src/app/controllers/vm_controller.rb @@ -20,11 +20,22 @@ require 'socket' class VmController < ApplicationController # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html) - verify :method => :post, :only => [ :destroy, :create, :update ], + verify :method => :post, :only => [ :destroy, :create, :update , :change_ha_vm], :redirect_to => { :controller => 'dashboard' } before_filter :pre_vm_action, :only => [:vm_action, :cancel_queued_tasks, :console] + def change_ha_vm + vm = Vm.find_by_id(params[:id]) + if vm.ha + then vm.ha = false + else vm.ha = true + end + vm.save! + alert = "vm was change ha successfully " + render :json => { :object => "vm", :success => true, :alert => alert } + end + def index roles = "('" + Permission::roles_for_privilege(Permission::PRIV_VIEW).join("', '") + diff --git a/src/app/views/vm/show.rhtml b/src/app/views/vm/show.rhtml index f361131..4809bbe 100644 --- a/src/app/views/vm/show.rhtml +++ b/src/app/views/vm/show.rhtml @@ -29,6 +29,9 @@ <% end -%> <% end %> + + <%= image_tag "icon_x.png" %> Change HA + <%= image_tag "icon_x.png" %> Cancel queued tasks @@ -40,6 +43,19 @@ <%= confirmation_dialog("confirm_cancel", "Are you sure?", "cancel_queued_tasks()") %> <%= confirmation_dialog("confirm_delete", "Are you sure?", "delete_vm()") %>