From dpierce at redhat.com Mon Dec 1 16:32:34 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 1 Dec 2008 11:32:34 -0500 Subject: [Ovirt-devel] [PATCH appliance] $dist-updates-newkey is now only used when the platform is Fedora 9. Message-ID: <1228149154-25040-1-git-send-email-dpierce@redhat.com> On all other platforms, it's simply $dist-updates. This patch requires the releated patch for node-image. Signed-off-by: Darryl L. Pierce --- Makefile.am | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Makefile.am b/Makefile.am index 268d67e..cbe8918 100644 --- a/Makefile.am +++ b/Makefile.am @@ -72,7 +72,11 @@ repos.ks: FEDORA_REPO=f$(FEDORA) ;\ FEDORA_REPO_LOC="$(if $(FEDORA_URL),--baseurl=$(FEDORA_URL)/releases/$(FEDORA)/Everything/$(ARCH)/os,--mirrorlist=$(FEDORA_MIRROR)?repo=fedora-$(FEDORA)&arch=$(ARCH))" ;\ OVIRT_DISTRO=$(FEDORA) ;\ - UPDATE_REPO_LINE="repo --name=$${FEDORA_REPO}-updates-newkey $(if $(FEDORA_URL),--baseurl=$(FEDORA_URL)/updates/$(FEDORA)/$(ARCH).newkey,--mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-f$(FEDORA).newkey&arch=$(ARCH))" ;\ + if [ "$FEDORA_REPO" == "f9" ]; then \ + UPDATE_REPO_LINE="repo --name=$${FEDORA_REPO}-updates-newkey $(if $(FEDORA_URL),--baseurl=$(FEDORA_URL)/updates/$(FEDORA)/$(ARCH).newkey,--mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-f$(FEDORA).newkey&arch=$(ARCH))" ;\ + else + UPDATE_REPO_LINE="repo --name=$${FEDORA_REPO}-updates $(if $(FEDORA_URL),--baseurl=$(FEDORA_URL)/updates/$(FEDORA)/$(ARCH),--mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-f$(FEDORA)&arch=$(ARCH))" ;\ + fi ; \ fi ;\ echo "repo --name=$${FEDORA_REPO} $${FEDORA_REPO_LOC}" > $@ ;\ echo "repo --name=ovirt-org --baseurl=$(OVIRT_URL)/$${OVIRT_DISTRO}/$(ARCH)" >> $@ ;\ -- 1.6.0.4 From dpierce at redhat.com Mon Dec 1 16:33:29 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 1 Dec 2008 11:33:29 -0500 Subject: [Ovirt-devel] [PATCH node-image] Makes $dist-updates-newkey only available on Fedora 9. Message-ID: <1228149209-25114-1-git-send-email-dpierce@redhat.com> On all other releases it's simply $dist-updates. Signed-off-by: Darryl L. Pierce --- Makefile.am | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Makefile.am b/Makefile.am index 67967fe..8d20ac4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -75,7 +75,11 @@ repos.ks: FEDORA_REPO=f$(FEDORA) ;\ FEDORA_REPO_LOC="$(if $(FEDORA_URL),--baseurl=$(FEDORA_URL)/releases/$(FEDORA)/Everything/${ARCH}/os,--mirrorlist=$(FEDORA_MIRROR)?repo=fedora-$(FEDORA)&arch=$(ARCH))" ;\ OVIRT_DISTRO=$(FEDORA) ;\ - UPDATE_REPO_LINE="repo --name=$${FEDORA_REPO}-updates-newkey $(if $(FEDORA_URL),--baseurl=$(FEDORA_URL)/updates/$(FEDORA)/${ARCH}.newkey,--mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-f$(FEDORA).newkey&arch=$(ARCH))" ;\ + if [ FEDORA_REPO == f9 ]; then \ + UPDATE_REPO_LINE="repo --name=$${FEDORA_REPO}-updates-newkey $(if $(FEDORA_URL),--baseurl=$(FEDORA_URL)/updates/$(FEDORA)/${ARCH}.newkey,--mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-f$(FEDORA).newkey&arch=$(ARCH))" ;\ + else + UPDATE_REPO_LINE="repo --name=$${FEDORA_REPO}-updates $(if $(FEDORA_URL),--baseurl=$(FEDORA_URL)/updates/$(FEDORA)/${ARCH},--mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-f$(FEDORA)&arch=$(ARCH))" ;\ + fi ;\ fi ;\ echo "repo --name=$${FEDORA_REPO} $${FEDORA_REPO_LOC}" > $@ ;\ echo "repo --name=ovirt-org --baseurl=$(OVIRT_URL)/$${OVIRT_DISTRO}/$(ARCH)" >> $@ ;\ -- 1.6.0.4 From apevec at redhat.com Mon Dec 1 18:32:06 2008 From: apevec at redhat.com (Alan Pevec) Date: Mon, 01 Dec 2008 19:32:06 +0100 Subject: [Ovirt-devel] Re: [PATCH appliance] $dist-updates-newkey is now only used when the platform is Fedora 9. In-Reply-To: <1228149154-25040-1-git-send-email-dpierce@redhat.com> References: <1228149154-25040-1-git-send-email-dpierce@redhat.com> Message-ID: <49342DA6.70004@redhat.com> Darryl L. Pierce wrote: > On all other platforms, it's simply $dist-updates. ACK From apevec at redhat.com Mon Dec 1 18:32:33 2008 From: apevec at redhat.com (Alan Pevec) Date: Mon, 01 Dec 2008 19:32:33 +0100 Subject: [Ovirt-devel] Re: [PATCH node-image] Makes $dist-updates-newkey only available on Fedora 9. In-Reply-To: <1228149209-25114-1-git-send-email-dpierce@redhat.com> References: <1228149209-25114-1-git-send-email-dpierce@redhat.com> Message-ID: <49342DC1.4090004@redhat.com> Darryl L. Pierce wrote: > On all other releases it's simply $dist-updates. ACK From dpierce at redhat.com Mon Dec 1 18:39:57 2008 From: dpierce at redhat.com (Darryl Pierce) Date: Mon, 1 Dec 2008 13:39:57 -0500 Subject: [Ovirt-devel] Re: [PATCH node-image] Makes $dist-updates-newkey only available on Fedora 9. In-Reply-To: <49342DC1.4090004@redhat.com> References: <1228149209-25114-1-git-send-email-dpierce@redhat.com> <49342DC1.4090004@redhat.com> Message-ID: <200812011340.03230.dpierce@redhat.com> On Monday 01 December 2008 1:32:33 pm Alan Pevec wrote: > Darryl L. Pierce wrote: > > On all other releases it's simply $dist-updates. > > ACK Pushed. -- 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: signature.asc Type: application/pgp-signature Size: 197 bytes Desc: This is a digitally signed message part. URL: From dpierce at redhat.com Mon Dec 1 18:40:11 2008 From: dpierce at redhat.com (Darryl Pierce) Date: Mon, 1 Dec 2008 13:40:11 -0500 Subject: [Ovirt-devel] Re: [PATCH appliance] $dist-updates-newkey is now only used when the platform is Fedora 9. In-Reply-To: <49342DA6.70004@redhat.com> References: <1228149154-25040-1-git-send-email-dpierce@redhat.com> <49342DA6.70004@redhat.com> Message-ID: <200812011340.11556.dpierce@redhat.com> On Monday 01 December 2008 1:32:06 pm Alan Pevec wrote: > Darryl L. Pierce wrote: > > On all other platforms, it's simply $dist-updates. > > ACK Pushed. -- 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: signature.asc Type: application/pgp-signature Size: 197 bytes Desc: This is a digitally signed message part. URL: From dpierce at redhat.com Mon Dec 1 21:40:30 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 1 Dec 2008 16:40:30 -0500 Subject: [Ovirt-devel] [PATCH appliance] Allows create-ovirt-appliance to overwrite an existing appliance. Message-ID: <1228167630-10376-1-git-send-email-dpierce@redhat.com> Adds the argument "-u" which tells the script to undefine an existing appliance with the same name as the appliance to be created. Signed-off-by: Darryl L. Pierce --- create-ovirt-appliance | 11 ++++++++++- 1 files changed, 10 insertions(+), 1 deletions(-) diff --git a/create-ovirt-appliance b/create-ovirt-appliance index 1a1529f..938c766 100755 --- a/create-ovirt-appliance +++ b/create-ovirt-appliance @@ -27,18 +27,20 @@ Usage: $ME [-d image_dir] [-n name] [-c] [-f raw|qcow2] -n: appliance name (default: $NAME_DEFAULT) -c: open console when appliance is started -f: disk image format for appliance (default: $DISK_FMT_DEFAULT) + -u: undefine any existing appliance with same name -h: display this help and exit EOF } err=0 help=0 console=0 -while getopts :d:n:cf:h c; do +while getopts :d:n:cf:uh c; do case $c in d) imgdir=$OPTARG;; n) name=$OPTARG;; c) console=1;; f) DISK_FMT=$OPTARG;; + u) undefine_vm=1;; h) help=1;; '?') err=1; warn "invalid option: \`-$OPTARG'";; :) err=1; warn "missing argument to \`-$OPTARG' option";; @@ -50,6 +52,13 @@ test $help = 1 && { usage; exit 0; } do_checks +if [ -n "$undefine_vm" ]; then + # destroy the existing virtual machine that has the same name as the + # appliance to be created + echo "Undefine existing application named $name..." + virsh undefine $name > /dev/null 2>&1& +fi + if virsh dumpxml $name > /dev/null 2>&1 ; then # If the appliance is already defined, abort since rewriting the appliance # will change network settings that break the appliance. -- 1.6.0.4 From pmyers at redhat.com Mon Dec 1 21:49:00 2008 From: pmyers at redhat.com (Perry Myers) Date: Mon, 01 Dec 2008 16:49:00 -0500 Subject: [Ovirt-devel] [PATCH appliance] Allows create-ovirt-appliance to overwrite an existing appliance. In-Reply-To: <1228167630-10376-1-git-send-email-dpierce@redhat.com> References: <1228167630-10376-1-git-send-email-dpierce@redhat.com> Message-ID: <49345BCC.9060103@redhat.com> Darryl L. Pierce wrote: > Adds the argument "-u" which tells the script to undefine an existing > appliance with the same name as the appliance to be created. This will create problems... If you run create-ovirt-appliance with -u it will re-create the appliance but if you have not updated the disk image your network on the appliance will be possibly messed up. Hence the reason why I say in the following check: > # If the appliance is already defined, abort since rewriting the appliance > # will change network settings that break the appliance. So the proper way to re-create the appliance image is to first run get-ovirt-appliance which copies a pristine disk image into the images directory, followed by create-ovirt-appliance. get-ovirt-appliance undefines the old appliance, making the -u option unnecessary for create-ovirt-appliance Perry > Signed-off-by: Darryl L. Pierce > --- > create-ovirt-appliance | 11 ++++++++++- > 1 files changed, 10 insertions(+), 1 deletions(-) > > diff --git a/create-ovirt-appliance b/create-ovirt-appliance > index 1a1529f..938c766 100755 > --- a/create-ovirt-appliance > +++ b/create-ovirt-appliance > @@ -27,18 +27,20 @@ Usage: $ME [-d image_dir] [-n name] [-c] [-f raw|qcow2] > -n: appliance name (default: $NAME_DEFAULT) > -c: open console when appliance is started > -f: disk image format for appliance (default: $DISK_FMT_DEFAULT) > + -u: undefine any existing appliance with same name > -h: display this help and exit > EOF > } > > err=0 help=0 > console=0 > -while getopts :d:n:cf:h c; do > +while getopts :d:n:cf:uh c; do > case $c in > d) imgdir=$OPTARG;; > n) name=$OPTARG;; > c) console=1;; > f) DISK_FMT=$OPTARG;; > + u) undefine_vm=1;; > h) help=1;; > '?') err=1; warn "invalid option: \`-$OPTARG'";; > :) err=1; warn "missing argument to \`-$OPTARG' option";; > @@ -50,6 +52,13 @@ test $help = 1 && { usage; exit 0; } > > do_checks > > +if [ -n "$undefine_vm" ]; then > + # destroy the existing virtual machine that has the same name as the > + # appliance to be created > + echo "Undefine existing application named $name..." > + virsh undefine $name > /dev/null 2>&1& > +fi > + > if virsh dumpxml $name > /dev/null 2>&1 ; then > # If the appliance is already defined, abort since rewriting the appliance > # will change network settings that break the appliance. -- |=- 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 Dec 1 21:58:47 2008 From: dpierce at redhat.com (Darryl Pierce) Date: Mon, 1 Dec 2008 16:58:47 -0500 Subject: [Ovirt-devel] [PATCH appliance] Allows create-ovirt-appliance =?utf-8?q?to=09overwrite_an_existing?= appliance. In-Reply-To: <49345BCC.9060103@redhat.com> References: <1228167630-10376-1-git-send-email-dpierce@redhat.com> <49345BCC.9060103@redhat.com> Message-ID: <200812011658.47796.dpierce@redhat.com> On Monday 01 December 2008 4:49:00 pm Perry Myers wrote: > So the proper way to re-create the appliance image is to first run > get-ovirt-appliance which copies a pristine disk image into the images > directory, followed by create-ovirt-appliance. On F10, at least, when I run get-ovirt-appliance and then create-ovirt- appliance I get: [root at mcpierce-testing ~]# create-ovirt-appliance ovirt-appliance is already a defined virtual machine. create-ovirt-appliance: Try `create-ovirt-appliance -h' for more information. In looking at the output it's failing to download http://ovirt.org/download/ovirt-appliance-0.96-x86_64.tar.bz2.sha1sum since there are no 0.96 rpms on the site. :-/ -- 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: signature.asc Type: application/pgp-signature Size: 197 bytes Desc: This is a digitally signed message part. URL: From pmyers at redhat.com Mon Dec 1 22:14:21 2008 From: pmyers at redhat.com (Perry Myers) Date: Mon, 01 Dec 2008 17:14:21 -0500 Subject: [Ovirt-devel] [PATCH appliance] Allows create-ovirt-appliance to overwrite an existing appliance. In-Reply-To: <200812011658.47796.dpierce@redhat.com> References: <1228167630-10376-1-git-send-email-dpierce@redhat.com> <49345BCC.9060103@redhat.com> <200812011658.47796.dpierce@redhat.com> Message-ID: <493461BD.1060607@redhat.com> Darryl Pierce wrote: > On Monday 01 December 2008 4:49:00 pm Perry Myers wrote: >> So the proper way to re-create the appliance image is to first run >> get-ovirt-appliance which copies a pristine disk image into the images >> directory, followed by create-ovirt-appliance. > > On F10, at least, when I run get-ovirt-appliance and then create-ovirt- > appliance I get: > > [root at mcpierce-testing ~]# create-ovirt-appliance > ovirt-appliance is already a defined virtual machine. > create-ovirt-appliance: > Try `create-ovirt-appliance -h' for more information. > > In looking at the output it's failing to download > http://ovirt.org/download/ovirt-appliance-0.96-x86_64.tar.bz2.sha1sum > > since there are no 0.96 rpms on the site. :-/ > We haven't done the official .96 release yet, hence no archives on the web site. What you should be doing is: # get-ovirt-appliance -l appliance from the top level directory you normally run ovirt.mk from. And there is a handy target in ovirt.mk that does all of this for you. # make update-app update-app does update-host followed by get-ovirt-appliance -l appliance and create-ovirt-appliance. See the following commit messages in ovirt-release: 23a4a7dd841d84809ec7722bfa1a47a11169f89f 49cdda6c669f7d6ce7986416048408663032b2ab 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 sburgess at redhat.com Tue Dec 2 00:07:07 2008 From: sburgess at redhat.com (Susan Burgess) Date: Tue, 02 Dec 2008 10:07:07 +1000 Subject: [Ovirt-devel] Status Report - Susan Burgess - 12/02/2008 Message-ID: <49347C2B.10505@redhat.com> * I passed the RHCT exam! Thanks to all my colleagues who helped and endured the endless questions!! * Preparing UI to olh linkmap, to assist in context-sensitivity * Continued to Updated OSS UI Usage doc * new tutorial chapter, Quick Start * Decided to update screenshots once the UI is frozen * Add networking information * Would like to know productization status of the UI? Next Week * Continue work on updating oVirt Usage Guide/s Other info A reminder that I will be on vacation from the 15th Dec to 14th Jan. (Yes, we are continuing with our holiday as planned. We will be in Bangalore, Goa and Mumbai, in that order.) Thanks Susan -- Susan Burgess Content Author Red Hat APAC Level 1, 193 North Quay Brisbane, QLD 4000 Australia Phone +61 7 3514 8179 Fax +61 7 3514 8199 Mail sburgess at redhat.com From jdong at redhat.com Tue Dec 2 06:01:19 2008 From: jdong at redhat.com (Jia Dong) Date: Tue, 02 Dec 2008 14:01:19 +0800 Subject: [Ovirt-devel] How to fix "500 internal server error"? Message-ID: <4934CF2F.6050604@redhat.com> Hey guys, I got a problem. I deleted "default" hardware pool several days before. And I had to reinstall ovirt. I got a prompt "500 internal server error" today. After refreshing,I can not login to UI. It prompt "We're sorry,but something went wrong." I think it may be caused by trying to rename the "default" hardware pool. How can I fix this? Must I reinstall it? Did this action just destroy UI or virtualization configuration ? Some other peoples also met this problem. Would ovirt buddies give a feature about resetting? :-) Thanks, Nikki From jdong at redhat.com Tue Dec 2 07:09:39 2008 From: jdong at redhat.com (Jia Dong) Date: Tue, 02 Dec 2008 15:09:39 +0800 Subject: [Ovirt-devel] How to fix "500 internal server error"? In-Reply-To: <4934CF2F.6050604@redhat.com> References: <4934CF2F.6050604@redhat.com> Message-ID: <4934DF33.7090302@redhat.com> Jia Dong wrote: > Hey guys, > I got a problem. > I deleted "default" hardware pool several days before. And I had to > reinstall ovirt. I got a prompt "500 internal server error" today. > After refreshing,I can not login to UI. It prompt "We're sorry,but > something went wrong." I think it may be caused by trying to rename > the "default" hardware pool. > How can I fix this? Must I reinstall it? > Did this action just destroy UI or virtualization configuration ? > Some other peoples also met this problem. Would ovirt buddies give a > feature about resetting? :-) And there are messages in virt-viewer: EXT3-fs error (device sda2):etx3_add_entry : bad entry in directory in directory #1141426 : rec_len is smaller than minimal - offset=0 ,inode=0,rec_len=0,name_len=0 > Thanks, > Nikki > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel From apevec at gmail.com Tue Dec 2 08:42:52 2008 From: apevec at gmail.com (Alan Pevec) Date: Tue, 2 Dec 2008 09:42:52 +0100 Subject: [Ovirt-devel] How to fix "500 internal server error"? In-Reply-To: <4934DF33.7090302@redhat.com> References: <4934CF2F.6050604@redhat.com> <4934DF33.7090302@redhat.com> Message-ID: <2be7262f0812020042l58affa23kd98ccffbfc56d181@mail.gmail.com> On Tue, Dec 2, 2008 at 8:09 AM, Jia Dong wrote: > Jia Dong wrote: > >> Hey guys, >> I got a problem. >> I deleted "default" hardware pool several days before. And I had to >> reinstall ovirt. I got a prompt "500 internal server error" today. After >> refreshing,I can not login to UI. It prompt "We're sorry,but something went >> wrong." I think it may be caused by trying to rename the "default" hardware >> pool. >> How can I fix this? Must I reinstall it? >> Did this action just destroy UI or virtualization configuration ? >> Some other peoples also met this problem. Would ovirt buddies give a >> feature about resetting? :-) >> > And there are messages in virt-viewer: > EXT3-fs error (device sda2):etx3_add_entry : bad entry in directory in > directory #1141426 : rec_len is smaller than minimal > - offset=0 ,inode=0,rec_len=0,name_len=0 > Jia, is that F-10 ? I just saw in my F10 dmesg output: EXT3-fs error (device sda2): htree_dirblock_to_tree: bad entry in directory #265106: rec_len is smaller than minimal - offset=0, inode=0, rec_len=0, name_len=0 EXT3-fs error (device sda2): htree_dirblock_to_tree: bad entry in directory #265110: rec_len is smaller than minimal - offset=0, inode=0, rec_len=0, name_len=0 On firstboot, I got PostgreSQL DB initialized, but psql failed with weird error: psql: FATAL: catalog is missing 1 attribute(s) for relid 2662 restarting postgres failed, in pg_log: LOG: database system was not properly shut down; automatic recovery in progress LOG: record with zero length at 0/49AD98 LOG: redo is not required FATAL: could not access status of transaction 1 DETAIL: Could not open file "pg_multixact/offsets/0000": No such file or directory. LOG: startup process (PID 6547) exited with exit code 1 LOG: aborting startup due to startup process failure This all looks like a bad corruption somewhere. As a sanity check, I'll do F9 build now. -------------- next part -------------- An HTML attachment was scrubbed... URL: From jdong at redhat.com Tue Dec 2 09:08:53 2008 From: jdong at redhat.com (Jia Dong) Date: Tue, 02 Dec 2008 17:08:53 +0800 Subject: [Ovirt-devel] How to fix "500 internal server error"? In-Reply-To: <2be7262f0812020042l58affa23kd98ccffbfc56d181@mail.gmail.com> References: <4934CF2F.6050604@redhat.com> <4934DF33.7090302@redhat.com> <2be7262f0812020042l58affa23kd98ccffbfc56d181@mail.gmail.com> Message-ID: <4934FB25.6020803@redhat.com> Alan Pevec wrote: > > > On Tue, Dec 2, 2008 at 8:09 AM, Jia Dong > wrote: > > Jia Dong wrote: > > Hey guys, > I got a problem. > I deleted "default" hardware pool several days before. And I > had to reinstall ovirt. I got a prompt "500 internal server > error" today. After refreshing,I can not login to UI. It > prompt "We're sorry,but something went wrong." I think it may > be caused by trying to rename the "default" hardware pool. > How can I fix this? Must I reinstall it? > Did this action just destroy UI or virtualization configuration ? > Some other peoples also met this problem. Would ovirt buddies > give a feature about resetting? :-) > > And there are messages in virt-viewer: > EXT3-fs error (device sda2):etx3_add_entry : bad entry in > directory in directory #1141426 : rec_len is smaller than minimal > - offset=0 ,inode=0,rec_len=0,name_len=0 > > > Jia, is that F-10 ? > I just saw in my F10 dmesg output: > EXT3-fs error (device sda2): htree_dirblock_to_tree: bad entry in > directory #265106: rec_len is smaller than minimal - offset=0, > inode=0, rec_len=0, name_len=0 > EXT3-fs error (device sda2): htree_dirblock_to_tree: bad entry in > directory #265110: rec_len is smaller than minimal - offset=0, > inode=0, rec_len=0, name_len=0 > > On firstboot, I got PostgreSQL DB initialized, but psql failed with > weird error: > psql: FATAL: catalog is missing 1 attribute(s) for relid 2662 > > restarting postgres failed, in pg_log: > LOG: database system was not properly shut down; automatic recovery > in progress > LOG: record with zero length at 0/49AD98 > LOG: redo is not required > FATAL: could not access status of transaction 1 > DETAIL: Could not open file "pg_multixact/offsets/0000": No such file > or directory. > LOG: startup process (PID 6547) exited with exit code 1 > LOG: aborting startup due to startup process failure > > This all looks like a bad corruption somewhere. As a sanity check, > I'll do F9 build now. > Hi Alan, I ran it on F9. How did you install it on F10? I tried to install it on F10 this morning, and got a message that there was no packages for F10.Or you built sources on F10? I guess there are maybe something unrecognize on F10. Now, if these errors appear, I have to reinstall ovirt again and again. T_T Waiting for any good solution. From apevec at gmail.com Tue Dec 2 10:43:47 2008 From: apevec at gmail.com (Alan Pevec) Date: Tue, 2 Dec 2008 11:43:47 +0100 Subject: [Ovirt-devel] How to fix "500 internal server error"? In-Reply-To: <2be7262f0812020242j765eb6e1v2291313abf93ed22@mail.gmail.com> References: <4934CF2F.6050604@redhat.com> <4934DF33.7090302@redhat.com> <2be7262f0812020042l58affa23kd98ccffbfc56d181@mail.gmail.com> <4934FB25.6020803@redhat.com> <2be7262f0812020242j765eb6e1v2291313abf93ed22@mail.gmail.com> Message-ID: <2be7262f0812020243k603ccc59keae5124c5db8b9b6@mail.gmail.com> On Tue, Dec 2, 2008 at 10:08 AM, Jia Dong wrote: > Alan Pevec wrote: >> This all looks like a bad corruption somewhere. As a sanity check, I'll do F9 build now. > I ran it on F9. > How did you install it on F10? I tried to install it on F10 this morning, and got a message that there was no packages for F10.Or you built sources on F10? Yeah, F10 was built from git. But in any case, I got the same issue on F9 and the culprit is the updated kvm-79. I'll downgrade back to 78-4 in ovirt.org repo and we'll use that for the 0.96 release we're wrapping up. After release is out, I'll bisect between 78 and 79 to find out what introduced this issue. From apevec at redhat.com Tue Dec 2 10:57:36 2008 From: apevec at redhat.com (Alan Pevec) Date: Tue, 2 Dec 2008 11:57:36 +0100 Subject: [Ovirt-devel] [PATCH node-image] edit-livecd: optionally append kernel boot params Message-ID: <1228215456-30502-1-git-send-email-apevec@redhat.com> --- edit-livecd | 37 +++++++++++++++++++++++++++++-------- 1 files changed, 29 insertions(+), 8 deletions(-) diff --git a/edit-livecd b/edit-livecd index 0200034..8025fb6 100755 --- a/edit-livecd +++ b/edit-livecd @@ -25,12 +25,17 @@ warn() { printf '%s: %s\n' "$ME" "$*" >&2; } try_h() { printf "Try \`$ME -h' for more information.\n" >&2; } die() { warn "$@"; try_h; exit 1; } +NODEIMG_DEFAULT=/usr/share/ovirt-node-image/ovirt-node-image.iso +CD=$NODEIMG_DEFAULT + usage() { case $# in 1) warn "$1"; try_h; exit 1;; esac cat < /dev/null 2>&1 WDIR=`mktemp -d $PWD/livecd.XXXXXXXXXX` @@ -81,7 +96,8 @@ function mnt() { addExit "rm -Rf $WDIR" -LABEL=$(isoinfo -d -i $CD | awk -F ": " '/Volume id:/ {print $2}') +eval $(/lib/udev/vol_id $CD) +LABEL=$ID_FS_LABEL # mount the CD image mnt "-t auto $CD -o loop,ro" cd @@ -122,6 +138,11 @@ mksquashfs $WDIR/sq-w/ $WDIR/cd-w/LiveOS/squashfs.img -noappend echo ">>> Recomputing MD5 sums" ( cd $WDIR/cd-w && find . -type f -not -name md5sum.txt -not -path '*/isolinux/*' -print0 | xargs -0 -- md5sum > md5sum.txt ) +if [ -n "$PARAMS" ]; then + echo ">>> Appending boot parameters" + sed -i 's/^ append .*$/& '$PARAMS/ "$WDIR/cd-w/isolinux/isolinux.cfg" +fi + echo ">>> Creating ISO image $ISO" mkisofs \ -V "$LABEL" \ -- 1.5.6.5 From jim at meyering.net Tue Dec 2 11:13:16 2008 From: jim at meyering.net (Jim Meyering) Date: Tue, 02 Dec 2008 12:13:16 +0100 Subject: [Ovirt-devel] [PATCH node-image] edit-livecd: optionally append kernel boot params In-Reply-To: <1228215456-30502-1-git-send-email-apevec@redhat.com> (Alan Pevec's message of "Tue, 2 Dec 2008 11:57:36 +0100") References: <1228215456-30502-1-git-send-email-apevec@redhat.com> Message-ID: <87zljeg78z.fsf@rho.meyering.net> Alan Pevec wrote: > --- > edit-livecd | 37 +++++++++++++++++++++++++++++-------- > 1 files changed, 29 insertions(+), 8 deletions(-) Good timing, since I was just considering changing usage to require something like an --output=FILE option to specify the output file name, rather than using $(basename $ISO .iso)-custom.iso, which puts the result in the current directory. > diff --git a/edit-livecd b/edit-livecd > index 0200034..8025fb6 100755 > --- a/edit-livecd > +++ b/edit-livecd > @@ -25,12 +25,17 @@ warn() { printf '%s: %s\n' "$ME" "$*" >&2; } > try_h() { printf "Try \`$ME -h' for more information.\n" >&2; } > die() { warn "$@"; try_h; exit 1; } > > +NODEIMG_DEFAULT=/usr/share/ovirt-node-image/ovirt-node-image.iso > +CD=$NODEIMG_DEFAULT > + > usage() { > case $# in 1) warn "$1"; try_h; exit 1;; esac > cat < -Usage: $ME livecd.iso program > - livecd.iso - LiveCD ISO to edit > - program - Arbitrary program/script that is run inside of the livecd root > +Usage: $ME -i LiveCD.iso [-b bootparams] [-p program] > + -h: display this help and exit > + -i: livecd.iso - LiveCD ISO to edit (default: $NODEIMG_DEFAULT) > + -b: bootparams - optional parameters appended to the kernel command line > + -p: program - Arbitrary program/script that is run inside of the livecd root Please remove the ":" after each option, and leave at least two spaces between option-arg and description (in case we ever use help2man): -h display this help and exit -i livecd.iso LiveCD ISO to edit (default: $NODEIMG_DEFAULT) -b bootparams optional parameters appended to the kernel command line -p program Arbitrary program/script that is run inside of the livecd ... > @@ -48,16 +53,26 @@ EOF > # exit after any error: > set -e > > -test $# -lt 1 && { usage; exit 1; } > +err=0 help=0 > +while getopts :b:i:p:h c; do > + case $c in > + i) CD=$OPTARG;; > + b) PARAMS=$OPTARG;; > + p) PROG=$OPTARG;; > + h) help=1;; > + '?') err=1; warn "invalid option: \`-$OPTARG'";; > + :) err=1; warn "missing argument to \`-$OPTARG' option";; > + *) err=1; warn "internal error: \`-$OPTARG' not handled";; > + esac > +done > +test $err = 1 && { try_h; exit 1; } > +test $help = 1 && { usage; exit 0; } > > # first, check to see we are root > if [ $( id -u ) -ne 0 ]; then > die "Must run as root" > fi > > -CD=$1 > -PROG=$2 > - > which mkisofs mksquashfs sed > /dev/null 2>&1 > > WDIR=`mktemp -d $PWD/livecd.XXXXXXXXXX` > @@ -81,7 +96,8 @@ function mnt() { > > addExit "rm -Rf $WDIR" > > -LABEL=$(isoinfo -d -i $CD | awk -F ": " '/Volume id:/ {print $2}') > +eval $(/lib/udev/vol_id $CD) You'll want extra quotes, to be safe: eval "$(/lib/udev/vol_id $CD)" > +LABEL=$ID_FS_LABEL > > # mount the CD image > mnt "-t auto $CD -o loop,ro" cd > @@ -122,6 +138,11 @@ mksquashfs $WDIR/sq-w/ $WDIR/cd-w/LiveOS/squashfs.img -noappend > echo ">>> Recomputing MD5 sums" > ( cd $WDIR/cd-w && find . -type f -not -name md5sum.txt -not -path '*/isolinux/*' -print0 | xargs -0 -- md5sum > md5sum.txt ) > > +if [ -n "$PARAMS" ]; then > + echo ">>> Appending boot parameters" > + sed -i 's/^ append .*$/& '$PARAMS/ "$WDIR/cd-w/isolinux/isolinux.cfg" and you need quotes around $PARAMS: sed -i 's/^ append .*$/& '"$PARAMS"/ "$WDIR/cd-w/isolinux/isolinux.cfg" And you'll also want to make the script fail -- or maybe try to find a usable sed delimiter if $PARAMS contains a slash. > +fi > + > echo ">>> Creating ISO image $ISO" > mkisofs \ > -V "$LABEL" \ From apevec at gmail.com Tue Dec 2 12:13:30 2008 From: apevec at gmail.com (Alan Pevec) Date: Tue, 2 Dec 2008 13:13:30 +0100 Subject: [Ovirt-devel] How to fix "500 internal server error"? In-Reply-To: <2be7262f0812020243k603ccc59keae5124c5db8b9b6@mail.gmail.com> References: <4934CF2F.6050604@redhat.com> <4934DF33.7090302@redhat.com> <2be7262f0812020042l58affa23kd98ccffbfc56d181@mail.gmail.com> <4934FB25.6020803@redhat.com> <2be7262f0812020242j765eb6e1v2291313abf93ed22@mail.gmail.com> <2be7262f0812020243k603ccc59keae5124c5db8b9b6@mail.gmail.com> Message-ID: <2be7262f0812020413s7d28aa16na23f18575325e399@mail.gmail.com> On Tue, Dec 2, 2008 at 11:43 AM, Alan Pevec wrote: > On Tue, Dec 2, 2008 at 10:08 AM, Jia Dong wrote: >> Alan Pevec wrote: >>> This all looks like a bad corruption somewhere. As a sanity check, I'll do F9 build now. >> I ran it on F9. >> How did you install it on F10? I tried to install it on F10 this morning, and got a message that there was no packages for F10.Or you built sources on F10? > > Yeah, F10 was built from git. > But in any case, I got the same issue on F9 and the culprit is the > updated kvm-79. > I'll downgrade back to 78-4 in ovirt.org repo and we'll use that for > the 0.96 release we're wrapping up. 78-4 is up now, please do: rpm -e --nodeps kvm; yum -y install --enablerepo=ovirt kvm and reinstall ovirt-appliance to run firstboot again From apevec at gmail.com Tue Dec 2 12:32:44 2008 From: apevec at gmail.com (Alan Pevec) Date: Tue, 2 Dec 2008 13:32:44 +0100 Subject: [Ovirt-devel] Re: [PATCH recipe] Switched console tty0 and ttyS0 so that serial console works properly in F10 In-Reply-To: <492C11EC.1030906@redhat.com> References: <1227223321-20319-1-git-send-email-pmyers@redhat.com> <20081121134141.7a3a44c2@tp.mains.net> <492BF7AF.8060002@redhat.com> <492C11EC.1030906@redhat.com> Message-ID: <2be7262f0812020432q417537b7p513a885a750fa8ee@mail.gmail.com> On Tue, Nov 25, 2008 at 3:55 PM, Perry Myers wrote: > So this patch is ok once we completely move to F10 then, but as long as > we've still got people using F9 we can't apply it. > > Correct? yeah, works perfect on f10 - I see boot messages on both console and serial displayed in parallel and /var/log/boot.log is back (after being empty since FC4). I think we should just force the upgrade to F10 for Node and appliance images and developers. Users could still install the appliance on F9 host using libvirt and kvm from ovirt.org. From jim at meyering.net Tue Dec 2 15:53:41 2008 From: jim at meyering.net (Jim Meyering) Date: Tue, 02 Dec 2008 16:53:41 +0100 Subject: [Ovirt-devel] [PATCH node-image] edit-livecd: optionally append kernel boot params In-Reply-To: <87zljeg78z.fsf@rho.meyering.net> (Jim Meyering's message of "Tue, 02 Dec 2008 12:13:16 +0100") References: <1228215456-30502-1-git-send-email-apevec@redhat.com> <87zljeg78z.fsf@rho.meyering.net> Message-ID: <87iqq2efp6.fsf@rho.meyering.net> Jim Meyering wrote: > Alan Pevec wrote: >> --- >> edit-livecd | 37 +++++++++++++++++++++++++++++-------- >> 1 files changed, 29 insertions(+), 8 deletions(-) > > Good timing, since I was just considering changing usage to require > something like an --output=FILE option to specify the output > file name, rather than using $(basename $ISO .iso)-custom.iso, > which puts the result in the current directory. > >> diff --git a/edit-livecd b/edit-livecd Hi Alan, Here's an incremental diff on top of yours. It reflects the comments I sent already in this thread, fixes a couple more things, and adds a few FIXME comments. If this looks ok to you, let me know and I'll amend and push the result. cat < TeST #!/bin/sh test -f etc/TeST && ls -l etc/TeST touch etc/TeST EOF chmod a+x TeST ./edit-livecd -p TeST -i ovirt-node-image.iso ./edit-livecd -p TeST -i ovirt-node-image-custom.iso and noted that the latter run did output this: -rw-r--r--. 1 root root 0 2008-12-02 16:50 etc/TeST Note the -p PROGRAM-related FIXME. When I make that change I'll also realign the --help output. Jim ------------------------ diff --git a/edit-livecd b/edit-livecd index 8025fb6..c122eee 100755 --- a/edit-livecd +++ b/edit-livecd @@ -32,15 +32,15 @@ usage() { case $# in 1) warn "$1"; try_h; exit 1;; esac cat < /dev/null 2>&1 WDIR=`mktemp -d $PWD/livecd.XXXXXXXXXX` +# FIXME: fail if $WDIR contains white space or shell meta-characters +# FIXME: do the same for $CD. + ISO="${CD##*/}" ISO="${ISO%.iso}-custom.iso" @@ -94,9 +106,9 @@ function mnt() { addExit "df | grep $mp > /dev/null 2>&1 && umount -v $mp" } -addExit "rm -Rf $WDIR" +addExit "rm -rf $WDIR" -eval $(/lib/udev/vol_id $CD) +eval "$(/lib/udev/vol_id $CD)" LABEL=$ID_FS_LABEL # mount the CD image @@ -139,8 +151,10 @@ echo ">>> Recomputing MD5 sums" ( cd $WDIR/cd-w && find . -type f -not -name md5sum.txt -not -path '*/isolinux/*' -print0 | xargs -0 -- md5sum > md5sum.txt ) if [ -n "$PARAMS" ]; then + # FIXME: make the script fail -- or maybe try to + # find a usable sed delimiter if $PARAMS contains a slash echo ">>> Appending boot parameters" - sed -i 's/^ append .*$/& '$PARAMS/ "$WDIR/cd-w/isolinux/isolinux.cfg" + sed -i 's/^ append .*$/& '"$PARAMS/" "$WDIR/cd-w/isolinux/isolinux.cfg" fi echo ">>> Creating ISO image $ISO" @@ -155,4 +169,3 @@ mkisofs \ # The trap ... callbacks will unmount everything. set +e - From apevec at redhat.com Tue Dec 2 16:56:29 2008 From: apevec at redhat.com (Alan Pevec) Date: Tue, 02 Dec 2008 17:56:29 +0100 Subject: [Ovirt-devel] [PATCH node-image] edit-livecd: optionally append kernel boot params In-Reply-To: <87iqq2efp6.fsf@rho.meyering.net> References: <1228215456-30502-1-git-send-email-apevec@redhat.com> <87zljeg78z.fsf@rho.meyering.net> <87iqq2efp6.fsf@rho.meyering.net> Message-ID: <493568BD.5090804@redhat.com> Jim Meyering wrote: > Here's an incremental diff on top of yours. > It reflects the comments I sent already in this thread, > fixes a couple more things, and adds a few FIXME comments. > If this looks ok to you, let me know and I'll amend and push the result. looks good, go ahead! > Note the -p PROGRAM-related FIXME. > When I make that change I'll also realign the --help output. ... > +# FIXME: instead of requiring a PROGRAM, allow arbitrary shell code, This is ok for quick changes, but forcing people to write a script has an advantage that they have more persistent trace what changes they did to the image. But anyway, let's have that option. From jim at meyering.net Tue Dec 2 17:10:11 2008 From: jim at meyering.net (Jim Meyering) Date: Tue, 02 Dec 2008 18:10:11 +0100 Subject: [Ovirt-devel] [PATCH node-image] edit-livecd: Retry upon failed umount. Message-ID: <873ah6ec5o.fsf@rho.meyering.net> This is useful when you manually edit an image and forget to "cd" out of the working directory. Without this, the script can't clean up, and it's a pain to do manually. --- edit-livecd | 16 ++++++++++++++-- 1 files changed, 14 insertions(+), 2 deletions(-) diff --git a/edit-livecd b/edit-livecd index c122eee..ce9e65b 100755 --- a/edit-livecd +++ b/edit-livecd @@ -141,8 +141,20 @@ else echo "***" read fi -echo ">>> Unmounting ext3fs" -umount $WDIR/ex + +# Try to unmount. But this is likely to fail, so let the user retry, +# e.g., if he forgot to "cd" out of $WDIR/ex. +while :; do + echo ">>> Unmounting ext3fs" + umount $WDIR/ex && break + echo ">>> Unmounting ext3fs failed" + echo "***" + echo "*** Did you forget to 'cd' out of $WDIR/ex?" + echo "***" + echo "*** Press any key to repeat the attempt." + echo "***" + read +done echo ">>> Compressing filesystem" mksquashfs $WDIR/sq-w/ $WDIR/cd-w/LiveOS/squashfs.img -noappend -- 1.6.1.rc1.279.g45d11 From jim at meyering.net Tue Dec 2 17:10:43 2008 From: jim at meyering.net (Jim Meyering) Date: Tue, 02 Dec 2008 18:10:43 +0100 Subject: [Ovirt-devel] [PATCH node-image] clean up quoting, cleanup-on-exception, use mktemp-not-/tmp, etc. Message-ID: <87zljecxkc.fsf@rho.meyering.net> --- ovirt-flash-static | 77 ++++++++++++++++++++++++++++++++++++--------------- 1 files changed, 54 insertions(+), 23 deletions(-) diff --git a/ovirt-flash-static b/ovirt-flash-static index 4c2bb22..00b26de 100755 --- a/ovirt-flash-static +++ b/ovirt-flash-static @@ -26,39 +26,70 @@ 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 ! -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-$$ +case $ISO in + *.iso) ;; + *) die "ME: ISO file name, '$ISO' lacks .iso suffix" +esac + +tmpdir=$(mktemp -d) || exit 1 + +IMGTMP="$tmpdir/ovirt" +SQUASHTMP="$tmpdir/ovirt-squash" +USBTMP="$tmpdir/ovirt-usb" + +cleanup() +{ + { umount "$USBTMP" + umount "$SQUASHTMP" + umount "$IMGTMP" + } 2> /dev/null || : + rm -rf "$tmpdir" +} +trap cleanup 0 +trap 'Exit $?' 1 2 13 15 + +# From here on, any failure makes the script fail. +set -e # do setup -mkdir -p $IMGTMP $SQUASHTMP $USBTMP -mount -o loop $ISO $IMGTMP -mount -o loop $IMGTMP/LiveOS/squashfs.img $SQUASHTMP +mkdir -p "$IMGTMP" "$SQUASHTMP" "$USBTMP" +mount -o loop "$ISO" "$IMGTMP" + +squashfs_img="$IMGTMP/LiveOS/squashfs.img" +find "$IMGTMP" # FIXME +test -f "$squashfs_img" \ + || die "not a LiveCD image: $ISO" + +mount -o loop "$squashfs_img" "$SQUASHTMP" # clear out the old partition table -dd if=/dev/zero of=$USBDEVICE bs=4096 count=1 -printf 'n\np\n1\n\n\nt\n83\na\n1\nw\n' | fdisk $USBDEVICE +dd if=/dev/zero of="$USBDEVICE" bs=4096 count=1 +printf 'n\np\n1\n\n\nt\n83\na\n1\nw\n' | fdisk "$USBDEVICE" -cat /usr/lib/syslinux/mbr.bin > $USBDEVICE -dd if=$SQUASHTMP/LiveOS/ext3fs.img of=${USBDEVICE}1 +cat /usr/lib/syslinux/mbr.bin > "$USBDEVICE" +dd if="$SQUASHTMP/LiveOS/ext3fs.img" of="${USBDEVICE}1" -mount ${USBDEVICE}1 $USBTMP +mount "${USBDEVICE}1" "$USBTMP" -cp $IMGTMP/isolinux/* $USBTMP +cp "$IMGTMP"/isolinux/* "$USBTMP" -rm -f $USBTMP/isolinux.bin -mv $USBTMP/isolinux.cfg $USBTMP/extlinux.conf +rm -f "$USBTMP/isolinux.bin" +mv "$USBTMP/isolinux.cfg" "$USBTMP/extlinux.conf" -LABEL=`echo $ISO | cut -d'.' -f1 | cut -c-16` -sed -i -e "s/ *append.*/ append initrd=initrd.img root=LABEL=$LABEL ro/" $USBTMP/extlinux.conf +iso_base=$(basename "$ISO" .iso) +# sanitize for sed and the label name and limit to 16 bytes +LABEL=$(echo "$iso_base" | cut -b-16 | tr -c '[[:alnum:]_.-]' _) +sed -i -e "s/ *append.*/ append initrd=initrd.img root=LABEL=$LABEL ro/" \ + "$USBTMP/extlinux.conf" -extlinux -i $USBTMP +extlinux -i "$USBTMP" -umount $USBTMP -umount $SQUASHTMP -umount $IMGTMP -rm -rf $SQUASHTMP $IMGTMP $USBTMP +# To test: +cat <<\EOF > /dev/null +mkdir -p t/LiveOS && (cd t/LiveOS && touch ext3fs.img squashfs.img) +genisoimage -U -o k2.iso t +EOF -- 1.6.1.rc1.279.g45d11 From pmyers at redhat.com Tue Dec 2 21:07:02 2008 From: pmyers at redhat.com (Perry Myers) Date: Tue, 2 Dec 2008 16:07:02 -0500 Subject: [Ovirt-devel] [PATCH release] Add check for minimum version of Fedora for building Message-ID: <1228252022-7047-1-git-send-email-pmyers@redhat.com> Builds on F9 will not work, so we check to make sure that minimum version if 10 Signed-off-by: Perry Myers --- ovirt.mk | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/ovirt.mk b/ovirt.mk index b0f7977..ee99f5a 100644 --- a/ovirt.mk +++ b/ovirt.mk @@ -15,12 +15,19 @@ SUBDIRS ?= release server node node-image recipe docs appliance SUBDIR_SEP = ============================================================ +FEDORA = $(shell rpm --eval '%{fedora}') +MIN_FEDORA = 10 + export OVIRT_CACHE_DIR ?= $(HOME)/ovirt-cache SRC_KS = $(OVIRT_CACHE_DIR)/src.ks F_REL = $(shell rpm -q --qf '%{VERSION}' fedora-release) BUILD_DIR := $(shell pwd) define subdir_gen_and_make + if [ "$(FEDORA)" -lt "$(MIN_FEDORA)" ]; then \ + echo "Minimum version of Fedora to build with is $(MIN_FEDORA)." ; \ + exit 1 ; \ + fi ; \ echo $(SUBDIR_SEP) $$dir; \ (cd $$dir && test ! -f Makefile.in && test -f autogen.sh && ./autogen.sh) \ || :; \ -- 1.6.0.4 From pmyers at redhat.com Tue Dec 2 21:19:02 2008 From: pmyers at redhat.com (Perry Myers) Date: Tue, 02 Dec 2008 16:19:02 -0500 Subject: [Ovirt-devel] Re: [PATCH release] Add check for minimum version of Fedora for building In-Reply-To: <1228252022-7047-1-git-send-email-pmyers@redhat.com> References: <1228252022-7047-1-git-send-email-pmyers@redhat.com> Message-ID: <4935A646.5010500@redhat.com> Perry Myers wrote: > Builds on F9 will not work, so we check to make sure that minimum > version if 10 This patch should have a bit more explanation to it :) Fedora 10 is officially released as of last week, and for the .96 release that is upcoming for oVirt we'll be moving to F10 as a base for the oVirt Node, Appliance and for building. There are several things that are broken on F9 that will probably not be fixed, and there aren't compelling reasons to continue supporting F9 as a base for oVirt as we're rapidly moving forward on the bleeding edge of functionality. The F9 repos on ovirt.org will be moved to an archive for historical purposes once .96 is released. Perry From dpierce at redhat.com Wed Dec 3 01:14:09 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Tue, 2 Dec 2008 20:14:09 -0500 Subject: [Ovirt-devel] Addition to install instructions... Message-ID: <20081203011406.GD8317@mcpierce-laptop.mcpierce.org> In testing on F10 I've found that our instructions do not include installing rubygem-rails onto a development system. Is there a reason we exclude that step? Or should I edit the instructions to include that? -- 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 Wed Dec 3 01:16:15 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Tue, 2 Dec 2008 20:16:15 -0500 Subject: [Ovirt-devel] Re: [PATCH release] Add check for minimum version of Fedora for building In-Reply-To: <4935A646.5010500@redhat.com> References: <1228252022-7047-1-git-send-email-pmyers@redhat.com> <4935A646.5010500@redhat.com> Message-ID: <20081203011612.GE8317@mcpierce-laptop.mcpierce.org> On Tue, Dec 02, 2008 at 04:19:02PM -0500, Perry Myers wrote: > Perry Myers wrote: >> Builds on F9 will not work, so we check to make sure that minimum >> version if 10 > > This patch should have a bit more explanation to it :) > > Fedora 10 is officially released as of last week, and for the .96 release > that is upcoming for oVirt we'll be moving to F10 as a base for the oVirt > Node, Appliance and for building. There are several things that are > broken on F9 that will probably not be fixed, and there aren't compelling > reasons to continue supporting F9 as a base for oVirt as we're rapidly > moving forward on the bleeding edge of functionality. > > The F9 repos on ovirt.org will be moved to an archive for historical > purposes once .96 is released. So once 0.96 is released we should also remove the conditionals in node-image and appliance Makefiles that check for F9 and include the *-newkeys repos. -- 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 sseago at redhat.com Wed Dec 3 02:52:00 2008 From: sseago at redhat.com (Scott Seago) Date: Tue, 02 Dec 2008 21:52:00 -0500 Subject: [Ovirt-devel] Addition to install instructions... In-Reply-To: <20081203011406.GD8317@mcpierce-laptop.mcpierce.org> References: <20081203011406.GD8317@mcpierce-laptop.mcpierce.org> Message-ID: <4935F450.20808@redhat.com> Darryl L. Pierce wrote: > In testing on F10 I've found that our instructions do not include > installing rubygem-rails onto a development system. Is there a > reason we exclude that step? Or should I edit the instructions to > include that? > Rails is already a dependency in the ovirt-server spec file: Requires: rubygem(rails) >= 2.1.1 So when you install the server RPM you'll get that automatically. Scott From pmyers at redhat.com Wed Dec 3 03:11:00 2008 From: pmyers at redhat.com (Perry Myers) Date: Tue, 02 Dec 2008 22:11:00 -0500 Subject: [Ovirt-devel] Re: [PATCH release] Add check for minimum version of Fedora for building In-Reply-To: <20081203011612.GE8317@mcpierce-laptop.mcpierce.org> References: <1228252022-7047-1-git-send-email-pmyers@redhat.com> <4935A646.5010500@redhat.com> <20081203011612.GE8317@mcpierce-laptop.mcpierce.org> Message-ID: <4935F8C4.5040009@redhat.com> Darryl L. Pierce wrote: > On Tue, Dec 02, 2008 at 04:19:02PM -0500, Perry Myers wrote: >> Perry Myers wrote: >>> Builds on F9 will not work, so we check to make sure that minimum >>> version if 10 >> This patch should have a bit more explanation to it :) >> >> Fedora 10 is officially released as of last week, and for the .96 release >> that is upcoming for oVirt we'll be moving to F10 as a base for the oVirt >> Node, Appliance and for building. There are several things that are >> broken on F9 that will probably not be fixed, and there aren't compelling >> reasons to continue supporting F9 as a base for oVirt as we're rapidly >> moving forward on the bleeding edge of functionality. >> >> The F9 repos on ovirt.org will be moved to an archive for historical >> purposes once .96 is released. > > So once 0.96 is released we should also remove the conditionals in > node-image and appliance Makefiles that check for F9 and include the > *-newkeys repos. > Yes, we should actually do this in next at the same time that this patch is pushed. 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 Wed Dec 3 03:12:16 2008 From: pmyers at redhat.com (Perry Myers) Date: Tue, 02 Dec 2008 22:12:16 -0500 Subject: [Ovirt-devel] Addition to install instructions... In-Reply-To: <4935F450.20808@redhat.com> References: <20081203011406.GD8317@mcpierce-laptop.mcpierce.org> <4935F450.20808@redhat.com> Message-ID: <4935F910.7080201@redhat.com> Scott Seago wrote: > Darryl L. Pierce wrote: >> In testing on F10 I've found that our instructions do not include >> installing rubygem-rails onto a development system. Is there a >> reason we exclude that step? Or should I edit the instructions to >> include that? >> > Rails is already a dependency in the ovirt-server spec file: > > Requires: rubygem(rails) >= 2.1.1 > > So when you install the server RPM you'll get that automatically. Also, for development (building via ovirt.mk) all dependencies are brought in by the ovirt-build RPM. So if there is a dependency for building missing, just patch the ovirt-release.spec file for that subpkg Perry From jdong at redhat.com Wed Dec 3 08:40:51 2008 From: jdong at redhat.com (Jia Dong) Date: Wed, 03 Dec 2008 16:40:51 +0800 Subject: [Ovirt-devel] How to login to the URL: http://192.168.50.2/cobbler/web/?mode=system_list In-Reply-To: <4935F8C4.5040009@redhat.com> References: <1228252022-7047-1-git-send-email-pmyers@redhat.com> <4935A646.5010500@redhat.com> <20081203011612.GE8317@mcpierce-laptop.mcpierce.org> <4935F8C4.5040009@redhat.com> Message-ID: <49364613.1010404@redhat.com> Hey guys, I am testing for a bug,and need more detail information. How to login to:http://192.168.50.2/cobbler/web/?mode=system_list ? I guess I must install something to support this.Cobbler?Or git the whole project?So turn to you guys for some detailed information. Thanks, Nikki From jdong at redhat.com Wed Dec 3 08:45:32 2008 From: jdong at redhat.com (Jia Dong) Date: Wed, 03 Dec 2008 16:45:32 +0800 Subject: [Ovirt-devel] How to fix "500 internal server error"? In-Reply-To: <2be7262f0812020413s7d28aa16na23f18575325e399@mail.gmail.com> References: <4934CF2F.6050604@redhat.com> <4934DF33.7090302@redhat.com> <2be7262f0812020042l58affa23kd98ccffbfc56d181@mail.gmail.com> <4934FB25.6020803@redhat.com> <2be7262f0812020242j765eb6e1v2291313abf93ed22@mail.gmail.com> <2be7262f0812020243k603ccc59keae5124c5db8b9b6@mail.gmail.com> <2be7262f0812020413s7d28aa16na23f18575325e399@mail.gmail.com> Message-ID: <4936472C.7070206@redhat.com> Alan Pevec wrote: > On Tue, Dec 2, 2008 at 11:43 AM, Alan Pevec wrote: > >> On Tue, Dec 2, 2008 at 10:08 AM, Jia Dong wrote: >> >>> Alan Pevec wrote: >>> >>>> This all looks like a bad corruption somewhere. As a sanity check, I'll do F9 build now. >>>> >>> I ran it on F9. >>> How did you install it on F10? I tried to install it on F10 this morning, and got a message that there was no packages for F10.Or you built sources on F10? >>> >> Yeah, F10 was built from git. >> But in any case, I got the same issue on F9 and the culprit is the >> updated kvm-79. >> I'll downgrade back to 78-4 in ovirt.org repo and we'll use that for >> the 0.96 release we're wrapping up. >> > > 78-4 is up now, please do: rpm -e --nodeps kvm; yum -y install > --enablerepo=ovirt kvm > and reinstall ovirt-appliance to run firstboot again > Hey Alan, I sent this mail just for a feedback that it works! And thank you. o(?_?)o... Nikki From hbrock at redhat.com Wed Dec 3 12:04:22 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Wed, 3 Dec 2008 07:04:22 -0500 Subject: [Ovirt-devel] How to login to the URL: http://192.168.50.2/cobbler/web/?mode=system_list In-Reply-To: <49364613.1010404@redhat.com> References: <1228252022-7047-1-git-send-email-pmyers@redhat.com> <4935A646.5010500@redhat.com> <20081203011612.GE8317@mcpierce-laptop.mcpierce.org> <4935F8C4.5040009@redhat.com> <49364613.1010404@redhat.com> Message-ID: <20081203120422.GL7558@redhat.com> On Wed, Dec 03, 2008 at 04:40:51PM +0800, Jia Dong wrote: > Hey guys, > I am testing for a bug,and need more detail information. > How to login to:http://192.168.50.2/cobbler/web/?mode=system_list ? I > guess I must install something to support this.Cobbler?Or git the whole > project?So turn to you guys for some detailed information. > Thanks, > Nikki Hi Nikki. The cobbler web UI should be installed in the appliance by default, but I can't remember what the default username/password is. I suspect it's admin/admin. I'll try to find out for you. Take care, --Hugh From d.vasilets at peterhost.ru Wed Dec 3 12:19:52 2008 From: d.vasilets at peterhost.ru (=?koi8-r?Q?=F7=C1=D3=C9=CC=C5=C3_?= =?koi8-r?Q?=E4=CD=C9=D4=D2=C9=CA?=) Date: Wed, 03 Dec 2008 15:19:52 +0300 Subject: [Ovirt-devel] what is default root password for ovirt-appliance ? Message-ID: <1228306792.8446.1.camel@dima-desktop> what is default root password for ovirt-appliance ? and for 192.168.50.2/ovirt/login/login i try all combination with ovirt, ovirtadmin, admin From hbrock at redhat.com Wed Dec 3 12:25:55 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Wed, 3 Dec 2008 07:25:55 -0500 Subject: [Ovirt-devel] what is default root password for ovirt-appliance ? In-Reply-To: <1228306792.8446.1.camel@dima-desktop> References: <1228306792.8446.1.camel@dima-desktop> Message-ID: <20081203122554.GM7558@redhat.com> On Wed, Dec 03, 2008 at 03:19:52PM +0300, ??????? ??????? wrote: > what is default root password for ovirt-appliance ? > and for 192.168.50.2/ovirt/login/login > i try all combination with ovirt, ovirtadmin, admin > ovirtadmin/admin should get you in if you're using the appliance. If it doesn't, something probably failed when creating the ovirtadmin user; check your install logs. --Hugh From jim at meyering.net Wed Dec 3 12:45:34 2008 From: jim at meyering.net (Jim Meyering) Date: Wed, 03 Dec 2008 13:45:34 +0100 Subject: [Ovirt-devel] [PATCH node-image] edit-livecd: add -o OUTPUT.iso option, required Message-ID: <878wqxbf69.fsf@rho.meyering.net> The new -o OUTPUT.iso option is now required. Allow the '-p CODE' option to specify bourne shell code, not just a file/script. This permits a common idiom: to avoid writing a separate shell script for a simple task, and instead include a quoted multi-line snippet in the invoking script, e.g., edit-livecd ...other-options... -p ' d=etc/foo mkdir -p $d && touch $d/file ' Also, in the boot params substitution, - use @ rather than / in the sed - warn if the selected string contains @ Update -h (help) output, and add examples. Evaluate $CODE in a subshell (safer and doesn't rely on pushd,popd). Guard against uninitialized ID_FS_LABEL. Don't use "function" keyword. Fail if there are any extra command-line arguments. Ensure that $PWD and $CD are double-eval safe (else fail), so that we don't have to quote them everywhere. Ensure that a $CODE (renamed from $PROG) definition doesn't leak in from the environment. --- edit-livecd | 117 ++++++++++++++++++++++++++++++++++++++--------------------- 1 files changed, 75 insertions(+), 42 deletions(-) diff --git a/edit-livecd b/edit-livecd index ce9e65b..6d6498a 100755 --- a/edit-livecd +++ b/edit-livecd @@ -34,38 +34,49 @@ usage() { Usage: $ME -i LiveCD.iso [-b bootparams] [-p program] -b BOOTPARAMS optional parameters appended to the kernel command line -i LIVECD.iso LiveCD ISO to edit (default: $NODEIMG_DEFAULT) - -p PROGRAM Arbitrary program/script that is run inside of the livecd root - filesystem. This script is not run in a chroot environment so - it can access the host filesystem. The program should be executable - If program is omitted the script will pause and allow the user in - another terminal to edit the filesystem manually. After enter is - pushed the script will re-package up the ISO. + -o OUTPUT.iso specify the output file (required) + -p CODE Arbitrary CODE that is eval'd while 'cd'd into the root of + the livecd root filesystem. Note; the code is not run in + a chroot environment, so it can access the host filesystem. + If this option is omitted, this program pauses and allows + the user (in another terminal) to modify the filesystem + manually. Type when done, and the script + re-packages the ISO. -h display this help and exit +EXAMPLES + Example Script: #!/bin/sh touch etc/sysconfig/foo + Save as foo and make executable: + chmod a+x foo + Run this to create a file /etc/sysconfig/foo in the livecd filesystem + (note the use of "\$PWD/foo", not "./foo", since it will be run from a + different directory): + + $ME -i input.iso -o /tmp/result.iso -p "\$PWD/foo" + + or, equivalently, but without a separate script: + + $ME -i input.iso -o /tmp/result.iso -p 'touch etc/sysconfig/foo' - This will create a file /etc/sysconfig/foo in the livecd filesystem. EOF } -# FIXME: instead of requiring a PROGRAM, allow arbitrary shell code, -# so we can invoke $0 -p 'touch etc/sysconfig/foo' ... -# This means that if you *do* have a program in the current directory -# running "$0 -p ./my-script" won't work, since it'll be run with -# a different working dir. However, *this* will: -# $0 -p "$PWD/my-script" - # exit after any error: set -e +CODE= +OUTPUT_FILE= + err=0 help=0 -while getopts :b:i:p:h c; do +while getopts :b:hi:o:p: c; do case $c in i) CD=$OPTARG;; b) PARAMS=$OPTARG;; - p) PROG=$OPTARG;; + o) OUTPUT_FILE=$OPTARG;; + p) CODE=$OPTARG;; h) help=1;; '?') err=1; warn "invalid option: \`-$OPTARG'";; :) err=1; warn "missing argument to \`-$OPTARG' option";; @@ -75,39 +86,59 @@ done test $err = 1 && { try_h; exit 1; } test $help = 1 && { usage; exit 0; } +# Require "-o OUTPUT_FILE" +test -z "$OUTPUT_FILE" \ + && { warn "no output file specified; use -o FILE.iso"; try_h; exit 1; } + +# Fail if there are any extra command-line arguments. +if test $OPTIND -le $#; then + bad_arg=$(eval "echo \$$OPTIND") + warn "extra argument '$bad_arg'"; try_h; exit 1 +fi + # first, check to see we are root if [ $( id -u ) -ne 0 ]; then die "Must run as root" fi -# FIXME: don't use which: with bash, it's a separate program -# FIXME: When failing due to a missing required program, tell the user why. -which mkisofs mksquashfs sed > /dev/null 2>&1 +# Check for some prerequisites. +# "type" prints "PROG not found" if it's not in $PATH. +type mkisofs +type mksquashfs +type sed + +sane_name() +{ + case $1 in + *[^a-zA-Z0-9._,+:/@%=-]*) false;; + *) true;; + esac +} + +# Fail if names we'll use contain white space or shell meta-characters +sane_name "$PWD" || die "invalid working directory name: $PWD" +sane_name "$CD" || die "invalid ISO name: $CD" WDIR=`mktemp -d $PWD/livecd.XXXXXXXXXX` -# FIXME: fail if $WDIR contains white space or shell meta-characters -# FIXME: do the same for $CD. - -ISO="${CD##*/}" -ISO="${ISO%.iso}-custom.iso" -function addExit() { +addExit() { EXIT="$@ ; $EXIT" trap "$EXIT" EXIT HUP TERM INT QUIT } -function mnt() { +mnt() { local margs="$1" ; shift local mp="$WDIR/$1" for D in "$@" ; do mkdir -v -p "$WDIR/$D" done - mount -v $margs "$mp" + eval mount -v $margs "$mp" addExit "df | grep $mp > /dev/null 2>&1 && umount -v $mp" } addExit "rm -rf $WDIR" +ID_FS_LABEL= # initialize, in case vol_id fails eval "$(/lib/udev/vol_id $CD)" LABEL=$ID_FS_LABEL @@ -120,21 +151,21 @@ mnt "-t squashfs $WDIR/cd/LiveOS/squashfs.img -o ro,loop" sq # create writable copy of the new filesystem for the CD cp -a $WDIR/cd $WDIR/cd-w -# create writable copy of the filesystem for the new compressed squashfs filesystem +# create writable copy of the filesystem for the new compressed +# squashfs filesystem cp -a $WDIR/sq $WDIR/sq-w # mount ext3 filesystem mnt "-t auto $WDIR/sq-w/LiveOS/ext3fs.img -o rw,loop" ex echo ">>> Updating CD content" -if [ -n "$PROG" ]; then - cp -av $PROG $WDIR/ex - pushd $WDIR/ex - set +e - ./$(basename $PROG) - set -e - popd - rm -f $WDIR/ex/$PROG +if [ -n "$CODE" ]; then + ( + cd $WDIR/ex + set +e + eval "$CODE" + set -e + ) else echo "***" echo "*** Pausing to allow manual changes. Press any key to continue." @@ -147,7 +178,7 @@ fi while :; do echo ">>> Unmounting ext3fs" umount $WDIR/ex && break - echo ">>> Unmounting ext3fs failed" + echo ">>> Unmounting the working file system copy failed" echo "***" echo "*** Did you forget to 'cd' out of $WDIR/ex?" echo "***" @@ -160,13 +191,15 @@ echo ">>> Compressing filesystem" mksquashfs $WDIR/sq-w/ $WDIR/cd-w/LiveOS/squashfs.img -noappend echo ">>> Recomputing MD5 sums" -( cd $WDIR/cd-w && find . -type f -not -name md5sum.txt -not -path '*/isolinux/*' -print0 | xargs -0 -- md5sum > md5sum.txt ) +( cd $WDIR/cd-w && find . -type f -not -name md5sum.txt \ + -not -path '*/isolinux/*' -print0 | xargs -0 -- md5sum > md5sum.txt ) if [ -n "$PARAMS" ]; then - # FIXME: make the script fail -- or maybe try to - # find a usable sed delimiter if $PARAMS contains a slash + case $PARAMS in + *@*) warn "PARAMS contains the @ sed delimiter, be sure it's escaped";; + esac echo ">>> Appending boot parameters" - sed -i 's/^ append .*$/& '"$PARAMS/" "$WDIR/cd-w/isolinux/isolinux.cfg" + sed -i 's@^ append .*$@& '"$PARAMS@" "$WDIR/cd-w/isolinux/isolinux.cfg" fi echo ">>> Creating ISO image $ISO" @@ -176,7 +209,7 @@ mkisofs \ -b isolinux/isolinux.bin \ -c isolinux/boot.cat \ -no-emul-boot -boot-load-size 4 -boot-info-table \ - -o "$ISO" \ + -o "$OUTPUT_FILE" \ $WDIR/cd-w # The trap ... callbacks will unmount everything. -- 1.6.1.rc1.279.g45d11 From d.vasilets at peterhost.ru Wed Dec 3 12:57:24 2008 From: d.vasilets at peterhost.ru (=?koi8-r?Q?=F7=C1=D3=C9=CC=C5=C3_?= =?koi8-r?Q?=E4=CD=C9=D4=D2=C9=CA?=) Date: Wed, 03 Dec 2008 15:57:24 +0300 Subject: [Ovirt-devel] what is default root password for ovirt-appliance ? In-Reply-To: <20081203122554.GM7558@redhat.com> References: <1228306792.8446.1.camel@dima-desktop> <20081203122554.GM7558@redhat.com> Message-ID: <1228309044.8446.7.camel@dima-desktop> Please write root default password I don't want change it ,using singlemode hash from /etc/shadow is Xa8QeYfWrtscM During first boot appear error with postgresql,ldap and kerberos ? ???, 03/12/2008 ? 07:25 -0500, Hugh O. Brock ?????: > On Wed, Dec 03, 2008 at 03:19:52PM +0300, ??????? ??????? wrote: > > what is default root password for ovirt-appliance ? > > and for 192.168.50.2/ovirt/login/login > > i try all combination with ovirt, ovirtadmin, admin > > > ovirtadmin/admin should get you in if you're using the appliance. If > it doesn't, something probably failed when creating the ovirtadmin > user; check your install logs. > > --Hugh > From dpierce at redhat.com Wed Dec 3 13:04:07 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 3 Dec 2008 08:04:07 -0500 Subject: [Ovirt-devel] Re: [PATCH release] Add check for minimum version of Fedora for building In-Reply-To: <4935F8C4.5040009@redhat.com> References: <1228252022-7047-1-git-send-email-pmyers@redhat.com> <4935A646.5010500@redhat.com> <20081203011612.GE8317@mcpierce-laptop.mcpierce.org> <4935F8C4.5040009@redhat.com> Message-ID: <20081203130406.GA4397@mcpierce-laptop.rdu.redhat.com> On Tue, Dec 02, 2008 at 10:11:00PM -0500, Perry Myers wrote: >> So once 0.96 is released we should also remove the conditionals in >> node-image and appliance Makefiles that check for F9 and include the >> *-newkeys repos. >> > > Yes, we should actually do this in next at the same time that this patch > is pushed. Okay, I'll take care of that now. -- 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 Wed Dec 3 13:05:49 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 3 Dec 2008 08:05:49 -0500 Subject: [Ovirt-devel] How to login to the URL: http://192.168.50.2/cobbler/web/?mode=system_list In-Reply-To: <49364613.1010404@redhat.com> References: <1228252022-7047-1-git-send-email-pmyers@redhat.com> <4935A646.5010500@redhat.com> <20081203011612.GE8317@mcpierce-laptop.mcpierce.org> <4935F8C4.5040009@redhat.com> <49364613.1010404@redhat.com> Message-ID: <20081203130549.GB4397@mcpierce-laptop.rdu.redhat.com> On Wed, Dec 03, 2008 at 04:40:51PM +0800, Jia Dong wrote: > Hey guys, > I am testing for a bug,and need more detail information. > How to login to:http://192.168.50.2/cobbler/web/?mode=system_list ? I > guess I must install something to support this.Cobbler?Or git the whole > project?So turn to you guys for some detailed information. Is the default admin name and password not cobbler/cobbler? -- 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 d.vasilets at peterhost.ru Wed Dec 3 13:09:06 2008 From: d.vasilets at peterhost.ru (=?koi8-r?Q?=F7=C1=D3=C9=CC=C5=C3_?= =?koi8-r?Q?=E4=CD=C9=D4=D2=C9=CA?=) Date: Wed, 03 Dec 2008 16:09:06 +0300 Subject: [Ovirt-devel] How to login to the URL: http://192.168.50.2/cobbler/web/?mode=system_list In-Reply-To: <20081203130549.GB4397@mcpierce-laptop.rdu.redhat.com> References: <1228252022-7047-1-git-send-email-pmyers@redhat.com> <4935A646.5010500@redhat.com> <20081203011612.GE8317@mcpierce-laptop.mcpierce.org> <4935F8C4.5040009@redhat.com> <49364613.1010404@redhat.com> <20081203130549.GB4397@mcpierce-laptop.rdu.redhat.com> Message-ID: <1228309746.8446.9.camel@dima-desktop> this is manual how to configure cobbler webui https://fedorahosted.org/cobbler/wiki/CobblerWebInterface ? ???, 03/12/2008 ? 08:05 -0500, Darryl L. Pierce ?????: > On Wed, Dec 03, 2008 at 04:40:51PM +0800, Jia Dong wrote: > > Hey guys, > > I am testing for a bug,and need more detail information. > > How to login to:http://192.168.50.2/cobbler/web/?mode=system_list ? I > > guess I must install something to support this.Cobbler?Or git the whole > > project?So turn to you guys for some detailed information. > > Is the default admin name and password not cobbler/cobbler? > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel From danken at redhat.com Wed Dec 3 13:52:05 2008 From: danken at redhat.com (Dan Kenigsberg) Date: Wed, 3 Dec 2008 15:52:05 +0200 Subject: [Ovirt-devel] [PATCH node-image] edit-livecd: Retry upon failed umount. In-Reply-To: <873ah6ec5o.fsf@rho.meyering.net> References: <873ah6ec5o.fsf@rho.meyering.net> Message-ID: <20081203135204.GA12550@redhat.com> On Tue, Dec 02, 2008 at 06:10:11PM +0100, Jim Meyering wrote: > > This is useful when you manually edit an image and forget to "cd" > out of the working directory. Without this, the script can't > clean up, and it's a pain to do manually. > I'm not sure its related, but would you tell what's the painful manual way to clean these /dev/loop1: [fd00]:6194759 (/tmp/node-image-tmp/imgcreate-XjH6K-/tmp-L816gf/ext3fs.img) I'm left with after an interrupted make .iso ? Dan From pmyers at redhat.com Wed Dec 3 13:52:07 2008 From: pmyers at redhat.com (Perry Myers) Date: Wed, 03 Dec 2008 08:52:07 -0500 Subject: [Ovirt-devel] what is default root password for ovirt-appliance ? In-Reply-To: <1228309044.8446.7.camel@dima-desktop> References: <1228306792.8446.1.camel@dima-desktop> <20081203122554.GM7558@redhat.com> <1228309044.8446.7.camel@dima-desktop> Message-ID: <49368F07.9010103@redhat.com> ?? wrote: > Please write root default password > I don't want change it ,using singlemode > hash from /etc/shadow is Xa8QeYfWrtscM > During first boot appear error with postgresql,ldap and kerberos The root password for the appliance and nodes are: root/ovirt Perry From jim at meyering.net Wed Dec 3 13:57:52 2008 From: jim at meyering.net (Jim Meyering) Date: Wed, 03 Dec 2008 14:57:52 +0100 Subject: [Ovirt-devel] [PATCH node-image] edit-livecd: Retry upon failed umount. In-Reply-To: <20081203135204.GA12550@redhat.com> (Dan Kenigsberg's message of "Wed, 3 Dec 2008 15:52:05 +0200") References: <873ah6ec5o.fsf@rho.meyering.net> <20081203135204.GA12550@redhat.com> Message-ID: <87k5ah9x9b.fsf@rho.meyering.net> Dan Kenigsberg wrote: > On Tue, Dec 02, 2008 at 06:10:11PM +0100, Jim Meyering wrote: >> >> This is useful when you manually edit an image and forget to "cd" >> out of the working directory. Without this, the script can't >> clean up, and it's a pain to do manually. >> > > I'm not sure its related, but would you tell what's the painful manual > way to clean these > > /dev/loop1: [fd00]:6194759 (/tmp/node-image-tmp/imgcreate-XjH6K-/tmp-L816gf/ext3fs.img) > > I'm left with after an interrupted make .iso ? There are usually three of those listed at the bottom of /proc/mounts. You have to umount them starting with the last one and working "up", e.g., umount /dev/loop3 umount /dev/loop2 umount /dev/loop1 From dpierce at redhat.com Wed Dec 3 14:02:30 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 3 Dec 2008 09:02:30 -0500 Subject: [Ovirt-devel] [PATCH release] Add rubygem-rails to the Requires list. Specifically version 2.1 or Message-ID: <1228312950-4964-1-git-send-email-dpierce@redhat.com> Signed-off-by: Darryl L. Pierce --- ovirt-release.spec.in | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/ovirt-release.spec.in b/ovirt-release.spec.in index a4b579f..1839c85 100644 --- a/ovirt-release.spec.in +++ b/ovirt-release.spec.in @@ -33,6 +33,7 @@ Requires: wget Requires: publican-ovirt Requires: python-virtinst >= 0.400 Requires: hal-devel selinux-policy-devel hardlink +Requires: rubygem-rails >= 2.1 %description -n ovirt-build Developer makefile and scripts to help automate the building of -- 1.6.0.4 From pmyers at redhat.com Wed Dec 3 14:02:46 2008 From: pmyers at redhat.com (Perry Myers) Date: Wed, 03 Dec 2008 09:02:46 -0500 Subject: [Ovirt-devel] [PATCH node-image] edit-livecd: add -o OUTPUT.iso option, required In-Reply-To: <878wqxbf69.fsf@rho.meyering.net> References: <878wqxbf69.fsf@rho.meyering.net> Message-ID: <49369186.4080803@redhat.com> Jim Meyering wrote: > The new -o OUTPUT.iso option is now required. > > Allow the '-p CODE' option to specify bourne shell code, not just > a file/script. This permits a common idiom: to avoid writing a > separate shell script for a simple task, and instead include a > quoted multi-line snippet in the invoking script, e.g., Question... Can you still pass a non bash script to -p like a python or ruby script? The reason why I left the script option as an 'arbitrary executable' instead of specifying bash was that I thought it would be useful for more complex operations for someone to use python instead of bash. Perry From jim at meyering.net Wed Dec 3 14:20:45 2008 From: jim at meyering.net (Jim Meyering) Date: Wed, 03 Dec 2008 15:20:45 +0100 Subject: [Ovirt-devel] [PATCH node-image] edit-livecd: add -o OUTPUT.iso option, required In-Reply-To: <49369186.4080803@redhat.com> (Perry Myers's message of "Wed, 03 Dec 2008 09:02:46 -0500") References: <878wqxbf69.fsf@rho.meyering.net> <49369186.4080803@redhat.com> Message-ID: <87ej0p9w76.fsf@rho.meyering.net> Perry Myers wrote: > Jim Meyering wrote: >> The new -o OUTPUT.iso option is now required. >> >> Allow the '-p CODE' option to specify bourne shell code, not just >> a file/script. This permits a common idiom: to avoid writing a >> separate shell script for a simple task, and instead include a >> quoted multi-line snippet in the invoking script, e.g., > > Question... Can you still pass a non bash script to -p like a python > or ruby script? The reason why I left the script option as an > arbitrary executable' instead of specifying bash was that I thought it > would be useful for more complex operations for someone to use python > instead of bash. Sure. "CODE" is eval'd as if by "bash -c "CODE", so a python or ruby script name would work fine, too. From danken at redhat.com Wed Dec 3 14:23:44 2008 From: danken at redhat.com (Dan Kenigsberg) Date: Wed, 3 Dec 2008 16:23:44 +0200 Subject: [Ovirt-devel] [PATCH node-image] edit-livecd: Retry upon failed umount. In-Reply-To: <87k5ah9x9b.fsf@rho.meyering.net> References: <873ah6ec5o.fsf@rho.meyering.net> <20081203135204.GA12550@redhat.com> <87k5ah9x9b.fsf@rho.meyering.net> Message-ID: <20081203142344.GA13507@redhat.com> On Wed, Dec 03, 2008 at 02:57:52PM +0100, Jim Meyering wrote: > Dan Kenigsberg wrote: > > > On Tue, Dec 02, 2008 at 06:10:11PM +0100, Jim Meyering wrote: > >> > >> This is useful when you manually edit an image and forget to "cd" > >> out of the working directory. Without this, the script can't > >> clean up, and it's a pain to do manually. > >> > > > > I'm not sure its related, but would you tell what's the painful manual > > way to clean these > > > > /dev/loop1: [fd00]:6194759 (/tmp/node-image-tmp/imgcreate-XjH6K-/tmp-L816gf/ext3fs.img) > > > > I'm left with after an interrupted make .iso ? > > There are usually three of those listed at the bottom of /proc/mounts. > You have to umount them starting with the last one and working "up", e.g., > > umount /dev/loop3 > umount /dev/loop2 > umount /dev/loop1 This does not sound painful. Here, umounting any of them results in $ sudo umount /dev/loop0 umount: /var/tmp/ovirt-cache/node-image-tmp/imgcreate-OmnXf7/install_root: device is busy umount: /var/tmp/ovirt-cache/node-image-tmp/imgcreate-OmnXf7/install_root: device is busy What am I missing? Dan. From pmyers at redhat.com Wed Dec 3 14:25:21 2008 From: pmyers at redhat.com (Perry Myers) Date: Wed, 03 Dec 2008 09:25:21 -0500 Subject: [Ovirt-devel] [PATCH node-image] edit-livecd: Retry upon failed umount. In-Reply-To: <20081203142344.GA13507@redhat.com> References: <873ah6ec5o.fsf@rho.meyering.net> <20081203135204.GA12550@redhat.com> <87k5ah9x9b.fsf@rho.meyering.net> <20081203142344.GA13507@redhat.com> Message-ID: <493696D1.10509@redhat.com> Dan Kenigsberg wrote: > On Wed, Dec 03, 2008 at 02:57:52PM +0100, Jim Meyering wrote: >> Dan Kenigsberg wrote: >> >>> On Tue, Dec 02, 2008 at 06:10:11PM +0100, Jim Meyering wrote: >>>> This is useful when you manually edit an image and forget to "cd" >>>> out of the working directory. Without this, the script can't >>>> clean up, and it's a pain to do manually. >>>> >>> I'm not sure its related, but would you tell what's the painful manual >>> way to clean these >>> >>> /dev/loop1: [fd00]:6194759 (/tmp/node-image-tmp/imgcreate-XjH6K-/tmp-L816gf/ext3fs.img) >>> >>> I'm left with after an interrupted make .iso ? >> There are usually three of those listed at the bottom of /proc/mounts. >> You have to umount them starting with the last one and working "up", e.g., >> >> umount /dev/loop3 >> umount /dev/loop2 >> umount /dev/loop1 > > This does not sound painful. Here, umounting any of them results in > > $ sudo umount /dev/loop0 > umount: /var/tmp/ovirt-cache/node-image-tmp/imgcreate-OmnXf7/install_root: device is busy > umount: /var/tmp/ovirt-cache/node-image-tmp/imgcreate-OmnXf7/install_root: device is busy > > What am I missing? The order you unmount them matters since they are nested mount points. So you have to start with the lowest level directory (i.e. loop3) and work upwards. Do a df -a to make sure there are no other mounts inside of the directory structure. Perry From jim at meyering.net Wed Dec 3 14:28:27 2008 From: jim at meyering.net (Jim Meyering) Date: Wed, 03 Dec 2008 15:28:27 +0100 Subject: [Ovirt-devel] [PATCH node-image] edit-livecd: Retry upon failed umount. In-Reply-To: <493696D1.10509@redhat.com> (Perry Myers's message of "Wed, 03 Dec 2008 09:25:21 -0500") References: <873ah6ec5o.fsf@rho.meyering.net> <20081203135204.GA12550@redhat.com> <87k5ah9x9b.fsf@rho.meyering.net> <20081203142344.GA13507@redhat.com> <493696D1.10509@redhat.com> Message-ID: <878wqx9vuc.fsf@rho.meyering.net> Perry Myers wrote: > Dan Kenigsberg wrote: >> On Wed, Dec 03, 2008 at 02:57:52PM +0100, Jim Meyering wrote: >>> Dan Kenigsberg wrote: >>> >>>> On Tue, Dec 02, 2008 at 06:10:11PM +0100, Jim Meyering wrote: >>>>> This is useful when you manually edit an image and forget to "cd" >>>>> out of the working directory. Without this, the script can't >>>>> clean up, and it's a pain to do manually. >>>>> >>>> I'm not sure its related, but would you tell what's the painful manual >>>> way to clean these >>>> >>>> /dev/loop1: [fd00]:6194759 (/tmp/node-image-tmp/imgcreate-XjH6K-/tmp-L816gf/ext3fs.img) >>>> >>>> I'm left with after an interrupted make .iso ? >>> There are usually three of those listed at the bottom of /proc/mounts. >>> You have to umount them starting with the last one and working "up", e.g., >>> >>> umount /dev/loop3 >>> umount /dev/loop2 >>> umount /dev/loop1 >> >> This does not sound painful. Here, umounting any of them results in >> >> $ sudo umount /dev/loop0 >> umount: /var/tmp/ovirt-cache/node-image-tmp/imgcreate-OmnXf7/install_root: device is busy >> umount: /var/tmp/ovirt-cache/node-image-tmp/imgcreate-OmnXf7/install_root: device is busy >> >> What am I missing? > > The order you unmount them matters since they are nested mount points. > So you have to start with the lowest level directory (i.e. loop3) and > work upwards. > > Do a df -a to make sure there are no other mounts inside of the > directory structure. Also, be sure you're not cd'd into any of those directories. And lsof can tell if something is holding a FD open. From danken at redhat.com Wed Dec 3 14:33:54 2008 From: danken at redhat.com (Dan Kenigsberg) Date: Wed, 3 Dec 2008 16:33:54 +0200 Subject: [Ovirt-devel] [PATCH node-image] edit-livecd: Retry upon failed umount. In-Reply-To: <493696D1.10509@redhat.com> References: <873ah6ec5o.fsf@rho.meyering.net> <20081203135204.GA12550@redhat.com> <87k5ah9x9b.fsf@rho.meyering.net> <20081203142344.GA13507@redhat.com> <493696D1.10509@redhat.com> Message-ID: <20081203143352.GB13507@redhat.com> On Wed, Dec 03, 2008 at 09:25:21AM -0500, Perry Myers wrote: > Dan Kenigsberg wrote: >> On Wed, Dec 03, 2008 at 02:57:52PM +0100, Jim Meyering wrote: >>> Dan Kenigsberg wrote: >>> >>>> On Tue, Dec 02, 2008 at 06:10:11PM +0100, Jim Meyering wrote: >>>>> This is useful when you manually edit an image and forget to "cd" >>>>> out of the working directory. Without this, the script can't >>>>> clean up, and it's a pain to do manually. >>>>> >>>> I'm not sure its related, but would you tell what's the painful manual >>>> way to clean these >>>> >>>> /dev/loop1: [fd00]:6194759 (/tmp/node-image-tmp/imgcreate-XjH6K-/tmp-L816gf/ext3fs.img) >>>> >>>> I'm left with after an interrupted make .iso ? >>> There are usually three of those listed at the bottom of /proc/mounts. >>> You have to umount them starting with the last one and working "up", e.g., >>> >>> umount /dev/loop3 >>> umount /dev/loop2 >>> umount /dev/loop1 >> >> This does not sound painful. Here, umounting any of them results in >> >> $ sudo umount /dev/loop0 >> umount: /var/tmp/ovirt-cache/node-image-tmp/imgcreate-OmnXf7/install_root: device is busy >> umount: /var/tmp/ovirt-cache/node-image-tmp/imgcreate-OmnXf7/install_root: device is busy >> >> What am I missing? > > The order you unmount them matters since they are nested mount points. > So you have to start with the lowest level directory (i.e. loop3) and > work upwards. > > Do a df -a to make sure there are no other mounts inside of the directory > structure. so *that* was the missing bit. several umount /var/tmp/ovirt-cache/node-image-tmp/*/install_root/*/*/* &co did the trick. Thanks. From d.vasilets at peterhost.ru Wed Dec 3 15:21:44 2008 From: d.vasilets at peterhost.ru (=?koi8-r?Q?=F7=C1=D3=C9=CC=C5=C3_?= =?koi8-r?Q?=E4=CD=C9=D4=D2=C9=CA?=) Date: Wed, 03 Dec 2008 18:21:44 +0300 Subject: [Ovirt-devel] ovirt see only 1 node. how to add other servers ? Message-ID: <1228317705.11195.2.camel@dima-desktop> ovirt see only 1 node. how to add other servers ? From pmyers at redhat.com Wed Dec 3 15:27:05 2008 From: pmyers at redhat.com (Perry Myers) Date: Wed, 03 Dec 2008 10:27:05 -0500 Subject: [Ovirt-devel] ovirt see only 1 node. how to add other servers ? In-Reply-To: <1228317705.11195.2.camel@dima-desktop> References: <1228317705.11195.2.camel@dima-desktop> Message-ID: <4936A549.5000203@redhat.com> ?? wrote: > ovirt see only 1 node. how to add other servers ? You just need to boot additional physical machines connected to the oVirt network. You need to have run create-ovirt-appliance with the -e parameter to indicate that you want to bridge the ovirt-appliance to an external network. (i.e. -e eth1) Then PXE boot some machines on that network and they'll boot the Node from the appliance and register themselves with the oVirt Server. Perry From dpierce at redhat.com Wed Dec 3 16:13:55 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 3 Dec 2008 11:13:55 -0500 Subject: [Ovirt-devel] [PATCH appliance] Removed build conditions to support the F9 newkey repos. Message-ID: <1228320835-8943-1-git-send-email-dpierce@redhat.com> NOTE: This patch depends on the complimentary patch for node-image. Since, with 0.96, F9 is not longer a target, we don't need this build conditional. Added repos.ks to the list of .PHONY targets. Signed-off-by: Darryl L. Pierce --- Makefile.am | 8 ++------ 1 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Makefile.am b/Makefile.am index 6153e62..52fe026 100644 --- a/Makefile.am +++ b/Makefile.am @@ -72,11 +72,7 @@ repos.ks: FEDORA_REPO=f$(FEDORA) ;\ FEDORA_REPO_LOC="$(if $(FEDORA_URL),--baseurl=$(FEDORA_URL)/releases/$(FEDORA)/Everything/$(ARCH)/os,--mirrorlist=$(FEDORA_MIRROR)?repo=fedora-$(FEDORA)&arch=$(ARCH))" ;\ OVIRT_DISTRO=$(FEDORA) ;\ - if [ "$FEDORA_REPO" == "f9" ]; then \ - UPDATE_REPO_LINE="repo --name=$${FEDORA_REPO}-updates-newkey $(if $(FEDORA_URL),--baseurl=$(FEDORA_URL)/updates/$(FEDORA)/$(ARCH).newkey,--mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-f$(FEDORA).newkey&arch=$(ARCH))" ;\ - else \ - UPDATE_REPO_LINE="repo --name=$${FEDORA_REPO}-updates $(if $(FEDORA_URL),--baseurl=$(FEDORA_URL)/updates/$(FEDORA)/$(ARCH),--mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-f$(FEDORA)&arch=$(ARCH))" ;\ - fi ; \ + UPDATE_REPO_LINE="repo --name=$${FEDORA_REPO}-updates $(if $(FEDORA_URL),--baseurl=$(FEDORA_URL)/updates/$(FEDORA)/$(ARCH),--mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-f$(FEDORA)&arch=$(ARCH))" ;\ fi ;\ echo "repo --name=$${FEDORA_REPO} $${FEDORA_REPO_LOC}" > $@ ;\ echo "repo --name=ovirt-org --baseurl=$(OVIRT_URL)/$${OVIRT_DISTRO}/$(ARCH)" >> $@ ;\ @@ -150,4 +146,4 @@ publish: rpms rsync -aq $(shell rpm --eval '%{_srcrpmdir}')/ $(OVIRT_CACHE_DIR)/ovirt/src/ createrepo $(OVIRT_CACHE_DIR)/ovirt -.PHONY: rpms publish $(NVR).$(PKG_FMT).$(SUM) $(NVR).$(PKG_FMT) keys +.PHONY: rpms publish $(NVR).$(PKG_FMT).$(SUM) $(NVR).$(PKG_FMT) keys repos.ks -- 1.6.0.4 From dpierce at redhat.com Wed Dec 3 16:14:09 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 3 Dec 2008 11:14:09 -0500 Subject: [Ovirt-devel] [PATCH node-image] Removed updates conditions for F9. Message-ID: <1228320849-8980-1-git-send-email-dpierce@redhat.com> Since, as of 0.96, F9 support is legacy, we'll no longer need this conditional check when building. Also added repos.ks to the list of .PHONY targets. Signed-off-by: Darryl L. Pierce --- Makefile.am | 8 ++------ 1 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Makefile.am b/Makefile.am index 02fe136..cb084e6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -75,11 +75,7 @@ repos.ks: FEDORA_REPO=f$(FEDORA) ;\ FEDORA_REPO_LOC="$(if $(FEDORA_URL),--baseurl=$(FEDORA_URL)/releases/$(FEDORA)/Everything/${ARCH}/os,--mirrorlist=$(FEDORA_MIRROR)?repo=fedora-$(FEDORA)&arch=$(ARCH))" ;\ OVIRT_DISTRO=$(FEDORA) ;\ - if [ FEDORA_REPO == f9 ]; then \ - UPDATE_REPO_LINE="repo --name=$${FEDORA_REPO}-updates-newkey $(if $(FEDORA_URL),--baseurl=$(FEDORA_URL)/updates/$(FEDORA)/${ARCH}.newkey,--mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-f$(FEDORA).newkey&arch=$(ARCH))" ;\ - else \ - UPDATE_REPO_LINE="repo --name=$${FEDORA_REPO}-updates $(if $(FEDORA_URL),--baseurl=$(FEDORA_URL)/updates/$(FEDORA)/${ARCH},--mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-f$(FEDORA)&arch=$(ARCH))" ;\ - fi ;\ + UPDATE_REPO_LINE="repo --name=$${FEDORA_REPO}-updates $(if $(FEDORA_URL),--baseurl=$(FEDORA_URL)/updates/$(FEDORA)/${ARCH},--mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-f$(FEDORA)&arch=$(ARCH))" ;\ fi ;\ echo "repo --name=$${FEDORA_REPO} $${FEDORA_REPO_LOC}" > $@ ;\ echo "repo --name=ovirt-org --baseurl=$(OVIRT_URL)/$${OVIRT_DISTRO}/$(ARCH)" >> $@ ;\ @@ -139,4 +135,4 @@ publish: rpms createrepo $(OVIRT_CACHE_DIR)/ovirt .PHONY: rpms publish $(NVR).$(PKG_FMT).$(SUM) $(NVR).$(PKG_FMT) \ - $(PACKAGE).$(PKG_FMT) keys + $(PACKAGE).$(PKG_FMT) keys repos.ks -- 1.6.0.4 From jim at meyering.net Wed Dec 3 16:37:12 2008 From: jim at meyering.net (Jim Meyering) Date: Wed, 03 Dec 2008 17:37:12 +0100 Subject: [Ovirt-devel] [PATCH node-image] common-post.ks: factor, fix quoting, handle case of no policy files Message-ID: <87r64p8bbb.fsf@rho.meyering.net> Mainly clean-up, this also avoids problems with unusual $TMPDIR, no *.pp or *.pp.bz2 files, and with a base policy file but no others. Minor changes: prefer bzip2 over bunzip, remove unnecessary use of xargs, remove a /usr/sbin prefix (PATH includes that at top). I'm testing it now... --- common-post.ks | 33 ++++++++++++++++++++++----------- 1 files changed, 22 insertions(+), 11 deletions(-) diff --git a/common-post.ks b/common-post.ks index 1cb5922..f785efd 100644 --- a/common-post.ks +++ b/common-post.ks @@ -14,21 +14,33 @@ lokkit -v --selinuxtype=minimum tmpdir=$(mktemp -d) for semodule in $SEMODULES; do - if [ -f /usr/share/selinux/minimum/$semodule.pp.bz2 ]; then - mv /usr/share/selinux/minimum/$semodule.pp.bz2 $tmpdir - bunzip2 $tmpdir/$semodule.pp.bz2 - elif [ -f /usr/share/selinux/minimum/$semodule.pp ]; then - mv /usr/share/selinux/minimum/$semodule.pp $tmpdir + found=0 + pp_file=/usr/share/selinux/minimum/$semodule.pp + if [ -f $pp_file.bz2 ]; then + bzip2 -dc $pp_file.bz2 > "$tmpdir/$semodule.pp" + rm $pp_file.bz2 + found=1 + elif [ -f $pp_file ]; then + mv $pp_file "$tmpdir" + found=1 fi + # Don't put "base.pp" on the list. + test $semodule = base \ + && continue + test $found=1 \ + && modules="$modules $semodule.pp" done -ls $tmpdir/*.pp | grep -Ev "base.pp|enableaudit.pp" \ - | xargs semodule -v -b $tmpdir/base.pp -i -semodule -v -B -rm -Rf $tmpdir +if test -n "$modules"; then + (cd "$tmpdir" \ + && test -f base.pp \ + && semodule -v -b base.pp -i $modules \ + && semodule -v -B ) +fi +rm -rf "$tmpdir" echo "Running ovirt-install-host stateless" -/usr/sbin/ovirt-install-node stateless +ovirt-install-node stateless echo "Creating shadow files" # because we aren't installing authconfig, we aren't setting up shadow @@ -66,4 +78,3 @@ cat > /etc/sysconfig/iptables << \EOF -A FORWARD -m physdev ! --physdev-is-bridged -j REJECT --reject-with icmp-host-prohibited COMMIT EOF - -- 1.6.1.rc1.279.g45d11 From jim at meyering.net Wed Dec 3 18:26:02 2008 From: jim at meyering.net (Jim Meyering) Date: Wed, 03 Dec 2008 19:26:02 +0100 Subject: [Ovirt-devel] [PATCH docs] remove doubled words: s/ the the / the / Message-ID: <874p1l869x.fsf@rho.meyering.net> --- It's not easy to "view" these changes in a normal-width terminal. (that's one good reason to keep line length < 80) To view changes like this, I find the "cdif" script very useful: http://freshmeat.net/projects/cdif/ I.e. pipe this patch through it, and the tiny "the"-omitting changes are highlighted in bold: cdif < THIS_FILE .../en-US/Managing-Storage-Pools.xml | 6 +++--- .../en-US/Managing-the-Hardware.xml | 6 +++--- .../en-US/Working-with-Storage.xml | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Using_the_oVirt_Admin_UI/en-US/Managing-Storage-Pools.xml b/Using_the_oVirt_Admin_UI/en-US/Managing-Storage-Pools.xml index 2bb7044..f7c483f 100644 --- a/Using_the_oVirt_Admin_UI/en-US/Managing-Storage-Pools.xml +++ b/Using_the_oVirt_Admin_UI/en-US/Managing-Storage-Pools.xml @@ -48,7 +48,7 @@ - To add an existing storage pool, click the the Import Existing Pools tab. + To add an existing storage pool, click the Import Existing Pools tab. The Import Existing Pools on the Add Storage dialog box displays the alias, Existing hardware pool, IP and Type of the available Storage Servers. @@ -62,7 +62,7 @@ - Select the the storage pools that you wish to add to the hardware pool. At least one storage pool must be selected for the Add Storage Pools button to be enabled. + Select the storage pools that you wish to add to the hardware pool. At least one storage pool must be selected for the Add Storage Pools button to be enabled. Click Add Storage Pools. The storage pool displays on the Storage Page of the hardware pool. @@ -348,4 +348,4 @@ - \ No newline at end of file + diff --git a/Using_the_oVirt_Admin_UI/en-US/Managing-the-Hardware.xml b/Using_the_oVirt_Admin_UI/en-US/Managing-the-Hardware.xml index 98ea08e..ab85975 100644 --- a/Using_the_oVirt_Admin_UI/en-US/Managing-the-Hardware.xml +++ b/Using_the_oVirt_Admin_UI/en-US/Managing-the-Hardware.xml @@ -63,7 +63,7 @@ The number of CPUs, amounts of used and available memory, storage and virtual resources appear in both a graphical and list form. Information on the history, performance and network traffic is also displayed. - To view information on the the physical host machines in this hardware resource pool, click Hosts on the menu bar. The Hosts page displays the list of hosts in the resource pool. + To view information on the physical host machines in this hardware resource pool, click Hosts on the menu bar. The Hosts page displays the list of hosts in the resource pool. @@ -570,7 +570,7 @@ - To add an existing storage pool, click the the Import Existing Pools tab. + To add an existing storage pool, click the Import Existing Pools tab. The Add Storage dialog box displays the alias, Existing hardware pool, IP and Type of the available Storage Servers. @@ -584,7 +584,7 @@ - Select the the storage pools that you wish to add to the hardware pool. At least one storage pool must be selected for the Add Storage Pools button to be enabled. + Select the storage pools that you wish to add to the hardware pool. At least one storage pool must be selected for the Add Storage Pools button to be enabled. Click Add Storage Pools. The storage pool displays on the Storage Page of the hardware pool. diff --git a/Using_the_oVirt_Admin_UI/en-US/Working-with-Storage.xml b/Using_the_oVirt_Admin_UI/en-US/Working-with-Storage.xml index a1b43fe..fcd3afb 100644 --- a/Using_the_oVirt_Admin_UI/en-US/Working-with-Storage.xml +++ b/Using_the_oVirt_Admin_UI/en-US/Working-with-Storage.xml @@ -66,7 +66,7 @@ The number of CPUs, amounts of used and available memory, storage and virtual resources appear in both a graphical and list form. Information on the history, performance and network traffic is also displayed. - To view information on the the physical host machines in this hardware resource pool, click Hosts on the menu bar. The Hosts page displays the list of hosts in the resource pool. + To view information on the physical host machines in this hardware resource pool, click Hosts on the menu bar. The Hosts page displays the list of hosts in the resource pool. @@ -571,7 +571,7 @@ - To add an existing storage pool, click the the Import Existing Pools tab. + To add an existing storage pool, click the Import Existing Pools tab. The Add Storage dialog box displays the alias, Existing hardware pool, IP and Type of the available Storage Servers. - Select the the storage pools that you wish to add to the hardware pool. At least one storage pool must be selected for the Add Storage Pools button to be enabled. + Select the storage pools that you wish to add to the hardware pool. At least one storage pool must be selected for the Add Storage Pools button to be enabled. Click Add Storage Pools. The storage pool displays on the Storage Page of the hardware pool. -- 1.6.0.4.1101.g642f8 From jim at meyering.net Wed Dec 3 18:29:03 2008 From: jim at meyering.net (Jim Meyering) Date: Wed, 03 Dec 2008 19:29:03 +0100 Subject: [Ovirt-devel] [PATCH appliance] Removed build conditions to support the F9 newkey repos. In-Reply-To: <1228320835-8943-1-git-send-email-dpierce@redhat.com> (Darryl L. Pierce's message of "Wed, 3 Dec 2008 11:13:55 -0500") References: <1228320835-8943-1-git-send-email-dpierce@redhat.com> Message-ID: <87vdu16rkg.fsf@rho.meyering.net> "Darryl L. Pierce" wrote: > NOTE: This patch depends on the complimentary patch for node-image. > > Since, with 0.96, F9 is not longer a target, we don't need this build > conditional. > > Added repos.ks to the list of .PHONY targets. Hi Darryl, I confirm that this gets me past a build failure due to unresolved dependency on rubygem(activesupport) on F10. That's because my repos.ks didn't mention f10. With this change, repos.ks can no longer get out of date, so ACK From jim at meyering.net Wed Dec 3 18:29:27 2008 From: jim at meyering.net (Jim Meyering) Date: Wed, 03 Dec 2008 19:29:27 +0100 Subject: [Ovirt-devel] [PATCH node-image] Removed updates conditions for F9. In-Reply-To: <1228320849-8980-1-git-send-email-dpierce@redhat.com> (Darryl L. Pierce's message of "Wed, 3 Dec 2008 11:14:09 -0500") References: <1228320849-8980-1-git-send-email-dpierce@redhat.com> Message-ID: <87skp56rjs.fsf@rho.meyering.net> "Darryl L. Pierce" wrote: > Since, as of 0.96, F9 support is legacy, we'll no longer need this > conditional check when building. > > Also added repos.ks to the list of .PHONY targets. > > Signed-off-by: Darryl L. Pierce > --- > Makefile.am | 8 ++------ Hi Darryl, This is just like the patch in appliance, so ACK From dpierce at redhat.com Wed Dec 3 19:36:16 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 3 Dec 2008 14:36:16 -0500 Subject: [Ovirt-devel] [PATCH node-image] Removed updates conditions for F9. In-Reply-To: <87skp56rjs.fsf@rho.meyering.net> References: <1228320849-8980-1-git-send-email-dpierce@redhat.com> <87skp56rjs.fsf@rho.meyering.net> Message-ID: <20081203193616.GB4960@mcpierce-laptop.mcpierce.org> On Wed, Dec 03, 2008 at 07:29:27PM +0100, Jim Meyering wrote: > "Darryl L. Pierce" wrote: > > Since, as of 0.96, F9 support is legacy, we'll no longer need this > > conditional check when building. > > > > Also added repos.ks to the list of .PHONY targets. > > > > Signed-off-by: Darryl L. Pierce > > --- > > Makefile.am | 8 ++------ > > Hi Darryl, > This is just like the patch in appliance, so > > ACK Pushed. Thanks. :) -- 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 Wed Dec 3 19:36:34 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 3 Dec 2008 14:36:34 -0500 Subject: [Ovirt-devel] [PATCH appliance] Removed build conditions to support the F9 newkey repos. In-Reply-To: <87vdu16rkg.fsf@rho.meyering.net> References: <1228320835-8943-1-git-send-email-dpierce@redhat.com> <87vdu16rkg.fsf@rho.meyering.net> Message-ID: <20081203193634.GC4960@mcpierce-laptop.mcpierce.org> On Wed, Dec 03, 2008 at 07:29:03PM +0100, Jim Meyering wrote: > "Darryl L. Pierce" wrote: > > > NOTE: This patch depends on the complimentary patch for node-image. > > > > Since, with 0.96, F9 is not longer a target, we don't need this build > > conditional. > > > > Added repos.ks to the list of .PHONY targets. > > Hi Darryl, > > I confirm that this gets me past a build failure due > to unresolved dependency on rubygem(activesupport) on F10. > > That's because my repos.ks didn't mention f10. > With this change, repos.ks can no longer get out of date, so > > ACK Pushed as well. Thanks again. :) -- 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 jim at meyering.net Wed Dec 3 22:06:31 2008 From: jim at meyering.net (Jim Meyering) Date: Wed, 03 Dec 2008 23:06:31 +0100 Subject: [Ovirt-devel] FYI, doc-build "errors" Message-ID: <87y6yw6hi0.fsf@rho.meyering.net> Doing a build this evening, I saw the following go by: END: test-en-US Wed Dec 3 19:01:03 CET 2008 START: html-en-US Wed Dec 3 19:01:03 CET 2008 Running Saxon: /usr/share/publican/xsl/html.xsl Recoverable error org.xml.sax.SAXParseException: Include operation failed, reverting to fall\ back. Resource error reading file as XML (href='Feedback.xml'). Reason: /h/m/r\ pmbuild/BUILD/ovirt-docs-0.96/Using_the_oVirt_Admin_UI/tmp/en-US/xml/Feedback.\ xml (No such file or directory) Failed to interpret image: Common_Content/images/title_logo.svg Failed to interpret image: Common_Content/images/title_logo.svg Failed to interpret image: Common_Content/images/title_logo.svg Failed to interpret image: Common_Content/images/title_logo.svg Writing About_the_Documentation_Suite.html for section(About_the_Documenta\ tion_Suite) Writing About_the_Audience.html for section(About_the_Audience) Writing pr01s04s02.html for section Writing pr01s04s03.html for section Writing pr01s04.html for section It didn't cause a build failure, and the first is "Recoverable", but it'd be nice to avoid them. Maybe it just means adding these two files? Using_the_oVirt_Admin_UI/tmp/en-US/xml/Feedback.xml Common_Content/images/title_logo.svg From jdong at redhat.com Thu Dec 4 05:26:30 2008 From: jdong at redhat.com (Jia Dong) Date: Thu, 04 Dec 2008 13:26:30 +0800 Subject: [Ovirt-devel] How to login to the URL: http://192.168.50.2/cobbler/web/?mode=system_list In-Reply-To: <20081203130549.GB4397@mcpierce-laptop.rdu.redhat.com> References: <1228252022-7047-1-git-send-email-pmyers@redhat.com> <4935A646.5010500@redhat.com> <20081203011612.GE8317@mcpierce-laptop.mcpierce.org> <4935F8C4.5040009@redhat.com> <49364613.1010404@redhat.com> <20081203130549.GB4397@mcpierce-laptop.rdu.redhat.com> Message-ID: <49376A06.2080002@redhat.com> Darryl L. Pierce wrote: > On Wed, Dec 03, 2008 at 04:40:51PM +0800, Jia Dong wrote: > >> Hey guys, >> I am testing for a bug,and need more detail information. >> How to login to:http://192.168.50.2/cobbler/web/?mode=system_list ? I >> guess I must install something to support this.Cobbler?Or git the whole >> project?So turn to you guys for some detailed information. >> > > Is the default admin name and password not cobbler/cobbler? > > Yup,it is ,Thanks. :) From jdong at redhat.com Thu Dec 4 05:50:06 2008 From: jdong at redhat.com (Jia Dong) Date: Thu, 04 Dec 2008 13:50:06 +0800 Subject: [Ovirt-devel] How to login to the URL: http://192.168.50.2/cobbler/web/?mode=system_list In-Reply-To: <20081203120422.GL7558@redhat.com> References: <1228252022-7047-1-git-send-email-pmyers@redhat.com> <4935A646.5010500@redhat.com> <20081203011612.GE8317@mcpierce-laptop.mcpierce.org> <4935F8C4.5040009@redhat.com> <49364613.1010404@redhat.com> <20081203120422.GL7558@redhat.com> Message-ID: <49376F8E.3040604@redhat.com> Hugh O. Brock wrote: > On Wed, Dec 03, 2008 at 04:40:51PM +0800, Jia Dong wrote: > >> Hey guys, >> I am testing for a bug,and need more detail information. >> How to login to:http://192.168.50.2/cobbler/web/?mode=system_list ? I >> guess I must install something to support this.Cobbler?Or git the whole >> project?So turn to you guys for some detailed information. >> Thanks, >> Nikki >> > > Hi Nikki. The cobbler web UI should be installed in the appliance by > default, but I can't remember what the default username/password is. I > suspect it's admin/admin. I'll try to find out for you. > > Take care, > --Hugh > Hey Hugh,I haven't tried admin/admin.And Darryl's suggestion of cobbler/cobbler works. :-) Thanks, Nikki From doron.fediuck at gmail.com Thu Dec 4 08:49:04 2008 From: doron.fediuck at gmail.com (Doron Fediuck) Date: Thu, 4 Dec 2008 10:49:04 +0200 Subject: [Ovirt-devel] Managed-node image boot issue Message-ID: <200812041049.04465.doron.fediuck@gmail.com> Hi ! A few days ago Alan identified a missing driver issue which caused us to get kernel panic during image boot. The missing driver was the hd's driver. My question is a conceptual one; Why does the boot fail due to local disc issues ? It is my impression that managed node may not include a local disk at all (and use the storage pool), which will lead to the same behavior- kernel panic on boot. If I misunderstand, please explain. Thanks, Doron. From apevec at gmail.com Thu Dec 4 10:29:34 2008 From: apevec at gmail.com (Alan Pevec) Date: Thu, 4 Dec 2008 11:29:34 +0100 Subject: [Ovirt-devel] Managed-node image boot issue In-Reply-To: <200812041049.04465.doron.fediuck@gmail.com> References: <200812041049.04465.doron.fediuck@gmail.com> Message-ID: <2be7262f0812040229h66300fdcte4803381488e2b44@mail.gmail.com> On Thu, Dec 4, 2008 at 9:49 AM, Doron Fediuck wrote: > Hi ! > A few days ago Alan identified a missing driver issue which > caused us to get kernel panic during image boot. The missing > driver was the hd's driver. you were booting from cd and it was missing pata_marvell to which CD drive was connected > My question is a conceptual one; > Why does the boot fail due to local disc issues ? > It is my impression that managed node may not include a local > disk at all (and use the storage pool), which will lead to > the same behavior- kernel panic on boot. yes, but you still need to mount rootfs (livecd iso in our case) which is on your boot media. You don't need additional drivers when PXE booting, b/c livecd iso is embedded into initrd and loop-mounted by init script. From d.vasilets at peterhost.ru Thu Dec 4 11:19:59 2008 From: d.vasilets at peterhost.ru (=?koi8-r?Q?=F7=C1=D3=C9=CC=C5=C3_?= =?koi8-r?Q?=E4=CD=C9=D4=D2=C9=CA?=) Date: Thu, 04 Dec 2008 14:19:59 +0300 Subject: [Ovirt-devel] ovirt see only 1 node. how to add other servers ? In-Reply-To: <4936A549.5000203@redhat.com> References: <1228317705.11195.2.camel@dima-desktop> <4936A549.5000203@redhat.com> Message-ID: <1228389599.7273.5.camel@dima-desktop> on node1 I "create-ovirt-appliance -e eth0" and "virsh start ovirt-appliance " on node2 I "ovirt-install-node stateful" I think i must create virtual network between real nodes on node1 and node2 i add eth0 to ovirtbr0 "brctl addif ovirtbr0 eth0", and set on both nodes ovirtbr0 adress 192.168.50.100/24 and 192.168.50.200/24 all nodes and virtual host "ovirt-appliance" is in same network (192.168.50.0/24), but only one node in list ? ???, 03/12/2008 ? 10:27 -0500, Perry Myers ?????: > ?? wrote: > > ovirt see only 1 node. how to add other servers ? > > You just need to boot additional physical machines connected to the oVirt > network. > > You need to have run create-ovirt-appliance with the -e parameter to > indicate that you want to bridge the ovirt-appliance to an external > network. (i.e. -e eth1) > > Then PXE boot some machines on that network and they'll boot the Node from > the appliance and register themselves with the oVirt Server. > > Perry > From dpierce at redhat.com Thu Dec 4 14:54:45 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Thu, 4 Dec 2008 09:54:45 -0500 Subject: [Ovirt-devel] [PATCH release] Removed the newkey repos which are needed only for F9. Message-ID: <1228402485-18018-1-git-send-email-dpierce@redhat.com> Signed-off-by: Darryl L. Pierce --- ovirt.mk | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ovirt.mk b/ovirt.mk index b0f7977..a06be30 100644 --- a/ovirt.mk +++ b/ovirt.mk @@ -99,17 +99,17 @@ tar-src: @( if [ -n "$(FEDORA_URL)" ]; then \ echo "repo --name=f$(F_REL) --baseurl=$(FEDORA_URL)/releases/$(F_REL)/Everything/\$$basearch/os" ; \ echo "repo --name=f$(F_REL)-updates --baseurl=$(FEDORA_URL)/updates/$(F_REL)/\$$basearch" ; \ - echo "repo --name=f$(F_REL)-updates-newkey --baseurl=$(FEDORA_URL)/updates/$(F_REL)/\$$basearch.newkey" ; \ + echo "repo --name=f$(F_REL)-updates --baseurl=$(FEDORA_URL)/updates/$(F_REL)/\$$basearch" ; \ echo "repo --name=f$(F_REL)-src --baseurl=$(FEDORA_URL)/releases/$(F_REL)/Everything/source/SRPMS" ; \ echo "repo --name=f$(F_REL)-updates-src --baseurl=$(FEDORA_URL)/updates/$(F_REL)/SRPMS" ; \ - echo "repo --name=f$(F_REL)-updates-src-newkey --baseurl=$(FEDORA_URL)/updates/$(F_REL)/SRPMS.newkey" ; \ + echo "repo --name=f$(F_REL)-updates-src --baseurl=$(FEDORA_URL)/updates/$(F_REL)/SRPMS" ; \ else \ echo "repo --name=f$(F_REL) --mirrorlist=$(FEDORA_MIRROR)?repo=fedora-$(F_REL)&arch=\$$basearch" ; \ echo "repo --name=f$(F_REL)-updates --mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-f$(F_REL)&arch=\$$basearch" ; \ - echo "repo --name=f$(F_REL)-updates-newkey --mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-f$(F_REL).newkey&arch=\$$basearch" ; \ + echo "repo --name=f$(F_REL)-updates --mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-f$(F_REL)&arch=\$$basearch" ; \ echo "repo --name=f$(F_REL)-src --mirrorlist=$(FEDORA_MIRROR)?repo=fedora-source-$(F_REL)&arch=src" ; \ echo "repo --name=f$(F_REL)-updates-src --mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-source-f$(F_REL)&arch=src" ; \ - echo "repo --name=f$(F_REL)-updates-src-newkey --mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-source-f$(F_REL).newkey&arch=src" ; \ + echo "repo --name=f$(F_REL)-updates-src --mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-source-f$(F_REL)&arch=src" ; \ fi ; \ echo "repo --name=ovirt-org --baseurl=$(OVIRT_URL)/${F_REL}/\$$basearch" ; \ echo "repo --name=ovirt-org-src --baseurl=$(OVIRT_URL)/${F_REL}/src" ; \ -- 1.6.0.4 From jdong at redhat.com Fri Dec 5 01:49:49 2008 From: jdong at redhat.com (Jia Dong) Date: Fri, 05 Dec 2008 09:49:49 +0800 Subject: [Ovirt-devel] How to login to the URL: http://192.168.50.2/cobbler/web/?mode=system_list In-Reply-To: <1228309746.8446.9.camel@dima-desktop> References: <1228252022-7047-1-git-send-email-pmyers@redhat.com> <4935A646.5010500@redhat.com> <20081203011612.GE8317@mcpierce-laptop.mcpierce.org> <4935F8C4.5040009@redhat.com> <49364613.1010404@redhat.com> <20081203130549.GB4397@mcpierce-laptop.rdu.redhat.com> <1228309746.8446.9.camel@dima-desktop> Message-ID: <493888BD.9050706@redhat.com> ??????? ??????? wrote: > this is manual how to configure cobbler webui > https://fedorahosted.org/cobbler/wiki/CobblerWebInterface > > > A great help, Thanks! :) From d.vasilets at peterhost.ru Fri Dec 5 12:20:50 2008 From: d.vasilets at peterhost.ru (=?koi8-r?Q?=F7=C1=D3=C9=CC=C5=C3_?= =?koi8-r?Q?=E4=CD=C9=D4=D2=C9=CA?=) Date: Fri, 05 Dec 2008 15:20:50 +0300 Subject: [Ovirt-devel] ovirt see only 1 node. how to add other servers ? In-Reply-To: <1228389599.7273.5.camel@dima-desktop> References: <1228317705.11195.2.camel@dima-desktop> <4936A549.5000203@redhat.com> <1228389599.7273.5.camel@dima-desktop> Message-ID: <1228479650.13032.7.camel@dima-desktop> i can't see hosts after reinstall ovirt-appliance how to real hosts report to ovirt that "i'm online " ? a demon responsible for this? ? ???, 04/12/2008 ? 14:19 +0300, ??????? ??????? ?????: > on node1 I "create-ovirt-appliance -e eth0" and "virsh start > ovirt-appliance " > on node2 I "ovirt-install-node stateful" > I think i must create virtual network between real nodes > on node1 and node2 i add eth0 to ovirtbr0 "brctl addif ovirtbr0 eth0", > and set on both nodes ovirtbr0 adress 192.168.50.100/24 and > 192.168.50.200/24 > > all nodes and virtual host "ovirt-appliance" is in same network > (192.168.50.0/24), but only one node in list > > ? ???, 03/12/2008 ? 10:27 -0500, Perry Myers ?????: > > ?? wrote: > > > ovirt see only 1 node. how to add other servers ? > > > > You just need to boot additional physical machines connected to the oVirt > > network. > > > > You need to have run create-ovirt-appliance with the -e parameter to > > indicate that you want to bridge the ovirt-appliance to an external > > network. (i.e. -e eth1) > > > > Then PXE boot some machines on that network and they'll boot the Node from > > the appliance and register themselves with the oVirt Server. > > > > Perry > > > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel > From jim at meyering.net Fri Dec 5 18:49:11 2008 From: jim at meyering.net (Jim Meyering) Date: Fri, 05 Dec 2008 19:49:11 +0100 Subject: [Ovirt-devel] [PATCH node-image] clean up quoting, cleanup-on-exception, use mktemp-not-/tmp, etc. In-Reply-To: <87zljecxkc.fsf@rho.meyering.net> (Jim Meyering's message of "Tue, 02 Dec 2008 18:10:43 +0100") References: <87zljecxkc.fsf@rho.meyering.net> Message-ID: <87myfa1mqg.fsf@rho.meyering.net> I've just pushed the following with the two marked corrections: Jim Meyering wrote: > --- > ovirt-flash-static | 77 ++++++++++++++++++++++++++++++++++++--------------- > 1 files changed, 54 insertions(+), 23 deletions(-) > > diff --git a/ovirt-flash-static b/ovirt-flash-static ... > +cleanup() > +{ > + { umount "$USBTMP" > + umount "$SQUASHTMP" > + umount "$IMGTMP" > + } 2> /dev/null || : > + rm -rf "$tmpdir" > +} > +trap cleanup 0 > +trap 'Exit $?' 1 2 13 15 s/Exit/exit/ ... > +find "$IMGTMP" # FIXME Remove the debug "find". From jim at meyering.net Fri Dec 5 18:50:17 2008 From: jim at meyering.net (Jim Meyering) Date: Fri, 05 Dec 2008 19:50:17 +0100 Subject: [Ovirt-devel] [PATCH node-image] edit-livecd: add -o OUTPUT.iso option, required Message-ID: <87hc5i1mom.fsf@rho.meyering.net> I've just pushed this, too: -------------- edit-livecd: add -o OUTPUT.iso option, required The new -o OUTPUT.iso option is now required. Allow the '-p CODE' option to specify bourne shell code, not just a file/script. This permits a common idiom: to avoid writing a separate shell script for a simple task, and instead include a quoted multi-line snippet in the invoking script, e.g., edit-livecd ...other-options... -p ' d=etc/foo mkdir -p $d && touch $d/file ' Also, in the boot params substitution, - use @ rather than / in the sed - warn if the selected string contains @ Update -h (help) output, and add examples. Evaluate $CODE in a subshell (safer and doesn't rely on pushd,popd). Guard against uninitialized ID_FS_LABEL. Don't use "function" keyword. Fail if there are any extra command-line arguments. Ensure that $PWD and $CD are double-eval safe (else fail), so that we don't have to quote them everywhere. Ensure that a $CODE (renamed from $PROG) definition doesn't leak in from the environment. --- edit-livecd | 117 ++++++++++++++++++++++++++++++++++++++--------------------- 1 files changed, 75 insertions(+), 42 deletions(-) diff --git a/edit-livecd b/edit-livecd index ce9e65b..6d6498a 100755 --- a/edit-livecd +++ b/edit-livecd @@ -34,38 +34,49 @@ usage() { Usage: $ME -i LiveCD.iso [-b bootparams] [-p program] -b BOOTPARAMS optional parameters appended to the kernel command line -i LIVECD.iso LiveCD ISO to edit (default: $NODEIMG_DEFAULT) - -p PROGRAM Arbitrary program/script that is run inside of the livecd root - filesystem. This script is not run in a chroot environment so - it can access the host filesystem. The program should be executable - If program is omitted the script will pause and allow the user in - another terminal to edit the filesystem manually. After enter is - pushed the script will re-package up the ISO. + -o OUTPUT.iso specify the output file (required) + -p CODE Arbitrary CODE that is eval'd while 'cd'd into the root of + the livecd root filesystem. Note; the code is not run in + a chroot environment, so it can access the host filesystem. + If this option is omitted, this program pauses and allows + the user (in another terminal) to modify the filesystem + manually. Type when done, and the script + re-packages the ISO. -h display this help and exit +EXAMPLES + Example Script: #!/bin/sh touch etc/sysconfig/foo + Save as foo and make executable: + chmod a+x foo + Run this to create a file /etc/sysconfig/foo in the livecd filesystem + (note the use of "\$PWD/foo", not "./foo", since it will be run from a + different directory): + + $ME -i input.iso -o /tmp/result.iso -p "\$PWD/foo" + + or, equivalently, but without a separate script: + + $ME -i input.iso -o /tmp/result.iso -p 'touch etc/sysconfig/foo' - This will create a file /etc/sysconfig/foo in the livecd filesystem. EOF } -# FIXME: instead of requiring a PROGRAM, allow arbitrary shell code, -# so we can invoke $0 -p 'touch etc/sysconfig/foo' ... -# This means that if you *do* have a program in the current directory -# running "$0 -p ./my-script" won't work, since it'll be run with -# a different working dir. However, *this* will: -# $0 -p "$PWD/my-script" - # exit after any error: set -e +CODE= +OUTPUT_FILE= + err=0 help=0 -while getopts :b:i:p:h c; do +while getopts :b:hi:o:p: c; do case $c in i) CD=$OPTARG;; b) PARAMS=$OPTARG;; - p) PROG=$OPTARG;; + o) OUTPUT_FILE=$OPTARG;; + p) CODE=$OPTARG;; h) help=1;; '?') err=1; warn "invalid option: \`-$OPTARG'";; :) err=1; warn "missing argument to \`-$OPTARG' option";; @@ -75,39 +86,59 @@ done test $err = 1 && { try_h; exit 1; } test $help = 1 && { usage; exit 0; } +# Require "-o OUTPUT_FILE" +test -z "$OUTPUT_FILE" \ + && { warn "no output file specified; use -o FILE.iso"; try_h; exit 1; } + +# Fail if there are any extra command-line arguments. +if test $OPTIND -le $#; then + bad_arg=$(eval "echo \$$OPTIND") + warn "extra argument '$bad_arg'"; try_h; exit 1 +fi + # first, check to see we are root if [ $( id -u ) -ne 0 ]; then die "Must run as root" fi -# FIXME: don't use which: with bash, it's a separate program -# FIXME: When failing due to a missing required program, tell the user why. -which mkisofs mksquashfs sed > /dev/null 2>&1 +# Check for some prerequisites. +# "type" prints "PROG not found" if it's not in $PATH. +type mkisofs +type mksquashfs +type sed + +sane_name() +{ + case $1 in + *[^a-zA-Z0-9._,+:/@%=-]*) false;; + *) true;; + esac +} + +# Fail if names we'll use contain white space or shell meta-characters +sane_name "$PWD" || die "invalid working directory name: $PWD" +sane_name "$CD" || die "invalid ISO name: $CD" WDIR=`mktemp -d $PWD/livecd.XXXXXXXXXX` -# FIXME: fail if $WDIR contains white space or shell meta-characters -# FIXME: do the same for $CD. - -ISO="${CD##*/}" -ISO="${ISO%.iso}-custom.iso" -function addExit() { +addExit() { EXIT="$@ ; $EXIT" trap "$EXIT" EXIT HUP TERM INT QUIT } -function mnt() { +mnt() { local margs="$1" ; shift local mp="$WDIR/$1" for D in "$@" ; do mkdir -v -p "$WDIR/$D" done - mount -v $margs "$mp" + eval mount -v $margs "$mp" addExit "df | grep $mp > /dev/null 2>&1 && umount -v $mp" } addExit "rm -rf $WDIR" +ID_FS_LABEL= # initialize, in case vol_id fails eval "$(/lib/udev/vol_id $CD)" LABEL=$ID_FS_LABEL @@ -120,21 +151,21 @@ mnt "-t squashfs $WDIR/cd/LiveOS/squashfs.img -o ro,loop" sq # create writable copy of the new filesystem for the CD cp -a $WDIR/cd $WDIR/cd-w -# create writable copy of the filesystem for the new compressed squashfs filesystem +# create writable copy of the filesystem for the new compressed +# squashfs filesystem cp -a $WDIR/sq $WDIR/sq-w # mount ext3 filesystem mnt "-t auto $WDIR/sq-w/LiveOS/ext3fs.img -o rw,loop" ex echo ">>> Updating CD content" -if [ -n "$PROG" ]; then - cp -av $PROG $WDIR/ex - pushd $WDIR/ex - set +e - ./$(basename $PROG) - set -e - popd - rm -f $WDIR/ex/$PROG +if [ -n "$CODE" ]; then + ( + cd $WDIR/ex + set +e + eval "$CODE" + set -e + ) else echo "***" echo "*** Pausing to allow manual changes. Press any key to continue." @@ -147,7 +178,7 @@ fi while :; do echo ">>> Unmounting ext3fs" umount $WDIR/ex && break - echo ">>> Unmounting ext3fs failed" + echo ">>> Unmounting the working file system copy failed" echo "***" echo "*** Did you forget to 'cd' out of $WDIR/ex?" echo "***" @@ -160,13 +191,15 @@ echo ">>> Compressing filesystem" mksquashfs $WDIR/sq-w/ $WDIR/cd-w/LiveOS/squashfs.img -noappend echo ">>> Recomputing MD5 sums" -( cd $WDIR/cd-w && find . -type f -not -name md5sum.txt -not -path '*/isolinux/*' -print0 | xargs -0 -- md5sum > md5sum.txt ) +( cd $WDIR/cd-w && find . -type f -not -name md5sum.txt \ + -not -path '*/isolinux/*' -print0 | xargs -0 -- md5sum > md5sum.txt ) if [ -n "$PARAMS" ]; then - # FIXME: make the script fail -- or maybe try to - # find a usable sed delimiter if $PARAMS contains a slash + case $PARAMS in + *@*) warn "PARAMS contains the @ sed delimiter, be sure it's escaped";; + esac echo ">>> Appending boot parameters" - sed -i 's/^ append .*$/& '"$PARAMS/" "$WDIR/cd-w/isolinux/isolinux.cfg" + sed -i 's@^ append .*$@& '"$PARAMS@" "$WDIR/cd-w/isolinux/isolinux.cfg" fi echo ">>> Creating ISO image $ISO" @@ -176,7 +209,7 @@ mkisofs \ -b isolinux/isolinux.bin \ -c isolinux/boot.cat \ -no-emul-boot -boot-load-size 4 -boot-info-table \ - -o "$ISO" \ + -o "$OUTPUT_FILE" \ $WDIR/cd-w # The trap ... callbacks will unmount everything. -- 1.6.1.rc1.333.gba3cb From almarzuki2001 at gmail.com Fri Dec 5 13:27:14 2008 From: almarzuki2001 at gmail.com (Hadi almarzuki) Date: Fri, 5 Dec 2008 18:57:14 +0530 Subject: [Ovirt-devel] help Message-ID: HI, im trying to setup ovirt on centos. when we flow ur instruction on the web we getting problem for downloading with yum . pls guide us http://ovirt.org/repos/ovirt/5/i386/repodata/repomd.xml: [Errno 14] HTTP Error 404: Not Found Trying other mirror. Error: Cannot retrieve repository metadata (repomd.xml) for repository: ovirt. Please verify its path and try again Regards -Hadi -------------- next part -------------- An HTML attachment was scrubbed... URL: From sseago at redhat.com Fri Dec 5 20:19:07 2008 From: sseago at redhat.com (Scott Seago) Date: Fri, 5 Dec 2008 20:19:07 +0000 Subject: [Ovirt-devel] [PATCH] fix for bug 464282: delete permissions Message-ID: <1228508347-25949-1-git-send-email-sseago@redhat.com> Delete permissions now works -- had a conditional statement wrong in the controller action. Signed-off-by: Scott Seago --- src/app/controllers/permission_controller.rb | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/app/controllers/permission_controller.rb b/src/app/controllers/permission_controller.rb index 5d3646d..813d9d9 100644 --- a/src/app/controllers/permission_controller.rb +++ b/src/app/controllers/permission_controller.rb @@ -102,7 +102,7 @@ class PermissionController < ApplicationController Permission.transaction do permissions = Permission.find(:all, :conditions => "id in (#{permission_ids.join(', ')})") permissions.each do |permission| - permission.destroy unless permission.is_primary? + permission.destroy if permission.is_primary? end end render :json => { :object => "permission", :success => true, -- 1.6.0.4 From bguthro at virtualiron.com Fri Dec 5 20:36:27 2008 From: bguthro at virtualiron.com (Ben Guthro) Date: Fri, 05 Dec 2008 15:36:27 -0500 Subject: [Ovirt-devel] help In-Reply-To: References: Message-ID: <493990CB.9060207@virtualiron.com> oVirt is currently desiged to be built on top of Fedora 9, or 10 The ovirt-release/ovirt.mk file adds repos for the livecd-creator: OVIRT_URL ?= http://ovirt.org/repos/ovirt ... F_REL = $(shell rpm -q --qf '%{VERSION}' fedora-release) ... echo "repo --name=ovirt-org --baseurl=$(OVIRT_URL)/${F_REL}/\$$basearch" ; \ F_REL must be resolving to "5" for Centos. ...I imagine this is going to be the first of many problems though, as this is not a supported config, AFAIK http://ovirt.org/repos/ovirt/5/i386/repodata/repomd.xml Hadi almarzuki wrote on 12/05/2008 08:27 AM: > HI, > > > im trying to setup ovirt on centos. when we flow ur instruction on the > web we getting problem for downloading with yum . > pls guide us > > http://ovirt.org/repos/ovirt/5/i386/repodata/repomd.xml: [Errno 14] HTTP > Error 404: Not Found > Trying other mirror. > Error: Cannot retrieve repository metadata (repomd.xml) for repository: > ovirt. Please verify its path and try again > > > Regards > > -Hadi > > > > > ------------------------------------------------------------------------ > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel From pmyers at redhat.com Fri Dec 5 20:40:42 2008 From: pmyers at redhat.com (Perry Myers) Date: Fri, 05 Dec 2008 15:40:42 -0500 Subject: [Ovirt-devel] help In-Reply-To: References: Message-ID: <493991CA.6040103@redhat.com> Hadi almarzuki wrote: > HI, > > > im trying to setup ovirt on centos. when we flow ur instruction on the > web we getting problem for downloading with yum . > pls guide us > > http://ovirt.org/repos/ovirt/5/i386/repodata/repomd.xml: [Errno 14] HTTP > Error 404: Not Found > Trying other mirror. > Error: Cannot retrieve repository metadata (repomd.xml) for repository: > ovirt. Please verify its path and try again Hadi, Thanks for looking into oVirt. At this time our developers are focused on Fedora 10 as the OS to support the oVirt Server. Centos 5 (being based on RHEL5) will have a much older package set and it's likely that things will not work correctly on that OS without some backporting and patching of other core packages (like kvm, ruby, etc...) You're welcome to give it a try and submit patches so that oVirt can support that OS as a base (in fact we'd love to get some community support for additional OSes!) But at the current time we don't have enough development help to port oVirt to Centos. At some point we will probably port things over to RHEL and from there moving to Centos should be trivial, but I don't know what the timeline for that is. Thanks, Perry From imain at redhat.com Fri Dec 5 20:52:25 2008 From: imain at redhat.com (Ian Main) Date: Fri, 5 Dec 2008 12:52:25 -0800 Subject: [Ovirt-devel] [PATCH server] Fix race condition with ovirt-identify-node. Message-ID: <1228510345-28441-1-git-send-email-imain@redhat.com> This patch teaches dbomatic how to keep track of whether or not it has actually synced an object with the database. There were problems with db-omatic getting information before the database entries were created by ovirt-identify-node and co. Now dbomatic will keep trying until synced with the database. Signed-off-by: Ian Main --- src/db-omatic/db_omatic.rb | 21 ++++++++++++++++++--- 1 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/db-omatic/db_omatic.rb b/src/db-omatic/db_omatic.rb index ba245e6..fe2d47c 100755 --- a/src/db-omatic/db_omatic.rb +++ b/src/db-omatic/db_omatic.rb @@ -29,8 +29,13 @@ class DbOmatic < Qpid::Qmf::Console def update_domain_state(domain, state_override = nil) vm = Vm.find(:first, :conditions => [ "uuid = ?", domain['uuid'] ]) if vm == nil - puts "VM Not found in database, must be created by user; ignoring." - return + puts "VM Not found in database, must be created by user; ignoring." + + #XXX: I mark this one as 'synced' here even though we couldn't sync + #it because there really should be a db entry for every vm unless it + #was created outside of ovirt. + domain[:synced] = true + return end if state_override != nil @@ -61,6 +66,8 @@ class DbOmatic < Qpid::Qmf::Console puts "Updating VM #{domain['name']} to state #{state}" vm.state = state vm.save + + domain[:synced] = true end def update_host_state(host_info, state) @@ -78,9 +85,15 @@ class DbOmatic < Qpid::Qmf::Console # XXX: This would just be for init.. #db_host.is_disabled = 0 db_host.save + host_info[:synced] = true else # FIXME: This would be a newly registered host. We could put it in the database. puts "Unknown host, probably not registered yet??" + # XXX: So it turns out this can happen as there is a race condition on bootup + # where the registration takes longer than libvirt-qpid does to relay information. + # So in this case, we mark this object as not synced so it will get resynced + # again in the heartbeat. + host_info[:synced] = false end end @@ -106,6 +119,7 @@ class DbOmatic < Qpid::Qmf::Console values[:agent_bank] = obj.object_id.agent_bank values[:class_type] = obj.klass_key[1] values[:timed_out] = false + values[:synced] = false puts "New object type #{type}" new_object = true @@ -150,6 +164,7 @@ class DbOmatic < Qpid::Qmf::Console values[:agent_bank] = obj.object_id.agent_bank values[:class_type] = obj.klass_key[1] values[:timed_out] = false + values[:synced] = false end obj.statistics.each do |key, newval| if values[key.to_s] != newval @@ -203,7 +218,7 @@ class DbOmatic < Qpid::Qmf::Console @cached_objects[objkey][:agent_bank] == agent.agent_bank values = @cached_objects[objkey] - if values[:timed_out] == true + if values[:timed_out] == true or values[:synced] == false puts "Marking object of type #{values[:class_type]} as in service." if values[:class_type] == 'node' update_host_state(values, Host::STATE_AVAILABLE) -- 1.6.0.4 From imain at redhat.com Fri Dec 5 21:20:53 2008 From: imain at redhat.com (Ian Main) Date: Fri, 5 Dec 2008 13:20:53 -0800 Subject: [Ovirt-devel] [PATCH server] Fix logging in db-omatic. Message-ID: <1228512053-29100-1-git-send-email-imain@redhat.com> This patch fixes the logging and then goes a step further to add timestamps to each log entry. Signed-off-by: Ian Main --- src/db-omatic/db_omatic.rb | 35 +++++++++++++++++++++-------------- 1 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/db-omatic/db_omatic.rb b/src/db-omatic/db_omatic.rb index fe2d47c..4afffb1 100755 --- a/src/db-omatic/db_omatic.rb +++ b/src/db-omatic/db_omatic.rb @@ -26,10 +26,14 @@ class DbOmatic < Qpid::Qmf::Console database_connect end + def log(s) + puts "#{Time.now}: #{s}" + end + def update_domain_state(domain, state_override = nil) vm = Vm.find(:first, :conditions => [ "uuid = ?", domain['uuid'] ]) if vm == nil - puts "VM Not found in database, must be created by user; ignoring." + log "VM Not found in database, must be created by user; ignoring." #XXX: I mark this one as 'synced' here even though we couldn't sync #it because there really should be a db entry for every vm unless it @@ -63,7 +67,7 @@ class DbOmatic < Qpid::Qmf::Console end end - puts "Updating VM #{domain['name']} to state #{state}" + log "Updating VM #{domain['name']} to state #{state}" vm.state = state vm.save @@ -73,7 +77,7 @@ class DbOmatic < Qpid::Qmf::Console def update_host_state(host_info, state) db_host = Host.find(:first, :conditions => [ "hostname = ?", host_info['hostname'] ]) if db_host - puts "Marking host #{host_info['hostname']} as state #{state}." + log "Marking host #{host_info['hostname']} as state #{state}." db_host.state = state db_host.hypervisor_type = host_info['hypervisorType'] db_host.arch = host_info['model'] @@ -88,7 +92,7 @@ class DbOmatic < Qpid::Qmf::Console host_info[:synced] = true else # FIXME: This would be a newly registered host. We could put it in the database. - puts "Unknown host, probably not registered yet??" + log "Unknown host, probably not registered yet??" # XXX: So it turns out this can happen as there is a race condition on bootup # where the registration takes longer than libvirt-qpid does to relay information. # So in this case, we mark this object as not synced so it will get resynced @@ -120,7 +124,7 @@ class DbOmatic < Qpid::Qmf::Console values[:class_type] = obj.klass_key[1] values[:timed_out] = false values[:synced] = false - puts "New object type #{type}" + log "New object type #{type}" new_object = true end @@ -130,7 +134,7 @@ class DbOmatic < Qpid::Qmf::Console obj.properties.each do |key, newval| if values[key.to_s] != newval values[key.to_s] = newval - #puts "new value for property #{key} : #{newval}" + #log "new value for property #{key} : #{newval}" if type == "domain" and key.to_s == "state" domain_state_change = true end @@ -169,7 +173,7 @@ class DbOmatic < Qpid::Qmf::Console obj.statistics.each do |key, newval| if values[key.to_s] != newval values[key.to_s] = newval - #puts "new value for statistic #{key} : #{newval}" + #log "new value for statistic #{key} : #{newval}" end end end @@ -196,7 +200,7 @@ class DbOmatic < Qpid::Qmf::Console @cached_objects[objkey][:agent_bank] == agent.agent_bank values = @cached_objects[objkey] - puts "Marking object of type #{values[:class_type]} as timed out." + log "Marking object of type #{values[:class_type]} as timed out." if values[:timed_out] == false if values[:class_type] == 'node' update_host_state(values, Host::STATE_UNAVAILABLE) @@ -219,7 +223,7 @@ class DbOmatic < Qpid::Qmf::Console values = @cached_objects[objkey] if values[:timed_out] == true or values[:synced] == false - puts "Marking object of type #{values[:class_type]} as in service." + log "Marking object of type #{values[:class_type]} as in service." if values[:class_type] == 'node' update_host_state(values, Host::STATE_AVAILABLE) elsif values[:class_type] == 'domain' @@ -236,14 +240,14 @@ class DbOmatic < Qpid::Qmf::Console def db_init_cleanup() db_host = Host.find(:all) db_host.each do |host| - puts "Marking host #{host.hostname} unavailable" + log "Marking host #{host.hostname} unavailable" host.state = Host::STATE_UNAVAILABLE host.save end db_vm = Vm.find(:all) db_vm.each do |vm| - puts "Marking vm #{vm.description} as stopped." + log "Marking vm #{vm.description} as stopped." vm.state = Vm::STATE_STOPPED vm.save end @@ -283,7 +287,7 @@ class DbOmatic < Qpid::Qmf::Console end -$logfile = '/var/log/ovirt-server/qpid-db-sync.log' +$logfile = '/var/log/ovirt-server/db-omatic.log' def main() @@ -313,8 +317,11 @@ def main() pwd = Dir.pwd daemonize Dir.chdir(pwd) - STDOUT.reopen $logfile, 'a' - STDERR.reopen STDOUT + + lf = open($logfile, 'a') + $stdout = lf + $stderr = lf + puts "#{Time.now}: db_omatic started." end dbsync = DbOmatic.new() -- 1.6.0.4 From sseago at redhat.com Fri Dec 5 21:58:53 2008 From: sseago at redhat.com (Scott Seago) Date: Fri, 5 Dec 2008 21:58:53 +0000 Subject: [Ovirt-devel] [PATCH] fixed cpu speed value for hosts grid. Message-ID: <1228514333-28272-1-git-send-email-sseago@redhat.com> Signed-off-by: Scott Seago --- src/app/models/host.rb | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/app/models/host.rb b/src/app/models/host.rb index 429f0c0..640782d 100644 --- a/src/app/models/host.rb +++ b/src/app/models/host.rb @@ -85,7 +85,7 @@ class Host < ActiveRecord::Base end def cpu_speed - "FIX ME!" + cpus[0].speed unless cpus.empty? end def display_name -- 1.6.0.4 From dpierce at redhat.com Fri Dec 5 22:52:43 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Fri, 5 Dec 2008 17:52:43 -0500 Subject: [Ovirt-devel] [PATCH node] Fixes a bug in the storage size configuration. Message-ID: <1228517563-9527-1-git-send-email-dpierce@redhat.com> When the user input values, those values were not being copied correctly. Signed-off-by: Darryl L. Pierce --- scripts/ovirt-config-storage | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage index 49e1880..5c666ba 100755 --- a/scripts/ovirt-config-storage +++ b/scripts/ovirt-config-storage @@ -254,12 +254,12 @@ case $MEM_SIZE in esac MEM_SIZE=$(echo "scale=0; $MEM_SIZE / 1024" | bc -l) -SWAP_SIZE=${OVIRT_VOL_SWAP_SIZE:-MEM_SIZE} +SWAP_SIZE=${OVIRT_VOL_SWAP_SIZE:-$MEM_SIZE} -BOOT_SIZE=${OVIRT_VOL_BOOT_SIZE:-default_boot_size} -ROOT_SIZE=${OVIRT_VOL_ROOT_SIZE:-default_root_size} -CONFIG_SIZE=${OVIRT_VOL_CONFIG_SIZE:-default_config_size} -LOGGING_SIZE=${OVIRT_VOL_LOGGING_SIZE:-default_logging_size} +BOOT_SIZE=${OVIRT_VOL_BOOT_SIZE:-$default_boot_size} +ROOT_SIZE=${OVIRT_VOL_ROOT_SIZE:-$default_root_size} +CONFIG_SIZE=${OVIRT_VOL_CONFIG_SIZE:-$default_config_size} +LOGGING_SIZE=${OVIRT_VOL_LOGGING_SIZE:-$default_logging_size} if [ "$1" == "AUTO" ]; then -- 1.6.0.4 From jboggs at redhat.com Fri Dec 5 23:08:35 2008 From: jboggs at redhat.com (Joey Boggs) Date: Fri, 05 Dec 2008 18:08:35 -0500 Subject: [Ovirt-devel] ovirt installation test scenarios Message-ID: <4939B473.7050701@redhat.com> Since the options are limited right with what can be external(postgres/freeipa) here's a list so far of different oVirt installation scenarios that should to be tested external dns + internal cobbler + external dhcp + internal pxe external dns + internal cobbler + internal dhcp + internal pxe external dns + external cobbler + external dhcp + external pxe external dns + external cobbler + internal dhcp + external pxe internal dns + internal cobbler + external dhcp + internal pxe internal dns + internal cobbler + internal dhcp + internal pxe Can't reproduce these below just yet due to dnsmasq config, currently does both dhcp and dns by default bundled config internal dns + external cobbler + external dhcp + external pxe internal dns + external cobbler + internal dhcp + external pxe There may be some issues in producing these scenarios if so please let me know and we can build/correct a solution. From pmyers at redhat.com Fri Dec 5 23:16:00 2008 From: pmyers at redhat.com (Perry Myers) Date: Fri, 05 Dec 2008 18:16:00 -0500 Subject: [Ovirt-devel] [PATCH] fixed cpu speed value for hosts grid. In-Reply-To: <1228514333-28272-1-git-send-email-sseago@redhat.com> References: <1228514333-28272-1-git-send-email-sseago@redhat.com> Message-ID: <4939B630.6050903@redhat.com> Scott Seago wrote: > Signed-off-by: Scott Seago > --- > src/app/models/host.rb | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > diff --git a/src/app/models/host.rb b/src/app/models/host.rb > index 429f0c0..640782d 100644 > --- a/src/app/models/host.rb > +++ b/src/app/models/host.rb > @@ -85,7 +85,7 @@ class Host < ActiveRecord::Base > end > > def cpu_speed > - "FIX ME!" > + cpus[0].speed unless cpus.empty? > end > > def display_name WFM, Ack and I pushed this :) Perry -- |=- Red Hat, Engineering, Emerging Technologies, Boston -=| |=- Email: pmyers at redhat.com -=| |=- Office: +1 412 474 3552 Mobile: +1 703 362 9622 -=| |=- GnuPG: E65E4F3D 88F9 F1C9 C2F3 1303 01FE 817C C5D2 8B91 E65E 4F3D -=| From pmyers at redhat.com Fri Dec 5 23:16:30 2008 From: pmyers at redhat.com (Perry Myers) Date: Fri, 05 Dec 2008 18:16:30 -0500 Subject: [Ovirt-devel] [PATCH server] Fix race condition with ovirt-identify-node. In-Reply-To: <1228510345-28441-1-git-send-email-imain@redhat.com> References: <1228510345-28441-1-git-send-email-imain@redhat.com> Message-ID: <4939B64E.4020401@redhat.com> Ian Main wrote: > This patch teaches dbomatic how to keep track of whether or not > it has actually synced an object with the database. There were > problems with db-omatic getting information before the database > entries were created by ovirt-identify-node and co. Now dbomatic > will keep trying until synced with the database. Ack. Seems to work for me, I went ahead and pushed this. Perry > Signed-off-by: Ian Main > --- > src/db-omatic/db_omatic.rb | 21 ++++++++++++++++++--- > 1 files changed, 18 insertions(+), 3 deletions(-) > > diff --git a/src/db-omatic/db_omatic.rb b/src/db-omatic/db_omatic.rb > index ba245e6..fe2d47c 100755 > --- a/src/db-omatic/db_omatic.rb > +++ b/src/db-omatic/db_omatic.rb > @@ -29,8 +29,13 @@ class DbOmatic < Qpid::Qmf::Console > def update_domain_state(domain, state_override = nil) > vm = Vm.find(:first, :conditions => [ "uuid = ?", domain['uuid'] ]) > if vm == nil > - puts "VM Not found in database, must be created by user; ignoring." > - return > + puts "VM Not found in database, must be created by user; ignoring." > + > + #XXX: I mark this one as 'synced' here even though we couldn't sync > + #it because there really should be a db entry for every vm unless it > + #was created outside of ovirt. > + domain[:synced] = true > + return > end > > if state_override != nil > @@ -61,6 +66,8 @@ class DbOmatic < Qpid::Qmf::Console > puts "Updating VM #{domain['name']} to state #{state}" > vm.state = state > vm.save > + > + domain[:synced] = true > end > > def update_host_state(host_info, state) > @@ -78,9 +85,15 @@ class DbOmatic < Qpid::Qmf::Console > # XXX: This would just be for init.. > #db_host.is_disabled = 0 > db_host.save > + host_info[:synced] = true > else > # FIXME: This would be a newly registered host. We could put it in the database. > puts "Unknown host, probably not registered yet??" > + # XXX: So it turns out this can happen as there is a race condition on bootup > + # where the registration takes longer than libvirt-qpid does to relay information. > + # So in this case, we mark this object as not synced so it will get resynced > + # again in the heartbeat. > + host_info[:synced] = false > end > end > > @@ -106,6 +119,7 @@ class DbOmatic < Qpid::Qmf::Console > values[:agent_bank] = obj.object_id.agent_bank > values[:class_type] = obj.klass_key[1] > values[:timed_out] = false > + values[:synced] = false > puts "New object type #{type}" > > new_object = true > @@ -150,6 +164,7 @@ class DbOmatic < Qpid::Qmf::Console > values[:agent_bank] = obj.object_id.agent_bank > values[:class_type] = obj.klass_key[1] > values[:timed_out] = false > + values[:synced] = false > end > obj.statistics.each do |key, newval| > if values[key.to_s] != newval > @@ -203,7 +218,7 @@ class DbOmatic < Qpid::Qmf::Console > @cached_objects[objkey][:agent_bank] == agent.agent_bank > > values = @cached_objects[objkey] > - if values[:timed_out] == true > + if values[:timed_out] == true or values[:synced] == false > puts "Marking object of type #{values[:class_type]} as in service." > if values[:class_type] == 'node' > update_host_state(values, Host::STATE_AVAILABLE) -- |=- 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 Dec 5 23:17:03 2008 From: pmyers at redhat.com (Perry Myers) Date: Fri, 05 Dec 2008 18:17:03 -0500 Subject: [Ovirt-devel] [PATCH server] Fix logging in db-omatic. In-Reply-To: <1228512053-29100-1-git-send-email-imain@redhat.com> References: <1228512053-29100-1-git-send-email-imain@redhat.com> Message-ID: <4939B66F.7020907@redhat.com> Ian Main wrote: > This patch fixes the logging and then goes a step further to add > timestamps to each log entry. Works for me, acked and pushed Perry From pmyers at redhat.com Fri Dec 5 23:29:48 2008 From: pmyers at redhat.com (Perry Myers) Date: Fri, 05 Dec 2008 18:29:48 -0500 Subject: [Ovirt-devel] [PATCH node-image] common-post.ks: factor, fix quoting, handle case of no policy files In-Reply-To: <87r64p8bbb.fsf@rho.meyering.net> References: <87r64p8bbb.fsf@rho.meyering.net> Message-ID: <4939B96C.8010503@redhat.com> Jim Meyering wrote: > Mainly clean-up, this also avoids problems with unusual $TMPDIR, > no *.pp or *.pp.bz2 files, and with a base policy file but no others. > Minor changes: prefer bzip2 over bunzip, remove unnecessary use of > xargs, remove a /usr/sbin prefix (PATH includes that at top). > > I'm testing it now... I tested this and it works fine. Good cleanup :) Pushed as well Thanks, Perry From pmyers at redhat.com Fri Dec 5 23:49:13 2008 From: pmyers at redhat.com (Perry Myers) Date: Fri, 05 Dec 2008 18:49:13 -0500 Subject: [Ovirt-devel] ovirt see only 1 node. how to add other servers ? In-Reply-To: <1228389599.7273.5.camel@dima-desktop> References: <1228317705.11195.2.camel@dima-desktop> <4936A549.5000203@redhat.com> <1228389599.7273.5.camel@dima-desktop> Message-ID: <4939BDF9.700@redhat.com> ?? wrote: > on node1 I "create-ovirt-appliance -e eth0" and "virsh start > ovirt-appliance " > on node2 I "ovirt-install-node stateful" > I think i must create virtual network between real nodes > on node1 and node2 i add eth0 to ovirtbr0 "brctl addif ovirtbr0 eth0", > and set on both nodes ovirtbr0 adress 192.168.50.100/24 and > 192.168.50.200/24 > > all nodes and virtual host "ovirt-appliance" is in same network > (192.168.50.0/24), but only one node in list ovirt-node-stateful only works on the same physical host that the ovirt-appliance is running on. So the correct sequence would be: on node 1: create-ovirt-appliance -e eth0 ovirt-install-node stateful virsh start ovirt-appliance let the appliance fully come up and then shut it down virsh destroy ovirt-appliance service libvirtd restart virsh start ovirt-appliance This startup dance is documented on the ovirt.org Wiki at: http://ovirt.org/page/Node_Stateful That will allow you to manage VMs on the same host that the appliance is running on. Then if you want to run additional ovirt Nodes you can do one of the following: on node 2 either: 1. Configure the host to PXE boot and it will boot the oVirt Node from the appliance 2. Configure the host to USB boot and use the ovirt-flash script to create a bootable USB stick from the oVirt Node ISO 3. Configure the host to CDROM boot and use it to boot the oVirt Node ISO Perry From pmyers at redhat.com Fri Dec 5 23:51:24 2008 From: pmyers at redhat.com (Perry Myers) Date: Fri, 05 Dec 2008 18:51:24 -0500 Subject: [Ovirt-devel] ovirt see only 1 node. how to add other servers ? In-Reply-To: <1228479650.13032.7.camel@dima-desktop> References: <1228317705.11195.2.camel@dima-desktop> <4936A549.5000203@redhat.com> <1228389599.7273.5.camel@dima-desktop> <1228479650.13032.7.camel@dima-desktop> Message-ID: <4939BE7C.80305@redhat.com> ?? wrote: > i can't see hosts after reinstall ovirt-appliance > how to real hosts report to ovirt that "i'm online " ? > a demon responsible for this? When an oVirt Node is booted it tries to contact the oVirt Server by looking up its IP address via DNS SRV record. If it finds an oVirt Server it attempts to register with it. However, if you reinstalled the ovirt-appliance and are using Nodes from a previous appliance installation this is not going to work since the Node will have a keytab from the old appliance. This is only a problem if you installed the Node onto a local hard disk. If you run the nodes completely stateless they always retrieve a new keytab on every boot. Perry From apevec at redhat.com Mon Dec 8 00:59:17 2008 From: apevec at redhat.com (Alan Pevec) Date: Mon, 08 Dec 2008 01:59:17 +0100 Subject: [Ovirt-devel] Re: [PATCH node] Fixes a bug in the storage size configuration. In-Reply-To: <1228517563-9527-1-git-send-email-dpierce@redhat.com> References: <1228517563-9527-1-git-send-email-dpierce@redhat.com> Message-ID: <493C7165.7070607@redhat.com> Darryl L. Pierce wrote: > When the user input values, those values were not being copied > correctly thanks, ack and pushed From jim at meyering.net Mon Dec 8 12:58:16 2008 From: jim at meyering.net (Jim Meyering) Date: Mon, 08 Dec 2008 13:58:16 +0100 Subject: [Ovirt-devel] Re: [PATCH node-image] common-post.ks: factor, fix quoting, handle case of no policy files In-Reply-To: <4939B96C.8010503@redhat.com> (Perry Myers's message of "Fri, 05 Dec 2008 18:29:48 -0500") References: <87r64p8bbb.fsf@rho.meyering.net> <4939B96C.8010503@redhat.com> Message-ID: <87bpvmzuvr.fsf_-_@rho.meyering.net> Perry Myers wrote: > I tested this and it works fine. Good cleanup :) > > Pushed as well Thanks for testing and pushing it. From pmyers at redhat.com Mon Dec 8 14:23:23 2008 From: pmyers at redhat.com (Perry Myers) Date: Mon, 08 Dec 2008 09:23:23 -0500 Subject: [Ovirt-devel] Re: qpid errors In-Reply-To: <4938938D.90706@redhat.com> References: <4938910C.1000504@redhat.com> <4938938D.90706@redhat.com> Message-ID: <493D2DDB.2050203@redhat.com> Ian, Just checking status on some of the open issues that I had... Perry Myers wrote: > Perry Myers wrote: >> You don't need to fix this tonight ;) >> >> But I figured I would just list the issues so that we tracked them >> somewhere. >> >> 1. fix race condition where it's possible that the broker gets the >> Node object before the db entry is created via ovirt-awake. This can >> be fixed by having a hashtable of nodes and for each node a dirty >> flag. If db-omatic goes to update the state in the db and can't it >> flags the node as dirty. On the next heartbeat if the flag is dirty >> for a particular node it tries to update the db again. The dirty flag >> isn't removed until the update succeeds. This should only be a >> temporary hack until we get ovirt-awake using qmf. This one you said is fixed correct? >> 2. fix objects to be persistent so that restarts of the broker do not >> lose state This was a non-issue, correct? >> 3. get one of the ui guys to fix the MHz display so that the value >> there shows up correctly sseago did this >> 4. figure out why libvirt and hypervisor version are showing up as >> unknown We need newer libvirt according to danpb (0.5.1) >> 5. db-omatic is not logging properly You fixed this >> 6. rsyslog is not working on node startup... you have top manually >> restart the rsyslog daemon after the node has booted to get a >> /var/log/messages file >> >> I'll take a look at #6, the rest are qpid related so they're yours... I still need to figure this one out > Oh adding to the list > > 7. Get MRG to repackage their RPMs so that doxygen stuff is built during > RPM build and not as part of the source tarball and also get them to use > something other than 24 bit color for their png files. And put their > docs into a docs rpm so that the devel rpm is not bloated. Have you talked to the MRG guys about this? Perry From bkearney at redhat.com Mon Dec 8 15:12:18 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 8 Dec 2008 10:12:18 -0500 Subject: [Ovirt-devel] [PATCH node] Allow the init scripts to handle ctrl-c well Message-ID: <1228749138-14904-1-git-send-email-bkearney@redhat.com> From: Bryan Kearney --- scripts/ovirt-functions | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/scripts/ovirt-functions b/scripts/ovirt-functions index c6a8504..f641ea0 100644 --- a/scripts/ovirt-functions +++ b/scripts/ovirt-functions @@ -2,6 +2,13 @@ OVIRT_LOGFILE=/var/log/ovirt.log +# handle ctrl-c gracefully +trap 'dropout' INT + +dropout() { + exit 0 +} + # label of the oVirt partition OVIRT_LABEL=OVIRT # configuration defaults -- 1.6.0.4 From mdehaan at redhat.com Mon Dec 8 16:08:17 2008 From: mdehaan at redhat.com (Michael DeHaan) Date: Mon, 08 Dec 2008 11:08:17 -0500 Subject: [Ovirt-devel] ovirt installation test scenarios In-Reply-To: <4939B473.7050701@redhat.com> References: <4939B473.7050701@redhat.com> Message-ID: <493D4671.3090003@redhat.com> Joey Boggs wrote: > Since the options are limited right with what can be > external(postgres/freeipa) here's a list so far of different oVirt > installation scenarios that should to be tested > > external dns + internal cobbler + external dhcp + internal pxe > external dns + internal cobbler + internal dhcp + internal pxe > external dns + external cobbler + external dhcp + external pxe > external dns + external cobbler + internal dhcp + external pxe > internal dns + internal cobbler + external dhcp + internal pxe > internal dns + internal cobbler + internal dhcp + internal pxe > > Can't reproduce these below just yet due to dnsmasq config, currently > does both dhcp and dns by default bundled config > internal dns + external cobbler + external dhcp + external pxe > internal dns + external cobbler + internal dhcp + external pxe > > There may be some issues in producing these scenarios if so please let > me know and we can build/correct a solution. > The cobbler server should be the PXE server, and that should help simplify things, no? All the admin would have to do is set the next-server for the subnet to point at the cobbler box if he happened to have another PXE environment. You could just document this step. Somewhat unrelated, is Ovirt doing any DHCP management? Cobbler has a built in feature for this that would probably be useful. DNS also -- and it does support dnsmasq in addition to the BIND stuff. This allows you to pin certain mac addresses to certain ip's and hostnames, just by creating cobbler system records with that information filled in. --Michael > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel From d.vasilets at peterhost.ru Mon Dec 8 17:24:58 2008 From: d.vasilets at peterhost.ru (=?koi8-r?Q?=F7=C1=D3=C9=CC=C5=C3_?= =?koi8-r?Q?=E4=CD=C9=D4=D2=C9=CA?=) Date: Mon, 08 Dec 2008 20:24:58 +0300 Subject: [Ovirt-devel] ovirt see only 1 node. how to add other servers ? In-Reply-To: <4939BE7C.80305@redhat.com> References: <1228317705.11195.2.camel@dima-desktop> <4936A549.5000203@redhat.com> <1228389599.7273.5.camel@dima-desktop> <1228479650.13032.7.camel@dima-desktop> <4939BE7C.80305@redhat.com> Message-ID: <1228757099.11371.4.camel@dima-desktop> After destroy ovirt-appliance file system produce a lot of errors I boot second real node from cobbler on ovirt-appliance but it is not appear in list second node have adress 192.168.50.254 - is this network for administrative message or 192.168.1222/24 ? ? ???, 05/12/2008 ? 18:51 -0500, Perry Myers ?????: > ?? wrote: > > i can't see hosts after reinstall ovirt-appliance > > how to real hosts report to ovirt that "i'm online " ? > > a demon responsible for this? > > When an oVirt Node is booted it tries to contact the oVirt Server by > looking up its IP address via DNS SRV record. If it finds an oVirt Server > it attempts to register with it. > > However, if you reinstalled the ovirt-appliance and are using Nodes from a > previous appliance installation this is not going to work since the Node > will have a keytab from the old appliance. This is only a problem if you > installed the Node onto a local hard disk. If you run the nodes > completely stateless they always retrieve a new keytab on every boot. > > Perry > From dhuff at redhat.com Mon Dec 8 17:44:38 2008 From: dhuff at redhat.com (David Huff) Date: Mon, 8 Dec 2008 12:44:38 -0500 Subject: [Ovirt-devel] Repost, use pungi to download the srpms for the appliance and creates a srpm.iso Message-ID: <1228758281-12698-1-git-send-email-dhuff@redhat.com> This patch set uses pungi to download the srpms for the appliance and creates a srpm.iso. These patches move this functionality form ovirt-release/ovirt.mk to the node-image and appliance Make files. Currently builds $(PWD)/$(PACKAGE)-source.iso instead of a RPM. Can also spit our a tar file or be configured to chose format depending on $(PKG_FMT). From dhuff at redhat.com Mon Dec 8 17:44:39 2008 From: dhuff at redhat.com (David Huff) Date: Mon, 8 Dec 2008 12:44:39 -0500 Subject: [Ovirt-devel] [PATCH node-image] Added make source target to build source.iso$ In-Reply-To: <1228758281-12698-1-git-send-email-dhuff@redhat.com> References: <1228758281-12698-1-git-send-email-dhuff@redhat.com> Message-ID: <1228758281-12698-2-git-send-email-dhuff@redhat.com> Workaround which uses pungi to download srpms and create a srpm.iso$ Currently builds $(PWD)/$(PACKAGE)-source.iso however can also spit our .tar and can be easily configured to chose depending on $(PKG_FMT)$ --- Makefile.am | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 53 insertions(+), 0 deletions(-) diff --git a/Makefile.am b/Makefile.am index cb084e6..a9895f5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -64,6 +64,7 @@ GIT_RELEASE = $(shell date --utc +%Y%m%d%H%M%S)git$(git_head) RPMDIR = $$(rpm --eval '%{_rpmdir}') RPM_FLAGS = --define "ovirt_cache_dir $(OVIRT_CACHE_DIR)" RPM_FLAGS += $(if $(_ovirt_dev),--define "extra_release .$(GIT_RELEASE)") +SRC_KS = $(OVIRT_CACHE_DIR)/$(PACKAGE)-tmp/src.ks repos.ks: ( \ @@ -124,6 +125,58 @@ $(NVR).$(PKG_FMT).$(SUM): $(NVR).$(PKG_FMT) $(PACKAGE).$(PKG_FMT) node: $(NVR).$(PKG_FMT).$(SUM) +$(PACKAGE).source source: $(NVR).$(PKG_FMT).$(SUM).source + +$(NVR).$(PKG_FMT).$(SUM).source: $(NVR).$(PKG_FMT).source + +$(NVR).$(PKG_FMT).source: + @mkdir -p $(OVIRT_CACHE_DIR)/$(PACKAGE)-tmp/tree/pungi + @sudo rm -Rf $(OVIRT_CACHE_DIR)/$(PACKAGE)-tmp/tree/pungi/* + @( if [ -n "$(FEDORA_URL)" ]; then \ + echo "repo --name=f$(FEDORA) --baseurl=$(FEDORA_URL)/releases/$(FEDORA)/Everything/\$$basearch/os" ; \ + echo "repo --name=f$(FEDORA)-updates --baseurl=$(FEDORA_URL)/updates/$(FEDORA)/\$$basearch" ; \ + echo "repo --name=f$(FEDORA)-updates-newkey --baseurl=$(FEDORA_URL)/updates/$(FEDORA)/\$$basearch.newkey" ; \ + echo "repo --name=f$(FEDORA)-src --baseurl=$(FEDORA_URL)/releases/$(FEDORA)/Everything/source/SRPMS" ; \ + echo "repo --name=f$(FEDORA)-updates-src --baseurl=$(FEDORA_URL)/updates/$(FEDORA)/SRPMS" ; \ + echo "repo --name=f$(FEDORA)-updates-src-newkey --baseurl=$(FEDORA_URL)/updates/$(FEDORA)/SRPMS.newkey" ; \ + else \ + echo "repo --name=f$(FEDORA) --mirrorlist=$(FEDORA_MIRROR)?repo=fedora-$(FEDORA)&arch=\$$basearch" ; \ + echo "repo --name=f$(FEDORA)-updates --mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-f$(FEDORA)&arch=\$$basearch" ; \ + echo "repo --name=f$(FEDORA)-updates-newkey --mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-f$(FEDORA).newkey&arch=\$$basearch" ; \ + echo "repo --name=f$(FEDORA)-src --mirrorlist=$(FEDORA_MIRROR)?repo=fedora-source-$(FEDORA)&arch=src" ; \ + echo "repo --name=f$(FEDORA)-updates-src --mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-source-f$(FEDORA)&arch=src" ; \ + echo "repo --name=f$(FEDORA)-updates-src-newkey --mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-source-f$(FEDORA).newkey&arch=src" ; \ + fi ; \ + echo "repo --name=ovirt-org --baseurl=$(OVIRT_URL)/$(FEDORA)/\$$basearch" ; \ + echo "repo --name=ovirt-org-src --baseurl=$(OVIRT_URL)/$(FEDORA)/src" ; \ + echo "#repo --name=thincrust-net --baseurl=$(THINCRUST_URL)/noarch" ; \ + echo "#repo --name=thincrust-net-src --baseurl=$(THINCRUST_URL)/srpms" ; \ + echo "#repo --name=ovirt-local --baseurl=file://$(OVIRT_CACHE_DIR)/ovirt" ; \ + echo "%packages --nobase" ; \ + grep -v '^-' /usr/share/appliance-os/includes/base-pkgs.ks ; \ + echo "lokkit" ; \ + for dir in $(SUBDIRS); do \ + echo "ovirt-$$dir" ; \ + test -f $$dir/common-pkgs.ks && grep -v '^-' $$dir/common-pkgs.ks ; \ + done ; \ + echo "%end" ) > $(SRC_KS) + cd $(OVIRT_CACHE_DIR)/$(PACKAGE)-tmp/tree/pungi && \ + pungi -G --ver=$(PACKAGE) -c $(SRC_KS) --cachedir=$(OVIRT_CACHE_DIR)/yum + if [ "iso" == "iso" ]; then \ + cd $(OVIRT_CACHE_DIR)/$(PACKAGE)-tmp/tree/pungi && \ + sudo pungi --sourceiso --ver=$(PACKAGE) -c $(SRC_KS) --cachedir=$(OVIRT_CACHE_DIR)/yum ; \ + sudo mv $(OVIRT_CACHE_DIR)/$(PACKAGE)-tmp/tree/pungi/$(PACKAGE)/source/iso/Fedora-$(PACKAGE)-source.iso $(PWD)/$(PACKAGE)-source.iso ; \ + sudo sudo chown -R $(USER) $(PWD)/$(PACKAGE)-source.iso ; \ + else \ + cd $(OVIRT_CACHE_DIR)/$(PACKAGE)-tmp/tree/pungi/$(PACKAGE)/source && \ + tar cf ovirt-source.tar SRPMS ; \ + sudo mv $(OVIRT_CACHE_DIR)/$(PACKAGE)-tmp/tree/pungi/$(PACKAGE)/source/ovirt-source.tar $(PWD)/$(PACKAGE)-source.tar ; \ + sudo sudo chown -R $(USER) $(PWD)/$(PACKAGE)-source.tar ; \ + fi; + sudo sudo chown -R $(USER) $(OVIRT_CACHE_DIR)/$(PACKAGE)-tmp/tree/pungi + @rm -Rf $(OVIRT_CACHE_DIR)/$(PACKAGE)-tmp/tree/pungi + @rm $(SRC_KS) + rpms: dist node rpmbuild $(RPM_FLAGS) -ts $(distdir).tar.gz rpmbuild $(RPM_FLAGS) --define "source_iso 1" -tb $(distdir).tar.gz -- 1.5.5.1 From dhuff at redhat.com Mon Dec 8 17:44:40 2008 From: dhuff at redhat.com (David Huff) Date: Mon, 8 Dec 2008 12:44:40 -0500 Subject: [Ovirt-devel] [PATCH appliance] Added make source target to build source.iso In-Reply-To: <1228758281-12698-2-git-send-email-dhuff@redhat.com> References: <1228758281-12698-1-git-send-email-dhuff@redhat.com> <1228758281-12698-2-git-send-email-dhuff@redhat.com> Message-ID: <1228758281-12698-3-git-send-email-dhuff@redhat.com> Workaround which uses pungi to download srpms and create a srpm.iso Currently builds $(PWD)/$(PACKAGE)-source.iso however can also spit our .tar and can be easily configured to chose depending on $(PKG_FMT) --- Makefile.am | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 53 insertions(+), 0 deletions(-) diff --git a/Makefile.am b/Makefile.am index 52fe026..450ddc2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -57,6 +57,7 @@ GIT_RELEASE = $$(date --utc +%Y%m%d%H%M%S)git$(git_head) RPMDIR = $$(rpm --eval '%{_rpmdir}') RPM_FLAGS = --define "ovirt_cache_dir $(OVIRT_CACHE_DIR)" RPM_FLAGS += $(if $(_ovirt_dev),--define "extra_release .$(GIT_RELEASE)") +SRC_KS = $(OVIRT_CACHE_DIR)/$(PACKAGE)-tmp/src.ks FEDORA_MIRROR = http://mirrors.fedoraproject.org/mirrorlist FEDORA_URL_DEF = http://download.fedoraproject.org/pub/fedora/linux @@ -137,6 +138,58 @@ $(NVR).$(PKG_FMT).$(SUM): $(NVR).$(PKG_FMT) appliance: $(NVR).$(PKG_FMT).$(SUM) +$(PACKAGE).source source: $(NVR).$(PKG_FMT).$(SUM).source + +$(NVR).$(PKG_FMT).$(SUM).source: $(NVR).$(PKG_FMT).source + +$(NVR).$(PKG_FMT).source: + @mkdir -p $(OVIRT_CACHE_DIR)/$(PACKAGE)-tmp/tree/pungi + @sudo rm -Rf $(OVIRT_CACHE_DIR)/$(PACKAGE)-tmp/tree/pungi/* + @( if [ -n "$(FEDORA_URL)" ]; then \ + echo "repo --name=f$(FEDORA) --baseurl=$(FEDORA_URL)/releases/$(FEDORA)/Everything/\$$basearch/os" ; \ + echo "repo --name=f$(FEDORA)-updates --baseurl=$(FEDORA_URL)/updates/$(FEDORA)/\$$basearch" ; \ + echo "repo --name=f$(FEDORA)-updates-newkey --baseurl=$(FEDORA_URL)/updates/$(FEDORA)/\$$basearch.newkey" ; \ + echo "repo --name=f$(FEDORA)-src --baseurl=$(FEDORA_URL)/releases/$(FEDORA)/Everything/source/SRPMS" ; \ + echo "repo --name=f$(FEDORA)-updates-src --baseurl=$(FEDORA_URL)/updates/$(FEDORA)/SRPMS" ; \ + echo "repo --name=f$(FEDORA)-updates-src-newkey --baseurl=$(FEDORA_URL)/updates/$(FEDORA)/SRPMS.newkey" ; \ + else \ + echo "repo --name=f$(FEDORA) --mirrorlist=$(FEDORA_MIRROR)?repo=fedora-$(FEDORA)&arch=\$$basearch" ; \ + echo "repo --name=f$(FEDORA)-updates --mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-f$(FEDORA)&arch=\$$basearch" ; \ + echo "repo --name=f$(FEDORA)-updates-newkey --mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-f$(FEDORA).newkey&arch=\$$basearch" ; \ + echo "repo --name=f$(FEDORA)-src --mirrorlist=$(FEDORA_MIRROR)?repo=fedora-source-$(FEDORA)&arch=src" ; \ + echo "repo --name=f$(FEDORA)-updates-src --mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-source-f$(FEDORA)&arch=src" ; \ + echo "repo --name=f$(FEDORA)-updates-src-newkey --mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-source-f$(FEDORA).newkey&arch=src" ; \ + fi ; \ + echo "repo --name=ovirt-org --baseurl=$(OVIRT_URL)/$(FEDORA)/\$$basearch" ; \ + echo "repo --name=ovirt-org-src --baseurl=$(OVIRT_URL)/$(FEDORA)/src" ; \ + echo "#repo --name=thincrust-net --baseurl=$(THINCRUST_URL)/noarch" ; \ + echo "#repo --name=thincrust-net-src --baseurl=$(THINCRUST_URL)/srpms" ; \ + echo "#repo --name=ovirt-local --baseurl=file://$(OVIRT_CACHE_DIR)/ovirt" ; \ + echo "%packages --nobase" ; \ + grep -v '^-' /usr/share/appliance-os/includes/base-pkgs.ks ; \ + echo "lokkit" ; \ + for dir in $(SUBDIRS); do \ + echo "ovirt-$$dir" ; \ + test -f $$dir/common-pkgs.ks && grep -v '^-' $$dir/common-pkgs.ks ; \ + done ; \ + echo "%end" ) > $(SRC_KS) + cd $(OVIRT_CACHE_DIR)/$(PACKAGE)-tmp/tree/pungi && \ + pungi -G --ver=$(PACKAGE) -c $(SRC_KS) --cachedir=$(OVIRT_CACHE_DIR)/yum + if [ "iso" == "iso" ]; then \ + cd $(OVIRT_CACHE_DIR)/$(PACKAGE)-tmp/tree/pungi && \ + sudo pungi --sourceiso --ver=$(PACKAGE) -c $(SRC_KS) --cachedir=$(OVIRT_CACHE_DIR)/yum ; \ + sudo mv $(OVIRT_CACHE_DIR)/$(PACKAGE)-tmp/tree/pungi/$(PACKAGE)/source/iso/Fedora-$(PACKAGE)-source.iso $(PWD)/$(PACKAGE)-source.iso ; \ + sudo sudo chown -R $(USER) $(PWD)/$(PACKAGE)-source.iso ; \ + else \ + cd $(OVIRT_CACHE_DIR)/$(PACKAGE)-tmp/tree/pungi/$(PACKAGE)/source && \ + tar cf ovirt-source.tar SRPMS ; \ + sudo mv $(OVIRT_CACHE_DIR)/$(PACKAGE)-tmp/tree/pungi/$(PACKAGE)/source/ovirt-source.tar $(PWD)/$(PACKAGE)-source.tar ; \ + sudo sudo chown -R $(USER) $(PWD)/$(PACKAGE)-source.tar ; \ + fi; + sudo sudo chown -R $(USER) $(OVIRT_CACHE_DIR)/$(PACKAGE)-tmp/tree/pungi + @rm -Rf $(OVIRT_CACHE_DIR)/$(PACKAGE)-tmp/tree/pungi + @rm $(SRC_KS) + rpms: dist appliance rpmbuild $(RPM_FLAGS) -ta $(distdir).tar.gz -- 1.5.5.1 From dhuff at redhat.com Mon Dec 8 17:44:41 2008 From: dhuff at redhat.com (David Huff) Date: Mon, 8 Dec 2008 12:44:41 -0500 Subject: [Ovirt-devel] [PATCH ovirt-release] removed tar-src target form ovirt.mk In-Reply-To: <1228758281-12698-3-git-send-email-dhuff@redhat.com> References: <1228758281-12698-1-git-send-email-dhuff@redhat.com> <1228758281-12698-2-git-send-email-dhuff@redhat.com> <1228758281-12698-3-git-send-email-dhuff@redhat.com> Message-ID: <1228758281-12698-4-git-send-email-dhuff@redhat.com> --- ovirt.mk | 35 ----------------------------------- 1 files changed, 0 insertions(+), 35 deletions(-) diff --git a/ovirt.mk b/ovirt.mk index 42893c9..0cc6f1a 100644 --- a/ovirt.mk +++ b/ovirt.mk @@ -103,40 +103,5 @@ update-app: update-host sudo create-ovirt-iso-nodes sudo create-ovirt-nodes -tar-src: - @mkdir -p $(OVIRT_CACHE_DIR) - @sudo chown -R $(USER) $(OVIRT_CACHE_DIR) - @rm -Rf $(OVIRT_CACHE_DIR)/source - @( if [ -n "$(FEDORA_URL)" ]; then \ - echo "repo --name=f$(F_REL) --baseurl=$(FEDORA_URL)/releases/$(F_REL)/Everything/\$$basearch/os" ; \ - echo "repo --name=f$(F_REL)-updates --baseurl=$(FEDORA_URL)/updates/$(F_REL)/\$$basearch" ; \ - echo "repo --name=f$(F_REL)-updates-newkey --baseurl=$(FEDORA_URL)/updates/$(F_REL)/\$$basearch.newkey" ; \ - echo "repo --name=f$(F_REL)-src --baseurl=$(FEDORA_URL)/releases/$(F_REL)/Everything/source/SRPMS" ; \ - echo "repo --name=f$(F_REL)-updates-src --baseurl=$(FEDORA_URL)/updates/$(F_REL)/SRPMS" ; \ - echo "repo --name=f$(F_REL)-updates-src-newkey --baseurl=$(FEDORA_URL)/updates/$(F_REL)/SRPMS.newkey" ; \ - else \ - echo "repo --name=f$(F_REL) --mirrorlist=$(FEDORA_MIRROR)?repo=fedora-$(F_REL)&arch=\$$basearch" ; \ - echo "repo --name=f$(F_REL)-updates --mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-f$(F_REL)&arch=\$$basearch" ; \ - echo "repo --name=f$(F_REL)-updates-newkey --mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-f$(F_REL).newkey&arch=\$$basearch" ; \ - echo "repo --name=f$(F_REL)-src --mirrorlist=$(FEDORA_MIRROR)?repo=fedora-source-$(F_REL)&arch=src" ; \ - echo "repo --name=f$(F_REL)-updates-src --mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-source-f$(F_REL)&arch=src" ; \ - echo "repo --name=f$(F_REL)-updates-src-newkey --mirrorlist=$(FEDORA_MIRROR)?repo=updates-released-source-f$(F_REL).newkey&arch=src" ; \ - fi ; \ - echo "repo --name=ovirt-org --baseurl=$(OVIRT_URL)/${F_REL}/\$$basearch" ; \ - echo "repo --name=ovirt-org-src --baseurl=$(OVIRT_URL)/${F_REL}/src" ; \ - echo "repo --name=ovirt-local --baseurl=file://$(OVIRT_CACHE_DIR)/ovirt" ; \ - echo "%packages --nobase" ; \ - grep -v '^-' /usr/share/appliance-os/includes/base-pkgs.ks ; \ - echo "lokkit" ; \ - for dir in $(SUBDIRS); do \ - echo "ovirt-$$dir" ; \ - test -f $$dir/common-pkgs.ks && grep -v '^-' $$dir/common-pkgs.ks ; \ - done ; \ - echo "%end" ) > $(SRC_KS) - cd $(OVIRT_CACHE_DIR) && \ - $(BUILD_DIR)/release/misc-scripts/getsrpms.py $(SRC_KS) $(OVIRT_CACHE_DIR)/yum - cd $(OVIRT_CACHE_DIR)/source && \ - tar cf ovirt-source.tar SRPMS - .PHONY: all build clean distclean publish $(SUBDIRS) update \ tar-src update-host status diff branch show-branch -- 1.5.5.1 From jim at meyering.net Mon Dec 8 17:57:25 2008 From: jim at meyering.net (Jim Meyering) Date: Mon, 08 Dec 2008 18:57:25 +0100 Subject: [Ovirt-devel] [PATCH node] Allow the init scripts to handle ctrl-c well In-Reply-To: <1228749138-14904-1-git-send-email-bkearney@redhat.com> (Bryan Kearney's message of "Mon, 8 Dec 2008 10:12:18 -0500") References: <1228749138-14904-1-git-send-email-bkearney@redhat.com> Message-ID: <87d4g2v9bu.fsf@rho.meyering.net> Bryan Kearney wrote: > From: Bryan Kearney > > --- > scripts/ovirt-functions | 7 +++++++ > 1 files changed, 7 insertions(+), 0 deletions(-) > > diff --git a/scripts/ovirt-functions b/scripts/ovirt-functions > index c6a8504..f641ea0 100644 > --- a/scripts/ovirt-functions > +++ b/scripts/ovirt-functions > @@ -2,6 +2,13 @@ > > OVIRT_LOGFILE=/var/log/ovirt.log > > +# handle ctrl-c gracefully > +trap 'dropout' INT > + > +dropout() { > + exit 0 > +} Hi Bryan, What's the motivation for this addition? It would make it so interrupting any script that sources ovirt-functions would cause it to exit _successfully_. And if some other program examines the script's exit status (like Make or another shell script), then it will be misled into thinking that the interrupted script succeeded. Even changing it to exit nonzero would be misleading, since that would hide the fact that the script had been terminated by a signal (which is normally indicated via the exit status). From mmorsi at redhat.com Mon Dec 8 21:05:22 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Mon, 8 Dec 2008 16:05:22 -0500 Subject: [Ovirt-devel] [PATCH server] missing ovirt wui validations (round 1) Message-ID: <1228770322-18529-1-git-send-email-mmorsi@redhat.com> note this is a review only patch, as I haven't tested it yet (or even run it) so there will most likely be syntax and other errors Attached is additional validations, added to the rails model and controller layers verifying: bondings: arp related fields boot_types: label uniqueness and proto inclusion cpus: various fields are set and min values help_sections: presence and uniqueness of fields hosts: presence and format of various fields ip_addresses: fk existance / integrity nics: mac address format permissions: presence / inclusion of various fields pools: fields requied for tree present quotas: minimum values smart_pool_tags: tagged_id / type fk present storage_pools: type, state field inclusion, min values tasks: various fields present and consistensy maintained usages: label, other fields present, unique vms: uuid of correct format, min values, various fields present can only move host and storage to / from pools when you have sufficient permissions and target entities don't have associated vms can only destroy storage volumes / pools if there are no attached vms --- src/app/controllers/hardware_controller.rb | 36 ++++++++++++++++++++++++++++ src/app/controllers/storage_controller.rb | 8 ++++++ src/app/models/bonding.rb | 11 ++++++++ src/app/models/boot_type.rb | 5 ++++ src/app/models/cpu.rb | 23 +++++++++++++++++ src/app/models/help_section.rb | 34 ++++++++++++++++++++++++++ src/app/models/host.rb | 21 ++++++++++++++++ src/app/models/ip_address.rb | 4 +++ src/app/models/nic.rb | 11 ++++++++ src/app/models/permission.rb | 7 +++++ src/app/models/pool.rb | 7 +++++ src/app/models/quota.rb | 22 +++++++++++++++++ src/app/models/smart_pool_tag.rb | 5 ++++ src/app/models/storage_pool.rb | 9 +++++++ src/app/models/storage_volume.rb | 15 +++++++++++ src/app/models/task.rb | 16 ++++++++++++ src/app/models/usage.rb | 6 ++++ src/app/models/vm.rb | 30 ++++++++++++++++++++++- 18 files changed, 269 insertions(+), 1 deletions(-) diff --git a/src/app/controllers/hardware_controller.rb b/src/app/controllers/hardware_controller.rb index 4dda736..a329f90 100644 --- a/src/app/controllers/hardware_controller.rb +++ b/src/app/controllers/hardware_controller.rb @@ -285,6 +285,23 @@ class HardwareController < PoolController end def move_hosts + # if vm's present on host, fail + resource_ids_str = params[:resource_ids] + resource_ids_str.split(",").each {|x| + if Host.find(x).vms > 0 + render :json => { :success => false, + :alert => "Cannot move hosts currently associated w/ vms" } + return + end + } + + # if user doesn't have modify permission on both source and destination + unless @pool.can_modify(@user) and Pool.find(params[:target_pool_id]).can_modify(@user) + render :json => { :success => false, + :alert => "Cannot move hosts without admin permissions on both pools" } + return + end + edit_items(Host, :move_hosts, params[:target_pool_id], :move) end @@ -293,6 +310,25 @@ class HardwareController < PoolController end def move_storage + # if vm's present on host, fail + resource_ids_str = params[:resource_ids] + resource_ids_str.split(",").each {|x| + StoragePool.find(x).volumes.each { |v| + if v.vms.size > 0 + render :json => { :success => false, + :alert => "Cannot move storage currently associated w/ vms" } + return + end + } + } + + # if user doesn't have modify permission on both source and destination + unless @pool.can_modify(@user) and Pool.find(params[:target_pool_id]).can_modify(@user) + render :json => { :success => false, + :alert => "Cannot move storage without admin permissions on both pools" } + return + end + edit_items(StoragePool, :move_storage, params[:target_pool_id], :move) end diff --git a/src/app/controllers/storage_controller.rb b/src/app/controllers/storage_controller.rb index 148d1be..804ba75 100644 --- a/src/app/controllers/storage_controller.rb +++ b/src/app/controllers/storage_controller.rb @@ -310,6 +310,14 @@ class StorageController < ApplicationController end def destroy + @storage_pool.volumes.each { |volume| + if volume.vms.size > 0 + format.json { render :json => { :object => "storage_pool", + :success => false, :alert => "Cannot delete storage with associated vms" } } + return + end + } + pool = @storage_pool.hardware_pool if @storage_pool.destroy alert="Storage Pool was successfully deleted." diff --git a/src/app/models/bonding.rb b/src/app/models/bonding.rb index c9af38c..fabdb67 100644 --- a/src/app/models/bonding.rb +++ b/src/app/models/bonding.rb @@ -30,6 +30,8 @@ # interface. They can be ignored if not used. # class Bonding < ActiveRecord::Base + + belongs_to :host belongs_to :bonding_type belongs_to :vlan @@ -58,6 +60,15 @@ class Bonding < ActiveRecord::Base validates_presence_of :vlan_id, :message => 'A vlan must be specified.' + # verify arp ping address to be ipv4 if set + validates_format_of :arp_ping_address, + :with => %r{^(\d{1,3}\.){3}\d{1,3}$}, + :unless => Proc.new { |bonding| bonding.arp_ping_address.nil? } + + validates_numericality_of :arp_interval, + :greater_than_or_equal_to => 0, + :unless => Proc.new { |bonding| bonding.arp_interval.nil? } + protected def validate if vlan.boot_type.proto == 'static' and ip_addresses.size == 0 diff --git a/src/app/models/boot_type.rb b/src/app/models/boot_type.rb index 8ffbe67..1f30e8a 100644 --- a/src/app/models/boot_type.rb +++ b/src/app/models/boot_type.rb @@ -18,4 +18,9 @@ # also available at http://www.gnu.org/copyleft/gpl.html. class BootType < ActiveRecord::Base + validates_presence_of :label + validates_uniqueness_of :label, + :message => 'Label must be unique' + validates_inclusion_of :proto, + :in => %w ( static, dhcp, bootp ) end diff --git a/src/app/models/cpu.rb b/src/app/models/cpu.rb index 1a7d3cf..714a8ed 100644 --- a/src/app/models/cpu.rb +++ b/src/app/models/cpu.rb @@ -21,4 +21,27 @@ # class Cpu < ActiveRecord::Base belongs_to :host + + validates_presence_of :host_id, + :message => 'A host must be specified.' + + validates_numericality_of :cpu_number, + :greater_than_or_equal_to => 0 + + validates_numericality_of :core_number, + :greater_than_or_equal_to => 0 + + validates_numericality_of :number_of_cores, + :greater_than_or_equal_to => 1 + + validates_numericality_of :cpuid_level, + :greater_than_or_equal_to => 0 + + validates_numericality_of :speed, + :greater_than => 0 + # also verify speed in MHz ? + + validates_presence_of :vendor + validates_presence_of :model + validates_presence_of :family end diff --git a/src/app/models/help_section.rb b/src/app/models/help_section.rb index a891383..1de1e5a 100644 --- a/src/app/models/help_section.rb +++ b/src/app/models/help_section.rb @@ -1,2 +1,36 @@ +# Copyright (C) 2008 Red Hat, Inc. +# Written by Mohammed Morsi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. +# +# +HelpSection+ defines a section of the web help document to be +# available for a specific controller / action +# class HelpSection < ActiveRecord::Base + + validates_uniqueness_of :action, + :scope => :controller + :message => 'Controller / Action must be unique' + + validates_presence_of :controller, + :message => 'A controller must be specified.' + + validates_presence_of :action, + :message => 'An action must be specified.' + + validates_presence_of :section, + :message => 'A section must be specified.' end diff --git a/src/app/models/host.rb b/src/app/models/host.rb index 640782d..5328500 100644 --- a/src/app/models/host.rb +++ b/src/app/models/host.rb @@ -51,6 +51,27 @@ class Host < ActiveRecord::Base [ :search_users, 'U', "search_users" ] ], :eager_load => :smart_pools + validates_presence_of :hardware_pool_id, + :message => 'A hardware pool id must be specified.' + + validates_presence_of :uuid, + :message => 'A uuid must be specified.' + + validates_format_of :uuid, + :with => %r([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}) + + validates_presence_of :hostname, + :message => 'A hostname must be specified.' + + # validate hostname doesn't contain invalid chars? + + # validates presence, format, or inclusion of arch? + + validates_inclusion_of :hypervisor_type, + :in => HYPERVISOR_TYPES + + validates_inclusion_of :state, + :in => STATES + Task::COMPLETED_STATES + TASK::WORKING_STATES KVM_HYPERVISOR_TYPE = "KVM" HYPERVISOR_TYPES = [KVM_HYPERVISOR_TYPE] diff --git a/src/app/models/ip_address.rb b/src/app/models/ip_address.rb index 5d2e6af..3f246b1 100644 --- a/src/app/models/ip_address.rb +++ b/src/app/models/ip_address.rb @@ -24,4 +24,8 @@ class IpAddress < ActiveRecord::Base belongs_to :network belongs_to :nic belongs_to :bonding + + def validate + errors.add("id", "ip must be associated with foreign entity") if network_id.nil? and nic_id.nil? and bonding_id.nil? + end end diff --git a/src/app/models/nic.rb b/src/app/models/nic.rb index 5649763..c9f970d 100644 --- a/src/app/models/nic.rb +++ b/src/app/models/nic.rb @@ -24,12 +24,23 @@ class Nic < ActiveRecord::Base has_and_belongs_to_many :bondings, :join_table => 'bondings_nics' + validates_presence_of :mac, + :message => 'A mac must be specified.' + + validates_format_of :mac, + :with => %r{^([0-9a-f]{2}([:-]|$)){6}$} + validates_presence_of :host_id, :message => 'A host must be specified.' validates_presence_of :physical_network_id, :message => 'A network must be specified.' + validates_numericality_of :bandwidth, + :greater_than_or_equal_to => 0, + + # validate 'bridge' or 'usage_type' attribute ? + protected def validate if physical_network.boot_type.proto == 'static' and ip_addresses.size == 0 diff --git a/src/app/models/permission.rb b/src/app/models/permission.rb index ece3da5..b3929ad 100644 --- a/src/app/models/permission.rb +++ b/src/app/models/permission.rb @@ -24,9 +24,12 @@ class Permission < ActiveRecord::Base has_many :child_permissions, :dependent => :destroy, :class_name => "Permission", :foreign_key => "inherited_from_id" + validates_presence_of :pool_id + validates_presence_of :uid validates_uniqueness_of :uid, :scope => [:pool_id, :inherited_from_id] + ROLE_SUPER_ADMIN = "Super Admin" ROLE_ADMIN = "Administrator" ROLE_USER = "User" @@ -44,6 +47,10 @@ class Permission < ActiveRecord::Base ROLE_USER => [PRIV_VIEW, PRIV_VM_CONTROL], ROLE_MONITOR => [PRIV_VIEW]} + + validates_inclusion_of :user_role, + :in => ROLES.keys + def self.invert_roles return_hash = {} ROLES.each do |role, privs| diff --git a/src/app/models/pool.rb b/src/app/models/pool.rb index 7034e79..5cfc947 100644 --- a/src/app/models/pool.rb +++ b/src/app/models/pool.rb @@ -52,6 +52,13 @@ class Pool < ActiveRecord::Base validates_presence_of :name validates_uniqueness_of :name, :scope => :parent_id + validates_presence_of :parent_id + validates_presence_of :lft + validates_presence_of :rgt + + validates_inclusion_of :type, + :in => %w( DirectoryPool HardwarePool VmResourcePool SmartPool ) + # overloading this method such that we can use permissions.admins to get all the admins for an object has_many :permissions, :dependent => :destroy, :order => "id ASC" do def super_admins diff --git a/src/app/models/quota.rb b/src/app/models/quota.rb index fc52177..2a9e0f0 100644 --- a/src/app/models/quota.rb +++ b/src/app/models/quota.rb @@ -22,6 +22,28 @@ require 'util/ovirt' class Quota < ActiveRecord::Base belongs_to :pool + validates_presence_of :pool_id + + + validates_numericality_of :total_vcpus, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |quota| quota.total_vcpus.nil? } + + validates_numericality_of :total_vmemory, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |quota| quota.total_vmemory.nil? } + + validates_numericality_of :total_vnics, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |quota| quota.total_vnics.nil? } + + validates_numericality_of :total_storage, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |quota| quota.total_storage.nil? } + + validates_numericality_of :total_vms, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |quota| quota.total_vms.nil? } def total_vmemory_in_mb kb_to_mb(total_vmemory) diff --git a/src/app/models/smart_pool_tag.rb b/src/app/models/smart_pool_tag.rb index e135ddf..00bb5a7 100644 --- a/src/app/models/smart_pool_tag.rb +++ b/src/app/models/smart_pool_tag.rb @@ -31,6 +31,11 @@ class SmartPoolTag < ActiveRecord::Base validates_uniqueness_of :smart_pool_id, :scope => [:tagged_id, :tagged_type] + validates_presence_of :tagged_id + + validates_inclusion_of :tagged_type, + :in => %w( Pool StoragePool Host Vm ) + def tagged_type=(sType) super(sType.to_s.classify.constantize.base_class.to_s) end diff --git a/src/app/models/storage_pool.rb b/src/app/models/storage_pool.rb index bab7031..cffb52f 100644 --- a/src/app/models/storage_pool.rb +++ b/src/app/models/storage_pool.rb @@ -39,6 +39,15 @@ class StoragePool < ActiveRecord::Base validates_presence_of :hardware_pool_id + validates_inclusion_of :type, + :in => %w( IscsiStoragePool LvmStoragePool NfsStoragePool ) + + validates_inclustion_of :state, + :in => [ STATE_PENDING_SETUP, STATE_PENDING_DELETION, STATE_AVAILABLE] + + validates_numericality_of :capacity, + :greater_than_or_equal_to => 0 + acts_as_xapian :texts => [ :ip_addr, :target, :export_path, :type ], :terms => [ [ :search_users, 'U', "search_users" ] ], :eager_load => :smart_pools diff --git a/src/app/models/storage_volume.rb b/src/app/models/storage_volume.rb index 39b72d5..0c05378 100644 --- a/src/app/models/storage_volume.rb +++ b/src/app/models/storage_volume.rb @@ -32,6 +32,21 @@ class StorageVolume < ActiveRecord::Base end end + validates_presence_of :storage_pool_id + + validates_inclustion_of :state, + :in => [ STATE_PENDING_SETUP, STATE_PENDING_DELETION, STATE_AVAILABLE] + + validates_numericality_of :size, + :greater_than_or_equal_to => 0, + :unless => Proc.new { |storage_volume| storage_volume.nil? } + + validates_inclusion_of :type, + :in => %w( IscsiStorageVolume LvmStorageVolume NfsStorageVolume ) + + # FIXME need to validate lun, filename, lv_name, lv_owner_perms, + # lv_group_perms, lv_mode_perms (which depends on what subclasses?) + STATE_PENDING_SETUP = "pending_setup" STATE_PENDING_DELETION = "pending_deletion" STATE_AVAILABLE = "available" diff --git a/src/app/models/task.rb b/src/app/models/task.rb index f231c18..bf5fbbd 100644 --- a/src/app/models/task.rb +++ b/src/app/models/task.rb @@ -45,6 +45,16 @@ class Task < ActiveRecord::Base COMPLETED_STATES = [STATE_FINISHED, STATE_FAILED, STATE_CANCELED] WORKING_STATES = [STATE_QUEUED, STATE_RUNNING, STATE_PAUSED] + validates_inclusion_of :type, + :in => %w( HostTask StorageTask StorageVolumeTask VmTask ) + + validates_inclustion_of :state, + :in => COMPLETED_STATES + WORKING_STATES + + # FIXME validate action depending on type / subclass + # validate task_target_id, task_type_id, arg, message + # depending on subclass, action, state + def cancel self[:state] = STATE_CANCELED save! @@ -71,4 +81,10 @@ class Task < ActiveRecord::Base "" end + def validate + errors.add("id", "Parent must be specified") if hardware_pool_id.nil? and vm_resource_pool_id.nil? + errors.add("time_ended", "Tasks ends before its started") unless time_ended > time_started + errors.add("time_started", "Tasks starts before its created") unless time_started > time_created + end + end diff --git a/src/app/models/usage.rb b/src/app/models/usage.rb index 353e8f4..59b0e48 100644 --- a/src/app/models/usage.rb +++ b/src/app/models/usage.rb @@ -18,4 +18,10 @@ class Usage < ActiveRecord::Base has_and_belongs_to_many :networks, :join_table => 'networks_usages' + + validates_presence_of :label + validates_presence_of :usage + + validates_uniqueness_of :usage + end diff --git a/src/app/models/vm.rb b/src/app/models/vm.rb index 227f343..6038ac6 100644 --- a/src/app/models/vm.rb +++ b/src/app/models/vm.rb @@ -34,7 +34,35 @@ class Vm < ActiveRecord::Base validates_presence_of :uuid, :description, :num_vcpus_allocated, :boot_device, :memory_allocated_in_mb, - :memory_allocated, :vnic_mac_addr + :memory_allocated, :vnic_mac_addr, + :vm_resource_pool_id + + validates_format_of :uuid, + :with => %r([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}) + + validates_inclusion_of :state, + :in => RUNNING_STATES + DESTROYABLE_STATES + + validates_numericality_of :needs_restart, + :greater_than_or_equal_to => 0, + :less_than_or_equal_to => 1, + :unless => Proc.new{ |vm| vm.needs_restart.nil? } + + validates_numericality_of :memory_used, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |vm| vm.memory_used.nil? } + + validates_numericality_of :vnc_port, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |vm| vm.vnc_port.nil? } + + validates_numericality_of :num_vcpus_allocated, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |vm| vm.num_vcpus_allocated.nil? } + + validates_numericality_of :memory_allocated, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |vm| vm.memory_allocated.nil? } acts_as_xapian :texts => [ :uuid, :description, :vnic_mac_addr, :state ], :terms => [ [ :search_users, 'U', "search_users" ] ], -- 1.6.0.4 From pmyers at redhat.com Mon Dec 8 21:47:07 2008 From: pmyers at redhat.com (Perry Myers) Date: Mon, 08 Dec 2008 16:47:07 -0500 Subject: [Ovirt-devel] ovirt see only 1 node. how to add other servers ? In-Reply-To: <1228757099.11371.4.camel@dima-desktop> References: <1228317705.11195.2.camel@dima-desktop> <4936A549.5000203@redhat.com> <1228389599.7273.5.camel@dima-desktop> <1228479650.13032.7.camel@dima-desktop> <4939BE7C.80305@redhat.com> <1228757099.11371.4.camel@dima-desktop> Message-ID: <493D95DB.6090802@redhat.com> ?? wrote: > After destroy ovirt-appliance file system produce a lot of errors Did you shut down the appliance first using shutdown -h now from the appliance console or an ssh session before running virsh destroy? virsh destroy is equivalent to pulling the power plug out of a computer. Generally with ext3 filesystems that should not result in disk corruption, but it's always safer to shutdown the OS using virsh shutdown or using shutdown from within the guest. > I boot second real node from cobbler on ovirt-appliance but it is not > appear in list > second node have adress 192.168.50.254 - is this network for > administrative message or 192.168.1222/24 ? Not sure what you're asking here. Let me summarize what I understand of your situation. You have the ovirt-appliance running on a physical host. It is bridged to an external network (using create-ovirt-appliance -e ethX). You have a second physical machine on the same network as ethX from the above command. You PXE boot the second physical machine and see the oVirt Node boot on that machine, but you never see the node appear in the hosts tab on the oVirt web interface. Is my understanding correct? If so, can you please send me a tarball with all of the logs on the appliance in /var/log and also a tarball of all of the logs on the Node in /var/log. Thanks, Perry From tom at accident-prone.com Mon Dec 8 22:39:51 2008 From: tom at accident-prone.com (Tom Metge) Date: Mon, 8 Dec 2008 15:39:51 -0700 Subject: [Ovirt-devel] host node not seen Message-ID: <2850ACAC-652F-4BC4-90DA-6B099A5082D2@accident-prone.com> just deployed ovirt- well conceived and well implemented. nice work. one problem- i'm able to bring the virtual nodes online and add them as hosts in the web console. i've followed the wiki steps to make the host node a member (stateless), including shutting down, destroy, restart libvirtd, etc. sadly, it never appears. log snippet on host node (on which the appliance is running) says keytab was retrieved: [ovirt-host.log] Doing awake Connecting to 192.168.50.2:12120 Starting wakeup conversation. Retrieving keytab: 'http://management.priv.ovirt.org/ipa/config/192.168.50.1-libvirt.tab' Disconnecting. Doing identify Sending oVirt Node details to server. still, no luck. any ideas? thanks, tom From sburgess at redhat.com Tue Dec 9 01:03:35 2008 From: sburgess at redhat.com (Susan Burgess) Date: Tue, 09 Dec 2008 11:03:35 +1000 Subject: [Ovirt-devel] Doc patch - Please ACK Message-ID: <493DC3E7.1040004@redhat.com> -- Susan Burgess Content Author Red Hat APAC Level 1, 193 North Quay Brisbane, QLD 4000 Australia Phone +61 7 3514 8179 Fax +61 7 3514 8199 Mail sburgess at redhat.com -------------- next part -------------- A non-text attachment was scrubbed... Name: DIFF.tgz Type: application/x-compressed-tar Size: 8506 bytes Desc: not available URL: From sseago at redhat.com Tue Dec 9 06:13:29 2008 From: sseago at redhat.com (Scott Seago) Date: Tue, 09 Dec 2008 01:13:29 -0500 Subject: [Ovirt-devel] [PATCH server] missing ovirt wui validations (round 1) In-Reply-To: <1228770322-18529-1-git-send-email-mmorsi@redhat.com> References: <1228770322-18529-1-git-send-email-mmorsi@redhat.com> Message-ID: <493E0C89.7090402@redhat.com> Mohammed Morsi wrote: > note this is a review only patch, as I haven't tested it yet > (or even run it) so there will most likely be syntax and > other errors > > It looks good overall, but a few comments inline... > Attached is additional validations, added to the rails model > and controller layers verifying: > bondings: arp related fields > boot_types: label uniqueness and proto inclusion > cpus: various fields are set and min values > help_sections: presence and uniqueness of fields > hosts: presence and format of various fields > ip_addresses: fk existance / integrity > nics: mac address format > permissions: presence / inclusion of various fields > pools: fields requied for tree present > quotas: minimum values > smart_pool_tags: tagged_id / type fk present > storage_pools: type, state field inclusion, min values > tasks: various fields present and consistensy maintained > usages: label, other fields present, unique > vms: uuid of correct format, min values, various fields present > > can only move host and storage to / from pools when you have > sufficient permissions and target entities don't have associated > vms > > can only destroy storage volumes / pools if there are no attached vms > --- > > diff --git a/src/app/controllers/hardware_controller.rb b/src/app/controllers/hardware_controller.rb > index 4dda736..a329f90 100644 > --- a/src/app/controllers/hardware_controller.rb > +++ b/src/app/controllers/hardware_controller.rb > @@ -285,6 +285,23 @@ class HardwareController < PoolController > end > > def move_hosts > + # if vm's present on host, fail > + resource_ids_str = params[:resource_ids] > + resource_ids_str.split(",").each {|x| > + if Host.find(x).vms > 0 > + render :json => { :success => false, > + :alert => "Cannot move hosts currently associated w/ vms" } > + return > + end > + } > + > To be consistent with the other multi-object actions, it might be worthwhile to go ahead and move those VMs that don't ahve hosts and just report which ones weren't moved. For a first pass though it may be acceptable to abort the action if any in-use hosts are selected, but at the least the error msg should identify which hosts have VMs -- and identify all VMs which fail rather than just the first. > + # if user doesn't have modify permission on both source and destination > + unless @pool.can_modify(@user) and Pool.find(params[:target_pool_id]).can_modify(@user) > + render :json => { :success => false, > + :alert => "Cannot move hosts without admin permissions on both pools" } > + return > + end > + > edit_items(Host, :move_hosts, params[:target_pool_id], :move) > end > > @@ -293,6 +310,25 @@ class HardwareController < PoolController > end > > def move_storage > + # if vm's present on host, fail > + resource_ids_str = params[:resource_ids] > + resource_ids_str.split(",").each {|x| > + StoragePool.find(x).volumes.each { |v| > + if v.vms.size > 0 > + render :json => { :success => false, > + :alert => "Cannot move storage currently associated w/ vms" } > + return > + end > + } > + } > As with hosts, we should consider allowing partial success here, and whether or not we allow partial success we should report which storage pools caused the failure. > + > + # if user doesn't have modify permission on both source and destination > + unless @pool.can_modify(@user) and Pool.find(params[:target_pool_id]).can_modify(@user) > + render :json => { :success => false, > + :alert => "Cannot move storage without admin permissions on both pools" } > + return > + end > + > edit_items(StoragePool, :move_storage, params[:target_pool_id], :move) > end > Similar permissions/usage checks should be made for add_hosts and add_storage -- those are essentially the same action as move_hosts and move_storage, but the difference is the direction of moving. move_xxx moves hosts _from_ here _to_ there, and add_xxx moves hosts _from_ there _to_ here. To avoid having four very similar blocks of code, though, we should probablhy add the above checks to edit_items rather than the 4 actions that call it. In edit_items you've already got resource_ids_str/resource_ids available. The StoragePool/Host class you're calling 'find' on is passed in as item_class. The one difficulty here would be the "movable" check -- since it's different for hosts and storage pools. But this should probably be abstracted out anyway. You could add a "movable?" method to host.rb and storage_pool.rb that returned vms.empty? for host. For storage_pool the result is a bit more complex, since you've also got lvm to consider, but essentially storage_pool.movable? should call movable? for each storage volume and return false if any fail. storage_volume.movable? would have to check vms.empty? as well as whether it had an associated lvm pool -- in the latter case it would have to call movable? on the lvm pool. > > diff --git a/src/app/controllers/storage_controller.rb b/src/app/controllers/storage_controller.rb > index 148d1be..804ba75 100644 > --- a/src/app/controllers/storage_controller.rb > +++ b/src/app/controllers/storage_controller.rb > @@ -310,6 +310,14 @@ class StorageController < ApplicationController > end > > def destroy > + @storage_pool.volumes.each { |volume| > + if volume.vms.size > 0 > + format.json { render :json => { :object => "storage_pool", > + :success => false, :alert => "Cannot delete storage with associated vms" } } > + return > + end > + } > + > Similar issue here as with moving storage -- we need to consider LVM as well -- but the above approach will also help you here. > pool = @storage_pool.hardware_pool > if @storage_pool.destroy > alert="Storage Pool was successfully deleted." > > diff --git a/src/app/models/host.rb b/src/app/models/host.rb > index 640782d..5328500 100644 > --- a/src/app/models/host.rb > +++ b/src/app/models/host.rb > @@ -51,6 +51,27 @@ class Host < ActiveRecord::Base > [ :search_users, 'U', "search_users" ] ], > :eager_load => :smart_pools > > + validates_presence_of :hardware_pool_id, > + :message => 'A hardware pool id must be specified.' > + > + validates_presence_of :uuid, > + :message => 'A uuid must be specified.' > + > + validates_format_of :uuid, > + :with => %r([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}) > + > uuid format check above won't work for hosts, as we're currently using the hostname for Host uuids > + # validate hostname doesn't contain invalid chars? > + > + # validates presence, format, or inclusion of arch? > + > Yes we need these too. > + validates_inclusion_of :hypervisor_type, > + :in => HYPERVISOR_TYPES > + > + validates_inclusion_of :state, > + :in => STATES + Task::COMPLETED_STATES + TASK::WORKING_STATES > > KVM_HYPERVISOR_TYPE = "KVM" > HYPERVISOR_TYPES = [KVM_HYPERVISOR_TYPE] > diff --git a/src/app/models/pool.rb b/src/app/models/pool.rb > index 7034e79..5cfc947 100644 > --- a/src/app/models/pool.rb > +++ b/src/app/models/pool.rb > @@ -52,6 +52,13 @@ class Pool < ActiveRecord::Base > validates_presence_of :name > validates_uniqueness_of :name, :scope => :parent_id > > + validates_presence_of :parent_id > + validates_presence_of :lft > + validates_presence_of :rgt > + > + validates_inclusion_of :type, > + :in => %w( DirectoryPool HardwarePool VmResourcePool SmartPool ) > + > # overloading this method such that we can use permissions.admins to get all the admins for an object > has_many :permissions, :dependent => :destroy, :order => "id ASC" do > def super_admins > diff --git a/src/app/models/storage_volume.rb b/src/app/models/storage_volume.rb > index 39b72d5..0c05378 100644 > --- a/src/app/models/storage_volume.rb > +++ b/src/app/models/storage_volume.rb > @@ -32,6 +32,21 @@ class StorageVolume < ActiveRecord::Base > end > end > > + validates_presence_of :storage_pool_id > + > + validates_inclustion_of :state, > + :in => [ STATE_PENDING_SETUP, STATE_PENDING_DELETION, STATE_AVAILABLE] > + > + validates_numericality_of :size, > + :greater_than_or_equal_to => 0, > + :unless => Proc.new { |storage_volume| storage_volume.nil? } > + > + validates_inclusion_of :type, > + :in => %w( IscsiStorageVolume LvmStorageVolume NfsStorageVolume ) > + > + # FIXME need to validate lun, filename, lv_name, lv_owner_perms, > + # lv_group_perms, lv_mode_perms (which depends on what subclasses?) > + > Yes these should be validated in their respective subclasses: lun: iscsi filename: nfs lv_*: lvm > STATE_PENDING_SETUP = "pending_setup" > STATE_PENDING_DELETION = "pending_deletion" > STATE_AVAILABLE = "available" > diff --git a/src/app/models/task.rb b/src/app/models/task.rb > index f231c18..bf5fbbd 100644 > --- a/src/app/models/task.rb > +++ b/src/app/models/task.rb > @@ -45,6 +45,16 @@ class Task < ActiveRecord::Base > COMPLETED_STATES = [STATE_FINISHED, STATE_FAILED, STATE_CANCELED] > WORKING_STATES = [STATE_QUEUED, STATE_RUNNING, STATE_PAUSED] > > + validates_inclusion_of :type, > + :in => %w( HostTask StorageTask StorageVolumeTask VmTask ) > + > + validates_inclustion_of :state, > + :in => COMPLETED_STATES + WORKING_STATES > + > + # FIXME validate action depending on type / subclass > + # validate task_target_id, task_type_id, arg, message > + # depending on subclass, action, state > + > > def cancel > self[:state] = STATE_CANCELED > save! > @@ -71,4 +81,10 @@ class Task < ActiveRecord::Base > "" > end > > + def validate > + errors.add("id", "Parent must be specified") if hardware_pool_id.nil? and vm_resource_pool_id.nil? > hardware_pool_id and vm_resource_pool_id are specified in after_initialize, so we probably don't need to explicitly validate it. > + errors.add("time_ended", "Tasks ends before its started") unless time_ended > time_started > + errors.add("time_started", "Tasks starts before its created") unless time_started > time_created > + end > + > e > diff --git a/src/app/models/vm.rb b/src/app/models/vm.rb > index 227f343..6038ac6 100644 > --- a/src/app/models/vm.rb > +++ b/src/app/models/vm.rb > @@ -34,7 +34,35 @@ class Vm < ActiveRecord::Base > > validates_presence_of :uuid, :description, :num_vcpus_allocated, > :boot_device, :memory_allocated_in_mb, > - :memory_allocated, :vnic_mac_addr > + :memory_allocated, :vnic_mac_addr, > + :vm_resource_pool_id > + > + validates_format_of :uuid, > + :with => %r([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}) > + > + validates_inclusion_of :state, > + :in => RUNNING_STATES + DESTROYABLE_STATES > + > RUNNING + DESTROYABLE misses a couple states. The closest thing we have to a full state list is EFFECTIVE_STATE.keys, although that hash is missing STATE_INVALID. Try adding STATE_INVALID => STATE_INVALID to EFFECTIVE_STATES. > + validates_numericality_of :needs_restart, > + :greater_than_or_equal_to => 0, > + :less_than_or_equal_to => 1, > + :unless => Proc.new{ |vm| vm.needs_restart.nil? } > + > + validates_numericality_of :memory_used, > + :greater_than_or_equal_to => 0, > + :unless => Proc.new{ |vm| vm.memory_used.nil? } > + > + validates_numericality_of :vnc_port, > + :greater_than_or_equal_to => 0, > + :unless => Proc.new{ |vm| vm.vnc_port.nil? } > + > + validates_numericality_of :num_vcpus_allocated, > + :greater_than_or_equal_to => 0, > + :unless => Proc.new{ |vm| vm.num_vcpus_allocated.nil? } > + > + validates_numericality_of :memory_allocated, > + :greater_than_or_equal_to => 0, > + :unless => Proc.new{ |vm| vm.memory_allocated.nil? } > > acts_as_xapian :texts => [ :uuid, :description, :vnic_mac_addr, :state ], > :terms => [ [ :search_users, 'U', "search_users" ] ], > Scott From d.vasilets at peterhost.ru Tue Dec 9 10:36:57 2008 From: d.vasilets at peterhost.ru (=?koi8-r?Q?=F7=C1=D3=C9=CC=C5=C3_?= =?koi8-r?Q?=E4=CD=C9=D4=D2=C9=CA?=) Date: Tue, 09 Dec 2008 13:36:57 +0300 Subject: [Ovirt-devel] ovirt see only 1 node. how to add other servers ? In-Reply-To: <493D95DB.6090802@redhat.com> References: <1228317705.11195.2.camel@dima-desktop> <4936A549.5000203@redhat.com> <1228389599.7273.5.camel@dima-desktop> <1228479650.13032.7.camel@dima-desktop> <4939BE7C.80305@redhat.com> <1228757099.11371.4.camel@dima-desktop> <493D95DB.6090802@redhat.com> Message-ID: <1228819017.559.7.camel@dima-desktop> Sorry for my English. You understand everything correctly Yes , shutdown -h now ovirt-appliance and after few minuts virsh destroy I try fsck in singlemode and set in fstab check file system but many services(such as postgresql and dirmng start with errors or not start) ? ???, 08/12/2008 ? 16:47 -0500, Perry Myers ?????: > ?? wrote: > > After destroy ovirt-appliance file system produce a lot of errors > > Did you shut down the appliance first using shutdown -h now from the > appliance console or an ssh session before running virsh destroy? virsh > destroy is equivalent to pulling the power plug out of a computer. > Generally with ext3 filesystems that should not result in disk corruption, > but it's always safer to shutdown the OS using virsh shutdown or using > shutdown from within the guest. > > > I boot second real node from cobbler on ovirt-appliance but it is not > > appear in list > > second node have adress 192.168.50.254 - is this network for > > administrative message or 192.168.1222/24 ? > > Not sure what you're asking here. > > Let me summarize what I understand of your situation. > > You have the ovirt-appliance running on a physical host. It is bridged to > an external network (using create-ovirt-appliance -e ethX). > > You have a second physical machine on the same network as ethX from the > above command. > > You PXE boot the second physical machine and see the oVirt Node boot on > that machine, but you never see the node appear in the hosts tab on the > oVirt web interface. > > Is my understanding correct? > > If so, can you please send me a tarball with all of the logs on the > appliance in /var/log and also a tarball of all of the logs on the Node in > /var/log. > > Thanks, > > Perry > -------------- next part -------------- A non-text attachment was scrubbed... Name: appliance.varlog.tgz Type: application/x-compressed-tar Size: 129426 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: node2.varlog.tgz Type: application/x-compressed-tar Size: 11988 bytes Desc: not available URL: From bkearney at redhat.com Tue Dec 9 12:48:22 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Tue, 09 Dec 2008 07:48:22 -0500 Subject: [Ovirt-devel] [PATCH node] Allow the init scripts to handle ctrl-c well In-Reply-To: <87d4g2v9bu.fsf@rho.meyering.net> References: <1228749138-14904-1-git-send-email-bkearney@redhat.com> <87d4g2v9bu.fsf@rho.meyering.net> Message-ID: <493E6916.3070704@redhat.com> Jim Meyering wrote: > Bryan Kearney wrote: >> From: Bryan Kearney >> >> --- >> scripts/ovirt-functions | 7 +++++++ >> 1 files changed, 7 insertions(+), 0 deletions(-) >> >> diff --git a/scripts/ovirt-functions b/scripts/ovirt-functions >> index c6a8504..f641ea0 100644 >> --- a/scripts/ovirt-functions >> +++ b/scripts/ovirt-functions >> @@ -2,6 +2,13 @@ >> >> OVIRT_LOGFILE=/var/log/ovirt.log >> >> +# handle ctrl-c gracefully >> +trap 'dropout' INT >> + >> +dropout() { >> + exit 0 >> +} > > Hi Bryan, > > What's the motivation for this addition? > It would make it so interrupting any script that sources > ovirt-functions would cause it to exit _successfully_. > And if some other program examines the script's exit status > (like Make or another shell script), then it will be misled > into thinking that the interrupted script succeeded. > > Even changing it to exit nonzero would be misleading, since > that would hide the fact that the script had been terminated > by a signal (which is normally indicated via the exit status). The goal was to allow a user to ctrl-c out of the standalone node scripts and get back to the main menu. We were not able to get the scripts to recognize INTR in the init process so I believe Darryl decided to abandondon this. -- bk From pmyers at redhat.com Tue Dec 9 14:47:38 2008 From: pmyers at redhat.com (Perry Myers) Date: Tue, 09 Dec 2008 09:47:38 -0500 Subject: [Ovirt-devel] Re: ovirt In-Reply-To: References: Message-ID: <493E850A.109@redhat.com> Hadi Al-Saadi wrote: > > *Dear perry,* > > as i told you we installed fedora 9 and kvm and ovirt successful. > our next step is to run ovirt. to mange the guest O/S. so we decide to > run ovirt node in the localhost itself . and we done this commands for > running ovirt node > > 1- create-ovirt-appliance > 2-ovirt-install-node stateful > > every thing executed fine with no problems. > the issue we are facing when we trying to login to ovirt node from the > browser to mange the guest OS. we observe that the ovirt node which is > running in the host OS is not running prefect. while boot ovirt node its > stick in the middle we can see throw vncviwer. > I'm attaching ovirt node error pls look at it and get back to us at the > earlier . Are you running the i386 appliance version .95? If so there was a known issue with that appliance that will be corrected in .96. If you don't want to wait for .96 you can use a workaround submitted by someone in the community who found this problem. (See below link) Basically the i386 appliance had a bad initrd and this process fixes the initrd on an existing appliance. You can also try to build the appliance from scratch from the repositories if you don't want to follow this procedure. Also, after you try this procedure if you do run into additional problems use the following wiki page for gathering pertinent info about the problem: http://ovirt.org/page/TroubleShooting Thanks, Perry From mcpierce at gmail.com Mon Dec 8 21:06:52 2008 From: mcpierce at gmail.com (Darryl Pierce) Date: Mon, 8 Dec 2008 16:06:52 -0500 Subject: [Ovirt-devel] git-refresh utility Message-ID: <329b60cf0812081306l24cad0c9sdb1b911786984fa8@mail.gmail.com> This is a script I use for work and wanted to share. If you put this script into your path, then you can use the command: git refresh to checkout "master", refresh it from origin, then checkout your working branch again. You can specify an alternate to "master" using the -r argument and supplying a different branch name (such as "next" or "devel"). And you can also name a set of directories to be processed, otherwise the script processes the current directory only. For myself, I use the command: git refresh -r next `ls -b` from the parent directory for oVirt to refresh everything. If you have any mods or updates, send them over. :) -- Darryl L. Pierce Visit the Infobahn Offramp: "Bury me next to my wife. Nothing too fancy..." - Ulysses S. Grant -------------- next part -------------- A non-text attachment was scrubbed... Name: git-refresh Type: application/octet-stream Size: 2053 bytes Desc: not available URL: From jboggs at redhat.com Tue Dec 9 22:12:06 2008 From: jboggs at redhat.com (Joey Boggs) Date: Tue, 09 Dec 2008 17:12:06 -0500 Subject: [Ovirt-devel] ovirt installation test scenarios In-Reply-To: <493D4671.3090003@redhat.com> References: <4939B473.7050701@redhat.com> <493D4671.3090003@redhat.com> Message-ID: <493EED36.3060304@redhat.com> Michael DeHaan wrote: > Joey Boggs wrote: >> Since the options are limited right with what can be >> external(postgres/freeipa) here's a list so far of different oVirt >> installation scenarios that should to be tested >> >> external dns + internal cobbler + external dhcp + internal pxe >> external dns + internal cobbler + internal dhcp + internal pxe >> external dns + external cobbler + external dhcp + external pxe >> external dns + external cobbler + internal dhcp + external pxe >> internal dns + internal cobbler + external dhcp + internal pxe >> internal dns + internal cobbler + internal dhcp + internal pxe >> >> Can't reproduce these below just yet due to dnsmasq config, currently >> does both dhcp and dns by default bundled config >> internal dns + external cobbler + external dhcp + external pxe >> internal dns + external cobbler + internal dhcp + external pxe >> >> There may be some issues in producing these scenarios if so please >> let me know and we can build/correct a solution. >> > > The cobbler server should be the PXE server, and that should help > simplify things, no? > > All the admin would have to do is set the next-server for the subnet > to point at the cobbler box if he happened to have another PXE > environment. You could just document this step. > > Somewhat unrelated, is Ovirt doing any DHCP management? Cobbler has > a built in feature for this that would probably be useful. DNS also > -- and it does support dnsmasq in addition to the BIND stuff. This > allows you to pin certain mac addresses to certain ip's and hostnames, > just by creating cobbler system records with that information filled in. > > --Michael > Currently oVirt can use any dhcp app to provide dhcp there is no management function. The appliance version uses dnsmasq based on install time basic configuration as will the first cut of the bare metal installer. We can use any dns server the only requirement for installation is forward/reverse lookup for the FreeIPA portion. We already provide some cobbler integration for the profiles, what would it take to integrate dns/dhcp into the ovirt console? >> >> _______________________________________________ >> Ovirt-devel mailing list >> Ovirt-devel at redhat.com >> https://www.redhat.com/mailman/listinfo/ovirt-devel > From mdehaan at redhat.com Tue Dec 9 22:20:10 2008 From: mdehaan at redhat.com (Michael DeHaan) Date: Tue, 09 Dec 2008 17:20:10 -0500 Subject: [Ovirt-devel] ovirt installation test scenarios In-Reply-To: <493EED36.3060304@redhat.com> References: <4939B473.7050701@redhat.com> <493D4671.3090003@redhat.com> <493EED36.3060304@redhat.com> Message-ID: <493EEF1A.7060400@redhat.com> Joey Boggs wrote: > Michael DeHaan wrote: >> Joey Boggs wrote: >>> Since the options are limited right with what can be >>> external(postgres/freeipa) here's a list so far of different oVirt >>> installation scenarios that should to be tested >>> >>> external dns + internal cobbler + external dhcp + internal pxe >>> external dns + internal cobbler + internal dhcp + internal pxe >>> external dns + external cobbler + external dhcp + external pxe >>> external dns + external cobbler + internal dhcp + external pxe >>> internal dns + internal cobbler + external dhcp + internal pxe >>> internal dns + internal cobbler + internal dhcp + internal pxe >>> >>> Can't reproduce these below just yet due to dnsmasq config, >>> currently does both dhcp and dns by default bundled config >>> internal dns + external cobbler + external dhcp + external pxe >>> internal dns + external cobbler + internal dhcp + external pxe >>> >>> There may be some issues in producing these scenarios if so please >>> let me know and we can build/correct a solution. >>> >> >> The cobbler server should be the PXE server, and that should help >> simplify things, no? >> >> All the admin would have to do is set the next-server for the subnet >> to point at the cobbler box if he happened to have another PXE >> environment. You could just document this step. >> >> Somewhat unrelated, is Ovirt doing any DHCP management? Cobbler has >> a built in feature for this that would probably be useful. DNS also >> -- and it does support dnsmasq in addition to the BIND stuff. This >> allows you to pin certain mac addresses to certain ip's and >> hostnames, just by creating cobbler system records with that >> information filled in. >> >> --Michael >> > Currently oVirt can use any dhcp app to provide dhcp there is no > management function. The appliance version uses dnsmasq based on > install time basic configuration as will the first cut of the bare > metal installer. We can use any dns server the only requirement for > installation is forward/reverse lookup for the FreeIPA portion. We > already provide some cobbler integration for the profiles, what would > it take to integrate dns/dhcp into the ovirt console? > > > > >>> >>> _______________________________________________ >>> Ovirt-devel mailing list >>> Ovirt-devel at redhat.com >>> https://www.redhat.com/mailman/listinfo/ovirt-devel >> > Possibly, if you want to do things like DHCP reservations (MAC->IP) or assign DNS hostnames it makes good sense. Ultimately I think ovirt centralizing on Cobbler where there are things Cobbler can help with -- that way we can not only get more eyes on Cobbler upstream, but we can also make sure we aren't duplicating effort. Naturally you can use any DHCP, there isn't much to do other than set the next server, but it would be a nice option ... the API's to do are pretty simple. Just edit /etc/cobbler/dhcp.template and create system records with the mac/ip info, BIND management (and dnsmasq, at the user's option) work similarly. Slight changes have to be made when dealing with multiple networks, which Cobbler can also account for. These are all things the user doesn't have to set up initially but if you create system records in the right way, the API consumer (ovirt) can take advantage of these features for free without having to know that cobbler is managing those services. I do recommend disabling omapi if you're not testing with the devel branch code -- it works much better if the configuration file is generated and we just "cobbler sync" when we want to apply changes. --Michael From imain at redhat.com Tue Dec 9 23:34:56 2008 From: imain at redhat.com (Ian Main) Date: Tue, 9 Dec 2008 15:34:56 -0800 Subject: [Ovirt-devel] Re: qpid errors In-Reply-To: <493D2DDB.2050203@redhat.com> References: <4938910C.1000504@redhat.com> <4938938D.90706@redhat.com> <493D2DDB.2050203@redhat.com> Message-ID: <20081209153456.08190be0@tp.mains.net> On Mon, 08 Dec 2008 09:23:23 -0500 Perry Myers wrote: > Ian, > > Just checking status on some of the open issues that I had... > > Perry Myers wrote: > > Perry Myers wrote: > >> You don't need to fix this tonight ;) > >> > >> But I figured I would just list the issues so that we tracked them > >> somewhere. > >> > >> 1. fix race condition where it's possible that the broker gets the > >> Node object before the db entry is created via ovirt-awake. This can > >> be fixed by having a hashtable of nodes and for each node a dirty > >> flag. If db-omatic goes to update the state in the db and can't it > >> flags the node as dirty. On the next heartbeat if the flag is dirty > >> for a particular node it tries to update the db again. The dirty flag > >> isn't removed until the update succeeds. This should only be a > >> temporary hack until we get ovirt-awake using qmf. > > This one you said is fixed correct? Yes, fixed. > >> 2. fix objects to be persistent so that restarts of the broker do not > >> lose state > > This was a non-issue, correct? Kind of.. the issue was that db-omatic was not reconnecting to qpidd when you kill it. Ted Ross added support to this to the ruby client today. Will have a new package soon that addresses this. > >> 3. get one of the ui guys to fix the MHz display so that the value > >> there shows up correctly > > sseago did this > > >> 4. figure out why libvirt and hypervisor version are showing up as > >> unknown > > We need newer libvirt according to danpb (0.5.1) > > >> 5. db-omatic is not logging properly > > You fixed this > > >> 6. rsyslog is not working on node startup... you have top manually > >> restart the rsyslog daemon after the node has booted to get a > >> /var/log/messages file > >> > >> I'll take a look at #6, the rest are qpid related so they're yours... > > I still need to figure this one out > > > Oh adding to the list > > > > 7. Get MRG to repackage their RPMs so that doxygen stuff is built during > > RPM build and not as part of the source tarball and also get them to use > > something other than 24 bit color for their png files. And put their > > docs into a docs rpm so that the devel rpm is not bloated. > > Have you talked to the MRG guys about this? I have.. I talked to them the day they released it but I will keep bugging them. I'm guessing it's going to be a bit before they repackage. Ian From imain at redhat.com Tue Dec 9 23:44:07 2008 From: imain at redhat.com (Ian Main) Date: Tue, 9 Dec 2008 15:44:07 -0800 Subject: [Ovirt-devel] host node not seen In-Reply-To: <2850ACAC-652F-4BC4-90DA-6B099A5082D2@accident-prone.com> References: <2850ACAC-652F-4BC4-90DA-6B099A5082D2@accident-prone.com> Message-ID: <20081209154407.028beb70@tp.mains.net> On Mon, 8 Dec 2008 15:39:51 -0700 Tom Metge wrote: > just deployed ovirt- well conceived and well implemented. nice work. > > one problem- i'm able to bring the virtual nodes online and add them > as hosts in the web console. i've followed the wiki steps to make the > host node a member (stateless), including shutting down, destroy, > restart libvirtd, etc. sadly, it never appears. log snippet on host > node (on which the appliance is running) says keytab was retrieved: Hrrm, are you running on i386 by chance? There was an issue where libvirt-qpid was not recompiled for i386 on f10 and wasn't starting on the nodes. If you do a new build it should pick that up. Otherwise, if x86_64, I'm not sure what the issue is but there is one report on irc of it not working. I'm going to be testing it right now. > [ovirt-host.log] > Doing awake > Connecting to 192.168.50.2:12120 > Starting wakeup conversation. > Retrieving keytab: 'http://management.priv.ovirt.org/ipa/config/192.168.50.1-libvirt.tab' > Disconnecting. > Doing identify > Sending oVirt Node details to server. > > still, no luck. any ideas? Yeah, the awake only creates the database entry. libvirt-qpid on the node communicates with db-omatic on the appliance to update the state of the nodes and VMs. Ian From mmorsi at redhat.com Tue Dec 9 16:00:10 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Tue, 9 Dec 2008 11:00:10 -0500 Subject: [Ovirt-devel] [PATCH server] missing ovirt wui validations Message-ID: <1228838410-7846-1-git-send-email-mmorsi@redhat.com> this patch is now syntactically correct and will run when invoking db:migrate or when running the tests. several tests now fail though and need to be debugged / possibly changed Attached is additional validations, added to the rails model and controller layers verifying: bondings: arp related fields boot_types: label uniqueness and proto inclusion cpus: various fields are set and min values help_sections: presence and uniqueness of fields hosts: presence and format of various fields ip_addresses: fk existance / integrity nics: mac address format permissions: presence / inclusion of various fields pools: fields requied for tree present quotas: minimum values smart_pool_tags: tagged_id / type fk present storage_pools: type, state field inclusion, min values storage_volumes: various fields, subclasses w/ various fields tasks: various fields present and consistensy maintained usages: label, other fields present, unique vms: uuid of correct format, min values, various fields present can only add / move host and storage volumes and pools to / from pools when you have sufficient permissions and target entities don't have associated vms can only destroy storage volumes / pools if there are no attached vms --- src/app/controllers/hardware_controller.rb | 28 +++++++++++++++++++++- src/app/controllers/storage_controller.rb | 7 +++++ src/app/models/bonding.rb | 11 +++++++++ src/app/models/boot_type.rb | 5 ++++ src/app/models/cpu.rb | 23 +++++++++++++++++++ src/app/models/help_section.rb | 34 ++++++++++++++++++++++++++++ src/app/models/host.rb | 21 +++++++++++++++++ src/app/models/ip_address.rb | 4 +++ src/app/models/iscsi_storage_volume.rb | 2 + src/app/models/lvm_storage_volume.rb | 6 +++++ src/app/models/nfs_storage_pool.rb | 3 ++ src/app/models/nic.rb | 11 +++++++++ src/app/models/permission.rb | 7 +++++ src/app/models/pool.rb | 7 +++++ src/app/models/quota.rb | 22 ++++++++++++++++++ src/app/models/smart_pool_tag.rb | 5 ++++ src/app/models/storage_pool.rb | 17 ++++++++++++++ src/app/models/storage_volume.rb | 21 +++++++++++++++++ src/app/models/task.rb | 15 ++++++++++++ src/app/models/usage.rb | 6 +++++ src/app/models/vm.rb | 34 ++++++++++++++++++++++++++- 21 files changed, 285 insertions(+), 4 deletions(-) diff --git a/src/app/controllers/hardware_controller.rb b/src/app/controllers/hardware_controller.rb index 4dda736..cf45c49 100644 --- a/src/app/controllers/hardware_controller.rb +++ b/src/app/controllers/hardware_controller.rb @@ -303,15 +303,39 @@ class HardwareController < PoolController resource_ids_str = params[:resource_ids] resource_ids = resource_ids_str.split(",").collect {|x| x.to_i} + # if user doesn't have modify permission on both source and destination + unless @pool.can_modify(@user) and Pool.find(params[:target_pool_id]).can_modify(@user) + render :json => { :success => false, + :alert => "Cannot #{item_action.to_s} #{item_class.table_name.humanize} without admin permissions on both pools" } + return + end + + # relay error message if movable check fails for any resource + success = true + failed_resources = "" + resource_ids.each {|x| + unless item_class.find(x).movable? + success = false + failed_resources += x.to_s + " " + end + } + resource_ids.delete_if { |x| ! item_class.find(x).movable? } + begin @pool.transaction do @pool.send(item_method, resource_ids, target_pool_id) end + rescue + success = false + end + + if success render :json => { :success => true, :alert => "#{item_action.to_s} #{item_class.table_name.humanize} successful." } - rescue + else render :json => { :success => false, - :alert => "#{item_action.to_s} #{item_class.table_name.humanize} failed." } + :alert => "#{item_action.to_s} #{item_class.table_name.humanize} failed" + + (failed_resources == "" ? "." : " for " + failed_resources) } end end diff --git a/src/app/controllers/storage_controller.rb b/src/app/controllers/storage_controller.rb index 148d1be..47e9e14 100644 --- a/src/app/controllers/storage_controller.rb +++ b/src/app/controllers/storage_controller.rb @@ -310,6 +310,13 @@ class StorageController < ApplicationController end def destroy + unless @storage_pool.movable? + format.json { render :json => { :object => "storage_pool", + :success => false, + :alert => "Cannot delete storage with associated vms" } } + return + end + pool = @storage_pool.hardware_pool if @storage_pool.destroy alert="Storage Pool was successfully deleted." diff --git a/src/app/models/bonding.rb b/src/app/models/bonding.rb index c9af38c..fabdb67 100644 --- a/src/app/models/bonding.rb +++ b/src/app/models/bonding.rb @@ -30,6 +30,8 @@ # interface. They can be ignored if not used. # class Bonding < ActiveRecord::Base + + belongs_to :host belongs_to :bonding_type belongs_to :vlan @@ -58,6 +60,15 @@ class Bonding < ActiveRecord::Base validates_presence_of :vlan_id, :message => 'A vlan must be specified.' + # verify arp ping address to be ipv4 if set + validates_format_of :arp_ping_address, + :with => %r{^(\d{1,3}\.){3}\d{1,3}$}, + :unless => Proc.new { |bonding| bonding.arp_ping_address.nil? } + + validates_numericality_of :arp_interval, + :greater_than_or_equal_to => 0, + :unless => Proc.new { |bonding| bonding.arp_interval.nil? } + protected def validate if vlan.boot_type.proto == 'static' and ip_addresses.size == 0 diff --git a/src/app/models/boot_type.rb b/src/app/models/boot_type.rb index 8ffbe67..6cfdb04 100644 --- a/src/app/models/boot_type.rb +++ b/src/app/models/boot_type.rb @@ -18,4 +18,9 @@ # also available at http://www.gnu.org/copyleft/gpl.html. class BootType < ActiveRecord::Base + validates_presence_of :label + validates_uniqueness_of :label, + :message => 'Label must be unique' + validates_inclusion_of :proto, + :in => %w( static dhcp bootp ) end diff --git a/src/app/models/cpu.rb b/src/app/models/cpu.rb index 1a7d3cf..714a8ed 100644 --- a/src/app/models/cpu.rb +++ b/src/app/models/cpu.rb @@ -21,4 +21,27 @@ # class Cpu < ActiveRecord::Base belongs_to :host + + validates_presence_of :host_id, + :message => 'A host must be specified.' + + validates_numericality_of :cpu_number, + :greater_than_or_equal_to => 0 + + validates_numericality_of :core_number, + :greater_than_or_equal_to => 0 + + validates_numericality_of :number_of_cores, + :greater_than_or_equal_to => 1 + + validates_numericality_of :cpuid_level, + :greater_than_or_equal_to => 0 + + validates_numericality_of :speed, + :greater_than => 0 + # also verify speed in MHz ? + + validates_presence_of :vendor + validates_presence_of :model + validates_presence_of :family end diff --git a/src/app/models/help_section.rb b/src/app/models/help_section.rb index a891383..1de1e5a 100644 --- a/src/app/models/help_section.rb +++ b/src/app/models/help_section.rb @@ -1,2 +1,36 @@ +# Copyright (C) 2008 Red Hat, Inc. +# Written by Mohammed Morsi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. +# +# +HelpSection+ defines a section of the web help document to be +# available for a specific controller / action +# class HelpSection < ActiveRecord::Base + + validates_uniqueness_of :action, + :scope => :controller + :message => 'Controller / Action must be unique' + + validates_presence_of :controller, + :message => 'A controller must be specified.' + + validates_presence_of :action, + :message => 'An action must be specified.' + + validates_presence_of :section, + :message => 'A section must be specified.' end diff --git a/src/app/models/host.rb b/src/app/models/host.rb index 640782d..ef495ff 100644 --- a/src/app/models/host.rb +++ b/src/app/models/host.rb @@ -51,6 +51,17 @@ class Host < ActiveRecord::Base [ :search_users, 'U', "search_users" ] ], :eager_load => :smart_pools + validates_presence_of :hardware_pool_id, + :message => 'A hardware pool id must be specified.' + + validates_presence_of :uuid, + :message => 'A uuid must be specified.' + + validates_presence_of :hostname, + :message => 'A hostname must be specified.' + + validates_presence_of :arch, + :message => 'An arch must be specified.' KVM_HYPERVISOR_TYPE = "KVM" HYPERVISOR_TYPES = [KVM_HYPERVISOR_TYPE] @@ -58,6 +69,12 @@ class Host < ActiveRecord::Base STATE_AVAILABLE = "available" STATES = [STATE_UNAVAILABLE, STATE_AVAILABLE] + validates_inclusion_of :hypervisor_type, + :in => HYPERVISOR_TYPES + + validates_inclusion_of :state, + :in => STATES + Task::COMPLETED_STATES + TASK::WORKING_STATES + def memory_in_mb kb_to_mb(memory) end @@ -99,4 +116,8 @@ class Host < ActiveRecord::Base hardware_pool.search_users end + def movable? + return vms.size == 0 + end + end diff --git a/src/app/models/ip_address.rb b/src/app/models/ip_address.rb index 5d2e6af..3f246b1 100644 --- a/src/app/models/ip_address.rb +++ b/src/app/models/ip_address.rb @@ -24,4 +24,8 @@ class IpAddress < ActiveRecord::Base belongs_to :network belongs_to :nic belongs_to :bonding + + def validate + errors.add("id", "ip must be associated with foreign entity") if network_id.nil? and nic_id.nil? and bonding_id.nil? + end end diff --git a/src/app/models/iscsi_storage_volume.rb b/src/app/models/iscsi_storage_volume.rb index 48edbd8..fe2cbf5 100644 --- a/src/app/models/iscsi_storage_volume.rb +++ b/src/app/models/iscsi_storage_volume.rb @@ -31,4 +31,6 @@ class IscsiStorageVolume < StorageVolume return true end + validates_presence_of :lun + end diff --git a/src/app/models/lvm_storage_volume.rb b/src/app/models/lvm_storage_volume.rb index 8eb1f0e..38949ce 100644 --- a/src/app/models/lvm_storage_volume.rb +++ b/src/app/models/lvm_storage_volume.rb @@ -29,4 +29,10 @@ class LvmStorageVolume < StorageVolume def volume_create_params return lv_name, size, lv_owner_perms, lv_group_perms, lv_mode_perms end + + validates_presence_of :lv_name + validates_presence_of :lv_owner_perms + validates_presence_of :lv_group_perms + validates_presence_of :lv_mode_perms + end diff --git a/src/app/models/nfs_storage_pool.rb b/src/app/models/nfs_storage_pool.rb index 398e3f9..da0d4b4 100644 --- a/src/app/models/nfs_storage_pool.rb +++ b/src/app/models/nfs_storage_pool.rb @@ -29,4 +29,7 @@ class NfsStoragePool < StoragePool def user_subdividable true end + + validates_presence_of :filename + end diff --git a/src/app/models/nic.rb b/src/app/models/nic.rb index 5649763..aa9c740 100644 --- a/src/app/models/nic.rb +++ b/src/app/models/nic.rb @@ -24,12 +24,23 @@ class Nic < ActiveRecord::Base has_and_belongs_to_many :bondings, :join_table => 'bondings_nics' + validates_presence_of :mac, + :message => 'A mac must be specified.' + + validates_format_of :mac, + :with => %r{^([0-9a-f]{2}([:-]|$)){6}$} + validates_presence_of :host_id, :message => 'A host must be specified.' validates_presence_of :physical_network_id, :message => 'A network must be specified.' + validates_numericality_of :bandwidth, + :greater_than_or_equal_to => 0 + + # validate 'bridge' or 'usage_type' attribute ? + protected def validate if physical_network.boot_type.proto == 'static' and ip_addresses.size == 0 diff --git a/src/app/models/permission.rb b/src/app/models/permission.rb index ece3da5..b3929ad 100644 --- a/src/app/models/permission.rb +++ b/src/app/models/permission.rb @@ -24,9 +24,12 @@ class Permission < ActiveRecord::Base has_many :child_permissions, :dependent => :destroy, :class_name => "Permission", :foreign_key => "inherited_from_id" + validates_presence_of :pool_id + validates_presence_of :uid validates_uniqueness_of :uid, :scope => [:pool_id, :inherited_from_id] + ROLE_SUPER_ADMIN = "Super Admin" ROLE_ADMIN = "Administrator" ROLE_USER = "User" @@ -44,6 +47,10 @@ class Permission < ActiveRecord::Base ROLE_USER => [PRIV_VIEW, PRIV_VM_CONTROL], ROLE_MONITOR => [PRIV_VIEW]} + + validates_inclusion_of :user_role, + :in => ROLES.keys + def self.invert_roles return_hash = {} ROLES.each do |role, privs| diff --git a/src/app/models/pool.rb b/src/app/models/pool.rb index 7034e79..5cfc947 100644 --- a/src/app/models/pool.rb +++ b/src/app/models/pool.rb @@ -52,6 +52,13 @@ class Pool < ActiveRecord::Base validates_presence_of :name validates_uniqueness_of :name, :scope => :parent_id + validates_presence_of :parent_id + validates_presence_of :lft + validates_presence_of :rgt + + validates_inclusion_of :type, + :in => %w( DirectoryPool HardwarePool VmResourcePool SmartPool ) + # overloading this method such that we can use permissions.admins to get all the admins for an object has_many :permissions, :dependent => :destroy, :order => "id ASC" do def super_admins diff --git a/src/app/models/quota.rb b/src/app/models/quota.rb index fc52177..2a9e0f0 100644 --- a/src/app/models/quota.rb +++ b/src/app/models/quota.rb @@ -22,6 +22,28 @@ require 'util/ovirt' class Quota < ActiveRecord::Base belongs_to :pool + validates_presence_of :pool_id + + + validates_numericality_of :total_vcpus, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |quota| quota.total_vcpus.nil? } + + validates_numericality_of :total_vmemory, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |quota| quota.total_vmemory.nil? } + + validates_numericality_of :total_vnics, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |quota| quota.total_vnics.nil? } + + validates_numericality_of :total_storage, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |quota| quota.total_storage.nil? } + + validates_numericality_of :total_vms, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |quota| quota.total_vms.nil? } def total_vmemory_in_mb kb_to_mb(total_vmemory) diff --git a/src/app/models/smart_pool_tag.rb b/src/app/models/smart_pool_tag.rb index e135ddf..00bb5a7 100644 --- a/src/app/models/smart_pool_tag.rb +++ b/src/app/models/smart_pool_tag.rb @@ -31,6 +31,11 @@ class SmartPoolTag < ActiveRecord::Base validates_uniqueness_of :smart_pool_id, :scope => [:tagged_id, :tagged_type] + validates_presence_of :tagged_id + + validates_inclusion_of :tagged_type, + :in => %w( Pool StoragePool Host Vm ) + def tagged_type=(sType) super(sType.to_s.classify.constantize.base_class.to_s) end diff --git a/src/app/models/storage_pool.rb b/src/app/models/storage_pool.rb index bab7031..f9abb55 100644 --- a/src/app/models/storage_pool.rb +++ b/src/app/models/storage_pool.rb @@ -39,6 +39,13 @@ class StoragePool < ActiveRecord::Base validates_presence_of :hardware_pool_id + validates_inclusion_of :type, + :in => %w( IscsiStoragePool LvmStoragePool NfsStoragePool ) + + + validates_numericality_of :capacity, + :greater_than_or_equal_to => 0 + acts_as_xapian :texts => [ :ip_addr, :target, :export_path, :type ], :terms => [ [ :search_users, 'U', "search_users" ] ], :eager_load => :smart_pools @@ -54,6 +61,9 @@ class StoragePool < ActiveRecord::Base STATE_PENDING_DELETION = "pending_deletion" STATE_AVAILABLE = "available" + validates_inclusion_of :state, + :in => [ STATE_PENDING_SETUP, STATE_PENDING_DELETION, STATE_AVAILABLE] + def self.factory(type, params = {}) params[:state] = STATE_PENDING_SETUP unless params[:state] case type @@ -121,4 +131,11 @@ class StoragePool < ActiveRecord::Base end return_hash end + + def movable? + storage_volumes.each{ |x| + return false unless x.movable? + } + return true + end end diff --git a/src/app/models/storage_volume.rb b/src/app/models/storage_volume.rb index 39b72d5..385c126 100644 --- a/src/app/models/storage_volume.rb +++ b/src/app/models/storage_volume.rb @@ -32,10 +32,23 @@ class StorageVolume < ActiveRecord::Base end end + validates_presence_of :storage_pool_id + + + validates_numericality_of :size, + :greater_than_or_equal_to => 0, + :unless => Proc.new { |storage_volume| storage_volume.nil? } + + validates_inclusion_of :type, + :in => %w( IscsiStorageVolume LvmStorageVolume NfsStorageVolume ) + STATE_PENDING_SETUP = "pending_setup" STATE_PENDING_DELETION = "pending_deletion" STATE_AVAILABLE = "available" + validates_inclusion_of :state, + :in => [ STATE_PENDING_SETUP, STATE_PENDING_DELETION, STATE_AVAILABLE] + def self.factory(type, params = {}) params[:state] = STATE_PENDING_SETUP unless params[:state] case type @@ -131,4 +144,12 @@ class StorageVolume < ActiveRecord::Base return_hash end + def movable? + if vms.size > 0 or + (not lvm_storage_pool.nil? and not lvm_stoage_pool.movable?) + return false + end + return true + end + end diff --git a/src/app/models/task.rb b/src/app/models/task.rb index f231c18..e6b9079 100644 --- a/src/app/models/task.rb +++ b/src/app/models/task.rb @@ -45,6 +45,16 @@ class Task < ActiveRecord::Base COMPLETED_STATES = [STATE_FINISHED, STATE_FAILED, STATE_CANCELED] WORKING_STATES = [STATE_QUEUED, STATE_RUNNING, STATE_PAUSED] + validates_inclusion_of :type, + :in => %w( HostTask StorageTask StorageVolumeTask VmTask ) + + validates_inclusion_of :state, + :in => COMPLETED_STATES + WORKING_STATES + + # FIXME validate action depending on type / subclass + # validate task_target_id, task_type_id, arg, message + # depending on subclass, action, state + def cancel self[:state] = STATE_CANCELED save! @@ -71,4 +81,9 @@ class Task < ActiveRecord::Base "" end + def validate + errors.add("time_ended", "Tasks ends before its started") unless time_ended > time_started + errors.add("time_started", "Tasks starts before its created") unless time_started > time_created + end + end diff --git a/src/app/models/usage.rb b/src/app/models/usage.rb index 353e8f4..59b0e48 100644 --- a/src/app/models/usage.rb +++ b/src/app/models/usage.rb @@ -18,4 +18,10 @@ class Usage < ActiveRecord::Base has_and_belongs_to_many :networks, :join_table => 'networks_usages' + + validates_presence_of :label + validates_presence_of :usage + + validates_uniqueness_of :usage + end diff --git a/src/app/models/vm.rb b/src/app/models/vm.rb index 227f343..4d66c63 100644 --- a/src/app/models/vm.rb +++ b/src/app/models/vm.rb @@ -34,7 +34,32 @@ class Vm < ActiveRecord::Base validates_presence_of :uuid, :description, :num_vcpus_allocated, :boot_device, :memory_allocated_in_mb, - :memory_allocated, :vnic_mac_addr + :memory_allocated, :vnic_mac_addr, + :vm_resource_pool_id + + validates_format_of :uuid, + :with => %r([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}) + + validates_numericality_of :needs_restart, + :greater_than_or_equal_to => 0, + :less_than_or_equal_to => 1, + :unless => Proc.new{ |vm| vm.needs_restart.nil? } + + validates_numericality_of :memory_used, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |vm| vm.memory_used.nil? } + + validates_numericality_of :vnc_port, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |vm| vm.vnc_port.nil? } + + validates_numericality_of :num_vcpus_allocated, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |vm| vm.num_vcpus_allocated.nil? } + + validates_numericality_of :memory_allocated, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |vm| vm.memory_allocated.nil? } acts_as_xapian :texts => [ :uuid, :description, :vnic_mac_addr, :state ], :terms => [ [ :search_users, 'U', "search_users" ] ], @@ -117,9 +142,14 @@ class Vm < ActiveRecord::Base STATE_SAVED => STATE_SAVED, STATE_RESTORING => STATE_RUNNING, STATE_MIGRATING => STATE_RUNNING, - STATE_CREATE_FAILED => STATE_CREATE_FAILED} + STATE_CREATE_FAILED => STATE_CREATE_FAILED, + STATE_INVALID => STATE_INVALID} TASK_STATE_TRANSITIONS = [] + validates_inclusion_of :state, + :in => EFFECTIVE_STATE.keys + + def get_hardware_pool pool = vm_resource_pool pool = pool.get_hardware_pool if pool -- 1.6.0.4 From jguiditt at redhat.com Wed Dec 10 03:49:21 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Tue, 09 Dec 2008 22:49:21 -0500 Subject: [Ovirt-devel] [PATCH server] missing ovirt wui validations In-Reply-To: <1228838410-7846-1-git-send-email-mmorsi@redhat.com> References: <1228838410-7846-1-git-send-email-mmorsi@redhat.com> Message-ID: <1228880961.4181.2.camel@physical.priv.ovirt.org> On Tue, 2008-12-09 at 11:00 -0500, Mohammed Morsi wrote: Mo, I'll review this tomorrow since I think Scott is off or at least limited availability. I am assuming this is still just looking for feedback as your last one was, since I cannot ack if it breaks tests (and depending what the new assertions are, really should be _adding_ tests, if anything). -j From pmyers at redhat.com Wed Dec 10 14:00:50 2008 From: pmyers at redhat.com (Perry Myers) Date: Wed, 10 Dec 2008 09:00:50 -0500 Subject: [Ovirt-devel] Re: help In-Reply-To: References: Message-ID: <493FCB92.4070103@redhat.com> Hadi Al-Saadi wrote: > > Sorry for disturbing you. But i know only you. If you can send me > another person email, So i can flow up with him. I'll be more then > thankful. Hadi, No problem. I'm happy to help. I've cc'd ovirt-devel on this message though, in case there are others with similar questions. > And i already register in ur mailing list but i don't know how to use > it. and i logged to the irc chat but no one replayed me in the channel. jdong_ replied to you on IRC. He works on oVirt as well so he could have helped you last night when you were asking for assistance. To use the ovirt-devel mailing list (if you are registered) all you need to do is send mail to ovirt-devel at redhat.com. Anything you send to that email address will show up on the mailing list for all list members to see and respond to. This mail is sent to ovirt-devel so if you reply to it it will go to the mailing list. > now our ovirt with fedora and kvm up and running fine.. we would like to > know if we can setup any other guest O/S expect fedora or ovirt node. > like for example windows, ubuntu. > can we install 64 bit guest O/S ? from ovirt ? Yes. KVM supports various Windows guests (Windows XP, 2003, Vista) in both 32 and 64 bit versions. You should be able to run any of those ok. To provision Windows guests from an ISO image you can set up an image object in Cobbler on the oVirt Appliance. Once that image object is set up you can select it during the VM creation process in the oVirt UI. I'm not sure if the docs cover this process. Darryl Pierce did some of the work on this so he can assist you further with the process. You can use the ISO provisioning method to provision other Linux OSes like Ubuntu as well (both in 32 and 64 bit versions). If the OS you are installing supports network install using kickstart, you can use the embedded Cobbler to create a profile object to install instead of the image object. The cobbler website has more information on how to set up image/profile objects in it. Darryl, perhaps you can write up a quick HOWTO on the ovirt.org wiki for adding profiles/images to Cobbler for oVirt? That would help out users immeasurably. Thanks, Perry -- |=- Red Hat, Engineering, Emerging Technologies, Boston -=| |=- Email: pmyers at redhat.com -=| |=- Office: +1 412 474 3552 Mobile: +1 703 362 9622 -=| |=- GnuPG: E65E4F3D 88F9 F1C9 C2F3 1303 01FE 817C C5D2 8B91 E65E 4F3D -=| From dpierce at redhat.com Wed Dec 10 14:18:25 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 10 Dec 2008 09:18:25 -0500 Subject: [Ovirt-devel] Re: help In-Reply-To: <493FCB92.4070103@redhat.com> References: <493FCB92.4070103@redhat.com> Message-ID: <20081210141824.GA4010@mcpierce-laptop.rdu.redhat.com> On Wed, Dec 10, 2008 at 09:00:50AM -0500, Perry Myers wrote: > Darryl, perhaps you can write up a quick HOWTO on the ovirt.org wiki for > adding profiles/images to Cobbler for oVirt? That would help out users > immeasurably. Absolutely. Hadi, I'd appreciate your help in reviewing the pages as well. That way we can be sure the documentation is complete. I've started the following page on the oVirt wiki: http://www.ovirt.org/page/Guest_Provisioning and would appreciate your feedback on it. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From gspurgeon at redhat.com Wed Dec 10 14:35:26 2008 From: gspurgeon at redhat.com (Gavin Spurgeon) Date: Wed, 10 Dec 2008 14:35:26 +0000 Subject: [Ovirt-devel] Basic/Simple Question re oVirt Message-ID: <1228919726.3169.19.camel@localhost.localdomain> Hi List, I have had a quick look over the Archives and could not find an answer to this question... Basically, can oVirt be installed on RHEL/Cent OS v5 rather than installed F10 on a production Box ? I have a few large Xen Servers running in a production environment with Cobbler doing the provisioning and wanted to look @ oVirt as the management tool for this setup, but I did not really want to install Fedora as the Base OS onto the bare Iron... Any Comments/Question/Flames ? -- Gavin Spurgeon. gspurgeon at redhat.com RedHat GLS Instructor EMEA Red Hat UK Ltd 200 Fowler Avenue IQ Farnborough, Farnborough, Hants GU14 7JP Mob: +44 7841 231160 Tel: +44 1252 362700 Fax: +44 1252 548116 Registered in England and Wales under Company Registration No. 03798903 Directors: Michael Cunningham (USA), Brendan Lane (Ireland), Matt Parson (USA), Charlie Peters (USA) -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 197 bytes Desc: This is a digitally signed message part URL: From jim at meyering.net Wed Dec 10 16:15:39 2008 From: jim at meyering.net (Jim Meyering) Date: Wed, 10 Dec 2008 17:15:39 +0100 Subject: [Ovirt-devel] [PATCH node-image] Don't install or distribute ovirt-flash-static. Message-ID: <877i68ovkk.fsf@rho.meyering.net> * ovirt-node-image.spec.in: Don't install ovirt-flash-static. * Makefile.am (EXTRA_DIST): Remove ovirt-flash-static from the tarball, too. --- Per discussion on IRC, we don't want to support/install this file right now, but we'll leave it in the repository. Makefile.am | 9 ++++----- ovirt-node-image.spec.in | 2 -- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Makefile.am b/Makefile.am index cb084e6..79230e9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -33,17 +33,16 @@ NVR = $(PACKAGE)-$(VERSION)-$(ARCH) EXTRA_DIST = \ .gitignore \ $(PACKAGE).spec \ - $(PACKAGE).spec.in \ + $(PACKAGE).spec.in \ README.krb5 \ - common-blacklist.ks \ + common-blacklist.ks \ common-install.ks \ common-pkgs.ks \ common-post.ks \ ovirt-flash \ - ovirt-flash-static \ $(PACKAGE).ks \ - ovirt-pxe \ - create-ovirt-iso-nodes \ + ovirt-pxe \ + create-ovirt-iso-nodes \ edit-livecd \ livecd-setauth diff --git a/ovirt-node-image.spec.in b/ovirt-node-image.spec.in index eab9cee..ff285c0 100644 --- a/ovirt-node-image.spec.in +++ b/ovirt-node-image.spec.in @@ -60,7 +60,6 @@ mkdir %{buildroot} %{__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} %{__install} -p -m0755 create-ovirt-iso-nodes %{buildroot}%{_sbindir} %{__install} -p -m0755 edit-livecd %{buildroot}%{_sbindir} %{__install} -p -m0755 livecd-setauth %{buildroot}%{_sbindir} @@ -80,7 +79,6 @@ cobbler sync > /dev/null 2>&1 || : %defattr(-,root,root,0755) %{_sbindir}/ovirt-pxe %{_sbindir}/ovirt-flash -%{_sbindir}/ovirt-flash-static %{_sbindir}/create-ovirt-iso-nodes %{_sbindir}/edit-livecd %{_sbindir}/livecd-setauth -- 1.6.1.rc2.299.gead4c From mmorsi at redhat.com Wed Dec 10 18:39:00 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Wed, 10 Dec 2008 13:39:00 -0500 Subject: [Ovirt-devel] [PATCH server] missing ovirt wui validations In-Reply-To: <1228880961.4181.2.camel@physical.priv.ovirt.org> References: <1228838410-7846-1-git-send-email-mmorsi@redhat.com> <1228880961.4181.2.camel@physical.priv.ovirt.org> Message-ID: <49400CC4.9080303@redhat.com> Jason Guiditta wrote: > On Tue, 2008-12-09 at 11:00 -0500, Mohammed Morsi wrote: > > Mo, I'll review this tomorrow since I think Scott is off or at least > limited availability. I am assuming this is still just looking for > feedback as your last one was, since I cannot ack if it breaks tests > (and depending what the new assertions are, really should be _adding_ > tests, if anything). > > -j > > Appreciate you looking at it and yes just looking for feedback. Working my way through the tests now and seeing what needs to be done to get them working again at the very least. -Mo From lutter at redhat.com Wed Dec 10 20:39:02 2008 From: lutter at redhat.com (David Lutterkort) Date: Wed, 10 Dec 2008 12:39:02 -0800 Subject: [Ovirt-devel] [PATCH server] API: add a call to list VMs for a user Message-ID: <1228941542-21128-1-git-send-email-lutter@redhat.com> Going to the URL /vms will return a list of all the VM's for which the current user has PRIV_VIEW permission. The VM info contains the host the VM is running on (if any) --- src/app/controllers/vm_controller.rb | 14 ++++++++++++++ src/config/routes.rb | 2 +- 2 files changed, 15 insertions(+), 1 deletions(-) diff --git a/src/app/controllers/vm_controller.rb b/src/app/controllers/vm_controller.rb index ff74a37..701dea8 100644 --- a/src/app/controllers/vm_controller.rb +++ b/src/app/controllers/vm_controller.rb @@ -25,6 +25,20 @@ class VmController < ApplicationController before_filter :pre_vm_action, :only => [:vm_action, :cancel_queued_tasks, :console] + def index + roles = "('" + + Permission::roles_for_privilege(Permission::PRIV_VIEW).join("', '") + + "')" + user = get_login_user + @vms = Vm.find(:all, + :joins => "join permissions p on (vm_resource_pool_id = p.pool_id)", + :conditions => [ "p.uid = :user and p.user_role in #{roles}", + { :user => user }]) + respond_to do |format| + format.xml { render :xml => @vms.to_xml(:include => :host) } + end + end + def show set_perms(@perm_obj) @actions = @vm.get_action_hash(@user) diff --git a/src/config/routes.rb b/src/config/routes.rb index 0dbe0d6..135d68b 100644 --- a/src/config/routes.rb +++ b/src/config/routes.rb @@ -56,5 +56,5 @@ ActionController::Routing::Routes.draw do |map| hardware_pools.resources :hosts, :controller => 'host' hardware_pools.resources :storage_pools, :controller => 'storage' end - + map.resources :vms, :controller => 'vm' end -- 1.6.0.4 From jim at meyering.net Wed Dec 10 20:49:31 2008 From: jim at meyering.net (Jim Meyering) Date: Wed, 10 Dec 2008 21:49:31 +0100 Subject: [Ovirt-devel] [PATCH node-image] Don't install or distribute ovirt-flash-static. In-Reply-To: <877i68ovkk.fsf@rho.meyering.net> (Jim Meyering's message of "Wed, 10 Dec 2008 17:15:39 +0100") References: <877i68ovkk.fsf@rho.meyering.net> Message-ID: <87skovn4bo.fsf@rho.meyering.net> Jim Meyering wrote: > * ovirt-node-image.spec.in: Don't install ovirt-flash-static. > * Makefile.am (EXTRA_DIST): Remove ovirt-flash-static from the tarball, too. > --- > Per discussion on IRC, we don't want to support/install > this file right now, but we'll leave it in the repository. Alan ACK'd this privately, so I pushed it. From pmyers at redhat.com Wed Dec 10 21:42:01 2008 From: pmyers at redhat.com (Perry Myers) Date: Wed, 10 Dec 2008 16:42:01 -0500 Subject: [Ovirt-devel] Doc patch - Please ACK In-Reply-To: <493DC3E7.1040004@redhat.com> References: <493DC3E7.1040004@redhat.com> Message-ID: <494037A9.9080909@redhat.com> Susan Burgess wrote: > > > ------------------------------------------------------------------------ > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel ack and pushed with a follow on patch to correct the spec file Note, the docs build in F10 properly but there are some formatting errors due to F10 not having up to date publican packages. We are working to get publican updated. 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 jguiditt at redhat.com Wed Dec 10 22:25:47 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Wed, 10 Dec 2008 17:25:47 -0500 Subject: [Ovirt-devel] [PATCH server] missing ovirt wui validations In-Reply-To: <1228838410-7846-1-git-send-email-mmorsi@redhat.com> References: <1228838410-7846-1-git-send-email-mmorsi@redhat.com> Message-ID: <1228947947.11590.8.camel@physical.priv.ovirt.org> Coming along nicely, some comments/corrections inline. There are some whitespace errors with the patch: Applying missing ovirt wui validations .dotest/patch:44: trailing whitespace. unless item_class.find(x).movable? .dotest/patch:81: trailing whitespace. :success => false, .dotest/patch:474: trailing whitespace. validates_numericality_of :size, .dotest/patch:496: trailing whitespace. if vms.size > 0 or .dotest/patch:498: trailing whitespace. return false warning: 5 lines add whitespace errors. On Tue, 2008-12-09 at 11:00 -0500, Mohammed Morsi wrote: > this patch is now syntactically correct and will run when invoking > db:migrate or when running the tests. several tests now fail though > and need to be debugged / possibly changed > > Attached is additional validations, added to the rails model > and controller layers verifying: > bondings: arp related fields > boot_types: label uniqueness and proto inclusion > cpus: various fields are set and min values > help_sections: presence and uniqueness of fields > hosts: presence and format of various fields > ip_addresses: fk existance / integrity > nics: mac address format > permissions: presence / inclusion of various fields > pools: fields requied for tree present > quotas: minimum values > smart_pool_tags: tagged_id / type fk present > storage_pools: type, state field inclusion, min values > storage_volumes: various fields, subclasses w/ various fields > tasks: various fields present and consistensy maintained > usages: label, other fields present, unique > vms: uuid of correct format, min values, various fields present > > can only add / move host and storage volumes and pools to / from pools > when you have sufficient permissions and target entities don't have > associated vms > > can only destroy storage volumes / pools if there are no attached vms > --- > src/app/controllers/hardware_controller.rb | 28 +++++++++++++++++++++- > src/app/controllers/storage_controller.rb | 7 +++++ > src/app/models/bonding.rb | 11 +++++++++ > src/app/models/boot_type.rb | 5 ++++ > src/app/models/cpu.rb | 23 +++++++++++++++++++ > src/app/models/help_section.rb | 34 ++++++++++++++++++++++++++++ > src/app/models/host.rb | 21 +++++++++++++++++ > src/app/models/ip_address.rb | 4 +++ > src/app/models/iscsi_storage_volume.rb | 2 + > src/app/models/lvm_storage_volume.rb | 6 +++++ > src/app/models/nfs_storage_pool.rb | 3 ++ > src/app/models/nic.rb | 11 +++++++++ > src/app/models/permission.rb | 7 +++++ > src/app/models/pool.rb | 7 +++++ > src/app/models/quota.rb | 22 ++++++++++++++++++ > src/app/models/smart_pool_tag.rb | 5 ++++ > src/app/models/storage_pool.rb | 17 ++++++++++++++ > src/app/models/storage_volume.rb | 21 +++++++++++++++++ > src/app/models/task.rb | 15 ++++++++++++ > src/app/models/usage.rb | 6 +++++ > src/app/models/vm.rb | 34 ++++++++++++++++++++++++++- > 21 files changed, 285 insertions(+), 4 deletions(-) > > diff --git a/src/app/controllers/hardware_controller.rb b/src/app/controllers/hardware_controller.rb > index 4dda736..cf45c49 100644 > --- a/src/app/controllers/hardware_controller.rb > +++ b/src/app/controllers/hardware_controller.rb > @@ -303,15 +303,39 @@ class HardwareController < PoolController > resource_ids_str = params[:resource_ids] > resource_ids = resource_ids_str.split(",").collect {|x| x.to_i} > > + # if user doesn't have modify permission on both source and destination > + unless @pool.can_modify(@user) and Pool.find(params[:target_pool_id]).can_modify(@user) > + render :json => { :success => false, > + :alert => "Cannot #{item_action.to_s} #{item_class.table_name.humanize} without admin permissions on both pools" } > + return > + end > + > + # relay error message if movable check fails for any resource > + success = true > + failed_resources = "" > + resource_ids.each {|x| > + unless item_class.find(x).movable? > + success = false > + failed_resources += x.to_s + " " > + end > + } > + resource_ids.delete_if { |x| ! item_class.find(x).movable? } > + > begin > @pool.transaction do > @pool.send(item_method, resource_ids, target_pool_id) > end > + rescue > + success = false > + end > + > + if success > render :json => { :success => true, > :alert => "#{item_action.to_s} #{item_class.table_name.humanize} successful." } > - rescue > + else > render :json => { :success => false, > - :alert => "#{item_action.to_s} #{item_class.table_name.humanize} failed." } > + :alert => "#{item_action.to_s} #{item_class.table_name.humanize} failed" + > + (failed_resources == "" ? "." : " for " + failed_resources) } > end > end Very nice, I like this much better than the first rev. > > diff --git a/src/app/controllers/storage_controller.rb b/src/app/controllers/storage_controller.rb > index 148d1be..47e9e14 100644 > --- a/src/app/controllers/storage_controller.rb > +++ b/src/app/controllers/storage_controller.rb > @@ -310,6 +310,13 @@ class StorageController < ApplicationController > end > > def destroy > + unless @storage_pool.movable? > + format.json { render :json => { :object => "storage_pool", > + :success => false, > + :alert => "Cannot delete storage with associated vms" } } > + return > + end > + > pool = @storage_pool.hardware_pool > if @storage_pool.destroy > alert="Storage Pool was successfully deleted." > diff --git a/src/app/models/bonding.rb b/src/app/models/bonding.rb > index c9af38c..fabdb67 100644 > --- a/src/app/models/bonding.rb > +++ b/src/app/models/bonding.rb > @@ -30,6 +30,8 @@ > # interface. They can be ignored if not used. > # > class Bonding < ActiveRecord::Base > + > + > belongs_to :host > belongs_to :bonding_type > belongs_to :vlan > @@ -58,6 +60,15 @@ class Bonding < ActiveRecord::Base > validates_presence_of :vlan_id, > :message => 'A vlan must be specified.' > > + # verify arp ping address to be ipv4 if set > + validates_format_of :arp_ping_address, > + :with => %r{^(\d{1,3}\.){3}\d{1,3}$}, > + :unless => Proc.new { |bonding| bonding.arp_ping_address.nil? } > + > + validates_numericality_of :arp_interval, > + :greater_than_or_equal_to => 0, > + :unless => Proc.new { |bonding| bonding.arp_interval.nil? } > + > protected > def validate > if vlan.boot_type.proto == 'static' and ip_addresses.size == 0 > diff --git a/src/app/models/boot_type.rb b/src/app/models/boot_type.rb > index 8ffbe67..6cfdb04 100644 > --- a/src/app/models/boot_type.rb > +++ b/src/app/models/boot_type.rb > @@ -18,4 +18,9 @@ > # also available at http://www.gnu.org/copyleft/gpl.html. > > class BootType < ActiveRecord::Base > + validates_presence_of :label > + validates_uniqueness_of :label, > + :message => 'Label must be unique' > + validates_inclusion_of :proto, > + :in => %w( static dhcp bootp ) > end > diff --git a/src/app/models/cpu.rb b/src/app/models/cpu.rb > index 1a7d3cf..714a8ed 100644 > --- a/src/app/models/cpu.rb > +++ b/src/app/models/cpu.rb > @@ -21,4 +21,27 @@ > # > class Cpu < ActiveRecord::Base > belongs_to :host > + > + validates_presence_of :host_id, > + :message => 'A host must be specified.' > + > + validates_numericality_of :cpu_number, > + :greater_than_or_equal_to => 0 > + > + validates_numericality_of :core_number, > + :greater_than_or_equal_to => 0 > + > + validates_numericality_of :number_of_cores, > + :greater_than_or_equal_to => 1 > + > + validates_numericality_of :cpuid_level, > + :greater_than_or_equal_to => 0 > + > + validates_numericality_of :speed, > + :greater_than => 0 > + # also verify speed in MHz ? > + > + validates_presence_of :vendor > + validates_presence_of :model > + validates_presence_of :family > end > diff --git a/src/app/models/help_section.rb b/src/app/models/help_section.rb > index a891383..1de1e5a 100644 > --- a/src/app/models/help_section.rb > +++ b/src/app/models/help_section.rb > @@ -1,2 +1,36 @@ > +# Copyright (C) 2008 Red Hat, Inc. > +# Written by Mohammed Morsi > +# > +# This program is free software; you can redistribute it and/or modify > +# it under the terms of the GNU General Public License as published by > +# the Free Software Foundation; version 2 of the License. > +# > +# This program is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +# GNU General Public License for more details. > +# > +# You should have received a copy of the GNU General Public License > +# along with this program; if not, write to the Free Software > +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, > +# MA 02110-1301, USA. A copy of the GNU General Public License is > +# also available at http://www.gnu.org/copyleft/gpl.html. > +# > +# +HelpSection+ defines a section of the web help document to be > +# available for a specific controller / action > +# > class HelpSection < ActiveRecord::Base > + > + validates_uniqueness_of :action, > + :scope => :controller Missing ',' on above line > + :message => 'Controller / Action must be unique' > + > + validates_presence_of :controller, > + :message => 'A controller must be specified.' > + > + validates_presence_of :action, > + :message => 'An action must be specified.' > + > + validates_presence_of :section, > + :message => 'A section must be specified.' > end > diff --git a/src/app/models/host.rb b/src/app/models/host.rb > index 640782d..ef495ff 100644 > --- a/src/app/models/host.rb > +++ b/src/app/models/host.rb > @@ -51,6 +51,17 @@ class Host < ActiveRecord::Base > [ :search_users, 'U', "search_users" ] ], > :eager_load => :smart_pools > > + validates_presence_of :hardware_pool_id, > + :message => 'A hardware pool id must be specified.' > + > + validates_presence_of :uuid, > + :message => 'A uuid must be specified.' > + > + validates_presence_of :hostname, > + :message => 'A hostname must be specified.' > + > + validates_presence_of :arch, > + :message => 'An arch must be specified.' > > KVM_HYPERVISOR_TYPE = "KVM" > HYPERVISOR_TYPES = [KVM_HYPERVISOR_TYPE] > @@ -58,6 +69,12 @@ class Host < ActiveRecord::Base > STATE_AVAILABLE = "available" > STATES = [STATE_UNAVAILABLE, STATE_AVAILABLE] > > + validates_inclusion_of :hypervisor_type, > + :in => HYPERVISOR_TYPES > + > + validates_inclusion_of :state, > + :in => STATES + Task::COMPLETED_STATES + TASK::WORKING_STATES 2nd 'Task' should not be all caps > + > def memory_in_mb > kb_to_mb(memory) > end > @@ -99,4 +116,8 @@ class Host < ActiveRecord::Base > hardware_pool.search_users > end > > + def movable? > + return vms.size == 0 > + end > + > end > diff --git a/src/app/models/ip_address.rb b/src/app/models/ip_address.rb > index 5d2e6af..3f246b1 100644 > --- a/src/app/models/ip_address.rb > +++ b/src/app/models/ip_address.rb > @@ -24,4 +24,8 @@ class IpAddress < ActiveRecord::Base > belongs_to :network > belongs_to :nic > belongs_to :bonding > + > + def validate > + errors.add("id", "ip must be associated with foreign entity") if network_id.nil? and nic_id.nil? and bonding_id.nil? > + end > end > diff --git a/src/app/models/iscsi_storage_volume.rb b/src/app/models/iscsi_storage_volume.rb > index 48edbd8..fe2cbf5 100644 > --- a/src/app/models/iscsi_storage_volume.rb > +++ b/src/app/models/iscsi_storage_volume.rb > @@ -31,4 +31,6 @@ class IscsiStorageVolume < StorageVolume > return true > end > > + validates_presence_of :lun > + > end > diff --git a/src/app/models/lvm_storage_volume.rb b/src/app/models/lvm_storage_volume.rb > index 8eb1f0e..38949ce 100644 > --- a/src/app/models/lvm_storage_volume.rb > +++ b/src/app/models/lvm_storage_volume.rb > @@ -29,4 +29,10 @@ class LvmStorageVolume < StorageVolume > def volume_create_params > return lv_name, size, lv_owner_perms, lv_group_perms, lv_mode_perms > end > + > + validates_presence_of :lv_name > + validates_presence_of :lv_owner_perms > + validates_presence_of :lv_group_perms > + validates_presence_of :lv_mode_perms > + > end > diff --git a/src/app/models/nfs_storage_pool.rb b/src/app/models/nfs_storage_pool.rb > index 398e3f9..da0d4b4 100644 > --- a/src/app/models/nfs_storage_pool.rb > +++ b/src/app/models/nfs_storage_pool.rb > @@ -29,4 +29,7 @@ class NfsStoragePool < StoragePool > def user_subdividable > true > end > + > + validates_presence_of :filename > + > end > diff --git a/src/app/models/nic.rb b/src/app/models/nic.rb > index 5649763..aa9c740 100644 > --- a/src/app/models/nic.rb > +++ b/src/app/models/nic.rb > @@ -24,12 +24,23 @@ class Nic < ActiveRecord::Base > > has_and_belongs_to_many :bondings, :join_table => 'bondings_nics' > > + validates_presence_of :mac, > + :message => 'A mac must be specified.' > + > + validates_format_of :mac, > + :with => %r{^([0-9a-f]{2}([:-]|$)){6}$} > + > validates_presence_of :host_id, > :message => 'A host must be specified.' > > validates_presence_of :physical_network_id, > :message => 'A network must be specified.' > > + validates_numericality_of :bandwidth, > + :greater_than_or_equal_to => 0 > + > + # validate 'bridge' or 'usage_type' attribute ? > + > protected > def validate > if physical_network.boot_type.proto == 'static' and ip_addresses.size == 0 > diff --git a/src/app/models/permission.rb b/src/app/models/permission.rb > index ece3da5..b3929ad 100644 > --- a/src/app/models/permission.rb > +++ b/src/app/models/permission.rb > @@ -24,9 +24,12 @@ class Permission < ActiveRecord::Base > has_many :child_permissions, :dependent => :destroy, > :class_name => "Permission", :foreign_key => "inherited_from_id" > > + validates_presence_of :pool_id > > + validates_presence_of :uid > validates_uniqueness_of :uid, :scope => [:pool_id, :inherited_from_id] > > + > ROLE_SUPER_ADMIN = "Super Admin" > ROLE_ADMIN = "Administrator" > ROLE_USER = "User" > @@ -44,6 +47,10 @@ class Permission < ActiveRecord::Base > ROLE_USER => [PRIV_VIEW, PRIV_VM_CONTROL], > ROLE_MONITOR => [PRIV_VIEW]} > > + > + validates_inclusion_of :user_role, > + :in => ROLES.keys > + > def self.invert_roles > return_hash = {} > ROLES.each do |role, privs| > diff --git a/src/app/models/pool.rb b/src/app/models/pool.rb > index 7034e79..5cfc947 100644 > --- a/src/app/models/pool.rb > +++ b/src/app/models/pool.rb > @@ -52,6 +52,13 @@ class Pool < ActiveRecord::Base > validates_presence_of :name > validates_uniqueness_of :name, :scope => :parent_id > > + validates_presence_of :parent_id > + validates_presence_of :lft > + validates_presence_of :rgt > + > + validates_inclusion_of :type, > + :in => %w( DirectoryPool HardwarePool VmResourcePool SmartPool ) > + > # overloading this method such that we can use permissions.admins to get all the admins for an object > has_many :permissions, :dependent => :destroy, :order => "id ASC" do > def super_admins > diff --git a/src/app/models/quota.rb b/src/app/models/quota.rb > index fc52177..2a9e0f0 100644 > --- a/src/app/models/quota.rb > +++ b/src/app/models/quota.rb > @@ -22,6 +22,28 @@ require 'util/ovirt' > class Quota < ActiveRecord::Base > belongs_to :pool > > + validates_presence_of :pool_id > + > + > + validates_numericality_of :total_vcpus, > + :greater_than_or_equal_to => 0, > + :unless => Proc.new{ |quota| quota.total_vcpus.nil? } > + > + validates_numericality_of :total_vmemory, > + :greater_than_or_equal_to => 0, > + :unless => Proc.new{ |quota| quota.total_vmemory.nil? } > + > + validates_numericality_of :total_vnics, > + :greater_than_or_equal_to => 0, > + :unless => Proc.new{ |quota| quota.total_vnics.nil? } > + > + validates_numericality_of :total_storage, > + :greater_than_or_equal_to => 0, > + :unless => Proc.new{ |quota| quota.total_storage.nil? } > + > + validates_numericality_of :total_vms, > + :greater_than_or_equal_to => 0, > + :unless => Proc.new{ |quota| quota.total_vms.nil? } > > def total_vmemory_in_mb > kb_to_mb(total_vmemory) > diff --git a/src/app/models/smart_pool_tag.rb b/src/app/models/smart_pool_tag.rb > index e135ddf..00bb5a7 100644 > --- a/src/app/models/smart_pool_tag.rb > +++ b/src/app/models/smart_pool_tag.rb > @@ -31,6 +31,11 @@ class SmartPoolTag < ActiveRecord::Base > > validates_uniqueness_of :smart_pool_id, :scope => [:tagged_id, :tagged_type] > > + validates_presence_of :tagged_id > + > + validates_inclusion_of :tagged_type, > + :in => %w( Pool StoragePool Host Vm ) > + > def tagged_type=(sType) > super(sType.to_s.classify.constantize.base_class.to_s) > end > diff --git a/src/app/models/storage_pool.rb b/src/app/models/storage_pool.rb > index bab7031..f9abb55 100644 > --- a/src/app/models/storage_pool.rb > +++ b/src/app/models/storage_pool.rb > @@ -39,6 +39,13 @@ class StoragePool < ActiveRecord::Base > > validates_presence_of :hardware_pool_id > > + validates_inclusion_of :type, > + :in => %w( IscsiStoragePool LvmStoragePool NfsStoragePool ) > + > + > + validates_numericality_of :capacity, > + :greater_than_or_equal_to => 0 > + > acts_as_xapian :texts => [ :ip_addr, :target, :export_path, :type ], > :terms => [ [ :search_users, 'U', "search_users" ] ], > :eager_load => :smart_pools > @@ -54,6 +61,9 @@ class StoragePool < ActiveRecord::Base > STATE_PENDING_DELETION = "pending_deletion" > STATE_AVAILABLE = "available" > > + validates_inclusion_of :state, > + :in => [ STATE_PENDING_SETUP, STATE_PENDING_DELETION, STATE_AVAILABLE] > + > def self.factory(type, params = {}) > params[:state] = STATE_PENDING_SETUP unless params[:state] > case type > @@ -121,4 +131,11 @@ class StoragePool < ActiveRecord::Base > end > return_hash > end > + > + def movable? > + storage_volumes.each{ |x| > + return false unless x.movable? > + } > + return true > + end > end > diff --git a/src/app/models/storage_volume.rb b/src/app/models/storage_volume.rb > index 39b72d5..385c126 100644 > --- a/src/app/models/storage_volume.rb > +++ b/src/app/models/storage_volume.rb > @@ -32,10 +32,23 @@ class StorageVolume < ActiveRecord::Base > end > end > > + validates_presence_of :storage_pool_id > + > + > + validates_numericality_of :size, > + :greater_than_or_equal_to => 0, > + :unless => Proc.new { |storage_volume| storage_volume.nil? } > + > + validates_inclusion_of :type, > + :in => %w( IscsiStorageVolume LvmStorageVolume NfsStorageVolume ) > + > STATE_PENDING_SETUP = "pending_setup" > STATE_PENDING_DELETION = "pending_deletion" > STATE_AVAILABLE = "available" > > + validates_inclusion_of :state, > + :in => [ STATE_PENDING_SETUP, STATE_PENDING_DELETION, STATE_AVAILABLE] > + > def self.factory(type, params = {}) > params[:state] = STATE_PENDING_SETUP unless params[:state] > case type > @@ -131,4 +144,12 @@ class StorageVolume < ActiveRecord::Base > return_hash > end > > + def movable? > + if vms.size > 0 or > + (not lvm_storage_pool.nil? and not lvm_stoage_pool.movable?) typo lvm_stoage_pool [unless that was an elmer fudd ref? ;) ] and shouldn't it be '!' rather than 'not'? > + return false > + end > + return true > + end > + > end > diff --git a/src/app/models/task.rb b/src/app/models/task.rb > index f231c18..e6b9079 100644 > --- a/src/app/models/task.rb > +++ b/src/app/models/task.rb > @@ -45,6 +45,16 @@ class Task < ActiveRecord::Base > COMPLETED_STATES = [STATE_FINISHED, STATE_FAILED, STATE_CANCELED] > WORKING_STATES = [STATE_QUEUED, STATE_RUNNING, STATE_PAUSED] > > + validates_inclusion_of :type, > + :in => %w( HostTask StorageTask StorageVolumeTask VmTask ) > + > + validates_inclusion_of :state, > + :in => COMPLETED_STATES + WORKING_STATES > + > + # FIXME validate action depending on type / subclass > + # validate task_target_id, task_type_id, arg, message > + # depending on subclass, action, state > + > def cancel > self[:state] = STATE_CANCELED > save! > @@ -71,4 +81,9 @@ class Task < ActiveRecord::Base > "" > end > > + def validate > + errors.add("time_ended", "Tasks ends before its started") unless time_ended > time_started > + errors.add("time_started", "Tasks starts before its created") unless time_started > time_created > + end > + > end > diff --git a/src/app/models/usage.rb b/src/app/models/usage.rb > index 353e8f4..59b0e48 100644 > --- a/src/app/models/usage.rb > +++ b/src/app/models/usage.rb > @@ -18,4 +18,10 @@ > > class Usage < ActiveRecord::Base > has_and_belongs_to_many :networks, :join_table => 'networks_usages' > + > + validates_presence_of :label > + validates_presence_of :usage > + > + validates_uniqueness_of :usage > + > end > diff --git a/src/app/models/vm.rb b/src/app/models/vm.rb > index 227f343..4d66c63 100644 > --- a/src/app/models/vm.rb > +++ b/src/app/models/vm.rb > @@ -34,7 +34,32 @@ class Vm < ActiveRecord::Base > > validates_presence_of :uuid, :description, :num_vcpus_allocated, > :boot_device, :memory_allocated_in_mb, > - :memory_allocated, :vnic_mac_addr > + :memory_allocated, :vnic_mac_addr, > + :vm_resource_pool_id > + > + validates_format_of :uuid, > + :with => %r([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}) > + > + validates_numericality_of :needs_restart, > + :greater_than_or_equal_to => 0, > + :less_than_or_equal_to => 1, > + :unless => Proc.new{ |vm| vm.needs_restart.nil? } > + > + validates_numericality_of :memory_used, > + :greater_than_or_equal_to => 0, > + :unless => Proc.new{ |vm| vm.memory_used.nil? } > + > + validates_numericality_of :vnc_port, > + :greater_than_or_equal_to => 0, > + :unless => Proc.new{ |vm| vm.vnc_port.nil? } > + > + validates_numericality_of :num_vcpus_allocated, > + :greater_than_or_equal_to => 0, > + :unless => Proc.new{ |vm| vm.num_vcpus_allocated.nil? } > + > + validates_numericality_of :memory_allocated, > + :greater_than_or_equal_to => 0, > + :unless => Proc.new{ |vm| vm.memory_allocated.nil? } > > acts_as_xapian :texts => [ :uuid, :description, :vnic_mac_addr, :state ], > :terms => [ [ :search_users, 'U', "search_users" ] ], > @@ -117,9 +142,14 @@ class Vm < ActiveRecord::Base > STATE_SAVED => STATE_SAVED, > STATE_RESTORING => STATE_RUNNING, > STATE_MIGRATING => STATE_RUNNING, > - STATE_CREATE_FAILED => STATE_CREATE_FAILED} > + STATE_CREATE_FAILED => STATE_CREATE_FAILED, > + STATE_INVALID => STATE_INVALID} > TASK_STATE_TRANSITIONS = [] > > + validates_inclusion_of :state, > + :in => EFFECTIVE_STATE.keys > + > + > def get_hardware_pool > pool = vm_resource_pool > pool = pool.get_hardware_pool if pool From apevec at redhat.com Wed Dec 10 22:40:01 2008 From: apevec at redhat.com (Alan Pevec) Date: Wed, 10 Dec 2008 23:40:01 +0100 Subject: [Ovirt-devel] [PATCH node] separate ovirt-config-boot for in-place image upgrades Message-ID: <1228948801-7623-1-git-send-email-apevec@redhat.com> Outstandig issue is /dev/vda support by grub, so if testing with 'fake' Node VMs, please switch to IDE, in domain XML: instead of --- ovirt-node.spec.in | 6 +++ scripts/ovirt-config-boot | 87 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 0 deletions(-) create mode 100755 scripts/ovirt-config-boot diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in index ef65bf0..0973af9 100644 --- a/ovirt-node.spec.in +++ b/ovirt-node.spec.in @@ -35,6 +35,7 @@ Requires: bind-utils # qemu-img RPM. Requires: qemu-img Requires: nc +Requires: grub Requires: /usr/sbin/crond ExclusiveArch: %{ix86} x86_64 @@ -87,6 +88,7 @@ cd - %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/logrotate.d %{__install} -p -m0755 scripts/ovirt-awake %{buildroot}%{_sbindir} +%{__install} -p -m0755 scripts/ovirt-config-boot %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-logging %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-networking %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-password %{buildroot}%{_sbindir} @@ -171,6 +173,7 @@ fi %files %defattr(-,root,root,0755) %{_sbindir}/ovirt-awake +%{_sbindir}/ovirt-config-boot %{_sbindir}/ovirt-config-logging %{_sbindir}/ovirt-config-networking %{_sbindir}/ovirt-config-password @@ -200,6 +203,9 @@ fi %doc ovirt-identify-node/COPYING %changelog +* Wed Dec 10 2008 Alan Pevec 0.96-0.1 +- ovirt-config-* setup scripts for standalone mode + * Thu Sep 11 2008 Chris Lalancette - 0.92 0.7 - Add the ovirt-install- and ovirt-uninstall-node scripts, and refactor post to accomodate diff --git a/scripts/ovirt-config-boot b/scripts/ovirt-config-boot new file mode 100755 index 0000000..8b950e6 --- /dev/null +++ b/scripts/ovirt-config-boot @@ -0,0 +1,87 @@ +#!/bin/bash +# +# ovirt-config-boot - configure local boot disk partition + +# SYNOPSIS +# ovirt-config-boot livecd_path bootparams +# +# boot_disk - boot disk device e.g. /dev/sda +# +# livecd_path - where livecd media is mounted, +# parent of LiveOS and isolinux folders +# +# bootparams - extra boot parameters like console=... +# + +# Source functions library +. /etc/init.d/functions +. /etc/init.d/ovirt-functions + + +# local_boot_install livecd_path bootparams +# livecd_path -livecd media +# bootparams - extra boot parameters like console=... +# +# copy oVirt Node image to the local LVM /dev/HostVG +ovirt_boot_setup() { + local disk=$1 + local live=$2 + local bootparams=$3 + printf "installing oVirt Node image ..." + mount_boot + mount_liveos + # install oVirt Node image for local boot + if [ -e "$live/syslinux" ]; then + syslinux=syslinux + elif [ -e "$live/isolinux" ]; then + syslinux=isolinux + else + syslinux= + fi + rm -rf /boot/grub + rm -rf /liveos/LiveOS + mkdir -p /boot/grub + mkdir -p /liveos/LiveOS + cp -p $live/LiveOS/squashfs.img /liveos/LiveOS \ + && cp -p $live/$syslinux/initrd0.img /boot \ + && cp -p $live/$syslinux/vmlinuz0 /boot + # TODO repack cpio archive initrd0.img + # to skip appended livecd ISO (PXE boot) + rc=$? + if [ $rc -ne 0 ]; then + printf "image copy failed\n" + return $rc + fi + cat > /boot/grub/grub.conf << EOF +default=0 +timeout=2 +hiddenmenu +title oVirt Node + root (hd0,0) + kernel /vmlinuz0 ro root=/dev/HostVG/Root roottypefs=ext3 liveimg $bootparams + initrd /initrd0.img +EOF + # XXX vda - virtio block issues: + # doesn't show up in device.map + # grub-install doesn't support vda: [sh]d + # does cciss devices work? + grub-install --root-directory=/boot $disk >&2 + rc=$? + if [ $rc -ne 0 ]; then + printf "boot loader install failed\n" + return $rc + fi + # remove unused 1.5 stages + find /boot/grub -name '*_stage1_5' ! -name e2fs_stage1_5 \ + -exec rm {} \; + # XXX avoid reboot loops when using Cobbler PXE only once + # Cobbler XMLRPC post-install trigger: + # wget "http://192.168.50.2/cblr/svc/op/trig/mode/post/system/$(hostname)" + # -O /dev/null + sync; sync; sync + # caller decideds when to reboot +} + + +ovirt_boot_setup $1 $2 $3 + -- 1.6.0.4 From apevec at redhat.com Wed Dec 10 22:40:32 2008 From: apevec at redhat.com (Alan Pevec) Date: Wed, 10 Dec 2008 23:40:32 +0100 Subject: [Ovirt-devel] [PATCH node] refactor Node local disk usage Message-ID: <1228948832-7649-1-git-send-email-apevec@redhat.com> use LVM partitions created by o-c-storage use file bindmounts for persisted configs add BOOTIF=link|eth* support Signed-off-by: Alan Pevec --- scripts/ovirt | 22 --- scripts/ovirt-early | 383 ++++++++++++++++------------------------------- scripts/ovirt-functions | 147 ++++++++++++++---- scripts/ovirt-post | 2 +- 4 files changed, 242 insertions(+), 312 deletions(-) mode change 100644 => 100755 scripts/ovirt diff --git a/scripts/ovirt b/scripts/ovirt old mode 100644 new mode 100755 index 81733a5..e2c406b --- a/scripts/ovirt +++ b/scripts/ovirt @@ -11,28 +11,6 @@ . /etc/init.d/ovirt-functions start() { - # retrieve config from local OVIRT partition if available - ovirt=$(mktemp -d) - ovirt_mount $ovirt - # /config on OVIRT partition contains persisted /etc files - cfg=$ovirt/config - if [ -d $cfg/etc ]; then - cp -rv $cfg/etc/* /etc - restorecon -r /etc - fi - # and optional Augeas augtool script - aug=$cfg/config.aug - if [ -f $aug ]; then - tmpaug=$(mktemp) - cp $aug $tmpaug - echo "save" >> $tmpaug - augtool < $tmpaug > /dev/null 2>&1 - if [ $? -eq 0 ]; then - printf "$aug applied." - fi - fi - umount $ovirt && rmdir $ovirt - if is_standalone; then exit 0 fi diff --git a/scripts/ovirt-early b/scripts/ovirt-early index c09a987..bcf55a3 100755 --- a/scripts/ovirt-early +++ b/scripts/ovirt-early @@ -10,8 +10,6 @@ . /etc/init.d/functions . /etc/init.d/ovirt-functions -# size of the oVirt partition in megabytes -OVIRT_SIZE=64 BONDING_MODCONF_FILE=/etc/modprobe.d/bonding AUGTOOL_CONFIG=/var/tmp/augtool-config @@ -80,11 +78,26 @@ configure_from_network() { echo "Default config applied" } -# find_disk $bus $serial $live_disk +# $(get_live_disk) +# livecd boot disk +get_live_disk() { + local live_dev=/dev/live + if [ ! -e $live_dev ]; then + # PXE boot + live_dev=/dev/loop0 + live_disk= + else + live_part=$(readlink -e $live_dev) + live_disk=$(basename $(dirname $(udevinfo --name=$live_part --query=path))) + fi + echo $live_disk +} + +# find_disk $bus $serial find_disk() { local bus=$1 local serial=$2 - local live=$3 + local live=$(get_live_disk) for d in /dev/disk/by-id/{scsi,usb}*; do ID_FS_USAGE= eval $(udevinfo --query env --name $d) @@ -104,216 +117,10 @@ find_disk() { return 1 } -# TODO move to ovirt-config-storage -# local_install $local_boot $local_disk $bootparams -# local_boot - 1=install LiveOS and boot loader -# 0=initialize oVirt partition only -# local_disk - local disk to hold the oVirt partition -# =usb|scsi[:serial#] -# bootparams - extra boot parameters like console= -# -# oVirt partition is a local primary ext2 partition, labeled OVIRT -# content: -# /config - local oVirt configuration (ktab, local admin password) -# /boot - boot loader, kernel and initramfs -# /LiveOS - oVirt Node compressed livecd image - -local_install() { - local local_boot=$1 - local local_disk=$2 - local bootparams=$3 - local disk - local part - local live_part - local live_disk - local live_dev=/dev/live - if [ ! -e $live_dev ]; then - # PXE boot - live_dev=/dev/loop0 - live_part=$live_dev - live_disk= - else - live_part=$(readlink -e $live_dev) - live_disk=${live_disk%[1-9]} - fi - local ovirt_part=$(readlink -e /dev/disk/by-label/$OVIRT_LABEL) - local ovirt_disk=${ovirt_part%[1-9]} - if [ "$ovirt_disk" = "$ovirt_part" ]; then - ovirt_disk= - fi - if [ -z "$local_disk" ]; then - if [ -z "$ovirt_disk" ]; then - return 1 - fi - # ovirt_init not specified, use pre-labeled oVirt partition - mode=update - disk=$ovirt_disk - part=$ovirt_part - else - case "$local_disk" in - =) - # empty ovirt_init, use current live image device - mode=update - disk=$live_disk - part=$live_part - ;; - =scsi*) - bus=scsi - serial=${local_disk#=scsi:} - mode=install - ;; - =usb*) - bus=usb - serial=${local_disk#=usb:} - mode=install - ;; - *) - return 1 - ;; - esac - if [ $mode = "install" ]; then - if [ "$serial" = "=$bus" ]; then - serial= - fi - disk=$(find_disk $bus $serial $live_disk) - rc=$? - if [ $rc -ne 0 ]; then - echo "local disk '$local_disk' not available" - return 1 - fi - if [ -n "$ovirt_disk" ]; then - if [ "$disk" = "$ovirt_disk" ]; then - # local disk contains oVirt partition, select it for update - # TODO force reinstall option - mode=update - part=$ovirt_part - else - # remove label from oVirt partition, there can be only one - e2label $ovirt_part "" - fi - fi - fi - if [ "$mode" = "install" ]; then - printf "installing $disk..." | tee /dev/console - dd if=/dev/zero bs=4096 count=1 of=$disk \ - && parted -s $disk mklabel msdos \ - && parted -s $disk mkpart primary ext2 0.0 $OVIRT_SIZE \ - && partprobe -s $disk - if [ $? -ne 0 ]; then - echo "$disk partition creation failed"; return 1 - fi - part=${disk}1 - udevsettle - mkfs.ext2 -L $OVIRT_LABEL $part \ - && tune2fs -c0 -i0 $part - if [ $? -ne 0 ]; then - echo "$disk ext2 creation failed"; return 1 - fi - # update by-label link manually, mkfs won't trigger udev - mkdir -p /dev/disk/by-label - ln -sf $part /dev/disk/by-label/$OVIRT_LABEL - fi - fi - - if [ "$mode" = "update" ]; then - printf "updating $disk..." | tee /dev/console - fi - ovirt=$(mktemp -d) - if [ "$part" = "$live_part" ]; then - # ovirt_init w/o local disk specified - # setup /config on live disk, if writeable - # TODO mlabel/e2label (check fs2 type or just blindly try?) - mount -r $part $ovirt && mount -o remount,rw $ovirt \ - && mkdir -p $ovirt/config - umount $ovirt && rmdir $ovirt - return 0 - fi - live=$(mktemp -d) - mount -r $live_dev $live - if [ $? -ne 0 ]; then - echo "source image mount failed" - rmdir $live - return 1 - fi - mount $part $ovirt - if [ $? -ne 0 ]; then - echo "local disk mount failed" - umount $live && rmdir $live - rmdir $ovirt - return 1 - fi - mkdir -p $ovirt/config - # update local config using the one embedded in livecd image - # TODO admin tool for adding /config into livecd image - if [ -d $live/config ]; then - cp -rv $live/config/* $ovirt/config \ - || echo "config copy failed" - fi - - if [ $local_boot = 0 ]; then - # config update only, cleanup and continue booting - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - else - # install oVirt Node image for local boot - if [ -e "$live/syslinux" ]; then - syslinux=syslinux - elif [ -e "$live/isolinux" ]; then - syslinux=isolinux - else - syslinux= - fi - rm -rf $ovirt/boot - rm -rf $ovirt/LiveOS - mkdir -p $ovirt/boot/grub - mkdir -p $ovirt/LiveOS - cp -p $live/LiveOS/squashfs.img $ovirt/LiveOS \ - && cp -p $live/$syslinux/initrd0.img $ovirt/boot \ - && cp -p $live/$syslinux/vmlinuz0 $ovirt/boot - if [ $? -ne 0 ]; then - echo "image copy failed" - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - return 1 - fi - part_num=$(( ${part#$disk} - 1 )) - cat > $ovirt/boot/grub/grub.conf << EOF -default=0 -timeout=2 -hiddenmenu -title oVirt Node - root (hd0,$part_num) - kernel /boot/vmlinuz0 ro root=LABEL=OVIRT roottypefs=ext2 liveimg $bootparams - initrd /boot/initrd0.img -EOF - grub-install --root-directory=$ovirt $disk >&2 - if [ $? -ne 0 ]; then - echo "boot loader install failed" - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - return 1 - fi - # remove 1.5 stages we don't need - find $ovirt/boot/grub -name '*_stage1_5' ! -name e2fs_stage1_5 \ - -exec rm {} \; - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - # FIXME avoid reboot loops - # temp. workaround: sync and wait - sync; sync; sync - printf "oVirt local installation finished, press Enter to reboot." \ - > /dev/console - read key - if [ "$key" = "debug" ]; then - sh > /dev/console 2>&1 - fi - reboot - fi -} start() { # oVirt boot parameters - # BOOTIF= (appended by pxelinux) + # BOOTIF=link|eth*| (appended by pxelinux) # ovirt_init=usb|scsi[:serial#] # ovirt_vol=BOOT_MB:SWAP_MB:ROOT_MB:CONFIG_MB:LOGGING_MB # ovirt_local_boot @@ -324,11 +131,14 @@ start() { # syslog=server[:port] # TBD logrotate maxsize - # BOOTIF= (appended by pxelinux) + # BOOTIF=link|eth*| (appended by pxelinux) # network boot interface is assumed to be on management network where # oVirt Server is reachable - # IPAPPEND 2 in pxelinux.cfg appends MAC address of the booting node - # e.g. BOOTIF=01-00-16-3e-12-34-57 + # BOOTIF= e.g. BOOTIF=01-00-16-3e-12-34-57 + # PXELINUX option IPAPPEND 2 in pxelinux.cfg appends MAC address + # of the booting node + # BOOTIF=link - take first eth for which ethtool reports link + # BOOTIF=eth* e.g. BOOTIF=eth0 - use given interface bootif= # ovirt_init=usb|scsi[:serial#] @@ -337,23 +147,23 @@ start() { # serial# - select exact disk using serial number, as reported by # udev ID_SERIAL # e.g. ovirt_init=usb:Generic_STORAGE_DEVICE_0000145418-0:0 - ovirt_init= + init= # ovirt_vol=BOOT_MB:SWAP_MB:ROOT_MB:CONFIG_MB:LOGGING_MB # local partition sizes in GB - ovirt_vol_boot= - ovirt_vol_swap= - ovirt_vol_root= - ovirt_vol_config= - ovirt_vol_logging= + vol_boot_size= + vol_swap_size= + vol_root_size= + vol_config_size= + vol_logging_size= # ovirt_local_boot # install/update oVirt Node image on the local installation target disk - ovirt_local_boot=0 + local_boot=0 # ovirt_standalone # force oVirt Node standalone mode - ovirt_standalone=0 + standalone=0 # pxelinux format: ip=::: # anaconda format: ip= netmask= gateway= @@ -376,25 +186,64 @@ start() { for i in $(cat /proc/cmdline); do case $i in - BOOTIF=??-??-??-??-??-??-??) - i=${i#BOOTIF=??-} - bootif=$(grep -il $(echo $i|sed 's/-/:/g') /sys/class/net/eth*/address|rev|cut -d/ -f2|rev) + BOOTIF=*) + i=${i#BOOTIF=} + case "$i" in + eth*) + bootif=$i + ;; + link) + for eth in $(cd /sys/class/net; echo eth*); do + if ethtool $eth 2>/dev/null|grep -q "Link detected: yes" + then + bootif=$eth + break + fi + done + ;; + ??-??-??-??-??-??-??) + i=${i#??-} + bootif=$(grep -il $(echo $i|sed 's/-/:/g') /sys/class/net/eth*/address|rev|cut -d/ -f2|rev) + ;; + esac ;; ovirt_init*) - ovirt_init=${i#ovirt_init} - if [ -z "$ovirt_init" ]; then - ovirt_init='=' + i=${i#ovirt_init} + if [ -n "$i" ]; then + # resolve to disk device + case "$i" in + =scsi*) + bus=scsi + i=${i#=scsi} + serial=${i#:} + ;; + =usb*) + bus=usb + i=${i#=usb} + serial=${i#:} + ;; + *) + bus= + serial= + ;; + esac + if [ -n "$bus" ]; then + init=$(find_disk $bus $serial) + fi + else + # 'ovirt_init' without value: grab first disk + init=/dev/sda fi ;; ovirt_vol=*) i=${i#ovirt_vol=} - eval $(printf $i|awk -F: '{print "ovirt_vol_boot="$1; ovirt_vol_swap="$2; print "ovirt_vol_root="$3; print "ovirt_vol_config="$4; print "ovirt_vol_logging="$5;}') + eval $(printf $i|awk -F: '{print "vol_boot_size="$1; print "vol_swap_size="$2; print "vol_root_size="$3; print "vol_config_size="$4; print "vol_logging_size="$5;}') ;; ovirt_local_boot*) - ovirt_local_boot=1 + local_boot=1 ;; ovirt_standalone*) - ovirt_standalone=1 + standalone=1 ;; ip=*) i=${i#ip=} @@ -418,41 +267,62 @@ start() { ;; esac done - # save boot parameters as defaults for ovirt-config-* + if [ -z "$ip_netmask" ]; then ip_netmask=$netmask fi if [ -z "$ip_gateway" ]; then ip_gateway=$gateway fi + # save boot parameters as defaults for ovirt-config-* + params="bootif init vol_boot_size vol_swap_size vol_root_size vol_config_size vol_logging_size local_boot standalone ip_address ip_netmask ip_gateway ipv6 syslog_server syslog_port bootparams" + mount_config + if [ -e $OVIRT_DEFAULTS ]; then + # update persisted defaults + tmpaug=$(mktemp) + for p in $params; do + PARAM=$(uc $p) + value=$(ptr $p) + if [ -n "$value" ] ; then + echo "set /files$OVIRT_DEFAULTS/OVIRT_$PARAM '\"$value\"'" \ + >> $tmpaug + fi + done + if [ -s $tmpaug ]; then + echo "save" >> $tmpaug + # augtool on bindmounted files fails, + # so edit file at persistent config root, /config + augtool -r /config < $tmpaug > /dev/null + fi + else + # initial startup, dump all ovirt bootparams + echo > $OVIRT_DEFAULTS + for p in $params; do + PARAM=$(uc $p) + echo "OVIRT_$PARAM='$(ptr $p)'" >> $OVIRT_DEFAULTS + done + ovirt_config_setup $OVIRT_DEFAULTS + fi - cat > $OVIRT_DEFAULTS </dev/null | (read MD5 filename; echo $MD5) +} + +# return uppercase value +uc() { + echo $(echo $1|tr '[[:lower:]]' '[[:upper:]]') +} + +# return indirect value +# non-bashism for ${!var} +ptr() { + local v=$1 + eval "v=\$$v" + echo $v +} + +# mount livecd media +# e.g. CD /dev/sr0, USB /dev/sda1, +# PXE /dev/loop0 (loopback ISO) +mount_live() { + if grep -q " /live " /proc/mounts; then + return 0 + fi + local live_dev=/dev/live + if [ ! -e $live_dev ]; then + # PXE boot + live_dev=/dev/loop0 + fi + mkdir -p /live + mount $live_dev /live +} + +# mount boot partition +# boot loader + kernel + initrd +mount_boot() { + if grep -q " /boot " /proc/mounts; then + return 0 + fi + mkdir -p /boot + mount /dev/disk/by-label/BOOT /boot +} + +# mount liveos partition +# LiveOS/ +mount_liveos() { + if grep -q " /liveos " /proc/mounts; then + return 0 + fi + mkdir -p /liveos + mount /dev/HostVG/Root /liveos +} + +# mount config partition +# /config for persistance +mount_config() { + if grep -q " /config " /proc/mounts; then + return 0 + fi + mkdir -p /config + mount /dev/HostVG/Config /config + if grep -q " /config " /proc/mounts; then + # TODO cp --update /live/config/ /config + # bind mount all persisted configs to rootfs + for f in $(find /config -type f); do + target=${f#/config} + if grep -q " $target " /proc/mounts ; then + # skip if already bind-mounted + true + else + mount -n --bind $f $target + fi + done else - mount -r /dev/live $1 \ - || mount /dev/live $1 + # /config is not available + return 1 fi } -md5() { - md5sum $1 2>/dev/null | (read MD5 filename; echo $MD5) +# unmount config bindmount /etc/config /etc/config2 ... +# +# augeas save fails on bindmounted files: +# https://fedorahosted.org/augeas/ticket/32 +# the same issue with sed -i +# +# After file is replaced, call ovirt_store_config /etc/config /etc/config2 ... +# to bindmount the config file again. +umount_config() { + if grep -q " /config " /proc/mounts; then + for f in "$@"; do + if grep -q " $f " /proc/mounts ; then + umount -n $f + # refresh rootfs copy + cp /config$f $f + fi + done + fi } -# persist configuration to /config on OVIRT partition +# persist configuration to /config # ovirt_store_config /etc/config /etc/config2 ... -ovirt_store_config() { - ovirt=$(mktemp -d) - ovirt_mount $ovirt - cfg=$ovirt/config - rw=0 - printf "store config:" - for f in "$@"; do - # ignore non-/etc paths - if [ $f != ${f#/etc/} ]; then - # check if changed - if [ "$(md5 $f)" != "$(md5 $cfg$f)" ]; then - if [ $rw = 0 ]; then - mount -o remount,rw $ovirt - rw=1 - fi - mkdir -p $cfg$(dirname $f) - cp $f $cfg$f - printf " $f" - fi - fi - done - echo - umount $ovirt && rmdir $ovirt +# copy to /config and bind-mount back +ovirt_config_setup() { + if grep -q " /config " /proc/mounts; then + printf "storing to /config :" + for f in "$@"; do + printf " $f" + # skip if already bind-mounted + if grep -q " $f " /proc/mounts ; then + printf " already persisted\n" + else + mkdir -p /config$(dirname $f) + cp -a $f /config$f \ + && mount -n --bind /config$f $f \ + || printf " failed to persist\n" + fi + done + echo + else + printf "warning: persistent config storage not available\n" + fi } + diff --git a/scripts/ovirt-post b/scripts/ovirt-post index 06506b7..a5bd930 100644 --- a/scripts/ovirt-post +++ b/scripts/ovirt-post @@ -12,7 +12,7 @@ start() { # persist selected configuration files - ovirt_store_config \ + ovirt_config_setup \ /etc/krb5.conf \ /etc/libvirt/krb5.tab \ /etc/ssh/ssh_host*_key* -- 1.6.0.4 From mmorsi at redhat.com Wed Dec 10 22:40:19 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Wed, 10 Dec 2008 17:40:19 -0500 Subject: [Ovirt-devel] [PATCH server] missing ovirt wui validations Message-ID: <1228948819-23516-1-git-send-email-mmorsi@redhat.com> This patch now contains all the validations and relevant fixes to the test suite. Additional tests asserting the new validations has not been written yet. Attached is additional validations, added to the rails model and controller layers verifying: bondings: arp related fields boot_types: label uniqueness and proto inclusion cpus: various fields are set and min values help_sections: presence and uniqueness of fields hosts: presence and format of various fields ip_addresses: fk existance / integrity nics: mac address format permissions: presence / inclusion of various fields pools: type inclusion quotas: minimum values smart_pool_tags: tagged_id / type fk present storage_pools: type, state field inclusion, min values storage_volumes: various fields, subclasses w/ various fields tasks: various fields present and consistensy maintained usages: label, other fields present, unique vms: uuid of correct format, min values, various fields present pools lft and rgt are not verified as they are added by acts_as_nested_set _after_ the pool is inserted into the db can only add / move host and storage volumes and pools to / from pools when you have sufficient permissions and target entities don't have associated vms can only destroy storage volumes / pools if there are no attached vms --- src/app/controllers/hardware_controller.rb | 28 ++++++++++++- src/app/controllers/storage_controller.rb | 7 +++ src/app/models/bonding.rb | 11 +++++ src/app/models/boot_type.rb | 5 ++ src/app/models/cpu.rb | 23 +++++++++++ src/app/models/help_section.rb | 34 ++++++++++++++++ src/app/models/host.rb | 21 ++++++++++ src/app/models/ip_address.rb | 4 ++ src/app/models/iscsi_storage_volume.rb | 2 + src/app/models/lvm_storage_volume.rb | 6 +++ src/app/models/nfs_storage_pool.rb | 1 + src/app/models/nic.rb | 11 +++++ src/app/models/permission.rb | 7 +++ src/app/models/pool.rb | 3 + src/app/models/quota.rb | 22 +++++++++++ src/app/models/smart_pool_tag.rb | 5 ++ src/app/models/storage_pool.rb | 17 ++++++++ src/app/models/storage_volume.rb | 21 ++++++++++ src/app/models/task.rb | 15 +++++++ src/app/models/usage.rb | 6 +++ src/app/models/vm.rb | 34 +++++++++++++++- src/test/fixtures/hosts.yml | 45 ++++++++++++++-------- src/test/fixtures/storage_pools.yml | 4 ++ src/test/functional/resources_controller_test.rb | 2 +- src/test/functional/storage_controller_test.rb | 4 +- 25 files changed, 315 insertions(+), 23 deletions(-) diff --git a/src/app/controllers/hardware_controller.rb b/src/app/controllers/hardware_controller.rb index 4dda736..cf45c49 100644 --- a/src/app/controllers/hardware_controller.rb +++ b/src/app/controllers/hardware_controller.rb @@ -303,15 +303,39 @@ class HardwareController < PoolController resource_ids_str = params[:resource_ids] resource_ids = resource_ids_str.split(",").collect {|x| x.to_i} + # if user doesn't have modify permission on both source and destination + unless @pool.can_modify(@user) and Pool.find(params[:target_pool_id]).can_modify(@user) + render :json => { :success => false, + :alert => "Cannot #{item_action.to_s} #{item_class.table_name.humanize} without admin permissions on both pools" } + return + end + + # relay error message if movable check fails for any resource + success = true + failed_resources = "" + resource_ids.each {|x| + unless item_class.find(x).movable? + success = false + failed_resources += x.to_s + " " + end + } + resource_ids.delete_if { |x| ! item_class.find(x).movable? } + begin @pool.transaction do @pool.send(item_method, resource_ids, target_pool_id) end + rescue + success = false + end + + if success render :json => { :success => true, :alert => "#{item_action.to_s} #{item_class.table_name.humanize} successful." } - rescue + else render :json => { :success => false, - :alert => "#{item_action.to_s} #{item_class.table_name.humanize} failed." } + :alert => "#{item_action.to_s} #{item_class.table_name.humanize} failed" + + (failed_resources == "" ? "." : " for " + failed_resources) } end end diff --git a/src/app/controllers/storage_controller.rb b/src/app/controllers/storage_controller.rb index 148d1be..47e9e14 100644 --- a/src/app/controllers/storage_controller.rb +++ b/src/app/controllers/storage_controller.rb @@ -310,6 +310,13 @@ class StorageController < ApplicationController end def destroy + unless @storage_pool.movable? + format.json { render :json => { :object => "storage_pool", + :success => false, + :alert => "Cannot delete storage with associated vms" } } + return + end + pool = @storage_pool.hardware_pool if @storage_pool.destroy alert="Storage Pool was successfully deleted." diff --git a/src/app/models/bonding.rb b/src/app/models/bonding.rb index c9af38c..fabdb67 100644 --- a/src/app/models/bonding.rb +++ b/src/app/models/bonding.rb @@ -30,6 +30,8 @@ # interface. They can be ignored if not used. # class Bonding < ActiveRecord::Base + + belongs_to :host belongs_to :bonding_type belongs_to :vlan @@ -58,6 +60,15 @@ class Bonding < ActiveRecord::Base validates_presence_of :vlan_id, :message => 'A vlan must be specified.' + # verify arp ping address to be ipv4 if set + validates_format_of :arp_ping_address, + :with => %r{^(\d{1,3}\.){3}\d{1,3}$}, + :unless => Proc.new { |bonding| bonding.arp_ping_address.nil? } + + validates_numericality_of :arp_interval, + :greater_than_or_equal_to => 0, + :unless => Proc.new { |bonding| bonding.arp_interval.nil? } + protected def validate if vlan.boot_type.proto == 'static' and ip_addresses.size == 0 diff --git a/src/app/models/boot_type.rb b/src/app/models/boot_type.rb index 8ffbe67..6cfdb04 100644 --- a/src/app/models/boot_type.rb +++ b/src/app/models/boot_type.rb @@ -18,4 +18,9 @@ # also available at http://www.gnu.org/copyleft/gpl.html. class BootType < ActiveRecord::Base + validates_presence_of :label + validates_uniqueness_of :label, + :message => 'Label must be unique' + validates_inclusion_of :proto, + :in => %w( static dhcp bootp ) end diff --git a/src/app/models/cpu.rb b/src/app/models/cpu.rb index 1a7d3cf..714a8ed 100644 --- a/src/app/models/cpu.rb +++ b/src/app/models/cpu.rb @@ -21,4 +21,27 @@ # class Cpu < ActiveRecord::Base belongs_to :host + + validates_presence_of :host_id, + :message => 'A host must be specified.' + + validates_numericality_of :cpu_number, + :greater_than_or_equal_to => 0 + + validates_numericality_of :core_number, + :greater_than_or_equal_to => 0 + + validates_numericality_of :number_of_cores, + :greater_than_or_equal_to => 1 + + validates_numericality_of :cpuid_level, + :greater_than_or_equal_to => 0 + + validates_numericality_of :speed, + :greater_than => 0 + # also verify speed in MHz ? + + validates_presence_of :vendor + validates_presence_of :model + validates_presence_of :family end diff --git a/src/app/models/help_section.rb b/src/app/models/help_section.rb index a891383..bd3e27c 100644 --- a/src/app/models/help_section.rb +++ b/src/app/models/help_section.rb @@ -1,2 +1,36 @@ +# Copyright (C) 2008 Red Hat, Inc. +# Written by Mohammed Morsi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. +# +# +HelpSection+ defines a section of the web help document to be +# available for a specific controller / action +# class HelpSection < ActiveRecord::Base + + validates_uniqueness_of :action, + :scope => :controller, + :message => 'Controller / Action must be unique' + + validates_presence_of :controller, + :message => 'A controller must be specified.' + + validates_presence_of :action, + :message => 'An action must be specified.' + + validates_presence_of :section, + :message => 'A section must be specified.' end diff --git a/src/app/models/host.rb b/src/app/models/host.rb index 640782d..08f9282 100644 --- a/src/app/models/host.rb +++ b/src/app/models/host.rb @@ -51,6 +51,17 @@ class Host < ActiveRecord::Base [ :search_users, 'U', "search_users" ] ], :eager_load => :smart_pools + validates_presence_of :hardware_pool_id, + :message => 'A hardware pool id must be specified.' + + validates_presence_of :uuid, + :message => 'A uuid must be specified.' + + validates_presence_of :hostname, + :message => 'A hostname must be specified.' + + validates_presence_of :arch, + :message => 'An arch must be specified.' KVM_HYPERVISOR_TYPE = "KVM" HYPERVISOR_TYPES = [KVM_HYPERVISOR_TYPE] @@ -58,6 +69,12 @@ class Host < ActiveRecord::Base STATE_AVAILABLE = "available" STATES = [STATE_UNAVAILABLE, STATE_AVAILABLE] + validates_inclusion_of :hypervisor_type, + :in => HYPERVISOR_TYPES + + validates_inclusion_of :state, + :in => STATES + Task::COMPLETED_STATES + Task::WORKING_STATES + def memory_in_mb kb_to_mb(memory) end @@ -99,4 +116,8 @@ class Host < ActiveRecord::Base hardware_pool.search_users end + def movable? + return vms.size == 0 + end + end diff --git a/src/app/models/ip_address.rb b/src/app/models/ip_address.rb index 5d2e6af..3f246b1 100644 --- a/src/app/models/ip_address.rb +++ b/src/app/models/ip_address.rb @@ -24,4 +24,8 @@ class IpAddress < ActiveRecord::Base belongs_to :network belongs_to :nic belongs_to :bonding + + def validate + errors.add("id", "ip must be associated with foreign entity") if network_id.nil? and nic_id.nil? and bonding_id.nil? + end end diff --git a/src/app/models/iscsi_storage_volume.rb b/src/app/models/iscsi_storage_volume.rb index 48edbd8..fe2cbf5 100644 --- a/src/app/models/iscsi_storage_volume.rb +++ b/src/app/models/iscsi_storage_volume.rb @@ -31,4 +31,6 @@ class IscsiStorageVolume < StorageVolume return true end + validates_presence_of :lun + end diff --git a/src/app/models/lvm_storage_volume.rb b/src/app/models/lvm_storage_volume.rb index 8eb1f0e..38949ce 100644 --- a/src/app/models/lvm_storage_volume.rb +++ b/src/app/models/lvm_storage_volume.rb @@ -29,4 +29,10 @@ class LvmStorageVolume < StorageVolume def volume_create_params return lv_name, size, lv_owner_perms, lv_group_perms, lv_mode_perms end + + validates_presence_of :lv_name + validates_presence_of :lv_owner_perms + validates_presence_of :lv_group_perms + validates_presence_of :lv_mode_perms + end diff --git a/src/app/models/nfs_storage_pool.rb b/src/app/models/nfs_storage_pool.rb index 398e3f9..3b438c8 100644 --- a/src/app/models/nfs_storage_pool.rb +++ b/src/app/models/nfs_storage_pool.rb @@ -29,4 +29,5 @@ class NfsStoragePool < StoragePool def user_subdividable true end + end diff --git a/src/app/models/nic.rb b/src/app/models/nic.rb index 5649763..aa9c740 100644 --- a/src/app/models/nic.rb +++ b/src/app/models/nic.rb @@ -24,12 +24,23 @@ class Nic < ActiveRecord::Base has_and_belongs_to_many :bondings, :join_table => 'bondings_nics' + validates_presence_of :mac, + :message => 'A mac must be specified.' + + validates_format_of :mac, + :with => %r{^([0-9a-f]{2}([:-]|$)){6}$} + validates_presence_of :host_id, :message => 'A host must be specified.' validates_presence_of :physical_network_id, :message => 'A network must be specified.' + validates_numericality_of :bandwidth, + :greater_than_or_equal_to => 0 + + # validate 'bridge' or 'usage_type' attribute ? + protected def validate if physical_network.boot_type.proto == 'static' and ip_addresses.size == 0 diff --git a/src/app/models/permission.rb b/src/app/models/permission.rb index ece3da5..b3929ad 100644 --- a/src/app/models/permission.rb +++ b/src/app/models/permission.rb @@ -24,9 +24,12 @@ class Permission < ActiveRecord::Base has_many :child_permissions, :dependent => :destroy, :class_name => "Permission", :foreign_key => "inherited_from_id" + validates_presence_of :pool_id + validates_presence_of :uid validates_uniqueness_of :uid, :scope => [:pool_id, :inherited_from_id] + ROLE_SUPER_ADMIN = "Super Admin" ROLE_ADMIN = "Administrator" ROLE_USER = "User" @@ -44,6 +47,10 @@ class Permission < ActiveRecord::Base ROLE_USER => [PRIV_VIEW, PRIV_VM_CONTROL], ROLE_MONITOR => [PRIV_VIEW]} + + validates_inclusion_of :user_role, + :in => ROLES.keys + def self.invert_roles return_hash = {} ROLES.each do |role, privs| diff --git a/src/app/models/pool.rb b/src/app/models/pool.rb index 7034e79..f7cc774 100644 --- a/src/app/models/pool.rb +++ b/src/app/models/pool.rb @@ -52,6 +52,9 @@ class Pool < ActiveRecord::Base validates_presence_of :name validates_uniqueness_of :name, :scope => :parent_id + validates_inclusion_of :type, + :in => %w( DirectoryPool HardwarePool VmResourcePool SmartPool ) + # overloading this method such that we can use permissions.admins to get all the admins for an object has_many :permissions, :dependent => :destroy, :order => "id ASC" do def super_admins diff --git a/src/app/models/quota.rb b/src/app/models/quota.rb index fc52177..2a9e0f0 100644 --- a/src/app/models/quota.rb +++ b/src/app/models/quota.rb @@ -22,6 +22,28 @@ require 'util/ovirt' class Quota < ActiveRecord::Base belongs_to :pool + validates_presence_of :pool_id + + + validates_numericality_of :total_vcpus, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |quota| quota.total_vcpus.nil? } + + validates_numericality_of :total_vmemory, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |quota| quota.total_vmemory.nil? } + + validates_numericality_of :total_vnics, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |quota| quota.total_vnics.nil? } + + validates_numericality_of :total_storage, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |quota| quota.total_storage.nil? } + + validates_numericality_of :total_vms, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |quota| quota.total_vms.nil? } def total_vmemory_in_mb kb_to_mb(total_vmemory) diff --git a/src/app/models/smart_pool_tag.rb b/src/app/models/smart_pool_tag.rb index e135ddf..00bb5a7 100644 --- a/src/app/models/smart_pool_tag.rb +++ b/src/app/models/smart_pool_tag.rb @@ -31,6 +31,11 @@ class SmartPoolTag < ActiveRecord::Base validates_uniqueness_of :smart_pool_id, :scope => [:tagged_id, :tagged_type] + validates_presence_of :tagged_id + + validates_inclusion_of :tagged_type, + :in => %w( Pool StoragePool Host Vm ) + def tagged_type=(sType) super(sType.to_s.classify.constantize.base_class.to_s) end diff --git a/src/app/models/storage_pool.rb b/src/app/models/storage_pool.rb index bab7031..f9abb55 100644 --- a/src/app/models/storage_pool.rb +++ b/src/app/models/storage_pool.rb @@ -39,6 +39,13 @@ class StoragePool < ActiveRecord::Base validates_presence_of :hardware_pool_id + validates_inclusion_of :type, + :in => %w( IscsiStoragePool LvmStoragePool NfsStoragePool ) + + + validates_numericality_of :capacity, + :greater_than_or_equal_to => 0 + acts_as_xapian :texts => [ :ip_addr, :target, :export_path, :type ], :terms => [ [ :search_users, 'U', "search_users" ] ], :eager_load => :smart_pools @@ -54,6 +61,9 @@ class StoragePool < ActiveRecord::Base STATE_PENDING_DELETION = "pending_deletion" STATE_AVAILABLE = "available" + validates_inclusion_of :state, + :in => [ STATE_PENDING_SETUP, STATE_PENDING_DELETION, STATE_AVAILABLE] + def self.factory(type, params = {}) params[:state] = STATE_PENDING_SETUP unless params[:state] case type @@ -121,4 +131,11 @@ class StoragePool < ActiveRecord::Base end return_hash end + + def movable? + storage_volumes.each{ |x| + return false unless x.movable? + } + return true + end end diff --git a/src/app/models/storage_volume.rb b/src/app/models/storage_volume.rb index 39b72d5..0f490f8 100644 --- a/src/app/models/storage_volume.rb +++ b/src/app/models/storage_volume.rb @@ -32,10 +32,23 @@ class StorageVolume < ActiveRecord::Base end end + validates_presence_of :storage_pool_id + + + validates_numericality_of :size, + :greater_than_or_equal_to => 0, + :unless => Proc.new { |storage_volume| storage_volume.nil? } + + validates_inclusion_of :type, + :in => %w( IscsiStorageVolume LvmStorageVolume NfsStorageVolume ) + STATE_PENDING_SETUP = "pending_setup" STATE_PENDING_DELETION = "pending_deletion" STATE_AVAILABLE = "available" + validates_inclusion_of :state, + :in => [ STATE_PENDING_SETUP, STATE_PENDING_DELETION, STATE_AVAILABLE] + def self.factory(type, params = {}) params[:state] = STATE_PENDING_SETUP unless params[:state] case type @@ -131,4 +144,12 @@ class StorageVolume < ActiveRecord::Base return_hash end + def movable? + if vms.size > 0 or + (! lvm_storage_pool.nil? and ! lvm_storage_pool.movable?) + return false + end + return true + end + end diff --git a/src/app/models/task.rb b/src/app/models/task.rb index f231c18..cb715e7 100644 --- a/src/app/models/task.rb +++ b/src/app/models/task.rb @@ -45,6 +45,16 @@ class Task < ActiveRecord::Base COMPLETED_STATES = [STATE_FINISHED, STATE_FAILED, STATE_CANCELED] WORKING_STATES = [STATE_QUEUED, STATE_RUNNING, STATE_PAUSED] + validates_inclusion_of :type, + :in => %w( HostTask StorageTask StorageVolumeTask VmTask ) + + validates_inclusion_of :state, + :in => COMPLETED_STATES + WORKING_STATES + + # FIXME validate action depending on type / subclass + # validate task_target_id, task_type_id, arg, message + # depending on subclass, action, state + def cancel self[:state] = STATE_CANCELED save! @@ -71,4 +81,9 @@ class Task < ActiveRecord::Base "" end + def validate + errors.add("time_ended", "Tasks ends before its started") unless time_ended.nil? or time_started.nil? or time_ended > time_started + errors.add("time_started", "Tasks starts before its created") unless time_started.nil? or time_created.nil? or time_started > time_created + end + end diff --git a/src/app/models/usage.rb b/src/app/models/usage.rb index 353e8f4..59b0e48 100644 --- a/src/app/models/usage.rb +++ b/src/app/models/usage.rb @@ -18,4 +18,10 @@ class Usage < ActiveRecord::Base has_and_belongs_to_many :networks, :join_table => 'networks_usages' + + validates_presence_of :label + validates_presence_of :usage + + validates_uniqueness_of :usage + end diff --git a/src/app/models/vm.rb b/src/app/models/vm.rb index 227f343..4d66c63 100644 --- a/src/app/models/vm.rb +++ b/src/app/models/vm.rb @@ -34,7 +34,32 @@ class Vm < ActiveRecord::Base validates_presence_of :uuid, :description, :num_vcpus_allocated, :boot_device, :memory_allocated_in_mb, - :memory_allocated, :vnic_mac_addr + :memory_allocated, :vnic_mac_addr, + :vm_resource_pool_id + + validates_format_of :uuid, + :with => %r([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}) + + validates_numericality_of :needs_restart, + :greater_than_or_equal_to => 0, + :less_than_or_equal_to => 1, + :unless => Proc.new{ |vm| vm.needs_restart.nil? } + + validates_numericality_of :memory_used, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |vm| vm.memory_used.nil? } + + validates_numericality_of :vnc_port, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |vm| vm.vnc_port.nil? } + + validates_numericality_of :num_vcpus_allocated, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |vm| vm.num_vcpus_allocated.nil? } + + validates_numericality_of :memory_allocated, + :greater_than_or_equal_to => 0, + :unless => Proc.new{ |vm| vm.memory_allocated.nil? } acts_as_xapian :texts => [ :uuid, :description, :vnic_mac_addr, :state ], :terms => [ [ :search_users, 'U', "search_users" ] ], @@ -117,9 +142,14 @@ class Vm < ActiveRecord::Base STATE_SAVED => STATE_SAVED, STATE_RESTORING => STATE_RUNNING, STATE_MIGRATING => STATE_RUNNING, - STATE_CREATE_FAILED => STATE_CREATE_FAILED} + STATE_CREATE_FAILED => STATE_CREATE_FAILED, + STATE_INVALID => STATE_INVALID} TASK_STATE_TRANSITIONS = [] + validates_inclusion_of :state, + :in => EFFECTIVE_STATE.keys + + def get_hardware_pool pool = vm_resource_pool pool = pool.get_hardware_pool if pool diff --git a/src/test/fixtures/hosts.yml b/src/test/fixtures/hosts.yml index 31e7580..4b97053 100644 --- a/src/test/fixtures/hosts.yml +++ b/src/test/fixtures/hosts.yml @@ -5,7 +5,7 @@ prod_corp_com: memory: 18384 is_disabled: 0 state: available - hypervisor_type: xen + hypervisor_type: KVM hardware_pool: corp_com workstation_corp_com: uuid: 1f2a8694-961d-11dc-9387-001558c41534 @@ -13,7 +13,8 @@ workstation_corp_com: arch: i386 memory: 2048 is_disabled: 0 - hypervisor_type: qemu + state: available + hypervisor_type: KVM hardware_pool: corp_com macworkstation_qa_corp_com: uuid: 58a85f44-75fd-4934-805f-88e45b40d4b4 @@ -21,7 +22,8 @@ macworkstation_qa_corp_com: arch: mips memory: 2048 is_disabled: 0 - hypervisor_type: kvm + state: available + hypervisor_type: KVM hardware_pool: corp_com_qa fedoraworkstation_qa_corp_com: uuid: 520bbb34-6515-490e-9d07-0c8b14f76805 @@ -29,7 +31,8 @@ fedoraworkstation_qa_corp_com: arch: i386 memory: 2048 is_disabled: 1 - hypervisor_type: kvm + state: available + hypervisor_type: KVM hardware_pool: corp_com_qa pipeline_qa_corp_com: uuid: 2e422f66-324e-48d4-973f-0b91b33070f9 @@ -37,7 +40,8 @@ pipeline_qa_corp_com: arch: xeon memory: 1048576 is_disabled: 0 - hypervisor_type: kvm + state: available + hypervisor_type: KVM hardware_pool: corp_com_qa app_qa_corp_com: uuid: bb0ce7c7-f234-49ae-84b5-6f4fd8bddcaa @@ -45,7 +49,8 @@ app_qa_corp_com: arch: xeon memory: 16384 is_disabled: 0 - hypervisor_type: kvm + state: available + hypervisor_type: KVM hardware_pool: corp_com_qa issue_qa_corp_com: uuid: ec0d86de-657b-48f6-b7cc-e733a3f9a834 @@ -53,7 +58,8 @@ issue_qa_corp_com: arch: x86 memory: 4096 is_disabled: 0 - hypervisor_type: kvm + state: available + hypervisor_type: KVM hardware_pool: corp_com_qa db_dev_corp_com: uuid: 81c15560-dbf4-45f5-9b75-106cdbd63aeb @@ -61,7 +67,8 @@ db_dev_corp_com: arch: x86 memory: 4096 is_disabled: 0 - hypervisor_type: kvm + state: available + hypervisor_type: KVM hardware_pool: corp_com_dev mystation_dev_corp_com: uuid: 6ae3d22e-97e0-4d86-9712-5395b20a0f45 @@ -69,7 +76,8 @@ mystation_dev_corp_com: arch: i686 memory: 2048 is_disabled: 0 - hypervisor_type: xen + state: available + hypervisor_type: KVM hardware_pool: corp_com_dev node3_priv_ovirt_org: uuid: 75f8d5f3-faf0-4308-9f20-e4b03d013a27 @@ -77,16 +85,17 @@ node3_priv_ovirt_org: arch: x86_64 memory: 4194304 is_disabled: 0 - hypervisor_type: kvm - hardware_pool: default state: available + hypervisor_type: KVM + hardware_pool: default mailservers_managed_node: uuid: 182a8596-961d-11dc-9387-001558c41534 hostname: mail.mynetwork.com arch: i386 memory: 16384 is_disabled: 0 - hypervisor_type: kvm + state: available + hypervisor_type: KVM hardware_pool: corp_com_prod fileserver_managed_node: uuid: 928ad8172-9723-11dc-9387-001558c41534 @@ -94,7 +103,8 @@ fileserver_managed_node: arch: x86_64 memory: 32768 is_disabled: 0 - hypervisor_type: kvm + state: available + hypervisor_type: KVM hardware_pool: corp_com_prod ldapserver_managed_node: uuid: 919ae372-9156-11dc-9387-001558c41534 @@ -102,7 +112,8 @@ ldapserver_managed_node: arch: i386 memory: 16384 is_disabled: 0 - hypervisor_type: kvm + state: available + hypervisor_type: KVM hardware_pool: corp_com_prod buildserver_managed_node: uuid: 6293acd9-2784-11dc-9387-001558c41534 @@ -110,7 +121,8 @@ buildserver_managed_node: arch: x86_64 memory: 65536 is_disabled: 0 - hypervisor_type: kvm + state: available + hypervisor_type: KVM hardware_pool: corp_com_prod mediaserver_managed_node: uuid: 6293acd9-2784-11dc-9387-001558c41534 @@ -118,5 +130,6 @@ mediaserver_managed_node: arch: x86_64 memory: 65536 is_disabled: 0 - hypervisor_type: kvm + state: available + hypervisor_type: KVM hardware_pool: corp_com_prod diff --git a/src/test/fixtures/storage_pools.yml b/src/test/fixtures/storage_pools.yml index ac72f99..3cda6db 100644 --- a/src/test/fixtures/storage_pools.yml +++ b/src/test/fixtures/storage_pools.yml @@ -5,14 +5,18 @@ corp_com_ovirtpriv_storage: port: 3260 target: ovirtpriv:storage state: available + capacity: 1024 corp_com_nfs_ovirtnfs: hardware_pool: corp_com type: NfsStoragePool ip_addr: 192.168.50.2 export_path: /ovirtnfs + capacity: 1024 + state: available corp_com_dev_nfs_ovirtnfs: hardware_pool: corp_com_dev type: NfsStoragePool ip_addr: 192.168.50.3 export_path: /devnfs state: available + capacity: 1024 diff --git a/src/test/functional/resources_controller_test.rb b/src/test/functional/resources_controller_test.rb index 8e3989b..0312c0c 100644 --- a/src/test/functional/resources_controller_test.rb +++ b/src/test/functional/resources_controller_test.rb @@ -45,7 +45,7 @@ class ResourcesControllerTest < ActionController::TestCase def test_create assert_difference('VmResourcePool.count') do - post :create, :vm_resource_pool => { :name => 'foo_resource_pool' }, :parent_id => pools(:default).id + post :create, :pool => { :name => 'foo_resource_pool'}, :parent_id => pools(:default).id end assert_response :success diff --git a/src/test/functional/storage_controller_test.rb b/src/test/functional/storage_controller_test.rb index a448fdf..f08fe1b 100644 --- a/src/test/functional/storage_controller_test.rb +++ b/src/test/functional/storage_controller_test.rb @@ -69,11 +69,11 @@ class StorageControllerTest < Test::Unit::TestCase assert_not_nil assigns(:storage_pools) end - def test_create + def test_create_storage_controller 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', :export_path => '/tmp/path' } + post :create, :storage_type => 'NFS', :storage_pool => { :hardware_pool => hw_pool, :ip_addr => '111.121.131.141', :export_path => '/tmp/path', :state => 'available', :capacity => 1024 } assert_response :success -- 1.6.0.4 From apevec at redhat.com Wed Dec 10 22:56:56 2008 From: apevec at redhat.com (Alan Pevec) Date: Wed, 10 Dec 2008 23:56:56 +0100 Subject: [Ovirt-devel] [PATCH node] simplify autoinstall condition Message-ID: <1228949816-7710-1-git-send-email-apevec@redhat.com> If minimal boot time config parameters are specified, autoinstall is performed. Minimum are BOOTIF for choosing management NIC (IPv4 DHCP is assumed) and ovirt_init to select local disk drive to install LVM partitions (default volume sizes are used if ovirt_vol parameter is missing) --- scripts/ovirt-config-storage | 3 +-- scripts/ovirt-firstboot | 7 ++++++- scripts/ovirt-functions | 13 ------------- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage index e2ddec1..12091db 100755 --- a/scripts/ovirt-config-storage +++ b/scripts/ovirt-config-storage @@ -270,10 +270,9 @@ ROOT_SIZE=${OVIRT_VOL_ROOT_SIZE:-$default_root_size} CONFIG_SIZE=${OVIRT_VOL_CONFIG_SIZE:-$default_config_size} LOGGING_SIZE=${OVIRT_VOL_LOGGING_SIZE:-$default_logging_size} +DRIVE=$OVIRT_INIT if [ "$1" == "AUTO" ]; then - # In "AUTO" mode, OVIRT_INIT should be defined in the environment. - DRIVE=$OVIRT_INIT check_partition_sizes printf "Partitioning hard disk..." perform_partitioning diff --git a/scripts/ovirt-firstboot b/scripts/ovirt-firstboot index 8189864..e422774 100755 --- a/scripts/ovirt-firstboot +++ b/scripts/ovirt-firstboot @@ -35,7 +35,12 @@ start () plymouth --quit plymouth --wait - if is_auto_install; then + if [ -n "$OVIRT_BOOTIF" -a -n "$OVIRT_INIT" ] ; then + # perform autoinstall if minimal parameters are present: + # networking - OVIRT_BOOTIF, management NIC + # if other ip bootparams are not specified, IPv4 DHCP is assumed + # storage - OVIRT_INIT, local disk to use + # if ovirt_vol is not specified, default volume sizes are set ovirt-config-networking AUTO newrole -r system_r -t virtd_t -- -c 'ovirt-config-storage AUTO' ovirt-config-logging AUTO diff --git a/scripts/ovirt-functions b/scripts/ovirt-functions index c0ebc3a..3196d4b 100644 --- a/scripts/ovirt-functions +++ b/scripts/ovirt-functions @@ -26,19 +26,6 @@ is_standalone() { if is_managed; then return 1; else return 0; fi } -# is_auto_install -# return 0 if all required oVirt boot parameters are present -is_auto_install() { - test -n "$OVIRT_BOOTIF" \ - -a -n "$OVIRT_OVIRT_STANDALONE" \ - -a -n "$OVIRT_INIT" \ - -a -n "$OVIRT_VOL_BOOT_SIZE" \ - -a -n "$OVIRT_VOL_SWAP_SIZE" \ - -a -n "$OVIRT_VOL_ROOT_SIZE" \ - -a -n "$OVIRT_VOL_CONFIG_SIZE" \ - -a -n "$OVIRT_VOL_LOGGING_SIZE" -} - # find_srv SERVICE PROTO # # reads DNS SRV record -- 1.6.0.4 From lutter at redhat.com Wed Dec 10 23:55:38 2008 From: lutter at redhat.com (David Lutterkort) Date: Wed, 10 Dec 2008 15:55:38 -0800 Subject: [Ovirt-devel] Re: [PATCH server] API: add a call to list VMs for a user In-Reply-To: <1228941542-21128-1-git-send-email-lutter@redhat.com> References: <1228941542-21128-1-git-send-email-lutter@redhat.com> Message-ID: <494056FA.3080004@redhat.com> David Lutterkort wrote: > Going to the URL /vms will return a list of all the VM's for which the > current user has PRIV_VIEW permission. The VM info contains the host the VM > is running on (if any) I am not too happy with the way the permission check is done, because it hardcodes a whole lot of knowledge about permissions in the wrong place- if anybody knows a better way to do that, please let me know. David From pmyers at redhat.com Thu Dec 11 03:17:18 2008 From: pmyers at redhat.com (Perry Myers) Date: Wed, 10 Dec 2008 22:17:18 -0500 Subject: [Ovirt-devel] Updated instructions for building oVirt from rawhide (next) Message-ID: <4940863E.6030802@redhat.com> I've updated the oVirt website and added the following page: http://ovirt.org/rawhide-build-instructions.html which describes how to build oVirt from the next branch. Feedback on this process and sanity checking is appreciated! I also added: http://ovirt.org/rawhide-install-instructions.html which will replace the existing install instructions once we release 0.96. This procedure cannot be tested yet, since we have not yet released .96, but I put it up there as a preview of the new process. Thanks, Perry -- |=- Red Hat, Engineering, Emerging Technologies, Boston -=| |=- Email: pmyers at redhat.com -=| |=- Office: +1 412 474 3552 Mobile: +1 703 362 9622 -=| |=- GnuPG: E65E4F3D 88F9 F1C9 C2F3 1303 01FE 817C C5D2 8B91 E65E 4F3D -=| From apevec at redhat.com Thu Dec 11 10:37:19 2008 From: apevec at redhat.com (Alan Pevec) Date: Thu, 11 Dec 2008 11:37:19 +0100 Subject: [Ovirt-devel] [PATCH node] separate ovirt-config-boot for in-place image upgrades In-Reply-To: <1228948801-7623-1-git-send-email-apevec@redhat.com> References: <1228948801-7623-1-git-send-email-apevec@redhat.com> Message-ID: <1228991839-11164-1-git-send-email-apevec@redhat.com> XXX outstandig issue is /dev/vda support by grub, so if testing with 'fake' Node VMs, please switch to IDE, in domain XML: instead of --- Makefile.am | 1 + ovirt-node.spec.in | 6 +++ scripts/ovirt-config-boot | 85 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 0 deletions(-) create mode 100755 scripts/ovirt-config-boot diff --git a/Makefile.am b/Makefile.am index 9b54ae6..c5829f3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,6 +27,7 @@ EXTRA_DIST = \ scripts/collectd.conf.in \ scripts/ovirt \ scripts/ovirt-awake \ + scripts/ovirt-config-boot \ scripts/ovirt-config-logging \ scripts/ovirt-config-networking \ scripts/ovirt-config-password \ diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in index ef65bf0..0973af9 100644 --- a/ovirt-node.spec.in +++ b/ovirt-node.spec.in @@ -35,6 +35,7 @@ Requires: bind-utils # qemu-img RPM. Requires: qemu-img Requires: nc +Requires: grub Requires: /usr/sbin/crond ExclusiveArch: %{ix86} x86_64 @@ -87,6 +88,7 @@ cd - %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/logrotate.d %{__install} -p -m0755 scripts/ovirt-awake %{buildroot}%{_sbindir} +%{__install} -p -m0755 scripts/ovirt-config-boot %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-logging %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-networking %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-password %{buildroot}%{_sbindir} @@ -171,6 +173,7 @@ fi %files %defattr(-,root,root,0755) %{_sbindir}/ovirt-awake +%{_sbindir}/ovirt-config-boot %{_sbindir}/ovirt-config-logging %{_sbindir}/ovirt-config-networking %{_sbindir}/ovirt-config-password @@ -200,6 +203,9 @@ fi %doc ovirt-identify-node/COPYING %changelog +* Wed Dec 10 2008 Alan Pevec 0.96-0.1 +- ovirt-config-* setup scripts for standalone mode + * Thu Sep 11 2008 Chris Lalancette - 0.92 0.7 - Add the ovirt-install- and ovirt-uninstall-node scripts, and refactor post to accomodate diff --git a/scripts/ovirt-config-boot b/scripts/ovirt-config-boot new file mode 100755 index 0000000..2052dfa --- /dev/null +++ b/scripts/ovirt-config-boot @@ -0,0 +1,85 @@ +#!/bin/bash +# +# ovirt-config-boot - configure local boot disk partition + +# SYNOPSIS +# ovirt-config-boot livecd_path bootparams +# +# boot_disk - boot disk device e.g. /dev/sda +# +# livecd_path - where livecd media is mounted, +# parent of LiveOS and isolinux folders +# +# bootparams - extra boot parameters like console=... +# + +# Source functions library +. /etc/init.d/functions +. /etc/init.d/ovirt-functions + + +# local_boot_install livecd_path bootparams +# livecd_path -livecd media +# bootparams - extra boot parameters like console=... +# +# copy oVirt Node image to the local LVM /dev/HostVG +ovirt_boot_setup() { + local disk=$1 + local live=$2 + local bootparams=$3 + printf "installing oVirt Node image ..." + mount_boot + mount_liveos + # install oVirt Node image for local boot + if [ -e "$live/syslinux" ]; then + syslinux=syslinux + elif [ -e "$live/isolinux" ]; then + syslinux=isolinux + else + syslinux= + fi + rm -rf /boot/grub + rm -rf /liveos/LiveOS + mkdir -p /boot/grub + mkdir -p /liveos/LiveOS + cp -p $live/LiveOS/squashfs.img /liveos/LiveOS \ + && cp -p $live/$syslinux/initrd0.img /boot \ + && cp -p $live/$syslinux/vmlinuz0 /boot + rc=$? + if [ $rc -ne 0 ]; then + printf "image copy failed\n" + return $rc + fi + cat > /boot/grub/grub.conf << EOF +default=0 +timeout=2 +hiddenmenu +title oVirt Node + root (hd0,0) + kernel /vmlinuz0 ro root=/dev/HostVG/Root roottypefs=ext3 liveimg $bootparams + initrd /initrd0.img +EOF + # XXX vda - virtio block: + # doesn't show up in device.map + # grub-install has regexp [sh]d + # TODO check if/how cciss work + grub-install --root-directory=/boot $disk >&2 + rc=$? + if [ $rc -ne 0 ]; then + printf "boot loader install failed\n" + return $rc + fi + # remove unused 1.5 stages + find /boot/grub -name '*_stage1_5' ! -name e2fs_stage1_5 \ + -exec rm {} \; + # avoid reboot loops using Cobbler PXE only once + # Cobbler XMLRPC post-install trigger (XXX is there cobbler SRV record?): + # wget "http://192.168.50.2/cblr/svc/op/trig/mode/post/system/$(hostname)" + # -O /dev/null + sync; sync; sync + # caller decides when to reboot +} + + +ovirt_boot_setup $1 $2 $3 + -- 1.6.0.4 From halsaadi at thoughtworks.com Thu Dec 11 07:21:07 2008 From: halsaadi at thoughtworks.com (Hadi Al-Saadi) Date: Thu, 11 Dec 2008 12:51:07 +0530 Subject: [Ovirt-devel] help Message-ID: Dear ovirt support team , Greeting I want to know how i can load ISO image into ovirt ui, with the help of cobbler. I done recherche over the net for how to import ISO image into cobbler profile. and I didn't succeed to load new O/S like windows or x86_64 bit O/S. -Regards Hadi -------------- next part -------------- An HTML attachment was scrubbed... URL: From halsaadi at thoughtworks.com Thu Dec 11 14:08:46 2008 From: halsaadi at thoughtworks.com (Hadi Al-Saadi) Date: Thu, 11 Dec 2008 19:38:46 +0530 Subject: [Ovirt-devel] help Message-ID: Dear ovirt i have a problem cant load guest O/S after creating image thru cobbler image add --name=ubuntu-64-2 --file=nfs://$(hostname)/cobblernfs/Fedora-9-i386-DVD.iso when i choose from the drop list my image.. it queued it and after a while it give filed in the status from ovirt . second problem from the host itself i was ably to run x86_64 O/S with kvm thru the command kvm-qemu-system-x86_64 but from ovirt i cant run that it run normal command kvm-qemu .. if i give ps -ef i can see kvm command in the process -------------- next part -------------- An HTML attachment was scrubbed... URL: From pmyers at redhat.com Thu Dec 11 14:42:43 2008 From: pmyers at redhat.com (Perry Myers) Date: Thu, 11 Dec 2008 09:42:43 -0500 Subject: [Ovirt-devel] help In-Reply-To: References: Message-ID: <494126E3.5000108@redhat.com> Hadi Al-Saadi wrote: > > Dear ovirt > > > i have a problem > > cant load guest O/S after creating image thru > cobbler image add --name=ubuntu-64-2 > --file=nfs://$(hostname)/cobblernfs/Fedora-9-i386-DVD.iso > > when i choose from the drop list my image.. it queued it and after a > while it give filed in the status from ovirt . > Please provide logs from the appliance and the Nodes that you have booted. /var/log/ovirt-server/* on the appliance and /var/log/ovirt.log on the Nodes. > second problem > > > from the host itself i was ably to run x86_64 O/S with kvm thru the command > kvm-qemu-system-x86_64 I don't know what that command is. There is qemu-system-x86_64 which is used to emulate x86_64 without using hardware virtualization. But we don't support that, since emulation is too slow to be practical. We require hardware virtualization. Hardware virtualization support is provided by the processor (either Intel VT or AMD-V). And there are 32 and 64 bit processors that have this capability. If your processor is 64-bit and has VT or AMD-V then you can run the 64-bit version of the oVirt Node or a 64-bit version of a Linux OS (Ubuntu or Fedora) on it. In this case, your host OS can run virtual machines that are either 32 or 64 bit with full hardware assist. If your processor is 32 bit and has VT or AMD-V then you can only run the 32 bit version of the oVirt Node or host OS. This means you can only run 32 bit virtual machines with full hardware assist. If you try to run a 64 bit virtual machine it will have to be fully emulated since a 32 bit host cannot normally run a 64 bit guest. If you have a 64 bit processor but you have installed a 32 bit OS or the 32 bit Node, then you will only be able to run 32 bit guests. In this case, re-install your host with the x86_64 version of the OS or Node. Perry From halsaadi at thoughtworks.com Thu Dec 11 14:37:23 2008 From: halsaadi at thoughtworks.com (Hadi Al-Saadi) Date: Thu, 11 Dec 2008 20:07:23 +0530 Subject: [Ovirt-devel] help In-Reply-To: <494126E3.5000108@redhat.com> Message-ID: Dear perry, thanks for your respond. today we going to reinstall the host O/S to x86_64 bit O/S fedora-9 next cant load guest O/S after creating image thru > cobbler image add --name=ubuntu-64-2 > --file=nfs://$(hostname)/cobblernfs/Fedora-9-i386-DVD.iso it showing in ovirt ui in the task tab status failed. can we run windows O/S ?? and how ?? thanks and regards Perry Myers 12/11/2008 08:12 PM To Hadi Al-Saadi cc ovirt-devel at redhat.com Subject Re: [Ovirt-devel] help Hadi Al-Saadi wrote: > > Dear ovirt > > > i have a problem > > cant load guest O/S after creating image thru > cobbler image add --name=ubuntu-64-2 > --file=nfs://$(hostname)/cobblernfs/Fedora-9-i386-DVD.iso > > when i choose from the drop list my image.. it queued it and after a > while it give filed in the status from ovirt . > Please provide logs from the appliance and the Nodes that you have booted. /var/log/ovirt-server/* on the appliance and /var/log/ovirt.log on the Nodes. > second problem > > > from the host itself i was ably to run x86_64 O/S with kvm thru the command > kvm-qemu-system-x86_64 I don't know what that command is. There is qemu-system-x86_64 which is used to emulate x86_64 without using hardware virtualization. But we don't support that, since emulation is too slow to be practical. We require hardware virtualization. Hardware virtualization support is provided by the processor (either Intel VT or AMD-V). And there are 32 and 64 bit processors that have this capability. If your processor is 64-bit and has VT or AMD-V then you can run the 64-bit version of the oVirt Node or a 64-bit version of a Linux OS (Ubuntu or Fedora) on it. In this case, your host OS can run virtual machines that are either 32 or 64 bit with full hardware assist. If your processor is 32 bit and has VT or AMD-V then you can only run the 32 bit version of the oVirt Node or host OS. This means you can only run 32 bit virtual machines with full hardware assist. If you try to run a 64 bit virtual machine it will have to be fully emulated since a 32 bit host cannot normally run a 64 bit guest. If you have a 64 bit processor but you have installed a 32 bit OS or the 32 bit Node, then you will only be able to run 32 bit guests. In this case, re-install your host with the x86_64 version of the OS or Node. Perry -------------- next part -------------- An HTML attachment was scrubbed... URL: From halsaadi at thoughtworks.com Thu Dec 11 14:41:39 2008 From: halsaadi at thoughtworks.com (Hadi Al-Saadi) Date: Thu, 11 Dec 2008 20:11:39 +0530 Subject: [Ovirt-devel] help Message-ID: Dear perry, thanks for your respond. today we going to reinstall the host O/S to x86_64 bit O/S fedora-9 next cant load guest O/S after creating image thru > cobbler image add --name=ubuntu-64-2 > --file=nfs://$(hostname)/cobblernfs/Fedora-9-i386-DVD.iso it showing in ovirt ui in the task tab status failed. can we run windows O/S ?? and how ?? thanks and regards -------------- next part -------------- An HTML attachment was scrubbed... URL: From pmyers at redhat.com Thu Dec 11 14:58:37 2008 From: pmyers at redhat.com (Perry Myers) Date: Thu, 11 Dec 2008 09:58:37 -0500 Subject: [Ovirt-devel] help In-Reply-To: References: Message-ID: <49412A9D.9040202@redhat.com> Hadi Al-Saadi wrote: > > Dear perry, > > > thanks for your respond. > today we going to reinstall the host O/S to x86_64 bit O/S fedora-9 Ok. If you are using the 0.95 version of oVirt x86_64 Fedora 9 is good. If you are building from the source repositories in the 'next' branch, we have moved there to Fedora 10. We're about to release 0.96 of oVirt which will require Fedora 10 for the host OS. > next > > cant load guest O/S after creating image thru > > cobbler image add --name=ubuntu-64-2 > > --file=nfs://$(hostname)/cobblernfs/Fedora-9-i386-DVD.iso > it showing in ovirt ui in the task tab status failed. > > can we run windows O/S ?? and how ?? As I said in my last email: > > Please provide logs from the appliance and the Nodes that you have booted. /var/log/ovirt-server/* on the appliance and /var/log/ovirt.log on the Nodes. Perry From halsaadi at thoughtworks.com Thu Dec 11 15:25:46 2008 From: halsaadi at thoughtworks.com (Hadi Al-Saadi) Date: Thu, 11 Dec 2008 20:55:46 +0530 Subject: [Ovirt-devel] help Message-ID: log file of applance -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: mongrel.log Type: application/octet-stream Size: 4481 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: taskomatic.log Type: application/octet-stream Size: 19882 bytes Desc: not available URL: From halsaadi at thoughtworks.com Thu Dec 11 14:53:19 2008 From: halsaadi at thoughtworks.com (Hadi Al-Saadi) Date: Thu, 11 Dec 2008 20:23:19 +0530 Subject: [Ovirt-devel] help Message-ID: so u mean i will not be ably to download ovirt 0.95 with yum from ur website ?? -------------- next part -------------- An HTML attachment was scrubbed... URL: From apevec at redhat.com Thu Dec 11 16:16:53 2008 From: apevec at redhat.com (Alan Pevec) Date: Thu, 11 Dec 2008 17:16:53 +0100 Subject: [Ovirt-devel] [PATCH node] separate ovirt-config-boot for in-place image upgrades In-Reply-To: <1228991839-11164-1-git-send-email-apevec@redhat.com> References: <1228991839-11164-1-git-send-email-apevec@redhat.com> Message-ID: <1229012213-27356-1-git-send-email-apevec@redhat.com> --- Makefile.am | 1 + ovirt-node.spec.in | 6 ++ scripts/ovirt-config-boot | 116 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 0 deletions(-) create mode 100755 scripts/ovirt-config-boot diff --git a/Makefile.am b/Makefile.am index 9b54ae6..c5829f3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,6 +27,7 @@ EXTRA_DIST = \ scripts/collectd.conf.in \ scripts/ovirt \ scripts/ovirt-awake \ + scripts/ovirt-config-boot \ scripts/ovirt-config-logging \ scripts/ovirt-config-networking \ scripts/ovirt-config-password \ diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in index ef65bf0..0973af9 100644 --- a/ovirt-node.spec.in +++ b/ovirt-node.spec.in @@ -35,6 +35,7 @@ Requires: bind-utils # qemu-img RPM. Requires: qemu-img Requires: nc +Requires: grub Requires: /usr/sbin/crond ExclusiveArch: %{ix86} x86_64 @@ -87,6 +88,7 @@ cd - %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/logrotate.d %{__install} -p -m0755 scripts/ovirt-awake %{buildroot}%{_sbindir} +%{__install} -p -m0755 scripts/ovirt-config-boot %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-logging %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-networking %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-password %{buildroot}%{_sbindir} @@ -171,6 +173,7 @@ fi %files %defattr(-,root,root,0755) %{_sbindir}/ovirt-awake +%{_sbindir}/ovirt-config-boot %{_sbindir}/ovirt-config-logging %{_sbindir}/ovirt-config-networking %{_sbindir}/ovirt-config-password @@ -200,6 +203,9 @@ fi %doc ovirt-identify-node/COPYING %changelog +* Wed Dec 10 2008 Alan Pevec 0.96-0.1 +- ovirt-config-* setup scripts for standalone mode + * Thu Sep 11 2008 Chris Lalancette - 0.92 0.7 - Add the ovirt-install- and ovirt-uninstall-node scripts, and refactor post to accomodate diff --git a/scripts/ovirt-config-boot b/scripts/ovirt-config-boot new file mode 100755 index 0000000..f535620 --- /dev/null +++ b/scripts/ovirt-config-boot @@ -0,0 +1,116 @@ +#!/bin/bash +# +# ovirt-config-boot - configure local boot disk partition + +# SYNOPSIS +# ovirt-config-boot livecd_path bootparams +# +# boot_disk - boot disk device e.g. /dev/sda +# +# livecd_path - where livecd media is mounted, +# parent of LiveOS and isolinux folders +# +# bootparams - extra boot parameters like console=... +# + +# Source functions library +. /etc/init.d/functions +. /etc/init.d/ovirt-functions + + +# local_boot_install livecd_path bootparams +# livecd_path -livecd media +# bootparams - extra boot parameters like console=... +# +# copy oVirt Node image to the local LVM /dev/HostVG +ovirt_boot_setup() { + local disk=$1 + local live=$2 + local bootparams=$3 + printf "installing oVirt Node image ..." + mount_boot + mount_liveos + # install oVirt Node image for local boot + if [ -e "$live/syslinux" ]; then + syslinux=syslinux + elif [ -e "$live/isolinux" ]; then + syslinux=isolinux + else + syslinux= + fi + rm -rf /boot/grub + rm -rf /liveos/LiveOS + mkdir -p /boot/grub + mkdir -p /liveos/LiveOS + cp -p $live/LiveOS/squashfs.img /liveos/LiveOS \ + && cp -p $live/$syslinux/vmlinuz0 /boot + rc=$? + if [ $rc -ne 0 ]; then + printf "image copy failed\n" + return $rc + fi + # append LVM support to the livecd initramfs + tmpdir=$(mktemp -d) + cd $tmpdir + gzip -dc $live/$syslinux/initrd0.img | cpio -id init sbin/real-init + init_script=init + if [ -e sbin/real-init ]; then + # Fedora mkliveinitrd + init_script=sbin/real-init + fi + sed -i '/^\/sbin\/udev.*settle/ a \echo Scanning logical volumes\ +lvm vgscan --ignorelockingfailure\ +echo Activating logical volumes\ +lvm vgchange -ay --ignorelockingfailure HostVG \ +' $init_script + mkdir -p bin + bit= + if [ -e /lib64 ]; then + bit=64 + fi + mkdir -p lib$bit + if [ -e /sbin/lvm.static ]; then + cp /sbin/lvm.static bin/lvm + else + cp /sbin/lvm bin + # lvm is not static in Fedora + cp /lib$bit/libreadline.so.5 /lib$bit/libncurses.so.5 lib$bit + fi + ( printf "$init_script\nbin\nlib$bit" | cpio -H newc --quiet -o ) | + gzip -9 | + cat $live/$syslinux/initrd0.img - > /boot/initrd0.img + + cat > /boot/grub/grub.conf << EOF +default=0 +timeout=5 +hiddenmenu +title oVirt Node + root (hd0,0) + kernel /vmlinuz0 ro root=/dev/HostVG/Root roottypefs=ext3 liveimg $bootparams + initrd /initrd0.img +EOF + echo "(hd0) $disk" > /boot/grub/device.map + ( cd /usr/share/grub/*; cp -p stage? e2fs_stage1_5 /boot/grub ) + grub --device-map=/boot/grub/device.map > /dev/null < References: <1228948832-7649-1-git-send-email-apevec@redhat.com> Message-ID: <1229012273-27387-1-git-send-email-apevec@redhat.com> use LVM partitions created by o-c-storage use file bindmounts for persisted configs use optional /config from livecd image support for old and new udev versions add BOOTIF=link|eth* support Signed-off-by: Alan Pevec --- scripts/ovirt | 22 --- scripts/ovirt-early | 388 ++++++++++++++++------------------------------- scripts/ovirt-functions | 171 +++++++++++++++++---- scripts/ovirt-post | 2 +- 4 files changed, 269 insertions(+), 314 deletions(-) mode change 100644 => 100755 scripts/ovirt mode change 100644 => 100755 scripts/ovirt-post diff --git a/scripts/ovirt b/scripts/ovirt old mode 100644 new mode 100755 index 81733a5..e2c406b --- a/scripts/ovirt +++ b/scripts/ovirt @@ -11,28 +11,6 @@ . /etc/init.d/ovirt-functions start() { - # retrieve config from local OVIRT partition if available - ovirt=$(mktemp -d) - ovirt_mount $ovirt - # /config on OVIRT partition contains persisted /etc files - cfg=$ovirt/config - if [ -d $cfg/etc ]; then - cp -rv $cfg/etc/* /etc - restorecon -r /etc - fi - # and optional Augeas augtool script - aug=$cfg/config.aug - if [ -f $aug ]; then - tmpaug=$(mktemp) - cp $aug $tmpaug - echo "save" >> $tmpaug - augtool < $tmpaug > /dev/null 2>&1 - if [ $? -eq 0 ]; then - printf "$aug applied." - fi - fi - umount $ovirt && rmdir $ovirt - if is_standalone; then exit 0 fi diff --git a/scripts/ovirt-early b/scripts/ovirt-early index c09a987..527d806 100755 --- a/scripts/ovirt-early +++ b/scripts/ovirt-early @@ -10,8 +10,6 @@ . /etc/init.d/functions . /etc/init.d/ovirt-functions -# size of the oVirt partition in megabytes -OVIRT_SIZE=64 BONDING_MODCONF_FILE=/etc/modprobe.d/bonding AUGTOOL_CONFIG=/var/tmp/augtool-config @@ -61,6 +59,7 @@ configure_from_network() { else echo "Failed to retrieve configuration bundle" fi + rm $cfgdb fi fi fi @@ -80,14 +79,29 @@ configure_from_network() { echo "Default config applied" } -# find_disk $bus $serial $live_disk +# $(get_live_disk) +# livecd boot disk +get_live_disk() { + local live_dev=/dev/live + if [ ! -e $live_dev ]; then + # PXE boot + live_dev=/dev/loop0 + live_disk= + else + live_part=$(readlink -e $live_dev) + live_disk=$(basename $(dirname $(udev_info $live_part path))) + fi + echo $live_disk +} + +# find_disk $bus $serial find_disk() { local bus=$1 local serial=$2 - local live=$3 + local live=$(get_live_disk) for d in /dev/disk/by-id/{scsi,usb}*; do ID_FS_USAGE= - eval $(udevinfo --query env --name $d) + eval $(udev_info $d env) # ID_FS_USAGE is set for partitions if [ -z "$ID_FS_USAGE" -a "$ID_BUS" = "$bus" ]; then if [ -z "$serial" -o "$ID_SERIAL" = "$serial" ]; then @@ -104,216 +118,10 @@ find_disk() { return 1 } -# TODO move to ovirt-config-storage -# local_install $local_boot $local_disk $bootparams -# local_boot - 1=install LiveOS and boot loader -# 0=initialize oVirt partition only -# local_disk - local disk to hold the oVirt partition -# =usb|scsi[:serial#] -# bootparams - extra boot parameters like console= -# -# oVirt partition is a local primary ext2 partition, labeled OVIRT -# content: -# /config - local oVirt configuration (ktab, local admin password) -# /boot - boot loader, kernel and initramfs -# /LiveOS - oVirt Node compressed livecd image - -local_install() { - local local_boot=$1 - local local_disk=$2 - local bootparams=$3 - local disk - local part - local live_part - local live_disk - local live_dev=/dev/live - if [ ! -e $live_dev ]; then - # PXE boot - live_dev=/dev/loop0 - live_part=$live_dev - live_disk= - else - live_part=$(readlink -e $live_dev) - live_disk=${live_disk%[1-9]} - fi - local ovirt_part=$(readlink -e /dev/disk/by-label/$OVIRT_LABEL) - local ovirt_disk=${ovirt_part%[1-9]} - if [ "$ovirt_disk" = "$ovirt_part" ]; then - ovirt_disk= - fi - if [ -z "$local_disk" ]; then - if [ -z "$ovirt_disk" ]; then - return 1 - fi - # ovirt_init not specified, use pre-labeled oVirt partition - mode=update - disk=$ovirt_disk - part=$ovirt_part - else - case "$local_disk" in - =) - # empty ovirt_init, use current live image device - mode=update - disk=$live_disk - part=$live_part - ;; - =scsi*) - bus=scsi - serial=${local_disk#=scsi:} - mode=install - ;; - =usb*) - bus=usb - serial=${local_disk#=usb:} - mode=install - ;; - *) - return 1 - ;; - esac - if [ $mode = "install" ]; then - if [ "$serial" = "=$bus" ]; then - serial= - fi - disk=$(find_disk $bus $serial $live_disk) - rc=$? - if [ $rc -ne 0 ]; then - echo "local disk '$local_disk' not available" - return 1 - fi - if [ -n "$ovirt_disk" ]; then - if [ "$disk" = "$ovirt_disk" ]; then - # local disk contains oVirt partition, select it for update - # TODO force reinstall option - mode=update - part=$ovirt_part - else - # remove label from oVirt partition, there can be only one - e2label $ovirt_part "" - fi - fi - fi - if [ "$mode" = "install" ]; then - printf "installing $disk..." | tee /dev/console - dd if=/dev/zero bs=4096 count=1 of=$disk \ - && parted -s $disk mklabel msdos \ - && parted -s $disk mkpart primary ext2 0.0 $OVIRT_SIZE \ - && partprobe -s $disk - if [ $? -ne 0 ]; then - echo "$disk partition creation failed"; return 1 - fi - part=${disk}1 - udevsettle - mkfs.ext2 -L $OVIRT_LABEL $part \ - && tune2fs -c0 -i0 $part - if [ $? -ne 0 ]; then - echo "$disk ext2 creation failed"; return 1 - fi - # update by-label link manually, mkfs won't trigger udev - mkdir -p /dev/disk/by-label - ln -sf $part /dev/disk/by-label/$OVIRT_LABEL - fi - fi - - if [ "$mode" = "update" ]; then - printf "updating $disk..." | tee /dev/console - fi - ovirt=$(mktemp -d) - if [ "$part" = "$live_part" ]; then - # ovirt_init w/o local disk specified - # setup /config on live disk, if writeable - # TODO mlabel/e2label (check fs2 type or just blindly try?) - mount -r $part $ovirt && mount -o remount,rw $ovirt \ - && mkdir -p $ovirt/config - umount $ovirt && rmdir $ovirt - return 0 - fi - live=$(mktemp -d) - mount -r $live_dev $live - if [ $? -ne 0 ]; then - echo "source image mount failed" - rmdir $live - return 1 - fi - mount $part $ovirt - if [ $? -ne 0 ]; then - echo "local disk mount failed" - umount $live && rmdir $live - rmdir $ovirt - return 1 - fi - mkdir -p $ovirt/config - # update local config using the one embedded in livecd image - # TODO admin tool for adding /config into livecd image - if [ -d $live/config ]; then - cp -rv $live/config/* $ovirt/config \ - || echo "config copy failed" - fi - - if [ $local_boot = 0 ]; then - # config update only, cleanup and continue booting - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - else - # install oVirt Node image for local boot - if [ -e "$live/syslinux" ]; then - syslinux=syslinux - elif [ -e "$live/isolinux" ]; then - syslinux=isolinux - else - syslinux= - fi - rm -rf $ovirt/boot - rm -rf $ovirt/LiveOS - mkdir -p $ovirt/boot/grub - mkdir -p $ovirt/LiveOS - cp -p $live/LiveOS/squashfs.img $ovirt/LiveOS \ - && cp -p $live/$syslinux/initrd0.img $ovirt/boot \ - && cp -p $live/$syslinux/vmlinuz0 $ovirt/boot - if [ $? -ne 0 ]; then - echo "image copy failed" - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - return 1 - fi - part_num=$(( ${part#$disk} - 1 )) - cat > $ovirt/boot/grub/grub.conf << EOF -default=0 -timeout=2 -hiddenmenu -title oVirt Node - root (hd0,$part_num) - kernel /boot/vmlinuz0 ro root=LABEL=OVIRT roottypefs=ext2 liveimg $bootparams - initrd /boot/initrd0.img -EOF - grub-install --root-directory=$ovirt $disk >&2 - if [ $? -ne 0 ]; then - echo "boot loader install failed" - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - return 1 - fi - # remove 1.5 stages we don't need - find $ovirt/boot/grub -name '*_stage1_5' ! -name e2fs_stage1_5 \ - -exec rm {} \; - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - # FIXME avoid reboot loops - # temp. workaround: sync and wait - sync; sync; sync - printf "oVirt local installation finished, press Enter to reboot." \ - > /dev/console - read key - if [ "$key" = "debug" ]; then - sh > /dev/console 2>&1 - fi - reboot - fi -} start() { # oVirt boot parameters - # BOOTIF= (appended by pxelinux) + # BOOTIF=link|eth*| (appended by pxelinux) # ovirt_init=usb|scsi[:serial#] # ovirt_vol=BOOT_MB:SWAP_MB:ROOT_MB:CONFIG_MB:LOGGING_MB # ovirt_local_boot @@ -324,11 +132,14 @@ start() { # syslog=server[:port] # TBD logrotate maxsize - # BOOTIF= (appended by pxelinux) + # BOOTIF=link|eth*| (appended by pxelinux) # network boot interface is assumed to be on management network where # oVirt Server is reachable - # IPAPPEND 2 in pxelinux.cfg appends MAC address of the booting node - # e.g. BOOTIF=01-00-16-3e-12-34-57 + # BOOTIF= e.g. BOOTIF=01-00-16-3e-12-34-57 + # PXELINUX option IPAPPEND 2 in pxelinux.cfg appends MAC address + # of the booting node + # BOOTIF=link - take first eth for which ethtool reports link + # BOOTIF=eth* e.g. BOOTIF=eth0 - use given interface bootif= # ovirt_init=usb|scsi[:serial#] @@ -337,23 +148,23 @@ start() { # serial# - select exact disk using serial number, as reported by # udev ID_SERIAL # e.g. ovirt_init=usb:Generic_STORAGE_DEVICE_0000145418-0:0 - ovirt_init= + init= # ovirt_vol=BOOT_MB:SWAP_MB:ROOT_MB:CONFIG_MB:LOGGING_MB # local partition sizes in GB - ovirt_vol_boot= - ovirt_vol_swap= - ovirt_vol_root= - ovirt_vol_config= - ovirt_vol_logging= + vol_boot_size= + vol_swap_size= + vol_root_size= + vol_config_size= + vol_logging_size= # ovirt_local_boot # install/update oVirt Node image on the local installation target disk - ovirt_local_boot=0 + local_boot=0 # ovirt_standalone # force oVirt Node standalone mode - ovirt_standalone=0 + standalone=0 # pxelinux format: ip=::: # anaconda format: ip= netmask= gateway= @@ -376,25 +187,65 @@ start() { for i in $(cat /proc/cmdline); do case $i in - BOOTIF=??-??-??-??-??-??-??) - i=${i#BOOTIF=??-} - bootif=$(grep -il $(echo $i|sed 's/-/:/g') /sys/class/net/eth*/address|rev|cut -d/ -f2|rev) + BOOTIF=*) + i=${i#BOOTIF=} + case "$i" in + eth*) + bootif=$i + ;; + link) + for eth in $(cd /sys/class/net; echo eth*); do + if ethtool $eth 2>/dev/null|grep -q "Link detected: yes" + then + bootif=$eth + break + fi + done + ;; + ??-??-??-??-??-??-??) + i=${i#??-} + bootif=$(grep -il $(echo $i|sed 's/-/:/g') /sys/class/net/eth*/address|rev|cut -d/ -f2|rev) + ;; + esac ;; ovirt_init*) - ovirt_init=${i#ovirt_init} - if [ -z "$ovirt_init" ]; then - ovirt_init='=' + i=${i#ovirt_init} + if [ -n "$i" ]; then + # resolve to disk device + case "$i" in + =scsi*) + bus=scsi + i=${i#=scsi} + serial=${i#:} + ;; + =usb*) + bus=usb + i=${i#=usb} + serial=${i#:} + ;; + *) + bus= + serial= + ;; + esac + if [ -n "$bus" ]; then + init=$(find_disk $bus $serial) + fi + else + # 'ovirt_init' without value: grab first disk + init=/dev/sda fi ;; ovirt_vol=*) i=${i#ovirt_vol=} - eval $(printf $i|awk -F: '{print "ovirt_vol_boot="$1; ovirt_vol_swap="$2; print "ovirt_vol_root="$3; print "ovirt_vol_config="$4; print "ovirt_vol_logging="$5;}') + eval $(printf $i|awk -F: '{print "vol_boot_size="$1; print "vol_swap_size="$2; print "vol_root_size="$3; print "vol_config_size="$4; print "vol_logging_size="$5;}') ;; ovirt_local_boot*) - ovirt_local_boot=1 + local_boot=1 ;; ovirt_standalone*) - ovirt_standalone=1 + standalone=1 + bootparams="$bootparams $i" ;; ip=*) i=${i#ip=} @@ -418,41 +269,63 @@ start() { ;; esac done - # save boot parameters as defaults for ovirt-config-* + if [ -z "$ip_netmask" ]; then ip_netmask=$netmask fi if [ -z "$ip_gateway" ]; then ip_gateway=$gateway fi + # save boot parameters as defaults for ovirt-config-* + params="bootif init vol_boot_size vol_swap_size vol_root_size vol_config_size vol_logging_size local_boot standalone ip_address ip_netmask ip_gateway ipv6 syslog_server syslog_port bootparams" + mount_config + if [ -e $OVIRT_DEFAULTS ]; then + # update persisted defaults + tmpaug=$(mktemp) + for p in $params; do + PARAM=$(uc $p) + value=$(ptr $p) + if [ -n "$value" ] ; then + echo "set /files$OVIRT_DEFAULTS/OVIRT_$PARAM '\"$value\"'" \ + >> $tmpaug + fi + done + if [ -s $tmpaug ]; then + echo "save" >> $tmpaug + # augtool on bindmounted files fails, + # so edit file at persistent config root, /config + augtool -r /config < $tmpaug > /dev/null + rm $tmpaug + fi + else + # initial startup, dump all ovirt bootparams + echo > $OVIRT_DEFAULTS + for p in $params; do + PARAM=$(uc $p) + echo "OVIRT_$PARAM='$(ptr $p)'" >> $OVIRT_DEFAULTS + done + ovirt_config_setup $OVIRT_DEFAULTS + fi - cat > $OVIRT_DEFAULTS </dev/null | (read MD5 filename; echo $MD5) +} + +# return uppercase value +uc() { + echo $(echo $1|tr '[[:lower:]]' '[[:upper:]]') +} + +# return indirect value +# non-bashism for ${!var} +ptr() { + local v=$1 + eval "v=\$$v" + echo $v +} + +# mount livecd media +# e.g. CD /dev/sr0, USB /dev/sda1, +# PXE /dev/loop0 (loopback ISO) +mount_live() { + if grep -q " /live " /proc/mounts; then + return 0 + fi + local live_dev=/dev/live + if [ ! -e $live_dev ]; then + # PXE boot + live_dev=/dev/loop0 + fi + mkdir -p /live + mount $live_dev /live +} + +# mount boot partition +# boot loader + kernel + initrd +mount_boot() { + if grep -q " /boot " /proc/mounts; then + return 0 + fi + mkdir -p /boot + mount /dev/disk/by-label/BOOT /boot +} + +# mount liveos partition +# LiveOS/ +mount_liveos() { + if grep -q " /liveos " /proc/mounts; then + return 0 + fi + mkdir -p /liveos + mount /dev/HostVG/Root /liveos +} + +# mount config partition +# /config for persistance +mount_config() { + if grep -q " /config " /proc/mounts; then + return 0 + fi + mkdir -p /config + mount /dev/HostVG/Config /config + if grep -q " /config " /proc/mounts; then + # optional config embedded in the livecd image + if [ -e /live/config ]; then + cp -rv --update /live/config/* /config + fi + # bind mount all persisted configs to rootfs + for f in $(find /config -type f); do + target=${f#/config} + if grep -q " $target " /proc/mounts ; then + # skip if already bind-mounted + true + else + mount -n --bind $f $target + fi + done else - mount -r /dev/live $1 \ - || mount /dev/live $1 + # /config is not available + return 1 fi } -md5() { - md5sum $1 2>/dev/null | (read MD5 filename; echo $MD5) +# unmount config bindmount /etc/config /etc/config2 ... +# +# augeas save fails on bindmounted files: +# https://fedorahosted.org/augeas/ticket/32 +# the same issue with sed -i +# +# After file is replaced, call ovirt_store_config /etc/config /etc/config2 ... +# to bindmount the config file again. +umount_config() { + if grep -q " /config " /proc/mounts; then + for f in "$@"; do + if grep -q " $f " /proc/mounts ; then + umount -n $f + # refresh rootfs copy + cp /config$f $f + fi + done + fi } -# persist configuration to /config on OVIRT partition -# ovirt_store_config /etc/config /etc/config2 ... -ovirt_store_config() { - ovirt=$(mktemp -d) - ovirt_mount $ovirt - cfg=$ovirt/config - rw=0 - printf "store config:" - for f in "$@"; do - # ignore non-/etc paths - if [ $f != ${f#/etc/} ]; then - # check if changed - if [ "$(md5 $f)" != "$(md5 $cfg$f)" ]; then - if [ $rw = 0 ]; then - mount -o remount,rw $ovirt - rw=1 - fi - mkdir -p $cfg$(dirname $f) - cp $f $cfg$f - printf " $f" - fi - fi - done - echo - umount $ovirt && rmdir $ovirt +# persist configuration to /config +# ovirt_config_setup /etc/config /etc/config2 ... +# copy to /config and bind-mount back +ovirt_config_setup() { + if grep -q " /config " /proc/mounts; then + printf "storing to /config :" + for f in "$@"; do + printf " $f" + # skip if already bind-mounted + if grep -q " $f " /proc/mounts ; then + printf " already persisted\n" + else + mkdir -p /config$(dirname $f) + cp -a $f /config$f \ + && mount -n --bind /config$f $f \ + || printf " failed to persist\n" + fi + done + echo + else + printf "warning: persistent config storage not available\n" + fi +} + +# compat function to handle different udev versions +udev_info() { + local name=$1 + local query=$2 + local out + + # old udev command with shortopts + out=$(udevinfo -n $name -q $query) + rc=$? + if [ $rc -ne 0 ]; then + out=$(udevadm info --name=$name --query=$query) + rc=$? + fi + if [ $rc -eq 0 ]; then + echo $out + fi + return $rc } + diff --git a/scripts/ovirt-post b/scripts/ovirt-post old mode 100644 new mode 100755 index 06506b7..a5bd930 --- a/scripts/ovirt-post +++ b/scripts/ovirt-post @@ -12,7 +12,7 @@ start() { # persist selected configuration files - ovirt_store_config \ + ovirt_config_setup \ /etc/krb5.conf \ /etc/libvirt/krb5.tab \ /etc/ssh/ssh_host*_key* -- 1.6.0.4 From apevec at redhat.com Thu Dec 11 16:18:54 2008 From: apevec at redhat.com (Alan Pevec) Date: Thu, 11 Dec 2008 17:18:54 +0100 Subject: [Ovirt-devel] [PATCH node] simplify autoinstall condition In-Reply-To: <1228949816-7710-1-git-send-email-apevec@redhat.com> References: <1228949816-7710-1-git-send-email-apevec@redhat.com> Message-ID: <1229012334-27415-1-git-send-email-apevec@redhat.com> Autoinstall is performed when required boot parameters are specified: - BOOTIF=link|eth*|01-11-22-33-44-55-66 for choosing management NIC (IPv4 DHCP is assumed) - ovirt_init=usb|scsi to select a local disk drive to install LVM volumes if ovirt_vol parameter is missing, default volume sizes are used, BOOT 50MB SWAP 2 * RAM size ROOT 256MB CONFIG 5MB LOGGING 256MB DATA rest of the disk equivalent is ovirt_vol=50::256:5:256 --- scripts/ovirt-config-storage | 5 ++--- scripts/ovirt-firstboot | 7 ++++++- scripts/ovirt-functions | 13 ------------- 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage index e2ddec1..c6b6b61 100755 --- a/scripts/ovirt-config-storage +++ b/scripts/ovirt-config-storage @@ -262,7 +262,7 @@ case $MEM_SIZE in ''|*[^0-9]*) die failed to get system memory size;; esac -MEM_SIZE=$(echo "scale=0; $MEM_SIZE / 1024" | bc -l) +MEM_SIZE=$(echo "scale=0; $MEM_SIZE / 1024 * 2" | bc -l) SWAP_SIZE=${OVIRT_VOL_SWAP_SIZE:-$MEM_SIZE} BOOT_SIZE=${OVIRT_VOL_BOOT_SIZE:-$default_boot_size} @@ -270,10 +270,9 @@ ROOT_SIZE=${OVIRT_VOL_ROOT_SIZE:-$default_root_size} CONFIG_SIZE=${OVIRT_VOL_CONFIG_SIZE:-$default_config_size} LOGGING_SIZE=${OVIRT_VOL_LOGGING_SIZE:-$default_logging_size} +DRIVE=$OVIRT_INIT if [ "$1" == "AUTO" ]; then - # In "AUTO" mode, OVIRT_INIT should be defined in the environment. - DRIVE=$OVIRT_INIT check_partition_sizes printf "Partitioning hard disk..." perform_partitioning diff --git a/scripts/ovirt-firstboot b/scripts/ovirt-firstboot index 8189864..eb22d07 100755 --- a/scripts/ovirt-firstboot +++ b/scripts/ovirt-firstboot @@ -35,7 +35,12 @@ start () plymouth --quit plymouth --wait - if is_auto_install; then + if [ -n "$OVIRT_BOOTIF" -a -n "$OVIRT_INIT" ] ; then + # perform autoinstall if following parameters are present: + # networking - OVIRT_BOOTIF, management NIC + # if other ip bootparams are not specified, IPv4 DHCP is assumed + # storage - OVIRT_INIT, local disk to use + # if ovirt_vol is not specified, default volume sizes are set ovirt-config-networking AUTO newrole -r system_r -t virtd_t -- -c 'ovirt-config-storage AUTO' ovirt-config-logging AUTO diff --git a/scripts/ovirt-functions b/scripts/ovirt-functions index 79081b5..7f4c205 100644 --- a/scripts/ovirt-functions +++ b/scripts/ovirt-functions @@ -26,19 +26,6 @@ is_standalone() { if is_managed; then return 1; else return 0; fi } -# is_auto_install -# return 0 if all required oVirt boot parameters are present -is_auto_install() { - test -n "$OVIRT_BOOTIF" \ - -a -n "$OVIRT_OVIRT_STANDALONE" \ - -a -n "$OVIRT_INIT" \ - -a -n "$OVIRT_VOL_BOOT_SIZE" \ - -a -n "$OVIRT_VOL_SWAP_SIZE" \ - -a -n "$OVIRT_VOL_ROOT_SIZE" \ - -a -n "$OVIRT_VOL_CONFIG_SIZE" \ - -a -n "$OVIRT_VOL_LOGGING_SIZE" -} - # find_srv SERVICE PROTO # # reads DNS SRV record -- 1.6.0.4 From apevec at redhat.com Thu Dec 11 16:19:12 2008 From: apevec at redhat.com (Alan Pevec) Date: Thu, 11 Dec 2008 17:19:12 +0100 Subject: [Ovirt-devel] [PATCH node] show firstboot menu only once Message-ID: <1229012352-27442-1-git-send-email-apevec@redhat.com> --- scripts/ovirt-firstboot | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/scripts/ovirt-firstboot b/scripts/ovirt-firstboot index eb22d07..765c80e 100755 --- a/scripts/ovirt-firstboot +++ b/scripts/ovirt-firstboot @@ -44,9 +44,15 @@ start () ovirt-config-networking AUTO newrole -r system_r -t virtd_t -- -c 'ovirt-config-storage AUTO' ovirt-config-logging AUTO - else + elif [ -z "$OVIRT_FIRSTBOOT" -o "$OVIRT_FIRSTBOOT" = "yes" ]; then ovirt-config-setup fi + if mount_config; then + augtool -r /config < Howdy Folks :) So in my working with taskomatic, I noticed that the save/resume functionality seems a bit broken. The first thing I noticed was that libvirt itself has no concept of a separate state for 'saved', which ovirt attempts to maintain. This could work fine but when a node is disconnected and then reconnected, the state will shift to 'unavailable' and then to 'stopped' when it reconnects. There may be other corner cases where this does not work as well. The other issue is that it saves the image to /tmp on the local node. This is usually (always?) a memory based FS and so it will be lost on reboot of the node. It also does not allow for resume on a different host, and presently is not removed after resume so the FS will eventually fill up with a few save/resume cycles. To fix all this I'm thinking we should save our images on a designated storage device, using a new field in the vm database to denote that it is saved, perhaps with the path to the saved image. Once restored or started the image should be deleted. Ian From pmyers at redhat.com Thu Dec 11 16:25:31 2008 From: pmyers at redhat.com (Perry Myers) Date: Thu, 11 Dec 2008 11:25:31 -0500 Subject: [Ovirt-devel] Save/Resume Issues In-Reply-To: <20081211082124.7655a8da@tp.mains.net> References: <20081211082124.7655a8da@tp.mains.net> Message-ID: <49413EFB.5020900@redhat.com> Ian Main wrote: > > Howdy Folks :) > > So in my working with taskomatic, I noticed that the save/resume functionality seems a bit broken. The first thing I noticed was that libvirt itself has no concept of a separate state for 'saved', which ovirt attempts to maintain. This could work fine but when a node is disconnected and then reconnected, the state will shift to 'unavailable' and then to 'stopped' when it reconnects. There may be other corner cases where this does not work as well. > > The other issue is that it saves the image to /tmp on the local node. This is usually (always?) a memory based FS and so it will be lost on reboot of the node. It also does not allow for resume on a different host, and presently is not removed after resume so the FS will eventually fill up with a few save/resume cycles. > > To fix all this I'm thinking we should save our images on a designated storage device, using a new field in the vm database to denote that it is saved, perhaps with the path to the saved image. Once restored or started the image should be deleted. One of the things we need to think about re: the above is how this interacts with libvirt functionality for snapshotting storage. The two mechanisms should be independent, but will need to be used together at times. libvirt snapshotting has not even been designed yet, so perhaps this discussion needs to happen on libvir-list? Perry From clalance at redhat.com Thu Dec 11 16:25:49 2008 From: clalance at redhat.com (Chris Lalancette) Date: Thu, 11 Dec 2008 17:25:49 +0100 Subject: [Ovirt-devel] Save/Resume Issues In-Reply-To: <20081211082124.7655a8da@tp.mains.net> References: <20081211082124.7655a8da@tp.mains.net> Message-ID: <49413F0D.3010202@redhat.com> Ian Main wrote: > > Howdy Folks :) > > So in my working with taskomatic, I noticed that the save/resume > functionality seems a bit broken. The first thing I noticed was that libvirt > itself has no concept of a separate state for 'saved', which ovirt attempts > to maintain. This could work fine but when a node is disconnected and then > reconnected, the state will shift to 'unavailable' and then to 'stopped' when > it reconnects. There may be other corner cases where this does not work as > well. > > The other issue is that it saves the image to /tmp on the local node. This > is usually (always?) a memory based FS and so it will be lost on reboot of > the node. It also does not allow for resume on a different host, and > presently is not removed after resume so the FS will eventually fill up with > a few save/resume cycles. > > To fix all this I'm thinking we should save our images on a designated > storage device, using a new field in the vm database to denote that it is > saved, perhaps with the path to the saved image. Once restored or started > the image should be deleted. Yes, sorry, Jim and I had a discussion about this on IRC the other day, I should have sent mail. You are basically exactly right; in it's current incarnation save/restore is 100% completely broken. Basically, we need what you say; the user needs to configure a "save pool" (probably per hardware pool), and then on a save we write to that pool, and store something in the database with a pointer to the filename. On a restore, we read that filename back, restore the image, and delete the restore file. I'm sure there are state problems like you point out as well. -- Chris Lalancette From imain at redhat.com Thu Dec 11 17:51:42 2008 From: imain at redhat.com (Ian Main) Date: Thu, 11 Dec 2008 09:51:42 -0800 Subject: [Ovirt-devel] Save/Resume Issues In-Reply-To: <20081211082124.7655a8da@tp.mains.net> References: <20081211082124.7655a8da@tp.mains.net> Message-ID: <20081211095142.5165ab77@tp.mains.net> On Thu, 11 Dec 2008 08:21:24 -0800 Ian Main wrote: > > > Howdy Folks :) > > So in my working with taskomatic, I noticed that the save/resume functionality seems a bit broken. The first thing I noticed was that libvirt itself has no concept of a separate state for 'saved', which ovirt attempts to maintain. This could work fine but when a node is disconnected and then reconnected, the state will shift to 'unavailable' and then to 'stopped' when it reconnects. There may be other corner cases where this does not work as well. > > The other issue is that it saves the image to /tmp on the local node. This is usually (always?) a memory based FS and so it will be lost on reboot of the node. It also does not allow for resume on a different host, and presently is not removed after resume so the FS will eventually fill up with a few save/resume cycles. > > To fix all this I'm thinking we should save our images on a designated storage device, using a new field in the vm database to denote that it is saved, perhaps with the path to the saved image. Once restored or started the image should be deleted. I should also mention that presently, because we use db-omatic to write state back to the database, save/restore will be broken in the UI as well. When you click 'save' it will save the VM and then the state will go to 'stopped' because db-omatic will see the change in libvirt but libvirt doesn't differentiate stopped from saved. If we add the database field to point to the saved image this would let us know that it was stopped and could be restored from image or started again. Ian From bkearney at redhat.com Thu Dec 11 18:36:38 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Thu, 11 Dec 2008 13:36:38 -0500 Subject: [Ovirt-devel] [PATCH node-image] db4 is needed by standalone mode to create SASL users Message-ID: <1229020598-23146-1-git-send-email-bkearney@redhat.com> --- common-blacklist.ks | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/common-blacklist.ks b/common-blacklist.ks index e05307d..98c6edd 100644 --- a/common-blacklist.ks +++ b/common-blacklist.ks @@ -18,7 +18,7 @@ RPMS="$RPMS kpartx mkinitrd isomd5sum dmraid checkpolicy" # Remove additional RPMs forcefully RPMS="$RPMS gamin pm-utils kbd usermode vbetool ConsoleKit hdparm \ efibootmgr krb5-workstation linux-atm-libs fedora-release-notes \ - slang psmisc gdbm cryptsetup-luks pciutils mtools syslinux db4 \ + slang psmisc gdbm cryptsetup-luks pciutils mtools syslinux \ wireless-tools radeontool cracklib-dicts cracklib libicu gnupg2 \ fedora-logos" -- 1.6.0.4 From bkearney at redhat.com Thu Dec 11 19:03:00 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Thu, 11 Dec 2008 14:03:00 -0500 Subject: [Ovirt-devel] Partitioning error running a standalone F-10 node Message-ID: <494163E4.9070905@redhat.com> I ran a standalone node in a vm with a 1 Gig disk. I selected the parition option, and configured the total to be less than 10 gig (The defaults were over a gig). I got the following error: Volume group "VG" not found Can't remove open logical volume "Swap" 1+0 records in 1+0 records out 1024 bytes (1.0 kB) copied BLKRRPART: Device or resource busy Did I miss a setup step? -- bk From sseago at redhat.com Thu Dec 11 19:16:54 2008 From: sseago at redhat.com (Scott Seago) Date: Thu, 11 Dec 2008 19:16:54 +0000 Subject: [Ovirt-devel] [PATCH] fix for Bug 466719 Message-ID: <1229023014-4066-1-git-send-email-sseago@redhat.com> fix for Bug 466719: VM pool sort by load no longer causes server errors. It's still not doing anything useful yet, but that won't come until we update the stats code to aggregate something useful in the new pools load_average column. Signed-off-by: Scott Seago --- src/app/views/resources/_grid.rhtml | 2 +- src/db/migrate/032_add_pool_load.rb | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletions(-) create mode 100644 src/db/migrate/032_add_pool_load.rb diff --git a/src/app/views/resources/_grid.rhtml b/src/app/views/resources/_grid.rhtml index 908eac7..9b5e1c2 100644 --- a/src/app/views/resources/_grid.rhtml +++ b/src/app/views/resources/_grid.rhtml @@ -15,7 +15,7 @@ colModel : [ {display: '', name : 'id', width : 20, sortable : false, align: 'left', process: <%= table_id %>checkbox}, {display: 'Name', name : 'name', width : 160, sortable : true, align: 'left'}, - {display: 'Load', name : 'load', width: 180, sortable : false, align: 'left', process: <%= table_id %>_load_widget } + {display: 'Load', name : 'load_average', width: 180, sortable : false, align: 'left', process: <%= table_id %>_load_widget } ], sortname: "name", sortorder: "asc", diff --git a/src/db/migrate/032_add_pool_load.rb b/src/db/migrate/032_add_pool_load.rb new file mode 100644 index 0000000..fbb1b55 --- /dev/null +++ b/src/db/migrate/032_add_pool_load.rb @@ -0,0 +1,28 @@ +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Scott Seago +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +class AddPoolLoad < ActiveRecord::Migration + def self.up + add_column :pools, :load_average, :float + end + + def self.down + drop_column :pools, :load_average + end +end -- 1.6.0.4 From sseago at redhat.com Thu Dec 11 20:42:59 2008 From: sseago at redhat.com (Scott Seago) Date: Thu, 11 Dec 2008 15:42:59 -0500 Subject: [Ovirt-devel] [PATCH server] missing ovirt wui validations In-Reply-To: <1228948819-23516-1-git-send-email-mmorsi@redhat.com> References: <1228948819-23516-1-git-send-email-mmorsi@redhat.com> Message-ID: <49417B53.7040707@redhat.com> Mohammed Morsi wrote: > This patch now contains all the validations and relevant > fixes to the test suite. Additional tests asserting the > new validations has not been written yet. > > Attached is additional validations, added to the rails model > and controller layers verifying: > bondings: arp related fields > boot_types: label uniqueness and proto inclusion > cpus: various fields are set and min values > help_sections: presence and uniqueness of fields > hosts: presence and format of various fields > ip_addresses: fk existance / integrity > nics: mac address format > permissions: presence / inclusion of various fields > pools: type inclusion > quotas: minimum values > smart_pool_tags: tagged_id / type fk present > storage_pools: type, state field inclusion, min values > storage_volumes: various fields, subclasses w/ various fields > tasks: various fields present and consistensy maintained > usages: label, other fields present, unique > vms: uuid of correct format, min values, various fields present > > pools lft and rgt are not verified as they are added by > acts_as_nested_set _after_ the pool is inserted into the db > > I haven't tested them yet, but after a brief look over the validations it seems fine to me. I can probably bring up a WUI with these in place sometime tomorrow to test the validations for components with UI forms -- but we'll have to leave it to the test framework to test some of the other fields (host, etc). Scott From jboggs at redhat.com Thu Dec 11 21:22:55 2008 From: jboggs at redhat.com (Joey Boggs) Date: Thu, 11 Dec 2008 16:22:55 -0500 Subject: [Ovirt-devel] ovirt installation test scenarios In-Reply-To: <493EED36.3060304@redhat.com> References: <4939B473.7050701@redhat.com> <493D4671.3090003@redhat.com> <493EED36.3060304@redhat.com> Message-ID: <494184AF.1030103@redhat.com> Pushed the latest build 0.0.94 Needs some testing to find bugs in the installer RPM + SRPM: http://cobalt.rdu.redhat.com/ovirt/ace-ovirt-0.0.94/ git: http://github.com/jboggs/ace-ovirt/tree/master You will need to enable the fedora-testing repo to get the latest ace-postgres package, there is a bug in the current one in the ovirt repo. For right now run the installer as : /usr/share/ace/modules/ovirt/ovirt-installer It will write your install config file based on your choices then run like the old method, I'll bridge the gaps in by the next release in a day or so. After running the installer install oVirt by: puppet -d /usr/share/ace/modules/ovirt/ovirt-install.pp --modulepath=/usr/share/ace/modules Please report any bugs so we can get these fixed asap Thanks, Joey Joey Boggs wrote: > Michael DeHaan wrote: >> Joey Boggs wrote: >>> Since the options are limited right with what can be >>> external(postgres/freeipa) here's a list so far of different oVirt >>> installation scenarios that should to be tested >>> >>> external dns + internal cobbler + external dhcp + internal pxe >>> external dns + internal cobbler + internal dhcp + internal pxe >>> external dns + external cobbler + external dhcp + external pxe >>> external dns + external cobbler + internal dhcp + external pxe >>> internal dns + internal cobbler + external dhcp + internal pxe >>> internal dns + internal cobbler + internal dhcp + internal pxe >>> >>> Can't reproduce these below just yet due to dnsmasq config, >>> currently does both dhcp and dns by default bundled config >>> internal dns + external cobbler + external dhcp + external pxe >>> internal dns + external cobbler + internal dhcp + external pxe >>> >>> There may be some issues in producing these scenarios if so please >>> let me know and we can build/correct a solution. >>> >> >> The cobbler server should be the PXE server, and that should help >> simplify things, no? >> >> All the admin would have to do is set the next-server for the subnet >> to point at the cobbler box if he happened to have another PXE >> environment. You could just document this step. >> >> Somewhat unrelated, is Ovirt doing any DHCP management? Cobbler has >> a built in feature for this that would probably be useful. DNS also >> -- and it does support dnsmasq in addition to the BIND stuff. This >> allows you to pin certain mac addresses to certain ip's and >> hostnames, just by creating cobbler system records with that >> information filled in. >> >> --Michael >> > Currently oVirt can use any dhcp app to provide dhcp there is no > management function. The appliance version uses dnsmasq based on > install time basic configuration as will the first cut of the bare > metal installer. We can use any dns server the only requirement for > installation is forward/reverse lookup for the FreeIPA portion. We > already provide some cobbler integration for the profiles, what would > it take to integrate dns/dhcp into the ovirt console? > > > > >>> >>> _______________________________________________ >>> Ovirt-devel mailing list >>> Ovirt-devel at redhat.com >>> https://www.redhat.com/mailman/listinfo/ovirt-devel >> > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel From bkearney at redhat.com Thu Dec 11 21:23:50 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Thu, 11 Dec 2008 16:23:50 -0500 Subject: [Ovirt-devel] Standalone rsyslog question Message-ID: <494184E6.6070204@redhat.com> When testing standalone on my pc, all my machines are named localhost. This makes the log output a bit confusing. In [1] the secon and third line are from the node, not the fist. Only way to tell is the time.. sine the node is by default in UTC. Is it safe to assume that the dhcp server will hand out hotnames, or should we expose a hostname option to the config? -- bk [1] http://ovirt.pastebin.com/m17a22f3c From sseago at redhat.com Thu Dec 11 21:48:22 2008 From: sseago at redhat.com (Scott Seago) Date: Thu, 11 Dec 2008 21:48:22 +0000 Subject: [Ovirt-devel] [PATCH] fix for Bug 467767: double render error for add user Message-ID: <1229032102-4535-1-git-send-email-sseago@redhat.com> Not yet tested as I don't have a working appliance at the moment, but this should fix the problem, as there was an obvious issue with the render statement. I'll test shortly unless someone else gets to it first and ACKs. Signed-off-by: Scott Seago --- src/app/controllers/permission_controller.rb | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/src/app/controllers/permission_controller.rb b/src/app/controllers/permission_controller.rb index 813d9d9..c301e1e 100644 --- a/src/app/controllers/permission_controller.rb +++ b/src/app/controllers/permission_controller.rb @@ -47,8 +47,9 @@ class PermissionController < ApplicationController unless @can_set_perms flash[:notice] = 'You do not have permission to create this permission record' redirect_to_parent + else + render :layout => 'popup' end - render :layout => 'popup' end def create -- 1.6.0.4 From pmyers at redhat.com Thu Dec 11 22:44:13 2008 From: pmyers at redhat.com (Perry Myers) Date: Thu, 11 Dec 2008 17:44:13 -0500 Subject: [Ovirt-devel] Standalone rsyslog question In-Reply-To: <494184E6.6070204@redhat.com> References: <494184E6.6070204@redhat.com> Message-ID: <494197BD.9090409@redhat.com> Bryan Kearney wrote: > When testing standalone on my pc, all my machines are named localhost. > This makes the log output a bit confusing. In [1] the secon and third > line are from the node, not the fist. Only way to tell is the time.. > sine the node is by default in UTC. Is it safe to assume that the dhcp > server will hand out hotnames, or should we expose a hostname option to > the config? A host using dhcp will query dns and set the hostname based on the ip address it gets. But... we may not always be using dhcp. So we should add a way to set hostname manually perhaps as part of the configuration UI. If you want to throw together a patch to do that, might be a good idea. Should also provide a kernel cmdline equivalent of the config UI for this so we can still have fully automated installs. Perry From pmyers at redhat.com Fri Dec 12 02:13:49 2008 From: pmyers at redhat.com (Perry Myers) Date: Thu, 11 Dec 2008 21:13:49 -0500 Subject: [Ovirt-devel] [PATCH node] Created stateful and stateless subpackages used for installing on bare metal Fedora hosts Message-ID: <1229048031-573-1-git-send-email-pmyers@redhat.com> ovirt-node-stateless is for use on the embedded oVirt Node. ovirt-node-stateful is for use on already installed Fedora hosts to configure that host to act as a Node. Presently it only works when run on the same host as the oVirt Appliance. ovirt-node RPM provides common binaries/scripts used by the subpackages Splitting up the RPMs is required since ovirt-node RPM now packages up gptsync which conflicts with anaconda. Signed-off-by: Perry Myers --- Makefile.am | 3 + ovirt-listen-awake/Makefile.am | 2 +- ovirt-listen-awake/ovirt-install-node | 177 -------------------- ovirt-node.spec.in | 73 +++++++-- scripts/ovirt-functions | 15 ++ scripts/ovirt-install-node-stateful | 113 +++++++++++++ scripts/ovirt-install-node-stateless | 52 ++++++ .../ovirt-uninstall-node-stateful | 0 8 files changed, 245 insertions(+), 190 deletions(-) delete mode 100755 ovirt-listen-awake/ovirt-install-node create mode 100755 scripts/ovirt-install-node-stateful create mode 100755 scripts/ovirt-install-node-stateless rename ovirt-listen-awake/ovirt-uninstall-node => scripts/ovirt-uninstall-node-stateful (100%) diff --git a/Makefile.am b/Makefile.am index 9b54ae6..a47beaa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -35,8 +35,11 @@ EXTRA_DIST = \ scripts/ovirt-early \ scripts/ovirt-firstboot \ scripts/ovirt-functions \ + scripts/ovirt-install-node-stateful \ + scripts/ovirt-install-node-stateless \ scripts/ovirt-post \ scripts/ovirt-process-config \ + scripts/ovirt-uninstall-node-stateful \ logrotate/ovirt-logrotate \ logrotate/ovirt-logrotate.conf diff --git a/ovirt-listen-awake/Makefile.am b/ovirt-listen-awake/Makefile.am index 05cb85b..783f15c 100644 --- a/ovirt-listen-awake/Makefile.am +++ b/ovirt-listen-awake/Makefile.am @@ -17,6 +17,6 @@ bin_PROGRAMS = ovirt-listen-awake -EXTRA_DIST = ovirt-listen-awake.init ovirt-install-node ovirt-uninstall-node +EXTRA_DIST = ovirt-listen-awake.init ovirt_listen_awake_SOURCES = ovirt-listen-awake.c diff --git a/ovirt-listen-awake/ovirt-install-node b/ovirt-listen-awake/ovirt-install-node deleted file mode 100755 index d65816f..0000000 --- a/ovirt-listen-awake/ovirt-install-node +++ /dev/null @@ -1,177 +0,0 @@ -#!/bin/bash - -PHYS_HOST=physical.priv.ovirt.org -MGMT_HOST=management.priv.ovirt.org - -. /etc/init.d/ovirt-functions - -PATH=$PATH:/sbin:/usr/sbin -ME=$(basename "$0") -warn() { printf '%s: %s\n' "$ME" "$*" >&2; } -die() { warn "$@"; exit 1; } - -usage() { - echo "Usage: $ME " -} - -# first, check to see we are root -if [ $( id -u ) -ne 0 ]; then - die "Must run as root" -fi - -if [ $# -ne 1 ]; then - usage - exit 1 -fi - -backup_file() { - dir=$(dirname "$1") - case $dir in /*);; *) die "unexpected non-absolute dir: $dir";; esac - mkdir -p "$OVIRT_BACKUP_DIR/${dir:1}" - test -f "$1" && cp -pf "$1" "$OVIRT_BACKUP_DIR/${dir:1}" -} - -add_if_not_exist() { - string="$1" - file="$2" - - grep -qE "^[[:space:]]*$string($|#|[[:space:]])" "$file" \ - || echo "$string" >> "$file" -} - -if [ "$1" = "stateless" ]; then - chkconfig --level 3 ovirt-early on - chkconfig --level 3 ovirt on - chkconfig --level 3 ovirt-post on - chkconfig --level 3 collectd on - - ovirt_setup_libvirtd - - # make sure we don't autostart virbr0 on libvirtd startup - rm -f /etc/libvirt/qemu/networks/autostart/default.xml - - # remove the /etc/krb5.conf file; it will be fetched on bootup - rm -f /etc/krb5.conf - - g=$(printf '\33[1m\33[32m') # similar to g=$(tput bold; tput setaf 2) - n=$(printf '\33[m') # similar to n=$(tput sgr0) - version=$(rpm -q --qf '%{version}' ovirt-node) - release=$(rpm -q --qf '%{release}' ovirt-node) - cat < /etc/issue - - 888 888 ${g}d8b$n 888 - 888 888 ${g}Y8P$n 888 - 888 888 888 - .d88b. Y88b d88P 888 888d888 888888 - d88''88b Y88b d88P 888 888P' 888 - 888 888 Y88o88P 888 888 888 - Y88..88P Y888P 888 888 Y88b. - 'Y88P' Y8P 888 888 'Y888 - - oVirt Node release ${version}-${release} - - Virtualization just got the ${g}Green Light$n - -EOF - cp -p /etc/issue /etc/issue.net -elif [ "$1" = "stateful" ]; then - echo "This script will make a number of changes to your system to enable it" - echo "to work as an oVirt node. You can later undo these changes by" - echo "running /usr/sbin/ovirt-uninstall-host. Do you want to proceed? [y/N]?" - read yesno - - if [ "$yesno" != "y" -a "$yesno" != "Y" ]; then - exit 2 - fi - - # Always try to uninstall first, that way the original pristine files are - # in place before re-installing, this prevents OVIRT_BACKUP_DIR from - # being overwritten with an older version of the node config files - ovirt-uninstall-node > /dev/null 2>&1 - - # Remove old keytab if it exists in case we have a new appliance to work with - rm -f /etc/libvirt/krb5.tab - - rm -Rf $OVIRT_BACKUP_DIR - mkdir -p $OVIRT_BACKUP_DIR - - backup_file /etc/sysconfig/network - if grep "^HOSTNAME=" /etc/sysconfig/network > /dev/null 2>&1 ; then - sed -i -e "s/^HOSTNAME=.*/HOSTNAME=$PHYS_HOST/" /etc/sysconfig/network - else - echo "HOSTNAME=$PHYS_HOST" >> /etc/sysconfig/network - fi - hostname $PHYS_HOST - - collectd_conf=/etc/collectd.conf - backup_file $collectd_conf - if [ -f $collectd_conf.in ]; then - sed -e "s/@COLLECTD_SERVER@/$MGMT_HOST/" \ - -e "s/@COLLECTD_PORT@/25826/" $collectd_conf.in \ - > $collectd_conf - fi - - libvirt_qpid_conf=/etc/sysconfig/libvirt-qpid - backup_file $libvirt_qpid_conf - if [ -f $libvirt_qpid_conf ]; then - if grep "^LIBVIRT_QPID_ARGS=" $libvirt_qpid_conf > /dev/null 2>&1 ; then - sed -i -e "s/^LIBVIRT_QPID_ARGS=.*/LIBVIRT_QPID_ARGS=\"--broker $MGMT_HOST --port 5672\"/" $libvirt_qpid_conf - else - echo "LIBVIRT_QPID_ARGS=\"--broker $MGMT_HOST --port 5672\"" >> $libvirt_qpid_conf - fi - fi - - backup_file /etc/hosts - add_if_not_exist "192.168.50.1 $PHYS_HOST" /etc/hosts - add_if_not_exist "192.168.50.2 $MGMT_HOST" /etc/hosts - - chkconfig ovirt-listen-awake on - chkconfig ovirt-early off - chkconfig ovirt off - chkconfig ovirt-post off - chkconfig ovirt-firstboot off - chkconfig collectd on - chkconfig libvirt-qpid on - chkconfig iptables on - chkconfig ntpdate on - chkconfig ntpd on - - backup_file /etc/sysconfig/libvirtd - backup_file /etc/libvirt/qemu.conf - backup_file /etc/libvirt/libvirtd.conf - backup_file /etc/sasl2/libvirt.conf - backup_file /etc/krb5.conf - ovirt_setup_libvirtd - - backup_file /etc/sysconfig/iptables - # We open up anything coming from ovirtbr0 to this node, since it - # is only intended for demo purposes. For reference, here are the - # ports that need to be opened: - # 7777:tcp (ovirt-listen-awake), 16509:tcp (libvirtd), 5900-6000:tcp (vnc), - # 49152-49216:tcp (libvirt migration) - lokkit -q -t ovirtbr0 - - service iptables restart - - # Check if any domains are active before restarting libvirtd, since it will - # kill them. Header information from virsh list is 2 lines, and 1 line for - # footer. So > 3 lines means domains are running - running_domains=$(( $(virsh -c qemu:///system list 2> /dev/null | wc -l) - 3 )) - if [ $running_domains -gt 0 ]; then - echo "Cannot restart libvirtd because domains are active." - echo "Please shutdown all domains and restart libvirtd with:" - echo "service libvirtd restart" - else - service libvirtd restart - fi - - service collectd restart - service ovirt-listen-awake restart - service libvirt-qpid restart - service ntpd stop - service ntpdate start - service ntpd start -else - usage - exit 1 -fi diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in index ef65bf0..59d9939 100644 --- a/ovirt-node.spec.in +++ b/ovirt-node.spec.in @@ -42,7 +42,29 @@ ExclusiveArch: %{ix86} x86_64 %description Provides a series of daemons and support utilities to allow an -oVirt Node to interact with the oVirt server. +oVirt Node to interact with the oVirt Server. + +%package stateless +Summary: oVirt Node for running as embedded hypervisor +Group: Applications/System +Requires: %{name} = %{version}-%{release} +ExclusiveArch: %{ix86} x86_64 + +%description stateless +Provides the oVirt Node functionality needed as part of the +ovirt-node-image creation. This provides a stateless oVirt Node +that runs as a livecd. + +%package stateful +Summary: oVirt Node for running on Fedora Hosts +Group: Applications/System +Requires: %{name} = %{version}-%{release} +ExclusiveArch: %{ix86} x86_64 + +%description stateful +Provides the oVirt Node functionality needed to convert an existing +host into a Node in a stateful manner. Presently intended for use on +the host running the oVirt Appliance. %package selinux Summary: SELinux policy module supporting ovirt-node @@ -93,11 +115,12 @@ cd - %{__install} -p -m0755 scripts/ovirt-config-setup %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-storage %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-process-config %{buildroot}%{_sbindir} +%{__install} -D -m0755 scripts/ovirt-install-node-stateful %{buildroot}%{_sbindir} +%{__install} -D -m0755 scripts/ovirt-install-node-stateless %{buildroot}%{_sbindir} +%{__install} -D -m0755 scripts/ovirt-uninstall-node-stateful %{buildroot}%{_sbindir} %{__install} -p -m0755 ovirt-identify-node/ovirt-identify-node %{buildroot}%{_sbindir} %{__install} -p -m0755 ovirt-listen-awake/ovirt-listen-awake %{buildroot}%{_sbindir} %{__install} -Dp -m0755 ovirt-listen-awake/ovirt-listen-awake.init %{buildroot}%{_initrddir}/ovirt-listen-awake -%{__install} -Dp -m0755 ovirt-listen-awake/ovirt-install-node %{buildroot}%{_sbindir} -%{__install} -Dp -m0755 ovirt-listen-awake/ovirt-uninstall-node %{buildroot}%{_sbindir} # gptsync %{__install} -p -m0755 gptsync/gptsync %{buildroot}%{_sbindir} @@ -131,7 +154,7 @@ cd - %clean %{__rm} -rf %{buildroot} -%post +%post stateless /sbin/chkconfig --add ovirt-early /sbin/chkconfig --add ovirt-firstboot /sbin/chkconfig --add ovirt @@ -140,14 +163,29 @@ cd - # /etc/chkconfig.d/collectd file, and then have to re-define collectd here /sbin/chkconfig --add collectd /sbin/chkconfig --add ovirt-listen-awake +/bin/ln -sf %{_sbindir}/ovirt-install-node-stateless %{_sbindir}/ovirt-install-node -%preun +%preun stateless if [ "$1" = 0 ] ; then /sbin/chkconfig --del ovirt-early /sbin/chkconfig --del ovirt-firstboot /sbin/chkconfig --del ovirt /sbin/chkconfig --del ovirt-post /sbin/chkconfig --del ovirt-listen-awake + rm -f %{_sbindir}/ovirt-install-node +fi + +%post stateful +/sbin/chkconfig --add collectd +/sbin/chkconfig --add ovirt-listen-awake +/bin/ln -sf %{_sbindir}/ovirt-install-node-stateful %{_sbindir}/ovirt-install-node +/bin/ln -sf %{_sbindir}/ovirt-uninstall-node-stateful %{_sbindir}/ovirt-uninstall-node + +%preun stateful +if [ "$1" = 0 ] ; then + /sbin/chkconfig --del ovirt-listen-awake + rm -f %{_sbindir}/ovirt-install-node + rm -f %{_sbindir}/ovirt-uninstall-node fi %post selinux @@ -168,28 +206,35 @@ fi %doc SELinux/* %{_datadir}/selinux/*/%{modulename}.pp -%files +%files stateless %defattr(-,root,root,0755) -%{_sbindir}/ovirt-awake %{_sbindir}/ovirt-config-logging %{_sbindir}/ovirt-config-networking %{_sbindir}/ovirt-config-password %{_sbindir}/ovirt-config-setup %{_sbindir}/ovirt-config-storage %{_sbindir}/ovirt-process-config -%{_sbindir}/ovirt-identify-node -%{_sbindir}/ovirt-listen-awake -%{_sbindir}/ovirt-install-node -%{_sbindir}/ovirt-uninstall-node +%{_sbindir}/ovirt-install-node-stateless %{_sbindir}/gptsync %{_sbindir}/showpart %{_initrddir}/ovirt-early %{_initrddir}/ovirt-firstboot %{_initrddir}/ovirt %{_initrddir}/ovirt-post -%{_initrddir}/ovirt-listen-awake %config %{_sysconfdir}/logrotate.d/ovirt-logrotate.conf %config %{_sysconfdir}/cron.hourly/ovirt-logrotate + +%files stateful +%defattr(-,root,root,0755) +%{_sbindir}/ovirt-listen-awake +%{_sbindir}/ovirt-install-node-stateful +%{_sbindir}/ovirt-uninstall-node-stateful +%{_initrddir}/ovirt-listen-awake + +%files +%defattr(-,root,root,0755) +%{_sbindir}/ovirt-awake +%{_sbindir}/ovirt-identify-node %defattr(-,root,root,0644) %{_initrddir}/ovirt-functions %{_sysconfdir}/collectd.conf.in @@ -200,6 +245,10 @@ fi %doc ovirt-identify-node/COPYING %changelog +* Thu Dec 11 2008 Perry Myers - 0.96 +- Subpackage stateful/stateless to separate out functionality for + embedded Node and Node running as part of already installed OS + * Thu Sep 11 2008 Chris Lalancette - 0.92 0.7 - Add the ovirt-install- and ovirt-uninstall-node scripts, and refactor post to accomodate diff --git a/scripts/ovirt-functions b/scripts/ovirt-functions index c6a8504..271e173 100644 --- a/scripts/ovirt-functions +++ b/scripts/ovirt-functions @@ -131,3 +131,18 @@ ovirt_store_config() { echo umount $ovirt && rmdir $ovirt } + +backup_file() { + dir=$(dirname "$1") + case $dir in /*);; *) die "unexpected non-absolute dir: $dir";; esac + mkdir -p "$OVIRT_BACKUP_DIR/${dir:1}" + test -f "$1" && cp -pf "$1" "$OVIRT_BACKUP_DIR/${dir:1}" +} + +add_if_not_exist() { + string="$1" + file="$2" + + grep -qE "^[[:space:]]*$string($|#|[[:space:]])" "$file" \ + || echo "$string" >> "$file" +} diff --git a/scripts/ovirt-install-node-stateful b/scripts/ovirt-install-node-stateful new file mode 100755 index 0000000..3ec1c29 --- /dev/null +++ b/scripts/ovirt-install-node-stateful @@ -0,0 +1,113 @@ +#!/bin/bash + +PHYS_HOST=physical.priv.ovirt.org +MGMT_HOST=management.priv.ovirt.org + +. /etc/init.d/ovirt-functions + +PATH=$PATH:/sbin:/usr/sbin +ME=$(basename "$0") +warn() { printf '%s: %s\n' "$ME" "$*" >&2; } +die() { warn "$@"; exit 1; } + +usage() { + echo "Usage: $ME" +} + +# first, check to see we are root +if [ $( id -u ) -ne 0 ]; then + die "Must run as root" +fi + +echo "This script will make a number of changes to your system to enable it" +echo "to work as an oVirt node. You can later undo these changes by" +echo "running /usr/sbin/ovirt-uninstall-host. Do you want to proceed? [y/N]?" +read yesno + +if [ "$yesno" != "y" -a "$yesno" != "Y" ]; then + exit 2 +fi + +# Always try to uninstall first, that way the original pristine files are +# in place before re-installing, this prevents OVIRT_BACKUP_DIR from +# being overwritten with an older version of the node config files +ovirt-uninstall-node > /dev/null 2>&1 + +# Remove old keytab if it exists in case we have a new appliance to work with +rm -f /etc/libvirt/krb5.tab + +rm -Rf $OVIRT_BACKUP_DIR +mkdir -p $OVIRT_BACKUP_DIR + +backup_file /etc/sysconfig/network +if grep "^HOSTNAME=" /etc/sysconfig/network > /dev/null 2>&1 ; then + sed -i -e "s/^HOSTNAME=.*/HOSTNAME=$PHYS_HOST/" /etc/sysconfig/network +else + echo "HOSTNAME=$PHYS_HOST" >> /etc/sysconfig/network +fi +hostname $PHYS_HOST + +collectd_conf=/etc/collectd.conf +backup_file $collectd_conf +if [ -f $collectd_conf.in ]; then + sed -e "s/@COLLECTD_SERVER@/$MGMT_HOST/" \ + -e "s/@COLLECTD_PORT@/25826/" $collectd_conf.in \ + > $collectd_conf +fi + +libvirt_qpid_conf=/etc/sysconfig/libvirt-qpid +backup_file $libvirt_qpid_conf +if [ -f $libvirt_qpid_conf ]; then + if grep "^LIBVIRT_QPID_ARGS=" $libvirt_qpid_conf > /dev/null 2>&1 ; then + sed -i -e "s/^LIBVIRT_QPID_ARGS=.*/LIBVIRT_QPID_ARGS=\"--broker $MGMT_HOST --port 5672\"/" $libvirt_qpid_conf + else + echo "LIBVIRT_QPID_ARGS=\"--broker $MGMT_HOST --port 5672\"" >> $libvirt_qpid_conf + fi +fi + +backup_file /etc/hosts +add_if_not_exist "192.168.50.1 $PHYS_HOST" /etc/hosts +add_if_not_exist "192.168.50.2 $MGMT_HOST" /etc/hosts + +chkconfig ovirt-listen-awake on +chkconfig collectd on +chkconfig libvirt-qpid on +chkconfig iptables on +chkconfig ntpdate on +chkconfig ntpd on + +backup_file /etc/sysconfig/libvirtd +backup_file /etc/libvirt/qemu.conf +backup_file /etc/libvirt/libvirtd.conf +backup_file /etc/sasl2/libvirt.conf +backup_file /etc/krb5.conf +ovirt_setup_libvirtd + +backup_file /etc/sysconfig/iptables +# We open up anything coming from ovirtbr0 to this node, since it +# is only intended for demo purposes. For reference, here are the +# ports that need to be opened: +# 7777:tcp (ovirt-listen-awake), 16509:tcp (libvirtd), 5900-6000:tcp (vnc), +# 49152-49216:tcp (libvirt migration) +lokkit -q -t ovirtbr0 + +service iptables restart + +# Check if any domains are active before restarting libvirtd, since it will +# kill them. Header information from virsh list is 2 lines, and 1 line for +# footer. So > 3 lines means domains are running +running_domains=$(( $(virsh -c qemu:///system list 2> /dev/null | wc -l) - 3 )) +if [ $running_domains -gt 0 ]; then + echo "Cannot restart libvirtd because domains are active." + echo "Please shutdown all domains and restart libvirtd with:" + echo "service libvirtd restart" +else + service libvirtd restart +fi + +service collectd restart +service ovirt-listen-awake restart +service libvirt-qpid restart +service ntpd stop +service ntpdate start +service ntpd start diff --git a/scripts/ovirt-install-node-stateless b/scripts/ovirt-install-node-stateless new file mode 100755 index 0000000..e7b36d4 --- /dev/null +++ b/scripts/ovirt-install-node-stateless @@ -0,0 +1,52 @@ +#!/bin/bash + +. /etc/init.d/ovirt-functions + +PATH=$PATH:/sbin:/usr/sbin +ME=$(basename "$0") +warn() { printf '%s: %s\n' "$ME" "$*" >&2; } +die() { warn "$@"; exit 1; } + +usage() { + echo "Usage: $ME" +} + +# first, check to see we are root +if [ $( id -u ) -ne 0 ]; then + die "Must run as root" +fi + +chkconfig --level 3 ovirt-early on +chkconfig --level 3 ovirt on +chkconfig --level 3 ovirt-post on +chkconfig --level 3 collectd on + +ovirt_setup_libvirtd + +# make sure we don't autostart virbr0 on libvirtd startup +rm -f /etc/libvirt/qemu/networks/autostart/default.xml + +# remove the /etc/krb5.conf file; it will be fetched on bootup +rm -f /etc/krb5.conf + +g=$(printf '\33[1m\33[32m') # similar to g=$(tput bold; tput setaf 2) +n=$(printf '\33[m') # similar to n=$(tput sgr0) +version=$(rpm -q --qf '%{version}' ovirt-node) +release=$(rpm -q --qf '%{release}' ovirt-node) +cat < /etc/issue + + 888 888 ${g}d8b$n 888 + 888 888 ${g}Y8P$n 888 + 888 888 888 + .d88b. Y88b d88P 888 888d888 888888 + d88''88b Y88b d88P 888 888P' 888 + 888 888 Y88o88P 888 888 888 + Y88..88P Y888P 888 888 Y88b. + 'Y88P' Y8P 888 888 'Y888 + + oVirt Node release ${version}-${release} + + Virtualization just got the ${g}Green Light$n + +EOF +cp -p /etc/issue /etc/issue.net diff --git a/ovirt-listen-awake/ovirt-uninstall-node b/scripts/ovirt-uninstall-node-stateful similarity index 100% rename from ovirt-listen-awake/ovirt-uninstall-node rename to scripts/ovirt-uninstall-node-stateful -- 1.6.0.4 From pmyers at redhat.com Fri Dec 12 02:13:50 2008 From: pmyers at redhat.com (Perry Myers) Date: Thu, 11 Dec 2008 21:13:50 -0500 Subject: [Ovirt-devel] [PATCH release] Switch to installing ovirt-node-stateful on host instead of ovirt-node In-Reply-To: <1229048031-573-1-git-send-email-pmyers@redhat.com> References: <1229048031-573-1-git-send-email-pmyers@redhat.com> Message-ID: <1229048031-573-2-git-send-email-pmyers@redhat.com> Signed-off-by: Perry Myers --- ovirt.mk | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ovirt.mk b/ovirt.mk index 42893c9..962fa07 100644 --- a/ovirt.mk +++ b/ovirt.mk @@ -94,8 +94,8 @@ update-host: @$(write_repo_file) @sudo yum install -c $(OVIRT_CACHE_DIR)/ovirt-local.repo -y \ --enablerepo=ovirt \ - ovirt-release ovirt-build ovirt-appliance ovirt-node ovirt-docs \ - ovirt-node-selinux ovirt-node-image + ovirt-release ovirt-build ovirt-appliance ovirt-docs \ + ovirt-node-stateful ovirt-node-selinux ovirt-node-image update-app: update-host sudo get-ovirt-appliance -l appliance -p $(PKG_FMT) -f $(DISK_FMT) -- 1.6.0.4 From pmyers at redhat.com Fri Dec 12 02:13:51 2008 From: pmyers at redhat.com (Perry Myers) Date: Thu, 11 Dec 2008 21:13:51 -0500 Subject: [Ovirt-devel] [PATCH node-image] Use ovirt-node-stateless In-Reply-To: <1229048031-573-2-git-send-email-pmyers@redhat.com> References: <1229048031-573-1-git-send-email-pmyers@redhat.com> <1229048031-573-2-git-send-email-pmyers@redhat.com> Message-ID: <1229048031-573-3-git-send-email-pmyers@redhat.com> Signed-off-by: Perry Myers --- common-pkgs.ks | 2 +- common-post.ks | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common-pkgs.ks b/common-pkgs.ks index 60fd2cf..2727b87 100644 --- a/common-pkgs.ks +++ b/common-pkgs.ks @@ -9,7 +9,7 @@ dhclient openssh-clients openssh-server kvm -ovirt-node +ovirt-node-stateless ovirt-node-selinux -selinux-policy-targeted selinux-policy-minimum diff --git a/common-post.ks b/common-post.ks index dd46f75..856030b 100644 --- a/common-post.ks +++ b/common-post.ks @@ -39,8 +39,8 @@ if test -n "$modules"; then fi rm -rf "$tmpdir" -echo "Running ovirt-install-host stateless" -ovirt-install-node stateless +echo "Running ovirt-install-node" +ovirt-install-node echo "Creating shadow files" # because we aren't installing authconfig, we aren't setting up shadow -- 1.6.0.4 From pmyers at redhat.com Fri Dec 12 03:21:58 2008 From: pmyers at redhat.com (Perry Myers) Date: Thu, 11 Dec 2008 22:21:58 -0500 Subject: [Ovirt-devel] freeipa cmdline tools failing Message-ID: <4941D8D6.90905@redhat.com> Simo, Follow up from the conversation we were having today on IRC in #ovirt So it looks like update to python-kerberos package broke freeipa... If I downgrade to python-kerberos-1.0-6.fc9.x86_64.rpm I can do: > [root at management ~]# ipa-finduser foo > No entries found for foo But if I upgrade to python-kerberos-1.1-1.fc10.x86_64.rpm I get: > [root at management ~]# ipa-finduser foo > Did not receive Kerberos credentials. Not sure if this is a problem with freeipa or python-kerberos... Could be they changed something (it wasn't a major version upgrade, but it was a 1.0 to 1.1 so likely they changed some interface and freeipa needs to be updated to work properly with it) Or could be that python-kerberos has a bug in it. In any case, if you could look try to replicate this let me know what you find out. Thanks! Perry -- |=- Red Hat, Engineering, Emerging Technologies, Boston -=| |=- Email: pmyers at redhat.com -=| |=- Office: +1 412 474 3552 Mobile: +1 703 362 9622 -=| |=- GnuPG: E65E4F3D 88F9 F1C9 C2F3 1303 01FE 817C C5D2 8B91 E65E 4F3D -=| From jboggs at redhat.com Fri Dec 12 03:36:48 2008 From: jboggs at redhat.com (Joey Boggs) Date: Thu, 11 Dec 2008 22:36:48 -0500 Subject: [Ovirt-devel] freeipa cmdline tools failing In-Reply-To: <4941D8D6.90905@redhat.com> References: <4941D8D6.90905@redhat.com> Message-ID: <4941DC50.7070704@redhat.com> I'm hitting the same error when running ipa-adduser for an oVirt installation and can replicate it easily, what info do you need? Perry Myers wrote: > Simo, > > Follow up from the conversation we were having today on IRC in #ovirt > > So it looks like update to python-kerberos package broke freeipa... > > If I downgrade to python-kerberos-1.0-6.fc9.x86_64.rpm I can do: > >> [root at management ~]# ipa-finduser foo >> No entries found for foo > > But if I upgrade to python-kerberos-1.1-1.fc10.x86_64.rpm I get: > >> [root at management ~]# ipa-finduser foo >> Did not receive Kerberos credentials. > > Not sure if this is a problem with freeipa or python-kerberos... > Could be they changed something (it wasn't a major version upgrade, > but it was a 1.0 to 1.1 so likely they changed some interface and > freeipa needs to be updated to work properly with it) > > Or could be that python-kerberos has a bug in it. > > In any case, if you could look try to replicate this let me know what > you find out. > > Thanks! > > Perry > From rcritten at redhat.com Fri Dec 12 05:09:07 2008 From: rcritten at redhat.com (Rob Crittenden) Date: Fri, 12 Dec 2008 00:09:07 -0500 Subject: [Ovirt-devel] Re: [Freeipa-devel] freeipa cmdline tools failing In-Reply-To: <4941D8D6.90905@redhat.com> References: <4941D8D6.90905@redhat.com> Message-ID: <4941F1F3.7050701@redhat.com> Perry Myers wrote: > Simo, > > Follow up from the conversation we were having today on IRC in #ovirt > > So it looks like update to python-kerberos package broke freeipa... > > If I downgrade to python-kerberos-1.0-6.fc9.x86_64.rpm I can do: > >> [root at management ~]# ipa-finduser foo >> No entries found for foo > > But if I upgrade to python-kerberos-1.1-1.fc10.x86_64.rpm I get: > >> [root at management ~]# ipa-finduser foo >> Did not receive Kerberos credentials. > > Not sure if this is a problem with freeipa or python-kerberos... Could > be they changed something (it wasn't a major version upgrade, but it was > a 1.0 to 1.1 so likely they changed some interface and freeipa needs to > be updated to work properly with it) > > Or could be that python-kerberos has a bug in it. > > In any case, if you could look try to replicate this let me know what > you find out. The problem is that PyKerberos doesn't support delegation. python-kerberos 1.0 had a patch which set the delegation flag on every request. A rather short-sighted fix, in retrospect. A slightly better fix, which will also require a change in freeipa, is attached. This adds an optional, unnamed argument to authGSSClientInit() to request delegation. The new call signature looks like: authGSSClientInit(service, False) The fix for freeipa is to add a second argument, True, to krbtransport.py, ~line 37. Should look something like this, minus proper spacing: rc, vc = kerberos.authGSSClientInit(service, True) I suppose the best solution is to provide a mechanism to set whatever flags one wants but my Python-to-C coding knowledge consists of about 10 minutes of reading the Python documentation so I'm not quite ready for that :-) This is briefly tested at best, so YMMV. rob -------------- next part -------------- A non-text attachment was scrubbed... Name: delegate.patch Type: text/x-patch Size: 3517 bytes Desc: not available URL: From ssubha at hcl.in Fri Dec 12 05:10:08 2008 From: ssubha at hcl.in (Subha Shrinivasan, TLS-Chennai) Date: Fri, 12 Dec 2008 10:40:08 +0530 Subject: [Ovirt-devel] unsubscribe Message-ID: DISCLAIMER: ----------------------------------------------------------------------------------------------------------------------- The contents of this e-mail and any attachment(s) are confidential and intended for the named recipient(s) only. It shall not attach any liability on the originator or HCL or its affiliates. Any views or opinions presented in this email are solely those of the author and may not necessarily reflect the opinions of HCL or its affiliates. Any form of reproduction, dissemination, copying, disclosure, modification, distribution and / or publication of this message without the prior written consent of the author of this e-mail is strictly prohibited. If you have received this email in error please delete it and notify the sender immediately. Before opening any mail and attachments please check them for viruses and defect. ----------------------------------------------------------------------------------------------------------------------- -------------- next part -------------- An HTML attachment was scrubbed... URL: From dpierce at redhat.com Fri Dec 12 12:54:22 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Fri, 12 Dec 2008 07:54:22 -0500 Subject: [Ovirt-devel] help In-Reply-To: References: Message-ID: <20081212125422.GB3781@mcpierce-laptop.rdu.redhat.com> On Thu, Dec 11, 2008 at 08:23:19PM +0530, Hadi Al-Saadi wrote: > so u mean i will not be ably to download ovirt 0.95 with yum from ur > website ?? 0.95, like 0.93-1, will be available for download by those who are unable to upgrade to Fedora 10. What was said is that our ongoing development will now focus on Fedora 10 as the target platform. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From pmyers at redhat.com Fri Dec 12 13:05:07 2008 From: pmyers at redhat.com (Perry Myers) Date: Fri, 12 Dec 2008 08:05:07 -0500 Subject: [Ovirt-devel] help In-Reply-To: References: Message-ID: <49426183.50804@redhat.com> Hadi Al-Saadi wrote: > > Dear perry, > > > thanks for your respond. > today we going to reinstall the host O/S to x86_64 bit O/S fedora-9 > > next > > cant load guest O/S after creating image thru > > cobbler image add --name=ubuntu-64-2 > > --file=nfs://$(hostname)/cobblernfs/Fedora-9-i386-DVD.iso > it showing in ovirt ui in the task tab status failed. > > can we run windows O/S ?? and how ?? You should be able to run a Windows OS on an oVirt Node. The steps are as follows: 1. Upload Windows install ISO to the Appliance in the /cobblernfs directory 2. Use cobbler command line on the Appliance to add the image in /cobblernfs as a Cobbler Image object 3. In the Create VM screen your new Image should show up in the drop down list for provisioning. Select this image. 4. Start the VM and use the link in the details pane for the VM to open a new Console for it to see the install. If this doesn't work, do the following to troubleshoot. On the appliance, remove all of the logs in /var/log/ovirt-server: rm -f /var/log/ovirt-server/* Then reboot the appliance to get to a clean state. Then try creating the VM again and start it again. If it fails, capture all logs in /var/log/ovirt-server so that we can see why it failed. Thanks, Perry From pmyers at redhat.com Fri Dec 12 13:07:16 2008 From: pmyers at redhat.com (Perry Myers) Date: Fri, 12 Dec 2008 08:07:16 -0500 Subject: [Ovirt-devel] help In-Reply-To: <20081212125422.GB3781@mcpierce-laptop.rdu.redhat.com> References: <20081212125422.GB3781@mcpierce-laptop.rdu.redhat.com> Message-ID: <49426204.4020002@redhat.com> Darryl L. Pierce wrote: > On Thu, Dec 11, 2008 at 08:23:19PM +0530, Hadi Al-Saadi wrote: >> so u mean i will not be ably to download ovirt 0.95 with yum from ur >> website ?? > > 0.95, like 0.93-1, will be available for download by those who are > unable to upgrade to Fedora 10. What was said is that our ongoing > development will now focus on Fedora 10 as the target platform. Correct. We won't remove the .95 RPMs from the website, but once the .96 release is out we will be strongly encouraging everyone to move to it. We only work with/support the latest release of oVirt at this point, so after .96 is released if people have problems with .95 our answer will be to tell them to upgrade. Perry From pmyers at redhat.com Fri Dec 12 13:10:11 2008 From: pmyers at redhat.com (Perry Myers) Date: Fri, 12 Dec 2008 08:10:11 -0500 Subject: [Ovirt-devel] [PATCH node-image] db4 is needed by standalone mode to create SASL users In-Reply-To: <1229020598-23146-1-git-send-email-bkearney@redhat.com> References: <1229020598-23146-1-git-send-email-bkearney@redhat.com> Message-ID: <494262B3.2080009@redhat.com> Bryan Kearney wrote: > --- > common-blacklist.ks | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > diff --git a/common-blacklist.ks b/common-blacklist.ks > index e05307d..98c6edd 100644 > --- a/common-blacklist.ks > +++ b/common-blacklist.ks > @@ -18,7 +18,7 @@ RPMS="$RPMS kpartx mkinitrd isomd5sum dmraid checkpolicy" > # Remove additional RPMs forcefully > RPMS="$RPMS gamin pm-utils kbd usermode vbetool ConsoleKit hdparm \ > efibootmgr krb5-workstation linux-atm-libs fedora-release-notes \ > - slang psmisc gdbm cryptsetup-luks pciutils mtools syslinux db4 \ > + slang psmisc gdbm cryptsetup-luks pciutils mtools syslinux \ > wireless-tools radeontool cracklib-dicts cracklib libicu gnupg2 \ > fedora-logos" > Ack, I went ahead and pushed this. 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 Fri Dec 12 13:14:57 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Fri, 12 Dec 2008 08:14:57 -0500 Subject: [Ovirt-devel] Partitioning error running a standalone F-10 node In-Reply-To: <494163E4.9070905@redhat.com> References: <494163E4.9070905@redhat.com> Message-ID: <20081212131456.GD3781@mcpierce-laptop.rdu.redhat.com> On Thu, Dec 11, 2008 at 02:03:00PM -0500, Bryan Kearney wrote: > I ran a standalone node in a vm with a 1 Gig disk. I selected the > parition option, and configured the total to be less than 10 gig (The Did you mean "less than 1 gig" here? > defaults were over a gig). I got the following error: > > Volume group "VG" not found > Can't remove open logical volume "Swap" > 1+0 records in > 1+0 records out > 1024 bytes (1.0 kB) copied > BLKRRPART: Device or resource busy > > Did I miss a setup step? Hmmm, not that I can tell from the description above. Can you recreate the error? -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From halsaadi at thoughtworks.com Fri Dec 12 06:18:56 2008 From: halsaadi at thoughtworks.com (Hadi Al-Saadi) Date: Fri, 12 Dec 2008 11:48:56 +0530 Subject: [Ovirt-devel] help Message-ID: Dear ovirt, how we can load windows O/S as a guest into ovirt. ? Regards -Hadi -------------- next part -------------- An HTML attachment was scrubbed... URL: From halsaadi at thoughtworks.com Fri Dec 12 07:03:59 2008 From: halsaadi at thoughtworks.com (Hadi Al-Saadi) Date: Fri, 12 Dec 2008 12:33:59 +0530 Subject: [Ovirt-devel] help Message-ID: heloo, how can i install guest O/S from cdrom Regards -Hadi -------------- next part -------------- An HTML attachment was scrubbed... URL: From pmyers at redhat.com Fri Dec 12 13:21:55 2008 From: pmyers at redhat.com (Perry Myers) Date: Fri, 12 Dec 2008 08:21:55 -0500 Subject: [Ovirt-devel] ovirt see only 1 node. how to add other servers ? In-Reply-To: <1228819017.559.7.camel@dima-desktop> References: <1228317705.11195.2.camel@dima-desktop> <4936A549.5000203@redhat.com> <1228389599.7273.5.camel@dima-desktop> <1228479650.13032.7.camel@dima-desktop> <4939BE7C.80305@redhat.com> <1228757099.11371.4.camel@dima-desktop> <493D95DB.6090802@redhat.com> <1228819017.559.7.camel@dima-desktop> Message-ID: <49426573.3050904@redhat.com> ?? wrote: > Sorry for my English. > You understand everything correctly > > Yes , shutdown -h now ovirt-appliance and after few minuts virsh destroy > I try fsck in singlemode and set in fstab check file system but many > services(such as postgresql and dirmng start with errors or not start) What version of the appliance are you using? .95/x86_64? I looked at your logs and it looks like the ovirt servers are not started, since taskomatic log complains that it cannot connect to postgres. The ovirt-server-appliance-setup.log looks truncated like it ran partially but did not get a chance to finish, and I don't see a log in /var/log/ace. There should be an install.log there that will tell me how the appliance firstboot went. Can you try reinstalling the appliance to run the firstboot again, and recapture the logs? I'd like to see the ace install.log to make sure the appliance setup is completing properly. Thanks, Perry From bkearney at redhat.com Fri Dec 12 13:24:18 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Fri, 12 Dec 2008 08:24:18 -0500 Subject: [Ovirt-devel] Partitioning error running a standalone F-10 node In-Reply-To: <20081212131456.GD3781@mcpierce-laptop.rdu.redhat.com> References: <494163E4.9070905@redhat.com> <20081212131456.GD3781@mcpierce-laptop.rdu.redhat.com> Message-ID: <49426602.7050202@redhat.com> Darryl L. Pierce wrote: > On Thu, Dec 11, 2008 at 02:03:00PM -0500, Bryan Kearney wrote: >> I ran a standalone node in a vm with a 1 Gig disk. I selected the >> parition option, and configured the total to be less than 10 gig (The > > Did you mean "less than 1 gig" here? Yes... I changed them to be less the the gig I allocated. > >> defaults were over a gig). I got the following error: >> >> Volume group "VG" not found >> Can't remove open logical volume "Swap" >> 1+0 records in >> 1+0 records out >> 1024 bytes (1.0 kB) copied >> BLKRRPART: Device or resource busy >> >> Did I miss a setup step? > > Hmmm, not that I can tell from the description above. Can you > recreate the error? > pretty easily. -- bk From dpierce at redhat.com Fri Dec 12 14:27:49 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Fri, 12 Dec 2008 09:27:49 -0500 Subject: [Ovirt-devel] [PATCH node] Usability fixes to the logging configuration. Message-ID: <1229092069-16641-1-git-send-email-dpierce@redhat.com> Users can now abort the configuration. At any point the user can enter either "abort" or an "a" depending on the input and quit the logging configuration. Also smoothes out the overall flow of configuration. Signed-off-by: Darryl L. Pierce --- scripts/ovirt-config-logging | 144 ++++++++++++++++++++++++++---------------- 1 files changed, 90 insertions(+), 54 deletions(-) diff --git a/scripts/ovirt-config-logging b/scripts/ovirt-config-logging index f79597f..8e6bc70 100755 --- a/scripts/ovirt-config-logging +++ b/scripts/ovirt-config-logging @@ -71,62 +71,98 @@ function is_numeric { } function prompt_user { + max_log_size="10" + syslog_server_ip="" + syslog_server_port="" + while true ; do - max_log_size="10k" - printf "\nWhat is the max size for log files on this machine [10k]? " - read -e - if [ -n "$REPLY" ]; then - max_log_size=$REPLY - fi - printf "\nWhat is the IP address or server name for the syslog server? " - read -e - syslog_server_ip=$REPLY - printf "\nWhat port does the syslog daemon run on? " - read -e - if is_numeric "$REPLY"; then - syslog_server_port=$REPLY - - PROTOCOLS="udp tcp" - PS3="Please select the protocol to use: " - select syslog_server_protocol in $PROTOCOLS; - do - case $syslog_server_protocol in - "tcp") - break ;; - "udp") - break;; - esac - done - - printf "\n" - printf "\nLogging will be configured as follows:" - printf "\n======================================" - printf "\n Max Logfile Size: $max_log_size" - printf "\n Remote Server: $syslog_server_ip" - printf "\n Remote Port: $syslog_server_port" - printf "\n Logging Protocol: $syslog_server_protocol" - printf "\n" - printf "\nPlease confirm these changes (Y/N)" - read -e - case $REPLY in - Y|y) - ovirt_rsyslog $syslog_server_ip \ - $syslog_server_port \ - $syslog_server_protocol - sed -i -e "s/^size=.*/size=$max_log_size/" \ - /etc/logrotate.d/ovirt-logrotate.conf - break - ;; - N|n) - printf "Discarding settings\n" - break - ;; - esac - else - printf "Invalid port number\n" - fi + while true; do + printf "\n" + read -p "What is the max size for log files on this machine (def. $max_log_size)? " + + if [ -n "$REPLY" ]; then + r=$(echo $REPLY|tr '[[:lower:]]' '[[:upper:]]') + if [[ $r =~ ^[0-9]+$ ]] && [[ $r -gt 0 ]]; then + max_log_size=$r + printf "\nMaximum logging size will be ${max_log_size}k.\n" + break + elif [ "ABORT" == "$r" ]; then + printf "\nAborting...\n" + return + else + printf "\nInvalid input.\n" + fi + else + printf "\nLeaving log size as $max_log_size.\n" + break + fi + done + + printf "\n" + read -p "What is the IP address or hostname for the syslog server? " + if [ -n "$REPLY" ]; then + syslog_server_ip=$REPLY + while true; do + read -p "What port does the syslog daemon use? " + r=$(echo $REPLY|tr '[[:lower:]]' '[[:upper:]]') + if [ -n "$r" ]; then + if [[ $r =~ ^[0-9]+$ ]] && [[ $r -gt 0 ]]; then + syslog_server_port=$REPLY + break + elif [ "ABORT" == "$r" ]; then + printf "\nAbort...\n" + return + else + printf "Invalid port.\n" + fi + fi + done + + printf "\n" + while true; do + read -p "Remote logging uses [t]cp or [u]dp, or [a]bort? " + r=$(echo $REPLY|tr '[[:lower:]]' '[[:upper:]]') + if [ "$r" == "T" ]; then syslog_server_protocol="tcp"; break; fi + if [ "$r" == "U" ]; then syslog_server_protocol="udp"; break; fi + if [ "$r" == "A" ]; then return; fi + # else + printf "Invalid input.\n" + done + else + printf "\nDisabling remote logging.\n" + fi + + printf "\n" + printf "\nLogging will be configured as follows:" + printf "\n======================================" + printf "\n Max Logfile Size: $max_log_size" + if [ -n "$syslog_server_ip" ]; then + printf "\n Remote Server: $syslog_server_ip" + printf "\n Remote Port: $syslog_server_port" + printf "\n Logging Protocol: $syslog_server_protocol" + fi + printf "\n" + printf "\n" + while true; do + read -p "Is this correct (Y/N/A)? " + r=$(echo $REPLY|tr '[[:lower:]]' '[[:upper:]]') + if [ "$r" == "Y" ]; then + printf "\nSaving configuration.\n" + ovirt_rsyslog $syslog_server_ip \ + $syslog_server_port \ + $syslog_server_protocol + sed -i -e "s/^size=.*/size=${max_log_size}k/" \ + /etc/logrotate.d/ovirt-logrotate.conf + return + elif [ "$r" == "N" ]; then + printf "\nRestarting logging configuration.\n" + break + elif [ "$r" == "A" ]; then + printf "\nAborting logging configuration.\n" + return + fi + done done - } # AUTO for auto-install -- 1.6.0.4 From d.vasilets at peterhost.ru Fri Dec 12 15:07:59 2008 From: d.vasilets at peterhost.ru (=?koi8-r?Q?=F7=C1=D3=C9=CC=C5=C3_?= =?koi8-r?Q?=E4=CD=C9=D4=D2=C9=CA?=) Date: Fri, 12 Dec 2008 18:07:59 +0300 Subject: [Ovirt-devel] ovirt see only 1 node. how to add other servers ? In-Reply-To: <49426573.3050904@redhat.com> References: <1228317705.11195.2.camel@dima-desktop> <4936A549.5000203@redhat.com> <1228389599.7273.5.camel@dima-desktop> <1228479650.13032.7.camel@dima-desktop> <4939BE7C.80305@redhat.com> <1228757099.11371.4.camel@dima-desktop> <493D95DB.6090802@redhat.com> <1228819017.559.7.camel@dima-desktop> <49426573.3050904@redhat.com> Message-ID: <1229094479.5845.5.camel@dima-desktop> Hello i send identify information from second node starting "ovirt-identify-node -s 192.168.50.2 -p 12120 -d -v" but in listing "Hosts" hypervisor field empty i think ovirt-appliance can't connect to libvirtd ? ???, 12/12/2008 ? 08:21 -0500, Perry Myers ?????: > ?? wrote: > > Sorry for my English. > > You understand everything correctly > > > > Yes , shutdown -h now ovirt-appliance and after few minuts virsh destroy > > I try fsck in singlemode and set in fstab check file system but many > > services(such as postgresql and dirmng start with errors or not start) > > What version of the appliance are you using? .95/x86_64? > > I looked at your logs and it looks like the ovirt servers are not started, > since taskomatic log complains that it cannot connect to postgres. > > The ovirt-server-appliance-setup.log looks truncated like it ran partially > but did not get a chance to finish, and I don't see a log in /var/log/ace. > There should be an install.log there that will tell me how the appliance > firstboot went. > > Can you try reinstalling the appliance to run the firstboot again, and > recapture the logs? I'd like to see the ace install.log to make sure the > appliance setup is completing properly. > > Thanks, > > Perry > > -------------- next part -------------- A non-text attachment was scrubbed... Name: ovirt-appliance.varlog.tgz Type: application/x-compressed-tar Size: 56988 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: Screenshot.png Type: image/png Size: 151428 bytes Desc: not available URL: From d.vasilets at peterhost.ru Fri Dec 12 15:30:36 2008 From: d.vasilets at peterhost.ru (=?koi8-r?Q?=F7=C1=D3=C9=CC=C5=C3_?= =?koi8-r?Q?=E4=CD=C9=D4=D2=C9=CA?=) Date: Fri, 12 Dec 2008 18:30:36 +0300 Subject: [Ovirt-devel] ovirt see only 1 node. how to add other servers ? In-Reply-To: <1229094479.5845.5.camel@dima-desktop> References: <1228317705.11195.2.camel@dima-desktop> <4936A549.5000203@redhat.com> <1228389599.7273.5.camel@dima-desktop> <1228479650.13032.7.camel@dima-desktop> <4939BE7C.80305@redhat.com> <1228757099.11371.4.camel@dima-desktop> <493D95DB.6090802@redhat.com> <1228819017.559.7.camel@dima-desktop> <49426573.3050904@redhat.com> <1229094479.5845.5.camel@dima-desktop> Message-ID: <1229095837.7026.1.camel@dima-desktop> This is in /var/log/ovirt-server/host-status.log Connecting to host 192.168.50.254 libvir: Remote error : Failed to start SASL negotiation: -4 (SASL(-4): no mechanism available: No worthy mechs found) Connecting to host physical.priv.ovirt.org libvir: Remote error : Failed to start SASL negotiation: -4 (SASL(-4): no mechanism available: No worthy mechs found) All needed livrary are installed ? ???, 12/12/2008 ? 18:07 +0300, ??????? ??????? ?????: > Hello > i send identify information from second node starting > "ovirt-identify-node -s 192.168.50.2 -p 12120 -d -v" > but in listing "Hosts" hypervisor field empty > i think ovirt-appliance can't connect to libvirtd > > > ? ???, 12/12/2008 ? 08:21 -0500, Perry Myers ?????: > > ?? wrote: > > > Sorry for my English. > > > You understand everything correctly > > > > > > Yes , shutdown -h now ovirt-appliance and after few minuts virsh destroy > > > I try fsck in singlemode and set in fstab check file system but many > > > services(such as postgresql and dirmng start with errors or not start) > > > > What version of the appliance are you using? .95/x86_64? > > > > I looked at your logs and it looks like the ovirt servers are not started, > > since taskomatic log complains that it cannot connect to postgres. > > > > The ovirt-server-appliance-setup.log looks truncated like it ran partially > > but did not get a chance to finish, and I don't see a log in /var/log/ace. > > There should be an install.log there that will tell me how the appliance > > firstboot went. > > > > Can you try reinstalling the appliance to run the firstboot again, and > > recapture the logs? I'd like to see the ace install.log to make sure the > > appliance setup is completing properly. > > > > Thanks, > > > > Perry > > > > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel From pmyers at redhat.com Fri Dec 12 15:31:26 2008 From: pmyers at redhat.com (Perry Myers) Date: Fri, 12 Dec 2008 10:31:26 -0500 Subject: [Ovirt-devel] ovirt see only 1 node. how to add other servers ? In-Reply-To: <1229094479.5845.5.camel@dima-desktop> References: <1228317705.11195.2.camel@dima-desktop> <4936A549.5000203@redhat.com> <1228389599.7273.5.camel@dima-desktop> <1228479650.13032.7.camel@dima-desktop> <4939BE7C.80305@redhat.com> <1228757099.11371.4.camel@dima-desktop> <493D95DB.6090802@redhat.com> <1228819017.559.7.camel@dima-desktop> <49426573.3050904@redhat.com> <1229094479.5845.5.camel@dima-desktop> Message-ID: <494283CE.6050208@redhat.com> ?? wrote: > Hello > i send identify information from second node starting > "ovirt-identify-node -s 192.168.50.2 -p 12120 -d -v" > but in listing "Hosts" hypervisor field empty > i think ovirt-appliance can't connect to libvirtd Why are you running ovirt-identify-node manually? That should run only as part of the Node bootup sequence automatically. Are you running that on the 192.168.50.254 host or is this a different physical machine? In the logs you sent, the only hosts that I can see that have tried to register with the Server are 192.168.50.254 and 192.168.50.1. If there are other nodes that have tried to register, the host-browser daemon on the Appliance did not see them. Can you give me the logs from these other nodes? I also saw errors like this in your host-status log: > Connecting to host 192.168.50.254 > libvir: Remote error : Failed to start SASL negotiation: -4 (SASL(-4): no mechanism available: No worthy mechs found) This could be a time synchronization issue. Please run date --utc on both the host running the Appliance, the appliance and all nodes and let me know what the results are Also, from your appliance in an ssh session try: klist ping -c 1 192.168.50.254 virsh -c qemu+tcp://192.168.50.254/system list And give me the output for those commands. Thanks, Perry From pmyers at redhat.com Fri Dec 12 15:39:37 2008 From: pmyers at redhat.com (Perry Myers) Date: Fri, 12 Dec 2008 10:39:37 -0500 Subject: [Ovirt-devel] Re: [PATCH node] Created stateful and stateless subpackages used for installing on bare metal Fedora hosts In-Reply-To: <1229048031-573-1-git-send-email-pmyers@redhat.com> References: <1229048031-573-1-git-send-email-pmyers@redhat.com> Message-ID: <494285B9.5070801@redhat.com> Perry Myers wrote: > ovirt-node-stateless is for use on the embedded oVirt Node. > ovirt-node-stateful is for use on already installed Fedora hosts to configure > that host to act as a Node. Presently it only works when run on the same > host as the oVirt Appliance. > > ovirt-node RPM provides common binaries/scripts used by the subpackages > > Splitting up the RPMs is required since ovirt-node RPM now packages up > gptsync which conflicts with anaconda. This patch series was pushed. Received an offline ACK from Alan Pevec who had the following suggestions (which were implemented in the push) 1. ovirt-node-stateful and ovirt-node-stateless can't exist on the same machine so put in Conflicts: for each with the other 2. Removed symlink for ovirt-install-node and ovirt-uninstall-node as it was an untracked file and instead users should call ovirt-install-node-stateless, ovirt-install-node-stateful and ovirt-uninstall-node-stateful directly From d.vasilets at peterhost.ru Fri Dec 12 15:54:29 2008 From: d.vasilets at peterhost.ru (=?koi8-r?Q?=F7=C1=D3=C9=CC=C5=C3_?= =?koi8-r?Q?=E4=CD=C9=D4=D2=C9=CA?=) Date: Fri, 12 Dec 2008 18:54:29 +0300 Subject: [Ovirt-devel] ovirt see only 1 node. how to add other servers ? In-Reply-To: <494283CE.6050208@redhat.com> References: <1228317705.11195.2.camel@dima-desktop> <4936A549.5000203@redhat.com> <1228389599.7273.5.camel@dima-desktop> <1228479650.13032.7.camel@dima-desktop> <4939BE7C.80305@redhat.com> <1228757099.11371.4.camel@dima-desktop> <493D95DB.6090802@redhat.com> <1228819017.559.7.camel@dima-desktop> <49426573.3050904@redhat.com> <1229094479.5845.5.camel@dima-desktop> <494283CE.6050208@redhat.com> Message-ID: <1229097269.7026.12.camel@dima-desktop> ? ???, 12/12/2008 ? 10:31 -0500, Perry Myers ?????: > ?? wrote: > > Hello > > i send identify information from second node starting > > "ovirt-identify-node -s 192.168.50.2 -p 12120 -d -v" > > but in listing "Hosts" hypervisor field empty > > i think ovirt-appliance can't connect to libvirtd > > Why are you running ovirt-identify-node manually? That should run only as > part of the Node bootup sequence automatically. Automaticaly this query "dig +short -t srv _$1._$2.$(dnsdomainname)" from /etc/init.d/ovirt-functions haven't answer (i didn't configure dns for local zones). > > Are you running that on the 192.168.50.254 host or is this a different > physical machine? physical machine is 192.168.50.254 and 192.168.50.1 ovirt-appliance virtual machine is 192.168.50.2 on 192.168.50.1 > > In the logs you sent, the only hosts that I can see that have tried to > register with the Server are 192.168.50.254 and 192.168.50.1. If there > are other nodes that have tried to register, the host-browser daemon on > the Appliance did not see them. Can you give me the logs from these other > nodes? > > I also saw errors like this in your host-status log: > > > Connecting to host 192.168.50.254 > > libvir: Remote error : Failed to start SASL negotiation: -4 (SASL(-4): no mechanism available: No worthy mechs found) > > This could be a time synchronization issue. Please run > date --utc > on both the host running the Appliance, the appliance and all nodes and > let me know what the results are on all nodes time is Fri Dec 12 15:43:58 UTC 2008 Fri Dec 12 15:43:49 UTC 2008 Fri Dec 12 15:43:40 UTC 2008 > > Also, from your appliance in an ssh session try: > > klist > ping -c 1 192.168.50.254 > virsh -c qemu+tcp://192.168.50.254/system list > > And give me the output for those commands. [root at management ~]# klist Ticket cache: FILE:/tmp/krb5cc_0 Default principal: admin at PRIV.OVIRT.ORG Valid starting Expires Service principal 12/12/08 14:13:19 12/13/08 14:13:19 krbtgt/PRIV.OVIRT.ORG at PRIV.OVIRT.ORG 12/12/08 14:13:20 12/13/08 14:13:19 ldap/management.priv.ovirt.org at PRIV.OVIRT.ORG 12/12/08 14:13:20 12/13/08 14:13:19 HTTP/management.priv.ovirt.org at PRIV.OVIRT.ORG Kerberos 4 ticket cache: /tmp/tkt0 klist: You have no tickets cached [root at management ~]# virsh -c qemu+tcp://192.168.50.254/system list libvir: Remote error : Failed to start SASL negotiation: -4 (SASL(-4): no mechanism available: No worthy mechs found) error: failed to connect to the hypervisor [root at management ~]# ping -c 1 192.168.50.254 PING 192.168.50.254 (192.168.50.254) 56(84) bytes of data. 64 bytes from 192.168.50.254: icmp_seq=1 ttl=64 time=0.554 ms --- 192.168.50.254 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.554/0.554/0.554/0.000 ms > > Thanks, > > Perry > From pmyers at redhat.com Fri Dec 12 17:00:30 2008 From: pmyers at redhat.com (Perry Myers) Date: Fri, 12 Dec 2008 12:00:30 -0500 Subject: [Ovirt-devel] ovirt see only 1 node. how to add other servers ? In-Reply-To: <1229097269.7026.12.camel@dima-desktop> References: <1228317705.11195.2.camel@dima-desktop> <4936A549.5000203@redhat.com> <1228389599.7273.5.camel@dima-desktop> <1228479650.13032.7.camel@dima-desktop> <4939BE7C.80305@redhat.com> <1228757099.11371.4.camel@dima-desktop> <493D95DB.6090802@redhat.com> <1228819017.559.7.camel@dima-desktop> <49426573.3050904@redhat.com> <1229094479.5845.5.camel@dima-desktop> <494283CE.6050208@redhat.com> <1229097269.7026.12.camel@dima-desktop> Message-ID: <494298AE.6010308@redhat.com> ?? wrote: > ? ???, 12/12/2008 ? 10:31 -0500, Perry Myers ?????: >> ?? wrote: >>> Hello >>> i send identify information from second node starting >>> "ovirt-identify-node -s 192.168.50.2 -p 12120 -d -v" >>> but in listing "Hosts" hypervisor field empty >>> i think ovirt-appliance can't connect to libvirtd >> Why are you running ovirt-identify-node manually? That should run only as >> part of the Node bootup sequence automatically. > > Automaticaly this query "dig +short -t srv _$1._$2.$(dnsdomainname)" > from /etc/init.d/ovirt-functions haven't answer (i didn't configure dns > for local zones). DNS on the oVirt Appliance is provided by dnsmasq which provides the DNS SRV records that oVirt needs automatically. The Appliance won't work with external DNS without major changes to it. From the .254 Node and the Appliance what is the output of: dig +short -t srv _ovirt._tcp.priv.ovirt.org >> Are you running that on the 192.168.50.254 host or is this a different >> physical machine? > physical machine is 192.168.50.254 and 192.168.50.1 Ok > ovirt-appliance virtual machine is 192.168.50.2 on 192.168.50.1 Ok >> In the logs you sent, the only hosts that I can see that have tried to >> register with the Server are 192.168.50.254 and 192.168.50.1. If there >> are other nodes that have tried to register, the host-browser daemon on >> the Appliance did not see them. Can you give me the logs from these other >> nodes? >> >> I also saw errors like this in your host-status log: >> >>> Connecting to host 192.168.50.254 >>> libvir: Remote error : Failed to start SASL negotiation: -4 (SASL(-4): no mechanism available: No worthy mechs found) >> This could be a time synchronization issue. Please run >> date --utc >> on both the host running the Appliance, the appliance and all nodes and >> let me know what the results are > on all nodes time is Fri Dec 12 15:43:58 UTC 2008 > Fri Dec 12 15:43:49 UTC 2008 > Fri Dec 12 15:43:40 UTC 2008 Ok, so not a time sync issue then >> Also, from your appliance in an ssh session try: >> >> klist >> ping -c 1 192.168.50.254 >> virsh -c qemu+tcp://192.168.50.254/system list >> >> And give me the output for those commands. > > [root at management ~]# klist > Ticket cache: FILE:/tmp/krb5cc_0 > Default principal: admin at PRIV.OVIRT.ORG > > Valid starting Expires Service principal > 12/12/08 14:13:19 12/13/08 14:13:19 > krbtgt/PRIV.OVIRT.ORG at PRIV.OVIRT.ORG > 12/12/08 14:13:20 12/13/08 14:13:19 > ldap/management.priv.ovirt.org at PRIV.OVIRT.ORG > 12/12/08 14:13:20 12/13/08 14:13:19 > HTTP/management.priv.ovirt.org at PRIV.OVIRT.ORG > > > Kerberos 4 ticket cache: /tmp/tkt0 > klist: You have no tickets cached > [root at management ~]# virsh -c qemu+tcp://192.168.50.254/system list > libvir: Remote error : Failed to start SASL negotiation: -4 (SASL(-4): > no mechanism available: No worthy mechs found) > error: failed to connect to the hypervisor > [root at management ~]# ping -c 1 192.168.50.254 > PING 192.168.50.254 (192.168.50.254) 56(84) bytes of data. > 64 bytes from 192.168.50.254: icmp_seq=1 ttl=64 time=0.554 ms > > --- 192.168.50.254 ping statistics --- > 1 packets transmitted, 1 received, 0% packet loss, time 0ms > rtt min/avg/max/mdev = 0.554/0.554/0.554/0.000 ms Ok, so we've ruled out a time sync issue. And you have valid kerberos tickets on the appliance. And we know the Node at .254 is running since you can ping it. The next question is, does the Node have a valid kerberos ticket? Can you give me the /var/log/ovirt.log file from the .254 Node? And do you have an /etc/libvirt/krb5.tab file on the Node? Perry From halsaadi at thoughtworks.com Fri Dec 12 17:03:42 2008 From: halsaadi at thoughtworks.com (Hadi Al-Saadi) Date: Fri, 12 Dec 2008 22:33:42 +0530 Subject: [Ovirt-devel] help Message-ID: help im not able to boot from ISO after creating it and puting it in cobbler dir.. it giveing qued and after that failed -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: host-status.log Type: application/octet-stream Size: 29733 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: host-browser.log Type: application/octet-stream Size: 14691 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: taskomatic.log Type: application/octet-stream Size: 10489 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: rails.log Type: application/octet-stream Size: 217730 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: mongrel.log Type: application/octet-stream Size: 2804 bytes Desc: not available URL: From lutter at redhat.com Fri Dec 12 17:33:53 2008 From: lutter at redhat.com (David Lutterkort) Date: Fri, 12 Dec 2008 17:33:53 +0000 Subject: [Ovirt-devel] ovirt installation test scenarios In-Reply-To: <493D4671.3090003@redhat.com> References: <4939B473.7050701@redhat.com> <493D4671.3090003@redhat.com> Message-ID: <1229103233.26198.3.camel@galia.watzmann.net> On Mon, 2008-12-08 at 11:08 -0500, Michael DeHaan wrote: > Somewhat unrelated, is Ovirt doing any DHCP management? Cobbler has a > built in feature for this that would probably be useful. DNS also -- > and it does support dnsmasq in addition to the BIND stuff. This allows > you to pin certain mac addresses to certain ip's and hostnames, just by > creating cobbler system records with that information filled in. Can you also manage SRV records with cobbler ? If we want to rely on cobbler for DNS mgmt, we'd need to be able to put both A and SRV records into DNS. David From bkearney at redhat.com Fri Dec 12 17:37:18 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Fri, 12 Dec 2008 12:37:18 -0500 Subject: [Ovirt-devel] [PATCH node] Usability fixes to the logging configuration. In-Reply-To: <1229092069-16641-1-git-send-email-dpierce@redhat.com> References: <1229092069-16641-1-git-send-email-dpierce@redhat.com> Message-ID: <4942A14E.7020500@redhat.com> Some comments below Darryl L. Pierce wrote: > Users can now abort the configuration. At any point the user can enter > either "abort" or an "a" depending on the input and quit the logging > configuration. > > Also smoothes out the overall flow of configuration. > > Signed-off-by: Darryl L. Pierce > --- > scripts/ovirt-config-logging | 144 ++++++++++++++++++++++++++---------------- > 1 files changed, 90 insertions(+), 54 deletions(-) > > diff --git a/scripts/ovirt-config-logging b/scripts/ovirt-config-logging > index f79597f..8e6bc70 100755 > --- a/scripts/ovirt-config-logging > +++ b/scripts/ovirt-config-logging > @@ -71,62 +71,98 @@ function is_numeric { > } > > function prompt_user { > + max_log_size="10" > + syslog_server_ip="" > + syslog_server_port="" > + > while true ; do > - max_log_size="10k" > - printf "\nWhat is the max size for log files on this machine [10k]? " > - read -e > - if [ -n "$REPLY" ]; then > - max_log_size=$REPLY > - fi > - printf "\nWhat is the IP address or server name for the syslog server? " > - read -e > - syslog_server_ip=$REPLY > - printf "\nWhat port does the syslog daemon run on? " > - read -e > - if is_numeric "$REPLY"; then > - syslog_server_port=$REPLY > - > - PROTOCOLS="udp tcp" > - PS3="Please select the protocol to use: " > - select syslog_server_protocol in $PROTOCOLS; > - do > - case $syslog_server_protocol in > - "tcp") > - break ;; > - "udp") > - break;; > - esac > - done > - > - printf "\n" > - printf "\nLogging will be configured as follows:" > - printf "\n======================================" > - printf "\n Max Logfile Size: $max_log_size" > - printf "\n Remote Server: $syslog_server_ip" > - printf "\n Remote Port: $syslog_server_port" > - printf "\n Logging Protocol: $syslog_server_protocol" > - printf "\n" > - printf "\nPlease confirm these changes (Y/N)" > - read -e > - case $REPLY in > - Y|y) > - ovirt_rsyslog $syslog_server_ip \ > - $syslog_server_port \ > - $syslog_server_protocol > - sed -i -e "s/^size=.*/size=$max_log_size/" \ > - /etc/logrotate.d/ovirt-logrotate.conf > - break > - ;; > - N|n) > - printf "Discarding settings\n" > - break > - ;; > - esac > - else > - printf "Invalid port number\n" > - fi > + while true; do > + printf "\n" > + read -p "What is the max size for log files on this machine (def. $max_log_size)? " I would let folks know that this is in kilibytes > + > + if [ -n "$REPLY" ]; then > + r=$(echo $REPLY|tr '[[:lower:]]' '[[:upper:]]') > + if [[ $r =~ ^[0-9]+$ ]] && [[ $r -gt 0 ]]; then > + max_log_size=$r > + printf "\nMaximum logging size will be ${max_log_size}k.\n" > + break > + elif [ "ABORT" == "$r" ]; then > + printf "\nAborting...\n" > + return this is undocumented. Will every input line allow me to ABORT? > + else > + printf "\nInvalid input.\n" > + fi > + else > + printf "\nLeaving log size as $max_log_size.\n" > + break > + fi > + done > + > + printf "\n" > + read -p "What is the IP address or hostname for the syslog server? " > + if [ -n "$REPLY" ]; then > + syslog_server_ip=$REPLY > + while true; do > + read -p "What port does the syslog daemon use? " > + r=$(echo $REPLY|tr '[[:lower:]]' '[[:upper:]]') > + if [ -n "$r" ]; then > + if [[ $r =~ ^[0-9]+$ ]] && [[ $r -gt 0 ]]; then > + syslog_server_port=$REPLY > + break > + elif [ "ABORT" == "$r" ]; then > + printf "\nAbort...\n" > + return > + else > + printf "Invalid port.\n" > + fi > + fi > + done > + > + printf "\n" > + while true; do > + read -p "Remote logging uses [t]cp or [u]dp, or [a]bort? " > + r=$(echo $REPLY|tr '[[:lower:]]' '[[:upper:]]') > + if [ "$r" == "T" ]; then syslog_server_protocol="tcp"; break; fi > + if [ "$r" == "U" ]; then syslog_server_protocol="udp"; break; fi > + if [ "$r" == "A" ]; then return; fi > + # else > + printf "Invalid input.\n" > + done > + else > + printf "\nDisabling remote logging.\n" > + fi I found it odd that if I hit return I could stilll commit the logging change, but if I hit the abort then I lost both chanages. I would suggest the following: - Keep the abort at the end of the process. - Allow me to "skip" over the rsyslog - Loose the ABORT Logic > + > + printf "\n" > + printf "\nLogging will be configured as follows:" > + printf "\n======================================" > + printf "\n Max Logfile Size: $max_log_size" > + if [ -n "$syslog_server_ip" ]; then > + printf "\n Remote Server: $syslog_server_ip" > + printf "\n Remote Port: $syslog_server_port" > + printf "\n Logging Protocol: $syslog_server_protocol" > + fi > + printf "\n" > + printf "\n" > + while true; do > + read -p "Is this correct (Y/N/A)? " > + r=$(echo $REPLY|tr '[[:lower:]]' '[[:upper:]]') > + if [ "$r" == "Y" ]; then > + printf "\nSaving configuration.\n" > + ovirt_rsyslog $syslog_server_ip \ > + $syslog_server_port \ > + $syslog_server_protocol > + sed -i -e "s/^size=.*/size=${max_log_size}k/" \ > + /etc/logrotate.d/ovirt-logrotate.conf > + return > + elif [ "$r" == "N" ]; then > + printf "\nRestarting logging configuration.\n" > + break > + elif [ "$r" == "A" ]; then > + printf "\nAborting logging configuration.\n" > + return > + fi > + done > done > - > } > > # AUTO for auto-install From apevec at redhat.com Fri Dec 12 18:32:12 2008 From: apevec at redhat.com (Alan Pevec) Date: Fri, 12 Dec 2008 19:32:12 +0100 Subject: [Ovirt-devel] [PATCH node] ovirt-config-boot - minimal installer for livecd image to local disk In-Reply-To: <1229012213-27356-1-git-send-email-apevec@redhat.com> References: <1229012213-27356-1-git-send-email-apevec@redhat.com> Message-ID: <1229106732-15062-1-git-send-email-apevec@redhat.com> LiveOS folder is copied to /dev/HostVG/Root LVM volume, kernel,initrd and GRUB are installed to /dev/HostVG/Boot partition. livecd initrd is modified on the fly to support LVM, which is not included in initramfs produced by mayflower/mkliveinitrd Example usage: ovirt-config-boot "$disk" /live "$bootparam1 $bootparam2" caller is responsible to issue reboot Signed-off-by: Alan Pevec --- Makefile.am | 1 + ovirt-node.spec.in | 5 ++ scripts/ovirt-config-boot | 122 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 0 deletions(-) create mode 100755 scripts/ovirt-config-boot diff --git a/Makefile.am b/Makefile.am index a47beaa..09ba56b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,6 +27,7 @@ EXTRA_DIST = \ scripts/collectd.conf.in \ scripts/ovirt \ scripts/ovirt-awake \ + scripts/ovirt-config-boot \ scripts/ovirt-config-logging \ scripts/ovirt-config-networking \ scripts/ovirt-config-password \ diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in index ef49b39..8303537 100644 --- a/ovirt-node.spec.in +++ b/ovirt-node.spec.in @@ -35,6 +35,7 @@ Requires: bind-utils # qemu-img RPM. Requires: qemu-img Requires: nc +Requires: grub Requires: /usr/sbin/crond ExclusiveArch: %{ix86} x86_64 @@ -111,6 +112,7 @@ cd - %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/logrotate.d %{__install} -p -m0755 scripts/ovirt-awake %{buildroot}%{_sbindir} +%{__install} -p -m0755 scripts/ovirt-config-boot %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-logging %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-networking %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-password %{buildroot}%{_sbindir} @@ -202,6 +204,8 @@ fi %files stateless %defattr(-,root,root,0755) +%{_sbindir}/ovirt-awake +%{_sbindir}/ovirt-config-boot %{_sbindir}/ovirt-config-logging %{_sbindir}/ovirt-config-networking %{_sbindir}/ovirt-config-password @@ -242,6 +246,7 @@ fi * Thu Dec 11 2008 Perry Myers - 0.96 - Subpackage stateful/stateless to separate out functionality for embedded Node and Node running as part of already installed OS +- ovirt-config-* setup scripts for standalone mode * Thu Sep 11 2008 Chris Lalancette - 0.92 0.7 - Add the ovirt-install- and ovirt-uninstall-node scripts, and refactor diff --git a/scripts/ovirt-config-boot b/scripts/ovirt-config-boot new file mode 100755 index 0000000..ad0aeb1 --- /dev/null +++ b/scripts/ovirt-config-boot @@ -0,0 +1,122 @@ +#!/bin/bash +# +# ovirt-config-boot - configure local boot disk partition + +# SYNOPSIS +# ovirt-config-boot livecd_path bootparams +# +# boot_disk - boot disk device e.g. /dev/sda +# +# livecd_path - where livecd media is mounted, +# parent of LiveOS and isolinux folders +# +# bootparams - extra boot parameters like console=... +# + +# Source functions library +. /etc/init.d/functions +. /etc/init.d/ovirt-functions + + +# local_boot_install livecd_path bootparams +# livecd_path -livecd media +# bootparams - extra boot parameters like console=... +# +# copy oVirt Node image to the local LVM /dev/HostVG +ovirt_boot_setup() { + local disk=$1 + local live=$2 + local bootparams=$3 + printf "installing oVirt Node image ... " + mount_boot + mount_liveos + # install oVirt Node image for local boot + if [ -e "$live/syslinux" ]; then + syslinux=syslinux + elif [ -e "$live/isolinux" ]; then + syslinux=isolinux + else + syslinux= + fi + rm -rf /boot/grub + rm -rf /liveos/LiveOS + mkdir -p /boot/grub + mkdir -p /liveos/LiveOS + cp -p $live/LiveOS/squashfs.img /liveos/LiveOS \ + && cp -p $live/$syslinux/vmlinuz0 /boot + rc=$? + if [ $rc -ne 0 ]; then + printf "image copy failed\n" + return $rc + fi + # append LVM support to the livecd initramfs + tmpdir=$(mktemp -d) + cd $tmpdir + gzip -dc $live/$syslinux/initrd0.img | + cpio -id init sbin/real-init 2> /dev/null + init_script=init + if [ -e sbin/real-init ]; then + # Fedora 10 mkliveinitrd + init_script=sbin/real-init + fi + sed -i '/^\/sbin\/udev.*settle/ a \echo Scanning logical volumes\ +lvm vgscan --ignorelockingfailure\ +echo Activating logical volumes\ +lvm vgchange -ay --ignorelockingfailure HostVG \ +' $init_script + # fix emergency shell + sed -i 's/^ bash$/ bash < \/dev\/console/' $init_script + # do not fail if device node already exists + sed -i 's/mknod.*$/& || :/' $init_script + mkdir -p bin + bit= + if [ -e /lib64 ]; then + bit=64 + fi + mkdir -p lib$bit + if [ -e /sbin/lvm.static ]; then + cp /sbin/lvm.static bin/lvm + else + cp /sbin/lvm bin + # lvm is not static in Fedora + cp /lib$bit/libreadline.so.5 /lib$bit/libncurses.so.5 lib$bit + fi + find $init_script bin/lvm lib$bit -type f | + cpio -H newc --quiet -o | + gzip -9 | + cat $live/$syslinux/initrd0.img - > /boot/initrd0.img + + cat > /boot/grub/grub.conf << EOF +default=0 +timeout=5 +hiddenmenu +title oVirt Node + root (hd0,0) + kernel /vmlinuz0 ro root=/dev/HostVG/Root roottypefs=ext3 liveimg $bootparams + initrd /initrd0.img +EOF + echo "(hd0) $disk" > /boot/grub/device.map + ( cd /usr/share/grub/*; cp -p stage? e2fs_stage1_5 /boot/grub ) + grub --device-map=/boot/grub/device.map > /dev/null < References: <1229012273-27387-1-git-send-email-apevec@redhat.com> Message-ID: <1229106776-15088-1-git-send-email-apevec@redhat.com> use LVM partitions created by o-c-storage use file bindmounts for persisted configs use optional /config from livecd image support for old and new udev versions add BOOTIF=link|eth* support Signed-off-by: Alan Pevec --- scripts/ovirt | 22 --- scripts/ovirt-early | 392 ++++++++++++++++------------------------------- scripts/ovirt-functions | 167 ++++++++++++++++---- 3 files changed, 270 insertions(+), 311 deletions(-) mode change 100644 => 100755 scripts/ovirt mode change 100644 => 100755 scripts/ovirt-post diff --git a/scripts/ovirt b/scripts/ovirt old mode 100644 new mode 100755 index 81733a5..e2c406b --- a/scripts/ovirt +++ b/scripts/ovirt @@ -11,28 +11,6 @@ . /etc/init.d/ovirt-functions start() { - # retrieve config from local OVIRT partition if available - ovirt=$(mktemp -d) - ovirt_mount $ovirt - # /config on OVIRT partition contains persisted /etc files - cfg=$ovirt/config - if [ -d $cfg/etc ]; then - cp -rv $cfg/etc/* /etc - restorecon -r /etc - fi - # and optional Augeas augtool script - aug=$cfg/config.aug - if [ -f $aug ]; then - tmpaug=$(mktemp) - cp $aug $tmpaug - echo "save" >> $tmpaug - augtool < $tmpaug > /dev/null 2>&1 - if [ $? -eq 0 ]; then - printf "$aug applied." - fi - fi - umount $ovirt && rmdir $ovirt - if is_standalone; then exit 0 fi diff --git a/scripts/ovirt-early b/scripts/ovirt-early index c09a987..7257d89 100755 --- a/scripts/ovirt-early +++ b/scripts/ovirt-early @@ -10,8 +10,6 @@ . /etc/init.d/functions . /etc/init.d/ovirt-functions -# size of the oVirt partition in megabytes -OVIRT_SIZE=64 BONDING_MODCONF_FILE=/etc/modprobe.d/bonding AUGTOOL_CONFIG=/var/tmp/augtool-config @@ -48,12 +46,15 @@ configure_from_network() { ovirt-process-config $cfgdb $BONDING_MODCONF_FILE $AUGTOOL_CONFIG if [ -f $AUGTOOL_CONFIG ]; then echo "Loading remote config" + # avoid bindmount issues with augeas + umount_config /etc/sysconfig/network-scripts/ifcfg-eth* augtool < $AUGTOOL_CONFIG \ && echo "Remote config applied" \ || echo "Failed applying remote config" fi if ls /etc/sysconfig/network-scripts/ifcfg-eth* > /dev/null 2>&1; then echo "Network interfaces created from remote config" + ovirt_store_config /etc/sysconfig/network-scripts/ifcfg-eth* return else echo "Remote config contained no network interfaces" @@ -61,6 +62,7 @@ configure_from_network() { else echo "Failed to retrieve configuration bundle" fi + rm $cfgdb fi fi fi @@ -80,14 +82,29 @@ configure_from_network() { echo "Default config applied" } -# find_disk $bus $serial $live_disk +# $(get_live_disk) +# livecd boot disk +get_live_disk() { + local live_dev=/dev/live + if [ ! -e $live_dev ]; then + # PXE boot + live_dev=/dev/loop0 + live_disk= + else + live_part=$(readlink -e $live_dev) + live_disk=$(basename $(dirname $(udev_info $live_part path))) + fi + echo $live_disk +} + +# find_disk $bus $serial find_disk() { local bus=$1 local serial=$2 - local live=$3 + local live=$(get_live_disk) for d in /dev/disk/by-id/{scsi,usb}*; do ID_FS_USAGE= - eval $(udevinfo --query env --name $d) + eval $(udev_info $d env) # ID_FS_USAGE is set for partitions if [ -z "$ID_FS_USAGE" -a "$ID_BUS" = "$bus" ]; then if [ -z "$serial" -o "$ID_SERIAL" = "$serial" ]; then @@ -104,216 +121,10 @@ find_disk() { return 1 } -# TODO move to ovirt-config-storage -# local_install $local_boot $local_disk $bootparams -# local_boot - 1=install LiveOS and boot loader -# 0=initialize oVirt partition only -# local_disk - local disk to hold the oVirt partition -# =usb|scsi[:serial#] -# bootparams - extra boot parameters like console= -# -# oVirt partition is a local primary ext2 partition, labeled OVIRT -# content: -# /config - local oVirt configuration (ktab, local admin password) -# /boot - boot loader, kernel and initramfs -# /LiveOS - oVirt Node compressed livecd image - -local_install() { - local local_boot=$1 - local local_disk=$2 - local bootparams=$3 - local disk - local part - local live_part - local live_disk - local live_dev=/dev/live - if [ ! -e $live_dev ]; then - # PXE boot - live_dev=/dev/loop0 - live_part=$live_dev - live_disk= - else - live_part=$(readlink -e $live_dev) - live_disk=${live_disk%[1-9]} - fi - local ovirt_part=$(readlink -e /dev/disk/by-label/$OVIRT_LABEL) - local ovirt_disk=${ovirt_part%[1-9]} - if [ "$ovirt_disk" = "$ovirt_part" ]; then - ovirt_disk= - fi - if [ -z "$local_disk" ]; then - if [ -z "$ovirt_disk" ]; then - return 1 - fi - # ovirt_init not specified, use pre-labeled oVirt partition - mode=update - disk=$ovirt_disk - part=$ovirt_part - else - case "$local_disk" in - =) - # empty ovirt_init, use current live image device - mode=update - disk=$live_disk - part=$live_part - ;; - =scsi*) - bus=scsi - serial=${local_disk#=scsi:} - mode=install - ;; - =usb*) - bus=usb - serial=${local_disk#=usb:} - mode=install - ;; - *) - return 1 - ;; - esac - if [ $mode = "install" ]; then - if [ "$serial" = "=$bus" ]; then - serial= - fi - disk=$(find_disk $bus $serial $live_disk) - rc=$? - if [ $rc -ne 0 ]; then - echo "local disk '$local_disk' not available" - return 1 - fi - if [ -n "$ovirt_disk" ]; then - if [ "$disk" = "$ovirt_disk" ]; then - # local disk contains oVirt partition, select it for update - # TODO force reinstall option - mode=update - part=$ovirt_part - else - # remove label from oVirt partition, there can be only one - e2label $ovirt_part "" - fi - fi - fi - if [ "$mode" = "install" ]; then - printf "installing $disk..." | tee /dev/console - dd if=/dev/zero bs=4096 count=1 of=$disk \ - && parted -s $disk mklabel msdos \ - && parted -s $disk mkpart primary ext2 0.0 $OVIRT_SIZE \ - && partprobe -s $disk - if [ $? -ne 0 ]; then - echo "$disk partition creation failed"; return 1 - fi - part=${disk}1 - udevsettle - mkfs.ext2 -L $OVIRT_LABEL $part \ - && tune2fs -c0 -i0 $part - if [ $? -ne 0 ]; then - echo "$disk ext2 creation failed"; return 1 - fi - # update by-label link manually, mkfs won't trigger udev - mkdir -p /dev/disk/by-label - ln -sf $part /dev/disk/by-label/$OVIRT_LABEL - fi - fi - - if [ "$mode" = "update" ]; then - printf "updating $disk..." | tee /dev/console - fi - ovirt=$(mktemp -d) - if [ "$part" = "$live_part" ]; then - # ovirt_init w/o local disk specified - # setup /config on live disk, if writeable - # TODO mlabel/e2label (check fs2 type or just blindly try?) - mount -r $part $ovirt && mount -o remount,rw $ovirt \ - && mkdir -p $ovirt/config - umount $ovirt && rmdir $ovirt - return 0 - fi - live=$(mktemp -d) - mount -r $live_dev $live - if [ $? -ne 0 ]; then - echo "source image mount failed" - rmdir $live - return 1 - fi - mount $part $ovirt - if [ $? -ne 0 ]; then - echo "local disk mount failed" - umount $live && rmdir $live - rmdir $ovirt - return 1 - fi - mkdir -p $ovirt/config - # update local config using the one embedded in livecd image - # TODO admin tool for adding /config into livecd image - if [ -d $live/config ]; then - cp -rv $live/config/* $ovirt/config \ - || echo "config copy failed" - fi - - if [ $local_boot = 0 ]; then - # config update only, cleanup and continue booting - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - else - # install oVirt Node image for local boot - if [ -e "$live/syslinux" ]; then - syslinux=syslinux - elif [ -e "$live/isolinux" ]; then - syslinux=isolinux - else - syslinux= - fi - rm -rf $ovirt/boot - rm -rf $ovirt/LiveOS - mkdir -p $ovirt/boot/grub - mkdir -p $ovirt/LiveOS - cp -p $live/LiveOS/squashfs.img $ovirt/LiveOS \ - && cp -p $live/$syslinux/initrd0.img $ovirt/boot \ - && cp -p $live/$syslinux/vmlinuz0 $ovirt/boot - if [ $? -ne 0 ]; then - echo "image copy failed" - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - return 1 - fi - part_num=$(( ${part#$disk} - 1 )) - cat > $ovirt/boot/grub/grub.conf << EOF -default=0 -timeout=2 -hiddenmenu -title oVirt Node - root (hd0,$part_num) - kernel /boot/vmlinuz0 ro root=LABEL=OVIRT roottypefs=ext2 liveimg $bootparams - initrd /boot/initrd0.img -EOF - grub-install --root-directory=$ovirt $disk >&2 - if [ $? -ne 0 ]; then - echo "boot loader install failed" - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - return 1 - fi - # remove 1.5 stages we don't need - find $ovirt/boot/grub -name '*_stage1_5' ! -name e2fs_stage1_5 \ - -exec rm {} \; - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - # FIXME avoid reboot loops - # temp. workaround: sync and wait - sync; sync; sync - printf "oVirt local installation finished, press Enter to reboot." \ - > /dev/console - read key - if [ "$key" = "debug" ]; then - sh > /dev/console 2>&1 - fi - reboot - fi -} start() { # oVirt boot parameters - # BOOTIF= (appended by pxelinux) + # BOOTIF=link|eth*| (appended by pxelinux) # ovirt_init=usb|scsi[:serial#] # ovirt_vol=BOOT_MB:SWAP_MB:ROOT_MB:CONFIG_MB:LOGGING_MB # ovirt_local_boot @@ -324,11 +135,14 @@ start() { # syslog=server[:port] # TBD logrotate maxsize - # BOOTIF= (appended by pxelinux) + # BOOTIF=link|eth*| (appended by pxelinux) # network boot interface is assumed to be on management network where # oVirt Server is reachable - # IPAPPEND 2 in pxelinux.cfg appends MAC address of the booting node - # e.g. BOOTIF=01-00-16-3e-12-34-57 + # BOOTIF= e.g. BOOTIF=01-00-16-3e-12-34-57 + # PXELINUX option IPAPPEND 2 in pxelinux.cfg appends MAC address + # of the booting node + # BOOTIF=link - take first eth for which ethtool reports link + # BOOTIF=eth* e.g. BOOTIF=eth0 - use given interface bootif= # ovirt_init=usb|scsi[:serial#] @@ -337,23 +151,23 @@ start() { # serial# - select exact disk using serial number, as reported by # udev ID_SERIAL # e.g. ovirt_init=usb:Generic_STORAGE_DEVICE_0000145418-0:0 - ovirt_init= + init= # ovirt_vol=BOOT_MB:SWAP_MB:ROOT_MB:CONFIG_MB:LOGGING_MB # local partition sizes in GB - ovirt_vol_boot= - ovirt_vol_swap= - ovirt_vol_root= - ovirt_vol_config= - ovirt_vol_logging= + vol_boot_size= + vol_swap_size= + vol_root_size= + vol_config_size= + vol_logging_size= # ovirt_local_boot # install/update oVirt Node image on the local installation target disk - ovirt_local_boot=0 + local_boot=0 # ovirt_standalone # force oVirt Node standalone mode - ovirt_standalone=0 + standalone=0 # pxelinux format: ip=::: # anaconda format: ip= netmask= gateway= @@ -376,25 +190,65 @@ start() { for i in $(cat /proc/cmdline); do case $i in - BOOTIF=??-??-??-??-??-??-??) - i=${i#BOOTIF=??-} - bootif=$(grep -il $(echo $i|sed 's/-/:/g') /sys/class/net/eth*/address|rev|cut -d/ -f2|rev) + BOOTIF=*) + i=${i#BOOTIF=} + case "$i" in + eth*) + bootif=$i + ;; + link) + for eth in $(cd /sys/class/net; echo eth*); do + if ethtool $eth 2>/dev/null|grep -q "Link detected: yes" + then + bootif=$eth + break + fi + done + ;; + ??-??-??-??-??-??-??) + i=${i#??-} + bootif=$(grep -il $(echo $i|sed 's/-/:/g') /sys/class/net/eth*/address|rev|cut -d/ -f2|rev) + ;; + esac ;; ovirt_init*) - ovirt_init=${i#ovirt_init} - if [ -z "$ovirt_init" ]; then - ovirt_init='=' + i=${i#ovirt_init} + if [ -n "$i" ]; then + # resolve to disk device + case "$i" in + =scsi*) + bus=scsi + i=${i#=scsi} + serial=${i#:} + ;; + =usb*) + bus=usb + i=${i#=usb} + serial=${i#:} + ;; + *) + bus= + serial= + ;; + esac + if [ -n "$bus" ]; then + init=$(find_disk $bus $serial) + fi + else + # 'ovirt_init' without value: grab first disk + init=/dev/?da fi ;; ovirt_vol=*) i=${i#ovirt_vol=} - eval $(printf $i|awk -F: '{print "ovirt_vol_boot="$1; ovirt_vol_swap="$2; print "ovirt_vol_root="$3; print "ovirt_vol_config="$4; print "ovirt_vol_logging="$5;}') + eval $(printf $i|awk -F: '{print "vol_boot_size="$1; print "vol_swap_size="$2; print "vol_root_size="$3; print "vol_config_size="$4; print "vol_logging_size="$5;}') ;; ovirt_local_boot*) - ovirt_local_boot=1 + local_boot=1 ;; ovirt_standalone*) - ovirt_standalone=1 + standalone=1 + bootparams="$bootparams $i" ;; ip=*) i=${i#ip=} @@ -418,41 +272,64 @@ start() { ;; esac done - # save boot parameters as defaults for ovirt-config-* + if [ -z "$ip_netmask" ]; then ip_netmask=$netmask fi if [ -z "$ip_gateway" ]; then ip_gateway=$gateway fi + # save boot parameters as defaults for ovirt-config-* + params="bootif init vol_boot_size vol_swap_size vol_root_size vol_config_size vol_logging_size local_boot standalone ip_address ip_netmask ip_gateway ipv6 syslog_server syslog_port bootparams" + mount_config + if [ -e $OVIRT_DEFAULTS ]; then + # update persisted defaults + tmpaug=$(mktemp) + for p in $params; do + PARAM=$(uc $p) + value=$(ptr $p) + if [ -n "$value" ] ; then + echo "set /files$OVIRT_DEFAULTS/OVIRT_$PARAM '\"$value\"'" \ + >> $tmpaug + fi + done + if [ -s $tmpaug ]; then + echo "save" >> $tmpaug + # augtool on bindmounted files fails, + # so edit file at persistent config root, /config + augtool -r /config < $tmpaug > /dev/null + rm $tmpaug + fi + else + # initial startup, dump all ovirt bootparams + echo > $OVIRT_DEFAULTS + for p in $params; do + PARAM=$(uc $p) + echo "OVIRT_$PARAM='$(ptr $p)'" >> $OVIRT_DEFAULTS + done + ovirt_store_config $OVIRT_DEFAULTS + fi - cat > $OVIRT_DEFAULTS </dev/null | (read MD5 filename; echo $MD5) +} + +# return uppercase value +uc() { + echo $(echo $1|tr '[[:lower:]]' '[[:upper:]]') +} + +# return indirect value +# non-bashism for ${!var} +ptr() { + local v=$1 + eval "v=\$$v" + echo $v +} + +# mount livecd media +# e.g. CD /dev/sr0, USB /dev/sda1, +# PXE /dev/loop0 (loopback ISO) +mount_live() { + if grep -q " /live " /proc/mounts; then + return 0 + fi + local live_dev=/dev/live + if [ ! -e $live_dev ]; then + # PXE boot + live_dev=/dev/loop0 + fi + mkdir -p /live + mount $live_dev /live +} + +# mount boot partition +# boot loader + kernel + initrd +mount_boot() { + if grep -q " /boot " /proc/mounts; then + return 0 + fi + mkdir -p /boot + mount /dev/disk/by-label/BOOT /boot +} + +# mount liveos partition +# LiveOS/ +mount_liveos() { + if grep -q " /liveos " /proc/mounts; then + return 0 + fi + mkdir -p /liveos + mount /dev/HostVG/Root /liveos +} + +# mount config partition +# /config for persistance +mount_config() { + if grep -q " /config " /proc/mounts; then + return 0 + fi + mkdir -p /config + mount /dev/HostVG/Config /config + if grep -q " /config " /proc/mounts; then + # optional config embedded in the livecd image + if [ -e /live/config ]; then + cp -rv --update /live/config/* /config + fi + # bind mount all persisted configs to rootfs + for f in $(find /config -type f); do + target=${f#/config} + if grep -q " $target " /proc/mounts ; then + # skip if already bind-mounted + true + else + mount -n --bind $f $target + fi + done else - mount -r /dev/live $1 \ - || mount /dev/live $1 + # /config is not available + return 1 fi } -md5() { - md5sum $1 2>/dev/null | (read MD5 filename; echo $MD5) +# unmount bindmounted config files +# umount_config /etc/config /etc/config2 ... +# +# Use before running sed -i or augeas against the bindmounted file, +# Otherwise save fails: https://fedorahosted.org/augeas/ticket/32 +# After file is replaced, call ovirt_store_config /etc/config /etc/config2 ... +# to bindmount the config file again. +# +# Alternatively, use augtool -r /config +umount_config() { + if grep -q " /config " /proc/mounts; then + for f in "$@"; do + if grep -q " $f " /proc/mounts ; then + umount -n $f + # refresh rootfs copy + cp /config$f $f + fi + done + fi } -# persist configuration to /config on OVIRT partition +# persist configuration to /config # ovirt_store_config /etc/config /etc/config2 ... +# copy to /config and bind-mount back ovirt_store_config() { - ovirt=$(mktemp -d) - ovirt_mount $ovirt - cfg=$ovirt/config - rw=0 - printf "store config:" - for f in "$@"; do - # ignore non-/etc paths - if [ $f != ${f#/etc/} ]; then - # check if changed - if [ "$(md5 $f)" != "$(md5 $cfg$f)" ]; then - if [ $rw = 0 ]; then - mount -o remount,rw $ovirt - rw=1 - fi - mkdir -p $cfg$(dirname $f) - cp $f $cfg$f - printf " $f" - fi - fi - done - echo - umount $ovirt && rmdir $ovirt + if grep -q " /config " /proc/mounts; then + printf "storing to /config :" + for f in "$@"; do + printf " $f" + # skip if already bind-mounted + if grep -q " $f " /proc/mounts ; then + printf " already persisted\n" + else + mkdir -p /config$(dirname $f) + cp -a $f /config$f \ + && mount -n --bind /config$f $f \ + || printf " failed to persist\n" + fi + done + echo + else + printf "warning: persistent config storage not available\n" + fi +} + +# compat function to handle different udev versions +udev_info() { + local name=$1 + local query=$2 + local out + + # old udev command with shortopts + out=$(udevinfo -n $name -q $query) + rc=$? + if [ $rc -ne 0 ]; then + out=$(udevadm info --name=$name --query=$query) + rc=$? + fi + if [ $rc -eq 0 ]; then + echo $out + fi + return $rc } backup_file() { diff --git a/scripts/ovirt-post b/scripts/ovirt-post old mode 100644 new mode 100755 -- 1.6.0.4 From apevec at redhat.com Fri Dec 12 18:33:40 2008 From: apevec at redhat.com (Alan Pevec) Date: Fri, 12 Dec 2008 19:33:40 +0100 Subject: [Ovirt-devel] [PATCH node] auto install and firstboot fixes In-Reply-To: <1229012334-27415-1-git-send-email-apevec@redhat.com> References: <1229012334-27415-1-git-send-email-apevec@redhat.com> Message-ID: <1229106820-15115-1-git-send-email-apevec@redhat.com> * Autoinstall is performed when required boot parameters are specified: - BOOTIF=link|eth*|01-11-22-33-44-55-66 for choosing management NIC (IPv4 DHCP is assumed) - ovirt_init=usb|scsi to select a local disk drive to create oVirt LVM volumes If ovirt_vol parameter is missing, default volume sizes are used: BOOT 50MB SWAP 2 * RAM size ROOT 256MB CONFIG 5MB LOGGING 256MB DATA rest of the disk equivalent is ovirt_vol=50::256:5:256 * Show firstboot menu only once. Firstboot state is stored in the persistent config storage. * Use the drive selected by ovirt_init boot parameter. Signed-off-by: Alan Pevec --- scripts/ovirt-config-storage | 45 ++++++++++++++++++++++------------------- scripts/ovirt-firstboot | 16 +++++++++++++- scripts/ovirt-functions | 36 +++++++++++++++++++++------------ 3 files changed, 61 insertions(+), 36 deletions(-) diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage index e2ddec1..fd877e2 100755 --- a/scripts/ovirt-config-storage +++ b/scripts/ovirt-config-storage @@ -28,13 +28,25 @@ check_partition_sizes() # or just let the mke2fs failure suffice. } -# Find a usable/selected storage device along with its size in bytes. +get_selected_drive_size() +{ + local udi=$(hal-find-by-property --key block.device --string $DRIVE) + if [ -z "$udi" ]; then + warn "ERROR: selected storage device is not available" + return 1 + fi + size=$(hal-get-property --udi "$udi" --key storage.size) + SPACE=$(echo "scale=0; $size / (1024 * 1024)" | bc -l) + echo "selected device: $DRIVE ($SPACE MB)" +} + +# Find a usable/selected storage device. # If there are none, give a diagnostic and return nonzero. # If there is just one, e.g., /dev/sda, treat it as selected (see below). # and return 0. If there are two or more, make the user select one # or decline. Upon decline, return nonzero. Otherwise, print the -# selected name, a space, and its size, then return 0. -# Sample output: "/dev/sda 320072933376" +# selected name, then return 0. +# Sample output: /dev/sda get_dev_name() { local udi_list=$(hal-find-by-capability --capability storage) @@ -58,20 +70,16 @@ get_dev_name() *) warn "block device name $block_dev doesn't start with '/';" \ " skipping"; continue;; esac - size=$(hal-get-property --udi "$d" --key storage.size) test -z "$devices" \ && devices=$block_dev \ || devices="$devices $block_dev" - test -z "$sizes" \ - && sizes=$size \ - || sizes="$sizes $size" done # If there's only one device, use it. case $devices in '') warn "ERROR: found no usable block device"; return 1;; *' '*) ;; # found more than one - *) echo "$devices $sizes"; return 0;; # just one + *) echo "$devices"; return 0;; # just one esac # There are two or more; make the user choose. @@ -80,10 +88,7 @@ get_dev_name() do test "$device" = Abort && return 1 test -z "$device" && continue - # $REPLY is the selected number; - # use that to map to the corresponding size. - size=$(echo "$sizes"|cut -d' ' -f "$REPLY") - echo "$device $size" + echo "$device" return 0 done } @@ -91,13 +96,8 @@ get_dev_name() do_configure() { local name_and_size - name_and_size=$(get_dev_name) || exit 1 - set -- $name_and_size - DRIVE=$1 - local n_bytes=$2 - - SPACE=$(echo "scale=0; $n_bytes / (1024 * 1024)" | bc -l) - echo "selected device: $DRIVE ($SPACE MB)" + DRIVE=$(get_dev_name) || exit 1 + get_selected_drive_size for i in boot swap root config logging ; do uc=$(echo $i|tr '[[:lower:]]' '[[:upper:]]') @@ -270,10 +270,13 @@ ROOT_SIZE=${OVIRT_VOL_ROOT_SIZE:-$default_root_size} CONFIG_SIZE=${OVIRT_VOL_CONFIG_SIZE:-$default_config_size} LOGGING_SIZE=${OVIRT_VOL_LOGGING_SIZE:-$default_logging_size} +if [ -n "$OVIRT_INIT" ]; then + # if present, use the drive selected with 'ovirt_init' boot parameter + DRIVE=$OVIRT_INIT + get_selected_drive_size +fi if [ "$1" == "AUTO" ]; then - # In "AUTO" mode, OVIRT_INIT should be defined in the environment. - DRIVE=$OVIRT_INIT check_partition_sizes printf "Partitioning hard disk..." perform_partitioning diff --git a/scripts/ovirt-firstboot b/scripts/ovirt-firstboot index 5df49d4..f8056e5 100755 --- a/scripts/ovirt-firstboot +++ b/scripts/ovirt-firstboot @@ -35,11 +35,23 @@ start () ovirt-config-networking AUTO newrole -r system_r -t virtd_t -- -c 'ovirt-config-storage AUTO' ovirt-config-logging AUTO - else - ovirt-config-setup + if [ "$OVIRT_LOCAL_BOOT" = 0 ]; then + mount_live + ovirt-config-boot $OVIRT_INIT /live "$OVIRT_BOOTPARAMS" + reboot + fi + elif is_firstboot; then + ovirt-config-setup < /dev/console fi plymouth --show-splash + + if mount_config; then + augtool -r /config > /dev/null < References: <1229012352-27442-1-git-send-email-apevec@redhat.com> Message-ID: <4942AF03.6080008@redhat.com> > scripts/ovirt-firstboot | 8 +++++++- updated patch was merged into [PATCH node] auto install and firstboot fixes From apevec at redhat.com Fri Dec 12 18:36:13 2008 From: apevec at redhat.com (Alan Pevec) Date: Fri, 12 Dec 2008 19:36:13 +0100 Subject: [Ovirt-devel] [PATCH node] get memory info directly from /proc/meminfo Message-ID: <1229106973-15145-1-git-send-email-apevec@redhat.com> to avoid libvirt dependecy and to drop newrole workaround for selinux issue with initrc_t Signed-off-by: Alan Pevec --- scripts/ovirt-config-setup | 2 +- scripts/ovirt-config-storage | 3 +-- scripts/ovirt-firstboot | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/scripts/ovirt-config-setup b/scripts/ovirt-config-setup index 639b7b8..20dd5ae 100755 --- a/scripts/ovirt-config-setup +++ b/scripts/ovirt-config-setup @@ -31,7 +31,7 @@ while true; do case "$OPTION" in "$NETWORK") ovirt-config-networking ; break ;; "$STORAGE") - newrole -r system_r -t virtd_t -- -c ovirt-config-storage ; + ovirt-config-storage ; break ;; "$LOGGING") ovirt-config-logging ; break ;; "$PASSWORD") ovirt-config-password ; break ;; diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage index fd877e2..dd3fab1 100755 --- a/scripts/ovirt-config-storage +++ b/scripts/ovirt-config-storage @@ -256,8 +256,7 @@ do_confirm() done } -MEM_SIZE=$(virsh --readonly -c qemu:///system nodeinfo \ - | awk '/Memory size/ { print $3 }') +MEM_SIZE=$(cat /proc/meminfo | awk '/MemTotal:/ { print $2 }') case $MEM_SIZE in ''|*[^0-9]*) die failed to get system memory size;; esac diff --git a/scripts/ovirt-firstboot b/scripts/ovirt-firstboot index f8056e5..1767618 100755 --- a/scripts/ovirt-firstboot +++ b/scripts/ovirt-firstboot @@ -33,7 +33,7 @@ start () if is_auto_install; then ovirt-config-networking AUTO - newrole -r system_r -t virtd_t -- -c 'ovirt-config-storage AUTO' + ovirt-config-storage AUTO ovirt-config-logging AUTO if [ "$OVIRT_LOCAL_BOOT" = 0 ]; then mount_live -- 1.6.0.4 From apevec at redhat.com Fri Dec 12 18:36:23 2008 From: apevec at redhat.com (Alan Pevec) Date: Fri, 12 Dec 2008 19:36:23 +0100 Subject: [Ovirt-devel] [PATCH node] set default swap size to twice the RAM size Message-ID: <1229106983-15171-1-git-send-email-apevec@redhat.com> --- scripts/ovirt-config-storage | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage index dd3fab1..2fae9fe 100755 --- a/scripts/ovirt-config-storage +++ b/scripts/ovirt-config-storage @@ -261,7 +261,7 @@ case $MEM_SIZE in ''|*[^0-9]*) die failed to get system memory size;; esac -MEM_SIZE=$(echo "scale=0; $MEM_SIZE / 1024" | bc -l) +MEM_SIZE=$(echo "scale=0; $MEM_SIZE / 1024 * 2" | bc -l) SWAP_SIZE=${OVIRT_VOL_SWAP_SIZE:-$MEM_SIZE} BOOT_SIZE=${OVIRT_VOL_BOOT_SIZE:-$default_boot_size} -- 1.6.0.4 From bkearney at redhat.com Fri Dec 12 18:35:39 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Fri, 12 Dec 2008 13:35:39 -0500 Subject: [Ovirt-devel] ovirt installation test scenarios In-Reply-To: <494184AF.1030103@redhat.com> References: <4939B473.7050701@redhat.com> <493D4671.3090003@redhat.com> <493EED36.3060304@redhat.com> <494184AF.1030103@redhat.com> Message-ID: <4942AEFB.5070509@redhat.com> Joey Boggs wrote: > Pushed the latest build 0.0.94 Needs some testing to find bugs in the > installer > > RPM + SRPM: http://cobalt.rdu.redhat.com/ovirt/ace-ovirt-0.0.94/ > git: http://github.com/jboggs/ace-ovirt/tree/master > > You will need to enable the fedora-testing repo to get the latest > ace-postgres package, there is a bug in the current one in the ovirt repo. > > For right now run the installer as : > /usr/share/ace/modules/ovirt/ovirt-installer > It will write your install config file based on your choices then run > like the old method, I'll bridge the gaps in by the next release in a > day or so. Stupid output from running this is at [1] Your prompt lines show what appear to be defaults what is your foo (bar)? If I hit enter, I expct for bar to be accepted. I would either accept the defatulr, or make it clear that bar is an example. Such as what is your foo (example: bar) [1] http://ovirt.pastebin.com/d1e4497d From slinabery at redhat.com Fri Dec 12 18:46:44 2008 From: slinabery at redhat.com (Steve Linabery) Date: Fri, 12 Dec 2008 12:46:44 -0600 Subject: [Ovirt-devel] [PATCH server] Add audit trail to model for members joining/leaving containers Message-ID: <1229107604-31790-1-git-send-email-slinabery@redhat.com> E.g. hosts joining/leaving hardware_pools --- src/app/models/hardware_pool.rb | 13 ++++++++++- src/app/models/host.rb | 1 + src/app/models/membership_audit_event.rb | 26 ++++++++++++++++++++++ src/app/models/pool.rb | 1 + src/db/migrate/032_add_pool_audit_trail.rb | 32 ++++++++++++++++++++++++++++ 5 files changed, 72 insertions(+), 1 deletions(-) create mode 100644 src/app/models/membership_audit_event.rb create mode 100644 src/db/migrate/032_add_pool_audit_trail.rb diff --git a/src/app/models/hardware_pool.rb b/src/app/models/hardware_pool.rb index d39d8e7..8307ce4 100644 --- a/src/app/models/hardware_pool.rb +++ b/src/app/models/hardware_pool.rb @@ -54,8 +54,19 @@ class HardwarePool < Pool hosts = Host.find(:all, :conditions => "id in (#{host_ids.join(', ')})") transaction do hosts.each do |host| - host.hardware_pool_id = target_pool_id + + leave = MembershipAuditEvent.new({ :member_target => host, + :container_target => host.hardware_pool, + :action => MembershipAuditEvent::LEAVE }) + leave.save! + + host.hardware_pool = HardwarePool.find(target_pool_id) host.save! + + join = MembershipAuditEvent.new({ :member_target => host, + :container_target => host.hardware_pool, + :action => MembershipAuditEvent::JOIN }) + join.save! end end end diff --git a/src/app/models/host.rb b/src/app/models/host.rb index 640782d..5e24dcf 100644 --- a/src/app/models/host.rb +++ b/src/app/models/host.rb @@ -23,6 +23,7 @@ class Host < ActiveRecord::Base belongs_to :hardware_pool belongs_to :bonding_type + has_many :membership_audit_events, :as => :member_target, :dependent => :destroy, :order => "created_at ASC" has_many :cpus, :dependent => :destroy has_many :nics, :dependent => :destroy has_many :bondings, :dependent => :destroy diff --git a/src/app/models/membership_audit_event.rb b/src/app/models/membership_audit_event.rb new file mode 100644 index 0000000..b36cbee --- /dev/null +++ b/src/app/models/membership_audit_event.rb @@ -0,0 +1,26 @@ +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Steve Linabery +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +class MembershipAuditEvent < ActiveRecord::Base + belongs_to :container_target, :polymorphic => true + belongs_to :member_target, :polymorphic => true + + JOIN = "join" + LEAVE = "leave" +end diff --git a/src/app/models/pool.rb b/src/app/models/pool.rb index 7034e79..614325a 100644 --- a/src/app/models/pool.rb +++ b/src/app/models/pool.rb @@ -20,6 +20,7 @@ class Pool < ActiveRecord::Base acts_as_nested_set + has_many :membership_audit_events, :as => :container_target, :dependent => :destroy # moved associations here so that nested set :include directives work # TODO: find a way to put this back into vm_resource_pool.rb has_many :vms, :dependent => :nullify, :order => "id ASC", :foreign_key => :vm_resource_pool_id diff --git a/src/db/migrate/032_add_pool_audit_trail.rb b/src/db/migrate/032_add_pool_audit_trail.rb new file mode 100644 index 0000000..656ad87 --- /dev/null +++ b/src/db/migrate/032_add_pool_audit_trail.rb @@ -0,0 +1,32 @@ +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Steve Linabery +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +class AddPoolAuditTrail < ActiveRecord::Migration + def self.up + create_table :membership_audit_events do |t| + t.timestamp :created_at + t.string :action + t.integer :container_target_id + t.string :container_target_type + t.integer :member_target_id + t.string :member_target_type + t.integer :lock_version, :default => 0 + end + end +end -- 1.6.0.4 From apevec at redhat.com Fri Dec 12 18:52:47 2008 From: apevec at redhat.com (Alan Pevec) Date: Fri, 12 Dec 2008 19:52:47 +0100 Subject: [Ovirt-devel] [PATCH node-image] updated config script needs hal-find-by-property Message-ID: <1229107967-15483-1-git-send-email-apevec@redhat.com> --- common-blacklist.ks | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/common-blacklist.ks b/common-blacklist.ks index 98c6edd..5b41982 100644 --- a/common-blacklist.ks +++ b/common-blacklist.ks @@ -99,7 +99,6 @@ blacklist_lib="/usr/lib{,64}/gconv \ blacklist_pango="/usr/lib{,64}/pango /usr/lib{,64}/libpango* \ /etc/pango /usr/bin/pango*" blacklist_hal="/usr/bin/hal-disable-polling \ - /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" blacklist_ssh="/usr/bin/sftp /usr/bin/slogin /usr/bin/ssh /usr/bin/ssh-add \ -- 1.6.0.4 From apevec at redhat.com Fri Dec 12 18:52:57 2008 From: apevec at redhat.com (Alan Pevec) Date: Fri, 12 Dec 2008 19:52:57 +0100 Subject: [Ovirt-devel] [PATCH node-image] add virtio block driver to livecd initramfs Message-ID: <1229107977-15509-1-git-send-email-apevec@redhat.com> not included by default in Fedora 10 livecd initramfs requires updated livecd-tools, available from ovirt.org repo Signed-off-by: Alan Pevec --- common-install.ks | 3 +++ ovirt-node-image.spec.in | 2 +- 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/common-install.ks b/common-install.ks index 4d3610b..dcfaf9a 100644 --- a/common-install.ks +++ b/common-install.ks @@ -10,3 +10,6 @@ services --enabled=ntpd,ntpdate,collectd,iptables,network bootloader --timeout=5 --append="console=tty0 console=ttyS0,115200n8" rootpw --iscrypted Xa8QeYfWrtscM +# not included by default in Fedora 10 livecd initramfs +device virtio_blk +device virtio_pci diff --git a/ovirt-node-image.spec.in b/ovirt-node-image.spec.in index ff285c0..f6429a6 100644 --- a/ovirt-node-image.spec.in +++ b/ovirt-node-image.spec.in @@ -16,7 +16,7 @@ License: GPLv2+ Group: Applications/System BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot URL: http://ovirt.org/ -BuildRequires: livecd-tools >= 020 +BuildRequires: livecd-tools >= 020-2 BuildRequires: syslinux Requires: appliance-tools >= 003.9 -- 1.6.0.4 From jboggs at redhat.com Fri Dec 12 19:03:00 2008 From: jboggs at redhat.com (Joey Boggs) Date: Fri, 12 Dec 2008 14:03:00 -0500 Subject: [Ovirt-devel] ovirt installation test scenarios In-Reply-To: <4942AEFB.5070509@redhat.com> References: <4939B473.7050701@redhat.com> <493D4671.3090003@redhat.com> <493EED36.3060304@redhat.com> <494184AF.1030103@redhat.com> <4942AEFB.5070509@redhat.com> Message-ID: <4942B564.6070505@redhat.com> fixed those entries Bryan Kearney wrote: > Joey Boggs wrote: >> Pushed the latest build 0.0.94 Needs some testing to find bugs in the >> installer >> >> RPM + SRPM: http://cobalt.rdu.redhat.com/ovirt/ace-ovirt-0.0.94/ >> git: http://github.com/jboggs/ace-ovirt/tree/master >> >> You will need to enable the fedora-testing repo to get the latest >> ace-postgres package, there is a bug in the current one in the ovirt >> repo. >> >> For right now run the installer as : >> /usr/share/ace/modules/ovirt/ovirt-installer >> It will write your install config file based on your choices then run >> like the old method, I'll bridge the gaps in by the next release in a >> day or so. > > Stupid output from running this is at [1] > > Your prompt lines show what appear to be defaults > > what is your foo (bar)? > > If I hit enter, I expct for bar to be accepted. I would either accept > the defatulr, or make it clear that bar is an example. Such as > > what is your foo (example: bar) > > [1] http://ovirt.pastebin.com/d1e4497d From dpierce at redhat.com Fri Dec 12 19:34:42 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Fri, 12 Dec 2008 14:34:42 -0500 Subject: [Ovirt-devel] [PATCH node] Usability fixes to the logging configuration. Message-ID: <1229110482-21302-1-git-send-email-dpierce@redhat.com> NOTE: This patch includes fixes per Bryan K's feedback. Users can now abort the configuration. At any point the user can enter either "abort" or an "a" depending on the input and quit the logging configuration. Also smoothes out the overall flow of configuration. Signed-off-by: Darryl L. Pierce --- scripts/ovirt-config-logging | 138 +++++++++++++++++++++++++----------------- 1 files changed, 83 insertions(+), 55 deletions(-) diff --git a/scripts/ovirt-config-logging b/scripts/ovirt-config-logging index f79597f..358a37c 100755 --- a/scripts/ovirt-config-logging +++ b/scripts/ovirt-config-logging @@ -5,7 +5,6 @@ . /etc/init.d/functions . /etc/init.d/ovirt-functions - RSYSLOG_FILE="/etc/rsyslog.conf" # Creates the rsyslog file based on the following inputs @@ -72,61 +71,90 @@ function is_numeric { function prompt_user { while true ; do - max_log_size="10k" - printf "\nWhat is the max size for log files on this machine [10k]? " - read -e - if [ -n "$REPLY" ]; then - max_log_size=$REPLY - fi - printf "\nWhat is the IP address or server name for the syslog server? " - read -e - syslog_server_ip=$REPLY - printf "\nWhat port does the syslog daemon run on? " - read -e - if is_numeric "$REPLY"; then - syslog_server_port=$REPLY - - PROTOCOLS="udp tcp" - PS3="Please select the protocol to use: " - select syslog_server_protocol in $PROTOCOLS; - do - case $syslog_server_protocol in - "tcp") - break ;; - "udp") - break;; - esac - done - - printf "\n" - printf "\nLogging will be configured as follows:" - printf "\n======================================" - printf "\n Max Logfile Size: $max_log_size" - printf "\n Remote Server: $syslog_server_ip" - printf "\n Remote Port: $syslog_server_port" - printf "\n Logging Protocol: $syslog_server_protocol" - printf "\n" - printf "\nPlease confirm these changes (Y/N)" - read -e - case $REPLY in - Y|y) - ovirt_rsyslog $syslog_server_ip \ - $syslog_server_port \ - $syslog_server_protocol - sed -i -e "s/^size=.*/size=$max_log_size/" \ - /etc/logrotate.d/ovirt-logrotate.conf - break - ;; - N|n) - printf "Discarding settings\n" - break - ;; - esac - else - printf "Invalid port number\n" - fi + max_log_size="10" + syslog_server_ip="" + syslog_server_port="" + + while true; do + printf "\n" + read -p "What is the max size, in kilobytes, for local log files (def. ${max_log_size}k)? " + + if [ -n "$REPLY" ]; then + r=$REPLY + if [[ $r =~ ^[0-9]+$ ]] && [[ $r -gt 0 ]]; then + max_log_size=$r + printf "\nMaximum logging size will be ${max_log_size}k.\n" + break + else + printf "\nInvalid input.\n" + fi + else + printf "\nLeaving log size as ${max_log_size}k.\n" + break + fi + done + + printf "\n" + read -p "What is the IP address for the syslog server, hit Enter to skip? " + if [ -n "$REPLY" ]; then + syslog_server_ip=$REPLY + while true; do + read -p "Please enter the remote logging port used: " + r=$REPLY + if [ -n "$r" ]; then + if [[ $r =~ ^[0-9]+$ ]] && [[ $r -gt 0 ]]; then + syslog_server_port=$REPLY + break + else + printf "Invalid port.\n" + fi + fi + done + + printf "\n" + while true; do + read -p "Remote logging uses [t]cp or [u]dp? " + r=$(echo $REPLY|tr '[[:lower:]]' '[[:upper:]]') + if [ "$r" == "T" ]; then syslog_server_protocol="tcp"; break; fi + if [ "$r" == "U" ]; then syslog_server_protocol="udp"; break; fi + # else + printf "Invalid input.\n" + done + else + printf "\nDisabling remote logging.\n" + fi + + printf "\n" + printf "\nLogging will be configured as follows:" + printf "\n======================================" + printf "\n Max Logfile Size: $max_log_size" + if [ -n "$syslog_server_ip" ]; then + printf "\n Remote Server: $syslog_server_ip" + printf "\n Remote Port: $syslog_server_port" + printf "\n Logging Protocol: $syslog_server_protocol" + fi + printf "\n" + printf "\n" + while true; do + read -p "Is this correct (Y/N/A)? " + r=$(echo $REPLY|tr '[[:lower:]]' '[[:upper:]]') + if [ "$r" == "Y" ]; then + printf "\nSaving configuration.\n" + ovirt_rsyslog $syslog_server_ip \ + $syslog_server_port \ + $syslog_server_protocol + sed -i -e "s/^size=.*/size=${max_log_size}k/" \ + /etc/logrotate.d/ovirt-logrotate.conf + return + elif [ "$r" == "N" ]; then + printf "\nRestarting logging configuration.\n" + break + elif [ "$r" == "A" ]; then + printf "\nAborting logging configuration.\n" + return + fi + done done - } # AUTO for auto-install -- 1.6.0.4 From dpierce at redhat.com Fri Dec 12 19:36:14 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Fri, 12 Dec 2008 14:36:14 -0500 Subject: [Ovirt-devel] help In-Reply-To: References: Message-ID: <20081212193614.GC17576@mcpierce-laptop.rdu.redhat.com> On Fri, Dec 12, 2008 at 10:33:42PM +0530, Hadi Al-Saadi wrote: > help im not able to boot from ISO after creating it and puting it in > cobbler dir.. > > it giveing qued and after that failed Per my previous request, please send me the output for the following command on your appliance: showmount -e localhost From what I'm seeing in the logs, the NFS service is not running or else the directory containing the ISO files are not being exported. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From mdehaan at redhat.com Fri Dec 12 20:37:07 2008 From: mdehaan at redhat.com (Michael DeHaan) Date: Fri, 12 Dec 2008 15:37:07 -0500 Subject: [Ovirt-devel] ovirt installation test scenarios In-Reply-To: <1229103233.26198.3.camel@galia.watzmann.net> References: <4939B473.7050701@redhat.com> <493D4671.3090003@redhat.com> <1229103233.26198.3.camel@galia.watzmann.net> Message-ID: <4942CB73.9070808@redhat.com> David Lutterkort wrote: > On Mon, 2008-12-08 at 11:08 -0500, Michael DeHaan wrote: > >> Somewhat unrelated, is Ovirt doing any DHCP management? Cobbler has a >> built in feature for this that would probably be useful. DNS also -- >> and it does support dnsmasq in addition to the BIND stuff. This allows >> you to pin certain mac addresses to certain ip's and hostnames, just by >> creating cobbler system records with that information filled in. >> > > Can you also manage SRV records with cobbler ? If we want to rely on > cobbler for DNS mgmt, we'd need to be able to put both A and SRV records > into DNS. > > David > > > You can add them currently by editing the template, but you can't edit them via the Cobbler API. I'll add an RFE in Trac that we can do for the next release (adding John Eckersberg). From bkearney at redhat.com Fri Dec 12 20:43:44 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Fri, 12 Dec 2008 15:43:44 -0500 Subject: [Ovirt-devel] [PATCH node] Usability fixes to the logging configuration. In-Reply-To: <1229110482-21302-1-git-send-email-dpierce@redhat.com> References: <1229110482-21302-1-git-send-email-dpierce@redhat.com> Message-ID: <4942CD00.8060107@redhat.com> One more thing: Darryl L. Pierce wrote: > NOTE: This patch includes fixes per Bryan K's feedback. > > Users can now abort the configuration. At any point the user can enter > either "abort" or an "a" depending on the input and quit the logging > configuration. > > Also smoothes out the overall flow of configuration. > > Signed-off-by: Darryl L. Pierce > --- > scripts/ovirt-config-logging | 138 +++++++++++++++++++++++++----------------- > 1 files changed, 83 insertions(+), 55 deletions(-) > > diff --git a/scripts/ovirt-config-logging b/scripts/ovirt-config-logging > index f79597f..358a37c 100755 > --- a/scripts/ovirt-config-logging > +++ b/scripts/ovirt-config-logging > @@ -5,7 +5,6 @@ > . /etc/init.d/functions > . /etc/init.d/ovirt-functions > > - > RSYSLOG_FILE="/etc/rsyslog.conf" > > # Creates the rsyslog file based on the following inputs > @@ -72,61 +71,90 @@ function is_numeric { > > function prompt_user { > while true ; do > - max_log_size="10k" > - printf "\nWhat is the max size for log files on this machine [10k]? " > - read -e > - if [ -n "$REPLY" ]; then > - max_log_size=$REPLY > - fi > - printf "\nWhat is the IP address or server name for the syslog server? " > - read -e > - syslog_server_ip=$REPLY > - printf "\nWhat port does the syslog daemon run on? " > - read -e > - if is_numeric "$REPLY"; then > - syslog_server_port=$REPLY > - > - PROTOCOLS="udp tcp" > - PS3="Please select the protocol to use: " > - select syslog_server_protocol in $PROTOCOLS; > - do > - case $syslog_server_protocol in > - "tcp") > - break ;; > - "udp") > - break;; > - esac > - done > - > - printf "\n" > - printf "\nLogging will be configured as follows:" > - printf "\n======================================" > - printf "\n Max Logfile Size: $max_log_size" > - printf "\n Remote Server: $syslog_server_ip" > - printf "\n Remote Port: $syslog_server_port" > - printf "\n Logging Protocol: $syslog_server_protocol" > - printf "\n" > - printf "\nPlease confirm these changes (Y/N)" > - read -e > - case $REPLY in > - Y|y) > - ovirt_rsyslog $syslog_server_ip \ > - $syslog_server_port \ > - $syslog_server_protocol > - sed -i -e "s/^size=.*/size=$max_log_size/" \ > - /etc/logrotate.d/ovirt-logrotate.conf > - break > - ;; > - N|n) > - printf "Discarding settings\n" > - break > - ;; > - esac > - else > - printf "Invalid port number\n" > - fi > + max_log_size="10" > + syslog_server_ip="" > + syslog_server_port="" > + > + while true; do > + printf "\n" > + read -p "What is the max size, in kilobytes, for local log files (def. ${max_log_size}k)? " > + > + if [ -n "$REPLY" ]; then > + r=$REPLY > + if [[ $r =~ ^[0-9]+$ ]] && [[ $r -gt 0 ]]; then > + max_log_size=$r > + printf "\nMaximum logging size will be ${max_log_size}k.\n" > + break > + else > + printf "\nInvalid input.\n" > + fi > + else > + printf "\nLeaving log size as ${max_log_size}k.\n" > + break > + fi > + done > + > + printf "\n" > + read -p "What is the IP address for the syslog server, hit Enter to skip? " > + if [ -n "$REPLY" ]; then > + syslog_server_ip=$REPLY > + while true; do > + read -p "Please enter the remote logging port used: " > + r=$REPLY > + if [ -n "$r" ]; then > + if [[ $r =~ ^[0-9]+$ ]] && [[ $r -gt 0 ]]; then > + syslog_server_port=$REPLY > + break > + else > + printf "Invalid port.\n" > + fi > + fi > + done > + > + printf "\n" > + while true; do > + read -p "Remote logging uses [t]cp or [u]dp? " > + r=$(echo $REPLY|tr '[[:lower:]]' '[[:upper:]]') > + if [ "$r" == "T" ]; then syslog_server_protocol="tcp"; break; fi > + if [ "$r" == "U" ]; then syslog_server_protocol="udp"; break; fi > + # else > + printf "Invalid input.\n" > + done > + else > + printf "\nDisabling remote logging.\n" > + fi > + > + printf "\n" > + printf "\nLogging will be configured as follows:" > + printf "\n======================================" > + printf "\n Max Logfile Size: $max_log_size" > + if [ -n "$syslog_server_ip" ]; then > + printf "\n Remote Server: $syslog_server_ip" > + printf "\n Remote Port: $syslog_server_port" > + printf "\n Logging Protocol: $syslog_server_protocol" > + fi > + printf "\n" > + printf "\n" > + while true; do > + read -p "Is this correct (Y/N/A)? " > + r=$(echo $REPLY|tr '[[:lower:]]' '[[:upper:]]') > + if [ "$r" == "Y" ]; then > + printf "\nSaving configuration.\n" > + ovirt_rsyslog $syslog_server_ip \ > + $syslog_server_port \ > + $syslog_server_protocol You need to not call the line above if $syslog_server_ip is blank. Becuase it adds a malformed row into the /etc/rsyslog.conf file if you do not > + sed -i -e "s/^size=.*/size=${max_log_size}k/" \ > + /etc/logrotate.d/ovirt-logrotate.conf > + return > + elif [ "$r" == "N" ]; then > + printf "\nRestarting logging configuration.\n" > + break > + elif [ "$r" == "A" ]; then > + printf "\nAborting logging configuration.\n" > + return > + fi > + done > done > - > } > > # AUTO for auto-install From sseago at redhat.com Fri Dec 12 20:51:13 2008 From: sseago at redhat.com (Scott Seago) Date: Fri, 12 Dec 2008 15:51:13 -0500 Subject: [Ovirt-devel] [PATCH server] API: add a call to list VMs for a user In-Reply-To: <1228941542-21128-1-git-send-email-lutter@redhat.com> References: <1228941542-21128-1-git-send-email-lutter@redhat.com> Message-ID: <4942CEC1.5080900@redhat.com> David Lutterkort wrote: > Going to the URL /vms will return a list of all the VM's for which the > current user has PRIV_VIEW permission. The VM info contains the host the VM > is running on (if any) > --- > src/app/controllers/vm_controller.rb | 14 ++++++++++++++ > src/config/routes.rb | 2 +- > 2 files changed, 15 insertions(+), 1 deletions(-) > > diff --git a/src/app/controllers/vm_controller.rb b/src/app/controllers/vm_controller.rb > index ff74a37..701dea8 100644 > --- a/src/app/controllers/vm_controller.rb > +++ b/src/app/controllers/vm_controller.rb > @@ -25,6 +25,20 @@ class VmController < ApplicationController > > before_filter :pre_vm_action, :only => [:vm_action, :cancel_queued_tasks, :console] > > + def index > + roles = "('" + > + Permission::roles_for_privilege(Permission::PRIV_VIEW).join("', '") + > + "')" > + user = get_login_user > + @vms = Vm.find(:all, > + :joins => "join permissions p on (vm_resource_pool_id = p.pool_id)", > + :conditions => [ "p.uid = :user and p.user_role in #{roles}", > + { :user => user }]) > Yeah we won't really be able to improve this much until we put the privilege-to-role mapping into the database... Works for me... ACK From dpierce at redhat.com Fri Dec 12 21:13:58 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Fri, 12 Dec 2008 16:13:58 -0500 Subject: [Ovirt-devel] [PATCH node] Usability fixes to the logging configuration. Message-ID: <1229116438-24551-1-git-send-email-dpierce@redhat.com> CHANGED CALL TO ovirt_rsyslog to require the ip, port and protocol to have been set first. Users can now abort the configuration. At any point the user can enter either "abort" or an "a" depending on the input and quit the logging configuration. Also smoothes out the overall flow of configuration. Signed-off-by: Darryl L. Pierce --- scripts/ovirt-config-logging | 142 ++++++++++++++++++++++++++---------------- 1 files changed, 87 insertions(+), 55 deletions(-) diff --git a/scripts/ovirt-config-logging b/scripts/ovirt-config-logging index f79597f..f1daf29 100755 --- a/scripts/ovirt-config-logging +++ b/scripts/ovirt-config-logging @@ -5,7 +5,6 @@ . /etc/init.d/functions . /etc/init.d/ovirt-functions - RSYSLOG_FILE="/etc/rsyslog.conf" # Creates the rsyslog file based on the following inputs @@ -72,61 +71,94 @@ function is_numeric { function prompt_user { while true ; do - max_log_size="10k" - printf "\nWhat is the max size for log files on this machine [10k]? " - read -e - if [ -n "$REPLY" ]; then - max_log_size=$REPLY - fi - printf "\nWhat is the IP address or server name for the syslog server? " - read -e - syslog_server_ip=$REPLY - printf "\nWhat port does the syslog daemon run on? " - read -e - if is_numeric "$REPLY"; then - syslog_server_port=$REPLY - - PROTOCOLS="udp tcp" - PS3="Please select the protocol to use: " - select syslog_server_protocol in $PROTOCOLS; - do - case $syslog_server_protocol in - "tcp") - break ;; - "udp") - break;; - esac - done - - printf "\n" - printf "\nLogging will be configured as follows:" - printf "\n======================================" - printf "\n Max Logfile Size: $max_log_size" - printf "\n Remote Server: $syslog_server_ip" - printf "\n Remote Port: $syslog_server_port" - printf "\n Logging Protocol: $syslog_server_protocol" - printf "\n" - printf "\nPlease confirm these changes (Y/N)" - read -e - case $REPLY in - Y|y) - ovirt_rsyslog $syslog_server_ip \ - $syslog_server_port \ - $syslog_server_protocol - sed -i -e "s/^size=.*/size=$max_log_size/" \ - /etc/logrotate.d/ovirt-logrotate.conf - break - ;; - N|n) - printf "Discarding settings\n" - break - ;; - esac - else - printf "Invalid port number\n" - fi + max_log_size="10" + syslog_server_ip="" + syslog_server_port="" + + while true; do + printf "\n" + read -p "What is the max size, in kilobytes, for local log files (def. ${max_log_size}k)? " + + if [ -n "$REPLY" ]; then + r=$REPLY + if [[ $r =~ ^[0-9]+$ ]] && [[ $r -gt 0 ]]; then + max_log_size=$r + printf "\nMaximum logging size will be ${max_log_size}k.\n" + break + else + printf "\nInvalid input.\n" + fi + else + printf "\nLeaving log size as ${max_log_size}k.\n" + break + fi + done + + printf "\n" + read -p "What is the IP address for the syslog server, hit Enter to skip? " + if [ -n "$REPLY" ]; then + syslog_server_ip=$REPLY + while true; do + read -p "Please enter the remote logging port used: " + r=$REPLY + if [ -n "$r" ]; then + if [[ $r =~ ^[0-9]+$ ]] && [[ $r -gt 0 ]]; then + syslog_server_port=$REPLY + break + else + printf "Invalid port.\n" + fi + fi + done + + printf "\n" + while true; do + read -p "Remote logging uses [t]cp or [u]dp? " + r=$(echo $REPLY|tr '[[:lower:]]' '[[:upper:]]') + if [ "$r" == "T" ]; then syslog_server_protocol="tcp"; break; fi + if [ "$r" == "U" ]; then syslog_server_protocol="udp"; break; fi + # else + printf "Invalid input.\n" + done + else + printf "\nDisabling remote logging.\n" + fi + + printf "\n" + printf "\nLogging will be configured as follows:" + printf "\n======================================" + printf "\n Max Logfile Size: $max_log_size" + if [ -n "$syslog_server_ip" ]; then + printf "\n Remote Server: $syslog_server_ip" + printf "\n Remote Port: $syslog_server_port" + printf "\n Logging Protocol: $syslog_server_protocol" + fi + printf "\n" + printf "\n" + while true; do + read -p "Is this correct (Y/N/A)? " + r=$(echo $REPLY|tr '[[:lower:]]' '[[:upper:]]') + if [ "$r" == "Y" ]; then + printf "\nSaving configuration.\n" + if [[ -n "$syslog_server_ip" ]] && + [[ -n "$syslog_server_port" ]] && + [[ -n "$syslog_server_protocol" ]]; then + ovirt_rsyslog $syslog_server_ip \ + $syslog_server_port \ + $syslog_server_protocol + fi + sed -i -e "s/^size=.*/size=${max_log_size}k/" \ + /etc/logrotate.d/ovirt-logrotate.conf + return + elif [ "$r" == "N" ]; then + printf "\nRestarting logging configuration.\n" + break + elif [ "$r" == "A" ]; then + printf "\nAborting logging configuration.\n" + return + fi + done done - } # AUTO for auto-install -- 1.6.0.4 From sseago at redhat.com Fri Dec 12 21:27:47 2008 From: sseago at redhat.com (Scott Seago) Date: Fri, 12 Dec 2008 16:27:47 -0500 Subject: [Ovirt-devel] [PATCH server] Add audit trail to model for members joining/leaving containers In-Reply-To: <1229107604-31790-1-git-send-email-slinabery@redhat.com> References: <1229107604-31790-1-git-send-email-slinabery@redhat.com> Message-ID: <4942D753.3030405@redhat.com> Steve Linabery wrote: > E.g. hosts joining/leaving hardware_pools > --- > src/app/models/hardware_pool.rb | 13 ++++++++++- > src/app/models/host.rb | 1 + > src/app/models/membership_audit_event.rb | 26 ++++++++++++++++++++++ > src/app/models/pool.rb | 1 + > src/db/migrate/032_add_pool_audit_trail.rb | 32 ++++++++++++++++++++++++++++ > 5 files changed, 72 insertions(+), 1 deletions(-) > create mode 100644 src/app/models/membership_audit_event.rb > create mode 100644 src/db/migrate/032_add_pool_audit_trail.rb > > Works for me. ACK. What's the plan for making this data accessible via the UI and/or another API? Scott From bkearney at redhat.com Fri Dec 12 22:31:17 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Fri, 12 Dec 2008 17:31:17 -0500 Subject: [Ovirt-devel] [PATCH node] Usability fixes to the logging configuration. In-Reply-To: <1229116438-24551-1-git-send-email-dpierce@redhat.com> References: <1229116438-24551-1-git-send-email-dpierce@redhat.com> Message-ID: <4942E635.3090709@redhat.com> Darryl L. Pierce wrote: > CHANGED CALL TO ovirt_rsyslog to require the ip, port and protocol to have > been set first. > > Users can now abort the configuration. At any point the user can enter > either "abort" or an "a" depending on the input and quit the logging > configuration. > > Also smoothes out the overall flow of configuration. > > Signed-off-by: Darryl L. Pierce > --- > scripts/ovirt-config-logging | 142 ++++++++++++++++++++++++++---------------- > 1 files changed, 87 insertions(+), 55 deletions(-) > > diff --git a/scripts/ovirt-config-logging b/scripts/ovirt-config-logging > index f79597f..f1daf29 100755 > --- a/scripts/ovirt-config-logging > +++ b/scripts/ovirt-config-logging > @@ -5,7 +5,6 @@ > . /etc/init.d/functions > . /etc/init.d/ovirt-functions > > - > RSYSLOG_FILE="/etc/rsyslog.conf" > > # Creates the rsyslog file based on the following inputs > @@ -72,61 +71,94 @@ function is_numeric { > > function prompt_user { > while true ; do > - max_log_size="10k" > - printf "\nWhat is the max size for log files on this machine [10k]? " > - read -e > - if [ -n "$REPLY" ]; then > - max_log_size=$REPLY > - fi > - printf "\nWhat is the IP address or server name for the syslog server? " > - read -e > - syslog_server_ip=$REPLY > - printf "\nWhat port does the syslog daemon run on? " > - read -e > - if is_numeric "$REPLY"; then > - syslog_server_port=$REPLY > - > - PROTOCOLS="udp tcp" > - PS3="Please select the protocol to use: " > - select syslog_server_protocol in $PROTOCOLS; > - do > - case $syslog_server_protocol in > - "tcp") > - break ;; > - "udp") > - break;; > - esac > - done > - > - printf "\n" > - printf "\nLogging will be configured as follows:" > - printf "\n======================================" > - printf "\n Max Logfile Size: $max_log_size" > - printf "\n Remote Server: $syslog_server_ip" > - printf "\n Remote Port: $syslog_server_port" > - printf "\n Logging Protocol: $syslog_server_protocol" > - printf "\n" > - printf "\nPlease confirm these changes (Y/N)" > - read -e > - case $REPLY in > - Y|y) > - ovirt_rsyslog $syslog_server_ip \ > - $syslog_server_port \ > - $syslog_server_protocol > - sed -i -e "s/^size=.*/size=$max_log_size/" \ > - /etc/logrotate.d/ovirt-logrotate.conf > - break > - ;; > - N|n) > - printf "Discarding settings\n" > - break > - ;; > - esac > - else > - printf "Invalid port number\n" > - fi > + max_log_size="10" > + syslog_server_ip="" > + syslog_server_port="" > + > + while true; do > + printf "\n" > + read -p "What is the max size, in kilobytes, for local log files (def. ${max_log_size}k)? " > + > + if [ -n "$REPLY" ]; then > + r=$REPLY > + if [[ $r =~ ^[0-9]+$ ]] && [[ $r -gt 0 ]]; then > + max_log_size=$r > + printf "\nMaximum logging size will be ${max_log_size}k.\n" > + break > + else > + printf "\nInvalid input.\n" > + fi > + else > + printf "\nLeaving log size as ${max_log_size}k.\n" > + break > + fi > + done > + > + printf "\n" > + read -p "What is the IP address for the syslog server, hit Enter to skip? " > + if [ -n "$REPLY" ]; then > + syslog_server_ip=$REPLY > + while true; do > + read -p "Please enter the remote logging port used: " > + r=$REPLY > + if [ -n "$r" ]; then > + if [[ $r =~ ^[0-9]+$ ]] && [[ $r -gt 0 ]]; then > + syslog_server_port=$REPLY > + break > + else > + printf "Invalid port.\n" > + fi > + fi > + done > + > + printf "\n" > + while true; do > + read -p "Remote logging uses [t]cp or [u]dp? " > + r=$(echo $REPLY|tr '[[:lower:]]' '[[:upper:]]') > + if [ "$r" == "T" ]; then syslog_server_protocol="tcp"; break; fi > + if [ "$r" == "U" ]; then syslog_server_protocol="udp"; break; fi > + # else > + printf "Invalid input.\n" > + done > + else > + printf "\nDisabling remote logging.\n" > + fi > + > + printf "\n" > + printf "\nLogging will be configured as follows:" > + printf "\n======================================" > + printf "\n Max Logfile Size: $max_log_size" > + if [ -n "$syslog_server_ip" ]; then > + printf "\n Remote Server: $syslog_server_ip" > + printf "\n Remote Port: $syslog_server_port" > + printf "\n Logging Protocol: $syslog_server_protocol" > + fi > + printf "\n" > + printf "\n" > + while true; do > + read -p "Is this correct (Y/N/A)? " > + r=$(echo $REPLY|tr '[[:lower:]]' '[[:upper:]]') > + if [ "$r" == "Y" ]; then > + printf "\nSaving configuration.\n" > + if [[ -n "$syslog_server_ip" ]] && > + [[ -n "$syslog_server_port" ]] && > + [[ -n "$syslog_server_protocol" ]]; then > + ovirt_rsyslog $syslog_server_ip \ > + $syslog_server_port \ > + $syslog_server_protocol > + fi > + sed -i -e "s/^size=.*/size=${max_log_size}k/" \ > + /etc/logrotate.d/ovirt-logrotate.conf > + return > + elif [ "$r" == "N" ]; then > + printf "\nRestarting logging configuration.\n" > + break > + elif [ "$r" == "A" ]; then > + printf "\nAborting logging configuration.\n" > + return > + fi > + done > done > - > } > > # AUTO for auto-install ACK -- bk From pmyers at redhat.com Sat Dec 13 00:10:04 2008 From: pmyers at redhat.com (Perry Myers) Date: Fri, 12 Dec 2008 19:10:04 -0500 Subject: [Ovirt-devel] [PATCH node-image] Added make source target to build source.iso$ In-Reply-To: <1228758281-12698-2-git-send-email-dhuff@redhat.com> References: <1228758281-12698-1-git-send-email-dhuff@redhat.com> <1228758281-12698-2-git-send-email-dhuff@redhat.com> Message-ID: <4942FD5C.4000407@redhat.com> David Huff wrote: > Workaround which uses pungi to download srpms and create a srpm.iso$ > Currently builds $(PWD)/$(PACKAGE)-source.iso however can also spit our .tar > and can be easily configured to chose depending on $(PKG_FMT)$ > --- > Makefile.am | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 files changed, 53 insertions(+), 0 deletions(-) I made some modifications to this patch series and pushed. You can now run using the top level Makefile: make srpm-iso make srpm-tar to create an iso or tar of the srpms for node-image and appliance. make srpm will make both (tar and iso) Perry From pmyers at redhat.com Sat Dec 13 00:29:57 2008 From: pmyers at redhat.com (Perry Myers) Date: Fri, 12 Dec 2008 19:29:57 -0500 Subject: [Ovirt-devel] [PATCH server] API: add a call to list VMs for a user In-Reply-To: <1228941542-21128-1-git-send-email-lutter@redhat.com> References: <1228941542-21128-1-git-send-email-lutter@redhat.com> Message-ID: <49430205.8010401@redhat.com> David Lutterkort wrote: > Going to the URL /vms will return a list of all the VM's for which the > current user has PRIV_VIEW permission. The VM info contains the host the VM > is running on (if any) pushed Perry From halsaadi at thoughtworks.com Sat Dec 13 08:39:58 2008 From: halsaadi at thoughtworks.com (Hadi Al-Saadi) Date: Sat, 13 Dec 2008 14:09:58 +0530 Subject: [Ovirt-devel] help Message-ID: HI, I'm getting this error from ovirt ui task while trying to load ISO image error description Call to function virStoragePoolDefineXML failed Regards -Hadi -------------- next part -------------- An HTML attachment was scrubbed... URL: From halsaadi at thoughtworks.com Sat Dec 13 12:44:54 2008 From: halsaadi at thoughtworks.com (Hadi Al-Saadi) Date: Sat, 13 Dec 2008 18:14:54 +0530 Subject: [Ovirt-devel] help Message-ID: Dear ovirt when im trying to load ISO image from localhost, after creating cobbler profile with the command cobbler image add --name=foo --file=/mnt/automnt/path/to/foo.iso --image-type=iso the profile create fine. no prolbmes, and i can see the ISO image from ovirt ui drop list and i can select it. when i try to start it, it giveing me error in ovirt ui task error descraption Call to function virStoragePoolCreate failed 2- when im trying to load ISO image from nfs from the localhost it self with the command cobbler image add --name=foo --file=nfs://user at host:/path/to/foo.iso --image-type=iso the comand create profile fine. and i can see the ISO image from ovirt uo drop list and i can select it but when im trying to start it it queued it for a while and after that it giveing me error in ovirt ui task error discraption Call to function virStoragePoolDefineXML failed when i give showmount -e localhost [root at management amd64]# showmount -e localhost Export list for localhost: /iso * /var/www/cobbler/ks_mirror/ubuntu-64 * /ovirtnfs 192.168.50.0/24 /cobblernfs 192.168.50.0/24 [root at management amd64]# i can see the mount point where i put the iso and also i can mount the mount point in onthere system pls help me to load ISO image -Regards Hadi -------------- next part -------------- An HTML attachment was scrubbed... URL: From d.vasilets at peterhost.ru Mon Dec 15 10:28:22 2008 From: d.vasilets at peterhost.ru (=?koi8-r?Q?=F7=C1=D3=C9=CC=C5=C3_?= =?koi8-r?Q?=E4=CD=C9=D4=D2=C9=CA?=) Date: Mon, 15 Dec 2008 13:28:22 +0300 Subject: [Ovirt-devel] ovirt see only 1 node. how to add other servers ? In-Reply-To: <494298AE.6010308@redhat.com> References: <1228317705.11195.2.camel@dima-desktop> <4936A549.5000203@redhat.com> <1228389599.7273.5.camel@dima-desktop> <1228479650.13032.7.camel@dima-desktop> <4939BE7C.80305@redhat.com> <1228757099.11371.4.camel@dima-desktop> <493D95DB.6090802@redhat.com> <1228819017.559.7.camel@dima-desktop> <49426573.3050904@redhat.com> <1229094479.5845.5.camel@dima-desktop> <494283CE.6050208@redhat.com> <1229097269.7026.12.camel@dima-desktop> <494298AE.6010308@redhat.com> Message-ID: <1229336902.20861.8.camel@dima-desktop> ? ???, 12/12/2008 ? 12:00 -0500, Perry Myers ?????: > ?? wrote: > > ? ???, 12/12/2008 ? 10:31 -0500, Perry Myers ?????: > >> ?? wrote: > >>> Hello > >>> i send identify information from second node starting > >>> "ovirt-identify-node -s 192.168.50.2 -p 12120 -d -v" > >>> but in listing "Hosts" hypervisor field empty > >>> i think ovirt-appliance can't connect to libvirtd > >> Why are you running ovirt-identify-node manually? That should run only as > >> part of the Node bootup sequence automatically. > > > > Automaticaly this query "dig +short -t srv _$1._$2.$(dnsdomainname)" > > from /etc/init.d/ovirt-functions haven't answer (i didn't configure dns > > for local zones). > > DNS on the oVirt Appliance is provided by dnsmasq which provides the DNS > SRV records that oVirt needs automatically. The Appliance won't work with > external DNS without major changes to it. > > From the .254 Node and the Appliance what is the output of: > > dig +short -t srv _ovirt._tcp.priv.ovirt.org hello i set in /etc/resolv.conf "nameserver 192.168.50.2" in all nodes after that "dig +short -t srv _ovirt._tcp.priv.ovirt.org" output is "0 0 80 management.priv.ovirt.org." > >> Are you running that on the 192.168.50.254 host or is this a different > >> physical machine? > > physical machine is 192.168.50.254 and 192.168.50.1 > > Ok > > > ovirt-appliance virtual machine is 192.168.50.2 on 192.168.50.1 > > Ok > > >> In the logs you sent, the only hosts that I can see that have tried to > >> register with the Server are 192.168.50.254 and 192.168.50.1. If there > >> are other nodes that have tried to register, the host-browser daemon on > >> the Appliance did not see them. Can you give me the logs from these other > >> nodes? > >> > >> I also saw errors like this in your host-status log: > >> > >>> Connecting to host 192.168.50.254 > >>> libvir: Remote error : Failed to start SASL negotiation: -4 (SASL(-4): no mechanism available: No worthy mechs found) > >> This could be a time synchronization issue. Please run > >> date --utc > >> on both the host running the Appliance, the appliance and all nodes and > >> let me know what the results are > > on all nodes time is Fri Dec 12 15:43:58 UTC 2008 > > Fri Dec 12 15:43:49 UTC 2008 > > Fri Dec 12 15:43:40 UTC 2008 > > Ok, so not a time sync issue then > > >> Also, from your appliance in an ssh session try: > >> > >> klist > >> ping -c 1 192.168.50.254 > >> virsh -c qemu+tcp://192.168.50.254/system list > >> > >> And give me the output for those commands. > > > > [root at management ~]# klist > > Ticket cache: FILE:/tmp/krb5cc_0 > > Default principal: admin at PRIV.OVIRT.ORG > > > > Valid starting Expires Service principal > > 12/12/08 14:13:19 12/13/08 14:13:19 > > krbtgt/PRIV.OVIRT.ORG at PRIV.OVIRT.ORG > > 12/12/08 14:13:20 12/13/08 14:13:19 > > ldap/management.priv.ovirt.org at PRIV.OVIRT.ORG > > 12/12/08 14:13:20 12/13/08 14:13:19 > > HTTP/management.priv.ovirt.org at PRIV.OVIRT.ORG > > > > > > Kerberos 4 ticket cache: /tmp/tkt0 > > klist: You have no tickets cached > > [root at management ~]# virsh -c qemu+tcp://192.168.50.254/system list > > libvir: Remote error : Failed to start SASL negotiation: -4 (SASL(-4): > > no mechanism available: No worthy mechs found) > > error: failed to connect to the hypervisor > > [root at management ~]# ping -c 1 192.168.50.254 > > PING 192.168.50.254 (192.168.50.254) 56(84) bytes of data. > > 64 bytes from 192.168.50.254: icmp_seq=1 ttl=64 time=0.554 ms > > > > --- 192.168.50.254 ping statistics --- > > 1 packets transmitted, 1 received, 0% packet loss, time 0ms > > rtt min/avg/max/mdev = 0.554/0.554/0.554/0.000 ms > > Ok, so we've ruled out a time sync issue. And you have valid kerberos > tickets on the appliance. And we know the Node at .254 is running since > you can ping it. > > The next question is, does the Node have a valid kerberos ticket? Can you > give me the /var/log/ovirt.log file from the .254 Node? And do you have > an /etc/libvirt/krb5.tab file on the Node? i haven't file /etc/libvirt/krb5.tab on all nodes where i can find valid kerberos ticket ? > > Perry > -------------- next part -------------- A non-text attachment was scrubbed... Name: ovirt.log Type: text/x-log Size: 1898 bytes Desc: not available URL: From dpierce at redhat.com Mon Dec 15 12:47:58 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 15 Dec 2008 07:47:58 -0500 Subject: [Ovirt-devel] [PATCH node] Usability fixes to the logging configuration. In-Reply-To: <4942E635.3090709@redhat.com> References: <1229116438-24551-1-git-send-email-dpierce@redhat.com> <4942E635.3090709@redhat.com> Message-ID: <20081215124758.GA3800@mcpierce-laptop.rdu.redhat.com> On Fri, Dec 12, 2008 at 05:31:17PM -0500, Bryan Kearney wrote: > ACK > > -- bk Thanks. This is now pushed. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From dpierce at redhat.com Mon Dec 15 14:39:39 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 15 Dec 2008 09:39:39 -0500 Subject: [Ovirt-devel] [PATCH node] set default swap size to twice the RAM size In-Reply-To: <1229106983-15171-1-git-send-email-apevec@redhat.com> References: <1229106983-15171-1-git-send-email-apevec@redhat.com> Message-ID: <20081215143939.GD3800@mcpierce-laptop.rdu.redhat.com> On Fri, Dec 12, 2008 at 07:36:23PM +0100, Alan Pevec wrote: > --- > scripts/ovirt-config-storage | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage > index dd3fab1..2fae9fe 100755 > --- a/scripts/ovirt-config-storage > +++ b/scripts/ovirt-config-storage > @@ -261,7 +261,7 @@ case $MEM_SIZE in > ''|*[^0-9]*) die failed to get system memory size;; > esac > > -MEM_SIZE=$(echo "scale=0; $MEM_SIZE / 1024" | bc -l) > +MEM_SIZE=$(echo "scale=0; $MEM_SIZE / 1024 * 2" | bc -l) > SWAP_SIZE=${OVIRT_VOL_SWAP_SIZE:-$MEM_SIZE} > > BOOT_SIZE=${OVIRT_VOL_BOOT_SIZE:-$default_boot_size} ACK. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From pmyers at redhat.com Mon Dec 15 14:46:25 2008 From: pmyers at redhat.com (Perry Myers) Date: Mon, 15 Dec 2008 09:46:25 -0500 Subject: [Ovirt-devel] ovirt see only 1 node. how to add other servers ? In-Reply-To: <1229336902.20861.8.camel@dima-desktop> References: <1228317705.11195.2.camel@dima-desktop> <4936A549.5000203@redhat.com> <1228389599.7273.5.camel@dima-desktop> <1228479650.13032.7.camel@dima-desktop> <4939BE7C.80305@redhat.com> <1228757099.11371.4.camel@dima-desktop> <493D95DB.6090802@redhat.com> <1228819017.559.7.camel@dima-desktop> <49426573.3050904@redhat.com> <1229094479.5845.5.camel@dima-desktop> <494283CE.6050208@redhat.com> <1229097269.7026.12.camel@dima-desktop> <494298AE.6010308@redhat.com> <1229336902.20861.8.camel@dima-desktop> Message-ID: <49466DC1.7080600@redhat.com> ?? wrote: > ? ???, 12/12/2008 ? 12:00 -0500, Perry Myers ?????: >> ?? wrote: >>> ? ???, 12/12/2008 ? 10:31 -0500, Perry Myers ?????: >>>> ?? wrote: >>>>> Hello >>>>> i send identify information from second node starting >>>>> "ovirt-identify-node -s 192.168.50.2 -p 12120 -d -v" >>>>> but in listing "Hosts" hypervisor field empty >>>>> i think ovirt-appliance can't connect to libvirtd >>>> Why are you running ovirt-identify-node manually? That should run only as >>>> part of the Node bootup sequence automatically. >>> Automaticaly this query "dig +short -t srv _$1._$2.$(dnsdomainname)" >>> from /etc/init.d/ovirt-functions haven't answer (i didn't configure dns >>> for local zones). >> DNS on the oVirt Appliance is provided by dnsmasq which provides the DNS >> SRV records that oVirt needs automatically. The Appliance won't work with >> external DNS without major changes to it. >> >> From the .254 Node and the Appliance what is the output of: >> >> dig +short -t srv _ovirt._tcp.priv.ovirt.org > > hello > i set in /etc/resolv.conf "nameserver 192.168.50.2" in all nodes > after that "dig +short -t srv _ovirt._tcp.priv.ovirt.org" output is "0 0 > 80 management.priv.ovirt.org." Ok that looks correct, but it is odd that you had to set resolv.conf manually. That should have been set by DHCP. >> The next question is, does the Node have a valid kerberos ticket? Can you >> give me the /var/log/ovirt.log file from the .254 Node? And do you have >> an /etc/libvirt/krb5.tab file on the Node? > > i haven't file /etc/libvirt/krb5.tab on all nodes > where i can find valid kerberos ticket ? The kerberos ticket is pulled from the management server at boot time. However, if DHCP was not working properly (as evidence from misconfigured resolv.conf shows, then this pull would have not happened) Let me check your logs to see if I can find the root cause of all of this... Ok here's your issue... From ovirt.log on the Node: > DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 8 > DHCPOFFER from 10.20.4.1 > DHCPREQUEST on eth0 to 255.255.255.255 port 67 > DHCPACK from 10.20.4.1 You have a DHCP server running on 10.20.4.1 that is on the same physical network as your Node. The only DHCP server that should be running on that network is the one on the Appliance at 192.168.50.2. So your Node initially booted and was given an address from this other DHCP server, which probably set resolv.conf to a different address than 192.168.50.2. If you remove this DHCP server from your network that should clear up the problem. Perry From dpierce at redhat.com Mon Dec 15 15:13:19 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 15 Dec 2008 10:13:19 -0500 Subject: [Ovirt-devel] [PATCH node] get memory info directly from /proc/meminfo In-Reply-To: <1229106973-15145-1-git-send-email-apevec@redhat.com> References: <1229106973-15145-1-git-send-email-apevec@redhat.com> Message-ID: <20081215151318.GF3800@mcpierce-laptop.rdu.redhat.com> On Fri, Dec 12, 2008 at 07:36:13PM +0100, Alan Pevec wrote: > to avoid libvirt dependecy and to drop newrole workaround > for selinux issue with initrc_t > > Signed-off-by: Alan Pevec > --- ACK. Works fine. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From clalance at redhat.com Mon Dec 15 15:21:20 2008 From: clalance at redhat.com (Chris Lalancette) Date: Mon, 15 Dec 2008 16:21:20 +0100 Subject: [Ovirt-devel] [PATCH node] set default swap size to twice the RAM size In-Reply-To: <1229106983-15171-1-git-send-email-apevec@redhat.com> References: <1229106983-15171-1-git-send-email-apevec@redhat.com> Message-ID: <494675F0.7090506@redhat.com> Alan Pevec wrote: > --- > scripts/ovirt-config-storage | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage > index dd3fab1..2fae9fe 100755 > --- a/scripts/ovirt-config-storage > +++ b/scripts/ovirt-config-storage > @@ -261,7 +261,7 @@ case $MEM_SIZE in > ''|*[^0-9]*) die failed to get system memory size;; > esac > > -MEM_SIZE=$(echo "scale=0; $MEM_SIZE / 1024" | bc -l) > +MEM_SIZE=$(echo "scale=0; $MEM_SIZE / 1024 * 2" | bc -l) > SWAP_SIZE=${OVIRT_VOL_SWAP_SIZE:-$MEM_SIZE} You probably want to have a maximum here; on a machine with 64GB of memory, you don't necessarily want a 128GB swap partition. -- Chris Lalancette From apevec at redhat.com Mon Dec 15 15:45:42 2008 From: apevec at redhat.com (Alan Pevec) Date: Mon, 15 Dec 2008 16:45:42 +0100 Subject: [Ovirt-devel] (no subject) Message-ID: <1229355947-22648-1-git-send-email-apevec@redhat.com> repost of [PATCH node] ovirt-config-boot - minimal installer for livecd image to local disk [PATCH node] refactor Node local disk usage [PATCH node] auto install and firstboot fixes [PATCH node] get memory info directly from /proc/meminfo [PATCH node] set default swap size to twice the RAM size From apevec at redhat.com Mon Dec 15 15:45:43 2008 From: apevec at redhat.com (Alan Pevec) Date: Mon, 15 Dec 2008 16:45:43 +0100 Subject: [Ovirt-devel] [PATCH node] ovirt-config-boot - minimal installer for livecd image to local disk In-Reply-To: <1229355947-22648-1-git-send-email-apevec@redhat.com> References: <1229355947-22648-1-git-send-email-apevec@redhat.com> Message-ID: <1229355947-22648-2-git-send-email-apevec@redhat.com> LiveOS folder is copied to /dev/HostVG/Root LVM volume, kernel,initrd and GRUB are installed to /dev/HostVG/Boot partition. livecd initrd is modified on the fly to support LVM, which is not included in initramfs produced by mayflower/mkliveinitrd Example usage: ovirt-config-boot "$disk" /live "$bootparam1 $bootparam2" caller is responsible to issue reboot Signed-off-by: Alan Pevec --- Makefile.am | 1 + ovirt-node.spec.in | 5 ++ scripts/ovirt-config-boot | 122 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 0 deletions(-) create mode 100755 scripts/ovirt-config-boot diff --git a/Makefile.am b/Makefile.am index a47beaa..09ba56b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,6 +27,7 @@ EXTRA_DIST = \ scripts/collectd.conf.in \ scripts/ovirt \ scripts/ovirt-awake \ + scripts/ovirt-config-boot \ scripts/ovirt-config-logging \ scripts/ovirt-config-networking \ scripts/ovirt-config-password \ diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in index 50b2d18..c634a58 100644 --- a/ovirt-node.spec.in +++ b/ovirt-node.spec.in @@ -36,6 +36,7 @@ Requires: bind-utils # qemu-img RPM. Requires: qemu-img Requires: nc +Requires: grub Requires: /usr/sbin/crond ExclusiveArch: %{ix86} x86_64 @@ -112,6 +113,7 @@ cd - %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/logrotate.d %{__install} -p -m0755 scripts/ovirt-awake %{buildroot}%{_sbindir} +%{__install} -p -m0755 scripts/ovirt-config-boot %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-logging %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-networking %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-password %{buildroot}%{_sbindir} @@ -203,6 +205,8 @@ fi %files stateless %defattr(-,root,root,0755) +%{_sbindir}/ovirt-awake +%{_sbindir}/ovirt-config-boot %{_sbindir}/ovirt-config-logging %{_sbindir}/ovirt-config-networking %{_sbindir}/ovirt-config-password @@ -243,6 +247,7 @@ fi * Thu Dec 11 2008 Perry Myers - 0.96 - Subpackage stateful/stateless to separate out functionality for embedded Node and Node running as part of already installed OS +- ovirt-config-* setup scripts for standalone mode * Thu Sep 11 2008 Chris Lalancette - 0.92 0.7 - Add the ovirt-install- and ovirt-uninstall-node scripts, and refactor diff --git a/scripts/ovirt-config-boot b/scripts/ovirt-config-boot new file mode 100755 index 0000000..ad0aeb1 --- /dev/null +++ b/scripts/ovirt-config-boot @@ -0,0 +1,122 @@ +#!/bin/bash +# +# ovirt-config-boot - configure local boot disk partition + +# SYNOPSIS +# ovirt-config-boot livecd_path bootparams +# +# boot_disk - boot disk device e.g. /dev/sda +# +# livecd_path - where livecd media is mounted, +# parent of LiveOS and isolinux folders +# +# bootparams - extra boot parameters like console=... +# + +# Source functions library +. /etc/init.d/functions +. /etc/init.d/ovirt-functions + + +# local_boot_install livecd_path bootparams +# livecd_path -livecd media +# bootparams - extra boot parameters like console=... +# +# copy oVirt Node image to the local LVM /dev/HostVG +ovirt_boot_setup() { + local disk=$1 + local live=$2 + local bootparams=$3 + printf "installing oVirt Node image ... " + mount_boot + mount_liveos + # install oVirt Node image for local boot + if [ -e "$live/syslinux" ]; then + syslinux=syslinux + elif [ -e "$live/isolinux" ]; then + syslinux=isolinux + else + syslinux= + fi + rm -rf /boot/grub + rm -rf /liveos/LiveOS + mkdir -p /boot/grub + mkdir -p /liveos/LiveOS + cp -p $live/LiveOS/squashfs.img /liveos/LiveOS \ + && cp -p $live/$syslinux/vmlinuz0 /boot + rc=$? + if [ $rc -ne 0 ]; then + printf "image copy failed\n" + return $rc + fi + # append LVM support to the livecd initramfs + tmpdir=$(mktemp -d) + cd $tmpdir + gzip -dc $live/$syslinux/initrd0.img | + cpio -id init sbin/real-init 2> /dev/null + init_script=init + if [ -e sbin/real-init ]; then + # Fedora 10 mkliveinitrd + init_script=sbin/real-init + fi + sed -i '/^\/sbin\/udev.*settle/ a \echo Scanning logical volumes\ +lvm vgscan --ignorelockingfailure\ +echo Activating logical volumes\ +lvm vgchange -ay --ignorelockingfailure HostVG \ +' $init_script + # fix emergency shell + sed -i 's/^ bash$/ bash < \/dev\/console/' $init_script + # do not fail if device node already exists + sed -i 's/mknod.*$/& || :/' $init_script + mkdir -p bin + bit= + if [ -e /lib64 ]; then + bit=64 + fi + mkdir -p lib$bit + if [ -e /sbin/lvm.static ]; then + cp /sbin/lvm.static bin/lvm + else + cp /sbin/lvm bin + # lvm is not static in Fedora + cp /lib$bit/libreadline.so.5 /lib$bit/libncurses.so.5 lib$bit + fi + find $init_script bin/lvm lib$bit -type f | + cpio -H newc --quiet -o | + gzip -9 | + cat $live/$syslinux/initrd0.img - > /boot/initrd0.img + + cat > /boot/grub/grub.conf << EOF +default=0 +timeout=5 +hiddenmenu +title oVirt Node + root (hd0,0) + kernel /vmlinuz0 ro root=/dev/HostVG/Root roottypefs=ext3 liveimg $bootparams + initrd /initrd0.img +EOF + echo "(hd0) $disk" > /boot/grub/device.map + ( cd /usr/share/grub/*; cp -p stage? e2fs_stage1_5 /boot/grub ) + grub --device-map=/boot/grub/device.map > /dev/null < References: <1229355947-22648-1-git-send-email-apevec@redhat.com> Message-ID: <1229355947-22648-3-git-send-email-apevec@redhat.com> use LVM partitions created by o-c-storage use file bindmounts for persisted configs use optional /config from livecd image support for old and new udev versions add BOOTIF=link|eth* support Signed-off-by: Alan Pevec --- scripts/ovirt | 22 --- scripts/ovirt-early | 394 ++++++++++++++++------------------------------- scripts/ovirt-firstboot | 18 ++- scripts/ovirt-functions | 166 ++++++++++++++++---- 4 files changed, 287 insertions(+), 313 deletions(-) mode change 100644 => 100755 scripts/ovirt mode change 100644 => 100755 scripts/ovirt-post diff --git a/scripts/ovirt b/scripts/ovirt old mode 100644 new mode 100755 index 81733a5..e2c406b --- a/scripts/ovirt +++ b/scripts/ovirt @@ -11,28 +11,6 @@ . /etc/init.d/ovirt-functions start() { - # retrieve config from local OVIRT partition if available - ovirt=$(mktemp -d) - ovirt_mount $ovirt - # /config on OVIRT partition contains persisted /etc files - cfg=$ovirt/config - if [ -d $cfg/etc ]; then - cp -rv $cfg/etc/* /etc - restorecon -r /etc - fi - # and optional Augeas augtool script - aug=$cfg/config.aug - if [ -f $aug ]; then - tmpaug=$(mktemp) - cp $aug $tmpaug - echo "save" >> $tmpaug - augtool < $tmpaug > /dev/null 2>&1 - if [ $? -eq 0 ]; then - printf "$aug applied." - fi - fi - umount $ovirt && rmdir $ovirt - if is_standalone; then exit 0 fi diff --git a/scripts/ovirt-early b/scripts/ovirt-early index c09a987..1201ab4 100755 --- a/scripts/ovirt-early +++ b/scripts/ovirt-early @@ -10,8 +10,6 @@ . /etc/init.d/functions . /etc/init.d/ovirt-functions -# size of the oVirt partition in megabytes -OVIRT_SIZE=64 BONDING_MODCONF_FILE=/etc/modprobe.d/bonding AUGTOOL_CONFIG=/var/tmp/augtool-config @@ -48,12 +46,15 @@ configure_from_network() { ovirt-process-config $cfgdb $BONDING_MODCONF_FILE $AUGTOOL_CONFIG if [ -f $AUGTOOL_CONFIG ]; then echo "Loading remote config" + # avoid bindmount issues with augeas + umount_config /etc/sysconfig/network-scripts/ifcfg-eth* augtool < $AUGTOOL_CONFIG \ && echo "Remote config applied" \ || echo "Failed applying remote config" fi if ls /etc/sysconfig/network-scripts/ifcfg-eth* > /dev/null 2>&1; then echo "Network interfaces created from remote config" + ovirt_store_config /etc/sysconfig/network-scripts/ifcfg-eth* return else echo "Remote config contained no network interfaces" @@ -61,6 +62,7 @@ configure_from_network() { else echo "Failed to retrieve configuration bundle" fi + rm $cfgdb fi fi fi @@ -80,14 +82,29 @@ configure_from_network() { echo "Default config applied" } -# find_disk $bus $serial $live_disk +# $(get_live_disk) +# livecd boot disk +get_live_disk() { + local live_dev=/dev/live + if [ ! -e $live_dev ]; then + # PXE boot + live_dev=/dev/loop0 + live_disk= + else + live_part=$(readlink -e $live_dev) + live_disk=$(basename $(dirname $(udev_info $live_part path))) + fi + echo $live_disk +} + +# find_disk $bus $serial find_disk() { local bus=$1 local serial=$2 - local live=$3 + local live=$(get_live_disk) for d in /dev/disk/by-id/{scsi,usb}*; do ID_FS_USAGE= - eval $(udevinfo --query env --name $d) + eval $(udev_info $d env) # ID_FS_USAGE is set for partitions if [ -z "$ID_FS_USAGE" -a "$ID_BUS" = "$bus" ]; then if [ -z "$serial" -o "$ID_SERIAL" = "$serial" ]; then @@ -104,216 +121,10 @@ find_disk() { return 1 } -# TODO move to ovirt-config-storage -# local_install $local_boot $local_disk $bootparams -# local_boot - 1=install LiveOS and boot loader -# 0=initialize oVirt partition only -# local_disk - local disk to hold the oVirt partition -# =usb|scsi[:serial#] -# bootparams - extra boot parameters like console= -# -# oVirt partition is a local primary ext2 partition, labeled OVIRT -# content: -# /config - local oVirt configuration (ktab, local admin password) -# /boot - boot loader, kernel and initramfs -# /LiveOS - oVirt Node compressed livecd image - -local_install() { - local local_boot=$1 - local local_disk=$2 - local bootparams=$3 - local disk - local part - local live_part - local live_disk - local live_dev=/dev/live - if [ ! -e $live_dev ]; then - # PXE boot - live_dev=/dev/loop0 - live_part=$live_dev - live_disk= - else - live_part=$(readlink -e $live_dev) - live_disk=${live_disk%[1-9]} - fi - local ovirt_part=$(readlink -e /dev/disk/by-label/$OVIRT_LABEL) - local ovirt_disk=${ovirt_part%[1-9]} - if [ "$ovirt_disk" = "$ovirt_part" ]; then - ovirt_disk= - fi - if [ -z "$local_disk" ]; then - if [ -z "$ovirt_disk" ]; then - return 1 - fi - # ovirt_init not specified, use pre-labeled oVirt partition - mode=update - disk=$ovirt_disk - part=$ovirt_part - else - case "$local_disk" in - =) - # empty ovirt_init, use current live image device - mode=update - disk=$live_disk - part=$live_part - ;; - =scsi*) - bus=scsi - serial=${local_disk#=scsi:} - mode=install - ;; - =usb*) - bus=usb - serial=${local_disk#=usb:} - mode=install - ;; - *) - return 1 - ;; - esac - if [ $mode = "install" ]; then - if [ "$serial" = "=$bus" ]; then - serial= - fi - disk=$(find_disk $bus $serial $live_disk) - rc=$? - if [ $rc -ne 0 ]; then - echo "local disk '$local_disk' not available" - return 1 - fi - if [ -n "$ovirt_disk" ]; then - if [ "$disk" = "$ovirt_disk" ]; then - # local disk contains oVirt partition, select it for update - # TODO force reinstall option - mode=update - part=$ovirt_part - else - # remove label from oVirt partition, there can be only one - e2label $ovirt_part "" - fi - fi - fi - if [ "$mode" = "install" ]; then - printf "installing $disk..." | tee /dev/console - dd if=/dev/zero bs=4096 count=1 of=$disk \ - && parted -s $disk mklabel msdos \ - && parted -s $disk mkpart primary ext2 0.0 $OVIRT_SIZE \ - && partprobe -s $disk - if [ $? -ne 0 ]; then - echo "$disk partition creation failed"; return 1 - fi - part=${disk}1 - udevsettle - mkfs.ext2 -L $OVIRT_LABEL $part \ - && tune2fs -c0 -i0 $part - if [ $? -ne 0 ]; then - echo "$disk ext2 creation failed"; return 1 - fi - # update by-label link manually, mkfs won't trigger udev - mkdir -p /dev/disk/by-label - ln -sf $part /dev/disk/by-label/$OVIRT_LABEL - fi - fi - - if [ "$mode" = "update" ]; then - printf "updating $disk..." | tee /dev/console - fi - ovirt=$(mktemp -d) - if [ "$part" = "$live_part" ]; then - # ovirt_init w/o local disk specified - # setup /config on live disk, if writeable - # TODO mlabel/e2label (check fs2 type or just blindly try?) - mount -r $part $ovirt && mount -o remount,rw $ovirt \ - && mkdir -p $ovirt/config - umount $ovirt && rmdir $ovirt - return 0 - fi - live=$(mktemp -d) - mount -r $live_dev $live - if [ $? -ne 0 ]; then - echo "source image mount failed" - rmdir $live - return 1 - fi - mount $part $ovirt - if [ $? -ne 0 ]; then - echo "local disk mount failed" - umount $live && rmdir $live - rmdir $ovirt - return 1 - fi - mkdir -p $ovirt/config - # update local config using the one embedded in livecd image - # TODO admin tool for adding /config into livecd image - if [ -d $live/config ]; then - cp -rv $live/config/* $ovirt/config \ - || echo "config copy failed" - fi - - if [ $local_boot = 0 ]; then - # config update only, cleanup and continue booting - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - else - # install oVirt Node image for local boot - if [ -e "$live/syslinux" ]; then - syslinux=syslinux - elif [ -e "$live/isolinux" ]; then - syslinux=isolinux - else - syslinux= - fi - rm -rf $ovirt/boot - rm -rf $ovirt/LiveOS - mkdir -p $ovirt/boot/grub - mkdir -p $ovirt/LiveOS - cp -p $live/LiveOS/squashfs.img $ovirt/LiveOS \ - && cp -p $live/$syslinux/initrd0.img $ovirt/boot \ - && cp -p $live/$syslinux/vmlinuz0 $ovirt/boot - if [ $? -ne 0 ]; then - echo "image copy failed" - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - return 1 - fi - part_num=$(( ${part#$disk} - 1 )) - cat > $ovirt/boot/grub/grub.conf << EOF -default=0 -timeout=2 -hiddenmenu -title oVirt Node - root (hd0,$part_num) - kernel /boot/vmlinuz0 ro root=LABEL=OVIRT roottypefs=ext2 liveimg $bootparams - initrd /boot/initrd0.img -EOF - grub-install --root-directory=$ovirt $disk >&2 - if [ $? -ne 0 ]; then - echo "boot loader install failed" - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - return 1 - fi - # remove 1.5 stages we don't need - find $ovirt/boot/grub -name '*_stage1_5' ! -name e2fs_stage1_5 \ - -exec rm {} \; - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - # FIXME avoid reboot loops - # temp. workaround: sync and wait - sync; sync; sync - printf "oVirt local installation finished, press Enter to reboot." \ - > /dev/console - read key - if [ "$key" = "debug" ]; then - sh > /dev/console 2>&1 - fi - reboot - fi -} start() { # oVirt boot parameters - # BOOTIF= (appended by pxelinux) + # BOOTIF=link|eth*| (appended by pxelinux) # ovirt_init=usb|scsi[:serial#] # ovirt_vol=BOOT_MB:SWAP_MB:ROOT_MB:CONFIG_MB:LOGGING_MB # ovirt_local_boot @@ -324,11 +135,14 @@ start() { # syslog=server[:port] # TBD logrotate maxsize - # BOOTIF= (appended by pxelinux) + # BOOTIF=link|eth*| (appended by pxelinux) # network boot interface is assumed to be on management network where # oVirt Server is reachable - # IPAPPEND 2 in pxelinux.cfg appends MAC address of the booting node - # e.g. BOOTIF=01-00-16-3e-12-34-57 + # BOOTIF= e.g. BOOTIF=01-00-16-3e-12-34-57 + # PXELINUX option IPAPPEND 2 in pxelinux.cfg appends MAC address + # of the booting node + # BOOTIF=link - take first eth for which ethtool reports link + # BOOTIF=eth* e.g. BOOTIF=eth0 - use given interface bootif= # ovirt_init=usb|scsi[:serial#] @@ -337,23 +151,23 @@ start() { # serial# - select exact disk using serial number, as reported by # udev ID_SERIAL # e.g. ovirt_init=usb:Generic_STORAGE_DEVICE_0000145418-0:0 - ovirt_init= + init= # ovirt_vol=BOOT_MB:SWAP_MB:ROOT_MB:CONFIG_MB:LOGGING_MB # local partition sizes in GB - ovirt_vol_boot= - ovirt_vol_swap= - ovirt_vol_root= - ovirt_vol_config= - ovirt_vol_logging= + vol_boot_size= + vol_swap_size= + vol_root_size= + vol_config_size= + vol_logging_size= # ovirt_local_boot # install/update oVirt Node image on the local installation target disk - ovirt_local_boot=0 + local_boot=0 # ovirt_standalone # force oVirt Node standalone mode - ovirt_standalone=0 + standalone=0 # pxelinux format: ip=::: # anaconda format: ip= netmask= gateway= @@ -376,25 +190,65 @@ start() { for i in $(cat /proc/cmdline); do case $i in - BOOTIF=??-??-??-??-??-??-??) - i=${i#BOOTIF=??-} - bootif=$(grep -il $(echo $i|sed 's/-/:/g') /sys/class/net/eth*/address|rev|cut -d/ -f2|rev) + BOOTIF=*) + i=${i#BOOTIF=} + case "$i" in + eth*) + bootif=$i + ;; + link) + for eth in $(cd /sys/class/net; echo eth*); do + if ethtool $eth 2>/dev/null|grep -q "Link detected: yes" + then + bootif=$eth + break + fi + done + ;; + ??-??-??-??-??-??-??) + i=${i#??-} + bootif=$(grep -il $(echo $i|sed 's/-/:/g') /sys/class/net/eth*/address|rev|cut -d/ -f2|rev) + ;; + esac ;; ovirt_init*) - ovirt_init=${i#ovirt_init} - if [ -z "$ovirt_init" ]; then - ovirt_init='=' + i=${i#ovirt_init} + if [ -n "$i" ]; then + # resolve to disk device + case "$i" in + =scsi*) + bus=scsi + i=${i#=scsi} + serial=${i#:} + ;; + =usb*) + bus=usb + i=${i#=usb} + serial=${i#:} + ;; + *) + bus= + serial= + ;; + esac + if [ -n "$bus" ]; then + init=$(find_disk $bus $serial) + fi + else + # 'ovirt_init' without value: grab first disk + init=/dev/?da fi ;; ovirt_vol=*) i=${i#ovirt_vol=} - eval $(printf $i|awk -F: '{print "ovirt_vol_boot="$1; ovirt_vol_swap="$2; print "ovirt_vol_root="$3; print "ovirt_vol_config="$4; print "ovirt_vol_logging="$5;}') + eval $(printf $i|awk -F: '{print "vol_boot_size="$1; print "vol_swap_size="$2; print "vol_root_size="$3; print "vol_config_size="$4; print "vol_logging_size="$5;}') ;; ovirt_local_boot*) - ovirt_local_boot=1 + local_boot=1 ;; ovirt_standalone*) - ovirt_standalone=1 + standalone=1 + bootparams="$bootparams $i" ;; ip=*) i=${i#ip=} @@ -418,41 +272,66 @@ start() { ;; esac done - # save boot parameters as defaults for ovirt-config-* + if [ -z "$ip_netmask" ]; then ip_netmask=$netmask fi if [ -z "$ip_gateway" ]; then ip_gateway=$gateway fi + # save boot parameters as defaults for ovirt-config-* + params="bootif init vol_boot_size vol_swap_size vol_root_size vol_config_size vol_logging_size local_boot standalone ip_address ip_netmask ip_gateway ipv6 syslog_server syslog_port bootparams" + mount_config + if [ -e $OVIRT_DEFAULTS ]; then + # update persisted defaults + tmpaug=$(mktemp) + for p in $params; do + PARAM=$(uc $p) + value=$(ptr $p) + if [ -n "$value" ] ; then + echo "set /files$OVIRT_DEFAULTS/OVIRT_$PARAM '\"$value\"'" \ + >> $tmpaug + fi + done + if [ -s $tmpaug ]; then + echo "save" >> $tmpaug + # augtool on bindmounted files fails, + # so edit file at persistent config root, /config + umount_config $OVIRT_DEFAULTS + augtool < $tmpaug > /dev/null + rm $tmpaug + ovirt_store_config $OVIRT_DEFAULTS + fi + else + # initial startup, dump all ovirt bootparams + echo > $OVIRT_DEFAULTS + for p in $params; do + PARAM=$(uc $p) + echo "OVIRT_$PARAM='$(ptr $p)'" >> $OVIRT_DEFAULTS + done + ovirt_store_config $OVIRT_DEFAULTS + fi - cat > $OVIRT_DEFAULTS < /dev/null </dev/null | (read MD5 filename; echo $MD5) +} + +# return uppercase value +uc() { + echo $(echo $1|tr '[[:lower:]]' '[[:upper:]]') +} + +# return indirect value +# non-bashism for ${!var} +ptr() { + local v=$1 + eval "v=\$$v" + echo $v +} + +# mount livecd media +# e.g. CD /dev/sr0, USB /dev/sda1, +# PXE /dev/loop0 (loopback ISO) +mount_live() { + if grep -q " /live " /proc/mounts; then + return 0 + fi + local live_dev=/dev/live + if [ ! -e $live_dev ]; then + # PXE boot + live_dev=/dev/loop0 + fi + mkdir -p /live + mount $live_dev /live +} + +# mount boot partition +# boot loader + kernel + initrd +mount_boot() { + if grep -q " /boot " /proc/mounts; then + return 0 + fi + mkdir -p /boot + mount /dev/disk/by-label/BOOT /boot +} + +# mount liveos partition +# LiveOS/ +mount_liveos() { + if grep -q " /liveos " /proc/mounts; then + return 0 + fi + mkdir -p /liveos + mount /dev/HostVG/Root /liveos +} + +# mount config partition +# /config for persistance +mount_config() { + if grep -q " /config " /proc/mounts; then + return 0 + fi + mkdir -p /config + mount /dev/HostVG/Config /config + if grep -q " /config " /proc/mounts; then + # optional config embedded in the livecd image + if [ -e /live/config ]; then + cp -rv --update /live/config/* /config + fi + # bind mount all persisted configs to rootfs + for f in $(find /config -type f); do + target=${f#/config} + if grep -q " $target " /proc/mounts ; then + # skip if already bind-mounted + true + else + mount -n --bind $f $target + fi + done else - mount -r /dev/live $1 \ - || mount /dev/live $1 + # /config is not available + return 1 fi } -md5() { - md5sum $1 2>/dev/null | (read MD5 filename; echo $MD5) +# unmount bindmounted config files +# umount_config /etc/config /etc/config2 ... +# +# Use before running sed -i or augeas against the bindmounted file, +# Otherwise save fails: https://fedorahosted.org/augeas/ticket/32 +# After file is replaced, call ovirt_store_config /etc/config /etc/config2 ... +# to bindmount the config file again. +# +umount_config() { + if grep -q " /config " /proc/mounts; then + for f in "$@"; do + if grep -q " $f " /proc/mounts ; then + umount -n $f + # refresh rootfs copy + cp /config$f $f + fi + done + fi } -# persist configuration to /config on OVIRT partition +# persist configuration to /config # ovirt_store_config /etc/config /etc/config2 ... +# copy to /config and bind-mount back ovirt_store_config() { - ovirt=$(mktemp -d) - ovirt_mount $ovirt - cfg=$ovirt/config - rw=0 - printf "store config:" - for f in "$@"; do - # ignore non-/etc paths - if [ $f != ${f#/etc/} ]; then - # check if changed - if [ "$(md5 $f)" != "$(md5 $cfg$f)" ]; then - if [ $rw = 0 ]; then - mount -o remount,rw $ovirt - rw=1 - fi - mkdir -p $cfg$(dirname $f) - cp $f $cfg$f - printf " $f" - fi - fi - done - echo - umount $ovirt && rmdir $ovirt + if grep -q " /config " /proc/mounts; then + printf "storing to /config :" + for f in "$@"; do + printf " $f" + # skip if already bind-mounted + if grep -q " $f " /proc/mounts ; then + printf " already persisted\n" + else + mkdir -p /config$(dirname $f) + cp -a $f /config$f \ + && mount -n --bind /config$f $f \ + || printf " failed to persist\n" + fi + done + echo + else + printf "warning: persistent config storage not available\n" + fi +} + +# compat function to handle different udev versions +udev_info() { + local name=$1 + local query=$2 + local out + + # old udev command with shortopts + out=$(udevinfo -n $name -q $query) + rc=$? + if [ $rc -ne 0 ]; then + out=$(udevadm info --name=$name --query=$query) + rc=$? + fi + if [ $rc -eq 0 ]; then + echo $out + fi + return $rc } backup_file() { diff --git a/scripts/ovirt-post b/scripts/ovirt-post old mode 100644 new mode 100755 -- 1.6.0.4 From apevec at redhat.com Mon Dec 15 15:45:45 2008 From: apevec at redhat.com (Alan Pevec) Date: Mon, 15 Dec 2008 16:45:45 +0100 Subject: [Ovirt-devel] [PATCH node] auto install and firstboot fixes In-Reply-To: <1229355947-22648-1-git-send-email-apevec@redhat.com> References: <1229355947-22648-1-git-send-email-apevec@redhat.com> Message-ID: <1229355947-22648-4-git-send-email-apevec@redhat.com> * Autoinstall is performed when required boot parameters are specified: - BOOTIF=link|eth*|01-11-22-33-44-55-66 for choosing management NIC (IPv4 DHCP is assumed) - ovirt_init=usb|scsi to select a local disk drive to create oVirt LVM volumes If ovirt_vol parameter is missing, default volume sizes are used: BOOT 50MB SWAP 2 * RAM size ROOT 256MB CONFIG 5MB LOGGING 256MB DATA rest of the disk equivalent is ovirt_vol=50::256:5:256 * Show firstboot menu only once. Firstboot state is stored in the persistent config storage. * Use the drive selected by ovirt_init boot parameter. Signed-off-by: Alan Pevec --- scripts/ovirt-config-storage | 45 ++++++++++++++++++++++------------------- scripts/ovirt-functions | 36 +++++++++++++++++++++------------ 2 files changed, 47 insertions(+), 34 deletions(-) diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage index e2ddec1..fd877e2 100755 --- a/scripts/ovirt-config-storage +++ b/scripts/ovirt-config-storage @@ -28,13 +28,25 @@ check_partition_sizes() # or just let the mke2fs failure suffice. } -# Find a usable/selected storage device along with its size in bytes. +get_selected_drive_size() +{ + local udi=$(hal-find-by-property --key block.device --string $DRIVE) + if [ -z "$udi" ]; then + warn "ERROR: selected storage device is not available" + return 1 + fi + size=$(hal-get-property --udi "$udi" --key storage.size) + SPACE=$(echo "scale=0; $size / (1024 * 1024)" | bc -l) + echo "selected device: $DRIVE ($SPACE MB)" +} + +# Find a usable/selected storage device. # If there are none, give a diagnostic and return nonzero. # If there is just one, e.g., /dev/sda, treat it as selected (see below). # and return 0. If there are two or more, make the user select one # or decline. Upon decline, return nonzero. Otherwise, print the -# selected name, a space, and its size, then return 0. -# Sample output: "/dev/sda 320072933376" +# selected name, then return 0. +# Sample output: /dev/sda get_dev_name() { local udi_list=$(hal-find-by-capability --capability storage) @@ -58,20 +70,16 @@ get_dev_name() *) warn "block device name $block_dev doesn't start with '/';" \ " skipping"; continue;; esac - size=$(hal-get-property --udi "$d" --key storage.size) test -z "$devices" \ && devices=$block_dev \ || devices="$devices $block_dev" - test -z "$sizes" \ - && sizes=$size \ - || sizes="$sizes $size" done # If there's only one device, use it. case $devices in '') warn "ERROR: found no usable block device"; return 1;; *' '*) ;; # found more than one - *) echo "$devices $sizes"; return 0;; # just one + *) echo "$devices"; return 0;; # just one esac # There are two or more; make the user choose. @@ -80,10 +88,7 @@ get_dev_name() do test "$device" = Abort && return 1 test -z "$device" && continue - # $REPLY is the selected number; - # use that to map to the corresponding size. - size=$(echo "$sizes"|cut -d' ' -f "$REPLY") - echo "$device $size" + echo "$device" return 0 done } @@ -91,13 +96,8 @@ get_dev_name() do_configure() { local name_and_size - name_and_size=$(get_dev_name) || exit 1 - set -- $name_and_size - DRIVE=$1 - local n_bytes=$2 - - SPACE=$(echo "scale=0; $n_bytes / (1024 * 1024)" | bc -l) - echo "selected device: $DRIVE ($SPACE MB)" + DRIVE=$(get_dev_name) || exit 1 + get_selected_drive_size for i in boot swap root config logging ; do uc=$(echo $i|tr '[[:lower:]]' '[[:upper:]]') @@ -270,10 +270,13 @@ ROOT_SIZE=${OVIRT_VOL_ROOT_SIZE:-$default_root_size} CONFIG_SIZE=${OVIRT_VOL_CONFIG_SIZE:-$default_config_size} LOGGING_SIZE=${OVIRT_VOL_LOGGING_SIZE:-$default_logging_size} +if [ -n "$OVIRT_INIT" ]; then + # if present, use the drive selected with 'ovirt_init' boot parameter + DRIVE=$OVIRT_INIT + get_selected_drive_size +fi if [ "$1" == "AUTO" ]; then - # In "AUTO" mode, OVIRT_INIT should be defined in the environment. - DRIVE=$OVIRT_INIT check_partition_sizes printf "Partitioning hard disk..." perform_partitioning diff --git a/scripts/ovirt-functions b/scripts/ovirt-functions index cbce347..766c432 100644 --- a/scripts/ovirt-functions +++ b/scripts/ovirt-functions @@ -9,34 +9,44 @@ OVIRT_DEFAULTS=/etc/default/ovirt if [ -f $OVIRT_DEFAULTS ]; then . $OVIRT_DEFAULTS fi -# fallback defaults when sysconfig is empty +# fallback when default is empty OVIRT_STANDALONE=${OVIRT_STANDALONE:-0} OVIRT_BACKUP_DIR=/var/lib/ovirt-backup -# is_managed # return 1 if oVirt Node is running in standalone mode # return 0 if oVirt Node is managed by the oVirt Server is_managed() { return $OVIRT_STANDALONE } -# is_standalone = not is_managed +# oVirt Node in standalone mode does not try to contact the oVirt Server is_standalone() { if is_managed; then return 1; else return 0; fi } -# is_auto_install -# return 0 if all required oVirt boot parameters are present +# perform automatic local disk installation +# when at least following boot parameters are present: +# for networking - OVIRT_BOOTIF, management NIC +# if other ip bootparams are not specified, IPv4 DHCP is assumed +# for storage - OVIRT_INIT, local disk to use +# if ovirt_vol is not specified, default volume sizes are set is_auto_install() { - test -n "$OVIRT_BOOTIF" \ - -a -n "$OVIRT_OVIRT_STANDALONE" \ - -a -n "$OVIRT_INIT" \ - -a -n "$OVIRT_VOL_BOOT_SIZE" \ - -a -n "$OVIRT_VOL_SWAP_SIZE" \ - -a -n "$OVIRT_VOL_ROOT_SIZE" \ - -a -n "$OVIRT_VOL_CONFIG_SIZE" \ - -a -n "$OVIRT_VOL_LOGGING_SIZE" + if [ -n "$OVIRT_BOOTIF" -a -n "$OVIRT_INIT" ] ; then + return 0 + else + return 1 + fi +} + +# was firstboot menu already shown? +# state is stored in persistent config partition +is_firstboot() { + if [ -z "$OVIRT_FIRSTBOOT" -o "$OVIRT_FIRSTBOOT" = "1" ]; then + return 0 + else + return 1 + fi } # find_srv SERVICE PROTO -- 1.6.0.4 From d.vasilets at peterhost.ru Mon Dec 15 15:45:43 2008 From: d.vasilets at peterhost.ru (=?koi8-r?Q?=F7=C1=D3=C9=CC=C5=C3_?= =?koi8-r?Q?=E4=CD=C9=D4=D2=C9=CA?=) Date: Mon, 15 Dec 2008 18:45:43 +0300 Subject: [Ovirt-devel] ovirt see only 1 node. how to add other servers ? In-Reply-To: <49466DC1.7080600@redhat.com> References: <1228317705.11195.2.camel@dima-desktop> <4936A549.5000203@redhat.com> <1228389599.7273.5.camel@dima-desktop> <1228479650.13032.7.camel@dima-desktop> <4939BE7C.80305@redhat.com> <1228757099.11371.4.camel@dima-desktop> <493D95DB.6090802@redhat.com> <1228819017.559.7.camel@dima-desktop> <49426573.3050904@redhat.com> <1229094479.5845.5.camel@dima-desktop> <494283CE.6050208@redhat.com> <1229097269.7026.12.camel@dima-desktop> <494298AE.6010308@redhat.com> <1229336902.20861.8.camel@dima-desktop> <49466DC1.7080600@redhat.com> Message-ID: <1229355943.30035.5.camel@dima-desktop> Thank you. I understand my mistake. Now i reboot secondary node and in log see that "libvir: Remote error : Failed to start SASL negotiation: -1 (SASL(-1): generic failure: GSSAPI Error: Unspecified GSS failure. Minor code may provide more information (Ticket expired))" how to update key without kinit ? ? ???, 15/12/2008 ? 09:46 -0500, Perry Myers ?????: > ?? wrote: > > ? ???, 12/12/2008 ? 12:00 -0500, Perry Myers ?????: > >> ?? wrote: > >>> ? ???, 12/12/2008 ? 10:31 -0500, Perry Myers ?????: > >>>> ?? wrote: > >>>>> Hello > >>>>> i send identify information from second node starting > >>>>> "ovirt-identify-node -s 192.168.50.2 -p 12120 -d -v" > >>>>> but in listing "Hosts" hypervisor field empty > >>>>> i think ovirt-appliance can't connect to libvirtd > >>>> Why are you running ovirt-identify-node manually? That should run only as > >>>> part of the Node bootup sequence automatically. > >>> Automaticaly this query "dig +short -t srv _$1._$2.$(dnsdomainname)" > >>> from /etc/init.d/ovirt-functions haven't answer (i didn't configure dns > >>> for local zones). > >> DNS on the oVirt Appliance is provided by dnsmasq which provides the DNS > >> SRV records that oVirt needs automatically. The Appliance won't work with > >> external DNS without major changes to it. > >> > >> From the .254 Node and the Appliance what is the output of: > >> > >> dig +short -t srv _ovirt._tcp.priv.ovirt.org > > > > hello > > i set in /etc/resolv.conf "nameserver 192.168.50.2" in all nodes > > after that "dig +short -t srv _ovirt._tcp.priv.ovirt.org" output is "0 0 > > 80 management.priv.ovirt.org." > > Ok that looks correct, but it is odd that you had to set resolv.conf > manually. That should have been set by DHCP. > > >> The next question is, does the Node have a valid kerberos ticket? Can you > >> give me the /var/log/ovirt.log file from the .254 Node? And do you have > >> an /etc/libvirt/krb5.tab file on the Node? > > > > i haven't file /etc/libvirt/krb5.tab on all nodes > > where i can find valid kerberos ticket ? > > The kerberos ticket is pulled from the management server at boot time. > However, if DHCP was not working properly (as evidence from misconfigured > resolv.conf shows, then this pull would have not happened) > > Let me check your logs to see if I can find the root cause of all of this... > > Ok here's your issue... From ovirt.log on the Node: > > > DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 8 > > DHCPOFFER from 10.20.4.1 > > DHCPREQUEST on eth0 to 255.255.255.255 port 67 > > DHCPACK from 10.20.4.1 > > You have a DHCP server running on 10.20.4.1 that is on the same physical > network as your Node. The only DHCP server that should be running on that > network is the one on the Appliance at 192.168.50.2. So your Node > initially booted and was given an address from this other DHCP server, > which probably set resolv.conf to a different address than 192.168.50.2. > > If you remove this DHCP server from your network that should clear up the > problem. > > Perry > From apevec at redhat.com Mon Dec 15 15:45:46 2008 From: apevec at redhat.com (Alan Pevec) Date: Mon, 15 Dec 2008 16:45:46 +0100 Subject: [Ovirt-devel] [PATCH node] get memory info directly from /proc/meminfo In-Reply-To: <1229355947-22648-1-git-send-email-apevec@redhat.com> References: <1229355947-22648-1-git-send-email-apevec@redhat.com> Message-ID: <1229355947-22648-5-git-send-email-apevec@redhat.com> to avoid libvirt dependecy and to drop newrole workaround for selinux issue with initrc_t Signed-off-by: Alan Pevec --- scripts/ovirt-config-setup | 2 +- scripts/ovirt-config-storage | 3 +-- scripts/ovirt-firstboot | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/scripts/ovirt-config-setup b/scripts/ovirt-config-setup index 639b7b8..20dd5ae 100755 --- a/scripts/ovirt-config-setup +++ b/scripts/ovirt-config-setup @@ -31,7 +31,7 @@ while true; do case "$OPTION" in "$NETWORK") ovirt-config-networking ; break ;; "$STORAGE") - newrole -r system_r -t virtd_t -- -c ovirt-config-storage ; + ovirt-config-storage ; break ;; "$LOGGING") ovirt-config-logging ; break ;; "$PASSWORD") ovirt-config-password ; break ;; diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage index fd877e2..dd3fab1 100755 --- a/scripts/ovirt-config-storage +++ b/scripts/ovirt-config-storage @@ -256,8 +256,7 @@ do_confirm() done } -MEM_SIZE=$(virsh --readonly -c qemu:///system nodeinfo \ - | awk '/Memory size/ { print $3 }') +MEM_SIZE=$(cat /proc/meminfo | awk '/MemTotal:/ { print $2 }') case $MEM_SIZE in ''|*[^0-9]*) die failed to get system memory size;; esac diff --git a/scripts/ovirt-firstboot b/scripts/ovirt-firstboot index ba565bf..1f7cf22 100755 --- a/scripts/ovirt-firstboot +++ b/scripts/ovirt-firstboot @@ -33,7 +33,7 @@ start () if is_auto_install; then ovirt-config-networking AUTO - newrole -r system_r -t virtd_t -- -c 'ovirt-config-storage AUTO' + ovirt-config-storage AUTO ovirt-config-logging AUTO if [ "$OVIRT_LOCAL_BOOT" = 1 ]; then mount_live -- 1.6.0.4 From apevec at redhat.com Mon Dec 15 15:45:47 2008 From: apevec at redhat.com (Alan Pevec) Date: Mon, 15 Dec 2008 16:45:47 +0100 Subject: [Ovirt-devel] [PATCH node] set default swap size to twice the RAM size In-Reply-To: <1229355947-22648-1-git-send-email-apevec@redhat.com> References: <1229355947-22648-1-git-send-email-apevec@redhat.com> Message-ID: <1229355947-22648-6-git-send-email-apevec@redhat.com> --- scripts/ovirt-config-storage | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage index dd3fab1..2fae9fe 100755 --- a/scripts/ovirt-config-storage +++ b/scripts/ovirt-config-storage @@ -261,7 +261,7 @@ case $MEM_SIZE in ''|*[^0-9]*) die failed to get system memory size;; esac -MEM_SIZE=$(echo "scale=0; $MEM_SIZE / 1024" | bc -l) +MEM_SIZE=$(echo "scale=0; $MEM_SIZE / 1024 * 2" | bc -l) SWAP_SIZE=${OVIRT_VOL_SWAP_SIZE:-$MEM_SIZE} BOOT_SIZE=${OVIRT_VOL_BOOT_SIZE:-$default_boot_size} -- 1.6.0.4 From apevec at redhat.com Mon Dec 15 16:35:28 2008 From: apevec at redhat.com (Alan Pevec) Date: Mon, 15 Dec 2008 17:35:28 +0100 Subject: [Ovirt-devel] [PATCH node] set default swap size to twice the RAM size In-Reply-To: <494675F0.7090506@redhat.com> References: <494675F0.7090506@redhat.com> Message-ID: <1229358928-24245-1-git-send-email-apevec@redhat.com> max. 2048MB specify manually via ovirt_vol parameter if more/less is needed ovirt_vol=BOOT_MB:SWAP_MB:ROOT_MB:CONFIG_MB:LOGGING_MB Signed-off-by: Alan Pevec --- scripts/ovirt-config-storage | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage index dd3fab1..1f1993a 100755 --- a/scripts/ovirt-config-storage +++ b/scripts/ovirt-config-storage @@ -261,7 +261,7 @@ case $MEM_SIZE in ''|*[^0-9]*) die failed to get system memory size;; esac -MEM_SIZE=$(echo "scale=0; $MEM_SIZE / 1024" | bc -l) +MEM_SIZE=$(echo "scale=0; m=($MEM_SIZE / 1024 * 2); if (m < 2048) { m } else { 2048 }" | bc -l) SWAP_SIZE=${OVIRT_VOL_SWAP_SIZE:-$MEM_SIZE} BOOT_SIZE=${OVIRT_VOL_BOOT_SIZE:-$default_boot_size} -- 1.6.0.4 From clalance at redhat.com Mon Dec 15 16:38:17 2008 From: clalance at redhat.com (Chris Lalancette) Date: Mon, 15 Dec 2008 17:38:17 +0100 Subject: [Ovirt-devel] [PATCH node] set default swap size to twice the RAM size In-Reply-To: <1229358928-24245-1-git-send-email-apevec@redhat.com> References: <494675F0.7090506@redhat.com> <1229358928-24245-1-git-send-email-apevec@redhat.com> Message-ID: <494687F9.6010107@redhat.com> Alan Pevec wrote: > max. 2048MB > specify manually via ovirt_vol parameter if more/less is needed > ovirt_vol=BOOT_MB:SWAP_MB:ROOT_MB:CONFIG_MB:LOGGING_MB Right, as long as the admin can override it, good stuff. We can always play with this value later if we find out that users want/need more generally. ACK -- Chris Lalancette From dpierce at redhat.com Mon Dec 15 16:41:26 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 15 Dec 2008 11:41:26 -0500 Subject: [Ovirt-devel] [PATCH node] set default swap size to twice the RAM size In-Reply-To: <1229355947-22648-6-git-send-email-apevec@redhat.com> References: <1229355947-22648-1-git-send-email-apevec@redhat.com> <1229355947-22648-6-git-send-email-apevec@redhat.com> Message-ID: <20081215164124.GG3800@mcpierce-laptop.rdu.redhat.com> On Mon, Dec 15, 2008 at 04:45:47PM +0100, Alan Pevec wrote: > --- > scripts/ovirt-config-storage | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage > index dd3fab1..2fae9fe 100755 > --- a/scripts/ovirt-config-storage > +++ b/scripts/ovirt-config-storage > @@ -261,7 +261,7 @@ case $MEM_SIZE in > ''|*[^0-9]*) die failed to get system memory size;; > esac > > -MEM_SIZE=$(echo "scale=0; $MEM_SIZE / 1024" | bc -l) > +MEM_SIZE=$(echo "scale=0; $MEM_SIZE / 1024 * 2" | bc -l) > SWAP_SIZE=${OVIRT_VOL_SWAP_SIZE:-$MEM_SIZE} > > BOOT_SIZE=${OVIRT_VOL_BOOT_SIZE:-$default_boot_size} > -- > 1.6.0.4 > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel ACK. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From dpierce at redhat.com Mon Dec 15 16:41:52 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 15 Dec 2008 11:41:52 -0500 Subject: [Ovirt-devel] [PATCH node] get memory info directly from /proc/meminfo In-Reply-To: <1229355947-22648-5-git-send-email-apevec@redhat.com> References: <1229355947-22648-1-git-send-email-apevec@redhat.com> <1229355947-22648-5-git-send-email-apevec@redhat.com> Message-ID: <20081215164152.GH3800@mcpierce-laptop.rdu.redhat.com> On Mon, Dec 15, 2008 at 04:45:46PM +0100, Alan Pevec wrote: > to avoid libvirt dependecy and to drop newrole workaround > for selinux issue with initrc_t > > Signed-off-by: Alan Pevec > --- > scripts/ovirt-config-setup | 2 +- > scripts/ovirt-config-storage | 3 +-- > scripts/ovirt-firstboot | 2 +- > 3 files changed, 3 insertions(+), 4 deletions(-) > > diff --git a/scripts/ovirt-config-setup b/scripts/ovirt-config-setup > index 639b7b8..20dd5ae 100755 > --- a/scripts/ovirt-config-setup > +++ b/scripts/ovirt-config-setup > @@ -31,7 +31,7 @@ while true; do > case "$OPTION" in > "$NETWORK") ovirt-config-networking ; break ;; > "$STORAGE") > - newrole -r system_r -t virtd_t -- -c ovirt-config-storage ; > + ovirt-config-storage ; > break ;; > "$LOGGING") ovirt-config-logging ; break ;; > "$PASSWORD") ovirt-config-password ; break ;; > diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage > index fd877e2..dd3fab1 100755 > --- a/scripts/ovirt-config-storage > +++ b/scripts/ovirt-config-storage > @@ -256,8 +256,7 @@ do_confirm() > done > } > > -MEM_SIZE=$(virsh --readonly -c qemu:///system nodeinfo \ > - | awk '/Memory size/ { print $3 }') > +MEM_SIZE=$(cat /proc/meminfo | awk '/MemTotal:/ { print $2 }') > case $MEM_SIZE in > ''|*[^0-9]*) die failed to get system memory size;; > esac > diff --git a/scripts/ovirt-firstboot b/scripts/ovirt-firstboot > index ba565bf..1f7cf22 100755 > --- a/scripts/ovirt-firstboot > +++ b/scripts/ovirt-firstboot > @@ -33,7 +33,7 @@ start () > > if is_auto_install; then > ovirt-config-networking AUTO > - newrole -r system_r -t virtd_t -- -c 'ovirt-config-storage AUTO' > + ovirt-config-storage AUTO > ovirt-config-logging AUTO > if [ "$OVIRT_LOCAL_BOOT" = 1 ]; then > mount_live > -- > 1.6.0.4 > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel ACK. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From apevec at redhat.com Mon Dec 15 17:47:20 2008 From: apevec at redhat.com (Alan Pevec) Date: Mon, 15 Dec 2008 18:47:20 +0100 Subject: [Ovirt-devel] [PATCH node] ovirt-config-networking fixes Message-ID: <1229363240-3811-1-git-send-email-apevec@redhat.com> import ovirt-functions for autoinstall mode (sources /etc/default/ovirt) send messages to both log and console --- scripts/ovirt-config-networking | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/ovirt-config-networking b/scripts/ovirt-config-networking index 0e84b29..6609d0a 100755 --- a/scripts/ovirt-config-networking +++ b/scripts/ovirt-config-networking @@ -3,6 +3,8 @@ # Iterates over the list of network devices on the node and prompts the user # to configure each. +. /etc/init.d/ovirt-functions + ME=$(basename "$0") warn() { printf '%s: %s\n' "$ME" "$*" >&2; } die() { warn "$*"; exit 1; } @@ -157,7 +159,7 @@ function setup_menu } if [ "$1" == "AUTO" ]; then - configure_interface $OVIRT_BOOTIF AUTO + configure_interface "$OVIRT_BOOTIF" AUTO RESTART="Y" else setup_menu @@ -181,5 +183,6 @@ if [ "$RESTART" == "Y" ]; then { cat "$WORKDIR"/augtool-* && printf "save\n"; } > $config \ && augtool < $config \ && service network restart - } >> $CONFIG_LOG_FILE 2>&1 + } 2>&1 | tee $CONFIG_LOG_FILE + fi -- 1.6.0.4 From dpierce at redhat.com Mon Dec 15 18:53:55 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 15 Dec 2008 13:53:55 -0500 Subject: [Ovirt-devel] [PATCH node] ovirt-config-networking fixes In-Reply-To: <1229363240-3811-1-git-send-email-apevec@redhat.com> References: <1229363240-3811-1-git-send-email-apevec@redhat.com> Message-ID: <20081215185355.GJ3800@mcpierce-laptop.rdu.redhat.com> On Mon, Dec 15, 2008 at 06:47:20PM +0100, Alan Pevec wrote: > import ovirt-functions for autoinstall mode (sources /etc/default/ovirt) > send messages to both log and console > --- > scripts/ovirt-config-networking | 7 +++++-- > 1 files changed, 5 insertions(+), 2 deletions(-) > > diff --git a/scripts/ovirt-config-networking b/scripts/ovirt-config-networking > index 0e84b29..6609d0a 100755 > --- a/scripts/ovirt-config-networking > +++ b/scripts/ovirt-config-networking > @@ -3,6 +3,8 @@ > # Iterates over the list of network devices on the node and prompts the user > # to configure each. > > +. /etc/init.d/ovirt-functions > + > ME=$(basename "$0") > warn() { printf '%s: %s\n' "$ME" "$*" >&2; } > die() { warn "$*"; exit 1; } > @@ -157,7 +159,7 @@ function setup_menu > } > > if [ "$1" == "AUTO" ]; then > - configure_interface $OVIRT_BOOTIF AUTO > + configure_interface "$OVIRT_BOOTIF" AUTO > RESTART="Y" > else > setup_menu > @@ -181,5 +183,6 @@ if [ "$RESTART" == "Y" ]; then > { cat "$WORKDIR"/augtool-* && printf "save\n"; } > $config \ > && augtool < $config \ > && service network restart > - } >> $CONFIG_LOG_FILE 2>&1 > + } 2>&1 | tee $CONFIG_LOG_FILE > + > fi > -- > 1.6.0.4 ACK. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From dpierce at redhat.com Mon Dec 15 19:21:50 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 15 Dec 2008 14:21:50 -0500 Subject: [Ovirt-devel] [PATCH node] ovirt-config-boot - minimal installer for livecd image to local disk In-Reply-To: <1229355947-22648-2-git-send-email-apevec@redhat.com> References: <1229355947-22648-1-git-send-email-apevec@redhat.com> <1229355947-22648-2-git-send-email-apevec@redhat.com> Message-ID: <20081215192150.GA14364@mcpierce-laptop.rdu.redhat.com> On Mon, Dec 15, 2008 at 04:45:43PM +0100, Alan Pevec wrote: > + cp -p $live/LiveOS/squashfs.img /liveos/LiveOS \ Where does this file come from? I'm looking and it's not on the managed node and not in my build environment. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From mmorsi at redhat.com Mon Dec 15 10:21:06 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Mon, 15 Dec 2008 05:21:06 -0500 Subject: [Ovirt-devel] [PATCH server] test suite updates and fixes for new validation components Message-ID: <1229336466-6293-1-git-send-email-mmorsi@redhat.com> note, this patch requires the last validation patch to be applied to work included are a few updates to the main server app and many updates to the test suite to fix a few various bits and assert all the new validations recently added. --- src/app/models/bonding.rb | 4 +- src/app/models/nic.rb | 4 +- src/app/models/storage_volume.rb | 2 +- src/app/models/vm.rb | 2 +- src/test/fixtures/help_sections.yml | 14 +++-- src/test/fixtures/storage_pools.yml | 7 ++ src/test/fixtures/usages.yml | 12 ++-- src/test/unit/bonding_test.rb | 35 ++++++++++ src/test/unit/boot_type_test.rb | 36 +++++++++- src/test/unit/cpu_test.rb | 95 ++++++++++++++++++++++++++- src/test/unit/help_section_test.rb | 51 +++++++++++++- src/test/unit/host_browser_identify_test.rb | 8 +- src/test/unit/host_test.rb | 60 ++++++++++++++++- src/test/unit/ip_address_test.rb | 5 ++ src/test/unit/ip_v4_address_test.rb | 3 +- src/test/unit/ip_v6_address_test.rb | 3 +- src/test/unit/nic_test.rb | 58 +++++++++++++++- src/test/unit/permission_test.rb | 28 ++++++++ src/test/unit/pool_test.rb | 21 ++++++ src/test/unit/quota_test.rb | 37 ++++++++++- src/test/unit/storage_pool_test.rb | 45 +++++++++++++ src/test/unit/storage_volume_test.rb | 86 ++++++++++++++++++++++++ src/test/unit/task_test.rb | 14 ++++ src/test/unit/usage_test.rb | 47 ++++++++++++- src/test/unit/vm_test.rb | 64 ++++++++++++++++++ 25 files changed, 697 insertions(+), 44 deletions(-) diff --git a/src/app/models/bonding.rb b/src/app/models/bonding.rb index fabdb67..660dcd0 100644 --- a/src/app/models/bonding.rb +++ b/src/app/models/bonding.rb @@ -71,7 +71,9 @@ class Bonding < ActiveRecord::Base protected def validate - if vlan.boot_type.proto == 'static' and ip_addresses.size == 0 + if ! vlan.nil? and + vlan.boot_type.proto == 'static' and + ip_addresses.size == 0 errors.add("vlan_id", "is static. Must create at least one static ip") end diff --git a/src/app/models/nic.rb b/src/app/models/nic.rb index aa9c740..029b4e4 100644 --- a/src/app/models/nic.rb +++ b/src/app/models/nic.rb @@ -43,7 +43,9 @@ class Nic < ActiveRecord::Base protected def validate - if physical_network.boot_type.proto == 'static' and ip_addresses.size == 0 + if ! physical_network.nil? and + physical_network.boot_type.proto == 'static' and + ip_addresses.size == 0 errors.add("physical_network_id", "is static. Must create at least one static ip") end diff --git a/src/app/models/storage_volume.rb b/src/app/models/storage_volume.rb index 0f490f8..385c126 100644 --- a/src/app/models/storage_volume.rb +++ b/src/app/models/storage_volume.rb @@ -146,7 +146,7 @@ class StorageVolume < ActiveRecord::Base def movable? if vms.size > 0 or - (! lvm_storage_pool.nil? and ! lvm_storage_pool.movable?) + (not lvm_storage_pool.nil? and not lvm_stoage_pool.movable?) return false end return true diff --git a/src/app/models/vm.rb b/src/app/models/vm.rb index 4d66c63..bf99e2d 100644 --- a/src/app/models/vm.rb +++ b/src/app/models/vm.rb @@ -341,7 +341,7 @@ class Vm < ActiveRecord::Base # FIXME: what should memory min/max be? errors.add("memory_allocated_in_mb", "must be at least 256 MB") unless not(memory_allocated_in_mb) or memory_allocated_in_mb >=256 # FIXME: what should cpu min/max - errors.add("num_vcpus_allocated", "must be between 1 and 16") unless (num_vcpus_allocated >=1 and num_vcpus_allocated <= 16) + errors.add("num_vcpus_allocated", "must be between 1 and 16") unless (num_vcpus_allocated.nil? or (num_vcpus_allocated >=1 and num_vcpus_allocated <= 16)) errors.add("memory_allocated_in_mb", "violates quota") unless not(memory_allocated) or resources[:memory].nil? or memory_allocated <= resources[:memory] errors.add("num_vcpus_allocated", "violates quota") unless not(num_vcpus_allocated) or resources[:cpus].nil? or num_vcpus_allocated <= resources[:cpus] errors.add_to_base("No available nics in quota") unless resources[:nics].nil? or resources[:nics] >= 1 diff --git a/src/test/fixtures/help_sections.yml b/src/test/fixtures/help_sections.yml index 5bf0293..d9f93e4 100644 --- a/src/test/fixtures/help_sections.yml +++ b/src/test/fixtures/help_sections.yml @@ -1,7 +1,11 @@ # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html -# one: -# column: value -# -# two: -# column: value +dashboard_help: + controller: dashboard + action: index + section: 'index.html' + +hardware_hosts_help: + controller: hardware + action: hosts + section: 'hardware_hosts.html' diff --git a/src/test/fixtures/storage_pools.yml b/src/test/fixtures/storage_pools.yml index 3cda6db..35bfc88 100644 --- a/src/test/fixtures/storage_pools.yml +++ b/src/test/fixtures/storage_pools.yml @@ -20,3 +20,10 @@ corp_com_dev_nfs_ovirtnfs: export_path: /devnfs state: available capacity: 1024 +corp_com_dev_lvm_ovirtlvm: + hardware_pool: corp_com_dev + type: LvmStoragePool + ip_addr: 192.168.50.3 + export_path: /devnfs + state: available + capacity: 1024 diff --git a/src/test/fixtures/usages.yml b/src/test/fixtures/usages.yml index 5bf0293..3bd72e6 100644 --- a/src/test/fixtures/usages.yml +++ b/src/test/fixtures/usages.yml @@ -1,7 +1,9 @@ # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html -# one: -# column: value -# -# two: -# column: value +management_usage: + label: management + usage: management + +guest_usage: + label: guest + usage: guest diff --git a/src/test/unit/bonding_test.rb b/src/test/unit/bonding_test.rb index 8b90cd5..157035a 100644 --- a/src/test/unit/bonding_test.rb +++ b/src/test/unit/bonding_test.rb @@ -35,6 +35,7 @@ class BondingTest < ActiveSupport::TestCase :bonding_type_id => bonding_types(:failover_bonding_type), :host_id => hosts(:mailservers_managed_node)) @bonding.vlan = networks(:dhcp_vlan_one) + @bonding.bonding_type = bonding_types(:load_balancing_bonding_type) end # Ensures that the name is required. @@ -69,6 +70,40 @@ class BondingTest < ActiveSupport::TestCase flunk 'Bondings have to have a host.' if @bonding.valid? end + def test_valid_fails_without_bonding_type + @bonding.bonding_type = nil + flunk 'Bonding must specify bonding type' if @bonding.valid? + end + + def test_valid_fails_without_vlan + @bonding.vlan = nil + flunk 'Bonding must specify vlan' if @bonding.valid? + end + + # Ensures that an arp ping address must have the correct format + # + def test_valid_fails_with_bad_arp_ping_address + @bonding.arp_ping_address = 'foobar' + + flunk "An arp ping address must be in the format ##.##.##.##." if @bonding.valid? + end + + # Ensures that an arp interval is a numerical value >= 0 + # + def test_valid_fails_with_bad_arp_interval + @bonding.arp_interval = -1 + + flunk "An arp interval must be >= 0" if @bonding.valid? + end + + def test_static_network_bonding_must_have_ip + @bonding.vlan = networks(:static_vlan_one) + @bonding.ip_addresses.delete_if { true } + + flunk 'Bonding assigned to static networks must have at least one ip' if @bonding.valid? + end + + # Ensure that retrieving a bonding returns its associated objects. # def test_find_all_for_host diff --git a/src/test/unit/boot_type_test.rb b/src/test/unit/boot_type_test.rb index a30e258..16ed516 100644 --- a/src/test/unit/boot_type_test.rb +++ b/src/test/unit/boot_type_test.rb @@ -19,8 +19,36 @@ require File.dirname(__FILE__) + '/../test_helper' class BootTypeTest < ActiveSupport::TestCase - # Replace this with your real tests. - def test_truth - assert true - end + fixtures :boot_types + + def setup + @boot_type = BootType.new( + :label => 'TestBootType', + :proto => 'static' ) + end + + def test_valid_fails_without_label + @boot_type.label = '' + + flunk 'Boot type must have label' if @boot_type.valid? + end + + def test_valid_fails_without_unique_label + @boot_type.label = 'Static IP' + + flunk 'Boot type must have unique label' if @boot_type.valid? + end + + def test_valid_fails_with_bad_proto + @boot_type.proto = 'foobar' + + flunk 'Boot type must have valid proto' if @boot_type.valid? + end + + def test_find_all_for_boot_type + result = BootType.find(:all) + + assert_equal 3, result.size, "Did not find right number of boot types" + end + end diff --git a/src/test/unit/cpu_test.rb b/src/test/unit/cpu_test.rb index 9558525..c1e9e63 100644 --- a/src/test/unit/cpu_test.rb +++ b/src/test/unit/cpu_test.rb @@ -1,10 +1,99 @@ +# Copyright (C) 2008 Red Hat, Inc. +# Written by Mohammed Morsi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + require File.dirname(__FILE__) + '/../test_helper' class CpuTest < ActiveSupport::TestCase fixtures :cpus + fixtures :hosts + + def setup + @cpu = Cpu.new( + :cpu_number => 3, + :core_number => 1, + :number_of_cores => 1, + :cpuid_level => 0, + :speed => 2048, + :vendor => 'foo', + :model => 'bar', + :family => 'alpha') + @cpu.host = hosts(:prod_corp_com) + end + + def test_find_cpus + assert_equal Cpu.find(:all).size, 8, "Failure retrieving all cpus" + + result = Cpu.find(cpus(:prod_corp_com_1).id) + assert_equal result.host.id, hosts(:prod_corp_com).id + end + + def test_valid_without_host + @cpu.host = nil + + flunk "CPUs must be associated with hosts" if @cpu.valid? + end + + def test_valid_with_bad_cpu_numer + @cpu.cpu_number = -1 + + flunk "cpu number must be >= 0" if @cpu.valid? + end + + def test_valid_with_bad_core_number + @cpu.core_number = -1 + + flunk "cpu core number must be >= 0" if @cpu.valid? + end - # Replace this with your real tests. - def test_truth - assert true + def test_valid_with_bad_number_of_cores + @cpu.number_of_cores = 0 + + flunk "cpu number of cores must be > 0" if @cpu.valid? end + + def test_valid_with_bad_cpuid_level + @cpu.cpuid_level = -1 + + flunk "cpu id level must be >= 0" if @cpu.valid? + end + + def test_valid_with_bad_speed + @cpu.speed = 0 + + flunk "cpu speed must be > 0" if @cpu.valid? + end + + def test_valid_without_vendor + @cpu.vendor = '' + + flunk "cpu vendor must be specified" if @cpu.valid? + end + + def test_valid_without_model + @cpu.model = '' + + flunk "cpu model must be specified" if @cpu.valid? + end + + def test_valid_without_family + @cpu.family = '' + + flunk "cpu family must be specified" if @cpu.valid? + end + end diff --git a/src/test/unit/help_section_test.rb b/src/test/unit/help_section_test.rb index a0e6a08..e30345a 100644 --- a/src/test/unit/help_section_test.rb +++ b/src/test/unit/help_section_test.rb @@ -1,8 +1,51 @@ +# Copyright (C) 2008 Red Hat, Inc. +# Written by Mohammed Morsi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. require 'test_helper' class HelpSectionTest < ActiveSupport::TestCase - # Replace this with your real tests. - def test_truth - assert true - end + fixtures :help_sections + + def setup + @help_section = HelpSection.new( + :controller => 'foo', + :action => 'bar', + :section => 'foobar') + end + + def test_unique_controller_action + @help_section.controller = 'dashboard' + @help_section.action = 'index' + + flunk 'help section must have unique controller / action' if @help_section.valid? + end + + def test_valid_fails_without_controller + @help_section.controller = '' + flunk 'help section controller must be specified' if @help_section.valid? + end + + def test_valid_fails_without_action + @help_section.action = '' + flunk 'help section action must be specified' if @help_section.valid? + end + + def test_valid_fails_without_section + @help_section.section = '' + flunk 'help section section must be specified' if @help_section.valid? + end end diff --git a/src/test/unit/host_browser_identify_test.rb b/src/test/unit/host_browser_identify_test.rb index a17ea30..9f7be1f 100644 --- a/src/test/unit/host_browser_identify_test.rb +++ b/src/test/unit/host_browser_identify_test.rb @@ -163,11 +163,11 @@ class HostBrowserIdentifyTest < Test::Unit::TestCase # Ensures that the server is fine when no UUID is present. # - def test_write_host_info_with_missing_uuid - @host_info['UUID'] = nil + #def test_write_host_info_with_missing_uuid + #@host_info['UUID'] = nil - assert_nothing_raised { @browser.write_host_info(@host_info) } - end + #assert_nothing_raised { @browser.write_host_info(@host_info) } + #end # Ensures that, if the hostname is missing, the server # raises an exception. diff --git a/src/test/unit/host_test.rb b/src/test/unit/host_test.rb index a4ead5d..a7458d2 100644 --- a/src/test/unit/host_test.rb +++ b/src/test/unit/host_test.rb @@ -21,9 +21,63 @@ require File.dirname(__FILE__) + '/../test_helper' class HostTest < Test::Unit::TestCase fixtures :hosts + fixtures :pools + fixtures :vms - # Replace this with your real tests. - def test_truth - assert true + def setup + @host = Host.new( + :uuid => 'foobar', + :hostname => 'foobar', + :arch => 'x86_64', + :hypervisor_type => 'kvm', + :state => 'available') + + @host.hardware_pool = pools(:corp_com) + end + + def test_valid_fails_without_hardware_pool + @host.hardware_pool = nil + + flunk "Hosts must be associated w/ a hardware pool" if @host.valid? + end + + def test_valid_fails_without_uuid + @host.uuid = '' + + flunk "Hosts must be associated w/ a uuid" if @host.valid? end + + + def test_valid_fails_without_hostname + @host.hostname = '' + + flunk "Hosts must be associated w/ a hostname" if @host.valid? + end + + + def test_valid_fails_without_arch + @host.arch = '' + + flunk "Hosts must be associated w/ an arch" if @host.valid? + end + + def test_valid_fails_with_bad_hypervisor_type + @host.hypervisor_type = 'foobar' + + flunk "Hosts must be associated w/ a valid hypervisor type" if @host.valid? + end + + def test_valid_fails_with_bad_state + @host.state = 'foobar' + + flunk "Hosts must be associated w/ a valid state" if @host.valid? + end + + def test_host_movable + assert_equal @host.movable?, true, "Hosts are movable unless associated w/ vms" + + @host.vms << vms(:production_httpd_vm) + assert_equal @host.movable?, false, "Hosts with associated vms are not movable" + end + end diff --git a/src/test/unit/ip_address_test.rb b/src/test/unit/ip_address_test.rb index 5ecff77..4cfc694 100644 --- a/src/test/unit/ip_address_test.rb +++ b/src/test/unit/ip_address_test.rb @@ -10,4 +10,9 @@ class IpAddressTest < ActiveSupport::TestCase def test_can_get_ipaddress_object assert_equal ip_addresses(:ip_v4_mailserver_nic_one).address, '172.31.0.15' end + + def test_valid_fails_without_foreign_entity + @ip_address = IpAddress.new + flunk "Ip Address must be associated with network, nic, or bonding" if @ip_address.valid? + end end diff --git a/src/test/unit/ip_v4_address_test.rb b/src/test/unit/ip_v4_address_test.rb index 65a08d3..9cb7362 100644 --- a/src/test/unit/ip_v4_address_test.rb +++ b/src/test/unit/ip_v4_address_test.rb @@ -24,7 +24,8 @@ class IpV4AddressTest < ActiveSupport::TestCase @address = IpV4Address.new(:address => '192.168.50.2', :netmask => '255.255.255.0', :gateway => '192.168.50.1', - :broadcast => '192.168.50.255') + :broadcast => '192.168.50.255', + :nic_id => 1) end # Ensures that an address must be supplied. diff --git a/src/test/unit/ip_v6_address_test.rb b/src/test/unit/ip_v6_address_test.rb index 070f407..96f212a 100644 --- a/src/test/unit/ip_v6_address_test.rb +++ b/src/test/unit/ip_v6_address_test.rb @@ -23,7 +23,8 @@ class IpV6AddressTest < ActiveSupport::TestCase def setup @address = IpV6Address.new(:address => 'fe80:0:0:0:200:f8ff:fe21:67cf', :gateway => ':::::::717', - :prefix => '0000:0000:0000:0000:1234:1234:1234:1234') + :prefix => '0000:0000:0000:0000:1234:1234:1234:1234', + :nic_id => 1) end # Ensures that the address must be provided. diff --git a/src/test/unit/nic_test.rb b/src/test/unit/nic_test.rb index 1de1e00..0e5321e 100644 --- a/src/test/unit/nic_test.rb +++ b/src/test/unit/nic_test.rb @@ -22,9 +22,61 @@ require File.dirname(__FILE__) + '/../test_helper' class NicTest < Test::Unit::TestCase fixtures :ip_addresses fixtures :nics + fixtures :hosts + fixtures :networks - # Replace this with your real tests. - def test_truth - assert true + def setup + @nic = Nic.new( + :mac => '00:11:22:33:44:55', + :usage_type => 1, + :bandwidth => 100 ) + @nic.host = hosts(:prod_corp_com) + @nic.physical_network = networks(:static_physical_network_one) + + @ip_address = IpV4Address.new( + :address => '1.2.3.4', + :netmask => '2.3.4.5', + :gateway => '3.4.5.6', + :broadcast => '4.5.6.7' ) + + @nic.ip_addresses << @ip_address + end + + def test_valid_fails_without_mac + @nic.mac = '' + + flunk 'Nic must have a mac' if @nic.valid? + end + + def test_valid_fails_with_invalid_mac + @nic.mac = 'foobar' + + flunk 'Nic must have a valid mac' if @nic.valid? + end + + def test_valid_fails_without_host + @nic.host = nil + + flunk 'Nic must have a host' if @nic.valid? end + + def test_valid_fails_without_physical_network + @nic.physical_network = nil + + flunk 'Nic must have a physical network' if @nic.valid? + end + + def test_valid_fails_with_invalid_bandwidth + @nic.bandwidth = -1 + + flunk 'Nic bandwidth must be >= 0' if @nic.valid? + end + + def test_static_network_nic_must_have_ip + @nic.physical_network = networks(:static_physical_network_one) + @nic.ip_addresses.delete_if { true } + + flunk 'Nics assigned to static networks must have at least one ip' if @nic.valid? + end + end diff --git a/src/test/unit/permission_test.rb b/src/test/unit/permission_test.rb index 5e2c7ba..0c0f4c7 100644 --- a/src/test/unit/permission_test.rb +++ b/src/test/unit/permission_test.rb @@ -21,6 +21,14 @@ require File.dirname(__FILE__) + '/../test_helper' class PermissionTest < Test::Unit::TestCase fixtures :permissions + fixtures :pools + + def setup + @permission = Permission.new( + :uid => 'foobar', + :user_role => 'Super Admin' ) + @permission.pool = pools(:root_dir_pool) + end # Replace this with your real tests. def test_simple_permission @@ -32,4 +40,24 @@ class PermissionTest < Test::Unit::TestCase assert_equal permissions(:ovirtadmin_default).inherited_from_id, permissions(:ovirtadmin_root).id assert_equal permissions(:ovirtadmin_default).parent_permission, permissions(:ovirtadmin_root) end + + def test_valid_fails_without_pool + @permission.pool = nil + flunk 'Permission must specify pool' if @permission.valid? + end + + def test_valid_fails_without_uid + @permission.uid = '' + flunk 'Permission must specify uid' if @permission.valid? + end + + def test_valid_fails_without_user_role + @permission.user_role = '' + flunk 'Permission must specify user role' if @permission.valid? + end + + def test_valid_fails_with_invalid_user_role + @permission.user_role = 'foobar' + flunk 'Permission must specify valid user role' if @permission.valid? + end end diff --git a/src/test/unit/pool_test.rb b/src/test/unit/pool_test.rb index 6f20f9f..c9a5554 100644 --- a/src/test/unit/pool_test.rb +++ b/src/test/unit/pool_test.rb @@ -22,6 +22,12 @@ require File.dirname(__FILE__) + '/../test_helper' class PoolTest < Test::Unit::TestCase fixtures :pools + def setup + @pool = Pool.new( + :name => 'foobar', + :type => 'DirectoryPool' ) + end + # Replace this with your real tests. def test_get_name assert_equal(pools(:corp_com_prod).name, 'Production Operations') @@ -30,4 +36,19 @@ class PoolTest < Test::Unit::TestCase def test_get_parent assert_equal(pools(:corp_com_prod).parent.name, 'corp.com') end + + def test_valid_fails_without_name + @pool.name = '' + flunk "Pool must specify name" if @pool.valid? + end + + def test_valid_fails_without_unique_name + @pool.name = 'root' + flunk "Pool must specify unique name" if @pool.valid? + end + + def test_valid_fails_with_invalid_type + @pool.name = 'foobar' + flunk "Pool must specify valid type" if @pool.valid? + end end diff --git a/src/test/unit/quota_test.rb b/src/test/unit/quota_test.rb index ac0fae0..5903cc8 100644 --- a/src/test/unit/quota_test.rb +++ b/src/test/unit/quota_test.rb @@ -21,9 +21,40 @@ require File.dirname(__FILE__) + '/../test_helper' class QuotaTest < Test::Unit::TestCase fixtures :quotas + fixtures :pools - # Replace this with your real tests. - def test_truth - assert true + def setup + @quota = Quota.new + @quota.pool = pools(:root_dir_pool) + end + + def test_valid_fails_without_pool + @quota.pool = nil + flunk "Quota's must specify pool" if @quota.valid? + end + + def test_valid_fails_with_bad_total_vcpus + @quota.total_vcpus = -1 + flunk "Quota must specify valid total vcpus" if @quota.valid? + end + + def test_valid_fails_with_bad_total_vmemory + @quota.total_vmemory = -1 + flunk "Quota must specify valid total vmemory" if @quota.valid? + end + + def test_valid_fails_with_bad_total_vnics + @quota.total_vnics = -1 + flunk "Quota must specify valid total vnics" if @quota.valid? + end + + def test_valid_fails_with_bad_total_storage + @quota.total_storage = -1 + flunk "Quota must specify valid total storage" if @quota.valid? + end + + def test_valid_fails_with_bad_total_vms + @quota.total_vms = -1 + flunk "Quota must specify valid total vms" if @quota.valid? end end diff --git a/src/test/unit/storage_pool_test.rb b/src/test/unit/storage_pool_test.rb index 8cc8d1b..00e1199 100644 --- a/src/test/unit/storage_pool_test.rb +++ b/src/test/unit/storage_pool_test.rb @@ -21,8 +21,53 @@ require File.dirname(__FILE__) + '/../test_helper' class StoragePoolTest < Test::Unit::TestCase fixtures :storage_pools + fixtures :pools + fixtures :vms + + def setup + @storage_pool = StoragePool.new( + :type => 'IscsiStoragePool', + :capacity => 100, + :state => 'available' ) + @storage_pool.hardware_pool = pools(:default) + end + + def test_valid_fails_without_hardware_pool + @storage_pool.hardware_pool = nil + flunk "Storage pool must specify hardware pool" if @storage_pool.valid? + end + + def test_valid_fails_with_bad_type + @storage_pool.type = 'foobar' + flunk 'Storage pool must specify valid type' if @storage_pool.valid? + end + + def test_valid_fails_with_bad_capacity + @storage_pool.capacity = -1 + flunk 'Storage pool must specify valid capacity >= 0' if @storage_pool.valid? + end + + def test_valid_fails_with_bad_state + @storage_pool.state = 'foobar' + flunk 'Storage pool must specify valid state' if @storage_pool.valid? + end def test_hardware_pool_relationship assert_equal 'corp.com', storage_pools(:corp_com_ovirtpriv_storage).hardware_pool.name end + + def test_movable + assert_equal @storage_pool.movable?, true, "Storage pool without volumes should be movable" + + storage_volume = StorageVolume.new( + :size => 100, + :type => 'IscsiStorageVolume', + :state => 'available' ) + @storage_pool.storage_volumes << storage_volume + + assert_equal @storage_pool.movable?, true, "Storage pool w/ movable storage volumes should be movable" + + storage_volume.vms << vms(:production_httpd_vm) + assert_equal @storage_pool.movable?, false, "Storage pool w/ unmovable storage volumes should not be movable" + end end diff --git a/src/test/unit/storage_volume_test.rb b/src/test/unit/storage_volume_test.rb index d0a89f4..7c620e3 100644 --- a/src/test/unit/storage_volume_test.rb +++ b/src/test/unit/storage_volume_test.rb @@ -21,9 +21,95 @@ require File.dirname(__FILE__) + '/../test_helper' class StorageVolumeTest < Test::Unit::TestCase fixtures :storage_volumes + fixtures :storage_pools + fixtures :vms + + def setup + @storage_volume = StorageVolume.new( + :size => 100, + :type => 'IscsiStorageVolume', + :state => 'available' ) + + @iscsi_storage_volume = IscsiStorageVolume.new( + :lun => 'foobar', + :size => 100, + :state => 'available' ) + + @lvm_storage_volume = LvmStorageVolume.new( + :lv_name => 'foobar', + :lv_owner_perms => '0700', + :lv_group_perms => '0777', + :lv_mode_perms => '0000' ) + + @storage_volume.storage_pool = storage_pools(:corp_com_ovirtpriv_storage) + @iscsi_storage_volume.storage_pool = storage_pools(:corp_com_ovirtpriv_storage) + @lvm_storage_volume.storage_pool = storage_pools(:corp_com_dev_lvm_ovirtlvm) + end # Replace this with your real tests. def test_relationship_to_storage_pool assert_equal 'corp.com', storage_volumes(:ovirtpriv_storage_lun_1).storage_pool.hardware_pool.name end + + + def test_valid_fails_with_bad_size + @storage_volume.size = -1 + + flunk "Storage volume size must be >= 0" if @storage_volume.valid? + end + + def test_valid_fails_with_bad_type + @storage_volume.type = 'foobar' + + flunk "Storage volume type must be valid" if @storage_volume.valid? + end + + def test_valid_fails_with_bad_state + @storage_volume.state = 'foobar' + flunk "Storage volume state must be valid" if @storage_volume.valid? + end + + def test_valid_fails_without_storage_pool + @storage_volume.storage_pool = nil + + flunk "Storage volume must be associated with a storage pool" if @storage_volume.valid? + end + + def test_valid_fails_without_lun + @iscsi_storage_volume.lun = '' + + flunk "iscsi storage volume lun must be valid" if @iscsi_storage_volume.valid? + end + + def test_valid_fails_without_lv_name + @lvm_storage_volume.lv_name = '' + + flunk "lvm storage volume lv_name must be valid" if @lvm_storage_volume.valid? + end + + def test_valid_fails_without_lv_owner_perms + @lvm_storage_volume.lv_owner_perms = '' + + flunk "lvm storage volume lv_owner_perms must be valid" if @lvm_storage_volume.valid? + end + + def test_valid_fails_without_lv_group_perms + @lvm_storage_volume.lv_group_perms = '' + + flunk "lvm storage volume lv_group_perms must be valid" if @lvm_storage_volume.valid? + end + + def test_valid_fails_without_lv_model_perms + @lvm_storage_volume.lv_mode_perms = '' + + flunk "lvm storage volume lv_model_perms must be valid" if @lvm_storage_volume.valid? + end + + def test_movable + assert_equal @storage_volume.movable?, true, "Storage volume without vms should be movable" + @storage_volume.vms << vms(:production_httpd_vm) + + assert_equal @storage_volume.movable?, false, "Storage volume w/ vms should not be movable" + end + end diff --git a/src/test/unit/task_test.rb b/src/test/unit/task_test.rb index 33a3bd8..ba780e7 100644 --- a/src/test/unit/task_test.rb +++ b/src/test/unit/task_test.rb @@ -22,6 +22,20 @@ require File.dirname(__FILE__) + '/../test_helper' class TaskTest < Test::Unit::TestCase fixtures :pools, :hosts, :vms, :permissions, :tasks + def setup + @task = Task.new( :type => 'HostTask', :state => 'finished' ) + end + + def test_valid_fails_with_bad_type + @task.type = 'foobar' + flunk 'Task must specify valid type' if @task.valid? + end + + def test_valid_fails_with_bad_state + @task.state = 'foobar' + flunk 'Task must specify valid state' if @task.valid? + end + def test_exercise_task_relationships assert_equal tasks(:shutdown_production_httpd_appliance_task).task_target.vm_resource_pool.name, 'corp.com production vmpool' assert_equal tasks(:shutdown_production_httpd_appliance_task).task_target.host.hostname, 'prod.corp.com' diff --git a/src/test/unit/usage_test.rb b/src/test/unit/usage_test.rb index 9a8ec9b..0cb25ae 100644 --- a/src/test/unit/usage_test.rb +++ b/src/test/unit/usage_test.rb @@ -1,8 +1,47 @@ +# Copyright (C) 2008 Red Hat, Inc. +# +# 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 'test_helper' class UsageTest < ActiveSupport::TestCase - # Replace this with your real tests. - def test_truth - assert true - end + fixtures :usages + + def setup + @usage = Usage.new( + :label => 'TestUsage', + :usage => 'foobar' ) + end + + def test_valid_fails_without_label + @usage.label = '' + + flunk 'Usage must have label' if @usage.valid? + end + + def test_valid_fails_without_usage + @usage.usage = '' + + flunk 'Usage must have usage' if @usage.valid? + end + + def test_valid_fails_without_unique_usage + @usage.usage = 'management' + + flunk 'Usage must have unique usage' if @usage.valid? + end + end diff --git a/src/test/unit/vm_test.rb b/src/test/unit/vm_test.rb index a196130..d1740cb 100644 --- a/src/test/unit/vm_test.rb +++ b/src/test/unit/vm_test.rb @@ -21,6 +21,7 @@ require File.dirname(__FILE__) + '/../test_helper' class VmTest < Test::Unit::TestCase fixtures :vms + fixtures :pools def setup @vm_name = "Test" @@ -29,6 +30,69 @@ class VmTest < Test::Unit::TestCase "#{Vm::IMAGE_PREFIX}@#{Vm::COBBLER_PREFIX}#{Vm::PROVISIONING_DELIMITER}#{@vm_name}" @cobbler_profile_provisioning = "#{Vm::PROFILE_PREFIX}@#{Vm::COBBLER_PREFIX}#{Vm::PROVISIONING_DELIMITER}#{@vm_name}" + + @vm = Vm.new( + :uuid => '00000000-1111-2222-3333-444444444444', + :description => 'foobar', + :num_vcpus_allocated => 1, + :boot_device => 'hd', + :memory_allocated_in_mb => 1, + :memory_allocated => 1024, + :vnic_mac_addr => '11:22:33:44:55:66') + + @vm.vm_resource_pool = pools(:corp_com_production_vmpool) + end + + def test_valid_fails_with_bad_uuid + @vm.uuid = 'foobar' + flunk "Vm must specify valid uuid" if @vm.valid? + end + + def test_valid_fails_without_description + @vm.description = '' + flunk 'Vm must specify description' if @vm.valid? + end + + def test_valid_fails_without_num_vcpus_allocated + @vm.num_vcpus_allocated = nil + flunk 'Vm must specify num_vcpus_allocated' if @vm.valid? + end + + def test_valid_fails_without_boot_device + @vm.boot_device = '' + flunk 'Vm must specify boot_device' if @vm.valid? + end + + + def test_valid_fails_without_memory_allocated + @vm.memory_allocated = '' + flunk 'Vm must specify memory_allocated' if @vm.valid? + end + + + def test_valid_fails_without_memory_allocated_in_mb + @vm.memory_allocated_in_mb = '' + flunk 'Vm must specify memory_allocated_in_mb' if @vm.valid? + end + + def test_valid_fails_without_vnic_mac_addr + @vm.vnic_mac_addr = '' + flunk 'Vm must specify vnic_mac_addr' if @vm.valid? + end + + def test_valid_fails_without_vm_resources_pool_id + @vm.vm_resource_pool_id = '' + flunk 'Vm must specify vm_resources_pool_id' if @vm.valid? + end + + def test_valid_fails_with_bad_needs_restart + @vm.needs_restart = 5 + flunk 'Vm must specify valid needs_restart' if @vm.valid? + end + + def test_valid_fails_with_bad_state + @vm.state = 'foobar' + flunk 'Vm must specify valid state' if @vm.valid? end # Ensures that, if the VM does not contain the Cobbler prefix, that it -- 1.6.0.4 From apevec at redhat.com Mon Dec 15 19:28:06 2008 From: apevec at redhat.com (Alan Pevec) Date: Mon, 15 Dec 2008 20:28:06 +0100 Subject: [Ovirt-devel] [PATCH node] ovirt-config-boot - minimal installer for livecd image to local disk In-Reply-To: <20081215192150.GA14364@mcpierce-laptop.rdu.redhat.com> References: <1229355947-22648-1-git-send-email-apevec@redhat.com> <1229355947-22648-2-git-send-email-apevec@redhat.com> <20081215192150.GA14364@mcpierce-laptop.rdu.redhat.com> Message-ID: <4946AFC6.6070105@redhat.com> Darryl L. Pierce wrote: > On Mon, Dec 15, 2008 at 04:45:43PM +0100, Alan Pevec wrote: >> + cp -p $live/LiveOS/squashfs.img /liveos/LiveOS \ > > Where does this file come from? I'm looking and it's not on the > managed node and not in my build environment. $live should point to /live where livecd media ( CD, USB or loop0 for PXE) should be mounted From apevec at redhat.com Tue Dec 16 02:41:14 2008 From: apevec at redhat.com (Alan Pevec) Date: Tue, 16 Dec 2008 03:41:14 +0100 Subject: [Ovirt-devel] REPOST#2 standalone and autoinstall mode fixes Message-ID: <1229395277-31053-1-git-send-email-apevec@redhat.com> [PATCH node] ovirt-config-storage autoinstall fixes [PATCH node] ovirt-config-boot - minimal installer for livecd image to local disk [PATCH node] refactor Node local disk usage From apevec at redhat.com Tue Dec 16 02:41:15 2008 From: apevec at redhat.com (Alan Pevec) Date: Tue, 16 Dec 2008 03:41:15 +0100 Subject: [Ovirt-devel] [PATCH node] ovirt-config-storage autoinstall fixes In-Reply-To: <1229395277-31053-1-git-send-email-apevec@redhat.com> References: <1229395277-31053-1-git-send-email-apevec@redhat.com> Message-ID: <1229395277-31053-2-git-send-email-apevec@redhat.com> Use the drive selected by ovirt_init boot parameter ovirt_init=usb|scsi to select a local disk drive to create oVirt LVM volumes If ovirt_vol parameter is missing, default volume sizes are used: BOOT 50MB SWAP 2 * RAM size ROOT 256MB CONFIG 5MB LOGGING 256MB DATA rest of the disk equivalent is ovirt_vol=50::256:5:256 Cleanup lvms on selected disk Signed-off-by: Alan Pevec --- scripts/ovirt-config-storage | 64 +++++++++++++++++++++++++++--------------- 1 files changed, 41 insertions(+), 23 deletions(-) diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage index 5b1f7fc..89ba175 100755 --- a/scripts/ovirt-config-storage +++ b/scripts/ovirt-config-storage @@ -28,13 +28,25 @@ check_partition_sizes() # or just let the mke2fs failure suffice. } -# Find a usable/selected storage device along with its size in bytes. +get_selected_drive_size() +{ + local udi=$(hal-find-by-property --key block.device --string $DRIVE) + if [ -z "$udi" ]; then + warn "ERROR: selected storage device is not available" + return 1 + fi + size=$(hal-get-property --udi "$udi" --key storage.size) + SPACE=$(echo "scale=0; $size / (1024 * 1024)" | bc -l) + echo "selected device: $DRIVE ($SPACE MB)" +} + +# Find a usable/selected storage device. # If there are none, give a diagnostic and return nonzero. # If there is just one, e.g., /dev/sda, treat it as selected (see below). # and return 0. If there are two or more, make the user select one # or decline. Upon decline, return nonzero. Otherwise, print the -# selected name, a space, and its size, then return 0. -# Sample output: "/dev/sda 320072933376" +# selected name, then return 0. +# Sample output: /dev/sda get_dev_name() { local udi_list=$(hal-find-by-capability --capability storage) @@ -58,20 +70,16 @@ get_dev_name() *) warn "block device name $block_dev doesn't start with '/';" \ " skipping"; continue;; esac - size=$(hal-get-property --udi "$d" --key storage.size) test -z "$devices" \ && devices=$block_dev \ || devices="$devices $block_dev" - test -z "$sizes" \ - && sizes=$size \ - || sizes="$sizes $size" done # If there's only one device, use it. case $devices in '') warn "ERROR: found no usable block device"; return 1;; *' '*) ;; # found more than one - *) echo "$devices $sizes"; return 0;; # just one + *) echo "$devices"; return 0;; # just one esac # There are two or more; make the user choose. @@ -80,10 +88,7 @@ get_dev_name() do test "$device" = Abort && return 1 test -z "$device" && continue - # $REPLY is the selected number; - # use that to map to the corresponding size. - size=$(echo "$sizes"|cut -d' ' -f "$REPLY") - echo "$device $size" + echo "$device" return 0 done } @@ -91,13 +96,8 @@ get_dev_name() do_configure() { local name_and_size - name_and_size=$(get_dev_name) || exit 1 - set -- $name_and_size - DRIVE=$1 - local n_bytes=$2 - - SPACE=$(echo "scale=0; $n_bytes / (1024 * 1024)" | bc -l) - echo "selected device: $DRIVE ($SPACE MB)" + DRIVE=$(get_dev_name) || exit 1 + get_selected_drive_size for i in boot swap root config logging ; do uc=$(echo $i|tr '[[:lower:]]' '[[:upper:]]') @@ -145,6 +145,22 @@ The local disk will be repartitioned as follows: EOF } +# cleanup lvms on selected disk +# - remove mounted filesystems +# - remove LVM volumes and groups +wipe_lvm_on_disk() +{ + for vg in $(pvdisplay -c $DRIVE* 2>/dev/null|awk -F: '{print $2}'|sort -u); do + for d in $(grep $vg /proc/mounts|awk '{print $2}'); do + umount $d + done + for lv in $(lvdisplay -c $vg|awk -F: '{print $1}'); do + lvremove -f $lv + done + vgremove -f $vg + done +} + perform_partitioning() { if [ -z "$DRIVE" ]; then @@ -156,8 +172,7 @@ perform_partitioning() LOG=/var/log/ovirt-partition.log { - vgroups=$(vgdisplay -C | awk '{ print $1" "; }') - vgremove -f $vgroups + wipe_lvm_on_disk # Exit upon any failure. set -e @@ -269,10 +284,13 @@ ROOT_SIZE=${OVIRT_VOL_ROOT_SIZE:-$default_root_size} CONFIG_SIZE=${OVIRT_VOL_CONFIG_SIZE:-$default_config_size} LOGGING_SIZE=${OVIRT_VOL_LOGGING_SIZE:-$default_logging_size} +if [ -n "$OVIRT_INIT" ]; then + # if present, use the drive selected with 'ovirt_init' boot parameter + DRIVE=$OVIRT_INIT + get_selected_drive_size +fi if [ "$1" == "AUTO" ]; then - # In "AUTO" mode, OVIRT_INIT should be defined in the environment. - DRIVE=$OVIRT_INIT check_partition_sizes printf "Partitioning hard disk..." perform_partitioning -- 1.6.0.4 From apevec at redhat.com Tue Dec 16 02:41:16 2008 From: apevec at redhat.com (Alan Pevec) Date: Tue, 16 Dec 2008 03:41:16 +0100 Subject: [Ovirt-devel] [PATCH node] ovirt-config-boot - minimal installer for livecd image to local disk In-Reply-To: <1229395277-31053-1-git-send-email-apevec@redhat.com> References: <1229395277-31053-1-git-send-email-apevec@redhat.com> Message-ID: <1229395277-31053-3-git-send-email-apevec@redhat.com> LiveOS folder is copied to /dev/HostVG/Root LVM volume, kernel,initrd and GRUB are installed to /dev/HostVG/Boot partition. livecd initrd is modified on the fly to support LVM, which is not included in initramfs produced by mayflower/mkliveinitrd Example usage: ovirt-config-boot "$disk" /live "$bootparam1 $bootparam2" caller is responsible to issue reboot Signed-off-by: Alan Pevec --- Makefile.am | 1 + ovirt-node.spec.in | 5 ++ scripts/ovirt-config-boot | 122 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 0 deletions(-) create mode 100755 scripts/ovirt-config-boot diff --git a/Makefile.am b/Makefile.am index a47beaa..09ba56b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,6 +27,7 @@ EXTRA_DIST = \ scripts/collectd.conf.in \ scripts/ovirt \ scripts/ovirt-awake \ + scripts/ovirt-config-boot \ scripts/ovirt-config-logging \ scripts/ovirt-config-networking \ scripts/ovirt-config-password \ diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in index 50b2d18..c634a58 100644 --- a/ovirt-node.spec.in +++ b/ovirt-node.spec.in @@ -36,6 +36,7 @@ Requires: bind-utils # qemu-img RPM. Requires: qemu-img Requires: nc +Requires: grub Requires: /usr/sbin/crond ExclusiveArch: %{ix86} x86_64 @@ -112,6 +113,7 @@ cd - %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/logrotate.d %{__install} -p -m0755 scripts/ovirt-awake %{buildroot}%{_sbindir} +%{__install} -p -m0755 scripts/ovirt-config-boot %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-logging %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-networking %{buildroot}%{_sbindir} %{__install} -p -m0755 scripts/ovirt-config-password %{buildroot}%{_sbindir} @@ -203,6 +205,8 @@ fi %files stateless %defattr(-,root,root,0755) +%{_sbindir}/ovirt-awake +%{_sbindir}/ovirt-config-boot %{_sbindir}/ovirt-config-logging %{_sbindir}/ovirt-config-networking %{_sbindir}/ovirt-config-password @@ -243,6 +247,7 @@ fi * Thu Dec 11 2008 Perry Myers - 0.96 - Subpackage stateful/stateless to separate out functionality for embedded Node and Node running as part of already installed OS +- ovirt-config-* setup scripts for standalone mode * Thu Sep 11 2008 Chris Lalancette - 0.92 0.7 - Add the ovirt-install- and ovirt-uninstall-node scripts, and refactor diff --git a/scripts/ovirt-config-boot b/scripts/ovirt-config-boot new file mode 100755 index 0000000..ad0aeb1 --- /dev/null +++ b/scripts/ovirt-config-boot @@ -0,0 +1,122 @@ +#!/bin/bash +# +# ovirt-config-boot - configure local boot disk partition + +# SYNOPSIS +# ovirt-config-boot livecd_path bootparams +# +# boot_disk - boot disk device e.g. /dev/sda +# +# livecd_path - where livecd media is mounted, +# parent of LiveOS and isolinux folders +# +# bootparams - extra boot parameters like console=... +# + +# Source functions library +. /etc/init.d/functions +. /etc/init.d/ovirt-functions + + +# local_boot_install livecd_path bootparams +# livecd_path -livecd media +# bootparams - extra boot parameters like console=... +# +# copy oVirt Node image to the local LVM /dev/HostVG +ovirt_boot_setup() { + local disk=$1 + local live=$2 + local bootparams=$3 + printf "installing oVirt Node image ... " + mount_boot + mount_liveos + # install oVirt Node image for local boot + if [ -e "$live/syslinux" ]; then + syslinux=syslinux + elif [ -e "$live/isolinux" ]; then + syslinux=isolinux + else + syslinux= + fi + rm -rf /boot/grub + rm -rf /liveos/LiveOS + mkdir -p /boot/grub + mkdir -p /liveos/LiveOS + cp -p $live/LiveOS/squashfs.img /liveos/LiveOS \ + && cp -p $live/$syslinux/vmlinuz0 /boot + rc=$? + if [ $rc -ne 0 ]; then + printf "image copy failed\n" + return $rc + fi + # append LVM support to the livecd initramfs + tmpdir=$(mktemp -d) + cd $tmpdir + gzip -dc $live/$syslinux/initrd0.img | + cpio -id init sbin/real-init 2> /dev/null + init_script=init + if [ -e sbin/real-init ]; then + # Fedora 10 mkliveinitrd + init_script=sbin/real-init + fi + sed -i '/^\/sbin\/udev.*settle/ a \echo Scanning logical volumes\ +lvm vgscan --ignorelockingfailure\ +echo Activating logical volumes\ +lvm vgchange -ay --ignorelockingfailure HostVG \ +' $init_script + # fix emergency shell + sed -i 's/^ bash$/ bash < \/dev\/console/' $init_script + # do not fail if device node already exists + sed -i 's/mknod.*$/& || :/' $init_script + mkdir -p bin + bit= + if [ -e /lib64 ]; then + bit=64 + fi + mkdir -p lib$bit + if [ -e /sbin/lvm.static ]; then + cp /sbin/lvm.static bin/lvm + else + cp /sbin/lvm bin + # lvm is not static in Fedora + cp /lib$bit/libreadline.so.5 /lib$bit/libncurses.so.5 lib$bit + fi + find $init_script bin/lvm lib$bit -type f | + cpio -H newc --quiet -o | + gzip -9 | + cat $live/$syslinux/initrd0.img - > /boot/initrd0.img + + cat > /boot/grub/grub.conf << EOF +default=0 +timeout=5 +hiddenmenu +title oVirt Node + root (hd0,0) + kernel /vmlinuz0 ro root=/dev/HostVG/Root roottypefs=ext3 liveimg $bootparams + initrd /initrd0.img +EOF + echo "(hd0) $disk" > /boot/grub/device.map + ( cd /usr/share/grub/*; cp -p stage? e2fs_stage1_5 /boot/grub ) + grub --device-map=/boot/grub/device.map > /dev/null < References: <1229395277-31053-1-git-send-email-apevec@redhat.com> Message-ID: <1229395277-31053-4-git-send-email-apevec@redhat.com> use LVM partitions created by o-c-storage use file bindmounts for persisted configs use optional /config from livecd image support for old and new udev versions add BOOTIF=link|eth* support Signed-off-by: Alan Pevec --- scripts/ovirt | 22 --- scripts/ovirt-early | 391 ++++++++++++++++------------------------------- scripts/ovirt-firstboot | 41 +++++- scripts/ovirt-functions | 204 +++++++++++++++++++------ 4 files changed, 329 insertions(+), 329 deletions(-) mode change 100644 => 100755 scripts/ovirt mode change 100644 => 100755 scripts/ovirt-post diff --git a/scripts/ovirt b/scripts/ovirt old mode 100644 new mode 100755 index 81733a5..e2c406b --- a/scripts/ovirt +++ b/scripts/ovirt @@ -11,28 +11,6 @@ . /etc/init.d/ovirt-functions start() { - # retrieve config from local OVIRT partition if available - ovirt=$(mktemp -d) - ovirt_mount $ovirt - # /config on OVIRT partition contains persisted /etc files - cfg=$ovirt/config - if [ -d $cfg/etc ]; then - cp -rv $cfg/etc/* /etc - restorecon -r /etc - fi - # and optional Augeas augtool script - aug=$cfg/config.aug - if [ -f $aug ]; then - tmpaug=$(mktemp) - cp $aug $tmpaug - echo "save" >> $tmpaug - augtool < $tmpaug > /dev/null 2>&1 - if [ $? -eq 0 ]; then - printf "$aug applied." - fi - fi - umount $ovirt && rmdir $ovirt - if is_standalone; then exit 0 fi diff --git a/scripts/ovirt-early b/scripts/ovirt-early index c09a987..8bf8928 100755 --- a/scripts/ovirt-early +++ b/scripts/ovirt-early @@ -10,8 +10,6 @@ . /etc/init.d/functions . /etc/init.d/ovirt-functions -# size of the oVirt partition in megabytes -OVIRT_SIZE=64 BONDING_MODCONF_FILE=/etc/modprobe.d/bonding AUGTOOL_CONFIG=/var/tmp/augtool-config @@ -48,12 +46,15 @@ configure_from_network() { ovirt-process-config $cfgdb $BONDING_MODCONF_FILE $AUGTOOL_CONFIG if [ -f $AUGTOOL_CONFIG ]; then echo "Loading remote config" + # avoid bindmount issues with augeas + umount_config /etc/sysconfig/network-scripts/ifcfg-eth* augtool < $AUGTOOL_CONFIG \ && echo "Remote config applied" \ || echo "Failed applying remote config" fi if ls /etc/sysconfig/network-scripts/ifcfg-eth* > /dev/null 2>&1; then echo "Network interfaces created from remote config" + ovirt_store_config /etc/sysconfig/network-scripts/ifcfg-eth* return else echo "Remote config contained no network interfaces" @@ -61,6 +62,7 @@ configure_from_network() { else echo "Failed to retrieve configuration bundle" fi + rm $cfgdb fi fi fi @@ -80,14 +82,29 @@ configure_from_network() { echo "Default config applied" } -# find_disk $bus $serial $live_disk +# $(get_live_disk) +# livecd boot disk +get_live_disk() { + local live_dev=/dev/live + if [ ! -e $live_dev ]; then + # PXE boot + live_dev=/dev/loop0 + live_disk= + else + live_part=$(readlink -e $live_dev) + live_disk=$(basename $(dirname $(udev_info $live_part path))) + fi + echo $live_disk +} + +# find_disk $bus $serial find_disk() { local bus=$1 local serial=$2 - local live=$3 + local live=$(get_live_disk) for d in /dev/disk/by-id/{scsi,usb}*; do ID_FS_USAGE= - eval $(udevinfo --query env --name $d) + eval $(udev_info $d env) # ID_FS_USAGE is set for partitions if [ -z "$ID_FS_USAGE" -a "$ID_BUS" = "$bus" ]; then if [ -z "$serial" -o "$ID_SERIAL" = "$serial" ]; then @@ -104,216 +121,10 @@ find_disk() { return 1 } -# TODO move to ovirt-config-storage -# local_install $local_boot $local_disk $bootparams -# local_boot - 1=install LiveOS and boot loader -# 0=initialize oVirt partition only -# local_disk - local disk to hold the oVirt partition -# =usb|scsi[:serial#] -# bootparams - extra boot parameters like console= -# -# oVirt partition is a local primary ext2 partition, labeled OVIRT -# content: -# /config - local oVirt configuration (ktab, local admin password) -# /boot - boot loader, kernel and initramfs -# /LiveOS - oVirt Node compressed livecd image - -local_install() { - local local_boot=$1 - local local_disk=$2 - local bootparams=$3 - local disk - local part - local live_part - local live_disk - local live_dev=/dev/live - if [ ! -e $live_dev ]; then - # PXE boot - live_dev=/dev/loop0 - live_part=$live_dev - live_disk= - else - live_part=$(readlink -e $live_dev) - live_disk=${live_disk%[1-9]} - fi - local ovirt_part=$(readlink -e /dev/disk/by-label/$OVIRT_LABEL) - local ovirt_disk=${ovirt_part%[1-9]} - if [ "$ovirt_disk" = "$ovirt_part" ]; then - ovirt_disk= - fi - if [ -z "$local_disk" ]; then - if [ -z "$ovirt_disk" ]; then - return 1 - fi - # ovirt_init not specified, use pre-labeled oVirt partition - mode=update - disk=$ovirt_disk - part=$ovirt_part - else - case "$local_disk" in - =) - # empty ovirt_init, use current live image device - mode=update - disk=$live_disk - part=$live_part - ;; - =scsi*) - bus=scsi - serial=${local_disk#=scsi:} - mode=install - ;; - =usb*) - bus=usb - serial=${local_disk#=usb:} - mode=install - ;; - *) - return 1 - ;; - esac - if [ $mode = "install" ]; then - if [ "$serial" = "=$bus" ]; then - serial= - fi - disk=$(find_disk $bus $serial $live_disk) - rc=$? - if [ $rc -ne 0 ]; then - echo "local disk '$local_disk' not available" - return 1 - fi - if [ -n "$ovirt_disk" ]; then - if [ "$disk" = "$ovirt_disk" ]; then - # local disk contains oVirt partition, select it for update - # TODO force reinstall option - mode=update - part=$ovirt_part - else - # remove label from oVirt partition, there can be only one - e2label $ovirt_part "" - fi - fi - fi - if [ "$mode" = "install" ]; then - printf "installing $disk..." | tee /dev/console - dd if=/dev/zero bs=4096 count=1 of=$disk \ - && parted -s $disk mklabel msdos \ - && parted -s $disk mkpart primary ext2 0.0 $OVIRT_SIZE \ - && partprobe -s $disk - if [ $? -ne 0 ]; then - echo "$disk partition creation failed"; return 1 - fi - part=${disk}1 - udevsettle - mkfs.ext2 -L $OVIRT_LABEL $part \ - && tune2fs -c0 -i0 $part - if [ $? -ne 0 ]; then - echo "$disk ext2 creation failed"; return 1 - fi - # update by-label link manually, mkfs won't trigger udev - mkdir -p /dev/disk/by-label - ln -sf $part /dev/disk/by-label/$OVIRT_LABEL - fi - fi - - if [ "$mode" = "update" ]; then - printf "updating $disk..." | tee /dev/console - fi - ovirt=$(mktemp -d) - if [ "$part" = "$live_part" ]; then - # ovirt_init w/o local disk specified - # setup /config on live disk, if writeable - # TODO mlabel/e2label (check fs2 type or just blindly try?) - mount -r $part $ovirt && mount -o remount,rw $ovirt \ - && mkdir -p $ovirt/config - umount $ovirt && rmdir $ovirt - return 0 - fi - live=$(mktemp -d) - mount -r $live_dev $live - if [ $? -ne 0 ]; then - echo "source image mount failed" - rmdir $live - return 1 - fi - mount $part $ovirt - if [ $? -ne 0 ]; then - echo "local disk mount failed" - umount $live && rmdir $live - rmdir $ovirt - return 1 - fi - mkdir -p $ovirt/config - # update local config using the one embedded in livecd image - # TODO admin tool for adding /config into livecd image - if [ -d $live/config ]; then - cp -rv $live/config/* $ovirt/config \ - || echo "config copy failed" - fi - - if [ $local_boot = 0 ]; then - # config update only, cleanup and continue booting - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - else - # install oVirt Node image for local boot - if [ -e "$live/syslinux" ]; then - syslinux=syslinux - elif [ -e "$live/isolinux" ]; then - syslinux=isolinux - else - syslinux= - fi - rm -rf $ovirt/boot - rm -rf $ovirt/LiveOS - mkdir -p $ovirt/boot/grub - mkdir -p $ovirt/LiveOS - cp -p $live/LiveOS/squashfs.img $ovirt/LiveOS \ - && cp -p $live/$syslinux/initrd0.img $ovirt/boot \ - && cp -p $live/$syslinux/vmlinuz0 $ovirt/boot - if [ $? -ne 0 ]; then - echo "image copy failed" - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - return 1 - fi - part_num=$(( ${part#$disk} - 1 )) - cat > $ovirt/boot/grub/grub.conf << EOF -default=0 -timeout=2 -hiddenmenu -title oVirt Node - root (hd0,$part_num) - kernel /boot/vmlinuz0 ro root=LABEL=OVIRT roottypefs=ext2 liveimg $bootparams - initrd /boot/initrd0.img -EOF - grub-install --root-directory=$ovirt $disk >&2 - if [ $? -ne 0 ]; then - echo "boot loader install failed" - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - return 1 - fi - # remove 1.5 stages we don't need - find $ovirt/boot/grub -name '*_stage1_5' ! -name e2fs_stage1_5 \ - -exec rm {} \; - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - # FIXME avoid reboot loops - # temp. workaround: sync and wait - sync; sync; sync - printf "oVirt local installation finished, press Enter to reboot." \ - > /dev/console - read key - if [ "$key" = "debug" ]; then - sh > /dev/console 2>&1 - fi - reboot - fi -} start() { # oVirt boot parameters - # BOOTIF= (appended by pxelinux) + # BOOTIF=link|eth*| (appended by pxelinux) # ovirt_init=usb|scsi[:serial#] # ovirt_vol=BOOT_MB:SWAP_MB:ROOT_MB:CONFIG_MB:LOGGING_MB # ovirt_local_boot @@ -324,11 +135,14 @@ start() { # syslog=server[:port] # TBD logrotate maxsize - # BOOTIF= (appended by pxelinux) + # BOOTIF=link|eth*| (appended by pxelinux) # network boot interface is assumed to be on management network where # oVirt Server is reachable - # IPAPPEND 2 in pxelinux.cfg appends MAC address of the booting node - # e.g. BOOTIF=01-00-16-3e-12-34-57 + # BOOTIF= e.g. BOOTIF=01-00-16-3e-12-34-57 + # PXELINUX option IPAPPEND 2 in pxelinux.cfg appends MAC address + # of the booting node + # BOOTIF=link - take first eth for which ethtool reports link + # BOOTIF=eth* e.g. BOOTIF=eth0 - use given interface bootif= # ovirt_init=usb|scsi[:serial#] @@ -337,23 +151,23 @@ start() { # serial# - select exact disk using serial number, as reported by # udev ID_SERIAL # e.g. ovirt_init=usb:Generic_STORAGE_DEVICE_0000145418-0:0 - ovirt_init= + init= # ovirt_vol=BOOT_MB:SWAP_MB:ROOT_MB:CONFIG_MB:LOGGING_MB # local partition sizes in GB - ovirt_vol_boot= - ovirt_vol_swap= - ovirt_vol_root= - ovirt_vol_config= - ovirt_vol_logging= + vol_boot_size= + vol_swap_size= + vol_root_size= + vol_config_size= + vol_logging_size= # ovirt_local_boot # install/update oVirt Node image on the local installation target disk - ovirt_local_boot=0 + local_boot=0 # ovirt_standalone # force oVirt Node standalone mode - ovirt_standalone=0 + standalone=0 # pxelinux format: ip=::: # anaconda format: ip= netmask= gateway= @@ -376,25 +190,65 @@ start() { for i in $(cat /proc/cmdline); do case $i in - BOOTIF=??-??-??-??-??-??-??) - i=${i#BOOTIF=??-} - bootif=$(grep -il $(echo $i|sed 's/-/:/g') /sys/class/net/eth*/address|rev|cut -d/ -f2|rev) + BOOTIF=*) + i=${i#BOOTIF=} + case "$i" in + eth*) + bootif=$i + ;; + link) + for eth in $(cd /sys/class/net; echo eth*); do + if ethtool $eth 2>/dev/null|grep -q "Link detected: yes" + then + bootif=$eth + break + fi + done + ;; + ??-??-??-??-??-??-??) + i=${i#??-} + bootif=$(grep -il $(echo $i|sed 's/-/:/g') /sys/class/net/eth*/address|rev|cut -d/ -f2|rev) + ;; + esac ;; ovirt_init*) - ovirt_init=${i#ovirt_init} - if [ -z "$ovirt_init" ]; then - ovirt_init='=' + i=${i#ovirt_init} + if [ -n "$i" ]; then + # resolve to disk device + case "$i" in + =scsi*) + bus=scsi + i=${i#=scsi} + serial=${i#:} + ;; + =usb*) + bus=usb + i=${i#=usb} + serial=${i#:} + ;; + *) + bus= + serial= + ;; + esac + if [ -n "$bus" ]; then + init=$(find_disk $bus $serial) + fi + else + # 'ovirt_init' without value: grab first disk + init=/dev/?da fi ;; ovirt_vol=*) i=${i#ovirt_vol=} - eval $(printf $i|awk -F: '{print "ovirt_vol_boot="$1; ovirt_vol_swap="$2; print "ovirt_vol_root="$3; print "ovirt_vol_config="$4; print "ovirt_vol_logging="$5;}') + eval $(printf $i|awk -F: '{print "vol_boot_size="$1; print "vol_swap_size="$2; print "vol_root_size="$3; print "vol_config_size="$4; print "vol_logging_size="$5;}') ;; ovirt_local_boot*) - ovirt_local_boot=1 + local_boot=1 ;; ovirt_standalone*) - ovirt_standalone=1 + standalone=1 + bootparams="$bootparams $i" ;; ip=*) i=${i#ip=} @@ -418,41 +272,63 @@ start() { ;; esac done - # save boot parameters as defaults for ovirt-config-* + if [ -z "$ip_netmask" ]; then ip_netmask=$netmask fi if [ -z "$ip_gateway" ]; then ip_gateway=$gateway fi + # save boot parameters as defaults for ovirt-config-* + params="bootif init vol_boot_size vol_swap_size vol_root_size vol_config_size vol_logging_size local_boot standalone ip_address ip_netmask ip_gateway ipv6 syslog_server syslog_port bootparams" + mount_config + if [ -e $OVIRT_DEFAULTS ]; then + echo "update ovirt defaults" + tmpaug=$(mktemp) + for p in $params; do + PARAM=$(uc $p) + value=$(ptr $p) + echo "set /files$OVIRT_DEFAULTS/OVIRT_$PARAM '\"$value\"'" \ + >> $tmpaug + done + echo "save" >> $tmpaug + # augtool on bindmounted files fails + umount_config $OVIRT_DEFAULTS + augtool < $tmpaug > /dev/null + ovirt_store_config $OVIRT_DEFAULTS + rm $tmpaug + else + echo "initial startup" + # dump all ovirt bootparams + mkdir -p $(dirname $OVIRT_DEFAULTS) + echo > $OVIRT_DEFAULTS + for p in $params; do + PARAM=$(uc $p) + echo "OVIRT_$PARAM='$(ptr $p)'" >> $OVIRT_DEFAULTS + done + ovirt_store_config $OVIRT_DEFAULTS + fi - cat > $OVIRT_DEFAULTS < /dev/null </dev/null | (read MD5 filename; echo $MD5) +} + +# return uppercase value +uc() { + echo $(echo $1|tr '[[:lower:]]' '[[:upper:]]') +} + +# return indirect value +# non-bashism for ${!var} +ptr() { + local v=$1 + eval "v=\$$v" + echo $v +} + +# mount livecd media +# e.g. CD /dev/sr0, USB /dev/sda1, +# PXE /dev/loop0 (loopback ISO) +mount_live() { + if grep -q " /live " /proc/mounts; then + return 0 + fi + local live_dev=/dev/live + if [ ! -e $live_dev ]; then + # PXE boot + live_dev=/dev/loop0 + fi + mkdir -p /live + mount $live_dev /live +} + +# mount boot partition +# boot loader + kernel + initrd +mount_boot() { + if grep -q " /boot " /proc/mounts; then + return 0 + fi + mkdir -p /boot + mount /dev/disk/by-label/BOOT /boot +} + +# mount liveos partition +# LiveOS/ +mount_liveos() { + if grep -q " /liveos " /proc/mounts; then + return 0 + fi + mkdir -p /liveos + mount /dev/HostVG/Root /liveos +} + +# mount config partition +# /config for persistance +mount_config() { + if grep -q " /config " /proc/mounts; then + return 0 + fi + mkdir -p /config + mount /dev/HostVG/Config /config + if grep -q " /config " /proc/mounts; then + # optional config embedded in the livecd image + if [ -e /live/config ]; then + cp -rv --update /live/config/* /config + fi + # bind mount all persisted configs to rootfs + for f in $(find /config -type f); do + target=${f#/config} + if grep -q " $target " /proc/mounts ; then + # skip if already bind-mounted + true + else + mkdir -p "$(dirname $target)" + touch "$target" + mount -n --bind $f "$target" + fi + done else - mount -r /dev/live $1 \ - || mount /dev/live $1 + # /config is not available + return 1 fi } -md5() { - md5sum $1 2>/dev/null | (read MD5 filename; echo $MD5) +# unmount bindmounted config files +# umount_config /etc/config /etc/config2 ... +# +# Use before running sed -i or augeas against the bindmounted file, +# Otherwise save fails: https://fedorahosted.org/augeas/ticket/32 +# After file is replaced, call ovirt_store_config /etc/config /etc/config2 ... +# to bindmount the config file again. +# +umount_config() { + if grep -q " /config " /proc/mounts; then + for f in "$@"; do + if grep -q " $f " /proc/mounts ; then + umount -n $f + # refresh rootfs copy + cp /config$f $f + fi + done + fi } -# persist configuration to /config on OVIRT partition +# persist configuration to /config # ovirt_store_config /etc/config /etc/config2 ... +# copy to /config and bind-mount back ovirt_store_config() { - ovirt=$(mktemp -d) - ovirt_mount $ovirt - cfg=$ovirt/config - rw=0 - printf "store config:" - for f in "$@"; do - # ignore non-/etc paths - if [ $f != ${f#/etc/} ]; then - # check if changed - if [ "$(md5 $f)" != "$(md5 $cfg$f)" ]; then - if [ $rw = 0 ]; then - mount -o remount,rw $ovirt - rw=1 - fi - mkdir -p $cfg$(dirname $f) - cp $f $cfg$f - printf " $f" - fi - fi - done - echo - umount $ovirt && rmdir $ovirt + if grep -q " /config " /proc/mounts; then + printf "storing to /config :" + for f in "$@"; do + printf " $f" + # skip if already bind-mounted + if grep -q " $f " /proc/mounts ; then + printf " already persisted\n" + else + mkdir -p /config$(dirname $f) + cp -a $f /config$f \ + && mount -n --bind /config$f $f \ + || printf " failed to persist\n" + fi + done + echo + else + printf "warning: persistent config storage not available\n" + fi +} + +# compat function to handle different udev versions +udev_info() { + local name=$1 + local query=$2 + local out + + # old udev command with shortopts + out=$(udevinfo -n $name -q $query) + rc=$? + if [ $rc -ne 0 ]; then + out=$(udevadm info --name=$name --query=$query) + rc=$? + fi + if [ $rc -eq 0 ]; then + echo $out + fi + return $rc } backup_file() { diff --git a/scripts/ovirt-post b/scripts/ovirt-post old mode 100644 new mode 100755 -- 1.6.0.4 From apevec at redhat.com Tue Dec 16 02:54:41 2008 From: apevec at redhat.com (Alan Pevec) Date: Tue, 16 Dec 2008 03:54:41 +0100 Subject: [Ovirt-devel] [PATCH node] refactor Node local disk usage In-Reply-To: <1229395277-31053-4-git-send-email-apevec@redhat.com> References: <1229395277-31053-4-git-send-email-apevec@redhat.com> Message-ID: <1229396081-9121-1-git-send-email-apevec@redhat.com> use LVM partitions created by o-c-storage use file bindmounts for persisted configs use optional /config from livecd image support for old and new udev versions add BOOTIF=link|eth* support Signed-off-by: Alan Pevec --- scripts/ovirt | 22 --- scripts/ovirt-early | 391 ++++++++++++++++------------------------------- scripts/ovirt-firstboot | 40 +++++- scripts/ovirt-functions | 204 +++++++++++++++++++------ 4 files changed, 328 insertions(+), 329 deletions(-) mode change 100644 => 100755 scripts/ovirt mode change 100644 => 100755 scripts/ovirt-post diff --git a/scripts/ovirt b/scripts/ovirt old mode 100644 new mode 100755 index 81733a5..e2c406b --- a/scripts/ovirt +++ b/scripts/ovirt @@ -11,28 +11,6 @@ . /etc/init.d/ovirt-functions start() { - # retrieve config from local OVIRT partition if available - ovirt=$(mktemp -d) - ovirt_mount $ovirt - # /config on OVIRT partition contains persisted /etc files - cfg=$ovirt/config - if [ -d $cfg/etc ]; then - cp -rv $cfg/etc/* /etc - restorecon -r /etc - fi - # and optional Augeas augtool script - aug=$cfg/config.aug - if [ -f $aug ]; then - tmpaug=$(mktemp) - cp $aug $tmpaug - echo "save" >> $tmpaug - augtool < $tmpaug > /dev/null 2>&1 - if [ $? -eq 0 ]; then - printf "$aug applied." - fi - fi - umount $ovirt && rmdir $ovirt - if is_standalone; then exit 0 fi diff --git a/scripts/ovirt-early b/scripts/ovirt-early index c09a987..8bf8928 100755 --- a/scripts/ovirt-early +++ b/scripts/ovirt-early @@ -10,8 +10,6 @@ . /etc/init.d/functions . /etc/init.d/ovirt-functions -# size of the oVirt partition in megabytes -OVIRT_SIZE=64 BONDING_MODCONF_FILE=/etc/modprobe.d/bonding AUGTOOL_CONFIG=/var/tmp/augtool-config @@ -48,12 +46,15 @@ configure_from_network() { ovirt-process-config $cfgdb $BONDING_MODCONF_FILE $AUGTOOL_CONFIG if [ -f $AUGTOOL_CONFIG ]; then echo "Loading remote config" + # avoid bindmount issues with augeas + umount_config /etc/sysconfig/network-scripts/ifcfg-eth* augtool < $AUGTOOL_CONFIG \ && echo "Remote config applied" \ || echo "Failed applying remote config" fi if ls /etc/sysconfig/network-scripts/ifcfg-eth* > /dev/null 2>&1; then echo "Network interfaces created from remote config" + ovirt_store_config /etc/sysconfig/network-scripts/ifcfg-eth* return else echo "Remote config contained no network interfaces" @@ -61,6 +62,7 @@ configure_from_network() { else echo "Failed to retrieve configuration bundle" fi + rm $cfgdb fi fi fi @@ -80,14 +82,29 @@ configure_from_network() { echo "Default config applied" } -# find_disk $bus $serial $live_disk +# $(get_live_disk) +# livecd boot disk +get_live_disk() { + local live_dev=/dev/live + if [ ! -e $live_dev ]; then + # PXE boot + live_dev=/dev/loop0 + live_disk= + else + live_part=$(readlink -e $live_dev) + live_disk=$(basename $(dirname $(udev_info $live_part path))) + fi + echo $live_disk +} + +# find_disk $bus $serial find_disk() { local bus=$1 local serial=$2 - local live=$3 + local live=$(get_live_disk) for d in /dev/disk/by-id/{scsi,usb}*; do ID_FS_USAGE= - eval $(udevinfo --query env --name $d) + eval $(udev_info $d env) # ID_FS_USAGE is set for partitions if [ -z "$ID_FS_USAGE" -a "$ID_BUS" = "$bus" ]; then if [ -z "$serial" -o "$ID_SERIAL" = "$serial" ]; then @@ -104,216 +121,10 @@ find_disk() { return 1 } -# TODO move to ovirt-config-storage -# local_install $local_boot $local_disk $bootparams -# local_boot - 1=install LiveOS and boot loader -# 0=initialize oVirt partition only -# local_disk - local disk to hold the oVirt partition -# =usb|scsi[:serial#] -# bootparams - extra boot parameters like console= -# -# oVirt partition is a local primary ext2 partition, labeled OVIRT -# content: -# /config - local oVirt configuration (ktab, local admin password) -# /boot - boot loader, kernel and initramfs -# /LiveOS - oVirt Node compressed livecd image - -local_install() { - local local_boot=$1 - local local_disk=$2 - local bootparams=$3 - local disk - local part - local live_part - local live_disk - local live_dev=/dev/live - if [ ! -e $live_dev ]; then - # PXE boot - live_dev=/dev/loop0 - live_part=$live_dev - live_disk= - else - live_part=$(readlink -e $live_dev) - live_disk=${live_disk%[1-9]} - fi - local ovirt_part=$(readlink -e /dev/disk/by-label/$OVIRT_LABEL) - local ovirt_disk=${ovirt_part%[1-9]} - if [ "$ovirt_disk" = "$ovirt_part" ]; then - ovirt_disk= - fi - if [ -z "$local_disk" ]; then - if [ -z "$ovirt_disk" ]; then - return 1 - fi - # ovirt_init not specified, use pre-labeled oVirt partition - mode=update - disk=$ovirt_disk - part=$ovirt_part - else - case "$local_disk" in - =) - # empty ovirt_init, use current live image device - mode=update - disk=$live_disk - part=$live_part - ;; - =scsi*) - bus=scsi - serial=${local_disk#=scsi:} - mode=install - ;; - =usb*) - bus=usb - serial=${local_disk#=usb:} - mode=install - ;; - *) - return 1 - ;; - esac - if [ $mode = "install" ]; then - if [ "$serial" = "=$bus" ]; then - serial= - fi - disk=$(find_disk $bus $serial $live_disk) - rc=$? - if [ $rc -ne 0 ]; then - echo "local disk '$local_disk' not available" - return 1 - fi - if [ -n "$ovirt_disk" ]; then - if [ "$disk" = "$ovirt_disk" ]; then - # local disk contains oVirt partition, select it for update - # TODO force reinstall option - mode=update - part=$ovirt_part - else - # remove label from oVirt partition, there can be only one - e2label $ovirt_part "" - fi - fi - fi - if [ "$mode" = "install" ]; then - printf "installing $disk..." | tee /dev/console - dd if=/dev/zero bs=4096 count=1 of=$disk \ - && parted -s $disk mklabel msdos \ - && parted -s $disk mkpart primary ext2 0.0 $OVIRT_SIZE \ - && partprobe -s $disk - if [ $? -ne 0 ]; then - echo "$disk partition creation failed"; return 1 - fi - part=${disk}1 - udevsettle - mkfs.ext2 -L $OVIRT_LABEL $part \ - && tune2fs -c0 -i0 $part - if [ $? -ne 0 ]; then - echo "$disk ext2 creation failed"; return 1 - fi - # update by-label link manually, mkfs won't trigger udev - mkdir -p /dev/disk/by-label - ln -sf $part /dev/disk/by-label/$OVIRT_LABEL - fi - fi - - if [ "$mode" = "update" ]; then - printf "updating $disk..." | tee /dev/console - fi - ovirt=$(mktemp -d) - if [ "$part" = "$live_part" ]; then - # ovirt_init w/o local disk specified - # setup /config on live disk, if writeable - # TODO mlabel/e2label (check fs2 type or just blindly try?) - mount -r $part $ovirt && mount -o remount,rw $ovirt \ - && mkdir -p $ovirt/config - umount $ovirt && rmdir $ovirt - return 0 - fi - live=$(mktemp -d) - mount -r $live_dev $live - if [ $? -ne 0 ]; then - echo "source image mount failed" - rmdir $live - return 1 - fi - mount $part $ovirt - if [ $? -ne 0 ]; then - echo "local disk mount failed" - umount $live && rmdir $live - rmdir $ovirt - return 1 - fi - mkdir -p $ovirt/config - # update local config using the one embedded in livecd image - # TODO admin tool for adding /config into livecd image - if [ -d $live/config ]; then - cp -rv $live/config/* $ovirt/config \ - || echo "config copy failed" - fi - - if [ $local_boot = 0 ]; then - # config update only, cleanup and continue booting - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - else - # install oVirt Node image for local boot - if [ -e "$live/syslinux" ]; then - syslinux=syslinux - elif [ -e "$live/isolinux" ]; then - syslinux=isolinux - else - syslinux= - fi - rm -rf $ovirt/boot - rm -rf $ovirt/LiveOS - mkdir -p $ovirt/boot/grub - mkdir -p $ovirt/LiveOS - cp -p $live/LiveOS/squashfs.img $ovirt/LiveOS \ - && cp -p $live/$syslinux/initrd0.img $ovirt/boot \ - && cp -p $live/$syslinux/vmlinuz0 $ovirt/boot - if [ $? -ne 0 ]; then - echo "image copy failed" - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - return 1 - fi - part_num=$(( ${part#$disk} - 1 )) - cat > $ovirt/boot/grub/grub.conf << EOF -default=0 -timeout=2 -hiddenmenu -title oVirt Node - root (hd0,$part_num) - kernel /boot/vmlinuz0 ro root=LABEL=OVIRT roottypefs=ext2 liveimg $bootparams - initrd /boot/initrd0.img -EOF - grub-install --root-directory=$ovirt $disk >&2 - if [ $? -ne 0 ]; then - echo "boot loader install failed" - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - return 1 - fi - # remove 1.5 stages we don't need - find $ovirt/boot/grub -name '*_stage1_5' ! -name e2fs_stage1_5 \ - -exec rm {} \; - umount $ovirt && rmdir $ovirt - umount $live && rmdir $live - # FIXME avoid reboot loops - # temp. workaround: sync and wait - sync; sync; sync - printf "oVirt local installation finished, press Enter to reboot." \ - > /dev/console - read key - if [ "$key" = "debug" ]; then - sh > /dev/console 2>&1 - fi - reboot - fi -} start() { # oVirt boot parameters - # BOOTIF= (appended by pxelinux) + # BOOTIF=link|eth*| (appended by pxelinux) # ovirt_init=usb|scsi[:serial#] # ovirt_vol=BOOT_MB:SWAP_MB:ROOT_MB:CONFIG_MB:LOGGING_MB # ovirt_local_boot @@ -324,11 +135,14 @@ start() { # syslog=server[:port] # TBD logrotate maxsize - # BOOTIF= (appended by pxelinux) + # BOOTIF=link|eth*| (appended by pxelinux) # network boot interface is assumed to be on management network where # oVirt Server is reachable - # IPAPPEND 2 in pxelinux.cfg appends MAC address of the booting node - # e.g. BOOTIF=01-00-16-3e-12-34-57 + # BOOTIF= e.g. BOOTIF=01-00-16-3e-12-34-57 + # PXELINUX option IPAPPEND 2 in pxelinux.cfg appends MAC address + # of the booting node + # BOOTIF=link - take first eth for which ethtool reports link + # BOOTIF=eth* e.g. BOOTIF=eth0 - use given interface bootif= # ovirt_init=usb|scsi[:serial#] @@ -337,23 +151,23 @@ start() { # serial# - select exact disk using serial number, as reported by # udev ID_SERIAL # e.g. ovirt_init=usb:Generic_STORAGE_DEVICE_0000145418-0:0 - ovirt_init= + init= # ovirt_vol=BOOT_MB:SWAP_MB:ROOT_MB:CONFIG_MB:LOGGING_MB # local partition sizes in GB - ovirt_vol_boot= - ovirt_vol_swap= - ovirt_vol_root= - ovirt_vol_config= - ovirt_vol_logging= + vol_boot_size= + vol_swap_size= + vol_root_size= + vol_config_size= + vol_logging_size= # ovirt_local_boot # install/update oVirt Node image on the local installation target disk - ovirt_local_boot=0 + local_boot=0 # ovirt_standalone # force oVirt Node standalone mode - ovirt_standalone=0 + standalone=0 # pxelinux format: ip=::: # anaconda format: ip= netmask= gateway= @@ -376,25 +190,65 @@ start() { for i in $(cat /proc/cmdline); do case $i in - BOOTIF=??-??-??-??-??-??-??) - i=${i#BOOTIF=??-} - bootif=$(grep -il $(echo $i|sed 's/-/:/g') /sys/class/net/eth*/address|rev|cut -d/ -f2|rev) + BOOTIF=*) + i=${i#BOOTIF=} + case "$i" in + eth*) + bootif=$i + ;; + link) + for eth in $(cd /sys/class/net; echo eth*); do + if ethtool $eth 2>/dev/null|grep -q "Link detected: yes" + then + bootif=$eth + break + fi + done + ;; + ??-??-??-??-??-??-??) + i=${i#??-} + bootif=$(grep -il $(echo $i|sed 's/-/:/g') /sys/class/net/eth*/address|rev|cut -d/ -f2|rev) + ;; + esac ;; ovirt_init*) - ovirt_init=${i#ovirt_init} - if [ -z "$ovirt_init" ]; then - ovirt_init='=' + i=${i#ovirt_init} + if [ -n "$i" ]; then + # resolve to disk device + case "$i" in + =scsi*) + bus=scsi + i=${i#=scsi} + serial=${i#:} + ;; + =usb*) + bus=usb + i=${i#=usb} + serial=${i#:} + ;; + *) + bus= + serial= + ;; + esac + if [ -n "$bus" ]; then + init=$(find_disk $bus $serial) + fi + else + # 'ovirt_init' without value: grab first disk + init=/dev/?da fi ;; ovirt_vol=*) i=${i#ovirt_vol=} - eval $(printf $i|awk -F: '{print "ovirt_vol_boot="$1; ovirt_vol_swap="$2; print "ovirt_vol_root="$3; print "ovirt_vol_config="$4; print "ovirt_vol_logging="$5;}') + eval $(printf $i|awk -F: '{print "vol_boot_size="$1; print "vol_swap_size="$2; print "vol_root_size="$3; print "vol_config_size="$4; print "vol_logging_size="$5;}') ;; ovirt_local_boot*) - ovirt_local_boot=1 + local_boot=1 ;; ovirt_standalone*) - ovirt_standalone=1 + standalone=1 + bootparams="$bootparams $i" ;; ip=*) i=${i#ip=} @@ -418,41 +272,63 @@ start() { ;; esac done - # save boot parameters as defaults for ovirt-config-* + if [ -z "$ip_netmask" ]; then ip_netmask=$netmask fi if [ -z "$ip_gateway" ]; then ip_gateway=$gateway fi + # save boot parameters as defaults for ovirt-config-* + params="bootif init vol_boot_size vol_swap_size vol_root_size vol_config_size vol_logging_size local_boot standalone ip_address ip_netmask ip_gateway ipv6 syslog_server syslog_port bootparams" + mount_config + if [ -e $OVIRT_DEFAULTS ]; then + echo "update ovirt defaults" + tmpaug=$(mktemp) + for p in $params; do + PARAM=$(uc $p) + value=$(ptr $p) + echo "set /files$OVIRT_DEFAULTS/OVIRT_$PARAM '\"$value\"'" \ + >> $tmpaug + done + echo "save" >> $tmpaug + # augtool on bindmounted files fails + umount_config $OVIRT_DEFAULTS + augtool < $tmpaug > /dev/null + ovirt_store_config $OVIRT_DEFAULTS + rm $tmpaug + else + echo "initial startup" + # dump all ovirt bootparams + mkdir -p $(dirname $OVIRT_DEFAULTS) + echo > $OVIRT_DEFAULTS + for p in $params; do + PARAM=$(uc $p) + echo "OVIRT_$PARAM='$(ptr $p)'" >> $OVIRT_DEFAULTS + done + ovirt_store_config $OVIRT_DEFAULTS + fi - cat > $OVIRT_DEFAULTS < /dev/null </dev/null | (read MD5 filename; echo $MD5) +} + +# return uppercase value +uc() { + echo $(echo $1|tr '[[:lower:]]' '[[:upper:]]') +} + +# return indirect value +# non-bashism for ${!var} +ptr() { + local v=$1 + eval "v=\$$v" + echo $v +} + +# mount livecd media +# e.g. CD /dev/sr0, USB /dev/sda1, +# PXE /dev/loop0 (loopback ISO) +mount_live() { + if grep -q " /live " /proc/mounts; then + return 0 + fi + local live_dev=/dev/live + if [ ! -e $live_dev ]; then + # PXE boot + live_dev=/dev/loop0 + fi + mkdir -p /live + mount $live_dev /live +} + +# mount boot partition +# boot loader + kernel + initrd +mount_boot() { + if grep -q " /boot " /proc/mounts; then + return 0 + fi + mkdir -p /boot + mount /dev/disk/by-label/BOOT /boot +} + +# mount liveos partition +# LiveOS/ +mount_liveos() { + if grep -q " /liveos " /proc/mounts; then + return 0 + fi + mkdir -p /liveos + mount /dev/HostVG/Root /liveos +} + +# mount config partition +# /config for persistance +mount_config() { + if grep -q " /config " /proc/mounts; then + return 0 + fi + mkdir -p /config + mount /dev/HostVG/Config /config + if grep -q " /config " /proc/mounts; then + # optional config embedded in the livecd image + if [ -e /live/config ]; then + cp -rv --update /live/config/* /config + fi + # bind mount all persisted configs to rootfs + for f in $(find /config -type f); do + target=${f#/config} + if grep -q " $target " /proc/mounts ; then + # skip if already bind-mounted + true + else + mkdir -p "$(dirname $target)" + touch "$target" + mount -n --bind $f "$target" + fi + done else - mount -r /dev/live $1 \ - || mount /dev/live $1 + # /config is not available + return 1 fi } -md5() { - md5sum $1 2>/dev/null | (read MD5 filename; echo $MD5) +# unmount bindmounted config files +# umount_config /etc/config /etc/config2 ... +# +# Use before running sed -i or augeas against the bindmounted file, +# Otherwise save fails: https://fedorahosted.org/augeas/ticket/32 +# After file is replaced, call ovirt_store_config /etc/config /etc/config2 ... +# to bindmount the config file again. +# +umount_config() { + if grep -q " /config " /proc/mounts; then + for f in "$@"; do + if grep -q " $f " /proc/mounts ; then + umount -n $f + # refresh rootfs copy + cp /config$f $f + fi + done + fi } -# persist configuration to /config on OVIRT partition +# persist configuration to /config # ovirt_store_config /etc/config /etc/config2 ... +# copy to /config and bind-mount back ovirt_store_config() { - ovirt=$(mktemp -d) - ovirt_mount $ovirt - cfg=$ovirt/config - rw=0 - printf "store config:" - for f in "$@"; do - # ignore non-/etc paths - if [ $f != ${f#/etc/} ]; then - # check if changed - if [ "$(md5 $f)" != "$(md5 $cfg$f)" ]; then - if [ $rw = 0 ]; then - mount -o remount,rw $ovirt - rw=1 - fi - mkdir -p $cfg$(dirname $f) - cp $f $cfg$f - printf " $f" - fi - fi - done - echo - umount $ovirt && rmdir $ovirt + if grep -q " /config " /proc/mounts; then + printf "storing to /config :" + for f in "$@"; do + printf " $f" + # skip if already bind-mounted + if grep -q " $f " /proc/mounts ; then + printf " already persisted\n" + else + mkdir -p /config$(dirname $f) + cp -a $f /config$f \ + && mount -n --bind /config$f $f \ + || printf " failed to persist\n" + fi + done + echo + else + printf "warning: persistent config storage not available\n" + fi +} + +# compat function to handle different udev versions +udev_info() { + local name=$1 + local query=$2 + local out + + # old udev command with shortopts + out=$(udevinfo -n $name -q $query) + rc=$? + if [ $rc -ne 0 ]; then + out=$(udevadm info --name=$name --query=$query) + rc=$? + fi + if [ $rc -eq 0 ]; then + echo $out + fi + return $rc } backup_file() { diff --git a/scripts/ovirt-post b/scripts/ovirt-post old mode 100644 new mode 100755 -- 1.6.0.4 From halsaadi at thoughtworks.com Tue Dec 16 03:40:00 2008 From: halsaadi at thoughtworks.com (Hadi Al-Saadi) Date: Tue, 16 Dec 2008 09:10:00 +0530 Subject: [Ovirt-devel] help Message-ID: Dear perry, when im trying to load ISO image from localhost, after creating cobbler profile with the command cobbler image add --name=foo --file=/mnt/automnt/path/to/foo.iso --image-type=iso the profile create fine. no prolbmes, and i can see the ISO image from ovirt ui drop list and i can select it. when i try to start it, it giveing me error in ovirt ui task error descraption Call to function virStoragePoolCreate failed 2- when im trying to load ISO image from nfs from the localhost it self with the command cobbler image add --name=foo --file=nfs://user at host:/path/to/foo.iso --image-type=iso the comand create profile fine. and i can see the ISO image from ovirt uo drop list and i can select it but when im trying to start it it queued it for a while and after that it giveing me error in ovirt ui task error discraption Call to function virStoragePoolDefineXML failed when i give showmount -e localhost [root at management amd64]# showmount -e localhost Export list for localhost: /iso * /var/www/cobbler/ks_mirror/ubuntu-64 * /ovirtnfs 192.168.50.0/24 /cobblernfs 192.168.50.0/24 [root at management amd64]# i can see the mount point where i put the iso and also i can mount the mount point in onthere system pls help me to load ISO image -Regards Hadi -------------- next part -------------- An HTML attachment was scrubbed... URL: From dpierce at redhat.com Tue Dec 16 13:03:12 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Tue, 16 Dec 2008 08:03:12 -0500 Subject: [Ovirt-devel] [PATCH node] Fixes some small issues with the ovirt-config-storage script. Message-ID: <1229432592-13124-1-git-send-email-dpierce@redhat.com> Wraps the vgremove call in a conditional that checks that any volume groups exist first. Signed-off-by: Darryl L. Pierce --- scripts/ovirt-config-storage | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage index e2ddec1..369989c 100755 --- a/scripts/ovirt-config-storage +++ b/scripts/ovirt-config-storage @@ -157,7 +157,7 @@ perform_partitioning() LOG=/var/log/ovirt-partition.log { vgroups=$(vgdisplay -C | awk '{ print $1" "; }') - vgremove -f $vgroups + if [ -n "$vgroups" ]; then vgremove -f $vgroups; fi # Exit upon any failure. set -e -- 1.6.0.4 From halsaadi at thoughtworks.com Tue Dec 16 13:51:33 2008 From: halsaadi at thoughtworks.com (Hadi Al-Saadi) Date: Tue, 16 Dec 2008 19:21:33 +0530 Subject: [Ovirt-devel] error while loading ISO image in ovirt ui Message-ID: Dear perry, when im trying to load ISO image from localhost, after creating cobbler profile with the command cobbler image add --name=foo --file=/mnt/automnt/path/to/foo.iso --image-type=iso the profile create fine. no prolbmes, and i can see the ISO image from ovirt ui drop list and i can select it. when i try to start it, it giveing me error in ovirt ui task error descraption Call to function virStoragePoolCreate failed 2- when im trying to load ISO image from nfs from the localhost it self with the command cobbler image add --name=foo --file=nfs://user at host:/path/to/foo.iso --image-type=iso the comand create profile fine. and i can see the ISO image from ovirt uo drop list and i can select it but when im trying to start it it queued it for a while and after that it giveing me error in ovirt ui task error discraption Call to function virStoragePoolDefineXML failed when i give showmount -e localhost [root at management amd64]# showmount -e localhost Export list for localhost: /iso * /var/www/cobbler/ks_mirror/ubuntu-64 * /ovirtnfs 192.168.50.0/24 /cobblernfs 192.168.50.0/24 [root at management amd64]# i can see the mount point where i put the iso and also i can mount the mount point in onthere system pls help me to load ISO image -Regards Hadi -------------- next part -------------- An HTML attachment was scrubbed... URL: From halsaadi at thoughtworks.com Tue Dec 16 15:55:00 2008 From: halsaadi at thoughtworks.com (Hadi Al-Saadi) Date: Tue, 16 Dec 2008 21:25:00 +0530 Subject: [Ovirt-devel] error while loading ISO image in ovirt ui Message-ID: Dear perry, pls look at problem,, im going to loas my job,, because of this.. pls sir i want to load ISO image so i can load windows or anything else, so we can test it and replase our vmware in office when im trying to load ISO image from localhost, after creating cobbler profile with the command cobbler image add --name=foo --file=/mnt/automnt/path/to/foo.iso --image-type=iso the profile create fine. no prolbmes, and i can see the ISO image from ovirt ui drop list and i can select it. when i try to start it, it giveing me error in ovirt ui task error descraption Call to function virStoragePoolCreate failed 2- when im trying to load ISO image from nfs from the localhost it self with the command cobbler image add --name=foo --file=nfs://user at host:/path/to/foo.iso --image-type=iso the comand create profile fine. and i can see the ISO image from ovirt uo drop list and i can select it but when im trying to start it it queued it for a while and after that it giveing me error in ovirt ui task error discraption Call to function virStoragePoolDefineXML failed when i give showmount -e localhost [root at management amd64]# showmount -e localhost Export list for localhost: /iso * /var/www/cobbler/ks_mirror/ubuntu-64 * /ovirtnfs 192.168.50.0/24 /cobblernfs 192.168.50.0/24 [root at management amd64]# i can see the mount point where i put the iso and also i can mount the mount point in onthere system pls help me to load ISO image -Regards Hadi -------------- next part -------------- An HTML attachment was scrubbed... URL: From bkearney at redhat.com Tue Dec 16 16:23:16 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Tue, 16 Dec 2008 11:23:16 -0500 Subject: [Ovirt-devel] [PATCH] make use of the user parameter for single execs instead of calling su- Message-ID: <1229444596-31252-1-git-send-email-bkearney@redhat.com> --- ace-ovirt/modules/ovirt/manifests/postgres.pp | 12 +++++++----- 1 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ace-ovirt/modules/ovirt/manifests/postgres.pp b/ace-ovirt/modules/ovirt/manifests/postgres.pp index 07d053d..1fb45a4 100644 --- a/ace-ovirt/modules/ovirt/manifests/postgres.pp +++ b/ace-ovirt/modules/ovirt/manifests/postgres.pp @@ -44,13 +44,15 @@ class postgres::bundled{ } single_exec {"create_ovirt_db": - command => "/bin/su - postgres -c '/usr/bin/createdb ovirt'", - require => [Exec[postgres_add_all_trust], Service[postgresql]] - } + command => "/usr/bin/createdb ovirt", + require => [Exec[postgres_add_all_trust], Service[postgresql]], + user => "postgres" + } single_exec {"create_ovirt_development_db": - command => "/bin/su - postgres -c '/usr/bin/createdb ovirt_development'", - require => [Exec[postgres_add_all_trust], Service[postgresql]] + command => "/usr/bin/createdb ovirt_development", + require => [Exec[postgres_add_all_trust], Service[postgresql]], + user => "postgres" } postgres_execute_command {"ovirt_db_create_role": -- 1.6.0.4 From pmyers at redhat.com Tue Dec 16 18:19:52 2008 From: pmyers at redhat.com (Perry Myers) Date: Tue, 16 Dec 2008 13:19:52 -0500 Subject: [Ovirt-devel] Re: error while loading ISO image in ovirt ui In-Reply-To: References: Message-ID: <4947F148.6020905@redhat.com> Hadi Al-Saadi wrote: > > Dear perry, > > pls look at problem,, im going to loas my job,, because of this.. pls > sir i want to load ISO image so i can load windows or anything else, so > we can test it and replase our vmware in office > > > when im trying to load ISO image from localhost, after creating cobbler > profile with the command > cobbler image add --name=foo --file=/mnt/automnt/path/to/foo.iso > --image-type=iso > the profile create fine. no prolbmes, and i can see the ISO image from > ovirt ui drop list and i can select it. > when i try to start it, it giveing me error in ovirt ui task > The problem is that there is a mismatch between the format that cobbler specifies for nfs servers in --file and what ovirt is expecting. What I am using is: cobbler image add --name=winxp --file=192.168.50.2:/cobblernfs/winxp.iso --image-type=iso With this syntax I was able to successfully boot a WinXP ISO to provision a new VM. I didn't go through the entire installation process, but it was able to boot the WinXP ISO and start the installation. On the Cobbler website it says to use the following syntax for --file argument: /cobblernfs/winxp.iso nfs://192.168.50.2:/cobblernfs/winxp.iso The former assumes that you already have the nfs share mounted. The latter would need to be parsed by the user to mount the nfs share (or koan would do this for you automatically if you were using it) It looks in oVirt we should interpret nfs://user at 192.168.50.2:/share/file.iso to work properly since that is the officially supported syntax for cobbler. Darryl, you worked on this piece, can you investigate this and make the appropriate changes? Hadi, for now use the workaround I describe above using the syntax: host:/dir/file for the --file parameter. Thanks, Perry From apevec at gmail.com Tue Dec 16 18:58:03 2008 From: apevec at gmail.com (Alan Pevec) Date: Tue, 16 Dec 2008 19:58:03 +0100 Subject: [Ovirt-devel] [PATCH node] Fixes some small issues with the ovirt-config-storage script. In-Reply-To: <1229432592-13124-1-git-send-email-dpierce@redhat.com> References: <1229432592-13124-1-git-send-email-dpierce@redhat.com> Message-ID: <2be7262f0812161058r6adb092bx9378643095e06b66@mail.gmail.com> please review [PATCH node] ovirt-config-storage autoinstall fixes there's wipe_lvm_on_disk() - which cleans up the disk more throughly From dpierce at redhat.com Tue Dec 16 20:14:37 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Tue, 16 Dec 2008 15:14:37 -0500 Subject: [Ovirt-devel] Re: error while loading ISO image in ovirt ui In-Reply-To: <4947F148.6020905@redhat.com> References: <4947F148.6020905@redhat.com> Message-ID: <20081216201437.GC18831@mcpierce-laptop.mcpierce.org> On Tue, Dec 16, 2008 at 01:19:52PM -0500, Perry Myers wrote: > Darryl, you worked on this piece, can you investigate this and make the > appropriate changes? > > Hadi, for now use the workaround I describe above using the syntax: > host:/dir/file for the --file parameter. Will do. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From bkearney at redhat.com Tue Dec 16 21:02:39 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Tue, 16 Dec 2008 16:02:39 -0500 Subject: [Ovirt-devel] Updated the documentation on the Appliance Configuration Engine Message-ID: <4948176F.1090000@redhat.com> Now that the Appliance Configuration Engine (ace) is in F9 and F10 the docs around using it got alot simpler. I updated them at the thincrust website. The most interesting change is that the examples page: http://www.thincrust.net/ace-examples.html Now provides the kickstart files directory. So, lets say you want to build the media wiki appliance. The steps for that are now: # yum install appliance-tools python-virtinst # wget http://www.thincrust.net/kickstarts/mediaWikiAppliance-f10.ks # appliance-creator -n mediaWiki --config mediaWikiAppliance-f10.ks # virt-image mediaWiki Hopefully this will help with the usage of the tools. Lemme know if you guys have questions or comments. -- bk From apevec at redhat.com Tue Dec 16 23:02:41 2008 From: apevec at redhat.com (Alan Pevec) Date: Wed, 17 Dec 2008 00:02:41 +0100 Subject: [Ovirt-devel] standalone mode fixups Message-ID: <1229468564-12836-1-git-send-email-apevec@redhat.com> [PATCH node] ovirt-node-selinux policy: bind-mount all files [PATCH node] select boot partition for grub [PATCH node] fix disk partitioning From apevec at redhat.com Tue Dec 16 23:02:42 2008 From: apevec at redhat.com (Alan Pevec) Date: Wed, 17 Dec 2008 00:02:42 +0100 Subject: [Ovirt-devel] [PATCH node] ovirt-node-selinux policy: bind-mount all files In-Reply-To: <1229468564-12836-1-git-send-email-apevec@redhat.com> References: <1229468564-12836-1-git-send-email-apevec@redhat.com> Message-ID: <1229468564-12836-2-git-send-email-apevec@redhat.com> default policy doesn't allow file types in security_file_type attribute to be mounted, e.g. shadow_t for /etc/shadow: allow $1 { file_type -security_file_type }:file mounton; This blocks file bind-mounts from /config partition for config files in that set. By allowing all file mounts, security risk is not really increased, for example /etc/shadow could be bypassed anyway by mounting /etc/passwd. --- ovirt-node-selinux.te | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/ovirt-node-selinux.te b/ovirt-node-selinux.te index a53d3de..327c231 100644 --- a/ovirt-node-selinux.te +++ b/ovirt-node-selinux.te @@ -1,8 +1,14 @@ module ovirt 1.0.0; require { type fixed_disk_device_t; + attribute file_type; + type mount_t; type qemu_t; class blk_file { ioctl getattr setattr read write }; + class file mounton; } # Give qemu_t access to any block device allow qemu_t fixed_disk_device_t:blk_file { ioctl getattr setattr read write }; +# allow any file to be bindmounted (for /config) +allow mount_t file_type:file mounton; + -- 1.6.0.4 From apevec at redhat.com Tue Dec 16 23:02:43 2008 From: apevec at redhat.com (Alan Pevec) Date: Wed, 17 Dec 2008 00:02:43 +0100 Subject: [Ovirt-devel] [PATCH node] select boot partition for grub In-Reply-To: <1229468564-12836-1-git-send-email-apevec@redhat.com> References: <1229468564-12836-1-git-send-email-apevec@redhat.com> Message-ID: <1229468564-12836-3-git-send-email-apevec@redhat.com> --- scripts/ovirt-config-boot | 12 ++++++++++-- 1 files changed, 10 insertions(+), 2 deletions(-) diff --git a/scripts/ovirt-config-boot b/scripts/ovirt-config-boot index ad0aeb1..9fa0144 100755 --- a/scripts/ovirt-config-boot +++ b/scripts/ovirt-config-boot @@ -29,6 +29,14 @@ ovirt_boot_setup() { local bootparams=$3 printf "installing oVirt Node image ... " mount_boot + # check that /boot mounted ok and find partition number for GRUB + BOOT=$(mount|awk '$3 == "/boot" {print $1}') + BOOT=$(( ${BOOT#$disk} - 1 )) + rc=$? + if [ $rc -ne 0 -o $BOOT -lt 0 ]; then + printf "boot partition not available\n" + return $rc + fi mount_liveos # install oVirt Node image for local boot if [ -e "$live/syslinux" ]; then @@ -91,14 +99,14 @@ default=0 timeout=5 hiddenmenu title oVirt Node - root (hd0,0) + root (hd0,$BOOT) kernel /vmlinuz0 ro root=/dev/HostVG/Root roottypefs=ext3 liveimg $bootparams initrd /initrd0.img EOF echo "(hd0) $disk" > /boot/grub/device.map ( cd /usr/share/grub/*; cp -p stage? e2fs_stage1_5 /boot/grub ) grub --device-map=/boot/grub/device.map > /dev/null < References: <1229468564-12836-1-git-send-email-apevec@redhat.com> Message-ID: <1229468564-12836-4-git-send-email-apevec@redhat.com> wipe disk more throughly ensure /boot is formated, otherwise gptsynce ignores it --- scripts/ovirt-config-storage | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage index 89ba175..ff2a3b2 100755 --- a/scripts/ovirt-config-storage +++ b/scripts/ovirt-config-storage @@ -178,7 +178,7 @@ perform_partitioning() set -e # FIXME: save a backup copy, just in case? - dd if=/dev/zero of=$DRIVE bs=1K count=1 + dd if=/dev/zero of=$DRIVE bs=1024K count=1 blockdev --rereadpt $DRIVE partprobe -s $DRIVE @@ -187,9 +187,11 @@ perform_partitioning() BOOT_SIZE=10 fi parted $DRIVE -s "mklabel gpt" - parted $DRIVE -s "mkpart primary ext2 0M ${BOOT_SIZE}M" + parted $DRIVE -s "mkpartfs primary ext2 0M ${BOOT_SIZE}M" parted $DRIVE -s "mkpart primary ext2 ${BOOT_SIZE}M ${SPACE}M" + parted $DRIVE -s "set 1 boot on" parted $DRIVE -s "set 2 lvm on" + parted $DRIVE -s "print" udevadm settle 2> /dev/null || udevsettle # sync GPT to the legacy MBR partitions gptsync $DRIVE -- 1.6.0.4 From apevec at gmail.com Wed Dec 17 06:44:39 2008 From: apevec at gmail.com (Alan Pevec) Date: Wed, 17 Dec 2008 07:44:39 +0100 Subject: [Ovirt-devel] Updated the documentation on the Appliance Configuration Engine In-Reply-To: <4948176F.1090000@redhat.com> References: <4948176F.1090000@redhat.com> Message-ID: <2be7262f0812162244h51207eefjce471c655a7347dc@mail.gmail.com> On Tue, Dec 16, 2008 at 10:02 PM, Bryan Kearney wrote: > http://www.thincrust.net/ace-examples.html # Sugar appliance Sugar desktop appliance, as seen on the OLPC. (Kickstart File) http://www.thincrust.net/kickstarts/sugarxo.ks is 404 There is also a JBoss appliance - jboxx, which is a very good appliance example, please link it from your page. One day I'd like to try ovirt rails webapp on jboss-rails :) From halsaadi at thoughtworks.com Wed Dec 17 08:56:49 2008 From: halsaadi at thoughtworks.com (Hadi Al-Saadi) Date: Wed, 17 Dec 2008 14:26:49 +0530 Subject: [Ovirt-devel] ISO image problem solved. Message-ID: Dear Perry, and support team of ovirt. Greeting. With the help of you guys and your support. We successfully loaded and install windows and ubuntu 32 bit and 64 bit both in the Host. And its up and running for Testing. For few Days tell we make it on-line previously, We were facing problem loading ubuntu, fedora, And Redhat. But now with this syntax . It solve. #cobbler image add --name=ubuntu32 --file=192.168.50.2:/cobblernfs/ubuntu-8.04.1-desktop-i386.iso --image-type=iso Thanks and warm Regards -Hadi -------------- next part -------------- An HTML attachment was scrubbed... URL: From halsaadi at thoughtworks.com Wed Dec 17 12:36:36 2008 From: halsaadi at thoughtworks.com (Hadi Al-Saadi) Date: Wed, 17 Dec 2008 18:06:36 +0530 Subject: [Ovirt-devel] port forwarding to ovirt-applance Message-ID: Dear all, when i done port forwarding from my LAN . To port 80 on the ovirt-applance to access ovirt ui, I'm ably to get username and password prompt but when i supply username and password, is coming back again asking username and password. not logging me in ovirt ui so what can be the problem ? thanks and Regards -Hadi -------------- next part -------------- An HTML attachment was scrubbed... URL: From apevec at gmail.com Wed Dec 17 13:07:04 2008 From: apevec at gmail.com (Alan Pevec) Date: Wed, 17 Dec 2008 14:07:04 +0100 Subject: [Ovirt-devel] port forwarding to ovirt-applance In-Reply-To: References: Message-ID: <2be7262f0812170507i6dab5d06l14ca6fd42a00bb34@mail.gmail.com> On Wed, Dec 17, 2008 at 1:36 PM, Hadi Al-Saadi wrote: > when i done port forwarding from my LAN . To port 80 on the ovirt-applance > to access ovirt ui, I'm ably to get username and password prompt but when i > supply username and password, is coming back again asking username and > password. not logging me in ovirt ui > > so what can be the problem ? Kerberos, what else? :) To tunnel successfully, please use Perry's ovirt-tunnel script (in ovirt-release.git/misc-scripts): http://git.et.redhat.com/?p=ovirt-release.git;a=blob;f=misc-scripts/ovirt-tunnel;hb=refs/heads/next which modifies /etc/hosts on the fly to fool that puppy... From bkearney at redhat.com Wed Dec 17 15:22:32 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Wed, 17 Dec 2008 10:22:32 -0500 Subject: [Ovirt-devel] Updated the documentation on the Appliance Configuration Engine In-Reply-To: <2be7262f0812162244h51207eefjce471c655a7347dc@mail.gmail.com> References: <4948176F.1090000@redhat.com> <2be7262f0812162244h51207eefjce471c655a7347dc@mail.gmail.com> Message-ID: <49491938.9070805@redhat.com> Alan Pevec wrote: > On Tue, Dec 16, 2008 at 10:02 PM, Bryan Kearney wrote: >> http://www.thincrust.net/ace-examples.html > > > # Sugar appliance Sugar desktop appliance, as seen on the OLPC. (Kickstart File) > > http://www.thincrust.net/kickstarts/sugarxo.ks is 404 > > There is also a JBoss appliance - jboxx, which is a very good > appliance example, please link it from your page. > One day I'd like to try ovirt rails webapp on jboss-rails :) Thank you. Fixed the link, and added the jboxx appliance instructions to the example page. -- bk From dpierce at redhat.com Wed Dec 17 18:51:39 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 17 Dec 2008 13:51:39 -0500 Subject: [Ovirt-devel] [PATCH server] Changed how taskomatic handles a Cobbler image record. Message-ID: <1229539899-27003-1-git-send-email-dpierce@redhat.com> It will now incrementally pull out the protocol, authentication details, hostname or ip address, export path and filename for the image record. Signed-off-by: Darryl L. Pierce --- src/task-omatic/task_vm.rb | 14 ++++++++++++-- 1 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/task-omatic/task_vm.rb b/src/task-omatic/task_vm.rb index 35d78f2..c187287 100644 --- a/src/task-omatic/task_vm.rb +++ b/src/task-omatic/task_vm.rb @@ -367,8 +367,18 @@ def start_vm(task) raise "Image #{vm.cobbler_name} not found in Cobbler server" unless details - ignored, ip_addr, export_path, filename = - details.file.split(/(.*):(.*)\/(.*)/) + # extract the components of the image filename + image_uri = details.file + protocol = auth = ip_addr = export_path = filename = "" + + protocol, image_uri = image_uri.split("://") if image_uri.include?("://") + auth, image_uri = image_uri.split("@") if image_uri.include?("@") + # it's ugly, but string.split returns an empty string as the first + # result here, so we'll just ignore it + ignored, ip_addr, image_uri = + image_uri.split(/^([^\/]+)(\/.*)/) unless image_uri =~ /^\// + ignored, export_path, filename = + image_uri.split(/^(.*)\/(.+)/) found = false -- 1.6.0.4 From jguiditt at redhat.com Wed Dec 17 19:13:08 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Wed, 17 Dec 2008 14:13:08 -0500 Subject: [Ovirt-devel] [PATCH] fix for bug 464282: delete permissions In-Reply-To: <1228508347-25949-1-git-send-email-sseago@redhat.com> References: <1228508347-25949-1-git-send-email-sseago@redhat.com> Message-ID: <1229541188.4167.11.camel@physical.priv.ovirt.org> On Fri, 2008-12-05 at 20:19 +0000, Scott Seago wrote: > Delete permissions now works -- had a conditional statement wrong in the controller action. > > Signed-off-by: Scott Seago > --- > src/app/controllers/permission_controller.rb | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > diff --git a/src/app/controllers/permission_controller.rb b/src/app/controllers/permission_controller.rb > index 5d3646d..813d9d9 100644 > --- a/src/app/controllers/permission_controller.rb > +++ b/src/app/controllers/permission_controller.rb > @@ -102,7 +102,7 @@ class PermissionController < ApplicationController > Permission.transaction do > permissions = Permission.find(:all, :conditions => "id in (#{permission_ids.join(', ')})") > permissions.each do |permission| > - permission.destroy unless permission.is_primary? > + permission.destroy if permission.is_primary? > end > end > render :json => { :object => "permission", :success => true, ACK, this works for me. From halsaadi at thoughtworks.com Thu Dec 18 08:19:24 2008 From: halsaadi at thoughtworks.com (Hadi Al-Saadi) Date: Thu, 18 Dec 2008 13:49:24 +0530 Subject: [Ovirt-devel] port forwarding Message-ID: HI, ssh tunnelling done fine, i can access ovirt wui from deferent LAN. but when i try to open console in wui ovirt from the browser it asking plug-in, that only run under linux not windows. what the solution for this to run that plug-in in my laptop, for support mozilla and microsoft explorer 7 -------------- next part -------------- An HTML attachment was scrubbed... URL: From pmyers at redhat.com Thu Dec 18 14:01:30 2008 From: pmyers at redhat.com (Perry Myers) Date: Thu, 18 Dec 2008 09:01:30 -0500 Subject: [Ovirt-devel] port forwarding In-Reply-To: References: Message-ID: <494A57BA.1050904@redhat.com> Hadi Al-Saadi wrote: > > HI, > > > ssh tunnelling done fine, i can access ovirt wui from deferent LAN. but > when i try to open console in wui ovirt from the browser it asking > plug-in, that only run under linux not windows. > what the solution for this to run that plug-in in my laptop, for support > mozilla and microsoft explorer 7 There are two plugins required for oVirt. The first is a flash plugin. I believe we've gotten things in the oVirt UI to work correctly with Adobe Flash 9 and 10. If you use version 10, you can use the x86_64 version if you have an x86_64 host OS. The second plugin is virt-viewer-plugin. Instructions for installing this are available at: http://ovirt.org/install-instructions.html This plugin allows you to use the "Open Console" link in the vm details pane. Note, this all works from Firefox 3 in Fedora 9 and 10 hosts. We don't yet support Internet Explorer or Firefox on Windows, though it is on our roadmap to get this supported. Perry From bkearney at redhat.com Thu Dec 18 17:11:54 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Thu, 18 Dec 2008 12:11:54 -0500 Subject: [Ovirt-devel] [PATCH] rakefile to build the ovirt rpm Message-ID: <1229620314-17548-1-git-send-email-bkearney@redhat.com> --- ace-ovirt.spec | 2 +- ace-ovirt/modules/ovirt/manifests/dns.pp | 21 ++++++++---- ace-ovirt/modules/ovirt/ovirt-installer | 4 ++- rakefile.rb | 53 ++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 rakefile.rb diff --git a/ace-ovirt.spec b/ace-ovirt.spec index 7c72962..451ce4b 100755 --- a/ace-ovirt.spec +++ b/ace-ovirt.spec @@ -44,7 +44,7 @@ install -d %{buildroot}/%{acehome} install -d %{buildroot}/%{ruby_sitelibdir} install -d %{buildroot}/%{_bindir} install -d %{buildroot}/%{_initrddir} -cp -pr %{pbuild}/modules %{buildroot}/%{acehome} +cp -pr %{pbuild}/ace-ovirt/modules %{buildroot}/%{acehome} diff --git a/ace-ovirt/modules/ovirt/manifests/dns.pp b/ace-ovirt/modules/ovirt/manifests/dns.pp index 8665b99..f6a82a5 100644 --- a/ace-ovirt/modules/ovirt/manifests/dns.pp +++ b/ace-ovirt/modules/ovirt/manifests/dns.pp @@ -18,8 +18,7 @@ # Author: Joey Boggs #-- - -define dns::bundled($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") { +define dns::common($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") { package {"dnsmasq": ensure => installed, @@ -45,10 +44,6 @@ define dns::bundled($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") require => [Single_exec["add_mgmt_server_to_etc_hosts"],Single_exec["set_hostname"]] } - single_exec {"add_mgmt_server_to_etc_hosts": - command => "/bin/echo $mgmt_ipaddr $ipa_host >> /etc/hosts", - notify => Service[dnsmasq] - } file_replacement {"dnsmasq_configdir": file => "/etc/dnsmasq.conf", @@ -63,7 +58,17 @@ define dns::bundled($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") } -class dns::remote { +define dns::bundled($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") { + + dns::common("setup": mgmt_ipaddr=>$mgmt_ipaddr, prov_ipaddr=>$prov_ipaddr, mgmt_dev=>$mgmt_dev, prov_dev=>$prov_dev) + + single_exec {"add_mgmt_server_to_etc_hosts": + command => "/bin/echo $mgmt_ipaddr $ipa_host >> /etc/hosts", + notify => Service[dnsmasq] + } +} + +define dns::remote($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") { # On the pxe server you will need to ensure that the # next server option points to the ip address of the tftp server @@ -81,4 +86,6 @@ class dns::remote { # Also A records must be present for each oVirt node. Without this they are unable # to determine their hostname and locate the management server. + dns::common("setup": mgmt_ipaddr=>$mgmt_ipaddr, prov_ipaddr=>$prov_ipaddr, mgmt_dev=>$mgmt_dev, prov_dev=>$prov_dev) + } diff --git a/ace-ovirt/modules/ovirt/ovirt-installer b/ace-ovirt/modules/ovirt/ovirt-installer index 7d7b9d8..902b916 100755 --- a/ace-ovirt/modules/ovirt/ovirt-installer +++ b/ace-ovirt/modules/ovirt/ovirt-installer @@ -123,16 +123,18 @@ mgmt_ipaddr= mgmt_ip.scan(/\s*inet addr:([\d.]+)/) prov_ip = `ifconfig #{prov_dev}` prov_ipaddr= prov_ip.scan(/\s*inet addr:([\d.]+)/) -if dns_servers == "n" config_file.write "# dns configuration\n" config_file.write "$mgmt_ipaddr = '#{mgmt_ipaddr}'\n" config_file.write "$prov_ipaddr = '#{prov_ipaddr}'\n" config_file.write "$ovirt_host = '#{ovirt_host}'\n" config_file.write "$ipa_host = '#{ipa_host}'\n\n" + +if dns_servers == "n" config_file.write "dns::bundled{setup: mgmt_ipaddr=> $mgmt_ipaddr, prov_ipaddr=> $prov_ipaddr, mgmt_dev => '#{mgmt_dev}', prov_dev => '#{prov_dev}'}\n\n" end if dns_servers == "y" +config_file.write "dns::remote{setup: mgmt_ipaddr=> $mgmt_ipaddr, prov_ipaddr=> $prov_ipaddr, mgmt_dev => '#{mgmt_dev}', prov_dev => '#{prov_dev}'}\n\n" host_lookup = Socket.getaddrinfo(ipa_host,nil) hostip = host_lookup[1][3] if hostip.to_s != mgmt_ipaddr.to_s diff --git a/rakefile.rb b/rakefile.rb new file mode 100644 index 0000000..a2fae18 --- /dev/null +++ b/rakefile.rb @@ -0,0 +1,53 @@ +# -*- ruby -*- +# Rakefile: build appliance configuration engine rpms +# +# Copyright (C) 2007 Red Hat, Inc. +# +# Distributed under the GNU Lesser General Public License v2.1 or later. +# See COPYING for details +# +# Bryan Kearney + +require 'rake/clean' +require 'rake/rdoctask' +require 'rake/testtask' +require 'rake/packagetask' + +ROOT_DIR = File::expand_path(".") +PKG_VERSION="0.0.94" +PACKAGE_DIR = ROOT_DIR + "/pkg" + +# +# Files to clean up +# + +CLEAN.include("**/*~","pkg") + + +# Packaging Tasks +# +Rake::PackageTask.new("ace-ovirt", PKG_VERSION) do |pkg| + pkg.need_tar_gz = true + pkg.package_files.include(Dir["ace-ovirt/**/*"]) +end + + +# +# Tasks to build the rpms +# + +# Set up the directories +task :rpm => [ :package ] do |t| + Dir["*.spec"].each do |specfile| + spec = File.basename(specfile) + cp(specfile, "pkg") + puts("Building with spec file #{spec}") + Dir::chdir("pkg") do |dir| + dir = File::expand_path(".") + system("rpmbuild --define '_topdir #{dir}' --define '_sourcedir #{dir}' --define '_srcrpmdir #{dir}' --define '_rpmdir #{dir}' --define '_builddir #{dir}' -ba #{spec} > #{spec}.rpmbuild.log 2>&1") + if $? != 0 + raise "rpmbuild failed" + end + end + end +end -- 1.6.0.4 From jguiditt at redhat.com Thu Dec 18 18:38:49 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Thu, 18 Dec 2008 13:38:49 -0500 Subject: [Ovirt-devel] [PATCH] fix for Bug 466719 In-Reply-To: <1229023014-4066-1-git-send-email-sseago@redhat.com> References: <1229023014-4066-1-git-send-email-sseago@redhat.com> Message-ID: <1229625529.4158.12.camel@physical.priv.ovirt.org> On Thu, 2008-12-11 at 19:16 +0000, Scott Seago wrote: > fix for Bug 466719: VM pool sort by load no longer causes server errors. It's still not doing anything useful yet, but that won't come until we update the stats code to aggregate something useful in the new pools load_average column. > > Signed-off-by: Scott Seago > --- > src/app/views/resources/_grid.rhtml | 2 +- > src/db/migrate/032_add_pool_load.rb | 28 ++++++++++++++++++++++++++++ > 2 files changed, 29 insertions(+), 1 deletions(-) > create mode 100644 src/db/migrate/032_add_pool_load.rb > > diff --git a/src/app/views/resources/_grid.rhtml b/src/app/views/resources/_grid.rhtml > index 908eac7..9b5e1c2 100644 > --- a/src/app/views/resources/_grid.rhtml > +++ b/src/app/views/resources/_grid.rhtml > @@ -15,7 +15,7 @@ > colModel : [ > {display: '', name : 'id', width : 20, sortable : false, align: 'left', process: <%= table_id %>checkbox}, > {display: 'Name', name : 'name', width : 160, sortable : true, align: 'left'}, > - {display: 'Load', name : 'load', width: 180, sortable : false, align: 'left', process: <%= table_id %>_load_widget } > + {display: 'Load', name : 'load_average', width: 180, sortable : false, align: 'left', process: <%= table_id %>_load_widget } > ], > sortname: "name", > sortorder: "asc", > diff --git a/src/db/migrate/032_add_pool_load.rb b/src/db/migrate/032_add_pool_load.rb > new file mode 100644 > index 0000000..fbb1b55 > --- /dev/null > +++ b/src/db/migrate/032_add_pool_load.rb > @@ -0,0 +1,28 @@ > +# > +# Copyright (C) 2008 Red Hat, Inc. > +# Written by Scott Seago > +# > +# This program is free software; you can redistribute it and/or modify > +# it under the terms of the GNU General Public License as published by > +# the Free Software Foundation; version 2 of the License. > +# > +# This program is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +# GNU General Public License for more details. > +# > +# You should have received a copy of the GNU General Public License > +# along with this program; if not, write to the Free Software > +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, > +# MA 02110-1301, USA. A copy of the GNU General Public License is > +# also available at http://www.gnu.org/copyleft/gpl.html. > + > +class AddPoolLoad < ActiveRecord::Migration > + def self.up > + add_column :pools, :load_average, :float > + end > + > + def self.down > + drop_column :pools, :load_average > + end > +end ACK From pmyers at redhat.com Thu Dec 18 21:34:44 2008 From: pmyers at redhat.com (Perry Myers) Date: Thu, 18 Dec 2008 16:34:44 -0500 Subject: [Ovirt-devel] [Patch] Add ovirt-node-logos package Message-ID: <1229636086-26978-1-git-send-email-pmyers@redhat.com> These patches add ovirt-node-logos to use the green splash screen instead of the blue Fedora splash. From pmyers at redhat.com Thu Dec 18 21:34:46 2008 From: pmyers at redhat.com (Perry Myers) Date: Thu, 18 Dec 2008 16:34:46 -0500 Subject: [Ovirt-devel] [PATCH node-image] Add ovirt-node-logos to package list In-Reply-To: <1229636086-26978-2-git-send-email-pmyers@redhat.com> References: <1229636086-26978-1-git-send-email-pmyers@redhat.com> <1229636086-26978-2-git-send-email-pmyers@redhat.com> Message-ID: <1229636086-26978-3-git-send-email-pmyers@redhat.com> Signed-off-by: Perry Myers --- common-pkgs.ks | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/common-pkgs.ks b/common-pkgs.ks index 2727b87..dd60930 100644 --- a/common-pkgs.ks +++ b/common-pkgs.ks @@ -11,6 +11,7 @@ openssh-server kvm ovirt-node-stateless ovirt-node-selinux +ovirt-node-logos -selinux-policy-targeted selinux-policy-minimum vim-minimal -- 1.6.0.4 From pmyers at redhat.com Thu Dec 18 21:34:45 2008 From: pmyers at redhat.com (Perry Myers) Date: Thu, 18 Dec 2008 16:34:45 -0500 Subject: [Ovirt-devel] [PATCH node] Add ovirt-node-logos to replace grub fedora boot splash with ovirt specific splash In-Reply-To: <1229636086-26978-1-git-send-email-pmyers@redhat.com> References: <1229636086-26978-1-git-send-email-pmyers@redhat.com> Message-ID: <1229636086-26978-2-git-send-email-pmyers@redhat.com> Signed-off-by: Perry Myers --- Makefile.am | 2 ++ images/grub-splash.xpm.gz | Bin 0 -> 51388 bytes images/syslinux-vesa-splash.jpg | Bin 0 -> 204721 bytes ovirt-node.spec.in | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 0 deletions(-) create mode 100644 images/grub-splash.xpm.gz create mode 100644 images/syslinux-vesa-splash.jpg diff --git a/Makefile.am b/Makefile.am index 09ba56b..37a6c19 100644 --- a/Makefile.am +++ b/Makefile.am @@ -23,6 +23,8 @@ EXTRA_DIST = \ ovirt-node.spec \ ovirt-node.spec.in \ ovirt-node-selinux.te \ + images/grub-splash.xpm.gz \ + images/syslinux-vesa-splash.jpg \ scripts/collectd \ scripts/collectd.conf.in \ scripts/ovirt \ diff --git a/images/grub-splash.xpm.gz b/images/grub-splash.xpm.gz new file mode 100644 index 0000000000000000000000000000000000000000..8cd25b89b37a8660067bdc5de4f84614d40880ec GIT binary patch literal 51388 zcmV)ZK&!tWiwFoYW0Ob#18;U|a&#?oaBN|7XfAkgZ2;Z4{FyT6GU*`YrU;UT=`k(&m|N5W*@}K{g|MY+SW&X?m_W%B0 z|BwIrKmV8i{r~Zw{>%UJKmULJ_y6br_5b#l^)LV5fAz2b@$dikFMt2<{`N0_{fEE& z^^{<>%aN at IDUToH~;ka|NgK4`1x`A{P_2O{fB at 2>%af} z`1t(z4}bd)fA?C0`cMDx&wu at opC8xbU;pu+{`xGSuu zpNngZ*U#Va`2FfN_|I?GI2`XM*LTOD1FfL#+sDU82H^os{vV!0?m%3DTlvZ%7+>o5 zSC~_*;ZMFizFC&HgR+Y at fGn=1{Mxq*LD&G}9Irdl;xGNIv;1oVbNg$6Yo2xp&hv3! zA#eZvMBpciCi~@2jW&Z?xe^FJ|L=Ab>VNSAF&M!5M%v4t3l`JMfxs>Z-~0;@?&wma zb$-oJhOsK^h9Of|U%;v0NN2=X6$ z)%db1FTF38H?SEUEo{O%YO$OQok?DX>|0zZhp%R2mF&^tgE1^Gkx5Ty4Z6ext) z0^LF?EcEwYwBEjh2lHPGi)-*9;CG-cUQmP^xLdRYgAwNyTo?qXm6%tvGu*k5h?@&N zIuDLoi-iZZ8EnE(;O8)uG936DhZ>1LtQPAX+CA3V)Fc`Sc9BT*f%ZO#y7D0q_Yr{m zXhTmyxbT)=u`6@{_84$wAzrO2XBY|+yDgv=)JJ>F_Q{lsDNCXH32H6P!yCD3owfMvSSbhVF at kcCHD*0Q5K9*$t6y at 1viGcIX zzl^*^J}vr=t`Lk!YCOAGhM_=I5=$jsycR1UXK>z%+8YQgh1dH(r9TBBCCRB60s5$f zqa;s-07->`z9}_*@zJ>NP$57dO7Pg|1&8f>^Pv90miZtU3o{aGfSi75HJE_w{sakv z2G2Oq_;1Pb*wimd^kTI-qYq7ALZXNepie-ztQm!-K??SQ2Io1xf>%=kabhc2e%Kb4 zm)QXr9pP~g?2!wjO&q4ALndhgM}eXdV#R_2$nVXARKRijk+{(6?}5wPCZVD*-V}cX zVuSpeP+WjO at Sy6Dg>Tv^UJxO=KjA)9Uwd!W;dzP1FZG0>M4}Qa4R$O-U=gsZ8bN`d zlAjf16UWm*f`j&hN_ at u)U?`ktcMSx7M;;{o5r8I6Xaq*{_pPf*#1XW+cLJmPG=jLk zVH4n!+ADSU&8iFlp5t##cdKyYQWxS at Q@Dd}v8K at AS37}g<4#DBFGY+rDlxc^wU`Jr zzMBT=0f(u`kewO_Da!y~4Z}(ae`gG4DH3Hk%i~&@q>|iZMKpg^@Arl|BU;#`aiaz& zA;MSmgf4!C|7tzF3IkFS+c0Di0;E at 6p>Vc8A;g(C`o$>=N;O7NW<7Q$lva>djF{7f z3xC7gV?sOl+bim?*wKR!Vk*UeU$Y(j4m?=*e^QAFL}?6 at 48AJK@AL_%BoTUNs3N%o zMiV4%Qi~p`k=QE1@@e&-brm at NR&AHhnwuFgga|*+0zUVpF&^omPksQu+8Z2|3J*H8 zG8|m^dG|?o2T(`U-zgYxdJMTPCmy69*yF+NyVYVtVR=oyU?A_C at m>pobf$Cn_m&bY zo^%B`lP9ezjH2u4vq{ON9(M4N7)_6u_-OQlYy??^(GXIBh%&BW2qy;aG+#S&Vi2Km z9_*M$LEU36-wgPNcsbBn7*MzmW0CAf_fYsfFjzn*E=-<|d;}|o5z{Tc-U{+Xp?DN# z)?N9~Da17uF08 at Xoqn4bj<>1`6Mno6)Ge*D+cO5|{9#sOX3oEY#Vm at 85C#$heseQN|_iN+&9u_%0C{ zps+=RNs)a13^FD at pg6Gm+fgX!JFtfrg_w$;v7#9Y>EkehX%bIEAf5o zs-)!%UK at jwQGn!a8q)gxty;WdK(cBRsB)xDfl-8YNFu`#jOb=f&9EXjd%+S_FjYKR zISvj~MZ(5#$KL$NF7<>$e8}Tn5KkQ%eAvK5aL5w<9c!^r-#5`B at MWqW0Pku>EJln9 z5OD;Fz>iB7G%6GzY7qwD8Zns$Ia(by7}B7w?ZCyLrd^=AF{{qx)^!!o^}N9emY{NB z&y``}En1`eO~3Vin&El`@E#K^nNTLvVFx}`i42q`f;FqdhQRH3`C~jtUz*ieK8gz? z^I`L38rU;S(5vwKgPP={(jqq+L1_YE2Ff%f^Iso$x%Ngl3k0}8jBrHKrNLR=XDP-d zo3L6d800v0`$55<3`wd&{E5HcIB&oC;7=yF0;RGTqXapo(3#U18mM7m`lK^j3 z7nr<3ufbqKl;|D{QW#f1?;yag9eBcpMuA$3mGk;lI1S~>kBE_6gg?Qi4sp)LKGQoc`72!05IQ$Y1MkVGbqyUbc;rj;uRFH5g7sA+#>Y%`-Cc?smticjs zMemmfCB$Niu7U?=p}%@ef_ at NcID~P~-Ly-QswLcsFyu%Ki(L*sMo}W7PFj6nNa8=t zgYLMv6_Yh_!QTx<+=%L{^YUTSklS92yjIS%UotQ5RbwT=@(rLS&a}|sEJUaiVwsGH zD=iSDJ5$f+7*K^P6UaMX9}#y(J?W{UL9f6EC5{-|xkz!01{LpUj42GW9`cN8lTLx at +8-{rMXFujhghm`p-z{z!Xke8f#b75uRrU;XJKS!i-J({zxk{I32FwC<{&0#bc$0 zcTOD89hOgzkwl1b$uOWXysE*83x5X&KL9`hB615KToj=sv60;g8%7;Y1z2fNz3H!t z5^V;>hLOJT?QD1s#8s-WhZFcop$9>XYI}T6fx$ePOa9<$AdCsgG9CANv?p9hgysYO2DRU~PRMUbp7grPb_n`HBCtxwBx{GlzVIriV3GvW5qi>?+|8{{5HmWdz1j?l79kNbFf;Yj`#0P{#1qV) zIdWQuLbf{mm`shRLK%Eitmw-r>eDI7Z~fr!os;+mv1(y_P;2JW610z{Ajj at -lEmP_ zuax3yN at o;kA|i*U z&AbeR at EqM?$YE&*4?l1Y(5WnbSRoz~2nPz{3m|S`4Gv%L2VIUxTtP;6AI^U&h|e+# z^6 at R^OqL`vFaAAKIvJF3N}`hFMjc)Se=Nvr)+WugjJAU_5Qxf*uNpQ@)ewprNjPk$ zR_#Mc35qRf+ni-+r_CSPa1cgxQ|1zUO*sCpTFiNHbcSgtVgRhInI;hBB#)2SqpQ}H zKE7OleT7LP`{o5+s$tt1$+CEjlANr;7W`~BqCD85J=ihSC3==ZV9~+}O%y(68Zk!| z{`_JmyU(xo8wcPHr_vBULL0Z`a14wK2i{P`TX5m;&?F*2NPU4jo0D|oS>F_QH4K#k zKVokrphy_rM4~KoE>@1;hclz9_<-XbAg-w~1QRkoIBR|o0NiCt_5n3I$Uab7!&HGC zdn$-EH|-#tl?!orLXjbetwM|h6o)x_!@;`2mMyar;X?{?2ZS5j!7vDa->j~H?n7>J zQ2*PlZqUZVAJ!SZqZrc}6gvExB0-88#!SPDxpD;)>XJ3MEX12QgH>=)`#>qdo=dQ- zj8Yev*vN->(jF(Ry^mg6br!{WFP{`Qzs9hP%Gh`(H#H at qLc;P07} zcM~!MstT)^tCvMi+5~B1w*$2boZP=|`}kY!esE#iVY)3lZ2a#ZV+) z;EM(jHwO*Q>Q!4U zCJh=8XT3{GxJKVfciK!D#8>k!r!gUB#0J2izRBPxGhwZ~CPt9oAFnd|YRYVpn)xyh zYF4X?PFp(|Huc>JiB5%mHuBLz;1`$>-e6i|s`p2(E|6YRl&tdM^s4G`_GQ=-3INyW z1Sf-E+?|ezL4ZMvEXwK+9{7tMPW{-G{Yb8Yy3nV7Fj$eBGk1dI;?@omgR1*GZNU&F zUW{izPe3>^MUB*!4 at dGMU0E#|k2dj9q%bk)6&cbvT*LkU&r}AJ%UBFCZG8eOv1`t1VNN4krRE)oLvFdUpm!`wln{*x*6iK|SB1obij44S* zA=oh1ncCf;Nn$5J(IGOZi_?FbHCPJqEco*ReAs~Vn6IeAjda40!Iw307lwf1_H|A2 zEjNCufvHL=Rb1il?f2{jy)SeGzO@!#hh>xoWkw7dl<@76b*>ip27&um_P^4P9c`8&G(E`+d^((6M+8!1O7vv&${$u!luCOJPk&j8eQd z_t{fJNEw2Jbp9a>MHed(g8Tf8BUIj=B!NN08L>2iiT?%)WXj`dH14BOI5-!c15oa^ zuVD~4ETGeTOlChr;WYr?4!w_hcjTktO5c?wJ{jRcyADQf at F2H}D-v9EuQQ!7ShnXf z0YVq2;YfmGP at qyH{b^Zg4^dLpVhd>n3Xes)XawhDl`b^!6p3j)eVS#MOsX9n)HIfC)a&?-8?^SyQ;FSUX- z^(`pIb#z}`>9x&+hPhQ~@DpbeoG$&}amTn;8k39-EKa&sj9NUEk%*pdGzj+0nUV4f z0rJJ90vf{G{$REQYb9J;)WL(@xJ<^MCuRhO^k!~eDutB*Ax6?3-30^2OPdDQbzK~Y zJ%3PE>E>ioCj^QV4j8VQQ;5+BI>FOZJ$TxnDPGvq0mDy2W)2Yy21IDpB?-O|F4T{8 za(Vy-ZrT+7hQj+i`0bmcE^I>MK(z at k;P)0T4D at wV(`pdjgP*m5noVFV;dDONu|&p3VNi19BbtT+R~%WNFa-;izjm7e%9rrtzhNA zcwn_MWA4aeg7GW5_`}KY<6EN`H_`VkBk%1WiN0<}_$3x(K!Ny!3^rM^(5gN|pY(w` z6_I=R(J>xw65&iDWOzEQkF1&h+ at apVw-)5B%OP16J2 at 694o#q=)Vh z3m!3>Lkrli$3cT&!7YGzPm}0AJAo*HRiZ5=WG*^F|HMgMs>E+{;oWUcgCf~a2E}*C z&$9{(vA0C|r8Nx-T-G`H(=r-yFR=VecBe^$>%6l50)?^7K3QC=0lyO4S5hoh7>7)E zP&h=BI39Z=M`~eWsYSs}p7bb~?6aWr;H_Hxp_udG2)!Ay9}`;_*E`c-d1(rgFKA*J z5Q{OWIR!1vmn^8Fq%fg|w#a)Wsu162ELuIb)uqauHenp-<6Xq~yK${D5TP$9gAth* zO93|Qu?8QvDMNky(_>7Kyojx49u#?eSCbHqsrVuqW7bSueIz!wM^bj*UFqBCdm};Z zM{M!k)kp`3wm-7Ui)IvHQy(w$(x5?KpUXU`x&wqv{65q`9w2K0Zi-Nfv+eCNO~6gI{Bl&Vn*lkkuZ% zLxPI{Fg}U6Z45GMo7Wjz(Armg*iq|5X!Ll?3}kGjRSxf z)$L!;j}{8U5F`#okGKdn0QQRU#tc8-Z}H%V-2#2zyaB9w!!`)thB|_erMaPtzd9#Y zYg%iujOlJ6F#17@@S7|V1g>orRldiA20b>1EXYZYT(*Mmbn`au`!EE4#hcdL^c$sj z!8=>P3joIQ(ke7qSK^{iq#^7&gOV9k7+PC6^L at wWB#}Y9GB2YUnFatoI9>ecBehVr zi#@dp%aBhe-nB8oH!`t5fc$7!-%M+HKX}WV$#zWFpoSc2_Ju7NT3EHIiG7LWCJ<#z z=iZ>((sxI6ORB)R8Y})}Qs-+Uyq(z+8Vy!3Y+lttmnUU-KUpSPLCeXM&_Y`eKW52I zQ=OzL%<1uE5f=JWUIYs7_=7@#o)P?(iZE^JD<*u)8%l7dK~6~C_sX#?(eYztQZI=U zy8x`ZKnJ4&Fx~7plnoNYqZooz#c3>(8bPH%w1vQ6!=4_Gufv|H%;_m9Vi(0I!aLTc zhX7G{Po^U>8Ob=5lLk?JZD4Zh4}P#0Y-CmqagICBEVL0wLF}C&Z9%#D5(_HmJgSO0 zvCv=>g{vb`{pl=-Nsn^`w<lUJxwg>>4qm54EPm2vgD6; zuFTRG!wnz??rKG%Rd|W0OcmZwy6)e#4v ze^?mRN at L=4QKB at MT|pHmkR^?cb`v9-l1Yl#OK>NykV#PgaK&(#l&I5 at QF=j)jpf3A zaj+c@;FptEhfz={y5u^kV4*?1J+H-eA@=N6;k%vu0KRW$P<)#piGDC at Z(~$<6NWY( z&U7f#I;X(X=rkBmyF%S$M?szo8#)In0 at u_DQVvT$*iFi0SEkxw0tV+vO0Fr9W2=r) z8Fqwt^2n|~T%W`q$$nQ(R-hKC#&c~TVwp3yg4>OB`6&WU0=lEafOR7{I~M5=%Ips1SDCOzBE3NYU_UP?M98YlxI%@( z(k~XLdQi at j#dfu806z}tPErbXxCh{;9pRNGNqd|YmI)U8;H>x(ep!@=8WDf+tw+qf zZ|ahiRA_pF*EJaY=e~4-oG>A;odD0w=|*mUR#xO&(IcfE$1L=x zfrT*!B?k&WC&+YUhU00RP$MHzDDs1XSWEEOL7{ApC=n8V=b9uInX)JCctj~ypxwY> zs=}l}b!YC2Vm;;!P_#*%&q}USgAPNXJ;Y{c&vYgvv%XZNI7PMGA3PR`#gIWScs`&j z6&dw-mYz_iBgcTa;Zqkrn2&y#LKJ%$u4zzw znK3tn(=^P}ND7p#PN6q6=z0I zRq*_ at wSr>`ZD~%%4pYG01HB+DnPX7w&R_trHfK&)(3P+ogQX%jG5En(g`s3+U`7WH zl at l)r(C5QV7BqwK5{Ib}i0Q&<>L2FAeM zz0^!D!ZxI9_%UBu=Cs`ELMDVIcx_JSz*Z@~nF1+`8?>jAxNx4KQqu`x%ygWYvN)WL z>7E`bub)mKY-+Uz6 at 7dLQ^DLP`7tR|(V#bh$(0!s{u(@34)^eae8PhtQITDe*ss9v z+Z78Y60DoScYeD!95G{>Oh|3qvSPYGf at fPmrLs>9m-trFM5uUpd= zqpgoTre~Ff3`*VXER(gPW@(C-K#dHyck at kV##4P68J6 zQk-3B<-Uu^*4thxbNa*hkN5ZRXPl_*pa_y{UvQE2B at x9d#>1hAF`qjE3!IOHELqH# zQEPCg!SH2dI2RWg(T>%cnlz{=#QGc|D7GNuTGPJFZhat*n;vyMTx$_g#aE4>g%zR_ zD+~(-_U6Un!Z-*uJXk)y#9nQl#c7crw zyod@>8e|7pc+ko(co1nBd;Un;T#{LF4Zg>$uHgRN(FaOwe-h+9${LCDAgw@{g$&P7 zm)tXFC`*PR(_jddc0ZVABhd-MkI`zZ$g5EJ&UYG^sk8eY-oF=C$XqCkbhb`+XOC$W zZ>H)6r96WL6AA@{aR7RJ7YV`D2E`=6<9Bk0T28&}wSp7$$28Yn;7*A1P{m}1gCq9` za)t<*;xUNjC5~4h=MH9<>gstI4Qid>0p;ey{ z+l=H3W%zA+#5IU|G|Q6TnpJq|5MUz0Lz2Lk$&gmUL~$gbI@lI^ldyE*JclA+xT-IhwF#W+g1;#< zVK2CP at Lr7Vu+GlAF)b6*oIYB at N$JmPGA|V4j7QDxTVhM6Bj(H0*)1p$VMOl$rR0W8 zIc33CDfaOQS at 0`~X|KXYg?cM>_!NcO6zaU#oN493r81`%L*gnZqzIOvf|OwZFO%TJ z4E5Bl!|(+s3S!LX#yD8vA!`Tivq6fi0dD>ZU8qiZCmMG$LK*eJhy0p5%7xlFmGmz?b-I9X&&@ofG0gU$E-j4%0cPb_&1q-Bo0qnOCPubqZsr3o6##9M({_pP zh+ at a0iV?gx3*I-XTPG?=8`#mq`HQr_RCj?3_eZokw~(kRL`TL_b5|um7&DU%izj4d zBskrKVOb-V0z5 at -`heav#M#p+ECYG$#xV%eHgpHm^qZ}6eKgcgZc<3Z)WZ#4)p zAj#Y8_e!wRUqCT?({EKJw`ed$WzvWadiX{m&XbW`g`r7&i!+08VQLFTj8$ZsGAk;u z(I9$39}@e~3TruAYdZ4#$AB1$c+xRl3d{%x9*LRHFCO6zh9jt6wHPvkzBNF&DGUif z3CaL^sK`|GL+ zt^<&JODM{yz~I6m at gPl^w7q0j408*&v~eQ9RE}efPQ96%z2JggFw%lH7S>vPg2UBe zsBqM_kmF)GSfN#kBf1(>5e`F=HK_UNY0i%(p3w<cJMkntr3Mm;J0~V!D_M3JLi#a+!W)hZy1}AGG%h&tw7328yR3;OlxH2kB6nG^$afqmumwwfMu at LE$|BQh4y2SL9pe*i}jT z`6Bx at Sg`g5FXkfcR%gNj{r^QNn z)3HRS1PC6)yXpv9ebLYxhT;SCanlm47p zgO6F at H)=P?;9w;|hNCMC;+qoojvA~**oMR>$w7&z`g`gGr6bhL0#WCtbaJOvh}cU9 zbYc&hEUvu4CKgZO*MZ|31sLC*s$v2#7h>6BGOxNPN^)c?M2Wc5oRO$IGf6ARmE!nX zOL2x_e8!-7jMShRoPqC7TiDngDLo)Zb5?;bmzWHG>JF}gLegNn4_qUz6e|yfMWIhfG7b8uqyt2W$1D^h z%7Rvkn?qtQwR<(b7!^-57wIM>7LM`oqzov<_+Y^)N^^l7#j!~f$Kp8~)+ihlhE|6m zQ_`H|gJ`U9`0=$CFcYG{4mONRk*_&3ioKQ|K>@xTk|g>QQ7oo(@&^W&6G%K*n zfUQf8SD+=>qd=*}>0lYXMM>7(r4Yjb(?Q!n_hcS4WIEV;2>xt^ZfF)`mf_?N5`G^_ zb85(Z`w%^HZOpt;gQfke{lPD8knqTT;xK{nS`Rx9t|m-e7!!pp0-V>#ss;c|8p zT_Vp4M at eky0W%josEO4{ed%e6qC4(P=>6cqf%Ai02-lCbm;@+tq#s>P1G)i74E)u7 zAP_hR20btxRoM{u!TqIc7JNgF5QK44JA)qvyfYBiuC#)V9pNJHSN`~&ZChurSrTNOlq-XT#=Mku#lq(VvWgU;8nG^jYZ-w zCUcz7X&Dx8y3K>?2&OSfLg6iWA|%*ApO)qO?)1`V1;v_{j&Qji6o(g+3$c6DQjT{V zYBoWeLDj|PNV6VKGOSC{X_?PSOIX{2MuxIL;s6}MgcBP=&rApIv;}-rd6 at wjnsXwg z4QQd&JRmXfwfezkT0xANgt#68-I4id=@F~KVN`$RLN6%IU?9-w at VpAAyr8s!BtYp0 zmssNz{P{GPt_;wIn1Z&1`^h z@!)hQqq%-H)*39%G;ydcp at z1M2b0oOONL(-bNX5l6NVq`1zR+z5$aoH7&c5sVo+c; zDLF%8$|#sG!@?Z+TMEY^LpT$L_yWCQ7&0uv>Is(2;IxVvs9m8wjOl!dNw(T0FepX1 z%E%x*IE-V-${;vs8zj~do^#+ZI0Ygqt)fI*K$RpZN1ZCN*wRf!d;^AgPS@%N at 43@e zFSxwzXA$7_o50ixw#;dxz{Zrs%dn}Cz}(sh?VD8{jHoQgBFx#`>ESYESQnf(Awezq z!TKryoCX$T$?vlUTX%SFQhPcfYBP5^5B8IS>@Wlmx+SBlBOgM5XC=4-;9C$_#}y9z zeKn=f0%Muik@(&>U|0|7tOxX<%<(d%mH8=B-uxM%|G|AVj zL3V;4G^CRlv46OOzoq`+ at 1i_-qKxwji2yLQgrvcgT$RNU*=U!c2ztf99qMwSKwaTP zfO@(p#4#74D3$?nn$S&Sc>;`nH!8%y2_N^UmJTQy4wycN=_?xg5yOixY^r*Ke-cMF!|Ew zJZL{0kbJljx#|hCGb7bmsV_iyRgxEdQ%^ciO5Q?-XGw(sW3 at Zt-5|Z0S#*b*GBdxU zMF=@U?6tD{T7#?5ptyrAHr&Z?jx#+-e+M8R^H417-!w9Fs}h!u9XgK<=CbTMxa-fT zJ&k~Zn1STMp at JVVXv<8FzZ#5pE{*O(9xD&h5By?E;axGH)Z>Zq>Q1w#;9Jw9%a$(%n9b{x4uQcl#8W-tJF zmDx(IAoxx|Y2S6d8R}wh1{Ha at zmeVt3|reHZ{Y81P&7@(;$a)9R$94uE&>7^;q;>5NMHAH)zfRgRo;* zki7&;6<)OyTojM%amW$!{8Ed7L((73nJJfI8IzRc^hFhBPq^n|_P$UYnj}aj?E}X+ zj2|`k_+$f-QLFHc0STrf(f~UB6`!VAiF-U~H0a}!n-M}a2CFKp==*YFP}vapt31NX z*eYqTDT=in>_`&&fjSQ%4O&hbz)R~R?#eJS)4j-odvsN^TM2Vi#8a^ZV>TkM(hHWy zGFkl%81}LT=QeuBd zYD87B36p*+mjzTmeO2>ZrTG9R0sVDNu9 at dPC_6Z7g>jv9%(dpoe>$D3S-h!<0m`GLe_rKkhf>p~c3D z)V~5kA`vwBU~a36MXquprp163i|{ZQ4f<8_px+2F7WiFhW7(Q}8vq4=9#puiMTGS# zms$tK*8ps7vzs%W#7K8sHwz&a=pFDAM>^bSHLOv9SH)c(kDR9lnNk?>xzM9Egt14$ z$sCr74S{A5>R0CtVQAmM`@t%>ssZX6i+0X}w0$Z=uC=gFM?TO73Met9Q|R5T!{osV ze#M#LbvwVGK!|#5eAvEbL0_UlccrZtTt$7PM)1fe%qJuW_^BceEFM{z?mn at -J;a`| zO6>SM8;?kQA55tBU`rNvXfSxtvx0S8<|Bs&+laKVmcUPE!yk6{rOUm+ckH$Y{oOKU z#Ec1rY>uEggIzLo9<;hEBf0AHw2CxwAQm)M+0_;b1B`OA%p_TvYDPEjpxe)xrZmQ> z(}@KsKQy~~0!En?7g8kUd3yi4A7lyEqDz}5t}Y?M6ig|FoSy!ABe-ZeRyne>o-pDK zbD9OYF&fb+$=YN>m%%}Zlp%DiMUDjUN>8XKDo7W2QHLWhT at D!BPgvlYmt!5*YGns? zR$T4S2?`aQO&C%M3l5o=35N!N?4a-2=m$R}oKVl`E=7qVFm;A`KKJp(YPDrSvLe!9qbc3 at 6ShXJvWFEs2qro&TKBYkq%J`ga949E^{p0Z| zdccWq8kwn<*;$NFhr at W=Dio3iU6XXZ!KlSy2R7VknU-9l(d-xt&uB*&^!KH1kcY17 z-SQS+=GG#ohWCX8YhApoYaDK5$>{(gORfM at i7$XhLadrW#8#&eB)z1JVlm|Kv`9#e=c0lzeIz#21+v84_RZaw-&W zppOg)8q|#7jijL9Fzpgog;-=r`{?r$TxEE5ra_(ciJ-0$BNE%Uq)d|tAAvu#hR2US zh>q`-B{-rO3k_C+_Y?k2Ol#WOw7j9`*e43tq0*BDW4IHK^-3b)g1!_??_N!d! zFBD@)VbLLM3*Xn37~>IEUt20xIqX;U1c=!-m~1$VTjpeH;2r2&C#}Tu1qMlfNNL3* z>4NsA(GHtF{%tts#CwBy0B~O=b`XO0NP}mk*z@`Wll&Wim?p*jIxIZ+;rZ1hg|9n7 z%gSU+`a@|@#PJROlNM0zX%2}~89twqz!Y4(9M|qlA;SZ4&Veg;IU!HTfHY`kXT-V{ zw6LJ16q-xzlG8de)CG*(BH6`pJcwx+B}hHkJB>jzWX6gHPo?md at K;4I-gsLzC_mV>-y;gu03bJ+);>Tn&lV{WW{R z6KlG%X4)qz at Wlpo2(A`Ye0bN7svk5FoM{lF;alCH!ccrbYYz>15}Fw at 07VyzEUv2Y zo#^1(6bZoShr88{;RPzIr4;tDM37qDZ0Ti%xTSTk^3k at Mg?K+31y*kP=@8=mx_$BmlvJ zjLLAExJ`noCmd at yj`kvLU^OclkK~}hF*`Eh)fDux8aGh5r4I+#toy@!#C at 4I6rZ1! zcuRYA=1bp1WjQC28R+FoQ(yw1k;Ndj0T4>&ey71Lsch@>tQzZ0Y$ybU7$u- zTL|2!i%k at _bjdXpz6Ff2zG-uj`0gG87k{ZIbc@`a*W%_egOv(t3`nvf4)`7KbOwPs z3k`n0PIP6C35hL{gd)xZk~t$#IM1|kdnR0^sL>6MW4M4qh$4cAjudV(qUBY$I=p`( zM%WELoActz9=roTy?Hl=#R9+E6qsWQMtUMhF4aijujx^%D|lEojzeHiit?f>B!a_^ z4%XcCDp}RJ9P7dC;Q4jvk|KonMKvG35xBN3;slmAMAtl5bpuNL=B(4-5bb53Y#_)s1eF zUjvDl53Bwq4{By#3$mVasq0IU9c*5YS(#86 at xUKLTgQJ0-*T*U1to^k;xj^V=~v)^x{G|S7i5R z0)e(fjkPXjjDqdiP> zI(4K+Bf|cWgr*?>gc0dSw;jT#ycZC5dGMYZHYS8GO+V225L|d0ic5vV=mnD&=_1j^ zNTVH;0SOYT%PLProT-wLlv#m0j7L`1;@OahM-)eF)uwb_gdK5)y~XT2c6CxZB7iB4en3 at U^!4j%Nt%ry?9-%}x6jp^QR zLhq&|W at y?=u{DC1Qlxp#pqF7as{?^^%1!S$oaxJORHDwH)?)DotK(LA*5y>X!p?{; zZF0(ZPNFhpz4}`FmPz>seD at t&UzGM$lqf{jsj?DHtK$vtfO7X2` z at U3z&sSX}b2Na7e3Qx9Ln_f3SfwdZ=;Os>FmIBKwI3s{u*76mv)d z9<;i9R}g1GqRn7qKzHkWt;KFNM9osnh}NAwI*dsg at bmGAaN+{wrD at 5mOo%2>9KlKp z>yUUhNemKf3zDe7b7}__i9FQ<=zC0q;&6DxQ%I!rf(Du3KlfzPLNN=n2xAmsr^3bp ziRh6nc+d|zk`c-6$jnlY2r|t z!T8|apyAM%aINuo+)px~>uoaejA_n{tprblG=`}R54;;jo~JbkAvW|#6Mqcr>ld43 z__?)drc48X2o3J=dmUhWQWs|wp1XrJ2f7j_69x_P^^yd2nKN(*0%UBpPlAaGbwunP zq3Mvd!-n$S*jchMaeyzBan%yim%ctu0ppMeOYeZ&UBR+YSBVj)K~cyfM#hyTEn|}Y z?#LirAz9Fz!6Eg77c-J4$918LKlJ4m59<5dk(k_>-%o=QR^V{tYImf8yoHB)a5PdW z6Rp8;q%jnZeY$m4T+X>Df8HE=IOk+!GJ<8!6Ms5RFajTrM5T0sSq{hD(FZZ^EsSngS at kKZ2 zgSyudAk at qP2=IJRYze_=1gq^4Hi2I$!Z|)IF7<+!&>pnc3$E79ptGQ2P}Ipv zFK{L8RdbPPXZVA(q;G98X)P8SZ1jS^6NOMC>O}_)x<7qNge~w%R~QO;aTIDc2I+l* zjvfto(8zE`XgV7*JWxiwneHiDpF9_bdWbhT#`B7$`vVJ>_)HlLk7<**4zBjcb2Sm# z3Q5D2Hg~!qkP+HCl*s27ul>)wnW`Ljp{L%o<@hTEeq2^zg8J9jTNHTckMiM#Q60S*LEpJY$kcuSueJpf0^e6;xY)gTgE5|4 zv>Cjxr`rqd2Ej#q8Kc2~B8DT;8_rUDX~UHE(Cq1W6chBws>$rE#SM!g0V*;!dPCc1Xr54QY4TgE0H%l5dw;c3ou(;EeKU0A(YVpdA_V8n(3M(NNJv>7ai!TE&Mm}{Q zc!*z8AGFD6=l$XZN6VD=*rU_m>L>Mr7jlGU*{m4VB13{-jts^c9e;Ni?nr!b$K8O} z1ECM*gb`a*_ at z?@^Ztmu0*j(hE>(%IaRv at s^O0b|491!H)q at P@d0xSOxbw_v5M$EB zbL6HcY!s^~NmnEo9-f%7Vr(6uS~KhcCmf}q4s|NPr!Z`Fgj$8=re_HNjzDq0k_MlV zli8uSVN$X^nOVr?xW=J$f}Iu4OoQBNx`98L(&fms42mxoiC6Jsln+f0>!_qvg3~-W zcu;k)*58$d__OI~&I!&W)(ls8_KE`NRJ3;9JO(Dl? zo{R_wZpwr~f(4iE3l4(76L;`gv~kRfqeX1g;u9FYNr0|TTJ`vAtsslBua2al-T5W` zpbSW|A($P(W><);Adj79aDn`XcjC`>iAyuMe~`#vb*)pD#ryB)!A8P>ow!zL;Pgrc zOwC|UuAaJs6vAQ!QjWMQ*sjP=0pV6=Bt;az1cNs-g9614_HqTj2BL%%)TLgS71XiF zjeTNI$wYD*GzeF)8Qh{NBXNbW1Fa2IF}#K#uH>+U1tCZ}l2|p!5gUvQD=KnP$>Uh8 z={+K|_kPFz()2I{4v7Nm3CUG47FFDA2OWi7QT&v+jEG|HljvGqxBi+8=?LNv?*nfU zp|pWZ{=otXjG2pGu(qYsI(s&!SD>-i4q`460Q9&F09dD01Amaj6%Eb~z+8!^n2^XO z=VZrDONx3>h4MJIi5-h-OM3~<1zBwv;7BRFi0Qp~7K>@U3njinzn9^}=5qHYnB z5Z^To;<_b at buQ8%!$99Hd)l380b-t&Xk!TEu?t+pADl^sb&?*@u2n!*eVvxrv z2oB>-%^B?nMF39%K9U~~Kz|^w1y$0`%jhW{d@~xX*sy!~63JeNOGCKxU|{e--i=|g zI)oxmk~64##b3N^NU~r^B1Cv)3-^*X39mVdNUJ=B{?4=8R$R{=t5Vh!sLNrYUFM=UWY`|S49 zn~qpJC_YR%;bTYQ>+>Uc at OE}u%xTN<=MmlSV8J{shBp%>_`;%I{dKkat8%2_3@$l1 zV;-SRN>VFT zWZfts^3V#lfcR7(7Dck{*gIYhVti_D<_`XJjW{{ePA&U~IiE3owr^850fPVi^y zxNQucEYhhnt)_H?2A4GtNVElykAWE@$ zgXQUS0?!Wgk{x{++#jSBY=%~CFsHJlD#UiS3 at z#xe=d3Ooj=CA?~lxEn_})i-vQnALajw=}$DNy>bp at 0b<8Sc at -qIbjHXfDgSN4BXvKu1b90 z54tpW at XC_W9XdN+!7Ff+|Be?_-{Xac@>fzsUle!y7uCu8E{RWK3S*Gpj?;!Ulj`vN zFk`y7(GeS at 0I3aXA;TUDH at Rme)*Ne+B)vM!)O1K<2$H=7hcy z^92DtjE5sbJ^A at s<)KV+%nX>YL4*Y1CWl7F>)4ZC>Yt;ah1fLt-@^G2k`g3hTVe9?7CTp at sM<8MM^u`3A`*uVlha z(^{INhBWD2v<9Cs9DbH6Tv#yL!aF>uIfbenY~b(~A#ym9yFlSUYXwjD=+G6`7PZKc zlWPVS5|$=Ryd2NGGfQx8K=68-cywnb?vK+2wHrigb?^^7-e?@FI!riTRAHsUp+a4A zD0kTq;*i0J4aShJ^n!agc%h4JrC5m2MDhI-J;;5$!Khe-iAv)erPxngl>v#NP&g35 z)!Yx_NjT^NSAtD{oc at 45&PU|P>ApQ^>%?%QPUlMWsOkP)Brzy(<*1 zq{7-3bYr^9h&W#>Ka*~D+~slc+Q<&tkgiXFI7cD0N!*vwaO at Gw;R?gV9g^LdnWO`3 zBo+*br5;~!p;$BIKr^Vf3lwf!Jo7;#3gwf~;1=!Rc`bG&A|WlUz_{);gWRJ-P+#c} zp+OMgc_Y|aVk+=c1fCUS=ny}AP||{VI)|`K(jxOL>^FA>v5_HJFpgIZS0;HghbHC` ztDm_UMy68**3jUkB~AOK5FTo=`h&Cy``zFZ at 6X5z2IwL$b09BN at s0eTfly!Saov|r zRd}lwjtx2;65sHq*QyOftg?d!4T+21T(^U(qA-!*YU{*>2sF!6yvnSM9ifEJmZuZ9(I1_ zPA3-JZ)Td(Tx#bB>kDm<$;xnf;S(U>(wxhZP0O%UVHRWS2YX?Klp1_(9L|;W!gIF< znI3$ddoxypJAuJ8qx-_O7!OJ{zA>O%?Y_Z=krxF$W)>Ir3)PLK$XPy#b^ zbchWi^a4Cv4;TQv5gVMQ2L8%`WPh{CaKLTUoz5864b at +d2OkoT8HP3mk^_f?!d4{? z%6n>3RpukFa=^l?&|tG4d at K98DppB+2Y7898V!amo%G1PtU`+MulZ;7MY<@;`9bZH zScUSn*$4#5Wadm&h-Hz4;pq%NYXc?4U&<~XMrS_tA&diYB8aUUghY?>`|$pVQ)Lnj z-ruDYB&r>)Geel-6f$0CK<+q60;bo!6-{h(hCk!dhw%y{q8EA9dN|n5JkC^Xi+4ezh^x7R!n9| zEcm;>!}Qk7pz4vOG=g_JK_kMd_{xwZm*CU}qWY$O at N76D-5}BmsJ*sSd?txUAwmp9 zreY43lcx`BWun~gW}Tx2___Trl&c~!Ayez#6$j057i`Gn!(v^jy9vLg{R8?tpm%?Tq}3C8C2q8WZ2snBiHQ#c zBM~NdP{t$evo5(qce>MF0;?3mL5fTe4yg;ZYOQ^r*$E1_o0Ln21m)@aklbNv%P&e^Y7(u|zD|geHx2fof7~eDKC4 zD3tzhU|u1J&*-o-ArTt6ozYW0Ji;T&nORwG|YuP(U^3*scTaLRv~2G@!N zIVx$RuDs^wFs+6<)xxW+&#e^1xeDi`LQfX^0b6pb{3nMhOj>&5W+)G9Pd|{t<8W1l zxA0@?MLNQ+S|dIoLJcaE;C`e8pFxD5?{Eiu{h$DmUQBy5@|AYbn?bPP8!RYw`1YKn zKJzy$YVuzLisDTJe8q|(0m`V at e3?oSyDFCOblnKD^y-0wpuUMGPVaB>4A{@V`N4$3 zh<{;j!C?sawQ<Qj^lg}r^4EhwsGBACDxwMC9#y^E)m*cGFxnrAUXZosEfB} z;4k*-x;bhem87uj6o5 z#rt$_3PvBu-0B!_p9DByIx at hSDW6pYYgaf{8=a~~v?pv&Nz5S>H&D%KDaaR^gsa45 z91^q-Ev^$k69MXkq~sT>TI?%KZ!)3JN8Z)J3g-YkVL^*cCthrzQPR_^ zOiHpOJ|E9X9rnE?e5DH|#(cXtUP~Wnrp!EF8!`!tajpW^iH-lF5gbQ6YD7%IQGN%E z=L!}dioo88PF3*!F*L}am`jsY7wC*5 at SMqoP!0?2wGgB z6P59E25S(G1fh7+$(pt;_6cjmJK**+6%qmo!g1uWtAh%XZd9S>Km%d;fEXK}r)AWh zdE#`z(8)d@*67wNYO(8)rY%^J;jJRvAi+10h{$vj#r@#4Fkr2T69oc!Y6-%8;aSrf z+1jDDYGOu!IL)g+n)vfm$l^;5)N?)L5jc5P=ab=Dn4kkx9lXPkn)t^0CM}urRbCuP zEO?GTb*B}IPXV2e=g5Ma&g$OEdNu#4D|lRA5XCYPp)z6lHDmA&2{x9P>fhkN(-}!7 zMrr?8h^b2IO*-tdQ<8KS>A2GlCx*+z!-R(tPmkX|>H~^76wz_1yVk=KgmP^+++F~?GIgasc~ zlCw#D>I)8#AXPEms=v;q$I2i)z40OK8^wAkP}CFc=M?(_TvvgZ0Fkk#a1+lVaRRYMCmT=u5Xra7_1M4HiWlyTnm| zb0Hq^P&&R1d<*8Y-!1_%vyacJNL;M2Fkcqqg2oqfGDQPNboyD>W6e?P7Tw#}P_#%g zXufdFpz4uD>+oW_a5f(oH6a6^8Njk=X)+#)YHcZ|15LR%5OoLBc}y>W*5e<1BgDW^JdWXNCS&^uh1l1)Km_i)2`U$cXXZ`w7gLNrh8y(>>BPrzfkii_MbcZwZ2(w0W3Yd>n z;7e54r$AYy+q5{tg8}pgd}=CVKg@$l1kTJ8Cr=|Q^NG7h2$BsLe7EEXsjw2oUs5FD z$EYG^O%~MMQzOoSX*iOBxU4y>wTK?Eu%OI|sfuSx67K`!ZJL0^b|n at q90VA%5jr$= zd^KdragM@)v`JgQ+MV&?-1U3}f><<3(k3uwdbTt$h%$`xJ)#%1B8(}?Va=3F=Ol!k z*WqXYby9K*emak1Q at GHfUeFfatI1M~)t!MZ5gOEZf=3l}pDreIi32UG<Oo=h7LoK!`u`!|e(_f^)#qRUDGQi~Zq&R?wL*85un{MdD)k2 z9Twz}&a1Lc=RR*AnGpMx*!*ekw3n&zlgsQ99^7%qZtxYF7qCIAkJtC zBP0l9K8h%QaKW<-=Hy{GLVcRwY5|ZEm~ONwlH^C942z!vz=H?lj5nGxu|#)J-m^e& zr at zPRg~FV9 at Lfrg4+Y_u*wE6`N`n<4-dkf at 4%|_R*lf;2gPqeZmngv1gv3o6)aV&; z!FFa)<1+mVF+q9Pte}bF>5#xS6e)a&ClrS|J`hPHW{0{1MJd5H5{U*-!uzL^gy956 z24h&P6S^v~P`J=}Flum<22)ACjY7`l5&_HS`Em2U%!a12QLmkAQq=4kwm=?Ty__Mw+6 at Gv+L%3RJp!c$jp)tMHBFzHp#S=+vB9uEFPAsH-E% zpzg$E8d3z0$3_*-woHsjY+M`*Bv8fC|G6hqUg zHUOF}SgB!pg at j@ocNvC?Lds*C̈#vx at 1BGkuP$w7FrPWMDDhAsFM6k0#nF2-U~ z-*;z}0}XkyJaYG34=u#z%{UFVOc_ZDDjrdKo0DQK#B>Rz9b`8MWo!&sHH4g#%%$=^ z;z6H2Yfmweg*V``<`V= zr`{mvb+1k03XNG^H5su1$(Qu7Vo_)i0ak$T%%WadhZFu-h^rY%H?u`LOrUHgr#mb- zp%;{xLK}W^teZrq=@*714wG7)LizL%#HBtkjp at 3Tc+=Y|C}=rBH)aBe-S9NRgIpki zHhJkmgBsgd@(2qJ zcAkQ>L~b?FU`F3;cax~%N#D(psXD at u!9je*uxf#(j7bhTJUyl%L9troOk$X8Bx+2b zF`6oSTtm(E~r1B)dSaT#+3sY&3=Y>L2_@!-3v$hjbY1&6gWt?VajBp1avrMA`> z)2&3K^53#2250LD=P+W_mJSj$JzQQUIccyUZ=JLkOtQGoffU4yD&)()9CH6RvNc3q zelV at 7alx;q6e>}?oy!moiDgLl5+I5z15vE97=Dae)X@*dOeBqp2|ZEA_h6XAGEszW zR(x846Ct`C!}+jxgP8_rqO;(Sb$MNLC8i?raUEkavO(9g2E`MUPSC?L6C`mZh7F4> z$ZYdAx*B<6P?B>q9 at tVD#ON#`p7`OUC!5rJc!+pWAT07D#qfqiO4^rT!#W?yw zsl(ND?n_YAMlj0nTXcxcim&LfRgcvg6iRHw_|wJp^;D$8n_)#}{jC5vi#bCU>}?cB zaMe?TA$}9`%KltpL<#PX?ERDjlSSPw!V;RXFTw`Q1b9-8Wh7F;vHX-{jiMmOIa>vW z)(vv6t|dkqz`LV8A!P#|eqCUp*!{XTi!8gfT6E>~Nqz_+cdr z@{2iy at M_qE4v~&fG|8R347m`&t%n$ZQ$wFb6BvJ%8zk7sfk_iLX;7C%fWjQ%Hwrul zV6BTII2}EqJ%dDj!R=Kuq0dPKf7Jcvo*G`c}?q17q$ z;#;V1T@`w!N7hLIXiH2%gKc}-YVpB;B}hF=Jw8;%F&LSG{vKtgPSChxZfvU&A;LEP z&=Pj?g6a(#`Wm6ZjXWs$lcUaKN+*u=1`d2a9emagra9f)?r%bI$+yz_sYiV|qf3jN zUXMi}uP%u at J)i)ul;e3;It&gJS(0`~&dd_pvM3bc&798ZR^G at uu~y?MJiYsZ$5X#j0XF3;PV@?2hBX-ZnF7AmNKh=@Uka;Uz%P~HR%*50Wone-xn{x?Uxf at odA1U)xoMuK zpeuCeXRX4S*2ExU)6=0wVxz>sM;+WA(jE7Yku=yBB at a$UEGN at aBJocr)tIOKiXVgM zems~{9*fB1-5A?yT#+Aqdt%|Oba)4e6%7UqTbkq&gi?^RCJ}ouZ!y(KjOW1uc}bY) z5*^5}@E>W=bE^`WX(7-LT%F>@|mPZo54s<@H2=hS at DXF#9)flzd0Qh at YFgt^)h?^Ru4Md^86jRU<$y)V+4!-iL z&Wx|KV@{W7kmqZy!F}imXMit9rfVF+3Ov4}G3^s$c^JDZk)d>n0zSl8D^c86B`$$e zQ|N_wI8!8&-cM15LV~Z-8NLpW2E)0sQY at i`PCr;rNPJrN1s2SvOfh5LYz!}naOHb) zs?`r97~5AF)e(quM5npQ2|cWXx{e^WRxQ)0DL~_$xs%zP#E4!^nh*L-KxbRL|lag3j%o8 ztHcUCnawSo1~4b5^a$GEFiz(zH?7mamJPz(=UqU)|f8ypyw36LW73I zC8JObnj883R%DRW=kmmNNd$Tdw4#rN2Iqhx<1&n at t~Cgenz0k7dz*C93PxpSW)KAU z01V*=4yKM}MyDdUwrH*ZNF;&^tvGu%Zl+c%8hoPS78-0knwT9SoauHcCJ(wfsO)#Q z81rb4);_1aUbr%*L6#81mQ}qWNQ4WilEaTKHF)(3yf!Pbt}vk+?AwCeq2p98z$cZs z8q-Dlr|6SX{7~#c4xjdcR+Kj_#9Q at p?o6{9KNAT)w=(~TM-zu8*%*z9)M^KTau%?& zAhgMy;Rp_TtDR{L$GlJ2uckp^Je$p3^??=kiYhreK#oIP6N3fw<41%9$%f}ApW7$& zfdz+Q4NhYnn)cvonH1Z(=PHsfXi$)diJg|=fzHgufaK}Oi{CizvM{BxUz}?6kOMuq zO4s4Rc6$FyB{<%fP67UcIj9F4i7jo$par&C#W=Kx%uT3(Y0Rujf$I*tvQBIcp=`6O zAV~rK at S;E6m;o^b&1&J4t)2GJ^$~zXBdT-d%?t*^lgL&M%EW7;Ky_zY*31 at dAZ79X zNV;;Q(X&|5B|q~d4_=pH@}MWB?c;3#h9YSswu}_7Sx^SVt5TqVk%c&w<0!hGl`%_Z zt at y991Z9V$S|*Ov%nce0`r9MZcs at I;a*$&=c3*>nbYsMsmd4QV*Fa%M6xXhxc7T0r z+82n6S6y`RW||nT;Bf?|L>KZ#XRgKB9sEiwh(3@&T#OGzg`CnL&$v`;dJ*NZcqdpT z7Q~HFMwG)9!i}LU7I~bG_29`e2yFG5!O+5F!$Tf_YF=Oyh4-P&pjy*>CVT5e)X9jR z at U#Ngdz?O at V+q#abOxXvFvH;p<|F&53KF7*9C^M at k(YVU#v?%AeP_`7KyL^ukNT!F zWA2PpV+CNhFPtO8pJ-6bn0V6;@YEcflnL#!@cu|`qGU)JJSqNUJQCjzunBFeeXv at b zxv-1Fc!NDdWAK(aXs$HUF>%rs4m&a&MtC2G%3!Viq#tA%W=D973Ugo!4)vmdTvQdG z!B1c(62v at e!mbr zVLA}^U?&LDi#s0@>y)Ggz<8C2f)9$%{Fns8G#-h#3 at J|^P6w+RPoyiz>-B{6s6UMR z?r+gW8|Xx6TG;oBFKTh}W?YA)I$ZYX8pmBOLWAK9)~IuHW_1j%sSKYUuw~nH$P6AT z#C)2BNcI{lyy ziBXkrpfA^ARmErrGycxVFj~NBfn-qxwo9-q&1p<#4r^w{Hw_pf{VNhX8&R7AqBHW2>r9~#iTZv7-wpb-WGx&Nn zPnYTPV0kL>7sPNMlQ}DM3xEyqIsO!f8sML67_uWwG&qMGhB2f4VbUYK)zMrFf_mPs z?GjHTC9r$b1NuWx365i7ylhXKJU)k>FA=jOx3UU&=@01eE4w3c=x=%m9d_EK9G}!+ z<3XW89ItQ(jp>lV#c9x)@T?9?NR&Y>kT38`7pbbk-D9}VmLZ7~N9cr|JG9!-k^s&IX;oNgU zp*)n6I6S37>S9Z5eU%RD8Hsg+my!fJWXY`{(lX1H9zL9zWwlZ~OK8xA$ciL2vkF<2 z%yz(FqQs^uk;9GRMN+F66z?k7!qYr?-^au at AqEX*UDBzjUv!qnx z!x`LX#YvZlGktk&1frxBl3fiD4jGGR17&?Ah9f1tkK<)F9gz62g!atq=B(~_Xc8PQ zv*bc-L2Bah41QjK%@<5m*kD5QW_G(K4 at lB{j+5fq)|m8QBj2MtL!m%%iixp0GKVad z!pr^533fDl!WH2QROn!6)kR(;v?MiraW~4!qM2LKhngrkf7= zWhzW_VW-10B3#X(P8PLH=$3vjSd_=%3VtGN(W)CE>Szzicey4j3j&OC+NEFg1a+BC z5BHF at VJX7Fg`bGxx%*OplQC0;_s=MhuNjHin-+E4=>(xlU`^{^oOF3)7G7Madp_eK zIJYj>Bwz8Sb#=)P_Mk4g1|TJIa-|VmJ>HkZfHe|lMWfOm2vEkuwnCDHNSYFp0V@=) z1$pJ9Rr6$!+R91k0zn>eBhL4>a&ipzsJg$7^o zbYigK9USVs_$$W?E_S1xAV(wgr{iiMaU~8}kj0qE(~$#`v}4?vfh8D?p;Tj;76X87 zf7(IVV?j{gG&8kIb9!ew)x_nr)j=vTN^}h5MtXrczCWJh&ql-a2(v0yTgDgaY5;m% z3$nPR24AvDC(Yo#<>}99zk@*?(EY*mJ`UR={O;^>RxKdFS2u)B`kVcZ2M)3XTW(O$ zR}NiWDL{CzhfYWOZD2ZOka9%#=}I-`prqK((5Dkh zXVK|`#ZrH_uw~-p{in={)ebzeThAw_#;nEln7FFNgx*(oihW!{8We~61b%6Sq)yC` z0+${YvhQ1R at ts+f2|pc^tWkVd;Xa#?M7izrVDR5Ds#E6EqZDLHH%t$$!Nnp}3LNwu zvZN-&9ujkKKYvIaVO5C{RYgW&FTML|mQQ&waXIS}Y3kS0oS2KijPhWW9=ySU9U5FR z4PK}BnU`@cw0`gee#gbffQ2fV>A$R15ni1KZ9qa_5cYHni7B;uJcB8n{Cgl#&zBKy zjQC(EW3+%#r&|no$04+#v9n-Gt~Q*()Dwm;NPBu0BHOc?6>o9K(WdR-&02iz##Gd2 zaBTbt4zDM4+6FGj at T*N-iIWP6vm{m}MIEM%3`xw7Db}D2MXLCIM-!Ja{D at u7(8b8g z42`Ikh>;iiEnba=c(ZIa1o(ERDs zZDI{iBdVb3)z~N&ms;`)j}XMs5k4qMY8dv2aPtovn?jex!hCm^oMbA zoNk0Ix-Vex8hRBHTkD)aVPy_>Q7AkJS4MO&=5s=WR)IacI?v%uYmb=4$SRdrA583> zVB*2%p$bqW4~5 at x#Gvf6ry}fYbhsTLjz`j<8ZtK~bsLa36auW#C%UAKL|x?6=(HO# zp^4)}kJoYDc|P9qOBlTE4(j?+rHQjAeLABv9<*w__LkZK&LoAGph9Z}S7caeOp8NU zDzfbq%MRz&feMa8j73D3L~M%~L~4e6n^uy8^3)qt_?>}plXn4Q)+Jkd>lR}g)EoAR znH>xbvXz<~8=b+0&#(7`Uqs|!+C1zO02PA;qLL!tBoF37xq)0)`TFWvF zmyjZ4ho4O4ET at 2a+(jYcTDCtTGZGz;U^p`Db$P00B!hmY3aLo2J0uokT9=p9oE~n# zZ%ex)fMTqW at G(rWJQq~x2mgK%gK=GgP|q1maV=XUu8qMOigj2)^D+{QkruFi5ED*Y zWqw9u`vf5yLNRA#r5FX-oSELa3NjVe1(Hz1QHvpoOIJ9=r-$KhjPSG#=R_C}H&wBD zGs=T*Oq)DTAVgeMf#_r6q=#dD7zu^;+2>~%e82Ba>QYVyZ6R?e?sMNQK6H`x$Hv+M{Ox$b>pBT`^VG6oQ!Vj^*DF?lM5rbd%Wo&Kaoj4Hw^hsDo zftaTwc|ey%i51~8nd2#gGhhgh(C%8ZVm(`C7Dap!nvUS$=g&NqExKvaMljDyP at DJj z6|hT!N!_CcA+I~hnNEgZa8m{8aS2 at rVjp-kzpPK+_#mt;w*#kWw{Xb3SI z78PZ{!o?Wx{gKALA9ca*pB>pryX$j#?Yb9=MGNn0ju>s>DOyLhs6$a at F zYEIA{YW1Xp22aYbATA=*CBN$CU_YgR%<7g)@fN2Wp$mMH`yfCtnd=_6dV#^aD@<<5 zNF5f|GaO#QFm7kwtpyUo4s1vLfqww?!JRov45|*%gICoUwAoycUyAL20f&}ZxLuB= zAPesaEN{$-g$El1=z65bf~)9av18US24$OW6*#WN7PJA0f^yOkN$Z+jnAltdo5Uf7 zrxxh;53IhU$>d~D_aSI`nW0|lL at kCckzTL{q6fB03;5Jg-Kzu^D)lYw06C)rCC<>pnF;9+wiU6(wJyUl z$FW-CP74R_&fxJRx~duc1Y_(JQwdjh(hpvhU;5MAX6Q?E;;oB5i>t8Q-II_ct(a?<)k~KTA0k2k}}#h7tQcL(>E1B|(DM zb7HVzXc8Tal&_@~Jk!L{5yn2}vq)juf;iekt-&Xdn7Y9)VDOGJv&gHLC(V2@5XSR(xUH=lQN(;VEv_mGXwA$5W!G1zdY`>I%d7zxdQ2shQp4cv8TklXA>c;BsQ zdtf{Bs=seMk}-G#fHb4Yg)yb0FLQg1sX>E{2}uWrpA|VsP>b-Y_gaI^kV(&CVolc6 zYUheE3Bvp3gVy4DI!9>?@P#S{4O(*W4*416hCvE2`@u9J>4dhP#(xEjk(G`|KER_k zo8~xC;mfvkg~6M(m^2tV_;?2=UdE;gL{#GVt>z=ip>9#(YPA^6pb28F%Cn8;Bqpc~ zcw$VC#g7@#2_hRaY5m=8!NVWaJx&Jrr6Kemmf-}$HXJv>Vcz288VO5rn+czC6G+6_ z3R^kn(hrr{UVMASsQBV3B)=Pj64&xx at U6553|_F{>O9zN2#o}T2p31+EKj}(5Tfde zN1Y-v`pU}8#Eh)7pB-+LjTwfhWv3l4BOX3NBtFcNb`@Ob6dL&3TK52;jEPa0bvV*- zW`Md9Qz(ZUg&au_q>JKmyJ}%~At7nNVo+~5vptONnh0_il+-T_uLnupK9-3MtAyI~O0X#3mR3QPo zem^LibYV+B5#q;2J61?uFDb>2y+7bl- at sk!1Q#vBN`qJUtMdB}Kq}%yg;Ihs_W<%p zgB%bG6DFHFy243tD9Pz_8Vn_(o=iN6DNRNi*HBIt3{Z~#q;}4Tb5ZWpVj46Q#v0%! z>orr;1Yqh5Lzu*&zbMAK+#busLW4gDg91iXB5%rJA;3Gckz`N1KTSn^9vqa^eybZK z3Q=|&B1E0Rc}6qXs>UTJLzmhHBoo$2G8K;SWNdUi7!nPEgQ${bDW)BW8 at 7N@!drE7 zri*c^C4XKxg8x~pL8-#={(?D3E_~gLDi{VYD)I8RbAO}!dW>3}noC5b4K+4I|Dpey3JcfzF_Y7S6K at hZ!Te)sao$Ftuy(q|q2D%7Z#I;J$DM1&NNs zht%N2f-tQEcP>P#X7Fi$HZ2ZUFd9Pc&c*pgF)sey1bCANnOapdhCmc!<|?nH2TrR! zsQ9x9-5CY446`Pi6s9HZ3MAPvvlQg>2{GG2Jg9y51LHuC1CqgYMG_BKB~b+WaL)9I zS<@$jl6sRf7hs at osG*lhFrqT3!5gM at Qi^p-EaTzRXA^%94BC`VwTPABd#?1NyJ4(-0>=mInz(^9A36ysrT; z!EgZsE`;GCS($Z}ycSJB!JSNlL3|Pxv|&jFL+b at keL>V}(Nk(it(}T8z zr*+tfQ27shXwBbnQjVYA4zdPgm5%!47!^Np;^jk+J^urNg+2xWz(j*#(=2$W7`|Gi zTQUeM9`usjx}+nNtU^rdlmY7 at o%7&?_j-w>O at wlw0-3N%PwzhT>|{6 at 3d@PBQG`Vz zn=RcZL4%^{lHkECNLnj608O$F_ at cY1t7h_HPPTqZ?JLMGe|DmK|5j#Fg)b17=xCg-j7lc`cq%p9hw_{ zjKOfrzX^Aw!@er9O?I+gbc6mlM7o1G;qA*OD)cdU0>8z`&*pUo!5dXLTY|MUxH$9{ z=>=mFvc^LZS({~K*RI25P|V1T9<3!}xStn%%t3-N5;?5E5Gdu0nLR4wtL?1CQG6vk z?UKYDnO;yKrxmRGYv8bpJ_)T_f*Qp)wm7$!j7Xk*I_&Sy$=t=D(V(OhRE9YEZUHeJ z^rix(=Dy$1mxxenuyliESZv)OiO^_pA_Qk|2w93n2|omiW6+MR3=hk*FO5DZH{I&mod&$xND>Nor(vi%?0>Q7Cex7&4EEhbing zcGP8Dzp-L05$~gtN0ub|>+WE$9NVCH7zRV&kW++Fi?7DShQj9-GvYXOTDC{xgh4!( zPMGkIz_6=}g#-yj8Z-rN_wriRlz4|)1B$5~6!u$LnE4CTMP@$~GNnj4N?{cMN+q5w zGI({+o1~{lmSJ$8UH+X;>nK1}hrkp(l_G*Xai>!kXk(FXL#X9fr*siteNq^|UfLH1 z;J$||)5oB$5HlutbcIoaxw&+m5&q;Fn z85$W5wGWHG7M8idV1>teK%zLj5+$ZWk`j^butS2zffAmcwGLM^y7*Mi`mL(49WmH@ z00|pGRAI4Z_Af9kX`pZ#@SI{j?X6m$!;o0m at RSJUgYuw2kS$>kiOc zB=NK2K^%FB&CVZ!LBv(7&{oPS2o3guNc=V2!G<)(jx}ym>z7A zp9+yGDRXkB0*1s#jv5Di(3hF`g!bYM7X5pO;sI;L$DwZK3M%y#1ddGx+?ZR{V1l5J zMK>#yUOT9;lbiyU*-ePV_Q(_Gt$w$}LXQV^Hm5b%1|u$xFKRLS!Ii~WsnA)leY66+ zX~Hi0LjW(_8G~e9iKQAhmg&qF#DHYtXig6pEW?r#rQUJL=hKNLsOI2U1F(%gN21+& zjNg!W=Er~rxzQfO;tj{GmZPYj7|VG{{=QcOgNxsLX3*B?u10jZ4BJofXV$dI)JpG1 z;XOumIBg3KO`6jw50()L3vty4HVJT60O}G6g8U`A&&*7AXyQSfV-m^1gE;xEHy3Fk zFuBrOh8{`qY at f~y8K*zgGPc}AzAcS>hO6nUc4C$cQB2K zyUk!xDl)JG>{Jhf0U<`#*<`T-Q34CSm;&!d7Gg{8Rvl}5CJV2kvI)nf7s+d zvjo9|0XjsrM4WV6K_U at tU}3=+*C8t%l{v)*zu%QGD7h!YPQSSM?L8Bq+pMftr2qAfI zgHuXw9a9i*klE=ZlA8>;VUvzpWFHV8pxXm7TUlSiYg!`tK^QbJaw^BTOrpWl=wKCD zZQ^kCD!hMoKjz5G1QWUqqf-)fre$1=7x~1a2HWs6A{;d;gHO{m+JlKdkyQ$FNZ;e= z)p$1NFxn4essQ1&GL}1|K>$zvz|#!>VabFW6KR?9#qm}W3fmL*;Oj;7#ryBJrcW^F zXAFu_sCm`vu#BNF>)>UzkByMlDoR*rFussMiHc$H;EYohRDtZ^N-~7=;XvbQDfY)dpffB_Vk)B#g!o at LX)xNs z at 99t17?i|T?M??VS}E at Lfl`Z;C1V_ at yuvUe?7ZL at 7dcIKw!&V{wA`1%rnJ=TdWT_Ac*lBP-+b_`%9+caxI zRyiWaY_+cu?+j(_$MCcF^TBZ=IfJgyr^9mIbi8y&BU}56EkgXNe`{N&2|y!1Hi9_e zsMvsqLmg_^1JmD^1rradD`PQ!SH$NOSdrmc!B7fv2A>93kAlnt-VQrPF-rOqNok=O4961P$mxhHVyVW%Stpn|5AzVsX;oA>Q~*>S ze6k{oDZ{u-9C7rD)82#xBrzG0vpu>qI$feGTDTnbd!X_WnJqMh`+yju5NiryN9&VfS$dWKZkU9|eFNcU zH!T7b07hDi*7S3evlO0i2r;88!njUNe>Xa;YOzd*IiS{d+H#Y2U{ZHpt%bwYgffiJKirgP!X=+Q>s`Pwn4fkEzzfc{jP$aTF(*QPM^p? zKAe+LNuLFEBtl294Cms9D)#gReY%Gs$9c2aop8x0i;(gtVo}e@$t8b4KS&Ov;HY z%Nr~5d0JtsO_{K(aoj4)@hc*#59DP6f6wnJOxpfnZOdr)*WVp+8dPsu<|0iRY*Qhu zY0f`Zk{vb4s@&%lnJ;$k>L~}t8l6q)lmg3%TS|RXIcM-Ns6U6rkI4`?3^n+w&`b+| zOlDbP)p)RB3f8Jve<($sWmyUC;PF|G{tdu=Z#|qbD9OME{@kBACqh*twerx?1}uy2R!rvm>;X+>%M1s^OCWzsO?l%}wQq!Oxe$ha`+}c~#a{kRuXRB7wi_ z*n*~H5Zv-TlFFcI(%|;Ys(6csavo at WZclNfpSnc%<1m;!nN)^d1i$6=q!#CXkU(tc z;r1RUYwm((kd5Ce%Gja`34RdA@^iw1SmT_yIycdr4h6D*l~3N6V-)C753NEh-Qcx5 zy^#qw?F=g#>`q8zHbUry5ZQIHJdi!|f7Js5e at sW1<|LIGE^5TxnH$MfmBhk^ zp-d{|;k&uQ;Sm^A0BSclD-vfH#RZ5I!Rg%TekVAw{(ipC6Jmo^bg-mn1aqv+1B&r* z%u6bJxI-*} zvFVcqrep|KkL8 at hlUdjV&QW_6dq#e>7B)=`A#!faOgw5D+C;*Fg$&D?)59ocp`36T zY#2&J7mAY{9 at D#A59#~76nitM#km{ZuWE7;D0_l1c1SAhg+&-kb-?0}z+i1p%Yib0 z;g at Jo`$5)anan{J*H2-JWjX+oG-yQ`f&RGcgYls3FP#9e{F?+6EGxKE;=t at ya3HI& zAFnU~kUE}oS<8hnB~d1+6BJznGHBOxL16Zf^2$59V|PaIL2!u8BD^&bih028obhjD=|jPUASVkO$0JMGhTOSu^*& z8E6ydKU8IJ0~=t>nZb}GM@*WFbds0Z!S+Nomf-3SBE;wi7s4+|;#_4(fDHo;}h4;F%_-AdVLz(UeG)SRIc3uuSTr2^=#8S~qwj zG&sbK7h~oW#2!3bq_gd%7?bSdkd3JYi7sGo$yeEbf;Z#C;w4w&$|>xyAWRv9q2&eJ zDVZq50X;wZca|z_(j-c9$!e{WV$t21)1~6kQ3w$30l~ncKbW}8MO=kQS at sGnNJKk$ zHYA}IN$Ygd4T?nW7GUSXvc7)2zKSM}kMw1zL;l!_=QlB!`@jXuoVT?|X2e<%FIIxR z9w#U+thv at 3mbz@%Gjp01SXD_nWb0Is0DyaVW(a9qG%=Dh`@apjDfAJYy3^?VF0(SB zgR3uH0+-_J`^25?k*6`?v#iuHx)mvzBQ}HL`;f4VV(|M7NECw>Tn$%7YVgGZlaQb~ zgKZAX#dsm{DHr0Cs9~&($bBF&sS%#$F{cKwTZ;E-2r`4@#3Dr|&PY-r*2t>PMszes zOHj?hQx4pW^zx8IZJLuMrYbgFrgK|KDBu`{7?i{_!7MoaLs`)CgXBRe!+N&Ir6Oqr z2P>nxN^Q05!BTDgJoKo*2r9_5WKPHLm!}g?rb(vGn65a}fxH8$g zj%As+C=m=utQ0qC at XDiMR3TY`j=LKHemXO+?FnNrJ)r%G;tQMR`#c))0)w=qNrQqy zg!pvDDZPdAO3QC=k?Gm-~2r%=NC#}$Vv zzzM{pgb-|_u&+yGk8_h&P|GkwGiVAsD2%AqW+YfpXb&KXf*idd9{%v-FY#tlSGd%l zE-o98pcW at xti52f9SlW+xm@{rc1#KdT05BQu{{1p`EPEaP(+Cij9XHeM{6DYX9Hsw z!_{*+?*s)6i;BYN1_ui*bUE-zBo&ON3Sf3`h)vOR at +{ zHFmH1@{$B~atGayiCcB4XUC#EnwaRc60C!g=F{jTwspQsZ2Ro-K1xw;#bhc3k_O3w z1%8S?z3DZ811v$R6IaDR9PODl584B8o at G)Jt0RY3{e0?>2WP|d at 3{N_q0u~DScr5k-NX&n&QHm1a$m04Fo-JDCX(BR|~5|bn}W at f?RSusv~Or<7= zGuUbh1EO)lR>9j8Pbt=s+(lrphM#<+tDI&K_G!=()8!u9BL at wZu*@sE!IEFy#R~K> z{lOoHM(GDlfMm>F#a44(#{3xO_>&50&Wfci)Gq{&mRgvyEVeVJbv)9^D~!kU=rErv z&a^p$pLaNYUn}vR6r5t6eJD{H3+wHsQt?f3p!}4~S|UiLJ&% zIpgr(gA(H*BtH{_E=iVb#ayW3Rq>Y%LWcKiS-i(rWpN~zW$go5h1W!fO+$tpcyEz& zM;kWVBe@#YcS;nvKYngjRYKT}n8}Sz8syZZhdqiBt-Vr;r55)X(BSBge<+sBUU!+< zk7r}=S1G}l__!2#CxRhaA)jbkD<_`MpjLWG-xotw9r>4R~?OmGT#tKepDqH$kXWR z6NhWP at Hi%W0Lf90$|6A5(dqgG1j|b4K9kpg2Xi;5#3<}c>zCakwtt!%;#tt1{yyP zT=hBeHgB*?&{>z38$8#Buniw=II(=chM^+qa z^u;|VB{+b8pN()%jFooD$o#Y_EEqKP at lG^&?oDemnC)pagS=@sgGPnmI_MDdWmJvS z6<8nrFexAQ1c at Hy;RbbdgBgV5aCCtWsmn=&NLOf@*scZ%7d~^ELHik6vLQFz)M+~KKc&WE$eD^*JgH{ji?%#)^ye?@RwJZ zq#W1yn*hXd(x1l>AUuxTml-h^oj&Pr3i7Ls80S5U at HY)=3(9Qr83 at Gc$kyK=k!51B z2{(`+;#)77(V;6WmrUt?0v5%aG3*&1URGn>q+8p^D>UVZWd@;07GO~ZB$$gNEV>gT z{h&t`&WiCP(1<8?96CM0nVCe2xF9hSOj~p*#MW0%z{X=ta?ss=KT3qZ5t~6yAxiPXVV8XwSHl-2IWN-59utHxp?5A!5FW&QBp$|z zGAumkYjnO%_cJi)V>;0%=Onliijc$|8UzVOK4w`(c*xTqXbm2np!$Lq+d3G}BGi^y zy^0LZm=nj4u3$0jK^)^Dn{orzi$5WT=W;>#(GSv;e$kaF zyL2xZ(ban-hz$l6{y<;QF!+{}J>D%eo}n;{5rPk*_+&l at LCjrFxYUensX7J@Cl+Hl zTPxJCk>E*7=!Ysy(*AiBKB6;mo)+ov(7;R#W@(J8gFrr at U6x3)9+sR!wae7#1a*lM zTXZ;WFtS?dL^ng=PrWLCFeSLIt{9J`0SUb6z+~zJ=lT=fYT(hz at BR`Zc%2gsiY%cH z>9Qb4b7O7J1P4y(v7A8S{P67&b*r@#OzQZY|GX$W7$v%Ykr)&(g8nvGGjhIB@y|n|>S7e&d%68Jn}ga7IurwEnGQw%u8olhE3rZmU0{`+c4MX^NYMWo2eJ(W z0~OBA!w4>9TUxeB8rvf~0Hqz|bmVkAmyY&GkwN1= zwt)Mao^dHzeY0gOyU;La{1guZAYNe15P&oZJ1`^y)uE17&&3mTEvnj^Ss)?hXT>l(Z!Q$`2HopLOO^o&;UGcesq${fr$ zi4b9O!H_0%yMYBc?oP_^h7VSSO&a%egUAU=C6;yKJ*gD|E^Lu(=m0lFr++>W;my#M zxvs^QkTL!P6qgJ=i*C)~)XcdIvqU#&kb<~I<1|?*E*AAv*J9w$!-G&IQ&Pna!$N|) zOxA-HNP2D-0(ECq8R*MJm;zaW*H2F)DXJb&!>Gz_f zc#XnpNT>K~?vSLyOZ^e#r!Am at Pz{#TXF2KZRT{#lg$50MKOKnB#c*Y=&o)|Y zJZBA|;!m;H$tmE7Eg#lNZq- at v^EGo|I%w5k*cHWgvIjm(V!@8F7$YMbvTEVA{N1m}o3`G81cgDP#J4am#43!4c3sy-o z56+!cIteS}*bL!Tp3#m$iJ>sY#36@!rC3u6Q<)Xh9hC7%TyfYSPGBvSmT0rDQ()$@ z46`L<{q>|mwyHbSx0wvtpo!xtV3O2|@*C$HJ%7U1$T60PAQ_BnrERHnipJ((nqzlc7Y(&ZJBiu?3#PJN+N zVWO`oi~Ug~s)@TZy8U|rB1-QFRJtG;8mJp3qw4qaGDL>@tO#?1WHaK+;^cHfLRtI_ zvl_A0XbfLZ=BAHN5#Hx<9zW^C!4?M7`pD_EE)7Y-vTFqx$|U1&Aq~!9)&v-nJ1xB- ziP2CPinug{mzK;lPI1(rr4(X7_pnEB4zfcxA|@lwpj$H3&b7V}BTzZ40{-)Z?8ZGmY%VrREAl$(c zV8GeGFX;t?2>(n`f-{eNT6`i)EVZTMVcTFL6*fA;nMf26niWXR0vhC9(4b`neO6pU zam3B&G`M5&F-2ckP&X?SWnjz#ytAR at 1!X#y1W7Zz-y_B(fs-j+ud`ch5c=5tnCA-) z^`0Ai;_(kW`}gOk6$FEK4_c)wQy1bSO&ai1TLw>kh^8?4)jA&*J`8OFV`c&yP7+h- zXZJ^W6;W~&>Y&0ziGxQ4?J$K=x7eK`0 zVI?VpnF;mCpFoE)FAnNEQ^Zn-Ybb*Lno`7gkJ*Gp=nivX_JdlA1BVivmNU=ImpO%D z94|ACu|KjSPogubiKkJdhvQIeLY{PYYIs`4!`cXX zGswA#PKO733A~v#c-{&Q==x+j0&+xmi0Epc1)0|3jD&i)WTl^gU)f`NKFd>>B)k9T z>f-LnZW)H~W*TD>*=9mDJ~?Jp4po??J>(`&m{f$%>}k)dmWOdF2fnaXERUlT4I%;RKL>}*QD5)U zMLlkJf~Ja3Y#Bo%dcZ&&$8?BHOKxG(0<7Q at CDNk7*e3=FHcp-<3S*BB4?`^H{Ynp* z64F$}I;QJ_Zm88SlGKvl*ZD}xomOw!X%K_qdNu`6Y1A{;#OEYojOLXU% z#Ex&J3{m~jKp$Gdxc7C=bi7vZUHf#S9M?i4NMokFKiCHHZFt0_SQN5m`LiK&R*M~o zhC2};J}a(Z7&DRT0Q54edmZDs7mt{M7jv|Kk6!?PpBMbWi%PsI4jc5R{O5376o08P zB=@a~K6eJ!7!sQ#p6qCuNq6bm*Qn->~2=WA&R1`+0_FmH2Kb(o}QkPI23 zmh_sszvG}cp};U at G_Bfd2W_DkN*Hm$+{53KFeDaVk=A;~D*N;GGnp5!CTE>QxHov?o3ADPsc+a)>!16 zWmc?abz@@8w2WjF42CBoI-x&H$xMuD?H|E;`G}c8 at n;>O?bTh_GM1i(9gWYmGRBn( zF>uJi$P-E=Qv4nklw$@DE9TG5 at WAUjeQ&9g{Sai11&~;B)f=92EH6UO4$Y z>M-5uKjFZ^bVWaSeW^WN^@JIB%}MdB2W-trCJX4Q58=YB<>Y<&u{lZSa2eMm0mqS# zr3+`U$l{6k8!@O0K|CgZFwtPICU1I+woiIN`>CMUfTFL_i6jOX<+;RQKRf_}izL4W z2G7hH$K1lPuxXNGTx at abR!1nt;OZq-TtZbLF&t5gTH`WWgu8lV#2THANW35)^2GE9 zX)uJyXhRXs?IVFe~w;@^C4ZpFY at YH)t`!|5K~=pR{vtHf3-upsRp^D?r5K#v{huNQI|iri5Xe=B~WP24k at g`X*PkeYAh^R%|}#_V108dqv972yVMdK?-_l6Iu5~uO%$>ROtpAflQu~# zSha#HPTddM6C)7HWYs`FxKKs$nk%s$@6j at +MG@PXtEC}q@}HiA$*=dvv+E<7k{>7( zc-9eaD8z$tp<05&1qW{6!1CykEgt^Bb>bJ;a3dI>kj8%f8F3k0m;Rt1E+brMvY05W zGlNxNi^Jm8*6Fki&ygIQ7#WNwj!0IpyGfj)`&C*i4qDwmA3FH+T$x89Ns+<@U4c%s z1!XRGLlvVTG#7dxIzAmFoPWblLrpMq%LQC{Q31)uNyqr+ at Z5>P@)PgK|K2x zv!GCrr)pRmLeH}Goc_gPK6<*@Z{3 at QHUR@saM?X}v;$<-a1{uzT;U^6)=mh6gekPf!yv2ycqFIG!7}(QUkyioP=QCx;R`;B&L$(rMYW1OT=C{t9JyzfR^PL|!NmS0V1pv}4q>^oLfDDU2yiLWInb zpVl+p!ih2b^(66VcccE4+FO`Wqgzuzu^e?-4C;rFA53en!MIw*_(2V_1rWuV5&m<3 zumeD>FJ)3ZXprX&Mpz%eFA4AeLM(XR56Y3N(hatZ!L}F{?5QnC02&9*R*gHE1s#jb zxfWMI#7g^U&0wbjkAv}|(x70kbY>V^C^xA9_`CzZ79+SBodjlN507mY%%& zD_tEP3>{+IOeRJe3ZxlUz+^67=A02cX2%*@ZId95Ig+Sg2Y`~?ACJ`$>S2!SLX+Tu zOoLG4q{8GAbo#9JB#5tk8SXE-vnZphgbFhe!LW8fTZ?^wR*J*AB znz(cLzL(^NGdKf#dsv3^yUL;#U at 8i$hjKEyN-=T at L_hGiTZ);RL3)3{F at ujO=@N~t zdJA}7k7Y_XNINJ=uG|a`hCVrK^{FAPErNp~LY}W!Xh(7e$DRLT-QXn;u08mvHC^bh z*%KZ~twps+XFk&E1nmi6np>R>gbhW)0RI?N$f)2jjn)W$UON?vG>*sNSY)e?DgcuG z;mGE=D}P%GY`FkwM+P^gKD at +ajt>PxTn4Vp^Cjls3xNDn$0N9!*)6gk26WjO)MFJI z;In*SqZ4!#hCrF|vVIC;eI8vB#OwpB%*>vTo?H>5H7v&r;+VJUg7}?|sKPLm%);P6 z)XY`~e~o&~AEiMN!vhxUI+fVZ_AokpmcU>H6rMPBP~xh;PEvtan+I2UJ2$3vQr9_N z1_vB9rHI)v<;71~os|qHq^IX at 5tapF%8{M?<}xsuNPT*h4U&oMmuRq9gW3_^g5Q=u z+6GfKA8DcR={VHDAg3aGXyz49VImFsKHcZ_E5Wem&A1ue{LtjV-105J+X at tF-zVi5 zfx%VPu^NL?j(g}M3g;-qMSM&s!O;>+Kr$ZL{h&oVT_Mj$&d0^clG!%jW{=Oe zV2Bc2PWC+%@e at y=JIZjBW;xjs26bGLBm5Pv8iQ-Ch+)SV4eFRUM9C5 at pw?txAK|=Y zU2|9_A1_#)tdM7QT^h7466`T?t6h0dnJ}P+!YoJ(uR0gvlk#gg6iy6}5a|SqYn at 19 z(4e04wrzYiY&;Fok5+iSenC$ruC6ALHR4>3Ju}$UBEX)oAd4z(E!ISduT{iR8a8SMqhg)t#Hv!-$DWjKO? z!;>g4|T^fWToiZ~)gfwI#I2e0NuYE|T zCl3BHNd;cbelXEsrHQ>WTvx2oHCw@$+|A+6(3r88B#WH}sf5o^NGBR>czm1>NkZ}i z2kr+AmR2wh94yDZJ%aqqod)dsu3&;8)W^UW|Da$@EO?&ULMwQ<(qawT3dt+RCE`y1 zY6MuW77uC-ZWz>+Kiv;c(~Jp3QVOd%V;$hC=*!0{oTX(9jcf+X34hsB at 3>J!!OnBPKtH0cpFu2MM z6-gI>%i8J)XFcQ+%y^VubbvlMmLW-IL5CtS*w)2-D(4hO4Kl1S7A)FOSSzqb_$h;x z2}yxO-N}5;0q6DDCnQ%JB>o7TI9(=Mz at sT-SWt7U1$kt{U+ppsu0WsCAmOL@>!h`2 zzoP+IaJa6lyv^+NI{VT4RKwuGvok%Wnft_(C%4=j9P>GY599}Nu%IF at Dd3CjbRt1` zgtavt6nN&zAS#2gh at 7&8oR&QP0lnbsc>M*NK)D*VSdrK|cbclCF3JR8dK}#v-5?x7 zlfor4y(apbW>_;erMvP5n`gTZCGMtB&yElD+m&!-hRT?|eX)Y(dD9S1c5> z_8zc%YVrNGX|UxF=4CoHWrX>9NtreB`(X{DAB-Nbv%>^K2Kjwg#pkg>J7ZOVSST<= z$~emR1mEb5A-0zW{~Zm0Kw!g at v9lDYM4}#xGd(0O>~w*Cyj$!P$L)bdJO(VKW?sKG z3 at aX7mKcUCOM+mozjAA1VvdUEBgeox%vo{m$|MOg$DCN?h-Rm|ku4pIOq3u6j)TE( z%&hnDCC;%4zbZC!!h;S(p~2|?Zlty(wTe;QD;^Rn5916s<{1Y~w}!>P-bD=R_DH7= z>u9dxz;yDtgcHP^HcJNWU}%vB5P9bBe4$8)L`|;Jr>;*X-26u at 7 z&kzV9ER|TS7;&l78dC#&puiW`he?1juzPM&lKptWU(}o~m+~O+r|H#HlNp=NNE8Sz zfx at NKbI5JuQW+eBF|OOz)Va?dKet-W+WGW9xyn`5pOyp$&{$`VV#bM6v+ln1Asz(dbomg ze3+ADbEe6K0A9)qmU;2>h3LYO-9Lo!fj&L$?Oy~2S3#gcu=b}{!(;_O65_n-MF4vA9{T{`2?BpnAbKr^J1qdL=fwS<5L$%6gcT_*9nL8s9!j_+ zOTd2;UG1-s%;3WZqJp at YAJP`4`7q`pU_;n6=FOB>>jqnB#CaZILC!-OD)^)z+jAd+ z2}^XfY|-)XUyE#&b-I56iX<=?fvrS?Xa{S7+`1yHrJqTIfjOySwj4sj7In&tqfN*sG)t9Xf>z(l4UwOZ1B{Uu_Zbw!O;hr z20>P)fbC(?g#cQs4qrMmn-^jtG5*m?@`)bi3R4_27&3T^sLT>=pZJ<0 zH*IhVjO_z7m%?wnZX27!GyBRG&OXAjS%&=g=Cb-h9Puo(npQrD=!EhIjJ1`kg#4tT?$IAVgYD9(H&-7n33dQlhin4={G z$*xDF5o`fa26kxuk{9h(O>zcvZWW1nW${b%3E at wJ4|)Ci&ETtGFl{f at o-{deZNd=#bf&-+ zOU1#0E19r&`N3M^&~%89_8 at 350gp^b@|*Oat%tx;@mC73nlpFUk7aqVVhqq(a=O8R zB7{|$l*d182ujDpm-JktXFT=cSI1slJ}(w)CWRFgcC9TsfKUg*ZV1YBq;!7?jU}ES zCo4>Sb6P4f6I$ZTBxCTAT0z7J2l-1<_ at ST4f2krjsnApV#)=lzI>}DUNvmoLZX1Wh z$C(OGIsg1A!sOQ{z;acyy4GlpVq{(Ycr6Pl%=wo%6hUHC*j%D(cru-XJ at jY~*5O@$ zl*3hZnJ%t5wnaw7RmU+1PkO(ROxP^R4fG*AjTxOOl8u1uN)qn|b&oS>ka$F3`WeT0 zlu?MBI{52f=m%RQ*w7 at Y4lmRq(HsUB(uig?mI>Vy-JsQAH3m_DPa}gGmHB*m%=`O* z$QJ2uj|>j%3HP6=NRs$Uy=fbi49bPwmQVoc9pMH^A{X6iB|%xFGjlM|cYy90qv7(* zhwX()@vkq1?UGqtvZo0~4n~$kfYc&{N1g+bGnPB^e0U}NrV50!0+IaJOv>1Y3QuT|NZcQU_>4o|I3+3POshA| z>G0>Z$^EZ>!JA2rj6x7bVOx%@46fRFgE0otg6xW9t?-uy#4d{)ID7~XYHTou#giSn z&lYf?H;8Yz*zVZ7b;+2xrHS*)RZhXqmkEk`xRUm6pJF1Bi%!N at Y) zIcgPsA?G7ee^>FOSA$*_#`(ZsW>>q#cqST|o<>||r#&FhCv=q}7C}5 at aUv4=tOO6D zMv@=~@re{U-yvaCTKUg4 at rDPqKhga8jBdYv&9n?J=?B9Z%rg?P1#54xbc1*@EHYZU zIzm-a6Ce+r4p%z+(p^tR&__2$3h!k4cXCfK%$PB`f@%vU;GMfNvPtYRI6H*Kf+rDb zijg3~@(@HEHI2DQ)MGha at Yjw`+f{flsbP;QtgC+80AaaZus;X=VN*I*Vnw3uk4#>T zZ!9q#w<8(wfZs62mj?=CJo4Ln8I{C?AEXwiAGfJbBmB&0!H70nW=lDlo-BSg6bV=A z;?ADK6tV+hN&i6n)uDd{TVRhCjOEBBOZghXlKxAUI zjEhl)A9I{UJp@(k8Cf6 z-oGFOdTvI4%#T^MF-)mx5TMrKS;r%p_*%W7HH5HaPH9jV=mL8a5O~}k7GWvRkCD$p zl%`O2O2m~W@{%m65UBZ>;6YoSb8pc0+Z!ZkWXKr*D*_AU#K9NM!Ot~1o~@?=unT_BNK%(l<0K?w~?gsY$sL77!(us-6bc|D{p6iMu| zqn_A_H7!awuvSGDBsqPqkI8>lk9oL<8ily}xtRlh8>S at B64=5vaUn%iU_IaH^~1w5 zkH0Bb^Iu-C>EmO%|G$!~-8fLLy8WIBhRAZ5nwntc^-cj{td|r|#6 at 7#3 at 4wLFXt=dK15J{5?c zmmj~;=VeP_UDue4|{rkq at p}VLs$?vrIxT&m`Q$JQCtP5YkQ_D!l#2`H3p>) zKZ69TGcUs#L~QjZhGiZtB79t8uz_3QL4jY>qQ*T!T6!B+V9S=y=o1ubcwdh6=tWm& zQ6n-ej@(S4K)FB0#FY$j{c8bgO;BGBNn|b;AJvkv=)PjHmzS}#R>O$d+?eJ===R^3 z&HY3Q3^dgkJg9N6#qEZ$#hs=}Jhh7H+{tW2;#!=J$m|%zs9oVyow&-(AP<+hFsFqE znH%JJN4pG;O6+s-H{`g#2p1DeETAw}= zfh`rqKLv)ZVq8!;e|)st!ABQ^O)*kwlByT9dB{pW40X&RY?;**QTJ z1gnTv-2aS$aZQAemQ2b22TcsdR^7 at Bf0o2;CS3Up98D#t7zvvuW3R!2(-gA!Dzz$y zdyKKsKIy><2NdT*g at eEl71>I#^nJ;$DUziDM-R&kTwuy2dD9BqEyadIT7$)viKE_P ze~!bsqKo744?pv&G1x*_^`G==ac&3Ksu#>0SdpLCUrvaP3T0Y{W2faAOgXpO-Y72N zEFBY1crdoA;!kJhnAHsmK4fOH8<=Jz?F!s1#sHpjo^CK12R6aC)f>g8N}?M)9!2u` z|903VChPrp`V(XNkrAad$nPKedcuSGnRHad9VpslM8B0`o#t1a1y>a#)(Z;sdH{?Q zwj`-FKMDoTk7ULe_oY at a6w0JeCD!t6nC!z)`atS(z9PhYtBERrnzgdH{oh_5ITWAj92pqyKr0!F&q88iOb0*f-iSGI3Yh$8%+u zc%9v!o-Mq8A&D&~IE4`AtZvF|I6ssI3(_Wm+^DRlz2OP;@>g4;!y1Yw^ARwiClw+r zbELM8V~$i4ogiN$SbRbpuXHL7|R zmU-r1`-v^O<50IK!B4~Di^mQAz)RRGu;+|MK;r9%5MX?+{)aOU3IGrI*%qAyWR{ec zG3twHUD$&Fpj(5qWhwyniEyMr_#g`XD4B at _xU1rc40yDErhgkQjj~|X6Z%+K-wPdr z6ulp8u^^9>c at mK91cL+*ag66bq>;!^QN+f1<-_0PFXf+km;Srze>r$Cw}W89c5Kzk zt|(rq$<_s`J*bCHW05%TFm(#?V at B@>COoWZDazzNF$ag=0IN&In2gl?cbQlf016`l ze#sJa4($5VP{F>^Zp*~xPyhDKgO<#XKKT4$@Ofy*C*M_2OD$uU2gRDU)U;RSDmJLH zm}3&k6ISE{Z0mmPeq{@~D{}(E2}e%bkZzcw5Q7UVWjy#PgRVgKw}${xDX?3H<7N{I zlnC`un9rft8PQ1}xKW7cvq%d5n9+Kw1pXNZ?>hzqWr{%oTf$)VpZTSk1u+LJ2E?OA zEIj at B1;f)WjHL=^YbLSa*)CnBNN}1*w0`UWL4^vwI8|AME5zwWFr<0DR-AkJLX!2z7vow2e|}U|BJgqy%71pwgPz_`B{&u2 z@)$7f1EoR}iXl&e2Ni-VCv-&;`+%fn%cv_8#|%#K{2RPzYpD6bp`1fK)HE14M3;!` zMruL#iZ{?;3hi at TlCkI;oKloGc`g&Zq`HASK|c+E^GFtpRB+m(3a&Hku%J!K2P<1M*RSaG)ndDhINC;kQy#iKqC zuIfHJ0J-Img8%jEaN~R}Pw^wO at WMHR1#>@biLOCtW)T{?x)?m+!D^|qbAj(v9V-pa zvw)Evb%gr&Hi&;GY!t>DVs zKKGdJT$+>lJYefMXF5*f|Gdgpu|B2PJ3%vOvLS==E9e^&@IZO=p%e0|*<6SJ$behP zN^2PoK_Y at U~OmkZ at o?8W!l{&FTkcm}U zVQPuuQhy__MHUQ)dSYURIjuqdFc?Wu{yZ6R9=y0VyK!HJzo*S03b9n;FsGlPge5D( zDM@)&?Ca+(wRd!JFk(;seuW2VQhSCPNR*h?YyeagiXkX3$Eo{sI(J(4IDx}U9*j0n z;h zGZOeW0W}B8_>UgczRZKy*SwSBLb3}i%AAf2NO$Ha!I=dsbGoO9B{0LFmTeL9+6gf| zk8Tn#MyM~1i*0h;M4k^wd~<{%Bv~@UDGe4qEIF;CA>6r;&uQm~Bs#(BVRS$CYRpL_ zpwOkeul9pge$`8H0bnV^OAO}<{xm9sUN9BnYO$SxnH~{7X2Ig93v>WtATciNw(BV# zXaJAz9|?_Jnyny=K^u at fDTxu!irn-wf?Chl&o*al5E7t! zR5WeGx$*3!E-v?6plfJ7>r04Ce)sY6Vi0TNi`P6T4(yoO6SA&4mULmr*a!Xt3=FGQ at 8MSyF@jO3eH|02qK{Wbi1s zg$n1#r~p*TOB#4&S9lFSDZ_00)RRF>Yv?qA!h?(q0)U$yKpi9qUoa*kg1(>4hH0-Z zt_p*Xzj^#kzDxfT@>R)EH!`bWKiYyKN4ykkLn!iCj2X!b@<+1MO)j)UWj+;hd;kp| z9pS`7j!F+`foZw%Aqjye`GjUvfyRsiFKH2 at zhnŠ9EV_honHL^P7hxHuS6}}^ z9twN&3QfZFV1#8nHa+K)esv^bV>+S1&kvIVk#L-BfwPlX9reQ`95}+HK7f}NIzfLW zzvb?<%941MntaBF;t}fFNPgR5Lfp at 7DGO4P#ACr;+jDaU41fB;)lQ8q{OU*VpI%mr zJ9RkMWJ4h)#;fD61v~nI8d*J2#Nx>W?xuJwF<j2|oFd zp=Y*qV!^r$Hx5p>1B&bh&7Ywrp7SLK zO)DE_AjV^tI2{@J&Vt-z!o5E%t)ZQ%U=(Q4nUmbULT at 7#ZmB8UhD}k}Z3dkSpE at Ky z81N9rg%35WP%Oa%c|ZNAw;y-Oyts+NX!>~Es=0u(eKIxD3MwErc#&8IBn^gnPVC!r zfwOYB>hTH3?fYCL*W{}zyruh107(8z0UGp%g99(7!c}hd6|vQj!B1E+v}S(h!3sa= zDz$j60)zD$-Mp at P?COjFjY?vh6W1)rA}rp_g*P3)`|+v=5Fe!_JkndCi-&|p{m}Ul zcltE35N?dKppNIP6|B}t8rAse-5|E<%o&skv5!Z7)|mKbT*iZaE~E-}F%nE at s-#(l zWrfL-3IV_d7LUnX#Iq)pVVo*+gau1(CV at _BZ(3w}2>jd}Y at u-5gVRHeJ^m(3 at Xi8V zH6IE5;Q{U3E8fcbTmc~Ss{gH^5dC2331`P%Y5A6TAmTzi&g=@4Gt=JW%yAicY4Beh zu!WDKFk%$sg1(0Uue|fb)he_%*eUn;5h^7>z^{dClJr&}U5t-0!7>hg+8IeMQ`Rr z90wV$3dCT;0>4TPPtq68GOLrrR=pG_?8OSFjEI}?E8I6fqy;S7b3+1PnGsW+G+3|~ zm+_oJs>ef4O!tR$sKN<_$NpRym6Z4v&sO*}05^LY*ndM;#e?-4F$2>!qf-qcouKld z1QaGKz!b#Ig<^WsVaz;OflCLtFL=sBAP(3LWAb7edV~|ZhuJbGESMHKtr0xnCP9TW z7*?YZp5}32?rA5x$&~K-G!Fc4sUf5;UK9B8kggij%}C6cASNN!rC9uFi7Vvmum+<6 ze6SvWZqKPrSQ^6lQDkwC`W7&hc1XQt-Ik)(-&l1hGjUuYz^w_I;_H2k_zPk lI1-zF#))r8%IG%nk6oktnb*Jm|God!{~!0la2=kw1OTIPExrH% literal 0 HcmV?d00001 diff --git a/images/syslinux-vesa-splash.jpg b/images/syslinux-vesa-splash.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0effa488712d6380ebaf69c1d064981f673d691f GIT binary patch literal 204721 zcmV(?K-a&CP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOb} z6&Ws2VuQN?000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM at dakSAh-}001BWNklDJ=kHpE+k2JvF z|DEBG7<~UN{{H><2Y>!i{Ft9VBR}u_N0=Ex9s%uhpASWURQ7j2|J~p3fq10yEcpFN z|DyL9ec#1@?caYs@@Ma-`2P8QFSyTa;x%%H;DETl{d
vGX=l;jbpU(O9Q)dR9Xu8-3Hd^051wDVKO63;_p?Uid&(c1d|p3`
z{rvf#y@#LgM#xLi_4Uh{c+MH{=XXFK+VDJ}epZaGm7jP2ogeq-$^IbkdF#i1J!{YN
zIp=DAma=a5>y-0Q-V=XrjGyml=S7^k_kNLkE%%mebh2%jxE}q$iM1rFgs?kC&l8?C
z3EhR~bL!!*KPH#-{kd{y%Nn`wxGp09*>-?%uPOO^zmKMzm-l)7`QFFRSw8uU+ur5A
zcF)yWW{G6EO
z0^#{reEzh3+wwdG{uE at lLPMJVsju{Z5^*x8K0+|Th-1pU29a6iw_LSLIa
z*6lv5&nq9`en-g7U>oG;A5cE?tv7iNh4X2M?-m(fO|k*ciSYAGG4^w42QmG#eCw22
zVq&k4Df^7~DSXe7@$Buiko9vPFMbM^XDfxKuIuyZwfMu&?~}snRSWrRy at e$50n&@V^EIS-
zAkZp+)xh|X0KYeZ)fAq!3TQoMHKY|aa)9I>^Vh at me(iCcwfa-M0t3)@jMgutYyEBZp&eyPv_q^vk)q=wo9612a64vw2UwvzCZ_x|N
zr4eUeerNF8_xO1g_ZI_F>@XSudDd1_^A;}1Cj1lb=a>he|OpQkOf1JBkn7HYrS
zbkrvKD|#>m9fjh~e#6;?1e9t+nsj0nt2qA;l at -FzV#sF?ZFpt^x`q{-RQf;`4!(*F
z{{jQ!t{pyLr_*?p4M_t?dQ*r8WaQuKD>i=CE~6PZ+Zy-&T1DcVJ#i1ApJtMl_*?0>-AlM8>qlS3 at D8gWovWY=a4n*Rdp%vK9o=!S6!&*4!q2i7eZK{
z*nhnKAROlI+&qW_^npr#fBj!80QukZM^M&QLs;-rG$HA|Rq|l}356NU__17wHfgaKQbErAzcB
zC=Vv+2gM&gv=d%PFlydf1SI034?|uMD*(&`)nmU%@20F0#Z+#Tm&!R;A)?TYpM^@f
z$D0PEW~Y1x$a_bt7W_a1?e`lxZ4C?RSIZj%A5uN6a1aBzCH$DOW=4JiNJrCOEQFyU
zx}RljDikV*ztWvX-R2nxxzO}I3B07|1cRsB%!Rxym3NQ{o7_f+-VFY|NO6jui>|U>
z%-n!{K!G at o=c1AX-Dd1buhZo+B^P3$&77Tc$VLUi7Vs3h7}Sf(&*Qx(519QGxrWBV
z8=6+nDB2a at 5phmwGl^{SN2DGFDc$_;MnACbKS#;+KQb~#FB^wft-Rxcec at E(&zi#z
z<&L;GZm}+H0w$Ww%W|FfEX+f#39*}>bEo`(IA?#)Mt!mwybbieYqD|wOXurRg?0B3
zaX{kdHZK@v!iOF~I{%7adiTNX^yxHim7u6X^V6$s5$Df(b$#anjiO_u!vA=*
z4@`v*g3^I#TfEyo#Q~DX!G at K!`}?SzZ(TC<9N+V3#jbD^P9N(ViW5UFOHR}2-42$7
zb*WbHP+>-2*C_QQML%>(nxD_D+DR4!@lY@P$*X)TNDjP&_3U!gv1Vn2>ms9*SAE$(9Xw3xe
zDQgrk>DH`M>~#UzOVgDED?BTzpO-Z#&Bet-&M78{r*44_G~!ZyLhm7vel!`@IT=E}
z!9sa)%URYjGWYP6yaeh+LR7OX&)THMG at v}VdpA6
zDXuEK!+74g72uRRFUoR|XJh_c`)9f<*-+Z?AMNVkN1N6MP_UWdfO!fof|gQ
zkTv-G(*ng=+$S$!+PK at ed38|U3!p21b#@%5x~(p!04_nyY|aUzSc0}%2~RR8{d0q_%>ygk
z6yVT}iq)(ILT#`D9DKt6B at Lh=Mr$yYFx>;8m5A^sZS=JE+|1vM=)uy
zCDNB|o0Lu#S$?woZ1k9*;$@nBgqBMj&w^7d8K53eOEAn*VeXBh3x!gQZ^8+E6>Kk3=uxU5v9rQ=jV|g?b)s>g%|)Tgh*5~D8Jf4B9Y$pR
z8n2J`PGLiGIBoz;ZoHyb_w1rh9^*&&p3|=lT|j`cjYsk>@eY14&{Vyo=``qsDBP64
zr68+&^IKnKaPiYv->nzaSOR-+r2g;6+RuwD!^uK>8S{aF3+yitl~w~rH|_65{aqUn
z#QCD3h)Ryu*nRgItkLu~@DzRJ?8te4{`T+S&CC6Vl(nje6K%aQbK(R~~iVxgW~G9)ydNbzDME0}|-4n*u0FF+?lC}CH-
zlO~j2A?hUD;g9d#!CVluNnp$lKw+c*H
zK|6gybsg9400pJv1Esq!s4-j=O%g+JbGr;8h9$C-bZ&TjRw|G}mg(A{WN6*u{%>Kv
z96p$HD3pmqH$m-`q#dC>)?6frSxVqv22{wkt>s<1r2va~3UP3vS)>SUrMEYJ)(L_2
zH5mk4iuSSj%d3HHb>YY!l0k*rB>2Sk_g()yN^M5jmGtemM$d#f9&)C+- at m-*pT`d?
zOs7urGUhmWwR#L)*ZF&yJTI4MnZ+~olld7$2*32RA&AhSA0(iGLJ at HnUPm{j at BO1k
zi7_2|>_6C904wH=MrNnfnVK?OnaREAX%q9et_Xb at D1$FE>Cr`nY6+c_cND#`QUa@|
zYzz$Pd`uHB5RJPxVO{_%t>5GL1R9r5(_m6A43uKB*_Y`T_4E8K at UNC;|~(BCt9&*x{(+WToWpgIX3Gi*gLIrr0h3tn_?G
zn1jM(*a;=v|1ai5sq?$jrz5sNd(<5d%K4yIXSZL!D;pk>_0L4pQggyR(Udj@%e)Jkrh>C&5z7{X$-)bj2vwK*%oVxM8H`NWe$8JD
zKAeFM(Lo&)K#MHQR&8)CoB7#;+LB>>h$YXo1h{QL0k=KE_!+Y7H at HugtJQS-9FA+D
zz?W(31pA-}$}I%i+!L{7Aj%5eQwT*M$XVN7TsA(-7{02lH5K5p6`0xyZ>rQR#;|mj
zAo(-E>@J#$P9sWICaBPE
zIHVeEo`Pf15}M!PJR0C_GrZT$f8qZp=-fr^Aokr7RLcR4phKfrSi*b+1fC_p&n^O3MZ!w^U7Cn$q;NrZ
zMMT)W;bDvNeP(i at dBC2~PR$U*s>Ihn
zmtJnF1w)f1aH)SFm;TF0-0#&-3ySEuSx)m({Lv at J?eaeQU at V224kKKRHEhyek+c*s
z=A7T);p?~bE7%5Z-fEbBilK%_6k&h9&vUe)?4D*$lv at +V@Cikm!kpszvYsd6yo$MI
z-H&jQ9aDpA^#$LaM&stb=0=bjVAHI+5%JQivUxXO3hp9(5RGYB=X&Yud8U^&`P6|i
zCU+M at 69p>y996YRYqXF6(PuIWokWk38#$hBTH8>jh;LxPt`(Y{2?{Hw12 at ZeHuc!i
zyxrm-9hv9UiPlj%nGjau>X at O(CRy1N2Smmiewws^3!vF0neW|ouan^zIO6B1&GxLr
zlPsvQ*tC&l?XpU|tm5I+gksExEpm|3w6lB8v8FnV&v|
zjxgC^$YK>)tWC6XS6fnSEy+^N?ZI+xxv_Ke at Po!rKigp-`U?Q7h at P}Z
zDJ)mQ-rMmU4-8xSY-|U51?JQ|I(-7Uke9K;cj+<1ycFqz-TvS5%Jai$7gBJIA7URV
zQja^3f(LmDxzJH+xjo#+rFDi@m%M-I{CBGtcFgY=~
z%xjtJ`7#03ga1ZpF-I#3jU?j
zvK^a|g$>htNoelrT-|ZP87&^M!uh0tyaLEShe8du*l$a{{xga-EkQZutlFNbv
z(WmdD!4oqtF~)~jY*;wr&?959HdZtfUYTEsX1p@&w?CW^YRVirJ2$m45G34G!({f^=Xd;Z!n8F_5RMrQk*?%=DRkG}66HTmw3+k&kQ at kIaN}``52cnziq$w2Q
z!C-VzWXigVU+gVncT>9`g#6EmU2wF<$yL{O5W*d
zHUsuT8#;)UF_P?Q0Tr~UnRFjdNn%@nWGtRWc0&aQC1e%i3mR-dMhafjW%*1K
z$ZSxX^Ed{rxj3j1ZjP|h at UH{xp-a0KA#|O!J%?xnw4ep_Q`LhQDHl+XJ`T2>+`N0F@~zW~uo`D~ftTydd{;jo5~!W!rr?;_8U*TzR?j+FIu
zmc#@#c|)&rj??ctrRaez56I at 7g=Obz?8p3NmyL`z=nJBmT^wSHE4wfSER;pc3AQcB
z`49eA3P4s@!+U8TQ8~FLu*g?ogJJ`NH{y|j$u@{mCQYTo`3lO+-$aOC3<3DUr+dA>
zH%oR%5*)wAxXE=vn+}SNIdbFG+ryo5b&>Vb733$>c_&Yt-G@@jL??y7pW1{tx1#05{X^p<(G6qecroTUb
z?2p>*5VdHH#BC2=&qEk(9=vF5F at fRj?`WeF^zUKvk|=(XnuJM2==;syzso+R(T^oU
zaM?HgmP(Kl?-nJAxO};+YEWVq+kiRM7H4$wS4(^;MiD<3fza6V6r+DK>p(w3)DLc<
zdvZDxn-(2sugGT3KkjP^xA9_AH_4f3cbTqjMeGn~av5 at +c}2p}T^l$)4lDLC5Ep<+
zc?xMsHX}@wqU4<={7_E%I{0YcLCIL2IxyHXNu37RKo1^O0PXy;No^RcQ15$dcH8wQ
zgDC&A1z^w#J_ at df0z<=hFD9TBkdiIi1UW3(kefwnEcKiaYeN`5pEA#SHNCN^E4RMl
zaq2AtU78OFy!Z?5^XejlOvRKg1`!_5TfkK6QP2RozaYrir`kCVCX!Y`zBfwBpM8Eg`vxLZkveG#|Q4SxrS at wcfF=pKyzpct#Y>FP!$9b$e&*cftAaH!ZY&Q(PVe~TpYCdl
zqdQZCI(4gPh_BnF<@@7JDwYm*BpU5`Ox=N<5Q?7r5gNY*>-n&*o07mWFI99LZ;>W*
z&Da at J)QD1tUX1nj?4gH}#+;~{S)@!wHOr&O-Wo6i08qiRw9`4$(1`F0g`-Q8
z_3V>K^b;w7gL0wp;*t>KD`Gg at FKl16Zi
zP9y4N6$~rN=`KWshR222yR=L*OA-b4j(n_o>G~xJTeIvFqUxSL+lz1tVtu7FT--X+
znE at sGhLH%e1hYvWHXK<+vPdi~O!05ip-KWmU302d0sq^#$&%eSK7L_j^?+yai94%B^4
zk(NvWPP(LhGQx!HdO5&-XA#%lV$|$MBOdPdJjLRdDX8h^mnzx57}FirGa9=|%fTW~
zFj6 at UA5+ny)r}E3Aet7$kx=Fm%^o@|==eHIkSHu}P=j325{kF(&@)%TE!Sd5J66EO
z|A-AtI2bI78h49x)LSQvLW`7Pp)#{OgKYvezebHNGtY3f*StkMJMz%<$WR2poiISI
zZVBQ}X}Sh>VfTmBG-FcT9PZnM?kB`54_lu%6dVP*Nw`l+26Qt|ji{k*;A`;#O)ZF3
zPArE;dJd0lbCt1*(_($
zER$aig5T(F8u4;`%DfHVAR2&igj4006-7*A5WptY;BLFAw7zbr@@K&^1L7Ur-tI!sGpeTF}!Cp`4mnA&^hC0ID@=8~^qHwYx
znBh=Cm49G1ni&4P#{TF)2u7yPUDD7{!EeCg4qHUrBvCW}@HDAZY8LB!V#sW^Wf<){
zuBb^hmVY$ojHn^Z&Gw~Ff%KxU6|ENSs;oQPHRJ5e@`~i$pAuVpT at dbX`tL6Q5uA14
zpBmwnuKo?epIl;Kp|)s;`66BsMh4QFLdsFME>T44ZP1x%sS>IPveyZ{*jSrfd_
zMNjvRvgp2Lq<=ST9o#ADA`v3Lij#8ty~OYn at 6pYiUr67zm@$eiastuxKNAB3?D1gk
z-{?p-77D;9q8uGKQ*Ys1s)rPwr75f!T75P50p6k5JXB#>##YXO>!JbN(~s5|V5PV`
zf`SV^@M*;8+{Z$sSUXgJqW#2rblXt<;cb)l94vBrVj&D`U1m|4&;93OXGN7?4X01)
zBf1sJV9{%+$)`bEM*y*3kLl6khIOM?C68OZCpCJ{?u4GzYPLDxlB%d*vQHW}Io02P
z|3_jQso;ghiP01uy?@c979FVL+`-E4_mp+I;zzrjAp;BYT`+vw))FSAS;D9*J*I?1+vT=?Ux3om9fi_le){^9bGvt!4>yEg!Nk}GTqGR5s
zJ7kU9yhXM8VtrjM*VNL|Q?)bIG--&gvef=;8jaW_lBZyh6rK*CZbxG#+U}?al&gy)
zg8*4Dcu{(bTi2CR1j6 at GuQI(XJMLYCR
zG%EC>amDiSQZ2II^>7AbA`r7D2YCg~IS4V_5DKCWqU6JnT~N
zdvgI}JT?+}rt1rx-HxY4VGyes$Y?xjuC)AltT>PSdEOCZX4kHoILj&y1${4;R0s)0
zvSM7ySGcX&ibHLQ1Yu+^ad#|?h-sE(^RvjwW<7;pm?k|-X50u{WV-)t1)%GZw_x6T
za#+`77!G_farmV1bTFccWmnZ3Mu?~P0A&*BfkCuX001BWNklV at B2Z3}PeC`wD
zlDl9-=hxIdp2Z>hYM?M}P|X6VNt-^65tggj;_MV&)4TAZItF{ku at f{hp0Mt0gp?x}
zE%wC+T}BW}A`NQGCY1X?(dP}?Y^OxfHEv!c`hSC<2|v4+6;%{sjWfNRx>UR-%rdvM
zAl_erJlpX8&>O{i-Uq8tU!)(Ikq=1P{L`Lr)ItIm4U>TsePO7s%d;;`y9 at 49KPxPe
zzjbbj&nRz3H%qGaiQgmr{Y_lnMVQ8y{=~051B=b)bo+Na2hFZ`sB4e+EYr0`u at F1R
zpOwOjh36P`b2yF(+-NgcPX|`WX2ebrMSg>1Gxd;vG4s=`igrZei#R;J8hwJV5T0bnMW(=8FWMb{iYxing$@6Q$*TNbL?(5FeWdz
zDiQX#U;XvpRsfokK|4LoAq#OmL#f5Gn6Nt740w#XJD9!f*Xtw5|}24SXi{`cnh~>f
zB92BFXJy({pGArIs-!ekG at ng{6_^~iAi^GWa&j{CEa(GA{k&WB$)2pd7s#%RTo%BG
zW|F`zu5~gp1L(=d?%6q&)AloIg3O9SO?r{h>G==6-9sV>o!dMHT7*)jP9xJMbnAhp
zlOQ6RUqw5td)sFBIc%rie)9ck!*KAdR|7sdq3>C1o5i2C-DoUDC-{qyAw4K%FWT4+
zbKyFoaF_$^N$X6#I0oWGfkRyq^eP^HOD}IGH1-{eedBed*l;a%7%cRijsk7Xfco`P
zvxAFP5(O!emY2GLg40JRi?kyUs)YwY2Ys at UI0R|AX*f#ON)Tb+9Lc5wj2LnLat%ZXpK!
zqb0YZG8ooFrQ0D1Qu(J${jCxByp$&Vk$ehAyX*Uo5U9ppLgG04Bo$>Z;
zn(H+H_Z2P^8-(Yd7;cB8Ke+5OSIV5QwKS>-!krjO3!faCFaGae@=@c2aaqWxt
zYw`u|0=Xg-7cCg~wMF
z-1$&N4lz4DVs^~nhahoY)_?Te)OlObPz1$m(6DK~7&>uq71aE+c-T6#f4dW*I_)&d
zj-g=XOB%BM(bQPR|65joN8Vo3MXm-kK!$aGEyR4EnTU`d76;ZPui%eHc>4R=F}FMZ
zY{`Xe(iZM-`5+Ip=~Q;WKmpJ+@!3p4nIMG5>`OCQ8kN1rszzOqPfoKENK%!nMxeQ+
zh{BgUo9kZ-z<-OpJC`zdw24hv2|~7zek3_VKLDv?`Y;;uUo#Lfh1s8@`&%9m#IMu7
zSDXxixb>dpF_+9~L$nVFoT8C}sxTvoQYv2R8mKtA_-YEuigf
zgQxZL=QL)C*27wOaK%YaX4~ZfucZX4Vw+b+KyDb<y&M%NQPa&ekVy^
zluF+v`+!JD?z!PnZMBiZzWXpU&)B5QypRfx
zpGBuADgJQ3bZU0kIsJz8DI at m9utDN$wL>lhe>WC9hwJj&e9}+2&#Mhc6^eDq6%=j2
z!vvg}2(W)wr at XF7FB`HS1q^51nPMx|ygOaXe2U{WDBz3wOwf4_p~
zpHX|QeJ13W??RESY_yWhBBzD_ at t9?&ZNhei^E1sA`Hszm
zd~E7>9(r>YWdTZ2hs!W%vn*C2oU{p}H4Id7UiD$a9x93^l`CFQJxURtq4V|ei~zI96DS0u_aXRkpfj|L&4`=qOYM!hYtgjK&m
z6XUuQemxB6mn4c3gY5~idP<9RmuPa9 at YH?f$wqHhVsmMAOvlKLcu(k4JtG}ro6{PX
zxSVx}`a at Xh`Yv)|wEKTdyO{zBK}#TJ=SIC>3NpZ;eZ|p<@!he6D0-Qt&lY#rys_Ew
zh}JdpAJbJ;DU+@
zPav0wxJ6dg()la+6yuc#V-gwg0k|AE38P?euRrPE!SsVIy#uiE0s$jXz>H-*mb9pX
z3h4iim4=5QY+xRCA8WCdxvCk>j2^ERVCHvtBy)4q49*mhVm=K+ZPg^3FSE)Ydnpbh
zZG-c)goFd!Sc6}cV|W(m
z7ydsR0%?ZNxLOADSmLhyD{f|cc0XV`5xc4A=)PG?3*17JyU<{1wtOtR{nR3uWr9l%
zNt?!Pg{_BSZt7-cQ(-LHJ#wD1%!
zHP>rz9RYfnl`F4=T}3Uk3bWc#{pRC<(bofC at J4&7jg&k5V|_Nng^Jca%7D<+u6wrj
zYDpCKGX#HYwRt9KGjCFp23V-u_Zh94K&&%W{r0dq(nxOUf`{Ul;E6uT9nZM+t^9LL
z#t*Xk`&XpL=X77CW*KnW%~WEHD=&Lorjtdup+|tH`~veDJ$3D%>#Q|F1$-3$!N8>z
z78Iqk0+!N5iFAU_Tr`dR=Xzid6h6e3G6+c4Zw`=YVT5JgJ(VJ0AtMmOOsdExrSOsl
z!x$_PBIAY-URi- at U$Ia-R?b{$=;C at Y4}VL#n?u?pIfRCS;&W7x`+sHw!{T0j5Ed at P
zMvaoSa3EW}&rAdv#-CxOATu%y8GjY110&P56>rNGo-A-YeJV2ECF>ZKpkoN at oS#2b
z$M1cAMz>y;5z;D!8AlmKsP?xVr-n~PwQE+o54)$sPPfGpLQYRALITE6h4H}4mZ!omd=%k)pn|R
zp`L!$6ZA$e_n~7~r7K_t(sGL5`;whDU7j9s$T_fZH^i5Qi>f!T}Y$
zMnDWLLC*njy(`2ZUFi>2qkz=)(~ZuZ`cM$+zZeB~#s8=l7{hr^vtC$t77}qDFBLN9
zHEJGa>+Uq5Ia|QHCDlKaV%yCzw>8H-n=#9~Wwv&P4a#Fo=MdLSS*>sAx{CcpL;pr5
ze&CX<5bx&X{LX at eX(gu8ZOyyb#e=WOF02c$Z8|w%Lr8tb+%xfjNnPCwQw at SS&J(j~
z5{iwy_K`J6-K-5 at CcjL|oq-$gVBD2x+!O_A3BbIt=P at nVey*aX;97eW^sW(mM^n1=
zTMshd!iq!yM`UL$aQBk|3X5Om>ZcZ7dmQbmjmg2>Tpjzi6)DEWH
zObq*~pC$&3?BRmKRx68PGLoOxVkyFspi7o=e9b6DiE)d0J1m{+k!TMmQ9ra7t>?IWM^EX^rq%mS*hfNT+!
zz_`0_YNanA1I*T=z9KjyK%>NW-GdlCQf`Rg0!tLUvtf5}le(9r7mXi at sDhg?mAMLsz_1&CAgt4}A<8m*@K)ErbEP`1&$D
z5&nZwwE8(hGkNEDBoaF&X3Na2a%Z80hZ3}AhHH3l;=2HS$YxC^q~B{6q2$)l&~>uS
zdvXKN`8>Po+I at I$j6ws4|K3!XfnUxGMyMDe>hS!3M(182SjC1_iq`bYg%Z(feUA
zJEh6XpM$CmhCyrKwYM3fMky!tKe3)J5CQY+H58tRXIDDy-;ms2hU&P~hpFv?om1mv
zOW3t_5Q)SEthjv^?Mw;5u0cVZF_kr(z1y1X{}ckqZMg@}Q3L~O{)|ek^MZt6dvCJd
z2Decr)6qYNXW6EDc at PE*K1YW(83 at aXFoG-oyzO?sa1_f2k7z-8o-bk6h+b-3b6~|D
zy5)&3L=@PfWEkf2n at 3U#3c72ajesBUu~=Keife#^2qKN*Y>{uNCqPiGOE)2qjCsbZ
zIJrk^EbSKL&<@{lw7d*RJL{F>XtafmQ}WSFDB199tstP_*J8HNM{6}8Jnb&Qm^)9Dk
zV}n>`ywui(DYfeNsKJ2B?0%V%$tcbK3Eg+Y4$2w;u-b5^V1ikiqZcqjVprYHA
zo0-Oa%`S#8gM
z)9#uJyiCES`zDQxugweZRUALhEwN#i%UL8kHDWCheYKKs^#)J0oK2NCrZIKEoMo*$=TLMFfjkt)M06gk<@K*A+u>%&?HqEjrh^6YbK-{tmf7OSR3QSPh|ck3gUaEq
z#-=Gw!S0w>glI?}m2K?G>tr6=TX*Q%v$6
zS^xzN+NYq3PFIFUm7zF$$!kIihC%gfak(>1S&HRMCh^dF)@C8KfSA14X^3I7A9yk;
zdEg_cOWbA*EMgnpOG(kEt1V02lTTA{y6#VtM at W{y`)fdL(}U6!0S~{i*&3X4?lqm!
zq(|Nug##1`h%`XwtO)WU?OM)-90M;G=zS#?VRfRP_USa#y0geIP?~=_YpgQOoo2!%FLKnn(4dgh1sNl*evqiP
zLQGxv*KEZ(0pu>m2Due2T$>&H-1|B2?Okwsc+L4-SW*sPN#4rD_3j!O(jJ=pC+mmM
z3eBA!23y18$u6x9!v)~>zQ(HXZQ{}n
z2Ih@#mlKmaPK1lie?xUgJFZD-P3G9q^vP^85B1b8pqqG+KJ93OCD?RI#JyZE!IGK8
zpt4&ej0TqLfmzT2`$Q;V_BK#bszy3Jjx55 at L51B-65BrHM=Y#|AC)&9v%|KZF+X&H
ziH(<>i0*G_G-mpwUF4Jo|I6pW%`Ao>1
)>&4NE2haXPk*@UXX{Okrh;xHBg&N0 zf34IIEocB~O5VPbS)h(}@1;O`CG=HRfm?3CG+gqsXpQ)}8XC?!wOg4BSYHavDip7~0+!+o?9z~t&q{{(W6p*d zM2fIS*aZNTW){78+IC$zQn4?JyXc07BsJddE|_Zq(JtsQ$&i*<1TEoaI}Jsi&^L4= z=r;|1!q%nQl?Ovz4TxIWW$LNh(eefd9>aV7OQF_ShS2x}^{^K?z9Ey^yg<%`JhotZrVas2Yqm?bAA#lm>CpYi`Dy zNyaQQh at 0HZ3vt;WKusgjGf(OIfmd2cw2=FvOkS|Lfi;im zF9PMB*jp`4gOfBNx9tZX6im5vE~=kj0aC=Ik!nHWkq2P-DZ+AKIzTbuFFKE$SF^ow zYH%SoU*w`RAC_Xv)k4i1QgJO9RnPKbOjC)L(N*k`D@*$~F-vjKtJKFN1y`cKH2#vR zRYGZ;?|xb6H7g)&=P^CT+BBgn at hSC{RG-t<74P8V6DK#@e=T*&%^;a#jGU!`=f1jk zl1Cl{-tWiKV#l`I0UjBOTm>E)u7z7PPoDGCCJFX^JTslHIhD1AC8yw#+-Usec0F)Q zH%bQwbb43Udn<6iTp}M}^TLU(uA)wGBZ8gs9^7$wkJ(nUhvK4- at 6XLanctT6*F667 zFR#2 at 4t3 zRl1!D;{Nz at n2o~bjs!an^?=a#xWks%L0i|OF#MKRtyeT&(lqi#Tg@!a6iXW!jVRHQ z2 at O<&(8w(+4#jAkD0=5JG{R#juIB!4SGQ7fmm#!VoaE?dg-O7%IW}VI1UPc~ zUYqIVM~1N5_?eu}#;nTp`2Hf6T2anH)jpaN1Y5>K^Nn^Sn8kQEs!x^qpiJ&q6M8OY zT88yRN%V$$__*M6O1C==P`aGdW3$BHu%X$dUEiVrEZzRGI-w)*cJ9ORI%8GLL)Wwm z!ITw%<;OnC2gzKrfCb&idHsjWWo>~VVnalOGj&b=f|~_m4e?6OyA9Ls$}Mzg|Dos4 zv$LTLK<_sj7_Vx1GF&N9Q$Q9QoOIo1n!qwb)Kia#4ACiQY7C3mgc~n4Sh%8Y2ztyK zKfND9KcE^Z at 0uDra;R^7n})7aRC<|QmyShiwvItRG;Y0xI9}TXm;uY!ku=PIGD( ziSh?1EP*tKsU`HO%(y1-Fl=urC7;XbQeZBJi#=@~?%(bQ ziserpDPxR_C#NsrXXX4N47D)a_#7qn>ZO&u2Z|S)45PcNv*&GK%Fo$0T-hv2K^KMI zJPON?mL~#RkK~C&Rj zFS=lrXGKNJ(C0VjUj>JN7`P#quCp3n086#IizbvF44#KQ+wLlSsH}lGXMJPy9?xve zF5>|_B`C!`6;2uC{O7luAwkPrMx-QAa8s^mpx4=?7(cPo#k>SmzMSs~LjgVuhKz*C z?8~HAf$hMK>n7&|XgOAfo7l-|Xz>EWQ(5{`|KN?&vrek(AGr@@YXdsA^|T|>00 z`5q|WQ*$d(Y(iugQ}UJbl3WN;qgt0qtsh4BcgrCSR7A>s|^gn7u}5T2>cPAnT(i+OC?B>0*C7rBNt^J!$JIzyU%jW^poI-HlS z3H#iq%v?ldmS{&k)7`yHw?C`s#)GS8DcJX6ge`Xorv?kDsFU}3)^LX*glLct+CWkL zWi-y~1gXZ(2B1D`mHU7Hy!2*B=$Z5A_9&s_fl|QH8iO&$mM;wfcDnsMC5QC9URWr>sCleXu_ru{)h|w<}=j#6F7JzqY z7AjCm2dY;z786*|sRW at x%rW!k-go-CO;~D8B6XKqls4 zBuuid))cV0-)Ay_8^O{A3p+B=C`g!A%wx*9I(?rw+&U at uIfUD6yo$U9j8PERm^ha& zv0m})hbbmDmu!Q2hyJ?(cq>q8ae8q3o(`Da$Mq-f30^&~!4!KG zh+OHtGw-#!yz`=9#p?ws5=1=@Xvja351(vQ8V2>PT`{H4{AV8&yN5-O6%Zx;S&(++r|xqI)54VW9&#Oc`qc zIY7q04B at 6Tg0JoFoo5X#b)hIZSlF<%o1sx^58j zMgdvQBwFJKH_8s3ql#ELx(`hDmgBVcIYW_HDoVIf+kt0 z8gBqA{QNwNSTEDOj>XbJ{y!S}zSSh^kpKW707*naR4KVB;JBhPO11lyf2~;zpZaNZ zkO=gOV5T(Tno{F;4_8+pLscOwx~Sro9Q7-*X~-b>M6IMigmGz!i=CN)CftQ0hoMz?Q-E-3%WC_fs32DEi1vWOCU>%L`he_}lg z7$9AG7cC#aEL0*1V(enjXehTtKq7$YOFQn-grObujpjQqncG%{s-KCM&*lpj9zcL^ z?sWE_^f99k>QTmG2{G@~L6FSrZ4*Bz*N_U~j|nGi5?2qy_Sj6HwkTulD97cs#M*KC zi}ET6hTjxTkkb57&Z~DG=5bOEp04v`8a{p6z=!L)9qw08c5Mi84}g+2o3&%@%9geb zu4IYNrb8If0?9$QV-0t~;wbQ|%mFDHF&J%5lTpa4Q at aWzHR;pd41L^Gt(zirqLKX3 z_?aFSztgGK(SO>?%n=8Fx3g*c at T3XA`S3 zH%>g?I&YR1K$%!HYv17kZGt7=o6%5lR<*+Ml)Z>Z!$*H$8O?frQv>t30L zHvVd8op%X~){W+OyJp?=yJF``!x)r3*_~NpECJE(Mj{dkc0>MYZFZWC2M4125#3}% zEQ(k=ZGL*wRp`G!8r-Zn)%Yk~vbp7WY9m6KczKzskUns+v^up!&d%&2 zU at K>9HqyqVWK}m1$tGqZ%b3hO_XBQ~{Z#$JRV?*uu at vM2DPznL6u;4zqn9ka%gvBz zd+c%~gW-*J5rZ7?VbE-w>eH^Pc%^*r5{Ys^Y=y!@(Dn!X-NUQe-;h6OAk`NE73dMg ze9|zurZrk=gA5w7xmQ1shoXto!IGu(E9(lWdz)5xiwE7e;t-e%w?2*;=_k&M?POw| za!)NDF1iPXWTa_p{AZkZiHw%yuZGsc{&O)okj2o|T&>!7A*!v_l_$`tRfP6-T`QuE zgA0b5_odlDATqee(;Fi7{9f_o(j#x~qaoCSme|9&4L(o;E7_2ZImHH%o^~Y{w%6SE z4AWH&NNo+bb^`WHU8GKYG853(l`;j0G at Lus#n6>|A at ymP*-+IQrDnlWTbC9VC{b}JY{|w`AOkLAD1quj$_RmZAZ2f15N^u} zenA-0O(1k_OPDT;e#IzFX!Mq1#k=Tr_0W9>xx7+fIhB@;_R-8sasxB at -!~!loSC9f#3VUmV7XU z%%SJHWq&h1q!iLVRgWx0&vStpwsKMO at B-se$RVlG)qFiB6{k3;$RU1z`=;ZW2*(1k z+#C_oDSO&7Tfb_^4ODZh=*yqWTv)0?8+?gkm)S(waRNujxHT}CtGT`C#JE0rLc1Bd z%PhJW#DZEJS+QO&Y{hf%6(382Z77PWQ zSGFrtV+!nDP{NedY=VL=*%E_(*Z6bEW76}sd52z&IcCk?hJ7T%C^6Ao8{YZQFo{Ui zoRigrAMZ{bPE6xcp7r9IzzDpa?IoNv+I0cJ)=3u29zK9K=i9LC%d#k>d6B}MP~?66 zGrkABbGPD^8 at 6tfFvVQ?qD733WFilDo}1=X3Fq~HM6ZmCf?;Git{Y3*>V$;v%6ADr zH$&PsDa?DsM>^Vbc^<0vZ&|dxntd07kwa9FXkrp75xa!^3A+es{@$nd?o at S5ms#N z71z`_g3iaI;LbB>9|*R_rg5- z*#bs9RGWMMl9gcmX9DElvp9kTL6N3t|S8Sg!!D*&P&>IDQ(@{N$g-rZ9iZ-RrDb$jHC#D2FXmt6Rk7V zuy-$p8BnHAffi=m)(svN!^-`nh=lC{SpX}xcZm3kT=Qjq?IDM%MCPPJC at 2$7Vx?LpP;b}-N=lE?U6Pp` zC36m1>n2FALo5T|hq5Qoa2G?ET26VA6-2M=1jk&sX{;ETiioJE{XSQ+j46*GmL~Ad zY%F-dwU(=p-mo^MP-VFTnWn&o+Op1uyew%>(JuoU#&9^0yDJzvHk z6Q>v_d+u*jwdEdxc*Cs>YRS3G;Wa$Oj#c7tbboN#4huvzD)D2-ZL}c|riecNLbRRW8m70;#DcsSb%vr{8z1)a zB8?}~ixUG8<9WHwEPGF!e&~DKe4DB at 7Ly~x6r`UeGpEn))*$U|Z~BYGM-8kP-%psBtpzYCHY=(9xHB zVBLIBTcR43my{I*ZdSBWGj at r2Mwcc-&sHAJ-gJW&&1}^Xb at J|8m}pS>^6y-Wkt@<@ z;;@^NUpX$;4U3DK&#E2$u?pB0 at OP85${cKX0pT-N_KJ7bk)f8}UtHx%ba3UkhIIRM z4+5xx`XdC~QxjssH+?yulSH0c9kA}w%dPLsS(-oEl`SE zmJhJd3?47fQvk5v2bz=a%@gDH5}F9;02&%4Dnal>>Cd@!T*NYzUp{8JHhE2cZ at L4N z1z-K?PAg&gA8hK04-Fcww8GO|CL=0}9rCwT3e-Ou6tHu(mxB_Dwu)~!4j5MB=vdVj{q{-}EiR7#}UJQHBk3>KVHT*p3HT{Hdu!Oum!XI?kK)`NdyY zjJ81&FJoM{+&1x36aTesq67ToIkeYWnhwrG&M-ZOl3S)jMi7DK)C=2c4CW8Tt!rDO zKfy)-#W%nO5)}RXhw#9kwsG16Ub;!_RgZ1)C>L2CMuGlA;m at 1YVR?jfuMA9^lPGG~ zMh8H0PAd{Kmo8&Uwy}^fgW|bia6mZ_ at qy!SQ^Kg>)$KAi``rk+U-U7BNMCVn at H{g3 z!3lKr!C6;7lvg5;2Yt{{MjiA_p$ zAC@*@YEZYv9gR@;+h%|TtWOPZmgd-or9js`aYKS&-r^qq=_w#Gk%ppI`K*&9y at lA? zvf2V=9GW&`!#6}>sSL#w9Fc)Uor;HRG)oTD at wzid=^U<*3oUz;#b~OjcwWac&W155 zgi`t7>J)E*6+5%#&~2S##BCai70k}GOE~{m481f at 8@^4^{_xsJl0pKVf^6Ewn5=v? z+RzErV5=~lfvV5V{o0(q=`Uj(K+IOl3hxshY=bkx)@-hbDq1dX5qB;hIEE>?OPZ zv!U>?9+{xiFl!2O)Z~%7i$x}}$pn|7MW!V{o!bAbDb^VaK{|#-WQG-;w)0^yEzX;U z`(YK39PZdwD}Fsj=-ut#N2stjtEU|!i?LV+oGzzLlsUzjd8}?X;0G)g2X$fh&o1HQ zC4xmZ5Jg2=KHyruFk)G@)}~cDH({jNCM`|PW5Suu%VNgY`#@9Ss3?9{$}DWIp);W6W4Et@%CtGj zI%Tki-JAAEZ2h)?na?fh9bsYEDN;x#g#_YA*$aPAKp|V14&9+Mhs3RDg- at i zCx;U#mO#5R;cHKRahya99+v0CjJj-31O{fXZkVW1UJZ;5m~hnTuO^=G%=%0IJm01b_WUv}aY^Ot{4fcIj|0pzlgzJh at kk(<&zZF at f!;-<7Q$T>6 zov#6DK(X=_Q+e at yZv1RQJV1gaCeVrG2DSwn*>oje{F&x3u1PJvg3X(mDr_KVhj2moWxlwe)QyyGoo9bUWAw|cm*3Lp8c(BE9ab?fIzEAat1PblLTEP2 z at Dvz2=V8;Q+y29y|}_|A^2#YW1E@=}9d#Mgn>J^{SP z^-H#-C^6g#m+?IP%;TeCps`F}K@~A%;mW|=x4b#ZLzzbA8w9g@)Fzs*rt~Yayh$H( zU-%>q#J+E6FyK-K+h>=*UuH?v=)54paYAp1&#hw#m6mdvZL+>uMY492Ty{qGSqtk$B+gh)5!_^4Ir-ZbX!!RoHu69f??+ zwUXB4-{*$Yq>qf!dC`c`u_0f2Suf1wboGP^#)Vnv*O;wsgbk(`92O1IV(=#Nd6RI2 z+Sc$l#A8I0L^p>wG(gf(P;^!HeWhR_*CbkUD;OQ@;X)4m^WVKqF|tN8 at ZfB{qhnA( zg*K{~<0=sGLu4`0=d6g!+k4RcC9zSi4{@C~Ep6xo7lX^xWE9&P8zvDQ9oU=A9hC;p zY5f|I_>z`nl`pDYgpq6-eEYF z)Q#7=#L-~$VG$zCnq{ERnn=y2bPcg+Bc#C(D6*Ab90=IXf3GSK7$5?MGl`GbG9rH5YnPq9hs^=2tOcta3kT4AqUEbmoKEmK7(S)dqMfB#%? z21`fqAsT7>hgFT^eOUu$8vBCh>`nzM&AayoeL@$G7{TbSVxF5i#_=hhg`xnlq?E~5 zijm9jhs|O~O*iN2$5K$NIuyi4)(L9pJ0w;~x3ZgOY(m!OS|B0bmSl zn(BsDEmrDLl>)NqO8UUY%Q9wS^;~~GxS0(2iwq93{V{G;D)-p z)aDZjV_eQUF-F2Qr;3V-JrOgii(beh-V#6NAOzWox#iFN)_Rsq)MES;pb1=1=J;;6 zrZRIy=2;(Eg?(p_gx**{ybwqm=VQ?daQI90gM=m3AC3tIf zu<+?`?amgFZjCOM(-LJMV$c}~s+PE-0&g^l at Lcs(T!RKwX|j#!5X&BPKTq%42 at 0x+ zWp6aPb`Jt5ax=!}ygp8FhxYcp&mk!z#|Q3S_gtGx5WZWqY<$Uc%hD at ag5fN^lBORR z5*IZRqICcAQZtAe6B-MaKx!$PVK04GR9wE_vnL=OoB!$L1M>{41QwU at HY9`aM$~5u zvEo=v74PNE at 8{t5UyytdV*gx(>1TC^B?gapKd|o_2E}m>VYLuq=T-ej!kdQ(ls+A^ zX<=ZrmB$EDEFdQAfI`=KsO2Jr&s=AQ9*8IxzI%FZga%@M3_*lE2?N=1EE^Ey3zCnk zldTZy2Vth}Rm2 at C!pfG#4i7a3YfoV_D9zTOVp%FV0 at mavvhI`03h!$c4azR11(_#z zE_xJ^XjUK^LnloTqeViDHNu$c at P!NtRL#FD!jf_qa#jGTFi;$2gfcmVZa*ex#7>E7 z at qPR3qOOS;!?hWQ6_4opVk%t|4g>f6 at l&|kc{E82Q|IMOO>KlNeZT<{78I7If!h61 z%b}vls$`L4BjALyYUYuL*3ls1^<3HzISs>j>oBR^&XZ4x9n9{m-Pd}rVl_uB1kERM zu*lj&{SpwkacU%Ufku;ak7vk1tW#Nv=X*oNSh7Ms(g6P%^6f)q2<&W+1P#MYPk46dgn4wZZgUSlLlCEGN($mI&WIvbxD6z2&-K7kg{- zdxJu_5_GiqcfH)~^^k2Nb7~xxWZ(rF{GraJsnvDC+Am3J_>9d}KWKe5mrPaUD{$xp zp5&4CL+)#si%#226n?3*1V{kUs6MR5sqv3YjyYKl9h8zn9Is>!a6QXmtIJ#mmQp`V zIV<=^@J7x5!TBA*dNZ+V9C)_u?IdCSN7 zg-6lIDOO`#`PpHN^&=13;R82+LebFXcVh( z3K2Iq7%i?Kn#e|3xc%;|#E9!B_4 at z;0xCZjsk>F)=ZUw>jt!Z at 9T-?swN%}XJ_k3i z-cWo at MJIZqa#7~kCjyX&n4q?#XCj`-$6fF*GDHisFViGMsZ#hHeEg-`*hC57oRWzJhhAU`wzPXF0+z>y_tSD8IrnDMHFMMMxhc$@sVm z-|2$h|C}2b5l02=Vhmd=OKjwu+^{fOSUgtu;8r?t6ai^fqmmOXKH at C)tm`ECW!l~f z9+~9Tq>U)^zT9EU#Evu$M*1`(rZR6t7Q^kyB&@JAwrIbuG&Bi7p2MG$$U6G5NL?uw zwxbGmQ%?9GGrTopUKY7beG(DNr?A6mh=Hz-Xm(+u?*lZ!&vm>3NVyq*9vhIeL)v97Kc1gPkT&hUTELZ+Rx74WKY+ zHsrHB^cv5sb!( zZV$qzUFNsqG4qcrs#yO+3+AqevyU;Swt%gmB%_mMDJ&Qoy at E-=8)fgJu*@FYEld=c zIV~oV1E*@{_9U-<43wMlGY3W~vkhA2>?$NO4^zEwKUZBRc)QLN!E2n~nnnX;h=t4k zM1|Zec}1|Ulg>b47nX_nr1xU)_>;kE7q}}$*wsln(B zzn5hi_4V|8|G41^O0IAz;5~cq#;m=}-vY- at H0s7rQ7#-hWmoKd+CDggQfEI(1gA<> zNX at d3!L{OJaOiJ(B$dOyzpT-ph7WN)DUyQU9H?9J5KWsrC5!p9P(ky}%KUP3{iQos z$U&+-*F|VN&g+o%W-KpsBzoR%d&TMWh6FL>rU429u7%A)gK_kj9ieM8F?4+huoX7h zh(GcrmWu%NCggf$6?6yc-e0+X3s at 3lPbqe|)z4|FAU7=NX=mhPh$R{aYA$iCMHHzP zvN-3sV-FW+18|#r>0g+RZdG?C2+!(!q2>udrg?ZsHu$83AA#qx*H#Q6C{wsuF>^(` zO`sKb{IL}mSm at Y|dCN&isQE#l=bX$&DCuj$!gJk7Y1Z8tf_PtGWSY0l8x)=Xz&~6D zu=?1)qRBnm{0_lZ#oWR{`9{`$(u)6>^)7f>c8~jhYBoF`*cp zKi{=77R42ZsG&msKyVsQ7!-pdmH5y?jX1sR*fI$a&D*M!5yWxCdr})LAjN35bhexc zn^j|i9%w2QDLA~LJ`=UJQQ)HjiSvYQ7D8IV7-3piI at NK|&qhQ+h_GKETZ6lCGqZP5 zp#K}jqlY>4Syhp$JdF6&8#0-kZEYv0CRwBoQI}6Q3czPM!{6|TK0~HO zjUtSj97V@;FGqMb;^*VVO{OCzw~&`raHGC_FleA?%J+B$@@gT2C{%-S4~>NvemT4L ziClS1JiV}lO&At#6gWoN-dYJt2lj5dp+;n68SRpqLB+A;V}lT*;hQGVOymz`@X#Dk z4RBxaBzo2pYvEtEg);R9c~&hV at I~oedSLlXYNrL5uiK*Q6#@Gh+h_W?^)b69!ii2; zbegY3jz at BZPw|aWIP*ZjxbBs(Xy;5J2}2jflXpE?*kjjbpw$Z=q=cOX3cTody3s86 zS;4w4w at J5WE9V@$vl at J&JM-hgI#m}rv(Zz?^m--=O+oh=d1aqA6PVYuP5C>g$ywA8 zjsj)$-91|~t- at Som~+99f-GOkZLCpp;-IF at c)iaF3n?|Sp?0rqH9+1{AF_+ilzEYHeCfpndbjW z?6j9X*46!UJLxhD;On*O_Eg at n5pljx8HgZfb2np*S`;qc`#z-C(0uaxzPx+;1sIhF z80fO)fA76a^I{dS at 8`GuV}cgW;?!*XUn##8!i?qjqnDpHSEl>&u)`jU`Y0l26{+y- zF^xq*m0eYPf{Qx*T+$i!6=Ij1AR~OCSjx%tWR430^2wp7W`r?ankc35Sh~m&hcaN_ z2*ooUL64whx^h)!<)tMu%Eq;`(Bj(fr3X!eXtr*NOV1P?ljbUdn}Usvq>a$Bs^B}` zd~E&0Ldo-hZoT6{U9kl<7Ne!@2P)Vs^x`$D{rk6}g<5`@Uev6C4Whq;M(+x;+V+%P zKH`U at lc$+|JF#lAR#R#;M~a&@QtG_+W$8k7MDzKqt*EpcMVth&YI&u;U^STxec&C$ z$%gPJ-i*a=iFgz?PHzLfQNa{xW!QpoYkf{bmS*aeNt!)jYZ^$S*0^ZNiuNc9#aTO# zIqeG*xJ+$B=P7ek7^v;V33l)6=lH(DL42;6c^@4|Z2E!n{MhrCfp}o(=UV3Gk at 6g~bjs7epHmB%`1oYMQy*nHw`ZCWjbpwCjgjco>-FmX#>b*=3&W zjg^rkd~P~g(Z3QmY$$|hZJ-saNZpmIxs@ZAZ4236a6OIqSVBYHHy!u6A0A z+|;G5SzYgSG<0IBJy8B;eaSr%z`@&4YR?j#sm88}M7FidEF3H2Tz~~c8>T~R(~@m& zGxr?mIhIxBJj^pO{q9Dcbc?o_ky;cfORD?(GwPlM(~qlc3ad87I_t3v1j88r7Xx8u zYEon9ZV_ySUrr?3U7N{Ea7&b8UxsJKsIsV(@-LDdF*f5)0W z!&&nJ$0JZ0!+U1nkru;p?{w;X3;}dtq8BtV&IsD>7B_dN3bQCV)0tG4b3|sHTma&+ z#9v59l9qpXW4)TztK at X5Lpbv1cbD%~$e`QVq!|;3K`EB0t1PyW`UFZW9mVu{svvub zIdz&1?@nerr7KM$Z6|kU3mbHilmG+;giF2cL6kzDwK04sMI7FR`pGTzLQ{{uB7q?c zSb2UVr67G}&~2&0F(u`=H=ZS^i1*fmIsvvujA*laK82nI2gHs@&rZT8*Ep_EwZyY3 z0m_v2^4S_~WyP%obPm)>cBcKqog#;IoHEp3M|dIg^KW( zHXEmzqgt9-!-&A`w}h$UeEz1dl3!@e5{jINNZ-N$(~HAKEhM#R`(dHfJl)b|^4 at yh>d*Gc9SI_Mb9Ypo9DotQ{VqdMp at 1u}zf4AwMSzMfV5kej1Pf z-W+AkyVLK%oDdwDdn%VL;YPQLNV{1ti!*-P8nlxGrr>AdAkmFq)taO8e&V(RX<@(1 zBMi1~sG6 at hY#D*#W5Mbux+D47%aFZYswgoAw^6{)bU%i at vlS^ybAdS5KT(ZZ-}LmZ z+$c05%#i%Y7Y(h3C_^=Ej1Y*61_6YI{+e5V4NwgJaW#AG+h!JPMBE*!m_EtN)>ucx zB7w!=vm60J-6QbJTVl&1==1-25+op&^=4Te>?X0PE#q> zp3NH|0UqS<$vQ+%|EPV~MY)GD@@6pUf3ECrWBt^oM}e#v^T{-1c6klY<3gvoq5Sm$ z)I#Fa7M?_bNdzj2lyr+vbc?B+x*5aE>x3|mn-;)MF_*Sb_z=C@>07(sv1q4sH_wX{ zlu+uRWmMBc*$iBi4(v&yfreHuh-mZkCTixaa#69|DVCywI5 at E>7cCAcLnN+6 at afT6 zd9mE at vkYQmg|NfA&7%zkqsR-{bvTS5(Z`>^(BdTF^BQPwF=I1(%DggpK`TqPbwe>1 z^)P0(OZ9To3$zK!8^gKmbFfXGWBm at X(j;z!&RX%B{sr9nR6eFxze1NiTFoLS16Ob@ zD9qmvdO6LwbyH*}{~G)kqpMgNEuMGOv~b6YXo78Eu{R058Phgouo_m%ET`K*(GUJM zMS3oF5jgUqDrfIuDm{D8DrQL~0)5x&^+7*pb@~f|p|)-S{PS0T at EDrN7_}&tvPt32 zsWn;4!V~e9O*O_`sXa2L)ZI$O*bBY}l4F+TCV_!D zsMBaKoXZJCZ|=uI((|kwz)sI9cdba;C}(x0Mt|>wthupku;W zKYQ8?UOg9M%n#ZuKZ6HbhV8w05L1D6WPGT>A1N%P+YsXgF&>7;_6e8t_d782u~x^+ z<<)r24e;o+oSk*yJ0k#oiVUeKH|1=F)r5l1%pMCnoVDrWev^V3?e(u?gi%2SN3yHyM&x)3XTz6=YlGi>T}bQClV zh>6wE&*~qE;rwF%^zhI$tE{kzqOCpjrj>aDx at +NaFbKp73~i-CBA{HBsRzf3w$nJR zv}RC?9h;!VrN^O-{|iVQhQ1g+mCIgb5xercF<(F56QwE}tat5N)VF at ygZiRbkDT5q z`nuEs@^L%skq)vk>qQvo)h5$|ALSqu at Z&lNpo1UjO&D^%Y>v|JHvym}=ir8m4j{$- zk=?J9Z)&(aGC;?|RCSGsEznlp`EUN{r})w3{xgFq(y^b(xZOb=%!awZW|?DD|w9O;)8O+iL}A$u2%MM>FCrp#?kSTT?;Rx(*^#Dre_Iq0fg>I zn|Qjv>e8qP0>X<{3?N+#Q#(@xdZ_auS;{xvoO%Sccw$T=7p;(2sAGny$>5S(?62hc?NH#Fs$U`;L60MI&IX%Gn+--gx8N-!0j1QAiG~hmL z$fZ3Vx_!)fn2aDheYOln1qDf_vPVAs+#323G}+xqczqXx75%4gYezE}7bQanfU2q4 zh=%4GGOPs1g3KY!LQ#6 at riK}1GhZ0COEmJLUUvcGlI^W7)0ILgUUz}C z;smOv8kfj8GLQNb5{Cb`14 at JFhqaoB1pw367}Y2zD-CIf6%FL8`t5DEyC7eX zK@(GbFO&b}?Q|0iTErtuY+is(_)PdiZo)v2wmL}mK46W6aUhI%!Ys1c8!7kPN_(PG zbHPu%lvjCUy$eO|iNN9{25Cwl9;pnysSMu4*T59LDpl(!pb>vz&YQ^suf}zy%ix)5 zwSdKYKU|a)XpBhbV|F3n)eA5kESQi(O$}&Yt$stsFs1PY7TT+>2 at 1meGkkUVz0*#* zv$^KyP=qZ2l+b$W=rlH5J88q^8I3;GD%(Sawy*KINjUv3Og?oXqJHF{C#Z2wj9G3amdn+|gL^^UmdoQvZHK4d&(!vspPE zaqEk`ayTCStdo^@A1=G8#{|d!%h;7=N0K8sgYJLk#C(*T1Yn?g=Dpdvx-+E+chU?i zWnt;5H4zP at u?yJ946VrrqF;k8HLJ>)oPTQ?kNif4hA2eljsVkL?&cJH>5`IKDl^u`3N!R+2RXux z3DGE4$2o4|T|_BlteKuy80}1 at F$5ZNfhn;s)CI;D#dS|V@>E%=(MA4kYFxCiUNebf z9AP|=+Ym`(wV1=mN7=6jyLDjE!xGjK2^-9jX(9E_sgw9UPY^8{-<_J-jpNAbGJm%V zJfM_AlCVNShPWE2wfb21H*vrS4W|EU+Mr7$YRuS{dO at 2h4WYu$?wXmIpLR-cQde|Q zA_koN0 at rrP7Ys(t#slVropcJLcv(Nrm42PveF19z&r^($YKStl5aT+1mMyw1 zuo}8fOvP#?W0o=OFp$3ynFK?=M(zRLmj1Q$#9&AcXZ~~sX6l480;f*W;;BUbB*Wm- zBQ;uWs4X<`@bj at MIFANlt}9Y^^vpn1{@jV7yS1PamK6oJ;Q`;)s`?<5H;hYzj?$@V zbaMPzgdh5;8{{LPcgW(*eITWXi3>Wl_k6b$;X2HYpbd6{eTq!AQyi_7XjeAV<}bnkqZ6T> zfLtlu39{G!RZW;tC^rI1qb?v3 zExTn$8&r}RZo>pyl^~mmU_5t%bZUtA``7k>JDZAxM9v;G;)vz_1XDw>;&UE%rMMOY z^_r>V6R`Z#_L-aRFVyZ;Y+mZgOm{gBJgm!=+dRZTV{Xk`jF71tw73`CmY2z174C?i zU8L*35958ptnO9HRZ`83StV%Ba;>6beAf?sl_e$UH@@j{u2B6nr=jW$>#(lIA?*8q zh&N&kM77)>kvZYA2VH8k*zYnylKW%6Q8{W;a>p-%v|wX*npO&NzRX?-9JGObE{H>f zjfw%w?xuH7lQbY!(*OR9pZfw`TfIJ78STLbq{)#+kOR#N;swBV*j|b4C;=wbOa4%L6C~{A>d at KZ|fTg1J58|TNK7Cu;M|< zIGcrFz(q*MCAurSX0pV+d^e- at JKI~{=x9cltvj}81n$+KU1_hz8X-g~AiWb5imhm% zs~2{|Kqb$fa~eM{9IiGSjr?()->ix;kWU)!73L1f%cEv`{*%8A$XPqg%oI}-jw#48 z+|q$ty0TSQhLwa8d0~Mr&YkxKL2<)SBL3>GL`1z#BDP5#eai*nNnUj7db{@Ue$c;| z2 at t{sK8OnWa&%zM0Bbyj`#v at rh5)Xi07WLVO>{Jn)eIOKXP}K0fTRcc at aZ>F6N=ji)P&xQMz&g_z&Iw;{jhR}6KjImb?|4dx_Ovr2C|{Cc81`+ zn^}Xg)NapWR6+nIY|r$Bf8e&=WVnf$QsDG2EG|r_?ljQ;ex5&iNHJzbgLUClS#C_2 zjgnt5`O=S;Jyzk|@v4{;fGfps5(-Vss!aOw`u5?dCG+w-SYYi$Hc`?F_j>lu-;xZ+ zUPqNQ0qj1K7ig8i!$MmZ?o+k$<*7w97gQ|VARS`^x0`Cm at i9Hf+)>&;pJSsqCO zi+0Gr!-g2R1ia>)%#_#!Z<>H1;MnV*XaZ;9Z?2S}l`@tR;T3_>+^3TXS!e*23;($! z9Wi{R25w_fCX~b at eh1X{kxYEOwT5b-`&XGw*U?e(`T$yti|U<0tlY=e`JGjIV1_)S zp9_KUQ)Dl$MdKRwR^1r7`3J3k9llg at Qly8Qn+Lwup{|p~tjLdy`!EI~0=d_&Q?;lvUdrm!^T_1 zuvm%@fns3wWSoz3Lz^kXx9kYlMrC*UVQ*aZiL(-HYx>?S0Go6*Js22jve$`Hk%*m+{m&_?+)R6>_9 zU7hi;yIG?S7R*3C)YjbSjWP|SM(+iEH8bhu3v?{7%!)b1v#tsOe&3R{h_*tCoOE1+s{TZjAyl-Cyz90lk4;$Te2 z3%eln^HU~(fquO%YtbDd^;~rNyUdYXLog#*AMT!RTU@=YyG_aUvfPJLapDbUr^9JN zIQ7ElMD458{ae;|hm;%-fzn-B8SMEaC(G!_YM}%)S*STR&Lp#UWamQ>lYNr*i`O^ zr0Dp(Tk?JgKsXB3OF%BU2};!#a+nne(g=(qWJM6nX=*_}z$(+!#uGu}6sWV|12o#e z_M>LUTKEfEM7`%rs%{S+NnoF*{%q-{!%MFM6Ip9}hz at EQwUA4Mg{Iqc<*hsKi2b;r zD+K4+d|31=932~VR{LMVsKqmi5zUjqFh=0e+@$OCT8>#F1BO=#&9xW2o~yh7bB<7Z z7ach7(v&Rd>iiZxk$mZlNr)30{gY~#s`7k|$6*=|6Vfb{?n7ij6urfR+WB*Ea!u|7 zRJ41a5;H?5N6Nr~)v=s8l3v#sDmK#HoDC3##%s`*^GJ@!_hm~4A?Tn#1M2;4m57bu zIg4RZx`4?+(mn3}-lU8XtQGCBGStWpt0EHs3aEE8OA%{Dem~tjxfiO!i*LRE1mno7 znY5pUj#j>o9`!eS3=Tqr`Nk|(un!byfi+ImzU`3x0FD~(F8hr6xRE{I&+)^SJ-`bY z;sLFgQKaOCK-(w;UIYtt&493%15^eDnYeY+L<<+9i2UM4^OMkec*1 znK8ttHUH2KbTx|)n3Y at L1*u8Uh+ZBBc(@O zu|%h64q?R_#+#(9jmbKww+?$H5{#rurP+rbZv;ic?FPpbfcR#%BJ}X&&Ol80M20}O zg$=t`2C)!>`S|imBqH4T1a!9;zvkFTV+>#hJrp!Ld(BG}t<NbA6v#klXb01O=8NB1aIRxrDmr zv4<_dn_#VMe%|m&?f_FjtiL(S4S6#+6+L|F;35{PHzWkf)uw_*nQ9$F6XE`b8CCAfESuZ+RtA+-Qi4&Ro zygxsXcj5p5AOJ~3K~#&Oyn7btPZV}0K6^o25mfbvR`lqg`RSzF%o&IO0f8bL)O-fx zGJ-^fndRKN<3?MDInBbx%d+ORmqffL! zkJq(;^!l;yC5Fa;pf3W*1aR^5mQv|^`Lg`8d>h>>N<>B+d%mF!1N38%zhoHU#FpDC=IzTax zy*D~ouLJ|KzO(9hJH-ecwA5_EPLqEKsU1*&-EUaWA~YbC)x6IR z9F_0@;d1e>3M4UR at DsH+qY4^!P;2+z814OV+(*$6m1w9j-4#-PImyFAcq=s|Xe3T% zy)EGP-~Mw)GhYuw1&=*ipcuT;GbJo1AYXO0W|w at caw&tJML=P7J~yOrEiT_Z4Mb=W zEoX7p%<6(u^kt7{0;0=IW27W}Nf-3h*IUfc(w4X5UH-k!(d|3FF+3CLO4CtSx1>&y z@!ap>XLso3!CE%@Srww^$i5LRez`Mhz>+!sXb6&K)6VFUp%;6l6U>C0GpjS#!)WpR z5FK0;cUlHilM9_9dW-^N2s;lCoE9Rx)(cBFcqs_xg_jnIRl|2TD~fVwCe!@?5T8aF z`yz%DYUHJ$SP!4Lk&`Dgh#)QcXhb5_D#5?dTVGJG0;19{nup|7kcpdj at O#OPPv(z}A z7$W_x>Crh51YmvTpqRC!Z3oip`WnXhMxfWyt4~xbI$w_>-1%(J)9-)(6Ds#H1A4eG zBjRN165pd!>4l~YA#tO;P_ggaLQN{X-vh1Yl9uMc5;l%DZ%ep8M1xl|9uDfvCA!Dz z*Bx=_b1%ep7vA9x at epT{tb!R=$H`qa`Rr|#Wr_Ryay@!BUZ^Z#-a|~@Y1D4!Jm<5L zO_q`==ze6cda_sK8BV82!3V4gDI8!(LM9q#=oPFVElZQ7K^i;c(+A7BsZs)zftU7A z(pZLKT7w=DJD&Fp;)X#Za(HEi_(|jjO%Ped9PFR9X7vE2O~6OnzaKPR z7y~`jYU;_t_I6MyJ;q&nPup-I0(4px(<~4G)>W+Z8Xl$O&EcffKq$uid!cU|tJ^kd zof?CJrISg`Dn)andaiFfy~6_C;vZ!!AQv@|^f~@0*Peoaeu3U#EdpD^v<*N^+Vb~j zKuWl2ly^CwdrFfAtDdlC+)6y{xVBh=CLwfTayo_4a`J*|_XHH4&(0W7B8Ji!*lkIK z3=FDqfYam;;{)*WBVaFKQrWi_{~ElCHB3+to~(4kgf15-_$*DLVH;fgSD!Qc)gB+AG6mnRdhYd*Vl z2yLU<5hCs4F*6&tX~a!g4KG(CT#M7;itu?qpESAA8nU_Ly>;Qxvlnk zT<2k at 8+ZR}26`E)v44RJ?C{d9&?K(R(Q>mRj)r zbqMWgftVp^dvxi}wAhj^FHvM|xswr~MG?h-CCq05FEl{8Bs@>!|EVr{Gx5;}@#xFO zJap}obUmNu(QHRD6d#UaGQ+hquqPE>aq;~8uM48;6C}A;`$Mok#Db6)k4d(2U~Tu? z7EeoBX!&{Z!RZ(DLLb>+aBMB0sA4nvnU9m05?Y&8HYXJJ1TFLV^X=I at hf#`$hV`?j zZSI+DFHR|xu4Oz$Z1;CjlW3OE(Ju-5k6kodFr82fBfn`7+#&2OD{58*>rRKS>Fwx_ zQ0fqpHjX^(;Kkf|X^7Se|SdzYz>H@?+Y5?kqrtrGjdpA-iw zIpc!J`XJATWXd$$aQ8PKRi5-(UX&RC2!1K at ko^dQ{X9SVC7v&z`2$@T7VBVvbn9Yv z3vE%D&|NO(%8gBM3s=k03(rO(wUWzwJ^8}GUJ&zSuY(`H2>Pf_^N`OjR&Giy)Q+s_ zvIZ05KeRd|{POV}?p4Fab706O-9DfvEu$4|p4C at P!_o5bia#rfWAz3`P;9Pu3u+f! zTWZE30g|#FEewX1aoes`-&VXr;&!8;nh?0Z2|wrqG|j6zk5NZlcI9SW<{Ctovq~pI z4gr*Aq}JamH1<+OprS?0j!QUtI%T+ORZ;~|8h6Mys?oJGz4j>qcn|oslJjPqYZnK; z=aSnaPEMeRDXFs13`!|~j`LkixY6yDsMJoX4hVHbX%fX(9e_>WPYJn!0mff at kABHFBD>UETa?B4Oiif2RD6W3W8XPjzxjIxN95VnI?JF5c44 at +2o?5S zeA7fQKWjwuH=_ at U^VgHmAWb&ZGhq9$_DQU>*a>bLWrEB^!Qvo6}3 zxCf>Y$kzFc!IQ+9IG{rHQ8?%ut>O_JYQ8}rWZ8L?aSO-sCBr;Imvs*fE{NwGl9>JC z$WUd9PYn#AUdZg6j_uT(UJx>yglnEA0T2Cu> zs6gA9PGsb?6cShzh4QS^)NLA-IPzBx;GCmn&7#M9%)`-#5c+bF!C% zt3TnX!P`dsU&1M;k8<2&F(%Gzah z)9R$?1GnfjPEYKpR&}1AmO=5 at LzXTyEfxOzJN?YaA;=9zgB*PLke<;uQ4@|A at eRBn zf+?9W3Y|6jr`0#=LxZ*o7gh|jA49%MgjW`o3)x)bN~aN3KrhrgzRqQC>K2*7jXDCz zj{>{2e5k(98)l_vnFb4KQ=)tm=z2c{!mz^wipYKSVONcWFov*pAkQSjIy(@QtO+RP zd_uawG9qkgzG1nbBh_1!{JZmKbIZQ$f|f`cWaxYhv;0$rLl5*2ZOfH7p>%XlNAKd2 zPLUhxAWjD{xYHL>G-2mPByS-8K4)*>)HX|ZJX`cL3)`nOZ&*^u6%%I~y-8!*9J-sj zRhPjQM)TfJCtB!l9a7_1m(PBw0;mi+M zvzhHdxRA2z{U8~3C~i1D6xpyX1_q0d32yUz_$`uN5VNQ>Fpg%)#I0`21O`x|FEHx| zXiLx1OWX%a!)l~hT&Wp&O>!UX;W=7H%;&+&qEb*46w%DiKr6RyO-11s{TEbfHFsPD z3X+!2vPpt at VDa`Q=An}Yn6lX)A^rEVTu#T#@#R(5hPtc=5H}%nJ(7{44=!$e=cdLB z5(KzQv~9mVt&EcE0&z6@`|NBKf5pQMiXPd8Zd%zHB8a*$;yE^bQtG^;V+=L-Gd3d>iq)R^eM;{JD8HoUL zCp1Ej{71F=F;JdKN~;6CtExsTG--`KK3gusAiHt!zvdXH6POkRy6$Yk3`DE~@Pj|? z;iCuS at +G1)a}YahKu5ySbPV`|^~gI2jNwi+)Ifz8UOShW-X5v_?&L3e)9A^L_2Cx{ zrt5~!D~IBF)F__&^I>#hq3Hp0?x?k_oND0XyyItR7_CSOfb)Be4rAE4#3*qGZjSl= zuYY%Y2cj%M&=}oskk9M#>Bm zD0KFOIKP#!&8eZv;+I`t);47>4nJdR?%mGL?Q%omD2QMR>v=MnX2qD?JRyvQRf0>8 z@{-+vkw*lL*>UX#g0opo7vVPCtrLniRxZW2WW1?yl2ud&4L{~~SZ{Iy>u^p4+FaZP ze)T-blmozjS7?1-VN9Sa*3>Gh)8m~7C0ah%7L^<7kO*RV!K~X|1z=_v!M;Sty)#HI z_?NOj(FaBvpe#%t?#)$MDH^BL8X at 2(x8B$J8YMQ>Hjtq2o}96W2hc6bkQ|x$flyB!K9f1_Zg2Y z@$y9^42PJ~R#V@%TTMv>Ad!LdTRr7NX^7{zbvu2=jH8^H|5#;BBLh5F&#(P$MrBEN zE+z8W>uer6ae6U>aT{1!bv|q8QXq@%>9r0f#gZFX5i);#FuW1% zU-Vd%lg$sZL=ygcSflgWQsq67AC6hY##_ShYXaHB4a2pwAQ!WWJDf&fS-@@3GcZ*i zs4qf;tQ5u;+rcQztZNJ3k`zA|J;TJ|ndnaG6Q!|kerexeU8lKKSM;P5;IuRs3N`y6 z8(O&IdeEs9*n{%KMjsbVVJ4OPAc8Iv_l(rYZk&B+-MVP5pwh`W4wXmQ1eSdq+c`(A zLkAOVpO+BxqG&WXFZj4nOFbUThs||7ah5SJ9iCZXgxMXXigG>D_e!^#HN4KcQ96_c|%ekK%) zFz5LbPa z?mlymzSTl&f6N~q#>2NJ3ggKce+QZxeg#c0wg#RXDL2 zVz$PXrG7~+esqlqfUUoqEls|aadKEcmQO%Jf$hPk!2PIQHyG|0SPtq>qOj_RBnMC{ z^E4P2B}8hgxN-qu|GbL`l%yLC^z(^$$aASv1jiIqBzs0H>LIifIx6WyqqbUe0sW9e zfo(BEAs;h4k@7rtb2fdP?%{s_ zLEpRa4q)2m?FNlmI=j!sh^@`S)k(vxe at j(gqeausT zlBjfn=iJkTY=fxy3SPM z at owM6JPa!BoMe|CK-;dC25y&Oe5m@;X=Zmhy-WG~-G8{8V>c!v)wlp9yY61g`(B at J_wl2a3 zY=)>;okL^{zh7Ge at YHXZ#!B}u;E(RyvAi}P&P%pYTJf3aXk1+3W%Z#bJ5x0}0*l7i z3j>U4M+05^YT@(wdSP_PViYw7%-X6AA;+Wyr(W3|7Q#A7DG2>yZ2&=?Ff=j=daW$M zTidh$J{=ApekWQYGYZPf6>R&jPDC$Sv$fn5hg&}MpJ5ICUV_F|3EGT_PSw!TQlu%! zu;+;kM)bwZ4G8e;xMyogL^6Gy*4%^Rb&cN(`s9kj9lz_dN3>?F+qM>aEZ`&m?9cIw z!}82uX->hBmf-2QtaTX9Sq<&U;)c^#jpvFYqIUq#`-7;%WMn|5zKU977?TXu`Okg7 zq4F#;3d8H(maTqiV})&DtIxX;DG2EokdEIl3XYTrw7Q;XYRUd>fA_L44H>3#L+LSl zm^vv2!2t1U$3ds9w>tAReCmP;%jJmxrYoVE>sivZh&U~rx)EU$+S$W}Epszq#O0VupLW(M5!bjFLk z8o|b$hLk1?Se`DU6IY5KlXoNIf(>#Yb!aN9ctm_T z%69dTpju{VpZh|(`JjJ{Hg_Y-vl$0_AkVx--%!xhhw@#uh!bu6*#kti&NE~OC+dP$ zu{IoYXY5u>qw;n(~@(^OhB9U~)| zVF3M*eNBbojc)^{17F$)uhCyJX#ZHe0Jv^NsOS(GND0vkv`bKFHm_LHBy8wQjJmh2 zPFQobA~iVtt2g=?$Z7$?kF6IdIs)KOo7$EM+4Lc_ZG|Z9q4Wy^Sv80KNo0%tDUlr0ov3Y-LBq)K_t0Kq+ z%&eLS);r)o>KE4ynT}2-?K*3lo8>Ih1`g~YB2(itxN;_jzZf3&ymK}*TJ|7fOT(ak zPZEp+~%vAN9x5lY?~&!CQPsi13$ zxzIWkM1RN6+^Q<}g{v;F5K7gJnagGcuar!=#EERuz<5TQ!(mEFon#EzwBY}s-_!}t zF%6+F4T0BH<0YetbL3~=gWyDT6<2VUAf>Gjd#=Q0^;@MWY#@k!X~!^GPh`8T=VRiI z+;1c+qrojHkawFs**XA@=#&$4<5_xuiTxM_`(**&9EiI6S9_CKdr8)4yc{ppB*Y>p^ENchAn!rMG+yk zbA4H{HES#Azh1BsBS5XQ`~B0vEgqNkoPR+QTnyLyEom=@iXyYp3ESh%$7il+r++%z)7zd&g>1I}j$c$S%^r1X8 at m1S) zk#SBmBp=|aI&-a3(2hy#rx9-6KDc#2vQUG17RE!`viW$ZS$(hJ!R>mU#OH;!n|_}S zqZI=4t`mo|BglbOV at Gr#kDt#=K$^~Y zknU;hesf;r81n49zL36blulSqX@{x(7>Vp*q5YhF4|I)_|BlGT>!mrRYyPs+goP95 z|6(r|RVfD?dZr_>L8LqD;=U`=U%n7+tn1jo2RrQ%z{q22f8CK6aqJN`zb24fj_q#^ zLsKJ=c7zVjYBk#eB1}4Sg_birlprV}D&^#t&Kr~$g zl3NJ##bF;rY5=e|AlN+)SDhpKY6WIuh at m+}&w#u?S%OaeKV9{8qm&-k#eT|qw2Txx zss}HSgd48{HAG|PRYQRd>4rcX=3rlX#iEFBd2F}K5^;F_F@(15fPspkv~9&XTf#UT zQTP?TqV-{-*P~>Nfey`#tWB14G&g$Me?AsFq9Xz*KnC`d!zTM^4Jmd=xB<=4YXlO9 z9>+Cl;JFvJwpHw#3q8_Bj9zRH^J{ziC&MaLizQ*Q%&b(dp9`zP&o2?gBZ at lc)mv}r z&o)w5&YE`E(EK$DDO)C_N9~Ll0v^_FLtes2LIj-}ktFD%tgrLghY*-iNn39A5vBzP z;+W3?MXCz1wskeXT%A7_0`IiyD2l8ehsl;9$nZj!Pg&+?`JB**ugLKv15MoLLjzbe zla-~{4pwG8l?K!y4}L7Wo|qo>Wr6IVgu=7bWQrW5NY%OuCXy2`HrtjG3 zG1#2vodVE^hZ20&-n1Te=guU)V3le-|anMo&jhTSuBATZvKuuR16()nLcU zpY at 4*2q9-bJ=GvK2YDz_vc`r3A-N57u=KYYiS*B{u{_yR+>@}d5%n^FhHM5O+Ur^IP4nt zq5hm9X7$7S=bkZmnKt5|$^8yKy*VOK`w8SLS4(AGJ at tU&%n6biUA{4T1kou2Pz@?v z+AuRebqEpHA*c=~bO8=0bXWT9c&1(zUGG*h&*+odu`dODRY?&Y3Z}2rU55YwAOJ~3 zK~(mEmK;D8nPa>IvjK zI+$0tt0nf|7=h0LrYJR2KSp1DTw|~(I!2gI233OTO(Kx%}E-T-1(dA?4v{dq0L&FpgZduaFkasgkfM$9D?C{nlSS{l7Id~-2PCm_H6D>-?=$@O)lmv8U%j6RXx72hrm*R z7vq at c=Bnj3wKA0E4p*?<{fafQkj_#@Z-9SI7Wks!!_E%kCt8VgfbQtLyceZh`g zvs{AmQh$fmieK4O^49z#(7UXvy3H at 0nibT{Uij8C1EUJC!hBgY9uTw{oAN~f8BSIXbz}5}K_7{WjBs7J%kTUBo_v%O!5(oF4LJptFh|77zyn1Y zBJU%52e$w`+}BjJcI}OrX_2zBu-V0c+~ND+j&|qAjm2_0^LNNN-<_om6l82FJY%%4 z=?Ix5(GHGiKXULCnV`K9!T-nQgKTU9B>aI}4U_|^^{~?}RR4x7+V(C$h1!KJgHe9@ zf~NVwXN5 at or(v z?9K$#3k|y-*lXCvea(_u=*E)M2q!Q|d-#12z9BJ0$s zl0A?d8`WP46%)F;mjAQ3Kna5WqJs)qh+;0xMwElAGEFoH_GV0ztc-UuBFy`yKxF#8 z at sR*xavIWGwlzpN#|BL4Pgi=@8^*v8Y(1LU+CsCO`X;sDl282Pw}b_KjlSiT1U?sC zu_R)lV8~NyDt5YpC_dqv`)Xyw(+`2t^(o(-gTb at GCIiholr=46QXxpsc|_D7^3_(duwEIACB|Qw4_~~M|5WtPzm+DBdDdG4c>WsHPTb5Vr(4r?q-)NeATk3V8nhI}X)CDQ98J)rk8a8|7- zVF#iWl~ObM9?P#vY5d*2S_DL19~%}X6PUW|N$x=pp5gdn5HrmAEUw^Y4k1HRzE`ou z(9Q>*j(0|L5ZLefRr6ZlPJq!KRKO)nvF42w5THmj60yH?nxeRf4dG=X`tGG4eF-5n z)6K#`p*AP91HV*b2Iz`dI=5${07~3w*j;_G_(kxxOZb^VuBHXO&f<$3hH>{b}`1oN~n-ELXPbW9|F;OecSGJ za|6f}hdA8~TRs_xJWa5!8c|@g9!~e7BcGYa1;}v&C!6J zVUZPI(1s#`p)cKjE at z~gI^cYGxG`)+hdbkg`+ghCOj`0o&-s0aqwK1-C^$po8Ba!- zDeYTi)UxLJ at VjhUXB?xZ5`|fs!pLDCLaR at lR#M=yI+td_s at 0>CkS=d9@@A#LvDN`z zt)#cMd~rXi{U2ciDDwhR)^dsmHe>N~u6ZgYDNPpINHIIA`yQ-VoXyQnLqV;uTrIVz znSwU#o}Z<&(oHQ9O}5I0mCwF6CDkWnKn(r8ok`GAjR|W^VK`dH|1e;O{)aZ?y24-@ z#WUE%AtbEenmwq8 at Sq6NF`FBB3>~|EV(I?craOfhg z3-CjdkwY1w<*ETa=;;aN<(4sU3Jt5ZM(S=BCFMhi%>pq4l+r|O_XGL#H_0d}e{Tf2 zM!b*Qoj#a^=77bau61oWH6Z5L-8V|tEU%YD_GhU?@?`!T8zo!v`(pmR5J+c9mKgxM zzj*9T`_c-($eV*pd!LZ#~itrn*g(qz5)V!fzMw5%bRy z(vzjiFf8h<7Pd=Yq8tiKYl7%UJTN}ZI(=QDSjFOGi#6dbVuotXu!@^G&4tIYiBvAB^TJ}Don=6$MUeo6MB)2p#E=pMNG!=z3?NFLBxCS?tY@rbX`~rm^0HJfZnS3 at vShB{?3l$$9XG@<_8XYMLw^C;nU9O`L1>V&aiAon4=` z$K!h;GK_!aNxvc6EcI%ySe%Y3vyFq~xcP4X+2wMiYg45%x zjc0dd9^l6zrWIGMllavcjK>PB+X7HvwOK*u85B*R2_NLsXMdou62eNYv)2MX zNmfQg*D@#dL>^k|9qaHGFdAbpCe8l}f2K&m5UpoqdnA$LXau-koiNZ8|S^sr`e z`7pi1%i$i61;ehqNU7F?ZN&RK;O_Ce28oFIDS+LBmqxT|Nb?2}Z4dp?w=BjS`niX_ zG_HAYHGF|e$Xe==s6oNp(LdlGf|)N|PPc65DqT-#O(GGq(=t8F0BO6;+O*)ybr=Vl zWRa3tSnN#!<1;Qpc)4L@=-sFlk4zfQACxAI#sIfmhYih)UCD!zX~E1SSG-YH+1jw7 z`LfjQ5h9667_7O#JzLHZ0K8=c?U`4MhSoH1nSGe0K;3zi8SEE&cK>#;TX3)?0~%h< z7hA;5Hn?PCYwqB)a7-A11no>)}qu5B3X3 z#^OhR%ogCbKow+S zAn=WHuE06-{-Dy%QnO~dEmKf%YoJyR)_C+!QeWRtqpsmvqnF}h%~5QjAiizh*IaAq zus3_e;Nr=`4?5>PMEAxL8lv5X1tOn+(cpl#5Y%*fx}(mt%3}fNi3l`uJu_gF1(E-aE33 z%Q;Um6N`rHn7{AxC$EP-eFlQ0Us`MB7=#HR{%x32yse6ev3eSXCNiZPP~9~Peehd{ zl7gGL2Y&B;dB4WRl_4od54}-HZE9JU^#s8s6q?-GU!!Y8VYM= z?wBqeuo}win6 at G4ym#jk z+FeXrChu6{H`8%G_!arLN7zjC5}GT&b;jyBD}%{GurL;|t)Hq{YN()c%2qESO at C3TiwPBHoxfTM5F;=LF8>1;u`+ghe`X` z(01E1XqpHI<$(i)K5wMf=Fu52ftn}osPfg at mPIU$65M%*D~nI=R+bQIZ`0GbtA at _e zB4YCMARk2FtMq|8S}si_KXtlc7x>$Y3=v5tCvSfn78k))ZAwRLLZEasd-h>+HCyS= ziG;8#Oiepea%pFcxU8i^bz|C;kN3-3*z=Ysz1t6vw2EFPc>HXkQHNaYGtU}{NMPvf zo^}=@qI%*oMEs|>=)Z*Q!X}>@ew?{(IX%N at QFhMc_utrbSeD^Sh9eqPebgG*S;)2g z&cG0Al!1#`@umYvrO+r8_RhpSlvlU{88O5eBcn)9M*p6(1ap?Kzq0fufNU;WD1!`; zWXenncHcD*u_RoV99Wj6pxqPhyoiDJGI9;SsjArp0(6TKT^9=UZe-4W-Www`6MeWg z%pjgL2307FEQ$#0=$g3B46gX(HozisQOl4usa0}w4Jta$j*6nh;Vkzm9Fc=xy5!W> zVnzKo^c>Zx>w<>wg7Q97@<6=`iu>cCze6zQ>_Wy|F=^LCz`Cw-GGN+_dCKx2?)u}v zE`4C!ts|)+hM at KZ&2R=rpX4%p=Q)we@^olxJR4UY8+K^=7azsCF5b3-I0uLY#d$@l zk$l(u)5<2&j)7z!hx3y;^jsaTMcT$zuznpFTt(7TGSIK9svc0}Izuhj$C at 5gS44}M zuqcIi*clF<%N*0I=uA-aaHHwxN5--Z6W89nryUW1WRvo)TskeK6_zm1wE>K6BZoNq zgK-{U09#7=z_J4KUdV-3bq#uA2r#`L;Z=9WHxkmqqAw!rMCY?kXVsg*_F&+3*I?=N z at QP?qmnLYGKz`sWB-`RPO{PLdyjG0~ENl zaTeO^aO<*ytt;o|i%5x5>O+I8U|>VA`!V5}gcByW1;EpWSe801N~Psn11IkwqW?F} zVXb!2Rv)-SUwpUx>Y3>bVIK6~Q=W16W9_jJAgszK+Ra`(3iR+a^>`JjcWkz{; z;w!kSv0S{t9iOrc0+N=lScGI-M{+xTV06QsZ96%f(NfQYYQjg&!!~BsV_?K7moq}q zIcV1}1Dod)9q_zAKk&J{&9Bd~3hHx~Wjhx0a$=$A29^?j{=WB{XiK6sC?~Ix at GYW1D$NZ)9X^Ed+=azMcNM>;|gc_a~*z-II2v7h{pdbiQq?J_^r zC at tgQ;a(J-&NLn@!jfNNWmsqtrmWgM7KWcv8IlO?4ye8eLgThQSh-Qcw0#{B{?_Ll)&rqFh z at Q{s#OsYg6OYBmCR1o8}tRO_}8~r9b{Svj;4(VOc^u8q4 zK`q)MZ+eihUu^jH>Ma?exgrz+HzM at v-^7%lSs8Y<8jUQAVb|wv^u~2Xy39=K8Og2Z zS=PalgOlq7_EJo$&QWOng$S3+)oY<8_wW%iEG9BOow|`O2+v-f+1lei^OY`*63Bfu zojc5Uf?Y7AL}IHfW(}?rXNjS}IKs!ZAnem>n7$+0aLp8NQ7Rt!_ at rzI=BfgufCJFQ zWB#fi8PjtgGv(0FAJxMl-RwI=2=>ft;zo$?;`>MP_miIvZ>!)UkW%U(znwypx;}Hy;+aBbt zUHTB}mIOoEUfFdhi?8eFzWlV`hv8q at F5>`Ml-AiIU2&AZGV1_9Yf4$}2{8D6uHW$x zsR;ABIHb at vm%RW;>_}MeBej2i4Jr_46ipJfi#Eter?E{jbY*Cmv=l~0Yln6<3!Dn?6gw2{^ zSTtulyXhQG8eYxlyX(3$4Ub2s!sIfswv)Dj12ZMK0c#*B%O*Ng5M_{du0V#?wWV0> z#MTLso*kEq=@PN8E=5W#jxI{+*v$I#eE_L|oQVv_vOY0 at nUK9Wj9B$~{9{3#H=@V9 zBw>5aYJ?PX0R at Rf@+Fve(+d6o6-hA zOdIQ at KCx2V|NgiyRsa}g>JJ_=BK^0gu`=IMJj#OXX`q8Ls6v2UJduXXZzV;1o4D)Abk7dN&D>%;fu( z)iz7UBj*gJTTke&L{|HP(EAKj2WAGrgVt_!$YXlTyP?98RWnR?TV*hR3^>Eu#n at y? z1lqPyUcyIKRJgA(ky$r4mgZEwtqe2K_~CWg?SotqOSA<22-P0ukyDcKTd8<1c}q;` zQ5en0#1-R!LNAuX9bDO~t3!EQik at iGLF?8{rxI?i^nnT+9a=~j0v+z~V#i!ycp0BA zd|PphOU~xbbL)SGqa=g)aTeo#j9yjk(LAzi)L1kg z$+L4M)%nf`@>5tDII^?g`fQS5t9Hs&z>5w%4vq4C-6%0&5ACgkmX_KODV) zXQ__Z5ocJOl|~bDG|+?7(0(bXKwrjK8Ot%I&hun1JNnaRYu^s#j}RRS z8Ns3t^be22kBV62HdsT-SRy9PkY0SH?n;7u`HXZ+O}1zDDrsF_d)IPk(qP-~;Q-d^ zh6=q$g*?jiOA%-jLfv6 at Bp^I&Tj({CtKgL7=Yh at GT+sCSyA`>MJ7{Ye)enGzkUBhW zG|xVod`N+A-tp&x4>7$nhAdSXmP$YFzyb<82p|0L(9-AyTVyshAXH1 at P=!mrOyuVN zr1uB!2q=>?&@N?r7Ez%dzwAp at mm&ycAYVX_qGVhIQP-!rhcyVe1;&f?WEU=6ckHe2 z!tS}Q&b+IwMgIK^0eyMisS&64-7#L0_0r8^nwMs4%8-GbQh=)u#iPevNx z(N`C(Z3LKk`jSIKif+OOr}lFLlIiLyHj|LN<^YRmYYfaP zMW5M$n<92R%mfw1D|GCnvFj9Htm1EelMMRIqRn}B<%2S z_c`E52xb#jzh4E?q!`ar?(o<{%B+kLN6}VWRYXvc!9wh|4-^#lyNh7XdH-|SFpNOE zA@>98G5|T}aSazSPUi5(l?mJQK*7LNIW0G+(GbGl7ZiVxHwfgG%OjvP8EhAzwMzIV za{`?$fBojUGGrOSvb%J}%v^YD21*PCWcye{FfhWeZS7hOm%i0{Sx&J&iy|r|qeTsl zD11x$e-yC&U^6bzrD>23H;xgF9(Tbr$Mg8aP7S5~;?QA5`keCJAMhg1m#zfU=`O-^ z*eoQI>J{cw)52AGb}tA>R*fQ#(Ux>`k4*IkDUX(^e_r~E8k}OeeE5(^?ZuV6F>p#h z>a;aq=+QA9p3~~H9CY(Pus2YQ0t@;Nw1Q(s11t-><`@*kpPV#{YU1lA-=C2J9NBA$ z$MEPHjk|sRO9 at VaWV6mqks5pYIh**iBKaKD9>Y+6_JJE9YPh(<^I-XQZON at m6uyWZ zNqVyw8AtpkbyMrPK;89MY-!MV6KK?}w at jh9EVsF_+YOXXYAo5dU^c6Zy5-4z&zUg| zrpe;IccR`;VKhcWO#+I`t`g>plxY0b{ftDDVgpjy{TYm!5FRgmAA)Lj1BBI6w#cm6 zLniHaqe&qk9Y!ob1TyQEP3M&vsEzhmQVA at X;3L^Sc150NOi<~R~03ZNKL_t)G4ywno zy^EEOE at +VuMB at 5o2OItL~pM|JMMUZyqp6yf- z8ADMP8qDm>zY`!W(j3v%SN)kB>x~o}6sZw#3}^15SRsSl zqkJ93+RwbczHnYFHo*rhVNpoYZe6r{DR7H~3q|YWt=P>She~VS4tqWv(>S`u8Lo31 z(-O^mpJ#{-A!qwxF}U4k%pKLfwYiyw^5C?{kqH@|M_k>Ewwrf}4XBlD!ZXB+?sHS) z at WvdtM6+pct*d_Bk)DDuB}~GaC}K#q$5a at adZi?kw?5a>Ak(dTlSL32L5B59a3N}X zSs!gDG5AN522fDT-4)%#%NK=Rmda)BTDthqC~Axy$^w}nhQ227WC+IRV-9|>#*f+J z%1E0CdiwkEe!Bly5dzoI02EEd)t~5=iAie{XT{CXW7S`SgS&bJ<+CV-{H6cIKW6>F zK at XTSu!$!)F|b4uI{etu#QP#Y{C#e86 at WpqKt!%Yr!7{mAbNyLHaI*yJQ%P0yFz+M zt43=WVGXfve>PPoiDqLj*@80*B~f&VDGm5-33xd)pE{4{vng|s at 9{qwXaU__E>w+@)S$^m=WpfN8w at Ykk~Dh?(1bZENgB! zk#q6aZl<%Zm4asZwnhG_(&&J3k% znA6=(L{zhU+fHc9T$gaEP|sMCMnt;!d5PLfk^ITQ8;vt59kJ*`9oP}Y?NlzRWc2Fi zr)dVd*|BPR?l9J9_XsN{Th_xxfDqIqmrv}5RJH9kFgU9muNXUKn*0H4 zRCV`PbW;+O?L5N?Oh5z2ZW=BQwk~5CfKW4vQfTk{a;eC0a`@`pehiXb;uZHO-u^)@%5NXSUk|DruteRKhp2&& zG`KVD`xdUrFo$3TZs+B!ACJ-`R8g=D3Si5x- at K>U3KFW%}ReIRVKDe|mM~hjK^R0h2 ze&&;A-!RJKLBQ2{>d*5)E)=))^3vt2v~@!& z*6 at i46`uJEjQ$_LnxKoS$W`5mQeqeBZO&L0onRK+FN$$?_P57lWY!Mr0-ltw>+zla z at IY`HWw*7Oj at m$>SkqAdpOMGX_;a%J z at DQw%2yrI>&UnY-UM@iZS$NQt?wC>U>{<&*jI!oRp2Ie*2Ou0x|GnFDl;e4Wv)50s at c ziMBOG&-;Rtcbcj at Vwpo@fdY4DWoQWIzrhB9BU`j!HV<=8e6 at d@8hrX#ytG9fG=%kT zvs})tn(=7AC#+AlRvc+IZlQ~Ph!C;#8OX<@WQsP;!kSkL1h&GLu7C4SLr6BuC+8g4y at TFNsCWD+lRUfuGkx`N at B7;@QY8_y$5^@ z-LEh-MadZ1XTTeIZ!xCYHEe73qd{Zk5FaT3LVLwKe6?Q6`D5Tz8&w8>ha=px)#)u% zEc&p#9H&3;C~+pY#?7N%@~=Ue8q~+&rk(O)MA`uULSXe|BwUU(SBs#=38-X&n{7}R zF at r;m1X|zdRKtTrTPgG;`m@!NVMsswSLJ5$0Lxj3@(#M>2M5q`fPz;~w+4Bh6o4&i za6KVQ-X(=eQub~GR(_{#b7H=iTnr0AJ72Ia!KT}uRYi-1plgE1KC7&~hKxGE?|y(& z_W}a^#9J&Vfl$D>0|F%8f$01uF z&kV_B#2hdk(UNZ7_91Z at BL?!Y%uMb|A^%+=+RX!o*)a{)rMjrBVCA at DMghkPI9{r) zy~`|)U8iiERzN%p`O{msam%9ds`F|=lhyFQV8kiPKNDK2giUp~eY9R#J!0qz=o**6M$aPwuOu^142Xd%fB>*(X( z$^|@91^#@O0*0kt#@f6xkACJONkAaATvOCR%HR8OD5)Ys>#%$1YAg0aq03b9Fc%DM ziQG8*yw5~!F_fI at wV;MLHm z)CjeV#4Ln}>1LO+2Xy?QW~PCIp)#;sA?!iY;=5d^Nu`MwJl zd!U4ml8lEmtZN)h?T;(RxE;tW>!=lT)2P4&(F69YJ4uBsfmxJ-CGCeJ2TkJzMtFA{ za70oN+zQdA*s%nNq(amgij~(eSFB(99<^1&HBcjUOBtIKcW%T9U>Hp>v)d~4OJNK} z9aM2wDCq8bmO*~FP#Hsr;acVvlH$H>)&Ht1R0n2stziuFit2z|2p2}=9ApP&lb_>_ zPHNFcTs_&WjWDxhHn>5x;%pr5Kn*6_!{Tflzqm55?>eD#-u`HK*g!Zly;Qk=UKdw2 z+8&Puh%Vsgi_1KbQw(aGD_ at Y@0vE8j`nk;#EK(9v1i at u5XMrF^cJfQ at K|hJj)P#8C zoFj*^OIi^8A5OKu?t86fEjJtacOX!NjWfbtTEiGq$De(=#EQ`R<5v^I6xSJSifwEy zxK;!r!HbjUCkucf%I^8^5p9UY73U87VrVAL4IMIn_|Rh=>va>eqR}VV#tOB9lk1>t zlZeiQ7#J0Yb~#`4Wit zustT%uxOeB0134?wsFR=VQUcfgW9TyGbSM5Nrs?1|1Xr`LF<@~$v`%H!?8CMy2EBs z_rZOC{(=6f=$UqD!G>kL6#3ku?2&f>%uRL{ii;*#nz-1YgVj`5g)S;aY5&5zVEI5Z zyU_+-r at NwNMKqQvK|$8wuBZz|yr9ukbm2Q1z0DD!J8aO?EHKRGms;}?kpvYERql(8 z{)+H92eZ(~n>MG*E<(de at 55#>9xS3nD?Nq50oKvo&W_9t5IeY|9Rr{n^{+c0(vhZ19?`fX?|2@#^{i#8BT5xFHm?D{v9Jk8t4fn`#G zNiOy at yMYmnu~t97e&Jhlo?9wqkW_6Qjl~)ZCy#Q9>DM+F1w9j0oiCuXpqd!b#2t&y*%O`=$Zoz6!m_U9Qfc*Z8r&J#a^pZM~!s>W`q3?%0 at FfnIo^`-DIIQ za{wM812!0{4k810xH0GiLpY+50enpGtyV_M*Z2fV6hce0m{!Zp1uJrOOyqk6yV$MvOv0b5 zF0#l=Cv;~XC&|c-i_Z~dM6iX4J4)QpJ`98y?9^Pl z^;J8ZC}vhG#yxA-9KQSJTUboi|Ge zXT-)9P_+1L*)=eB%7;^~MQIIL;MAhY!pwNwQ1}~G(ZU|!{0d{lx_Da>i{m{Nb3aDe zsFuv`FnG2~b0%k^b(FI&x~Mf5WS3q$l*HMyhK5%RlQi-lFN;3>hz$z6OPVdKW9BW?k7YtprK(Y}T>%RP(E#cHC^EVU`cb~g zHfWy9g%;=Vq9O4zMKsYNRL_>3$3n>o-Jv=Rvvzn%&92WHM=>*Ap4Q&dhyNPEf{l)q z9vNS#P!P6OUdU|F`0s!JTYbtYl==PLAeu4;!bgdCK+hC}gi$Llu+ZbsS~jly={P)s zbJXFWA{{_ICmAo5g|D~Q3oF;Xda>r*zN_`D zxrHy}4swFf2gP9vAI_Z8Cd|WVWDH)VH-rDWD;Y2bFM^L@^^VH%q>l!W8iML7uLUc-G=U{}OCML#|L#s_&khkLCu?Gn+`j^vI1#}E#r(qNr4oaoP z-)Gm-qZ;j+9Z~*57 at bmUDbbrWhFh2QR5-9`AMGDQvZUrwJ=5bVK)DnuWiW631$;Tv zeC(2-Ev|E}j6jc9xkJYdZoQP2Iq70id?EkL2o8J3i(8uBr`sYBn9&?c6+T5b_mBjW zH-%AG2s>FW94pB({xu68XW+ at jY+N(88`Kq9TMJmXFkVC*(~VO?2~vGgO``~8$|&gJ z>Qm%sWErN$#o&|$426q6_e%w*^7?COUCo}JE51fF=*@TuE at 5=4 at IE@b_xYTWtO^x-*GMjuhQ^+}SUd0NMs9}|7 at Yy?tb-$G)iTsT zMaX?={lj_jqiKFyPx}2^QLnhj2gU?d%#;2>K2ZB6Mbb*s7;dnZ7Z>~U)o?;}V{7_^ zZ-9tgTduhySW>7wqX*%zo{JZagg&oYn+Qm&S{{)U2F!;%%-Ed^KEgNU+xWR@>Z+;g zkqL_!r9!mFj2x`56a9RmGbj%roXd_uGo at AwriO%SvYdr;gE!rAG_L>A%r%K7U_Ql} zwyj^966T zfF1_&Ye2I5kk8dwN=od5AIBh zZhGsl4IM7Rh&YD+_#Hs48>1M6z=dAz?3Y;*ATn#mcxhyyEK2eGx~SVU!d$hiJX+ls zz>*bk_jy3nnLgDJOA|yxKN-$p-13GXMVPHkf>ItY0l0P6%qNQVJ!3jU|C*Ju++zJ7 zbXs_|er(Uia3lsM4#QPozbgB&DhzV2W^NBqK>KJtl3mUQC*su<5}L z;@MoH@)D at i3i4nuA*Kgic(o+32%TZue%r(H_*d3;m93(Pg#CVzvQnFoaYYy7Vj(B9 z_?c3AB3qSE>11ty@)nKD$=bdJhR=e_A9{m+6%n8aRkWSIA7r4+XTSAeFJxPZ&JfY_QPi+Q zCrg*;D}Q1BjK`A&jYrEQE8-5!wX*o2zoM3qLC3Gwl-%FGvq}3+BfJf-cennGI?K`B z<66a~OY4$UQvP at 9bupd{o3xj^EyOF*dpxzs*|Nv%q&{iVouzGzolOA*q2A`+TCE9 z_}x2;?cjOvbSqVSdW##FJ2uY42Gf^h%K4P!2iS{()W6i1cFc*G5kZYx zhmq%K#&VKM& z6!B(z0^Yi&Z}SCpk`MiXl1k7Tq*6%E9ip68q)e%B4M~PF7Y||qJK6FSa?6+o)p1{w z*q$iAojkvhuRh9$rsf<_!&UK;i47}fkp+dLb}Dwq;pgT;`E&7Si)!Z2ZEYb6mAxeg zsNcN~BA-SON%hREH2yX4z)DY+7RsvnPCO0_>t=&9*rEj_5<-SZfE8H-8WLPyRCdG* zCh{Vrd!%liIf- z7>|BjnKBWBoDjL at d$RqFA<|!R3^&LK|qO0!Uc7vLd-y_ba54r~iqZ z!s(9tqP2RIkM;KTPZ+2xmSJ)Mm}5HIas9Q?-3aq4ig`+Ys-KY!m8Ba=-%TzWwRLs& z+ at O*yGNbVsafxw3(%5xbMHq+BS|rY&&MQs*KSMAX!%`~GAW7;yM#CNq at L6S6DOv7l zmJ^4lL7kLHc>2qpIg1FXAglp_V-1HZUGqjGAoB2N`Eq;B)ZP|Y9 at qF5Y2lb^?Scip zCYk`F+Q%gVEJG4_O0ww)}kcjMw~!HJ~5rX_R_miRr&D z($?_4VL6*mUfEtPoII-RU^H=D@*XlNRf5^4xVZYOA#d*x(!qn_`k(VRLP=`6=KVa^ z)ESOl&5trO*N!ebBR*l{&Wo+PJnuz at AR! zqfp<8CNv$B006s?5`-_v78=b05U~Pb?U+X*@W=&v2~GX^WXn>&5Yo>okbkt at P6=2uA(ZX+*}| z)7uP~7K^zJPFAh!^u_bct|55ksXbbuLe6l9)s%{0T at 15+Bq6lT;DR$$lCLI(pzbhh zqW*FVtwn?VQQx$23gTgoXdtzw5BF{~2C2Il3k_QE*xoQ?$l{9Uy4iP(+Rjx^Y{vjB zYY&Y{=jw)J~m%Sz$@R&;OjlZACjdCHGTJkl_+r`$9MZ}N>tRP#xB-w%_-)fFUkF#uIS+-qc zG$p8%5k^MosLn;?T9XtrQ-g`LF?ahCNe`A z6w`{JqET$~qMbCd!n*tzS#(^_0&~Ld8^T(SVb@|Ok~>yYrKtO3 z#lQohTk%4WcWDg022rA^&^RaS0KUa4k*?4X{BibyD%=O;tW*=^cJ}Up0cJS6FC+r+ zWF17frEE^oBjT at APB7a=?9nyaaUO%Mx{&ia=N`6G<^36_w2F*^NY*B~z(tt#VungF zdb_XGD<>vvVoFquv18{ujxEDD-)6=QiTq*j{Vae9R;mL;+iC9xV&ua8*R at rM&Ggp3 zvjAlvch66XtL?#_5`U3n2RG$(YmWS*Kozp10#2EqmeB at eYzqjP{clCjCoukW22=xT z{O(vE7Cj>5+$yxKt4&=e7KcHXSe03%f45OyXv2$8Wa#CWiq63whx*L?mq1IVN@*cv zqk*1N`Ju;uxmF<^tE&olK9^D$ESBqO_CuMmBih->h!7yGvhBWQ*F~r=7XOI9 at xcU( zkJIzo0eh^BE~xM-Qvb8<#$*}5>T}U*vl~+CKRd7;dAUTG_N+iBSpUB|5*dBPVgQqk z*zU)cLp#3lIcnza{2 at wSRw58hy|hODKLi at Ih4vuOT5CA!>=?_bED~KCrmaelT+aI* zs_fZw8<1w*9-cY#FGMAdz;nU>(GSbT32& z)H~>5#rBzHaV1L^5>^a3B2REpQ?D}1CjVOg4NAAMrU4Vt}YcBT>Njxc!w{|Oq) z%qpD1Bz-RlBqD*H32)IFpv5iBK0CI?CsNZH>`CNd-slb919TwY4f_9Y4)jCHNdN|_dd at o2Jyn?z(%$Z*8Lo!R z92%mvK53&#UHF{RsVLXXHZ+LNkL;M9H!|d(4gbtRLzYgyBo at yb?KKR?I}h!fKd+(R zk*{_XXv8(WJu1`~oG at OW74q2)jblQsg?9ISDX3000;DMb57ZogIr#5#K-Ea1f+9va2e*>U&QL6qOqWM)BTF5&U(ZEOIFNfM zksVnyvpJL{XV0U5q&c`H2pGB*d=I~Yl7h&WoJPL%Jsxha2kJeBUD^b`xz}qtVl-8; z{!Xdqu)GU;Q3w0T{rkD2;}-lfL}ByQPil=MfZIDCMJIDP{N<@Vj+W|tGPxjRSjk!( z2*So`uomUvM`e>gJGuv3vyLg_)_HgrLsm;DnpBt$r+f{mMpUE;&&-%tqdV{(P&dls zZb6c5hoIu0H4N~>fjWpyZ(!g?9!wi2Mde2a1Ggd7DmSB?#*_XWfCiBm3!SfF$P!CKen9hWYV9cp&aq1pyvd_IUfh(V;o^Iq4O?e zEm^>RhYV;%J*n50O@(y0`kF^kDFl0nSt$$cd|K*=tpy8JaG;5&Wuu>^EN=2|s8sn1 z*@oj{`1`b|K$V|?EP7Xpya&Si>AxO`ZV`vb6 zgYfIlZ3mZ58C+XTvQb}JznvMtqJh5;72I*|8oX$gIJPxmEKyWYnMxB_>RXYC-XaCk-FMwPOllt|7Me5gs>yMm3 zHGZ7-R{Sot4-VSsY&k=ZiG+)()Ni_c?81P+722&26HT7LI$d5=yFhYu6G`S=+U}q$ zSbI*AMP>^!mOB9`(CU6L|LQUBX9MeVu;mvoT{V3HRrRLCv;Adu at Hmt-mCDaU86wD_ znh`GW_)X-xfB;{Za78O4IkU4ZWzk?}Nmb4^2-9 zDOiHcR=fz7OKhhGz}?NDLOZql at CQrqp0ut zMLR8ccxg>gbM<_vy{G3foMqk7cd-8Z9IC9tP}N;97XqPA!!SmP8#1hu`0H^jE@$ln zie6%-5r_rRC`~v*OokQtmL$+-G%t%X`u)cAn|Co#< zfU)dIT^P1wJSxj%DELdJ%=~#uamUi2SBVWon!-SP(C@;OG*}BtRJJjB6Q>_-VMi7y ztYXf&`Gs%h+1uNL-lp at st@sY+J0R9~rvm-&jd09A zs9OE-j7n=gWq1T+7gfA9$3SS92Qs-}1V~O}swK;y1{Pt*Qb4?Js_C_K)1pji8FAV5 z`$Y}4YA>hT!Sb!8tj6Cq*U zPT4IUIw$b+C}F#TCnBkw>Ik!T{!V3yrn>d!`6ZgUBd`5g6qA;gb?8RAF>HZ#fv~mC=`s;^9;^UX7qAOet1x*)2t?&BCkjVn%MKTV%3a2{vfLol at +M?G&Ie_6 at qJ z28S@>#0~lv8}8;}5{g^b&dPF49{2 at Tb+-AaMpQ}1wsKbBVw_%|5n76dmJ>WPHa8fA z#pz&W16GlPCx69Kj8SzmDqGhZR<0{PF$n-r{XM4C?~y|>B;&k$4h at -jpynS&fyMw*}ZU#c?mxGcuEY;aqfyGBL3 zf?3^JmWj4LqyIM2YAMhG1k>M=WvF8u__ at YcFpcz{Kb>rGVZ zT!XS1RGvK$;L;kYKJqwEPm;SI*eNBrTZxL3XQl1uqgaQ&vh9JX7KVXa&#=p9buns~ zG5^PUpG_wAeYgC^_#TxupoZK=dnuJlnOBXFzh^9iq-in19lDEX1yGl7ZlkX)y!BUq zgBiUY;#?T)a-)Z|)f|$v0aaQsR=W)YiS+NnK5-m*HuaGy5f zLGh`3p1VOlFVnjiz9A|Nb7~C2EAAy at a!i-z4FM0tqZJ3r=qN~(p}O1>Gv at ZGzc_2j zqIXtvyFX6%vAJIZHR49q{rrP155_v3sId|(Uk4BtjXuk+`1hHWi0S^jvOm0r%lUhl z6Ba_A5)&dz*RhqOQp|yqM9dxvvA^9_1fbyD>f|8oTz&A-{#-7w6S1G8qsv8Fg0nwI z8<((!e|T72mZXfZ|So>+H(B43VtiSf#e*fABU<-?Oenf`^!W{n5OvunRt5hTB~ z5E+BA;1;GSkhq#YRD<=ZP^dHTXY73aZEwX~aO8!hw1yb8BRPN5;%Xd$vX( zADjx0K4(ePYXO_(V^}dW4{!|}2$W=2c<9pJR5q7J^`^Fxv5~KF5dkHp0V8VG@`v!a zsq0WYQVFGs$9rMP=|&PvR6#K|>u`InW}Hm*&mPjCXqKkn^~TV%@T^Xezvcx at c^#^h z;2cEu{9q*juL`F)^zFaIV-QubxH#k%8iQHk**D^27E)9r7aA{DPJhxjeapv8nhM&o z0$Y#?z6az9H*)rIK*Q7hOx5 at c^;uy(CM9o8BnYNaBHuABMbO9JfcqQY6!m6QL&U7! zWe?O&v4Dr8?=07sz8!|B{PR)3i^3x3D20H{{xF#*hm`w4KPqPyAt07R$( z at bi$;b94U-i4}NwUBY=}QSOuU8pn(NXGA`u|Y4AJincWu0ZL}m5N26s0O-WnxC*QTIk9Iv&U z{@yGR5>aAAB+MPnF^w3|=&}YddUcTiUpz^$1 at SiVV3{*YjUCX4GV$NJo6`3+c1Psjz7 zsh4Ay_9U|;_khJ5m0`&xUFdw3_I2aV5c_QBQ&#Ntv|I+g27zr5EiRh9n|`G0eb_ z5I_M^gT#L&P_nBWAql@}`XxF~j3$k|rFB}W;d*;%O<-$iIGco{h<-_QZ zKO60ztP6t;LD(bfyuc5%pt&`3-=ylClNj&wsY)ak>c;aKjd zhRE%uB0eCj9y)3+*6#-UuU)?B8eRiW1Ud3y1X##}{(hG_FgZ8wV1w8D6hp)nNn>fY zR;QpL1bP^FE)&vL%G at 3w_d;B1K6j`^HWWjPLWy8edm!}K4X4npCUm(0OSUdnAMPE at Z}gJTi__bY+!=_+RielX*CR(= z9;l1g{ku7?eXeK*rp68E`Jk+cxAA<4a|0lBFcrx=9r?oA#*(X`@rCY$Rd!6f)n&*r zmpoT(CcuT>*$^87cpIn|A|#>kP{R_OvRAh$RD~RadZRHDqG=iQOps#d=wY^bWnm!< zxd|^-ZmAE!6d*jI6ayLBIXd1=zQR>!&k?@<;-O{0(=14)7ajJ3V?j_@=p(;S;gAmsyeN27KWD|@kq)+>&-W;csHiu%Uy+{1e}xB93r{^A5>(_7PX5kip& zY~kGM at x4RzE5s+O>fi$OhN2>EaB45}RWB~1Yt+>Eo`gTu4yhAUC7(7t^XC}CVYg+fv^U%JGn at E)uKhYda z)Jm({%JM at o2H5uoBm9(BXledQFX5G-6`z`~?bCVm3eK@(SC$vH9~K;C=#pH)i+ZgWfwRw$Q*GMR`? zmh1;E*Rnaxe#yf*Qn?A=QF^$n&hKkRs^WaW5>fQocaF?tutB zf`>+D|FkP!?(dN9Xa^Yf&|o^_M>SnCJBX!iN3-zCcPNb}qh0sNv0F9$D^ilu%#y{4 z2~;=0920UOs;f7;YaeM7T%ZCCNZE^-#G`=QjXnkCUX-&&R6RnD&_L9lL7DeJMa0V` zplJ>$_YT3+dek0!7RJ&*k=etau{L`D=9Ozd?`=doF64M=e)Lc}LkQ>x*6$hz)x6Yx zzk88GGXEml+Dpf)R^#_bSqarJ)5nO3qk)vRz|EMk!s)C|BdjS~lPNJ}Mv}q~O zb%~%S+~fC!NzG-jtu-=Ss@!F6}oPOWdF!gL2~(~fX07qoN at Z65)wj6{1AJ{ub4+pn@$ra at WSg_6lI4|yK^cO~?I6C~}lJ9stW$UBIl2hbWe zF4_tnozw)0p9{2ibd`}B5?O*Lo6>k6S{n>ZXZX*~kC0c<3IAvpcIpykNcwtVm&Qhn z2ZSAZ*lsdUeDNImy8m?ykd}P7(o~ah`iyZ^mdn+KQ>_nAlE at j-$ zI}Zgc`w+9=9M`VR(yEg-Z5LbQGZY^@RV>bRLqdlVx#?K!T5J at nmMB|bNWiwXOruOz zl#^ zbtK)|^a at 2UW}kfwo+xNk`~9N*1C#Ly67);IcxIwO=0p#`^pSTk?lc$L$(O;?xh?qBd*(Ws_wZ%tLMJ6adGB0F(fBGE%b%f#_d)=m7&54{2r{>DB;_mEyX*d^?R zn10Hcw|%tG at YzHZQ(wy-!=wxR_jduMe;JQ_v82)Dynr?jU0SkKC!5X|mdh7|Gc4}c zMfN5e at Rpg|hmFDV%f7P*_^eU%wv$;JDR$Hb_d5gMZ51XaijebD&kC$(nyWvYn#p3> z%{v#B9Y*KG854qv%@f-9dB6TgMk=;PV)E=qP~P?&A|xm~N}UC#YY3^K>X at ZvD*@s+++8C)6eO}9HZ*a?aCk84{>mFYfQPLAX|Gml+LGa; zZf6A(d;cNwDuIe<)7cz{l~Nm~BS5%yz3n44AuD!YMCA?&z#TCd(gTxQh#{G7>goHnK39bCj90-aHqJzPiKWK^PDRHD57jkymM_ zF+~f9tL=WE9=Vaz;@ek0fVjY1AF`E)`-8ZKB%!L&Jy^F*$2FDbc~yO3q*NyAfoYli zci?8>Y%C^lRe>@9wu at TW1!oN&(Eqg~5EG8*lqaapFC6)wkbP;k&oj`wvyB$_uf=Gx z94d6N*TpvHtro=owF&Wa81|6Hdiz8ul)ayZk<#N^5b6k&U}lawY^Ubc=77)D9x;(q zt0)0>R%PrEJ_LRylp9NQDUza>3(DK_F;DXrmjjoiU!@jJmH#VCR+im2_xgi7*(>&9XJ<+5!W>MnmD|(I$Ca8Th>k; z*_oQGi;POf#C2~ACYSFe$@L$L>&2egD+nc4SlB^7mc^x2Osa{YI-W2~sloDVuR`R| zjr|z|6I+8`O!h!yLw1(;x1bWVp*A)Mb&+VxRbQ*w!YQs1 znhfiXE1!H^lYrq9?_G~U)gHG223X2>-V at 5 z+=Q;Q3cJd3h^A{wfO2l?sFVxgP=)?psfWF2B{piff;wqY7&ih#oRjHJ6_NS*ZXRk6 zLu`u^kRjFB3GCA{eN97km;|U6E2{PoOd~TGn^ivtv|v_6&i0}J9g5(bb at 7od)l+uc z;Wr}2&u1J>wu$=FIjnVDnkz|83q&M#0QW)yGRVI_ at jK9c<)?k&)=NpY-5E-&mM&P( zL%v(1#6eVI;Q{tEf9^7?9YauV4P>HZy3&?K-PFxJ{SbI(W8zC~JM1aM^jMuZ=zya=B z$@N{*^`Uz2{oXb2Ca;NHB0fDNLXt;%l`ad5VVGjPBV9!_SplJuGR=~u+tGS zL4h=f$p$N;Y>wZ+NEiG^Yy%soDFxp~1Zxgc?(JaJ at 6|)8#n7OX-pj*DmcfGo^RvMB zbcd&Ih!nF0DKzqlD8Rm8sed1LQ0<50o(sN&02j^0#0EB_U8<^YD;h!#AV0t;gl>2J zCaR!B9}n~)0vi1zXb3Q at D3epoY@xNt+A!(6PP#(V>)A#@?iQL5;YYKt9cDaX>l*kB z3&gH$v`$D7$ok)a7ttF*KY&{Yce+%e8q;h$fDb?{&d2`!YvZ z0ZQ%Ss_dF~r|v8!A=Y^9i;Z*EP)NEq@}rk-F4@)cW!B;{fqcUwvGl$;(M?!O-6~^Q z=SE&gs&>TAog0aTT6iK0(lgI`&?=|VaT8Y~hPB3`DwAl;ibHvPww7#jh7Xm$&SfBA z3{}bPDpZT43b+l0kH#CY%RZ8Y%Vnqyn%J&kK3r%G z^tnS6N_&@ZD(gM3a1%ZN03ZNKL_t*9RI8g$U}X%eYlx*RO#;u8p~x(ZZ6+;jtDvKk z_2GdyQ-J_IK*GP1zk2m%=4Tgu at d@33D+XTKjkud1%BqDiN4#_7-1`v4^l|FO at Tg8; z8Jz=f_J{}WfZ6Gb6IaH9Xan&2_ahI92p%61!NPw2E&0Rm!3H*KpFLXT%Ft>%kQASQgocgekF3!Kh zOJ!s^wP)<~lv>Yu zOZuJNe_ksP8l_E>THw{WuK%}D^^B!WVz#2hK1YL0I)f8TRhZj6V}s-~#$&;3 z3hQIsTO|rthY1_JQ7-CcSdjeMT`23F^i^phh7py+d_T{b3t?t6wg=B1pUl^FaD>>> zC6Ob>?>AHH4`@|4mu9+I^jqi^iMr^`z=LbR^GOWAG at 8p|JKrHk)k_vgIT zlv at mcyXmCEHCgZ({nUR}d_qfi7HJYzNG%1`qZcTr^Q3%nuWt5(It+7CTr at Qow~5=G z$&Ch`Seo&A7{<@Cv at e8h$5iMTkPy=?*uV6H$JvzZ2CJ4McFYGubKqA!c2GCxSxHFh zur5O_u-%OhEzd&5*fl}wd^EY+n$;nn0euF^74(ZjP+{y^X($1=Sn07A^qh$@NaC}= zNrR%Bp`adrY4=$2pl(lV8x#okp7j}b=cg6q^b?~j;@B?B94;4sIs>pt$tJ*IWdaw(mB0b#o|kZ2dY609NIIUCve zAZK6gTt}rO?Ty2JT2DI*JwbtgK`#q!WOvdw0|T`JvmCO99m-XHP{O}ORc7h}B}L&w z{IM_?yBq1}2u!{NVf%LAy at x&T^N-0ht1OM}Jd1M;mzJeu)iQ=|lbX&vY9cRt<;)Q7 zz{!mMdS1C1swSR++Y^k4f7*TV_iy-N{IIaJ`#k zD0{7!!|g-IP5#|`HKG=-9P0BA)VXmjr9?1tt)1e?`a`aIM_qHc4MciS z3d-i9;5&@2&*vLP%*+sObajb~0DaX3s>DTC0^mK!XFG%<_3?nx6mKQbEU9D*hF)PJ z2Baf-rssF=@|+Xd0)Hm;d&7En^{iDBQ?!R*8^eI|qZR!UBzKdwBf4BRQT6s+s at A!@ z*bu3{eCdDLDojP+TH%-yU#4g2QMkYs;!L~XV|7H)p836SwT at iXbyF_Y+k^rcJ}9fE zeo-jcY9a=@l0y+epii!AT9^%AXBMptZi*_}IfDX5&!*0r0a6#BjS#!4?*?N#+KGa& z^>PrW>OIqSL+=q_Vp0W0W7B2DW*f}LO^_^-x1W5H`9&|hmiO73r2}o3X&u}LjsEAr z#6`^&Q(#xV#EBp_vz0=>_Ny)51*U`{&&`RlCWqB38xLPX<&2tWX84l{J?mXGEE_EB zl6!pe_FK;;Z at h}?uQ>_-I~e$Wm?+ynOq-D7hxVVcgyLE}5wY%yH8=yEI~*5fe;1@( zULn4`=|hYIFa{qwa@{|rBHk5&Cry~Zg;WodK9k!~bS^C;9Zxs1Tv+IkFSPlEumysZ z%WMwf4}FDQBFro^(-UGl^cl=7wcmuh)y9qrK^-MXJvILC-c1zt%w70 zU6MxQIJDPcqO%wvlIKTJjTw(|*k^JJaIv+y{J?#YFZt1Oj-#EoGb=;Q$pw at Yh%l?g zS2Zy}{3VM5A=P6Wm1!|RSJtAjJlAZq8(jnu60;z55i at d}*3@$4R^?(x|HU|*f4>78 z?AharGefCs=d&ze<5K<-MwjxsmuI7CmMj2Eo5Ygm!~&lYCBGrubV|oD=#n)^F^71Z zlTAu}??$fwr5_z{tv5pQq&^m`((1c>ev%J-3?Ao=F8_YOKRW|rAI8t70j&>eeKR(g z(T6?x^qKV-zq%Dn&@(IxdT1 at 27C}>5|3$Y~nvT2B)(5!8QZKC!ckYuQ9Bh*$wXZR? zY>DXXV-0K?75~_l%Sr-*bvOo>1j4UQrSo0~l7jQ`bUG5!h7k4OJqmvD(oUebq9D}W z{bvyLg6k$3vMwxY^ouW8eY14qiA7xy7C+*l(t>aFgqVnQ|w%DVjiCU`yRKI{dTvE{Y z)&Nt_h%M}6VPovwCH8+7S|}PFtwGeBJkDEZGuBdxefCurBiGVA91-`;ULc`z8U39N z`-jZ3ECAFU!l2qT__ASjpr2Xmx7DFVXSyzXLZdA1-2dl0T2Zj2XZK1v6phz|e~6i* ziEYvThcuS>u&1U>qqI>pM^tTP!9A_Bp0?|_ghJ;Z`AM)9qTArHqnDN+VU(d$ZLdq4 z&`=Y5{$LGL{pQy2``9;Zcov(JMiMo;88_BR=O^q3WH6kcoy`{1C?5k-(Z`TGVc!3H z*;F}xK|nh&Y4Ch8U7nYCA(I--k*jGbXzu=z_ at LzX{a?ifMeF`Rx;-s_*YC+iGi8t{ zng|<2|OSPa2r7M zQ%Wvi>B9Ung at x1Ym+E^7(FE|E)q{O$I;J1i?+fOGgc7IVE_CRlzua}Wat*ki?h`=o zn89M!Si!@R)hSb%QrCDP3};YQU7C}?3K6PH~jH$Q7e61j at QKhyj$fdOs@*{(+ zZ1|hE%cZD_U^_qlp;d+`8X$7E>F|m8FGRugE%!L+F`r2ufFcy ztTX*SxHCMp>6HSIwYfnW2FXUpU;m{n-5L9M#Q)vC8NIYt<&T>_cCR-J(J(Aiz;qBeS9p6(c~w>*ZT zJec6q4473AM&Z610F at 6&4v z(b`*_IoJWFxG at gvJ0n))NYbNT&8KfC&(Oo+a=fZ=zlEP}Aq<*yC&U|p^xFl9-gH5@ z&UJ)#9!;@y5&isw>;9(2o{S-J`c7UkHM+Ur52}Ot4+6VPTXX;J&I{m zA61ElU{M-n=)u@|39&QoYk0iRF7CZmD%CI#KamEUmqCHpa}3+n6uK&bpGj#cxHtdEJL|xo>mSeo%o_W!KAXqU| zCjdaH{iHhaXvNTPjuNqes`P3MwP&ztC$XjTZ_1O9=kS5HT^$O89>X+|5<9PF|Lm<0 z5|onnb0jyFZu?is_DRp_U)gte{)v_w?E%GJ3Lt-3>Vw8;4{VMRwD)Ppho)u-(@YK5 zghH#UTl%2Vg=|eL_5*mu5!;YNzqq7|+81lO*{vpB&6so5PJ(Y?Aza_i)%sVLu;);% za*5af$%s2(IqovE4)Oz{jA2-O=Jv&KriQQCGcDRFw~mzR-HQAJ^76ct at T(t1X(G?DyUneAr# z7ywqwg_>C(3g61ot*XPU;5!KOeyG&wXhOMY8*$j4FSXNXx&mWwFq23WKa6Q27p!J< z^Cz+Uc|ozT!N at OmY9Q&9cCu-4ed(-A5hWe2Wj~NMm4h2t3>>OZ!DBw!1r`$%h?_qG zZGFj)hLN$<1R7jO=PT9_i~EhP&NG0!{_X{_f0x|Rli55XkrC+VQ8q{1?Xe91xD{v2 z4O3zG_MA+hZQ~;GD(fU4zw?-TZaEyaAie1jrP0I^%jlRp*bXV4&j1D3&n<2?Fndt+ zT at 8vjc$|D>)^0c~BWOrD(3S`vRx{LiBE~7q2^xkKFbJa7H%}JHf?sM`B{pw1gDpG; z7OAskja=@TD>z3Ok)p~Grh?c}O>K06w^)2(#wf%41QHY#7NSd2trWJ=Yy7zwxcB3iS_)^wZ6jumE=oq>H()yOOCp&eiPK#KdZpXG1B2LcHj ztU(3Z7f;VE;468$A9o=|bFDKYaiNrQY{Z<1VYmdhCXokJnT0>2aPwh2%mCg at 5B*)B z>P){rUZm|Y@^|Nr$Y04-)ZkI)1Xh&>^PG`06y)9})2;SctPPD^+T}mcy#?cz{Kt`Z_UDtY2`2_Q>=w9 zy)58D!)PZYTQE=4Vx$Id5Ltga2`%4dm<2rYx2RkBcWJryLBEQXM+WZjL}m*^dHb?C zA}QQ79`KLPs+9;BRC$%&$3TLhQ&}WgO}HDnq4@(HJKe1jl&rs>qP!p~dQNt8E-mT; z-68$dB*55vM`w2!_Js&e7ssVz?GOEHutjI zrFCooSHEmRBuH7NJSommd-hqFL_XT zw<$4MFH|wn$^T>n?6g}scvrg!X82E%$G|dve;Q%d!Et24vU_GvmX!sVJZe-meR(%|FhFZ8Wu<#fAjJvTS>p at rsXk9o|fl?VyPyVi4k=h_Z7kImK=0`g38w z?dcIy6bCKnb`RH`zK&N}z-oA?yq_)Oy2!;SFL^DkDc=f%{qU;H`C?$2*ylYhqx6(c z)L;R7Svc6q3U_YQFE=I3S at g|}RKyt#^|^>qzg*QnZ0-0>^EaeyTo{DZMU>xl1JI0< zvTqaiG?~VaCSPi9!205#1X>FNiq^4vk3vffGZMeqz1=@?OZZdaNUxGr77*s$6{{Lt2w-KX&p+^)dpKGX* ztv((>2tt~=n=%ux<%!Wn3dy?~P4o}S08yE^a+$QH%>a_+fPn(%i=+iv6d;LMS=?DzV{<%XK*RyXpP8>zl!2$bPeMZXA!eE z7{ivgM_U!{Go3LTAp?3K1;0AWK<1l2R-)j^WM;NJ%0t2oHtPCuWh(Q{8rqSb+{n)1ccf~^!s|NVD`ifuv9bQ(01-9_7}unZXmWR ztjp-i(t53p<>VSXll`}pB>vb);THuZ(L7k&SAtVVa)r~U3`i at Wo4P&Hg!^^RKaDl zN&%>V>>_81ovojg{Qb`5AD6UERpf$C`d`dt^QC#c!J z?#JVeCi`F>_q$CWFi?PmNPXD$BBu(G6R&;;*Q{YG&ZpjCg7&(ImO1>-%ZYs!bJryv zO**61==a<~LZqxdwCN;oYQryRf`^&|sxec868%l&AA`f%v at te_(gMSAm<^Eim?6UG zCBstc{cpfL`B at sUAbZQSY&G56xv#b!M$Ndaa3wBG{0g_}p<`SgMlAAKJe}r0^GpR6Gr93tl;MQ?i5FmO{U{7lp!?s0M3r zH`i)D^85?H^3BSGvY;6u`2bhk#3Bdu&L;`M(M|t16;E8U4tHnP843+Pvm&&kPnX;W zR6hDEcotgwKKEciYLz^o_v{A6h~|gL&SJYrA)hf0H=f`<6yD`0vH_o2W^h5jT$13I z{RN{^G0{I=tbTleKwo40rT at +i@g7X`y=ixhnl` z at cd&Ub&Z>M0gY*^my;KzN{$T79cNjp^m?HY(TFg>hArrl#2q4SRe_5c*&7pP;?ryA zrXaNTZ)EEf48Fv}S*cP7SQ|v>IWyx8(OS4_A0_1==wrNW*3`UIU%3xELpA01y_3vtOziIkF)jaBt(kfEpA7$N) z+OD&yf-Vu6X*S&buu=kynK}?$Lj%1=&T3y at uD@u%WeeTSQu?JkMkGx1ZGJ+-!3CR| zfA$P>CjQ1lJGi$V$gZ^t>Q2RO_R-X0^|gd!Qi4==XuHA&yS(UZWW46X~58dEt0%U zfu~9gSc1AU?60s#lsjyzV7&e0R)rx5+-o8jE6M at AM)i!y*_fp11m%%p4(Jy963%9m z96WMTC8O2MpQXGLrS`45^>t{c{7&+&6E7`~GlIFG|My3S*4yL^tf-$?tZE!uJX2ZV zl8sm!r?3Ihn6()Eu4E<{r-LkJXu7n~kftAnKC{5QKt_B>?l@@nGt;f%KAC1X25io` z=b~queL=L_BfJ)xq9+8FO9md!Oab*jVBXqi_<6ZN9-s7jx9M5pSVyJ?0g z-I|CL|Mh^v4y*R_G{l<|-rqE3S->r-wqF+mD9R&C)ZNOXNdj##D!Gmy>Pr7Pd?CrZ zrr0|WBsOMAC^%DslB1uLvb6DPff3U!dW>e!t$bYN*eELhKpoVeV+dl=6VCi^V?+kL z+ZjabW93$sly!oON}CY%u>GhKEDCNZ(pjW*sV7YC1TqjLF`2-*6Mpi7QblI!90gKv zhZ{q)$tnrrlj+g3YKMedhj$>*uX(@Gxybt|b;%0U1#ij-_a8$gxy9XUz-owq&H&h0 z!g>z_9GROcU{VY at TbUO#UUiGU&|yUz+*t{7{!kWps)XXJpDTU#D**(%Gx(l0cloCF zPR9-KZNT*_U;eH}qAVMkaGR8VMFVnrFqJdJ> z4Id&-4NwZl$=ZcUc*yoPngyP~h*UwepuE71Fs48@`THedr5|MC08B4P%jk0r7Z@~WDav!Y z!pSX`YC<03gUVlC`3odO06$$GfZ%igM+;E*D%K#^NKE>Lv0KM(B9T#Y-a`Q)qZ8_VeQ=)+X=+lb)}oQFMbkrw%s79@;7y|> zRnNy1jtiX0(%Ex&8b^C=smSPras4Ne)VB0vzYLOS&tmK>j0?!_f0$rewP}cuY2 zUC$UXv2~7-DXPYZv)skmYOP$lfXkqTeQJsBw4*Zwg7Jkt%vblhd%#g;HVj8=I>ba( zO at wh^j^;E`PA>Q$4s>!S48VtcH|nU%cVDiU9VFeKIUEEJX%2$Y%TtU%oV|YDsE_MT z_wSlzh*z)xGh6$8VLkm*jNAHGbT+moaL at X3)IGwGN_`iSqhYd5eAps}UmPHY& z3_5p#n8DG*mDM1WS6*B(6ikDL6)^}xlS|4{vX>Dl-+p6d0|~}k15^U+RdZFzvef3w z8$_kidjdR40I3JT=G5<(27~Nb{}uw0K7FULQ9#;5X0tZBoa`-3srQMS^N(OQf!Q&# zfy<7n<|W1raZyOrgY=9tWq2W{4qI3u+k*PeE;w(Rk)#p$6j_ZOSbU*k<5g>pkh_5b zWqh(gcJB8NylzjdpL6%3F8A{&7mw`&o1+7PAPS(vpH~D-EvkcGjk&$SPJYqw2L563lEL at c`i&JbDV^`7~b4 z(HP#T&WsB~l%YJGrx%R_vt6RVhWRy$Nokc7ipDZ~yQMJap+D!^lo|J>YO7j8f)DM^ zOr6X-)8B0QkzX9JqzIj0U-^MK!&H=*sbQPqK<`v9Pdf{q%vbRrd$08ZMRtdt#=>2P zIkw!e4gJT=BF{dH=fT?#ZJE1NuhR$6&hwVK&Ngtu4L2V8)qw)?w+q;w32FL8Y?8AZ z3DmWA=tI0o`GYQ?-GbBAJ-Au|g=>#RKE;n!`@#^|Lxk@;d9#Oyf7MYC`L5H{-{uAW z at p~B}#Hl?*ZF;I2p?3_-g at Y4uq1GO+p3+NSO=t at wD~RTGeV2#Y;C}<1&DYx~)@fOk zci+;6xCR!8001BWNkl&f$vZ6S~~FBeeNnv>uo!EV=<; zxxX3i%00+q;GNPd`FA6A`Jtu859WOKaOb3|o96ByI7_xd%Ta3 at r1iO33in=^(9jn( z4MnUGt+E3lwb)43(he>p!wne-L@$jk2#LW;ti^gtO_&~1A<0Wh zR?EOOIkA`@Hy3T|`l_1T0hC*FRt9ew*fegNx{`jHzm`9E1xa5s(RaT59ko-Q8H4BD7LW1Lh;=S0?W?Q` zMgGTEgH|4g0zg at 6E~ROQv(@nWD{yNKd1VfZ;d|DuIXzBUyu70(&xcq3!b at _3Sng9ONV0Pt`Ad$N;I=wdupM-$jMOF=Rmv zDMTQD&t+*Ho|ug`VD5qAm2HBuHr?YVc(=+FY&TV-a}aP=3egv#!fRrivkMyNg zTP#>Hqu)i6H$H at ue<$rsDb0QoOpNio#z6353u^P5nhWvW_h$m-dA`oKSG*WR`DLwV zTtNU#Ei(=bTZ~H#-f)ebzGQgfeDQKufC=n}g3WOXt9+2uil=FS|;h zf65Jl5*>0hTOz<>^s(We-$ZnB?bl2}OM1bp&yZt^5|+2~v?cWfhC+ z)s0SDWsVVE8+_<;n7WM_zu3#Q;<`B>w8664$o0VC-W)&FRRM2B;dD3-8rBq0RIfkx zB0J91_+U-b?wHLYgee;AOoZ-~Zsf`2EoPv4Q8-g|Jii)MPY~o1(y7eXj6-oBCz0<@ zqko?@c2Km3*FmYzG8al{e;?dfPnt|KKs zBv)@IEZpZWTah%*OV7B8A`B8GR;&RXrTS4 at n37e(Hp%^*e|V+8hdmQhgJgr4yKpOn zj$4KW*mjRhqCR$NL_|Q;k$JN7Ic(LHc?In{d{A6XyT>*pQ+E at P3*-i-j at LcSqhHq0 z1>cwuISSAe at stwUc~(l(7EQDRBR2K2S6Qx(MnpaqU+?p*dQx+HGU5q#1kr!qdw2WlOY^Ip|OpZQT zbIZ|ndRTPab+GAB&!Hb$1+BnD%))RD)EQ`e)>!bJt(Oan9GL2;%iWp~3NVZ71+l}* zf#W0YNyhRVj=#z=NZ7fe2p at vZ7P?NaKa~du(p+JbpVnUn8v0%C=PkAz9#q8L+K!k> z6C&e at 2$fmG_w*3<&*Z=`9Sx$*VMkc#MY>-WSa>^96TqF3=J%t*5J z2ignY9O^&2UveJSL-g_gT#{)M$9ZTG8`#jJGCX9qrrFMr^G{YQ9q#gr&L$`ug{aju z&fB9M@}hNQwpqX%NX~{_x{w`;rZ_J#S$@sjtn;aO&-Qpyi(EOzkPV7b7`r z at QDlv)Z|h|t~p_?1C5pbe(rzcj^7HuD3$pAA^-d|xYdSoiQ0Eq;B`4Ix={ z5DZ=LfLS>EJoHA4lWwv&$Vu_pjCS1iuYBC$qpa+ at 2$OAQb zg$*u_vheBHoEsI?5WtiT02WcQ1o_x44ZhglL6w-*Ui2Z8%LN+U#9Kod5|z+Nxtl)C zCz?$OD{@f0NkgLT!ubV7FqxPQ_a|i5-sm!f#W5d8bGa~9i2jrWh}rfjhAd!D__G>K zT=n7T72}LXqs!+qgeHAKjB$7j=6vevZhVX_!&l=7OfB#DnG>2Dbuw#;PM8L_a2%;y zpgh3u&QXn8bNSHK;i!NSv0J1onX?iyc0Vq%V|FaIhU?bYP`%slzWgBWQ0FB@%z=}e z`qUT(M$3WGXhkiCc(w6|iHiYse=Q*_s+?b=%_1C7Xs^8jc{e3G!t9F;cKzU5Uuf^) z+Ea|u;myOs2jipo(a_#4*Ib17ziID)J+1J?okY#qGCw8p*P<@zSp3eg3~DnZISh&6 z(lVtAiWh18^j^)0>ZS{NSn7As(ZvEg`ZLFKTHM1>>*=xnfEu)|CLiuPJ`e4ZkZd at b zK(0Az53m{9_2**2^SP)FD&NROQLn at U+JH)_^`f}<6?F#o&cVQ7Is)+@{SL-Dj;={d z^Bb!-d!GjjU2aiG=}tabdz5&M*$Dxu(ZV*Gpb7^$XtW~(RnGoxY5MqLugrgR{=Q(R z-~|HE+Qv8(?!2#(iQII#6Z6NbVOd|OL$0JCgR{ARdD?i z)dcha{-6y#bS;#9`O*5Zq-Z=AYer|rFa^26SHSVBYN`@o# zGo>MS6Vju6FSuS37woqgD&zHGqtKOvWOr+@!~T3>3Z=vyEH53^d|X0yQ6o at pai7+T zv6B5Z1~?#)7WiJ75nqq)S=jS{wM=T%5KB^oX5fN~!m_qx=x1IU%oc?Y-5_khrXad) z3FBHGpyhKle6=j*%GjNO)WIyC<-_k1PHA-t5g7NXFsZW6E^g0XEbU-u4J#=Hm=*1| z${JP;w%^??H6&Z4lom#*Ff>z4BEf+MSE{~b*qF>!w1Y7AhoK+EWa3_?hd|KbAAML6 zClY_Bdb9_t51NK9nFA}T8%?N=0!PP(JI!FMVV(wuW1#?NKV6v=^XLLq;Z|6|!L`t! zHP#f=Q&B_Dq(jh%Q+0Yf*t9tcTMm~XHJU)L!x=OdDs@$b=OxKN zfQX-95x~zvu6GhSmFh+jILocQf at wpym8~K at mk@Tj6ITMks4YPoaP=sH zT!&ON$~`;O)p@{2ptLAVd(Qm5j{Q{Zg@~ml%P(S z9ksi1g?WH>TMBo0-mce!GTH&^9P{2M%Om4~0 zAy)MZQp&7b9=nc!f0!*O?yz~_h?p{TS0o%y?L*GgGkcu_r#g>Ds5OgW$OP68Ft>lMu;I zLCf$!R78O5D1>jWrtxYnI2|Zcn*`Jj%Z55N~lj7UBoR~qcub? z=?J0NW>(5a)5GaqcIp9kxQD(aA}9PsyvClT5Tvi|WL`$$aKkL!&xD4xQ9!$93G2*e z8dy$*KD>Y1toB}ShZQ#&-L_PxJ|d?KQ#1d{`gvL)5JnR1>tr2>}XkKfysy{ zqv);(_4Iy|g_q|nYVK8RG9l6Nh2L2pLnAqle6v8d$+!r+j`M~t!1$Cgee&->gWZ16 z?hUR!V#dx5117+>;xT~xF#d>{VK-0ZBhH0Ft(3T6D5#541#!IC&NA}s^a;dJdkK=I z6A*zbY9TVjvlT>ioVWWHM>3FpG2V at 14;bYz at mZ`bmy{2lyYbJy6A&OQkGn>M=jcc0g!~tkEp*7W%4% z=>gZyUqB$E3gr%$TU5I>TFn7u?%E}a=&Ty;n}a`S^Y~I^8%0&{so0s0`X#;ecL}9` zbL6I^Vh(J&Kl at qFkX^V%Oc++S43hPK+o8p*{~Im&;pi=)gH&pH)SVn{5G8bcImYQm zB&tmx9;?D8isF?c5D^=bmz&Z%FZ4#IqT{X&eU-F9;DPS=U=z<<8`?DIcp_rO5V`%_ zW2U17V4$WL*PGmvu}0Bd~x)_-BUsgMd;)ZkEMGn2kJMJvGGD%6suvMu>~sa6M%9HgmnRn68cFdY`dAY&eoLVa^YYK8tK> z!O)%ynYmBc+IcgZ0>UiHQj2}9rsMPOUd6>zRz0^<5SC{$xbfUUg))q?E%6@!XMV z4JR(I-tj at 2D^PMVxRW04z2ZdyEcz<`I$qEFHe=}m4e?OjHUmil)eN`kA2N)4kT>g) z3%T`k{|*lf!ef(m(rPYf)Evx4L;WEmGMPZ&&e+$}`i_lZfUEePEmerWMbK!sjr-ry z+At2kge%w33mVe^ChZU|uJJUTvj;Qtfutd;2j^ymZfQ)O<2y1)|L&cZ;jAbJ9wEcN zY~(YA%tLA(0D5+&1-As^_)`iVr#59n4uB<6<*vXiItQZYSR~XkAT-m+ShilQhFH*e z+#pf^Vp5{n&R8n4Rz4GAcCxwP(=VpY#Jd at l(#!`G8k;Pkro}BBs3|c!9-+z-xL^2( zej^I?yi|S=v?+~wv#*3j(^BkbzJld4#q&2m0U(yeqQ9Di at yZ20rH8zm)7SQixQ(tG6GzLrltv7ff4ny;G$60;)c(m;Oa-T! zQE2=#pgs;MyWrp`3tMTsSJll6bcSZ+YTOYGMb0YhEva^@3ifU`AZ9NxNbVH8Lv_hU zvNqRtUq|<}zi1KPk_kAO+ta9ATm4bMrK~6_j6r0DrrUwDy%Ot4<>TInaO at T-20b(A z%P-bNd`$>2Rx9q`xizz1Px_uW0r;AAmgx)alI7|9i)~Fv#F!5RZ5Q|4KB|p z*Y9hv6hX88`CR4y51G;I<_ zU7xcy;axw6vth2Xd(N)y!)#;kL&$su(_6~Tw+g^0^g-`SZLubNRbOYeT*^Xnz-eS8b9LCG=7nHo9uoBnes)^>B6V?Z z+F<0#3c%Ir(YLYTP_;l9(@=g7HUe&;uKF&X=aF}f z=G|bIuDjJX>Jf6 at Yp}{M@(8ho5BhTb_xJx~m}83Bu-t1I-N1c;V}hQL)=4CPF1vPzy>0H5Ucx=^Gn9A)$yio%8 z&~k4?UoBP7x)^cgZzeQ9?hKZ-XyF~!i^@EjC{ZB at IP z<&+l0g?6<&6c;Y7=X%)<7|CtO%s)zdOClG0JmYJ_ep& zqJOSs%=}?a_Japq1Cf&4S($IGcvNbyzWkFC-fa>U+#oLf?7sJDDFlOGMKgj#Ze9NN zkXD at K9xV+=h-7YN5WhGPnHo^3scI#5`^`etLE&guJ*W*8IhjA?Ez$R_X`c@<)?YfO z#WzTBH5OYEF)(~A8_4Je9CO6&p`G;{ER+r0y{_f?h3x>4n50O}`{?l~Mc9<-Wrb=G zeGMg#m65ahk5IGh^bW`A!p(ttZ3Dr`XPk_MBu}LXAHu!NrCXhcOQvPd1pG8<&$Ehk ze5uAR<%%CqJlS`!oYZL2o^$ESL<#tv0U=J%)tM<T%>-p=1xrVHRA?GPF{_`em4pr-=Fb_`*tNU5r@;fB^%qp)Oy>F$fkK9~EzHrq z^6u9JvT2Kr3dL9u2o*dx2T>gUfXtmVb_NX%!3atLt5up3s}WmZPztb18%~(?)JoS- zOi;Zm<;r7HFZ|^j6xqEplN7EUlzgHtPHlQD0 at uJC4Hk4MFGP{O$`#TTrOyMk$R2iA zy>jWecHygsqtG6!?g-n1ZX#WLhfHxYVpESz+huSScUb6}=f-IcL>G!fv;KX$o7kg! z$Z||WbF!3{l)-zYwut*V0;4S- at z74(@j4T+BlelR9Kifri#TqANOvCfdqF=?Z81GV zlV_JH at q`wX&0fuG#NB#sVR0F||EMf&46P&oK*RXf1==YHf6g>#j4hgoe{5EUE at J)j zK;1cFaKLMQ+Xn&CS=swfLGLHdC9cKQdRz>)nGLw+r+ at vY^~~ijSUU} z+51zTtr5e8EEx$nNH9N)kWiEyG1mNH92y at ImYfqyvr)cPh_s<84c-6E@!z3^ldtMi zG9gck2(wMIL}6yW=x4IPqUUkqeg1NkQ!sdCWvH2uEE1CzEWk{$xU{|*`*H>m8ADyp zOb&+QZX(Rzer8o%LthZ zZ5mEmfb8-Ctw2$CGJ@$8y}DGzTm1PzafLDdzuX*EUVwvA`@P90GxoJQa7`7g2#(1u z^oNDlL$RPn1QjG%dCk-nDTUC0p;;jJ`KxcnYUqfbM{If|4?fyqo*i|r1++*SK{3EC ztMH+R>mz4wCoI%&$OBSX&noi5yIE+_O1z!w$yK5+O#U;Zs!UMy)vlAjTt{c7rVwzc zR9L&M8B6Cj6t?_4efAkTvz?XN*IE97 at YA_Ae>ilx!=2<;hk+V0B3m+DpPJ~fJTsw9 z_k37bUTaEaZuMnhBh1zvVd5FcU+mWRykG0hCQ|<22HAl{1pb;pZzra+|33- zYs(qE-f32L(e;mr-<4({^O|**M1$Lcf=x{C`yQJj&MZ~ie&E1aN}hJGwE$9)v-mTG z4RP^gT$B*OvO4-oq=`=HS3HWcd8groUAts9newz4$Bj?QDwNLZX z44Vs+?!=)-djy28lFxzQE~PJpxUbwWLUI<%hqN8#h~Yb*CD=R0(%lU{xBiLp%yI#j zqi)_sGwc at O$1|_aTaRMO7^BNh2p#`&%`li0jTcFTgc%N!9K} zX!dq0JxRM5G1+yBj?~6mbF-ZMy3T%HC at 0>Em19$&(vC~h)F|g!!Pmi{ty$c+Mcsb6 zLl&vF`B@=+c+u^0VC#ORYbcX0kjGmaEA2TS(~sU%Db#_WZ2(Y$TPC<9xSOG?A8|q zbD?+$@VW>?CpBXmed`-Vt^`K$!v=~azW340g*<3FzLF+DZ1oZg4NbipeqkZJ001BW zNklhsHVuI3wQ^Igob at u4 z*%c|k_WM6lY}irPkvzDf3`#mh;|fSK(LP%ncfnwDiiT8F at g5}{m)@X3m at LY6FUtWalq0v^!30O8Eh392#un?f$K|^>J97XKL$!}xn;=cCG=AxqRqt z`KMV=-=}R#&98EDVAc}_X>7f>`%exbT;(jDzKmq(Jc-8Tz zHsxk4In9Ft-+SW+O_yp{JKB18D-BWJv)K|cK?35_=XS}ZJC-Ppd)zKj2HI3Z+?s^V zHVAotQ{I6{^Izx!mvf7euHOY|s at Gy`Onu5#L<( zy-U>aykHnO8A&_;gT${{k)I^tXVy&kw at 8;v5xC2x)EWEfGcF?L=`?&6kYLL0P^Ra1 z(KAvZ^I7tte#NG?hSsWXq~{N+k1L4^e{PDY(fJ>|2=tExdYZ+){vBWY1^7^f`1a34hF;jB1&N{O4TU<)@R2uJZCdsChu*MW~ks z>>l44Z_RZJ=Pga6f{ZE?r(Y6;2uf`N!GM7RO?(H2UTo%pYd8X)E at KZ_f4F)h7Jo%U zEmMd;6jqN!80~)-b}SgL|8pCKS?3;EQI2zT6r at An^X5Li)L--h>)!)-4I*cmt5{f| zud)iohyk)M1x+YS|6T57h`%F3RMsNTVh;Ic=4g6Q+)Gp`7LO6y^;;96^F2xx&-aK< zYS-Lw3WVN+(cM{_jUXi7i{lm>7;<+V{iuf)L2rPGBm(Av$Ii$?Co-7EW;H46%4nH^ zbgEz5QS$7{+|#^5(23Gz#S$RA7m3MPyi zvz(aMR3e9l3l at qYA}4QH&CWy*p-u0UZ6NQPx*S=`yzosdYf& zB at DC-^2g%ArfL)kt%*ZJPZ at o#8qA7#_F-ldu6(5tgtpea>2npq!VqMWO;wc{YE`K& z2cYQw at LNNrIbxYe1EvcOh0Dc7g7#Xvm|Pzy=z+fzI at PEFvMjpLK``QJNJgv#)`hXM zvXH+5{EGO8ldINfu*aUWvM{l9RLZ2Snw1vj z2|PktJy>o;^72f9w{*jH~ZnF<jM(L`YMD5 zE`qJO7h|;dnX{UqqU_zAqe<^$3hF}^RsyB1%KsTuxkBc5N<@gDTYPB8?E6n-bgpp` zD_~~+1R-+qqeK%;sbOpK1nNQ_-~w~|W0%tS<#9J!H3izg1Nfk~Ld;_r<4p+ErY7?t zP``J*<7ic!tnx2s!xm4w(0SY+9<%?9I5mhrvVax6*34Hkn!<>#pM4jhJ~-5PTs&U7 zMYjpBujn6mn;7C$qzqLk>+5+i(GIcMZ5^r^p at bu+izan~JEvD(02DDSTNg*>sjdxy zLV-ZsiI!%wg%*oi7}d-DJ}6|@kz~HwG$cj?dr6V9^JZpkm`D&4mP)H~i+=eR zJr&ggpdD(HTv}ePX7>&IYhuNKlK+SYbHay)_&R~_JD%uu`Fz9_g*AwUL8#CntNN=V z-5Uv*7R7N~?w at F$E>j`;a1;`^1hirKmRXfWM}HrK{LZq&4)lw|3JgS|Y%IFqSvr6& zp%EmFDWwh;>;7NZvAsu46PfRT8U>+_mtW%*H&wm}??MMU;80NeaVZSjo)>8AIr~0+ zJluK8#}%i;$r-#^ME)(lN8VdoqJE!E>g9 at LFLuEAMg}EKgEVdU(xV0sn&hP#J_&Z6 zA$$B5>_&#s0T|C!MA21dn6d&=78#ACS*xbU=aKryLe8s}azZiSwj;ge5!2+oh at kWT z5Wu;D)MZtMyJjf-S4MLXg2y81W9+1OCY=?VdFl!TwFB;;(|hH)#84Z at g0IFMEU*_5 z6TOrsNZxr8OFFlvB&S?!-c?_~N`K-f&B}oa|7Dv}spHt5Ve!CM&lc3w%aN5~!D9oP z_dVAnO~i}MNBo%7Kvfivu{)!SLBJFVk=-B6uQU`K}bR!$|-HT_1%xt)q+Rr~t)tx`V?L*KA`fW3yxqhk~@3X at 59jVH!LG4VRENSw9sbm$9F{n8*(MjJ*i98&iMQx zQsg<&ojJRjAkdK1Bh5&)(5T~&k?fDiolAMi&M{Co=|?Bx1+Yd&$N4?AszjZ at Wm__L z>7fZF8<4tz at sGF*$9MK{>t8Yq%Z+Vb4SJCsHPf_kPFkrpiUAGyeE`QmkeKIn_U%oT zu5C$p${e3-o$NVC at M3MdV%RjIjeGpx?r1ccDm01q>|i~i@|JpZ3yO9&V+*ueFI7uA z!RN4iB~*;q6KtIw6=8W$M08D~Wx`l?;2u&lq6Ku?%qeXNRz{}x#@C$a7F++TIQl89 zMfu#BpYL}*T!GYz$A~_Hi+Yah(^4SH2ff1=y0%6qY(|M#XEYw#E6c0Qg)J}dd>^R; zn&_y>{#`H^ZyiD*{pg#DX45^L|L=GB#&Y4}Yi|lZntXhx;bDT% z2L9+WqGUoFS9<6DDD=9AUB$+#`Haw-aGA!!9t+J&O0(oIY$4zLd-(s at l8+(aHA=B% z6S7n;#$f88#EmdBw7Rrwt$3*#Ij|SmjET}Z_=PHpj^V6v#!Q8-J7-X~RTv8tKmZ2H zK>a9s!oap6R8ek4OP=)-8KgZSJAfY>K8%Bk14K6Kdx^pROfJQr54Q9c+IbWWUz#uY zU{DMm-0R3eE4M05io at G>oLdq1+=7CT1*$qheWAVFY!0C at lozY3*HsE6R{_KtTflwT zn{;Wv+-xr*UxMiJIj*@7t6O&#z3%x>8ar^Sw*1dLou{O0E5pXW^k>v)qpO$I-wB77 zK~TzwUT>!zPIXst$=*LED)RI{kNM(KyV*_cLs=%$FWgHq9}lGsY$xVC&^k0E97|PW zK5Mcf84D2`Y?y3-yWiW`u&zf$KddW|>jA?0?*MBn$;!+G^zY5^<1%>a?tkZiCW92HxN=uR53MXhFCqG{Q&gN&kvb~(HL|sWZN1A^6f5q+ zkM=^3SD7u8F3eUvoPKt(y-{PDpa9bgZZ!m>+Z9toz-MZ*1tlwQWPsK?Wlz97LBvGq z6p%a7Lhz}}IE=Ej&e?&}RTcnU5*j?ObA+uRORS?6BrTI{YewzsD4L zMA*v>`62J_u$9^5yz{J!BG5pAR2TB)%cz1&@UcKpa|?r4m2Pz|CQ`MMvvaBtx9LMC zZoTA at I-;6Qgk~xS at 1GRR&!_>Tymc9Vh~V#sC7aLJz%Ji{P$w?Kp2_S!WGV+qwdG!T-*)I#o2SoAayKe2#{$1<5{yq;PbicVp1+`Ee+n)KQ zkpHtSjouJ(e(ZmW=*48%(DOF9C`zlSKbm;GFA_V>23zhOXDDnc4arfV^N|Q2UTs(V zJ)^deQX{9^Yga_VxmncB7nZd zV|6PV%nYIIIa_d4f{ttB2n^*zUp=Y}r;x{?a7TPs(W>$SA6ib`uy{KeXY6M4Pv$TK z%rM=b0wSe31RnypE;Idb8E|Z5CRv^njPLFTBpwG(v=1XSYw#+%*%fG5$Y0hfX{LkQ z(U3?RbZE)mKo!#a+s3l_+Q1@@zdKBQGu);RO72=~Vxhl~4@$cseF!wqOgq$J5LHvM z>XNJzlPfn%^@7bfwW%71=RGu7B5g`_mTlQ^r}ou>%>Nz|E2zUN{v}=Ay2>%Ay^(rB zWc483k!Ld*9#Ho$T at 3DwjKu~=D6eV;4gSBHQEbbbErm;}F>b`zS5{sy*k=O0#GTP1 zV68NfH`_GBz?cqWfk013Q6l{eUi>od`#?8HW$^uS zQ3|Smb3tLvE2W|Fzi01A8=U_pihjWm_iTQ;hYskn24g&enc^SIl4=O9DZmjneKXh= zF4v>$b~|AnsDmku=ssGDP-8GLEes9K5YAl3qr|P9K<$^ z7TG`g7Y&IZmJuMAB0%VJsC;sK`(+Hd+%*#uy$}@C0}+`_kIf+C(lv@!breo{orabF zW9({|E7^@(L+}60i~P765Qf76x4ms36{BvZk)>D0GTa$2MCCPqJ==W zz~_uUp~wjs2(bQ0AwN3L#6&R)J;`2p~SYq9+?XwPnb8E#F!`Sh4X(@_Dw99`c8g2YT{8nn!LHp z5XMZxB~HatS4cLxDKz5BQptmb{_$!6nao~1Oi&4l(6p=TwX{{QzR%rQ6ArZdqF4ZO ztRM at pNkavx%gKqk;Z`t=rR^uRS%QLgB0P7hLeutOPrryEF`b=P7R9qs+#x~_2d|nU zT_2P4r#rqiLIBp;$bdkws+Puz?^k93cZVKR1!?Yl2yL9=*yh{B*+voJyJLkqdzfKR zt1D!-L}2Kang}pT6Z7V?DIb?RLcC5d%G;t9<$uLunBL@%K1wWG8fPW<&u4N$rDa}G zOlTK8R5-u&mG|uDdhNl#wP|<+Py2!%d34AOHN>*ZO$E2yGW#wm?-4Cq)BmUl-S6R} zl_F{xruR~D(}sm$QKsI9K`2=qFoy=%$h9(1GwFj5T>#yjHc4fI3!%|>kFhk)T2S0| z?B<{Qz^quE&%sQW4UuppD{`}UcJ0{miHJAgZu?%7h?%aad8gwQYJtpP=^U_;lB9j3 zzrNKdBH5x4;c+>?Q`?!(7>hnoo-a-{t3}-Fy at h4t0HbqB4|4?-{(RPFMK at V{i^kuz ztIsMRuNHV`9>#p)$H^VAkQgx zzeXEuMZXMfyHjq^VIrJ*p;?9k;OcRV(rjtfOI@|8kJOhj;j?AwMhQ+Xb|mA%x9pO z-`~EQUoBNHj%PWW;8GM!Xp0 at 8^Qw!2La9tqwaS4`sMfW&ca>lG7+p$M!zz^0k3Sk> z_;Q27HOY7c>t?QFP*Gptuov7v%z4$Q17j($YPI4s`6FZKG=QW`~P`}=!Vln at 9WlyXxGq=z{a)XvqP6C2y&^vQO3`uSD=0Vxghpm_Q9d>>*0CMK{Ns`xkKh5)-pe&`xPA${r9?2lBin at lAEr6 z;Z8`Xj at Zz$t1*a=&mQu#>L7}ug!yeT$*mjUGIw%O_Sd<22wFxASZd3Aa{>yEy-?VT3w*LvnFv!LY~umY5ZOI>C}-UdIouF0ZkW!J at UF7T^b7ubxIG^ zL1h2&%x>4Uc%$4bDvmFRSZqt*L30bdP(@-ll-cv5sC7FtRuX<+RLnD6f~|&YW`(Oh z{=4UpAuBSo{t)&*kKDSd{*O|AAAb$;y3oL_FF^*L$}jFB^pKOI%mG*E7KA zM{wn>4x`Y~+}m?GJe|GH7aCH6)+X9z3ZG at C6$6SLI(*cz{h~oklms5M3uZz)N`uVI z153I;lZJP*sPvF>QJ%A)hF*%k^A60iC7ap;<$Q~_RED07jvThGWgsaujqBOJ-~Kx8 zWy+`#%ypKExEHwz9-+2s-~n0#4W8g1z}b#W+~*=QFR^q%72$_9S-3obZ2U@**c}uM zc4=ZltD4#Kv%+KUSrzpUZf4nk?naRqJ@&hU+8RjO0-VA6pJtYErDw?WX4gF$MAkkk z1qoVg+e=$)&sID{AY-9oAkQ09Pvzrk?9eIpu_U!@*=+>rrbx80N8aZzK8kCkfi1L| z6M3Sk65K+ff79vT+!eLe#&`c zMI2zY4oO7R&!&0ib}wHD9|BiKSTV&R%ycm_v}&2Rq=QJlR9IQFXu|%w-t%P5Wt4zY zbh;ri99d}b5R5+8Jakcze$WQlnM|jV%rT_H(`oPBXDFIDd_#bzU!!qd-wTNpDeLaG zku<`G$x9WwlNWLbN0)rj)fK&#!)lh<*t&nG{H#j=23$mC+*r(q9clg-+Hs^t at YarK z4neQ8tvASuJ;K&NdEhD5P<}>^ht-hUlvR9X0cKt3%Akla;@MZS9!QN&0)h0L!)Xw z`x-3mKZlNDC?8_f1r(|?{=cOMK3h2!;)Ol5U`l(3=v0nw at HD(o0^G5q!<1Kwcn1o! zjns>0|9jN|P$ZN^`Q_8 zVPi-hGM(n|pDai-u<`4wi@(7E8y4%=aS>+5IZ${tu-Z3?(y$iN&hJkMuxE zgy2)753tQKx%FnTGn?Lt at n+{my)-E>)M({E at md8eFK}H%IO7 at q zCNvUczpXH|#)Xd3`pOK!=I;FjA7)x`6yFKyTJx#Z2_kmcH0>4UHn8n%?+9N&a^@5%%m-knVBA(}O}m+#ZqExXdDdh+(!W zMTFKc8sFh)6m!#Zwkqfdi^M#0IOzsE z?OC;4yV-J#XF8 at 1KF1A!^t!-Kv~TJu;|%e$7{`%Rmj;&ix#e_bWQJ)lvV2RU^b<>bY2GCH=iT zgPkX0l-ShMxa0&4^38fKwxz{XBnmk{;C?SqM7CV8fN6#IijpZ5=q; z5g2G)sHht!;xbghHe26narLPi29inVxn5;kV++vbN_Ds3hPFO`e+`w^n03LceV?ga zVAmWu$1mO?ia)h+W_aW91Wco;2Ljm#f|>o2QbMZ_-G$yiTyp{^j54GAU!JyXbfX$C_fvO(8HR-E;LBnJm{G<*NDWFLtqC<>nZ+y2f1tnD>Eh+ at ymWa?->zg00l|}QF+Hh zAMK0n*68tpmRs83%6HZ4g^Qgyny`Skh)5ZD$hMf3eIFG~Tqd9_j7IK0GSo-FAX7r}CH-=VwP5JSdWrlU3EBB{pPg3jB58(kTvJ7+7uX zIh1n!ABtu}I#oNH`j<3-76UMs`V}62_m=Ke&f8dWxbbadp_|;P<(#G$p&%oCK?7 at p zusk+#UEdV;mjWkI&g&{`nimXPYUP~;+0iLcVceY>vDp?3ppN$hho12^r9+be(vml5*h_f7`n)=UhFMm#H#36ue?~zlKEb#uLQw6oB zl;f?iu+$BhDhsQXW at +ieoqnQJWVKb?4gm(L$tLR|IqrgXI)=N}F!Tag?%&_v5HyLv zaz`Q-Sq-_C#rM)Mo^et08;MfKCebIPH}L$=)B>0Yp3 at H8_#FQ_W~6ucqwN`0hvxsF z#|rIb{&HC)uj6?c7!ZaEmIF*_MpTWN?=xIy*!oy;a}dv|8Yu~U#3dd25*h*>AI|ht z7dzRPi~JkFixxFeVSAzS*{cn}X6noLWre20*%B=^u+Jcsbs7K19VWieKt-fU(}8|J z(?5CNdQR_t4yMSXY)mY!eE(h?Xd~ZS)ivh1ya19Ft9LG%lbA~YCwYPYeHuT{czQ>WJX{G+Jbw!i-q=3tpz%B at k)n0wX`u z6XIvEmWSqw!Ojs488~b`@84cY0z at Y z1y?o=BtVa*o^N`|#d^~x}?ddA!ROT?f`6Jp%qvV}sg#h4LSgryg9)b(l>)AQuZ6+-jK ztq}{)g#FzT+Kk2)e9=zyp6fqp$a&gprr;oClz=!Mp4 at 1p_;?pXYbA?SZ%UtD0%M&uxuc|?M2kmu6RbOOIcO` zGZaPssY)mmOu5T4cCCwcGNkVz+Xnh&T=`^Z+$d5G?3B2ud+9-L=S58Ka1$qW?_SyT%Uo}2Nv zw1#0=LDedBm6dUox*+JKp{6MM;F3`clLN#bJcXCY!`@8 at jpkICUb62-b{mBOLj$lV zq==BvPb=i8QxqGDEE8SdbYn_s!L)QWa05y1#cNK`3sx7W34ZJ+fYHx{!EQ5Hl=acnjpm-+|1#YbM`JDVtTNGgEkCVJ{ z!{(K>Ax8 at Ni+|QJf}{mJ^jY0&j16_`1ah!(R((UcJeQ>XQWHN9)9?@`3AH>Icbl71 zFnhj)qYc!e_P?ND7FZjVTB{YbEpYRognCg^zDPcla5;QP1_Zc93*Ua?1rkx~!2u}S z(>V2j@~1Pk5+x}2{4=R>(SIUS+pRAX`K~xF9h5Z2ics!As>m~)qT~GOvXB`Xa>)In z6u81asN7D+K8csJ56%%f zdQpvwierDp;9m^smJ at p&p6QSq0iJ-^Deh$5{&GV{47NN)@2<(D3_!?(90ir|{Df!^ z$YBU2)|whXxdmo77=SX>J%x2st#@1I~ulKq$T(#>2n1HW{T&8G4x; z;WJXHNH#1u4}wr!F;mqj1_nM60ylfh;;=d-*<&?ih&C^@3H|;5?-%sFyfSi#!#-qj ztk`{Da3Wy0fOMg-L`IS&h-O2(UXz;Gv&_%LPj-41&q> z5MFN1F?4O4g1CBCI87YMK=@m{91Sm_6Q{q|fVx_aAp-FEyH2vT9dV^7vzQf9O~JIx+Hen}V99FZ{(O^dQY zfR9CpD7pu)g$GN0dxWv#(}N(Lf0-Kl1#*_!t0M!VzZATdTkv{n%@@RI zF|etjR$L2g!@XxaF7m3)HQ=AS4HPjdRg4EQ&*8XGb+?O`&!wmKZklY$-LkaIw($eL z72B+L8}hlq-xXrgK&4R^i9%GgfP1KU0=Ouca|s+htv{xvLP at 7$5**gr(hPN+)@G7A z3dX?7eN}3sPV3zkV at 0Nn9i(TxB|}X(jOCl-I;V*)a#(otbR=+9UFHV?%MyIvS!IgM zG6IH}uHNT at g6enbBMCx-E2Czs;hjQ(nx>UUYO*rsDv9s)bDS(6ge?ZkIH?F at h83y= zNk9)b)+0Kd+aWu_hDj2^Lr-r$DsIlyvpQo+Qz zN(BH?`Njs{V46Wbn5_I6v2f4;gnz%&pEbdQhhoIr1JeoF21DLmagyFr7d6ZGQm(W;^bXfE6Q-thJJV>~(8P|<7(cKQ4cH7*v%?KFi0 zbXGwB5FRLPBW(8|!kKkb42?i!3&p`qrEuufbs#PLgKAkJCBM!sqG*of1++^Fv-_h% zunznC=(s%MWum7;9F2%Z3e4_rUDFU-t)Zg<{4UPOS_lPZVmfuRS`8JJd_A=wJ*lLO z(D)`Vij<~pyTu4=5Z(%;|K3k?M@~~-7Zo0>^x(!h!BYj#!H8)Q+G>Ea%OY#7?CZ^H zMn;e;1IgE=Ifs#v_6)3MCMb=V6OcL}#jG%qsYZGm(y2Zi?1r9oCc+}12#>=#MuKOI zkZl=Jb;TY1sI;yND);uC*H3Xt<)T))OCbO*#}k2z3BxY6-W5=RB&&u>A at NGAkpNrmI12_e=6;>7)c9E zjo=b+LAhYj5Twi3s1&DPp|#AD#pYNlNVKR4mH#dGt{;qGP&{PlazgYx6SOI2Py!SS zg at i{8!AG^MgEBXzK&LfJtn1O~Id at D4Xf%5i?E=auhS}9%l-tM!=NF;9KM!P3ma7Al zx+TuPN8F`Y$&G$KV&xj}y6c2K5x18&V!78aWq?`lr7sbtPdW%T<=N(w8Zz`DP%J=P zje*3i&&Vi5eSn3Ae<g-Wp9*}nn4Y>5)&XAH_Rb$#l@@??coKBNJP1VtX z4kk@`o|;U+d<=H<-JIT-$Di!qgopqw1aJqG&OZf6!Ckkdj7R2h%CK2j-8JAR`k#8p zAAjlKjzmfA)(Wl*G2*RjXlf6Y`n-!6|ijk_bLFmCUl4Q1vHlK|~#V#>>+);6&Gl(HOyh1CM(hG|^ zSz$`vx13bVk^sn`!7n?_`i8$B4K>bYu}~4tY at vq_O>m1Qn%0dQXY0-L)VjKBOhH_} zj*^B(vl+M$Xm)6-9W(ScnfnUVuA(|4LRu8S$m7J;Jg>^PXG~T&YdNI>WTqCt7+(Ak z{wSlUQY1ZdaX&nidw{{Qa%IRRT`o5vBNi&S6QD at bMvRkFnoHmv==L6FJITa$ccepv+i0Hl?GgUatAgU7>s~ZT{vdFKm}vq_I}@4u|HabF)Os5_N--l)hpQ6 zL&33znFP7c?TpJrIZT)D;Bf)FwnVM>W@{IhEaOQcwgQg1F{7<~w+e+)$%S7n1Z5j= z2jG1n0oHC)F7^QLtXsCN^}*b=!SFLANKA;epkdFRskwqoU`~kfrqZv0jRn5X8JCi$ zsNsrLQa(vM)BSB>tB(3VJGG~IxLn`LW&8gzI2;7R{WeL)1Fl%aICb|_=El?Jw at mPB( zSzOCeSC`n_iyA(tH$2=t+VlDz*Lj|SD{ofi;srafCueSK5p>k{sdJ2}0K86XBASzU zwZ34R-rF!j6V_k0hE7S2BIqaxD5fX8{a(MoTEZ=#QUiRM1Hk=E&sfyMUY4LBcdhDbxyYlL1ulrv(FyL>lEQ6*gar&~qK_CMXH>9Ia(H)aGA23vP5WXP>pJtkG%QG!Ts} zOV at y{eJj7pF{UQjC*n7IxW6smWMDB{AE!NrB{jD(r*h6OC5^A?NmUQebL z4Un{Z9gx!dSX|{&UFgDaO#--DF at Q^Nd3&#?o58xcX*oevE2I^Mj+lr$ceW0$BO7Jz zFBIFo=ds8G29V=eJ at Qvue{MyS+d at W1^4Itl1`9^O`bVQe`$xrfM;k7;lah at _ix9H) zyE{?Z_BZ?P@{54UKCvRpR-Y`H-`dh^Bjqu4wUWy%7#WU&POgDGB@`_Js2t*qplx6| z;-AK~U_To7xw7 at -uC_vj?|y}@u(Hac=DMx-$s{nAFaZ1e3zsSeHn{BTEE1mU2)S{m zykAY5yAfWP>}V~gw)A)-k=+$=9VUWN_qaPn^&&+>(O}+=tZ3~^+ at nBZ>F;Dtb80ioCfNKh!AV7Kd{3_0Mo zuak&<0=4ym2?rjXb>TF~LX|xRbnaLiJ{mwgYl((FFiXno}@%+o}cmt43i=gOV9wOh1W*fqXfePLs z_xzaI at tou{xQ%EJp&cIF!uuUBcKCV at Om!-buXRVVuqtk}*0WTg at z3FnA?dgV3_E-D zxdlyIT#<)#y>c&~RlLKuFYHseiI zYXG}1)>!u{%Rp&$bte1z>%dw!!tA^v5t)$AL`{EQtKdp>xzISKhCn>fs at 2@YY`1|( zj((Z8SW=Kf{qN=hYH2B!G-L7#pbutVFA)RGLU>(X$lVwzbA?jR+6J;e;-7YbFNdBL zYoiKYp~C&ZFF=;Kf{m_QPML(|-t>R9kW)cxqlGN!GkwD&w(Y(19paBx#LLg zxiu9ve6;L-6wyH!cdihI^Geu2>CU8z;b)g?Clbc-i;K!wMQL(edH{#U9jlOoqaxdWeDmOp!yl7JPnAz=KRSP1~$=3h4{`cZHHK%-l5c3 zdOxEnF?Bgi_66(%w_=jkExi6wtpA%Q2}EnlyhwpDRAIVt&n=d5#sE_+-+`1N&P(W5 z8|V4Nz&dHLw$IMQ9EYB!SJ|bUfp9J2N2~KcDVz6tA!5!Fp;54Bx2s*x#s18{|NUo? zUf3w#BM)KI6WL)$`Ox7!V^%nAtS5jZ*qnRC*xb~_CnZ9*unW>kNf$A81EFH-!q!#;2lyKNOuV`i%=-QbH?N!3COtF>dT+&4Q06TBiofr48 zP$M8(oO}GfKG+(*gPyTOmhptQ&4i%~`6{cJ$Q+$2#W)>wz8}z9L^g8T_i8v^ohPI@ ztP>zj8AGVl?zxA|`}+=_cJU*IQmjaxdmeGQdK*RW>;TGSKu3BpZ;?NIa|ZU}q=)@v z97PSkXPi^cVsTgYbhQ)YGXZzI()TPg&M+p$I^#}9MBU)SO}q5i_;vDzbJ%LaD0D5? z0OK+`uInkah5Fgd{847ewY|u%$!?UYB~Y}Ga-$HL-*c%(gM$VXjv1DDnK_($wo2 at T zpkzKGk}&)}YM3yBeN(4AVu)9?hj|ZI;lM*PJ)tqi4WCBmqy=N4w}{YLnbmlj)pcAJ z)1%*~b;Or62ef!PI?%!wxCu|x;OZpsvm~Tyjp|+tMjLKWx zrJ^VM+o0yl`3jm1m$`i)C&YOPQn#mWU+c4jf`bZngUF6?fKK4CG2ZQgHL+YN#Nj>z zNw0$fV}Fy|>$G(=zF2C48b!pvs=?$tad{B}e8+=QV6RVGgN;N)s2+#uLTp3F?B{`- zR-RcwC$0yH!=9lNVqA1--pM-Xblv$q5~8-uMN8ey=?fj{Y at U_eY~$;0vNFw*_IBz6 z%|POIS1adER&Si&BXSoJ0+IhJFxmau%Yq2btOI at N-Tsp%x9aNb5 zu9S#nF?k at S6RjL*@mpgE?M40Sv at 4PbtPIw@M99FHnTD%(96Q=0>mT(@jBZ(QmB+d4 zutXgt&JPa&FawQXIf=hV!D$Op{VO)To+IBqP1^ zPGA26+TC%Ne;8=O=>wHhzv}wUCmSwa9_@^5B&If3zWG!Gx<0JAyA7}zGwox{%|#`ECich90k^GAV^G5xa5N4TP8UxPc0jDXx*E;HtFi?Lf*iwhw^MXdb~9@{a8S<>l{D2nRF>) z4JRE5DRD@;8D};a9ldLTscdDYQ;G~4`;tMeluW~73Q%1bU%QU}x4GfG?|Mx)C?8<} z=kvst6{N0hZ5MQzyFqZ^HUn~8FFI~oU~Dayg2W!?bP#Ec8kkm>6k0c!T;QT1y&(G{ zp_)qYG<;=t!5>y2E~$1S&G$i zMJBCD<1|2LNogOq5CQ1&nLb!$`1qT!6+aUNXgB_BgMqg2 at PZYS(OYi9G97zTB3 zkzVKD)y#$s?7Dyc&#NizY!G#YWW65jp! z4dSHhLpe{X06B!3qYEC^igNxim40*tlPCzV*32dF1(Pv+ at i8>Y12VI*<{RCwoMRbe z=-7V&h#%EXkiDISN}njNVlnWtVBlI0x9sP$BCzOGVcoz_$UQwgnO*9z&o!Q(zbdBK zevd>ja|n_15gL1fWSzQ%Vy<9)4}YkpkqND?KA-0|0HV=Iq&KtaRpc*y7kgNQe at a4_W zWo`}^2tw_FhFhZaxP&R})TepNruEe4z`qwdUw`g;WN$Tkbk_=R#*!GQ?wC=O at Rx7T zhdy`Lm{Yp31+%kJu?TsovNcaPV+cj~A@=(Qk^Q_hvfoervtB|xM5jpIQSkP&DG at J& z_xIBue%g>kMqeXoEex&u^d52n2ilg8-Q!z_Jd8beRMPA^1D7Z|j&^^rXnz?#bA~<~ zL^pawt}yDM@%84uzl*IGQcfYN*SK#M=A~f_a#VjzUfx_t#?GTUI)v2&ZDFb5jDAw9 zlgXCxbDW_M at 7QlB(i+spie5+s6`l)J(torTlHh={-2rQUze5MKER5Y!%2^syJ;2Wb z2FjLtBL*O`MLC$aRho+eYgiL~}_!U`6UJRcy;0o4%Q)vN^1v z>RrXK^s#8veEIKSBhwUQdX_pT+|Z`qV&oi7{XWqKsz|g&L%ZbzQq(u4+!1 zX5dJnw>J6nep)J~Ip?+U_GZGK&r?vX7LQZXel9|akXUh})j-dvOJkTj|5C1iN2cf2 zzYcFj?nV#c>`+p|80&R5#>nOZnE_Zs3PK`r|1w5B3^NHEjs5uV9RKl-TFjD#1sZ7n z6lymn-`{c!A3Jgc+uocG%0vVf&dD{!QZvPv+bZgim9?Q&(`F7cyn_9&_|*iOutIkF z>U-#5K86q=#iFt~5Zm$fFdtG&TjlR${fBq7ZzEmS)X?;R;qt#F&C2%d>Y?T=!phdF6;b9L_1f zaBb+-ju$tW+$^?4Wo+pUvirdYX1^`z6s0NHk(XP^V$&K>W`h8t&4Byv)OxmM(8M3w zCdb;EBqm*O&Jj_VhCkA at OCrG5IpV~EfZWZT%ur at 5f#Q{CNI5{>l==B%N1|Z7SAGrD zd}RJC3BzV^kYAi2bE!m2f2Su=i0&K^2})An^SUfodWN@#g$gMCcS4^7c=9rH4ci}* z(GIQ2541{2X*TibFGVD(l>;gP9-qDS at 2uaiAU@!mrSrtlM9&sjS2$v1) zgQL-wUF_LlE)RL#e`?X5;-M2uXDoJv{F2zP#kI_2!Q&MuC(1H?i!GGvERCJ(ton<_ za0Wr5Y#LnH;q2{(e#Z>Vc|pgN0TaUXC;$K;07*naREs+-8cY+XLDwst)%K() z`qtoAE}x#vSQ56K9mrUXfc~j3U6PEE5)G8J87C>A=#4%ApX7pV1^7;IeHfVxB_^!$ zuCj7=>0wYv<$n;?0FCB2sp{0bau? z?#pK3%msZT`{WM`WQ>csQCd+`G(O7;T9NH~-%yA^9(&jCK_jCvByVA=zV4;NX%xeA zN37xh3+=fClSeIp?+urW;^qT|9Z%gC{mFI%>y|8zFQe;GrfAylVXjF8x}XE*%AVsr zd`eYcGa($r8?%z*^FmlrpXnT4`Xa2xmV-}xf^OBtvSh$8g#@9`rT_jEbZrkTJ2t1+ z_D#gd1d1qh6Zt>Pcsdpw&JZ@{$0+9aSo=KecZO|2(4cK{yRw%F4EMY$s9 at H5VoUNW z)n`(QNABfwP3rCq29^q`fUh(X1K zSJ_E)v-KX`xj>{8d~6src8(k6F+dN-P$i>b$h9_sfj!tnK`})#nK4P at Y!9YxQf`mM z+8_ at CN|d`b5<+B&|1s>1>0b4N8|v^3$X*DL4n5^U9R`#8gQKpEXo6t4u40Owj75#j z*8rkh+}SE&aToV|=5l&zJAxra(%naJ^VfX4t#^J_3EoWXMJp8BmSe5uLKlf%2;>v7 zK;(1TpfxQJ+x1mo4}V6Zfb+ZOA{Mq{fSSvP?XstSYIi3^L<=3kKJL&5xr8pL!^#dc z>Y(OAsw0DX)cwsT_b4d(4bLPj|ek$MzBrWn-Ko*pZzB;Tp5xOlpeV|eaTH> zY6hEq!`jM$$)ff9xN#kkWZRr)BZoz=wK?du zgl_+1gxzOvI6c2l*Sdq2N$gVV!BbEPMJKEodY3AMYc5qDv06rxa!1)cLdQ88bf3Cf zcC?H9WnkVlG)yx~DFPt3ZW;KCkMgi&&FY2qI^)R<*c=O8`coG5xP^;O^*+-%%&TNX zW-Id)u*U3|bC at G@hRy;siI&C)Is5V7AO54&W~S?Cy}1?^mm_Kp4Cr#eD9EEA2!=+n z=u+AyH at mhdR2ZFcZu%x8ZsBO1#8nub!_-q?i+fQri-=8w%x2?l^DY at e0IimdmL(T) ziA*P(xUdjLocZg!P^T--zq4I-na4$zIM}N>LZQ918#pW5v=ClhbDslUZS^aJIJQ;V zb{D;`Ie4AO3)kh~k8CRqtuf7^AiscS0`96eDsL_C>W!eI#0=e71eKWl3lO+bl6+CM z<0AMBLM2rn{74V|Oi=BB1N{FeHMn1(utBqo9I%wC56Tu0}ts*{ZHUJBP7C)5R@|G{Ge$jHg`4 z)H2*smMX~SBi;)orD3#DihFzB*IAfPcw${l_G4kdG##*;MY!Gc#_VC;PpvDR%TmnQ z(ZW7m!v-b~FGdwy(Z|O$t)c12i`Ea6j$1+h=mx{2QkP`#Gdj6GD`u6;h(IPiEdblb zz{kUf5V{bh*=gTnlnlyUVVHsgiRs~nVk`3eK(yeni`CeE at 8i!!{!sf)UEf7RZ?e&n zY2T~RsMMy|V1oj0J|aRetFuv?IqRtI%wt|7TF9yFp4zAeiETH_+a zrEKvH;UD9nc3|oJnrJb(U8ChzCB+aFN+9-7{l=oWyv1a!XBp2euHBF~IM`Zz=Cw~K zBK#kXPk$ZZRJ#F+Hr(<-H#0&;TUc|P!|=hCq7O_2_-L5EO%5&zU`32E{1OV&mD4nI>hqG!aE&fREJ8%L@@}m`T;WNRf7Rh860hYE;hdkeRVc#cp zAe>JF2>$_=iR!zE0e4-I9ZL&{9C^RUmk($Gvm7RvM-b{`T4L*7W4O^@z)D{}m z0P_YfSDcGk?tyG%;T?t{D(NX}95d^0H=Sv&Y&=6YT3S>@k$T%QN{OMK&_eg>vl!fi zHXG2~Zx-TXANiMHq|g^qQCY*LHE!o0{bFjMQr_&A?0 z>u at DUmgRuH@c21#ej%g!4vBivH3 at XPF;OZS^(A3k66A)yQs*H$x|u>R zNk)@$;tDTiPDx9_1B+MoWy&QHfOT84x7!#C=Ys at nGsQGUKC_0owG2eOU#!gDW=2C%uMGGx>Q<}l9RmBjE(9*vuZBR7EWx3*Pe zs3>N2XySGdI%;+|X&hRx9G{FR3#3+UyJTa5DS3dD|A?YLX+n_MP${OyLGVLN7gFV` zbLLtdx{NeoD(O)RmZA_8FLm&ohp2 at c0m1|6QGxS95t2S at 4KkcnH?Nv0L at 12n*VfJ6 zwnT1$faXdX0nPo at rPI)jEJ8(oS~%?yj`k2PPLWMcvqsftZ3SXs5xoGk at GUyx47KJq zhiJ&{L7#vQfrT6ah`!O&_enz?DAQ*xwO at Z7jMmU>L^j$AMMs#B-Bo zu6*`2Ld#-gqSGFsd0uz$Yz_X_ymD(@brHorFgaR1`jFxj3N}qTKdZl!j~Zk8A$7&Y z8*^EQN;Xo|KA%#O&3uUVWqgJ5 at LvuEM_mJhW>CSjS?-XkScyc>Bq2 z5rGuVbGfKF at ngoF_(e)All6Ll`(e)9t)T_#&9Oe`To7S at V91Vv#H1TE8p{r9G1S#I>6s;;Se z%l!#TeItXY1g&u0Ku7hlHc)AhHzc?Pbm2G_CGJTW&tFd(WD%E>J|3)`Oy_QGXdV)$8mibnUC`{(Sn at Gy_Wy=mSu) zO1i{NNmAc2VZAlMQJ&?_6nY5>3hezmmORz#?)Su7Xf`61G$wXgj~`I;KE at CxjzqDr z_z5oBo;wOSz8B3zYWa4kJ6G5BF$Bh at ei-Te9b0To0S8nE_|rC#CRDWR3_ at Y3 zI*A?3x>^b7)L{-t|GV+0x+pDG7kWn(SwskaK=}GVdEAQ~s{fBo;^YQW4G4Fm(@mJe zcS!R%y_(G+M9)yftI*&a!Xa*+=udvlNC+yM+H0u;3g^!V5qd>{(k|W?N(tMZ0y}t6 z?-|lDjvi;GVS=rB({SqFAskZ^R_231W+c*Js;p-+b&+)Aq6Q`R+9 zi%uK62#=sYO3zor9bS at -0xT45r};99W(?rp^tYf_FL(K_OQj(>46`I_k1?iwdb+Tb zeufg_E<@I0j@%58UnLs at lkxxxGxm6IxYZ;Zmqe)~%>xQ`$64AC1U$u; ze(t~rZo|sFVxqJVn%wT2c$`a0J)Fx`QGczF+uM&un)pChE{wT4jTZl~XoVG5!AftQ z;e%VNlrLnO9%jGy>sVQ~jaOxxp!^sP{sm92f9^+36r;|HbOMaxKu+l92>eCIM1$d8 z?Co6hx=Ywr#|?;n6p28Ni}DYx6A>Va9IDF}C0-%*ni(7q7LIR6p*&~Z z#n08v{G at 0fido8Y{MKd-(lc%DcoA9ywb7NksUDvL4Mx7pX?*Z{;6z6YFDzCl z(Z6y~@I_-{To^d2hV$3!j}FL*{zay|U4r46%q=}AHQ%jkT;a54F{0cHXhFsAy2YD+ z=ppLW0nUp)FtoZV&VCudmlJXg^2M4??2`2OF!q0>ODbxJYi*BBBU#jFIrEMJ2o`As zw?^5{o6rNHUWg1mDr0bRr}c_DTKw7_jE^KFdS~fh_&P`YJK-Kqg>kWG4>7#NnoN3Z z%oq7#RD6p3AI!%8qOC{sAXhIisy>vF1;_EYDMJ(+l||8Xt26^N4KvFb_8FXzG91XV zJ&Ay#>(gxbicWcyA at dK`BN>UTip3h0Skso%odFNzI+n9??z at J4VY6H`et>1%tis3#VmZK^^ z|8s#OwIuN;Yv-)OBy=zt)?*rjFq^35%RLKNccr4J`#1P3>p)~9Bu%5kLUH at H8ez2! z>r}CF>n4rrK6^nagDzQF?aFq0ZG^a_{pYm$>hh6qJs3{WH|c{N*k1<#1-ZSNI7}>H zj6RmWo%H{U9*D!|mQxT2%@s2&CmK#B$caSJH4R{d!XYfyq>%`;x>TiGzK=|n0I2q6 z6I$uW$D~FT&Lu{BPt!rU;;Z)`SsYA3dsf!!Z$~yX@=7nEii`%e%`!l6FT|LQD0`XN z#6QcW-??#tTOW5*GjN^(mD2TRF69eaDc0aKTn!-Ja64bi&XV(J at 32yc8u`JZgt_bl z8a|4thsuTO at 9citrQ~zJg+Mi1~^Qu2!&+xA+<4a7oG%OISWvh z*Rd{X`uDaizN=m3)cegIEbUX*tC&**Eg`#spz3Qa_Cx`x}CfOcQP zK$dBI!@t|&osPiYJh$vON)0sq0UnFR*u0Tz&fg&+s*h9+rxm-iY`VJ1f7+-iN%7QI zwse!}WuHHrIN)yW88%&-EPnKpGM!#0iM-6vc3w-GLmp1@;fHr!kK%2RESea$K&pqq2B zRAEcrCe$KswPCAxVA)nRbQ)7-MmpRSNUhV7lJU!#h3L0BIV&1~lCUU?MZxk^U?P9AiZc$2^&%vx)Tc~!D97hgJRy*{ zsZEk{G16+wMj9AyK)wQ&!RB!PjtBJw9;ah4Ehbp^dd87%Z_~`N^O=}%w<~?C<+9ki zUZ431;$;i$~|OZ at dL+rMW2wHHkjJinZ;4` zu31bEE at pjOAe5~hpzvo>^9Y5C!Bo%2EuAa#9~;fIl6B!zfCbQEJ3+ZAo=j(@NJgf( zb9eVGtf2<^E?|k at tnp`M(Q&B{cYyga**5hYM7B~)f at gW*Ba)~^Nx})LqBjIv;NS#1 zC1JfIUnCO{W!<`m*@YUzi$@^1R5-77D_>ueXk4}UNpI at +6wEBU%|oWO- at BRc54O2 zu%|6P)Oewkw8WIM0)eM(NRBEeK=Eu{D#nj{_G2xq9+72^!MLI0K7wB%-Z;Y|lbVQC z8EID$R2bM1L_04#hU++RxV3_uwt;tmJU?Js{8zLJ0Ht}S2=2r~;JwPC%Pzy77gBBS zfsXa2(Tivzqf|>G$ekT{mnr@)30l4{R}5H;(x7Sx;SLa=BGy9`33eULw5*c`l^`12V0AJI|G z7Pf*-taH+LBYfF&Pu!)4U6*7oCiJ+Vb$|+)nL&)4h(XzU82jFOSmjfzSvya$7daQ| z-rqGHnT#zG+{CZXo333ls<47!2&GPYN~h~KL09Nq5UF0fNfHo{+RWjAiKL&NO&Ll~?V$U at 6fNt*M`@#Q=ylbkqLk%w) z5?Z6aOlq87H*6P-B`&N&Igz+vBg*638BK3Dj-oI+mUF3AlnUBUeTVgyf>Jdw%-Mnx zF26#W{=zr&79aPa3yPGKUTF~a`UORlTlB)+&T?Iyea2<&IxH-xHgMPVCeb<1|w zZes*u*vnDXOrI51WS}&<{eCevdJ);l_F43VMn}izBK2Z2E{7aUSXUyOl%NciV`ir6B8sUWey>4{o at 1b5#?T0CfiD z|33TZD4mcME49v|5h_tgU=A%x!Jq=@7R1X(2Uv^f&|)9kV027iEJRpC(l&1V>H#xK zgZCl?;DaR at G-C!x|GI|FbisSqdV>G}AOJ~3K~!oqaMH&c1lB+a+;oAgCNm_B{e%Ca zyQs at 6V?M_;*A%Cf-uvID-O zB#~FdmV8JjE(^PHG`dJHAOAS)iX>|t-wz2&VbuQ$vF7lZJx3IM#V3Kl)?a8N5b|Y* zwIwetzJmt1?=Bt9Z7_V#8iuh@&h|BpG#3zoy|em~MIGWqQkJ=oIl9<)l7lGQ_?S59 z`Pa{e%~-Z;QL8i3r(|`#7Xhpj(;`bVFctr8ADCu6-?r{C$K>yS2OY`)70ULi9zzIg z=-(p8?$Qo*{l*yv+fmry_az zA0T8HbXiY(kKl5UBZSvB7;yLF#@UBbM2jU4c*k7%b6o8IqRUESO-7$3TJ{JF+n*)( z at R85aL4i%zd#8b>vo>x0sx5+}pUjt(B~r?VO4x#Fkb`{_9#hiesc0338VN>Ypcv7! z`bxQpBIxYQq+J&~s&nKs$Pw)5{Q5o}K}TU0bEaav+g_1N3(n9^>rwewkpoODFtic+ zzyJAp1$+8|2-7sV_K at cGA$5b at Xw<3=+oc5C5zC-!VmR_Ij7Kj*?3y9f*O83BpkP9l z%}3LyH6oP(qc;{RQfCfDSVmXEWY`$ZDU=Xs33>a8?DDm83^$g&{s7!S-2 zbyERmJlL~#k5UOSF4VBeC%(p?30JayEqc*{8-=BXyE??d3HRTJ3aIYpnGo=5df>EJ zJZ`CsP2f}m#R>=heh=JqxDI>MLyAnuiO4iAf-lO758i0(UQ zE0oYg>8}4n#(=E_t_GMKe%e5KzO%B7W`}MzXb}dVOw{0MM9=+AaVrzq44EZ4OM-+k zcr0#y7yQ%DPVWARd(@1flFP at Cvw*JEwrECR(P(=&@;t`x&to96H%mS!J#c+aIenW0 z+0J21#(Hh69M-e-eR at CU4m@tp^~vt72Ek at uzR+|%PDPji5cm+SSN#Cp#l(v8p4bFcD9e4k7QvZ%k z(Ouwq5Mig+?w6Yl>o#|~N;3J9Nwii8PN zDOs3Ts1s4LJxV5S60guh)rDc{KwXc+p}RO&m!@phbr0C3=ZwR4G8N!)d{Ek3_ at J3! zR6M5Rhk~pev!BwE at cbrDYj}-InBl}h1lZH0B#gSe9GruT84vv3l(#*XFaw?gQ at chf9pXW*bf)Hgw8}p0Bbrl%_&J#jS8O}0>q%AHD%0P?sb1) zR3ha#zXj{kh0mCR2-1tucl64o_wA=kJEQ at X@B~()`*7$O^3OE00$mi_c~o_f9 zA~i<)#b6z;9AV)@;&f}HJgn|IyZQL z{tN?*)>mN>qx<|~3}&Y5zV3jtq_u1~$fd7CEaGfq56|88AEHUJ+`=vTC`V!dATapf zVs33Ih)O?QAdm(V1eM2lPF^W<4cwqJ32IPbR6+*!Ndqjl#)vOLs9CKhU(A~mYoX%e zV9u8h`PC)6*JLNN+}gTeP|g)K>u|}C;15;&xi`f_-n}J3^-8-xF4aphvkc8FjHSvu z#%bf7Nz0j{?qg8p`hi~qSj-rR#Fa(-3fqQ~m-vxX7mv!NqXzjl8F5Bkya7fF zPR34ek9FIB>Lroluu$D=qsYMsUnU^-Mj8JwLf7Ih<4nJzWdt%bTB`wNSFM=if8C2s zyo at RIK<=0bX#heRNUu_|n#EmsZ^H#6=yqneW!TROqdiT8Prq77lpTsI>{Q`D7#hs8 zMXM{j1w)kEiO-4GuBzpQW!fQj|0ejlB2_PCz8Y=BBvW8nb^ z2-<#LJf`QY_G5CzGxLvYab2xIJF7TiWH7BsgVO2CKX&hphtGDc>Zpxe?lZuh%OQq{ z`Iys20gFXaC!{X?Uwg%Pf#6;)#PD$uEH0Oo)j at Je!RC>}zFf{qv0}Ru*R#d*)192Ptl`#aCZx0(65Hg;BiJ`dBY zjnavo=SA9E0n6;!1g1D4w5w{U3{M+6+LvA?nH%+k9qq9)l1 at 4|8eo4mxL1hpymU5m zgHBo60Kj at T?4$#tK at Ptq;ZwyRo&4kK3HiX4Dk z=}+%3AAyg at H~bk)B0zTKQ1j&;olr8vk^^=Pbn7n-osAsYAUi`rmS_J4W%IaV%d>^Y zr>00c)78Uhbh(?j4p-Gv!U&SKJ3;pS&13f zF7Vn|b|VqD!+oTtl6{Et@I0PRUfGr z!>uRuGyBw)7F9aok7mV87CwOB_jr??~j9eY7Wcv4o>&BI&^^*smk at T z at sWVRX`c(P at J4O at Edohdj%+Ipw7{s&C;E}8y|y?4|7<>Z zHw;W4M2pRS)~rj{9cid9XCn^Lp{sOOZkT{)NGYmwn@?C|e$g39h(o>;LCy7OTk6Cu zq}iA$wRoi8>=Fk?0CaBp!Qihb25raD0U5I at 1dl0;3%TBD07dYtR|lfM%myF6qnr}a z*MtBTm#JvsmWz_K1{!Fag at lS@?Hpo00KB1~)T=UE4~J3Z_x)KssPxJnTGTi_JiE+z z*CCI!ls*@`MhoN8fE$gL$f&GX1|v=>mMO>uj(F!@sVP?53aLNsNZ5+Qv-XY{JSGfB z&^wSzcX?NZ+=et at x)?{`=crew=@~y(X($Bd{`;_({u9|m#P4Ys zk5X?HD#od1N;SPCV);UmGKEZJ1gL at 1@gAqhm}I583TJaNpo9XCosiWm64_~oy^)QI*ci*S zt>-boAv81z#aqzl6Di;tp!b6{rNxL3Jy=i)p(}uHC~Sii?M0^8c5lWWE0nNm$1EHP z%Rpm#D~pB6fnifk*6pkhEegJiO}n3NT%|e~J*wZ(3r7lCz_M#{T-Tv8MV3zTmeY3U zPtRo{|5Bl@`}_Cr)?t^KWaza-bWmYsvVo=3lacL)eX+k(ez9FS3(X2(-$9!jowh7N zc))mceR;iFIGLMfltn8v at Aw&;5zt&s{>dZ`l~?xu0YTM zshJgm+<8 at 3EQK0MFL&AC4uSzq!Nz$%)96Cxa~pf`BYj5kV8qWy(JO9bRHDS}40Bgy z=1I{829$=B%t0Na-4VY6jrwJ49CJv4yTI5=UZ}@t zA&5tFTl1Cm&ZOPFh(_P+8o^NXgmv+-;LJFz+Gn}M at fqI=p=MB=hVy7G2)D2O7qQON zRe~t_KfF-jdP)?uzVWInAaTGxRC{P<9>7 z$kvx_B$E~rZeD3U3ScEiE*sD(HncM=Z^tDp!$IHdyC{ZyXA!)`LC+xVJ>Sq+K7Xo= z<(*GMCtLkdh?RLAn-{q|2UzQCNtp6_U=}8*2=VoHa`TI1cxA*_rsy1F|KEq&&?gI z?o%-E5XM-UKVbrVv7k6g%ozgQyHD|tP0Xq{X^_Lxb*Ot)WVBgbv`Nt`%`JR8T+-b8 zYdiF?w0{glv9Zc1=pYsu=Yh4&@x+9am4+}h<$)@&OAWXRsB<*CU~oFd*t8r65l5$5 z?Y7HbF0$iBHn)JIF|65D8^u)T6rGm%|9tP9M{J06A|j|(Ljl+izwdH8F(>nG#?F)3 zJ~ruSUc4fFaC?7b8-mc724eTfh6r6H4}cb!m-p^-hoZ2DXsZEg3=qG~e0p2M`lmTj zW1i2Ze3$4!Y^#8v4(eJb$%Py~ha|n>5Pv at X(h4BEJ~J$NX4-4L60penF0Un$sb51) zK5&{&{~9b5@;`6}HYjrOkp71*L!MNYU7fWqvb}R0qVaNS&E-1F%k+46uII<&jmQ!x z!uZcQJnLBy1sGJIk?_Urj(^RIj})}n*jNEW2qC*ENAt&AJD0o+=h?nn2e00&oK=3-b^q4 zGS&--j{#9MU at AykqH?j~_=5P8y^)M5^P`1`wlVH99z~ZF3fCM#&aH at J%;CtPl3nb@ zGFzWRRk}SP+kQiK7Cm&iHI+ZH4;tJ at s_wZJl zeHR&1S2Qsw$7`CEf}|seNnhD#%I4!9iv}6XJ==5)*X~HOHlEV~ih8;O7Q|y;fRjGL z2WDCYAL!k(T|_`E1CjyT!2VT{1ufTeZA$yb6v+-_!A8+3PEhfzV1W-8Sb2 at Nnr=%o zP|^V|x*pSFF1E&=gnSsgRR(~t4N~oxr3fg;f#Ebh`~lH!A}M6GC&JmH-(cOkLTh1KJFib~{Kl8TcvIWA z82DTK-&RVATUj~Q98qGhf8^M at Orr{!quK=Em8N&N4y)%Vv0yyvYTMHNaGH!Yutk)zW zr)(C<=$JeYXe%Xz*@!SOxOjln50L zW~U%eW*tjrefjS$jq9x0P!4R#U1T{ggcIK&NURaI<;yalLE{ZX5Di{4BDe@$#n3O) zfm|w7jaJ4k$9sq|1Cz%j(P{}db;@a(uirC-eBiJ{cwuO=UpHCYKxHWEQW4<}NfE+> zb1TiBq3h#~0Wa`@_7`YW%M?U?R>KNQ77h3ztd3~l{P~X#&QxO|BksTD?$+d4bypmP zj7Swm(-bAqfaP4?Ad#pnp_IOdZZp%gFwcebi at xHF>GznxO4|&xpN`IG-4yyV20wbw z{pY<)00(>bWg{%uyN+Go6kx-C2-td;*`xVZpYv=v8w9HaL?b&pD4yl#vQq_qLMeKh zi%YA*^|0qA5z)x=>Mx%(MzU}Nj?i9&_-8Orj$6wrzo6gM>xs^V6AIvzR|nCF%; zE%Pq*odQWS-JM+7(&kjlURR5p1eV721-bEytN6VX97haQNJ#}iEU23HeskJ#5awq4 z=mQAn56b5E!9~5SGvq?TMANx=Pp^B_pHBmHA#T0dFc2S;`bcyqnX3#m!yda)8O?~oVG6X0b5 zsLQ|+VDOxwUn*&nWeezIoDg`%!(kn(=7Exvea8gpBg;fmm{w3}Yv7jA{4W3z~L%8><>7 zIs0FS=}cJ&5ug{$poWkMEHDT?x at P5DS54AxM}ZB2bkkP_xVp3P$LU{+(~`cyVAE0% zfoYyAC zLI?^RzVeBvOUg^gLC;Zw^!$>mK?3HOis9{KMLL>tUr>6&8 at I-(A`c;^(V8_hlMWg_ z&E1u0)Ffi8x3T;YDZ%9;-^Fm6n&X+Vu8HGNM z)+uViK&FYU4%5WVq%4_#)H9&YUwF at CC5YNg zDoFDlq(=3D*x7Ix@$H`j8;x_qj>MU`3#Uv*CpQzTTF)|Sw|LjJrA!?U8S{|R zvUHSE%skl)jK*Xk6PqEZG at KU6mY|i-oklJMi&bW!@14uoMI%NIS!iRu_*A&%7v1(+U_3}H)#*!vv~&|4Jib-Qzk?)DPiq#P(92<475 zlryX?^)n1v4JQUnX0slP6lZoW9AnVccb$-UqN(+n&P<8!T#^usWVHIn$O6p4vLv!W znI>qLh4a<05OUi~k_{kUXE at DNwy16Jb#9=}w!Ol${q?$r1r z`f3ebEAT$txp8wFCdW%Vnn`6;OX9z1hLDrf540lqSqRg(9 at M8ETr6Dh8x1~#!08{W~~@b1M)6K at 5Ut<(w at CP)BxxbhqcLK{+v$S`W0iJB3Cwq)jN0kbCSyl}2A+ zxw!Y%Yend6kch|ZXxq+Gws7Z?oG|8h}7PRCcf( z_6S5X_kYUw2hqok=;a$-kKuXZV)GGMO%naYbq06qHhmQspX-vh6XO}-j+N~)V%rBrKY43icI}% zvE^xzFXx@?bF|J-#6KinOtt|PwmTQhF*yMXF!EPG`o1l?>tSVr!@2qAV%!^R-RiAp zi&pqiJb#+KCz-Cc*ucMf!d%Aps(vM&(8yibs>ty-UE4uuW1`{y(yJ}jz~FmChw^gI%QpOkyT4e7n4ZA>-s^WSF#a6p z9V|c1PzvU_%1XDHM$Aq&p?>H2j_sm*-F%5v4d#1VHbaO>gibCv>V+EpN6gtI5zmhz zT$@N}REa0plUtpXHBl6IW22b#cXb3 at snR<*F?*2LYQu{<&38|JJMsdg#g#F zINQyHQfGq5gM$q&*m5srCcfIc0IC5&72OR^X*gzcjV%3wV|&)^)(_;2lc^six>`oINR^yWMjHq&^BA*HL&KLJ^z at v%9TA+HSI$+cG_W$4i z`B?aTCS#X53Y7o=AOJ~3K~zZMLLH!{-3n&1x7UNK>; z2za;uG*{PdYeOJ}-#_zX5I;Ap&yueGGH7`CET>OG$_SvBg=ZRf!Amq7#~$AAAz{3P zA@(q|uUjUcp{IP%A{!!fn0S4bGb_ at OtvLV))UDUGG2>}eyHMQJ>9))NpP$=YHOSdZ z$<*N3k9r3&9O_;xi at 06cHTV{i&FD5{nlc5hEdX55Y za8>|4K*GPSilUBM{JykFj0>)Zh$oeawQ;I>Wa~wj?()+R$%6`9#glhs(_&wA1z(6t z9ZV^jD<7>~BFKWN{$3HUmzS^l##}B ze%SJqxiYUXi9+-#Omi7h+Rascd9|}`xl3>q<-344!XO949nX(7;D^S!)mo0nIC-m0 z<|ieP32)R|?f~QoQY1GBi3(P}#*aI?Xy{)ac8C|l4%DSlaB&|cCyRytL0gtp!=$>u zj4pW`PUg~0=sPq*ifpVo7zKG;e>eK(tfm3>wg?*=P;7eCh?NbALh0dYmn?02Au-Eq zogM&gjh4D$wUQ>k!<(%%?(oHwK?Qbq;g3Jp)E#i012ycHKHwr8$`_ at g$rB)<%4Y~z z4S86fG3(aVHGyV#$;lKdy+#pSVIShqI`DoTGLV)dpTO-cof-_G^K$%Q-^p2Fdrr+> zWC3_sA`h}QU}&Zx=TbBCOkCjfEtt`p*`F^LBpV}*B72CmgWcU+&J5FmDh=kL4JJ6$ z&sA&ZG_gSzLFSXFvYuc%?mNUQ57ud$n_>S-Tk-(v$*!iQ{=yf{IikUj$d4q5P(W6+tvy5D#SN#!G=4WmqLo^sL20 zJ}Lx;1a-sI7qW}R0G(Dbt~>C4pXoqD1c0Li17gc_f|$yfC+dAD;#IIH5wg|e7B0s^ z?@U-Tg3aog?*D^95VvE4AdkWlYaSZW_D5WM20>#~W%Sx)UcB?}cb=@e_{4DtaLNfkL8- zs5LX53;Md66iHd at Ia7{~$qS6J*{>SAA}Sj8 zWkQezlrMQzF2?V@`iKps!KLffz%=f*Zh{j2+07KeKb87=@RIBF*WjfPxy>U7k|-Pf zrX^PkXt|S#)-WRtqBSQFFM>ptdZp at nOU8OsA!PprFw~ z$1N<%$vkcwds(q14 at B2O;emT+pm)UqF`OpKMy^h>#Cn)#<`lGwl!5P)uml|mm*%?N zMWbBev(6s&r~~pjn;W^z8v{Cw-p!_!`%HV=B at w{UBENs1;K-+CG~x%5CHyYfyb)O~ zI{W{lz3>4Mo?vO`1I8P~ln53L;1%KjA7fvZ966FDY0CSbIki860CY1}k4VeZ7LlYo zVD_G_)QjT;JlwPrrJIa`PwMCF4||{29EX5jWjZZ*qL_p}-N4qE!wDTOG`B_m6xL!i|BRW?b<&go{1X{?9_a4~U4|f~OMgs> zsTUfqOG*u*Wo^E)3y}k*YrG^pr#wfDJJxA&4jpHP#A`@-)W-#y%K65j~v#jaXwkG>h84B0-UHv30%<~cIqNi=#zua@$9&zDeK~D+cvQWv)nLs5aqAq zHZ#k_xY_Ud!iX7v_>Ah8KtQg8G{#E$Mv|QE*0TJ$2o4qslNjRd<5S?f8^2~5oaP?x z=rG@(VR=!M`bD6^E*CHw3~V at ayx;0 at y}GW38x$!jmH&NlKrGw&S7*j4 zzv#h{X8MuO8VKj-ppfMZK|HTOrk4qwoBJ4XdADHso5$@9@%#AT>}+t)scNY2-||4+o)j14AeV)Yl2T zBFZjNPOerb0OMsi3_R5WbaJ8#as1 at 1%Q3f%X9 z&PO5tc!mrovXGy~EOH<58zp7Vf4MT_uvJujo!pXAn at XnAf~#8=S-^CzE~oAlrp4dX zaLh~K>52YKS1kM at NL#61v5i7G(YveS(3gvzXYfNOGV at p!>fKSm89n)qDtH94nA~@3 z;?Bq`YnK#}*^97$$*#o=Z-aLEihI?J7(O9a_cBoQxJJyF%axNQ7E~svdbwa|8*y`@ z+9tq4l4Q{dVf1Pe#Mwh&juoJ$+1827vd`lxd(@|=d at IXlOJ-!;0n_&iKaySyennporNrQB=}fsNuE2Ie~1hI zV;Xy*Wzk43c^a)$c%q9~#E^jH&no+JlqB%IX} zplTj$jaN6x9BHe=eUl8Qg6V3u;!CuCDTb;#v>2hY_bIjV`3h!=9lX!h7JGiQ}e* zz`B5iCJAa4)@95~pYq;-gGoP?+cp23jKq&g1}@kAC<9C?wH<&MoqQn>XXXadVn7=J z)+#6YCsjSkx)Zb<{b^b8C|3%OWG&52F& zi{D~)zi4(GLV`jM>Yecz at Z8uM<~h2X at ICLVmBbh6K~+=qa58XFhStf#ER~AfBMi+L z>}O3nlO{bkSA4bAsH48&F%J?B6VgGAA~*bIu~kJk{^sBs(F9x&+ZHGhQtQdoFvIKR zmW*N!ywZqLGaUUHDi5Bf5Tqv8=O>fMjK-EOLT3$aj_4Jv;!e9b|_RPet1eh_UW z*}~7a(UcfpXGDnTH^@k6^@z}n@;aowybwM_3=itHRXW* zUZ9OOP$KZIWP#xl^7+JS=@!XwjV zp-a~I1b5`e;`FDWUdKmzg&s$JB^IM4Fqff%=+>ab6sbtoVl;9971|&NTyhWd7z!;) zpE_`MT`!roDCv|NiKe2h#_8|UatlSjOnugQIh+g3$Z+I=!1kPY3eq z?OHT6suTY|(X2}!IbroS!3fxz`DDd*u!FDjaFBHmC3 at h9jQFaM-Yu8Q8HmWF%zP|g z6miZaBuzrH^HAU|m+g2QiixWw#G;HVGVl*Arn;snG|dwaL*R1RoIub}XAH6~7F`Hp z!*PH|Abt4xbq`ih6MTn8){CSwMOEGXjn2EZ)i3vXFJq-QdDie)5`Pai3L*+&2LFZ&tubDNCBn-n9!IcoR!Ye8s#cI;hFN?hxTMiDE5r9 zYiO4PeI^q&t$s378RzF*dO2^in&vfqiSHtgysE-J%X at b6KAR)!;fGPC7 at 44^wI_Xa zA`ERZf$zDruYfVxqdFe(id5 at qZgi6l!+L&Rv?-h(ZVXXmUuxv0TzmLj+6 at ZADsDj1 zD}kuauFY!c2a1CGVYDWi+3XhvnvM4Hx}L=rpIiQdLe+e8kV1Ogr;C^d7{4FGO|Cg- zy!5xO9um?UEi53GLl>dTk1pFv9)m$1_-5{HBjNc at 8doD?m|fl{ax>vMlrlVF0`}PY zvD4eLOC&tPriU{j_*Rd at rUj$DbMwcD2i+Oi++z{ zp&|T`_~*tf35}x6k&%ZZ8d#o at 4#&D+p6bDuHHz at -c4ITJ{bR99)bE97ibRmz-A`4b z{k(kJHwLp=ky?t7sPsWGyP=L4AgkbquU|}mr_8t0oh-CqcDt|ox8qWjBr1lxo9A3u z9fXECD>mtbC712sFNme7+Ac8j{7hCSZlju7HT(XJl(s3}v~=&x9N;h at 54L!(*ifQ>bJ-Y_ma-Y%{$8T>IwKJL{PA8>mI4D` z|C at m0hxDO`7ht`p43vX^Ys9#hEe$hv7c-Y1LjL1V!T~PS=evL)J*F6j8xGB(W^rMC zcZyQ+jOFWuC|(lqew#&ViNS4|!i)IvLW3h`dim!szw6pYsG74ARbx1nw}m&|O7xo= zBrSolnN|Az{n%5<^PD02WoPZx at k|mO#K=y!(Xk=CM- at k!eKO&4Zw2ayeuGKmj?N0r zbwiARm#k3`Aq`0M-BkkoAGvdQo-GD7jxR`<=N$YOStI<(x)eE;GgnBOX)=+23FM1-teS`jx;5#Wae19Wbi% z*o_dy${4H8cBORFCNXt#eu1Kwon at 89r*q{^cQu$dM$vofbY9Kmvn8A0KM|>wSbf4- zsE_vUN8YHP(%Q1;(hoH=@$5xio-J-o&Z02p&vNd(sT{(23|Ocwg0-MKim6*)9EHd| z%-S!OQ>5REDqvU|7c;u7SRa}h!ZT!G-&?T*=Ui0Orw0w&-eGGx5$Wo3c5w+3#@yKp=TEg&~D!j&6V24LJo=V&$NgI4DO z&e22?|C6U1yHYTrMmM1&6JA{~V6h}0=*z#Me%U4kN?85(9To8DIrN_D$2vmg!0&0R5l at uiTnay zm7Nq)o4w(_06ESn<@~8G>R1yuUB!f_10||nNkQifdZxHpF)nGWLm5RUJkGf{=js`% z at on*S;2;JhYqWqx at MwPHIuvMw>i6IPX&%67&zK+B{!zeMIUosZwZUqZYkvQrx90HE z(P8*CB01WF9`6FG}J7{2Y1cPGsXvT!b8& zTwM;LS?Bxg<^3J{COjlKdl-wD%gyCb0o`e(V9rph7PJe#jU-?-hkq_na#aX7* zVdykFAL?(P$si_3_}=v&Mu+K2T!2}m at oqr@`^2BSY;dL|887}T{)(gOQsC}r-iIgi zG$#JIBS9|d-fQfjOc$RjmOI$3r%x|kyXk8I6K6OFrN~Hz+J_8P;ADLMb z>F1emssc-ydW at _@j-01Ab#Vgo5A8L2aCkBUY2T-I+^Qb*L#D9hCQ?uz;HL?OgF?b& zkt_`#iK626#>CLe-&lmw1VS1cWhjU1qmltUR`V3p68ykkciIVnh%)V3Ete_lhU;8r z6u742_q*~?WjzpfF!O@$C`uC)4azWeP=nMl;z6utJzf+GlYu}T+e=f(03zpiLHB+`PZ zT_#d5-ExpN_zXD>eBFJ&C(&pfSv0 at T2m79{h78gE>1D0iP$*ozbtw;11Q`dOb}S&! z=WhYQxF6s9 at 4%}|l_%GjLV5{8S(9X8Vr9;);Tz5Ku1?~kLC*JrT95-6_w)$ZoPkP( z@^S~r0)@a+KCp(3Y4~h1hQSPJrU<@pJf{yq at ZJdR%%4aSImbfO2zs6zKu+o_;Y`m8 zmFpGwLTu at iCZGs4+ijz-EPGn!MQdl>f5+Xq)U8BX4jzPrm&`I~xxGGQP{C*aLpfxc zWuVKV`*3q&WERzvDh1~lEhz6G#Z6^0>0W~+(e-&6-H>3i9$wG93|21K$?I#NuCPLG zPL;$NA=|Ud81bizX7)6!DL7k`35JV`4ijQR(&x(tWK2y$Pr%&VuwOUzmNwpD1XL6D zIjlh5mQjY#5u9eNcf25Zb%rX+GZ?)liwv#MG&v+=EaAU`K7AT?n#|{1 z8t#0|Qg~P6l!EC>Hu2Koi!ezsDy3A9+ad96mJb!3x!rKdM6l7=q?7C(=S{|e&=+$k z>s(>KohUpj)(SDHdOM$Eije^^5a<|T-s zmw`aas&&a=dt;^H*<8mQF)_79wE6?M;qBvedJRbNzUNz|rYYkB7?jU<-lGe(NANUb zIP#aG4>XPgsxy-Cp^hB*0b|1F{So{$9OJxE{bNv`erB;Us<_rTsnhbdl8y^v>J{EH z@*ZARiTJ3$kV9Ry5m{Ism=jj*9?qXhuk%8>oH6=>Qh$F`tsUxI%nh#5EdP7a-OMV+ zrfVzp;p5Uo8WO-jpfG>`44(eL9+pJQaB;R9_B%A;^e8)DHop)1Z0S*{7K>Bw^-Vny zaodtv_mcSVW+3E=r`kbr>~i$+rqsfhAYlN|jErWlXWr{4FUjv&%ic<3)5zvn5^UtM zI4T5+_Lk5#s7xQaQ>L6+WKCt at 1@S)O1g98J?7c*y{-RAii|ygpS!`N>525#G9YePn z0nx;Kq8)WYIrBeN(i)ZZJ!10~mYd#4&<7%ao$er`C;4&)wqB?gu%Mfvy~hCpy-5b6 znsMg^V=K`PJA at k#BjsyDMQVcgT2^Bjy0e3JH~CN8tF$WF8FPm-f*D+d<17yBPoCcx z7(|sx#i8L+-3D3o*?Pw at fV^%*$o5C=_&pX~kRP;9-mssUba&(<49$K_3++B$lzvY1 zeI9h91jBQYo97x at jw4)r8c5Ju37lQiEVHAyS5Guq`7bneJTwnju6hN7$E!fmY+}xDSq=)~^By z{?Q_6mtwejLAV-QRPSeo1*b?55DKpqPG{iJezClonuA(0aov-Z>SyHY;aV2rdcAP1 z!po8tvZMOo9FPEx>`EQ&;SRtdfd7U+5qKl63~I{?df{0Ctz(N+G&LQIz(RZI_i=q6 z-gc59Ok6}&M3R-hm}79Vg<696_4CFjVNosD^o(3eiOCq1Ok6HY0{U~-^P5EI_O|8K zk!aW1BEC=SwT at 7G282eFxX`mRdAwVhXM#S2)4raLC4&r5=(MFXoWA;ec*t0=JUo3+ zO5Y&PWw?h3t16J*pE z_7_(bB_Uv3TlffJXG$1WpR9eKDAYn-+=yafyiRUbIeCu7om#^(d-$Zmp)sMGEM6x# zPh~0O{Sx;MaA1V=Cd>Jd$~#=XHhOd<=eT^NqMs_xr1SU>k0}es%h0Cb9&R>5Sp> zoCt467?4awC%QV0ywxZ^u|(R&gnA+n(Mbq4)QyG16&(K@%$vu{ zA{OfW!?Sxpp)VmM9C*@?ozy-LSXgS^6x13*gZ}SMZY0!Zj!(()$$hvQ;vCW78J1QI z=$QAKQcCQ`39&YvGJgj;PL{3jC5GIS`a(Ox!3+B8hyB{o zmZWY%i|E&l%5w`GDm at R!$%q_eqIDwST at HjNiCA*ywST|Tf*nF~u(Hdp14^{TmXr0% z1gv^IT$OE=KZ#st;{5)AP&YzxQ7^oF=WB4IUz7~(iXQWv8EUL;xei960kfDVY>$=~ znkRz9ImV-Tiz2#n=}QmXnf at +~@yK!okrIu?60yM0Lhk3jOt at nkscX`{?Hq9UHd3s2 z7lN)6C54NsFP9t~3+!eTa7l6|TRLIk`t&9p%zR63Oa-^QEka3n5riP{Ao1sTYkk&g)fh&y z-+usR;AD!tt5BXp-0)QmI#p at +Wte~X z at 5j#o03ZNKL_t)t;6T?eIE at OYA}|(j&7lPSaz0*1_(oBTO`f4^B3Fc(X!9NG5TPqYb!x^^koz7Rm(G{(uSl<)&Vlcsow;E|IRRA%vH+d zAy|-=+;KQ(geX6V3 at lDa7o#GW_+5ZpW;Y%i)KFQ7e{@MJ6I01`(Q{hb-&5_C+W7L& zzxEI3W-xM~#HE?|O~;^Dad9QbpibU_fPM+q9BoY1#wVNl_dRAlDC;;mmo^J#%SwK* z2vfvZ=D=|6LBNJW*Z=OW->f?3Wt^ee&U#RysH6wp26gnv#I5gs*gTb{K_FVdixzMd zM)A5tFU|;l%8gZi`F{N!{zy?ZuLERbVYj zi;~ZT_7wJmrk66OeLu1ParT}a%KI%O_~7!_#4 at IOdaMR4?~lXKk|o?@Agv-H8P-5c z+qHCcbETd$oCxn9N9f1gS*Z~~u*C@`_J*4mR>HJYJ25*ct@;e|g#_iL$g`r(SvhLo zgTL at JQTRQ+;NTeS&peP;NCM%M`Q`9Cff8soAv9_-I7>;AqHx=?0Y~Pa=NcidXYcmk z^OW^XsWJLw7GKHk4f&h#4W}~%Q*!4{Q<)7kw} z$r;D~h7L#I=_d4IvrqvskGb-c+V6-Ke`IuX<%C9IzaJ!E^kV{+JB{BA_aPgr4@}Yi2q{Y6=}rgL zyy?o5Roj=8GL^Hl#X~!i;oEe~riKo`RFE8n4Cx4Xea?~ZYX&?M3ESb>?adSd){TQFOM0namA;?^0)N z(gLE=612y9N)FFxqj{K$DmuVR?{ml$v^MW;KFRKSvOjOTA2TrnFUn>giHCfA`wcIP z>u>HM#Y9r!>?g;O;T4bt^wY at ZpC1Vn&|@3*-d5_x{C6nUu|n$e&Nb4Om%sD&Pt7b* zkAnV5{@)mC`eXY+y3r>nPT~|tbDb835XPhq)@4t0>Jx#|6)`n0#TTQuNSnevlI9bp zdKFByYfvZgQB>0 at F1GFvXO@fCC;^%grw*J+G4O-!LY$h4fUz*G zg|pgG;@gM;8;f!u1EEd>-)zQ8SHM{@MmZpMwQ0&)90}!%T=zr4w}GgIF^Ew<`oJ>` z`kB_;C15t#=<$#??sMD~ zAJijPrPMepZ=QYC4widMZ%Vo(4NJyR%^bB>5Aef&ni2Jtwh!1S*opic23JI_-FKJ$ z=!QT4LPl9PSPbcCgZX{XFj#JO&CjhX at U>ZMbObL>0=($a$kdENcgE%=rQNat9JWc< z0Kx3y4K(!2G{cT7fwQuD7-gl4Z at CQl126FRDXQzc&>9}nOA;1c6Z*zMT(v0tqY6RS zJ+Mk?&dd**L{?=3 at Es;hu?>u^3q>(rnwui>;POG8t at E;6M8blKAFUVrgW5S~$6cUj zd=IaK8*Exs_+B!iU*0XBKE$ADA`io6ZSVGs;|q($4JHBxg5?{y1}ayaL~iUH7-!mf7#FgIY>`_!45zSJ$j<@PJ$gr}~ z6E3kkj2cFKh73wo9&ssy{o|JANspL2!m(O8xbHF>bE3vOgqu2%hlABHL0fvMX(VgL_KI4lW=zW*&`Vh?bAE at N)6a2<^WP}9q7JiODp zU%${zitQfVXb4^vdot_ARdVxG#u>(m|Ir?&Hs5pGKMW}uJwXcdXUsur#X=mO z@&g=N+W)J-yM*+0z9P(F>O>sAPU#E6>3_!}FHWK6Io~s~$f(0Q8!bAwK~iHy&OjS2 z!>x4%C+O!{PH;vyT5o=tAP3x~`XwdSiZgo~d ztz7D-M68kb7#ndmuw^+SU7Lr}sX&Y}q1v5>oug_yi`HQSWmf>l(c?rUPf^87?r=iV zkd=jJWl_%j$JVJgvU%=24_rexD9=;op?IeefCOz&q}NjpZFTZP{#0U$!LYi-fB)al z$r+Zk1CHiWNcleYXP|tR{*dCZA at 5Gdtei_hjlIm{(CY`}ED>38;|8)r^fbsN1!Jq| z&+*J!=VQU!R%1gyq?|coaW9!-(;p`*pYUkr(KxK~ctW6^ucH{AJ%-q>OO=2QqCHr4 zb)0);&j8RZ8U~do_h at xE@-h_F|M4EBk%CUauKe-c*h(OYL|a?q*&b z23l#iT1;=t+-r1T1oNA*i`S0xGu^rLr6aX=I1@!YN$qO{nwkkm8F|IY4at!+Re$8x zM$8hb9?|viYI3U!;%2^G2s+(_2#HU+M!&!Y$wQfG-}#*MA&eEqiOz8NpQYDm5+ zBC&(VsqnNL*v}uI-E3w#oPoow-I0GTJZ`cg@&@f_0>#=_6ai&z`8VOWx?Me at 5@J?i zw2ho|5B|f+2M~&Y$}a`XyGmpZU$jf3ZW&&VsVU(=3he^nE`IL-9tt#4|IG zvnTQ#jSR)uo5wT36Q&QHkx&8YZ#Z>7u8}8(qS8Lb9F at U|!@Ah2-AA;Cv}l!6vg_Op zSJ=JMSElO`GzovOnXoMupHmUi8bL&@9J4UUb!(O(h?7SvE?;Ivr5vw9vUZ2(>X7Y| zq7fqcyH$O)HJQ|D#IJ3FS3=`^_cNV%#B&sal#(KRW&yr^yr^dpr)dEXg7(ZzvH=sX zknAfc<9wT{7OB#94UI)Fh6;SKBso=Z79h|}Nh%vqWZv>?Z_ueqe3o|h3`WINHi5>W zvo&#Gb$+>=ne-|QI2Z`nyOgBFA;KsSi+OAPF|c;V_|{BJJ9t&2=VuRUspq^2kzkhT zv}xbekI8$0j0Sc`Qgni%*OgDqZJL#=_Zbi;6W~-mnxjhOn!h8EIAnug7pTDYzeVSl zCNtl-Dv&tx=^m}0#-u>#TzKNW>gFl{y}Nx- at tD6<0z*WKt<@;9>a8L@`XkY z!2iBVq!0B8sv^3d7ZB$|q0kb~0!63yZ!I*vZ1N;@uclAjzWYFIHC>=mM9I)mZq1+T zIi=H8E}l1f$_1jX^F6C_ib2hXhnfuoet& z3XOQ7AR0_-^zkdR)dOavAcu@%Yi{iv2vILmK0`*Zd$T?#ingZ6UZc!_5wa=fj)+PH zGpExXr6^#pi)%3pXjQYD`K-tEzUdi6f-lEIr1O5zt7WAmK||4H>VfG;akia(9j)RV zHVT|o9AV8H5{?gc9_iO$!&yksI;b>1ZMTpPc1=OY<1Hx>l*M?}A+iM*<4}e5h3sf& z?<3yJJ)_TtRf6jCfl$Cnx4v^Hp{?bm2x$IZ^fvkfgrFR6*eE^Y2_agK#OfSaXn9&= z>(Z>JA?Ec8W_lSsdv^Aa$m8Lz+8c>8OW9W~=EpC?Dww`tEQIFZBG0Oy8PVLp6SI8d zLyYcJp3a0cSFwWUh+h-_Owmz5EaWEKflDJYjY_|l7?|3xKl1P{v=NDj3xZLk&1{PdGJ2q_kDh}B|p7 at gHyEeb{OtDa5S zI-E|NU z+M*+A=EyAyuSgsGBe3%KGXAgh0vtb=2Gw#tNtBGGhKHEq8sDH6+FE4VnU1g(-hI{8 ztrbY$c#|@5Zm at V;5<-QBFu9CAWcDu at S}C)18`AKFyrR?$mNjj%?aSde@&xX+gbCbF=jZHh9&qq6WL$8!zFTu*|==wnO6kw-!uu<`*2H!g z(hBSp@)KdVheJ>J{L9aAoq^N1)>Oje at YdcF69S1CycbaI)S3l7m)4JU54)ix&Ks=m z>Tz5_B};lSkEf7~7FgsXIB45!C4wgp#Ch-U=|Y$kEoa3)G2HlC!D@(jy$5mGP^N%O z4m;1?WTyxy*=Hb_!=B3^OaxMSlQ{#e1SVc&HYhvl|HAZgtQWCc#WvFvv`#ahi7lS9 zvNL0C_#FTdKqGlgZb;#$_1CXb5=!pSVMJ5$FPZn{ztPJ9uB*DBN01i=0psw0d^w5W zWB}+H1k7}pQqd62AYy;*_ypOQS_k=r4Jp(w#|d=?ZK?D%a`UAJVe*)={c}bmC#z1( zug(Wnh5U2`Ds5$Q9_yh*X(C&rM?)j$R(~)`SC5Bg2MWS#`#}mUVJ#y1`<4q5acOb{ zf+v{3fykUR$)o}<7BIF;o)L}k?2}doUvKCa8C0)Gd3$&)WSgzEo7GQre_ z4qN9T-#@Y5>18ClnAVtMfktLQ&JUtN4HH2&Eo~@KxpObWU;bzOmJ~xm>Yq14{UL}3 z$D~9Y|D${>@_3rE^r1Nh8Qu&{r^a7q_c`^V!W(Y{dTIksw at o7}hV7EH&N01M zx-36h7bj?apcn`;X zzCk_>&zB90vD(R$h)clxa~l0y+O at YWAUAG$A1_hR{Sh;Pb`NWhVYQY&gA|><`jYD5 zEh}$_D0)a5+Kc5J)m$o~qaT1FnjQt))|&BbqVSE-z!2sB>uzUdt9?x}Jk at v~lm{>l zO41IAgC{{hX+O-18qROZVW&9|;_9X*1 z;CbU3J8j^EG^7?qMBqAYiTnnimHo;v6rsrA=e^DOT%{&59haS1DQdTW$8#}d3M7x zbR+qeew4L~^;rX at 1_*{8L;rjT)^X{9w at VozC?~Z4jNjdh%pQn$w&r(6i>Fg;w=l9cswa*>=g2ZWqVnqDm{xd-1bdcOF>$SI&^6kK0=ltd^ zy)~|bJ@~qj#Q+uqLuV#-d`S)Ab!jBM#}{^zh_ND zT0StC03wjl at DEgs%aMFlB!~f-3v?gntd~43cCql6ud;Fg5Cc_Rum$!Cd;+(f%;Skz zHl{l}439sQ;?#&EEq2hg+j^}8pMLYPQ-q;l1h{Y^fm_GcbTNk3aX6%AIqU_TRbdcgXpThcVJ4|GhUe*b~VQ{ z1f#SIx?5y;+;s_CfWF at c#9dQ{I7UNh at va0<+!kD^RRb2~GAG=(*b z5tY3>3js0Ch22N5`H?!5yyi#w#o at tP3t*0oT{Ua6d at i}gK`NBKj%U%DTa+~sjNSJc zZ%iut03q3kh}e|BzyUR${hm9#NWp*=7EvGI+w;3>8Ue%NRw^(}`oy_dxoYnOnuyCk zVVx5kf5Kh7D`w_Tl2V+(blltimp?8s#4L~p$3Fk|H6o}>p3F=~Ar|Z;e$kNrW1usH zb%!4&?r!lj*uxr9QzQQxX9?X=;nF20UN?;n!Z}3I<5Fo6HSS*ab3ka<)72uT(Fp3d zr#SZ!eU01^ufvf^mqGMUN`^-LIw}v at z-~P*3<_&?=zUu{FAhwbdKo&&LyI*!J at 1dh zN2=V63YF0X+8e~R-UXXZYvM_l?{gqu&dn1kL$*Mm5Eh97;W_-ze-0Y8mmQq`ymL__ zCE;+WO~ELfw?C^-_TTexTUOsV|&a(*4ej)FX%O6XxIaYMT}@0it)G{4^1QR0J4(V zw;nkVi2d+yCsY_nAq)mVwU^esis+vJS!_a(Uo&Sp|*c&5TArreMkZ$O0lpGZ0Q> z*9m%oM(KGj4(eGq{4Le6Wj3w=dNU1c*`*IuXH(cO5q7B%B-Vn83;_~j#iby} znKEAffgaH_*fM%2gL{Ed#DbxRc&aGzxtf#D at iPJy-mNmIOjCHY$K=hI9&#F!&cq#i z5nOQ4Mcy(LI^}tPh2wfOy8xa$hv=hS3_WTzI;CaY@5gEb6jB6MzvJHhW{AkDkQl?c8o?5s8h=Xm+pW%IT=ri#iuR(aH& zGZu)sE)3g(g%&C*c|h&m+WqNMQZop4kO at Pt^oE)~#u8N-Fm;yLC{L+w^-!hnUK|n$ z?qK6{0xjU at US{0N+L!F$GfeJ~UxrC}(T6V34+xl&-1qkXq8CbZ6LsFz-lMxFir%H= z*Kx>$ASLp2w>lz(_5ARK-qXw>nwCdf9!}qXqsm+K#Fv1505RI%`|b zQNQcAm}8*9?8_gcj*7gZ$)+}$)PWkLxMc$)rf!GdBhHwog3r4h90bH`X2Ez~ka>nP z%$>FrXFL#z23GPii@^BGxez4u&Danr5atcZmOy1A0sj=p)mfjv at 7LiCISWExIE6l0 zr^rB48A`izrFMDF%s8=Fw$lsDt~J;aom|qjDdewmMtxj<{ABCKy4p=}UVR=00`&d& zO)R`KTPD;?0M?Va1*-YLHwCSiVcZ at J4)@va!A`cHdbV(HGA93~d&b6EP&a0G_hM)3 zJgWJL5fAYUH26AiGbNsbRdlA-v$N<)^d_psM?a(Tr<}^~=YW^0U+$OCwwaHPzD?aV z_lg5nUoCQHKdA=81yu~4(Ow?70(fyjyo(C{{(g`xEvw7u7omvdfedtlpR*BUXPp_4 z%?K#}U at 0y)xM^t$3yMY^S{c)a7O_=W6Ezjck;-h^7jfMWLXp;cPss$V#l_4LHi0^1!CxZ* zFqUIjMVr~?&z8-AqngC?{&ziJ#0jp8>K$YVm%@~^K}d1*WMHu|k~5t15hlYo z%ouVKm889s@#i#`PlvW6!ugIriotRu6YG?w)M2(hB=T*+vqCd~l2=vxf#d at s5J#Hs zD&?(HZ8XrxDcYyh_C at 8AY5-BgJUZ5=M70;R`!x0QxP=TzkFKSs+n9~J60fCS)oN9RihYy3h&sb^98IdGQL^>Q0pN~pTEa3qu z4TD7rWrysHSC*e;_5|>A at LR7aW$?+1ul`Q%w+)tL}le{0TWsvqJ`oB03ZNKL_t)W zgNt_X;1tOF=f{Zbs;+x03qnmrQx~l?N)q-<-Eeusj z-%b*A1)+DCpD}1YKjDw+#PWkqD#L6BFFcJG1*)#zTa4EGlJV8dSgS-r>sm@)u^hh} zJ5)b*T+2k)c at UZFxN6%Nfx}L_d_x=DRXgBq8l8fHV`BzKCuG2&o1A5$gnaU)3UIx> zD2}y|tMf}uTmj8StQ&uTm}f$~0Bb;$ze|rl=;$+wxh4J&*)4V^nw0^%@9%}+?_Pu@ zIw?;Nx^SK}5CGgFAuqNizw8r;C|yV%pl}_Zcj$`XfQYXJMU$K$W$+G&`VQrGkG{N2 zD;CeCUXols{j(&tuLG6#t_aCZcmKK9pwi{=)@8er#lC^P zisKb at m=A$R_RMZIl`&<04fl9+{C{%tMtngfCY#p`@XpM+fjKMXV(fU9{e{uIaj%NY z6|YiNMqAijr`NMYOcW<|vzK0={@yKqJaYhZDWI=DnXv6SYCJ10hunvKU3`qogk$?n zSsyRryOWtytf3BU+OAg5Q8J8qTk(BxUtFmD_gy=dVYKsNStqmhE2_t5R2v2CvE!!2xu+ZwaC?A#Y9&59SOt5~Tmh=1fg#=G#GwVRVvi at MyltD`+S5CJjlzNrR z_?VlVSItV&!Vj&EWfKx~JxvQ#l%QNLGR$ZNT4-<6Bw}BgTzp at bw+1h>0%e&pH`DR( z at A5VM8U~VG#q|RQs|qK=Xb}dgbwrX-hi~=-V`#^6cd!RAGYCtWm1Z|~6 zIFygkv7fF_o-oD*#5C=2Any$2i$n?~T*NiSu)@i|P-l2)J-4!oqt*n0dQs#EY+$#k zcaHP)Stvk}!?@`qgE$zM4HYWP0aBz2xB|_iuQ~pENR$>p12cA5R|5>Rr4fz at XVc~d zIYk;YczLBb$R5du^UOlgw{b~Sa8bEiv^eh4^~=cx at As^pZ^lBQeV3-SV{FzR zlX6opuEjy=>skqv(KcS;m1m at sHHdyFc~gl=;p7=xW3Q1j(NUR_+TP|;J7#4-^?8`H zBIpzb?Kg*J%D at 2DfkFv~-C7!st<-gx)O at Y_9i77hUDDuNG)JPl50n;#68ggzH3vq< z&F|&UoCVtS2 at yTVt)%A{-a=EtoFQVtSE?A8U{0rdL6${ zn7GK0Y*<+5){&SYZQ{s59Zn4149+?{et-X`7D0^7CJNK?~Wm{szg=^PyoHt)9 zQ@$0fR;_h!dkc)Tav at M4UXt^MT;N?Mq|FC~>hJFyJif>W$?AxcCckbs0f*s5(RNO= z2r`VVx6SA&O8JHp(Mds{5Mwzz at k4sH1FdrDL_Z~^DhHo-<*9Ljx{EqX&^xCKiC0`B$F{ygM9T3XG#bVi^pj-goR z><-B6xrSz$;R~2Wg>Ca5?V&FtGxv;!T&+wiva5a^QN?dg*~nt!D8&fC_Mn?6t^XKo z+U(qhKL(iBO)nNwz<%Dpu4qT#G2HYgE{IMd5c^+ zGrw#ut)y$^j^~}-vnn}I#NPQ=^=4O{eb12Ls^neTlK>XS%OzU~={Sh76e2}V?!wGy z!?mDD66gp%m#g=U%R#@(7 at ECxoIZ$E)-Z}BAqO$kRi1^yr?L?>lM(&M*@Fq9QAKz@ zBj};R at ALQOqS6qKH@+rA!{svIg$+Sxmx(+{r5^h;Ca)j9Ao~b3*poDFi9%bucSdpB zKIFMV!bgBJYK=^3#bC_p=cO&zvjJ=Ww}B-7`}aTZ_H&CQhju3-ard*vepYe?{Tb98 zB-PI}lW2$Mt)H*zt`Uj;%dKhDQMiE2&It!<282HWF?C5 zj{ZqpDxGB5q*9ts5`SrjdUhS5A{VAOUu$m1s_C_ZE7igE at Q(?1=tXC8w$K{p<{IE) zv`Lf~X;4sWvwy;b*JqH=^-bl{$saH$p?w!%4W2qAoDD42fJ7p*HbC$rt zHBe*s*9O9#S2oj^$#&?An;E&u)%Sh+a(NdQdgwef(j?8ZE%|sYknj*?)e!45#e8Dp`3Hw zwPvT->KjAA2>#+0GL93`|A`zbg8A>?|2X2|n-SsY-*d=SukCR{Jxj>fRLiQ-IHl{! zWO|%74p29J2I?>fe51FajR%Sn!EO~+72Cbvc$|4MUwL2PG(a-hWAAt*IV50giXz1S zueJ+x-IBf_I=~0VM|f+1Ih3FXU>{^y!X<9{-d=K!ZOE;PRv~0d2_N at 3JCHQD*c^P$ z%(94TDVTmHzw^GBmD0gfW$e}2_&a|#0k1nUBpmY*g&35U}H&ffaGW9}nl zdd{L%%K7whlCWDCDs%cCKNEG(=$sG-UPM?I^N7!QACjaI^ec7UevVJ`VcCV{NNsch zvN>Aq7IlMDqs15I`3Q^2Qx$zS_}1X=q1F6 at rpsCz2r_vjU-F^wF{+{}F69yr at o76# z-T-Nn=oBZs!QT))jXOuNr at Ib_HNBYr8T!0Bs5v`|La}VFHQs`m!>oazq at mirMh^KW zotcO1%1=|OHz|}Gm4f;Xol(fJG7kDh0BE4&XMqr~d+uW!&)h`DL>lXr<^>gy3o-v! zJay^hu*mZV5BVb2UNHrn-A<$_4Eb&s%Ms4+NDs(1JnB0w&!>V67Vi_i#8^2(Lq4Rf zLWXkWtR(L;YPyG*4dDwK^77VtM~URfinSb2a&fxU+qLPfDR9rl9rA(HV8-+WiFG<@ zkSrdN6>Q2A*Vs*C$dIFgRjotM?uqgIdA zyuJT_1ZeUU04A3`&8^Kr&si*v6|SedF_6--3ZrNx9YWke6;)dy{`q7%DD4{8gmOk72Da~Q)pGc1pcqkMJEii0(iKA6a}k{-LiH&k{HKTJ^S}OfJ7o zo+{&D`auHWQhGh!?KP0{G^IKn*rKtfBjL#VEY1mU0D=A0h|vD;9D}`1v}d9!AA<1p z(zSGw!}NLgce5kMIi+;0e~&`;mmc9(iRQYXNtG+5m3YmkET8P-tn#$pf4=PISqS#P9;A+(HY(jTc ze>)k^=B!d&{=c%FP>hsGVPo)OBDp}sU_`xHA`kS8$6bLIgXMZo#zM!_-`A`|&s;e9 zLx^Gdlr2LY%dq>WQI8|~S8w_tv{^#>T(f4&E+ldPLl4fs( zE~>6Iw1YeJHB>}?`2oqRUi}SRx4OlZ&FqVmGQ>%X0;|py_8HqaFnW2b at 3?wbigCi-~`JO=q18b+AX>s-=;quWe{S?cW_)Es9HVO z8Db<*Fy at cDl29?oE`4*_Iy;(u$o)CtqC|#!Az=&UIuEC2Y$zfj)a-GJF zWtCO97krD|4|blIX&aFy0bW|$`%)Y-z4zanOjM>YU^pOc5)ev9-!44_$r(Ov)pSp1 zh50x17bRaTdQmkHm$#9r< z9_EOADOsL7$~oMI3!(O<;=>5e8i3#F6LztdS=cn`zO|Fd3>D_sz#5Z|LO8gylJTRA z5%&WO6v(Oi*mH}^8OptK`aduZsKr<=bpO4O;W>m at sRCz!#^Sc>s~86UfjF0Pr9RIl z3pa|7FYm5(D}&9-=$B0oroUEY+hN&@Cc&LA#`Y0>X0dMGUG7~Ev|9Om`w-fIOr5;v z7Ut|yI8K!zF1TJ7Qn+zP{}(@JPN5NhKn+;sXe8rkD#PavrE9Rlj%hBgYs>^rX#{GE z<1vjJ$9F`iZZWS*ep(;a9Z=}sSAxNE?^7wrZG2Pp&Kt3!;&~)W^+&Z)SE}i7h1#@n z9MP!se&v5sWV|ZBp26g%Im#n7I(5Gb6Lq$#R at d85AQV-%tK|1;@P96n>}$~BnzNC= z3xcw`bE&a9EWfvfd9Sb{YW0|H>R%iXCO7JOm*s9}8dN0v8lm1H6s;+r$i7}_g8}7PM`x7sQaCS{ z7e<;rmQ?q4RXxTS_+rLOTowK>ka%3o$P_)TrB?Q7_XnS*z{G^ZnI3{bc*FY%*Y#1P zEX^?V=YYfNF at B5?omqLNT>q8k2zC6N|5$_C$QG=!q&3_aT6y@~Nl|1%dJg!chHmS^?gOTtfA-;EELiJ!jYx< zngZBd at 1}Gpml~qO7()x at G?jNksL+|6?Ufo;I{FNS2CR`sgov1Naf-_lVAx%v ziY&X^DX0SH9^QqZh+WLV<3a8{cw*`ee|(#Tp*$bjMvr|+M2CawdN#1%17rnCV8Ps7 zL-N%WDWEgC)Ln*iV$j39>Q3b0q at f`233;Gl8m;lBAv!WozpIT_CP=Kbg}gZIL4;&n zhjBY(pfxxaat;LQ8`R7xdv1 at 0Z=G|`G9v^3hk}lUVi_1Nln8F!twZq0In2RjX(Qtg zw|@XJI&=Bbh%aiqqCE=1gBVd^e|J6b&>lUj=7mFvY5su2TWv$dvTiBQf+%J%`=&?1*hJG6BW#*$mYGY56J zkDN>|c!7Xs2n3XGi1 at TX(`(R*^)4r|Xi?!AC`x_*$Mffqg;=_1bYgs?x~!oY1&7~Y zlgUlwv&j{_ORv+We3$p7X at r(4FrD`Cdrost{!9 at sLr;{Wa$tIEMS>|I782AXF+B}n(8}7z!OpnMym>h z`QW7)WIbi5pX6LdQEhlp2 at awLb3Nr8bI%X!{QVFXuYQTGGy}#jKlC}8X_WHFORqCO zWan|EG1NR*Q4BmgM^JTj92fLSswng<`tve7Rq^%!x3Kk2z2qGQ)i~JKyEz!`py$xq z9d?&8f#_J~bk;taI7F<-dl3XemNtJb`h>czxG))SsA~^HuXulmT{7SAGcZ9SUk37u zI5>Duv1jQ)&Tt|lly%YRD5CEGhg02fmQu(Z>yz?{x+e}YwVWp3XNo{JkhB`Vz;RmK zA}*I6QamVNMNlXYrTxC=jQT>H%iUo?^>tY(UQ9`-M6;=13>yT2_eBUv9b>^B?qo`4tu66yR8bQ147PAn8L+`7F*r?i}UFi)_*2FUro#&vrgJ zh$2QvpD2=$&PY`Q%Mn?FB8M3PMbRqi;>3u-deZ?)aQL04zG%AppDM$W z&=ths)J-7m2}XU+ogvB7@~R&5cy^(lw;)mJ-U^e~Ka=1DBD!X$G4t^JlqQET6vMn_ z{9iPh_v!Hhy}mEaO`Lkd-J8-jgd86m2ke+M$R*ZJ(B`ZbwGdR&yPa~veC+5l8>Zev zz%&yv_iF~+65+Z+Pc|4$&8HzJO*x3hmh9vSIvRB{s$xWHoJ8lCo+v#m=nbF4WMrC= zsR=tS0v~R?s-2AHgp)`&IW>7Dc at Rq{EIpe|dBx^q0R$L@@cLnBHDE^VVD3ck`<7yD z6zRYVEF#r`8i|4(4EzjHD0JDw3!a!INYDaqJ=tSvrWF0|trx~!rxwtfBu#FO-$yMp zvTSWh4wY)sdK-0kc2{pHeUBadN85zXHyG#@(Nb{w&|DG`<*z??y9I6YT)0a=)XM0P zmSdd&k?AgQQ%tSe-*oXl!&c#kS6}I?8p;gDFf*pUFvW9(8f`GlE)wU%V9#@@e_w~? z=z*bS<}Ssk=p^fcLg=AOD7dS^Ya`~{`Ode+B>zw+qBW-jsYZNPx?f2Xawt|4&lK$? zAOlMWDy=HBtY8H<(}pOuNBDq+8tb+&&EL5H7(xQzo(4St{W<#vJZ#aW()RogDzBwmUCP%cr=SppmRU3^w+`r~(sU_;4$Rfv zHEO8%Zs^MFAW%YtY*=ZXo7q0&4J at DW3>h<5ZBjss)Ux}LatE*`Zu at ti|{Tve3^3Y( zu=wX8 at IE1K%}k-xR)uOw5x2PZNb{?Qg#a` zKFE at l;Xwd(i-0v`$T1gCF6RJ3Lz3Pfg{pai(Jo5>^}*dTvizp-<3gX-hhVyI!I{Ah z!R5u_hU2bcq7kQ%T7GomwY9XCGvZViX zN$sm1F*xI(mQ(`pTv|Bj?(lKVdmyb)RTC{%Iy&N6SK9|;5jZ>eRxc~ckfdLv);kI; zTbM(&v}m!jUiOIPIw)XT;0xy3#PxrSaNDBkIRoJ9)S>?u-VcRFE~b0VKV2rYL^t8A zcNHb at Mw!ueH+V~|Ht-|~0Aa#Qi9nsvKC7Et1<0R)^~_gaHZ>%jAQ~eF}9v z=9$K`2~9Rs^*XB~G?YUC2AvZw{@i19YZe~DmQi1GG+YK at mFzQ^V-U?bBZ*%W<&TL_ zW|zs2rLE(C)iTAdXHy)$+^!==giNeReF##w!HKxEn=a_I*+V0m4xGps6yYqkc8{e7 zU~NWVH>A3`L8u$imY^sT5%Ai;IzWMS8IUh+Wgs`bs~G|HxW*He)c!9UGTS5A?Fo at 5 zta*}b-n9a|`|%G!ct`Tv_w&A1H*Zi>7P2g7Q!aC|q}((x7 at MGJ_4A)~>M;E0sqtXc zFRyMjK=g2>|Hi&2Tu|F3;_-O3dG!2q?o));tRU1 at 8pYcI8BPdm>X<#Z$o+v;O{a?z z2IUVd1dm^Q({cGrsep(#x3BJDe1mbC9}H1o*s|!z-)o+c at M5TLsp_!!BB)4>moAip z=JZCDOd9({ z1{ud<5pOc{I|E5G6DLc{+-eP!ky#>pYVUjP{Ou)9nW*L86JKCV<+M{Wy05$%pKVmZ3|uj z$an$Q*aZ3_@*bY4CA9qS4!h=rLi}53aD}ZmQr{Ym>!DWKm#^; zGNz0xD4csPcxF6;A-fVj_QqBTtz`o_*!7j?GdX><|L;Bz7U_0k0nNrRR1TU9H`Y&z zMz6{_njz~NhTUP$%nNf$HX3Tfe@;~CW^C+?BK{RQ^RY#+E_eC)G}Z}CK_^O3ax8h`6i#nY%CdZ!Vi at C^8`NsTER4^@O z3TOnr$zW7*n`4A0ntJa at aK=LK#~hTfG8h_RO7tRF#E8g4WhA8LLLkj zZ1Qg8xl;jAXP3fVVuGWU7<$stS5n2|>zOhV$rJ-5Acv&w001BWNklGkR$+%hio5B=g-h}`i!a^sr| z?hFqbat^;mII#qa&qn<(c1FHSZ29S}#j at yT3(xhsI&}v6V9U}K5{SGs4=m?dA-PT= zIz7X$w>MBhTWBjT>Z{VU>yu{^Kg7z0iz~6dZ`9?1Kdul)M>^Gcsoy^_LW>nmhDW}< zGbwy6qeNA4*{#=uLXWv|%|I_GL9_y?mpi{H2JDoHLQ77VX&)^iEUHOw#R{=MKFHa4 z7!#Drt*lgGpqokr#anYSR at kG0PTjj${A*l*jFHILrrUrj>;>(hIU^KxHOyt3#R+Yy z1gGaSyoehHf;=z19mvdKnaFBYUKM~0L*W^WMCSqCc4QrWStBF*9kA!YqoOmLK!56= za~S9ZJ)wUDjb;OgP6Id|9LdmU?RsCHbi3vtV+aNZVsXYs0PbTlbZr<9XojZJ()Z!{ zh_o!*?Y2sz0=}U+>-geZI43rBebMp!9V!fF=<6zZUmkV98Ua-Cg{3W50q at Lu{mcw{ zu;?kNTa at W^Rl7181m5gHWRoqN#Sc2#;(MUFD|btujJ>hEtlRUGHQe9D%~&4n#pf;% zqQ)SFK>?R;O&zjj=zH{4O#6^U)urYWlnT{^+9nZG1iQM zK-v4Ofek2-pDP23j at 4O_OJXAQczha^OLe4NZDj*|VDh}vV?)GBJs9@*(=kPVOpWM% z<|hs;`vn|9r|z?bMsr1?;Y9B)Jf4Olo)@`2p&F#rAW?BS782jko9W%@f$Pkl2R&0U z23|wF*jO;4=XVb*{^zX!M&eh_h$fu~drxZ)9jzZFao&QMQ zlYAkayocLx!lS{aF|TJQXiollo8qSPkqsB!a%|^LhU_y0_l9EW0z`KavsiM=YW$wB z0qX;1S}G77ik|R|a^MoObF{}~0)PA&L=f9O}NZ&}gC zwno+%$^oy%~wal<K!0Q2T4%;lzlK=QT(am*N7iW#jGD)|pRxiDVjPHEm6Q*3Kl!f5{H_uB z_sNb%%2~|Y=g`{-E)t4*262Y^tP%PCRtmXW-``C_!%@|C=}Qt^a~5PyfebDKr>6%t z$Hc1u;7AuR0?x#EK=t4%ROt5r*KLC0AI^?PdMv`fm#5B)#-))o)khqo?V+!VtU+w|`Rv-P#j*N6rxwl}FkwEY$PEnYOFN$4vh2f!7`sRjC}y z7d)H|liznKozI1mENyViU`(x;CUP;mveVt?;<{EnhWoa9dYjhMu@#-z-oX)B3x?rs z8U`U`?=y$i7rkRUD%K8lnvQCxpYgPT&@Oljln>bhZ=$0QnIq}-Rz&Fob5I;r((ilx z0e*qe(HRR2*pJMH7kYp_^Uv{&y!0|F#t3+7!g+g~+4u6<6!ke at o}`}3vlk= z=Td2`emUuuP7#P<^=8InzF}`OlL(U>-T at JIW zb2jQ_s6#lKXk0mj8dCh8Re&RxXT_wSa`M~m`Lw?%W((J%Em_a|O=Inus5A%ak}>g> z?-{E0jE>5C2Q7xNWmL>Ma*ZeSd5j3`=0^Qzl%k9<3Y!BEx#`|M2~lVem`vMlxOpKS zY&D%{Izy5nF|e zvyWyVIfE}kCADS-sGq|B{@qW-+R4LVJBK=PC8{99YYEDW;s-C)=8xMHmZ{z!)J?=M z!YyMtnc9CO-)j{gtX_2leuZ=8N4Wjor)szGp^8}B_Ka#66o_aokpb~%dOSiZ7RC?4 zD%Y4)E5}3398w{PLJTBBKYQ36L~WNCA>;_E2GT6Tyx19%1LrP`&P(6oxqrQW;R_Y? zd}b*9(Al3GKE%9+;iAsE#_ph{Z-%B<%LYS@))$Tiz~(SJ@*9m1wV&fRr_;h|JMSLS z+~I8kbPZ=cw7o~1xVCd>N at QjA*yhprBFvfVIOG`?19Fz+TO|i)XC1E>C(uU1WPn(8Y<@19 z2`z3LR`U<6$;acWb`~Ko#IOIIiB9?mY$gzEfmjdISsB5IsV<9dnqty)O4h4kaTqB99lcWFU}(XfWBDaxG&NypAv zx_%0~ZIO9~eUvjbl at KIRInyT?xAFsaW)DWjk!DD;>ex7)+eSr%9JedsLi-blU~8Bt zRaqXW0|vD8WBeQTm`F!38ytEkq*!M!o+}oOqmj)>0g)j?{D>=>Ll at L zEDav95QRxG;W~9ghFI07=t6Mr5Xe{H-BA_j_wpT_=O7akcrrH0ojZ)($5mOn;Q^S{i^QFy>dPFy#B5*q&hH^MW*k9Z0 zyVQOd0~aO+i+IjZf~mxLIr&8tWRU|b0ujV%M>9eLn7W200xs}FAbk)0i1 at fi$2cyq zm)AjQI4n)e)0&x~mywq*;noK_uPmfOZWsc0N`R+#@18Rpt%h*mw1&8m8`n&Hbg>Rz zw at 3>PH<{xw7m?a?py&joh2^KEX;!$MZ~AMr5raepqq>VXUn(e*fZX13owlnJmi~7# zHz_uak*J$>6vqL0rc at zWMc7i(Zc+Xju(YqTt+*mjLyDS66LrTaL_ZOQ;xy3&<^=J; zpFjCZvo5gyq`3qwv;xC*+p+^uM2L%%7G~>OG|9C4&z~n>R6b{Yx at r+;hb5YD)U(pv z&nLC8l*cRzj5v&MC`Lwfj8Zj;<2jQ|ZGiRe=ET4YI(Pmb&oKO=d at KHtDJ-XbHH;zG zyK`%c#sKav)z$7q7_BpL^_NwV`MP~38xOPR^`3n}ORTdxe}X?gU(AE1 z?HP3899=0(8v^~U_-o=u4S8w%z<5qrQPYvO{87M&!_fye{DB;lFwG!y%;iDp)I>)j zoDXdv0UcHIbQ_MEvyu3-z#8U|hNdqE84kUek#|{r`W!Ho zjL)HP!&Q%XW;k`|cepPZt|o_9FW4Xa9GF80ZU?5xGuR=8C)+CeAmBJ4UliAi5(lb- zvoTXSFLI4x6pam2if387e)FZP&&p%@p7G+~iQ3ng7fA||IL;d$)4EVGm4!aRmFo{N)X3gp`7o3E^bo}Onsn8L?#+b2Oqy>RHE$c8c?&S at v#7mf}o`$b0Z@%%Be`Vcp-_;0&b~{q2n&TIeLX z?LslV%$YS?YUwxO>2$jt+V*?^M z^T at v3E=OfpG{bHgXfX$)in&x{K6yhT54fJ%GbZda2fyb4htPC*G?3Klqc8xF13AYS zF~8`L41ryUiXJ+IheaRWYQ`??oC$*k2aFdQCoZ&`dnah~L(TTnpi=F0X1Vz4(S8D9 z1^WDQuh4^Z-s!mKURJ#nMsgL$fMzlw?uj$%4yOz9V6OW_aCprA+NF64I$8Ai?~(V~ zy+;hog#*JAJk2m5Kt$8am5cl+Br^_lFn?%^)BvV`2O$>|LxK at TBy@`M6G{gsq{(%{(SDN3^m#gZ4Z7c)_TxZ61&3){W~Fu*b3l+jjgjTQMrM zt`63ez-SXbp<4}MoT;S|-s8P4^RL3CQOM^G;~%HmX*8`;sqdUXDHbQ^B>TQ!)@!Jc zc;|7YLZYhB0^|fj2WOyny z6By&7ji~xiSHlFoT(!iP$qi!7??Lvl?02r(F$01{kko;OIDA5hfgaop0Ef4};HZJg z_aa^|nolU-m$9b$qjYu|-ko9T^UHsR4TQVa3`&r9uN5Y&zn}9v#R&xJcy-*SO#Whb z1Lk6wW?ou{5)rkWr}CVT-t|h15ZONbz|-ZY{08Q4 at bTe_V-d4eiL5~w=RW1LsP&zz zX-FGATIO34!rD(*1jd?vh%ZL#oLHnsRookgBT+lw^79AX7|0)aEEo3e&nE4idVa>t zY)wt-_jj*mjR;59`om$0vr9XSi at rnAh7F3=3}<9|{$1I9&1(GO2P0}}NK0tT$d(@P zf-#g7iy;pf#=D|zNJtf(*j;T!-107GHXB$ydQZ`=p4b!anr=D ziNZS*m&;FoSGaNbls&6+)#L^wOl;vf=jQ;Wfm&x8ER0nhQyd6T*xZ$h z^YqruCLHJq(BP4w-)9$ z!%tU{8U>!9+dmq5r?sX9-cJ(E$NCrmx-cIn+*v3Mh`q=-lVUf81pR>N#G+EIoiD#j z;%Ner#i`_oaY3`XbWd!I=UZ;wO&?++{-P%&hr7*9C5{Gj6ei_!&(rc{(I}bjER`jf zy!_v1Z}xeXqm`?3OWgZSMdKRQT06(_sy|%lqF^Bd_D}zL(oKJ6+1P=4uh-RCl!v1o(ry+wV^A&VJiro%HkBDwoYccp7yL7qc$OfJ|El252t+>dk5|10G$0hi zaKOZxGN(h#0;W$B{m`fZTAp&+#0U|Jaxo&IcR_6-3dJtkVm)+J%J8(^kP at uhs2(l} z{H$QqrnW^)eTE?cjxN2V)$?MHr}1-scO<;U7SKaYsnH%dmD$0}jSRuEC+DajKAhRJ zjtjLJl at 2nSId0-Aei14*q~ZephcQM&t+OW>T<*Th1u^S)dhpY^7J&jYa at x=istaz> zu320V4W3caBs(aF29mNsC_Uz*ydOxGn#nDi=D81*4SDl1HSP-uR>pgSF%)_WgN2k|-09}n zeuv`GqC#&#vVw&?f8dpPdIl+)TS$BH=$;?4kYisz2c4XQ34IYfCKBQt*AgELUMN0O z22PfS5px{OKReQ6FXo at MTn`qYntd~wFnt9GoTM`)pHJea#P{XW%|l8ydVCb*q=Iv{ z3dhebna<|QaKWkl`q{YfH9Mdqj{nw5lz!vMYKt$PXJ;4k_^?1&k-bq!<7IjNGmL3h z>z7nRakKd=I)w?It6)xY`gjRYM!;mx1+r?+hI@@M{I%rFcbTPQduIDOh^aMYD}7o` zKW%?MYLYwf=XJR*Cp at jy(q~2UDFX;GJ}(Y-Y&f+HeLOG_gHC3 ztuM_%!LrJ_Sl(M0v=t<1T@(L{{_<>NS{{bbi(08xdxU7A=B2?Kk__n1Dahi9yi<%4 zIg0#(7?OYorHP!ix7%B(x2%O>B3Lk*F8 at 0+q(6b7zn2|9eeTIdpb?7i$|t@?21{$; zxx^G%^!q6 at o<@%7wT}LN5>Z69gp^D^;%CT-(g0lv_oDiiHRJc(s<}TmgQWorxMs%q z5QnktW(G?l!*OPEke^xsmM(PmS+tTD9|;H$eO`hcxku(W(ewjO#A2}*iO>LmLx at p_23kJJOr^fP%s``R!Q!N at kdn66Hz2*{t!V&8BI+S9Z>d())4XDF at R$MTEf zGxkk>!yAxgkQOj&TyMrq#AA=psj$$}N&~E|joQYZHS9_Kq5*#q^I(~gWy8vBlahqD z24)r-c|0G`5H_4aPgnGy%-2NwrZrHrt5_&z)NP!Xx^!{dUg$t|1sER9NkzyPd!lX? zOb@;*&nH%P*x})!!}I@#65#)s!gtgY(sk_2SU5ztqr7xKhM8*#6X}f{T)uJm;$dHD zj0dm*31YCox7 at QEO(2 at JHE@jr1xMBnL=#axZ{Tr6irAAHTzr4tg)G7r_jOiz2NS;X zf?YUZI0qiw>o#6xl-WF=`J=I0RB+q=U`{Doh`HZOAS`zk>v4dcM+Q2K|Mz?lGJG4j z+I at -bW72!KX6RQA%AxLy{ggcnOLAVjB!pklxG1;)g+A~}ShY2m|LPKGMsS+%W}nd_z~7JQO5OB4 zJ at hAM&j z&N|UDE=3Voi9X;&53JwAo1Vvaf&ORca{2dBlVKPg&v^``drx~8y+^t0EpsdEh?aye zjwQ2uwYV<@rrA=nz+NO^nVdzx)|RNqfZGC3E<|?3-OhI5OMo=59L8u at mY3zSB_^Mi zBOfJhrBRe;Suws1y0`Ue#K}Rc?dMp zaS~b&aWg~+r7Z#LXk=|agZ((bOCL3YT8E&1J@`0?tJe4uQ>foNTF at l;5_j}{4#l;^ zg2)QKwUKbA^Qi&Ju;u4a!VEafG at LUYI1fYQ5Ch@J*yo5L?f;)~E6x5vlP(!?59bnT zCJaaU6of)q9VkTilz$!#lb$xUn0 at rO3T|sNwursjoAtumVvcwX`0jRxpiCAIu at 3k= zCQ-eMqy|jW9?ARI158v4$LUd*QQt z;j`Jd at M}66cn0|WJ;E&byc;D;iR;svwpIs}KW_yzdj=_7oPC_Z`-own5c{)nq-KW- z*9d&uRndZd&sXNrH#_o&nxqdEVnYVAI~ad~#Tp#UCz|Un#eskd>lCJBk*5UV|qk0aI8XYbJ>S at 94)=6^I9;a^L4< zWXQ2djYr6)3{E}_j0Gcm->&`{Xds7N!l}uAEh`^diuGsJ0D0bpJ+K^Hbe+L8UCGb{ zi9s=)3UD1A2&-#J6{l>l+ zJd|G)?bg;oot(C!REKd`bWlfleGhL`379xXSq3+#dlH8Hqz)u|A-_us55xHxdAX?) z`~3fKc(Ow6h|unn^XN#bw^pFk%vsM{qImp6khuqjj1D1KP$38zgU2)E-~D!Ba(%8h zZ!3)wT+|0k{xa5t$}-`@ePSCe!7>?%>SQ#AL>2%E0udA82hSSDG>m at dw%^DUygkR2~zxpld}r7tyy+gmV`B8vDTZEcwTCqkX;(?M!ail)CCn z`M?{s|F%gE+7GsO21 at oKhXyUCDKuks%JPiV_aD at _AhZ=B`8ICsAbc8;s!=EqOb?9= zG&FfHL=5%bObPv#xFt>tYDSY<`FA}}+pHAGp&*25b#16Q1m$!%?KcN7$7e3czUAKi z(Pnr*rnpEaHESl+y$`jioF&61`?qLC>_NE+hF)0hK`8*=Hy zU9eHI6|uCN`ZF<4y;b+L!)Kus>w4Dd;k)SJttwyMA}Ykuy){pvG}yY^_AET&ez*a? z{T{Gg6Teib4bF~!J%A)lS-?vl(U1&i=pyfwiy$_4ATl4uQI;!cEY}b9b-yznBvNN) zWI$5`&}~lHEj^kdfD0A?Aqg66mTL_g001BWNkl=IwcJ;fCdZWYe~ zQlEVHKJQGzTT}qUEO&?vjs`HOAN*?L)&K*X3ZPbjt06fuPK^L_K0% z?7LZDv|b8&G5cF2;~!b6Z7y_3E-c(~c1CZpLgJp?hZmyj$gAx(G$_91=RqPxC|Z$t z=*W;S?n5#=JW-+U*R56C$D zClag$C0ez1FD$fQn{P_qbJT8~ndM=-gPTq866eyB6EO5u|EaO~2e%M*K zGIJn;(2ZK+u1+itwx}*-+?P_= z`|ZyPR$e4v6-up4x38i_Cj|L;RN} zqZlomMIkZDazCaG92-?N(>7GKF at UNjkyQqThdcUb!{kCg{D;DCu!j9hS~fF5_OG&P zG-OO%o_jr0cNgS9L|(kor3Iy|)>c0y^fq)IYoL>heK}0R at QT9qK6EQz&0f4AjWxAP zhY^6RKhwzWGIfaG2Z#`>oY3Q3$Y|zeo6N3d%^?IWlgXlpLL206RCD9WIt<2=krCaf zwNpFlgYEN|IgTy@{0(IOB8o6CR|Xz1I+*$oGUH|F)A3t9VMw0}Y_ckjR{zbA7{_tm z%up at Jb?MzASA!G{Sq=$$fD^UpsHp;w3A;{a=L1cA!eD#m)g1siW&u< zqy2xr0_0BI!~A<4+(?75D<4rD6m87(2Mqy(;2#3Wpg;CjTj&&Ol6w|RFHCT6$}0m& z?j&!FkOcmvuVW_8qdbr at Yy#2dg-yX7T?S6DE{av3=Js=x-iPLvLM_hKVNnZVT3>C8 z*}&Rn5N?gd(F3AJ`P*Luq#}Ar>fJp9LC132#Z^Z*TKH zacryFVfS}t#9A_2iWi0tCZKDCOB8PT2gwJ$|4C-HiACJGs;ug=gozIB!-#Ov_hygY z!x$dF7p>Cppf_Z?M{PkT_j~ea5ZL*EoBi1{r?)>CEPI^LD2`74PiFKkCgbuP3T6Gb zY?V^ynGm@>RLJOQmnmqCDs8lYw2OeXG)cZgeD`OGVBQ&dG+iZv^6uI#aPGbl?il8oNL9^B*VFe)`O8eDs5xEbm{wB7twHs{tfg26jCA(aUWSKA5 z*RbeYt9vU9h4**vkhSCdHj3#Hd#?1L*KdA}6=Xp;5E?NeKY(3S*#>?#IRN5#TR&q{ zZ$jQXukAgb6t_w2p9BNgJ><;r5E=_^b7nic!ne!mk|_GfJ|;AzMzj>UgCAY%mzyc* zuxhPWOVpY5*&~WfuPLBG`9VfnNrS)x-%+Fly%~Q~yHK at X9g@a5nbDzd-_alh#5wh<7 z%m2s!@N*!RVq2%7Q8N}9ruj1jh}1ztjrkn(^Z>?daeR6?8`b4k9j0mpSYk(MU)3Iv z{Ss+9MjPDzTc7)Qx3VCKIA_4F69k`v2r&$+Ou?$ z#EtoCLA%`l{yHx)YJfP6A@*n22!;5MB?P49_Pv0rjX)EJZMrn`QhIsX+Ur4F8hCox zJSpumg1&zL^?xhsO5jGFz=W9s9y-d>*-IMGgFm8IXnU5WShM3GwgU^5Z(w~DeOXA7$`7P?-3tlKOnyD2!x;%^onPYAGY`6o8D$5eRLKumZ<8fTMYnj>LS!EJi5wTi0HW9=4B3X`86R%I(W)-bPgFl!xddgIY zN!1WFoB_90Xeu4|y~kHpfX|UnhA9e|a3hw!k9E+Yl25T9nBEO9A)_yc4~&>bmZ_#K zkuxr5EquuLr5k}x7}|?up5%As`Wnq?w`i3Km7MYvKx|VNW{h()2ce9!G#Dn^#8E{PjKa565_?IU28R8JFz_oB zZ{>vC!MQV at k3ogrel|2TIEF%f z*@gNr;}Y?RR@)^j5}u{{P(}vo68DyFx{X$82r$pH2&ZC;9TJAje9t_ce}fORSpB)U zh9D5Vto878Di#Z-^HS){bz#ciZ*Vs8lKJ2dI){-BW}R8%;is_4et*wLBv07$ zmzpvzL at cxPM^POjPnQzOB>%*6E7fjNY(1hzQEb_#Hqn at 4CUxw!9xJ~N=~6q$n#f+D zsNIuJWiH;g*+Q3=p;o>{Ef}a(e0=cW)G2Kd`qImM9MD$Y5x%W#o*DIKCZ%sEqmE5Ce}y%QokvU ziIflo6tNe at Y{hsvw|$_}zq`GmX%L%0@)D6V)oG1(>G&XOi%*i*y)D^q$RBNRzkf+fBf_QMiOW&7SZ8&I%YPWRyJqO}G;mKh4wf{BYcLDPR^~Ad9mlnsY z$idoqM=eK%yrUZ>XR_0?+2nm1_=3Bcc}d#`(b!zc2DDB%l7CL3&}m8X#4bXDNbhCU zYci-kR&;@PW4EoY4K-xtR3+joC|H(k=t+uI#P8cdVaW5V`bssI8x=(o6`_BdkU${F za|;Wl(RJP-T80D>g`-d=tIHEhsE^3if_@*gBg>@(V`1VeFHi>#r_yuz(f4~%*F=iJ z;>ccd&^w>%+O8_%Kl!D at TmRK@cUkj#~*;?0h z6OV!Q@&s6lu=tQU`1JShBI#WYLyxl20L12lvJI4%IC2Bk1t^`!ydj{hTd}_|OyqN8K3fkWi|?HZ zm`aIGH_h8M; zPJ(pua)3%lxQ4E*+%6v|Mx39o3+^nvEZ)Zzv$LsLId>lME5ri4l|4 zuzWgVZG(XI66-mPGgu=vodSWeE^bNvYWf8kc at +wBvki~XeUB at 9Z--w4^*M=odr1!* zY2zB?J33b)fow_99I0Cv5xJSmbV)JaUPr-(2ZOl!++AjC`yTJBLS z3~D&JEsv+^xqcFZ9pm=K-T44dy4Xkiiy@~5=4We4?n{G`mOuJ3`=#i4%cdiFu|Bu3 zd~Hm2c~m2xGvzcMFAj1%{{W{pF*GXBl>w07Uj{$q7xz`9?HI^QJMg^x{?Q@?LOmon zt!U*lXSwlf>-Jc~00U9ei!8-3Zs1YH0+r2MLnw>DnubIX{b{m0 at _x=#_&fzo1p%Qy z?`C&D1|H7 at VrJ)-Xd=zMG(k5KNez?AelE>@$LgKyFJM%Y&5Z~l#sdw1zuQ=!E;_(Qs46r|L9PIhb32VcbZ9myc!WwDjz$cdN@ zKaI}BCIq0*4my1BO8KZg+FTfvXeu+`Q}wg^!ZyN>&~EPXePn(&Rs at S>T?Qp at 76W&X z%c7d%rTx>wqKRDHPb$bjlM%3>ax8>w)Lf>YetMHM=5Hc76~W%c@$PouXbVS4${%(0 zX7Cm)LJV$oDXwAX8`7M*|J)xPHazy7k{*wp(7g_~NHZtx&n)_ct+B!%aTn8jHZ|mu z*6Oe>XFxP)Gi6??8C42>5|ECJ&>!KwIbUOeG5y3!fC3 at +lGOwYP&~3t(KY_UIapoZ5W<&Z8w7m|54Z+jl zglWE-CD}52eAN58JtR`^=>qfb@&*yFCAFu4n8P%bz^Ei9J*F zxU}bztCkQCWe$tG_N;59tOI&$Q*$Jl&!>cJV`~7ta&Tvf@@Yr{EDqLO6F{jo`;P76 z$Q7I+C_SZRxRI!RiIo?D5zM at 3TO+Kpb%-*P3c!G7N=y1&kD$e4qv_XhV#4P6KJUB7 zX-QptAZI_+?`P_z7W&;OU=*ypEseNUacjWck|l5gOc1FIOr!mwcI0ZmVw{)LX6ij8 zp|c5aP=+bXXhW(CzG$eMi at ES<`{o}Sy^#su){2f4d9iA=8|~6?$oo zr`P}F&kJc@&_N3QciZ|nxEWX-p4j>n(?8)QVcX)`osC6933fgd*zuL!Ke>afnYnS? zF3v|%($%iXk#o0h>Y^_^*`BRG!3YwA;)kX+C`kSY1YLhrmu5TxAQ4B`U7Ry2{Q2d`t`36} zFv}GfwB(p?tmIvhN|9JnZXmfdDF#`tg-vJ^pasm;QwnhB`D0;15 zXcejZ=fj0X_Mu7&Bn&50s^89+8iw4Cb=YX;4OEPq!*AqP&1j)yl2YPf&GUTTk?))@ zO!Chl)(Je`M-^XTJpATg4xqP2U_yg;i=`nnAA=S`J*@PHXvmR+n#eYTwY_2?0{PPx zilmxHruW)fP$j2tH6NWsc^9c at z^M~+XV?gb--av-PQL}f`$SQJ68Jb!q(zMdDTHca zDs94C4 at pxic=W}dV^NH_`ao|@mWYMvFKF+Jy%8*94UOAfhZtn!AX^_8EfZnu(k$1w zTq}77N}br=;h?l{HRr*8;4?73-GObL6 at 4AuoYC(Re-`R%Gd%C+HjQYwIV0L5jya~1 zW~RxT5uLgfWpIJ^(oVut2T&RqBqvDS6xsYq5%l{rGT_Q=~XQ3c#Z%{jlyy$S}Q2vK24EKuB#fp&Ae`mGvCV|*XKW_k zm)I!_PKpw){qMi|+4O-AMmNUeUOXo~9t*)M7k`=$5H#U!_1HQAuE8MDJnX|CJ#U-_ z^IZc0stAqJ8;LyCh(D6!H#>aMI(LzxtXWOOEBS+RD`Ls}_E2Od5z5lM&JZrjMPEG7 zw(CEdIeaP+;c^N8mPj0<@@4#}9ZbkPv8Q&EI%N7zBw1;GnVN{7N+l0q+ZjgNjtaH& z$U}U(F_z#TO}()vleLZOIuElO?7-Q2NlqSd~s)Q07a+ z`1h<+BT%?lK@} zsfvXnsNV70^?!YqB++z>M;UQ-9KgLWg;!SMc at N>F4OWFE96PBcplR-~xf3f_Dq zAV71^K$oOl4=K5bkT7T%Dz)bWl$tbHbj_KsJ1%1c_$RcBkc?PP$PQ8-7`Y5wHCmJ7J`o(_}(N4AEB5`6#o8?p|i=&r1j)e%A`wD^b1kYZD_}7;i at Lk)Cpn#UcFLqe=#ct ziY7GPq3k6mHaCsmg#|M#X$rLu{78GuPW+w8s~Z>A11Tzksen|`dcj!J6zowbWtQl& zSqLCg?ywP|6)$t1Glb>6Afb9acxB{WV11OqH2*6enSc`m98B4#gXtd$x-l&2$vvUD zn@|x_^8a9&1vxmv&Xwi}_PfIeLUj}eJx&Cv%}7SoKmBLo%cBf*6ZzUVcr!Qetjyf; zDUzjQF(EuoUIY!4(;HN13)?81{zbkpA6-Lh&-BX_qrVj8^0iTqW8k)JcjZEiSvO)e zaEEQQ4ZBM!t|qZnU*FFT#eHn4CzkzqwIDk(L&Ws+2-!pdCn>#5zn4PNR(u_noCiEV zMmg~mv%e5nSS}v_;7-X!>B+;r4k|~Ls4sm=75E2JM3W3C`lqidQb_JW?(2Iy=z2UV zB{)6kW9?5+dZxG9$TAa15(T~0=nPbSRuHmCya2pQKx{ea+tYqN&(*-Icl?IAeaUj3 z-89n9F|IwE$pIz~*5YL6KAyPx1`I`P&pmxXS*;^Ju-5M2iEd*3?j|mL$(AhIY}KKm zy3Bb77%qgDqSJoqaJBvhC)}Lg(6AOPmIf6pv`!u4-9YCpF0;Xmh{sxuM}Eh$Fd!&K zlru1MFkY5`i2eZ)HDx>CT=*DoN1~$Lpy}|r>ku>V5jOO-H3OmAgN$)GGCpE>W-kTI zCZ~ebx#c2h;W6Hb#z=9RKn7KH=rPvYCZj>;aq}Um6o$5MApw_Jb1kf{bm>JJ}n|En=OAmA}H|p?bR?pZ{83 zilU+OAnQjDYXIUQn!*YM#Hn_x(>!AwVuLa+8x7-R>z(mr?8CL>E& z|0pMvU9+LI*5&IiLzhl~cK`q&07*naR76!B`XRrEeb@#@t^A7b3k5df^n(XQyTlSm zOQYN+_Jk+HliPvp(Koy1t(EktrbA(l2Tj;F<&7*bGd~~shWjOl{TZRLk|jwc0-jeK z`c6K6UNFsbOnsg_ujR0oqjrIWFfD};J|*@*5Nwo15o2h~9>i&qoj*`%7`?{i7AW+r zIk^{73^+YR8Mw7c6j3Rd@({yTYZGx zUgEThZ$J2JVCR$PG5XdHm6Op|XiBtywhLa;v)Zs-*1-+tc}gb`^6cBw5RGu_y*Lzq`I z#CMP}D~xT$nmF2d=?M^`xM(z8xHUiOqaioY{f$LZm2PQ|&}Mg)m3kwx=$4|+Eh8C@ zpnQc#qrI4st!1f;L}(>G6s$S8f`MTrCj~UrsP-z85DzpG^ zx7jFF_K|X-MXZ+mMM8Z3vVnY0KTI+v#>s(1h3y+;8w?NoeN)7>$(TQ{GM)N z0g}CF=RsK#=q9tJ2c#z&cvI2nxsGxDa%S5?amqhZ`LhY#g_^f&l3S6xc3MQeg2kx}f`R at njT{iiLSyO9p}AUU&V#e{ zdrtE?Qih4lxQ`kl?A0zQ{z}KJh#wT854n&`D%lato2JLl1HnA$Fl82!CK{7NfW?cq zgxep=LN=Qj)KK28A z=*7kyknwI7@%|Uz^17f~^qYJJz5p{2GFLg06yf;(Lw9ANM(yO{sJ+WrAMr-}+d|;~ zk2N5Q(`BabD2lcr-|Ep(ab~S{> z_Z0S`CIXbmC9L5X-Z=;kusSY)+OSG9AF&Q=?wxIjom0lFUDmAQ86WoussIZzgl?T3 zg^YEIpFuwNY#uyE$NUah5*a;fkO4fQ3cXya#!-a$M}Y9H1+v~pN=?p;J+nfei5rv< za|W%y6q8}^puOZU;R`){R6A_>aFBT+`t0p>*Eu~xi>K(}WTTyHmq&rdU)6J_R=Uj< zfL~)bgcs`C_w8DAN}Gbgl&U`11+~-%yYkQW=zPNQoc!3(5OWj44l|ZO+6 at 7yNC6g5 z-66j%vhTb4O10-Lb|)2F?+nO#6`7Uh$CYSvAq)w@`h0LM*G=hdhjYBDq5DIjs6*pY z^2o*o`b_N>=A~g8Lpkl|iks}WV$8Q^ln1J~?5{L{5*Dvy$R9cXbso5Z>2y7m=sGoa zDTh!Wq0PC!-z$`VUtHl-JU&D zQ;Ihk`i%Xd2;9oY#_*uf%P9`nK68pjP=!LNaMUPl{Kmj6NeZn?5)OYsr+h>Jveq{f zleYjgR^la at j{m(iDotC2g6^>=oP(5Y-{fRD5V1I7XQG2xP$hb9VIq^XCX5pxjeW4D zyA`bO?$x(2!y@;u6(i9p~s8mmJRRE^~hUnUji zKieDnq#0mvj7M$Zau>Yp^t&YIQDf;jczY33`NKjlM(@a at iSl?5lONwk9aOP5iqRmv z51~8U1SD3xlp$XHYdW=-5GZBJkRE6c_t%sB*J=Btu^lZUyIzT!>lxXg5pN2ke-~*; zr4QS{tcwi{UAEDQ%QRBtoI-7We?PP-ghqP`o=6Qc+#T at nOdy!iFfwOQPkzaTbjiY*0aOwcFT#15YO$eJ%w^V)^W~MTMIJo)Zb6lq^vqH$F53%vL at +*SvzU zpm0J={|}vmB3O#1RPm!9!eBwA`0GvLt? z2|;*wuvUnf=g_|c>B7ArKvyXb)LJs8vtWTeTStxs(oWblpZ>XoB~>YBr2!yj=- zsy^b6|0x`N0t-3N_hzs?57Fc6F$TXBpqRNMaghhIt zff9N)uVtl{7gz}d4O_bkpp_f=Fwe78QgZyCN8Cz}KeK at tl;dSLiQSZchM zTr{@*S_c at 1QNrFY>q2NOG~#ocIt_&K8TrHCnqnG_#s`#xu`pj=T8&oUfLQuczqc2{ zlhX$ZrABt$R7VtPivyPC3qh;)XZ`nr18lItMSE--YG at a=rhA<+h at RJJrnAvPE8Wtd z>0LW8^$!V at XS&TssDU)mdHwAR`4QJ*s?{`uktK at ZcagyRIVF-{ofr%$|J-StfHFS! zcb>Ye2afZdm8Plk;CX-%k)#rW(Pd|+PV9@{%oRt?II%lJg0+1#x{DbA>kOWE@|_^9$>txZ3}m?1Efc3|3>wx zwkX5tKxnV9FbNa{z5Py^@t+b8*d3bEkbM*3R3$dO813M`bYRkr7okc^H43lygc-1poIH9_$;- zo at g0xyu;)D`>Sm8iP7afDQ)V~T3zb(0459whuHf%a_}Q0%q5xJ~Hfa&RjS4GU zjI4mvhRowbkX8emoI`Az;*F~}iDU842R7)xLp^POwQ+{U=?? zMq<~Tb!b!LFNBU$iAe+j$7efbfEzKBNVS<$QQP&)^4qao3mZ`ZRvSn=9Q^b2h!1N+ zCoK>=hgfd(&@#Rh`a+nXabvAj3x(t!2uQH4P_0+ZFw$d;x^`~|Wu$9bxU>7VzGKgx*FL+5e@(Ls}lWq2dl zQ-31D=Z5%!UGd|R8qaFn6>+MoMC!pD!BIoCJ_{Zyyq8qVLp*XH(gk9_F8owpC)dbp0^&2VW!ufOFquvky%jiGPZjNR`UNLcWL~kR1Y0_wJ*(8f~ z_;TtOp<>kdF~rX at ku<2QAFOu+oydjTSlHPKgKyMo(wx+&_X-W^TumU|ivpoR{uo|t zOKx<)VWll1-1DEc#6F`SIx6}j)FLhJ zG$5404l`~!j{5QPQCxiuO#EZ6J8d8Vha;S!r?>+w)vSz7xaY8=1gCz#2a5zEmjFOR zVl$h{is5$|`xc$Mt8%lW1gH4Ej8aV0LbZtKAs+r`G zK_t-oK`Lp;D at X8ipep*96+tYTIBj3^hY(`$L1`G!-_ at H6R%}U4C}ip1-im!lHkxZ{ zc8pPLfr0fyYjxfCJnV=EoQ-rh76^-65kD1-!xmH&y_g2fPKNF7*My#-sK=akh0^2& z*QJ}^Ril=c%W!AHMJ@=R* z=T=5%)QoO35Az(N=do(v?_~(GkAY>V49%b_^weA9q@!Voz>`0qc>4cFSKs*oLk>TN-8{FIBx}Yug$E0*5ZW>Fd1!GB2ITEtZjx_MdlGeXqV5?#I2Xt4(Dt}gWYHdE5B#zp|^(xq2U!c zq}S15OuiJbDNs}`f*w!R;nk4uqk;Q^+Dn`(@E6YDc!BB(fu6a!H}K+g)D*BT?cnLB zE*$bWL*be%_9_RjQ(rH at ZeD?PKTE*SIyY$MigW|HF7&=MCqMN+szC|%(DI_q`n#}D zdd at a%wFZ@%G~|FV6<2y{90yw(>7}9tp7Oe=yEX^#8QfNQ^cj{)Bp7MYWDYT7U(HKu zwGt0>gj??e5m|MpHVWJtO*YN+{l2iZ$m`zm at R`lbi^tSuLJv|q4Gb)(9IfRxUA}Lh zt>)obspGU@=_HK#RPQnJ_oj at z-ZFwh{!XBKh^$H!I-5b`PC)?kX`qqaUgNnbU_#To zWpkx&H(L`%`$6SEs*P^?Leq at dEORkZ`*$P!N+EL7Bfzv|v->2kFk5>Z4MFH)ky}&6 z(&Y=w8WM8`baaP6wN%CJ2?r@<84*C^MNDfcLE(5b#D-Pr&dGL^aEY(qQ-3eSY%^t8 zW{iaY{)V44Ky*lw1_8?JNkq<7xa2Au;f4`D4AWXuhW3IQWA6C?G at 6W~mxG=;rKlZ9 z=m+~TE-%cXzrU=!tc0S3sG!{yHMI2p-!ccGS>@*sy=0&@Co|^u`_iZYr5ek0S3*X~ z2;7qN6|BK}|88U?+f0UJ%{(eTSDXY-h8j at +KuOH6ljVx!k-*&}ap)nl=vm73qy>H7 zLvN~Jp`Sq$)Wbd#J-om&=%FBDv``Iv!|sSvFf~=z9Zc7&eSZd&4+C4bXCCJAzI*>8 zw)t$Pz1n9Vv*nJ at V&zU_HVFWKQ5Je2JE5g6WnqzK4jHTO(8e!t{2{(q$p`=ZJ=y1BCA7vNwuwmw}hATXF5>KaSj*|}+ocG{P`S-U0F*~GTn6RT% z8|_2Tv+h|vjaor5~|$U?5RpXk+7EGfGxC#dl@^QWTG$JX{a zY%So=d-y^%#$I=r!T1lRoA7dHr_K_{mT8PrQs`aV%TfYAc5Se}W#Ihr2=NM2w=;~e z+&Tk?YkpIScPX(NsZyWU#Fk|;3t3^Srsnj_z;>!E7XyK3eL&Ab@`K3f<#hZ(1Vb=` z$@;R6h`skhN<17D(H4ibQ#8EB2sE*lplgh^6l>Gou53y+4(to8>A=``#4R^xYT?=;Jwi5gA~ z>!cQ~8}>kD*5DQlu%@xw_+7ZWd+iukCUZ_5qS{w{twh zNaf at cHGKZOS47c-RxVw1y()j`g1$tNrYNd>=|nMtF>5&aW?{Hq+AXE{ocfSH`!;!J zL=J}eED%Kop(GdDyk|c&zU7yN0m7nZ*+(b5xt2h{JR#L<$ns`}P{wH at LG2{xJeH|K zi*j-vfvs7u5(E#5M!0_&3#tlxlD76iw<#MQpGuRy6riuI2z`>Qf z75qq!`mi$=VYMAf+Eqe*FdF239}qD$Z3_EGk)aFvS?J at LG!p^3U?n(!?IfZikJa=3}IZv?furGWIRRA9#mTVhLTGP9DiITbBsYVSBw!xMU znK*AAXAu14Nah+To!1)xPcwi-!rSwsNbKJliw|Xl?vty}x|z#RhB$GvpBR~Cwn0w? zDA1o$+|z?xvgy^%M4G&E6L`#YTpq&xEWC88h)Q=#iPFrP2tpVwK(17=NdOy|@d&M?DRYI&T)d*5$WW-op)%~6+ z5ef~RD0^l^wOE(&de(%Vh|c8>)?F>?D{m=(GS)g`^~jw!iR>_ at Az~O$ryr%*_dx=_ z)?yi$z9<{I{|OxTq{%^v#{h50%+~}HZdOmVVo?!DC!i4_pNT4?ysn=0`Cdcw30E@( z@#;;rv at j9=Q*}jt*|QAr5^sd4(3{pnZ0{iz?zyZB?OWj=Vdmuk1Yivq8*#+Q^z!Et z-abfbU->$tS=3{K*zKpE8L+G9mbDMr*@dR3fYFygLD>uBt_zqsHPqIt)%|!tU2$t! zF*8zEv-LKx;9Uu|ltIw)`~u1-B15QX9ZM%38XoQqco%y94miw+m(XmX$jM~W&(6a5 z2RC~&UFSd%T7>kr$GVz6w)v^*}`Mcw5JSW*vb?85%qXw#iKaF=L) zXTK2(0cOxAA^7^jyRBWo^Y}am4J)Mg!~?A^(erGvzWGIFz>$=pry$b?EMIN_L!I|g za-{_P%4RXiC&-0lSm at 7LJ$wMgNllNKOo{=DvMrcfNzj7Y+B9c<|{z%+fcK(nkaHrAyT7*m@?as7`^BegXhS&;*rU$SX3e6gBn%d%)JF^3}RKj zZ9OO}MUB#?GvSnNLm2Z;=lnsl`cv&KCq6FX5#^lTX++=)rnK2VutTGOr^J+Cdgj>q zb*OShHXRN{X0=>oT(scYzNqx2>=W!ms@&>SfEK@(E*=1jYJgynx`pPF#elD&rOnW$ zh{a@<7OxYVRiF13y+Vq>rw5%v>Gw-jG5RW5YN-93sy)0yc`f>dj}#~WPQJ&vW}0oy zQ}%D3pPX60#}lWJhy|e=?=W|@^Z72L0)7u;>EkTZl?0rAgDZQz_#Uc#5J?cl4>ZKU zoTJ at D$o6g{i)0V)Xr11 at tY7NOfS?F7UHiHPgiuXeE=?RYo>|=#=Amn&yvu}6Q7&@Dx=w(@-Z&rW| z!RfDe9!m>t1{pwe8tDR%73 at h&44{di{E_oMzMO3c0H+BH%n1t;NMNxzPQ_65N|bmj z+F7&)So&1WkU%JS(FbHCkG}5YrrpaAi(GObu-!lw#ey{&>QJNg3z^=>z!~{iho&HW z6g^%l{48ToqIo#YbL^^86ipq0f|*(spC}tkzOfDV9^!%;x#Q^wnIy+3THQ~Qa(7T|qWv}PE>&SFK{ZsW^R zgOI0=atab=kG1I1xP#znC~awdy3bY;kh2g(K9OVnyqtlSGY^#W43br+XK+3PvX5lw zerVa>aU^;RYR||3VadsMd>#wqQ4Z2xV z^SQTZ8!6^lY53N}usbpVJrs)$N-i&d?74>060EHYU)MAER(fvrirKP;BcYeGEh&m$sU2)|BTIzqG16>)xY)j74Axb at HM z-(z3g@=O~liJ}%j39zjW=C-%3{~NaUjIIeOVRx{B+^YBfeQs^EKtbQeJr5ELd*L$3 z;G4h~GM+_-5WVFNl29E75EK10l at X!u77*_-rd40ragP>6jT`T>GTuh+|CD!2_8ea$ zhp&aq5M%>VfxLt-N`Z^QnH=o2saWW+e8z!{qSh=rlFT-(fz`pO-NZ~}9(vtYeU>-n zk3$T+LqEL#dNDe z-Ey*8Ns%gTWVr8C_ITnEs7uzSJJ}3lWB1xKF at 4lvy2`Smh|yZL47cWsl>EFWf7LEE zjpu(R!vr!oy4AP9*1NT0(f=czqTjPX(~@pVnGiDn4jNh;?P-j$ZRzEpBrH&X=d;;U zeC>JI!SAe);vRP$`RKI3nB>l!t(zu<$q1Aj at ChC$3yq;ktm&@^IxURl=j7aIG%W{B zUsg;hgfeRDAb(>4)a=p}dNfoJ3E5n;1zoWBUgT>#C)5ys+G47`&+aJqY`k?iZ$|)@ zvl%`-QaX3tD1zS#HEtc?*Q#U{V15>AE0Z=Fd}uw$;sc{-8iB-o&e>_*(zkvNlIlQf z7-KT_9acQX zt-O+v`=oK)ihA2Xb6o_jNZ?U0|*g)o1ewm9reFG at cs zPXh&g8^M$?nyHokWP!;D{#3TudYh#9I?otNQk-QTL+w6-t1>j)D;F zt(u-drS$i~&)>>7mS&2eyf$*e;&YH6v&=Os1pUWdUnymL-NS z4zgL+v5+<><-N68U#B-qgaf<{!x90u`?m!r7kx4_VP_%UG|ZyA?jg&L%Sy1S5%)XE z&@Q`1bx&WkY*}%{y8>d?v$f9nIJ+dk633nFEmNHS12zMLBq)7yBtPfq1!8{R*g0h_ zA(0A1TPv`;n>9OtFobNg%>tY5SJ&$)StK`q{qG6An`#C#00@)eD==DC0F;%*$0EMM z#?8P7IX$KsWW+sjCY-xtanh`Uq*qjS4%n&kqx=o8&sL*$JQ*TvmQyzbr!Dp67E4l21^D#7oDv1w!@C1Y^P!r+&{LG z#;92JWlcE7qDCU4h#FS!L%UoB(c)pWjV}T4fYP;X;BNR>2i)$t#BR!1y0ab6vg2tQ zXoWnR>^|ZWH=F%_UjTINilRIugt}`73jFi3lK3r=eM0zL1^xg< z|3kXYoJz%ufwveN}!lI{Fl9hpht%evl4VN<50u>I7ZQO(>bFE6#uxCS2y#> zrAQq#_)Mo2K*6^QKo4{=+LU3TqH^*}e8!lKLZndn8P4H at RV7U-hX?$VO4Nt zwZ~jI{BFarGY{!o#k$-#Dp7f;k^ZMG`29G+FG|YgLX7HB^-a at A5nP4u`bt35t^)Yg+I_+19(8pEb8d zV%X{UXUO%ra}+)FhQ2)z0p4z7 at 77-a$usnF(_4ij-}V}0 zx(G;(+M}jPp*T4u_i;VDYT&^`jr0dv=Wl;dr#iF7MT;qThn~;!y at devBj#p zYrQS}tEy6(GXw>|hS2jLWFs7EIho zTfh78l8+r~-%)0#e*La!WpOOSD2sE!gJu*N#NX at cBYjW1KM+5g*TK>L&Q3?e!_J>; zb^k6VuBCfo{Gj6br9Nku-f#V$iF;s$4+HHn6lV`^deCF>U9%dke3|8E%^toM1iL?0 z?$F_#^@sJ~pl#V>U8;o&a81<;*?eYs$=eQ#Q{Wlm#W5KP>hM90G$go0MbO^O?orC43t z3Gk%L+lIU{X6{8oJ?AQ-NL=b1BkafbS)pX9fD<~=+sEtyr2I7?M7o7e+ zkoXusXT0D-x&hXieB8tb at S-hC%C6|gRQl0huqBHegDX`2JK3oc0g0q3DuIfXkcRs} zsbyEY+49 at +8f8JEUhU0;CqUwARe{mrTrvcpUll at Y%-CHE*|xk*&)wC#ce}k$p4!)Y zGFZ^7DT5nFZvdE6n9=1ybH;nO?i3?n<5<#|k`c>E6}R9O8gxOUd-dm}%YI~ZM{OSQ ziN`%|Tq9;t##V*k{$77V%kv$^B~=~7g5JwOG(D;@lp^$1gl|DZhn=|bSiaO*=uEXH4DCpl!4aA6vPh2y-w0%vS} zWfOP7Vl1H4-mY&->Sd?as3R6LtF=TCPC9k6k*m at 0Q{_gs7L{jH2QC#IZFcLQN0A4} z0nAe3j`<&sIgK~k;6Li=xsd}m9Z at bl%n17JUmd+``sg>2H1%6qxMWJ4<*O1z at KW(R zC(Z`7+8p-Cff>qxzAs&vUhMukMGF_{*8Z$IqPP}?t?i;Y=rBt*GMW=;KLcEx at 4CIE zGlr)jOsVo-6d|n*NQLbxw|LU-cG(||At}fqXD0I3nQ$q#glNSfP#9 zUG&9GlG|kC5E`Oam=A5IsTfx0oF2+++vnPGpiwucA`t4v{U{`?lz*CK?`tP$xvBSV zbaCtz?xg at c16vEU{fO$B$dSwkc2eN;$fx@>n1L2e>B!vf-%{Lu>Cz&1M&1tJ5Xw?+ z8?6ZCypXn_kSl*-$QswMJH7ElfzW&q at _n4+vuH`B{)>w4_!s4EakVi=s6Z@=&X58^ zFaLe~$meP8$MhcnhUO#MT6P509EUY;lajqFY*9|T6WfHew8(`$gYM5A9>L at 8=N*Z) znj`Kz{iu{g_A8H>|IUJo$MV~lMUezB8XWkr7zib8gXqUZ&5kdl_h~TF(#*M8_UATNqD3mGN==da&hz at m+L4u?IC`pVxq*%0(`F~&! zC;PmC=x_C4MNT!x!O=1H-wUm9C-m!y{+ at A9^;1&c~pog%+({sb`Jn^u-%y z?LpnU-X?R5 at AG~Gq)RRMx)lA4jGk;mduX!czk(9B#|!&GfdlxktTp?&O7T6`Vu#08 z%OcY)dqwu*T9e6 at IX;}bxWTt_aSFoa(KN^gl4-)z6`w*QP?#P;Md>z^um&PDYTnK? zJ63Lr0WuhTov~cV{Jj2LuBD861`am-wBwj2XytS4!%@F)p-yDSzk3*MuT(=zO66+z zWDboi-nYgK!P+@j}UT{sIGN3wD8Q80LwhV=PKUR2i5m5_R}> zV;2`b#;W at 3wQ*x;;{M4?mE?Qc81 at +-}cuIbd#G z+2#0@?RT2uk))tA?snfD at ow?@Jm}GS=oHvn`Z!xA?k_?rx((BPbhn`?7awz2MvYJ@ zr9av#ls+&!ep*=L(oO_s4I;|~f|p4yfbHb+_)xmA|K4W4mAwg69P?dIxRv&Yh%S8 zW_)a6 at Hs7!JsADcwTiu|FGNQe-iPq at i`0NqvV7;-N=Wje(gancnoYdA6c3>fEhxB^ znU4<{<4tqMzsjS7CnAS^u_3JHUKj=z~WKCiQ=eryp9&ZtWDmm1ak{>HX~7s(vl|^ zAyiP4P_CpJSkvx}^kM%zKxtnsV*A+3H0Z9(twr;hl$JI>Du$YT;ihC+%Kxj)Ib=-y zg!yJ^Z6sIZ7HHJA%F`ldLRYu`zG at DDHC=FT_VjuM)89>3DXdV_LtDUyrm;kP%lCq( z>TB%)45>In43$=pU~1Rc(K6z84jO#!gz0 at YO!)Wt?0c;^oR66fV2qq}U!+`vpp zG}ctcseXj`nXrGRK!ki4v}Yl*zODnBT1}v}MzrIT4hHgZX-erBj z=OCiJqasnlhNG7>pp{$Vz2gl1+OyJ1qjTZkT`{KigXAq_5H$S+5 zyEBV6q)$mNw$OF@&TN`ay{w=Wir!2zuO`-|gxj$_9;a-O@~#_JW0j9(C{*Q$4Wy;~ zIf^yUkx<_w8o8|4)oT&QgAUc7x4UkUnqSi~=Fo(hlDyIL2Kk_KTQR9p-aa}u$;to% zMPYgp24q=jbV{1(Df zkO?k2AkhvWA^iqK!Um}G1+nIuo`C^Q(eE5S(6-%m;NVdd^HeVHEdfgtQY5QvaygF} zS-Q~4C{IrdV7bt|q&&mA+6OmxK&S6JE0 at u`63Ovc)+>=R$uVzUTeysoS_#(AJxP1g z&>;RHbzsS%m&gz|AuxdgX1N90VFdlTLblCPqbn#fg&v1*(`9Lb1t7Q1Wr);6K_7At zg?^P-MN^5c01yTq?kG4vGW|IX+-uYF)Wvhp21HPS at Xw4H=E*5?jU6QMnXkBBE+p~h zSR>2-^_=ZApCnoIvZF!yquHU at QiJ_Y?ayJs&EMaJ{m&yQRKi9=mb4R^m at OKc?v;9C zj`olrxvB`x;Y-7y+&2vUV?{bEKb$_!ZE%zwyS&D9pk?RP67%YPK^cAD?zWEmqSE>~ zdN`q~f9{UFaYPL=ZmN9;#eJ)*RytvE7>fkBTymySZZDw+mgji?9I$Kx)KL%?VYB~x zC2J>srp6<97jS2Z=0TVLENO(n?Od+SO8u)29xSXaLe^ zlG(i(Pel`98fdPCz^D(j$Az9wojW^nJw%~553p0-e$_(fi-?t>Cno}pYFi=uYztJm zEX9$zJYegI*e& zn7O<(YKBJhs{-ouVazNjA0Z+CB#PE-6leF2%%?N|+1GJVS8AKYb1=5(ng{v_KJ4_xaI+BOZCNs5V{#=xZgQg-XAS&HhO}au>ALb{@cc)BI7RiHWwS}4mAEcqeXX!g6*-P z(>R|mje3RCn#+_As`S9?1VJAjejAYhMby|R?v}Cep{jeyFAY4byQ{is-5zYqNDY?v z1%gb6G1P$4K6mhD&QVbJMU}6GMMAGEofcy&I<+aKZ2P3`Ie+}&S&_w)`+JL}! zw2?ffcnnRD0C3OyYZuu}GYsCJ1%)<(QI%J_xaY|d!5f95N_FlZ5^Nb(iY~kBIhwc% z#DC+0nlSD|?dyCj8eA6SEX0DbETw)zntr_Utx at Ymzvla`9PC7#x7Y>(77g280`_FL z&NZ^oR-8W|<@-xuxlL(5(kX_9x}!55k_D=>unl2MdZroiDcOl;CN{I2Rt21{*28*YA_0 z(&pldG$mf4iQJ#HKNm|YS>wxkk12u51lk*9EML zfQ&5$#xb=)g|kf=)5D-RxFr|d9ZN)$HEj!Ijl3Bu)NSw z$9FaDQiaFf8nSW${TD-E=@Ur{Xp{A#^iYb;Gx}pBGZGQSte3t9syKc$K>_=MoQ<`J z-rSdgL6=pAlF-MRBuY^iPS|hKT8&xo#)c{~ez(L0Ri~&CUD^oDg2>KFX2_9v%nq{0 z)@|yEs=D9L^JgD)-&2N1Ph)Q2d~A`7qHIhNv{o3*TLgHcSzukHqtrkYKAXmF_re_~ zsYTpp*P;n4MI=S7rUS(=z(>gY-N5rPOeck6gBdepuSF??6$j+$!bOQkdAyRMmmEbK zr=;Q0k${cT%|yrq*9(lL35%+vVl*=Gx1v-ueOFSNs*B5yLfUH%^6~xdSWPJFP(TC6 zS*X#^X+4G}UurW_CXn>~7j1#l&#jtCp;)?`rRqxWN619+m^^dJ%0pqhX at HM6xSaOi3M% z7{exwVq_T>{+hScVaXSndf#jd$rb|x8G5Q~8l1B1*(Zmx7!gM7Aza3COu^#-SB9-1 zuYTpaoMAoLh4}{|G!7-`-Wz$eQ%{Jg(c+nLprf4+@@HN%f)Q{WN{6| zkCVM<^zK?4e&88^!B*^{^7olV37hq14WtUHD&hQ{py6SA=_{EroFcvFb-`oSS}Onm zAOJ~3K~(Z_&c%*WuTHE!>5;1_@`*SRV|044X*3o~4Iz;km0z7Cow9}@ek#)UI>i^& zzBPID4GxY^Kr%D;IjDov{0VywU{f4isqA^+KjB=y_MlK{xT#>};pW)e=- zW*kl9<}r=u`nsfD=#5fVw>6gJPC|qX*dNMx%o6^Q?8}M15RPW#fYXVnb4J3;iZzm#MfrNjkKz%Y(XDu*V!0U=cA6u}TB zUg&LNpwN$Q_ at YHAw*e8;jS7GDXgDVJzX;^O664Ql$eu6LuwnCWf;&A7D4I&v0O*hL zq%{<)@49uOyux_YWv!&}4`+*B`^A~b^iy1prlr~2D at x%a6P6tp#!k8vXKAp8ELug& z^TN6y$pBsVrSj6_45z%nsEs1}5W2(H0OF0 z6dg at 25r~?vDul!-D9a+6WmUw;^RxouJ!>!eRq350x|q8W$SJ_{ZvQ%vKV2>g?fH^G zxF&CFqjfe%WL{p);08XSUc=wJ)u(+oZ0ihWsn)>Z<(=Id*?)I)vwe z)=?L&nFk4+Q7z6oFjS)&d(+p at j+rrVH&j^_+gn&r zr=-VV3IPkGl~@Mb=HQ6PdXdZ>&E?9vgD%TXiAqh~2oy#M{Isna6T`}Z at jqQ7i->B9 zAe%N!M_nM6lXp=-9t2EkBZOrb21r8Hl%mu^W7UMw`Qb0d0t~$r8&bG0$Y1&rJEv at S zH`0QY*<9)>7f_Uap<_&CRW?Rjz&U8;^0*G*(!0z(CAv;(kkpy)?zMxPVo=z#O7mbV zt&BoNuP at vZfP>mCH)rtXhbIqBd}e9k6g-{ttLJLcUPl&pr)c6ut=S2 zE($&Beh<0pC$$M>vo4pSQuMl%YsPsQXxoW&(iRIZ?jUp5{=$8CK=npH|4g6=WFITa zX`N%Z=R6C#uS~991dy7y!o>L5Y%yI7)PN%K=K1}td8-Uop`U!TdH6_yZ~)^E=j;5D z*pWIzbsM*_3y*Qivw~UtwJ10$ia`*TVal0D-?yqurw;QRJU$H{%@QG&cBcA$OdSke zpUMa2r4Hl!&-`@SXAL`m<=l8oqi%AO%wgE~gMI)k&cp3vP#u&-W8`4EjvmC$m at hHc zMS at 1V@=^|#|JGO``0tCA-ftcCfWVL)J*Xgg+w|5M+89ty364!e#+1EojA^;Uh7D@; zP+jv;tpOeVs<>{vv40j5mq^xKu5A)ZR|qW*MJW$+`58TcFqq&7)fozq<|G at MdwBmB zyW6%@{e at YERIS@_{kkCr5)*Pp9D}w=)*2DAO)RY*kFT2}mf`*UyrNxT=gXch6Ny-t zenaX+%L=1Y^%lLLmIZI)Rg%CJ#Jq==f}%Wv&*AS9AsM1F`m%&%+aSSTlfjwMxO>FE zF#i>|QVcCbo9zF+L$nVT^qTRm!EJFe=OX*Mc|$CSDqV at VF*16u-7zjd%06%R!diKK zl=Ov^CeRk~$jxhC*z5|@n|-(k!9IvA+8HAt%g}&L-i9h~$U!VBY9z!41cWZk$Ptt> zhUVcNBaMAzq5aJ{HlmDNd?JjUrD>Uk=-Mmo%E;(-578LVV?LT{QWX-D}V1T z!=EEMn&4x8n6iXLyKIDya#dsIj|%38Xqw7&Gw2g6`fKFPlg0#@U)JC2o8-9@%j4Sy z9b8&h%)aQS+ADPUJQ^lw_6rv?HOW6wJX$1x=MZT)X)p=ggF at l+mYbP!5vtpa&8!Vn zuwNe0`as}8aP9BF^^EA%alUQxN)X7Bye_$gMmbS+FbYVbyJ*={ziCF!|6}ZJW3^4I zD#5*uA3p}InzYUg0jlhYwx6XFr34qo_?Mf`aWwR2+NAkXGA) zq{V?jMMXeClpr6CtQ1w&-rs43_I2Ia4wU|r|uh;5<}eH)>;mk-}C1SB77z&i^@ z+~|a<2XEyz7vn_ at B^Z;yDDFld+q#G3{MNKO>W8vSXzDT;M&NOJQ70+;CF!Nu~dRJF*insyH0|p_P?w^OwE0g;8gH{g~iZ$Slbw2A!-NhxK%TQ at k?bmNJ?B( zFks)xkua_h2YKukUmOkFOmkoF|4J!YjE0{xB}s`BWT8x&3_~;Q9pl_=+h%CBR;I4` zZmWxiJx(jiZfhc)U<9^q1oQKcm{svIR8D^}Z_B)G$sjqX=uuc=`I4>F5;x#mpK(qV z+SIX`iu!V&M!@a5_6bE?qhyqD`>xHw5VA+a)`xUhV%EJwD at Sg7u>4Rj!#+(8)l{ZA z`Ga2Rrn^$`uE7-ep$WYL&+Eap zE^QEC_?tBZ(m at t#aW%anxe|OvnbidO*^i>l$iS$&P7b(%D6?#Z98IrJZVL91JXCQ^ z3`67z8tm1^Lcv*x1#|9E{M8!NlSX6D-VK%39C&I+G?2BCheX1PsAJunpfi^nLC*~C zR#ko5x-MWbsQb~F6Okex)EJvBP$-1^Pzt-HO_NsOn5yqXi+xa}W6x$H-813^S(fZt zg&(^I0Ry1|T5|2kxZ90MaDy}@OK4pm=U!;uqx1E(ROiKKaAxdk;%$YmCFG2wgq>)o z#m_=TQBFF?$V(%ECnuC(Gsf?j;*{CdLhb=7Wx(X?@1^hcpDW0QP0<>ii}WmBXi5ML zE$_&N%W2ADf=qxkwO*Kq=_s7q;eOC3Nu-LHrPZ}02D{y$C?0voSQx1}>=CGrJ{d}l z7K+nt at M+#MO38^vHA%+K$1q7>%%}XYADL8f8bClOG&$X!QpkPjbmK5KB?k?e)m62z zeQAdX%p*#?2`NbdHKk$eelW?R*C7p`1dZ=|Lt$6bp1Q#~qGV}pXl$RWTiZxKgUMCF zb!G^11GCWx+iTIYG!f~l6OpJqelloV*w7d{O3w0$?CPf4A*K!8rsq_aFbMgSvUlL? zM9~J)VaWoLscq;UA^NiQtXh`m$Ttfpd1-{@rBO6tME2*dXscIvNQeWYHwvw}I11gM z#Rez^!`ZYTDaL}7NT9eHc4Aqer#bD%ZSRE0>3YDNQ4f(Pqp$=0Zw$6cO=1|)?ijb% z%DlC&_a-(a*TB$Yw1$up{xyB)e7+XJC}r{|dx{Ya at tUS9JHoka9~mQTL$Sw)ZD8il zricJqNjmd+8EM*dh4Sn|ZB21ELK#G8 at 1X^MmIF=RwoYe+mgu at bM=K8yY`}^JP|}DTd=e^$eZs; z=kF2jeBCC*WV>`tVjvNCz=kUUmQFwBMO0YPIo1PdmCNfJa z0Yi>8?IySfUz)m-dS%l8I%hM9BnEc9N(J!%ABLhe=>sxlewv(jZ at SZNt4kl|sQpy? zwgZ=~KqkUo+&~BT=cOqaIP}u!MOH7orHR%39Y^+VM~I>JDB^W%r4Wsdo&o1nfaGY* z(%>KZ`{FrdMqxato^;Wx6tM_!iZL0~FuLP0ylT$QU>Fur4I2$D^Xc3C?q`1QTq7{N zOp(8tp1Yeno*cklWyn};x at F5u3-J;XR-T~{KWD0+5L{|eyE852w;WM$fh{z0YC^e& z8dl|4<;eLAdd5)>cXy{}KU7bTSVJB(1gjf~vZBE}GjE>;MY`5%G at EW!g9%5UVr|<5 z*%=>u{Cf=Xq9b)$7*%6%rNv|>mUXBlFuYoJ11KH}!hsxhKg2 at C%}VbTgyUBOT}nYt zr)WBwgPhMuJKzpF66k}BKGAKu#+Wq=O;@ohN$*`)RhV=ksy1_I4f*ccMX*T(no5=v zf|p-M8sfnA?X=H@$vFEP9tchHcb+jhC%7~hu^jr8)@|@5naJalakr2gfk9YozYQm{3hx4U}e68D7 za;Bc*jJe!rNRM at bTwwR9bs6m81R>I$Jwpeg*HB=QJc5(hAdRYlW%*+VU5hlmE5jfe zx?}~XmFUD&%@Ee z`vEpR at VHreXF^0Di6gBZhUpesQH12BeY3$dZO-bVw0P(R0O7?Jw~BNclm_n|(yWC1 zJ8A~qa?-vNj0sS(h4co=PC9so@}YYtHd_NCn{h^?*y7|%F%x9`eIR9)I_k>+-ot_P|K52ulcIA-Rx|6m1~W1gt1Qmr2->F^Xn!GaR;DM at Qe}7Ik?JOu=n< z(!J}=iI~k8N(W>17?uaj3!Gvc&CU7(NAjYi4)lVCwezpCzIsq$sQuG?G)%VVH77nv_ORvWRM>4Y07L7&4mq#^8 at FlA+c>0i{ccGOe>^SgQ=b1~ly_HpN#M z*X~1hi1ixGAq!`6(z0cm;)0nl%ITXIi~mleLI<6u=4V|LEFa3)6;Yce&9Td8OHz~fROhTL3__sc-$BWTp-z(!iP99Jb(E7;swMEtEQ{VZ!t zMkzTaZ_yG%rhbwaNZoxjom1OtaGht99UE;|#s&^O96&{7xE=y=zcGc|Iism0Q at 1uW z5~YY!n-BH+;h;|wKnJP7*}5o>6bVe|gNiP(hlY;5i38Rf(^rQ`7ZV|zo3mPEDykDe zCO(`{cENBYwtH-L`cj}fv7}_OfZmC!GOS%G^ zET4%=kWlHl1~ik{$;sSIVU#^8E1Kq)!I~!e=AylhGHW#oPT}3k2P8&9(J0||rD4+K zVIb^fxTq?})n#MaU?YU(vEhD*RyNaQI}!J=vYZiS%eg9$D^80C?LT!THQnxHtZ!Q5TA=5tLOeRA&T;5BW~*$x6Vsrh zf#tJXjZXSile33C$e5m2iGSxnkyK&CL<=EcyQiNaT2^7@=|fQn1cLyr#9b0=BKUZg`OJYbjDm(lb~y((2Kd#`UPASEn4t-g>-7Se)TAMBkF{`@ z8w`_?$g`f10S- at 2KR=G90 at EseH6lI%u9!teH_MPpOyrH5Y3ZT+JIw1yZ=$lWYbI3n6So0dYGA{1!DCw@?@6;P*a-QvT2h@>-&^r6Jc z`Rgm at g@MLl%XFq|ll=*ImZucr*iZavlB3>$*pzaPpCW#W6c9_n`V=kfpY%!m$qYi7(o|twVAST)s?|S8d4>-C|%VuR1Dta+cS#r}^b<(2A zs1e&^(f6~_n%j;-an?=w9^o*|wVda6kjddd)ZUZBh!W~HuDn}w>}QrE70o68)LL3o zLY)Z|kIv~WltM)|joCcp&$vU*sdyODAQRK0p$L!q6buisJZt(IA{}mGI69HyFm-8Vvzkh2jyiV$!+6)otKG#421i!(PI6Vf`Qa16gkb)Gc6 z8>D$cFJ!Gj7^t8O2&!xP97GDyK7$5kfI_*AsvJpCC^6TkSyv1UtwrQ5EvccsfZEg0 zrA3q>E+QT7O7OY|oFe+3F at b<2O=eB9ak(SbX~eJXW1$3dpS`jX64;1IS=l((vS;Az z1aGu<+%dlWKJ7 at VetJ&%m>_(J^_N;^!#-j9zNzwrh1)@7MOX;nEIRTb6r~V`&Vw+D zE5TDxxgR|v)$2mdoIQU--+?$KmeLKvbtu$>Kgim8OrC!NH56$Yhn5k%GIDcB%h;S@ z4`Z87n;?Fo>}PCrjbg6Mk08O>IZ;)JUo#wr>9^!3sXkSMQY7Y~hl-Xj5?U`Ps9A at U zrUeW-hYg)}1x(Ovq8(PYA3#1-q3!XIG7eSs0XCjNvLL>v?;Td*kZA<2Kai(KFp$<1{qP6)f+9C z7a;;nsMi#crc|T~#o#oddb_?!NXD;0&^)70YfCty$mu>ZtdlVY9mRuAr4WkJG+>&Ij=-Ifi4nxK$F~ZG9(pMYY zV26~txVuNMk>kx1jA%hwMSSX at s4zEV!?g%47s$e$`>~uJ0E at 3$lr(Ba7CkhIF>LNY zq9A7?3ao=&6Nd=kJB$L7>5FxJV8w8wHrIxl0<24rqU&3W*dz=P65dxeT6^gCP!}w{ zF48pBHB!FGL(>Mj&|9X%`upj*oPIyylkX-V52EvHjh5=XxC1N-V|vg>3x%-Yw&t2S zXp;Z`B_ysCYM$$!bA4i4`w at G_Hej1tgXZ$%)^No%qa%BrhA8e95tin9B_u(8yN)J4q}~iszE~P)qr-Ig ziFxppsw{;K+q5roUDxp?sD5kZaKo)0s}B**SU#hAkx4gpzgXMxV%{~%iV07hC}R)u zxb^~G8nREH(`9*p>vZD77{)-+6dSNX5>NBknVq<1Ek(TLL=5$)oxuvcIQduuAxxI| zYASgZZcqf-V7ThNJB{UiQNa$69s&>5n5xxJquGh6x3rE*CKl1rEhs7z25dyOU_;|w zN5w%@Oq!JmX&yJm%6fA>AJ%kqUFC$~&}hkIHR8|m8aUBOVEytef at 3tSG*_m&;Sj5d zeop;QH3kl3P*)r}$T=d44NcrBTG1T944n<=;?{#vt4`HYFRGtrkgm<4#hA&zH;t?9 zVMQCdSspQ3z!WFq+Dn3mrrbm0#Voyr$$OTKst%1Hl7H!Yff1?bsnCQdgFDPuN`c&j*BmUmf)|pUi0?fR4FwqruYcOLpd|J^@gq5SoNDDHi!U at py%xG|=>j3!xEXy$t?{w*oM4i&>(%AxNAO%A<$YF9`Gr7}ifwI9F z_ZI_)eyVfIG*DEIj6Npb?0^72XxG5Z5L5*7|7CZj>_r8H;Ly1u#naIBW5=3qhXo+@ z at v@uf@`|pV3uYSRM*6{#VS6;FJ^yqST(CUfPQP>NEj!)T2dQj|*?_&#EWn!t);4m^ z@GghMZ+Y8J>$8OCDI#8GsQ1KW{YuJ}l2KD^=M1lbi4W455jVe546+aS$&0)|Z%8vLsPRD)G6FP;~4<^_o-|QY@ z=NG8AY2`W5IXY6qGN}3axgXcbdcTyn0AUpYZPJ)j&0`u?q3%KT**{dd4jzSSD-|YTxOv$9^y8kxoD-$6d$!X6fL0# z%(Enm6al`UUUmvSPp>08&?}jywy9+3xP^!II7rhEU=AHsO${1n(#G6-sJ0 at 9{lJMt zQK;-V|Ae%k`RD)}mA at J8XKKq+&l!pis9zgGLDcP8Qh9<=+|`_trWa-!{ayZVoLZxG zPFY|OrVN)GYa0o@?@Nu0*6M2eaTIiXm@)He+A*x~`kU)`Zc1d9i*a at _JPT&TxjLD^ z-T+a8kPpNILBw5~l7}iWpsIuCkPR&o7$O~zzPlMiM`=S)EaifUVHl;O?!1uKeaH%C zmaC?KAU45k+SF)!sQEHo76MEI>o)LoQjG00P;$xrsORi2tyi07$Q{8tzy;{w2SX2p z!%k_T at 94n6<|a;1myt4NpWt?S-H2wN0HGD+lBmRmVjOHD+qWv_|n6T83b= zq!X<*ElyCE$r_Cq531m8Tx3;XWC?CbylAOJ~3K~!E%81Vvm z7UvvBHT^oUE*a9yVOoR?5q*u?jGJJn{#Z%0;s98`|5v9 at qoaPdz^mCN3=JIXLLTb$ z_jX9-yhwI~56AcE1(nqeTBMc6HyMPCH=$vIF()zC}J|9Q5RVU}5c$JB!-t>8SwU~~2fJDrUm22ty#G?e=Q zYgW~Sd+uG(y**$6l0a?0h_L;Xe!>B%6+4We?PH64!}B5g>IxWnkJ^Go&4e8oM at V?~ zRtOubQF$rD_UKY;4Ir>*w~Btly5wZ(VUJcvV}vqxuLcBfR_YDv(OaX?!i0$DHAK7@ z;+SsUerO(o(~Pxs%N`R`vr1rXy))67QCIV~6((u%_-E9l10BP^*6atQ*B z<`8XqR+2-KAoU_ at 94TNmYP@VVEf;Z8sEPlG_TPSuxW3#78n-F3JtFSTVI^{CkZIQ<<0&c-#|A}B_?lLm zI(Sk0tkThaqRVN9-4fgM^G3=<(|FSE8)lkEU;e|`xeqo9V+lbJnY86818~Hl*1+m2 zDD#v!g_U0%C5=<598 at _+f#M|yW5G6CON0}vh6A1>l^UMLK&%FsVxx0}p`RFzdJI>X z8-wflduEN~G&Y*mO~M)bm`XxheT2k`dA%NrYF>3+){ujUi7iI7*(s=|iFoPMZE41( z7Y{JR4ZdYzOfaUq%B{eydHT^NM4BP(Dpq#;4ox at SH?5sjK|}dAz~fL?G+G23T26ir z9U_O?dl6G7Un6$8j$s}67(8oeG|6G8zcx?P5D9J6(JNw at HfNvdW?X4{CX$Mr<|v7f zQj9VD=q|=7d4t?Bqzk#jk;;+s>u5C#7gaZ~QD7p4RZ**1R0n=X9cuFbdp4scGFOb_WtvV+}t1_45>s4$61tfYjyW8b*`abghr at 8A%gK zop7!;bTtjA%W|fzbYbO&4LMsAqZG?hzasP};=TAj+;(4zTXS6*n_J`*me2(I)kxj+A5TVY9Khsw?#aJ$BA?1AbLU(0WBbC4nB#OYVQvXL1IVo z%HKx`m3f+uhCN|+l0EC!x_fGOSeVT0xhX=`Khx{!cz$S6M|L9~Dl1dwq8ULz*r~;m zMvJnsZiXg<-YX%}RAi^+*ReG8e)mg=nqFQsRNn1&*b9jrWy(4Ijmnl96|Dcv>v2UX znzCo4(CxkY*F-pnmV}$KYSCq!hU0WtOg&5Y05&9H;naXi?Z8-rFO`h$nM#YZx=L5l zP=jiOk+J2CUmx1A%`DvD at j|C=kJ>;(O}1BTUp%*T(*MSho2{ThNA`!wbC#UIkv(cT zQ-wWpi1~y7lt%K1W^=&?3>1uDX18)_+G!_I(XG;&t(9jRb6WGa7}B|5do&%HDd|0~ zRiUub{Qw)Plq0pq at 5v+@_a`z3Iyb*}dLS~Q9SG>3eli9WQ{S^TO$a5a at 9!A4>z?WX zL036uZ`F*2qh#bTrExa~jCMVj_=wK|A_eb7;}y!MVyZNow}vpkocb9qS;qjv@{992 z3WK`k+2JGjzE#&05aGQX3!FL((DEW_!X?^4?9w%M at iX^A*Cbn~pkp-c8H7GiqtKi0 zu<`$@P9H*yQ?;YkN02nllGFL8-lwGGF zCTB;?*^F+(kXLMy;Y_3#7Zv(!BwOIn`PWcy%N8h6s0#qNGTP}>SccJRE1qT00y zsozdSQ8g}>RBSX|zCPlq6}(C3kgXSJu1UqITk~Vd>z at pGAeeL_uOrSwuGnMb82l7D zjzQ at wrGUvs*gP5oYGh at m@r)bbR8~r)Su5 at knXYNE!|F*N)B(F4GD<}JgHd;O+~$p? z%>pztf-;h9*i7wnKSm90KKF)x-hql at O)ao_-40ePojBNbL&;fBK!no74+K=n^C!}j zEQNr?Mj at 9-Q@4)p?jAEG0|9tJjJ(4JALI77vF3R(TMK14J>!@g^X5y|Y%nr^+ON4Y zi4VT%pe)BwO$?E&YYiag00uDiJ7h+soExGPF&wPhKv~$U6+H;b=?P5Qn1M1&54syK zt4Eo$NWFMV0~W&m+Q!}up!I=2Hk%X8I1)pGc-}uV`lPlk0JjXF#DiV(5W_+p$h<*P zjY at -6o^TgE;bcAox{0QMdN+k0s0Op)@d|6l)}ZTLsrWf8{vPslT_ah)}aTTHb< zIHy|bj!*rbbaM_}T7!ViH2`a}Q>MO2({WmIQb+%!f1w)l8zPhvb+N(9yxhp>Ub3_b zE*jz*o78{PFa_48YN4ZKtbgB-{)D{Zop&J(NlT?ORIDL*sQ+u(Z-W at S%+Q0K%5rquvX4?f?dtf*X~`-$)^txXuQ6MwlH|9;R;WSbnOUXDJzxcIK`h!O`4o~uc)1*Dn at 5?@_6*ic~!ibJL z*4LO0!_d&}VW&myRZYTHAIsN%0Q~z0N^4ki1q=IG` zzq+2Vp>uR4N3z6$O$U}uiP-0c(^!P%GW_DxXCJ3Z`1f)|x zOkA3=tNV&#Sdk=S*%}6$M>9D*=K6JWBkLpWD996fA(fISkS!n=y5?}-t~zo(AjXn&z2WXrg`}TH%~SJI zR=F41K%3$o%Tc#{4t%36Z%nqDx$x_<2~H!_sEk$5!`)cO)Py1JiB-Y8nW3cI8eM8cg96Vf=b*W^A}@}3ybPA`^w>B*ro z%$X~5=qcf_Wf<$nm-!75p at Kx;1YD=oHxcFr)hU_Q;iBu*c6P1Y at aio4Ia@056p^Og zazLDF;R<3c#zQ-EQXCA$Z>g7iiob(qNFJJ;v(kVbWL{v<4O|)Ed(NAzzE?Lk1WYpD zMO#43{Wt-Ku;Z&qDi at t76LLppuOe6nvM}>lOQ_mKDJg1-efc;{L06waZ3 at Cck@`=$ zQPA!iJ=Z!w1hO6sHD=IDbk8})PgjbHIHKSY-Ck at -Q6@0i+L(GgA!fzk@=@6|!KG0< zDS&;z>p3D2)^^VepvP6Xp|kD(;B^~ z>TX$Cw!$H|pxB;y%1>|}%ILZ1!@0tqeJe%?$vdCZm|`?L at TL@1Dz5zvmH68 zS7?1YbYR*yHV^L>SwN1O9%r+oh!wG#0B{-?Q(Kp>Vyz){?qBLJ83xbLl_er{I;4Snr{T&lUr#Exn-Vb)LW zfZ09U;={;^Tm>hxe(h6Elj}Fd9EL1)maDd}a-12%PRQd(TfyC3AP_)T`a&G`WH-pq z1(}03)aw1{Wd$ha3gdmzk$KscVH31@>a;3Ft<{KstDv;&O*;c2i`Hpy(61cSFD*g1 zLV?AQV7xEJ`bYx;f~BwWgeN?qzTgYKpl-eO*0B?O+NXV5z3_X!rOF0MJjdAcOuS6} zjNAU3`rhyT-m0ql$VWa>FaL>`RPn05 at Jm0nKKss3uBxi{KlriwH~-6DoN^&VO+;;6 z4GmGW#HPMqY0<3+;hz4be5$K0V`JK^@&WJ2S_Mpe80abmH~luOSYvjBzZM*GVDi_8 z**d6e12{uez~PXR2^g&0#tkdhC-R2wrcW*#N11&9ODct7XJJJr&D9z0x-<4^rnx$& zPgj`z at Hv&VG%NndixQ=Bp*u2U$1rI{P_q-vsUKu9(oZ;36p|2_J1ZC at ong`p_G?6? za}XpHP1G%uvYeeSyBAp*Wo*->o-4d)`IRIAM{5LmG1-Az40-BK>V1SJ%rS!JlZT97 zrinh!lH<^|@dDXZq8Bt_pdN#6RE)mI^hrz|xY6}R$+IqIcY$tTjuEAmDB3p2(+ASg zb#yJI1=PKnQzJc1mZ60n*<_$t=)BRi{dY*?)~bBk#08<{@AaO7!8oxstgeq;7D5Vh zOX)GhV+?+o6sd#GX;Gg8PVetiIx!?t(ys at C(~|m3r^7wxuqpn^C`Op=kf&KJH6aIz zXsZK073a&(+s_-B;CT-EmvJ_O-7aCD7BJ z_O!~X$eHz3l at g7wzxH)s_jTvLUjH7{7k=5N);-Vol=_rMePVseqdu|jdB&&I7k=5N zRv0sl3 at 1m*M;r7>K4Q_?W>V!|Y$D{jT&4HK;DpQ4ssc_;C2zL at SWKFCmwz{$Tg1zc z1_c~cX{R?!hFW^qLkiFKVC5KF($T##w5`(Ilz6!0bor5U&AhDX)KXcR0bIrxtFc1> z550MfQZWS2C`EGWmriXSFQh+sSMDasoIaEqS(ZZYu~&q&bb_&Maaz0djUIGBu at COF zMuV#QkOY=d{7o-I5;LwmArGQKTKckWa!aW`D!nedIc}*S9Aq>2wL{q`KbmYr^H-;z z(az#%hQ0R;RhZRET_nT1)=bz5(1xFIp=)VJX3s}&Ix+L7QVXGAXHq@&22 at GIh;y4c zznu_(`6BwzQXk+zVIX1L_&=8oo1JV*(pbR9Ee`)r)^eB7K{YRkL^_lVxY<4jc}CX3 z41Bb#i2*D_vL-udh4zA z#3%eco5vLok(w@`YUEy40RGTRzq6{UKI?CP()irh|Hd%STcM10bL?!)w4P(u3!eA= z_1Mq<(oxjUQkF)bTNdy!t%{bvHew1D8sXju|#jc17=bPb0S(#FTnC25n5>tGf9rbbIvs2Dp2ddJ+) z_+&Dm$j^4Hk{ChW%OkAeJex!(K?{!O at I+#*VE|NS7uLq2o!BOJsfOZ=gzP|IH8(dS zY at BJ3qbOpA?xMOP$`WGd>EDix&wh$`#wK^Wd+J$-8e+?mJ!YOl at APHYEKk4F{)~z; zn`qC3Uy3QR>wWpL9}q#LZbg&dQ|D*<^SuTe)OyPAjhm(e{rN#nUqwIaxbvPEe>=Zl zEGZuTC*k&2u%nN2x^+l8SRrYMHWxNVW1qu(A(gT{?Ta7y#=(lcj|C)?tb)sb2n zgjwU9OXcaf*tC2;D02PpuXx2zjIH!J&v}ly9ge5k$Y#appZJ7lob>W_fr))8S)pvjQcNeZMJ+nCl%Qd1`hu0Nl;tLvOGlo|hXC7#dIa#Ux zUkFhP98 at n9@heF&syWl|(NcA0pbG0f)W$sXTTd&8(}b8NL&cbA9?%%n5gb)xlCDsZ zR_hzzqGiL-H`~xe2+VLv?V@!Okk9abl@>V=i@}f8qQ=e+!>ABiliLSbC@$3P!KC^w z?KNJC3bTTLSziQbwI-(!P_|F%;RksZgU6JzNs4fH&W$_=M|L!M%DNWhw#Dg<^?&$v zMw4+BsJkZ{!9jz1A;WTArN3Y0K9Sz%I9p~`Y_VHXaj*szq!vmQH?c#z>6+%jU?R;k ztF at elh0){*6{^ZiNcCB$U^G20rv at Q=5j;0|PMewoJ;$`eL||9?x<1nuKs#U=4CTwr z2&TsyfzYhaf(q6Us8qIr4pZ4z=7n8~&#y@@MFcUBn&_s(jW)Gq7w#5Ha at BP2-F&GZJ+csx(TqLev~WQJ1uVetLEK`Ip}M zn)=8`J|b87sZV`seO&!#ZwnC>iJr)d)@2KEA_|!+kYB&^pAh{Kh-Xs z1p(=2rBRrf^786eyrG`+oabn*VE23KCfo3wsdleMuhS-H;qXYK2SD%4Z139a5*$^5 zP6KD$5yO~OyKalQpz3D2&mJ*#Hz$okoq{-QSqM9(X?y3Pv1w}F6>S&V$BTzy;BVpA z7N^nZ$UHS~gr3uU8a}s7P&bq%eZw{Q!Z+SzSAqR7qf3&>)NNuuFPIXzS?)0w#@)gv z#RcgS+4vl?>w>Vok?f~6kIdta&?)H8$O*OH-TnSraUj=T5HF~fsa+j(n$ zrDq^CXvvr*YwGia7T(nHYg(0)&xJP$tBD$B#)kngsUDt$G`8nv7(`jv9GBIa0+8{3 zrT-dHYA7*?MkqXbUo=()-7l^W=s=A4PbmyNT5|)WawEfW-CLE#-j$pibPZ4U)dO>S zErVmh$v#+X$0>E#6>mpDN*hK4&E(t$5uGky3=Wp2n+cb~sZGv^P${Ef&F5?{VTDn` zmXuD!#_g^gaU)HM2gCVL`?TM=TVYc?Rk=9{MiTD)90=uP{#=R3tz!M^+kSOi|7Sk^ z{+brf7?>Fi!~Fz&(ph*_RsH18z5M*SfBl>PcfIGW|Dpck&;GLh;?MrF-t*S~Q2+Wj z|1T@|oH_GS9b<^YSIT$%qwkj@)Ljr~{M@{zKJaoi7<&d)jc2h2 at usK#fYAnT^bC}_ z2oBwn&zQo!?;0w$J7Rju&QRD{4Bgr^FvZfQ_1SMe0c2*guW+5&@aDrxi4eyTrBisx zTddKuVl3GvM6N$OI^d_~)eKrpPCqaA%W`UmiQgO(;;=%?iYDfv^I?;8`3*G9%`0gDGqbtgV^&VJW`oS_M%}#Xd01#7ctdZV2gP}bgkj;wa_M0`++ElA2$njM z<`0h&<8GH3=Ej9J?QOzRrVTL%7ynMhjGF{Yo1hM%oX-V1g4|4B9p;7(_&D1Iw&%CH z zlPfatf>)e?#D|@bAfS|JuVX^leF at K7TLXqa(Hf9qyF{n`56xYQvjfDAW0|;P6glYB z`iMeXg+6>LBp76KOkj_XHzUxGA&(YMF}=l^;~OuO>Y5|X6V-S32PDUPTffKm0339q z98G4mrP{w1RFo+pQV;}15tHr!TYZlwcra!GGY+{NcliT<`ls at m_uO+& zJ?c|GD9;Gt~uc=z5`u`g_4}=}(iP!%{`Yo=saq zr<5^L4|sltb{vp1Uaog7oCgJc64`!y&>5KY*!l6?#M!E8$QU*H4`wb5y=d@*ADR@< zY(C^r4nvM)kQPXx$|TE+oFTU4C!>-9@$xjZf>2LUZd)$(QdIb{A=eP?s<#KOSEktQ zHG3X#pfo*Eq$5x>m|LoN37`G8R7{b4F&P;&`1+PROv6BXB8V&5 zHWn4*(|Hkk{pYSPdQ#o>*eBQBU-aZ?9NoY7m9Ko|cv`>utDh<-{R}D9bN12y#b?$X zcid4`*WQ1>_$xnU#x45)AOA&9is+>encV%@Cs*K*>h8xrxjz2mK5?G$n3?8tAI7$* z#+YeF;n^?xj2IqD7ZLXa4SU9;6%1?mj)@sa`kmB1NSJ>5I9>B7qS;GIZe`eGJFQ8l zleyjKW;~ji=gNDS%XB81aQW_4#dH<1tJwMNB`OhYIz9 at rAjets;zJE1W4RCNfK7U? z3QlB6JCCLbN+l*&;hGacDpFbN`~8Q|e8d>Hg41$w`tvZ57&z9%yX#*7&Ym(Tt|#e6h at UoT3#e(&(`lct=y52zAj9fOKluJQFh|I_~{|NXxAy|145)pyC> zp9BGDzxz91bZz$cl(Ki}UYZ-2!3 zx$b`Klk1KtdraMN#~t-~pLfSOP5j8)A5pBTPx!b`s9$*P+v at R;e|%L{{i}cV zTlJiO at XY%8pMLXcIDgyix5?*!-}~NIAN}Y at hWy~(2fiY*b5qQMBMMG0wyBAhMZo5X z=CDX#HYPYJm|4V(f)L&86g3z`+Efko at Ltv@Df>qkFyil5fp$7K6;Z+LJ&x`YH(|d( z3!nExK6rP7jSj(PVHkSRmlZVCKzcTdq8lk7KII$CNjcO|GYjlIV2t8ClRo62!x^E* z0kwvKf2z`i-7#JCh=-@$?8*=7R|YFux`b-*AccBG-P5Rh=K0fysI0bzfmpI0!AS~$ zc8l2OPAoQzB6UbQJac>x8 at m^M&G+AOdL00nIn>am#-f5ay2{EGxD*;U-LV&VjbcWJ zIx&finKEikUH_bYTD8){fbgCTodH`cJk6TtuCOB*U8~5B#cR`t+&<#4?Iv0Jn%rh@|CZw at Bi<= zL$2%F-~RUcs;~O0^S|%7_uTW?C)ZE?^iRuY1ggI1^B-UL-1GSDPade`o?Mbn0!okS23Sw`UTQEpIfAWccT1y_)#hF|b3}@7>It9} z7rTDXbS(0nh{#M4}P#i5NuEqJo^)0(9DYTdk->^&`o z<4M!mv(*z}N~S!6|c#1_;qM93F8YdWwBGW4#eHQ*gH(WfRhO15B#uGxV+L zSx1|6MyYA5vVBF&32+~7a*M^^p|V8edP at oD}xa0gmih#Q{-n z!h%Q?Clw#62TUOB`E%CnfqS1 at FMHX`&cf)UAN^=O{{_#lN8bKPb>}^wU7z*&kFH1k z&HudK@%DF|zww*D`J3z4-}c+`2*2Z>wIC0sup%s0UWLL^qkc8m&k5a!aW! zf+o??2hWr=RMYNTYTC(JxD5ncUV-A$TMj7LNkr)b&GkS2*pJEg{pgSWXua at -FFfDV2R`tD^J~w1;41{r`_AY8cjxyWzr)Jw z3cJ0rHhOqnp?spL8}m)m&tZ>}hx{7-l+ZTYJOYYQbdrxz%TNg_Z;*;ykZvzR51WAw zuXLpD)VjHzq#Xur((Fv>XpJbM<_f}siOonK-f&bQjUhudWuu$#+MAH+r5<}G6Glzs z(D9O#J506dk^i=mNe;0to*pqDO=n1_E;;5El8+fW`T(bIHfCu%)cer=z=M}?K8G_V z4<0pL)#%g{Lj<>3or5wKf7)*7tmy!3pLu{^W_P4Zlrl&H)VN;DAJm8 at cuM8kIJEdH zfi;5zjAEmppmhB at k6~M?<&@eJK~iv*>j1>qSujRynqNQ=guE0L^`>bh*>#=?9Un9` z9r)MD)bRjQ8hgnXE(oQndA2P-x|b?&tsf-`#PgrQnlUK}K{-s*Q8W5&_oM8?bK}%f zRU1qFPDgWq=H*JW%HT}K2^$52{TnvOQ+Ly2=q{&K2r8w14D;?$NHVq$ z6&wjsItQz--)B)1%gB25D>cve#V>xbm1)Y>J^wquQHrPMKKHrxC6D{c^F6%d9q*9W zyY05y>PsH?Rl4>^7BGc6{{DaR?WJ?O>#n@}-R}<9MR&*7zv)%u`aSo#*H$$@_=7)K zci!_kb?*aTasJ;5XTXxV%q3oZuD9f8F!YtQzh9->n)6JTD?cSF(c)^_;-)l}K}*0{ zz^PZ1IsoG=?65Q=p~m#su(N3;MB9eb)OAzXco6}Oaq79ARRgCRFQS*D$R%qwFpe!Y1-pq%mlNxJE+I9qVr%V(9f5bVNrcQNb-2 z8_#Xpbo!b!l*vKc`uc$%CAEO~gn5F)S&+#4;&w@#n~zYurqwEFoz}jFuH-TCRuca+ z28*Mm^>8&oWV5kxPAi)ojQexMl at Y@SFVrdHP!S4}rb?CT5T^FqEyI9m*?=gk?waYZ z3}FaNt%D|xfSvJiPWnZJ&T?@3Fc3NgX~pq|iQzcdA?uvfK^~`&S*jVtrf0wgeH5>8 zp;^^4iR^kx({Nao?9860+7AI&f{krv#)@XQqR5n9i@*7p&#SxdzFW|`*S+bL zhAhtO{9}f$ebYC6(|J|?>5sf*T+grl+OM_iM=8Xg^Q><wj*! z<(B%6 at A!`TiJ$!8a9-u2dlJn7ml*#a;u3jSe_hR=ZeVQR)QQbzV{=F_EiFr8#nSLV z-oJe8kE-Wt9&fndGEkJ9I}weD@$19A7coahC`z;dq0=~RnhqVLBxQPZeKZTeVyDx> z$Uih4pjWMI`JGyL*-|~;&qGf0bdfZ-_g_#rx7Dbw$D;U6O0m>8VWe1`Zq}>G96prO z>oEd1o at rFt7z}h&&?_UI9SL%-_t(=X{g0mSOK5pzL+AAS~ zp>j>l5_Icrg{==X8(RVdwh<0Cxnbj^lx1K=P4zi@!Ru*UglSY*tBReZCp9jZNZIj9 z-%qL58M4XG5j&4fUVi38h44KY~ zZYj-JI8Z({t#sU3lsN{4VcEPdOE`k$`YYZ4HP4n+{LXj&i-6@$N5r3h#h{s922iN3%CY>qoKmp z at _A)EF}j>qnRzw~LyPCLamoH_I%Tz=hncav2!hkNSq5qmCd)VRd>x(1lGA2#%Dq#+ z7Ty$p#_N1t%qNF3ei~@d+CzdiSk(u?D73QPPNd at ea1kKm5q2~fh?_%5eK{$7j)AEQ z4ZR!!U3xJN1EX-))aqKfF;jn zRxhoAi@}Ctv*(>&i_>71`BB=_xTQ at z4dft#jT3DNMi*FDPKVGa+;|6c8I+ zZ-yVj%*#9`Eh`CO1&B(QX6`RWitl=jyY9MMuF at a9{}1z`3ppEq at CSb=Kl^oG`>p3Y zdE+ns;y~Y?{*-4MPI>*^w>;u+NCEiTH@N(+1R*`xLr!|5_a-IW$o{v$Pw6>M$^4jIdn5CN9?L zx~v(3>w3sgxiV%SjyPWvP_IOjc76JQNtifW^-fTbSftr3fUvA4$~7*fv}(1S%x+f$ zZjlzfG^m-i=>Bk#oE5z!2(^un=q=iD#;J#^osDoWD%p at jNN#lMsjD9ZXJJ(%Te)v~ z at U#h&8w!@t4o{jMgM9eDll^xE%D8LUhPNE}++*DCyydl-xk}H* zcFnY=c1rOFS>vn}mx at a91Xldpa2z%$Qp%mC%!SuT_q97Y2vCetXU+ at H;g!7_&5uJ< zAP+S9?z``j&-kGaesG|4jt3t9{jrbfr0s2wx$XS^|KZ2JZ#;ru^EJ;3!M3Qs|Lo^B z1oEAOlSxH%f*M>(x-+H5N{MM%0} zdP)RJ>< zD1PR;VouOOw>Az`(p;elow?((R!Gq?@K-Dq-Gl0i={ zYK=t&>m=*)*qAHY21oZ)?5HU#7EWcE-_>IFasj8vA4NL=o6Y5RLK9XzP5(VDH6W;( zAMa`sl#X93g-6=5*2Te#v}TUF<9?8oc>!zx~_4EkAkJU3WEK zMAUoU^B(#7SA4}&jEcT~htGP}%Km-RFa6R6g^y3efL;t5l0WbJx4%6I5 zu_7`WP8K2EulymjiHA{f#6*U15UeqI0~d!+>O5aHO$1^Hxb$^Qk+h@~bOV(lO*evY znI{A<^bTgd57T+oPU|P|r`a#%EfikG0 z6+8}B%ujxGm79MxnaMxvP1|)br+>cw{(mH|@YpZ-()!%b{oJa$wx4;++h1#UH)%F^ z>bS zU7 at 80$b)3kn?nl-FBn-Dr&`6tl0Df2Mj8J#yu4P3ar^8QsU>x(*YIe}an0HSZ zZ|Y(1n-+VTLz~_@%w`S2hMnH5kYXVSo1sByg$WruK6Lj_Ti3DCpKyV&sOAM+|E+=M;KdPq1cJs8&yx3Cawj6-I65He{bK z^XjzN)!-YZtr!~4Gy&^Amec|Z@!BWZ#4(%$V at Dw2+4QjK-AH1E962tO8NS~{YpQIo>hF{e6_d%OngP7)$a9=W+w!KQh}Y@;)WlhRpXp>t0zI z&${ovh5o(iO&18)b~Pe8=U6JXn+?N{-y(EEY$1*b9s`LM+5bdf7Je_3AKRinNb?0hIBxT3QSEs zhxLm;TGm;UJKay6g>4Z+Grww6qzW8U)k_VF at wLT;6njeNzqT<#|3Wil7Kg zuzZR8SK#+lJ4(GgHra)-F8Reit591OZmRAUaw_{8u;)eyes_99O3)|O(N z{%+~_&>Z0Aet}q6z;@0Q at rDp;x5ul3sZ(S=w20f`d)#y$^BVP{?OpHEyx=eX;=Agz z|LZ$fL3rPye}733LoaiAVZL_?MzBGZA;wV{STL*stRO?_za_ngojmu-DaO^kR1^aX zXbDJ{!W%ETWmQtq*GnE!$&Ne at dv^@KSr*t7qk2SF at -@P=W*r5(m^xQAZ!@lmW?0e$ zO)FdiB&h8Q)<6pT!leID@;1bJ32ONJ^mebkT at NQ^JEOW6g?PaK;yE8fFIv~vMh3H! zd<{L~vf83(k6ma9|TvclbY)EWaszLvT at 6QI=HnWz-q0Z?1RRb(`U zZpuvIItq@^_QanfEl+VftfG;|l$_|oV z7;AAnoYQF9;)W_Aw!c&<1#22CH>%cy!|2k8p}#Odw$s zvW|eHmCZp5W(fcWHOYY{CirE-0sb1WFtVI2;uP&Ix7?yv15xNFImPiDn>AAui_s4s$Ow)X1GBll>(dsqij4p6C|jI zEg?+RNg+41+~K}x`oM__uC#;T%UBbYIj`?Ss`sTUn9R5kT#d)fzD>yo44V$mDQU4M zA%qrmNr2wBr6ug(O3-#wNwN|N9j> zH5nMg6W(cBK^C-oqd^Nn)pJVY&p0;AOl8 at C#qu>f_IJ=xrLY4r7*+NTyB*@gc>0W- zYkEZYUpWUQD70K3Ru-EvNaRQ}oen}~Vs!UBX~jTyS^g`{7sr{XPU*Q5hIX@@OV9ou{XK1=GR2-BC9C>HoNNP#F5D;#^eHw+GuBkz^z3Ui-aU>j^i{ zKTtK)nf)4Y01Q%J0Zy>+JgEH~5N$mA2xO- zq#5wG!ds|EsKrrFZJ|Hl4PIyWlj=4&+ZaLi8nZo{I4McMhu%=h^$3lwUkrSYN8Ba1 zKoRbZD>d7UCRro6es*9T9i}$0BdU|Ck)09FO(sJ{Yh>tyjjd<}Yhu;T@$i<9E+T2P z=3*m*N{0DB(2`j*#!35P_zt4fPDrfNE0M?;n6(y-*jxyVpFlwBv_L};`eemfGHt;H z!n21f^wt&TdNB>ExwAT{ss|r at P`>iG$33q7EJe=6(x&hD-s8{lT2A2p$jg3ctn!z> z^rh$D-}~P8)?fbBUxvaB16;T?F`fwXbb8I9XL6bIM{7x}Zr|znzE3MSVag(3^ zQOlUQ4-C)_y7D;{$%sUweS0P{JUggVE9hCl$~E`o1X#1HVyx{%mDx9-7pBab&-tvI zr%WX?ZD?{t`@I-iCm3BxJ?R=p8|@}&CdLC`^1l{K5Q;Z(3Jj5HC5;>d3A`&$+_rlC zdD$yoGSIm at KJ)HKhNG3s&wBblke~a|hdxyA{@r&46qNP<{(t{Zz5o4xB;Wt&M?d=f z`!E0UFZ-z~D5dKvYlH1EpmVwK-3bj^O at hlbFvd>k|K(ZK2L-I>>sTx^1l_bkgutsa z)~s^Omgw5dF$W0s83lde5(}-UGCv^u;DGE$R7!Vj5{!}4V?vLihICsGq8)V1NsPhR zcR7C0ll)re038Sj=bpa)#-N+5C~RO>iJeGQYY0w+prM4l5fEa-hFMTX$w_^$dQv2M zv+I>icX}2hutWjT8!qGsFTOfGPaEX1q6B?XlAMh|)v0}}(nAqeF)$AO*M_WVV)a3F zVQMaoKAKy%N;5oGkIffw_Uw%1sOz?(z}p9I%x363^xOT35r$(LHpou8CuV+OHed~G at Uk|aa}OBnt`8v^>%`$@=e8X_+=8(hSvq~r?RvyU zM+VD*oi at v<(DFUT&7iCDtgSbODf1?+_f8_4+0NLVTqpT6Kl3y4JHF?8z9*EeiiCds z*MGhI%#Z*0k6VVa?qWatvp*M0vX6c2WA&3i_i~|ru_=6algoWLXFma40fDYE0Y{{B ztEyh`yzkp0*cbz`bIzg;AHb+f?_CkCi}Az^geV{cEek_*T5C6l`LHuMO_3WMq^hfS z>D(RyZ!V*}Q+dJeI-S$zYfterEciZ+lTkC>KWOtk7~$DWny3CqP`lgHp9;t at 8k_cN zs8cbL2S}Tw#LSdEwWA{_{pQnk9V5yXtv-{A7QoQ0JSBEK^xeq1ss at TT(@t9FCX>jl zhi&K$nLUuB?J#JYE~mNQcG<;ZJgLa>K{r#!9j6z(HcCk5lXC62%}ph=2-HN8vKU0G z5Jq$#&%EYYT-FU`jv>V;7^;YwqS{R`;Py3OMzeYXOcSNX@^_dFTYc;XYESl{&DzCb{x{t7?v-TzeR-v=LjuwMPM zFWcg7RaLM4*_XwC|Cj&r*G3_yrZ*gsb_luy&un?P;=x>(t^DVWp0VVbbf$&jr^gcx z#jdZ$W9pJ6YwOoEAJm`Bc}q4rMZ$M`S_G#JLxl(~(^t{7Lh?An?MNyV18V5$(`0IP zs)6arLodZCEmWgt7&rI&fk4$j8T+)MwAjq-f1c#3nH5zYWd*bBsJWC`f!eSK&rdl& z>{20t<@*Ru`-9rpqD%liEA|gBL07nNWX3=bGx( zKfm!Czqvs;AqFc_9%An6+=R#N5I`;0=2ZAQ-}P4csXOnyvtIjCZ>c9d?kVTb-}cDQ zu>BLGj2Gnf{%`;EvxZti at g$TFnjUs3=`QjEn)1+)7W64s0p&boyoR(765wrFxJiHH z)03VpDlt<*=)#TEldR-}L{^R~3qkT^DtLINOQ4zD=2yjLI3kSQR?=s|G-wRm6(Tr$ zUIPQh7-U$Z^CV`R8SV36NA(3$@jhJBP!C`ttlaHsyF6K%g*UlXY*e6_DB4eGZfUDJ zxH)Ogqm||wPpA<)Cw|(!{nR>Xb3;uL5C?$<1#3+~(j%jpfTtl3KO7ju>GrIhAFD|_ z%*1XL55-|Yl(l$$pJDqNV8`9K+ zym#x{NK;SNJzfXcnA8uO{3>1Hs_3HNhRHC5kzSruGY4_(>9K!Zg<1amal9`eq>y;f zM?dn@>nHyC|6F(8d1w7~{yg~LgY~rg{*GMB`S z!diz+I9FADd`8)9=)4yol6JE-&sZN`I6uz?Z3xauF?s|Yr$Ej(-*G}iwIkl)9o8Hp zCF92apzV4)=YJa1uG&Y>4-G`G3p-6i8IL2Vy6&yWQ7LB_jl6A~ZuVseBTkcNKp#rzqd!U> z&PKpR1|vO=3H{Py-_bsVa}yhD4x)kzPQQ2NWFXpuOmxi}#!yy9#8gsy(S%D7YZo_4H>vy}ta*zq~&AlRsI0>cb!Y za6S0ogY_$K`IY+Bcm2Xp at lQ&9J(I70^Q-H-zU#Z{QIC35RaO1^umAcWtSgwg_zw4$ zxBN=|&hPwA#0~pBe#I+Zu_?zm(9|@2{DUw3&U*hJ|J!=T)1O{<-g)P^7P{Vc7@O5$ot|@geH}H>!in)Q#K^#HS;??b zUZg_Hxx1slapd^|vLy!u7b4^cM(rU#bHJD(JtNWnC`Kv{G$?e^Pt|bSVBE-X^ld)SpwSVpqocSu#r^C>><$g~*tX*o8Kup^=C0^ueaM9Yn?5z_t(RA9COn)5(Dka2pTS+RTWL@ zm2TXjfZUdF5C6%-v#y+52tu0xOKr+!+S8`mJZ}6%!g(VRrHEghy2 at FeUn;o_mfD8s zF|5oA*KOW26a!_i&yZf%tFD_%pmFb3W=Gd33ugK#WaFqR!eM<@W!^UE3dE+ScWmoY z<=f at lSVNzXih>%sroHQ-`I at t`mdz?(v?QN zmBmQlG;9XKTq$g+4f~ZIp~Z2}>gKRTxFs0Ri_4{NnvxNu8~`tR1R`W8jY(5v*_-Fbg1j%LBCdO9s?$ZnC7@^%!(nP2R+tWd zKGa6PqG>H0NMjg4vDmPr1k_iirM+OFIa)d)XwAZB8Yo-Bg=$cl`jqu4*tS06Zq3Se zH&fLc2heIhOPAadQ2_)9Da9r48|8y2)A$NCJu8?cDg*0dB+2{tK(ab&FrNPSGnld= z{_cFwr?a49qE{ot+s3odBZq*|!R_v$zU+!TTZNNLBU)-l6lks#M at 1YM2tkOjoyYCk?j(8{D at oRSvkespCNEG1`CKy_{q z%__}CWp{mV)H&_ZWm(*tLPf)>fHwOS44F^+l$r(CaJ?Zm2XQNg$zUu%)f53M2Cm;~ z21^Z^kuuyWLK`s#)Rt5GKR=I>#-rY6TG&jnM_Sn8guf6r0*488>QagU`18Bs;3|3t zrnDC;48ryX_eJb`kQCv}OvE_4L(CiJbD_g8Tqzcqe)HoH2p)Sn;A8tt8VGI&0Y*&a zEH`ASbURDzn)RLVos&V~?zp7Nk|Y|2>Z97r1Fk_4SUGlno`=>4IEGYWY7_bpO!>p< zJ3`ICNQOeM&ygxI>o7sCwKtxc5xhZ26ZU|xj;2verja)D*!t~LQ<6<&8Zkj6)H(Nn zaaw5;M0>LRlj&>Ga5;+G2DbPwDrHb5yX9$BT_IvXr**4I=XU5NL+Qx!RFGl3)>g#2 zMpxP)EsPz9K>0XT05!^Fg?T5M#7oE3S0=9=5bXfK#uIaCZ=uv!Pnzfj%NXl*dxJXd zJ=mcVQYQb%*pOQI#e5KlC}`99>fWd at anJXJ9mcdxl}Xt_G~XX9aA9;-G&ZInZZn~x zoAIoJoHDG_Cct6A;K4As|18ax at Dptnciu3Pt-5>_MCP90Bl zqtsK*Qgn2=x1+;i=5+Dl^v&ZAj_Pq&4bp?c{h0~qhgP4A4yeGOS-Uik4!Sss$w(KE zp|qQ3vY;kOJ%bG9eRmd{H;4aja#$FFE-64aWuU~9VRIsnCL!hS_U9@(S3yqEb4LYZ zQQs|~;w2PSg-p;iN_j`$Q==F?+EPs3X__?HW6m0(X{e!e>$(a6(r~hN5*EV%v9!f( zdjf-bd>;nMp=zGzJ|jA{Jeh=Mj1p{?A_yw;8c+HxR1lCW)NUOyP=*Xix9(yH`}Bx7 z*_;eVEDRIsR#tR{7H^<~o67=_Go$0(rkq$9%^VPpO7StZAa- zPaFc)H_vlzGOpjj)%j*jW5zBRYDGvl5=_!0uon#;6_XEG8lp1cR?{UN(LYJN-pz2) zV2ushryd#(3{s=NP$NFcVI*kzR%yU at 7{BA_M*EZ`%=HgmGg~oNmap6%!7e&xv}8-R zd*!lO`Cd5iA2u6!j1uMt0ET0h)a at H0H(8vd&o!tGORYe4TD$^+Y0gzWan5A0>`0CTr6A5N zO3Typ!CSU0iBr;mPR&z0~`F-$h6r#+a9Zpt&Fd+x9jOEbWnpA>G1TBW+?bzi+ z(U}M~dW{d!x=zVPjiTGL#udXtOHxs(NMb*jl5DBS at c>~j`RRIV$Tc;s6f|^D4K)wv ztwHP5)FBXtiT+blUqrkpHD0|GaDvw9&1~{MO at e7=(2Pm3iPnMK>pr8Lsd1Q7-7J5q zrgvTby)bMGn`RYOnD6sddfM)^dr?%j29lU)S60QMI+5&3%VrrD0-oqknPP#7yhf$u z=^G7T#Y4LZhS2BoIAWC6w?j~ZN(P>;)2R at qO%ICcF>)T;R+0gE>e4!jglWJgn|h<^ zTFo1VOuKV^6zt4`xN3yg$Md&wofOSh^Di>GKI+(-y8pZCS#yUYa;gEk`> z{8q(-)&=_5)g-8~Ob3s5HWADO$*AEt>0W>BzGcf4w$iQ1FRasYg1#P;>0Og0GCs<5 zC1})ubI4&+5!8)T6cy3 at WDJcUAXH+2>$%!)xk6PXO-CV)$>Bc0126Q(0NI5O1B#lC zp#y)U10r at d5#gX8wo8~n8$(&u{4h2N)mN0Pse^7qgwUXLF<=sl5 at jU@-kL=R z7~0uXey2i;8)}=Cjh%M^)|*Cb%nf8$N3V-uPZ&dTh@*{&GJy5xO2PW3>**rmei}1e z_ER*iyX(0L^unfXX7G)jsI1AOQD&6GoBKJTWka_{4&qf=}$4lDI(`oU^LuESff#*l~T)(pk+2aX=poN?NG=z*II2Bu?{!eFEC>$Wz+3~;6R zzz|PZu5R}X*HjH^It`Xwgn-ic$qe3f(;X4Z*{KZF)!cVhstjU5m*{=QQVEgr+$Cnr zNmvH at Rnen41j0d1veJ+Vj1;WUB<7h?r`iz$Ds(I53e{jgnKGlO#bf(9aLy!Mj7mOrjRDGOhzt>^Oy+K=A6_&BiCd*Y`;@}$ zqV1Bi0~*C!uiju_H8B+_aH0Q>R#~xSS}D(^-46v?Clblzu at l;|-`M|fBM?3ccI at sK z6^88yFHDpsNP$lp4>A2rx9qf2^u_6 at _eN(oQC3K9>QMS)7C1T-p_{5S9s*69-=)N> zaf}nQ=hNDK5}O at E1_>otx`wwGAyeO0W6#kdEFsa;SbHl2*rAnY`i1R#7LPYwW;6k{ zoQ9;j2zcMOvnW~_!GUq0B_M^u8-0MxG}?6Qhnn?1Ob2QXs-wFTB$Br0w*p-Ydx}g& zs{hJt!u4BrpTCgVK75BbqVzD>fjI_{EK^eUGeS$9X<;^TK1IP+f|g<6Lpwv3sS(Ur zo at UBpBrr3Ma?CSQN3j@@yP0ajI1qt|h9*^8RZ3 at urJl@YeWI1_ at RzM@CW1KUZf(D9 znaD{9Q0A66Q-J-6sobc}pvnt_L+gECiEb(@V)K+#sb+^TRTH$+mF0ujM6}7PCe}9E z$fs`lCaMD)H0^(&`e5i8H_Q?yjddae9T{npEH;}Gke2HX6*LS5{e7|W#5L7wMTR++ zzmqcD6Z6?}H0vAqXj`rM$I|9 at fElHE2C!-(Af%taTCED!+QRhqoUb|lRV3E~q< z+AMnZYc((hJ__fAURZfSunopMaOHL&cvDm%!y}YgD77J6YZP{jSfra--4~`~IVDaw zbAqXlYMqU%@7ylb=3 at c$ibI3~&8x at sib#rME#OKXEXbqK+G8`CZ{E<3i{?voh&Ct_ z0X!8kN^f4Mp){^#e#Ys}IQm-)uGrU^O`fYhlM08aLjtAs18?K(Qn6>TZ$&qzm<=K# z4f~i}4oOUo;;J>wzIJXWqFKMoa_lKb4wXl&37s}r6ZSe#6f2u4)Q6xhxd_9XKQAC! zagZZF3UY-|17mvJ-IeEi03XR9u2O{T zWc6aGp>?QtEG=Rhj}W#C^v}&b7qlh9is?>_c{Ayk_DQ$xTk{O;6a)4$ND&t7bNU4l%v2brqI>SgM?E at u+V}{Uy#rZ2CN>-iFHTCg zModW_K{@>1qJ^9lJLhzZS}(T7jx;~tEoOQ=AOo1ArID7k0;Xa6%63II1q}(Q2=W(W z^g46!hNT#0e+pT}TDTnrC?npNl7noP8~(wC|&rZ$@bUzbVXbczF*0~_# zwC+y>y;0%1eJ|vbHVygkR-ZM>@21VIq at kfHZvL|m`V=0}%z~ST8w|Zl)R)J=xfFP$ zoqaxp=HN@~hr>yitHelz(np?~>B~y$xjz*S4kS;kbC1Yz+*K at mkVAtJ+WkSjdoF!y z$R%t-#B$AYbiPNmD6Bp$nf<3UIvVPIeXrz??`(mhsX|!IV9AWc(gT>Y;Z(|IW;sW@ zQ^q!>6|RVO$=9Q>Uwdn&7$dxWP~c>ExtVEU=&&CO6+T#9gO#(Ch^ETv?Fo#c|AAt!hy>A>?Wpi{GTq#czU?Rx6kD*Zbq(T)#CFeR8g_!e~u zJjT4lMv7?a=YslSH93hc5wJp(FvR^tUB+<|$BT(bnQ6(IU>OqcLAK9Pyx5ug&I~>z zixu at o4&BJS|3xU10&h6m^<@Z3QX`Bb|MQ!$L*q3!2G=-!Ie^|6YR#M)SJJzs%QuHb z&ed_xjB&qRuB2t*4`U2qk3KUG^?A^ExzV21m6&RSphRgkJ2iBMJ#o%>u}OC8 at i!A4 zc%fKHddHRpcc1V?i=s+2D~IG1y_-BZHSB@(1eITYBU6g2`!abxFK at IIizPO5<6YA$ zb~2T|_Zov7i3t%h`Y}aD7S8xhbhz^U^!IwRMR86(3Kw6vmIMObAI0^wSoat#rPQY!}2 zLW^OXgOU{7nO(`M6%c)mGQAMkF1#~gaO~zH^jsP at 1FS!KdPo)-sgx} P00000NkvXXu0mjfKlN_; literal 0 HcmV?d00001 diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in index c634a58..d7424c1 100644 --- a/ovirt-node.spec.in +++ b/ovirt-node.spec.in @@ -70,6 +70,23 @@ Provides the oVirt Node functionality needed to convert an existing host into a Node in a stateful manner. Presently intended for use on the host running the oVirt Appliance. +%package logos +Summary: oVirt Node Logos +Group: System Environment/Base +BuildArch: noarch +Obsoletes: redhat-logos +Provides: redhat-logos = 10.0.1-1 +Provides: system-logos = 10.0.1-1 +Conflicts: fedora-logos +Conflicts: generic-logos +Conflicts: fedora-logos +Conflicts: anaconda-images <= 10 +Conflicts: redhat-artwork <= 5.0.5 + +%description logos +The ovirt-logos package contains various image files which can be +used by the bootloader, anaconda, and other related tools. + %package selinux Summary: SELinux policy module supporting ovirt-node Group: System Environment/Base @@ -156,6 +173,15 @@ cd - /usr/sbin/hardlink -cv %{buildroot}%{_datadir}/selinux +# ovirt-logos +# should be ifarch i386 +mkdir -p %{buildroot}/boot/grub +install -p -m 644 images/grub-splash.xpm.gz %{buildroot}/boot/grub/splash.xpm.gz +# end i386 bits +mkdir -p %{buildroot}/usr/lib/anaconda-runtime +install -p -m 644 images/syslinux-vesa-splash.jpg %{buildroot}/usr/lib/anaconda-runtime +# ovirt-logos + %clean %{__rm} -rf %{buildroot} @@ -203,6 +229,14 @@ fi %doc SELinux/* %{_datadir}/selinux/*/%{modulename}.pp +%files logos +%defattr(-, root, root) +%doc COPYING +# should be ifarch i386 +/boot/grub/splash.xpm.gz +# end i386 bits +/usr/lib/anaconda-runtime/*.jpg + %files stateless %defattr(-,root,root,0755) %{_sbindir}/ovirt-awake -- 1.6.0.4 From apevec at redhat.com Thu Dec 18 22:38:11 2008 From: apevec at redhat.com (Alan Pevec) Date: Thu, 18 Dec 2008 23:38:11 +0100 Subject: [Ovirt-devel] Re: [PATCH node] Add ovirt-node-logos to replace grub fedora boot splash with ovirt specific splash In-Reply-To: <1229636086-26978-2-git-send-email-pmyers@redhat.com> References: <1229636086-26978-1-git-send-email-pmyers@redhat.com> <1229636086-26978-2-git-send-email-pmyers@redhat.com> Message-ID: <494AD0D3.7070609@redhat.com> ah, nice green colour finally! ACK > images/grub-splash.xpm.gz | Bin 0 -> 51388 bytes this one is not used, but it doesn't hurt either > images/syslinux-vesa-splash.jpg | Bin 0 -> 204721 bytes Note that this is actually PNG 640x480 - no idea why it's .jpg but this is what fedora-logos have and livecd-creator expects. "source" for this image is in ovirt-recipe.git - resources/ovirt-splash.xcf From imain at redhat.com Thu Dec 18 22:42:08 2008 From: imain at redhat.com (Ian Main) Date: Thu, 18 Dec 2008 14:42:08 -0800 Subject: [Ovirt-devel] [PATCH server] Taskomatic Refactoring and Qpidification. Message-ID: <1229640128-5443-1-git-send-email-imain@redhat.com> This patch reworks taskomatic quite a bit. This mostly just shifts taskomatic to using the qpid interface in place of ruby-libvirt. It also fixes a few bugs I discovered a long the way and adds new ones I'm sure. The only other thing added was round-robin host selection for VMs. Wherevery possible the hosts are queried directly using qpid rather than relying on states etc. from the database. This patch loses about 150 lines from the original taskomatic and moves most of the task implementation into a central class. This was done to provide access to the qpid session as well as providing for locking/task ordering in future versions. This requires the latest libvirt-qpid (0.2.7) as it fixes a number of bugs. It's in the ovirt repository now. Issues remaining: - libvirt-qpid migrate is broken. Since the migrate takes place on the node instead of from the ovirt-appliance, the source node doesn't have the ability to authenticate against the destination node. For this reason I'm still using ruby-libvirt migrate. I talked to Chris about this and we have a plan worked out. :) - I wanted to get threading into this but that will have to wait. I'll post a thread about this to get the discussion started again. I think the refactoring allows this to be put in pretty easily. Signed-off-by: Ian Main --- src/task-omatic/task_host.rb | 33 ------ src/task-omatic/utils.rb | 221 ------------------------------------------ 2 files changed, 0 insertions(+), 254 deletions(-) delete mode 100644 src/task-omatic/task_host.rb delete mode 100644 src/task-omatic/utils.rb diff --git a/src/task-omatic/task_host.rb b/src/task-omatic/task_host.rb deleted file mode 100644 index 3d039fb..0000000 --- a/src/task-omatic/task_host.rb +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (C) 2008 Red Hat, Inc. -# Written by Chris Lalancette -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. A copy of the GNU General Public License is -# also available at http://www.gnu.org/copyleft/gpl.html. - -require 'utils' - -# FIXME: a little ugly to be including all of task_vm here, but -# utils really isn't the right place for the migrate() method -require 'task_vm' - -def clear_vms_host(task) - puts "clear_vms_host" - - src_host = task.host - - src_host.vms.each do |vm| - migrate(vm) - end -end diff --git a/src/task-omatic/utils.rb b/src/task-omatic/utils.rb deleted file mode 100644 index e3005ed..0000000 --- a/src/task-omatic/utils.rb +++ /dev/null @@ -1,221 +0,0 @@ -require 'rexml/document' -include REXML - -def String.random_alphanumeric(size=16) - s = "" - size.times { s << (i = Kernel.rand(62); i += ((i < 10) ? 48 : ((i < 36) ? 55 : 61 ))).chr } - s -end - -def all_storage_pools(conn) - all_pools = conn.list_defined_storage_pools - all_pools.concat(conn.list_storage_pools) - return all_pools -end - -def get_libvirt_lvm_pool_from_volume(db_volume) - phys_volume = StorageVolume.find(:first, :conditions => - [ "lvm_pool_id = ?", db_volume.storage_pool_id]) - - return LibvirtPool.factory(phys_volume.storage_pool) -end - -class LibvirtPool - def initialize(type, name = nil) - @remote_pool = nil - @build_on_start = true - @remote_pool_defined = false - @remote_pool_started = false - - if name == nil - @name = type + "-" + String.random_alphanumeric - else - @name = name - end - - @xml = Document.new - @xml.add_element("pool", {"type" => type}) - - @xml.root.add_element("name").add_text(@name) - - @xml.root.add_element("source") - - @xml.root.add_element("target") - @xml.root.elements["target"].add_element("path") - end - - def connect(conn) - all_storage_pools(conn).each do |remote_pool_name| - tmppool = conn.lookup_storage_pool_by_name(remote_pool_name) - - if self.xmlequal?(Document.new(tmppool.xml_desc).root) - @remote_pool = tmppool - break - end - end - - if @remote_pool == nil - @remote_pool = conn.define_storage_pool_xml(@xml.to_s) - # we need this because we don't necessarily want to "build" LVM pools, - # which might destroy existing data - if @build_on_start - @remote_pool.build - end - @remote_pool_defined = true - end - - if @remote_pool.info.state == Libvirt::StoragePool::INACTIVE - # only try to start the pool if it is currently inactive; in all other - # states, assume it is already running - @remote_pool.create - @remote_pool_started = true - end - end - - def list_volumes - return @remote_pool.list_volumes - end - - def lookup_vol_by_path(dev) - return @remote_pool.lookup_volume_by_path(dev) - end - - def lookup_vol_by_name(name) - return @remote_pool.lookup_volume_by_name(name) - end - - def create_vol(type, name, size, owner, group, mode) - @vol_xml = Document.new - @vol_xml.add_element("volume", {"type" => type}) - @vol_xml.root.add_element("name").add_text(name) - @vol_xml.root.add_element("capacity", {"unit" => "K"}).add_text(size.to_s) - @vol_xml.root.add_element("target") - @vol_xml.root.elements["target"].add_element("permissions") - @vol_xml.root.elements["target"].elements["permissions"].add_element("owner").add_text(owner) - @vol_xml.root.elements["target"].elements["permissions"].add_element("group").add_text(group) - @vol_xml.root.elements["target"].elements["permissions"].add_element("mode").add_text(mode) - end - - def shutdown - if @remote_pool_started - @remote_pool.destroy - end - if @remote_pool_defined - @remote_pool.undefine - end - end - - def xmlequal?(docroot) - return false - end - - def self.factory(pool) - if pool[:type] == "IscsiStoragePool" - return IscsiLibvirtPool.new(pool.ip_addr, pool[:target]) - elsif pool[:type] == "NfsStoragePool" - return NFSLibvirtPool.new(pool.ip_addr, pool.export_path) - elsif pool[:type] == "LvmStoragePool" - # OK, if this is LVM storage, there are two cases we need to care about: - # 1) this is a LUN with LVM already on it. In this case, all we need to - # do is to create a new LV (== libvirt volume), and be done with it - # 2) this LUN is blank, so there is no LVM on it already. In this - # case, we need to pvcreate, vgcreate first (== libvirt pool build), - # and *then* create the new LV (== libvirt volume) on top of that. - # - # We can tell the difference between an LVM Pool that exists and one - # that needs to be created based on the value of the pool.state; - # if it is PENDING_SETUP, we need to create it first - phys_volume = StorageVolume.find(:first, :conditions => - [ "lvm_pool_id = ?", pool.id]) - - return LVMLibvirtPool.new(pool.vg_name, phys_volume.path, - pool.state == StoragePool::STATE_PENDING_SETUP) - else - raise "Unknown storage pool type " + pool[:type].to_s - end - end -end - -class IscsiLibvirtPool < LibvirtPool - def initialize(ip_addr, target) - super('iscsi') - - @type = 'iscsi' - @ipaddr = ip_addr - @target = target - - @xml.root.elements["source"].add_element("host", {"name" => @ipaddr}) - @xml.root.elements["source"].add_element("device", {"path" => @target}) - - @xml.root.elements["target"].elements["path"].text = "/dev/disk/by-id" - end - - def xmlequal?(docroot) - return (docroot.attributes['type'] == @type and - docroot.elements['source'].elements['host'].attributes['name'] == @ipaddr and - docroot.elements['source'].elements['device'].attributes['path'] == @target) - end -end - -class NFSLibvirtPool < LibvirtPool - def initialize(ip_addr, export_path) - super('netfs') - - @type = 'netfs' - @host = ip_addr - @remote_path = export_path - @name = String.random_alphanumeric - - @xml.root.elements["source"].add_element("host", {"name" => @host}) - @xml.root.elements["source"].add_element("dir", {"path" => @remote_path}) - @xml.root.elements["source"].add_element("format", {"type" => "nfs"}) - - @xml.root.elements["target"].elements["path"].text = "/mnt/" + @name - end - - def create_vol(name, size, owner, group, mode) - # FIXME: this can actually take some time to complete (since we aren't - # doing sparse allocations at the moment). During that time, whichever - # libvirtd we chose to use is completely hung up. The solution is 3-fold: - # 1. Allow sparse allocations in the WUI front-end - # 2. Make libvirtd multi-threaded - # 3. Make taskomatic multi-threaded - super("netfs", name, size, owner, group, mode) - - # FIXME: we have to add the format as raw here because of a bug in libvirt; - # if you specify a volume with no format, it will crash libvirtd - @vol_xml.root.elements["target"].add_element("format", {"type" => "raw"}) - @remote_pool.create_vol_xml(@vol_xml.to_s) - end - - def xmlequal?(docroot) - return (docroot.attributes['type'] == @type and - docroot.elements['source'].elements['host'].attributes['name'] == @host and - docroot.elements['source'].elements['dir'].attributes['path'] == @remote_path) - end -end - -class LVMLibvirtPool < LibvirtPool - def initialize(vg_name, device, build_on_start) - super('logical', vg_name) - - @type = 'logical' - @build_on_start = build_on_start - - @xml.root.elements["source"].add_element("name").add_text(@name) - @xml.root.elements["source"].add_element("device", {"path" => device}) - - @xml.root.elements["target"].elements["path"].text = "/dev/" + @name - end - - def create_vol(name, size, owner, group, mode) - super("logical", name, size, owner, group, mode) - @remote_pool.create_vol_xml(@vol_xml.to_s) - end - - def xmlequal?(docroot) - return (docroot.attributes['type'] == @type and - docroot.elements['name'].text == @name and - docroot.elements['source'].elements['name'] == @name) - end -end -- 1.6.0.4 From imain at redhat.com Thu Dec 18 23:52:36 2008 From: imain at redhat.com (Ian Main) Date: Thu, 18 Dec 2008 15:52:36 -0800 Subject: [Ovirt-devel] Re: [PATCH server] Taskomatic Refactoring and Qpidification. In-Reply-To: <1229640128-5443-1-git-send-email-imain@redhat.com> References: <1229640128-5443-1-git-send-email-imain@redhat.com> Message-ID: <20081218155236.76768f90@tp.mains.net> Doh, I screwed that up, sorry.. reposting. Ian On Thu, 18 Dec 2008 14:42:08 -0800 Ian Main wrote: > This patch reworks taskomatic quite a bit. This mostly just shifts > taskomatic to using the qpid interface in place of ruby-libvirt. It > also fixes a few bugs I discovered a long the way and adds new ones > I'm sure. The only other thing added was round-robin host selection > for VMs. > > Wherevery possible the hosts are queried directly using qpid rather than > relying on states etc. from the database. > > This patch loses about 150 lines from the original taskomatic and moves > most of the task implementation into a central class. This was done to > provide access to the qpid session as well as providing for locking/task > ordering in future versions. > > This requires the latest libvirt-qpid (0.2.7) as it fixes a number of > bugs. It's in the ovirt repository now. > > Issues remaining: > > - libvirt-qpid migrate is broken. Since the migrate takes place on the > node instead of from the ovirt-appliance, the source node doesn't have > the ability to authenticate against the destination node. For this > reason I'm still using ruby-libvirt migrate. I talked to Chris about > this and we have a plan worked out. :) > > - I wanted to get threading into this but that will have to wait. I'll > post a thread about this to get the discussion started again. I think > the refactoring allows this to be put in pretty easily. > > Signed-off-by: Ian Main > --- > src/task-omatic/task_host.rb | 33 ------ > src/task-omatic/utils.rb | 221 ------------------------------------------ > 2 files changed, 0 insertions(+), 254 deletions(-) > delete mode 100644 src/task-omatic/task_host.rb > delete mode 100644 src/task-omatic/utils.rb > > diff --git a/src/task-omatic/task_host.rb b/src/task-omatic/task_host.rb > deleted file mode 100644 > index 3d039fb..0000000 > --- a/src/task-omatic/task_host.rb > +++ /dev/null > @@ -1,33 +0,0 @@ > -# Copyright (C) 2008 Red Hat, Inc. > -# Written by Chris Lalancette > -# > -# This program is free software; you can redistribute it and/or modify > -# it under the terms of the GNU General Public License as published by > -# the Free Software Foundation; version 2 of the License. > -# > -# This program is distributed in the hope that it will be useful, > -# but WITHOUT ANY WARRANTY; without even the implied warranty of > -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > -# GNU General Public License for more details. > -# > -# You should have received a copy of the GNU General Public License > -# along with this program; if not, write to the Free Software > -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, > -# MA 02110-1301, USA. A copy of the GNU General Public License is > -# also available at http://www.gnu.org/copyleft/gpl.html. > - > -require 'utils' > - > -# FIXME: a little ugly to be including all of task_vm here, but > -# utils really isn't the right place for the migrate() method > -require 'task_vm' > - > -def clear_vms_host(task) > - puts "clear_vms_host" > - > - src_host = task.host > - > - src_host.vms.each do |vm| > - migrate(vm) > - end > -end > diff --git a/src/task-omatic/utils.rb b/src/task-omatic/utils.rb > deleted file mode 100644 > index e3005ed..0000000 > --- a/src/task-omatic/utils.rb > +++ /dev/null > @@ -1,221 +0,0 @@ > -require 'rexml/document' > -include REXML > - > -def String.random_alphanumeric(size=16) > - s = "" > - size.times { s << (i = Kernel.rand(62); i += ((i < 10) ? 48 : ((i < 36) ? 55 : 61 ))).chr } > - s > -end > - > -def all_storage_pools(conn) > - all_pools = conn.list_defined_storage_pools > - all_pools.concat(conn.list_storage_pools) > - return all_pools > -end > - > -def get_libvirt_lvm_pool_from_volume(db_volume) > - phys_volume = StorageVolume.find(:first, :conditions => > - [ "lvm_pool_id = ?", db_volume.storage_pool_id]) > - > - return LibvirtPool.factory(phys_volume.storage_pool) > -end > - > -class LibvirtPool > - def initialize(type, name = nil) > - @remote_pool = nil > - @build_on_start = true > - @remote_pool_defined = false > - @remote_pool_started = false > - > - if name == nil > - @name = type + "-" + String.random_alphanumeric > - else > - @name = name > - end > - > - @xml = Document.new > - @xml.add_element("pool", {"type" => type}) > - > - @xml.root.add_element("name").add_text(@name) > - > - @xml.root.add_element("source") > - > - @xml.root.add_element("target") > - @xml.root.elements["target"].add_element("path") > - end > - > - def connect(conn) > - all_storage_pools(conn).each do |remote_pool_name| > - tmppool = conn.lookup_storage_pool_by_name(remote_pool_name) > - > - if self.xmlequal?(Document.new(tmppool.xml_desc).root) > - @remote_pool = tmppool > - break > - end > - end > - > - if @remote_pool == nil > - @remote_pool = conn.define_storage_pool_xml(@xml.to_s) > - # we need this because we don't necessarily want to "build" LVM pools, > - # which might destroy existing data > - if @build_on_start > - @remote_pool.build > - end > - @remote_pool_defined = true > - end > - > - if @remote_pool.info.state == Libvirt::StoragePool::INACTIVE > - # only try to start the pool if it is currently inactive; in all other > - # states, assume it is already running > - @remote_pool.create > - @remote_pool_started = true > - end > - end > - > - def list_volumes > - return @remote_pool.list_volumes > - end > - > - def lookup_vol_by_path(dev) > - return @remote_pool.lookup_volume_by_path(dev) > - end > - > - def lookup_vol_by_name(name) > - return @remote_pool.lookup_volume_by_name(name) > - end > - > - def create_vol(type, name, size, owner, group, mode) > - @vol_xml = Document.new > - @vol_xml.add_element("volume", {"type" => type}) > - @vol_xml.root.add_element("name").add_text(name) > - @vol_xml.root.add_element("capacity", {"unit" => "K"}).add_text(size.to_s) > - @vol_xml.root.add_element("target") > - @vol_xml.root.elements["target"].add_element("permissions") > - @vol_xml.root.elements["target"].elements["permissions"].add_element("owner").add_text(owner) > - @vol_xml.root.elements["target"].elements["permissions"].add_element("group").add_text(group) > - @vol_xml.root.elements["target"].elements["permissions"].add_element("mode").add_text(mode) > - end > - > - def shutdown > - if @remote_pool_started > - @remote_pool.destroy > - end > - if @remote_pool_defined > - @remote_pool.undefine > - end > - end > - > - def xmlequal?(docroot) > - return false > - end > - > - def self.factory(pool) > - if pool[:type] == "IscsiStoragePool" > - return IscsiLibvirtPool.new(pool.ip_addr, pool[:target]) > - elsif pool[:type] == "NfsStoragePool" > - return NFSLibvirtPool.new(pool.ip_addr, pool.export_path) > - elsif pool[:type] == "LvmStoragePool" > - # OK, if this is LVM storage, there are two cases we need to care about: > - # 1) this is a LUN with LVM already on it. In this case, all we need to > - # do is to create a new LV (== libvirt volume), and be done with it > - # 2) this LUN is blank, so there is no LVM on it already. In this > - # case, we need to pvcreate, vgcreate first (== libvirt pool build), > - # and *then* create the new LV (== libvirt volume) on top of that. > - # > - # We can tell the difference between an LVM Pool that exists and one > - # that needs to be created based on the value of the pool.state; > - # if it is PENDING_SETUP, we need to create it first > - phys_volume = StorageVolume.find(:first, :conditions => > - [ "lvm_pool_id = ?", pool.id]) > - > - return LVMLibvirtPool.new(pool.vg_name, phys_volume.path, > - pool.state == StoragePool::STATE_PENDING_SETUP) > - else > - raise "Unknown storage pool type " + pool[:type].to_s > - end > - end > -end > - > -class IscsiLibvirtPool < LibvirtPool > - def initialize(ip_addr, target) > - super('iscsi') > - > - @type = 'iscsi' > - @ipaddr = ip_addr > - @target = target > - > - @xml.root.elements["source"].add_element("host", {"name" => @ipaddr}) > - @xml.root.elements["source"].add_element("device", {"path" => @target}) > - > - @xml.root.elements["target"].elements["path"].text = "/dev/disk/by-id" > - end > - > - def xmlequal?(docroot) > - return (docroot.attributes['type'] == @type and > - docroot.elements['source'].elements['host'].attributes['name'] == @ipaddr and > - docroot.elements['source'].elements['device'].attributes['path'] == @target) > - end > -end > - > -class NFSLibvirtPool < LibvirtPool > - def initialize(ip_addr, export_path) > - super('netfs') > - > - @type = 'netfs' > - @host = ip_addr > - @remote_path = export_path > - @name = String.random_alphanumeric > - > - @xml.root.elements["source"].add_element("host", {"name" => @host}) > - @xml.root.elements["source"].add_element("dir", {"path" => @remote_path}) > - @xml.root.elements["source"].add_element("format", {"type" => "nfs"}) > - > - @xml.root.elements["target"].elements["path"].text = "/mnt/" + @name > - end > - > - def create_vol(name, size, owner, group, mode) > - # FIXME: this can actually take some time to complete (since we aren't > - # doing sparse allocations at the moment). During that time, whichever > - # libvirtd we chose to use is completely hung up. The solution is 3-fold: > - # 1. Allow sparse allocations in the WUI front-end > - # 2. Make libvirtd multi-threaded > - # 3. Make taskomatic multi-threaded > - super("netfs", name, size, owner, group, mode) > - > - # FIXME: we have to add the format as raw here because of a bug in libvirt; > - # if you specify a volume with no format, it will crash libvirtd > - @vol_xml.root.elements["target"].add_element("format", {"type" => "raw"}) > - @remote_pool.create_vol_xml(@vol_xml.to_s) > - end > - > - def xmlequal?(docroot) > - return (docroot.attributes['type'] == @type and > - docroot.elements['source'].elements['host'].attributes['name'] == @host and > - docroot.elements['source'].elements['dir'].attributes['path'] == @remote_path) > - end > -end > - > -class LVMLibvirtPool < LibvirtPool > - def initialize(vg_name, device, build_on_start) > - super('logical', vg_name) > - > - @type = 'logical' > - @build_on_start = build_on_start > - > - @xml.root.elements["source"].add_element("name").add_text(@name) > - @xml.root.elements["source"].add_element("device", {"path" => device}) > - > - @xml.root.elements["target"].elements["path"].text = "/dev/" + @name > - end > - > - def create_vol(name, size, owner, group, mode) > - super("logical", name, size, owner, group, mode) > - @remote_pool.create_vol_xml(@vol_xml.to_s) > - end > - > - def xmlequal?(docroot) > - return (docroot.attributes['type'] == @type and > - docroot.elements['name'].text == @name and > - docroot.elements['source'].elements['name'] == @name) > - end > -end > -- > 1.6.0.4 > From imain at redhat.com Thu Dec 18 22:49:49 2008 From: imain at redhat.com (Ian Main) Date: Thu, 18 Dec 2008 14:49:49 -0800 Subject: [Ovirt-devel] [PATCH server] Taskomatic Refactoring and Qpidification. Message-ID: <1229640589-5662-1-git-send-email-imain@redhat.com> This patch reworks taskomatic quite a bit. This mostly just shifts taskomatic to using the qpid interface in place of ruby-libvirt. It also fixes a few bugs I discovered a long the way and adds new ones I'm sure. The only other thing added was round-robin host selection for VMs. Wherevery possible the hosts are queried directly using qpid rather than relying on states etc. from the database. This patch loses about 150 lines from the original taskomatic and moves most of the task implementation into a central class. This was done to provide access to the qpid session as well as providing for locking/task ordering in future versions. This requires the latest libvirt-qpid (0.2.7) as it fixes a number of bugs. It's in the ovirt repository now. Issues remaining: - libvirt-qpid migrate is broken. Since the migrate takes place on the node instead of from the ovirt-appliance, the source node doesn't have the ability to authenticate against the destination node. For this reason I'm still using ruby-libvirt migrate. I talked to Chris about this and we have a plan worked out. :) - I wanted to get threading into this but that will have to wait. I'll post a thread about this to get the discussion started again. I think the refactoring allows this to be put in pretty easily. Signed-off-by: Ian Main --- src/task-omatic/task_host.rb | 33 -- src/task-omatic/task_storage.rb | 465 ++++++++++----------- src/task-omatic/task_vm.rb | 570 +------------------------ src/task-omatic/taskomatic.rb | 905 ++++++++++++++++++++++++++++++++++----- src/task-omatic/utils.rb | 221 ---------- 5 files changed, 1016 insertions(+), 1178 deletions(-) delete mode 100644 src/task-omatic/task_host.rb delete mode 100644 src/task-omatic/utils.rb diff --git a/src/task-omatic/task_host.rb b/src/task-omatic/task_host.rb deleted file mode 100644 index 3d039fb..0000000 --- a/src/task-omatic/task_host.rb +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (C) 2008 Red Hat, Inc. -# Written by Chris Lalancette -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. A copy of the GNU General Public License is -# also available at http://www.gnu.org/copyleft/gpl.html. - -require 'utils' - -# FIXME: a little ugly to be including all of task_vm here, but -# utils really isn't the right place for the migrate() method -require 'task_vm' - -def clear_vms_host(task) - puts "clear_vms_host" - - src_host = task.host - - src_host.vms.each do |vm| - migrate(vm) - end -end diff --git a/src/task-omatic/task_storage.rb b/src/task-omatic/task_storage.rb index 19800fb..802a573 100644 --- a/src/task-omatic/task_storage.rb +++ b/src/task-omatic/task_storage.rb @@ -17,286 +17,255 @@ # also available at http://www.gnu.org/copyleft/gpl.html. require 'utils' - require 'libvirt' +require 'rexml/document' +include REXML + + +def build_libvirt_vol_xml(name, size, owner, group, mode) + vol_xml = Document.new + vol_xml.add_element("volume", {"type" => "logical"}) + vol_xml.root.add_element("name").add_text(name) + vol_xml.root.add_element("capacity", {"unit" => "K"}).add_text(size.to_s) + vol_xml.root.add_element("target") + vol_xml.root.elements["target"].add_element("permissions") + vol_xml.root.elements["target"].elements["permissions"].add_element("owner").add_text(owner) + vol_xml.root.elements["target"].elements["permissions"].add_element("group").add_text(group) + vol_xml.root.elements["target"].elements["permissions"].add_element("mode").add_text(mode) + + return vol_xml +end -def add_volumes_to_db(db_pool, libvirt_pool, owner = nil, group = nil, mode = nil) - # FIXME: this is currently broken if you do something like: - # 1. Add an iscsi pool with 3 volumes (lun-1, lun-2, lun-3) - # 2. Scan it in - # 3. Remove lun-3 from the pool - # 4. Re-scan it - # What will happen is that you will still have lun-3 available in the - # database, even though it's not available in the pool anymore. It's a - # little tricky, though; we have to make sure that we don't pull the - # database entry out from underneath a possibly running VM (or do we?) - libvirt_pool.list_volumes.each do |volname| - storage_volume = StorageVolume.factory(db_pool.get_type_label) - - # NOTE: it is safe (and, in fact, necessary) to use - # #{storage_volume.volume_name} here without sanitizing it. This is - # because this is *not* based on user modifiable data, but rather, on an - # internal implementation detail - existing_vol = StorageVolume.find(:first, :conditions => - [ "storage_pool_id = ? AND #{storage_volume.volume_name} = ?", - db_pool.id, volname]) - if existing_vol != nil - # in this case, this path already exists in the database; just skip - next - end +def String.random_alphanumeric(size=16) + s = "" + size.times { s << (i = Kernel.rand(62); i += ((i < 10) ? 48 : ((i < 36) ? 55 : 61 ))).chr } + s +end + +def get_libvirt_lvm_pool_from_volume(db_volume) + phys_volume = StorageVolume.find(:first, :conditions => + ["lvm_pool_id = ?", db_volume.storage_pool_id]) - volptr = libvirt_pool.lookup_vol_by_name(volname) - - volinfo = volptr.info - - storage_volume = StorageVolume.factory(db_pool.get_type_label) - storage_volume.path = volptr.path - storage_volume.size = volinfo.capacity / 1024 - storage_volume.storage_pool_id = db_pool.id - storage_volume.write_attribute(storage_volume.volume_name, volname) - storage_volume.lv_owner_perms = owner - storage_volume.lv_group_perms = group - storage_volume.lv_mode_perms = mode - storage_volume.state = StorageVolume::STATE_AVAILABLE - storage_volume.save! - end + return LibvirtPool.factory(phys_volume.storage_pool) end -def storage_find_suitable_host(hardware_pool) - conn = nil - hardware_pool.hosts.each do |host| - if not host.is_disabled.nil? and host.is_disabled == 0 \ - and host.state == Host::STATE_AVAILABLE - begin - # FIXME: this can hang up taskomatic for quite some time. To see how, - # make one of your remote servers do "iptables -I INPUT -j DROP" - # and then try to run this; it will take TCP quite a while to give up. - # Unfortunately the solution is probably to do some sort of threading - conn = Libvirt::open("qemu+tcp://" + host.hostname + "/system") - - # if we didn't raise an exception, we connected; get out of here - break - rescue Libvirt::ConnectionError - # if we couldn't connect for whatever reason, just try the next host - next - end - end - end - - if conn == nil - # last ditch effort; if we didn't find any hosts, just use ourselves. - # this may or may not work - begin - conn = Libvirt::open("qemu:///system") - rescue - end - end +class LibvirtPool - if conn == nil - raise "Could not find a host to scan storage" - end + attr_reader :remote_pool - return conn -end + def initialize(type, name = nil) + @remote_pool = nil + @build_on_start = true + @remote_pool_defined = false + @remote_pool_started = false -# The words "pool" and "volume" are ridiculously overloaded in our context. -# Therefore, the refresh_pool method adopts this convention: -# phys_db_pool: The underlying physical storage pool, as it is represented in -# the database -# phys_libvirt_pool: The underlying physical storage, as it is represented in -# libvirt -# lvm_db_pool: The logical storage pool (if it exists), as it is represented -# in the database -# lvm_libvirt_pool: The logical storage pool (if it exists), as it is -# represented in the database - -def refresh_pool(task) - puts "refresh_pool" - - phys_db_pool = task.storage_pool - if phys_db_pool == nil - raise "Could not find storage pool" - end - - conn = storage_find_suitable_host(phys_db_pool.hardware_pool) - - begin - phys_libvirt_pool = LibvirtPool.factory(phys_db_pool) - phys_libvirt_pool.connect(conn) - - begin - # OK, the pool is all set. Add in all of the volumes - add_volumes_to_db(phys_db_pool, phys_libvirt_pool) - - phys_db_pool.state = StoragePool::STATE_AVAILABLE - phys_db_pool.save! - - # OK, now we've scanned the underlying hardware pool and added the - # volumes. Next we scan for pre-existing LVM volumes - logical_xml = conn.discover_storage_pool_sources("logical") - - Document.new(logical_xml).elements.each('sources/source') do |source| - vgname = source.elements["name"].text - - begin - source.elements.each("device") do |device| - byid_device = phys_libvirt_pool.lookup_vol_by_path(device.attributes["path"]).path - end - rescue - # If matching any of the sections in the LVM XML fails - # against the storage pool, then it is likely that this is a storage - # pool not associated with the one we connected above. Go on - # FIXME: it would be nicer to catch the right exception here, and - # fail on other exceptions - puts "One of the logical volumes in #{vgname} is not part of the pool of type #{phys_db_pool[:type]} that we are scanning; ignore the previous error!" - next + if name == nil + @name = type + "-" + String.random_alphanumeric + else + @name = name end - # if we make it here, then we were able to resolve all of the devices, - # so we know we need to use a new pool - lvm_db_pool = LvmStoragePool.find(:first, :conditions => - [ "vg_name = ?", vgname ]) - if lvm_db_pool == nil - lvm_db_pool = LvmStoragePool.new - lvm_db_pool[:type] = "LvmStoragePool" - # set the LVM pool to the same hardware pool as the underlying storage - lvm_db_pool.hardware_pool_id = phys_db_pool.hardware_pool_id - lvm_db_pool.vg_name = vgname - lvm_db_pool.save! + @xml = Document.new + @xml.add_element("pool", {"type" => type}) + + @xml.root.add_element("name").add_text(@name) + + @xml.root.add_element("source") + + @xml.root.add_element("target") + @xml.root.elements["target"].add_element("path") + end + + def connect(session, node) + pools = session.objects(:class => 'pool', 'node' => node.object_id) + pools.each do |pool| + result = pool.getXMLDesc() + raise "Error getting xml description of pool: #{result.text}" unless result.status == 0 + + xml_desc = result.description + puts "we have xml desc of existing pool #{pool.name}: #{xml_desc}" + if self.xmlequal?(Document.new(xml_desc).root) + puts "yes this one is good, using this pool.." + @remote_pool = pool + break + end end - source.elements.each("device") do |device| - byid_device = phys_libvirt_pool.lookup_vol_by_path(device.attributes["path"]).path - physical_vol = StorageVolume.find(:first, :conditions => - [ "path = ?", byid_device]) - if physical_vol == nil - # Hm. We didn't find the device in the storage volumes already. - # something went wrong internally, and we have to bail - raise "Storage internal physical volume error" - end - - # OK, put the right lvm_pool_id in place - physical_vol.lvm_pool_id = lvm_db_pool.id - physical_vol.save! + #XXX: I'm not sure.. it seems like there could be other things going on + # with the storage pool state. State can be inactive, building, running + # or degraded. I think some more thought should go here to make sure + # we're doing things right in each state. + if @remote_pool == nil + puts "calling storagePoolDefineXML(), xml is #{@xml.to_s}" + result = node.storagePoolDefineXML(@xml.to_s) + raise "Error creating pool: #{result.text}" unless result.status == 0 + @remote_pool = session.object(:object_id => result.pool) + raise "Error finding newly created remote pool." unless @remote_pool + + # we need this because we don't want to "build" LVM pools, which would + # destroy existing data + if @build_on_start + puts "building remote pool #{@remote_pool.name}" + result = @remote_pool.build + raise "Error building pool: #{result.text}" unless result.status == 0 + end + @remote_pool_defined = true end - lvm_libvirt_pool = LibvirtPool.factory(lvm_db_pool) - lvm_libvirt_pool.connect(conn) + puts "state of remote pool is: #{@remote_pool.state}" + puts "#{@remote_pool.properties}" + if @remote_pool.state == "inactive" + # only try to start the pool if it is currently inactive; in all other + # states, assume it is already running + puts "calling create on remote pool." + result = @remote_pool.create + raise "Error creating pool: #{result.text}" unless result.status == 0 - begin - add_volumes_to_db(lvm_db_pool, lvm_libvirt_pool, "0744", "0744", "0744") - ensure - lvm_libvirt_pool.shutdown + # Refresh qpid object with new properties. + @remote_pool.update + puts "state of remote pool is: #{@remote_pool.state}" + + @remote_pool_started = true end - end - ensure - phys_libvirt_pool.shutdown end - ensure - conn.close - end -end -def create_volume(task) - puts "create_volume" + def create_vol(type, name, size, owner, group, mode) + @vol_xml = Document.new + @vol_xml.add_element("volume", {"type" => type}) + @vol_xml.root.add_element("name").add_text(name) + @vol_xml.root.add_element("capacity", {"unit" => "K"}).add_text(size.to_s) + @vol_xml.root.add_element("target") + @vol_xml.root.elements["target"].add_element("permissions") + @vol_xml.root.elements["target"].elements["permissions"].add_element("owner").add_text(owner) + @vol_xml.root.elements["target"].elements["permissions"].add_element("group").add_text(group) + @vol_xml.root.elements["target"].elements["permissions"].add_element("mode").add_text(mode) + end - db_volume = task.storage_volume - if db_volume == nil - raise "Could not find storage volume to create" - end + def shutdown + puts "shutting down remote pool #{@type} #{@name}" + if @remote_pool_started + puts "destroying remote pool #{@type} #{@name}" + result = @remote_pool.destroy + puts "Error destroying pool: #{result.text}" unless result.status == 0 + end + if @remote_pool_defined + puts "undefining remote pool" + result = @remote_pool.undefine + puts "Error undefining pool: #{result.text}" unless result.status == 0 + end + end - db_pool = db_volume.storage_pool - if db_pool == nil - raise "Could not find storage pool" - end + def xmlequal?(docroot) + return false + end + + def self.factory(pool) + if pool[:type] == "IscsiStoragePool" + return IscsiLibvirtPool.new(pool.ip_addr, pool[:target]) + elsif pool[:type] == "NfsStoragePool" + return NFSLibvirtPool.new(pool.ip_addr, pool.export_path) + elsif pool[:type] == "LvmStoragePool" + # OK, if this is LVM storage, there are two cases we need to care about: + # 1) this is a LUN with LVM already on it. In this case, all we need to + # do is to create a new LV (== libvirt volume), and be done with it + # 2) this LUN is blank, so there is no LVM on it already. In this + # case, we need to pvcreate, vgcreate first (== libvirt pool build), + # and *then* create the new LV (== libvirt volume) on top of that. + # + # We can tell the difference between an LVM Pool that exists and one + # that needs to be created based on the value of the pool.state; + # if it is PENDING_SETUP, we need to create it first + phys_volume = StorageVolume.find(:first, :conditions => + [ "lvm_pool_id = ?", pool.id]) + return LVMLibvirtPool.new(pool.vg_name, phys_volume.path, + pool.state == StoragePool::STATE_PENDING_SETUP) + else + raise "Unknown storage pool type " + pool[:type].to_s + end + end +end - conn = storage_find_suitable_host(db_pool.hardware_pool) +class IscsiLibvirtPool < LibvirtPool + def initialize(ip_addr, target) + super('iscsi') - begin - if db_volume[:type] == "LvmStorageVolume" - phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(db_volume) - phys_libvirt_pool.connect(conn) + @type = 'iscsi' + @ipaddr = ip_addr + @target = target + + @xml.root.elements["source"].add_element("host", {"name" => @ipaddr}) + @xml.root.elements["source"].add_element("device", {"path" => @target}) + + @xml.root.elements["target"].elements["path"].text = "/dev/disk/by-id" end - begin - libvirt_pool = LibvirtPool.factory(db_pool) - - begin - libvirt_pool.connect(conn) - - libvirt_pool.create_vol(*db_volume.volume_create_params) - db_volume.state = StorageVolume::STATE_AVAILABLE - db_volume.save! - - db_pool.state = StoragePool::STATE_AVAILABLE - db_pool.save! - ensure - libvirt_pool.shutdown - end - ensure - if db_volume[:type] == "LvmStorageVolume" - phys_libvirt_pool.shutdown - end + def xmlequal?(docroot) + return (docroot.attributes['type'] == @type and + docroot.elements['source'].elements['host'].attributes['name'] == @ipaddr and + docroot.elements['source'].elements['device'].attributes['path'] == @target) end - ensure - conn.close - end end -def delete_volume(task) - puts "delete_volume" +class NFSLibvirtPool < LibvirtPool + def initialize(ip_addr, export_path) + super('netfs') + + @type = 'netfs' + @host = ip_addr + @remote_path = export_path + @name = String.random_alphanumeric + + @xml.root.elements["source"].add_element("host", {"name" => @host}) + @xml.root.elements["source"].add_element("dir", {"path" => @remote_path}) + @xml.root.elements["source"].add_element("format", {"type" => "nfs"}) - db_volume = task.storage_volume - if db_volume == nil - raise "Could not find storage volume to create" - end + @xml.root.elements["target"].elements["path"].text = "/mnt/" + @name + end + + def create_vol(name, size, owner, group, mode) + # FIXME: this can actually take some time to complete (since we aren't + # doing sparse allocations at the moment). During that time, whichever + # libvirtd we chose to use is completely hung up. The solution is 3-fold: + # 1. Allow sparse allocations in the WUI front-end + # 2. Make libvirtd multi-threaded + # 3. Make taskomatic multi-threaded + super("netfs", name, size, owner, group, mode) + + # FIXME: we have to add the format as raw here because of a bug in libvirt; + # if you specify a volume with no format, it will crash libvirtd + @vol_xml.root.elements["target"].add_element("format", {"type" => "raw"}) + @remote_pool.createVolumeXML(@vol_xml.to_s) + end - db_pool = db_volume.storage_pool - if db_pool == nil - raise "Could not find storage pool" - end + def xmlequal?(docroot) + return (docroot.attributes['type'] == @type and + docroot.elements['source'].elements['host'].attributes['name'] == @host and + docroot.elements['source'].elements['dir'].attributes['path'] == @remote_path) + end +end - conn = storage_find_suitable_host(db_pool.hardware_pool) +class LVMLibvirtPool < LibvirtPool + def initialize(vg_name, device, build_on_start) + super('logical', vg_name) - begin - if db_volume[:type] == "LvmStorageVolume" - phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(db_volume) - phys_libvirt_pool.connect(conn) + @type = 'logical' + @build_on_start = build_on_start + + @xml.root.elements["source"].add_element("name").add_text(@name) + @xml.root.elements["source"].add_element("device", {"path" => device}) + @xml.root.elements["target"].elements["path"].text = "/dev/" + @name + end + + def create_vol(name, size, owner, group, mode) + super("logical", name, size, owner, group, mode) + @remote_pool.createVolumeXML(@vol_xml.to_s) end - begin - libvirt_pool = LibvirtPool.factory(db_pool) - libvirt_pool.connect(conn) - - begin - libvirt_volume = libvirt_pool.lookup_vol_by_name(db_volume.read_attribute(db_volume.volume_name)) - # FIXME: we actually probably want to zero out the whole volume here, so - # we aren't potentially leaking data from one user to another. There - # are two problems, though: - # 1) I'm not sure how I would go about zero'ing the data on a remote - # machine, since there is no "libvirt_write_data" call - # 2) This could potentially take quite a while, so we want to spawn - # off another thread to do it - libvirt_volume.delete - - # Note: we have to nil out the task_target because when we delete the - # volume object, that also deletes all dependent tasks (including this - # one), which leads to accessing stale tasks. Orphan the task, then - # delete the object; we can clean up orphans later (or not, depending - # on the audit policy) - task.task_target = nil - task.save! - - db_volume.destroy - ensure - libvirt_pool.shutdown - end - ensure - if db_volume[:type] == "LvmStorageVolume" - phys_libvirt_pool.shutdown - end + def xmlequal?(docroot) + return (docroot.attributes['type'] == @type and + docroot.elements['name'].text == @name and + docroot.elements['source'].elements['name'] and + docroot.elements['source'].elements['name'].text == @name) end - ensure - conn.close - end end + diff --git a/src/task-omatic/task_vm.rb b/src/task-omatic/task_vm.rb index c187287..05ca3eb 100644 --- a/src/task-omatic/task_vm.rb +++ b/src/task-omatic/task_vm.rb @@ -24,30 +24,7 @@ require 'utils' gem 'cobbler' require 'cobbler' -def findHostSLA(vm) - host = nil - - vm.vm_resource_pool.get_hardware_pool.hosts.each do |curr| - # FIXME: we probably need to add in some notion of "load" into this check - if curr.num_cpus >= vm.num_vcpus_allocated \ - and curr.memory >= vm.memory_allocated \ - and not curr.is_disabled.nil? and curr.is_disabled == 0 \ - and curr.state == Host::STATE_AVAILABLE \ - and (vm.host_id.nil? or (not vm.host_id.nil? and vm.host_id != curr.id)) - host = curr - break - end - end - - if host == nil - # we couldn't find a host that matches this criteria - raise "No host matching VM parameters could be found" - end - - return host -end - -def findHost(host_id) +def find_host(host_id) host = Host.find(:first, :conditions => [ "id = ?", host_id]) if host == nil @@ -58,75 +35,6 @@ def findHost(host_id) return host end -def connect_storage_pools(conn, storage_volumes) - storagedevs = [] - storage_volumes.each do |volume| - # here, we need to iterate through each volume and possibly attach it - # to the host we are going to be using - db_pool = volume.storage_pool - if db_pool == nil - # Hum. Specified by the VM description, but not in the storage pool? - # continue on and hope for the best - puts "Couldn't find pool for volume #{volume.path}; skipping" - next - end - - # we have to special case LVM pools. In that case, we need to first - # activate the underlying physical device, and then do the logical one - if volume[:type] == "LvmStorageVolume" - phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(volume) - phys_libvirt_pool.connect(conn) - end - - libvirt_pool = LibvirtPool.factory(db_pool) - libvirt_pool.connect(conn) - - # OK, the pool should be all set. The last thing we need to do is get - # the path based on the volume name - storagedevs << libvirt_pool.lookup_vol_by_name(volume.read_attribute(volume.volume_name)).path - end - - return storagedevs -end - -def remove_pools(conn, type = nil) - all_storage_pools(conn).each do |remote_pool_name| - pool = conn.lookup_storage_pool_by_name(remote_pool_name) - - if type == nil or type == Document.new(pool.xml_desc).root.attributes['type'] - begin - pool.destroy - rescue - end - - begin - # if the destroy failed, we still try to undefine; it may be a pool - # that was previously destroyed but not undefined for whatever reason - pool.undefine - rescue - # do nothing if any of this failed; the worst that happens is that - # we leave a pool configured - puts "Could not teardown pool " + remote_pool_name + "; skipping" - end - end - end -end - -def teardown_storage_pools(conn) - # FIXME: this needs to get a *lot* smarter. In particular, we want to make - # sure we can tear down unused pools even when there are other guests running - if conn.list_domains.empty? - # OK, there are no running guests on this host anymore. We can teardown - # any storage pools that are there without fear - - # we first have to tear-down LVM pools, because they might depend on the - # underlying physical pools - remove_pools(conn, "logical") - - # now tear down the rest of the pools - remove_pools(conn) - end -end def create_vm_xml(name, uuid, memAllocated, memUsed, vcpus, bootDevice, macAddr, bridge, diskDevices) @@ -195,12 +103,12 @@ def create_vm_xml(name, uuid, memAllocated, memUsed, vcpus, bootDevice, return doc end -def setVmState(vm, state) +def set_vm_state(vm, state) vm.state = state vm.save! end -def setVmVncPort(vm, domain) +def set_vm_vnc_port(vm, domain) doc = REXML::Document.new(domain.xml_desc) attrib = REXML::XPath.match(doc, "//graphics/@port") if not attrib.empty?: @@ -209,32 +117,22 @@ def setVmVncPort(vm, domain) vm.save! end -def findVM(task, fail_on_nil_host_id = true) +def find_vm(task, fail_on_nil_host_id = true) # find the matching VM in the vms table vm = task.vm if vm == nil - raise "VM not found for task " + task.id + raise "VM #{task.vm} not found for task #{task.id}" end if vm.host_id == nil && fail_on_nil_host_id - # in this case, we have no idea where the VM is. How can we handle this - # gracefully? We don't necessarily want to just set the VM state to off; - # if the machine does happen to be running somewhere and we set it to - # disabled here, and then start it again, we could corrupt the disk - - # FIXME: the right thing to do here is probably to contact all of the - # hosts we know about and ensure that the domain isn't running; then we - # can mark it either as off (if we didn't find it), or mark the correct - # vm.host_id if we did. However, if you have a large number of hosts - # out there, this could take a while. raise "No host_id for VM " + vm.id.to_s end return vm end -def setVmShutdown(vm) +def set_vm_shut_down(vm) vm.host_id = nil vm.memory_used = nil vm.num_vcpus_used = nil @@ -244,459 +142,3 @@ def setVmShutdown(vm) vm.save! end -def create_vm(task) - puts "create_vm" - - vm = findVM(task, false) - - if vm.state != Vm::STATE_PENDING - raise "VM not pending" - end - setVmState(vm, Vm::STATE_CREATING) - - # create cobbler system profile - begin - # FIXME: Presently the wui handles all cobbler system creation. - # This should be moved out of the wui into Taskomatic. Specifically - # here, and in the edit_vm methods. - - setVmState(vm, Vm::STATE_STOPPED) - rescue Exception => error - setVmState(vm, Vm::STATE_CREATE_FAILED) - raise "Unable to create system: #{error.message}" - end -end - -def shut_or_destroy_vm(task, which) - # here, we are given an id for a VM to shutdown; we have to lookup which - # physical host it is running on - - vm = findVM(task) - - if vm.state == Vm::STATE_STOPPED - # the VM is already shutdown; just return success - setVmShutdown(vm) - return - elsif vm.state == Vm::STATE_SUSPENDED - raise "Cannot shutdown suspended domain" - elsif vm.state == Vm::STATE_SAVED - raise "Cannot shutdown saved domain" - end - - vm_orig_state = vm.state - setVmState(vm, Vm::STATE_STOPPING) - - begin - conn = Libvirt::open("qemu+tcp://" + vm.host.hostname + "/system") - dom = conn.lookup_domain_by_uuid(vm.uuid) - dom.send(which) - - begin - dom.undefine - rescue - # undefine can fail, for instance, if we live migrated from A -> B, and - # then we are shutting down the VM on B (because it only has "transient" - # XML). Therefore, just ignore undefine errors so we do the rest - # FIXME: we really should have a marker in the database somehow so that - # we can tell if this domain was migrated; that way, we can tell the - # difference between a real undefine failure and one because of migration - end - - teardown_storage_pools(conn) - - conn.close - rescue => ex - setVmState(vm, vm_orig_state) - raise ex - end - - setVmShutdown(vm) -end - -def shutdown_vm(task) - puts "shutdown_vm" - shut_or_destroy_vm(task, "shutdown") -end - -def poweroff_vm(task) - puts "poweroff_vm" - shut_or_destroy_vm(task, "destroy") -end - -def start_vm(task) - puts "start_vm" - - # here, we are given an id for a VM to start - - vm = findVM(task, false) - - if vm.state == Vm::STATE_RUNNING - # the VM is already running; just return success - return - elsif vm.state == Vm::STATE_SUSPENDED - raise "Cannot start suspended domain" - elsif vm.state == Vm::STATE_SAVED - raise "Cannot start saved domain" - end - - # FIXME: Validate that the VM is still within quota - - vm_orig_state = vm.state - setVmState(vm, Vm::STATE_STARTING) - - begin - if vm.host_id != nil - # OK, marked in the database as already running on a host; for now, we - # will just fail the operation - - # FIXME: we probably want to go out to the host it is marked on and check - # things out, just to make sure things are consistent - raise "VM already running" - end - - # OK, now that we found the VM, go looking in the hardware_pool - # hosts to see if there is a host that will fit these constraints - host = findHostSLA(vm) - - # if we're booting from a CDROM the VM is an image, - # then we need to add the NFS mount as a storage volume for this - # boot - # - if (vm.boot_device == Vm::BOOT_DEV_CDROM) && vm.uses_cobbler? && (vm.cobbler_type == Vm::IMAGE_PREFIX) - details = Cobbler::Image.find_one(vm.cobbler_name) - - raise "Image #{vm.cobbler_name} not found in Cobbler server" unless details - - # extract the components of the image filename - image_uri = details.file - protocol = auth = ip_addr = export_path = filename = "" - - protocol, image_uri = image_uri.split("://") if image_uri.include?("://") - auth, image_uri = image_uri.split("@") if image_uri.include?("@") - # it's ugly, but string.split returns an empty string as the first - # result here, so we'll just ignore it - ignored, ip_addr, image_uri = - image_uri.split(/^([^\/]+)(\/.*)/) unless image_uri =~ /^\// - ignored, export_path, filename = - image_uri.split(/^(.*)\/(.+)/) - - found = false - - vm.storage_volumes.each do |volume| - if volume.filename == filename - if (volume.storage_pool.ip_addr == ip_addr) && - (volume.storage_pool.export_path == export_path) - found = true - end - end - end - - unless found - # Create a new transient NFS storage volume - # This volume is *not* persisted. - image_volume = StorageVolume.factory("NFS", - :filename => filename - ) - - image_volume.storage_pool - image_pool = StoragePool.factory(StoragePool::NFS) - - image_pool.ip_addr = ip_addr - image_pool.export_path = export_path - image_pool.storage_volumes << image_volume - image_volume.storage_pool = image_pool - end - end - - volumes = [] - volumes += vm.storage_volumes - volumes << image_volume if image_volume - - conn = Libvirt::open("qemu+tcp://" + host.hostname + "/system") - - begin - storagedevs = connect_storage_pools(conn, volumes) - - dom = nil - begin - # FIXME: get rid of the hardcoded bridge - xml = create_vm_xml(vm.description, vm.uuid, vm.memory_allocated, - vm.memory_used, vm.num_vcpus_allocated, - vm.boot_device, vm.vnic_mac_addr, "ovirtbr0", - storagedevs) - dom = conn.define_domain_xml(xml.to_s) - dom.create - - setVmVncPort(vm, dom) - rescue - if dom != nil - dom.undefine - end - teardown_storage_pools(conn) - raise ex - end - ensure - conn.close - end - rescue => ex - setVmState(vm, vm_orig_state) - raise ex - end - - vm.host_id = host.id - vm.state = Vm::STATE_RUNNING - vm.memory_used = vm.memory_allocated - vm.num_vcpus_used = vm.num_vcpus_allocated - vm.boot_device = Vm::BOOT_DEV_HD - vm.save! -end - -def save_vm(task) - puts "save_vm" - - # here, we are given an id for a VM to suspend - - vm = findVM(task) - - if vm.state == Vm::STATE_SAVED - # the VM is already saved; just return success - return - elsif vm.state == Vm::STATE_SUSPENDED - raise "Cannot save suspended domain" - elsif vm.state == Vm::STATE_STOPPED - raise "Cannot save shutdown domain" - end - - vm_orig_state = vm.state - setVmState(vm, Vm::STATE_SAVING) - - begin - conn = Libvirt::open("qemu+tcp://" + vm.host.hostname + "/system") - dom = conn.lookup_domain_by_uuid(vm.uuid) - dom.save("/tmp/" + vm.uuid + ".save") - conn.close - rescue => ex - setVmState(vm, vm_orig_state) - raise ex - end - - # note that we do *not* reset the host_id here, since we stored the saved - # vm state information locally. restore_vm will pick it up from here - - # FIXME: it would be much nicer to be able to save the VM and remove the - # the host_id and undefine the XML; that way we could resume it on another - # host later. This can be done once we have the storage APIs, but it will - # need more work - - setVmState(vm, Vm::STATE_SAVED) -end - -def restore_vm(task) - puts "restore_vm" - - # here, we are given an id for a VM to start - - vm = findVM(task) - - if vm.state == Vm::STATE_RUNNING - # the VM is already saved; just return success - return - elsif vm.state == Vm::STATE_SUSPENDED - raise "Cannot restore suspended domain" - elsif vm.state == Vm::STATE_STOPPED - raise "Cannot restore shutdown domain" - end - - vm_orig_state = vm.state - setVmState(vm, Vm::STATE_RESTORING) - - begin - # FIXME: we should probably go out to the host and check what it thinks - # the state is - - conn = Libvirt::open("qemu+tcp://" + vm.host.hostname + "/system") - dom = conn.lookup_domain_by_uuid(vm.uuid) - dom.restore - - setVmVncPort(vm, dom) - - conn.close - rescue => ex - setVmState(vm, vm_orig_state) - raise ex - end - - setVmState(vm, Vm::STATE_RUNNING) -end - -def suspend_vm(task) - puts "suspend_vm" - - # here, we are given an id for a VM to suspend; we have to lookup which - # physical host it is running on - - vm = findVM(task) - - if vm.state == Vm::STATE_SUSPENDED - # the VM is already suspended; just return success - return - elsif vm.state == Vm::STATE_STOPPED - raise "Cannot suspend stopped domain" - elsif vm.state == Vm::STATE_SAVED - raise "Cannot suspend saved domain" - end - - vm_orig_state = vm.state - setVmState(vm, Vm::STATE_SUSPENDING) - - begin - conn = Libvirt::open("qemu+tcp://" + vm.host.hostname + "/system") - dom = conn.lookup_domain_by_uuid(vm.uuid) - dom.suspend - conn.close - rescue => ex - setVmState(vm, vm_orig_state) - raise ex - end - - # note that we do *not* reset the host_id here, since we just suspended the VM - # resume_vm will pick it up from here - - setVmState(vm, Vm::STATE_SUSPENDED) -end - -def resume_vm(task) - puts "resume_vm" - - # here, we are given an id for a VM to start - - vm = findVM(task) - - # OK, marked in the database as already running on a host; let's check it - - if vm.state == Vm::STATE_RUNNING - # the VM is already suspended; just return success - return - elsif vm.state == Vm::STATE_STOPPED - raise "Cannot resume stopped domain" - elsif vm.state == Vm::STATE_SAVED - raise "Cannot resume suspended domain" - end - - vm_orig_state = vm.state - setVmState(vm, Vm::STATE_RESUMING) - - begin - conn = Libvirt::open("qemu+tcp://" + vm.host.hostname + "/system") - dom = conn.lookup_domain_by_uuid(vm.uuid) - dom.resume - conn.close - rescue => ex - setVmState(vm, vm_orig_state) - raise ex - end - - setVmState(vm, Vm::STATE_RUNNING) -end - -def update_state_vm(task) - puts "update_state_vm" - - # NOTE: findVM() will only return a vm if all the host information is filled - # in. So if a vm that we thought was stopped is running, this returns nil - # and we don't update any information about it. The tricky part - # is that we're still not sure what to do in this case :). - Ian - # - # Actually for migration it is necessary that it be able to update - # the host and state of the VM once it is migrated. - vm = findVM(task, false) - new_vm_state, host_id_str = task.args.split(",") - if (vm.host_id == nil) and host_id_str - vm.host_id = host_id_str.to_i - end - - - vm_effective_state = Vm::EFFECTIVE_STATE[vm.state] - task_effective_state = Vm::EFFECTIVE_STATE[new_vm_state] - - if vm_effective_state != task_effective_state - vm.state = new_vm_state - - if task_effective_state == Vm::STATE_STOPPED - setVmShutdown(vm) - end - vm.save! - puts "Updated state to " + new_vm_state - end -end - -def migrate(vm, dest = nil) - if vm.state == Vm::STATE_STOPPED - raise "Cannot migrate stopped domain" - elsif vm.state == Vm::STATE_SUSPENDED - raise "Cannot migrate suspended domain" - elsif vm.state == Vm::STATE_SAVED - raise "Cannot migrate saved domain" - end - - vm_orig_state = vm.state - setVmState(vm, Vm::STATE_MIGRATING) - - begin - src_host = findHost(vm.host_id) - unless dest.nil? or dest.empty? - if dest.to_i == vm.host_id - raise "Cannot migrate from host " + src_host.hostname + " to itself!" - end - dst_host = findHost(dest.to_i) - else - dst_host = findHostSLA(vm) - end - - src_conn = Libvirt::open("qemu+tcp://" + src_host.hostname + "/system") - dst_conn = Libvirt::open("qemu+tcp://" + dst_host.hostname + "/system") - - connect_storage_pools(dst_conn, vm) - - dom = src_conn.lookup_domain_by_uuid(vm.uuid) - dom.migrate(dst_conn, Libvirt::Domain::MIGRATE_LIVE) - - # if we didn't raise an exception, then the migration was successful. We - # still have a pointer to the now-shutdown domain on the source side, so - # undefine it - begin - dom.undefine - rescue - # undefine can fail, for instance, if we live migrated from A -> B, and - # then we are shutting down the VM on B (because it only has "transient" - # XML). Therefore, just ignore undefine errors so we do the rest - # FIXME: we really should have a marker in the database somehow so that - # we can tell if this domain was migrated; that way, we can tell the - # difference between a real undefine failure and one because of migration - end - - teardown_storage_pools(src_conn) - dst_conn.close - src_conn.close - rescue => ex - # FIXME: ug. We may have open connections that we need to close; not - # sure how to handle that - setVmState(vm, vm_orig_state) - raise ex - end - - setVmState(vm, Vm::STATE_RUNNING) - vm.host_id = dst_host.id - vm.save! -end - -def migrate_vm(task) - puts "migrate_vm" - - # here, we are given an id for a VM to migrate; we have to lookup which - # physical host it is running on - - vm = findVM(task) - - migrate(vm, task.args) -end diff --git a/src/task-omatic/taskomatic.rb b/src/task-omatic/taskomatic.rb index ce37058..dcae4ca 100755 --- a/src/task-omatic/taskomatic.rb +++ b/src/task-omatic/taskomatic.rb @@ -1,7 +1,7 @@ #!/usr/bin/ruby # # Copyright (C) 2008 Red Hat, Inc. -# Written by Chris Lalancette +# Written by Chris Lalancette and Ian Main # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -22,122 +22,803 @@ $: << File.join(File.dirname(__FILE__), "../dutils") $: << File.join(File.dirname(__FILE__), ".") require 'rubygems' +require "qpid" +require 'monitor' +require 'dutils' require 'optparse' require 'daemons' include Daemonize -$logfile = '/var/log/ovirt-server/taskomatic.log' - -do_daemon = true -sleeptime = 5 -opts = OptionParser.new do |opts| - opts.on("-h", "--help", "Print help message") do - puts opts - exit - end - opts.on("-n", "--nodaemon", "Run interactively (useful for debugging)") do |n| - do_daemon = !n - end - opts.on("-s N", Integer, "--sleep", "Seconds to sleep between iterations (default is 5 seconds)") do |s| - sleeptime = s - end -end -begin - opts.parse!(ARGV) -rescue OptionParser::InvalidOption - puts opts - exit -end +require 'task_vm' +require 'task_storage' -if do_daemon - daemonize - STDOUT.reopen $logfile, 'a' - STDERR.reopen STDOUT -end +class TaskOmatic -begin - require 'dutils' -rescue => ex - puts "dutils require failed! #{ex.class}: #{ex.message}" -end + include MonitorMixin -require 'task_vm' -require 'task_storage' -require 'task_host' - -loop do - tasks = Array.new - begin - tasks = Task.find(:all, :conditions => [ "state = ?", Task::STATE_QUEUED ]) - rescue => ex - puts "1 #{ex.class}: #{ex.message}" - if Task.connected? - begin - ActiveRecord::Base.connection.reconnect! - rescue => norecon - puts "2 #{norecon.class}: #{norecon.message}" - end - else - begin - database_connect - rescue => ex - puts "3 #{ex.class}: #{ex.message}" - end - end - end - tasks.each do |task| - # make sure we get our credentials up-front - get_credentials - - task.time_started = Time.now - task.state = Task::STATE_RUNNING - task.save! - - state = Task::STATE_FINISHED - begin - case task.action - when VmTask::ACTION_CREATE_VM then create_vm(task) - when VmTask::ACTION_SHUTDOWN_VM then shutdown_vm(task) - when VmTask::ACTION_POWEROFF_VM then poweroff_vm(task) - when VmTask::ACTION_START_VM then start_vm(task) - when VmTask::ACTION_SUSPEND_VM then suspend_vm(task) - when VmTask::ACTION_RESUME_VM then resume_vm(task) - when VmTask::ACTION_SAVE_VM then save_vm(task) - when VmTask::ACTION_RESTORE_VM then restore_vm(task) - when VmTask::ACTION_UPDATE_STATE_VM then update_state_vm(task) - when VmTask::ACTION_MIGRATE_VM then migrate_vm(task) - when StorageTask::ACTION_REFRESH_POOL then refresh_pool(task) - when StorageVolumeTask::ACTION_CREATE_VOLUME then create_volume(task) - when StorageVolumeTask::ACTION_DELETE_VOLUME then delete_volume(task) - when HostTask::ACTION_CLEAR_VMS then clear_vms_host(task) - else - puts "unknown task " + task.action - state = Task::STATE_FAILED - task.message = "Unknown task type" - end - rescue => ex - puts "Task action processing failed: #{ex.class}: #{ex.message}" - puts ex.backtrace - state = Task::STATE_FAILED - task.message = ex.message - end - - task.state = state - task.time_ended = Time.now - task.save! - puts "done" - end - - # FIXME: here, we clean up "orphaned" tasks. These are tasks that we had - # to orphan (set task_target to nil) because we were deleting the object they - # depended on. - Task.find(:all, :conditions => [ "task_target_id IS NULL and task_target_type IS NULL" ]).each do |task| - task.destroy - end - - # we could destroy credentials, but another process might be using them (in - # particular, host-browser). Just leave them around, it shouldn't hurt - - STDOUT.flush - sleep sleeptime + $logfile = '/var/log/ovirt-server/taskomatic.log' + + def initialize() + super() + + @sleeptime = 5 + @nth_host = 0 + + @session = Qpid::Qmf::Session.new() + # FIXME: Should come from some kind of config or DNS SRV or what have you. + @broker = @session.add_broker("amqp://localhost:5672") + + do_daemon = true + + opts = OptionParser.new do |opts| + opts.on("-h", "--help", "Print help message") do + puts opts + exit + end + opts.on("-n", "--nodaemon", "Run interactively (useful for debugging)") do |n| + do_daemon = false + end + opts.on("-s N", Integer, "--sleep", "Seconds to sleep between iterations (default is 5 seconds)") do |s| + sleeptime = s + end + end + begin + opts.parse!(ARGV) + rescue OptionParser::InvalidOption + puts opts + exit + end + + if do_daemon + # XXX: This gets around a problem with paths for the database stuff. + # Normally daemonize would chdir to / but the paths for the database + # stuff are relative so it breaks it.. It's either this or rearrange + # things so the db stuff is included after daemonizing. + pwd = Dir.pwd + daemonize + Dir.chdir(pwd) + STDOUT.reopen $logfile, 'a' + STDERR.reopen STDOUT + end + end + + def find_capable_host(db_vm) + possible_hosts = [] + + puts "find capable host, looking up vm" + vm = @session.object(:class => "domain", 'uuid' => db_vm.uuid) + puts "done" + + db_vm.vm_resource_pool.get_hardware_pool.hosts.each do |curr| + # Now each of 'curr' is in the right hardware pool.. now we check them out. + + puts "find capable host, looking up node" + node = @session.object(:class => "node", 'hostname' => curr.hostname) + puts "done. node is #{node}" + next unless node + + # So now we expect if the node was found it's alive and well, then we check + # to make sure there's enough real cores for the number of vcpus, the node + # memory is adequate, the node is not disabled in the database, and if the + # node id is nil or if it is already running (has a node id set) then it + # is probably looking to migrate so we find a node that is not the current + # node. + # + # In the future we could add load or similar checks here. + + puts "checking node, #{node.cores} >= #{db_vm.num_vcpus_allocated}," + puts "and #{node.memory} >= #{db_vm.memory_allocated}" + puts "and not #{curr.is_disabled.nil?} and #{curr.is_disabled == 0}" + puts "and #{vm ? vm : 'nil'} or #{vm ? vm.active : 'nil'}) or #{vm ? vm.node : 'nil'} != #{node.object_id}" + + if node and node.cores >= db_vm.num_vcpus_allocated \ + and node.memory >= db_vm.memory_allocated \ + and not curr.is_disabled.nil? and curr.is_disabled == 0 \ + and ((!vm or vm.active == 'false') or vm.node != node.object_id) + possible_hosts.push(curr) + end + end + + puts "possible_hosts.length = #{possible_hosts.length}" + if possible_hosts.length == 0 + # we couldn't find a host that matches this criteria + raise "No host matching VM parameters could be found" + end + + # XXX: Right now we're just picking the nth host, we could also look at + # how many vms are already on it, or the load of the hosts etc. + host = possible_hosts[@nth_host % possible_hosts.length] + @nth_host += 1 + + return host + end + + def connect_storage_pools(node, storage_volumes) + storagedevs = [] + storage_volumes.each do |db_volume| + # here, we need to iterate through each volume and possibly attach it + # to the host we are going to be using + db_pool = db_volume.storage_pool + if db_pool == nil + # Hum. Specified by the VM description, but not in the storage pool? + # continue on and hope for the best + puts "Couldn't find pool for volume #{db_volume.path}; skipping" + next + end + + # we have to special case LVM pools. In that case, we need to first + # activate the underlying physical device, and then do the logical one + if db_volume[:type] == "LvmStorageVolume" + phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(db_volume) + phys_libvirt_pool.connect(@session, node) + end + + puts "Connecting to pool on node #{node.hostname}" + libvirt_pool = LibvirtPool.factory(db_pool) + libvirt_pool.connect(@session, node) + + # OK, the pool should be all set. The last thing we need to do is get + # the path based on the volume name + + volume_name = db_volume.read_attribute(db_volume.volume_name) + puts "volume_name is #{volume_name}, straight it is #{db_volume.volume_name}" + pool = libvirt_pool.remote_pool + volume = @session.object(:class => 'volume', + 'name' => volume_name, + 'storagePool' => pool.object_id) + raise "Unable to find volume #{volume_name} attached to pool #{pool.name}." unless volume + storagedevs << volume.path + end + + return storagedevs + end + + def task_create_vm(task) + # XXX: This is mostly just a place holder. + vm = find_vm(task, false) + if vm.state != Vm::STATE_PENDING + raise "VM not pending" + end + vm.state = Vm::STATE_STOPPED + vm.save! + end + + def teardown_storage_pools(node) + + # This is rather silly because we only destroy pools if there are no + # more vms on the node. We should be reference counting the pools + # somehow so we know when they are no longer in use. + vms = @session.objects(:class => 'domain', 'node' => node.object_id) + if vms.length > 0 + return + end + pools = @session.objects(:class => 'pool', 'node' => node.object_id) + + # FIXME: I think we should be destroying/undefining logical volumes first. + pools.each do |pool| + result = pool.destroy + result = pool.undefine + end + end + + + def task_shutdown_or_destroy_vm(task, action) + db_vm = task.vm + vm = @session.object(:class => 'domain', 'uuid' => db_vm.uuid) + if !vm + puts ("VM already shut down?") + return + end + + node = @session.object(:object_id => vm.node) + raise "Unable to get node that vm is on??" unless node + + if vm.state == "shutdown" or vm.state == "shutoff" + set_vm_shut_down(db_vm) + return + elsif vm.state == "suspended" + raise "Cannot shutdown suspended domain" + elsif vm.state == "saved" + raise "Cannot shutdown saved domain" + end + + if action == :shutdown + result = vm.shutdown() + raise "Error shutting down VM: #{result.text}" unless result.status == 0 + elsif action == :destroy + result = vm.destroy() + raise "Error destroying VM: #{result.text}" unless result.status == 0 + end + + # undefine can fail, for instance, if we live migrated from A -> B, and + # then we are shutting down the VM on B (because it only has "transient" + # XML). Therefore, just ignore undefine errors so we do the rest + # FIXME: we really should have a marker in the database somehow so that + # we can tell if this domain was migrated; that way, we can tell the + # difference between a real undefine failure and one because of migration + result = vm.undefine() + puts "Error undefining VM: #{result.text}" unless result.status == 0 + + teardown_storage_pools(node) + + set_vm_shut_down(db_vm) + end + + def task_start_vm(task) + db_vm = find_vm(task, false) + + # XXX: Kinda silly? I dunno about these intermediate states.. + set_vm_state(db_vm, Vm::STATE_STARTING) + + puts "looking up domain" + vm = @session.object(:class => "domain", 'uuid' => db_vm.uuid) + puts "domain lookup complete, domain is #{vm}" + + if vm + case vm.state + when "running" + return + when "blocked" + raise "Virtual machine state is blocked, cannot start VM." + when "paused" + raise "Virtual machine is currently paused, cannot start, must resume." + end + end + # FIXME: There's a bug here in that a host that's already running the vm won't be + # returned. I think that's supposed to be for migration but it just breaks stuff. + db_host = find_capable_host(db_vm) + + node = @session.object(:class => "node", 'hostname' => db_host.hostname) + + raise "Unable to find host #{db_host.hostname} to create VM on." unless node + + if (db_vm.boot_device == Vm::BOOT_DEV_CDROM) && db_vm.uses_cobbler? && (db_vm.cobbler_type == Vm::IMAGE_PREFIX) + details = Cobbler::Image.find_one(db_vm.cobbler_name) + raise "Image #{vm.cobbler_name} not found in Cobbler server" unless details + ignored, ip_addr, export_path, filename = details.file.split(/(.*):(.*)\/(.*)/) + + found = false + + db_vm.storage_volumes.each do |volume| + if volume.filename == filename + if (volume.storage_pool.ip_addr == ip_addr) && + (volume.storage_pool.export_path == export_path) + found = true + end + end + end + + unless found + # Create a new transient NFS storage volume + # This volume is *not* persisted. + image_volume = StorageVolume.factory("NFS", :filename => filename) + + image_volume.storage_pool + image_pool = StoragePool.factory(StoragePool::NFS) + + image_pool.ip_addr = ip_addr + image_pool.export_path = export_path + image_pool.storage_volumes << image_volume + image_volume.storage_pool = image_pool + end + end + + # FIXME: I know this part is broken.. + # + # hrrm, who wrote this comment and why is it broken? - Ian + volumes = [] + volumes += db_vm.storage_volumes + volumes << image_volume if image_volume + puts "volumes are #{volumes}" + storagedevs = connect_storage_pools(node, volumes) + + # FIXME: get rid of the hardcoded bridge + xml = create_vm_xml(db_vm.description, db_vm.uuid, db_vm.memory_allocated, + db_vm.memory_used, db_vm.num_vcpus_allocated, db_vm.boot_device, + db_vm.vnic_mac_addr, "ovirtbr0", storagedevs) + + host = @session.object(:class => 'node', 'hostname' => db_host.hostname) + raise "Cannot find host #{db_host.hostname}, cannot create virtual machine." unless host + + result = host.domainDefineXML(xml.to_s) + raise "Error defining virtual machine: #{result.text}" unless result.status == 0 + + puts "domain result is #{result.domain}" + domain = @session.object(:object_id => result.domain) + raise "Cannot find domain on host #{db_host.hostname}, cannot create virtual machine." unless domain + + puts "domain is #{domain}, it has #{domain.properties}" + result = domain.create() + raise "Error creating virtual machine: #{result.text}" unless result.status == 0 + + db_vm = find_vm(task, false) + + # XXX: This information is not available via the libvirt interface. + db_vm.memory_used = db_vm.memory_allocated + db_vm.boot_device = Vm::BOOT_DEV_HD + db_vm.host_id = db_host.id + + # We write the new state here even though dbomatic will set it soon anyway. + # This is just to let the UI know that it's good to go right away and really + # dbomatic will just write the same thing over top of it soon enough. + db_vm.state = Vm::STATE_RUNNING + db_vm.save! + end + + def task_suspend_vm(task) + db_vm = task.vm + dom = @session.object(:class => 'domain', 'uuid' => db_vm.uuid) + raise "Unable to locate VM to suspend" unless dom + + if dom.state == "shutdown" or dom.state == "shutoff" + raise "Cannot suspend stopped domain" + elsif dom.state == "paused" + raise "Cannot suspend saved domain" + end + + result = dom.suspend + raise "Error suspending VM: #{result.text}" unless result.status == 0 + + db_vm.state = Vm::STATE_SUSPENDED + db_vm.save! + end + + def task_resume_vm(task) + db_vm = task.vm + dom = @session.object(:class => 'domain', 'uuid' => db_vm.uuid) + raise "Unable to locate VM to resume" unless dom + + if dom.state == "running" + # the VM is already suspended; just return success + return + elsif dom.state == "shutoff" or dom.state == "shutdown" + raise "Cannot resume stopped domain" + elsif dom.state == "blocked" + raise "Cannot resume suspended domain" + end + + result = dom.resume + raise "Error resuming VM: #{result.text}" unless result.status == 0 + + db_vm.state = Vm::STATE_RUNNING + db_vm.save! + end + + def task_save_vm(task) + db_vm = task.vm + dom = @session.object(:class => 'domain', 'uuid' => db_vm.uuid) + raise "Unable to locate VM to save" unless dom + + #XXX: I'm not checking states here. I want to see if libvirt gives back + #decent error messages for different states. + filename = "/tmp/#{dom.uuid}.save" + puts "saving vm #{dom.name} to #{filename}" + result = dom.save(filename) + raise "Error saving VM: #{result.text}" unless result.status == 0 + + set_vm_state(db_vm, Vm::STATE_SAVED) + end + + def task_restore_vm(task) + db_vm = task.vm + dom = @session.object(:class => 'domain', 'uuid' => db_vm.uuid) + raise "Unable to locate VM to restore" unless dom + + #XXX: I'm not checking states here. I want to see if libvirt gives back + #decent error messages for different states. + + filename = "/tmp/#{dom.uuid}.save" + puts "restoring vm #{dom.name} from #{filename}" + result = dom.restore("/tmp/" + dom.uuid + ".save") + raise "Error restoring VM: #{result.text}" unless result.status == 0 + + set_vm_state(db_vm, Vm::STATE_RUNNING) + end + + def migrate(db_vm, dest = nil) + + vm = @session.object(:class => "domain", 'uuid' => db_vm.uuid) + raise "Unable to find VM to migrate" unless vm + src_node = @session.object(:object_id => vm.node) + raise "Unable to find node that VM is on??" unless src_node + + puts "Migrating domain lookup complete, domain is #{vm}" + + case vm.state + when "blocked" + raise "Unable to migrate blocked VM." + when "paused" + raise "Unable to migrate suspended VM." + end + + vm_orig_state = db_vm.state + set_vm_state(db_vm, Vm::STATE_MIGRATING) + + begin + unless dest.nil? or dest.empty? + if dest.to_i == db_vm.host_id + raise "Cannot migrate from host " + src_node.hostname + " to itself!" + end + db_dst_host = find_host(dest.to_i) + else + db_dst_host = find_capable_host(db_vm) + end + + dest_node = @session.object(:class => 'node', 'hostname' => db_dst_host.hostname) + raise "Unable to find host #{db_dst_host.hostname} to migrate to." unless dest_node + + volumes = [] + volumes += db_vm.storage_volumes + puts "for migrating, volumes are #{volumes}" + connect_storage_pools(dest_node, volumes) + + # Sadly migrate with qpid is broken because it requires a connection between + # both nodes and currently that can't happen securely. For now we do it + # the old fashioned way.. + dst_uri = "qemu+tcp://#{dest_node.hostname}/system" + src_uri = "qemu+tcp://#{src_node.hostname}/system" + src_conn = Libvirt::open("qemu+tcp://" + src_node.hostname + "/system") + dst_conn = Libvirt::open("qemu+tcp://" + dest_node.hostname + "/system") + dom = src_conn.lookup_domain_by_uuid(vm.uuid) + dom.migrate(dst_conn, Libvirt::Domain::MIGRATE_LIVE) + src_conn.close + dst_conn.close + + # undefine can fail, for instance, if we live migrated from A -> B, and + # then we are shutting down the VM on B (because it only has "transient" + # XML). Therefore, just ignore undefine errors so we do the rest + # FIXME: we really should have a marker in the database somehow so that + # we can tell if this domain was migrated; that way, we can tell the + # difference between a real undefine failure and one because of migration + result = vm.undefine + puts "Error undefining old vm after migrate: #{result.text}" unless result.status == 0 + + # See if we can take down storage pools on the src host. + teardown_storage_pools(src_node) + rescue => ex + puts "Error: #{ex}" + set_vm_state(db_vm, vm_orig_state) + raise ex + end + + db_vm.state = Vm::STATE_RUNNING + db_vm.host_id = db_dst_host.id + db_vm.save! + end + + def task_migrate_vm(task) + puts "migrate_vm" + + # here, we are given an id for a VM to migrate; we have to lookup which + # physical host it is running on + vm = find_vm(task) + migrate(vm, task.args) + end + + def storage_find_suitable_host(pool_id) + # find all of the hosts in the same pool as the storage + hosts = Host.find(:all, :conditions => + ["hardware_pool_id = ?", pool_id]) + hosts.each do |host| + puts "storage_find_suitable_host: host #{host.hostname} uuid #{host.uuid}" + node = @session.object(:class => 'node', 'hostname' => host.hostname) + puts 'node found' if node + return node if node + end + + raise "Could not find a host within this storage pool to scan the storage server." + end + + def add_volumes_to_db(db_pool, libvirt_pool, owner = nil, group = nil, mode = nil) + # FIXME: this is currently broken if you do something like: + # 1. Add an iscsi pool with 3 volumes (lun-1, lun-2, lun-3) + # 2. Scan it in + # 3. Remove lun-3 from the pool + # 4. Re-scan it + # What will happen is that you will still have lun-3 available in the + # database, even though it's not available in the pool anymore. It's a + # little tricky, though; we have to make sure that we don't pull the + # database entry out from underneath a possibly running VM (or do we?) + volumes = @session.objects(:class => 'volume', 'storagePool' => libvirt_pool.remote_pool.object_id) + puts "volumes list is #{volumes.length} long" + volumes.each do |volume| + puts "have new volume for storage pool: #{volume.path}" + storage_volume = StorageVolume.factory(db_pool.get_type_label) + + # NOTE: it is safe (and, in fact, necessary) to use + # #{storage_volume.volume_name} here without sanitizing it. This is + # because this is *not* based on user modifiable data, but rather, on an + # internal implementation detail + existing_vol = StorageVolume.find(:first, :conditions => + ["storage_pool_id = ? AND #{storage_volume.volume_name} = ?", + db_pool.id, volume.name]) + + # in this case, this path already exists in the database; just skip + next if existing_vol + + storage_volume = StorageVolume.factory(db_pool.get_type_label) + storage_volume.path = volume.path + storage_volume.size = volume.capacity / 1024 + storage_volume.storage_pool_id = db_pool.id + storage_volume.write_attribute(storage_volume.volume_name, volume.name) + storage_volume.lv_owner_perms = owner + storage_volume.lv_group_perms = group + storage_volume.lv_mode_perms = mode + storage_volume.state = StorageVolume::STATE_AVAILABLE + puts "saving storage volume to db." + storage_volume.save! + end + end + + # The words "pool" and "volume" are ridiculously overloaded in our context. + # Therefore, the refresh_pool method adopts this convention: + # db_pool_phys: The underlying physical storage pool, as it is represented in + # the database + # phys_libvirt_pool: The underlying physical storage, as it is represented in + # libvirt + # db_lvm_pool: The logical storage pool (if it exists), as it is represented + # in the database + # lvm_libvirt_pool: The logical storage pool (if it exists), as it is + # represented in the database + + def task_refresh_pool(task) + puts "refresh_pool" + + db_pool_phys = task.storage_pool + raise "Could not find storage pool" unless db_pool_phys + + node = storage_find_suitable_host(db_pool_phys.hardware_pool_id) + + begin + phys_libvirt_pool = LibvirtPool.factory(db_pool_phys) + phys_libvirt_pool.connect(@session, node) + + begin + # OK, the pool is all set. Add in all of the volumes + add_volumes_to_db(db_pool_phys, phys_libvirt_pool) + + # OK, now we've scanned the underlying hardware pool and added the + # volumes. Next we scan for pre-existing LVM volumes + result = node.findStoragePoolSources("logical", nil) + raise "Error finding logical volumes in pool: #{result.text}" unless result.status == 0 + logical_xml = result.xmlDesc + + puts "logical xml is: #{logical_xml}" + + Document.new(logical_xml).elements.each('sources/source') do |source| + vgname = source.elements["name"].text + + # If matching any of the sections in the LVM XML fails + # against the storage pool, then it is likely that this is a storage + # pool not associated with the one we connected above. Go on + # FIXME: it would be nicer to catch the right exception here, and + # fail on other exceptions + source.elements.each("device") do |device| + log_vol = @session.object(:class => 'volume', + 'path' => device.attributes["path"], + 'storagePool' => phys_libvirt_pool.remote_pool) + next unless log_vol + end + + # if we make it here, then we were able to resolve all of the devices, + # so we know we need to use a new pool + db_lvm_pool = LvmStoragePool.find(:first, :conditions => + ["vg_name = ?", vgname]) + if db_lvm_pool == nil + db_lvm_pool = LvmStoragePool.new + db_lvm_pool[:type] = "LvmStoragePool" + # set the LVM pool to the same hardware pool as the underlying storage + db_lvm_pool.hardware_pool_id = db_pool_phys.hardware_pool_id + db_lvm_pool.vg_name = vgname + db_lvm_pool.save! + end + + source.elements.each("device") do |device| + log_vol = @session.object(:class => 'volume', + 'path' => device.attributes["path"], + 'storagePool' => phys_libvirt_pool.remote_pool.object_id) + if !log_vol + puts "Unable to find logical volume with path #{device.attributes["path"]} on host" + next + end + + physical_vol = StorageVolume.find(:first, :conditions => + ["path = ?", log_vol.path]) + if physical_vol == nil + # Hm. We didn't find the device in the storage volumes already. + # something went wrong internally, and we have to bail + raise "Storage internal physical volume error" + end + + # OK, put the right lvm_pool_id in place + physical_vol.lvm_pool_id = db_lvm_pool.id + physical_vol.save! + end + + lvm_libvirt_pool = LibvirtPool.factory(db_lvm_pool) + lvm_libvirt_pool.connect(@session, node) + + # Do this in a block just in case we have some issue with the database. + begin + add_volumes_to_db(db_lvm_pool, lvm_libvirt_pool, "0744", "0744", "0744") + ensure + lvm_libvirt_pool.shutdown + end + end + end + ensure + phys_libvirt_pool.shutdown + end + end + + def task_create_volume(task) + puts "create_volume" + + db_volume = task.storage_volume + raise "Could not find storage volume to create" unless db_volume + + db_pool = db_volume.storage_pool + raise "Could not find storage pool" unless db_pool + + node = storage_find_suitable_host(db_pool.hardware_pool) + + begin + if db_volume[:type] == "LvmStorageVolume" + phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(db_volume) + phys_libvirt_pool.connect(@session, node) + end + + begin + libvirt_pool = LibvirtPool.factory(db_pool) + + begin + libvirt_pool.connect(@session, node) + + libvirt_pool.create_vol(*db_volume.volume_create_params) + db_volume.state = StorageVolume::STATE_AVAILABLE + db_volume.save! + + db_pool.state = StoragePool::STATE_AVAILABLE + db_pool.save! + ensure + libvirt_pool.shutdown + end + ensure + if db_volume[:type] == "LvmStorageVolume" + phys_libvirt_pool.shutdown + end + end + end + end + + def task_delete_volume(task) + puts "delete_volume" + + db_volume = task.storage_volume + raise "Could not find storage volume to create" unless db_volume + + db_pool = db_volume.storage_pool + raise "Could not find storage pool" unless db_pool + + node = storage_find_suitable_host(db_pool.hardware_pool) + + begin + if db_volume[:type] == "LvmStorageVolume" + phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(db_volume) + phys_libvirt_pool.connect(@session, node) + end + + begin + libvirt_pool = LibvirtPool.factory(db_pool) + libvirt_pool.connect(@session, node) + + begin + volume = @session.object(:class => 'volume', 'storagePool' => libvirt_pool.remote_pool.object_id) + puts "Unable to find volume to delete" unless volume + + # FIXME: we actually probably want to zero out the whole volume here, so + # we aren't potentially leaking data from one user to another. There + # are two problems, though: + # 1) I'm not sure how I would go about zero'ing the data on a remote + # machine, since there is no "libvirt_write_data" call + # 2) This could potentially take quite a while, so we want to spawn + # off another thread to do it + volume.delete + + # Note: we have to nil out the task_target because when we delete the + # volume object, that also deletes all dependent tasks (including this + # one), which leads to accessing stale tasks. Orphan the task, then + # delete the object; we can clean up orphans later (or not, depending + # on the audit policy) + task.task_target = nil + task.save! + + db_volume.destroy + ensure + libvirt_pool.shutdown + end + ensure + if db_volume[:type] == "LvmStorageVolume" + phys_libvirt_pool.shutdown + end + end + end + end + + def task_clear_vms_host(task) + src_host = task.host + + src_host.vms.each do |vm| + migrate(vm) + end + end + + def mainloop() + loop do + tasks = Array.new + begin + tasks = Task.find(:all, :conditions => [ "state = ?", Task::STATE_QUEUED ]) + rescue => ex + puts "1 #{ex.class}: #{ex.message}" + if Task.connected? + begin + ActiveRecord::Base.connection.reconnect! + rescue => norecon + puts "2 #{norecon.class}: #{norecon.message}" + end + else + begin + database_connect + rescue => ex + puts "3 #{ex.class}: #{ex.message}" + end + end + end + + tasks.each do |task| + # make sure we get our credentials up-front + get_credentials + + task.time_started = Time.now + + puts "got task, id is #{task}" + state = Task::STATE_FINISHED + begin + case task.action + when VmTask::ACTION_CREATE_VM then task_create_vm(task) + when VmTask::ACTION_SHUTDOWN_VM then task_shutdown_or_destroy_vm(task, :shutdown) + when VmTask::ACTION_POWEROFF_VM then task_shutdown_or_destroy_vm(task, :destroy) + when VmTask::ACTION_START_VM then task_start_vm(task) + when VmTask::ACTION_SUSPEND_VM then task_suspend_vm(task) + when VmTask::ACTION_RESUME_VM then task_resume_vm(task) + when VmTask::ACTION_SAVE_VM then task_save_vm(task) + when VmTask::ACTION_RESTORE_VM then task_restore_vm(task) + when VmTask::ACTION_MIGRATE_VM then task_migrate_vm(task) + when StorageTask::ACTION_REFRESH_POOL then task_refresh_pool(task) + when StorageVolumeTask::ACTION_CREATE_VOLUME then task_create_volume(task) + when StorageVolumeTask::ACTION_DELETE_VOLUME then task_delete_volume(task) + when HostTask::ACTION_CLEAR_VMS then task_clear_vms_host(task) + else + puts "unknown task " + task.action + state = Task::STATE_FAILED + task.message = "Unknown task type" + end + rescue => ex + puts "Task action processing failed: #{ex.class}: #{ex.message}" + puts ex.backtrace + state = Task::STATE_FAILED + task.message = ex.message + end + + task.state = state + task.time_ended = Time.now + task.save! + end + sleep(1) + end + end end + +taskomatic = TaskOmatic.new() +taskomatic.mainloop() + diff --git a/src/task-omatic/utils.rb b/src/task-omatic/utils.rb deleted file mode 100644 index e3005ed..0000000 --- a/src/task-omatic/utils.rb +++ /dev/null @@ -1,221 +0,0 @@ -require 'rexml/document' -include REXML - -def String.random_alphanumeric(size=16) - s = "" - size.times { s << (i = Kernel.rand(62); i += ((i < 10) ? 48 : ((i < 36) ? 55 : 61 ))).chr } - s -end - -def all_storage_pools(conn) - all_pools = conn.list_defined_storage_pools - all_pools.concat(conn.list_storage_pools) - return all_pools -end - -def get_libvirt_lvm_pool_from_volume(db_volume) - phys_volume = StorageVolume.find(:first, :conditions => - [ "lvm_pool_id = ?", db_volume.storage_pool_id]) - - return LibvirtPool.factory(phys_volume.storage_pool) -end - -class LibvirtPool - def initialize(type, name = nil) - @remote_pool = nil - @build_on_start = true - @remote_pool_defined = false - @remote_pool_started = false - - if name == nil - @name = type + "-" + String.random_alphanumeric - else - @name = name - end - - @xml = Document.new - @xml.add_element("pool", {"type" => type}) - - @xml.root.add_element("name").add_text(@name) - - @xml.root.add_element("source") - - @xml.root.add_element("target") - @xml.root.elements["target"].add_element("path") - end - - def connect(conn) - all_storage_pools(conn).each do |remote_pool_name| - tmppool = conn.lookup_storage_pool_by_name(remote_pool_name) - - if self.xmlequal?(Document.new(tmppool.xml_desc).root) - @remote_pool = tmppool - break - end - end - - if @remote_pool == nil - @remote_pool = conn.define_storage_pool_xml(@xml.to_s) - # we need this because we don't necessarily want to "build" LVM pools, - # which might destroy existing data - if @build_on_start - @remote_pool.build - end - @remote_pool_defined = true - end - - if @remote_pool.info.state == Libvirt::StoragePool::INACTIVE - # only try to start the pool if it is currently inactive; in all other - # states, assume it is already running - @remote_pool.create - @remote_pool_started = true - end - end - - def list_volumes - return @remote_pool.list_volumes - end - - def lookup_vol_by_path(dev) - return @remote_pool.lookup_volume_by_path(dev) - end - - def lookup_vol_by_name(name) - return @remote_pool.lookup_volume_by_name(name) - end - - def create_vol(type, name, size, owner, group, mode) - @vol_xml = Document.new - @vol_xml.add_element("volume", {"type" => type}) - @vol_xml.root.add_element("name").add_text(name) - @vol_xml.root.add_element("capacity", {"unit" => "K"}).add_text(size.to_s) - @vol_xml.root.add_element("target") - @vol_xml.root.elements["target"].add_element("permissions") - @vol_xml.root.elements["target"].elements["permissions"].add_element("owner").add_text(owner) - @vol_xml.root.elements["target"].elements["permissions"].add_element("group").add_text(group) - @vol_xml.root.elements["target"].elements["permissions"].add_element("mode").add_text(mode) - end - - def shutdown - if @remote_pool_started - @remote_pool.destroy - end - if @remote_pool_defined - @remote_pool.undefine - end - end - - def xmlequal?(docroot) - return false - end - - def self.factory(pool) - if pool[:type] == "IscsiStoragePool" - return IscsiLibvirtPool.new(pool.ip_addr, pool[:target]) - elsif pool[:type] == "NfsStoragePool" - return NFSLibvirtPool.new(pool.ip_addr, pool.export_path) - elsif pool[:type] == "LvmStoragePool" - # OK, if this is LVM storage, there are two cases we need to care about: - # 1) this is a LUN with LVM already on it. In this case, all we need to - # do is to create a new LV (== libvirt volume), and be done with it - # 2) this LUN is blank, so there is no LVM on it already. In this - # case, we need to pvcreate, vgcreate first (== libvirt pool build), - # and *then* create the new LV (== libvirt volume) on top of that. - # - # We can tell the difference between an LVM Pool that exists and one - # that needs to be created based on the value of the pool.state; - # if it is PENDING_SETUP, we need to create it first - phys_volume = StorageVolume.find(:first, :conditions => - [ "lvm_pool_id = ?", pool.id]) - - return LVMLibvirtPool.new(pool.vg_name, phys_volume.path, - pool.state == StoragePool::STATE_PENDING_SETUP) - else - raise "Unknown storage pool type " + pool[:type].to_s - end - end -end - -class IscsiLibvirtPool < LibvirtPool - def initialize(ip_addr, target) - super('iscsi') - - @type = 'iscsi' - @ipaddr = ip_addr - @target = target - - @xml.root.elements["source"].add_element("host", {"name" => @ipaddr}) - @xml.root.elements["source"].add_element("device", {"path" => @target}) - - @xml.root.elements["target"].elements["path"].text = "/dev/disk/by-id" - end - - def xmlequal?(docroot) - return (docroot.attributes['type'] == @type and - docroot.elements['source'].elements['host'].attributes['name'] == @ipaddr and - docroot.elements['source'].elements['device'].attributes['path'] == @target) - end -end - -class NFSLibvirtPool < LibvirtPool - def initialize(ip_addr, export_path) - super('netfs') - - @type = 'netfs' - @host = ip_addr - @remote_path = export_path - @name = String.random_alphanumeric - - @xml.root.elements["source"].add_element("host", {"name" => @host}) - @xml.root.elements["source"].add_element("dir", {"path" => @remote_path}) - @xml.root.elements["source"].add_element("format", {"type" => "nfs"}) - - @xml.root.elements["target"].elements["path"].text = "/mnt/" + @name - end - - def create_vol(name, size, owner, group, mode) - # FIXME: this can actually take some time to complete (since we aren't - # doing sparse allocations at the moment). During that time, whichever - # libvirtd we chose to use is completely hung up. The solution is 3-fold: - # 1. Allow sparse allocations in the WUI front-end - # 2. Make libvirtd multi-threaded - # 3. Make taskomatic multi-threaded - super("netfs", name, size, owner, group, mode) - - # FIXME: we have to add the format as raw here because of a bug in libvirt; - # if you specify a volume with no format, it will crash libvirtd - @vol_xml.root.elements["target"].add_element("format", {"type" => "raw"}) - @remote_pool.create_vol_xml(@vol_xml.to_s) - end - - def xmlequal?(docroot) - return (docroot.attributes['type'] == @type and - docroot.elements['source'].elements['host'].attributes['name'] == @host and - docroot.elements['source'].elements['dir'].attributes['path'] == @remote_path) - end -end - -class LVMLibvirtPool < LibvirtPool - def initialize(vg_name, device, build_on_start) - super('logical', vg_name) - - @type = 'logical' - @build_on_start = build_on_start - - @xml.root.elements["source"].add_element("name").add_text(@name) - @xml.root.elements["source"].add_element("device", {"path" => device}) - - @xml.root.elements["target"].elements["path"].text = "/dev/" + @name - end - - def create_vol(name, size, owner, group, mode) - super("logical", name, size, owner, group, mode) - @remote_pool.create_vol_xml(@vol_xml.to_s) - end - - def xmlequal?(docroot) - return (docroot.attributes['type'] == @type and - docroot.elements['name'].text == @name and - docroot.elements['source'].elements['name'] == @name) - end -end -- 1.6.0.4 From imain at redhat.com Thu Dec 18 22:50:50 2008 From: imain at redhat.com (Ian Main) Date: Thu, 18 Dec 2008 14:50:50 -0800 Subject: [Ovirt-devel] [PATCH server] Reindent task_vm.rb Message-ID: <1229640650-5735-1-git-send-email-imain@redhat.com> This just changes the remaining 2 space indentation in task_vm to 4 space indentation.. yeah I'm evil. Signed-off-by: Ian Main --- src/task-omatic/task_vm.rb | 148 ++++++++++++++++++++++---------------------- 1 files changed, 74 insertions(+), 74 deletions(-) diff --git a/src/task-omatic/task_vm.rb b/src/task-omatic/task_vm.rb index 05ca3eb..0c79b27 100644 --- a/src/task-omatic/task_vm.rb +++ b/src/task-omatic/task_vm.rb @@ -25,120 +25,120 @@ gem 'cobbler' require 'cobbler' def find_host(host_id) - host = Host.find(:first, :conditions => [ "id = ?", host_id]) + host = Host.find(:first, :conditions => [ "id = ?", host_id]) - if host == nil - # Hm, we didn't find the host_id. Seems odd. Return a failure - raise "Could not find host_id " + host_id.to_s - end + if host == nil + # Hm, we didn't find the host_id. Seems odd. Return a failure + raise "Could not find host_id " + host_id.to_s + end - return host + return host end def create_vm_xml(name, uuid, memAllocated, memUsed, vcpus, bootDevice, macAddr, bridge, diskDevices) - doc = Document.new + doc = Document.new - doc.add_element("domain", {"type" => "kvm"}) + doc.add_element("domain", {"type" => "kvm"}) - doc.root.add_element("name").add_text(name) + doc.root.add_element("name").add_text(name) - doc.root.add_element("uuid").add_text(uuid) + doc.root.add_element("uuid").add_text(uuid) - doc.root.add_element("memory").add_text(memAllocated.to_s) + doc.root.add_element("memory").add_text(memAllocated.to_s) - doc.root.add_element("currentMemory").add_text(memUsed.to_s) + doc.root.add_element("currentMemory").add_text(memUsed.to_s) - doc.root.add_element("vcpu").add_text(vcpus.to_s) + doc.root.add_element("vcpu").add_text(vcpus.to_s) - doc.root.add_element("os") - doc.root.elements["os"].add_element("type").add_text("hvm") - doc.root.elements["os"].add_element("boot", {"dev" => bootDevice}) + doc.root.add_element("os") + doc.root.elements["os"].add_element("type").add_text("hvm") + doc.root.elements["os"].add_element("boot", {"dev" => bootDevice}) - doc.root.add_element("clock", {"offset" => "utc"}) + doc.root.add_element("clock", {"offset" => "utc"}) - doc.root.add_element("on_poweroff").add_text("destroy") + doc.root.add_element("on_poweroff").add_text("destroy") - doc.root.add_element("on_reboot").add_text("restart") + doc.root.add_element("on_reboot").add_text("restart") - doc.root.add_element("on_crash").add_text("destroy") + doc.root.add_element("on_crash").add_text("destroy") - doc.root.add_element("devices") - doc.root.elements["devices"].add_element("emulator").add_text("/usr/bin/qemu-kvm") + doc.root.add_element("devices") + doc.root.elements["devices"].add_element("emulator").add_text("/usr/bin/qemu-kvm") - devs = ['hda', 'hdb', 'hdc', 'hdd'] - which_device = 0 - diskDevices.each do |disk| - is_cdrom = (disk =~ /\.iso/) ? true : false + devs = ['hda', 'hdb', 'hdc', 'hdd'] + which_device = 0 + diskDevices.each do |disk| + is_cdrom = (disk =~ /\.iso/) ? true : false - diskdev = Element.new("disk") - diskdev.add_attribute("type", is_cdrom ? "file" : "block") - diskdev.add_attribute("device", is_cdrom ? "cdrom" : "disk") + diskdev = Element.new("disk") + diskdev.add_attribute("type", is_cdrom ? "file" : "block") + diskdev.add_attribute("device", is_cdrom ? "cdrom" : "disk") - if is_cdrom - diskdev.add_element("readonly") - diskdev.add_element("source", {"file" => disk}) - diskdev.add_element("target", {"dev" => devs[which_device], "bus" => "ide"}) - else - diskdev.add_element("source", {"dev" => disk}) - diskdev.add_element("target", {"dev" => devs[which_device]}) - end + if is_cdrom + diskdev.add_element("readonly") + diskdev.add_element("source", {"file" => disk}) + diskdev.add_element("target", {"dev" => devs[which_device], "bus" => "ide"}) + else + diskdev.add_element("source", {"dev" => disk}) + diskdev.add_element("target", {"dev" => devs[which_device]}) + end - doc.root.elements["devices"] << diskdev - which_device += 1 - end + doc.root.elements["devices"] << diskdev + which_device += 1 + end - doc.root.elements["devices"].add_element("interface", {"type" => "bridge"}) - doc.root.elements["devices"].elements["interface"].add_element("mac", {"address" => macAddr}) - doc.root.elements["devices"].elements["interface"].add_element("source", {"bridge" => bridge}) - doc.root.elements["devices"].add_element("input", {"type" => "mouse", "bus" => "ps2"}) - doc.root.elements["devices"].add_element("graphics", {"type" => "vnc", "port" => "-1", "listen" => "0.0.0.0"}) + doc.root.elements["devices"].add_element("interface", {"type" => "bridge"}) + doc.root.elements["devices"].elements["interface"].add_element("mac", {"address" => macAddr}) + doc.root.elements["devices"].elements["interface"].add_element("source", {"bridge" => bridge}) + doc.root.elements["devices"].add_element("input", {"type" => "mouse", "bus" => "ps2"}) + doc.root.elements["devices"].add_element("graphics", {"type" => "vnc", "port" => "-1", "listen" => "0.0.0.0"}) - serial = Element.new("serial") - serial.add_attribute("type", "pty") - serial.add_element("target", {"port" => "0"}) - doc.root.elements["devices"] << serial + serial = Element.new("serial") + serial.add_attribute("type", "pty") + serial.add_element("target", {"port" => "0"}) + doc.root.elements["devices"] << serial - return doc + return doc end def set_vm_state(vm, state) - vm.state = state - vm.save! + vm.state = state + vm.save! end def set_vm_vnc_port(vm, domain) - doc = REXML::Document.new(domain.xml_desc) - attrib = REXML::XPath.match(doc, "//graphics/@port") - if not attrib.empty?: - vm.vnc_port = attrib.to_s.to_i - end - vm.save! + doc = REXML::Document.new(domain.xml_desc) + attrib = REXML::XPath.match(doc, "//graphics/@port") + if not attrib.empty?: + vm.vnc_port = attrib.to_s.to_i + end + vm.save! end def find_vm(task, fail_on_nil_host_id = true) - # find the matching VM in the vms table - vm = task.vm + # find the matching VM in the vms table + vm = task.vm - if vm == nil - raise "VM #{task.vm} not found for task #{task.id}" - end + if vm == nil + raise "VM #{task.vm} not found for task #{task.id}" + end - if vm.host_id == nil && fail_on_nil_host_id - raise "No host_id for VM " + vm.id.to_s - end + if vm.host_id == nil && fail_on_nil_host_id + raise "No host_id for VM " + vm.id.to_s + end - return vm + return vm end def set_vm_shut_down(vm) - vm.host_id = nil - vm.memory_used = nil - vm.num_vcpus_used = nil - vm.state = Vm::STATE_STOPPED - vm.needs_restart = nil - vm.vnc_port = nil - vm.save! + vm.host_id = nil + vm.memory_used = nil + vm.num_vcpus_used = nil + vm.state = Vm::STATE_STOPPED + vm.needs_restart = nil + vm.vnc_port = nil + vm.save! end -- 1.6.0.4 From sseago at redhat.com Fri Dec 19 03:42:53 2008 From: sseago at redhat.com (Scott Seago) Date: Thu, 18 Dec 2008 22:42:53 -0500 Subject: [Ovirt-devel] [PATCH server] Reindent task_vm.rb In-Reply-To: <1229640650-5735-1-git-send-email-imain@redhat.com> References: <1229640650-5735-1-git-send-email-imain@redhat.com> Message-ID: <494B183D.3090700@redhat.com> Ian Main wrote: > This just changes the remaining 2 space indentation in task_vm to > 4 space indentation.. yeah I'm evil. > I'm all for consistency and everything, but 2 space indentation seems to be the de facto standard for most ruby development: I haven't found a definitive reference for this (mostly I've taken this from what I see in /usr/lib/ruby...) But I did find this: http://www.pathf.com/blogs/2008/10/elements-of-ruby-style/ Scott From imain at redhat.com Fri Dec 19 04:18:56 2008 From: imain at redhat.com (Ian Main) Date: Thu, 18 Dec 2008 20:18:56 -0800 Subject: [Ovirt-devel] [PATCH server] Reindent task_vm.rb In-Reply-To: <494B183D.3090700@redhat.com> References: <1229640650-5735-1-git-send-email-imain@redhat.com> <494B183D.3090700@redhat.com> Message-ID: <20081218201856.61274100@tp.mains.net> On Thu, 18 Dec 2008 22:42:53 -0500 Scott Seago wrote: > Ian Main wrote: > > This just changes the remaining 2 space indentation in task_vm to > > 4 space indentation.. yeah I'm evil. > > > > I'm all for consistency and everything, but 2 space indentation seems to > be the de facto standard for most ruby development: > > I haven't found a definitive reference for this (mostly I've taken this > from what I see in /usr/lib/ruby...) > > But I did find this: > > http://www.pathf.com/blogs/2008/10/elements-of-ruby-style/ > > Scott Yeah I figured that'd happen :)... and somehow I thought I might get away with it :) Ian From imain at redhat.com Fri Dec 19 06:08:39 2008 From: imain at redhat.com (Ian Main) Date: Thu, 18 Dec 2008 22:08:39 -0800 Subject: [Ovirt-devel] [PATCH server] Taskomatic Refactoring and Qpidification Take 2 Message-ID: <1229666919-9739-1-git-send-email-imain@redhat.com> This is a repost of the new patch in its entirety including a number of new bugfixes from this evening. If most folks think it should go to 2 spaces let me know, I'm not really opposed to that. This patch reworks taskomatic quite a bit. This mostly just shifts taskomatic to using the qpid interface in place of ruby-libvirt. It also fixes a few bugs I discovered a long the way and adds new ones I'm sure. The only other thing added was round-robin host selection for VMs. Wherevery possible the hosts are queried directly using qpid rather than relying on states from the database. This patch loses about 150 lines from the original taskomatic and moves most of the task implementation into a central class. This was done to provide access to the qpid session as well as providing for locking/task ordering in future versions. This requires the latest libvirt-qpid (0.2.8) as it fixes a number of bugs. It's in the ovirt repository now. Issues remaining: - libvirt-qpid migrate is broken. Since the migrate takes place on the node instead of from the ovirt-appliance, the source node doesn't have the ability to authenticate against the destination node. For this reason I'm still using ruby-libvirt migrate. I talked to Chris about this and we have a plan worked out. :) - I wanted to get threading into this but that will have to wait. I'll post a thread about this to get the discussion started again. I think the refactoring allows this to be put in pretty easily. Signed-off-by: Ian Main --- src/task-omatic/task_host.rb | 33 -- src/task-omatic/task_storage.rb | 438 ++++++++----------- src/task-omatic/task_vm.rb | 708 ++++--------------------------- src/task-omatic/taskomatic.rb | 915 ++++++++++++++++++++++++++++++++++----- src/task-omatic/utils.rb | 221 ---------- 5 files changed, 1065 insertions(+), 1250 deletions(-) delete mode 100644 src/task-omatic/task_host.rb delete mode 100644 src/task-omatic/utils.rb diff --git a/src/task-omatic/task_host.rb b/src/task-omatic/task_host.rb deleted file mode 100644 index 3d039fb..0000000 --- a/src/task-omatic/task_host.rb +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (C) 2008 Red Hat, Inc. -# Written by Chris Lalancette -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. A copy of the GNU General Public License is -# also available at http://www.gnu.org/copyleft/gpl.html. - -require 'utils' - -# FIXME: a little ugly to be including all of task_vm here, but -# utils really isn't the right place for the migrate() method -require 'task_vm' - -def clear_vms_host(task) - puts "clear_vms_host" - - src_host = task.host - - src_host.vms.each do |vm| - migrate(vm) - end -end diff --git a/src/task-omatic/task_storage.rb b/src/task-omatic/task_storage.rb index 19800fb..7167f52 100644 --- a/src/task-omatic/task_storage.rb +++ b/src/task-omatic/task_storage.rb @@ -16,287 +16,227 @@ # MA 02110-1301, USA. A copy of the GNU General Public License is # also available at http://www.gnu.org/copyleft/gpl.html. -require 'utils' - require 'libvirt' +require 'rexml/document' +include REXML -def add_volumes_to_db(db_pool, libvirt_pool, owner = nil, group = nil, mode = nil) - # FIXME: this is currently broken if you do something like: - # 1. Add an iscsi pool with 3 volumes (lun-1, lun-2, lun-3) - # 2. Scan it in - # 3. Remove lun-3 from the pool - # 4. Re-scan it - # What will happen is that you will still have lun-3 available in the - # database, even though it's not available in the pool anymore. It's a - # little tricky, though; we have to make sure that we don't pull the - # database entry out from underneath a possibly running VM (or do we?) - libvirt_pool.list_volumes.each do |volname| - storage_volume = StorageVolume.factory(db_pool.get_type_label) - - # NOTE: it is safe (and, in fact, necessary) to use - # #{storage_volume.volume_name} here without sanitizing it. This is - # because this is *not* based on user modifiable data, but rather, on an - # internal implementation detail - existing_vol = StorageVolume.find(:first, :conditions => - [ "storage_pool_id = ? AND #{storage_volume.volume_name} = ?", - db_pool.id, volname]) - if existing_vol != nil - # in this case, this path already exists in the database; just skip - next - end +def String.random_alphanumeric(size=16) + s = "" + size.times { s << (i = Kernel.rand(62); i += ((i < 10) ? 48 : ((i < 36) ? 55 : 61 ))).chr } + s +end - volptr = libvirt_pool.lookup_vol_by_name(volname) - - volinfo = volptr.info - - storage_volume = StorageVolume.factory(db_pool.get_type_label) - storage_volume.path = volptr.path - storage_volume.size = volinfo.capacity / 1024 - storage_volume.storage_pool_id = db_pool.id - storage_volume.write_attribute(storage_volume.volume_name, volname) - storage_volume.lv_owner_perms = owner - storage_volume.lv_group_perms = group - storage_volume.lv_mode_perms = mode - storage_volume.state = StorageVolume::STATE_AVAILABLE - storage_volume.save! - end +def get_libvirt_lvm_pool_from_volume(db_volume) + phys_volume = StorageVolume.find(:first, :conditions => + ["lvm_pool_id = ?", db_volume.storage_pool_id]) + + return LibvirtPool.factory(phys_volume.storage_pool) end -def storage_find_suitable_host(hardware_pool) - conn = nil - hardware_pool.hosts.each do |host| - if not host.is_disabled.nil? and host.is_disabled == 0 \ - and host.state == Host::STATE_AVAILABLE - begin - # FIXME: this can hang up taskomatic for quite some time. To see how, - # make one of your remote servers do "iptables -I INPUT -j DROP" - # and then try to run this; it will take TCP quite a while to give up. - # Unfortunately the solution is probably to do some sort of threading - conn = Libvirt::open("qemu+tcp://" + host.hostname + "/system") - - # if we didn't raise an exception, we connected; get out of here - break - rescue Libvirt::ConnectionError - # if we couldn't connect for whatever reason, just try the next host - next - end - end - end - - if conn == nil - # last ditch effort; if we didn't find any hosts, just use ourselves. - # this may or may not work - begin - conn = Libvirt::open("qemu:///system") - rescue - end - end +class LibvirtPool - if conn == nil - raise "Could not find a host to scan storage" - end + attr_reader :remote_pool - return conn -end + def initialize(type, name = nil) + @remote_pool = nil + @build_on_start = true + @remote_pool_defined = false + @remote_pool_started = false -# The words "pool" and "volume" are ridiculously overloaded in our context. -# Therefore, the refresh_pool method adopts this convention: -# phys_db_pool: The underlying physical storage pool, as it is represented in -# the database -# phys_libvirt_pool: The underlying physical storage, as it is represented in -# libvirt -# lvm_db_pool: The logical storage pool (if it exists), as it is represented -# in the database -# lvm_libvirt_pool: The logical storage pool (if it exists), as it is -# represented in the database - -def refresh_pool(task) - puts "refresh_pool" - - phys_db_pool = task.storage_pool - if phys_db_pool == nil - raise "Could not find storage pool" - end - - conn = storage_find_suitable_host(phys_db_pool.hardware_pool) - - begin - phys_libvirt_pool = LibvirtPool.factory(phys_db_pool) - phys_libvirt_pool.connect(conn) - - begin - # OK, the pool is all set. Add in all of the volumes - add_volumes_to_db(phys_db_pool, phys_libvirt_pool) - - phys_db_pool.state = StoragePool::STATE_AVAILABLE - phys_db_pool.save! - - # OK, now we've scanned the underlying hardware pool and added the - # volumes. Next we scan for pre-existing LVM volumes - logical_xml = conn.discover_storage_pool_sources("logical") - - Document.new(logical_xml).elements.each('sources/source') do |source| - vgname = source.elements["name"].text - - begin - source.elements.each("device") do |device| - byid_device = phys_libvirt_pool.lookup_vol_by_path(device.attributes["path"]).path - end - rescue - # If matching any of the sections in the LVM XML fails - # against the storage pool, then it is likely that this is a storage - # pool not associated with the one we connected above. Go on - # FIXME: it would be nicer to catch the right exception here, and - # fail on other exceptions - puts "One of the logical volumes in #{vgname} is not part of the pool of type #{phys_db_pool[:type]} that we are scanning; ignore the previous error!" - next + if name == nil + @name = type + "-" + String.random_alphanumeric + else + @name = name end - # if we make it here, then we were able to resolve all of the devices, - # so we know we need to use a new pool - lvm_db_pool = LvmStoragePool.find(:first, :conditions => - [ "vg_name = ?", vgname ]) - if lvm_db_pool == nil - lvm_db_pool = LvmStoragePool.new - lvm_db_pool[:type] = "LvmStoragePool" - # set the LVM pool to the same hardware pool as the underlying storage - lvm_db_pool.hardware_pool_id = phys_db_pool.hardware_pool_id - lvm_db_pool.vg_name = vgname - lvm_db_pool.save! + @xml = Document.new + @xml.add_element("pool", {"type" => type}) + + @xml.root.add_element("name").add_text(@name) + + @xml.root.add_element("source") + + @xml.root.add_element("target") + @xml.root.elements["target"].add_element("path") + end + + def connect(session, node) + pools = session.objects(:class => 'pool', 'node' => node.object_id) + pools.each do |pool| + result = pool.getXMLDesc + raise "Error getting xml description of pool: #{result.text}" unless result.status == 0 + + xml_desc = result.description + if self.xmlequal?(Document.new(xml_desc).root) + @remote_pool = pool + break + end end - source.elements.each("device") do |device| - byid_device = phys_libvirt_pool.lookup_vol_by_path(device.attributes["path"]).path - physical_vol = StorageVolume.find(:first, :conditions => - [ "path = ?", byid_device]) - if physical_vol == nil - # Hm. We didn't find the device in the storage volumes already. - # something went wrong internally, and we have to bail - raise "Storage internal physical volume error" - end - - # OK, put the right lvm_pool_id in place - physical_vol.lvm_pool_id = lvm_db_pool.id - physical_vol.save! + #XXX: I'm not sure.. it seems like there could be other things going on + # with the storage pool state. State can be inactive, building, running + # or degraded. I think some more thought should go here to make sure + # we're doing things right in each state. + if @remote_pool == nil + result = node.storagePoolDefineXML(@xml.to_s) + raise "Error creating pool: #{result.text}" unless result.status == 0 + @remote_pool = session.object(:object_id => result.pool) + raise "Error finding newly created remote pool." unless @remote_pool + + # we need this because we don't want to "build" LVM pools, which would + # destroy existing data + if @build_on_start + result = @remote_pool.build + raise "Error building pool: #{result.text}" unless result.status == 0 + end + @remote_pool_defined = true end - lvm_libvirt_pool = LibvirtPool.factory(lvm_db_pool) - lvm_libvirt_pool.connect(conn) + if @remote_pool.state == "inactive" + # only try to start the pool if it is currently inactive; in all other + # states, assume it is already running + result = @remote_pool.create + raise "Error creating pool: #{result.text}" unless result.status == 0 - begin - add_volumes_to_db(lvm_db_pool, lvm_libvirt_pool, "0744", "0744", "0744") - ensure - lvm_libvirt_pool.shutdown + # Refresh qpid object with new properties. + @remote_pool.update + + @remote_pool_started = true + end + end + + def create_vol(type, name, size, owner, group, mode) + @vol_xml = Document.new + @vol_xml.add_element("volume", {"type" => type}) + @vol_xml.root.add_element("name").add_text(name) + @vol_xml.root.add_element("capacity", {"unit" => "K"}).add_text(size.to_s) + @vol_xml.root.add_element("target") + @vol_xml.root.elements["target"].add_element("permissions") + @vol_xml.root.elements["target"].elements["permissions"].add_element("owner").add_text(owner) + @vol_xml.root.elements["target"].elements["permissions"].add_element("group").add_text(group) + @vol_xml.root.elements["target"].elements["permissions"].add_element("mode").add_text(mode) + end + + def shutdown + if @remote_pool_started + result = @remote_pool.destroy + end + if @remote_pool_defined + result = @remote_pool.undefine end - end - ensure - phys_libvirt_pool.shutdown end - ensure - conn.close - end -end -def create_volume(task) - puts "create_volume" + def xmlequal?(docroot) + return false + end - db_volume = task.storage_volume - if db_volume == nil - raise "Could not find storage volume to create" - end + def self.factory(pool) + if pool[:type] == "IscsiStoragePool" + return IscsiLibvirtPool.new(pool.ip_addr, pool[:target]) + elsif pool[:type] == "NfsStoragePool" + return NFSLibvirtPool.new(pool.ip_addr, pool.export_path) + elsif pool[:type] == "LvmStoragePool" + # OK, if this is LVM storage, there are two cases we need to care about: + # 1) this is a LUN with LVM already on it. In this case, all we need to + # do is to create a new LV (== libvirt volume), and be done with it + # 2) this LUN is blank, so there is no LVM on it already. In this + # case, we need to pvcreate, vgcreate first (== libvirt pool build), + # and *then* create the new LV (== libvirt volume) on top of that. + # + # We can tell the difference between an LVM Pool that exists and one + # that needs to be created based on the value of the pool.state; + # if it is PENDING_SETUP, we need to create it first + phys_volume = StorageVolume.find(:first, :conditions => + [ "lvm_pool_id = ?", pool.id]) + return LVMLibvirtPool.new(pool.vg_name, phys_volume.path, + pool.state == StoragePool::STATE_PENDING_SETUP) + else + raise "Unknown storage pool type " + pool[:type].to_s + end + end +end + +class IscsiLibvirtPool < LibvirtPool + def initialize(ip_addr, target) + super('iscsi') - db_pool = db_volume.storage_pool - if db_pool == nil - raise "Could not find storage pool" - end + @type = 'iscsi' + @ipaddr = ip_addr + @target = target - conn = storage_find_suitable_host(db_pool.hardware_pool) + @xml.root.elements["source"].add_element("host", {"name" => @ipaddr}) + @xml.root.elements["source"].add_element("device", {"path" => @target}) - begin - if db_volume[:type] == "LvmStorageVolume" - phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(db_volume) - phys_libvirt_pool.connect(conn) + @xml.root.elements["target"].elements["path"].text = "/dev/disk/by-id" end - begin - libvirt_pool = LibvirtPool.factory(db_pool) - - begin - libvirt_pool.connect(conn) - - libvirt_pool.create_vol(*db_volume.volume_create_params) - db_volume.state = StorageVolume::STATE_AVAILABLE - db_volume.save! - - db_pool.state = StoragePool::STATE_AVAILABLE - db_pool.save! - ensure - libvirt_pool.shutdown - end - ensure - if db_volume[:type] == "LvmStorageVolume" - phys_libvirt_pool.shutdown - end + def xmlequal?(docroot) + return (docroot.attributes['type'] == @type and + docroot.elements['source'].elements['host'].attributes['name'] == @ipaddr and + docroot.elements['source'].elements['device'].attributes['path'] == @target) end - ensure - conn.close - end end -def delete_volume(task) - puts "delete_volume" +class NFSLibvirtPool < LibvirtPool + def initialize(ip_addr, export_path) + super('netfs') + + @type = 'netfs' + @host = ip_addr + @remote_path = export_path + @name = String.random_alphanumeric + + @xml.root.elements["source"].add_element("host", {"name" => @host}) + @xml.root.elements["source"].add_element("dir", {"path" => @remote_path}) + @xml.root.elements["source"].add_element("format", {"type" => "nfs"}) - db_volume = task.storage_volume - if db_volume == nil - raise "Could not find storage volume to create" - end + @xml.root.elements["target"].elements["path"].text = "/mnt/" + @name + end + + def create_vol(name, size, owner, group, mode) + # FIXME: this can actually take some time to complete (since we aren't + # doing sparse allocations at the moment). During that time, whichever + # libvirtd we chose to use is completely hung up. The solution is 3-fold: + # 1. Allow sparse allocations in the WUI front-end + # 2. Make libvirtd multi-threaded + # 3. Make taskomatic multi-threaded + super("netfs", name, size, owner, group, mode) + + # FIXME: we have to add the format as raw here because of a bug in libvirt; + # if you specify a volume with no format, it will crash libvirtd + @vol_xml.root.elements["target"].add_element("format", {"type" => "raw"}) + @remote_pool.createVolumeXML(@vol_xml.to_s) + end - db_pool = db_volume.storage_pool - if db_pool == nil - raise "Could not find storage pool" - end + def xmlequal?(docroot) + return (docroot.attributes['type'] == @type and + docroot.elements['source'].elements['host'].attributes['name'] == @host and + docroot.elements['source'].elements['dir'].attributes['path'] == @remote_path) + end +end - conn = storage_find_suitable_host(db_pool.hardware_pool) +class LVMLibvirtPool < LibvirtPool + def initialize(vg_name, device, build_on_start) + super('logical', vg_name) - begin - if db_volume[:type] == "LvmStorageVolume" - phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(db_volume) - phys_libvirt_pool.connect(conn) + @type = 'logical' + @build_on_start = build_on_start + + @xml.root.elements["source"].add_element("name").add_text(@name) + @xml.root.elements["source"].add_element("device", {"path" => device}) + @xml.root.elements["target"].elements["path"].text = "/dev/" + @name + end + + def create_vol(name, size, owner, group, mode) + super("logical", name, size, owner, group, mode) + @remote_pool.createVolumeXML(@vol_xml.to_s) end - begin - libvirt_pool = LibvirtPool.factory(db_pool) - libvirt_pool.connect(conn) - - begin - libvirt_volume = libvirt_pool.lookup_vol_by_name(db_volume.read_attribute(db_volume.volume_name)) - # FIXME: we actually probably want to zero out the whole volume here, so - # we aren't potentially leaking data from one user to another. There - # are two problems, though: - # 1) I'm not sure how I would go about zero'ing the data on a remote - # machine, since there is no "libvirt_write_data" call - # 2) This could potentially take quite a while, so we want to spawn - # off another thread to do it - libvirt_volume.delete - - # Note: we have to nil out the task_target because when we delete the - # volume object, that also deletes all dependent tasks (including this - # one), which leads to accessing stale tasks. Orphan the task, then - # delete the object; we can clean up orphans later (or not, depending - # on the audit policy) - task.task_target = nil - task.save! - - db_volume.destroy - ensure - libvirt_pool.shutdown - end - ensure - if db_volume[:type] == "LvmStorageVolume" - phys_libvirt_pool.shutdown - end + def xmlequal?(docroot) + return (docroot.attributes['type'] == @type and + docroot.elements['name'].text == @name and + docroot.elements['source'].elements['name'] and + docroot.elements['source'].elements['name'].text == @name) end - ensure - conn.close - end end + diff --git a/src/task-omatic/task_vm.rb b/src/task-omatic/task_vm.rb index c187287..ae44a90 100644 --- a/src/task-omatic/task_vm.rb +++ b/src/task-omatic/task_vm.rb @@ -19,684 +19,124 @@ require 'rexml/document' include REXML -require 'utils' - gem 'cobbler' require 'cobbler' -def findHostSLA(vm) - host = nil - - vm.vm_resource_pool.get_hardware_pool.hosts.each do |curr| - # FIXME: we probably need to add in some notion of "load" into this check - if curr.num_cpus >= vm.num_vcpus_allocated \ - and curr.memory >= vm.memory_allocated \ - and not curr.is_disabled.nil? and curr.is_disabled == 0 \ - and curr.state == Host::STATE_AVAILABLE \ - and (vm.host_id.nil? or (not vm.host_id.nil? and vm.host_id != curr.id)) - host = curr - break - end - end - - if host == nil - # we couldn't find a host that matches this criteria - raise "No host matching VM parameters could be found" - end - - return host -end - -def findHost(host_id) - host = Host.find(:first, :conditions => [ "id = ?", host_id]) - - if host == nil - # Hm, we didn't find the host_id. Seems odd. Return a failure - raise "Could not find host_id " + host_id.to_s - end +def find_host(host_id) + host = Host.find(:first, :conditions => [ "id = ?", host_id]) - return host -end - -def connect_storage_pools(conn, storage_volumes) - storagedevs = [] - storage_volumes.each do |volume| - # here, we need to iterate through each volume and possibly attach it - # to the host we are going to be using - db_pool = volume.storage_pool - if db_pool == nil - # Hum. Specified by the VM description, but not in the storage pool? - # continue on and hope for the best - puts "Couldn't find pool for volume #{volume.path}; skipping" - next - end - - # we have to special case LVM pools. In that case, we need to first - # activate the underlying physical device, and then do the logical one - if volume[:type] == "LvmStorageVolume" - phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(volume) - phys_libvirt_pool.connect(conn) + if host == nil + # Hm, we didn't find the host_id. Seems odd. Return a failure + raise "Could not find host_id " + host_id.to_s end - libvirt_pool = LibvirtPool.factory(db_pool) - libvirt_pool.connect(conn) - - # OK, the pool should be all set. The last thing we need to do is get - # the path based on the volume name - storagedevs << libvirt_pool.lookup_vol_by_name(volume.read_attribute(volume.volume_name)).path - end - - return storagedevs + return host end -def remove_pools(conn, type = nil) - all_storage_pools(conn).each do |remote_pool_name| - pool = conn.lookup_storage_pool_by_name(remote_pool_name) - - if type == nil or type == Document.new(pool.xml_desc).root.attributes['type'] - begin - pool.destroy - rescue - end - - begin - # if the destroy failed, we still try to undefine; it may be a pool - # that was previously destroyed but not undefined for whatever reason - pool.undefine - rescue - # do nothing if any of this failed; the worst that happens is that - # we leave a pool configured - puts "Could not teardown pool " + remote_pool_name + "; skipping" - end - end - end -end - -def teardown_storage_pools(conn) - # FIXME: this needs to get a *lot* smarter. In particular, we want to make - # sure we can tear down unused pools even when there are other guests running - if conn.list_domains.empty? - # OK, there are no running guests on this host anymore. We can teardown - # any storage pools that are there without fear - - # we first have to tear-down LVM pools, because they might depend on the - # underlying physical pools - remove_pools(conn, "logical") - - # now tear down the rest of the pools - remove_pools(conn) - end -end def create_vm_xml(name, uuid, memAllocated, memUsed, vcpus, bootDevice, macAddr, bridge, diskDevices) - doc = Document.new - - doc.add_element("domain", {"type" => "kvm"}) - - doc.root.add_element("name").add_text(name) - - doc.root.add_element("uuid").add_text(uuid) - - doc.root.add_element("memory").add_text(memAllocated.to_s) - - doc.root.add_element("currentMemory").add_text(memUsed.to_s) - - doc.root.add_element("vcpu").add_text(vcpus.to_s) - - doc.root.add_element("os") - doc.root.elements["os"].add_element("type").add_text("hvm") - doc.root.elements["os"].add_element("boot", {"dev" => bootDevice}) - - doc.root.add_element("clock", {"offset" => "utc"}) + doc = Document.new - doc.root.add_element("on_poweroff").add_text("destroy") + doc.add_element("domain", {"type" => "kvm"}) - doc.root.add_element("on_reboot").add_text("restart") + doc.root.add_element("name").add_text(name) - doc.root.add_element("on_crash").add_text("destroy") + doc.root.add_element("uuid").add_text(uuid) - doc.root.add_element("devices") - doc.root.elements["devices"].add_element("emulator").add_text("/usr/bin/qemu-kvm") + doc.root.add_element("memory").add_text(memAllocated.to_s) - devs = ['hda', 'hdb', 'hdc', 'hdd'] - which_device = 0 - diskDevices.each do |disk| - is_cdrom = (disk =~ /\.iso/) ? true : false + doc.root.add_element("currentMemory").add_text(memUsed.to_s) - diskdev = Element.new("disk") - diskdev.add_attribute("type", is_cdrom ? "file" : "block") - diskdev.add_attribute("device", is_cdrom ? "cdrom" : "disk") + doc.root.add_element("vcpu").add_text(vcpus.to_s) - if is_cdrom - diskdev.add_element("readonly") - diskdev.add_element("source", {"file" => disk}) - diskdev.add_element("target", {"dev" => devs[which_device], "bus" => "ide"}) - else - diskdev.add_element("source", {"dev" => disk}) - diskdev.add_element("target", {"dev" => devs[which_device]}) - end - - doc.root.elements["devices"] << diskdev - which_device += 1 - end - - doc.root.elements["devices"].add_element("interface", {"type" => "bridge"}) - doc.root.elements["devices"].elements["interface"].add_element("mac", {"address" => macAddr}) - doc.root.elements["devices"].elements["interface"].add_element("source", {"bridge" => bridge}) - doc.root.elements["devices"].add_element("input", {"type" => "mouse", "bus" => "ps2"}) - doc.root.elements["devices"].add_element("graphics", {"type" => "vnc", "port" => "-1", "listen" => "0.0.0.0"}) - - serial = Element.new("serial") - serial.add_attribute("type", "pty") - serial.add_element("target", {"port" => "0"}) - doc.root.elements["devices"] << serial - - return doc -end - -def setVmState(vm, state) - vm.state = state - vm.save! -end - -def setVmVncPort(vm, domain) - doc = REXML::Document.new(domain.xml_desc) - attrib = REXML::XPath.match(doc, "//graphics/@port") - if not attrib.empty?: - vm.vnc_port = attrib.to_s.to_i - end - vm.save! -end - -def findVM(task, fail_on_nil_host_id = true) - # find the matching VM in the vms table - vm = task.vm - - if vm == nil - raise "VM not found for task " + task.id - end - - if vm.host_id == nil && fail_on_nil_host_id - # in this case, we have no idea where the VM is. How can we handle this - # gracefully? We don't necessarily want to just set the VM state to off; - # if the machine does happen to be running somewhere and we set it to - # disabled here, and then start it again, we could corrupt the disk - - # FIXME: the right thing to do here is probably to contact all of the - # hosts we know about and ensure that the domain isn't running; then we - # can mark it either as off (if we didn't find it), or mark the correct - # vm.host_id if we did. However, if you have a large number of hosts - # out there, this could take a while. - raise "No host_id for VM " + vm.id.to_s - end - - return vm -end - -def setVmShutdown(vm) - vm.host_id = nil - vm.memory_used = nil - vm.num_vcpus_used = nil - vm.state = Vm::STATE_STOPPED - vm.needs_restart = nil - vm.vnc_port = nil - vm.save! -end + doc.root.add_element("os") + doc.root.elements["os"].add_element("type").add_text("hvm") + doc.root.elements["os"].add_element("boot", {"dev" => bootDevice}) -def create_vm(task) - puts "create_vm" + doc.root.add_element("clock", {"offset" => "utc"}) - vm = findVM(task, false) + doc.root.add_element("on_poweroff").add_text("destroy") - if vm.state != Vm::STATE_PENDING - raise "VM not pending" - end - setVmState(vm, Vm::STATE_CREATING) - - # create cobbler system profile - begin - # FIXME: Presently the wui handles all cobbler system creation. - # This should be moved out of the wui into Taskomatic. Specifically - # here, and in the edit_vm methods. - - setVmState(vm, Vm::STATE_STOPPED) - rescue Exception => error - setVmState(vm, Vm::STATE_CREATE_FAILED) - raise "Unable to create system: #{error.message}" - end -end - -def shut_or_destroy_vm(task, which) - # here, we are given an id for a VM to shutdown; we have to lookup which - # physical host it is running on - - vm = findVM(task) - - if vm.state == Vm::STATE_STOPPED - # the VM is already shutdown; just return success - setVmShutdown(vm) - return - elsif vm.state == Vm::STATE_SUSPENDED - raise "Cannot shutdown suspended domain" - elsif vm.state == Vm::STATE_SAVED - raise "Cannot shutdown saved domain" - end - - vm_orig_state = vm.state - setVmState(vm, Vm::STATE_STOPPING) - - begin - conn = Libvirt::open("qemu+tcp://" + vm.host.hostname + "/system") - dom = conn.lookup_domain_by_uuid(vm.uuid) - dom.send(which) - - begin - dom.undefine - rescue - # undefine can fail, for instance, if we live migrated from A -> B, and - # then we are shutting down the VM on B (because it only has "transient" - # XML). Therefore, just ignore undefine errors so we do the rest - # FIXME: we really should have a marker in the database somehow so that - # we can tell if this domain was migrated; that way, we can tell the - # difference between a real undefine failure and one because of migration - end - - teardown_storage_pools(conn) - - conn.close - rescue => ex - setVmState(vm, vm_orig_state) - raise ex - end - - setVmShutdown(vm) -end - -def shutdown_vm(task) - puts "shutdown_vm" - shut_or_destroy_vm(task, "shutdown") -end - -def poweroff_vm(task) - puts "poweroff_vm" - shut_or_destroy_vm(task, "destroy") -end + doc.root.add_element("on_reboot").add_text("restart") -def start_vm(task) - puts "start_vm" + doc.root.add_element("on_crash").add_text("destroy") - # here, we are given an id for a VM to start + doc.root.add_element("devices") + doc.root.elements["devices"].add_element("emulator").add_text("/usr/bin/qemu-kvm") - vm = findVM(task, false) + devs = ['hda', 'hdb', 'hdc', 'hdd'] + which_device = 0 + diskDevices.each do |disk| + is_cdrom = (disk =~ /\.iso/) ? true : false - if vm.state == Vm::STATE_RUNNING - # the VM is already running; just return success - return - elsif vm.state == Vm::STATE_SUSPENDED - raise "Cannot start suspended domain" - elsif vm.state == Vm::STATE_SAVED - raise "Cannot start saved domain" - end + diskdev = Element.new("disk") + diskdev.add_attribute("type", is_cdrom ? "file" : "block") + diskdev.add_attribute("device", is_cdrom ? "cdrom" : "disk") - # FIXME: Validate that the VM is still within quota - - vm_orig_state = vm.state - setVmState(vm, Vm::STATE_STARTING) - - begin - if vm.host_id != nil - # OK, marked in the database as already running on a host; for now, we - # will just fail the operation - - # FIXME: we probably want to go out to the host it is marked on and check - # things out, just to make sure things are consistent - raise "VM already running" - end - - # OK, now that we found the VM, go looking in the hardware_pool - # hosts to see if there is a host that will fit these constraints - host = findHostSLA(vm) - - # if we're booting from a CDROM the VM is an image, - # then we need to add the NFS mount as a storage volume for this - # boot - # - if (vm.boot_device == Vm::BOOT_DEV_CDROM) && vm.uses_cobbler? && (vm.cobbler_type == Vm::IMAGE_PREFIX) - details = Cobbler::Image.find_one(vm.cobbler_name) - - raise "Image #{vm.cobbler_name} not found in Cobbler server" unless details - - # extract the components of the image filename - image_uri = details.file - protocol = auth = ip_addr = export_path = filename = "" - - protocol, image_uri = image_uri.split("://") if image_uri.include?("://") - auth, image_uri = image_uri.split("@") if image_uri.include?("@") - # it's ugly, but string.split returns an empty string as the first - # result here, so we'll just ignore it - ignored, ip_addr, image_uri = - image_uri.split(/^([^\/]+)(\/.*)/) unless image_uri =~ /^\// - ignored, export_path, filename = - image_uri.split(/^(.*)\/(.+)/) - - found = false - - vm.storage_volumes.each do |volume| - if volume.filename == filename - if (volume.storage_pool.ip_addr == ip_addr) && - (volume.storage_pool.export_path == export_path) - found = true - end + if is_cdrom + diskdev.add_element("readonly") + diskdev.add_element("source", {"file" => disk}) + diskdev.add_element("target", {"dev" => devs[which_device], "bus" => "ide"}) + else + diskdev.add_element("source", {"dev" => disk}) + diskdev.add_element("target", {"dev" => devs[which_device]}) end - end - - unless found - # Create a new transient NFS storage volume - # This volume is *not* persisted. - image_volume = StorageVolume.factory("NFS", - :filename => filename - ) - - image_volume.storage_pool - image_pool = StoragePool.factory(StoragePool::NFS) - - image_pool.ip_addr = ip_addr - image_pool.export_path = export_path - image_pool.storage_volumes << image_volume - image_volume.storage_pool = image_pool - end - end - volumes = [] - volumes += vm.storage_volumes - volumes << image_volume if image_volume - - conn = Libvirt::open("qemu+tcp://" + host.hostname + "/system") - - begin - storagedevs = connect_storage_pools(conn, volumes) - - dom = nil - begin - # FIXME: get rid of the hardcoded bridge - xml = create_vm_xml(vm.description, vm.uuid, vm.memory_allocated, - vm.memory_used, vm.num_vcpus_allocated, - vm.boot_device, vm.vnic_mac_addr, "ovirtbr0", - storagedevs) - dom = conn.define_domain_xml(xml.to_s) - dom.create - - setVmVncPort(vm, dom) - rescue - if dom != nil - dom.undefine - end - teardown_storage_pools(conn) - raise ex - end - ensure - conn.close + doc.root.elements["devices"] << diskdev + which_device += 1 end - rescue => ex - setVmState(vm, vm_orig_state) - raise ex - end - - vm.host_id = host.id - vm.state = Vm::STATE_RUNNING - vm.memory_used = vm.memory_allocated - vm.num_vcpus_used = vm.num_vcpus_allocated - vm.boot_device = Vm::BOOT_DEV_HD - vm.save! -end - -def save_vm(task) - puts "save_vm" - - # here, we are given an id for a VM to suspend - - vm = findVM(task) - - if vm.state == Vm::STATE_SAVED - # the VM is already saved; just return success - return - elsif vm.state == Vm::STATE_SUSPENDED - raise "Cannot save suspended domain" - elsif vm.state == Vm::STATE_STOPPED - raise "Cannot save shutdown domain" - end - - vm_orig_state = vm.state - setVmState(vm, Vm::STATE_SAVING) - - begin - conn = Libvirt::open("qemu+tcp://" + vm.host.hostname + "/system") - dom = conn.lookup_domain_by_uuid(vm.uuid) - dom.save("/tmp/" + vm.uuid + ".save") - conn.close - rescue => ex - setVmState(vm, vm_orig_state) - raise ex - end - # note that we do *not* reset the host_id here, since we stored the saved - # vm state information locally. restore_vm will pick it up from here + doc.root.elements["devices"].add_element("interface", {"type" => "bridge"}) + doc.root.elements["devices"].elements["interface"].add_element("mac", {"address" => macAddr}) + doc.root.elements["devices"].elements["interface"].add_element("source", {"bridge" => bridge}) + doc.root.elements["devices"].add_element("input", {"type" => "mouse", "bus" => "ps2"}) + doc.root.elements["devices"].add_element("graphics", {"type" => "vnc", "port" => "-1", "listen" => "0.0.0.0"}) - # FIXME: it would be much nicer to be able to save the VM and remove the - # the host_id and undefine the XML; that way we could resume it on another - # host later. This can be done once we have the storage APIs, but it will - # need more work + serial = Element.new("serial") + serial.add_attribute("type", "pty") + serial.add_element("target", {"port" => "0"}) + doc.root.elements["devices"] << serial - setVmState(vm, Vm::STATE_SAVED) + return doc end -def restore_vm(task) - puts "restore_vm" - - # here, we are given an id for a VM to start - - vm = findVM(task) - - if vm.state == Vm::STATE_RUNNING - # the VM is already saved; just return success - return - elsif vm.state == Vm::STATE_SUSPENDED - raise "Cannot restore suspended domain" - elsif vm.state == Vm::STATE_STOPPED - raise "Cannot restore shutdown domain" - end - - vm_orig_state = vm.state - setVmState(vm, Vm::STATE_RESTORING) - - begin - # FIXME: we should probably go out to the host and check what it thinks - # the state is - - conn = Libvirt::open("qemu+tcp://" + vm.host.hostname + "/system") - dom = conn.lookup_domain_by_uuid(vm.uuid) - dom.restore - - setVmVncPort(vm, dom) - - conn.close - rescue => ex - setVmState(vm, vm_orig_state) - raise ex - end - - setVmState(vm, Vm::STATE_RUNNING) -end - -def suspend_vm(task) - puts "suspend_vm" - - # here, we are given an id for a VM to suspend; we have to lookup which - # physical host it is running on - - vm = findVM(task) - - if vm.state == Vm::STATE_SUSPENDED - # the VM is already suspended; just return success - return - elsif vm.state == Vm::STATE_STOPPED - raise "Cannot suspend stopped domain" - elsif vm.state == Vm::STATE_SAVED - raise "Cannot suspend saved domain" - end - - vm_orig_state = vm.state - setVmState(vm, Vm::STATE_SUSPENDING) - - begin - conn = Libvirt::open("qemu+tcp://" + vm.host.hostname + "/system") - dom = conn.lookup_domain_by_uuid(vm.uuid) - dom.suspend - conn.close - rescue => ex - setVmState(vm, vm_orig_state) - raise ex - end - - # note that we do *not* reset the host_id here, since we just suspended the VM - # resume_vm will pick it up from here - - setVmState(vm, Vm::STATE_SUSPENDED) -end - -def resume_vm(task) - puts "resume_vm" - - # here, we are given an id for a VM to start - - vm = findVM(task) - - # OK, marked in the database as already running on a host; let's check it - - if vm.state == Vm::STATE_RUNNING - # the VM is already suspended; just return success - return - elsif vm.state == Vm::STATE_STOPPED - raise "Cannot resume stopped domain" - elsif vm.state == Vm::STATE_SAVED - raise "Cannot resume suspended domain" - end - - vm_orig_state = vm.state - setVmState(vm, Vm::STATE_RESUMING) - - begin - conn = Libvirt::open("qemu+tcp://" + vm.host.hostname + "/system") - dom = conn.lookup_domain_by_uuid(vm.uuid) - dom.resume - conn.close - rescue => ex - setVmState(vm, vm_orig_state) - raise ex - end - - setVmState(vm, Vm::STATE_RUNNING) +def set_vm_state(vm, state) + vm.state = state + vm.save! end -def update_state_vm(task) - puts "update_state_vm" - - # NOTE: findVM() will only return a vm if all the host information is filled - # in. So if a vm that we thought was stopped is running, this returns nil - # and we don't update any information about it. The tricky part - # is that we're still not sure what to do in this case :). - Ian - # - # Actually for migration it is necessary that it be able to update - # the host and state of the VM once it is migrated. - vm = findVM(task, false) - new_vm_state, host_id_str = task.args.split(",") - if (vm.host_id == nil) and host_id_str - vm.host_id = host_id_str.to_i - end - - - vm_effective_state = Vm::EFFECTIVE_STATE[vm.state] - task_effective_state = Vm::EFFECTIVE_STATE[new_vm_state] - - if vm_effective_state != task_effective_state - vm.state = new_vm_state - - if task_effective_state == Vm::STATE_STOPPED - setVmShutdown(vm) +def set_vm_vnc_port(vm, xml_desc) + doc = REXML::Document.new(xml_desc) + attrib = REXML::XPath.match(doc, "//graphics/@port") + if not attrib.empty?: + vm.vnc_port = attrib.to_s.to_i end vm.save! - puts "Updated state to " + new_vm_state - end end -def migrate(vm, dest = nil) - if vm.state == Vm::STATE_STOPPED - raise "Cannot migrate stopped domain" - elsif vm.state == Vm::STATE_SUSPENDED - raise "Cannot migrate suspended domain" - elsif vm.state == Vm::STATE_SAVED - raise "Cannot migrate saved domain" - end - - vm_orig_state = vm.state - setVmState(vm, Vm::STATE_MIGRATING) - - begin - src_host = findHost(vm.host_id) - unless dest.nil? or dest.empty? - if dest.to_i == vm.host_id - raise "Cannot migrate from host " + src_host.hostname + " to itself!" - end - dst_host = findHost(dest.to_i) - else - dst_host = findHostSLA(vm) +def find_vm(task, fail_on_nil_host_id = true) + # find the matching VM in the vms table + vm = task.vm + + if vm == nil + raise "VM #{task.vm} not found for task #{task.id}" end - src_conn = Libvirt::open("qemu+tcp://" + src_host.hostname + "/system") - dst_conn = Libvirt::open("qemu+tcp://" + dst_host.hostname + "/system") - - connect_storage_pools(dst_conn, vm) - - dom = src_conn.lookup_domain_by_uuid(vm.uuid) - dom.migrate(dst_conn, Libvirt::Domain::MIGRATE_LIVE) - - # if we didn't raise an exception, then the migration was successful. We - # still have a pointer to the now-shutdown domain on the source side, so - # undefine it - begin - dom.undefine - rescue - # undefine can fail, for instance, if we live migrated from A -> B, and - # then we are shutting down the VM on B (because it only has "transient" - # XML). Therefore, just ignore undefine errors so we do the rest - # FIXME: we really should have a marker in the database somehow so that - # we can tell if this domain was migrated; that way, we can tell the - # difference between a real undefine failure and one because of migration + if vm.host_id == nil && fail_on_nil_host_id + raise "No host_id for VM " + vm.id.to_s end - teardown_storage_pools(src_conn) - dst_conn.close - src_conn.close - rescue => ex - # FIXME: ug. We may have open connections that we need to close; not - # sure how to handle that - setVmState(vm, vm_orig_state) - raise ex - end - - setVmState(vm, Vm::STATE_RUNNING) - vm.host_id = dst_host.id - vm.save! + return vm end -def migrate_vm(task) - puts "migrate_vm" - - # here, we are given an id for a VM to migrate; we have to lookup which - # physical host it is running on - - vm = findVM(task) - - migrate(vm, task.args) +def set_vm_shut_down(vm) + vm.host_id = nil + vm.memory_used = nil + vm.num_vcpus_used = nil + vm.state = Vm::STATE_STOPPED + vm.needs_restart = nil + vm.vnc_port = nil + vm.save! end + diff --git a/src/task-omatic/taskomatic.rb b/src/task-omatic/taskomatic.rb index ce37058..de56a90 100755 --- a/src/task-omatic/taskomatic.rb +++ b/src/task-omatic/taskomatic.rb @@ -1,7 +1,7 @@ #!/usr/bin/ruby -# +# # Copyright (C) 2008 Red Hat, Inc. -# Written by Chris Lalancette +# Written by Chris Lalancette and Ian Main # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -22,122 +22,811 @@ $: << File.join(File.dirname(__FILE__), "../dutils") $: << File.join(File.dirname(__FILE__), ".") require 'rubygems' +require "qpid" +require 'monitor' +require 'dutils' require 'optparse' require 'daemons' include Daemonize -$logfile = '/var/log/ovirt-server/taskomatic.log' - -do_daemon = true -sleeptime = 5 -opts = OptionParser.new do |opts| - opts.on("-h", "--help", "Print help message") do - puts opts - exit - end - opts.on("-n", "--nodaemon", "Run interactively (useful for debugging)") do |n| - do_daemon = !n - end - opts.on("-s N", Integer, "--sleep", "Seconds to sleep between iterations (default is 5 seconds)") do |s| - sleeptime = s - end -end -begin - opts.parse!(ARGV) -rescue OptionParser::InvalidOption - puts opts - exit -end +require 'task_vm' +require 'task_storage' -if do_daemon - daemonize - STDOUT.reopen $logfile, 'a' - STDERR.reopen STDOUT -end +class TaskOmatic -begin - require 'dutils' -rescue => ex - puts "dutils require failed! #{ex.class}: #{ex.message}" -end + include MonitorMixin -require 'task_vm' -require 'task_storage' -require 'task_host' - -loop do - tasks = Array.new - begin - tasks = Task.find(:all, :conditions => [ "state = ?", Task::STATE_QUEUED ]) - rescue => ex - puts "1 #{ex.class}: #{ex.message}" - if Task.connected? - begin - ActiveRecord::Base.connection.reconnect! - rescue => norecon - puts "2 #{norecon.class}: #{norecon.message}" - end - else - begin - database_connect - rescue => ex - puts "3 #{ex.class}: #{ex.message}" - end - end - end - tasks.each do |task| - # make sure we get our credentials up-front - get_credentials - - task.time_started = Time.now - task.state = Task::STATE_RUNNING - task.save! - - state = Task::STATE_FINISHED - begin - case task.action - when VmTask::ACTION_CREATE_VM then create_vm(task) - when VmTask::ACTION_SHUTDOWN_VM then shutdown_vm(task) - when VmTask::ACTION_POWEROFF_VM then poweroff_vm(task) - when VmTask::ACTION_START_VM then start_vm(task) - when VmTask::ACTION_SUSPEND_VM then suspend_vm(task) - when VmTask::ACTION_RESUME_VM then resume_vm(task) - when VmTask::ACTION_SAVE_VM then save_vm(task) - when VmTask::ACTION_RESTORE_VM then restore_vm(task) - when VmTask::ACTION_UPDATE_STATE_VM then update_state_vm(task) - when VmTask::ACTION_MIGRATE_VM then migrate_vm(task) - when StorageTask::ACTION_REFRESH_POOL then refresh_pool(task) - when StorageVolumeTask::ACTION_CREATE_VOLUME then create_volume(task) - when StorageVolumeTask::ACTION_DELETE_VOLUME then delete_volume(task) - when HostTask::ACTION_CLEAR_VMS then clear_vms_host(task) - else - puts "unknown task " + task.action - state = Task::STATE_FAILED - task.message = "Unknown task type" - end - rescue => ex - puts "Task action processing failed: #{ex.class}: #{ex.message}" - puts ex.backtrace - state = Task::STATE_FAILED - task.message = ex.message - end - - task.state = state - task.time_ended = Time.now - task.save! - puts "done" - end - - # FIXME: here, we clean up "orphaned" tasks. These are tasks that we had - # to orphan (set task_target to nil) because we were deleting the object they - # depended on. - Task.find(:all, :conditions => [ "task_target_id IS NULL and task_target_type IS NULL" ]).each do |task| - task.destroy - end - - # we could destroy credentials, but another process might be using them (in - # particular, host-browser). Just leave them around, it shouldn't hurt - - STDOUT.flush - sleep sleeptime + $logfile = '/var/log/ovirt-server/taskomatic.log' + + def initialize() + super() + + @sleeptime = 5 + @nth_host = 0 + + @session = Qpid::Qmf::Session.new() + # FIXME: Should come from some kind of config or DNS SRV or what have you. + @broker = @session.add_broker("amqp://localhost:5672") + + do_daemon = true + + opts = OptionParser.new do |opts| + opts.on("-h", "--help", "Print help message") do + puts opts + exit + end + opts.on("-n", "--nodaemon", "Run interactively (useful for debugging)") do |n| + do_daemon = false + end + opts.on("-s N", Integer, "--sleep", "Seconds to sleep between iterations (default is 5 seconds)") do |s| + sleeptime = s + end + end + begin + opts.parse!(ARGV) + rescue OptionParser::InvalidOption + puts opts + exit + end + + if do_daemon + # XXX: This gets around a problem with paths for the database stuff. + # Normally daemonize would chdir to / but the paths for the database + # stuff are relative so it breaks it.. It's either this or rearrange + # things so the db stuff is included after daemonizing. + pwd = Dir.pwd + daemonize + Dir.chdir(pwd) + STDOUT.reopen $logfile, 'a' + STDERR.reopen STDOUT + end + end + + def find_capable_host(db_vm) + possible_hosts = [] + + vm = @session.object(:class => "domain", 'uuid' => db_vm.uuid) + + db_vm.vm_resource_pool.get_hardware_pool.hosts.each do |curr| + # Now each of 'curr' is in the right hardware pool.. now we check them out. + + node = @session.object(:class => "node", 'hostname' => curr.hostname) + next unless node + + # So now we expect if the node was found it's alive and well, then we check + # to make sure there's enough real cores for the number of vcpus, the node + # memory is adequate, the node is not disabled in the database, and if the + # node id is nil or if it is already running (has a node id set) then it + # is probably looking to migrate so we find a node that is not the current + # node. + # + # In the future we could add load or similar checks here. + + #puts "checking node, #{node.cores} >= #{db_vm.num_vcpus_allocated}," + #puts "and #{node.memory} >= #{db_vm.memory_allocated}" + #puts "and not #{curr.is_disabled.nil?} and #{curr.is_disabled == 0}" + #puts "and #{vm ? vm : 'nil'} or #{vm ? vm.active : 'nil'}) or #{vm ? vm.node : 'nil'} != #{node.object_id}" + + if node and node.cores >= db_vm.num_vcpus_allocated \ + and node.memory >= db_vm.memory_allocated \ + and not curr.is_disabled.nil? and curr.is_disabled == 0 \ + and ((!vm or vm.active == 'false') or vm.node != node.object_id) + possible_hosts.push(curr) + end + end + + #puts "possible_hosts.length = #{possible_hosts.length}" + if possible_hosts.length == 0 + # we couldn't find a host that matches this criteria + raise "No host matching VM parameters could be found" + end + + # XXX: Right now we're just picking the nth host, we could also look at + # how many vms are already on it, or the load of the hosts etc. + host = possible_hosts[@nth_host % possible_hosts.length] + @nth_host += 1 + + return host + end + + def connect_storage_pools(node, storage_volumes) + storagedevs = [] + storage_volumes.each do |db_volume| + # here, we need to iterate through each volume and possibly attach it + # to the host we are going to be using + db_pool = db_volume.storage_pool + if db_pool == nil + # Hum. Specified by the VM description, but not in the storage pool? + # continue on and hope for the best + puts "Couldn't find pool for volume #{db_volume.path}; skipping" + next + end + + # we have to special case LVM pools. In that case, we need to first + # activate the underlying physical device, and then do the logical one + if db_volume[:type] == "LvmStorageVolume" + phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(db_volume) + phys_libvirt_pool.connect(@session, node) + end + + libvirt_pool = LibvirtPool.factory(db_pool) + libvirt_pool.connect(@session, node) + + # OK, the pool should be all set. The last thing we need to do is get + # the path based on the volume name + + volume_name = db_volume.read_attribute(db_volume.volume_name) + pool = libvirt_pool.remote_pool + volume = @session.object(:class => 'volume', + 'name' => volume_name, + 'storagePool' => pool.object_id) + raise "Unable to find volume #{volume_name} attached to pool #{pool.name}." unless volume + storagedevs << volume.path + end + + return storagedevs + end + + def task_create_vm(task) + # XXX: This is mostly just a place holder. + vm = find_vm(task, false) + if vm.state != Vm::STATE_PENDING + raise "VM not pending" + end + vm.state = Vm::STATE_STOPPED + vm.save! + end + + def teardown_storage_pools(node) + + # This is rather silly because we only destroy pools if there are no + # more vms on the node. We should be reference counting the pools + # somehow so we know when they are no longer in use. + vms = @session.objects(:class => 'domain', 'node' => node.object_id) + if vms.length > 0 + return + end + pools = @session.objects(:class => 'pool', 'node' => node.object_id) + + # FIXME: I think we should be destroying/undefining logical volumes first. + pools.each do |pool| + result = pool.destroy + result = pool.undefine + end + end + + + def task_shutdown_or_destroy_vm(task, action) + db_vm = task.vm + vm = @session.object(:class => 'domain', 'uuid' => db_vm.uuid) + if !vm + puts "VM already shut down?" + return + end + + node = @session.object(:object_id => vm.node) + raise "Unable to get node that vm is on??" unless node + + if vm.state == "shutdown" or vm.state == "shutoff" + set_vm_shut_down(db_vm) + return + elsif vm.state == "suspended" + raise "Cannot shutdown suspended domain" + elsif vm.state == "saved" + raise "Cannot shutdown saved domain" + end + + if action == :shutdown + result = vm.shutdown + raise "Error shutting down VM: #{result.text}" unless result.status == 0 + elsif action == :destroy + result = vm.destroy + raise "Error destroying VM: #{result.text}" unless result.status == 0 + end + + # undefine can fail, for instance, if we live migrated from A -> B, and + # then we are shutting down the VM on B (because it only has "transient" + # XML). Therefore, just ignore undefine errors so we do the rest + # FIXME: we really should have a marker in the database somehow so that + # we can tell if this domain was migrated; that way, we can tell the + # difference between a real undefine failure and one because of migration + result = vm.undefine + puts "Error undefining VM: #{result.text}" unless result.status == 0 + + teardown_storage_pools(node) + + set_vm_shut_down(db_vm) + end + + def task_start_vm(task) + db_vm = find_vm(task, false) + + # XXX: Kinda silly? I dunno about these intermediate states.. + set_vm_state(db_vm, Vm::STATE_STARTING) + + vm = @session.object(:class => "domain", 'uuid' => db_vm.uuid) + + if vm + case vm.state + when "running" + return + when "blocked" + raise "Virtual machine state is blocked, cannot start VM." + when "paused" + raise "Virtual machine is currently paused, cannot start, must resume." + end + end + # FIXME: There's a bug here in that a host that's already running the vm won't be + # returned. I think that's supposed to be for migration but it just breaks stuff. + db_host = find_capable_host(db_vm) + + node = @session.object(:class => "node", 'hostname' => db_host.hostname) + + raise "Unable to find host #{db_host.hostname} to create VM on." unless node + + if (db_vm.boot_device == Vm::BOOT_DEV_CDROM) && db_vm.uses_cobbler? && (db_vm.cobbler_type == Vm::IMAGE_PREFIX) + details = Cobbler::Image.find_one(db_vm.cobbler_name) + raise "Image #{vm.cobbler_name} not found in Cobbler server" unless details + + # extract the components of the image filename + image_uri = details.file + protocol = auth = ip_addr = export_path = filename = "" + + protocol, image_uri = image_uri.split("://") if image_uri.include?("://") + auth, image_uri = image_uri.split("@") if image_uri.include?("@") + # it's ugly, but string.split returns an empty string as the first + # result here, so we'll just ignore it + ignored, ip_addr, image_uri = + image_uri.split(/^([^\/]+)(\/.*)/) unless image_uri =~ /^\// + ignored, export_path, filename = + image_uri.split(/^(.*)\/(.+)/) + + found = false + + db_vm.storage_volumes.each do |volume| + if volume.filename == filename + if (volume.storage_pool.ip_addr == ip_addr) && + (volume.storage_pool.export_path == export_path) + found = true + end + end + end + + unless found + # Create a new transient NFS storage volume + # This volume is *not* persisted. + image_volume = StorageVolume.factory("NFS", :filename => filename) + + image_volume.storage_pool + image_pool = StoragePool.factory(StoragePool::NFS) + + image_pool.ip_addr = ip_addr + image_pool.export_path = export_path + image_pool.storage_volumes << image_volume + image_volume.storage_pool = image_pool + end + end + + # FIXME: I know this part is broken.. + # + # hrrm, who wrote this comment and why is it broken? - Ian + volumes = [] + volumes += db_vm.storage_volumes + volumes << image_volume if image_volume + storagedevs = connect_storage_pools(node, volumes) + + # FIXME: get rid of the hardcoded bridge + xml = create_vm_xml(db_vm.description, db_vm.uuid, db_vm.memory_allocated, + db_vm.memory_used, db_vm.num_vcpus_allocated, db_vm.boot_device, + db_vm.vnic_mac_addr, "ovirtbr0", storagedevs) + + result = node.domainDefineXML(xml.to_s) + raise "Error defining virtual machine: #{result.text}" unless result.status == 0 + + domain = @session.object(:object_id => result.domain) + raise "Cannot find domain on host #{db_host.hostname}, cannot start virtual machine." unless domain + + result = domain.create + if result.status != 0 + domain.undefine + raise "Error creating virtual machine: #{result.text}" + end + + result = domain.getXMLDesc + + # Reget the db record or you can get 'dirty' errors. + db_vm = find_vm(task, false) + set_vm_vnc_port(db_vm, result.description) unless result.status != 0 + + # XXX: This information is not available via the libvirt interface. + db_vm.memory_used = db_vm.memory_allocated + db_vm.boot_device = Vm::BOOT_DEV_HD + db_vm.host_id = db_host.id + + # We write the new state here even though dbomatic will set it soon anyway. + # This is just to let the UI know that it's good to go right away and really + # dbomatic will just write the same thing over top of it soon enough. + db_vm.state = Vm::STATE_RUNNING + db_vm.save! + end + + def task_suspend_vm(task) + db_vm = task.vm + dom = @session.object(:class => 'domain', 'uuid' => db_vm.uuid) + raise "Unable to locate VM to suspend" unless dom + + if dom.state == "shutdown" or dom.state == "shutoff" + raise "Cannot suspend stopped domain" + elsif dom.state == "paused" + raise "Cannot suspend saved domain" + end + + result = dom.suspend + raise "Error suspending VM: #{result.text}" unless result.status == 0 + + db_vm.state = Vm::STATE_SUSPENDED + db_vm.save! + end + + def task_resume_vm(task) + db_vm = task.vm + dom = @session.object(:class => 'domain', 'uuid' => db_vm.uuid) + raise "Unable to locate VM to resume" unless dom + + if dom.state == "running" + # the VM is already suspended; just return success + return + elsif dom.state == "shutoff" or dom.state == "shutdown" + raise "Cannot resume stopped domain" + elsif dom.state == "blocked" + raise "Cannot resume suspended domain" + end + + result = dom.resume + raise "Error resuming VM: #{result.text}" unless result.status == 0 + + db_vm.state = Vm::STATE_RUNNING + db_vm.save! + end + + def task_save_vm(task) + db_vm = task.vm + dom = @session.object(:class => 'domain', 'uuid' => db_vm.uuid) + raise "Unable to locate VM to save" unless dom + + #XXX: I'm not checking states here. I want to see if libvirt gives back + #decent error messages for different states. + filename = "/tmp/#{dom.uuid}.save" + puts "saving vm #{dom.name} to #{filename}" + result = dom.save(filename) + raise "Error saving VM: #{result.text}" unless result.status == 0 + + set_vm_state(db_vm, Vm::STATE_SAVED) + end + + def task_restore_vm(task) + db_vm = task.vm + dom = @session.object(:class => 'domain', 'uuid' => db_vm.uuid) + raise "Unable to locate VM to restore" unless dom + + #XXX: I'm not checking states here. I want to see if libvirt gives back + #decent error messages for different states. + + filename = "/tmp/#{dom.uuid}.save" + puts "restoring vm #{dom.name} from #{filename}" + result = dom.restore("/tmp/" + dom.uuid + ".save") + raise "Error restoring VM: #{result.text}" unless result.status == 0 + + set_vm_state(db_vm, Vm::STATE_RUNNING) + end + + def migrate(db_vm, dest = nil) + + vm = @session.object(:class => "domain", 'uuid' => db_vm.uuid) + raise "Unable to find VM to migrate" unless vm + src_node = @session.object(:object_id => vm.node) + raise "Unable to find node that VM is on??" unless src_node + + puts "Migrating domain lookup complete, domain is #{vm}" + + case vm.state + when "blocked" + raise "Unable to migrate blocked VM." + when "paused" + raise "Unable to migrate suspended VM." + end + + vm_orig_state = db_vm.state + set_vm_state(db_vm, Vm::STATE_MIGRATING) + + begin + unless dest.nil? or dest.empty? + if dest.to_i == db_vm.host_id + raise "Cannot migrate from host " + src_node.hostname + " to itself!" + end + db_dst_host = find_host(dest.to_i) + else + db_dst_host = find_capable_host(db_vm) + end + + dest_node = @session.object(:class => 'node', 'hostname' => db_dst_host.hostname) + raise "Unable to find host #{db_dst_host.hostname} to migrate to." unless dest_node + + volumes = [] + volumes += db_vm.storage_volumes + connect_storage_pools(dest_node, volumes) + + # Sadly migrate with qpid is broken because it requires a connection between + # both nodes and currently that can't happen securely. For now we do it + # the old fashioned way.. + dst_uri = "qemu+tcp://#{dest_node.hostname}/system" + src_uri = "qemu+tcp://#{src_node.hostname}/system" + src_conn = Libvirt::open("qemu+tcp://" + src_node.hostname + "/system") + dst_conn = Libvirt::open("qemu+tcp://" + dest_node.hostname + "/system") + dom = src_conn.lookup_domain_by_uuid(vm.uuid) + dom.migrate(dst_conn, Libvirt::Domain::MIGRATE_LIVE) + src_conn.close + dst_conn.close + + # undefine can fail, for instance, if we live migrated from A -> B, and + # then we are shutting down the VM on B (because it only has "transient" + # XML). Therefore, just ignore undefine errors so we do the rest + # FIXME: we really should have a marker in the database somehow so that + # we can tell if this domain was migrated; that way, we can tell the + # difference between a real undefine failure and one because of migration + result = vm.undefine + puts "Error undefining old vm after migrate: #{result.text}" unless result.status == 0 + + # See if we can take down storage pools on the src host. + teardown_storage_pools(src_node) + rescue => ex + puts "Error: #{ex}" + set_vm_state(db_vm, vm_orig_state) + raise ex + end + + db_vm.state = Vm::STATE_RUNNING + db_vm.host_id = db_dst_host.id + db_vm.save! + end + + def task_migrate_vm(task) + puts "migrate_vm" + + # here, we are given an id for a VM to migrate; we have to lookup which + # physical host it is running on + vm = find_vm(task) + migrate(vm, task.args) + end + + def storage_find_suitable_host(hardware_pool) + # find all of the hosts in the same pool as the storage + hardware_pool.hosts.each do |host| + puts "storage_find_suitable_host: host #{host.hostname} uuid #{host.uuid}" + node = @session.object(:class => 'node', 'hostname' => host.hostname) + return node if node + end + + raise "Could not find a host within this storage pool to scan the storage server." + end + + def add_volumes_to_db(db_pool, libvirt_pool, owner = nil, group = nil, mode = nil) + # FIXME: this is currently broken if you do something like: + # 1. Add an iscsi pool with 3 volumes (lun-1, lun-2, lun-3) + # 2. Scan it in + # 3. Remove lun-3 from the pool + # 4. Re-scan it + # What will happen is that you will still have lun-3 available in the + # database, even though it's not available in the pool anymore. It's a + # little tricky, though; we have to make sure that we don't pull the + # database entry out from underneath a possibly running VM (or do we?) + volumes = @session.objects(:class => 'volume', 'storagePool' => libvirt_pool.remote_pool.object_id) + volumes.each do |volume| + storage_volume = StorageVolume.factory(db_pool.get_type_label) + + # NOTE: it is safe (and, in fact, necessary) to use + # #{storage_volume.volume_name} here without sanitizing it. This is + # because this is *not* based on user modifiable data, but rather, on an + # internal implementation detail + existing_vol = StorageVolume.find(:first, :conditions => + ["storage_pool_id = ? AND #{storage_volume.volume_name} = ?", + db_pool.id, volume.name]) + + # in this case, this path already exists in the database; just skip + next if existing_vol + + storage_volume = StorageVolume.factory(db_pool.get_type_label) + storage_volume.path = volume.path + storage_volume.size = volume.capacity / 1024 + storage_volume.storage_pool_id = db_pool.id + storage_volume.write_attribute(storage_volume.volume_name, volume.name) + storage_volume.lv_owner_perms = owner + storage_volume.lv_group_perms = group + storage_volume.lv_mode_perms = mode + storage_volume.state = StorageVolume::STATE_AVAILABLE + puts "saving storage volume to db." + storage_volume.save! + end + end + + # The words "pool" and "volume" are ridiculously overloaded in our context. + # Therefore, the refresh_pool method adopts this convention: + # db_pool_phys: The underlying physical storage pool, as it is represented in + # the database + # phys_libvirt_pool: The underlying physical storage, as it is represented in + # libvirt + # db_lvm_pool: The logical storage pool (if it exists), as it is represented + # in the database + # lvm_libvirt_pool: The logical storage pool (if it exists), as it is + # represented in the database + + def task_refresh_pool(task) + puts "refresh_pool" + + db_pool_phys = task.storage_pool + raise "Could not find storage pool" unless db_pool_phys + + node = storage_find_suitable_host(db_pool_phys.hardware_pool) + + begin + phys_libvirt_pool = LibvirtPool.factory(db_pool_phys) + phys_libvirt_pool.connect(@session, node) + + begin + # OK, the pool is all set. Add in all of the volumes + add_volumes_to_db(db_pool_phys, phys_libvirt_pool) + + db_pool_phys.state = StoragePool::STATE_AVAILABLE + db_pool_phys.save! + + # OK, now we've scanned the underlying hardware pool and added the + # volumes. Next we scan for pre-existing LVM volumes + result = node.findStoragePoolSources("logical", nil) + raise "Error finding logical volumes in pool: #{result.text}" unless result.status == 0 + logical_xml = result.xmlDesc + + Document.new(logical_xml).elements.each('sources/source') do |source| + vgname = source.elements["name"].text + + # If matching any of the sections in the LVM XML fails + # against the storage pool, then it is likely that this is a storage + # pool not associated with the one we connected above. Go on + # FIXME: it would be nicer to catch the right exception here, and + # fail on other exceptions + source.elements.each("device") do |device| + log_vol = @session.object(:class => 'volume', + 'path' => device.attributes["path"], + 'storagePool' => phys_libvirt_pool.remote_pool.object_id) + puts "Didn't find logical volume for device #{device}" + next unless log_vol + end + + # if we make it here, then we were able to resolve all of the devices, + # so we know we need to use a new pool + db_lvm_pool = LvmStoragePool.find(:first, :conditions => + ["vg_name = ?", vgname]) + if db_lvm_pool == nil + puts "Adding lvm storage pool to database." + db_lvm_pool = LvmStoragePool.new + db_lvm_pool[:type] = "LvmStoragePool" + # set the LVM pool to the same hardware pool as the underlying storage + db_lvm_pool.hardware_pool_id = db_pool_phys.hardware_pool_id + db_lvm_pool.vg_name = vgname + db_lvm_pool.save! + end + + source.elements.each("device") do |device| + log_vol = @session.object(:class => 'volume', + 'path' => device.attributes["path"], + 'storagePool' => phys_libvirt_pool.remote_pool.object_id) + if !log_vol + puts "Unable to find logical volume with path #{device.attributes["path"]} on host" + next + end + + physical_vol = StorageVolume.find(:first, :conditions => + ["path = ?", log_vol.path]) + if physical_vol == nil + # Hm. We didn't find the device in the storage volumes already. + # something went wrong internally, and we have to bail + raise "Storage internal physical volume error" + end + + # OK, put the right lvm_pool_id in place + physical_vol.lvm_pool_id = db_lvm_pool.id + physical_vol.save! + end + + lvm_libvirt_pool = LibvirtPool.factory(db_lvm_pool) + lvm_libvirt_pool.connect(@session, node) + + # Do this in a block just in case we have some issue with the database. + begin + add_volumes_to_db(db_lvm_pool, lvm_libvirt_pool, "0744", "0744", "0744") + ensure + lvm_libvirt_pool.shutdown + end + end + end + ensure + phys_libvirt_pool.shutdown + end + end + + def task_create_volume(task) + puts "create_volume" + + db_volume = task.storage_volume + raise "Could not find storage volume to create" unless db_volume + + db_pool = db_volume.storage_pool + raise "Could not find storage pool" unless db_pool + + node = storage_find_suitable_host(db_pool.hardware_pool) + + begin + if db_volume[:type] == "LvmStorageVolume" + phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(db_volume) + phys_libvirt_pool.connect(@session, node) + end + + begin + libvirt_pool = LibvirtPool.factory(db_pool) + + begin + libvirt_pool.connect(@session, node) + + libvirt_pool.create_vol(*db_volume.volume_create_params) + db_volume.state = StorageVolume::STATE_AVAILABLE + db_volume.save! + + db_pool.state = StoragePool::STATE_AVAILABLE + db_pool.save! + ensure + libvirt_pool.shutdown + end + ensure + if db_volume[:type] == "LvmStorageVolume" + phys_libvirt_pool.shutdown + end + end + end + end + + def task_delete_volume(task) + puts "delete_volume" + + db_volume = task.storage_volume + raise "Could not find storage volume to create" unless db_volume + + db_pool = db_volume.storage_pool + raise "Could not find storage pool" unless db_pool + + node = storage_find_suitable_host(db_pool.hardware_pool) + + begin + if db_volume[:type] == "LvmStorageVolume" + phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(db_volume) + phys_libvirt_pool.connect(@session, node) + end + + begin + libvirt_pool = LibvirtPool.factory(db_pool) + libvirt_pool.connect(@session, node) + + begin + volume = @session.object(:class => 'volume', 'storagePool' => libvirt_pool.remote_pool.object_id) + puts "Unable to find volume to delete" unless volume + + # FIXME: we actually probably want to zero out the whole volume here, so + # we aren't potentially leaking data from one user to another. There + # are two problems, though: + # 1) I'm not sure how I would go about zero'ing the data on a remote + # machine, since there is no "libvirt_write_data" call + # 2) This could potentially take quite a while, so we want to spawn + # off another thread to do it + volume.delete + + # Note: we have to nil out the task_target because when we delete the + # volume object, that also deletes all dependent tasks (including this + # one), which leads to accessing stale tasks. Orphan the task, then + # delete the object; we can clean up orphans later (or not, depending + # on the audit policy) + task.task_target = nil + task.save! + + db_volume.destroy + ensure + libvirt_pool.shutdown + end + ensure + if db_volume[:type] == "LvmStorageVolume" + phys_libvirt_pool.shutdown + end + end + end + end + + def task_clear_vms_host(task) + src_host = task.host + + src_host.vms.each do |vm| + migrate(vm) + end + end + + def mainloop() + loop do + tasks = Array.new + begin + tasks = Task.find(:all, :conditions => [ "state = ?", Task::STATE_QUEUED ]) + rescue => ex + puts "1 #{ex.class}: #{ex.message}" + if Task.connected? + begin + ActiveRecord::Base.connection.reconnect! + rescue => norecon + puts "2 #{norecon.class}: #{norecon.message}" + end + else + begin + database_connect + rescue => ex + puts "3 #{ex.class}: #{ex.message}" + end + end + end + + tasks.each do |task| + # make sure we get our credentials up-front + get_credentials + + task.time_started = Time.now + + state = Task::STATE_FINISHED + begin + case task.action + when VmTask::ACTION_CREATE_VM then task_create_vm(task) + when VmTask::ACTION_SHUTDOWN_VM then task_shutdown_or_destroy_vm(task, :shutdown) + when VmTask::ACTION_POWEROFF_VM then task_shutdown_or_destroy_vm(task, :destroy) + when VmTask::ACTION_START_VM then task_start_vm(task) + when VmTask::ACTION_SUSPEND_VM then task_suspend_vm(task) + when VmTask::ACTION_RESUME_VM then task_resume_vm(task) + when VmTask::ACTION_SAVE_VM then task_save_vm(task) + when VmTask::ACTION_RESTORE_VM then task_restore_vm(task) + when VmTask::ACTION_MIGRATE_VM then task_migrate_vm(task) + when StorageTask::ACTION_REFRESH_POOL then task_refresh_pool(task) + when StorageVolumeTask::ACTION_CREATE_VOLUME then task_create_volume(task) + when StorageVolumeTask::ACTION_DELETE_VOLUME then task_delete_volume(task) + when HostTask::ACTION_CLEAR_VMS then task_clear_vms_host(task) + else + puts "unknown task " + task.action + state = Task::STATE_FAILED + task.message = "Unknown task type" + end + rescue => ex + puts "Task action processing failed: #{ex.class}: #{ex.message}" + puts ex.backtrace + state = Task::STATE_FAILED + task.message = ex.message + end + + task.state = state + task.time_ended = Time.now + task.save! + puts "done" + end + # FIXME: here, we clean up "orphaned" tasks. These are tasks that we had + # to orphan (set task_target to nil) because we were deleting the object they + # depended on. + Task.find(:all, :conditions => [ "task_target_id IS NULL and task_target_type IS NULL" ]).each do |task| + task.destroy + end + sleep(1) + end + end end + +taskomatic = TaskOmatic.new() +taskomatic.mainloop() + diff --git a/src/task-omatic/utils.rb b/src/task-omatic/utils.rb deleted file mode 100644 index e3005ed..0000000 --- a/src/task-omatic/utils.rb +++ /dev/null @@ -1,221 +0,0 @@ -require 'rexml/document' -include REXML - -def String.random_alphanumeric(size=16) - s = "" - size.times { s << (i = Kernel.rand(62); i += ((i < 10) ? 48 : ((i < 36) ? 55 : 61 ))).chr } - s -end - -def all_storage_pools(conn) - all_pools = conn.list_defined_storage_pools - all_pools.concat(conn.list_storage_pools) - return all_pools -end - -def get_libvirt_lvm_pool_from_volume(db_volume) - phys_volume = StorageVolume.find(:first, :conditions => - [ "lvm_pool_id = ?", db_volume.storage_pool_id]) - - return LibvirtPool.factory(phys_volume.storage_pool) -end - -class LibvirtPool - def initialize(type, name = nil) - @remote_pool = nil - @build_on_start = true - @remote_pool_defined = false - @remote_pool_started = false - - if name == nil - @name = type + "-" + String.random_alphanumeric - else - @name = name - end - - @xml = Document.new - @xml.add_element("pool", {"type" => type}) - - @xml.root.add_element("name").add_text(@name) - - @xml.root.add_element("source") - - @xml.root.add_element("target") - @xml.root.elements["target"].add_element("path") - end - - def connect(conn) - all_storage_pools(conn).each do |remote_pool_name| - tmppool = conn.lookup_storage_pool_by_name(remote_pool_name) - - if self.xmlequal?(Document.new(tmppool.xml_desc).root) - @remote_pool = tmppool - break - end - end - - if @remote_pool == nil - @remote_pool = conn.define_storage_pool_xml(@xml.to_s) - # we need this because we don't necessarily want to "build" LVM pools, - # which might destroy existing data - if @build_on_start - @remote_pool.build - end - @remote_pool_defined = true - end - - if @remote_pool.info.state == Libvirt::StoragePool::INACTIVE - # only try to start the pool if it is currently inactive; in all other - # states, assume it is already running - @remote_pool.create - @remote_pool_started = true - end - end - - def list_volumes - return @remote_pool.list_volumes - end - - def lookup_vol_by_path(dev) - return @remote_pool.lookup_volume_by_path(dev) - end - - def lookup_vol_by_name(name) - return @remote_pool.lookup_volume_by_name(name) - end - - def create_vol(type, name, size, owner, group, mode) - @vol_xml = Document.new - @vol_xml.add_element("volume", {"type" => type}) - @vol_xml.root.add_element("name").add_text(name) - @vol_xml.root.add_element("capacity", {"unit" => "K"}).add_text(size.to_s) - @vol_xml.root.add_element("target") - @vol_xml.root.elements["target"].add_element("permissions") - @vol_xml.root.elements["target"].elements["permissions"].add_element("owner").add_text(owner) - @vol_xml.root.elements["target"].elements["permissions"].add_element("group").add_text(group) - @vol_xml.root.elements["target"].elements["permissions"].add_element("mode").add_text(mode) - end - - def shutdown - if @remote_pool_started - @remote_pool.destroy - end - if @remote_pool_defined - @remote_pool.undefine - end - end - - def xmlequal?(docroot) - return false - end - - def self.factory(pool) - if pool[:type] == "IscsiStoragePool" - return IscsiLibvirtPool.new(pool.ip_addr, pool[:target]) - elsif pool[:type] == "NfsStoragePool" - return NFSLibvirtPool.new(pool.ip_addr, pool.export_path) - elsif pool[:type] == "LvmStoragePool" - # OK, if this is LVM storage, there are two cases we need to care about: - # 1) this is a LUN with LVM already on it. In this case, all we need to - # do is to create a new LV (== libvirt volume), and be done with it - # 2) this LUN is blank, so there is no LVM on it already. In this - # case, we need to pvcreate, vgcreate first (== libvirt pool build), - # and *then* create the new LV (== libvirt volume) on top of that. - # - # We can tell the difference between an LVM Pool that exists and one - # that needs to be created based on the value of the pool.state; - # if it is PENDING_SETUP, we need to create it first - phys_volume = StorageVolume.find(:first, :conditions => - [ "lvm_pool_id = ?", pool.id]) - - return LVMLibvirtPool.new(pool.vg_name, phys_volume.path, - pool.state == StoragePool::STATE_PENDING_SETUP) - else - raise "Unknown storage pool type " + pool[:type].to_s - end - end -end - -class IscsiLibvirtPool < LibvirtPool - def initialize(ip_addr, target) - super('iscsi') - - @type = 'iscsi' - @ipaddr = ip_addr - @target = target - - @xml.root.elements["source"].add_element("host", {"name" => @ipaddr}) - @xml.root.elements["source"].add_element("device", {"path" => @target}) - - @xml.root.elements["target"].elements["path"].text = "/dev/disk/by-id" - end - - def xmlequal?(docroot) - return (docroot.attributes['type'] == @type and - docroot.elements['source'].elements['host'].attributes['name'] == @ipaddr and - docroot.elements['source'].elements['device'].attributes['path'] == @target) - end -end - -class NFSLibvirtPool < LibvirtPool - def initialize(ip_addr, export_path) - super('netfs') - - @type = 'netfs' - @host = ip_addr - @remote_path = export_path - @name = String.random_alphanumeric - - @xml.root.elements["source"].add_element("host", {"name" => @host}) - @xml.root.elements["source"].add_element("dir", {"path" => @remote_path}) - @xml.root.elements["source"].add_element("format", {"type" => "nfs"}) - - @xml.root.elements["target"].elements["path"].text = "/mnt/" + @name - end - - def create_vol(name, size, owner, group, mode) - # FIXME: this can actually take some time to complete (since we aren't - # doing sparse allocations at the moment). During that time, whichever - # libvirtd we chose to use is completely hung up. The solution is 3-fold: - # 1. Allow sparse allocations in the WUI front-end - # 2. Make libvirtd multi-threaded - # 3. Make taskomatic multi-threaded - super("netfs", name, size, owner, group, mode) - - # FIXME: we have to add the format as raw here because of a bug in libvirt; - # if you specify a volume with no format, it will crash libvirtd - @vol_xml.root.elements["target"].add_element("format", {"type" => "raw"}) - @remote_pool.create_vol_xml(@vol_xml.to_s) - end - - def xmlequal?(docroot) - return (docroot.attributes['type'] == @type and - docroot.elements['source'].elements['host'].attributes['name'] == @host and - docroot.elements['source'].elements['dir'].attributes['path'] == @remote_path) - end -end - -class LVMLibvirtPool < LibvirtPool - def initialize(vg_name, device, build_on_start) - super('logical', vg_name) - - @type = 'logical' - @build_on_start = build_on_start - - @xml.root.elements["source"].add_element("name").add_text(@name) - @xml.root.elements["source"].add_element("device", {"path" => device}) - - @xml.root.elements["target"].elements["path"].text = "/dev/" + @name - end - - def create_vol(name, size, owner, group, mode) - super("logical", name, size, owner, group, mode) - @remote_pool.create_vol_xml(@vol_xml.to_s) - end - - def xmlequal?(docroot) - return (docroot.attributes['type'] == @type and - docroot.elements['name'].text == @name and - docroot.elements['source'].elements['name'] == @name) - end -end -- 1.6.0.4 From jguiditt at redhat.com Fri Dec 19 15:39:48 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Fri, 19 Dec 2008 10:39:48 -0500 Subject: [Ovirt-devel] [PATCH] fix for Bug 467767: double render error for add user In-Reply-To: <1229032102-4535-1-git-send-email-sseago@redhat.com> References: <1229032102-4535-1-git-send-email-sseago@redhat.com> Message-ID: <1229701188.4216.0.camel@physical.priv.ovirt.org> On Thu, 2008-12-11 at 21:48 +0000, Scott Seago wrote: > Not yet tested as I don't have a working appliance at the moment, but this should fix the problem, as there was an obvious issue with the render statement. I'll test shortly unless someone else gets to it first and ACKs. > > Signed-off-by: Scott Seago > --- > src/app/controllers/permission_controller.rb | 3 ++- > 1 files changed, 2 insertions(+), 1 deletions(-) > > diff --git a/src/app/controllers/permission_controller.rb b/src/app/controllers/permission_controller.rb > index 813d9d9..c301e1e 100644 > --- a/src/app/controllers/permission_controller.rb > +++ b/src/app/controllers/permission_controller.rb > @@ -47,8 +47,9 @@ class PermissionController < ApplicationController > unless @can_set_perms > flash[:notice] = 'You do not have permission to create this permission record' > redirect_to_parent > + else > + render :layout => 'popup' > end > - render :layout => 'popup' > end > > def create ACK From bkearney at redhat.com Fri Dec 19 15:49:29 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Fri, 19 Dec 2008 10:49:29 -0500 Subject: [Ovirt-devel] Cleaned up puppet patch series Message-ID: <1229701772-6466-1-git-send-email-bkearney@redhat.com> THis is a cleaned up patch series based on installing .96 rpms onto an F-10 machine. It adds a rakefile for rpmbuilding, cleans up the dns setup, and removes references to the ovirt-host-status script. -- bk From bkearney at redhat.com Fri Dec 19 15:49:30 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Fri, 19 Dec 2008 10:49:30 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Add a rake file to build the rpms In-Reply-To: <1229701772-6466-1-git-send-email-bkearney@redhat.com> References: <1229701772-6466-1-git-send-email-bkearney@redhat.com> Message-ID: <1229701772-6466-2-git-send-email-bkearney@redhat.com> --- .gitignore | 1 + ace-ovirt.spec | 4 ++-- rakefile.rb | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 rakefile.rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5fff1d9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +pkg diff --git a/ace-ovirt.spec b/ace-ovirt.spec index 7c72962..25fa36f 100755 --- a/ace-ovirt.spec +++ b/ace-ovirt.spec @@ -8,7 +8,7 @@ Summary: ACE oVirt Module Name: ace-ovirt Version: 0.0.94 -Release: 14%{?dist} +Release: 15%{?dist} Group: Applications/Internet License: LGPLv2+ BuildArch: noarch @@ -44,7 +44,7 @@ install -d %{buildroot}/%{acehome} install -d %{buildroot}/%{ruby_sitelibdir} install -d %{buildroot}/%{_bindir} install -d %{buildroot}/%{_initrddir} -cp -pr %{pbuild}/modules %{buildroot}/%{acehome} +cp -pr %{pbuild}/ace-ovirt/modules %{buildroot}/%{acehome} diff --git a/rakefile.rb b/rakefile.rb new file mode 100644 index 0000000..a2fae18 --- /dev/null +++ b/rakefile.rb @@ -0,0 +1,53 @@ +# -*- ruby -*- +# Rakefile: build appliance configuration engine rpms +# +# Copyright (C) 2007 Red Hat, Inc. +# +# Distributed under the GNU Lesser General Public License v2.1 or later. +# See COPYING for details +# +# Bryan Kearney + +require 'rake/clean' +require 'rake/rdoctask' +require 'rake/testtask' +require 'rake/packagetask' + +ROOT_DIR = File::expand_path(".") +PKG_VERSION="0.0.94" +PACKAGE_DIR = ROOT_DIR + "/pkg" + +# +# Files to clean up +# + +CLEAN.include("**/*~","pkg") + + +# Packaging Tasks +# +Rake::PackageTask.new("ace-ovirt", PKG_VERSION) do |pkg| + pkg.need_tar_gz = true + pkg.package_files.include(Dir["ace-ovirt/**/*"]) +end + + +# +# Tasks to build the rpms +# + +# Set up the directories +task :rpm => [ :package ] do |t| + Dir["*.spec"].each do |specfile| + spec = File.basename(specfile) + cp(specfile, "pkg") + puts("Building with spec file #{spec}") + Dir::chdir("pkg") do |dir| + dir = File::expand_path(".") + system("rpmbuild --define '_topdir #{dir}' --define '_sourcedir #{dir}' --define '_srcrpmdir #{dir}' --define '_rpmdir #{dir}' --define '_builddir #{dir}' -ba #{spec} > #{spec}.rpmbuild.log 2>&1") + if $? != 0 + raise "rpmbuild failed" + end + end + end +end -- 1.6.0.4 From bkearney at redhat.com Fri Dec 19 15:49:31 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Fri, 19 Dec 2008 10:49:31 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Always do basic DNS setup In-Reply-To: <1229701772-6466-2-git-send-email-bkearney@redhat.com> References: <1229701772-6466-1-git-send-email-bkearney@redhat.com> <1229701772-6466-2-git-send-email-bkearney@redhat.com> Message-ID: <1229701772-6466-3-git-send-email-bkearney@redhat.com> --- ace-ovirt/modules/ovirt/manifests/dns.pp | 23 +++++++++++++++-------- ace-ovirt/modules/ovirt/ovirt-installer | 4 +++- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/ace-ovirt/modules/ovirt/manifests/dns.pp b/ace-ovirt/modules/ovirt/manifests/dns.pp index 8665b99..5bd2f4d 100644 --- a/ace-ovirt/modules/ovirt/manifests/dns.pp +++ b/ace-ovirt/modules/ovirt/manifests/dns.pp @@ -18,8 +18,7 @@ # Author: Joey Boggs #-- - -define dns::bundled($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") { +define dns::common($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") { package {"dnsmasq": ensure => installed, @@ -42,13 +41,9 @@ define dns::bundled($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") single_exec {"add_dns_server_to_resolv.conf": command => "/bin/sed -e '1i nameserver $prov_ipaddr' -i /etc/resolv.conf", - require => [Single_exec["add_mgmt_server_to_etc_hosts"],Single_exec["set_hostname"]] + require => [Single_exec["set_hostname"]] } - single_exec {"add_mgmt_server_to_etc_hosts": - command => "/bin/echo $mgmt_ipaddr $ipa_host >> /etc/hosts", - notify => Service[dnsmasq] - } file_replacement {"dnsmasq_configdir": file => "/etc/dnsmasq.conf", @@ -63,7 +58,17 @@ define dns::bundled($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") } -class dns::remote { +define dns::bundled($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") { + + dns::common{"setup": mgmt_ipaddr=>$mgmt_ipaddr, prov_ipaddr=>$prov_ipaddr, mgmt_dev=>$mgmt_dev, prov_dev=>$prov_dev} + + single_exec {"add_mgmt_server_to_etc_hosts": + command => "/bin/echo $mgmt_ipaddr $ipa_host >> /etc/hosts", + notify => [Service[dnsmasq], Single_exec["add_dns_server_to_resolv.conf"]] + } +} + +define dns::remote($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") { # On the pxe server you will need to ensure that the # next server option points to the ip address of the tftp server @@ -81,4 +86,6 @@ class dns::remote { # Also A records must be present for each oVirt node. Without this they are unable # to determine their hostname and locate the management server. + dns::common{"setup": mgmt_ipaddr=>$mgmt_ipaddr, prov_ipaddr=>$prov_ipaddr, mgmt_dev=>$mgmt_dev, prov_dev=>$prov_dev} + } diff --git a/ace-ovirt/modules/ovirt/ovirt-installer b/ace-ovirt/modules/ovirt/ovirt-installer index 7d7b9d8..902b916 100755 --- a/ace-ovirt/modules/ovirt/ovirt-installer +++ b/ace-ovirt/modules/ovirt/ovirt-installer @@ -123,16 +123,18 @@ mgmt_ipaddr= mgmt_ip.scan(/\s*inet addr:([\d.]+)/) prov_ip = `ifconfig #{prov_dev}` prov_ipaddr= prov_ip.scan(/\s*inet addr:([\d.]+)/) -if dns_servers == "n" config_file.write "# dns configuration\n" config_file.write "$mgmt_ipaddr = '#{mgmt_ipaddr}'\n" config_file.write "$prov_ipaddr = '#{prov_ipaddr}'\n" config_file.write "$ovirt_host = '#{ovirt_host}'\n" config_file.write "$ipa_host = '#{ipa_host}'\n\n" + +if dns_servers == "n" config_file.write "dns::bundled{setup: mgmt_ipaddr=> $mgmt_ipaddr, prov_ipaddr=> $prov_ipaddr, mgmt_dev => '#{mgmt_dev}', prov_dev => '#{prov_dev}'}\n\n" end if dns_servers == "y" +config_file.write "dns::remote{setup: mgmt_ipaddr=> $mgmt_ipaddr, prov_ipaddr=> $prov_ipaddr, mgmt_dev => '#{mgmt_dev}', prov_dev => '#{prov_dev}'}\n\n" host_lookup = Socket.getaddrinfo(ipa_host,nil) hostip = host_lookup[1][3] if hostip.to_s != mgmt_ipaddr.to_s -- 1.6.0.4 From bkearney at redhat.com Fri Dec 19 15:49:32 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Fri, 19 Dec 2008 10:49:32 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Removed a service which is no longer present in .96 In-Reply-To: <1229701772-6466-3-git-send-email-bkearney@redhat.com> References: <1229701772-6466-1-git-send-email-bkearney@redhat.com> <1229701772-6466-2-git-send-email-bkearney@redhat.com> <1229701772-6466-3-git-send-email-bkearney@redhat.com> Message-ID: <1229701772-6466-4-git-send-email-bkearney@redhat.com> --- ace-ovirt/modules/ovirt/manifests/ovirt.pp | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-) diff --git a/ace-ovirt/modules/ovirt/manifests/ovirt.pp b/ace-ovirt/modules/ovirt/manifests/ovirt.pp index 954bf89..84e47b2 100644 --- a/ace-ovirt/modules/ovirt/manifests/ovirt.pp +++ b/ace-ovirt/modules/ovirt/manifests/ovirt.pp @@ -98,12 +98,6 @@ class ovirt::setup { ensure => running } - service {"ovirt-host-status" : - enable => true, - require => [Package[ovirt-server],Single_Exec[db_migrate]], - ensure => running - } - service {"ovirt-host-collect" : enable => true, require => [Package[ovirt-server],Single_Exec[db_migrate]], -- 1.6.0.4 From mmorsi at redhat.com Fri Dec 19 12:24:12 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Fri, 19 Dec 2008 07:24:12 -0500 Subject: [Ovirt-devel] [PATCH server] validations fix, remove incorrect host uuid validation Message-ID: <1229689452-4022-1-git-send-email-mmorsi@redhat.com> updates to the host model to remove the uuid validation which should not be enforced by the application. updates to the testing framework to assert the change --- src/app/models/host.rb | 3 --- src/test/unit/host_browser_identify_test.rb | 8 ++++---- src/test/unit/host_test.rb | 8 ++++---- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/app/models/host.rb b/src/app/models/host.rb index 08f9282..de060b2 100644 --- a/src/app/models/host.rb +++ b/src/app/models/host.rb @@ -54,9 +54,6 @@ class Host < ActiveRecord::Base validates_presence_of :hardware_pool_id, :message => 'A hardware pool id must be specified.' - validates_presence_of :uuid, - :message => 'A uuid must be specified.' - validates_presence_of :hostname, :message => 'A hostname must be specified.' diff --git a/src/test/unit/host_browser_identify_test.rb b/src/test/unit/host_browser_identify_test.rb index 9f7be1f..a17ea30 100644 --- a/src/test/unit/host_browser_identify_test.rb +++ b/src/test/unit/host_browser_identify_test.rb @@ -163,11 +163,11 @@ class HostBrowserIdentifyTest < Test::Unit::TestCase # Ensures that the server is fine when no UUID is present. # - #def test_write_host_info_with_missing_uuid - #@host_info['UUID'] = nil + def test_write_host_info_with_missing_uuid + @host_info['UUID'] = nil - #assert_nothing_raised { @browser.write_host_info(@host_info) } - #end + assert_nothing_raised { @browser.write_host_info(@host_info) } + end # Ensures that, if the hostname is missing, the server # raises an exception. diff --git a/src/test/unit/host_test.rb b/src/test/unit/host_test.rb index a7458d2..f311bce 100644 --- a/src/test/unit/host_test.rb +++ b/src/test/unit/host_test.rb @@ -29,7 +29,7 @@ class HostTest < Test::Unit::TestCase :uuid => 'foobar', :hostname => 'foobar', :arch => 'x86_64', - :hypervisor_type => 'kvm', + :hypervisor_type => 'KVM', :state => 'available') @host.hardware_pool = pools(:corp_com) @@ -41,10 +41,10 @@ class HostTest < Test::Unit::TestCase flunk "Hosts must be associated w/ a hardware pool" if @host.valid? end - def test_valid_fails_without_uuid - @host.uuid = '' + def test_valid_without_uuid + @host.uuid = nil - flunk "Hosts must be associated w/ a uuid" if @host.valid? + flunk "Hosts on't need to be associated w/ a uuid" unless @host.valid? end -- 1.6.0.4 From bkearney at redhat.com Fri Dec 19 19:02:34 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Fri, 19 Dec 2008 14:02:34 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Make use of the environment variables parameter so we are not combining two calls in one exec. In-Reply-To: <1229713355-24507-1-git-send-email-bkearney@redhat.com> References: <1229713355-24507-1-git-send-email-bkearney@redhat.com> Message-ID: <1229713355-24507-2-git-send-email-bkearney@redhat.com> --- ace-ovirt/modules/ovirt/manifests/ovirt.pp | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ace-ovirt/modules/ovirt/manifests/ovirt.pp b/ace-ovirt/modules/ovirt/manifests/ovirt.pp index 84e47b2..2be45c5 100644 --- a/ace-ovirt/modules/ovirt/manifests/ovirt.pp +++ b/ace-ovirt/modules/ovirt/manifests/ovirt.pp @@ -61,9 +61,9 @@ class ovirt::setup { single_exec { "db_migrate" : cwd => "/usr/share/ovirt-server/", - path => ["/bin"], - command => "export RAILS_ENV='production' && /usr/bin/rake db:migrate", - require => [File["/usr/share/ovirt-server/log"],Package[ovirt-server],Package[rubygem-rake]] + command => "/usr/bin/rake db:migrate", + require => [File["/usr/share/ovirt-server/log"],Package[ovirt-server],Package[rubygem-rake]], + environment => "RAILS_ENV=production" } file { "/usr/share/ovirt-server/log" : -- 1.6.0.4 From bkearney at redhat.com Fri Dec 19 19:02:33 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Fri, 19 Dec 2008 14:02:33 -0500 Subject: [Ovirt-devel] continuation of the series Message-ID: <1229713355-24507-1-git-send-email-bkearney@redhat.com> Two more to add onto the series. These make use of a few more plugins and got me a clean run From bkearney at redhat.com Fri Dec 19 19:02:35 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Fri, 19 Dec 2008 14:02:35 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Rework the dependencies so it is package.. stuff.. then servce In-Reply-To: <1229713355-24507-2-git-send-email-bkearney@redhat.com> References: <1229713355-24507-1-git-send-email-bkearney@redhat.com> <1229713355-24507-2-git-send-email-bkearney@redhat.com> Message-ID: <1229713355-24507-3-git-send-email-bkearney@redhat.com> --- ace-ovirt/modules/ovirt/manifests/dns.pp | 65 ++++++++++++++++------------- 1 files changed, 36 insertions(+), 29 deletions(-) diff --git a/ace-ovirt/modules/ovirt/manifests/dns.pp b/ace-ovirt/modules/ovirt/manifests/dns.pp index 5bd2f4d..df1d90c 100644 --- a/ace-ovirt/modules/ovirt/manifests/dns.pp +++ b/ace-ovirt/modules/ovirt/manifests/dns.pp @@ -20,41 +20,48 @@ define dns::common($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") { - package {"dnsmasq": - ensure => installed, - require => [Single_exec["add_dns_server_to_resolv.conf"],File_replacement["dnsmasq_configdir"], - File["/etc/dnsmasq.d/ovirt-dns.conf"],File_replacement ["dnsmasq_configdir"]] - } - - service {"dnsmasq" : - ensure => running, - enable => true, - require => File["/etc/dnsmasq.d/ovirt-dns.conf"] - } - - file {"/etc/dnsmasq.d/ovirt-dns.conf": - content => template("ovirt/ovirt-dns.conf.erb"), - mode => 644, - notify => Service[dnsmasq], - #require => Package[dnsmasq] - } - - single_exec {"add_dns_server_to_resolv.conf": - command => "/bin/sed -e '1i nameserver $prov_ipaddr' -i /etc/resolv.conf", - require => [Single_exec["set_hostname"]] - } - - - file_replacement {"dnsmasq_configdir": - file => "/etc/dnsmasq.conf", - pattern => "^#conf-dir=*$", - replacement => "conf-dir=/etc/dnsmasq.d", - notify => Service[dnsmasq] - } - - single_exec {"dhclient_config": - command => "/bin/echo 'prepend domain-name-servers $prov_ipaddr;' >> /etc/dhclient.conf" - } + package {"dnsmasq": + ensure => installed, + require => [Single_exec["add_dns_server_to_resolv.conf"]] + } + + service {"dnsmasq" : + ensure => running, + enable => true, + require => [File["/etc/dnsmasq.d/ovirt-dns.conf"], Package["dnsmasq"]] + } + + file {"/etc/dnsmasq.d/ovirt-dns.conf": + content => template("ovirt/ovirt-dns.conf.erb"), + mode => 644, + notify => Service[dnsmasq], + require => Package["dnsmasq"] + } + + single_exec {"add_dns_server_to_resolv.conf": + command => "/bin/sed -e '1i nameserver $prov_ipaddr' -i /etc/resolv.conf", + require => [Single_exec["set_hostname"]] + } + + + file_replacement {"dnsmasq_configdir": + file => "/etc/dnsmasq.conf", + pattern => "^#conf-dir=*$", + replacement => "conf-dir=/etc/dnsmasq.d", + notify => Service[dnsmasq], + require => Package["dnsmasq"] + } + + file {"/etc/dhclient.conf": + ensure => present + } + + file_append {"dhclient_config": + file => "/etc/dhclient.conf", + line => "prepend domain-name-servers $prov_ipaddr", + require => [Single_exec["set_hostname"], Package["dnsmasq"], File["/etc/dhclient.conf"]] , + notify => Service[dnsmasq], + } } -- 1.6.0.4 From jboggs at redhat.com Fri Dec 19 19:30:33 2008 From: jboggs at redhat.com (Joey Boggs) Date: Fri, 19 Dec 2008 14:30:33 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Add a rake file to build the rpms In-Reply-To: <1229701772-6466-2-git-send-email-bkearney@redhat.com> References: <1229701772-6466-1-git-send-email-bkearney@redhat.com> <1229701772-6466-2-git-send-email-bkearney@redhat.com> Message-ID: <494BF659.5080408@redhat.com> ack, applied Bryan Kearney wrote: > --- > .gitignore | 1 + > ace-ovirt.spec | 4 ++-- > rakefile.rb | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 56 insertions(+), 2 deletions(-) > create mode 100644 .gitignore > create mode 100644 rakefile.rb > > diff --git a/.gitignore b/.gitignore > new file mode 100644 > index 0000000..5fff1d9 > --- /dev/null > +++ b/.gitignore > @@ -0,0 +1 @@ > +pkg > diff --git a/ace-ovirt.spec b/ace-ovirt.spec > index 7c72962..25fa36f 100755 > --- a/ace-ovirt.spec > +++ b/ace-ovirt.spec > @@ -8,7 +8,7 @@ > Summary: ACE oVirt Module > Name: ace-ovirt > Version: 0.0.94 > -Release: 14%{?dist} > +Release: 15%{?dist} > Group: Applications/Internet > License: LGPLv2+ > BuildArch: noarch > @@ -44,7 +44,7 @@ install -d %{buildroot}/%{acehome} > install -d %{buildroot}/%{ruby_sitelibdir} > install -d %{buildroot}/%{_bindir} > install -d %{buildroot}/%{_initrddir} > -cp -pr %{pbuild}/modules %{buildroot}/%{acehome} > +cp -pr %{pbuild}/ace-ovirt/modules %{buildroot}/%{acehome} > > > > diff --git a/rakefile.rb b/rakefile.rb > new file mode 100644 > index 0000000..a2fae18 > --- /dev/null > +++ b/rakefile.rb > @@ -0,0 +1,53 @@ > +# -*- ruby -*- > +# Rakefile: build appliance configuration engine rpms > +# > +# Copyright (C) 2007 Red Hat, Inc. > +# > +# Distributed under the GNU Lesser General Public License v2.1 or later. > +# See COPYING for details > +# > +# Bryan Kearney > + > +require 'rake/clean' > +require 'rake/rdoctask' > +require 'rake/testtask' > +require 'rake/packagetask' > + > +ROOT_DIR = File::expand_path(".") > +PKG_VERSION="0.0.94" > +PACKAGE_DIR = ROOT_DIR + "/pkg" > + > +# > +# Files to clean up > +# > + > +CLEAN.include("**/*~","pkg") > + > + > +# Packaging Tasks > +# > +Rake::PackageTask.new("ace-ovirt", PKG_VERSION) do |pkg| > + pkg.need_tar_gz = true > + pkg.package_files.include(Dir["ace-ovirt/**/*"]) > +end > + > + > +# > +# Tasks to build the rpms > +# > + > +# Set up the directories > +task :rpm => [ :package ] do |t| > + Dir["*.spec"].each do |specfile| > + spec = File.basename(specfile) > + cp(specfile, "pkg") > + puts("Building with spec file #{spec}") > + Dir::chdir("pkg") do |dir| > + dir = File::expand_path(".") > + system("rpmbuild --define '_topdir #{dir}' --define '_sourcedir #{dir}' --define '_srcrpmdir #{dir}' --define '_rpmdir #{dir}' --define '_builddir #{dir}' -ba #{spec} > #{spec}.rpmbuild.log 2>&1") > + if $? != 0 > + raise "rpmbuild failed" > + end > + end > + end > +end > From bkearney at redhat.com Fri Dec 19 20:26:33 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Fri, 19 Dec 2008 15:26:33 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Drop a modules.conf file so that the username and password are checked Message-ID: <1229718393-27952-1-git-send-email-bkearney@redhat.com> --- ace-ovirt/modules/ovirt/files/modules.conf | 96 ++++++++++++++++++++++++++ ace-ovirt/modules/ovirt/manifests/cobbler.pp | 5 ++ 2 files changed, 101 insertions(+), 0 deletions(-) create mode 100644 ace-ovirt/modules/ovirt/files/modules.conf diff --git a/ace-ovirt/modules/ovirt/files/modules.conf b/ace-ovirt/modules/ovirt/files/modules.conf new file mode 100644 index 0000000..236ef4c --- /dev/null +++ b/ace-ovirt/modules/ovirt/files/modules.conf @@ -0,0 +1,96 @@ +# specifies what cobbler modules to load. + +# what file/data formats to use for metadata +# +# choices: +# serializer_catalog (fast, uses .d directories in /var/lib/cobbler/config) +# serializer_yaml (original serializer, uses a few text files) +# +# for 99% or more of all installations, use serializer_catalog. +# +# NOTE: serializer changes may remove your ability to access old data. +# serializer_yaml users can change to serializer_catalog w/o manual +# migration steps. Other changes are for new installs only. + +[serializers] +settings = serializer_catalog +distro = serializer_catalog +profile = serializer_catalog +system = serializer_catalog +repo = serializer_catalog +image = serializer_catalog + +# policy: what users can log into the WebUI and Read-Write XMLRPC? +# +# choices: +# authn_denyall -- no one (default) +# authn_configfile -- use /etc/cobbler/users.digest (for basic setups) +# authn_passthru -- ask Apache to handle it (used for kerberos) +# authn_ldap -- authenticate against LDAP +# authn_spacewalk -- ask Spacewalk/Satellite (experimental) +# authn_testing -- username/password is always testing/testing (debug) +# (user supplied) -- you may write your own module +# +# WARNING: this is a security setting, do not choose an option blindly. +# +# for more information: +# https://fedorahosted.org/cobbler/wiki/CobblerWebInterface +# https://fedorahosted.org/cobbler/wiki/CustomizableSecurity +# https://fedorahosted.org/cobbler/wiki/CobblerWithKerberos +# https://fedorahosted.org/cobbler/wiki/CobblerWithLdap + +[authentication] +module = authn_configfile + +# policy: once a user has been cleared by the WebUI/XMLRPC, what can they do? +# +# choices: +# authz_allowall -- full access for all authneticated users (default) +# authz_configfile -- determined by /etc/cobbler/users.conf +# authz_ownership -- use users.conf, but add object ownership semantics +# (user supplied) -- you may write your own module +# +# WARNING: this is a security setting, do not choose an option blindly. +# +# for more information: +# https://fedorahosted.org/cobbler/wiki/CobblerWebInterface +# https://fedorahosted.org/cobbler/wiki/CustomizableSecurity +# https://fedorahosted.org/cobbler/wiki/CustomizableAuthorization +# https://fedorahosted.org/cobbler/wiki/AuthorizationWithOwnership + +[authorization] +module = authz_allowall + +# chooses the DNS management engine if manage_dns is enabled +# in /etc/cobbler/settings, which is off by default. +# +# choices: +# manage_bind -- default, uses BIND/named +# manage_dnsmasq -- uses dnsmasq, also must select dnsmasq for dhcp below +# +# NOTE: more configuration is still required in /etc/cobbler +# +# for more information: +# https://fedorahosted.org/cobbler/wiki/ManageDns + +[dns] +module = manage_bind + +# chooses the DHCP management engine if manage_dhcp is enabled +# in /etc/cobbler/settings, which is off by default. +# +# choices: +# manage_isc -- default, uses ISC dhcpd +# manage_dnsmasq -- uses dnsmasq, also must select dnsmasq for dns above +# +# NOTE: more configuration is still required in /etc/cobbler +# +# for more information: +# https://fedorahosted.org/cobbler/wiki/ManageDhcp + +[dhcp] +module = manage_isc + + + + diff --git a/ace-ovirt/modules/ovirt/manifests/cobbler.pp b/ace-ovirt/modules/ovirt/manifests/cobbler.pp index e4aae62..e3f3698 100644 --- a/ace-ovirt/modules/ovirt/manifests/cobbler.pp +++ b/ace-ovirt/modules/ovirt/manifests/cobbler.pp @@ -97,6 +97,11 @@ class cobbler::bundled { enable => true, require => File_replacement[settings_ip_address] } + + file {"/etc/cobbler/modules.conf": + source => "puppet:///ovirt/modules.conf", + notify => Service[cobblerd] + } # firewall_rule{"69": destination_port => "69"} # firewall_rule{"25150": destination_port => "25150"} -- 1.6.0.4 From halsaadi at thoughtworks.com Fri Dec 19 20:45:50 2008 From: halsaadi at thoughtworks.com (Hadi Al-Saadi) Date: Sat, 20 Dec 2008 02:15:50 +0530 Subject: [Ovirt-devel] cpu cluster Message-ID: hi, can i cluster more then one physical Host cpu with ovirt, so they can act as one Host, for example: i have 4 system, Each one 4 cpu, i want to cluster them togathere and make them act as one Big host, so i can creats my vms under one big host. -------------- next part -------------- An HTML attachment was scrubbed... URL: From jboggs at redhat.com Fri Dec 19 21:16:00 2008 From: jboggs at redhat.com (Joey Boggs) Date: Fri, 19 Dec 2008 16:16:00 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Removed a service which is no longer present in .96 In-Reply-To: <1229701772-6466-4-git-send-email-bkearney@redhat.com> References: <1229701772-6466-1-git-send-email-bkearney@redhat.com> <1229701772-6466-2-git-send-email-bkearney@redhat.com> <1229701772-6466-3-git-send-email-bkearney@redhat.com> <1229701772-6466-4-git-send-email-bkearney@redhat.com> Message-ID: <494C0F10.4050803@redhat.com> ack, applied Bryan Kearney wrote: > --- > ace-ovirt/modules/ovirt/manifests/ovirt.pp | 6 ------ > 1 files changed, 0 insertions(+), 6 deletions(-) > > diff --git a/ace-ovirt/modules/ovirt/manifests/ovirt.pp b/ace-ovirt/modules/ovirt/manifests/ovirt.pp > index 954bf89..84e47b2 100644 > --- a/ace-ovirt/modules/ovirt/manifests/ovirt.pp > +++ b/ace-ovirt/modules/ovirt/manifests/ovirt.pp > @@ -98,12 +98,6 @@ class ovirt::setup { > ensure => running > } > > - service {"ovirt-host-status" : > - enable => true, > - require => [Package[ovirt-server],Single_Exec[db_migrate]], > - ensure => running > - } > - > service {"ovirt-host-collect" : > enable => true, > require => [Package[ovirt-server],Single_Exec[db_migrate]], > From jboggs at redhat.com Fri Dec 19 21:16:14 2008 From: jboggs at redhat.com (Joey Boggs) Date: Fri, 19 Dec 2008 16:16:14 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Make use of the environment variables parameter so we are not combining two calls in one exec. In-Reply-To: <1229713355-24507-2-git-send-email-bkearney@redhat.com> References: <1229713355-24507-1-git-send-email-bkearney@redhat.com> <1229713355-24507-2-git-send-email-bkearney@redhat.com> Message-ID: <494C0F1E.5090403@redhat.com> ack, applied Bryan Kearney wrote: > --- > ace-ovirt/modules/ovirt/manifests/ovirt.pp | 6 +++--- > 1 files changed, 3 insertions(+), 3 deletions(-) > > diff --git a/ace-ovirt/modules/ovirt/manifests/ovirt.pp b/ace-ovirt/modules/ovirt/manifests/ovirt.pp > index 84e47b2..2be45c5 100644 > --- a/ace-ovirt/modules/ovirt/manifests/ovirt.pp > +++ b/ace-ovirt/modules/ovirt/manifests/ovirt.pp > @@ -61,9 +61,9 @@ class ovirt::setup { > > single_exec { "db_migrate" : > cwd => "/usr/share/ovirt-server/", > - path => ["/bin"], > - command => "export RAILS_ENV='production' && /usr/bin/rake db:migrate", > - require => [File["/usr/share/ovirt-server/log"],Package[ovirt-server],Package[rubygem-rake]] > + command => "/usr/bin/rake db:migrate", > + require => [File["/usr/share/ovirt-server/log"],Package[ovirt-server],Package[rubygem-rake]], > + environment => "RAILS_ENV=production" > } > > file { "/usr/share/ovirt-server/log" : > From jboggs at redhat.com Fri Dec 19 21:16:36 2008 From: jboggs at redhat.com (Joey Boggs) Date: Fri, 19 Dec 2008 16:16:36 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Rework the dependencies so it is package.. stuff.. then servce In-Reply-To: <1229713355-24507-3-git-send-email-bkearney@redhat.com> References: <1229713355-24507-1-git-send-email-bkearney@redhat.com> <1229713355-24507-2-git-send-email-bkearney@redhat.com> <1229713355-24507-3-git-send-email-bkearney@redhat.com> Message-ID: <494C0F34.3020502@redhat.com> ack, applied Bryan Kearney wrote: > --- > ace-ovirt/modules/ovirt/manifests/dns.pp | 65 ++++++++++++++++------------- > 1 files changed, 36 insertions(+), 29 deletions(-) > > diff --git a/ace-ovirt/modules/ovirt/manifests/dns.pp b/ace-ovirt/modules/ovirt/manifests/dns.pp > index 5bd2f4d..df1d90c 100644 > --- a/ace-ovirt/modules/ovirt/manifests/dns.pp > +++ b/ace-ovirt/modules/ovirt/manifests/dns.pp > @@ -20,41 +20,48 @@ > > define dns::common($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") { > > - package {"dnsmasq": > - ensure => installed, > - require => [Single_exec["add_dns_server_to_resolv.conf"],File_replacement["dnsmasq_configdir"], > - File["/etc/dnsmasq.d/ovirt-dns.conf"],File_replacement ["dnsmasq_configdir"]] > - } > - > - service {"dnsmasq" : > - ensure => running, > - enable => true, > - require => File["/etc/dnsmasq.d/ovirt-dns.conf"] > - } > - > - file {"/etc/dnsmasq.d/ovirt-dns.conf": > - content => template("ovirt/ovirt-dns.conf.erb"), > - mode => 644, > - notify => Service[dnsmasq], > - #require => Package[dnsmasq] > - } > - > - single_exec {"add_dns_server_to_resolv.conf": > - command => "/bin/sed -e '1i nameserver $prov_ipaddr' -i /etc/resolv.conf", > - require => [Single_exec["set_hostname"]] > - } > - > - > - file_replacement {"dnsmasq_configdir": > - file => "/etc/dnsmasq.conf", > - pattern => "^#conf-dir=*$", > - replacement => "conf-dir=/etc/dnsmasq.d", > - notify => Service[dnsmasq] > - } > - > - single_exec {"dhclient_config": > - command => "/bin/echo 'prepend domain-name-servers $prov_ipaddr;' >> /etc/dhclient.conf" > - } > + package {"dnsmasq": > + ensure => installed, > + require => [Single_exec["add_dns_server_to_resolv.conf"]] > + } > + > + service {"dnsmasq" : > + ensure => running, > + enable => true, > + require => [File["/etc/dnsmasq.d/ovirt-dns.conf"], Package["dnsmasq"]] > + } > + > + file {"/etc/dnsmasq.d/ovirt-dns.conf": > + content => template("ovirt/ovirt-dns.conf.erb"), > + mode => 644, > + notify => Service[dnsmasq], > + require => Package["dnsmasq"] > + } > + > + single_exec {"add_dns_server_to_resolv.conf": > + command => "/bin/sed -e '1i nameserver $prov_ipaddr' -i /etc/resolv.conf", > + require => [Single_exec["set_hostname"]] > + } > + > + > + file_replacement {"dnsmasq_configdir": > + file => "/etc/dnsmasq.conf", > + pattern => "^#conf-dir=*$", > + replacement => "conf-dir=/etc/dnsmasq.d", > + notify => Service[dnsmasq], > + require => Package["dnsmasq"] > + } > + > + file {"/etc/dhclient.conf": > + ensure => present > + } > + > + file_append {"dhclient_config": > + file => "/etc/dhclient.conf", > + line => "prepend domain-name-servers $prov_ipaddr", > + require => [Single_exec["set_hostname"], Package["dnsmasq"], File["/etc/dhclient.conf"]] , > + notify => Service[dnsmasq], > + } > > } > > From thomas.vonsteiger at bluewin.ch Fri Dec 19 21:33:49 2008 From: thomas.vonsteiger at bluewin.ch (Thomas von Steiger) Date: Fri, 19 Dec 2008 22:33:49 +0100 Subject: [Ovirt-devel] cpu cluster In-Reply-To: References: Message-ID: <5C64837C-EB8D-42F9-BF24-3FE9890327DC@bluewin.ch> Hi, I think you need for this special hardware with a high speed link between the systems. With future baremetal technologies you are eable to build one large host over many systems. There are hardware to day like ibm x3950 where you can connect up to 4 systems to one big large system. Thomas On 19.12.2008, at 21:45, Hadi Al-Saadi wrote: > > hi, > > > can i cluster more then one physical Host cpu with ovirt, so they > can act as one Host, > > for example: > > > i have 4 system, Each one 4 cpu, i want to cluster them togathere > and make them act as one Big host, so i can creats my vms under one > big host. > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel -------------- next part -------------- An HTML attachment was scrubbed... URL: From dpierce at redhat.com Fri Dec 19 22:11:43 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Fri, 19 Dec 2008 17:11:43 -0500 Subject: [Ovirt-devel] [PATCH node] Moved functionality to o-process-config. Message-ID: <1229724703-21914-1-git-send-email-dpierce@redhat.com> Code to copy the network configuration files to the config partition and to restart the network service have been moved out of ovirt-early and into ovirt-process-config. This will allow the script to be reuseable. Signed-off-by: Darryl L. Pierce --- scripts/ovirt-early | 20 +++++--------------- scripts/ovirt-process-config | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/scripts/ovirt-early b/scripts/ovirt-early index 8bf8928..2d2a96d 100755 --- a/scripts/ovirt-early +++ b/scripts/ovirt-early @@ -44,21 +44,11 @@ configure_from_network() { if [ $? -eq 0 ]; then echo "Remote configuration bundle retrieved to $cfgdb" ovirt-process-config $cfgdb $BONDING_MODCONF_FILE $AUGTOOL_CONFIG - if [ -f $AUGTOOL_CONFIG ]; then - echo "Loading remote config" - # avoid bindmount issues with augeas - umount_config /etc/sysconfig/network-scripts/ifcfg-eth* - augtool < $AUGTOOL_CONFIG \ - && echo "Remote config applied" \ - || echo "Failed applying remote config" - fi - if ls /etc/sysconfig/network-scripts/ifcfg-eth* > /dev/null 2>&1; then - echo "Network interfaces created from remote config" - ovirt_store_config /etc/sysconfig/network-scripts/ifcfg-eth* - return - else - echo "Remote config contained no network interfaces" - fi + if [ $? -eq 0 ]; then + echo "Remote configuration retrieved and applied" + else + echo "Failure to retrieve or apply remote configuration" + fi else echo "Failed to retrieve configuration bundle" fi diff --git a/scripts/ovirt-process-config b/scripts/ovirt-process-config index 48068ef..8641fa0 100755 --- a/scripts/ovirt-process-config +++ b/scripts/ovirt-process-config @@ -1,4 +1,9 @@ #!/bin/bash +# +# Takes as input a reference to an encoded configuration file +# and produces from that a kernel module file and a network +# configuration file. It then restarts the networking service +# and saves the configuration files. ME=$(basename "$0") warn() { printf '%s: %s\n' "$ME" "$*" >&2; } @@ -58,3 +63,14 @@ networking=$(awk '/^[ \t]*ifcfg=/ { }' $CONFIG) echo "$networking" > $OVIRT_CONFIG_OUTPUT_FILE + +if [ -f $OVIRT_CONFIG_OUTPUT_FILE ]; then + umount_config /etc/sysconfig/network-scripts/ifcfg* + augtool < $OVIRT_CONFIG_OUTPUT_FILE \ + && RESULT=0 || RESULT=1 + if ls /etc/sysconfig/network-scripts/ifcfg* > /dev/null >2&1; then + ovirt_store_config /etc/sysconfig/network-scripts/ifcfg* + fi +fi + +exit $RESULT -- 1.6.0.4 From bkearney at redhat.com Fri Dec 19 22:42:53 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Fri, 19 Dec 2008 17:42:53 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Various small dependency changes Message-ID: <1229726573-8554-1-git-send-email-bkearney@redhat.com> --- ace-ovirt/modules/ovirt/manifests/cobbler.pp | 3 ++- ace-ovirt/modules/ovirt/manifests/freeipa.pp | 3 ++- ace-ovirt/modules/ovirt/manifests/ovirt.pp | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ace-ovirt/modules/ovirt/manifests/cobbler.pp b/ace-ovirt/modules/ovirt/manifests/cobbler.pp index e3f3698..7fd4e1e 100644 --- a/ace-ovirt/modules/ovirt/manifests/cobbler.pp +++ b/ace-ovirt/modules/ovirt/manifests/cobbler.pp @@ -100,7 +100,8 @@ class cobbler::bundled { file {"/etc/cobbler/modules.conf": source => "puppet:///ovirt/modules.conf", - notify => Service[cobblerd] + notify => Service[cobblerd], + require => Package["cobbler"] } # firewall_rule{"69": destination_port => "69"} diff --git a/ace-ovirt/modules/ovirt/manifests/freeipa.pp b/ace-ovirt/modules/ovirt/manifests/freeipa.pp index 573535f..1f292bf 100644 --- a/ace-ovirt/modules/ovirt/manifests/freeipa.pp +++ b/ace-ovirt/modules/ovirt/manifests/freeipa.pp @@ -55,7 +55,8 @@ class freeipa::bundled{ } single_exec {"dnsmasq_restart": - command => "/etc/init.d/dnsmasq restart" + command => "/etc/init.d/dnsmasq restart", + require => Service["dnsmasq"] } single_exec {"ipa_server_install": diff --git a/ace-ovirt/modules/ovirt/manifests/ovirt.pp b/ace-ovirt/modules/ovirt/manifests/ovirt.pp index 2be45c5..36e364f 100644 --- a/ace-ovirt/modules/ovirt/manifests/ovirt.pp +++ b/ace-ovirt/modules/ovirt/manifests/ovirt.pp @@ -62,7 +62,7 @@ class ovirt::setup { single_exec { "db_migrate" : cwd => "/usr/share/ovirt-server/", command => "/usr/bin/rake db:migrate", - require => [File["/usr/share/ovirt-server/log"],Package[ovirt-server],Package[rubygem-rake]], + require => [File["/usr/share/ovirt-server/log"],Package[ovirt-server],Package[rubygem-rake],Postgres_execute_command["ovirt_db_grant_permissions"]], environment => "RAILS_ENV=production" } -- 1.6.0.4 From imain at redhat.com Fri Dec 19 22:59:11 2008 From: imain at redhat.com (Ian Main) Date: Fri, 19 Dec 2008 14:59:11 -0800 Subject: [Ovirt-devel] LVM Fun Message-ID: <20081219145911.1d364c26@tp.mains.net> OK, so in my refactoring of taskomatic, I've discovered just how crazy LVM partitions are. Basically there is no way that I can see (and hopefully I'm wrong) of determining what underlying hardware pool or volume is associated with an LVM pool or volume. I think in the current taskomatic they attempt to figure some of this out when doing a storage refresh, but it's actually not correct and still relies on information from the database. Here's the code in taskomatic: logical_xml = conn.discover_storage_pool_sources("logical") Document.new(logical_xml).elements.each('sources/source') do |source| vgname = source.elements["name"].text begin source.elements.each("device") do |device| byid_device = phys_libvirt_pool.lookup_vol_by_path(device.attributes["path"]).path end rescue # If matching any of the sections in the LVM XML fails # against the storage pool, then it is likely that this is a storage # pool not associated with the one we connected above. Go on # FIXME: it would be nicer to catch the right exception here, and # fail on other exceptions puts "One of the logical volumes in #{vgname} is not part of the pool of type #{phys_db_pool[:type]} that we are scanning; ignore the previous error!" next end So first we get a list of pools which are of the "logical"/LVM type, then iterate through them and use lookup_vol_by_path using the physical hardware pool as the pool to look in for the LVM volume. However that is not correct.. the ruby API makes it look like you are only searching in that one pool when in fact lookup_vol_by_path uses the main connection pointer and is a global search across all storage pools. Code from libvirt-ruby: /* * Call +virStorageVolLookupByPath+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolLookupByPath] */ VALUE libvirt_pool_lookup_vol_by_path(VALUE p, VALUE path) { virStorageVolPtr vol; // FIXME: Why does this take a connection, not a pool ? vol = virStorageVolLookupByPath(conn(p), StringValueCStr(path)); _E(vol == NULL, create_error(e_RetrieveError, "virStorageVolLookupByPath", "", conn(p))); return vol_new(vol, conn_attr(p)); } As you can see in the FIXME comment and the usage of virStorageVolLookupByPath(), it's not associated with a specific pool. So this part of the code then doesn't actually prevent us from picking up LVM volumes associated with other pools which may be active on this host (most likely for VMs to use). Remember we're just picking some random host to do our scan with. Then afterwords we put the entries in the database: source.elements.each("device") do |device| byid_device = phys_libvirt_pool.lookup_vol_by_path(device.attributes["path"]).path physical_vol = StorageVolume.find(:first, :conditions => [ "path = ?", byid_device]) if physical_vol == nil # Hm. We didn't find the device in the storage volumes already. # something went wrong internally, and we have to bail raise "Storage internal physical volume error" end # OK, put the right lvm_pool_id in place physical_vol.lvm_pool_id = lvm_db_pool.id physical_vol.save! end If I read this right it means that if we don't have the LVM volume in the database already we're lost as to what physical volume it belongs. And again we're using lookup_vol_by_path() to determine its in the pool. Anyway, all this basically means we have no way to track LVM volumes from libvirt and if we intend to keep using them we're just going to have to rely on the database to keep track of their setup. We could still check allocations etc. but we shouldn't be attempting to fill in the database with LVM information from a scan/refresh of the storage volume. Make sense? Am I missing something? Ian From imain at redhat.com Fri Dec 19 23:01:18 2008 From: imain at redhat.com (Ian Main) Date: Fri, 19 Dec 2008 15:01:18 -0800 Subject: [Ovirt-devel] Re: [PATCH server] Taskomatic Refactoring and Qpidification Take 2 In-Reply-To: <1229666919-9739-1-git-send-email-imain@redhat.com> References: <1229666919-9739-1-git-send-email-imain@redhat.com> Message-ID: <20081219150118.6c5de7c3@tp.mains.net> On Thu, 18 Dec 2008 22:08:39 -0800 Ian Main wrote: > This is a repost of the new patch in its entirety including a number > of new bugfixes from this evening. If most folks think it should go > to 2 spaces let me know, I'm not really opposed to that. So it sounds like we want to go 2 spaces with this. I'll post another patch with 2 space indents. Also note that as per my other email LVM storage pool scanning is broken (although create/delete/usage seems fine). Ian From imain at redhat.com Fri Dec 19 22:19:33 2008 From: imain at redhat.com (Ian Main) Date: Fri, 19 Dec 2008 14:19:33 -0800 Subject: [Ovirt-devel] [PATCH server] Taskomatic Refactoring and Qpidification Take 3 Message-ID: <1229725173-18065-1-git-send-email-imain@redhat.com> This update adds a few small bugfixes, removes LVM storage pool/volume scanning and reindents to 2 spaces. This patch reworks taskomatic quite a bit. This mostly just shifts taskomatic to using the qpid interface in place of ruby-libvirt. It also fixes a few bugs I discovered a long the way and adds new ones I'm sure. The only other thing added was round-robin host selection for VMs. Wherevery possible the hosts are queried directly using qpid rather than relying on states from the database. This patch loses about 150 lines from the original taskomatic and moves most of the task implementation into a central class. This was done to provide access to the qpid session as well as providing for locking/task ordering in future versions. This requires the latest libvirt-qpid (0.2.8) as it fixes a number of bugs. It's in the ovirt repository now. Issues remaining: - libvirt-qpid migrate is broken. Since the migrate takes place on the node instead of from the ovirt-appliance, the source node doesn't have the ability to authenticate against the destination node. For this reason I'm still using ruby-libvirt migrate. I talked to Chris about this and we have a plan worked out. :) - I wanted to get threading into this but that will have to wait. I'll post a thread about this to get the discussion started again. I think the refactoring allows this to be put in pretty easily. Signed-off-by: Ian Main --- src/task-omatic/task_host.rb | 33 -- src/task-omatic/task_storage.rb | 424 +++++++++----------- src/task-omatic/task_vm.rb | 574 +-------------------------- src/task-omatic/taskomatic.rb | 841 ++++++++++++++++++++++++++++++++++----- src/task-omatic/utils.rb | 221 ---------- 5 files changed, 933 insertions(+), 1160 deletions(-) delete mode 100644 src/task-omatic/task_host.rb delete mode 100644 src/task-omatic/utils.rb diff --git a/src/task-omatic/task_host.rb b/src/task-omatic/task_host.rb deleted file mode 100644 index 3d039fb..0000000 --- a/src/task-omatic/task_host.rb +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (C) 2008 Red Hat, Inc. -# Written by Chris Lalancette -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. A copy of the GNU General Public License is -# also available at http://www.gnu.org/copyleft/gpl.html. - -require 'utils' - -# FIXME: a little ugly to be including all of task_vm here, but -# utils really isn't the right place for the migrate() method -require 'task_vm' - -def clear_vms_host(task) - puts "clear_vms_host" - - src_host = task.host - - src_host.vms.each do |vm| - migrate(vm) - end -end diff --git a/src/task-omatic/task_storage.rb b/src/task-omatic/task_storage.rb index 19800fb..a5eb55d 100644 --- a/src/task-omatic/task_storage.rb +++ b/src/task-omatic/task_storage.rb @@ -16,287 +16,231 @@ # MA 02110-1301, USA. A copy of the GNU General Public License is # also available at http://www.gnu.org/copyleft/gpl.html. -require 'utils' - require 'libvirt' +require 'rexml/document' +include REXML + +def String.random_alphanumeric(size=16) + s = "" + size.times { s << (i = Kernel.rand(62); i += ((i < 10) ? 48 : ((i < 36) ? 55 : 61 ))).chr } + s +end + +def get_libvirt_lvm_pool_from_volume(db_volume) + phys_volume = StorageVolume.find(:first, :conditions => + ["lvm_pool_id = ?", db_volume.storage_pool_id]) + + return LibvirtPool.factory(phys_volume.storage_pool) +end + +class LibvirtPool + + attr_reader :remote_pool -def add_volumes_to_db(db_pool, libvirt_pool, owner = nil, group = nil, mode = nil) - # FIXME: this is currently broken if you do something like: - # 1. Add an iscsi pool with 3 volumes (lun-1, lun-2, lun-3) - # 2. Scan it in - # 3. Remove lun-3 from the pool - # 4. Re-scan it - # What will happen is that you will still have lun-3 available in the - # database, even though it's not available in the pool anymore. It's a - # little tricky, though; we have to make sure that we don't pull the - # database entry out from underneath a possibly running VM (or do we?) - libvirt_pool.list_volumes.each do |volname| - storage_volume = StorageVolume.factory(db_pool.get_type_label) - - # NOTE: it is safe (and, in fact, necessary) to use - # #{storage_volume.volume_name} here without sanitizing it. This is - # because this is *not* based on user modifiable data, but rather, on an - # internal implementation detail - existing_vol = StorageVolume.find(:first, :conditions => - [ "storage_pool_id = ? AND #{storage_volume.volume_name} = ?", - db_pool.id, volname]) - if existing_vol != nil - # in this case, this path already exists in the database; just skip - next + def initialize(type, name = nil) + @remote_pool = nil + @build_on_start = true + @remote_pool_defined = false + @remote_pool_started = false + + if name == nil + @name = type + "-" + String.random_alphanumeric + else + @name = name end - volptr = libvirt_pool.lookup_vol_by_name(volname) + @xml = Document.new + @xml.add_element("pool", {"type" => type}) + + @xml.root.add_element("name").add_text(@name) - volinfo = volptr.info + @xml.root.add_element("source") - storage_volume = StorageVolume.factory(db_pool.get_type_label) - storage_volume.path = volptr.path - storage_volume.size = volinfo.capacity / 1024 - storage_volume.storage_pool_id = db_pool.id - storage_volume.write_attribute(storage_volume.volume_name, volname) - storage_volume.lv_owner_perms = owner - storage_volume.lv_group_perms = group - storage_volume.lv_mode_perms = mode - storage_volume.state = StorageVolume::STATE_AVAILABLE - storage_volume.save! + @xml.root.add_element("target") + @xml.root.elements["target"].add_element("path") end -end -def storage_find_suitable_host(hardware_pool) - conn = nil - hardware_pool.hosts.each do |host| - if not host.is_disabled.nil? and host.is_disabled == 0 \ - and host.state == Host::STATE_AVAILABLE - begin - # FIXME: this can hang up taskomatic for quite some time. To see how, - # make one of your remote servers do "iptables -I INPUT -j DROP" - # and then try to run this; it will take TCP quite a while to give up. - # Unfortunately the solution is probably to do some sort of threading - conn = Libvirt::open("qemu+tcp://" + host.hostname + "/system") - - # if we didn't raise an exception, we connected; get out of here + def connect(session, node) + pools = session.objects(:class => 'pool', 'node' => node.object_id) + pools.each do |pool| + result = pool.getXMLDesc + raise "Error getting xml description of pool: #{result.text}" unless result.status == 0 + + xml_desc = result.description + if self.xmlequal?(Document.new(xml_desc).root) + @remote_pool = pool break - rescue Libvirt::ConnectionError - # if we couldn't connect for whatever reason, just try the next host - next end end - end - if conn == nil - # last ditch effort; if we didn't find any hosts, just use ourselves. - # this may or may not work - begin - conn = Libvirt::open("qemu:///system") - rescue + #XXX: I'm not sure.. it seems like there could be other things going on + # with the storage pool state. State can be inactive, building, running + # or degraded. I think some more thought should go here to make sure + # we're doing things right in each state. + if @remote_pool == nil + result = node.storagePoolDefineXML(@xml.to_s) + raise "Error creating pool: #{result.text}" unless result.status == 0 + @remote_pool = session.object(:object_id => result.pool) + raise "Error finding newly created remote pool." unless @remote_pool + + # we need this because we don't want to "build" LVM pools, which would + # destroy existing data + if @build_on_start + result = @remote_pool.build + raise "Error building pool: #{result.text}" unless result.status == 0 + end + @remote_pool_defined = true + end + + if @remote_pool.state == "inactive" + # only try to start the pool if it is currently inactive; in all other + # states, assume it is already running + result = @remote_pool.create + raise "Error creating pool: #{result.text}" unless result.status == 0 + + # Refresh qpid object with new properties. + @remote_pool.update + + @remote_pool_started = true end end - if conn == nil - raise "Could not find a host to scan storage" + def create_vol(type, name, size, owner, group, mode) + @vol_xml = Document.new + @vol_xml.add_element("volume", {"type" => type}) + @vol_xml.root.add_element("name").add_text(name) + @vol_xml.root.add_element("capacity", {"unit" => "K"}).add_text(size.to_s) + @vol_xml.root.add_element("target") + @vol_xml.root.elements["target"].add_element("permissions") + @vol_xml.root.elements["target"].elements["permissions"].add_element("owner").add_text(owner) + @vol_xml.root.elements["target"].elements["permissions"].add_element("group").add_text(group) + @vol_xml.root.elements["target"].elements["permissions"].add_element("mode").add_text(mode) end - return conn -end + def shutdown + if @remote_pool_started + result = @remote_pool.destroy + end + if @remote_pool_defined + result = @remote_pool.undefine + end + end -# The words "pool" and "volume" are ridiculously overloaded in our context. -# Therefore, the refresh_pool method adopts this convention: -# phys_db_pool: The underlying physical storage pool, as it is represented in -# the database -# phys_libvirt_pool: The underlying physical storage, as it is represented in -# libvirt -# lvm_db_pool: The logical storage pool (if it exists), as it is represented -# in the database -# lvm_libvirt_pool: The logical storage pool (if it exists), as it is -# represented in the database - -def refresh_pool(task) - puts "refresh_pool" - - phys_db_pool = task.storage_pool - if phys_db_pool == nil - raise "Could not find storage pool" + def xmlequal?(docroot) + return false end - conn = storage_find_suitable_host(phys_db_pool.hardware_pool) - - begin - phys_libvirt_pool = LibvirtPool.factory(phys_db_pool) - phys_libvirt_pool.connect(conn) - - begin - # OK, the pool is all set. Add in all of the volumes - add_volumes_to_db(phys_db_pool, phys_libvirt_pool) - - phys_db_pool.state = StoragePool::STATE_AVAILABLE - phys_db_pool.save! - - # OK, now we've scanned the underlying hardware pool and added the - # volumes. Next we scan for pre-existing LVM volumes - logical_xml = conn.discover_storage_pool_sources("logical") - - Document.new(logical_xml).elements.each('sources/source') do |source| - vgname = source.elements["name"].text - - begin - source.elements.each("device") do |device| - byid_device = phys_libvirt_pool.lookup_vol_by_path(device.attributes["path"]).path - end - rescue - # If matching any of the sections in the LVM XML fails - # against the storage pool, then it is likely that this is a storage - # pool not associated with the one we connected above. Go on - # FIXME: it would be nicer to catch the right exception here, and - # fail on other exceptions - puts "One of the logical volumes in #{vgname} is not part of the pool of type #{phys_db_pool[:type]} that we are scanning; ignore the previous error!" - next - end - - # if we make it here, then we were able to resolve all of the devices, - # so we know we need to use a new pool - lvm_db_pool = LvmStoragePool.find(:first, :conditions => - [ "vg_name = ?", vgname ]) - if lvm_db_pool == nil - lvm_db_pool = LvmStoragePool.new - lvm_db_pool[:type] = "LvmStoragePool" - # set the LVM pool to the same hardware pool as the underlying storage - lvm_db_pool.hardware_pool_id = phys_db_pool.hardware_pool_id - lvm_db_pool.vg_name = vgname - lvm_db_pool.save! - end - - source.elements.each("device") do |device| - byid_device = phys_libvirt_pool.lookup_vol_by_path(device.attributes["path"]).path - physical_vol = StorageVolume.find(:first, :conditions => - [ "path = ?", byid_device]) - if physical_vol == nil - # Hm. We didn't find the device in the storage volumes already. - # something went wrong internally, and we have to bail - raise "Storage internal physical volume error" - end - - # OK, put the right lvm_pool_id in place - physical_vol.lvm_pool_id = lvm_db_pool.id - physical_vol.save! - end - - lvm_libvirt_pool = LibvirtPool.factory(lvm_db_pool) - lvm_libvirt_pool.connect(conn) - - begin - add_volumes_to_db(lvm_db_pool, lvm_libvirt_pool, "0744", "0744", "0744") - ensure - lvm_libvirt_pool.shutdown - end - end - ensure - phys_libvirt_pool.shutdown + def self.factory(pool) + if pool[:type] == "IscsiStoragePool" + return IscsiLibvirtPool.new(pool.ip_addr, pool[:target]) + elsif pool[:type] == "NfsStoragePool" + return NFSLibvirtPool.new(pool.ip_addr, pool.export_path) + elsif pool[:type] == "LvmStoragePool" + # OK, if this is LVM storage, there are two cases we need to care about: + # 1) this is a LUN with LVM already on it. In this case, all we need to + # do is to create a new LV (== libvirt volume), and be done with it + # 2) this LUN is blank, so there is no LVM on it already. In this + # case, we need to pvcreate, vgcreate first (== libvirt pool build), + # and *then* create the new LV (== libvirt volume) on top of that. + # + # We can tell the difference between an LVM Pool that exists and one + # that needs to be created based on the value of the pool.state; + # if it is PENDING_SETUP, we need to create it first + phys_volume = StorageVolume.find(:first, :conditions => + [ "lvm_pool_id = ?", pool.id]) + return LVMLibvirtPool.new(pool.vg_name, phys_volume.path, + pool.state == StoragePool::STATE_PENDING_SETUP) + else + raise "Unknown storage pool type " + pool[:type].to_s end - ensure - conn.close end end -def create_volume(task) - puts "create_volume" +class IscsiLibvirtPool < LibvirtPool + def initialize(ip_addr, target) + super('iscsi') + + @type = 'iscsi' + @ipaddr = ip_addr + @target = target + + @xml.root.elements["source"].add_element("host", {"name" => @ipaddr}) + @xml.root.elements["source"].add_element("device", {"path" => @target}) - db_volume = task.storage_volume - if db_volume == nil - raise "Could not find storage volume to create" + @xml.root.elements["target"].elements["path"].text = "/dev/disk/by-id" end - db_pool = db_volume.storage_pool - if db_pool == nil - raise "Could not find storage pool" + def xmlequal?(docroot) + return (docroot.attributes['type'] == @type and + docroot.elements['source'].elements['host'].attributes['name'] == @ipaddr and + docroot.elements['source'].elements['device'].attributes['path'] == @target) end +end - conn = storage_find_suitable_host(db_pool.hardware_pool) +class NFSLibvirtPool < LibvirtPool + def initialize(ip_addr, export_path) + super('netfs') - begin - if db_volume[:type] == "LvmStorageVolume" - phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(db_volume) - phys_libvirt_pool.connect(conn) - end + @type = 'netfs' + @host = ip_addr + @remote_path = export_path + @name = String.random_alphanumeric - begin - libvirt_pool = LibvirtPool.factory(db_pool) + @xml.root.elements["source"].add_element("host", {"name" => @host}) + @xml.root.elements["source"].add_element("dir", {"path" => @remote_path}) + @xml.root.elements["source"].add_element("format", {"type" => "nfs"}) - begin - libvirt_pool.connect(conn) + @xml.root.elements["target"].elements["path"].text = "/mnt/" + @name + end - libvirt_pool.create_vol(*db_volume.volume_create_params) - db_volume.state = StorageVolume::STATE_AVAILABLE - db_volume.save! + def create_vol(name, size, owner, group, mode) + # FIXME: this can actually take some time to complete (since we aren't + # doing sparse allocations at the moment). During that time, whichever + # libvirtd we chose to use is completely hung up. The solution is 3-fold: + # 1. Allow sparse allocations in the WUI front-end + # 2. Make libvirtd multi-threaded + # 3. Make taskomatic multi-threaded + super("netfs", name, size, owner, group, mode) + + # FIXME: we have to add the format as raw here because of a bug in libvirt; + # if you specify a volume with no format, it will crash libvirtd + @vol_xml.root.elements["target"].add_element("format", {"type" => "raw"}) + result = @remote_pool.createVolumeXML(@vol_xml.to_s) + raise "Error creating remote pool: #{result.text}" unless result.status == 0 + return result.volume + end - db_pool.state = StoragePool::STATE_AVAILABLE - db_pool.save! - ensure - libvirt_pool.shutdown - end - ensure - if db_volume[:type] == "LvmStorageVolume" - phys_libvirt_pool.shutdown - end - end - ensure - conn.close + def xmlequal?(docroot) + return (docroot.attributes['type'] == @type and + docroot.elements['source'].elements['host'].attributes['name'] == @host and + docroot.elements['source'].elements['dir'].attributes['path'] == @remote_path) end end -def delete_volume(task) - puts "delete_volume" +class LVMLibvirtPool < LibvirtPool + def initialize(vg_name, device, build_on_start) + super('logical', vg_name) - db_volume = task.storage_volume - if db_volume == nil - raise "Could not find storage volume to create" - end + @type = 'logical' + @build_on_start = build_on_start - db_pool = db_volume.storage_pool - if db_pool == nil - raise "Could not find storage pool" + @xml.root.elements["source"].add_element("name").add_text(@name) + @xml.root.elements["source"].add_element("device", {"path" => device}) + @xml.root.elements["target"].elements["path"].text = "/dev/" + @name end - conn = storage_find_suitable_host(db_pool.hardware_pool) - - begin - if db_volume[:type] == "LvmStorageVolume" - phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(db_volume) - phys_libvirt_pool.connect(conn) - end + def create_vol(name, size, owner, group, mode) + super("logical", name, size, owner, group, mode) + result = @remote_pool.createVolumeXML(@vol_xml.to_s) + raise "Error creating remote pool: #{result.text}" unless result.status == 0 + return result.volume + end - begin - libvirt_pool = LibvirtPool.factory(db_pool) - libvirt_pool.connect(conn) - - begin - libvirt_volume = libvirt_pool.lookup_vol_by_name(db_volume.read_attribute(db_volume.volume_name)) - # FIXME: we actually probably want to zero out the whole volume here, so - # we aren't potentially leaking data from one user to another. There - # are two problems, though: - # 1) I'm not sure how I would go about zero'ing the data on a remote - # machine, since there is no "libvirt_write_data" call - # 2) This could potentially take quite a while, so we want to spawn - # off another thread to do it - libvirt_volume.delete - - # Note: we have to nil out the task_target because when we delete the - # volume object, that also deletes all dependent tasks (including this - # one), which leads to accessing stale tasks. Orphan the task, then - # delete the object; we can clean up orphans later (or not, depending - # on the audit policy) - task.task_target = nil - task.save! - - db_volume.destroy - ensure - libvirt_pool.shutdown - end - ensure - if db_volume[:type] == "LvmStorageVolume" - phys_libvirt_pool.shutdown - end - end - ensure - conn.close + def xmlequal?(docroot) + return (docroot.attributes['type'] == @type and + docroot.elements['name'].text == @name and + docroot.elements['source'].elements['name'] and + docroot.elements['source'].elements['name'].text == @name) end end + diff --git a/src/task-omatic/task_vm.rb b/src/task-omatic/task_vm.rb index c187287..46ef261 100644 --- a/src/task-omatic/task_vm.rb +++ b/src/task-omatic/task_vm.rb @@ -19,35 +19,10 @@ require 'rexml/document' include REXML -require 'utils' - gem 'cobbler' require 'cobbler' -def findHostSLA(vm) - host = nil - - vm.vm_resource_pool.get_hardware_pool.hosts.each do |curr| - # FIXME: we probably need to add in some notion of "load" into this check - if curr.num_cpus >= vm.num_vcpus_allocated \ - and curr.memory >= vm.memory_allocated \ - and not curr.is_disabled.nil? and curr.is_disabled == 0 \ - and curr.state == Host::STATE_AVAILABLE \ - and (vm.host_id.nil? or (not vm.host_id.nil? and vm.host_id != curr.id)) - host = curr - break - end - end - - if host == nil - # we couldn't find a host that matches this criteria - raise "No host matching VM parameters could be found" - end - - return host -end - -def findHost(host_id) +def find_host(host_id) host = Host.find(:first, :conditions => [ "id = ?", host_id]) if host == nil @@ -58,75 +33,6 @@ def findHost(host_id) return host end -def connect_storage_pools(conn, storage_volumes) - storagedevs = [] - storage_volumes.each do |volume| - # here, we need to iterate through each volume and possibly attach it - # to the host we are going to be using - db_pool = volume.storage_pool - if db_pool == nil - # Hum. Specified by the VM description, but not in the storage pool? - # continue on and hope for the best - puts "Couldn't find pool for volume #{volume.path}; skipping" - next - end - - # we have to special case LVM pools. In that case, we need to first - # activate the underlying physical device, and then do the logical one - if volume[:type] == "LvmStorageVolume" - phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(volume) - phys_libvirt_pool.connect(conn) - end - - libvirt_pool = LibvirtPool.factory(db_pool) - libvirt_pool.connect(conn) - - # OK, the pool should be all set. The last thing we need to do is get - # the path based on the volume name - storagedevs << libvirt_pool.lookup_vol_by_name(volume.read_attribute(volume.volume_name)).path - end - - return storagedevs -end - -def remove_pools(conn, type = nil) - all_storage_pools(conn).each do |remote_pool_name| - pool = conn.lookup_storage_pool_by_name(remote_pool_name) - - if type == nil or type == Document.new(pool.xml_desc).root.attributes['type'] - begin - pool.destroy - rescue - end - - begin - # if the destroy failed, we still try to undefine; it may be a pool - # that was previously destroyed but not undefined for whatever reason - pool.undefine - rescue - # do nothing if any of this failed; the worst that happens is that - # we leave a pool configured - puts "Could not teardown pool " + remote_pool_name + "; skipping" - end - end - end -end - -def teardown_storage_pools(conn) - # FIXME: this needs to get a *lot* smarter. In particular, we want to make - # sure we can tear down unused pools even when there are other guests running - if conn.list_domains.empty? - # OK, there are no running guests on this host anymore. We can teardown - # any storage pools that are there without fear - - # we first have to tear-down LVM pools, because they might depend on the - # underlying physical pools - remove_pools(conn, "logical") - - # now tear down the rest of the pools - remove_pools(conn) - end -end def create_vm_xml(name, uuid, memAllocated, memUsed, vcpus, bootDevice, macAddr, bridge, diskDevices) @@ -195,13 +101,13 @@ def create_vm_xml(name, uuid, memAllocated, memUsed, vcpus, bootDevice, return doc end -def setVmState(vm, state) +def set_vm_state(vm, state) vm.state = state vm.save! end -def setVmVncPort(vm, domain) - doc = REXML::Document.new(domain.xml_desc) +def set_vm_vnc_port(vm, xml_desc) + doc = REXML::Document.new(xml_desc) attrib = REXML::XPath.match(doc, "//graphics/@port") if not attrib.empty?: vm.vnc_port = attrib.to_s.to_i @@ -209,32 +115,22 @@ def setVmVncPort(vm, domain) vm.save! end -def findVM(task, fail_on_nil_host_id = true) +def find_vm(task, fail_on_nil_host_id = true) # find the matching VM in the vms table vm = task.vm if vm == nil - raise "VM not found for task " + task.id + raise "VM #{task.vm} not found for task #{task.id}" end if vm.host_id == nil && fail_on_nil_host_id - # in this case, we have no idea where the VM is. How can we handle this - # gracefully? We don't necessarily want to just set the VM state to off; - # if the machine does happen to be running somewhere and we set it to - # disabled here, and then start it again, we could corrupt the disk - - # FIXME: the right thing to do here is probably to contact all of the - # hosts we know about and ensure that the domain isn't running; then we - # can mark it either as off (if we didn't find it), or mark the correct - # vm.host_id if we did. However, if you have a large number of hosts - # out there, this could take a while. raise "No host_id for VM " + vm.id.to_s end return vm end -def setVmShutdown(vm) +def set_vm_shut_down(vm) vm.host_id = nil vm.memory_used = nil vm.num_vcpus_used = nil @@ -244,459 +140,3 @@ def setVmShutdown(vm) vm.save! end -def create_vm(task) - puts "create_vm" - - vm = findVM(task, false) - - if vm.state != Vm::STATE_PENDING - raise "VM not pending" - end - setVmState(vm, Vm::STATE_CREATING) - - # create cobbler system profile - begin - # FIXME: Presently the wui handles all cobbler system creation. - # This should be moved out of the wui into Taskomatic. Specifically - # here, and in the edit_vm methods. - - setVmState(vm, Vm::STATE_STOPPED) - rescue Exception => error - setVmState(vm, Vm::STATE_CREATE_FAILED) - raise "Unable to create system: #{error.message}" - end -end - -def shut_or_destroy_vm(task, which) - # here, we are given an id for a VM to shutdown; we have to lookup which - # physical host it is running on - - vm = findVM(task) - - if vm.state == Vm::STATE_STOPPED - # the VM is already shutdown; just return success - setVmShutdown(vm) - return - elsif vm.state == Vm::STATE_SUSPENDED - raise "Cannot shutdown suspended domain" - elsif vm.state == Vm::STATE_SAVED - raise "Cannot shutdown saved domain" - end - - vm_orig_state = vm.state - setVmState(vm, Vm::STATE_STOPPING) - - begin - conn = Libvirt::open("qemu+tcp://" + vm.host.hostname + "/system") - dom = conn.lookup_domain_by_uuid(vm.uuid) - dom.send(which) - - begin - dom.undefine - rescue - # undefine can fail, for instance, if we live migrated from A -> B, and - # then we are shutting down the VM on B (because it only has "transient" - # XML). Therefore, just ignore undefine errors so we do the rest - # FIXME: we really should have a marker in the database somehow so that - # we can tell if this domain was migrated; that way, we can tell the - # difference between a real undefine failure and one because of migration - end - - teardown_storage_pools(conn) - - conn.close - rescue => ex - setVmState(vm, vm_orig_state) - raise ex - end - - setVmShutdown(vm) -end - -def shutdown_vm(task) - puts "shutdown_vm" - shut_or_destroy_vm(task, "shutdown") -end - -def poweroff_vm(task) - puts "poweroff_vm" - shut_or_destroy_vm(task, "destroy") -end - -def start_vm(task) - puts "start_vm" - - # here, we are given an id for a VM to start - - vm = findVM(task, false) - - if vm.state == Vm::STATE_RUNNING - # the VM is already running; just return success - return - elsif vm.state == Vm::STATE_SUSPENDED - raise "Cannot start suspended domain" - elsif vm.state == Vm::STATE_SAVED - raise "Cannot start saved domain" - end - - # FIXME: Validate that the VM is still within quota - - vm_orig_state = vm.state - setVmState(vm, Vm::STATE_STARTING) - - begin - if vm.host_id != nil - # OK, marked in the database as already running on a host; for now, we - # will just fail the operation - - # FIXME: we probably want to go out to the host it is marked on and check - # things out, just to make sure things are consistent - raise "VM already running" - end - - # OK, now that we found the VM, go looking in the hardware_pool - # hosts to see if there is a host that will fit these constraints - host = findHostSLA(vm) - - # if we're booting from a CDROM the VM is an image, - # then we need to add the NFS mount as a storage volume for this - # boot - # - if (vm.boot_device == Vm::BOOT_DEV_CDROM) && vm.uses_cobbler? && (vm.cobbler_type == Vm::IMAGE_PREFIX) - details = Cobbler::Image.find_one(vm.cobbler_name) - - raise "Image #{vm.cobbler_name} not found in Cobbler server" unless details - - # extract the components of the image filename - image_uri = details.file - protocol = auth = ip_addr = export_path = filename = "" - - protocol, image_uri = image_uri.split("://") if image_uri.include?("://") - auth, image_uri = image_uri.split("@") if image_uri.include?("@") - # it's ugly, but string.split returns an empty string as the first - # result here, so we'll just ignore it - ignored, ip_addr, image_uri = - image_uri.split(/^([^\/]+)(\/.*)/) unless image_uri =~ /^\// - ignored, export_path, filename = - image_uri.split(/^(.*)\/(.+)/) - - found = false - - vm.storage_volumes.each do |volume| - if volume.filename == filename - if (volume.storage_pool.ip_addr == ip_addr) && - (volume.storage_pool.export_path == export_path) - found = true - end - end - end - - unless found - # Create a new transient NFS storage volume - # This volume is *not* persisted. - image_volume = StorageVolume.factory("NFS", - :filename => filename - ) - - image_volume.storage_pool - image_pool = StoragePool.factory(StoragePool::NFS) - - image_pool.ip_addr = ip_addr - image_pool.export_path = export_path - image_pool.storage_volumes << image_volume - image_volume.storage_pool = image_pool - end - end - - volumes = [] - volumes += vm.storage_volumes - volumes << image_volume if image_volume - - conn = Libvirt::open("qemu+tcp://" + host.hostname + "/system") - - begin - storagedevs = connect_storage_pools(conn, volumes) - - dom = nil - begin - # FIXME: get rid of the hardcoded bridge - xml = create_vm_xml(vm.description, vm.uuid, vm.memory_allocated, - vm.memory_used, vm.num_vcpus_allocated, - vm.boot_device, vm.vnic_mac_addr, "ovirtbr0", - storagedevs) - dom = conn.define_domain_xml(xml.to_s) - dom.create - - setVmVncPort(vm, dom) - rescue - if dom != nil - dom.undefine - end - teardown_storage_pools(conn) - raise ex - end - ensure - conn.close - end - rescue => ex - setVmState(vm, vm_orig_state) - raise ex - end - - vm.host_id = host.id - vm.state = Vm::STATE_RUNNING - vm.memory_used = vm.memory_allocated - vm.num_vcpus_used = vm.num_vcpus_allocated - vm.boot_device = Vm::BOOT_DEV_HD - vm.save! -end - -def save_vm(task) - puts "save_vm" - - # here, we are given an id for a VM to suspend - - vm = findVM(task) - - if vm.state == Vm::STATE_SAVED - # the VM is already saved; just return success - return - elsif vm.state == Vm::STATE_SUSPENDED - raise "Cannot save suspended domain" - elsif vm.state == Vm::STATE_STOPPED - raise "Cannot save shutdown domain" - end - - vm_orig_state = vm.state - setVmState(vm, Vm::STATE_SAVING) - - begin - conn = Libvirt::open("qemu+tcp://" + vm.host.hostname + "/system") - dom = conn.lookup_domain_by_uuid(vm.uuid) - dom.save("/tmp/" + vm.uuid + ".save") - conn.close - rescue => ex - setVmState(vm, vm_orig_state) - raise ex - end - - # note that we do *not* reset the host_id here, since we stored the saved - # vm state information locally. restore_vm will pick it up from here - - # FIXME: it would be much nicer to be able to save the VM and remove the - # the host_id and undefine the XML; that way we could resume it on another - # host later. This can be done once we have the storage APIs, but it will - # need more work - - setVmState(vm, Vm::STATE_SAVED) -end - -def restore_vm(task) - puts "restore_vm" - - # here, we are given an id for a VM to start - - vm = findVM(task) - - if vm.state == Vm::STATE_RUNNING - # the VM is already saved; just return success - return - elsif vm.state == Vm::STATE_SUSPENDED - raise "Cannot restore suspended domain" - elsif vm.state == Vm::STATE_STOPPED - raise "Cannot restore shutdown domain" - end - - vm_orig_state = vm.state - setVmState(vm, Vm::STATE_RESTORING) - - begin - # FIXME: we should probably go out to the host and check what it thinks - # the state is - - conn = Libvirt::open("qemu+tcp://" + vm.host.hostname + "/system") - dom = conn.lookup_domain_by_uuid(vm.uuid) - dom.restore - - setVmVncPort(vm, dom) - - conn.close - rescue => ex - setVmState(vm, vm_orig_state) - raise ex - end - - setVmState(vm, Vm::STATE_RUNNING) -end - -def suspend_vm(task) - puts "suspend_vm" - - # here, we are given an id for a VM to suspend; we have to lookup which - # physical host it is running on - - vm = findVM(task) - - if vm.state == Vm::STATE_SUSPENDED - # the VM is already suspended; just return success - return - elsif vm.state == Vm::STATE_STOPPED - raise "Cannot suspend stopped domain" - elsif vm.state == Vm::STATE_SAVED - raise "Cannot suspend saved domain" - end - - vm_orig_state = vm.state - setVmState(vm, Vm::STATE_SUSPENDING) - - begin - conn = Libvirt::open("qemu+tcp://" + vm.host.hostname + "/system") - dom = conn.lookup_domain_by_uuid(vm.uuid) - dom.suspend - conn.close - rescue => ex - setVmState(vm, vm_orig_state) - raise ex - end - - # note that we do *not* reset the host_id here, since we just suspended the VM - # resume_vm will pick it up from here - - setVmState(vm, Vm::STATE_SUSPENDED) -end - -def resume_vm(task) - puts "resume_vm" - - # here, we are given an id for a VM to start - - vm = findVM(task) - - # OK, marked in the database as already running on a host; let's check it - - if vm.state == Vm::STATE_RUNNING - # the VM is already suspended; just return success - return - elsif vm.state == Vm::STATE_STOPPED - raise "Cannot resume stopped domain" - elsif vm.state == Vm::STATE_SAVED - raise "Cannot resume suspended domain" - end - - vm_orig_state = vm.state - setVmState(vm, Vm::STATE_RESUMING) - - begin - conn = Libvirt::open("qemu+tcp://" + vm.host.hostname + "/system") - dom = conn.lookup_domain_by_uuid(vm.uuid) - dom.resume - conn.close - rescue => ex - setVmState(vm, vm_orig_state) - raise ex - end - - setVmState(vm, Vm::STATE_RUNNING) -end - -def update_state_vm(task) - puts "update_state_vm" - - # NOTE: findVM() will only return a vm if all the host information is filled - # in. So if a vm that we thought was stopped is running, this returns nil - # and we don't update any information about it. The tricky part - # is that we're still not sure what to do in this case :). - Ian - # - # Actually for migration it is necessary that it be able to update - # the host and state of the VM once it is migrated. - vm = findVM(task, false) - new_vm_state, host_id_str = task.args.split(",") - if (vm.host_id == nil) and host_id_str - vm.host_id = host_id_str.to_i - end - - - vm_effective_state = Vm::EFFECTIVE_STATE[vm.state] - task_effective_state = Vm::EFFECTIVE_STATE[new_vm_state] - - if vm_effective_state != task_effective_state - vm.state = new_vm_state - - if task_effective_state == Vm::STATE_STOPPED - setVmShutdown(vm) - end - vm.save! - puts "Updated state to " + new_vm_state - end -end - -def migrate(vm, dest = nil) - if vm.state == Vm::STATE_STOPPED - raise "Cannot migrate stopped domain" - elsif vm.state == Vm::STATE_SUSPENDED - raise "Cannot migrate suspended domain" - elsif vm.state == Vm::STATE_SAVED - raise "Cannot migrate saved domain" - end - - vm_orig_state = vm.state - setVmState(vm, Vm::STATE_MIGRATING) - - begin - src_host = findHost(vm.host_id) - unless dest.nil? or dest.empty? - if dest.to_i == vm.host_id - raise "Cannot migrate from host " + src_host.hostname + " to itself!" - end - dst_host = findHost(dest.to_i) - else - dst_host = findHostSLA(vm) - end - - src_conn = Libvirt::open("qemu+tcp://" + src_host.hostname + "/system") - dst_conn = Libvirt::open("qemu+tcp://" + dst_host.hostname + "/system") - - connect_storage_pools(dst_conn, vm) - - dom = src_conn.lookup_domain_by_uuid(vm.uuid) - dom.migrate(dst_conn, Libvirt::Domain::MIGRATE_LIVE) - - # if we didn't raise an exception, then the migration was successful. We - # still have a pointer to the now-shutdown domain on the source side, so - # undefine it - begin - dom.undefine - rescue - # undefine can fail, for instance, if we live migrated from A -> B, and - # then we are shutting down the VM on B (because it only has "transient" - # XML). Therefore, just ignore undefine errors so we do the rest - # FIXME: we really should have a marker in the database somehow so that - # we can tell if this domain was migrated; that way, we can tell the - # difference between a real undefine failure and one because of migration - end - - teardown_storage_pools(src_conn) - dst_conn.close - src_conn.close - rescue => ex - # FIXME: ug. We may have open connections that we need to close; not - # sure how to handle that - setVmState(vm, vm_orig_state) - raise ex - end - - setVmState(vm, Vm::STATE_RUNNING) - vm.host_id = dst_host.id - vm.save! -end - -def migrate_vm(task) - puts "migrate_vm" - - # here, we are given an id for a VM to migrate; we have to lookup which - # physical host it is running on - - vm = findVM(task) - - migrate(vm, task.args) -end diff --git a/src/task-omatic/taskomatic.rb b/src/task-omatic/taskomatic.rb index ce37058..3eefc5a 100755 --- a/src/task-omatic/taskomatic.rb +++ b/src/task-omatic/taskomatic.rb @@ -1,7 +1,7 @@ #!/usr/bin/ruby -# +# # Copyright (C) 2008 Red Hat, Inc. -# Written by Chris Lalancette +# Written by Chris Lalancette and Ian Main # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -22,122 +22,765 @@ $: << File.join(File.dirname(__FILE__), "../dutils") $: << File.join(File.dirname(__FILE__), ".") require 'rubygems' +require "qpid" +require 'monitor' +require 'dutils' require 'optparse' require 'daemons' include Daemonize -$logfile = '/var/log/ovirt-server/taskomatic.log' +require 'task_vm' +require 'task_storage' + +class TaskOmatic + + include MonitorMixin + + $logfile = '/var/log/ovirt-server/taskomatic.log' + + def initialize() + super() + + @sleeptime = 5 + @nth_host = 0 + + @session = Qpid::Qmf::Session.new() + # FIXME: Should come from some kind of config or DNS SRV or what have you. + @broker = @session.add_broker("amqp://localhost:5672") + + do_daemon = true + + opts = OptionParser.new do |opts| + opts.on("-h", "--help", "Print help message") do + puts opts + exit + end + opts.on("-n", "--nodaemon", "Run interactively (useful for debugging)") do |n| + do_daemon = false + end + opts.on("-s N", Integer, "--sleep", "Seconds to sleep between iterations (default is 5 seconds)") do |s| + sleeptime = s + end + end + begin + opts.parse!(ARGV) + rescue OptionParser::InvalidOption + puts opts + exit + end -do_daemon = true -sleeptime = 5 -opts = OptionParser.new do |opts| - opts.on("-h", "--help", "Print help message") do - puts opts - exit + if do_daemon + # XXX: This gets around a problem with paths for the database stuff. + # Normally daemonize would chdir to / but the paths for the database + # stuff are relative so it breaks it.. It's either this or rearrange + # things so the db stuff is included after daemonizing. + pwd = Dir.pwd + daemonize + Dir.chdir(pwd) + lf = open($logfile, 'a') + $stdout = lf + $stderr = lf + end end - opts.on("-n", "--nodaemon", "Run interactively (useful for debugging)") do |n| - do_daemon = !n + + def find_capable_host(db_vm) + possible_hosts = [] + + vm = @session.object(:class => "domain", 'uuid' => db_vm.uuid) + + db_vm.vm_resource_pool.get_hardware_pool.hosts.each do |curr| + # Now each of 'curr' is in the right hardware pool.. now we check them out. + + node = @session.object(:class => "node", 'hostname' => curr.hostname) + next unless node + + # So now we expect if the node was found it's alive and well, then we check + # to make sure there's enough real cores for the number of vcpus, the node + # memory is adequate, the node is not disabled in the database, and if the + # node id is nil or if it is already running (has a node id set) then it + # is probably looking to migrate so we find a node that is not the current + # node. + # + # In the future we could add load or similar checks here. + + #puts "checking node, #{node.cores} >= #{db_vm.num_vcpus_allocated}," + #puts "and #{node.memory} >= #{db_vm.memory_allocated}" + #puts "and not #{curr.is_disabled.nil?} and #{curr.is_disabled == 0}" + #puts "and #{vm ? vm : 'nil'} or #{vm ? vm.active : 'nil'}) or #{vm ? vm.node : 'nil'} != #{node.object_id}" + + if node and node.cores >= db_vm.num_vcpus_allocated \ + and node.memory >= db_vm.memory_allocated \ + and not curr.is_disabled.nil? and curr.is_disabled == 0 \ + and ((!vm or vm.active == 'false') or vm.node != node.object_id) + possible_hosts.push(curr) + end + end + + #puts "possible_hosts.length = #{possible_hosts.length}" + if possible_hosts.length == 0 + # we couldn't find a host that matches this criteria + raise "No host matching VM parameters could be found" + end + + # XXX: Right now we're just picking the nth host, we could also look at + # how many vms are already on it, or the load of the hosts etc. + host = possible_hosts[@nth_host % possible_hosts.length] + @nth_host += 1 + + return host end - opts.on("-s N", Integer, "--sleep", "Seconds to sleep between iterations (default is 5 seconds)") do |s| - sleeptime = s + + def connect_storage_pools(node, storage_volumes) + storagedevs = [] + storage_volumes.each do |db_volume| + # here, we need to iterate through each volume and possibly attach it + # to the host we are going to be using + db_pool = db_volume.storage_pool + if db_pool == nil + # Hum. Specified by the VM description, but not in the storage pool? + # continue on and hope for the best + puts "Couldn't find pool for volume #{db_volume.path}; skipping" + next + end + + # we have to special case LVM pools. In that case, we need to first + # activate the underlying physical device, and then do the logical one + if db_volume[:type] == "LvmStorageVolume" + phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(db_volume) + phys_libvirt_pool.connect(@session, node) + end + + libvirt_pool = LibvirtPool.factory(db_pool) + libvirt_pool.connect(@session, node) + + # OK, the pool should be all set. The last thing we need to do is get + # the path based on the volume name + + volume_name = db_volume.read_attribute(db_volume.volume_name) + pool = libvirt_pool.remote_pool + volume = @session.object(:class => 'volume', + 'name' => volume_name, + 'storagePool' => pool.object_id) + raise "Unable to find volume #{volume_name} attached to pool #{pool.name}." unless volume + storagedevs << volume.path + end + + return storagedevs end -end -begin - opts.parse!(ARGV) -rescue OptionParser::InvalidOption - puts opts - exit -end -if do_daemon - daemonize - STDOUT.reopen $logfile, 'a' - STDERR.reopen STDOUT -end + def task_create_vm(task) + # XXX: This is mostly just a place holder. + vm = find_vm(task, false) + if vm.state != Vm::STATE_PENDING + raise "VM not pending" + end + vm.state = Vm::STATE_STOPPED + vm.save! + end -begin - require 'dutils' -rescue => ex - puts "dutils require failed! #{ex.class}: #{ex.message}" -end + def teardown_storage_pools(node) -require 'task_vm' -require 'task_storage' -require 'task_host' - -loop do - tasks = Array.new - begin - tasks = Task.find(:all, :conditions => [ "state = ?", Task::STATE_QUEUED ]) - rescue => ex - puts "1 #{ex.class}: #{ex.message}" - if Task.connected? - begin - ActiveRecord::Base.connection.reconnect! - rescue => norecon - puts "2 #{norecon.class}: #{norecon.message}" + # This is rather silly because we only destroy pools if there are no + # more vms on the node. We should be reference counting the pools + # somehow so we know when they are no longer in use. + vms = @session.objects(:class => 'domain', 'node' => node.object_id) + if vms.length > 0 + return + end + pools = @session.objects(:class => 'pool', 'node' => node.object_id) + + # FIXME: I think we should be destroying/undefining logical volumes first. + pools.each do |pool| + result = pool.destroy + result = pool.undefine + end + end + + + def task_shutdown_or_destroy_vm(task, action) + db_vm = task.vm + vm = @session.object(:class => 'domain', 'uuid' => db_vm.uuid) + if !vm + puts "VM already shut down?" + return + end + + node = @session.object(:object_id => vm.node) + raise "Unable to get node that vm is on??" unless node + + if vm.state == "shutdown" or vm.state == "shutoff" + set_vm_shut_down(db_vm) + return + elsif vm.state == "suspended" + raise "Cannot shutdown suspended domain" + elsif vm.state == "saved" + raise "Cannot shutdown saved domain" + end + + if action == :shutdown + result = vm.shutdown + raise "Error shutting down VM: #{result.text}" unless result.status == 0 + elsif action == :destroy + result = vm.destroy + raise "Error destroying VM: #{result.text}" unless result.status == 0 + end + + # undefine can fail, for instance, if we live migrated from A -> B, and + # then we are shutting down the VM on B (because it only has "transient" + # XML). Therefore, just ignore undefine errors so we do the rest + # FIXME: we really should have a marker in the database somehow so that + # we can tell if this domain was migrated; that way, we can tell the + # difference between a real undefine failure and one because of migration + result = vm.undefine + puts "Error undefining VM: #{result.text}" unless result.status == 0 + + teardown_storage_pools(node) + + set_vm_shut_down(db_vm) + end + + def task_start_vm(task) + db_vm = find_vm(task, false) + + # XXX: Kinda silly? I dunno about these intermediate states.. + set_vm_state(db_vm, Vm::STATE_STARTING) + + vm = @session.object(:class => "domain", 'uuid' => db_vm.uuid) + + if vm + case vm.state + when "running" + return + when "blocked" + raise "Virtual machine state is blocked, cannot start VM." + when "paused" + raise "Virtual machine is currently paused, cannot start, must resume." end - else - begin - database_connect - rescue => ex - puts "3 #{ex.class}: #{ex.message}" + end + # FIXME: There's a bug here in that a host that's already running the vm won't be + # returned. I think that's supposed to be for migration but it just breaks stuff. + db_host = find_capable_host(db_vm) + + node = @session.object(:class => "node", 'hostname' => db_host.hostname) + + raise "Unable to find host #{db_host.hostname} to create VM on." unless node + + if (db_vm.boot_device == Vm::BOOT_DEV_CDROM) && db_vm.uses_cobbler? && (db_vm.cobbler_type == Vm::IMAGE_PREFIX) + + details = Cobbler::Image.find_one(db_vm.cobbler_name) + raise "Image #{vm.cobbler_name} not found in Cobbler server" unless details + + # extract the components of the image filename + image_uri = details.file + protocol = auth = ip_addr = export_path = filename = "" + + protocol, image_uri = image_uri.split("://") if image_uri.include?("://") + auth, image_uri = image_uri.split("@") if image_uri.include?("@") + # it's ugly, but string.split returns an empty string as the first + # result here, so we'll just ignore it + ignored, ip_addr, image_uri = + image_uri.split(/^([^\/]+)(\/.*)/) unless image_uri =~ /^\// + ignored, export_path, filename = + image_uri.split(/^(.*)\/(.+)/) + + found = false + + db_vm.storage_volumes.each do |volume| + if volume.filename == filename + if (volume.storage_pool.ip_addr == ip_addr) && + (volume.storage_pool.export_path == export_path) + found = true + end + end + end + + unless found + # Create a new transient NFS storage volume + # This volume is *not* persisted. + image_volume = StorageVolume.factory("NFS", :filename => filename) + + image_volume.storage_pool + image_pool = StoragePool.factory(StoragePool::NFS) + + image_pool.ip_addr = ip_addr + image_pool.export_path = export_path + image_pool.storage_volumes << image_volume + image_volume.storage_pool = image_pool end end + + # FIXME: I know this part is broken.. + # + # hrrm, who wrote this comment and why is it broken? - Ian + volumes = [] + volumes += db_vm.storage_volumes + volumes << image_volume if image_volume + storagedevs = connect_storage_pools(node, volumes) + + # FIXME: get rid of the hardcoded bridge + xml = create_vm_xml(db_vm.description, db_vm.uuid, db_vm.memory_allocated, + db_vm.memory_used, db_vm.num_vcpus_allocated, db_vm.boot_device, + db_vm.vnic_mac_addr, "ovirtbr0", storagedevs) + + result = node.domainDefineXML(xml.to_s) + raise "Error defining virtual machine: #{result.text}" unless result.status == 0 + + domain = @session.object(:object_id => result.domain) + raise "Cannot find domain on host #{db_host.hostname}, cannot start virtual machine." unless domain + + result = domain.create + if result.status != 0 + domain.undefine + raise "Error creating virtual machine: #{result.text}" + end + + result = domain.getXMLDesc + + # Reget the db record or you can get 'dirty' errors. + db_vm = find_vm(task, false) + set_vm_vnc_port(db_vm, result.description) unless result.status != 0 + + # XXX: This information is not available via the libvirt interface. + db_vm.memory_used = db_vm.memory_allocated + db_vm.boot_device = Vm::BOOT_DEV_HD + db_vm.host_id = db_host.id + + # We write the new state here even though dbomatic will set it soon anyway. + # This is just to let the UI know that it's good to go right away and really + # dbomatic will just write the same thing over top of it soon enough. + db_vm.state = Vm::STATE_RUNNING + db_vm.save! + end + + def task_suspend_vm(task) + db_vm = task.vm + dom = @session.object(:class => 'domain', 'uuid' => db_vm.uuid) + raise "Unable to locate VM to suspend" unless dom + + if dom.state == "shutdown" or dom.state == "shutoff" + raise "Cannot suspend stopped domain" + elsif dom.state == "paused" + raise "Cannot suspend saved domain" + end + + result = dom.suspend + raise "Error suspending VM: #{result.text}" unless result.status == 0 + + db_vm.state = Vm::STATE_SUSPENDED + db_vm.save! end - tasks.each do |task| - # make sure we get our credentials up-front - get_credentials - task.time_started = Time.now - task.state = Task::STATE_RUNNING - task.save! + def task_resume_vm(task) + db_vm = task.vm + dom = @session.object(:class => 'domain', 'uuid' => db_vm.uuid) + raise "Unable to locate VM to resume" unless dom + + if dom.state == "running" + # the VM is already suspended; just return success + return + elsif dom.state == "shutoff" or dom.state == "shutdown" + raise "Cannot resume stopped domain" + elsif dom.state == "blocked" + raise "Cannot resume suspended domain" + end + + result = dom.resume + raise "Error resuming VM: #{result.text}" unless result.status == 0 + + db_vm.state = Vm::STATE_RUNNING + db_vm.save! + end + + def task_save_vm(task) + db_vm = task.vm + dom = @session.object(:class => 'domain', 'uuid' => db_vm.uuid) + raise "Unable to locate VM to save" unless dom + + #XXX: I'm not checking states here. I want to see if libvirt gives back + #decent error messages for different states. + filename = "/tmp/#{dom.uuid}.save" + puts "saving vm #{dom.name} to #{filename}" + result = dom.save(filename) + raise "Error saving VM: #{result.text}" unless result.status == 0 + + set_vm_state(db_vm, Vm::STATE_SAVED) + end + + def task_restore_vm(task) + db_vm = task.vm + dom = @session.object(:class => 'domain', 'uuid' => db_vm.uuid) + raise "Unable to locate VM to restore" unless dom + + #XXX: I'm not checking states here. I want to see if libvirt gives back + #decent error messages for different states. + + filename = "/tmp/#{dom.uuid}.save" + puts "restoring vm #{dom.name} from #{filename}" + result = dom.restore("/tmp/" + dom.uuid + ".save") + raise "Error restoring VM: #{result.text}" unless result.status == 0 + + set_vm_state(db_vm, Vm::STATE_RUNNING) + end + + def migrate(db_vm, dest = nil) + + vm = @session.object(:class => "domain", 'uuid' => db_vm.uuid) + raise "Unable to find VM to migrate" unless vm + src_node = @session.object(:object_id => vm.node) + raise "Unable to find node that VM is on??" unless src_node + + puts "Migrating domain lookup complete, domain is #{vm}" + + case vm.state + when "blocked" + raise "Unable to migrate blocked VM." + when "paused" + raise "Unable to migrate suspended VM." + end + + vm_orig_state = db_vm.state + set_vm_state(db_vm, Vm::STATE_MIGRATING) - state = Task::STATE_FINISHED begin - case task.action - when VmTask::ACTION_CREATE_VM then create_vm(task) - when VmTask::ACTION_SHUTDOWN_VM then shutdown_vm(task) - when VmTask::ACTION_POWEROFF_VM then poweroff_vm(task) - when VmTask::ACTION_START_VM then start_vm(task) - when VmTask::ACTION_SUSPEND_VM then suspend_vm(task) - when VmTask::ACTION_RESUME_VM then resume_vm(task) - when VmTask::ACTION_SAVE_VM then save_vm(task) - when VmTask::ACTION_RESTORE_VM then restore_vm(task) - when VmTask::ACTION_UPDATE_STATE_VM then update_state_vm(task) - when VmTask::ACTION_MIGRATE_VM then migrate_vm(task) - when StorageTask::ACTION_REFRESH_POOL then refresh_pool(task) - when StorageVolumeTask::ACTION_CREATE_VOLUME then create_volume(task) - when StorageVolumeTask::ACTION_DELETE_VOLUME then delete_volume(task) - when HostTask::ACTION_CLEAR_VMS then clear_vms_host(task) + unless dest.nil? or dest.empty? + if dest.to_i == db_vm.host_id + raise "Cannot migrate from host " + src_node.hostname + " to itself!" + end + db_dst_host = find_host(dest.to_i) else - puts "unknown task " + task.action - state = Task::STATE_FAILED - task.message = "Unknown task type" + db_dst_host = find_capable_host(db_vm) end + + dest_node = @session.object(:class => 'node', 'hostname' => db_dst_host.hostname) + raise "Unable to find host #{db_dst_host.hostname} to migrate to." unless dest_node + + volumes = [] + volumes += db_vm.storage_volumes + connect_storage_pools(dest_node, volumes) + + # Sadly migrate with qpid is broken because it requires a connection between + # both nodes and currently that can't happen securely. For now we do it + # the old fashioned way.. + dst_uri = "qemu+tcp://#{dest_node.hostname}/system" + src_uri = "qemu+tcp://#{src_node.hostname}/system" + src_conn = Libvirt::open("qemu+tcp://" + src_node.hostname + "/system") + dst_conn = Libvirt::open("qemu+tcp://" + dest_node.hostname + "/system") + dom = src_conn.lookup_domain_by_uuid(vm.uuid) + dom.migrate(dst_conn, Libvirt::Domain::MIGRATE_LIVE) + src_conn.close + dst_conn.close + + # undefine can fail, for instance, if we live migrated from A -> B, and + # then we are shutting down the VM on B (because it only has "transient" + # XML). Therefore, just ignore undefine errors so we do the rest + # FIXME: we really should have a marker in the database somehow so that + # we can tell if this domain was migrated; that way, we can tell the + # difference between a real undefine failure and one because of migration + result = vm.undefine + puts "Error undefining old vm after migrate: #{result.text}" unless result.status == 0 + + # See if we can take down storage pools on the src host. + teardown_storage_pools(src_node) rescue => ex - puts "Task action processing failed: #{ex.class}: #{ex.message}" - puts ex.backtrace - state = Task::STATE_FAILED - task.message = ex.message - end - - task.state = state - task.time_ended = Time.now - task.save! - puts "done" - end - - # FIXME: here, we clean up "orphaned" tasks. These are tasks that we had - # to orphan (set task_target to nil) because we were deleting the object they - # depended on. - Task.find(:all, :conditions => [ "task_target_id IS NULL and task_target_type IS NULL" ]).each do |task| - task.destroy - end - - # we could destroy credentials, but another process might be using them (in - # particular, host-browser). Just leave them around, it shouldn't hurt - - STDOUT.flush - sleep sleeptime + puts "Error: #{ex}" + set_vm_state(db_vm, vm_orig_state) + raise ex + end + + db_vm.state = Vm::STATE_RUNNING + db_vm.host_id = db_dst_host.id + db_vm.save! + end + + def task_migrate_vm(task) + puts "migrate_vm" + + # here, we are given an id for a VM to migrate; we have to lookup which + # physical host it is running on + vm = find_vm(task) + migrate(vm, task.args) + end + + def storage_find_suitable_host(hardware_pool) + # find all of the hosts in the same pool as the storage + hardware_pool.hosts.each do |host| + puts "storage_find_suitable_host: host #{host.hostname} uuid #{host.uuid}" + node = @session.object(:class => 'node', 'hostname' => host.hostname) + return node if node + end + + raise "Could not find a host within this storage pool to scan the storage server." + end + + def add_volumes_to_db(db_pool, libvirt_pool, owner = nil, group = nil, mode = nil) + # FIXME: this is currently broken if you do something like: + # 1. Add an iscsi pool with 3 volumes (lun-1, lun-2, lun-3) + # 2. Scan it in + # 3. Remove lun-3 from the pool + # 4. Re-scan it + # What will happen is that you will still have lun-3 available in the + # database, even though it's not available in the pool anymore. It's a + # little tricky, though; we have to make sure that we don't pull the + # database entry out from underneath a possibly running VM (or do we?) + volumes = @session.objects(:class => 'volume', 'storagePool' => libvirt_pool.remote_pool.object_id) + volumes.each do |volume| + storage_volume = StorageVolume.factory(db_pool.get_type_label) + + # NOTE: it is safe (and, in fact, necessary) to use + # #{storage_volume.volume_name} here without sanitizing it. This is + # because this is *not* based on user modifiable data, but rather, on an + # internal implementation detail + existing_vol = StorageVolume.find(:first, :conditions => + ["storage_pool_id = ? AND #{storage_volume.volume_name} = ?", + db_pool.id, volume.name]) + + # in this case, this path already exists in the database; just skip + next if existing_vol + + storage_volume = StorageVolume.factory(db_pool.get_type_label) + storage_volume.path = volume.path + storage_volume.size = volume.capacity / 1024 + storage_volume.storage_pool_id = db_pool.id + storage_volume.write_attribute(storage_volume.volume_name, volume.name) + storage_volume.lv_owner_perms = owner + storage_volume.lv_group_perms = group + storage_volume.lv_mode_perms = mode + storage_volume.state = StorageVolume::STATE_AVAILABLE + puts "saving storage volume to db." + storage_volume.save! + end + end + + # The words "pool" and "volume" are ridiculously overloaded in our context. + # Therefore, the refresh_pool method adopts this convention: + # db_pool_phys: The underlying physical storage pool, as it is represented in + # the database + # phys_libvirt_pool: The underlying physical storage, as it is represented in + # libvirt + # db_lvm_pool: The logical storage pool (if it exists), as it is represented + # in the database + # lvm_libvirt_pool: The logical storage pool (if it exists), as it is + # represented in the database + + def task_refresh_pool(task) + puts "refresh_pool" + + db_pool_phys = task.storage_pool + raise "Could not find storage pool" unless db_pool_phys + + node = storage_find_suitable_host(db_pool_phys.hardware_pool) + + # FIXME: We may want to scan through all the LVM volumes available + # and just update the database with allocation information. + # However afaict right now libvirt provides no way for us to know + # where an LVM pool/volume sits in terms of its physical pool/volume + # so we're kinda screwed for now for updating the database. + # + # Ian + begin + phys_libvirt_pool = LibvirtPool.factory(db_pool_phys) + phys_libvirt_pool.connect(@session, node) + + begin + # OK, the pool is all set. Add in all of the volumes + add_volumes_to_db(db_pool_phys, phys_libvirt_pool) + + db_pool_phys.state = StoragePool::STATE_AVAILABLE + db_pool_phys.save! + end + ensure + phys_libvirt_pool.shutdown + end + end + + def task_create_volume(task) + puts "create_volume" + + db_volume = task.storage_volume + raise "Could not find storage volume to create" unless db_volume + + db_pool = db_volume.storage_pool + raise "Could not find storage pool" unless db_pool + + node = storage_find_suitable_host(db_pool.hardware_pool) + + begin + if db_volume[:type] == "LvmStorageVolume" + phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(db_volume) + phys_libvirt_pool.connect(@session, node) + end + + begin + libvirt_pool = LibvirtPool.factory(db_pool) + + begin + libvirt_pool.connect(@session, node) + volume_id = libvirt_pool.create_vol(*db_volume.volume_create_params) + volume = @session.object(:object_id => volume_id) + raise "Unable to find newly created volume" unless volume + + puts " volume:" + for (key, val) in volume.properties + puts " property: #{key}, #{val}" + end + + # FIXME: Should have this too I think.. + #db_volume.key = volume.key + db_volume.path = volume.path + db_volume.state = StorageVolume::STATE_AVAILABLE + db_volume.save! + + db_pool.state = StoragePool::STATE_AVAILABLE + db_pool.save! + ensure + libvirt_pool.shutdown + end + ensure + if db_volume[:type] == "LvmStorageVolume" + phys_libvirt_pool.shutdown + end + end + end + end + + def task_delete_volume(task) + puts "delete_volume" + + db_volume = task.storage_volume + raise "Could not find storage volume to create" unless db_volume + + db_pool = db_volume.storage_pool + raise "Could not find storage pool" unless db_pool + + node = storage_find_suitable_host(db_pool.hardware_pool) + + begin + if db_volume[:type] == "LvmStorageVolume" + phys_libvirt_pool = get_libvirt_lvm_pool_from_volume(db_volume) + phys_libvirt_pool.connect(@session, node) + puts "connected to lvm pool.." + end + + begin + libvirt_pool = LibvirtPool.factory(db_pool) + libvirt_pool.connect(@session, node) + + begin + volume = @session.object(:class => 'volume', + 'storagePool' => libvirt_pool.remote_pool.object_id, + 'path' => db_volume.path) + puts "Unable to find volume to delete" unless volume + + # FIXME: we actually probably want to zero out the whole volume here, so + # we aren't potentially leaking data from one user to another. There + # are two problems, though: + # 1) I'm not sure how I would go about zero'ing the data on a remote + # machine, since there is no "libvirt_write_data" call + # 2) This could potentially take quite a while, so we want to spawn + # off another thread to do it + result = volume.delete + raise "Error deleting volume: #{result.text}" unless result.status == 0 + + # Note: we have to nil out the task_target because when we delete the + # volume object, that also deletes all dependent tasks (including this + # one), which leads to accessing stale tasks. Orphan the task, then + # delete the object; we can clean up orphans later (or not, depending + # on the audit policy) + task.task_target = nil + task.save! + + db_volume.destroy + ensure + libvirt_pool.shutdown + end + ensure + if db_volume[:type] == "LvmStorageVolume" + phys_libvirt_pool.shutdown + end + end + end + end + + def task_clear_vms_host(task) + src_host = task.host + + src_host.vms.each do |vm| + migrate(vm) + end + end + + def mainloop() + loop do + tasks = Array.new + begin + tasks = Task.find(:all, :conditions => [ "state = ?", Task::STATE_QUEUED ]) + rescue => ex + puts "1 #{ex.class}: #{ex.message}" + if Task.connected? + begin + ActiveRecord::Base.connection.reconnect! + rescue => norecon + puts "2 #{norecon.class}: #{norecon.message}" + end + else + begin + database_connect + rescue => ex + puts "3 #{ex.class}: #{ex.message}" + end + end + end + + tasks.each do |task| + # make sure we get our credentials up-front + get_credentials + + task.time_started = Time.now + + state = Task::STATE_FINISHED + begin + case task.action + when VmTask::ACTION_CREATE_VM then task_create_vm(task) + when VmTask::ACTION_SHUTDOWN_VM then task_shutdown_or_destroy_vm(task, :shutdown) + when VmTask::ACTION_POWEROFF_VM then task_shutdown_or_destroy_vm(task, :destroy) + when VmTask::ACTION_START_VM then task_start_vm(task) + when VmTask::ACTION_SUSPEND_VM then task_suspend_vm(task) + when VmTask::ACTION_RESUME_VM then task_resume_vm(task) + when VmTask::ACTION_SAVE_VM then task_save_vm(task) + when VmTask::ACTION_RESTORE_VM then task_restore_vm(task) + when VmTask::ACTION_MIGRATE_VM then task_migrate_vm(task) + when StorageTask::ACTION_REFRESH_POOL then task_refresh_pool(task) + when StorageVolumeTask::ACTION_CREATE_VOLUME then task_create_volume(task) + when StorageVolumeTask::ACTION_DELETE_VOLUME then task_delete_volume(task) + when HostTask::ACTION_CLEAR_VMS then task_clear_vms_host(task) + else + puts "unknown task " + task.action + state = Task::STATE_FAILED + task.message = "Unknown task type" + end + rescue => ex + puts "Task action processing failed: #{ex.class}: #{ex.message}" + puts ex.backtrace + state = Task::STATE_FAILED + task.message = ex.message + end + + task.state = state + task.time_ended = Time.now + task.save! + puts "done" + end + # FIXME: here, we clean up "orphaned" tasks. These are tasks that we had + # to orphan (set task_target to nil) because we were deleting the object they + # depended on. + Task.find(:all, :conditions => [ "task_target_id IS NULL and task_target_type IS NULL" ]).each do |task| + task.destroy + end + sleep(1) + end + end end + +taskomatic = TaskOmatic.new() +taskomatic.mainloop() + diff --git a/src/task-omatic/utils.rb b/src/task-omatic/utils.rb deleted file mode 100644 index e3005ed..0000000 --- a/src/task-omatic/utils.rb +++ /dev/null @@ -1,221 +0,0 @@ -require 'rexml/document' -include REXML - -def String.random_alphanumeric(size=16) - s = "" - size.times { s << (i = Kernel.rand(62); i += ((i < 10) ? 48 : ((i < 36) ? 55 : 61 ))).chr } - s -end - -def all_storage_pools(conn) - all_pools = conn.list_defined_storage_pools - all_pools.concat(conn.list_storage_pools) - return all_pools -end - -def get_libvirt_lvm_pool_from_volume(db_volume) - phys_volume = StorageVolume.find(:first, :conditions => - [ "lvm_pool_id = ?", db_volume.storage_pool_id]) - - return LibvirtPool.factory(phys_volume.storage_pool) -end - -class LibvirtPool - def initialize(type, name = nil) - @remote_pool = nil - @build_on_start = true - @remote_pool_defined = false - @remote_pool_started = false - - if name == nil - @name = type + "-" + String.random_alphanumeric - else - @name = name - end - - @xml = Document.new - @xml.add_element("pool", {"type" => type}) - - @xml.root.add_element("name").add_text(@name) - - @xml.root.add_element("source") - - @xml.root.add_element("target") - @xml.root.elements["target"].add_element("path") - end - - def connect(conn) - all_storage_pools(conn).each do |remote_pool_name| - tmppool = conn.lookup_storage_pool_by_name(remote_pool_name) - - if self.xmlequal?(Document.new(tmppool.xml_desc).root) - @remote_pool = tmppool - break - end - end - - if @remote_pool == nil - @remote_pool = conn.define_storage_pool_xml(@xml.to_s) - # we need this because we don't necessarily want to "build" LVM pools, - # which might destroy existing data - if @build_on_start - @remote_pool.build - end - @remote_pool_defined = true - end - - if @remote_pool.info.state == Libvirt::StoragePool::INACTIVE - # only try to start the pool if it is currently inactive; in all other - # states, assume it is already running - @remote_pool.create - @remote_pool_started = true - end - end - - def list_volumes - return @remote_pool.list_volumes - end - - def lookup_vol_by_path(dev) - return @remote_pool.lookup_volume_by_path(dev) - end - - def lookup_vol_by_name(name) - return @remote_pool.lookup_volume_by_name(name) - end - - def create_vol(type, name, size, owner, group, mode) - @vol_xml = Document.new - @vol_xml.add_element("volume", {"type" => type}) - @vol_xml.root.add_element("name").add_text(name) - @vol_xml.root.add_element("capacity", {"unit" => "K"}).add_text(size.to_s) - @vol_xml.root.add_element("target") - @vol_xml.root.elements["target"].add_element("permissions") - @vol_xml.root.elements["target"].elements["permissions"].add_element("owner").add_text(owner) - @vol_xml.root.elements["target"].elements["permissions"].add_element("group").add_text(group) - @vol_xml.root.elements["target"].elements["permissions"].add_element("mode").add_text(mode) - end - - def shutdown - if @remote_pool_started - @remote_pool.destroy - end - if @remote_pool_defined - @remote_pool.undefine - end - end - - def xmlequal?(docroot) - return false - end - - def self.factory(pool) - if pool[:type] == "IscsiStoragePool" - return IscsiLibvirtPool.new(pool.ip_addr, pool[:target]) - elsif pool[:type] == "NfsStoragePool" - return NFSLibvirtPool.new(pool.ip_addr, pool.export_path) - elsif pool[:type] == "LvmStoragePool" - # OK, if this is LVM storage, there are two cases we need to care about: - # 1) this is a LUN with LVM already on it. In this case, all we need to - # do is to create a new LV (== libvirt volume), and be done with it - # 2) this LUN is blank, so there is no LVM on it already. In this - # case, we need to pvcreate, vgcreate first (== libvirt pool build), - # and *then* create the new LV (== libvirt volume) on top of that. - # - # We can tell the difference between an LVM Pool that exists and one - # that needs to be created based on the value of the pool.state; - # if it is PENDING_SETUP, we need to create it first - phys_volume = StorageVolume.find(:first, :conditions => - [ "lvm_pool_id = ?", pool.id]) - - return LVMLibvirtPool.new(pool.vg_name, phys_volume.path, - pool.state == StoragePool::STATE_PENDING_SETUP) - else - raise "Unknown storage pool type " + pool[:type].to_s - end - end -end - -class IscsiLibvirtPool < LibvirtPool - def initialize(ip_addr, target) - super('iscsi') - - @type = 'iscsi' - @ipaddr = ip_addr - @target = target - - @xml.root.elements["source"].add_element("host", {"name" => @ipaddr}) - @xml.root.elements["source"].add_element("device", {"path" => @target}) - - @xml.root.elements["target"].elements["path"].text = "/dev/disk/by-id" - end - - def xmlequal?(docroot) - return (docroot.attributes['type'] == @type and - docroot.elements['source'].elements['host'].attributes['name'] == @ipaddr and - docroot.elements['source'].elements['device'].attributes['path'] == @target) - end -end - -class NFSLibvirtPool < LibvirtPool - def initialize(ip_addr, export_path) - super('netfs') - - @type = 'netfs' - @host = ip_addr - @remote_path = export_path - @name = String.random_alphanumeric - - @xml.root.elements["source"].add_element("host", {"name" => @host}) - @xml.root.elements["source"].add_element("dir", {"path" => @remote_path}) - @xml.root.elements["source"].add_element("format", {"type" => "nfs"}) - - @xml.root.elements["target"].elements["path"].text = "/mnt/" + @name - end - - def create_vol(name, size, owner, group, mode) - # FIXME: this can actually take some time to complete (since we aren't - # doing sparse allocations at the moment). During that time, whichever - # libvirtd we chose to use is completely hung up. The solution is 3-fold: - # 1. Allow sparse allocations in the WUI front-end - # 2. Make libvirtd multi-threaded - # 3. Make taskomatic multi-threaded - super("netfs", name, size, owner, group, mode) - - # FIXME: we have to add the format as raw here because of a bug in libvirt; - # if you specify a volume with no format, it will crash libvirtd - @vol_xml.root.elements["target"].add_element("format", {"type" => "raw"}) - @remote_pool.create_vol_xml(@vol_xml.to_s) - end - - def xmlequal?(docroot) - return (docroot.attributes['type'] == @type and - docroot.elements['source'].elements['host'].attributes['name'] == @host and - docroot.elements['source'].elements['dir'].attributes['path'] == @remote_path) - end -end - -class LVMLibvirtPool < LibvirtPool - def initialize(vg_name, device, build_on_start) - super('logical', vg_name) - - @type = 'logical' - @build_on_start = build_on_start - - @xml.root.elements["source"].add_element("name").add_text(@name) - @xml.root.elements["source"].add_element("device", {"path" => device}) - - @xml.root.elements["target"].elements["path"].text = "/dev/" + @name - end - - def create_vol(name, size, owner, group, mode) - super("logical", name, size, owner, group, mode) - @remote_pool.create_vol_xml(@vol_xml.to_s) - end - - def xmlequal?(docroot) - return (docroot.attributes['type'] == @type and - docroot.elements['name'].text == @name and - docroot.elements['source'].elements['name'] == @name) - end -end -- 1.6.0.4 From pmyers at redhat.com Sat Dec 20 02:39:34 2008 From: pmyers at redhat.com (Perry Myers) Date: Fri, 19 Dec 2008 21:39:34 -0500 Subject: [Ovirt-devel] [PATCH server] Changed how taskomatic handles a Cobbler image record. In-Reply-To: <1229539899-27003-1-git-send-email-dpierce@redhat.com> References: <1229539899-27003-1-git-send-email-dpierce@redhat.com> Message-ID: <494C5AE6.4000104@redhat.com> Darryl L. Pierce wrote: > It will now incrementally pull out the protocol, authentication details, > hostname or ip address, export path and filename for the image record. This patch works fine for urls like: nfs://192.168.50.2/cobblernfs/winxp.iso but does not work for nfs://192.168.50.2:/cobblernfs/winxp.iso And according to the cobbler site: https://fedorahosted.org/cobbler/wiki/AllAboutImages The format for nfs urls should look like: nfs://user at host:/path/to/foo.iso --image-type=iso The problem is if you put the : in the url after the hostname two colons are put into the libvirt xml and the mount then fails. This needs to be fixed, but .96 will be released with this error. For .96 people will just need to use: nfs://host/dir/file.iso Since that is the format that does work Perry From danken at redhat.com Sun Dec 21 07:57:22 2008 From: danken at redhat.com (Dan Kenigsberg) Date: Sun, 21 Dec 2008 09:57:22 +0200 Subject: [Ovirt-devel] [PATCH node] /sbin/ifup is strict about case. indulge it. Message-ID: <1229846242-11335-1-git-send-email-danken@redhat.com> --- scripts/ovirt-config-networking | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/scripts/ovirt-config-networking b/scripts/ovirt-config-networking index 6609d0a..bee1c73 100755 --- a/scripts/ovirt-config-networking +++ b/scripts/ovirt-config-networking @@ -42,7 +42,7 @@ function configure_interface local BR_ROOT="$CONFIG_FILE_ROOT-$BRIDGE" local BR_CONFIG="rm $BR_ROOT\nset $BR_ROOT/DEVICE $BRIDGE" - BR_CONFIG="$BR_CONFIG\nset $BR_ROOT/TYPE bridge" + BR_CONFIG="$BR_CONFIG\nset $BR_ROOT/TYPE Bridge" BR_CONFIG="$BR_CONFIG\nset $BR_ROOT/PEERNTP yes" BR_CONFIG="$BR_CONFIG\nset $BR_ROOT/DELAY 0" IF_CONFIG="$IF_CONFIG\nset $IF_ROOT/BRIDGE $BRIDGE" -- 1.6.0.4 From dpierce at redhat.com Mon Dec 22 13:36:31 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 22 Dec 2008 08:36:31 -0500 Subject: [Ovirt-devel] [PATCH server] Changed how taskomatic handles a Cobbler image record. In-Reply-To: <494C5AE6.4000104@redhat.com> References: <1229539899-27003-1-git-send-email-dpierce@redhat.com> <494C5AE6.4000104@redhat.com> Message-ID: <20081222133631.GA4289@mcpierce-laptop.rdu.redhat.com> On Fri, Dec 19, 2008 at 09:39:34PM -0500, Perry Myers wrote: > Darryl L. Pierce wrote: >> It will now incrementally pull out the protocol, authentication details, >> hostname or ip address, export path and filename for the image record. > > This patch works fine for urls like: > > nfs://192.168.50.2/cobblernfs/winxp.iso > > but does not work for > > nfs://192.168.50.2:/cobblernfs/winxp.iso > > And according to the cobbler site: > https://fedorahosted.org/cobbler/wiki/AllAboutImages > > The format for nfs urls should look like: > nfs://user at host:/path/to/foo.iso --image-type=iso Is the host-then-colon pattern valid if not port follows? -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From bkearney at redhat.com Mon Dec 22 14:45:21 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 22 Dec 2008 09:45:21 -0500 Subject: [Ovirt-devel] SELInux failure after install Message-ID: <494FA801.3020800@redhat.com> I am trying out the puppet bare metal installer. It runs clean using the latest bits from the ovirt 10 repo. I can log into the server suite and into cobbler. When I shutdown, and restart the image.. I get the following failure at the console: http://bkearney.fedorapeople.org/selinux.png I am going to keep digging into it.. but wanted to see if this was a known issue or not. -- bk From dpierce at redhat.com Mon Dec 22 14:57:37 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 22 Dec 2008 09:57:37 -0500 Subject: [Ovirt-devel] [PATCH server] Changed how taskomatic handles a Cobbler image record. In-Reply-To: <494C5AE6.4000104@redhat.com> References: <1229539899-27003-1-git-send-email-dpierce@redhat.com> <494C5AE6.4000104@redhat.com> Message-ID: <20081222145737.GC4289@mcpierce-laptop.rdu.redhat.com> On Fri, Dec 19, 2008 at 09:39:34PM -0500, Perry Myers wrote: > Darryl L. Pierce wrote: >> It will now incrementally pull out the protocol, authentication details, >> hostname or ip address, export path and filename for the image record. > > This patch works fine for urls like: > > nfs://192.168.50.2/cobblernfs/winxp.iso > > but does not work for > > nfs://192.168.50.2:/cobblernfs/winxp.iso > > And according to the cobbler site: > https://fedorahosted.org/cobbler/wiki/AllAboutImages > > The format for nfs urls should look like: > nfs://user at host:/path/to/foo.iso --image-type=iso Okay, doing a quick lookup, the above is valid but discouraged so long as the protocol is specified.[1] I'll have a quick look in Cobbler to make sure such a case is handled. But in oVirt we'll raise an exception if no protocol is specified and there's a colon and no port. [1] http://labs.apache.org/webarch/uri/rfc/rfc3986.html#port -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From pmyers at redhat.com Mon Dec 22 15:03:19 2008 From: pmyers at redhat.com (Perry Myers) Date: Mon, 22 Dec 2008 10:03:19 -0500 Subject: [Ovirt-devel] [PATCH server] Changed how taskomatic handles a Cobbler image record. In-Reply-To: <20081222145737.GC4289@mcpierce-laptop.rdu.redhat.com> References: <1229539899-27003-1-git-send-email-dpierce@redhat.com> <494C5AE6.4000104@redhat.com> <20081222145737.GC4289@mcpierce-laptop.rdu.redhat.com> Message-ID: <494FAC37.4030503@redhat.com> Darryl L. Pierce wrote: > On Fri, Dec 19, 2008 at 09:39:34PM -0500, Perry Myers wrote: >> Darryl L. Pierce wrote: >>> It will now incrementally pull out the protocol, authentication details, >>> hostname or ip address, export path and filename for the image record. >> This patch works fine for urls like: >> >> nfs://192.168.50.2/cobblernfs/winxp.iso >> >> but does not work for >> >> nfs://192.168.50.2:/cobblernfs/winxp.iso >> >> And according to the cobbler site: >> https://fedorahosted.org/cobbler/wiki/AllAboutImages >> >> The format for nfs urls should look like: >> nfs://user at host:/path/to/foo.iso --image-type=iso > > Okay, doing a quick lookup, the above is valid but discouraged so > long as the protocol is specified.[1] I'll have a quick look in > Cobbler to make sure such a case is handled. But in oVirt we'll > raise an exception if no protocol is specified and there's a colon > and no port. > > [1] http://labs.apache.org/webarch/uri/rfc/rfc3986.html#port iirc, mpdehaan told me that that field is completely unvalidated so you could put ANY string you want in there... so I think what's important for us to do is to make sure we handle all of the expected normal formats... So just make sure we're doing the proper validation on our end. And you might want to raise an issue with the cobbler team to see if they can put some validation in the field Perry -- |=- Red Hat, Engineering, Emerging Technologies, Boston -=| |=- Email: pmyers at redhat.com -=| |=- Office: +1 412 474 3552 Mobile: +1 703 362 9622 -=| |=- GnuPG: E65E4F3D 88F9 F1C9 C2F3 1303 01FE 817C C5D2 8B91 E65E 4F3D -=| From dpierce at redhat.com Mon Dec 22 15:14:26 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 22 Dec 2008 10:14:26 -0500 Subject: [Ovirt-devel] [PATCH server] Refines the validation for an NFS URL for Cobbler images. Message-ID: <1229958866-17623-1-git-send-email-dpierce@redhat.com> If the URL contains a : after the hostname but no port, then it is ignored. However, if there is no protocol specified and no port supplied then an exception is raised. For now, however, we do not use the port if it's included and use the default NFS port regardless. Signed-off-by: Darryl L. Pierce --- src/task-omatic/task_vm.rb | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/src/task-omatic/task_vm.rb b/src/task-omatic/task_vm.rb index c187287..345bde5 100644 --- a/src/task-omatic/task_vm.rb +++ b/src/task-omatic/task_vm.rb @@ -369,7 +369,7 @@ def start_vm(task) # extract the components of the image filename image_uri = details.file - protocol = auth = ip_addr = export_path = filename = "" + protocol = auth = ip_addr = port = export_path = filename = "" protocol, image_uri = image_uri.split("://") if image_uri.include?("://") auth, image_uri = image_uri.split("@") if image_uri.include?("@") @@ -377,9 +377,14 @@ def start_vm(task) # result here, so we'll just ignore it ignored, ip_addr, image_uri = image_uri.split(/^([^\/]+)(\/.*)/) unless image_uri =~ /^\// + # we extract the port even though we currently do not make use of it + ip_addr, port = ip_addr.split(":") if ip_addr.include?(":") + port = "" if !port ignored, export_path, filename = image_uri.split(/^(.*)\/(.+)/) + raise "Invalid image URL specified" if ip_addr && port.empty? && protocol.empty? + found = false vm.storage_volumes.each do |volume| -- 1.6.0.6 From bkearney at redhat.com Mon Dec 22 15:10:40 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 22 Dec 2008 10:10:40 -0500 Subject: [Ovirt-devel] Re: SELInux failure after install In-Reply-To: <494FA801.3020800@redhat.com> References: <494FA801.3020800@redhat.com> Message-ID: <494FADF0.1060601@redhat.com> Bryan Kearney wrote: > I am trying out the puppet bare metal installer. It runs clean using the > latest bits from the ovirt 10 repo. I can log into the server suite and > into cobbler. > > When I shutdown, and restart the image.. I get the following failure at > the console: > > http://bkearney.fedorapeople.org/selinux.png > > I am going to keep digging into it.. but wanted to see if this was a > known issue or not. > > -- bk > Ok.. the installer does not disable SELinux, but the appliance does. Is the preferred state to be run selinux disabled? I would assume not. -- bk From pmyers at redhat.com Mon Dec 22 15:22:35 2008 From: pmyers at redhat.com (Perry Myers) Date: Mon, 22 Dec 2008 10:22:35 -0500 Subject: [Ovirt-devel] Re: SELInux failure after install In-Reply-To: <494FADF0.1060601@redhat.com> References: <494FA801.3020800@redhat.com> <494FADF0.1060601@redhat.com> Message-ID: <494FB0BB.7040306@redhat.com> Bryan Kearney wrote: > Bryan Kearney wrote: >> I am trying out the puppet bare metal installer. It runs clean using >> the latest bits from the ovirt 10 repo. I can log into the server >> suite and into cobbler. >> >> When I shutdown, and restart the image.. I get the following failure >> at the console: >> >> http://bkearney.fedorapeople.org/selinux.png >> >> I am going to keep digging into it.. but wanted to see if this was a >> known issue or not. >> >> -- bk >> > Ok.. the installer does not disable SELinux, but the appliance does. Is > the preferred state to be run selinux disabled? I would assume not. We've been running the appliance w/ SELinux disabled just because we haven't had time to work through all of the issues that will come up when we enable it. However this is not a long term strategy. The bare metal installer and the appliance both need to eventually work with SELinux properly. I suggest that we release the bare metal installer with a caveat that SELinux must be disabled as a first pass. And then immediately start working on resolving any SELinux issues so that we can enable it properly. Perry From bkearney at redhat.com Mon Dec 22 15:25:43 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 22 Dec 2008 10:25:43 -0500 Subject: [Ovirt-devel] Re: SELInux failure after install In-Reply-To: <494FB0BB.7040306@redhat.com> References: <494FA801.3020800@redhat.com> <494FADF0.1060601@redhat.com> <494FB0BB.7040306@redhat.com> Message-ID: <494FB177.5040502@redhat.com> Perry Myers wrote: > Bryan Kearney wrote: >> Bryan Kearney wrote: >>> I am trying out the puppet bare metal installer. It runs clean using >>> the latest bits from the ovirt 10 repo. I can log into the server >>> suite and into cobbler. >>> >>> When I shutdown, and restart the image.. I get the following failure >>> at the console: >>> >>> http://bkearney.fedorapeople.org/selinux.png >>> >>> I am going to keep digging into it.. but wanted to see if this was a >>> known issue or not. >>> >>> -- bk >>> >> Ok.. the installer does not disable SELinux, but the appliance does. >> Is the preferred state to be run selinux disabled? I would assume not. > > We've been running the appliance w/ SELinux disabled just because we > haven't had time to work through all of the issues that will come up > when we enable it. > > However this is not a long term strategy. The bare metal installer and > the appliance both need to eventually work with SELinux properly. > > I suggest that we release the bare metal installer with a caveat that > SELinux must be disabled as a first pass. And then immediately start > working on resolving any SELinux issues so that we can enable it properly. > > Perry K. .i will work aon a patch to disable it. -- bk From bkearney at redhat.com Mon Dec 22 16:04:48 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 22 Dec 2008 11:04:48 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Use lokkit to disable selinux Message-ID: <1229961888-5968-1-git-send-email-bkearney@redhat.com> --- ace-ovirt/modules/ovirt/manifests/ovirt.pp | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/ace-ovirt/modules/ovirt/manifests/ovirt.pp b/ace-ovirt/modules/ovirt/manifests/ovirt.pp index 36e364f..b3d5756 100644 --- a/ace-ovirt/modules/ovirt/manifests/ovirt.pp +++ b/ace-ovirt/modules/ovirt/manifests/ovirt.pp @@ -80,6 +80,10 @@ class ovirt::setup { command => "/usr/bin/ovirt-add-host $ipa_host /usr/share/ovirt-server/ovirt.keytab", require => Package[ovirt-server] } + + exec { "disable_selinux" : + command => "/usr/sbin/lokkit --selinux=disabled" + } service {"httpd" : enable => true, -- 1.6.0.4 From laine at laine.org Mon Dec 22 14:32:51 2008 From: laine at laine.org (Laine Stump) Date: Mon, 22 Dec 2008 09:32:51 -0500 Subject: [Ovirt-devel] [PATCH server] Changed how taskomatic handles a Cobbler image record. In-Reply-To: <20081222133631.GA4289@mcpierce-laptop.rdu.redhat.com> References: <1229539899-27003-1-git-send-email-dpierce@redhat.com> <494C5AE6.4000104@redhat.com> <20081222133631.GA4289@mcpierce-laptop.rdu.redhat.com> Message-ID: <494FA513.3040204@laine.org> On 12/22/2008 08:36 AM, Darryl L. Pierce wrote: > On Fri, Dec 19, 2008 at 09:39:34PM -0500, Perry Myers wrote: > >> This patch works fine for urls like: >> nfs://192.168.50.2/cobblernfs/winxp.iso >> >> but does not work for >> >> nfs://192.168.50.2:/cobblernfs/winxp.iso >> >> And according to the cobbler site: >> https://fedorahosted.org/cobbler/wiki/AllAboutImages >> >> The format for nfs urls should look like: >> nfs://user at host:/path/to/foo.iso --image-type=iso >> > > Is the host-then-colon pattern valid if not port follows? > That caught my eye too. It's a bit degenerate, but the BNF for NFS URLs (in RFC 2224) allows it: hostport = host [ ":" port ] port = *digit So port is 0 or more occurrences of digit. From dpierce at redhat.com Mon Dec 22 16:14:13 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 22 Dec 2008 11:14:13 -0500 Subject: [Ovirt-devel] [PATCH server] Changed how taskomatic handles a Cobbler image record. In-Reply-To: <494FA513.3040204@laine.org> References: <1229539899-27003-1-git-send-email-dpierce@redhat.com> <494C5AE6.4000104@redhat.com> <20081222133631.GA4289@mcpierce-laptop.rdu.redhat.com> <494FA513.3040204@laine.org> Message-ID: <20081222161413.GE4289@mcpierce-laptop.rdu.redhat.com> On Mon, Dec 22, 2008 at 09:32:51AM -0500, Laine Stump wrote: >> Is the host-then-colon pattern valid if not port follows? >> > That caught my eye too. It's a bit degenerate, but the BNF for NFS URLs > (in RFC 2224) allows it: > > hostport = host [ ":" port ] > port = *digit > > So port is 0 or more occurrences of digit. Yeah, I noticed that as well and think it's an oversight on their part. But, be that as it may, they do describe handling by saying if no port is specified to then use the one for the given protocol. So, if no protocol is specified, then treat it as an error. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From bkearney at redhat.com Mon Dec 22 16:15:38 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 22 Dec 2008 11:15:38 -0500 Subject: [Ovirt-devel] [PATCH server] ovirt-db-omatic requires ruby-qpid to run Message-ID: <1229962538-6347-1-git-send-email-bkearney@redhat.com> --- ovirt-server.spec.in | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/ovirt-server.spec.in b/ovirt-server.spec.in index 79a5adf..c30306b 100644 --- a/ovirt-server.spec.in +++ b/ovirt-server.spec.in @@ -23,6 +23,7 @@ Requires: rubygem(gettext) Requires: ruby-flexmock Requires: postgresql-server Requires: ruby-postgres +Requires: ruby-qpid Requires: xapian-bindings-ruby Requires: xapian-core Requires: pwgen -- 1.6.0.4 From laine at laine.org Mon Dec 22 16:51:01 2008 From: laine at laine.org (Laine Stump) Date: Mon, 22 Dec 2008 11:51:01 -0500 Subject: [Ovirt-devel] [PATCH server] Changed how taskomatic handles a Cobbler image record. In-Reply-To: <20081222161413.GE4289@mcpierce-laptop.rdu.redhat.com> References: <1229539899-27003-1-git-send-email-dpierce@redhat.com> <494C5AE6.4000104@redhat.com> <20081222133631.GA4289@mcpierce-laptop.rdu.redhat.com> <494FA513.3040204@laine.org> <20081222161413.GE4289@mcpierce-laptop.rdu.redhat.com> Message-ID: <494FC575.7010808@laine.org> On 12/22/2008 11:14 AM, Darryl L. Pierce wrote: > On Mon, Dec 22, 2008 at 09:32:51AM -0500, Laine Stump wrote: > >>> Is the host-then-colon pattern valid if not port follows? >>> >>> >> That caught my eye too. It's a bit degenerate, but the BNF for NFS URLs >> (in RFC 2224) allows it: >> >> hostport = host [ ":" port ] >> port = *digit >> >> So port is 0 or more occurrences of digit. >> > > Yeah, I noticed that as well and think it's an oversight on their > part. But, be that as it may, they do describe handling by saying if > no port is specified to then use the one for the given protocol. So, > if no protocol is specified, then treat it as an error. > Definitely an oversight - the original URL RFC (1738) uses 1*digits for port rather than *digits. My guess is that the particular style of URL given in the cobbler docs started when someone took the location format used by mount, rsync, etc (host:/path) and tacked nfs:// on the beginning. From jboggs at redhat.com Mon Dec 22 17:12:21 2008 From: jboggs at redhat.com (Joey Boggs) Date: Mon, 22 Dec 2008 12:12:21 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Use lokkit to disable selinux In-Reply-To: <1229961888-5968-1-git-send-email-bkearney@redhat.com> References: <1229961888-5968-1-git-send-email-bkearney@redhat.com> Message-ID: <494FCA75.20900@redhat.com> ack applied Bryan Kearney wrote: > --- > ace-ovirt/modules/ovirt/manifests/ovirt.pp | 4 ++++ > 1 files changed, 4 insertions(+), 0 deletions(-) > > diff --git a/ace-ovirt/modules/ovirt/manifests/ovirt.pp b/ace-ovirt/modules/ovirt/manifests/ovirt.pp > index 36e364f..b3d5756 100644 > --- a/ace-ovirt/modules/ovirt/manifests/ovirt.pp > +++ b/ace-ovirt/modules/ovirt/manifests/ovirt.pp > @@ -80,6 +80,10 @@ class ovirt::setup { > command => "/usr/bin/ovirt-add-host $ipa_host /usr/share/ovirt-server/ovirt.keytab", > require => Package[ovirt-server] > } > + > + exec { "disable_selinux" : > + command => "/usr/sbin/lokkit --selinux=disabled" > + } > > service {"httpd" : > enable => true, > From bkearney at redhat.com Mon Dec 22 17:26:40 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 22 Dec 2008 12:26:40 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Added better lokkit dependencies, and added ruby-qpid package until next release ups the specfile Message-ID: <1229966800-14209-1-git-send-email-bkearney@redhat.com> --- ace-ovirt/modules/ovirt/manifests/ovirt.pp | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/ace-ovirt/modules/ovirt/manifests/ovirt.pp b/ace-ovirt/modules/ovirt/manifests/ovirt.pp index b3d5756..33e11f1 100644 --- a/ace-ovirt/modules/ovirt/manifests/ovirt.pp +++ b/ace-ovirt/modules/ovirt/manifests/ovirt.pp @@ -44,6 +44,10 @@ class ovirt::setup { package {"libvirt": ensure => installed; } + + package {"ruby-qpid": + ensure => installed; + } package {"ntp": ensure => installed; @@ -82,7 +86,8 @@ class ovirt::setup { } exec { "disable_selinux" : - command => "/usr/sbin/lokkit --selinux=disabled" + command => "/usr/sbin/lokkit --selinux=disabled", + require => Package["ovirt-server"] } service {"httpd" : -- 1.6.0.4 From bkearney at redhat.com Mon Dec 22 17:53:05 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 22 Dec 2008 12:53:05 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] collectd configuration requires the collectd-rrdtool to be installed Message-ID: <1229968385-17096-1-git-send-email-bkearney@redhat.com> --- ace-ovirt/modules/ovirt/manifests/ovirt.pp | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/ace-ovirt/modules/ovirt/manifests/ovirt.pp b/ace-ovirt/modules/ovirt/manifests/ovirt.pp index 33e11f1..809db8e 100644 --- a/ace-ovirt/modules/ovirt/manifests/ovirt.pp +++ b/ace-ovirt/modules/ovirt/manifests/ovirt.pp @@ -40,6 +40,10 @@ class ovirt::setup { package {"collectd": ensure => installed; } + + package {"collectd-rrdtool": + ensure => installed; + } package {"libvirt": ensure => installed; @@ -55,7 +59,8 @@ class ovirt::setup { file {"/etc/collectd.conf": source => "puppet:///ovirt/collectd.conf", - notify => Service[collectd] + notify => Service[collectd], + require => Package["collectd-rrdtool"] } file {"/etc/qpidd.conf": -- 1.6.0.4 From bkearney at redhat.com Mon Dec 22 18:16:31 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 22 Dec 2008 13:16:31 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Use lokkit to disable selinux In-Reply-To: <494FCA75.20900@redhat.com> References: <1229961888-5968-1-git-send-email-bkearney@redhat.com> <494FCA75.20900@redhat.com> Message-ID: <494FD97F.80602@redhat.com> Joey Boggs wrote: > ack applied When you get a chancge, can you push your latest out? I want to compare your version to the patch stream I have. -- bk From bkearney at redhat.com Mon Dec 22 19:04:33 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 22 Dec 2008 14:04:33 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Cobbler remote had typos. Message-ID: <1229972673-23124-1-git-send-email-bkearney@redhat.com> --- ace-ovirt/modules/ovirt/manifests/cobbler.pp | 10 ++-------- 1 files changed, 2 insertions(+), 8 deletions(-) diff --git a/ace-ovirt/modules/ovirt/manifests/cobbler.pp b/ace-ovirt/modules/ovirt/manifests/cobbler.pp index 7fd4e1e..3c2cb2e 100644 --- a/ace-ovirt/modules/ovirt/manifests/cobbler.pp +++ b/ace-ovirt/modules/ovirt/manifests/cobbler.pp @@ -97,12 +97,6 @@ class cobbler::bundled { enable => true, require => File_replacement[settings_ip_address] } - - file {"/etc/cobbler/modules.conf": - source => "puppet:///ovirt/modules.conf", - notify => Service[cobblerd], - require => Package["cobbler"] - } # firewall_rule{"69": destination_port => "69"} # firewall_rule{"25150": destination_port => "25150"} @@ -118,8 +112,8 @@ class cobbler::remote { cobbler_user_config {"cobbler_remote_user": - user_name => "$cobbler_user_name", - user_password => "$cobbler_user_password", + cobbler_user_name => "$cobbler_user_name", + cobbler_user_name => "$cobbler_user_password", cobbler_hostname => "$cobbler_hostname" } } -- 1.6.0.4 From bkearney at redhat.com Mon Dec 22 19:13:55 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 22 Dec 2008 14:13:55 -0500 Subject: [Ovirt-devel] RESEND of PATCH Message-ID: <1229973236-23417-1-git-send-email-bkearney@redhat.com> Please ignore the eaarlier patch. That one removed an earlier patch. This one is correct. From bkearney at redhat.com Mon Dec 22 19:13:56 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 22 Dec 2008 14:13:56 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Cobbler remote had typos. In-Reply-To: <1229973236-23417-1-git-send-email-bkearney@redhat.com> References: <1229973236-23417-1-git-send-email-bkearney@redhat.com> Message-ID: <1229973236-23417-2-git-send-email-bkearney@redhat.com> --- ace-ovirt/modules/ovirt/manifests/cobbler.pp | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ace-ovirt/modules/ovirt/manifests/cobbler.pp b/ace-ovirt/modules/ovirt/manifests/cobbler.pp index 7fd4e1e..a6b16e6 100644 --- a/ace-ovirt/modules/ovirt/manifests/cobbler.pp +++ b/ace-ovirt/modules/ovirt/manifests/cobbler.pp @@ -83,7 +83,7 @@ class cobbler::bundled { notify => Service[cobblerd], require => Package[cobbler] } - + file_replacement{"settings_xml_rpc": file => "/etc/cobbler/settings", pattern => "xmlrpc_rw_enabled: 0", @@ -97,12 +97,12 @@ class cobbler::bundled { enable => true, require => File_replacement[settings_ip_address] } - + file {"/etc/cobbler/modules.conf": source => "puppet:///ovirt/modules.conf", notify => Service[cobblerd], require => Package["cobbler"] - } + } # firewall_rule{"69": destination_port => "69"} # firewall_rule{"25150": destination_port => "25150"} @@ -118,8 +118,8 @@ class cobbler::remote { cobbler_user_config {"cobbler_remote_user": - user_name => "$cobbler_user_name", - user_password => "$cobbler_user_password", + cobbler_user_name => "$cobbler_user_name", + cobbler_user_name => "$cobbler_user_password", cobbler_hostname => "$cobbler_hostname" } } -- 1.6.0.4 From bkearney at redhat.com Mon Dec 22 20:10:56 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 22 Dec 2008 15:10:56 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Add a rake file to build the rpms In-Reply-To: <1229976663-27879-1-git-send-email-bkearney@redhat.com> References: <1229976663-27879-1-git-send-email-bkearney@redhat.com> Message-ID: <1229976663-27879-2-git-send-email-bkearney@redhat.com> --- .gitignore | 1 + rakefile.rb | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 0 deletions(-) create mode 100644 .gitignore create mode 100644 rakefile.rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5fff1d9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +pkg diff --git a/rakefile.rb b/rakefile.rb new file mode 100644 index 0000000..a2fae18 --- /dev/null +++ b/rakefile.rb @@ -0,0 +1,53 @@ +# -*- ruby -*- +# Rakefile: build appliance configuration engine rpms +# +# Copyright (C) 2007 Red Hat, Inc. +# +# Distributed under the GNU Lesser General Public License v2.1 or later. +# See COPYING for details +# +# Bryan Kearney + +require 'rake/clean' +require 'rake/rdoctask' +require 'rake/testtask' +require 'rake/packagetask' + +ROOT_DIR = File::expand_path(".") +PKG_VERSION="0.0.94" +PACKAGE_DIR = ROOT_DIR + "/pkg" + +# +# Files to clean up +# + +CLEAN.include("**/*~","pkg") + + +# Packaging Tasks +# +Rake::PackageTask.new("ace-ovirt", PKG_VERSION) do |pkg| + pkg.need_tar_gz = true + pkg.package_files.include(Dir["ace-ovirt/**/*"]) +end + + +# +# Tasks to build the rpms +# + +# Set up the directories +task :rpm => [ :package ] do |t| + Dir["*.spec"].each do |specfile| + spec = File.basename(specfile) + cp(specfile, "pkg") + puts("Building with spec file #{spec}") + Dir::chdir("pkg") do |dir| + dir = File::expand_path(".") + system("rpmbuild --define '_topdir #{dir}' --define '_sourcedir #{dir}' --define '_srcrpmdir #{dir}' --define '_rpmdir #{dir}' --define '_builddir #{dir}' -ba #{spec} > #{spec}.rpmbuild.log 2>&1") + if $? != 0 + raise "rpmbuild failed" + end + end + end +end -- 1.6.0.4 From bkearney at redhat.com Mon Dec 22 20:10:55 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 22 Dec 2008 15:10:55 -0500 Subject: [Ovirt-devel] Rebased all prior patches Message-ID: <1229976663-27879-1-git-send-email-bkearney@redhat.com> This is a rebase of all the prior patches off of the current github repo (12/22 at about 2:00 pm EST). -- bk From bkearney at redhat.com Mon Dec 22 20:10:57 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 22 Dec 2008 15:10:57 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Always do basic DNS setup In-Reply-To: <1229976663-27879-2-git-send-email-bkearney@redhat.com> References: <1229976663-27879-1-git-send-email-bkearney@redhat.com> <1229976663-27879-2-git-send-email-bkearney@redhat.com> Message-ID: <1229976663-27879-3-git-send-email-bkearney@redhat.com> --- ace-ovirt/modules/ovirt/manifests/dns.pp | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/ace-ovirt/modules/ovirt/manifests/dns.pp b/ace-ovirt/modules/ovirt/manifests/dns.pp index 4d6a05e..99690e5 100644 --- a/ace-ovirt/modules/ovirt/manifests/dns.pp +++ b/ace-ovirt/modules/ovirt/manifests/dns.pp @@ -18,6 +18,7 @@ # Author: Joey Boggs #-- +# common featues define dns::common($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") { package {"dnsmasq": -- 1.6.0.4 From bkearney at redhat.com Mon Dec 22 20:10:58 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 22 Dec 2008 15:10:58 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Rework the dependencies so it is package.. stuff.. then servce In-Reply-To: <1229976663-27879-3-git-send-email-bkearney@redhat.com> References: <1229976663-27879-1-git-send-email-bkearney@redhat.com> <1229976663-27879-2-git-send-email-bkearney@redhat.com> <1229976663-27879-3-git-send-email-bkearney@redhat.com> Message-ID: <1229976663-27879-4-git-send-email-bkearney@redhat.com> --- ace-ovirt/modules/ovirt/manifests/dns.pp | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ace-ovirt/modules/ovirt/manifests/dns.pp b/ace-ovirt/modules/ovirt/manifests/dns.pp index 99690e5..c16abfd 100644 --- a/ace-ovirt/modules/ovirt/manifests/dns.pp +++ b/ace-ovirt/modules/ovirt/manifests/dns.pp @@ -47,8 +47,8 @@ define dns::common($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") { file_replacement {"dnsmasq_configdir": file => "/etc/dnsmasq.conf", - pattern => "^#conf-dir=/etc/dnsmasq.d$" - replacement => "conf-dir=/etc/dnsmasq.d", + pattern => "^#conf-dir=*$", + replacement => "conf-dir=/etc/dnsmasq.d", notify => Service[dnsmasq], require => Package["dnsmasq"] } -- 1.6.0.4 From bkearney at redhat.com Mon Dec 22 20:10:59 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 22 Dec 2008 15:10:59 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Drop a modules.conf file so that the username and password are checked In-Reply-To: <1229976663-27879-4-git-send-email-bkearney@redhat.com> References: <1229976663-27879-1-git-send-email-bkearney@redhat.com> <1229976663-27879-2-git-send-email-bkearney@redhat.com> <1229976663-27879-3-git-send-email-bkearney@redhat.com> <1229976663-27879-4-git-send-email-bkearney@redhat.com> Message-ID: <1229976663-27879-5-git-send-email-bkearney@redhat.com> --- ace-ovirt/modules/ovirt/files/modules.conf | 96 ++++++++++++++++++++++++++ ace-ovirt/modules/ovirt/manifests/cobbler.pp | 5 ++ 2 files changed, 101 insertions(+), 0 deletions(-) create mode 100644 ace-ovirt/modules/ovirt/files/modules.conf diff --git a/ace-ovirt/modules/ovirt/files/modules.conf b/ace-ovirt/modules/ovirt/files/modules.conf new file mode 100644 index 0000000..236ef4c --- /dev/null +++ b/ace-ovirt/modules/ovirt/files/modules.conf @@ -0,0 +1,96 @@ +# specifies what cobbler modules to load. + +# what file/data formats to use for metadata +# +# choices: +# serializer_catalog (fast, uses .d directories in /var/lib/cobbler/config) +# serializer_yaml (original serializer, uses a few text files) +# +# for 99% or more of all installations, use serializer_catalog. +# +# NOTE: serializer changes may remove your ability to access old data. +# serializer_yaml users can change to serializer_catalog w/o manual +# migration steps. Other changes are for new installs only. + +[serializers] +settings = serializer_catalog +distro = serializer_catalog +profile = serializer_catalog +system = serializer_catalog +repo = serializer_catalog +image = serializer_catalog + +# policy: what users can log into the WebUI and Read-Write XMLRPC? +# +# choices: +# authn_denyall -- no one (default) +# authn_configfile -- use /etc/cobbler/users.digest (for basic setups) +# authn_passthru -- ask Apache to handle it (used for kerberos) +# authn_ldap -- authenticate against LDAP +# authn_spacewalk -- ask Spacewalk/Satellite (experimental) +# authn_testing -- username/password is always testing/testing (debug) +# (user supplied) -- you may write your own module +# +# WARNING: this is a security setting, do not choose an option blindly. +# +# for more information: +# https://fedorahosted.org/cobbler/wiki/CobblerWebInterface +# https://fedorahosted.org/cobbler/wiki/CustomizableSecurity +# https://fedorahosted.org/cobbler/wiki/CobblerWithKerberos +# https://fedorahosted.org/cobbler/wiki/CobblerWithLdap + +[authentication] +module = authn_configfile + +# policy: once a user has been cleared by the WebUI/XMLRPC, what can they do? +# +# choices: +# authz_allowall -- full access for all authneticated users (default) +# authz_configfile -- determined by /etc/cobbler/users.conf +# authz_ownership -- use users.conf, but add object ownership semantics +# (user supplied) -- you may write your own module +# +# WARNING: this is a security setting, do not choose an option blindly. +# +# for more information: +# https://fedorahosted.org/cobbler/wiki/CobblerWebInterface +# https://fedorahosted.org/cobbler/wiki/CustomizableSecurity +# https://fedorahosted.org/cobbler/wiki/CustomizableAuthorization +# https://fedorahosted.org/cobbler/wiki/AuthorizationWithOwnership + +[authorization] +module = authz_allowall + +# chooses the DNS management engine if manage_dns is enabled +# in /etc/cobbler/settings, which is off by default. +# +# choices: +# manage_bind -- default, uses BIND/named +# manage_dnsmasq -- uses dnsmasq, also must select dnsmasq for dhcp below +# +# NOTE: more configuration is still required in /etc/cobbler +# +# for more information: +# https://fedorahosted.org/cobbler/wiki/ManageDns + +[dns] +module = manage_bind + +# chooses the DHCP management engine if manage_dhcp is enabled +# in /etc/cobbler/settings, which is off by default. +# +# choices: +# manage_isc -- default, uses ISC dhcpd +# manage_dnsmasq -- uses dnsmasq, also must select dnsmasq for dns above +# +# NOTE: more configuration is still required in /etc/cobbler +# +# for more information: +# https://fedorahosted.org/cobbler/wiki/ManageDhcp + +[dhcp] +module = manage_isc + + + + diff --git a/ace-ovirt/modules/ovirt/manifests/cobbler.pp b/ace-ovirt/modules/ovirt/manifests/cobbler.pp index e4aae62..e3f3698 100644 --- a/ace-ovirt/modules/ovirt/manifests/cobbler.pp +++ b/ace-ovirt/modules/ovirt/manifests/cobbler.pp @@ -97,6 +97,11 @@ class cobbler::bundled { enable => true, require => File_replacement[settings_ip_address] } + + file {"/etc/cobbler/modules.conf": + source => "puppet:///ovirt/modules.conf", + notify => Service[cobblerd] + } # firewall_rule{"69": destination_port => "69"} # firewall_rule{"25150": destination_port => "25150"} -- 1.6.0.4 From bkearney at redhat.com Mon Dec 22 20:11:00 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 22 Dec 2008 15:11:00 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Various small dependency changes In-Reply-To: <1229976663-27879-5-git-send-email-bkearney@redhat.com> References: <1229976663-27879-1-git-send-email-bkearney@redhat.com> <1229976663-27879-2-git-send-email-bkearney@redhat.com> <1229976663-27879-3-git-send-email-bkearney@redhat.com> <1229976663-27879-4-git-send-email-bkearney@redhat.com> <1229976663-27879-5-git-send-email-bkearney@redhat.com> Message-ID: <1229976663-27879-6-git-send-email-bkearney@redhat.com> --- ace-ovirt/modules/ovirt/manifests/cobbler.pp | 3 ++- ace-ovirt/modules/ovirt/manifests/freeipa.pp | 3 ++- ace-ovirt/modules/ovirt/manifests/ovirt.pp | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ace-ovirt/modules/ovirt/manifests/cobbler.pp b/ace-ovirt/modules/ovirt/manifests/cobbler.pp index e3f3698..7fd4e1e 100644 --- a/ace-ovirt/modules/ovirt/manifests/cobbler.pp +++ b/ace-ovirt/modules/ovirt/manifests/cobbler.pp @@ -100,7 +100,8 @@ class cobbler::bundled { file {"/etc/cobbler/modules.conf": source => "puppet:///ovirt/modules.conf", - notify => Service[cobblerd] + notify => Service[cobblerd], + require => Package["cobbler"] } # firewall_rule{"69": destination_port => "69"} diff --git a/ace-ovirt/modules/ovirt/manifests/freeipa.pp b/ace-ovirt/modules/ovirt/manifests/freeipa.pp index 573535f..1f292bf 100644 --- a/ace-ovirt/modules/ovirt/manifests/freeipa.pp +++ b/ace-ovirt/modules/ovirt/manifests/freeipa.pp @@ -55,7 +55,8 @@ class freeipa::bundled{ } single_exec {"dnsmasq_restart": - command => "/etc/init.d/dnsmasq restart" + command => "/etc/init.d/dnsmasq restart", + require => Service["dnsmasq"] } single_exec {"ipa_server_install": diff --git a/ace-ovirt/modules/ovirt/manifests/ovirt.pp b/ace-ovirt/modules/ovirt/manifests/ovirt.pp index 0be8689..b3d5756 100644 --- a/ace-ovirt/modules/ovirt/manifests/ovirt.pp +++ b/ace-ovirt/modules/ovirt/manifests/ovirt.pp @@ -62,7 +62,7 @@ class ovirt::setup { single_exec { "db_migrate" : cwd => "/usr/share/ovirt-server/", command => "/usr/bin/rake db:migrate", - require => [File["/usr/share/ovirt-server/log"],Package[ovirt-server],Package[rubygem-rake]], + require => [File["/usr/share/ovirt-server/log"],Package[ovirt-server],Package[rubygem-rake],Postgres_execute_command["ovirt_db_grant_permissions"]], environment => "RAILS_ENV=production" } -- 1.6.0.4 From bkearney at redhat.com Mon Dec 22 20:11:01 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 22 Dec 2008 15:11:01 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Added better lokkit dependencies, and added ruby-qpid package until next release ups the specfile In-Reply-To: <1229976663-27879-6-git-send-email-bkearney@redhat.com> References: <1229976663-27879-1-git-send-email-bkearney@redhat.com> <1229976663-27879-2-git-send-email-bkearney@redhat.com> <1229976663-27879-3-git-send-email-bkearney@redhat.com> <1229976663-27879-4-git-send-email-bkearney@redhat.com> <1229976663-27879-5-git-send-email-bkearney@redhat.com> <1229976663-27879-6-git-send-email-bkearney@redhat.com> Message-ID: <1229976663-27879-7-git-send-email-bkearney@redhat.com> --- ace-ovirt/modules/ovirt/manifests/ovirt.pp | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/ace-ovirt/modules/ovirt/manifests/ovirt.pp b/ace-ovirt/modules/ovirt/manifests/ovirt.pp index b3d5756..33e11f1 100644 --- a/ace-ovirt/modules/ovirt/manifests/ovirt.pp +++ b/ace-ovirt/modules/ovirt/manifests/ovirt.pp @@ -44,6 +44,10 @@ class ovirt::setup { package {"libvirt": ensure => installed; } + + package {"ruby-qpid": + ensure => installed; + } package {"ntp": ensure => installed; @@ -82,7 +86,8 @@ class ovirt::setup { } exec { "disable_selinux" : - command => "/usr/sbin/lokkit --selinux=disabled" + command => "/usr/sbin/lokkit --selinux=disabled", + require => Package["ovirt-server"] } service {"httpd" : -- 1.6.0.4 From bkearney at redhat.com Mon Dec 22 20:11:02 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 22 Dec 2008 15:11:02 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] collectd configuration requires the collectd-rrdtool to be installed In-Reply-To: <1229976663-27879-7-git-send-email-bkearney@redhat.com> References: <1229976663-27879-1-git-send-email-bkearney@redhat.com> <1229976663-27879-2-git-send-email-bkearney@redhat.com> <1229976663-27879-3-git-send-email-bkearney@redhat.com> <1229976663-27879-4-git-send-email-bkearney@redhat.com> <1229976663-27879-5-git-send-email-bkearney@redhat.com> <1229976663-27879-6-git-send-email-bkearney@redhat.com> <1229976663-27879-7-git-send-email-bkearney@redhat.com> Message-ID: <1229976663-27879-8-git-send-email-bkearney@redhat.com> --- ace-ovirt/modules/ovirt/manifests/ovirt.pp | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/ace-ovirt/modules/ovirt/manifests/ovirt.pp b/ace-ovirt/modules/ovirt/manifests/ovirt.pp index 33e11f1..809db8e 100644 --- a/ace-ovirt/modules/ovirt/manifests/ovirt.pp +++ b/ace-ovirt/modules/ovirt/manifests/ovirt.pp @@ -40,6 +40,10 @@ class ovirt::setup { package {"collectd": ensure => installed; } + + package {"collectd-rrdtool": + ensure => installed; + } package {"libvirt": ensure => installed; @@ -55,7 +59,8 @@ class ovirt::setup { file {"/etc/collectd.conf": source => "puppet:///ovirt/collectd.conf", - notify => Service[collectd] + notify => Service[collectd], + require => Package["collectd-rrdtool"] } file {"/etc/qpidd.conf": -- 1.6.0.4 From bkearney at redhat.com Mon Dec 22 20:11:03 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 22 Dec 2008 15:11:03 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Cobbler remote had typos. In-Reply-To: <1229976663-27879-8-git-send-email-bkearney@redhat.com> References: <1229976663-27879-1-git-send-email-bkearney@redhat.com> <1229976663-27879-2-git-send-email-bkearney@redhat.com> <1229976663-27879-3-git-send-email-bkearney@redhat.com> <1229976663-27879-4-git-send-email-bkearney@redhat.com> <1229976663-27879-5-git-send-email-bkearney@redhat.com> <1229976663-27879-6-git-send-email-bkearney@redhat.com> <1229976663-27879-7-git-send-email-bkearney@redhat.com> <1229976663-27879-8-git-send-email-bkearney@redhat.com> Message-ID: <1229976663-27879-9-git-send-email-bkearney@redhat.com> --- ace-ovirt/modules/ovirt/manifests/cobbler.pp | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ace-ovirt/modules/ovirt/manifests/cobbler.pp b/ace-ovirt/modules/ovirt/manifests/cobbler.pp index 7fd4e1e..e509502 100644 --- a/ace-ovirt/modules/ovirt/manifests/cobbler.pp +++ b/ace-ovirt/modules/ovirt/manifests/cobbler.pp @@ -83,7 +83,7 @@ class cobbler::bundled { notify => Service[cobblerd], require => Package[cobbler] } - + file_replacement{"settings_xml_rpc": file => "/etc/cobbler/settings", pattern => "xmlrpc_rw_enabled: 0", @@ -97,12 +97,12 @@ class cobbler::bundled { enable => true, require => File_replacement[settings_ip_address] } - + file {"/etc/cobbler/modules.conf": source => "puppet:///ovirt/modules.conf", notify => Service[cobblerd], require => Package["cobbler"] - } + } # firewall_rule{"69": destination_port => "69"} # firewall_rule{"25150": destination_port => "25150"} @@ -118,8 +118,8 @@ class cobbler::remote { cobbler_user_config {"cobbler_remote_user": - user_name => "$cobbler_user_name", - user_password => "$cobbler_user_password", + cobbler_user_name => "$cobbler_user_name", + cobbler_user_password => "$cobbler_user_password", cobbler_hostname => "$cobbler_hostname" } } -- 1.6.0.4 From jboggs at redhat.com Mon Dec 22 20:50:10 2008 From: jboggs at redhat.com (Joey Boggs) Date: Mon, 22 Dec 2008 15:50:10 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Add a rake file to build the rpms In-Reply-To: <1229976663-27879-2-git-send-email-bkearney@redhat.com> References: <1229976663-27879-1-git-send-email-bkearney@redhat.com> <1229976663-27879-2-git-send-email-bkearney@redhat.com> Message-ID: <494FFD82.1080605@redhat.com> I applied this one earlier but since it didn't add the rakefile into the repo it got ignored, but fixed that a few mins ago. Bryan Kearney wrote: > --- > .gitignore | 1 + > rakefile.rb | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 54 insertions(+), 0 deletions(-) > create mode 100644 .gitignore > create mode 100644 rakefile.rb > > diff --git a/.gitignore b/.gitignore > new file mode 100644 > index 0000000..5fff1d9 > --- /dev/null > +++ b/.gitignore > @@ -0,0 +1 @@ > +pkg > diff --git a/rakefile.rb b/rakefile.rb > new file mode 100644 > index 0000000..a2fae18 > --- /dev/null > +++ b/rakefile.rb > @@ -0,0 +1,53 @@ > +# -*- ruby -*- > +# Rakefile: build appliance configuration engine rpms > +# > +# Copyright (C) 2007 Red Hat, Inc. > +# > +# Distributed under the GNU Lesser General Public License v2.1 or later. > +# See COPYING for details > +# > +# Bryan Kearney > + > +require 'rake/clean' > +require 'rake/rdoctask' > +require 'rake/testtask' > +require 'rake/packagetask' > + > +ROOT_DIR = File::expand_path(".") > +PKG_VERSION="0.0.94" > +PACKAGE_DIR = ROOT_DIR + "/pkg" > + > +# > +# Files to clean up > +# > + > +CLEAN.include("**/*~","pkg") > + > + > +# Packaging Tasks > +# > +Rake::PackageTask.new("ace-ovirt", PKG_VERSION) do |pkg| > + pkg.need_tar_gz = true > + pkg.package_files.include(Dir["ace-ovirt/**/*"]) > +end > + > + > +# > +# Tasks to build the rpms > +# > + > +# Set up the directories > +task :rpm => [ :package ] do |t| > + Dir["*.spec"].each do |specfile| > + spec = File.basename(specfile) > + cp(specfile, "pkg") > + puts("Building with spec file #{spec}") > + Dir::chdir("pkg") do |dir| > + dir = File::expand_path(".") > + system("rpmbuild --define '_topdir #{dir}' --define '_sourcedir #{dir}' --define '_srcrpmdir #{dir}' --define '_rpmdir #{dir}' --define '_builddir #{dir}' -ba #{spec} > #{spec}.rpmbuild.log 2>&1") > + if $? != 0 > + raise "rpmbuild failed" > + end > + end > + end > +end > From dpierce at redhat.com Mon Dec 22 22:03:23 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 22 Dec 2008 17:03:23 -0500 Subject: [Ovirt-devel] [PATCH server] Refines the validation for an NFS URL for Cobbler images. Message-ID: <1229983403-11205-1-git-send-email-dpierce@redhat.com> The image record file validation has changed. Entries are now going to be in the following allowed formats: username:password at hostname:/path/to/the/filename.ext username at hostname:/path/to/the/filename.ext hostname:/path/to/the/filename.ext /path/to/the/filename.ext Any other format, including legacy ones specifying a protocol, are quietly modified to fit the above formats. Signed-off-by: Darryl L. Pierce --- src/task-omatic/task_vm.rb | 12 ++++-------- 1 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/task-omatic/task_vm.rb b/src/task-omatic/task_vm.rb index c187287..f9d1617 100644 --- a/src/task-omatic/task_vm.rb +++ b/src/task-omatic/task_vm.rb @@ -369,16 +369,12 @@ def start_vm(task) # extract the components of the image filename image_uri = details.file - protocol = auth = ip_addr = export_path = filename = "" + auth = ip_addr = path = filename = "" - protocol, image_uri = image_uri.split("://") if image_uri.include?("://") auth, image_uri = image_uri.split("@") if image_uri.include?("@") - # it's ugly, but string.split returns an empty string as the first - # result here, so we'll just ignore it - ignored, ip_addr, image_uri = - image_uri.split(/^([^\/]+)(\/.*)/) unless image_uri =~ /^\// - ignored, export_path, filename = - image_uri.split(/^(.*)\/(.+)/) + ip_addr, image_uri = image_uri.split(":") if image_uri.include?(":") + filename = image_uri.split("/").last + export_path = filename[0...(0-filename.length)] found = false -- 1.6.0.6 From jboggs at redhat.com Tue Dec 23 00:22:15 2008 From: jboggs at redhat.com (Joey Boggs) Date: Mon, 22 Dec 2008 19:22:15 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Add a rake file to build the rpms In-Reply-To: <494FFD82.1080605@redhat.com> References: <1229976663-27879-1-git-send-email-bkearney@redhat.com> <1229976663-27879-2-git-send-email-bkearney@redhat.com> <494FFD82.1080605@redhat.com> Message-ID: <49502F37.4010204@redhat.com> ack'd all, tested and applied Joey Boggs wrote: > I applied this one earlier but since it didn't add the rakefile into > the repo it got ignored, but fixed that a few mins ago. > > > Bryan Kearney wrote: >> --- >> .gitignore | 1 + >> rakefile.rb | 53 >> +++++++++++++++++++++++++++++++++++++++++++++++++++++ >> 2 files changed, 54 insertions(+), 0 deletions(-) >> create mode 100644 .gitignore >> create mode 100644 rakefile.rb >> >> diff --git a/.gitignore b/.gitignore >> new file mode 100644 >> index 0000000..5fff1d9 >> --- /dev/null >> +++ b/.gitignore >> @@ -0,0 +1 @@ >> +pkg >> diff --git a/rakefile.rb b/rakefile.rb >> new file mode 100644 >> index 0000000..a2fae18 >> --- /dev/null >> +++ b/rakefile.rb >> @@ -0,0 +1,53 @@ >> +# -*- ruby -*- >> +# Rakefile: build appliance configuration engine rpms >> +# >> +# Copyright (C) 2007 Red Hat, Inc. >> +# >> +# Distributed under the GNU Lesser General Public License v2.1 or >> later. >> +# See COPYING for details >> +# >> +# Bryan Kearney >> + >> +require 'rake/clean' >> +require 'rake/rdoctask' >> +require 'rake/testtask' >> +require 'rake/packagetask' >> + >> +ROOT_DIR = File::expand_path(".") >> +PKG_VERSION="0.0.94" >> +PACKAGE_DIR = ROOT_DIR + "/pkg" >> + >> +# >> +# Files to clean up >> +# >> + >> +CLEAN.include("**/*~","pkg") >> + >> + >> +# Packaging Tasks >> +# >> +Rake::PackageTask.new("ace-ovirt", PKG_VERSION) do |pkg| >> + pkg.need_tar_gz = true >> + pkg.package_files.include(Dir["ace-ovirt/**/*"]) +end + >> + >> +# >> +# Tasks to build the rpms >> +# >> + >> +# Set up the directories >> +task :rpm => [ :package ] do |t| >> + Dir["*.spec"].each do |specfile| >> + spec = File.basename(specfile) >> + cp(specfile, "pkg") >> + puts("Building with spec file #{spec}") + >> Dir::chdir("pkg") do |dir| >> + dir = File::expand_path(".") >> + system("rpmbuild --define '_topdir #{dir}' --define >> '_sourcedir #{dir}' --define '_srcrpmdir #{dir}' --define '_rpmdir >> #{dir}' --define '_builddir #{dir}' -ba #{spec} > >> #{spec}.rpmbuild.log 2>&1") >> + if $? != 0 >> + raise "rpmbuild failed" >> + end >> + end >> + end >> +end >> > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel From jboggs at redhat.com Tue Dec 23 00:23:08 2008 From: jboggs at redhat.com (Joey Boggs) Date: Mon, 22 Dec 2008 19:23:08 -0500 Subject: [Ovirt-devel] Rebased all prior patches In-Reply-To: <1229976663-27879-1-git-send-email-bkearney@redhat.com> References: <1229976663-27879-1-git-send-email-bkearney@redhat.com> Message-ID: <49502F6C.8060304@redhat.com> sent to wrong thread earlier, ack'd all, tested and applied Bryan Kearney wrote: > This is a rebase of all the prior patches off of the current github repo (12/22 at about 2:00 pm EST). > > -- bk > > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel > From mschenck at tek-ops.com Tue Dec 23 02:26:20 2008 From: mschenck at tek-ops.com (Michael Schenck) Date: Mon, 22 Dec 2008 21:26:20 -0500 Subject: [Ovirt-devel] ran into some issues with the .96 release Message-ID: <26cc652e0812221826g67752eb9ua4316cf8ef954598@mail.gmail.com> oVirt devel, At point 1 under "Installing and Running the Appliance" on the documents page [http://ovirt.org/install-instructions.html] : this doesn't work "# create-ovirt-appliance -e eth1" I think you mean "# create-ovirt-network -e eth1" Is something wrong with the ovirt-appliance rpm? it's only 15kb; this is from "yum list" " ovirt-appliance noarch 0.96-1.fc10 ovirt 15 k" The documentation (and previous release) would lead me to believe it should still be over 350 MB, and the admin node image file never gets installed. on a side note, where can I make a feature request, I want to get the option to migrate eth0's configs to that of ovirtbr0 Best Regards, Michael Schenck -- Michael Schenck - www.tek-ops.com Karma police, arrest this man He talks in maths He buzzes like a fridge He's like a detuned radio -------------- next part -------------- An HTML attachment was scrubbed... URL: From pmyers at redhat.com Tue Dec 23 02:53:38 2008 From: pmyers at redhat.com (Perry Myers) Date: Mon, 22 Dec 2008 21:53:38 -0500 Subject: [Ovirt-devel] ran into some issues with the .96 release In-Reply-To: <26cc652e0812221826g67752eb9ua4316cf8ef954598@mail.gmail.com> References: <26cc652e0812221826g67752eb9ua4316cf8ef954598@mail.gmail.com> Message-ID: <495052B2.5090305@redhat.com> Michael Schenck wrote: > oVirt devel, > > At point 1 under "Installing and Running the Appliance" on the documents > page [http://ovirt.org/install-instructions.html] : > this doesn't work "# create-ovirt-appliance -e eth1" > I think you mean "# create-ovirt-network -e eth1" I think you're looking at out of date web pages. As of today we updated to version 0.96 for oVirt which uses Fedora 10 as a base. The install instructions say: > # Create the appliance on the host with the following command: > > sudo create-ovirt-appliance > > # If you want to manage real physical hosts, and you have a separately cabled management LAN, run this command on the host machine: > > sudo create-ovirt-network [-e ethX] Refresh the page to make sure you're getting the latest copy of the documentation in your browser, you might have a stale copy in your cache. > Is something wrong with the ovirt-appliance rpm? it's only 15kb; this > is from "yum list" > " ovirt-appliance noarch > 0.96-1.fc10 ovirt 15 k" > The documentation (and previous release) would lead me to believe it > should still be over 350 MB, and the admin node image file never gets > installed. This is also explained on the install instructions page: > Downloading the Appliance > > The ovirt-appliance RPM only contains several scripts to assist in the downloading of the appliance image archive. After the ovirt-appliance RPM is installed, run the following command: > > sudo get-ovirt-appliance > > This will download the ovirt-appliance image archive and then extract the images and metadata to the libvirt image repository at /var/lib/libvirt/images. > on a side note, where can I make a feature request, I want to get the > option to migrate eth0's configs to that of ovirtbr0 Feature requests can be made directly to ovirt-devel. Also, you can put request into bugzilla at bugzilla.redhat.com. Use the Other Miscellaneous Products and Virtualization Tools as the categories. Then the components are all prefaced with oVirt (i.e. oVirt Node, oVirt Server Suite, etc...) Thanks, Perry From pmyers at redhat.com Tue Dec 23 04:23:30 2008 From: pmyers at redhat.com (Perry Myers) Date: Mon, 22 Dec 2008 23:23:30 -0500 Subject: [Ovirt-devel] 0.96 oVirt Release Message-ID: <495067C2.40806@redhat.com> The oVirt development team is pleased to announce the 0.96 release of both the oVirt Node and oVirt Server Suite. New features in this release include: Common: * based on Fedora 10 * added support for building in mock and i386 builds on x86_64 * make source target to build source iso or tarball * Add logic for allowing SSH keys to be included during image and appliance creation time - this is to be used for development purposes only * image/appliance build process creates a manifest tar that can be used in comparing builds oVirt Node: * standalone and autoinstall mode - first boot configuration menu - network configuration - use LVM volumes on GPT partitioned local disk for autoinstall mode ovirt boot parameter is used to define volumes: ovirt_vol=BOOT_MB:SWAP_MB:ROOT_MB:CONFIG_MB:LOGGING_MB - livecd image to local disk installer - use file bindmounts for persisted configs - use optional /config from livecd image - add BOOTIF=link|eth* support * oVirt branded splash image for boot menu * ovirt-node subpackages: - ovirt-node-stateless is for use on the embedded oVirt Node. - ovirt-node-stateful is for use on already installed Fedora hosts to configure that host to act as a Node. Presently it only works when run on the same host as the oVirt Appliance. * edit-livecd script for ad-hoc modification to livecd image * add minimal python into the Node image * use minimal selinux configuration and add modules selectively oVirt Server Suite: * fix for Bug 467767: double render error for add user * fix for Bug 466719: The virtual machine pool table is disabled after clicking sort by "Load" column * fix for bug 464282: can't remove user * fix how taskomatic handles a Cobbler image record * API: add a call to list VMs for a user * fixed cpu speed value for hosts grid * add aggregation method to stats API courtesy Mark Wagner * NFS file creation/deletion in the taskomatic back-end * replace host-status with db-omatic - uses the qpid console to recieve events from libvirt-qpid on various nodes and update state in the database directly * fix for bug 467758: Pool quota edit link does not appear * add time range and data type selection to flexchart * refactored storage UI to allow for creating/deleting NFS volumes * test/fixture revamp - Redoing the test fixtures to take advantage of rails 2.1 'foxy fixtures'. * replaced flexigrid-based display for HW and smart pool storage with tree component * implement "poweroff" in the WUI * fixes / improvements to selenium interface tests * implement LVM scanning, creation, deletion, and VM use in the taskomatic * lvm storage volume HW pool admin tab * support for multiple package formats for the appliance packaging * split create-ovirt-appliance into several scripts - http://ovirt.org/page/Appliance_Installation * separate data disk for storing iSCSI and NFS for appliance * remove second network interface on the appliance - eth0 is bridged to ovirtbr0 and eth1 is removed, the host is the default gateway Instructions for configuring yum to point to the ovirt.org repository: http://www.ovirt.org/download.html Instructions for using the Appliance and Nodes: http://www.ovirt.org/install-instructions.html Please download and try it out. Let us know via the mailing list or IRC if you have any suggestions for enhancements or feedback on what we've implemented so far. Also, bugs can be filed on the oVirt project at links provided on: http://www.ovirt.org/contribute.html Thanks to everyone who contributed to oVirt for this release! From dpierce at redhat.com Tue Dec 23 13:01:17 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Tue, 23 Dec 2008 08:01:17 -0500 Subject: [Ovirt-devel] Re: [PATCH server] Changed how taskomatic handles a Cobbler image record. In-Reply-To: <1229539899-27003-1-git-send-email-dpierce@redhat.com> References: <1229539899-27003-1-git-send-email-dpierce@redhat.com> Message-ID: <20081223130117.GA4961@mcpierce-laptop.mcpierce.org> On Wed, Dec 17, 2008 at 01:51:39PM -0500, Darryl L. Pierce wrote: > It will now incrementally pull out the protocol, authentication details, > hostname or ip address, export path and filename for the image record. I spoke with Mike yesterday regarding this topic, and the conclusion is that we'll handle it as: [auth@]hostname:/[path to /]filename where "auth" is the optional (though currently unused) username and password, and the path is the absolute path, from that mount point, to the image record. There's a patch out for review with the Cobbler folks, and a matching patch for oVirt. -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From dpierce at redhat.com Tue Dec 23 13:12:11 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Tue, 23 Dec 2008 08:12:11 -0500 Subject: [Ovirt-devel] Re: [PATCH node] Moved functionality to o-process-config. In-Reply-To: <1229724703-21914-1-git-send-email-dpierce@redhat.com> References: <1229724703-21914-1-git-send-email-dpierce@redhat.com> Message-ID: <20081223131211.GA6612@mcpierce-laptop.mcpierce.org> On Fri, Dec 19, 2008 at 05:11:43PM -0500, Darryl L. Pierce wrote: > Code to copy the network configuration files to the config partition and > to restart the network service have been moved out of ovirt-early and > into ovirt-process-config. This will allow the script to be reuseable. Can I get some feedback or an ACK on this patch, please? -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From dpierce at redhat.com Tue Dec 23 14:18:42 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Tue, 23 Dec 2008 09:18:42 -0500 Subject: [Ovirt-devel] ovirt-early script, scan_for_swap method Message-ID: <20081223141842.GB6612@mcpierce-laptop.mcpierce.org> In writing up the boot description wiki page[1] I found a method in ovirt-early called scan_for_swap. But I can't find any reference to this script anywhere, nothing seems to be invoking it. Is this unused and should be removed? [1] http://ovirt.org/wiki/index.php?title=Node_Boot_Sequence -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From bkearney at redhat.com Tue Dec 23 16:59:20 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Tue, 23 Dec 2008 11:59:20 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Have the installer spit out to the appliance directory instead of modules. This allows user to call ace install ovirt Message-ID: <1230051560-17181-1-git-send-email-bkearney@redhat.com> --- ace-ovirt/modules/ovirt/ovirt-installer | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/ace-ovirt/modules/ovirt/ovirt-installer b/ace-ovirt/modules/ovirt/ovirt-installer index 902b916..b55b6d6 100755 --- a/ace-ovirt/modules/ovirt/ovirt-installer +++ b/ace-ovirt/modules/ovirt/ovirt-installer @@ -21,6 +21,7 @@ ## oVirt Installation Script require 'socket' +require 'fileutils' if File.exist?("/usr/sbin/sestatus") sestatus = `/usr/sbin/sestatus` @@ -31,7 +32,8 @@ exit end end -config_file = File.new("/usr/share/ace/modules/ovirt/ovirt-install.pp", "w") +FileUtils.mkdir_p("/usr/share/ace/appliances/ovirt") +config_file = File.new("/usr/share/ace/appliances/ovirt/ovirt.pp", "w") config_file.write "import 'ovirt'\n" config_file.write "import 'firewall'\n\n" config_file.write "firewall::setup{'setup': status => 'disabled'}\n\n" -- 1.6.0.4 From clalance at redhat.com Tue Dec 23 17:50:51 2008 From: clalance at redhat.com (Chris Lalancette) Date: Tue, 23 Dec 2008 18:50:51 +0100 Subject: [Ovirt-devel] [PATCH server] Taskomatic Refactoring and Qpidification Take 3 In-Reply-To: <1229725173-18065-1-git-send-email-imain@redhat.com> References: <1229725173-18065-1-git-send-email-imain@redhat.com> Message-ID: <495124FB.5070503@redhat.com> Ian Main wrote: > This update adds a few small bugfixes, removes LVM storage pool/volume > scanning and reindents to 2 spaces. I'm still reviewing the older (v2) patch, but...why did you remove the LVM storage pool/volume scanning? As far as I know it is still needed, unless we are using some other mechanism to achieve this now. I'll continue to review (slowly, over the break), and post review comments once I have them. Chris Lalancette From apevec at gmail.com Tue Dec 23 17:53:39 2008 From: apevec at gmail.com (Alan Pevec) Date: Tue, 23 Dec 2008 18:53:39 +0100 Subject: [Ovirt-devel] ovirt-early script, scan_for_swap method In-Reply-To: <20081223141842.GB6612@mcpierce-laptop.mcpierce.org> References: <20081223141842.GB6612@mcpierce-laptop.mcpierce.org> Message-ID: <2be7262f0812230953g43f84337sc03d9831e0597178@mail.gmail.com> On Tue, Dec 23, 2008 at 3:18 PM, Darryl L. Pierce wrote: > In writing up the boot description wiki page[1] I found a method in > ovirt-early called scan_for_swap. But I can't find any reference to > this script anywhere, nothing seems to be invoking it. Is this > unused and should be removed? > > [1] http://ovirt.org/wiki/index.php?title=Node_Boot_Sequence I moved swap scanning into a function recently and wanted to discuss whether we want to do such scanning or use only swap area created by ovirt-config-storage on /dev/HostVG/Swap Chris, since you originally wrote that swap scanning, what do you think - should we keep adding all swap areas in sight? I think this could be problematic as we add clustered storage. From clalance at redhat.com Tue Dec 23 17:55:53 2008 From: clalance at redhat.com (Chris Lalancette) Date: Tue, 23 Dec 2008 18:55:53 +0100 Subject: [Ovirt-devel] LVM Fun In-Reply-To: <20081219145911.1d364c26@tp.mains.net> References: <20081219145911.1d364c26@tp.mains.net> Message-ID: <49512629.60102@redhat.com> Ian Main wrote: > OK, so in my refactoring of taskomatic, I've discovered just how crazy LVM > partitions are. > > Basically there is no way that I can see (and hopefully I'm wrong) of > determining what underlying hardware pool or volume is associated with an LVM > pool or volume. I think in the current taskomatic they attempt to figure > some of this out when doing a storage refresh, but it's actually not correct > and still relies on information from the database. > > Here's the code in taskomatic: > > logical_xml = conn.discover_storage_pool_sources("logical") > > Document.new(logical_xml).elements.each('sources/source') do |source| vgname > = source.elements["name"].text > > begin source.elements.each("device") do |device| byid_device = > phys_libvirt_pool.lookup_vol_by_path(device.attributes["path"]).path end > rescue # If matching any of the sections in the LVM XML fails # > against the storage pool, then it is likely that this is a storage # pool not > associated with the one we connected above. Go on # FIXME: it would be nicer > to catch the right exception here, and # fail on other exceptions puts "One > of the logical volumes in #{vgname} is not part of the pool of type > #{phys_db_pool[:type]} that we are scanning; ignore the previous error!" next > end > > So first we get a list of pools which are of the "logical"/LVM type, then > iterate through them and use lookup_vol_by_path using the physical hardware > pool as the pool to look in for the LVM volume. However that is not > correct.. the ruby API makes it look like you are only searching in that one > pool when in fact lookup_vol_by_path uses the main connection pointer and is > a global search across all storage pools. > > Code from libvirt-ruby: > > /* * Call > +virStorageVolLookupByPath+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolLookupByPath] > */ VALUE libvirt_pool_lookup_vol_by_path(VALUE p, VALUE path) { > virStorageVolPtr vol; > > // FIXME: Why does this take a connection, not a pool ? vol = > virStorageVolLookupByPath(conn(p), StringValueCStr(path)); _E(vol == NULL, > create_error(e_RetrieveError, "virStorageVolLookupByPath", "", conn(p))); > > return vol_new(vol, conn_attr(p)); } > > As you can see in the FIXME comment and the usage of > virStorageVolLookupByPath(), it's not associated with a specific pool. > > So this part of the code then doesn't actually prevent us from picking up LVM > volumes associated with other pools which may be active on this host (most > likely for VMs to use). Remember we're just picking some random host to do > our scan with. > > Then afterwords we put the entries in the database: > > source.elements.each("device") do |device| byid_device = > phys_libvirt_pool.lookup_vol_by_path(device.attributes["path"]).path > physical_vol = StorageVolume.find(:first, :conditions => [ "path = ?", > byid_device]) if physical_vol == nil # Hm. We didn't find the device in the > storage volumes already. # something went wrong internally, and we have to > bail raise "Storage internal physical volume error" end > > # OK, put the right lvm_pool_id in place physical_vol.lvm_pool_id = > lvm_db_pool.id physical_vol.save! end > > If I read this right it means that if we don't have the LVM volume in the > database already we're lost as to what physical volume it belongs. And again > we're using lookup_vol_by_path() to determine its in the pool. > > Anyway, all this basically means we have no way to track LVM volumes from > libvirt and if we intend to keep using them we're just going to have to rely > on the database to keep track of their setup. We could still check > allocations etc. but we shouldn't be attempting to fill in the database with > LVM information from a scan/refresh of the storage volume. > > Make sense? Am I missing something? (sorry, I didn't see this until after I posted my other message). The short of it is that we *have* to scan LVM during refresh time, otherwise we will not be able to import iSCSI LUNs that already have LVM on them. So we have to make it work one way or another, we can't just rip it out. I'm not actually sure what you mean by the above; the whole point of the LVM scanning is to find LVM volumes out on the /dev devices so we can *add* them to the database as new LVM volumes. Also, we aren't picking some random host; we are picking a host that is in this hardware pool. I'm don't really follow your objection; what's the exact problem you are running into that causes you to question all of this? Chris Lalancette From jboggs at redhat.com Tue Dec 23 18:58:14 2008 From: jboggs at redhat.com (Joey Boggs) Date: Tue, 23 Dec 2008 13:58:14 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Have the installer spit out to the appliance directory instead of modules. This allows user to call ace install ovirt In-Reply-To: <1230051560-17181-1-git-send-email-bkearney@redhat.com> References: <1230051560-17181-1-git-send-email-bkearney@redhat.com> Message-ID: <495134C6.5000102@redhat.com> ack, applied Bryan Kearney wrote: > --- > ace-ovirt/modules/ovirt/ovirt-installer | 4 +++- > 1 files changed, 3 insertions(+), 1 deletions(-) > > diff --git a/ace-ovirt/modules/ovirt/ovirt-installer b/ace-ovirt/modules/ovirt/ovirt-installer > index 902b916..b55b6d6 100755 > --- a/ace-ovirt/modules/ovirt/ovirt-installer > +++ b/ace-ovirt/modules/ovirt/ovirt-installer > @@ -21,6 +21,7 @@ > ## oVirt Installation Script > > require 'socket' > +require 'fileutils' > > if File.exist?("/usr/sbin/sestatus") > sestatus = `/usr/sbin/sestatus` > @@ -31,7 +32,8 @@ exit > end > end > > -config_file = File.new("/usr/share/ace/modules/ovirt/ovirt-install.pp", "w") > +FileUtils.mkdir_p("/usr/share/ace/appliances/ovirt") > +config_file = File.new("/usr/share/ace/appliances/ovirt/ovirt.pp", "w") > config_file.write "import 'ovirt'\n" > config_file.write "import 'firewall'\n\n" > config_file.write "firewall::setup{'setup': status => 'disabled'}\n\n" > From bkearney at redhat.com Tue Dec 23 19:40:46 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Tue, 23 Dec 2008 14:40:46 -0500 Subject: [Ovirt-devel] Merge the puppet installs Message-ID: <49513EBE.8010107@redhat.com> I spoke with Perry about this, and we wanted to get a quick take from everyone else. The puppet installer which Joey has been writing [1] can handle several various cases of installes (embedded cobbler or not, embedded dhcp or not, etc). The current appliance is driven by a similar puppet script and is just one variation. Currently the ovirt-appliance recipe is in a seperate git repo (ovirt-recipe) We think it makes sense to merge the work Joey did into the ovit-server git repo. Since the installer brings in alot of stuff with it, it could be a subpack of the main server (ovirt-server-install) so folks could still install ovirt-server w/o the baggage. We could then modify the appliance building to use this new sub-package and deprecate the ovirt-recipe git repo. Benefits to this are: * Installer and product versioned together. * Less git repos * Only one puppet recipe is maintained for bare metal and appliance. * Better testing on said recipe Drawbacks * Makes a big spec file a bit bigger * More coarse grained git repos Any concerns or alternatives to this? Thanks! -- bk [1] http://github.com/jboggs/ace-ovirt/tree/master From bkearney at redhat.com Tue Dec 23 20:15:16 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Tue, 23 Dec 2008 15:15:16 -0500 Subject: [Ovirt-devel] [PATCH PuppetInstaller] Add re-usable yes/no logic to the install script. Improve Indentation Message-ID: <1230063316-24368-1-git-send-email-bkearney@redhat.com> --- ace-ovirt/modules/ovirt/ovirt-installer | 258 +++++++++++++++---------------- 1 files changed, 124 insertions(+), 134 deletions(-) diff --git a/ace-ovirt/modules/ovirt/ovirt-installer b/ace-ovirt/modules/ovirt/ovirt-installer index b55b6d6..cc89cf8 100755 --- a/ace-ovirt/modules/ovirt/ovirt-installer +++ b/ace-ovirt/modules/ovirt/ovirt-installer @@ -23,13 +23,28 @@ require 'socket' require 'fileutils' -if File.exist?("/usr/sbin/sestatus") -sestatus = `/usr/sbin/sestatus` -if sestatus !~ /(Current mode: permissive|Current mode: disabled|SELinux status: disabled|SELinux status: permissive)/ -puts "SELinux enabled, please disable or set in permissive mode permanently by editing" -puts "/etc/selinux/config and rebooting" -exit + +# Allow a user to enter a Yes/No +# And repeat the prompt until they do +def prompt_yes_no(prompt) + puts("\n#{prompt} (y/n)") + answer = gets.chomp().downcase() + while answer != "y" and answer != "n" + puts("Invalid choice") + puts("\n#{prompt} (y/n)") + answer = gets.chomp + end + + return answer end + +if File.exist?("/usr/sbin/sestatus") + sestatus = `/usr/sbin/sestatus` + if sestatus !~ /(Current mode: permissive|Current mode: disabled|SELinux status: disabled|SELinux status: permissive)/ + puts "SELinux enabled, please disable or set in permissive mode permanently by editing" + puts "/etc/selinux/config and rebooting" + exit + end end FileUtils.mkdir_p("/usr/share/ace/appliances/ovirt") @@ -43,82 +58,70 @@ prov_dev = "" dev_ct = 0 net_devs = `hal-find-by-capability --capability net` -net_devs.each_line{ |dev| -dev_ct = dev_ct + 1 -} +net_devs.each_line do |dev| + dev_ct = dev_ct + 1 +end if dev_ct == 0 -puts "Unable to install without a network interface" -exit - + puts "Unable to install without a network interface" + exit else -puts "" -get_net_devs = `hal-find-by-capability --capability net` -puts "Below are the detected networking devices\n\n" -puts "mac address interface ip address" -net_devs.each_line{ |dev| -dev = dev.chomp -interface = `hal-get-property --udi #{dev} --key net.interface` -mac = `hal-get-property --udi #{dev} --key net.address` -ip = `ifconfig #{interface}` -ipaddr = ip.scan(/\s*inet addr:([\d.]+)/) -puts mac.chop + " : " + interface.chop + " : " + ipaddr.to_s if interface.chop != "lo" -} + puts "" + get_net_devs = `hal-find-by-capability --capability net` + puts "Below are the detected networking devices\n\n" + puts "mac address interface ip address" + net_devs.each_line do|dev| + dev = dev.chomp + interface = `hal-get-property --udi #{dev} --key net.interface` + mac = `hal-get-property --udi #{dev} --key net.address` + ip = `ifconfig #{interface}` + ipaddr = ip.scan(/\s*inet addr:([\d.]+)/) + puts mac.chop + " : " + interface.chop + " : " + ipaddr.to_s if interface.chop != "lo" + end end if dev_ct > 1 -puts "\nDo you want separate management and provisioning networks? (y/n)" -sep_networks = gets.chomp -while sep_networks != "y" and sep_networks != "n" -puts "Invalid choice" -puts "Do you want separate management and provisioning networks? (y/n)" -sep_networks = gets.chomp -end - -if sep_networks == "y" -while mgmt_dev == "" -puts "Input your management interface (example: eth0)" -mgmt_dev = gets.chomp -end - -while prov_dev == "" -puts "Input your provisioning interface, this may also be your management interface (example: eth1)" -prov_dev = gets.chomp -end - -elsif sep_networks == "n" -while mgmt_dev == "" -puts "Input your management/provisioning interface (example: eth1)" -mgmt_dev = gets.chomp -prov_dev = mgmt_dev -end -end - + sep_networks = prompt_yes_no("Do you want separate management and provisioning networks?") + + if sep_networks == "y" + while mgmt_dev == "" + puts "Input your management interface (example: eth0)" + mgmt_dev = gets.chomp + end + + while prov_dev == "" + puts "Input your provisioning interface, this may also be your management interface (example: eth1)" + prov_dev = gets.chomp + end + + elsif sep_networks == "n" + while mgmt_dev == "" + puts "Input your management/provisioning interface (example: eth1)" + mgmt_dev = gets.chomp + prov_dev = mgmt_dev + end + end elsif dev_ct == 1 -while mgmt_dev == "" -puts "\nOnly one networking device detected" -puts "Input your management/provisioning interface (example: eth1)" -mgmt_dev = gets.chomp -prov_dev = mgmt_dev -puts "Need Management interface" -end + while mgmt_dev == "" + puts "\nOnly one networking device detected" + puts "Input your management/provisioning interface (example: eth1)" + mgmt_dev = gets.chomp + prov_dev = mgmt_dev + puts "Need Management interface" + end end puts "Enter the hostname of the oVirt management server (example: management.example.com)" ovirt_host = gets.chomp ipa_host = ovirt_host -puts "\nUse this system's dns servers (y/n)" -File.open('/etc/resolv.conf').each_line{ |line| - line = line.chomp -puts line if line =~ /nameserver/ and line !~ /nameserver 127.0.0.1/ -} -dns_servers = gets.chomp - -while dns_servers != "y" and dns_servers != "n" -puts "Invalid choice" -dns_servers = gets.chomp +prompt = "\nUse this system's dns servers?" +File.open('/etc/resolv.conf').each_line do |line| + line = line.chomp + prompt << "\n #{line}" if line =~ /nameserver/ and line !~ /nameserver 127.0.0.1/ end +prompt << "\nPlease Enter" +dns_servers = prompt_yes_no(prompt) mgmt_ip = `ifconfig #{mgmt_dev}` mgmt_ipaddr= mgmt_ip.scan(/\s*inet addr:([\d.]+)/) @@ -132,91 +135,78 @@ config_file.write "$ovirt_host = '#{ovirt_host}'\n" config_file.write "$ipa_host = '#{ipa_host}'\n\n" if dns_servers == "n" -config_file.write "dns::bundled{setup: mgmt_ipaddr=> $mgmt_ipaddr, prov_ipaddr=> $prov_ipaddr, mgmt_dev => '#{mgmt_dev}', prov_dev => '#{prov_dev}'}\n\n" + config_file.write "dns::bundled{setup: mgmt_ipaddr=> $mgmt_ipaddr, prov_ipaddr=> $prov_ipaddr, mgmt_dev => '#{mgmt_dev}', prov_dev => '#{prov_dev}'}\n\n" end if dns_servers == "y" -config_file.write "dns::remote{setup: mgmt_ipaddr=> $mgmt_ipaddr, prov_ipaddr=> $prov_ipaddr, mgmt_dev => '#{mgmt_dev}', prov_dev => '#{prov_dev}'}\n\n" -host_lookup = Socket.getaddrinfo(ipa_host,nil) -hostip = host_lookup[1][3] -if hostip.to_s != mgmt_ipaddr.to_s -puts "Reverse dns lookup for #{ipa_host} failed, exiting" -exit -end + config_file.write "dns::remote{setup: mgmt_ipaddr=> $mgmt_ipaddr, prov_ipaddr=> $prov_ipaddr, mgmt_dev => '#{mgmt_dev}', prov_dev => '#{prov_dev}'}\n\n" + host_lookup = Socket.getaddrinfo(ipa_host,nil) + hostip = host_lookup[1][3] + if hostip.to_s != mgmt_ipaddr.to_s + puts "Reverse dns lookup for #{ipa_host} failed, exiting" + exit + end end -puts "Does you provisioning network already have dhcp? (y/n)" -dhcp_setup = gets.chomp -while dhcp_setup != "y" and dhcp_setup != "n" -puts "Invalid choice" -dhcp_setup = gets.chomp -end +dhcp_setup = prompt_yes_no("Does you provisioning network already have dhcp?") if dhcp_setup == "n" -puts "DHCP Configuration\n" -config_file.write "# dhcp configuration\n" -dhcp_interface = prov_dev -config_file.write "$dhcp_interface = '#{dhcp_interface}'\n" + puts "DHCP Configuration\n" + config_file.write "# dhcp configuration\n" + dhcp_interface = prov_dev + config_file.write "$dhcp_interface = '#{dhcp_interface}'\n" -puts "Enter the first 3 octets of the dhcp network you wish to use (example: 192.168.50)" -dhcp_network = gets.chomp -config_file.write "$dhcp_network = '#{dhcp_network}'\n" + puts "Enter the first 3 octets of the dhcp network you wish to use (example: 192.168.50)" + dhcp_network = gets.chomp + config_file.write "$dhcp_network = '#{dhcp_network}'\n" -puts "Enter the dhcp pool start address (example: 3)" -dhcp_start = gets.chomp -config_file.write "$dhcp_start = '#{dhcp_start}'\n" + puts "Enter the dhcp pool start address (example: 3)" + dhcp_start = gets.chomp + config_file.write "$dhcp_start = '#{dhcp_start}'\n" -puts "Enter the dhcp pool end addess (example: 100)" -dhcp_stop = gets.chomp -config_file.write "$dhcp_stop = '#{dhcp_stop}'\n" + puts "Enter the dhcp pool end addess (example: 100)" + dhcp_stop = gets.chomp + config_file.write "$dhcp_stop = '#{dhcp_stop}'\n" -puts "Enter the dhcp domain you wish to use (example: example.com)" -dhcp_domain = gets.chomp -config_file.write "$dhcp_domain = '#{dhcp_domain}'\n" + puts "Enter the dhcp domain you wish to use (example: example.com)" + dhcp_domain = gets.chomp + config_file.write "$dhcp_domain = '#{dhcp_domain}'\n" -config_file.write "$ntp_server = '#{mgmt_ipaddr}'\n\n" + config_file.write "$ntp_server = '#{mgmt_ipaddr}'\n\n" -puts "Provide pxe/tftp capability? (y/n)" -tftp_setup = gets.chomp + tftp_setup = prompt_yes_no("Provide pxe/tftp capability? ") -if sep_networks == "y" -prov_ip = `ifconfig #{prov_dev}` -prov_dns_server = prov_ip.scan(/\s*inet addr:([\d.]+)/) -config_file.write "$prov_dns_server = '#{prov_dns_server}'\n" + if sep_networks == "y" + prov_ip = `ifconfig #{prov_dev}` + prov_dns_server = prov_ip.scan(/\s*inet addr:([\d.]+)/) + config_file.write "$prov_dns_server = '#{prov_dns_server}'\n" -puts "Enter the network gateway for your provisioning network (example: 192.168.50.254)" -prov_network_gateway = gets.chomp -config_file.write "$prov_network_gateway = '#{prov_network_gateway}'\n" -end + puts "Enter the network gateway for your provisioning network (example: 192.168.50.254)" + prov_network_gateway = gets.chomp + config_file.write "$prov_network_gateway = '#{prov_network_gateway}'\n" + end end # Cobbler Configuration -puts "Do you have a cobbler already that you wish to use? (y/n)" -cobbler_setup = gets.chomp - -while cobbler_setup != "y" and cobbler_setup != "n" -puts "Invalid choice" -cobbler_setup = gets.chomp -end - +cobbler_setup = prompt_yes_no("Do you have a cobbler already that you wish to use? ") cobbler_config = "n" if cobbler_setup == "y" -puts "Enter the hostname of your cobbler server" -cobbler_hostname = gets.chomp -puts "Enter your cobbler username" -cobbler_user_name= gets.chomp -puts "Enter your cobbler user password" -cobbler_user_password = gets.chomp + puts "Enter the hostname of your cobbler server" + cobbler_hostname = gets.chomp + puts "Enter your cobbler username" + cobbler_user_name= gets.chomp + puts "Enter your cobbler user password" + cobbler_user_password = gets.chomp elsif cobbler_setup == "n" -cobbler_hostname = "localhost" -puts "We will setup a cobbler instance, please provide the following information" -puts "Enter your cobbler username" -cobbler_user_name= gets.chomp -puts "Enter your cobbler user password" -cobbler_user_password = gets.chomp + cobbler_hostname = "localhost" + puts "We will setup a cobbler instance, please provide the following information" + puts "Enter your cobbler username" + cobbler_user_name= gets.chomp + puts "Enter your cobbler user password" + cobbler_user_password = gets.chomp end config_file.write "# cobbler configuration\n" @@ -244,24 +234,24 @@ config_file.write "$freeipa_password = '#{freeipa_password}'\n" ldap_dn = "cn=ipaConfig,cn=etc," ldap_dn_temp = realm_name.split(".") ldap_dn_temp.each do |i| -ldap_dn += "dc=#{i}," + ldap_dn += "dc=#{i}," end ldap_dn = ldap_dn.chop config_file.write "$ldap_dn = '#{ldap_dn}'\n\n" if cobbler_setup == "y" -config_file.write "include cobbler::remote\n" + config_file.write "include cobbler::remote\n" elsif cobbler_setup == "n" -config_file.write "include cobbler::bundled\n" + config_file.write "include cobbler::bundled\n" end if dhcp_setup == "n" -config_file.write "include dhcp::bundled\n" + config_file.write "include dhcp::bundled\n" end if tftp_setup == "y" -config_file.write "include tftp::bundled\n" + config_file.write "include tftp::bundled\n" end config_file.write "include postgres::bundled\n" -- 1.6.0.4 From dpierce at redhat.com Tue Dec 23 20:30:27 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Tue, 23 Dec 2008 15:30:27 -0500 Subject: [Ovirt-devel] Documenting the node boot process... Message-ID: <20081223203027.GF6612@mcpierce-laptop.mcpierce.org> I've written up a preliminary wiki page documenting the node boot process, identifying key points. I'd appreciate feedback from every, especially Alan. http://ovirt.org/page/Node_Boot_Sequence -- Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc. Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From imain at redhat.com Tue Dec 23 21:13:27 2008 From: imain at redhat.com (Ian Main) Date: Tue, 23 Dec 2008 13:13:27 -0800 Subject: [Ovirt-devel] LVM Fun In-Reply-To: <49512629.60102@redhat.com> References: <20081219145911.1d364c26@tp.mains.net> <49512629.60102@redhat.com> Message-ID: <20081223131327.5d1c675f@tp.mains.net> On Tue, 23 Dec 2008 18:55:53 +0100 Chris Lalancette wrote: > Ian Main wrote: > > OK, so in my refactoring of taskomatic, I've discovered just how crazy LVM > > partitions are. > > > > Basically there is no way that I can see (and hopefully I'm wrong) of > > determining what underlying hardware pool or volume is associated with an LVM > > pool or volume. I think in the current taskomatic they attempt to figure > > some of this out when doing a storage refresh, but it's actually not correct > > and still relies on information from the database. > > > > Here's the code in taskomatic: > > > > logical_xml = conn.discover_storage_pool_sources("logical") > > > > Document.new(logical_xml).elements.each('sources/source') do |source| vgname > > = source.elements["name"].text > > > > begin source.elements.each("device") do |device| byid_device = > > phys_libvirt_pool.lookup_vol_by_path(device.attributes["path"]).path end > > rescue # If matching any of the sections in the LVM XML fails # > > against the storage pool, then it is likely that this is a storage # pool not > > associated with the one we connected above. Go on # FIXME: it would be nicer > > to catch the right exception here, and # fail on other exceptions puts "One > > of the logical volumes in #{vgname} is not part of the pool of type > > #{phys_db_pool[:type]} that we are scanning; ignore the previous error!" next > > end > > > > So first we get a list of pools which are of the "logical"/LVM type, then > > iterate through them and use lookup_vol_by_path using the physical hardware > > pool as the pool to look in for the LVM volume. However that is not > > correct.. the ruby API makes it look like you are only searching in that one > > pool when in fact lookup_vol_by_path uses the main connection pointer and is > > a global search across all storage pools. > > > > Code from libvirt-ruby: > > > > /* * Call > > +virStorageVolLookupByPath+[http://www.libvirt.org/html/libvirt-libvirt.html#virStorageVolLookupByPath] > > */ VALUE libvirt_pool_lookup_vol_by_path(VALUE p, VALUE path) { > > virStorageVolPtr vol; > > > > // FIXME: Why does this take a connection, not a pool ? vol = > > virStorageVolLookupByPath(conn(p), StringValueCStr(path)); _E(vol == NULL, > > create_error(e_RetrieveError, "virStorageVolLookupByPath", "", conn(p))); > > > > return vol_new(vol, conn_attr(p)); } > > > > As you can see in the FIXME comment and the usage of > > virStorageVolLookupByPath(), it's not associated with a specific pool. > > > > So this part of the code then doesn't actually prevent us from picking up LVM > > volumes associated with other pools which may be active on this host (most > > likely for VMs to use). Remember we're just picking some random host to do > > our scan with. > > > > Then afterwords we put the entries in the database: > > > > source.elements.each("device") do |device| byid_device = > > phys_libvirt_pool.lookup_vol_by_path(device.attributes["path"]).path > > physical_vol = StorageVolume.find(:first, :conditions => [ "path = ?", > > byid_device]) if physical_vol == nil # Hm. We didn't find the device in the > > storage volumes already. # something went wrong internally, and we have to > > bail raise "Storage internal physical volume error" end > > > > # OK, put the right lvm_pool_id in place physical_vol.lvm_pool_id = > > lvm_db_pool.id physical_vol.save! end > > > > If I read this right it means that if we don't have the LVM volume in the > > database already we're lost as to what physical volume it belongs. And again > > we're using lookup_vol_by_path() to determine its in the pool. > > > > Anyway, all this basically means we have no way to track LVM volumes from > > libvirt and if we intend to keep using them we're just going to have to rely > > on the database to keep track of their setup. We could still check > > allocations etc. but we shouldn't be attempting to fill in the database with > > LVM information from a scan/refresh of the storage volume. > > > > Make sense? Am I missing something? > > (sorry, I didn't see this until after I posted my other message). The short of > it is that we *have* to scan LVM during refresh time, otherwise we will not be > able to import iSCSI LUNs that already have LVM on them. So we have to make it > work one way or another, we can't just rip it out. I'm not actually sure what > you mean by the above; the whole point of the LVM scanning is to find LVM > volumes out on the /dev devices so we can *add* them to the database as new LVM > volumes. Also, we aren't picking some random host; we are picking a host that > is in this hardware pool. I'm don't really follow your objection; what's the > exact problem you are running into that causes you to question all of this? > > Chris Lalancette Hehe. :) Well we can still find all the LVM pools, it's just that we can't tell what real storage pool backs them. In the database we make a hierarchy where LVM pools are created inside physical pools/volumes. Through libvirt alone we have no way of determining this parent/child relationship, which is what I'm trying to say above. This in turn opens up the possibility that another storage pool may be active on the host we select to do the scanning, which would mean we'd pick up LVM volumes from that other pool as well. From what I can tell, right now the only way to fill the LVM volume/pool information in the DB correctly is by keeping track of it during creation which defeats the purpose of the scan/refresh. Hence the removal. If I missed something (which is possible), let me know, but from what I can tell this is the case. While I've done some playing with the API and have shown myself that this is the case, it might be worth setting up a test case with two pools with LVM volumes in each and see if it sorts them out right. Ian From imain at redhat.com Wed Dec 24 06:38:00 2008 From: imain at redhat.com (Ian Main) Date: Tue, 23 Dec 2008 22:38:00 -0800 Subject: [Ovirt-devel] [PATCH server] ovirt-db-omatic requires ruby-qpid to run In-Reply-To: <1229962538-6347-1-git-send-email-bkearney@redhat.com> References: <1229962538-6347-1-git-send-email-bkearney@redhat.com> Message-ID: <20081223223800.4b92f15c@tp.mains.net> On Mon, 22 Dec 2008 11:15:38 -0500 Bryan Kearney wrote: > --- > ovirt-server.spec.in | 1 + > 1 files changed, 1 insertions(+), 0 deletions(-) > > diff --git a/ovirt-server.spec.in b/ovirt-server.spec.in > index 79a5adf..c30306b 100644 > --- a/ovirt-server.spec.in > +++ b/ovirt-server.spec.in > @@ -23,6 +23,7 @@ Requires: rubygem(gettext) > Requires: ruby-flexmock > Requires: postgresql-server > Requires: ruby-postgres > +Requires: ruby-qpid > Requires: xapian-bindings-ruby > Requires: xapian-core > Requires: pwgen Hmm, you have to be careful here. There are actually two packages available right now. rubygem-qpid, and ruby-qpid. rubygem-qpid is what David and I released initially, and what I have been working with until the MRG team released ruby-qpid. They did that in the last week or two but I have not tested db-omatic nor taskomatic with this package yet. Well, in fact I know that the previously released ruby-qpid will not work with taskomatic as there were still outstanding bugs plus API changes in that release.. it may work with db-omatic, I'm not sure. They did however just do another release which may address these changes, but I haven't looked at it yet. Basically I've been making patches to the rubygem-qpid git repo that we started and have been submitting patches upstream but I'm not sure that they are all merged yet. rubygem-qpid is available in the ovirt repo for f10 and development. Ian From apevec at gmail.com Wed Dec 24 08:55:40 2008 From: apevec at gmail.com (Alan Pevec) Date: Wed, 24 Dec 2008 09:55:40 +0100 Subject: [Ovirt-devel] Merge the puppet installs In-Reply-To: <49513EBE.8010107@redhat.com> References: <49513EBE.8010107@redhat.com> Message-ID: <2be7262f0812240055m748d6fpaa5c0e820f8ee018@mail.gmail.com> On Tue, Dec 23, 2008 at 8:40 PM, Bryan Kearney wrote: > I spoke with Perry about this, and we wanted to get a quick take from > everyone else. The puppet installer which Joey has been writing [1] can > handle several various cases of installes (embedded cobbler or not, embedded > dhcp or not, etc). The current appliance is driven by a similar puppet > script and is just one variation. Currently the ovirt-appliance recipe is in > a seperate git repo (ovirt-recipe) > > We think it makes sense to merge the work Joey did into the ovit-server git > repo. Since the installer brings in alot of stuff with it, it could be a > subpack of the main server (ovirt-server-install) so folks could still > install ovirt-server w/o the baggage. We could then modify the appliance > building to use this new sub-package and deprecate the ovirt-recipe git > repo. > > Benefits to this are: > * Installer and product versioned together. > * Less git repos > * Only one puppet recipe is maintained for bare metal and appliance. > * Better testing on said recipe > > Drawbacks > * Makes a big spec file a bit bigger > * More coarse grained git repos +1 Drawbacks are not really problematic, while benefits are really useful. ovirt-recipe is not really independent, as you said it is really just one deployment possibility for ovirt-server, so it makes sense to bind them together. From apevec at gmail.com Wed Dec 24 12:13:14 2008 From: apevec at gmail.com (Alan Pevec) Date: Wed, 24 Dec 2008 13:13:14 +0100 Subject: [Ovirt-devel] running 0.96 i386 appliance on x86_64 host Message-ID: <2be7262f0812240413m3d5d2179q19152e73fb0df75f@mail.gmail.com> Just noted one issue when running i386 appliance on x86_64 host: virt-image descriptor, ovirt-appliance.xml generated by appliance-creator sets domain/boot/arch to i686 which makes create-ovirt-appliance fail with ImageInstallerException: Could not find suitable boot descriptor for this host Workaround is to change in /var/lib/libvirt/images/ovirt-appliance/ovirt-appliance.xml i686 to x86_64 and rerun create-ovirt-appliance From bkearney at redhat.com Wed Dec 24 13:04:07 2008 From: bkearney at redhat.com (Bryan Kearney) Date: Wed, 24 Dec 2008 08:04:07 -0500 Subject: [Ovirt-devel] Merge the puppet installs In-Reply-To: <2be7262f0812240055m748d6fpaa5c0e820f8ee018@mail.gmail.com> References: <49513EBE.8010107@redhat.com> <2be7262f0812240055m748d6fpaa5c0e820f8ee018@mail.gmail.com> Message-ID: <49523347.9050106@redhat.com> Alan Pevec wrote: > On Tue, Dec 23, 2008 at 8:40 PM, Bryan Kearney wrote: >> I spoke with Perry about this, and we wanted to get a quick take from >> everyone else. The puppet installer which Joey has been writing [1] can >> handle several various cases of installes (embedded cobbler or not, embedded >> dhcp or not, etc). The current appliance is driven by a similar puppet >> script and is just one variation. Currently the ovirt-appliance recipe is in >> a seperate git repo (ovirt-recipe) >> >> We think it makes sense to merge the work Joey did into the ovit-server git >> repo. Since the installer brings in alot of stuff with it, it could be a >> subpack of the main server (ovirt-server-install) so folks could still >> install ovirt-server w/o the baggage. We could then modify the appliance >> building to use this new sub-package and deprecate the ovirt-recipe git >> repo. >> >> Benefits to this are: >> * Installer and product versioned together. >> * Less git repos >> * Only one puppet recipe is maintained for bare metal and appliance. >> * Better testing on said recipe >> >> Drawbacks >> * Makes a big spec file a bit bigger >> * More coarse grained git repos > > +1 > > Drawbacks are not really problematic, while benefits are really useful. > ovirt-recipe is not really independent, as you said it is really just > one deployment possibility for ovirt-server, so it makes sense to bind > them together. Barring any issues from other folks... We will work on this first part of January. -- bk From pmyers at redhat.com Wed Dec 24 13:21:41 2008 From: pmyers at redhat.com (Perry Myers) Date: Wed, 24 Dec 2008 08:21:41 -0500 Subject: [Ovirt-devel] running 0.96 i386 appliance on x86_64 host In-Reply-To: <2be7262f0812240413m3d5d2179q19152e73fb0df75f@mail.gmail.com> References: <2be7262f0812240413m3d5d2179q19152e73fb0df75f@mail.gmail.com> Message-ID: <49523765.6020804@redhat.com> Alan Pevec wrote: > Just noted one issue when running i386 appliance on x86_64 host: > virt-image descriptor, ovirt-appliance.xml generated by > appliance-creator sets domain/boot/arch to i686 which makes > create-ovirt-appliance fail with ImageInstallerException: Could not > find suitable boot descriptor for this host > > Workaround is to change in > /var/lib/libvirt/images/ovirt-appliance/ovirt-appliance.xml > i686 to x86_64 > and rerun create-ovirt-appliance Or just run x86_64 appliance on x86_64 host... If you follow the instructions on the web site you'll get the right arch appliance image for your host since the get-ovirt-appliance script uses uname -i to determine which appliance image to download. The only way you'd get i386 appliance running on x86_64 host would be if you tricked get-ovirt-appliance script by running: setarch i386 get-ovirt-appliance And that's just sneaky :) Perry From apevec at redhat.com Wed Dec 24 22:59:58 2008 From: apevec at redhat.com (Alan Pevec) Date: Wed, 24 Dec 2008 23:59:58 +0100 Subject: [Ovirt-devel] [PATCH node] make ovirt-config-setup menu configurable Message-ID: <1230159599-4277-1-git-send-email-apevec@redhat.com> custom menu option can be added using a symlink in /etc/ovirt-config-setup.d/ pointing to the script to be executed implement default options using this method --- ovirt-node.spec.in | 10 ++++++++++ scripts/ovirt-config-setup | 25 +++++++++++-------------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in index d7424c1..f529f60 100644 --- a/ovirt-node.spec.in +++ b/ovirt-node.spec.in @@ -121,6 +121,7 @@ cd - %install %{__rm} -rf %{buildroot} +# FIXME move installs into makefile %{__install} -d -m0755 %{buildroot}%{_sbindir} %{__install} -d -m0755 %{buildroot}%{_sysconfdir} %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/chkconfig.d @@ -182,6 +183,14 @@ mkdir -p %{buildroot}/usr/lib/anaconda-runtime install -p -m 644 images/syslinux-vesa-splash.jpg %{buildroot}/usr/lib/anaconda-runtime # ovirt-logos +# default ovirt-config-setup menu options +%{__install} -d -m0755 %{buildroot}%{_sysconfdir}/ovirt-config-setup.d +%{__ln_s} ../..%{_sbindir}/ovirt-config-networking %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Networking Setup" +%{__ln_s} ../..%{_sbindir}/ovirt-config-storage %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Disk Partitioning" +%{__ln_s} ../..%{_sbindir}/ovirt-config-logging %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Logging Setup" +%{__ln_s} ../..%{_sbindir}/ovirt-config-password %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Administrator Password" + + %clean %{__rm} -rf %{buildroot} @@ -256,6 +265,7 @@ fi %{_initrddir}/ovirt-post %config %{_sysconfdir}/logrotate.d/ovirt-logrotate.conf %config %{_sysconfdir}/cron.hourly/ovirt-logrotate +%{_sysconfdir}/ovirt-config-setup.d %files stateful %defattr(-,root,root,0755) diff --git a/scripts/ovirt-config-setup b/scripts/ovirt-config-setup index 20dd5ae..9f97afc 100755 --- a/scripts/ovirt-config-setup +++ b/scripts/ovirt-config-setup @@ -2,21 +2,23 @@ # # Entry point for configuring an oVirt node when running in standalone mode. -NETWORK="Networking Setup" -STORAGE="Disk Partitioning" -LOGGING="Logging Setup" -PASSWORD="Administrator Password" +# symlinked scripts for menu options, link name is menu label +CONFIG_DIR=/etc/ovirt-config-setup.d + +# special options, all others execute the symlinked script in CONFIG_DIR DEBUG_SHELL="Shell" CONTINUE="Continue" declare -a OPTIONS -OPTIONS[${#OPTIONS[*]}]="$NETWORK" -OPTIONS[${#OPTIONS[*]}]="$STORAGE" -OPTIONS[${#OPTIONS[*]}]="$LOGGING" -OPTIONS[${#OPTIONS[*]}]="$PASSWORD" +for cfg in $CONFIG_DIR/*; do + label=$(basename "$cfg") + OPTIONS[${#OPTIONS[*]}]="$label" +done OPTIONS[${#OPTIONS[*]}]="$CONTINUE" OPTIONS[${#OPTIONS[*]}]="$DEBUG_SHELL" + + # reset tty, otherwise serial console is broken reset > /dev/null clear @@ -29,14 +31,9 @@ while true; do select OPTION in "${OPTIONS[@]}" do case "$OPTION" in - "$NETWORK") ovirt-config-networking ; break ;; - "$STORAGE") - ovirt-config-storage ; - break ;; - "$LOGGING") ovirt-config-logging ; break ;; - "$PASSWORD") ovirt-config-password ; break ;; "$DEBUG_SHELL") bash ; break ;; "$CONTINUE") exit 0 ;; + *) $CONFIG_DIR/"$OPTION" ;; esac printf "\n" -- 1.6.0.6 From apevec at redhat.com Wed Dec 24 22:59:59 2008 From: apevec at redhat.com (Alan Pevec) Date: Wed, 24 Dec 2008 23:59:59 +0100 Subject: [Ovirt-devel] [PATCH node] add "Local install and reboot" option In-Reply-To: <1230159599-4277-1-git-send-email-apevec@redhat.com> References: <1230159599-4277-1-git-send-email-apevec@redhat.com> Message-ID: <1230159599-4277-2-git-send-email-apevec@redhat.com> ovirt-config-boot can be called without parameters, as an option in ovirt-config-setup menu, defaults are taken from /etc/default/ovirt --- ovirt-node.spec.in | 1 + scripts/ovirt-config-boot | 35 +++++++++++++++++++++++++++-------- scripts/ovirt-config-storage | 1 + scripts/ovirt-early | 4 +--- scripts/ovirt-firstboot | 17 ++--------------- scripts/ovirt-functions | 11 +++++++++++ 6 files changed, 43 insertions(+), 26 deletions(-) diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in index f529f60..e5031ad 100644 --- a/ovirt-node.spec.in +++ b/ovirt-node.spec.in @@ -189,6 +189,7 @@ install -p -m 644 images/syslinux-vesa-splash.jpg %{buildroot}/usr/lib/anaconda- %{__ln_s} ../..%{_sbindir}/ovirt-config-storage %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Disk Partitioning" %{__ln_s} ../..%{_sbindir}/ovirt-config-logging %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Logging Setup" %{__ln_s} ../..%{_sbindir}/ovirt-config-password %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Administrator Password" +%{__ln_s} ../..%{_sbindir}/ovirt-config-boot %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"Local install and reboot" %clean diff --git a/scripts/ovirt-config-boot b/scripts/ovirt-config-boot index d7bd48a..8ddd46a 100755 --- a/scripts/ovirt-config-boot +++ b/scripts/ovirt-config-boot @@ -1,28 +1,28 @@ #!/bin/bash # -# ovirt-config-boot - configure local boot disk partition +# ovirt-config-boot - configure local boot/root disk partitions # SYNOPSIS -# ovirt-config-boot livecd_path bootparams +# ovirt-config-boot boot_disk livecd_path bootparams reboot # # boot_disk - boot disk device e.g. /dev/sda +# default is $OVIRT_INIT # # livecd_path - where livecd media is mounted, # parent of LiveOS and isolinux folders +# default is /live # # bootparams - extra boot parameters like console=... +# default is $OVIRT_BOOTPARAMS # +# reboot - reboot after install +# default is yes # Source functions library . /etc/init.d/functions . /etc/init.d/ovirt-functions -# local_boot_install livecd_path bootparams -# livecd_path -livecd media -# bootparams - extra boot parameters like console=... -# -# copy oVirt Node image to the local LVM /dev/HostVG ovirt_boot_setup() { local disk=$1 local live=$2 @@ -127,5 +127,24 @@ EOF } -ovirt_boot_setup "$1" "$2" "$3" +disk=$1 +live=$2 +bootparams=$3 +doreboot=$4 +if [ -z "$disk" ]; then + disk=$OVIRT_INIT +fi +if [ -z "$live" ]; then + mount_live + live=/live +fi +if [ -z "$bootparams" ]; then + bootparams="$OVIRT_BOOTPARAMS" +fi + +ovirt_boot_setup "$disk" "$live" "$bootparams" +if [ -z "$doreboot" -o "$doreboot" = "yes" ]; then + disable_firstbot + reboot +fi diff --git a/scripts/ovirt-config-storage b/scripts/ovirt-config-storage index ff2a3b2..1c31a58 100755 --- a/scripts/ovirt-config-storage +++ b/scripts/ovirt-config-storage @@ -114,6 +114,7 @@ do_configure() done # save input variables augtool < /dev/null +set /files$OVIRT_DEFAULTS/OVIRT_INIT $DRIVE set /files$OVIRT_DEFAULTS/OVIRT_VOL_BOOT_SIZE $BOOT_SIZE set /files$OVIRT_DEFAULTS/OVIRT_VOL_SWAP_SIZE $SWAP_SIZE set /files$OVIRT_DEFAULTS/OVIRT_VOL_ROOT_SIZE $ROOT_SIZE diff --git a/scripts/ovirt-early b/scripts/ovirt-early index ecdf52e..7ee2357 100755 --- a/scripts/ovirt-early +++ b/scripts/ovirt-early @@ -319,9 +319,7 @@ start() { $BONDING_MODCONF_FILE if [ $local_boot = 1 ]; then # local disk installation for managed mode - mount_live - ovirt-config-boot $init /live "$bootparams" - reboot + ovirt-config-boot $init "" "$bootparams" fi fi fi diff --git a/scripts/ovirt-firstboot b/scripts/ovirt-firstboot index da03b98..fe7723f 100755 --- a/scripts/ovirt-firstboot +++ b/scripts/ovirt-firstboot @@ -27,18 +27,6 @@ . /etc/init.d/functions . /etc/init.d/ovirt-functions -disable_firstboot () -{ - if mount_config; then - umount_config $OVIRT_DEFAULTS - augtool > /dev/null < /dev/null < how to increase RAM on running vm ? From pmyers at redhat.com Thu Dec 25 18:40:04 2008 From: pmyers at redhat.com (Perry Myers) Date: Thu, 25 Dec 2008 13:40:04 -0500 Subject: [Ovirt-devel] how to Increase memory for vm online ? In-Reply-To: <1230219162.14739.1.camel@dima-desktop> References: <1230219162.14739.1.camel@dima-desktop> Message-ID: <4953D384.1070806@redhat.com> ?? wrote: > how to increase RAM on running vm ? As far as I know, kvm doesn't allow memory hotplug. So in order to give a vm more memory you need to shut the vm down, adjust the memory and then restart. I'm not sure where memory hotplug is on the list of features for kvm, someone on the kvm team can probably comment on that. Perry From pmyers at redhat.com Thu Dec 25 18:48:39 2008 From: pmyers at redhat.com (Perry Myers) Date: Thu, 25 Dec 2008 13:48:39 -0500 Subject: [Ovirt-devel] Re: Fw: Install problems on fresh F10 In-Reply-To: References: Message-ID: <4953D587.7000804@redhat.com> Daniel Galeus wrote: > > ----- Original Message ----- > *From:* daniel at sml.se > *To:* ovirt-devel at redhat.com > *Sent:* Thursday, December 25, 2008 11:00 AM > *Subject:* Install problems on fresh F10 > > I'm trying to install 0.96 on a fresh install of Fedora 10. > > I follow the install instructions on the web page, and in addition I > disable Network Manager with commands provided by pmyers. > > When I run create-ovirt-network I get the following error. > > Currently defined libvirt networks: > ----------------------------------- > libvir: Remote error : unable to connect to > '/var/run/libvirt/libvirt-sock': No such file or directory > error: failed to connect to the hypervisor > > Please find below the console output during my install. Thanks for the info. That libvirt error would seem to indicate that libvirt daemon is not running. Comments and some debugging inline below... > Ciao, > bs66 > > *** > > > [root at localhost sysuser]# sudo service networkmanager stop > networkmanager: unrecognized service > [root at localhost sysuser]# sudo service NetworkManager stop > Stopping NetworkManager daemon: [ OK ] > [root at localhost sysuser]# sudo yum remove NetworkManager\* > Loaded plugins: refresh-packagekit > Setting up Remove Process > Resolving Dependencies > --> Running transaction check > ---> Package NetworkManager-gnome.x86_64 1:0.7.0-0.12.svn4326.fc10 set > to be erased > ---> Package NetworkManager.x86_64 1:0.7.0-0.12.svn4326.fc10 set to be > erased > ---> Package NetworkManager-glib.x86_64 1:0.7.0-0.12.svn4326.fc10 set to > be erased > --> Processing Dependency: libnm_glib.so.0()(64bit) for package: evolution > --> Processing Dependency: libnm_glib.so.0()(64bit) for package: > krb5-auth-dialog > --> Processing Dependency: libnm_glib.so.0()(64bit) for package: PackageKit > --> Running transaction check > ---> Package evolution.x86_64 0:2.24.2-2.fc10 set to be erased > --> Processing Dependency: evolution = 2.24.2-2.fc10 for package: > evolution-help > --> Processing Dependency: evolution = 2.24.2-2.fc10 for package: > evolution-perl > ---> Package krb5-auth-dialog.x86_64 0:0.7-7.fc9 set to be erased > ---> Package PackageKit.x86_64 0:0.3.12-1.fc10 set to be erased > --> Processing Dependency: PackageKit = 0.3.12-1.fc10 for package: > PackageKit-yum > --> Processing Dependency: PackageKit >= 0.3.11 for package: > gnome-packagekit > --> Processing Dependency: PackageKit = 0.3.12-1.fc10 for package: > PackageKit-glib > --> Processing Dependency: PackageKit for package: PackageKit-yum-plugin > --> Processing Dependency: PackageKit for package: PackageKit-udev-helper > --> Running transaction check > ---> Package evolution-help.x86_64 0:2.24.2-2.fc10 set to be erased > ---> Package PackageKit-glib.x86_64 0:0.3.12-1.fc10 set to be erased > --> Processing Dependency: PackageKit-glib = 0.3.12-1.fc10 for package: > PackageKit-gstreamer-plugin > ---> Package gnome-packagekit.x86_64 0:0.3.12-1.fc10 set to be erased > ---> Package PackageKit-udev-helper.x86_64 0:0.3.12-1.fc10 set to be erased > ---> Package PackageKit-yum.x86_64 0:0.3.12-1.fc10 set to be erased > ---> Package evolution-perl.x86_64 0:2.24.2-2.fc10 set to be erased > ---> Package PackageKit-yum-plugin.x86_64 0:0.3.12-1.fc10 set to be erased > --> Running transaction check > ---> Package PackageKit-gstreamer-plugin.x86_64 0:0.3.12-1.fc10 set to > be erased > --> Finished Dependency Resolution > > Dependencies Resolved > > ================================================================================ > Package Arch Version Repository > > Size > ================================================================================ > Removing: > NetworkManager x86_64 1:0.7.0-0.12.svn4326.fc10 > installed 2.9 M > NetworkManager-glib x86_64 1:0.7.0-0.12.svn4326.fc10 > installed 370 k > NetworkManager-gnome x86_64 1:0.7.0-0.12.svn4326.fc10 > installed 889 k > Removing for dependencies: > PackageKit x86_64 0.3.12-1.fc10 > installed 1.1 M > PackageKit-glib x86_64 0.3.12-1.fc10 > installed 321 k > PackageKit-gstreamer-plugin x86_64 0.3.12-1.fc10 > installed 139 k > PackageKit-udev-helper x86_64 0.3.12-1.fc10 > installed 126 k > PackageKit-yum x86_64 0.3.12-1.fc10 > installed 334 k > PackageKit-yum-plugin x86_64 0.3.12-1.fc10 > installed 128 k > evolution x86_64 2.24.2-2.fc10 > installed 38 M > evolution-help x86_64 2.24.2-2.fc10 > installed 53 M > evolution-perl x86_64 2.24.2-2.fc10 > installed 7.6 k > gnome-packagekit x86_64 0.3.12-1.fc10 > installed 6.0 M > krb5-auth-dialog x86_64 0.7-7.fc9 > installed 56 k > > Transaction Summary > ================================================================================ > Install 0 Package(s) > Update 0 Package(s) > Remove 14 Package(s) > > Is this ok [y/N]: y > Downloading Packages: > ============================== Entering rpm code > =============================== > Running rpm_check_debug > Running Transaction Test > Finished Transaction Test > Transaction Test Succeeded > Running Transaction > Erasing : > krb5-auth-dialog 1/14 > Erasing : > NetworkManager-glib 2/14 > Erasing : > PackageKit-yum-plugin 3/14 > Erasing : > PackageKit-glib 4/14 > Erasing : > NetworkManager-gnome 5/14 > Erasing : > gnome-packagekit 6/14 > Erasing : > PackageKit 7/14 > Erasing : > NetworkManager 8/14 > Erasing : > evolution-perl 9/14 > Erasing : > PackageKit-udev-helper 10/14 > Erasing : > evolution-help 11/14 > Erasing : > evolution 12/14 > Erasing : > PackageKit-yum 13/14 > Erasing : > PackageKit-gstreamer-plugin 14/14 > Unable to send message to PackageKit > =============================== Leaving rpm code > =============================== > > Removed: > NetworkManager.x86_64 > 1:0.7.0-0.12.svn4326.fc10 > NetworkManager-glib.x86_64 > 1:0.7.0-0.12.svn4326.fc10 > NetworkManager-gnome.x86_64 > 1:0.7.0-0.12.svn4326.fc10 > > Dependency Removed: > PackageKit.x86_64 > 0:0.3.12-1.fc10 > PackageKit-glib.x86_64 > 0:0.3.12-1.fc10 > PackageKit-gstreamer-plugin.x86_64 > 0:0.3.12-1.fc10 > PackageKit-udev-helper.x86_64 > 0:0.3.12-1.fc10 > PackageKit-yum.x86_64 > 0:0.3.12-1.fc10 > PackageKit-yum-plugin.x86_64 > 0:0.3.12-1.fc10 > evolution.x86_64 > 0:2.24.2-2.fc10 > evolution-help.x86_64 > 0:2.24.2-2.fc10 > evolution-perl.x86_64 > 0:2.24.2-2.fc10 > gnome-packagekit.x86_64 > 0:0.3.12-1.fc10 > krb5-auth-dialog.x86_64 > 0:0.7-7.fc9 > > Complete! > [root at localhost sysuser]# sudo chkconfig network on > [root at localhost sysuser]# sudo service network stop > Shutting down loopback interface: [ OK ] > [root at localhost sysuser]# sudo service network start > Bringing up loopback interface: [ OK ] Looks like you don't have /etc/sysconfig/network-scripts/ifcfg-eth0 file defined... That's why your network doesn't work after removing NetworkManager. If you use DHCP for eth0, minimum ifcfg-eth0 can look like this: > DEVICE=eth0 > BOOTPROTO=dhcp > ONBOOT=yes After creating /etc/sysconfig/network-scripts/ifcfg-eth0 with above contents then try sudo service network restart and you should get your network back. > [root at localhost sysuser]# sudo create-ovirt-network > Currently active bridges: > ------------------------- > bridge name bridge id STP enabled interfaces > pan0 8000.000000000000 no > virbr0 8000.000000000000 yes > > Currently defined libvirt networks: > ----------------------------------- > libvir: Remote error : unable to connect to > '/var/run/libvirt/libvirt-sock': No such file or directory > error: failed to connect to the hypervisor Yeah, this indicates that libvirtd is not running. Try sudo service libvirtd restart sudo virsh net-list --all and then retry sudo create-ovirt-network and see if you get the same error message. Let me know what the output of all of the above commands are. > Removing ovirtbr0 > Done Removing ovirtbr0 > Network ovirtbr0 defined from /tmp/tmp.uBtmBwfX65 > > Network ovirtbr0 started > > Network ovirtbr0 marked as autostarted > > net.ipv4.ip_forward = 1 > augtool> set /files/etc/sysctl.conf/net.ipv4.ip_forward 1 > augtool> save > Saved 1 file(s) > augtool> > Shutting down dnsmasq: [FAILED] > Starting dnsmasq: [ OK ] > Currently active bridges: > ------------------------- > bridge name bridge id STP enabled interfaces > ovirtbr0 8000.000000000000 no > pan0 8000.000000000000 no > virbr0 8000.000000000000 yes > > Currently defined libvirt networks: > ----------------------------------- > Name State Autostart > ----------------------------------------- > default active yes > ovirtbr0 active yes > > > [root at localhost sysuser]# > > > -- |=- 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 pronix.service at gmail.com Thu Dec 25 19:42:48 2008 From: pronix.service at gmail.com (pronix pronix) Date: Thu, 25 Dec 2008 22:42:48 +0300 Subject: [Ovirt-devel] how to Increase memory for vm online ? In-Reply-To: <4953D384.1070806@redhat.com> References: <1230219162.14739.1.camel@dima-desktop> <4953D384.1070806@redhat.com> Message-ID: <639ce0480812251142p68ed4b5cq6b56ab9b24eb79c4@mail.gmail.com> I found virtio_balloon.ko but can't find how it work. 2008/12/25 Perry Myers : > ?? wrote: >> >> how to increase RAM on running vm ? > > As far as I know, kvm doesn't allow memory hotplug. So in order to give a > vm more memory you need to shut the vm down, adjust the memory and then > restart. > > I'm not sure where memory hotplug is on the list of features for kvm, > someone on the kvm team can probably comment on that. > > Perry > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel > From pmyers at redhat.com Fri Dec 26 04:00:32 2008 From: pmyers at redhat.com (Perry Myers) Date: Thu, 25 Dec 2008 23:00:32 -0500 Subject: [Ovirt-devel] Re: Fw: Install problems on fresh F10 In-Reply-To: References: Message-ID: <495456E0.8010100@redhat.com> daniel at sml.se wrote: > Thank you for your help. No problem. Can you email ovirt-devel at redhat.com instead of me individually? I don't mind getting the emails at all :) But it is better if we keep discussions like this on the list, since there may be others that could benefit from what we're discussing/figuring out. > I got no errors issuing the commands, and I can now reach > http://192.168.50.2/ovirt > > I am pretty sure I followed the install instructions, so I guess > something more should be changed in there to get the install working > smoothly. The issues you were having had to do with the fact that you had to disable NetworkManager. This is covered in the install instructions in the section "Installing and Running the Appliance": > NOTE: Fedora 10 uses NetworkManager by default to configure network interfaces. We recommend disabling NetworkManager and using the standard network scripts and network service. However, if you want to try running with NetworkManager enabled you can override the check with the -f flag to the create-ovirt-network script We didn't explicitly list the instructions for disabling NetworkManager in Fedora as there are plenty of resources for Fedora users in regards to network configuration. For example, a quick Google search found this as the #1 link when searching for "Fedora 10 disable NetworkManager": http://www.mjmwired.net/resources/mjm-fedora-f10.html#network But since this will probably be a common case for users of oVirt, I'll incorporate the steps described in the above link into our Wiki and provide a link to the Wiki page from the install instructions page. The other problem you had was that libvirtd service was not started properly. This is handled in the installation instructions under the section "Getting oVirt RPMs" in step 4. That step should ensure that libvirtd is running properly after upgrading/installing the daemon. Thanks, Perry > Please find below the console output fyi. > > Thanks again. > bs66 > > > > > [root at localhost network-scripts]# sudo service network restart > Shutting down loopback interface: [ OK ] > Disabling IPv4 packet forwarding: net.ipv4.ip_forward = 0 > [ OK ] > Bringing up loopback interface: [ OK ] > Bringing up interface eth0: > Determining IP information for eth0... done. > [ OK ] > [root at localhost network-scripts]# ifconfig > eth0 Link encap:Ethernet HWaddr 00:17:31:3F:20:85 > inet addr:192.168.0.205 Bcast:192.168.0.255 Mask:255.255.255.0 > inet6 addr: fe80::217:31ff:fe3f:2085/64 Scope:Link > UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 > RX packets:8 errors:0 dropped:0 overruns:0 frame:0 > TX packets:23 errors:0 dropped:0 overruns:0 carrier:0 > collisions:0 txqueuelen:1000 > RX bytes:1028 (1.0 KiB) TX bytes:5223 (5.1 KiB) > Interrupt:19 > > lo Link encap:Local Loopback > inet addr:127.0.0.1 Mask:255.0.0.0 > inet6 addr: ::1/128 Scope:Host > UP LOOPBACK RUNNING MTU:16436 Metric:1 > RX packets:40 errors:0 dropped:0 overruns:0 frame:0 > TX packets:40 errors:0 dropped:0 overruns:0 carrier:0 > collisions:0 txqueuelen:0 > RX bytes:11587 (11.3 KiB) TX bytes:11587 (11.3 KiB) > > ovirtbr0 Link encap:Ethernet HWaddr CE:86:E6:CF:A4:B5 > inet addr:192.168.50.1 Bcast:192.168.50.255 Mask:255.255.255.0 > inet6 addr: fe80::cc86:e6ff:fecf:a4b5/64 Scope:Link > UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 > RX packets:0 errors:0 dropped:0 overruns:0 frame:0 > TX packets:35 errors:0 dropped:0 overruns:0 carrier:0 > collisions:0 txqueuelen:0 > RX bytes:0 (0.0 b) TX bytes:5324 (5.1 KiB) > > virbr0 Link encap:Ethernet HWaddr FE:72:75:99:D3:E3 > inet addr:192.168.122.1 Bcast:192.168.122.255 Mask:255.255.255.0 > inet6 addr: fe80::fc72:75ff:fe99:d3e3/64 Scope:Link > UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 > RX packets:0 errors:0 dropped:0 overruns:0 frame:0 > TX packets:29 errors:0 dropped:0 overruns:0 carrier:0 > collisions:0 txqueuelen:0 > RX bytes:0 (0.0 b) TX bytes:5122 (5.0 KiB) > > [root at localhost network-scripts]# sudo service libvirtd restart > Stopping libvirtd daemon: [ OK ] > Starting libvirtd daemon: [ OK ] > [root at localhost network-scripts]# sudo virsh net-list --all > Name State Autostart > ----------------------------------------- > default active yes > ovirtbr0 active yes > > [root at localhost network-scripts]# sudo create-ovirt-network > Currently active bridges: > ------------------------- > bridge name bridge id STP enabled interfaces > ovirtbr0 8000.000000000000 no > pan0 8000.000000000000 no > virbr0 8000.000000000000 yes > > Currently defined libvirt networks: > ----------------------------------- > Name State Autostart > ----------------------------------------- > default active yes > ovirtbr0 active yes > > > Removing ovirtbr0 > Network ovirtbr0 destroyed > > Network ovirtbr0 has been undefined > > Done Removing ovirtbr0 > Network ovirtbr0 defined from /tmp/tmp.mYuVHglF21 > > Network ovirtbr0 started > > Network ovirtbr0 marked as autostarted > > net.ipv4.ip_forward = 1 > augtool> set /files/etc/sysctl.conf/net.ipv4.ip_forward 1 > augtool> save > augtool> > Shutting down dnsmasq: [ OK ] > Starting dnsmasq: [ OK ] > Currently active bridges: > ------------------------- > bridge name bridge id STP enabled interfaces > ovirtbr0 8000.000000000000 no > pan0 8000.000000000000 no > virbr0 8000.000000000000 yes > > Currently defined libvirt networks: > ----------------------------------- > Name State Autostart > ----------------------------------------- > default active yes > ovirtbr0 active yes > > > [root at localhost network-scripts]# > -- |=- 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 agx at sigxcpu.org Fri Dec 26 13:05:51 2008 From: agx at sigxcpu.org (Guido =?iso-8859-1?Q?G=FCnther?=) Date: Fri, 26 Dec 2008 14:05:51 +0100 Subject: [Ovirt-devel] how to Increase memory for vm online ? In-Reply-To: <639ce0480812251142p68ed4b5cq6b56ab9b24eb79c4@mail.gmail.com> References: <1230219162.14739.1.camel@dima-desktop> <4953D384.1070806@redhat.com> <639ce0480812251142p68ed4b5cq6b56ab9b24eb79c4@mail.gmail.com> Message-ID: <20081226130551.GA5355@bogon.ms20.nix> On Thu, Dec 25, 2008 at 10:42:48PM +0300, pronix pronix wrote: > I found virtio_balloon.ko > but can't find how it work. > > 2008/12/25 Perry Myers : > > ?? wrote: > >> > >> how to increase RAM on running vm ? > > > > As far as I know, kvm doesn't allow memory hotplug. So in order to give a > > vm more memory you need to shut the vm down, adjust the memory and then > > restart. > > > > I'm not sure where memory hotplug is on the list of features for kvm, See the balloon monitor command in recent kvm. This needs to be hooked into libvirt's qemudDomainSetMemory. -- Guido > > someone on the kvm team can probably comment on that. From pmyers at redhat.com Fri Dec 26 15:59:35 2008 From: pmyers at redhat.com (Perry Myers) Date: Fri, 26 Dec 2008 10:59:35 -0500 Subject: [Ovirt-devel] how to Increase memory for vm online ? In-Reply-To: <20081226130551.GA5355@bogon.ms20.nix> References: <1230219162.14739.1.camel@dima-desktop> <4953D384.1070806@redhat.com> <639ce0480812251142p68ed4b5cq6b56ab9b24eb79c4@mail.gmail.com> <20081226130551.GA5355@bogon.ms20.nix> Message-ID: <4954FF67.1090501@redhat.com> Guido ? wrote: > On Thu, Dec 25, 2008 at 10:42:48PM +0300, pronix pronix wrote: >> I found virtio_balloon.ko >> but can't find how it work. >> >> 2008/12/25 Perry Myers : >>> ?? wrote: >>>> how to increase RAM on running vm ? >>> As far as I know, kvm doesn't allow memory hotplug. So in order to give a >>> vm more memory you need to shut the vm down, adjust the memory and then >>> restart. >>> >>> I'm not sure where memory hotplug is on the list of features for kvm, > See the balloon monitor command in recent kvm. This needs to be hooked > into libvirt's qemudDomainSetMemory. > -- Guido Guido, How does the guest support this? Do Windows/Linux OSes support hotplug (add/remove) of system memory dynamically or are additional guest drivers needed for this? Thanks, Perry From pmyers at redhat.com Fri Dec 26 16:11:47 2008 From: pmyers at redhat.com (Perry Myers) Date: Fri, 26 Dec 2008 11:11:47 -0500 Subject: [Ovirt-devel] Re: Fw: Install problems on fresh F10 In-Reply-To: References: Message-ID: <49550243.5060507@redhat.com> daniel at sml.se wrote: > I did post to ovirt-devel but I am not a registered user, so a moderator > need to review my posting before it becomes available. > > I will register, but right now I only have a few seconds to spare. > > I try to add use "Add Virtual Machine" but the "Storage" is empty. My > iSCSI and NFS storage says "State: pending_setup". What am I doing wrong? Ok. Do you have a working oVirt Node running? Either one of nodeX.priv.ovirt.org or physical.priv.ovirt.org? They should show up in the default hardware pool under the Hosts tab. If they are working properly they should show up as "available (enabled)" In order to add storage to the storage pool you need to have a Node available to query the storage to make sure it is accessible. If the Node you are relying on is physical.priv.ovirt.org did you follow the multiple reboot instructions for getting this node to work properly? In short you needed to: 1. shutdown the appliance 2. on host run ovirt-install-node-stateful 3. boot appliance 4. shutdown appliance 5. sudo service libvirtd restart 6. start appliance 7. physical should show up as available (enabled) now and you should be able to run: virsh -c qemu+tcp://physical.priv.ovirt.org/system --list from the appliance. If you do have one or more Nodes listed as available (enabled) in the Hosts tab but still see the problem with storage in pending_setup, do the following: ssh to the appliance (user:ovirt pass:ovirt) klist virsh -c qemu+tcp://nodeX.priv.ovirt.org/system list --all virsh -c qemu+tcp://physical.priv.ovirt.org/system list --all Let me know what the output of the above commands is. Also, please tar up the logs on the appliance in: /var/log/ovirt-server /var/log/ovirt*.log /var/log/ace/* And send them to me so I can see if there are any errors. Thanks, Perry From pronix.service at gmail.com Sat Dec 27 09:54:45 2008 From: pronix.service at gmail.com (pronix pronix) Date: Sat, 27 Dec 2008 12:54:45 +0300 Subject: [Ovirt-devel] how to Increase memory for vm online ? In-Reply-To: <4954FF67.1090501@redhat.com> References: <1230219162.14739.1.camel@dima-desktop> <4953D384.1070806@redhat.com> <639ce0480812251142p68ed4b5cq6b56ab9b24eb79c4@mail.gmail.com> <20081226130551.GA5355@bogon.ms20.nix> <4954FF67.1090501@redhat.com> Message-ID: <639ce0480812270154la2793cdjb81093a0cc0f2466@mail.gmail.com> kernel documentation ram hotplug linux-2.6.27/Documentation/memory-hotplug.txt cpu hotplug linux-2.6.27/Documentation/cpu-hotplug.txt 2008/12/26 Perry Myers : > Guido ? wrote: >> >> On Thu, Dec 25, 2008 at 10:42:48PM +0300, pronix pronix wrote: >>> >>> I found virtio_balloon.ko >>> but can't find how it work. >>> >>> 2008/12/25 Perry Myers : >>>> >>>> ?? wrote: >>>>> >>>>> how to increase RAM on running vm ? >>>> >>>> As far as I know, kvm doesn't allow memory hotplug. So in order to give >>>> a >>>> vm more memory you need to shut the vm down, adjust the memory and then >>>> restart. >>>> >>>> I'm not sure where memory hotplug is on the list of features for kvm, >> >> See the balloon monitor command in recent kvm. This needs to be hooked >> into libvirt's qemudDomainSetMemory. >> -- Guido > > Guido, > > How does the guest support this? Do Windows/Linux OSes support hotplug > (add/remove) of system memory dynamically or are additional guest drivers > needed for this? > > Thanks, > > Perry > From phr at cally.be Sat Dec 27 11:09:59 2008 From: phr at cally.be (Philippe Rodrigues) Date: Sat, 27 Dec 2008 12:09:59 +0100 (CET) Subject: [Ovirt-devel] Install issue on fresh F10 Message-ID: <2823.83.134.22.193.1230376199.squirrel@webmail.cally.be> First of all thanks everybody for the good job. Sorry for my english it's not my native language but I do my best to explain the problem. In fact I've the same problem like daniel sml in previous post. So I followed instructions from Perry Myers and this the output: [root at management ovirt-server]# klist Ticket cache: FILE:/tmp/krb5cc_0 Default principal: admin at PRIV.OVIRT.ORG Valid starting Expires Service principal 12/26/08 15:23:41 12/27/08 15:23:41 krbtgt/PRIV.OVIRT.ORG at PRIV.OVIRT.ORG 12/26/08 15:23:42 12/27/08 15:23:41 ldap/management.priv.ovirt.org at PRIV.OVIRT.ORG 12/26/08 15:23:43 12/27/08 15:23:41 HTTP/management.priv.ovirt.org at PRIV.OVIRT.ORG 12/27/08 06:48:11 12/27/08 15:23:41 libvirt/physical.priv.ovirt.org at PRIV.OVIRT.ORG Kerberos 4 ticket cache: /tmp/tkt0 klist: You have no tickets cached [root at management ovirt-server]# virsh -c qemu+tcp://physical.priv.ovirt.org/system list --all Id Name State ---------------------------------- 1 ovirt-appliance running If this can help, service libvirt-qpid hang up on host and you have this message in var/log/message : Dec 27 08:02:33 physical kernel: libvirt-qpid[3897]: segfault at 57e58951 ip 067435ae sp bfe54190 error 4 in libstdc++.so.6.0.10[66ab000+e7000] In attachment screenshot of Dashboard. Thanks for your help. -------------- next part -------------- A non-text attachment was scrubbed... Name: ovirt Type: application/octet-stream Size: 111397 bytes Desc: not available URL: From pronix.service at gmail.com Sat Dec 27 11:14:43 2008 From: pronix.service at gmail.com (pronix pronix) Date: Sat, 27 Dec 2008 14:14:43 +0300 Subject: [Ovirt-devel] Install issue on fresh F10 In-Reply-To: <2823.83.134.22.193.1230376199.squirrel@webmail.cally.be> References: <2823.83.134.22.193.1230376199.squirrel@webmail.cally.be> Message-ID: <639ce0480812270314i52aaa2a6n8f9ea794205c1970@mail.gmail.com> i solve problem with libvirt-qpid . download src.rpm and build rpm. 2008/12/27 Philippe Rodrigues : > First of all thanks everybody for the good job. > Sorry for my english it's not my native language but I do my best to > explain the problem. > In fact I've the same problem like daniel sml in previous post. So I > followed instructions from Perry Myers and this the output: > > [root at management ovirt-server]# klist > Ticket cache: FILE:/tmp/krb5cc_0 > Default principal: admin at PRIV.OVIRT.ORG > > Valid starting Expires Service principal > 12/26/08 15:23:41 12/27/08 15:23:41 krbtgt/PRIV.OVIRT.ORG at PRIV.OVIRT.ORG > 12/26/08 15:23:42 12/27/08 15:23:41 > ldap/management.priv.ovirt.org at PRIV.OVIRT.ORG > 12/26/08 15:23:43 12/27/08 15:23:41 > HTTP/management.priv.ovirt.org at PRIV.OVIRT.ORG > 12/27/08 06:48:11 12/27/08 15:23:41 > libvirt/physical.priv.ovirt.org at PRIV.OVIRT.ORG > > Kerberos 4 ticket cache: /tmp/tkt0 > klist: You have no tickets cached > > [root at management ovirt-server]# virsh -c > qemu+tcp://physical.priv.ovirt.org/system list --all > Id Name State > ---------------------------------- > 1 ovirt-appliance running > > If this can help, service libvirt-qpid hang up on host and you have this > message in var/log/message : > > Dec 27 08:02:33 physical kernel: libvirt-qpid[3897]: segfault at 57e58951 > ip 067435ae sp bfe54190 error 4 in libstdc++.so.6.0.10[66ab000+e7000] > > In attachment screenshot of Dashboard. > > Thanks for your help. > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel > > From halsaadi at thoughtworks.com Sat Dec 27 11:09:02 2008 From: halsaadi at thoughtworks.com (Hadi Al-Saadi) Date: Sat, 27 Dec 2008 16:39:02 +0530 Subject: [Ovirt-devel] Re: Ovirt-devel Digest, Vol 11, Issue 65 In-Reply-To: <20081227111022.A037B618A16@hormel.redhat.com> Message-ID: use virsh-command-line for Increase vm memory -------------- next part -------------- An HTML attachment was scrubbed... URL: From phr at cally.be Sat Dec 27 14:36:46 2008 From: phr at cally.be (Philippe Rodrigues) Date: Sat, 27 Dec 2008 15:36:46 +0100 (CET) Subject: [Ovirt-devel] Install issue on fresh F10 In-Reply-To: <639ce0480812270314i52aaa2a6n8f9ea794205c1970@mail.gmail.com> References: <2823.83.134.22.193.1230376199.squirrel@webmail.cally.be> <639ce0480812270314i52aaa2a6n8f9ea794205c1970@mail.gmail.com> Message-ID: <37189.83.134.23.79.1230388606.squirrel@webmail.cally.be> Thanks for your reply Pronix. I've installed Ovirt using "Install Instruction" but if your solution can resolve availability of physical node and NFS storage too, I can try it. > i solve problem with libvirt-qpid . > download src.rpm and build rpm. > > 2008/12/27 Philippe Rodrigues : >> First of all thanks everybody for the good job. >> Sorry for my english it's not my native language but I do my best to >> explain the problem. >> In fact I've the same problem like daniel sml in previous post. So I >> followed instructions from Perry Myers and this the output: >> >> [root at management ovirt-server]# klist >> Ticket cache: FILE:/tmp/krb5cc_0 >> Default principal: admin at PRIV.OVIRT.ORG >> >> Valid starting Expires Service principal >> 12/26/08 15:23:41 12/27/08 15:23:41 >> krbtgt/PRIV.OVIRT.ORG at PRIV.OVIRT.ORG >> 12/26/08 15:23:42 12/27/08 15:23:41 >> ldap/management.priv.ovirt.org at PRIV.OVIRT.ORG >> 12/26/08 15:23:43 12/27/08 15:23:41 >> HTTP/management.priv.ovirt.org at PRIV.OVIRT.ORG >> 12/27/08 06:48:11 12/27/08 15:23:41 >> libvirt/physical.priv.ovirt.org at PRIV.OVIRT.ORG >> >> Kerberos 4 ticket cache: /tmp/tkt0 >> klist: You have no tickets cached >> >> [root at management ovirt-server]# virsh -c >> qemu+tcp://physical.priv.ovirt.org/system list --all >> Id Name State >> ---------------------------------- >> 1 ovirt-appliance running >> >> If this can help, service libvirt-qpid hang up on host and you have this >> message in var/log/message : >> >> Dec 27 08:02:33 physical kernel: libvirt-qpid[3897]: segfault at >> 57e58951 >> ip 067435ae sp bfe54190 error 4 in libstdc++.so.6.0.10[66ab000+e7000] >> >> In attachment screenshot of Dashboard. >> >> Thanks for your help. >> >> _______________________________________________ >> Ovirt-devel mailing list >> Ovirt-devel at redhat.com >> https://www.redhat.com/mailman/listinfo/ovirt-devel >> >> > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel > From pmyers at redhat.com Sat Dec 27 15:34:45 2008 From: pmyers at redhat.com (Perry Myers) Date: Sat, 27 Dec 2008 10:34:45 -0500 Subject: [Ovirt-devel] how to Increase memory for vm online ? In-Reply-To: <639ce0480812270154la2793cdjb81093a0cc0f2466@mail.gmail.com> References: <1230219162.14739.1.camel@dima-desktop> <4953D384.1070806@redhat.com> <639ce0480812251142p68ed4b5cq6b56ab9b24eb79c4@mail.gmail.com> <20081226130551.GA5355@bogon.ms20.nix> <4954FF67.1090501@redhat.com> <639ce0480812270154la2793cdjb81093a0cc0f2466@mail.gmail.com> Message-ID: <49564B15.2070603@redhat.com> pronix pronix wrote: > kernel documentation > ram hotplug > linux-2.6.27/Documentation/memory-hotplug.txt > cpu hotplug > linux-2.6.27/Documentation/cpu-hotplug.txt Ah, so only supported in Linux guests... Windows guests don't have support for dynamic resizing of memory them. Thanks for the pointers. Perry From sander at hoentjen.eu Sat Dec 27 15:40:50 2008 From: sander at hoentjen.eu (Sander Hoentjen) Date: Sat, 27 Dec 2008 16:40:50 +0100 Subject: [Ovirt-devel] how to Increase memory for vm online ? In-Reply-To: <49564B15.2070603@redhat.com> References: <1230219162.14739.1.camel@dima-desktop> <4953D384.1070806@redhat.com> <639ce0480812251142p68ed4b5cq6b56ab9b24eb79c4@mail.gmail.com> <20081226130551.GA5355@bogon.ms20.nix> <4954FF67.1090501@redhat.com> <639ce0480812270154la2793cdjb81093a0cc0f2466@mail.gmail.com> <49564B15.2070603@redhat.com> Message-ID: <1230392450.5588.14.camel@peecee.hoentjen.eu> On Sat, 2008-12-27 at 10:34 -0500, Perry Myers wrote: > pronix pronix wrote: > > kernel documentation > > ram hotplug > > linux-2.6.27/Documentation/memory-hotplug.txt > > cpu hotplug > > linux-2.6.27/Documentation/cpu-hotplug.txt > > Ah, so only supported in Linux guests... Windows guests don't have > support for dynamic resizing of memory them. Actually it does support adding: http://www.microsoft.com/whdc/system/pnppwr/hotadd/hotaddmem.mspx Sander From pmyers at redhat.com Sat Dec 27 16:12:25 2008 From: pmyers at redhat.com (Perry Myers) Date: Sat, 27 Dec 2008 11:12:25 -0500 Subject: [Ovirt-devel] how to Increase memory for vm online ? In-Reply-To: <1230392450.5588.14.camel@peecee.hoentjen.eu> References: <1230219162.14739.1.camel@dima-desktop> <4953D384.1070806@redhat.com> <639ce0480812251142p68ed4b5cq6b56ab9b24eb79c4@mail.gmail.com> <20081226130551.GA5355@bogon.ms20.nix> <4954FF67.1090501@redhat.com> <639ce0480812270154la2793cdjb81093a0cc0f2466@mail.gmail.com> <49564B15.2070603@redhat.com> <1230392450.5588.14.camel@peecee.hoentjen.eu> Message-ID: <495653E9.1050804@redhat.com> Sander Hoentjen wrote: > On Sat, 2008-12-27 at 10:34 -0500, Perry Myers wrote: >> pronix pronix wrote: >>> kernel documentation >>> ram hotplug >>> linux-2.6.27/Documentation/memory-hotplug.txt >>> cpu hotplug >>> linux-2.6.27/Documentation/cpu-hotplug.txt >> Ah, so only supported in Linux guests... Windows guests don't have >> support for dynamic resizing of memory them. > > Actually it does support adding: > http://www.microsoft.com/whdc/system/pnppwr/hotadd/hotaddmem.mspx Interesting... I'll have to give this a whirl on both linux and windows guests... If things work seamlessly we should be able to support this easily in oVirt... Perry From pmyers at redhat.com Sat Dec 27 17:52:42 2008 From: pmyers at redhat.com (Perry Myers) Date: Sat, 27 Dec 2008 12:52:42 -0500 Subject: [Ovirt-devel] Install issue on fresh F10 In-Reply-To: <37189.83.134.23.79.1230388606.squirrel@webmail.cally.be> References: <2823.83.134.22.193.1230376199.squirrel@webmail.cally.be> <639ce0480812270314i52aaa2a6n8f9ea794205c1970@mail.gmail.com> <37189.83.134.23.79.1230388606.squirrel@webmail.cally.be> Message-ID: <49566B6A.8000205@redhat.com> Philippe Rodrigues wrote: > Thanks for your reply Pronix. I've installed Ovirt using "Install > Instruction" but if your solution can resolve availability of physical > node and NFS storage too, I can try it. > >> i solve problem with libvirt-qpid . >> download src.rpm and build rpm. I have seen this error w/ libvirt-qpid on my hosts too. The last update must have been a bad build. I've rebuilt the libvirt-qpid packages for both i386 and x86_64 and put them up on ovirt.org repos. Please give these new RPMS a try and let me know if you encounter any issues. Thanks, Perry From daniel at sml.se Thu Dec 25 10:00:08 2008 From: daniel at sml.se (daniel at sml.se) Date: Thu, 25 Dec 2008 11:00:08 +0100 Subject: [Ovirt-devel] Install problems on fresh F10 Message-ID: I'm trying to install 0.96 on a fresh install of Fedora 10. I follow the install instructions on the web page, and in addition I disable Network Manager with commands provided by pmyers. When I run create-ovirt-network I get the following error. Currently defined libvirt networks: ----------------------------------- libvir: Remote error : unable to connect to '/var/run/libvirt/libvirt-sock': No such file or directory error: failed to connect to the hypervisor Please find below the console output during my install. Ciao, bs66 *** [root at localhost sysuser]# sudo service networkmanager stop networkmanager: unrecognized service [root at localhost sysuser]# sudo service NetworkManager stop Stopping NetworkManager daemon: [ OK ] [root at localhost sysuser]# sudo yum remove NetworkManager\* Loaded plugins: refresh-packagekit Setting up Remove Process Resolving Dependencies --> Running transaction check ---> Package NetworkManager-gnome.x86_64 1:0.7.0-0.12.svn4326.fc10 set to be erased ---> Package NetworkManager.x86_64 1:0.7.0-0.12.svn4326.fc10 set to be erased ---> Package NetworkManager-glib.x86_64 1:0.7.0-0.12.svn4326.fc10 set to be erased --> Processing Dependency: libnm_glib.so.0()(64bit) for package: evolution --> Processing Dependency: libnm_glib.so.0()(64bit) for package: krb5-auth-dialog --> Processing Dependency: libnm_glib.so.0()(64bit) for package: PackageKit --> Running transaction check ---> Package evolution.x86_64 0:2.24.2-2.fc10 set to be erased --> Processing Dependency: evolution = 2.24.2-2.fc10 for package: evolution-help --> Processing Dependency: evolution = 2.24.2-2.fc10 for package: evolution-perl ---> Package krb5-auth-dialog.x86_64 0:0.7-7.fc9 set to be erased ---> Package PackageKit.x86_64 0:0.3.12-1.fc10 set to be erased --> Processing Dependency: PackageKit = 0.3.12-1.fc10 for package: PackageKit-yum --> Processing Dependency: PackageKit >= 0.3.11 for package: gnome-packagekit --> Processing Dependency: PackageKit = 0.3.12-1.fc10 for package: PackageKit-glib --> Processing Dependency: PackageKit for package: PackageKit-yum-plugin --> Processing Dependency: PackageKit for package: PackageKit-udev-helper --> Running transaction check ---> Package evolution-help.x86_64 0:2.24.2-2.fc10 set to be erased ---> Package PackageKit-glib.x86_64 0:0.3.12-1.fc10 set to be erased --> Processing Dependency: PackageKit-glib = 0.3.12-1.fc10 for package: PackageKit-gstreamer-plugin ---> Package gnome-packagekit.x86_64 0:0.3.12-1.fc10 set to be erased ---> Package PackageKit-udev-helper.x86_64 0:0.3.12-1.fc10 set to be erased ---> Package PackageKit-yum.x86_64 0:0.3.12-1.fc10 set to be erased ---> Package evolution-perl.x86_64 0:2.24.2-2.fc10 set to be erased ---> Package PackageKit-yum-plugin.x86_64 0:0.3.12-1.fc10 set to be erased --> Running transaction check ---> Package PackageKit-gstreamer-plugin.x86_64 0:0.3.12-1.fc10 set to be erased --> Finished Dependency Resolution Dependencies Resolved ================================================================================ Package Arch Version Repository Size ================================================================================ Removing: NetworkManager x86_64 1:0.7.0-0.12.svn4326.fc10 installed 2.9 M NetworkManager-glib x86_64 1:0.7.0-0.12.svn4326.fc10 installed 370 k NetworkManager-gnome x86_64 1:0.7.0-0.12.svn4326.fc10 installed 889 k Removing for dependencies: PackageKit x86_64 0.3.12-1.fc10 installed 1.1 M PackageKit-glib x86_64 0.3.12-1.fc10 installed 321 k PackageKit-gstreamer-plugin x86_64 0.3.12-1.fc10 installed 139 k PackageKit-udev-helper x86_64 0.3.12-1.fc10 installed 126 k PackageKit-yum x86_64 0.3.12-1.fc10 installed 334 k PackageKit-yum-plugin x86_64 0.3.12-1.fc10 installed 128 k evolution x86_64 2.24.2-2.fc10 installed 38 M evolution-help x86_64 2.24.2-2.fc10 installed 53 M evolution-perl x86_64 2.24.2-2.fc10 installed 7.6 k gnome-packagekit x86_64 0.3.12-1.fc10 installed 6.0 M krb5-auth-dialog x86_64 0.7-7.fc9 installed 56 k Transaction Summary ================================================================================ Install 0 Package(s) Update 0 Package(s) Remove 14 Package(s) Is this ok [y/N]: y Downloading Packages: ============================== Entering rpm code =============================== Running rpm_check_debug Running Transaction Test Finished Transaction Test Transaction Test Succeeded Running Transaction Erasing : krb5-auth-dialog 1/14 Erasing : NetworkManager-glib 2/14 Erasing : PackageKit-yum-plugin 3/14 Erasing : PackageKit-glib 4/14 Erasing : NetworkManager-gnome 5/14 Erasing : gnome-packagekit 6/14 Erasing : PackageKit 7/14 Erasing : NetworkManager 8/14 Erasing : evolution-perl 9/14 Erasing : PackageKit-udev-helper 10/14 Erasing : evolution-help 11/14 Erasing : evolution 12/14 Erasing : PackageKit-yum 13/14 Erasing : PackageKit-gstreamer-plugin 14/14 Unable to send message to PackageKit =============================== Leaving rpm code =============================== Removed: NetworkManager.x86_64 1:0.7.0-0.12.svn4326.fc10 NetworkManager-glib.x86_64 1:0.7.0-0.12.svn4326.fc10 NetworkManager-gnome.x86_64 1:0.7.0-0.12.svn4326.fc10 Dependency Removed: PackageKit.x86_64 0:0.3.12-1.fc10 PackageKit-glib.x86_64 0:0.3.12-1.fc10 PackageKit-gstreamer-plugin.x86_64 0:0.3.12-1.fc10 PackageKit-udev-helper.x86_64 0:0.3.12-1.fc10 PackageKit-yum.x86_64 0:0.3.12-1.fc10 PackageKit-yum-plugin.x86_64 0:0.3.12-1.fc10 evolution.x86_64 0:2.24.2-2.fc10 evolution-help.x86_64 0:2.24.2-2.fc10 evolution-perl.x86_64 0:2.24.2-2.fc10 gnome-packagekit.x86_64 0:0.3.12-1.fc10 krb5-auth-dialog.x86_64 0:0.7-7.fc9 Complete! [root at localhost sysuser]# sudo chkconfig network on [root at localhost sysuser]# sudo service network stop Shutting down loopback interface: [ OK ] [root at localhost sysuser]# sudo service network start Bringing up loopback interface: [ OK ] [root at localhost sysuser]# sudo create-ovirt-network Currently active bridges: ------------------------- bridge name bridge id STP enabled interfaces pan0 8000.000000000000 no virbr0 8000.000000000000 yes Currently defined libvirt networks: ----------------------------------- libvir: Remote error : unable to connect to '/var/run/libvirt/libvirt-sock': No such file or directory error: failed to connect to the hypervisor Removing ovirtbr0 Done Removing ovirtbr0 Network ovirtbr0 defined from /tmp/tmp.uBtmBwfX65 Network ovirtbr0 started Network ovirtbr0 marked as autostarted net.ipv4.ip_forward = 1 augtool> set /files/etc/sysctl.conf/net.ipv4.ip_forward 1 augtool> save Saved 1 file(s) augtool> Shutting down dnsmasq: [FAILED] Starting dnsmasq: [ OK ] Currently active bridges: ------------------------- bridge name bridge id STP enabled interfaces ovirtbr0 8000.000000000000 no pan0 8000.000000000000 no virbr0 8000.000000000000 yes Currently defined libvirt networks: ----------------------------------- Name State Autostart ----------------------------------------- default active yes ovirtbr0 active yes [root at localhost sysuser]# -------------- next part -------------- An HTML attachment was scrubbed... URL: From daniel at sml.se Fri Dec 26 09:11:21 2008 From: daniel at sml.se (daniel at sml.se) Date: Fri, 26 Dec 2008 10:11:21 +0100 Subject: [Ovirt-devel] Re: Fw: Install problems on fresh F10 Message-ID: I did post to ovirt-devel but I am not a registered user, so a moderator need to review my posting before it becomes available. I will register, but right now I only have a few seconds to spare. I try to add use "Add Virtual Machine" but the "Storage" is empty. My iSCSI and NFS storage says "State: pending_setup". What am I doing wrong? Sincerely, /bs66 ---------------------------------------- From: Perry Myers Sent: Friday, December 26, 2008 5:01 AM To: daniel at sml.se, ovirt-devel at redhat.com Subject: Re: Fw: Install problems on fresh F10 daniel at sml.se wrote: > Thank you for your help. No problem. Can you email ovirt-devel at redhat.com instead of me individually? I don't mind getting the emails at all :) But it is better if we keep discussions like this on the list, since there may be others that could benefit from what we're discussing/figuring out. > I got no errors issuing the commands, and I can now reach > http://192.168.50.2/ovirt > > I am pretty sure I followed the install instructions, so I guess > something more should be changed in there to get the install working > smoothly. The issues you were having had to do with the fact that you had to disable NetworkManager. This is covered in the install instructions in the section "Installing and Running the Appliance": > NOTE: Fedora 10 uses NetworkManager by default to configure network interfaces. We recommend disabling NetworkManager and using the standard network scripts and network service. However, if you want to try running with NetworkManager enabled you can override the check with the -f flag to the create-ovirt-network script We didn't explicitly list the instructions for disabling NetworkManager in Fedora as there are plenty of resources for Fedora users in regards to network configuration. For example, a quick Google search found this as the #1 link when searching for "Fedora 10 disable NetworkManager": http://www.mjmwired.net/resources/mjm-fedora-f10.html#network But since this will probably be a common case for users of oVirt, I'll incorporate the steps described in the above link into our Wiki and provide a link to the Wiki page from the install instructions page. The other problem you had was that libvirtd service was not started properly. This is handled in the installation instructions under the section "Getting oVirt RPMs" in step 4. That step should ensure that libvirtd is running properly after upgrading/installing the daemon. Thanks, Perry > Please find below the console output fyi. > > Thanks again. > bs66 > > > > > [root at localhost network-scripts]# sudo service network restart > Shutting down loopback interface: [ OK ] > Disabling IPv4 packet forwarding: net.ipv4.ip_forward = 0 > [ OK ] > Bringing up loopback interface: [ OK ] > Bringing up interface eth0: > Determining IP information for eth0... done. > [ OK ] > [root at localhost network-scripts]# ifconfig > eth0 Link encap:Ethernet HWaddr 00:17:31:3F:20:85 > inet addr:192.168.0.205 Bcast:192.168.0.255 Mask:255.255.255.0 > inet6 addr: fe80::217:31ff:fe3f:2085/64 Scope:Link > UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 > RX packets:8 errors:0 dropped:0 overruns:0 frame:0 > TX packets:23 errors:0 dropped:0 overruns:0 carrier:0 > collisions:0 txqueuelen:1000 > RX bytes:1028 (1.0 KiB) TX bytes:5223 (5.1 KiB) > Interrupt:19 > > lo Link encap:Local Loopback > inet addr:127.0.0.1 Mask:255.0.0.0 > inet6 addr: ::1/128 Scope:Host > UP LOOPBACK RUNNING MTU:16436 Metric:1 > RX packets:40 errors:0 dropped:0 overruns:0 frame:0 > TX packets:40 errors:0 dropped:0 overruns:0 carrier:0 > collisions:0 txqueuelen:0 > RX bytes:11587 (11.3 KiB) TX bytes:11587 (11.3 KiB) > > ovirtbr0 Link encap:Ethernet HWaddr CE:86:E6:CF:A4:B5 > inet addr:192.168.50.1 Bcast:192.168.50.255 Mask:255.255.255.0 > inet6 addr: fe80::cc86:e6ff:fecf:a4b5/64 Scope:Link > UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 > RX packets:0 errors:0 dropped:0 overruns:0 frame:0 > TX packets:35 errors:0 dropped:0 overruns:0 carrier:0 > collisions:0 txqueuelen:0 > RX bytes:0 (0.0 b) TX bytes:5324 (5.1 KiB) > > virbr0 Link encap:Ethernet HWaddr FE:72:75:99:D3:E3 > inet addr:192.168.122.1 Bcast:192.168.122.255 Mask:255.255.255.0 > inet6 addr: fe80::fc72:75ff:fe99:d3e3/64 Scope:Link > UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 > RX packets:0 errors:0 dropped:0 overruns:0 frame:0 > TX packets:29 errors:0 dropped:0 overruns:0 carrier:0 > collisions:0 txqueuelen:0 > RX bytes:0 (0.0 b) TX bytes:5122 (5.0 KiB) > > [root at localhost network-scripts]# sudo service libvirtd restart > Stopping libvirtd daemon: [ OK ] > Starting libvirtd daemon: [ OK ] > [root at localhost network-scripts]# sudo virsh net-list --all > Name State Autostart > ----------------------------------------- > default active yes > ovirtbr0 active yes > > [root at localhost network-scripts]# sudo create-ovirt-network > Currently active bridges: > ------------------------- > bridge name bridge id STP enabled interfaces > ovirtbr0 8000.000000000000 no > pan0 8000.000000000000 no > virbr0 8000.000000000000 yes > > Currently defined libvirt networks: > ----------------------------------- > Name State Autostart > ----------------------------------------- > default active yes > ovirtbr0 active yes > > > Removing ovirtbr0 > Network ovirtbr0 destroyed > > Network ovirtbr0 has been undefined > > Done Removing ovirtbr0 > Network ovirtbr0 defined from /tmp/tmp.mYuVHglF21 > > Network ovirtbr0 started > > Network ovirtbr0 marked as autostarted > > net.ipv4.ip_forward = 1 > augtool> set /files/etc/sysctl.conf/net.ipv4.ip_forward 1 > augtool> save > augtool> > Shutting down dnsmasq: [ OK ] > Starting dnsmasq: [ OK ] > Currently active bridges: > ------------------------- > bridge name bridge id STP enabled interfaces > ovirtbr0 8000.000000000000 no > pan0 8000.000000000000 no > virbr0 8000.000000000000 yes > > Currently defined libvirt networks: > ----------------------------------- > Name State Autostart > ----------------------------------------- > default active yes > ovirtbr0 active yes > > > [root at localhost network-scripts]# > -- |=- 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 -=| -------------- next part -------------- An HTML attachment was scrubbed... URL: From daniel at sml.se Fri Dec 26 09:11:21 2008 From: daniel at sml.se (daniel at sml.se) Date: Fri, 26 Dec 2008 10:11:21 +0100 Subject: [Ovirt-devel] Re: Fw: Install problems on fresh F10 Message-ID: I did post to ovirt-devel but I am not a registered user, so a moderator need to review my posting before it becomes available. I will register, but right now I only have a few seconds to spare. I try to add use "Add Virtual Machine" but the "Storage" is empty. My iSCSI and NFS storage says "State: pending_setup". What am I doing wrong? Sincerely, /bs66 ---------------------------------------- From: Perry Myers Sent: Friday, December 26, 2008 5:01 AM To: daniel at sml.se, ovirt-devel at redhat.com Subject: Re: Fw: Install problems on fresh F10 daniel at sml.se wrote: > Thank you for your help. No problem. Can you email ovirt-devel at redhat.com instead of me individually? I don't mind getting the emails at all :) But it is better if we keep discussions like this on the list, since there may be others that could benefit from what we're discussing/figuring out. > I got no errors issuing the commands, and I can now reach > http://192.168.50.2/ovirt > > I am pretty sure I followed the install instructions, so I guess > something more should be changed in there to get the install working > smoothly. The issues you were having had to do with the fact that you had to disable NetworkManager. This is covered in the install instructions in the section "Installing and Running the Appliance": > NOTE: Fedora 10 uses NetworkManager by default to configure network interfaces. We recommend disabling NetworkManager and using the standard network scripts and network service. However, if you want to try running with NetworkManager enabled you can override the check with the -f flag to the create-ovirt-network script We didn't explicitly list the instructions for disabling NetworkManager in Fedora as there are plenty of resources for Fedora users in regards to network configuration. For example, a quick Google search found this as the #1 link when searching for "Fedora 10 disable NetworkManager": http://www.mjmwired.net/resources/mjm-fedora-f10.html#network But since this will probably be a common case for users of oVirt, I'll incorporate the steps described in the above link into our Wiki and provide a link to the Wiki page from the install instructions page. The other problem you had was that libvirtd service was not started properly. This is handled in the installation instructions under the section "Getting oVirt RPMs" in step 4. That step should ensure that libvirtd is running properly after upgrading/installing the daemon. Thanks, Perry > Please find below the console output fyi. > > Thanks again. > bs66 > > > > > [root at localhost network-scripts]# sudo service network restart > Shutting down loopback interface: [ OK ] > Disabling IPv4 packet forwarding: net.ipv4.ip_forward = 0 > [ OK ] > Bringing up loopback interface: [ OK ] > Bringing up interface eth0: > Determining IP information for eth0... done. > [ OK ] > [root at localhost network-scripts]# ifconfig > eth0 Link encap:Ethernet HWaddr 00:17:31:3F:20:85 > inet addr:192.168.0.205 Bcast:192.168.0.255 Mask:255.255.255.0 > inet6 addr: fe80::217:31ff:fe3f:2085/64 Scope:Link > UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 > RX packets:8 errors:0 dropped:0 overruns:0 frame:0 > TX packets:23 errors:0 dropped:0 overruns:0 carrier:0 > collisions:0 txqueuelen:1000 > RX bytes:1028 (1.0 KiB) TX bytes:5223 (5.1 KiB) > Interrupt:19 > > lo Link encap:Local Loopback > inet addr:127.0.0.1 Mask:255.0.0.0 > inet6 addr: ::1/128 Scope:Host > UP LOOPBACK RUNNING MTU:16436 Metric:1 > RX packets:40 errors:0 dropped:0 overruns:0 frame:0 > TX packets:40 errors:0 dropped:0 overruns:0 carrier:0 > collisions:0 txqueuelen:0 > RX bytes:11587 (11.3 KiB) TX bytes:11587 (11.3 KiB) > > ovirtbr0 Link encap:Ethernet HWaddr CE:86:E6:CF:A4:B5 > inet addr:192.168.50.1 Bcast:192.168.50.255 Mask:255.255.255.0 > inet6 addr: fe80::cc86:e6ff:fecf:a4b5/64 Scope:Link > UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 > RX packets:0 errors:0 dropped:0 overruns:0 frame:0 > TX packets:35 errors:0 dropped:0 overruns:0 carrier:0 > collisions:0 txqueuelen:0 > RX bytes:0 (0.0 b) TX bytes:5324 (5.1 KiB) > > virbr0 Link encap:Ethernet HWaddr FE:72:75:99:D3:E3 > inet addr:192.168.122.1 Bcast:192.168.122.255 Mask:255.255.255.0 > inet6 addr: fe80::fc72:75ff:fe99:d3e3/64 Scope:Link > UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 > RX packets:0 errors:0 dropped:0 overruns:0 frame:0 > TX packets:29 errors:0 dropped:0 overruns:0 carrier:0 > collisions:0 txqueuelen:0 > RX bytes:0 (0.0 b) TX bytes:5122 (5.0 KiB) > > [root at localhost network-scripts]# sudo service libvirtd restart > Stopping libvirtd daemon: [ OK ] > Starting libvirtd daemon: [ OK ] > [root at localhost network-scripts]# sudo virsh net-list --all > Name State Autostart > ----------------------------------------- > default active yes > ovirtbr0 active yes > > [root at localhost network-scripts]# sudo create-ovirt-network > Currently active bridges: > ------------------------- > bridge name bridge id STP enabled interfaces > ovirtbr0 8000.000000000000 no > pan0 8000.000000000000 no > virbr0 8000.000000000000 yes > > Currently defined libvirt networks: > ----------------------------------- > Name State Autostart > ----------------------------------------- > default active yes > ovirtbr0 active yes > > > Removing ovirtbr0 > Network ovirtbr0 destroyed > > Network ovirtbr0 has been undefined > > Done Removing ovirtbr0 > Network ovirtbr0 defined from /tmp/tmp.mYuVHglF21 > > Network ovirtbr0 started > > Network ovirtbr0 marked as autostarted > > net.ipv4.ip_forward = 1 > augtool> set /files/etc/sysctl.conf/net.ipv4.ip_forward 1 > augtool> save > augtool> > Shutting down dnsmasq: [ OK ] > Starting dnsmasq: [ OK ] > Currently active bridges: > ------------------------- > bridge name bridge id STP enabled interfaces > ovirtbr0 8000.000000000000 no > pan0 8000.000000000000 no > virbr0 8000.000000000000 yes > > Currently defined libvirt networks: > ----------------------------------- > Name State Autostart > ----------------------------------------- > default active yes > ovirtbr0 active yes > > > [root at localhost network-scripts]# > -- |=- 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 -=| -------------- next part -------------- An HTML attachment was scrubbed... URL: From pmyers at redhat.com Sat Dec 27 23:57:36 2008 From: pmyers at redhat.com (Perry Myers) Date: Sat, 27 Dec 2008 18:57:36 -0500 Subject: [Ovirt-devel] Install problems on fresh F10 In-Reply-To: References: Message-ID: <4956C0F0.5000309@redhat.com> daniel at sml.se wrote: > I'm trying to install 0.96 on a fresh install of Fedora 10. > > I follow the install instructions on the web page, and in addition I > disable Network Manager with commands provided by pmyers. > > When I run create-ovirt-network I get the following error. > > Currently defined libvirt networks: > ----------------------------------- > libvir: Remote error : unable to connect to > '/var/run/libvirt/libvirt-sock': No such file or directory > error: failed to connect to the hypervisor > > Please find below the console output during my install. From the logs it looks like you never ran: sudo system-config-network which is mentioned in the instructions for removing NetworkManager on: http://ovirt.org/page/Appliance_Installation The absence of eth0 shouldn't cause a problem with libvirtd, so I think this problem is not related to the libvirtd error you saw when running create-ovirt-network. That libvirt error is harmless. The error occurs because libvirtd is not running when the script tries to query to see what networks are defined in libvirt. However, later in the script we restart the livirt daemon and the rest of the commands look like they succeed. So I think you can safely ignore that error message. What else is not working or is it just the libvirt error message you saw above? Thanks, Perry > Ciao, > bs66 > > *** > > > [root at localhost sysuser]# sudo service networkmanager stop > networkmanager: unrecognized service > [root at localhost sysuser]# sudo service NetworkManager stop > Stopping NetworkManager daemon: [ OK ] > [root at localhost sysuser]# sudo yum remove NetworkManager\* > Loaded plugins: refresh-packagekit > Setting up Remove Process > Resolving Dependencies > --> Running transaction check > ---> Package NetworkManager-gnome.x86_64 1:0.7.0-0.12.svn4326.fc10 set > to be erased > ---> Package NetworkManager.x86_64 1:0.7.0-0.12.svn4326.fc10 set to be > erased > ---> Package NetworkManager-glib.x86_64 1:0.7.0-0.12.svn4326.fc10 set to > be erased > --> Processing Dependency: libnm_glib.so.0()(64bit) for package: evolution > --> Processing Dependency: libnm_glib.so.0()(64bit) for package: > krb5-auth-dialog > --> Processing Dependency: libnm_glib.so.0()(64bit) for package: PackageKit > --> Running transaction check > ---> Package evolution.x86_64 0:2.24.2-2.fc10 set to be erased > --> Processing Dependency: evolution = 2.24.2-2.fc10 for package: > evolution-help > --> Processing Dependency: evolution = 2.24.2-2.fc10 for package: > evolution-perl > ---> Package krb5-auth-dialog.x86_64 0:0.7-7.fc9 set to be erased > ---> Package PackageKit.x86_64 0:0.3.12-1.fc10 set to be erased > --> Processing Dependency: PackageKit = 0.3.12-1.fc10 for package: > PackageKit-yum > --> Processing Dependency: PackageKit >= 0.3.11 for package: > gnome-packagekit > --> Processing Dependency: PackageKit = 0.3.12-1.fc10 for package: > PackageKit-glib > --> Processing Dependency: PackageKit for package: PackageKit-yum-plugin > --> Processing Dependency: PackageKit for package: PackageKit-udev-helper > --> Running transaction check > ---> Package evolution-help.x86_64 0:2.24.2-2.fc10 set to be erased > ---> Package PackageKit-glib.x86_64 0:0.3.12-1.fc10 set to be erased > --> Processing Dependency: PackageKit-glib = 0.3.12-1.fc10 for package: > PackageKit-gstreamer-plugin > ---> Package gnome-packagekit.x86_64 0:0.3.12-1.fc10 set to be erased > ---> Package PackageKit-udev-helper.x86_64 0:0.3.12-1.fc10 set to be erased > ---> Package PackageKit-yum.x86_64 0:0.3.12-1.fc10 set to be erased > ---> Package evolution-perl.x86_64 0:2.24.2-2.fc10 set to be erased > ---> Package PackageKit-yum-plugin.x86_64 0:0.3.12-1.fc10 set to be erased > --> Running transaction check > ---> Package PackageKit-gstreamer-plugin.x86_64 0:0.3.12-1.fc10 set to > be erased > --> Finished Dependency Resolution > > Dependencies Resolved > > ================================================================================ > Package Arch Version Repository > > Size > ================================================================================ > Removing: > NetworkManager x86_64 1:0.7.0-0.12.svn4326.fc10 > installed 2.9 M > NetworkManager-glib x86_64 1:0.7.0-0.12.svn4326.fc10 > installed 370 k > NetworkManager-gnome x86_64 1:0.7.0-0.12.svn4326.fc10 > installed 889 k > Removing for dependencies: > PackageKit x86_64 0.3.12-1.fc10 > installed 1.1 M > PackageKit-glib x86_64 0.3.12-1.fc10 > installed 321 k > PackageKit-gstreamer-plugin x86_64 0.3.12-1.fc10 > installed 139 k > PackageKit-udev-helper x86_64 0.3.12-1.fc10 > installed 126 k > PackageKit-yum x86_64 0.3.12-1.fc10 > installed 334 k > PackageKit-yum-plugin x86_64 0.3.12-1.fc10 > installed 128 k > evolution x86_64 2.24.2-2.fc10 > installed 38 M > evolution-help x86_64 2.24.2-2.fc10 > installed 53 M > evolution-perl x86_64 2.24.2-2.fc10 > installed 7.6 k > gnome-packagekit x86_64 0.3.12-1.fc10 > installed 6.0 M > krb5-auth-dialog x86_64 0.7-7.fc9 > installed 56 k > > Transaction Summary > ================================================================================ > Install 0 Package(s) > Update 0 Package(s) > Remove 14 Package(s) > > Is this ok [y/N]: y > Downloading Packages: > ============================== Entering rpm code > =============================== > Running rpm_check_debug > Running Transaction Test > Finished Transaction Test > Transaction Test Succeeded > Running Transaction > Erasing : > krb5-auth-dialog 1/14 > Erasing : > NetworkManager-glib 2/14 > Erasing : > PackageKit-yum-plugin 3/14 > Erasing : > PackageKit-glib 4/14 > Erasing : > NetworkManager-gnome 5/14 > Erasing : > gnome-packagekit 6/14 > Erasing : > PackageKit 7/14 > Erasing : > NetworkManager 8/14 > Erasing : > evolution-perl 9/14 > Erasing : > PackageKit-udev-helper 10/14 > Erasing : > evolution-help 11/14 > Erasing : > evolution 12/14 > Erasing : > PackageKit-yum 13/14 > Erasing : > PackageKit-gstreamer-plugin 14/14 > Unable to send message to PackageKit > =============================== Leaving rpm code > =============================== > > Removed: > NetworkManager.x86_64 > 1:0.7.0-0.12.svn4326.fc10 > NetworkManager-glib.x86_64 > 1:0.7.0-0.12.svn4326.fc10 > NetworkManager-gnome.x86_64 > 1:0.7.0-0.12.svn4326.fc10 > > Dependency Removed: > PackageKit.x86_64 > 0:0.3.12-1.fc10 > PackageKit-glib.x86_64 > 0:0.3.12-1.fc10 > PackageKit-gstreamer-plugin.x86_64 > 0:0.3.12-1.fc10 > PackageKit-udev-helper.x86_64 > 0:0.3.12-1.fc10 > PackageKit-yum.x86_64 > 0:0.3.12-1.fc10 > PackageKit-yum-plugin.x86_64 > 0:0.3.12-1.fc10 > evolution.x86_64 > 0:2.24.2-2.fc10 > evolution-help.x86_64 > 0:2.24.2-2.fc10 > evolution-perl.x86_64 > 0:2.24.2-2.fc10 > gnome-packagekit.x86_64 > 0:0.3.12-1.fc10 > krb5-auth-dialog.x86_64 > 0:0.7-7.fc9 > > Complete! > [root at localhost sysuser]# sudo chkconfig network on > [root at localhost sysuser]# sudo service network stop > Shutting down loopback interface: [ OK ] > [root at localhost sysuser]# sudo service network start > Bringing up loopback interface: [ OK ] > [root at localhost sysuser]# sudo create-ovirt-network > Currently active bridges: > ------------------------- > bridge name bridge id STP enabled interfaces > pan0 8000.000000000000 no > virbr0 8000.000000000000 yes > > Currently defined libvirt networks: > ----------------------------------- > libvir: Remote error : unable to connect to > '/var/run/libvirt/libvirt-sock': No such file or directory > error: failed to connect to the hypervisor > > Removing ovirtbr0 > Done Removing ovirtbr0 > Network ovirtbr0 defined from /tmp/tmp.uBtmBwfX65 > > Network ovirtbr0 started > > Network ovirtbr0 marked as autostarted > > net.ipv4.ip_forward = 1 > augtool> set /files/etc/sysctl.conf/net.ipv4.ip_forward 1 > augtool> save > Saved 1 file(s) > augtool> > Shutting down dnsmasq: [FAILED] > Starting dnsmasq: [ OK ] > Currently active bridges: > ------------------------- > bridge name bridge id STP enabled interfaces > ovirtbr0 8000.000000000000 no > pan0 8000.000000000000 no > virbr0 8000.000000000000 yes > > Currently defined libvirt networks: > ----------------------------------- > Name State Autostart > ----------------------------------------- > default active yes > ovirtbr0 active yes > > > [root at localhost sysuser]# > > > > > ------------------------------------------------------------------------ > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel -- |=- 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 Sun Dec 28 03:31:02 2008 From: pmyers at redhat.com (Perry Myers) Date: Sat, 27 Dec 2008 22:31:02 -0500 Subject: [Ovirt-devel] Re: Fw: Install problems on fresh F10 In-Reply-To: References: <49550243.5060507@redhat.com> <49552EA2.7030307@redhat.com> Message-ID: <4956F2F6.6020407@redhat.com> Daniel Galeus wrote: > rehi, > > i made a new fresh f10 install, updated with latest fixes, and then > tried again to install. > > i suggest that you first take a look at the attached console.txt to see > what i did, and if i made any obvious errors. Sure thing. I'll put some comments inline below... > i still had the network problem, as you can see in console.txt line 292 > i also had the libvirt-sock error at line 322 > i did get-ovirt-appliance using a local file at line 369, and you see > the filenames just above. > > will send ovirt-host.log and logs from appliance in separate mails. > > ciao, > bs66 > > ----- Original Message ----- From: "Perry Myers" > To: "Daniel Galeus" > Sent: Friday, December 26, 2008 8:21 PM > Subject: SPAM(6.1) Re: Fw: Install problems on fresh F10 > > >> Daniel Galeus wrote: >>> i have and had physical.priv.ovirt.org in Hosts, but it's >>> "unavailable (enabled)". >>> please find attached the log files. i hope i got it right. >>> >>> unfortunatelly i'm a windows guy trying to convert to linux and open >>> source, which makes me ask a lot of basic questions. but i hope i >>> learn quick while doing. >> >> No problem. I'll try to help as much as I can. :) >> >> The logs for the most part look ok. The only thing odd that I saw is >> that you have a few instances in the taskomatic.log where it says it >> can't connect to the database. That is a little weird... if you're >> going to reinstall send me the logs right after the appliance boots >> the first time so I can see how the install went. >> >> And then run the virsh commands from the appliance to physical.priv as >> I suggested in the earlier email... That'll give me an idea of what >> might be going on. Also on the host, grab /var/log/ovirt*.log as well. >> >> Thanks, >> >> Perry >> > [sysuser at localhost ~]$ su > Password: > [root at localhost sysuser]# sudo rpm -ivh > http://ovirt.org/repos/ovirt/ovirt-release-LATEST.noarch.rpm > Retrieving http://ovirt.org/repos/ovirt/ovirt-release-LATEST.noarch.rpm > Preparing... ########################################### > [100%] > 1:ovirt-release ########################################### > [100%] > > [root at localhost sysuser]# sudo yum update --enablerepo=ovirt > Loaded plugins: refresh-packagekit > ovirt | 951 B > 00:00 ovirt/primary | 7.7 > kB 00:01 > ovirt > 26/26 > Setting up Update Process > No Packages marked for Update > > [root at localhost sysuser]# sudo yum install --enablerepo=ovirt > ovirt-appliance python-virtinst > Loaded plugins: refresh-packagekit > Setting up Install Process > Parsing package install arguments > Resolving Dependencies > --> Running transaction check > ---> Package ovirt-appliance.noarch 0:0.96-1.fc10 set to be updated > --> Processing Dependency: libvirt >= 0.4.6-2 for package: ovirt-appliance > --> Processing Dependency: kvm >= 78-4 for package: ovirt-appliance > --> Processing Dependency: qemu-img for package: ovirt-appliance > --> Processing Dependency: virt-viewer-plugin for package: ovirt-appliance > --> Processing Dependency: augeas for package: ovirt-appliance > ---> Package python-virtinst.noarch 0:0.400.0-5.fc10 set to be updated > --> Processing Dependency: libvirt-python >= 0.4.5-2.fc10 for package: > python-virtinst > --> Running transaction check > ---> Package kvm.x86_64 0:78-4.1ovirt.fc10 set to be updated > --> Processing Dependency: etherboot-roms-kvm for package: kvm > ---> Package libvirt-python.x86_64 0:0.5.1-2.fc10 set to be updated > ---> Package qemu-img.x86_64 0:0.9.1-10.fc10 set to be updated > ---> Package augeas.x86_64 0:0.3.5-1.fc10 set to be updated > --> Processing Dependency: augeas-libs = 0.3.5-1.fc10 for package: augeas > --> Processing Dependency: libfa.so.0()(64bit) for package: augeas > --> Processing Dependency: libaugeas.so.0()(64bit) for package: augeas > ---> Package libvirt.x86_64 0:0.5.1-2.fc10 set to be updated > --> Processing Dependency: iscsi-initiator-utils for package: libvirt > --> Processing Dependency: bridge-utils for package: libvirt > --> Processing Dependency: libxenstore.so.3.0()(64bit) for package: libvirt > ---> Package virt-viewer-plugin.x86_64 0:0.0.3-3ovirt1.fc9 set to be > updated > --> Processing Dependency: vinagre for package: virt-viewer-plugin > --> Running transaction check > ---> Package augeas-libs.x86_64 0:0.3.5-1.fc10 set to be updated > ---> Package iscsi-initiator-utils.x86_64 0:6.2.0.870-1.0.fc10 set to be > updated > ---> Package bridge-utils.x86_64 0:1.2-6.fc10 set to be updated > ---> Package xen-libs.x86_64 0:3.3.0-1.fc10 set to be updated > ---> Package vinagre.x86_64 0:2.24.2-1.fc10 set to be updated > --> Processing Dependency: libavahi-gobject.so.0()(64bit) for package: > vinagre > --> Processing Dependency: libgtk-vnc-1.0.so.0()(64bit) for package: > vinagre > --> Processing Dependency: libavahi-ui.so.0()(64bit) for package: vinagre > ---> Package etherboot-roms-kvm.x86_64 0:5.4.4-4.fc10 set to be updated > --> Running transaction check > ---> Package gtk-vnc.x86_64 0:0.3.8-1.fc10 set to be updated > ---> Package avahi-ui.x86_64 0:0.6.22-11.fc10 set to be updated > ---> Package avahi-gobject.x86_64 0:0.6.22-11.fc10 set to be updated > --> Finished Dependency Resolution > > Dependencies Resolved > > ================================================================================ > > Package Arch Version > Repository Size > ================================================================================ > > Installing: > ovirt-appliance noarch 0.96-1.fc10 > ovirt 15 k > python-virtinst noarch 0.400.0-5.fc10 updates > 315 k > Installing for dependencies: > augeas x86_64 0.3.5-1.fc10 > ovirt 20 k > augeas-libs x86_64 0.3.5-1.fc10 ovirt > 186 k > avahi-gobject x86_64 0.6.22-11.fc10 > fedora 29 k > avahi-ui x86_64 0.6.22-11.fc10 > fedora 31 k > bridge-utils x86_64 1.2-6.fc10 > fedora 28 k > etherboot-roms-kvm x86_64 5.4.4-4.fc10 fedora > 126 k > gtk-vnc x86_64 0.3.8-1.fc10 > updates 85 k > iscsi-initiator-utils x86_64 6.2.0.870-1.0.fc10 updates > 627 k > kvm x86_64 78-4.1ovirt.fc10 ovirt > 844 k > libvirt x86_64 0.5.1-2.fc10 updates > 1.7 M > libvirt-python x86_64 0.5.1-2.fc10 updates > 103 k > qemu-img x86_64 0.9.1-10.fc10 > fedora 75 k > vinagre x86_64 2.24.2-1.fc10 updates > 1.2 M > virt-viewer-plugin x86_64 0.0.3-3ovirt1.fc9 ovirt > 9.7 k > xen-libs x86_64 3.3.0-1.fc10 fedora > 174 k > > Transaction Summary > ================================================================================ > > Install 17 Package(s) Update 0 Package(s) > Remove 0 Package(s) > Total download size: 5.5 M > Is this ok [y/N]: y > Downloading Packages: > (1/17): virt-viewer-plugin-0.0.3-3ovirt1.fc9.x86_64.rpm | 9.7 kB > 00:04 (2/17): ovirt-appliance-0.96-1.fc10.noarch.rpm | 15 > kB 00:07 (3/17): > augeas-0.3.5-1.fc10.x86_64.rpm | 20 kB 00:10 > ftp://ftp.sunet.se/pub/Linux/distributions/fedora/linux/releases/10/Everything/x86_64/os/Packages/bridge-utils-1.2-6.fc10.x86_64.rpm: > [Errno 4] IOError: > Trying other mirror. > http://mirrors.se.eu.kernel.org/fedora/releases/10/Everything/x86_64/os/Packages/bridge-utils-1.2-6.fc10.x86_64.rpm: > [Errno 4] IOError: resolution')> > Trying other mirror. > (4/17): bridge-utils-1.2-6.fc10.x86_64.rpm | 28 kB > 00:06 (5/17): avahi-gobject-0.6.22-11.fc10.x86_64.rpm | 29 > kB 00:08 (6/17): > avahi-ui-0.6.22-11.fc10.x86_64.rpm | 31 kB 00:09 > (7/17): qemu-img-0.9.1-10.fc10.x86_64.rpm | 75 kB > 00:18 > http://mirrors.se.eu.kernel.org/fedora/updates/10/x86_64/gtk-vnc-0.3.8-1.fc10.x86_64.rpm: > [Errno 4] IOError: resolution')> > Trying other mirror. > (8/17): gtk-vnc-0.3.8-1.fc10.x86_64.rpm | 85 kB > 00:14 (9/17): libvirt-python-0.5.1-2.fc10.x86_64.rpm | 103 > kB 00:07 (10/17): > etherboot-roms-kvm-5.4.4-4.fc10.x86_64.rpm | 126 kB 00:16 > (11/17): xen-libs-3.3.0-1.fc10.x86_64.rpm | 174 kB > 00:25 (12/17): augeas-libs-0.3.5-1.fc10.x86_64.rpm | 186 > kB 00:23 (13/17): > python-virtinst-0.400.0-5.fc10.noarch.rpm | 315 kB 00:27 > (14/17): iscsi-initiator-utils-6.2.0.870-1.0.fc10.x86_64 | 627 kB > 01:55 (15/17): kvm-78-4.1ovirt.fc10.x86_64.rpm | 844 > kB 00:59 (16/17): > vinagre-2.24.2-1.fc10.x86_64.rpm | 1.2 MB 02:18 > (17/17): libvirt-0.5.1-2.fc10.x86_64.rpm | 1.7 MB > 03:12 > -------------------------------------------------------------------------------- Looks like you're having some intermittent mirror issues. You might want to edit your /etc/yum.repos.d/fedora.repo and fedora-updates.repo to use a specific baseurl instead of a mirrorlist. But it looks like all of the packages installed ok so this might be a non-issue. > Total 6.3 kB/s | 5.5 MB > 14:50 ============================== Entering rpm code > =============================== > Running rpm_check_debug > Running Transaction Test > Finished Transaction Test > Transaction Test Succeeded > Running Transaction > Installing : > qemu-img 1/17 > Installing : > iscsi-initiator-utils 2/17 > Installing : > avahi-gobject 3/17 > Installing : > xen-libs 4/17 > Installing : > bridge-utils 5/17 > Installing : > libvirt 6/17 > Installing : > libvirt-python 7/17 > Installing : > augeas-libs 8/17 > Installing : > augeas 9/17 > Installing : avahi-ui > 10/17 Installing : > gtk-vnc 11/17 > Installing : vinagre > 12/17 Installing : > virt-viewer-plugin 13/17 > Installing : etherboot-roms-kvm > 14/17 Installing : > kvm 15/17 > Installing : python-virtinst > 16/17 Installing : > ovirt-appliance 17/17 > =============================== Leaving rpm code > =============================== > > Installed: > ovirt-appliance.noarch 0:0.96-1.fc10 python-virtinst.noarch > 0:0.400.0-5.fc10 > Dependency Installed: > augeas.x86_64 > 0:0.3.5-1.fc10 > augeas-libs.x86_64 > 0:0.3.5-1.fc10 > avahi-gobject.x86_64 > 0:0.6.22-11.fc10 > avahi-ui.x86_64 > 0:0.6.22-11.fc10 > bridge-utils.x86_64 > 0:1.2-6.fc10 > etherboot-roms-kvm.x86_64 > 0:5.4.4-4.fc10 gtk-vnc.x86_64 > 0:0.3.8-1.fc10 > iscsi-initiator-utils.x86_64 > 0:6.2.0.870-1.0.fc10 kvm.x86_64 > 0:78-4.1ovirt.fc10 > libvirt.x86_64 > 0:0.5.1-2.fc10 > libvirt-python.x86_64 > 0:0.5.1-2.fc10 qemu-img.x86_64 > 0:0.9.1-10.fc10 > vinagre.x86_64 > 0:2.24.2-1.fc10 > virt-viewer-plugin.x86_64 > 0:0.0.3-3ovirt1.fc9 xen-libs.x86_64 > 0:3.3.0-1.fc10 > Complete! > > [root at localhost sysuser]# cd dgtmp > > [root at localhost dgtmp]# ls -l > total 360704 > -rwxr-xr-x 1 sysuser sysuser 368988893 2008-12-23 21:59 > ovirt-appliance-0.96-x86_64.tar.bz2 > -rwxr-xr-x 1 sysuser sysuser 77 2008-12-23 20:22 > ovirt-appliance-0.96-x86_64.tar.bz2.sha1sum > > [root at localhost dgtmp]# sudo service NetworkManager stop > Stopping NetworkManager daemon: [ OK ] > > [root at localhost dgtmp]# sudo yum remove NetworkManager\* > Loaded plugins: refresh-packagekit > Setting up Remove Process > Resolving Dependencies > --> Running transaction check > ---> Package NetworkManager-gnome.x86_64 1:0.7.0-0.12.svn4326.fc10 set > to be erased > ---> Package NetworkManager.x86_64 1:0.7.0-0.12.svn4326.fc10 set to be > erased > ---> Package NetworkManager-glib.x86_64 1:0.7.0-0.12.svn4326.fc10 set to > be erased > --> Processing Dependency: libnm_glib.so.0()(64bit) for package: evolution > --> Processing Dependency: libnm_glib.so.0()(64bit) for package: > krb5-auth-dialog > --> Processing Dependency: libnm_glib.so.0()(64bit) for package: PackageKit > --> Running transaction check > ---> Package evolution.x86_64 0:2.24.2-2.fc10 set to be erased > --> Processing Dependency: evolution = 2.24.2-2.fc10 for package: > evolution-help > --> Processing Dependency: evolution = 2.24.2-2.fc10 for package: > evolution-perl > ---> Package krb5-auth-dialog.x86_64 0:0.7-7.fc9 set to be erased > ---> Package PackageKit.x86_64 0:0.3.12-1.fc10 set to be erased > --> Processing Dependency: PackageKit = 0.3.12-1.fc10 for package: > PackageKit-yum > --> Processing Dependency: PackageKit >= 0.3.11 for package: > gnome-packagekit > --> Processing Dependency: PackageKit = 0.3.12-1.fc10 for package: > PackageKit-glib > --> Processing Dependency: PackageKit for package: PackageKit-yum-plugin > --> Processing Dependency: PackageKit for package: PackageKit-udev-helper > --> Running transaction check > ---> Package gnome-packagekit.x86_64 0:0.3.12-1.fc10 set to be erased > ---> Package PackageKit-yum-plugin.x86_64 0:0.3.12-1.fc10 set to be erased > ---> Package evolution-perl.x86_64 0:2.24.2-2.fc10 set to be erased > ---> Package evolution-help.x86_64 0:2.24.2-2.fc10 set to be erased > ---> Package PackageKit-glib.x86_64 0:0.3.12-1.fc10 set to be erased > --> Processing Dependency: PackageKit-glib = 0.3.12-1.fc10 for package: > PackageKit-gstreamer-plugin > ---> Package PackageKit-yum.x86_64 0:0.3.12-1.fc10 set to be erased > ---> Package PackageKit-udev-helper.x86_64 0:0.3.12-1.fc10 set to be erased > --> Running transaction check > ---> Package PackageKit-gstreamer-plugin.x86_64 0:0.3.12-1.fc10 set to > be erased > --> Finished Dependency Resolution > > Dependencies Resolved > > ================================================================================ > > Package Arch Version Repository > > Size > ================================================================================ > > Removing: > NetworkManager x86_64 1:0.7.0-0.12.svn4326.fc10 installed > 2.9 M > NetworkManager-glib x86_64 1:0.7.0-0.12.svn4326.fc10 installed > 370 k > NetworkManager-gnome x86_64 1:0.7.0-0.12.svn4326.fc10 installed > 889 k > Removing for dependencies: > PackageKit x86_64 0.3.12-1.fc10 installed > 1.1 M > PackageKit-glib x86_64 0.3.12-1.fc10 installed > 321 k > PackageKit-gstreamer-plugin x86_64 0.3.12-1.fc10 installed > 139 k > PackageKit-udev-helper x86_64 0.3.12-1.fc10 installed > 126 k > PackageKit-yum x86_64 0.3.12-1.fc10 installed > 334 k > PackageKit-yum-plugin x86_64 0.3.12-1.fc10 installed > 128 k > evolution x86_64 2.24.2-2.fc10 > installed 38 M > evolution-help x86_64 2.24.2-2.fc10 > installed 53 M > evolution-perl x86_64 2.24.2-2.fc10 installed > 7.6 k > gnome-packagekit x86_64 0.3.12-1.fc10 installed > 6.0 M > krb5-auth-dialog x86_64 0.7-7.fc9 > installed 56 k > > Transaction Summary > ================================================================================ > > Install 0 Package(s) Update 0 Package(s) > Remove 14 Package(s) > Is this ok [y/N]: y > Downloading Packages: > ============================== Entering rpm code > =============================== > Running rpm_check_debug > Running Transaction Test > Finished Transaction Test > Transaction Test Succeeded > Running Transaction > Erasing : > krb5-auth-dialog 1/14 > Erasing : > NetworkManager-glib 2/14 > Erasing : > PackageKit-yum-plugin 3/14 > Erasing : > PackageKit-glib 4/14 > Erasing : > NetworkManager-gnome 5/14 > Erasing : > gnome-packagekit 6/14 > Erasing : > PackageKit 7/14 > Erasing : > NetworkManager 8/14 > Erasing : > evolution-perl 9/14 > Erasing : PackageKit-udev-helper > 10/14 Erasing : > evolution-help 11/14 > Erasing : evolution > 12/14 Erasing : > PackageKit-yum 13/14 > Erasing : PackageKit-gstreamer-plugin > 14/14 Unable to send message to PackageKit > =============================== Leaving rpm code > =============================== > > Removed: > NetworkManager.x86_64 > 1:0.7.0-0.12.svn4326.fc10 > NetworkManager-glib.x86_64 > 1:0.7.0-0.12.svn4326.fc10 > NetworkManager-gnome.x86_64 > 1:0.7.0-0.12.svn4326.fc10 > Dependency Removed: > PackageKit.x86_64 > 0:0.3.12-1.fc10 > PackageKit-glib.x86_64 > 0:0.3.12-1.fc10 > PackageKit-gstreamer-plugin.x86_64 > 0:0.3.12-1.fc10 > PackageKit-udev-helper.x86_64 > 0:0.3.12-1.fc10 PackageKit-yum.x86_64 > 0:0.3.12-1.fc10 > PackageKit-yum-plugin.x86_64 > 0:0.3.12-1.fc10 evolution.x86_64 > 0:2.24.2-2.fc10 > evolution-help.x86_64 > 0:2.24.2-2.fc10 > evolution-perl.x86_64 > 0:2.24.2-2.fc10 > gnome-packagekit.x86_64 > 0:0.3.12-1.fc10 > krb5-auth-dialog.x86_64 > 0:0.7-7.fc9 > Complete! > > [root at localhost dgtmp]# sudo chkconfig network on > > [root at localhost dgtmp]# sudo service network stop > Shutting down loopback interface: [ OK ] > > [root at localhost dgtmp]# cat /etc/sysconfig/network-scripts/ifcfg-eth0 > # Marvell Technology Group Ltd. 88E8053 PCI-E Gigabit Ethernet Controller > DEVICE=eth0 > HWADDR=00:17:31:3f:20:85 > ONBOOT=no > > [root at localhost dgtmp]# gedit /etc/sysconfig/network-scripts/ifcfg-eth0 > > [root at localhost dgtmp]# cat /etc/sysconfig/network-scripts/ifcfg-eth0 > # Marvell Technology Group Ltd. 88E8053 PCI-E Gigabit Ethernet Controller > DEVICE=eth0 > HWADDR=00:17:31:3f:20:85 > #ONBOOT=no > ONBOOT=yes > BOOTPROTO=dhcp > > [root at localhost dgtmp]# sudo service network start > Bringing up loopback interface: [ OK ] > Bringing up interface eth0: Determining IP information for eth0... done. > [ OK ] > [root at localhost dgtmp]# ping ftp.sunet.se > PING ftp.sunet.se (194.71.11.69) 56(84) bytes of data. > 64 bytes from ftp.sunet.se (194.71.11.69): icmp_seq=1 ttl=57 time=1132 ms > 64 bytes from ftp.sunet.se (194.71.11.69): icmp_seq=2 ttl=57 time=1062 ms > ^C > --- ftp.sunet.se ping statistics --- > 3 packets transmitted, 2 received, 33% packet loss, time 2634ms > rtt min/avg/max/mdev = 1062.122/1097.401/1132.680/35.279 ms, pipe 2 Ok, looks good so far. > [root at localhost dgtmp]# sudo create-ovirt-network > Currently active bridges: > ------------------------- > bridge name bridge id STP enabled interfaces > pan0 8000.000000000000 no > virbr0 8000.000000000000 yes > > Currently defined libvirt networks: > ----------------------------------- > libvir: Remote error : unable to connect to > '/var/run/libvirt/libvirt-sock': No such file or directory > error: failed to connect to the hypervisor The reason you're getting this error is that you didn't start the libvirt daemon after you did the yum install of ovirt-appliance and python-virtinst. The instructions say: > # Install additional RPMs from the oVirt repository: > > sudo yum install --enablerepo=ovirt ovirt-appliance python-virtinst > > # Restart libvirtd to pick up the newer version: > > sudo service libvirtd restart I see in the above console log where you do the yum install command, but you never followed it up with the libvirtd restart. In any case, this error is harmless since we make sure that libvirtd is started later in the create-ovirt-network script. So you can ignore this error. > Removing ovirtbr0 > Done Removing ovirtbr0 > Network ovirtbr0 defined from /tmp/tmp.PDSIWoiFCW > > Network ovirtbr0 started > > Network ovirtbr0 marked as autostarted > > net.ipv4.ip_forward = 1 > augtool> set /files/etc/sysctl.conf/net.ipv4.ip_forward 1 > augtool> save > Saved 1 file(s) > augtool> Shutting down dnsmasq: > [FAILED] > Starting dnsmasq: [ OK ] > Currently active bridges: > ------------------------- > bridge name bridge id STP enabled interfaces > ovirtbr0 8000.000000000000 no > pan0 8000.000000000000 no > virbr0 8000.000000000000 yes > > Currently defined libvirt networks: > ----------------------------------- > Name State Autostart > ----------------------------------------- > default active yes ovirtbr0 > active yes Ok this all looks good. > [root at localhost dgtmp]# ls -l > total 360704 > -rwxr-xr-x 1 sysuser sysuser 368988893 2008-12-23 21:59 > ovirt-appliance-0.96-x86_64.tar.bz2 > -rwxr-xr-x 1 sysuser sysuser 77 2008-12-23 20:22 > ovirt-appliance-0.96-x86_64.tar.bz2.sha1sum > > [root at localhost dgtmp]# sudo get-ovirt-appliance -l . > Using local files in . for appliance > performing checksum of ./ovirt-appliance-0.96-x86_64.tar.bz2 > checksum verified > ovirt-appliance/ovirt-appliance.xml > ovirt-appliance/get-ovirt-appliance > ovirt-appliance/create-ovirt-appliance > ovirt-appliance/ovirt-appliance-functions > ovirt-appliance/ovirt-appliance-sda.qcow2 > ovirt-appliance/create-ovirt-nodes > ovirt-appliance/ovirt-appliance-sdb.qcow2 > ovirt-appliance/create-ovirt-network > Appliance Disks installed to /var/lib/libvirt/images > Run create-ovirt-appliance to define and start the appliance > > [root at localhost dgtmp]# sudo create-ovirt-appliance > > > Creating guest ovirt-appliance... > Creating domain... | 0 B > 00:00 Domain ovirt-appliance defined from /tmp/tmp.8HrLyC6qiE > > [root at localhost dgtmp]# sudo virsh start ovirt-appliance > Domain ovirt-appliance started > > [root at localhost dgtmp]# sudo yum install virt-viewer > Setting up Install Process > Parsing package install arguments > Resolving Dependencies > --> Running transaction check > ---> Package virt-viewer.x86_64 0:0.0.3-3.fc10 set to be updated > --> Finished Dependency Resolution > > Dependencies Resolved > > ================================================================================ > > Package Arch Version > Repository Size > ================================================================================ > > Installing: > virt-viewer x86_64 0.0.3-3.fc10 > fedora 29 k > > Transaction Summary > ================================================================================ > > Install 1 Package(s) Update 0 Package(s) > Remove 0 Package(s) > Total download size: 29 k > Is this ok [y/N]: y > Downloading Packages: > virt-viewer-0.0.3-3.fc10.x86_64.rpm | 29 kB > 00:00 ============================== Entering rpm code > =============================== > Running rpm_check_debug > Running Transaction Test > Finished Transaction Test > Transaction Test Succeeded > Running Transaction > Installing : > virt-viewer 1/1 > =============================== Leaving rpm code > =============================== > > Installed: > virt-viewer.x86_64 > 0:0.0.3-3.fc10 > Complete! > > [root at localhost dgtmp]# sudo virt-viewer ovirt-appliance > > [root at localhost dgtmp]# sudo virt-viewer ovirt-appliance > > [root at localhost dgtmp]# sudo virsh shutdown ovirt-appliance > Domain ovirt-appliance is being shutdown > > [root at localhost dgtmp]# sudo virt-viewer ovirt-appliance > > [root at localhost dgtmp]# udo yum install --enablerepo=ovirt > ovirt-node-stateful ovirt-node-selinux > bash: udo: command not found > > [root at localhost dgtmp]# sudo yum install --enablerepo=ovirt > ovirt-node-stateful ovirt-node-selinux > fedora | 2.8 kB > 00:00 updates | 2.3 > kB 00:00 Setting up Install Process > Parsing package install arguments > Resolving Dependencies > --> Running transaction check > ---> Package ovirt-node-stateful.x86_64 0:0.96-1.fc10 set to be updated > --> Processing Dependency: ovirt-node = 0.96-1.fc10 for package: > ovirt-node-stateful > ---> Package ovirt-node-selinux.x86_64 0:0.96-1.fc10 set to be updated > --> Running transaction check > ---> Package ovirt-node.x86_64 0:0.96-1.fc10 set to be updated > --> Processing Dependency: libvirt-qpid >= 0.2.3 for package: ovirt-node > --> Processing Dependency: collectd-virt for package: ovirt-node > --> Processing Dependency: cyrus-sasl-gssapi for package: ovirt-node > --> Running transaction check > ---> Package libvirt-qpid.x86_64 0:0.2.9-0 set to be updated > --> Processing Dependency: qmf >= 0.3.722557 for package: libvirt-qpid > --> Processing Dependency: qpidc >= 0.3.722557 for package: libvirt-qpid > --> Processing Dependency: libqpidclient.so.0()(64bit) for package: > libvirt-qpid > --> Processing Dependency: libqpidcommon.so.0()(64bit) for package: > libvirt-qpid > --> Processing Dependency: libqmfagent.so.0()(64bit) for package: > libvirt-qpid > ---> Package collectd-virt.x86_64 0:4.5.1-2.1.fc10 set to be updated > --> Processing Dependency: collectd = 4.5.1-2.1.fc10 for package: > collectd-virt > ---> Package cyrus-sasl-gssapi.x86_64 0:2.1.22-19.fc10 set to be updated > --> Running transaction check > ---> Package collectd.x86_64 0:4.5.1-2.1.fc10 set to be updated > ---> Package qmf.x86_64 0:0.4.728142-1.fc10 set to be updated > ---> Package qpidc.x86_64 0:0.4.728142-1.fc10 set to be updated > --> Finished Dependency Resolution > > Dependencies Resolved > > ================================================================================ > > Package Arch Version > Repository Size > ================================================================================ > > Installing: > ovirt-node-selinux x86_64 0.96-1.fc10 ovirt > 7.5 k > ovirt-node-stateful x86_64 0.96-1.fc10 ovirt > 9.7 k > Installing for dependencies: > collectd x86_64 4.5.1-2.1.fc10 updates > 284 k > collectd-virt x86_64 4.5.1-2.1.fc10 > updates 13 k > cyrus-sasl-gssapi x86_64 2.1.22-19.fc10 > fedora 31 k > libvirt-qpid x86_64 0.2.9-0 > ovirt 70 k > ovirt-node x86_64 0.96-1.fc10 > ovirt 25 k > qmf x86_64 0.4.728142-1.fc10 updates > 137 k > qpidc x86_64 0.4.728142-1.fc10 updates > 809 k > > Transaction Summary > ================================================================================ > > Install 9 Package(s) Update 0 Package(s) > Remove 0 Package(s) > Total download size: 1.4 M > Is this ok [y/N]: y > Downloading Packages: > (1/9): ovirt-node-selinux-0.96-1.fc10.x86_64.rpm | 7.5 kB > 00:00 (2/9): ovirt-node-stateful-0.96-1.fc10.x86_64.rpm | 9.7 > kB 00:00 (3/9): > collectd-virt-4.5.1-2.1.fc10.x86_64.rpm | 13 kB 00:00 > (4/9): ovirt-node-0.96-1.fc10.x86_64.rpm | 25 kB > 00:00 (5/9): cyrus-sasl-gssapi-2.1.22-19.fc10.x86_64.rpm | 31 > kB 00:00 (6/9): > libvirt-qpid-0.2.9-0.x86_64.rpm | 70 kB 00:01 > (7/9): qmf-0.4.728142-1.fc10.x86_64.rpm | 137 kB > 00:01 (8/9): collectd-4.5.1-2.1.fc10.x86_64.rpm | 284 > kB 00:02 (9/9): > qpidc-0.4.728142-1.fc10.x86_64.rpm | 809 kB 00:07 > -------------------------------------------------------------------------------- > > Total 54 kB/s | 1.4 MB > 00:25 ============================== Entering rpm code > =============================== > Running rpm_check_debug > Running Transaction Test > Finished Transaction Test > Transaction Test Succeeded > Running Transaction > Installing : > qpidc 1/9 > Installing : > qmf 2/9 > Installing : > libvirt-qpid 3/9 > Installing : > cyrus-sasl-gssapi 4/9 > Installing : > collectd 5/9 > Installing : > collectd-virt 6/9 > Installing : > ovirt-node 7/9 > Installing : > ovirt-node-stateful 8/9 > Installing : > ovirt-node-selinux 9/9 > =============================== Leaving rpm code > =============================== > > Installed: > ovirt-node-selinux.x86_64 > 0:0.96-1.fc10 > ovirt-node-stateful.x86_64 > 0:0.96-1.fc10 > Dependency Installed: > collectd.x86_64 > 0:4.5.1-2.1.fc10 > collectd-virt.x86_64 > 0:4.5.1-2.1.fc10 > cyrus-sasl-gssapi.x86_64 > 0:2.1.22-19.fc10 > libvirt-qpid.x86_64 > 0:0.2.9-0 > ovirt-node.x86_64 > 0:0.96-1.fc10 qmf.x86_64 > 0:0.4.728142-1.fc10 > qpidc.x86_64 > 0:0.4.728142-1.fc10 > Complete! > > [root at localhost dgtmp]# sudo ovirt-install-node-stateful > This script will make a number of changes to your system to enable it > to work as an oVirt node. You can later undo these changes by > running /usr/sbin/ovirt-uninstall-host. Do you want to proceed? [y/N]? > y > iptables: Flushing firewall rules: [ OK ] > iptables: Setting chains to policy ACCEPT: filter [ OK ] > iptables: Unloading modules: [ OK ] > iptables: Applying firewall rules: [ OK ] > Stopping libvirtd daemon: [ OK ] > Starting libvirtd daemon: [ OK ] > Stopping collectd: [FAILED] > Starting collectd: libvir: Remote error : unable to connect to > '/var/run/libvirt/libvirt-sock-ro': Connection refused > [ OK ] > Shutting down ovirt-listen-awake: [FAILED] > Starting ovirt-listen-awake: [ OK ] > Stopping libvirt-qpid daemon: [FAILED] > Starting libvirt-qpid daemon: libvirt-qpid: Symbol > `_ZTVN4qpid10management16ManagementObjectE' has different size in shared > object, consider re-linking This error was due to qpid RPMs being updated in Fedora w/o a rebuild of libvirt-qpid package. I've rebuilt this package manually and uploaded it to the ovirt.org repo. You'll need to do the following to get it installed: sudo rpm --erase libvirt-qpid --nodeps sudo yum clean all sudo rm -Rf /var/cache/yum/* sudo yum install libvirt-qpid --enablerepo=ovirt sudo service libvirt-qpid restart That should clear up the issue with libvirt-qpid due to the bad build. > [ OK ] > Shutting down ntpd: [FAILED] > ntpdate: Synchronizing with time server: [ OK ] > Starting ntpd: [ OK ] > > [root at localhost dgtmp]# sudo virsh start ovirt-appliance > Domain ovirt-appliance started > > [root at localhost dgtmp]# # *** physical.priv.ovirt.org status is now > "unavailable (enabled)" This is related to the libvirt-qpid error above... This should go away if you retry things with the newer package. > [root at localhost dgtmp]# > [root at localhost dgtmp]# mkdir log > > [root at localhost dgtmp]# cd log > > [root at localhost log]# ls -l > total 0 > > [root at localhost log]# > [root at localhost log]# sudo service libvirtd restart > Stopping libvirtd daemon: [ OK ] > Starting libvirtd daemon: [ OK ] > > [root at localhost log]# sudo virsh net-list --all > Name State Autostart > ----------------------------------------- > default active yes ovirtbr0 > active yes > [root at localhost log]# sudo create-ovirt-network > Currently active bridges: > ------------------------- > bridge name bridge id STP enabled interfaces > ovirtbr0 8000.000000000000 no > pan0 8000.000000000000 no > virbr0 8000.000000000000 yes > > Currently defined libvirt networks: > ----------------------------------- > Name State Autostart > ----------------------------------------- > default active yes ovirtbr0 > active yes > > Removing ovirtbr0 > Network ovirtbr0 destroyed > > Network ovirtbr0 has been undefined > > Done Removing ovirtbr0 > Network ovirtbr0 defined from /tmp/tmp.J6MFg9rM8s > > Network ovirtbr0 started > > Network ovirtbr0 marked as autostarted > > net.ipv4.ip_forward = 1 > augtool> set /files/etc/sysctl.conf/net.ipv4.ip_forward 1 > augtool> save > augtool> Shutting down dnsmasq: [ > OK ] > Starting dnsmasq: [ OK ] > Currently active bridges: > ------------------------- > bridge name bridge id STP enabled interfaces > ovirtbr0 8000.000000000000 no > pan0 8000.000000000000 no > virbr0 8000.000000000000 yes > > Currently defined libvirt networks: > ----------------------------------- > Name State Autostart > ----------------------------------------- > default active yes ovirtbr0 > active yes Ok, this may be a problem. I've seen issues with the appliance if you recreate the ovirt-network after booting the appliance the first time... What you'll want to do now is reset your appliance with: sudo get-ovirt-appliance -l . sudo create-ovirt-appliance sudo virsh start ovirt-appliance (wait for the appliance to completely boot) sudo virsh shutdown ovirt-appliance sudo service libvirtd restart sudo virsh start ovirt-appliance Now you should be able to see the physical host come up as available (enabled). > [root at localhost log]# sudo virsh start ovirt-applianceDomain > ovirt-appliance started > > [root at localhost log]# # *** physical.priv.ovirt.org status is now > "unavailable (enabled)" > > [root at localhost log]# sudo virsh shutdown ovirt-applianceDomain > ovirt-appliance is being shutdown > > [root at localhost log]# sudo virt-viewer ovirt-applianceNo protocol specified > > (virt-viewer:7322): Gtk-WARNING **: cannot open display: :0.0 > > [root at localhost log]# sudo ovirt-install-node-stateful There shouldn't be a need to rerun this script, but it shouldn't hurt anything if you do. > This script will make a number of changes to your system to enable it > to work as an oVirt node. You can later undo these changes by > running /usr/sbin/ovirt-uninstall-host. Do you want to proceed? [y/N]? > y > iptables: Flushing firewall rules: [ OK ] > iptables: Setting chains to policy ACCEPT: filter [ OK ] > iptables: Unloading modules: [ OK ] > iptables: Applying firewall rules: [ OK ] > Stopping libvirtd daemon: [ OK ] > Starting libvirtd daemon: [ OK ] > Stopping collectd: [ OK ] > Starting collectd: libvir: Remote error : unable to connect to > '/var/run/libvirt/libvirt-sock-ro': Connection refused > [ OK ] > Shutting down ovirt-listen-awake: [ OK ] > Starting ovirt-listen-awake: [ OK ] > Stopping libvirt-qpid daemon: [FAILED] > Starting libvirt-qpid daemon: libvirt-qpid: Symbol > `_ZTVN4qpid10management16ManagementObjectE' has different size in shared > object, consider re-linking > [ OK ] > Shutting down ntpd: [ OK ] > ntpdate: Synchronizing with time server: [ OK ] > Starting ntpd: [ OK ] > > [root at localhost log]# sudo virsh start ovirt-applianceDomain > ovirt-appliance started > > [root at localhost log]# sudo virt-viewer ovirt-appliance > No protocol specified > > (virt-viewer:7874): Gtk-WARNING **: cannot open display: :0.0 > [root at localhost log]# sudo virsh shutdown ovirt-appliance > Domain ovirt-appliance is being shutdown > > [root at localhost log]# sudo service libvirtd restart > Stopping libvirtd daemon: [ OK ] > Starting libvirtd daemon: [ OK ] > [root at localhost log]# sudo virsh start ovirt-appliance > Domain ovirt-appliance started > > [root at localhost log]# # *** physical.priv.ovirt.org status is now > "unavailable (enabled)" > > [root at localhost log]# ssh -l root 192.168.50.2 cat /root/otto2.tar.gz > >otto2.tar.gz > The authenticity of host '192.168.50.2 (192.168.50.2)' can't be > established. > RSA key fingerprint is a9:0a:30:13:2a:46:9e:b3:25:dd:0e:07:ae:bb:f2:fe. > Are you sure you want to continue connecting (yes/no)? yes > Warning: Permanently added '192.168.50.2' (RSA) to the list of known hosts. > root at 192.168.50.2's password: > [root at localhost log]# ls -l > total 1444 > -rw-r--r-- 1 root root 1472761 2008-12-27 00:34 otto2.tar.gz I think the core problems above were: 1. libvirtd error was because you didn't do the service libvirtd restart after doing the yum install ovirt-appliance. This is covered in the install instructions 2. libvirt-qpid issues that are now resolved with the new packages on ovirt.org repositories. This should be resolved until the qpid team releases another qpid package that breaks binary compatibility again... (We're working with them to try to limit this but they are still in rapid development so it may happen again) 3. Running create-ovirt-network after booting the appliance. I need to add a note to the install docs that indicates that this is problematic. So follow the instructions I provided for re-installing the libvirt-qpid package and then follow the instructions for redoing the get-ovirt-appliance sequence. That should clear things up. Thanks, Perry From pmyers at redhat.com Sun Dec 28 05:02:03 2008 From: pmyers at redhat.com (Perry Myers) Date: Sun, 28 Dec 2008 00:02:03 -0500 Subject: [Ovirt-devel] cobbler import of a repo with only noarch packages in it Message-ID: <4957084B.8060503@redhat.com> I'm trying to do a cobbler import of a directory structure that only has noarch packages in it. I'm using the import to create a minimal pxe boot environment without needing to mirror all of the packages (we just use external repos for the packages) However, when I try to do a cobbler import of a directory structure that only contains noarch packages I get the following error: > + cobbler import --name=Fedora-10 --arch=x86_64 --path=/var/www/cobbler/ks_mirror/Fedora-10-x86_64 > sending incremental file list > > sent 392 bytes received 16 bytes 816.00 bytes/sec > total size is 134808812 speedup is 330413.75 > Given arch (x86_64) not found on imported tree /var/www/cobbler/ks_mirror/Fedora-10-x86_64/Packages > > - rsync -a '/var/www/cobbler/ks_mirror/Fedora-10-x86_64/' /var/www/cobbler/ks_mirror/Fedora-10-x86_64 --exclude-from=/etc/cobbler/rsync.exclude --progress > ---------------- (adding distros) > - found content (breed=redhat) at /var/www/cobbler/ks_mirror/Fedora-10-x86_64/images/pxeboot I know in the past we were able to import a directory structure with only noarch packages and still specify an arch (x86_64 or i386) and it didn't fail like above. Is this a recent change or restriction? Should we just add a single arch specific package to the directory structure to get around this? Thanks, Perry -- |=- Red Hat, Engineering, Emerging Technologies, Boston -=| |=- Email: pmyers at redhat.com -=| |=- Office: +1 412 474 3552 Mobile: +1 703 362 9622 -=| |=- GnuPG: E65E4F3D 88F9 F1C9 C2F3 1303 01FE 817C C5D2 8B91 E65E 4F3D -=| From pmyers at redhat.com Sun Dec 28 05:05:02 2008 From: pmyers at redhat.com (Perry Myers) Date: Sun, 28 Dec 2008 00:05:02 -0500 Subject: [Ovirt-devel] cobbler import of a repo with only noarch packages in it In-Reply-To: <4957084B.8060503@redhat.com> References: <4957084B.8060503@redhat.com> Message-ID: <495708FE.6090400@redhat.com> Perry Myers wrote: > I'm trying to do a cobbler import of a directory structure that only has > noarch packages in it. I'm using the import to create a minimal pxe > boot environment without needing to mirror all of the packages (we just > use external repos for the packages) > > However, when I try to do a cobbler import of a directory structure that > only contains noarch packages I get the following error: >> + cobbler import --name=Fedora-10 --arch=x86_64 >> --path=/var/www/cobbler/ks_mirror/Fedora-10-x86_64 >> sending incremental file list >> >> sent 392 bytes received 16 bytes 816.00 bytes/sec >> total size is 134808812 speedup is 330413.75 >> Given arch (x86_64) not found on imported tree >> /var/www/cobbler/ks_mirror/Fedora-10-x86_64/Packages >> >> - rsync -a '/var/www/cobbler/ks_mirror/Fedora-10-x86_64/' >> /var/www/cobbler/ks_mirror/Fedora-10-x86_64 >> --exclude-from=/etc/cobbler/rsync.exclude --progress >> ---------------- (adding distros) >> - found content (breed=redhat) at >> /var/www/cobbler/ks_mirror/Fedora-10-x86_64/images/pxeboot > > I know in the past we were able to import a directory structure with > only noarch packages and still specify an arch (x86_64 or i386) and it > didn't fail like above. Is this a recent change or restriction? Should > we just add a single arch specific package to the directory structure to > get around this? So, for those of you using the 0.96 release or building new appliances from the development repositories it appears that a new version of cobbler in Fedora has broken the ovirt-appliance. I've posted the above question to the cobbler mailing list to find out if this was an intended change or something that recently broke in cobbler. Hopefully it is the latter and an update to the cobbler package will fix this. The alternative is that we need to change the appliance build procedure to account for this change and we'll have to do a 0.96-2 release to fix this. Thanks, Perry From pmyers at redhat.com Sun Dec 28 05:06:53 2008 From: pmyers at redhat.com (Perry Myers) Date: Sun, 28 Dec 2008 00:06:53 -0500 Subject: [Ovirt-devel] cobbler import of a repo with only noarch packages in it In-Reply-To: <495708FE.6090400@redhat.com> References: <4957084B.8060503@redhat.com> <495708FE.6090400@redhat.com> Message-ID: <4957096D.5020105@redhat.com> Perry Myers wrote: > Perry Myers wrote: >> I'm trying to do a cobbler import of a directory structure that only >> has noarch packages in it. I'm using the import to create a minimal >> pxe boot environment without needing to mirror all of the packages (we >> just use external repos for the packages) >> >> However, when I try to do a cobbler import of a directory structure >> that only contains noarch packages I get the following error: >>> + cobbler import --name=Fedora-10 --arch=x86_64 >>> --path=/var/www/cobbler/ks_mirror/Fedora-10-x86_64 >>> sending incremental file list >>> >>> sent 392 bytes received 16 bytes 816.00 bytes/sec >>> total size is 134808812 speedup is 330413.75 >>> Given arch (x86_64) not found on imported tree >>> /var/www/cobbler/ks_mirror/Fedora-10-x86_64/Packages >>> >>> - rsync -a '/var/www/cobbler/ks_mirror/Fedora-10-x86_64/' >>> /var/www/cobbler/ks_mirror/Fedora-10-x86_64 >>> --exclude-from=/etc/cobbler/rsync.exclude --progress >>> ---------------- (adding distros) >>> - found content (breed=redhat) at >>> /var/www/cobbler/ks_mirror/Fedora-10-x86_64/images/pxeboot >> >> I know in the past we were able to import a directory structure with >> only noarch packages and still specify an arch (x86_64 or i386) and it >> didn't fail like above. Is this a recent change or restriction? >> Should we just add a single arch specific package to the directory >> structure to get around this? > > So, for those of you using the 0.96 release or building new appliances > from the development repositories it appears that a new version of > cobbler in Fedora has broken the ovirt-appliance. > > I've posted the above question to the cobbler mailing list to find out > if this was an intended change or something that recently broke in > cobbler. Hopefully it is the latter and an update to the cobbler package > will fix this. The alternative is that we need to change the appliance > build procedure to account for this change and we'll have to do a 0.96-2 > release to fix this. Hmm, scratch the part about this affecting the 0.96 release. I think we built the appliance with a working version of cobbler so this shouldn't affect 0.96 only building from the development repos. Perry From pmyers at redhat.com Sun Dec 28 06:20:03 2008 From: pmyers at redhat.com (Perry Myers) Date: Sun, 28 Dec 2008 01:20:03 -0500 Subject: [Ovirt-devel] Re: cobbler import of a repo with only noarch packages in it In-Reply-To: References: <4957084B.8060503@redhat.com> Message-ID: <49571A93.9070302@redhat.com> James Cammarata wrote: > On Sun, 28 Dec 2008 00:02:03 -0500, Perry Myers wrote: >> I'm trying to do a cobbler import of a directory structure that only has >> noarch packages in it. I'm using the import to create a minimal pxe boot >> environment without needing to mirror all of the packages (we just use >> external repos for the packages) >> >> However, when I try to do a cobbler import of a directory structure that >> only contains noarch packages I get the following error: >>> + cobbler import --name=Fedora-10 --arch=x86_64 >> --path=/var/www/cobbler/ks_mirror/Fedora-10-x86_64 >>> sending incremental file list >>> >>> sent 392 bytes received 16 bytes 816.00 bytes/sec >>> total size is 134808812 speedup is 330413.75 >>> Given arch (x86_64) not found on imported tree >> /var/www/cobbler/ks_mirror/Fedora-10-x86_64/Packages >>> - rsync -a '/var/www/cobbler/ks_mirror/Fedora-10-x86_64/' >> /var/www/cobbler/ks_mirror/Fedora-10-x86_64 >> --exclude-from=/etc/cobbler/rsync.exclude --progress >>> ---------------- (adding distros) >>> - found content (breed=redhat) at >> /var/www/cobbler/ks_mirror/Fedora-10-x86_64/images/pxeboot >> >> I know in the past we were able to import a directory structure with only >> noarch packages and still specify an arch (x86_64 or i386) and it didn't >> fail like above. Is this a recent change or restriction? Should we just >> add a single arch specific package to the directory structure to get >> around this? >> >> Thanks, >> >> Perry > > > What version of cobbler are you running? I know there were a lot of > changes to the import stuff for debian recently, including how it detected > the arch from the tree automatically, it's possible if you're running a > newer version that functionality may have been broken inadvertently. > I'm running 1.4.0-2 and I think I found the problem... You're right it is with the arch detection. Even though I pass --arch to the cobbler import manually, it still tries to verify the arch by looking specifically at the kernel-headers package located in the path that you are importing from. Problem is, our minimal tree didn't even have kernel-headers in it. To fix the problem I'm just going to add kernel-headers package into our tree. That seems to work. Thanks, Perry -- |=- Red Hat, Engineering, Emerging Technologies, Boston -=| |=- Email: pmyers at redhat.com -=| |=- Office: +1 412 474 3552 Mobile: +1 703 362 9622 -=| |=- GnuPG: E65E4F3D 88F9 F1C9 C2F3 1303 01FE 817C C5D2 8B91 E65E 4F3D -=| From jimi at sngx.net Sun Dec 28 06:13:15 2008 From: jimi at sngx.net (James Cammarata) Date: Sun, 28 Dec 2008 00:13:15 -0600 Subject: [Ovirt-devel] Re: cobbler import of a repo with only noarch packages in it In-Reply-To: <4957084B.8060503@redhat.com> References: <4957084B.8060503@redhat.com> Message-ID: On Sun, 28 Dec 2008 00:02:03 -0500, Perry Myers wrote: > I'm trying to do a cobbler import of a directory structure that only has > noarch packages in it. I'm using the import to create a minimal pxe boot > environment without needing to mirror all of the packages (we just use > external repos for the packages) > > However, when I try to do a cobbler import of a directory structure that > only contains noarch packages I get the following error: >> + cobbler import --name=Fedora-10 --arch=x86_64 > --path=/var/www/cobbler/ks_mirror/Fedora-10-x86_64 >> sending incremental file list >> >> sent 392 bytes received 16 bytes 816.00 bytes/sec >> total size is 134808812 speedup is 330413.75 >> Given arch (x86_64) not found on imported tree > /var/www/cobbler/ks_mirror/Fedora-10-x86_64/Packages >> >> - rsync -a '/var/www/cobbler/ks_mirror/Fedora-10-x86_64/' > /var/www/cobbler/ks_mirror/Fedora-10-x86_64 > --exclude-from=/etc/cobbler/rsync.exclude --progress >> ---------------- (adding distros) >> - found content (breed=redhat) at > /var/www/cobbler/ks_mirror/Fedora-10-x86_64/images/pxeboot > > I know in the past we were able to import a directory structure with only > noarch packages and still specify an arch (x86_64 or i386) and it didn't > fail like above. Is this a recent change or restriction? Should we just > add a single arch specific package to the directory structure to get > around this? > > Thanks, > > Perry What version of cobbler are you running? I know there were a lot of changes to the import stuff for debian recently, including how it detected the arch from the tree automatically, it's possible if you're running a newer version that functionality may have been broken inadvertently. -- This message has been scanned for viruses and dangerous content by MailScanner, and is believed to be clean. From jimi at sngx.net Sun Dec 28 06:48:37 2008 From: jimi at sngx.net (James Cammarata) Date: Sun, 28 Dec 2008 00:48:37 -0600 Subject: [Ovirt-devel] Re: cobbler import of a repo with only noarch packages in it In-Reply-To: <49571A93.9070302@redhat.com> References: <4957084B.8060503@redhat.com> <49571A93.9070302@redhat.com> Message-ID: <7e7930692d161f8e594ba63219072dfd@sngx.net> > I'm running 1.4.0-2 and I think I found the problem... You're right it is > with the arch detection. Even though I pass --arch to the cobbler import > manually, it still tries to verify the arch by looking specifically at the > kernel-headers package located in the path that you are importing from. > Problem is, our minimal tree didn't even have kernel-headers in it. > > To fix the problem I'm just going to add kernel-headers package into our > tree. That seems to work. > > Thanks, > > Perry Yep, that's what I figured. In 1.2.x, cobbler was more trusting and I don't think it verified the arch if you specified it on the command line. It's a bit more strict now, though there should probably be some alternate method to catch corner cases like yours. I'd submit a trac bug for this still so we can make the arch checking a bit more robust in the future. -- This message has been scanned for viruses and dangerous content by MailScanner, and is believed to be clean. From pmyers at redhat.com Sun Dec 28 07:05:41 2008 From: pmyers at redhat.com (Perry Myers) Date: Sun, 28 Dec 2008 02:05:41 -0500 Subject: [Ovirt-devel] [PATCH appliance] fix cobbler tree import Message-ID: <1230447942-26586-1-git-send-email-pmyers@redhat.com> cobbler tree import used to determine arch via --arch flag. Now it checks arch flag against arch of kernel-headers package in the imported tree. Needed to add kernel-headers to our minimal tree so that this works. Signed-off-by: Perry Myers --- gettree.sh | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/gettree.sh b/gettree.sh index 9188a4e..b96bf8b 100755 --- a/gettree.sh +++ b/gettree.sh @@ -64,6 +64,8 @@ echo $os $ver $arch > "$dest/.treeinfo.ova" mkdir -p "$dest/Packages" download "$dest/Packages" "$url/Packages/basesystem-8.1-1.noarch.rpm" \ "$url/Packages/basesystem-10.0-1.noarch.rpm" +download "$dest/Packages" "$url/Packages/kernel-headers-2.6.27.5-117.fc10.$arch.rpm" \ + "$url/Packages/kernel-headers-2.6.28-3.fc11.$arch.rpm" createrepo "$dest" dir="$dest/$(dirname $stage2)" mkdir -p "$dir" -- 1.6.0.6 From pmyers at redhat.com Sun Dec 28 07:05:42 2008 From: pmyers at redhat.com (Perry Myers) Date: Sun, 28 Dec 2008 02:05:42 -0500 Subject: [Ovirt-devel] [PATCH recipe] Fix location of cobbler kickstarts In-Reply-To: <1230447942-26586-1-git-send-email-pmyers@redhat.com> References: <1230447942-26586-1-git-send-email-pmyers@redhat.com> Message-ID: <1230447942-26586-2-git-send-email-pmyers@redhat.com> cobbler used to put sample kickstarts into /etc/cobbler. This has moved to /var/lib/cobbler/kickstarts so cobbler-import had to be updated accordingly. Also location of pxe templates moved from /etc/cobbler to /etc/cobbler/pxe so had to fix that too Signed-off-by: Perry Myers --- appliances/ovirt/files/cobbler-import | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/appliances/ovirt/files/cobbler-import b/appliances/ovirt/files/cobbler-import index f5ec528..d516c68 100644 --- a/appliances/ovirt/files/cobbler-import +++ b/appliances/ovirt/files/cobbler-import @@ -21,8 +21,8 @@ for dir in $ksdir/* ; do cobbler import --name=$os-$ver --arch=$arch --path=$dir - sed -e 's#^reboot.*#poweroff#' /etc/cobbler/sample_end.ks \ - > /etc/cobbler/sample-$os-$ver-$arch.ks + sed -e 's#^reboot.*#poweroff#' /var/lib/cobbler/kickstarts/sample_end.ks \ + > /var/lib/cobbler/kickstarts/sample-$os-$ver-$arch.ks if [[ "$ver" =~ "$rawhide" ]]; then cobbler repo add --name=f$ver-$arch --arch=$arch --mirror-locally=0 \ @@ -38,7 +38,7 @@ for dir in $ksdir/* ; do cobbler profile edit --name=$os-$ver-$arch \ --repos="$repos" \ - --kickstart=/etc/cobbler/sample-$os-$ver-$arch.ks + --kickstart=/var/lib/cobbler/kickstarts/sample-$os-$ver-$arch.ks done node_arch=$(rpm -q --qf "%{arch}" ovirt-node-image) @@ -67,9 +67,9 @@ sed -i -e "s/^module = authn_denyall.*/module = authn_configfile/" \ sed -i -e "s/^server:.*/server: '192.168.50.2'/" \ -e "s/^next_server:.*/next_server: '192.168.50.2'/" \ /etc/cobbler/settings -sed -i -e '/kernel /a \\tIPAPPEND 2' /etc/cobbler/pxesystem.template +sed -i -e '/kernel /a \\tIPAPPEND 2' /etc/cobbler/pxe/pxesystem.template sed -i -e "s/^ONTIMEOUT.*/ONTIMEOUT oVirt-Node-$node_arch/" \ - /etc/cobbler/pxedefault.template + /etc/cobbler/pxe/pxedefault.template service cobblerd restart cobbler sync -- 1.6.0.6 From pmyers at redhat.com Sun Dec 28 07:10:36 2008 From: pmyers at redhat.com (Perry Myers) Date: Sun, 28 Dec 2008 02:10:36 -0500 Subject: [Ovirt-devel] Re: [PATCH recipe] Fix location of cobbler kickstarts In-Reply-To: <1230447942-26586-2-git-send-email-pmyers@redhat.com> References: <1230447942-26586-1-git-send-email-pmyers@redhat.com> <1230447942-26586-2-git-send-email-pmyers@redhat.com> Message-ID: <4957266C.6000106@redhat.com> Perry Myers wrote: > cobbler used to put sample kickstarts into /etc/cobbler. This > has moved to /var/lib/cobbler/kickstarts so cobbler-import had > to be updated accordingly. > > Also location of pxe templates moved from /etc/cobbler to > /etc/cobbler/pxe so had to fix that too This patch was pushed since it fixes a major build issue. Perry From pmyers at redhat.com Sun Dec 28 07:10:56 2008 From: pmyers at redhat.com (Perry Myers) Date: Sun, 28 Dec 2008 02:10:56 -0500 Subject: [Ovirt-devel] Re: [PATCH appliance] fix cobbler tree import In-Reply-To: <1230447942-26586-1-git-send-email-pmyers@redhat.com> References: <1230447942-26586-1-git-send-email-pmyers@redhat.com> Message-ID: <49572680.8020600@redhat.com> Perry Myers wrote: > cobbler tree import used to determine arch via --arch flag. Now > it checks arch flag against arch of kernel-headers package in the > imported tree. Needed to add kernel-headers to our minimal tree > so that this works. This patch was pushed since it fixes a major build issue. Perry From phr at cally.be Sun Dec 28 07:59:01 2008 From: phr at cally.be (Philippe Rodrigues) Date: Sun, 28 Dec 2008 08:59:01 +0100 (CET) Subject: [Ovirt-devel] Install issue on fresh F10 In-Reply-To: <49566B6A.8000205@redhat.com> References: <2823.83.134.22.193.1230376199.squirrel@webmail.cally.be> <639ce0480812270314i52aaa2a6n8f9ea794205c1970@mail.gmail.com> <37189.83.134.23.79.1230388606.squirrel@webmail.cally.be> <49566B6A.8000205@redhat.com> Message-ID: <16835.83.134.16.8.1230451141.squirrel@webmail.cally.be> > Philippe Rodrigues wrote: >> Thanks for your reply Pronix. I've installed Ovirt using "Install >> Instruction" but if your solution can resolve availability of physical >> node and NFS storage too, I can try it. >> >>> i solve problem with libvirt-qpid . >>> download src.rpm and build rpm. > > I have seen this error w/ libvirt-qpid on my hosts too. The last update > must have been a bad build. I've rebuilt the libvirt-qpid packages for > both i386 and x86_64 and put them up on ovirt.org repos. > > Please give these new RPMS a try and let me know if you encounter any > issues. > > Thanks, > > Perry > It's work :-) I download new libvirt-qpid package do : rpm -Uvh --force /libvirt-qpid-0.2.9-0.i386.rpm service libvirt-qpid start I found this error in /var/log/messages Dec 28 08:13:36 physical libvirt-qpid: Error: virConnectGetVersion Subsystem qemu: internal error Cannot find QEMU binary /usr/bin/qemu: No such file or directory in\ NodeWrap.cpp:NodeWrap:82 code: 1 So I install qemu package, start ovirt-appliance and now both physical-node and NFS storage are available. Thanks, Philippe From pmyers at redhat.com Sun Dec 28 15:01:53 2008 From: pmyers at redhat.com (Perry Myers) Date: Sun, 28 Dec 2008 10:01:53 -0500 Subject: [Ovirt-devel] Install issue on fresh F10 In-Reply-To: <16835.83.134.16.8.1230451141.squirrel@webmail.cally.be> References: <2823.83.134.22.193.1230376199.squirrel@webmail.cally.be> <639ce0480812270314i52aaa2a6n8f9ea794205c1970@mail.gmail.com> <37189.83.134.23.79.1230388606.squirrel@webmail.cally.be> <49566B6A.8000205@redhat.com> <16835.83.134.16.8.1230451141.squirrel@webmail.cally.be> Message-ID: <495794E1.3070700@redhat.com> Philippe Rodrigues wrote: >> Philippe Rodrigues wrote: >>> Thanks for your reply Pronix. I've installed Ovirt using "Install >>> Instruction" but if your solution can resolve availability of physical >>> node and NFS storage too, I can try it. >>> >>>> i solve problem with libvirt-qpid . >>>> download src.rpm and build rpm. >> I have seen this error w/ libvirt-qpid on my hosts too. The last update >> must have been a bad build. I've rebuilt the libvirt-qpid packages for >> both i386 and x86_64 and put them up on ovirt.org repos. >> >> Please give these new RPMS a try and let me know if you encounter any >> issues. >> >> Thanks, >> >> Perry >> > It's work :-) > I download new libvirt-qpid package > do : > rpm -Uvh --force /libvirt-qpid-0.2.9-0.i386.rpm > service libvirt-qpid start > > I found this error in /var/log/messages > Dec 28 08:13:36 physical libvirt-qpid: Error: virConnectGetVersion > Subsystem qemu: internal error Cannot find QEMU binary /usr/bin/qemu: No > such file or directory in\ > NodeWrap.cpp:NodeWrap:82 code: 1 > So I install qemu package, start ovirt-appliance and now both > physical-node and NFS storage are available. Hmm, this would indicate that libvirt-qpid requires the qemu package to be installed. If this is the case it should be in the Requires for libvirt-qpid in the spec file. Ian, you have any thoughts on this? Perry From apevec at gmail.com Sun Dec 28 20:56:55 2008 From: apevec at gmail.com (Alan Pevec) Date: Sun, 28 Dec 2008 21:56:55 +0100 Subject: [Ovirt-devel] Install issue on fresh F10 In-Reply-To: <495794E1.3070700@redhat.com> References: <2823.83.134.22.193.1230376199.squirrel@webmail.cally.be> <639ce0480812270314i52aaa2a6n8f9ea794205c1970@mail.gmail.com> <37189.83.134.23.79.1230388606.squirrel@webmail.cally.be> <49566B6A.8000205@redhat.com> <16835.83.134.16.8.1230451141.squirrel@webmail.cally.be> <495794E1.3070700@redhat.com> Message-ID: <2be7262f0812281256s28b3f045w5f073712e317b1e6@mail.gmail.com> >> Subsystem qemu: internal error Cannot find QEMU binary /usr/bin/qemu: No >> such file or directory in\ please check that you have kvm in `virsh capabilities` output Fallback to qemu happens if hardware virtualization support (vmx or svm) is disabled. From phr at cally.be Mon Dec 29 06:31:29 2008 From: phr at cally.be (Philippe Rodrigues) Date: Mon, 29 Dec 2008 07:31:29 +0100 (CET) Subject: [Ovirt-devel] Install issue on fresh F10 In-Reply-To: <2be7262f0812281256s28b3f045w5f073712e317b1e6@mail.gmail.com> References: <2823.83.134.22.193.1230376199.squirrel@webmail.cally.be> <639ce0480812270314i52aaa2a6n8f9ea794205c1970@mail.gmail.com> <37189.83.134.23.79.1230388606.squirrel@webmail.cally.be> <49566B6A.8000205@redhat.com> <16835.83.134.16.8.1230451141.squirrel@webmail.cally.be> <495794E1.3070700@redhat.com> <2be7262f0812281256s28b3f045w5f073712e317b1e6@mail.gmail.com> Message-ID: <65244.83.134.17.221.1230532289.squirrel@webmail-vh.amenworld.com> >>> Subsystem qemu: internal error Cannot find QEMU binary /usr/bin/qemu: >>> No >>> such file or directory in\ > > please check that you have kvm in `virsh capabilities` output > Fallback to qemu happens if hardware virtualization support (vmx or > svm) is disabled. > Like you can see in the output, hardware virtualization is enable [root at physical ~]# virsh capabilities | grep kvm /usr/bin/qemu-kvm [root at physical ~]# grep -E 'svm|vmx' /proc/cpuinfo 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 [root at physical ~]# lsmod | grep kvm kvm_intel 41144 0 kvm 114880 1 kvm_intel In attachment output file of all virsh capabilities -------------- next part -------------- A non-text attachment was scrubbed... Name: capabilities.xml Type: text/xml Size: 1992 bytes Desc: not available URL: From pmyers at redhat.com Mon Dec 29 06:48:05 2008 From: pmyers at redhat.com (Perry Myers) Date: Mon, 29 Dec 2008 01:48:05 -0500 Subject: [Ovirt-devel] Install issue on fresh F10 In-Reply-To: <65244.83.134.17.221.1230532289.squirrel@webmail-vh.amenworld.com> References: <2823.83.134.22.193.1230376199.squirrel@webmail.cally.be> <639ce0480812270314i52aaa2a6n8f9ea794205c1970@mail.gmail.com> <37189.83.134.23.79.1230388606.squirrel@webmail.cally.be> <49566B6A.8000205@redhat.com> <16835.83.134.16.8.1230451141.squirrel@webmail.cally.be> <495794E1.3070700@redhat.com> <2be7262f0812281256s28b3f045w5f073712e317b1e6@mail.gmail.com> <65244.83.134.17.221.1230532289.squirrel@webmail-vh.amenworld.com> Message-ID: <495872A5.7020301@redhat.com> Philippe Rodrigues wrote: >>>> Subsystem qemu: internal error Cannot find QEMU binary /usr/bin/qemu: >>>> No >>>> such file or directory in\ >> please check that you have kvm in `virsh capabilities` output >> Fallback to qemu happens if hardware virtualization support (vmx or >> svm) is disabled. >> > Like you can see in the output, hardware virtualization is enable > > [root at physical ~]# virsh capabilities | grep kvm > > /usr/bin/qemu-kvm > [root at physical ~]# grep -E 'svm|vmx' /proc/cpuinfo > 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 > [root at physical ~]# lsmod | grep kvm > kvm_intel 41144 0 > kvm 114880 1 kvm_intel > > In attachment output file of all virsh capabilities > So missing or misconfigured kvm is not the issue. I tried uninstalling the qemu package on my host and did not see this error when starting the libvirt-qpid daemon. So missing qemu package does not seem to be the trigger for this error on my host at least. Did installing the qemu package solve the problem for you? Can you replicate the problem again by uninstalling the qemu package? 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 phr at cally.be Mon Dec 29 12:36:01 2008 From: phr at cally.be (Philippe Rodrigues) Date: Mon, 29 Dec 2008 13:36:01 +0100 (CET) Subject: [Ovirt-devel] Install issue on fresh F10 In-Reply-To: <495872A5.7020301@redhat.com> References: <2823.83.134.22.193.1230376199.squirrel@webmail.cally.be> <639ce0480812270314i52aaa2a6n8f9ea794205c1970@mail.gmail.com> <37189.83.134.23.79.1230388606.squirrel@webmail.cally.be> <49566B6A.8000205@redhat.com> <16835.83.134.16.8.1230451141.squirrel@webmail.cally.be> <495794E1.3070700@redhat.com> <2be7262f0812281256s28b3f045w5f073712e317b1e6@mail.gmail.com> <65244.83.134.17.221.1230532289.squirrel@webmail-vh.amenworld.com> <495872A5.7020301@redhat.com> Message-ID: <41457.83.134.23.32.1230554161.squirrel@webmail.cally.be> > Philippe Rodrigues wrote: >>>>> Subsystem qemu: internal error Cannot find QEMU binary /usr/bin/qemu: >>>>> No >>>>> such file or directory in\ >>> please check that you have kvm in `virsh capabilities` output >>> Fallback to qemu happens if hardware virtualization support (vmx or >>> svm) is disabled. >>> >> Like you can see in the output, hardware virtualization is enable >> >> [root at physical ~]# virsh capabilities | grep kvm >> >> /usr/bin/qemu-kvm >> [root at physical ~]# grep -E 'svm|vmx' /proc/cpuinfo >> 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 >> [root at physical ~]# lsmod | grep kvm >> kvm_intel 41144 0 >> kvm 114880 1 kvm_intel >> >> In attachment output file of all virsh capabilities >> > > So missing or misconfigured kvm is not the issue. I tried uninstalling > the qemu package on my host and did not see this error when starting the > libvirt-qpid daemon. So missing qemu package does not seem to be the > trigger for this error on my host at least. > > Did installing the qemu package solve the problem for you? Can you > replicate the problem again by uninstalling the qemu package? > > 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 -=| > Qemu package solve the problem for me until I had '500 Internal Server Error' ;-) Physical-node is available (disable). Screenshot in attachment. Uninstalling qemu do not change anything : 1. libvirt-qpid error in /var/log/messages Dec 29 12:23:31 physical libvirt-qpid: Error: virConnectGetVersion Subsystem qemu: internal error Cannot find QEMU binary /usr/bin/qemu: No such file or directory in\ NodeWrap.cpp:NodeWrap:82 code: 1 2. ovirt-appliance 500 Internal Server Error In attachment tar log of the appliance so you can see if any error. I don't know if 'Internal Server Error' is due to libvirt-qpid or maybe to a miss configuration I made! So to avoid any confusion I can do an install from scratch of both F10 and ovirt-appliance. -------------- next part -------------- A non-text attachment was scrubbed... Name: Screenshot-Dashboard.png Type: image/png Size: 89036 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: ovirt-log.tar.bz2 Type: application/x-bzip Size: 476409 bytes Desc: not available URL: From pmyers at redhat.com Mon Dec 29 14:23:19 2008 From: pmyers at redhat.com (Perry Myers) Date: Mon, 29 Dec 2008 09:23:19 -0500 Subject: [Ovirt-devel] Install issue on fresh F10 In-Reply-To: <41457.83.134.23.32.1230554161.squirrel@webmail.cally.be> References: <2823.83.134.22.193.1230376199.squirrel@webmail.cally.be> <639ce0480812270314i52aaa2a6n8f9ea794205c1970@mail.gmail.com> <37189.83.134.23.79.1230388606.squirrel@webmail.cally.be> <49566B6A.8000205@redhat.com> <16835.83.134.16.8.1230451141.squirrel@webmail.cally.be> <495794E1.3070700@redhat.com> <2be7262f0812281256s28b3f045w5f073712e317b1e6@mail.gmail.com> <65244.83.134.17.221.1230532289.squirrel@webmail-vh.amenworld.com> <495872A5.7020301@redhat.com> <41457.83.134.23.32.1230554161.squirrel@webmail.cally.be> Message-ID: <4958DD57.1070807@redhat.com> Philippe Rodrigues wrote: > Qemu package solve the problem for me until I had '500 Internal Server > Error' ;-) > Physical-node is available (disable). Screenshot in attachment. Enabled/Disabled is a user configurable option for hosts. Available/Unavailable indicates whether the host is running and accessible or not. You can toggle the status of a host from Enabled to Disabled by clicking on the Disable Host button in the host details pane. If you want to re-enable this host just click on the Enable Host button in the host details pane. > Uninstalling qemu do not change anything : > 1. libvirt-qpid error in /var/log/messages > Dec 29 12:23:31 physical libvirt-qpid: Error: virConnectGetVersion > Subsystem qemu: internal error Cannot find QEMU binary /usr/bin/qemu: No > such file or directory in\ > NodeWrap.cpp:NodeWrap:82 code: 1 I'm confused... You say that qemu packages solved the problem for you, but then you say that you still get the libvirt-qpid error in /var/log/messages. I'm not sure from your description here what state your computer is in. Do you have the qemu package installed on the host? Or is it uninstalled? Do you get the above error in /var/log/messages when the qemu package is installed, uninstalled, or both? > 2. ovirt-appliance 500 Internal Server Error Also confused about this. You say that the appliance is giving you a 500 Internal Server Error, but then below you post a screen shot from the appliance web interface. Can you get to the web interface or not? > In attachment tar log of the appliance so you can see if any error. > I don't know if 'Internal Server Error' is due to libvirt-qpid or maybe to > a miss configuration I made! An HTTP 500 error would not be related to libvirt-qpid at all. > So to avoid any confusion I can do an install from scratch of both > F10 and ovirt-appliance. Yes, go ahead and do a fresh install. Make sure to use the newer libvirt-qpid packages from the ovirt.org site. Thanks, Perry From phr at cally.be Mon Dec 29 14:49:11 2008 From: phr at cally.be (Philippe Rodrigues) Date: Mon, 29 Dec 2008 15:49:11 +0100 (CET) Subject: [Ovirt-devel] Install issue on fresh F10 In-Reply-To: <4958DD57.1070807@redhat.com> References: <2823.83.134.22.193.1230376199.squirrel@webmail.cally.be> <639ce0480812270314i52aaa2a6n8f9ea794205c1970@mail.gmail.com> <37189.83.134.23.79.1230388606.squirrel@webmail.cally.be> <49566B6A.8000205@redhat.com> <16835.83.134.16.8.1230451141.squirrel@webmail.cally.be> <495794E1.3070700@redhat.com> <2be7262f0812281256s28b3f045w5f073712e317b1e6@mail.gmail.com> <65244.83.134.17.221.1230532289.squirrel@webmail-vh.amenworld.com> <495872A5.7020301@redhat.com> <41457.83.134.23.32.1230554161.squirrel@webmail.cally.be> <4958DD57.1070807@redhat.com> Message-ID: <21967.83.134.23.32.1230562151.squirrel@webmail.cally.be> > Philippe Rodrigues wrote: >> Qemu package solve the problem for me until I had '500 Internal Server >> Error' ;-) >> Physical-node is available (disable). Screenshot in attachment. > > Enabled/Disabled is a user configurable option for hosts. > Available/Unavailable indicates whether the host is running and accessible > or not. > > You can toggle the status of a host from Enabled to Disabled by clicking > on the Disable Host button in the host details pane. If you want to > re-enable this host just click on the Enable Host button in the host > details pane. > >> Uninstalling qemu do not change anything : >> 1. libvirt-qpid error in /var/log/messages >> Dec 29 12:23:31 physical libvirt-qpid: Error: virConnectGetVersion >> Subsystem qemu: internal error Cannot find QEMU binary /usr/bin/qemu: No >> such file or directory in\ >> NodeWrap.cpp:NodeWrap:82 code: 1 > > I'm confused... You say that qemu packages solved the problem for you, but > then you say that you still get the libvirt-qpid error in > /var/log/messages. I'm not sure from your description here what state > your computer is in. > > Do you have the qemu package installed on the host? Or is it uninstalled? > Do you get the above error in /var/log/messages when the qemu package is > installed, uninstalled, or both? > No qemu package is uninstalled [root at physical phr]# rpm -qa | grep qemu qemu-img-0.9.1-10.fc10.i386 >> 2. ovirt-appliance 500 Internal Server Error > > Also confused about this. You say that the appliance is giving you a 500 > Internal Server Error, but then below you post a screen shot from the > appliance web interface. Can you get to the web interface or not? > >> In attachment tar log of the appliance so you can see if any error. >> I don't know if 'Internal Server Error' is due to libvirt-qpid or maybe >> to >> a miss configuration I made! > > An HTTP 500 error would not be related to libvirt-qpid at all. > Sorry, it's not an HTTP error but an ovirt-appliance message (screenshot in attachment) >> So to avoid any confusion I can do an install from scratch of both >> F10 and ovirt-appliance. > > Yes, go ahead and do a fresh install. Make sure to use the newer > libvirt-qpid packages from the ovirt.org site. > > Thanks, > > Perry > Ok, I'll give you a feedback. Thanks, Philippe -------------- next part -------------- A non-text attachment was scrubbed... Name: Screenshot.png Type: image/png Size: 105872 bytes Desc: not available URL: From pmyers at redhat.com Mon Dec 29 18:06:29 2008 From: pmyers at redhat.com (Perry Myers) Date: Mon, 29 Dec 2008 13:06:29 -0500 Subject: [Ovirt-devel] Install issue on fresh F10 In-Reply-To: <21967.83.134.23.32.1230562151.squirrel@webmail.cally.be> References: <2823.83.134.22.193.1230376199.squirrel@webmail.cally.be> <639ce0480812270314i52aaa2a6n8f9ea794205c1970@mail.gmail.com> <37189.83.134.23.79.1230388606.squirrel@webmail.cally.be> <49566B6A.8000205@redhat.com> <16835.83.134.16.8.1230451141.squirrel@webmail.cally.be> <495794E1.3070700@redhat.com> <2be7262f0812281256s28b3f045w5f073712e317b1e6@mail.gmail.com> <65244.83.134.17.221.1230532289.squirrel@webmail-vh.amenworld.com> <495872A5.7020301@redhat.com> <41457.83.134.23.32.1230554161.squirrel@webmail.cally.be> <4958DD57.1070807@redhat.com> <21967.83.134.23.32.1230562151.squirrel@webmail.cally.be> Message-ID: <495911A5.7090305@redhat.com> Philippe Rodrigues wrote: >> Philippe Rodrigues wrote: >>> Qemu package solve the problem for me until I had '500 Internal Server >>> Error' ;-) >>> Physical-node is available (disable). Screenshot in attachment. >> Enabled/Disabled is a user configurable option for hosts. >> Available/Unavailable indicates whether the host is running and accessible >> or not. >> >> You can toggle the status of a host from Enabled to Disabled by clicking >> on the Disable Host button in the host details pane. If you want to >> re-enable this host just click on the Enable Host button in the host >> details pane. >> >>> Uninstalling qemu do not change anything : >>> 1. libvirt-qpid error in /var/log/messages >>> Dec 29 12:23:31 physical libvirt-qpid: Error: virConnectGetVersion >>> Subsystem qemu: internal error Cannot find QEMU binary /usr/bin/qemu: No >>> such file or directory in\ >>> NodeWrap.cpp:NodeWrap:82 code: 1 >> I'm confused... You say that qemu packages solved the problem for you, but >> then you say that you still get the libvirt-qpid error in >> /var/log/messages. I'm not sure from your description here what state >> your computer is in. >> >> Do you have the qemu package installed on the host? Or is it uninstalled? >> Do you get the above error in /var/log/messages when the qemu package is >> installed, uninstalled, or both? >> > > No qemu package is uninstalled > > [root at physical phr]# rpm -qa | grep qemu > qemu-img-0.9.1-10.fc10.i386 Ok. You said that installing the qemu package fixes the problem, so please reinstall it until we can figure out why libvirt-qpid requires that package on your host. The person (Ian) who will be able to help with that is out of the office until next week, so for now install the qemu package and we'll see next week how to resolve this in the long term. >>> 2. ovirt-appliance 500 Internal Server Error >> Also confused about this. You say that the appliance is giving you a 500 >> Internal Server Error, but then below you post a screen shot from the >> appliance web interface. Can you get to the web interface or not? >> >>> In attachment tar log of the appliance so you can see if any error. >>> I don't know if 'Internal Server Error' is due to libvirt-qpid or maybe >>> to >>> a miss configuration I made! >> An HTTP 500 error would not be related to libvirt-qpid at all. >> > > Sorry, it's not an HTTP error but an ovirt-appliance message (screenshot > in attachment) Ok, I understand now. Not sure why that error is appearing, but I have seen it myself as well. I don't think it's anything serious though since it didn't seem to adversely affect anything I was doing. Scott or Jay should be able to help diagnose the 500 error when they get back from vacation. Thanks, Perry From phr at cally.be Tue Dec 30 13:34:44 2008 From: phr at cally.be (Philippe Rodrigues) Date: Tue, 30 Dec 2008 14:34:44 +0100 (CET) Subject: [Ovirt-devel] Install issue on fresh F10 -Feedback In-Reply-To: <495911A5.7090305@redhat.com> References: <2823.83.134.22.193.1230376199.squirrel@webmail.cally.be> <639ce0480812270314i52aaa2a6n8f9ea794205c1970@mail.gmail.com> <37189.83.134.23.79.1230388606.squirrel@webmail.cally.be> <49566B6A.8000205@redhat.com> <16835.83.134.16.8.1230451141.squirrel@webmail.cally.be> <495794E1.3070700@redhat.com> <2be7262f0812281256s28b3f045w5f073712e317b1e6@mail.gmail.com> <65244.83.134.17.221.1230532289.squirrel@webmail-vh.amenworld.com> <495872A5.7020301@redhat.com> <41457.83.134.23.32.1230554161.squirrel@webmail.cally.be> <4958DD57.1070807@redhat.com> <21967.83.134.23.32.1230562151.squirrel@webmail.cally.be> <495911A5.7090305@redhat.com> Message-ID: <49477.83.134.18.141.1230644084.squirrel@webmail.cally.be> Just a feedback; I made an install from scratch of both Fedora 10 and Ovirt. It works :-) To be sure that everything is Ok, I made few tests and these are the results: 1. Qemu package is not (for me) necessary even there is a message in /var/log/messages Dec 30 13:20:31 physical libvirt-qpid: Error: virConnectGetVersion Subsystem qemu: internal error Cannot find QEMU binary /usr/bin/qemu: No such file or directory i\ n NodeWrap.cpp:NodeWrap:82 code: 1 2. If you shutdown and start ovirt-appliance, physical node has a state unavailable(enable) until you restart libvirt-qpid. Thanks and happy new year 2009, Philippe From pmyers at redhat.com Tue Dec 30 15:35:10 2008 From: pmyers at redhat.com (Perry Myers) Date: Tue, 30 Dec 2008 10:35:10 -0500 Subject: [Ovirt-devel] Install issue on fresh F10 -Feedback In-Reply-To: <49477.83.134.18.141.1230644084.squirrel@webmail.cally.be> References: <2823.83.134.22.193.1230376199.squirrel@webmail.cally.be> <639ce0480812270314i52aaa2a6n8f9ea794205c1970@mail.gmail.com> <37189.83.134.23.79.1230388606.squirrel@webmail.cally.be> <49566B6A.8000205@redhat.com> <16835.83.134.16.8.1230451141.squirrel@webmail.cally.be> <495794E1.3070700@redhat.com> <2be7262f0812281256s28b3f045w5f073712e317b1e6@mail.gmail.com> <65244.83.134.17.221.1230532289.squirrel@webmail-vh.amenworld.com> <495872A5.7020301@redhat.com> <41457.83.134.23.32.1230554161.squirrel@webmail.cally.be> <4958DD57.1070807@redhat.com> <21967.83.134.23.32.1230562151.squirrel@webmail.cally.be> <495911A5.7090305@redhat.com> <49477.83.134.18.141.1230644084.squirrel@webmail.cally.be> Message-ID: <495A3FAE.1010302@redhat.com> Philippe Rodrigues wrote: > Just a feedback; > > I made an install from scratch of both Fedora 10 and Ovirt. It works :-) Happy news! Just in time for the new year :) > To be sure that everything is Ok, I made few tests and these are the results: > > 1. Qemu package is not (for me) necessary even there is a message in > /var/log/messages > > Dec 30 13:20:31 physical libvirt-qpid: Error: virConnectGetVersion > Subsystem qemu: internal error Cannot find QEMU binary /usr/bin/qemu: No > such file or directory i\ > n NodeWrap.cpp:NodeWrap:82 code: 1 Ok, we'll look into why this message is appearing in the first place. But it is good to know that it's not hurting anything. > 2. If you shutdown and start ovirt-appliance, physical node has a state > unavailable(enable) until you restart libvirt-qpid. To get the physical node working, the instruction say: > Shut down the appliance with: > > sudo virsh shutdown ovirt-appliance > > Restart the libvirt daemon: > > sudo service libvirtd restart > > Start the appliance Should we add "Restart the libvirt-qpid daemon" on the same line as "Restart the libvirt daemon" ? Would that make the instructions match what you did? > Thanks and happy new year 2009, You too! :) Perry From mdehaan at redhat.com Tue Dec 30 23:37:22 2008 From: mdehaan at redhat.com (Michael DeHaan) Date: Tue, 30 Dec 2008 18:37:22 -0500 Subject: [Ovirt-devel] Re: cobbler import of a repo with only noarch packages in it In-Reply-To: <4957084B.8060503@redhat.com> References: <4957084B.8060503@redhat.com> Message-ID: <495AB0B2.6090008@redhat.com> Perry Myers wrote: > I'm trying to do a cobbler import of a directory structure that only has > noarch packages in it. I'm using the import to create a minimal pxe boot > environment without needing to mirror all of the packages (we just use > external repos for the packages) > > However, when I try to do a cobbler import of a directory structure that > only contains noarch packages I get the following error: > >> + cobbler import --name=Fedora-10 --arch=x86_64 --path=/var/www/cobbler/ks_mirror/Fedora-10-x86_64 >> sending incremental file list >> >> sent 392 bytes received 16 bytes 816.00 bytes/sec >> total size is 134808812 speedup is 330413.75 >> Given arch (x86_64) not found on imported tree /var/www/cobbler/ks_mirror/Fedora-10-x86_64/Packages >> >> - rsync -a '/var/www/cobbler/ks_mirror/Fedora-10-x86_64/' /var/www/cobbler/ks_mirror/Fedora-10-x86_64 --exclude-from=/etc/cobbler/rsync.exclude --progress >> ---------------- (adding distros) >> - found content (breed=redhat) at /var/www/cobbler/ks_mirror/Fedora-10-x86_64/images/pxeboot >> > > I know in the past we were able to import a directory structure with only > noarch packages and still specify an arch (x86_64 or i386) and it didn't > fail like above. Is this a recent change or restriction? Should we just > add a single arch specific package to the directory structure to get > around this? > > Thanks, > > Perry > > It seems you want "cobbler repo add" and not "import", as you're talking more about a noarch repo than an install tree. I don't see how you could get an installable distribution with just noarch packages :) Import is for install trees, which can also be used as repos, yes. But repos are not == install trees. Does that make sense or did I miss something? If you're doing something really simple "cobbler distro add" alone might suffice, though I'd like to understand a little more about the use case to say for sure. --Michael From pmyers at redhat.com Tue Dec 30 23:56:12 2008 From: pmyers at redhat.com (Perry Myers) Date: Tue, 30 Dec 2008 18:56:12 -0500 Subject: [Ovirt-devel] Re: cobbler import of a repo with only noarch packages in it In-Reply-To: <495AB0B2.6090008@redhat.com> References: <4957084B.8060503@redhat.com> <495AB0B2.6090008@redhat.com> Message-ID: <495AB51C.9010008@redhat.com> Michael DeHaan wrote: > Perry Myers wrote: >> I'm trying to do a cobbler import of a directory structure that only >> has noarch packages in it. I'm using the import to create a minimal >> pxe boot environment without needing to mirror all of the packages (we >> just use external repos for the packages) >> >> However, when I try to do a cobbler import of a directory structure >> that only contains noarch packages I get the following error: >> >>> + cobbler import --name=Fedora-10 --arch=x86_64 >>> --path=/var/www/cobbler/ks_mirror/Fedora-10-x86_64 >>> sending incremental file list >>> >>> sent 392 bytes received 16 bytes 816.00 bytes/sec >>> total size is 134808812 speedup is 330413.75 >>> Given arch (x86_64) not found on imported tree >>> /var/www/cobbler/ks_mirror/Fedora-10-x86_64/Packages >>> >>> - rsync -a '/var/www/cobbler/ks_mirror/Fedora-10-x86_64/' >>> /var/www/cobbler/ks_mirror/Fedora-10-x86_64 >>> --exclude-from=/etc/cobbler/rsync.exclude --progress >>> ---------------- (adding distros) >>> - found content (breed=redhat) at >>> /var/www/cobbler/ks_mirror/Fedora-10-x86_64/images/pxeboot >>> >> >> I know in the past we were able to import a directory structure with >> only noarch packages and still specify an arch (x86_64 or i386) and it >> didn't fail like above. Is this a recent change or restriction? >> Should we just add a single arch specific package to the directory >> structure to get around this? >> >> Thanks, >> >> Perry >> >> > > It seems you want "cobbler repo add" and not "import", as you're talking > more about a noarch repo than an install tree. I don't see how you > could get an installable distribution with just noarch packages :) > > Import is for install trees, which can also be used as repos, yes. > > But repos are not == install trees. > > Does that make sense or did I miss something? > > If you're doing something really simple "cobbler distro add" alone might > suffice, though I'd like to understand a little more about the use case > to say for sure. We wanted to set up a distro and profile for using cobbler to install Fedora over pxe but without needing to put any of the rpms in our local cobbler install. i.e. our distro is just the kernel and initrd and the other images to do an anaconda install. But the kickstart uses all remote repos for packages. That make sense? It's sort of a niche use case. We just wanted to provide on the oVirt Appliance a minimal cobbler setup so people could immediately deploy Fedora on oVirt Guests w/o needing to put the entire Fedora DVD into the appliance image. Perry From mdehaan at redhat.com Wed Dec 31 21:40:59 2008 From: mdehaan at redhat.com (Michael DeHaan) Date: Wed, 31 Dec 2008 16:40:59 -0500 Subject: [Ovirt-devel] Re: cobbler import of a repo with only noarch packages in it In-Reply-To: <495AB51C.9010008@redhat.com> References: <4957084B.8060503@redhat.com> <495AB0B2.6090008@redhat.com> <495AB51C.9010008@redhat.com> Message-ID: <495BE6EB.9070101@redhat.com> Perry Myers wrote: > Michael DeHaan wrote: >> Perry Myers wrote: >>> I'm trying to do a cobbler import of a directory structure that only >>> has noarch packages in it. I'm using the import to create a minimal >>> pxe boot environment without needing to mirror all of the packages >>> (we just use external repos for the packages) >>> >>> However, when I try to do a cobbler import of a directory structure >>> that only contains noarch packages I get the following error: >>> >>>> + cobbler import --name=Fedora-10 --arch=x86_64 >>>> --path=/var/www/cobbler/ks_mirror/Fedora-10-x86_64 >>>> sending incremental file list >>>> >>>> sent 392 bytes received 16 bytes 816.00 bytes/sec >>>> total size is 134808812 speedup is 330413.75 >>>> Given arch (x86_64) not found on imported tree >>>> /var/www/cobbler/ks_mirror/Fedora-10-x86_64/Packages >>>> >>>> - rsync -a '/var/www/cobbler/ks_mirror/Fedora-10-x86_64/' >>>> /var/www/cobbler/ks_mirror/Fedora-10-x86_64 >>>> --exclude-from=/etc/cobbler/rsync.exclude --progress >>>> ---------------- (adding distros) >>>> - found content (breed=redhat) at >>>> /var/www/cobbler/ks_mirror/Fedora-10-x86_64/images/pxeboot >>>> >>> >>> I know in the past we were able to import a directory structure with >>> only noarch packages and still specify an arch (x86_64 or i386) and >>> it didn't fail like above. Is this a recent change or restriction? >>> Should we just add a single arch specific package to the directory >>> structure to get around this? >>> >>> Thanks, >>> >>> Perry >>> >>> >> >> It seems you want "cobbler repo add" and not "import", as you're >> talking more about a noarch repo than an install tree. I don't see >> how you could get an installable distribution with just noarch >> packages :) >> >> Import is for install trees, which can also be used as repos, yes. >> >> But repos are not == install trees. >> >> Does that make sense or did I miss something? >> >> If you're doing something really simple "cobbler distro add" alone >> might suffice, though I'd like to understand a little more about the >> use case to say for sure. > > We wanted to set up a distro and profile for using cobbler to install > Fedora over pxe but without needing to put any of the rpms in our > local cobbler install. > > i.e. our distro is just the kernel and initrd and the other images to > do an anaconda install. But the kickstart uses all remote repos for > packages. > > That make sense? It's sort of a niche use case. We just wanted to > provide on the oVirt Appliance a minimal cobbler setup so people could > immediately deploy Fedora on oVirt Guests w/o needing to put the > entire Fedora DVD into the appliance image. Yeah, this is really simple to do still, I'd just skip cobbler import altogether. # cobbler distro add --name=foo --arch=x86 --initrd=/path/to/initrd --kernel=/path/to/kernel # cobbler profile add --name=bar --profile=foo --kickstart=/path/to/kickstart_template.ks Import is mainly there to assist folks with mirroring install trees (and possibly more than one at a time), which you wouldn't need to do. It just makes it a two step process instead of one. > > Perry From sander at hoentjen.eu Sat Dec 27 15:40:50 2008 From: sander at hoentjen.eu (Sander Hoentjen) Date: Sat, 27 Dec 2008 16:40:50 +0100 Subject: [Ovirt-devel] how to Increase memory for vm online ? In-Reply-To: <49564B15.2070603@redhat.com> References: <1230219162.14739.1.camel@dima-desktop> <4953D384.1070806@redhat.com> <639ce0480812251142p68ed4b5cq6b56ab9b24eb79c4@mail.gmail.com> <20081226130551.GA5355@bogon.ms20.nix> <4954FF67.1090501@redhat.com> <639ce0480812270154la2793cdjb81093a0cc0f2466@mail.gmail.com> <49564B15.2070603@redhat.com> Message-ID: <1230392450.5588.14.camel@peecee.hoentjen.eu> On Sat, 2008-12-27 at 10:34 -0500, Perry Myers wrote: > pronix pronix wrote: > > kernel documentation > > ram hotplug > > linux-2.6.27/Documentation/memory-hotplug.txt > > cpu hotplug > > linux-2.6.27/Documentation/cpu-hotplug.txt > > Ah, so only supported in Linux guests... Windows guests don't have > support for dynamic resizing of memory them. Actually it does support adding: http://www.microsoft.com/whdc/system/pnppwr/hotadd/hotaddmem.mspx Sander