From apevec at redhat.com Sun Feb 1 22:23:47 2009 From: apevec at redhat.com (Alan Pevec) Date: Sun, 1 Feb 2009 23:23:47 +0100 Subject: [Ovirt-devel] [PATCH node-image] increase timeout to 30s for CD/USB boot Message-ID: <1233527027-32730-1-git-send-email-apevec@redhat.com> timeout quickly for PXE boot --- common-install.ks | 2 +- ovirt-pxe | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/common-install.ks b/common-install.ks index 8e34301..0c26d9b 100644 --- a/common-install.ks +++ b/common-install.ks @@ -7,7 +7,7 @@ firewall --disabled part / --size 550 --fstype ext2 services --enabled=ntpd,ntpdate,collectd,iptables,network,rsyslog # This requires a new fixed version of livecd-creator to honor the --append settings. -bootloader --timeout=5 --append="console=tty0 console=ttyS0,115200n8" +bootloader --timeout=30 --append="console=tty0 console=ttyS0,115200n8" # not included by default in Fedora 10 livecd initramfs device virtio_blk diff --git a/ovirt-pxe b/ovirt-pxe index 5223990..b605644 100755 --- a/ovirt-pxe +++ b/ovirt-pxe @@ -32,3 +32,6 @@ livecd-iso-to-pxeboot $ISO # append BOOTIF with PXE MAC info f=tftpboot/pxelinux.cfg/default grep -q 'IPAPPEND 2' $f || sed -i '/KERNEL/a \\tIPAPPEND 2' $f + +# timeout quickly for PXE boots +sed -i 's/timeout.*/timeout 1/' $f -- 1.6.0.6 From apevec at gmail.com Mon Feb 2 08:54:20 2009 From: apevec at gmail.com (Alan Pevec) Date: Mon, 2 Feb 2009 09:54:20 +0100 Subject: [Ovirt-devel] [PATCH node-image] increase timeout to 30s for CD/USB boot In-Reply-To: <1233527027-32730-1-git-send-email-apevec@redhat.com> References: <1233527027-32730-1-git-send-email-apevec@redhat.com> Message-ID: <2be7262f0902020054q22072246i9bee500ce8e83a63@mail.gmail.com> On Sun, Feb 1, 2009 at 11:23 PM, Alan Pevec wrote: > +# timeout quickly for PXE boots > +sed -i 's/timeout.*/timeout 1/' $f or maybe still timeout 50 (5s) here? From sseago at redhat.com Mon Feb 2 17:25:36 2009 From: sseago at redhat.com (Scott Seago) Date: Mon, 2 Feb 2009 17:25:36 +0000 Subject: [Ovirt-devel] [PATCH] changed tasks flexigrid to use icons (with mouseover text) to show task state. Message-ID: <1233595536-3774-1-git-send-email-sseago@redhat.com> Signed-off-by: Scott Seago --- src/app/views/task/_grid.rhtml | 7 ++++++- src/public/images/icon-canceled-11.png | Bin 0 -> 436 bytes src/public/images/icon-failed-11.png | Bin 0 -> 419 bytes src/public/images/icon-finished-11.png | Bin 0 -> 241 bytes src/public/images/icon-paused-11.png | Bin 0 -> 405 bytes src/public/images/icon-queued-11.png | Bin 0 -> 406 bytes src/public/images/icon-running-11.png | Bin 0 -> 470 bytes src/public/stylesheets/components.css | 27 +++++++++++++++++++++++++++ 8 files changed, 33 insertions(+), 1 deletions(-) create mode 100644 src/public/images/icon-canceled-11.png create mode 100644 src/public/images/icon-failed-11.png create mode 100644 src/public/images/icon-finished-11.png create mode 100644 src/public/images/icon-paused-11.png create mode 100644 src/public/images/icon-queued-11.png create mode 100644 src/public/images/icon-running-11.png diff --git a/src/app/views/task/_grid.rhtml b/src/app/views/task/_grid.rhtml index 5e2a3d5..de428f7 100644 --- a/src/app/views/task/_grid.rhtml +++ b/src/app/views/task/_grid.rhtml @@ -20,7 +20,7 @@ {display: 'Item', width : 120, align: 'right', process: <%= table_id%>item}, {display: 'Action', name : 'action', width : 120, align: 'left'}, {display: 'Message', name : 'message', width : 180, align: 'left'}, - {display: 'State', name : 'state', width : 60, align: 'left'}, + {display: 'State', name : 'state', width : 30, align: 'left', process: task_state}, {display: 'User', name : 'user', width : 60, align: 'right'}, {display: 'Created', name : 'tasks.created_at', width : 140, align: 'right'} ], @@ -41,6 +41,11 @@ { $(celDiv).html($(celDiv).html().split(";;;")[2]); } + function task_state(celDiv) + { + var state_name = $(celDiv).html() + $(celDiv).html('
'); + } function <%= table_id %>_select(celDiv) { //nothing now diff --git a/src/public/images/icon-canceled-11.png b/src/public/images/icon-canceled-11.png new file mode 100644 index 0000000000000000000000000000000000000000..c1b3d85a476a16a0c3165f496aba5de9f67cf2b4 GIT binary patch literal 436 zcmV;l0ZaagP)%kj3B1v9YNzFkN4x*2JtjTy|(MAIc-LSms>RN|@7ziNl^R3tCQKY9Jr8PzgZ8J at U zlBRj)(sI*0y$rEAYFNiOuQ2Avoa at NZIOeS|m_fy;bgE}p8F((2J^5VN_4;8NNpdvL z7fuI7(7AixkAr_d|G^Xvrfw0Of5gpUN}z|Ex6hw`5q#QNQNR63mnj60Bjbi;3xM=C zq~RN7z>IjbJNbofz+o%B4S*VX+_d0h296Lggo2n1$rA|@*fq;AN;BgIC$mVI5+RS4 eKK8Nx6JP-SLWS=%B?V3Z0000 zp%ymcuf#i$bXObCFpEBhMW4Ydcmg}E1Z%;n5{aUz>P)9|?{&Z1R-DY4bH1N@?mgnG zatg-N{Y~C+GF6!lLX0BgPSli=7aKcAufz_2&kyyIR;rov{IIxp41c8nR$}tht(g;* zl=Z^q7MAjBNOt$Jetl;vF?s64n}t)I^?bM)2QrCZl;ImpB_>auK3B>#T<|@}e(%r3 z(AI1?4fsa?ZhwX at g|Sg{sefh_{g_VJk0BbxKraV#L#H9Ty}r%d%#_VB|JLfjycxB2 zrwcWRp^_M0xq^eocg&a1ES7@^)aetq#UO7EH at z(2I-~1O&Y`a^ZJ#Qj9oyln;$=I) zM}(5rsAtUvxk>y*Hv!_*7zGX&r_r#p*zjZ`QEQo9$4N|{I(@$a3;?6-p2(4D5NQAa N002ovPDHLkV1fmuyLkWr literal 0 HcmV?d00001 diff --git a/src/public/images/icon-finished-11.png b/src/public/images/icon-finished-11.png new file mode 100644 index 0000000000000000000000000000000000000000..bd1156a0296dbfc539d5b4388ae79c039838a39d GIT binary patch literal 241 zcmeAS at N?(olHy`uVBq!ia0vp^+#t-s1|(OmDOUqhk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5XCVRR#hE&{2`t$$4ee-uNSvDpG#*Xrh1_ErK8*j*ToZl$0 z at B)8FtHTUVtqg`EzZ)YMd>3kmJY-d{V+gL{=#Xu&VDVgNE8y)cYSqM&cfRo6A7X$qWkhbxM5w$>III3ADS`#xk at CQtH=F|e#P5XXmM2say7P9Tlr2$EY3 at 0Bw1GecJ4~r+G*A{jG($OUjb(lFLev)2^Z+oQ$V|I;`ZK#5PF6wAU`$PKwoNj zeof+R{R!6B27-Vi5FD|X0Qtl*^~Lt^P#3;3LcyZ%cNUM4>gDJ)_`VMEiHlqkL{CQ$ zvO(Tm=Lln+T%?mv6|H{n=Mesb53V**4bD}^2O4EAxXpyR&7+)D`^7Chwu&m69_el? z0j4-@^(1R^)~}9RP3W4$XU{~!?5aViQK*pwlA+;_LP{;eQo~*?l$z7{7=_m{5o02n zg6}hUUnWRbphH{~QZ*$hS;lL}3-zXjSJwjVUMF54J(ciE#C;1e00?HSPo;3$k^lez M07*qoM6N<$g3AleZU6uP literal 0 HcmV?d00001 diff --git a/src/public/stylesheets/components.css b/src/public/stylesheets/components.css index 228ff7b..9a913c6 100644 --- a/src/public/stylesheets/components.css +++ b/src/public/stylesheets/components.css @@ -316,3 +316,30 @@ width: 40%; padding-bottom: 15px; } + +/* classes for task state icons */ +.state-canceled { + background:url(../images/icon-canceled-11.png) top center no-repeat; + height: 11px; +} +.state-failed { + background:url(../images/icon-failed-11.png) top center no-repeat; + height: 11px; +} +.state-finished { + background:url(../images/icon-finished-11.png) top center no-repeat; + height: 11px; +} +.state-paused { + background:url(../images/icon-paused-11.png) top center no-repeat; + height: 11px; +} +.state-queued { + background:url(../images/icon-queued-11.png) top center no-repeat; + height: 11px; +} +.state-running { + background:url(../images/icon-running-11.png) top center no-repeat; + height: 11px; +} + -- 1.6.0.6 From jguiditt at redhat.com Mon Feb 2 19:27:50 2009 From: jguiditt at redhat.com (Jason Guiditta) Date: Mon, 02 Feb 2009 14:27:50 -0500 Subject: [Ovirt-devel] [PATCH] changed tasks flexigrid to use icons (with mouseover text) to show task state. In-Reply-To: <1233595536-3774-1-git-send-email-sseago@redhat.com> References: <1233595536-3774-1-git-send-email-sseago@redhat.com> Message-ID: <1233602870.4614.5.camel@physical.priv.ovirt.org> On Mon, 2009-02-02 at 17:25 +0000, Scott Seago wrote: > Signed-off-by: Scott Seago > --- > src/app/views/task/_grid.rhtml | 7 ++++++- > src/public/images/icon-canceled-11.png | Bin 0 -> 436 bytes > src/public/images/icon-failed-11.png | Bin 0 -> 419 bytes > src/public/images/icon-finished-11.png | Bin 0 -> 241 bytes > src/public/images/icon-paused-11.png | Bin 0 -> 405 bytes > src/public/images/icon-queued-11.png | Bin 0 -> 406 bytes > src/public/images/icon-running-11.png | Bin 0 -> 470 bytes > src/public/stylesheets/components.css | 27 +++++++++++++++++++++++++++ > 8 files changed, 33 insertions(+), 1 deletions(-) > create mode 100644 src/public/images/icon-canceled-11.png > create mode 100644 src/public/images/icon-failed-11.png > create mode 100644 src/public/images/icon-finished-11.png > create mode 100644 src/public/images/icon-paused-11.png > create mode 100644 src/public/images/icon-queued-11.png > create mode 100644 src/public/images/icon-running-11.png > > diff --git a/src/app/views/task/_grid.rhtml b/src/app/views/task/_grid.rhtml > index 5e2a3d5..de428f7 100644 > --- a/src/app/views/task/_grid.rhtml > +++ b/src/app/views/task/_grid.rhtml > @@ -20,7 +20,7 @@ > {display: 'Item', width : 120, align: 'right', process: <%= table_id%>item}, > {display: 'Action', name : 'action', width : 120, align: 'left'}, > {display: 'Message', name : 'message', width : 180, align: 'left'}, > - {display: 'State', name : 'state', width : 60, align: 'left'}, > + {display: 'State', name : 'state', width : 30, align: 'left', process: task_state}, > {display: 'User', name : 'user', width : 60, align: 'right'}, > {display: 'Created', name : 'tasks.created_at', width : 140, align: 'right'} > ], > @@ -41,6 +41,11 @@ > { > $(celDiv).html($(celDiv).html().split(";;;")[2]); > } > + function task_state(celDiv) > + { > + var state_name = $(celDiv).html() > + $(celDiv).html('
'); > + } > function <%= table_id %>_select(celDiv) > { > //nothing now > diff --git a/src/public/images/icon-canceled-11.png b/src/public/images/icon-canceled-11.png > new file mode 100644 > index 0000000000000000000000000000000000000000..c1b3d85a476a16a0c3165f496aba5de9f67cf2b4 > GIT binary patch > literal 436 > zcmV;l0ZaagP) z)K6G40000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzMoC0LRCwB4 > zkiAaBFcgKa9n+*sq$VjKQYs-)F# z1QINWKZUAIh!f)*nhZHoV&8MW8=shb9UTDb{^r`IRB6XNYQbCzTj(W8e6qgXe8rmL > z>%kj3B1v9YNzFkN4x*2JtjTy|(MAIc-LSms>RN|@7ziNl^R3tCQKY9Jr8PzgZ8J at U > zlBRj)(sI*0y$rEAYFNiOuQ2Avoa at NZIOeS|m_fy;bgE}p8F((2J^5VN_4;8NNpdvL > z7fuI7(7AixkAr_d|G^Xvrfw0Of5gpUN}z|Ex6hw`5q#QNQNR63mnj60Bjbi;3xM=C > zq~RN7z>IjbJNbofz+o%B4S*VX+_d0h296Lggo2n1$rA|@*fq;AN;BgIC$mVI5+RS4 > eKK8Nx6JP-SLWS=%B?V3Z0000 > literal 0 > HcmV?d00001 > > diff --git a/src/public/images/icon-failed-11.png b/src/public/images/icon-failed-11.png > new file mode 100644 > index 0000000000000000000000000000000000000000..346e5234b54af6800d5588d5f35145a07c3b9e1e > GIT binary patch > literal 419 > zcmV;U0bKrxP) zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzMM*?KRCwA > zp%ymcuf#i$bXObCFpEBhMW4Ydcmg}E1Z%;n5{aUz>P)9|?{&Z1R-DY4bH1N@?mgnG > zatg-N{Y~C+GF6!lLX0BgPSli=7aKcAufz_2&kyyIR;rov{IIxp41c8nR$}tht(g;* > zl=Z^q7MAjBNOt$Jetl;vF?s64n}t)I^?bM)2QrCZl;ImpB_>auK3B>#T<|@}e(%r3 > z(AI1?4fsa?ZhwX at g|Sg{sefh_{g_VJk0BbxKraV#L#H9Ty}r%d%#_VB|JLfjycxB2 > zrwcWRp^_M0xq^eocg&a1ES7@^)aetq#UO7EH at z(2I-~1O&Y`a^ZJ#Qj9oyln;$=I) > zM}(5rsAtUvxk>y*Hv!_*7zGX&r_r#p*zjZ`QEQo9$4N|{I(@$a3;?6-p2(4D5NQAa > N002ovPDHLkV1fmuyLkWr > > literal 0 > HcmV?d00001 > > diff --git a/src/public/images/icon-finished-11.png b/src/public/images/icon-finished-11.png > new file mode 100644 > index 0000000000000000000000000000000000000000..bd1156a0296dbfc539d5b4388ae79c039838a39d > GIT binary patch > literal 241 > zcmeAS at N?(olHy`uVBq!ia0vp^+#t-s1|(OmDOUqhk|nMYCBgY=CFO}lsSJ)O`AMk? > zp1FzXsX?iUDV2pMQ*D5XCVRR#hE&{2`t$$4ee-uNSvDpG#*Xrh1_ErK8*j*ToZl$0 > z at B)8FtHTUVtqg`EzZ)YMd>3kmJY-d{V+gL{=#Xu&VDVgNE8y)cYSqM&c zV-&tIBylR#F@*kLj5Iv+OG9B=qZW%MM~kLQ7!UKkfM3j4j&PrtWMD4uAar<@K;%a! > lCoabZL6PPoObrao3<=GO+4JNDl7P-*@O1TaS?83{1OWM-P1FDY > > literal 0 > HcmV?d00001 > > diff --git a/src/public/images/icon-paused-11.png b/src/public/images/icon-paused-11.png > new file mode 100644 > index 0000000000000000000000000000000000000000..f6ba04ffa265f1d5c1526d51d5915d56790d259c > GIT binary patch > literal 405 > zcmV;G0c!q zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzH%UZ6RCwB4kTH^iKoCWH28u|eFcYZ4 > z)P!)YBC@=P2at%sV{E`dJOf3#h9n*U2q6MQ7+||+)hhQV)BpFIrWtm*T!0kEv8}4= > zx$pZBp3*ce5<+|*4u^s~BRENtFARTd+lK9S`(ojCyFpPDfJ1is{r<{=Ah4%t%0176 > z#bN>fRo6A7X$qWkhbxM5w$>III3ADS`#xk at CQtH=F|e#P5XXmM2say7P9Tlr2$ zN#8ULxbB9skW+B)9x{BvxIc`Oc*BpbleL7q?hb9+eohvn^pxLUFzyoNc at Fqwf3SE? > ze!`SfpE!0po$Ps at b2Rd2NL14oNZ6A#_8e}Ss{)H11u8;@v6N3}ESK*~)HhdV!G#z= > z*Yzt7aUOjim1PBGSwdM=v_eEV^~E6ISAYQke}%MAx4X<-00000NkvXXu0mjfDuk%t > > literal 0 > HcmV?d00001 > > diff --git a/src/public/images/icon-queued-11.png b/src/public/images/icon-queued-11.png > new file mode 100644 > index 0000000000000000000000000000000000000000..159e763892533ceb20e34c6a5d95f22a0827467f > GIT binary patch > literal 406 > zcmV;H0crk;P) zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzI7vi7RCwBA{Qv(y0|;ow)k-rkvz9RY > z{$9WU1FW1A82 zqst5oENtf27c`z?(1@*()`+h7pTF_O|F_@&{s)1Ftu zxODs=*!C}Hj)Q3szwFIk2184G29P=?kQ+f(3vn zRtz9 at Odtsz5f+A3D_1fggZrgf46>EY3 at 0Bw1 zsU?F0kl%Xp6Ih%H6g(hbzx(lz;lTd=U_qtsX<&sQK1duS4^qbj3P(`zH0`?0pa=2@ > z5Wt)S;)BG&!3R`_HJm|i1UU^ooEb at pL4W`Q0HnjIr!FTu)c^nh07*qoM6N<$f?~m^ > A!T > literal 0 > HcmV?d00001 > > diff --git a/src/public/images/icon-running-11.png b/src/public/images/icon-running-11.png > new file mode 100644 > index 0000000000000000000000000000000000000000..461241902b1e28b91c6d5aa8728d06fe929feca1 > GIT binary patch > literal 470 > zcmV;{0V)28P) zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzcu7P-RCwA z$yP*MI5 zd44nV zNAOTdLj>GecJ4~r+G*A{jG($OUjb(lFLev)2^Z+oQ$V|I;`ZK#5PF6wAU`$PKwoNj > zeof+R{R!6B27-Vi5FD|X0Qtl*^~Lt^P#3;3LcyZ%cNUM4>gDJ)_`VMEiHlqkL{CQ$ > zvO(Tm=Lln+T%?mv6|H{n=Mesb53V**4bD}^2O4EAxXpyR&7+)D`^7Chwu&m69_el? > z0j4-@^(1R^)~}9RP3W4$XU{~!?5aViQK*pwlA+;_LP{;eQo~*?l$z7{7=_m{5o02n > zg6}hUUnWRbphH{~QZ*$hS;lL}3-zXjSJwjVUMF54J(ciE#C;1e00?HSPo;3$k^lez > M07*qoM6N<$g3AleZU6uP > > literal 0 > HcmV?d00001 > > diff --git a/src/public/stylesheets/components.css b/src/public/stylesheets/components.css > index 228ff7b..9a913c6 100644 > --- a/src/public/stylesheets/components.css > +++ b/src/public/stylesheets/components.css > @@ -316,3 +316,30 @@ > width: 40%; > padding-bottom: 15px; > } > + > +/* classes for task state icons */ > +.state-canceled { > + background:url(../images/icon-canceled-11.png) top center no-repeat; > + height: 11px; > +} > +.state-failed { > + background:url(../images/icon-failed-11.png) top center no-repeat; > + height: 11px; > +} > +.state-finished { > + background:url(../images/icon-finished-11.png) top center no-repeat; > + height: 11px; > +} > +.state-paused { > + background:url(../images/icon-paused-11.png) top center no-repeat; > + height: 11px; > +} > +.state-queued { > + background:url(../images/icon-queued-11.png) top center no-repeat; > + height: 11px; > +} > +.state-running { > + background:url(../images/icon-running-11.png) top center no-repeat; > + height: 11px; > +} > + ACK, this works/looks good. One comment, the naming of the png's seems a little odd with '-11', which I realize is to designate size, but that might be clearer if it were something like '-11px'. I am fine with it as is, just a thought. -j From pmyers at redhat.com Mon Feb 2 20:20:10 2009 From: pmyers at redhat.com (Perry Myers) Date: Mon, 02 Feb 2009 15:20:10 -0500 Subject: [Ovirt-devel] Installing a VM in oVirt 0.96 In-Reply-To: <0AAE5AB84B013E45A7B61CB66943C17215B5F88E72@USEA-EXCH7.na.uis.unisys.com> References: <20090129164641.491FB8E0371@hormel.redhat.com> <0AAE5AB84B013E45A7B61CB66943C17215B5DCF688@USEA-EXCH7.na.uis.unisys.com> <49825A00.70209@redhat.com> <0AAE5AB84B013E45A7B61CB66943C17215B5E29981@USEA-EXCH7.na.uis.unisys.com> <49834F20.8020507@redhat.com> <0AAE5AB84B013E45A7B61CB66943C17215B5F88E72@USEA-EXCH7.na.uis.unisys.com> Message-ID: <4987557A.7000501@redhat.com> Carb, Brian A wrote: > I added a slax iso and then did the image add in cobbler. Then, when I create a VM, the slax cobbler ISO entry showed up in the interface drop-down as you said it would, and so I selected it. But the VM refuses to start - taskomatic.log shows a libvir error: > > libvir: Storage error : XML description for missing storage pool source host name is not well formed or invalid > > i have /ovirtnfs added as a storage pool. I tried adding /cobblernfs but this didn't seem to fix anything. > > any ideas? Can you give me the exact syntax for cobbler that you used to add the image? The syntax for the nfs:// url part needs to follow some strict conventions in order to work properly, but upstream cobbler doesn't do any validation of that string so it won't tell you if you did it incorrectly. This thread on ovirt-devel is useful and will probably help fix your issue: https://www.redhat.com/archives/ovirt-devel/2008-December/msg00234.html Perry > > brian carb > unisys corporation - malvern, pa > brian.carb at unisys.com > > -----Original Message----- > From: Perry Myers [mailto:pmyers at redhat.com] > Sent: Friday, January 30, 2009 2:04 PM > To: Carb, Brian A > Subject: Re: [Ovirt-devel] Installing a VM in oVirt 0.96 > > Carb, Brian A wrote: >> Thanks perry. Adding the image to cobbler makes it available - now i'll try to install into it. >> >> I noticed also that after sitting overnight, 2 of my 4 nodes show as unavailable(enabled). I can access them via their consoles though, so the machines are up. any ideas ? >> > > That could be issues with qpid which is the messaging transport we use. I would email Ian Main on ovirt-devel (his nick on irc is Slower) and outline the issue there as he'll have a much better idea of what is going on... > > Thanks, > > Perry > > >> brian carb >> unisys corporation - malvern, pa >> brian.carb at unisys.com >> >> -----Original Message----- >> From: Perry Myers [mailto:pmyers at redhat.com] >> Sent: Thursday, January 29, 2009 8:38 PM >> To: Carb, Brian A >> Cc: ovirt-devel at redhat.com >> Subject: Re: [Ovirt-devel] Installing a VM in oVirt 0.96 >> >> Carb, Brian A wrote: >>> Installing a VM in oVirt >>> >>> Appliance Host: Dell Optiplex 745, VT-capable, x86_64 Nodes: four >>> cells of ES7000/one, each with 8x at 3.4GHz and 32GB memory >>> >>> Downloaded and installed 0.96 release on top of Fedora10 as indicated >>> in the documentation. Successfully PXE booted 4 ES7000 nodes, and all >>> show up in the oVirt dashboard. Defined a storage pool using the >>> /ovirtnfs share from the appliance at 192.168.50.2 Created a Virtual >>> Machine using one of the NFS disks, 4cpu and 1024mb >>> >>> However, I'm unable to install into that VM. If I launch the QEMU >>> viewer as the VM launches, I can select the Fedora option from the >>> PXE installer... but the fedora install always reports an error with >>> the network interface. If I select retry, the install goes a little >>> farther, downloading the install.img and running the installer. >>> However the system hangs for a long time at "Retrieving installation >>> information for f10-x86_64-updates..." and then fails at "Unable to >>> read package metadata..." >> The initial network error you get that is solved with a retry I have seen every time I try to provision Fedora from a kickstart in oVirt. Hitting retry has always fixed it for me. The problem is probably a transient network issue, like the network bridge not being fully up and forwarding traffic by the time the guest gets to this phase of the install. >> >> If you have bugzilla access and can file a bug at bugzilla.redhat.com under Other->Virtualization Tools->ovirt-node we'll hunt this down and try to fix it. >> >> After the retry though provisioning generally works for me... It could be a few things... The way we have the appliance set up, we provision from cobbler but the cobbler repos are just pointers to upstream Fedora mirrors. So first thing to check would be to make sure that from a Node you can access (ping) the internet. If not, that's probably the issue. >> If you can, it could be a mirror problem since sometimes mirrors are unreliable. >> >>> Any ideas? >>> >>> Also, I saw someone mentioned installation from an ISO - is this >>> supported? Is it possible to use existing VM images? I might be able >>> to specify "boot from HD" and then dd an existing image - but i was >>> looking for a more official method :-) >> We do support provisioning from ISO files. There should be something >> on the wiki about this, if not Darryl Pierce is the developer who set >> that up. The short of it is that you add an ISO image to the >> /cobblernfs directory on the Appliance. Once the ISO is there you >> need to use the cobbler image add command to add the ISO image to >> cobbler >> >> This will make the image ISO show up in the oVirt UI under the provisioning drop down. >> >> Try that out and let me know if it works. >> >> For disk image provisioning, we have plans to support that as well. Just not implemented yet... >> >> Perry > > > -- > |=- 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 > |-=| -- |=- 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 lutter at redhat.com Mon Feb 2 20:35:29 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 2 Feb 2009 12:35:29 -0800 Subject: [Ovirt-devel] [REPOST 1] Various API patches In-Reply-To: <1233004325-18032-1-git-send-email-lutter@redhat.com> References: <1233004325-18032-1-git-send-email-lutter@redhat.com> Message-ID: <1233606937-18469-1-git-send-email-lutter@redhat.com> This is a rebase of the patches onto the current HEAD of next From lutter at redhat.com Mon Feb 2 20:35:30 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 2 Feb 2009 12:35:30 -0800 Subject: [Ovirt-devel] [PATCH server 1/8] Wrap generation of error message in respond_to block In-Reply-To: <1233004325-18032-1-git-send-email-lutter@redhat.com> References: <1233004325-18032-1-git-send-email-lutter@redhat.com> Message-ID: <1233606937-18469-2-git-send-email-lutter@redhat.com> --- src/app/controllers/storage_controller.rb | 10 ++++++---- 1 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/app/controllers/storage_controller.rb b/src/app/controllers/storage_controller.rb index 1920e27..160d22e 100644 --- a/src/app/controllers/storage_controller.rb +++ b/src/app/controllers/storage_controller.rb @@ -302,10 +302,12 @@ class StorageController < ApplicationController def destroy unless @storage_pool.movable? - format.json { render :json => { :object => "storage_pool", - :success => false, - :alert => "Cannot delete storage with associated vms" } } - return + respond_to do |format| + format.json { render :json => { :object => "storage_pool", + :success => false, + :alert => "Cannot delete storage with associated vms" } } + end + return end pool = @storage_pool.hardware_pool -- 1.6.0.6 From lutter at redhat.com Mon Feb 2 20:35:31 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 2 Feb 2009 12:35:31 -0800 Subject: [Ovirt-devel] [PATCH server 2/8] Remove client/ directory, it will live in its own repo In-Reply-To: <1233004325-18032-1-git-send-email-lutter@redhat.com> References: <1233004325-18032-1-git-send-email-lutter@redhat.com> Message-ID: <1233606937-18469-3-git-send-email-lutter@redhat.com> --- client/README | 17 ------- client/examples/script.rb | 101 -------------------------------------------- client/lib/ovirt.rb | 102 --------------------------------------------- 3 files changed, 0 insertions(+), 220 deletions(-) delete mode 100644 client/README delete mode 100755 client/examples/script.rb delete mode 100644 client/lib/ovirt.rb diff --git a/client/README b/client/README deleted file mode 100644 index ee1db15..0000000 --- a/client/README +++ /dev/null @@ -1,17 +0,0 @@ -This is a very simple client library for accessing the OVirt API from Ruby. - -The file examples/script.rb contains a script that shows how this is done -in some detail. - -You must have ActiveResource installed, e.g. with 'yum install -rubygem-activeresource' - -The server is specified with a URL of the form - http://USER:PASSWORD at HOST/ovirt - -This requires that the server is configured to allow HTTP authentication, -since there are no mechanisms in the API to forward krb5 tickets. - -Before calling any other method on the API, you need to call - OVirt::Base::site = "http://USER:PASSWORD at HOST/ovirt" - OVirt::Base::login diff --git a/client/examples/script.rb b/client/examples/script.rb deleted file mode 100755 index 1485535..0000000 --- a/client/examples/script.rb +++ /dev/null @@ -1,101 +0,0 @@ -#! /usr/bin/ruby - -# Sample script that shows how to use the OVirt API - -require 'pp' -require 'rubygems' -require 'activeresource' -require 'optparse' - -require 'ovirt' - -def move_random_host(hosts, pool) - host = hosts[rand(hosts.size)] - puts "Move #{host.hostname} to #{pool.name}" - pool.hosts << host - pool.save -end - -def element_path(obj) - "[#{obj.class.element_path(obj.id)}]" -end - -def print_pool(pool) - puts "\n\nPool #{pool.name}: #{pool.hosts.size} hosts, #{pool.storage_pools.size} storage pools #{element_path(pool)} " - puts "=" * 75 - pool.hosts.each do |h| - printf "%-36s %s\n", h.hostname, element_path(h) - end - pool.storage_pools.each do |sp| - type = sp.nfs? ? "NFS" : "iSCSI" - printf "%-5s %-30s %s\n", type, sp.label, element_path(sp) - end - puts "-" * 75 -end - -# Plumbing so we can find the OVirt server -# "http://ovirt.watzmann.net:3000/ovirt/rest" -PROGNAME=File::basename($0) -OVirt::Base.site = ENV["OVIRT_SERVER"] -opts = OptionParser.new("#{PROGNAME} GLOBAL_OPTS") -opts.separator(" Run some things against an OVirt server. The server is specified with") -opts.separator(" the -s option as a URL of the form http://USER:PASSWORD at SERVER/ovirt") -opts.separator("") -opts.separator "Global options:" -opts.on("-s", "--server=URL", "The OVirt server. Since there is no auth\n" + - "#{" "*37}yet, must be the mongrel server port.\n" + - "#{" "*37}Overrides env var OVIRT_SERVER") do |val| - OVirt::Base.site = val -end - -opts.order(ARGV) - -unless OVirt::Base.site - $stderr.puts < defpool.id, - :name => "mypool" } ) -end - -# Move some hosts around -puts -if defpool.hosts.size > 1 - move_random_host(defpool.hosts, mypool) -elsif mypool.hosts.size > 0 - move_random_host(mypool.hosts, defpool) -end - -# Delete all storage pools for mypool and add a new one -mypool.storage_pools.each do |sp| - puts "Delete storage pool #{sp.id}" - sp.destroy -end - -storage_pool = OVirt::StoragePool.create( { :storage_type => "NFS", - :hardware_pool_id => mypool.id, - :ip_addr => "192.168.122.50", - :export_path => "/exports/pool1" } ) -puts "Created storage pool #{storage_pool.id}" - -# For some reason, mypool.reload doesn't work here -mypool = OVirt::HardwarePool.find_by_path("/default/mypool") -print_pool(mypool) diff --git a/client/lib/ovirt.rb b/client/lib/ovirt.rb deleted file mode 100644 index 15dc467..0000000 --- a/client/lib/ovirt.rb +++ /dev/null @@ -1,102 +0,0 @@ -require 'pp' -require 'rubygems' -require 'activeresource' - -class ActiveResource::Connection - attr_accessor :session - - alias_method :old_default_header, :default_header - - def default_header - old_default_header - @default_header ||= {} - if session - @default_header["Cookie"] = session - end - @default_header - end -end - -module OVirt - class Base < ActiveResource::Base - LOGIN_PATH = "login/login" - - def self.login - response = nil - begin - response = connection.get(prefix + LOGIN_PATH) - rescue ActiveResource::Redirection => e - response = e.response - end - unless connection.session = session_cookie(response) - raise "Authentication failed" - end - end - - private - def self.session_cookie(response) - if cookies = response.get_fields("Set-Cookie") - cookies.find { |cookie| - cookie.split(";")[0].split("=")[0] == "_ovirt_session_id" - } - end - end - - end - - class HardwarePool < Base - def self.find_by_path(path) - find(:first, :params => { :path => path }) - end - - def self.default_pool - find(:first, :params => { :path => "/default" }) - end - end - - class StoragePool < Base - def iscsi? - attributes["type"] == "IscsiStoragePool" - end - - def nfs? - attributes["type"] == "NfsStoragePool" - end - - def label - if iscsi? - "#{ip_addr}:#{port}:#{target}" - elsif nfs? - "#{ip_addr}:#{export_path}" - else - raise "Unknown type #{attributes["type"]}" - end - end - end - - class IscsiStoragePool < StoragePool - def initialize(attributes = {}) - super(attributes.update( "type" => "IscsiStoragePool" )) - end - end - - class NfsStoragePool < StoragePool - def initialize(attributes = {}) - super(attributes.update( "type" => "NfsStoragePool" )) - end - end - - class Host < Base - def self.find_by_uuid(uuid) - find(:first, :params => { :uuid => uuid }) - end - - def self.find_by_hostname(hostname) - find(:first, :params => { :hostname => hostname }) - end - - def hardware_pool - HardwarePool.find(hardware_pool_id) - end - end -end -- 1.6.0.6 From lutter at redhat.com Mon Feb 2 20:35:32 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 2 Feb 2009 12:35:32 -0800 Subject: [Ovirt-devel] [PATCH server 3/8] Include CPU's in host information In-Reply-To: <1233004325-18032-1-git-send-email-lutter@redhat.com> References: <1233004325-18032-1-git-send-email-lutter@redhat.com> Message-ID: <1233606937-18469-4-git-send-email-lutter@redhat.com> --- src/app/controllers/hardware_controller.rb | 7 ++++++- src/app/controllers/host_controller.rb | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/app/controllers/hardware_controller.rb b/src/app/controllers/hardware_controller.rb index fc16a27..0f9cceb 100644 --- a/src/app/controllers/hardware_controller.rb +++ b/src/app/controllers/hardware_controller.rb @@ -51,7 +51,12 @@ class HardwareController < PoolController end respond_to do |format| - format.xml { render :xml => @pools.to_xml(XML_OPTS) } + format.xml { + opts = XML_OPTS.dup + opts[:include] = opts[:include].inject({}) { |m, k| m[k] = {}; m } + opts[:include][:hosts] = { :include => :cpus } + render :xml => @pools.to_xml(opts) + } end end diff --git a/src/app/controllers/host_controller.rb b/src/app/controllers/host_controller.rb index 02ad8c9..f0b8c2b 100644 --- a/src/app/controllers/host_controller.rb +++ b/src/app/controllers/host_controller.rb @@ -61,7 +61,7 @@ class HostController < ApplicationController else respond_to do |format| format.html { render :layout => 'selection' } - format.xml { render :xml => @host.to_xml } + format.xml { render :xml => @host.to_xml(:include => [ :cpus ] ) } end end end -- 1.6.0.6 From lutter at redhat.com Mon Feb 2 20:35:33 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 2 Feb 2009 12:35:33 -0800 Subject: [Ovirt-devel] [PATCH server 4/8] API: include storage_volumes; indicate type for individual pools In-Reply-To: <1233004325-18032-1-git-send-email-lutter@redhat.com> References: <1233004325-18032-1-git-send-email-lutter@redhat.com> Message-ID: <1233606937-18469-5-git-send-email-lutter@redhat.com> --- src/app/controllers/storage_controller.rb | 9 +++++++-- 1 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/app/controllers/storage_controller.rb b/src/app/controllers/storage_controller.rb index 160d22e..ee9f116 100644 --- a/src/app/controllers/storage_controller.rb +++ b/src/app/controllers/storage_controller.rb @@ -32,7 +32,7 @@ class StorageController < ApplicationController list respond_to do |format| format.html { render :action => 'list' } - format.xml { render :xml => @storage_pools.to_xml } + format.xml { render :xml => @storage_pools.to_xml( :include => :storage_volumes) } end end @@ -80,7 +80,12 @@ class StorageController < ApplicationController else respond_to do |format| format.html { render :layout => 'selection' } - format.xml { render :xml => @storage_pool.to_xml } + format.xml { + xml_txt = @storage_pool.to_xml(:include => :storage_volumes) do |xml| + xml.type @storage_pool.class.name + end + render :xml => xml_txt + } end end end -- 1.6.0.6 From lutter at redhat.com Mon Feb 2 20:35:34 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 2 Feb 2009 12:35:34 -0800 Subject: [Ovirt-devel] [PATCH server 5/8] Factor StorageVolume functionality out of StorageController In-Reply-To: <1233004325-18032-1-git-send-email-lutter@redhat.com> References: <1233004325-18032-1-git-send-email-lutter@redhat.com> Message-ID: <1233606937-18469-6-git-send-email-lutter@redhat.com> Storage volumes can now be accessed through their own controller. This is needed to expose them in the API. --- src/app/controllers/search_controller.rb | 12 +- src/app/controllers/storage_controller.rb | 204 ----------------- src/app/controllers/storage_volume_controller.rb | 228 ++++++++++++++++++++ src/app/views/storage/_list_volumes.rhtml | 2 +- src/app/views/storage/_new_volume_form.rhtml | 24 -- src/app/views/storage/new_volume.rhtml | 53 ----- src/app/views/storage/show.rhtml | 2 +- src/app/views/storage/show_volume.rhtml | 87 -------- .../views/storage_volume/_new_volume_form.rhtml | 24 ++ src/app/views/storage_volume/new.rhtml | 53 +++++ src/app/views/storage_volume/show.rhtml | 87 ++++++++ 11 files changed, 400 insertions(+), 376 deletions(-) create mode 100644 src/app/controllers/storage_volume_controller.rb delete mode 100644 src/app/views/storage/_new_volume_form.rhtml delete mode 100644 src/app/views/storage/new_volume.rhtml delete mode 100644 src/app/views/storage/show_volume.rhtml create mode 100644 src/app/views/storage_volume/_new_volume_form.rhtml create mode 100644 src/app/views/storage_volume/new.rhtml create mode 100644 src/app/views/storage_volume/show.rhtml diff --git a/src/app/controllers/search_controller.rb b/src/app/controllers/search_controller.rb index 7551242..0fb6456 100644 --- a/src/app/controllers/search_controller.rb +++ b/src/app/controllers/search_controller.rb @@ -37,14 +37,14 @@ class SearchController < ApplicationController "NfsStoragePool" => {:controller => "storage", :show_action => "show", :searched => true}, - "IscsiStorageVolume" => {:controller => "storage", - :show_action => "show_volume", + "IscsiStorageVolume" => {:controller => "storage_volume", + :show_action => "show", :searched => false}, - "NfsStorageVolume" => {:controller => "storage", - :show_action => "show_volume", + "NfsStorageVolume" => {:controller => "storage_volume", + :show_action => "show", :searched => false}, - "LvmStorageVolume" => {:controller => "storage", - :show_action => "show_volume", + "LvmStorageVolume" => {:controller => "storage_volume", + :show_action => "show", :searched => false}} MULTI_TYPE_MODELS = {"StoragePool" => ["IscsiStoragePool", "NfsStoragePool"]} diff --git a/src/app/controllers/storage_controller.rb b/src/app/controllers/storage_controller.rb index ee9f116..3579967 100644 --- a/src/app/controllers/storage_controller.rb +++ b/src/app/controllers/storage_controller.rb @@ -24,8 +24,6 @@ class StorageController < ApplicationController before_filter :pre_pool_admin, :only => [:refresh] before_filter :pre_new2, :only => [:new2] - before_filter :pre_json, :only => [:storage_volumes_json] - before_filter :pre_create_volume, :only => [:create_volume] before_filter :pre_add, :only => [:add, :addstorage] def index @@ -90,35 +88,6 @@ class StorageController < ApplicationController end end - def storage_volumes_json - @storage_pool = StoragePool.find(params[:id]) - set_perms(@storage_pool.hardware_pool) - unless @can_view - flash[:notice] = 'You do not have permission to view this storage pool: redirecting to top level' - redirect_to :controller => 'dashboard' - end - attr_list = [] - attr_list << :id if (@storage_pool.user_subdividable and @can_modify) - attr_list += [:display_name, :size_in_gb, :get_type_label] - json_list(@storage_pool.storage_volumes, attr_list) - end - def show_volume - @storage_volume = StorageVolume.find(params[:id]) - set_perms(@storage_volume.storage_pool.hardware_pool) - unless @can_view - flash[:notice] = 'You do not have permission to view this storage volume: redirecting to top level' - respond_to do |format| - format.html { redirect_to :controller => 'dashboard' } - format.xml { head :forbidden } - end - else - respond_to do |format| - format.html { render :layout => 'selection' } - format.xml { render :xml => @storage_volume.to_xml } - end - end - end - def new end @@ -127,78 +96,6 @@ class StorageController < ApplicationController render :layout => false end - def new_volume - @return_to_workflow = params[:return_to_workflow] - @return_to_workflow ||= false - if params[:storage_pool_id] - @storage_pool = StoragePool.find(params[:storage_pool_id]) - unless @storage_pool.user_subdividable - #fixme: proper error page for popups - redirect_to :controller => 'dashboard' - return - end - new_volume_internal(@storage_pool, - { :storage_pool_id => params[:storage_pool_id]}) - else - @source_volume = StorageVolume.find(params[:source_volume_id]) - unless @source_volume.supports_lvm_subdivision - #fixme: proper error page for popups - redirect_to :controller => 'dashboard' - return - end - lvm_pool = @source_volume.lvm_storage_pool - unless lvm_pool - # FIXME: what should we do about VG/LV names? - # for now auto-create VG name as ovirt_vg_#{@source_volume.id} - new_params = { :vg_name => "ovirt_vg_#{@source_volume.id}", - :hardware_pool_id => @source_volume.storage_pool.hardware_pool_id} - lvm_pool = StoragePool.factory(StoragePool::LVM, new_params) - lvm_pool.source_volumes << @source_volume - lvm_pool.save! - end - new_volume_internal(lvm_pool, { :storage_pool_id => lvm_pool.id}) - @storage_volume.lv_owner_perms='0744' - @storage_volume.lv_group_perms='0744' - @storage_volume.lv_mode_perms='0744' - end - render :layout => 'popup' - end - - def create_volume - begin - StorageVolume.transaction do - @storage_volume.save! - @task = StorageVolumeTask.new({ :user => @user, - :task_target => @storage_volume, - :action => StorageVolumeTask::ACTION_CREATE_VOLUME, - :state => Task::STATE_QUEUED}) - @task.save! - end - respond_to do |format| - format.json { render :json => { :object => "storage_volume", - :success => true, - :alert => "Storage Volume was successfully created.", - :new_volume => @storage_volume.storage_tree_element({:filter_unavailable => false, :state => 'new'})} } - format.xml { render :xml => @storage_volume, - :status => :created, - # FIXME: create storage_volume_url method if relevant - :location => storage_pool_url(@storage_volume) - } - end - rescue => ex - # FIXME: need to distinguish volume vs. task save errors - respond_to do |format| - format.json { - json_hash = { :object => "storage_volume", :success => false, - :errors => @storage_volume.errors.localize_error_messages.to_a } - json_hash[:message] = ex.message if json_hash[:errors].empty? - render :json => json_hash } - format.xml { render :xml => @storage_volume.errors, - :status => :unprocessable_entity } - end - end - end - def insert_refresh_task @task = StorageTask.new({ :user => @user, :task_target => @storage_pool, @@ -330,67 +227,6 @@ class StorageController < ApplicationController end end - def delete_volumes - storage_volume_ids_str = params[:storage_volume_ids] - storage_volume_ids = storage_volume_ids_str.split(",").collect {|x| x.to_i} - alerts = [] - status = true - begin - StorageVolume.transaction do - storage = StorageVolume.find(:all, :conditions => "id in (#{storage_volume_ids.join(', ')})") - unless storage.empty? - set_perms(storage[0].storage_pool.hardware_pool) - unless @can_modify and storage[0].storage_pool.user_subdividable - respond_to do |format| - format.json { render :json => { :object => "storage_volume", - :success => false, - :alert => "You do not have permission to delete this storage volume." } } - format.xml { head :forbidden } - end - else - storage.each do |storage_volume| - alert, success = delete_volume_internal(storage_volume) - alerts << alert - status = false unless success - end - respond_to do |format| - format.json { render :json => { :object => "storage_volume", - :success => status, :alert => alerts.join("\n") } } - format.xml { head(status ? :ok : :method_not_allowed) } - end - end - else - respond_to do |format| - format.json { render :json => { :object => "storage_volume", - :success => false, :alert => "no volumes selected" } } - format.xml { head(status ? :ok : :method_not_allowed) } - end - end - end - end - end - - def delete_volume - @storage_volume = StorageVolume.find(params[:id]) - set_perms(@storage_volume.storage_pool.hardware_pool) - unless @can_modify and @storage_volume.storage_pool.user_subdividable - respond_to do |format| - format.json { render :json => { :object => "storage_volume", - :success => false, - :alert => "You do not have permission to delete this storage volume." } } - format.xml { head :forbidden } - end - else - alert, success = delete_volume_internal(@storage_volume) - respond_to do |format| - format.json { render :json => { :object => "storage_volume", - :success => success, :alert => alert } } - format.xml { head(success ? :ok : :method_not_allowed) } - end - end - - end - def pre_new @hardware_pool = HardwarePool.find(params[:hardware_pool_id]) @perm_obj = @hardware_pool @@ -424,49 +260,9 @@ class StorageController < ApplicationController @storage_pool = StoragePool.find(params[:id]) @perm_obj = @storage_pool.hardware_pool end - def pre_create_volume - volume = params[:storage_volume] - unless type = params[:storage_type] - type = volume.delete(:storage_type) - end - @storage_volume = StorageVolume.factory(type, volume) - @perm_obj = @storage_volume.storage_pool.hardware_pool - authorize_admin - end - def pre_json - pre_show - end def pre_pool_admin pre_edit authorize_admin end - private - def new_volume_internal(storage_pool, new_params) - @storage_volume = StorageVolume.factory(storage_pool.get_type_label, new_params) - @perm_obj = @storage_volume.storage_pool.hardware_pool - authorize_admin - end - - def delete_volume_internal(volume) - begin - name = volume.display_name - if !volume.vms.empty? - vm_list = volume.vms.collect {|vm| vm.description}.join(", ") - ["Storage Volume #{name} must be unattached from VMs (#{vm_list}) before deleting it.", - false] - else - volume.state=StorageVolume::STATE_PENDING_DELETION - volume.save! - @task = StorageVolumeTask.new({ :user => @user, - :task_target => volume, - :action => StorageVolumeTask::ACTION_DELETE_VOLUME, - :state => Task::STATE_QUEUED}) - @task.save! - ["Storage Volume #{name} deletion was successfully queued.", true] - end - rescue => ex - ["Failed to delete storage volume #{name} (#{ex.message}.",false] - end - end end diff --git a/src/app/controllers/storage_volume_controller.rb b/src/app/controllers/storage_volume_controller.rb new file mode 100644 index 0000000..ba486d2 --- /dev/null +++ b/src/app/controllers/storage_volume_controller.rb @@ -0,0 +1,228 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Scott Seago +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +class StorageVolumeController < ApplicationController + + before_filter :pre_create, :only => [:create] + + def new + @return_to_workflow = params[:return_to_workflow] || false + if params[:storage_pool_id] + @storage_pool = StoragePool.find(params[:storage_pool_id]) + unless @storage_pool.user_subdividable + #fixme: proper error page for popups + redirect_to :controller => 'dashboard' + return + end + new_volume_internal(@storage_pool, + { :storage_pool_id => params[:storage_pool_id]}) + else + @source_volume = StorageVolume.find(params[:source_volume_id]) + unless @source_volume.supports_lvm_subdivision + #fixme: proper error page for popups + redirect_to :controller => 'dashboard' + return + end + lvm_pool = @source_volume.lvm_storage_pool + unless lvm_pool + # FIXME: what should we do about VG/LV names? + # for now auto-create VG name as ovirt_vg_#{@source_volume.id} + new_params = { :vg_name => "ovirt_vg_#{@source_volume.id}", + :hardware_pool_id => @source_volume.storage_pool.hardware_pool_id} + lvm_pool = StoragePool.factory(StoragePool::LVM, new_params) + lvm_pool.source_volumes << @source_volume + lvm_pool.save! + end + new_volume_internal(lvm_pool, { :storage_pool_id => lvm_pool.id}) + @storage_volume.lv_owner_perms='0744' + @storage_volume.lv_group_perms='0744' + @storage_volume.lv_mode_perms='0744' + end + render :layout => 'popup' + end + + def create + begin + StorageVolume.transaction do + @storage_volume.save! + @task = StorageVolumeTask.new({ :user => @user, + :task_target => @storage_volume, + :action => StorageVolumeTask::ACTION_CREATE_VOLUME, + :state => Task::STATE_QUEUED}) + @task.save! + end + respond_to do |format| + format.json { render :json => { :object => "storage_volume", + :success => true, + :alert => "Storage Volume was successfully created." , + :new_volume => @storage_volume.storage_tree_element({:filter_unavailable => false, :state => 'new'})} } + format.xml { render :xml => @storage_volume, + :status => :created, + # FIXME: create storage_volume_url method if relevant + :location => storage_pool_url(@storage_volume) + } + end + rescue => ex + # FIXME: need to distinguish volume vs. task save errors + respond_to do |format| + format.json { + json_hash = { :object => "storage_volume", :success => false, + :errors => @storage_volume.errors.localize_error_messages.to_a } + json_hash[:message] = ex.message if json_hash[:errors].empty? + render :json => json_hash } + format.xml { render :xml => @storage_volume.errors, + :status => :unprocessable_entity } + end + end + end + + def show + @storage_volume = StorageVolume.find(params[:id]) + set_perms(@storage_volume.storage_pool.hardware_pool) + @storage_pool = @storage_volume.storage_pool + unless @can_view + flash[:notice] = 'You do not have permission to view this storage volume: redirecting to top level' + respond_to do |format| + format.html { redirect_to :controller => 'dashboard' } + format.json { redirect_to :controller => 'dashboard' } + format.xml { head :forbidden } + end + else + respond_to do |format| + format.html { render :layout => 'selection' } + format.json do + attr_list = [] + attr_list << :id if (@storage_pool.user_subdividable and @can_modify) + attr_list += [:display_name, :size_in_gb, :get_type_label] + json_list(@storage_pool.storage_volumes, attr_list) + end + format.xml { render :xml => @storage_volume.to_xml } + end + end + end + + def destroy + if params[:id] + delete_volume + else + delete_volumes + end + end + + def delete_volumes + storage_volume_ids_str = params[:storage_volume_ids] + storage_volume_ids = storage_volume_ids_str.split(",").collect {|x| x.to_i} + alerts = [] + status = true + begin + StorageVolume.transaction do + storage = StorageVolume.find(:all, :conditions => "id in (#{storage_volume_ids.join(', ')})") + unless storage.empty? + set_perms(storage[0].storage_pool.hardware_pool) + unless @can_modify and storage[0].storage_pool.user_subdividable + respond_to do |format| + format.json { render :json => { :object => "storage_volume", + :success => false, + :alert => "You do not have permission to delete this storage volume." } } + format.xml { head :forbidden } + end + else + storage.each do |storage_volume| + alert, success = delete_volume_internal(storage_volume) + alerts << alert + status = false unless success + end + respond_to do |format| + format.json { render :json => { :object => "storage_volume", + :success => status, :alert => alerts.join("\n") } } + format.xml { head(status ? :ok : :method_not_allowed) } + end + end + else + respond_to do |format| + format.json { render :json => { :object => "storage_volume", + :success => false, :alert => "no volumes selected" } } + format.xml { head(status ? :ok : :method_not_allowed) } + end + end + end + end + end + + def delete_volume + @storage_volume = StorageVolume.find(params[:id]) + set_perms(@storage_volume.storage_pool.hardware_pool) + unless @can_modify and @storage_volume.storage_pool.user_subdividable + respond_to do |format| + format.json { render :json => { :object => "storage_volume", + :success => false, + :alert => "You do not have permission to delete this storage volume." } } + format.xml { head :forbidden } + end + else + alert, success = delete_volume_internal(@storage_volume) + respond_to do |format| + format.json { render :json => { :object => "storage_volume", + :success => success, :alert => alert } } + format.xml { head(success ? :ok : :method_not_allowed) } + end + end + + end + + def pre_create + volume = params[:storage_volume] + unless type = params[:storage_type] + type = volume.delete(:storage_type) + end + @storage_volume = StorageVolume.factory(type, volume) + @perm_obj = @storage_volume.storage_pool.hardware_pool + authorize_admin + end + + private + def new_volume_internal(storage_pool, new_params) + @storage_volume = StorageVolume.factory(storage_pool.get_type_label, new_params) + @perm_obj = @storage_volume.storage_pool.hardware_pool + authorize_admin + end + + def delete_volume_internal(volume) + begin + name = volume.display_name + if !volume.vms.empty? + vm_list = volume.vms.collect {|vm| vm.description}.join(", ") + ["Storage Volume #{name} must be unattached from VMs (#{vm_list}) before deleting it.", + false] + else + volume.state=StorageVolume::STATE_PENDING_DELETION + volume.save! + @task = StorageVolumeTask.new({ :user => @user, + :task_target => volume, + :action => StorageVolumeTask::ACTION_DELETE_VOLUME, + :state => Task::STATE_QUEUED}) + @task.save! + ["Storage Volume #{name} deletion was successfully queued.", true] + end + rescue => ex + ["Failed to delete storage volume #{name} (#{ex.message}.",false] + end + end + +end diff --git a/src/app/views/storage/_list_volumes.rhtml b/src/app/views/storage/_list_volumes.rhtml index 212720e..ab4f623 100644 --- a/src/app/views/storage/_list_volumes.rhtml +++ b/src/app/views/storage/_list_volumes.rhtml @@ -19,7 +19,7 @@ <% for storage_volume in type_volumes %> - <% vol_hash = { :controller => 'storage', :action => 'show_volume', :id => storage_volume } + <% vol_hash = { :controller => 'storage_volume', :action => 'show', :id => storage_volume } vol_hash[:vm_id] = vm_id if defined? vm_id %> <%= link_to storage_volume.storage_pool.ip_addr, vol_hash, { :class => "show" } %> diff --git a/src/app/views/storage/_new_volume_form.rhtml b/src/app/views/storage/_new_volume_form.rhtml deleted file mode 100644 index ae65e18..0000000 --- a/src/app/views/storage/_new_volume_form.rhtml +++ /dev/null @@ -1,24 +0,0 @@ -<%= error_messages_for 'storage_volume' %> - - -<%= hidden_field 'storage_volume', 'storage_pool_id' %> -<%= hidden_field_tag 'storage_type', @storage_volume.get_type_label %> - -<%= text_field_with_label "Size (GB):", 'storage_volume', 'size_in_gb' %> - -<%if @storage_volume.get_type_label==StoragePool::LVM -%> - <%= text_field_with_label "LV Name:", 'storage_volume', 'lv_name' %> - - <%= text_field_with_label "Owner permissions:", 'storage_volume', 'lv_owner_perms' %> - - <%= text_field_with_label "Group permissions:", 'storage_volume', 'lv_group_perms' %> - - <%= text_field_with_label "Mode permissions:", 'storage_volume', 'lv_mode_perms' %> -<%- end -%> -<%= text_field_with_label "LUN:", 'storage_volume', 'lun' if @storage_volume.get_type_label==StoragePool::ISCSI %> - -<%= text_field_with_label "Filename:", 'storage_volume', 'filename' if @storage_volume.get_type_label==StoragePool::NFS %> - - - - diff --git a/src/app/views/storage/new_volume.rhtml b/src/app/views/storage/new_volume.rhtml deleted file mode 100644 index 2e49d16..0000000 --- a/src/app/views/storage/new_volume.rhtml +++ /dev/null @@ -1,53 +0,0 @@ -<%- content_for :title do -%> - <%= _("Add New Volume") %> -<%- end -%> -<%- content_for :description do -%> - Add a new Storage Volume to - <%= if @storage_volume.get_type_label==StoragePool::LVM - @source_volume.display_name - else - @storage_pool.display_name - end %>. -<%- end -%> -
-
-
-
-
- <%= render :partial => 'new_volume_form' %> -
-
- - <% if @return_to_workflow %> - <%# TODO: update this method in application_helper to take an array, so we can include - a callback or trigger to to go previous step in flow. %> - <%= popup_footer("$('#storage_volume_form').submit()", "New Storage Volume") %> - <% else %> - <%= popup_footer("$('#storage_volume_form').submit()", "New Storage Volume") %> - <% end %> -
-
- diff --git a/src/app/views/storage/show.rhtml b/src/app/views/storage/show.rhtml index 7e02f32..dd52d79 100644 --- a/src/app/views/storage/show.rhtml +++ b/src/app/views/storage/show.rhtml @@ -12,7 +12,7 @@ <%if @storage_pool.user_subdividable -%> <%= link_to image_tag("icon_addstorage.png") + " Add new Volume", - {:controller => 'storage', :action => 'new_volume', :storage_pool_id => @storage_pool.id}, + {:controller => 'storage_volume', :action => 'new', :storage_pool_id => @storage_pool.id}, :rel=>"facebox[.bolder]", :class=>"selection_facebox" %> <% end %> diff --git a/src/app/views/storage/show_volume.rhtml b/src/app/views/storage/show_volume.rhtml deleted file mode 100644 index f85feaa..0000000 --- a/src/app/views/storage/show_volume.rhtml +++ /dev/null @@ -1,87 +0,0 @@ -<%- content_for :title do -%> - <%=h @storage_volume.display_name %> -<%- end -%> - -<%- content_for :action_links do -%> - <%if @can_modify -%> - <%if @storage_volume.supports_lvm_subdivision and @storage_volume.vms.empty? -%> - <%= link_to image_tag("icon_addstorage.png") + " Add new Volume", - {:controller => 'storage', :action => 'new_volume', :source_volume_id => @storage_volume.id}, - :rel=>"facebox[.bolder]", :class=>"selection_facebox" %> - <% end %> - <%if @storage_volume.deletable -%> - - <%= image_tag "icon_x.png" %> Delete - - <%- end -%> - <%- end -%> -<%- end -%> -<%= confirmation_dialog("confirm_delete", "Are you sure?", "delete_volume()") %> - -
- <% unless @storage_volume.storage_pool[:type] == "LvmStoragePool" %> - IP address:
- <% end %> - <% if @storage_volume.storage_pool[:type] == "IscsiStoragePool" %> - Port:
- Target:
- <% elsif @storage_volume.storage_pool[:type] == "NfsStoragePool" %> - Export path:
- <% end %> - Type:
- State:
- Path:
- <% if @storage_volume[:type] == "IscsiStorageVolume" %> - LUN:
- <% elsif @storage_volume[:type] == "NfsStorageVolume" %> - Filename:
- <% elsif @storage_volume[:type] == "LvmStorageVolume" %> - Volume Group:
- Logical Volume:
- Permissions (owner/group/mode):
- <% end %> - Size:
-
-
- <% unless @storage_volume.storage_pool[:type] == "LvmStoragePool" %> - <%=h @storage_volume.storage_pool.ip_addr %>
- <% end %> - <% if @storage_volume.storage_pool[:type] == "IscsiStoragePool" %> - <%=h @storage_volume.storage_pool.port %>
- <%=h @storage_volume.storage_pool[:target] %>
- <% elsif @storage_volume.storage_pool[:type] == "NfsStoragePool" %> - <%=h @storage_volume.storage_pool.export_path %>
- <% end %> - <%=h @storage_volume.storage_pool.get_type_label %>
- <%=h @storage_volume.state %>
- <%=h @storage_volume.path %>
- <% if @storage_volume[:type] == "IscsiStorageVolume" %> - <%=h @storage_volume.lun %>
- <% elsif @storage_volume[:type] == "NfsStorageVolume" %> - <%=h @storage_volume.filename %>
- <% elsif @storage_volume[:type] == "LvmStorageVolume" %> - <%=h @storage_volume.storage_pool.vg_name %>
- <%=h @storage_volume.lv_name %>
- <%=h @storage_volume.lv_owner_perms %>/<%=h @storage_volume.lv_group_perms %>/<%=h @storage_volume.lv_mode_perms %>
- <% end %> - <%=h @storage_volume.size_in_gb %> GB
-
-<%- content_for :right do -%> - -<%- end -%> - - diff --git a/src/app/views/storage_volume/_new_volume_form.rhtml b/src/app/views/storage_volume/_new_volume_form.rhtml new file mode 100644 index 0000000..ae65e18 --- /dev/null +++ b/src/app/views/storage_volume/_new_volume_form.rhtml @@ -0,0 +1,24 @@ +<%= error_messages_for 'storage_volume' %> + + +<%= hidden_field 'storage_volume', 'storage_pool_id' %> +<%= hidden_field_tag 'storage_type', @storage_volume.get_type_label %> + +<%= text_field_with_label "Size (GB):", 'storage_volume', 'size_in_gb' %> + +<%if @storage_volume.get_type_label==StoragePool::LVM -%> + <%= text_field_with_label "LV Name:", 'storage_volume', 'lv_name' %> + + <%= text_field_with_label "Owner permissions:", 'storage_volume', 'lv_owner_perms' %> + + <%= text_field_with_label "Group permissions:", 'storage_volume', 'lv_group_perms' %> + + <%= text_field_with_label "Mode permissions:", 'storage_volume', 'lv_mode_perms' %> +<%- end -%> +<%= text_field_with_label "LUN:", 'storage_volume', 'lun' if @storage_volume.get_type_label==StoragePool::ISCSI %> + +<%= text_field_with_label "Filename:", 'storage_volume', 'filename' if @storage_volume.get_type_label==StoragePool::NFS %> + + + + diff --git a/src/app/views/storage_volume/new.rhtml b/src/app/views/storage_volume/new.rhtml new file mode 100644 index 0000000..46d379e --- /dev/null +++ b/src/app/views/storage_volume/new.rhtml @@ -0,0 +1,53 @@ +<%- content_for :title do -%> + <%= _("Add New Volume") %> +<%- end -%> +<%- content_for :description do -%> + Add a new Storage Volume to + <%= if @storage_volume.get_type_label==StoragePool::LVM + @source_volume.display_name + else + @storage_pool.display_name + end %>. +<%- end -%> +
+
+
+
+
+ <%= render :partial => 'new_volume_form' %> +
+
+ + <% if @return_to_workflow %> + <%# TODO: update this method in application_helper to take an array, so we can include + a callback or trigger to to go previous step in flow. %> + <%= popup_footer("$('#storage_volume_form').submit()", "New Storage Volume") %> + <% else %> + <%= popup_footer("$('#storage_volume_form').submit()", "New Storage Volume") %> + <% end %> +
+
+ diff --git a/src/app/views/storage_volume/show.rhtml b/src/app/views/storage_volume/show.rhtml new file mode 100644 index 0000000..c2434aa --- /dev/null +++ b/src/app/views/storage_volume/show.rhtml @@ -0,0 +1,87 @@ +<%- content_for :title do -%> + <%=h @storage_volume.display_name %> +<%- end -%> + +<%- content_for :action_links do -%> + <%if @can_modify -%> + <%if @storage_volume.supports_lvm_subdivision and @storage_volume.vms.empty? -%> + <%= link_to image_tag("icon_addstorage.png") + " Add new Volume", + {:controller => 'storage_volume', :action => 'new', :source_volume_id => @storage_volume.id}, + :rel=>"facebox[.bolder]", :class=>"selection_facebox" %> + <% end %> + <%if @storage_volume.deletable -%> + + <%= image_tag "icon_x.png" %> Delete + + <%- end -%> + <%- end -%> +<%- end -%> +<%= confirmation_dialog("confirm_delete", "Are you sure?", "delete_volume()") %> + +
+ <% unless @storage_volume.storage_pool[:type] == "LvmStoragePool" %> + IP address:
+ <% end %> + <% if @storage_volume.storage_pool[:type] == "IscsiStoragePool" %> + Port:
+ Target:
+ <% elsif @storage_volume.storage_pool[:type] == "NfsStoragePool" %> + Export path:
+ <% end %> + Type:
+ State:
+ Path:
+ <% if @storage_volume[:type] == "IscsiStorageVolume" %> + LUN:
+ <% elsif @storage_volume[:type] == "NfsStorageVolume" %> + Filename:
+ <% elsif @storage_volume[:type] == "LvmStorageVolume" %> + Volume Group:
+ Logical Volume:
+ Permissions (owner/group/mode):
+ <% end %> + Size:
+
+
+ <% unless @storage_volume.storage_pool[:type] == "LvmStoragePool" %> + <%=h @storage_volume.storage_pool.ip_addr %>
+ <% end %> + <% if @storage_volume.storage_pool[:type] == "IscsiStoragePool" %> + <%=h @storage_volume.storage_pool.port %>
+ <%=h @storage_volume.storage_pool[:target] %>
+ <% elsif @storage_volume.storage_pool[:type] == "NfsStoragePool" %> + <%=h @storage_volume.storage_pool.export_path %>
+ <% end %> + <%=h @storage_volume.storage_pool.get_type_label %>
+ <%=h @storage_volume.state %>
+ <%=h @storage_volume.path %>
+ <% if @storage_volume[:type] == "IscsiStorageVolume" %> + <%=h @storage_volume.lun %>
+ <% elsif @storage_volume[:type] == "NfsStorageVolume" %> + <%=h @storage_volume.filename %>
+ <% elsif @storage_volume[:type] == "LvmStorageVolume" %> + <%=h @storage_volume.storage_pool.vg_name %>
+ <%=h @storage_volume.lv_name %>
+ <%=h @storage_volume.lv_owner_perms %>/<%=h @storage_volume.lv_group_perms %>/<%=h @storage_volume.lv_mode_perms %>
+ <% end %> + <%=h @storage_volume.size_in_gb %> GB
+
+<%- content_for :right do -%> + +<%- end -%> + + -- 1.6.0.6 From lutter at redhat.com Mon Feb 2 20:35:35 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 2 Feb 2009 12:35:35 -0800 Subject: [Ovirt-devel] [PATCH server 6/8] Remove delete_volumes, since it was not used In-Reply-To: <1233004325-18032-1-git-send-email-lutter@redhat.com> References: <1233004325-18032-1-git-send-email-lutter@redhat.com> Message-ID: <1233606937-18469-7-git-send-email-lutter@redhat.com> --- src/app/controllers/storage_volume_controller.rb | 49 ---------------------- src/app/views/storage_volume/show.rhtml | 2 +- 2 files changed, 1 insertions(+), 50 deletions(-) diff --git a/src/app/controllers/storage_volume_controller.rb b/src/app/controllers/storage_volume_controller.rb index ba486d2..9cde09b 100644 --- a/src/app/controllers/storage_volume_controller.rb +++ b/src/app/controllers/storage_volume_controller.rb @@ -118,54 +118,6 @@ class StorageVolumeController < ApplicationController end def destroy - if params[:id] - delete_volume - else - delete_volumes - end - end - - def delete_volumes - storage_volume_ids_str = params[:storage_volume_ids] - storage_volume_ids = storage_volume_ids_str.split(",").collect {|x| x.to_i} - alerts = [] - status = true - begin - StorageVolume.transaction do - storage = StorageVolume.find(:all, :conditions => "id in (#{storage_volume_ids.join(', ')})") - unless storage.empty? - set_perms(storage[0].storage_pool.hardware_pool) - unless @can_modify and storage[0].storage_pool.user_subdividable - respond_to do |format| - format.json { render :json => { :object => "storage_volume", - :success => false, - :alert => "You do not have permission to delete this storage volume." } } - format.xml { head :forbidden } - end - else - storage.each do |storage_volume| - alert, success = delete_volume_internal(storage_volume) - alerts << alert - status = false unless success - end - respond_to do |format| - format.json { render :json => { :object => "storage_volume", - :success => status, :alert => alerts.join("\n") } } - format.xml { head(status ? :ok : :method_not_allowed) } - end - end - else - respond_to do |format| - format.json { render :json => { :object => "storage_volume", - :success => false, :alert => "no volumes selected" } } - format.xml { head(status ? :ok : :method_not_allowed) } - end - end - end - end - end - - def delete_volume @storage_volume = StorageVolume.find(params[:id]) set_perms(@storage_volume.storage_pool.hardware_pool) unless @can_modify and @storage_volume.storage_pool.user_subdividable @@ -183,7 +135,6 @@ class StorageVolumeController < ApplicationController format.xml { head(success ? :ok : :method_not_allowed) } end end - end def pre_create diff --git a/src/app/views/storage_volume/show.rhtml b/src/app/views/storage_volume/show.rhtml index c2434aa..3963a3c 100644 --- a/src/app/views/storage_volume/show.rhtml +++ b/src/app/views/storage_volume/show.rhtml @@ -75,7 +75,7 @@ { $(document).trigger('close.facebox'); $.post('<%= url_for :controller => "storage_volume", :action => "destroy" %>', - { storage_volume_ids: <%= @storage_volume.id %> }, + { id: <%= @storage_volume.id %> }, function(data,status) { // FIXME: reload tree if (data.alert) { -- 1.6.0.6 From lutter at redhat.com Mon Feb 2 20:35:36 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 2 Feb 2009 12:35:36 -0800 Subject: [Ovirt-devel] [PATCH server 7/8] Produce a human-readable error when deleting a pool fails In-Reply-To: <1233004325-18032-1-git-send-email-lutter@redhat.com> References: <1233004325-18032-1-git-send-email-lutter@redhat.com> Message-ID: <1233606937-18469-8-git-send-email-lutter@redhat.com> --- src/app/controllers/storage_controller.rb | 6 ++++-- src/app/views/errors/simple.xml.builder | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 src/app/views/errors/simple.xml.builder diff --git a/src/app/controllers/storage_controller.rb b/src/app/controllers/storage_controller.rb index 3579967..a951656 100644 --- a/src/app/controllers/storage_controller.rb +++ b/src/app/controllers/storage_controller.rb @@ -204,10 +204,12 @@ class StorageController < ApplicationController def destroy unless @storage_pool.movable? + @error = "Cannot delete storage with associated vms" respond_to do |format| format.json { render :json => { :object => "storage_pool", - :success => false, - :alert => "Cannot delete storage with associated vms" } } + :success => false, :alert => @error } } + format.xml { render :template => "errors/simple", :layout => false, + :status => :forbidden } end return end diff --git a/src/app/views/errors/simple.xml.builder b/src/app/views/errors/simple.xml.builder new file mode 100644 index 0000000..d8d3c5b --- /dev/null +++ b/src/app/views/errors/simple.xml.builder @@ -0,0 +1,3 @@ +xml.instruct! + +xml.error @error -- 1.6.0.6 From lutter at redhat.com Mon Feb 2 20:35:37 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 2 Feb 2009 12:35:37 -0800 Subject: [Ovirt-devel] [PATCH server 8/8] REST route for storage volumes In-Reply-To: <1233004325-18032-1-git-send-email-lutter@redhat.com> References: <1233004325-18032-1-git-send-email-lutter@redhat.com> Message-ID: <1233606937-18469-9-git-send-email-lutter@redhat.com> --- src/config/routes.rb | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/src/config/routes.rb b/src/config/routes.rb index 132072e..168ded5 100644 --- a/src/config/routes.rb +++ b/src/config/routes.rb @@ -53,6 +53,7 @@ ActionController::Routing::Routes.draw do |map| # REST work out of the box, and use these as the default routes map.resources :hosts, :controller => 'host' map.resources :storage_pools, :controller => 'storage' + map.resources :storage_volumes, :controller => 'storage_volume' map.resources :hardware_pools, :controller => 'hardware' do |hardware_pools| hardware_pools.resources :hosts, :controller => 'host' hardware_pools.resources :storage_pools, :controller => 'storage' -- 1.6.0.6 From dpierce at redhat.com Mon Feb 2 20:44:02 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Mon, 2 Feb 2009 15:44:02 -0500 Subject: [Ovirt-devel] [PATCH node-image] increase timeout to 30s for CD/USB boot In-Reply-To: <1233527027-32730-1-git-send-email-apevec@redhat.com> References: <1233527027-32730-1-git-send-email-apevec@redhat.com> Message-ID: <20090202204402.GA18806@mcpierce-laptop.rdu.redhat.com> On Sun, Feb 01, 2009 at 11:23:47PM +0100, Alan Pevec wrote: > timeout quickly for PXE boot > --- > common-install.ks | 2 +- > ovirt-pxe | 3 +++ > 2 files changed, 4 insertions(+), 1 deletions(-) > > diff --git a/common-install.ks b/common-install.ks > index 8e34301..0c26d9b 100644 > --- a/common-install.ks > +++ b/common-install.ks > @@ -7,7 +7,7 @@ firewall --disabled > part / --size 550 --fstype ext2 > services --enabled=ntpd,ntpdate,collectd,iptables,network,rsyslog > # This requires a new fixed version of livecd-creator to honor the --append settings. > -bootloader --timeout=5 --append="console=tty0 console=ttyS0,115200n8" > +bootloader --timeout=30 --append="console=tty0 console=ttyS0,115200n8" > > # not included by default in Fedora 10 livecd initramfs > device virtio_blk > diff --git a/ovirt-pxe b/ovirt-pxe > index 5223990..b605644 100755 > --- a/ovirt-pxe > +++ b/ovirt-pxe > @@ -32,3 +32,6 @@ livecd-iso-to-pxeboot $ISO > # append BOOTIF with PXE MAC info > f=tftpboot/pxelinux.cfg/default > grep -q 'IPAPPEND 2' $f || sed -i '/KERNEL/a \\tIPAPPEND 2' $f > + > +# timeout quickly for PXE boots > +sed -i 's/timeout.*/timeout 1/' $f 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 imain at redhat.com Mon Feb 2 21:20:58 2009 From: imain at redhat.com (Ian Main) Date: Mon, 2 Feb 2009 13:20:58 -0800 Subject: [Ovirt-devel] gssapi/kerberos support for qpidd In-Reply-To: <20090129084508.04ad1ab2@tp.mains.net> References: <20090129084508.04ad1ab2@tp.mains.net> Message-ID: <20090202132058.29fb14e5@tp.mains.net> On Thu, 29 Jan 2009 08:45:08 -0800 Ian Main wrote: > > This set of patches adds support gssapi/kerberos to qpidd. You'll note that it's still not secure as we allow 'plain' auth with a guest account for daemons that connect over localhost (taskomatic, dbomatic etc.) and unfortunately there's no way to constrain that to localhost connections at this time. > > The qpid team is putting out a new set of rpms in the next day or two which will add gssapi support to ruby at which point we can move those connections to gssapi as well and remove the plain auth with guest access. I've pushed these patches. I figured we all know the need to go in anyway so if someone has problems using this let me know and we'll get them resolved asap. Ian From bkearney at redhat.com Mon Feb 2 22:25:23 2009 From: bkearney at redhat.com (Bryan Kearney) Date: Mon, 2 Feb 2009 17:25:23 -0500 Subject: [Ovirt-devel] [PATCH server] Tweaked the install file to change the ovirt password to ovirt, uncomments dnsmag config directory, extend the dns config, and run cobbler import. All per perry's comments Message-ID: <1233613523-26851-1-git-send-email-bkearney@redhat.com> THis is a resend of the earlier ptch. It needs to be applied on top of perrys path stream for the installer. In addition to the subject, it breaks out the cobbler import into an appliance and non-appliance portion. -- bk --- .../appliances/ovirt-appliance/ovirt-appliance.pp | 18 ++++- installer/modules/ovirt/files/cobbler-import | 81 ++++++++++++++++++++ .../modules/ovirt/files/cobbler-import-appliance | 55 +++++++++++++ .../modules/ovirt/files/cobbler-import-generic | 23 ++++++ installer/modules/ovirt/manifests/cobbler.pp | 12 +++ installer/modules/ovirt/manifests/dns.pp | 18 +++-- installer/modules/ovirt/manifests/ovirt.pp | 4 + 7 files changed, 199 insertions(+), 12 deletions(-) create mode 100644 installer/modules/ovirt/files/cobbler-import create mode 100644 installer/modules/ovirt/files/cobbler-import-appliance create mode 100644 installer/modules/ovirt/files/cobbler-import-generic diff --git a/installer/appliances/ovirt-appliance/ovirt-appliance.pp b/installer/appliances/ovirt-appliance/ovirt-appliance.pp index 4a7908b..9234d4f 100644 --- a/installer/appliances/ovirt-appliance/ovirt-appliance.pp +++ b/installer/appliances/ovirt-appliance/ovirt-appliance.pp @@ -13,12 +13,12 @@ $ipa_host = 'management.priv.ovirt.org' dns::bundled{setup: mgmt_ipaddr=> $mgmt_ipaddr, prov_ipaddr=> $prov_ipaddr, mgmt_dev => 'eth0', prov_dev => 'eth1'} # dhcp configuration -$dhcp_interface = 'eth1' +$dhcp_interface = 'eth0' $dhcp_network = '192.168.50' $dhcp_start = '3' -$dhcp_stop = '10' +$dhcp_stop = '50' $dhcp_domain = 'priv.ovirt.org' -$ntp_server = '192.168.222.211' +$ntp_server = $mgmt_ipaddr $prov_dns_server = '' $prov_network_gateway = '192.168.50.1' @@ -33,7 +33,7 @@ $db_password = 'cobbler' # FreeIPA configuration $realm_name = 'priv.ovirt.org' -$freeipa_password = 'password' +$freeipa_password = 'ovirt' $ldap_dn = 'cn=ipaConfig,cn=etc,dc=priv,dc=ovirt,dc=org' include cobbler::bundled @@ -42,3 +42,13 @@ include tftp::bundled include postgres::bundled include freeipa::bundled include ovirt::setup + +file {"/usr/sbin/cobbler-import-appliance": + source => "puppet:///ovirt/cobbler-import-appliance", + mode => 755 +} + +single_exec {"cobbler-import-appliance": + command => "/usr/sbin/cobbler-import-appliance >> /var/log/cobbler-import-appliance.log 2>&1", + require => [File["/usr/sbin/cobbler-import-appliance"], Service["cobblerd"], Single_Exec["cobbler-import"]] +} diff --git a/installer/modules/ovirt/files/cobbler-import b/installer/modules/ovirt/files/cobbler-import new file mode 100644 index 0000000..d516c68 --- /dev/null +++ b/installer/modules/ovirt/files/cobbler-import @@ -0,0 +1,81 @@ +#!/bin/sh + +# Import Cobbler profiles on first boot + +url=http://download.fedora.redhat.com/pub/fedora/linux +ksdir=/var/www/cobbler/ks_mirror +rawhide=11 + +set -x +set -e +for dir in $ksdir/* ; do + ova=$dir/.treeinfo.ova + if [ ! -f $ova ]; then + echo "Skipping $dir, no $ova file present" + continue + fi + + os=$(awk '{print $1}' $ova) + ver=$(awk '{print $2}' $ova) + arch=$(awk '{print $3}' $ova) + + cobbler import --name=$os-$ver --arch=$arch --path=$dir + + 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 \ + --mirror=$url/development/$arch/os + repos="" + else + cobbler repo add --name=f$ver-$arch --arch=$arch --mirror-locally=0 \ + --mirror=$url/releases/$ver/Everything/$arch/os + cobbler repo add --name=f$ver-$arch-updates --arch=$arch --mirror-locally=0 \ + --mirror=$url/updates/$ver/$arch.newkey + repos="f$ver-$arch f$ver-$arch-updates" + fi + + cobbler profile edit --name=$os-$ver-$arch \ + --repos="$repos" \ + --kickstart=/var/lib/cobbler/kickstarts/sample-$os-$ver-$arch.ks +done + +node_arch=$(rpm -q --qf "%{arch}" ovirt-node-image) +node_dir=/usr/share/ovirt-node-image + +# Create PXE images from oVirt ISO +pushd $node_dir +ovirt-pxe ovirt-node-image.iso +popd + +cobbler distro add --name="oVirt-Node-$node_arch" --arch=$node_arch \ + --initrd=$node_dir/tftpboot/initrd0.img --kernel=$node_dir/tftpboot/vmlinuz0 \ + --kopts="rootflags=loop root=/ovirt-node-image.iso rootfstype=iso9660 ro console=tty0 console=ttyS0,115200n8" + +cobbler profile add --name=oVirt-Node-$node_arch --distro=oVirt-Node-$node_arch +cobbler system add --netboot-enabled=1 --profile=oVirt-Node-$node_arch \ + --name=node3 --mac=00:16:3e:12:34:57 +cobbler system add --netboot-enabled=1 --profile=oVirt-Node-$node_arch \ + --name=node4 --mac=00:16:3e:12:34:58 --kopts="ovirt_init=scsi ovirt_local_boot" +cobbler system add --netboot-enabled=1 --profile=oVirt-Node-$node_arch \ + --name=node5 --mac=00:16:3e:12:34:59 --kopts="ovirt_init=scsi" + +# TODO use Augeas 0.3.0 Inifile lens +sed -i -e "s/^module = authn_denyall.*/module = authn_configfile/" \ + /etc/cobbler/modules.conf +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/pxe/pxesystem.template +sed -i -e "s/^ONTIMEOUT.*/ONTIMEOUT oVirt-Node-$node_arch/" \ + /etc/cobbler/pxe/pxedefault.template + +service cobblerd restart +cobbler sync +cobbler list + +set +x +set +e +echo "Add new oVirt Nodes as Cobbler systems to make them PXE boot oVirt Node image directly." +echo "oVirt-Node-$node_arch is also default boot option in Cobbler menu" diff --git a/installer/modules/ovirt/files/cobbler-import-appliance b/installer/modules/ovirt/files/cobbler-import-appliance new file mode 100644 index 0000000..89ccfdb --- /dev/null +++ b/installer/modules/ovirt/files/cobbler-import-appliance @@ -0,0 +1,55 @@ +#!/bin/sh + +# Import Cobbler profiles on first boot + +url=http://download.fedora.redhat.com/pub/fedora/linux +ksdir=/var/www/cobbler/ks_mirror +rawhide=11 +node_arch=$(rpm -q --qf "%{arch}" ovirt-node-image) + +set -x +set -e +for dir in $ksdir/* ; do + ova=$dir/.treeinfo.ova + if [ ! -f $ova ]; then + echo "Skipping $dir, no $ova file present" + continue + fi + + os=$(awk '{print $1}' $ova) + ver=$(awk '{print $2}' $ova) + arch=$(awk '{print $3}' $ova) + + # Would prefer cobbler distro add + cobbler import --name=$os-$ver --arch=$arch --path=$dir + + 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 \ + --mirror=$url/development/$arch/os + repos="" + else + cobbler repo add --name=f$ver-$arch --arch=$arch --mirror-locally=0 \ + --mirror=$url/releases/$ver/Everything/$arch/os + cobbler repo add --name=f$ver-$arch-updates --arch=$arch --mirror-locally=0 \ + --mirror=$url/updates/$ver/$arch.newkey + repos="f$ver-$arch f$ver-$arch-updates" + fi + + cobbler profile edit --name=$os-$ver-$arch \ + --repos="$repos" \ + --kickstart=/var/lib/cobbler/kickstarts/sample-$os-$ver-$arch.ks +done + +sed -i -e "s/^server:.*/server: '192.168.50.2'/" \ + -e "s/^next_server:.*/next_server: '192.168.50.2'/" \ + /etc/cobbler/settings + +cobbler system add --netboot-enabled=1 --profile=oVirt-Node-$node_arch \ + --name=node3 --mac=00:16:3e:12:34:57 +cobbler system add --netboot-enabled=1 --profile=oVirt-Node-$node_arch \ + --name=node4 --mac=00:16:3e:12:34:58 --kopts="ovirt_init=scsi ovirt_local_boot" +cobbler system add --netboot-enabled=1 --profile=oVirt-Node-$node_arch \ + --name=node5 --mac=00:16:3e:12:34:59 --kopts="ovirt_init=scsi" diff --git a/installer/modules/ovirt/files/cobbler-import-generic b/installer/modules/ovirt/files/cobbler-import-generic new file mode 100644 index 0000000..cee095d --- /dev/null +++ b/installer/modules/ovirt/files/cobbler-import-generic @@ -0,0 +1,23 @@ +#!/bin/sh + +node_arch=$(rpm -q --qf "%{arch}" ovirt-node-image) +node_dir=/usr/share/ovirt-node-image + +# Create PXE images from oVirt ISO +pushd $node_dir +ovirt-pxe ovirt-node-image.iso +popd + +cobbler distro add --name="oVirt-Node-$node_arch" --arch=$node_arch \ + --initrd=$node_dir/tftpboot/initrd0.img --kernel=$node_dir/tftpboot/vmlinuz0 \ + --kopts="rootflags=loop root=/ovirt-node-image.iso rootfstype=iso9660 ro console=tty0 console=ttyS0,115200n8" +cobbler profile add --name=oVirt-Node-$node_arch --distro=oVirt-Node-$node_arch + +# TODO use Augeas 0.3.0 Inifile lens +sed -i -e '/kernel /a \\tIPAPPEND 2' /etc/cobbler/pxe/pxesystem.template +sed -i -e "s/^ONTIMEOUT.*/ONTIMEOUT oVirt-Node-$node_arch/" \ + /etc/cobbler/pxe/pxedefault.template + +#service cobblerd restart +#cobbler sync +#cobbler list diff --git a/installer/modules/ovirt/manifests/cobbler.pp b/installer/modules/ovirt/manifests/cobbler.pp index ca83b38..1cbf605 100644 --- a/installer/modules/ovirt/manifests/cobbler.pp +++ b/installer/modules/ovirt/manifests/cobbler.pp @@ -108,6 +108,18 @@ class cobbler::bundled { # firewall_rule{"25150": destination_port => "25150"} # firewall_rule{"25151": destination_port => "25151"} + + file {"/usr/sbin/cobbler-import": + source => "puppet:///ovirt/cobbler-import-generic", + mode => 755 + } + + single_exec {"cobbler-import": + command => "/usr/sbin/cobbler-import >> /var/log/cobbler-import.log 2>&1", + require => [File["/usr/sbin/cobbler-import"], + Service["cobblerd"]] + } + } class cobbler::remote { diff --git a/installer/modules/ovirt/manifests/dns.pp b/installer/modules/ovirt/manifests/dns.pp index 5326c7c..d1d18fc 100644 --- a/installer/modules/ovirt/manifests/dns.pp +++ b/installer/modules/ovirt/manifests/dns.pp @@ -19,6 +19,9 @@ #-- # common featues + +import "augeas" + define dns::common($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") { package {"dnsmasq": @@ -44,14 +47,13 @@ define dns::common($mgmt_ipaddr="", $prov_ipaddr="",$mgmt_dev="",$prov_dev="") { 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"] - } + augeas{"appliance_info": + context => "/files/etc/dnsmasq.conf", + changes => [ + "set conf-dir /etc/dnsmasq.d" + ], + notify => Service[dnsmasq] + } file {"/etc/dhclient.conf": ensure => present diff --git a/installer/modules/ovirt/manifests/ovirt.pp b/installer/modules/ovirt/manifests/ovirt.pp index c9d3aee..9eab6bd 100644 --- a/installer/modules/ovirt/manifests/ovirt.pp +++ b/installer/modules/ovirt/manifests/ovirt.pp @@ -149,6 +149,10 @@ class ovirt::setup { require => Package[ntp] } + service {"ace" : + enable => false + } + # firewall_rule{"http": destination_port => "80"} } -- 1.6.0.6 From mmorsi at redhat.com Mon Feb 2 22:40:42 2009 From: mmorsi at redhat.com (Mohammed Morsi) Date: Mon, 2 Feb 2009 17:40:42 -0500 Subject: [Ovirt-devel] [PATCH server] allow admin to setup iptables port forwarding on server for a vm's vnc port Message-ID: <1233614442-7907-1-git-send-email-mmorsi@redhat.com> --- src/app/controllers/vm_controller.rb | 21 +++++- src/app/models/vm.rb | 26 ++++++ src/app/views/vm/_form.rhtml | 15 ++++ src/app/views/vm/show.rhtml | 4 + src/db/migrate/034_add_vm_vnc.rb | 30 +++++++ src/task-omatic/taskomatic.rb | 4 + src/task-omatic/vnc.rb | 140 ++++++++++++++++++++++++++++++++++ src/test/fixtures/vms.yml | 2 + src/test/unit/vm_test.rb | 16 ++++ 9 files changed, 257 insertions(+), 1 deletions(-) create mode 100644 src/db/migrate/034_add_vm_vnc.rb create mode 100644 src/task-omatic/vnc.rb diff --git a/src/app/controllers/vm_controller.rb b/src/app/controllers/vm_controller.rb index 56501fd..d4c516b 100644 --- a/src/app/controllers/vm_controller.rb +++ b/src/app/controllers/vm_controller.rb @@ -116,6 +116,15 @@ class VmController < ApplicationController new_storage_ids = new_storage_ids.sort.collect {|x| x.to_i } needs_restart = true unless current_storage_ids == new_storage_ids end + params[:vm][:forward_vnc] = params[:forward_vnc] + if params[:forward_vnc] + if params[:vm][:forward_vnc_port].to_i == 0 + params[:vm][:forward_vnc_port] = Vm.available_forward_vnc_port + end + else + params[:vm][:forward_vnc_port] = nil + end + params[:vm][:needs_restart] = 1 if needs_restart @vm.update_attributes!(params[:vm]) _setup_vm_provision(params) @@ -325,7 +334,8 @@ class VmController < ApplicationController newargs = { :vm_resource_pool_id => params[:vm_resource_pool_id], :vnic_mac_addr => mac.collect {|x| "%02x" % x}.join(":"), - :uuid => uuid + :uuid => uuid, + :forward_vnc_port => 0 } @vm = Vm.new( newargs ) unless params[:vm_resource_pool_id] @@ -345,6 +355,14 @@ class VmController < ApplicationController vm_resource_pool.create_with_parent(hardware_pool) params[:vm][:vm_resource_pool_id] = vm_resource_pool.id end + params[:vm][:forward_vnc] = params[:forward_vnc] + if params[:forward_vnc] + if params[:vm][:forward_vnc_port].to_i == 0 + params[:vm][:forward_vnc_port] = Vm.available_forward_vnc_port + end + else + params[:vm][:forward_vnc_port] = nil + end @vm = Vm.new(params[:vm]) @perm_obj = @vm.vm_resource_pool @current_pool_id=@perm_obj.id @@ -356,6 +374,7 @@ class VmController < ApplicationController end def pre_edit @vm = Vm.find(params[:id]) + @vm.forward_vnc_port = 0 unless @vm.forward_vnc @perm_obj = @vm.vm_resource_pool @current_pool_id=@perm_obj.id _setup_provisioning_options diff --git a/src/app/models/vm.rb b/src/app/models/vm.rb index bf99e2d..1cfcc72 100644 --- a/src/app/models/vm.rb +++ b/src/app/models/vm.rb @@ -40,6 +40,17 @@ class Vm < ActiveRecord::Base validates_format_of :uuid, :with => %r([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}) + FORWARD_VNC_PORT_START = 5900 + + validates_numericality_of :forward_vnc_port, + :message => 'must be >= ' + FORWARD_VNC_PORT_START.to_s, + :greater_than_or_equal_to => FORWARD_VNC_PORT_START, + :if => Proc.new { |vm| vm.forward_vnc } + + validates_uniqueness_of :forward_vnc_port, + :message => "is already in use", + :if => Proc.new { |vm| vm.forward_vnc } + validates_numericality_of :needs_restart, :greater_than_or_equal_to => 0, :less_than_or_equal_to => 1, @@ -335,6 +346,21 @@ class Vm < ActiveRecord::Base super end + # find the first available vnc port + def self.available_forward_vnc_port + # FIXME need a way to reserve values returned + # by this until table is saved + + i = FORWARD_VNC_PORT_START + Vm.find(:all, + :conditions => "forward_vnc_port is not NULL", + :order => 'forward_vnc_port ASC' ).collect{ |vm| + return i if vm.forward_vnc_port > i + i = i + 1 + } + return i + end + protected def validate resources = vm_resource_pool.max_resources_for_vm(self) diff --git a/src/app/views/vm/_form.rhtml b/src/app/views/vm/_form.rhtml index 7cbe16d..f1c0239 100644 --- a/src/app/views/vm/_form.rhtml +++ b/src/app/views/vm/_form.rhtml @@ -51,6 +51,21 @@
+
+ <%= check_box_tag_with_label "Forward vm's vnc port locally", "forward_vnc", 1, @vm.forward_vnc %> + (set to 0 to autoassign port) +
+
+ <%= text_field_with_label "", "vm", "forward_vnc_port", { :style=>"width: 80px;", :size => 7, :disabled => ! @vm.forward_vnc } %> +
+
+
+ + <%= check_box_tag_with_label "Start VM Now? (pending current resource availability)", "start_now", nil if create or @vm.state == Vm::STATE_STOPPED %> <%= check_box_tag_with_label "Restart VM Now? (pending current resource availability)", "restart_now", nil if @vm.state == Vm::STATE_RUNNING %> diff --git a/src/app/views/vm/show.rhtml b/src/app/views/vm/show.rhtml index f361131..add29b4 100644 --- a/src/app/views/vm/show.rhtml +++ b/src/app/views/vm/show.rhtml @@ -88,6 +88,7 @@
Uuid:
+ <%= @vm.forward_vnc ? "VNC uri:
" : "" %> Num vcpus allocated:
Num vcpus used:
Memory allocated:
@@ -100,6 +101,9 @@
<%=h @vm.uuid %>
+ <%= url = request.url + url = request.url[0..(url.index('/', 8) - 1)] + ":" + @vm.forward_vnc_port.to_s + @vm.forward_vnc ? (url + "
") : "" %> <%=h @vm.num_vcpus_allocated %>
<%=h @vm.num_vcpus_used %>
<%=h @vm.memory_allocated_in_mb %> MB
diff --git a/src/db/migrate/034_add_vm_vnc.rb b/src/db/migrate/034_add_vm_vnc.rb new file mode 100644 index 0000000..f23e24d --- /dev/null +++ b/src/db/migrate/034_add_vm_vnc.rb @@ -0,0 +1,30 @@ +# Copyright (C) 2008 Red Hat, Inc. +# Written by Mohammed Morsi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +class AddVmVnc < ActiveRecord::Migration + def self.up + add_column :vms, :forward_vnc, :bool, :default => false + add_column :vms, :forward_vnc_port, :int, :default => 0, :unique => true + end + + def self.down + drop_column :vms, :forward_vnc + drop_column :vms, :forward_vnc_port + end +end + diff --git a/src/task-omatic/taskomatic.rb b/src/task-omatic/taskomatic.rb index 0570246..380be92 100755 --- a/src/task-omatic/taskomatic.rb +++ b/src/task-omatic/taskomatic.rb @@ -32,6 +32,7 @@ include Daemonize require 'task_vm' require 'task_storage' +require 'vnc' class TaskOmatic @@ -232,6 +233,8 @@ class TaskOmatic raise "Error destroying VM: #{result.text}" unless result.status == 0 end + VmVnc.close(vm) + # undefine can fail, for instance, if we live migrated from A -> B, and # then we are shutting down the VM on B (because it only has "transient" # XML). Therefore, just ignore undefine errors so we do the rest @@ -303,6 +306,7 @@ class TaskOmatic # of places so you'll see a lot of .reloads. db_vm.reload set_vm_vnc_port(db_vm, result.description) unless result.status != 0 + VmVnc.forward(db_vm) # This information is not available via the libvirt interface. db_vm.memory_used = db_vm.memory_allocated diff --git a/src/task-omatic/vnc.rb b/src/task-omatic/vnc.rb new file mode 100644 index 0000000..0876f36 --- /dev/null +++ b/src/task-omatic/vnc.rb @@ -0,0 +1,140 @@ +# Copyright (C) 2008 Red Hat, Inc. +# Written by Mohammed Morsi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +# provides static 'forward' and 'close' methods to forward a specified vm's vnc connections +class VmVnc + + private + + # TODO no ruby/libiptc wrapper exists, when + # it does replace iptables command w/ calls to it + IPTABLES_CMD='/sbin/iptables ' + + VNC_DEBUG = false + + # FIXME can this be retreived in any way + # since machine will have both external + # and internal network interface + LOCAL_IP = '192.168.50.2' + + def self.debug(msg) + puts "\n" + msg + "\n" if VNC_DEBUG + end + + def self.find_host_ip(hostname) + # FIXME + addrinfo = Socket::getaddrinfo(hostname, nil) + unless addrinfo.size > 0 + raise "Could not retreive address for " + hostname + end + result = addrinfo[0][3] # return ip address of first entry + debug( "vm host hostname resolved to " + result.to_s ) + return result + end + + def self.port_open?(port) + cmd=IPTABLES_CMD + ' -t nat -nL ' + debug("vncPortOpen? iptables command: " + cmd) + + `#{cmd}`.each_line do |l| + return true if l =~ /.*#{port}.*/ + end + return false + end + + def self.get_forward_rules(vm) + ip = find_host_ip(vm.host.hostname) + return " -d " + ip + " -p tcp --dport " + vm.vnc_port.to_s + " -j ACCEPT", + " -s " + ip + " -p tcp --sport " + vm.vnc_port.to_s + " -j ACCEPT" + end + + def self.get_nat_rules(vm) + ip = find_host_ip(vm.host.hostname) + + return " -p tcp --dport " + vm.forward_vnc_port.to_s + " -j DNAT --to " + ip + ":" + vm.vnc_port.to_s, + " -d " + ip + " -p tcp --dport " + vm.vnc_port.to_s + " -j SNAT --to " + LOCAL_IP + end + + def self.run_command(cmd) + debug("Running command " + cmd) + status = system(cmd) + raise 'Command terminated with error code ' + $?.to_s unless status + end + + public + + def self.forward(vm) + return unless vm.forward_vnc + unless vm.forward_vnc_port > 0 + raise "Must specify valid port to forward " + vm.forward_vnc_port.to_s + end + + if port_open?(vm.forward_vnc_port) + raise "Port already open " + vm.forward_vnc_port.to_s + end + + forward_rule1, forward_rule2 = get_forward_rules(vm) + forward_rule1 = IPTABLES_CMD + " -A FORWARD " + forward_rule1 + forward_rule2 = IPTABLES_CMD + " -A FORWARD " + forward_rule2 + + prerouting_rule, postrouting_rule = get_nat_rules(vm) + prerouting_rule = IPTABLES_CMD + " -t nat -A PREROUTING " + prerouting_rule + postrouting_rule = IPTABLES_CMD + " -t nat -A POSTROUTING " + postrouting_rule + + debug(" open\n forward rule 1: " + forward_rule1 + + "\n forward_rule 2: " + forward_rule2 + + "\n prerouting rule: " + prerouting_rule + + "\n postrouting rule: " + postrouting_rule) + + File::open("/proc/sys/net/ipv4/ip_forward", "w") { |f| f.puts "1" } + run_command(forward_rule1) + run_command(forward_rule2) + run_command(prerouting_rule) + run_command(postrouting_rule) + end + + def self.close(vm) + # FIXME forward_vnc may have been changed while the vm is running + return unless vm.forward_vnc + unless vm.forward_vnc_port > 0 + raise "Must specify valid port to forward " + vm.forward_vnc_port.to_s + end + + unless port_open?(vm.forward_vnc_port) + raise "Port not open " + vm.forward_vnc_port.to_s + end + + forward_rule1, forward_rule2 = get_forward_rules(vm) + forward_rule1 = IPTABLES_CMD + " -D FORWARD " + forward_rule1 + forward_rule2 = IPTABLES_CMD + " -D FORWARD " + forward_rule2 + + prerouting_rule, postrouting_rule = get_nat_rules(vm) + prerouting_rule = IPTABLES_CMD + " -t nat -D PREROUTING " + prerouting_rule + postrouting_rule = IPTABLES_CMD + " -t nat -D POSTROUTING " + postrouting_rule + + debug(" close\n forward rule 1: " + forward_rule1 + + "\n forward_rule 2: " + forward_rule2 + + "\n prerouting rule: " + prerouting_rule + + "\n postrouting rule: " + postrouting_rule) + + run_command(forward_rule1) + run_command(forward_rule2) + run_command(prerouting_rule) + run_command(postrouting_rule) + end +end diff --git a/src/test/fixtures/vms.yml b/src/test/fixtures/vms.yml index ca0d63f..366f192 100644 --- a/src/test/fixtures/vms.yml +++ b/src/test/fixtures/vms.yml @@ -11,6 +11,8 @@ production_httpd_vm: boot_device: hd host: prod_corp_com vm_resource_pool: corp_com_production_vmpool + forward_vnc: true + forward_vnc_port: 1234 production_mysqld_vm: uuid: 89e62d32-04d9-4351-b573-b1a253397296 description: production mysqld appliance diff --git a/src/test/unit/vm_test.rb b/src/test/unit/vm_test.rb index cba3188..b868dfa 100644 --- a/src/test/unit/vm_test.rb +++ b/src/test/unit/vm_test.rb @@ -95,6 +95,22 @@ class VmTest < Test::Unit::TestCase flunk 'Vm must specify valid state' if @vm.valid? end + # ensure duplicate forward_vnc_ports cannot exist + def test_invalid_without_unique_forward_vnc_port + vm = vms(:production_mysqld_vm) + vm.forward_vnc = true + vm.forward_vnc_port = 1234 # duplicate + assert !vm.valid?, "forward vnc port must be unique" + end + + # ensure bad forward_vnc_ports cannot exist + def test_invalid_without_bad_forward_vnc_port + vm = vms(:production_mysqld_vm) + vm.forward_vnc = true + vm.forward_vnc_port = 1 # too small + assert !vm.valid?, "forward vnc port must be >= 5900" + end + # Ensures that, if the VM does not contain the Cobbler prefix, that it # does not claim to be a Cobbler VM. # -- 1.6.0.6 From mmorsi at redhat.com Mon Feb 2 22:48:59 2009 From: mmorsi at redhat.com (Mohammed Morsi) Date: Mon, 02 Feb 2009 17:48:59 -0500 Subject: [Ovirt-devel] Re: [PATCH server] allow admin to setup iptables port forwarding on server for a vm's vnc port In-Reply-To: <1233359683.15906.372.camel@localhost.localdomain> References: <1233191768-9399-1-git-send-email-mmorsi@redhat.com> <1233359683.15906.372.camel@localhost.localdomain> Message-ID: <4987785B.80709@redhat.com> Just sent out a followup patch addressing these issues, comments inline below. David Lutterkort wrote: > On Wed, 2009-01-28 at 20:16 -0500, Mohammed Morsi wrote: > > >> diff --git a/src/app/models/vm.rb b/src/app/models/vm.rb >> index bf99e2d..63c9232 100644 >> --- a/src/app/models/vm.rb >> +++ b/src/app/models/vm.rb >> > > >> @@ -335,6 +344,14 @@ class Vm < ActiveRecord::Base >> super >> end >> >> + def self.available_forward_vnc_port >> + i = 5900 >> + until Vm.find(:first, :conditions => [ "forward_vnc_port = ?", i]).nil? >> + i += 1 >> + end >> + return i >> + end >> + >> > > I like that you're auto-assigning those ports now :) Unfortunately, the > above code is (a) inefficient and (b) will blow up when multiple people > need a vnc port at almost the same time - it is possible that they both > get the same vnc port, and things will blow up when the second one tries > to store the vm to the database (thanks to the unique constraint on > forward_vnc_port - that's vital) > > To make this more efficient, you can just suck all the assigned ports > into memory, something like > > select forward_vnc_port from vms where forward_vnc_port is not null; > > and then pick the next available from that list. > Done, thanks for the performance tip. > To address the race condition, the simplest solution is to take an > exclusive table lock on the vms table (before listing the assigned vnc > ports !) and hold that until the vm is saved in the DB, i.e. the end of > the current transaction. > > This is not done as I'm a little concerned about locking the table (what if the user doesn't submit the form and walks away, will it stay locked?). I changed the additions to the server such that the autogenerated port isn't displayed in the form, eg the user is prompted to set the port or leave it at '0' after which the server will autogenerate it immediately before saving. Because I'm not employing locks, I believe the race condition you described is still possible, but the rails validation / errors framework should take care of that, as when the user submits the form, the uniqueness constraint will be checked and fail, resulting in the save operation not completing and an error message being presented in the wui indicating that the port is already in use and to select another (or autoassign it). >> diff --git a/src/task-omatic/vnc.rb b/src/task-omatic/vnc.rb >> new file mode 100644 >> index 0000000..bc3fd8f >> --- /dev/null >> +++ b/src/task-omatic/vnc.rb >> @@ -0,0 +1,136 @@ >> +# Copyright (C) 2008 Red Hat, Inc. >> +# Written by Mohammed Morsi >> +# >> +# This program is free software; you can redistribute it and/or modify >> +# it under the terms of the GNU General Public License as published by >> +# the Free Software Foundation; version 2 of the License. >> +# >> +# This program is distributed in the hope that it will be useful, >> +# but WITHOUT ANY WARRANTY; without even the implied warranty of >> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> +# GNU General Public License for more details. >> +# >> +# You should have received a copy of the GNU General Public License >> +# along with this program; if not, write to the Free Software >> +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, >> +# MA 02110-1301, USA. A copy of the GNU General Public License is >> +# also available at http://www.gnu.org/copyleft/gpl.html. >> + >> +# provides static 'forward' and 'close' methods to forward a specified vm's vnc connections >> +class VmVnc >> > > Much better :) > > >> + system(forward_rule1) >> + system(forward_rule2) >> + system(prerouting_rule) >> + system(postrouting_rule) >> + system(IP_FORWARD_CMD) >> > > You should at the very least check the exit status of all those system > commands and raise an error if any ofthem exit with nonzero. > > BTW, you could save one shell invocation by replacing > 'system(IP_FORWARD_CMD)' with > > File::open("/proc/sys/net/ipv4/ip_forward", "w") { |f| f.puts > "1" } > > David > > > Both the checking of the status and the open file call are now being done. Thanks for these tips. -Mo From lutter at redhat.com Mon Feb 2 23:00:30 2009 From: lutter at redhat.com (David Lutterkort) Date: Mon, 02 Feb 2009 23:00:30 +0000 Subject: [Ovirt-devel] Re: [PATCH server] allow admin to setup iptables port forwarding on server for a vm's vnc port In-Reply-To: <4987785B.80709@redhat.com> References: <1233191768-9399-1-git-send-email-mmorsi@redhat.com> <1233359683.15906.372.camel@localhost.localdomain> <4987785B.80709@redhat.com> Message-ID: <1233615630.20462.16.camel@localhost.localdomain> On Mon, 2009-02-02 at 17:48 -0500, Mohammed Morsi wrote: > David Lutterkort wrote: > > On Wed, 2009-01-28 at 20:16 -0500, Mohammed Morsi wrote: > > > > To address the race condition, the simplest solution is to take an > > exclusive table lock on the vms table (before listing the assigned vnc > > ports !) and hold that until the vm is saved in the DB, i.e. the end of > > the current transaction. > > > > > This is not done as I'm a little concerned about locking the table (what > if the user doesn't submit the form and walks away, will it stay > locked?). I must have misunderstood the logic: I thought the port-assignment logic was happening as part of saving the VM, not when the form is presented to the user. > I changed the additions to the server such that the > autogenerated port isn't displayed in the form, eg the user is prompted > to set the port or leave it at '0' after which the server will > autogenerate it immediately before saving. Yes, that's the flow that makes sense. > Because I'm not employing > locks, I believe the race condition you described is still possible, but > the rails validation / errors framework should take care of that, as > when the user submits the form, the uniqueness constraint will be > checked and fail, resulting in the save operation not completing and an > error message being presented in the wui indicating that the port is > already in use and to select another (or autoassign it). Kicking out that error when the user wants 'autoassign' is pretty confusing. As long as you take the lock inside a transaction, it will be released at the end of the transaction, i.e. something like this _should_ do the right thing Vm.transaction do # Whatever Rails magic is needed to do 'LOCK TABLE vms EXCLUSIVE;' ... determine vnc port ... ... save VM ... end David From pmyers at redhat.com Tue Feb 3 02:08:57 2009 From: pmyers at redhat.com (Perry Myers) Date: Mon, 02 Feb 2009 21:08:57 -0500 Subject: [Ovirt-devel] Installing a VM in oVirt 0.96 In-Reply-To: <0AAE5AB84B013E45A7B61CB66943C17215B5F892BF@USEA-EXCH7.na.uis.unisys.com> References: <20090129164641.491FB8E0371@hormel.redhat.com> <0AAE5AB84B013E45A7B61CB66943C17215B5DCF688@USEA-EXCH7.na.uis.unisys.com> <49825A00.70209@redhat.com> <0AAE5AB84B013E45A7B61CB66943C17215B5E29981@USEA-EXCH7.na.uis.unisys.com> <49834F20.8020507@redhat.com> <0AAE5AB84B013E45A7B61CB66943C17215B5F88E72@USEA-EXCH7.na.uis.unisys.com> <4987557A.7000501@redhat.com> <0AAE5AB84B013E45A7B61CB66943C17215B5F892BF@USEA-EXCH7.na.uis.unisys.com> Message-ID: <4987A739.6040001@redhat.com> Carb, Brian A wrote: >> Can you give me the exact syntax for cobbler that you used to add the image? >> The syntax for the nfs:// url part needs to follow some strict conventions in >> order to work properly, but upstream cobbler doesn't do any validation >> of that string so it won't tell you if you did it incorrectly. > >> This thread on ovirt-devel is useful and will probably help fix your issue: >> https://www.redhat.com/archives/ovirt-devel/2008-December/msg00234.html > > I added an iso image to cobbler with the command > cobbler image add --name=slax-6.0.6 --file=/cobblernfs/slax-6.0.6.iso > > but once I read the thread I issued 2 new commands: > cobbler image remove --name=slax-6.0.6 > cobbler image add --name=slax-6.0.6 --file=192.168.50.2:/cobblernfs/slax-6.0.6.iso --image-type=iso > > but now cobbler daemon cannot restart and complains at every command: > invalid image name (slax-6.0.6) > i must have done something wrong using the remove. Hmm. This would seem to be more of a cobbler issue. You could try editing the file for that image in: /var/lib/cobbler/config/images.d And then restarting the daemon again. I don't see anything wrong in that syntax. I've cc'd Mike DeHaan as he may be able to help with this. Perry From mdehaan at redhat.com Tue Feb 3 02:48:42 2009 From: mdehaan at redhat.com (Michael DeHaan) Date: Mon, 02 Feb 2009 21:48:42 -0500 Subject: [Ovirt-devel] Installing a VM in oVirt 0.96 In-Reply-To: <4987A739.6040001@redhat.com> References: <20090129164641.491FB8E0371@hormel.redhat.com> <0AAE5AB84B013E45A7B61CB66943C17215B5DCF688@USEA-EXCH7.na.uis.unisys.com> <49825A00.70209@redhat.com> <0AAE5AB84B013E45A7B61CB66943C17215B5E29981@USEA-EXCH7.na.uis.unisys.com> <49834F20.8020507@redhat.com> <0AAE5AB84B013E45A7B61CB66943C17215B5F88E72@USEA-EXCH7.na.uis.unisys.com> <4987557A.7000501@redhat.com> <0AAE5AB84B013E45A7B61CB66943C17215B5F892BF@USEA-EXCH7.na.uis.unisys.com> <4987A739.6040001@redhat.com> Message-ID: <4987B08A.8030705@redhat.com> Perry Myers wrote: > Carb, Brian A wrote: >>> Can you give me the exact syntax for cobbler that you used to add >>> the image? >>> The syntax for the nfs:// url part needs to follow some strict >>> conventions in >>> order to work properly, but upstream cobbler doesn't do any validation >>> of that string so it won't tell you if you did it incorrectly. >> >>> This thread on ovirt-devel is useful and will probably help fix your >>> issue: >>> https://www.redhat.com/archives/ovirt-devel/2008-December/msg00234.html >> >> I added an iso image to cobbler with the command >> cobbler image add --name=slax-6.0.6 --file=/cobblernfs/slax-6.0.6.iso >> >> but once I read the thread I issued 2 new commands: >> cobbler image remove --name=slax-6.0.6 >> cobbler image add --name=slax-6.0.6 >> --file=192.168.50.2:/cobblernfs/slax-6.0.6.iso --image-type=iso >> >> but now cobbler daemon cannot restart and complains at every command: >> invalid image name (slax-6.0.6) >> i must have done something wrong using the remove. > > Hmm. This would seem to be more of a cobbler issue. You could try > editing the file for that image in: > /var/lib/cobbler/config/images.d > > And then restarting the daemon again. I don't see anything wrong in > that syntax. > > I've cc'd Mike DeHaan as he may be able to help with this. > > Perry Which Cobbler version is this? I think I recall a bug about the wrong parameter being passed to that but can't remember right now. Let me know what version (rpm -q cobbler) and I'll take a look. Cobbler has pretty good automated tests for nearly everything /but/ the command line flags now. Sorry about that, we'll take care of it. --Michael From apevec at redhat.com Tue Feb 3 03:44:16 2009 From: apevec at redhat.com (Alan Pevec) Date: Tue, 3 Feb 2009 04:44:16 +0100 Subject: [Ovirt-devel] [PATCH node] improve ovirt-config-boot Message-ID: <1233632656-4282-1-git-send-email-apevec@redhat.com> setup two Root LVs, install into non-active and switch them just before reboot drop drive from parameters, always use /dev/disk/by-label/BOOT to find the boot partition enable post-install hooks for e.g. Cobbler PXE-only-once feature Signed-off-by: Alan Pevec --- ovirt-node.spec.in | 4 ++ scripts/ovirt-config-boot | 83 ++++++++++++++++++------------------- scripts/ovirt-config-boot-wrapper | 5 ++- scripts/ovirt-config-storage | 11 +++-- scripts/ovirt-early | 3 +- scripts/ovirt-firstboot | 3 +- scripts/ovirt-functions | 29 ++++++++---- 7 files changed, 79 insertions(+), 59 deletions(-) diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in index 287a29f..5226131 100644 --- a/ovirt-node.spec.in +++ b/ovirt-node.spec.in @@ -190,6 +190,9 @@ mkdir -p %{buildroot}/usr/lib/anaconda-runtime install -p -m 644 images/syslinux-vesa-splash.jpg %{buildroot}/usr/lib/anaconda-runtime # ovirt-logos +# ovirt-config-boot post-install hooks +%{__install} -d -m0755 %{buildroot}%{_sysconfdir}/ovirt-config-boot.d + # default ovirt-config-setup menu options %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/ovirt-config-setup.d %{__ln_s} ../..%{_sbindir}/ovirt-config-storage %{buildroot}%{_sysconfdir}/ovirt-config-setup.d/"00_Disk Partitioning" @@ -283,6 +286,7 @@ fi %config %{_sysconfdir}/cron.hourly/ovirt-kinit %config %{_sysconfdir}/logrotate.d/ovirt-logrotate.conf %config %{_sysconfdir}/cron.hourly/ovirt-logrotate +%{_sysconfdir}/ovirt-config-boot.d %{_sysconfdir}/ovirt-config-setup.d %files stateful diff --git a/scripts/ovirt-config-boot b/scripts/ovirt-config-boot index 30ad8df..34d696f 100755 --- a/scripts/ovirt-config-boot +++ b/scripts/ovirt-config-boot @@ -3,10 +3,7 @@ # ovirt-config-boot - configure local boot/root disk partitions # SYNOPSIS -# ovirt-config-boot boot_disk livecd_path bootparams reboot -# -# boot_disk - boot disk device e.g. /dev/sda -# default is $OVIRT_INIT +# ovirt-config-boot livecd_path bootparams reboot # # livecd_path - where livecd media is mounted, # parent of LiveOS and isolinux folders @@ -26,20 +23,32 @@ trap '__st=$?; stop_log; exit $__st' 0 trap 'exit $?' 1 2 13 15 ovirt_boot_setup() { - local disk=$1 - local live=$2 - local bootparams=$3 + local live=$1 + local bootparams=$2 + local disk + local partN=-1 log "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 )) + eval $(mount|awk '$3 == "/boot" { + print "disk=" substr($1,1,length($1)-1); + partN=substr($1,length($1),1); partN--; + print "partN=" partN; + }') rc=$? - if [ $rc -ne 0 -o $BOOT -lt 0 ]; then + if [ $rc -ne 0 -o $partN -lt 0 ]; then log "boot partition not available." + return 1 + fi + mkdir -p /liveos + # prepare Root partition update + lvrename HostVG RootBackup RootNew \ + && mount /dev/HostVG/RootNew /liveos + rc=$? + if [ $rc -ne 0 ]; then + log "root partition not available." return $rc fi - mount_liveos # install oVirt Node image for local boot if [ -e "$live/syslinux" ]; then syslinux=syslinux @@ -96,21 +105,24 @@ lvm vgchange -ay --ignorelockingfailure HostVG \ gzip -9 | cat $live/$syslinux/initrd0.img - > /boot/initrd0.img + version=$(rpm -q --qf '%{version}' ovirt-node) + release=$(rpm -q --qf '%{release}' ovirt-node) # reorder tty0 to allow both serial and phys console after installation - bootparams="console=tty0 $(echo $bootparams | sed s/console=tty0//g)" + bootparams="ro root=/dev/HostVG/Root roottypefs=ext3 console=tty0 \ + $(echo $bootparams | sed s/console=tty0//g)" cat > /boot/grub/grub.conf << EOF default=0 timeout=5 hiddenmenu -title oVirt Node - root (hd0,$BOOT) - kernel /vmlinuz0 ro root=/dev/HostVG/Root roottypefs=ext3 liveimg $bootparams +title oVirt Node (${version}-${release}) + root (hd0,$partN) + kernel /vmlinuz0 $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 <> /etc/fstab fi if [ "$ROOT_SIZE" -gt 0 ]; then - log "Creating root partition" + log "Creating root and root backup partitions" lvcreate --name Root --size ${ROOT_SIZE}M /dev/HostVG mke2fs -j /dev/HostVG/Root -L "ROOT" tune2fs -c 0 -i 0 /dev/HostVG/Root + lvcreate --name RootBackup --size ${ROOT_SIZE}M /dev/HostVG + mke2fs -j /dev/HostVG/RootBackup -L "ROOT2" + tune2fs -c 0 -i 0 /dev/HostVG/RootBackup fi if [ "$CONFIG_SIZE" -gt 0 ]; then log "Creating config partition" diff --git a/scripts/ovirt-early b/scripts/ovirt-early index 7971234..bf39f7f 100755 --- a/scripts/ovirt-early +++ b/scripts/ovirt-early @@ -366,7 +366,8 @@ start() { $BONDING_MODCONF_FILE if [ $local_boot = 1 ]; then # local disk installation for managed mode - ovirt-config-boot $init "" "$bootparams" + mount_live + ovirt-config-boot /live "$bootparams" fi fi fi diff --git a/scripts/ovirt-firstboot b/scripts/ovirt-firstboot index 593a55b..2d87768 100755 --- a/scripts/ovirt-firstboot +++ b/scripts/ovirt-firstboot @@ -47,7 +47,8 @@ start () ovirt-config-logging AUTO ovirt-config-collectd AUTO if [ "$OVIRT_LOCAL_BOOT" = 1 ]; then - ovirt-config-boot $OVIRT_INIT "" "$OVIRT_BOOTPARAMS" no + mount_live + ovirt-config-boot /live "$OVIRT_BOOTPARAMS" no disable_firstboot reboot fi diff --git a/scripts/ovirt-functions b/scripts/ovirt-functions index 98d5d53..f3ba4fc 100644 --- a/scripts/ovirt-functions +++ b/scripts/ovirt-functions @@ -208,16 +208,6 @@ mount_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() { @@ -442,3 +432,22 @@ add_if_not_exist() { is_numeric() { printf "$1" | grep -q -E '^[0-9]+$' } + +# reboot wrapper +# cleanup before reboot +reboot() { + # setup new Root if update is prepared + if [ -e /dev/HostVG/RootUpdate ]; then + lvrename HostVG Root RootBackup + lvrename HostVG RootUpdate Root + fi + # run post-install hooks + # e.g. to 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 + for hook in $(ls /etc/ovirt-config-boot.d/* 2>/dev/null); do + $hook + done + /sbin/reboot +} -- 1.6.0.6 From sseago at physical.priv.ovirt.org Tue Feb 3 05:46:52 2009 From: sseago at physical.priv.ovirt.org (Scott Seago) Date: Tue, 3 Feb 2009 05:46:52 +0000 Subject: [Ovirt-devel] [PATCH server] Fix for Bug #467729. In-Reply-To: <1233337873-20908-1-git-send-email-jguiditt@redhat.com> References: <1233337873-20908-1-git-send-email-jguiditt@redhat.com> Message-ID: <20090203054652.GA20146@physical.priv.ovirt.org> On Fri, Jan 30, 2009 at 12:51:13PM -0500, Jason Guiditta wrote: > Replaced svg bar graphs with css version. Removed > peak indicators, at least for now. > > Signed-off-by: Jason Guiditta > --- > src/app/helpers/graph_helper.rb | 24 ++++++-- > src/app/views/graph/_snapshot_graph.rhtml | 4 + > src/app/views/graph/snapshot_graph.rhtml | 97 ++++++++--------------------- > src/public/stylesheets/components.css | 56 ++++------------ > 4 files changed, 63 insertions(+), 118 deletions(-) > create mode 100644 src/app/views/graph/_snapshot_graph.rhtml ACK Works for me. Scott From dpierce at redhat.com Tue Feb 3 14:42:28 2009 From: dpierce at redhat.com (Darryl L. Pierce) Date: Tue, 3 Feb 2009 09:42:28 -0500 Subject: [Ovirt-devel] Installing a VM in oVirt 0.96 In-Reply-To: <4987557A.7000501@redhat.com> References: <20090129164641.491FB8E0371@hormel.redhat.com> <0AAE5AB84B013E45A7B61CB66943C17215B5DCF688@USEA-EXCH7.na.uis.unisys.com> <49825A00.70209@redhat.com> <0AAE5AB84B013E45A7B61CB66943C17215B5E29981@USEA-EXCH7.na.uis.unisys.com> <49834F20.8020507@redhat.com> <0AAE5AB84B013E45A7B61CB66943C17215B5F88E72@USEA-EXCH7.na.uis.unisys.com> <4987557A.7000501@redhat.com> Message-ID: <20090203144228.GE4165@mcpierce-laptop.rdu.redhat.com> On Mon, Feb 02, 2009 at 03:20:10PM -0500, Perry Myers wrote: > Can you give me the exact syntax for cobbler that you used to add the > image? The syntax for the nfs:// url part needs to follow some strict > conventions in order to work properly, but upstream cobbler doesn't do > any validation of that string so it won't tell you if you did it > incorrectly. There's code in upstream that seems to have been merged out by mistake. MPD is looking into that and fixing it upstream for us. -- 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 Tue Feb 3 15:19:19 2009 From: mmorsi at redhat.com (Mohammed Morsi) Date: Tue, 3 Feb 2009 10:19:19 -0500 Subject: [Ovirt-devel] [PATCH server] allow admin to setup iptables port forwarding on server for a vm's vnc port Message-ID: <1233674359-3801-1-git-send-email-mmorsi@redhat.com> --- src/app/controllers/vm_controller.rb | 29 ++++++- src/app/models/vm.rb | 26 ++++++ src/app/views/vm/_form.rhtml | 15 ++++ src/app/views/vm/show.rhtml | 4 + src/db/migrate/034_add_vm_vnc.rb | 30 +++++++ src/task-omatic/taskomatic.rb | 4 + src/task-omatic/vnc.rb | 140 ++++++++++++++++++++++++++++++++++ src/test/fixtures/vms.yml | 2 + src/test/unit/vm_test.rb | 16 ++++ 9 files changed, 263 insertions(+), 3 deletions(-) create mode 100644 src/db/migrate/034_add_vm_vnc.rb create mode 100644 src/task-omatic/vnc.rb diff --git a/src/app/controllers/vm_controller.rb b/src/app/controllers/vm_controller.rb index 56501fd..39150ae 100644 --- a/src/app/controllers/vm_controller.rb +++ b/src/app/controllers/vm_controller.rb @@ -62,6 +62,14 @@ class VmController < ApplicationController def create begin Vm.transaction do + if @vm.forward_vnc + if @vm.forward_vnc_port.to_i == 0 + @vm.forward_vnc_port = Vm.available_forward_vnc_port + end + else + @vm.forward_vnc_port = nil + end + @vm.save! _setup_vm_provision(params) @task = VmTask.new({ :user => @user, @@ -116,8 +124,20 @@ class VmController < ApplicationController new_storage_ids = new_storage_ids.sort.collect {|x| x.to_i } needs_restart = true unless current_storage_ids == new_storage_ids end - params[:vm][:needs_restart] = 1 if needs_restart - @vm.update_attributes!(params[:vm]) + + Vm.transaction do + params[:vm][:forward_vnc] = params[:forward_vnc] + if params[:forward_vnc] + if params[:vm][:forward_vnc_port].to_i == 0 + params[:vm][:forward_vnc_port] = Vm.available_forward_vnc_port + end + else + params[:vm][:forward_vnc_port] = nil + end + + params[:vm][:needs_restart] = 1 if needs_restart + @vm.update_attributes!(params[:vm]) + end _setup_vm_provision(params) if (params[:start_now] and @vm.get_action_list.include?(VmTask::ACTION_START_VM) ) @@ -325,7 +345,8 @@ class VmController < ApplicationController newargs = { :vm_resource_pool_id => params[:vm_resource_pool_id], :vnic_mac_addr => mac.collect {|x| "%02x" % x}.join(":"), - :uuid => uuid + :uuid => uuid, + :forward_vnc_port => 0 } @vm = Vm.new( newargs ) unless params[:vm_resource_pool_id] @@ -345,6 +366,7 @@ class VmController < ApplicationController vm_resource_pool.create_with_parent(hardware_pool) params[:vm][:vm_resource_pool_id] = vm_resource_pool.id end + params[:vm][:forward_vnc] = params[:forward_vnc] @vm = Vm.new(params[:vm]) @perm_obj = @vm.vm_resource_pool @current_pool_id=@perm_obj.id @@ -356,6 +378,7 @@ class VmController < ApplicationController end def pre_edit @vm = Vm.find(params[:id]) + @vm.forward_vnc_port = 0 unless @vm.forward_vnc @perm_obj = @vm.vm_resource_pool @current_pool_id=@perm_obj.id _setup_provisioning_options diff --git a/src/app/models/vm.rb b/src/app/models/vm.rb index bf99e2d..1cfcc72 100644 --- a/src/app/models/vm.rb +++ b/src/app/models/vm.rb @@ -40,6 +40,17 @@ class Vm < ActiveRecord::Base validates_format_of :uuid, :with => %r([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}) + FORWARD_VNC_PORT_START = 5900 + + validates_numericality_of :forward_vnc_port, + :message => 'must be >= ' + FORWARD_VNC_PORT_START.to_s, + :greater_than_or_equal_to => FORWARD_VNC_PORT_START, + :if => Proc.new { |vm| vm.forward_vnc } + + validates_uniqueness_of :forward_vnc_port, + :message => "is already in use", + :if => Proc.new { |vm| vm.forward_vnc } + validates_numericality_of :needs_restart, :greater_than_or_equal_to => 0, :less_than_or_equal_to => 1, @@ -335,6 +346,21 @@ class Vm < ActiveRecord::Base super end + # find the first available vnc port + def self.available_forward_vnc_port + # FIXME need a way to reserve values returned + # by this until table is saved + + i = FORWARD_VNC_PORT_START + Vm.find(:all, + :conditions => "forward_vnc_port is not NULL", + :order => 'forward_vnc_port ASC' ).collect{ |vm| + return i if vm.forward_vnc_port > i + i = i + 1 + } + return i + end + protected def validate resources = vm_resource_pool.max_resources_for_vm(self) diff --git a/src/app/views/vm/_form.rhtml b/src/app/views/vm/_form.rhtml index 7cbe16d..f1c0239 100644 --- a/src/app/views/vm/_form.rhtml +++ b/src/app/views/vm/_form.rhtml @@ -51,6 +51,21 @@
+
+ <%= check_box_tag_with_label "Forward vm's vnc port locally", "forward_vnc", 1, @vm.forward_vnc %> + (set to 0 to autoassign port) +
+
+ <%= text_field_with_label "", "vm", "forward_vnc_port", { :style=>"width: 80px;", :size => 7, :disabled => ! @vm.forward_vnc } %> +
+
+
+ + <%= check_box_tag_with_label "Start VM Now? (pending current resource availability)", "start_now", nil if create or @vm.state == Vm::STATE_STOPPED %> <%= check_box_tag_with_label "Restart VM Now? (pending current resource availability)", "restart_now", nil if @vm.state == Vm::STATE_RUNNING %> diff --git a/src/app/views/vm/show.rhtml b/src/app/views/vm/show.rhtml index f361131..add29b4 100644 --- a/src/app/views/vm/show.rhtml +++ b/src/app/views/vm/show.rhtml @@ -88,6 +88,7 @@
Uuid:
+ <%= @vm.forward_vnc ? "VNC uri:
" : "" %> Num vcpus allocated:
Num vcpus used:
Memory allocated:
@@ -100,6 +101,9 @@
<%=h @vm.uuid %>
+ <%= url = request.url + url = request.url[0..(url.index('/', 8) - 1)] + ":" + @vm.forward_vnc_port.to_s + @vm.forward_vnc ? (url + "
") : "" %> <%=h @vm.num_vcpus_allocated %>
<%=h @vm.num_vcpus_used %>
<%=h @vm.memory_allocated_in_mb %> MB
diff --git a/src/db/migrate/034_add_vm_vnc.rb b/src/db/migrate/034_add_vm_vnc.rb new file mode 100644 index 0000000..f23e24d --- /dev/null +++ b/src/db/migrate/034_add_vm_vnc.rb @@ -0,0 +1,30 @@ +# Copyright (C) 2008 Red Hat, Inc. +# Written by Mohammed Morsi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +class AddVmVnc < ActiveRecord::Migration + def self.up + add_column :vms, :forward_vnc, :bool, :default => false + add_column :vms, :forward_vnc_port, :int, :default => 0, :unique => true + end + + def self.down + drop_column :vms, :forward_vnc + drop_column :vms, :forward_vnc_port + end +end + diff --git a/src/task-omatic/taskomatic.rb b/src/task-omatic/taskomatic.rb index 0570246..380be92 100755 --- a/src/task-omatic/taskomatic.rb +++ b/src/task-omatic/taskomatic.rb @@ -32,6 +32,7 @@ include Daemonize require 'task_vm' require 'task_storage' +require 'vnc' class TaskOmatic @@ -232,6 +233,8 @@ class TaskOmatic raise "Error destroying VM: #{result.text}" unless result.status == 0 end + VmVnc.close(vm) + # undefine can fail, for instance, if we live migrated from A -> B, and # then we are shutting down the VM on B (because it only has "transient" # XML). Therefore, just ignore undefine errors so we do the rest @@ -303,6 +306,7 @@ class TaskOmatic # of places so you'll see a lot of .reloads. db_vm.reload set_vm_vnc_port(db_vm, result.description) unless result.status != 0 + VmVnc.forward(db_vm) # This information is not available via the libvirt interface. db_vm.memory_used = db_vm.memory_allocated diff --git a/src/task-omatic/vnc.rb b/src/task-omatic/vnc.rb new file mode 100644 index 0000000..0876f36 --- /dev/null +++ b/src/task-omatic/vnc.rb @@ -0,0 +1,140 @@ +# Copyright (C) 2008 Red Hat, Inc. +# Written by Mohammed Morsi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +# provides static 'forward' and 'close' methods to forward a specified vm's vnc connections +class VmVnc + + private + + # TODO no ruby/libiptc wrapper exists, when + # it does replace iptables command w/ calls to it + IPTABLES_CMD='/sbin/iptables ' + + VNC_DEBUG = false + + # FIXME can this be retreived in any way + # since machine will have both external + # and internal network interface + LOCAL_IP = '192.168.50.2' + + def self.debug(msg) + puts "\n" + msg + "\n" if VNC_DEBUG + end + + def self.find_host_ip(hostname) + # FIXME + addrinfo = Socket::getaddrinfo(hostname, nil) + unless addrinfo.size > 0 + raise "Could not retreive address for " + hostname + end + result = addrinfo[0][3] # return ip address of first entry + debug( "vm host hostname resolved to " + result.to_s ) + return result + end + + def self.port_open?(port) + cmd=IPTABLES_CMD + ' -t nat -nL ' + debug("vncPortOpen? iptables command: " + cmd) + + `#{cmd}`.each_line do |l| + return true if l =~ /.*#{port}.*/ + end + return false + end + + def self.get_forward_rules(vm) + ip = find_host_ip(vm.host.hostname) + return " -d " + ip + " -p tcp --dport " + vm.vnc_port.to_s + " -j ACCEPT", + " -s " + ip + " -p tcp --sport " + vm.vnc_port.to_s + " -j ACCEPT" + end + + def self.get_nat_rules(vm) + ip = find_host_ip(vm.host.hostname) + + return " -p tcp --dport " + vm.forward_vnc_port.to_s + " -j DNAT --to " + ip + ":" + vm.vnc_port.to_s, + " -d " + ip + " -p tcp --dport " + vm.vnc_port.to_s + " -j SNAT --to " + LOCAL_IP + end + + def self.run_command(cmd) + debug("Running command " + cmd) + status = system(cmd) + raise 'Command terminated with error code ' + $?.to_s unless status + end + + public + + def self.forward(vm) + return unless vm.forward_vnc + unless vm.forward_vnc_port > 0 + raise "Must specify valid port to forward " + vm.forward_vnc_port.to_s + end + + if port_open?(vm.forward_vnc_port) + raise "Port already open " + vm.forward_vnc_port.to_s + end + + forward_rule1, forward_rule2 = get_forward_rules(vm) + forward_rule1 = IPTABLES_CMD + " -A FORWARD " + forward_rule1 + forward_rule2 = IPTABLES_CMD + " -A FORWARD " + forward_rule2 + + prerouting_rule, postrouting_rule = get_nat_rules(vm) + prerouting_rule = IPTABLES_CMD + " -t nat -A PREROUTING " + prerouting_rule + postrouting_rule = IPTABLES_CMD + " -t nat -A POSTROUTING " + postrouting_rule + + debug(" open\n forward rule 1: " + forward_rule1 + + "\n forward_rule 2: " + forward_rule2 + + "\n prerouting rule: " + prerouting_rule + + "\n postrouting rule: " + postrouting_rule) + + File::open("/proc/sys/net/ipv4/ip_forward", "w") { |f| f.puts "1" } + run_command(forward_rule1) + run_command(forward_rule2) + run_command(prerouting_rule) + run_command(postrouting_rule) + end + + def self.close(vm) + # FIXME forward_vnc may have been changed while the vm is running + return unless vm.forward_vnc + unless vm.forward_vnc_port > 0 + raise "Must specify valid port to forward " + vm.forward_vnc_port.to_s + end + + unless port_open?(vm.forward_vnc_port) + raise "Port not open " + vm.forward_vnc_port.to_s + end + + forward_rule1, forward_rule2 = get_forward_rules(vm) + forward_rule1 = IPTABLES_CMD + " -D FORWARD " + forward_rule1 + forward_rule2 = IPTABLES_CMD + " -D FORWARD " + forward_rule2 + + prerouting_rule, postrouting_rule = get_nat_rules(vm) + prerouting_rule = IPTABLES_CMD + " -t nat -D PREROUTING " + prerouting_rule + postrouting_rule = IPTABLES_CMD + " -t nat -D POSTROUTING " + postrouting_rule + + debug(" close\n forward rule 1: " + forward_rule1 + + "\n forward_rule 2: " + forward_rule2 + + "\n prerouting rule: " + prerouting_rule + + "\n postrouting rule: " + postrouting_rule) + + run_command(forward_rule1) + run_command(forward_rule2) + run_command(prerouting_rule) + run_command(postrouting_rule) + end +end diff --git a/src/test/fixtures/vms.yml b/src/test/fixtures/vms.yml index ca0d63f..366f192 100644 --- a/src/test/fixtures/vms.yml +++ b/src/test/fixtures/vms.yml @@ -11,6 +11,8 @@ production_httpd_vm: boot_device: hd host: prod_corp_com vm_resource_pool: corp_com_production_vmpool + forward_vnc: true + forward_vnc_port: 1234 production_mysqld_vm: uuid: 89e62d32-04d9-4351-b573-b1a253397296 description: production mysqld appliance diff --git a/src/test/unit/vm_test.rb b/src/test/unit/vm_test.rb index cba3188..b868dfa 100644 --- a/src/test/unit/vm_test.rb +++ b/src/test/unit/vm_test.rb @@ -95,6 +95,22 @@ class VmTest < Test::Unit::TestCase flunk 'Vm must specify valid state' if @vm.valid? end + # ensure duplicate forward_vnc_ports cannot exist + def test_invalid_without_unique_forward_vnc_port + vm = vms(:production_mysqld_vm) + vm.forward_vnc = true + vm.forward_vnc_port = 1234 # duplicate + assert !vm.valid?, "forward vnc port must be unique" + end + + # ensure bad forward_vnc_ports cannot exist + def test_invalid_without_bad_forward_vnc_port + vm = vms(:production_mysqld_vm) + vm.forward_vnc = true + vm.forward_vnc_port = 1 # too small + assert !vm.valid?, "forward vnc port must be >= 5900" + end + # Ensures that, if the VM does not contain the Cobbler prefix, that it # does not claim to be a Cobbler VM. # -- 1.6.0.6 From mmorsi at redhat.com Tue Feb 3 15:57:06 2009 From: mmorsi at redhat.com (Mohammed Morsi) Date: Tue, 03 Feb 2009 10:57:06 -0500 Subject: [Ovirt-devel] Re: [PATCH server] allow admin to setup iptables port forwarding on server for a vm's vnc port In-Reply-To: <1233615630.20462.16.camel@localhost.localdomain> References: <1233191768-9399-1-git-send-email-mmorsi@redhat.com> <1233359683.15906.372.camel@localhost.localdomain> <4987785B.80709@redhat.com> <1233615630.20462.16.camel@localhost.localdomain> Message-ID: <49886952.9080708@redhat.com> David Lutterkort wrote: > Kicking out that error when the user wants 'autoassign' is pretty > confusing. > > As long as you take the lock inside a transaction, it will be released > at the end of the transaction, i.e. something like this _should_ do the > right thing > > Vm.transaction do > # Whatever Rails magic is needed to do 'LOCK TABLE vms EXCLUSIVE;' > ... determine vnc port ... > ... save VM ... > end > > David > > I guess I misread this when I just implemented it and sent out the patch, I added the transaction bits where necessary but couldn't find a suitable way to lock an entire table via rails (am I mistaken Jay or Scott?), though particular rows can be locked quite easily upon retrieval. I could add an array class variable to the VM class, concurrently protected via mutex, to store ports returned by available_forward_vnc_port, but this seems to me to be an iffy solution at best. I figure the best solution given what we have would be to determine if the error raised by the model is due to the forward_vnc_port unique constraint failing and then loop around to generate another port (doing as many times as necessary). It will make the controller code a bit uglier, but it should work so long as I can determine the particular fields and validations which cause the failure (from what I've read I should be able to). I'll get started on this bit, unless there are better alternate suggestions. -Mo From berrange at redhat.com Tue Feb 3 16:16:10 2009 From: berrange at redhat.com (Daniel P. Berrange) Date: Tue, 3 Feb 2009 16:16:10 +0000 Subject: [Ovirt-devel] Re: [PATCH server] allow admin to setup iptables port forwarding on server for a vm's vnc port In-Reply-To: <1233615630.20462.16.camel@localhost.localdomain> References: <1233191768-9399-1-git-send-email-mmorsi@redhat.com> <1233359683.15906.372.camel@localhost.localdomain> <4987785B.80709@redhat.com> <1233615630.20462.16.camel@localhost.localdomain> Message-ID: <20090203161610.GT15613@redhat.com> On Mon, Feb 02, 2009 at 11:00:30PM +0000, David Lutterkort wrote: > On Mon, 2009-02-02 at 17:48 -0500, Mohammed Morsi wrote: > > David Lutterkort wrote: > > > On Wed, 2009-01-28 at 20:16 -0500, Mohammed Morsi wrote: > > > > > > To address the race condition, the simplest solution is to take an > > > exclusive table lock on the vms table (before listing the assigned vnc > > > ports !) and hold that until the vm is saved in the DB, i.e. the end of > > > the current transaction. > > > > > > > > This is not done as I'm a little concerned about locking the table (what > > if the user doesn't submit the form and walks away, will it stay > > locked?). > > I must have misunderstood the logic: I thought the port-assignment logic > was happening as part of saving the VM, not when the form is presented > to the user. I rather think both options are wrong. Automatic port assignment should be just done when starting a VM, so you don't have to reserve a tonne of ports for inactive VMs. > > I changed the additions to the server such that the > > autogenerated port isn't displayed in the form, eg the user is prompted > > to set the port or leave it at '0' after which the server will > > autogenerate it immediately before saving. > > Yes, that's the flow that makes sense. Does the user really need the ability to choose a specific port ? If there is a non-trivial number of VMs, any port they might wish to reserve for their own VM is probably already taken by another. With the ovirt-viewer client app, they should never need to know what port is used for a VM, since ovirt-viewer will automatically lookup the port for them. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| From mmorsi at redhat.com Tue Feb 3 16:42:12 2009 From: mmorsi at redhat.com (Mohammed Morsi) Date: Tue, 03 Feb 2009 11:42:12 -0500 Subject: [Ovirt-devel] Re: [PATCH server] allow admin to setup iptables port forwarding on server for a vm's vnc port In-Reply-To: <20090203161610.GT15613@redhat.com> References: <1233191768-9399-1-git-send-email-mmorsi@redhat.com> <1233359683.15906.372.camel@localhost.localdomain> <4987785B.80709@redhat.com> <1233615630.20462.16.camel@localhost.localdomain> <20090203161610.GT15613@redhat.com> Message-ID: <498873E4.6020504@redhat.com> Daniel P. Berrange wrote: > On Mon, Feb 02, 2009 at 11:00:30PM +0000, David Lutterkort wrote: > >> On Mon, 2009-02-02 at 17:48 -0500, Mohammed Morsi wrote: >> >>> David Lutterkort wrote: >>> >>>> On Wed, 2009-01-28 at 20:16 -0500, Mohammed Morsi wrote: >>>> >>>> To address the race condition, the simplest solution is to take an >>>> exclusive table lock on the vms table (before listing the assigned vnc >>>> ports !) and hold that until the vm is saved in the DB, i.e. the end of >>>> the current transaction. >>>> >>>> >>>> >>> This is not done as I'm a little concerned about locking the table (what >>> if the user doesn't submit the form and walks away, will it stay >>> locked?). >>> >> I must have misunderstood the logic: I thought the port-assignment logic >> was happening as part of saving the VM, not when the form is presented >> to the user. >> > > I rather think both options are wrong. Automatic port assignment should > be just done when starting a VM, so you don't have to reserve a tonne > of ports for inactive VMs. > > This makes sense, save for the manual port assignment scenario as discussed below. I could add another flag (or change the boolean forward_vnc field to an int) in the db and vm form to store whether or not to defer autoassignment to vm startup, in order to handle both scenarios. >>> I changed the additions to the server such that the >>> autogenerated port isn't displayed in the form, eg the user is prompted >>> to set the port or leave it at '0' after which the server will >>> autogenerate it immediately before saving. >>> >> Yes, that's the flow that makes sense. >> > > Does the user really need the ability to choose a specific port ? If there > is a non-trivial number of VMs, any port they might wish to reserve for > their own VM is probably already taken by another. With the ovirt-viewer > client app, they should never need to know what port is used for a VM, > since ovirt-viewer will automatically lookup the port for them. > > Daniel > I would say its just another use case, eg since the default is to autoassign the port, is there really any drawback to allowing an administrator to manually set it? I can see the autoassignment scenario being useful in large deployments as you mentioned, but for smaller ones, I think a way to allow admin defined / consistent port assignments would be useful. If an administrator chooses to override the autoassignment, and assign a port already in use, the conflict will be due to a problem in his own assignment schema. Also while I agree ovirt-viewer will take care of the port internally, clients may wish to use their own vnc viewer (granted the client accessable vnc uri is displayed in the vm's details pane). Perhaps a better solution would be to add a config option to one of the yml's (or even to the db on a pool by pool or other basis) to allow the server administrator to allow or disallow manual vnc port assignment. I can do whatever the requirements dictate, as the original reqs didn't specify this either way, (removing the field from the form is pretty straightforward and would probably make the controller logic a bit simpler) , but any way will push this patch's review / ack / commit a little while back. -Mo From pronix.service at gmail.com Tue Feb 3 16:45:01 2009 From: pronix.service at gmail.com (pronix.service at gmail.com) Date: Tue, 3 Feb 2009 19:45:01 +0300 Subject: [Ovirt-devel] [PATCH] Add virtual machine restart if host crashed. Use fencing by ssh and id_rsa key. Message-ID: <1233679501-20816-1-git-send-email-pronix.service@gmail.com> From: root --- src/app/controllers/vm_controller.rb | 13 +++- src/app/views/vm/show.rhtml | 16 ++++ src/db-omatic/db_omatic.rb | 126 ++++++++++++++++++++++++++++++--- src/db/migrate/006_create_vms.rb | 1 + 4 files changed, 143 insertions(+), 13 deletions(-) diff --git a/src/app/controllers/vm_controller.rb b/src/app/controllers/vm_controller.rb index 56501fd..0f43680 100644 --- a/src/app/controllers/vm_controller.rb +++ b/src/app/controllers/vm_controller.rb @@ -20,11 +20,22 @@ require 'socket' class VmController < ApplicationController # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html) - verify :method => :post, :only => [ :destroy, :create, :update ], + verify :method => :post, :only => [ :destroy, :create, :update , :change_ha_vm], :redirect_to => { :controller => 'dashboard' } before_filter :pre_vm_action, :only => [:vm_action, :cancel_queued_tasks, :console] + def change_ha_vm + vm = Vm.find_by_id(params[:id]) + if vm.ha + then vm.ha = false + else vm.ha = true + end + vm.save! + alert = "vm was change ha successfully " + render :json => { :object => "vm", :success => true, :alert => alert } + end + def index roles = "('" + Permission::roles_for_privilege(Permission::PRIV_VIEW).join("', '") + diff --git a/src/app/views/vm/show.rhtml b/src/app/views/vm/show.rhtml index f361131..b0479a6 100644 --- a/src/app/views/vm/show.rhtml +++ b/src/app/views/vm/show.rhtml @@ -29,6 +29,9 @@ <% end -%> <% end %> + + <%= image_tag "icon_x.png" %> <% if @vm.ha %> disable_ha (cur. enabled)<% else %> enable_ha (cur. disabled) <% end %> + <%= image_tag "icon_x.png" %> Cancel queued tasks @@ -40,6 +43,19 @@ <%= confirmation_dialog("confirm_cancel", "Are you sure?", "cancel_queued_tasks()") %> <%= confirmation_dialog("confirm_delete", "Are you sure?", "delete_vm()") %> + <%= check_box_tag_with_label "Start VM Now? (pending current resource availability)", "start_now", nil if create or @vm.state == Vm::STATE_STOPPED %> <%= check_box_tag_with_label "Restart VM Now? (pending current resource availability)", "restart_now", nil if @vm.state == Vm::STATE_RUNNING %> diff --git a/src/app/views/vm/show.rhtml b/src/app/views/vm/show.rhtml index f361131..add29b4 100644 --- a/src/app/views/vm/show.rhtml +++ b/src/app/views/vm/show.rhtml @@ -88,6 +88,7 @@
Uuid:
+ <%= @vm.forward_vnc ? "VNC uri:
" : "" %> Num vcpus allocated:
Num vcpus used:
Memory allocated:
@@ -100,6 +101,9 @@
<%=h @vm.uuid %>
+ <%= url = request.url + url = request.url[0..(url.index('/', 8) - 1)] + ":" + @vm.forward_vnc_port.to_s + @vm.forward_vnc ? (url + "
") : "" %> <%=h @vm.num_vcpus_allocated %>
<%=h @vm.num_vcpus_used %>
<%=h @vm.memory_allocated_in_mb %> MB
diff --git a/src/db/migrate/034_add_vm_vnc.rb b/src/db/migrate/034_add_vm_vnc.rb new file mode 100644 index 0000000..f23e24d --- /dev/null +++ b/src/db/migrate/034_add_vm_vnc.rb @@ -0,0 +1,30 @@ +# Copyright (C) 2008 Red Hat, Inc. +# Written by Mohammed Morsi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +class AddVmVnc < ActiveRecord::Migration + def self.up + add_column :vms, :forward_vnc, :bool, :default => false + add_column :vms, :forward_vnc_port, :int, :default => 0, :unique => true + end + + def self.down + drop_column :vms, :forward_vnc + drop_column :vms, :forward_vnc_port + end +end + diff --git a/src/task-omatic/taskomatic.rb b/src/task-omatic/taskomatic.rb index 0570246..380be92 100755 --- a/src/task-omatic/taskomatic.rb +++ b/src/task-omatic/taskomatic.rb @@ -32,6 +32,7 @@ include Daemonize require 'task_vm' require 'task_storage' +require 'vnc' class TaskOmatic @@ -232,6 +233,8 @@ class TaskOmatic raise "Error destroying VM: #{result.text}" unless result.status == 0 end + VmVnc.close(vm) + # undefine can fail, for instance, if we live migrated from A -> B, and # then we are shutting down the VM on B (because it only has "transient" # XML). Therefore, just ignore undefine errors so we do the rest @@ -303,6 +306,7 @@ class TaskOmatic # of places so you'll see a lot of .reloads. db_vm.reload set_vm_vnc_port(db_vm, result.description) unless result.status != 0 + VmVnc.forward(db_vm) # This information is not available via the libvirt interface. db_vm.memory_used = db_vm.memory_allocated diff --git a/src/task-omatic/vnc.rb b/src/task-omatic/vnc.rb new file mode 100644 index 0000000..0876f36 --- /dev/null +++ b/src/task-omatic/vnc.rb @@ -0,0 +1,140 @@ +# Copyright (C) 2008 Red Hat, Inc. +# Written by Mohammed Morsi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +# provides static 'forward' and 'close' methods to forward a specified vm's vnc connections +class VmVnc + + private + + # TODO no ruby/libiptc wrapper exists, when + # it does replace iptables command w/ calls to it + IPTABLES_CMD='/sbin/iptables ' + + VNC_DEBUG = false + + # FIXME can this be retreived in any way + # since machine will have both external + # and internal network interface + LOCAL_IP = '192.168.50.2' + + def self.debug(msg) + puts "\n" + msg + "\n" if VNC_DEBUG + end + + def self.find_host_ip(hostname) + # FIXME + addrinfo = Socket::getaddrinfo(hostname, nil) + unless addrinfo.size > 0 + raise "Could not retreive address for " + hostname + end + result = addrinfo[0][3] # return ip address of first entry + debug( "vm host hostname resolved to " + result.to_s ) + return result + end + + def self.port_open?(port) + cmd=IPTABLES_CMD + ' -t nat -nL ' + debug("vncPortOpen? iptables command: " + cmd) + + `#{cmd}`.each_line do |l| + return true if l =~ /.*#{port}.*/ + end + return false + end + + def self.get_forward_rules(vm) + ip = find_host_ip(vm.host.hostname) + return " -d " + ip + " -p tcp --dport " + vm.vnc_port.to_s + " -j ACCEPT", + " -s " + ip + " -p tcp --sport " + vm.vnc_port.to_s + " -j ACCEPT" + end + + def self.get_nat_rules(vm) + ip = find_host_ip(vm.host.hostname) + + return " -p tcp --dport " + vm.forward_vnc_port.to_s + " -j DNAT --to " + ip + ":" + vm.vnc_port.to_s, + " -d " + ip + " -p tcp --dport " + vm.vnc_port.to_s + " -j SNAT --to " + LOCAL_IP + end + + def self.run_command(cmd) + debug("Running command " + cmd) + status = system(cmd) + raise 'Command terminated with error code ' + $?.to_s unless status + end + + public + + def self.forward(vm) + return unless vm.forward_vnc + unless vm.forward_vnc_port > 0 + raise "Must specify valid port to forward " + vm.forward_vnc_port.to_s + end + + if port_open?(vm.forward_vnc_port) + raise "Port already open " + vm.forward_vnc_port.to_s + end + + forward_rule1, forward_rule2 = get_forward_rules(vm) + forward_rule1 = IPTABLES_CMD + " -A FORWARD " + forward_rule1 + forward_rule2 = IPTABLES_CMD + " -A FORWARD " + forward_rule2 + + prerouting_rule, postrouting_rule = get_nat_rules(vm) + prerouting_rule = IPTABLES_CMD + " -t nat -A PREROUTING " + prerouting_rule + postrouting_rule = IPTABLES_CMD + " -t nat -A POSTROUTING " + postrouting_rule + + debug(" open\n forward rule 1: " + forward_rule1 + + "\n forward_rule 2: " + forward_rule2 + + "\n prerouting rule: " + prerouting_rule + + "\n postrouting rule: " + postrouting_rule) + + File::open("/proc/sys/net/ipv4/ip_forward", "w") { |f| f.puts "1" } + run_command(forward_rule1) + run_command(forward_rule2) + run_command(prerouting_rule) + run_command(postrouting_rule) + end + + def self.close(vm) + # FIXME forward_vnc may have been changed while the vm is running + return unless vm.forward_vnc + unless vm.forward_vnc_port > 0 + raise "Must specify valid port to forward " + vm.forward_vnc_port.to_s + end + + unless port_open?(vm.forward_vnc_port) + raise "Port not open " + vm.forward_vnc_port.to_s + end + + forward_rule1, forward_rule2 = get_forward_rules(vm) + forward_rule1 = IPTABLES_CMD + " -D FORWARD " + forward_rule1 + forward_rule2 = IPTABLES_CMD + " -D FORWARD " + forward_rule2 + + prerouting_rule, postrouting_rule = get_nat_rules(vm) + prerouting_rule = IPTABLES_CMD + " -t nat -D PREROUTING " + prerouting_rule + postrouting_rule = IPTABLES_CMD + " -t nat -D POSTROUTING " + postrouting_rule + + debug(" close\n forward rule 1: " + forward_rule1 + + "\n forward_rule 2: " + forward_rule2 + + "\n prerouting rule: " + prerouting_rule + + "\n postrouting rule: " + postrouting_rule) + + run_command(forward_rule1) + run_command(forward_rule2) + run_command(prerouting_rule) + run_command(postrouting_rule) + end +end diff --git a/src/test/fixtures/vms.yml b/src/test/fixtures/vms.yml index ca0d63f..366f192 100644 --- a/src/test/fixtures/vms.yml +++ b/src/test/fixtures/vms.yml @@ -11,6 +11,8 @@ production_httpd_vm: boot_device: hd host: prod_corp_com vm_resource_pool: corp_com_production_vmpool + forward_vnc: true + forward_vnc_port: 1234 production_mysqld_vm: uuid: 89e62d32-04d9-4351-b573-b1a253397296 description: production mysqld appliance diff --git a/src/test/unit/vm_test.rb b/src/test/unit/vm_test.rb index cba3188..b868dfa 100644 --- a/src/test/unit/vm_test.rb +++ b/src/test/unit/vm_test.rb @@ -95,6 +95,22 @@ class VmTest < Test::Unit::TestCase flunk 'Vm must specify valid state' if @vm.valid? end + # ensure duplicate forward_vnc_ports cannot exist + def test_invalid_without_unique_forward_vnc_port + vm = vms(:production_mysqld_vm) + vm.forward_vnc = true + vm.forward_vnc_port = 1234 # duplicate + assert !vm.valid?, "forward vnc port must be unique" + end + + # ensure bad forward_vnc_ports cannot exist + def test_invalid_without_bad_forward_vnc_port + vm = vms(:production_mysqld_vm) + vm.forward_vnc = true + vm.forward_vnc_port = 1 # too small + assert !vm.valid?, "forward vnc port must be >= 5900" + end + # Ensures that, if the VM does not contain the Cobbler prefix, that it # does not claim to be a Cobbler VM. # -- 1.6.0.6 From mmorsi at redhat.com Tue Feb 3 17:06:18 2009 From: mmorsi at redhat.com (Mohammed Morsi) Date: Tue, 03 Feb 2009 12:06:18 -0500 Subject: [Ovirt-devel] Re: [PATCH server] allow admin to setup iptables port forwarding on server for a vm's vnc port In-Reply-To: <49886952.9080708@redhat.com> References: <1233191768-9399-1-git-send-email-mmorsi@redhat.com> <1233359683.15906.372.camel@localhost.localdomain> <4987785B.80709@redhat.com> <1233615630.20462.16.camel@localhost.localdomain> <49886952.9080708@redhat.com> Message-ID: <4988798A.4010103@redhat.com> > I figure the best solution given what we have would be to determine if > the error raised by the model is due to the forward_vnc_port unique > constraint failing and then loop around to generate another port (doing > as many times as necessary). It will make the controller code a bit > uglier, but it should work so long as I can determine the particular > fields and validations which cause the failure (from what I've read I > should be able to). I'll get started on this bit, unless there are > better alternate suggestions. > > -Mo > > > Just sent the patch with this included. -Mo From sseago at physical.priv.ovirt.org Tue Feb 3 15:35:24 2009 From: sseago at physical.priv.ovirt.org (Scott Seago) Date: Tue, 3 Feb 2009 15:35:24 +0000 Subject: [Ovirt-devel] [PATCH server 4/8] API: include storage_volumes; indicate type for individual pools In-Reply-To: <1233606937-18469-5-git-send-email-lutter@redhat.com> References: <1233004325-18032-1-git-send-email-lutter@redhat.com> <1233606937-18469-5-git-send-email-lutter@redhat.com> Message-ID: <20090203153524.GA3312@physical.priv.ovirt.org> On Mon, Feb 02, 2009 at 12:35:33PM -0800, David Lutterkort wrote: > --- > src/app/controllers/storage_controller.rb | 9 +++++++-- > 1 files changed, 7 insertions(+), 2 deletions(-) > > diff --git a/src/app/controllers/storage_controller.rb b/src/app/controllers/storage_controller.rb > index 160d22e..ee9f116 100644 > --- a/src/app/controllers/storage_controller.rb > +++ b/src/app/controllers/storage_controller.rb > @@ -32,7 +32,7 @@ class StorageController < ApplicationController > list > respond_to do |format| > format.html { render :action => 'list' } > - format.xml { render :xml => @storage_pools.to_xml } > + format.xml { render :xml => @storage_pools.to_xml( :include => :storage_volumes) } > end > end One thing this isn't handling is the nesting of LVM volumes. Instead of the lvm volumes showing up as children of the source volume they show up as separate entries. On the WUI side when we generate the storage tree we filter out top level LvmStorageVolumes and include the LVM volumes as children of the containing iSCSI volume. At the active_record level this would mean following the lvm_storage_pool association on StorageVolume and then getting the lvm pool's storage volumes. In the UI tree we don't show the LVM pool at all -- a storage volume will belong to at most one LVM pool, and we're currently not allowing multiple source volumes in a volume group, so for the end user all that matters is that a given storage volume (iSCSI lun, etc) may contain several LVM volumes. Since the API results tend to be a lot closer to the underlying data model, perhaps you want to include the lvm pool in the results. In which case we'd need storage_volumes to include :lvm_storage_pool, and that would, in turn, include :storage_volumes. In addition to this we would filter the top level find all query to only find storage pools that aren't LVM pools. Scott > > @@ -80,7 +80,12 @@ class StorageController < ApplicationController > else > respond_to do |format| > format.html { render :layout => 'selection' } > - format.xml { render :xml => @storage_pool.to_xml } > + format.xml { > + xml_txt = @storage_pool.to_xml(:include => :storage_volumes) do |xml| > + xml.type @storage_pool.class.name > + end > + render :xml => xml_txt > + } > end > end > end > -- > 1.6.0.6 > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel From sseago at physical.priv.ovirt.org Tue Feb 3 16:15:29 2009 From: sseago at physical.priv.ovirt.org (Scott Seago) Date: Tue, 3 Feb 2009 16:15:29 +0000 Subject: [Ovirt-devel] [PATCH server 5/8] Factor StorageVolume functionality out of StorageController In-Reply-To: <1233606937-18469-6-git-send-email-lutter@redhat.com> References: <1233004325-18032-1-git-send-email-lutter@redhat.com> <1233606937-18469-6-git-send-email-lutter@redhat.com> Message-ID: <20090203161529.GB3312@physical.priv.ovirt.org> On Mon, Feb 02, 2009 at 12:35:34PM -0800, David Lutterkort wrote: > Storage volumes can now be accessed through their own controller. This is > needed to expose them in the API. > --- > diff --git a/src/app/controllers/storage_volume_controller.rb b/src/app/controllers/storage_volume_controller.rb > new file mode 100644 > index 0000000..ba486d2 > --- /dev/null > +++ b/src/app/controllers/storage_volume_controller.rb > @@ -0,0 +1,228 @@ > +# > +# Copyright (C) 2009 Red Hat, Inc. > +# Written by Scott Seago > +# > +# This program is free software; you can redistribute it and/or modify > +# it under the terms of the GNU General Public License as published by > +# the Free Software Foundation; version 2 of the License. > +# > +# This program is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +# GNU General Public License for more details. > +# > +# You should have received a copy of the GNU General Public License > +# along with this program; if not, write to the Free Software > +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, > +# MA 02110-1301, USA. A copy of the GNU General Public License is > +# also available at http://www.gnu.org/copyleft/gpl.html. > + > +class StorageVolumeController < ApplicationController > + > + before_filter :pre_create, :only => [:create] This before_filter isn't necessary since it's already defined in application.rb -- all you need to do here is define the before_filter method implementation One thing that I did find missing was another reference to the new_volume action -- but this was in jguiddita's new code that wasn't there when the original patches were created -- and since it was new, it didn't come up as a merge conflict: diff --git a/src/app/views/vm/_form.rhtml b/src/app/views/vm/_form.rhtml index 7cbe16d..d1c0e45 100644 --- a/src/app/views/vm/_form.rhtml +++ b/src/app/views/vm/_form.rhtml @@ -71,10 +71,10 @@ {if item.create_volume} <%=image_tag("icon_addstorage.png")%> {if item.is_pool} - {else} - {/if} {/if} Scott From sseago at physical.priv.ovirt.org Tue Feb 3 16:18:20 2009 From: sseago at physical.priv.ovirt.org (Scott Seago) Date: Tue, 3 Feb 2009 16:18:20 +0000 Subject: [Ovirt-devel] [REPOST 1] Various API patches In-Reply-To: <1233606937-18469-1-git-send-email-lutter@redhat.com> References: <1233004325-18032-1-git-send-email-lutter@redhat.com> <1233606937-18469-1-git-send-email-lutter@redhat.com> Message-ID: <20090203161820.GC3312@physical.priv.ovirt.org> On Mon, Feb 02, 2009 at 12:35:29PM -0800, David Lutterkort wrote: > This is a rebase of the patches onto the current HEAD of next > I sent a couple replies to the patches with some minor comments/issues, but once those are resolved, it's an ACK. Scott From lutter at redhat.com Tue Feb 3 18:23:36 2009 From: lutter at redhat.com (David Lutterkort) Date: Tue, 03 Feb 2009 18:23:36 +0000 Subject: [Ovirt-devel] Re: [PATCH server] allow admin to setup iptables port forwarding on server for a vm's vnc port In-Reply-To: <49886952.9080708@redhat.com> References: <1233191768-9399-1-git-send-email-mmorsi@redhat.com> <1233359683.15906.372.camel@localhost.localdomain> <4987785B.80709@redhat.com> <1233615630.20462.16.camel@localhost.localdomain> <49886952.9080708@redhat.com> Message-ID: <1233685416.22652.44.camel@localhost.localdomain> On Tue, 2009-02-03 at 10:57 -0500, Mohammed Morsi wrote: > I guess I misread this when I just implemented it and sent out the > patch, I added the transaction bits where necessary but couldn't find a > suitable way to lock an entire table via rails (am I mistaken Jay or > Scott?), though particular rows can be locked quite easily upon retrieval. You might have to do that by giving AR a raw SQL statement. (get the connection from ActiveRecord::Base and execute the SQL statement) > I could add an array class variable to the VM class, concurrently > protected via mutex, to store ports returned by > available_forward_vnc_port, but this seems to me to be an iffy solution > at best. Mutexes are pretty much useless in web applications, since several server processes might be accessing the same DB. > I figure the best solution given what we have would be to determine if > the error raised by the model is due to the forward_vnc_port unique > constraint failing and then loop around to generate another port (doing > as many times as necessary). It will make the controller code a bit > uglier, but it should work so long as I can determine the particular > fields and validations which cause the failure (from what I've read I > should be able to). I'll get started on this bit, unless there are > better alternate suggestions. That's a really ugly hack - just lock the table and be done with it. David From lutter at redhat.com Tue Feb 3 18:27:59 2009 From: lutter at redhat.com (David Lutterkort) Date: Tue, 03 Feb 2009 18:27:59 +0000 Subject: [Ovirt-devel] Re: [PATCH server] allow admin to setup iptables port forwarding on server for a vm's vnc port In-Reply-To: <498873E4.6020504@redhat.com> References: <1233191768-9399-1-git-send-email-mmorsi@redhat.com> <1233359683.15906.372.camel@localhost.localdomain> <4987785B.80709@redhat.com> <1233615630.20462.16.camel@localhost.localdomain> <20090203161610.GT15613@redhat.com> <498873E4.6020504@redhat.com> Message-ID: <1233685679.22652.48.camel@localhost.localdomain> On Tue, 2009-02-03 at 11:42 -0500, Mohammed Morsi wrote: > I would say its just another use case, eg since the default is to > autoassign the port, is there really any drawback to allowing an > administrator to manually set it? It complicates things (e.g. that you need to assign the port when the VM is created) It's enough to autoassign a port when the VM is started (assuming the user checked the 'forward vnc port' checkbox), and display the assigned port in the VM details. I don't see much point in manually managing port allocations. A more interesting feature than manual port assignment would be to allow to set port forwarding up for a VM that is already running - but that's something we can add in later. David From lutter at redhat.com Tue Feb 3 18:46:14 2009 From: lutter at redhat.com (David Lutterkort) Date: Tue, 03 Feb 2009 18:46:14 +0000 Subject: [Ovirt-devel] [PATCH server 5/8] Factor StorageVolume functionality out of StorageController In-Reply-To: <20090203161529.GB3312@physical.priv.ovirt.org> References: <1233004325-18032-1-git-send-email-lutter@redhat.com> <1233606937-18469-6-git-send-email-lutter@redhat.com> <20090203161529.GB3312@physical.priv.ovirt.org> Message-ID: <1233686774.22652.51.camel@localhost.localdomain> On Tue, 2009-02-03 at 16:15 +0000, Scott Seago wrote: > On Mon, Feb 02, 2009 at 12:35:34PM -0800, David Lutterkort wrote: > > Storage volumes can now be accessed through their own controller. This is > > needed to expose them in the API. > > --- > > diff --git a/src/app/controllers/storage_volume_controller.rb b/src/app/controllers/storage_volume_controller.rb > > new file mode 100644 > > index 0000000..ba486d2 > > --- /dev/null > > +++ b/src/app/controllers/storage_volume_controller.rb > > @@ -0,0 +1,228 @@ > > +# > > +# Copyright (C) 2009 Red Hat, Inc. > > +# Written by Scott Seago > > +# > > +# This program is free software; you can redistribute it and/or modify > > +# it under the terms of the GNU General Public License as published by > > +# the Free Software Foundation; version 2 of the License. > > +# > > +# This program is distributed in the hope that it will be useful, > > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > +# GNU General Public License for more details. > > +# > > +# You should have received a copy of the GNU General Public License > > +# along with this program; if not, write to the Free Software > > +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, > > +# MA 02110-1301, USA. A copy of the GNU General Public License is > > +# also available at http://www.gnu.org/copyleft/gpl.html. > > + > > +class StorageVolumeController < ApplicationController > > + > > + before_filter :pre_create, :only => [:create] > This before_filter isn't necessary since it's already defined in > application.rb -- all you need to do here is define the before_filter > method implementation Removed that from the patch. > One thing that I did find missing was another reference to the > new_volume action -- but this was in jguiddita's new code that wasn't > there when the original patches were created -- and since it was new, > it didn't come up as a merge conflict: Fixed that up. David From lutter at redhat.com Tue Feb 3 19:51:19 2009 From: lutter at redhat.com (David Lutterkort) Date: Tue, 03 Feb 2009 11:51:19 -0800 Subject: [Ovirt-devel] Various API patches In-Reply-To: <1233004325-18032-1-git-send-email-lutter@redhat.com> References: <1233004325-18032-1-git-send-email-lutter@redhat.com> Message-ID: <1233690679.22652.58.camel@localhost.localdomain> On Mon, 2009-01-26 at 13:11 -0800, David Lutterkort wrote: > This series of patches makes various changes needed for the API and the > command line client. In detail, they do: I just committed all these to next. David From dhuff at redhat.com Tue Feb 3 20:20:38 2009 From: dhuff at redhat.com (David Huff) Date: Tue, 03 Feb 2009 15:20:38 -0500 Subject: [Ovirt-devel] issues creating a vm on stand-alone ovirt node remotely via virt-manager Message-ID: <4988A716.8000608@redhat.com> Running: ovirt-node-image-0.97-rc3.el5ovirt.x86_64 I will try to reproduce on upstream fedora node next... I am able to conect to node via virt manager with "qemu+tcp://hostname/system" I run thought the install remotely via virt-manager every thing seems fine, ie Im connected to the node and can create new networks and stuff, however when hit finish "ready to begin installation" I get an error.... " Unable to complete install ' Failed to start SASL negotiation: -4 (SASL(-4): no mechanism available: No worthy mechs found) Traceback (most recent call last): File "/usr/share/virt-manager/virtManager/create.py", line 719, in do_install guest.conn = libvirt.open(self.connection.get_uri()) File "/usr/lib64/python2.5/site-packages/libvirt.py", line 160, in open if ret is None:raise libvirtError('virConnectOpen() failed') libvirtError: Failed to start SASL negotiation: -4 (SASL(-4): no mechanism available: No worthy mechs found) " every thing looks good on the node: [root at NODE ~]# cat /etc/sasl2/libvirt.conf | grep -v ^# sasldb_path: /etc/libvirt/passwd.db mech_list: digest-md5 [root at NODE ~]# cat /etc/libvirt/libvirtd.conf | grep -v ^# | grep -v ^$ listen_tls = 0 listen_tcp = 1 Virt-install with LIBVIRT_DEBUG=1: [david at sunset src]$ sudo LIBVIRT_DEBUG=1 virt-install --connect=qemu+tcp://dhcp231-77.rdu.redhat.com/system --hvm --name test --ram 512 --network bridge:breth1 -f /var/lib/libvirt/images/test.img -s 10 --cdrom /dev/cdrom DEBUG: libvirt.c: virInitialize (register drivers) DEBUG: libvirt.c: virRegisterDriver (registering Test as driver 0) DEBUG: libvirt.c: virRegisterNetworkDriver (registering Test as network driver 0) DEBUG: libvirt.c: virRegisterStorageDriver (registering Test as storage driver 0) DEBUG: libvirt.c: virRegisterDriver (registering Xen as driver 1) DEBUG: libvirt.c: virRegisterDriver (registering OPENVZ as driver 2) DEBUG: libvirt.c: virRegisterDriver (registering remote as driver 3) DEBUG: libvirt.c: virRegisterNetworkDriver (registering remote as network driver 1) DEBUG: libvirt.c: virRegisterStorageDriver (registering remote as storage driver 1) DEBUG: libvirt.c: virRegisterDeviceMonitor (registering remote as device driver 0) DEBUG: libvirt.c: virConnectOpen (name=qemu+tcp://dhcp231-77.rdu.redhat.com/system) DEBUG: libvirt.c: do_open (name "qemu+tcp://dhcp231-77.rdu.redhat.com/system" to URI components: scheme qemu+tcp opaque (null) authority (null) server dhcp231-77.rdu.redhat.com user (null) port 0 path /system ) DEBUG: libvirt.c: do_open (trying driver 0 (Test) ...) DEBUG: libvirt.c: do_open (driver 0 Test returned DECLINED) DEBUG: libvirt.c: do_open (trying driver 1 (Xen) ...) DEBUG: libvirt.c: do_open (driver 1 Xen returned DECLINED) DEBUG: libvirt.c: do_open (trying driver 2 (OPENVZ) ...) DEBUG: libvirt.c: do_open (driver 2 OPENVZ returned DECLINED) DEBUG: libvirt.c: do_open (trying driver 3 (remote) ...) DEBUG: remote_internal.c: doRemoteOpen (proceeding with name = qemu:///system) DEBUG: remote_internal.c: remoteAuthSASL (Client initialize SASL authentication) DEBUG: remote_internal.c: remoteAuthSASL (Client start negotiation mechlist 'DIGEST-MD5') DEBUG: libvirt.c: do_open (driver 3 remote returned ERROR) DEBUG: datatypes.c: virUnrefConnect (unref connection 0x22b9e70 1) DEBUG: datatypes.c: virReleaseConnect (release connection 0x22b9e70) ERROR Failed to start SASL negotiation: -4 (SASL(-4): no mechanism available: No worthy mechs found) Traceback (most recent call last): File "/usr/sbin/virt-install", line 692, in main() File "/usr/sbin/virt-install", line 507, in main conn = cli.getConnection(options.connect) File "/usr/lib/python2.5/site-packages/virtinst/cli.py", line 127, in getConnection return libvirt.open(connect) File "/usr/lib64/python2.5/site-packages/libvirt.py", line 160, in open if ret is None:raise libvirtError('virConnectOpen() failed') libvirtError: Failed to start SASL negotiation: -4 (SASL(-4): no mechanism available: No worthy mechs found) Any suggestions..... -D From mmorsi at redhat.com Tue Feb 3 20:33:23 2009 From: mmorsi at redhat.com (Mohammed Morsi) Date: Tue, 3 Feb 2009 15:33:23 -0500 Subject: [Ovirt-devel] [PATCH server] allow admin to setup iptables port forwarding on server for a vm's vnc port Message-ID: <1233693203-9306-1-git-send-email-mmorsi@redhat.com> --- src/app/controllers/vm_controller.rb | 3 + src/app/models/vm.rb | 23 +++++ src/app/views/vm/_form.rhtml | 3 + src/app/views/vm/show.rhtml | 4 + src/db/migrate/034_add_vm_vnc.rb | 30 +++++++ src/task-omatic/taskomatic.rb | 4 + src/task-omatic/vnc.rb | 154 ++++++++++++++++++++++++++++++++++ src/test/fixtures/vms.yml | 2 + src/test/unit/vm_test.rb | 16 ++++ 9 files changed, 239 insertions(+), 0 deletions(-) create mode 100644 src/db/migrate/034_add_vm_vnc.rb create mode 100644 src/task-omatic/vnc.rb diff --git a/src/app/controllers/vm_controller.rb b/src/app/controllers/vm_controller.rb index 56501fd..f104415 100644 --- a/src/app/controllers/vm_controller.rb +++ b/src/app/controllers/vm_controller.rb @@ -116,6 +116,8 @@ class VmController < ApplicationController new_storage_ids = new_storage_ids.sort.collect {|x| x.to_i } needs_restart = true unless current_storage_ids == new_storage_ids end + + params[:vm][:forward_vnc] = params[:forward_vnc] params[:vm][:needs_restart] = 1 if needs_restart @vm.update_attributes!(params[:vm]) _setup_vm_provision(params) @@ -345,6 +347,7 @@ class VmController < ApplicationController vm_resource_pool.create_with_parent(hardware_pool) params[:vm][:vm_resource_pool_id] = vm_resource_pool.id end + params[:vm][:forward_vnc] = params[:forward_vnc] @vm = Vm.new(params[:vm]) @perm_obj = @vm.vm_resource_pool @current_pool_id=@perm_obj.id diff --git a/src/app/models/vm.rb b/src/app/models/vm.rb index bf99e2d..b6b5457 100644 --- a/src/app/models/vm.rb +++ b/src/app/models/vm.rb @@ -40,6 +40,17 @@ class Vm < ActiveRecord::Base validates_format_of :uuid, :with => %r([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}) + FORWARD_VNC_PORT_START = 5900 + + validates_numericality_of :forward_vnc_port, + :message => 'must be >= ' + FORWARD_VNC_PORT_START.to_s, + :greater_than_or_equal_to => FORWARD_VNC_PORT_START, + :if => Proc.new { |vm| vm.forward_vnc && !vm.forward_vnc_port.nil? } + + validates_uniqueness_of :forward_vnc_port, + :message => "is already in use", + :if => Proc.new { |vm| vm.forward_vnc && !vm.forward_vnc_port.nil? } + validates_numericality_of :needs_restart, :greater_than_or_equal_to => 0, :less_than_or_equal_to => 1, @@ -335,6 +346,18 @@ class Vm < ActiveRecord::Base super end + # find the first available vnc port + def self.available_forward_vnc_port + i = FORWARD_VNC_PORT_START + Vm.find(:all, + :conditions => "forward_vnc_port is not NULL", + :order => 'forward_vnc_port ASC' ).collect{ |vm| + return i if vm.forward_vnc_port > i + i = i + 1 + } + return i + end + protected def validate resources = vm_resource_pool.max_resources_for_vm(self) diff --git a/src/app/views/vm/_form.rhtml b/src/app/views/vm/_form.rhtml index d1c0e45..79621ca 100644 --- a/src/app/views/vm/_form.rhtml +++ b/src/app/views/vm/_form.rhtml @@ -51,6 +51,9 @@
+ <%= check_box_tag_with_label "Forward vm's vnc port locally", "forward_vnc", 1, @vm.forward_vnc %> +
+ <%= check_box_tag_with_label "Start VM Now? (pending current resource availability)", "start_now", nil if create or @vm.state == Vm::STATE_STOPPED %> <%= check_box_tag_with_label "Restart VM Now? (pending current resource availability)", "restart_now", nil if @vm.state == Vm::STATE_RUNNING %> diff --git a/src/app/views/vm/show.rhtml b/src/app/views/vm/show.rhtml index f361131..add29b4 100644 --- a/src/app/views/vm/show.rhtml +++ b/src/app/views/vm/show.rhtml @@ -88,6 +88,7 @@
Uuid:
+ <%= @vm.forward_vnc ? "VNC uri:
" : "" %> Num vcpus allocated:
Num vcpus used:
Memory allocated:
@@ -100,6 +101,9 @@
<%=h @vm.uuid %>
+ <%= url = request.url + url = request.url[0..(url.index('/', 8) - 1)] + ":" + @vm.forward_vnc_port.to_s + @vm.forward_vnc ? (url + "
") : "" %> <%=h @vm.num_vcpus_allocated %>
<%=h @vm.num_vcpus_used %>
<%=h @vm.memory_allocated_in_mb %> MB
diff --git a/src/db/migrate/034_add_vm_vnc.rb b/src/db/migrate/034_add_vm_vnc.rb new file mode 100644 index 0000000..f23e24d --- /dev/null +++ b/src/db/migrate/034_add_vm_vnc.rb @@ -0,0 +1,30 @@ +# Copyright (C) 2008 Red Hat, Inc. +# Written by Mohammed Morsi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +class AddVmVnc < ActiveRecord::Migration + def self.up + add_column :vms, :forward_vnc, :bool, :default => false + add_column :vms, :forward_vnc_port, :int, :default => 0, :unique => true + end + + def self.down + drop_column :vms, :forward_vnc + drop_column :vms, :forward_vnc_port + end +end + diff --git a/src/task-omatic/taskomatic.rb b/src/task-omatic/taskomatic.rb index 0570246..380be92 100755 --- a/src/task-omatic/taskomatic.rb +++ b/src/task-omatic/taskomatic.rb @@ -32,6 +32,7 @@ include Daemonize require 'task_vm' require 'task_storage' +require 'vnc' class TaskOmatic @@ -232,6 +233,8 @@ class TaskOmatic raise "Error destroying VM: #{result.text}" unless result.status == 0 end + VmVnc.close(vm) + # undefine can fail, for instance, if we live migrated from A -> B, and # then we are shutting down the VM on B (because it only has "transient" # XML). Therefore, just ignore undefine errors so we do the rest @@ -303,6 +306,7 @@ class TaskOmatic # of places so you'll see a lot of .reloads. db_vm.reload set_vm_vnc_port(db_vm, result.description) unless result.status != 0 + VmVnc.forward(db_vm) # This information is not available via the libvirt interface. db_vm.memory_used = db_vm.memory_allocated diff --git a/src/task-omatic/vnc.rb b/src/task-omatic/vnc.rb new file mode 100644 index 0000000..0fd3afd --- /dev/null +++ b/src/task-omatic/vnc.rb @@ -0,0 +1,154 @@ +# Copyright (C) 2008 Red Hat, Inc. +# Written by Mohammed Morsi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +# provides static 'forward' and 'close' methods to forward a specified vm's vnc connections +class VmVnc + + private + + # TODO no ruby/libiptc wrapper exists, when + # it does replace iptables command w/ calls to it + IPTABLES_CMD='/sbin/iptables ' + + VNC_DEBUG = false + + # FIXME can this be retreived in any way + # since machine will have both external + # and internal network interface + LOCAL_IP = '192.168.50.2' + + def self.debug(msg) + puts "\n" + msg + "\n" if VNC_DEBUG + end + + def self.find_host_ip(hostname) + # FIXME + addrinfo = Socket::getaddrinfo(hostname, nil) + unless addrinfo.size > 0 + raise "Could not retreive address for " + hostname + end + result = addrinfo[0][3] # return ip address of first entry + debug( "vm host hostname resolved to " + result.to_s ) + return result + end + + def self.port_open?(port) + cmd=IPTABLES_CMD + ' -t nat -nL ' + debug("vncPortOpen? iptables command: " + cmd) + + `#{cmd}`.each_line do |l| + return true if l =~ /.*#{port}.*/ + end + return false + end + + def self.allocate_forward_vnc_port(vm) + Vm.transaction do + ActiveRecord::Base.connection.execute('LOCK TABLE vms') + vm.forward_vnc_port = Vm.available_forward_vnc_port + debug("Allocating forward vnc port " + vm.forward_vnc_port.to_s) + vm.save! + end + end + + def self.deallocate_forward_vnc_port(vm) + debug("Deallocating forward vnc port " + vm.forward_vnc_port.to_s) + vm.forward_vnc_port = nil + vm.save! + end + + def self.get_forward_rules(vm) + ip = find_host_ip(vm.host.hostname) + return " -d " + ip + " -p tcp --dport " + vm.vnc_port.to_s + " -j ACCEPT", + " -s " + ip + " -p tcp --sport " + vm.vnc_port.to_s + " -j ACCEPT" + end + + def self.get_nat_rules(vm) + ip = find_host_ip(vm.host.hostname) + + return " -p tcp --dport " + vm.forward_vnc_port.to_s + " -j DNAT --to " + ip + ":" + vm.vnc_port.to_s, + " -d " + ip + " -p tcp --dport " + vm.vnc_port.to_s + " -j SNAT --to " + LOCAL_IP + end + + def self.run_command(cmd) + debug("Running command " + cmd) + status = system(cmd) + raise 'Command terminated with error code ' + $?.to_s unless status + end + + public + + def self.forward(vm) + return unless vm.forward_vnc + + allocate_forward_vnc_port(vm) + if port_open?(vm.forward_vnc_port) + deallocate_forward_vnc_port(vm) + raise "Port already open " + vm.forward_vnc_port.to_s + end + + forward_rule1, forward_rule2 = get_forward_rules(vm) + forward_rule1 = IPTABLES_CMD + " -A FORWARD " + forward_rule1 + forward_rule2 = IPTABLES_CMD + " -A FORWARD " + forward_rule2 + + prerouting_rule, postrouting_rule = get_nat_rules(vm) + prerouting_rule = IPTABLES_CMD + " -t nat -A PREROUTING " + prerouting_rule + postrouting_rule = IPTABLES_CMD + " -t nat -A POSTROUTING " + postrouting_rule + + debug(" open\n forward rule 1: " + forward_rule1 + + "\n forward_rule 2: " + forward_rule2 + + "\n prerouting rule: " + prerouting_rule + + "\n postrouting rule: " + postrouting_rule) + + + File::open("/proc/sys/net/ipv4/ip_forward", "w") { |f| f.puts "1" } + run_command(forward_rule1) + run_command(forward_rule2) + run_command(prerouting_rule) + run_command(postrouting_rule) + end + + def self.close(vm) + return unless vm.forward_vnc + + unless port_open?(vm.forward_vnc_port) + raise "Port not open " + vm.forward_vnc_port.to_s + end + + forward_rule1, forward_rule2 = get_forward_rules(vm) + forward_rule1 = IPTABLES_CMD + " -D FORWARD " + forward_rule1 + forward_rule2 = IPTABLES_CMD + " -D FORWARD " + forward_rule2 + + prerouting_rule, postrouting_rule = get_nat_rules(vm) + prerouting_rule = IPTABLES_CMD + " -t nat -D PREROUTING " + prerouting_rule + postrouting_rule = IPTABLES_CMD + " -t nat -D POSTROUTING " + postrouting_rule + + debug(" close\n forward rule 1: " + forward_rule1 + + "\n forward_rule 2: " + forward_rule2 + + "\n prerouting rule: " + prerouting_rule + + "\n postrouting rule: " + postrouting_rule) + + run_command(forward_rule1) + run_command(forward_rule2) + run_command(prerouting_rule) + run_command(postrouting_rule) + + + deallocate_forward_vnc_port(vm) + end +end diff --git a/src/test/fixtures/vms.yml b/src/test/fixtures/vms.yml index ca0d63f..40997b0 100644 --- a/src/test/fixtures/vms.yml +++ b/src/test/fixtures/vms.yml @@ -11,6 +11,8 @@ production_httpd_vm: boot_device: hd host: prod_corp_com vm_resource_pool: corp_com_production_vmpool + forward_vnc: true + forward_vnc_port: 5900 production_mysqld_vm: uuid: 89e62d32-04d9-4351-b573-b1a253397296 description: production mysqld appliance diff --git a/src/test/unit/vm_test.rb b/src/test/unit/vm_test.rb index cba3188..b868dfa 100644 --- a/src/test/unit/vm_test.rb +++ b/src/test/unit/vm_test.rb @@ -95,6 +95,22 @@ class VmTest < Test::Unit::TestCase flunk 'Vm must specify valid state' if @vm.valid? end + # ensure duplicate forward_vnc_ports cannot exist + def test_invalid_without_unique_forward_vnc_port + vm = vms(:production_mysqld_vm) + vm.forward_vnc = true + vm.forward_vnc_port = 1234 # duplicate + assert !vm.valid?, "forward vnc port must be unique" + end + + # ensure bad forward_vnc_ports cannot exist + def test_invalid_without_bad_forward_vnc_port + vm = vms(:production_mysqld_vm) + vm.forward_vnc = true + vm.forward_vnc_port = 1 # too small + assert !vm.valid?, "forward vnc port must be >= 5900" + end + # Ensures that, if the VM does not contain the Cobbler prefix, that it # does not claim to be a Cobbler VM. # -- 1.6.0.6 From mmorsi at redhat.com Tue Feb 3 20:37:56 2009 From: mmorsi at redhat.com (Mohammed Morsi) Date: Tue, 03 Feb 2009 15:37:56 -0500 Subject: [Ovirt-devel] Re: [PATCH server] allow admin to setup iptables port forwarding on server for a vm's vnc port In-Reply-To: <1233693203-9306-1-git-send-email-mmorsi@redhat.com> References: <1233693203-9306-1-git-send-email-mmorsi@redhat.com> Message-ID: <4988AB24.7060708@redhat.com> This working patch includes all your suggestions - forward vnc port isn't assign until vm startup and unassigned until vm shutdown - manual port allocation has been remove - 'lock table' invocations added for concurrent port assignment -Mo From jguiditt at redhat.com Tue Feb 3 20:51:22 2009 From: jguiditt at redhat.com (Jason Guiditta) Date: Tue, 3 Feb 2009 15:51:22 -0500 Subject: [Ovirt-devel] [PATCH server] Minor bug fixes and enhancements. Message-ID: <1233694282-874-1-git-send-email-jguiditt@redhat.com> * Fixed weird css issue with popup for 'add storage server'. * Fixed bug in edit_items method of HardwareController. It was looking for a param that was not always present. * Made the storage tree in main content area of storage tab a subscriber to the STORAGE_VOLUME channel, set a couple places to publish events to that channel. This means it will now update when a new storage item is added. Signed-off-by: Jason Guiditta --- src/app/controllers/hardware_controller.rb | 5 +++-- src/app/controllers/storage_controller.rb | 3 ++- src/app/models/hardware_pool.rb | 2 +- src/app/views/hardware/move.rhtml | 3 ++- src/app/views/hardware/show_storage.rhtml | 3 ++- src/public/javascripts/ovirt.js | 21 ++++++++++----------- src/public/javascripts/ovirt.tree.js | 4 ++-- src/public/stylesheets/ovirt-tree/tree.css | 2 +- 8 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/app/controllers/hardware_controller.rb b/src/app/controllers/hardware_controller.rb index 0f9cceb..3caf024 100644 --- a/src/app/controllers/hardware_controller.rb +++ b/src/app/controllers/hardware_controller.rb @@ -299,7 +299,7 @@ class HardwareController < PoolController 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) + unless @pool.can_modify(@user) and Pool.find(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 @@ -326,7 +326,8 @@ class HardwareController < PoolController if success render :json => { :success => true, - :alert => "#{item_action.to_s} #{item_class.table_name.humanize} successful." } + :alert => "#{item_action.to_s} #{item_class.table_name.humanize} successful.", + :storage => @pool.storage_tree({:filter_unavailable => false, :include_used => true, :state => item_action.to_s})} else render :json => { :success => false, :alert => "#{item_action.to_s} #{item_class.table_name.humanize} failed" + diff --git a/src/app/controllers/storage_controller.rb b/src/app/controllers/storage_controller.rb index 7f69efa..98ba0f6 100644 --- a/src/app/controllers/storage_controller.rb +++ b/src/app/controllers/storage_controller.rb @@ -126,7 +126,8 @@ class StorageController < ApplicationController respond_to do |format| format.json { render :json => { :object => "storage_pool", :success => true, - :alert => "Storage Pool was successfully created." } } + :alert => "Storage Pool was successfully created.", + :new_pool => @storage_pool.storage_tree_element({:filter_unavailable => false, :state => 'new'})} } format.xml { render :xml => @storage_pool, :status => :created, :location => storage_pool_url(@storage_pool) diff --git a/src/app/models/hardware_pool.rb b/src/app/models/hardware_pool.rb index b72d485..7015854 100644 --- a/src/app/models/hardware_pool.rb +++ b/src/app/models/hardware_pool.rb @@ -60,7 +60,7 @@ class HardwarePool < Pool end end - def move_storage(storage_pool_ids, target_pool_id) + def move_storage(storage_pool_ids, target_pool_id) storage_pools = StoragePool.find(:all, :conditions => "id in (#{storage_pool_ids.join(', ')})") transaction do storage_pools.each do |storage_pool| diff --git a/src/app/views/hardware/move.rhtml b/src/app/views/hardware/move.rhtml index 3bcb8bb..6ada86d 100644 --- a/src/app/views/hardware/move.rhtml +++ b/src/app/views/hardware/move.rhtml @@ -9,6 +9,7 @@ $(document).ready(function(){ $('#move_tree').tree({ content: {"pools" : <%= @pools %>}, + template: 'move_template', clickHandler: move_<%= @resource_type %>, cacheContent: false }); @@ -42,7 +43,7 @@ $('#move_to_new_pool').click(function(){
    -