emyl / vagrant-triggers

Allow the definition of arbitrary scripts that will run on the host before and/or after Vagrant commands.
MIT License
546 stars 35 forks source link

run command does not properly handle passed quotes #49

Closed ephantom closed 8 years ago

ephantom commented 9 years ago

OS Centos 6 INFO global: Vagrant version: 1.7.2 INFO global: Ruby version: 2.0.0 INFO global: RubyGems version: 2.0.14 INFO global: - vagrant-triggers = 0.5.0

So I have a problem with passing quotes within quotes while using vagrant-triggers.

Essentially I'm trying to run this sed command, which works fine on the command line: sed -i -r 's/"groups": [$/"groups": [\n "TEST_admin",/' ~/chef-repo/data_bags/users/vagrant.json

Normally that would be: run "sed -i -r 's/"groups": [$/"groups": [\n "TEST_admin",/' ~/chef-repo/data_bags/users/vagrant.json"

The quotes being processed on three different levels (vagrant-triggers, command line and regular expression) causes a problem. Using ruby variables I've eliminated one level of the problem now I only have to deal with vagrant-triggers (ruby) and command line. I can theoretically backslash a quote to fix that problem.

   #Before we do anything with this box:
   config.trigger.before :up do
    admimquote = '"TEST_admin"'
    groupquote = '"groups"'
    run  "sed -i -r \'s/#{groupquote}: \\[$/#{groupquote}: \\[\\n    #{admimquote},/\' ~/chef-repo/data_bags/users/vagrant.json"
   end

The reason I'm logging this as a possible bug ticket is that I'm getting back two responses from the logging and I can't tell which one its outputted to the command line.

"INFO interface:" indicates its executing this command: sed -i -r s/"groups": [$/"groups": [n "TEST_admin",/ ~/chef-repo/data_bags/users/vagrant.json

The "ERROR warden:" is indicating it received this command: sed -i -r 's/"groups": [$/"groups": [\n "TEST_admin",/' ~/chef-repo/data_bags/users/vagrant.json

I can't tell from the logs which command was actually sent to the command line.

Here is the full error:

 INFO interface: info: Executing command "sed -i -r s/"groups": [$/"groups": [n    "TEST_admin",/ ~/chef-repo/data_bags/users/vagrant.json"...
 INFO interface: info: ==> default: Executing command "sed -i -r s/"groups": [$/"groups": [n    "TEST_admin",/ ~/chef-repo/data_bags/users/vagrant.json"...
==> default: Executing command "sed -i -r s/"groups": [$/"groups": [n    "TEST_admin",/ ~/chef-repo/data_bags/users/vagrant.json"...
 INFO subprocess: Starting process: ["/bin/sed", "-i", "-r", "s/\"groups\": [$/\"groups\": [n    \"TEST_admin\",/", "~/chef-repo/data_bags/users/vagrant.json"]
 INFO interface: error: /bin/sed: -e expression #1, char 47: unterminated `s' command

 INFO interface: error: ==> default: /bin/sed: -e expression #1, char 47: unterminated `s' command
==> default: /bin/sed: -e expression #1, char 47: unterminated `s' command
 INFO interface: info: Command execution finished.
 INFO interface: info: ==> default: Command execution finished.
==> default: Command execution finished.
ERROR warden: Error occurred: The command "sed -i -r 's/"groups": \[$/"groups": \[\n    "TEST_admin",/' ~/chef-repo/data_bags/users/vagrant.json" returned a failed exit code. The
error output is shown below:

/bin/sed: -e expression #1, char 47: unterminated `s' command

For testing here’s the pertinent portion of vagrant.json that sed is working on the sed command should add a line between groups and lastentry:

  "groups": [
    "lastentry"
  ],
ephantom commented 9 years ago

I just tried the following which should have removed all quoting issues. but it looks like there is still a problem:

admimquote = '"TEST_admin"'
groupquote = '"groups"'
runthis = "sed -i -r 's/" + groupquote + ": \[$/" + groupquote + ": \[" + '\n' + "    " + admimquote + ",/' ~/chef-repo/data_bags/users/vagrant.json"
run   runthis

==> default: Executing command "sed -i -r s/"groups": [$/"groups": [n    "TEST_admin",/ ~/chef-repo/data_bags/users/vagrant.json"...
==> default: /bin/sed: -e expression #1, char 47: unterminated `s' command
==> default: Command execution finished.
The command "sed -i -r 's/"groups": [$/"groups": [\n    "TEST_admin",/' ~/chef-repo/data_bags/users/vagrant.json" returned a failed exit code. The
error output is shown below:

/bin/sed: -e expression #1, char 47: unterminated `s' command
ephantom commented 9 years ago

Humm another thing I tried was moving the command to a bash shell script (prebootstrap.sh).

 INFO interface: info: Running triggers before up...
 INFO interface: info: ==> default: Running triggers before up...
==> default: Running triggers before up...
 INFO interface: info: Executing command "prebootstrap.sh"...
 INFO interface: info: ==> default: Executing command "prebootstrap.sh"...
==> default: Executing command "prebootstrap.sh"...
 INFO subprocess: Starting process: ["prebootstrap.sh"]
ERROR warden: Error occurred: No such file or directory - prebootstrap.sh
 INFO warden: Beginning recovery process...
 INFO warden: Recovery complete.
 INFO warden: Beginning recovery process...
 INFO warden: Recovery complete.
 INFO warden: Beginning recovery process...
 INFO warden: Recovery complete.
 INFO environment: Released process lock: machine-action-92cb79e7b5444cdf0349bca3ac36999e
 INFO environment: Running hook: environment_unload
 INFO runner: Preparing hooks for middleware sequence...
 INFO runner: 3 hooks defined.
 INFO runner: Running action: #<Vagrant::Action::Builder:0x00000002261ec8>
 INFO warden: Calling IN action: #<VagrantPlugins::Triggers::Action::Trigger:0x00000002268db8>
 INFO warden: Calling IN action: #<VagrantPlugins::Triggers::Action::Trigger:0x0000000228d078>
 INFO warden: Calling IN action: #<VagrantPlugins::Triggers::Action::Trigger:0x000000022b5eb0>
 INFO warden: Calling OUT action: #<VagrantPlugins::Triggers::Action::Trigger:0x000000022b5eb0>
 INFO warden: Calling OUT action: #<VagrantPlugins::Triggers::Action::Trigger:0x0000000228d078>
 INFO warden: Calling OUT action: #<VagrantPlugins::Triggers::Action::Trigger:0x00000002268db8>
/opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/util/subprocess.rb:109:in `rescue in execute': No such file or directory - prebootstrap.sh (Vagrant::Util::Subprocess::LaunchError)
    from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/util/subprocess.rb:102:in `execute'
    from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/util/subprocess.rb:22:in `execute'
    from /root/.vagrant.d/gems/gems/vagrant-triggers-0.5.0/lib/vagrant-triggers/dsl.rb:44:in `block in run'
    from /opt/vagrant/embedded/gems/gems/bundler-1.7.11/lib/bundler.rb:236:in `block in with_clean_env'
    from /opt/vagrant/embedded/gems/gems/bundler-1.7.11/lib/bundler.rb:223:in `with_original_env'
    from /opt/vagrant/embedded/gems/gems/bundler-1.7.11/lib/bundler.rb:229:in `with_clean_env'
    from /root/.vagrant.d/gems/gems/vagrant-triggers-0.5.0/lib/vagrant-triggers/dsl.rb:41:in `run'
    from /root/vagrant/Vagrantfile:33:in `block (2 levels) in <top (required)>'
    from /root/.vagrant.d/gems/gems/vagrant-triggers-0.5.0/lib/vagrant-triggers/action/trigger.rb:55:in `instance_eval'
    from /root/.vagrant.d/gems/gems/vagrant-triggers-0.5.0/lib/vagrant-triggers/action/trigger.rb:55:in `block in fire_triggers'
    from /root/.vagrant.d/gems/gems/vagrant-triggers-0.5.0/lib/vagrant-triggers/action/trigger.rb:51:in `each'
    from /root/.vagrant.d/gems/gems/vagrant-triggers-0.5.0/lib/vagrant-triggers/action/trigger.rb:51:in `fire_triggers'
    from /root/.vagrant.d/gems/gems/vagrant-triggers-0.5.0/lib/vagrant-triggers/action/trigger.rb:16:in `call'
    from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/action/warden.rb:34:in `call'
    from /root/.vagrant.d/gems/gems/vagrant-triggers-0.5.0/lib/vagrant-triggers/action/trigger.rb:17:in `call'
    from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/action/warden.rb:34:in `call'
    from /root/.vagrant.d/gems/gems/vagrant-triggers-0.5.0/lib/vagrant-triggers/action/trigger.rb:17:in `call'
    from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/action/warden.rb:34:in `call'
    from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/action/builder.rb:116:in `call'
    from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/action/runner.rb:66:in `block in run'
    from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/util/busy.rb:19:in `busy'
    from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/action/runner.rb:66:in `run'
    from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/machine.rb:214:in `action_raw'
    from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/machine.rb:191:in `block in action'
    from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/environment.rb:516:in `lock'
    from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/machine.rb:178:in `call'
    from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/machine.rb:178:in `action'
    from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/batch_action.rb:82:in `block (2 levels) in run'

So is this a vagrant-triggers issue or a /vagrant-1.7.2/lib/vagrant/util/subprocess.rb issue? or an environment variable issue? I don't think its the latter, as I've give the full path to sed and vagrant.json in the bash script. The error: No such file or directory is vague. If I run the prebootstrap.sh script it works fine. If I make a short test ruby scrip and exec('./prebootstrap.sh') it it works fine.

Does anyone have any suggestions?

ephantom commented 9 years ago

I should mention these commands are being run before the box is up, meaning they are running on the system that vagrant is on, not on the box. I have successfully run other commands that are not using quotes, so I can verify that this issue seems to be specific to "run" not properly handling a command that is trying to pass quotes. I'm not clear on weather run is a part of vagrant or the vagrant-triggers project.

I did find a cleaner method using hex escapes and the run command still fails. So there is a coding issue with the run command and quotes that should be fixed.

run "/bin/sed -i -r \x27s/\x22groups\x22: [$/\x22groups\x22: [\x5cn \x22TEST_admin\x22,/\x27 /user/chef-repo/data_bags/users/vagrant.json"

outputs:

==> default: Executing command "/bin/sed -i -r s/"groups": [$/"groups": [n "TEST_admin",/ /user/chef-repo/data_bags/users/vagrant.json"... ==> default: /bin/sed: -e expression #1, char 47: unterminated `s' command ==> default: Command execution finished. The command "/bin/sed -i -r 's/"groups": [$/"groups": [\n "TEST_admin",/' /user/chef-repo/data_bags/users/vagrant.json" returned a failed exit code.

I did solve the "No such file or directory" error when trying to run the commands in a bash script. Unlike the config.vm.provision command, it turned out that vagrant-triggers doesn't "auto-look" at the current directory so you have to specify a path to your script. So I just needed to modify it to: "./prebootstrap.sh" The sed command with quotes worked fine in the bash script. So I now have a useable solution.

emyl commented 8 years ago

I know it's an old thread, but for the future I suggest you to take a look to the :append_to_path option for temporarily adding a directory to the path.

For better handling quotes, I have some ideas for the next versions of the plugin. Thank you for all the tests and suggestions!