How to use special characters in Chef? - ruby

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

Related

fail2ban "command not found" when executing banaction

One of the actions for fail2ban is configured to run a ruby script; however, fail2ban fails when trying to execute the ruby script with a "Command not found" error. I don't understand this error because I'm providing the full path to the ruby script and it has execution permissions:
Here's my fail2ban action:
[root:a17924e746f0:~]# cat /etc/fail2ban/action.d/404.conf
# Fail2Ban action configuration file for Subzero/Core
[Definition]
actionstart =
actionstop =
actioncheck =
actionban = /root/ban_modify.rb ban <ip>
actionunban = /root/ban_modify.rb unban <ip>
Here are the contents to the /root/ban_modify.rb script:
#!/usr/bin/env ruby
command = ARGV[0]
ip_address = ARGV[1]
blacklist = File.open("/root/blacklist.txt").read.split("\n")
if command == "unban"
if blacklist.include? "#{ip_address} deny"
blacklist.delete "#{ip_address} deny"
end
elsif command == "ban"
blacklist << "#{ip_address} deny"
end
File.open("/root/blacklist.txt", "w") {|f| f.write(blacklist.join("\n"))}
Very simple. This blacklist.txt file is used by Apache to permanently ban individuals from the web server when a fail2ban condition is met.
However, when I issue the following command: sudo /usr/bin/fail2ban-client set 404 unbanip <my ip>
I get the following error:
2019-08-19 20:56:43,508 fail2ban.utils [16176]: Level 39 7ff7395873f0 -- exec: ban_modify.rb ban <myip>
2019-08-19 20:56:43,509 fail2ban.utils [16176]: ERROR 7ff7395873f0 -- stderr: '/bin/sh: 1: ban_modify.rb: not found'
2019-08-19 20:56:43,509 fail2ban.utils [16176]: ERROR 7ff7395873f0 -- returned 127
2019-08-19 20:56:43,509 fail2ban.utils [16176]: INFO HINT on 127: "Command not found". Make sure that all commands in 'ban_modify.rb ban <myip>' are in the PATH of fail2ban-server process (grep -a PATH= /proc/`pidof -x fail2ban-server`/environ). You may want to start "fail2ban-server -f" separately, initiate it with "fail2ban-client reload" in another shell session and observe if additional informative error messages appear in the terminals.
2019-08-19 20:56:43,509 fail2ban.actions [16176]: ERROR Failed to execute ban jail '404' action '404' info 'ActionInfo({'ip': '<myip>', 'family': 'inet4', 'ip-rev': '<myip>.', 'ip-host': '<myip>', 'fid': '<myip>', 'failures': 1, 'time': 1566266203.3465006, 'matches': '', 'restored': 0, 'F-*': {'matches': [], 'failures': 1}, 'ipmatches': '', 'ipjailmatches': '', 'ipfailures': 1, 'ipjailfailures': 1})': Error banning <myip>
I'm not sure why this error is happening if the actionban is pointing to the full path of a ruby script.
I even tried changing the contents of /root/ban_modify.rb to just simply puts "Hello World". Tried changing the banaction to iptables-allports and that still failed. It seems like banaction just simply doesn't work.
You can enable fail2ban debug mode & check fail2ban log for more details.
# change fail2ban log level
sudo nano /etc/fail2ban/fail2ban.conf
loglevel = DEBUG
# restart fail2ban
sudo systemctl restart fail2ban
# check logs
tail -f /var/log/fail2ban.log
You can restart the fail2ban and check it again:
sudo systemctl restart fail2ban

shell script echo back fatal error

I am using Elixir's porcelain to invoke shell script, in there I have command like:
#!/usr/bin/env bash
aws s3 sync frontend/dist s3://$S3_BUCKET --delete
echo
Now, if command fails(because of wrong bucket) it displays:
fatal error: An error occurred (InvalidBucketName) when calling the
ListObjects operation: The specified bucket is not valid.
But doesn't return this fatal "fatal error" message back to porcelain. How can I echo this error back?
Edit:
Porcelain code:
Porcelain.shell(". #{Path.join(:code.priv_dir(:hub), "scripts/copy_site_to_s3.sh")}")
I know the possible solution would be to use exec instead of shell but this is more of an example, I have a couple of slightly more complicated but similar shell scripts, facing the same problem.
Another script/example(I am testing failures):
Invoking with:
result = Porcelain.shell(". #{Path.join(:code.priv_dir(:hub),
"scripts/git_clone_pull.sh")} #{github}"
)
IO.inspect result
Script:
if cd frontend; then git reset --hard && git pull; else git clone $1 frontend; fi
It properly fails with:
fatal: Authentication failed for
'https://github.com/x/frontend.git/'
But porcelain result fails to capture message:
%Porcelain.Result{err: nil, out: "", status: 128}
If you’ll check the documentation for Porcelain.{exec,shell}/3 options, you’ll see:
:err — specify the way stderr will be passed back to Elixir.
Possible values are the same as for :out. In addition, it accepts the atom :out which denotes redirecting stderr to stdout.
Caveat: when using Porcelain.Driver.Basic, the only supported values are nil (stderr will be printed to the terminal) and :out.
Emphasis is mine. That caveat might be easily proven in the less cumbersome environment, without involving AWS and any other 3rd parties:
iex|1 ▶ Porcelain.shell("ls --gg", err: {:append, "error.log"})
#⇒ ls: unrecognized option '--gg'
# Try 'ls --help' for more information.
# %Porcelain.Result{err: {:append, "error.log"}, out: "", status: 2}
iex|2 ▶ ls "error.log"
# [ERROR] No such file or directory error.log
But we still have :out option!
iex|3 ▶ Porcelain.shell(">&2 echo 'error'", err: :out)
%Porcelain.Result{err: :out, out: "error\n", status: 0}
iex|4 ▶ Porcelain.shell("ls --gg", err: :out)
%Porcelain.Result{
err: :out,
out: "ls: unrecognized option '--gg'\nTry 'ls --help' for more information.\n",
status: 2
}
Naya, luckily even Basic driver might redirect :err to :out. That said, you have two options:
use err: :out parameter, pattern match to when status > 0 and examine standard output, or:
use Porcelain.Driver.Goon driver and deal with your stderr stream like a profi.

Error while unzipping file on AIX system using CHEF

I want to un zip / un tar a file on AIX system using CHEF.
Steps i have done :
1.I have uploaded a zip file Test.zip on AIX system using Winscp.
2.Edited the default.rb using below command:
execute "extract_Test_tar" do
command "tar -xvf Test.zip"
cwd "/var/chef/cookbooks"
end
3.While uploading my cookbook it is giving me following error:
Recipe: Infy_Patrol::default
* execute[extract_Test_tar] action run
================================================================================
Error executing action `run` on resource 'execute[extract_Test_tar]'
================================================================================
Mixlib::ShellOut::ShellCommandFailed
------------------------------------
Expected process to exit with [0], but received '1'
---- Begin output of tar -xvf Test.zip ----
STDOUT:
STDERR: tar: tape blocksize error
---- End output of tar -xvf Test.zip ----
Ran tar -xvf Test.zip returned 1
Resource Declaration:
---------------------
# In /.chef/local-mode-cache/cache/cookbooks/Infy_Patrol/recipes/default.rb
10: execute "extract_Test_tar" do
11: command "tar -xvf Test.zip"
12: cwd "/var/chef/cookbooks"
13: end
Compiled Resource:
------------------
# Declared in /.chef/local-mode-cache/cache/cookbooks/Infy_Patrol/recipes/default.rb:10:in `from_file'
execute("extract_Test_tar") do
action [:run]
retries 0
retry_delay 2
default_guard_interpreter :execute
command "tar -xvf Test.zip"
backup 5
cwd "/var/chef/cookbooks"
returns 0
declared_type :execute
cookbook_name "Infy_Patrol"
recipe_name "default"
end
Running handlers:
[2016-01-29T06:27:47-06:00] ERROR: Running exception handlers
Running handlers complete
[2016-01-29T06:27:47-06:00] ERROR: Exception handlers complete
Chef Client failed. 0 resources updated in 05 seconds
[2016-01-29T06:27:47-06:00] FATAL: Stacktrace dumped to /.chef/local-mode-cache/cache/chef-stacktrace.out
[2016-01-29T06:27:47-06:00] FATAL: Please provide the contents of the stacktrace.out file if you file a bug report
[2016-01-29T06:27:47-06:00] ERROR: execute[extract_Test_tar] (Infy_Patrol::default line 10) had an error: Mixlib::ShellOut::ShellCommandFailed: Expected process to exit with [0], but received '1'
REPHRASING MY QUESTION.
Below are the steps I followed :
1.Logged into my AIX machine.2.Logged into Winscp.
3.created a cookbook using : knife cookbook create Test
4.Using winscp i went to the path where my cookbook is saved:
/var/chef/cookbooks/Test 5.Opened recipes folder: and edited default.rb as given:
#
# Cookbook Name:: Infy_Patrol
# Recipe:: default
#
# Copyright 2016, YOUR_COMPANY_NAME
#
# All rights reserved - Do Not Redistribute
#
tar_extract '/var/chef/cookbooks/Test.zip' do
action :extract_local
target_dir '/var/chef/cookbooks'
creates '/var/chef/cookbooks/new'
end
#Also tried the following piece of code
#execute "extract files" do
#command "tar xvf Test.tar.gz -C /var/chef/cookbooks"
#end
6.uploaded cookbook using :
chef-client -z -r Test::default
BUT IT IS GIVING ME AN ERROR :
Error executing action `run` on resource 'execute[extract_Test_tar]

Chef:Install windows_feature with guard clause not_if

I'm using Chef 12.4 and using chef-client in local mode. I'm trying to install windows features and detect their current status before I do the installation, or removal. The reason for using the not if, is because when using DISM it takes for ever to check the current state.
Currently I have a server that takes 45 minutes to build and then 20 minutes to run chef even when there is nothing to do.
I used the following Powershell script 'service-check.ps1' to output the status of the package, this is put in place by the recipe itself:
$content = Get-Content .\features.txt
$feature = $args[0]
function grep($f) {
foreach($_ in $content){
$data = $_.split("|")
%{if($($data[0]) -match $f) {return "$($data[1])"}}
}
}
grep $feature
The recipe I'm using writes the 'features.txt' file to the location where Chef is being run, by querying dism for the current features and their status. The recipe file is as follows:
#Check the features and their current state
powershell_script 'installed_features' do
code <<-EOH
dism /online /get-features /format:table > c://chef//features.txt
EOH
end
cookbook_file 'C:\Scripts\service-check.ps1' do
source 'service-check.ps1'
end
windows_feature 'TelnetClient' do
action :remove
only_if {
status = powershell_out("Powershell -f C:\\scripts\\service-check.ps1 TelnetClient").stdout.chop
Disabled != status
}
end
I have tried many different formats in the only_if {} segment, however none of them have worked. I used the example that is here:
http://pdalinis.blogspot.co.uk/2013/09/chef-using-powershell-as-conditional.html
The output I get is:
* windows_feature[TelnetClient] action remove
================================================================================
Error executing action `remove` on resource 'windows_feature[TelnetClient]'
================================================================================
NameError
---------
uninitialized constant Chef::Recipe::Disabled
Resource Declaration:
---------------------
# In C:/chef/local-mode-cache/cache/cookbooks/tester/recipes/default.rb
12: windows_feature 'TelnetClient' do
13: action :remove
14: only_if {
15: status = powershell_out("Powershell -f C:\\scripts\\service-check.ps1 TelnetClient").stdout.chop
16: Disabled != status
17: }
18: end
Compiled Resource:
------------------
# Declared in C:/chef/local-mode-cache/cache/cookbooks/tester/recipes/default.rb:12:in `from_file'
windows_feature("TelnetClient") do
provider LWRP provider windows_feature_dism from cookbook windows
action [:remove]
retries 0
retry_delay 2
default_guard_interpreter :default
declared_type :windows_feature
cookbook_name "tester"
recipe_name "default"
only_if { #code block }
end
I'm a novice at Chef, Ruby and Powershell. I'm assuming that the only_if or not_if are expecting a true or false result, however this seems to be appending the written status that I've added the check against (in this script, disabled).
I have checked the powershell script, it does indeed output Enabed / Disabled depending on the status.
My questions are:
Is it possible to use windows_feature and powershell_out in this way, according to the example it's using powershell_script, but I'd rather use the windows_feature specification to install features.
If it is possible, what am I doing wrong? I have a feeling it might be the output of the script as it seems to insert a space:
" Enabled"
" Disabled"
If it isn't possible, is there another way to do it?
I'd be very grateful for any assistance.
Thank you.
is it possible you just need to quote "Disabled"? Otherwise Ruby is trying to figure out what it is, but doesn't know about any variable or class with that name.

In Chef, why are raised exceptions not rescued?

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.

Resources