From pmyers at redhat.com Tue Jul 1 00:00:08 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Mon, 30 Jun 2008 20:00:08 -0400 Subject: [Ovirt-devel] [PATCH] Add additional blacklisting and rpm removal to managed node In-Reply-To: <20080630165628.58582eb5@tp.mains.net> References: <1214829972-22991-1-git-send-email-pmyers@redhat.com> <4868DCA7.8060401@redhat.com> <20080630165628.58582eb5@tp.mains.net> Message-ID: <48697388.6000603@redhat.com> Ian Main wrote: > On Mon, 30 Jun 2008 15:16:23 +0200 > Chris Lalancette wrote: > >> Perry Myers wrote: >>> A few important notes: >>> 1. /lib/modules was scoured for things that didn't seem necessary, however >>> my notion of not necessary may not be correct. Please review the list >>> of modules that I'm removing and if you see one that we need to add back >>> in, comment. >>> 2. /boot is removed as we don't need an initrd and kernel image inside of >>> the livecd initrd. >> Ah yes, good to remove this, since it is superflous. >> >>> 3. The blacklisting method is a hack. What we need is an appliance creator >>> that has black/whitelisting capabilities... (hint, hint to our AOS >>> friends out there) >>> >>> The ISO image RPM is down to 45MB >>> PXE image RPM is at 52MB >>> Running filesystem is 130MB >> My question is: so? I don't really see how it's much of an improvement over >> what we already have. Or rather, it's an improvement, but in my opinion the >> cost (breaking RPM, breaking RPM dependencies, etc) is too high. > > [snip] > >> Overall, seems to be breaking a lot of debug and reproducibility functionality >> for very little gain. > > I think we should bring back the idea of having a debug image and a production > image. Have your cake and eat it too.. might be a bit more to maintain though.. > have to think about that. This is a double edged sword... Having multiple image types means that we can have custom spins for developers, specific hardware types, etc. But it also means that we need to test -each- of these images. It's very easy to fall into a trap where everyone uses the developer image and then you go to release and start seeing unforeseen problems in the production images. To note: there are no changes in this patch that affect developer usability. I intentionally left in vi, userland utils, sshd, etc... So at this point with this patch there is no need to split developer/production images. However, if we need to minimize further than this we may need to consider splitting. Perry From pmyers at redhat.com Tue Jul 1 00:05:45 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Mon, 30 Jun 2008 20:05:45 -0400 Subject: [Ovirt-devel] [PATCH] Add additional blacklisting and rpm removal to managed node In-Reply-To: <4868DCA7.8060401@redhat.com> References: <1214829972-22991-1-git-send-email-pmyers@redhat.com> <4868DCA7.8060401@redhat.com> Message-ID: <486974D9.4070508@redhat.com> Chris Lalancette wrote: > Perry Myers wrote: >> A few important notes: >> 1. /lib/modules was scoured for things that didn't seem necessary, however >> my notion of not necessary may not be correct. Please review the list >> of modules that I'm removing and if you see one that we need to add back >> in, comment. >> 2. /boot is removed as we don't need an initrd and kernel image inside of >> the livecd initrd. > > Ah yes, good to remove this, since it is superflous. > >> 3. The blacklisting method is a hack. What we need is an appliance creator >> that has black/whitelisting capabilities... (hint, hint to our AOS >> friends out there) >> >> The ISO image RPM is down to 45MB >> PXE image RPM is at 52MB >> Running filesystem is 130MB > > My question is: so? I don't really see how it's much of an improvement over > what we already have. Or rather, it's an improvement, but in my opinion the > cost (breaking RPM, breaking RPM dependencies, etc) is too high. This patch doesn't break RPM. It does break some dependencies since we're doing rpm -e --nodeps on a handful of packages. But this is necessary if we want the embedded hypervisor to live up to its name (i.e. embedded). As to whether or not living up to the embedded moniker is important, that's a completely different issue. >> echo "Removing excess kernel modules" >> MODULES="/lib/modules/*/kernel" >> @@ -438,16 +421,60 @@ fs_mods="fs/nls fs/9p fs/affs fs/autofs fs/autofs4 fs/befs fs/bfs fs/cifs \ >> net_mods="net/802 net/8021q net/9p net/appletalk net/atm net/ax25 \ >> net/bluetooth net/dccp net/decnet net/ieee80211 net/ipx net/irda \ >> net/mac80211 net/netrom net/rfkill net/rose net/sched net/tipc \ >> - net/wanrouter net/wireless drivers/auxdisplay drivers/net/appletalk \ >> + net/wanrouter net/wireless" >> + >> +driver_mods="drivers/auxdisplay drivers/net/appletalk \ >> drivers/net/hamradio drivers/net/pcmcia drivers/net/tokenring \ >> - drivers/net/wireless drivers/net/irda drivers/atm drivers/usb/atm" >> + drivers/net/wireless drivers/net/irda drivers/atm drivers/usb/atm \ >> + drivers/acpi drivers/char/drm drivers/char/hw_random drivers/char/mwave \ > > We probably want to keep hw_random for feeding the random number generator in > the future, especially because: a) we don't keep our entropy pool across > reboots, b) we might be running diskless, and c) not all NIC devices contribute > entropy. I'll add these back in and resubmit the patch. >> + drivers/char/ipmp drivers/char/pcmcia drivers/crypto drivers/dca \ >> + drivers/dma drivers/edac drivers/firmware drivers/hwmon > > We definitely need to keep drivers/edac around for reporting errors. Same goes > for drivers/hwmon Ditto >> + drivers/memstick drivers/mmc drivers/mfs drivers/parport \ >> + drivers/serial drivers/video drivers/watchdog drivers/net/ppp* \ >> + drivers/usb/serial drivers/usb/misc drivers/usb/class \ >> + drivers/usb/image drivers/rtc" > > The serial stuff will be useful for debugging, and some administrators might > want to use a serial concentrator to see what's going on with their nodes. Ditto, though we don't provide a way to change the boot options so that serial console is enabled. Should we do this by default perhaps? I'd be tempted to put drivers/serial in but not drivers/usb/serial as that's sort of a fringe case. Most people are going to have real serial ports on servers, probably not needing USB serial devices. >> >> misc_mods="drivers/bluetooth drivers/firewire drivers/i2c drivers/isdn \ >> drivers/media drivers/misc drivers/leds drivers/mtd drivers/w1 sound \ >> - drivers/input drivers/pcmcia drivers/scsi/pcmcia" >> + drivers/input drivers/pcmcia drivers/scsi/pcmcia arch/x86/oprofile \ >> + crypto lib" > > oprofile might be useful in the future, for profiling the nodes, but we haven't > given any thought to it yet. It's small anyhow. I'll add it back in. >> >> -for mods in $fs_mods $net_mods $misc_mods ; do >> +for mods in $fs_mods $net_mods $misc_mods $driver_mods ; do >> $RM $MODULES/$mods >> done >> >> -echo "Finished Kickstart Post" >> +echo "Removing all timezones except for UTC" >> +find /usr/share/zoneinfo -regextype egrep -type f \ >> + ! -regex ".*/UTC" -exec $RM {} \; >> +# XXX anaconda/timezone.py does it, missing in imgcreate/kickstart.py >> +cp /usr/share/zoneinfo/UTC /etc/localtime >> + >> +echo "Removing blacklisted files and directories" >> +blacklist="/boot /etc/alsa /etc/pki /usr/share/hwdata/MonitorsDB \ >> + /usr/share/hwdata/oui.txt /usr/share/hwdata/videoaliases \ >> + /usr/share/hwdata/videodrivers /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/src /usr/etc /usr/games /usr/include /usr/local /usr/lib64/python2.5 \ >> + /usr/lib64/tc /usr/lib64/tls /usr/lib64/sse2 /usr/lib64/pkgconfig \ >> + /usr/lib64/nss /usr/lib64/X11 /usr/lib64/games /usr/lib64/alsa-lib \ >> + /usr/lib64/fs/reiserfs /usr/lib64/krb5 /usr/lib64/hal /usr/lib64/gio \ >> + /usr/bin/hal-device /usr/bin/hal-disable-polling \ >> + /usr/bin/hal-find-by-capability /usr/bin/hal-find-by-property \ >> + /usr/bin/hal-is-caller-locked-out /usr/bin/hal-is-caller-privileged \ >> + /usr/bin/hal-lock /usr/bin/hal-set-property /usr/bin/hal-setup-keymap \ >> + /usr/sbin/dell* /lib/terminfo/d /lib/terminfo/v /lib/terminfo/a \ >> + /lib/firmware /lib/security /usr/lib/locale /usr/lib/syslinux \ >> + /usr/lib64/gconv /usr/lib64/pango /usr/lib64/libpango* /etc/pango \ >> + /usr/bin/pango*" >> + >> +docs_blacklist="/usr/share/omf /usr/share/gnome /usr/share/doc \ >> + /usr/share/locale /usr/share/libthai /usr/share/man /usr/share/terminfo \ >> + /usr/share/X11 /usr/share/i18n" >> + >> +$RM $blacklist $docs_blacklist >> + >> +echo "Cleanup empty directory structures in /usr/share" >> +find /usr/share -type d -exec rmdir {} \; > /dev/null 2>&1 >> + >> +echo "Finished Kickstart Common Post" > > Overall, seems to be breaking a lot of debug and reproducibility functionality > for very little gain. I don't see how this break reproducibility. There will be one image, just stripped down to be smaller. As for breaking debug, I'll add serial/oprofile mods back in, so with those added back do you feel that anything else breaks debugging support? 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 jeffschroed at gmail.com Tue Jul 1 00:16:36 2008 From: jeffschroed at gmail.com (Jeff Schroeder) Date: Mon, 30 Jun 2008 17:16:36 -0700 Subject: [Ovirt-devel] [PATCH] Add additional blacklisting and rpm removal to managed node In-Reply-To: <48697388.6000603@redhat.com> References: <1214829972-22991-1-git-send-email-pmyers@redhat.com> <4868DCA7.8060401@redhat.com> <20080630165628.58582eb5@tp.mains.net> <48697388.6000603@redhat.com> Message-ID: On Mon, Jun 30, 2008 at 5:00 PM, Perry N. Myers wrote: > Ian Main wrote: >> >> On Mon, 30 Jun 2008 15:16:23 +0200 >> Chris Lalancette wrote: >> >>> Perry Myers wrote: >>>> >>>> A few important notes: >>>> 1. /lib/modules was scoured for things that didn't seem necessary, >>>> however >>>> my notion of not necessary may not be correct. Please review the list >>>> of modules that I'm removing and if you see one that we need to add >>>> back >>>> in, comment. >>>> 2. /boot is removed as we don't need an initrd and kernel image inside >>>> of >>>> the livecd initrd. >>> >>> Ah yes, good to remove this, since it is superflous. >>> >>>> 3. The blacklisting method is a hack. What we need is an appliance >>>> creator >>>> that has black/whitelisting capabilities... (hint, hint to our AOS >>>> friends out there) >>>> >>>> The ISO image RPM is down to 45MB >>>> PXE image RPM is at 52MB >>>> Running filesystem is 130MB >>> >>> My question is: so? I don't really see how it's much of an improvement >>> over >>> what we already have. Or rather, it's an improvement, but in my opinion >>> the >>> cost (breaking RPM, breaking RPM dependencies, etc) is too high. >> >> [snip] >> >>> >>> Overall, seems to be breaking a lot of debug and reproducibility >>> functionality >>> for very little gain. >> >> I think we should bring back the idea of having a debug image and a >> production >> image. Have your cake and eat it too.. might be a bit more to maintain >> though.. >> have to think about that. > > This is a double edged sword... Having multiple image types means that we > can have custom spins for developers, specific hardware types, etc. But it > also means that we need to test -each- of these images. It's very easy to > fall into a trap where everyone uses the developer image and then you go to > release and start seeing unforeseen problems in the production images. If only there was a way to do automated testing? The Zumastor project (http://www.zumastor.org) has a pretty complete set of automated tests here but they run under uml: http://code.google.com/p/zumastor/source/browse/trunk/cbtb Have any redhat-ers thought of asking for a few boxes to do continuous integration and unit testing on oVirt? Would it be a good time to consider or too much effort to get up and running? > To note: there are no changes in this patch that affect developer usability. > I intentionally left in vi, userland utils, sshd, etc... So at this point > with this patch there is no need to split developer/production images. > > However, if we need to minimize further than this we may need to consider > splitting. -- Jeff Schroeder Don't drink and derive, alcohol and analysis don't mix. http://www.digitalprognosis.com From pmyers at redhat.com Tue Jul 1 00:30:18 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Mon, 30 Jun 2008 20:30:18 -0400 Subject: [Ovirt-devel] [PATCH] Add additional blacklisting and rpm removal to managed node In-Reply-To: References: <1214829972-22991-1-git-send-email-pmyers@redhat.com> <4868DCA7.8060401@redhat.com> <20080630165628.58582eb5@tp.mains.net> <48697388.6000603@redhat.com> Message-ID: <48697A9A.3010803@redhat.com> Jeff Schroeder wrote: > On Mon, Jun 30, 2008 at 5:00 PM, Perry N. Myers wrote: >> Ian Main wrote: >>> On Mon, 30 Jun 2008 15:16:23 +0200 >>> Chris Lalancette wrote: >>> >>>> Perry Myers wrote: >>>>> A few important notes: >>>>> 1. /lib/modules was scoured for things that didn't seem necessary, >>>>> however >>>>> my notion of not necessary may not be correct. Please review the list >>>>> of modules that I'm removing and if you see one that we need to add >>>>> back >>>>> in, comment. >>>>> 2. /boot is removed as we don't need an initrd and kernel image inside >>>>> of >>>>> the livecd initrd. >>>> Ah yes, good to remove this, since it is superflous. >>>> >>>>> 3. The blacklisting method is a hack. What we need is an appliance >>>>> creator >>>>> that has black/whitelisting capabilities... (hint, hint to our AOS >>>>> friends out there) >>>>> >>>>> The ISO image RPM is down to 45MB >>>>> PXE image RPM is at 52MB >>>>> Running filesystem is 130MB >>>> My question is: so? I don't really see how it's much of an improvement >>>> over >>>> what we already have. Or rather, it's an improvement, but in my opinion >>>> the >>>> cost (breaking RPM, breaking RPM dependencies, etc) is too high. >>> [snip] >>> >>>> Overall, seems to be breaking a lot of debug and reproducibility >>>> functionality >>>> for very little gain. >>> I think we should bring back the idea of having a debug image and a >>> production >>> image. Have your cake and eat it too.. might be a bit more to maintain >>> though.. >>> have to think about that. >> This is a double edged sword... Having multiple image types means that we >> can have custom spins for developers, specific hardware types, etc. But it >> also means that we need to test -each- of these images. It's very easy to >> fall into a trap where everyone uses the developer image and then you go to >> release and start seeing unforeseen problems in the production images. > > > If only there was a way to do automated testing? > > The Zumastor project (http://www.zumastor.org) has a pretty complete set of > automated tests here but they run under uml: > http://code.google.com/p/zumastor/source/browse/trunk/cbtb > > Have any redhat-ers thought of asking for a few boxes to do continuous > integration > and unit testing on oVirt? Would it be a good time to consider or too > much effort to get up > and running? We are planning on doing automated testing. However, even with automated testing, testing & supporting multiple node spins will still take more time and energy (especially from a support perspective). So the ultimate question is, what do we gain by splitting up the node into multiple images in order to meet an arbitrary size goal? Perry From pmyers at redhat.com Tue Jul 1 00:33:16 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Mon, 30 Jun 2008 20:33:16 -0400 Subject: [Ovirt-devel] [PATCH] Two convenience scripts to simplify appliance usage In-Reply-To: <48688547.3060105@redhat.com> References: <1214691587-11710-1-git-send-email-pmyers@redhat.com> <48688547.3060105@redhat.com> Message-ID: <48697B4C.8000502@redhat.com> Chris Lalancette wrote: > Perry Myers wrote: >> ovirt-firefox.sh is used to launch firefox on the appliance >> ovirt-view-vm.sh is used to launch virt-viewer on a specific managed node >> connected to a specific virtual machine. > > Sure, should make life a little easier. > >> +KNOWN_HOSTS=~/.ssh/ovirt-known_hosts >> +SSH_ARGS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=$KNOWN_HOSTS -Yf" >> + >> +rm -f $KNOWN_HOSTS > /dev/null 2>&1 >> +ssh $SSH_ARGS 192.168.50.2 firefox --no-remote > > Sneaky. Redefine where the known hosts goes, and blow it away. Do we need both > "StrictHostKeyChecking=no" and the removal of KnownHosts, though? Yes. Even with StrickHostKeyChecking=no, if you don't blow away known hosts you'll get a nasty warning message. And if you just do the known-hosts delete, you'll get a prompt to add the new key on each connect. So the combination does the trick. Of course, this is a controlled test environment. Don't do this at home, kids... > > >> +if [[ $# < 2 ]]; then >> + echo "usage: $0 node vm" >> + echo " node: hostname of node to connect to (i.e. node3)" >> + echo " vm : name of virtual machine on designated node to view" >> + exit 1 >> +fi > > Minor whitespace damage. Already fixed :) >> + >> +NODE=$1 >> +VM=$2 >> + >> +rm -f $KNOWN_HOSTS > /dev/null 2>&1 >> +ssh $SSH_ARGS 192.168.50.2 virt-viewer -c qemu+tcp://$NODE.priv.ovirt.org/system $VM > > Other than the two minor issues above, looks good, so I will ACK it. Thanks, Perry From pmyers at redhat.com Tue Jul 1 00:51:18 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Mon, 30 Jun 2008 20:51:18 -0400 Subject: [Ovirt-devel] [PATCH] Merge developer/bundled appliance into a single appliance: ovirt-appliance In-Reply-To: <4868847D.3020001@redhat.com> References: <1214691574-11687-1-git-send-email-pmyers@redhat.com> <4868847D.3020001@redhat.com> Message-ID: <48697F86.2020104@redhat.com> Chris Lalancette wrote: > Perry Myers wrote: >> The separation of the ovirt appliance image into developer/bundled versions >> is not necessary, since the only differences between them are in how the >> host bridge is configured. Developer assumes that you only have a single >> NIC on your host so you can't have a separate ovirt network managed by >> the appliance. Bundled assumes you have the second NIC available. > > Yes, very good point. I totally agree; the only real difference is in the > underlying setup, so unifying them is good. > >> These patches remove the separation between bundled/developer. The new >> appliance is called ovirt-appliance and can be installed with or without >> a bridge to a real network device. In either case dummy managed nodes >> are allowed (they can be used in conjunction with the real managed nodes >> or just ignored in that case) > > Yep, also a good point. > >> Both build-all.sh and create-wui-appliance.sh have the developer/bundled >> flags removed, and replaced with -e flag to indicate the ethernet device >> to use as the bridge. If this is omitted it is assumed that the ovirtbr >> will not bridge to a physical network. The bridge (if to a physical net) >> is made persistent in rc.local (eventually libvirt should handle this) >> If the device to use on the bridge is used already, the script aborts >> (we don't want to mess up someones eth0 config by accident) > > Yay! Removal of a command-line switch :). And yes, totally agreed about the > eth0 checking; we can't fix it up (and really probably shouldn't blindly > override the user's decision for eth0), so just detecting with a good error is > the best we can do here. > >> diff --git a/build-all.sh b/build-all.sh >> index 6e27957..d231241 100755 >> --- a/build-all.sh >> +++ b/build-all.sh >> @@ -29,16 +29,15 @@ DEP_RPMS="createrepo httpd kvm libvirt livecd-tools pungi-1.2.18.1" >> usage() { >> case $# in 1) warn "$1"; try_h; exit 1;; esac >> cat <> -Usage: $ME [-w] [-n] [-p init|update] [-s] [-d|-b] [-a] [-c] [-v git|release|none] >> +Usage: $ME [-w] [-n] [-p init|update] [-s] [-a] [-c] [-v git|release|none] > > Minor nit; you forgot to put the [-e nic] as part of the initial Usage string. Will fix. > > >> @@ -57,19 +56,18 @@ update_wui=0 update_node=0 >> update_pungi=0 update_app=0 >> include_src=0 >> cleanup=0 >> -app_type= >> version_type=git >> +bridge= >> err=0 help=0 >> -while getopts wnp:sdbahcv: c; do >> +while getopts wnp:sahcv:e: c; do >> case $c in >> w) update_wui=1;; >> n) update_node=1;; >> p) update_pungi=$OPTARG;; >> s) include_src=1;; >> - d) update_app=1; app_type="-v";; >> - b) update_app=1; app_type="-b";; > > Not 100% certain of this, but don't you need to set the "update_app" flag > somewhere now that you've removed the options that set it? It's part of the -a flag to the script. -a is to 'rebuild all' and in reality if you're going to rebuild the appliance, you probably should always rebuild the node/wui RPMs, etc. > > >> +if [ -n "$bridge" ]; then >> + ifconfig $bridge > /dev/null 2>&1 ; bridge_dev_present=$? >> + test $bridge_dev_present != 0 && die "$bridge device not present, aborting!" >> + test -f $NET_SCRIPTS/ifcfg-$bridge && die "$bridge defined in $NET_SCRIPTS, aborting!" >> fi > > Unless I'm missing something (and please point out if I am), this looks to be > the only check for already existing networking devices. If this is the only > check, I don't think it is strong enough. In particular, if you are doing this > over a remote link, and happen to pass eth0 as the device you want to bridge, I > think you will still make it by this check and then totally hose up your remote > connection. I think we need to check both if the device is present, and if the > device is currently configured with an IP address. In that case, we would > abort, since we can't make any guarantees about not hosing up the connection. We talked about this offline, and you were misreading the code. $bridge here refers to eth1, eth2 (i.e. whatever you passed in on -e flag) However you did point out two things here, first is that the check for ifcfg-eth1 may not be sufficient to detect whether or not the designated interface is running. Secondly there may be portability issues with using ifconfig. I'll see if I can refactor these checks to use something like ip. Suggestions from our friends working in other distros would be appreciated here. > > >> +if [ -n "$bridge" ]; then >> + # FIXME: unfortunately, these two can't be done by libvirt at the >> + # moment, so we do them by hand here and persist the config by >> + # by adding to rc.local >> + echo "Adding new bridge $bridge" >> + TMPBRCTL=$(mktemp) || exit 1 >> + cat > $TMPBRCTL << EOF >> +brctl addif $BRIDGENAME $bridge # $BRIDGENAME >> +ifconfig $bridge up # $BRIDGENAME >> +EOF >> + chmod a+x $TMPBRCTL >> + >> + cat $TMPBRCTL >> /etc/rc.d/rc.local >> + >> + $TMPBRCTL >> + rm $TMPBRCTL > > Is there any reason you need the TMPBRCTL file at all? Can't you just: > > cat >> /etc/rc.d/rc.local << EOF > brctl addif $BRIDGENAME $bridge # $BRIDGENAME > ifconfig $bridge up # $BRIDGENAME > EOF There are two things that need to be done. First is to start the bridge *now*, second is to put the stuff in rc.local to have it start on reboot. We can't just put it in rc.local and then execute rc.local because we don't know what else is in rc.local and it might be bad to reexecute that file. So rather than duplicating the brctl and ifconfig lines in the script, I write it once to a temp file, put the contents of the temp file in rc.local and then execute the temp file now so that the bridge comes up immediately. Make more sense now? Again, if ifconfig is a bad command to use for portability suggestions for more portable commands would be appreciated. Perry > and be done with it? > > Chris Lalancette -- |=- 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 Tue Jul 1 00:52:10 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Mon, 30 Jun 2008 20:52:10 -0400 Subject: [Ovirt-devel] [PATCH] Merge developer/bundled appliance into a single appliance: ovirt-appliance In-Reply-To: References: <1214691574-11687-1-git-send-email-pmyers@redhat.com> <4868847D.3020001@redhat.com> Message-ID: <48697FBA.8090004@redhat.com> Jeff Schroeder wrote: > On Mon, Jun 30, 2008 at 12:00 AM, Chris Lalancette wrote: > ...snip... >>> + chmod a+x $TMPBRCTL >>> + >>> + cat $TMPBRCTL >> /etc/rc.d/rc.local >>> + >>> + $TMPBRCTL >>> + rm $TMPBRCTL >> Is there any reason you need the TMPBRCTL file at all? Can't you just: >> >> cat >> /etc/rc.d/rc.local << EOF >> brctl addif $BRIDGENAME $bridge # $BRIDGENAME >> ifconfig $bridge up # $BRIDGENAME >> EOF > > Either way, you don't make sure /etc/rc.local is executable. The chmod a+x hunk > should probably be changed to "chmod a+x $TMPBRCTL /etc/rc.local" or something > similar. Noted. I'll add chmod rc.local to the script. Thanks, Perry From jeffschroed at gmail.com Tue Jul 1 01:26:55 2008 From: jeffschroed at gmail.com (Jeff Schroeder) Date: Mon, 30 Jun 2008 18:26:55 -0700 Subject: [Ovirt-devel] [PATCH] Add additional blacklisting and rpm removal to managed node In-Reply-To: <48697A9A.3010803@redhat.com> References: <1214829972-22991-1-git-send-email-pmyers@redhat.com> <4868DCA7.8060401@redhat.com> <20080630165628.58582eb5@tp.mains.net> <48697388.6000603@redhat.com> <48697A9A.3010803@redhat.com> Message-ID: On Mon, Jun 30, 2008 at 5:30 PM, Perry N. Myers wrote: > Jeff Schroeder wrote: >> >> On Mon, Jun 30, 2008 at 5:00 PM, Perry N. Myers wrote: >>> >>> Ian Main wrote: >>>> >>>> On Mon, 30 Jun 2008 15:16:23 +0200 >>>> Chris Lalancette wrote: >>>> >>>>> Perry Myers wrote: >>>>>> >>>>>> A few important notes: >>>>>> 1. /lib/modules was scoured for things that didn't seem necessary, >>>>>> however >>>>>> my notion of not necessary may not be correct. Please review the >>>>>> list >>>>>> of modules that I'm removing and if you see one that we need to add >>>>>> back >>>>>> in, comment. >>>>>> 2. /boot is removed as we don't need an initrd and kernel image inside >>>>>> of >>>>>> the livecd initrd. >>>>> >>>>> Ah yes, good to remove this, since it is superflous. >>>>> >>>>>> 3. The blacklisting method is a hack. What we need is an appliance >>>>>> creator >>>>>> that has black/whitelisting capabilities... (hint, hint to our AOS >>>>>> friends out there) >>>>>> >>>>>> The ISO image RPM is down to 45MB >>>>>> PXE image RPM is at 52MB >>>>>> Running filesystem is 130MB >>>>> >>>>> My question is: so? I don't really see how it's much of an improvement >>>>> over >>>>> what we already have. Or rather, it's an improvement, but in my >>>>> opinion >>>>> the >>>>> cost (breaking RPM, breaking RPM dependencies, etc) is too high. >>>> >>>> [snip] >>>> >>>>> Overall, seems to be breaking a lot of debug and reproducibility >>>>> functionality >>>>> for very little gain. >>>> >>>> I think we should bring back the idea of having a debug image and a >>>> production >>>> image. Have your cake and eat it too.. might be a bit more to maintain >>>> though.. >>>> have to think about that. >>> >>> This is a double edged sword... Having multiple image types means that >>> we >>> can have custom spins for developers, specific hardware types, etc. But >>> it >>> also means that we need to test -each- of these images. It's very easy >>> to >>> fall into a trap where everyone uses the developer image and then you go >>> to >>> release and start seeing unforeseen problems in the production images. >> >> >> If only there was a way to do automated testing? >> >> The Zumastor project (http://www.zumastor.org) has a pretty complete set >> of >> automated tests here but they run under uml: >> http://code.google.com/p/zumastor/source/browse/trunk/cbtb >> >> Have any redhat-ers thought of asking for a few boxes to do continuous >> integration >> and unit testing on oVirt? Would it be a good time to consider or too >> much effort to get up >> and running? > > We are planning on doing automated testing. However, even with automated > testing, testing & supporting multiple node spins will still take more time > and energy (especially from a support perspective). > > So the ultimate question is, what do we gain by splitting up the node into > multiple images in order to meet an arbitrary size goal? Maybe that should be ultimate question number two... The ultimate question seems like, "Why do we need the node to be so small in the first place and is it really worth it to keep pushing things smaller at the sake of usability?". Are you guys looking at running nodes in firmware or something? 60MB seems awful hefty for that goal and flat out unreasonable in most cases. PXE booting a few hundred megabytes seems perfectly reasonable even if a bit big. What does being smaller _really_ buy you? After that question is realized your question applies. KISS is good, but if being small inhibits a user from properly troubleshooting a system the project has failed them in one aspect. How can oVirt save it's users time and stay out of their way? How can using oVirt give me more time to go on vacation? How can oVirt help me get this crazy infrastructure back in check? Those are questions we should ask. Is getting an image < 20MB a "worthless microoptimization" as danpb so eloquently put it? Or is there something that necessitates it? If there is please enlighten me. Getting in user's way is certainly not a way to win friends. Please don't take this as a rant or attack. It is meant to start a constructive conversation. -- Jeff Schroeder Don't drink and derive, alcohol and analysis don't mix. http://www.digitalprognosis.com From jeffschroed at gmail.com Tue Jul 1 01:31:20 2008 From: jeffschroed at gmail.com (Jeff Schroeder) Date: Mon, 30 Jun 2008 18:31:20 -0700 Subject: [Ovirt-devel] [PATCH] Two convenience scripts to simplify appliance usage In-Reply-To: <48697B4C.8000502@redhat.com> References: <1214691587-11710-1-git-send-email-pmyers@redhat.com> <48688547.3060105@redhat.com> <48697B4C.8000502@redhat.com> Message-ID: On Mon, Jun 30, 2008 at 5:33 PM, Perry N. Myers wrote: > Chris Lalancette wrote: >> >> Perry Myers wrote: >>> >>> ovirt-firefox.sh is used to launch firefox on the appliance >>> ovirt-view-vm.sh is used to launch virt-viewer on a specific managed node >>> connected to a specific virtual machine. >> >> Sure, should make life a little easier. >> >>> +KNOWN_HOSTS=~/.ssh/ovirt-known_hosts >>> +SSH_ARGS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=$KNOWN_HOSTS >>> -Yf" >>> + >>> +rm -f $KNOWN_HOSTS > /dev/null 2>&1 At the point of arguing stupid semantics, this seems to do the same with less moving code: SSH_ARGS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -fY" This looks pretty good. >>> +ssh $SSH_ARGS 192.168.50.2 firefox --no-remote >> >> Sneaky. Redefine where the known hosts goes, and blow it away. Do we >> need both >> "StrictHostKeyChecking=no" and the removal of KnownHosts, though? > > Yes. Even with StrickHostKeyChecking=no, if you don't blow away known hosts > you'll get a nasty warning message. And if you just do the known-hosts > delete, you'll get a prompt to add the new key on each connect. So the > combination does the trick. Of course, this is a controlled test > environment. Don't do this at home, kids... > >> >> >>> +if [[ $# < 2 ]]; then >>> + echo "usage: $0 node vm" >>> + echo " node: hostname of node to connect to (i.e. node3)" >>> + echo " vm : name of virtual machine on designated node to view" >>> + exit 1 >>> +fi >> >> Minor whitespace damage. > > Already fixed :) > >>> + >>> +NODE=$1 >>> +VM=$2 >>> + >>> +rm -f $KNOWN_HOSTS > /dev/null 2>&1 >>> +ssh $SSH_ARGS 192.168.50.2 virt-viewer -c >>> qemu+tcp://$NODE.priv.ovirt.org/system $VM >> >> Other than the two minor issues above, looks good, so I will ACK it. > > Thanks, > > Perry -- Jeff Schroeder Don't drink and derive, alcohol and analysis don't mix. http://www.digitalprognosis.com From pmyers at redhat.com Tue Jul 1 02:00:11 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Mon, 30 Jun 2008 22:00:11 -0400 Subject: [Ovirt-devel] [PATCH] Two convenience scripts to simplify appliance usage In-Reply-To: References: <1214691587-11710-1-git-send-email-pmyers@redhat.com> <48688547.3060105@redhat.com> <48697B4C.8000502@redhat.com> Message-ID: <48698FAB.1080905@redhat.com> Jeff Schroeder wrote: > On Mon, Jun 30, 2008 at 5:33 PM, Perry N. Myers wrote: >> Chris Lalancette wrote: >>> Perry Myers wrote: >>>> ovirt-firefox.sh is used to launch firefox on the appliance >>>> ovirt-view-vm.sh is used to launch virt-viewer on a specific managed node >>>> connected to a specific virtual machine. >>> Sure, should make life a little easier. >>> >>>> +KNOWN_HOSTS=~/.ssh/ovirt-known_hosts >>>> +SSH_ARGS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=$KNOWN_HOSTS >>>> -Yf" >>>> + >>>> +rm -f $KNOWN_HOSTS > /dev/null 2>&1 > > At the point of arguing stupid semantics, this seems to do the same > with less moving code: > SSH_ARGS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -fY" > > This looks pretty good. ah, I didn't think of putting the known hosts file in /dev/null. If that works, I'm all for it :) Perry From pmyers at redhat.com Tue Jul 1 02:15:24 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Mon, 30 Jun 2008 22:15:24 -0400 Subject: [Ovirt-devel] [PATCH] Add additional blacklisting and rpm removal to managed node In-Reply-To: References: <1214829972-22991-1-git-send-email-pmyers@redhat.com> <4868DCA7.8060401@redhat.com> <20080630165628.58582eb5@tp.mains.net> <48697388.6000603@redhat.com> <48697A9A.3010803@redhat.com> Message-ID: <4869933C.8010807@redhat.com> Jeff Schroeder wrote: [snip] > > Maybe that should be ultimate question number two... > > The ultimate question seems like, "Why do we need the node to be so > small in the first place and > is it really worth it to keep pushing things smaller at the sake of > usability?". Are you guys looking > at running nodes in firmware or something? 60MB seems awful hefty for > that goal and flat out > unreasonable in most cases. PXE booting a few hundred megabytes seems > perfectly reasonable > even if a bit big. What does being smaller _really_ buy you? > > After that question is realized your question applies. > > KISS is good, but if being small inhibits a user from properly > troubleshooting a system the project > has failed them in one aspect. How can oVirt save it's users time and > stay out of their way? How > can using oVirt give me more time to go on vacation? How can oVirt > help me get this crazy infrastructure > back in check? Those are questions we should ask. Is getting an image > < 20MB a "worthless microoptimization" > as danpb so eloquently put it? Or is there something that necessitates > it? If there is please enlighten me. > > Getting in user's way is certainly not a way to win friends. Embedding in firmware could be an option, if the firmware sizes grow and the image sizes shrinks and there is a good place to meet in the middle. I'm more of a fan of embedding on system flash, in which case it's a tradeoff between cost of image minimization vs. size of the flash you need to include. One could make a good argument that once you've decided to go with flash anyhow, paying for 64MB vs. 128MB flash is negligible. But then again, I know nothing about managing hardware on large scales. But you bring up a good discussion point, I'd be interested to see what others weigh in on here. > > Please don't take this as a rant or attack. It is meant to start a > constructive conversation. > > Not taken as such. It's constructive discussion. 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 jeffschroed at gmail.com Tue Jul 1 03:15:41 2008 From: jeffschroed at gmail.com (Jeff Schroeder) Date: Mon, 30 Jun 2008 20:15:41 -0700 Subject: [Ovirt-devel] [PATCH] Merge developer/bundled appliance into a single appliance: ovirt-appliance In-Reply-To: <48697F86.2020104@redhat.com> References: <1214691574-11687-1-git-send-email-pmyers@redhat.com> <4868847D.3020001@redhat.com> <48697F86.2020104@redhat.com> Message-ID: On Mon, Jun 30, 2008 at 5:51 PM, Perry N. Myers wrote: > Chris Lalancette wrote: >> >> Perry Myers wrote: >>> >>> The separation of the ovirt appliance image into developer/bundled >>> versions >>> is not necessary, since the only differences between them are in how the >>> host bridge is configured. Developer assumes that you only have a single >>> NIC on your host so you can't have a separate ovirt network managed by >>> the appliance. Bundled assumes you have the second NIC available. >> >> Yes, very good point. I totally agree; the only real difference is in the >> underlying setup, so unifying them is good. >> >>> These patches remove the separation between bundled/developer. The new >>> appliance is called ovirt-appliance and can be installed with or without >>> a bridge to a real network device. In either case dummy managed nodes >>> are allowed (they can be used in conjunction with the real managed nodes >>> or just ignored in that case) >> >> Yep, also a good point. >> >>> Both build-all.sh and create-wui-appliance.sh have the developer/bundled >>> flags removed, and replaced with -e flag to indicate the ethernet device >>> to use as the bridge. If this is omitted it is assumed that the ovirtbr >>> will not bridge to a physical network. The bridge (if to a physical net) >>> is made persistent in rc.local (eventually libvirt should handle this) >>> If the device to use on the bridge is used already, the script aborts >>> (we don't want to mess up someones eth0 config by accident) >> >> Yay! Removal of a command-line switch :). And yes, totally agreed about >> the >> eth0 checking; we can't fix it up (and really probably shouldn't blindly >> override the user's decision for eth0), so just detecting with a good >> error is >> the best we can do here. >> >>> diff --git a/build-all.sh b/build-all.sh >>> index 6e27957..d231241 100755 >>> --- a/build-all.sh >>> +++ b/build-all.sh >>> @@ -29,16 +29,15 @@ DEP_RPMS="createrepo httpd kvm libvirt livecd-tools >>> pungi-1.2.18.1" >>> usage() { >>> case $# in 1) warn "$1"; try_h; exit 1;; esac >>> cat <>> -Usage: $ME [-w] [-n] [-p init|update] [-s] [-d|-b] [-a] [-c] [-v >>> git|release|none] >>> +Usage: $ME [-w] [-n] [-p init|update] [-s] [-a] [-c] [-v >>> git|release|none] >> >> Minor nit; you forgot to put the [-e nic] as part of the initial Usage >> string. > > Will fix. > >> >> >>> @@ -57,19 +56,18 @@ update_wui=0 update_node=0 >>> update_pungi=0 update_app=0 >>> include_src=0 >>> cleanup=0 >>> -app_type= >>> version_type=git >>> +bridge= >>> err=0 help=0 >>> -while getopts wnp:sdbahcv: c; do >>> +while getopts wnp:sahcv:e: c; do >>> case $c in >>> w) update_wui=1;; >>> n) update_node=1;; >>> p) update_pungi=$OPTARG;; >>> s) include_src=1;; >>> - d) update_app=1; app_type="-v";; >>> - b) update_app=1; app_type="-b";; >> >> Not 100% certain of this, but don't you need to set the "update_app" flag >> somewhere now that you've removed the options that set it? > > It's part of the -a flag to the script. -a is to 'rebuild all' and in > reality if you're going to rebuild the appliance, you probably should always > rebuild the node/wui RPMs, etc. > >> >> >>> +if [ -n "$bridge" ]; then >>> + ifconfig $bridge > /dev/null 2>&1 ; bridge_dev_present=$? >>> + test $bridge_dev_present != 0 && die "$bridge device not present, >>> aborting!" >>> + test -f $NET_SCRIPTS/ifcfg-$bridge && die "$bridge defined in >>> $NET_SCRIPTS, aborting!" >>> fi >> >> Unless I'm missing something (and please point out if I am), this looks to >> be >> the only check for already existing networking devices. If this is the >> only >> check, I don't think it is strong enough. In particular, if you are doing >> this >> over a remote link, and happen to pass eth0 as the device you want to >> bridge, I >> think you will still make it by this check and then totally hose up your >> remote >> connection. I think we need to check both if the device is present, and >> if the >> device is currently configured with an IP address. In that case, we would >> abort, since we can't make any guarantees about not hosing up the >> connection. > > We talked about this offline, and you were misreading the code. $bridge > here refers to eth1, eth2 (i.e. whatever you passed in on -e flag) > > However you did point out two things here, first is that the check for > ifcfg-eth1 may not be sufficient to detect whether or not the designated > interface is running. Secondly there may be portability issues with using > ifconfig. I'll see if I can refactor these checks to use something like ip. > Suggestions from our friends working in other distros would be appreciated > here. What makes this more portable than the same thing using ifconfig? "ip addr show $bridge > /dev/null 2>&1 ; bridge_dev_present=$?" Are there distros that use something other than net-tools for /sbin/ifconfig? Since there is no real distro agnostic way to do this, you'll end up special casing major distro versions like redhat and debian. The majority of distributions are based upon those two anyways. Even if it is slackware based, suse has enough redhat-isms you could probably make the checks for suse the same as redhat. + test -f $NET_SCRIPTS/ifcfg-$bridge && die "$bridge defined in $NET_SCRIPTS, aborting!" ... somewhere near the top... if [ -e /etc/redhat-release ]; then DISTRO=redhat elif [ -e /etc/debian_version ]; then DISTRO=debian fi ifconfig "$bridge" ... && croak because the interface is already up and active... case "$DISTRO" in redhat) test -f "$NET_SCRIPTS/ifcfg-$bridge"; bridge_int_undefined=$? ;; debian) grep -qs "$bridge" /etc/network/interfaces; bridge_int_undefined=$? ;; *) you should never be here esac if [ $bridge_int_undefined = 0 ]; then die "$bridge defined in $NET_SCRIPTS, aborting!" fi Maybe there is a way to seperate all "distro specific checks" to a common shell functions file? Then you could have the common shell functions file return variables and keep the individual scripts a bit cleaner? This might be overkill, but there isn't a generic way to configure persistent network settings on Linux. If you absolutely need that feature, you might think about abstracting things out a bit more. Also, why not be a bit more magical? Instead of dying if $bridge is defined, why not pick the next available interface? Especially for a developer appliance? >>> +if [ -n "$bridge" ]; then >>> + # FIXME: unfortunately, these two can't be done by libvirt at the >>> + # moment, so we do them by hand here and persist the config by >>> + # by adding to rc.local >>> + echo "Adding new bridge $bridge" >>> + TMPBRCTL=$(mktemp) || exit 1 >>> + cat > $TMPBRCTL << EOF >>> +brctl addif $BRIDGENAME $bridge # $BRIDGENAME >>> +ifconfig $bridge up # $BRIDGENAME >>> +EOF >>> + chmod a+x $TMPBRCTL >>> + >>> + cat $TMPBRCTL >> /etc/rc.d/rc.local >>> + >>> + $TMPBRCTL >>> + rm $TMPBRCTL >> >> Is there any reason you need the TMPBRCTL file at all? Can't you just: >> >> cat >> /etc/rc.d/rc.local << EOF >> brctl addif $BRIDGENAME $bridge # $BRIDGENAME >> ifconfig $bridge up # $BRIDGENAME >> EOF > > There are two things that need to be done. First is to start the bridge > *now*, second is to put the stuff in rc.local to have it start on reboot. > We can't just put it in rc.local and then execute rc.local because we don't > know what else is in rc.local and it might be bad to reexecute that file. > So rather than duplicating the brctl and ifconfig lines in the script, I > write it once to a temp file, put the contents of the temp file in rc.local > and then execute the temp file now so that the bridge comes up immediately. > Make more sense now? > > Again, if ifconfig is a bad command to use for portability suggestions for > more portable commands would be appreciated. Your approach seems sane to me. -- Jeff Schroeder Don't drink and derive, alcohol and analysis don't mix. http://www.digitalprognosis.com From sseago at redhat.com Tue Jul 1 03:23:22 2008 From: sseago at redhat.com (Scott Seago) Date: Mon, 30 Jun 2008 23:23:22 -0400 Subject: [Ovirt-devel] [Patch] Fixed Test Cases In-Reply-To: <48695EB4.6010005@redhat.com> References: <48695EB4.6010005@redhat.com> Message-ID: <4869A32A.80506@redhat.com> Mohammed Morsi wrote: > With this patch, all test cases but one are fixed. The one involves a > quirk when destroying a vm resource pool, where the application > incorrectly tries to unassociate hosts from the pool. This is most > likely due to the hack we had to do where we associated hosts w/ with > the base pools class instead of vm_resource_pools to fix something or > an other. Hmm -- what was your exact error here? Although hosts are listed on the base pools class now, there will never be hosts assigned here, so the "unassociation" should be a no-op. BTW, the reason we had to move the associations to the base class was in order to get :include directives working -- so queries on the base class (i.e. Pool.children, etc.) could automatically include hosts for child Hardware pools -- but hopefully this won't keep tests from working here. Scott From mmorsi at redhat.com Tue Jul 1 04:07:45 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Tue, 01 Jul 2008 00:07:45 -0400 Subject: [Ovirt-devel] [Patch] Fixed Test Cases In-Reply-To: <4869A32A.80506@redhat.com> References: <48695EB4.6010005@redhat.com> <4869A32A.80506@redhat.com> Message-ID: <4869AD91.4040507@redhat.com> Scott Seago wrote: > Mohammed Morsi wrote: >> With this patch, all test cases but one are fixed. The one involves a >> quirk when destroying a vm resource pool, where the application >> incorrectly tries to unassociate hosts from the pool. This is most >> likely due to the hack we had to do where we associated hosts w/ with >> the base pools class instead of vm_resource_pools to fix something or >> an other. > > Hmm -- what was your exact error here? Although hosts are listed on > the base pools class now, there will never be hosts assigned here, so > the "unassociation" should be a no-op. BTW, the reason we had to move > the associations to the base class was in order to get :include > directives working -- so queries on the base class (i.e. > Pool.children, etc.) could automatically include hosts for child > Hardware pools -- but hopefully this won't keep tests from working here. > > Scott Looking into it further I see the fixtures are incorrect as there were a few hosts which were associated with a vm resource pool id instead of a hardware pool id. Changing those to a valid hardware pool resolved the last of the issues. -Mo From bkearney at redhat.com Tue Jul 1 11:30:17 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Tue, 01 Jul 2008 07:30:17 -0400 Subject: [Thincrust-devel] [Fwd: [Ovirt-devel] [PATCH] Add additional blacklisting and rpm removal to managed node] In-Reply-To: <486957FA.1080502@redhat.com> References: <4868D84E.2000008@redhat.com> <486957FA.1080502@redhat.com> Message-ID: <486A1549.8070308@redhat.com> Alan Pevec wrote: > Bryan Kearney wrote: >> Cross posting from our friends over at ovirt. >> >> Question for folks on the list.. how would you like to see >> whitelisting/blacklisting implemented? I could see it >> >> 1) A second file in addition to the kickstart file. >> 2) Embedded in the kickstart file. >> 3) A completely separate post-process step. >> >> I tend to like (1) since it allows one step, and does not add a new >> syntax to the kickstart file. Comments from folks? > > I'd like we find a way to embed this in the ks w/o adding new syntax > e.g. implement appliance-filter as a script interpreter > > %post --interpreter=/usr/bin/appliance-filter > drop /etc/pango > drop /usr/bin/hal-* file /usr/bin/hal-get-property > ... It appears that the interpreter needs to handle the entire post section. Is that correct? > > drop is a blacklist and file is whitelist action, so above would be the > equivalent of: > # rm -rf /etc/pango /usr/bin/hal-device /usr/bin/hal-disable-polling > /usr/bin/hal-find-by-capability /usr/bin/hal-find-by-property > /usr/bin/hal-is-caller-locked-out /usr/bin/hal-is-caller-privileged > /usr/bin/hal-lock /usr/bin/hal-set-property /usr/bin/hal-setup-keymap Did the fact that the file command was on the same line matter in your example? Or.. could I have written this and gotten the same results: file /usr/bin/hal-get-property drop /etc/pango drop /usr/bin/hal-* -- bk From jim at meyering.net Tue Jul 1 12:22:46 2008 From: jim at meyering.net (Jim Meyering) Date: Tue, 01 Jul 2008 14:22:46 +0200 Subject: [Ovirt-devel] git change set management Message-ID: <87iqvplrop.fsf@rho.meyering.net> Scott, Jason, (following up on IRC discussion from last week) If you have a patch that you can improve on, that's on a rewindable branch (like your local topic branch), please do adjust it before pushing public. There's no point in leaving a single conceptual delta in two change-sets just because you made a commit before making a related e.g., fix-up change -- it just makes more work for anyone who might cherry-pick (you'd have to cherry-pick also the fix-up patch). Keeping things in order also makes it easier to search using "git bisect". Of course, if you have logically independent changes that can be separated, then separating them is almost always better than squashing them into one. From apevec at redhat.com Tue Jul 1 12:40:57 2008 From: apevec at redhat.com (Alan Pevec) Date: Tue, 01 Jul 2008 14:40:57 +0200 Subject: [Thincrust-devel] [Fwd: [Ovirt-devel] [PATCH] Add additional blacklisting and rpm removal to managed node] In-Reply-To: <486A1549.8070308@redhat.com> References: <4868D84E.2000008@redhat.com> <486957FA.1080502@redhat.com> <486A1549.8070308@redhat.com> Message-ID: <486A25D9.5090504@redhat.com> Bryan Kearney wrote: > It appears that the interpreter needs to handle the entire post section. > Is that correct? yes, but you can have multiple %post sections, normal w/ shell and this one with a special interpreter see ImageCreator.__run_post_scripts() > Did the fact that the file command was on the same line matter in your > example? Or.. could I have written this and gotten the same results: > > file /usr/bin/hal-get-property > drop /etc/pango > drop /usr/bin/hal-* Yes, that's how I wanted it, one action per line but Thunderbird messed up my copy/paste, sorry. The only thing you put differently is the precedence: I think it would be intuitive to have white/blacklist actions on the same level and that order matters, so it would be: drop /etc/pango drop /usr/bin/hal-* file /usr/bin/hal-get-property From pmyers at redhat.com Tue Jul 1 13:28:39 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Tue, 01 Jul 2008 09:28:39 -0400 Subject: [Ovirt-devel] [PATCH] Merge developer/bundled appliance into a single appliance: ovirt-appliance In-Reply-To: References: <1214691574-11687-1-git-send-email-pmyers@redhat.com> <4868847D.3020001@redhat.com> <48697F86.2020104@redhat.com> Message-ID: <486A3107.3030200@redhat.com> Jeff Schroeder wrote: [snip] >> However you did point out two things here, first is that the check for >> ifcfg-eth1 may not be sufficient to detect whether or not the designated >> interface is running. Secondly there may be portability issues with using >> ifconfig. I'll see if I can refactor these checks to use something like ip. >> Suggestions from our friends working in other distros would be appreciated >> here. > > What makes this more portable than the same thing using ifconfig? > "ip addr show $bridge > /dev/null 2>&1 ; bridge_dev_present=$?" No idea :) Chris just mentioned to me that ifconfig may not be portable, if you suggest that ifconfig is fairly prevalent then I am content to leave it that way for the time being. If another random distro wants to use oVirt, then they can refactor the script accordingly. > Are there distros that use something other than net-tools for /sbin/ifconfig? > Since there is no real distro agnostic way to do this, you'll end up > special casing > major distro versions like redhat and debian. The majority of > distributions are based > upon those two anyways. Even if it is slackware based, suse has enough > redhat-isms > you could probably make the checks for suse the same as redhat. > > + test -f $NET_SCRIPTS/ifcfg-$bridge && die "$bridge defined in > $NET_SCRIPTS, aborting!" > > ... somewhere near the top... > if [ -e /etc/redhat-release ]; then > DISTRO=redhat > elif [ -e /etc/debian_version ]; then > DISTRO=debian > fi > > ifconfig "$bridge" ... && croak because the interface is already up > and active... > > case "$DISTRO" in > redhat) > test -f "$NET_SCRIPTS/ifcfg-$bridge"; bridge_int_undefined=$? > ;; > debian) > grep -qs "$bridge" /etc/network/interfaces; bridge_int_undefined=$? > ;; > *) you should never be here > esac > > if [ $bridge_int_undefined = 0 ]; then > die "$bridge defined in $NET_SCRIPTS, aborting!" > fi > > Maybe there is a way to seperate all "distro specific checks" to a common > shell functions file? Then you could have the common shell functions file return > variables and keep the individual scripts a bit cleaner? This might be > overkill, but > there isn't a generic way to configure persistent network settings on > Linux. If you > absolutely need that feature, you might think about abstracting things > out a bit more. I think eventually that will be a good idea, but for right now I think we're ok. > Also, why not be a bit more magical? Instead of dying if $bridge is > defined, why not pick > the next available interface? Especially for a developer appliance? Because the user explicitly selected the interface via the -e parameter. I don't like the idea of iterating through the physical inferfaces since you don't know which one the user has wire to their oVirt physical lan. This is only the case for bundled installs. For developer we don't even use the interface since the network is completely internal to the host box. 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 Tue Jul 1 13:31:45 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Tue, 01 Jul 2008 09:31:45 -0400 Subject: [Thincrust-devel] [Fwd: [Ovirt-devel] [PATCH] Add additional blacklisting and rpm removal to managed node] In-Reply-To: <486A25D9.5090504@redhat.com> References: <4868D84E.2000008@redhat.com> <486957FA.1080502@redhat.com> <486A1549.8070308@redhat.com> <486A25D9.5090504@redhat.com> Message-ID: <486A31C1.7000904@redhat.com> Alan Pevec wrote: > Bryan Kearney wrote: >> It appears that the interpreter needs to handle the entire post >> section. Is that correct? > > yes, but you can have multiple %post sections, normal w/ shell and this > one with a special interpreter > see ImageCreator.__run_post_scripts() > >> Did the fact that the file command was on the same line matter in your >> example? Or.. could I have written this and gotten the same results: >> >> file /usr/bin/hal-get-property >> drop /etc/pango >> drop /usr/bin/hal-* > > Yes, that's how I wanted it, one action per line but Thunderbird messed > up my copy/paste, sorry. > The only thing you put differently is the precedence: I think it would > be intuitive to have white/blacklist actions on the same level and that > order matters, so it would be: > > drop /etc/pango > drop /usr/bin/hal-* > file /usr/bin/hal-get-property Wouldn't this make more sense: file /usr/bin/hal-get-property drop /usr/bin/hal-* drop /etc/pango Since in this case hal-get-property is marked as persistent before you go and delete everything hal-*? In the other ordering you would delete hal-* first and then when you get to whitelisting hal-get-property it's already gone. Unless of course the ordering of the list is irrelevant and you set a precedence that whitelisted files always trump blacklisted files. Perry From bkearney at redhat.com Tue Jul 1 13:32:00 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Tue, 01 Jul 2008 09:32:00 -0400 Subject: [Thincrust-devel] [Fwd: [Ovirt-devel] [PATCH] Add additional blacklisting and rpm removal to managed node] In-Reply-To: <486A31C1.7000904@redhat.com> References: <4868D84E.2000008@redhat.com> <486957FA.1080502@redhat.com> <486A1549.8070308@redhat.com> <486A25D9.5090504@redhat.com> <486A31C1.7000904@redhat.com> Message-ID: <486A31D0.1050208@redhat.com> Perry N. Myers wrote: > Alan Pevec wrote: >> Bryan Kearney wrote: >>> It appears that the interpreter needs to handle the entire post >>> section. Is that correct? >> >> yes, but you can have multiple %post sections, normal w/ shell and >> this one with a special interpreter >> see ImageCreator.__run_post_scripts() >> >>> Did the fact that the file command was on the same line matter in >>> your example? Or.. could I have written this and gotten the same >>> results: >>> >>> file /usr/bin/hal-get-property >>> drop /etc/pango >>> drop /usr/bin/hal-* >> >> Yes, that's how I wanted it, one action per line but Thunderbird >> messed up my copy/paste, sorry. >> The only thing you put differently is the precedence: I think it would >> be intuitive to have white/blacklist actions on the same level and >> that order matters, so it would be: >> >> drop /etc/pango >> drop /usr/bin/hal-* >> file /usr/bin/hal-get-property > > Wouldn't this make more sense: > file /usr/bin/hal-get-property > drop /usr/bin/hal-* > drop /etc/pango > > Since in this case hal-get-property is marked as persistent before you > go and delete everything hal-*? > > In the other ordering you would delete hal-* first and then when you get > to whitelisting hal-get-property it's already gone. Unless of course > the ordering of the list is irrelevant and you set a precedence that > whitelisted files always trump blacklisted files. > I think I like the model that WL is always the trump. That way you omit subtle errors from ordering. If you list it, it stays. Question.. can you whitelist a directory? -- bk From pmyers at redhat.com Tue Jul 1 13:40:26 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Tue, 01 Jul 2008 09:40:26 -0400 Subject: [Thincrust-devel] [Fwd: [Ovirt-devel] [PATCH] Add additional blacklisting and rpm removal to managed node] In-Reply-To: <486A31D0.1050208@redhat.com> References: <4868D84E.2000008@redhat.com> <486957FA.1080502@redhat.com> <486A1549.8070308@redhat.com> <486A25D9.5090504@redhat.com> <486A31C1.7000904@redhat.com> <486A31D0.1050208@redhat.com> Message-ID: <486A33CA.7080102@redhat.com> Bryan Kearney wrote: > > > Perry N. Myers wrote: >> Alan Pevec wrote: >>> Bryan Kearney wrote: >>>> It appears that the interpreter needs to handle the entire post >>>> section. Is that correct? >>> >>> yes, but you can have multiple %post sections, normal w/ shell and >>> this one with a special interpreter >>> see ImageCreator.__run_post_scripts() >>> >>>> Did the fact that the file command was on the same line matter in >>>> your example? Or.. could I have written this and gotten the same >>>> results: >>>> >>>> file /usr/bin/hal-get-property >>>> drop /etc/pango >>>> drop /usr/bin/hal-* >>> >>> Yes, that's how I wanted it, one action per line but Thunderbird >>> messed up my copy/paste, sorry. >>> The only thing you put differently is the precedence: I think it >>> would be intuitive to have white/blacklist actions on the same level >>> and that order matters, so it would be: >>> >>> drop /etc/pango >>> drop /usr/bin/hal-* >>> file /usr/bin/hal-get-property >> >> Wouldn't this make more sense: >> file /usr/bin/hal-get-property >> drop /usr/bin/hal-* >> drop /etc/pango >> >> Since in this case hal-get-property is marked as persistent before you >> go and delete everything hal-*? >> >> In the other ordering you would delete hal-* first and then when you >> get to whitelisting hal-get-property it's already gone. Unless of >> course the ordering of the list is irrelevant and you set a precedence >> that whitelisted files always trump blacklisted files. >> > I think I like the model that WL is always the trump. That way you omit > subtle errors from ordering. If you list it, it stays. > > Question.. can you whitelist a directory? I think you want to allow whitelisting of directories. But, if you allow whitelisting of directories, is the WL recursive? Maybe there needs to be a different parameter to indicate that sort of stuff... Recursiveness also will come into play with the blacklisting directives as well. Perry From hbrock at redhat.com Tue Jul 1 13:42:32 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Tue, 1 Jul 2008 09:42:32 -0400 Subject: [Ovirt-devel] [Patch] Fixed Test Cases In-Reply-To: <4869AD91.4040507@redhat.com> References: <48695EB4.6010005@redhat.com> <4869A32A.80506@redhat.com> <4869AD91.4040507@redhat.com> Message-ID: <20080701134223.GG20856@redhat.com> On Tue, Jul 01, 2008 at 12:07:45AM -0400, Mohammed Morsi wrote: > Scott Seago wrote: >> Mohammed Morsi wrote: >>> With this patch, all test cases but one are fixed. The one involves a >>> quirk when destroying a vm resource pool, where the application >>> incorrectly tries to unassociate hosts from the pool. This is most >>> likely due to the hack we had to do where we associated hosts w/ with >>> the base pools class instead of vm_resource_pools to fix something or >>> an other. >> >> Hmm -- what was your exact error here? Although hosts are listed on >> the base pools class now, there will never be hosts assigned here, so >> the "unassociation" should be a no-op. BTW, the reason we had to move >> the associations to the base class was in order to get :include >> directives working -- so queries on the base class (i.e. >> Pool.children, etc.) could automatically include hosts for child >> Hardware pools -- but hopefully this won't keep tests from working >> here. >> >> Scott > Looking into it further I see the fixtures are incorrect as there were a > few hosts which were associated with a vm resource pool id instead of a > hardware pool id. Changing those to a valid hardware pool resolved the > last of the issues. > > -Mo Very cool... can you make a real git patch and resend then? --Hugh From mmorsi at redhat.com Tue Jul 1 21:06:26 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Tue, 01 Jul 2008 17:06:26 -0400 Subject: [Ovirt-devel] [Patch] Fixed Test Cases In-Reply-To: <20080701134223.GG20856@redhat.com> References: <48695EB4.6010005@redhat.com> <4869A32A.80506@redhat.com> <4869AD91.4040507@redhat.com> <20080701134223.GG20856@redhat.com> Message-ID: <486A9C52.5060409@redhat.com> > Very cool... can you make a real git patch and resend then? > > --Hugh > Attached (includes the latest fix). Also found that when developing on the oVirt appliance, switching the server to look at a oVirt copy you checked out instead of /usr/share/ovirt-wui is as simple as editing /etc/init.d/ovirt-mongrel-rails and changing the OVIRT_DIR at the top of the file and restarting the server. (you will also have to change config/ldap.yml in your ovirt checkout to point to the correct ldap server). -Mo -------------- next part -------------- A non-text attachment was scrubbed... Name: tests-fix2.patch Type: text/x-patch Size: 12145 bytes Desc: not available URL: From hbrock at redhat.com Tue Jul 1 21:31:18 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Tue, 1 Jul 2008 17:31:18 -0400 Subject: [Ovirt-devel] [Patch] Fixed Test Cases In-Reply-To: <486A9C52.5060409@redhat.com> References: <48695EB4.6010005@redhat.com> <4869A32A.80506@redhat.com> <4869AD91.4040507@redhat.com> <20080701134223.GG20856@redhat.com> <486A9C52.5060409@redhat.com> Message-ID: <20080701213114.GO20856@redhat.com> On Tue, Jul 01, 2008 at 05:06:26PM -0400, Mohammed Morsi wrote: > >> Very cool... can you make a real git patch and resend then? >> >> --Hugh >> > Attached (includes the latest fix). Also found that when developing on > the oVirt appliance, switching the server to look at a oVirt copy you > checked out instead of /usr/share/ovirt-wui is as simple as editing > /etc/init.d/ovirt-mongrel-rails and changing the OVIRT_DIR at the top of > the file and restarting the server. (you will also have to change > config/ldap.yml in your ovirt checkout to point to the correct ldap > server). > > > -Mo > >From d31b5cd66aa4833bfbb553e7384f1967b3d48570 Mon Sep 17 00:00:00 2001 > From: root > Date: Tue, 1 Jul 2008 20:49:44 +0000 > Subject: [PATCH] refixed test cases, all now run successfully again > > --- > wui/src/app/controllers/hardware_controller.rb | 1 + > wui/src/app/controllers/host_controller.rb | 5 +++++ > wui/src/config/database.yml | 3 +-- > wui/src/config/ldap.yml | 12 ++++++------ > wui/src/test/fixtures/hosts.yml | 10 +++++----- > wui/src/test/fixtures/permissions.yml | 2 +- > wui/src/test/fixtures/quotas.yml | 6 +++--- > wui/src/test/fixtures/vms.yml | 2 +- > .../test/functional/permission_controller_test.rb | 5 ++--- > wui/src/test/functional/quota_controller_test.rb | 11 ++++------- > .../test/functional/resources_controller_test.rb | 8 +++----- > wui/src/test/functional/storage_controller_test.rb | 11 ++++------- > wui/src/test/functional/vm_controller_test.rb | 11 ++++------- > 13 files changed, 40 insertions(+), 47 deletions(-) > > diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb > index 9718d60..8c8f8c0 100644 > --- a/wui/src/app/controllers/hardware_controller.rb > +++ b/wui/src/app/controllers/hardware_controller.rb > @@ -35,6 +35,7 @@ class HardwareController < ApplicationController > unless @can_view > flash[:notice] = 'You do not have permission to view this hardware pool: redirecting to top level' > redirect_to :controller => "dashboard" > + return > end > if params[:ajax] > render :layout => 'tabs-and-content' > diff --git a/wui/src/app/controllers/host_controller.rb b/wui/src/app/controllers/host_controller.rb > index 8eb26b9..2a72254 100644 > --- a/wui/src/app/controllers/host_controller.rb > +++ b/wui/src/app/controllers/host_controller.rb > @@ -27,6 +27,11 @@ class HostController < ApplicationController > verify :method => :post, :only => [ :destroy, :create, :update ], > :redirect_to => { :action => :list } > > + def list > + @hosts = Host.find(:all) if @hosts.nil? > + end > + > + > def show > set_perms(@perm_obj) > unless @can_view > diff --git a/wui/src/config/database.yml b/wui/src/config/database.yml > index b87fa3e..c60ee8f 100644 > --- a/wui/src/config/database.yml > +++ b/wui/src/config/database.yml > @@ -34,8 +34,7 @@ development: > test: > adapter: postgresql > database: ovirt_test > - username: ovirt > - password: v23zj59an > + username: postgres > host: localhost > > production: > diff --git a/wui/src/config/ldap.yml b/wui/src/config/ldap.yml > index 796c334..e1ef4e7 100644 > --- a/wui/src/config/ldap.yml > +++ b/wui/src/config/ldap.yml > @@ -1,14 +1,14 @@ > development: > - host: ldap.for.your.domain.com > + host: management.priv.ovirt.org > port: 389 > - base: dc=domain,dc=com > + base: dc=priv,dc=ovirt,dc=org > > test: > - host: ldap.for.your.domain.com > + host: management.priv.ovirt.org > port: 389 > - base: dc=domain,dc=com > + base: dc=priv,dc=ovirt,dc=org > > production: > - host: ldap.for.your.domain.com > + host: management.priv.ovirt.org > port: 389 > - base: dc=domain,dc=com > + base: dc=priv,dc=ovirt,dc=org > diff --git a/wui/src/test/fixtures/hosts.yml b/wui/src/test/fixtures/hosts.yml > index 966a829..3b93aea 100644 > --- a/wui/src/test/fixtures/hosts.yml > +++ b/wui/src/test/fixtures/hosts.yml > @@ -30,7 +30,7 @@ three: > memory: 2048 > is_disabled: 0 > hypervisor_type: 'kvm' > - hardware_pool_id: 2 > + hardware_pool_id: 3 > four: > id: 4 > uuid: '520bbb34-6515-490e-9d07-0c8b14f76805' > @@ -41,7 +41,7 @@ four: > memory: 2048 > is_disabled: 1 > hypervisor_type: 'kvm' > - hardware_pool_id: 2 > + hardware_pool_id: 3 > five: > id: 5 > uuid: '2e422f66-324e-48d4-973f-0b91b33070f9' > @@ -49,10 +49,10 @@ five: > num_cpus: 32 > cpu_speed: 4096 > arch: 'xeon' > - memory: 16384 > + memory: 1048576 > is_disabled: 0 > hypervisor_type: 'kvm' > - hardware_pool_id: 2 > + hardware_pool_id: 3 > six: > id: 6 > uuid: 'bb0ce7c7-f234-49ae-84b5-6f4fd8bddcaa' > @@ -63,7 +63,7 @@ six: > memory: 16384 > is_disabled: 0 > hypervisor_type: 'kvm' > - hardware_pool_id: 2 > + hardware_pool_id: 3 > seven: > id: 7 > uuid: '6ae3d22e-97e0-4d86-9712-5395b20a0f45' > diff --git a/wui/src/test/fixtures/permissions.yml b/wui/src/test/fixtures/permissions.yml > index eb99ee2..ded5865 100644 > --- a/wui/src/test/fixtures/permissions.yml > +++ b/wui/src/test/fixtures/permissions.yml > @@ -1,7 +1,7 @@ > one: > id: 1 > user_role: 'Super Admin' > - uid: 'admin' > + uid: 'ovirtadmin' > pool_id: 1 > two: > id: 2 > diff --git a/wui/src/test/fixtures/quotas.yml b/wui/src/test/fixtures/quotas.yml > index 089d688..2d56ea0 100644 > --- a/wui/src/test/fixtures/quotas.yml > +++ b/wui/src/test/fixtures/quotas.yml > @@ -2,7 +2,7 @@ > one: > id: 1 > total_vcpus: 8 > - total_vmemory: 4096 > + total_vmemory: 2097152 > total_vnics: 3 > total_storage: 500 > total_vms: 2 > @@ -30,7 +30,7 @@ four: > total_vnics: > total_storage: > total_vms: 2 > - pool_id: 4 > + pool_id: 6 > five: > id: 5 > total_vcpus: 3 > @@ -58,7 +58,7 @@ seven: > eight: > id: 8 > total_vcpus: 20 > - total_vmemory: 200000 > + total_vmemory: 2097152 > total_vnics: 30 > total_storage: 1111111111 > total_vms: 20 > diff --git a/wui/src/test/fixtures/vms.yml b/wui/src/test/fixtures/vms.yml > index 59c6311..ca783e6 100644 > --- a/wui/src/test/fixtures/vms.yml > +++ b/wui/src/test/fixtures/vms.yml > @@ -4,7 +4,7 @@ one: > description: 'production httpd appliance' > num_vcpus_allocated: 2 > num_vcpus_used: 2 > - memory_allocated: 2048 > + memory_allocated: 262144 > memory_used: 1024 > vnic_mac_addr: '23:51:90:A1:13:37' > state: 'stopped' > diff --git a/wui/src/test/functional/permission_controller_test.rb b/wui/src/test/functional/permission_controller_test.rb > index 61ecf2a..45e7ec5 100644 > --- a/wui/src/test/functional/permission_controller_test.rb > +++ b/wui/src/test/functional/permission_controller_test.rb > @@ -56,10 +56,9 @@ class PermissionControllerTest < Test::Unit::TestCase > def test_create > num_permissions = Permission.count > > - post :create, :permission => { :user_role => 'Administrator', :uid => 'admin', :pool_id => 1} > + post :create, :permission => { :user_role => 'Administrator', :uid => 'admin', :pool_id => 2} > > - assert_response :redirect > - assert_redirected_to :controller => 'hardware', :action => 'show', :id => 1 > + assert_response :success > > assert_equal num_permissions + 1, Permission.count > end > diff --git a/wui/src/test/functional/quota_controller_test.rb b/wui/src/test/functional/quota_controller_test.rb > index c609cf2..c87faef 100644 > --- a/wui/src/test/functional/quota_controller_test.rb > +++ b/wui/src/test/functional/quota_controller_test.rb > @@ -56,10 +56,9 @@ class QuotaControllerTest < Test::Unit::TestCase > def test_create > num_quotas = Quota.count > > - post :create, :quota => { :pool_id => 1 } > + post :create, :quota => { :pool_id => 8 } > > - assert_response :redirect > - assert_redirected_to :controller=> 'hardware', :action => 'show', :id => 1 > + assert_response :success > > assert_equal num_quotas + 1, Quota.count > end > @@ -76,8 +75,7 @@ class QuotaControllerTest < Test::Unit::TestCase > > def test_update > post :update, :id => @first_id > - assert_response :redirect > - assert_redirected_to :action => 'show', :id => @first_id > + assert_response :success > end > > def test_destroy > @@ -88,8 +86,7 @@ class QuotaControllerTest < Test::Unit::TestCase > } > > post :destroy, :id => @first_id > - assert_response :redirect > - assert_redirected_to :controller => 'hardware', :action => 'show', :id => pool.id > + assert_response :success > > assert_raise(ActiveRecord::RecordNotFound) { > Quota.find(@first_id) > diff --git a/wui/src/test/functional/resources_controller_test.rb b/wui/src/test/functional/resources_controller_test.rb > index 8f0099c..fca7aad 100644 > --- a/wui/src/test/functional/resources_controller_test.rb > +++ b/wui/src/test/functional/resources_controller_test.rb > @@ -33,11 +33,10 @@ class ResourcesControllerTest < ActionController::TestCase > > def test_create > assert_difference('VmResourcePool.count') do > - post :create, :vm_resource_pool => { }, :parent_id => 1 > + post :create, :vm_resource_pool => { :name => 'foo_resource_pool' }, :parent_id => 1 > end > > - assert_response :redirect > - assert_redirected_to :controller => 'hardware', :action => 'show', :id => 1 > + assert_response :success > end > > def test_show > @@ -63,8 +62,7 @@ class ResourcesControllerTest < ActionController::TestCase > } > > post :destroy, :id => 2 > - assert_response :redirect > - assert_redirected_to :controller => 'hardware', :action => 'show', :id => pool > + assert_response :success > > assert_raise(ActiveRecord::RecordNotFound) { > VmResourcePool.find(2) > diff --git a/wui/src/test/functional/storage_controller_test.rb b/wui/src/test/functional/storage_controller_test.rb > index 248058f..ff728b9 100644 > --- a/wui/src/test/functional/storage_controller_test.rb > +++ b/wui/src/test/functional/storage_controller_test.rb > @@ -72,10 +72,9 @@ class StorageControllerTest < Test::Unit::TestCase > hw_pool = HardwarePool.get_default_pool > num_storage_volumes = StoragePool.count > > - post :create, :storage_type => 'NFS', :storage_pool => { :hardware_pool => hw_pool, :ip_addr => '111.121.131.141'} > + post :create, :storage_type => 'NFS', :storage_pool => { :hardware_pool => hw_pool, :ip_addr => '111.121.131.141', :export_path => '/tmp/path' } > > - assert_response :redirect > - assert_redirected_to :controller => 'hardware', :action => 'show', :id => hw_pool.id > + assert_response :success > > assert_equal num_storage_volumes + 1, StoragePool.count > end > @@ -92,8 +91,7 @@ class StorageControllerTest < Test::Unit::TestCase > > def test_update > post :update, :id => @first_id > - assert_response :redirect > - assert_redirected_to :action => 'show', :id => @first_id > + assert_response :success > end > > def test_destroy > @@ -104,8 +102,7 @@ class StorageControllerTest < Test::Unit::TestCase > } > > post :destroy, :id => @first_id > - assert_response :redirect > - assert_redirected_to :controller => 'hardware', :action => 'show', :id => hw_pool_id > + assert_response :success > > assert_raise(ActiveRecord::RecordNotFound) { > StoragePool.find(@first_id) > diff --git a/wui/src/test/functional/vm_controller_test.rb b/wui/src/test/functional/vm_controller_test.rb > index aa33625..815321f 100644 > --- a/wui/src/test/functional/vm_controller_test.rb > +++ b/wui/src/test/functional/vm_controller_test.rb > @@ -56,10 +56,9 @@ class VmControllerTest < Test::Unit::TestCase > def test_create > num_vms = Vm.count > > - post :create, :vm_resource_pool_name => 'foobar', :hardware_pool_id => 1, :vm => { :uuid => 'f43b298c-1e65-46fa-965f-0f6fb9ffaa10', :description => 'descript', :num_vcpus_allocated => 4, :memory_allocated => 1024, :vnic_mac_addr => 'AA:BB:CC:DD:EE:FF' } > + post :create, :vm_resource_pool_name => 'foobar', :hardware_pool_id => 1, :vm => { :uuid => 'f43b298c-1e65-46fa-965f-0f6fb9ffaa10', :description => 'descript', :num_vcpus_allocated => 4, :memory_allocated => 262144, :vnic_mac_addr => 'AA:BB:CC:DD:EE:FF' } > > - assert_response :redirect > - assert_redirected_to :controller => 'resources', :action => 'show', :id => 12 > + assert_response :success > > assert_equal num_vms + 1, Vm.count > end > @@ -76,8 +75,7 @@ class VmControllerTest < Test::Unit::TestCase > > def test_update > post :update, :id => @first_id, :vm => {} > - assert_response :redirect > - assert_redirected_to :action => 'show', :id => @first_id > + assert_response :success > end > > def test_destroy > @@ -87,8 +85,7 @@ class VmControllerTest < Test::Unit::TestCase > } > > post :destroy, :id => @first_id > - assert_response :redirect > - assert_redirected_to :controller=>'resources', :action => 'show', :id => pool > + assert_response :success > > assert_raise(ActiveRecord::RecordNotFound) { > Vm.find(@first_id) This looks good to me with one caveat: Even for developer config, we shouldn't ever have to edit an init script -- if a value in an init script needs to change, we should put it in a config file under /etc (right apevec?). Can you check with Alan and work out the right way to do this? In general I think the idea of being able to repoint the Mongrel server for development purposes is very cool. With that fixed I will ACK. Take care, --Hugh From pmyers at redhat.com Tue Jul 1 21:53:14 2008 From: pmyers at redhat.com (Perry Myers) Date: Tue, 1 Jul 2008 17:53:14 -0400 Subject: [Ovirt-devel] [PATCH] [REPOST] [DOC] Merge developer/bundled appliance into a single appliance: ovirt-appliance Message-ID: <1214949194-17440-1-git-send-email-pmyers@redhat.com> The separation of the ovirt appliance image into developer/bundled versions is not necessary, since the only differences between them are in how the host bridge is configured. Developer assumes that you only have a single NIC on your host so you can't have a separate ovirt network managed by the appliance. Bundled assumes you have the second NIC available. These patches remove the separation between bundled/developer. The new appliance is called ovirt-appliance and can be installed with or without a bridge to a real network device. In either case dummy managed nodes are allowed (they can be used in conjunction with the real managed nodes or just ignored in that case) Both build-all.sh and create-wui-appliance.sh have the developer/bundled flags removed, and replaced with -e flag to indicate the ethernet device to use as the bridge. If this is omitted it is assumed that the ovirtbr will not bridge to a physical network. The bridge (if to a physical net) is made persistent in rc.local (eventually libvirt should handle this) If the device to use on the bridge is used already, the script aborts (we don't want to mess up someones eth0 config by accident) Because the appliance name, bridge name and appliance image name have changed (ovirt-appliance, ovirtbr, ovirt-appliance.img) there are sections of the script that clean up the older named appliances. NOTE: This revised patch incorporates suggestions from Chris L. and Jeff Schroeder. Specifically fixing some of the checks for the presence of $bridge, making rc.local executable and fixing the usage syntax for build-all.sh Signed-off-by: Perry Myers --- build-all.sh | 34 ++++---- wui-appliance/create-wui-appliance.sh | 147 ++++++++++++++++++++++----------- 2 files changed, 115 insertions(+), 66 deletions(-) diff --git a/build-all.sh b/build-all.sh index 6e27957..ddeb15d 100755 --- a/build-all.sh +++ b/build-all.sh @@ -29,16 +29,15 @@ DEP_RPMS="createrepo httpd kvm libvirt livecd-tools pungi-1.2.18.1" usage() { case $# in 1) warn "$1"; try_h; exit 1;; esac cat <$KVM_BINARY - + @@ -135,14 +129,12 @@ EOF } gen_app() { - local name=$1 - local disk=$2 - local bridge=$3 - local ram=$4 + local disk=$1 + local ram=$2 cat< - $name + $NAME $(( $ram * 1024 )) $(( $ram * 1024 )) 1 @@ -164,7 +156,7 @@ gen_app() { - + @@ -194,27 +186,58 @@ fi if [ $CHECK -ne 0 ]; then # one of the previous packages wasn't installed; bail out - die "Must have the libvirt, kvm, virt-manager, and virt-viewer packages installed" + die "Must have the $PACKAGES packages installed" fi -if [ $devel = 1 ]; then - NAME=developer - BRIDGENAME=dummybridge - - # define the fake managed nodes we will use - for i in `seq 3 5` ; do - virsh destroy node$i >& /dev/null - virsh undefine node$i >& /dev/null - TMPXML=$(mktemp) - gen_fake_managed_node $i > $TMPXML - virsh define $TMPXML - rm $TMPXML - done -elif [ $bundled = 1 ]; then - NAME=bundled - BRIDGENAME=eth1bridge +service libvirtd status > /dev/null 2>&1 \ + || service libvirtd start > /dev/null 2>&1 +chkconfig libvirtd on + +# Cleanup to handle older version of script that used these bridge names +{ + virsh net-destroy dummybridge + virsh net-undefine dummybridge + brctl delif eth1bridge eth1 + virsh net-destroy eth1bridge + virsh net-undefine eth1bridge +} > /dev/null 2>&1 + +# If we're bridging to a physical network, run some checks to make sure the +# choice of physical eth device is sane +if [ -n "$bridge" ]; then + # Check to see if the physical device is present + ifconfig $bridge > /dev/null 2>&1 ; bridge_dev_present=$? + test $bridge_dev_present != 0 \ + && die "$bridge device not present, aborting!" + + # Check to make sure that the system is not already using the interface + test -f $NET_SCRIPTS/ifcfg-$bridge \ + && die "$bridge defined in $NET_SCRIPTS, aborting!" + + # Check to see if the eth device is already tied to a non oVirt bridge + attached_bridge=$(brctl show \ + | awk -v BRIDGE=$bridge '$4~BRIDGE {print $1}') + test -n "$attached_bridge" -a "$attached_bridge" != "$BRIDGENAME" \ + && die "$bridge already attached to other bridge $attached_bridge" + + # Check to see if the eth device does not have an active inet address + ip address show dev $bridge \ + | grep "inet.*$bridge" > /dev/null 2>&1 ; bridge_dev_active=$? + test $bridge_dev_active == 0 \ + && die "$bridge device active with ip address, aborting!" fi +# define the fake managed nodes we will use. These can be used for both +# developer and bundled, since the bridge name/network config is the same +for i in `seq 3 5` ; do + virsh destroy node$i >& /dev/null + virsh undefine node$i >& /dev/null + TMPXML=$(mktemp) + gen_fake_managed_node $i > $TMPXML + virsh define $TMPXML + rm $TMPXML +done + virsh net-dumpxml $BRIDGENAME >& /dev/null RETVAL=$? if [ $( brctl show | grep -c $BRIDGENAME ) -ne 0 -a $RETVAL -ne 0 ]; then @@ -225,10 +248,20 @@ if [ $( brctl show | grep -c $BRIDGENAME ) -ne 0 -a $RETVAL -ne 0 ]; then exit 1 fi +# Remove old bridge device if it exists +sed -i "/# $BRIDGENAME/d" /etc/rc.d/rc.local +old_bridge=$(brctl show \ + | awk -v BRIDGENAME=$BRIDGENAME '$1~BRIDGENAME {print $4}') +if [ -n "$old_bridge" ]; then + echo "Removing old bridge $old_bridge" + ifconfig $old_bridge down + brctl delif $BRIDGENAME $old_bridge +fi + # TODO when virFileReadAll is fixed for stdin #virsh net-define <(gen_dummy) -virsh net-destroy $BRIDGENAME -virsh net-undefine $BRIDGENAME +virsh net-destroy $BRIDGENAME > /dev/null 2>&1 +virsh net-undefine $BRIDGENAME > /dev/null 2>&1 TMPXML=$(mktemp) || exit 1 gen_bridge $BRIDGENAME > $TMPXML virsh net-define $TMPXML @@ -236,14 +269,32 @@ rm $TMPXML virsh net-start $BRIDGENAME virsh net-autostart $BRIDGENAME -if [ $bundled = 1 ]; then - # unfortunately, these two can't be done by libvirt at the moment, so - # we do them by hand here - # FIXME: how do we make this persistent, so that we survive reboots? - /usr/sbin/brctl addif $BRIDGENAME eth1 - /sbin/ifconfig eth1 up +if [ -n "$bridge" ]; then + # FIXME: unfortunately, these two can't be done by libvirt at the + # moment, so we do them by hand here and persist the config by + # by adding to rc.local + echo "Adding new bridge $bridge" + TMPBRCTL=$(mktemp) || exit 1 + cat > $TMPBRCTL << EOF +brctl addif $BRIDGENAME $bridge # $BRIDGENAME +ifconfig $bridge up # $BRIDGENAME +EOF + chmod a+x $TMPBRCTL /etc/rc.d/rc.local + + cat $TMPBRCTL >> /etc/rc.d/rc.local + + $TMPBRCTL + rm $TMPBRCTL fi +# Cleanup to handle older version of script that used these domain names +{ + virsh destroy developer + virsh undefine developer + virsh destroy bundled + virsh undefine bundled +} > /dev/null 2>&1 + IMGNAME=$NAME.img mkdir -p $IMGDIR virsh destroy $NAME > /dev/null 2>&1 @@ -259,8 +310,8 @@ if [ $do_install = 1 ]; then else test ! -r $IMGDIR/$IMGNAME && die "Disk image not found at $IMGDIR/$IMGNAME" - TMPXML=$(mktemp) - gen_app $NAME $IMGDIR/$IMGNAME $BRIDGENAME $RAM > $TMPXML + TMPXML=$(mktemp) || exit 1 + gen_app $IMGDIR/$IMGNAME $RAM > $TMPXML virsh define $TMPXML rm $TMPXML echo "Application defined using disk located at $IMGDIR/$IMGNAME." -- 1.5.5.1 From apevec at redhat.com Tue Jul 1 21:56:30 2008 From: apevec at redhat.com (Alan Pevec) Date: Tue, 01 Jul 2008 23:56:30 +0200 Subject: [Ovirt-devel] [PATCH] generalized wait_for_service Message-ID: <486AA80E.2080103@redhat.com> service (libvirtd in this case) was assumed to be ready immediately after startup, which wasn't guaranteed. I generalized waiting loop w/ timeout we had for postgres to a shell function, so it can be used where needed. SYNOPSIS: wait_for_service 'test command' n_retries seconds_to_sleep_between_retries -------------- next part -------------- A non-text attachment was scrubbed... Name: wait_for_service.patch Type: text/x-patch Size: 1819 bytes Desc: not available URL: From dpierce at redhat.com Wed Jul 2 01:07:35 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Tue, 01 Jul 2008 21:07:35 -0400 Subject: [Ovirt-devel] [PATCH] [REPOST] [DOC] Merge developer/bundled appliance into a single appliance: ovirt-appliance In-Reply-To: <1214949194-17440-1-git-send-email-pmyers@redhat.com> References: <1214949194-17440-1-git-send-email-pmyers@redhat.com> Message-ID: <486AD4D7.2070307@redhat.com> Perry Myers wrote: > Signed-off-by: Perry Myers > --- > build-all.sh | 34 ++++---- > wui-appliance/create-wui-appliance.sh | 147 ++++++++++++++++++++++----------- > 2 files changed, 115 insertions(+), 66 deletions(-) > > diff --git a/build-all.sh b/build-all.sh > index 6e27957..ddeb15d 100755 > --- a/build-all.sh > +++ b/build-all.sh > @@ -29,16 +29,15 @@ DEP_RPMS="createrepo httpd kvm libvirt livecd-tools pungi-1.2.18.1" > usage() { > case $# in 1) warn "$1"; try_h; exit 1;; esac > cat < -Usage: $ME [-w] [-n] [-p init|update] [-s] [-d|-b] [-a] [-c] [-v git|release|none] > +Usage: $ME [-w] [-n] [-p init|update] [-s] [-a] [-c] [-v git|release|none] [-e eth] > -w: update oVirt WUI RPMs > -n: update oVirt Managed Node RPMs > -p: update pungi repository (init or update) > -s: include SRPMs and produce source ISO > - -d: update developer appliance > - -b: update bundled appliance > - -a: updates all (WUI, Node, App), requires -d or -b > + -a: updates all (WUI, Node, Appliance) > -c: cleanup old repos (pungi and ovirt) > -v: update version type (git, release, none) default is git > + -e: ethernet device to use as bridge (i.e. eth1) > -h: display this help and exit > EOF > } > @@ -57,19 +56,18 @@ update_wui=0 update_node=0 > update_pungi=0 update_app=0 > include_src=0 > cleanup=0 > -app_type= > version_type=git > +bridge= > err=0 help=0 > -while getopts wnp:sdbahcv: c; do > +while getopts wnp:sahcv:e: c; do > case $c in > w) update_wui=1;; > n) update_node=1;; > p) update_pungi=$OPTARG;; > s) include_src=1;; > - d) update_app=1; app_type="-v";; > - b) update_app=1; app_type="-b";; > a) update_wui=1; update_node=1; update_app=1; update_pungi=init;; > c) cleanup=1;; > + e) bridge=$OPTARG;; > v) version_type=$OPTARG;; > h) help=1;; > '?') err=1; warn "invalid option: \`-$OPTARG'";; > @@ -79,7 +77,6 @@ while getopts wnp:sdbahcv: c; do > done > test $err = 1 && { try_h; exit 1; } > test $help = 1 && { usage; exit 0; } > -test $update_app = 1 -a -z "$app_type" && usage "Need to specify -d or -b" > test $include_src = 1 -a "$update_pungi" = 0 && > usage "Need to specify -p when including source" > test "$update_pungi" != 0 -a "$update_pungi" != "init" \ > @@ -262,17 +259,18 @@ repo --name=ovirt-org --baseurl=http://ovirt.org/repos/ovirt/$F_REL/x86_64 $excl > EOF > make > cp wui-rel-*.ks $OVIRT > + > + bridge_flag= > + if [ -n "$bridge" ]; then > + bridge_flag="-e $bridge" > + fi > + > ./create-wui-appliance.sh \ > - -t http://$VIRBR/pungi/$F_REL/$ARCH/os \ > - -k http://$VIRBR/ovirt/wui-rel-$ARCH.ks $app_type > + -t http://$VIRBR/pungi/$F_REL/$ARCH/os \ > + -k http://$VIRBR/ovirt/wui-rel-$ARCH.ks \ > + $bridge_flag > > set +x > echo "oVirt appliance setup started, check progress with:" > - echo -n " virt-viewer " > - if [[ "$app_type" == "-b" ]]; then > - echo "bundled" > - else > - echo "developer" > - fi > - > + echo -n " virt-viewer ovirt-appliance" > fi > diff --git a/wui-appliance/create-wui-appliance.sh b/wui-appliance/create-wui-appliance.sh > index 18d7983..d77ba16 100755 > --- a/wui-appliance/create-wui-appliance.sh > +++ b/wui-appliance/create-wui-appliance.sh > @@ -10,36 +10,34 @@ IMGSIZE=6000M > > ISO= > IMGDIR_DEFAULT=/var/lib/libvirt/images > +NET_SCRIPTS=/etc/sysconfig/network-scripts > ARCH_DEFAULT=$(uname -m) > +NAME=ovirt-appliance > +BRIDGENAME=ovirtbr > > ARCH=$ARCH_DEFAULT > IMGDIR=$IMGDIR_DEFAULT > CONSOLE_FLAG=--noautoconsole > > -# stupid bridge name so that if all of our checks below fail, we will still > -# fail the install > -BRIDGENAME=failme > - > usage() { > case $# in 1) warn "$1"; try_h; exit 1;; esac > cat < -Usage: $ME [-i install_iso | -t install_tree] [-d image_dir] [-a x86_64|i686] [-k kickstart] -v -b > +Usage: $ME [-i install_iso | -t install_tree] [-d image_dir] [-a x86_64|i686] [-k kickstart] [-e eth] > -i: location of installation ISO > -t: location of installation tree > -k: URL of kickstart file for use with installation tree > -o: Display virt-viewer window during install (implied by -i option) > -d: directory to place virtual disk (default: $IMGDIR_DEFAULT) > -a: architecture for the virtual machine (default: $ARCH_DEFAULT) > - -v: Install in developer mode (see http://ovirt.org for details) > - -b: Install in bundled mode (see http://ovirt.org for details) > + -e: ethernet device to use as bridge (i.e. eth1) > -h: display this help and exit > EOF > } > > err=0 help=0 > -devel=0 bundled=0 > viewer=0 > -while getopts :a:d:i:t:k:ohvb c; do > +bridge= > +while getopts :a:d:i:t:k:ohe: c; do > case $c in > i) ISO=$OPTARG;; > t) TREE=$OPTARG;; > @@ -47,9 +45,8 @@ while getopts :a:d:i:t:k:ohvb c; do > d) IMGDIR=$OPTARG;; > a) ARCH=$OPTARG;; > o) CONSOLE_FLAG=;; > + e) bridge=$OPTARG;; > h) help=1;; > - v) devel=1;; > - b) bundled=1;; > '?') err=1; warn "invalid option: \`-$OPTARG'";; > :) err=1; warn "missing argument to \`-$OPTARG' option";; > *) err=1; warn "internal error: \`-$OPTARG' not handled";; > @@ -83,9 +80,6 @@ else > CONSOLE_FLAG= > fi > > -test $devel = 1 -a $bundled = 1 && usage "Can only specify one of -v and -b" > -test $devel = 0 -a $bundled = 0 && usage "Must specify one of -v or -b" > - > case $ARCH in > i686|x86_64);; > *) usage "invalid architecture: \`$ARCH'";; > @@ -125,7 +119,7 @@ gen_fake_managed_node() { > $KVM_BINARY > > > - > + > > > > @@ -135,14 +129,12 @@ EOF > } > > gen_app() { > - local name=$1 > - local disk=$2 > - local bridge=$3 > - local ram=$4 > + local disk=$1 > + local ram=$2 > > cat< > - $name > + $NAME > $(( $ram * 1024 )) > $(( $ram * 1024 )) > 1 > @@ -164,7 +156,7 @@ gen_app() { > > > > - > + > > > > @@ -194,27 +186,58 @@ fi > > if [ $CHECK -ne 0 ]; then > # one of the previous packages wasn't installed; bail out > - die "Must have the libvirt, kvm, virt-manager, and virt-viewer packages installed" > + die "Must have the $PACKAGES packages installed" > fi > > -if [ $devel = 1 ]; then > - NAME=developer > - BRIDGENAME=dummybridge > - > - # define the fake managed nodes we will use > - for i in `seq 3 5` ; do > - virsh destroy node$i >& /dev/null > - virsh undefine node$i >& /dev/null > - TMPXML=$(mktemp) > - gen_fake_managed_node $i > $TMPXML > - virsh define $TMPXML > - rm $TMPXML > - done > -elif [ $bundled = 1 ]; then > - NAME=bundled > - BRIDGENAME=eth1bridge > +service libvirtd status > /dev/null 2>&1 \ > + || service libvirtd start > /dev/null 2>&1 > +chkconfig libvirtd on > + > +# Cleanup to handle older version of script that used these bridge names > +{ > + virsh net-destroy dummybridge > + virsh net-undefine dummybridge > + brctl delif eth1bridge eth1 > + virsh net-destroy eth1bridge > + virsh net-undefine eth1bridge > +} > /dev/null 2>&1 > + > +# If we're bridging to a physical network, run some checks to make sure the > +# choice of physical eth device is sane > +if [ -n "$bridge" ]; then > + # Check to see if the physical device is present > + ifconfig $bridge > /dev/null 2>&1 ; bridge_dev_present=$? > + test $bridge_dev_present != 0 \ > + && die "$bridge device not present, aborting!" > + > + # Check to make sure that the system is not already using the interface > + test -f $NET_SCRIPTS/ifcfg-$bridge \ > + && die "$bridge defined in $NET_SCRIPTS, aborting!" > + > + # Check to see if the eth device is already tied to a non oVirt bridge > + attached_bridge=$(brctl show \ > + | awk -v BRIDGE=$bridge '$4~BRIDGE {print $1}') > + test -n "$attached_bridge" -a "$attached_bridge" != "$BRIDGENAME" \ > + && die "$bridge already attached to other bridge $attached_bridge" > + > + # Check to see if the eth device does not have an active inet address > + ip address show dev $bridge \ > + | grep "inet.*$bridge" > /dev/null 2>&1 ; bridge_dev_active=$? > + test $bridge_dev_active == 0 \ > + && die "$bridge device active with ip address, aborting!" > fi > > +# define the fake managed nodes we will use. These can be used for both > +# developer and bundled, since the bridge name/network config is the same > +for i in `seq 3 5` ; do > + virsh destroy node$i >& /dev/null > + virsh undefine node$i >& /dev/null > + TMPXML=$(mktemp) > + gen_fake_managed_node $i > $TMPXML > + virsh define $TMPXML > + rm $TMPXML > +done > + > virsh net-dumpxml $BRIDGENAME >& /dev/null > RETVAL=$? > if [ $( brctl show | grep -c $BRIDGENAME ) -ne 0 -a $RETVAL -ne 0 ]; then > @@ -225,10 +248,20 @@ if [ $( brctl show | grep -c $BRIDGENAME ) -ne 0 -a $RETVAL -ne 0 ]; then > exit 1 > fi > > +# Remove old bridge device if it exists > +sed -i "/# $BRIDGENAME/d" /etc/rc.d/rc.local > +old_bridge=$(brctl show \ > + | awk -v BRIDGENAME=$BRIDGENAME '$1~BRIDGENAME {print $4}') > +if [ -n "$old_bridge" ]; then > + echo "Removing old bridge $old_bridge" > + ifconfig $old_bridge down > + brctl delif $BRIDGENAME $old_bridge > +fi > + > # TODO when virFileReadAll is fixed for stdin > #virsh net-define <(gen_dummy) > -virsh net-destroy $BRIDGENAME > -virsh net-undefine $BRIDGENAME > +virsh net-destroy $BRIDGENAME > /dev/null 2>&1 > +virsh net-undefine $BRIDGENAME > /dev/null 2>&1 > TMPXML=$(mktemp) || exit 1 > gen_bridge $BRIDGENAME > $TMPXML > virsh net-define $TMPXML > @@ -236,14 +269,32 @@ rm $TMPXML > virsh net-start $BRIDGENAME > virsh net-autostart $BRIDGENAME > > -if [ $bundled = 1 ]; then > - # unfortunately, these two can't be done by libvirt at the moment, so > - # we do them by hand here > - # FIXME: how do we make this persistent, so that we survive reboots? > - /usr/sbin/brctl addif $BRIDGENAME eth1 > - /sbin/ifconfig eth1 up > +if [ -n "$bridge" ]; then > + # FIXME: unfortunately, these two can't be done by libvirt at the > + # moment, so we do them by hand here and persist the config by > + # by adding to rc.local > + echo "Adding new bridge $bridge" > + TMPBRCTL=$(mktemp) || exit 1 > + cat > $TMPBRCTL << EOF > +brctl addif $BRIDGENAME $bridge # $BRIDGENAME > +ifconfig $bridge up # $BRIDGENAME > +EOF > + chmod a+x $TMPBRCTL /etc/rc.d/rc.local > + > + cat $TMPBRCTL >> /etc/rc.d/rc.local > + > + $TMPBRCTL > + rm $TMPBRCTL > fi > > +# Cleanup to handle older version of script that used these domain names > +{ > + virsh destroy developer > + virsh undefine developer > + virsh destroy bundled > + virsh undefine bundled > +} > /dev/null 2>&1 > + > IMGNAME=$NAME.img > mkdir -p $IMGDIR > virsh destroy $NAME > /dev/null 2>&1 > @@ -259,8 +310,8 @@ if [ $do_install = 1 ]; then > else > test ! -r $IMGDIR/$IMGNAME && die "Disk image not found at $IMGDIR/$IMGNAME" > > - TMPXML=$(mktemp) > - gen_app $NAME $IMGDIR/$IMGNAME $BRIDGENAME $RAM > $TMPXML > + TMPXML=$(mktemp) || exit 1 > + gen_app $IMGDIR/$IMGNAME $RAM > $TMPXML > virsh define $TMPXML > rm $TMPXML > echo "Application defined using disk located at $IMGDIR/$IMGNAME." ACK. -- Darryl L. Pierce, Sr. Software Engineer Red Hat, Inc. - http://www.redhat.com/ oVirt - Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" From pmyers at redhat.com Wed Jul 2 02:11:23 2008 From: pmyers at redhat.com (Perry Myers) Date: Tue, 1 Jul 2008 22:11:23 -0400 Subject: [Ovirt-devel] [PATCH] Remove separation between x86_64 and i386 for node and appliance kickstarts Message-ID: <1214964683-22171-1-git-send-email-pmyers@redhat.com> In Fedora 8 we needed to maintain two kickstarts (one for each arch) for the managed node and the wui appliance since Fedora 8 would install the i386 versions of RPMs in the x86_64 OS. Fedora 9 is smarter about this and only installs the package specific to the arch. Since the only difference between the two kickstarts was the removal of specific i386/i686 packages, this can be simplified. Note: This combines my previous two patches that had to do with removing arch specific kickstarts. I determined that these patches were interdependent so doing it as one patch makes more sense. The previous patches this replaces had subjects: [PATCH] Remove separation between x86_64 and i386 managed node kickstarts [PATCH] Remove separation of x86_64 and i386 architectures for appliance and node Signed-off-by: Perry Myers --- build-all.sh | 12 +++--- ovirt-host-creator/Makefile | 4 +- ovirt-host-creator/ovirt-common.sh | 2 +- ovirt-host-creator/ovirt-x86_64.ks | 33 ------------------- ovirt-host-creator/{ovirt-i386.ks => ovirt.ks} | 0 ovirt-host-creator/repos.ks.in | 6 ++-- wui-appliance/.gitignore | 8 +--- wui-appliance/Makefile | 34 +++---------------- wui-appliance/{repos-x86_64.ks.in => repos.ks.in} | 8 ++-- .../{wui-devel-x86_64.ks => wui-devel.ks} | 2 +- 10 files changed, 25 insertions(+), 84 deletions(-) delete mode 100644 ovirt-host-creator/ovirt-x86_64.ks rename ovirt-host-creator/{ovirt-i386.ks => ovirt.ks} (100%) rename wui-appliance/{repos-x86_64.ks.in => repos.ks.in} (50%) rename wui-appliance/{wui-devel-x86_64.ks => wui-devel.ks} (99%) diff --git a/build-all.sh b/build-all.sh index 62fe949..740fa10 100755 --- a/build-all.sh +++ b/build-all.sh @@ -246,25 +246,25 @@ if [ $update_app == 1 ]; then cd $BASE/wui-appliance make clean - cat > repos-x86_64.ks << EOF + cat > repos.ks << EOF url --url http://$VIRBR/pungi/$F_REL/$ARCH/os EOF excludepkgs= if [[ -f $OVIRT/repodata/repomd.xml ]]; then excludepkgs='--excludepkgs=ovirt*' - cat >> repos-x86_64.ks << EOF + cat >> repos.ks << EOF repo --name=ovirt --baseurl=http://$VIRBR/ovirt EOF fi - cat >> repos-x86_64.ks << EOF -repo --name=ovirt-org --baseurl=http://ovirt.org/repos/ovirt/$F_REL/x86_64 $excludepkgs + cat >> repos.ks << EOF +repo --name=ovirt-org --baseurl=http://ovirt.org/repos/ovirt/$F_REL/$ARCH $excludepkgs EOF make - cp wui-rel-*.ks $OVIRT + cp wui-rel.ks $OVIRT ./create-wui-appliance.sh \ -t http://$VIRBR/pungi/$F_REL/$ARCH/os \ - -k http://$VIRBR/ovirt/wui-rel-$ARCH.ks $app_type + -k http://$VIRBR/ovirt/wui-rel.ks $app_type set +x echo "oVirt appliance setup started, check progress with:" diff --git a/ovirt-host-creator/Makefile b/ovirt-host-creator/Makefile index 7d74b08..6f862f3 100644 --- a/ovirt-host-creator/Makefile +++ b/ovirt-host-creator/Makefile @@ -10,9 +10,9 @@ distclean: clean rm -rf *.iso tftpboot repos.ks rpm-build iso-file repos.ks: repos.ks.in - cp repos.ks.in repos.ks + sed "s/@@ARCH@@/$(ARCH)/" repos.ks.in > repos.ks -build: ovirt-$(ARCH).ks common-install.ks common-pkgs.ks common-post.ks repos.ks +build: ovirt.ks common-install.ks common-pkgs.ks common-post.ks repos.ks rm -rf tftpboot/ ./ovirt-pxe.sh > ovirt-pxe.log 2>&1 diff --git a/ovirt-host-creator/ovirt-common.sh b/ovirt-host-creator/ovirt-common.sh index a015cc3..62d2e93 100644 --- a/ovirt-host-creator/ovirt-common.sh +++ b/ovirt-host-creator/ovirt-common.sh @@ -2,7 +2,7 @@ PATH=/sbin:/bin:/usr/bin export PATH create_iso() { - KICKSTART=ovirt-`uname -i`.ks + KICKSTART=ovirt.ks if [ $# -eq 0 ]; then LABEL=ovirt-`date +%Y%m%d%H%M` livecd-creator --skip-minimize -c $KICKSTART -f $LABEL 1>&2 && diff --git a/ovirt-host-creator/ovirt-x86_64.ks b/ovirt-host-creator/ovirt-x86_64.ks deleted file mode 100644 index 302d436..0000000 --- a/ovirt-host-creator/ovirt-x86_64.ks +++ /dev/null @@ -1,33 +0,0 @@ -%include common-install.ks - -%include repos.ks - -%packages --excludedocs -%include common-pkgs.ks --glibc.i686 --xen-libs.i386 --libxml2.i386 --zlib.i386 --libvirt.i386 --avahi.i386 --libgcrypt.i386 --gnutls.i386 --libstdc++.i386 --e2fsprogs-libs.i386 --readline.i386 --libselinux.i386 --device-mapper-libs.i386 --libdaemon.i386 --dbus-libs.i386 --expat.i386 --libsepol.i386 --libcap.i386 --libgpg-error.i386 --libgcc.i386 --cyrus-sasl-gssapi.i386 --cyrus-sasl-lib.i386 - -%post -%include common-post.ks - -%end diff --git a/ovirt-host-creator/ovirt-i386.ks b/ovirt-host-creator/ovirt.ks similarity index 100% rename from ovirt-host-creator/ovirt-i386.ks rename to ovirt-host-creator/ovirt.ks diff --git a/ovirt-host-creator/repos.ks.in b/ovirt-host-creator/repos.ks.in index 6703b91..0a5cb52 100644 --- a/ovirt-host-creator/repos.ks.in +++ b/ovirt-host-creator/repos.ks.in @@ -1,3 +1,3 @@ -repo --name=f9 --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-9&arch=$basearch -repo --name=f9-updates --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=updates-released-f9&arch=$basearch - +repo --name=f9 --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-9&arch=@@ARCH@@ +repo --name=f9-updates --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=updates-released-f9&arch=@@ARCH@@ +repo --name=ovirt --baseurl=http://ovirt.org/repos/ovirt/9/@@ARCH@@ diff --git a/wui-appliance/.gitignore b/wui-appliance/.gitignore index 1eb6469..481444d 100644 --- a/wui-appliance/.gitignore +++ b/wui-appliance/.gitignore @@ -1,6 +1,2 @@ -.deps -wui-devel-i386.ks -wui-rel-i386.ks -wui-rel-x86_64.ks -repos-i386.ks -repos-x86_64.ks +wui-rel.ks +repos.ks diff --git a/wui-appliance/Makefile b/wui-appliance/Makefile index 03c3457..b023622 100644 --- a/wui-appliance/Makefile +++ b/wui-appliance/Makefile @@ -1,14 +1,8 @@ all: ks -primary_src = \ - wui-devel-x86_64.ks \ - wui-devel-i386.ks +ARCH := $(shell uname -i) -rel_ks = \ - wui-rel-i386.ks \ - wui-rel-x86_64.ks - -ks: $(rel_ks) +ks: wui-rel.ks define ks-flatten rm -f $@ $@-t @@ -17,27 +11,11 @@ define ks-flatten mv $@-t $@ endef -wui-rel-%.ks: wui-devel-%.ks +wui-rel.ks: wui-devel.ks repos.ks $(ks-flatten) -repos-x86_64.ks: repos-x86_64.ks.in - cp repos-x86_64.ks.in repos-x86_64.ks - -# Generate each *-i386.ks file from the corresponding -x86_64.ks one. -%-i386.ks: %-x86_64.ks - rm -f $@ $@-t - sed 's/x86_64/i386/' $< > $@-t - chmod a=r $@-t - mv $@-t $@ - -# Generate dependencies. -include .deps -.deps: $(primary_src) - rm -f .deps - for i in $^; do \ - sed -n '/^%include \(.*\.ks\)$$/s//'"$$i: "'\1/p' $$i >> $@-t; \ - done - mv $@-t $@ +repos.ks: repos.ks.in + sed "s/@@ARCH@@/$(ARCH)/" repos.ks.in > repos.ks clean: - rm -f wui-devel-i386.ks repos-i386.ks $(rel_ks) .deps *~ + rm -f repos.ks wui-rel.ks *~ diff --git a/wui-appliance/repos-x86_64.ks.in b/wui-appliance/repos.ks.in similarity index 50% rename from wui-appliance/repos-x86_64.ks.in rename to wui-appliance/repos.ks.in index 54fabed..29fbbc6 100644 --- a/wui-appliance/repos-x86_64.ks.in +++ b/wui-appliance/repos.ks.in @@ -1,6 +1,6 @@ -url --url http://download.fedora.redhat.com/pub/fedora/linux/releases/9/Fedora/x86_64/os/ +url --url http://download.fedora.redhat.com/pub/fedora/linux/releases/9/Fedora/@@ARCH@@/os/ -repo --name=f9 --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-9&arch=x86_64 -repo --name=f9-updates --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=updates-released-f9&arch=x86_64 -repo --name=ovirt --baseurl=http://ovirt.org/repos/ovirt/9/x86_64 +repo --name=f9 --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-9&arch=@@ARCH@@ +repo --name=f9-updates --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=updates-released-f9&arch=@@ARCH@@ +repo --name=ovirt --baseurl=http://ovirt.org/repos/ovirt/9/@@ARCH@@ diff --git a/wui-appliance/wui-devel-x86_64.ks b/wui-appliance/wui-devel.ks similarity index 99% rename from wui-appliance/wui-devel-x86_64.ks rename to wui-appliance/wui-devel.ks index e288560..c50b3a8 100644 --- a/wui-appliance/wui-devel-x86_64.ks +++ b/wui-appliance/wui-devel.ks @@ -9,7 +9,7 @@ logvol /iscsi3 --name=iSCSI3 --vgname=VolGroup00 --size=64 logvol /iscsi4 --name=iSCSI4 --vgname=VolGroup00 --size=64 logvol /iscsi5 --name=iSCSI5 --vgname=VolGroup00 --size=64 -%include repos-x86_64.ks +%include repos.ks %packages --nobase -- 1.5.5.1 From jim at meyering.net Wed Jul 2 06:37:07 2008 From: jim at meyering.net (Jim Meyering) Date: Wed, 02 Jul 2008 08:37:07 +0200 Subject: [Ovirt-devel] [PATCH] generalized wait_for_service In-Reply-To: <486AA80E.2080103@redhat.com> (Alan Pevec's message of "Tue, 01 Jul 2008 23:56:30 +0200") References: <486AA80E.2080103@redhat.com> Message-ID: <87r6achjvw.fsf@rho.meyering.net> Alan Pevec wrote: > service (libvirtd in this case) was assumed to be ready immediately after startup, which wasn't guaranteed. > I generalized waiting loop w/ timeout we had for postgres to a shell function, so it can be used where needed. > > SYNOPSIS: wait_for_service 'test command' n_retries seconds_to_sleep_between_retries Hi Alan, Nice to factor that out. > diff --git a/wui/scripts/ovirt-wui-install b/wui/scripts/ovirt-wui-install > index 6eb7d8e..fc8f8bf 100755 > --- a/wui/scripts/ovirt-wui-install > +++ b/wui/scripts/ovirt-wui-install > @@ -71,6 +71,30 @@ find_ldap_base() { > fi > } > > +wait_for_service() { > + local testcmd=$1; shift > + declare -i timeout=$1; shift > + declare -i seconds=$1; shift Using a name like "sleep_seconds" would help readability. Maybe put your SYNOPSIS comment in the code, too. > + declare -i total > + let total=timeout*seconds > + > + while [[ timeout -gt 0 ]] > + do > + $testcmd > /dev/null 2>&1 > + rc=$? > + if [[ rc -eq 0 ]] > + then > + break > + else > + echo service not ready yet, retrying... > + fi > + let timeout-- > + sleep $seconds > + done > + [[ timeout -eq 0 ]] && printf 'service not ready after %d seconds, giving up\n' $total && exit 1 > +} [[ timeout -eq 0 ]] && { printf 'service not ready after %d seconds, giving up\n' $total 1>&2 exit 1 } I did a double-take at the lack of syntax: no "$" on variable names, the uses of "let" and "declare". On one hand, I like the reduced syntax, but I do find it slightly surprising. If we might ever care about portability to a system without /bin/bash, it'd be better to switch from "[[ var" to "[ $var", etc. Using timeout=$((timeout-1)) is POSIX and nearly as readable as the "let timeout--" bashism. FYI, here's a portable version, checked with dash: wait_for_service() { local testcmd=$1; shift local n_retries=$1; shift local sleep_seconds=$1; shift local total=$((n_retries*sleep_seconds)) while [ $n_retries -gt 0 ] do eval "$testcmd" > /dev/null 2>&1 && return 0 echo service not ready yet, retrying... n_retries=$((n_retries-1)) sleep $sleep_seconds done printf 'service not ready after %d seconds, giving up\n' $total 1>&2 return 1 } Note that while it still prints a diagnostic upon failure (now to stderr), it no longer exits, so you'd use it like this: wait_for_service 'virsh connect' 10 2 || exit 1 From apevec at redhat.com Wed Jul 2 07:30:35 2008 From: apevec at redhat.com (Alan Pevec) Date: Wed, 02 Jul 2008 09:30:35 +0200 Subject: [Ovirt-devel] [PATCH] generalized wait_for_service In-Reply-To: References: <486AA80E.2080103@redhat.com> Message-ID: <486B2E9B.2080607@redhat.com> Jeff Schroeder wrote: > On Tue, Jul 1, 2008 at 2:56 PM, Alan Pevec wrote: >> service (libvirtd in this case) was assumed to be ready immediately after >> startup, which wasn't guaranteed. >> I generalized waiting loop w/ timeout we had for postgres to a shell >> function, so it can be used where needed. >> >> SYNOPSIS: wait_for_service 'test command' n_retries >> seconds_to_sleep_between_retries >> > > We really need to decide on if bashisms are ok or not. Jim is against them, > danpb is for them, I would prefer not to use them, and patches full of them > are flying around. declare is bash specific as far as I know. Good idea for > this patch and it looks solid. > > Either we allow patches with bashism or not. Which is it? The goal of my patch was to factor out the existing code, introducing minimal changes. In general, portability is a noble goal but in scripts which have #!/bin/bash bashism is correct, and bash is available everywhere - apt-get install bash :) It should be pragmatic not political decision whether it's worth it to replace all bashism we have and change the shebang shell or we have other things to do? IMO best way to proceed is to fix as we go: you, Jim and everybody else concerned about portability, keep an eye on new patches and NACK them if you spot non-portal construct. In this case, I'll gladly take Jim's fixed, portable version. As always, patches are welcome! From apevec at redhat.com Wed Jul 2 08:10:43 2008 From: apevec at redhat.com (Alan Pevec) Date: Wed, 02 Jul 2008 10:10:43 +0200 Subject: [Ovirt-devel] [Patch] Fixed Test Cases In-Reply-To: <20080701213114.GO20856@redhat.com> References: <48695EB4.6010005@redhat.com> <4869A32A.80506@redhat.com> <4869AD91.4040507@redhat.com> <20080701134223.GG20856@redhat.com> <486A9C52.5060409@redhat.com> <20080701213114.GO20856@redhat.com> Message-ID: <486B3803.5080201@redhat.com> Hugh O. Brock wrote: > On Tue, Jul 01, 2008 at 05:06:26PM -0400, Mohammed Morsi wrote: >> Attached (includes the latest fix). Also found that when developing on >> the oVirt appliance, switching the server to look at a oVirt copy you >> checked out instead of /usr/share/ovirt-wui is as simple as editing >> /etc/init.d/ovirt-mongrel-rails and changing the OVIRT_DIR at the top of >> the file and restarting the server. (you will also have to change >> config/ldap.yml in your ovirt checkout to point to the correct ldap >> server). > This looks good to me with one caveat: Even for developer config, we > shouldn't ever have to edit an init script -- if a value in an init > script needs to change, we should put it in a config file under /etc > (right apevec?). Can you check with Alan and work out the right way to > do this? In general I think the idea of being able to repoint the > Mongrel server for development purposes is very cool. > > With that fixed I will ACK. Usual place for service customization is /etc/sysconfig/, overriding default values. Something like this should be applied to all sysV service scripts: diff --git a/wui/conf/ovirt-mongrel-rails b/wui/conf/ovirt-mongrel-rails index 67c03c4..9c770ac 100755 --- a/wui/conf/ovirt-mongrel-rails +++ b/wui/conf/ovirt-mongrel-rails @@ -8,16 +8,19 @@ # ovirt VM manager. # -OVIRT_DIR=/usr/share/ovirt-wui +[ -r /etc/sysconfig/ovirt-mongrel-rails ] && . /etc/sysconfig/ovirt-mongrel-rails + +OVIRT_DIR="${OVIRT_DIR:-/usr/share/ovirt-wui}" +MONGREL_LOG="${MONGREL_LOG:-/var/log/ovirt-wui/mongrel.log}" +MONGREL_PID="${MONGREL_PID:-/var/run/ovirt-wui/mongrel.pid}" +MONGREL_LOCKFILE="${MONGREL_LOCKFILE:-/var/lock/subsys/ovirt-wui}" +RAILS_ENVIRONMENT="${RAILS_ENVIRONMENT:-production}" +USER="${USER:-ovirt}" +GROUP="${GROUP:-ovirt}" +PREFIX="${PREFIX:-/ovirt}" + MONGREL_PROG=mongrel_rails -MONGREL_LOG=/var/log/ovirt-wui/mongrel.log -MONGREL_PID=/var/run/ovirt-wui/mongrel.pid -MONGREL_LOCKFILE=/var/lock/subsys/ovirt-wui ADDR=127.0.0.1 -RAILS_ENVIRONMENT=production -USER=ovirt -GROUP=ovirt -PREFIX=/ovirt RETVAL=0 From apevec at redhat.com Wed Jul 2 10:17:40 2008 From: apevec at redhat.com (Alan Pevec) Date: Wed, 2 Jul 2008 12:17:40 +0200 Subject: [Ovirt-devel] [PATCH] generalized wait_for_service In-Reply-To: <87r6achjvw.fsf@rho.meyering.net> References: <87r6achjvw.fsf@rho.meyering.net> Message-ID: <1214993860-6547-1-git-send-email-apevec@redhat.com> services were assumed to be ready immediately after startup, which isn't guaranteed This generalizes waiting loop w/ timeout we had for postgres to a shell function, so it can be used where needed. Portability fix by Jim Meyering Signed-off-by: Alan Pevec --- wui/scripts/ovirt-wui-install | 35 ++++++++++++++++++++--------------- 1 files changed, 20 insertions(+), 15 deletions(-) diff --git a/wui/scripts/ovirt-wui-install b/wui/scripts/ovirt-wui-install index 6eb7d8e..8839358 100755 --- a/wui/scripts/ovirt-wui-install +++ b/wui/scripts/ovirt-wui-install @@ -71,6 +71,24 @@ find_ldap_base() { fi } +# wait_for_service 'test command' max_retries seconds_to_sleep_between_retries +wait_for_service() { + local testcmd=$1; shift + local n_retries=$1; shift + local sleep_seconds=$1; shift + local total=$((n_retries*sleep_seconds)) + + while [ $n_retries -gt 0 ] + do + eval "$testcmd" > /dev/null 2>&1 && return 0 + echo service not ready yet, retrying... + n_retries=$((n_retries-1)) + sleep $sleep_seconds + done + printf 'service not ready after %d seconds, giving up\n' $total 1>&2 + return 1 +} + PASSWD= for i ; do case $1 in @@ -124,6 +142,7 @@ fi # dnsmasq if [[ "$PROD_INST" == "false" ]]; then service libvirtd status > /dev/null 2&>1 || service libvirtd start > /dev/null 2>&1 + wait_for_service 'virsh connect' 10 2 || exit 1 virsh net-destroy default virsh net-undefine default fi @@ -135,21 +154,7 @@ echo "host all all 127.0.0.1 255.255.255.0 trust" >> /var/lib/pgsql/data/pg_hba. service postgresql stop > /dev/null 2>&1 service postgresql start [ $? != 0 ] && echo "Failed to start database" && exit 1 -declare -i timeout=10 -while [[ timeout -gt 0 ]] -do - psql -l -U postgres > /dev/null 2>&1 - rc=$? - if [[ rc -eq 0 ]] - then - break - else - echo Database not ready yet, retrying... - fi - let timeout-- - sleep 2 -done -[[ timeout -eq 0 ]] && echo "Failed to start database" && exit 1 +wait_for_service 'psql -l -U postgres' 10 2 || exit 1 if [ -z $PASSWD ]; then # generate random pg user password -- 1.5.5.1 From apevec at redhat.com Wed Jul 2 10:20:47 2008 From: apevec at redhat.com (Alan Pevec) Date: Wed, 2 Jul 2008 12:20:47 +0200 Subject: [Ovirt-devel] [PATCH] ovirt-wui is noarch now Message-ID: <1214994047-6857-1-git-send-email-apevec@redhat.com> Signed-off-by: Alan Pevec --- wui/ovirt-wui.spec | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/wui/ovirt-wui.spec b/wui/ovirt-wui.spec index f596495..48facb0 100644 --- a/wui/ovirt-wui.spec +++ b/wui/ovirt-wui.spec @@ -37,7 +37,7 @@ BuildRequires: ruby-gettext-package BuildRequires: rubygem(rake) >= 0.7 BuildRequires: avahi-devel Provides: ovirt-wui -BuildArch: i386 x86_64 +BuildArch: noarch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot URL: http://ovirt.org/ -- 1.5.5.1 From apevec at redhat.com Wed Jul 2 10:21:02 2008 From: apevec at redhat.com (Alan Pevec) Date: Wed, 2 Jul 2008 12:21:02 +0200 Subject: [Ovirt-devel] [PATCH] ruby-1.8.6.230-3.fc9 - Resolved segfault issues in Rails Message-ID: <1214994062-6880-1-git-send-email-apevec@redhat.com> Signed-off-by: Alan Pevec --- build-all.sh | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/build-all.sh b/build-all.sh index 740fa10..497977d 100755 --- a/build-all.sh +++ b/build-all.sh @@ -149,7 +149,7 @@ if [ $update_pungi != 0 ]; then fedora_mirror=http://mirrors.fedoraproject.org/mirrorlist # use Fedora + updates - currentbadupdates='--excludepkgs=ruby,ruby-devel,ruby-docs,ruby-irb,ruby-libs,ruby-mode,ruby-rdoc,ruby-ri,ruby-tcltk' + currentbadupdates='' cat > $PUNGIKS << EOF repo --name=f$F_REL \ --mirrorlist=$fedora_mirror?repo=fedora-$F_REL&arch=\$basearch -- 1.5.5.1 From pmyers at redhat.com Wed Jul 2 11:32:03 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Wed, 02 Jul 2008 07:32:03 -0400 Subject: [Ovirt-devel] [PATCH] generalized wait_for_service In-Reply-To: <486B2E9B.2080607@redhat.com> References: <486AA80E.2080103@redhat.com> <486B2E9B.2080607@redhat.com> Message-ID: <486B6733.2090409@redhat.com> Alan Pevec wrote: > Jeff Schroeder wrote: >> On Tue, Jul 1, 2008 at 2:56 PM, Alan Pevec wrote: >>> service (libvirtd in this case) was assumed to be ready immediately >>> after >>> startup, which wasn't guaranteed. >>> I generalized waiting loop w/ timeout we had for postgres to a shell >>> function, so it can be used where needed. >>> >>> SYNOPSIS: wait_for_service 'test command' n_retries >>> seconds_to_sleep_between_retries >>> >> >> We really need to decide on if bashisms are ok or not. Jim is against >> them, >> danpb is for them, I would prefer not to use them, and patches full of >> them >> are flying around. declare is bash specific as far as I know. Good >> idea for >> this patch and it looks solid. >> >> Either we allow patches with bashism or not. Which is it? > > The goal of my patch was to factor out the existing code, introducing > minimal changes. > In general, portability is a noble goal but in scripts which have > #!/bin/bash bashism is correct, and bash is available everywhere - > apt-get install bash :) > > It should be pragmatic not political decision whether it's worth it to > replace all bashism we have and change the shebang shell or we have > other things to do? > IMO best way to proceed is to fix as we go: you, Jim and everybody else > concerned about portability, keep an eye on new patches and NACK them if > you spot non-portal construct. > In this case, I'll gladly take Jim's fixed, portable version. > As always, patches are welcome! I agree with this approach. Portability is a concern, but since bash is fairly prevalent we can fix as we go. Perry From pmyers at redhat.com Wed Jul 2 11:35:05 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Wed, 02 Jul 2008 07:35:05 -0400 Subject: [Ovirt-devel] [PATCH] generalized wait_for_service In-Reply-To: <1214993860-6547-1-git-send-email-apevec@redhat.com> References: <87r6achjvw.fsf@rho.meyering.net> <1214993860-6547-1-git-send-email-apevec@redhat.com> Message-ID: <486B67E9.4010203@redhat.com> Alan Pevec wrote: > services were assumed to be ready immediately after startup, which isn't guaranteed > This generalizes waiting loop w/ timeout we had for postgres to a shell function, so it can be used where needed. > Portability fix by Jim Meyering > > Signed-off-by: Alan Pevec Looks reasonable to me. ACK Perry > --- > wui/scripts/ovirt-wui-install | 35 ++++++++++++++++++++--------------- > 1 files changed, 20 insertions(+), 15 deletions(-) > > diff --git a/wui/scripts/ovirt-wui-install b/wui/scripts/ovirt-wui-install > index 6eb7d8e..8839358 100755 > --- a/wui/scripts/ovirt-wui-install > +++ b/wui/scripts/ovirt-wui-install > @@ -71,6 +71,24 @@ find_ldap_base() { > fi > } > > +# wait_for_service 'test command' max_retries seconds_to_sleep_between_retries > +wait_for_service() { > + local testcmd=$1; shift > + local n_retries=$1; shift > + local sleep_seconds=$1; shift > + local total=$((n_retries*sleep_seconds)) > + > + while [ $n_retries -gt 0 ] > + do > + eval "$testcmd" > /dev/null 2>&1 && return 0 > + echo service not ready yet, retrying... > + n_retries=$((n_retries-1)) > + sleep $sleep_seconds > + done > + printf 'service not ready after %d seconds, giving up\n' $total 1>&2 > + return 1 > +} > + > PASSWD= > for i ; do > case $1 in > @@ -124,6 +142,7 @@ fi > # dnsmasq > if [[ "$PROD_INST" == "false" ]]; then > service libvirtd status > /dev/null 2&>1 || service libvirtd start > /dev/null 2>&1 > + wait_for_service 'virsh connect' 10 2 || exit 1 > virsh net-destroy default > virsh net-undefine default > fi > @@ -135,21 +154,7 @@ echo "host all all 127.0.0.1 255.255.255.0 trust" >> /var/lib/pgsql/data/pg_hba. > service postgresql stop > /dev/null 2>&1 > service postgresql start > [ $? != 0 ] && echo "Failed to start database" && exit 1 > -declare -i timeout=10 > -while [[ timeout -gt 0 ]] > -do > - psql -l -U postgres > /dev/null 2>&1 > - rc=$? > - if [[ rc -eq 0 ]] > - then > - break > - else > - echo Database not ready yet, retrying... > - fi > - let timeout-- > - sleep 2 > -done > -[[ timeout -eq 0 ]] && echo "Failed to start database" && exit 1 > +wait_for_service 'psql -l -U postgres' 10 2 || exit 1 > > if [ -z $PASSWD ]; then > # generate random pg user password -- |=- 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 Wed Jul 2 11:35:28 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Wed, 02 Jul 2008 07:35:28 -0400 Subject: [Ovirt-devel] [PATCH] ovirt-wui is noarch now In-Reply-To: <1214994047-6857-1-git-send-email-apevec@redhat.com> References: <1214994047-6857-1-git-send-email-apevec@redhat.com> Message-ID: <486B6800.9070605@redhat.com> Alan Pevec wrote: > Signed-off-by: Alan Pevec Yep, this is overdue for some time now :) ACK Perry > --- > wui/ovirt-wui.spec | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > diff --git a/wui/ovirt-wui.spec b/wui/ovirt-wui.spec > index f596495..48facb0 100644 > --- a/wui/ovirt-wui.spec > +++ b/wui/ovirt-wui.spec > @@ -37,7 +37,7 @@ BuildRequires: ruby-gettext-package > BuildRequires: rubygem(rake) >= 0.7 > BuildRequires: avahi-devel > Provides: ovirt-wui > -BuildArch: i386 x86_64 > +BuildArch: noarch > BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot > URL: http://ovirt.org/ > -- |=- 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 Wed Jul 2 11:36:23 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Wed, 02 Jul 2008 07:36:23 -0400 Subject: [Ovirt-devel] [PATCH] ruby-1.8.6.230-3.fc9 - Resolved segfault issues in Rails In-Reply-To: <1214994062-6880-1-git-send-email-apevec@redhat.com> References: <1214994062-6880-1-git-send-email-apevec@redhat.com> Message-ID: <486B6837.4090205@redhat.com> Alan Pevec wrote: > Signed-off-by: Alan Pevec Assuming that you verified that these packages upstream are all more functional than the last set :) ACK Perry > --- > build-all.sh | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > diff --git a/build-all.sh b/build-all.sh > index 740fa10..497977d 100755 > --- a/build-all.sh > +++ b/build-all.sh > @@ -149,7 +149,7 @@ if [ $update_pungi != 0 ]; then > > fedora_mirror=http://mirrors.fedoraproject.org/mirrorlist > # use Fedora + updates > - currentbadupdates='--excludepkgs=ruby,ruby-devel,ruby-docs,ruby-irb,ruby-libs,ruby-mode,ruby-rdoc,ruby-ri,ruby-tcltk' > + currentbadupdates='' > cat > $PUNGIKS << EOF > repo --name=f$F_REL \ > --mirrorlist=$fedora_mirror?repo=fedora-$F_REL&arch=\$basearch -- |=- 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 apevec at redhat.com Wed Jul 2 13:41:12 2008 From: apevec at redhat.com (Alan Pevec) Date: Wed, 02 Jul 2008 15:41:12 +0200 Subject: [Ovirt-devel] [PATCH] Remove separation between x86_64 and i386 for node and appliance kickstarts In-Reply-To: <1214964683-22171-1-git-send-email-pmyers@redhat.com> References: <1214964683-22171-1-git-send-email-pmyers@redhat.com> Message-ID: <486B8578.1040102@redhat.com> ACK - i386 builds ok From pmyers at redhat.com Wed Jul 2 13:50:14 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Wed, 02 Jul 2008 09:50:14 -0400 Subject: [Ovirt-devel] [PATCH] Remove separation between x86_64 and i386 for node and appliance kickstarts In-Reply-To: <486B8578.1040102@redhat.com> References: <1214964683-22171-1-git-send-email-pmyers@redhat.com> <486B8578.1040102@redhat.com> Message-ID: <486B8796.4020008@redhat.com> Alan Pevec wrote: > ACK - i386 builds ok > I've tested x86_64 pretty well, so I'll go ahead and commit. If we find problems we'll fix them :) 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 dhuff at redhat.com Wed Jul 2 14:24:08 2008 From: dhuff at redhat.com (David Huff) Date: Wed, 02 Jul 2008 10:24:08 -0400 Subject: [Thincrust-devel] [Fwd: [Ovirt-devel] [PATCH] Add additional blacklisting and rpm removal to managed node] In-Reply-To: <486A33CA.7080102@redhat.com> References: <4868D84E.2000008@redhat.com> <486957FA.1080502@redhat.com> <486A1549.8070308@redhat.com> <486A25D9.5090504@redhat.com> <486A31C1.7000904@redhat.com> <486A31D0.1050208@redhat.com> <486A33CA.7080102@redhat.com> Message-ID: <486B8F88.7000003@redhat.com> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Perry N. Myers wrote: | Bryan Kearney wrote: |> |> |> Perry N. Myers wrote: |>> Alan Pevec wrote: |>>> Bryan Kearney wrote: |>>>> It appears that the interpreter needs to handle the entire post |>>>> section. Is that correct? |>>> |>>> yes, but you can have multiple %post sections, normal w/ shell and |>>> this one with a special interpreter |>>> see ImageCreator.__run_post_scripts() |>>> |>>>> Did the fact that the file command was on the same line matter in |>>>> your example? Or.. could I have written this and gotten the same |>>>> results: |>>>> |>>>> file /usr/bin/hal-get-property |>>>> drop /etc/pango |>>>> drop /usr/bin/hal-* |>>> |>>> Yes, that's how I wanted it, one action per line but Thunderbird |>>> messed up my copy/paste, sorry. |>>> The only thing you put differently is the precedence: I think it |>>> would be intuitive to have white/blacklist actions on the same level |>>> and that order matters, so it would be: |>>> |>>> drop /etc/pango |>>> drop /usr/bin/hal-* |>>> file /usr/bin/hal-get-property |>> |>> Wouldn't this make more sense: |>> file /usr/bin/hal-get-property |>> drop /usr/bin/hal-* |>> drop /etc/pango |>> |>> Since in this case hal-get-property is marked as persistent before |>> you go and delete everything hal-*? |>> |>> In the other ordering you would delete hal-* first and then when you |>> get to whitelisting hal-get-property it's already gone. Unless of |>> course the ordering of the list is irrelevant and you set a |>> precedence that whitelisted files always trump blacklisted files. |>> |> I think I like the model that WL is always the trump. That way you |> omit subtle errors from ordering. If you list it, it stays. |> |> Question.. can you whitelist a directory? | | I think you want to allow whitelisting of directories. | | But, if you allow whitelisting of directories, is the WL recursive? | Maybe there needs to be a different parameter to indicate that sort of | stuff... Recursiveness also will come into play with the blacklisting | directives as well. | | Perry | | _______________________________________________ | Thincrust-devel mailing list | Thincrust-devel at redhat.com | https://www.redhat.com/mailman/listinfo/thincrust-devel Cool I'll look into adding this to the appliance creator tools. What else form the ovirt perspective would help to get the managed node appliance built with the appliance creator tools. Alan had mentioned qcow compression which is on my list is there any others? - -D - -- David Huff Red Hat, Raleigh, NC Mobile: 919-796-3553 Office: 919-754-4129 GPG Key ID: 6A20BBF7 GPG Fingerprint: FE13 8AF6 0E58 D92E A4E1 2D0A 71C1 CADF 6A20 BBF7 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org iD8DBQFIa4+IccHK32ogu/cRAqpQAJ0WkXsAsvgjS37mDdPBXxDpmbRxMgCfYT+s fkbzUD3ctQPHQ+j2GuLGN1U= =CBC2 -----END PGP SIGNATURE----- From dlutter at redhat.com Wed Jul 2 18:08:45 2008 From: dlutter at redhat.com (David Lutterkort) Date: Wed, 02 Jul 2008 18:08:45 +0000 Subject: [Thincrust-devel] [Fwd: [Ovirt-devel] [PATCH] Add additional blacklisting and rpm removal to managed node] In-Reply-To: <486A33CA.7080102@redhat.com> References: <4868D84E.2000008@redhat.com> <486957FA.1080502@redhat.com> <486A1549.8070308@redhat.com> <486A25D9.5090504@redhat.com> <486A31C1.7000904@redhat.com> <486A31D0.1050208@redhat.com> <486A33CA.7080102@redhat.com> Message-ID: <1215022125.3368.112.camel@localhost.localdomain> On Tue, 2008-07-01 at 09:40 -0400, Perry N. Myers wrote: > > Question.. can you whitelist a directory? > > I think you want to allow whitelisting of directories. I agree, but you'll have to be careful to handle intermediate directories right: drop /foo dir /foo/bar/baz means that, implicitly, /foo/bar is also on the whitelist. > But, if you allow whitelisting of directories, is the WL recursive? > Maybe > there needs to be a different parameter to indicate that sort of stuff... > Recursiveness also will come into play with the blacklisting directives > as well. Might be cleanest to build that into the syntax for paths, e.g. following rsync's syntax use '*' to mean 'one component in a path, and '**' to mean 'any number of path components' David From pmyers at redhat.com Wed Jul 2 18:17:22 2008 From: pmyers at redhat.com (Perry Myers) Date: Wed, 2 Jul 2008 14:17:22 -0400 Subject: [Ovirt-devel] [PATCH] Move building of PXE image into RPM build step Message-ID: <1215022642-21227-1-git-send-email-pmyers@redhat.com> Old ovirt-host-image rpm used to store a copy of the ISO and the tftpboot directory. This is redundant. Source file for RPM is now just the ISO and build step uses livecd-tools to build the tftpboot directory from the ISO Signed-off-by: Perry Myers --- ovirt-host-creator/.gitignore | 1 + ovirt-host-creator/Makefile | 6 +++--- ovirt-host-creator/ovirt-cd.sh | 1 + ovirt-host-creator/ovirt-host-image.spec | 17 ++++++++++++----- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/ovirt-host-creator/.gitignore b/ovirt-host-creator/.gitignore index 455b5f7..9adce7e 100644 --- a/ovirt-host-creator/.gitignore +++ b/ovirt-host-creator/.gitignore @@ -3,4 +3,5 @@ iso-file tftpboot rpm-build ovirt-pxe.log +ovirt-cd.log repos.ks diff --git a/ovirt-host-creator/Makefile b/ovirt-host-creator/Makefile index 6f862f3..c522851 100644 --- a/ovirt-host-creator/Makefile +++ b/ovirt-host-creator/Makefile @@ -4,7 +4,7 @@ all: rpms include ../common/release.mk clean: - rm -rf ovirt-host-image-* ovirt-pxe.log + rm -rf ovirt-host-image-* ovirt-pxe.log ovirt-cd.log distclean: clean rm -rf *.iso tftpboot repos.ks rpm-build iso-file @@ -14,12 +14,12 @@ repos.ks: repos.ks.in build: ovirt.ks common-install.ks common-pkgs.ks common-post.ks repos.ks rm -rf tftpboot/ - ./ovirt-pxe.sh > ovirt-pxe.log 2>&1 + ./ovirt-cd.sh > ovirt-cd.log 2>&1 tar: clean build mv $$(cat iso-file) ovirt.iso mkdir -p $(NV) - cp -a ovirt-host-image.spec ovirt.iso tftpboot/* $(NV) + cp -a ovirt-host-image.spec ovirt.iso $(NV) mkdir -p rpm-build tar zcvf rpm-build/$(NV).tar $(NV) cp version rpm-build/ diff --git a/ovirt-host-creator/ovirt-cd.sh b/ovirt-host-creator/ovirt-cd.sh index a4e4cff..0469e6a 100755 --- a/ovirt-host-creator/ovirt-cd.sh +++ b/ovirt-host-creator/ovirt-cd.sh @@ -29,3 +29,4 @@ else fi ISO=`create_iso $ISO` +echo $ISO > iso-file diff --git a/ovirt-host-creator/ovirt-host-image.spec b/ovirt-host-creator/ovirt-host-image.spec index 91ca6af..a4aacc2 100644 --- a/ovirt-host-creator/ovirt-host-image.spec +++ b/ovirt-host-creator/ovirt-host-image.spec @@ -22,15 +22,19 @@ At the moment, this RPM just packages prebuilt ISO. %package pxe Summary: oVirt Managed Node boot PXE image Group: Applications/System +BuildRequires: livecd-tools >= 017.1-1 %description pxe The PXE boot image for oVirt Managed Node network boot from oVirt Admin Node. -At the moment, this RPM just packages prebuilt tftpboot folder. %prep %setup -q %build +/usr/bin/livecd-iso-to-pxeboot ovirt.iso +# append BOOTIF with PXE MAC info +f=tftpboot/pxelinux.cfg/default +grep -q 'IPAPPEND 2' $f || sed -i '/KERNEL/a \\tIPAPPEND 2' $f %install %{__rm} -rf %{buildroot} @@ -38,10 +42,10 @@ mkdir %{buildroot} %{__install} -d -m0755 %{buildroot}%{tftpboot} %{__install} -d -m0755 %{buildroot}%{tftpboot}/pxelinux.cfg -%{__install} -p -m0644 pxelinux.cfg/default %{buildroot}%{tftpboot}/pxelinux.cfg/default -%{__install} -p -m0644 pxelinux.0 %{buildroot}%{tftpboot} -%{__install} -p -m0644 initrd0.img %{buildroot}%{tftpboot} -%{__install} -p -m0644 vmlinuz0 %{buildroot}%{tftpboot} +%{__install} -p -m0644 tftpboot/pxelinux.cfg/default %{buildroot}%{tftpboot}/pxelinux.cfg/default +%{__install} -p -m0644 tftpboot/pxelinux.0 %{buildroot}%{tftpboot} +%{__install} -p -m0644 tftpboot/initrd0.img %{buildroot}%{tftpboot} +%{__install} -p -m0644 tftpboot/vmlinuz0 %{buildroot}%{tftpboot} %{__install} -d -m0755 %{buildroot}%{app_root} %{__install} -p -m0644 ovirt.iso %{buildroot}%{app_root} @@ -60,5 +64,8 @@ mkdir %{buildroot} %{tftpboot}/vmlinuz0 %changelog +* Wed Jul 02 2008 Perry Myers 0.92-0 +- Only store ISO in SRPM, and generate PXE from that during build + * Tue Jun 03 2008 Alan Pevec 0.0.5-1 - Initial build. -- 1.5.5.1 From dpierce at redhat.com Wed Jul 2 20:46:21 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 2 Jul 2008 16:46:21 -0400 Subject: [Ovirt-devel] [PATCH] Using log rotation to minimize writing to the managed node filesystem. Message-ID: <1215031581-27210-1-git-send-email-dpierce@redhat.com> From: Darryl Pierce Signed-off-by: Darryl L. Pierce --- ovirt-host-creator/common-pkgs.ks | 1 + ovirt-managed-node/ovirt-managed-node.spec | 10 ++++++++++ ovirt-managed-node/src/logrotate/ovirt-logrotate | 10 ++++++++++ .../src/logrotate/ovirt-logrotate.conf | 11 +++++++++++ 4 files changed, 32 insertions(+), 0 deletions(-) create mode 100755 ovirt-managed-node/src/logrotate/ovirt-logrotate create mode 100644 ovirt-managed-node/src/logrotate/ovirt-logrotate.conf diff --git a/ovirt-host-creator/common-pkgs.ks b/ovirt-host-creator/common-pkgs.ks index 8d0ba70..2d1ad6e 100644 --- a/ovirt-host-creator/common-pkgs.ks +++ b/ovirt-host-creator/common-pkgs.ks @@ -26,6 +26,7 @@ augeas nc bind-utils syslinux +cronie hal ovirt-managed-node -policycoreutils diff --git a/ovirt-managed-node/ovirt-managed-node.spec b/ovirt-managed-node/ovirt-managed-node.spec index bd807b1..fa943f5 100644 --- a/ovirt-managed-node/ovirt-managed-node.spec +++ b/ovirt-managed-node/ovirt-managed-node.spec @@ -36,6 +36,8 @@ make %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/chkconfig.d %{__install} -d -m0755 %{buildroot}%{_initrddir} %{__install} -d -m0755 %{buildroot}%{app_root} +%{__install} -d -m0755 %{buildroot}%{_sysconfdir}/cron.hourly +%{__install} -d -m0755 %{buildroot}%{_sysconfdir}/logrotate.d %{__install} -p -m0755 scripts/ovirt-awake %{buildroot}%{_sbindir} %{__install} -p -m0755 ovirt-identify-node %{buildroot}%{_sbindir} @@ -52,6 +54,9 @@ make %{__install} -p -m0755 scripts/ovirt-setup %{buildroot}%{app_root} +%{__install} -p -m0644 logrotate/ovirt-logrotate %{buildroot}%{_sysconfdir}/cron.hourly +%{__install} -p -m0644 logrotate/ovirt-logrotate.conf %{buildroot}%{_sysconfdir}/logrotate.d + %clean %{__rm} -rf %{buildroot} @@ -81,6 +86,8 @@ fi %{_initrddir}/ovirt-post %{_sysconfdir}/kvm-ifup %{_sysconfdir}/dhclient-exit-hooks +%config %{_sysconfdir}/logrotate.d/ovirt-logrotate.conf +%config %{_sysconfdir}/cron.hourly/ovirt-logrotate %{app_root}/ovirt-setup %defattr(-,root,root,0644) %{_initrddir}/ovirt-functions @@ -89,5 +96,8 @@ fi %doc README NEWS AUTHOR ChangeLog %changelog +* Wed Jul 02 2008 Darryl Pierce - 0.92 0.2 +- Added log rotation to limit file system writes. + * Mon Jun 30 2008 Perry Myers - 0.92 0.1 - Add in sections of kickstart post, general cleanup diff --git a/ovirt-managed-node/src/logrotate/ovirt-logrotate b/ovirt-managed-node/src/logrotate/ovirt-logrotate new file mode 100755 index 0000000..f0a2dde --- /dev/null +++ b/ovirt-managed-node/src/logrotate/ovirt-logrotate @@ -0,0 +1,10 @@ +#!/bin/sh + +/usr/sbin/logrotate /etc/logrotate.d/ovirt-logrotate.conf + +EXITVALUE=$? +if [ $EXITVALUE != 0 ]; then + /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]" +fi +exit 0 + diff --git a/ovirt-managed-node/src/logrotate/ovirt-logrotate.conf b/ovirt-managed-node/src/logrotate/ovirt-logrotate.conf new file mode 100644 index 0000000..96fb87c --- /dev/null +++ b/ovirt-managed-node/src/logrotate/ovirt-logrotate.conf @@ -0,0 +1,11 @@ +/var/log/*.log { + rotate 0 + missingok + size=10k +} + +/var/log/messages { + rotate 0 + missingok + size=10k +} -- 1.5.5.1 From jguiditt at redhat.com Wed Jul 2 22:39:28 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Wed, 2 Jul 2008 18:39:28 -0400 (EDT) Subject: [Ovirt-devel] [R&D] Breaking the Browser In-Reply-To: <368865082.756671215038318114.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> Message-ID: <722066189.756751215038368416.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> ==Part 1: The Problem == I have been asked to look into some options for how we might fulfill a requirement for the web application to have data pushed to it from the server (instead of polling, which was our short-term solution). This takes us one step further away from the traditional page-centric approach of the web. We are already essentially a 'single page' app, kind of on the line of web2.0 and ria (though I suppose the 'richness' could be argued at this point in time). Just to be a catch-phrasey dork, I am going to call our goal web2.1 (I think 3.0 is presumptuous, but we are trying to do more than just update some content dynamically, a la web2.0). What we really want to do is stream various kinds of data to the client (browser), basically in some sort of subscriber pattern. Here is a rough cut at a couple of use cases for this. Use case #1: * Situation: Joe Admin has given rights to various hosts to Tina Developer. Tina is currently viewing one of these hosts through the ovirt wui. While she is looking at it, Joe realizes she should not have access to this system, and it should in fact be located elsewhere. He makes the changes, so she should no longer see or have access to this box. * Requirement: Tina should immediately be notified that the host she was viewing is no longer accessible, be redirected to either her dashboard or some other default location, and her left navigation tree should update itself to no longer have that host (and any affected sub-hosts or storage, etc). Use Case #2: * Situation: Joe Admin has selected a number of devices to monitor on his dashboard. One or more of the items (graphs) show him up-to-the-second data that he wants to keep an eye on. * Requirement: Joe needs these graphs to be constantly updated (maybe even every second, or 'x' milliseconds') == Part 2: Possible Solutions == There are two main categories of solution here: 1. 'Comet' - a variety of specific implementations, all using some form of standard http request, and requiring only javascript on the client side. 2. Plugin-based TCP connection from the browser. Long-term there is another solution in HTML 5, but it is not yet implemented in any major browsers (well, at least the ones we are targeting): event-source. Basically, this is a new element that you will be able to put in your markup that a server can push data to at will. Very cool, sadly it is not an option yet. Here is a little extra information: http://cometdaily.com/2008/01/10/the-future-of-comet-part-2-html-5%E2%80%99s-server-sent-events/ Each of these solutions has their issues, both from a technical and standards-compliance side. Here is some more information for each. = Comet = * This term was coined by Alex Russell of the Dojo Toolkit ( http://alex.dojotoolkit.org/?p=545 ), and is meant to describe 'long-lived http connections'. * Primer on push technology: http://en.wikipedia.org/wiki/Comet_(programming) Pros: * No plugins needed, just native javascript (or the library of your choice) * Standardization attempt called the Bayeux Protocol. ** pubsub protocol, data encoded in JSON. ** clients can create a 'permanent 'connection using a handshake, or send one-off messages ** reference: http://svn.xantus.org/shortbus/trunk/bayeux/bayeux.html Cons: * Too many long-lived connections to server can cause problems (as in slow performance or crashing of the browser in some cases). HTTP/1.1 specifies no more than 2 open connections per client, and this is enforced by the major browsers. From my understanding, this is why having things like google reader or gmail open for a long time slows down firefox (and probably others) * Bayeux Protocol - currently no ruby implementations that I can find, unless we want to use jruby, in which case, we could use jetty as the server, which does handle comet/bayeux = TCP = * Both Flash and Java can make TCP connections to a server from within a plugin and communicate with the host html page. Pros: * This has the huge benefit of being low-latency, low-bandwidth usage. * Would enable us to use a more standard client/server, pub/sub model --- Flash-specific: ** If the pro-flash folks win out, and the graphs get moved to being flash, then using this for the tcp connection would mean one less plugin required on the client browser. ** There is a rails plugin called juggernaut that does this (http://juggernaut.rubyforge.org/), though it uses it's own event-based server of the same name on the back end (based on eventmachine), not sure how that part would fit in with our messaging needs. Also, it is not very actively developed, and I was unable to get their example working (guess that is not a pro...) --- Java-specific: ** Truly open source, will work on all platforms, once the bug (see cons) is fixed. ** Could potentially, now or in the future, use jruby for the applet, so it would be more in line with the existing knowledge of our current developers. ** Probably more friendly for firewalls/security. While not perfect, I read much less negative articles about use of tcp in applets vs flash (which has had _many_ security issues of late) ** _If_ we wanted to, at some point we could use javafx scripting, though this is not even out in GA yet. This is Sun's entry into the RIA world, to compete with Flash and Silverlight (which of course I am not even reviewing, since it is an MS product). ** Bindings exist in qpid for java/ruby, so we could potentially have easier integration for communication with the messaging system. ** Java has support for kerberos, gssapi, and anything else we might need for auth-related stuff Cons: * _Really_ breaks the web standards, since it isn't even using http. * Open source versions of both plugins currently have issues with the communication between the plugin and the html --- Flash-specific: ** Flash uses an actionscript class called XMLSocket for the TCP connections. One potentially major drawback for this is that it requires a port of 1024 or higher be specified. From my reading, this is a potential issue for corporate firewalls. ** The player communicates with the browser (and vice versa) using the ExternalInterface actionscript class. This works fine on all major browsers with the adobe player (32-bit only, adobe still doesn't support 64), but according to Rob Savoye (the project lead) gnash can only support it through an 'extension', which does not seem to currently exist, nor could I find anything useful to help me get it working. If we wanted to go this route, we would need to write (and possibly maintain) such an extension, which I believe needs to be written in c++. Directions are here- http://www.gnu.org/software/gnash/manual/gnashref.html#extensions. We would also need to figure out packaging of that so it gets installed for the browser plugin. This is outside the realm of my knowledge, so I will leave it to others to discuss the feasibility of this option. ** Didn't see anything on how to integrate flash with kerberos, gssapi, or any of the auth technologies we are using. --- Java-specific: ** There is a java-javascript bridge needed for this to work, and does not have any problems with the sun plugin. However, there is a bug filed against the icedtea/openjdk version because this is not yet implemented (apparently it falls under some of the encumbrances sun has been trying to get rid of for the open source version). The good news here is that it is actually being worked on (http://icedtea.classpath.org/wiki/FrequentlyAskedQuestions#What_is_the_status_of_javascript) so this has the potential of being remedied soon, which gnash does not appear to have. == Part 3: Thoughts == Obviously I do not have final say here, but my feeling is that the best option is the applet approach with TCP (which surprised me, didn't think I would be advocating anything with applets, ever). I think the load incurred by comet makes it not a good option, and the security/plugin issues are making me less in favor of the flash approach (as well as quite possibly running into acceptance issues in the enterprise). Java is well-accepted there, has a better security model, _and_ is now open source. Of course, we know this means more people looking at bugs and fixing them, so security should improve even more with time. I like the possible integration points with qpid, and the future option of considering javafx for graphs should we move away from svg (still not in favor of those being flash). Another point is all of this can be done with the ability to fall back gracefully to lesser platforms. For instance, if java is not allowed, we can optionally fall back to either polling (much less often than we do now) or just updating the browser when the user attempts to perform an action that is no longer possible (like a vm no longer existing), providing a useful failure message and moving them to a sensible replacement location in the app. Similarly with the graphs, they could fall back to periodic updates, and if there was no svg support in a browser, we could even render the data values in a table, so they could still be somewhat useful. I look forward to hearing other people's thoughts on the ideas presented here, including any options that I may have missed or forgotten to mention. -j -------------- next part -------------- An HTML attachment was scrubbed... URL: From jeffschroed at gmail.com Wed Jul 2 23:12:28 2008 From: jeffschroed at gmail.com (Jeff Schroeder) Date: Wed, 2 Jul 2008 16:12:28 -0700 Subject: [Ovirt-devel] [R&D] Breaking the Browser In-Reply-To: <722066189.756751215038368416.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> References: <368865082.756671215038318114.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <722066189.756751215038368416.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> Message-ID: On Wed, Jul 2, 2008 at 3:39 PM, Jason Guiditta wrote: > ==Part 1: The Problem == > > I have been asked to look into some options for how we might fulfill a > requirement for the web application to have data pushed to it from the > server (instead of polling, which was our short-term solution). This takes > us one step further away from the traditional page-centric approach of the > web. We are already essentially a 'single page' app, kind of on the line of > web2.0 and ria (though I suppose the 'richness' could be argued at this > point in time). Just to be a catch-phrasey dork, I am going to call our > goal web2.1 (I think 3.0 is presumptuous, but we are trying to do more than > just update some content dynamically, a la web2.0). What we really want to > do is stream various kinds of data to the client (browser), basically in > some sort of subscriber pattern. Here is a rough cut at a couple of use > cases for this. > > Use case #1: > * Situation: Joe Admin has given rights to various hosts to Tina > Developer. Tina is currently viewing one of these hosts through the ovirt > wui. While she is looking at it, Joe realizes she should not have access > to this system, and it should in fact be located elsewhere. He makes the > changes, so she should no longer see or have access to this box. > * Requirement: Tina should immediately be notified that the host she was > viewing is no longer accessible, be redirected to either her dashboard or > some other default location, and her left navigation tree should update > itself to no longer have that host (and any affected sub-hosts or storage, > etc). Cool, but... why? Why isn't having an error message and a graceful fallback not good enough? You are describing a thick client not a web client. This seems like something where 99% of the people would be ok with an error message and ajax page updates that take them back to a dashboard. In saying ajax I'm meaning dhtml that takes you back to the mainpage with no page refresh more than anything else. This seems like a lot of extra work for a cool feature which wouldn't be missed if it was never implemented. Maybe you could implement a compromise with a javascript timer and a small data stream? Yes that is pull and not push based, but it would be: - Easier to implement - More compatible with existing mechanisms - Not overly complex Do you anticipate 10k different users connection to the wui at the same time? > Use Case #2: > * Situation: Joe Admin has selected a number of devices to monitor on his > dashboard. One or more of the items (graphs) show him up-to-the-second data > that he wants to keep an eye on. > * Requirement: Joe needs these graphs to be constantly updated (maybe even > every second, or 'x' milliseconds') > > == Part 2: Possible Solutions == > > There are two main categories of solution here: > 1. 'Comet' - a variety of specific implementations, all using some form of > standard http request, and requiring only javascript on the client side. > 2. Plugin-based TCP connection from the browser. #2 shouldn't be considered if cross browser compatibility is to be considered. > Long-term there is another solution in HTML 5, but it is not yet implemented > in any major browsers (well, at least the ones we are targeting): > event-source. Basically, this is a new element that you will be able to put > in your markup that a server can push data to at will. Very cool, sadly it > is not an option yet. Here is a little extra information: > http://cometdaily.com/2008/01/10/the-future-of-comet-part-2-html-5%E2%80%99s-server-sent-events/ > > Each of these solutions has their issues, both from a technical and > standards-compliance side. Here is some more information for each. > > = Comet = > * This term was coined by Alex Russell of the Dojo Toolkit > (http://alex.dojotoolkit.org/?p=545), and is meant to describe 'long-lived > http connections'. > * Primer on push technology: > http://en.wikipedia.org/wiki/Comet_(programming) > > Pros: > * No plugins needed, just native javascript (or the library of your choice) > * Standardization attempt called the Bayeux Protocol. > ** pubsub protocol, data encoded in JSON. > ** clients can create a 'permanent 'connection using a handshake, or > send one-off messages > ** reference: http://svn.xantus.org/shortbus/trunk/bayeux/bayeux.html > > Cons: > * Too many long-lived connections to server can cause problems (as in slow > performance or crashing of the browser in some cases). HTTP/1.1 specifies > no more than 2 open connections per client, and this is enforced by the > major browsers. From my understanding, this is why having things like > google reader or gmail open for a long time slows down firefox (and probably > others) > * Bayeux Protocol - currently no ruby implementations that I can find, > unless we want to use jruby, in which case, we could use jetty as the > server, which does handle comet/bayeux > > = TCP = > * Both Flash and Java can make TCP connections to a server from within a > plugin and communicate with the host html page. > > Pros: > * This has the huge benefit of being low-latency, low-bandwidth usage. > * Would enable us to use a more standard client/server, pub/sub model > --- Flash-specific: > ** If the pro-flash folks win out, and the graphs get moved to being > flash, then using this for the tcp connection would mean one less plugin > required on the client browser. > ** There is a rails plugin called juggernaut that does this > (http://juggernaut.rubyforge.org/), though it uses it's own event-based > server of the same name on the back end (based on eventmachine), not sure > how that part would fit in with our messaging needs. Also, it is not very > actively developed, and I was unable to get their example working (guess > that is not a pro...) > --- Java-specific: > ** Truly open source, will work on all platforms, once the bug (see cons) > is fixed. > ** Could potentially, now or in the future, use jruby for the applet, so > it would be more in line with the existing knowledge of our current > developers. > ** Probably more friendly for firewalls/security. While not perfect, I > read much less negative articles about use of tcp in applets vs flash (which > has had _many_ security issues of late) > ** _If_ we wanted to, at some point we could use javafx scripting, though > this is not even out in GA yet. This is Sun's entry into the RIA world, to > compete with Flash and Silverlight (which of course I am not even reviewing, > since it is an MS product). > ** Bindings exist in qpid for java/ruby, so we could potentially have > easier integration for communication with the messaging system. > ** Java has support for kerberos, gssapi, and anything else we might need > for auth-related stuff > > Cons: > * _Really_ breaks the web standards, since it isn't even using http. > * Open source versions of both plugins currently have issues with the > communication between the plugin and the html > --- Flash-specific: > ** Flash uses an actionscript class called XMLSocket for the TCP > connections. One potentially major drawback for this is that it requires a > port of 1024 or higher be specified. From my reading, this is a potential > issue for corporate firewalls. > ** The player communicates with the browser (and vice versa) using the > ExternalInterface actionscript class. This works fine on all major browsers > with the adobe player (32-bit only, adobe still doesn't support 64), but > according to Rob Savoye (the project lead) gnash can only support it > through an 'extension', which does not seem to currently exist, nor could I > find anything useful to help me get it working. If we wanted to go this > route, we would need to write (and possibly maintain) such an extension, > which I believe needs to be written in c++. Directions are here- > http://www.gnu.org/software/gnash/manual/gnashref.html#extensions. We would > also need to figure out packaging of that so it gets installed for the > browser plugin. This is outside the realm of my knowledge, so I will leave > it to others to discuss the feasibility of this option. > ** Didn't see anything on how to integrate flash with kerberos, gssapi, > or any of the auth technologies we are using. > --- Java-specific: > ** There is a java-javascript bridge needed for this to work, and does not > have any problems with the sun plugin. However, there is a bug filed > against the icedtea/openjdk version because this is not yet implemented > (apparently it falls under some of the encumbrances sun has been trying to > get rid of for the open source version). The good news here is that it is > actually being worked on > (http://icedtea.classpath.org/wiki/FrequentlyAskedQuestions#What_is_the_status_of_javascript) > so this has the potential of being remedied soon, which gnash does not > appear to have. > > == Part 3: Thoughts == > Obviously I do not have final say here, but my feeling is that the best > option is the applet approach with TCP (which surprised me, didn't think I > would be advocating anything with applets, ever). I think the load incurred > by comet makes it not a good option, and the security/plugin issues are > making me less in favor of the flash approach (as well as quite possibly > running into acceptance issues in the enterprise). Java is well-accepted > there, has a better security model, _and_ is now open source. Of course, we > know this means more people looking at bugs and fixing them, so security > should improve even more with time. I like the possible integration points > with qpid, and the future option of considering javafx for graphs should we > move away from svg (still not in favor of those being flash). My opinion would be the best solution is to not implement this feature until it is supported via html5 in mainstream browsers. > Another point is all of this can be done with the ability to fall back > gracefully to lesser platforms. For instance, if java is not allowed, we > can optionally fall back to either polling (much less often than we do now) > or just updating the browser when the user attempts to perform an action > that is no longer possible (like a vm no longer existing), providing a > useful failure message and moving them to a sensible replacement location in > the app. Similarly with the graphs, they could fall back to periodic > updates, and if there was no svg support in a browser, we could even render > the data values in a table, so they could still be somewhat useful. > > I look forward to hearing other people's thoughts on the ideas presented > here, including any options that I may have missed or forgotten to mention. For what it isn't really worth, strong NACK. Really good and forward looking idea, but not technically feasible in a clean standards compliant fashion. It still is over my head why a pretty error message (something like litebox) and a page refresh to the dashboard doesn't work. Time could be spent in other places. Building a thick-client in a web browser is one of the things that killed the hula project. The bongo project (hula fork after novell dumped it) is still plagued by the rich web client code-named "dragonfly". Whenever they edit it, things break. Ambition is good, too much is really bad, just my 2 cents. -- Jeff Schroeder Don't drink and derive, alcohol and analysis don't mix. http://www.digitalprognosis.com From apevec at redhat.com Thu Jul 3 11:06:23 2008 From: apevec at redhat.com (Alan Pevec) Date: Thu, 3 Jul 2008 13:06:23 +0200 Subject: [Ovirt-devel] [PATCH] make ovirtadmin also an IPA admin Message-ID: <1215083183-6549-1-git-send-email-apevec@redhat.com> Signed-off-by: Alan Pevec --- wui-appliance/wui-devel.ks | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/wui-appliance/wui-devel.ks b/wui-appliance/wui-devel.ks index c50b3a8..2903a19 100644 --- a/wui-appliance/wui-devel.ks +++ b/wui-appliance/wui-devel.ks @@ -158,6 +158,8 @@ replace: ipaMaxUsernameLength ipaMaxUsernameLength: 12 LDAP ipa-adduser -f Ovirt -l Admin -p @password@ @principal@ + # make ovitadmin also an IPA admin + ipa-modgroup -a ovirtadmin admins ipa-moduser --setattr krbPasswordExpiration=19700101000000Z @principal@ ipa-getkeytab -s management.priv.ovirt.org -p @principal@ -k @ktab_file@ @cron_file@ -- 1.5.4.1 From bkearney at redhat.com Thu Jul 3 11:22:25 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Thu, 03 Jul 2008 07:22:25 -0400 Subject: [Ovirt-devel] [R&D] Breaking the Browser In-Reply-To: <722066189.756751215038368416.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> References: <722066189.756751215038368416.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> Message-ID: <486CB671.8090001@redhat.com> Jason Guiditta wrote: > ==Part 1: The Problem == > > I have been asked to look into some options for how we might fulfill a > requirement for the web application to have data pushed to it from the > server (instead of polling, which was our short-term solution). Just curious.. why is this bad? This > takes us one step further away from the traditional page-centric > approach of the web. We are already essentially a 'single page' app, > kind of on the line of web2.0 and ria (though I suppose the 'richness' > could be argued at this point in time). Just to be a catch-phrasey > dork, I am going to call our goal web2.1 (I think 3.0 is presumptuous, > but we are trying to do more than just update some content dynamically, > a la web2.0). What we really want to do is stream various kinds of data > to the client (browser), basically in some sort of subscriber pattern. > Here is a rough cut at a couple of use cases for this. > > Use case #1: > * Situation: Joe Admin has given rights to various hosts to Tina > Developer. Tina is currently viewing one of these hosts through the > ovirt wui. While she is looking at it, Joe realizes she should not > have access to this system, and it should in fact be located elsewhere. > He makes the changes, so she should no longer see or have access to this > box. > * Requirement: Tina should immediately be notified that the host she > was viewing is no longer accessible, be redirected to either her > dashboard or some other default location, and her left navigation tree > should update itself to no longer have that host (and any affected > sub-hosts or storage, etc). > > Use Case #2: > * Situation: Joe Admin has selected a number of devices to monitor on > his dashboard. One or more of the items (graphs) show him > up-to-the-second data that he wants to keep an eye on. > * Requirement: Joe needs these graphs to be constantly updated (maybe > even every second, or 'x' milliseconds') Perhaps the graphs become a flash/applet? But nothing else? > > == Part 2: Possible Solutions == > > There are two main categories of solution here: > 1. 'Comet' - a variety of specific implementations, all using some form > of standard http request, and requiring only javascript on the client side. > 2. Plugin-based TCP connection from the browser. > > Long-term there is another solution in HTML 5, but it is not yet > implemented in any major browsers (well, at least the ones we are > targeting): event-source. Basically, this is a new element that you > will be able to put in your markup that a server can push data to at > will. Very cool, sadly it is not an option yet. Here is a little extra > information: > http://cometdaily.com/2008/01/10/the-future-of-comet-part-2-html-5%E2%80%99s-server-sent-events/ > > Each of these solutions has their issues, both from a technical and > standards-compliance side. Here is some more information for each. > > = Comet = > * This term was coined by Alex Russell of the Dojo Toolkit > (http://alex.dojotoolkit.org/?p=545), and is meant to describe > 'long-lived http connections'. > * Primer on push technology: > http://en.wikipedia.org/wiki/Comet_(programming) > > Pros: > * No plugins needed, just native javascript (or the library of your choice) > * Standardization attempt called the Bayeux Protocol. > ** pubsub protocol, data encoded in JSON. > ** clients can create a 'permanent 'connection using a handshake, > or send one-off messages > ** reference: http://svn.xantus.org/shortbus/trunk/bayeux/bayeux.html > > Cons: > * Too many long-lived connections to server can cause problems (as in > slow performance or crashing of the browser in some cases). HTTP/1.1 > specifies no more than 2 open connections per client, and this is > enforced by the major browsers. From my understanding, this is why > having things like google reader or gmail open for a long time slows > down firefox (and probably others) > * Bayeux Protocol - currently no ruby implementations that I can find, > unless we want to use jruby, in which case, we could use jetty as the > server, which does handle comet/bayeux > > = TCP = > * Both Flash and Java can make TCP connections to a server from within > a plugin and communicate with the host html page. > > Pros: > * This has the huge benefit of being low-latency, low-bandwidth usage. > * Would enable us to use a more standard client/server, pub/sub model > --- Flash-specific: > ** If the pro-flash folks win out, and the graphs get moved to being > flash, then using this for the tcp connection would mean one less plugin > required on the client browser. > ** There is a rails plugin called juggernaut that does this > (http://juggernaut.rubyforge.org/), though it uses it's own event-based > server of the same name on the back end (based on eventmachine), not > sure how that part would fit in with our messaging needs. Also, it is > not very actively developed, and I was unable to get their example > working (guess that is not a pro...) > --- Java-specific: > ** Truly open source, will work on all platforms, once the bug (see > cons) is fixed. > ** Could potentially, now or in the future, use jruby for the applet, > so it would be more in line with the existing knowledge of our current > developers. > ** Probably more friendly for firewalls/security. While not perfect, > I read much less negative articles about use of tcp in applets vs flash > (which has had _many_ security issues of late) > ** _If_ we wanted to, at some point we could use javafx scripting, > though this is not even out in GA yet. This is Sun's entry into the RIA > world, to compete with Flash and Silverlight (which of course I am not > even reviewing, since it is an MS product). > ** Bindings exist in qpid for java/ruby, so we could potentially have > easier integration for communication with the messaging system. > ** Java has support for kerberos, gssapi, and anything else we might > need for auth-related stuff > > Cons: > * _Really_ breaks the web standards, since it isn't even using http. > * Open source versions of both plugins currently have issues with the > communication between the plugin and the html In a complicated production environment, you may not be allowed to install this. Try asking out SOC guys to open up a wacky port for you. > --- Flash-specific: > ** Flash uses an actionscript class called XMLSocket for the TCP > connections. One potentially major drawback for this is that it > requires a port of 1024 or higher be specified. From my reading, this > is a potential issue for corporate firewalls. > ** The player communicates with the browser (and vice versa) using > the ExternalInterface actionscript class. This works fine on all major > browsers with the adobe player (32-bit only, adobe still doesn't support > 64), but according to Rob Savoye (the project lead) gnash can only > support it through an 'extension', which does not seem to currently > exist, nor could I find anything useful to help me get it working. If > we wanted to go this route, we would need to write (and possibly > maintain) such an extension, which I believe needs to be written in > c++. Directions are here- > http://www.gnu.org/software/gnash/manual/gnashref.html#extensions. We > would also need to figure out packaging of that so it gets installed for > the browser plugin. This is outside the realm of my knowledge, so I > will leave it to others to discuss the feasibility of this option. > ** Didn't see anything on how to integrate flash with kerberos, > gssapi, or any of the auth technologies we are using. > --- Java-specific: > ** There is a java-javascript bridge needed for this to work, and does > not have any problems with the sun plugin. However, there is a bug > filed against the icedtea/openjdk version because this is not yet > implemented (apparently it falls under some of the encumbrances sun has > been trying to get rid of for the open source version). The good news > here is that it is actually being worked on > (http://icedtea.classpath.org/wiki/FrequentlyAskedQuestions#What_is_the_status_of_javascript) > so this has the potential of being remedied soon, which gnash does not > appear to have. > > == Part 3: Thoughts == > Obviously I do not have final say here, but my feeling is that the best > option is the applet approach with TCP (which surprised me, didn't think > I would be advocating anything with applets, ever). I think the load > incurred by comet makes it not a good option, and the security/plugin > issues are making me less in favor of the flash approach (as well as > quite possibly running into acceptance issues in the enterprise). Java > is well-accepted there, has a better security model, _and_ is now open > source. Of course, we know this means more people looking at bugs and > fixing them, so security should improve even more with time. I like the > possible integration points with qpid, and the future option of > considering javafx for graphs should we move away from svg (still not in > favor of those being flash). Is the comet load on the server? I would assume not since there should not be too many folks using the WUI. > > Another point is all of this can be done with the ability to fall back > gracefully to lesser platforms. For instance, if java is not allowed, > we can optionally fall back to either polling (much less often than we > do now) or just updating the browser when the user attempts to perform > an action that is no longer possible (like a vm no longer existing), > providing a useful failure message and moving them to a sensible > replacement location in the app. Similarly with the graphs, they could > fall back to periodic updates, and if there was no svg support in a > browser, we could even render the data values in a table, so they could > still be somewhat useful. > > I look forward to hearing other people's thoughts on the ideas presented > here, including any options that I may have missed or forgotten to mention. > > -j > > > ------------------------------------------------------------------------ > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel From berrange at redhat.com Thu Jul 3 11:45:49 2008 From: berrange at redhat.com (Daniel P. Berrange) Date: Thu, 3 Jul 2008 12:45:49 +0100 Subject: [Ovirt-devel] [R&D] Breaking the Browser In-Reply-To: <722066189.756751215038368416.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> References: <368865082.756671215038318114.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <722066189.756751215038368416.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> Message-ID: <20080703114549.GE9452@redhat.com> Off-topic: please make your mail client insert line breaks in your messages to the likst. On Wed, Jul 02, 2008 at 06:39:28PM -0400, Jason Guiditta wrote: > = TCP = > * Both Flash and Java can make TCP connections to a server from > within a plugin and communicate with the host html page. > > Pros: > * This has the huge benefit of being low-latency, low-bandwidth usage. > * Would enable us to use a more standard client/server, pub/sub model > --- Flash-specific: > ** If the pro-flash folks win out, and the graphs get moved to being > flash, then using this for the tcp connection would mean one less > plugin required on the client browser. > ** There is a rails plugin called juggernaut that does this > (http://juggernaut.rubyforge.org/), though it uses it's own event- > based server of the same name on the back end (based on eventmachine), > not sure how that part would fit in with our messaging needs. Also, it > is not very actively developed, and I was unable to get their example > working (guess that is not a pro...) > --- Java-specific: > ** Truly open source, will work on all platforms, once the bug > (see cons) is fixed. In my experiance Java plugins are a real PITA - for example at one company I worked at, blade centers were using a Java plugin for their remote console. Unfortunatelty this required a specific version of Java from a specific vendor in order to work. Another web app they used required a different version of Java. Spot the problem. Java promises portability, but this is very hard to actually deliver especially in the context of browsers where its hard to switch between different installed versions. Flash has been much better at compatability - i've rarely found things which were broken simply by the user updating to a newer flash release. > ** Could potentially, now or in the future, use jruby for the applet, > so it would be more in line with the existing knowledge of our current > developers. > ** Probably more friendly for firewalls/security. While not perfect, > I read much less negative articles about use of tcp in applets vs > flash (which has had _many_ security issues of late) > ** _If_ we wanted to, at some point we could use javafx scripting, > though this is not even out in GA yet. This is Sun's entry into the > RIA world, to compete with Flash and Silverlight (which of course I > am not even reviewing, since it is an MS product). > ** Bindings exist in qpid for java/ruby, so we could potentially > have easier integration for communication with the messaging system. > ** Java has support for kerberos, gssapi, and anything else we might > need for auth-related stuff I don't think that's a serious problem for graphing at least. If the web page containing the applet is authenticated with Kerberos SSO, its no neccessary to repeat this with the applet. We would simply generate a unique one-time key for the applet when generating the HTML page and the server would validate this when the applet connects. > Cons: > * _Really_ breaks the web standards, since it isn't even using http. > * Open source versions of both plugins currently have issues with > the communication between the plugin and the html > --- Flash-specific: > ** Flash uses an actionscript class called XMLSocket for the TCP > connections. One potentially major drawback for this is that it > requires a port of 1024 or higher be specified. From my reading, > this is a potential issue for corporate firewalls. Well Kerberos isn't going to get across the firewall either so this isn't an issue. We're only talking within scope of an intranet and people don't typically have strict firewalls for purely internal traffic. > ** The player communicates with the browser (and vice versa) using > the ExternalInterface actionscript class. This works fine on all > major browsers with the adobe player (32-bit only, adobe still > doesn't support 64), but according to Rob Savoye (the project > lead) gnash can only support it through an 'extension', which does > not seem to currently exist, nor could I find anything useful to > help me get it working. If we wanted to go this route, we would > need to write (and possibly maintain) such an extension, which I > believe needs to be written in c++. Directions are here- > http://www.gnu.org/software/gnash/manual/gnashref.html#extensions. > We would also need to figure out packaging of that so it gets > installed for the browser plugin. This is outside the realm of > my knowledge, so I will leave it to others to discuss the > feasibility of this option. > ** Didn't see anything on how to integrate flash with kerberos, > gssapi, or any of the auth technologies we are using. I don't expect there is any Kerberos/GSSAPI support. At most I'd expect SSL. I don't see this as an issue though because the web page access is already authenticated & we can just use onetime keys passed to the applet via the webpage. > --- Java-specific: > ** There is a java-javascript bridge needed for this to work, > and does not have any problems with the sun plugin. However, > there is a bug filed against the icedtea/openjdk version > because this is not yet implemented (apparently it falls under > some of the encumbrances sun has been trying to get rid of > for the open source version). The good news here is that it > is actually being worked on (http://icedtea.classpath.org/ > wiki/FrequentlyAskedQuestions#What_is_the_status_of_javascript) > so this has the potential of being remedied soon, which > gnash does not appear to have. > == Part 3: Thoughts == > Obviously I do not have final say here, but my feeling is that > the best option is the applet approach with TCP (which surprised > me, didn't think I would be advocating anything with applets, > ever). I think the load incurred by comet makes it not a good > option, and the security/plugin issues are making me less in > favor of the flash approach (as well as quite possibly running > into acceptance issues in the enterprise). Java is well-accepted > there, has a better security model, _and_ is now open source. Of > course, we know this means more people looking at bugs and fixing > them, so security should improve even more with time. I like the > possible integration points with qpid, and the future option of > considering javafx for graphs should we move away from svg (still > not in favor of those being flash). I agree that we want a plugin approach if we want to have highly interactive graphics. The things that discourage me from Java are the pain wrt deployment on the client browser end in comparison to flash. Second if you look at the major internet sites doing live graphing (eg Yahoo and Google finance) they're all using Flash. The limited open source flash support is a concern, but if we have access to the source of the applet we use, then we can ensure it is written to work within the scope of the open source flash support. > Another point is all of this can be done with the ability to fall > back gracefully to lesser platforms. For instance, if java is not > allowed, we can optionally fall back to either polling (much less > often than we do now) or just updating the browser when the user > attempts to perform an action that is no longer possible (like a > vm no longer existing), providing a useful failure message and > moving them to a sensible replacement location in the app. Similarly > with the graphs, they could fall back to periodic updates, and if > there was no svg support in a browser, we could even render the > data values in a table, so they could still be somewhat useful. I'd just have the server render graphs as PNG and a slow (10-15 second) refresh in javascript as a fallback for non-applet users. 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 pmyers at redhat.com Thu Jul 3 11:59:00 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Thu, 03 Jul 2008 07:59:00 -0400 Subject: [Ovirt-devel] [PATCH] make ovirtadmin also an IPA admin In-Reply-To: <1215083183-6549-1-git-send-email-apevec@redhat.com> References: <1215083183-6549-1-git-send-email-apevec@redhat.com> Message-ID: <486CBF04.8020104@redhat.com> Alan Pevec wrote: > Signed-off-by: Alan Pevec > --- > wui-appliance/wui-devel.ks | 2 ++ > 1 files changed, 2 insertions(+), 0 deletions(-) > > diff --git a/wui-appliance/wui-devel.ks b/wui-appliance/wui-devel.ks > index c50b3a8..2903a19 100644 > --- a/wui-appliance/wui-devel.ks > +++ b/wui-appliance/wui-devel.ks > @@ -158,6 +158,8 @@ replace: ipaMaxUsernameLength > ipaMaxUsernameLength: 12 > LDAP > ipa-adduser -f Ovirt -l Admin -p @password@ @principal@ > + # make ovitadmin also an IPA admin > + ipa-modgroup -a ovirtadmin admins > ipa-moduser --setattr krbPasswordExpiration=19700101000000Z @principal@ > ipa-getkeytab -s management.priv.ovirt.org -p @principal@ -k @ktab_file@ > @cron_file@ This is a good temporary solution for those using the appliance to be able to use both IPA and oVirt with the same principal. We probably should give some more thought to how we want to structure the users though. In the long run having ovirtadmin be an IPA admin might not be the best idea. But ACK for now 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 sghosh at redhat.com Thu Jul 3 13:32:12 2008 From: sghosh at redhat.com (Subhendu Ghosh) Date: Thu, 03 Jul 2008 09:32:12 -0400 Subject: [Ovirt-devel] hardware monitoring support? Message-ID: <486CD4DC.1010600@redhat.com> Are there plans to provide sufficient infrastructure for 3rd party hardware monitoring agents with oVirt hypervisor layer? I am thinking about the usual suspects HP, Dell, IBM -regards Subhendu -- Subhendu Ghosh Solutions Architect Red Hat From veillard at redhat.com Thu Jul 3 13:45:05 2008 From: veillard at redhat.com (Daniel Veillard) Date: Thu, 3 Jul 2008 09:45:05 -0400 Subject: [Ovirt-devel] hardware monitoring support? In-Reply-To: <486CD4DC.1010600@redhat.com> References: <486CD4DC.1010600@redhat.com> Message-ID: <20080703134504.GA1362@redhat.com> On Thu, Jul 03, 2008 at 09:32:12AM -0400, Subhendu Ghosh wrote: > Are there plans to provide sufficient infrastructure for 3rd party > hardware monitoring agents with oVirt hypervisor layer? > > I am thinking about the usual suspects HP, Dell, IBM You mean DMTF CIM providers ? If yes adding libvirt-cim and some CMPI provider package (pegasus or sfcb) on the host images might be possible but it will take room. Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard at redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/ From berrange at redhat.com Thu Jul 3 14:20:12 2008 From: berrange at redhat.com (Daniel P. Berrange) Date: Thu, 3 Jul 2008 15:20:12 +0100 Subject: [Ovirt-devel] hardware monitoring support? In-Reply-To: <486CD4DC.1010600@redhat.com> References: <486CD4DC.1010600@redhat.com> Message-ID: <20080703142012.GH9452@redhat.com> On Thu, Jul 03, 2008 at 09:32:12AM -0400, Subhendu Ghosh wrote: > Are there plans to provide sufficient infrastructure for 3rd party hardware > monitoring agents with oVirt hypervisor layer? The general purpose oVirt host image has tight space constraints which mean that we've stripped the pacakge set installed right back to the bare minimum needed to support oVirt, and we also prune files on a blacklist post-install. So adding extra 3rd party software is not really an option for the general image. If you had a need for extra software though it would be possible to use the livecd tools to build a custom host image at a larger size, containing the extra packages desired. 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 pmyers at redhat.com Thu Jul 3 14:26:11 2008 From: pmyers at redhat.com (Perry Myers) Date: Thu, 3 Jul 2008 10:26:11 -0400 Subject: [Ovirt-devel] [PATCH] Move building of PXE image into RPM build step Message-ID: <1215095171-7207-1-git-send-email-pmyers@redhat.com> Old ovirt-host-image rpm used to store a copy of the ISO and the tftpboot directory. This is redundant. Source file for RPM is now just the ISO and build step uses ovirt-pxe script to build the tftpboot directory from the ISO ovirt-pxe, ovirt-flash and ovirt-flash-static are now all part of the ISO RPM so that users can easily deploy the ISO image onto these media types. Signed-off-by: Perry Myers --- ovirt-host-creator/.gitignore | 2 +- ovirt-host-creator/Makefile | 9 ++--- ovirt-host-creator/{ovirt-cd.sh => ovirt-cd} | 16 ++++------ ovirt-host-creator/ovirt-common.sh | 16 ---------- ovirt-host-creator/{ovirt-flash.sh => ovirt-flash} | 23 +++++---------- .../{ovirt-flash-static.sh => ovirt-flash-static} | 26 ++++++---------- ovirt-host-creator/ovirt-host-image.spec | 30 +++++++++++++++---- ovirt-host-creator/{ovirt-pxe.sh => ovirt-pxe} | 20 ++++-------- 8 files changed, 59 insertions(+), 83 deletions(-) rename ovirt-host-creator/{ovirt-cd.sh => ovirt-cd} (82%) delete mode 100644 ovirt-host-creator/ovirt-common.sh rename ovirt-host-creator/{ovirt-flash.sh => ovirt-flash} (77%) rename ovirt-host-creator/{ovirt-flash-static.sh => ovirt-flash-static} (83%) rename ovirt-host-creator/{ovirt-pxe.sh => ovirt-pxe} (79%) diff --git a/ovirt-host-creator/.gitignore b/ovirt-host-creator/.gitignore index 455b5f7..dee1a01 100644 --- a/ovirt-host-creator/.gitignore +++ b/ovirt-host-creator/.gitignore @@ -2,5 +2,5 @@ iso-file *.iso tftpboot rpm-build -ovirt-pxe.log +ovirt-cd.log repos.ks diff --git a/ovirt-host-creator/Makefile b/ovirt-host-creator/Makefile index 6f862f3..6ebdfbd 100644 --- a/ovirt-host-creator/Makefile +++ b/ovirt-host-creator/Makefile @@ -4,22 +4,21 @@ all: rpms include ../common/release.mk clean: - rm -rf ovirt-host-image-* ovirt-pxe.log + rm -rf ovirt-host-image-* ovirt-cd.log distclean: clean - rm -rf *.iso tftpboot repos.ks rpm-build iso-file + rm -rf *.iso repos.ks rpm-build iso-file repos.ks: repos.ks.in sed "s/@@ARCH@@/$(ARCH)/" repos.ks.in > repos.ks build: ovirt.ks common-install.ks common-pkgs.ks common-post.ks repos.ks - rm -rf tftpboot/ - ./ovirt-pxe.sh > ovirt-pxe.log 2>&1 + ./ovirt-cd > ovirt-cd.log 2>&1 tar: clean build mv $$(cat iso-file) ovirt.iso mkdir -p $(NV) - cp -a ovirt-host-image.spec ovirt.iso tftpboot/* $(NV) + cp -a ovirt-host-image.spec ovirt-pxe ovirt-flash ovirt-flash-static ovirt.iso $(NV) mkdir -p rpm-build tar zcvf rpm-build/$(NV).tar $(NV) cp version rpm-build/ diff --git a/ovirt-host-creator/ovirt-cd.sh b/ovirt-host-creator/ovirt-cd similarity index 82% rename from ovirt-host-creator/ovirt-cd.sh rename to ovirt-host-creator/ovirt-cd index a4e4cff..5678f14 100755 --- a/ovirt-host-creator/ovirt-cd.sh +++ b/ovirt-host-creator/ovirt-cd @@ -17,15 +17,11 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -. ./ovirt-common.sh +PATH=/sbin:/bin:/usr/bin -if [ $# -eq 0 ]; then - ISO= -elif [ $# -eq 1 ]; then - ISO=$1 -else - echo "Usage: ovirt-cd.sh [iso-image]" - exit 1 -fi +KICKSTART=ovirt.ks -ISO=`create_iso $ISO` +LABEL=ovirt-`date +%Y%m%d%H%M` +livecd-creator --skip-minimize -c $KICKSTART -f $LABEL 1>&2 && + +echo $LABEL.iso > iso-file diff --git a/ovirt-host-creator/ovirt-common.sh b/ovirt-host-creator/ovirt-common.sh deleted file mode 100644 index 62d2e93..0000000 --- a/ovirt-host-creator/ovirt-common.sh +++ /dev/null @@ -1,16 +0,0 @@ -PATH=/sbin:/bin:/usr/bin -export PATH - -create_iso() { - KICKSTART=ovirt.ks - if [ $# -eq 0 ]; then - LABEL=ovirt-`date +%Y%m%d%H%M` - livecd-creator --skip-minimize -c $KICKSTART -f $LABEL 1>&2 && - echo $LABEL.iso - elif [ $# -eq 1 ]; then - livecd-creator --skip-minimize -c $KICKSTART -b $1 1>&2 && - echo $1 - else - return 1 - fi -} diff --git a/ovirt-host-creator/ovirt-flash.sh b/ovirt-host-creator/ovirt-flash similarity index 77% rename from ovirt-host-creator/ovirt-flash.sh rename to ovirt-host-creator/ovirt-flash index 621972c..bb5b9be 100755 --- a/ovirt-host-creator/ovirt-flash.sh +++ b/ovirt-host-creator/ovirt-flash @@ -17,25 +17,18 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -. ./ovirt-common.sh +ME=$(basename "$0") +warn() { printf "$ME: $@\n" >&2; } +die() { warn "$@"; exit 1; } -if [ $# -eq 1 ]; then - ISO= -elif [ $# -eq 2 ]; then - ISO=$2 -else - echo "Usage: ovirt-flash.sh [iso-image]" - exit 1 -fi +test $# != 2 && die "Usage: $ME " USBDEVICE=$1 +ISO=$2 -if [ ! -b "$USBDEVICE" ]; then - echo "USB device $USBDEVICE doesn't seem to exist" - exit 2 -fi - -ISO=`create_iso $ISO` || exit 1 +test ! -r $ISO && die "$ISO is not a readable file" +test ! -b $USBDEVICE && die "$USBDEVICE is not a valid block device" +test $( id -u ) -ne 0 && die "$ME must run as root" # clear out the old partition table dd if=/dev/zero of=$USBDEVICE bs=4096 count=1 diff --git a/ovirt-host-creator/ovirt-flash-static.sh b/ovirt-host-creator/ovirt-flash-static similarity index 83% rename from ovirt-host-creator/ovirt-flash-static.sh rename to ovirt-host-creator/ovirt-flash-static index 12e3d14..be9c7c9 100755 --- a/ovirt-host-creator/ovirt-flash-static.sh +++ b/ovirt-host-creator/ovirt-flash-static @@ -17,29 +17,23 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -. ./ovirt-common.sh +ME=$(basename "$0") +warn() { printf "$ME: $@\n" >&2; } +die() { warn "$@"; exit 1; } -if [ $# -eq 1 ]; then - ISO= -elif [ $# -eq 2 ]; then - ISO=$2 -else - echo "Usage: ovirt-flash.sh [iso-image]" - exit 1 -fi +test $# != 2 && die "Usage: $ME " USBDEVICE=$1 +ISO=$2 + +test ! -r $ISO && die "$ISO is not a readable file" +test ! -b $USBDEVICE && die "$USBDEVICE is not a valid block device" +test $( id -u ) -ne 0 && die "$ME must run as root" + IMGTMP=/var/tmp/ovirt-$$ SQUASHTMP=/var/tmp/ovirt-squash-$$ USBTMP=/var/tmp/ovirt-usb-$$ -if [ ! -b "$USBDEVICE" ]; then - echo "USB device $USBDEVICE doesn't seem to exist" - exit 2 -fi - -ISO=`create_iso $ISO` || exit 1 - # do setup mkdir -p $IMGTMP $SQUASHTMP $USBTMP mount -o loop $ISO $IMGTMP diff --git a/ovirt-host-creator/ovirt-host-image.spec b/ovirt-host-creator/ovirt-host-image.spec index 91ca6af..0475cab 100644 --- a/ovirt-host-creator/ovirt-host-image.spec +++ b/ovirt-host-creator/ovirt-host-image.spec @@ -8,6 +8,8 @@ License: Fedora Group: Applications/System BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot URL: http://ovirt.org/ +Requires: livecd-tools >= 017 +Requires: syslinux %define app_root %{_datadir}/%{name} %define tftpboot %{_var}/lib/tftpboot @@ -22,15 +24,16 @@ At the moment, this RPM just packages prebuilt ISO. %package pxe Summary: oVirt Managed Node boot PXE image Group: Applications/System +BuildRequires: livecd-tools >= 017 %description pxe The PXE boot image for oVirt Managed Node network boot from oVirt Admin Node. -At the moment, this RPM just packages prebuilt tftpboot folder. %prep %setup -q %build +./ovirt-pxe ovirt.iso %install %{__rm} -rf %{buildroot} @@ -38,27 +41,40 @@ mkdir %{buildroot} %{__install} -d -m0755 %{buildroot}%{tftpboot} %{__install} -d -m0755 %{buildroot}%{tftpboot}/pxelinux.cfg -%{__install} -p -m0644 pxelinux.cfg/default %{buildroot}%{tftpboot}/pxelinux.cfg/default -%{__install} -p -m0644 pxelinux.0 %{buildroot}%{tftpboot} -%{__install} -p -m0644 initrd0.img %{buildroot}%{tftpboot} -%{__install} -p -m0644 vmlinuz0 %{buildroot}%{tftpboot} +%{__install} -p -m0644 tftpboot/pxelinux.cfg/default %{buildroot}%{tftpboot}/pxelinux.cfg/default +%{__install} -p -m0644 tftpboot/pxelinux.0 %{buildroot}%{tftpboot} +%{__install} -p -m0644 tftpboot/initrd0.img %{buildroot}%{tftpboot} +%{__install} -p -m0644 tftpboot/vmlinuz0 %{buildroot}%{tftpboot} %{__install} -d -m0755 %{buildroot}%{app_root} %{__install} -p -m0644 ovirt.iso %{buildroot}%{app_root} +%{__install} -d -m0755 %{buildroot}%{_sbindir} +%{__install} -p -m0755 ovirt-pxe %{buildroot}%{_sbindir} +%{__install} -p -m0755 ovirt-flash %{buildroot}%{_sbindir} +%{__install} -p -m0755 ovirt-flash-static %{buildroot}%{_sbindir} %clean %{__rm} -rf %{buildroot} %files -%defattr(-,root,root) +%defattr(-,root,root,0644) %{app_root}/ovirt.iso +%defattr(-,root,root,0755) +%{_sbindir}/ovirt-pxe +%{_sbindir}/ovirt-flash +%{_sbindir}/ovirt-flash-static %files pxe -%defattr(-,root,root) +%defattr(-,root,root,0644) %config(noreplace) %{tftpboot}/pxelinux.cfg/default %{tftpboot}/pxelinux.0 %{tftpboot}/initrd0.img %{tftpboot}/vmlinuz0 %changelog +* Thu Jul 03 2008 Perry Myers 0.92-0 +- Only store ISO in SRPM, and generate PXE from that during build + * Tue Jun 03 2008 Alan Pevec 0.0.5-1 - Initial build. + + diff --git a/ovirt-host-creator/ovirt-pxe.sh b/ovirt-host-creator/ovirt-pxe similarity index 79% rename from ovirt-host-creator/ovirt-pxe.sh rename to ovirt-host-creator/ovirt-pxe index 624ac78..facca5b 100755 --- a/ovirt-host-creator/ovirt-pxe.sh +++ b/ovirt-host-creator/ovirt-pxe @@ -17,24 +17,18 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -. ./ovirt-common.sh +ME=$(basename "$0") +warn() { printf "$ME: $@\n" >&2; } +die() { warn "$@"; exit 1; } -if [ $# -eq 0 ]; then - ISO= -elif [ $# -eq 1 ]; then - ISO=$1 -else - echo "Usage: ovirt-pxe.sh [iso-image]" - exit 1 -fi +test $# != 1 && die "Usage: $ME " -rm -f iso-file -ISO=`create_iso $ISO` || exit 1 +ISO=$1 +test ! -r $ISO && die "$ISO is not a readable file" +test $( id -u ) -ne 0 && die "$ME must run as root" livecd-iso-to-pxeboot $ISO # append BOOTIF with PXE MAC info f=tftpboot/pxelinux.cfg/default grep -q 'IPAPPEND 2' $f || sed -i '/KERNEL/a \\tIPAPPEND 2' $f - -echo $ISO > iso-file -- 1.5.5.1 From jmh at redhat.com Thu Jul 3 14:27:27 2008 From: jmh at redhat.com (Jan Mark Holzer) Date: Thu, 03 Jul 2008 10:27:27 -0400 Subject: [Ovirt-devel] hardware monitoring support? In-Reply-To: <20080703142012.GH9452@redhat.com> References: <486CD4DC.1010600@redhat.com> <20080703142012.GH9452@redhat.com> Message-ID: <486CE1CF.9030107@redhat.com> Daniel P. Berrange wrote: > On Thu, Jul 03, 2008 at 09:32:12AM -0400, Subhendu Ghosh wrote: > >> Are there plans to provide sufficient infrastructure for 3rd party hardware >> monitoring agents with oVirt hypervisor layer? >> > > The general purpose oVirt host image has tight space constraints which > mean that we've stripped the pacakge set installed right back to the bare > minimum needed to support oVirt, and we also prune files on a blacklist > post-install. So adding extra 3rd party software is not really an option > for the general image. > > If you had a need for extra software though it would be possible to use > the livecd tools to build a custom host image at a larger size, containing > the extra packages desired. > > Daniel > I think it is/will be important to have a mechanism in place which allows the addition of software (packages/scripts) to the host image (and build a new/custom one (within the rules of supportability) by a non-rocket scientist . Ideally it would be part of the oVirt UI (maybe via an advanced tab and require "special" privileges) and CLI . Maybe another route (or parallel) would to look into a similar remote API capability like ESX3i/3.5 has for 3rd party monitoring apps. They now have to use the remote API and no longer can be installed on the host/HV , this also avoids the issue of someone tinkering with the host image and creating an unsupportable environment . We have had a number of customers asking for this capability (Goldman, UBS, Lehman, BoA etc..) - Jan From apevec at redhat.com Thu Jul 3 14:49:37 2008 From: apevec at redhat.com (Alan Pevec) Date: Thu, 03 Jul 2008 16:49:37 +0200 Subject: [Ovirt-devel] [PATCH] Move building of PXE image into RPM build step In-Reply-To: <1215095171-7207-1-git-send-email-pmyers@redhat.com> References: <1215095171-7207-1-git-send-email-pmyers@redhat.com> Message-ID: <486CE701.3020505@redhat.com> ACK From apevec at redhat.com Thu Jul 3 15:40:38 2008 From: apevec at redhat.com (Alan Pevec) Date: Thu, 3 Jul 2008 17:40:38 +0200 Subject: [Ovirt-devel] [PATCH] use last committish on the current branch for pre-release tag Message-ID: <1215099638-8475-1-git-send-email-apevec@redhat.com> thanks to Jim for another great git tip! Signed-off-by: Alan Pevec --- common/release.mk | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/common/release.mk b/common/release.mk index f1fb5f7..7d45ecb 100644 --- a/common/release.mk +++ b/common/release.mk @@ -11,7 +11,7 @@ NEWVERSION = $$(awk 'BEGIN { printf "%.2f", $(VERSION) + .01 }') NEWRELEASE = $$(($(RELEASE) + 1)) X = $$(awk '{ split($$2,r,"."); \ printf("%d.%d\n", r[1], r[2]+1) }' version) -git_head = $$(git show-ref --hash=7 HEAD) +git_head = $$(git log -1 --pretty=format:%h) GITRELEASE = $(X).$$(date --utc +%Y%m%d%H%M)git$(git_head) DIST = $$(rpm --eval '%{dist}') -- 1.5.4.1 From clalance at redhat.com Thu Jul 3 17:57:57 2008 From: clalance at redhat.com (Chris Lalancette) Date: Thu, 03 Jul 2008 19:57:57 +0200 Subject: [Ovirt-devel] [PATCH] Merge developer/bundled appliance into a single appliance: ovirt-appliance In-Reply-To: <486A3107.3030200@redhat.com> References: <1214691574-11687-1-git-send-email-pmyers@redhat.com> <4868847D.3020001@redhat.com> <48697F86.2020104@redhat.com> <486A3107.3030200@redhat.com> Message-ID: <486D1325.7040800@redhat.com> Perry N. Myers wrote: > Jeff Schroeder wrote: > [snip] >>> However you did point out two things here, first is that the check for >>> ifcfg-eth1 may not be sufficient to detect whether or not the designated >>> interface is running. Secondly there may be portability issues with using >>> ifconfig. I'll see if I can refactor these checks to use something like ip. >>> Suggestions from our friends working in other distros would be appreciated >>> here. >> What makes this more portable than the same thing using ifconfig? >> "ip addr show $bridge > /dev/null 2>&1 ; bridge_dev_present=$?" > > No idea :) Chris just mentioned to me that ifconfig may not be portable, > if you suggest that ifconfig is fairly prevalent then I am content to > leave it that way for the time being. If another random distro wants to > use oVirt, then they can refactor the script accordingly. > I think we mis-understood each other. ifconfig is definitely portable, it's the existence of /etc/sysconfig/network-script files that is very RedHat/Fedora specific. I think these days the "ip" command is slightly preferred to the "ifconfig" command, but I think either should be fine from a cross-distro point of view. Chris Lalancette From jeffschroed at gmail.com Thu Jul 3 18:15:18 2008 From: jeffschroed at gmail.com (Jeff Schroeder) Date: Thu, 3 Jul 2008 11:15:18 -0700 Subject: [Ovirt-devel] [PATCH] Merge developer/bundled appliance into a single appliance: ovirt-appliance In-Reply-To: <486D1325.7040800@redhat.com> References: <1214691574-11687-1-git-send-email-pmyers@redhat.com> <4868847D.3020001@redhat.com> <48697F86.2020104@redhat.com> <486A3107.3030200@redhat.com> <486D1325.7040800@redhat.com> Message-ID: On Thu, Jul 3, 2008 at 10:57 AM, Chris Lalancette wrote: > Perry N. Myers wrote: >> Jeff Schroeder wrote: >> [snip] >>>> However you did point out two things here, first is that the check for >>>> ifcfg-eth1 may not be sufficient to detect whether or not the designated >>>> interface is running. Secondly there may be portability issues with using >>>> ifconfig. I'll see if I can refactor these checks to use something like ip. >>>> Suggestions from our friends working in other distros would be appreciated >>>> here. >>> What makes this more portable than the same thing using ifconfig? >>> "ip addr show $bridge > /dev/null 2>&1 ; bridge_dev_present=$?" >> >> No idea :) Chris just mentioned to me that ifconfig may not be portable, >> if you suggest that ifconfig is fairly prevalent then I am content to >> leave it that way for the time being. If another random distro wants to >> use oVirt, then they can refactor the script accordingly. >> > > I think we mis-understood each other. ifconfig is definitely portable, it's the > existence of /etc/sysconfig/network-script files that is very RedHat/Fedora > specific. I think these days the "ip" command is slightly preferred to the > "ifconfig" command, but I think either should be fine from a cross-distro point > of view. Oh well in that case I agree. For Debian-based distributions this does what you want: egrep -q "^(iface|auto) $bridge" /etc/network/interfaces If the interface has been hand defined (iface...) or if the interface is brought up and magic along the lines of network-manager brings it up (auto) this will find it. > Chris Lalancette -- Jeff Schroeder Don't drink and derive, alcohol and analysis don't mix. http://www.digitalprognosis.com From pmyers at redhat.com Thu Jul 3 18:18:57 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Thu, 03 Jul 2008 14:18:57 -0400 Subject: [Ovirt-devel] [PATCH] Merge developer/bundled appliance into a single appliance: ovirt-appliance In-Reply-To: References: <1214691574-11687-1-git-send-email-pmyers@redhat.com> <4868847D.3020001@redhat.com> <48697F86.2020104@redhat.com> <486A3107.3030200@redhat.com> <486D1325.7040800@redhat.com> Message-ID: <486D1811.8050602@redhat.com> Jeff Schroeder wrote: > On Thu, Jul 3, 2008 at 10:57 AM, Chris Lalancette wrote: >> Perry N. Myers wrote: >>> Jeff Schroeder wrote: >>> [snip] >>>>> However you did point out two things here, first is that the check for >>>>> ifcfg-eth1 may not be sufficient to detect whether or not the designated >>>>> interface is running. Secondly there may be portability issues with using >>>>> ifconfig. I'll see if I can refactor these checks to use something like ip. >>>>> Suggestions from our friends working in other distros would be appreciated >>>>> here. >>>> What makes this more portable than the same thing using ifconfig? >>>> "ip addr show $bridge > /dev/null 2>&1 ; bridge_dev_present=$?" >>> No idea :) Chris just mentioned to me that ifconfig may not be portable, >>> if you suggest that ifconfig is fairly prevalent then I am content to >>> leave it that way for the time being. If another random distro wants to >>> use oVirt, then they can refactor the script accordingly. >>> >> I think we mis-understood each other. ifconfig is definitely portable, it's the >> existence of /etc/sysconfig/network-script files that is very RedHat/Fedora >> specific. I think these days the "ip" command is slightly preferred to the >> "ifconfig" command, but I think either should be fine from a cross-distro point >> of view. > > Oh well in that case I agree. > > For Debian-based distributions this does what you want: > egrep -q "^(iface|auto) $bridge" /etc/network/interfaces > > If the interface has been hand defined (iface...) or if the interface > is brought up > and magic along the lines of network-manager brings it up (auto) this > will find it. I'll add this logic in for Debian and keep the /etc/sysconfig/network-scripts/if- method as a fallback. Perry From jguiditt at redhat.com Thu Jul 3 20:49:30 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Thu, 03 Jul 2008 16:49:30 -0400 Subject: [Ovirt-devel] [R&D] Breaking the Browser In-Reply-To: References: <368865082.756671215038318114.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <722066189.756751215038368416.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> Message-ID: <1215118170.3094.9.camel@localhost.localdomain> On Wed, 2008-07-02 at 16:12 -0700, Jeff Schroeder wrote: > Cool, but... why? Why isn't having an error message and a graceful fallback > not good enough? You are describing a thick client not a web client. This seems > like something where 99% of the people would be ok with an error message and > ajax page updates that take them back to a dashboard. In saying ajax I'm meaning > dhtml that takes you back to the mainpage with no page refresh more > than anything > else. > This is the kind of feedback we were looking for. The idea was that people would want 'real-time' updates (which may still be valid for graphs), but if periodic updates and notification if a user tries to go to something unavailable will suffice, then that is fine (and easier). > This seems like a lot of extra work for a cool feature which wouldn't > be missed if it was > never implemented. Maybe you could implement a compromise with a > javascript timer > and a small data stream? Yes that is pull and not push based, but it would be: > - Easier to implement > - More compatible with existing mechanisms > - Not overly complex We are already doing this with the left nav tree. If we stick with doing periodic updates, we will probably make the refresh time configurable somewhere. > > Do you anticipate 10k different users connection to the wui at the same time? Possibly, yes. Any user who is given permission to something managed by ovirt would be using the webapp, so in a big company, this could be a _lot_ of people. > > My opinion would be the best solution is to not implement this feature until it > is supported via html5 in mainstream browsers. I don't disagree so long as we can meet the needs of our users without it in the interim, and just make it better once html 5 is supported. > For what it isn't really worth, strong NACK. Really good and forward > looking idea, > but not technically feasible in a clean standards compliant fashion. > > It still is over my head why a pretty error message (something like litebox) and > a page refresh to the dashboard doesn't work. Time could be spent in > other places. > Building a thick-client in a web browser is one of the things that > killed the hula project. > The bongo project (hula fork after novell dumped it) is still plagued > by the rich web client > code-named "dragonfly". Whenever they edit it, things break. Ambition > is good, too much > is really bad, just my 2 cents. > Great feedback, thanks! -j From jguiditt at redhat.com Thu Jul 3 20:56:59 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Thu, 03 Jul 2008 16:56:59 -0400 Subject: [Ovirt-devel] [R&D] Breaking the Browser In-Reply-To: <486CB671.8090001@redhat.com> References: <722066189.756751215038368416.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <486CB671.8090001@redhat.com> Message-ID: <1215118619.3094.17.camel@localhost.localdomain> On Thu, 2008-07-03 at 07:22 -0400, Bryan Kearney wrote: > > Jason Guiditta wrote: > > ==Part 1: The Problem == > > > > I have been asked to look into some options for how we might fulfill a > > requirement for the web application to have data pushed to it from the > > server (instead of polling, which was our short-term solution). > > Just curious.. why is this bad? As long as you are not polling too often, it is not bad, but we were trying to simulate real-time updates, which means _very_ frequent polling, which would create an enormous load of the server (could even be described as a DOS) in any environments with more than a few users. > > > Perhaps the graphs become a flash/applet? But nothing else? Based on feedback thus far, this is a definite possibility > In a complicated production environment, you may not be allowed to > install this. Try asking out SOC guys to open up a wacky port for you. > I was assuming this would be proxied in some way as with services like xmpp in a webapp (like previous incarnations of rhx). > Is the comet load on the server? I would assume not since there should > not be too many folks using the WUI. > Yes, on the server, though the holding a connection open would also affect the client. And our assumption is that there could potentially be _many_ people using the webapp, as mentioned above. -j From jeffschroed at gmail.com Thu Jul 3 20:59:45 2008 From: jeffschroed at gmail.com (Jeff Schroeder) Date: Thu, 3 Jul 2008 13:59:45 -0700 Subject: [Ovirt-devel] [R&D] Breaking the Browser In-Reply-To: <1215118170.3094.9.camel@localhost.localdomain> References: <368865082.756671215038318114.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <722066189.756751215038368416.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <1215118170.3094.9.camel@localhost.localdomain> Message-ID: On Thu, Jul 3, 2008 at 1:49 PM, Jason Guiditta wrote: > On Wed, 2008-07-02 at 16:12 -0700, Jeff Schroeder wrote: > >> Cool, but... why? Why isn't having an error message and a graceful fallback >> not good enough? You are describing a thick client not a web client. This seems >> like something where 99% of the people would be ok with an error message and >> ajax page updates that take them back to a dashboard. In saying ajax I'm meaning >> dhtml that takes you back to the mainpage with no page refresh more >> than anything >> else. >> > This is the kind of feedback we were looking for. The idea was that > people would want 'real-time' updates (which may still be valid for > graphs), but if periodic updates and notification if a user tries to go > to something unavailable will suffice, then that is fine (and easier). Q: How do you get realtime graphs with a webapp? A: SVG + AJAX A good example of how to do this would be the m0n0wall firewall. Here is a screenshot of their interface graphs: http://m0n0.ch/wall/images/screens/status_graph.png The svg graphs are drawn by the javascript. It gets the data from a xmlhttprequest feed directly from the server. It is really sexy technology and most browsers support it. Is asking IE users to install the Adobe SVG plugin or user Firefox too much? Take a look at how easy this is to do: http://www.browserland.org/scripts/svgclock/ If you compress that svg down, the whole thing is 4k. I don't even think flash could do something that smooth and clean looking in 4k. Were you aware of this? -- Jeff Schroeder Don't drink and derive, alcohol and analysis don't mix. http://www.digitalprognosis.com From jguiditt at redhat.com Thu Jul 3 21:09:46 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Thu, 03 Jul 2008 17:09:46 -0400 Subject: [Ovirt-devel] [R&D] Breaking the Browser In-Reply-To: <20080703114549.GE9452@redhat.com> References: <368865082.756671215038318114.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <722066189.756751215038368416.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <20080703114549.GE9452@redhat.com> Message-ID: <1215119386.3094.30.camel@localhost.localdomain> On Thu, 2008-07-03 at 12:45 +0100, Daniel P. Berrange wrote: > Off-topic: please make your mail client insert line breaks in your > messages to the likst. > Apologies, used the web client, which apparently has some formatting issues for plain text. > In my experiance Java plugins are a real PITA - for example at one > company I worked at, blade centers were using a Java plugin for their > remote console. Unfortunatelty this required a specific version of > Java from a specific vendor in order to work. Another web app they > used required a different version of Java. Spot the problem. > > Java promises portability, but this is very hard to actually deliver > especially in the context of browsers where its hard to switch between > different installed versions. I think this is less of an issue than it used to be, but point well taken, it could be extra complexity we don't need. > > Flash has been much better at compatability - i've rarely found things > which were broken simply by the user updating to a newer flash release. The main one I was concerned about here was the ExternalInterface class, introduced in flash 8 to allow communication with the host html page. As I mentioned, this is not support in gnash. However, if we use this just for charts, there is probably no requirement for that interface, so it may not be an issue. > > I don't think that's a serious problem for graphing at least. If the > web page containing the applet is authenticated with Kerberos SSO, > its no neccessary to repeat this with the applet. We would simply > generate a unique one-time key for the applet when generating the > HTML page and the server would validate this when the applet connects. > Good point. > Well Kerberos isn't going to get across the firewall either so this > isn't an issue. We're only talking within scope of an intranet > and people don't typically have strict firewalls for purely > internal traffic. If this is true, great, but I was not sure, since I have heard talk of admins possibly wanting to be able to log in remotely (though if it is through a vpn or something, may not be an issue either). Just wanted to make sure security was properly accounted for. > I agree that we want a plugin approach if we want to have highly > interactive graphics. The things that discourage me from Java are > the pain wrt deployment on the client browser end in comparison to > flash. Second if you look at the major internet sites doing live > graphing (eg Yahoo and Google finance) they're all using Flash. > Sure, makes sense. And just to be clear, I was not suggesting we draw graphs in the applet, just use it as the transport mechanism for the data. The graph could continue to be drawn in svg or flash in that scenario. > The limited open source flash support is a concern, but if we have access > to the source of the applet we use, then we can ensure it is written to > work within the scope of the open source flash support. > Agreed. > I'd just have the server render graphs as PNG and a slow (10-15 second) > refresh in javascript as a fallback for non-applet users. I have heard from some folks that the graphs would be the most important thing to have close to real-time, possibly the only thing. We are already rendering them with svg, which gives us the ability to hook into the svg object model and manipulate with javascript (including drilling down into the data), though we are not currently taking advantage of this. Flash, of course, would give us the same thing, just in a different way. -j From jguiditt at redhat.com Thu Jul 3 21:14:05 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Thu, 03 Jul 2008 17:14:05 -0400 Subject: [Ovirt-devel] [R&D] Breaking the Browser In-Reply-To: References: <368865082.756671215038318114.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <722066189.756751215038368416.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <1215118170.3094.9.camel@localhost.localdomain> Message-ID: <1215119645.3094.35.camel@localhost.localdomain> On Thu, 2008-07-03 at 13:59 -0700, Jeff Schroeder wrote: > Q: How do you get realtime graphs with a webapp? > A: SVG + AJAX > > A good example of how to do this would be the m0n0wall firewall. > Here is a screenshot of their interface graphs: > http://m0n0.ch/wall/images/screens/status_graph.png > > The svg graphs are drawn by the javascript. It gets the data from a > xmlhttprequest > feed directly from the server. It is really sexy technology and most browsers > support it. Is asking IE users to install the Adobe SVG plugin or user Firefox > too much? > > Take a look at how easy this is to do: > http://www.browserland.org/scripts/svgclock/ > > If you compress that svg down, the whole thing is 4k. I don't even think flash > could do something that smooth and clean looking in 4k. Were you aware of this? > Agreed, and we are using svg for the graphs right now, though they do need some optimization and better javascript hooks. I am not a proponent of us using flash for this, but others disagree. Also, since adobe is discontinuing support for their svg viewer, there is another one I have read good things about called renesis: http://www.examotion.com/Downloads.product_player_download.0.html From jeffschroed at gmail.com Thu Jul 3 21:36:02 2008 From: jeffschroed at gmail.com (Jeff Schroeder) Date: Thu, 3 Jul 2008 14:36:02 -0700 Subject: [Ovirt-devel] [R&D] Breaking the Browser In-Reply-To: <1215119645.3094.35.camel@localhost.localdomain> References: <368865082.756671215038318114.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <722066189.756751215038368416.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <1215118170.3094.9.camel@localhost.localdomain> <1215119645.3094.35.camel@localhost.localdomain> Message-ID: On Thu, Jul 3, 2008 at 2:14 PM, Jason Guiditta wrote: > On Thu, 2008-07-03 at 13:59 -0700, Jeff Schroeder wrote: > >> Q: How do you get realtime graphs with a webapp? >> A: SVG + AJAX >> >> A good example of how to do this would be the m0n0wall firewall. >> Here is a screenshot of their interface graphs: >> http://m0n0.ch/wall/images/screens/status_graph.png >> >> The svg graphs are drawn by the javascript. It gets the data from a >> xmlhttprequest >> feed directly from the server. It is really sexy technology and most browsers >> support it. Is asking IE users to install the Adobe SVG plugin or user Firefox >> too much? >> >> Take a look at how easy this is to do: >> http://www.browserland.org/scripts/svgclock/ >> >> If you compress that svg down, the whole thing is 4k. I don't even think flash >> could do something that smooth and clean looking in 4k. Were you aware of this? >> > Agreed, and we are using svg for the graphs right now, though they do > need some optimization and better javascript hooks. I am not a > proponent of us using flash for this, but others disagree. Also, since > adobe is discontinuing support for their svg viewer, there is another > one I have read good things about called renesis: > http://www.examotion.com/Downloads.product_player_download.0.html Besides internet explorer, a better question would be why not use javascript + svg? If someone that isn't you disagrees, can they give a solid technical reason for this? What graph _absolutely has to be_ realtime? In all of the cases I could come up with not a one wouldn't be serviced by near-realtime graphs. Do you expect users to have ovirt graph screens up on a bank of plasma displays watching node stats in realtime? Even in a big fortune 100 NOC this seems unreasonable and a bad use case. Once oVirt a policy engine (like VMotion) the graphs updating in realtime don't seem near as useful. Can you think of a reason that demands absolute realtime graphs? Here is how I envision oVirt with a 2-3 major releases under it's belt. AMQP bus message: OH NOES, Node3 is about to bust out the oom killer to lay the smack down on vm1 and vm2. Run around, scream, and panic! oVirt Policy Engine: Live migrates vm1 and vm2 from Node3 to Node4 because Node4 is idle. AMQP bus message: Disaster diverted by policy engine. All systems nominal. oVirt Policy Engine: Goes back to saving the world and drinking it's latte Systems Admin: Hey look at that, something bad almost happened but this cool software fixed itsself. /goes back to reading xkcd What do you think? -- Jeff Schroeder Don't drink and derive, alcohol and analysis don't mix. http://www.digitalprognosis.com From mwagner at redhat.com Sat Jul 5 02:33:22 2008 From: mwagner at redhat.com (mark wagner) Date: Fri, 04 Jul 2008 22:33:22 -0400 Subject: [Ovirt-devel] [R&D] Breaking the Browser In-Reply-To: References: <368865082.756671215038318114.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <722066189.756751215038368416.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <1215118170.3094.9.camel@localhost.localdomain> <1215119645.3094.35.camel@localhost.localdomain> Message-ID: <486EDD72.3050006@redhat.com> Jeff Schroeder wrote: > On Thu, Jul 3, 2008 at 2:14 PM, Jason Guiditta wrote: >> On Thu, 2008-07-03 at 13:59 -0700, Jeff Schroeder wrote: >> >>> Q: How do you get realtime graphs with a webapp? >>> A: SVG + AJAX >>> >>> A good example of how to do this would be the m0n0wall firewall. >>> Here is a screenshot of their interface graphs: >>> http://m0n0.ch/wall/images/screens/status_graph.png >>> >>> The svg graphs are drawn by the javascript. It gets the data from a >>> xmlhttprequest >>> feed directly from the server. It is really sexy technology and most browsers >>> support it. Is asking IE users to install the Adobe SVG plugin or user Firefox >>> too much? >>> >>> Take a look at how easy this is to do: >>> http://www.browserland.org/scripts/svgclock/ >>> >>> If you compress that svg down, the whole thing is 4k. I don't even think flash >>> could do something that smooth and clean looking in 4k. Were you aware of this? >>> >> Agreed, and we are using svg for the graphs right now, though they do >> need some optimization and better javascript hooks. I am not a >> proponent of us using flash for this, but others disagree. Also, since >> adobe is discontinuing support for their svg viewer, there is another >> one I have read good things about called renesis: >> http://www.examotion.com/Downloads.product_player_download.0.html > > Besides internet explorer, a better question would be why not use > javascript + svg? > If someone that isn't you disagrees, can they give a solid technical > reason for this? > > What graph _absolutely has to be_ realtime? In all of the cases I > could come up with > not a one wouldn't be serviced by near-realtime graphs. Do you expect > users to have > ovirt graph screens up on a bank of plasma displays watching node > stats in realtime? So if your job is to monitor the 25 hosts in your pool and take immediate and effective action to mitigate any performance or catastrophic issues in said pool within one minute and 26 secs (3 nines, assuming this is the only issue that day) of the event, how are you going to monitor your pool ? If we don't provide the ability to notify immediately when a host goes down, you are rapidly eating into time specified to resolve a problem. The thing that people seem to be missing or ignoring is that this a Systems Management Tool. Often times, there will be Service Level Agreements associated with with running a NOC. Not making data available in real time is going to exclude ovirt from sites. We need to look at making the nav bar have near realtime capabilities. I need to know if a system is getting close to capacity (change the color of the icon?) or is offline. If I have a graph of CPU utilization in my browser for the last two hours of "my pool" it should automatically get updated as data becomes available or my finger will get tired from hitting refresh. Never underestimate the strain on a server caused by people hitting refresh to see if the data has changed, if I know it will auto update, I cease that behavior. (How often to update the data from the host and guests is also an important part of this equation) > Even in a big fortune 100 NOC this seems unreasonable and a bad use case. So are you saying we should focus our attention on providing real time alerts / event notification? How do the admins get notified as quickly as possible? Do they sit in front of a terminal and hit refresh on there browser? Set their mail clients to fetch every 10 secs ? This is clearly a case where time is money, if you are in a big NOC and miss your SLA it could cost big bucks, not to mention a job or two. > > Once oVirt a policy engine (like VMotion) the graphs updating in > realtime don't seem > near as useful. This does not make the case not to have the ability *now*. Just that it may not be needed later. Can you think of a reason that demands absolute realtime graphs? I agree that no graph "has to be realtime". We could do things via a "top" like tool or other means. However, graphs tend to be easier to read, although "top" updates more frequently.... The argument you make is actually a not meaningful here because there is really nothing that "demands ovirt". Its a tool to (hopefully) make management of a virtualized easier, but its not an absolute to deploying virtualization. You could do the same management with existing tools, just be a lot harder and costly. In my mind, realtime graphs in some limited form could be a useful feature. For instance, I don't think that we need a realtime graph to show the monthly data (sigh, but now I know that some customers will want it, double sigh ) > > Here is how I envision oVirt with a 2-3 major releases under it's belt. You realize that two or three major releases are at least several years away. Do we have the functionality required now to ensure that there is will be sufficient demand for ovirt that far out ? The internet is littered with many projects that never deliver the functionality needed to survive until their third major release is ready... > > AMQP bus message: OH NOES, Node3 is about to bust out the oom killer to lay the > smack down on vm1 and vm2. Run > around, scream, and panic! > oVirt Policy Engine: Live migrates vm1 and vm2 from Node3 to Node4 > because Node4 is idle. > AMQP bus message: Disaster diverted by policy engine. All systems nominal. > oVirt Policy Engine: Goes back to saving the world and drinking it's latte > Systems Admin: Hey look at that, something bad almost happened but this > cool software fixed itsself. /goes > back to reading xkcd > > What do you think? This seems to require real time data to do its job effectively. Doing it after the fact will interrupt your comics... We do need to be concerned about overtaxing the servers with polling from many clients. The correct solution would most likely involve a more distributed architecture that distributes the load and can sustain growth to meet the needs of the customers. A push model for certain types of data is also essential. Keep in mind that we are trying to solve problems that have been resolved many times over the years. The basic architecture of network management apps is that a server polls for stats and events / alerts get pushed to the server. With a distributed system, the servers need to push the events amongst themselves. Stats can be stored centrally or in a distributed fashion, the important aspect is that the data is available to all the servers . -mark From pmyers at redhat.com Sat Jul 5 03:26:37 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Fri, 04 Jul 2008 23:26:37 -0400 Subject: [Ovirt-devel] [R&D] Breaking the Browser In-Reply-To: <486EDD72.3050006@redhat.com> References: <368865082.756671215038318114.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <722066189.756751215038368416.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <1215118170.3094.9.camel@localhost.localdomain> <1215119645.3094.35.camel@localhost.localdomain> <486EDD72.3050006@redhat.com> Message-ID: <486EE9ED.7010707@redhat.com> mark wagner wrote: >> What graph _absolutely has to be_ realtime? In all of the cases I >> could come up with >> not a one wouldn't be serviced by near-realtime graphs. Do you expect >> users to have >> ovirt graph screens up on a bank of plasma displays watching node >> stats in realtime? > > So if your job is to monitor the 25 hosts in your pool and take > immediate and > effective action to mitigate any performance or catastrophic issues in said > pool within one minute and 26 secs (3 nines, assuming this is the only > issue > that day) of the event, how are you going to monitor your pool ? > > If we don't provide the ability to notify immediately when a host goes > down, > you are rapidly eating into time specified to resolve a problem. > If your job is to monitor hosts in realtime, there are already really good monitoring solutions for this. I don't think we are attempting to replace NOC software with oVirt. We're trying to handle things like managing virtual systems, provisioning and simplifying the usage of the datacenter. If you need to look at performance trends to determine whether or not to rebalance your vms across physical hosts, oVirt will be able to do that for you. If you're looking to divvy up hardware among different groups in your organization, we'll do that too. If you're looking to monitor hosts and get immediate notification of when they go down, then you probably already have a system implemented in your NOC that does this. (I can think of a few big names offhand) Maybe eventually we can have oVirt try to get into this space, but I think doing that right now might be a bit premature. We need to get really good at the other things I mention above. (i.e. our core capabilities) Perry From dlutter at redhat.com Sat Jul 5 06:44:33 2008 From: dlutter at redhat.com (David Lutterkort) Date: Sat, 05 Jul 2008 06:44:33 +0000 Subject: [Ovirt-devel] [R&D] Breaking the Browser In-Reply-To: <486EDD72.3050006@redhat.com> References: <368865082.756671215038318114.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <722066189.756751215038368416.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <1215118170.3094.9.camel@localhost.localdomain> <1215119645.3094.35.camel@localhost.localdomain> <486EDD72.3050006@redhat.com> Message-ID: <1215240273.3368.130.camel@localhost.localdomain> On Fri, 2008-07-04 at 22:33 -0400, mark wagner wrote: > > What graph _absolutely has to be_ realtime? In all of the cases I > > could come up with > > not a one wouldn't be serviced by near-realtime graphs. Do you expect > > users to have > > ovirt graph screens up on a bank of plasma displays watching node > > stats in realtime? > > So if your job is to monitor the 25 hosts in your pool and take immediate and > effective action to mitigate any performance or catastrophic issues in said > pool within one minute and 26 secs (3 nines, assuming this is the only issue > that day) of the event, how are you going to monitor your pool ? > > If we don't provide the ability to notify immediately when a host goes down, > you are rapidly eating into time specified to resolve a problem. This is completely unrealistic - notification of any sort of important event would not come through a web browser, they would be sent from a monitoring system to a pager or similar. Graphs in the browser might help understand what is happening and why load is the way it is, but it would never be used as the primary notification. David From dpierce at redhat.com Sat Jul 5 13:59:57 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Sat, 5 Jul 2008 09:59:57 -0400 Subject: [Ovirt-devel] [PATCH] ovirt-identify-node now submits all extended CPU details. Message-ID: <1215266397-13191-1-git-send-email-dpierce@redhat.com> From: Darryl Pierce Signed-off-by: Darryl L. Pierce --- ovirt-managed-node/src/ovirt-identify-node.c | 420 +++++++++++++++----- ovirt-managed-node/src/ovirt-identify-node.h | 56 +++ wui/src/app/models/cpu.rb | 24 ++ wui/src/app/models/host.rb | 21 +- wui/src/db/migrate/002_create_hosts.rb | 2 - wui/src/db/migrate/010_create_cpus.rb | 26 ++ wui/src/dutils/active_record_env.rb | 5 +- wui/src/host-browser/host-browser.rb | 103 +++++- wui/src/host-browser/test-host-browser-awake.rb | 94 +++++ wui/src/host-browser/test-host-browser-awaken.rb | 94 ----- wui/src/host-browser/test-host-browser-identify.rb | 345 ++++++++++------ wui/src/test/fixtures/cpus.yml | 21 + wui/src/test/fixtures/hosts.yml | 26 +- wui/src/test/unit/cpu_test.rb | 8 + 14 files changed, 875 insertions(+), 370 deletions(-) create mode 100644 ovirt-managed-node/src/ovirt-identify-node.h create mode 100644 wui/src/app/models/cpu.rb create mode 100644 wui/src/db/migrate/010_create_cpus.rb create mode 100755 wui/src/host-browser/test-host-browser-awake.rb delete mode 100755 wui/src/host-browser/test-host-browser-awaken.rb create mode 100644 wui/src/test/fixtures/cpus.yml create mode 100644 wui/src/test/unit/cpu_test.rb diff --git a/ovirt-managed-node/src/ovirt-identify-node.c b/ovirt-managed-node/src/ovirt-identify-node.c index 819f700..f114d81 100644 --- a/ovirt-managed-node/src/ovirt-identify-node.c +++ b/ovirt-managed-node/src/ovirt-identify-node.c @@ -31,31 +31,7 @@ #include #include -int config(int argc,char** argv); -void usage(void); - -int start_conversation(void); -int send_details(void); -int end_conversation(void); - -int send_text(char* text); -int get_text(const char *const expected); -int create_connection(void); - -int debug = 1; -int verbose = 1; -int testing = 0; - -#define BUFFER_LENGTH 128 - -char arch[BUFFER_LENGTH]; -char uuid[VIR_UUID_BUFLEN]; -char memsize[BUFFER_LENGTH]; -char numcpus[BUFFER_LENGTH]; -char cpuspeed[BUFFER_LENGTH]; -char *hostname; -int hostport = -1; -int socketfd; +#include "ovirt-identify-node.h" int main(int argc,char** argv) { @@ -63,9 +39,11 @@ int main(int argc,char** argv) virConnectPtr connection; virNodeInfo info; + fprintf(stdout,"Sending managed node details to server.\n"); + if(!config(argc,argv)) { - fprintf(stdout,"Connecting to libvirt.\n"); + if(verbose) fprintf(stdout,"Connecting to libvirt.\n"); connection = virConnectOpenReadOnly(testing ? "test:///default" : NULL); @@ -73,42 +51,68 @@ int main(int argc,char** argv) if(connection) { - if(debug) fprintf(stdout,"Getting hostname: %s\n", uuid); + if(verbose) fprintf(stdout,"Getting hostname: %s\n", uuid); if(!strlen(uuid)) gethostname(uuid,sizeof uuid); - if(debug) fprintf(stdout,"Retrieving node information.\n"); + if(verbose) fprintf(stdout,"Retrieving node information.\n"); if(!virNodeGetInfo(connection,&info)) { snprintf(arch, BUFFER_LENGTH, "%s", info.model); snprintf(memsize, BUFFER_LENGTH, "%ld", info.memory); - snprintf(numcpus, BUFFER_LENGTH, "%d", info.cpus); - snprintf(cpuspeed, BUFFER_LENGTH, "%d", info.mhz); - if(debug) + cpu_info = NULL; + + if(!get_cpu_info()) { - fprintf(stdout,"Node Info:\n"); - fprintf(stdout," UUID: %s\n", uuid); - fprintf(stdout," Arch: %s\n", arch); - fprintf(stdout," Memory: %s\n", memsize); - fprintf(stdout," # CPUs: %s\n", numcpus); - fprintf(stdout,"CPU Speed: %s\n", cpuspeed); + if(verbose) fprintf(stdout, "Getting CPU info.\n"); + + if(debug) + { + fprintf(stdout,"Node Info:\n"); + fprintf(stdout," UUID: %s\n", uuid); + fprintf(stdout," Arch: %s\n", arch); + fprintf(stdout," Memory: %s\n", memsize); + + t_cpu_info* current = cpu_info; + while(current != NULL) + { + fprintf(stdout,"\n"); + fprintf(stdout," CPU Number: %s\n", current->cpu_num); + fprintf(stdout," Core Number: %s\n", current->core_num); + fprintf(stdout,"Number of Cores: %s\n", current->number_of_cores); + fprintf(stdout," Vendor: %s\n", current->vendor); + fprintf(stdout," Model: %s\n", current->model); + fprintf(stdout," Family: %s\n", current->family); + fprintf(stdout," CPUID Level: %s\n", current->cpuid_level); + fprintf(stdout," CPU Speed: %s\n", current->speed); + fprintf(stdout," Cache Size: %s\n", current->cache); + fprintf(stdout," CPU Flags: %s\n", current->flags); + + current = current->next; + } + } + + if(verbose) fprintf(stdout, "Retrieved node information.\n"); + + if(!start_conversation() && !send_details() && !end_conversation()) + { + fprintf(stdout,"Finished!\n"); + result = 0; + } } - - if(debug) fprintf(stdout, "Retrieved node information.\n"); - - if(!start_conversation() && !send_details() && !end_conversation()) + else { - result = 0; + if(verbose) fprintf(stderr,"Failed to get CPU info.\n"); } } else { - if(debug) fprintf(stderr,"Failed to get node info.\n"); + if(verbose) fprintf(stderr,"Failed to get node info.\n"); } } else { - if(debug) fprintf(stderr,"Could not connect to libvirt.\n"); + if(verbose) fprintf(stderr,"Could not connect to libvirt.\n"); } } else @@ -181,35 +185,35 @@ int start_conversation(void) { if(debug || verbose) fprintf(stdout,"Connected.\n"); - if (!get_text("HELLO?\n")) + if (!get_text("HELLO?")) { - if(debug) fprintf(stdout,"Checking for handshake.\n"); + if(verbose) fprintf(stdout,"Checking for handshake.\n"); - if(!send_text("HELLO!\n")) + if(!send_text("HELLO!")) { - if(debug) fprintf(stdout,"Handshake received. Starting conversation.\n"); + if(verbose) fprintf(stdout,"Handshake received. Starting conversation.\n"); - if(!get_text("MODE?\n")) + if(!get_text("MODE?")) { - if(debug) fprintf(stdout,"Shifting to IDENTIFY mode.\n"); + if(verbose) fprintf(stdout,"Shifting to IDENTIFY mode.\n"); - if(!send_text("IDENTIFY\n")) result = 0; + if(!send_text("IDENTIFY")) result = 0; } else { - if(debug) fprintf(stderr,"Was not asked for a mode.\n"); + if(verbose) fprintf(stderr,"Was not asked for a mode.\n"); } } } else { - if(debug) fprintf(stderr,"Did not receive a proper handshake.\n"); + if(verbose) fprintf(stderr,"Did not receive a proper handshake.\n"); } } else { - if(debug) fprintf(stderr,"Did not get a connection.\n"); + if(verbose) fprintf(stderr,"Did not get a connection.\n"); } if(debug) fprintf(stdout,"start_conversation: result=%d\n", result); @@ -223,19 +227,15 @@ int send_value(char* label,char* value) int result = 1; char expected[BUFFER_LENGTH]; - snprintf(buffer,BUFFER_LENGTH,"%s=%s\n", label, value); + snprintf(buffer,BUFFER_LENGTH,"%s=%s", label, value); if(!send_text(buffer)) { - snprintf(expected, BUFFER_LENGTH, "ACK %s\n", label); + snprintf(expected, BUFFER_LENGTH, "ACK %s", label); - if(debug) fprintf(stdout,"Expecting \"%s\"\n", expected); - - if (!get_text(expected)) - { - result = 0; - } + if(verbose) fprintf(stdout,"Expecting \"%s\"\n", expected); + result = get_text(expected); } return result; @@ -245,40 +245,238 @@ int send_details(void) { int result = 1; - fprintf(stdout,"Sending node details.\n"); + if(verbose) fprintf(stdout,"Sending node details.\n"); - if (!get_text("INFO?\n")) + if (!get_text("INFO?")) { if((!send_value("ARCH", arch)) && (!send_value("UUID", uuid)) && - (!send_value("NUMCPUS", numcpus)) && - (!send_value("CPUSPEED", cpuspeed)) && - (!send_value("MEMSIZE", memsize))) + (!send_value("MEMSIZE", memsize)) && + (!send_cpu_details())) { - if(!send_text("ENDINFO\n")) result = 0; + if(!send_text("ENDINFO")) result = 0; } } else { - if(debug) fprintf(stdout,"Was not interrogated for hardware info.\n"); + if(verbose) fprintf(stdout,"Was not interrogated for hardware info.\n"); } return result; } +int send_cpu_details(void) +{ + int result = 1; + t_cpu_info* current = cpu_info; + + while(current != NULL) + { + send_text("CPU"); + + if(!(get_text("CPUINFO?")) && + (!send_value("CPUNUM",current->cpu_num)) && + (!send_value("CORENUM",current->core_num)) && + (!send_value("NUMCORES",current->number_of_cores)) && + (!send_value("VENDOR",current->vendor)) && + (!send_value("MODEL",current->model)) && + (!send_value("FAMILY",current->family)) && + (!send_value("CPUIDLVL",current->cpuid_level)) && + (!send_value("SPEED",current->speed)) && + (!send_value("CACHE", current->cache)) && + (!send_value("FLAGS", current->flags))) + { + send_text("ENDCPU"); + result = get_text("ACK CPU"); + } + + current = current->next; + } + + + return result; +} + int end_conversation(void) { int result = 0; - fprintf(stdout,"Ending conversation.\n"); + if(debug || verbose) fprintf(stdout,"Ending conversation.\n"); - send_text("ENDINFO\n"); + send_text("ENDINFO"); close(socketfd); return result; } +void get_label_and_value(char* text, + char* label, size_t label_length, + char* value, size_t value_length) +{ + int offset = 0; + int which = 0; /* 0 = label, 1 = value */ + char* current = text; + + /* iterate through the text supplied and find where the + * label ends with a colon, then copy that into the supplied + * label buffer and trim any trailing spaces + */ + + while(current != NULL && *current != '\0') + { + /* if we're on the separator, then switch modes and reset + * the offset indicator, otherwise just process the character + */ + if(which == 0 && *current == ':') + { + which = 1; + offset = 0; + } + else + { + char* buffer = (which == 0 ? label : value); + int length = (which == 0 ? label_length : value_length); + + /* only copy if we're past the first character and it's not + * a space + */ + if((offset > 0 || (*current != 9 && *current != ' ')) && offset < (length - 1)) + { + buffer[offset++] = *current; + buffer[offset] = 0; + } + } + + current++; + } + + /* now trim all trailing spaces from the values */ + while(label[strlen(label) - 1 ] == 9) + label[strlen(label) - 1] = 0; + while(value[strlen(value) - 1] == 9) + value[strlen(value) - 1] = 0; +} + +int get_cpu_info(void) +{ + int result = 1; + FILE* inputfd; + t_cpu_info* current = NULL; + + if(( inputfd = fopen("/proc/cpuinfo","rb")) != NULL) + { + if(verbose) fprintf(stdout,"Parsing CPU information\n"); + do + { + char buffer[255]; + char label[BUFFER_LENGTH]; + char value[BUFFER_LENGTH]; + + fgets(buffer, 255, inputfd); + if(strlen(buffer) > 0) buffer[strlen(buffer) - 1] = '\0'; + + get_label_and_value(buffer, + label,BUFFER_LENGTH, + value,BUFFER_LENGTH); + + if(debug) + fprintf(stdout,"label=\"%s\", value=\"%s\"\n", label, value); + + if(strlen(label)) + { + if(!strcmp(label,"processor")) + { + if(debug || verbose) + fprintf(stdout,"Starting new CPU\n"); + + t_cpu_info* last = current; + + current = create_cpu_info(); + if(last != NULL) + { + last->next = current; + } + else + { + cpu_info = current; + } + + COPY_VALUE_TO_BUFFER(value,current->cpu_num,BUFFER_LENGTH); + } + else + if(!strcmp(label,"core id")) + { + COPY_VALUE_TO_BUFFER(value,current->core_num,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cpu cores")) + { + COPY_VALUE_TO_BUFFER(value,current->number_of_cores,BUFFER_LENGTH); + } + else + if(!strcmp(label,"vendor_id")) + { + COPY_VALUE_TO_BUFFER(value,current->vendor,BUFFER_LENGTH); + } + else + if(!strcmp(label,"model")) + { + COPY_VALUE_TO_BUFFER(value,current->model,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cpu family")) + { + COPY_VALUE_TO_BUFFER(value,current->family,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cpuid level")) + { + COPY_VALUE_TO_BUFFER(value,current->cpuid_level,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cpu MHz")) + { + COPY_VALUE_TO_BUFFER(value,current->speed,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cache size")) + { + COPY_VALUE_TO_BUFFER(value,current->cache,BUFFER_LENGTH); + } + else + if(!strcmp(label,"flags")) + { + COPY_VALUE_TO_BUFFER(value,current->flags,BUFFER_LENGTH); + } + } + + } while(!feof(inputfd)); + + fclose(inputfd); + + result = 0; + } + else + { + if(verbose) fprintf(stderr,"Unable to open /proc/cpuinfo\n"); + } + + return result; +} + +t_cpu_info* create_cpu_info(void) +{ + t_cpu_info* result = calloc(1,sizeof(t_cpu_info)); + bzero(result,sizeof(t_cpu_info)); + + strcpy(result->core_num,"0"); + strcpy(result->number_of_cores,"1"); + + + return result; +} + ssize_t safewrite(int fd, const void *buf, size_t count) { size_t nwritten = 0; @@ -303,9 +501,10 @@ int send_text(char* text) int result = 1; int sent; - if(debug || verbose) fprintf(stdout,"\"%s\" -> %s:%d\n", text, hostname, hostport); + if(verbose) fprintf(stdout,"Sending: \"%s\"\n", text); sent = safewrite(socketfd, text, strlen(text)); + sent += safewrite(socketfd, "\n", 1); if(sent >= 0) { @@ -317,35 +516,46 @@ int send_text(char* text) return result; } -int saferead(int fd, void *buf, size_t count) +int saferead(int fd, char *buf, size_t count) { ssize_t bytes,offset; int len_left; + int done = 0; if(debug) fprintf(stdout,"Begin saferead(%d, %p, %ld)\n", fd, buf, count); offset = 0; len_left = count; - while(len_left > 0) { - bytes = read(fd, buf+offset, len_left); - fprintf(stderr,"After read, bytes is %ld\n",bytes); - if (bytes < 0) { - if (errno == EINTR) { - continue; - } - else { - offset = -1; - break; - } - } - else if (bytes == 0) { - // reached EOF; break out of here - break; - } - - offset += bytes; - len_left -= bytes; + + while(!done) + { + if(debug) fprintf(stdout,"Before read(%ld,%p,%ld)\n",fd,buf+offset,len_left); + + bytes = read(fd, buf+offset, len_left); + + if(debug) fprintf(stdout,"After read: bytes=%ld\n", bytes); + + if(bytes == 0) + { + done = 1; + } + else if(bytes > 0) + { + offset += bytes; + len_left -= bytes; + done = 1; + } + else if(errno == EINTR) + { + continue; + } + else + { + done = 1; + } + + if(debug) fprintf(stdout,"End of decision loop: offset=%ld, len_left=%dl, done=%d\n",offset, len_left, done); } return offset; @@ -353,22 +563,22 @@ int saferead(int fd, void *buf, size_t count) int get_text(const char *const expected) { + int result = 1; int received; char buffer[BUFFER_LENGTH]; + bzero(buffer,BUFFER_LENGTH); - if(debug) fprintf(stdout, "Looking to receive %s\n", expected); + if(verbose) fprintf(stdout, "Looking to receive %s\n", expected); - received = saferead(socketfd, buffer, strlen(expected)); + received = saferead(socketfd, buffer, BUFFER_LENGTH); buffer[received - 1] = 0; - if(debug) fprintf(stdout,"Received \"%s\": size=%d (trimmed ending carriage return)\n", buffer, received); + if(verbose) fprintf(stdout,"Received \"%s\": size=%d (trimmed ending carriage return)\n", buffer, received); - if (strncmp(expected, buffer, strlen(expected)) != 0) { - return 0; - } + result = strcmp(expected,buffer); - return 1; + return result; } int create_connection(void) @@ -379,7 +589,7 @@ int create_connection(void) char port[6]; struct addrinfo* rptr; - if(debug) fprintf(stdout,"Creating the socket connection.\n"); + if(verbose) fprintf(stdout,"Creating the socket connection.\n"); memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; @@ -387,13 +597,13 @@ int create_connection(void) hints.ai_flags = 0; hints.ai_protocol = 0; - if(debug) fprintf(stdout,"Searching for host candidates.\n"); + if(verbose) fprintf(stdout,"Searching for host candidates.\n"); snprintf(port, 6, "%d", hostport); if(!getaddrinfo(hostname, port, &hints, &results)) { - if(debug) fprintf(stdout,"Got address information. Searching for a proper entry.\n"); + if(verbose) fprintf(stdout,"Got address information. Searching for a proper entry.\n"); for(rptr = results; rptr != NULL; rptr = rptr->ai_next) { @@ -416,13 +626,13 @@ int create_connection(void) } // invalid connection, so close it - if(debug) fprintf(stdout, "Invalid connection.\n"); + if(verbose) fprintf(stdout, "Invalid connection.\n"); close(socketfd); } if(rptr == NULL) { - if(debug) fprintf(stdout,"Unable to connect to server %s:%d\n", hostname, hostport); + if(verbose) fprintf(stdout,"Unable to connect to server %s:%d\n", hostname, hostport); } else { @@ -434,7 +644,7 @@ int create_connection(void) } else { - if(debug) fprintf(stderr,"No hosts found. Exiting...\n"); + if(verbose) fprintf(stderr,"No hosts found. Exiting...\n"); } if(debug) fprintf(stdout, "create_connection: result=%d\n", result); diff --git a/ovirt-managed-node/src/ovirt-identify-node.h b/ovirt-managed-node/src/ovirt-identify-node.h new file mode 100644 index 0000000..1cb1526 --- /dev/null +++ b/ovirt-managed-node/src/ovirt-identify-node.h @@ -0,0 +1,56 @@ +#ifndef __OVIRT_IDENTIFY_NODE_H +#define __OVIRT_IDENTIFY_NODE_H + +#define BUFFER_LENGTH 128 +#define CPU_FLAGS_BUFFER_LENGTH 256 + +typedef struct _cpu_info { + char cpu_num[BUFFER_LENGTH]; + char core_num[BUFFER_LENGTH]; + char number_of_cores[BUFFER_LENGTH]; + char vendor[BUFFER_LENGTH]; + char model[BUFFER_LENGTH]; + char family[BUFFER_LENGTH]; + char cpuid_level[BUFFER_LENGTH]; + char speed[BUFFER_LENGTH]; + char cache[BUFFER_LENGTH]; + char flags[CPU_FLAGS_BUFFER_LENGTH]; + struct _cpu_info* next; +} t_cpu_info; + +#define COPY_VALUE_TO_BUFFER(value,buffer,length) \ + snprintf(buffer,length,"%s",value) + +int config(int argc,char** argv); +void usage(void); + +int start_conversation(void); +int send_details(void); +int send_cpu_details(void); +int end_conversation(void); + +void get_label_and_value(char* text, + char* label,size_t label_length, + char* value,size_t value_length); +t_cpu_info* create_cpu_info(void); +int get_cpu_info(void); + +int send_text(char* text); +int get_text(const char *const expected); +int create_connection(void); + +int debug = 0; +int verbose = 0; +int testing = 0; + +char arch[BUFFER_LENGTH]; +char uuid[VIR_UUID_BUFLEN]; +char memsize[BUFFER_LENGTH]; +char numcpus[BUFFER_LENGTH]; +char cpuspeed[BUFFER_LENGTH]; +char *hostname; +int hostport = -1; +int socketfd; +t_cpu_info* cpu_info; + +#endif diff --git a/wui/src/app/models/cpu.rb b/wui/src/app/models/cpu.rb new file mode 100644 index 0000000..1a7d3cf --- /dev/null +++ b/wui/src/app/models/cpu.rb @@ -0,0 +1,24 @@ +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Darryl L. Pierce +# +# 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. + +# +Cpu+ represents the details for a single CPU on a managed node. +# +class Cpu < ActiveRecord::Base + belongs_to :host +end diff --git a/wui/src/app/models/host.rb b/wui/src/app/models/host.rb index 6917226..3413370 100644 --- a/wui/src/app/models/host.rb +++ b/wui/src/app/models/host.rb @@ -1,4 +1,4 @@ -# +# # Copyright (C) 2008 Red Hat, Inc. # Written by Scott Seago # @@ -21,8 +21,11 @@ require 'util/ovirt' class Host < ActiveRecord::Base belongs_to :hardware_pool + + has_many :cpus has_many :nics, :dependent => :destroy has_many :vms, :dependent => :nullify do + def consuming_resources find(:all, :conditions=>{:state=>Vm::RUNNING_STATES}) end @@ -32,7 +35,7 @@ class Host < ActiveRecord::Base find(:all, :conditions=>{:state=>Task::STATE_QUEUED}) end def pending_clear_tasks - find(:all, :conditions=>{:state=>Task::WORKING_STATES, + find(:all, :conditions=>{:state=>Task::WORKING_STATES, :action=>HostTask::ACTION_CLEAR_VMS}) end end @@ -42,12 +45,18 @@ class Host < ActiveRecord::Base STATE_UNAVAILABLE = "unavailable" STATE_AVAILABLE = "available" STATES = [STATE_UNAVAILABLE, STATE_AVAILABLE] + + KVM_HYPERVISOR_TYPE = "KVM" + HYPERVISOR_TYPES = [KVM_HYPERVISOR_TYPE] + def memory_in_mb kb_to_mb(memory) end + def memory_in_mb=(mem) self[:memory]=(mb_to_kb(mem)) end + def status_str "#{state} (#{disabled? ? 'disabled':'enabled'})" end @@ -61,4 +70,12 @@ class Host < ActiveRecord::Base not(disabled? and vms.consuming_resources.empty?) and tasks.pending_clear_tasks.empty? end + + def num_cpus + return cpu_details.size + end + + def cpu_speed + "FIX ME!" + end end diff --git a/wui/src/db/migrate/002_create_hosts.rb b/wui/src/db/migrate/002_create_hosts.rb index cef7996..442e674 100644 --- a/wui/src/db/migrate/002_create_hosts.rb +++ b/wui/src/db/migrate/002_create_hosts.rb @@ -23,8 +23,6 @@ class CreateHosts < ActiveRecord::Migration t.string :uuid t.string :hypervisor_type t.string :hostname - t.integer :num_cpus - t.integer :cpu_speed t.string :arch t.integer :memory t.integer :is_disabled diff --git a/wui/src/db/migrate/010_create_cpus.rb b/wui/src/db/migrate/010_create_cpus.rb new file mode 100644 index 0000000..381bf19 --- /dev/null +++ b/wui/src/db/migrate/010_create_cpus.rb @@ -0,0 +1,26 @@ +class CreateCpus < ActiveRecord::Migration + def self.up + create_table :cpus do |t| + t.integer :host_id + t.integer :cpu_number + t.integer :core_number + t.integer :number_of_cores + t.string :vendor, :limit => 128 + t.integer :model + t.integer :family + t.integer :cpuid_level + t.float :speed + t.string :cache + t.string :flags + + t.timestamps + end + + execute "alter table cpus add constraint fk_host_cpus + foreign key (host_id) references hosts(id)" + end + + def self.down + drop_table :cpus + end +end diff --git a/wui/src/dutils/active_record_env.rb b/wui/src/dutils/active_record_env.rb index b0aef04..72feb89 100644 --- a/wui/src/dutils/active_record_env.rb +++ b/wui/src/dutils/active_record_env.rb @@ -1,5 +1,5 @@ #!/usr/bin/ruby -# +# # Copyright (C) 2008 Red Hat, Inc. # Written by Scott Seago # @@ -23,7 +23,7 @@ $: << File.join(File.dirname(__FILE__), "../vendor/plugins/betternestedset/lib") require 'rubygems' -gem 'activeldap' +gem 'activeldap' require 'active_ldap' require 'active_support' @@ -58,6 +58,7 @@ require 'models/quota.rb' require 'models/hardware_pool.rb' require 'models/host.rb' +require 'models/cpu.rb' require 'models/nic.rb' require 'models/vm_resource_pool.rb' diff --git a/wui/src/host-browser/host-browser.rb b/wui/src/host-browser/host-browser.rb index 691e4ed..e66493d 100755 --- a/wui/src/host-browser/host-browser.rb +++ b/wui/src/host-browser/host-browser.rb @@ -19,6 +19,7 @@ # also available at http://www.gnu.org/copyleft/gpl.html. $: << File.join(File.dirname(__FILE__), "../dutils") +$: << File.join(File.dirname(__FILE__), "../") require 'rubygems' require 'libvirt' @@ -73,16 +74,61 @@ class HostBrowser # def get_remote_info puts "#{@log_prefix} Begin remote info collection" unless defined?(TESTING) - result = {} + result = Hash.new result['HOSTNAME'] = @session.peeraddr[2] result['IPADDR'] = @session.peeraddr[3] + @session.write("INFO?\n") loop do info = @session.readline.chomp + puts "Received info='#{info}'" + break if info == "ENDINFO" + # if we got the start of a CPU details marker, then process it + if info == "CPU" + cpu = get_cpu_info + cpu_info = result['CPUINFO'] + + if(cpu_info == nil) + cpu_info = Array.new + result['CPUINFO'] = cpu_info + end + + cpu_info << cpu + + else + + raise Exception.new("ERRINFO! Excepted key=value : #{info}\n") unless info =~ /[\w]+[\s]*=[\w]/ + + key, value = info.split("=") + + puts "#{@log_prefix} ::Received - #{key}:#{value}" unless defined?(TESTING) + result[key] = value + + @session.write("ACK #{key}\n") + end + end + + return result + end + + # Extracts CPU details from the managed node. + # + def get_cpu_info + puts "Begin receiving CPU details" + + result = Hash.new + + @session.write("CPUINFO?\n") + + loop do + info = @session.readline.chomp + + break if info == "ENDCPU" + raise Exception.new("ERRINFO! Excepted key=value : #{info}\n") unless info =~ /[\w]+[\s]*=[\w]/ key, value = info.split("=") @@ -93,6 +139,8 @@ class HostBrowser @session.write("ACK #{key}\n") end + @session.write("ACK CPU\n"); + return result end @@ -100,10 +148,24 @@ class HostBrowser # def write_host_info(host_info) ensure_present(host_info,'HOSTNAME') - ensure_present(host_info,'NUMCPUS') - ensure_present(host_info,'CPUSPEED') ensure_present(host_info,'ARCH') ensure_present(host_info,'MEMSIZE') + ensure_present(host_info,'CPUINFO') + + cpu_info = host_info['CPUINFO'] + + cpu_info.each do |cpu| + ensure_present(cpu,'CPUNUM') + ensure_present(cpu,'CORENUM') + ensure_present(cpu,'NUMCORES') + ensure_present(cpu,'VENDOR') + ensure_present(cpu,'MODEL') + ensure_present(cpu,'FAMILY') + ensure_present(cpu,'CPUIDLVL') + ensure_present(cpu,'SPEED') + ensure_present(cpu,'CACHE') + ensure_present(cpu,'FLAGS') + end puts "Searching for existing host record..." unless defined?(TESTING) host = Host.find(:first, :conditions => ["hostname = ?", host_info['HOSTNAME']]) @@ -112,31 +174,49 @@ class HostBrowser begin puts "Creating a new record for #{host_info['HOSTNAME']}..." unless defined?(TESTING) - Host.new( + host = Host.create( "uuid" => host_info['UUID'], "hostname" => host_info['HOSTNAME'], "hypervisor_type" => host_info['HYPERVISOR_TYPE'], - "num_cpus" => host_info['NUMCPUS'], - "cpu_speed" => host_info['CPUSPEED'], "arch" => host_info['ARCH'], "memory_in_mb" => host_info['MEMSIZE'], "is_disabled" => 0, "hardware_pool" => HardwarePool.get_default_pool, # Let host-status mark it available when it # successfully connects to it via libvirt. - "state" => Host::STATE_UNAVAILABLE).save + "state" => Host::STATE_UNAVAILABLE) + host.save! rescue Exception => error puts "Error while creating record: #{error.message}" unless defined?(TESTING) end else host.uuid = host_info['UUID'] host.hostname = host_info['HOSTNAME'] - host.num_cpus = host_info['NUMCPUS'] - host.cpu_speed = host_info['CPUSPEED'] host.arch = host_info['ARCH'] host.memory_in_mb = host_info['MEMSIZE'] end + # delete an existing CPUs and create new ones based on the data + puts "Deleting any existing CPUs" + Cpu.delete_all(['host_id = ?', host.id]) + + puts "Saving new CPU records" + cpu_info.collect do |cpu| + detail = Cpu.new( + "cpu_number" => cpu['CPUNUM'], + "core_number" => cpu['CORENUM]'], + "number_of_cores" => cpu['NUMCORES'], + "vendor" => cpu['VENDOR'], + "model" => cpu['MODEL'], + "family" => cpu['FAMILY'], + "cpuid_level" => cpu['CPUIDLVL'], + "speed" => cpu['SPEED'], + "cache" => cpu['CACHE'], + "flags" => cpu['FLAGS']) + + host.cpus << detail + end + return host end @@ -181,8 +261,8 @@ class HostBrowser # Private method to ensure that a required field is present. # - def ensure_present(host_info,key) - raise Exception.new("ERROR! Missing '#{key}'...") if host_info[key] == nil + def ensure_present(info,key) + raise Exception.new("ERROR! Missing '#{key}'...") if info[key] == nil end # Executes an external program to support the keytab function. @@ -226,7 +306,6 @@ def entry_point(server) end unless defined?(TESTING) - # The main entry point. # unless ARGV[0] == "-n" diff --git a/wui/src/host-browser/test-host-browser-awake.rb b/wui/src/host-browser/test-host-browser-awake.rb new file mode 100755 index 0000000..02e9146 --- /dev/null +++ b/wui/src/host-browser/test-host-browser-awake.rb @@ -0,0 +1,94 @@ +#!/usr/bin/ruby -Wall +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Darryl L. Pierce +# +# 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 File.dirname(__FILE__) + '/../test/test_helper' +require 'test/unit' +require 'flexmock/test_unit' + +TESTING=true + +require 'host-browser' + +# +TestHostBrowserAwaken+ +class TestHostBrowserAwaken < Test::Unit::TestCase + + def setup + @session = flexmock('session') + @session.should_receive(:peeraddr).at_least.once.returns { [nil,nil,nil,"192.168.2.255"] } + + @krb5 = flexmock('krb5') + + @browser = HostBrowser.new(@session) + @browser.logfile = './unit-test.log' + @browser.keytab_dir = '/var/temp/' + end + + # Ensures that the server raises an exception when it receives an + # improper handshake response. + # + def test_begin_conversation_with_improper_response_to_greeting + @session.should_receive(:write).with("HELLO?\n").once().returns { |greeting| greeting.length } + @session.should_receive(:readline).once().returns { "SUP?" } + + assert_raise(Exception) { @browser.begin_conversation } + end + + # Ensures the server accepts a proper response from the remote system. + # + def test_begin_conversation + @session.should_receive(:write).with("HELLO?\n").once().returns { |greeting| greeting.length } + @session.should_receive(:readline).once().returns { "HELLO!\n" } + + assert_nothing_raised(Exception) { @browser.begin_conversation } + end + + # Ensures that the server is satisfied if the remote system is + # making a wakeup call. + # + def test_get_mode_with_awaken_request + @session.should_receive(:write).with("MODE?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "AWAKEN\n" } + + result = @browser.get_mode() + + assert_equal "AWAKEN", result, "method did not return the right value" + end + + # Ensures the host browser generates a keytab as expected. + # + def test_create_keytab + @krb5.should_receive(:get_default_realm).once().returns { "ovirt-test-realm" } + servername = `hostname -f`.chomp + @session.should_receive(:write).with("KTAB http://#{servername}/ipa/config/127.0.0.1-libvirt.tab\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ACK\n" } + + assert_nothing_raised(Exception) { @browser.create_keytab('localhost','127.0.0.1', at krb5) } + end + + # Ensures that, if a keytab is present and a key version number available, + # the server ends the conversation by returning the key version number. + # + def test_end_conversation + @session.should_receive(:write).with("BYE\n").once().returns { |request| request.length } + + assert_nothing_raised(Exception) { @browser.end_conversation } + end + +end diff --git a/wui/src/host-browser/test-host-browser-awaken.rb b/wui/src/host-browser/test-host-browser-awaken.rb deleted file mode 100755 index a5ca2e7..0000000 --- a/wui/src/host-browser/test-host-browser-awaken.rb +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/ruby -Wall -# -# Copyright (C) 2008 Red Hat, Inc. -# Written by Darryl L. Pierce -# -# 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 File.dirname(__FILE__) + '/../test/test_helper' -require 'test/unit' -require 'flexmock/test_unit' - -TESTING=true - -require 'host-browser' - -# +TestHostBrowserAwaken+ -class TestHostBrowserAwaken < Test::Unit::TestCase - - def setup - @session = flexmock('session') - @session.should_receive(:peeraddr).at_least.once.returns { [nil,nil,nil,"192.168.2.255"] } - - @krb5 = flexmock('krb5') - - @browser = HostBrowser.new(@session) - @browser.logfile = './unit-test.log' - @browser.keytab_dir = '/var/temp/' - end - - # Ensures that the server raises an exception when it receives an - # improper handshake response. - # - def test_begin_conversation_with_improper_response_to_greeting - @session.should_receive(:write).with("HELLO?\n").once().returns { |greeting| greeting.length } - @session.should_receive(:readline).once().returns { "SUP?" } - - assert_raise(Exception) { @browser.begin_conversation } - end - - # Ensures the server accepts a proper response from the remote system. - # - def test_begin_conversation - @session.should_receive(:write).with("HELLO?\n").once().returns { |greeting| greeting.length } - @session.should_receive(:readline).once().returns { "HELLO!\n" } - - assert_nothing_raised(Exception) { @browser.begin_conversation } - end - - # Ensures that the server is satisfied if the remote system is - # making a wakeup call. - # - def test_get_mode_with_awaken_request - @session.should_receive(:write).with("MODE?\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "AWAKEN\n" } - - result = @browser.get_mode() - - assert_equal "AWAKEN", result, "method did not return the right value" - end - - # Ensures the host browser generates a keytab as expected. - # - def test_create_keytab - @krb5.should_receive(:get_default_realm).once().returns { "ovirt-test-realm" } - servername = `hostname -f`.chomp - @session.should_receive(:write).with("KTAB http://#{servername}/config/127.0.0.1-libvirt.tab\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "ACK\n" } - - assert_nothing_raised(Exception) { @browser.create_keytab('localhost','127.0.0.1', at krb5) } - end - - # Ensures that, if a keytab is present and a key version number available, - # the server ends the conversation by returning the key version number. - # - def test_end_conversation - @session.should_receive(:write).with("BYE\n").once().returns { |request| request.length } - - assert_nothing_raised(Exception) { @browser.end_conversation } - end - -end diff --git a/wui/src/host-browser/test-host-browser-identify.rb b/wui/src/host-browser/test-host-browser-identify.rb index 8f215e9..4197e19 100755 --- a/wui/src/host-browser/test-host-browser-identify.rb +++ b/wui/src/host-browser/test-host-browser-identify.rb @@ -27,136 +27,219 @@ TESTING=true require 'host-browser' class TestHostBrowser < Test::Unit::TestCase - - def setup - @session = flexmock('session') - @session.should_receive(:peeraddr).at_least.once.returns { [nil,nil,nil,"192.168.2.255"] } - - @browser = HostBrowser.new(@session) - @browser.logfile = './unit-test.log' - - # default host info - @host_info = {} - @host_info['UUID'] = 'node1' - @host_info['IPADDR'] = '192.168.2.2' - @host_info['HOSTNAME'] = 'node1.ovirt.redhat.com' - @host_info['NUMCPUS'] = '3' - @host_info['CPUSPEED'] = '3' - @host_info['ARCH'] = 'x86_64' - @host_info['MEMSIZE'] = '16384' - @host_info['DISABLED'] = '0' - end - - # Ensures that the server is satisfied if the remote system is - # making a wakeup call. - # - def test_get_mode_with_awaken_request - @session.should_receive(:write).with("MODE?\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "IDENTIFY\n" } - - result = @browser.get_mode() - - assert_equal "IDENTIFY", result, "method did not return the right value" - end - - # Ensures that, if an info field is missing a key, the server raises - # an exception. - # - def test_get_info_with_missing_key - @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "=value1\n" } - - assert_raise(Exception) { @browser.get_remote_info } - end - - # Ensures that, if an info field is missing a value, the server raises - # an exception. - # - def test_get_info_with_missing_value - @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "key1=\n" } - - assert_raise(Exception) { @browser.get_remote_info } - end - - # Ensures that, if the server gets a poorly formed ending statement, it - # raises an exception. - # - def test_get_info_with_invalid_end - @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "key1=value1\n" } - @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "ENDIFNO\n" } - - assert_raise(Exception) { @browser.get_remote_info } - end - - # Ensures that a well-formed transaction works as expected. - # - def test_get_info - @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "key1=value1\n" } - @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "key2=value2\n" } - @session.should_receive(:write).with("ACK key2\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "ENDINFO\n" } - - info = @browser.get_remote_info - - assert_equal 4,info.keys.size, "Should contain two keys" - assert info.include?("IPADDR") - assert info.include?("HOSTNAME") - assert info.include?("key1") - assert info.include?("key2") - end - - # Ensures that the server is fine when no UUID is present. - # - def test_write_host_info_with_missing_uuid - @host_info['UUID'] = nil - - assert_nothing_raised { @browser.write_host_info(@host_info) } - end - - # Ensures that, if the hostname is missing, the server - # raises an exception. - # - def test_write_host_info_with_missing_hostname - @host_info['HOSTNAME'] = nil - - assert_raise(Exception) { @browser.write_host_info(@host_info) } - end - - # Ensures that, if the number of CPUs is missing, the server raises an exception. - # - def test_write_host_info_with_missing_numcpus - @host_info['NUMCPUS'] = nil - - assert_raise(Exception) { @browser.write_host_info(@host_info) } - end - - # Ensures that, if the CPU speed is missing, the server raises an exception. - # - def test_write_host_info_with_missing_cpuspeed - @host_info['CPUSPEED'] = nil - - assert_raise(Exception) { @browser.write_host_info(@host_info) } - end - - # Ensures that, if the architecture is missing, the server raises an exception. - # - def test_write_host_info_with_missing_arch - @host_info['ARCH'] = nil - - assert_raise(Exception) { @browser.write_host_info(@host_info) } - end - - # Ensures that, if the memory size is missing, the server raises an exception. - # - def test_write_host_info_info_with_missing_memsize - @host_info['MEMSIZE'] = nil - - assert_raise(Exception) { @browser.write_host_info(@host_info) } - end + def setup + @session = flexmock('session') + @session.should_receive(:peeraddr).at_least.once.returns { [nil,nil,nil,"192.168.2.255"] } + + @browser = HostBrowser.new(@session) + @browser.logfile = './unit-test.log' + + # default host info + @host_info = {} + @host_info['UUID'] = 'node1' + @host_info['IPADDR'] = '192.168.2.2' + @host_info['HOSTNAME'] = 'node1.ovirt.redhat.com' + @host_info['ARCH'] = 'x86_64' + @host_info['MEMSIZE'] = '16384' + @host_info['DISABLED'] = '0' + + @host_info['NUMCPUS'] = '2' + + @host_info['CPUINFO'] = Array.new + @host_info['CPUINFO'][0] = {} + @host_info['CPUINFO'][0]['CPUNUM'] = '0' + @host_info['CPUINFO'][0]['CORENUM'] = '0' + @host_info['CPUINFO'][0]['NUMCORES'] = '2' + @host_info['CPUINFO'][0]['VENDOR'] = 'GenuineIntel' + @host_info['CPUINFO'][0]['MODEL'] = '15' + @host_info['CPUINFO'][0]['FAMILY'] = '6' + @host_info['CPUINFO'][0]['CPUIDLVL'] = '10' + @host_info['CPUINFO'][0]['SPEED'] = '3' + @host_info['CPUINFO'][0]['CACHE'] = '4096 kb' + @host_info['CPUINFO'][0]['FLAGS'] = 'fpu vme de pse tsc msr pae \ + mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx \ + fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs \ + bts pni monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr lahf_lm' + + @host_info['CPUINFO'][1] = {} + @host_info['CPUINFO'][1]['CPUNUM'] = '1' + @host_info['CPUINFO'][1]['CORENUM'] = '1' + @host_info['CPUINFO'][1]['NUMCORES'] = '2' + @host_info['CPUINFO'][1]['VENDOR'] = 'GenuineIntel' + @host_info['CPUINFO'][1]['MODEL'] = '15' + @host_info['CPUINFO'][1]['FAMILY'] = '6' + @host_info['CPUINFO'][1]['CPUIDLVL'] = '10' + @host_info['CPUINFO'][1]['SPEED'] = '3' + @host_info['CPUINFO'][1]['CACHE'] = '4096 kb' + @host_info['CPUINFO'][1]['FLAGS'] = 'fpu vme de pse tsc msr pae \ + mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx \ + fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs \ + bts pni monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr lahf_lm' + end + + # Ensures that the server is satisfied if the remote system is + # making a wakeup call. + # + def test_get_mode_with_awaken_request + @session.should_receive(:write).with("MODE?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "IDENTIFY\n" } + + result = @browser.get_mode() + + assert_equal "IDENTIFY", result, "method did not return the right value" + end + + # Ensures that, if an info field is missing a key, the server raises + # an exception. + # + def test_get_info_with_missing_key + @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "=value1\n" } + + assert_raise(Exception) { @browser.get_remote_info } + end + + # Ensures that, if an info field is missing a value, the server raises + # an exception. + # + def test_get_info_with_missing_value + @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key1=\n" } + + assert_raise(Exception) { @browser.get_remote_info } + end + + # Ensures that, if the server gets a poorly formed ending statement, it + # raises an exception. + # + def test_get_info_with_invalid_end + @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key1=value1\n" } + @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDIFNO\n" } + + assert_raise(Exception) { @browser.get_remote_info } + end + + # Ensures that a well-formed transaction works as expected. + # + def test_get_info + @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key1=value1\n" } + @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key2=value2\n" } + @session.should_receive(:write).with("ACK key2\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDINFO\n" } + + info = @browser.get_remote_info + + assert_equal 4,info.keys.size, "Should contain four keys" + assert info.include?("IPADDR") + assert info.include?("HOSTNAME") + assert info.include?("key1") + assert info.include?("key2") + end + + # Ensures that the server is fine when no UUID is present. + # + def test_write_host_info_with_missing_uuid + @host_info['UUID'] = nil + + assert_nothing_raised { @browser.write_host_info(@host_info) } + end + + # Ensures that, if the hostname is missing, the server + # raises an exception. + # + def test_write_host_info_with_missing_hostname + @host_info['HOSTNAME'] = nil + + assert_raise(Exception) { @browser.write_host_info(@host_info) } + end + + # Ensures that, if the architecture is missing, the server raises an + # exception. + # + def test_write_host_info_with_missing_arch + @host_info['ARCH'] = nil + + assert_raise(Exception) { @browser.write_host_info(@host_info) } + end + + # Ensures that, if the memory size is missing, the server raises an + # exception. + # + def test_write_host_info_info_with_missing_memsize + @host_info['MEMSIZE'] = nil + + assert_raise(Exception) { @browser.write_host_info(@host_info) } + end + + # Ensures that, if no cpu info was available, the server raises an + # exception. + # + def test_write_host_info_with_missing_cpuinfo + @host_info['CPUINFO'] = nil + + assert_raise(Exception) { @browser.write_host_info(@host_info) } + end + + # Ensures the browser can properly parse the CPU details. + # + def test_parse_cpu_info + @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "CPU\n" } + @session.should_receive(:write).with("CPUINFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key1=value1\n" } + @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key2=value2\n" } + @session.should_receive(:write).with("ACK key2\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDCPU\n" } + @session.should_receive(:write).with("ACK CPU\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDINFO\n" } + + info = @browser.get_remote_info + + assert_equal 3,info.keys.size, "Should contain four keys" + assert info.include?("CPUINFO") + end + + # Ensures the browser can properly parse the CPU details of two CPUs. + # + def test_parse_cpu_info + @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } + + # CPU 0 + @session.should_receive(:readline).once().returns { "CPU\n" } + @session.should_receive(:write).with("CPUINFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key1=value1\n" } + @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key2=value2\n" } + @session.should_receive(:write).with("ACK key2\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDCPU\n" } + @session.should_receive(:write).with("ACK CPU\n").once().returns { |request| request.length } + + # CPU 1 + @session.should_receive(:readline).once().returns { "CPU\n" } + @session.should_receive(:write).with("CPUINFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key3=value3\n" } + @session.should_receive(:write).with("ACK key3\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key4=value4\n" } + @session.should_receive(:write).with("ACK key4\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDCPU\n" } + @session.should_receive(:write).with("ACK CPU\n").once().returns { |request| request.length } + + @session.should_receive(:readline).once().returns { "ENDINFO\n" } + + info = @browser.get_remote_info + + assert_equal 3,info.keys.size, "Should contain four keys" + assert info.include?('CPUINFO') + assert_equal 2, info['CPUINFO'].size, "Should contain details for two CPUs" + assert_not_nil info['CPUINFO'][0]['key1'] + assert_not_nil info['CPUINFO'][0]['key2'] + assert_not_nil info['CPUINFO'][1]['key3'] + assert_not_nil info['CPUINFO'][1]['key4'] + end end diff --git a/wui/src/test/fixtures/cpus.yml b/wui/src/test/fixtures/cpus.yml new file mode 100644 index 0000000..5586303 --- /dev/null +++ b/wui/src/test/fixtures/cpus.yml @@ -0,0 +1,21 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html + +one: + cpu_number: 1 + core_number: 1 + cpu_id_level: 1 + vendor: 1 + family: 1 + model: 1 + family: MyString + flags: MyString + +two: + cpu_number: 1 + core_number: 1 + cpu_id_level: 1 + vendor: 1 + family: 1 + model: 1 + family: MyString + flags: MyString diff --git a/wui/src/test/fixtures/hosts.yml b/wui/src/test/fixtures/hosts.yml index 966a829..6658fa7 100644 --- a/wui/src/test/fixtures/hosts.yml +++ b/wui/src/test/fixtures/hosts.yml @@ -2,8 +2,6 @@ one: id: 1 uuid: '1148fdf8-961d-11dc-9387-001558c41534' hostname: 'prod.corp.com' - num_cpus: 8 - cpu_speed: 4096 arch: 'i686' memory: 18384 is_disabled: 0 @@ -13,8 +11,6 @@ two: id: 2 uuid: '1f2a8694-961d-11dc-9387-001558c41534' hostname: 'myworkstation.dev.corp.com' - num_cpus: 4 - cpu_speed: 2048 arch: 'i386' memory: 2048 is_disabled: 0 @@ -24,52 +20,42 @@ three: id: 3 uuid: '58a85f44-75fd-4934-805f-88e45b40d4b4' hostname: 'macworkstation.foobar.com' - num_cpus: 8 - cpu_speed: 1024 arch: 'mips' memory: 2048 - is_disabled: 0 + is_disabled: 0 hypervisor_type: 'kvm' hardware_pool_id: 2 four: id: 4 uuid: '520bbb34-6515-490e-9d07-0c8b14f76805' hostname: 'fedoraworkstation.foobar.com' - num_cpus: 8 - cpu_speed: 3072 arch: 'i386' memory: 2048 - is_disabled: 1 + is_disabled: 1 hypervisor_type: 'kvm' hardware_pool_id: 2 five: id: 5 uuid: '2e422f66-324e-48d4-973f-0b91b33070f9' hostname: 'pipeline.foobar.com' - num_cpus: 32 - cpu_speed: 4096 arch: 'xeon' memory: 16384 - is_disabled: 0 + is_disabled: 0 hypervisor_type: 'kvm' hardware_pool_id: 2 six: id: 6 uuid: 'bb0ce7c7-f234-49ae-84b5-6f4fd8bddcaa' hostname: 'prod.foobar.com' - num_cpus: 32 - cpu_speed: 4096 arch: 'xeon' memory: 16384 - is_disabled: 0 + is_disabled: 0 hypervisor_type: 'kvm' hardware_pool_id: 2 seven: id: 7 uuid: '6ae3d22e-97e0-4d86-9712-5395b20a0f45' hostname: 'mystation.dev.corp.com' - num_cpus: 4 - cpu_speed: 3072 arch: 'i686' memory: 2048 is_disabled: 0 @@ -79,8 +65,6 @@ eight: id: 8 uuid: 'ec0d86de-657b-48f6-b7cc-e733a3f9a834' hostname: 'issue.qa.corp.com' - num_cpus: 8 - cpu_speed: 4096 arch: 'x86' memory: 4096 is_disabled: 0 @@ -90,8 +74,6 @@ nine: id: 9 uuid: '81c15560-dbf4-45f5-9b75-106cdbd63aeb' hostname: 'somehost' - num_cpus: 4 - cpu_speed: 4096 arch: 'x86' memory: 4096 is_disabled: 0 diff --git a/wui/src/test/unit/cpu_test.rb b/wui/src/test/unit/cpu_test.rb new file mode 100644 index 0000000..5b64ca7 --- /dev/null +++ b/wui/src/test/unit/cpu_test.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class CpuTest < ActiveSupport::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end -- 1.5.5.1 From jim at meyering.net Sat Jul 5 17:23:27 2008 From: jim at meyering.net (Jim Meyering) Date: Sat, 05 Jul 2008 19:23:27 +0200 Subject: [Ovirt-devel] [PATCH] use last committish on the current branch for pre-release tag In-Reply-To: <1215099638-8475-1-git-send-email-apevec@redhat.com> (Alan Pevec's message of "Thu, 3 Jul 2008 17:40:38 +0200") References: <1215099638-8475-1-git-send-email-apevec@redhat.com> Message-ID: <87od5c5jow.fsf@rho.meyering.net> Alan Pevec wrote: > diff --git a/common/release.mk b/common/release.mk > index f1fb5f7..7d45ecb 100644 > --- a/common/release.mk > +++ b/common/release.mk > @@ -11,7 +11,7 @@ NEWVERSION = $$(awk 'BEGIN { printf "%.2f", $(VERSION) + .01 }') > NEWRELEASE = $$(($(RELEASE) + 1)) > X = $$(awk '{ split($$2,r,"."); \ > printf("%d.%d\n", r[1], r[2]+1) }' version) > -git_head = $$(git show-ref --hash=7 HEAD) > +git_head = $$(git log -1 --pretty=format:%h) ACK ;-) From jeffschroed at gmail.com Sat Jul 5 19:31:31 2008 From: jeffschroed at gmail.com (Jeff Schroeder) Date: Sat, 5 Jul 2008 12:31:31 -0700 Subject: [Ovirt-devel] [R&D] Breaking the Browser In-Reply-To: <486EDD72.3050006@redhat.com> References: <368865082.756671215038318114.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <722066189.756751215038368416.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <1215118170.3094.9.camel@localhost.localdomain> <1215119645.3094.35.camel@localhost.localdomain> <486EDD72.3050006@redhat.com> Message-ID: On Fri, Jul 4, 2008 at 7:33 PM, mark wagner wrote: > > > Jeff Schroeder wrote: >> >> On Thu, Jul 3, 2008 at 2:14 PM, Jason Guiditta >> wrote: >>> >>> On Thu, 2008-07-03 at 13:59 -0700, Jeff Schroeder wrote: >>> >>>> Q: How do you get realtime graphs with a webapp? >>>> A: SVG + AJAX >>>> >>>> A good example of how to do this would be the m0n0wall firewall. >>>> Here is a screenshot of their interface graphs: >>>> http://m0n0.ch/wall/images/screens/status_graph.png >>>> >>>> The svg graphs are drawn by the javascript. It gets the data from a >>>> xmlhttprequest >>>> feed directly from the server. It is really sexy technology and most >>>> browsers >>>> support it. Is asking IE users to install the Adobe SVG plugin or user >>>> Firefox >>>> too much? >>>> >>>> Take a look at how easy this is to do: >>>> http://www.browserland.org/scripts/svgclock/ >>>> >>>> If you compress that svg down, the whole thing is 4k. I don't even think >>>> flash >>>> could do something that smooth and clean looking in 4k. Were you aware >>>> of this? >>>> >>> Agreed, and we are using svg for the graphs right now, though they do >>> need some optimization and better javascript hooks. I am not a >>> proponent of us using flash for this, but others disagree. Also, since >>> adobe is discontinuing support for their svg viewer, there is another >>> one I have read good things about called renesis: >>> http://www.examotion.com/Downloads.product_player_download.0.html >> >> Besides internet explorer, a better question would be why not use >> javascript + svg? >> If someone that isn't you disagrees, can they give a solid technical >> reason for this? >> >> What graph _absolutely has to be_ realtime? In all of the cases I >> could come up with >> not a one wouldn't be serviced by near-realtime graphs. Do you expect >> users to have >> ovirt graph screens up on a bank of plasma displays watching node >> stats in realtime? > > So if your job is to monitor the 25 hosts in your pool and take immediate > and > effective action to mitigate any performance or catastrophic issues in said > pool within one minute and 26 secs (3 nines, assuming this is the only issue > that day) of the event, how are you going to monitor your pool ? That is what monitoring software is for. If you expect someone to _look_ at a webgui 24/7 you are approaching the problem from the absolute wrong angle. > If we don't provide the ability to notify immediately when a host goes down, > you are rapidly eating into time specified to resolve a problem. You are agreeing with me on this one. This is what monitoring software is for, not a website. Something like nagios could call a pager or run a script to do something much faster than a human could. > The thing that people seem to be missing or ignoring is that this a > Systems Management Tool. Often times, there will be Service Level Agreements > associated with with running a NOC. Not making data available in real > time is going to exclude ovirt from sites. No, you missed my point entirely. SLAs in a NOC are perfectly reasonable. > We need to look at making the nav bar have near realtime capabilities. > I need to know if a system is getting close to capacity (change the color > of the icon?) or is offline. Changing the color of the icon would be good, but the admin should be able to set threshholds. When X reaches X%, send alert to foo at bar.com or run script /usr/local/bin/foo-alert.sh > If I have a graph of CPU utilization in my browser for the last two > hours of "my pool" it should automatically get updated as data becomes > available or my finger will get tired from hitting refresh. Never > underestimate the strain on a server caused by people hitting refresh > to see if the data has changed, if I know it will auto update, I cease > that behavior. > (How often to update the data from the host and guests is also an important > part of this equation) If you have to hit refresh over and over you are doing this completely wrong. >> Even in a big fortune 100 NOC this seems unreasonable and a bad use case. > > So are you saying we should focus our attention on providing real time > alerts > / event notification? > How do the admins get notified as quickly as possible? > Do they sit in front of a terminal and hit refresh on there browser? > Set their mail clients to fetch every 10 secs ? > This is clearly a case where time is money, if you are in a big NOC and > miss your SLA it could cost big bucks, not to mention a job or two. Mark, without causing any bad blood, this conversation is basicly over. You agree with me that notification should happen as soon as possible. You disagree with me on how it should be done. For true autonomy, the human aspect needs to be taken out of the picture as much as possible. This is why I'd argue a script should automatically do alerting and NOT a human. What the human does with that alert is up to the business. >> Once oVirt a policy engine (like VMotion) the graphs updating in >> realtime don't seem >> near as useful. > > This does not make the case not to have the ability *now*. Just that it may > not > be needed later. Yes we are both aware of this and that it will take a few years for this to materialize. > Can you think of a reason that demands absolute realtime graphs? > > I agree that no graph "has to be realtime". We could do things via a "top" > like tool or other means. However, graphs tend to be easier to read, > although "top" > updates more frequently.... > > The argument you make is actually a not meaningful here because there is > really > nothing that "demands ovirt". Its a tool to (hopefully) make management of a > virtualized easier, but its not an absolute to deploying virtualization. You > could > do the same management with existing tools, just be a lot harder and costly. > > In my mind, realtime graphs in some limited form could be a useful feature. > For instance, I don't think that we need a realtime graph to show the > monthly > data (sigh, but now I know that some customers will want it, double sigh ) > > > >> >> Here is how I envision oVirt with a 2-3 major releases under it's belt. > > You realize that two or three major releases are at least several years > away. > Do we have the functionality required now to ensure that there is will be > sufficient demand for ovirt that far out ? > The internet is littered with many projects that never deliver the > functionality > needed to survive until their third major release is ready... > >> >> AMQP bus message: OH NOES, Node3 is about to bust out the oom killer to >> lay the >> smack down on vm1 and vm2. Run >> around, scream, and panic! >> oVirt Policy Engine: Live migrates vm1 and vm2 from Node3 to Node4 >> because Node4 is idle. >> AMQP bus message: Disaster diverted by policy engine. All systems >> nominal. >> oVirt Policy Engine: Goes back to saving the world and drinking it's >> latte >> Systems Admin: Hey look at that, something bad almost happened but >> this >> cool software fixed itsself. /goes >> back to reading xkcd >> >> What do you think? > > This seems to require real time data to do its job effectively. Doing it > after the fact will interrupt your comics... > > > We do need to be concerned about overtaxing the servers with polling from > many clients. The correct solution would most likely involve a more > distributed architecture that distributes the load and can sustain growth > to meet the needs of the customers. A push model for certain types of data > is also essential. > > Keep in mind that we are trying to solve problems that have been resolved > many times over the years. The basic architecture of network management > apps is that a server polls for stats and events / alerts get pushed to > the server. With a distributed system, the servers need to push the events > amongst themselves. Stats can be stored centrally or in a distributed > fashion, the important aspect is that the data is available to all the > servers . > > -mark > -- Jeff Schroeder Don't drink and derive, alcohol and analysis don't mix. http://www.digitalprognosis.com From mwagner at redhat.com Mon Jul 7 02:26:43 2008 From: mwagner at redhat.com (mark wagner) Date: Sun, 06 Jul 2008 22:26:43 -0400 Subject: [Ovirt-devel] [R&D] Breaking the Browser In-Reply-To: References: <368865082.756671215038318114.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <722066189.756751215038368416.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <1215118170.3094.9.camel@localhost.localdomain> <1215119645.3094.35.camel@localhost.localdomain> <486EDD72.3050006@redhat.com> Message-ID: <48717EE3.4060602@redhat.com> Note sort of a combinational reply to several responses in this thread.... Jeff Schroeder wrote: > On Fri, Jul 4, 2008 at 7:33 PM, mark wagner wrote: >> >> Jeff Schroeder wrote: >>> On Thu, Jul 3, 2008 at 2:14 PM, Jason Guiditta >>> wrote: >> So if your job is to monitor the 25 hosts in your pool and take immediate >> and >> effective action to mitigate any performance or catastrophic issues in said >> pool within one minute and 26 secs (3 nines, assuming this is the only issue >> that day) of the event, how are you going to monitor your pool ? > > That is what monitoring software is for. If you expect someone to _look_ at > a webgui 24/7 you are approaching the problem from the absolute wrong angle. > >> If we don't provide the ability to notify immediately when a host goes down, >> you are rapidly eating into time specified to resolve a problem. > You are agreeing with me on this one. This is what monitoring software is for, > not a website. Something like nagios could call a pager or run a script to do > something much faster than a human could. > So I guess the question to people is why not just make the decision to switch over to Nagios and something like Cacti now ? We all seem to agree that we need the Nagios type of functionality, Cacti or something should be able to solve our graphing requirements as well. >> We need to look at making the nav bar have near realtime capabilities. >> I need to know if a system is getting close to capacity (change the color >> of the icon?) or is offline. > Changing the color of the icon would be good, but the admin should be able > to set threshholds. When X reaches X%, send alert to foo at bar.com or run > script /usr/local/bin/foo-alert.sh > >> How do the admins get notified as quickly as possible? >> Do they sit in front of a terminal and hit refresh on there browser? >> Set their mail clients to fetch every 10 secs ? >> This is clearly a case where time is money, if you are in a big NOC and >> miss your SLA it could cost big bucks, not to mention a job or two. > > Mark, without causing any bad blood, this conversation is basicly over. You > agree with me that notification should happen as soon as possible. You disagree > with me on how it should be done. For true autonomy, the human aspect > needs to be taken out of the picture as much as possible. This is why I'd > argue a script should automatically do alerting and NOT a human. What > the human does with that alert is up to the business. > Jeff, no bad blood thoughts here, this is an open, professional discussion aimed at making ovirt as good is can. My goal is to provoke discussion to make sure that we have considered all angles that we can and the ramifications of any decision. I agree that the human interaction needs to be minimized as quickly and as much as possible. However, I don't know that anyone is even considering how to add that at this point in time. (someone jump in if I'm wrong here) I still think there will be cases where things are not automated and some interaction needs to get done by hand. Thus, even though we agree on functionality we need, I'm not sure that the discussion should be over yet. For instance, I think that we should see what it takes to update the NavBar as soon a possible with state changes. If I start a guest or host manually, I would want to see when it is available ASAP w/o the need for my pager to go off or an email to arrive. The logical place to me is in the NavBar. My logic is that if I'm starting it via the WUI, there is a reasonable chance I'm going to do something else with it. In the case of the host, I may move some guests to it. As a user, if there is no immediate notification, I'll be hitting refresh to see when its available so I can continue my work. I will admit that I do not work as an admin. I do sometimes play one when running performance tests, etc. Our solution is very low-tech, we poll until the systems are up and then monitor the tests. If "industry standard practice" for a NOC is to use pagers then my argument may be irrelevant to our "target audience" and us lab weenies can wear out the refresh button :) -mark From jeffschroed at gmail.com Mon Jul 7 05:46:43 2008 From: jeffschroed at gmail.com (Jeff Schroeder) Date: Sun, 6 Jul 2008 22:46:43 -0700 Subject: [Ovirt-devel] [R&D] Breaking the Browser In-Reply-To: <48717EE3.4060602@redhat.com> References: <368865082.756671215038318114.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <722066189.756751215038368416.JavaMail.root@zmail02.collab.prod.int.phx2.redhat.com> <1215118170.3094.9.camel@localhost.localdomain> <1215119645.3094.35.camel@localhost.localdomain> <486EDD72.3050006@redhat.com> <48717EE3.4060602@redhat.com> Message-ID: On Sun, Jul 6, 2008 at 7:26 PM, mark wagner wrote: > Note sort of a combinational reply to several responses in this thread.... Thanks again for keeping this civil. The only reason I asked to end this thread was to prevent it from turning into a flamefest. > Jeff Schroeder wrote: >> >> On Fri, Jul 4, 2008 at 7:33 PM, mark wagner wrote: >>> >>> Jeff Schroeder wrote: >>>> >>>> On Thu, Jul 3, 2008 at 2:14 PM, Jason Guiditta >>>> wrote: > > >>> So if your job is to monitor the 25 hosts in your pool and take immediate >>> and >>> effective action to mitigate any performance or catastrophic issues in >>> said >>> pool within one minute and 26 secs (3 nines, assuming this is the only >>> issue >>> that day) of the event, how are you going to monitor your pool ? >> >> That is what monitoring software is for. If you expect someone to _look_ >> at >> a webgui 24/7 you are approaching the problem from the absolute wrong >> angle. >> >>> If we don't provide the ability to notify immediately when a host goes >>> down, >>> you are rapidly eating into time specified to resolve a problem. >> You are agreeing with me on this one. This is what monitoring software is >> for, >> not a website. Something like nagios could call a pager or run a script to >> do >> something much faster than a human could. >> > > So I guess the question to people is why not just make the decision to > switch > over to Nagios and something like Cacti now ? > We all seem to agree that we need the Nagios type of functionality, Cacti or > something should be able to solve our graphing requirements as well. If you've ever looked over the cacti codebase you might want to go let out aggression on an inanimate object afterwards. Apache + php would add a lot of dependencies to the management node appliance also. +1 for nagios, but you might be better off to roll your own small graphing libs in ruby or whatnot. >>> We need to look at making the nav bar have near realtime capabilities. >>> I need to know if a system is getting close to capacity (change the color >>> of the icon?) or is offline. Key word being near-realtime like I stated in an earlier thread. Even if it really only polls, gmail does a pretty good job of something similar to oVirt. >> Changing the color of the icon would be good, but the admin should be able >> to set threshholds. When X reaches X%, send alert to foo at bar.com or run >> script /usr/local/bin/foo-alert.sh >> > >>> How do the admins get notified as quickly as possible? >>> Do they sit in front of a terminal and hit refresh on there browser? >>> Set their mail clients to fetch every 10 secs ? >>> This is clearly a case where time is money, if you are in a big NOC and >>> miss your SLA it could cost big bucks, not to mention a job or two. This is clearly a case where you've not sat in an admin's shoes. If the only tool you give a good admin to monitor his hosts is a web-ui, he is going to crack open perl LWP or python and scrape it every few seconds. He's also going to say nasty things to you for only giving him a webui to work with. Trying to reinforce the idea again, a web ui should never be relied on for realtime issues or alerts. Give a good api (commandline or web services) and the admin will deal with that. Good admins are too lazy to hit refresh and will write a script to do that for them. This is my day job and has been for some time. >> Mark, without causing any bad blood, this conversation is basicly over. >> You >> agree with me that notification should happen as soon as possible. You >> disagree >> with me on how it should be done. For true autonomy, the human aspect >> needs to be taken out of the picture as much as possible. This is why I'd >> argue a script should automatically do alerting and NOT a human. What >> the human does with that alert is up to the business. >> > > Jeff, no bad blood thoughts here, this is an open, professional discussion > aimed at making ovirt as good is can. My goal is to provoke discussion > to make sure that we have considered all angles that we can and the > ramifications of any decision. > > I agree that the human interaction needs to be minimized as quickly and as > much as possible. However, I don't know that anyone is even considering > how to add that at this point in time. (someone jump in if I'm wrong here) > > I still think there will be cases where things are not automated and some > interaction needs to get done by hand. Thus, even though we agree on > functionality we need, I'm not sure that the discussion should be over yet. > For instance, I think that we should see what it takes to update the > NavBar as soon a possible with state changes. If I start a guest or host > manually, I would want to see when it is available ASAP w/o the need for > my pager to go off or an email to arrive. The logical place to me is in the > NavBar. While still trying to be constructive, is the difference between 5-10 seconds(poll) and a few milliseconds (realtime) honestly going to matter? From a systems administrator standpoint, I'm still unconvinced what this buys you. I've worked at fortune 500 and 200 companies with some pretty complex uptime SLAs. This still boggles my mind. Can you give an actual use case where this is required? Putting my admin hat on, starting a service is a good event and should *never* alert. Stopping, restarting, or abnormal shutdown of hosts should alert. If you drown out the bad things with white noise important things will get glanced over. > My logic is that if I'm starting it via the WUI, there is a reasonable > chance I'm going to do something else with it. In the case of the host, > I may move some guests to it. As a user, if there is no immediate > notification, > I'll be hitting refresh to see when its available so I can continue my work. You should never have to refresh a proper web-2.0 application. Again, if we can strive to be somewhat similar to gmail with near-realtime updates, I think it will be "good enough". If you disagree and want to send in patches more power to you. Can you give me an actual use case of the above scenario though? Is it something along the lines of an admin starting a host and moving vms on it and a user waiting to play with those vms? In 8+ years of doing this kind of work I've not seen something like this where it absolutely must be realtime. This seems niche and overkill for 95% of the cases. Feel free to prove otherwise. > I will admit that I do not work as an admin. I do sometimes play one when > running performance tests, etc. Our solution is very low-tech, we poll > until the systems are up and then monitor the tests. If "industry standard > practice" for a NOC is to use pagers then my argument may be irrelevant > to our "target audience" and us lab weenies can wear out the refresh button > :) I'm trying to move from an admin to more of a "systems developer" roll. Why not just poll more and make the data transferred very small? Here is a quick idea from a current sleep deprived state, please comment and or rip it to shreds: Have a _very small_ bit of json with a few variables for each host. When a new host comes up, it can add itsself to an object somewhere that a json feed creator can access. If a user is logged in with sufficient access to see host information, a json file is created with the hosts he/she is allowed to view. The json can sit in memory and so polling it shouldn't be a huge deal. If another user is logged in with access to the exact same hosts, the ruby just includes the exact same file / object or whatever and uses the same already-cached json. If this was the "enterprise deployment" of oVirt with everything split up onto different hosts, this would still scale pretty well on a low mid-range server like a dl360 or whatnot. Kind of cheesy, but what do you think? And for the "too much polling kills the server" argument, you split it up into > 1 ovirt server and have them do realtime communication (AMQP) between each other. Network would be the main bottleneck in this design, but it rarely is the bottleneck in "enterprises". Thoughts? > > -mark > -- Jeff Schroeder Don't drink and derive, alcohol and analysis don't mix. http://www.digitalprognosis.com From apevec at redhat.com Mon Jul 7 08:26:56 2008 From: apevec at redhat.com (Alan Pevec) Date: Mon, 7 Jul 2008 10:26:56 +0200 Subject: [Ovirt-devel] [PATCH] customization of ovirt-mongrel-rails service Message-ID: <1215419216-4623-1-git-send-email-apevec@redhat.com> using /etc/sysconfig/ config file instead of editing the init script Signed-off-by: Alan Pevec --- wui/conf/ovirt-mongrel-rails | 19 +++++++++++-------- 1 files changed, 11 insertions(+), 8 deletions(-) diff --git a/wui/conf/ovirt-mongrel-rails b/wui/conf/ovirt-mongrel-rails index 67c03c4..9c770ac 100755 --- a/wui/conf/ovirt-mongrel-rails +++ b/wui/conf/ovirt-mongrel-rails @@ -8,16 +8,19 @@ # ovirt VM manager. # -OVIRT_DIR=/usr/share/ovirt-wui +[ -r /etc/sysconfig/ovirt-mongrel-rails ] && . /etc/sysconfig/ovirt-mongrel-rails + +OVIRT_DIR="${OVIRT_DIR:-/usr/share/ovirt-wui}" +MONGREL_LOG="${MONGREL_LOG:-/var/log/ovirt-wui/mongrel.log}" +MONGREL_PID="${MONGREL_PID:-/var/run/ovirt-wui/mongrel.pid}" +MONGREL_LOCKFILE="${MONGREL_LOCKFILE:-/var/lock/subsys/ovirt-wui}" +RAILS_ENVIRONMENT="${RAILS_ENVIRONMENT:-production}" +USER="${USER:-ovirt}" +GROUP="${GROUP:-ovirt}" +PREFIX="${PREFIX:-/ovirt}" + MONGREL_PROG=mongrel_rails -MONGREL_LOG=/var/log/ovirt-wui/mongrel.log -MONGREL_PID=/var/run/ovirt-wui/mongrel.pid -MONGREL_LOCKFILE=/var/lock/subsys/ovirt-wui ADDR=127.0.0.1 -RAILS_ENVIRONMENT=production -USER=ovirt -GROUP=ovirt -PREFIX=/ovirt RETVAL=0 -- 1.5.4.1 From mmorsi at redhat.com Mon Jul 7 16:32:35 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Mon, 07 Jul 2008 12:32:35 -0400 Subject: [Ovirt-devel] [PATCH] customization of ovirt-mongrel-rails service In-Reply-To: <1215419216-4623-1-git-send-email-apevec@redhat.com> References: <1215419216-4623-1-git-send-email-apevec@redhat.com> Message-ID: <48724523.8060805@redhat.com> Alan Pevec wrote: > using /etc/sysconfig/ config file instead of editing the init script > > ACK. Just tried this on my local oVirt appliance and it works great for switching between the copy of oVirt that comes with the appliance in /usr/share/ovirt-wui and an updatable copy pulled from git which I checked out in my home dir. The /etc/sysconfig/ovirt-mongrel-rails script should probably be added to the project and the oVirt RPM eventually, but it not being there doesn't break anything so its not a big deal. Once this is committed, I'll commit my fixes to the test cases as previously acked (pending this patch) by hugh. -Mo From apevec at redhat.com Mon Jul 7 17:20:22 2008 From: apevec at redhat.com (Alan Pevec) Date: Mon, 7 Jul 2008 19:20:22 +0200 Subject: [Ovirt-devel] [PATCH] customization of ovirt-mongrel-rails service In-Reply-To: <48724523.8060805@redhat.com> References: <48724523.8060805@redhat.com> Message-ID: <1215451222-17233-1-git-send-email-apevec@redhat.com> using /etc/sysconfig/ config file instead of editing the init script ovirt-wui RPM: add default config /etc/sysconfig/ovirt-mongrel-rails with doc comments Signed-off-by: Alan Pevec --- wui/conf/ovirt-mongrel-rails | 19 +++++++++++-------- wui/conf/ovirt-mongrel-rails.sysconf | 23 +++++++++++++++++++++++ wui/ovirt-wui.spec | 4 +++- 3 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 wui/conf/ovirt-mongrel-rails.sysconf diff --git a/wui/conf/ovirt-mongrel-rails b/wui/conf/ovirt-mongrel-rails index 67c03c4..9c770ac 100755 --- a/wui/conf/ovirt-mongrel-rails +++ b/wui/conf/ovirt-mongrel-rails @@ -8,16 +8,19 @@ # ovirt VM manager. # -OVIRT_DIR=/usr/share/ovirt-wui +[ -r /etc/sysconfig/ovirt-mongrel-rails ] && . /etc/sysconfig/ovirt-mongrel-rails + +OVIRT_DIR="${OVIRT_DIR:-/usr/share/ovirt-wui}" +MONGREL_LOG="${MONGREL_LOG:-/var/log/ovirt-wui/mongrel.log}" +MONGREL_PID="${MONGREL_PID:-/var/run/ovirt-wui/mongrel.pid}" +MONGREL_LOCKFILE="${MONGREL_LOCKFILE:-/var/lock/subsys/ovirt-wui}" +RAILS_ENVIRONMENT="${RAILS_ENVIRONMENT:-production}" +USER="${USER:-ovirt}" +GROUP="${GROUP:-ovirt}" +PREFIX="${PREFIX:-/ovirt}" + MONGREL_PROG=mongrel_rails -MONGREL_LOG=/var/log/ovirt-wui/mongrel.log -MONGREL_PID=/var/run/ovirt-wui/mongrel.pid -MONGREL_LOCKFILE=/var/lock/subsys/ovirt-wui ADDR=127.0.0.1 -RAILS_ENVIRONMENT=production -USER=ovirt -GROUP=ovirt -PREFIX=/ovirt RETVAL=0 diff --git a/wui/conf/ovirt-mongrel-rails.sysconf b/wui/conf/ovirt-mongrel-rails.sysconf new file mode 100644 index 0000000..c7c97fd --- /dev/null +++ b/wui/conf/ovirt-mongrel-rails.sysconf @@ -0,0 +1,23 @@ +# root directory of the oVirt WUI Rails application +#OVIRT_DIR=/usr/share/ovirt-wui + +# location of the logfile +#MONGREL_LOG=/var/log/ovirt-wui/mongrel.log + +# location of the lockfile +#MONGREL_LOCKFILE=/var/lock/subsys/ovirt-wui + +# location of the file containing running process ID +#MONGREL_PID=/var/run/ovirt-wui/mongrel.pid + + +# sets ruby on Rails environment / mode of operation +# http://wiki.rubyonrails.org/rails/pages/Environments +#RAILS_ENVIRONMENT=production + +# user and group under which Rails application runs +#USER=ovirt +#GROUP=ovirt + +# URL prefix for Rails application +#PREFIX=/ovirt diff --git a/wui/ovirt-wui.spec b/wui/ovirt-wui.spec index 48facb0..9ed33ca 100644 --- a/wui/ovirt-wui.spec +++ b/wui/ovirt-wui.spec @@ -57,8 +57,8 @@ mkdir %{buildroot} %{__install} -d -m0755 %{buildroot}%{_bindir} %{__install} -d -m0755 %{buildroot}%{_sbindir} %{__install} -d -m0755 %{buildroot}%{_initrddir} +%{__install} -d -m0755 %{buildroot}%{_sysconfdir}/sysconfig %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/httpd/conf.d -%{__install} -d -m0755 %{buildroot}%{_sysconfdir}/sysconfig/%{name} %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/%{name} %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/%{name}/db %{__install} -d -m0755 %{buildroot}%{_localstatedir}/lib/%{name} @@ -76,6 +76,7 @@ touch %{buildroot}%{_localstatedir}/log/%{name}/host-status.log %{__install} -Dp -m0755 %{pbuild}/conf/ovirt-host-status %{buildroot}%{_initrddir} %{__install} -Dp -m0755 %{pbuild}/conf/ovirt-host-collect %{buildroot}%{_initrddir} %{__install} -Dp -m0755 %{pbuild}/conf/ovirt-mongrel-rails %{buildroot}%{_initrddir} +%{__install} -Dp -m0755 %{pbuild}/conf/ovirt-mongrel-rails.sysconf %{buildroot}%{_sysconfdir}/sysconfig/ovirt-mongrel-rails %{__install} -Dp -m0755 %{pbuild}/conf/ovirt-taskomatic %{buildroot}%{_initrddir} # copy over all of the src directory... @@ -163,6 +164,7 @@ fi %{_initrddir}/ovirt-host-collect %{_initrddir}/ovirt-mongrel-rails %{_initrddir}/ovirt-taskomatic +%config(noreplace) %{_sysconfdir}/sysconfig/ovirt-mongrel-rails %config(noreplace) %{_sysconfdir}/httpd/conf.d/%{name}.conf %doc %attr(-, ovirt, ovirt) %{_localstatedir}/lib/%{name} -- 1.5.4.1 From pmyers at redhat.com Tue Jul 8 00:50:53 2008 From: pmyers at redhat.com (Perry Myers) Date: Mon, 7 Jul 2008 20:50:53 -0400 Subject: [Ovirt-devel] [PATCH] [RESEND] Add additional blacklisting and rpm removal to managed node Message-ID: <1215478253-11844-1-git-send-email-pmyers@redhat.com> A few important notes: 1. /lib/modules was scoured for things that didn't seem necessary, however my notion of not necessary may not be correct. Please review the list of modules that I'm removing and if you see one that we need to add back in, comment. 2. /boot is removed as we don't need an initrd and kernel image inside of the livecd initrd. 3. The blacklisting method is a hack. What we need is an appliance creator that has black/whitelisting capabilities... (hint, hint to our AOS friends out there) NOTE: This patch is revised from my patch last week. I incorporated suggestions from Chris regarding reinclusion of some kernel modules and fixed an issue with i386 builds by not wiping out /lib/security. With this patch both i386 and x86_64 managed nodes boot and work. Signed-off-by: Perry Myers --- ovirt-host-creator/common-post.ks | 99 +++++++++++++++++++++++-------------- 1 files changed, 62 insertions(+), 37 deletions(-) diff --git a/ovirt-host-creator/common-post.ks b/ovirt-host-creator/common-post.ks index d56059a..900f620 100644 --- a/ovirt-host-creator/common-post.ks +++ b/ovirt-host-creator/common-post.ks @@ -9,13 +9,6 @@ echo "Creating shadow files" pwconv grpconv -echo "Re-creating cracklib dicts" -# cracklib-dicts is 8MB. We probably don't need to have strict password -# checking on the ovirt host -# unfortunately we can't create an empty cracklib dict, so we create it -# with a single entry "1" -echo 1 | packer >& /dev/null - echo "Forcing C locale" # force logins (via ssh, etc) to use C locale, since we remove locales cat >> /etc/profile << \EOF @@ -23,9 +16,6 @@ cat >> /etc/profile << \EOF export LC_ALL=C LANG=C EOF -# here, remove a bunch of files we don't need that are just eating up space. -# it breaks rpm slightly, but it's not too bad - echo "Removing excess RPMs" # kernel pulls in mkinitrd which pulls in isomd5sum which pulls in python, @@ -36,36 +26,30 @@ rpm -e system-config-firewall-tui system-config-network-tui rhpl \ rpm-python dbus-python kudzu newt-python newt rpm -e qemu kpartx mkinitrd isomd5sum dmraid python python-libs +RPM="rpm -v -e --nodeps" + # Sigh. ntp has a silly dependency on perl because of auxiliary scripts which # we don't need to use. Forcibly remove it here -rpm -e --nodeps perl perl-libs perl-Module-Pluggable perl-version \ +$RPM perl perl-libs perl-Module-Pluggable perl-version \ perl-Pod-Simple perl-Pod-Escapes -RM="rm -rf" +# Remove additional RPMs forcefully +$RPM gamin pm-utils kbd libuser passwd usermode \ + openssh-clients vbetool ConsoleKit hdparm \ + efibootmgr krb5-workstation linux-atm-libs fedora-release-notes \ + slang psmisc gdbm cryptsetup-luks pciutils mtools syslinux db4 \ + wireless-tools radeontool cracklib-dicts cracklib -echo "Removing docs and internationalization" -$RM /usr/share/omf -$RM /usr/share/gnome -$RM /usr/share/doc -$RM /usr/share/locale -$RM /usr/share/libthai -$RM /usr/share/man -$RM /usr/share/terminfo -$RM /usr/share/X11 -$RM /usr/share/i18n +# Things we could probably remove if libvirt didn't link against them +#$RPM avahi PolicyKit xen-libs -find /usr/share/zoneinfo -regextype egrep -type f \ - ! -regex ".*/UTC" -exec $RM {} \; -# XXX anaconda/timezone.py does it, missing in imgcreate/kickstart.py -cp /usr/share/zoneinfo/UTC /etc/localtime +# Things we could probably remove if qemu-kvm didn't link against them +#$RPM SDL alsa-lib -$RM /usr/lib/locale -$RM /usr/lib/syslinux -$RM /usr/lib64/gconv -$RM /usr/lib64/pango -$RM /usr/lib64/libpango* -$RM /etc/pango -$RM /usr/bin/pango* +# Pam complains when this is missing +#$RPM ConsoleKit-libs + +RM="rm -rf" echo "Removing excess kernel modules" MODULES="/lib/modules/*/kernel" @@ -83,16 +67,57 @@ fs_mods="fs/nls fs/9p fs/affs fs/autofs fs/autofs4 fs/befs fs/bfs fs/cifs \ net_mods="net/802 net/8021q net/9p net/appletalk net/atm net/ax25 \ net/bluetooth net/dccp net/decnet net/ieee80211 net/ipx net/irda \ net/mac80211 net/netrom net/rfkill net/rose net/sched net/tipc \ - net/wanrouter net/wireless drivers/auxdisplay drivers/net/appletalk \ + net/wanrouter net/wireless" + +driver_mods="drivers/auxdisplay drivers/net/appletalk \ drivers/net/hamradio drivers/net/pcmcia drivers/net/tokenring \ - drivers/net/wireless drivers/net/irda drivers/atm drivers/usb/atm" + drivers/net/wireless drivers/net/irda drivers/atm drivers/usb/atm \ + drivers/acpi drivers/char/drm drivers/char/mwave \ + drivers/char/ipmp drivers/char/pcmcia drivers/crypto drivers/dca \ + drivers/firmware drivers/memstick drivers/mmc drivers/mfs \ + drivers/parport drivers/video drivers/watchdog drivers/net/ppp* \ + drivers/usb/serial drivers/usb/misc drivers/usb/class \ + drivers/usb/image drivers/rtc" misc_mods="drivers/bluetooth drivers/firewire drivers/i2c drivers/isdn \ drivers/media drivers/misc drivers/leds drivers/mtd drivers/w1 sound \ - drivers/input drivers/pcmcia drivers/scsi/pcmcia" + drivers/input drivers/pcmcia drivers/scsi/pcmcia crypto lib" -for mods in $fs_mods $net_mods $misc_mods ; do +for mods in $fs_mods $net_mods $misc_mods $driver_mods ; do $RM $MODULES/$mods done +echo "Removing all timezones except for UTC" +find /usr/share/zoneinfo -regextype egrep -type f \ + ! -regex ".*/UTC|.*/GMT" -exec $RM {} \; +# XXX anaconda/timezone.py does it, missing in imgcreate/kickstart.py +cp /usr/share/zoneinfo/UTC /etc/localtime + +echo "Removing blacklisted files and directories" +blacklist="/boot /etc/alsa /etc/pki /usr/share/hwdata/MonitorsDB \ + /usr/share/hwdata/oui.txt /usr/share/hwdata/videoaliases \ + /usr/share/hwdata/videodrivers /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/src /usr/etc /usr/games /usr/include /usr/local /usr/lib64/python2.5 \ + /usr/lib64/tc /usr/lib64/tls /usr/lib64/sse2 /usr/lib64/pkgconfig \ + /usr/lib64/nss /usr/lib64/X11 /usr/lib64/games /usr/lib64/alsa-lib \ + /usr/lib64/fs/reiserfs /usr/lib64/krb5 /usr/lib64/hal /usr/lib64/gio \ + /usr/bin/hal-device /usr/bin/hal-disable-polling \ + /usr/bin/hal-find-by-capability /usr/bin/hal-find-by-property \ + /usr/bin/hal-is-caller-locked-out /usr/bin/hal-is-caller-privileged \ + /usr/bin/hal-lock /usr/bin/hal-set-property /usr/bin/hal-setup-keymap \ + /usr/sbin/dell* /lib/terminfo/d /lib/terminfo/v /lib/terminfo/a \ + /lib/firmware /usr/lib/locale /usr/lib/syslinux /usr/lib64/gconv \ + /usr/lib64/pango /usr/lib64/libpango* /etc/pango /usr/bin/pango*" + +docs_blacklist="/usr/share/omf /usr/share/gnome /usr/share/doc \ + /usr/share/locale /usr/share/libthai /usr/share/man /usr/share/terminfo \ + /usr/share/X11 /usr/share/i18n" + +$RM $blacklist $docs_blacklist + +echo "Cleanup empty directory structures in /usr/share" +find /usr/share -type d -exec rmdir {} \; > /dev/null 2>&1 + echo "Finished Kickstart Post" -- 1.5.5.1 From apevec at redhat.com Tue Jul 8 08:33:00 2008 From: apevec at redhat.com (Alan Pevec) Date: Tue, 08 Jul 2008 10:33:00 +0200 Subject: [Ovirt-devel] [PATCH] [RESEND] Add additional blacklisting and rpm removal to managed node In-Reply-To: <1215478253-11844-1-git-send-email-pmyers@redhat.com> References: <1215478253-11844-1-git-send-email-pmyers@redhat.com> Message-ID: <4873263C.3010302@redhat.com> Perry Myers wrote: > NOTE: This patch is revised from my patch last week. I incorporated > suggestions from Chris regarding reinclusion of some kernel modules and > fixed an issue with i386 builds by not wiping out /lib/security. With > this patch both i386 and x86_64 managed nodes boot and work. ACK for that, just few things I missed before: > +# XXX anaconda/timezone.py does it, missing in imgcreate/kickstart.py > +cp /usr/share/zoneinfo/UTC /etc/localtime this is fixed in livecd-tools-017.1: - Handle copying timezone to /etc/localtime (#445624) so we could remove it from here and add BuildRequires: livecd-tools >= 017.1 in ovirt-host-image.spec > +echo "Removing blacklisted files and directories" ... > + /usr/lib64/pango /usr/lib64/libpango* /etc/pango /usr/bin/pango*" I don't see /usr/lib/pango/ in the blacklist - in general, to avoid 32/64 idiosyncrasies we could use /usr/lib{,64}/pango /usr/lib{,64}/libpango* ... From dpierce at redhat.com Tue Jul 8 12:01:25 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Tue, 8 Jul 2008 08:01:25 -0400 Subject: [Ovirt-devel] Re: ovirt-identify-node now submits all extended CPU details. In-Reply-To: <1215266397-13191-1-git-send-email-dpierce@redhat.com> References: <1215266397-13191-1-git-send-email-dpierce@redhat.com> Message-ID: <20080708120125.GF14152@redhat.com> +++ Darryl L. Pierce [05/07/08 09:59 -0400]: Ditto on feedback here. I've got code queued up for NICs but don't want to base those changes on this codeset and any feedback I get. -- Darryl L. Pierce, Sr. Software Engineer Red Hat, Inc. - http://www.redhat.com/ oVirt - 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 Tue Jul 8 12:00:17 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Tue, 8 Jul 2008 08:00:17 -0400 Subject: [Ovirt-devel] Re: Using log rotation to minimize writing to the managed node filesystem. In-Reply-To: <1215031581-27210-1-git-send-email-dpierce@redhat.com> References: <1215031581-27210-1-git-send-email-dpierce@redhat.com> Message-ID: <20080708120015.GE14152@redhat.com> +++ Darryl L. Pierce [02/07/08 16:46 -0400]: >From: Darryl Pierce Can I get some feedback on this patch? -- Darryl L. Pierce, Sr. Software Engineer Red Hat, Inc. - http://www.redhat.com/ oVirt - 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 apevec at redhat.com Tue Jul 8 12:42:36 2008 From: apevec at redhat.com (Alan Pevec) Date: Tue, 08 Jul 2008 14:42:36 +0200 Subject: [Ovirt-devel] [PATCH] Using log rotation to minimize writing to the managed node filesystem. In-Reply-To: <1215031581-27210-1-git-send-email-dpierce@redhat.com> References: <1215031581-27210-1-git-send-email-dpierce@redhat.com> Message-ID: <487360BC.30504@redhat.com> ACK From pmyers at redhat.com Tue Jul 8 12:46:15 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Tue, 08 Jul 2008 08:46:15 -0400 Subject: [Ovirt-devel] [PATCH] Using log rotation to minimize writing to the managed node filesystem. In-Reply-To: <1215031581-27210-1-git-send-email-dpierce@redhat.com> References: <1215031581-27210-1-git-send-email-dpierce@redhat.com> Message-ID: <48736197.6040208@redhat.com> Darryl L. Pierce wrote: > From: Darryl Pierce > > > Signed-off-by: Darryl L. Pierce > --- > ovirt-host-creator/common-pkgs.ks | 1 + > ovirt-managed-node/ovirt-managed-node.spec | 10 ++++++++++ > ovirt-managed-node/src/logrotate/ovirt-logrotate | 10 ++++++++++ > .../src/logrotate/ovirt-logrotate.conf | 11 +++++++++++ > 4 files changed, 32 insertions(+), 0 deletions(-) > create mode 100755 ovirt-managed-node/src/logrotate/ovirt-logrotate > create mode 100644 ovirt-managed-node/src/logrotate/ovirt-logrotate.conf > > diff --git a/ovirt-host-creator/common-pkgs.ks b/ovirt-host-creator/common-pkgs.ks > index 8d0ba70..2d1ad6e 100644 > --- a/ovirt-host-creator/common-pkgs.ks > +++ b/ovirt-host-creator/common-pkgs.ks > @@ -26,6 +26,7 @@ augeas > nc > bind-utils > syslinux > +cronie > hal > ovirt-managed-node > -policycoreutils > diff --git a/ovirt-managed-node/ovirt-managed-node.spec b/ovirt-managed-node/ovirt-managed-node.spec > index bd807b1..fa943f5 100644 > --- a/ovirt-managed-node/ovirt-managed-node.spec > +++ b/ovirt-managed-node/ovirt-managed-node.spec > @@ -36,6 +36,8 @@ make > %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/chkconfig.d > %{__install} -d -m0755 %{buildroot}%{_initrddir} > %{__install} -d -m0755 %{buildroot}%{app_root} > +%{__install} -d -m0755 %{buildroot}%{_sysconfdir}/cron.hourly > +%{__install} -d -m0755 %{buildroot}%{_sysconfdir}/logrotate.d > > %{__install} -p -m0755 scripts/ovirt-awake %{buildroot}%{_sbindir} > %{__install} -p -m0755 ovirt-identify-node %{buildroot}%{_sbindir} > @@ -52,6 +54,9 @@ make > > %{__install} -p -m0755 scripts/ovirt-setup %{buildroot}%{app_root} > > +%{__install} -p -m0644 logrotate/ovirt-logrotate %{buildroot}%{_sysconfdir}/cron.hourly > +%{__install} -p -m0644 logrotate/ovirt-logrotate.conf %{buildroot}%{_sysconfdir}/logrotate.d > + > %clean > %{__rm} -rf %{buildroot} > > @@ -81,6 +86,8 @@ fi > %{_initrddir}/ovirt-post > %{_sysconfdir}/kvm-ifup > %{_sysconfdir}/dhclient-exit-hooks > +%config %{_sysconfdir}/logrotate.d/ovirt-logrotate.conf > +%config %{_sysconfdir}/cron.hourly/ovirt-logrotate > %{app_root}/ovirt-setup > %defattr(-,root,root,0644) > %{_initrddir}/ovirt-functions > @@ -89,5 +96,8 @@ fi > %doc README NEWS AUTHOR ChangeLog > > %changelog > +* Wed Jul 02 2008 Darryl Pierce - 0.92 0.2 > +- Added log rotation to limit file system writes. > + > * Mon Jun 30 2008 Perry Myers - 0.92 0.1 > - Add in sections of kickstart post, general cleanup > diff --git a/ovirt-managed-node/src/logrotate/ovirt-logrotate b/ovirt-managed-node/src/logrotate/ovirt-logrotate > new file mode 100755 > index 0000000..f0a2dde > --- /dev/null > +++ b/ovirt-managed-node/src/logrotate/ovirt-logrotate > @@ -0,0 +1,10 @@ > +#!/bin/sh > + > +/usr/sbin/logrotate /etc/logrotate.d/ovirt-logrotate.conf > + > +EXITVALUE=$? > +if [ $EXITVALUE != 0 ]; then > + /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]" > +fi > +exit 0 > + > diff --git a/ovirt-managed-node/src/logrotate/ovirt-logrotate.conf b/ovirt-managed-node/src/logrotate/ovirt-logrotate.conf > new file mode 100644 > index 0000000..96fb87c > --- /dev/null > +++ b/ovirt-managed-node/src/logrotate/ovirt-logrotate.conf > @@ -0,0 +1,11 @@ > +/var/log/*.log { > + rotate 0 > + missingok > + size=10k > +} > + > +/var/log/messages { > + rotate 0 > + missingok > + size=10k > +} Sorry for the delay. ACK 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 Tue Jul 8 13:16:07 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Tue, 8 Jul 2008 09:16:07 -0400 Subject: [Ovirt-devel] [PATCH] ovirt-identify-node now submits all extended CPU details. Message-ID: <1215522967-13363-1-git-send-email-dpierce@redhat.com> From: Darryl Pierce Signed-off-by: Darryl Pierce --- ovirt-managed-node/src/ovirt-identify-node.c | 420 +++++++++++++++----- ovirt-managed-node/src/ovirt-identify-node.h | 56 +++ wui/src/app/models/cpu.rb | 24 ++ wui/src/app/models/host.rb | 21 +- wui/src/db/migrate/002_create_hosts.rb | 2 - wui/src/db/migrate/010_create_cpus.rb | 26 ++ wui/src/dutils/active_record_env.rb | 5 +- wui/src/host-browser/host-browser.rb | 103 +++++- wui/src/host-browser/test-host-browser-awake.rb | 94 +++++ wui/src/host-browser/test-host-browser-awaken.rb | 94 ----- wui/src/host-browser/test-host-browser-identify.rb | 345 ++++++++++------ wui/src/test/fixtures/cpus.yml | 21 + wui/src/test/fixtures/hosts.yml | 24 +- wui/src/test/unit/cpu_test.rb | 8 + 14 files changed, 874 insertions(+), 369 deletions(-) create mode 100644 ovirt-managed-node/src/ovirt-identify-node.h create mode 100644 wui/src/app/models/cpu.rb create mode 100644 wui/src/db/migrate/010_create_cpus.rb create mode 100755 wui/src/host-browser/test-host-browser-awake.rb delete mode 100755 wui/src/host-browser/test-host-browser-awaken.rb create mode 100644 wui/src/test/fixtures/cpus.yml create mode 100644 wui/src/test/unit/cpu_test.rb diff --git a/ovirt-managed-node/src/ovirt-identify-node.c b/ovirt-managed-node/src/ovirt-identify-node.c index 819f700..f114d81 100644 --- a/ovirt-managed-node/src/ovirt-identify-node.c +++ b/ovirt-managed-node/src/ovirt-identify-node.c @@ -31,31 +31,7 @@ #include #include -int config(int argc,char** argv); -void usage(void); - -int start_conversation(void); -int send_details(void); -int end_conversation(void); - -int send_text(char* text); -int get_text(const char *const expected); -int create_connection(void); - -int debug = 1; -int verbose = 1; -int testing = 0; - -#define BUFFER_LENGTH 128 - -char arch[BUFFER_LENGTH]; -char uuid[VIR_UUID_BUFLEN]; -char memsize[BUFFER_LENGTH]; -char numcpus[BUFFER_LENGTH]; -char cpuspeed[BUFFER_LENGTH]; -char *hostname; -int hostport = -1; -int socketfd; +#include "ovirt-identify-node.h" int main(int argc,char** argv) { @@ -63,9 +39,11 @@ int main(int argc,char** argv) virConnectPtr connection; virNodeInfo info; + fprintf(stdout,"Sending managed node details to server.\n"); + if(!config(argc,argv)) { - fprintf(stdout,"Connecting to libvirt.\n"); + if(verbose) fprintf(stdout,"Connecting to libvirt.\n"); connection = virConnectOpenReadOnly(testing ? "test:///default" : NULL); @@ -73,42 +51,68 @@ int main(int argc,char** argv) if(connection) { - if(debug) fprintf(stdout,"Getting hostname: %s\n", uuid); + if(verbose) fprintf(stdout,"Getting hostname: %s\n", uuid); if(!strlen(uuid)) gethostname(uuid,sizeof uuid); - if(debug) fprintf(stdout,"Retrieving node information.\n"); + if(verbose) fprintf(stdout,"Retrieving node information.\n"); if(!virNodeGetInfo(connection,&info)) { snprintf(arch, BUFFER_LENGTH, "%s", info.model); snprintf(memsize, BUFFER_LENGTH, "%ld", info.memory); - snprintf(numcpus, BUFFER_LENGTH, "%d", info.cpus); - snprintf(cpuspeed, BUFFER_LENGTH, "%d", info.mhz); - if(debug) + cpu_info = NULL; + + if(!get_cpu_info()) { - fprintf(stdout,"Node Info:\n"); - fprintf(stdout," UUID: %s\n", uuid); - fprintf(stdout," Arch: %s\n", arch); - fprintf(stdout," Memory: %s\n", memsize); - fprintf(stdout," # CPUs: %s\n", numcpus); - fprintf(stdout,"CPU Speed: %s\n", cpuspeed); + if(verbose) fprintf(stdout, "Getting CPU info.\n"); + + if(debug) + { + fprintf(stdout,"Node Info:\n"); + fprintf(stdout," UUID: %s\n", uuid); + fprintf(stdout," Arch: %s\n", arch); + fprintf(stdout," Memory: %s\n", memsize); + + t_cpu_info* current = cpu_info; + while(current != NULL) + { + fprintf(stdout,"\n"); + fprintf(stdout," CPU Number: %s\n", current->cpu_num); + fprintf(stdout," Core Number: %s\n", current->core_num); + fprintf(stdout,"Number of Cores: %s\n", current->number_of_cores); + fprintf(stdout," Vendor: %s\n", current->vendor); + fprintf(stdout," Model: %s\n", current->model); + fprintf(stdout," Family: %s\n", current->family); + fprintf(stdout," CPUID Level: %s\n", current->cpuid_level); + fprintf(stdout," CPU Speed: %s\n", current->speed); + fprintf(stdout," Cache Size: %s\n", current->cache); + fprintf(stdout," CPU Flags: %s\n", current->flags); + + current = current->next; + } + } + + if(verbose) fprintf(stdout, "Retrieved node information.\n"); + + if(!start_conversation() && !send_details() && !end_conversation()) + { + fprintf(stdout,"Finished!\n"); + result = 0; + } } - - if(debug) fprintf(stdout, "Retrieved node information.\n"); - - if(!start_conversation() && !send_details() && !end_conversation()) + else { - result = 0; + if(verbose) fprintf(stderr,"Failed to get CPU info.\n"); } } else { - if(debug) fprintf(stderr,"Failed to get node info.\n"); + if(verbose) fprintf(stderr,"Failed to get node info.\n"); } } else { - if(debug) fprintf(stderr,"Could not connect to libvirt.\n"); + if(verbose) fprintf(stderr,"Could not connect to libvirt.\n"); } } else @@ -181,35 +185,35 @@ int start_conversation(void) { if(debug || verbose) fprintf(stdout,"Connected.\n"); - if (!get_text("HELLO?\n")) + if (!get_text("HELLO?")) { - if(debug) fprintf(stdout,"Checking for handshake.\n"); + if(verbose) fprintf(stdout,"Checking for handshake.\n"); - if(!send_text("HELLO!\n")) + if(!send_text("HELLO!")) { - if(debug) fprintf(stdout,"Handshake received. Starting conversation.\n"); + if(verbose) fprintf(stdout,"Handshake received. Starting conversation.\n"); - if(!get_text("MODE?\n")) + if(!get_text("MODE?")) { - if(debug) fprintf(stdout,"Shifting to IDENTIFY mode.\n"); + if(verbose) fprintf(stdout,"Shifting to IDENTIFY mode.\n"); - if(!send_text("IDENTIFY\n")) result = 0; + if(!send_text("IDENTIFY")) result = 0; } else { - if(debug) fprintf(stderr,"Was not asked for a mode.\n"); + if(verbose) fprintf(stderr,"Was not asked for a mode.\n"); } } } else { - if(debug) fprintf(stderr,"Did not receive a proper handshake.\n"); + if(verbose) fprintf(stderr,"Did not receive a proper handshake.\n"); } } else { - if(debug) fprintf(stderr,"Did not get a connection.\n"); + if(verbose) fprintf(stderr,"Did not get a connection.\n"); } if(debug) fprintf(stdout,"start_conversation: result=%d\n", result); @@ -223,19 +227,15 @@ int send_value(char* label,char* value) int result = 1; char expected[BUFFER_LENGTH]; - snprintf(buffer,BUFFER_LENGTH,"%s=%s\n", label, value); + snprintf(buffer,BUFFER_LENGTH,"%s=%s", label, value); if(!send_text(buffer)) { - snprintf(expected, BUFFER_LENGTH, "ACK %s\n", label); + snprintf(expected, BUFFER_LENGTH, "ACK %s", label); - if(debug) fprintf(stdout,"Expecting \"%s\"\n", expected); - - if (!get_text(expected)) - { - result = 0; - } + if(verbose) fprintf(stdout,"Expecting \"%s\"\n", expected); + result = get_text(expected); } return result; @@ -245,40 +245,238 @@ int send_details(void) { int result = 1; - fprintf(stdout,"Sending node details.\n"); + if(verbose) fprintf(stdout,"Sending node details.\n"); - if (!get_text("INFO?\n")) + if (!get_text("INFO?")) { if((!send_value("ARCH", arch)) && (!send_value("UUID", uuid)) && - (!send_value("NUMCPUS", numcpus)) && - (!send_value("CPUSPEED", cpuspeed)) && - (!send_value("MEMSIZE", memsize))) + (!send_value("MEMSIZE", memsize)) && + (!send_cpu_details())) { - if(!send_text("ENDINFO\n")) result = 0; + if(!send_text("ENDINFO")) result = 0; } } else { - if(debug) fprintf(stdout,"Was not interrogated for hardware info.\n"); + if(verbose) fprintf(stdout,"Was not interrogated for hardware info.\n"); } return result; } +int send_cpu_details(void) +{ + int result = 1; + t_cpu_info* current = cpu_info; + + while(current != NULL) + { + send_text("CPU"); + + if(!(get_text("CPUINFO?")) && + (!send_value("CPUNUM",current->cpu_num)) && + (!send_value("CORENUM",current->core_num)) && + (!send_value("NUMCORES",current->number_of_cores)) && + (!send_value("VENDOR",current->vendor)) && + (!send_value("MODEL",current->model)) && + (!send_value("FAMILY",current->family)) && + (!send_value("CPUIDLVL",current->cpuid_level)) && + (!send_value("SPEED",current->speed)) && + (!send_value("CACHE", current->cache)) && + (!send_value("FLAGS", current->flags))) + { + send_text("ENDCPU"); + result = get_text("ACK CPU"); + } + + current = current->next; + } + + + return result; +} + int end_conversation(void) { int result = 0; - fprintf(stdout,"Ending conversation.\n"); + if(debug || verbose) fprintf(stdout,"Ending conversation.\n"); - send_text("ENDINFO\n"); + send_text("ENDINFO"); close(socketfd); return result; } +void get_label_and_value(char* text, + char* label, size_t label_length, + char* value, size_t value_length) +{ + int offset = 0; + int which = 0; /* 0 = label, 1 = value */ + char* current = text; + + /* iterate through the text supplied and find where the + * label ends with a colon, then copy that into the supplied + * label buffer and trim any trailing spaces + */ + + while(current != NULL && *current != '\0') + { + /* if we're on the separator, then switch modes and reset + * the offset indicator, otherwise just process the character + */ + if(which == 0 && *current == ':') + { + which = 1; + offset = 0; + } + else + { + char* buffer = (which == 0 ? label : value); + int length = (which == 0 ? label_length : value_length); + + /* only copy if we're past the first character and it's not + * a space + */ + if((offset > 0 || (*current != 9 && *current != ' ')) && offset < (length - 1)) + { + buffer[offset++] = *current; + buffer[offset] = 0; + } + } + + current++; + } + + /* now trim all trailing spaces from the values */ + while(label[strlen(label) - 1 ] == 9) + label[strlen(label) - 1] = 0; + while(value[strlen(value) - 1] == 9) + value[strlen(value) - 1] = 0; +} + +int get_cpu_info(void) +{ + int result = 1; + FILE* inputfd; + t_cpu_info* current = NULL; + + if(( inputfd = fopen("/proc/cpuinfo","rb")) != NULL) + { + if(verbose) fprintf(stdout,"Parsing CPU information\n"); + do + { + char buffer[255]; + char label[BUFFER_LENGTH]; + char value[BUFFER_LENGTH]; + + fgets(buffer, 255, inputfd); + if(strlen(buffer) > 0) buffer[strlen(buffer) - 1] = '\0'; + + get_label_and_value(buffer, + label,BUFFER_LENGTH, + value,BUFFER_LENGTH); + + if(debug) + fprintf(stdout,"label=\"%s\", value=\"%s\"\n", label, value); + + if(strlen(label)) + { + if(!strcmp(label,"processor")) + { + if(debug || verbose) + fprintf(stdout,"Starting new CPU\n"); + + t_cpu_info* last = current; + + current = create_cpu_info(); + if(last != NULL) + { + last->next = current; + } + else + { + cpu_info = current; + } + + COPY_VALUE_TO_BUFFER(value,current->cpu_num,BUFFER_LENGTH); + } + else + if(!strcmp(label,"core id")) + { + COPY_VALUE_TO_BUFFER(value,current->core_num,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cpu cores")) + { + COPY_VALUE_TO_BUFFER(value,current->number_of_cores,BUFFER_LENGTH); + } + else + if(!strcmp(label,"vendor_id")) + { + COPY_VALUE_TO_BUFFER(value,current->vendor,BUFFER_LENGTH); + } + else + if(!strcmp(label,"model")) + { + COPY_VALUE_TO_BUFFER(value,current->model,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cpu family")) + { + COPY_VALUE_TO_BUFFER(value,current->family,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cpuid level")) + { + COPY_VALUE_TO_BUFFER(value,current->cpuid_level,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cpu MHz")) + { + COPY_VALUE_TO_BUFFER(value,current->speed,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cache size")) + { + COPY_VALUE_TO_BUFFER(value,current->cache,BUFFER_LENGTH); + } + else + if(!strcmp(label,"flags")) + { + COPY_VALUE_TO_BUFFER(value,current->flags,BUFFER_LENGTH); + } + } + + } while(!feof(inputfd)); + + fclose(inputfd); + + result = 0; + } + else + { + if(verbose) fprintf(stderr,"Unable to open /proc/cpuinfo\n"); + } + + return result; +} + +t_cpu_info* create_cpu_info(void) +{ + t_cpu_info* result = calloc(1,sizeof(t_cpu_info)); + bzero(result,sizeof(t_cpu_info)); + + strcpy(result->core_num,"0"); + strcpy(result->number_of_cores,"1"); + + + return result; +} + ssize_t safewrite(int fd, const void *buf, size_t count) { size_t nwritten = 0; @@ -303,9 +501,10 @@ int send_text(char* text) int result = 1; int sent; - if(debug || verbose) fprintf(stdout,"\"%s\" -> %s:%d\n", text, hostname, hostport); + if(verbose) fprintf(stdout,"Sending: \"%s\"\n", text); sent = safewrite(socketfd, text, strlen(text)); + sent += safewrite(socketfd, "\n", 1); if(sent >= 0) { @@ -317,35 +516,46 @@ int send_text(char* text) return result; } -int saferead(int fd, void *buf, size_t count) +int saferead(int fd, char *buf, size_t count) { ssize_t bytes,offset; int len_left; + int done = 0; if(debug) fprintf(stdout,"Begin saferead(%d, %p, %ld)\n", fd, buf, count); offset = 0; len_left = count; - while(len_left > 0) { - bytes = read(fd, buf+offset, len_left); - fprintf(stderr,"After read, bytes is %ld\n",bytes); - if (bytes < 0) { - if (errno == EINTR) { - continue; - } - else { - offset = -1; - break; - } - } - else if (bytes == 0) { - // reached EOF; break out of here - break; - } - - offset += bytes; - len_left -= bytes; + + while(!done) + { + if(debug) fprintf(stdout,"Before read(%ld,%p,%ld)\n",fd,buf+offset,len_left); + + bytes = read(fd, buf+offset, len_left); + + if(debug) fprintf(stdout,"After read: bytes=%ld\n", bytes); + + if(bytes == 0) + { + done = 1; + } + else if(bytes > 0) + { + offset += bytes; + len_left -= bytes; + done = 1; + } + else if(errno == EINTR) + { + continue; + } + else + { + done = 1; + } + + if(debug) fprintf(stdout,"End of decision loop: offset=%ld, len_left=%dl, done=%d\n",offset, len_left, done); } return offset; @@ -353,22 +563,22 @@ int saferead(int fd, void *buf, size_t count) int get_text(const char *const expected) { + int result = 1; int received; char buffer[BUFFER_LENGTH]; + bzero(buffer,BUFFER_LENGTH); - if(debug) fprintf(stdout, "Looking to receive %s\n", expected); + if(verbose) fprintf(stdout, "Looking to receive %s\n", expected); - received = saferead(socketfd, buffer, strlen(expected)); + received = saferead(socketfd, buffer, BUFFER_LENGTH); buffer[received - 1] = 0; - if(debug) fprintf(stdout,"Received \"%s\": size=%d (trimmed ending carriage return)\n", buffer, received); + if(verbose) fprintf(stdout,"Received \"%s\": size=%d (trimmed ending carriage return)\n", buffer, received); - if (strncmp(expected, buffer, strlen(expected)) != 0) { - return 0; - } + result = strcmp(expected,buffer); - return 1; + return result; } int create_connection(void) @@ -379,7 +589,7 @@ int create_connection(void) char port[6]; struct addrinfo* rptr; - if(debug) fprintf(stdout,"Creating the socket connection.\n"); + if(verbose) fprintf(stdout,"Creating the socket connection.\n"); memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; @@ -387,13 +597,13 @@ int create_connection(void) hints.ai_flags = 0; hints.ai_protocol = 0; - if(debug) fprintf(stdout,"Searching for host candidates.\n"); + if(verbose) fprintf(stdout,"Searching for host candidates.\n"); snprintf(port, 6, "%d", hostport); if(!getaddrinfo(hostname, port, &hints, &results)) { - if(debug) fprintf(stdout,"Got address information. Searching for a proper entry.\n"); + if(verbose) fprintf(stdout,"Got address information. Searching for a proper entry.\n"); for(rptr = results; rptr != NULL; rptr = rptr->ai_next) { @@ -416,13 +626,13 @@ int create_connection(void) } // invalid connection, so close it - if(debug) fprintf(stdout, "Invalid connection.\n"); + if(verbose) fprintf(stdout, "Invalid connection.\n"); close(socketfd); } if(rptr == NULL) { - if(debug) fprintf(stdout,"Unable to connect to server %s:%d\n", hostname, hostport); + if(verbose) fprintf(stdout,"Unable to connect to server %s:%d\n", hostname, hostport); } else { @@ -434,7 +644,7 @@ int create_connection(void) } else { - if(debug) fprintf(stderr,"No hosts found. Exiting...\n"); + if(verbose) fprintf(stderr,"No hosts found. Exiting...\n"); } if(debug) fprintf(stdout, "create_connection: result=%d\n", result); diff --git a/ovirt-managed-node/src/ovirt-identify-node.h b/ovirt-managed-node/src/ovirt-identify-node.h new file mode 100644 index 0000000..1cb1526 --- /dev/null +++ b/ovirt-managed-node/src/ovirt-identify-node.h @@ -0,0 +1,56 @@ +#ifndef __OVIRT_IDENTIFY_NODE_H +#define __OVIRT_IDENTIFY_NODE_H + +#define BUFFER_LENGTH 128 +#define CPU_FLAGS_BUFFER_LENGTH 256 + +typedef struct _cpu_info { + char cpu_num[BUFFER_LENGTH]; + char core_num[BUFFER_LENGTH]; + char number_of_cores[BUFFER_LENGTH]; + char vendor[BUFFER_LENGTH]; + char model[BUFFER_LENGTH]; + char family[BUFFER_LENGTH]; + char cpuid_level[BUFFER_LENGTH]; + char speed[BUFFER_LENGTH]; + char cache[BUFFER_LENGTH]; + char flags[CPU_FLAGS_BUFFER_LENGTH]; + struct _cpu_info* next; +} t_cpu_info; + +#define COPY_VALUE_TO_BUFFER(value,buffer,length) \ + snprintf(buffer,length,"%s",value) + +int config(int argc,char** argv); +void usage(void); + +int start_conversation(void); +int send_details(void); +int send_cpu_details(void); +int end_conversation(void); + +void get_label_and_value(char* text, + char* label,size_t label_length, + char* value,size_t value_length); +t_cpu_info* create_cpu_info(void); +int get_cpu_info(void); + +int send_text(char* text); +int get_text(const char *const expected); +int create_connection(void); + +int debug = 0; +int verbose = 0; +int testing = 0; + +char arch[BUFFER_LENGTH]; +char uuid[VIR_UUID_BUFLEN]; +char memsize[BUFFER_LENGTH]; +char numcpus[BUFFER_LENGTH]; +char cpuspeed[BUFFER_LENGTH]; +char *hostname; +int hostport = -1; +int socketfd; +t_cpu_info* cpu_info; + +#endif diff --git a/wui/src/app/models/cpu.rb b/wui/src/app/models/cpu.rb new file mode 100644 index 0000000..1a7d3cf --- /dev/null +++ b/wui/src/app/models/cpu.rb @@ -0,0 +1,24 @@ +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Darryl L. Pierce +# +# 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. + +# +Cpu+ represents the details for a single CPU on a managed node. +# +class Cpu < ActiveRecord::Base + belongs_to :host +end diff --git a/wui/src/app/models/host.rb b/wui/src/app/models/host.rb index 6917226..3413370 100644 --- a/wui/src/app/models/host.rb +++ b/wui/src/app/models/host.rb @@ -1,4 +1,4 @@ -# +# # Copyright (C) 2008 Red Hat, Inc. # Written by Scott Seago # @@ -21,8 +21,11 @@ require 'util/ovirt' class Host < ActiveRecord::Base belongs_to :hardware_pool + + has_many :cpus has_many :nics, :dependent => :destroy has_many :vms, :dependent => :nullify do + def consuming_resources find(:all, :conditions=>{:state=>Vm::RUNNING_STATES}) end @@ -32,7 +35,7 @@ class Host < ActiveRecord::Base find(:all, :conditions=>{:state=>Task::STATE_QUEUED}) end def pending_clear_tasks - find(:all, :conditions=>{:state=>Task::WORKING_STATES, + find(:all, :conditions=>{:state=>Task::WORKING_STATES, :action=>HostTask::ACTION_CLEAR_VMS}) end end @@ -42,12 +45,18 @@ class Host < ActiveRecord::Base STATE_UNAVAILABLE = "unavailable" STATE_AVAILABLE = "available" STATES = [STATE_UNAVAILABLE, STATE_AVAILABLE] + + KVM_HYPERVISOR_TYPE = "KVM" + HYPERVISOR_TYPES = [KVM_HYPERVISOR_TYPE] + def memory_in_mb kb_to_mb(memory) end + def memory_in_mb=(mem) self[:memory]=(mb_to_kb(mem)) end + def status_str "#{state} (#{disabled? ? 'disabled':'enabled'})" end @@ -61,4 +70,12 @@ class Host < ActiveRecord::Base not(disabled? and vms.consuming_resources.empty?) and tasks.pending_clear_tasks.empty? end + + def num_cpus + return cpu_details.size + end + + def cpu_speed + "FIX ME!" + end end diff --git a/wui/src/db/migrate/002_create_hosts.rb b/wui/src/db/migrate/002_create_hosts.rb index cef7996..442e674 100644 --- a/wui/src/db/migrate/002_create_hosts.rb +++ b/wui/src/db/migrate/002_create_hosts.rb @@ -23,8 +23,6 @@ class CreateHosts < ActiveRecord::Migration t.string :uuid t.string :hypervisor_type t.string :hostname - t.integer :num_cpus - t.integer :cpu_speed t.string :arch t.integer :memory t.integer :is_disabled diff --git a/wui/src/db/migrate/010_create_cpus.rb b/wui/src/db/migrate/010_create_cpus.rb new file mode 100644 index 0000000..381bf19 --- /dev/null +++ b/wui/src/db/migrate/010_create_cpus.rb @@ -0,0 +1,26 @@ +class CreateCpus < ActiveRecord::Migration + def self.up + create_table :cpus do |t| + t.integer :host_id + t.integer :cpu_number + t.integer :core_number + t.integer :number_of_cores + t.string :vendor, :limit => 128 + t.integer :model + t.integer :family + t.integer :cpuid_level + t.float :speed + t.string :cache + t.string :flags + + t.timestamps + end + + execute "alter table cpus add constraint fk_host_cpus + foreign key (host_id) references hosts(id)" + end + + def self.down + drop_table :cpus + end +end diff --git a/wui/src/dutils/active_record_env.rb b/wui/src/dutils/active_record_env.rb index b0aef04..72feb89 100644 --- a/wui/src/dutils/active_record_env.rb +++ b/wui/src/dutils/active_record_env.rb @@ -1,5 +1,5 @@ #!/usr/bin/ruby -# +# # Copyright (C) 2008 Red Hat, Inc. # Written by Scott Seago # @@ -23,7 +23,7 @@ $: << File.join(File.dirname(__FILE__), "../vendor/plugins/betternestedset/lib") require 'rubygems' -gem 'activeldap' +gem 'activeldap' require 'active_ldap' require 'active_support' @@ -58,6 +58,7 @@ require 'models/quota.rb' require 'models/hardware_pool.rb' require 'models/host.rb' +require 'models/cpu.rb' require 'models/nic.rb' require 'models/vm_resource_pool.rb' diff --git a/wui/src/host-browser/host-browser.rb b/wui/src/host-browser/host-browser.rb index 691e4ed..e66493d 100755 --- a/wui/src/host-browser/host-browser.rb +++ b/wui/src/host-browser/host-browser.rb @@ -19,6 +19,7 @@ # also available at http://www.gnu.org/copyleft/gpl.html. $: << File.join(File.dirname(__FILE__), "../dutils") +$: << File.join(File.dirname(__FILE__), "../") require 'rubygems' require 'libvirt' @@ -73,16 +74,61 @@ class HostBrowser # def get_remote_info puts "#{@log_prefix} Begin remote info collection" unless defined?(TESTING) - result = {} + result = Hash.new result['HOSTNAME'] = @session.peeraddr[2] result['IPADDR'] = @session.peeraddr[3] + @session.write("INFO?\n") loop do info = @session.readline.chomp + puts "Received info='#{info}'" + break if info == "ENDINFO" + # if we got the start of a CPU details marker, then process it + if info == "CPU" + cpu = get_cpu_info + cpu_info = result['CPUINFO'] + + if(cpu_info == nil) + cpu_info = Array.new + result['CPUINFO'] = cpu_info + end + + cpu_info << cpu + + else + + raise Exception.new("ERRINFO! Excepted key=value : #{info}\n") unless info =~ /[\w]+[\s]*=[\w]/ + + key, value = info.split("=") + + puts "#{@log_prefix} ::Received - #{key}:#{value}" unless defined?(TESTING) + result[key] = value + + @session.write("ACK #{key}\n") + end + end + + return result + end + + # Extracts CPU details from the managed node. + # + def get_cpu_info + puts "Begin receiving CPU details" + + result = Hash.new + + @session.write("CPUINFO?\n") + + loop do + info = @session.readline.chomp + + break if info == "ENDCPU" + raise Exception.new("ERRINFO! Excepted key=value : #{info}\n") unless info =~ /[\w]+[\s]*=[\w]/ key, value = info.split("=") @@ -93,6 +139,8 @@ class HostBrowser @session.write("ACK #{key}\n") end + @session.write("ACK CPU\n"); + return result end @@ -100,10 +148,24 @@ class HostBrowser # def write_host_info(host_info) ensure_present(host_info,'HOSTNAME') - ensure_present(host_info,'NUMCPUS') - ensure_present(host_info,'CPUSPEED') ensure_present(host_info,'ARCH') ensure_present(host_info,'MEMSIZE') + ensure_present(host_info,'CPUINFO') + + cpu_info = host_info['CPUINFO'] + + cpu_info.each do |cpu| + ensure_present(cpu,'CPUNUM') + ensure_present(cpu,'CORENUM') + ensure_present(cpu,'NUMCORES') + ensure_present(cpu,'VENDOR') + ensure_present(cpu,'MODEL') + ensure_present(cpu,'FAMILY') + ensure_present(cpu,'CPUIDLVL') + ensure_present(cpu,'SPEED') + ensure_present(cpu,'CACHE') + ensure_present(cpu,'FLAGS') + end puts "Searching for existing host record..." unless defined?(TESTING) host = Host.find(:first, :conditions => ["hostname = ?", host_info['HOSTNAME']]) @@ -112,31 +174,49 @@ class HostBrowser begin puts "Creating a new record for #{host_info['HOSTNAME']}..." unless defined?(TESTING) - Host.new( + host = Host.create( "uuid" => host_info['UUID'], "hostname" => host_info['HOSTNAME'], "hypervisor_type" => host_info['HYPERVISOR_TYPE'], - "num_cpus" => host_info['NUMCPUS'], - "cpu_speed" => host_info['CPUSPEED'], "arch" => host_info['ARCH'], "memory_in_mb" => host_info['MEMSIZE'], "is_disabled" => 0, "hardware_pool" => HardwarePool.get_default_pool, # Let host-status mark it available when it # successfully connects to it via libvirt. - "state" => Host::STATE_UNAVAILABLE).save + "state" => Host::STATE_UNAVAILABLE) + host.save! rescue Exception => error puts "Error while creating record: #{error.message}" unless defined?(TESTING) end else host.uuid = host_info['UUID'] host.hostname = host_info['HOSTNAME'] - host.num_cpus = host_info['NUMCPUS'] - host.cpu_speed = host_info['CPUSPEED'] host.arch = host_info['ARCH'] host.memory_in_mb = host_info['MEMSIZE'] end + # delete an existing CPUs and create new ones based on the data + puts "Deleting any existing CPUs" + Cpu.delete_all(['host_id = ?', host.id]) + + puts "Saving new CPU records" + cpu_info.collect do |cpu| + detail = Cpu.new( + "cpu_number" => cpu['CPUNUM'], + "core_number" => cpu['CORENUM]'], + "number_of_cores" => cpu['NUMCORES'], + "vendor" => cpu['VENDOR'], + "model" => cpu['MODEL'], + "family" => cpu['FAMILY'], + "cpuid_level" => cpu['CPUIDLVL'], + "speed" => cpu['SPEED'], + "cache" => cpu['CACHE'], + "flags" => cpu['FLAGS']) + + host.cpus << detail + end + return host end @@ -181,8 +261,8 @@ class HostBrowser # Private method to ensure that a required field is present. # - def ensure_present(host_info,key) - raise Exception.new("ERROR! Missing '#{key}'...") if host_info[key] == nil + def ensure_present(info,key) + raise Exception.new("ERROR! Missing '#{key}'...") if info[key] == nil end # Executes an external program to support the keytab function. @@ -226,7 +306,6 @@ def entry_point(server) end unless defined?(TESTING) - # The main entry point. # unless ARGV[0] == "-n" diff --git a/wui/src/host-browser/test-host-browser-awake.rb b/wui/src/host-browser/test-host-browser-awake.rb new file mode 100755 index 0000000..02e9146 --- /dev/null +++ b/wui/src/host-browser/test-host-browser-awake.rb @@ -0,0 +1,94 @@ +#!/usr/bin/ruby -Wall +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Darryl L. Pierce +# +# 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 File.dirname(__FILE__) + '/../test/test_helper' +require 'test/unit' +require 'flexmock/test_unit' + +TESTING=true + +require 'host-browser' + +# +TestHostBrowserAwaken+ +class TestHostBrowserAwaken < Test::Unit::TestCase + + def setup + @session = flexmock('session') + @session.should_receive(:peeraddr).at_least.once.returns { [nil,nil,nil,"192.168.2.255"] } + + @krb5 = flexmock('krb5') + + @browser = HostBrowser.new(@session) + @browser.logfile = './unit-test.log' + @browser.keytab_dir = '/var/temp/' + end + + # Ensures that the server raises an exception when it receives an + # improper handshake response. + # + def test_begin_conversation_with_improper_response_to_greeting + @session.should_receive(:write).with("HELLO?\n").once().returns { |greeting| greeting.length } + @session.should_receive(:readline).once().returns { "SUP?" } + + assert_raise(Exception) { @browser.begin_conversation } + end + + # Ensures the server accepts a proper response from the remote system. + # + def test_begin_conversation + @session.should_receive(:write).with("HELLO?\n").once().returns { |greeting| greeting.length } + @session.should_receive(:readline).once().returns { "HELLO!\n" } + + assert_nothing_raised(Exception) { @browser.begin_conversation } + end + + # Ensures that the server is satisfied if the remote system is + # making a wakeup call. + # + def test_get_mode_with_awaken_request + @session.should_receive(:write).with("MODE?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "AWAKEN\n" } + + result = @browser.get_mode() + + assert_equal "AWAKEN", result, "method did not return the right value" + end + + # Ensures the host browser generates a keytab as expected. + # + def test_create_keytab + @krb5.should_receive(:get_default_realm).once().returns { "ovirt-test-realm" } + servername = `hostname -f`.chomp + @session.should_receive(:write).with("KTAB http://#{servername}/ipa/config/127.0.0.1-libvirt.tab\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ACK\n" } + + assert_nothing_raised(Exception) { @browser.create_keytab('localhost','127.0.0.1', at krb5) } + end + + # Ensures that, if a keytab is present and a key version number available, + # the server ends the conversation by returning the key version number. + # + def test_end_conversation + @session.should_receive(:write).with("BYE\n").once().returns { |request| request.length } + + assert_nothing_raised(Exception) { @browser.end_conversation } + end + +end diff --git a/wui/src/host-browser/test-host-browser-awaken.rb b/wui/src/host-browser/test-host-browser-awaken.rb deleted file mode 100755 index a5ca2e7..0000000 --- a/wui/src/host-browser/test-host-browser-awaken.rb +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/ruby -Wall -# -# Copyright (C) 2008 Red Hat, Inc. -# Written by Darryl L. Pierce -# -# 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 File.dirname(__FILE__) + '/../test/test_helper' -require 'test/unit' -require 'flexmock/test_unit' - -TESTING=true - -require 'host-browser' - -# +TestHostBrowserAwaken+ -class TestHostBrowserAwaken < Test::Unit::TestCase - - def setup - @session = flexmock('session') - @session.should_receive(:peeraddr).at_least.once.returns { [nil,nil,nil,"192.168.2.255"] } - - @krb5 = flexmock('krb5') - - @browser = HostBrowser.new(@session) - @browser.logfile = './unit-test.log' - @browser.keytab_dir = '/var/temp/' - end - - # Ensures that the server raises an exception when it receives an - # improper handshake response. - # - def test_begin_conversation_with_improper_response_to_greeting - @session.should_receive(:write).with("HELLO?\n").once().returns { |greeting| greeting.length } - @session.should_receive(:readline).once().returns { "SUP?" } - - assert_raise(Exception) { @browser.begin_conversation } - end - - # Ensures the server accepts a proper response from the remote system. - # - def test_begin_conversation - @session.should_receive(:write).with("HELLO?\n").once().returns { |greeting| greeting.length } - @session.should_receive(:readline).once().returns { "HELLO!\n" } - - assert_nothing_raised(Exception) { @browser.begin_conversation } - end - - # Ensures that the server is satisfied if the remote system is - # making a wakeup call. - # - def test_get_mode_with_awaken_request - @session.should_receive(:write).with("MODE?\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "AWAKEN\n" } - - result = @browser.get_mode() - - assert_equal "AWAKEN", result, "method did not return the right value" - end - - # Ensures the host browser generates a keytab as expected. - # - def test_create_keytab - @krb5.should_receive(:get_default_realm).once().returns { "ovirt-test-realm" } - servername = `hostname -f`.chomp - @session.should_receive(:write).with("KTAB http://#{servername}/config/127.0.0.1-libvirt.tab\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "ACK\n" } - - assert_nothing_raised(Exception) { @browser.create_keytab('localhost','127.0.0.1', at krb5) } - end - - # Ensures that, if a keytab is present and a key version number available, - # the server ends the conversation by returning the key version number. - # - def test_end_conversation - @session.should_receive(:write).with("BYE\n").once().returns { |request| request.length } - - assert_nothing_raised(Exception) { @browser.end_conversation } - end - -end diff --git a/wui/src/host-browser/test-host-browser-identify.rb b/wui/src/host-browser/test-host-browser-identify.rb index 8f215e9..4197e19 100755 --- a/wui/src/host-browser/test-host-browser-identify.rb +++ b/wui/src/host-browser/test-host-browser-identify.rb @@ -27,136 +27,219 @@ TESTING=true require 'host-browser' class TestHostBrowser < Test::Unit::TestCase - - def setup - @session = flexmock('session') - @session.should_receive(:peeraddr).at_least.once.returns { [nil,nil,nil,"192.168.2.255"] } - - @browser = HostBrowser.new(@session) - @browser.logfile = './unit-test.log' - - # default host info - @host_info = {} - @host_info['UUID'] = 'node1' - @host_info['IPADDR'] = '192.168.2.2' - @host_info['HOSTNAME'] = 'node1.ovirt.redhat.com' - @host_info['NUMCPUS'] = '3' - @host_info['CPUSPEED'] = '3' - @host_info['ARCH'] = 'x86_64' - @host_info['MEMSIZE'] = '16384' - @host_info['DISABLED'] = '0' - end - - # Ensures that the server is satisfied if the remote system is - # making a wakeup call. - # - def test_get_mode_with_awaken_request - @session.should_receive(:write).with("MODE?\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "IDENTIFY\n" } - - result = @browser.get_mode() - - assert_equal "IDENTIFY", result, "method did not return the right value" - end - - # Ensures that, if an info field is missing a key, the server raises - # an exception. - # - def test_get_info_with_missing_key - @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "=value1\n" } - - assert_raise(Exception) { @browser.get_remote_info } - end - - # Ensures that, if an info field is missing a value, the server raises - # an exception. - # - def test_get_info_with_missing_value - @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "key1=\n" } - - assert_raise(Exception) { @browser.get_remote_info } - end - - # Ensures that, if the server gets a poorly formed ending statement, it - # raises an exception. - # - def test_get_info_with_invalid_end - @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "key1=value1\n" } - @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "ENDIFNO\n" } - - assert_raise(Exception) { @browser.get_remote_info } - end - - # Ensures that a well-formed transaction works as expected. - # - def test_get_info - @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "key1=value1\n" } - @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "key2=value2\n" } - @session.should_receive(:write).with("ACK key2\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "ENDINFO\n" } - - info = @browser.get_remote_info - - assert_equal 4,info.keys.size, "Should contain two keys" - assert info.include?("IPADDR") - assert info.include?("HOSTNAME") - assert info.include?("key1") - assert info.include?("key2") - end - - # Ensures that the server is fine when no UUID is present. - # - def test_write_host_info_with_missing_uuid - @host_info['UUID'] = nil - - assert_nothing_raised { @browser.write_host_info(@host_info) } - end - - # Ensures that, if the hostname is missing, the server - # raises an exception. - # - def test_write_host_info_with_missing_hostname - @host_info['HOSTNAME'] = nil - - assert_raise(Exception) { @browser.write_host_info(@host_info) } - end - - # Ensures that, if the number of CPUs is missing, the server raises an exception. - # - def test_write_host_info_with_missing_numcpus - @host_info['NUMCPUS'] = nil - - assert_raise(Exception) { @browser.write_host_info(@host_info) } - end - - # Ensures that, if the CPU speed is missing, the server raises an exception. - # - def test_write_host_info_with_missing_cpuspeed - @host_info['CPUSPEED'] = nil - - assert_raise(Exception) { @browser.write_host_info(@host_info) } - end - - # Ensures that, if the architecture is missing, the server raises an exception. - # - def test_write_host_info_with_missing_arch - @host_info['ARCH'] = nil - - assert_raise(Exception) { @browser.write_host_info(@host_info) } - end - - # Ensures that, if the memory size is missing, the server raises an exception. - # - def test_write_host_info_info_with_missing_memsize - @host_info['MEMSIZE'] = nil - - assert_raise(Exception) { @browser.write_host_info(@host_info) } - end + def setup + @session = flexmock('session') + @session.should_receive(:peeraddr).at_least.once.returns { [nil,nil,nil,"192.168.2.255"] } + + @browser = HostBrowser.new(@session) + @browser.logfile = './unit-test.log' + + # default host info + @host_info = {} + @host_info['UUID'] = 'node1' + @host_info['IPADDR'] = '192.168.2.2' + @host_info['HOSTNAME'] = 'node1.ovirt.redhat.com' + @host_info['ARCH'] = 'x86_64' + @host_info['MEMSIZE'] = '16384' + @host_info['DISABLED'] = '0' + + @host_info['NUMCPUS'] = '2' + + @host_info['CPUINFO'] = Array.new + @host_info['CPUINFO'][0] = {} + @host_info['CPUINFO'][0]['CPUNUM'] = '0' + @host_info['CPUINFO'][0]['CORENUM'] = '0' + @host_info['CPUINFO'][0]['NUMCORES'] = '2' + @host_info['CPUINFO'][0]['VENDOR'] = 'GenuineIntel' + @host_info['CPUINFO'][0]['MODEL'] = '15' + @host_info['CPUINFO'][0]['FAMILY'] = '6' + @host_info['CPUINFO'][0]['CPUIDLVL'] = '10' + @host_info['CPUINFO'][0]['SPEED'] = '3' + @host_info['CPUINFO'][0]['CACHE'] = '4096 kb' + @host_info['CPUINFO'][0]['FLAGS'] = 'fpu vme de pse tsc msr pae \ + mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx \ + fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs \ + bts pni monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr lahf_lm' + + @host_info['CPUINFO'][1] = {} + @host_info['CPUINFO'][1]['CPUNUM'] = '1' + @host_info['CPUINFO'][1]['CORENUM'] = '1' + @host_info['CPUINFO'][1]['NUMCORES'] = '2' + @host_info['CPUINFO'][1]['VENDOR'] = 'GenuineIntel' + @host_info['CPUINFO'][1]['MODEL'] = '15' + @host_info['CPUINFO'][1]['FAMILY'] = '6' + @host_info['CPUINFO'][1]['CPUIDLVL'] = '10' + @host_info['CPUINFO'][1]['SPEED'] = '3' + @host_info['CPUINFO'][1]['CACHE'] = '4096 kb' + @host_info['CPUINFO'][1]['FLAGS'] = 'fpu vme de pse tsc msr pae \ + mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx \ + fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs \ + bts pni monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr lahf_lm' + end + + # Ensures that the server is satisfied if the remote system is + # making a wakeup call. + # + def test_get_mode_with_awaken_request + @session.should_receive(:write).with("MODE?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "IDENTIFY\n" } + + result = @browser.get_mode() + + assert_equal "IDENTIFY", result, "method did not return the right value" + end + + # Ensures that, if an info field is missing a key, the server raises + # an exception. + # + def test_get_info_with_missing_key + @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "=value1\n" } + + assert_raise(Exception) { @browser.get_remote_info } + end + + # Ensures that, if an info field is missing a value, the server raises + # an exception. + # + def test_get_info_with_missing_value + @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key1=\n" } + + assert_raise(Exception) { @browser.get_remote_info } + end + + # Ensures that, if the server gets a poorly formed ending statement, it + # raises an exception. + # + def test_get_info_with_invalid_end + @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key1=value1\n" } + @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDIFNO\n" } + + assert_raise(Exception) { @browser.get_remote_info } + end + + # Ensures that a well-formed transaction works as expected. + # + def test_get_info + @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key1=value1\n" } + @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key2=value2\n" } + @session.should_receive(:write).with("ACK key2\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDINFO\n" } + + info = @browser.get_remote_info + + assert_equal 4,info.keys.size, "Should contain four keys" + assert info.include?("IPADDR") + assert info.include?("HOSTNAME") + assert info.include?("key1") + assert info.include?("key2") + end + + # Ensures that the server is fine when no UUID is present. + # + def test_write_host_info_with_missing_uuid + @host_info['UUID'] = nil + + assert_nothing_raised { @browser.write_host_info(@host_info) } + end + + # Ensures that, if the hostname is missing, the server + # raises an exception. + # + def test_write_host_info_with_missing_hostname + @host_info['HOSTNAME'] = nil + + assert_raise(Exception) { @browser.write_host_info(@host_info) } + end + + # Ensures that, if the architecture is missing, the server raises an + # exception. + # + def test_write_host_info_with_missing_arch + @host_info['ARCH'] = nil + + assert_raise(Exception) { @browser.write_host_info(@host_info) } + end + + # Ensures that, if the memory size is missing, the server raises an + # exception. + # + def test_write_host_info_info_with_missing_memsize + @host_info['MEMSIZE'] = nil + + assert_raise(Exception) { @browser.write_host_info(@host_info) } + end + + # Ensures that, if no cpu info was available, the server raises an + # exception. + # + def test_write_host_info_with_missing_cpuinfo + @host_info['CPUINFO'] = nil + + assert_raise(Exception) { @browser.write_host_info(@host_info) } + end + + # Ensures the browser can properly parse the CPU details. + # + def test_parse_cpu_info + @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "CPU\n" } + @session.should_receive(:write).with("CPUINFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key1=value1\n" } + @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key2=value2\n" } + @session.should_receive(:write).with("ACK key2\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDCPU\n" } + @session.should_receive(:write).with("ACK CPU\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDINFO\n" } + + info = @browser.get_remote_info + + assert_equal 3,info.keys.size, "Should contain four keys" + assert info.include?("CPUINFO") + end + + # Ensures the browser can properly parse the CPU details of two CPUs. + # + def test_parse_cpu_info + @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } + + # CPU 0 + @session.should_receive(:readline).once().returns { "CPU\n" } + @session.should_receive(:write).with("CPUINFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key1=value1\n" } + @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key2=value2\n" } + @session.should_receive(:write).with("ACK key2\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDCPU\n" } + @session.should_receive(:write).with("ACK CPU\n").once().returns { |request| request.length } + + # CPU 1 + @session.should_receive(:readline).once().returns { "CPU\n" } + @session.should_receive(:write).with("CPUINFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key3=value3\n" } + @session.should_receive(:write).with("ACK key3\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key4=value4\n" } + @session.should_receive(:write).with("ACK key4\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDCPU\n" } + @session.should_receive(:write).with("ACK CPU\n").once().returns { |request| request.length } + + @session.should_receive(:readline).once().returns { "ENDINFO\n" } + + info = @browser.get_remote_info + + assert_equal 3,info.keys.size, "Should contain four keys" + assert info.include?('CPUINFO') + assert_equal 2, info['CPUINFO'].size, "Should contain details for two CPUs" + assert_not_nil info['CPUINFO'][0]['key1'] + assert_not_nil info['CPUINFO'][0]['key2'] + assert_not_nil info['CPUINFO'][1]['key3'] + assert_not_nil info['CPUINFO'][1]['key4'] + end end diff --git a/wui/src/test/fixtures/cpus.yml b/wui/src/test/fixtures/cpus.yml new file mode 100644 index 0000000..5586303 --- /dev/null +++ b/wui/src/test/fixtures/cpus.yml @@ -0,0 +1,21 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html + +one: + cpu_number: 1 + core_number: 1 + cpu_id_level: 1 + vendor: 1 + family: 1 + model: 1 + family: MyString + flags: MyString + +two: + cpu_number: 1 + core_number: 1 + cpu_id_level: 1 + vendor: 1 + family: 1 + model: 1 + family: MyString + flags: MyString diff --git a/wui/src/test/fixtures/hosts.yml b/wui/src/test/fixtures/hosts.yml index 3b93aea..f10a756 100644 --- a/wui/src/test/fixtures/hosts.yml +++ b/wui/src/test/fixtures/hosts.yml @@ -2,8 +2,6 @@ one: id: 1 uuid: '1148fdf8-961d-11dc-9387-001558c41534' hostname: 'prod.corp.com' - num_cpus: 8 - cpu_speed: 4096 arch: 'i686' memory: 18384 is_disabled: 0 @@ -13,8 +11,6 @@ two: id: 2 uuid: '1f2a8694-961d-11dc-9387-001558c41534' hostname: 'myworkstation.dev.corp.com' - num_cpus: 4 - cpu_speed: 2048 arch: 'i386' memory: 2048 is_disabled: 0 @@ -24,30 +20,24 @@ three: id: 3 uuid: '58a85f44-75fd-4934-805f-88e45b40d4b4' hostname: 'macworkstation.foobar.com' - num_cpus: 8 - cpu_speed: 1024 arch: 'mips' memory: 2048 - is_disabled: 0 + is_disabled: 0 hypervisor_type: 'kvm' hardware_pool_id: 3 four: id: 4 uuid: '520bbb34-6515-490e-9d07-0c8b14f76805' hostname: 'fedoraworkstation.foobar.com' - num_cpus: 8 - cpu_speed: 3072 arch: 'i386' memory: 2048 - is_disabled: 1 + is_disabled: 1 hypervisor_type: 'kvm' hardware_pool_id: 3 five: id: 5 uuid: '2e422f66-324e-48d4-973f-0b91b33070f9' hostname: 'pipeline.foobar.com' - num_cpus: 32 - cpu_speed: 4096 arch: 'xeon' memory: 1048576 is_disabled: 0 @@ -57,19 +47,15 @@ six: id: 6 uuid: 'bb0ce7c7-f234-49ae-84b5-6f4fd8bddcaa' hostname: 'prod.foobar.com' - num_cpus: 32 - cpu_speed: 4096 arch: 'xeon' memory: 16384 - is_disabled: 0 + is_disabled: 0 hypervisor_type: 'kvm' hardware_pool_id: 3 seven: id: 7 uuid: '6ae3d22e-97e0-4d86-9712-5395b20a0f45' hostname: 'mystation.dev.corp.com' - num_cpus: 4 - cpu_speed: 3072 arch: 'i686' memory: 2048 is_disabled: 0 @@ -79,8 +65,6 @@ eight: id: 8 uuid: 'ec0d86de-657b-48f6-b7cc-e733a3f9a834' hostname: 'issue.qa.corp.com' - num_cpus: 8 - cpu_speed: 4096 arch: 'x86' memory: 4096 is_disabled: 0 @@ -90,8 +74,6 @@ nine: id: 9 uuid: '81c15560-dbf4-45f5-9b75-106cdbd63aeb' hostname: 'somehost' - num_cpus: 4 - cpu_speed: 4096 arch: 'x86' memory: 4096 is_disabled: 0 diff --git a/wui/src/test/unit/cpu_test.rb b/wui/src/test/unit/cpu_test.rb new file mode 100644 index 0000000..5b64ca7 --- /dev/null +++ b/wui/src/test/unit/cpu_test.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class CpuTest < ActiveSupport::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end -- 1.5.5.1 From sseago at redhat.com Tue Jul 8 13:26:00 2008 From: sseago at redhat.com (Scott Seago) Date: Tue, 08 Jul 2008 09:26:00 -0400 Subject: [Ovirt-devel] [PATCH] ovirt-identify-node now submits all extended CPU details. In-Reply-To: <1215266397-13191-1-git-send-email-dpierce@redhat.com> References: <1215266397-13191-1-git-send-email-dpierce@redhat.com> Message-ID: <48736AE8.9030001@redhat.com> Darryl L. Pierce wrote: > diff --git a/wui/src/app/models/host.rb b/wui/src/app/models/host.rb > index 6917226..3413370 100644 > --- a/wui/src/app/models/host.rb > +++ b/wui/src/app/models/host.rb > @@ -21,8 +21,11 @@ require 'util/ovirt' > > class Host < ActiveRecord::Base > belongs_to :hardware_pool > + > + has_many :cpus > has_many :nics, :dependent => :destroy > has_many :vms, :dependent => :nullify do > + > def consuming_resources > find(:all, :conditions=>{:state=>Vm::RUNNING_STATES}) > end > Should probably add ':dependent => :destroy' here like we do for nics to handle automatic deletion of the CPU objects when the host is deleted. > @@ -42,12 +45,18 @@ class Host < ActiveRecord::Base > STATE_UNAVAILABLE = "unavailable" > STATE_AVAILABLE = "available" > STATES = [STATE_UNAVAILABLE, STATE_AVAILABLE] > + > + KVM_HYPERVISOR_TYPE = "KVM" > + HYPERVISOR_TYPES = [KVM_HYPERVISOR_TYPE] > + > def memory_in_mb > kb_to_mb(memory) > end > + > def memory_in_mb=(mem) > self[:memory]=(mb_to_kb(mem)) > end > + > def status_str > "#{state} (#{disabled? ? 'disabled':'enabled'})" > end > @@ -61,4 +70,12 @@ class Host < ActiveRecord::Base > not(disabled? and vms.consuming_resources.empty?) and > tasks.pending_clear_tasks.empty? > end > + > + def num_cpus > + return cpu_details.size > + end > + > + def cpu_speed > + "FIX ME!" > + end > end > I'm assuming cpu_speed above is so that the WUI view code doesn't break with this change. This is a question for Hugh or Tim -- have we determined what the UI should look like for this? Off the top of my head, we leave num_cpus in the host flexigrid tables and just remove cpu_speed. Then in the host detail pane we add a table (not a flexigrid) with the enumerated CPU details. Do we show all 10 attributes per CPU or just some of them? > diff --git a/wui/src/db/migrate/002_create_hosts.rb b/wui/src/db/migrate/002_create_hosts.rb > index cef7996..442e674 100644 > --- a/wui/src/db/migrate/002_create_hosts.rb > +++ b/wui/src/db/migrate/002_create_hosts.rb > @@ -23,8 +23,6 @@ class CreateHosts < ActiveRecord::Migration > t.string :uuid > t.string :hypervisor_type > t.string :hostname > - t.integer :num_cpus > - t.integer :cpu_speed > t.string :arch > t.integer :memory > t.integer :is_disabled > I think we had agreed that after the beta we'd track schema changes by adding new migrations rather than modifying existing ones. Hugh -- is this correct, or are we still doing it this way? If we are adding new migrations, then we'd need the above done as something like 11_remove_cpu_from_hosts.rb or whatever you want to call it. Another point we'll need to clarify -- if we're doing incremental migrations, do we have to handle existing data too? Or can we explicitly _not_ support live data migrations until later? OK, that's it for my comments here -- I'll let someone on the managed node side look at/test the back end bits. Scott From dpierce at redhat.com Tue Jul 8 14:06:03 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Tue, 8 Jul 2008 10:06:03 -0400 Subject: [Ovirt-devel] [PATCH] ovirt-identify-node now submits all extended CPU details. Message-ID: <1215525963-16483-1-git-send-email-dpierce@redhat.com> From: Darryl Pierce Signed-off-by: Darryl L. Pierce --- ovirt-managed-node/src/ovirt-identify-node.c | 420 +++++++++++++++----- ovirt-managed-node/src/ovirt-identify-node.h | 56 +++ wui/src/app/models/cpu.rb | 24 ++ wui/src/app/models/host.rb | 23 +- wui/src/db/migrate/010_create_cpus.rb | 32 ++ wui/src/dutils/active_record_env.rb | 5 +- wui/src/host-browser/host-browser.rb | 103 +++++- wui/src/host-browser/test-host-browser-awake.rb | 94 +++++ wui/src/host-browser/test-host-browser-awaken.rb | 94 ----- wui/src/host-browser/test-host-browser-identify.rb | 345 ++++++++++------ wui/src/test/fixtures/cpus.yml | 21 + wui/src/test/fixtures/hosts.yml | 24 +- wui/src/test/unit/cpu_test.rb | 8 + 13 files changed, 881 insertions(+), 368 deletions(-) create mode 100644 ovirt-managed-node/src/ovirt-identify-node.h create mode 100644 wui/src/app/models/cpu.rb create mode 100644 wui/src/db/migrate/010_create_cpus.rb create mode 100755 wui/src/host-browser/test-host-browser-awake.rb delete mode 100755 wui/src/host-browser/test-host-browser-awaken.rb create mode 100644 wui/src/test/fixtures/cpus.yml create mode 100644 wui/src/test/unit/cpu_test.rb diff --git a/ovirt-managed-node/src/ovirt-identify-node.c b/ovirt-managed-node/src/ovirt-identify-node.c index 819f700..f114d81 100644 --- a/ovirt-managed-node/src/ovirt-identify-node.c +++ b/ovirt-managed-node/src/ovirt-identify-node.c @@ -31,31 +31,7 @@ #include #include -int config(int argc,char** argv); -void usage(void); - -int start_conversation(void); -int send_details(void); -int end_conversation(void); - -int send_text(char* text); -int get_text(const char *const expected); -int create_connection(void); - -int debug = 1; -int verbose = 1; -int testing = 0; - -#define BUFFER_LENGTH 128 - -char arch[BUFFER_LENGTH]; -char uuid[VIR_UUID_BUFLEN]; -char memsize[BUFFER_LENGTH]; -char numcpus[BUFFER_LENGTH]; -char cpuspeed[BUFFER_LENGTH]; -char *hostname; -int hostport = -1; -int socketfd; +#include "ovirt-identify-node.h" int main(int argc,char** argv) { @@ -63,9 +39,11 @@ int main(int argc,char** argv) virConnectPtr connection; virNodeInfo info; + fprintf(stdout,"Sending managed node details to server.\n"); + if(!config(argc,argv)) { - fprintf(stdout,"Connecting to libvirt.\n"); + if(verbose) fprintf(stdout,"Connecting to libvirt.\n"); connection = virConnectOpenReadOnly(testing ? "test:///default" : NULL); @@ -73,42 +51,68 @@ int main(int argc,char** argv) if(connection) { - if(debug) fprintf(stdout,"Getting hostname: %s\n", uuid); + if(verbose) fprintf(stdout,"Getting hostname: %s\n", uuid); if(!strlen(uuid)) gethostname(uuid,sizeof uuid); - if(debug) fprintf(stdout,"Retrieving node information.\n"); + if(verbose) fprintf(stdout,"Retrieving node information.\n"); if(!virNodeGetInfo(connection,&info)) { snprintf(arch, BUFFER_LENGTH, "%s", info.model); snprintf(memsize, BUFFER_LENGTH, "%ld", info.memory); - snprintf(numcpus, BUFFER_LENGTH, "%d", info.cpus); - snprintf(cpuspeed, BUFFER_LENGTH, "%d", info.mhz); - if(debug) + cpu_info = NULL; + + if(!get_cpu_info()) { - fprintf(stdout,"Node Info:\n"); - fprintf(stdout," UUID: %s\n", uuid); - fprintf(stdout," Arch: %s\n", arch); - fprintf(stdout," Memory: %s\n", memsize); - fprintf(stdout," # CPUs: %s\n", numcpus); - fprintf(stdout,"CPU Speed: %s\n", cpuspeed); + if(verbose) fprintf(stdout, "Getting CPU info.\n"); + + if(debug) + { + fprintf(stdout,"Node Info:\n"); + fprintf(stdout," UUID: %s\n", uuid); + fprintf(stdout," Arch: %s\n", arch); + fprintf(stdout," Memory: %s\n", memsize); + + t_cpu_info* current = cpu_info; + while(current != NULL) + { + fprintf(stdout,"\n"); + fprintf(stdout," CPU Number: %s\n", current->cpu_num); + fprintf(stdout," Core Number: %s\n", current->core_num); + fprintf(stdout,"Number of Cores: %s\n", current->number_of_cores); + fprintf(stdout," Vendor: %s\n", current->vendor); + fprintf(stdout," Model: %s\n", current->model); + fprintf(stdout," Family: %s\n", current->family); + fprintf(stdout," CPUID Level: %s\n", current->cpuid_level); + fprintf(stdout," CPU Speed: %s\n", current->speed); + fprintf(stdout," Cache Size: %s\n", current->cache); + fprintf(stdout," CPU Flags: %s\n", current->flags); + + current = current->next; + } + } + + if(verbose) fprintf(stdout, "Retrieved node information.\n"); + + if(!start_conversation() && !send_details() && !end_conversation()) + { + fprintf(stdout,"Finished!\n"); + result = 0; + } } - - if(debug) fprintf(stdout, "Retrieved node information.\n"); - - if(!start_conversation() && !send_details() && !end_conversation()) + else { - result = 0; + if(verbose) fprintf(stderr,"Failed to get CPU info.\n"); } } else { - if(debug) fprintf(stderr,"Failed to get node info.\n"); + if(verbose) fprintf(stderr,"Failed to get node info.\n"); } } else { - if(debug) fprintf(stderr,"Could not connect to libvirt.\n"); + if(verbose) fprintf(stderr,"Could not connect to libvirt.\n"); } } else @@ -181,35 +185,35 @@ int start_conversation(void) { if(debug || verbose) fprintf(stdout,"Connected.\n"); - if (!get_text("HELLO?\n")) + if (!get_text("HELLO?")) { - if(debug) fprintf(stdout,"Checking for handshake.\n"); + if(verbose) fprintf(stdout,"Checking for handshake.\n"); - if(!send_text("HELLO!\n")) + if(!send_text("HELLO!")) { - if(debug) fprintf(stdout,"Handshake received. Starting conversation.\n"); + if(verbose) fprintf(stdout,"Handshake received. Starting conversation.\n"); - if(!get_text("MODE?\n")) + if(!get_text("MODE?")) { - if(debug) fprintf(stdout,"Shifting to IDENTIFY mode.\n"); + if(verbose) fprintf(stdout,"Shifting to IDENTIFY mode.\n"); - if(!send_text("IDENTIFY\n")) result = 0; + if(!send_text("IDENTIFY")) result = 0; } else { - if(debug) fprintf(stderr,"Was not asked for a mode.\n"); + if(verbose) fprintf(stderr,"Was not asked for a mode.\n"); } } } else { - if(debug) fprintf(stderr,"Did not receive a proper handshake.\n"); + if(verbose) fprintf(stderr,"Did not receive a proper handshake.\n"); } } else { - if(debug) fprintf(stderr,"Did not get a connection.\n"); + if(verbose) fprintf(stderr,"Did not get a connection.\n"); } if(debug) fprintf(stdout,"start_conversation: result=%d\n", result); @@ -223,19 +227,15 @@ int send_value(char* label,char* value) int result = 1; char expected[BUFFER_LENGTH]; - snprintf(buffer,BUFFER_LENGTH,"%s=%s\n", label, value); + snprintf(buffer,BUFFER_LENGTH,"%s=%s", label, value); if(!send_text(buffer)) { - snprintf(expected, BUFFER_LENGTH, "ACK %s\n", label); + snprintf(expected, BUFFER_LENGTH, "ACK %s", label); - if(debug) fprintf(stdout,"Expecting \"%s\"\n", expected); - - if (!get_text(expected)) - { - result = 0; - } + if(verbose) fprintf(stdout,"Expecting \"%s\"\n", expected); + result = get_text(expected); } return result; @@ -245,40 +245,238 @@ int send_details(void) { int result = 1; - fprintf(stdout,"Sending node details.\n"); + if(verbose) fprintf(stdout,"Sending node details.\n"); - if (!get_text("INFO?\n")) + if (!get_text("INFO?")) { if((!send_value("ARCH", arch)) && (!send_value("UUID", uuid)) && - (!send_value("NUMCPUS", numcpus)) && - (!send_value("CPUSPEED", cpuspeed)) && - (!send_value("MEMSIZE", memsize))) + (!send_value("MEMSIZE", memsize)) && + (!send_cpu_details())) { - if(!send_text("ENDINFO\n")) result = 0; + if(!send_text("ENDINFO")) result = 0; } } else { - if(debug) fprintf(stdout,"Was not interrogated for hardware info.\n"); + if(verbose) fprintf(stdout,"Was not interrogated for hardware info.\n"); } return result; } +int send_cpu_details(void) +{ + int result = 1; + t_cpu_info* current = cpu_info; + + while(current != NULL) + { + send_text("CPU"); + + if(!(get_text("CPUINFO?")) && + (!send_value("CPUNUM",current->cpu_num)) && + (!send_value("CORENUM",current->core_num)) && + (!send_value("NUMCORES",current->number_of_cores)) && + (!send_value("VENDOR",current->vendor)) && + (!send_value("MODEL",current->model)) && + (!send_value("FAMILY",current->family)) && + (!send_value("CPUIDLVL",current->cpuid_level)) && + (!send_value("SPEED",current->speed)) && + (!send_value("CACHE", current->cache)) && + (!send_value("FLAGS", current->flags))) + { + send_text("ENDCPU"); + result = get_text("ACK CPU"); + } + + current = current->next; + } + + + return result; +} + int end_conversation(void) { int result = 0; - fprintf(stdout,"Ending conversation.\n"); + if(debug || verbose) fprintf(stdout,"Ending conversation.\n"); - send_text("ENDINFO\n"); + send_text("ENDINFO"); close(socketfd); return result; } +void get_label_and_value(char* text, + char* label, size_t label_length, + char* value, size_t value_length) +{ + int offset = 0; + int which = 0; /* 0 = label, 1 = value */ + char* current = text; + + /* iterate through the text supplied and find where the + * label ends with a colon, then copy that into the supplied + * label buffer and trim any trailing spaces + */ + + while(current != NULL && *current != '\0') + { + /* if we're on the separator, then switch modes and reset + * the offset indicator, otherwise just process the character + */ + if(which == 0 && *current == ':') + { + which = 1; + offset = 0; + } + else + { + char* buffer = (which == 0 ? label : value); + int length = (which == 0 ? label_length : value_length); + + /* only copy if we're past the first character and it's not + * a space + */ + if((offset > 0 || (*current != 9 && *current != ' ')) && offset < (length - 1)) + { + buffer[offset++] = *current; + buffer[offset] = 0; + } + } + + current++; + } + + /* now trim all trailing spaces from the values */ + while(label[strlen(label) - 1 ] == 9) + label[strlen(label) - 1] = 0; + while(value[strlen(value) - 1] == 9) + value[strlen(value) - 1] = 0; +} + +int get_cpu_info(void) +{ + int result = 1; + FILE* inputfd; + t_cpu_info* current = NULL; + + if(( inputfd = fopen("/proc/cpuinfo","rb")) != NULL) + { + if(verbose) fprintf(stdout,"Parsing CPU information\n"); + do + { + char buffer[255]; + char label[BUFFER_LENGTH]; + char value[BUFFER_LENGTH]; + + fgets(buffer, 255, inputfd); + if(strlen(buffer) > 0) buffer[strlen(buffer) - 1] = '\0'; + + get_label_and_value(buffer, + label,BUFFER_LENGTH, + value,BUFFER_LENGTH); + + if(debug) + fprintf(stdout,"label=\"%s\", value=\"%s\"\n", label, value); + + if(strlen(label)) + { + if(!strcmp(label,"processor")) + { + if(debug || verbose) + fprintf(stdout,"Starting new CPU\n"); + + t_cpu_info* last = current; + + current = create_cpu_info(); + if(last != NULL) + { + last->next = current; + } + else + { + cpu_info = current; + } + + COPY_VALUE_TO_BUFFER(value,current->cpu_num,BUFFER_LENGTH); + } + else + if(!strcmp(label,"core id")) + { + COPY_VALUE_TO_BUFFER(value,current->core_num,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cpu cores")) + { + COPY_VALUE_TO_BUFFER(value,current->number_of_cores,BUFFER_LENGTH); + } + else + if(!strcmp(label,"vendor_id")) + { + COPY_VALUE_TO_BUFFER(value,current->vendor,BUFFER_LENGTH); + } + else + if(!strcmp(label,"model")) + { + COPY_VALUE_TO_BUFFER(value,current->model,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cpu family")) + { + COPY_VALUE_TO_BUFFER(value,current->family,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cpuid level")) + { + COPY_VALUE_TO_BUFFER(value,current->cpuid_level,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cpu MHz")) + { + COPY_VALUE_TO_BUFFER(value,current->speed,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cache size")) + { + COPY_VALUE_TO_BUFFER(value,current->cache,BUFFER_LENGTH); + } + else + if(!strcmp(label,"flags")) + { + COPY_VALUE_TO_BUFFER(value,current->flags,BUFFER_LENGTH); + } + } + + } while(!feof(inputfd)); + + fclose(inputfd); + + result = 0; + } + else + { + if(verbose) fprintf(stderr,"Unable to open /proc/cpuinfo\n"); + } + + return result; +} + +t_cpu_info* create_cpu_info(void) +{ + t_cpu_info* result = calloc(1,sizeof(t_cpu_info)); + bzero(result,sizeof(t_cpu_info)); + + strcpy(result->core_num,"0"); + strcpy(result->number_of_cores,"1"); + + + return result; +} + ssize_t safewrite(int fd, const void *buf, size_t count) { size_t nwritten = 0; @@ -303,9 +501,10 @@ int send_text(char* text) int result = 1; int sent; - if(debug || verbose) fprintf(stdout,"\"%s\" -> %s:%d\n", text, hostname, hostport); + if(verbose) fprintf(stdout,"Sending: \"%s\"\n", text); sent = safewrite(socketfd, text, strlen(text)); + sent += safewrite(socketfd, "\n", 1); if(sent >= 0) { @@ -317,35 +516,46 @@ int send_text(char* text) return result; } -int saferead(int fd, void *buf, size_t count) +int saferead(int fd, char *buf, size_t count) { ssize_t bytes,offset; int len_left; + int done = 0; if(debug) fprintf(stdout,"Begin saferead(%d, %p, %ld)\n", fd, buf, count); offset = 0; len_left = count; - while(len_left > 0) { - bytes = read(fd, buf+offset, len_left); - fprintf(stderr,"After read, bytes is %ld\n",bytes); - if (bytes < 0) { - if (errno == EINTR) { - continue; - } - else { - offset = -1; - break; - } - } - else if (bytes == 0) { - // reached EOF; break out of here - break; - } - - offset += bytes; - len_left -= bytes; + + while(!done) + { + if(debug) fprintf(stdout,"Before read(%ld,%p,%ld)\n",fd,buf+offset,len_left); + + bytes = read(fd, buf+offset, len_left); + + if(debug) fprintf(stdout,"After read: bytes=%ld\n", bytes); + + if(bytes == 0) + { + done = 1; + } + else if(bytes > 0) + { + offset += bytes; + len_left -= bytes; + done = 1; + } + else if(errno == EINTR) + { + continue; + } + else + { + done = 1; + } + + if(debug) fprintf(stdout,"End of decision loop: offset=%ld, len_left=%dl, done=%d\n",offset, len_left, done); } return offset; @@ -353,22 +563,22 @@ int saferead(int fd, void *buf, size_t count) int get_text(const char *const expected) { + int result = 1; int received; char buffer[BUFFER_LENGTH]; + bzero(buffer,BUFFER_LENGTH); - if(debug) fprintf(stdout, "Looking to receive %s\n", expected); + if(verbose) fprintf(stdout, "Looking to receive %s\n", expected); - received = saferead(socketfd, buffer, strlen(expected)); + received = saferead(socketfd, buffer, BUFFER_LENGTH); buffer[received - 1] = 0; - if(debug) fprintf(stdout,"Received \"%s\": size=%d (trimmed ending carriage return)\n", buffer, received); + if(verbose) fprintf(stdout,"Received \"%s\": size=%d (trimmed ending carriage return)\n", buffer, received); - if (strncmp(expected, buffer, strlen(expected)) != 0) { - return 0; - } + result = strcmp(expected,buffer); - return 1; + return result; } int create_connection(void) @@ -379,7 +589,7 @@ int create_connection(void) char port[6]; struct addrinfo* rptr; - if(debug) fprintf(stdout,"Creating the socket connection.\n"); + if(verbose) fprintf(stdout,"Creating the socket connection.\n"); memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; @@ -387,13 +597,13 @@ int create_connection(void) hints.ai_flags = 0; hints.ai_protocol = 0; - if(debug) fprintf(stdout,"Searching for host candidates.\n"); + if(verbose) fprintf(stdout,"Searching for host candidates.\n"); snprintf(port, 6, "%d", hostport); if(!getaddrinfo(hostname, port, &hints, &results)) { - if(debug) fprintf(stdout,"Got address information. Searching for a proper entry.\n"); + if(verbose) fprintf(stdout,"Got address information. Searching for a proper entry.\n"); for(rptr = results; rptr != NULL; rptr = rptr->ai_next) { @@ -416,13 +626,13 @@ int create_connection(void) } // invalid connection, so close it - if(debug) fprintf(stdout, "Invalid connection.\n"); + if(verbose) fprintf(stdout, "Invalid connection.\n"); close(socketfd); } if(rptr == NULL) { - if(debug) fprintf(stdout,"Unable to connect to server %s:%d\n", hostname, hostport); + if(verbose) fprintf(stdout,"Unable to connect to server %s:%d\n", hostname, hostport); } else { @@ -434,7 +644,7 @@ int create_connection(void) } else { - if(debug) fprintf(stderr,"No hosts found. Exiting...\n"); + if(verbose) fprintf(stderr,"No hosts found. Exiting...\n"); } if(debug) fprintf(stdout, "create_connection: result=%d\n", result); diff --git a/ovirt-managed-node/src/ovirt-identify-node.h b/ovirt-managed-node/src/ovirt-identify-node.h new file mode 100644 index 0000000..1cb1526 --- /dev/null +++ b/ovirt-managed-node/src/ovirt-identify-node.h @@ -0,0 +1,56 @@ +#ifndef __OVIRT_IDENTIFY_NODE_H +#define __OVIRT_IDENTIFY_NODE_H + +#define BUFFER_LENGTH 128 +#define CPU_FLAGS_BUFFER_LENGTH 256 + +typedef struct _cpu_info { + char cpu_num[BUFFER_LENGTH]; + char core_num[BUFFER_LENGTH]; + char number_of_cores[BUFFER_LENGTH]; + char vendor[BUFFER_LENGTH]; + char model[BUFFER_LENGTH]; + char family[BUFFER_LENGTH]; + char cpuid_level[BUFFER_LENGTH]; + char speed[BUFFER_LENGTH]; + char cache[BUFFER_LENGTH]; + char flags[CPU_FLAGS_BUFFER_LENGTH]; + struct _cpu_info* next; +} t_cpu_info; + +#define COPY_VALUE_TO_BUFFER(value,buffer,length) \ + snprintf(buffer,length,"%s",value) + +int config(int argc,char** argv); +void usage(void); + +int start_conversation(void); +int send_details(void); +int send_cpu_details(void); +int end_conversation(void); + +void get_label_and_value(char* text, + char* label,size_t label_length, + char* value,size_t value_length); +t_cpu_info* create_cpu_info(void); +int get_cpu_info(void); + +int send_text(char* text); +int get_text(const char *const expected); +int create_connection(void); + +int debug = 0; +int verbose = 0; +int testing = 0; + +char arch[BUFFER_LENGTH]; +char uuid[VIR_UUID_BUFLEN]; +char memsize[BUFFER_LENGTH]; +char numcpus[BUFFER_LENGTH]; +char cpuspeed[BUFFER_LENGTH]; +char *hostname; +int hostport = -1; +int socketfd; +t_cpu_info* cpu_info; + +#endif diff --git a/wui/src/app/models/cpu.rb b/wui/src/app/models/cpu.rb new file mode 100644 index 0000000..1a7d3cf --- /dev/null +++ b/wui/src/app/models/cpu.rb @@ -0,0 +1,24 @@ +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Darryl L. Pierce +# +# 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. + +# +Cpu+ represents the details for a single CPU on a managed node. +# +class Cpu < ActiveRecord::Base + belongs_to :host +end diff --git a/wui/src/app/models/host.rb b/wui/src/app/models/host.rb index 6917226..90e18d5 100644 --- a/wui/src/app/models/host.rb +++ b/wui/src/app/models/host.rb @@ -1,4 +1,4 @@ -# +# # Copyright (C) 2008 Red Hat, Inc. # Written by Scott Seago # @@ -21,8 +21,11 @@ require 'util/ovirt' class Host < ActiveRecord::Base belongs_to :hardware_pool + + has_many :cpus, :dependent => :destroy has_many :nics, :dependent => :destroy - has_many :vms, :dependent => :nullify do + has_many :vms, :dependent => :nullify do + def consuming_resources find(:all, :conditions=>{:state=>Vm::RUNNING_STATES}) end @@ -32,7 +35,7 @@ class Host < ActiveRecord::Base find(:all, :conditions=>{:state=>Task::STATE_QUEUED}) end def pending_clear_tasks - find(:all, :conditions=>{:state=>Task::WORKING_STATES, + find(:all, :conditions=>{:state=>Task::WORKING_STATES, :action=>HostTask::ACTION_CLEAR_VMS}) end end @@ -42,12 +45,18 @@ class Host < ActiveRecord::Base STATE_UNAVAILABLE = "unavailable" STATE_AVAILABLE = "available" STATES = [STATE_UNAVAILABLE, STATE_AVAILABLE] + + KVM_HYPERVISOR_TYPE = "KVM" + HYPERVISOR_TYPES = [KVM_HYPERVISOR_TYPE] + def memory_in_mb kb_to_mb(memory) end + def memory_in_mb=(mem) self[:memory]=(mb_to_kb(mem)) end + def status_str "#{state} (#{disabled? ? 'disabled':'enabled'})" end @@ -61,4 +70,12 @@ class Host < ActiveRecord::Base not(disabled? and vms.consuming_resources.empty?) and tasks.pending_clear_tasks.empty? end + + def num_cpus + return cpu_details.size + end + + def cpu_speed + "FIX ME!" + end end diff --git a/wui/src/db/migrate/010_create_cpus.rb b/wui/src/db/migrate/010_create_cpus.rb new file mode 100644 index 0000000..bd17274 --- /dev/null +++ b/wui/src/db/migrate/010_create_cpus.rb @@ -0,0 +1,32 @@ +class CreateCpus < ActiveRecord::Migration + def self.up + create_table :cpus do |t| + t.integer :host_id + t.integer :cpu_number + t.integer :core_number + t.integer :number_of_cores + t.string :vendor, :limit => 128 + t.integer :model + t.integer :family + t.integer :cpuid_level + t.float :speed + t.string :cache + t.string :flags + + t.timestamps + end + + execute "alter table cpus add constraint fk_host_cpus + foreign key (host_id) references hosts(id)" + + remove_column :hosts, :cpu_speed + remove_column :hosts, :num_cpus + end + + def self.down + drop_table :cpus + + add_column :hosts, :cpu_speed, :integer + add_column :hosts, :num_cpus, :integer + end +end diff --git a/wui/src/dutils/active_record_env.rb b/wui/src/dutils/active_record_env.rb index b0aef04..72feb89 100644 --- a/wui/src/dutils/active_record_env.rb +++ b/wui/src/dutils/active_record_env.rb @@ -1,5 +1,5 @@ #!/usr/bin/ruby -# +# # Copyright (C) 2008 Red Hat, Inc. # Written by Scott Seago # @@ -23,7 +23,7 @@ $: << File.join(File.dirname(__FILE__), "../vendor/plugins/betternestedset/lib") require 'rubygems' -gem 'activeldap' +gem 'activeldap' require 'active_ldap' require 'active_support' @@ -58,6 +58,7 @@ require 'models/quota.rb' require 'models/hardware_pool.rb' require 'models/host.rb' +require 'models/cpu.rb' require 'models/nic.rb' require 'models/vm_resource_pool.rb' diff --git a/wui/src/host-browser/host-browser.rb b/wui/src/host-browser/host-browser.rb index 691e4ed..e66493d 100755 --- a/wui/src/host-browser/host-browser.rb +++ b/wui/src/host-browser/host-browser.rb @@ -19,6 +19,7 @@ # also available at http://www.gnu.org/copyleft/gpl.html. $: << File.join(File.dirname(__FILE__), "../dutils") +$: << File.join(File.dirname(__FILE__), "../") require 'rubygems' require 'libvirt' @@ -73,16 +74,61 @@ class HostBrowser # def get_remote_info puts "#{@log_prefix} Begin remote info collection" unless defined?(TESTING) - result = {} + result = Hash.new result['HOSTNAME'] = @session.peeraddr[2] result['IPADDR'] = @session.peeraddr[3] + @session.write("INFO?\n") loop do info = @session.readline.chomp + puts "Received info='#{info}'" + break if info == "ENDINFO" + # if we got the start of a CPU details marker, then process it + if info == "CPU" + cpu = get_cpu_info + cpu_info = result['CPUINFO'] + + if(cpu_info == nil) + cpu_info = Array.new + result['CPUINFO'] = cpu_info + end + + cpu_info << cpu + + else + + raise Exception.new("ERRINFO! Excepted key=value : #{info}\n") unless info =~ /[\w]+[\s]*=[\w]/ + + key, value = info.split("=") + + puts "#{@log_prefix} ::Received - #{key}:#{value}" unless defined?(TESTING) + result[key] = value + + @session.write("ACK #{key}\n") + end + end + + return result + end + + # Extracts CPU details from the managed node. + # + def get_cpu_info + puts "Begin receiving CPU details" + + result = Hash.new + + @session.write("CPUINFO?\n") + + loop do + info = @session.readline.chomp + + break if info == "ENDCPU" + raise Exception.new("ERRINFO! Excepted key=value : #{info}\n") unless info =~ /[\w]+[\s]*=[\w]/ key, value = info.split("=") @@ -93,6 +139,8 @@ class HostBrowser @session.write("ACK #{key}\n") end + @session.write("ACK CPU\n"); + return result end @@ -100,10 +148,24 @@ class HostBrowser # def write_host_info(host_info) ensure_present(host_info,'HOSTNAME') - ensure_present(host_info,'NUMCPUS') - ensure_present(host_info,'CPUSPEED') ensure_present(host_info,'ARCH') ensure_present(host_info,'MEMSIZE') + ensure_present(host_info,'CPUINFO') + + cpu_info = host_info['CPUINFO'] + + cpu_info.each do |cpu| + ensure_present(cpu,'CPUNUM') + ensure_present(cpu,'CORENUM') + ensure_present(cpu,'NUMCORES') + ensure_present(cpu,'VENDOR') + ensure_present(cpu,'MODEL') + ensure_present(cpu,'FAMILY') + ensure_present(cpu,'CPUIDLVL') + ensure_present(cpu,'SPEED') + ensure_present(cpu,'CACHE') + ensure_present(cpu,'FLAGS') + end puts "Searching for existing host record..." unless defined?(TESTING) host = Host.find(:first, :conditions => ["hostname = ?", host_info['HOSTNAME']]) @@ -112,31 +174,49 @@ class HostBrowser begin puts "Creating a new record for #{host_info['HOSTNAME']}..." unless defined?(TESTING) - Host.new( + host = Host.create( "uuid" => host_info['UUID'], "hostname" => host_info['HOSTNAME'], "hypervisor_type" => host_info['HYPERVISOR_TYPE'], - "num_cpus" => host_info['NUMCPUS'], - "cpu_speed" => host_info['CPUSPEED'], "arch" => host_info['ARCH'], "memory_in_mb" => host_info['MEMSIZE'], "is_disabled" => 0, "hardware_pool" => HardwarePool.get_default_pool, # Let host-status mark it available when it # successfully connects to it via libvirt. - "state" => Host::STATE_UNAVAILABLE).save + "state" => Host::STATE_UNAVAILABLE) + host.save! rescue Exception => error puts "Error while creating record: #{error.message}" unless defined?(TESTING) end else host.uuid = host_info['UUID'] host.hostname = host_info['HOSTNAME'] - host.num_cpus = host_info['NUMCPUS'] - host.cpu_speed = host_info['CPUSPEED'] host.arch = host_info['ARCH'] host.memory_in_mb = host_info['MEMSIZE'] end + # delete an existing CPUs and create new ones based on the data + puts "Deleting any existing CPUs" + Cpu.delete_all(['host_id = ?', host.id]) + + puts "Saving new CPU records" + cpu_info.collect do |cpu| + detail = Cpu.new( + "cpu_number" => cpu['CPUNUM'], + "core_number" => cpu['CORENUM]'], + "number_of_cores" => cpu['NUMCORES'], + "vendor" => cpu['VENDOR'], + "model" => cpu['MODEL'], + "family" => cpu['FAMILY'], + "cpuid_level" => cpu['CPUIDLVL'], + "speed" => cpu['SPEED'], + "cache" => cpu['CACHE'], + "flags" => cpu['FLAGS']) + + host.cpus << detail + end + return host end @@ -181,8 +261,8 @@ class HostBrowser # Private method to ensure that a required field is present. # - def ensure_present(host_info,key) - raise Exception.new("ERROR! Missing '#{key}'...") if host_info[key] == nil + def ensure_present(info,key) + raise Exception.new("ERROR! Missing '#{key}'...") if info[key] == nil end # Executes an external program to support the keytab function. @@ -226,7 +306,6 @@ def entry_point(server) end unless defined?(TESTING) - # The main entry point. # unless ARGV[0] == "-n" diff --git a/wui/src/host-browser/test-host-browser-awake.rb b/wui/src/host-browser/test-host-browser-awake.rb new file mode 100755 index 0000000..02e9146 --- /dev/null +++ b/wui/src/host-browser/test-host-browser-awake.rb @@ -0,0 +1,94 @@ +#!/usr/bin/ruby -Wall +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Darryl L. Pierce +# +# 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 File.dirname(__FILE__) + '/../test/test_helper' +require 'test/unit' +require 'flexmock/test_unit' + +TESTING=true + +require 'host-browser' + +# +TestHostBrowserAwaken+ +class TestHostBrowserAwaken < Test::Unit::TestCase + + def setup + @session = flexmock('session') + @session.should_receive(:peeraddr).at_least.once.returns { [nil,nil,nil,"192.168.2.255"] } + + @krb5 = flexmock('krb5') + + @browser = HostBrowser.new(@session) + @browser.logfile = './unit-test.log' + @browser.keytab_dir = '/var/temp/' + end + + # Ensures that the server raises an exception when it receives an + # improper handshake response. + # + def test_begin_conversation_with_improper_response_to_greeting + @session.should_receive(:write).with("HELLO?\n").once().returns { |greeting| greeting.length } + @session.should_receive(:readline).once().returns { "SUP?" } + + assert_raise(Exception) { @browser.begin_conversation } + end + + # Ensures the server accepts a proper response from the remote system. + # + def test_begin_conversation + @session.should_receive(:write).with("HELLO?\n").once().returns { |greeting| greeting.length } + @session.should_receive(:readline).once().returns { "HELLO!\n" } + + assert_nothing_raised(Exception) { @browser.begin_conversation } + end + + # Ensures that the server is satisfied if the remote system is + # making a wakeup call. + # + def test_get_mode_with_awaken_request + @session.should_receive(:write).with("MODE?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "AWAKEN\n" } + + result = @browser.get_mode() + + assert_equal "AWAKEN", result, "method did not return the right value" + end + + # Ensures the host browser generates a keytab as expected. + # + def test_create_keytab + @krb5.should_receive(:get_default_realm).once().returns { "ovirt-test-realm" } + servername = `hostname -f`.chomp + @session.should_receive(:write).with("KTAB http://#{servername}/ipa/config/127.0.0.1-libvirt.tab\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ACK\n" } + + assert_nothing_raised(Exception) { @browser.create_keytab('localhost','127.0.0.1', at krb5) } + end + + # Ensures that, if a keytab is present and a key version number available, + # the server ends the conversation by returning the key version number. + # + def test_end_conversation + @session.should_receive(:write).with("BYE\n").once().returns { |request| request.length } + + assert_nothing_raised(Exception) { @browser.end_conversation } + end + +end diff --git a/wui/src/host-browser/test-host-browser-awaken.rb b/wui/src/host-browser/test-host-browser-awaken.rb deleted file mode 100755 index a5ca2e7..0000000 --- a/wui/src/host-browser/test-host-browser-awaken.rb +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/ruby -Wall -# -# Copyright (C) 2008 Red Hat, Inc. -# Written by Darryl L. Pierce -# -# 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 File.dirname(__FILE__) + '/../test/test_helper' -require 'test/unit' -require 'flexmock/test_unit' - -TESTING=true - -require 'host-browser' - -# +TestHostBrowserAwaken+ -class TestHostBrowserAwaken < Test::Unit::TestCase - - def setup - @session = flexmock('session') - @session.should_receive(:peeraddr).at_least.once.returns { [nil,nil,nil,"192.168.2.255"] } - - @krb5 = flexmock('krb5') - - @browser = HostBrowser.new(@session) - @browser.logfile = './unit-test.log' - @browser.keytab_dir = '/var/temp/' - end - - # Ensures that the server raises an exception when it receives an - # improper handshake response. - # - def test_begin_conversation_with_improper_response_to_greeting - @session.should_receive(:write).with("HELLO?\n").once().returns { |greeting| greeting.length } - @session.should_receive(:readline).once().returns { "SUP?" } - - assert_raise(Exception) { @browser.begin_conversation } - end - - # Ensures the server accepts a proper response from the remote system. - # - def test_begin_conversation - @session.should_receive(:write).with("HELLO?\n").once().returns { |greeting| greeting.length } - @session.should_receive(:readline).once().returns { "HELLO!\n" } - - assert_nothing_raised(Exception) { @browser.begin_conversation } - end - - # Ensures that the server is satisfied if the remote system is - # making a wakeup call. - # - def test_get_mode_with_awaken_request - @session.should_receive(:write).with("MODE?\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "AWAKEN\n" } - - result = @browser.get_mode() - - assert_equal "AWAKEN", result, "method did not return the right value" - end - - # Ensures the host browser generates a keytab as expected. - # - def test_create_keytab - @krb5.should_receive(:get_default_realm).once().returns { "ovirt-test-realm" } - servername = `hostname -f`.chomp - @session.should_receive(:write).with("KTAB http://#{servername}/config/127.0.0.1-libvirt.tab\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "ACK\n" } - - assert_nothing_raised(Exception) { @browser.create_keytab('localhost','127.0.0.1', at krb5) } - end - - # Ensures that, if a keytab is present and a key version number available, - # the server ends the conversation by returning the key version number. - # - def test_end_conversation - @session.should_receive(:write).with("BYE\n").once().returns { |request| request.length } - - assert_nothing_raised(Exception) { @browser.end_conversation } - end - -end diff --git a/wui/src/host-browser/test-host-browser-identify.rb b/wui/src/host-browser/test-host-browser-identify.rb index 8f215e9..4197e19 100755 --- a/wui/src/host-browser/test-host-browser-identify.rb +++ b/wui/src/host-browser/test-host-browser-identify.rb @@ -27,136 +27,219 @@ TESTING=true require 'host-browser' class TestHostBrowser < Test::Unit::TestCase - - def setup - @session = flexmock('session') - @session.should_receive(:peeraddr).at_least.once.returns { [nil,nil,nil,"192.168.2.255"] } - - @browser = HostBrowser.new(@session) - @browser.logfile = './unit-test.log' - - # default host info - @host_info = {} - @host_info['UUID'] = 'node1' - @host_info['IPADDR'] = '192.168.2.2' - @host_info['HOSTNAME'] = 'node1.ovirt.redhat.com' - @host_info['NUMCPUS'] = '3' - @host_info['CPUSPEED'] = '3' - @host_info['ARCH'] = 'x86_64' - @host_info['MEMSIZE'] = '16384' - @host_info['DISABLED'] = '0' - end - - # Ensures that the server is satisfied if the remote system is - # making a wakeup call. - # - def test_get_mode_with_awaken_request - @session.should_receive(:write).with("MODE?\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "IDENTIFY\n" } - - result = @browser.get_mode() - - assert_equal "IDENTIFY", result, "method did not return the right value" - end - - # Ensures that, if an info field is missing a key, the server raises - # an exception. - # - def test_get_info_with_missing_key - @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "=value1\n" } - - assert_raise(Exception) { @browser.get_remote_info } - end - - # Ensures that, if an info field is missing a value, the server raises - # an exception. - # - def test_get_info_with_missing_value - @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "key1=\n" } - - assert_raise(Exception) { @browser.get_remote_info } - end - - # Ensures that, if the server gets a poorly formed ending statement, it - # raises an exception. - # - def test_get_info_with_invalid_end - @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "key1=value1\n" } - @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "ENDIFNO\n" } - - assert_raise(Exception) { @browser.get_remote_info } - end - - # Ensures that a well-formed transaction works as expected. - # - def test_get_info - @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "key1=value1\n" } - @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "key2=value2\n" } - @session.should_receive(:write).with("ACK key2\n").once().returns { |request| request.length } - @session.should_receive(:readline).once().returns { "ENDINFO\n" } - - info = @browser.get_remote_info - - assert_equal 4,info.keys.size, "Should contain two keys" - assert info.include?("IPADDR") - assert info.include?("HOSTNAME") - assert info.include?("key1") - assert info.include?("key2") - end - - # Ensures that the server is fine when no UUID is present. - # - def test_write_host_info_with_missing_uuid - @host_info['UUID'] = nil - - assert_nothing_raised { @browser.write_host_info(@host_info) } - end - - # Ensures that, if the hostname is missing, the server - # raises an exception. - # - def test_write_host_info_with_missing_hostname - @host_info['HOSTNAME'] = nil - - assert_raise(Exception) { @browser.write_host_info(@host_info) } - end - - # Ensures that, if the number of CPUs is missing, the server raises an exception. - # - def test_write_host_info_with_missing_numcpus - @host_info['NUMCPUS'] = nil - - assert_raise(Exception) { @browser.write_host_info(@host_info) } - end - - # Ensures that, if the CPU speed is missing, the server raises an exception. - # - def test_write_host_info_with_missing_cpuspeed - @host_info['CPUSPEED'] = nil - - assert_raise(Exception) { @browser.write_host_info(@host_info) } - end - - # Ensures that, if the architecture is missing, the server raises an exception. - # - def test_write_host_info_with_missing_arch - @host_info['ARCH'] = nil - - assert_raise(Exception) { @browser.write_host_info(@host_info) } - end - - # Ensures that, if the memory size is missing, the server raises an exception. - # - def test_write_host_info_info_with_missing_memsize - @host_info['MEMSIZE'] = nil - - assert_raise(Exception) { @browser.write_host_info(@host_info) } - end + def setup + @session = flexmock('session') + @session.should_receive(:peeraddr).at_least.once.returns { [nil,nil,nil,"192.168.2.255"] } + + @browser = HostBrowser.new(@session) + @browser.logfile = './unit-test.log' + + # default host info + @host_info = {} + @host_info['UUID'] = 'node1' + @host_info['IPADDR'] = '192.168.2.2' + @host_info['HOSTNAME'] = 'node1.ovirt.redhat.com' + @host_info['ARCH'] = 'x86_64' + @host_info['MEMSIZE'] = '16384' + @host_info['DISABLED'] = '0' + + @host_info['NUMCPUS'] = '2' + + @host_info['CPUINFO'] = Array.new + @host_info['CPUINFO'][0] = {} + @host_info['CPUINFO'][0]['CPUNUM'] = '0' + @host_info['CPUINFO'][0]['CORENUM'] = '0' + @host_info['CPUINFO'][0]['NUMCORES'] = '2' + @host_info['CPUINFO'][0]['VENDOR'] = 'GenuineIntel' + @host_info['CPUINFO'][0]['MODEL'] = '15' + @host_info['CPUINFO'][0]['FAMILY'] = '6' + @host_info['CPUINFO'][0]['CPUIDLVL'] = '10' + @host_info['CPUINFO'][0]['SPEED'] = '3' + @host_info['CPUINFO'][0]['CACHE'] = '4096 kb' + @host_info['CPUINFO'][0]['FLAGS'] = 'fpu vme de pse tsc msr pae \ + mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx \ + fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs \ + bts pni monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr lahf_lm' + + @host_info['CPUINFO'][1] = {} + @host_info['CPUINFO'][1]['CPUNUM'] = '1' + @host_info['CPUINFO'][1]['CORENUM'] = '1' + @host_info['CPUINFO'][1]['NUMCORES'] = '2' + @host_info['CPUINFO'][1]['VENDOR'] = 'GenuineIntel' + @host_info['CPUINFO'][1]['MODEL'] = '15' + @host_info['CPUINFO'][1]['FAMILY'] = '6' + @host_info['CPUINFO'][1]['CPUIDLVL'] = '10' + @host_info['CPUINFO'][1]['SPEED'] = '3' + @host_info['CPUINFO'][1]['CACHE'] = '4096 kb' + @host_info['CPUINFO'][1]['FLAGS'] = 'fpu vme de pse tsc msr pae \ + mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx \ + fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs \ + bts pni monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr lahf_lm' + end + + # Ensures that the server is satisfied if the remote system is + # making a wakeup call. + # + def test_get_mode_with_awaken_request + @session.should_receive(:write).with("MODE?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "IDENTIFY\n" } + + result = @browser.get_mode() + + assert_equal "IDENTIFY", result, "method did not return the right value" + end + + # Ensures that, if an info field is missing a key, the server raises + # an exception. + # + def test_get_info_with_missing_key + @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "=value1\n" } + + assert_raise(Exception) { @browser.get_remote_info } + end + + # Ensures that, if an info field is missing a value, the server raises + # an exception. + # + def test_get_info_with_missing_value + @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key1=\n" } + + assert_raise(Exception) { @browser.get_remote_info } + end + + # Ensures that, if the server gets a poorly formed ending statement, it + # raises an exception. + # + def test_get_info_with_invalid_end + @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key1=value1\n" } + @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDIFNO\n" } + + assert_raise(Exception) { @browser.get_remote_info } + end + + # Ensures that a well-formed transaction works as expected. + # + def test_get_info + @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key1=value1\n" } + @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key2=value2\n" } + @session.should_receive(:write).with("ACK key2\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDINFO\n" } + + info = @browser.get_remote_info + + assert_equal 4,info.keys.size, "Should contain four keys" + assert info.include?("IPADDR") + assert info.include?("HOSTNAME") + assert info.include?("key1") + assert info.include?("key2") + end + + # Ensures that the server is fine when no UUID is present. + # + def test_write_host_info_with_missing_uuid + @host_info['UUID'] = nil + + assert_nothing_raised { @browser.write_host_info(@host_info) } + end + + # Ensures that, if the hostname is missing, the server + # raises an exception. + # + def test_write_host_info_with_missing_hostname + @host_info['HOSTNAME'] = nil + + assert_raise(Exception) { @browser.write_host_info(@host_info) } + end + + # Ensures that, if the architecture is missing, the server raises an + # exception. + # + def test_write_host_info_with_missing_arch + @host_info['ARCH'] = nil + + assert_raise(Exception) { @browser.write_host_info(@host_info) } + end + + # Ensures that, if the memory size is missing, the server raises an + # exception. + # + def test_write_host_info_info_with_missing_memsize + @host_info['MEMSIZE'] = nil + + assert_raise(Exception) { @browser.write_host_info(@host_info) } + end + + # Ensures that, if no cpu info was available, the server raises an + # exception. + # + def test_write_host_info_with_missing_cpuinfo + @host_info['CPUINFO'] = nil + + assert_raise(Exception) { @browser.write_host_info(@host_info) } + end + + # Ensures the browser can properly parse the CPU details. + # + def test_parse_cpu_info + @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "CPU\n" } + @session.should_receive(:write).with("CPUINFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key1=value1\n" } + @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key2=value2\n" } + @session.should_receive(:write).with("ACK key2\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDCPU\n" } + @session.should_receive(:write).with("ACK CPU\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDINFO\n" } + + info = @browser.get_remote_info + + assert_equal 3,info.keys.size, "Should contain four keys" + assert info.include?("CPUINFO") + end + + # Ensures the browser can properly parse the CPU details of two CPUs. + # + def test_parse_cpu_info + @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } + + # CPU 0 + @session.should_receive(:readline).once().returns { "CPU\n" } + @session.should_receive(:write).with("CPUINFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key1=value1\n" } + @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key2=value2\n" } + @session.should_receive(:write).with("ACK key2\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDCPU\n" } + @session.should_receive(:write).with("ACK CPU\n").once().returns { |request| request.length } + + # CPU 1 + @session.should_receive(:readline).once().returns { "CPU\n" } + @session.should_receive(:write).with("CPUINFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key3=value3\n" } + @session.should_receive(:write).with("ACK key3\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key4=value4\n" } + @session.should_receive(:write).with("ACK key4\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDCPU\n" } + @session.should_receive(:write).with("ACK CPU\n").once().returns { |request| request.length } + + @session.should_receive(:readline).once().returns { "ENDINFO\n" } + + info = @browser.get_remote_info + + assert_equal 3,info.keys.size, "Should contain four keys" + assert info.include?('CPUINFO') + assert_equal 2, info['CPUINFO'].size, "Should contain details for two CPUs" + assert_not_nil info['CPUINFO'][0]['key1'] + assert_not_nil info['CPUINFO'][0]['key2'] + assert_not_nil info['CPUINFO'][1]['key3'] + assert_not_nil info['CPUINFO'][1]['key4'] + end end diff --git a/wui/src/test/fixtures/cpus.yml b/wui/src/test/fixtures/cpus.yml new file mode 100644 index 0000000..5586303 --- /dev/null +++ b/wui/src/test/fixtures/cpus.yml @@ -0,0 +1,21 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html + +one: + cpu_number: 1 + core_number: 1 + cpu_id_level: 1 + vendor: 1 + family: 1 + model: 1 + family: MyString + flags: MyString + +two: + cpu_number: 1 + core_number: 1 + cpu_id_level: 1 + vendor: 1 + family: 1 + model: 1 + family: MyString + flags: MyString diff --git a/wui/src/test/fixtures/hosts.yml b/wui/src/test/fixtures/hosts.yml index 3b93aea..f10a756 100644 --- a/wui/src/test/fixtures/hosts.yml +++ b/wui/src/test/fixtures/hosts.yml @@ -2,8 +2,6 @@ one: id: 1 uuid: '1148fdf8-961d-11dc-9387-001558c41534' hostname: 'prod.corp.com' - num_cpus: 8 - cpu_speed: 4096 arch: 'i686' memory: 18384 is_disabled: 0 @@ -13,8 +11,6 @@ two: id: 2 uuid: '1f2a8694-961d-11dc-9387-001558c41534' hostname: 'myworkstation.dev.corp.com' - num_cpus: 4 - cpu_speed: 2048 arch: 'i386' memory: 2048 is_disabled: 0 @@ -24,30 +20,24 @@ three: id: 3 uuid: '58a85f44-75fd-4934-805f-88e45b40d4b4' hostname: 'macworkstation.foobar.com' - num_cpus: 8 - cpu_speed: 1024 arch: 'mips' memory: 2048 - is_disabled: 0 + is_disabled: 0 hypervisor_type: 'kvm' hardware_pool_id: 3 four: id: 4 uuid: '520bbb34-6515-490e-9d07-0c8b14f76805' hostname: 'fedoraworkstation.foobar.com' - num_cpus: 8 - cpu_speed: 3072 arch: 'i386' memory: 2048 - is_disabled: 1 + is_disabled: 1 hypervisor_type: 'kvm' hardware_pool_id: 3 five: id: 5 uuid: '2e422f66-324e-48d4-973f-0b91b33070f9' hostname: 'pipeline.foobar.com' - num_cpus: 32 - cpu_speed: 4096 arch: 'xeon' memory: 1048576 is_disabled: 0 @@ -57,19 +47,15 @@ six: id: 6 uuid: 'bb0ce7c7-f234-49ae-84b5-6f4fd8bddcaa' hostname: 'prod.foobar.com' - num_cpus: 32 - cpu_speed: 4096 arch: 'xeon' memory: 16384 - is_disabled: 0 + is_disabled: 0 hypervisor_type: 'kvm' hardware_pool_id: 3 seven: id: 7 uuid: '6ae3d22e-97e0-4d86-9712-5395b20a0f45' hostname: 'mystation.dev.corp.com' - num_cpus: 4 - cpu_speed: 3072 arch: 'i686' memory: 2048 is_disabled: 0 @@ -79,8 +65,6 @@ eight: id: 8 uuid: 'ec0d86de-657b-48f6-b7cc-e733a3f9a834' hostname: 'issue.qa.corp.com' - num_cpus: 8 - cpu_speed: 4096 arch: 'x86' memory: 4096 is_disabled: 0 @@ -90,8 +74,6 @@ nine: id: 9 uuid: '81c15560-dbf4-45f5-9b75-106cdbd63aeb' hostname: 'somehost' - num_cpus: 4 - cpu_speed: 4096 arch: 'x86' memory: 4096 is_disabled: 0 diff --git a/wui/src/test/unit/cpu_test.rb b/wui/src/test/unit/cpu_test.rb new file mode 100644 index 0000000..5b64ca7 --- /dev/null +++ b/wui/src/test/unit/cpu_test.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class CpuTest < ActiveSupport::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end -- 1.5.5.1 From fj0588di at aa.jp.fujitsu.com Wed Jul 9 12:04:08 2008 From: fj0588di at aa.jp.fujitsu.com (S.Sakamoto) Date: Wed, 9 Jul 2008 21:04:08 +0900 Subject: [Ovirt-devel] [Q]Can VM start in Developer Version? Message-ID: <200807092104.CDA57722.90JGEK96@aa.jp.fujitsu.com> Hi, I have a question. Can VM start in Developer Version? I install the Developer Version on x86 machine. When I make VM on this environment and do "start", The following error is output on taskomatic.log, and "start" failed. libvir: QEMU error : internal error QEMU quit during console startup open /dev/kvm: No such file or directory Could not initialize KVM, will disable KVM support Could not allocate physical memory start_vm Task action processing failed: Libvirt::Error: Call to function virDomainCreate failed The operation is as follows ------------------------------------------------------------ 1. (on console)virsh start developer 2. (on console)virsh start node3 3. (on WebUI)make Hadware Pool and add Node3 to this pool. 4. (on WebUI)add an iSCSI storage of developer to HardwarePool. 5. (on WebUI)make VmMachinePool and make VM1 on this pool. 6. (on WebUI)do start VM1. ------------------------------------------------------------ On Node3, I was able to confirm that VM1 was defined with "virsh list". An same error was output when I try "virsh start VM1" on Node3. Because /dev/kvm does not exist on Node3 and cannot load "kvm-intel or kvm-amd", I was not able to solve this error. First of all, Can VM start in Developer Version? If it can do, please teach me a right method to start VM. Thanks, Shigeki Sakamoto. From clalance at redhat.com Wed Jul 9 12:08:38 2008 From: clalance at redhat.com (Chris Lalancette) Date: Wed, 09 Jul 2008 14:08:38 +0200 Subject: [Ovirt-devel] [Q]Can VM start in Developer Version? In-Reply-To: <200807092104.CDA57722.90JGEK96@aa.jp.fujitsu.com> References: <200807092104.CDA57722.90JGEK96@aa.jp.fujitsu.com> Message-ID: <4874AA46.9050607@redhat.com> S.Sakamoto wrote: > Hi, > > I have a question. > Can VM start in Developer Version? In theory, yes. In practice, you might run into a problem (see below). > I install the Developer Version on x86 machine. > > When I make VM on this environment and do "start", > The following error is output on taskomatic.log, and "start" failed. > > libvir: QEMU error : internal error QEMU quit during console startup > open /dev/kvm: No such file or directory > Could not initialize KVM, will disable KVM support > Could not allocate physical memory > start_vm > Task action processing failed: Libvirt::Error: Call to function virDomainCreate failed OK, so the "Could not initialize KVM" error is not fatal; it just means your guests will be using Qemu for full emulation, which is expected in the developer version. The part that does seem fatal is the "Could not allocate physical memory". By default, we only give 512MB to the "fake" managed nodes (such as node3); as such, there isn't a lot of room for guests on there. What size guest were you trying to run? My guess is that if you increase the size of the managed node, you will then be able to start your guest. You can modify the managed node by doing something like: # virsh dumpxml node3 > node3.xml # virsh define node3.xml # virsh start node3 Which should give you additional memory to start a guest in node3. Chris Lalancette From mdehaan at redhat.com Wed Jul 9 13:12:08 2008 From: mdehaan at redhat.com (Michael DeHaan) Date: Wed, 09 Jul 2008 09:12:08 -0400 Subject: [Ovirt-devel] Skipping the Browser :) Message-ID: <4874B928.9060802@redhat.com> Hi folks, The "Breaking the browser thread" has been interesting :) I definitely agree on the importance of using /existing/ monitoring and trending tech (which is all the more likely to already be in use at a given shop, or be usable by another app on the network) and not focusing too much on shiny AJAX bits, and definitely not something that has weak OSS support like Flash. This reminded me of something I wanted to bring up -- basically, I wondering about what happens when we don't have the (ovirt) browser :) I'm pretty much a backend guy, and administrators I deal with love scripts and command line tools. More so, one of the things I am looking out for is integration with other applications in the future, one of them being Spacewalk (http://fedorahosted.org/spacewalk). So, in this case, we'd be hoping to see ovirt more as a web service than a GUI application. This is basically what we are doing with Cobbler -- it has it's own GUI, but Spacewalk is probably just going to use it as a web service. Is everything in ovirt that can be accessed as a GUI (and performed by the GUI) accessible as a web service (by this, I mean something simple like XMLRPC or JSON-over-REST?). Can there also be an ovirt command line for simple scripting integration? I can see it being highly useful to saying "find where to put this VM and give it storage and make it so (which in turn calls Cobbler API's)" though all of this may need to be exposed via other interfaces, scripts, and so on. If there are docs somewhere on how to go about playing with that kind of stuff, I'd like to take a look at it. --Michael From apevec at redhat.com Wed Jul 9 13:09:48 2008 From: apevec at redhat.com (Alan Pevec) Date: Wed, 09 Jul 2008 15:09:48 +0200 Subject: [Ovirt-devel] [PATCH] ovirt-identify-node now submits all extended CPU details. In-Reply-To: <1215525963-16483-1-git-send-email-dpierce@redhat.com> References: <1215525963-16483-1-git-send-email-dpierce@redhat.com> Message-ID: <4874B89C.4070909@redhat.com> ACK functionality tested with updated ovirt-wui and ovirt-host-image RPMs rake db:migrate also worked (please add a notice how to upgrade db in the commit msg) general issue for all startup scripts: logging should be redirected from stdout and for readability log() introduced instead of fprintf(stdout,... From clalance at redhat.com Wed Jul 9 13:16:14 2008 From: clalance at redhat.com (Chris Lalancette) Date: Wed, 09 Jul 2008 15:16:14 +0200 Subject: [Ovirt-devel] [PATCH]: First cut of the taskomatic migration patch Message-ID: <4874BA1E.4000605@redhat.com> All, I know I promised a taskomatic migration patch "early this week", but then early turned into later :). Anyway, here is the first cut of it. I haven't really had a chance to test it because of various problems with pungi, but that's up next. Also note that to have any hope of this working, you need an updated libvirt package with rjones' KVM migration patch; packages are here: http://koji.fedoraproject.org/koji/taskinfo?taskID=701124 Once I solve my pungi problems I'll start trying to test it; if we confirm that the libvirt KVM migration patch works, then we can get it into libvirt proper pretty easily. Chris Lalancette -------------- next part -------------- A non-text attachment was scrubbed... Name: taskomatic-migration.patch Type: text/x-patch Size: 5006 bytes Desc: not available URL: From clalance at redhat.com Wed Jul 9 13:20:15 2008 From: clalance at redhat.com (Chris Lalancette) Date: Wed, 09 Jul 2008 15:20:15 +0200 Subject: [Ovirt-devel] Skipping the Browser :) In-Reply-To: <4874B928.9060802@redhat.com> References: <4874B928.9060802@redhat.com> Message-ID: <4874BB0F.7020903@redhat.com> Michael DeHaan wrote: > Is everything in ovirt that can be accessed as a GUI (and performed by > the GUI) accessible as a web service (by this, I mean something simple > like XMLRPC or JSON-over-REST?). Can there also be an ovirt command > line for simple scripting integration? The answer right now is "no", but it's something basically everyone has asked for, so it's definitely on the roadmap. We have to define the API, then implement the underlying API, and then (possibly) port the web application over to using that API. Agreed that it is a very useful thing to have. Chris Lalancette From mdehaan at redhat.com Wed Jul 9 13:28:25 2008 From: mdehaan at redhat.com (Michael DeHaan) Date: Wed, 09 Jul 2008 09:28:25 -0400 Subject: [Ovirt-devel] Details about pending cobbler image support & ovirt integration Message-ID: <4874BCF9.7030900@redhat.com> Hi folks, So I'm still working on the image tracking support for Cobbler ... I've been a bit sidetracked with other Cobbler/Func items though this is the /big/ item for Cobbler 1.1. Anyhow, I wanted to provide a basic summary of what will be going on there in Cobbler land to make sure we're all on the same page, and that ovirt can get what it wants out of this. I should also add that I am more than happy to take patches if you'd like to work on Cobbler directly :) Essentially the idea is that cobbler contains a series of related objects.... Distros, Profiles, Systems, and Repos at the base level. In ovirt's case, we do not care so much about repos. A distro record contains info about a kernel, initrd, and tree -- and maybe some additional kernel options and so forth. A profile takes a distro and adds a kickstart, and specific parameters that (if providing a virtual install environment) pass extra parameters to python-virtinst when invoked with koan. A system takes a profile and customizes it further -- for instance, it may add networking info or specific kickstart or kernel options customizations. Images are the new object. We want cobbler to track them like other objects. # cobbler image add --name=QuestionableRemondInstallISO --file=/mnt/nfs/blah/foo.img Then we are going to teach koan about images. Currently koan can be used to reinstall existing systems or launch VM installations, but it doesn't know about images. This will look like: # koan --server=cobbler.example.org --image=QuestionableRemondInstallISO --virt And that will kick of the install using the centrally managed parameters. The next thing to do after getting fullvirt ISO tracking done is to make sure --file can just take NFS urls and mount them (I'll look into the libvirt storage stuff for this). After that, we also teach "cobbler image add" to track images that can be fed to virt-image, AKA virt disk images. This will have a similar syntax, most likely... # cobbler image add --name=MysteryOS --file=/mnt/nfs/blah/foo.img --image-type=blah [--virt-ram=] [--virt-disk=] [etc] The --virt parameters will work basically as they do with cobbler profiles today. All of the cobbler image stuff will also be accessible over the web service. So most likely ovirt would have to make the calls to add new images (and their details) into the "registry" (via cobbler XMLRPC) and then on the host end, make the right calls to koan to replicate them on demand. The next logical step after handling virt-images is perhaps teaching cobbler about physical images and cloning tools, though I'm much more interested in the virt case, as I have no problem if all the hypervisors out there have to run Linux :) The other thing we might want to talk about are cobbler triggers, which could be written to notify ovirt of changes to the cobbler configuration -- this is similar to something we are planning with Spacewalk. In general, I think ovirt would mostly be giving orders to cobbler, but if someone makes a change outside of cobbler, like deleting a virt-image ovirt wants to have used, it should probably have a way of knowing it should re-scan cobbler XMLRPC to see what changed. Kerberos authorization can be configured here ... https://fedorahosted.org/cobbler/wiki/CobblerWithKerberos though I should mention I found a way to get cobbler to authenticate against Spacewalk here... https://www.redhat.com/archives/spacewalk-devel/2008-July/msg00024.html -- in that general theme, it would be possible to write a cobbler auth plugin that allowed Cobbler to defer authorization of it's own API into ovirt if we really wanted to. That probably won't be neccessary though, but I thought I'd throw it out there. The other thing I'd like to see is Cobbler managing /tftpboot for ovirt and PXE for ovirt, which I think was something you wanted to do. All of those APIs are stable now -- if someone wants pointers on how all that works just let me know. Thanks! --Michael From clalance at redhat.com Wed Jul 9 15:44:27 2008 From: clalance at redhat.com (Chris Lalancette) Date: Wed, 09 Jul 2008 17:44:27 +0200 Subject: [Ovirt-devel] [PATCH]: Configure iptables on the managed node Message-ID: <4874DCDB.30507@redhat.com> One of the side-effects of the SELinux support that recently went into livecd-tools (and is now in Fedora 9) is that it runs lokkit at the end of installation. This results in the default firewall being applied to the managed node. In general, this is a good thing, but we need to customize that firewall to allow incoming ssh and incoming libvirt, at the very least (there may be more in the future). The attached patch just configures the firewall in %post, and with this in place I can successfully ssh into the managed node and use remote libvirt commands. Signed-off-by: Chris Lalancette -------------- next part -------------- A non-text attachment was scrubbed... Name: ovirt-iptables.patch Type: text/x-patch Size: 971 bytes Desc: not available URL: From dpierce at redhat.com Wed Jul 9 19:51:17 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 9 Jul 2008 15:51:17 -0400 Subject: [Ovirt-devel] [PATCH] Redirecting all logs to /var/log/ovirt.log Message-ID: <1215633077-29050-1-git-send-email-dpierce@redhat.com> From: Darryl Pierce Signed-off-by: Darryl L. Pierce --- ovirt-managed-node/src/scripts/ovirt | 21 ++++++++++++--------- ovirt-managed-node/src/scripts/ovirt-early | 20 +++++++++++--------- ovirt-managed-node/src/scripts/ovirt-functions | 5 ++++- ovirt-managed-node/src/scripts/ovirt-post | 18 ++++++++++-------- 4 files changed, 37 insertions(+), 27 deletions(-) diff --git a/ovirt-managed-node/src/scripts/ovirt b/ovirt-managed-node/src/scripts/ovirt index 92a0e40..4f86c23 100755 --- a/ovirt-managed-node/src/scripts/ovirt +++ b/ovirt-managed-node/src/scripts/ovirt @@ -18,7 +18,8 @@ start() { if [ ! -s $krb5_conf ]; then rm -f $krb5_conf # FIXME this is IPA specific - wget -q http://$SRV_HOST:$SRV_PORT/ipa/config/krb5.ini -O $krb5_conf \ + wget -nv \ + http://$SRV_HOST:$SRV_PORT/ipa/config/krb5.ini -O $krb5_conf \ || die "Failed to get $krb5_conf" fi IPA_HOST=$SRV_HOST @@ -41,11 +42,13 @@ start() { echo } -case "$1" in - start) - start - ;; - *) - echo "Usage: ovirt {start}" - exit 2 -esac +{ + case "$1" in + start) + start + ;; + *) + echo "Usage: ovirt {start}" + exit 2 + esac +} | tee -a $OVIRT_LOGFILE diff --git a/ovirt-managed-node/src/scripts/ovirt-early b/ovirt-managed-node/src/scripts/ovirt-early index 4116847..066b175 100755 --- a/ovirt-managed-node/src/scripts/ovirt-early +++ b/ovirt-managed-node/src/scripts/ovirt-early @@ -27,7 +27,7 @@ configure_from_network() { find_srv ovirt tcp printf . if [ -n "$SRV_HOST" -a -n "$SRV_PORT" ]; then - wget --quiet -O - "http://$SRV_HOST:$SRV_PORT/ovirt/cfgdb/$(hostname)" \ + wget -nv -O - "http://$SRV_HOST:$SRV_PORT/ovirt/cfgdb/$(hostname)" \ | augtool > /dev/null 2>&1 if [ $? -eq 0 ]; then printf "remote config applied." @@ -94,11 +94,13 @@ start() { done } -case "$1" in - start) - start - ;; - *) - echo "Usage: ovirt-early {start}" - exit 2 -esac +{ + case "$1" in + start) + start + ;; + *) + echo "Usage: ovirt-early {start}" + exit 2 + esac +} | tee -a $OVIRT_LOGFILE diff --git a/ovirt-managed-node/src/scripts/ovirt-functions b/ovirt-managed-node/src/scripts/ovirt-functions index 9974533..5b530f7 100644 --- a/ovirt-managed-node/src/scripts/ovirt-functions +++ b/ovirt-managed-node/src/scripts/ovirt-functions @@ -1,6 +1,9 @@ # -*-Shell-script-*- -find_srv() { +OVIRT_LOGFILE=/var/log/ovirt.log + +find_srv() +{ local dnsreply dnsreply=$(dig +short -t srv _$1._$2.$(dnsdomainname)) if [ $? -eq 0 ]; then diff --git a/ovirt-managed-node/src/scripts/ovirt-post b/ovirt-managed-node/src/scripts/ovirt-post index 3bb0f6d..130d6b6 100755 --- a/ovirt-managed-node/src/scripts/ovirt-post +++ b/ovirt-managed-node/src/scripts/ovirt-post @@ -27,11 +27,13 @@ start() { echo } -case "$1" in - start) - start - ;; - *) - echo "Usage: ovirt-post {start}" - exit 2 -esac +{ + case "$1" in + start) + start + ;; + *) + echo "Usage: ovirt-post {start}" + exit 2 + esac +} | tee -a $OVIRT_LOGFILE -- 1.5.5.1 From clalance at redhat.com Wed Jul 9 20:15:21 2008 From: clalance at redhat.com (Chris Lalancette) Date: Wed, 09 Jul 2008 22:15:21 +0200 Subject: [Ovirt-devel] [PATCH REPOST]: Configure iptables on the managed node Message-ID: <48751C59.1090206@redhat.com> I totally forgot the COMMIT line in the iptables stuff; not sure how it worked last time without that. Anyway, here is the updated patch; ignore the last one. One of the side-effects of the SELinux support that recently went into livecd-tools (and is now in Fedora 9) is that it runs lokkit at the end of installation. This results in the default firewall being applied to the managed node. In general, this is a good thing, but we need to customize that firewall to allow incoming ssh and incoming libvirt, at the very least (there may be more in the future). The attached patch just configures the firewall in %post, and with this in place I can successfully ssh into the managed node and use remote libvirt commands. Signed-off-by: Chris Lalancette -------------- next part -------------- A non-text attachment was scrubbed... Name: ovirt-iptables-2.patch Type: text/x-patch Size: 979 bytes Desc: not available URL: From dpierce at redhat.com Wed Jul 9 20:21:57 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 9 Jul 2008 16:21:57 -0400 Subject: [Ovirt-devel] [PATCH] Fix the attributes for the log rotate script. Message-ID: <1215634917-30933-1-git-send-email-dpierce@redhat.com> Signed-off-by: Darryl L. Pierce --- ovirt-managed-node/ovirt-managed-node.spec | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/ovirt-managed-node/ovirt-managed-node.spec b/ovirt-managed-node/ovirt-managed-node.spec index fa943f5..4e14b08 100644 --- a/ovirt-managed-node/ovirt-managed-node.spec +++ b/ovirt-managed-node/ovirt-managed-node.spec @@ -54,7 +54,7 @@ make %{__install} -p -m0755 scripts/ovirt-setup %{buildroot}%{app_root} -%{__install} -p -m0644 logrotate/ovirt-logrotate %{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 %clean -- 1.5.5.1 From apevec at redhat.com Wed Jul 9 20:22:45 2008 From: apevec at redhat.com (Alan Pevec) Date: Wed, 09 Jul 2008 22:22:45 +0200 Subject: [Ovirt-devel] [PATCH] Fix the attributes for the log rotate script. In-Reply-To: <1215634917-30933-1-git-send-email-dpierce@redhat.com> References: <1215634917-30933-1-git-send-email-dpierce@redhat.com> Message-ID: <48751E15.7090206@redhat.com> ACK From dpierce at redhat.com Wed Jul 9 20:32:01 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 9 Jul 2008 16:32:01 -0400 Subject: [Ovirt-devel] [PATCH] Fix the attributes for the log rotate script. Message-ID: <1215635521-31891-1-git-send-email-dpierce@redhat.com> Signed-off-by: Darryl L. Pierce --- wui/src/host-browser/host-browser.rb | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/wui/src/host-browser/host-browser.rb b/wui/src/host-browser/host-browser.rb index e66493d..3b3d0cd 100755 --- a/wui/src/host-browser/host-browser.rb +++ b/wui/src/host-browser/host-browser.rb @@ -217,6 +217,8 @@ class HostBrowser host.cpus << detail end + host.save + return host end -- 1.5.5.1 From clalance at redhat.com Wed Jul 9 20:35:36 2008 From: clalance at redhat.com (Chris Lalancette) Date: Wed, 09 Jul 2008 22:35:36 +0200 Subject: [Ovirt-devel] [PATCH] Fix the attributes for the log rotate script. In-Reply-To: <1215635521-31891-1-git-send-email-dpierce@redhat.com> References: <1215635521-31891-1-git-send-email-dpierce@redhat.com> Message-ID: <48752118.6080600@redhat.com> Darryl L. Pierce wrote: > Signed-off-by: Darryl L. Pierce > --- > wui/src/host-browser/host-browser.rb | 2 ++ > 1 files changed, 2 insertions(+), 0 deletions(-) > > diff --git a/wui/src/host-browser/host-browser.rb b/wui/src/host-browser/host-browser.rb > index e66493d..3b3d0cd 100755 > --- a/wui/src/host-browser/host-browser.rb > +++ b/wui/src/host-browser/host-browser.rb > @@ -217,6 +217,8 @@ class HostBrowser > host.cpus << detail > end > > + host.save > + > return host > end We definitely need this patch, otherwise "updates" to the host (i.e. adding more memory, etc.) don't get committed to the database. Two things: 1) The subject for this patch seems wrong 2) I think putting the "host.save" at this point in "write_host_info" is the correct thing to do. We should probably remove the one further up in the "Host.create()" section, since you are duplicating going to the database in that case. Chris Lalancette From dpierce at redhat.com Wed Jul 9 20:43:49 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 9 Jul 2008 16:43:49 -0400 Subject: [Ovirt-devel] [PATCH] Moved the host saving call to after the CPU records are created. Also made it Message-ID: <1215636229-32534-1-git-send-email-dpierce@redhat.com> Signed-off-by: Darryl L. Pierce --- wui/src/host-browser/host-browser.rb | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/wui/src/host-browser/host-browser.rb b/wui/src/host-browser/host-browser.rb index e66493d..624661d 100755 --- a/wui/src/host-browser/host-browser.rb +++ b/wui/src/host-browser/host-browser.rb @@ -185,7 +185,6 @@ class HostBrowser # Let host-status mark it available when it # successfully connects to it via libvirt. "state" => Host::STATE_UNAVAILABLE) - host.save! rescue Exception => error puts "Error while creating record: #{error.message}" unless defined?(TESTING) end @@ -217,6 +216,8 @@ class HostBrowser host.cpus << detail end + host.save! + return host end -- 1.5.5.1 From clalance at redhat.com Wed Jul 9 20:44:09 2008 From: clalance at redhat.com (Chris Lalancette) Date: Wed, 09 Jul 2008 22:44:09 +0200 Subject: [Ovirt-devel] [PATCH] Moved the host saving call to after the CPU records are created. Also made it In-Reply-To: <1215636229-32534-1-git-send-email-dpierce@redhat.com> References: <1215636229-32534-1-git-send-email-dpierce@redhat.com> Message-ID: <48752319.1010608@redhat.com> Darryl L. Pierce wrote: > Signed-off-by: Darryl L. Pierce > --- > wui/src/host-browser/host-browser.rb | 3 ++- > 1 files changed, 2 insertions(+), 1 deletions(-) > > diff --git a/wui/src/host-browser/host-browser.rb b/wui/src/host-browser/host-browser.rb > index e66493d..624661d 100755 > --- a/wui/src/host-browser/host-browser.rb > +++ b/wui/src/host-browser/host-browser.rb > @@ -185,7 +185,6 @@ class HostBrowser > # Let host-status mark it available when it > # successfully connects to it via libvirt. > "state" => Host::STATE_UNAVAILABLE) > - host.save! > rescue Exception => error > puts "Error while creating record: #{error.message}" unless defined?(TESTING) > end > @@ -217,6 +216,8 @@ class HostBrowser > host.cpus << detail > end > > + host.save! > + > return host > end Yep, this one looks good. ACK Chris Lalancette From apevec at redhat.com Wed Jul 9 20:50:24 2008 From: apevec at redhat.com (Alan Pevec) Date: Wed, 09 Jul 2008 22:50:24 +0200 Subject: [Ovirt-devel] [PATCH REPOST]: Configure iptables on the managed node In-Reply-To: <48751C59.1090206@redhat.com> References: <48751C59.1090206@redhat.com> Message-ID: <48752490.3050208@redhat.com> ACK From clalance at redhat.com Wed Jul 9 21:00:34 2008 From: clalance at redhat.com (Chris Lalancette) Date: Wed, 09 Jul 2008 23:00:34 +0200 Subject: [Ovirt-devel] [PATCH REPOST]: Configure iptables on the managed node In-Reply-To: <48751C59.1090206@redhat.com> References: <48751C59.1090206@redhat.com> Message-ID: <487526F2.4050308@redhat.com> Chris Lalancette wrote: > I totally forgot the COMMIT line in the iptables stuff; not sure how it worked > last time without that. Anyway, here is the updated patch; ignore the last one. > > One of the side-effects of the SELinux support that recently went into > livecd-tools (and is now in Fedora 9) is that it runs lokkit at the end of > installation. This results in the default firewall being applied to the managed > node. In general, this is a good thing, but we need to customize that firewall > to allow incoming ssh and incoming libvirt, at the very least (there may be more > in the future). The attached patch just configures the firewall in %post, and > with this in place I can successfully ssh into the managed node and use remote > libvirt commands. Committed Chris Lalancette From dpierce at redhat.com Wed Jul 9 21:08:55 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 9 Jul 2008 17:08:55 -0400 Subject: [Ovirt-devel] [PATCH] Fixed a misnamed reference: cpu_details should have been cpus. Message-ID: <1215637735-1694-1-git-send-email-dpierce@redhat.com> Signed-off-by: Darryl L. Pierce --- wui/src/app/models/host.rb | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/wui/src/app/models/host.rb b/wui/src/app/models/host.rb index 90e18d5..e5f6264 100644 --- a/wui/src/app/models/host.rb +++ b/wui/src/app/models/host.rb @@ -72,7 +72,7 @@ class Host < ActiveRecord::Base end def num_cpus - return cpu_details.size + return cpus.size end def cpu_speed -- 1.5.5.1 From berrange at redhat.com Wed Jul 9 21:37:55 2008 From: berrange at redhat.com (Daniel P. Berrange) Date: Wed, 9 Jul 2008 22:37:55 +0100 Subject: [Ovirt-devel] [herrold@owlriver.com: Re: OLPC & package dependency growth] Message-ID: <20080709213755.GJ716@redhat.com> The idea of 4k -> 512 byte sectors probably won't help our size because the wasted space from files smaller than 4k will compress nicely with squashfs - but would killing the journal gain us any significant space ? Daniel ----- Forwarded message from R P Herrold ----- > Date: Wed, 9 Jul 2008 17:16:01 -0400 (EDT) > From: R P Herrold > To: "Daniel P. Berrange" > Subject: Re: OLPC & package dependency growth > > On Wed, 9 Jul 2008, Daniel P. Berrange wrote: > > >> On Wed, 2008-07-09 at 16:10 +0100, Daniel P. Berrange wrote: > >>> We could sure use some scripts to anaylse RPM deps on a nightly basis > >>> and produces reports on interesting stats. eg disk footprint of the > >>> chain starting from package 'X' ... We > >>> are fighting a similar battle to OLPC with the oVirt project which > >>> has a live CD we're trying to keep under 64 MB in size. > > > Extra points if you round up the sizes to 4k to take account of the > > typical ext3 blocksize which adds extra storage overhead for small > > files. > > With a known 64M cap, why not force the target empty image > into 512 byte blocks to get the minimum of wastage? AND as it > is a live CD, why pay the ext3 journal penalty -- make it ext2 > and be done with it (this may also permit a smaller kernel > footprint)? > > I ask offlist as it is not really in scope on the main thread > about stats. > > thanks -- > > -- Russ herrold > ----- End forwarded message ----- -- |: 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 Jul 9 22:33:41 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 9 Jul 2008 18:33:41 -0400 Subject: [Ovirt-devel] [PATCH] Redirecting all logs to /var/log/ovirt.log Message-ID: <1215642821-6503-1-git-send-email-dpierce@redhat.com> From: Darryl Pierce Signed-off-by: Darryl L. Pierce --- ovirt-managed-node/src/scripts/ovirt | 21 ++++++++++++--------- ovirt-managed-node/src/scripts/ovirt-awake | 2 +- ovirt-managed-node/src/scripts/ovirt-early | 20 +++++++++++--------- ovirt-managed-node/src/scripts/ovirt-functions | 5 ++++- ovirt-managed-node/src/scripts/ovirt-post | 18 ++++++++++-------- 5 files changed, 38 insertions(+), 28 deletions(-) diff --git a/ovirt-managed-node/src/scripts/ovirt b/ovirt-managed-node/src/scripts/ovirt index 92a0e40..644675b 100755 --- a/ovirt-managed-node/src/scripts/ovirt +++ b/ovirt-managed-node/src/scripts/ovirt @@ -18,7 +18,8 @@ start() { if [ ! -s $krb5_conf ]; then rm -f $krb5_conf # FIXME this is IPA specific - wget -q http://$SRV_HOST:$SRV_PORT/ipa/config/krb5.ini -O $krb5_conf \ + wget -q \ + http://$SRV_HOST:$SRV_PORT/ipa/config/krb5.ini -O $krb5_conf \ || die "Failed to get $krb5_conf" fi IPA_HOST=$SRV_HOST @@ -41,11 +42,13 @@ start() { echo } -case "$1" in - start) - start - ;; - *) - echo "Usage: ovirt {start}" - exit 2 -esac +{ + case "$1" in + start) + start + ;; + *) + echo "Usage: ovirt {start}" + exit 2 + esac +} >> $OVIRT_LOGFILE diff --git a/ovirt-managed-node/src/scripts/ovirt-awake b/ovirt-managed-node/src/scripts/ovirt-awake index 4e43d45..38d405e 100755 --- a/ovirt-managed-node/src/scripts/ovirt-awake +++ b/ovirt-managed-node/src/scripts/ovirt-awake @@ -66,7 +66,7 @@ start () { if [ -n $KEYTAB ]; then echo "Retrieving keytab: '$KEYTAB'" - wget $KEYTAB --output-document=$KEYTAB_FILE + wget -q $KEYTAB --output-document=$KEYTAB_FILE else echo "No keytab to retrieve" fi diff --git a/ovirt-managed-node/src/scripts/ovirt-early b/ovirt-managed-node/src/scripts/ovirt-early index 4116847..975ba9d 100755 --- a/ovirt-managed-node/src/scripts/ovirt-early +++ b/ovirt-managed-node/src/scripts/ovirt-early @@ -27,7 +27,7 @@ configure_from_network() { find_srv ovirt tcp printf . if [ -n "$SRV_HOST" -a -n "$SRV_PORT" ]; then - wget --quiet -O - "http://$SRV_HOST:$SRV_PORT/ovirt/cfgdb/$(hostname)" \ + wget -q -O - "http://$SRV_HOST:$SRV_PORT/ovirt/cfgdb/$(hostname)" \ | augtool > /dev/null 2>&1 if [ $? -eq 0 ]; then printf "remote config applied." @@ -94,11 +94,13 @@ start() { done } -case "$1" in - start) - start - ;; - *) - echo "Usage: ovirt-early {start}" - exit 2 -esac +{ + case "$1" in + start) + start + ;; + *) + echo "Usage: ovirt-early {start}" + exit 2 + esac +} >> $OVIRT_LOGFILE diff --git a/ovirt-managed-node/src/scripts/ovirt-functions b/ovirt-managed-node/src/scripts/ovirt-functions index 9974533..5b530f7 100644 --- a/ovirt-managed-node/src/scripts/ovirt-functions +++ b/ovirt-managed-node/src/scripts/ovirt-functions @@ -1,6 +1,9 @@ # -*-Shell-script-*- -find_srv() { +OVIRT_LOGFILE=/var/log/ovirt.log + +find_srv() +{ local dnsreply dnsreply=$(dig +short -t srv _$1._$2.$(dnsdomainname)) if [ $? -eq 0 ]; then diff --git a/ovirt-managed-node/src/scripts/ovirt-post b/ovirt-managed-node/src/scripts/ovirt-post index 3bb0f6d..fbdc1f6 100755 --- a/ovirt-managed-node/src/scripts/ovirt-post +++ b/ovirt-managed-node/src/scripts/ovirt-post @@ -27,11 +27,13 @@ start() { echo } -case "$1" in - start) - start - ;; - *) - echo "Usage: ovirt-post {start}" - exit 2 -esac +{ + case "$1" in + start) + start + ;; + *) + echo "Usage: ovirt-post {start}" + exit 2 + esac +} >> $OVIRT_LOGFILE -- 1.5.5.1 From mwagner at redhat.com Thu Jul 10 02:53:29 2008 From: mwagner at redhat.com (mark wagner) Date: Wed, 09 Jul 2008 22:53:29 -0400 Subject: [Ovirt-devel] Skipping the Browser :) In-Reply-To: <4874BB0F.7020903@redhat.com> References: <4874B928.9060802@redhat.com> <4874BB0F.7020903@redhat.com> Message-ID: <487579A9.7040506@redhat.com> Chris Lalancette wrote: > Michael DeHaan wrote: >> Is everything in ovirt that can be accessed as a GUI (and performed by >> the GUI) accessible as a web service (by this, I mean something simple >> like XMLRPC or JSON-over-REST?). Can there also be an ovirt command >> line for simple scripting integration? > > The answer right now is "no", but it's something basically everyone has asked > for, so it's definitely on the roadmap. We have to define the API, then > implement the underlying API, and then (possibly) port the web application over > to using that API. Agreed that it is a very useful thing to have. This is certainly something that I feel we should start on sooner rather than later. From my perspective, it will be a major enabler to getting any type of useful automated testing implemented. From a selfish perspective, it is needed before development of limit / scaling tests can be considered. While I realize that there are tools out there to twiddle WUI's in an automated manner, an ovirt API would allow scripting of the basic stuff (and hopefully basic++ stuff too :) -mark > > Chris Lalancette > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel From imain at redhat.com Thu Jul 10 04:35:27 2008 From: imain at redhat.com (Ian Main) Date: Wed, 9 Jul 2008 21:35:27 -0700 Subject: [Ovirt-devel] Skipping the Browser :) In-Reply-To: <4874BB0F.7020903@redhat.com> References: <4874B928.9060802@redhat.com> <4874BB0F.7020903@redhat.com> Message-ID: <20080709213527.2d9bfbde@tp.mains.net> On Wed, 09 Jul 2008 15:20:15 +0200 Chris Lalancette wrote: > Michael DeHaan wrote: > > Is everything in ovirt that can be accessed as a GUI (and performed by > > the GUI) accessible as a web service (by this, I mean something simple > > like XMLRPC or JSON-over-REST?). Can there also be an ovirt command > > line for simple scripting integration? > > The answer right now is "no", but it's something basically everyone has asked > for, so it's definitely on the roadmap. We have to define the API, then > implement the underlying API, and then (possibly) port the web application over > to using that API. Agreed that it is a very useful thing to have. Yeah, we're working on exposing an API for multiple languages for scripting. Myself and David Lutterkort are working on it. We'll post a draft API probly in a few days. You can read a bit of the discussion we had prior to this on the list in the 'Thoughts about taskomatic' thread. Cheers! :) Ian From imain at redhat.com Thu Jul 10 04:38:21 2008 From: imain at redhat.com (Ian Main) Date: Wed, 9 Jul 2008 21:38:21 -0700 Subject: [Ovirt-devel] [PATCH]: Configure iptables on the managed node In-Reply-To: <4874DCDB.30507@redhat.com> References: <4874DCDB.30507@redhat.com> Message-ID: <20080709213821.1bd8db1a@tp.mains.net> On Wed, 09 Jul 2008 17:44:27 +0200 Chris Lalancette wrote: > One of the side-effects of the SELinux support that recently went into > livecd-tools (and is now in Fedora 9) is that it runs lokkit at the end of > installation. This results in the default firewall being applied to the managed > node. In general, this is a good thing, but we need to customize that firewall > to allow incoming ssh and incoming libvirt, at the very least (there may be more > in the future). The attached patch just configures the firewall in %post, and > with this in place I can successfully ssh into the managed node and use remote > libvirt commands. > > Signed-off-by: Chris Lalancette ACK! Very nice :) Ian From imain at redhat.com Thu Jul 10 04:55:44 2008 From: imain at redhat.com (Ian Main) Date: Wed, 9 Jul 2008 21:55:44 -0700 Subject: [Ovirt-devel] Managed Node qpid Modeling Message-ID: <20080709215544.0599ea7a@tp.mains.net> So here's what I've come up with so far. I have run this past a few folks and hopefully it's in a reasonable shape now. I suspect there may be some aspects that are lacking or need changing but that's what lots of eyes are for. :) Also once we get into implementation it'll flesh itself out. For those who haven't seen this yet, this is an XML markup for qpid modeling. qpid is an implementation of the AMQP specification, see http://cwiki.apache.org/qpid/ for more information. The modeling aspect is pretty new and I don't know if there's any good documentation on it yet. It's also not released yet so I guess that's to be expected.. :) This defines a model or object oriented API that taskomatic will use to talk to the managed nodes. Properties are updated when set on the nodes and statistics are pushed at a regular interval. Methods can be called asynchronously or synchronously. The idea is to unify our communications between the nodes and wui with qpid modeling. If you look at what is available here and what taskomatic, host-status, host-collect and even some of ovirt-identify-node do, you'll see that's pretty much all contained within this model/API. So please take a look and feel free to post questions or comments. Thanks! Ian -- From apevec at redhat.com Thu Jul 10 06:53:53 2008 From: apevec at redhat.com (Alan Pevec) Date: Thu, 10 Jul 2008 08:53:53 +0200 Subject: [Ovirt-devel] [PATCH] Add additional blacklisting and rpm removal to managed node In-Reply-To: <4873263C.3010302@redhat.com> References: <4873263C.3010302@redhat.com> Message-ID: <1215672833-16485-1-git-send-email-apevec@redhat.com> From: Perry Myers A few important notes: 1. /lib/modules was scoured for things that didn't seem necessary, however my notion of not necessary may not be correct. Please review the list of modules that I'm removing and if you see one that we need to add back in, comment. 2. /boot is removed as we don't need an initrd and kernel image inside of the livecd initrd. 3. The blacklisting method is a hack. What we need is an appliance creator that has black/whitelisting capabilities... (hint, hint to our AOS friends out there) NOTE: This patch is revised from my patch last week. I incorporated suggestions from Chris regarding reinclusion of some kernel modules and fixed an issue with i386 builds by not wiping out /lib/security. With this patch both i386 and x86_64 managed nodes boot and work. Signed-off-by: Perry Myers - use lib{,64} in the blacklist - drop copying /etc/timezone, fixed in livecd-tools >= 0.17.1 check for RPM version in Makefile Signed-off-by: Alan Pevec --- ovirt-host-creator/Makefile | 1 + ovirt-host-creator/common-post.ks | 99 +++++++++++++++++++++++-------------- ovirt-host-creator/rpm-compare.py | 39 ++++++++++++++ 3 files changed, 101 insertions(+), 38 deletions(-) create mode 100755 ovirt-host-creator/rpm-compare.py diff --git a/ovirt-host-creator/Makefile b/ovirt-host-creator/Makefile index 6ebdfbd..1f0122f 100644 --- a/ovirt-host-creator/Makefile +++ b/ovirt-host-creator/Makefile @@ -13,6 +13,7 @@ repos.ks: repos.ks.in sed "s/@@ARCH@@/$(ARCH)/" repos.ks.in > repos.ks build: ovirt.ks common-install.ks common-pkgs.ks common-post.ks repos.ks + ./rpm-compare.py GE 0 livecd-tools 017.1 1 ./ovirt-cd > ovirt-cd.log 2>&1 tar: clean build diff --git a/ovirt-host-creator/common-post.ks b/ovirt-host-creator/common-post.ks index 2f7b612..b21f52c 100644 --- a/ovirt-host-creator/common-post.ks +++ b/ovirt-host-creator/common-post.ks @@ -9,13 +9,6 @@ echo "Creating shadow files" pwconv grpconv -echo "Re-creating cracklib dicts" -# cracklib-dicts is 8MB. We probably don't need to have strict password -# checking on the ovirt host -# unfortunately we can't create an empty cracklib dict, so we create it -# with a single entry "1" -echo 1 | packer >& /dev/null - echo "Forcing C locale" # force logins (via ssh, etc) to use C locale, since we remove locales cat >> /etc/profile << \EOF @@ -41,9 +34,6 @@ cat > /etc/sysconfig/iptables << \EOF COMMIT EOF -# here, remove a bunch of files we don't need that are just eating up space. -# it breaks rpm slightly, but it's not too bad - echo "Removing excess RPMs" # kernel pulls in mkinitrd which pulls in isomd5sum which pulls in python, @@ -54,36 +44,30 @@ rpm -e system-config-firewall-tui system-config-network-tui rhpl \ rpm-python dbus-python kudzu newt-python newt rpm -e qemu kpartx mkinitrd isomd5sum dmraid python python-libs +RPM="rpm -v -e --nodeps" + # Sigh. ntp has a silly dependency on perl because of auxiliary scripts which # we don't need to use. Forcibly remove it here -rpm -e --nodeps perl perl-libs perl-Module-Pluggable perl-version \ +$RPM perl perl-libs perl-Module-Pluggable perl-version \ perl-Pod-Simple perl-Pod-Escapes -RM="rm -rf" +# Remove additional RPMs forcefully +$RPM gamin pm-utils kbd libuser passwd usermode \ + openssh-clients vbetool ConsoleKit hdparm \ + efibootmgr krb5-workstation linux-atm-libs fedora-release-notes \ + slang psmisc gdbm cryptsetup-luks pciutils mtools syslinux db4 \ + wireless-tools radeontool cracklib-dicts cracklib -echo "Removing docs and internationalization" -$RM /usr/share/omf -$RM /usr/share/gnome -$RM /usr/share/doc -$RM /usr/share/locale -$RM /usr/share/libthai -$RM /usr/share/man -$RM /usr/share/terminfo -$RM /usr/share/X11 -$RM /usr/share/i18n +# Things we could probably remove if libvirt didn't link against them +#$RPM avahi PolicyKit xen-libs -find /usr/share/zoneinfo -regextype egrep -type f \ - ! -regex ".*/UTC" -exec $RM {} \; -# XXX anaconda/timezone.py does it, missing in imgcreate/kickstart.py -cp /usr/share/zoneinfo/UTC /etc/localtime - -$RM /usr/lib/locale -$RM /usr/lib/syslinux -$RM /usr/lib64/gconv -$RM /usr/lib64/pango -$RM /usr/lib64/libpango* -$RM /etc/pango -$RM /usr/bin/pango* +# Things we could probably remove if qemu-kvm didn't link against them +#$RPM SDL alsa-lib + +# Pam complains when this is missing +#$RPM ConsoleKit-libs + +RM="rm -rf" echo "Removing excess kernel modules" MODULES="/lib/modules/*/kernel" @@ -101,16 +85,55 @@ fs_mods="fs/nls fs/9p fs/affs fs/autofs fs/autofs4 fs/befs fs/bfs fs/cifs \ net_mods="net/802 net/8021q net/9p net/appletalk net/atm net/ax25 \ net/bluetooth net/dccp net/decnet net/ieee80211 net/ipx net/irda \ net/mac80211 net/netrom net/rfkill net/rose net/sched net/tipc \ - net/wanrouter net/wireless drivers/auxdisplay drivers/net/appletalk \ + net/wanrouter net/wireless" + +driver_mods="drivers/auxdisplay drivers/net/appletalk \ drivers/net/hamradio drivers/net/pcmcia drivers/net/tokenring \ - drivers/net/wireless drivers/net/irda drivers/atm drivers/usb/atm" + drivers/net/wireless drivers/net/irda drivers/atm drivers/usb/atm \ + drivers/acpi drivers/char/drm drivers/char/mwave \ + drivers/char/ipmp drivers/char/pcmcia drivers/crypto drivers/dca \ + drivers/firmware drivers/memstick drivers/mmc drivers/mfs \ + drivers/parport drivers/video drivers/watchdog drivers/net/ppp* \ + drivers/usb/serial drivers/usb/misc drivers/usb/class \ + drivers/usb/image drivers/rtc" misc_mods="drivers/bluetooth drivers/firewire drivers/i2c drivers/isdn \ drivers/media drivers/misc drivers/leds drivers/mtd drivers/w1 sound \ - drivers/input drivers/pcmcia drivers/scsi/pcmcia" + drivers/input drivers/pcmcia drivers/scsi/pcmcia crypto lib" -for mods in $fs_mods $net_mods $misc_mods ; do +for mods in $fs_mods $net_mods $misc_mods $driver_mods ; do $RM $MODULES/$mods done +echo "Removing all timezones except for UTC" +find /usr/share/zoneinfo -regextype egrep -type f \ + ! -regex ".*/UTC|.*/GMT" -exec $RM {} \; + +echo "Removing blacklisted files and directories" +blacklist="/boot /etc/alsa /etc/pki /usr/share/hwdata/MonitorsDB \ + /usr/share/hwdata/oui.txt /usr/share/hwdata/videoaliases \ + /usr/share/hwdata/videodrivers /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/src /usr/etc /usr/games /usr/include /usr/local /usr/lib{,64}/python2.5 \ + /usr/{,lib64}/tc /usr/lib{,64}/tls /usr/lib{,64}/sse2 /usr/lib{,64}/pkgconfig \ + /usr/lib{,64}/nss /usr/lib{,64}/X11 /usr/lib{,64}/games /usr/lib{,64}/alsa-lib \ + /usr/lib{,64}/fs/reiserfs /usr/lib{,64}/krb5 /usr/lib{,64}/hal /usr/lib{,64}/gio \ + /usr/bin/hal-device /usr/bin/hal-disable-polling \ + /usr/bin/hal-find-by-capability /usr/bin/hal-find-by-property \ + /usr/bin/hal-is-caller-locked-out /usr/bin/hal-is-caller-privileged \ + /usr/bin/hal-lock /usr/bin/hal-set-property /usr/bin/hal-setup-keymap \ + /usr/sbin/dell* /lib/terminfo/d /lib/terminfo/v /lib/terminfo/a \ + /lib/firmware /usr/lib/locale /usr/lib/syslinux /usr/lib{,64}/gconv \ + /usr/lib{,64}/pango /usr/lib{,64}/libpango* /etc/pango /usr/bin/pango*" + +docs_blacklist="/usr/share/omf /usr/share/gnome /usr/share/doc \ + /usr/share/locale /usr/share/libthai /usr/share/man /usr/share/terminfo \ + /usr/share/X11 /usr/share/i18n" + +$RM $blacklist $docs_blacklist + +echo "Cleanup empty directory structures in /usr/share" +find /usr/share -type d -exec rmdir {} \; > /dev/null 2>&1 + echo "Finished Kickstart Post" diff --git a/ovirt-host-creator/rpm-compare.py b/ovirt-host-creator/rpm-compare.py new file mode 100755 index 0000000..f91b02f --- /dev/null +++ b/ovirt-host-creator/rpm-compare.py @@ -0,0 +1,39 @@ +#!/usr/bin/python +# +# rpm-compare.py - return 0 if installed package version satisfies condition + +import sys +import rpm +import rpmUtils.miscutils as rpmutils +# pkgTupleFromHeader(hdr) -> (name, arch, epoch, ver, rel) +# rangeCheck(reqtuple, pkgtuple) reqtuple := (reqn, reqf, (reqe, reqv, reqr)) + +def usage(): + print "usage: %s {GE|GT|EQ|LE|LT} epoch name ver rel \n" % sys.argv[0] + sys.exit(1) + +if len(sys.argv) < 6: + usage() + +cond = sys.argv[1] +epoch = sys.argv[2] +name = sys.argv[3] +ver = sys.argv[4] +rel = sys.argv[5] + +if cond not in ('GE','GT','EQ','LE','LT'): + usage() + +#broken from pkgs with - in the name +#name, ver, rel, epoch, arch = rpmutils.splitFilename(rpmname) +##print "epoch %s name %s ver %s rel %s" % (epoch, name, ver, rel) + +ts = rpm.TransactionSet() +for hdr in ts.dbMatch('name', name): + (n, a, e, v, r) = rpmutils.pkgTupleFromHeader(hdr) + ##print (n, a, e, v, r) + if rpmutils.rangeCheck((name, cond, (epoch, ver, rel)), (n, a, e, v, r)) == 1: + exit(0) +print 'RPM condition not satisfied' +exit(1) + -- 1.5.5.1 From fj0588di at aa.jp.fujitsu.com Thu Jul 10 08:50:39 2008 From: fj0588di at aa.jp.fujitsu.com (S.Sakamoto) Date: Thu, 10 Jul 2008 17:50:39 +0900 Subject: [Ovirt-devel] [Q]Can VM start in Developer Version? In-Reply-To: <4874AA46.9050607@redhat.com> References: <200807092104.CDA57722.90JGEK96@aa.jp.fujitsu.com> <4874AA46.9050607@redhat.com> Message-ID: <200807101750.CJI86423.6EJ99K0G@aa.jp.fujitsu.com> > OK, so the "Could not initialize KVM" error is not fatal; it just means your > guests will be using Qemu for full emulation, which is expected in the developer > version. The part that does seem fatal is the "Could not allocate physical > memory". By default, we only give 512MB to the "fake" managed nodes (such as > node3); as such, there isn't a lot of room for guests on there. What size guest > were you trying to run? My guess is that if you increase the size of the > managed node, you will then be able to start your guest. You can modify the > managed node by doing something like: > > # virsh dumpxml node3 > node3.xml > > # virsh define node3.xml > # virsh start node3 > Thank you for your information! I was able to start a guest in an above procedure. Thanks, Shigeki Sakamoto. From berrange at redhat.com Thu Jul 10 09:18:56 2008 From: berrange at redhat.com (Daniel P. Berrange) Date: Thu, 10 Jul 2008 10:18:56 +0100 Subject: [Ovirt-devel] Managed Node qpid Modeling In-Reply-To: <20080709215544.0599ea7a@tp.mains.net> References: <20080709215544.0599ea7a@tp.mains.net> Message-ID: <20080710091856.GD23601@redhat.com> On Wed, Jul 09, 2008 at 09:55:44PM -0700, Ian Main wrote: > So please take a look and feel free to post questions or comments. > > > > > > > > > > > This is a seriously bad direction to take. libvirt explicitly uses XML for passing domain creation information so that it is extendable without having to constantly change the API of the creation methods. IMHO any wire protocol between managed nodes and WUI should map pretty much 1-to-1 onto the libvirt APIs. In fact rather than defining an oVirt AMQP protocol I'd like this to be positioned as the canonical libvirt AMQP protocol. This will enable good interoperability for any other applications using AMQP who also interact with libvirt. For it to be a libvirt AMQP protocol it should be a pretty much direct serialization of libvirt API onto the wire. Sure you'll probably need some oVirt specific bits too for APIs outside the scope of libvirt, such as the broader monitoring / stats stuff oVirt does. So we'll actually want 2 separate AMQP specifications - one for libvirt & one for oVirt. 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 veillard at redhat.com Thu Jul 10 09:51:09 2008 From: veillard at redhat.com (Daniel Veillard) Date: Thu, 10 Jul 2008 05:51:09 -0400 Subject: [Ovirt-devel] Managed Node qpid Modeling In-Reply-To: <20080710091856.GD23601@redhat.com> References: <20080709215544.0599ea7a@tp.mains.net> <20080710091856.GD23601@redhat.com> Message-ID: <20080710095109.GF9696@redhat.com> On Thu, Jul 10, 2008 at 10:18:56AM +0100, Daniel P. Berrange wrote: > On Wed, Jul 09, 2008 at 09:55:44PM -0700, Ian Main wrote: > > So please take a look and feel free to post questions or comments. > > > > > > > > > > > > > > > > > > > > > > > > This is a seriously bad direction to take. libvirt explicitly uses XML for > passing domain creation information so that it is extendable without having > to constantly change the API of the creation methods. IMHO any wire protocol > between managed nodes and WUI should map pretty much 1-to-1 onto the libvirt > APIs. Agree. And even if AMQP is usually used to transport SOAP payload, I don't think you have to a priori restrict yourself to that format. > In fact rather than defining an oVirt AMQP protocol I'd like this to be > positioned as the canonical libvirt AMQP protocol. This will enable good > interoperability for any other applications using AMQP who also interact > with libvirt. For it to be a libvirt AMQP protocol it should be a pretty > much direct serialization of libvirt API onto the wire. Look at http://libvirt.org/html/libvirt-libvirt.html#virDomainCreateLinux virDomainPtr virDomainCreateLinux (virConnectPtr conn, const char * xmlDesc, unsigned int flags) for the description of the creation API and http://libvirt.org/formatdomain.html http://libvirt.org/drvqemu.html#xmlconfig for the description of the domain XML format used underneath. IMHO your suggested SOAP API encoding get immediately into the trap i tried to avoid when designing libvirt API for creating a domain, which is that it's extremely hard to know the full set of informtations actually needed to start a domain. Even with all the experience gained from Xen FV/PV, QEmu, KVM, OpenVZ, LDom, etc. I would not be able to restrict that to a list. Even if you were to put some abstraction by passing objects instead of basic types you just can't block an API for something which is ultimately based on libvirt the way you're suggesting. A trivial breakage is that as soon as someone adds support for Xen or LXC to oVirt, the AMQP bindings will break beacause your boot methodology assumes something like a boot device, but that's not necessarily the way those hypervisor works. Maybe you don't want to revisit the case of using SOAP bindings on top of AMQP, still you should try to stay in line with libvirt, a lot of work and thoughts have been invested onto those APIs, please don't assume you can build a different set, the divergence would kill the AMQP API in a relatively short term. > Sure you'll probably need some oVirt specific bits too for APIs outside the > scope of libvirt, such as the broader monitoring / stats stuff oVirt does. > So we'll actually want 2 separate AMQP specifications - one for libvirt & > one for oVirt. Splitting the two might be a good option, yes. Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard at redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/ From berrange at redhat.com Thu Jul 10 10:28:42 2008 From: berrange at redhat.com (Daniel P. Berrange) Date: Thu, 10 Jul 2008 11:28:42 +0100 Subject: [Ovirt-devel] Managed Node qpid Modeling In-Reply-To: <20080710095109.GF9696@redhat.com> References: <20080709215544.0599ea7a@tp.mains.net> <20080710091856.GD23601@redhat.com> <20080710095109.GF9696@redhat.com> Message-ID: <20080710102842.GB5806@redhat.com> On Thu, Jul 10, 2008 at 05:51:09AM -0400, Daniel Veillard wrote: > On Thu, Jul 10, 2008 at 10:18:56AM +0100, Daniel P. Berrange wrote: > > On Wed, Jul 09, 2008 at 09:55:44PM -0700, Ian Main wrote: > > > So please take a look and feel free to post questions or comments. > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > This is a seriously bad direction to take. libvirt explicitly uses XML for > > passing domain creation information so that it is extendable without having > > to constantly change the API of the creation methods. IMHO any wire protocol > > between managed nodes and WUI should map pretty much 1-to-1 onto the libvirt > > APIs. > > Agree. And even if AMQP is usually used to transport SOAP payload, I don't > think you have to a priori restrict yourself to that format. The wire format isn't actually XML in AMQP world - only the description of the wire format is XML. AMQP uses this XML description of APIs to serialize the data into the wire in a binary format. 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 Jul 10 10:59:53 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Thu, 10 Jul 2008 06:59:53 -0400 Subject: [Ovirt-devel] Managed Node qpid Modeling In-Reply-To: <20080709215544.0599ea7a@tp.mains.net> References: <20080709215544.0599ea7a@tp.mains.net> Message-ID: <4875EBA9.6030900@redhat.com> Ian Main wrote: > So here's what I've come up with so far. I have run this past a few folks and hopefully it's in a reasonable shape now. I suspect there may be some aspects that are lacking or need changing but that's what lots of eyes are for. :) Also once we get into implementation it'll flesh itself out. > > For those who haven't seen this yet, this is an XML markup for qpid modeling. qpid is an implementation of the AMQP specification, see http://cwiki.apache.org/qpid/ for more information. The modeling aspect is pretty new and I don't know if there's any good documentation on it yet. It's also not released yet so I guess that's to be expected.. :) > > This defines a model or object oriented API that taskomatic will use to talk to the managed nodes. Properties are updated when set on the nodes and statistics are pushed at a regular interval. Methods can be called asynchronously or synchronously. > > The idea is to unify our communications between the nodes and wui with qpid modeling. If you look at what is available here and what taskomatic, host-status, host-collect and even some of ovirt-identify-node do, you'll see that's pretty much all contained within this model/API. > > So please take a look and feel free to post questions or comments. > > Thanks! > > Ian > This seems to combine state with RPC syntax. Any way of breaking those out into seperate schemas? -- bk From veillard at redhat.com Thu Jul 10 11:39:07 2008 From: veillard at redhat.com (Daniel Veillard) Date: Thu, 10 Jul 2008 07:39:07 -0400 Subject: [Ovirt-devel] Managed Node qpid Modeling In-Reply-To: <20080710102842.GB5806@redhat.com> References: <20080709215544.0599ea7a@tp.mains.net> <20080710091856.GD23601@redhat.com> <20080710095109.GF9696@redhat.com> <20080710102842.GB5806@redhat.com> Message-ID: <20080710113906.GA14724@redhat.com> On Thu, Jul 10, 2008 at 11:28:42AM +0100, Daniel P. Berrange wrote: > On Thu, Jul 10, 2008 at 05:51:09AM -0400, Daniel Veillard wrote: > > On Thu, Jul 10, 2008 at 10:18:56AM +0100, Daniel P. Berrange wrote: > > > On Wed, Jul 09, 2008 at 09:55:44PM -0700, Ian Main wrote: > > > > So please take a look and feel free to post questions or comments. > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > This is a seriously bad direction to take. libvirt explicitly uses XML for > > > passing domain creation information so that it is extendable without having > > > to constantly change the API of the creation methods. IMHO any wire protocol > > > between managed nodes and WUI should map pretty much 1-to-1 onto the libvirt > > > APIs. > > > > Agree. And even if AMQP is usually used to transport SOAP payload, I don't > > think you have to a priori restrict yourself to that format. > > The wire format isn't actually XML in AMQP world - only the description of > the wire format is XML. AMQP uses this XML description of APIs to serialize > the data into the wire in a binary format. I found that out, and the str16 type should be just fine to carry XML libvirt instances. Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard at redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/ From veillard at redhat.com Thu Jul 10 11:49:31 2008 From: veillard at redhat.com (Daniel Veillard) Date: Thu, 10 Jul 2008 07:49:31 -0400 Subject: [Ovirt-devel] Managed Node qpid Modeling In-Reply-To: <20080710095109.GF9696@redhat.com> References: <20080709215544.0599ea7a@tp.mains.net> <20080710091856.GD23601@redhat.com> <20080710095109.GF9696@redhat.com> Message-ID: <20080710114930.GB14724@redhat.com> On Thu, Jul 10, 2008 at 05:51:09AM -0400, Daniel Veillard wrote: > On Thu, Jul 10, 2008 at 10:18:56AM +0100, Daniel P. Berrange wrote: > > On Wed, Jul 09, 2008 at 09:55:44PM -0700, Ian Main wrote: > > > So please take a look and feel free to post questions or comments. > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > [...] > Look at http://libvirt.org/html/libvirt-libvirt.html#virDomainCreateLinux > virDomainPtr virDomainCreateLinux (virConnectPtr conn, > const char * xmlDesc, > unsigned int flags) > > for the description of the creation API and > http://libvirt.org/formatdomain.html > http://libvirt.org/drvqemu.html#xmlconfig > for the description of the domain XML format used underneath. Note the availability of an existing XML description of libvirt APIs http://libvirt.org/libvirt-api.xml Also installed under /usr/share/doc/libvirt-*/libvirt-api.xml you will find for example: .... Launch a new Linux guest domain, based on an XML description similar to the one returned by virDomainGetXMLDesc() This function may requires privileged access to the hypervisor. .... I use that to (mostly) automatize the python libvirt bindings. I do no suggest to do the same but a simple XSLT or scripting using those data may help doing the AMQP bindings. Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard at redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/ From clalance at redhat.com Thu Jul 10 14:21:56 2008 From: clalance at redhat.com (Chris Lalancette) Date: Thu, 10 Jul 2008 16:21:56 +0200 Subject: [Ovirt-devel] [PATCH] Fixed a misnamed reference: cpu_details should have been cpus. In-Reply-To: <1215637735-1694-1-git-send-email-dpierce@redhat.com> References: <1215637735-1694-1-git-send-email-dpierce@redhat.com> Message-ID: <48761B04.9070300@redhat.com> Darryl L. Pierce wrote: > Signed-off-by: Darryl L. Pierce > --- > wui/src/app/models/host.rb | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > diff --git a/wui/src/app/models/host.rb b/wui/src/app/models/host.rb > index 90e18d5..e5f6264 100644 > --- a/wui/src/app/models/host.rb > +++ b/wui/src/app/models/host.rb > @@ -72,7 +72,7 @@ class Host < ActiveRecord::Base > end > > def num_cpus > - return cpu_details.size > + return cpus.size > end > > def cpu_speed Yes, this was messing up display in the WUI itself. ACK, and committed. Chris Lalancette From clalance at redhat.com Thu Jul 10 14:37:22 2008 From: clalance at redhat.com (Chris Lalancette) Date: Thu, 10 Jul 2008 10:37:22 -0400 Subject: [Ovirt-devel] [PATCH] Removed a duplicate KVM_HYPERVISOR and HYPERVISOR_TYPE lines that was causing Message-ID: <1215700642-24679-1-git-send-email-clalance@redhat.com> Signed-off-by: Chris Lalancette --- wui/src/app/models/host.rb | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/wui/src/app/models/host.rb b/wui/src/app/models/host.rb index e5f6264..80acaeb 100644 --- a/wui/src/app/models/host.rb +++ b/wui/src/app/models/host.rb @@ -46,9 +46,6 @@ class Host < ActiveRecord::Base STATE_AVAILABLE = "available" STATES = [STATE_UNAVAILABLE, STATE_AVAILABLE] - KVM_HYPERVISOR_TYPE = "KVM" - HYPERVISOR_TYPES = [KVM_HYPERVISOR_TYPE] - def memory_in_mb kb_to_mb(memory) end -- 1.5.5.1 From clalance at redhat.com Thu Jul 10 15:05:55 2008 From: clalance at redhat.com (Chris Lalancette) Date: Thu, 10 Jul 2008 11:05:55 -0400 Subject: [Ovirt-devel] [PATCH] Fix a small typo in the graphing stuff that was causing backtraces in the Message-ID: <1215702355-25433-1-git-send-email-clalance@redhat.com> Signed-off-by: Chris Lalancette --- wui/src/app/controllers/graph_controller.rb | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/wui/src/app/controllers/graph_controller.rb b/wui/src/app/controllers/graph_controller.rb index 6c57ba1..dbe2afc 100644 --- a/wui/src/app/controllers/graph_controller.rb +++ b/wui/src/app/controllers/graph_controller.rb @@ -457,7 +457,7 @@ class GraphController < ApplicationController end end - def _generated_default_time_axis(myDays) + def _generate_default_time_axis(myDays) times = [] now = Time.now if myDays.to_i == 1 -- 1.5.5.1 From clalance at redhat.com Thu Jul 10 17:00:15 2008 From: clalance at redhat.com (Chris Lalancette) Date: Thu, 10 Jul 2008 13:00:15 -0400 Subject: [Ovirt-devel] Fix VM creation Message-ID: <1215709216-27171-1-git-send-email-clalance@redhat.com> Since cpus is now it's own table, we no longer have a "num_cpus" column to order by in available_vm_resources. Thanks to Scott Seago, replace this with a LEFT OUTER JOIN combined with a select to count the cpus for a particular host. From clalance at redhat.com Thu Jul 10 17:00:16 2008 From: clalance at redhat.com (Chris Lalancette) Date: Thu, 10 Jul 2008 13:00:16 -0400 Subject: [Ovirt-devel] [PATCH] Since cpus is now it's own table, we no longer have a "num_cpus" column to In-Reply-To: <1215709216-27171-1-git-send-email-clalance@redhat.com> References: <1215709216-27171-1-git-send-email-clalance@redhat.com> Message-ID: <1215709216-27171-2-git-send-email-clalance@redhat.com> Signed-off-by: Chris Lalancette --- wui/src/app/models/vm_resource_pool.rb | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/wui/src/app/models/vm_resource_pool.rb b/wui/src/app/models/vm_resource_pool.rb index 85e3661..de8bcb3 100644 --- a/wui/src/app/models/vm_resource_pool.rb +++ b/wui/src/app/models/vm_resource_pool.rb @@ -97,6 +97,9 @@ class VmResourcePool < Pool :conditions => "hardware_pool_id = #{hw_pool.id}") host_mem_limit = (memhost.nil? ? 0 : memhost.memory) cpuhost = Host.find(:first, :order => "num_cpus DESC", + :select => "hosts.id, count (cpus) as num_cpus", + :joins => "LEFT OUTER JOIN cpus ON hosts.id = cpus.host_id", + :group => "hosts.id", :conditions => "hardware_pool_id = #{hw_pool.id}") host_cpu_limit = cpuhost.nil? ? 0 : cpuhost.num_cpus resources[:memory] = host_mem_limit if resources[:memory].nil? or host_mem_limit < resources[:memory] -- 1.5.5.1 From clalance at redhat.com Thu Jul 10 17:01:23 2008 From: clalance at redhat.com (Chris Lalancette) Date: Thu, 10 Jul 2008 19:01:23 +0200 Subject: [Ovirt-devel] Fix VM creation In-Reply-To: <1215709216-27171-1-git-send-email-clalance@redhat.com> References: <1215709216-27171-1-git-send-email-clalance@redhat.com> Message-ID: <48764063.8000909@redhat.com> Chris Lalancette wrote: > Since cpus is now it's own table, we no longer have a "num_cpus" column to > order by in available_vm_resources. Thanks to Scott Seago, replace this with > a LEFT OUTER JOIN combined with a select to count the cpus for a particular > host. > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel Ignore this; I was playing around with git-send-email, and it obviously did something different than what I thought it would do. Chris Lalancette From imain at redhat.com Thu Jul 10 17:31:54 2008 From: imain at redhat.com (Ian Main) Date: Thu, 10 Jul 2008 10:31:54 -0700 Subject: [Ovirt-devel] Managed Node qpid Modeling In-Reply-To: <20080710091856.GD23601@redhat.com> References: <20080709215544.0599ea7a@tp.mains.net> <20080710091856.GD23601@redhat.com> Message-ID: <20080710103154.220e7732@tp.mains.net> On Thu, 10 Jul 2008 10:18:56 +0100 "Daniel P. Berrange" wrote: > On Wed, Jul 09, 2008 at 09:55:44PM -0700, Ian Main wrote: > > So please take a look and feel free to post questions or comments. > > > > > > > > > > > > > > > > > > > > > > > > This is a seriously bad direction to take. libvirt explicitly uses XML for > passing domain creation information so that it is extendable without having > to constantly change the API of the creation methods. IMHO any wire protocol > between managed nodes and WUI should map pretty much 1-to-1 onto the libvirt > APIs. > > In fact rather than defining an oVirt AMQP protocol I'd like this to be > positioned as the canonical libvirt AMQP protocol. This will enable good > interoperability for any other applications using AMQP who also interact > with libvirt. For it to be a libvirt AMQP protocol it should be a pretty > much direct serialization of libvirt API onto the wire. > > Sure you'll probably need some oVirt specific bits too for APIs outside the > scope of libvirt, such as the broader monitoring / stats stuff oVirt does. > So we'll actually want 2 separate AMQP specifications - one for libvirt & > one for oVirt. I agree with the idea of passing XML instead of defining each argument, very good point and I'll send out an update soon that mirrors the libvirt API. I'll keep the canonical libvirt amqp API part in mind as I work on it but for now I'm going to focus on getting this working in ovirt first. When things mature a bit more we can look at fleshing it out and possibly splitting things out.. if that is even necessary. Ian From imain at redhat.com Thu Jul 10 17:33:22 2008 From: imain at redhat.com (Ian Main) Date: Thu, 10 Jul 2008 10:33:22 -0700 Subject: [Ovirt-devel] Managed Node qpid Modeling In-Reply-To: <4875EBA9.6030900@redhat.com> References: <20080709215544.0599ea7a@tp.mains.net> <4875EBA9.6030900@redhat.com> Message-ID: <20080710103322.5ab2b365@tp.mains.net> On Thu, 10 Jul 2008 06:59:53 -0400 Bryan Kearney wrote: [snip] > This seems to combine state with RPC syntax. Any way of breaking those > out into seperate schemas? > > -- bk The idea is that this creates a kind of OO model of the node/domains etc. I'm not sure I see the advantage to splitting the properties out.. ? Ian From bkearney at redhat.com Thu Jul 10 17:39:26 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Thu, 10 Jul 2008 13:39:26 -0400 Subject: [Ovirt-devel] Managed Node qpid Modeling In-Reply-To: <20080710103322.5ab2b365@tp.mains.net> References: <20080709215544.0599ea7a@tp.mains.net> <4875EBA9.6030900@redhat.com> <20080710103322.5ab2b365@tp.mains.net> Message-ID: <4876494E.504@redhat.com> Ian Main wrote: > On Thu, 10 Jul 2008 06:59:53 -0400 > Bryan Kearney wrote: > > [snip] > >> This seems to combine state with RPC syntax. Any way of breaking those >> out into seperate schemas? >> >> -- bk > > The idea is that this creates a kind of OO model of the node/domains etc. I'm not sure I see the advantage to splitting the properties out.. ? > Clarity about is required. How much of the node data is actually required for anything but the heartbeat? -- bk From imain at redhat.com Thu Jul 10 18:14:08 2008 From: imain at redhat.com (Ian Main) Date: Thu, 10 Jul 2008 11:14:08 -0700 Subject: [Ovirt-devel] Managed Node qpid Modeling In-Reply-To: <20080710091856.GD23601@redhat.com> References: <20080709215544.0599ea7a@tp.mains.net> <20080710091856.GD23601@redhat.com> Message-ID: <20080710111408.74cbdad5@tp.mains.net> On Thu, 10 Jul 2008 10:18:56 +0100 "Daniel P. Berrange" wrote: [snip] > In fact rather than defining an oVirt AMQP protocol I'd like this to be > positioned as the canonical libvirt AMQP protocol. This will enable good > interoperability for any other applications using AMQP who also interact > with libvirt. For it to be a libvirt AMQP protocol it should be a pretty > much direct serialization of libvirt API onto the wire. > > Sure you'll probably need some oVirt specific bits too for APIs outside the > scope of libvirt, such as the broader monitoring / stats stuff oVirt does. > So we'll actually want 2 separate AMQP specifications - one for libvirt & > one for oVirt. > Actually it's interesting because the qpid guys wanted me to unify this API with their management schema too :). Talk about pressures in different directions.. :) Ian From imain at redhat.com Thu Jul 10 18:18:31 2008 From: imain at redhat.com (Ian Main) Date: Thu, 10 Jul 2008 11:18:31 -0700 Subject: [Ovirt-devel] Managed Node qpid Modeling In-Reply-To: <4876494E.504@redhat.com> References: <20080709215544.0599ea7a@tp.mains.net> <4875EBA9.6030900@redhat.com> <20080710103322.5ab2b365@tp.mains.net> <4876494E.504@redhat.com> Message-ID: <20080710111831.03ac969a@tp.mains.net> On Thu, 10 Jul 2008 13:39:26 -0400 Bryan Kearney wrote: > > > Ian Main wrote: > > On Thu, 10 Jul 2008 06:59:53 -0400 > > Bryan Kearney wrote: > > > > [snip] > > > >> This seems to combine state with RPC syntax. Any way of breaking those > >> out into seperate schemas? > >> > >> -- bk > > > > The idea is that this creates a kind of OO model of the node/domains etc. I'm not sure I see the advantage to splitting the properties out.. ? > > > > Clarity about is required. How much of the node data is actually > required for anything but the heartbeat? Actually I have been thinking.. there are actually two aspects to what is needed here. One is to implement the task queue like taskomatic does now, the other is to keep the database updated with information about the nodes. Taskomatic does use that information at times but the idea there was to parallelize it (multi thread/process). However we only need one process updating the database so splitting out the properties could work and could be handled separately. Something to think about.. Ian From dlutter at redhat.com Thu Jul 10 20:59:33 2008 From: dlutter at redhat.com (David Lutterkort) Date: Thu, 10 Jul 2008 13:59:33 -0700 Subject: [Ovirt-devel] Managed Node qpid Modeling In-Reply-To: <20080710114930.GB14724@redhat.com> References: <20080709215544.0599ea7a@tp.mains.net> <20080710091856.GD23601@redhat.com> <20080710095109.GF9696@redhat.com> <20080710114930.GB14724@redhat.com> Message-ID: <1215723573.13841.89.camel@localhost.localdomain> On Thu, 2008-07-10 at 07:49 -0400, Daniel Veillard wrote: > Note the availability of an existing XML description of libvirt APIs > http://libvirt.org/libvirt-api.xml > > Also installed under > /usr/share/doc/libvirt-*/libvirt-api.xml > > you will find for example: > > .... > > Launch a new Linux guest domain, based on an XML description similar to the one returned by virDomainGetXMLDesc() This function may requires privileged access to the hypervisor. > > > > > > .... > > I use that to (mostly) automatize the python libvirt bindings. I do no > suggest to do the same but a simple XSLT or scripting using those data may > help doing the AMQP bindings. One piece of info that is missing from the above XML, but needed for the qpid API is the notion of calling a method on an object. The above only has enough information to generate C-style function calls. It's also missing information about what are input and what are output parameters. How about adding an attribute 'role' to the element that would take one of three values: input, output or receiver, where 'receiver' says that that is logically the object to which the function/method belongs ? David From dlutter at redhat.com Thu Jul 10 21:07:37 2008 From: dlutter at redhat.com (David Lutterkort) Date: Thu, 10 Jul 2008 14:07:37 -0700 Subject: [Ovirt-devel] Skipping the Browser :) In-Reply-To: <4874B928.9060802@redhat.com> References: <4874B928.9060802@redhat.com> Message-ID: <1215724057.13841.94.camel@localhost.localdomain> On Wed, 2008-07-09 at 09:12 -0400, Michael DeHaan wrote: > Is everything in ovirt that can be accessed as a GUI (and performed by > the GUI) accessible as a web service (by this, I mean something simple > like XMLRPC or JSON-over-REST?). Can there also be an ovirt command > line for simple scripting integration? As Ian said, we're in the process of defining an API for that; right now the htinking is that it will be JSON-over-REST or similar. What needs to be exposed is at a minimum * VM lifecycle management (start/stop/create/destroy/migrate) * queries for lots of info around the various pools * defining/organizing resources into pools * some higher level ops like 'clear all VM's from this host' Essentially, everything that you can do through the UI should be scriptable. If you have any specific uses/operations that you want to see supported, let me know. David From dlutter at redhat.com Thu Jul 10 21:20:46 2008 From: dlutter at redhat.com (David Lutterkort) Date: Thu, 10 Jul 2008 14:20:46 -0700 Subject: [Ovirt-devel] Details about pending cobbler image support & ovirt integration In-Reply-To: <4874BCF9.7030900@redhat.com> References: <4874BCF9.7030900@redhat.com> Message-ID: <1215724846.13841.102.camel@localhost.localdomain> On Wed, 2008-07-09 at 09:28 -0400, Michael DeHaan wrote: > Images are the new object. We want cobbler to track them like other > objects. > > # cobbler image add --name=QuestionableRemondInstallISO > --file=/mnt/nfs/blah/foo.img Are images also meant for bare-metal installs or only for VM installs ? > After that, we also teach "cobbler image add" to track images that can > be fed to virt-image, AKA virt disk images. This will have a similar > syntax, most likely... > > # cobbler image add --name=MysteryOS --file=/mnt/nfs/blah/foo.img > --image-type=blah [--virt-ram=] [--virt-disk=] [etc] > > The --virt parameters will work basically as they do with cobbler > profiles today. It would be much simpler for VM images to tell cobbler to add an image.xml; all the parameters above are listed in that, and adding a VM image to a cobbler server would be as simple as # cobbler image add /foo/bar/image.xml and koan would basically take the same command line args as virt-image; the only thing on top of what virt-image does is that koan would have to make the actual disk files available on the local host. There's one small wrinkle: when you instantiate from an image, you can treat that image either as an immutable template (in which case you'd have to copy the disk files) or as the image for a specific VM (in which case you'd directly use the disk files to back the VM) > The next logical step after handling virt-images is perhaps teaching > cobbler about physical images and cloning tools, though I'm much more > interested in the virt case, as I have no problem if all the hypervisors > out there have to run Linux :) Heh .. yeah, definitely the more interesting first step. > The other thing we might want to talk about are cobbler triggers, which > could be written to notify ovirt of changes to the cobbler configuration > -- this is similar to something we are planning with Spacewalk. In > general, I think ovirt would mostly be giving orders to cobbler, but if > someone makes a change outside of cobbler, like deleting a virt-image > ovirt wants to have used, it should probably have a way of knowing it > should re-scan cobbler XMLRPC to see what changed. Yeah, might definitely be useful; though very very soon we'll all be talking amqp, and ovirt can just pick notifications off the bus, right ? David From berrange at redhat.com Thu Jul 10 21:34:29 2008 From: berrange at redhat.com (Daniel P. Berrange) Date: Thu, 10 Jul 2008 22:34:29 +0100 Subject: [Ovirt-devel] Managed Node qpid Modeling In-Reply-To: <1215723573.13841.89.camel@localhost.localdomain> References: <20080709215544.0599ea7a@tp.mains.net> <20080710091856.GD23601@redhat.com> <20080710095109.GF9696@redhat.com> <20080710114930.GB14724@redhat.com> <1215723573.13841.89.camel@localhost.localdomain> Message-ID: <20080710213429.GC32272@redhat.com> On Thu, Jul 10, 2008 at 01:59:33PM -0700, David Lutterkort wrote: > On Thu, 2008-07-10 at 07:49 -0400, Daniel Veillard wrote: > > Note the availability of an existing XML description of libvirt APIs > > http://libvirt.org/libvirt-api.xml > > > > Also installed under > > /usr/share/doc/libvirt-*/libvirt-api.xml > > > > you will find for example: > > > > .... > > > > Launch a new Linux guest domain, based on an XML description similar to the one returned by virDomainGetXMLDesc() This function may requires privileged access to the hypervisor. > > > > > > > > > > > > .... > > > > I use that to (mostly) automatize the python libvirt bindings. I do no > > suggest to do the same but a simple XSLT or scripting using those data may > > help doing the AMQP bindings. > > One piece of info that is missing from the above XML, but needed for the > qpid API is the notion of calling a method on an object. The above only > has enough information to generate C-style function calls. > > It's also missing information about what are input and what are output > parameters. > > How about adding an attribute 'role' to the element that would > take one of three values: input, output or receiver, where 'receiver' > says that that is logically the object to which the function/method > belongs ? It ultimately wouldn't help much - you can only practically use this info for methods without output parameters - the complexity is just too hard to make automate it work all methods - I tried and failed to fully automate python bindings. 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 mdehaan at redhat.com Thu Jul 10 21:42:17 2008 From: mdehaan at redhat.com (Michael DeHaan) Date: Thu, 10 Jul 2008 17:42:17 -0400 Subject: [Ovirt-devel] Skipping the Browser :) In-Reply-To: <1215724057.13841.94.camel@localhost.localdomain> References: <4874B928.9060802@redhat.com> <1215724057.13841.94.camel@localhost.localdomain> Message-ID: <48768239.1050405@redhat.com> David Lutterkort wrote: > On Wed, 2008-07-09 at 09:12 -0400, Michael DeHaan wrote: > >> Is everything in ovirt that can be accessed as a GUI (and performed by >> the GUI) accessible as a web service (by this, I mean something simple >> like XMLRPC or JSON-over-REST?). Can there also be an ovirt command >> line for simple scripting integration? >> > > As Ian said, we're in the process of defining an API for that; right now > the htinking is that it will be JSON-over-REST or similar. > > What needs to be exposed is at a minimum > * VM lifecycle management (start/stop/create/destroy/migrate) > * queries for lots of info around the various pools > * defining/organizing resources into pools > * some higher level ops like 'clear all VM's from this host' > > Essentially, everything that you can do through the UI should be > scriptable. > > If you have any specific uses/operations that you want to see supported, > let me know. > Yep, I'm trying to get at least some people from both sides of the fence together ... I'll make sure they hop on here too. Ideally we could have oVirt be the API for all virt operations and we just ask the ovirt server to obey orders. The couple concerns I have for adoptability there is the usage of the F9/F10 storage APIs and so forth, as we have the problem of needing to support RHEL 5 for a long time, so having two APIs and ways of managing virt /might/ be a problem. I am not sure leaving the two side by side makes sense -- which is what I hope we can figure out. --Michael From mdehaan at redhat.com Thu Jul 10 21:48:48 2008 From: mdehaan at redhat.com (Michael DeHaan) Date: Thu, 10 Jul 2008 17:48:48 -0400 Subject: [Ovirt-devel] Details about pending cobbler image support & ovirt integration In-Reply-To: <1215724846.13841.102.camel@localhost.localdomain> References: <4874BCF9.7030900@redhat.com> <1215724846.13841.102.camel@localhost.localdomain> Message-ID: <487683C0.3010602@redhat.com> David Lutterkort wrote: > On Wed, 2008-07-09 at 09:28 -0400, Michael DeHaan wrote: > >> Images are the new object. We want cobbler to track them like other >> objects. >> >> # cobbler image add --name=QuestionableRemondInstallISO >> --file=/mnt/nfs/blah/foo.img >> > > Are images also meant for bare-metal installs or only for VM installs ? > Hopefully both ... I'm doing VMs first. If Linux must be a hypervisor for non-Linux OS's that is not such a bad universe :) >> After that, we also teach "cobbler image add" to track images that can >> be fed to virt-image, AKA virt disk images. This will have a similar >> syntax, most likely... >> >> # cobbler image add --name=MysteryOS --file=/mnt/nfs/blah/foo.img >> --image-type=blah [--virt-ram=] [--virt-disk=] [etc] >> >> The --virt parameters will work basically as they do with cobbler >> profiles today. >> > > It would be much simpler for VM images to tell cobbler to add an > image.xml; all the parameters above are listed in that, and adding a VM > image to a cobbler server would be as simple as > > # cobbler image add /foo/bar/image.xml > That would be doable for virt-image cloning where we have a way to source it from. For ISO installs, admins generally don't like to create XML, so as with virt-install, there needs to be a way to enter it. To do the above, I really need a utility to extract the XML config needed by virt-image from a running/happy guest. Can we do that? > > and koan would basically take the same command line args as virt-image; > the only thing on top of what virt-image does is that koan would have to > make the actual disk files available on the local host. > > There's one small wrinkle: when you instantiate from an image, you can > treat that image either as an immutable template (in which case you'd > have to copy the disk files) or as the image for a specific VM (in which > case you'd directly use the disk files to back the VM) > > >> The next logical step after handling virt-images is perhaps teaching >> cobbler about physical images and cloning tools, though I'm much more >> interested in the virt case, as I have no problem if all the hypervisors >> out there have to run Linux :) >> > > Heh .. yeah, definitely the more interesting first step. > > >> The other thing we might want to talk about are cobbler triggers, which >> could be written to notify ovirt of changes to the cobbler configuration >> -- this is similar to something we are planning with Spacewalk. In >> general, I think ovirt would mostly be giving orders to cobbler, but if >> someone makes a change outside of cobbler, like deleting a virt-image >> ovirt wants to have used, it should probably have a way of knowing it >> should re-scan cobbler XMLRPC to see what changed. >> > > Yeah, might definitely be useful; though very very soon we'll all be > talking amqp, and ovirt can just pick notifications off the bus, right ? > An AMQP notification trigger is definitely possible. (or dbus, though remoteness is always preferable). > David > > > From dlutter at redhat.com Thu Jul 10 22:18:58 2008 From: dlutter at redhat.com (David Lutterkort) Date: Thu, 10 Jul 2008 22:18:58 +0000 Subject: [Ovirt-devel] Details about pending cobbler image support & ovirt integration In-Reply-To: <487683C0.3010602@redhat.com> References: <4874BCF9.7030900@redhat.com> <1215724846.13841.102.camel@localhost.localdomain> <487683C0.3010602@redhat.com> Message-ID: <1215728338.13841.118.camel@localhost.localdomain> On Thu, 2008-07-10 at 17:48 -0400, Michael DeHaan wrote: > David Lutterkort wrote: > > > > It would be much simpler for VM images to tell cobbler to add an > > image.xml; all the parameters above are listed in that, and adding a VM > > image to a cobbler server would be as simple as > > > > # cobbler image add /foo/bar/image.xml > > > > That would be doable for virt-image cloning where we have a way to > source it from. For ISO installs, admins generally don't like to create > XML, so as with virt-install, there needs to be a way to enter it. So we'd have a command line tool that basically templates a few values into a stock image.xml file ? > To do the above, I really need a utility to extract the XML config > needed by virt-image from a running/happy guest. > Can we do that? No, there's no tool currently that goes from libvirt XML -> image XML, though it wouldn't be hard to write (especially given the virt-convert work that John Levon is doing). As with all VM conversions, the real fun is in the disk conversion - for cobbler, you'd need file-based disks, so you'd need to do some conversion if the VM is running off of LVM volumes etc. David From mdehaan at redhat.com Thu Jul 10 22:29:58 2008 From: mdehaan at redhat.com (Michael DeHaan) Date: Thu, 10 Jul 2008 18:29:58 -0400 Subject: [Ovirt-devel] Details about pending cobbler image support & ovirt integration In-Reply-To: <1215728338.13841.118.camel@localhost.localdomain> References: <4874BCF9.7030900@redhat.com> <1215724846.13841.102.camel@localhost.localdomain> <487683C0.3010602@redhat.com> <1215728338.13841.118.camel@localhost.localdomain> Message-ID: <48768D66.7030201@redhat.com> David Lutterkort wrote: > On Thu, 2008-07-10 at 17:48 -0400, Michael DeHaan wrote: > >> David Lutterkort wrote: >> >>> It would be much simpler for VM images to tell cobbler to add an >>> image.xml; all the parameters above are listed in that, and adding a VM >>> image to a cobbler server would be as simple as >>> >>> # cobbler image add /foo/bar/image.xml >>> >>> >> That would be doable for virt-image cloning where we have a way to >> source it from. For ISO installs, admins generally don't like to create >> XML, so as with virt-install, there needs to be a way to enter it. >> > > So we'd have a command line tool that basically templates a few values > into a stock image.xml file ? > Right now I have it working using Cobbler objects to be consistent. These ISO installs are not much different from what koan does now. Hardly anything changes but the install source. > >> To do the above, I really need a utility to extract the XML config >> needed by virt-image from a running/happy guest. >> Can we do that? >> > > No, there's no tool currently that goes from libvirt XML -> image XML, > though it wouldn't be hard to write (especially given the virt-convert > work that John Levon is doing). As with all VM conversions, the real fun > is in the disk conversion - for cobbler, you'd need file-based disks, so > you'd need to do some conversion if the VM is running off of LVM volumes > etc. > > David > > > virt-convert sounds very neat. I'll have to ping John. From bkearney at redhat.com Fri Jul 11 12:02:57 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Fri, 11 Jul 2008 08:02:57 -0400 Subject: [Ovirt-devel] Details about pending cobbler image support & ovirt integration In-Reply-To: <48768D66.7030201@redhat.com> References: <4874BCF9.7030900@redhat.com> <1215724846.13841.102.camel@localhost.localdomain> <487683C0.3010602@redhat.com> <1215728338.13841.118.camel@localhost.localdomain> <48768D66.7030201@redhat.com> Message-ID: <48774BF1.9040303@redhat.com> Michael DeHaan wrote: > David Lutterkort wrote: >> On Thu, 2008-07-10 at 17:48 -0400, Michael DeHaan wrote: >> >>> David Lutterkort wrote: >>> >>>> It would be much simpler for VM images to tell cobbler to add an >>>> image.xml; all the parameters above are listed in that, and adding a VM >>>> image to a cobbler server would be as simple as >>>> # cobbler image add /foo/bar/image.xml >>>> >>> That would be doable for virt-image cloning where we have a way to >>> source it from. For ISO installs, admins generally don't like to >>> create >>> XML, so as with virt-install, there needs to be a way to enter it. >>> >> >> So we'd have a command line tool that basically templates a few values >> into a stock image.xml file ? >> > > Right now I have it working using Cobbler objects to be consistent. > These ISO installs > are not much different from what koan does now. Hardly anything changes > but the install > source. Is it jus ISO format, or will you support raw disk images as well? From bkearney at redhat.com Fri Jul 11 12:07:29 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Fri, 11 Jul 2008 08:07:29 -0400 Subject: [Ovirt-devel] Details about pending cobbler image support & ovirt integration In-Reply-To: <1215724846.13841.102.camel@localhost.localdomain> References: <4874BCF9.7030900@redhat.com> <1215724846.13841.102.camel@localhost.localdomain> Message-ID: <48774D01.6060805@redhat.com> David Lutterkort wrote: > On Wed, 2008-07-09 at 09:28 -0400, Michael DeHaan wrote: >> Images are the new object. We want cobbler to track them like other >> objects. >> >> # cobbler image add --name=QuestionableRemondInstallISO >> --file=/mnt/nfs/blah/foo.img > > Are images also meant for bare-metal installs or only for VM installs ? > >> After that, we also teach "cobbler image add" to track images that can >> be fed to virt-image, AKA virt disk images. This will have a similar >> syntax, most likely... >> >> # cobbler image add --name=MysteryOS --file=/mnt/nfs/blah/foo.img >> --image-type=blah [--virt-ram=] [--virt-disk=] [etc] >> >> The --virt parameters will work basically as they do with cobbler >> profiles today. > > It would be much simpler for VM images to tell cobbler to add an > image.xml; all the parameters above are listed in that, and adding a VM > image to a cobbler server would be as simple as > > # cobbler image add /foo/bar/image.xml > > and koan would basically take the same command line args as virt-image; > the only thing on top of what virt-image does is that koan would have to > make the actual disk files available on the local host. > > There's one small wrinkle: when you instantiate from an image, you can > treat that image either as an immutable template (in which case you'd > have to copy the disk files) or as the image for a specific VM (in which > case you'd directly use the disk files to back the VM) I would assume that you are using cobbler to provisiion.. so it is more of the former. Given Michaels description abovethe image is a combination of distro+profile.. not system. From pmyers at redhat.com Fri Jul 11 13:54:38 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Fri, 11 Jul 2008 09:54:38 -0400 Subject: [Ovirt-devel] Re: [PATCH] Add additional blacklisting and rpm removal to managed node In-Reply-To: <1215672833-16485-1-git-send-email-apevec@redhat.com> References: <4873263C.3010302@redhat.com> <1215672833-16485-1-git-send-email-apevec@redhat.com> Message-ID: <4877661E.8040605@redhat.com> Alan Pevec wrote: > From: Perry Myers > > A few important notes: > 1. /lib/modules was scoured for things that didn't seem necessary, however > my notion of not necessary may not be correct. Please review the list > of modules that I'm removing and if you see one that we need to add back > in, comment. > 2. /boot is removed as we don't need an initrd and kernel image inside of > the livecd initrd. > 3. The blacklisting method is a hack. What we need is an appliance creator > that has black/whitelisting capabilities... (hint, hint to our AOS > friends out there) > > NOTE: This patch is revised from my patch last week. I incorporated > suggestions from Chris regarding reinclusion of some kernel modules and > fixed an issue with i386 builds by not wiping out /lib/security. With > this patch both i386 and x86_64 managed nodes boot and work. > > Signed-off-by: Perry Myers > > - use lib{,64} in the blacklist > - drop copying /etc/timezone, fixed in livecd-tools >= 0.17.1 > check for RPM version in Makefile > > Signed-off-by: Alan Pevec ACK. This patch has gone back and forth enough now... I'm going to commit/push this. Perry > --- > ovirt-host-creator/Makefile | 1 + > ovirt-host-creator/common-post.ks | 99 +++++++++++++++++++++++-------------- > ovirt-host-creator/rpm-compare.py | 39 ++++++++++++++ > 3 files changed, 101 insertions(+), 38 deletions(-) > create mode 100755 ovirt-host-creator/rpm-compare.py > > diff --git a/ovirt-host-creator/Makefile b/ovirt-host-creator/Makefile > index 6ebdfbd..1f0122f 100644 > --- a/ovirt-host-creator/Makefile > +++ b/ovirt-host-creator/Makefile > @@ -13,6 +13,7 @@ repos.ks: repos.ks.in > sed "s/@@ARCH@@/$(ARCH)/" repos.ks.in > repos.ks > > build: ovirt.ks common-install.ks common-pkgs.ks common-post.ks repos.ks > + ./rpm-compare.py GE 0 livecd-tools 017.1 1 > ./ovirt-cd > ovirt-cd.log 2>&1 > > tar: clean build > diff --git a/ovirt-host-creator/common-post.ks b/ovirt-host-creator/common-post.ks > index 2f7b612..b21f52c 100644 > --- a/ovirt-host-creator/common-post.ks > +++ b/ovirt-host-creator/common-post.ks > @@ -9,13 +9,6 @@ echo "Creating shadow files" > pwconv > grpconv > > -echo "Re-creating cracklib dicts" > -# cracklib-dicts is 8MB. We probably don't need to have strict password > -# checking on the ovirt host > -# unfortunately we can't create an empty cracklib dict, so we create it > -# with a single entry "1" > -echo 1 | packer >& /dev/null > - > echo "Forcing C locale" > # force logins (via ssh, etc) to use C locale, since we remove locales > cat >> /etc/profile << \EOF > @@ -41,9 +34,6 @@ cat > /etc/sysconfig/iptables << \EOF > COMMIT > EOF > > -# here, remove a bunch of files we don't need that are just eating up space. > -# it breaks rpm slightly, but it's not too bad > - > echo "Removing excess RPMs" > > # kernel pulls in mkinitrd which pulls in isomd5sum which pulls in python, > @@ -54,36 +44,30 @@ rpm -e system-config-firewall-tui system-config-network-tui rhpl \ > rpm-python dbus-python kudzu newt-python newt > rpm -e qemu kpartx mkinitrd isomd5sum dmraid python python-libs > > +RPM="rpm -v -e --nodeps" > + > # Sigh. ntp has a silly dependency on perl because of auxiliary scripts which > # we don't need to use. Forcibly remove it here > -rpm -e --nodeps perl perl-libs perl-Module-Pluggable perl-version \ > +$RPM perl perl-libs perl-Module-Pluggable perl-version \ > perl-Pod-Simple perl-Pod-Escapes > > -RM="rm -rf" > +# Remove additional RPMs forcefully > +$RPM gamin pm-utils kbd libuser passwd usermode \ > + openssh-clients vbetool ConsoleKit hdparm \ > + efibootmgr krb5-workstation linux-atm-libs fedora-release-notes \ > + slang psmisc gdbm cryptsetup-luks pciutils mtools syslinux db4 \ > + wireless-tools radeontool cracklib-dicts cracklib > > -echo "Removing docs and internationalization" > -$RM /usr/share/omf > -$RM /usr/share/gnome > -$RM /usr/share/doc > -$RM /usr/share/locale > -$RM /usr/share/libthai > -$RM /usr/share/man > -$RM /usr/share/terminfo > -$RM /usr/share/X11 > -$RM /usr/share/i18n > +# Things we could probably remove if libvirt didn't link against them > +#$RPM avahi PolicyKit xen-libs > > -find /usr/share/zoneinfo -regextype egrep -type f \ > - ! -regex ".*/UTC" -exec $RM {} \; > -# XXX anaconda/timezone.py does it, missing in imgcreate/kickstart.py > -cp /usr/share/zoneinfo/UTC /etc/localtime > - > -$RM /usr/lib/locale > -$RM /usr/lib/syslinux > -$RM /usr/lib64/gconv > -$RM /usr/lib64/pango > -$RM /usr/lib64/libpango* > -$RM /etc/pango > -$RM /usr/bin/pango* > +# Things we could probably remove if qemu-kvm didn't link against them > +#$RPM SDL alsa-lib > + > +# Pam complains when this is missing > +#$RPM ConsoleKit-libs > + > +RM="rm -rf" > > echo "Removing excess kernel modules" > MODULES="/lib/modules/*/kernel" > @@ -101,16 +85,55 @@ fs_mods="fs/nls fs/9p fs/affs fs/autofs fs/autofs4 fs/befs fs/bfs fs/cifs \ > net_mods="net/802 net/8021q net/9p net/appletalk net/atm net/ax25 \ > net/bluetooth net/dccp net/decnet net/ieee80211 net/ipx net/irda \ > net/mac80211 net/netrom net/rfkill net/rose net/sched net/tipc \ > - net/wanrouter net/wireless drivers/auxdisplay drivers/net/appletalk \ > + net/wanrouter net/wireless" > + > +driver_mods="drivers/auxdisplay drivers/net/appletalk \ > drivers/net/hamradio drivers/net/pcmcia drivers/net/tokenring \ > - drivers/net/wireless drivers/net/irda drivers/atm drivers/usb/atm" > + drivers/net/wireless drivers/net/irda drivers/atm drivers/usb/atm \ > + drivers/acpi drivers/char/drm drivers/char/mwave \ > + drivers/char/ipmp drivers/char/pcmcia drivers/crypto drivers/dca \ > + drivers/firmware drivers/memstick drivers/mmc drivers/mfs \ > + drivers/parport drivers/video drivers/watchdog drivers/net/ppp* \ > + drivers/usb/serial drivers/usb/misc drivers/usb/class \ > + drivers/usb/image drivers/rtc" > > misc_mods="drivers/bluetooth drivers/firewire drivers/i2c drivers/isdn \ > drivers/media drivers/misc drivers/leds drivers/mtd drivers/w1 sound \ > - drivers/input drivers/pcmcia drivers/scsi/pcmcia" > + drivers/input drivers/pcmcia drivers/scsi/pcmcia crypto lib" > > -for mods in $fs_mods $net_mods $misc_mods ; do > +for mods in $fs_mods $net_mods $misc_mods $driver_mods ; do > $RM $MODULES/$mods > done > > +echo "Removing all timezones except for UTC" > +find /usr/share/zoneinfo -regextype egrep -type f \ > + ! -regex ".*/UTC|.*/GMT" -exec $RM {} \; > + > +echo "Removing blacklisted files and directories" > +blacklist="/boot /etc/alsa /etc/pki /usr/share/hwdata/MonitorsDB \ > + /usr/share/hwdata/oui.txt /usr/share/hwdata/videoaliases \ > + /usr/share/hwdata/videodrivers /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/src /usr/etc /usr/games /usr/include /usr/local /usr/lib{,64}/python2.5 \ > + /usr/{,lib64}/tc /usr/lib{,64}/tls /usr/lib{,64}/sse2 /usr/lib{,64}/pkgconfig \ > + /usr/lib{,64}/nss /usr/lib{,64}/X11 /usr/lib{,64}/games /usr/lib{,64}/alsa-lib \ > + /usr/lib{,64}/fs/reiserfs /usr/lib{,64}/krb5 /usr/lib{,64}/hal /usr/lib{,64}/gio \ > + /usr/bin/hal-device /usr/bin/hal-disable-polling \ > + /usr/bin/hal-find-by-capability /usr/bin/hal-find-by-property \ > + /usr/bin/hal-is-caller-locked-out /usr/bin/hal-is-caller-privileged \ > + /usr/bin/hal-lock /usr/bin/hal-set-property /usr/bin/hal-setup-keymap \ > + /usr/sbin/dell* /lib/terminfo/d /lib/terminfo/v /lib/terminfo/a \ > + /lib/firmware /usr/lib/locale /usr/lib/syslinux /usr/lib{,64}/gconv \ > + /usr/lib{,64}/pango /usr/lib{,64}/libpango* /etc/pango /usr/bin/pango*" > + > +docs_blacklist="/usr/share/omf /usr/share/gnome /usr/share/doc \ > + /usr/share/locale /usr/share/libthai /usr/share/man /usr/share/terminfo \ > + /usr/share/X11 /usr/share/i18n" > + > +$RM $blacklist $docs_blacklist > + > +echo "Cleanup empty directory structures in /usr/share" > +find /usr/share -type d -exec rmdir {} \; > /dev/null 2>&1 > + > echo "Finished Kickstart Post" > diff --git a/ovirt-host-creator/rpm-compare.py b/ovirt-host-creator/rpm-compare.py > new file mode 100755 > index 0000000..f91b02f > --- /dev/null > +++ b/ovirt-host-creator/rpm-compare.py > @@ -0,0 +1,39 @@ > +#!/usr/bin/python > +# > +# rpm-compare.py - return 0 if installed package version satisfies condition > + > +import sys > +import rpm > +import rpmUtils.miscutils as rpmutils > +# pkgTupleFromHeader(hdr) -> (name, arch, epoch, ver, rel) > +# rangeCheck(reqtuple, pkgtuple) reqtuple := (reqn, reqf, (reqe, reqv, reqr)) > + > +def usage(): > + print "usage: %s {GE|GT|EQ|LE|LT} epoch name ver rel \n" % sys.argv[0] > + sys.exit(1) > + > +if len(sys.argv) < 6: > + usage() > + > +cond = sys.argv[1] > +epoch = sys.argv[2] > +name = sys.argv[3] > +ver = sys.argv[4] > +rel = sys.argv[5] > + > +if cond not in ('GE','GT','EQ','LE','LT'): > + usage() > + > +#broken from pkgs with - in the name > +#name, ver, rel, epoch, arch = rpmutils.splitFilename(rpmname) > +##print "epoch %s name %s ver %s rel %s" % (epoch, name, ver, rel) > + > +ts = rpm.TransactionSet() > +for hdr in ts.dbMatch('name', name): > + (n, a, e, v, r) = rpmutils.pkgTupleFromHeader(hdr) > + ##print (n, a, e, v, r) > + if rpmutils.rangeCheck((name, cond, (epoch, ver, rel)), (n, a, e, v, r)) == 1: > + exit(0) > +print 'RPM condition not satisfied' > +exit(1) > + -- |=- 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 Jul 11 15:25:52 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Fri, 11 Jul 2008 11:25:52 -0400 Subject: [Ovirt-devel] [herrold@owlriver.com: Re: OLPC & package dependency growth] In-Reply-To: <20080709213755.GJ716@redhat.com> References: <20080709213755.GJ716@redhat.com> Message-ID: <48777B80.9020307@redhat.com> Daniel P. Berrange wrote: > The idea of 4k -> 512 byte sectors probably won't help our size > because the wasted space from files smaller than 4k will compress > nicely with squashfs - but would killing the journal gain us any > significant space ? re: ext2 vs ext3... I ran a quick test and on the Managed Node it saves about 800K on the compressed image size. So it dropped from 57064392 to 56211019. Probably worth doing since we're not getting anything out of ext3 in this environment anyhow. Perry From pmyers at redhat.com Fri Jul 11 15:49:09 2008 From: pmyers at redhat.com (Perry Myers) Date: Fri, 11 Jul 2008 11:49:09 -0400 Subject: [Ovirt-devel] [PATCH] Switch / on Managed Node to be ext2. Saves about 1MB on the compressed image Message-ID: <1215791349-7245-1-git-send-email-pmyers@redhat.com> Signed-off-by: Perry Myers --- ovirt-host-creator/common-install.ks | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/ovirt-host-creator/common-install.ks b/ovirt-host-creator/common-install.ks index ced731e..badc847 100644 --- a/ovirt-host-creator/common-install.ks +++ b/ovirt-host-creator/common-install.ks @@ -4,7 +4,7 @@ timezone --utc UTC auth --useshadow --enablemd5 selinux --disabled firewall --disabled -part / --size 550 +part / --size 550 --fstype ext2 services --enabled=ntpd,ntpdate,collectd,iptables,network bootloader --timeout=1 rootpw --iscrypted Xa8QeYfWrtscM -- 1.5.5.1 From mdehaan at redhat.com Fri Jul 11 16:12:10 2008 From: mdehaan at redhat.com (Michael DeHaan) Date: Fri, 11 Jul 2008 12:12:10 -0400 Subject: [Ovirt-devel] Details about pending cobbler image support & ovirt integration In-Reply-To: <48774BF1.9040303@redhat.com> References: <4874BCF9.7030900@redhat.com> <1215724846.13841.102.camel@localhost.localdomain> <487683C0.3010602@redhat.com> <1215728338.13841.118.camel@localhost.localdomain> <48768D66.7030201@redhat.com> <48774BF1.9040303@redhat.com> Message-ID: <4877865A.8000305@redhat.com> Bryan Kearney wrote: > > > Michael DeHaan wrote: >> David Lutterkort wrote: >>> On Thu, 2008-07-10 at 17:48 -0400, Michael DeHaan wrote: >>> >>>> David Lutterkort wrote: >>>> >>>>> It would be much simpler for VM images to tell cobbler to add an >>>>> image.xml; all the parameters above are listed in that, and adding >>>>> a VM >>>>> image to a cobbler server would be as simple as >>>>> # cobbler image add /foo/bar/image.xml >>>>> >>>> That would be doable for virt-image cloning where we have a way to >>>> source it from. For ISO installs, admins generally don't like to >>>> create >>>> XML, so as with virt-install, there needs to be a way to enter it. >>>> >>> >>> So we'd have a command line tool that basically templates a few values >>> into a stock image.xml file ? >>> >> >> Right now I have it working using Cobbler objects to be consistent. >> These ISO installs >> are not much different from what koan does now. Hardly anything >> changes but the install >> source. > > Is it jus ISO format, or will you support raw disk images as well? > > Disks also. From dpierce at redhat.com Fri Jul 11 19:28:50 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Fri, 11 Jul 2008 15:28:50 -0400 Subject: [Ovirt-devel] [PATCH] Adding NIC details to ovirt identify stage. Message-ID: <1215804530-31082-1-git-send-email-dpierce@redhat.com> This patch includes submitting to the server the MAC address and bandwidth, as determined via HAL, for each physical NIC in the machine. The source code for the ovirt-identify-node was split up as well to make it easier to review and manage. Signed-off-by: Darryl L. Pierce --- ovirt-managed-node/ovirt-managed-node.spec | 2 + ovirt-managed-node/src/Makefile | 6 +- ovirt-managed-node/src/comm.c | 87 +++ ovirt-managed-node/src/debug.c | 48 ++ ovirt-managed-node/src/gather.c | 278 +++++++++ ovirt-managed-node/src/hal_support.c | 65 ++ ovirt-managed-node/src/main.c | 216 +++++++ ovirt-managed-node/src/ovirt-identify-node.c | 653 -------------------- ovirt-managed-node/src/ovirt-identify-node.h | 119 +++- ovirt-managed-node/src/protocol.c | 276 +++++++++ ovirt-managed-node/src/scripts/ovirt-post | 9 +- wui/src/host-browser/host-browser.rb | 84 +++- wui/src/host-browser/test-host-browser-identify.rb | 42 ++- 13 files changed, 1195 insertions(+), 690 deletions(-) create mode 100644 ovirt-managed-node/src/comm.c create mode 100644 ovirt-managed-node/src/debug.c create mode 100644 ovirt-managed-node/src/gather.c create mode 100644 ovirt-managed-node/src/hal_support.c create mode 100644 ovirt-managed-node/src/main.c delete mode 100644 ovirt-managed-node/src/ovirt-identify-node.c create mode 100644 ovirt-managed-node/src/protocol.c diff --git a/ovirt-managed-node/ovirt-managed-node.spec b/ovirt-managed-node/ovirt-managed-node.spec index 4e14b08..0cd3aa8 100644 --- a/ovirt-managed-node/ovirt-managed-node.spec +++ b/ovirt-managed-node/ovirt-managed-node.spec @@ -12,7 +12,9 @@ URL: http://www.ovirt.org/ Requires(post): /sbin/chkconfig Requires(preun): /sbin/chkconfig BuildRequires: libvirt-devel +BuildRequires: dbus-devel hal-devel Requires: libvirt +Requires: hal ExclusiveArch: %{ix86} x86_64 %define app_root %{_datadir}/%{name} diff --git a/ovirt-managed-node/src/Makefile b/ovirt-managed-node/src/Makefile index 1991e46..d5e4093 100644 --- a/ovirt-managed-node/src/Makefile +++ b/ovirt-managed-node/src/Makefile @@ -17,9 +17,9 @@ # also available at http://www.gnu.org/copyleft/gpl.html. CC=gcc -CFLAGS=-Wall -c -g -LFLAGS=-lvirt -OBJECTS=ovirt-identify-node.o +CFLAGS=-Wall -c -g $(shell pkg-config --cflags dbus-1) +LFLAGS=-lhal -lvirt +OBJECTS=comm.o gather.o hal_support.o main.o protocol.o TARGET=ovirt-identify-node SOURCES=\ ovirt-identify-node.c diff --git a/ovirt-managed-node/src/comm.c b/ovirt-managed-node/src/comm.c new file mode 100644 index 0000000..a63a58d --- /dev/null +++ b/ovirt-managed-node/src/comm.c @@ -0,0 +1,87 @@ +/* comm.c -- Contains communications routines. + * + * Copyright (C) 2008 Red Hat, Inc. + * Written by Darryl L. Pierce + * + * 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. + */ + +#include "ovirt-identify-node.h" + +ssize_t saferead(int fd, char *buf, size_t count) +{ + ssize_t bytes,offset; + int len_left; + int done = 0; + + DEBUG("Begin saferead(%d, %p, %d)\n", fd, buf, count); + + offset = 0; + len_left = count; + + + while(!done) + { + DEBUG("Before read(%d,%p,%d)\n",fd,buf+offset,len_left); + + bytes = read(fd, buf+offset, len_left); + + DEBUG("After read: bytes=%d\n", bytes); + + if(bytes == 0) + { + done = 1; + } + else if(bytes > 0) + { + offset += bytes; + len_left -= bytes; + done = 1; + } + else if(errno == EINTR) + { + continue; + } + else + { + done = 1; + } + + DEBUG("End of decision loop: offset=%d, len_left=%dl, done=%d\n",offset, len_left, done); + } + + return offset; +} + +ssize_t safewrite(int fd, const void *buf, size_t count) +{ + size_t nwritten = 0; + while (count > 0) { + ssize_t r = write(fd, buf, count); + + if (r < 0 && errno == EINTR) + continue; + if (r < 0) + return r; + if (r == 0) + return nwritten; + buf = (const char *)buf + r; + count -= r; + nwritten += r; + } + return nwritten; +} + diff --git a/ovirt-managed-node/src/debug.c b/ovirt-managed-node/src/debug.c new file mode 100644 index 0000000..807d88b --- /dev/null +++ b/ovirt-managed-node/src/debug.c @@ -0,0 +1,48 @@ +/* debug.c -- Debugging methods. + * + * Copyright (C) 2008 Red Hat, Inc. + * Written by Darryl L. Pierce + * + * 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. + */ + +#include "ovirt-identify-node.h" + +void debug_cpu_info(void) +{ + fprintf(stdout,"Node Info:\n"); + fprintf(stdout," UUID: %s\n", uuid); + fprintf(stdout," Arch: %s\n", arch); + fprintf(stdout," Memory: %s\n", memsize); + + t_cpu_info* current = cpu_info; + while(current != NULL) + { + fprintf(stdout,"\n"); + fprintf(stdout," CPU Number: %s\n", current->cpu_num); + fprintf(stdout," Core Number: %s\n", current->core_num); + fprintf(stdout,"Number of Cores: %s\n", current->number_of_cores); + fprintf(stdout," Vendor: %s\n", current->vendor); + fprintf(stdout," Model: %s\n", current->model); + fprintf(stdout," Family: %s\n", current->family); + fprintf(stdout," CPUID Level: %s\n", current->cpuid_level); + fprintf(stdout," CPU Speed: %s\n", current->speed); + fprintf(stdout," Cache Size: %s\n", current->cache); + fprintf(stdout," CPU Flags: %s\n", current->flags); + + current = current->next; + } +} diff --git a/ovirt-managed-node/src/gather.c b/ovirt-managed-node/src/gather.c new file mode 100644 index 0000000..d18eb86 --- /dev/null +++ b/ovirt-managed-node/src/gather.c @@ -0,0 +1,278 @@ +/* gather.c -- Contains methods for collecting data about the system. + * + * Copyright (C) 2008 Red Hat, Inc. + * Written by Darryl L. Pierce + * + * 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. + */ + +#include "ovirt-identify-node.h" + +int init_gather(void) +{ + int result = 1; + + hal_ctx = get_hal_ctx(); + + if(hal_ctx != NULL) + { + result = 0; + } + + return result; +} + +int get_uuid(void) +{ + const char* udi = "/org/freedesktop/Hal/devices/computer"; + const char* key = "system.hardware.uuid"; + + VERBOSE("Getting system UUID.\n"); + + int result = 1; + int type; + + type = libhal_device_get_property_type(hal_ctx,udi,key,&dbus_error); + + if(type == LIBHAL_PROPERTY_TYPE_STRING) + { + char* value; + + DEBUG("%s/%s=%d\n",udi,key,type); + + value = libhal_device_get_property_string(hal_ctx,udi,key,&dbus_error); + snprintf(uuid,BUFFER_LENGTH,"%s",value); + + DEBUG("UUID=%s\n",uuid); + + result = 0; + } + + return result; +} + +/* Creates a new instance of type t_cpu_info and places it into the + * linked list of CPUs. + */ +t_cpu_info* create_cpu_info(void) +{ + t_cpu_info* result = calloc(1,sizeof(t_cpu_info)); + bzero(result,sizeof(t_cpu_info)); + + strcpy(result->core_num,"0"); + strcpy(result->number_of_cores,"1"); + + return result; +} + +int get_cpu_info(void) +{ + int result = 1; + FILE* inputfd; + t_cpu_info* current = NULL; + + if(( inputfd = fopen("/proc/cpuinfo","rb")) != NULL) + { + VERBOSE("Parsing CPU information\n"); + do + { + char buffer[255]; + char label[BUFFER_LENGTH]; + char value[BUFFER_LENGTH]; + + fgets(buffer, 255, inputfd); + if(strlen(buffer) > 0) buffer[strlen(buffer) - 1] = '\0'; + + get_label_and_value(buffer, + label,BUFFER_LENGTH, + value,BUFFER_LENGTH); + + DEBUG("label=\"%s\", value=\"%s\"\n", label, value); + + if(strlen(label)) + { + if(!strcmp(label,"processor")) + { + VERBOSE("Starting new CPU\n"); + + t_cpu_info* last = current; + + current = create_cpu_info(); + if(last != NULL) + { + last->next = current; + } + else + { + cpu_info = current; + } + + COPY_VALUE_TO_BUFFER(value,current->cpu_num,BUFFER_LENGTH); + } + else + if(!strcmp(label,"core id")) + { + COPY_VALUE_TO_BUFFER(value,current->core_num,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cpu cores")) + { + COPY_VALUE_TO_BUFFER(value,current->number_of_cores,BUFFER_LENGTH); + } + else + if(!strcmp(label,"vendor_id")) + { + COPY_VALUE_TO_BUFFER(value,current->vendor,BUFFER_LENGTH); + } + else + if(!strcmp(label,"model")) + { + COPY_VALUE_TO_BUFFER(value,current->model,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cpu family")) + { + COPY_VALUE_TO_BUFFER(value,current->family,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cpuid level")) + { + COPY_VALUE_TO_BUFFER(value,current->cpuid_level,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cpu MHz")) + { + COPY_VALUE_TO_BUFFER(value,current->speed,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cache size")) + { + COPY_VALUE_TO_BUFFER(value,current->cache,BUFFER_LENGTH); + } + else + if(!strcmp(label,"flags")) + { + COPY_VALUE_TO_BUFFER(value,current->flags,BUFFER_LENGTH); + } + } + + } while(!feof(inputfd)); + + fclose(inputfd); + + result = 0; + } + else + { + VERBOSE("Unable to open /proc/cpuinfo\n"); + } + + return result; +} + +/* Creates a new instance of type t_nic_info. + */ +t_nic_info* create_nic_info(void) +{ + t_nic_info* result = calloc(1,sizeof(t_nic_info)); + bzero(result,sizeof(t_nic_info)); + + return result; +} + +/* Determines the speed of the network interface. + */ +void get_nic_data(char* nic,t_nic_info* nic_info) +{ + char* interface; + struct ifreq ifr; + int sockfd; + struct ethtool_cmd ecmd; + + interface = libhal_device_get_property_string(hal_ctx,nic,"net.interface", + &dbus_error); + bzero(&ifr,sizeof(struct ifreq)); + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if(sockfd >= 0) + { + int bandwidth; + + ifr.ifr_addr.sa_family = AF_INET; + strncpy(ifr.ifr_name,interface,IFNAMSIZ-1); + + ioctl(sockfd, SIOCETHTOOL, &ifr); + close(sockfd); + + bandwidth = 10; + if (ecmd.supported & SUPPORTED_10000baseT_Full) + bandwidth = 10000; + else if (ecmd.supported & SUPPORTED_2500baseX_Full) + bandwidth = 2500; + else if (ecmd.supported & (SUPPORTED_1000baseT_Half|SUPPORTED_1000baseT_Full)) + bandwidth = 1000; + else if (ecmd.supported & (SUPPORTED_100baseT_Half|SUPPORTED_100baseT_Full)) + bandwidth = 100; + else if (ecmd.supported & (SUPPORTED_10baseT_Half|SUPPORTED_10baseT_Full)) + bandwidth = 10; + + snprintf(nic_info->bandwidth,BUFFER_LENGTH,"%d",bandwidth); + } +} + +int get_nic_info(void) +{ + int result = 0; + t_nic_info* current = NULL; + t_nic_info* last = NULL; + + char** nics; + int num_results; + int index; + + nics = libhal_find_device_by_capability(hal_ctx,"net", + &num_results,&dbus_error); + + DEBUG("Found %d NICs\n", num_results); + + for(index = 0;index < num_results;index++) + { + char* nic = nics[index]; + + VERBOSE("Starting new NIC.\n"); + + if(current != NULL) + { + last = current; + current = create_nic_info(); + last->next = current; + } + else + { + nic_info = current = create_nic_info(); + } + + snprintf(current->mac_address,BUFFER_LENGTH,"%s", + libhal_device_get_property_string(hal_ctx,nic,"net.address", + &dbus_error)); + get_nic_data(nic,current); + + DEBUG("NIC details: MAC:%s, speed:%s, IP:%s\n", + nic_info->mac_address, nic_info->bandwidth,nic_info->ip_address); + } + + return result; +} diff --git a/ovirt-managed-node/src/hal_support.c b/ovirt-managed-node/src/hal_support.c new file mode 100644 index 0000000..58ee29b --- /dev/null +++ b/ovirt-managed-node/src/hal_support.c @@ -0,0 +1,65 @@ +/* hal_support.c -- Interfaces with the HAL libraries. + * + * Copyright (C) 2008 Red Hat, Inc. + * Written by Darryl L. Pierce + * + * 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. + */ + +#include "ovirt-identify-node.h" + +DBusConnection* dbus_connection; +DBusError dbus_error; + +LibHalContext* get_hal_ctx(void) +{ + LibHalContext* result = NULL; + LibHalContext* ctx; + + ctx = libhal_ctx_new(); + if(ctx != NULL) + { + dbus_error_init(&dbus_error); + dbus_connection = dbus_bus_get(DBUS_BUS_SYSTEM,&dbus_error); + + if(!dbus_error_is_set(&dbus_error)) + { + libhal_ctx_set_dbus_connection(ctx,dbus_connection); + + if(libhal_ctx_init(ctx,&dbus_error)) + { + result = ctx; + } + else + { + fprintf(stderr,"Failed to initial libhal context: %s : %s\n", + dbus_error.name, dbus_error.message); + } + } + else + { + fprintf(stderr,"Unable to connect to system bus: %s : %s\n", + dbus_error.name, dbus_error.message); + dbus_error_free(&dbus_error); + } + } + else + { + fprintf(stderr,"Unable to initialize HAL context.\n"); + } + + return result; +} diff --git a/ovirt-managed-node/src/main.c b/ovirt-managed-node/src/main.c new file mode 100644 index 0000000..29e08a5 --- /dev/null +++ b/ovirt-managed-node/src/main.c @@ -0,0 +1,216 @@ +/* identify-node -- Main entry point for the identify-node utility. + * + * Copyright (C) 2008 Red Hat, Inc. + * Written by Darryl L. Pierce + * + * 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. + */ + +#include "ovirt-identify-node.h" + +int debug = 0; +int verbose = 0; +int testing = 0; + +char arch[BUFFER_LENGTH]; +char uuid[BUFFER_LENGTH]; +char memsize[BUFFER_LENGTH]; +char numcpus[BUFFER_LENGTH]; +char cpuspeed[BUFFER_LENGTH]; +char *hostname; +int hostport = -1; +int socketfd; +t_cpu_info* cpu_info; +t_nic_info* nic_info; + +LibHalContext* hal_ctx; + +int main(int argc,char** argv) +{ + int result = 1; + virConnectPtr connection; + virNodeInfo info; + + fprintf(stdout,"Sending managed node details to server.\n"); + + if(!config(argc,argv)) + { + VERBOSE("Connecting to libvirt.\n"); + + connection = virConnectOpenReadOnly(testing ? "test:///default" : NULL); + + DEBUG("connection=%p\n",connection); + + if(connection) + { + VERBOSE("Retrieving node information.\n"); + if(!virNodeGetInfo(connection,&info)) + { + snprintf(arch, BUFFER_LENGTH, "%s", info.model); + snprintf(memsize, BUFFER_LENGTH, "%ld", info.memory); + + cpu_info = NULL; + nic_info = NULL; + + if(!init_gather() && !get_uuid() && !get_cpu_info() && !get_nic_info()) + { + if(!start_conversation() && !send_details() && !end_conversation()) + { + fprintf(stdout,"Finished!\n"); + result = 0; + } + } + else + { + VERBOSE("Failed to get CPU info.\n"); + } + } + else + { + VERBOSE("Failed to get node info.\n"); + } + } + else + { + VERBOSE("Could not connect to libvirt.\n"); + } + } + else + { + usage(); + } + + return result; +} + +int config(int argc,char** argv) +{ + int result = 0; + int option; + + while((option = getopt(argc,argv,"s:p:dvth")) != -1) + { + DEBUG("Processing argument: %c (optarg:%s)\n",option,optarg); + + switch(option) + { + case 's': hostname = optarg; break; + case 'p': hostport = atoi(optarg); break; + case 't': testing = 1; break; + case 'd': debug = 1; break; + case 'v': verbose = 1; break; + case 'h': + // fall thru + default : result = 1; break; + } + } + + // verify that required options are provided + if(hostname == NULL || strlen(hostname) == 0) + { + fprintf(stderr,"ERROR: The server name is required. (-s [hostname])\n"); + result = 1; + } + + if(hostport <= 0) + { + fprintf(stderr,"ERROR: The server port is required. (-p [port])\n"); + result = 1; + } + + return result; +} + +void usage() +{ + fprintf(stdout,"\n"); + fprintf(stdout,"Usage: ovirt-identify [OPTION]\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"\t-s [server]\t\tThe remote server's hostname.\n"); + fprintf(stdout,"\t-p [port]\t\tThe remote server's port.\n"); + fprintf(stdout,"\t-d\t\tDisplays debug information during execution.\n"); + fprintf(stdout,"\t-v\t\tDisplays verbose information during execution.\n"); + fprintf(stdout,"\t-h\t\tDisplays this help information and then exits.\n"); + fprintf(stdout,"\n"); +} + +void get_label_and_value(char* text, + char* label, size_t label_length, + char* value, size_t value_length) +{ + int offset = 0; + int which = 0; /* 0 = label, 1 = value */ + char* current = text; + + /* iterate through the text supplied and find where the + * label ends with a colon, then copy that into the supplied + * label buffer and trim any trailing spaces + */ + + while(current != NULL && *current != '\0') + { + /* if we're on the separator, then switch modes and reset + * the offset indicator, otherwise just process the character + */ + if(which == 0 && *current == ':') + { + which = 1; + offset = 0; + } + else + { + char* buffer = (which == 0 ? label : value); + int length = (which == 0 ? label_length : value_length); + + /* only copy if we're past the first character and it's not + * a space + */ + if((offset > 0 || (*current != 9 && *current != ' ')) && offset < (length - 1)) + { + buffer[offset++] = *current; + buffer[offset] = 0; + } + } + + current++; + } + + /* now trim all trailing spaces from the values */ + while(label[strlen(label) - 1 ] == 9) + label[strlen(label) - 1] = 0; + while(value[strlen(value) - 1] == 9) + value[strlen(value) - 1] = 0; +} + +int get_text(const char *const expected) +{ + int result = 1; + int received; + char buffer[BUFFER_LENGTH]; + bzero(buffer,BUFFER_LENGTH); + + VERBOSE( "Looking to receive %s\n", expected); + + received = saferead(socketfd, buffer, BUFFER_LENGTH); + + buffer[received - 1] = 0; + + VERBOSE("Received \"%s\": size=%d (trimmed ending carriage return)\n", buffer, received); + + result = strcmp(expected,buffer); + + return result; +} diff --git a/ovirt-managed-node/src/ovirt-identify-node.c b/ovirt-managed-node/src/ovirt-identify-node.c deleted file mode 100644 index f114d81..0000000 --- a/ovirt-managed-node/src/ovirt-identify-node.c +++ /dev/null @@ -1,653 +0,0 @@ -/* identify-node -- Main entry point for the identify-node utility. - * - * Copyright (C) 2008 Red Hat, Inc. - * Written by Darryl L. Pierce - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ovirt-identify-node.h" - -int main(int argc,char** argv) -{ - int result = 1; - virConnectPtr connection; - virNodeInfo info; - - fprintf(stdout,"Sending managed node details to server.\n"); - - if(!config(argc,argv)) - { - if(verbose) fprintf(stdout,"Connecting to libvirt.\n"); - - connection = virConnectOpenReadOnly(testing ? "test:///default" : NULL); - - if(debug) fprintf(stderr,"connection=%p\n",connection); - - if(connection) - { - if(verbose) fprintf(stdout,"Getting hostname: %s\n", uuid); - if(!strlen(uuid)) gethostname(uuid,sizeof uuid); - - if(verbose) fprintf(stdout,"Retrieving node information.\n"); - if(!virNodeGetInfo(connection,&info)) - { - snprintf(arch, BUFFER_LENGTH, "%s", info.model); - snprintf(memsize, BUFFER_LENGTH, "%ld", info.memory); - - cpu_info = NULL; - - if(!get_cpu_info()) - { - if(verbose) fprintf(stdout, "Getting CPU info.\n"); - - if(debug) - { - fprintf(stdout,"Node Info:\n"); - fprintf(stdout," UUID: %s\n", uuid); - fprintf(stdout," Arch: %s\n", arch); - fprintf(stdout," Memory: %s\n", memsize); - - t_cpu_info* current = cpu_info; - while(current != NULL) - { - fprintf(stdout,"\n"); - fprintf(stdout," CPU Number: %s\n", current->cpu_num); - fprintf(stdout," Core Number: %s\n", current->core_num); - fprintf(stdout,"Number of Cores: %s\n", current->number_of_cores); - fprintf(stdout," Vendor: %s\n", current->vendor); - fprintf(stdout," Model: %s\n", current->model); - fprintf(stdout," Family: %s\n", current->family); - fprintf(stdout," CPUID Level: %s\n", current->cpuid_level); - fprintf(stdout," CPU Speed: %s\n", current->speed); - fprintf(stdout," Cache Size: %s\n", current->cache); - fprintf(stdout," CPU Flags: %s\n", current->flags); - - current = current->next; - } - } - - if(verbose) fprintf(stdout, "Retrieved node information.\n"); - - if(!start_conversation() && !send_details() && !end_conversation()) - { - fprintf(stdout,"Finished!\n"); - result = 0; - } - } - else - { - if(verbose) fprintf(stderr,"Failed to get CPU info.\n"); - } - } - else - { - if(verbose) fprintf(stderr,"Failed to get node info.\n"); - } - } - else - { - if(verbose) fprintf(stderr,"Could not connect to libvirt.\n"); - } - } - else - { - usage(); - } - - return result; -} - -int config(int argc,char** argv) -{ - int result = 0; - int option; - - while((option = getopt(argc,argv,"s:p:u:dvth")) != -1) - { - if(debug) fprintf(stdout,"Processing argument: %c (optarg:%s)\n",option,optarg); - - switch(option) - { - case 's': hostname = optarg; break; - case 'p': hostport = atoi(optarg); break; - case 'u': snprintf(uuid,VIR_UUID_BUFLEN,"%s",optarg); break; - case 't': testing = 1; break; - case 'd': debug = 1; break; - case 'v': verbose = 1; break; - case 'h': - // fall thru - default : result = 1; break; - } - } - - // verify that required options are provided - if(hostname == NULL || strlen(hostname) == 0) - { - fprintf(stderr,"ERROR: The server name is required. (-s [hostname])\n"); - result = 1; - } - - if(hostport <= 0) - { - fprintf(stderr,"ERROR: The server port is required. (-p [port])\n"); - result = 1; - } - - return result; -} - -void usage() -{ - fprintf(stdout,"\n"); - fprintf(stdout,"Usage: ovirt-identify [OPTION]\n"); - fprintf(stdout,"\n"); - fprintf(stdout,"\t-s [server]\t\tThe remote server's hostname.\n"); - fprintf(stdout,"\t-p [port]\t\tThe remote server's port.\n"); - fprintf(stdout,"\t-d\t\tDisplays debug information during execution.\n"); - fprintf(stdout,"\t-v\t\tDisplays verbose information during execution.\n"); - fprintf(stdout,"\t-h\t\tDisplays this help information and then exits.\n"); - fprintf(stdout,"\n"); -} - -int start_conversation(void) -{ - int result = 1; - - if(verbose || debug) fprintf(stdout,"Starting conversation with %s:%d.\n",hostname,hostport); - - if(!create_connection()) - { - if(debug || verbose) fprintf(stdout,"Connected.\n"); - - if (!get_text("HELLO?")) - { - if(verbose) fprintf(stdout,"Checking for handshake.\n"); - - if(!send_text("HELLO!")) - { - if(verbose) fprintf(stdout,"Handshake received. Starting conversation.\n"); - - if(!get_text("MODE?")) - { - if(verbose) fprintf(stdout,"Shifting to IDENTIFY mode.\n"); - - if(!send_text("IDENTIFY")) result = 0; - } - else - { - if(verbose) fprintf(stderr,"Was not asked for a mode.\n"); - } - } - } - else - { - if(verbose) fprintf(stderr,"Did not receive a proper handshake.\n"); - } - } - - else - { - if(verbose) fprintf(stderr,"Did not get a connection.\n"); - } - - if(debug) fprintf(stdout,"start_conversation: result=%d\n", result); - - return result; -} - -int send_value(char* label,char* value) -{ - char buffer[BUFFER_LENGTH]; - int result = 1; - char expected[BUFFER_LENGTH]; - - snprintf(buffer,BUFFER_LENGTH,"%s=%s", label, value); - - if(!send_text(buffer)) - { - snprintf(expected, BUFFER_LENGTH, "ACK %s", label); - - if(verbose) fprintf(stdout,"Expecting \"%s\"\n", expected); - - result = get_text(expected); - } - - return result; -} - -int send_details(void) -{ - int result = 1; - - if(verbose) fprintf(stdout,"Sending node details.\n"); - - if (!get_text("INFO?")) - { - if((!send_value("ARCH", arch)) && - (!send_value("UUID", uuid)) && - (!send_value("MEMSIZE", memsize)) && - (!send_cpu_details())) - { - if(!send_text("ENDINFO")) result = 0; - } - } - else - { - if(verbose) fprintf(stdout,"Was not interrogated for hardware info.\n"); - } - - return result; -} - -int send_cpu_details(void) -{ - int result = 1; - t_cpu_info* current = cpu_info; - - while(current != NULL) - { - send_text("CPU"); - - if(!(get_text("CPUINFO?")) && - (!send_value("CPUNUM",current->cpu_num)) && - (!send_value("CORENUM",current->core_num)) && - (!send_value("NUMCORES",current->number_of_cores)) && - (!send_value("VENDOR",current->vendor)) && - (!send_value("MODEL",current->model)) && - (!send_value("FAMILY",current->family)) && - (!send_value("CPUIDLVL",current->cpuid_level)) && - (!send_value("SPEED",current->speed)) && - (!send_value("CACHE", current->cache)) && - (!send_value("FLAGS", current->flags))) - { - send_text("ENDCPU"); - result = get_text("ACK CPU"); - } - - current = current->next; - } - - - return result; -} - -int end_conversation(void) -{ - int result = 0; - - if(debug || verbose) fprintf(stdout,"Ending conversation.\n"); - - send_text("ENDINFO"); - - close(socketfd); - - return result; -} - -void get_label_and_value(char* text, - char* label, size_t label_length, - char* value, size_t value_length) -{ - int offset = 0; - int which = 0; /* 0 = label, 1 = value */ - char* current = text; - - /* iterate through the text supplied and find where the - * label ends with a colon, then copy that into the supplied - * label buffer and trim any trailing spaces - */ - - while(current != NULL && *current != '\0') - { - /* if we're on the separator, then switch modes and reset - * the offset indicator, otherwise just process the character - */ - if(which == 0 && *current == ':') - { - which = 1; - offset = 0; - } - else - { - char* buffer = (which == 0 ? label : value); - int length = (which == 0 ? label_length : value_length); - - /* only copy if we're past the first character and it's not - * a space - */ - if((offset > 0 || (*current != 9 && *current != ' ')) && offset < (length - 1)) - { - buffer[offset++] = *current; - buffer[offset] = 0; - } - } - - current++; - } - - /* now trim all trailing spaces from the values */ - while(label[strlen(label) - 1 ] == 9) - label[strlen(label) - 1] = 0; - while(value[strlen(value) - 1] == 9) - value[strlen(value) - 1] = 0; -} - -int get_cpu_info(void) -{ - int result = 1; - FILE* inputfd; - t_cpu_info* current = NULL; - - if(( inputfd = fopen("/proc/cpuinfo","rb")) != NULL) - { - if(verbose) fprintf(stdout,"Parsing CPU information\n"); - do - { - char buffer[255]; - char label[BUFFER_LENGTH]; - char value[BUFFER_LENGTH]; - - fgets(buffer, 255, inputfd); - if(strlen(buffer) > 0) buffer[strlen(buffer) - 1] = '\0'; - - get_label_and_value(buffer, - label,BUFFER_LENGTH, - value,BUFFER_LENGTH); - - if(debug) - fprintf(stdout,"label=\"%s\", value=\"%s\"\n", label, value); - - if(strlen(label)) - { - if(!strcmp(label,"processor")) - { - if(debug || verbose) - fprintf(stdout,"Starting new CPU\n"); - - t_cpu_info* last = current; - - current = create_cpu_info(); - if(last != NULL) - { - last->next = current; - } - else - { - cpu_info = current; - } - - COPY_VALUE_TO_BUFFER(value,current->cpu_num,BUFFER_LENGTH); - } - else - if(!strcmp(label,"core id")) - { - COPY_VALUE_TO_BUFFER(value,current->core_num,BUFFER_LENGTH); - } - else - if(!strcmp(label,"cpu cores")) - { - COPY_VALUE_TO_BUFFER(value,current->number_of_cores,BUFFER_LENGTH); - } - else - if(!strcmp(label,"vendor_id")) - { - COPY_VALUE_TO_BUFFER(value,current->vendor,BUFFER_LENGTH); - } - else - if(!strcmp(label,"model")) - { - COPY_VALUE_TO_BUFFER(value,current->model,BUFFER_LENGTH); - } - else - if(!strcmp(label,"cpu family")) - { - COPY_VALUE_TO_BUFFER(value,current->family,BUFFER_LENGTH); - } - else - if(!strcmp(label,"cpuid level")) - { - COPY_VALUE_TO_BUFFER(value,current->cpuid_level,BUFFER_LENGTH); - } - else - if(!strcmp(label,"cpu MHz")) - { - COPY_VALUE_TO_BUFFER(value,current->speed,BUFFER_LENGTH); - } - else - if(!strcmp(label,"cache size")) - { - COPY_VALUE_TO_BUFFER(value,current->cache,BUFFER_LENGTH); - } - else - if(!strcmp(label,"flags")) - { - COPY_VALUE_TO_BUFFER(value,current->flags,BUFFER_LENGTH); - } - } - - } while(!feof(inputfd)); - - fclose(inputfd); - - result = 0; - } - else - { - if(verbose) fprintf(stderr,"Unable to open /proc/cpuinfo\n"); - } - - return result; -} - -t_cpu_info* create_cpu_info(void) -{ - t_cpu_info* result = calloc(1,sizeof(t_cpu_info)); - bzero(result,sizeof(t_cpu_info)); - - strcpy(result->core_num,"0"); - strcpy(result->number_of_cores,"1"); - - - return result; -} - -ssize_t safewrite(int fd, const void *buf, size_t count) -{ - size_t nwritten = 0; - while (count > 0) { - ssize_t r = write(fd, buf, count); - - if (r < 0 && errno == EINTR) - continue; - if (r < 0) - return r; - if (r == 0) - return nwritten; - buf = (const char *)buf + r; - count -= r; - nwritten += r; - } - return nwritten; -} - -int send_text(char* text) -{ - int result = 1; - int sent; - - if(verbose) fprintf(stdout,"Sending: \"%s\"\n", text); - - sent = safewrite(socketfd, text, strlen(text)); - sent += safewrite(socketfd, "\n", 1); - - if(sent >= 0) - { - if(debug) fprintf(stdout,"Sent %d bytes total.\n", sent); - - result = 0; - } - - return result; -} - -int saferead(int fd, char *buf, size_t count) -{ - ssize_t bytes,offset; - int len_left; - int done = 0; - - if(debug) fprintf(stdout,"Begin saferead(%d, %p, %ld)\n", fd, buf, count); - - offset = 0; - len_left = count; - - - while(!done) - { - if(debug) fprintf(stdout,"Before read(%ld,%p,%ld)\n",fd,buf+offset,len_left); - - bytes = read(fd, buf+offset, len_left); - - if(debug) fprintf(stdout,"After read: bytes=%ld\n", bytes); - - if(bytes == 0) - { - done = 1; - } - else if(bytes > 0) - { - offset += bytes; - len_left -= bytes; - done = 1; - } - else if(errno == EINTR) - { - continue; - } - else - { - done = 1; - } - - if(debug) fprintf(stdout,"End of decision loop: offset=%ld, len_left=%dl, done=%d\n",offset, len_left, done); - } - - return offset; -} - -int get_text(const char *const expected) -{ - int result = 1; - int received; - char buffer[BUFFER_LENGTH]; - bzero(buffer,BUFFER_LENGTH); - - if(verbose) fprintf(stdout, "Looking to receive %s\n", expected); - - received = saferead(socketfd, buffer, BUFFER_LENGTH); - - buffer[received - 1] = 0; - - if(verbose) fprintf(stdout,"Received \"%s\": size=%d (trimmed ending carriage return)\n", buffer, received); - - result = strcmp(expected,buffer); - - return result; -} - -int create_connection(void) -{ - int result = 1; - struct addrinfo hints; - struct addrinfo* results; - char port[6]; - struct addrinfo* rptr; - - if(verbose) fprintf(stdout,"Creating the socket connection.\n"); - - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = 0; - hints.ai_protocol = 0; - - if(verbose) fprintf(stdout,"Searching for host candidates.\n"); - - snprintf(port, 6, "%d", hostport); - - if(!getaddrinfo(hostname, port, &hints, &results)) - { - if(verbose) fprintf(stdout,"Got address information. Searching for a proper entry.\n"); - - for(rptr = results; rptr != NULL; rptr = rptr->ai_next) - { - if(debug) - { - fprintf(stdout,"Attempting connection: family=%d, socket type=%d, protocol=%d\n", - rptr->ai_family, rptr->ai_socktype, rptr->ai_protocol); - } - - socketfd = socket(rptr->ai_family, rptr->ai_socktype, rptr->ai_protocol); - - if(socketfd == -1) - { - continue; - } - - if(connect(socketfd, rptr->ai_addr, rptr->ai_addrlen) != -1) - { - break; - } - - // invalid connection, so close it - if(verbose) fprintf(stdout, "Invalid connection.\n"); - close(socketfd); - } - - if(rptr == NULL) - { - if(verbose) fprintf(stdout,"Unable to connect to server %s:%d\n", hostname, hostport); - } - else - { - // success - result = 0; - } - - freeaddrinfo(results); - } - else - { - if(verbose) fprintf(stderr,"No hosts found. Exiting...\n"); - } - - if(debug) fprintf(stdout, "create_connection: result=%d\n", result); - - return result; -} diff --git a/ovirt-managed-node/src/ovirt-identify-node.h b/ovirt-managed-node/src/ovirt-identify-node.h index 1cb1526..fd1bc0a 100644 --- a/ovirt-managed-node/src/ovirt-identify-node.h +++ b/ovirt-managed-node/src/ovirt-identify-node.h @@ -1,6 +1,49 @@ +/* Copyright (C) 2008 Red Hat, Inc. + * Written by Darryl L. Pierce + * + * 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. + */ + #ifndef __OVIRT_IDENTIFY_NODE_H #define __OVIRT_IDENTIFY_NODE_H +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include +#include +#include + +#include + +#include +#include +#include + #define BUFFER_LENGTH 128 #define CPU_FLAGS_BUFFER_LENGTH 256 @@ -18,39 +61,71 @@ typedef struct _cpu_info { struct _cpu_info* next; } t_cpu_info; -#define COPY_VALUE_TO_BUFFER(value,buffer,length) \ - snprintf(buffer,length,"%s",value) +typedef struct _nic_info { + char mac_address[BUFFER_LENGTH]; + char bandwidth[BUFFER_LENGTH]; + char ip_address[BUFFER_LENGTH]; + struct _nic_info* next; +} t_nic_info; int config(int argc,char** argv); void usage(void); -int start_conversation(void); -int send_details(void); -int send_cpu_details(void); -int end_conversation(void); - void get_label_and_value(char* text, char* label,size_t label_length, char* value,size_t value_length); -t_cpu_info* create_cpu_info(void); -int get_cpu_info(void); int send_text(char* text); int get_text(const char *const expected); + +/* comm.c */ +ssize_t saferead(int fd, char *buf, size_t count); +ssize_t safewrite(int fd, const void *buf, size_t count); + +/* debug.c */ +void debug_cpu_info(void); + +/* gather.c */ +int init_gather(void); +int get_uuid(void); +int get_cpu_info(void); +int get_nic_info(void); + +/* hal_support.c */ +LibHalContext* get_hal_ctx(void); + +/* protocol.c */ int create_connection(void); +int start_conversation(void); +int send_details(void); +int end_conversation(void); +int send_value(char* label,char* value); +int send_text(char* text); + +/* variables */ +extern int debug; +extern int verbose; +extern int testing; + +extern char arch[BUFFER_LENGTH]; +extern char uuid[BUFFER_LENGTH]; +extern char memsize[BUFFER_LENGTH]; +extern char numcpus[BUFFER_LENGTH]; +extern char cpuspeed[BUFFER_LENGTH]; +extern char *hostname; +extern int hostport; +extern int socketfd; +extern t_cpu_info* cpu_info; +extern t_nic_info* nic_info; -int debug = 0; -int verbose = 0; -int testing = 0; - -char arch[BUFFER_LENGTH]; -char uuid[VIR_UUID_BUFLEN]; -char memsize[BUFFER_LENGTH]; -char numcpus[BUFFER_LENGTH]; -char cpuspeed[BUFFER_LENGTH]; -char *hostname; -int hostport = -1; -int socketfd; -t_cpu_info* cpu_info; +extern DBusConnection* dbus_connection; +extern DBusError dbus_error; +extern LibHalContext* hal_ctx; + +/* macros */ +#define DEBUG(arg...) if(debug) fprintf(stderr, ##arg) +#define VERBOSE(arg...) if(verbose) fprintf(stdout, ##arg) +#define COPY_VALUE_TO_BUFFER(value,buffer,length) \ + snprintf(buffer,length,"%s",value) #endif diff --git a/ovirt-managed-node/src/protocol.c b/ovirt-managed-node/src/protocol.c new file mode 100644 index 0000000..111a1c1 --- /dev/null +++ b/ovirt-managed-node/src/protocol.c @@ -0,0 +1,276 @@ +/* protocol.c -- Manages the communication between the managed node and + * the oVirt server. + * + * Copyright (C) 2008 Red Hat, Inc. + * Written by Darryl L. Pierce + * + * 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. + */ + +#include "ovirt-identify-node.h" + +int create_connection(void) +{ + int result = 1; + struct addrinfo hints; + struct addrinfo* results; + char port[6]; + struct addrinfo* rptr; + + VERBOSE("Creating the socket connection.\n"); + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = 0; + hints.ai_protocol = 0; + + VERBOSE("Searching for host candidates.\n"); + + snprintf(port, 6, "%d", hostport); + + if(!getaddrinfo(hostname, port, &hints, &results)) + { + VERBOSE("Got address information. Searching for a proper entry.\n"); + + for(rptr = results; rptr != NULL; rptr = rptr->ai_next) + { + if(debug) + { + fprintf(stdout,"Attempting connection: family=%d, socket type=%d, protocol=%d\n", + rptr->ai_family, rptr->ai_socktype, rptr->ai_protocol); + } + + socketfd = socket(rptr->ai_family, rptr->ai_socktype, rptr->ai_protocol); + + if(socketfd == -1) + { + continue; + } + + if(connect(socketfd, rptr->ai_addr, rptr->ai_addrlen) != -1) + { + break; + } + + // invalid connection, so close it + VERBOSE( "Invalid connection.\n"); + close(socketfd); + } + + if(rptr == NULL) + { + VERBOSE("Unable to connect to server %s:%d\n", hostname, hostport); + } + else + { + // success + result = 0; + } + + freeaddrinfo(results); + } + else + { + VERBOSE("No hosts found. Exiting...\n"); + } + + DEBUG( "create_connection: result=%d\n", result); + + return result; +} + +int start_conversation(void) +{ + int result = 1; + + VERBOSE("Starting conversation with %s:%d.\n",hostname,hostport); + + if(!create_connection()) + { + VERBOSE("Connected.\n"); + + if (!get_text("HELLO?")) + { + VERBOSE("Checking for handshake.\n"); + + if(!send_text("HELLO!")) + { + VERBOSE("Handshake received. Starting conversation.\n"); + + if(!get_text("MODE?")) + { + VERBOSE("Shifting to IDENTIFY mode.\n"); + + if(!send_text("IDENTIFY")) result = 0; + } + else + { + VERBOSE("Was not asked for a mode.\n"); + } + } + } + else + { + VERBOSE("Did not receive a proper handshake.\n"); + } + } + + else + { + VERBOSE("Did not get a connection.\n"); + } + + DEBUG("start_conversation: result=%d\n", result); + + return result; +} + +/* Transmits the CPU details to the server. + */ +int send_cpu_details(void) +{ + int result = 1; + t_cpu_info* current = cpu_info; + + while(current != NULL) + { + send_text("CPU"); + + if(!(get_text("CPUINFO?")) && + (!send_value("CPUNUM",current->cpu_num)) && + (!send_value("CORENUM",current->core_num)) && + (!send_value("NUMCORES",current->number_of_cores)) && + (!send_value("VENDOR",current->vendor)) && + (!send_value("MODEL",current->model)) && + (!send_value("FAMILY",current->family)) && + (!send_value("CPUIDLVL",current->cpuid_level)) && + (!send_value("SPEED",current->speed)) && + (!send_value("CACHE", current->cache)) && + (!send_value("FLAGS", current->flags))) + { + send_text("ENDCPU"); + result = get_text("ACK CPU"); + } + + current = current->next; + } + + + return result; +} + +/* Transmits the NIC details to the server. + */ +int send_nic_details(void) +{ + int result = 1; + t_nic_info* current = nic_info; + + while(current != NULL) + { + send_text("NIC"); + + if(!(get_text("NICINFO?")) && + (!send_value("MAC", current->mac_address)) && + (!send_value("BANDWIDTH",current->bandwidth))) + { + send_text("ENDNIC"); + result = get_text("ACK NIC"); + } + + current = current->next; + } + + return result; +} + +int send_details(void) +{ + int result = 1; + + VERBOSE("Sending node details.\n"); + + if (!get_text("INFO?")) + { + if((!send_value("ARCH", arch)) && + (!send_value("UUID", uuid)) && + (!send_value("MEMSIZE", memsize)) && + (!send_cpu_details() && !send_nic_details())) + { + if(!send_text("ENDINFO")) result = 0; + } + } + else + { + VERBOSE("Was not interrogated for hardware info.\n"); + } + + return result; +} + +int end_conversation(void) +{ + int result = 0; + + VERBOSE("Ending conversation.\n"); + + send_text("ENDINFO"); + + close(socketfd); + + return result; +} + +int send_value(char* label,char* value) +{ + char buffer[BUFFER_LENGTH]; + int result = 1; + char expected[BUFFER_LENGTH]; + + snprintf(buffer,BUFFER_LENGTH,"%s=%s", label, value); + + if(!send_text(buffer)) + { + snprintf(expected, BUFFER_LENGTH, "ACK %s", label); + + VERBOSE("Expecting \"%s\"\n", expected); + + result = get_text(expected); + } + + return result; +} + +int send_text(char* text) +{ + int result = 1; + int sent; + + VERBOSE("Sending: \"%s\"\n", text); + + sent = safewrite(socketfd, text, strlen(text)); + sent += safewrite(socketfd, "\n", 1); + + if(sent >= 0) + { + DEBUG("Sent %d bytes total.\n", sent); + + result = 0; + } + + return result; +} diff --git a/ovirt-managed-node/src/scripts/ovirt-post b/ovirt-managed-node/src/scripts/ovirt-post index 3bb0f6d..2624e01 100755 --- a/ovirt-managed-node/src/scripts/ovirt-post +++ b/ovirt-managed-node/src/scripts/ovirt-post @@ -14,16 +14,11 @@ start() { echo -n $"Starting ovirt-post: " find_srv identify tcp - UUID=`hal-get-property --udi \ - /org/freedesktop/Hal/devices/computer --key system.hardware.uuid` - if [ -z $UUID ]; then - ovirt-identify-node -s $SRV_HOST -p $SRV_PORT - else - ovirt-identify-node -s $SRV_HOST -p $SRV_PORT -u $UUID - fi + ovirt-identify-node -s $SRV_HOST -p $SRV_PORT success + echo } diff --git a/wui/src/host-browser/host-browser.rb b/wui/src/host-browser/host-browser.rb index 624661d..d209bdb 100755 --- a/wui/src/host-browser/host-browser.rb +++ b/wui/src/host-browser/host-browser.rb @@ -87,8 +87,8 @@ class HostBrowser break if info == "ENDINFO" - # if we got the start of a CPU details marker, then process it - if info == "CPU" + case info + when "CPU" cpu = get_cpu_info cpu_info = result['CPUINFO'] @@ -98,7 +98,16 @@ class HostBrowser end cpu_info << cpu + when "NIC" + nic = get_nic_info + nic_info = result['NICINFO'] + if(nic_info == nil) + nic_info = Array.new + result['NICINFO'] = nic_info + end + + nic_info << nic else raise Exception.new("ERRINFO! Excepted key=value : #{info}\n") unless info =~ /[\w]+[\s]*=[\w]/ @@ -144,6 +153,35 @@ class HostBrowser return result end + # Extracts NIC details from the managed node. + # + def get_nic_info + puts "Begin receiving NIC details" + + result = Hash.new + + @session.write("NICINFO?\n") + + loop do + info = @session.readline.chomp + + break if info == "ENDNIC" + + raise Exception.new("ERRINFO! Excepted key=value : #{info}\n") unless info =~ /[\w]+[\s]*=[\w]/ + + key, value = info.split("=") + + puts "#{@log_prefix} ::Received - #{key}:#{value}" unless defined?(TESTING) + result[key] = value + + @session.write("ACK #{key}\n") + end + + @session.write("ACK NIC\n"); + + return result + end + # Writes the supplied host information to the database. # def write_host_info(host_info) @@ -151,8 +189,10 @@ class HostBrowser ensure_present(host_info,'ARCH') ensure_present(host_info,'MEMSIZE') ensure_present(host_info,'CPUINFO') + ensure_present(host_info,'NICINFO') cpu_info = host_info['CPUINFO'] + nic_info = host_info['NICINFO'] cpu_info.each do |cpu| ensure_present(cpu,'CPUNUM') @@ -216,7 +256,45 @@ class HostBrowser host.cpus << detail end - host.save! + # Update the NIC details for this host: + # -if the NIC exists, then update the IP address + # -if the NIC does not exist, create it + # -any nic not in this list is deleted + + puts "Updating NIC records for the node" + nics = Array.new + + host.nics.collect do |nic| + found = false + + nic_info.collect do |detail| + # if we have a match, then update the database and remove + # the received data to avoid creating a dupe later + if detail['MAC'] == nic.mac + nic_info.delete(detail) + end + end + + # if the record wasn't found, then remove it from the database + unless found + host.nics.delete(nic) + nic.destroy + end + end + + # iterate over any nics left and create new records for them. + + nic_info.collect do |nic| + puts "Creating a new nic..." + detail = Nic.new( + 'mac' => nic['MAC'], + 'bandwidth' => nic['BANDWIDTH'], + 'usage_type' => 1) + + host.nics << detail + end + + host.save! return host end diff --git a/wui/src/host-browser/test-host-browser-identify.rb b/wui/src/host-browser/test-host-browser-identify.rb index 4197e19..7e672ce 100755 --- a/wui/src/host-browser/test-host-browser-identify.rb +++ b/wui/src/host-browser/test-host-browser-identify.rb @@ -38,7 +38,7 @@ class TestHostBrowser < Test::Unit::TestCase @host_info = {} @host_info['UUID'] = 'node1' @host_info['IPADDR'] = '192.168.2.2' - @host_info['HOSTNAME'] = 'node1.ovirt.redhat.com' + @host_info['HOSTNAME'] = 'prod.corp.com' @host_info['ARCH'] = 'x86_64' @host_info['MEMSIZE'] = '16384' @host_info['DISABLED'] = '0' @@ -75,6 +75,15 @@ class TestHostBrowser < Test::Unit::TestCase mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx \ fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs \ bts pni monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr lahf_lm' + + @host_info['NICINFO'] = Array.new + @host_info['NICINFO'][0] = {} + @host_info['NICINFO'][0]['MAC'] = '00:11:22:33:44:55' + @host_info['NICINFO'][0]['BANDWIDTH'] = '100' + + @host_info['NICINFO'][1] = {} + @host_info['NICINFO'][1]['MAC'] = '00:77:11:77:19:65' + @host_info['NICINFO'][1]['BANDWIDTH'] = '100' end # Ensures that the server is satisfied if the remote system is @@ -184,6 +193,15 @@ class TestHostBrowser < Test::Unit::TestCase assert_raise(Exception) { @browser.write_host_info(@host_info) } end + # Ensures that, if no NIC info was available, the server raises an + # exception. + # + def test_write_host_info_with_missing_nicinfo + @host_info['NICINFO'] = nil + + assert_raise(Exception) { @browser.write_host_info(@host_info) } + end + # Ensures the browser can properly parse the CPU details. # def test_parse_cpu_info @@ -206,7 +224,7 @@ class TestHostBrowser < Test::Unit::TestCase # Ensures the browser can properly parse the CPU details of two CPUs. # - def test_parse_cpu_info + def test_parse_cpu_info_with_two_entries @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } # CPU 0 @@ -242,4 +260,24 @@ class TestHostBrowser < Test::Unit::TestCase assert_not_nil info['CPUINFO'][1]['key4'] end + # Ensures the browser can properly parse the details for a NIC. + # + def test_parse_nic_info + @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "NIC\n" } + @session.should_receive(:write).with("NICINFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key1=value1\n" } + @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key2=value2\n" } + @session.should_receive(:write).with("ACK key2\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDNIC\n" } + @session.should_receive(:write).with("ACK NIC\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDINFO\n" } + + info = @browser.get_remote_info + + assert_equal 3,info.keys.size, "Should contain four keys" + assert info.include?("NICINFO") + end + end -- 1.5.5.1 From berrange at redhat.com Fri Jul 11 19:46:43 2008 From: berrange at redhat.com (Daniel P. Berrange) Date: Fri, 11 Jul 2008 20:46:43 +0100 Subject: [Ovirt-devel] [PATCH] Adding NIC details to ovirt identify stage. In-Reply-To: <1215804530-31082-1-git-send-email-dpierce@redhat.com> References: <1215804530-31082-1-git-send-email-dpierce@redhat.com> Message-ID: <20080711194643.GA11611@redhat.com> On Fri, Jul 11, 2008 at 03:28:50PM -0400, Darryl L. Pierce wrote: > This patch includes submitting to the server the MAC address and bandwidth, as > determined via HAL, for each physical NIC in the machine. > +int get_cpu_info(void) > +{ > + int result = 1; > + FILE* inputfd; > + t_cpu_info* current = NULL; > + > + if(( inputfd = fopen("/proc/cpuinfo","rb")) != NULL) This is just plain wrong if running on Xen. This is why we provide the virNodeGetInfo API in libvirt, which knows whether to ask /proc/cpuinfo, or whether to query the hypervisor for the real info > + { > + VERBOSE("Parsing CPU information\n"); > + do > + { > + char buffer[255]; > + char label[BUFFER_LENGTH]; > + char value[BUFFER_LENGTH]; > + > + fgets(buffer, 255, inputfd); > + if(strlen(buffer) > 0) buffer[strlen(buffer) - 1] = '\0'; > + > + get_label_and_value(buffer, > + label,BUFFER_LENGTH, > + value,BUFFER_LENGTH); > + > + DEBUG("label=\"%s\", value=\"%s\"\n", label, value); > + > + if(strlen(label)) > + { > + if(!strcmp(label,"processor")) > + { > + VERBOSE("Starting new CPU\n"); > + > + t_cpu_info* last = current; > + > + current = create_cpu_info(); > + if(last != NULL) > + { > + last->next = current; > + } > + else > + { > + cpu_info = current; > + } > + > + COPY_VALUE_TO_BUFFER(value,current->cpu_num,BUFFER_LENGTH); > + } > + else > + if(!strcmp(label,"core id")) > + { > + COPY_VALUE_TO_BUFFER(value,current->core_num,BUFFER_LENGTH); > + } This data is useless/wrong on Xen. > + else > + if(!strcmp(label,"cpu cores")) > + { > + COPY_VALUE_TO_BUFFER(value,current->number_of_cores,BUFFER_LENGTH); > + } This data is useless/wrong on Xen. > + else > + if(!strcmp(label,"vendor_id")) > + { > + COPY_VALUE_TO_BUFFER(value,current->vendor,BUFFER_LENGTH); > + } > + else > + if(!strcmp(label,"model")) > + { > + COPY_VALUE_TO_BUFFER(value,current->model,BUFFER_LENGTH); > + } > + else > + if(!strcmp(label,"cpu family")) > + { > + COPY_VALUE_TO_BUFFER(value,current->family,BUFFER_LENGTH); > + } > + else > + if(!strcmp(label,"cpuid level")) > + { > + COPY_VALUE_TO_BUFFER(value,current->cpuid_level,BUFFER_LENGTH); > + } > + else > + if(!strcmp(label,"cpu MHz")) > + { > + COPY_VALUE_TO_BUFFER(value,current->speed,BUFFER_LENGTH); > + } > + else This data is useless/wrong if CPU frequency scaling is active - it is active by default > + if(!strcmp(label,"cache size")) > + { > + COPY_VALUE_TO_BUFFER(value,current->cache,BUFFER_LENGTH); > + } > + else > + if(!strcmp(label,"flags")) > + { > + COPY_VALUE_TO_BUFFER(value,current->flags,BUFFER_LENGTH); > + } 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 pmyers at redhat.com Fri Jul 11 20:36:10 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Fri, 11 Jul 2008 16:36:10 -0400 Subject: [Ovirt-devel] [PATCH] Adding NIC details to ovirt identify stage. In-Reply-To: <20080711194643.GA11611@redhat.com> References: <1215804530-31082-1-git-send-email-dpierce@redhat.com> <20080711194643.GA11611@redhat.com> Message-ID: <4877C43A.4050500@redhat.com> Daniel P. Berrange wrote: > On Fri, Jul 11, 2008 at 03:28:50PM -0400, Darryl L. Pierce wrote: >> This patch includes submitting to the server the MAC address and bandwidth, as >> determined via HAL, for each physical NIC in the machine. > > >> +int get_cpu_info(void) >> +{ >> + int result = 1; >> + FILE* inputfd; >> + t_cpu_info* current = NULL; >> + >> + if(( inputfd = fopen("/proc/cpuinfo","rb")) != NULL) > > This is just plain wrong if running on Xen. This is why we provide > the virNodeGetInfo API in libvirt, which knows whether to ask > /proc/cpuinfo, or whether to query the hypervisor for the real info Agreed. While we're targeting this code for the Managed Node which is KVM only, this will eventually need to run on Xen hosts as well. So we should use virNodeGetInfo... Does virNodeGetInfo provide the same level of details as /proc/cpuinfo in terms of listing things like cpuflags? Perry From berrange at redhat.com Fri Jul 11 21:22:32 2008 From: berrange at redhat.com (Daniel P. Berrange) Date: Fri, 11 Jul 2008 22:22:32 +0100 Subject: [Ovirt-devel] [PATCH] Adding NIC details to ovirt identify stage. In-Reply-To: <4877C43A.4050500@redhat.com> References: <1215804530-31082-1-git-send-email-dpierce@redhat.com> <20080711194643.GA11611@redhat.com> <4877C43A.4050500@redhat.com> Message-ID: <20080711212232.GA24167@redhat.com> On Fri, Jul 11, 2008 at 04:36:10PM -0400, Perry N. Myers wrote: > Daniel P. Berrange wrote: > >On Fri, Jul 11, 2008 at 03:28:50PM -0400, Darryl L. Pierce wrote: > >>This patch includes submitting to the server the MAC address and > >>bandwidth, as > >>determined via HAL, for each physical NIC in the machine. > > > > > >>+int get_cpu_info(void) > >>+{ > >>+ int result = 1; > >>+ FILE* inputfd; > >>+ t_cpu_info* current = NULL; > >>+ > >>+ if(( inputfd = fopen("/proc/cpuinfo","rb")) != NULL) > > > >This is just plain wrong if running on Xen. This is why we provide > >the virNodeGetInfo API in libvirt, which knows whether to ask > >/proc/cpuinfo, or whether to query the hypervisor for the real info > > Agreed. While we're targeting this code for the Managed Node which is KVM > only, this will eventually need to run on Xen hosts as well. So we should > use virNodeGetInfo... > > Does virNodeGetInfo provide the same level of details as /proc/cpuinfo in > terms of listing things like cpuflags? No, it only currently exposes VMX, SVM and PAE flags. Why exactly does oVirt need the full set ? They're a forever changing set across processor vendors and models and architectures which makes them fairly useless as a whole. Specific applications typically only care about specific flags hence we only exposed the ones clearly virt related so far 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 acathrow at redhat.com Fri Jul 11 21:31:39 2008 From: acathrow at redhat.com (Andrew Cathrow) Date: Fri, 11 Jul 2008 17:31:39 -0400 Subject: [Ovirt-devel] [PATCH] Adding NIC details to ovirt identify stage. In-Reply-To: <20080711212232.GA24167@redhat.com> References: <1215804530-31082-1-git-send-email-dpierce@redhat.com> <20080711194643.GA11611@redhat.com> <4877C43A.4050500@redhat.com> <20080711212232.GA24167@redhat.com> Message-ID: <1215811899.5258.1.camel@aic-macbook-rhel5.cathrow.org> On Fri, 2008-07-11 at 22:22 +0100, Daniel P. Berrange wrote: > No, it only currently exposes VMX, SVM and PAE flags. Why exactly does > oVirt need the full set ? They're a forever changing set across processor > vendors and models and architectures which makes them fairly useless as > a whole. Specific applications typically only care about specific flags > hence we only exposed the ones clearly virt related so far > > Daniel Other flags would be useful for verifying migration support. If we pulled back the full set of flags then we'd have a baseline of information to use in working out which hosts a guest can be migrated to. For example if a guest is running on a host that has SSE2 then we wouldn't want to live migrate that to a host that didn't have this feature as it would probably choke. Obviously the logic behind working out what would and wouldn't work is horrific, but if we pull back this data at least we have a foundation to work on if we decided to go down that path. VMware has done some work on this - for example allowing the NX bit to be masked, and have added some more cpu bitmasking features in 3.5, but I've not looked too closely into them. Aic -------------- next part -------------- An HTML attachment was scrubbed... URL: From berrange at redhat.com Sat Jul 12 10:13:34 2008 From: berrange at redhat.com (Daniel P. Berrange) Date: Sat, 12 Jul 2008 11:13:34 +0100 Subject: [Ovirt-devel] [PATCH] Adding NIC details to ovirt identify stage. In-Reply-To: <1215811899.5258.1.camel@aic-macbook-rhel5.cathrow.org> References: <1215804530-31082-1-git-send-email-dpierce@redhat.com> <20080711194643.GA11611@redhat.com> <4877C43A.4050500@redhat.com> <20080711212232.GA24167@redhat.com> <1215811899.5258.1.camel@aic-macbook-rhel5.cathrow.org> Message-ID: <20080712101334.GA16121@redhat.com> On Fri, Jul 11, 2008 at 05:31:39PM -0400, Andrew Cathrow wrote: > > On Fri, 2008-07-11 at 22:22 +0100, Daniel P. Berrange wrote: > > > > No, it only currently exposes VMX, SVM and PAE flags. Why exactly does > > oVirt need the full set ? They're a forever changing set across processor > > vendors and models and architectures which makes them fairly useless as > > a whole. Specific applications typically only care about specific flags > > hence we only exposed the ones clearly virt related so far > > Other flags would be useful for verifying migration support. If we > pulled back the full set of flags then we'd have a baseline of > information to use in working out which hosts a guest can be migrated > to. This doesn't require the full set of flags - if you compare the full set every time you want to migrate you will be overly restricting your migration pool. > For example if a guest is running on a host that has SSE2 then we > wouldn't want to live migrate that to a host that didn't have this > feature as it would probably choke. SSE is just a handful of the available flags. > Obviously the logic behind working out what would and wouldn't work is > horrific, but if we pull back this data at least we have a foundation to > work on if we decided to go down that path. I'm inclined to think we want to put as much of this CPU compatability logic as possible into a libvirt API, or capabilities XML. Any app using libvirt's migration API will ned todo this check so we should provide a centralized piece of logic for it. We don't want every app to have to repeat the logic of figuring out compatible CPUs. > VMware has done some work on this - for example allowing the NX bit to > be masked, and have added some more cpu bitmasking features in 3.5, but > I've not looked too closely into them. Yep, Xen and KVM have both talked of CPU feature masking but not really gone anywhere with it so far because its such a troublesome problem to manage 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 acathrow at redhat.com Sat Jul 12 14:12:40 2008 From: acathrow at redhat.com (Andrew Cathrow) Date: Sat, 12 Jul 2008 10:12:40 -0400 Subject: [Ovirt-devel] [PATCH] Adding NIC details to ovirt identify stage. In-Reply-To: <20080712101334.GA16121@redhat.com> References: <1215804530-31082-1-git-send-email-dpierce@redhat.com> <20080711194643.GA11611@redhat.com> <4877C43A.4050500@redhat.com> <20080711212232.GA24167@redhat.com> <1215811899.5258.1.camel@aic-macbook-rhel5.cathrow.org> <20080712101334.GA16121@redhat.com> Message-ID: <1215871960.3906.7.camel@aic-thinkpad-f9.cathrow.org> On Sat, 2008-07-12 at 11:13 +0100, Daniel P. Berrange wrote: > > This doesn't require the full set of flags - if you compare the full > set every time you want to migrate you will be overly restricting > your migration pool. Agree - just making the point that it's probably better to collect it just in case. But it sounds like you're saying that rather expose all the data to the end user you'd abstract that within libvirt. > > I'm inclined to think we want to put as much of this CPU compatability > logic as possible into a libvirt API, or capabilities XML. Any app > using libvirt's migration API will ned todo this check so we should > provide a centralized piece of logic for it. We don't want every app > to have to repeat the logic of figuring out compatible CPUs. Absolutely - that's where it belongs. So then a management tool could query the information and use it to better plan the architecture of clusters grouping "compatible" machines together. > > > VMware has done some work on this - for example allowing the NX bit to > > be masked, and have added some more cpu bitmasking features in 3.5, but > > I've not looked too closely into them. > > Yep, Xen and KVM have both talked of CPU feature masking but not really > gone anywhere with it so far because its such a troublesome problem to > manage Yeah it really belongs in the silicon, Intel FlexMigration sounds interesting for that reason, but all I know is what their marketing folks tell me :-) > > Daniel -------------- next part -------------- An HTML attachment was scrubbed... URL: From clalance at redhat.com Mon Jul 14 14:47:41 2008 From: clalance at redhat.com (Chris Lalancette) Date: Mon, 14 Jul 2008 16:47:41 +0200 Subject: [Ovirt-devel] [PATCH] Switch / on Managed Node to be ext2. Saves about 1MB on the compressed image In-Reply-To: <1215791349-7245-1-git-send-email-pmyers@redhat.com> References: <1215791349-7245-1-git-send-email-pmyers@redhat.com> Message-ID: <487B670D.8070808@redhat.com> Perry Myers wrote: > Signed-off-by: Perry Myers > --- > ovirt-host-creator/common-install.ks | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > diff --git a/ovirt-host-creator/common-install.ks b/ovirt-host-creator/common-install.ks > index ced731e..badc847 100644 > --- a/ovirt-host-creator/common-install.ks > +++ b/ovirt-host-creator/common-install.ks > @@ -4,7 +4,7 @@ timezone --utc UTC > auth --useshadow --enablemd5 > selinux --disabled > firewall --disabled > -part / --size 550 > +part / --size 550 --fstype ext2 Yeah, this is fine. Doesn't save all that much, but won't hurt anything either, so... ACK Chris Lalancette From dpierce at redhat.com Mon Jul 14 15:31:32 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 14 Jul 2008 11:31:32 -0400 Subject: [Ovirt-devel] Re: [PATCH] Redirecting all logs to /var/log/ovirt.log In-Reply-To: <1215642821-6503-1-git-send-email-dpierce@redhat.com> References: <1215642821-6503-1-git-send-email-dpierce@redhat.com> Message-ID: <487B7154.3060501@redhat.com> Can I get some feedback or an ACK on this patch, please? Darryl L. Pierce wrote: > From: Darryl Pierce > > > Signed-off-by: Darryl L. Pierce > --- > ovirt-managed-node/src/scripts/ovirt | 21 ++++++++++++--------- > ovirt-managed-node/src/scripts/ovirt-awake | 2 +- > ovirt-managed-node/src/scripts/ovirt-early | 20 +++++++++++--------- > ovirt-managed-node/src/scripts/ovirt-functions | 5 ++++- > ovirt-managed-node/src/scripts/ovirt-post | 18 ++++++++++-------- > 5 files changed, 38 insertions(+), 28 deletions(-) > > diff --git a/ovirt-managed-node/src/scripts/ovirt b/ovirt-managed-node/src/scripts/ovirt > index 92a0e40..644675b 100755 > --- a/ovirt-managed-node/src/scripts/ovirt > +++ b/ovirt-managed-node/src/scripts/ovirt > @@ -18,7 +18,8 @@ start() { > if [ ! -s $krb5_conf ]; then > rm -f $krb5_conf > # FIXME this is IPA specific > - wget -q http://$SRV_HOST:$SRV_PORT/ipa/config/krb5.ini -O $krb5_conf \ > + wget -q \ > + http://$SRV_HOST:$SRV_PORT/ipa/config/krb5.ini -O $krb5_conf \ > || die "Failed to get $krb5_conf" > fi > IPA_HOST=$SRV_HOST > @@ -41,11 +42,13 @@ start() { > echo > } > > -case "$1" in > - start) > - start > - ;; > - *) > - echo "Usage: ovirt {start}" > - exit 2 > -esac > +{ > + case "$1" in > + start) > + start > + ;; > + *) > + echo "Usage: ovirt {start}" > + exit 2 > + esac > +} >> $OVIRT_LOGFILE > diff --git a/ovirt-managed-node/src/scripts/ovirt-awake b/ovirt-managed-node/src/scripts/ovirt-awake > index 4e43d45..38d405e 100755 > --- a/ovirt-managed-node/src/scripts/ovirt-awake > +++ b/ovirt-managed-node/src/scripts/ovirt-awake > @@ -66,7 +66,7 @@ start () { > if [ -n $KEYTAB ]; then > echo "Retrieving keytab: '$KEYTAB'" > > - wget $KEYTAB --output-document=$KEYTAB_FILE > + wget -q $KEYTAB --output-document=$KEYTAB_FILE > else > echo "No keytab to retrieve" > fi > diff --git a/ovirt-managed-node/src/scripts/ovirt-early b/ovirt-managed-node/src/scripts/ovirt-early > index 4116847..975ba9d 100755 > --- a/ovirt-managed-node/src/scripts/ovirt-early > +++ b/ovirt-managed-node/src/scripts/ovirt-early > @@ -27,7 +27,7 @@ configure_from_network() { > find_srv ovirt tcp > printf . > if [ -n "$SRV_HOST" -a -n "$SRV_PORT" ]; then > - wget --quiet -O - "http://$SRV_HOST:$SRV_PORT/ovirt/cfgdb/$(hostname)" \ > + wget -q -O - "http://$SRV_HOST:$SRV_PORT/ovirt/cfgdb/$(hostname)" \ > | augtool > /dev/null 2>&1 > if [ $? -eq 0 ]; then > printf "remote config applied." > @@ -94,11 +94,13 @@ start() { > done > } > > -case "$1" in > - start) > - start > - ;; > - *) > - echo "Usage: ovirt-early {start}" > - exit 2 > -esac > +{ > + case "$1" in > + start) > + start > + ;; > + *) > + echo "Usage: ovirt-early {start}" > + exit 2 > + esac > +} >> $OVIRT_LOGFILE > diff --git a/ovirt-managed-node/src/scripts/ovirt-functions b/ovirt-managed-node/src/scripts/ovirt-functions > index 9974533..5b530f7 100644 > --- a/ovirt-managed-node/src/scripts/ovirt-functions > +++ b/ovirt-managed-node/src/scripts/ovirt-functions > @@ -1,6 +1,9 @@ > # -*-Shell-script-*- > > -find_srv() { > +OVIRT_LOGFILE=/var/log/ovirt.log > + > +find_srv() > +{ > local dnsreply > dnsreply=$(dig +short -t srv _$1._$2.$(dnsdomainname)) > if [ $? -eq 0 ]; then > diff --git a/ovirt-managed-node/src/scripts/ovirt-post b/ovirt-managed-node/src/scripts/ovirt-post > index 3bb0f6d..fbdc1f6 100755 > --- a/ovirt-managed-node/src/scripts/ovirt-post > +++ b/ovirt-managed-node/src/scripts/ovirt-post > @@ -27,11 +27,13 @@ start() { > echo > } > > -case "$1" in > - start) > - start > - ;; > - *) > - echo "Usage: ovirt-post {start}" > - exit 2 > -esac > +{ > + case "$1" in > + start) > + start > + ;; > + *) > + echo "Usage: ovirt-post {start}" > + exit 2 > + esac > +} >> $OVIRT_LOGFILE -- Darryl L. Pierce, Sr. Software Engineer Red Hat, Inc. - http://www.redhat.com/ oVirt - Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" From pmyers at redhat.com Mon Jul 14 15:40:23 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Mon, 14 Jul 2008 11:40:23 -0400 Subject: [Ovirt-devel] Re: [PATCH] Redirecting all logs to /var/log/ovirt.log In-Reply-To: <487B7154.3060501@redhat.com> References: <1215642821-6503-1-git-send-email-dpierce@redhat.com> <487B7154.3060501@redhat.com> Message-ID: <487B7367.6080108@redhat.com> Darryl L. Pierce wrote: > Can I get some feedback or an ACK on this patch, please? Sorry for the delay... Two comments about this... The redirects just do stdout. Probably want >> $OVIRT_LOGFILE 2>&1 to get stderr as well. And this brings up a cosmetic question... By putting the redirects where you have them, we don't get the pretty [ OK ] things popping up on boot. Should be able to do that by redirecting output from things like echo -n "Starting ovirt: " and success to another fd that eventually goes to stdout. Perry > Darryl L. Pierce wrote: >> From: Darryl Pierce >> >> >> Signed-off-by: Darryl L. Pierce >> --- >> ovirt-managed-node/src/scripts/ovirt | 21 >> ++++++++++++--------- >> ovirt-managed-node/src/scripts/ovirt-awake | 2 +- >> ovirt-managed-node/src/scripts/ovirt-early | 20 >> +++++++++++--------- >> ovirt-managed-node/src/scripts/ovirt-functions | 5 ++++- >> ovirt-managed-node/src/scripts/ovirt-post | 18 ++++++++++-------- >> 5 files changed, 38 insertions(+), 28 deletions(-) >> >> diff --git a/ovirt-managed-node/src/scripts/ovirt >> b/ovirt-managed-node/src/scripts/ovirt >> index 92a0e40..644675b 100755 >> --- a/ovirt-managed-node/src/scripts/ovirt >> +++ b/ovirt-managed-node/src/scripts/ovirt >> @@ -18,7 +18,8 @@ start() { >> if [ ! -s $krb5_conf ]; then >> rm -f $krb5_conf >> # FIXME this is IPA specific >> - wget -q http://$SRV_HOST:$SRV_PORT/ipa/config/krb5.ini -O >> $krb5_conf \ >> + wget -q \ >> + http://$SRV_HOST:$SRV_PORT/ipa/config/krb5.ini -O >> $krb5_conf \ >> || die "Failed to get $krb5_conf" >> fi >> IPA_HOST=$SRV_HOST >> @@ -41,11 +42,13 @@ start() { >> echo >> } >> >> -case "$1" in >> - start) >> - start >> - ;; >> - *) >> - echo "Usage: ovirt {start}" >> - exit 2 >> -esac >> +{ >> + case "$1" in >> + start) >> + start >> + ;; >> + *) >> + echo "Usage: ovirt {start}" >> + exit 2 >> + esac >> +} >> $OVIRT_LOGFILE >> diff --git a/ovirt-managed-node/src/scripts/ovirt-awake >> b/ovirt-managed-node/src/scripts/ovirt-awake >> index 4e43d45..38d405e 100755 >> --- a/ovirt-managed-node/src/scripts/ovirt-awake >> +++ b/ovirt-managed-node/src/scripts/ovirt-awake >> @@ -66,7 +66,7 @@ start () { >> if [ -n $KEYTAB ]; then >> echo "Retrieving keytab: '$KEYTAB'" >> >> - wget $KEYTAB --output-document=$KEYTAB_FILE >> + wget -q $KEYTAB --output-document=$KEYTAB_FILE >> else >> echo "No keytab to retrieve" >> fi >> diff --git a/ovirt-managed-node/src/scripts/ovirt-early >> b/ovirt-managed-node/src/scripts/ovirt-early >> index 4116847..975ba9d 100755 >> --- a/ovirt-managed-node/src/scripts/ovirt-early >> +++ b/ovirt-managed-node/src/scripts/ovirt-early >> @@ -27,7 +27,7 @@ configure_from_network() { >> find_srv ovirt tcp >> printf . >> if [ -n "$SRV_HOST" -a -n "$SRV_PORT" ]; then >> - wget --quiet -O - >> "http://$SRV_HOST:$SRV_PORT/ovirt/cfgdb/$(hostname)" \ >> + wget -q -O - >> "http://$SRV_HOST:$SRV_PORT/ovirt/cfgdb/$(hostname)" \ >> | augtool > /dev/null 2>&1 >> if [ $? -eq 0 ]; then >> printf "remote config applied." >> @@ -94,11 +94,13 @@ start() { >> done >> } >> >> -case "$1" in >> - start) >> - start >> - ;; >> - *) >> - echo "Usage: ovirt-early {start}" >> - exit 2 >> -esac >> +{ >> + case "$1" in >> + start) >> + start >> + ;; >> + *) >> + echo "Usage: ovirt-early {start}" >> + exit 2 >> + esac >> +} >> $OVIRT_LOGFILE >> diff --git a/ovirt-managed-node/src/scripts/ovirt-functions >> b/ovirt-managed-node/src/scripts/ovirt-functions >> index 9974533..5b530f7 100644 >> --- a/ovirt-managed-node/src/scripts/ovirt-functions >> +++ b/ovirt-managed-node/src/scripts/ovirt-functions >> @@ -1,6 +1,9 @@ >> # -*-Shell-script-*- >> >> -find_srv() { >> +OVIRT_LOGFILE=/var/log/ovirt.log >> + >> +find_srv() >> +{ >> local dnsreply >> dnsreply=$(dig +short -t srv _$1._$2.$(dnsdomainname)) >> if [ $? -eq 0 ]; then >> diff --git a/ovirt-managed-node/src/scripts/ovirt-post >> b/ovirt-managed-node/src/scripts/ovirt-post >> index 3bb0f6d..fbdc1f6 100755 >> --- a/ovirt-managed-node/src/scripts/ovirt-post >> +++ b/ovirt-managed-node/src/scripts/ovirt-post >> @@ -27,11 +27,13 @@ start() { >> echo >> } >> >> -case "$1" in >> - start) >> - start >> - ;; >> - *) >> - echo "Usage: ovirt-post {start}" >> - exit 2 >> -esac >> +{ >> + case "$1" in >> + start) >> + start >> + ;; >> + *) >> + echo "Usage: ovirt-post {start}" >> + exit 2 >> + esac >> +} >> $OVIRT_LOGFILE > > -- |=- 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 Jul 14 16:53:36 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 14 Jul 2008 12:53:36 -0400 Subject: [Ovirt-devel] [PATCH] Redirecting all logs to /var/log/ovirt.log Message-ID: <1216054416-12022-1-git-send-email-dpierce@redhat.com> From: Darryl Pierce Signed-off-by: Darryl L. Pierce --- ovirt-managed-node/src/scripts/ovirt | 17 ++++++++++------- ovirt-managed-node/src/scripts/ovirt-awake | 2 +- ovirt-managed-node/src/scripts/ovirt-early | 11 +++++++++-- ovirt-managed-node/src/scripts/ovirt-functions | 5 ++++- ovirt-managed-node/src/scripts/ovirt-post | 14 ++++++++------ 5 files changed, 32 insertions(+), 17 deletions(-) diff --git a/ovirt-managed-node/src/scripts/ovirt b/ovirt-managed-node/src/scripts/ovirt index 92a0e40..5487e87 100755 --- a/ovirt-managed-node/src/scripts/ovirt +++ b/ovirt-managed-node/src/scripts/ovirt @@ -11,14 +11,13 @@ . /etc/init.d/ovirt-functions start() { - echo -n $"Starting ovirt: " - find_srv ipa tcp krb5_conf=/etc/krb5.conf if [ ! -s $krb5_conf ]; then rm -f $krb5_conf # FIXME this is IPA specific - wget -q http://$SRV_HOST:$SRV_PORT/ipa/config/krb5.ini -O $krb5_conf \ + wget -q \ + http://$SRV_HOST:$SRV_PORT/ipa/config/krb5.ini -O $krb5_conf \ || die "Failed to get $krb5_conf" fi IPA_HOST=$SRV_HOST @@ -36,14 +35,18 @@ start() { > $collectd_conf \ || die "Failed to write $collectd_conf" fi - - success - echo } case "$1" in start) - start + echo -n $"Starting ovirt: " + + { + start + } >> $OVIRT_LOGFILE 2>&1 + + success + echo ;; *) echo "Usage: ovirt {start}" diff --git a/ovirt-managed-node/src/scripts/ovirt-awake b/ovirt-managed-node/src/scripts/ovirt-awake index 4e43d45..38d405e 100755 --- a/ovirt-managed-node/src/scripts/ovirt-awake +++ b/ovirt-managed-node/src/scripts/ovirt-awake @@ -66,7 +66,7 @@ start () { if [ -n $KEYTAB ]; then echo "Retrieving keytab: '$KEYTAB'" - wget $KEYTAB --output-document=$KEYTAB_FILE + wget -q $KEYTAB --output-document=$KEYTAB_FILE else echo "No keytab to retrieve" fi diff --git a/ovirt-managed-node/src/scripts/ovirt-early b/ovirt-managed-node/src/scripts/ovirt-early index 4116847..26f3623 100755 --- a/ovirt-managed-node/src/scripts/ovirt-early +++ b/ovirt-managed-node/src/scripts/ovirt-early @@ -27,7 +27,7 @@ configure_from_network() { find_srv ovirt tcp printf . if [ -n "$SRV_HOST" -a -n "$SRV_PORT" ]; then - wget --quiet -O - "http://$SRV_HOST:$SRV_PORT/ovirt/cfgdb/$(hostname)" \ + wget -q -O - "http://$SRV_HOST:$SRV_PORT/ovirt/cfgdb/$(hostname)" \ | augtool > /dev/null 2>&1 if [ $? -eq 0 ]; then printf "remote config applied." @@ -96,7 +96,14 @@ start() { case "$1" in start) - start + echo -n $"Starting ovirt-early: " + + { + start + } >> $OVIRT_LOGFILE 2>&1 + + success + echo ;; *) echo "Usage: ovirt-early {start}" diff --git a/ovirt-managed-node/src/scripts/ovirt-functions b/ovirt-managed-node/src/scripts/ovirt-functions index 9974533..5b530f7 100644 --- a/ovirt-managed-node/src/scripts/ovirt-functions +++ b/ovirt-managed-node/src/scripts/ovirt-functions @@ -1,6 +1,9 @@ # -*-Shell-script-*- -find_srv() { +OVIRT_LOGFILE=/var/log/ovirt.log + +find_srv() +{ local dnsreply dnsreply=$(dig +short -t srv _$1._$2.$(dnsdomainname)) if [ $? -eq 0 ]; then diff --git a/ovirt-managed-node/src/scripts/ovirt-post b/ovirt-managed-node/src/scripts/ovirt-post index 3bb0f6d..98a994d 100755 --- a/ovirt-managed-node/src/scripts/ovirt-post +++ b/ovirt-managed-node/src/scripts/ovirt-post @@ -11,8 +11,6 @@ . /etc/init.d/ovirt-functions start() { - echo -n $"Starting ovirt-post: " - find_srv identify tcp UUID=`hal-get-property --udi \ /org/freedesktop/Hal/devices/computer --key system.hardware.uuid` @@ -22,14 +20,18 @@ start() { else ovirt-identify-node -s $SRV_HOST -p $SRV_PORT -u $UUID fi - - success - echo } case "$1" in start) - start + echo -n $"Starting ovirt-post: " + + { + start + } >> $OVIRT_LOGFILE 2>&1 + + success + echo ;; *) echo "Usage: ovirt-post {start}" -- 1.5.5.1 From jguiditt at redhat.com Mon Jul 14 16:53:39 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Mon, 14 Jul 2008 12:53:39 -0400 Subject: [Ovirt-devel] [PATCH] Fix a small typo in the graphing stuff that was causing backtraces in the In-Reply-To: <1215702355-25433-1-git-send-email-clalance@redhat.com> References: <1215702355-25433-1-git-send-email-clalance@redhat.com> Message-ID: <1216054419.3715.0.camel@localhost.localdomain> ACK, thanks for tracking that down. It was annoying me in the logs, just hadn't gotten around to finding it yet. -j On Thu, 2008-07-10 at 11:05 -0400, Chris Lalancette wrote: > Signed-off-by: Chris Lalancette > --- > wui/src/app/controllers/graph_controller.rb | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > diff --git a/wui/src/app/controllers/graph_controller.rb b/wui/src/app/controllers/graph_controller.rb > index 6c57ba1..dbe2afc 100644 > --- a/wui/src/app/controllers/graph_controller.rb > +++ b/wui/src/app/controllers/graph_controller.rb > @@ -457,7 +457,7 @@ class GraphController < ApplicationController > end > end > > - def _generated_default_time_axis(myDays) > + def _generate_default_time_axis(myDays) > times = [] > now = Time.now > if myDays.to_i == 1 From dpierce at redhat.com Mon Jul 14 16:54:21 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 14 Jul 2008 12:54:21 -0400 Subject: [Ovirt-devel] Re: [PATCH] Redirecting all logs to /var/log/ovirt.log In-Reply-To: <1216054416-12022-1-git-send-email-dpierce@redhat.com> References: <1216054416-12022-1-git-send-email-dpierce@redhat.com> Message-ID: <487B84BD.60409@redhat.com> Darryl L. Pierce wrote: > From: Darryl Pierce This update addresses points brought up by Perry. -- Darryl L. Pierce, Sr. Software Engineer Red Hat, Inc. - http://www.redhat.com/ oVirt - Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" From jguiditt at redhat.com Mon Jul 14 16:54:38 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Mon, 14 Jul 2008 12:54:38 -0400 Subject: [Ovirt-devel] [PATCH] Removed a duplicate KVM_HYPERVISOR and HYPERVISOR_TYPE lines that was causing In-Reply-To: <1215700642-24679-1-git-send-email-clalance@redhat.com> References: <1215700642-24679-1-git-send-email-clalance@redhat.com> Message-ID: <1216054478.3715.2.camel@localhost.localdomain> ACK, excellent, you seem to have fixed most of the little errors that were bugging me :) -j On Thu, 2008-07-10 at 10:37 -0400, Chris Lalancette wrote: > Signed-off-by: Chris Lalancette > --- > wui/src/app/models/host.rb | 3 --- > 1 files changed, 0 insertions(+), 3 deletions(-) > > diff --git a/wui/src/app/models/host.rb b/wui/src/app/models/host.rb > index e5f6264..80acaeb 100644 > --- a/wui/src/app/models/host.rb > +++ b/wui/src/app/models/host.rb > @@ -46,9 +46,6 @@ class Host < ActiveRecord::Base > STATE_AVAILABLE = "available" > STATES = [STATE_UNAVAILABLE, STATE_AVAILABLE] > > - KVM_HYPERVISOR_TYPE = "KVM" > - HYPERVISOR_TYPES = [KVM_HYPERVISOR_TYPE] > - > def memory_in_mb > kb_to_mb(memory) > end From pmyers at redhat.com Mon Jul 14 17:10:27 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Mon, 14 Jul 2008 13:10:27 -0400 Subject: [Ovirt-devel] [PATCH] Redirecting all logs to /var/log/ovirt.log In-Reply-To: <1216054416-12022-1-git-send-email-dpierce@redhat.com> References: <1216054416-12022-1-git-send-email-dpierce@redhat.com> Message-ID: <487B8883.30002@redhat.com> Darryl L. Pierce wrote: > From: Darryl Pierce > > > Signed-off-by: Darryl L. Pierce > --- > ovirt-managed-node/src/scripts/ovirt | 17 ++++++++++------- > ovirt-managed-node/src/scripts/ovirt-awake | 2 +- > ovirt-managed-node/src/scripts/ovirt-early | 11 +++++++++-- > ovirt-managed-node/src/scripts/ovirt-functions | 5 ++++- > ovirt-managed-node/src/scripts/ovirt-post | 14 ++++++++------ > 5 files changed, 32 insertions(+), 17 deletions(-) > > diff --git a/ovirt-managed-node/src/scripts/ovirt b/ovirt-managed-node/src/scripts/ovirt > index 92a0e40..5487e87 100755 > --- a/ovirt-managed-node/src/scripts/ovirt > +++ b/ovirt-managed-node/src/scripts/ovirt > @@ -11,14 +11,13 @@ > . /etc/init.d/ovirt-functions > > start() { > - echo -n $"Starting ovirt: " > - > find_srv ipa tcp > krb5_conf=/etc/krb5.conf > if [ ! -s $krb5_conf ]; then > rm -f $krb5_conf > # FIXME this is IPA specific > - wget -q http://$SRV_HOST:$SRV_PORT/ipa/config/krb5.ini -O $krb5_conf \ > + wget -q \ > + http://$SRV_HOST:$SRV_PORT/ipa/config/krb5.ini -O $krb5_conf \ > || die "Failed to get $krb5_conf" > fi > IPA_HOST=$SRV_HOST > @@ -36,14 +35,18 @@ start() { > > $collectd_conf \ > || die "Failed to write $collectd_conf" > fi > - > - success > - echo > } > > case "$1" in > start) > - start > + echo -n $"Starting ovirt: " > + > + { > + start > + } >> $OVIRT_LOGFILE 2>&1 > + > + success > + echo > ;; > *) > echo "Usage: ovirt {start}" > diff --git a/ovirt-managed-node/src/scripts/ovirt-awake b/ovirt-managed-node/src/scripts/ovirt-awake > index 4e43d45..38d405e 100755 > --- a/ovirt-managed-node/src/scripts/ovirt-awake > +++ b/ovirt-managed-node/src/scripts/ovirt-awake > @@ -66,7 +66,7 @@ start () { > if [ -n $KEYTAB ]; then > echo "Retrieving keytab: '$KEYTAB'" > > - wget $KEYTAB --output-document=$KEYTAB_FILE > + wget -q $KEYTAB --output-document=$KEYTAB_FILE > else > echo "No keytab to retrieve" > fi > diff --git a/ovirt-managed-node/src/scripts/ovirt-early b/ovirt-managed-node/src/scripts/ovirt-early > index 4116847..26f3623 100755 > --- a/ovirt-managed-node/src/scripts/ovirt-early > +++ b/ovirt-managed-node/src/scripts/ovirt-early > @@ -27,7 +27,7 @@ configure_from_network() { > find_srv ovirt tcp > printf . > if [ -n "$SRV_HOST" -a -n "$SRV_PORT" ]; then > - wget --quiet -O - "http://$SRV_HOST:$SRV_PORT/ovirt/cfgdb/$(hostname)" \ > + wget -q -O - "http://$SRV_HOST:$SRV_PORT/ovirt/cfgdb/$(hostname)" \ > | augtool > /dev/null 2>&1 > if [ $? -eq 0 ]; then > printf "remote config applied." > @@ -96,7 +96,14 @@ start() { > > case "$1" in > start) > - start > + echo -n $"Starting ovirt-early: " > + > + { > + start > + } >> $OVIRT_LOGFILE 2>&1 > + > + success > + echo > ;; > *) > echo "Usage: ovirt-early {start}" > diff --git a/ovirt-managed-node/src/scripts/ovirt-functions b/ovirt-managed-node/src/scripts/ovirt-functions > index 9974533..5b530f7 100644 > --- a/ovirt-managed-node/src/scripts/ovirt-functions > +++ b/ovirt-managed-node/src/scripts/ovirt-functions > @@ -1,6 +1,9 @@ > # -*-Shell-script-*- > > -find_srv() { > +OVIRT_LOGFILE=/var/log/ovirt.log > + > +find_srv() > +{ > local dnsreply > dnsreply=$(dig +short -t srv _$1._$2.$(dnsdomainname)) > if [ $? -eq 0 ]; then > diff --git a/ovirt-managed-node/src/scripts/ovirt-post b/ovirt-managed-node/src/scripts/ovirt-post > index 3bb0f6d..98a994d 100755 > --- a/ovirt-managed-node/src/scripts/ovirt-post > +++ b/ovirt-managed-node/src/scripts/ovirt-post > @@ -11,8 +11,6 @@ > . /etc/init.d/ovirt-functions > > start() { > - echo -n $"Starting ovirt-post: " > - > find_srv identify tcp > UUID=`hal-get-property --udi \ > /org/freedesktop/Hal/devices/computer --key system.hardware.uuid` > @@ -22,14 +20,18 @@ start() { > else > ovirt-identify-node -s $SRV_HOST -p $SRV_PORT -u $UUID > fi > - > - success > - echo > } > > case "$1" in > start) > - start > + echo -n $"Starting ovirt-post: " > + > + { > + start > + } >> $OVIRT_LOGFILE 2>&1 > + > + success > + echo > ;; > *) > echo "Usage: ovirt-post {start}" This might be in the realm of nitpicking, but... I think it might be better to have things structured like this: do_ovirt_post() { .... } >> $OVIRT_LOGFILE 2>&1 start() { echo -n $"Starting ovirt-post: " do_ovirt_post; ret=$? echo test $ret == 0 && success || failure } case "$1" in start) start ;; *) echo "Usage: ovirt-post {start}" exit 2 esac And make sure do_ovirt_post returns a non-zero error code if there is an error. In the ovirt init script this will require factoring out the calls to die, since die does an exit 1. Open to suggestions from other people on this, however... Perry From dpierce at redhat.com Mon Jul 14 18:51:35 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 14 Jul 2008 14:51:35 -0400 Subject: [Ovirt-devel] [PATCH] Redirecting all logs to /var/log/ovirt.log In-Reply-To: <487B8883.30002@redhat.com> References: <1216054416-12022-1-git-send-email-dpierce@redhat.com> <487B8883.30002@redhat.com> Message-ID: <487BA037.6090602@redhat.com> Perry N. Myers wrote: > This might be in the realm of nitpicking, but... I think it might be > better to have things structured like this: > > do_ovirt_post() { > .... > } >> $OVIRT_LOGFILE 2>&1 > > start() { > echo -n $"Starting ovirt-post: " > do_ovirt_post; ret=$? > echo > test $ret == 0 && success || failure > } Given how short our scripts are, I don't see a benefit to inserting a method in between the entry point and the functionality. However,I do like the failure notice as opposed to just exiting the script. So I've pulled that into the script and replaced all calls to die "message" with: function start () { wget -q -o "some url" || echo "message" && return 1 } I'll have a patch out shortly once I run through tests. -- Darryl L. Pierce, Sr. Software Engineer Red Hat, Inc. - http://www.redhat.com/ oVirt - Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" From clalance at redhat.com Mon Jul 14 18:57:38 2008 From: clalance at redhat.com (Chris Lalancette) Date: Mon, 14 Jul 2008 20:57:38 +0200 Subject: [Ovirt-devel] [PATCH] Redirecting all logs to /var/log/ovirt.log In-Reply-To: <487BA037.6090602@redhat.com> References: <1216054416-12022-1-git-send-email-dpierce@redhat.com> <487B8883.30002@redhat.com> <487BA037.6090602@redhat.com> Message-ID: <487BA1A2.5070005@redhat.com> Darryl L. Pierce wrote: > Given how short our scripts are, I don't see a benefit to inserting a > method in between the entry point and the functionality. However,I do > like the failure notice as opposed to just exiting the script. So I've > pulled that into the script and replaced all calls to die "message" with: > > function start () { > wget -q -o "some url" || echo "message" && return 1 > } > > I'll have a patch out shortly once I run through tests. I think what Perry is trying to get at is that it would be nice to both display an [ OK ] or [ FAIL ] message at the console (like all of the other init scripts do), but to also put more verbose output into a logging directory for debugging. That way, if you see you have a [ FAIL ], you at least have an opportunity to debug it. The other advantage is that you don't have redirects littered throughout the code for each individual line, and new code (if and when we need it) automatically get logged to the appropriate place. Oh, one other nit-pick from me; I would name the log something like /var/log/ovirt-init.log, to make entirely clear it is the output from the init scripts. Chris Lalancette From dpierce at redhat.com Mon Jul 14 19:08:31 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 14 Jul 2008 15:08:31 -0400 Subject: [Ovirt-devel] [PATCH] Redirecting all logs to /var/log/ovirt.log In-Reply-To: <487BA1A2.5070005@redhat.com> References: <1216054416-12022-1-git-send-email-dpierce@redhat.com> <487B8883.30002@redhat.com> <487BA037.6090602@redhat.com> <487BA1A2.5070005@redhat.com> Message-ID: <487BA42F.3000908@redhat.com> Chris Lalancette wrote: > Darryl L. Pierce wrote: >> Given how short our scripts are, I don't see a benefit to inserting a >> method in between the entry point and the functionality. However,I do >> like the failure notice as opposed to just exiting the script. So I've >> pulled that into the script and replaced all calls to die "message" with: >> >> function start () { >> wget -q -o "some url" || echo "message" && return 1 >> } >> >> I'll have a patch out shortly once I run through tests. > > I think what Perry is trying to get at is that it would be nice to both display > an [ OK ] or [ FAIL ] message at the console (like all of the other init scripts > do), but to also put more verbose output into a logging directory for debugging. Sorry, guess I wasn't clear: I did get the above and that's in there. The basic structure is: function start () { ... do_something_useful || echo "I failed" && return 1 ... } case "$1" in start) echo -n $"Starting ovirt-early: " { start } >> $OVIRT_LOGFILE 2>&1 test $? == 0 && success || failure ;; esac With the above structure, any function where we previously called "die" it instead echoes and returns 1. This avoids the script existing at the point of failure and passes control to the test line after the call to start. And that test will print either [OK] or [FAILED] depending on whether the function exited cleanly or returned a 1. > Oh, one other nit-pick from me; I would name the log something like > /var/log/ovirt-init.log, to make entirely clear it is the output from the init > scripts. I can see it either way. One thing we can do, if there's a concern, is inject a "Starting early/setup/post phase" line rather than having multiple logs as a delimiter. -- Darryl L. Pierce, Sr. Software Engineer Red Hat, Inc. - http://www.redhat.com/ oVirt - Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" From dpierce at redhat.com Mon Jul 14 19:16:31 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 14 Jul 2008 15:16:31 -0400 Subject: [Ovirt-devel] [PATCH] Redirecting all logs to /var/log/ovirt.log Message-ID: <1216062991-19462-1-git-send-email-dpierce@redhat.com> From: Darryl Pierce This incorporates feedback and ensures that any function call that fails shows the [FAILED] output in the console, while still ensuring data is captured to the /var/log/ovirt.log file. Signed-off-by: Darryl L. Pierce --- ovirt-managed-node/src/scripts/ovirt | 21 ++++++++++++--------- ovirt-managed-node/src/scripts/ovirt-awake | 2 +- ovirt-managed-node/src/scripts/ovirt-early | 11 +++++++++-- ovirt-managed-node/src/scripts/ovirt-functions | 5 ++++- ovirt-managed-node/src/scripts/ovirt-post | 14 ++++++++------ 5 files changed, 34 insertions(+), 19 deletions(-) diff --git a/ovirt-managed-node/src/scripts/ovirt b/ovirt-managed-node/src/scripts/ovirt index 92a0e40..7a5ba80 100755 --- a/ovirt-managed-node/src/scripts/ovirt +++ b/ovirt-managed-node/src/scripts/ovirt @@ -11,15 +11,14 @@ . /etc/init.d/ovirt-functions start() { - echo -n $"Starting ovirt: " - find_srv ipa tcp krb5_conf=/etc/krb5.conf if [ ! -s $krb5_conf ]; then rm -f $krb5_conf # FIXME this is IPA specific - wget -q http://$SRV_HOST:$SRV_PORT/ipa/config/krb5.ini -O $krb5_conf \ - || die "Failed to get $krb5_conf" + wget -q \ + http://$SRV_HOST:$SRV_PORT/ipa/config/krb5.ini -O $krb5_conf \ + || echo "Failed to get $krb5_conf" && return 1 fi IPA_HOST=$SRV_HOST IPA_PORT=$SRV_PORT @@ -34,16 +33,20 @@ start() { sed -e "s/@COLLECTD_SERVER@/$SRV_HOST/" \ -e "s/@COLLECTD_PORT@/$SRV_PORT/" $collectd_conf.in \ > $collectd_conf \ - || die "Failed to write $collectd_conf" + || echo "Failed to write $collectd_conf" && return 1 fi - - success - echo } case "$1" in start) - start + echo -n $"Starting ovirt: " + + { + start + } >> $OVIRT_LOGFILE 2>&1 + + test $? == 0 && success || failure + echo ;; *) echo "Usage: ovirt {start}" diff --git a/ovirt-managed-node/src/scripts/ovirt-awake b/ovirt-managed-node/src/scripts/ovirt-awake index 4e43d45..38d405e 100755 --- a/ovirt-managed-node/src/scripts/ovirt-awake +++ b/ovirt-managed-node/src/scripts/ovirt-awake @@ -66,7 +66,7 @@ start () { if [ -n $KEYTAB ]; then echo "Retrieving keytab: '$KEYTAB'" - wget $KEYTAB --output-document=$KEYTAB_FILE + wget -q $KEYTAB --output-document=$KEYTAB_FILE else echo "No keytab to retrieve" fi diff --git a/ovirt-managed-node/src/scripts/ovirt-early b/ovirt-managed-node/src/scripts/ovirt-early index 4116847..6c7aaa3 100755 --- a/ovirt-managed-node/src/scripts/ovirt-early +++ b/ovirt-managed-node/src/scripts/ovirt-early @@ -27,7 +27,7 @@ configure_from_network() { find_srv ovirt tcp printf . if [ -n "$SRV_HOST" -a -n "$SRV_PORT" ]; then - wget --quiet -O - "http://$SRV_HOST:$SRV_PORT/ovirt/cfgdb/$(hostname)" \ + wget -q -O - "http://$SRV_HOST:$SRV_PORT/ovirt/cfgdb/$(hostname)" \ | augtool > /dev/null 2>&1 if [ $? -eq 0 ]; then printf "remote config applied." @@ -96,7 +96,14 @@ start() { case "$1" in start) - start + echo -n $"Starting ovirt-early: " + + { + start + } >> $OVIRT_LOGFILE 2>&1 + + test $? == 0 && success || failure + echo ;; *) echo "Usage: ovirt-early {start}" diff --git a/ovirt-managed-node/src/scripts/ovirt-functions b/ovirt-managed-node/src/scripts/ovirt-functions index 9974533..5b530f7 100644 --- a/ovirt-managed-node/src/scripts/ovirt-functions +++ b/ovirt-managed-node/src/scripts/ovirt-functions @@ -1,6 +1,9 @@ # -*-Shell-script-*- -find_srv() { +OVIRT_LOGFILE=/var/log/ovirt.log + +find_srv() +{ local dnsreply dnsreply=$(dig +short -t srv _$1._$2.$(dnsdomainname)) if [ $? -eq 0 ]; then diff --git a/ovirt-managed-node/src/scripts/ovirt-post b/ovirt-managed-node/src/scripts/ovirt-post index 3bb0f6d..f113b28 100755 --- a/ovirt-managed-node/src/scripts/ovirt-post +++ b/ovirt-managed-node/src/scripts/ovirt-post @@ -11,8 +11,6 @@ . /etc/init.d/ovirt-functions start() { - echo -n $"Starting ovirt-post: " - find_srv identify tcp UUID=`hal-get-property --udi \ /org/freedesktop/Hal/devices/computer --key system.hardware.uuid` @@ -22,14 +20,18 @@ start() { else ovirt-identify-node -s $SRV_HOST -p $SRV_PORT -u $UUID fi - - success - echo } case "$1" in start) - start + echo -n $"Starting ovirt-post: " + + { + start + } >> $OVIRT_LOGFILE 2>&1 + + test $? -eq 0 && success || failure + echo ;; *) echo "Usage: ovirt-post {start}" -- 1.5.5.1 From jeffschroed at gmail.com Mon Jul 14 19:17:27 2008 From: jeffschroed at gmail.com (Jeff Schroeder) Date: Mon, 14 Jul 2008 12:17:27 -0700 Subject: [Ovirt-devel] [PATCH] Redirecting all logs to /var/log/ovirt.log In-Reply-To: <487BA1A2.5070005@redhat.com> References: <1216054416-12022-1-git-send-email-dpierce@redhat.com> <487B8883.30002@redhat.com> <487BA037.6090602@redhat.com> <487BA1A2.5070005@redhat.com> Message-ID: On Mon, Jul 14, 2008 at 11:57 AM, Chris Lalancette wrote: > Darryl L. Pierce wrote: >> Given how short our scripts are, I don't see a benefit to inserting a >> method in between the entry point and the functionality. However,I do >> like the failure notice as opposed to just exiting the script. So I've >> pulled that into the script and replaced all calls to die "message" with: >> >> function start () { >> wget -q -o "some url" || echo "message" && return 1 >> } >> >> I'll have a patch out shortly once I run through tests. > > I think what Perry is trying to get at is that it would be nice to both display > an [ OK ] or [ FAIL ] message at the console (like all of the other init scripts > do), but to also put more verbose output into a logging directory for debugging. > That way, if you see you have a [ FAIL ], you at least have an opportunity to > debug it. The other advantage is that you don't have redirects littered > throughout the code for each individual line, and new code (if and when we need > it) automatically get logged to the appropriate place. > > Oh, one other nit-pick from me; I would name the log something like > /var/log/ovirt-init.log, to make entirely clear it is the output from the init > scripts. My take it it should actually use syslog(3) which by default sends it to /var/log/messages. Instead of using output redirection, can you use logger(1)? Even if you insist on a seperate logfile, it will do these things for you with "-f". When you've built out a sizable syslog infrastructure accross your datacenters, it is nice when important applications such as ovirt actually use it. For shell scripts, something like: logger -t ovirt-init -p daemon.$level "message"; exit $RETVAL ... logger -t ovirt-init -p daemon.warn "Ovirt starting" logger -t ovirt-init -p daemon.error "Can not start daemon for some reason" # Not tested, just typed into gmail's web interface. function log() { level=$1 shift message="$*" logger -t ovirt-init -p daemon.$level "$message" } ... Called via something like: log warn "This is a warning from ovirt-init" If you wanted to be really fancy, put a case statement towards the bottom of the log function that would exit on crit, emerg, panic, and error levels. What do you think of that? -- Jeff Schroeder Don't drink and derive, alcohol and analysis don't mix. http://www.digitalprognosis.com From pmyers at redhat.com Mon Jul 14 19:24:46 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Mon, 14 Jul 2008 15:24:46 -0400 Subject: [Ovirt-devel] [PATCH] Redirecting all logs to /var/log/ovirt.log In-Reply-To: References: <1216054416-12022-1-git-send-email-dpierce@redhat.com> <487B8883.30002@redhat.com> <487BA037.6090602@redhat.com> <487BA1A2.5070005@redhat.com> Message-ID: <487BA7FE.7030204@redhat.com> Jeff Schroeder wrote: > On Mon, Jul 14, 2008 at 11:57 AM, Chris Lalancette wrote: >> Darryl L. Pierce wrote: >>> Given how short our scripts are, I don't see a benefit to inserting a >>> method in between the entry point and the functionality. However,I do >>> like the failure notice as opposed to just exiting the script. So I've >>> pulled that into the script and replaced all calls to die "message" with: >>> >>> function start () { >>> wget -q -o "some url" || echo "message" && return 1 >>> } >>> >>> I'll have a patch out shortly once I run through tests. >> I think what Perry is trying to get at is that it would be nice to both display >> an [ OK ] or [ FAIL ] message at the console (like all of the other init scripts >> do), but to also put more verbose output into a logging directory for debugging. >> That way, if you see you have a [ FAIL ], you at least have an opportunity to >> debug it. The other advantage is that you don't have redirects littered >> throughout the code for each individual line, and new code (if and when we need >> it) automatically get logged to the appropriate place. >> >> Oh, one other nit-pick from me; I would name the log something like >> /var/log/ovirt-init.log, to make entirely clear it is the output from the init >> scripts. > My take it it should actually use syslog(3) which by default sends it > to /var/log/messages. > Instead of using output redirection, can you use logger(1)? Even if > you insist on a seperate > logfile, it will do these things for you with "-f". > > When you've built out a sizable syslog infrastructure accross your datacenters, > it is nice when important applications such as ovirt actually use it. > > For shell scripts, something like: > logger -t ovirt-init -p daemon.$level "message"; exit $RETVAL > ... > logger -t ovirt-init -p daemon.warn "Ovirt starting" > logger -t ovirt-init -p daemon.error "Can not start daemon for some reason" > > # Not tested, just typed into gmail's web interface. > function log() { > level=$1 > shift > message="$*" > logger -t ovirt-init -p daemon.$level "$message" > } > ... > > Called via something like: > log warn "This is a warning from ovirt-init" > > If you wanted to be really fancy, put a case statement towards the bottom > of the log function that would exit on crit, emerg, panic, and error levels. > > What do you think of that? > I like the idea of using logger for info/error/warning messages, but the primary purpose of the /var/log/ovirt.log file is really for ease in debugging... i.e. we want to be able to capture the output (fairly verbose) of ovirt-identify-node and other programs that are running. Not sure if that kind of verbose output belongs in /var/log/messages. Might make sense to do what Darryl's patch is doing for use in debugging, but still use a few calls to logger in the init scripts so that important messages get logged that way. 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 jeffschroed at gmail.com Mon Jul 14 19:26:37 2008 From: jeffschroed at gmail.com (Jeff Schroeder) Date: Mon, 14 Jul 2008 12:26:37 -0700 Subject: [Ovirt-devel] [PATCH] Redirecting all logs to /var/log/ovirt.log In-Reply-To: <487BA7FE.7030204@redhat.com> References: <1216054416-12022-1-git-send-email-dpierce@redhat.com> <487B8883.30002@redhat.com> <487BA037.6090602@redhat.com> <487BA1A2.5070005@redhat.com> <487BA7FE.7030204@redhat.com> Message-ID: On Mon, Jul 14, 2008 at 12:24 PM, Perry N. Myers wrote: > Jeff Schroeder wrote: >> >> On Mon, Jul 14, 2008 at 11:57 AM, Chris Lalancette >> wrote: >>> >>> Darryl L. Pierce wrote: >>>> >>>> Given how short our scripts are, I don't see a benefit to inserting a >>>> method in between the entry point and the functionality. However,I do >>>> like the failure notice as opposed to just exiting the script. So I've >>>> pulled that into the script and replaced all calls to die "message" >>>> with: >>>> >>>> function start () { >>>> wget -q -o "some url" || echo "message" && return 1 >>>> } >>>> >>>> I'll have a patch out shortly once I run through tests. >>> >>> I think what Perry is trying to get at is that it would be nice to both >>> display >>> an [ OK ] or [ FAIL ] message at the console (like all of the other init >>> scripts >>> do), but to also put more verbose output into a logging directory for >>> debugging. >>> That way, if you see you have a [ FAIL ], you at least have an >>> opportunity to >>> debug it. The other advantage is that you don't have redirects littered >>> throughout the code for each individual line, and new code (if and when >>> we need >>> it) automatically get logged to the appropriate place. >>> >>> Oh, one other nit-pick from me; I would name the log something like >>> /var/log/ovirt-init.log, to make entirely clear it is the output from the >>> init >>> scripts. >> >> My take it it should actually use syslog(3) which by default sends it >> to /var/log/messages. >> Instead of using output redirection, can you use logger(1)? Even if >> you insist on a seperate >> logfile, it will do these things for you with "-f". >> >> When you've built out a sizable syslog infrastructure accross your >> datacenters, >> it is nice when important applications such as ovirt actually use it. >> >> For shell scripts, something like: >> logger -t ovirt-init -p daemon.$level "message"; exit $RETVAL >> ... >> logger -t ovirt-init -p daemon.warn "Ovirt starting" >> logger -t ovirt-init -p daemon.error "Can not start daemon for some >> reason" >> >> # Not tested, just typed into gmail's web interface. >> function log() { >> level=$1 >> shift >> message="$*" >> logger -t ovirt-init -p daemon.$level "$message" >> } >> ... >> >> Called via something like: >> log warn "This is a warning from ovirt-init" >> >> If you wanted to be really fancy, put a case statement towards the bottom >> of the log function that would exit on crit, emerg, panic, and error >> levels. >> >> What do you think of that? >> > > I like the idea of using logger for info/error/warning messages, but the > primary purpose of the /var/log/ovirt.log file is really for ease in > debugging... i.e. we want to be able to capture the output (fairly verbose) > of ovirt-identify-node and other programs that are running. Not sure if > that kind of verbose output belongs in /var/log/messages. > > Might make sense to do what Darryl's patch is doing for use in debugging, > but still use a few calls to logger in the init scripts so that important > messages get logged that way. Agreed > Perry -- Jeff Schroeder Don't drink and derive, alcohol and analysis don't mix. http://www.digitalprognosis.com From pmyers at redhat.com Mon Jul 14 19:29:35 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Mon, 14 Jul 2008 15:29:35 -0400 Subject: [Ovirt-devel] [PATCH] Redirecting all logs to /var/log/ovirt.log In-Reply-To: <1216062991-19462-1-git-send-email-dpierce@redhat.com> References: <1216062991-19462-1-git-send-email-dpierce@redhat.com> Message-ID: <487BA91F.5000006@redhat.com> Darryl L. Pierce wrote: > From: Darryl Pierce > > This incorporates feedback and ensures that any function call that fails > shows the [FAILED] output in the console, while still ensuring data is > captured to the /var/log/ovirt.log file. > > > Signed-off-by: Darryl L. Pierce > --- > ovirt-managed-node/src/scripts/ovirt | 21 ++++++++++++--------- > ovirt-managed-node/src/scripts/ovirt-awake | 2 +- > ovirt-managed-node/src/scripts/ovirt-early | 11 +++++++++-- > ovirt-managed-node/src/scripts/ovirt-functions | 5 ++++- > ovirt-managed-node/src/scripts/ovirt-post | 14 ++++++++------ > 5 files changed, 34 insertions(+), 19 deletions(-) > > diff --git a/ovirt-managed-node/src/scripts/ovirt b/ovirt-managed-node/src/scripts/ovirt > index 92a0e40..7a5ba80 100755 > --- a/ovirt-managed-node/src/scripts/ovirt > +++ b/ovirt-managed-node/src/scripts/ovirt > @@ -11,15 +11,14 @@ > . /etc/init.d/ovirt-functions > > start() { > - echo -n $"Starting ovirt: " > - > find_srv ipa tcp > krb5_conf=/etc/krb5.conf > if [ ! -s $krb5_conf ]; then > rm -f $krb5_conf > # FIXME this is IPA specific > - wget -q http://$SRV_HOST:$SRV_PORT/ipa/config/krb5.ini -O $krb5_conf \ > - || die "Failed to get $krb5_conf" > + wget -q \ > + http://$SRV_HOST:$SRV_PORT/ipa/config/krb5.ini -O $krb5_conf \ > + || echo "Failed to get $krb5_conf" && return 1 > fi > IPA_HOST=$SRV_HOST > IPA_PORT=$SRV_PORT > @@ -34,16 +33,20 @@ start() { > sed -e "s/@COLLECTD_SERVER@/$SRV_HOST/" \ > -e "s/@COLLECTD_PORT@/$SRV_PORT/" $collectd_conf.in \ > > $collectd_conf \ > - || die "Failed to write $collectd_conf" > + || echo "Failed to write $collectd_conf" && return 1 > fi > - > - success > - echo > } > > case "$1" in > start) > - start > + echo -n $"Starting ovirt: " > + > + { > + start > + } >> $OVIRT_LOGFILE 2>&1 > + > + test $? == 0 && success || failure > + echo > ;; > *) > echo "Usage: ovirt {start}" > diff --git a/ovirt-managed-node/src/scripts/ovirt-awake b/ovirt-managed-node/src/scripts/ovirt-awake > index 4e43d45..38d405e 100755 > --- a/ovirt-managed-node/src/scripts/ovirt-awake > +++ b/ovirt-managed-node/src/scripts/ovirt-awake > @@ -66,7 +66,7 @@ start () { > if [ -n $KEYTAB ]; then > echo "Retrieving keytab: '$KEYTAB'" > > - wget $KEYTAB --output-document=$KEYTAB_FILE > + wget -q $KEYTAB --output-document=$KEYTAB_FILE > else > echo "No keytab to retrieve" > fi > diff --git a/ovirt-managed-node/src/scripts/ovirt-early b/ovirt-managed-node/src/scripts/ovirt-early > index 4116847..6c7aaa3 100755 > --- a/ovirt-managed-node/src/scripts/ovirt-early > +++ b/ovirt-managed-node/src/scripts/ovirt-early > @@ -27,7 +27,7 @@ configure_from_network() { > find_srv ovirt tcp > printf . > if [ -n "$SRV_HOST" -a -n "$SRV_PORT" ]; then > - wget --quiet -O - "http://$SRV_HOST:$SRV_PORT/ovirt/cfgdb/$(hostname)" \ > + wget -q -O - "http://$SRV_HOST:$SRV_PORT/ovirt/cfgdb/$(hostname)" \ > | augtool > /dev/null 2>&1 > if [ $? -eq 0 ]; then > printf "remote config applied." > @@ -96,7 +96,14 @@ start() { > > case "$1" in > start) > - start > + echo -n $"Starting ovirt-early: " > + > + { > + start > + } >> $OVIRT_LOGFILE 2>&1 > + > + test $? == 0 && success || failure > + echo > ;; > *) > echo "Usage: ovirt-early {start}" > diff --git a/ovirt-managed-node/src/scripts/ovirt-functions b/ovirt-managed-node/src/scripts/ovirt-functions > index 9974533..5b530f7 100644 > --- a/ovirt-managed-node/src/scripts/ovirt-functions > +++ b/ovirt-managed-node/src/scripts/ovirt-functions > @@ -1,6 +1,9 @@ > # -*-Shell-script-*- > > -find_srv() { > +OVIRT_LOGFILE=/var/log/ovirt.log > + > +find_srv() > +{ > local dnsreply > dnsreply=$(dig +short -t srv _$1._$2.$(dnsdomainname)) > if [ $? -eq 0 ]; then > diff --git a/ovirt-managed-node/src/scripts/ovirt-post b/ovirt-managed-node/src/scripts/ovirt-post > index 3bb0f6d..f113b28 100755 > --- a/ovirt-managed-node/src/scripts/ovirt-post > +++ b/ovirt-managed-node/src/scripts/ovirt-post > @@ -11,8 +11,6 @@ > . /etc/init.d/ovirt-functions > > start() { > - echo -n $"Starting ovirt-post: " > - > find_srv identify tcp > UUID=`hal-get-property --udi \ > /org/freedesktop/Hal/devices/computer --key system.hardware.uuid` > @@ -22,14 +20,18 @@ start() { > else > ovirt-identify-node -s $SRV_HOST -p $SRV_PORT -u $UUID > fi > - > - success > - echo > } > > case "$1" in > start) > - start > + echo -n $"Starting ovirt-post: " > + > + { > + start > + } >> $OVIRT_LOGFILE 2>&1 > + > + test $? -eq 0 && success || failure > + echo > ;; > *) > echo "Usage: ovirt-post {start}" ACK, this looks ok as long as it's been tested :) As Jeff notes in another message, we should also add some logger commands to log important things to syslog (so that we can eventually get those over to an rsyslog server). But this patch is good as is, we can add in logger stuff in another patch later. 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 Mon Jul 14 20:40:28 2008 From: imain at redhat.com (Ian Main) Date: Mon, 14 Jul 2008 13:40:28 -0700 Subject: [Ovirt-devel] Managed Node qpid Modeling In-Reply-To: <20080709215544.0599ea7a@tp.mains.net> References: <20080709215544.0599ea7a@tp.mains.net> Message-ID: <20080714134028.7cabfb71@tp.mains.net> OK, similar idea. I spent a bunch of time looking at the libvirt API and decided that I would keep the properties and object relations in place rather than going to all libvirt style calls. I like the idea of modeling the system and having any state changes pushed up rather than having to poll. I did change the main creation functions to mirror the libvirt calls using XML descriptions. Very good call there. I also switched the create/destroy etc. to use libvirt equivalents. New version is attached. Sorry it took a while. I probably should deal with the >80 width lines at some point too.. Ian -------------- next part -------------- A non-text attachment was scrubbed... Name: managed-node-model.xml Type: application/xml Size: 6887 bytes Desc: not available URL: From berrange at redhat.com Tue Jul 15 09:33:01 2008 From: berrange at redhat.com (Daniel P. Berrange) Date: Tue, 15 Jul 2008 10:33:01 +0100 Subject: [Ovirt-devel] Managed Node qpid Modeling In-Reply-To: <20080714134028.7cabfb71@tp.mains.net> References: <20080709215544.0599ea7a@tp.mains.net> <20080714134028.7cabfb71@tp.mains.net> Message-ID: <20080715093301.GA25562@redhat.com> On Mon, Jul 14, 2008 at 01:40:28PM -0700, Ian Main wrote: > OK, similar idea. I spent a bunch of time looking at the > libvirt API and decided that I would keep the properties > and object relations in place rather than going to all > libvirt style calls. I like the idea of modeling the > system and having any state changes pushed up rather > than having to poll. You're not getting rid of polling, you're just pushing it elsewhere. To fill in the property fields & keep them updated you're going to have to poll on the managed node fetching the XML document all the time. This is absolutely something you do not want todo. Fetching the XML is a heavyweight operation on some hypervisor. eg if you have Xen and fetch the XML doc for 20 VMs, once a second you'll have 100% cpu usage on the managed node just from polling. The only methods that can be efficiently polled are those for getting the live domain resource info - ie virDomainGetInfo(), and those for listing active/inactive domains. > I did change the main creation functions to mirror the > libvirt calls using XML descriptions. Very good call > there. I also switched the create/destroy etc. to use > libvirt equivalents. I maintain that this modelling should match the libvirt API and object model 100%, so that it can be a general purpose libvirt API-over-QPid rather than a oVirt specific modelling as it is now. Having a general libvirt moel provides for interoperability with other applications needing to access libvirt over QPid, and will allow us to implement QPid support directly into the libvirt client for those who do not need to talk directly to QPid for asynchronous comms. Reducing the amount of oVirt specific code is also important for long term code maintainence overhead. > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > The only properties that should be on the wire should be uuid, name and ID. Nothing else can be implemented efficiently. General configuration information should be returned via a invocation of the virDomainGetXMLDesc() method mapping. Live memory usage can be obtained via the XML doc, or via a mapping to the virDomainGetInfo() method. > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > This is missing alot of arguments compared to the libvirt API parameters. > > > > > > > > > > Again the only properties should be the UUID and Name. Everything else should be in the XML document. > > > > > > > > > > > > > > A storage volume has 3 identifying properties, a Key and Path and a Name. There is no UUID - the 'key' property provides an equivalent role, but not in the strict 16 hex digit format. Everything else should be in the XML dump. There is no concept of a LUN for anything other than iSCSI/SCSI. There are two different sizes that are needed - 'allocation' and 'capacity'. This is all dealt with in the XML format correctly. > > Not in the libvirt storage model, it isn't. > > > > > > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel -- |: 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 sseago at redhat.com Tue Jul 15 15:28:40 2008 From: sseago at redhat.com (Scott Seago) Date: Tue, 15 Jul 2008 11:28:40 -0400 Subject: [Ovirt-devel] [PATCH] added VM-level migration support to the WUI. Still no back end bits here, though. Message-ID: <1216135720-15149-1-git-send-email-sseago@redhat.com> Signed-off-by: Scott Seago --- wui/src/app/controllers/hardware_controller.rb | 18 ++++-- wui/src/app/controllers/host_controller.rb | 11 +++ wui/src/app/controllers/resources_controller.rb | 25 ------- wui/src/app/controllers/vm_controller.rb | 13 +++- wui/src/app/models/vm.rb | 31 ++++++--- wui/src/app/models/vm_task.rb | 70 +++++++++++++++----- wui/src/app/views/hardware/show_hosts.rhtml | 5 +- wui/src/app/views/hardware/show_storage.rhtml | 2 +- wui/src/app/views/host/_grid.rhtml | 15 +++-- wui/src/app/views/host/addhost.html.erb | 5 +- wui/src/app/views/host/quick_summary.rhtml | 1 + wui/src/app/views/storage/_grid.rhtml | 4 +- wui/src/app/views/storage/add.rhtml | 2 +- wui/src/app/views/vm/migrate.rhtml | 81 +++++++++++++++++++++++ wui/src/app/views/vm/show.rhtml | 15 +++- wui/src/public/javascripts/flexigrid.js | 4 +- wui/src/public/javascripts/ovirt.js | 2 +- 17 files changed, 230 insertions(+), 74 deletions(-) create mode 100644 wui/src/app/views/host/quick_summary.rhtml create mode 100644 wui/src/app/views/vm/migrate.rhtml diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb index 4175fd8..926b6c8 100644 --- a/wui/src/app/controllers/hardware_controller.rb +++ b/wui/src/app/controllers/hardware_controller.rb @@ -112,7 +112,12 @@ class HardwareController < ApplicationController end def hosts_json - if params[:id] + if params[:exclude_host] + pre_json + hosts = @pool.hosts + find_opts = {:conditions => ["id != ?", params[:exclude_host]]} + include_pool = false + elsif params[:id] pre_json hosts = @pool.hosts find_opts = {} @@ -120,14 +125,17 @@ class HardwareController < ApplicationController else # FIXME: no permissions or usage checks here yet # filtering on which pool to exclude - id = params[:exclude_id] + id = params[:exclude_pool] hosts = Host find_opts = {:include => :hardware_pool, :conditions => ["pools.id != ?", id]} include_pool = true end - attr_list = [:id, :hostname, :uuid, :hypervisor_type, :num_cpus, :cpu_speed, :arch, :memory_in_mb, :status_str, :id] - attr_list.insert(2, [:hardware_pool, :name]) if include_pool + attr_list = [] + attr_list << :id if params[:checkboxes] + attr_list << :hostname + attr_list << [:hardware_pool, :name] if include_pool + attr_list += [:uuid, :hypervisor_type, :num_cpus, :cpu_speed, :arch, :memory_in_mb, :status_str, :id] json_list(hosts, attr_list, [:all], find_opts) end @@ -152,7 +160,7 @@ class HardwareController < ApplicationController else # FIXME: no permissions or usage checks here yet # filtering on which pool to exclude - id = params[:exclude_id] + id = params[:exclude_pool] storage_pools = StoragePool find_opts = {:include => :hardware_pool, :conditions => ["pools.id != ?", id]} diff --git a/wui/src/app/controllers/host_controller.rb b/wui/src/app/controllers/host_controller.rb index 20571d7..4e4375a 100644 --- a/wui/src/app/controllers/host_controller.rb +++ b/wui/src/app/controllers/host_controller.rb @@ -44,6 +44,17 @@ class HostController < ApplicationController render :layout => 'selection' end + def quick_summary + pre_show + set_perms(@perm_obj) + unless @can_view + flash[:notice] = 'You do not have permission to view this host: redirecting to top level' + #perm errors for ajax should be done differently + redirect_to :controller => 'dashboard', :action => 'list' + end + render :layout => false + end + # retrieves data used by snapshot graphs def snapshot_graph end diff --git a/wui/src/app/controllers/resources_controller.rb b/wui/src/app/controllers/resources_controller.rb index 694ef74..ca10960 100644 --- a/wui/src/app/controllers/resources_controller.rb +++ b/wui/src/app/controllers/resources_controller.rb @@ -184,31 +184,6 @@ class ResourcesController < ApplicationController @failure_list = [] end render :layout => 'confirmation' - - #if params[:vm_actions][:vms] - # vms = params[:vm_actions][:vms] - # if params[:vm_actions][VmTask::ACTION_START_VM] - # flash[:notice] = "Starting Machines #{vms.join(',')}." - # elsif params[:vm_actions][VmTask::ACTION_SHUTDOWN_VM] - # flash[:notice] = "Stopping Machines #{vms.join(',')}." - # elsif params[:vm_actions][:other_actions] - # case params[:vm_actions][:other_actions] - # when VmTask::ACTION_SHUTDOWN_VM then flash[:notice] = "Stopping Machines #{vms.join(',')}." - # when VmTask::ACTION_START_VM then flash[:notice] = "Starting Machines #{vms.join(',')}." - # when VmTask::ACTION_SUSPEND_VM then flash[:notice] = "Suspending Machines #{vms.join(',')}." - # when VmTask::ACTION_RESUME_VM then flash[:notice] = "Resuming Machines #{vms.join(',')}." - # when VmTask::ACTION_SAVE_VM then flash[:notice] = "Saving Machines #{vms.join(',')}." - # when VmTask::ACTION_RESTORE_VM then flash[:notice] = "Restoring Machines #{vms.join(',')}." - # when "destroy" then flash[:notice] = "Destroying Machines #{vms.join(',')}." - # else - # flash[:notice] = 'No Action Chosen.' - # end - # else - # flash[:notice] = 'No Action Chosen.' - # end - #else - # flash[:notice] = 'No Virtual Machines Selected.' - #end end protected diff --git a/wui/src/app/controllers/vm_controller.rb b/wui/src/app/controllers/vm_controller.rb index b9156d2..4f9962d 100644 --- a/wui/src/app/controllers/vm_controller.rb +++ b/wui/src/app/controllers/vm_controller.rb @@ -26,7 +26,7 @@ class VmController < ApplicationController def show set_perms(@perm_obj) - @actions = @vm.get_action_and_label_list + @actions = @vm.get_action_hash(@user) unless @can_view flash[:notice] = 'You do not have permission to view this vm: redirecting to top level' redirect_to :controller => 'resources', :controller => 'dashboard' @@ -149,8 +149,9 @@ class VmController < ApplicationController def vm_action vm_action = params[:vm_action] + data = params[:vm_action_data] begin - if @vm.queue_action(get_login_user, vm_action) + if @vm.queue_action(get_login_user, vm_action, data) render :json => { :object => "vm", :success => true, :alert => "#{vm_action} was successfully queued." } else render :json => { :object => "vm", :success => false, :alert => "#{vm_action} is an invalid action." } @@ -171,6 +172,14 @@ class VmController < ApplicationController end end + def migrate + @vm = Vm.find(params[:id]) + @perm_obj = @vm.get_hardware_pool + @redir_obj = @vm + @current_pool_id=@vm.vm_resource_pool.id + authorize_admin + render :layout => 'popup' + end def console @show_vnc_error = "Console is unavailable for VM #{@vm.description}" unless @vm.has_console diff --git a/wui/src/app/models/vm.rb b/wui/src/app/models/vm.rb index 617512e..b607886 100644 --- a/wui/src/app/models/vm.rb +++ b/wui/src/app/models/vm.rb @@ -22,7 +22,7 @@ require 'util/ovirt' class Vm < ActiveRecord::Base belongs_to :vm_resource_pool belongs_to :host - has_many :tasks, :class_name => "VmTask", :dependent => :destroy, :order => "id DESC" do + has_many :tasks, :class_name => "VmTask", :dependent => :destroy, :order => "id ASC" do def queued find(:all, :conditions=>{:state=>Task::STATE_QUEUED}) end @@ -58,6 +58,9 @@ class Vm < ActiveRecord::Base STATE_SAVING = "saving" STATE_SAVED = "saved" STATE_RESTORING = "restoring" + + STATE_MIGRATING = "migrating" + STATE_CREATE_FAILED = "create_failed" STATE_INVALID = "invalid" @@ -68,7 +71,8 @@ class Vm < ActiveRecord::Base STATE_SUSPENDING, STATE_RESUMING, STATE_SAVING, - STATE_RESTORING] + STATE_RESTORING, + STATE_MIGRATING] EFFECTIVE_STATE = { STATE_PENDING => STATE_PENDING, STATE_UNREACHABLE => STATE_UNREACHABLE, @@ -83,9 +87,15 @@ class Vm < ActiveRecord::Base STATE_SAVING => STATE_SAVED, STATE_SAVED => STATE_SAVED, STATE_RESTORING => STATE_RUNNING, + STATE_MIGRATING => STATE_RUNNING, STATE_CREATE_FAILED => STATE_CREATE_FAILED} TASK_STATE_TRANSITIONS = [] + def get_hardware_pool + pool = vm_resource_pool + pool = pool.get_hardware_pool if pool + pool + end def storage_volume_ids storage_volumes.collect {|x| x.id } end @@ -126,9 +136,9 @@ class Vm < ActiveRecord::Base RUNNING_STATES.include?(get_pending_state) end - def get_action_list + def get_action_list(user=nil) # return empty list rather than nil - return_val = VmTask::VALID_ACTIONS_PER_VM_STATE[get_pending_state] || [] + return_val = VmTask.valid_actions_for_vm_state(get_pending_state, self, user) || [] # filter actions based on quota unless resources_for_start? return_val = return_val - [VmTask::ACTION_START_VM, VmTask::ACTION_RESTORE_VM] @@ -136,10 +146,12 @@ class Vm < ActiveRecord::Base return_val end - def get_action_and_label_list - get_action_list.collect do |action| - VmTask.label_and_action(action) + def get_action_hash(user=nil) + actions = {} + get_action_list(user).each do |action| + actions[action] = VmTask::ACTIONS[action] end + actions end # these resource checks are made at VM start/restore time @@ -158,11 +170,12 @@ class Vm < ActiveRecord::Base return return_val end - def queue_action(user, action) + def queue_action(user, action, data = nil) return false unless get_action_list.include?(action) task = VmTask.new({ :user => user, :vm_id => id, - :action => action, + :action => action, + :args => data, :state => Task::STATE_QUEUED}) task.save! return true diff --git a/wui/src/app/models/vm_task.rb b/wui/src/app/models/vm_task.rb index aa12903..3f52478 100644 --- a/wui/src/app/models/vm_task.rb +++ b/wui/src/app/models/vm_task.rb @@ -33,59 +33,97 @@ class VmTask < Task ACTION_UPDATE_STATE_VM = "update_state_vm" + # for migrate VM action, args provides the optional target host + ACTION_MIGRATE_VM = "migrate_vm" + + PRIV_OBJECT_VM_POOL = "vm_resource_pool" + PRIV_OBJECT_HW_POOL = "get_hardware_pool" + + # a hash of task actions which point to a hash which define valid state transitions ACTIONS = { ACTION_CREATE_VM => { :label => "Create", :icon => "icon_start.png", :start => Vm::STATE_PENDING, :running => Vm::STATE_CREATING, :success => Vm::STATE_STOPPED, - :failure => Vm::STATE_CREATE_FAILED}, + :failure => Vm::STATE_CREATE_FAILED, + :privilege => [Permission::PRIV_MODIFY, + PRIV_OBJECT_VM_POOL]}, ACTION_START_VM => { :label => "Start", :icon => "icon_start.png", :start => Vm::STATE_STOPPED, :running => Vm::STATE_STARTING, :success => Vm::STATE_RUNNING, - :failure => Vm::STATE_STOPPED}, + :failure => Vm::STATE_STOPPED, + :privilege => [Permission::PRIV_VM_CONTROL, + PRIV_OBJECT_VM_POOL]}, ACTION_SHUTDOWN_VM => { :label => "Shutdown", :icon => "icon_x.png", :start => Vm::STATE_RUNNING, :running => Vm::STATE_STOPPING, :success => Vm::STATE_STOPPED, - :failure => Vm::STATE_RUNNING}, + :failure => Vm::STATE_RUNNING, + :privilege => [Permission::PRIV_VM_CONTROL, + PRIV_OBJECT_VM_POOL]}, ACTION_SUSPEND_VM => { :label => "Suspend", :icon => "icon_suspend.png", :start => Vm::STATE_RUNNING, :running => Vm::STATE_SUSPENDING, :success => Vm::STATE_SUSPENDED, - :failure => Vm::STATE_RUNNING}, + :failure => Vm::STATE_RUNNING, + :privilege => [Permission::PRIV_VM_CONTROL, + PRIV_OBJECT_VM_POOL]}, ACTION_RESUME_VM => { :label => "Resume", :icon => "icon_start.png", :start => Vm::STATE_SUSPENDED, :running => Vm::STATE_RESUMING, :success => Vm::STATE_RUNNING, - :failure => Vm::STATE_SUSPENDED}, + :failure => Vm::STATE_SUSPENDED, + :privilege => [Permission::PRIV_VM_CONTROL, + PRIV_OBJECT_VM_POOL]}, ACTION_SAVE_VM => { :label => "Save", :icon => "icon_save.png", :start => Vm::STATE_RUNNING, :running => Vm::STATE_SAVING, :success => Vm::STATE_SAVED, - :failure => Vm::STATE_RUNNING}, + :failure => Vm::STATE_RUNNING, + :privilege => [Permission::PRIV_VM_CONTROL, + PRIV_OBJECT_VM_POOL]}, ACTION_RESTORE_VM => { :label => "Restore", :icon => "icon_restore.png", :start => Vm::STATE_SAVED, :running => Vm::STATE_RESTORING, :success => Vm::STATE_RUNNING, - :failure => Vm::STATE_SAVED} } + :failure => Vm::STATE_SAVED, + :privilege => [Permission::PRIV_VM_CONTROL, + PRIV_OBJECT_VM_POOL]}, + ACTION_MIGRATE_VM => { :label => "Migrate", + :icon => "icon_restore.png", + :start => Vm::STATE_RUNNING, + :running => Vm::STATE_MIGRATING, + :success => Vm::STATE_RUNNING, + :failure => Vm::STATE_RUNNING, + :privilege => [Permission::PRIV_MODIFY, + PRIV_OBJECT_HW_POOL], + :popup_action => 'migrate'} } - VALID_ACTIONS_PER_VM_STATE = { Vm::STATE_PENDING => [ACTION_CREATE_VM], - Vm::STATE_RUNNING => [ACTION_SHUTDOWN_VM, - ACTION_SUSPEND_VM, - ACTION_SAVE_VM], - Vm::STATE_STOPPED => [ACTION_START_VM], - Vm::STATE_SUSPENDED => [ACTION_RESUME_VM], - Vm::STATE_SAVED => [ACTION_RESTORE_VM], - Vm::STATE_CREATE_FAILED => [], - Vm::STATE_INVALID => []} + def self.valid_actions_for_vm_state(state, vm=nil, user=nil) + actions = [] + ACTIONS.each do |action, hash| + if hash[:start] == state + add_action = true + print "vm: #{vm}\n user: #{user}\n" + if (vm and user) + pool = vm.send(hash[:privilege][1]) + print "pool: #{pool}\n privilege: #{hash[:privilege][1]}\n" + add_action = pool ? pool.has_privilege(user, hash[:privilege][0]) : false + end + print "add_action: #{add_action}\n" + actions << action if add_action + end + end + actions + end def self.action_label(action) return ACTIONS[action][:label] diff --git a/wui/src/app/views/hardware/show_hosts.rhtml b/wui/src/app/views/hardware/show_hosts.rhtml index aaf28b6..167c601 100644 --- a/wui/src/app/views/hardware/show_hosts.rhtml +++ b/wui/src/app/views/hardware/show_hosts.rhtml @@ -60,7 +60,10 @@
<%= render :partial => "/host/grid", :locals => { :table_id => "hosts_grid", :hwpool => @pool, - :exclude_id => nil, + :exclude_pool => nil, + :exclude_host => nil, + :show_pool => false, + :checkboxes => true, :on_select => "hosts_select", :on_deselect => "load_widget_deselect", :on_hover => "load_widget_hover", diff --git a/wui/src/app/views/hardware/show_storage.rhtml b/wui/src/app/views/hardware/show_storage.rhtml index ec1a82d..dc1460a 100644 --- a/wui/src/app/views/hardware/show_storage.rhtml +++ b/wui/src/app/views/hardware/show_storage.rhtml @@ -66,7 +66,7 @@
<%= render :partial => "/storage/grid", :locals => { :table_id => "storage_grid", :hwpool => @pool, - :exclude_id => nil, + :exclude_pool => nil, :on_select => "storage_select" } %>
diff --git a/wui/src/app/views/host/_grid.rhtml b/wui/src/app/views/host/_grid.rhtml index 98a8af4..d4d4d11 100644 --- a/wui/src/app/views/host/_grid.rhtml +++ b/wui/src/app/views/host/_grid.rhtml @@ -2,20 +2,25 @@ <% hosts_per_page = 40 %>
-
+<%= '' if checkboxes %> -
+<%= '' if checkboxes %>
+
+ + +
+
+ <%= error_messages_for 'migrate_vm' %> + + <%= render :partial => "/host/grid", :locals => { :table_id => "migrate_vm_grid", + :hwpool => @vm.get_hardware_pool, + :exclude_pool => nil, + :exclude_host => @vm.host_id, + :checkboxes => false, + :on_select => "migrate_vm_select", + :on_deselect => "migrate_vm_deselect", + :on_hover => "load_widget_hover", + :on_unhover => "load_widget_unhover" } %> + + <% form_tag do %> + + <%= hidden_field_tag 'id', @vm.id %> + <%= hidden_field_tag 'vm_action', VmTask::ACTION_MIGRATE_VM %> + Selected Migration Target: +
+
+
No migration target selected.
+
+
+ <%= hidden_field_tag 'vm_action_data', "" %> + <% end %> +
+<%= popup_footer("$('#migrate_vm_form').submit()", "Migrate Virtual Machine") %> +
+ + diff --git a/wui/src/app/views/vm/show.rhtml b/wui/src/app/views/vm/show.rhtml index 8b0a760..fe671ef 100644 --- a/wui/src/app/views/vm/show.rhtml +++ b/wui/src/app/views/vm/show.rhtml @@ -17,10 +17,17 @@ <%= link_to image_tag("icon_edit.png") + " Edit", {:controller => 'vm', :action => 'edit', :id => @vm}, :rel=>"facebox[.bolder]", :class=>"selection_facebox" %> - <% for action in @actions %> - - <%= image_tag action[2] %> <%= action[0] %> - + <% for name, action in @actions %> + <% if action[:popup_action] -%> + <%= link_to image_tag(action[:icon]) + action[:label], + {:controller => 'vm', + :action => action[:popup_action], :id => @vm}, + :rel=>"facebox[.bolder]", :class=>"selection_facebox" %> + <% else -%> + + <%= image_tag action[:icon] %> <%= action[:label] %> + + <% end -%> <% end %> <%= image_tag "icon_x.png" %> Cancel queued tasks diff --git a/wui/src/public/javascripts/flexigrid.js b/wui/src/public/javascripts/flexigrid.js index d7b6416..3715e6f 100644 --- a/wui/src/public/javascripts/flexigrid.js +++ b/wui/src/public/javascripts/flexigrid.js @@ -719,7 +719,9 @@ } $(this).toggleClass('trSelected'); if($(this).hasClass('trSelected')){ - if (p.onSelect) p.onSelect($(t).find("tr.trSelected")); + if (p.onSelect) p.onSelect($(t).find("tr.trSelected")); + } else { + if (p.onDeselect) p.onDeselect(this); } } ) diff --git a/wui/src/public/javascripts/ovirt.js b/wui/src/public/javascripts/ovirt.js index c776458..e0aa222 100644 --- a/wui/src/public/javascripts/ovirt.js +++ b/wui/src/public/javascripts/ovirt.js @@ -74,7 +74,7 @@ function ajax_validation(response, status) if (response.object) { $(".fieldWithErrors").removeClass("fieldWithErrors"); $("div.errorExplanation").remove(); - if (!response.success) { + if (!response.success && response.errors ) { for(i=0; i I've replaced all instances of "alert($foo)" with the jgrowl implementation, and I've increased the default visibility duration to 10 seconds. This can still be customized on a per-message basis if we eventually want to change the behavior based on the context of the message. Signed-off-by: Scott Seago --- wui/src/app/views/hardware/move.rhtml | 2 +- wui/src/app/views/hardware/quick_summary.rhtml | 2 +- wui/src/app/views/hardware/show_hosts.rhtml | 2 +- wui/src/app/views/hardware/show_storage.rhtml | 4 +- wui/src/app/views/hardware/show_vms.rhtml | 2 +- wui/src/app/views/host/show.rhtml | 2 +- wui/src/app/views/layouts/redux.rhtml | 12 +- wui/src/app/views/resources/quick_summary.rhtml | 2 +- wui/src/app/views/resources/show_vms.rhtml | 2 +- wui/src/app/views/storage/show.rhtml | 4 +- wui/src/app/views/user/_show.rhtml | 4 +- wui/src/app/views/vm/show.rhtml | 6 +- wui/src/public/images/icon_conf_message.png | Bin 0 -> 49126 bytes wui/src/public/javascripts/jquery.jgrowl.js | 204 +++++++++++++++++++++++ wui/src/public/javascripts/ovirt.js | 8 +- wui/src/public/stylesheets/jquery.jgrowl.css | 125 ++++++++++++++ 16 files changed, 356 insertions(+), 25 deletions(-) create mode 100644 wui/src/public/images/icon_conf_message.png create mode 100644 wui/src/public/javascripts/jquery.jgrowl.js create mode 100644 wui/src/public/stylesheets/jquery.jgrowl.css diff --git a/wui/src/app/views/hardware/move.rhtml b/wui/src/app/views/hardware/move.rhtml index 4126e3b..968e2ca 100644 --- a/wui/src/app/views/hardware/move.rhtml +++ b/wui/src/app/views/hardware/move.rhtml @@ -27,7 +27,7 @@ $("#<%= @resource_type %>_grid").flexReload() jQuery(document).trigger('close.facebox'); if (data.alert) { - alert(data.alert); + $.jGrowl(data.alert); } if (get_selected_<%= @resource_type %>().indexOf($('#<%= @resource_type %>_selection_id').html()) != -1){ empty_summary('<%= @resource_type %>_selection', '<%= @resource_type == 'hosts' ? 'Host' : 'Storage Pool' %>') diff --git a/wui/src/app/views/hardware/quick_summary.rhtml b/wui/src/app/views/hardware/quick_summary.rhtml index 85524f4..897cecb 100644 --- a/wui/src/app/views/hardware/quick_summary.rhtml +++ b/wui/src/app/views/hardware/quick_summary.rhtml @@ -31,7 +31,7 @@ :action => "quick_summary" %>', <%= @pool.id %>) if (data.alert) { - alert(data.alert); + $.jGrowl(data.alert); } }, 'json'); } diff --git a/wui/src/app/views/hardware/show_hosts.rhtml b/wui/src/app/views/hardware/show_hosts.rhtml index 167c601..f2962cb 100644 --- a/wui/src/app/views/hardware/show_hosts.rhtml +++ b/wui/src/app/views/hardware/show_hosts.rhtml @@ -31,7 +31,7 @@ function(data,status){ $("#hosts_grid").flexReload() if (data.alert) { - alert(data.alert); + $.jGrowl(data.alert); } if (hosts.indexOf($('#hosts_selection_id').html()) != -1){ empty_summary('hosts_selection', 'Host') diff --git a/wui/src/app/views/hardware/show_storage.rhtml b/wui/src/app/views/hardware/show_storage.rhtml index dc1460a..3446280 100644 --- a/wui/src/app/views/hardware/show_storage.rhtml +++ b/wui/src/app/views/hardware/show_storage.rhtml @@ -22,7 +22,7 @@ function(data,status){ $("#storage_grid").flexReload() if (data.alert) { - alert(data.alert); + $.jGrowl(data.alert); } if (storage.indexOf($('#storage_selection_id').html()) != -1){ empty_summary('storage_selection', 'Storage Pool') @@ -39,7 +39,7 @@ function(data,status){ $("#storage_grid").flexReload() if (data.alert) { - alert(data.alert); + $.jGrowl(data.alert); } if (storage.indexOf($('#storage_selection_id').html()) != -1){ empty_summary('storage_selection', 'Storage Pool') diff --git a/wui/src/app/views/hardware/show_vms.rhtml b/wui/src/app/views/hardware/show_vms.rhtml index 26e2488..4555718 100644 --- a/wui/src/app/views/hardware/show_vms.rhtml +++ b/wui/src/app/views/hardware/show_vms.rhtml @@ -18,7 +18,7 @@ function(data,status){ $("#vmpools_grid").flexReload() if (data.alert) { - alert(data.alert); + $.jGrowl(data.alert); } if (vm_pools.indexOf($('#vmpool_selection_id').html()) != -1){ empty_summary('vmpool_selection', 'Virtual Machine Pool') diff --git a/wui/src/app/views/host/show.rhtml b/wui/src/app/views/host/show.rhtml index e1bafac..b5582f6 100644 --- a/wui/src/app/views/host/show.rhtml +++ b/wui/src/app/views/host/show.rhtml @@ -31,7 +31,7 @@ <%= @host.id %>) $("#hosts_grid").flexReload() if (data.alert) { - alert(data.alert); + $.jGrowl(data.alert); } }, 'json'); } diff --git a/wui/src/app/views/layouts/redux.rhtml b/wui/src/app/views/layouts/redux.rhtml index f0bc049..46ff9da 100644 --- a/wui/src/app/views/layouts/redux.rhtml +++ b/wui/src/app/views/layouts/redux.rhtml @@ -15,6 +15,7 @@ <%= stylesheet_link_tag '/javascripts/jquery-treeview/ovirt.treeview.css' %> <%= stylesheet_link_tag 'flexigrid/flexigrid.css' %> <%= stylesheet_link_tag 'facebox' %> + <%= stylesheet_link_tag 'jquery.jgrowl.css' %> <%= javascript_include_tag "jquery-1.2.6.min.js" -%> <%= javascript_include_tag "jquery-treeview/jquery.treeview.js" -%> @@ -30,6 +31,7 @@ <%= javascript_include_tag "jquery.cookie.js" -%> <%= javascript_include_tag "jquery.livequery.pack.js" -%> <%= javascript_include_tag "jquery.form.js" -%> + <%= javascript_include_tag "jquery.jgrowl.js" -%> <%= javascript_include_tag "ovirt.js" -%> @@ -66,7 +68,7 @@ $('#side-toolbar').html($(data).find('div.toolbar')); $('#tabs-and-content-container').html($(data).not('div#side-toolbar')); }, - error: function(xhr) {alert(xhr.status + ' ' + xhr.statusText);} + error: function(xhr) {$.jGrowl(xhr.status + ' ' + xhr.statusText);} }); return false;})},function(){}); $('.tab_nav a').livequery(function(){ @@ -83,7 +85,7 @@ var my_parent = $(this).parent(); $('#content-area').html($(data).find('div').filter('[id=content-area]')); }, - error: function(xhr) {alert(xhr.status + ' ' + xhr.statusText);} + error: function(xhr) {$.jGrowl(xhr.status + ' ' + xhr.statusText);} }); return false;})},function(){}); $('.dialog_tab_nav a').livequery(function(){ @@ -100,7 +102,7 @@ var my_parent = $(this).parent(); $('#dialog-content-area').html($(data)); }, - error: function(xhr) {alert(xhr.status + ' ' + xhr.statusText);} + error: function(xhr) {$.jGrowl(xhr.status + ' ' + xhr.statusText);} }); return false;})},function(){}); }); @@ -114,7 +116,7 @@ // need to redirect to the parent using the new ajax reload stuff $("#vmpools_grid").flexReload() if (data.alert) { - alert(data.alert); + $.jGrowl(data.alert); } }, 'json'); } @@ -127,7 +129,7 @@ function(data,status){ // need to redirect to the parent using the new ajax reload stuff if (data.alert) { - alert(data.alert); + $.jGrowl(data.alert); } }, 'json'); } diff --git a/wui/src/app/views/resources/quick_summary.rhtml b/wui/src/app/views/resources/quick_summary.rhtml index 972c439..77b1708 100644 --- a/wui/src/app/views/resources/quick_summary.rhtml +++ b/wui/src/app/views/resources/quick_summary.rhtml @@ -32,7 +32,7 @@ :action => "quick_summary" %>', <%= @vm_resource_pool.id %>) if (data.alert) { - alert(data.alert); + $.jGrowl(data.alert); } }, 'json'); } diff --git a/wui/src/app/views/resources/show_vms.rhtml b/wui/src/app/views/resources/show_vms.rhtml index b1accd3..359bd8f 100644 --- a/wui/src/app/views/resources/show_vms.rhtml +++ b/wui/src/app/views/resources/show_vms.rhtml @@ -33,7 +33,7 @@ function(data,status){ $("#vms_grid").flexReload() if (data.alert) { - alert(data.alert); + $.jGrowl(data.alert); } if (vms.indexOf($('#vms_selection_id').html()) != -1){ empty_summary('vms_selection', 'Virtual Machine') diff --git a/wui/src/app/views/storage/show.rhtml b/wui/src/app/views/storage/show.rhtml index 8da0f8c..6263021 100644 --- a/wui/src/app/views/storage/show.rhtml +++ b/wui/src/app/views/storage/show.rhtml @@ -84,7 +84,7 @@ <%= @storage_pool.id %>) $("#storage_grid").flexReload() if (data.alert) { - alert(data.alert); + $.jGrowl(data.alert); } }, 'json'); } @@ -95,7 +95,7 @@ function(data,status){ $("#storage_grid").flexReload() if (data.alert) { - alert(data.alert); + $.jGrowl(data.alert); } empty_summary('storage_selection', 'Storage Pool') }, 'json'); diff --git a/wui/src/app/views/user/_show.rhtml b/wui/src/app/views/user/_show.rhtml index dd391dd..351d0c7 100644 --- a/wui/src/app/views/user/_show.rhtml +++ b/wui/src/app/views/user/_show.rhtml @@ -19,7 +19,7 @@ function(data,status){ $("#users_grid").flexReload() if (data.alert) { - alert(data.alert); + $.jGrowl(data.alert); } }, 'json'); } @@ -33,7 +33,7 @@ function(data,status){ $("#users_grid").flexReload() if (data.alert) { - alert(data.alert); + $.jGrowl(data.alert); } }, 'json'); } diff --git a/wui/src/app/views/vm/show.rhtml b/wui/src/app/views/vm/show.rhtml index fe671ef..293b632 100644 --- a/wui/src/app/views/vm/show.rhtml +++ b/wui/src/app/views/vm/show.rhtml @@ -49,7 +49,7 @@ <%= @vm.id %>) $("#vms_grid").flexReload() if (data.alert) { - alert(data.alert); + $.jGrowl(data.alert); } }, 'json'); } @@ -62,7 +62,7 @@ function(data,status){ $("#vms_grid").flexReload() if (data.alert) { - alert(data.alert); + $.jGrowl(data.alert); } empty_summary('vms_selection', 'Virtual Machine') }, 'json'); @@ -79,7 +79,7 @@ <%= @vm.id %>) $("#vms_grid").flexReload() if (data.alert) { - alert(data.alert); + $.jGrowl(data.alert); } }, 'json'); } diff --git a/wui/src/public/images/icon_conf_message.png b/wui/src/public/images/icon_conf_message.png new file mode 100644 index 0000000000000000000000000000000000000000..1153a76fedee496949647a72b4fc345231dd884e GIT binary patch literal 49126 zcmdSA1#DbD+vc4#ZNtpmG~6&VGcz+YGbar*Gc^r2%*;#^W at er+!)*G0cK2D3UhVhl zlU8fZvF~%nZ zzj5^iQ!%ZK`K2#UoDU`79p1d`Qmys99j$mY+=6Pj;U|_QOX==6PwZt!0?LOPzcwg=n z*H2+=ll!L5gbz})U}!Rv=PUW->qLYdeDTH$y{5o2)8;7Mg;JU)w+XV2_oAH7BcKVG zVb_S- at Am$i^pEbDEkI4HBg*wLUBj03XWqrKdiw zvg>(Su*1jB2WoZE^ZB>O)88%|WL3Ek8v}gH513{zuVFVrJK+EB@<+54OK3E~z4rro zTkPXZ+{Q{!^m$|S{UiSTKh^tBoKO}p<$-~*LD*O+D}BtO&$`=cV=bMW+w5HU%{*}a z#$LC5fyZsV*!4zAFE+(w+16Mqd9VLi3PU73S`MFl)phOO{n)RI3Bv!gK-_l=A9nb% z!8j(TkO;um}>Q)!d=C>}-7BXBQxfB^6_m9pRZCSM23>r*}JF>SH zvN{Y#P6K7_Pt)q&0+9;?*A47ftIYzpN3e~X9)1P+zh~Zgb!4u(626~V$5z@#!y8#Y z4r=AwNk_vzx|(K9BE%pN9U|{(^T(LHLbaF;=GqTFSx<2g7{#xODPOZHFQv1ZoddvC zYkige!@B++;}qC*&>WGG zHTJ6gEsie;Y7;}8dX0yKcD*MzcYxX at 05SDzIhrPew2;>$l z!dA=`c+x3EH`JdmlH|FRfzV%2GhAt4W#}L?B8p7%O3gExmNq1i7EW=XLf=@&uxph= zZnY3BGM{(Tx1IQN9r#1ROu<^4P2jdx$=O-cSFIY&d4 at aGRl8{PAz}25XdyGrpsj%=e6Wp4r()(z(|wXwu`5jxN0S*ZDZg$J@@`_B zi7N#ZW#I;>lg_+G`4 at T>JS#;?g?wz_is-d6fmE{h5%xIXY}o-_cP%@6)Of|knpy0T zm_z30t~6ys^H_o`A at b+4?e&PIW@}h}J}Eiz=nuaLZO~u<0e)pXQEYlf$M^%Wy=gM0<=u+N at hbHG`twOK>=q-2vaRA{=g@ z=1%40YvruBQlkq}N@@e at HSr|9vRK?z^Qf71t6MKw*zm>cOdh6DcMNo`zNYZy7=Y|rLNaFe2s%|nzBHOK$F&iHq!}X zqy+LntgjjdT?76UMi1=$K>Vjm-fz34I{=Zh;?7CMZ!Gwno3scz<~&xcfq>e#wfotO z17ORzZZ9Sm1z5IxGyYGwWZKm`HU0cX^I_SZifzoHiG2gp*x76*2d6&O&do-VsdOqY zUlPJW2m=v$54iGp28& zHzO%5XusWXuzHe6u*H8Hg1uNNC at Ap%G#pS~A?-Kz?U^3W&wcR1>353ESF^|-2|)Je zVh^&bc+2H2UkgEE>`VF0EDl_qBIUyT>MWtr!i!aw8%7Sh at _f$LcUxf^{{TG|Z at j4$@#D8Wpc!owKDfdyy`vnLG=e5zhOY;`9%DTv5c at 8XYPaVW+T2m<;$w&{!kfpZtLS)rIa*SB*1p` zd(3LMc#oL^g zfSHBcNAxSS2rHFNd*6ToSq&+`b1ZX%MSjwuoRWR;4!*%&9F}BO#x`5-X39CXPqBac z3Ogo=GYKUoXx0A`1pu>cHaT?R5Jo6l>*-BKv5MfnLZnN;k|kaDQ>(KWo-PQYeSBCt zVm1L)!0}7sY3 z8F=G_ifv?JIx8sdfT6=9$6n`R?>kLT$T#DkVSMUL8-TW;)o&_VL)`;8c6M_G5#VmNH8k6@`Q!y zpaB6C`RqXV{nBwOa|pYwjH_yBVZnm(M#IDwDxdJgI2g(cuDSTG$36G5?;TzgK+KeS z9y&h?Xv2_~GX;?7HS$McN$0Wx1BTjO-Ba<&$yLXJTJV*r at S?waOX63nC&gI^ixA;G zf at N7VVi06Z1{DyC(>JBQ5lH;mUCJgDfzi?YB13}kwRl2@@wN9g=pg9@`Z4%SVcj_9 zlK}^kPi{0;gu!!&Gjm()kc~oRTss)cBnAS)iF(_XghPA154TNP97cMi92AjtL1v#Y z5(z#pgLbzK9;T at ODWv^m9D-=s0VCF_!=GCidJ~=1c^MnE;xyBA6NTPiLu|cEYrmCF zIPsD6J}>z2R`!$CHrFsu6+B**ub!^0x$fgP zgO3=BgSRkQL at M$#vj2ws+D?9)Rd8UR?u`9S$Mm>W8n>frp3+x{l%~l9C23O~ z59*;G{cNv><@}`ySxyNVN|lnVWhf+G2GP3wKChSHXs7__#hDwl%3h*`Ni)H?W}jU* zd9ADF2;c at 4*t>Zsx-Zz~!}H_k6k4zT2noH;WEmV9k$Yp;Y z3S2M2MYLvJZq8T579vJhF?lb`(a|YwElbi?WbZy{%m!@uaY{2P=e0=u!h(W$or9bM zKuN9;D=}9_qAC14wl^nCK#)268jB(BQ`q+l65^_?J#8|MrUdQu&S4UJ8Qr78ZmHwQ zXD3<5EGKf;hH}XQ5n-GsRRW%MD$OVSOK2{KSCV~q4u|=)X3OOIQSmZ4*#f$A5yZzO zZ9F~+4qaJIc(Mvn(hA0z6O`|XNQgwqM~@PtSB^85j20|Z7U=N{sI(P2onm*ySD9y7 z+}qdF*$#{kQI56N3>u9;G%(`#g=oiEWp?#~6JG?Hsm>VBTu!DP9k0`~UL|Ek_Ue%l zfYnvihwP;g*A!y-abg_%#;gX6naYe*M)SI}f_)afe?*4l6k}2o7m_5bG$qQ$_1g$1 zW`cO%^QX9yZe$s+M8gmgd4=&0p>D_L~tl^J~=v5i{-frG at _)lCWGdVn1LNa-{w0*?jy8&}S zJjY1FaE$3YVz8f{VJ6x?yZ at EK;{F49E6sX`<$OWqB?CiY);Z%369$oGhU=JB0TGO^ zFwcDatj@}C^PHkpk`xipwcw?{+IX%@0F)A at XNsUh_CG8!Vkuj;95 zuwwexTB||N5VQ5J*dwqH`88yS?3S#R49|)`Mj{s{d)dDWV{fZUyELA&S4pF;|?lEr|cQgp|7o1;D{_d_t#Fq0Ldy zVSs8G43sQAfN^bm?_t+)E)k8DKnns-z`_Ofd2)2!gU?|MiK#)0nkUXx zmV)3UZYq^t4q#2e z1kTqGcaKu+WK65jS$_Sl$5(CKDOhe&JKDdGKApXW)!kIhJ@^KDy_znei>cvtILEkB z#Z9BfSzSs2|y)QtKm^0 zQ~hWIx{w;24udm>5F!{$JK=pxL>^U$F00TYRmeYeKEcrp6#b1okKxXh|JEFs`m*4< z6-W{h$rmaxpGyu?JWX?C(>Xt}6|XUb?5|N8A4DpzWQ~1N;pyAcWLD z8u%*-O307nZ`g?l_qVOT{rGOh)ftuShR(GK=~}6}p>n2OKw!kBNhxF0Xr=p;^YY~R+mh>tT>Z5$m7H_>>nq8Q62xXC$+iz<%wV#W`pzbg z?v^s1j)U{SG%5Rv;{~?+EyY&}wfK{7zAn0df<2C{K zyuU-AR`Vk16-4a_;pGcwIpIn*2>#;Mf2A|n&!~`>o;&!W^JnAGGEmDX!71qh%&`vp zr>7M(jR)E)?vHC#s|g!VHWk!ch!uG42jXK`%eW~jZdS61jG*xuk{80buiq!fVOG~$ zzsEkYDy$zTEM^oqoH#a*>Ifjtp2}duuSF%-cb1q&dqsdhg&j$-ZteCy?Kf1LE7uj( zB&#ShSrEIdpe%OCl{d*QXS1>XR867o93o!o+-mVXEO z=|~!1fTHxZi8QTPl0md_Bg`_I(05yo!3?TR#bZLSr^qP)shDi1qGwLoLLn6{{ZF)% zyFc}!-`LvX2;+F^ZJWS)GK!j3tj;T1?+066B1l{$@~fKGAl+fR{FnwyQDXIOVoqgV z|M(&0ml8||F`sfCX6J|>9(Ij=-6Q^bv0bIvnOt`_JGUgRdYWH$-NgGQYf&-T8M)%w z^6Gw?TU`InCe*&mZ6ll&;_q2l=_|)VG2XVzM1$f1yk`#)z2>##7K=r*ecWB43N+u=!aP$!Ei2{gi-HU$cY>Q%&6e&*`z214hr8+a+xX@)jcBeAP7Y6UU? z7ESH=MA#yxCeWxS0hY!^XXOp+nonWeOX?o_;_OW`@8NWV>w>LfA{kQKqx+xiVG_a@ z4L?A8FyxRbMq6$e)`1e`WVSq9j0#^rb^jwnwoMHH$viV)?3- z5WB_orihDBTP0pndmBVBG0j}eYKIAcRb}3jcBva;mRkHUTFK(C9yBm7W5=pI`Fy^y@~6jLiQQoA#>in$g9qzd z*_DeX%}H={Py>3|^FpwnXW1foxS9MU?21pXV`DFRt%(LbFtGJu2{L=}e&1>Pq2FBr zenXMuHo_G|*PA=~LvN^=CD_4lxcQya>M#N2g5!4!XO;@an_p)6hH8?M=4Md=2U*1w zzEai%dA8&5$@AL9U>D0uEQxAPenob|z+la#<+Gn=+3x*xe%(f|Prt at f!ClAws2sP- z17^8rB`B}Q6 at PFsB=T?&A335#r!1zT%Cp$OyYPM|SGoY`F7W8muN1?>w2;K#>H>aO`f3-jR)T3?(i!_-dX~hsb%1ShOd5?kKfpy_)qf_v4SG^|0l=CWe4Q z<>X>Pa_3&hReJvNHj*&=sa>qC?J8GC-Ksx`?X*_!j?&k3-IwCnj`IGA)st5Q>lg|p zJ|=N4OW at Gm+X~Q{e~(SprXv{=YSzU1ij%#rSqJSxCbsIrYAYU%>Moi1=_tH$+<8so6&jg5^wy;Xe45czR5z}eOp zFZB|Rmln|2vJLz!(Tm4;0y@{B?n)HOx8C)9d}*;& zo>mv|}PXR4R` zmNCEP)b85>i?W5Z&l-d)KZO^M<=l20fNL$!kQ0(5A)CN;Mu*z*kd$Eae7nQ6P7QME zK<%txnc9IbaT9SU>}1h$E?4_sXKtKhfke_39f!*)y( zoG0Z)sF%j#byM8;5O7`wvneOEs at aV2Z6B=z!{>j#a1cnzjguMoK3k1L! z389nUHY85sDSLFBi0swMc&(UTrU`0h#DrWE zg;WWo5E^Sz#MG(e*NkA5;ZSfRkMX#YoN0_tWfx7u14pPa89}8&Aq$PVaf|oF6^=al zXQf8jevc4dJ3NTDWLU^%BVKOd-J8r_8VZ9T(4C_<*1SgNIw8r?g_kH5L zL6f?oTgSS~wH$-q*sgpbL^z)%Nako_4vO24Ryc-{+(G*isKuU z4VkC9#ks=_-J at uT5y7o9QLp#yX0g8g-c0Qjr!DKSYpTb zEK#(;=f~y$2+BP at k*6o!~7(1*@0 z|5=E^cF-e`5B^@e&?Dl&Jp2c)c-cT+{g6hW8TzPT-{Fk at N`<#R at 4h~8${EcoD+!A2 zHCc)h7d6CW)=XX&Q~1dgV}F&Dt9*SN!a%|Qa|OJ4CH$hiwy~gb14iVu;riXa{w at 3v zl+oRyrZdj>&SJB-@@Y6-oW3DlE?zXfyl<*6ve`h)Ejm^)YNLY%EYk&ba2a6{nUIWJ z5&eKvv9e)#@#guKn*Op>h_xzrC4x4`atUF5lNXcBqLper-{BZ)CnOqjx1=7%^&Oo$ zQ%0zfL;<+K^6E`P{-hc&Ji{SZ=SSwvs=@5YB{`qmLVin5=T05G)+x^g>#x}+FD>WA zEEDTa=^a6IuJT}o at jW`P37p~#m$4^bNO%=PqjMxF|t}9l0oRLk?Vb6IHN*4wqI7tNJ_#`_~Q+)jNUfE{YLD&3N?G>CAVBQwr|AB+FO&b z&v2WUO3fRAQY=ej9~;G}E`-qB4M4}Ds9DmEJS7{d2MAQOS)5=4Twv%S_>U})3!X!!;Px- at O3X|Epl>A`J1c}%x<}rcAP8N2H z5;6|C&zV_iu0i~w$#RyPs1m(z83Va;&z_#p^+g*qU(B~`Df|w0PaV}QqXqz2yAn2I zbIHy=^WNBwYEnMC7P_N1)u6 at T%FSY0Gov-dR{(E-c`0aRJitX*s4)%4 at xq7q48JLA zX|F}SFy}w)*`qiRRM*=kLa`%@3Qjgs4i&Tb6B%g2mfk|@RV{Px&yJAV{maLmfs~G& zEkvku{o-dM)t>(UyCjZpY9Xy+{)l-H(($N%LZYV$y)fr84jcDsQo-sQBF!AHUgNRT z&%4Y&bh0bdok!@|KFGTcNwCmRUwTE4aI*b+MXoZ=QTGjyo;216MAKZAaN9`KoCsR< z(Q3EAW|0G=oRuz^yPcgOq%~*K8;|PnqMlM1D3nU_>eB66JHg_5i(%%|Dc)s?^v_}T z=yT8pxQ7EU^}Y at zpfh88QNUUp8fo{Nz&B$e_jiPKj|JEfn4MJu+X=L^iVMfhl3R$P zd`lA1zn?K|ay+O at T0+MfG){40#a=--b^WXZg8d8KD>m4fxy1r6_RvPYc|jXV#C7PtqET zt}aTe^OQvzrW#4~M_1AGtW8HB_?9ub%;_c}7k9uhl9p#r6=HrVnj`O1>38BX>EL|d zvPh`Y&?4=VRQiGjo-}g2k%6^R$e6O_>=}Bb`UReFZoGp-XVFDF#kb zRb=Mta#LzBbsZ^ReNL8qfH(0gbNAF3<xh~fd`??nwgPZ<6%!{tx+y^AaQ zR)0?07Bs&ZA^LJo)@Ya_$IV}hv7rrX-pG`vrKni<{RCTut2pMmpM&$f4rw)1_)?+E z3T3^YD+)E_BHQt(-H7EizWQ-zOSJ!G1o?{lNH>V}E(>EHJ^JCu?CZsbngvZP+U3>l zAGQg?&#E*Ps!u_w+)(+f62&7Q7?3k!wGqa at YZu_I+d6ZAV>sWFX=eB)xOF{*kSHueg0zcjw-1uHWBCu`fk%YBL^M#IPelQ()Q=WNf=Vdp~myltyM> z6Thcwp>h5=vzpl{|HOqQNZEV?$x}#39+01bhbE&y)Rm`UBJ6bJ%cgbkuy1$Jmgp|=-o#*2$S?I>=JEBh~Krp-cD zsre5yOGG`E@|uR=WySm##ZnEFC{vIqi>hxu%LXSR5d1NHm6)`@^O`ukX at c8X2LU>6MeL!iCdlF8EPT>k#v z9uvn?a#qB!1u@>5fu6yngCgXfLJa4(SjW*3>t18lQe)M at KOL+~ebp*u82JC5>Dz8wyP~eJ41O1u znYHzZW)|*=Eh*-7Y?Z>rPSyO-Pubs5`7um84#Tj7Potl_`_ErI{>0tBfk|;NZO=&Q zdti&tw59F*Uj=H(8%8f5ce%B8KZx4UMiT)bQl<|ZeXHzasv8AbTs)a*I)gDbgQD!P z8vB~&cQTJM?8^o0$_C`30oL7mu#T6D(jJF)x3W)XO^bX90Od^4! zjiB0$mpQJeOp7U|%gpddoXBBm!V{b8wr>}DdS)abl2BBGw;-2R-AzCOLu=rJt zVZ+z=tE4!huS#Of9+$jG*?A1I5iw1KHyu&h^#FaZzS=?AXBIVQA>?e zk;Dlbf`*iPIf}`2-U`c-sY2`7tOYBkbSUSwdu&tr%y8 at bk5I75E-D&%N|A+T_WAfx zjCTFh=@2*f at TVS+e)K at uB&@L9QR687r+ZE3jPtwOcn(mCk z9hyi0*#jGlyt&zg4zBOX&l^==I~NxJVOoVw^;&=V2)fwe*3kvK7-F9F)gH7f at 0SSp z`{(k%OiP#5Y!%&1ElbD26#=jz?&vx&g)T&wou^V+ at s|%p{i{s91C3tQ{SAD^&h4sWoBOdx8?_Qs&0fJ41yN_i;-?-mNoVx{&KGOgk_EV5xu=p zt}??zuWrC!LX`~yp5a*>>MT7;X?v(S-1=-CS?=rnBXs+pX!#+quIvL$eMrj=t?O$4 z2!%EwL;f;Z+-OtY2mL%jnylY^7gW&C*EqO z4_0P)7?Dlv3hdS>0VQzvk<&7|#^}~xvAQl;F0VlNT4B?AlgaBk5m{$f4E#ax9DSY7 zUz)#J&=@gAU~%uU at 7t)%_2y)rxYc zkyXh8dy3;pd~a56BiGV6;wpA0+{Gfyyhsf94y at 5m9+~k`xLccCL{(W;@c5lfuIcf6 zZ10d9ITzOIdzoYKzKF%vPE2+Hk at +nRoxq#gAv9Lf-7$iy`OkXu1PIEh*L?T~Sq6G(GfQsyK1OB?d>O`2A=vu&jrzX+#nw^|7$^yCAB zbhm35EEY(NQ^=M<{>(@orm9Q81$2+`rtlNl)b<6EXr1;${D!k4sZ$v)!a{KvV_49BN|6MC z4eJHD(sDRnC(qnyH_+-V`y&@rm#Y=Bd}>(^e)Yc%aA^AiwZPmluWMyD- at pb~S0gEv z!tv?Y=k3;de9L5zO?H3HaMQNiQF{x-lDP{bE6`ZvxVRPOb at dX8mHnqRRP1Ie71`oqs`J*<~o zvJ1Ze@(_k}xqe4?!g~71n$5&1-_-|z at 1cdCcG1PrD>nwFmrds9b+!&7sNsACwH~F4qmXHFWGkLjFBu;f7YNoV(e@ zB20(g!-hwfg-s>*)+oe3S*IVtW&RP=9wRHap2MD}pl+B{ynL>y47cX-l;Zcrqj~q5 zc_ijKX)3B>s%un&pgH80vD|k|b zoN0!nA~1oiM-@=rfNetUz)z(p9rt-BMwRW?)3kX^4~bONwR#olLX$f>4{i9n69FRn zYK+3*pP zXPqKU^*GG9a|aiA&XbDD45u~*7pYl1^fQ>ycW(>=Z&Ikg+rYT z!qWJ2erE+vmSL;uM=Vlgr0aJ{`$^lU1Y at G)XZ(4kHN8iI)D?$HNXyHV?|EwVFMi1H%BoMCgB6rfFG7QNiyB<1N$!)# z6Z6~UwMU>;Ydo9tBx=@}V6|D$ ztR{X_EJ5}i29OvqN?vi%pys<%+S;W*@AQTU-*`&j$*RrG1`LxIKG$@y_L=8`-=%86 z1Q~yKnH0+D2uX1qXzvI)(nDX>h+n%>JZD35GMo49qjQjZ{Bf`7on31uHaW1vLH`o8 z92yaNG2C~;@(>WJ(ov?~Y`EP;2+QVFclpCrv8d*f&HtLi;|}#G*KjezyL|kJ>sJ_K zr1K;9^-_ZBr&|0qvg!j*H~S&2*4LVQqms~OJxAss9^t4w{Cx==-2P%e6Yb#hAm&hS zy*L1)Hf=a*b(77y!U<{wBik at zqxgwS#=Oly0dJ8;sH*hIBi%12H6~D8 at tdER4!`fa zcu6&fQ4OQyS?U?8mo6%77t at l`!qngf5+`Gk#G87hUPyc!rACTBH+58%>@iH976Ahc zut2mc>O7=@162PF(o9ITZm||B!qKObtm2mRB6<>U;(7H0rQge5oUv|!CR)$bd?Io+ zng~Z9wIVz_qjRK at 2iboLN9~fZn0?rJHZ$sgB|ae|wy6o*+shU3U7}`93*}r#QyO}A1VO;@<}`c+y^Xa_U>}E!Q{&|9^rafbWDp(XRK&Ev;aMZH z^qT()FXuUJ(XVBo1?ZsBi at lfZ?DlKgt=C+_J8KpKUrhCh&v>ukGx0laT(#-y8-Y~F z($V=j{&T~6o-x#b^!7M{ZgpsIMqTbpSJwIhJ$`NO5cToyo!2^qv at gL92SGvG*&$Tq zi^md~zL$^SEfiG~+u3%_#^vWk1SwCUgl at nk65Z-LwxLnX2HcgJop{&1Sg88&dzcFd zK>_2>DPhu#Vb!ul>K}Jc at jF8J682`4#906<`UX$%r>N!WJTE6$KY;BiljNrqb!vv> z&oi_+h$l*!3ZKxLz3Kyx&D+G9PP>XSjYNoUE}>}Ixlg9nP2W0*84Y~;@&(2)8TBL!;t=$`f;WHIVq~t*YwF6={BSk(*W!P_8gRZRqPvu6$IOmf1<;25)~}4TVb@!pzN#VXFGH2UX?^L(>l-xSPOJY9~lRj8fW8BZFxCIEE%;gP}vKY;a(j2 zMIqd}U!0sX!eTlwCZ}v;Al81~0E=8WofE6zi(V^%UXf7En#hMg(Bq>g%Flogv!EaQ zz<puAKCR)towARub;yoU{=UNSk6h_x?et9Oc%Kypn=S| z2T88KPv~}%@|?U@{WDWJN~tS{6V4YVbWaOOr{7Ym4SaAXI<1}`=JXowJsSARIp#7( ztS3C9XFxtS#9cRHo3Bzj?|hgRY3T z+O-#Ay#?;;tovT37C?>-$%8J38GNc22U)dS9a;M-=UDn_xJ&Gv=|aYHt77m2=R$`x zm5tiaEq0umZazVAzbEN~L}~}HkTEwOm}+g8|30aS+i1$yX~lf6*1k4Gb3|NzQvuDV zN_UoOqzh^ydLTmb!gd*N7_C<+TE4+qZUUhSWKF-tgTzdD#eClR20++;_wRA8J6Rpr zF^^235p`5w%Z}%)RIg8up323y0!?zdlh>ow)4Zq;b$m|Q97{8FYBN>#@sTa_sJG~ zu3O&(7n-{(N}s^4urcmNl}Cm)GpxqFH_k(YLHixU!+I94>_?^tirC~pKdUPu8*-b` zoaJFqK4b0;?Xa)b0;P}GCZN?Yc3NFzO}grE at oo8~C&Rus%T6 at e^#ZA3>WhM?JM6rWJLDK^aC_)#m3y$$S#-i1a>^(gnmogLqkfp{aKRX> z<<=ddhx6+Ub-t)IO7^KUaIKhl;c4)jXX|>82I at 7QdZ}`p=I(oD`@9S;ceU!yzKuC` zUg&`q4?TQW_!iGVJ|?T4z{QKz#<%D3hr_P7uBvB(#fP#7{>pi`mn at O_T>M3=|1RzM z;jcyi|13T7^T9loH}fc$e)#th7XLlGx$ggG4gANoK880tIv$S_E*L)y)!`dLe>gi5 zC)Vlr%6q*#g=g2~qQu4X&8KV~55}6-g%t-vLL3D6T`pte2t#`0~*?_((8Kn1;TK?ILVkyUlYqD zO)_cZ67xJTzO=z9zU;9!D>K^;0!n03G{fw+D>BpV*Zssk)uvd8+zM)9wV)P4Sla25_r7 zy0-H3juP=bpsQrRJ;hCqZDNBi7%-a$-jBGSiSK}Wh40C4KKMJ`jY~Z5qFUcRy678H zeygw&DR`47n@)S#L`!uZ-=b^cXFPY<@hWXcrKLSUb6<>a)poH5Z+x%j7kV-AOyRTs z7JI at 9bXb2Q=_Ib>^PFN$IToBPov^?hzPKOayOw_4$DUxTB-&*l<5Y=4_*+F`_Mt$4Tc)GPB}6 at jpz*tJ%@rWYD-=@ zQ%i4;Tk-$f&xDixA$8qv;@Yl zZMQx9g9kYuw!5zPhUjMWz5iSpBe`x?qY$Ej&(ZYS>>V^pkb(N5mX+$XFxsJtw`}_~ zclRS#b(s*T{zSZw#seA`9bS9$`vWmqmf)94rIm+Mwk3M&JK*s}yi8j<)%PF40J)ja z{3vt8Tb7*lhOQXwoO at -+;`=W26T2;(B)2MWB~#4Gm$jbR+$2A$+=XMxx+VY at HfH_V zxG4BOMqND at r#t-1>C(v1!ww}~n4A&-)}!`RK=yqTC; zdJNBnUk{Z5F2RG zk^K7*|G~;2 zB~g^){eO-G{ugjvJ&z9HbIeoyZZiB z)|I1`)ipEL0d)Vpc;4)@C) zo?!e&fUB-0^mK6!iDp02Z=|dh=`3(}SttxFc)V=k4Q2Lik(&AFcs0qJ!*FHt!{hPV zsmm^{=EehTPDbxI`5Q%uRSe5VK=Cu~WncFPiU74QGVDQ05tc`d6 zw;jbML@@YdxMd4VQ|k_RoJ<(v!n$p*hr6aCL|g{F9D#$=`EL0+T|PD|yI8(c2gVPT_kJ};#46>m#_{{^q;*sDdM&_C@|qj! zvOd#^z2xdE)@E8=KLg1`)qvM6fpGNj={DdVr1|NfL;9}8Xwm#~atKZTP|VWpV}k%} z?)$V(YMAQ}q4VpLDF0k{d#o9L2t8VIl}sYN`&&54UvF0@?)J$nQ>8IPCdb(Pv3-k% zX0tAw{zW0B;D6h~4qy*-e+j1DlGfa1yv+dXf-Lml``7?AO`bcNiDArVB$s3RNMRls zSq8M#)GgzhU?y!of2n!wR+?1v)RL;p<#h}Qf zMHIj~AGPj&$Ejd-K4*y8s5CfzQsSP|P(A9eqk`lq;_ at csAW<_Rd9bh4`bWlIy7IzWrk~ zH5h!{ZLG5U3bj3oRcnrGmFz!1_IeZs+!VuQJO{DxSr$3YYxe)hix!cqeSBn^RXK1 zgZb*_lJh#Q{O|MUSFPi|ri*CN|C;36_8&(yrr;GvhQ*V23EnAPTsCDNOe at G?lk?#) zOjkLxWa!^hNof_GqI$r0j02zJnp&!PNhvthm4A3MlPgv7YmHNWT4+P8w8VO;*6F8h zO3VW9!eXfg5R(*J1)}>u8pvtGX7>TKy&sHUhybT6Aj at tcuHQ at BS4~rZf>j^Iidg}ZfrgET^zv$ zRwD|>j${D;)O^6Z5^_zb%U~sm=HW^63Ku%Az-g2>x?lRZ=Cb>6#p6eP9^8E*y=%PQ zR7M6pW<4ED!_|3<0PnsG`p^+|y|r=u_6FU~k3jv0i+UR6glzt56WV-LeV1e>5mgOo zJ8$}$U+`HU0_PSS)7%DBbf#jOW_LX`5r5DMyM>&FOc?(ycGN`UJ?P(kIaaZv3>o6w z#-ktLkt!he{nf#XOcrz>56&dnE&#Io{P8~Xef_C6tIcA`)s!)1cc1Pz{I`ZEaoepPK}>czD at m8ZcS1}amoD?dy}JJt zZTe75EuDNIfP3YXEdS3&vaQbQR?;u->n;iIw6t~@Tgk!XD7gaqvn4bx&Po3XYft3!0E+ at tJK~Q3UuX7 zXFX_U{R`P=*AF-Tkuu({zx&s}n7GFst6c^Kqw!!EGb9h91tYpX-r^G~@RRf3$2Hwn zeO)X!iw82z++YXSv#JZFgBIX1Lo>j90N_IqHdX>Q}b)^ON9)e0|YQg>u8cXKE znl-03kh_e%)XwGPn+ at cd*N2Vox*~<{pB2z2;|_GT$OgeIma&7CzmFtfj-LR1aH4ur zgEEEZrbFY9*Cxy-`eWm3rn{GwqbP)?WS0QDY}fI&Y>1Z%?Ic2?tpf1}8o0aa9X5(O z6vcGrkEh(v(KcPz($8o71f>;t(5+6|4KM|l1{BVCGUg*wN0uRiQ-h{HP^#3^KP#(# zzB2_^s}f7uGE4qnA7{PjoFw+O!%u*h-W>+Uv&R2Pace^U_vH2etoA=C?y?x6vhM$~ zjj8IAlIMGQN}xJoSVO<;Cs;6d7*m2r{u3kR{?3yo+Two{zjs|gG-??JN at hgUx3lXd z1!iw9-kojsyLSHvU;G1K>as)Xi~k|)e+cUUZ{3__p<3IUlIC35fz>MdM1e9Ph=uvN z_o!2}6Y&1(0J847-i1V5?2ZBNf8J0x)?9GD;hWs0fu?F8O{$l`wM(vd=|1_!UyRJ> zYAwL;C-YH!5_dop;tnEmt%>Go%^*w>7qA3CKca at 8=Rijy$lDFx9h>5^lHy65f#Ml8BbU7`2k-KVBR`SE4lUd|`z9{yS#C3LYlN zQWH0F++buq0Av3lv%tH5%2WN01(K#`dL*N24*%BUe`}Zq@@adu9Cw|tYwkSog%GXd zy at m2@U^JaD`0mVDW^VVuX=u2{NpkPJXA1G>&aSI;USbM}<{vrC{V!SiDbaw|(^dXL z%Fvgtd@#d{)q4h$L&r9e>uSHqvHcSVT=1TqYW`W)O;>vs{4yT_UN}zW=SG(^ASpP|G+~N2WH at -r#~hA+FL~q#bse{R ze{*zYXqvWGe*~0mI>6>VuHeksbae+RWFflK0m17svY-cp!k)?XZx`%52#lS7BWR9J z{Zs(>=02~kwj=&(aG4r03M|8&B<=#tn>6-Dl%9~W!P$0Ei$v4KRC9d%zO9TZ|_6E+AjtMJyic&!v82* zR>sG92q~FvI}_=f&=*$Sj7`Dk_3B;m1f7(?enh{Wo!!4f#Kt`SJ~1c~y3%vSBX4$e z>1b{T7{B;YqYU_7TwlS2&Rm7~ybTIkNSdNu07`?(RJ*l?PM7VVp2yAGd?0(qh1BzR zL?AEZN(eP1F!cg@?_yRK9M%Lg+Pfub^H(f5%Dx02H(v_x#~z at e1|z^yw7$>TRcV3NMXKfq}g2cYRIw8mFzgjd^5PK-OZ{e#vPv1t0C*8_=S`Lp2F+d?~x zormtR(b^AzJAnUNE^i5;H0B$Qf?Yk(Xqkqz?OUuu+U1oY>f3;wmlY$oSmqJ=2oUux z!bBIfO%Nni&55=Q3QHawg^G6d{I^oO at HS?89Yxbw0LcMP18_5i?aXyDAIGZ7g-(|0 zjYnbFJfxg*q8kLI1kE70%d}0ceU4|9)=qa;z+Sdy2Q{v|@4K!*W}Az9Dcm2WCe^MRb_PjD5(}F7cvmwl|t5H=Ci&dzzGCM>N^j4TnpzT=v{ZLZW!we zQSSnd0ry?sl2bKL;Q at Z|guqs|1<>-$#|U~)^r^3j^1rY zr8^TrP_wOej8QrNeKK$&aB*baW*A2BkgJjjOyw6i04-P5fZc1#a=v&w+frwz%XIU0 z&!JX>E2}4tF1}ZX6j&Vp_l*6`HTG`k&f_{0z18(`uk42%@6A`;_)kVbpV4;$*1}VP z$-y*DMZ4c$8r(sBPX?P(mwd(n>$`u~f1kk>&(LAXcSg(UXFTqFS%CHWbLs9wDYCKg zkfwyZ7#8IE;$9Vcaj#vb>EEKVBRXN3*&THo at E6mgs#|;C6<>U4z~dM9ZR}}PnahNs zu_WC|nd_beCMQsqq=n}*q>N`lG#7wN0FRu#{#rR7_bbTkxR;=HQ4NV7(r-yYcv5u$ zD7lo&&*bSEmsjXM8EH6lRqCQc1O$}4+Xhu!c_QHZsFnX=t^zmw#u9Q&27zl|S04`D z=>4EgfVYtN4r&&(aKZYPi@;x+ZZsSET$;E-k$$>+-eACyZ{_DTB(0+r<3(#^}}es3>Gg z$fPIlHu(~^|MzKhigSd}Vw2{|35+sGo&jBDjVQQ)-||6k7jeI#dM$-f%Ol;x{;1Vk znBMlhjOWEBw%;IrR<^Qb#Gx9Eu;q1B5zny~#(CR7n!kqJ8ZGF+t{tU- zO2RkUe9%B{8H}nOW_xn7ADF43?MyzFwRzn6&F*@_6LtOdNbN_ zc)deRNHlZvX&|H9UhCGKfVgj{NCw>;-xM!hVE~WMiNpgJ5`-?ktWytM)6Zr=CO^D4 zY^^bZSB)Mv{`}0^oIrFkQ{p6^9MwS%%{(b+%AuR90kdd=^#Zu|d-c!&$x|f7oo5ns z#X2{H!RLHKqd6}|F&`@WhSv~ULCfVM at z38z^6FM>EcjQ*0eUqks=1D z#m}{WU`H3%U4E#%kRaJnG_4a^aj3M-&$+Ps at a^bHKt5j$*FvXpU{cOHeVfPGs=}3e zwIRg)SIFkRaXVdLvVVL>arMQ7|4V$Ur^5kq-DPW6?N_O5lK)P9VUZQJp&;?>N{WCH z&j9`Ij0e@~@0Z7ypJFWh1ko5j!ta@?AjN$c7*GEn=kWDz|7R}h|Gw3u0}C;B()Fgp zJ-ccA@^9~|gou>M&=l*XE56_v+e=2KS8QEmEMzpaOs6_8SBB<^ma5w`)n2E*NX5 at 1 zcuCX#mePO?V%jz)ezM>IA!d;x%?u5<(mp>zH at wB&?3KyqzAM;C_nbr{zosDV#C4KQMkO1cxVgK;A)`(W_t>0}a*%298 zm_td0cUHLj*-PiLHx+yTBrQzdvs^E2u5IU1S)JLL-FsQs6>@bNBT(P2xib%S+Y@=0 zn3w!+!G9^LjjLumr46SjHS;VgyLY*phEkphfkphrb!-1N at b+~F18Y8?@K?JqT`3Ah zdT~89SO`Zy;(>l>73pDh>Q4K<%byr`cCP$I0GTD>E;4CWV&c3I^F`6Lo_+2D2CS8G zsr6^H!fcv1EJi?AX5(x}Sk0}OuUE!~@+LA{KA|W`YlqJx#8P at +l`*hk{pEVJCm>2| zrg0 at 5!u(>uef6Oz!P;5+6{kOl^|q!Xp~p?+P2UCD1Eq{72t>bH0rj343D+3TI~=T% z*bL>bJM>RhE0yb;hxrZ@*9^}~zAkHKtg!=G-zsM at d$dy|XU`W!hy^+Gyl>BrHyQ^P zd>KQ}eEkYDE&pU%PM4)EZb|KEVSVZo(EZ6Y`uF;SZM~~*@&=L^TYj1n&&=%i+)O*; z=m)8qK^*jkz->lUxz6!I1$Ph1QM~+RV;Scc?`bEKZc(v3Wae+z+S=8OT#5wiO{-m= zs;o7nmhG?0ysGl}ScKk-z>oOrt5 at 5o!tS3B%25l=WkU|dya+M&hXFoqCl~X`H*;AM zr at HyKLQS?3-BEC~lwg%K`e>+bGkIY%{(VbOJ!|Hnw(gpo(G4a6Z&A2TP-s}AQ zyFXFp*B60 z*ML;yLKUVHj2}Fib0lji{yvbZg|zbM!qv?SR;*GSR}6v+PI;X5(WXJ$WlRg_*G65!SPt#lcqFVj9s|Hh(l& z)SFo_wL*7i-C*I1{J~SMAhL54YKWYI4ml)($eS4+P^94$^UFFijezVqI>?5)GEpg? z?PTR6J-;SAghTLJm$_NU3YqbEPu2NT16*!ViQrH4AUyw;-CorpM^a1BLS-&Cawh&$ zX?g##yKi2?HH7E)%jEx1^>5u->*;k;b`z&tF1p6r*_^yntL2zu{w7V8 zn>=oSIaT#F)r-e3ORB+Z@)vQ52?+^_+&Mt)hwrBa1qXMt=-F5!&jT5~KnVU{URXQt z$31AUNCC!DeJaloMEP?}aX*%u>EKgGjP0;OniX^0mXV#<{hRt7$i_0y~rv#4I>N7tDtW&Ro=9Kq;Y}?{^%&Ns_I+4Rky<) zl4-x?jGHX_fg!@3`##3l;vj;dYoENZR zc?Kx?`JVA?V+nqI;$oNhv<&ThC~^aG=Bb{L*&1BTtm5HcwdAnQBwt8%7-7G zB6*Y8>JbKq!*}vl2Kj8DZ|^%Pyq?&!^N!w-Bg(<}g1j^iHXIpXz^oJ?pNIe8wOhU> zrZff;==c03c>)1?35m~WD)rv0uc-NxU0&|zpm*F-J1v>P8_Ji&+76~uuB^sd7Sl+~ zSP>+R0l8uKgw!VW9{_2&p{qScsB!@{;;o42W>^)Y$b04UY!&0PsHeU at oVj3805{!^ ztZ&k at L>w3O4bZPu3g_{sqmD9w>-~`rOAauSdP?cgRgxuE-w31FF9FIQ{cyrauOeTQ zh1ED}-H7EWHK#aV+~PYtCYw8-h1{=&Rus_5grL%*cULwRqEp*&4&=q}8 at KSI3Fb?% z#Pq5v)aZy6`h6N4ERRS&5bWs}`3c7EQCw=t_vQQ61__L&lJ5tKlVDbOv3{@f z%M_;}&1)p21wSbaK7WBQFddg4O_RzxjVC{Nxcqf~9acVM1`(f(gayc}fD3+TOH&TH z*pluzMk*fORN6>BlPX8vQd#^%$Z$7q{Vd3H7=k&*yp=CBcH_9-dfiQr(G~;xk-B^{ z?uHa1bQyaw=KeXuU?}|#|K11Oc(YHl$m at 5l>XPt~=;~4UzAF?gTzTHRfmYq1^Zp%o zes~mc*kdToAsms1E7Qe(oVpVRv{^xE=iCKgZEUg+v zMdRYbzqg zzozXn%d-h}J|r$A{wcpBs{&9ra}Xx7`L6PcDzJpe2jYdB*8F=0*~-?N)yJwM6wR68 z2Rb;0gxh3TskC={P>q4^7^k)s7kFvOrLV at +8dgq^@CId9^;bc)>g3oDZ+Ameu(uyh z_IEnoPMY8>UHAc0E~|aO?&}&xKM7=5o(vI1L?&#=D`n&7lyYW&Ir{Y9xow7x)Lw+16SM?%3S at KbBR5P0ns1m+);Lp~R>Yd;y_{&C()G$3 at yd6G z7Q<+sWZIlZ#V1DS=&oOd4MjN1SbuvLc7Sq1U0twi5LrZ95ByXSY-LT1?qI3l1nhT! zUq8k4WTaci$2J$1rl>nHqyx$8u<$rCyQ^sNOxcj5n4z{+y?A|_tnf$*s!oXi&eC4LC+}|;O<07dV-g`f!L?u5|8%;lN<VyfbB}H|kX&@s z^=xd=#k%~qWWV`rGc!=u<67&R4C#<#pKpRAq_eAtfTe}R(SX|4Kb3r52?Wm_mis*+ z-zVPZtxo!Pc}+-5y4C#2Kc}>mAv^u#>V=q9jm+nBELr9*k2#TGC2rVm1l&eZ4CH7% z?>v#=ba?-#UwQxjw(P!DQcD$m6V!~PF|7&AM~Dh5n;gtGwciJ5FHrsnc(oZ0!o~Nd zR1K9mMPL5%cFV0>y1D+iSlsR^sKpt3+hDw5HYc(@zjV3%nTaRYnvHz(jdT<1K+mYH zVVYF8Sz5$G^JjCB{POkTAba|j at uR1L3q>-akpfIFwAx7T-O&(HTuN|KJppo#7{RUK z+2zo#oFgsY_!aS)p!_7PK2xFW;^xVhB)v3FOr3+2WZ4gc>o_yjk at 4s_daPzpnX{#o z0EMz at x{mwbI=cQ=U1Jp9gafuu z7bNIqM=Nwxb9k{Y7GYoiiu9d#)b@)cIi&1jmRaqoXu4_g5Ru+jiO{Q3&miwtMuBSi zBk%W?^?D|csU+IogCe@}zamF`r0fEcwiEWBoHL!H@%WYBxI5?YNTw6LyGVSFAxZ?m zUSrtOJmxU;AX>Dx0X+kcDC3M$6Yb{U&)iR!q8}ql7F4rH8OM4pjzOU1qWw}CnjumQ z?xM_=8bNeCt>Uo}UVN+4`RGtJ=8U`h+3|v?8*Lb%C1N;XO|23q1wP11JY4oVOp;`) z1HgdPuJoWu6sdR9!WRA9VUZKva$qJMi5rO=(SbIZQ%7It)N?u)M}lN}6a`rr`icoV z%-M;c?@)d8BURoc6Y&bYqdYo^E~GZwHIemo;7dkN&&;0F58!dB;VM3g#tm8>&Y%xo z=KSpk7rj#6*TG896o&(x`p#cJSN%su%mvfHqc^7%IPUhuwZdGk;kocoP5s3C<3)XG z?A1&3wAt#C>m|(*dzwSiBbicA}S)@$a-pRK%x~PV--G-Cv-%9G&R((ya(;eK4Sh0ITjbh(#A&C4 z<;>Lox>C5Cn<+yn!Vkd#_#;8lWY?p2)EGsr+#ytubJ)X#zrR6+ciFh!+OH&(5Qg(A ztKJa_C>H|1Kc`kFYlkjn6JJJwUeS%={dhYBwGuhF{yl8SpIm+xCLPK|(v8|bEY ztl<^UAX{cx at _rBVPeW3CY4&%~$VvJLv9soVn!xrP=UCbgd?Aso$uA=MUZIjf4`|+P zd06$v!t}VDba}xow4>HAXN)i?;K|jQgl!xxOJ60>)xK50z#;4w)bTEee}3VMAcY)9 z&|R4isV)B?HbvqjsPCeV^146FSX`+tP`pl|tWN^4 zwzk6JiE0MmhBMnCUt)JMBDAV8V%

cf7< ztLMSTE(o}Tv}_4KUC;lxaSTso&(mnTvK-IgD|)S at k=gp^nJTs%)yZ^!e{wZ)WlBdHIC^ zw}|n|c^{|JDko`z2-0K*%8?es<9(2SA>~S!uopHm>embz0mNA;A}pYQ3-N~@rcPVi z6)#i%q1zE89q-{mD3pkOcYIiec+O{sB*|6k at gPU_glI+6{Bn_BH~vv=VrNVlSX2>{ zX7{pq+i)4%N2gGqoi;k=S)j7bUuS;U8fHQu0oJN-7cTY(^qgc0y=Xbx>r^Pp at 7`+Z zwtwnvAwgJDfy?Sm+~o-y+5M9DpscW`!v1rGxmxG%=Zs>iG!ff2w&$?cAuqzTNhz)O zM(C at gzp@d at u#~&u74$xRQ9G4TzFJUqGRtRT>R at V%LPs(kjV<&K_Uw>%dawE%FZ3}( z!#*VB89}ZUzdg}V%j_+E3Lh`h+r}X*{th01BUdFGa_z>+VIM*)I81kI)?Udw`0R5` z+g^aK8H>AHuS}XR<#(S3r^$J%!gY#DevsizVqwhL9l^hyzEo#CB`B8?jUm*GZ-+$61nBn6Z98l{I3r at r(DWxfe64Eql?=-d0`>?b89f^KT4N%fy4O{Ed# z6 at iz$7+wU`%thFjE?&7W0TdfYiPm4v|5}bKh}2(7{~cAruYd7_p^9OSIEp*8ly@{PuwKMXq`IWp(=C)4Wr%^*-_E2^ zObg7H`##tzs!zR{H=#uQUoRasAZo~u;Q;Q~MW{!F^yx}cv_Y_lf;_3d$Z|VIit;*j zxyh+umUE!cD^qdwW_uN6<-L&0!Se+Q;rIVMBYneH%n1J|7Q*ezNx~Da5&~|*+nb8l zkz(k~4LYr(4Abm at eCo5yHvT4BztXJ`Y79ixzt<+kakQD{<+Uz~}KmrpL{jG58qYI!kCq{)xxjP)39jn}y&#}zhGhixai2d$(j;S0x0 zT>l(A&j#EQB3tm*S*6%scm)aq5{mIEgEVkB-9*VOb7rxCr`rdBS&Nb{JBk#I`c8Pj zG%C!Z&a+s9>_V&_qa_(h at 7sLN5=U2TP8R*m;R)Sbmuf4WPQR;+K;s at y10Vj9N^#*h zGV{upm2cG!Xs&x{zLGV~<%llH6kvRGD-w>0Z&_?8ae66Os*7M=$UppW+8Jw*au@~8 zuQ1*ecD^aPB_?d^*2a)#_71*D9dZMId*hdAc{3N+cDkLt&GJQ^tNu>5-RM;cKB^g9 z9pbPtW03>gF at +Fl#saadGY z at 5!#qum?OVc#abZ`9NA(Q(w7^MST?0^t)5UC}p}wEa)@skjN at C)^36UCjYv5C`rIm zc2c5KWuD*g_UYsYz~6fVGpq{&ISBwi-cMY~g>id6HJXA?^6b~Rga{u^7jniI;3vwu z7vUWvgx5GjC5L}u<7?W1(vJ3`IX%?syEQ$&2HJOS2ooRJMEayAAG(Qm at Mh_}_1RUT zhG6rAs+!K(h|^cKEap6SdXkF_hB!0*l_&M~VIBOwUUv-JKM3q)ak0uOrv=Y!$QeaY z8bMiU)J?s=7b+?O`K=4PC%{!rCylf|6;G~m}R>$|mR zxkJa5acVN19j8}<-uGe~OJV*L>qh_z^8)?BgHFx}IZK6^>w{~}yH_3o-H{eQON4c6 zCtT*Ui|b>_So)qzA%z6}lUGET|4{yz(Lo+gU#&+dgoSHA+3jYNX)#XjV0k8wp*jKT zTo3dqve|eFan$UGd>nCd=SbF5#Xg&8v`;1>Y+ua~BW>fB_4?a*Gu%HH{$V-L4X@!v zCW0}JZ{f|@2j;}**5>|%j4)uKBe&2gfy#Ima at tZ+hPxNc>*`3(j8v424ie2W=B1=- zRGe2hp_cnzNVdZg_XV_f;Dkoh#DNQo-pyA|QC;9|U9K at IcDr|)a;?$WDB)*bWSLj+ z at chV$_(ibv*XlQ2Uj05a)aSGp6;vO_))UPopPUqU5V;k{w z*k3x at Uobvn1Sq7xZpMEw%R2WONQQTdTXUp}QE9D4nJzWu7DIfE$$w({I?)_}B^wj0 zGiP10A<!e_Zk$OSwv907z_<(RAbxT7 at _QQ1 z>6tL62)QcX&Goq91b<8mQ?0hnUVE&rx$|`K?P!z_gD`!6pP$rD z#HES2Ay)G$+G_IwGPM)Tzw}mw8Pf1-KKZinNc_;+NrF9#@PS{IxmQY6qX~=6lwd#@ ze3LBFBo2B-_3ngUk~w9B;r7(fPYw)G>_6Jyxo|h$=nb zy at eOO!~b-vB3-Y43w(v?A##xCJFO~sSxeJS^)Tbcd`=Hpj;AKXY%K~eX0a1_<5w!q zcvc+=a|~2Xsg}}DDZjxxS&^sGUQg77c9W=odO~&=6{u!^U1%mXt_-A%(r+G+gI z6AeO2_`VMM>uMPKok!bLiej{4V(Hc9tKEXuhcjg`gS#wgu%K;`&Mhl_`?o|_%7Mqu zl8UErJZcoLFV0aUTw at wR$A%Mzh at 2!5qyufX2R8pSKc%D4?fn;agOL{q+Xxeh6`Sg{ z4mi_FNUN53?(Pi#$$DaP{j(d!Xg1L#G3_D?H=AqFIV^hrCRUh9+|~1!`jUS({K5b1&UC7z(q zg4sZQCYu1MM6Gu!7bFVl;nfds%Vqb4PCyUc1lV(H3=hIBSi*LVnSN-iq?3=`DpxBH zdM~b6YIJ646%>X5Ue;(E*tbcHAjo1DMbkg!w z6HPomc;VI7ZV`R^P9Vp!M@^OFgdD!%IVGs=Q=B=yj z&oElk<@7i+j?Y>oWTWmU6 at 3vtO;t9w&6o#ZpHuc+O*v`#&Hbsdw$P(6-%o5OQJjRczati1WZhh0iO at RJ)$u^VN}nbP zf_q{b(0ya{TEAiH{)Fut3w_v(c?=u-v-gf~T}tDA)+o04?I%9~2{KIhRMS_+M-&M+ zy|E|VNsO{gmJ(FBb~76d2!O{%r5|Mi*vUliv}3~D$?_swle$_*5>BvK)V6eZFZdMF z+i^e5uh at aKA;XpBy9e8sj3xwIq{p9IngP};%hde-^%=X~>dPWSjbcUyregiKW^Pe` ze6^3Ll)9iqY)JhWpYx&CRU-R^`CI+jFBK8 zPes2=Tsui~WvrDymXb3`O2{=4Nwz-QM=Jl?aA({A7mY+|#~E)m@=H0EpRQ{3%dDZZ zby+o`z#=QVdSyO#@C+$&yPe$@nOULf=0d#5p!LmiCzW9J>u;7T)2~e?>l2O3<>hHX9 zMVxZq9-iwwl)(2384txVL8nzt4ZH5p&1u>P)_N;@KL(yokEX8We&?LjI%_Hr at C z3bCdZcFH|Sn8PE|Xg!C*Pdk;=h)M>pG(_cxoDG8p&-L~l+QIN at MKpV+%SH0u1 at Nzx zS*y9mZzh;3raAK^6)8R6hQ`hf4aS2w6CWb}Xz^!Z6r zMk_U8ShdwoUet8Xb?x~IB@%(8R&sJy=_|94P9~tX$Gf2FE0-}8>DhZwpT9amH- z8+tNb=^ZpOQwFHhvW-cMt*W at RV1m6*c&`-=;vQeE6*h2rPM6zTbc2;Axfa|sTfu6e z3Fr(FV7psgpgV2BRrYXj_(?|dlRio;HjltxZggme`c17qDLz?IJw;sT?-|l}DKli> z;7`)U`C7}o!!0?l!;I>kXe5pZJvTduTbab_ at PvDM-e2d+grL7PgnbW7nY#S;PAbJQ z|Ae@&i70llWZUegF2pa_IDQ|uZr+nPv`R&hx at D89XPYA$gDWnZS*f_SUe#qjTFyLg z(?t0%fze&(;tST9aoYH_ff>LWTIh4*lgdipd|9UXZqDf89p+X}-Iobzhg zblc!>rA;Gf=%AL8LyhzBl8*#TdzgVfw)+WeX3ayRtH#)O{3<_SNj_qEzV4k?W89&G@>b zj?Vq_uEh^ggMp6KjSy0FFRG+Vr at C~CZ*L^fKFvPre4P20-EIF%GHGADZ;y=T$HQE9 z?AJ)Z{l5eBcvGr3xdy#`;EEkJ$>lx3%l%J5tn&%??oaQZ#&E;F%OzJYG)@uMRp|3q z7527EP+kGk53BMD6Ps-5l^iQw1R|<&sTyT?ZMuvWbx0c13I6z zv-?n&Fy`z at Jj@fzM*3FHC!JCekgkc9^B5cRGyWz at dc=3P{e3tz7+%58f3>R2lDcka z5E14^S>pcurD^txXVRm8$8Frl`i70J2&Yyyf?l!1_OgGbRW4>R$JR50uyc&NJYr3z z8zpE6rkl;A#*>6fu-GeosD$JjW9n#H$B&YksT}0WC64{JT at NvQg&dpOQQAGEImdIM zZYI7$ysZft+~BK_BVN4-dzPiP>kJRatRx0OFSY^3 at XTTEhWG9XwX88*dO23yn;f;$4*0*^;4mugq?GquPiFaKq zC~Mor7|}PQ17;htS-!Zwq^E>|oS$YHJ1>4$z>SPK6t<=2KoF|W at 60c1e8KKcGBlX- zn<}R$-J6px6ME)9ph}~eDz#JaHYhh43Z$bDyeb_h#Tz$9-^k-j0Im5`nT-}TUvsJX z!M}{BNy9w9?Y?h8h0fajiXA3=8nXVySSNrznx-QccSwb at fThMKH9L4orWBwb;>K9x z3H|{nKs(m2$-yCN{T_pj1A~)}vRUuWf at IA6&OBQHNRzp<&)kZ%`#aa;X_&tg{yv`D z*We!H>tjB|0z0!${K2i)S- at m>!bpAJjJ_9SbDfCgy>4jKo`X ziRSZno1P8}N$$R;ua#qpgXz#eDck)kh#-&$Zc7^Wx&6NyF_S3iS=ZK^`K#Ht+|RDd zLFl&jt&prC^>~Jefrn>?nK}(|r9xXGT(6Qdf at MRzV;ufkdF3n2-fvuM at eUetApOvg zq~sr+kbp*jDEZqVeFNo{;x1QO>;&4*=9+lH0OI(tuc2 at 8fPbl~Nqeot%5{nlRce3Q zG3LG9xS=4#`t>ne at 95?2MPz6DllXk!DrP>R`nCDwN2=QO_*9VgXXB at Vn)T^V+N_3M zYD_b+o47IqmjkPy9cy!w1R7+o!UQwJq^j3IpH9M${rwKOUnxA>%dxEE{c(urWIGSp z?Y(6uj-2T=VS*G+f={-O?7X>2Cp(&3a(#LDsIJxpmrL*3&QCP{o@^O#mfR zy;dhvJWKT)eeu(xnFYb}HqeTwcev+_wb5HqUqK#|qSPo5_Fk!cBzdwxvh zfZHzz_Gcb7;*A~3io=zhArge!`xI at 3+2ShBE63@60%@gpJOEFeEDsA6W`7^O`Y<;O zNga~MXLF&C=Y9hb->I3#PXECaa5F8IqQZ{pt!qVIrQB4WvS<)XnApp`bTltHnD->XJyw^i4>_E9N; z8 at CU$_YQOfs4opXFw+5+E3TGGH$2fP^)?IWuePd5E2|&JEoD&oxxKp6GOnH`9!E0z68IY%ivwcx3`cOsC$_&b|mo4Tke%aBONxRh& zyB-eKJMfQ*k(ab3U^YzoB0aBIMj$=9MHk*HlzQ@&ttcsN4HDF)fJ~neY#)H<+LM1FaUXee^<5w1QT-A!!8IL*9ecxp(B at _g zXKvj0b%Azv!6QB)oQI|))YE&OuK>Qc`*4H2xUjwbZwxBg%706pUWq0}>wTXOQgGR% zvW3-0N$|=#yR%mJ?#E=*K6*F*ba1G>0l2(b$r3gD7V<|O^KIkfBuXqQbP;y!{st9_ zyJ+tiUH!J59MD%q&V+9Q{E+F!7jd5&V=e6TD>t-~>g(JSJE0Ze;WRJ-_5_t at 1|tC2 z*OV!{Ysbv_=j0Fcx2MVc$BV72z%|Un3R^)tc$_QNGzv^_M(QhJcGSU)k+~Y!O7q8> zrJj=J6*$^!BltJ>K&P)@HqUu<@OVacqaR0yBJNIxX(>{(%Qj6pi(YB`1dWAVV zjA at 22&L-;+B{jwvr(tG{sTm?m=c06Etcod<$~h~9a#$gU4p at h{F+w1z9C2N6s7%ZN71;MMWys!Ck*u_P1tT at eg&5M}Ph-$~l2o zvAuXuSvmzl>YD9YUS0V-hHy#tT5B%rQ+fRW;nj(RRo^x3;eE7FeRz6Ot*6t0ckBAo zt)sgV#+&T;`#nK z!I9g|n{yQKiZX)Yhmpekjj=^rN|Y+Fd@|~p|6o{8{B(`wm7}72FCns~zq?x;KQN$Q zSe&h%`Y?$s()Q!OYz<zWuoD!z4Yi6!|nVol1?fBmI>9u#? z7omP{yjC}JXH{+Uq$s*yk33!PQ9gblC-VP)xb{cU%I;)!K6kTlQbGc)9O$-#vxDS_ zqcTI_6knzf4bBT$cwrxJ#$!>abQ%ZZL-P-05TGM>??EAfz67X;Aqh!hS<(UmZ6nw; z*NAOy)CfAF2Dud_Y#0^4d914UN63ht0 at d(h*eR1OP{4 at dz`HXPr1gQD^f{-1g zA0U=YHVt9`N5QB_i~+>J2#z*Jn;0AELtH5wh&_b?K^sHRNTm1!jYFYu1}Mnl1vQls zkML|?Kb#BEdT~whHv%+(!(rhN2rick=VIVYwm$-8Vq$_oq7i5`OiaMS!WkS255@@7 zT4?fTA0jP`$_`|40+|fRd|!$Wb1#Pgh0ZUubS>T-g|)O0BWzKiSS5l-VIfd(Bx0$v zxDYR%#96Xw6b_T^#$*PYF5JF#Ae+Wzvgu(EOIHkjzVa{7msP*i(})xf%~b3I3qu;i zkS1SxCkJ*pe|4sAOnD4FkPT7Kn4K8V7fqEfD8bF z!E}MT02u%TgXscw0Wtsx2Ga%V0%QOX45kaz1;_v(7)%$a3y=XoFqke-7a#+GU@%>v zEH=f{5DcaZ)CI@@AQ(&+s0)w* zKromtP!}KrfM76Ppe{fL0Ks6oKwW?g0D}K9T{2%zde9i+;~iY_ISzA)aeWC1DYhNa z+|Bm*+cr{w*LIcrW1`~8MjJovbNsqZ{A=IX9lhutyRTnOLnd~`jm}J&Co+eFRs{`0 zb=}iW!c{W!3Un at dJ3LnHJp6ru>XtcqgHj5O z1*^^p*139G+Z1+RF6j$@ZaAun?ZeF|tVXT7E~(`J}m!PUHi(bLVYHpHmNNw4(m+GU$~y|xo`?53n(s}vEo zYx%^5-q8TFsG&U&4Th$zV~1sK>$nYn%$# zNFLF{^d>kqmSK6i>=H&hc3U*H{a%H#0{X%xix7vTxps#DQ96sK_^6JHe08wEyc^i2C7d^jVC%v8nX^$$MA&8Z_^|9t;u& zpOun~U#C^Jx5~%ydY7!Nx?TjxiZa%w1{3A%W3IGL?QX<(kI55a;sa=T>GVUx8p&{N6NB<|O~VHE zn~7UDAGEwtlHK)l%Am`QxO^#R`QF`Tb|p#GF5g`qYXTO9gh=9nUbHHm3e-v z-(R7mIdOaQIRAz1OoX8vcWl?QsG47ozv`t6Ry!HNp+phnk6J~5%LO^CC0 z7i$r2)^U`PidPeQBG}x95wdK3Bl*%s|1)pr5`tMXhQrc_yRIszT*xQodF#+ZWH!$T z@>BZq-Um%J@;(f&jOicy=n+#?_PWJdvy~ov-RNURprXHv3boVas%CI~&!^WD~4K#J!RyhDhQ39}w7CZ6jt|c*p($EuLSu literal 0 HcmV?d00001 diff --git a/wui/src/public/javascripts/jquery.jgrowl.js b/wui/src/public/javascripts/jquery.jgrowl.js new file mode 100644 index 0000000..b803de8 --- /dev/null +++ b/wui/src/public/javascripts/jquery.jgrowl.js @@ -0,0 +1,204 @@ +/** + * jGrowl 1.1.0 + * + * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) + * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. + * + * Written by Stan Lemon + * Last updated: 2008.06.13 + * + * jGrowl is a jQuery plugin implementing unobtrusive userland notifications. These + * notifications function similarly to the Growl Framework available for + * Mac OS X (http://growl.info). + * + * Changes in 1.1.0 + * - Multiple container and instances. + * - Standard $.jGrowl() now wraps $.fn.jGrowl() by first establishing a generic jGrowl container. + * - Instance methods of a jGrowl container can be called by $.fn.jGrowl(methodName) + * - Added glue preferenced, which allows notifications to be inserted before or after nodes in the container + * - Added new log callback which is called before anything is done for the notification + * - Corner's attribute are now applied on an individual notification basis. + * + * Changes in 1.0.4 + * - Various CSS fixes so that jGrowl renders correctly in IE6. + * + * Changes in 1.0.3 + * - Fixed bug with options persisting across notifications + * - Fixed theme application bug + * - Simplified some selectors and manipulations. + * - Added beforeOpen and beforeClose callbacks + * - Reorganized some lines of code to be more readable + * - Removed unnecessary this.defaults context + * - If corners plugin is present, it's now customizable. + * - Customizable open animation. + * - Customizable close animation. + * - Customizable animation easing. + * - Added customizable positioning (top-left, top-right, bottom-left, bottom-right, center) + * + * Changes in 1.0.2 + * - All CSS styling is now external. + * - Added a theme parameter which specifies a secondary class for styling, such + * that notifications can be customized in appearance on a per message basis. + * - Notification life span is now customizable on a per message basis. + * - Added the ability to disable the global closer, enabled by default. + * - Added callbacks for when a notification is opened or closed. + * - Added callback for the global closer. + * - Customizable animation speed. + * - jGrowl now set itself up and tears itself down. + * + * Changes in 1.0.1: + * - Removed dependency on metadata plugin in favor of .data() + * - Namespaced all events + * + * @todo Group by header. + */ +(function($) { + + /** jGrowl Wrapper - Establish a base jGrowl Container for compatibility with older releases. **/ + $.jGrowl = function( m , o ) { + // To maintain compatibility with older version that only supported one instance we'll create the base container. + if ( $('#jGrowl').size() == 0 ) $('

').addClass($.jGrowl.defaults.position).appendTo('body'); + // Create a notification on the container. + $('#jGrowl').jGrowl(m,o); + }; + + + /** Raise jGrowl Notification on a jGrowl Container **/ + $.fn.jGrowl = function( m , o ) { + if ( $.isFunction(this.each) ) { + var args = arguments; + + return this.each(function() { + var self = this; + + /** Create a jGrowl Instance on the Container if it does not exist **/ + if ( $(this).data('jGrowl.instance') == undefined ) { + $(this).data('jGrowl.instance', new $.fn.jGrowl()); + $(this).data('jGrowl.instance').startup( this ); + } + + /** Optionally call jGrowl instance methods, or just raise a normal notification **/ + if ( $.isFunction($(this).data('jGrowl.instance')[m]) ) { + $(this).data('jGrowl.instance')[m].apply( $(this).data('jGrowl.instance') , $.makeArray(args).slice(1) ); + } else { + $(this).data('jGrowl.instance').notification( m , o ); + } + }); + }; + }; + + $.extend( $.fn.jGrowl.prototype , { + + /** Default JGrowl Settings **/ + defaults: { + header: '', + sticky: false, + position: 'center', + glue: 'after', + theme: 'default', + corners: '10px', + check: 500, + life: 10000, + speed: 'normal', + easing: 'swing', + closer: true, + log: function(e,m,o) {}, + beforeOpen: function(e,m,o) {}, + open: function(e,m,o) {}, + beforeClose: function(e,m,o) {}, + close: function(e,m,o) {}, + animateOpen: { + opacity: 'show' + }, + animateClose: { + opacity: 'hide' + } + }, + + /** jGrowl Container Node **/ + element: null, + + /** Interval Function **/ + interval: null, + + /** Create a Notification **/ + notification: function( message , o ) { + var self = this; + var o = $.extend({}, this.defaults, o); + + o.log.apply( this.element , [this.element,message,o] ); + + var notification = $('
×
' + o.header + '
' + message + '
') + .data("jGrowl", o).addClass(o.theme).children('div.close').bind("click.jGrowl", function() { + $(this).unbind('click.jGrowl').parent().trigger('jGrowl.beforeClose').animate(o.animateClose, o.speed, o.easing, function() { + $(this).trigger('jGrowl.close').remove(); + }); + }).parent(); + + ( o.glue == 'after' ) ? $('div.jGrowl-notification:last', this.element).after(notification) : $('div.jGrowl-notification:first', this.element).before(notification); + + /** Notification Actions **/ + $(notification).bind("mouseover.jGrowl", function() { + $(this).data("jGrowl").pause = true; + }).bind("mouseout.jGrowl", function() { + $(this).data("jGrowl").pause = false; + }).bind('jGrowl.beforeOpen', function() { + o.beforeOpen.apply( self.element , [self.element,message,o] ); + }).bind('jGrowl.open', function() { + o.open.apply( self.element , [self.element,message,o] ); + }).bind('jGrowl.beforeClose', function() { + o.beforeClose.apply( self.element , [self.element,message,o] ); + }).bind('jGrowl.close', function() { + o.close.apply( self.element , [self.element,message,o] ); + }).trigger('jGrowl.beforeOpen').animate(o.animateOpen, o.speed, o.easing, function() { + $(this).data("jGrowl").created = new Date(); + }).trigger('jGrowl.open'); + + /** Optional Corners Plugin **/ + if ( $.fn.corner != undefined ) $(notification).corner( o.corners ); + + /** Add a Global Closer if more than one notification exists **/ + if ( $('div.jGrowl-notification:parent', this.element).size() > 1 && $('div.jGrowl-closer', this.element).size() == 0 && this.defaults.closer != false ) { + $('
[ close all ]
').addClass(this.defaults.theme).appendTo(this.element).animate(this.defaults.animateOpen, this.defaults.speed, this.defaults.easing).bind("click.jGrowl", function() { + $(this).siblings().children('div.close').trigger("click.jGrowl"); + + if ( $.isFunction( self.defaults.closer ) ) self.defaults.closer.apply( $(this).parent()[0] , [$(this).parent()[0]] ); + }); + }; + }, + + /** Update the jGrowl Container, removing old jGrowl notifications **/ + update: function() { + $(this.element).find('div.jGrowl-notification:parent').each( function() { + if ( $(this).data("jGrowl") != undefined && $(this).data("jGrowl").created != undefined && ($(this).data("jGrowl").created.getTime() + $(this).data("jGrowl").life) < (new Date()).getTime() && $(this).data("jGrowl").sticky != true && + ($(this).data("jGrowl").pause == undefined || $(this).data("jGrowl").pause != true) ) { + $(this).children('div.close').trigger('click.jGrowl'); + } + }); + + if ( $(this.element).find('div.jGrowl-notification:parent').size() < 2 ) { + $(this.element).find('div.jGrowl-closer').animate(this.defaults.animateClose, this.defaults.speed, this.defaults.easing, function() { + $(this).remove(); + }); + }; + }, + + /** Setup the jGrowl Notification Container **/ + startup: function(e) { + this.element = $(e).addClass('jGrowl').append('
'); + this.interval = setInterval( function() { jQuery(e).data('jGrowl.instance').update(); }, this.defaults.check); + + if ($.browser.msie && parseInt($.browser.version) < 7) $(this.element).addClass('ie6'); + }, + + /** Shutdown jGrowl, removing it and clearing the interval **/ + shutdown: function() { + $(this.element).removeClass('jGrowl').find('div.jGrowl-notification').remove(); + clearInterval( this.interval ); + } + }); + + /** Reference the Defaults Object for compatibility with older versions of jGrowl **/ + $.jGrowl.defaults = $.fn.jGrowl.prototype.defaults; + +})(jQuery); \ No newline at end of file diff --git a/wui/src/public/javascripts/ovirt.js b/wui/src/public/javascripts/ovirt.js index e0aa222..829738f 100644 --- a/wui/src/public/javascripts/ovirt.js +++ b/wui/src/public/javascripts/ovirt.js @@ -21,7 +21,7 @@ function get_selected_checkboxes(formid) function validate_selected(selected_array, name) { if (selected_array.length == 0) { - alert("Please select at least one " + name + " to continue") + $.jGrowl("Please select at least one " + name + " to continue") return false } else { return true @@ -43,7 +43,7 @@ function add_hosts(url) $('.tab_nav li.current a').click() } if (data.alert) { - alert(data.alert); + $.jGrowl(data.alert); } }, 'json'); } @@ -63,7 +63,7 @@ function add_storage(url) $('.tab_nav li.current a').click() } if (data.alert) { - alert(data.alert); + $.jGrowl(data.alert); } }, 'json'); } @@ -86,7 +86,7 @@ function ajax_validation(response, status) } } if (response.alert) { - alert(response.alert) + $.jGrowl(response.alert) } } } diff --git a/wui/src/public/stylesheets/jquery.jgrowl.css b/wui/src/public/stylesheets/jquery.jgrowl.css new file mode 100644 index 0000000..7f558f1 --- /dev/null +++ b/wui/src/public/stylesheets/jquery.jgrowl.css @@ -0,0 +1,125 @@ + +div.jGrowl { + padding: 10px; + z-index: 9999; +} + +/** Special IE6 Style Positioning **/ +div.ie6 { + position: absolute; +} + +div.ie6.top-right { + right: auto; + bottom: auto; + left: expression( ( 0 - jGrowl.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' ); + top: expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' ); +} + +div.ie6.top-left { + left: expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' ); + top: expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' ); +} + +div.ie6.bottom-right { + left: expression( ( 0 - jGrowl.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' ); + top: expression( ( 0 - jGrowl.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' ); +} + +div.ie6.bottom-left { + left: expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' ); + top: expression( ( 0 - jGrowl.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' ); +} + +div.id6.center { + left: expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' ); + top: expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' ); + width: 100%; +} + +/** Normal Style Positions **/ +body > div.jGrowl { + position: fixed; +} + +body > div.jGrowl.top-left { + left: 0px; + top: 0px; +} + +body > div.jGrowl.top-right { + right: 0px; + top: 0px; +} + +body > div.jGrowl.bottom-left { + left: 0px; + bottom: 0px; +} + +body > div.jGrowl.bottom-right { + right: 0px; + bottom: 0px; +} + +body > div.jGrowl.center { + top: 0px; + width: 50%; + left: 25%; +} + +/** Cross Browser Styling **/ +div.center div.jGrowl-notification, div.center div.jGrowl-closer { + margin-left: auto; + margin-right: auto; +} + +div.jGrowl div.jGrowl-notification, div.jGrowl div.jGrowl-closer { + background-color: #FFFFCC; + background-image: url(../images/icon_conf_message.png); + background-repeat: no-repeat; + color: #333333; + opacity: .95; + filter: alpha(opacity = 85); + zoom: 1; + width: 380px; + padding: 10px 10px 10px 40px; + margin-top: 5px; + margin-bottom: 5px; + font-family: Tahoma, Arial, Helvetica, sans-serif; + font-size: 12px; + text-align: left; + display: none; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border:#E7A543 solid 1px; +} + +div.jGrowl div.jGrowl-notification { + min-height: 18px; + +} + +div.jGrowl div.jGrowl-notification div.header { + font-weight: bold; + font-size: 10px; +} + +div.jGrowl div.jGrowl-notification div.close { + float: right; + font-weight: bold; + font-size: 12px; + cursor: pointer; + padding: 0 0 10px 12px; +} + +div.jGrowl div.jGrowl-closer { + height: 15px; + padding-top: 4px; + padding-bottom: 4px; + cursor: pointer; + font-size: 11px; + font-weight: bold; + text-align: center; + background-image:none; +} -- 1.5.5.1 From imain at redhat.com Tue Jul 15 21:22:29 2008 From: imain at redhat.com (Ian Main) Date: Tue, 15 Jul 2008 14:22:29 -0700 Subject: [Ovirt-devel] Managed Node qpid Modeling In-Reply-To: <20080715093301.GA25562@redhat.com> References: <20080709215544.0599ea7a@tp.mains.net> <20080714134028.7cabfb71@tp.mains.net> <20080715093301.GA25562@redhat.com> Message-ID: <20080715142229.555bbe9e@tp.mains.net> On Tue, 15 Jul 2008 10:33:01 +0100 "Daniel P. Berrange" wrote: > On Mon, Jul 14, 2008 at 01:40:28PM -0700, Ian Main wrote: > > OK, similar idea. I spent a bunch of time looking at the > > libvirt API and decided that I would keep the properties > > and object relations in place rather than going to all > > libvirt style calls. I like the idea of modeling the > > system and having any state changes pushed up rather > > than having to poll. > > You're not getting rid of polling, you're just pushing it > elsewhere. To fill in the property fields & keep them updated > you're going to have to poll on the managed node fetching the > XML document all the time. This is absolutely something you > do not want todo. Fetching the XML is a heavyweight operation > on some hypervisor. eg if you have Xen and fetch the XML doc > for 20 VMs, once a second you'll have 100% cpu usage on the > managed node just from polling. The only methods that can be > efficiently polled are those for getting the live domain > resource info - ie virDomainGetInfo(), and those for listing > active/inactive domains. I'm very well aware that we're not getting rid of polling. My concern was the network traffic that would be generated in polling, I didn't realize it was such a heavy operation to call the XML based calls. We need to have as up to date info of what the state of the domains as possible. As per our IRC discussion we can move the domain info to a set of properties, probably within a DomainInfo class or such. The rest we'll have to use the XML classes and call them infrequently because polling is unrealistic. This should work fine.. the only other thing we need on a semi-regular basis is the vnc port, but we can just grab that on state changes. > > I did change the main creation functions to mirror the > > libvirt calls using XML descriptions. Very good call > > there. I also switched the create/destroy etc. to use > > libvirt equivalents. > > I maintain that this modelling should match the libvirt API > and object model 100%, so that it can be a general purpose > libvirt API-over-QPid rather than a oVirt specific modelling > as it is now. Having a general libvirt moel provides for > interoperability with other applications needing to access > libvirt over QPid, and will allow us to implement QPid > support directly into the libvirt client for those who do > not need to talk directly to QPid for asynchronous comms. > Reducing the amount of oVirt specific code is also important > for long term code maintainence overhead. OK, well, after our chat and some thought I think we can move in this direction. My only other concern would be some stray statistics and perhaps properties that would be outside of libvirt. Perhaps these could be in a separate class though. Ian From jguiditt at redhat.com Tue Jul 15 22:04:25 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Tue, 15 Jul 2008 18:04:25 -0400 Subject: [Ovirt-devel] [PATCH] added VM-level migration support to the WUI. Still no back end bits here, though. In-Reply-To: <1216135720-15149-1-git-send-email-sseago@redhat.com> References: <1216135720-15149-1-git-send-email-sseago@redhat.com> Message-ID: <1216159465.3695.8.camel@localhost.localdomain> Scott, could you give me a quick scenario to test against this so I can see it does what you meant it to? Comments based just on the code inline. On Tue, 2008-07-15 at 11:28 -0400, Scott Seago wrote: > Signed-off-by: Scott Seago > --- > wui/src/app/controllers/hardware_controller.rb | 18 ++++-- > wui/src/app/controllers/host_controller.rb | 11 +++ > wui/src/app/controllers/resources_controller.rb | 25 ------- > wui/src/app/controllers/vm_controller.rb | 13 +++- > wui/src/app/models/vm.rb | 31 ++++++--- > wui/src/app/models/vm_task.rb | 70 +++++++++++++++----- > wui/src/app/views/hardware/show_hosts.rhtml | 5 +- > wui/src/app/views/hardware/show_storage.rhtml | 2 +- > wui/src/app/views/host/_grid.rhtml | 15 +++-- > wui/src/app/views/host/addhost.html.erb | 5 +- > wui/src/app/views/host/quick_summary.rhtml | 1 + > wui/src/app/views/storage/_grid.rhtml | 4 +- > wui/src/app/views/storage/add.rhtml | 2 +- > wui/src/app/views/vm/migrate.rhtml | 81 +++++++++++++++++++++++ > wui/src/app/views/vm/show.rhtml | 15 +++- > wui/src/public/javascripts/flexigrid.js | 4 +- > wui/src/public/javascripts/ovirt.js | 2 +- > 17 files changed, 230 insertions(+), 74 deletions(-) > create mode 100644 wui/src/app/views/host/quick_summary.rhtml > create mode 100644 wui/src/app/views/vm/migrate.rhtml > > diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb > index 4175fd8..926b6c8 100644 > --- a/wui/src/app/controllers/hardware_controller.rb > +++ b/wui/src/app/controllers/hardware_controller.rb > @@ -112,7 +112,12 @@ class HardwareController < ApplicationController > end > > def hosts_json > - if params[:id] > + if params[:exclude_host] > + pre_json > + hosts = @pool.hosts > + find_opts = {:conditions => ["id != ?", params[:exclude_host]]} > + include_pool = false > + elsif params[:id] > pre_json > hosts = @pool.hosts > find_opts = {} > @@ -120,14 +125,17 @@ class HardwareController < ApplicationController > else > # FIXME: no permissions or usage checks here yet > # filtering on which pool to exclude > - id = params[:exclude_id] > + id = params[:exclude_pool] > hosts = Host > find_opts = {:include => :hardware_pool, > :conditions => ["pools.id != ?", id]} > include_pool = true > end > - attr_list = [:id, :hostname, :uuid, :hypervisor_type, :num_cpus, :cpu_speed, :arch, :memory_in_mb, :status_str, :id] > - attr_list.insert(2, [:hardware_pool, :name]) if include_pool > + attr_list = [] > + attr_list << :id if params[:checkboxes] > + attr_list << :hostname > + attr_list << [:hardware_pool, :name] if include_pool > + attr_list += [:uuid, :hypervisor_type, :num_cpus, :cpu_speed, :arch, :memory_in_mb, :status_str, :id] > json_list(hosts, attr_list, [:all], find_opts) > end > > @@ -152,7 +160,7 @@ class HardwareController < ApplicationController > else > # FIXME: no permissions or usage checks here yet > # filtering on which pool to exclude > - id = params[:exclude_id] > + id = params[:exclude_pool] > storage_pools = StoragePool > find_opts = {:include => :hardware_pool, > :conditions => ["pools.id != ?", id]} > diff --git a/wui/src/app/controllers/host_controller.rb b/wui/src/app/controllers/host_controller.rb > index 20571d7..4e4375a 100644 > --- a/wui/src/app/controllers/host_controller.rb > +++ b/wui/src/app/controllers/host_controller.rb > @@ -44,6 +44,17 @@ class HostController < ApplicationController > render :layout => 'selection' > end > > + def quick_summary > + pre_show > + set_perms(@perm_obj) > + unless @can_view > + flash[:notice] = 'You do not have permission to view this host: redirecting to top level' > + #perm errors for ajax should be done differently Considering it is almost all ajax now, we should figure out what 'differently' is asap > + redirect_to :controller => 'dashboard', :action => 'list' > + end > + render :layout => false > + end > + > # retrieves data used by snapshot graphs > def snapshot_graph > end > diff --git a/wui/src/app/controllers/resources_controller.rb b/wui/src/app/controllers/resources_controller.rb > index 694ef74..ca10960 100644 > --- a/wui/src/app/controllers/resources_controller.rb > +++ b/wui/src/app/controllers/resources_controller.rb > @@ -184,31 +184,6 @@ class ResourcesController < ApplicationController > @failure_list = [] > end > render :layout => 'confirmation' > - > - #if params[:vm_actions][:vms] > - # vms = params[:vm_actions][:vms] > - # if params[:vm_actions][VmTask::ACTION_START_VM] > - # flash[:notice] = "Starting Machines #{vms.join(',')}." > - # elsif params[:vm_actions][VmTask::ACTION_SHUTDOWN_VM] > - # flash[:notice] = "Stopping Machines #{vms.join(',')}." > - # elsif params[:vm_actions][:other_actions] > - # case params[:vm_actions][:other_actions] > - # when VmTask::ACTION_SHUTDOWN_VM then flash[:notice] = "Stopping Machines #{vms.join(',')}." > - # when VmTask::ACTION_START_VM then flash[:notice] = "Starting Machines #{vms.join(',')}." > - # when VmTask::ACTION_SUSPEND_VM then flash[:notice] = "Suspending Machines #{vms.join(',')}." > - # when VmTask::ACTION_RESUME_VM then flash[:notice] = "Resuming Machines #{vms.join(',')}." > - # when VmTask::ACTION_SAVE_VM then flash[:notice] = "Saving Machines #{vms.join(',')}." > - # when VmTask::ACTION_RESTORE_VM then flash[:notice] = "Restoring Machines #{vms.join(',')}." > - # when "destroy" then flash[:notice] = "Destroying Machines #{vms.join(',')}." > - # else > - # flash[:notice] = 'No Action Chosen.' > - # end > - # else > - # flash[:notice] = 'No Action Chosen.' > - # end > - #else > - # flash[:notice] = 'No Virtual Machines Selected.' > - #end > end > > protected > diff --git a/wui/src/app/controllers/vm_controller.rb b/wui/src/app/controllers/vm_controller.rb > index b9156d2..4f9962d 100644 > --- a/wui/src/app/controllers/vm_controller.rb > +++ b/wui/src/app/controllers/vm_controller.rb > @@ -26,7 +26,7 @@ class VmController < ApplicationController > > def show > set_perms(@perm_obj) > - @actions = @vm.get_action_and_label_list > + @actions = @vm.get_action_hash(@user) > unless @can_view > flash[:notice] = 'You do not have permission to view this vm: redirecting to top level' > redirect_to :controller => 'resources', :controller => 'dashboard' > @@ -149,8 +149,9 @@ class VmController < ApplicationController > > def vm_action > vm_action = params[:vm_action] > + data = params[:vm_action_data] > begin > - if @vm.queue_action(get_login_user, vm_action) > + if @vm.queue_action(get_login_user, vm_action, data) > render :json => { :object => "vm", :success => true, :alert => "#{vm_action} was successfully queued." } > else > render :json => { :object => "vm", :success => false, :alert => "#{vm_action} is an invalid action." } > @@ -171,6 +172,14 @@ class VmController < ApplicationController > end > end > > + def migrate > + @vm = Vm.find(params[:id]) > + @perm_obj = @vm.get_hardware_pool > + @redir_obj = @vm > + @current_pool_id=@vm.vm_resource_pool.id > + authorize_admin > + render :layout => 'popup' > + end > > def console > @show_vnc_error = "Console is unavailable for VM #{@vm.description}" unless @vm.has_console > diff --git a/wui/src/app/models/vm.rb b/wui/src/app/models/vm.rb > index 617512e..b607886 100644 > --- a/wui/src/app/models/vm.rb > +++ b/wui/src/app/models/vm.rb > @@ -22,7 +22,7 @@ require 'util/ovirt' > class Vm < ActiveRecord::Base > belongs_to :vm_resource_pool > belongs_to :host > - has_many :tasks, :class_name => "VmTask", :dependent => :destroy, :order => "id DESC" do > + has_many :tasks, :class_name => "VmTask", :dependent => :destroy, :order => "id ASC" do > def queued > find(:all, :conditions=>{:state=>Task::STATE_QUEUED}) > end > @@ -58,6 +58,9 @@ class Vm < ActiveRecord::Base > STATE_SAVING = "saving" > STATE_SAVED = "saved" > STATE_RESTORING = "restoring" > + > + STATE_MIGRATING = "migrating" > + > STATE_CREATE_FAILED = "create_failed" > STATE_INVALID = "invalid" > > @@ -68,7 +71,8 @@ class Vm < ActiveRecord::Base > STATE_SUSPENDING, > STATE_RESUMING, > STATE_SAVING, > - STATE_RESTORING] > + STATE_RESTORING, > + STATE_MIGRATING] > > EFFECTIVE_STATE = { STATE_PENDING => STATE_PENDING, > STATE_UNREACHABLE => STATE_UNREACHABLE, > @@ -83,9 +87,15 @@ class Vm < ActiveRecord::Base > STATE_SAVING => STATE_SAVED, > STATE_SAVED => STATE_SAVED, > STATE_RESTORING => STATE_RUNNING, > + STATE_MIGRATING => STATE_RUNNING, > STATE_CREATE_FAILED => STATE_CREATE_FAILED} > TASK_STATE_TRANSITIONS = [] > > + def get_hardware_pool > + pool = vm_resource_pool > + pool = pool.get_hardware_pool if pool > + pool > + end > def storage_volume_ids > storage_volumes.collect {|x| x.id } > end > @@ -126,9 +136,9 @@ class Vm < ActiveRecord::Base > RUNNING_STATES.include?(get_pending_state) > end > > - def get_action_list > + def get_action_list(user=nil) You do this in several places below, and I must be misunderstanding - what is the purpose of having this user var if it is always nil? > # return empty list rather than nil > - return_val = VmTask::VALID_ACTIONS_PER_VM_STATE[get_pending_state] || [] > + return_val = VmTask.valid_actions_for_vm_state(get_pending_state, self, user) || [] > # filter actions based on quota > unless resources_for_start? > return_val = return_val - [VmTask::ACTION_START_VM, VmTask::ACTION_RESTORE_VM] > @@ -136,10 +146,12 @@ class Vm < ActiveRecord::Base > return_val > end > > - def get_action_and_label_list > - get_action_list.collect do |action| > - VmTask.label_and_action(action) > + def get_action_hash(user=nil) > + actions = {} > + get_action_list(user).each do |action| > + actions[action] = VmTask::ACTIONS[action] > end > + actions > end > > # these resource checks are made at VM start/restore time > @@ -158,11 +170,12 @@ class Vm < ActiveRecord::Base > return return_val > end > > - def queue_action(user, action) > + def queue_action(user, action, data = nil) > return false unless get_action_list.include?(action) > task = VmTask.new({ :user => user, > :vm_id => id, > - :action => action, > + :action => action, > + :args => data, > :state => Task::STATE_QUEUED}) > task.save! > return true > diff --git a/wui/src/app/models/vm_task.rb b/wui/src/app/models/vm_task.rb > index aa12903..3f52478 100644 > --- a/wui/src/app/models/vm_task.rb > +++ b/wui/src/app/models/vm_task.rb > @@ -33,59 +33,97 @@ class VmTask < Task > > ACTION_UPDATE_STATE_VM = "update_state_vm" > > + # for migrate VM action, args provides the optional target host > + ACTION_MIGRATE_VM = "migrate_vm" > + > + PRIV_OBJECT_VM_POOL = "vm_resource_pool" > + PRIV_OBJECT_HW_POOL = "get_hardware_pool" > + > + Perhaps this is less a comment on the patch and more on the way we are doing this. It feels vaguely wrong to me to do it this way. I see a lot of repeated attributes, which to me says it should be more encapsulated in some way. Would it make more sense to put these 'contants' in the database? Or even a fixture of some sort? > # a hash of task actions which point to a hash which define valid state transitions > ACTIONS = { ACTION_CREATE_VM => { :label => "Create", > :icon => "icon_start.png", > :start => Vm::STATE_PENDING, > :running => Vm::STATE_CREATING, > :success => Vm::STATE_STOPPED, > - :failure => Vm::STATE_CREATE_FAILED}, > + :failure => Vm::STATE_CREATE_FAILED, > + :privilege => [Permission::PRIV_MODIFY, > + PRIV_OBJECT_VM_POOL]}, > ACTION_START_VM => { :label => "Start", > :icon => "icon_start.png", > :start => Vm::STATE_STOPPED, > :running => Vm::STATE_STARTING, > :success => Vm::STATE_RUNNING, > - :failure => Vm::STATE_STOPPED}, > + :failure => Vm::STATE_STOPPED, > + :privilege => [Permission::PRIV_VM_CONTROL, > + PRIV_OBJECT_VM_POOL]}, > ACTION_SHUTDOWN_VM => { :label => "Shutdown", > :icon => "icon_x.png", > :start => Vm::STATE_RUNNING, > :running => Vm::STATE_STOPPING, > :success => Vm::STATE_STOPPED, > - :failure => Vm::STATE_RUNNING}, > + :failure => Vm::STATE_RUNNING, > + :privilege => [Permission::PRIV_VM_CONTROL, > + PRIV_OBJECT_VM_POOL]}, > ACTION_SUSPEND_VM => { :label => "Suspend", > :icon => "icon_suspend.png", > :start => Vm::STATE_RUNNING, > :running => Vm::STATE_SUSPENDING, > :success => Vm::STATE_SUSPENDED, > - :failure => Vm::STATE_RUNNING}, > + :failure => Vm::STATE_RUNNING, > + :privilege => [Permission::PRIV_VM_CONTROL, > + PRIV_OBJECT_VM_POOL]}, > ACTION_RESUME_VM => { :label => "Resume", > :icon => "icon_start.png", > :start => Vm::STATE_SUSPENDED, > :running => Vm::STATE_RESUMING, > :success => Vm::STATE_RUNNING, > - :failure => Vm::STATE_SUSPENDED}, > + :failure => Vm::STATE_SUSPENDED, > + :privilege => [Permission::PRIV_VM_CONTROL, > + PRIV_OBJECT_VM_POOL]}, > ACTION_SAVE_VM => { :label => "Save", > :icon => "icon_save.png", > :start => Vm::STATE_RUNNING, > :running => Vm::STATE_SAVING, > :success => Vm::STATE_SAVED, > - :failure => Vm::STATE_RUNNING}, > + :failure => Vm::STATE_RUNNING, > + :privilege => [Permission::PRIV_VM_CONTROL, > + PRIV_OBJECT_VM_POOL]}, > ACTION_RESTORE_VM => { :label => "Restore", > :icon => "icon_restore.png", > :start => Vm::STATE_SAVED, > :running => Vm::STATE_RESTORING, > :success => Vm::STATE_RUNNING, > - :failure => Vm::STATE_SAVED} } > + :failure => Vm::STATE_SAVED, > + :privilege => [Permission::PRIV_VM_CONTROL, > + PRIV_OBJECT_VM_POOL]}, > + ACTION_MIGRATE_VM => { :label => "Migrate", > + :icon => "icon_restore.png", > + :start => Vm::STATE_RUNNING, > + :running => Vm::STATE_MIGRATING, > + :success => Vm::STATE_RUNNING, > + :failure => Vm::STATE_RUNNING, > + :privilege => [Permission::PRIV_MODIFY, > + PRIV_OBJECT_HW_POOL], > + :popup_action => 'migrate'} } > > - VALID_ACTIONS_PER_VM_STATE = { Vm::STATE_PENDING => [ACTION_CREATE_VM], > - Vm::STATE_RUNNING => [ACTION_SHUTDOWN_VM, > - ACTION_SUSPEND_VM, > - ACTION_SAVE_VM], > - Vm::STATE_STOPPED => [ACTION_START_VM], > - Vm::STATE_SUSPENDED => [ACTION_RESUME_VM], > - Vm::STATE_SAVED => [ACTION_RESTORE_VM], > - Vm::STATE_CREATE_FAILED => [], > - Vm::STATE_INVALID => []} > + def self.valid_actions_for_vm_state(state, vm=nil, user=nil) > + actions = [] > + ACTIONS.each do |action, hash| > + if hash[:start] == state > + add_action = true > + print "vm: #{vm}\n user: #{user}\n" > + if (vm and user) > + pool = vm.send(hash[:privilege][1]) > + print "pool: #{pool}\n privilege: #{hash[:privilege][1]}\n" > + add_action = pool ? pool.has_privilege(user, hash[:privilege][0]) : false > + end > + print "add_action: #{add_action}\n" > + actions << action if add_action > + end > + end > + actions > + end > > def self.action_label(action) > return ACTIONS[action][:label] > diff --git a/wui/src/app/views/hardware/show_hosts.rhtml b/wui/src/app/views/hardware/show_hosts.rhtml > index aaf28b6..167c601 100644 > --- a/wui/src/app/views/hardware/show_hosts.rhtml > +++ b/wui/src/app/views/hardware/show_hosts.rhtml > @@ -60,7 +60,10 @@ >
<% end -%> <% end -%> - +
diff --git a/wui/src/app/views/layouts/redux.rhtml b/wui/src/app/views/layouts/redux.rhtml index 46ff9da..23983fa 100644 --- a/wui/src/app/views/layouts/redux.rhtml +++ b/wui/src/app/views/layouts/redux.rhtml @@ -109,30 +109,28 @@ function delete_vm_pool(id, parent) { - if(confirm("Are you sure?")){ - $.post('<%= url_for :controller => "resources", :action => "destroy" %>', - {id: id}, - function(data,status){ - // need to redirect to the parent using the new ajax reload stuff - $("#vmpools_grid").flexReload() - if (data.alert) { - $.jGrowl(data.alert); - } - }, 'json'); - } + jQuery(document).trigger('close.facebox'); + $.post('<%= url_for :controller => "resources", :action => "destroy" %>', + {id: id}, + function(data,status){ + // need to redirect to the parent using the new ajax reload stuff + $("#vmpools_grid").flexReload(); + if (data.alert) { + $.jGrowl(data.alert); + } + }, 'json'); } function delete_hw_pool(id, parent) { - if(confirm("Are you sure?")){ - $.post('<%= url_for :controller => "hardware", :action => "destroy" %>', - {id: id}, - function(data,status){ - // need to redirect to the parent using the new ajax reload stuff - if (data.alert) { - $.jGrowl(data.alert); - } - }, 'json'); - } + jQuery(document).trigger('close.facebox'); + $.post('<%= url_for :controller => "hardware", :action => "destroy" %>', + {id: id}, + function(data,status){ + // need to redirect to the parent using the new ajax reload stuff + if (data.alert) { + $.jGrowl(data.alert); + } + }, 'json'); } <%= yield :scripts -%> diff --git a/wui/src/app/views/resources/quick_summary.rhtml b/wui/src/app/views/resources/quick_summary.rhtml index 77b1708..b17d332 100644 --- a/wui/src/app/views/resources/quick_summary.rhtml +++ b/wui/src/app/views/resources/quick_summary.rhtml @@ -10,7 +10,7 @@ <%= link_to image_tag("icon_edit.png") + " Edit Quota", {:controller => 'quota', :action => 'edit', :id => @vm_resource_pool.quota}, :rel=>"facebox[.bolder]", :class=>"selection_facebox" %> - + <%= image_tag "icon_x.png" %> Revert to Default Quota <% else -%> @@ -20,22 +20,22 @@ <% end -%> <% end -%> <% end -%> +<%= confirmation_dialog("confirm_delete_quota", "Are you sure?", "delete_vm_quota()") %> diff --git a/wui/src/app/views/storage/show.rhtml b/wui/src/app/views/storage/show.rhtml index 6263021..19ab30e 100644 --- a/wui/src/app/views/storage/show.rhtml +++ b/wui/src/app/views/storage/show.rhtml @@ -10,7 +10,7 @@ <%= image_tag "icon_refresh.png" %> Refresh - + <%= image_tag "icon_x.png" %> Delete <%- end -%> @@ -52,6 +52,7 @@ <%- end -%> +<%= confirmation_dialog("confirm_delete_storage", "Are you sure?", "delete_storage_pool()") %> diff --git a/wui/src/app/views/vm/show.rhtml b/wui/src/app/views/vm/show.rhtml index 293b632..defd40e 100644 --- a/wui/src/app/views/vm/show.rhtml +++ b/wui/src/app/views/vm/show.rhtml @@ -29,44 +29,44 @@ <% end -%> <% end %> - + <%= image_tag "icon_x.png" %> Cancel queued tasks - + <%= image_tag "icon_x.png" %> Delete <% end -%> <% end -%> +<%= confirmation_dialog("confirm_cancel", "Are you sure?", "cancel_queued_tasks()") %> +<%= confirmation_dialog("confirm_delete", "Are you sure?", "delete_vm()") %> diff --git a/wui/src/app/views/search/_grid.rhtml b/wui/src/app/views/search/_grid.rhtml new file mode 100644 index 0000000..6de9074 --- /dev/null +++ b/wui/src/app/views/search/_grid.rhtml @@ -0,0 +1,40 @@ +<% per_page = 40 %> +
+<%= '
' if checkboxes %> + +<%= '
' if checkboxes %> +
+ diff --git a/wui/src/app/views/search/results.rhtml b/wui/src/app/views/search/results.rhtml new file mode 100644 index 0000000..a7641b7 --- /dev/null +++ b/wui/src/app/views/search/results.rhtml @@ -0,0 +1,68 @@ +
+
'results' %>"> +
    +
  • + + " title="Search" type="image"> + +
  • +
  • + <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Actions    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> +
      + <% @types.each_index { |index| %> + +
    • + style="border-bottom: 1px solid #CCCCCC;" + <% end %> + > + + <%= @model_param == @types[index][1] ? "X" : "  " %> + <%=@types[index][0]%> +
    • + <% } %> +
    +
  • +
+
+
+ + + +
+ <% if @results.matches_estimated != 0 %> +
+ <%= render :partial => "/search/grid", :locals => { :table_id => "search_grid", + :terms => @terms, + :model => @model_param, + :checkboxes => false, + :on_select => "results_select" } %> +
+
+
+
Select an item above.
+
+
+<% else %> +
+
+ <%= image_tag 'no-grid-items.png', :style => 'float: left;' %> +
+ No results found.

+
+
+
+<% end %> diff --git a/wui/src/db/migrate/011_create_acts_as_xapian.rb b/wui/src/db/migrate/011_create_acts_as_xapian.rb new file mode 100644 index 0000000..84a9dd7 --- /dev/null +++ b/wui/src/db/migrate/011_create_acts_as_xapian.rb @@ -0,0 +1,14 @@ +class CreateActsAsXapian < ActiveRecord::Migration + def self.up + create_table :acts_as_xapian_jobs do |t| + t.column :model, :string, :null => false + t.column :model_id, :integer, :null => false + t.column :action, :string, :null => false + end + add_index :acts_as_xapian_jobs, [:model, :model_id], :unique => true + end + def self.down + drop_table :acts_as_xapian_jobs + end +end + diff --git a/wui/src/dutils/active_record_env.rb b/wui/src/dutils/active_record_env.rb index 72feb89..9b7b416 100644 --- a/wui/src/dutils/active_record_env.rb +++ b/wui/src/dutils/active_record_env.rb @@ -36,6 +36,7 @@ require 'erb' OVIRT_DIR = "/usr/share/ovirt-wui" require "#{OVIRT_DIR}/vendor/plugins/betternestedset/init.rb" +require "#{OVIRT_DIR}/vendor/plugins/acts_as_xapian/lib/acts_as_xapian" def database_connect $dbconfig = YAML::load(ERB.new(IO.read("#{OVIRT_DIR}/config/database.yml")).result) diff --git a/wui/src/vendor/plugins/acts_as_xapian/.gitignore b/wui/src/vendor/plugins/acts_as_xapian/.gitignore new file mode 100644 index 0000000..3fad9cc --- /dev/null +++ b/wui/src/vendor/plugins/acts_as_xapian/.gitignore @@ -0,0 +1,3 @@ +xapiandbs +CVS +*.swp diff --git a/wui/src/vendor/plugins/acts_as_xapian/LICENSE.txt b/wui/src/vendor/plugins/acts_as_xapian/LICENSE.txt new file mode 100644 index 0000000..72d93c4 --- /dev/null +++ b/wui/src/vendor/plugins/acts_as_xapian/LICENSE.txt @@ -0,0 +1,21 @@ +acts_as_xapian is released under the MIT License. + +Copyright (c) 2008 UK Citizens Online Democracy. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of the acts_as_xapian software and associated documentation files (the +"Software"), to deal in the Software without restriction, including without +limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom +the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/wui/src/vendor/plugins/acts_as_xapian/README.txt b/wui/src/vendor/plugins/acts_as_xapian/README.txt new file mode 100644 index 0000000..239289e --- /dev/null +++ b/wui/src/vendor/plugins/acts_as_xapian/README.txt @@ -0,0 +1,236 @@ +Do patch this file if there is documentation missing / wrong. It's called +README.txt and is in git, using Textile formatting. The wiki page is just +copied from the README.txt file. + +Contents +======== + +* a. Introduction to acts_as_xapian +* b. Installation +* c. Comparison to acts_as_solr (as on 24 April 2008) +* d. Documentation - indexing +* e. Documentation - querying +* f. Support + + +a. Introduction to acts_as_xapian +================================= + +"Xapian":http://www.xapian.org is a full text search engine library which has +Ruby bindings. acts_as_xapian adds support for it to Rails. It is an +alternative to acts_as_solr, acts_as_ferret, Ultrasphinx, acts_as_indexed, +acts_as_searchable or acts_as_tsearch. + +acts_as_xapian is deployed in production on these websites. +* "WhatDoTheyKnow":http://www.whatdotheyknow.com +* "MindBites":http://www.mindbites.com + +The section "c. Comparison to acts_as_solr" below will give you an idea of +acts_as_xapian's features. + +acts_as_xapian was started by Francis Irving in May 2008 for search and email +alerts in WhatDoTheyKnow, and so was supported by "mySociety":http://www.mysociety.org +and initially paid for by the "JRSST Charitable Trust":http://www.jrrt.org.uk/jrsstct.htm + + +b. Installation +=============== + +Retrieve the plugin directly from the git version control system by running +this command within your Rails app. + + git clone git://github.com/frabcus/acts_as_xapian.git vendor/plugins/acts_as_xapian + +Xapian 1.0.5 and associated Ruby bindings are also required. + +Debian or Ubuntu - install the packages libxapian15 and libxapian-ruby1.8. + +Mac OSX - follow the instructions for installing from source on +the "Installing Xapian":http://xapian.org/docs/install.html page - you need the +Xapian library and bindings (you don't need Omega). + +There is no Ruby Gem for Xapian, it would be great if you could make one! + + +c. Comparison to acts_as_solr (as on 24 April 2008) +============================= + +* Offline indexing only mode - which is a minus if you want changes +immediately reflected in the search index, and a plus if you were going to +have to implement your own offline indexing anyway. + +* Collapsing - the equivalent of SQL's "group by". You can specify a field +to collapse on, and only the most relevant result from each value of that +field is returned. Along with a count of how many there are in total. +acts_as_solr doesn't have this. + +* No highlighting - Xapian can't return you text highlighted with a search +query. You can try and make do with TextHelper::highlight (combined with +words_to_highlight below). I found the highlighting in acts_as_solr didn't +really understand the query anyway. + +* Date range searching - this exists in acts_as_solr, but I found it +wasn't documented well enough, and was hard to get working. + +* Spelling correction - "did you mean?" built in and just works. + +* Similar documents - acts_as_xapian has a simple command to find other models +that are like a specified model. + +* Multiple models - acts_as_xapian searches multiple types of model if you +like, returning them mixed up together by relevancy. This is like +multi_solr_search, only it is the default mode of operation and is properly +supported. + +* No daemons - However, if you have more than one web server, you'll need to +work out how to use "Xapian's remote backend":http://xapian.org/docs/remote.html. + +* One layer - full-powered Xapian is called directly from the Ruby, without +Solr getting in the way whenever you want to use a new feature from Lucene. + +* No Java - an advantage if you're more used to working in the rest of the +open source world. acts_as_xapian, it's pure Ruby and C++. + +* Xapian's awesome email list - the kids over at +"xapian-discuss":http://lists.xapian.org/mailman/listinfo/xapian-discuss +are super helpful. Useful if you need to extend and improve acts_as_xapian. The +Ruby bindings are mature and well maintained as part of Xapian. + + +d. Documentation - indexing +=========================== + +Xapian is an *offline indexing* search library - only one process can have the +Xapian database open for writing at once, and others that try meanwhile are +unceremoniously kicked out. For this reason, acts_as_xapian does not support +immediate writing to the database when your models change. + +Instead, there is a ActsAsXapianJob model which stores which models need +updating or deleting in the search index. A rake task 'xapian:update_index' +then performs the updates since last change. You can run it on a cron job, or +similar. + +Here's how to add indexing to your Rails app: + +1. Put acts_as_xapian in your models that need search indexing. e.g. + + acts_as_xapian :texts => [ :name, :short_name ], + :values => [ [ :created_at, 0, "created_at", :date ] ], + :terms => [ [ :variety, 'V', "variety" ] ] + +Options must include: + +* :texts, an array of fields for indexing with full text search. +e.g. :texts => [ :title, :body ] + +* :values, things which have a range of values for sorting, or for collapsing. +Specify an array quadruple of [ field, identifier, prefix, type ] where +** identifier is an arbitary numeric identifier for use in the Xapian database +** prefix is the part to use in search queries that goes before the : +** type can be any of :string, :number or :date + +e.g. :values => [ [ :created_at, 0, "created_at", :date ], +[ :size, 1, "size", :string ] ] + +* :terms, things which come with a prefix (before a :) in search queries. +Specify an array triple of [ field, char, prefix ] where +** char is an arbitary single upper case char used in the Xapian database, just +pick any single uppercase character, but use a different one for each prefix. +** prefix is the part to use in search queries that goes before the : +For example, if you were making Google and indexing to be able to later do a +query like "site:www.whatdotheyknow.com", then the prefix would be "site". + +e.g. :terms => [ [ :variety, 'V', "variety" ] ] + +A 'field' is a symbol referring to either an attribute or a function which +returns the text, date or number to index. Both 'identifier' and 'char' must be +the same for the same prefix in different models. + +Alternatively, +* :instead_index, a field which refers to another model that should be reindexed + instead of this one. + +Options may include: +* :eager_load, added as an :include clause when looking up search results in +database +* :if, either an attribute or a function which if returns false means the +object isn't indexed + +2. Generate a database migration to create the ActsAsXapianJob model: + + script/generate acts_as_xapian + rake db:migrate + +3. Call 'rake xapian:rebuild_index models="ModelName1 ModelName2"' to build the index +the first time (you must specify all your indexed models). It's put in a +development/test/production dir in acts_as_xapian/xapiandbs. + +4. Then from a cron job or a daemon, or by hand regularly!, call 'rake xapian:update_index' + + +e. Documentation - querying +=========================== + +Testing indexing +---------------- + +If you just want to test indexing is working, you'll find this rake task +useful (it has more options, see tasks/xapian.rake) + + rake xapian:query models="PublicBody User" query="moo" + +Performing a query +------------------ + +To perform a query from code call ActsAsXapian::Search.new. This takes in turn: +* model_classes - list of models to search, e.g. [PublicBody, InfoRequestEvent] +* query_string - Google like syntax, see below + +And then a hash of options: +* :offset - Offset of first result (default 0) +* :limit - Number of results per page (default -1, all) +* :sort_by_prefix - Optionally, prefix of value to sort by, otherwise sort by relevance +* :sort_by_ascending - Default true, set to false for descending sort +* :collapse_by_prefix - Optionally, prefix of value to collapse by (i.e. only return most relevant result from group) + +Google like query syntax is as described in + "Xapian::QueryParser Syntax":http://www.xapian.org/docs/queryparser.html +Queries can include prefix:value parts, according to what you indexed in the +acts_as_xapian part above. You can also say things like model:InfoRequestEvent +to constrain by model in more complex ways than the :model parameter, or +modelid:InfoRequestEvent-100 to only find one specific object. + +Returns an ActsAsXapian::Search object. Useful methods are: +* description - a techy one, to check how the query has been parsed +* matches_estimated - a guesstimate at the total number of hits +* spelling_correction - the corrected query string if there is a correction, otherwise nil +* words_to_highlight - list of words for you to highlight, perhaps with TextHelper::highlight +* results - an array of hashes each containing: +** :model - your Rails model, this is what you most want! +** :weight - relevancy measure +** :percent - the weight as a %, 0 meaning the item did not match the query at all +** :collapse_count - number of results with the same prefix, if you specified collapse_by_prefix + +Finding similar models +---------------------- + +To find models that are similar to a given set of models call ActsAsXapian::Similar.new. This takes: +* model_classes - list of model classes to return models from within +* models - list of models that you want to find related ones to + +Returns an ActsAsXapian::Similar object. Has all methods from ActsAsXapian::Search above, except +for words_to_highlight. In addition has: +* important_terms - the terms extracted from the input models, that were used to search for output +You need the results methods to get the similar models. + + +f. Support +========== + +Please ask any questions on the +"acts_as_xapian Google Group":http://groups.google.com/group/acts_as_xapian + +The official home page and repository for acts_as_xapian are the +"acts_as_xapian github page":http://github.com/frabcus/acts_as_xapian/wikis + +For more details about anything, see source code in lib/acts_as_xapian.rb diff --git a/wui/src/vendor/plugins/acts_as_xapian/generators/acts_as_xapian/USAGE b/wui/src/vendor/plugins/acts_as_xapian/generators/acts_as_xapian/USAGE new file mode 100644 index 0000000..2d027c4 --- /dev/null +++ b/wui/src/vendor/plugins/acts_as_xapian/generators/acts_as_xapian/USAGE @@ -0,0 +1 @@ +./script/generate acts_as_xapian diff --git a/wui/src/vendor/plugins/acts_as_xapian/generators/acts_as_xapian/acts_as_xapian_generator.rb b/wui/src/vendor/plugins/acts_as_xapian/generators/acts_as_xapian/acts_as_xapian_generator.rb new file mode 100644 index 0000000..5ac587d --- /dev/null +++ b/wui/src/vendor/plugins/acts_as_xapian/generators/acts_as_xapian/acts_as_xapian_generator.rb @@ -0,0 +1,13 @@ +class ActsAsXapianGenerator < Rails::Generator::Base + def manifest + record do |m| + m.migration_template 'migration.rb', 'db/migrate', + :migration_file_name => "create_acts_as_xapian" + end + end + + protected + def banner + "Usage: #{$0} acts_as_xapian" + end +end diff --git a/wui/src/vendor/plugins/acts_as_xapian/generators/acts_as_xapian/templates/migration.rb b/wui/src/vendor/plugins/acts_as_xapian/generators/acts_as_xapian/templates/migration.rb new file mode 100644 index 0000000..84a9dd7 --- /dev/null +++ b/wui/src/vendor/plugins/acts_as_xapian/generators/acts_as_xapian/templates/migration.rb @@ -0,0 +1,14 @@ +class CreateActsAsXapian < ActiveRecord::Migration + def self.up + create_table :acts_as_xapian_jobs do |t| + t.column :model, :string, :null => false + t.column :model_id, :integer, :null => false + t.column :action, :string, :null => false + end + add_index :acts_as_xapian_jobs, [:model, :model_id], :unique => true + end + def self.down + drop_table :acts_as_xapian_jobs + end +end + diff --git a/wui/src/vendor/plugins/acts_as_xapian/init.rb b/wui/src/vendor/plugins/acts_as_xapian/init.rb new file mode 100644 index 0000000..336bee1 --- /dev/null +++ b/wui/src/vendor/plugins/acts_as_xapian/init.rb @@ -0,0 +1,9 @@ +# acts_as_xapian/init.rb: +# +# Copyright (c) 2008 UK Citizens Online Democracy. All rights reserved. +# Email: francis at mysociety.org; WWW: http://www.mysociety.org/ +# +# $Id: init.rb,v 1.1 2008/04/23 13:33:50 francis Exp $ + +require 'acts_as_xapian' + diff --git a/wui/src/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb b/wui/src/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb new file mode 100644 index 0000000..74eb4bf --- /dev/null +++ b/wui/src/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb @@ -0,0 +1,629 @@ +# acts_as_xapian/lib/acts_as_xapian.rb: +# Xapian full text search in Ruby on Rails. +# +# Copyright (c) 2008 UK Citizens Online Democracy. All rights reserved. +# Email: francis at mysociety.org; WWW: http://www.mysociety.org/ +# +# Documentation +# ============= +# +# See ../README.txt foocumentation. Please update that file if you edit +# code. + +# Make it so if Xapian isn't installed, the Rails app doesn't fail completely, +# just when somebody does a search. +begin + require 'xapian' + $acts_as_xapian_bindings_available = true +rescue LoadError + STDERR.puts "acts_as_xapian: No Ruby bindings for Xapian installed" + $acts_as_xapian_bindings_available = false +end + +module ActsAsXapian + ###################################################################### + # Module level variables + # XXX must be some kind of cattr_accessor that can do this better + def ActsAsXapian.bindings_available + $acts_as_xapian_bindings_available + end + class NoXapianRubyBindingsError < StandardError + end + + def ActsAsXapian.db_path + @@db_path + end + # XXX global class intializers here get loaded more than once, don't know why. Protect them. + if not $acts_as_xapian_class_var_init + @@db = nil + @@writable_db = nil + @@writable_suffix = nil + @@init_values = [] + $acts_as_xapian_class_var_init = true + end + def ActsAsXapian.db + @@db + end + def ActsAsXapian.writable_db + @@writable_db + end + def ActsAsXapian.stemmer + @@stemmer + end + def ActsAsXapian.term_generator + @@term_generator + end + def ActsAsXapian.enquire + @@enquire + end + def ActsAsXapian.query_parser + @@query_parser + end + def ActsAsXapian.values_by_prefix + @@values_by_prefix + end + + ###################################################################### + # Initialisation + def ActsAsXapian.init(classname = nil, options = nil) + if not classname.nil? + # store class and options for use later, when we open the db in readable_init + @@init_values.push([classname,options]) + end + + # make the directory for the xapian databases to go in + db_parent_path = File.join(File.dirname(__FILE__), '../xapiandbs/') + Dir.mkdir(db_parent_path) unless File.exists?(db_parent_path) + raise "Set RAILS_ENV, so acts_as_xapian can find the right Xapian database" if not ENV['RAILS_ENV'] + @@db_path = File.join(db_parent_path, ENV['RAILS_ENV']) + + # make some things that don't depend on the db + # XXX this gets made once for each acts_as_xapian. Oh well. + @@stemmer = Xapian::Stem.new('english') + end + + # Opens / reopens the db for reading + # XXX we perhaps don't need to rebuild database and enquire and queryparser - + # but db.reopen wasn't enough by itself, so just do everything it's easier. + def ActsAsXapian.readable_init + raise NoXapianRubyBindingsError.new("Xapian Ruby bindings not installed") unless ActsAsXapian.bindings_available + + # basic Xapian objects + begin + @@db = Xapian::Database.new(@@db_path) + @@enquire = Xapian::Enquire.new(@@db) + rescue IOError + raise "Xapian database not opened; have you built it with scripts/rebuild-xapian-index ?" + end + + init_query_parser + end + + # Make a new query parser + def ActsAsXapian.init_query_parser + # for queries + @@query_parser = Xapian::QueryParser.new + @@query_parser.stemmer = @@stemmer + @@query_parser.stemming_strategy = Xapian::QueryParser::STEM_SOME + @@query_parser.database = @@db + @@query_parser.default_op = Xapian::Query::OP_AND + + @@terms_by_capital = {} + @@values_by_number = {} + @@values_by_prefix = {} + @@value_ranges_store = [] + + for init_value_pair in @@init_values + classname = init_value_pair[0] + options = init_value_pair[1] + + # go through the various field types, and tell query parser about them, + # and error check them - i.e. check for consistency between models + @@query_parser.add_boolean_prefix("model", "M") + @@query_parser.add_boolean_prefix("modelid", "I") + if options[:terms] + for term in options[:terms] + raise "Use a single capital letter for term code" if not term[1].match(/^[A-Z]$/) + raise "M and I are reserved for use as the model/id term" if term[1] == "M" or term[1] == "I" + raise "model and modelid are reserved for use as the model/id prefixes" if term[2] == "model" or term[2] == "modelid" + raise "Z is reserved for stemming terms" if term[1] == "Z" + raise "Already have code '" + term[1] + "' in another model but with different prefix '" + @@terms_by_capital[term[1]] + "'" if @@terms_by_capital.include?(term[1]) && @@terms_by_capital[term[1]] != term[2] + @@terms_by_capital[term[1]] = term[2] + @@query_parser.add_boolean_prefix(term[2], term[1]) + end + end + if options[:values] + for value in options[:values] + raise "Value index '"+value[1].to_s+"' must be an integer, is " + value[1].class.to_s if value[1].class != 1.class + raise "Already have value index '" + value[1].to_s + "' in another model but with different prefix '" + @@values_by_number[value[1]].to_s + "'" if @@values_by_number.include?(value[1]) && @@values_by_number[value[1]] != value[2] + + # date types are special, mark them so the first model they're seen for + if !@@values_by_number.include?(value[1]) + if value[3] == :date + value_range = Xapian::DateValueRangeProcessor.new(value[1]) + elsif value[3] == :string + value_range = Xapian::StringValueRangeProcessor.new(value[1]) + elsif value[3] == :number + value_range = Xapian::NumberValueRangeProcessor.new(value[1]) + else + raise "Unknown value type '" + value[3].to_s + "'" + end + + @@query_parser.add_valuerangeprocessor(value_range) + + # stop it being garbage collected, as + # add_valuerangeprocessor ref is outside Ruby's GC + @@value_ranges_store.push(value_range) + end + + @@values_by_number[value[1]] = value[2] + @@values_by_prefix[value[2]] = value[1] + end + end + end + end + + def ActsAsXapian.writable_init(suffix = "") + raise NoXapianRubyBindingsError.new("Xapian Ruby bindings not installed") unless ActsAsXapian.bindings_available + + # XXX called so db_path is made, shouldn't really be calling .init here + # as will make it remake stemmer etc. excessively often. + ActsAsXapian.init + + new_path = @@db_path + suffix + raise "writable_suffix/suffix inconsistency" if @@writable_suffix && @@writable_suffix != suffix + if @@writable_db.nil? + # for indexing + @@writable_db = Xapian::WritableDatabase.new(new_path, Xapian::DB_CREATE_OR_OPEN) + @@term_generator = Xapian::TermGenerator.new() + @@term_generator.set_flags(Xapian::TermGenerator::FLAG_SPELLING, 0) + @@term_generator.database = @@writable_db + @@term_generator.stemmer = @@stemmer + @@writable_suffix = suffix + end + end + + ###################################################################### + # Search with a query or for similar models + + # Base class for Search and Similar below + class QueryBase + attr_accessor :offset + attr_accessor :limit + attr_accessor :query + attr_accessor :matches + attr_accessor :query_models + + def initialize_db + ActsAsXapian.readable_init + if ActsAsXapian.db.nil? + raise "ActsAsXapian not initialized" + end + end + + # Set self.query before calling this + def initialize_query(options) + #raise options.to_yaml + offset = options[:offset] || 0; offset = offset.to_i + limit = options[:limit] || -1; limit = limit.to_i # -1 means all matches? + sort_by_prefix = options[:sort_by_prefix] || nil + sort_by_ascending = options[:sort_by_ascending] || true + collapse_by_prefix = options[:collapse_by_prefix] || nil + + ActsAsXapian.enquire.query = self.query + + if sort_by_prefix.nil? + ActsAsXapian.enquire.sort_by_relevance! + else + value = ActsAsXapian.values_by_prefix[sort_by_prefix] + raise "couldn't find prefix '" + sort_by_prefix + "'" if value.nil? + ActsAsXapian.enquire.sort_by_value_then_relevance!(value, sort_by_ascending) + end + if collapse_by_prefix.nil? + ActsAsXapian.enquire.collapse_key = Xapian.BAD_VALUENO + else + value = ActsAsXapian.values_by_prefix[collapse_by_prefix] + raise "couldn't find prefix '" + collapse_by_prefix + "'" if value.nil? + ActsAsXapian.enquire.collapse_key = value + end + + self.matches = ActsAsXapian.enquire.mset(offset, limit, 100) + @cached_results = nil + end + + # Return a description of the query + def description + self.query.description + end + + # Estimate total number of results + def matches_estimated + self.matches.matches_estimated + end + + # Return query string with spelling correction + def spelling_correction + correction = ActsAsXapian.query_parser.get_corrected_query_string + if correction.empty? + return nil + end + return correction + end + + # Return array of models found + def results + # If they've already pulled out the results, just return them. + if not @cached_results.nil? + return @cached_results + end + + # Pull out all the results + docs = [] + iter = self.matches._begin + while not iter.equals(self.matches._end) + docs.push({:data => iter.document.data, + :percent => iter.percent, + :weight => iter.weight, + :collapse_count => iter.collapse_count}) + iter.next + end + + # Look up without too many SQL queries + lhash = {} + lhash.default = [] + for doc in docs + k = doc[:data].split('-') + lhash[k[0]] = lhash[k[0]] + [k[1]] + end + # for each class, look up all ids + chash = {} + for cls, ids in lhash + conditions = [ "#{cls.constantize.table_name}.id in (?)", ids ] + found = cls.constantize.find(:all, :conditions => conditions, :include => cls.constantize.xapian_options[:eager_load]) + for f in found + chash[[cls, f.id]] = f + end + end + # now get them in right order again + results = [] + docs.each{|doc| k = doc[:data].split('-'); results << { :model => chash[[k[0], k[1].to_i]], + :percent => doc[:percent], :weight => doc[:weight], :collapse_count => doc[:collapse_count] } } + @cached_results = results + return results + end + end + + # Search for a query string, returns an array of hashes in result order. + # Each hash contains the actual Rails object in :model, and other detail + # about relevancy etc. in other keys. + class Search < QueryBase + attr_accessor :query_string + + # Note that model_classes is not only sometimes useful here - it's + # essential to make sure the classes have been loaded, and thus + # acts_as_xapian called on them, so we know the fields for the query + # parser. + + # model_classes - model classes to search within, e.g. [PublicBody, + # User]. Can take a single model class, or you can express the model + # class names in strings if you like. + # query_string - user inputed query string, with syntax much like Google Search + def initialize(model_classes, query_string, options = {}) + # Check parameters, convert to actual array of model classes + new_model_classes = [] + model_classes = [model_classes] if model_classes.class != Array + for model_class in model_classes: + raise "pass in the model class itself, or a string containing its name" if model_class.class != Class && model_class.class != String + model_class = model_class.constantize if model_class.class == String + new_model_classes.push(model_class) + end + model_classes = new_model_classes + + # Set things up + self.initialize_db + + # Case of a string, searching for a Google-like syntax query + self.query_string = query_string + + # Construct query which only finds things from specified models + model_query = Xapian::Query.new(Xapian::Query::OP_OR, model_classes.map{|mc| "M" + mc.to_s}) + user_query = ActsAsXapian.query_parser.parse_query(self.query_string, + Xapian::QueryParser::FLAG_BOOLEAN | Xapian::QueryParser::FLAG_PHRASE | + Xapian::QueryParser::FLAG_LOVEHATE | Xapian::QueryParser::FLAG_WILDCARD | + Xapian::QueryParser::FLAG_SPELLING_CORRECTION) + self.query = Xapian::Query.new(Xapian::Query::OP_AND, model_query, user_query) + + # Call base class constructor + self.initialize_query(options) + end + + # Return just normal words in the query i.e. Not operators, ones in + # date ranges or similar. Use this for cheap highlighting with + # TextHelper::highlight, and excerpt. + def words_to_highlight + query_nopunc = self.query_string.gsub(/[^a-z0-9:\.\/_]/i, " ") + query_nopunc = query_nopunc.gsub(/\s+/, " ") + words = query_nopunc.split(" ") + # Remove anything with a :, . or / in it + words = words.find_all {|o| !o.match(/(:|\.|\/)/) } + words = words.find_all {|o| !o.match(/^(AND|NOT|OR|XOR)$/) } + return words + end + + end + + # Search for models which contain theimportant terms taken from a specified + # list of models. i.e. Use to find documents similar to one (or more) + # documents, or use to refine searches. + class Similar < QueryBase + attr_accessor :query_models + attr_accessor :important_terms + + # model_classes - model classes to search within, e.g. [PublicBody, User] + # query_models - list of models you want to find things similar to + def initialize(model_classes, query_models, options = {}) + self.initialize_db + + # Case of an array, searching for models similar to those models in the array + self.query_models = query_models + + # Find the documents by their unique term + input_models_query = Xapian::Query.new(Xapian::Query::OP_OR, query_models.map{|m| "I" + m.xapian_document_term}) + ActsAsXapian.enquire.query = input_models_query + matches = ActsAsXapian.enquire.mset(0, 100, 100) # XXX so this whole method will only work with 100 docs + + # Get set of relevant terms for those documents + selection = Xapian::RSet.new() + iter = matches._begin + while not iter.equals(matches._end) + selection.add_document(iter) + iter.next + end + + # Bit weird that the function to make esets is part of the enquire + # object. This explains what exactly it does, which is to exclude + # terms in the existing query. + # http://thread.gmane.org/gmane.comp.search.xapian.general/3673/focus=3681 + eset = ActsAsXapian.enquire.eset(40, selection) + + # Do main search for them + self.important_terms = [] + iter = eset._begin + while not iter.equals(eset._end) + self.important_terms.push(iter.term) + iter.next + end + similar_query = Xapian::Query.new(Xapian::Query::OP_OR, self.important_terms) + # Exclude original + combined_query = Xapian::Query.new(Xapian::Query::OP_AND_NOT, similar_query, input_models_query) + + # Restrain to model classes + model_query = Xapian::Query.new(Xapian::Query::OP_OR, model_classes.map{|mc| "M" + mc.to_s}) + self.query = Xapian::Query.new(Xapian::Query::OP_AND, model_query, combined_query) + + # Call base class constructor + self.initialize_query(options) + end + end + + ###################################################################### + # Index + + # Offline indexing job queue model, create with migration made + # using "script/generate acts_as_xapian" as described in ../README.txt + class ActsAsXapianJob < ActiveRecord::Base + end + + # Update index with any changes needed, call this offline. Only call it + # from a script that exits - otherwise Xapian's writable database won't + # flush your changes. Specifying flush will reduce performance, but + # make sure that each index update is definitely saved to disk before + # logging in the database that it has been. + def ActsAsXapian.update_index(flush = false, verbose = false) + ActsAsXapian.writable_init + + ids_to_refresh = ActsAsXapianJob.find(:all).map() { |i| i.id } + for id in ids_to_refresh + begin + ActiveRecord::Base.transaction do + job = ActsAsXapianJob.find(id, :lock =>true) + STDOUT.puts("ActsAsXapian.update_index #{job.action} #{job.model} #{job.model_id.to_s}") if verbose + if job.action == 'update' + # XXX Index functions may reference other models, so we could eager load here too? + model = job.model.constantize.find(job.model_id) # :include => cls.constantize.xapian_options[:include] + model.xapian_index + elsif job.action == 'destroy' + # Make dummy model with right id, just for destruction + model = job.model.constantize.new + model.id = job.model_id + model.xapian_destroy + else + raise "unknown ActsAsXapianJob action '" + job.action + "'" + end + job.destroy + + if flush + ActsAsXapian.writable_db.flush + end + end + rescue => detail + # print any error, and carry on so other things are indexed + # XXX If item is later deleted, this should give up, and it + # won't. It will keep trying (assuming update_index called from + # regular cron job) and mayhap cause trouble. + STDERR.puts(detail.backtrace.join("\n") + "\nFAILED ActsAsXapian.update_index job #{id} #{$!}") + end + end + end + + # You must specify *all* the models here, this totally rebuilds the Xapian database. + # You'll want any readers to reopen the database after this. + def ActsAsXapian.rebuild_index(model_classes, verbose = false) + raise "when rebuilding all, please call as first and only thing done in process / task" if not ActsAsXapian.writable_db.nil? + + # Delete any existing .new database, and open a new one + new_path = ActsAsXapian.db_path + ".new" + if File.exist?(new_path) + raise "found existing " + new_path + " which is not Xapian flint database, please delete for me" if not File.exist?(File.join(new_path, "iamflint")) + FileUtils.rm_r(new_path) + end + ActsAsXapian.writable_init(".new") + + # Index everything + # XXX not a good place to do this destroy, as unindexed list is lost if + # process is aborted and old database carries on being used. Perhaps do in + # transaction and commit after rename below? Not sure if thenlocking is then bad + # for live website running at same time. + ActsAsXapianJob.destroy_all + for model_class in model_classes + models = model_class.find(:all) + for model in models + STDOUT.puts("ActsAsXapian.rebuild_index #{model_class} #{model.id}") if verbose + model.xapian_index + end + end + ActsAsXapian.writable_db.flush + + # Rename into place + old_path = ActsAsXapian.db_path + temp_path = ActsAsXapian.db_path + ".tmp" + if File.exist?(temp_path) + raise "temporary database found " + temp_path + " which is not Xapian flint database, please delete for me" if not File.exist?(File.join(temp_path, "iamflint")) + FileUtils.rm_r(temp_path) + end + if File.exist?(old_path) + FileUtils.mv old_path, temp_path + end + FileUtils.mv new_path, old_path + + # Delete old database + if File.exist?(temp_path) + raise "old database now at " + temp_path + " is not Xapian flint database, please delete for me" if not File.exist?(File.join(temp_path, "iamflint")) + FileUtils.rm_r(temp_path) + end + + # You'll want to restart your FastCGI or Mongrel processes after this, + # so they get the new db + end + + ###################################################################### + # Instance methods that get injected into your model. + + module InstanceMethods + # Used internally + def xapian_document_term + self.class.to_s + "-" + self.id.to_s + end + + # Extract value of a field from the model + def xapian_value(field, type = nil) + value = self[field] || self.send(field.to_sym) + if type == :date + value.utc.strftime("%Y%m%d") + elsif type == :boolean + value ? true : false + else + value.to_s + end + end + + # Store record in the Xapian database + def xapian_index + # if we have a conditional function for indexing, call it and destory object if failed + if self.class.xapian_options.include?(:if) + if_value = xapian_value(self.class.xapian_options[:if], :boolean) + if not if_value + self.xapian_destroy + return + end + end + + # otherwise (re)write the Xapian record for the object + doc = Xapian::Document.new + ActsAsXapian.term_generator.document = doc + + doc.data = self.xapian_document_term + + doc.add_term("M" + self.class.to_s) + doc.add_term("I" + doc.data) + if self.xapian_options[:terms] + for term in self.xapian_options[:terms] + doc.add_term(term[1] + xapian_value(term[0])) + end + end + if self.xapian_options[:values] + for value in self.xapian_options[:values] + doc.add_value(value[1], xapian_value(value[0], value[3])) + end + end + if self.xapian_options[:texts] + for text in self.xapian_options[:texts] + ActsAsXapian.term_generator.increase_termpos # stop phrases spanning different text fields + ActsAsXapian.term_generator.index_text(xapian_value(text)) + end + end + + ActsAsXapian.writable_db.replace_document("I" + doc.data, doc) + end + + # Delete record from the Xapian database + def xapian_destroy + ActsAsXapian.writable_db.delete_document("I" + self.xapian_document_term) + end + + # Used to mark changes needed by batch indexer + def xapian_mark_needs_index + model = self.class.to_s + model_id = self.id + ActiveRecord::Base.transaction do + found = ActsAsXapianJob.delete_all([ "model = ? and model_id = ?", model, model_id]) + job = ActsAsXapianJob.new + job.model = model + job.model_id = model_id + job.action = 'update' + job.save! + end + end + def xapian_mark_needs_destroy + model = self.class.to_s + model_id = self.id + ActiveRecord::Base.transaction do + found = ActsAsXapianJob.delete_all([ "model = ? and model_id = ?", model, model_id]) + job = ActsAsXapianJob.new + job.model = model + job.model_id = model_id + job.action = 'destroy' + job.save! + end + end + end + + ###################################################################### + # Main entry point, add acts_as_xapian to your model. + + module ActsMethods + # See top of this file for docs + def acts_as_xapian(options) + # Give error only on queries if bindings not available + if not ActsAsXapian.bindings_available + return + end + + include InstanceMethods + + cattr_accessor :xapian_options + self.xapian_options = options + + ActsAsXapian.init(self.class.to_s, options) + + after_save :xapian_mark_needs_index + after_destroy :xapian_mark_needs_destroy + end + end + +end + +# Reopen ActiveRecord and include the acts_as_xapian method +ActiveRecord::Base.extend ActsAsXapian::ActsMethods + + diff --git a/wui/src/vendor/plugins/acts_as_xapian/tasks/xapian.rake b/wui/src/vendor/plugins/acts_as_xapian/tasks/xapian.rake new file mode 100644 index 0000000..682b138 --- /dev/null +++ b/wui/src/vendor/plugins/acts_as_xapian/tasks/xapian.rake @@ -0,0 +1,43 @@ +require 'rubygems' +require 'rake' +require 'rake/testtask' +require 'activerecord' +require File.dirname(__FILE__) + '/../lib/acts_as_xapian.rb' + +namespace :xapian do + # Parameters - specify "flush=true" to save changes to the Xapian database + # after each model that is updated. This is safer, but slower. Specify + # "verbose=true" to print model name as it is run. + desc 'Updates Xapian search index with changes to models since last call' + task (:update_index => :environment) do + ActsAsXapian.update_index(ENV['flush'] ? true : false, ENV['verbose'] ? true : false) + end + + # Parameters - specify 'models="PublicBody User"' to say which models + # you index with Xapian. + # This totally rebuilds the database, so you will want to restart any + # web server afterwards to make sure it gets the changes, rather than + # still pointing to the old deleted database. Specify "verbose=true" to + # print model name as it is run. + desc 'Completely rebuilds Xapian search index (must specify all models)' + task (:rebuild_index => :environment) do + raise "specify ALL your models with models=\"ModelName1 ModelName2\" as parameter" if ENV['models'].nil? + ActsAsXapian.rebuild_index(ENV['models'].split(" ").map{|m| m.constantize}, ENV['verbose'] ? true : false) + end + + # Parameters - are models, query, offset, limit, sort_by_prefix, + # collapse_by_prefix + desc 'Run a query, return YAML of results' + task (:query => :environment) do + raise "specify models=\"ModelName1 ModelName2\" as parameter" if ENV['models'].nil? + raise "specify query=\"your terms\" as parameter" if ENV['query'].nil? + s = ActsAsXapian::Search.new(ENV['models'].split(" ").map{|m| m.constantize}, + ENV['query'], + :offset => (ENV['offset'] || 0), :limit => (ENV['limit'] || 10), + :sort_by_prefix => (ENV['sort_by_prefix'] || nil), + :collapse_by_prefix => (ENV['collapse_by_prefix'] || nil) + ) + STDOUT.puts(s.results.to_yaml) + end +end + -- 1.5.5.1 From dlutter at redhat.com Thu Jul 31 00:41:32 2008 From: dlutter at redhat.com (David Lutterkort) Date: Wed, 30 Jul 2008 17:41:32 -0700 Subject: [Ovirt-devel] SVG support Message-ID: <1217464892.25288.141.camel@localhost.localdomain> I keep getting the message 'SVG not supported by this browser' when I run with the latest Firefox from F-9 (firefox-3.0.1-1.fc9.x86_64) Besides not having pretty graphs, other parts of the UI also fail miserably when jquery-svg turns itself off - for example, when I look at the hosts in my default pool, clicking on a host name has no effect, and I get an error 'svg is undefined' in my JS console; I assume that's a cascading failure from jquery-svg turning itself off. What's worse, it seems that the jquery-svg check whether SVG is supported in the browser is busted. If I apply the patch at the bottom of this mail, I do get pretty graphs, and clicking on hosts does show the details. What are others doing ? Am I the only one who is affected by this ? There's also a new release of jquery-svg - a quick try didn't seem to fix the issue, but I am not sure if that's just because my way of 'updating' (unzip in public/javascripts/jquery-svg) broke something else. BTW, when you reload the OVirt WUI, there's a long list of JS errors flowing by in the console ... they really need to be fixed. David diff --git a/wui/src/app/views/layouts/redux.rhtml b/wui/src/app/views/layouts/redux.rhtml index 924f300..bcabe91 100644 --- a/wui/src/app/views/layouts/redux.rhtml +++ b/wui/src/app/views/layouts/redux.rhtml @@ -23,7 +23,7 @@ <%= javascript_include_tag "flexigrid.js" -%> <%= javascript_include_tag "facebox.js" -%> <%= javascript_include_tag "jquery.timers.js" -%> - <%= javascript_include_tag "jquery-svg/jquery.svg.pack.js" -%> + <%= javascript_include_tag "jquery-svg/jquery.svg.js" -%> <%= javascript_include_tag "jquery-svg/jquery.svggraph.js" -%>
> <%= render :partial => "/host/grid", :locals => { :table_id => "hosts_grid", > :hwpool => @pool, > - :exclude_id => nil, > + :exclude_pool => nil, > + :exclude_host => nil, > + :show_pool => false, > + :checkboxes => true, > :on_select => "hosts_select", > :on_deselect => "load_widget_deselect", > :on_hover => "load_widget_hover", > diff --git a/wui/src/app/views/hardware/show_storage.rhtml b/wui/src/app/views/hardware/show_storage.rhtml > index ec1a82d..dc1460a 100644 > --- a/wui/src/app/views/hardware/show_storage.rhtml > +++ b/wui/src/app/views/hardware/show_storage.rhtml > @@ -66,7 +66,7 @@ >
> <%= render :partial => "/storage/grid", :locals => { :table_id => "storage_grid", > :hwpool => @pool, > - :exclude_id => nil, > + :exclude_pool => nil, > :on_select => "storage_select" } %> >
> > diff --git a/wui/src/app/views/host/_grid.rhtml b/wui/src/app/views/host/_grid.rhtml > index 98a8af4..d4d4d11 100644 > --- a/wui/src/app/views/host/_grid.rhtml > +++ b/wui/src/app/views/host/_grid.rhtml > @@ -2,20 +2,25 @@ > > <% hosts_per_page = 40 %> >
> -
> +<%= '' if checkboxes %> > > -
> +<%= '' if checkboxes %> >
> > +
> + > + > +
> +
> + <%= error_messages_for 'migrate_vm' %> > + > + <%= render :partial => "/host/grid", :locals => { :table_id => "migrate_vm_grid", > + :hwpool => @vm.get_hardware_pool, > + :exclude_pool => nil, > + :exclude_host => @vm.host_id, > + :checkboxes => false, > + :on_select => "migrate_vm_select", > + :on_deselect => "migrate_vm_deselect", > + :on_hover => "load_widget_hover", > + :on_unhover => "load_widget_unhover" } %> > + > + <% form_tag do %> > + > + <%= hidden_field_tag 'id', @vm.id %> > + <%= hidden_field_tag 'vm_action', VmTask::ACTION_MIGRATE_VM %> > + Selected Migration Target: > +
> +
> +
No migration target selected.
> +
> +
> + <%= hidden_field_tag 'vm_action_data', "" %> > + <% end %> > +
> +<%= popup_footer("$('#migrate_vm_form').submit()", "Migrate Virtual Machine") %> > +
> + > + > diff --git a/wui/src/app/views/vm/show.rhtml b/wui/src/app/views/vm/show.rhtml > index 8b0a760..fe671ef 100644 > --- a/wui/src/app/views/vm/show.rhtml > +++ b/wui/src/app/views/vm/show.rhtml > @@ -17,10 +17,17 @@ > <%= link_to image_tag("icon_edit.png") + " Edit", > {:controller => 'vm', :action => 'edit', :id => @vm}, > :rel=>"facebox[.bolder]", :class=>"selection_facebox" %> > - <% for action in @actions %> > -
> - <%= image_tag action[2] %> <%= action[0] %> > - > + <% for name, action in @actions %> > + <% if action[:popup_action] -%> > + <%= link_to image_tag(action[:icon]) + action[:label], > + {:controller => 'vm', > + :action => action[:popup_action], :id => @vm}, > + :rel=>"facebox[.bolder]", :class=>"selection_facebox" %> > + <% else -%> > + > + <%= image_tag action[:icon] %> <%= action[:label] %> > + > + <% end -%> > <% end %> > > <%= image_tag "icon_x.png" %> Cancel queued tasks I had trouble applying this (manually dropped in the 4 lines), but it seems to have worked for steve, so hopefully it is just me > diff --git a/wui/src/public/javascripts/flexigrid.js b/wui/src/public/javascripts/flexigrid.js > index d7b6416..3715e6f 100644 > --- a/wui/src/public/javascripts/flexigrid.js > +++ b/wui/src/public/javascripts/flexigrid.js > @@ -719,7 +719,9 @@ > } > $(this).toggleClass('trSelected'); > if($(this).hasClass('trSelected')){ > - if (p.onSelect) p.onSelect($(t).find("tr.trSelected")); > + if (p.onSelect) p.onSelect($(t).find("tr.trSelected")); > + } else { > + if (p.onDeselect) p.onDeselect(this); > } > } > ) > diff --git a/wui/src/public/javascripts/ovirt.js b/wui/src/public/javascripts/ovirt.js > index c776458..e0aa222 100644 > --- a/wui/src/public/javascripts/ovirt.js > +++ b/wui/src/public/javascripts/ovirt.js > @@ -74,7 +74,7 @@ function ajax_validation(response, status) > if (response.object) { > $(".fieldWithErrors").removeClass("fieldWithErrors"); > $("div.errorExplanation").remove(); > - if (!response.success) { > + if (!response.success && response.errors ) { > for(i=0; i var element = $("div.form_field:has(#"+response.object + "_" + response.errors[i][0]+")"); > if (element) { From dlutter at redhat.com Tue Jul 15 23:11:31 2008 From: dlutter at redhat.com (David Lutterkort) Date: Tue, 15 Jul 2008 16:11:31 -0700 Subject: [Ovirt-devel] OVirt public API Message-ID: <1216163491.19722.20.camel@localhost.localdomain> Here is my current thinking around a public API for OVirt. The basic idea is that that API will expose all operations that are available through the WUI, with small adaptations to the fact that it's an API, and not an interactive interface. In particular, the API will (eventually) support the following: * Lifecycle control for virtual machines (start/stop/suspend/resume/migrate) * Management of the various pools, i.e. host, storage and VM pools * Querying of information about the above; I'd explicitly exclude performance data from this 'information' - I think that should be communicated by different means (e.g., collectd) Architecturally, the API will be a remote API over HTTP, using a RESTful style; in a nutshell, that means that clients make calls through HTTP requests, with arguments and results suitably encoded - for GET requests, that simply means ordinary request params, for POST, it's TBD which possible ways to serialize data is preferrable. Obvious candidates are XML, YAML, and JSON; right now, I am leaning towards XML. Stylistically, REST uses URL's to represent objects (or 'nouns') and different HTTP methods to retrieve and/or change those objects ('verbs') You can think of the HTTP methods GET, POST, PUT, DELETE as analogous to the SQL actions select, insert, update, and delete, respectively. Or the show/create/update/delete methods in Rails controllers. Besides being lightweight, a RESTful API is also very attractive because of the support for it in Rails 2 (ActionController::Resources on the server side, and ActiveResource for clients) That support takes away a lot of the headaches around serialization of objects, routing etc. Objects ======= Each object (VM, host, storage pool etc.) needs to be identified by a unique URL. For a VM, this may be /vms/7. Since the internal id '7' appears in the URL, we need a way to find VM's by various criteria, for example doing a 'GET /vms?uuid=...' will return the URL to a VM with that UUID, or 'GET /vms?num_vcpus_allocated=2' lists all VM's that have 2 vcpus. More interestingly, something like 'GET /storage_volumes/5/vms' would list all the VM's that use storage volume 5. Toplevel objects accessible in this way are VM's, hosts, and the various pools. Besides retrieving a readonly representation of them, changes can be made, for example by doing a 'POST /vms' with a suitable body to create a new VM. One difficulty is the inherently asynchronous nature of OVirt, where you ask for a state change (e.g. start a VM) but that doesn't happen until some time later. It's probably best to expose those pending state changes nested underneath the object to which they apply, e.g. /vms/7/tasks would give you a list of the tasks queued for VM 7, and doing a 'POST /vms/7/tasks' can be used to queue a new task for VM 7. One thing that's not entirely clear is whether and how the actual tasks that wind up in task-o-matic map to the tasks in the public API. For the currently supported tasks, there's no need to beat around the bush, and they correspond directly to actions one would want to perform through the API. That might not be true in the future when we get more complex operations like 'clear_host' that may be decomposed into multiple tasks in task-o-matic. We definitely don't want to leak too much implementation detail through the public API. Architecture ============ For now, the API should just run side-by-side with the WUI, in the same web server, simply because much of the underlying infrastructure, from models to authentication is shared between the two. If we ever need an API-only or WUI-only server, it's probably easiest to just configure that out. Rails' ActiveResource package provides a convenient way for users to access this API in Ruby - I am not entirely clear on how people who insist on writing Python will access the API. At worst, somebody would have to either write code that deserializes Rails' XML representation of objects into Python objects; though from a quick googling it seems that there are a couple of fledgling projects to bridge the ActiveResource <-> Python gap. A second option is to provide output from API methods through another format, like JSON, which might be better supported for Python deserialization. Another small wrinkle is that we want to keep the URL's for API resources separate from URL's used by the WUI. The whole API should probably live underneath a /api or /rest prefix on the server, though common logic between WUI and API methods would be factored into controllers and/or helpers used by both. There are some examples on the web where WUI and API are served by the same controller, and only the views change between the two, but I am not sure if that is really realistic for a decent sized app. Implementation ============== To get started, I'll hack out some of the simpler API calls, like updating the data for a VM. David From sseago at redhat.com Wed Jul 16 02:45:51 2008 From: sseago at redhat.com (Scott Seago) Date: Tue, 15 Jul 2008 22:45:51 -0400 Subject: [Ovirt-devel] [PATCH] added VM-level migration support to the WUI. Still no back end bits here, though. In-Reply-To: <1216159465.3695.8.camel@localhost.localdomain> References: <1216135720-15149-1-git-send-email-sseago@redhat.com> <1216159465.3695.8.camel@localhost.localdomain> Message-ID: <487D60DF.7060809@redhat.com> Jason Guiditta wrote: > Scott, could you give me a quick scenario to test against this so I can > see it does what you meant it to? Comments based just on the code > inline. > > OK. so there are several things to look for. First, there's the question of the migrate link itself. In the VM details pane, you should get a migrate action link if: 1) you have permission to migrate this VM; and 2) the VM can be migrated. For 1) -- you've got to have the administrator role on the HW pool that contains this VM's Virtual Machine pool. So if you're ovirtadmin, you should see the link. If you create a new user, give that user admin or user permissions on the VM pool only, the migrate link won't show up. For 2) the VM must have a "pending state" of running -- i.e. take the VM state and "apply" all pending tasks, and if the result is "running" then the VM can be migrated. So a stopped VM with no pending tasks can't be migrated. A running VM with no pending tasks can. A stopped VM with a pending (not yet started) "start_vm" task can be migrated too. Now once you get the migrate link, you should get a dialog form upon clicking it. You should see a flexigrid with all hosts in the hardware pool (minus the host that the VM is currently running on if the VM currently has a host listed. it won't have a host if, for example, it's not yet running but there's a pending start task. If you click "migrate" without choosing a host, then there should be a migrate_vm task inserted for the proper VM and user -- the 'args' field will be empty. If you click in the row for a host, then that host should show as selected, and clicking "migrate" creates a migrate task with that host's ID in the 'args' field. Two points for the form action though: 1) the "selected host" part of the dialog probably needs styling work from Tim -- I was just going for basic functionality here. 2) as we don't currently have a "task list" UI, you'll have to test this by looking at the tasks table directly in the database. And a final point -- if you have taskomatic running, you'll probably see that all the tasks fail -- that's because Taskomatic doesn't yet know about migration. And some comments on your comments below... > On Tue, 2008-07-15 at 11:28 -0400, Scott Seago wrote: > >> diff --git a/wui/src/app/controllers/host_controller.rb b/wui/src/app/controllers/host_controller.rb >> index 20571d7..4e4375a 100644 >> --- a/wui/src/app/controllers/host_controller.rb >> +++ b/wui/src/app/controllers/host_controller.rb >> @@ -44,6 +44,17 @@ class HostController < ApplicationController >> render :layout => 'selection' >> end >> >> + def quick_summary >> + pre_show >> + set_perms(@perm_obj) >> + unless @can_view >> + flash[:notice] = 'You do not have permission to view this host: redirecting to top level' >> + #perm errors for ajax should be done differently >> > Considering it is almost all ajax now, we should figure out what > 'differently' is asap > Agreed. this handles stuff "just like the rest of it" -- i.e. it's broken in the same way. When we switched to the ajax design, we explicitly avoided fixing permissions/redirection across the board for schedule reasons. So this needs to be added to one of the upcoming sprint task lists (probably not the current one though!) >> diff --git a/wui/src/app/models/vm.rb b/wui/src/app/models/vm.rb >> index 617512e..b607886 100644 >> --- a/wui/src/app/models/vm.rb >> +++ b/wui/src/app/models/vm.rb >> @@ -22,7 +22,7 @@ require 'util/ovirt' >> class Vm < ActiveRecord::Base >> belongs_to :vm_resource_pool >> belongs_to :host >> - has_many :tasks, :class_name => "VmTask", :dependent => :destroy, :order => "id DESC" do >> + has_many :tasks, :class_name => "VmTask", :dependent => :destroy, :order => "id ASC" do >> def queued >> find(:all, :conditions=>{:state=>Task::STATE_QUEUED}) >> end >> @@ -58,6 +58,9 @@ class Vm < ActiveRecord::Base >> STATE_SAVING = "saving" >> STATE_SAVED = "saved" >> STATE_RESTORING = "restoring" >> + >> + STATE_MIGRATING = "migrating" >> + >> STATE_CREATE_FAILED = "create_failed" >> STATE_INVALID = "invalid" >> >> @@ -68,7 +71,8 @@ class Vm < ActiveRecord::Base >> STATE_SUSPENDING, >> STATE_RESUMING, >> STATE_SAVING, >> - STATE_RESTORING] >> + STATE_RESTORING, >> + STATE_MIGRATING] >> >> EFFECTIVE_STATE = { STATE_PENDING => STATE_PENDING, >> STATE_UNREACHABLE => STATE_UNREACHABLE, >> @@ -83,9 +87,15 @@ class Vm < ActiveRecord::Base >> STATE_SAVING => STATE_SAVED, >> STATE_SAVED => STATE_SAVED, >> STATE_RESTORING => STATE_RUNNING, >> + STATE_MIGRATING => STATE_RUNNING, >> STATE_CREATE_FAILED => STATE_CREATE_FAILED} >> TASK_STATE_TRANSITIONS = [] >> >> + def get_hardware_pool >> + pool = vm_resource_pool >> + pool = pool.get_hardware_pool if pool >> + pool >> + end >> def storage_volume_ids >> storage_volumes.collect {|x| x.id } >> end >> @@ -126,9 +136,9 @@ class Vm < ActiveRecord::Base >> RUNNING_STATES.include?(get_pending_state) >> end >> >> - def get_action_list >> + def get_action_list(user=nil) >> > You do this in several places below, and I must be misunderstanding - > what is the purpose of having this user var if it is always nil? > > Mostly an issue of backwards compatibility. Up to now, we didn't pass a user into this method -- the intent is to get a list of valid actions for a VM given its state. With the migration patch, we also care _who_ will be doing the actions -- i.e. different actions can have different permission requirements. But if a user isn't passed in, the method still returns the list of possible actions (i.e. "somebody can do this") which may still be a valid use case on the admin or reporting side. i.e. "give me a list of stoppable VMs, etc. However, for the action list that we display in the VM details pane, we _do_ want to filter based on user permissions -- if I'm just a user in this VM pool, I can't migrate. If I'm an admin for this VM's Hardware Pool, I _can_ migrate. Above I'm just supplying the default value if get_action_list is called, like before, with no args. I do pass in the user in the vm_controller where the list is generated for the details pane. > >> diff --git a/wui/src/app/models/vm_task.rb b/wui/src/app/models/vm_task.rb >> index aa12903..3f52478 100644 >> --- a/wui/src/app/models/vm_task.rb >> +++ b/wui/src/app/models/vm_task.rb >> @@ -33,59 +33,97 @@ class VmTask < Task >> >> ACTION_UPDATE_STATE_VM = "update_state_vm" >> >> + # for migrate VM action, args provides the optional target host >> + ACTION_MIGRATE_VM = "migrate_vm" >> + >> + PRIV_OBJECT_VM_POOL = "vm_resource_pool" >> + PRIV_OBJECT_HW_POOL = "get_hardware_pool" >> + >> + >> > > Perhaps this is less a comment on the patch and more on the way we are > doing this. It feels vaguely wrong to me to do it this way. I see a > lot of repeated attributes, which to me says it should be more > encapsulated in some way. Would it make more sense to put these > 'contants' in the database? Or even a fixture of some sort? > > Yeah, again I'm just being consistent here :-) -- but now is the time to raise more general architecture/implementation issues for the project, so we should probably start a list of "things to revisit in the current design/implementation" and prioritize those separately from the functionality-based patches. As for this particular case, I started doing this early on as an improvement over the proliferation of magic strings that was starting to happen. i.e. worst case scenario for this sort of list of random text strings is to inline the string literal everywhere. I was trying to consolidate all required string literals in one place per model class into a list (even if an unstructured one) of string constants in each model. Some of these might make sense in the db -- i.e. create tables for vm_actions, vm_states, task_states, etc. ACTION_MIGRATE_VM above is an example of this. PRIV_OBJECT_VM_POOL on the other hand has a more limited use -- in this case it signifies what method to call on the vm model object to determine what pool to use for permissions checks -- and, as such is probably best left as-is. Then comes the already-considered question of internationalization -- in which case, you might want to forget everything I said above and start over. But, seriously, we really can't figure out how we want to redesign our handling of string literals apart from the more general internationalization case, so ultimately this is probably just another part of that process. > I had trouble applying this (manually dropped in the 4 lines), but it > seems to have worked for steve, so hopefully it is just me > > I wonder if it's the usual dos/windows cr/lf junk creeping back in -- it was all over the jquery stuff when we first imported it and it really confuses git. Anyway if it applied for steve, then we're probably fine, and upon ACK I can just push my change from my repo. From hbrock at redhat.com Wed Jul 16 12:53:30 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Wed, 16 Jul 2008 08:53:30 -0400 Subject: [Ovirt-devel] OVirt public API In-Reply-To: <1216163491.19722.20.camel@localhost.localdomain> References: <1216163491.19722.20.camel@localhost.localdomain> Message-ID: <20080716125330.GM24297@redhat.com> On Tue, Jul 15, 2008 at 04:11:31PM -0700, David Lutterkort wrote: > Here is my current thinking around a public API for OVirt. The basic > idea is that that API will expose all operations that are available > through the WUI, with small adaptations to the fact that it's an API, > and not an interactive interface. > > In particular, the API will (eventually) support the following: > > * Lifecycle control for virtual machines > (start/stop/suspend/resume/migrate) > > * Management of the various pools, i.e. host, storage and VM pools > > * Querying of information about the above; I'd explicitly exclude > performance data from this 'information' - I think that should be > communicated by different means (e.g., collectd) > > Architecturally, the API will be a remote API over HTTP, using a RESTful > style; in a nutshell, that means that clients make calls through HTTP > requests, with arguments and results suitably encoded - for GET > requests, that simply means ordinary request params, for POST, it's TBD > which possible ways to serialize data is preferrable. Obvious candidates > are XML, YAML, and JSON; right now, I am leaning towards > XML. Stylistically, REST uses URL's to represent objects (or 'nouns') > and different HTTP methods to retrieve and/or change those objects > ('verbs') You can think of the HTTP methods GET, POST, PUT, DELETE as > analogous to the SQL actions select, insert, update, and delete, > respectively. Or the show/create/update/delete methods in Rails > controllers. > > Besides being lightweight, a RESTful API is also very attractive because > of the support for it in Rails 2 (ActionController::Resources on the > server side, and ActiveResource for clients) That support takes away a > lot of the headaches around serialization of objects, routing etc. I like the REST concept, especially the fact that it will leverage the model code we already have in oVirt. However, I would very much like to have a command line interface (oVirsh?) to go along with the API. Does that seem doable on top of a REST API? XML-RPC I assume is covered if we use XML to serialize data. > Objects > ======= > > Each object (VM, host, storage pool etc.) needs to be identified by a > unique URL. For a VM, this may be /vms/7. Since the internal id '7' > appears in the URL, we need a way to find VM's by various criteria, for > example doing a 'GET /vms?uuid=...' will return the URL to a VM with > that UUID, or 'GET /vms?num_vcpus_allocated=2' lists all VM's that have > 2 vcpus. More interestingly, something like 'GET /storage_volumes/5/vms' > would list all the VM's that use storage volume 5. > > Toplevel objects accessible in this way are VM's, hosts, and the various > pools. Besides retrieving a readonly representation of them, changes can > be made, for example by doing a 'POST /vms' with a suitable body to > create a new VM. > > One difficulty is the inherently asynchronous nature of OVirt, where you > ask for a state change (e.g. start a VM) but that doesn't happen until > some time later. It's probably best to expose those pending state > changes nested underneath the object to which they apply, > e.g. /vms/7/tasks would give you a list of the tasks queued for VM 7, > and doing a 'POST /vms/7/tasks' can be used to queue a new task for VM > 7. One thing that's not entirely clear is whether and how the actual > tasks that wind up in task-o-matic map to the tasks in the public > API. For the currently supported tasks, there's no need to beat around > the bush, and they correspond directly to actions one would want to > perform through the API. That might not be true in the future when we > get more complex operations like 'clear_host' that may be decomposed > into multiple tasks in task-o-matic. We definitely don't want to leak > too much implementation detail through the public API. > > Architecture > ============ > > For now, the API should just run side-by-side with the WUI, in the same > web server, simply because much of the underlying infrastructure, from > models to authentication is shared between the two. If we ever need an > API-only or WUI-only server, it's probably easiest to just configure > that out. > > Rails' ActiveResource package provides a convenient way for users to > access this API in Ruby - I am not entirely clear on how people who > insist on writing Python will access the API. At worst, somebody would > have to either write code that deserializes Rails' XML representation of > objects into Python objects; though from a quick googling it seems that > there are a couple of fledgling projects to bridge the ActiveResource > <-> Python gap. A second option is to provide output from API methods > through another format, like JSON, which might be better supported for > Python deserialization. > > Another small wrinkle is that we want to keep the URL's for API > resources separate from URL's used by the WUI. The whole API should > probably live underneath a /api or /rest prefix on the server, though > common logic between WUI and API methods would be factored into > controllers and/or helpers used by both. There are some examples on the > web where WUI and API are served by the same controller, and only the > views change between the two, but I am not sure if that is really > realistic for a decent sized app. > > Implementation > ============== > > To get started, I'll hack out some of the simpler API calls, like > updating the data for a VM. This is great, looking forward to seeing what you come up with. I do think we will need to have some form of python "bindings" -- surely python has some concept of REST? Take care, --Hugh From bkahn at redhat.com Wed Jul 16 14:25:05 2008 From: bkahn at redhat.com (Benjamin Kahn) Date: Wed, 16 Jul 2008 14:25:05 +0000 Subject: [Ovirt-devel] OVirt public API In-Reply-To: <20080716125330.GM24297@redhat.com> References: <1216163491.19722.20.camel@localhost.localdomain> <20080716125330.GM24297@redhat.com> Message-ID: <1216218305.3015.65.camel@localhost.localdomain> On Wed, 2008-07-16 at 08:53 -0400, Hugh O. Brock wrote: > XML-RPC I assume is covered if we use XML to serialize data. No. XML-RPC is very different from this proposal. XML-RPC uses a single URL which accepts only post data. The content of the POST request is a single command (verb) and a number of arguments to that verb. The arguments can be a limited number of supported types: arrays, lists, ints, strings, etc. For an example, here is the URL for our bugzilla install: https://bugzilla.redhat.com/xmlrpc.cgi To get information about a bug, you can call the command: bugzilla.getBug ($bugid, $username, $password); Which encodes to: bugzilla.getBug $bugid $username $password And gets an immediate return for the data. -- Benjamin Kahn Program Manager (978) 392 - 3176 From jguiditt at redhat.com Wed Jul 16 15:33:33 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Wed, 16 Jul 2008 11:33:33 -0400 Subject: [Ovirt-devel] [PATCH] added VM-level migration support to the WUI. Still no back end bits here, though. In-Reply-To: <487D60DF.7060809@redhat.com> References: <1216135720-15149-1-git-send-email-sseago@redhat.com> <1216159465.3695.8.camel@localhost.localdomain> <487D60DF.7060809@redhat.com> Message-ID: <1216222413.3372.5.camel@localhost.localdomain> On Tue, 2008-07-15 at 22:45 -0400, Scott Seago wrote: > Jason Guiditta wrote: > > Scott, could you give me a quick scenario to test against this so I can > > see it does what you meant it to? Comments based just on the code > > inline. > > > > > OK. so there are several things to look for. > > First, there's the question of the migrate link itself. In the VM > details pane, you should get a migrate action link if: > 1) you have permission to migrate this VM; and > 2) the VM can be migrated. > > For 1) -- you've got to have the administrator role on the HW pool that > contains this VM's Virtual Machine pool. So if you're ovirtadmin, you > should see the link. If you create a new user, give that user admin or > user permissions on the VM pool only, the migrate link won't show up. > > For 2) the VM must have a "pending state" of running -- i.e. take the VM > state and "apply" all pending tasks, and if the result is "running" then > the VM can be migrated. So a stopped VM with no pending tasks can't be > migrated. A running VM with no pending tasks can. A stopped VM with a > pending (not yet started) "start_vm" task can be migrated too. > > Now once you get the migrate link, you should get a dialog form upon > clicking it. You should see a flexigrid with all hosts in the hardware > pool (minus the host that the VM is currently running on if the VM > currently has a host listed. it won't have a host if, for example, it's > not yet running but there's a pending start task. If you click "migrate" > without choosing a host, then there should be a migrate_vm task inserted > for the proper VM and user -- the 'args' field will be empty. If you > click in the row for a host, then that host should show as selected, and > clicking "migrate" creates a migrate task with that host's ID in the > 'args' field. > > Two points for the form action though: > 1) the "selected host" part of the dialog probably needs styling work > from Tim -- I was just going for basic functionality here. > 2) as we don't currently have a "task list" UI, you'll have to test this > by looking at the tasks table directly in the database. > > And a final point -- if you have taskomatic running, you'll probably see > that all the tasks fail -- that's because Taskomatic doesn't yet know > about migration. ACK, I was able to test this, and it appears to do everything intended (once I removed all the 'widget' calls, since the svg plugin does not work for me). -j > > And some comments on your comments below... > > > Mostly an issue of backwards compatibility. Up to now, we didn't pass a > user into this method -- the intent is to get a list of valid actions > for a VM given its state. With the migration patch, we also care _who_ > will be doing the actions -- i.e. different actions can have different > permission requirements. But if a user isn't passed in, the method still > returns the list of possible actions (i.e. "somebody can do this") which > may still be a valid use case on the admin or reporting side. i.e. "give > me a list of stoppable VMs, etc. > > However, for the action list that we display in the VM details pane, we > _do_ want to filter based on user permissions -- if I'm just a user in > this VM pool, I can't migrate. If I'm an admin for this VM's Hardware > Pool, I _can_ migrate. Above I'm just supplying the default value if > get_action_list is called, like before, with no args. I do pass in the > user in the vm_controller where the list is generated for the details pane. Ah, thanks, that makes much more sense now. > > Yeah, again I'm just being consistent here :-) -- but now is the time to > raise more general architecture/implementation issues for the project, > so we should probably start a list of "things to revisit in the current > design/implementation" and prioritize those separately from the > functionality-based patches. As for this particular case, I started > doing this early on as an improvement over the proliferation of magic > strings that was starting to happen. i.e. worst case scenario for this > sort of list of random text strings is to inline the string literal > everywhere. I was trying to consolidate all required string literals in > one place per model class into a list (even if an unstructured one) of > string constants in each model. Some of these might make sense in the db > -- i.e. create tables for vm_actions, vm_states, task_states, etc. > ACTION_MIGRATE_VM above is an example of this. PRIV_OBJECT_VM_POOL on > the other hand has a more limited use -- in this case it signifies what > method to call on the vm model object to determine what pool to use for > permissions checks -- and, as such is probably best left as-is. > > Then comes the already-considered question of internationalization -- in > which case, you might want to forget everything I said above and start > over. But, seriously, we really can't figure out how we want to redesign > our handling of string literals apart from the more general > internationalization case, so ultimately this is probably just another > part of that process. > > I should have been more specific here - I really didn't mean to move _all_ of these 'somewhere', just the ones that there were a lot of and everything had the same params for the hash. I agree though, since we use these status messages for visual output, we should indeed combine any refactoring here to account for i18n. From jim at meyering.net Wed Jul 16 16:51:38 2008 From: jim at meyering.net (Jim Meyering) Date: Wed, 16 Jul 2008 18:51:38 +0200 Subject: [Ovirt-devel] enforcing the no-push-to-master policy Message-ID: <87prpdg4bp.fsf@rho.meyering.net> FYI, as any of you with commit access know, we now have a policy that limits commits to "master". Most development is expected to take place on the "next" branch. To enforce that policy, I've just added a server-side commit hook. For details, see the new README file on the new vcs-admin branch: http://git.et.redhat.com/?p=ovirt.git;a=blob_plain;f=README;hb=3b159148c1bb Denying/granting push access to a branch: ======================================== Prerequisites: - you need shell access to the git server host - you must be a member of the ovirt-adm group To lock a branch (e.g., "master"), ssh SERVER git --git-dir=/var/www/git/ovirt.git \ config hooks.denypush.branch.master contact-email at example.com To unlock it: ssh SERVER git --git-dir=/var/www/git/ovirt.git \ config --unset hooks.denypush.branch.master [ Note to self, to set this up on a fedora/RHEL-based system: g=ovirt-adm repo=/var/www/git/ovirt.git/config groupadd $g for u in user1 user2 user3; do usermod -a -G $g $u; done chgrp $g $repo && chmod g+w $repo ] From dlutter at redhat.com Wed Jul 16 16:57:46 2008 From: dlutter at redhat.com (David Lutterkort) Date: Wed, 16 Jul 2008 09:57:46 -0700 Subject: [Ovirt-devel] OVirt public API In-Reply-To: <20080716125330.GM24297@redhat.com> References: <1216163491.19722.20.camel@localhost.localdomain> <20080716125330.GM24297@redhat.com> Message-ID: <1216227466.19321.5.camel@localhost.localdomain> On Wed, 2008-07-16 at 08:53 -0400, Hugh O. Brock wrote: > > Besides being lightweight, a RESTful API is also very attractive because > > of the support for it in Rails 2 (ActionController::Resources on the > > server side, and ActiveResource for clients) That support takes away a > > lot of the headaches around serialization of objects, routing etc. > > I like the REST concept, especially the fact that it will leverage the > model code we already have in oVirt. However, I would very much like > to have a command line interface (oVirsh?) to go along with the > API. Does that seem doable on top of a REST API? XML-RPC I assume is > covered if we use XML to serialize data. That's a very important point: a RESTful API does not give you an XML-RPC API, it's two completly different styles of API. With the support built into Rails, it's relatively easy to change the way objects get (de)serialized, but that still doesn't give you XML-RPC. > This is great, looking forward to seeing what you come up with. I do > think we will need to have some form of python "bindings" -- surely > python has some concept of REST? I think the stickiest point is how hard will it be to deserialize data into python objects to make using the API easy. There's a 'pyactiveresource'[1] which should give people similar convenience in accessing the API from Python as from Ruby (see the example[2]), but I haven't tried it. David [1] http://pypi.python.org/pypi/pyactiveresource/0.2.4 [2] http://superjared.com/projects/pyactiveresource/ From jim at meyering.net Wed Jul 16 17:21:46 2008 From: jim at meyering.net (Jim Meyering) Date: Wed, 16 Jul 2008 19:21:46 +0200 Subject: [Ovirt-devel] a pox on whitespace Message-ID: <87ej5tg2xh.fsf@rho.meyering.net> Here are some things we can do to avoid bad whitespace (not just trailing whitespace) without causing too much development pain: server-side enforcement have a git pre-push hook check for and reject changes that add trailing blanks. This typically cannot be circumvented. However, I've set up similar things whereby exceptional cases can be white-listed. local-commit-enforcement With recent git, just do this in each of your working directories: chmod a+x .git/hooks/pre-commit and a commit that would have added bad whitespace will fail. (you can circumvent it with git commit's --no-verify (-n) option) "make check"-style detection Add a top-level Makefile rule that fails if any file contains bad whitespace. Then establish policy that one must pass "make check"s tests before committing/pushing. editor highlighting Enable syntax highlighting in your editor and tell it to display bad whitespace. For example, add this to your ~/.vimrc: let c_space_errors=1 highlight RedundantSpaces ctermbg=red guibg=red match RedundantSpaces /\s\+$\| \+\ze\t/ For emacs, you might want to try show-wspace.el (I haven't, but it's the first google hit for "highlight whitespace emacs") , or maybe you already use font-lock mode, which you can customize. Jim From jguiditt at redhat.com Wed Jul 16 18:55:59 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Wed, 16 Jul 2008 14:55:59 -0400 Subject: [Ovirt-devel] [PATCH] incorporated tallen's notification UI enhancements. In-Reply-To: <1216152748-22365-1-git-send-email-sseago@redhat.com> References: <1216152748-22365-1-git-send-email-sseago@redhat.com> Message-ID: <1216234559.3372.8.camel@localhost.localdomain> On Tue, 2008-07-15 at 16:12 -0400, Scott Seago wrote: >
×
class="header">' + o.header + '
' + message > + '
' ACK, though I would like to see a packed or min version of this new js. -j From sseago at redhat.com Wed Jul 16 20:02:27 2008 From: sseago at redhat.com (Scott Seago) Date: Wed, 16 Jul 2008 16:02:27 -0400 Subject: [Ovirt-devel] [PATCH] incorporated tallen's notification UI enhancements. In-Reply-To: <1216234559.3372.8.camel@localhost.localdomain> References: <1216152748-22365-1-git-send-email-sseago@redhat.com> <1216234559.3372.8.camel@localhost.localdomain> Message-ID: <487E53D3.2080105@redhat.com> Jason Guiditta wrote: > On Tue, 2008-07-15 at 16:12 -0400, Scott Seago wrote: > >>
×
> class="header">' + o.header + '
' + message >> + '
' >> > > ACK, though I would like to see a packed or min version of this new js. > > -j > > More generally, we need to handle packing these in our build. At this point, we're probably not using the packed version of several of the plugins, as we've made small modifications to them -- at least for tree, flexigrid, and (in a small way) jgrowl. Scott From mdehaan at redhat.com Wed Jul 16 20:07:19 2008 From: mdehaan at redhat.com (Michael DeHaan) Date: Wed, 16 Jul 2008 16:07:19 -0400 Subject: [Ovirt-devel] OVirt public API In-Reply-To: <1216163491.19722.20.camel@localhost.localdomain> References: <1216163491.19722.20.camel@localhost.localdomain> Message-ID: <487E54F7.3060908@redhat.com> David Lutterkort wrote: > Here is my current thinking around a public API for OVirt. The basic > idea is that that API will expose all operations that are available > through the WUI, with small adaptations to the fact that it's an API, > and not an interactive interface. > > In particular, the API will (eventually) support the following: > > * Lifecycle control for virtual machines > (start/stop/suspend/resume/migrate) > > * Management of the various pools, i.e. host, storage and VM pools > > * Querying of information about the above; I'd explicitly exclude > performance data from this 'information' - I think that should be > communicated by different means (e.g., collectd) > > Architecturally, the API will be a remote API over HTTP, using a RESTful > style; in a nutshell, that means that clients make calls through HTTP > requests, with arguments and results suitably encoded - for GET > requests, that simply means ordinary request params, for POST, it's TBD > which possible ways to serialize data is preferrable. Obvious candidates > are XML, YAML, and JSON; right now, I am leaning towards > XML. Stylistically, REST uses URL's to represent objects (or 'nouns') > and different HTTP methods to retrieve and/or change those objects > ('verbs') You can think of the HTTP methods GET, POST, PUT, DELETE as > analogous to the SQL actions select, insert, update, and delete, > respectively. Or the show/create/update/delete methods in Rails > controllers. > > Besides being lightweight, a RESTful API is also very attractive because > of the support for it in Rails 2 (ActionController::Resources on the > server side, and ActiveResource for clients) That support takes away a > lot of the headaches around serialization of objects, routing etc. > I would make an argument for XMLRPC/SSL based on that a lot of our management applications already have XMLRPC API's (such as Spacewalk/Cobbler/etc), and that serialization and more remote faults are supported. Having an app have to speak to multiple API types if of course going to be a reality. That being said, REST is definitely workable, and as long as there is an API, I think most people will be reasonably happy. Basically with XMLRPC you don't have to write any wrapper code around the API caller and it just works as if it were a local API, which is nice > Objects > ======= > > Each object (VM, host, storage pool etc.) needs to be identified by a > unique URL. For a VM, this may be /vms/7. Since the internal id '7' > appears in the URL, we need a way to find VM's by various criteria, for > example doing a 'GET /vms?uuid=...' will return the URL to a VM with > that UUID, or 'GET /vms?num_vcpus_allocated=2' lists all VM's that have > 2 vcpus. More interestingly, something like 'GET /storage_volumes/5/vms' > would list all the VM's that use storage volume 5. > > Toplevel objects accessible in this way are VM's, hosts, and the various > pools. Besides retrieving a readonly representation of them, changes can > be made, for example by doing a 'POST /vms' with a suitable body to > create a new VM. > > One difficulty is the inherently asynchronous nature of OVirt, where you > ask for a state change (e.g. start a VM) but that doesn't happen until > some time later. It's probably best to expose those pending state > changes nested underneath the object to which they apply, > e.g. /vms/7/tasks would give you a list of the tasks queued for VM 7, > and doing a 'POST /vms/7/tasks' can be used to queue a new task for VM > 7. One thing that's not entirely clear is whether and how the actual > tasks that wind up in task-o-matic map to the tasks in the public > API. For the currently supported tasks, there's no need to beat around > the bush, and they correspond directly to actions one would want to > perform through the API. That might not be true in the future when we > get more complex operations like 'clear_host' that may be decomposed > into multiple tasks in task-o-matic. We definitely don't want to leak > too much implementation detail through the public API. > > Architecture > ============ > > For now, the API should just run side-by-side with the WUI, in the same > web server, simply because much of the underlying infrastructure, from > models to authentication is shared between the two. If we ever need an > API-only or WUI-only server, it's probably easiest to just configure > that out. > > Rails' ActiveResource package provides a convenient way for users to > access this API in Ruby - I am not entirely clear on how people who > insist on writing Python will access the API. At worst, somebody would > have to either write code that deserializes Rails' XML representation of > objects into Python objects; though from a quick googling it seems that > there are a couple of fledgling projects to bridge the ActiveResource > <-> Python gap. A second option is to provide output from API methods > through another format, like JSON, which might be better supported for > Python deserialization. > > Another small wrinkle is that we want to keep the URL's for API > resources separate from URL's used by the WUI. The whole API should > probably live underneath a /api or /rest prefix on the server, though > common logic between WUI and API methods would be factored into > controllers and/or helpers used by both. There are some examples on the > web where WUI and API are served by the same controller, and only the > views change between the two, but I am not sure if that is really > realistic for a decent sized app. > > Implementation > ============== > > To get started, I'll hack out some of the simpler API calls, like > updating the data for a VM. > > David > > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel > From mdehaan at redhat.com Wed Jul 16 20:09:49 2008 From: mdehaan at redhat.com (Michael DeHaan) Date: Wed, 16 Jul 2008 16:09:49 -0400 Subject: [Ovirt-devel] OVirt public API In-Reply-To: <487E54F7.3060908@redhat.com> References: <1216163491.19722.20.camel@localhost.localdomain> <487E54F7.3060908@redhat.com> Message-ID: <487E558D.50408@redhat.com> Michael DeHaan wrote: > David Lutterkort wrote: >> Here is my current thinking around a public API for OVirt. The basic >> idea is that that API will expose all operations that are available >> through the WUI, with small adaptations to the fact that it's an API, >> and not an interactive interface. >> >> In particular, the API will (eventually) support the following: >> >> * Lifecycle control for virtual machines >> (start/stop/suspend/resume/migrate) >> >> * Management of the various pools, i.e. host, storage and VM pools >> >> * Querying of information about the above; I'd explicitly exclude >> performance data from this 'information' - I think that should be >> communicated by different means (e.g., collectd) >> >> Architecturally, the API will be a remote API over HTTP, using a RESTful >> style; in a nutshell, that means that clients make calls through HTTP >> requests, with arguments and results suitably encoded - for GET >> requests, that simply means ordinary request params, for POST, it's TBD >> which possible ways to serialize data is preferrable. Obvious candidates >> are XML, YAML, and JSON; right now, I am leaning towards >> XML. Stylistically, REST uses URL's to represent objects (or 'nouns') >> and different HTTP methods to retrieve and/or change those objects >> ('verbs') You can think of the HTTP methods GET, POST, PUT, DELETE as >> analogous to the SQL actions select, insert, update, and delete, >> respectively. Or the show/create/update/delete methods in Rails >> controllers. >> >> Besides being lightweight, a RESTful API is also very attractive because >> of the support for it in Rails 2 (ActionController::Resources on the >> server side, and ActiveResource for clients) That support takes away a >> lot of the headaches around serialization of objects, routing etc. >> > > I would make an argument for XMLRPC/SSL based on that a lot of our > management applications already have XMLRPC API's (such as > Spacewalk/Cobbler/etc), and that serialization and more remote faults > are supported. Having an app have to speak to multiple API types if > of course going to be a reality. > > That being said, REST is definitely workable, and as long as there is > an API, I think most people will be reasonably happy. > > Basically with XMLRPC you don't have to write any wrapper code around > the API caller and it just works as if it were a local API, which is > nice > I should add, embedding XML in an XMLRPC request as a string sounds weird, but does work. The main benefit is not the format, which is not perfect, just that there are a lot of nice libraries that make XMLRPC behave as if it were a local API/module, doing the usual getattr()/method_missing magic and so forth. s/more remote faults/remote faults/ From jguiditt at redhat.com Wed Jul 16 20:13:09 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Wed, 16 Jul 2008 16:13:09 -0400 Subject: [Ovirt-devel] [PATCH] incorporated tallen's notification UI enhancements. In-Reply-To: <487E53D3.2080105@redhat.com> References: <1216152748-22365-1-git-send-email-sseago@redhat.com> <1216234559.3372.8.camel@localhost.localdomain> <487E53D3.2080105@redhat.com> Message-ID: <1216239189.3372.17.camel@localhost.localdomain> On Wed, 2008-07-16 at 16:02 -0400, Scott Seago wrote: > > > More generally, we need to handle packing these in our build. At this > point, we're probably not using the packed version of several of the > plugins, as we've made small modifications to them -- at least for tree, > flexigrid, and (in a small way) jgrowl. > > Scott Agreed. I am pretty sure the tool(s) used by jquery for packing are readily available, so we should be able to do this for any we have modified. -j From berrange at redhat.com Wed Jul 16 20:21:22 2008 From: berrange at redhat.com (Daniel P. Berrange) Date: Wed, 16 Jul 2008 21:21:22 +0100 Subject: [Ovirt-devel] OVirt public API In-Reply-To: <1216227466.19321.5.camel@localhost.localdomain> References: <1216163491.19722.20.camel@localhost.localdomain> <20080716125330.GM24297@redhat.com> <1216227466.19321.5.camel@localhost.localdomain> Message-ID: <20080716202122.GD32686@redhat.com> On Wed, Jul 16, 2008 at 09:57:46AM -0700, David Lutterkort wrote: > On Wed, 2008-07-16 at 08:53 -0400, Hugh O. Brock wrote: > > > Besides being lightweight, a RESTful API is also very attractive because > > > of the support for it in Rails 2 (ActionController::Resources on the > > > server side, and ActiveResource for clients) That support takes away a > > > lot of the headaches around serialization of objects, routing etc. > > > > I like the REST concept, especially the fact that it will leverage the > > model code we already have in oVirt. However, I would very much like > > to have a command line interface (oVirsh?) to go along with the > > API. Does that seem doable on top of a REST API? XML-RPC I assume is > > covered if we use XML to serialize data. > > That's a very important point: a RESTful API does not give you an > XML-RPC API, it's two completly different styles of API. With the > support built into Rails, it's relatively easy to change the way objects > get (de)serialized, but that still doesn't give you XML-RPC. As a point of reference, Flickr provides XMLRPC, REST *and* SOAP at once. Obviously they're fairly different in the way they encoded requests parameters, but in all three cases the responses are just an embedded XML document containing the result or error code. So its pretty clear they have some nice generic servlet, and a way to bridge this to all three API styles, so they only write the server side stuff once and get all three APIs. I've no idea how you're anticipating doing the server side coding for the API, but if there was a way todo it such that the Ruby impl of the APIs didn't have any direct knowledge of REST, we could add in other API styles later. http://www.flickr.com/services/api/ In particular: REST http://www.flickr.com/services/api/request.rest.html http://www.flickr.com/services/api/response.rest.html XMLRPC http://www.flickr.com/services/api/request.xmlrpc.html http://www.flickr.com/services/api/response.xmlrpc.html SOAP http://www.flickr.com/services/api/request.soap.html http://www.flickr.com/services/api/response.soap.html 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 berrange at redhat.com Wed Jul 16 20:27:02 2008 From: berrange at redhat.com (Daniel P. Berrange) Date: Wed, 16 Jul 2008 21:27:02 +0100 Subject: [Ovirt-devel] OVirt public API In-Reply-To: <487E54F7.3060908@redhat.com> References: <1216163491.19722.20.camel@localhost.localdomain> <487E54F7.3060908@redhat.com> Message-ID: <20080716202702.GE32686@redhat.com> On Wed, Jul 16, 2008 at 04:07:19PM -0400, Michael DeHaan wrote: > David Lutterkort wrote: > >Here is my current thinking around a public API for OVirt. The basic > >idea is that that API will expose all operations that are available > >through the WUI, with small adaptations to the fact that it's an API, > >and not an interactive interface. > > > >In particular, the API will (eventually) support the following: > > > > * Lifecycle control for virtual machines > > (start/stop/suspend/resume/migrate) > > > > * Management of the various pools, i.e. host, storage and VM pools > > > > * Querying of information about the above; I'd explicitly exclude > > performance data from this 'information' - I think that should be > > communicated by different means (e.g., collectd) > > > >Architecturally, the API will be a remote API over HTTP, using a RESTful > >style; in a nutshell, that means that clients make calls through HTTP > >requests, with arguments and results suitably encoded - for GET > >requests, that simply means ordinary request params, for POST, it's TBD > >which possible ways to serialize data is preferrable. Obvious candidates > >are XML, YAML, and JSON; right now, I am leaning towards > >XML. Stylistically, REST uses URL's to represent objects (or 'nouns') > >and different HTTP methods to retrieve and/or change those objects > >('verbs') You can think of the HTTP methods GET, POST, PUT, DELETE as > >analogous to the SQL actions select, insert, update, and delete, > >respectively. Or the show/create/update/delete methods in Rails > >controllers. > > > >Besides being lightweight, a RESTful API is also very attractive because > >of the support for it in Rails 2 (ActionController::Resources on the > >server side, and ActiveResource for clients) That support takes away a > >lot of the headaches around serialization of objects, routing etc. > > > > I would make an argument for XMLRPC/SSL based on that a lot of our > management applications already have XMLRPC API's (such as > Spacewalk/Cobbler/etc), and that serialization and more remote faults > are supported. That's rubbish - REST is just as expressive as XMLRPC in terms of data serialization and fault reporting - in fact its more expressive, since it is not tied into the XMLRPC format. This examples shows one way in which a fault response used in XMLRPC can trivially be mapped into a REST style API. http://www.flickr.com/services/api/response.rest.html http://www.flickr.com/services/api/response.xmlrpc.html You don't even need to use the same serialization format for errors vs normal responses since you can distinguish a fault based on the HTTP return code. Since REST is just plain HTTP, the expressiveness is entirely at your control when defining the data format for your HTTP responses. You get to choose whether to provide an unstructured text blob response, or a structured XML document - whichever best suits the needs of the API. 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 mdehaan at redhat.com Wed Jul 16 20:52:46 2008 From: mdehaan at redhat.com (Michael DeHaan) Date: Wed, 16 Jul 2008 16:52:46 -0400 Subject: [Ovirt-devel] OVirt public API In-Reply-To: <20080716202702.GE32686@redhat.com> References: <1216163491.19722.20.camel@localhost.localdomain> <487E54F7.3060908@redhat.com> <20080716202702.GE32686@redhat.com> Message-ID: <487E5F9E.5020800@redhat.com> Daniel P. Berrange wrote: > On Wed, Jul 16, 2008 at 04:07:19PM -0400, Michael DeHaan wrote: > >> David Lutterkort wrote: >> >>> Here is my current thinking around a public API for OVirt. The basic >>> idea is that that API will expose all operations that are available >>> through the WUI, with small adaptations to the fact that it's an API, >>> and not an interactive interface. >>> >>> In particular, the API will (eventually) support the following: >>> >>> * Lifecycle control for virtual machines >>> (start/stop/suspend/resume/migrate) >>> >>> * Management of the various pools, i.e. host, storage and VM pools >>> >>> * Querying of information about the above; I'd explicitly exclude >>> performance data from this 'information' - I think that should be >>> communicated by different means (e.g., collectd) >>> >>> Architecturally, the API will be a remote API over HTTP, using a RESTful >>> style; in a nutshell, that means that clients make calls through HTTP >>> requests, with arguments and results suitably encoded - for GET >>> requests, that simply means ordinary request params, for POST, it's TBD >>> which possible ways to serialize data is preferrable. Obvious candidates >>> are XML, YAML, and JSON; right now, I am leaning towards >>> XML. Stylistically, REST uses URL's to represent objects (or 'nouns') >>> and different HTTP methods to retrieve and/or change those objects >>> ('verbs') You can think of the HTTP methods GET, POST, PUT, DELETE as >>> analogous to the SQL actions select, insert, update, and delete, >>> respectively. Or the show/create/update/delete methods in Rails >>> controllers. >>> >>> Besides being lightweight, a RESTful API is also very attractive because >>> of the support for it in Rails 2 (ActionController::Resources on the >>> server side, and ActiveResource for clients) That support takes away a >>> lot of the headaches around serialization of objects, routing etc. >>> >>> >> I would make an argument for XMLRPC/SSL based on that a lot of our >> management applications already have XMLRPC API's (such as >> Spacewalk/Cobbler/etc), and that serialization and more remote faults >> are supported. >> > > That's rubbish - REST is just as expressive as XMLRPC in terms of data > serialization and fault reporting - in fact its more expressive, since > it is not tied into the XMLRPC format. This examples shows one way in > which a fault response used in XMLRPC can trivially be mapped into a > REST style API. > Yes, being able to talk in Esperanto to someone talking Finnish is expressive, and being able to make up your own language is more expressive than that. Yet this is software, and those things are bad :) This fault info as is defined by the Flickr return codes not REST as a specification --- REST allows basically any transport and has almost no conventions. It is a nice hack for mashups, but as a standard or even a well codified specification, it's not one. The data format is not defined. It's expressive because they made it expressive, sure, but at what cost to the caller? Why not use the libraries that are available to make this stuff simple? Most languages (pseudocodey) have XMLRPC libraries that work out of the box and the caller doesn't have to care what your transfer format is or how you express your faults. You don't have to ship a client-side flickr library even, there's no need for one. However, for REST, lots of people /did/ have to write these to make it all glue together appropriately. It would be nice if all languages had something like this for REST like they do for XMLRPC, but this is not possible as the fault system and the interchange formats are not defined import restlibrary_from_standard_distribution as restfoo connection = restfoo.connect("http://blah") try: connection.foo.bar(1,2,3,"baz") except: something else With XMLRPC, that is possible, as that is what it was designed to do. > http://www.flickr.com/services/api/response.rest.html > http://www.flickr.com/services/api/response.xmlrpc.html > > You don't even need to use the same serialization format for errors vs > normal responses since you can distinguish a fault based on the HTTP > return code. > > Since REST is just plain HTTP, the expressiveness is entirely at your > control when defining the data format for your HTTP responses. You get > to choose whether to provide an unstructured text blob response, or a > structured XML document - whichever best suits the needs of the API. > > Daniel > From dlutter at redhat.com Wed Jul 16 21:02:57 2008 From: dlutter at redhat.com (David Lutterkort) Date: Wed, 16 Jul 2008 21:02:57 +0000 Subject: [Ovirt-devel] OVirt public API In-Reply-To: <487E558D.50408@redhat.com> References: <1216163491.19722.20.camel@localhost.localdomain> <487E54F7.3060908@redhat.com> <487E558D.50408@redhat.com> Message-ID: <1216242177.19321.43.camel@localhost.localdomain> On Wed, 2008-07-16 at 16:09 -0400, Michael DeHaan wrote: > Michael DeHaan wrote: > > > > I would make an argument for XMLRPC/SSL based on that a lot of our > > management applications already have XMLRPC API's (such as > > Spacewalk/Cobbler/etc), and that serialization and more remote faults > > are supported. Having an app have to speak to multiple API types if > > of course going to be a reality. > > > > That being said, REST is definitely workable, and as long as there is > > an API, I think most people will be reasonably happy. > > > > Basically with XMLRPC you don't have to write any wrapper code around > > the API caller and it just works as if it were a local API, which is > > nice > > > I should add, embedding XML in an XMLRPC request as a string sounds > weird, but does work. The main benefit is not the format, which is not > perfect, just that there are a lot of nice libraries that make XMLRPC > behave as if it were a local API/module, doing the usual > getattr()/method_missing magic and so forth. This seems to come down to an argument that serialization/deserialization, or in general, support for XMLRPC, is more mature than for REST - I don't doubt that that's true right now, simply because XMLRPC has been around for much longer. With all the attention that REST has been getting, and Rails shunning SOAP/XMLRPC etc. explicitly in favor of rest, it's only a matter of time before REST support in other languages catches up with that for XMLRPC. In the meantime, there are things like pyActiveResource which seems a good start for Pyhton, and alternatively, using well-supported serialization formats like YAML or JSON. One of the things that makes me very hesitant about XMLRPC is that I've been watching it fall apart in the case of puppet - Luke is still trying to dig out from under that decision, and migrating away from it. David From dpierce at redhat.com Wed Jul 16 21:12:42 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 16 Jul 2008 17:12:42 -0400 Subject: [Ovirt-devel] [PATCH] Adding NIC details to ovirt identify stage. Message-ID: <1216242762-25136-1-git-send-email-dpierce@redhat.com> Signed-off-by: Darryl L. Pierce --- ovirt-managed-node/ovirt-managed-node.spec | 2 + ovirt-managed-node/src/Makefile | 6 +- ovirt-managed-node/src/comm.c | 87 +++ ovirt-managed-node/src/debug.c | 48 ++ ovirt-managed-node/src/gather.c | 284 +++++++++ ovirt-managed-node/src/hal_support.c | 65 ++ ovirt-managed-node/src/main.c | 216 +++++++ ovirt-managed-node/src/ovirt-identify-node.c | 653 -------------------- ovirt-managed-node/src/ovirt-identify-node.h | 119 +++- ovirt-managed-node/src/protocol.c | 276 +++++++++ ovirt-managed-node/src/scripts/ovirt-post | 8 +- wui/src/host-browser/host-browser.rb | 84 +++- wui/src/host-browser/test-host-browser-identify.rb | 42 ++- 13 files changed, 1200 insertions(+), 690 deletions(-) create mode 100644 ovirt-managed-node/src/comm.c create mode 100644 ovirt-managed-node/src/debug.c create mode 100644 ovirt-managed-node/src/gather.c create mode 100644 ovirt-managed-node/src/hal_support.c create mode 100644 ovirt-managed-node/src/main.c delete mode 100644 ovirt-managed-node/src/ovirt-identify-node.c create mode 100644 ovirt-managed-node/src/protocol.c diff --git a/ovirt-managed-node/ovirt-managed-node.spec b/ovirt-managed-node/ovirt-managed-node.spec index 4e14b08..0cd3aa8 100644 --- a/ovirt-managed-node/ovirt-managed-node.spec +++ b/ovirt-managed-node/ovirt-managed-node.spec @@ -12,7 +12,9 @@ URL: http://www.ovirt.org/ Requires(post): /sbin/chkconfig Requires(preun): /sbin/chkconfig BuildRequires: libvirt-devel +BuildRequires: dbus-devel hal-devel Requires: libvirt +Requires: hal ExclusiveArch: %{ix86} x86_64 %define app_root %{_datadir}/%{name} diff --git a/ovirt-managed-node/src/Makefile b/ovirt-managed-node/src/Makefile index 1991e46..d5e4093 100644 --- a/ovirt-managed-node/src/Makefile +++ b/ovirt-managed-node/src/Makefile @@ -17,9 +17,9 @@ # also available at http://www.gnu.org/copyleft/gpl.html. CC=gcc -CFLAGS=-Wall -c -g -LFLAGS=-lvirt -OBJECTS=ovirt-identify-node.o +CFLAGS=-Wall -c -g $(shell pkg-config --cflags dbus-1) +LFLAGS=-lhal -lvirt +OBJECTS=comm.o gather.o hal_support.o main.o protocol.o TARGET=ovirt-identify-node SOURCES=\ ovirt-identify-node.c diff --git a/ovirt-managed-node/src/comm.c b/ovirt-managed-node/src/comm.c new file mode 100644 index 0000000..a63a58d --- /dev/null +++ b/ovirt-managed-node/src/comm.c @@ -0,0 +1,87 @@ +/* comm.c -- Contains communications routines. + * + * Copyright (C) 2008 Red Hat, Inc. + * Written by Darryl L. Pierce + * + * 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. + */ + +#include "ovirt-identify-node.h" + +ssize_t saferead(int fd, char *buf, size_t count) +{ + ssize_t bytes,offset; + int len_left; + int done = 0; + + DEBUG("Begin saferead(%d, %p, %d)\n", fd, buf, count); + + offset = 0; + len_left = count; + + + while(!done) + { + DEBUG("Before read(%d,%p,%d)\n",fd,buf+offset,len_left); + + bytes = read(fd, buf+offset, len_left); + + DEBUG("After read: bytes=%d\n", bytes); + + if(bytes == 0) + { + done = 1; + } + else if(bytes > 0) + { + offset += bytes; + len_left -= bytes; + done = 1; + } + else if(errno == EINTR) + { + continue; + } + else + { + done = 1; + } + + DEBUG("End of decision loop: offset=%d, len_left=%dl, done=%d\n",offset, len_left, done); + } + + return offset; +} + +ssize_t safewrite(int fd, const void *buf, size_t count) +{ + size_t nwritten = 0; + while (count > 0) { + ssize_t r = write(fd, buf, count); + + if (r < 0 && errno == EINTR) + continue; + if (r < 0) + return r; + if (r == 0) + return nwritten; + buf = (const char *)buf + r; + count -= r; + nwritten += r; + } + return nwritten; +} + diff --git a/ovirt-managed-node/src/debug.c b/ovirt-managed-node/src/debug.c new file mode 100644 index 0000000..807d88b --- /dev/null +++ b/ovirt-managed-node/src/debug.c @@ -0,0 +1,48 @@ +/* debug.c -- Debugging methods. + * + * Copyright (C) 2008 Red Hat, Inc. + * Written by Darryl L. Pierce + * + * 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. + */ + +#include "ovirt-identify-node.h" + +void debug_cpu_info(void) +{ + fprintf(stdout,"Node Info:\n"); + fprintf(stdout," UUID: %s\n", uuid); + fprintf(stdout," Arch: %s\n", arch); + fprintf(stdout," Memory: %s\n", memsize); + + t_cpu_info* current = cpu_info; + while(current != NULL) + { + fprintf(stdout,"\n"); + fprintf(stdout," CPU Number: %s\n", current->cpu_num); + fprintf(stdout," Core Number: %s\n", current->core_num); + fprintf(stdout,"Number of Cores: %s\n", current->number_of_cores); + fprintf(stdout," Vendor: %s\n", current->vendor); + fprintf(stdout," Model: %s\n", current->model); + fprintf(stdout," Family: %s\n", current->family); + fprintf(stdout," CPUID Level: %s\n", current->cpuid_level); + fprintf(stdout," CPU Speed: %s\n", current->speed); + fprintf(stdout," Cache Size: %s\n", current->cache); + fprintf(stdout," CPU Flags: %s\n", current->flags); + + current = current->next; + } +} diff --git a/ovirt-managed-node/src/gather.c b/ovirt-managed-node/src/gather.c new file mode 100644 index 0000000..c7f6278 --- /dev/null +++ b/ovirt-managed-node/src/gather.c @@ -0,0 +1,284 @@ +/* gather.c -- Contains methods for collecting data about the system. + * + * Copyright (C) 2008 Red Hat, Inc. + * Written by Darryl L. Pierce + * + * 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. + */ + +#include "ovirt-identify-node.h" + +int init_gather(void) +{ + int result = 1; + + hal_ctx = get_hal_ctx(); + + if(hal_ctx != NULL) + { + result = 0; + } + + return result; +} + +int get_uuid(void) +{ + const char* udi = "/org/freedesktop/Hal/devices/computer"; + const char* key = "system.hardware.uuid"; + + VERBOSE("Getting system UUID.\n"); + + int result = 1; + int type; + + type = libhal_device_get_property_type(hal_ctx,udi,key,&dbus_error); + + if(type == LIBHAL_PROPERTY_TYPE_STRING) + { + char* value; + + DEBUG("%s/%s=%d\n",udi,key,type); + + value = libhal_device_get_property_string(hal_ctx,udi,key,&dbus_error); + snprintf(uuid,BUFFER_LENGTH,"%s",value); + + DEBUG("UUID=%s\n",uuid); + + result = 0; + } + + return result; +} + +/* Creates a new instance of type t_cpu_info and places it into the + * linked list of CPUs. + */ +t_cpu_info* create_cpu_info(void) +{ + t_cpu_info* result = calloc(1,sizeof(t_cpu_info)); + bzero(result,sizeof(t_cpu_info)); + + strcpy(result->core_num,"0"); + strcpy(result->number_of_cores,"1"); + + return result; +} + +int get_cpu_info(void) +{ + int result = 1; + FILE* inputfd; + t_cpu_info* current = NULL; + + /* in order to support Xen, this data will need to be gathered + * from libvirt rather than directly from cpuinfo + */ + if(( inputfd = fopen("/proc/cpuinfo","rb")) != NULL) + { + VERBOSE("Parsing CPU information\n"); + do + { + char buffer[255]; + char label[BUFFER_LENGTH]; + char value[BUFFER_LENGTH]; + + fgets(buffer, 255, inputfd); + if(strlen(buffer) > 0) buffer[strlen(buffer) - 1] = '\0'; + + get_label_and_value(buffer, + label,BUFFER_LENGTH, + value,BUFFER_LENGTH); + + DEBUG("label=\"%s\", value=\"%s\"\n", label, value); + + if(strlen(label)) + { + if(!strcmp(label,"processor")) + { + VERBOSE("Starting new CPU\n"); + + t_cpu_info* last = current; + + current = create_cpu_info(); + if(last != NULL) + { + last->next = current; + } + else + { + cpu_info = current; + } + + COPY_VALUE_TO_BUFFER(value,current->cpu_num,BUFFER_LENGTH); + } + else + /* core id and number of cores is not correct on + * Xen machines + */ + if(!strcmp(label,"core id")) + { + COPY_VALUE_TO_BUFFER(value,current->core_num,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cpu cores")) + { + COPY_VALUE_TO_BUFFER(value,current->number_of_cores,BUFFER_LENGTH); + } + else + if(!strcmp(label,"vendor_id")) + { + COPY_VALUE_TO_BUFFER(value,current->vendor,BUFFER_LENGTH); + } + else + if(!strcmp(label,"model")) + { + COPY_VALUE_TO_BUFFER(value,current->model,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cpu family")) + { + COPY_VALUE_TO_BUFFER(value,current->family,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cpuid level")) + { + COPY_VALUE_TO_BUFFER(value,current->cpuid_level,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cpu MHz")) + { + COPY_VALUE_TO_BUFFER(value,current->speed,BUFFER_LENGTH); + } + else + if(!strcmp(label,"cache size")) + { + COPY_VALUE_TO_BUFFER(value,current->cache,BUFFER_LENGTH); + } + else + if(!strcmp(label,"flags")) + { + COPY_VALUE_TO_BUFFER(value,current->flags,BUFFER_LENGTH); + } + } + + } while(!feof(inputfd)); + + fclose(inputfd); + + result = 0; + } + else + { + VERBOSE("Unable to open /proc/cpuinfo\n"); + } + + return result; +} + +/* Creates a new instance of type t_nic_info. + */ +t_nic_info* create_nic_info(void) +{ + t_nic_info* result = calloc(1,sizeof(t_nic_info)); + bzero(result,sizeof(t_nic_info)); + + return result; +} + +/* Determines the speed of the network interface. + */ +void get_nic_data(char* nic,t_nic_info* nic_info) +{ + char* interface; + struct ifreq ifr; + int sockfd; + struct ethtool_cmd ecmd; + + interface = libhal_device_get_property_string(hal_ctx,nic,"net.interface", + &dbus_error); + bzero(&ifr,sizeof(struct ifreq)); + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if(sockfd >= 0) + { + int bandwidth; + + ifr.ifr_addr.sa_family = AF_INET; + strncpy(ifr.ifr_name,interface,IFNAMSIZ-1); + + ioctl(sockfd, SIOCETHTOOL, &ifr); + close(sockfd); + + bandwidth = 10; + if (ecmd.supported & SUPPORTED_10000baseT_Full) + bandwidth = 10000; + else if (ecmd.supported & SUPPORTED_2500baseX_Full) + bandwidth = 2500; + else if (ecmd.supported & (SUPPORTED_1000baseT_Half|SUPPORTED_1000baseT_Full)) + bandwidth = 1000; + else if (ecmd.supported & (SUPPORTED_100baseT_Half|SUPPORTED_100baseT_Full)) + bandwidth = 100; + else if (ecmd.supported & (SUPPORTED_10baseT_Half|SUPPORTED_10baseT_Full)) + bandwidth = 10; + + snprintf(nic_info->bandwidth,BUFFER_LENGTH,"%d",bandwidth); + } +} + +int get_nic_info(void) +{ + int result = 0; + t_nic_info* current = NULL; + t_nic_info* last = NULL; + + char** nics; + int num_results; + int index; + + nics = libhal_find_device_by_capability(hal_ctx,"net", + &num_results,&dbus_error); + + DEBUG("Found %d NICs\n", num_results); + + for(index = 0;index < num_results;index++) + { + char* nic = nics[index]; + + VERBOSE("Starting new NIC.\n"); + + if(current != NULL) + { + last = current; + current = create_nic_info(); + last->next = current; + } + else + { + nic_info = current = create_nic_info(); + } + + snprintf(current->mac_address,BUFFER_LENGTH,"%s", + libhal_device_get_property_string(hal_ctx,nic,"net.address", + &dbus_error)); + get_nic_data(nic,current); + + DEBUG("NIC details: MAC:%s, speed:%s, IP:%s\n", + nic_info->mac_address, nic_info->bandwidth,nic_info->ip_address); + } + + return result; +} diff --git a/ovirt-managed-node/src/hal_support.c b/ovirt-managed-node/src/hal_support.c new file mode 100644 index 0000000..58ee29b --- /dev/null +++ b/ovirt-managed-node/src/hal_support.c @@ -0,0 +1,65 @@ +/* hal_support.c -- Interfaces with the HAL libraries. + * + * Copyright (C) 2008 Red Hat, Inc. + * Written by Darryl L. Pierce + * + * 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. + */ + +#include "ovirt-identify-node.h" + +DBusConnection* dbus_connection; +DBusError dbus_error; + +LibHalContext* get_hal_ctx(void) +{ + LibHalContext* result = NULL; + LibHalContext* ctx; + + ctx = libhal_ctx_new(); + if(ctx != NULL) + { + dbus_error_init(&dbus_error); + dbus_connection = dbus_bus_get(DBUS_BUS_SYSTEM,&dbus_error); + + if(!dbus_error_is_set(&dbus_error)) + { + libhal_ctx_set_dbus_connection(ctx,dbus_connection); + + if(libhal_ctx_init(ctx,&dbus_error)) + { + result = ctx; + } + else + { + fprintf(stderr,"Failed to initial libhal context: %s : %s\n", + dbus_error.name, dbus_error.message); + } + } + else + { + fprintf(stderr,"Unable to connect to system bus: %s : %s\n", + dbus_error.name, dbus_error.message); + dbus_error_free(&dbus_error); + } + } + else + { + fprintf(stderr,"Unable to initialize HAL context.\n"); + } + + return result; +} diff --git a/ovirt-managed-node/src/main.c b/ovirt-managed-node/src/main.c new file mode 100644 index 0000000..29e08a5 --- /dev/null +++ b/ovirt-managed-node/src/main.c @@ -0,0 +1,216 @@ +/* identify-node -- Main entry point for the identify-node utility. + * + * Copyright (C) 2008 Red Hat, Inc. + * Written by Darryl L. Pierce + * + * 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. + */ + +#include "ovirt-identify-node.h" + +int debug = 0; +int verbose = 0; +int testing = 0; + +char arch[BUFFER_LENGTH]; +char uuid[BUFFER_LENGTH]; +char memsize[BUFFER_LENGTH]; +char numcpus[BUFFER_LENGTH]; +char cpuspeed[BUFFER_LENGTH]; +char *hostname; +int hostport = -1; +int socketfd; +t_cpu_info* cpu_info; +t_nic_info* nic_info; + +LibHalContext* hal_ctx; + +int main(int argc,char** argv) +{ + int result = 1; + virConnectPtr connection; + virNodeInfo info; + + fprintf(stdout,"Sending managed node details to server.\n"); + + if(!config(argc,argv)) + { + VERBOSE("Connecting to libvirt.\n"); + + connection = virConnectOpenReadOnly(testing ? "test:///default" : NULL); + + DEBUG("connection=%p\n",connection); + + if(connection) + { + VERBOSE("Retrieving node information.\n"); + if(!virNodeGetInfo(connection,&info)) + { + snprintf(arch, BUFFER_LENGTH, "%s", info.model); + snprintf(memsize, BUFFER_LENGTH, "%ld", info.memory); + + cpu_info = NULL; + nic_info = NULL; + + if(!init_gather() && !get_uuid() && !get_cpu_info() && !get_nic_info()) + { + if(!start_conversation() && !send_details() && !end_conversation()) + { + fprintf(stdout,"Finished!\n"); + result = 0; + } + } + else + { + VERBOSE("Failed to get CPU info.\n"); + } + } + else + { + VERBOSE("Failed to get node info.\n"); + } + } + else + { + VERBOSE("Could not connect to libvirt.\n"); + } + } + else + { + usage(); + } + + return result; +} + +int config(int argc,char** argv) +{ + int result = 0; + int option; + + while((option = getopt(argc,argv,"s:p:dvth")) != -1) + { + DEBUG("Processing argument: %c (optarg:%s)\n",option,optarg); + + switch(option) + { + case 's': hostname = optarg; break; + case 'p': hostport = atoi(optarg); break; + case 't': testing = 1; break; + case 'd': debug = 1; break; + case 'v': verbose = 1; break; + case 'h': + // fall thru + default : result = 1; break; + } + } + + // verify that required options are provided + if(hostname == NULL || strlen(hostname) == 0) + { + fprintf(stderr,"ERROR: The server name is required. (-s [hostname])\n"); + result = 1; + } + + if(hostport <= 0) + { + fprintf(stderr,"ERROR: The server port is required. (-p [port])\n"); + result = 1; + } + + return result; +} + +void usage() +{ + fprintf(stdout,"\n"); + fprintf(stdout,"Usage: ovirt-identify [OPTION]\n"); + fprintf(stdout,"\n"); + fprintf(stdout,"\t-s [server]\t\tThe remote server's hostname.\n"); + fprintf(stdout,"\t-p [port]\t\tThe remote server's port.\n"); + fprintf(stdout,"\t-d\t\tDisplays debug information during execution.\n"); + fprintf(stdout,"\t-v\t\tDisplays verbose information during execution.\n"); + fprintf(stdout,"\t-h\t\tDisplays this help information and then exits.\n"); + fprintf(stdout,"\n"); +} + +void get_label_and_value(char* text, + char* label, size_t label_length, + char* value, size_t value_length) +{ + int offset = 0; + int which = 0; /* 0 = label, 1 = value */ + char* current = text; + + /* iterate through the text supplied and find where the + * label ends with a colon, then copy that into the supplied + * label buffer and trim any trailing spaces + */ + + while(current != NULL && *current != '\0') + { + /* if we're on the separator, then switch modes and reset + * the offset indicator, otherwise just process the character + */ + if(which == 0 && *current == ':') + { + which = 1; + offset = 0; + } + else + { + char* buffer = (which == 0 ? label : value); + int length = (which == 0 ? label_length : value_length); + + /* only copy if we're past the first character and it's not + * a space + */ + if((offset > 0 || (*current != 9 && *current != ' ')) && offset < (length - 1)) + { + buffer[offset++] = *current; + buffer[offset] = 0; + } + } + + current++; + } + + /* now trim all trailing spaces from the values */ + while(label[strlen(label) - 1 ] == 9) + label[strlen(label) - 1] = 0; + while(value[strlen(value) - 1] == 9) + value[strlen(value) - 1] = 0; +} + +int get_text(const char *const expected) +{ + int result = 1; + int received; + char buffer[BUFFER_LENGTH]; + bzero(buffer,BUFFER_LENGTH); + + VERBOSE( "Looking to receive %s\n", expected); + + received = saferead(socketfd, buffer, BUFFER_LENGTH); + + buffer[received - 1] = 0; + + VERBOSE("Received \"%s\": size=%d (trimmed ending carriage return)\n", buffer, received); + + result = strcmp(expected,buffer); + + return result; +} diff --git a/ovirt-managed-node/src/ovirt-identify-node.c b/ovirt-managed-node/src/ovirt-identify-node.c deleted file mode 100644 index f114d81..0000000 --- a/ovirt-managed-node/src/ovirt-identify-node.c +++ /dev/null @@ -1,653 +0,0 @@ -/* identify-node -- Main entry point for the identify-node utility. - * - * Copyright (C) 2008 Red Hat, Inc. - * Written by Darryl L. Pierce - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ovirt-identify-node.h" - -int main(int argc,char** argv) -{ - int result = 1; - virConnectPtr connection; - virNodeInfo info; - - fprintf(stdout,"Sending managed node details to server.\n"); - - if(!config(argc,argv)) - { - if(verbose) fprintf(stdout,"Connecting to libvirt.\n"); - - connection = virConnectOpenReadOnly(testing ? "test:///default" : NULL); - - if(debug) fprintf(stderr,"connection=%p\n",connection); - - if(connection) - { - if(verbose) fprintf(stdout,"Getting hostname: %s\n", uuid); - if(!strlen(uuid)) gethostname(uuid,sizeof uuid); - - if(verbose) fprintf(stdout,"Retrieving node information.\n"); - if(!virNodeGetInfo(connection,&info)) - { - snprintf(arch, BUFFER_LENGTH, "%s", info.model); - snprintf(memsize, BUFFER_LENGTH, "%ld", info.memory); - - cpu_info = NULL; - - if(!get_cpu_info()) - { - if(verbose) fprintf(stdout, "Getting CPU info.\n"); - - if(debug) - { - fprintf(stdout,"Node Info:\n"); - fprintf(stdout," UUID: %s\n", uuid); - fprintf(stdout," Arch: %s\n", arch); - fprintf(stdout," Memory: %s\n", memsize); - - t_cpu_info* current = cpu_info; - while(current != NULL) - { - fprintf(stdout,"\n"); - fprintf(stdout," CPU Number: %s\n", current->cpu_num); - fprintf(stdout," Core Number: %s\n", current->core_num); - fprintf(stdout,"Number of Cores: %s\n", current->number_of_cores); - fprintf(stdout," Vendor: %s\n", current->vendor); - fprintf(stdout," Model: %s\n", current->model); - fprintf(stdout," Family: %s\n", current->family); - fprintf(stdout," CPUID Level: %s\n", current->cpuid_level); - fprintf(stdout," CPU Speed: %s\n", current->speed); - fprintf(stdout," Cache Size: %s\n", current->cache); - fprintf(stdout," CPU Flags: %s\n", current->flags); - - current = current->next; - } - } - - if(verbose) fprintf(stdout, "Retrieved node information.\n"); - - if(!start_conversation() && !send_details() && !end_conversation()) - { - fprintf(stdout,"Finished!\n"); - result = 0; - } - } - else - { - if(verbose) fprintf(stderr,"Failed to get CPU info.\n"); - } - } - else - { - if(verbose) fprintf(stderr,"Failed to get node info.\n"); - } - } - else - { - if(verbose) fprintf(stderr,"Could not connect to libvirt.\n"); - } - } - else - { - usage(); - } - - return result; -} - -int config(int argc,char** argv) -{ - int result = 0; - int option; - - while((option = getopt(argc,argv,"s:p:u:dvth")) != -1) - { - if(debug) fprintf(stdout,"Processing argument: %c (optarg:%s)\n",option,optarg); - - switch(option) - { - case 's': hostname = optarg; break; - case 'p': hostport = atoi(optarg); break; - case 'u': snprintf(uuid,VIR_UUID_BUFLEN,"%s",optarg); break; - case 't': testing = 1; break; - case 'd': debug = 1; break; - case 'v': verbose = 1; break; - case 'h': - // fall thru - default : result = 1; break; - } - } - - // verify that required options are provided - if(hostname == NULL || strlen(hostname) == 0) - { - fprintf(stderr,"ERROR: The server name is required. (-s [hostname])\n"); - result = 1; - } - - if(hostport <= 0) - { - fprintf(stderr,"ERROR: The server port is required. (-p [port])\n"); - result = 1; - } - - return result; -} - -void usage() -{ - fprintf(stdout,"\n"); - fprintf(stdout,"Usage: ovirt-identify [OPTION]\n"); - fprintf(stdout,"\n"); - fprintf(stdout,"\t-s [server]\t\tThe remote server's hostname.\n"); - fprintf(stdout,"\t-p [port]\t\tThe remote server's port.\n"); - fprintf(stdout,"\t-d\t\tDisplays debug information during execution.\n"); - fprintf(stdout,"\t-v\t\tDisplays verbose information during execution.\n"); - fprintf(stdout,"\t-h\t\tDisplays this help information and then exits.\n"); - fprintf(stdout,"\n"); -} - -int start_conversation(void) -{ - int result = 1; - - if(verbose || debug) fprintf(stdout,"Starting conversation with %s:%d.\n",hostname,hostport); - - if(!create_connection()) - { - if(debug || verbose) fprintf(stdout,"Connected.\n"); - - if (!get_text("HELLO?")) - { - if(verbose) fprintf(stdout,"Checking for handshake.\n"); - - if(!send_text("HELLO!")) - { - if(verbose) fprintf(stdout,"Handshake received. Starting conversation.\n"); - - if(!get_text("MODE?")) - { - if(verbose) fprintf(stdout,"Shifting to IDENTIFY mode.\n"); - - if(!send_text("IDENTIFY")) result = 0; - } - else - { - if(verbose) fprintf(stderr,"Was not asked for a mode.\n"); - } - } - } - else - { - if(verbose) fprintf(stderr,"Did not receive a proper handshake.\n"); - } - } - - else - { - if(verbose) fprintf(stderr,"Did not get a connection.\n"); - } - - if(debug) fprintf(stdout,"start_conversation: result=%d\n", result); - - return result; -} - -int send_value(char* label,char* value) -{ - char buffer[BUFFER_LENGTH]; - int result = 1; - char expected[BUFFER_LENGTH]; - - snprintf(buffer,BUFFER_LENGTH,"%s=%s", label, value); - - if(!send_text(buffer)) - { - snprintf(expected, BUFFER_LENGTH, "ACK %s", label); - - if(verbose) fprintf(stdout,"Expecting \"%s\"\n", expected); - - result = get_text(expected); - } - - return result; -} - -int send_details(void) -{ - int result = 1; - - if(verbose) fprintf(stdout,"Sending node details.\n"); - - if (!get_text("INFO?")) - { - if((!send_value("ARCH", arch)) && - (!send_value("UUID", uuid)) && - (!send_value("MEMSIZE", memsize)) && - (!send_cpu_details())) - { - if(!send_text("ENDINFO")) result = 0; - } - } - else - { - if(verbose) fprintf(stdout,"Was not interrogated for hardware info.\n"); - } - - return result; -} - -int send_cpu_details(void) -{ - int result = 1; - t_cpu_info* current = cpu_info; - - while(current != NULL) - { - send_text("CPU"); - - if(!(get_text("CPUINFO?")) && - (!send_value("CPUNUM",current->cpu_num)) && - (!send_value("CORENUM",current->core_num)) && - (!send_value("NUMCORES",current->number_of_cores)) && - (!send_value("VENDOR",current->vendor)) && - (!send_value("MODEL",current->model)) && - (!send_value("FAMILY",current->family)) && - (!send_value("CPUIDLVL",current->cpuid_level)) && - (!send_value("SPEED",current->speed)) && - (!send_value("CACHE", current->cache)) && - (!send_value("FLAGS", current->flags))) - { - send_text("ENDCPU"); - result = get_text("ACK CPU"); - } - - current = current->next; - } - - - return result; -} - -int end_conversation(void) -{ - int result = 0; - - if(debug || verbose) fprintf(stdout,"Ending conversation.\n"); - - send_text("ENDINFO"); - - close(socketfd); - - return result; -} - -void get_label_and_value(char* text, - char* label, size_t label_length, - char* value, size_t value_length) -{ - int offset = 0; - int which = 0; /* 0 = label, 1 = value */ - char* current = text; - - /* iterate through the text supplied and find where the - * label ends with a colon, then copy that into the supplied - * label buffer and trim any trailing spaces - */ - - while(current != NULL && *current != '\0') - { - /* if we're on the separator, then switch modes and reset - * the offset indicator, otherwise just process the character - */ - if(which == 0 && *current == ':') - { - which = 1; - offset = 0; - } - else - { - char* buffer = (which == 0 ? label : value); - int length = (which == 0 ? label_length : value_length); - - /* only copy if we're past the first character and it's not - * a space - */ - if((offset > 0 || (*current != 9 && *current != ' ')) && offset < (length - 1)) - { - buffer[offset++] = *current; - buffer[offset] = 0; - } - } - - current++; - } - - /* now trim all trailing spaces from the values */ - while(label[strlen(label) - 1 ] == 9) - label[strlen(label) - 1] = 0; - while(value[strlen(value) - 1] == 9) - value[strlen(value) - 1] = 0; -} - -int get_cpu_info(void) -{ - int result = 1; - FILE* inputfd; - t_cpu_info* current = NULL; - - if(( inputfd = fopen("/proc/cpuinfo","rb")) != NULL) - { - if(verbose) fprintf(stdout,"Parsing CPU information\n"); - do - { - char buffer[255]; - char label[BUFFER_LENGTH]; - char value[BUFFER_LENGTH]; - - fgets(buffer, 255, inputfd); - if(strlen(buffer) > 0) buffer[strlen(buffer) - 1] = '\0'; - - get_label_and_value(buffer, - label,BUFFER_LENGTH, - value,BUFFER_LENGTH); - - if(debug) - fprintf(stdout,"label=\"%s\", value=\"%s\"\n", label, value); - - if(strlen(label)) - { - if(!strcmp(label,"processor")) - { - if(debug || verbose) - fprintf(stdout,"Starting new CPU\n"); - - t_cpu_info* last = current; - - current = create_cpu_info(); - if(last != NULL) - { - last->next = current; - } - else - { - cpu_info = current; - } - - COPY_VALUE_TO_BUFFER(value,current->cpu_num,BUFFER_LENGTH); - } - else - if(!strcmp(label,"core id")) - { - COPY_VALUE_TO_BUFFER(value,current->core_num,BUFFER_LENGTH); - } - else - if(!strcmp(label,"cpu cores")) - { - COPY_VALUE_TO_BUFFER(value,current->number_of_cores,BUFFER_LENGTH); - } - else - if(!strcmp(label,"vendor_id")) - { - COPY_VALUE_TO_BUFFER(value,current->vendor,BUFFER_LENGTH); - } - else - if(!strcmp(label,"model")) - { - COPY_VALUE_TO_BUFFER(value,current->model,BUFFER_LENGTH); - } - else - if(!strcmp(label,"cpu family")) - { - COPY_VALUE_TO_BUFFER(value,current->family,BUFFER_LENGTH); - } - else - if(!strcmp(label,"cpuid level")) - { - COPY_VALUE_TO_BUFFER(value,current->cpuid_level,BUFFER_LENGTH); - } - else - if(!strcmp(label,"cpu MHz")) - { - COPY_VALUE_TO_BUFFER(value,current->speed,BUFFER_LENGTH); - } - else - if(!strcmp(label,"cache size")) - { - COPY_VALUE_TO_BUFFER(value,current->cache,BUFFER_LENGTH); - } - else - if(!strcmp(label,"flags")) - { - COPY_VALUE_TO_BUFFER(value,current->flags,BUFFER_LENGTH); - } - } - - } while(!feof(inputfd)); - - fclose(inputfd); - - result = 0; - } - else - { - if(verbose) fprintf(stderr,"Unable to open /proc/cpuinfo\n"); - } - - return result; -} - -t_cpu_info* create_cpu_info(void) -{ - t_cpu_info* result = calloc(1,sizeof(t_cpu_info)); - bzero(result,sizeof(t_cpu_info)); - - strcpy(result->core_num,"0"); - strcpy(result->number_of_cores,"1"); - - - return result; -} - -ssize_t safewrite(int fd, const void *buf, size_t count) -{ - size_t nwritten = 0; - while (count > 0) { - ssize_t r = write(fd, buf, count); - - if (r < 0 && errno == EINTR) - continue; - if (r < 0) - return r; - if (r == 0) - return nwritten; - buf = (const char *)buf + r; - count -= r; - nwritten += r; - } - return nwritten; -} - -int send_text(char* text) -{ - int result = 1; - int sent; - - if(verbose) fprintf(stdout,"Sending: \"%s\"\n", text); - - sent = safewrite(socketfd, text, strlen(text)); - sent += safewrite(socketfd, "\n", 1); - - if(sent >= 0) - { - if(debug) fprintf(stdout,"Sent %d bytes total.\n", sent); - - result = 0; - } - - return result; -} - -int saferead(int fd, char *buf, size_t count) -{ - ssize_t bytes,offset; - int len_left; - int done = 0; - - if(debug) fprintf(stdout,"Begin saferead(%d, %p, %ld)\n", fd, buf, count); - - offset = 0; - len_left = count; - - - while(!done) - { - if(debug) fprintf(stdout,"Before read(%ld,%p,%ld)\n",fd,buf+offset,len_left); - - bytes = read(fd, buf+offset, len_left); - - if(debug) fprintf(stdout,"After read: bytes=%ld\n", bytes); - - if(bytes == 0) - { - done = 1; - } - else if(bytes > 0) - { - offset += bytes; - len_left -= bytes; - done = 1; - } - else if(errno == EINTR) - { - continue; - } - else - { - done = 1; - } - - if(debug) fprintf(stdout,"End of decision loop: offset=%ld, len_left=%dl, done=%d\n",offset, len_left, done); - } - - return offset; -} - -int get_text(const char *const expected) -{ - int result = 1; - int received; - char buffer[BUFFER_LENGTH]; - bzero(buffer,BUFFER_LENGTH); - - if(verbose) fprintf(stdout, "Looking to receive %s\n", expected); - - received = saferead(socketfd, buffer, BUFFER_LENGTH); - - buffer[received - 1] = 0; - - if(verbose) fprintf(stdout,"Received \"%s\": size=%d (trimmed ending carriage return)\n", buffer, received); - - result = strcmp(expected,buffer); - - return result; -} - -int create_connection(void) -{ - int result = 1; - struct addrinfo hints; - struct addrinfo* results; - char port[6]; - struct addrinfo* rptr; - - if(verbose) fprintf(stdout,"Creating the socket connection.\n"); - - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = 0; - hints.ai_protocol = 0; - - if(verbose) fprintf(stdout,"Searching for host candidates.\n"); - - snprintf(port, 6, "%d", hostport); - - if(!getaddrinfo(hostname, port, &hints, &results)) - { - if(verbose) fprintf(stdout,"Got address information. Searching for a proper entry.\n"); - - for(rptr = results; rptr != NULL; rptr = rptr->ai_next) - { - if(debug) - { - fprintf(stdout,"Attempting connection: family=%d, socket type=%d, protocol=%d\n", - rptr->ai_family, rptr->ai_socktype, rptr->ai_protocol); - } - - socketfd = socket(rptr->ai_family, rptr->ai_socktype, rptr->ai_protocol); - - if(socketfd == -1) - { - continue; - } - - if(connect(socketfd, rptr->ai_addr, rptr->ai_addrlen) != -1) - { - break; - } - - // invalid connection, so close it - if(verbose) fprintf(stdout, "Invalid connection.\n"); - close(socketfd); - } - - if(rptr == NULL) - { - if(verbose) fprintf(stdout,"Unable to connect to server %s:%d\n", hostname, hostport); - } - else - { - // success - result = 0; - } - - freeaddrinfo(results); - } - else - { - if(verbose) fprintf(stderr,"No hosts found. Exiting...\n"); - } - - if(debug) fprintf(stdout, "create_connection: result=%d\n", result); - - return result; -} diff --git a/ovirt-managed-node/src/ovirt-identify-node.h b/ovirt-managed-node/src/ovirt-identify-node.h index 1cb1526..fd1bc0a 100644 --- a/ovirt-managed-node/src/ovirt-identify-node.h +++ b/ovirt-managed-node/src/ovirt-identify-node.h @@ -1,6 +1,49 @@ +/* Copyright (C) 2008 Red Hat, Inc. + * Written by Darryl L. Pierce + * + * 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. + */ + #ifndef __OVIRT_IDENTIFY_NODE_H #define __OVIRT_IDENTIFY_NODE_H +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include +#include +#include + +#include + +#include +#include +#include + #define BUFFER_LENGTH 128 #define CPU_FLAGS_BUFFER_LENGTH 256 @@ -18,39 +61,71 @@ typedef struct _cpu_info { struct _cpu_info* next; } t_cpu_info; -#define COPY_VALUE_TO_BUFFER(value,buffer,length) \ - snprintf(buffer,length,"%s",value) +typedef struct _nic_info { + char mac_address[BUFFER_LENGTH]; + char bandwidth[BUFFER_LENGTH]; + char ip_address[BUFFER_LENGTH]; + struct _nic_info* next; +} t_nic_info; int config(int argc,char** argv); void usage(void); -int start_conversation(void); -int send_details(void); -int send_cpu_details(void); -int end_conversation(void); - void get_label_and_value(char* text, char* label,size_t label_length, char* value,size_t value_length); -t_cpu_info* create_cpu_info(void); -int get_cpu_info(void); int send_text(char* text); int get_text(const char *const expected); + +/* comm.c */ +ssize_t saferead(int fd, char *buf, size_t count); +ssize_t safewrite(int fd, const void *buf, size_t count); + +/* debug.c */ +void debug_cpu_info(void); + +/* gather.c */ +int init_gather(void); +int get_uuid(void); +int get_cpu_info(void); +int get_nic_info(void); + +/* hal_support.c */ +LibHalContext* get_hal_ctx(void); + +/* protocol.c */ int create_connection(void); +int start_conversation(void); +int send_details(void); +int end_conversation(void); +int send_value(char* label,char* value); +int send_text(char* text); + +/* variables */ +extern int debug; +extern int verbose; +extern int testing; + +extern char arch[BUFFER_LENGTH]; +extern char uuid[BUFFER_LENGTH]; +extern char memsize[BUFFER_LENGTH]; +extern char numcpus[BUFFER_LENGTH]; +extern char cpuspeed[BUFFER_LENGTH]; +extern char *hostname; +extern int hostport; +extern int socketfd; +extern t_cpu_info* cpu_info; +extern t_nic_info* nic_info; -int debug = 0; -int verbose = 0; -int testing = 0; - -char arch[BUFFER_LENGTH]; -char uuid[VIR_UUID_BUFLEN]; -char memsize[BUFFER_LENGTH]; -char numcpus[BUFFER_LENGTH]; -char cpuspeed[BUFFER_LENGTH]; -char *hostname; -int hostport = -1; -int socketfd; -t_cpu_info* cpu_info; +extern DBusConnection* dbus_connection; +extern DBusError dbus_error; +extern LibHalContext* hal_ctx; + +/* macros */ +#define DEBUG(arg...) if(debug) fprintf(stderr, ##arg) +#define VERBOSE(arg...) if(verbose) fprintf(stdout, ##arg) +#define COPY_VALUE_TO_BUFFER(value,buffer,length) \ + snprintf(buffer,length,"%s",value) #endif diff --git a/ovirt-managed-node/src/protocol.c b/ovirt-managed-node/src/protocol.c new file mode 100644 index 0000000..111a1c1 --- /dev/null +++ b/ovirt-managed-node/src/protocol.c @@ -0,0 +1,276 @@ +/* protocol.c -- Manages the communication between the managed node and + * the oVirt server. + * + * Copyright (C) 2008 Red Hat, Inc. + * Written by Darryl L. Pierce + * + * 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. + */ + +#include "ovirt-identify-node.h" + +int create_connection(void) +{ + int result = 1; + struct addrinfo hints; + struct addrinfo* results; + char port[6]; + struct addrinfo* rptr; + + VERBOSE("Creating the socket connection.\n"); + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = 0; + hints.ai_protocol = 0; + + VERBOSE("Searching for host candidates.\n"); + + snprintf(port, 6, "%d", hostport); + + if(!getaddrinfo(hostname, port, &hints, &results)) + { + VERBOSE("Got address information. Searching for a proper entry.\n"); + + for(rptr = results; rptr != NULL; rptr = rptr->ai_next) + { + if(debug) + { + fprintf(stdout,"Attempting connection: family=%d, socket type=%d, protocol=%d\n", + rptr->ai_family, rptr->ai_socktype, rptr->ai_protocol); + } + + socketfd = socket(rptr->ai_family, rptr->ai_socktype, rptr->ai_protocol); + + if(socketfd == -1) + { + continue; + } + + if(connect(socketfd, rptr->ai_addr, rptr->ai_addrlen) != -1) + { + break; + } + + // invalid connection, so close it + VERBOSE( "Invalid connection.\n"); + close(socketfd); + } + + if(rptr == NULL) + { + VERBOSE("Unable to connect to server %s:%d\n", hostname, hostport); + } + else + { + // success + result = 0; + } + + freeaddrinfo(results); + } + else + { + VERBOSE("No hosts found. Exiting...\n"); + } + + DEBUG( "create_connection: result=%d\n", result); + + return result; +} + +int start_conversation(void) +{ + int result = 1; + + VERBOSE("Starting conversation with %s:%d.\n",hostname,hostport); + + if(!create_connection()) + { + VERBOSE("Connected.\n"); + + if (!get_text("HELLO?")) + { + VERBOSE("Checking for handshake.\n"); + + if(!send_text("HELLO!")) + { + VERBOSE("Handshake received. Starting conversation.\n"); + + if(!get_text("MODE?")) + { + VERBOSE("Shifting to IDENTIFY mode.\n"); + + if(!send_text("IDENTIFY")) result = 0; + } + else + { + VERBOSE("Was not asked for a mode.\n"); + } + } + } + else + { + VERBOSE("Did not receive a proper handshake.\n"); + } + } + + else + { + VERBOSE("Did not get a connection.\n"); + } + + DEBUG("start_conversation: result=%d\n", result); + + return result; +} + +/* Transmits the CPU details to the server. + */ +int send_cpu_details(void) +{ + int result = 1; + t_cpu_info* current = cpu_info; + + while(current != NULL) + { + send_text("CPU"); + + if(!(get_text("CPUINFO?")) && + (!send_value("CPUNUM",current->cpu_num)) && + (!send_value("CORENUM",current->core_num)) && + (!send_value("NUMCORES",current->number_of_cores)) && + (!send_value("VENDOR",current->vendor)) && + (!send_value("MODEL",current->model)) && + (!send_value("FAMILY",current->family)) && + (!send_value("CPUIDLVL",current->cpuid_level)) && + (!send_value("SPEED",current->speed)) && + (!send_value("CACHE", current->cache)) && + (!send_value("FLAGS", current->flags))) + { + send_text("ENDCPU"); + result = get_text("ACK CPU"); + } + + current = current->next; + } + + + return result; +} + +/* Transmits the NIC details to the server. + */ +int send_nic_details(void) +{ + int result = 1; + t_nic_info* current = nic_info; + + while(current != NULL) + { + send_text("NIC"); + + if(!(get_text("NICINFO?")) && + (!send_value("MAC", current->mac_address)) && + (!send_value("BANDWIDTH",current->bandwidth))) + { + send_text("ENDNIC"); + result = get_text("ACK NIC"); + } + + current = current->next; + } + + return result; +} + +int send_details(void) +{ + int result = 1; + + VERBOSE("Sending node details.\n"); + + if (!get_text("INFO?")) + { + if((!send_value("ARCH", arch)) && + (!send_value("UUID", uuid)) && + (!send_value("MEMSIZE", memsize)) && + (!send_cpu_details() && !send_nic_details())) + { + if(!send_text("ENDINFO")) result = 0; + } + } + else + { + VERBOSE("Was not interrogated for hardware info.\n"); + } + + return result; +} + +int end_conversation(void) +{ + int result = 0; + + VERBOSE("Ending conversation.\n"); + + send_text("ENDINFO"); + + close(socketfd); + + return result; +} + +int send_value(char* label,char* value) +{ + char buffer[BUFFER_LENGTH]; + int result = 1; + char expected[BUFFER_LENGTH]; + + snprintf(buffer,BUFFER_LENGTH,"%s=%s", label, value); + + if(!send_text(buffer)) + { + snprintf(expected, BUFFER_LENGTH, "ACK %s", label); + + VERBOSE("Expecting \"%s\"\n", expected); + + result = get_text(expected); + } + + return result; +} + +int send_text(char* text) +{ + int result = 1; + int sent; + + VERBOSE("Sending: \"%s\"\n", text); + + sent = safewrite(socketfd, text, strlen(text)); + sent += safewrite(socketfd, "\n", 1); + + if(sent >= 0) + { + DEBUG("Sent %d bytes total.\n", sent); + + result = 0; + } + + return result; +} diff --git a/ovirt-managed-node/src/scripts/ovirt-post b/ovirt-managed-node/src/scripts/ovirt-post index f113b28..310a41c 100755 --- a/ovirt-managed-node/src/scripts/ovirt-post +++ b/ovirt-managed-node/src/scripts/ovirt-post @@ -12,14 +12,8 @@ start() { find_srv identify tcp - UUID=`hal-get-property --udi \ - /org/freedesktop/Hal/devices/computer --key system.hardware.uuid` - if [ -z $UUID ]; then - ovirt-identify-node -s $SRV_HOST -p $SRV_PORT - else - ovirt-identify-node -s $SRV_HOST -p $SRV_PORT -u $UUID - fi + ovirt-identify-node -s $SRV_HOST -p $SRV_PORT } case "$1" in diff --git a/wui/src/host-browser/host-browser.rb b/wui/src/host-browser/host-browser.rb index 624661d..d209bdb 100755 --- a/wui/src/host-browser/host-browser.rb +++ b/wui/src/host-browser/host-browser.rb @@ -87,8 +87,8 @@ class HostBrowser break if info == "ENDINFO" - # if we got the start of a CPU details marker, then process it - if info == "CPU" + case info + when "CPU" cpu = get_cpu_info cpu_info = result['CPUINFO'] @@ -98,7 +98,16 @@ class HostBrowser end cpu_info << cpu + when "NIC" + nic = get_nic_info + nic_info = result['NICINFO'] + if(nic_info == nil) + nic_info = Array.new + result['NICINFO'] = nic_info + end + + nic_info << nic else raise Exception.new("ERRINFO! Excepted key=value : #{info}\n") unless info =~ /[\w]+[\s]*=[\w]/ @@ -144,6 +153,35 @@ class HostBrowser return result end + # Extracts NIC details from the managed node. + # + def get_nic_info + puts "Begin receiving NIC details" + + result = Hash.new + + @session.write("NICINFO?\n") + + loop do + info = @session.readline.chomp + + break if info == "ENDNIC" + + raise Exception.new("ERRINFO! Excepted key=value : #{info}\n") unless info =~ /[\w]+[\s]*=[\w]/ + + key, value = info.split("=") + + puts "#{@log_prefix} ::Received - #{key}:#{value}" unless defined?(TESTING) + result[key] = value + + @session.write("ACK #{key}\n") + end + + @session.write("ACK NIC\n"); + + return result + end + # Writes the supplied host information to the database. # def write_host_info(host_info) @@ -151,8 +189,10 @@ class HostBrowser ensure_present(host_info,'ARCH') ensure_present(host_info,'MEMSIZE') ensure_present(host_info,'CPUINFO') + ensure_present(host_info,'NICINFO') cpu_info = host_info['CPUINFO'] + nic_info = host_info['NICINFO'] cpu_info.each do |cpu| ensure_present(cpu,'CPUNUM') @@ -216,7 +256,45 @@ class HostBrowser host.cpus << detail end - host.save! + # Update the NIC details for this host: + # -if the NIC exists, then update the IP address + # -if the NIC does not exist, create it + # -any nic not in this list is deleted + + puts "Updating NIC records for the node" + nics = Array.new + + host.nics.collect do |nic| + found = false + + nic_info.collect do |detail| + # if we have a match, then update the database and remove + # the received data to avoid creating a dupe later + if detail['MAC'] == nic.mac + nic_info.delete(detail) + end + end + + # if the record wasn't found, then remove it from the database + unless found + host.nics.delete(nic) + nic.destroy + end + end + + # iterate over any nics left and create new records for them. + + nic_info.collect do |nic| + puts "Creating a new nic..." + detail = Nic.new( + 'mac' => nic['MAC'], + 'bandwidth' => nic['BANDWIDTH'], + 'usage_type' => 1) + + host.nics << detail + end + + host.save! return host end diff --git a/wui/src/host-browser/test-host-browser-identify.rb b/wui/src/host-browser/test-host-browser-identify.rb index 4197e19..7e672ce 100755 --- a/wui/src/host-browser/test-host-browser-identify.rb +++ b/wui/src/host-browser/test-host-browser-identify.rb @@ -38,7 +38,7 @@ class TestHostBrowser < Test::Unit::TestCase @host_info = {} @host_info['UUID'] = 'node1' @host_info['IPADDR'] = '192.168.2.2' - @host_info['HOSTNAME'] = 'node1.ovirt.redhat.com' + @host_info['HOSTNAME'] = 'prod.corp.com' @host_info['ARCH'] = 'x86_64' @host_info['MEMSIZE'] = '16384' @host_info['DISABLED'] = '0' @@ -75,6 +75,15 @@ class TestHostBrowser < Test::Unit::TestCase mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx \ fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs \ bts pni monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr lahf_lm' + + @host_info['NICINFO'] = Array.new + @host_info['NICINFO'][0] = {} + @host_info['NICINFO'][0]['MAC'] = '00:11:22:33:44:55' + @host_info['NICINFO'][0]['BANDWIDTH'] = '100' + + @host_info['NICINFO'][1] = {} + @host_info['NICINFO'][1]['MAC'] = '00:77:11:77:19:65' + @host_info['NICINFO'][1]['BANDWIDTH'] = '100' end # Ensures that the server is satisfied if the remote system is @@ -184,6 +193,15 @@ class TestHostBrowser < Test::Unit::TestCase assert_raise(Exception) { @browser.write_host_info(@host_info) } end + # Ensures that, if no NIC info was available, the server raises an + # exception. + # + def test_write_host_info_with_missing_nicinfo + @host_info['NICINFO'] = nil + + assert_raise(Exception) { @browser.write_host_info(@host_info) } + end + # Ensures the browser can properly parse the CPU details. # def test_parse_cpu_info @@ -206,7 +224,7 @@ class TestHostBrowser < Test::Unit::TestCase # Ensures the browser can properly parse the CPU details of two CPUs. # - def test_parse_cpu_info + def test_parse_cpu_info_with_two_entries @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } # CPU 0 @@ -242,4 +260,24 @@ class TestHostBrowser < Test::Unit::TestCase assert_not_nil info['CPUINFO'][1]['key4'] end + # Ensures the browser can properly parse the details for a NIC. + # + def test_parse_nic_info + @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "NIC\n" } + @session.should_receive(:write).with("NICINFO?\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key1=value1\n" } + @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "key2=value2\n" } + @session.should_receive(:write).with("ACK key2\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDNIC\n" } + @session.should_receive(:write).with("ACK NIC\n").once().returns { |request| request.length } + @session.should_receive(:readline).once().returns { "ENDINFO\n" } + + info = @browser.get_remote_info + + assert_equal 3,info.keys.size, "Should contain four keys" + assert info.include?("NICINFO") + end + end -- 1.5.5.1 From dlutter at redhat.com Wed Jul 16 21:16:48 2008 From: dlutter at redhat.com (David Lutterkort) Date: Wed, 16 Jul 2008 21:16:48 +0000 Subject: [Ovirt-devel] OVirt public API In-Reply-To: <20080716202122.GD32686@redhat.com> References: <1216163491.19722.20.camel@localhost.localdomain> <20080716125330.GM24297@redhat.com> <1216227466.19321.5.camel@localhost.localdomain> <20080716202122.GD32686@redhat.com> Message-ID: <1216243008.19321.50.camel@localhost.localdomain> On Wed, 2008-07-16 at 21:21 +0100, Daniel P. Berrange wrote: > I've no idea how you're anticipating doing the server side coding for > the API, but if there was a way todo it such that the Ruby impl of > the APIs didn't have any direct knowledge of REST, we could add in > other API styles later. The nice thing about REST is that it's very well supported in Rails, to the point that exposing things through REST is as simple as doing traditional WUI responses (actually simpler, since you don't have to worry about those pesky views) In terms of implementation, it is definitely the quickest way to get an API going. David From mdehaan at redhat.com Wed Jul 16 21:20:17 2008 From: mdehaan at redhat.com (Michael DeHaan) Date: Wed, 16 Jul 2008 17:20:17 -0400 Subject: [Ovirt-devel] OVirt public API In-Reply-To: <1216242177.19321.43.camel@localhost.localdomain> References: <1216163491.19722.20.camel@localhost.localdomain> <487E54F7.3060908@redhat.com> <487E558D.50408@redhat.com> <1216242177.19321.43.camel@localhost.localdomain> Message-ID: <487E6611.2060402@redhat.com> David Lutterkort wrote: > On Wed, 2008-07-16 at 16:09 -0400, Michael DeHaan wrote: > >> Michael DeHaan wrote: >> >>> I would make an argument for XMLRPC/SSL based on that a lot of our >>> management applications already have XMLRPC API's (such as >>> Spacewalk/Cobbler/etc), and that serialization and more remote faults >>> are supported. Having an app have to speak to multiple API types if >>> of course going to be a reality. >>> >>> That being said, REST is definitely workable, and as long as there is >>> an API, I think most people will be reasonably happy. >>> >>> Basically with XMLRPC you don't have to write any wrapper code around >>> the API caller and it just works as if it were a local API, which is >>> nice >>> >>> >> I should add, embedding XML in an XMLRPC request as a string sounds >> weird, but does work. The main benefit is not the format, which is not >> perfect, just that there are a lot of nice libraries that make XMLRPC >> behave as if it were a local API/module, doing the usual >> getattr()/method_missing magic and so forth. >> > > This seems to come down to an argument that > serialization/deserialization, or in general, support for XMLRPC, is > more mature than for REST - I don't doubt that that's true right now, > simply because XMLRPC has been around for much longer. > > With all the attention that REST has been getting, and Rails shunning > SOAP/XMLRPC etc. explicitly in favor of rest, it's only a matter of time > before REST support in other languages catches up with that for XMLRPC. > Hopefully. In this case we see something standard like the XMLRPC spec over HTTP get/post/etc. This is what it needs. Maybe call this "RESTX" or substitute in some name that does not suck :) > In the meantime, there are things like pyActiveResource which seems a > good start for Pyhton, and alternatively, using well-supported > serialization formats like YAML or JSON. > Hmm, good deal. I would advise against YAML. It's fine if you control the library, but there's a big mix of 1.0/2.0 out there and they don't play nicely. JSON is nice in that it has only one real "version" (maybe they'll screw that up) and also plays nicer for AJAXy things for those that care about that. > One of the things that makes me very hesitant about XMLRPC is that I've > been watching it fall apart in the case of puppet - Luke is still trying > to dig out from under that decision, and migrating away from it. > Indeed. XMLRPC is obviously not a good way to do large file requests, sure enough. Luke was using that wrong. That being said, it holds up quite fine for things like Satellite AFAIK, especially if you turn on the threading/forking mixins. Anyhow, in this case, the concern is not as much for people writing enterprisey software, but the sysadmins who want to write tools to automate their ovirt infrastructure. If we provide them nice libraries that wrap the ugly XML parsing bits, and show them how to do things in a minimalistic way, that's ok... we just have to have that. Flickr's REST support is an example of how to do that wrong, seeing they didn't put out those libraries and the open source ones out there are pretty bad as they had to reverse engineer the API or sorts to get all the bits working, where something like XMLRPC would have mostly just worked out of the box. Anyhow, as long as you can keep admins away from XML and keep their code short, they will be reasonably happy. --Michael > David > > > From dlutter at redhat.com Wed Jul 16 21:27:20 2008 From: dlutter at redhat.com (David Lutterkort) Date: Wed, 16 Jul 2008 21:27:20 +0000 Subject: [Ovirt-devel] OVirt public API In-Reply-To: <487E54F7.3060908@redhat.com> References: <1216163491.19722.20.camel@localhost.localdomain> <487E54F7.3060908@redhat.com> Message-ID: <1216243640.19321.59.camel@localhost.localdomain> On Wed, 2008-07-16 at 16:07 -0400, Michael DeHaan wrote: > I would make an argument for XMLRPC/SSL based on that a lot of our OVirt uses Kerberos for authentication/authorization throughout, and I was not planning onchanging that for the API. To do authorization with SSL we'd have to get into the business of distributing client-side certs, and I would only want to make that move if that is done for OVirt as a whole (which, from what I understand, wouldn't happen unless FreeIPA supports it). > management applications already have XMLRPC API's (such as > Spacewalk/Cobbler/etc), and that serialization and more remote faults > are supported. All I can find about XMLRPC faults is that there's a certain XML format for faults which transmits an integer error code and a string error message, with no agreement on what those integer codes mean - the response is actually sent back with an HTTP status 200 (okiedokie). I'd argue that situation is worse than for REST, where errors are reported both through the HTTP status (like 403 - go log in) and the payload. That has the advantage that HTTP status codes are fairly extensive and have well defined meanings. David From mdehaan at redhat.com Wed Jul 16 21:52:23 2008 From: mdehaan at redhat.com (Michael DeHaan) Date: Wed, 16 Jul 2008 17:52:23 -0400 Subject: [Ovirt-devel] OVirt public API In-Reply-To: <1216243640.19321.59.camel@localhost.localdomain> References: <1216163491.19722.20.camel@localhost.localdomain> <487E54F7.3060908@redhat.com> <1216243640.19321.59.camel@localhost.localdomain> Message-ID: <487E6D97.3000608@redhat.com> David Lutterkort wrote: > On Wed, 2008-07-16 at 16:07 -0400, Michael DeHaan wrote: > >> I would make an argument for XMLRPC/SSL based on that a lot of our >> > > OVirt uses Kerberos for authentication/authorization throughout, and I > was not planning onchanging that for the API. To do authorization with > SSL we'd have to get into the business of distributing client-side > certs, and I would only want to make that move if that is done for OVirt > as a whole (which, from what I understand, wouldn't happen unless > FreeIPA supports it). > Right. I was referring to data stream encryption, not authn/authz. >> management applications already have XMLRPC API's (such as >> Spacewalk/Cobbler/etc), and that serialization and more remote faults >> are supported. >> > > All I can find about XMLRPC faults is that there's a certain XML format > for faults which transmits an integer error code and a string error > message, with no agreement on what those integer codes mean - the > response is actually sent back with an HTTP status 200 (okiedokie). I'd > argue that situation is worse than for REST, where errors are reported > both through the HTTP status (like 403 - go log in) and the payload. > That has the advantage that HTTP status codes are fairly extensive and > have well defined meanings. > The main nice thing is the libraries are usually smart enough to translate them automatically to caller-side exceptions and raise something (forcing the caller to deal with them), but yes, the data you get from that is limited. > David > > > From thomas.vonsteiger at bluewin.ch Thu Jul 17 15:14:37 2008 From: thomas.vonsteiger at bluewin.ch (Thomas von Steiger) Date: Thu, 17 Jul 2008 17:14:37 +0200 Subject: [Ovirt-devel] OVirt public API In-Reply-To: <1216243008.19321.50.camel@localhost.localdomain> References: <1216163491.19722.20.camel@localhost.localdomain> <20080716125330.GM24297@redhat.com> <1216227466.19321.5.camel@localhost.localdomain> <20080716202122.GD32686@redhat.com> <1216243008.19321.50.camel@localhost.localdomain> Message-ID: <0F31CBD6-6510-4C11-B726-1C8DD6C2CD79@bluewin.ch> On Jul 16, 2008, at 11:16 PM, David Lutterkort wrote: > On Wed, 2008-07-16 at 21:21 +0100, Daniel P. Berrange wrote: >> I've no idea how you're anticipating doing the server side coding for >> the API, but if there was a way todo it such that the Ruby impl of >> the APIs didn't have any direct knowledge of REST, we could add in >> other API styles later. > > The nice thing about REST is that it's very well supported in Rails, > to > the point that exposing things through REST is as simple as doing > traditional WUI responses (actually simpler, since you don't have to > worry about those pesky views) Definitve interesting discussion! XMLRPC or/and RESTful i found this is a good solution: http://md314159265.wordpress.com/2006/10/30/comparison-of-rest-vs-xml-rpc/ google hits for XMLRPC: 11'900'000 google hits for RESTful: 5'400'000 Thomas From berrange at redhat.com Thu Jul 17 15:36:49 2008 From: berrange at redhat.com (Daniel P. Berrange) Date: Thu, 17 Jul 2008 16:36:49 +0100 Subject: [Ovirt-devel] OVirt public API In-Reply-To: <0F31CBD6-6510-4C11-B726-1C8DD6C2CD79@bluewin.ch> References: <1216163491.19722.20.camel@localhost.localdomain> <20080716125330.GM24297@redhat.com> <1216227466.19321.5.camel@localhost.localdomain> <20080716202122.GD32686@redhat.com> <1216243008.19321.50.camel@localhost.localdomain> <0F31CBD6-6510-4C11-B726-1C8DD6C2CD79@bluewin.ch> Message-ID: <20080717153649.GJ16865@redhat.com> On Thu, Jul 17, 2008 at 05:14:37PM +0200, Thomas von Steiger wrote: > > On Jul 16, 2008, at 11:16 PM, David Lutterkort wrote: > > >On Wed, 2008-07-16 at 21:21 +0100, Daniel P. Berrange wrote: > >>I've no idea how you're anticipating doing the server side coding for > >>the API, but if there was a way todo it such that the Ruby impl of > >>the APIs didn't have any direct knowledge of REST, we could add in > >>other API styles later. > > > >The nice thing about REST is that it's very well supported in Rails, > >to > >the point that exposing things through REST is as simple as doing > >traditional WUI responses (actually simpler, since you don't have to > >worry about those pesky views) > > Definitve interesting discussion! > > XMLRPC or/and RESTful i found this is a good solution: > > http://md314159265.wordpress.com/2006/10/30/comparison-of-rest-vs-xml-rpc/ Frankly that's a rather dubious article, eg to quote "REST is an HTTP based protocol. Whereas XML-RPC is XML based." What network protocol exactly does the author think the XML is being sent over ?!?!? Does he really think you can't send XML over HTTP ? Or another "Advantage of XML-RPC is that it is client independant. Any sort of client be it a desktop application a mobile application, a mashup using information from your site can easily integrate with XML-RPC" Any client which can make XML-RPC calls, can by definition also make REST calls, since the both run over HTTP(s). A HTTP client is a neccessary pre-requisite for both XML-RPC & REST. When they make such basis mistakes of understanding, any conclusions they may come to are worthless. 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 Thu Jul 17 15:49:10 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Thu, 17 Jul 2008 11:49:10 -0400 Subject: [Ovirt-devel] Re: a pox on whitespace In-Reply-To: <87ej5tg2xh.fsf@rho.meyering.net> References: <87ej5tg2xh.fsf@rho.meyering.net> Message-ID: <20080717154910.GW24297@redhat.com> On Wed, Jul 16, 2008 at 07:21:46PM +0200, Jim Meyering wrote: > Here are some things we can do to avoid > bad whitespace (not just trailing whitespace) > without causing too much development pain: > > server-side enforcement > have a git pre-push hook check for and reject changes that > add trailing blanks. This typically cannot be circumvented. > However, I've set up similar things whereby exceptional cases > can be white-listed. I'd be in favor of putting this into place immediately. > local-commit-enforcement > With recent git, just do this in each of your > working directories: chmod a+x .git/hooks/pre-commit > and a commit that would have added bad whitespace will fail. > (you can circumvent it with git commit's --no-verify (-n) option) And this... how recent a git version? > "make check"-style detection > Add a top-level Makefile rule that fails if any file > contains bad whitespace. Then establish policy that one must > pass "make check"s tests before committing/pushing. This is probably less compelling for us since we don't really compile the app (although I habitually still run make and then install the RPM to test changes). > editor highlighting > Enable syntax highlighting in your editor and tell it to > display bad whitespace. For example, add this to your ~/.vimrc: > > let c_space_errors=1 > highlight RedundantSpaces ctermbg=red guibg=red > match RedundantSpaces /\s\+$\| \+\ze\t/ > > For emacs, you might want to try show-wspace.el (I haven't, > but it's the first google hit for "highlight whitespace emacs") > , or maybe > you already use font-lock mode, which you can customize. This is voluntary I guess but seems like a good thing for developers to do. Also needed might be a quick script to remove trailing whitespace from a file? Thanks for this, --Hugh From mdehaan at redhat.com Thu Jul 17 16:02:18 2008 From: mdehaan at redhat.com (Michael DeHaan) Date: Thu, 17 Jul 2008 12:02:18 -0400 Subject: [Ovirt-devel] OVirt public API In-Reply-To: <20080717153649.GJ16865@redhat.com> References: <1216163491.19722.20.camel@localhost.localdomain> <20080716125330.GM24297@redhat.com> <1216227466.19321.5.camel@localhost.localdomain> <20080716202122.GD32686@redhat.com> <1216243008.19321.50.camel@localhost.localdomain> <0F31CBD6-6510-4C11-B726-1C8DD6C2CD79@bluewin.ch> <20080717153649.GJ16865@redhat.com> Message-ID: <487F6D0A.9000608@redhat.com> Daniel P. Berrange wrote: > On Thu, Jul 17, 2008 at 05:14:37PM +0200, Thomas von Steiger wrote: > >> On Jul 16, 2008, at 11:16 PM, David Lutterkort wrote: >> >> >>> On Wed, 2008-07-16 at 21:21 +0100, Daniel P. Berrange wrote: >>> >>>> I've no idea how you're anticipating doing the server side coding for >>>> the API, but if there was a way todo it such that the Ruby impl of >>>> the APIs didn't have any direct knowledge of REST, we could add in >>>> other API styles later. >>>> >>> The nice thing about REST is that it's very well supported in Rails, >>> to >>> the point that exposing things through REST is as simple as doing >>> traditional WUI responses (actually simpler, since you don't have to >>> worry about those pesky views) >>> >> Definitve interesting discussion! >> >> XMLRPC or/and RESTful i found this is a good solution: >> >> http://md314159265.wordpress.com/2006/10/30/comparison-of-rest-vs-xml-rpc/ >> > > Frankly that's a rather dubious article, eg to quote > > "REST is an HTTP based protocol. Whereas XML-RPC is XML based." > > What network protocol exactly does the author think the XML is being sent > over ?!?!? Does he really think you can't send XML over HTTP ? Or another > That sentence is correct. REST does not specify XML. It has zero defined protocol for the data other than that it uses some set of HTTP error codes and operations. From jim at meyering.net Thu Jul 17 16:06:06 2008 From: jim at meyering.net (Jim Meyering) Date: Thu, 17 Jul 2008 18:06:06 +0200 Subject: [Ovirt-devel] Re: a pox on whitespace In-Reply-To: <20080717154910.GW24297@redhat.com> (Hugh O. Brock's message of "Thu, 17 Jul 2008 11:49:10 -0400") References: <87ej5tg2xh.fsf@rho.meyering.net> <20080717154910.GW24297@redhat.com> Message-ID: <87d4lc7axd.fsf@rho.meyering.net> "Hugh O. Brock" wrote: > On Wed, Jul 16, 2008 at 07:21:46PM +0200, Jim Meyering wrote: >> Here are some things we can do to avoid >> bad whitespace (not just trailing whitespace) >> without causing too much development pain: >> >> server-side enforcement >> have a git pre-push hook check for and reject changes that >> add trailing blanks. This typically cannot be circumvented. >> However, I've set up similar things whereby exceptional cases >> can be white-listed. > > I'd be in favor of putting this into place immediately. > >> local-commit-enforcement >> With recent git, just do this in each of your >> working directories: chmod a+x .git/hooks/pre-commit >> and a commit that would have added bad whitespace will fail. >> (you can circumvent it with git commit's --no-verify (-n) option) > > And this... how recent a git version? Actually it goes back farther than I thought, so we should all have this: To check, run this: grep whitespace .git/hooks/pre-commit if it shows something like this, then enable it via "chmod a+x .git/hooks/pre-commit" # Lines you introduce should not have trailing whitespace. bad_line("trailing whitespace", $_); >> "make check"-style detection >> Add a top-level Makefile rule that fails if any file >> contains bad whitespace. Then establish policy that one must >> pass "make check"s tests before committing/pushing. > > This is probably less compelling for us since we don't really compile > the app (although I habitually still run make and then install the RPM > to test changes). > >> editor highlighting >> Enable syntax highlighting in your editor and tell it to >> display bad whitespace. For example, add this to your ~/.vimrc: >> >> let c_space_errors=1 >> highlight RedundantSpaces ctermbg=red guibg=red >> match RedundantSpaces /\s\+$\| \+\ze\t/ >> >> For emacs, you might want to try show-wspace.el (I haven't, >> but it's the first google hit for "highlight whitespace emacs") >> , or maybe >> you already use font-lock mode, which you can customize. > > This is voluntary I guess but seems like a good thing for developers > to do. > > Also needed might be a quick script to remove trailing whitespace from > a file? perl -pi -e 's/\s+$//' file1 file2 ... From berrange at redhat.com Thu Jul 17 16:12:47 2008 From: berrange at redhat.com (Daniel P. Berrange) Date: Thu, 17 Jul 2008 17:12:47 +0100 Subject: [Ovirt-devel] OVirt public API In-Reply-To: <487F6D0A.9000608@redhat.com> References: <1216163491.19722.20.camel@localhost.localdomain> <20080716125330.GM24297@redhat.com> <1216227466.19321.5.camel@localhost.localdomain> <20080716202122.GD32686@redhat.com> <1216243008.19321.50.camel@localhost.localdomain> <0F31CBD6-6510-4C11-B726-1C8DD6C2CD79@bluewin.ch> <20080717153649.GJ16865@redhat.com> <487F6D0A.9000608@redhat.com> Message-ID: <20080717161247.GK16865@redhat.com> On Thu, Jul 17, 2008 at 12:02:18PM -0400, Michael DeHaan wrote: > Daniel P. Berrange wrote: > >On Thu, Jul 17, 2008 at 05:14:37PM +0200, Thomas von Steiger wrote: > > > >>On Jul 16, 2008, at 11:16 PM, David Lutterkort wrote: > > > >Frankly that's a rather dubious article, eg to quote > > > > "REST is an HTTP based protocol. Whereas XML-RPC is XML based." > > > >What network protocol exactly does the author think the XML is being sent > >over ?!?!? Does he really think you can't send XML over HTTP ? Or another > > > > That sentence is correct. REST does not specify XML. It has zero defined > protocol for the data other > than that it uses some set of HTTP error codes and operations. No, its uttter crap when you're using that as a comparison. REST uses HTTP, XML-RPC uses HTTP. REST can use XML. XML-RPC uses XML. It is not a meaningful statement when you're comparing the two. 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 mdehaan at redhat.com Thu Jul 17 16:29:07 2008 From: mdehaan at redhat.com (Michael DeHaan) Date: Thu, 17 Jul 2008 12:29:07 -0400 Subject: [Ovirt-devel] OVirt public API In-Reply-To: <20080717161247.GK16865@redhat.com> References: <1216163491.19722.20.camel@localhost.localdomain> <20080716125330.GM24297@redhat.com> <1216227466.19321.5.camel@localhost.localdomain> <20080716202122.GD32686@redhat.com> <1216243008.19321.50.camel@localhost.localdomain> <0F31CBD6-6510-4C11-B726-1C8DD6C2CD79@bluewin.ch> <20080717153649.GJ16865@redhat.com> <487F6D0A.9000608@redhat.com> <20080717161247.GK16865@redhat.com> Message-ID: <487F7353.2090102@redhat.com> Daniel P. Berrange wrote: > On Thu, Jul 17, 2008 at 12:02:18PM -0400, Michael DeHaan wrote: > >> Daniel P. Berrange wrote: >> >>> On Thu, Jul 17, 2008 at 05:14:37PM +0200, Thomas von Steiger wrote: >>> >>> >>>> On Jul 16, 2008, at 11:16 PM, David Lutterkort wrote: >>>> >>> Frankly that's a rather dubious article, eg to quote >>> >>> "REST is an HTTP based protocol. Whereas XML-RPC is XML based." >>> >>> What network protocol exactly does the author think the XML is being sent >>> over ?!?!? Does he really think you can't send XML over HTTP ? Or another >>> >>> >> That sentence is correct. REST does not specify XML. It has zero defined >> protocol for the data other >> than that it uses some set of HTTP error codes and operations. >> > > No, its uttter crap when you're using that as a comparison. REST uses > HTTP, XML-RPC uses HTTP. REST can use XML. XML-RPC uses XML. It is not > a meaningful statement when you're comparing the two. > > Daniel > I read that as "REST is a protocol whos return values are based on HTTP error codes." You've got to admit you understood it, so arguing about it seems kind of pointless. From jberman at redhat.com Thu Jul 17 20:31:44 2008 From: jberman at redhat.com (Joel Berman) Date: Thu, 17 Jul 2008 16:31:44 -0400 Subject: [Ovirt-devel] two minor doc issues Message-ID: <487FAC30.8070300@redhat.com> An HTML attachment was scrubbed... URL: From dlutter at redhat.com Fri Jul 18 01:10:22 2008 From: dlutter at redhat.com (David Lutterkort) Date: Fri, 18 Jul 2008 01:10:22 +0000 Subject: [Ovirt-devel] Dev setup for a home network Message-ID: <1216343422.19321.148.camel@localhost.localdomain> Since I am cheap (and hate fiddling with cables), I wanted an OVirt dev setup that would fit more closely into how my home network is setup. In particular, * the WUI appliance should be a VM that is on the main network, i.e. using a shared network interface * PXE boot my existing hardware as a OVirt managed node, without having to put them on a separate network Like for most people, my home network is one segemnt on which I already run DNS and DHCP. Here's what I had to do to get there: (1) Download and install the OVirt WUI appliance following the instructions on the website. (2) Modify the libvirt XML for the appliance to put its first network interface onto the bridge (let's call it eth0) used for shared networking. For that, you need to * virsh dumpxml developer > /tmp/developer.xml * edit /tmp/developer.xml and change the first block to * virsh define /tmp/developer.xml (3) Enter the MAC address above, a fixed IP and hostname (let's call that ovirt.home.net) into your existing DHCP server. If you use dnsmasq, I'll attach the relevant bits to this mail. You should also enter IP and hostname into /etc/hosts on your DHCP server. To play it safe, you also want management.priv.ovirt.org to be an alias for ovirt.home.net; I don't know how to do that with bind, but for dnsmasq, just add an alias in /etc/hosts for ovirt.home.net, i.e. altogether you want to have a line like 172.31.0.129 ovirt.home.net management.priv.ovirt.org (4) Start the WUI appliance with 'virsh start developer' and 'ssh -Y root at ovirt.home.net'. The following all needs to be done inside the appliance: * Edit /etc/xinet.d/tftp and change the line that says 'disable = yes' to 'enable = yes' and restart xinetd (we will use a normal tftpd for PXE booting, since dnsmasq can't do DHCP and TFTP separately on an interface, and we want TFTP only on the 'public' interface eth0) * Edit /etc/sysconfig/network-scripts/ifcfg-eth0 and set HWADDR=52:54:00:22:83:50 and remove the line setting DNS1 (I don't think this is strictly necessary, but having the wrong HWADDR throws ifdown/ifup into knots) * Edit /etc/init.d/ovirt-wui-dev and remove the --enable-tftp and --tftp-root options from the dnsmasq invocation in start(). Then restart ovirt-wui-dev (could we put the dnsmasq options into dnsmasq.conf instead of hardcoding them in an init script ?) (5) On your DNS server, enter the various SRV records that OVirt uses (see the srv-host lines in the attached ovirt.conf dnsmasq snippet) (6) On your DHCP server, make sure PXE clients are pointed to ovirt.home.net as the TFTP server and told to download pxelinux.0 (the dhcp-boot line in ovirt.conf) (7) Don't forget to restart your DNS/DHCP server ;) With that, you should be able to 1. do fun stuff like NFS mount your home dir into ovirt.home.net, just as you do for all your other machines or run a puppet client to customize the appliance in all the ways you customize your other machines 2. set your favorite VT enabled box to PXE boot, fire it up and watch it download and boot the managed node image 3. boot fake nodes just as you could before Now, if only I could figure out how to kinit against ovirt.home.net from my laptop, I'd be completely happy (just putting the relevant bits from [realms] and [domain_realm] into krb5.conf doesn't seem to do the trick) Running firefox inside the WUI appliance is painfully slow. David From jeffschroed at gmail.com Fri Jul 18 01:38:55 2008 From: jeffschroed at gmail.com (Jeff Schroeder) Date: Thu, 17 Jul 2008 18:38:55 -0700 Subject: [Ovirt-devel] Dev setup for a home network In-Reply-To: <1216343422.19321.148.camel@localhost.localdomain> References: <1216343422.19321.148.camel@localhost.localdomain> Message-ID: On Thu, Jul 17, 2008 at 6:10 PM, David Lutterkort wrote: > Since I am cheap (and hate fiddling with cables), I wanted an OVirt dev > setup that would fit more closely into how my home network is setup. In > particular, > > * the WUI appliance should be a VM that is on the main network, > i.e. using a shared network interface > * PXE boot my existing hardware as a OVirt managed node, without > having to put them on a separate network > > Like for most people, my home network is one segemnt on which I already > run DNS and DHCP. Here's what I had to do to get there: > > (1) Download and install the OVirt WUI appliance following the > instructions on the website. > > (2) Modify the libvirt XML for the appliance to put its first network > interface onto the bridge (let's call it eth0) used for shared > networking. For that, you need to > > * virsh dumpxml developer > /tmp/developer.xml > * edit /tmp/developer.xml and change the first block > to > > > > > > > * virsh define /tmp/developer.xml > > (3) Enter the MAC address above, a fixed IP and hostname (let's call > that ovirt.home.net) into your existing DHCP server. If you use dnsmasq, > I'll attach the relevant bits to this mail. You should also enter IP and > hostname into /etc/hosts on your DHCP server. To play it safe, you also > want management.priv.ovirt.org to be an alias for ovirt.home.net; I > don't know how to do that with bind, but for dnsmasq, just add an alias > in /etc/hosts for ovirt.home.net, i.e. altogether you want to have a > line like > 172.31.0.129 ovirt.home.net management.priv.ovirt.org > > (4) Start the WUI appliance with 'virsh start developer' and 'ssh -Y > root at ovirt.home.net'. The following all needs to be done inside the > appliance: > * Edit /etc/xinet.d/tftp and change the line that says 'disable = > yes' to 'enable = yes' and restart xinetd (we will use a normal > tftpd for PXE booting, since dnsmasq can't do DHCP and TFTP > separately on an interface, and we want TFTP only on the > 'public' interface eth0) > * Edit /etc/sysconfig/network-scripts/ifcfg-eth0 and set > HWADDR=52:54:00:22:83:50 and remove the line setting DNS1 (I > don't think this is strictly necessary, but having the wrong > HWADDR throws ifdown/ifup into knots) > * Edit /etc/init.d/ovirt-wui-dev and remove the --enable-tftp and > --tftp-root options from the dnsmasq invocation in start(). Then > restart ovirt-wui-dev (could we put the dnsmasq options into > dnsmasq.conf instead of hardcoding them in an init script ?) > > (5) On your DNS server, enter the various SRV records that OVirt uses > (see the srv-host lines in the attached ovirt.conf dnsmasq snippet) > > (6) On your DHCP server, make sure PXE clients are pointed to > ovirt.home.net as the TFTP server and told to download pxelinux.0 (the > dhcp-boot line in ovirt.conf) > > (7) Don't forget to restart your DNS/DHCP server ;) > > With that, you should be able to > 1. do fun stuff like NFS mount your home dir into ovirt.home.net, > just as you do for all your other machines or run a puppet > client to customize the appliance in all the ways you customize > your other machines > 2. set your favorite VT enabled box to PXE boot, fire it up and > watch it download and boot the managed node image > 3. boot fake nodes just as you could before > > Now, if only I could figure out how to kinit against ovirt.home.net from > my laptop, I'd be completely happy (just putting the relevant bits from > [realms] and [domain_realm] into krb5.conf doesn't seem to do the trick) > Running firefox inside the WUI appliance is painfully slow. > > David Can you put this in the wiki? This is great info. -- Jeff Schroeder Don't drink and derive, alcohol and analysis don't mix. http://www.digitalprognosis.com From clalance at redhat.com Fri Jul 18 14:44:49 2008 From: clalance at redhat.com (Chris Lalancette) Date: Fri, 18 Jul 2008 16:44:49 +0200 Subject: [Ovirt-devel] [PATCH]: Fix get_credentials so we don't fill log files In-Reply-To: <4843A641.3080609@redhat.com> References: <4843A641.3080609@redhat.com> Message-ID: <4880AC61.3090003@redhat.com> Chris Lalancette wrote: > Hello, > I was doing some testing on the ovirt backend stuff (i.e. host-status, > taskomatic, etc.), and I noticed that the /var/log/krb5kdc.log file was filling > up very quickly. I traced it down to the host-status daemon, and in particular, > the fact that it was waking up every 5 seconds and running the get_credentials() > method in dutils. Every time it does that, two new lines are added to the > krb5kdc.log file. To fix it, I added a new method to the upstream krb5-auth > binding code called list_cache(), that will list all of the credentials (and > their properties) stored in a cache. This is the ovirt patch to use that > method; basically we just check to see if we have more than an hour left for > this credential, and if so, we don't renew it. I know this is kind of old, but I sort of forgot about it. Anyway, apevec ended up pushing the new rubygem-krb5-auth to the f-9 updates repo, so now this patch can work. I've committed it to next. Chris Lalancette From sseago at redhat.com Fri Jul 18 16:59:49 2008 From: sseago at redhat.com (Scott Seago) Date: Fri, 18 Jul 2008 12:59:49 -0400 Subject: [Ovirt-devel] [PATCH] added tallen's confirmation dialog styling changes. I've replaced all of the confirm("foo") javascript confirmation popups with the facebox-based design. Message-ID: <1216400389-26143-1-git-send-email-sseago@redhat.com> Signed-off-by: Scott Seago --- wui/src/app/helpers/application_helper.rb | 24 ++++++++++ wui/src/app/views/hardware/quick_summary.rhtml | 26 ++++++------ wui/src/app/views/layouts/_side_toolbar.rhtml | 6 ++- wui/src/app/views/layouts/redux.rhtml | 40 ++++++++--------- wui/src/app/views/resources/quick_summary.rhtml | 30 +++++++------- wui/src/app/views/storage/show.rhtml | 24 +++++----- wui/src/app/views/vm/show.rhtml | 52 +++++++++++----------- wui/src/public/images/bg_warningMessage.png | Bin 0 -> 625 bytes wui/src/public/images/icon_warning.png | Bin 0 -> 1954 bytes wui/src/public/stylesheets/layout.css | 18 ++++++++ 10 files changed, 131 insertions(+), 89 deletions(-) create mode 100644 wui/src/public/images/bg_warningMessage.png create mode 100644 wui/src/public/images/icon_warning.png diff --git a/wui/src/app/helpers/application_helper.rb b/wui/src/app/helpers/application_helper.rb index 58a6358..63a33d3 100644 --- a/wui/src/app/helpers/application_helper.rb +++ b/wui/src/app/helpers/application_helper.rb @@ -113,6 +113,30 @@ module ApplicationHelper } end + def confirmation_dialog(div_id, text, action) + %{ +
+ } + end + def timeout_flash(name) %{ diff --git a/wui/src/app/views/layouts/_side_toolbar.rhtml b/wui/src/app/views/layouts/_side_toolbar.rhtml index 2cdd4f3..42cbae6 100644 --- a/wui/src/app/views/layouts/_side_toolbar.rhtml +++ b/wui/src/app/views/layouts/_side_toolbar.rhtml @@ -13,10 +13,12 @@