In Chef, why are raised exceptions not rescued? - ruby

In Chef, Why does this code not catch the thrown exception in the bash resource? If I run this code, I never ever get to the python resource even when the exception is thrown. The error is expected, which is why I'm catching it, and then going over to pymongo and fixing it that way.
begin
bash "mongo fix" do
code "mongo --verbose #{filename}"
action :run
end
rescue
python 'pymongo reconfig' do
code "Pymongo does a catch and reconfig"
end
end
And this is the exception output
[2013-03-05T20:03:55+00:00] FATAL: Mixlib::ShellOut::ShellCommandFailed: bash[mongo fix (noudata::mongo line 77) had an error: Mixlib::ShellOut::ShellCommandFailed: Expected process to exit with [0], but received '253'
---- Begin output of "bash" "/tmp/chef-script20130305-3916-14xxhn5-0" ----
STDOUT: MongoDB shell version: 2.2.3
Tue Mar 5 20:03:55 versionCmpTest passed
Tue Mar 5 20:03:55 versionArrayTest passed
connecting to: test
Tue Mar 5 20:03:55 creating new connection to:127.0.0.1:27017
Tue Mar 5 20:03:55 BackgroundJob starting: ConnectBG
Tue Mar 5 20:03:55 connected connection!
true
{
"errmsg" : "replSetReconfig command must be sent to the current replica set primary.",
"ok" : 0
}
Tue Mar 5 20:03:55 uncaught exception: [object bson_object]
failed to load: /tmp/test.js
STDERR:
---- End output of "bash" "/tmp/chef-script20130305-3916-14xxhn5-0" ----
Ran "bash" "/tmp/chef-script20130305-3916-14xxhn5-0" returned 253

The code in the begin block makes an instance of a Chef::Resource::Bash resource, assigns the resource's code and action attributes, and adds the resource to run_context.resource_collection. The resource is not "run" in any sense. Making an instance of the resource does not raise any exceptions, so the code in the rescue block is not run.
Later on, once all of your recipe code has finished running, Chef will loop over the resources in the run_context.resource_collection. For each resource, Chef will run the resource's actions. In the case of a bash resource, that means running the string given in the resource's code attribute. Notice that this happens well after your recipe and all other recipes have finished running, and so this happens well outside of your begin block. Any exceptions raised by this resource when its actions are run do not propagate to your begin block, because the actions are not called from within your begin block, but from well after it.
You can try something like this:
bash "mongo fix" do
code "mongo --verbose #{filename} || python pymongo reconfig"
end

Put your code in definition and call definition from the recipe.

Related

Systemctl bash variable

I'm trying to get this variable work, but I'm getting always an error about systemd-escape. Although I escape the special character, the variable is not working:
status="systemctl status syslog-ng | grep Active: | sed 's/.*: //' | sed 's/since.*//g'"
The result I'm getting is here:
Invalid unit name "|" was escaped as "\x7c" (maybe you should use systemd-escape?)
Invalid unit name "|" was escaped as "\x7c" (maybe you should use systemd-escape?)
Invalid unit name "'s/.*:" was escaped as "\x27s-.*:" (maybe you should use systemd-escape?)
Invalid unit name "|" was escaped as "\x7c" (maybe you should use systemd-escape?)
Invalid unit name "'s/since.*//g'" was escaped as "\x27s-since.*--g\x27" (maybe you should use systemd-escape?)
Unit \x7c.service could not be found.
Unit grep.service could not be found.
Unit Active:.service could not be found.
Unit \x7c.service could not be found.
Unit sed.service could not be found.
Unit \x27.mount could not be found.
Unit \x7c.service could not be found.
Unit sed.service could not be found.
● syslog-ng.service - System Logger Daemon
Loaded: loaded (/usr/lib/systemd/system/syslog-ng.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2021-10-11 14:01:23 CEST; 26min ago
Docs: man:syslog-ng(8)
Main PID: 3020944 (syslog-ng)
Tasks: 3 (limit: 101081)
Memory: 8.9M
CGroup: /system.slice/syslog-ng.service
└─3020944 /usr/sbin/syslog-ng -F -p /var/run/syslogd.pid
Oct 11 14:01:23 syslog-ng systemd[1]: Starting System Logger Daemon...
Oct 11 14:01:23 syslog-ng syslog-ng[3020944]: [2021-10-11T14:01:23.798405] Plugin module not found in 'module-path'; module-path='/usr/lib64/syslog-ng'>
Oct 11 14:01:23 syslog-ng syslog-ng[3020944]: [2021-10-11T14:01:23.801271] Plugin module not found in 'module-path'; module-path='/usr/lib64/syslog-ng'>
Oct 11 14:01:23 syslog-ng syslog-ng[3020944]: [2021-10-11T14:01:23.801828] Plugin module not found in 'module-path'; module-path='/usr/lib64/syslog-ng'>
Oct 11 14:01:23 syslog-ng syslog-ng[3020944]: [2021-10-11T14:01:23.808340] WARNING: With use-dns(no), dns-cache() will be forced to 'no' too!;
Oct 11 14:01:23 syslog-ng systemd[1]: Started System Logger Daemon.
I just want to have the status of my syslog-ng as a variable
We suggest to follow systemd service unit definition documentation.
As stated in the Command lines section.
This syntax is inspired by shell syntax, but only the meta-characters and expansions described in the following paragraphs are understood, and the expansion of variables is different. Specifically, redirection using "<", "<<", ">", and ">>", pipes using "|", running programs in the background using "&", and other elements of shell syntax are not supported.
We cannot assume bash nor sh syntax/rules writing systemd service unit.
Environment variables are better defined statically.
In case you need to store values in dynamic variables. We suggest create a script service-unit-xyx.bash that executes all the required assignments and eventually run the target service.
Using a single script service-unit-xyx.bash you can easily log and debug every line.
Eventually execute service-unit-xyx.bash script with full path in ExecStart= command.
Using execution script service-unit-xyx.bash also simplify the service unit development, from systemd service unit file to bash/sh script development.
It is also possible to use a ExecStartPre=, ExecStartPost= commands to control service runtime environments.
Read and follow sample service units from the internet.
All commands/scripts should specify absolute path reference.

Running awesome-client from a script executing as root

Running Awesome on Debian (11) testing
awesome v4.3 (Too long)
• Compiled against Lua 5.3.3 (running with Lua 5.3)
• D-Bus support: ✔
• execinfo support: ✔
• xcb-randr version: 1.6
• LGI version: 0.9.2
I'm trying to signal to Awesome when systemd triggers suspend. After fiddling with D-Bus directly for awhile and getting nowhere, I wrote a couple of functions that somewhat duplicate the functionality of signals.
I tested it by running the following command in a shell, inside of my Awesome session:
$ awesome-client 'require("lib.syskit").signal("awesome-client", "Hello world!")'
This runs just fine. A notification posts to the desktop "Hello world!" as expected. I added the path to my lib.syskit code to the $LUA_PATH in my ~/.xsessionrc. Given the error described below, I doubt this is an issue.
Now for the more difficult part. I put the following in a script located at /lib/systemd/system-sleep/pre-suspend.sh
#!/bin/bash
if [ "${1}" == "pre" ]; then
ERR=$(export DISPLAY=":0"; sudo -u naddan awesome-client 'require("lib.syskit").signal("awesome-client", "pre-suspend")' 2>&1)
echo "suspending at `date`, ${ERR}" > /tmp/systemd_suspend_test
elif [ "${1}" == "post" ]; then
ERR=$(export DISPLAY=":0"; sudo -u naddan awesome-client 'require("lib.syskit").signal("awesome-client", "post-suspend")' 2>&1)
echo "resuming at `date`, ${ERR}" >> /tmp/systemd_suspend_test
fi
Here's the output written to /tmp/systemd_suspend_test
suspending at Thu 22 Jul 2021 10:58:01 PM MDT, Failed to open connection to "session" message bus: /usr/bin/dbus-launch terminated abnormally without any error message
E: dbus-send failed.
resuming at Thu 22 Jul 2021 10:58:05 PM MDT, Failed to open connection to "session" message bus: /usr/bin/dbus-launch terminated abnormally without any error message
E: dbus-send failed.
Given that I'm already telling it the $DISPLAY that Awesome is running under (this is a laptop), and that I'm running awesome-client as my user, not root, what else am I missing that's keeping this from working?
Is there a better way that I could achieve telling Awesome when the system suspends?
awesome-client is a shell script. It is a thin wrapper around dbus-send. Thus, since you write "After fiddling with D-Bus directly for awhile and getting nowhere", I guess the same reasoning applies.
Given that I'm already telling it the $DISPLAY that Awesome is running under (this is a laptop), and that I'm running awesome-client as my user, not root, what else am I missing that's keeping this from working?
You are missing the address of the dbus session bus. For me, it is:
$ env | grep DBUS
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
Is there a better way that I could achieve telling Awesome when the system suspends?
Instead of sending a message directly to awesome via some script, you could use the existing mechanism for this: Dbus signals. These are broadcasts that interested parties can listen to.
Google suggests that there is already a PrepareForSleep signal:
https://serverfault.com/questions/573379/system-suspend-dbus-upower-signals-are-not-seen
Based on this, Google then gave me the following AwesomeWM lua code that listens for logind's PrepareForSleep signal (written by yours truely - thanks Google for finding that!):
https://github.com/awesomeWM/awesome/issues/344#issuecomment-328354719
local lgi = require("lgi")
local Gio = lgi.require("Gio")
local function listen_to_signals()
local bus = lgi.Gio.bus_get_sync(Gio.BusType.SYSTEM)
local sender = "org.freedesktop.login1"
local interface = "org.freedesktop.login1.Manager"
local object = "/org/freedesktop/login1"
local member = "PrepareForSleep"
bus:signal_subscribe(sender, interface, member, object, nil, Gio.DBusSignalFlags.NONE,
function(bus, sender, object, interface, signal, params)
-- "signals are sent right before (with the argument True) and
-- after (with the argument False) the system goes down for
-- reboot/poweroff, resp. suspend/hibernate."
if not params[1] then
-- This code is run before suspend. You can replace the following with something else.
require("gears.timer").start_new(2, function()
mytextclock:force_update()
end)
end
end)
end
listen_to_signals()

Does $argv behave the same between Centos and RHEL systems

I am trying to troubleshoot an old TCL accounting script called GOTS - Grant Of The System. What it does is creates a time stamped logfile entry for each user login and another for the logout. The problem is it is not creating the second log file entry on logout. I think I tracked down the area where it is going wrong and I have attached it here. FYI the log file exists and it does not exit with the error "GOTS was called incorrectly!!". It should be executing the if then for [string match "$argv" "end_session"]
This software runs properly on RHEL Linux 6.9 but fails as described on Centos 7. I am thinking that there is a system variable or difference in the $argv argument vector for the different systems that creates this behavior.
Am I correct in suspecting $argv and if not does anyone see the true problem?
How do I print or display the $argv values on logout?
# Find out if we're beginning or ending a session
if { [string match "$argv" "end_session"] } {
if { ![file writable $Log] } {
onErrorNotify "4 LOG"
}
set ifd [open $Log a]
puts $ifd "[clock format [clock seconds]]\t$Instrument\t$LogName\t$GroupName"
close $ifd
unset ifd
exit 0
} elseif { [string match "$argv" "begin_session"] == 0 } {
puts stderr "GOTS was called incorrectly!!"
exit -1
}
end_session is populated by the /etc/gdm/PostSession/Default file
#!/bin/sh
### Begin GOTS PostSession
# Do not run GOTS if root is logging out
if test "${USER}" == "root" ; then
exit 0
fi
/usr/local/lib/GOTS/gots end_session > /var/tmp/gots_postsession.log 2> /var/tmp/gots_postsession.log
exit 0
### End GOTS PostSession
This is the postsession log file:
Application initialization failed: couldn't connect to display ":1"
Error in startup script: invalid command name "option"
while executing
"option add *Font "-adobe-new century schoolbook-medium-r-*-*-*-140-*-*-*-*-*-*""
(file "/usr/local/lib/GOTS/gots" line 26)
After a lot of troubleshooting we have determined that for whatever reason Centos is not allowing part of the /etc/gdm/PostSession/default file to execute:
fi
/usr/local/lib/GOTS/gots end_session
But it does update the PostSession.log file as it should .. . Does anyone have any idea what could be interfering with only part of the PostSession/default?
Does anyone have any idea what could be interfereing with PostSession/default?
Could it be that you are hitting Bug 851769?
That said, am I correct in stating that, as your investigation shows, this is not a Tcl-related issue or question anymore?
So it turns out that our script has certain elements that depend upon the Xserver running on logout to display some of the GUI error messages. This from:
Gnome Configuration
"When a user terminates their session, GDM will run the PostSession script. Note that the Xserver will have been stopped by the time this script is run, so it should not be accessed.
Note that the PostSession script will be run even when the display fails to respond due to an I/O error or similar. Thus, there is no guarantee that X applications will work during script execution."
We are having to rewrite those error message callouts so they simply write the errors to a file instead of depending on the display. The errors are for things that should be there in the beginning anyway.

How to use special characters in Chef?

I am writing Chef recipes using chef-solo, where I need to run commands which include + but Chef returns an error if I use the + character.
bash "testing" do
code <<-EOH
/bin/grep '^+:' /etc/shadow >>/var/info
EOH
end
Method 1: put code in any script.sh file and use it as:
execute " script running " do
command "sh /path/script.sh"
end
but I don't want to use it. Is there any other way to use special characters?
Note: I tried using back-slash ("\").
update : got below error when i use code
bash "testing" do
code "/bin/grep '^+:' /etc/shadow >>/var/info"
end
Error:
chef-solo -c solo.rb -j web.json
Starting Chef Client, version 11.8.2
Compiling Cookbooks...
Converging 1 resources
Recipe: test::test
* bash[testing] action run
================================================================================
Error executing action `run` on resource 'bash[testing]'
================================================================================
Mixlib::ShellOut::ShellCommandFailed
------------------------------------
Expected process to exit with [0], but received '1'
---- Begin output of "bash" "/tmp/chef-script20150822-12224-kbivpd" ----
STDOUT:
STDERR:
---- End output of "bash" "/tmp/chef-script20150822-12224-kbivpd" ----
Ran "bash" "/tmp/chef-script20150822-12224-kbivpd" returned 1
Resource Declaration:
---------------------
# In /home/new/cookbooks/test/recipes/test.rb
1: bash "testing" do
2: code "/bin/grep '^+:' /etc/shadow >>/var/info"
3: end
Compiled Resource:
------------------
# Declared in /home/new/cookbooks/test/recipes/test.rb:1:in `from_file'
bash("testing") do
action "run"
retries 0
retry_delay 2
command "\"bash\" \"/tmp/chef-script20150822-12224-kbivpd\""
backup 5
returns 0
code "/bin/grep '^+:' /etc/shadow >>/var/info"
interpreter "bash"
cookbook_name :test
recipe_name "test"
end
[2015-08-22T19:49:52+05:30] ERROR: Running exception handlers
[2015-08-22T19:49:52+05:30] ERROR: Exception handlers complete
[2015-08-22T19:49:52+05:30] FATAL: Stacktrace dumped to /home/chef-solo/chef-stacktrace.out
Chef Client failed. 0 resources updated
[2015-08-22T19:49:52+05:30] ERROR: bash[testing] (test::test line 1) had an error: Mixlib::ShellOut::ShellCommandFailed: Expected process to exit with [0], but received '1'
---- Begin output of "bash" "/tmp/chef-script20150822-12224-kbivpd" ----
STDOUT:
STDERR:
---- End output of "bash" "/tmp/chef-script20150822-12224-kbivpd" ----
Ran "bash" "/tmp/chef-script20150822-12224-kbivpd" returned 1
[2015-08-22T19:49:52+05:30] FATAL: Chef::Exceptions::ChildConvergeError: Chef run process exited unsuccessfully (exit code 1)
This has nothing to do with the + in the command !
There's nothing wrong, chef works as expected:
# grep '^+' /etc/shadow; echo $?
1
This command returns a status code of 1 as nothing is found (quote of man grep emphasis is mine):
EXIT STATUS
The exit status is 0 if selected lines are found, and 1 if not found. If an error occurred the exit status is 2. (Note: POSIX
error handling
code should check for '2' or greater.)
And chef tell's you exactly this:
Expected process to exit with [0], but received '1'
Reading the bash resource documentation we see there's a returns attribute with this description:
returns Ruby Types: Integer, Array
The return value for a command. This may be an array of accepted
values. An exception is raised when the return value(s) do not match.
Default value: 0.
So if you want to accept this command return 0 or 1:
bash "testing" do
code "/bin/grep '^+:' /etc/shadow >>/var/info"
return [0,1]
end
So this may not solve your problem as you didn't describe what you're trying to achieve, we're on a XY problem here
Chef recipes are pure ruby, so you can write something like this without any problems:
bash "testing" do
code "/bin/grep '^+:' /etc/shadow >>/var/info"
end
If you need to use double quotes inside your command, you can escape it with back slash "\".
i solved my problem using
`/bin/grep '^+:' /etc/passwd >> /var/output`
this is ruby method to execute system command using backticks in which global variable $? is set through the backticks automatically

cloud-init per-boot script on ubuntu ec2-instance

I am trying to start a script with cloud-init on a ubuntu 11.10 ec2 instance.
I put the script script.sh in the folder /var/lib/cloud/scripts/per-boot.
Content of script.sh is simple:
#/!/bin/sh
echo "test"
After a reboot, I get the following error:
run-parts: failed to exec /var/lib/cloud/scripts/per-boot/script.sh: Exec format error
run-parts: /var/lib/cloud/scripts/per-boot/script.sh exited with return code 1
2012-04-14 19:10:52,642 - cc_scripts_per_boot.py[WARNING]: failed to run-parts in /var/lib/cloud/scripts/per-boot
2012-04-14 19:10:52,648 - __init__.py[WARNING]: Traceback (most recent call last):
File "/usr/lib/python2.7/dist-packages/cloudinit/CloudConfig/__init__.py", line 108, in run_cc_modules
cc.handle(name, run_args, freq=freq)
File "/usr/lib/python2.7/dist-packages/cloudinit/CloudConfig/__init__.py", line 72, in handle
[ name, self.cfg, self.cloud, cloudinit.log, args ])
File "/usr/lib/python2.7/dist-packages/cloudinit/__init__.py", line 309, in sem_and_run
func(*args)
File "/usr/lib/python2.7/dist-packages/cloudinit/CloudConfig/cc_scripts_per_boot.py", line 27, in handle
util.runparts(runparts_path)
File "/usr/lib/python2.7/dist-packages/cloudinit/util.py", line 140, in runparts
raise subprocess.CalledProcessError(sp.returncode,cmd)
CalledProcessError: Command '['run-parts', '--regex', '.*', '/var/lib/cloud/scripts/per-boot']' returned non-zero exit status 1
2012-04-14 19:10:52,648 - __init__.py[ERROR]: config handling of scripts-per-boot, None, [] failed
cloud-init boot finished at Sat, 14 Apr 2012 19:10:52 +0000. Up 3.70 seconds
2012-04-14 19:10:52,672 - cloud-init-cfg[ERROR]: errors running cloud_config [final]: ['scripts-per-boot']
errors running cloud_config [final]: ['scripts-per-boot']
Any ideas how to fix it?
I believe your problem is related to the fact that #/!/bin/sh is not a valid input type. Need to remove the / after the #.
#!/bin/sh
echo "test"
Let me know if you still see the problems after this.

Resources