Luke Bigum
2011-Sep-08 08:27 UTC
[Puppet Users] commands in Puppet providers being escaped differently to a shell
Hi list, I''m making a few modifications to the puppet-virt type from GitHub (https://github.com/carlasouza/puppet-virt.git) and I''ve run across an interesting problem with what looks like how a "command" in a Puppet provider is escaping or interpreting it''s arguments. Explaining this is a bit long winded so bear with me... We want to pass in multiple kernel boot arguments when doing a KVM virt-install, a simple example is below. --extra-args takes a single argument and can''t be specified twice so if you want to specify multiple you have to group them together as one string like so: virt-install --name foo --extra-args "dhcp console=ttyS0 ks=http:// ks/foo.ks" This gets translated by virt-install (Python) into individual arguments after "-append" to the qemu-kvm binary like so: /usr/bin/qemu-kvm <heaps of other arguments> -append method=http:// gs2repo.gs2.tradefair/mrepo/latest/fedora15-x86_64/RPMS.os/ noipv6 console=ttyS0,115200 dhcp ks=http://gs2repo.gs2.tradefair/mrepo/ kickstarts/fedora15.ks So the transition of arguments is "Shell -> Python -> Binary" and everything works grand. Now, trying to replicate the same thing in Puppet has proved difficult. Nearest I can tell with my limited Puppet / Ruby knowledge, the argument list is being handled differently and so what gets put on the qemu-kvm binary''s command line is one single string of arguments that aren''t expanded out properly and so qemu-kvm doesn''t function as we intend. Here''s how I''m trying to do it in Puppet. A simplified virt resource in a manifest, note the double sets of quotes: virt { "foo": ensure => running, boot_options => ''"noipv6 console=ttyS0,115200 dhcp ks=http:// gs2repo.gs2.tradefair/mrepo/kickstarts/fedora15.ks"'', } This gets translated into the provider (heavily simplified below for brevity), arguments are pulled from resource parameters and translated into arrays and appended as arguments to the Puppet/Ruby virt-install command: Puppet::Type.type(:virt).provide(:libvirt) do commands :virtinstall => "/usr/bin/virt-install" bootargs = ["--extra-args", resource[:boot_options] ] def install virtinstall generalargs + networkargs + graphicargs + bootargs Applying this manifest and looking at the debug output, it seems to be escaped correctly: debug: Puppet::Type::Virt::ProviderLibvirt: Executing ''/usr/bin/ virt-install --name foo --extra-args "dhcp console=ttyS0 ks=http://ks/ foo.ks"'' notice: /Stage[main]//Virt[foo]/ensure: created However if you then check to see what qemu-kvm command is now running, it''s still got the shell quotes in the argument list: /usr/bin/qemu-kvm <heaps of other arguments> -append method=http:// gs2repo.gs2.tradefair/mrepo/latest/fedora15-x86_64/RPMS.os/ "noipv6 console=ttyS0,115200 dhcp ks=http://gs2repo.gs2.tradefair/mrepo/ kickstarts/fedora15.ks" This causes some strange side affects, like the machine kickstarting but no console, or if you reorder things, you can get a console but the kickstart isn''t found. Single quotes vs double quotes isn''t much better, qemu-kvm just behaves different but still incorrect. I''ve tried passing the arguments as an array from Puppet/Ruby, but this won''t work as virt-install must take a single multi-word string as the one and only argument to --extra-args or it complains. You could argue that virt-install could be more helpful and accept multiple --extra- args, but it''s the only tool at hand. So, somewhere between Puppet/Ruby and Python the arguments are being passed to virt-install strangely, maybe the way Puppet exec''s it''s commands? I''m not sure. For the moment I''ve managed to work around this using a dirty, dirty hack: commands :virtinstall => "/bin/sh" virtinstallargs = generalargs + networkargs + graphicargs + bootargs virtinstallstring = "/usr/bin/virt-install " + virtinstallargs.join('' '') virtinstall [ "-c", virtinstallstring ] I''d like to be able to do it without using a shell to get the desired escaping behaviour. It''s a bit of a strange one, but if anyone has any suggestions I could try I''ll give them a go. Thanks, -Luke -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To post to this group, send email to puppet-users@googlegroups.com. To unsubscribe from this group, send email to puppet-users+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.
jcbollinger
2011-Sep-08 14:08 UTC
[Puppet Users] Re: commands in Puppet providers being escaped differently to a shell
On Sep 8, 3:27 am, Luke Bigum <Luke.Bi...@lmax.com> wrote:> Hi list, > > I''m making a few modifications to the puppet-virt type from GitHub > (https://github.com/carlasouza/puppet-virt.git) and I''ve run across an > interesting problem with what looks like how a "command" in a Puppet > provider is escaping or interpreting it''s arguments. Explaining this > is a bit long winded so bear with me... > > We want to pass in multiple kernel boot arguments when doing a KVM > virt-install, a simple example is below. --extra-args takes a single > argument and can''t be specified twice so if you want to specify > multiple you have to group them together as one string like so: > > virt-install --name foo --extra-args "dhcp console=ttyS0 ks=http:// > ks/foo.ks" > > This gets translated by virt-install (Python) into individual > arguments after "-append" to the qemu-kvm binary like so: > > /usr/bin/qemu-kvm <heaps of other arguments> -append method=http:// > gs2repo.gs2.tradefair/mrepo/latest/fedora15-x86_64/RPMS.os/ noipv6 > console=ttyS0,115200 dhcp ks=http://gs2repo.gs2.tradefair/mrepo/ > kickstarts/fedora15.ks > > So the transition of arguments is "Shell -> Python -> Binary" and > everything works grand. Now, trying to replicate the same thing in > Puppet has proved difficult. Nearest I can tell with my limited > Puppet / Ruby knowledge, the argument list is being handled > differently and so what gets put on the qemu-kvm binary''s command line > is one single string of arguments that aren''t expanded out properly > and so qemu-kvm doesn''t function as we intend. > > Here''s how I''m trying to do it in Puppet. A simplified virt resource > in a manifest, note the double sets of quotes: > > virt { "foo": > ensure => running, > boot_options => ''"noipv6 console=ttyS0,115200 dhcp ks=http:// > gs2repo.gs2.tradefair/mrepo/kickstarts/fedora15.ks"'', > } > > This gets translated into the provider (heavily simplified below for > brevity), arguments are pulled from resource parameters and translated > into arrays and appended as arguments to the Puppet/Ruby virt-install > command: > > Puppet::Type.type(:virt).provide(:libvirt) do > commands :virtinstall => "/usr/bin/virt-install" > bootargs = ["--extra-args", resource[:boot_options] ] > def install > virtinstall generalargs + networkargs + graphicargs + > bootargs > > Applying this manifest and looking at the debug output, it seems to be > escaped correctly: > > debug: Puppet::Type::Virt::ProviderLibvirt: Executing ''/usr/bin/ > virt-install --name foo --extra-args "dhcp console=ttyS0 ks=http://ks/ > foo.ks"'' > notice: /Stage[main]//Virt[foo]/ensure: created > > However if you then check to see what qemu-kvm command is now running, > it''s still got the shell quotes in the argument list: > > /usr/bin/qemu-kvm <heaps of other arguments> -append method=http:// > gs2repo.gs2.tradefair/mrepo/latest/fedora15-x86_64/RPMS.os/ "noipv6 > console=ttyS0,115200 dhcp ks=http://gs2repo.gs2.tradefair/mrepo/ > kickstarts/fedora15.ks" > > This causes some strange side affects, like the machine kickstarting > but no console, or if you reorder things, you can get a console but > the kickstart isn''t found. Single quotes vs double quotes isn''t much > better, qemu-kvm just behaves different but still incorrect. I''ve > tried passing the arguments as an array from Puppet/Ruby, but this > won''t work as virt-install must take a single multi-word string as the > one and only argument to --extra-args or it complains. You could argue > that virt-install could be more helpful and accept multiple --extra- > args, but it''s the only tool at hand. > > So, somewhere between Puppet/Ruby and Python the arguments are being > passed to virt-install strangely, maybe the way Puppet exec''s it''s > commands? I''m not sure. > > For the moment I''ve managed to work around this using a dirty, dirty > hack: > > commands :virtinstall => "/bin/sh" > virtinstallargs = generalargs + networkargs + graphicargs + > bootargs > virtinstallstring = "/usr/bin/virt-install " + > virtinstallargs.join('' '') > virtinstall [ "-c", virtinstallstring ] > > I''d like to be able to do it without using a shell to get the desired > escaping behaviour. > > It''s a bit of a strange one, but if anyone has any suggestions I could > try I''ll give them a go.It looks like the LibVirt provider is launching virt-install directly instead of via the shell (i.e. it is forking and then exec''ing /usr/ bin/virt-install, instead of, for instance, using the system() command or a %x string). If it is indeed doing that then it should not be quoting any arguments, even if though they contain whitespace or shell metacharacters, because the arguments are not processed by the shell. Your hack solves the problem by forcing the provider to run virt- install via the shell, which isn''t that bad. Better, however, would be to make the provider do the right thing with the arguments in the first place. Since you provide only a simplified approximation to the provider code, I can''t tell what would be needed to accomplish that. John -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To post to this group, send email to puppet-users@googlegroups.com. To unsubscribe from this group, send email to puppet-users+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.
Luke Bigum
2011-Sep-08 14:59 UTC
[Puppet Users] Re: commands in Puppet providers being escaped differently to a shell
Ahhhh! That makes sense, I should be thinking like C/C++ execv, one array element per argument, no matter what it''s string content. Dropping the quotes in the parameter sting and using the original Ruby command exec works fine. I should have tried that before - I was confusing myself by trying too hard to emulate what the shell version of virt-install looked like. Thanks for the nudge in the right direction, John :-) -Luke On Sep 8, 3:08 pm, jcbollinger <John.Bollin...@stJude.org> wrote:> > It looks like the LibVirt provider is launching virt-install directly > instead of via the shell (i.e. it is forking and then exec''ing /usr/ > bin/virt-install, instead of, for instance, using the system() command > or a %x string). If it is indeed doing that then it should not be > quoting any arguments, even if though they contain whitespace or shell > metacharacters, because the arguments are not processed by the shell. > > Your hack solves the problem by forcing the provider to run virt- > install via the shell, which isn''t that bad. Better, however, would > be to make the provider do the right thing with the arguments in the > first place. Since you provide only a simplified approximation to the > provider code, I can''t tell what would be needed to accomplish that. > > John-- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To post to this group, send email to puppet-users@googlegroups.com. To unsubscribe from this group, send email to puppet-users+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.