Cron and Ruby.. Does "puts `system command`" do anything? - ruby

Quick question on cron with ruby,
I have a script which runs
puts `tar etc..`
I'm trying to debug why this script isn't tarring up the files like it should..
It works fine when I invoke it manually and i see the tar output too..
Does puts actually do anything when its run in a cron job?
Thanks
Daniel

From the crontab helping page:
If standard output and standard error are not redirected by commands executed from the crontab entry, any generated output or errors shall be mailed, via an implementation-defined method, to the user.
What I usually do for debugging crontabs is creating a Logger:
logfile = File.open('/path/to/log.log', 'rw')
logger = Logger.new(logfile)
logger.debug('something')

if you have the privilege to install gems, you can try minitar, instead of depending on system tar.
require 'zlib'
require 'archive/tar/minitar'
include Archive::Tar
File.open('test.tar', 'wb') do |tarfile|
Archive::Tar::Minitar::Writer.open(tarfile) do |tar|
Dir["file*"].each do |file|
if File.file?(file)
tar.add_file(file, :mode =>0644, :mtime =>Time.now) { |stream, io|
stream.write( File.open(file).read )
}
end
end
end
end

Related

How can we apply shell commands by using puppet providers?

I have my custom puppet provider with property of ensure as below.
....
def create
/* echo 'show system uptime' >> /home/Vinoth/config_vino.txt */
end
def destroy
FileUtils.rm_rf '/home/Vinoth/config_vino.txt'
end
def exists?
File.file? 'config_vino.txt'
end
In the manifest ensure = 'present'. So when the the file config_vino.txt does not exist, I want to create it by using shell command echo. Can anyone suggest how to achieve this? Hope my question is clear and if not please come back.
My aim is to execute shell commands using puppet providers.
Thanks in advance.
In Ruby, there are some ways to execute a shell command. What you actually want to do, though, is the equivalent of this (untested):
def create
uptime = `your uptime command`
Puppet::FileSystem.open(filename, nil, 'w') do |file|
file.write("#{uptime}\n")
end
end

Can't get File Tail working

Out of curiosity I tried file-tail ruby library to see how it works with ruby code. But, the code doesn't seem to be working.
Here is what I tired(logger.rb):
$:.unshift File.dirname(__FILE__)
filename = 'logger.log'
require "file-tail"
File.open(filename) do |log|
log.extend(File::Tail)
log.interval = 10
log.backward(10)
log.tail { |line| puts line }
end
My logger.log file is in the same directory. Now, when I run: $ ruby logger.rb I see the last 10 lines from my log, but when I open logger.log file append some log data to it, the console doesn't show any progress. I mean it doesn't output the new log I appended.
I thought there may be in an issue with this. So, I tried inheriting and including the File::Tail in the inherited class, like this:
$:.unshift File.dirname(__FILE__)
filename = 'logger.log'
require "file-tail"
class FileTail < File
require "file-tail"
include File::Tail
end
log = FileTail.new(filename)
log.interval = 10
log.backward(10)
log.tail { |line| print line }
However this behaves the same way!!
Any pointers?
I am running on MAC OC X 10.8.5 with ruby-2.0.0-p353 installed.
Also, please let me know if anybody has implemented web version of tail in Ruby?
My Bad. This works when I closed all streams of my logger file. I'd opened the file in my ruby code but, didn't close the file stream. Maybe that's why I didn't see any log output on my console using the file-tail.
So, make sure you close all streams of the log/text file you're running with file-tail program.

Ruby Dump all cron jobs to text file

I want a ruby script that will dump all the existing cron jobs to a text file using "crontab -l" or anything else that will achieve the same objective. Also the text file should be possible to use with crontab txtfile to create the cron jobs again.
Below is the code I already wrote:
def dump_pre_cron_jobs(file_path)
begin
cron_list = %x[crontab -l]
if(cron_list.size > 0)
cron_list.each do |crl|
mymethod_that_writes_tofile(file_path, crl) unless crl.chomp.include?("myfilter")
end
end
rescue Exception => e
raise(e.message)
end
end
Why does this need to be a Ruby script?
As you say, you can dump the crontab to a file with crontab -l > crontab.txt.
To read them back in again, simply use crontab crontab.txt, or cat crontab.txt | crontab -
I agree with #Vortura that you do not need to create a Ruby script to do this.
If you really want to, here is a probable way:
File.open('crontab.txt', 'w') do |crontab|
crontab << `crontab -l`
end
NOTE: Running this as root, or using sudo should capture all the cron jobs on a system, not just a single users' jobs. Run it as yourself or as that user and it might capture just those jobs. I haven't test that aspect of it.
Trying to run crontab -l to capture crontab files for all the users and packages seems the indirect way to do the task and could have the hassle of dealing with password requests hanging your code. I'd write code to comb through the directories that store them, rather than mess with prompts. Run the code using sudo and you shouldn't have any problems accessing the files.
Take a look at the discussion at: http://www.linuxquestions.org/questions/linux-newbie-8/etc-crontab-vs-etc-cron-d-vs-var-spool-cron-crontabs-853881/ for information on where the actual cron tab files are stored on disk.
Also https://superuser.com/questions/389116/how-to-recover-crontab-jobs-from-filesystem/389137 has similar information.
Mac OS varies a little from Linux in where Apple puts the cron files. Run man cron at the command-line for the definitive details on either OS.
Here's slightly-tested code for how I'd back up the files. How you restore them is for you to figure out, but it shouldn't be hard to figure out:
require 'fileutils'
BACKUP_PATH = '/path/to/some/safe/storage/directory'
CRONTAB_DIRS = %w[
/usr/lib/cron/tabs
/var/spool/cron
/etc/anacrontab
/etc/cron.d
]
CRONTAB_FILES = %w[
/etc/cron_list
]
def dump_pre_cron_jobs(file_path)
full_backup_path = File.join(
BACKUP_PATH,
File.dirname(file_path)
)
FileUtils.mkdir_p(full_backup_path) unless Dir.exist?(full_backup_path)
File.write(
File.join(
full_backup_path,
file_path
),
File.read(file_path)
)
rescue Exception => e
STDERR.puts e.message
end
CRONTAB_DIRS.each do |ct|
next unless Dir.exist?(ct)
begin
Dir.entries(File.join(ct, '*')).each { |fn| dump_pre_cron_jobs(fn) }
rescue Errno::EACCES => e
STDERR.puts e.message
end
end
CRONTAB_FILES.each do |fn|
dump_pre_cron_jobs(fn)
end
You'll need to run this as root via sudo to access the directories and files as they're usually locked down from unauthorized prying eyes.
The code creates a repository of crontabs, in BACKUP_PATH, based on their original file paths. No changes are made to the file contents so they can be restored as-is by copying them back via cp or writing code to reverse this process.

how to write selenium ruby webdriver test results from Ruby terminal to output files

Currently, I'm running all selenium scripts in my test suite (written by Selenium Ruby Webdriver) at one time by using rake gem in "Start Command Prompt with Ruby" terminal.
To do this I have to create a file with name "rakefile.rb" with below content and just call "rake" in my terminal: (I have known this knowledge based on the guide of a person in my previous post how to export results when running selenium ruby webdriver scripts to output files from command prompt ruby window).
task :default do
$stdout = File.new('console.out', 'w')
$stdout.sync = true
FileList['test*.rb'].each { |file|
begin
ruby file
rescue
puts "The following tests reported unexpected behavior:"
puts "#{file} \n"
end
}
end
However, I do not know how to modify "rakefile.rb" to be able to export the content of executing each failed tests (that being displayed on my Terminal) to each output file ? It means that I expect the content of executing each my script will be written to output files instead of displaying on my Ruby terminal (ex: when I'm running the test script "test_GI-1.rb", then the content of executing this script will be written to an output file "test_GI-1.rb.out" instead of showing in my Terminal.
I modified my "rakefile.rb" to something like ruby file >> test.rb.out, but it does not work at all (this thing only works when I type directly the thing like ruby test.rb >> output.out on my Ruby Terminal). Anybody please guide me a way. Thanks so much.
I have not tried this out, but I guess this should work
task :default do
FileList['test*.rb'].each { |file|
begin
system("ruby #{file} > #{file}.log")
rescue
puts "The following tests reported unexpected behavior:"
puts "#{file} \n"
end
}
end
Based on new requirements -
UPDATE
task :default do
logfile.new("console.out", "w")
FileList['test*.rb'].each { |file|
begin
system("ruby #{file} > #{file}.log")
rescue
logfile.puts("The following tests reported unexpected behavior:")
logfile.puts("#{file} \n")
end
}
end

How to read an open file in Ruby

I want to be able to read a currently open file. The test.rb is sending its output to test.log which I want to be able to read and ultimately send via email.
I am running this using cron:
*/5 * * * /tmp/test.rb > /tmp/log/test.log 2>&1
I have something like this in test.rb:
#!/usr/bin/ruby
def read_file(file_name)
file = File.open(file_name, "r")
data = file.read
file.close
return data
end
puts "Start"
puts read_file("/tmp/log/test.log")
puts "End"
When I run this code, it only gives me this output:
Start
End
I would expect the output to be something like this:
Start
Start (from the reading of the test.log since it should have the word start already)
End
Ok, you're trying to do several things at once, and I suspect you didn't systematically test before moving from one step to the next.
First we're going to clean up your code:
def read_file(file_name)
file = File.open(file_name, "r")
data = file.read
file.close
return data
end
puts "Start"
puts read_file("/tmp/log/test.log")
puts "End"
can be replaced with:
puts "Start"
puts File.read("./test.log")
puts "End"
It's plain and simple; There's no need for a method or anything complicated... yet.
Note that for ease of testing I'm working with a file in the current directory. To put some content in it I'll simply do:
echo "foo" > ./test.log
Running the test code gives me...
Greg:Desktop greg$ ruby test.rb
Start
foo
End
so I know the code is reading and printing correctly.
Now we can test what would go into the crontab, before we deal with its madness:
Greg:Desktop greg$ ruby test.rb > ./test.log
Greg:Desktop greg$
Hmm. No output. Something is broken with that. We knew there was content in the file previously, so what happened?
Greg:Desktop greg$ cat ./test.log
Start
End
Cat'ing the file shows it has the "Start" and "End" output of the code, but the part that should have been read and output is now missing.
What happening is that the shell truncated "test.log" just before it passed control to Ruby, which then opened and executed the code, which opened the now empty file to print it. In other words, you're asking the shell to truncate (empty) it just before you read it.
The fix is to read from a different file than you're going to write to, if you're trying to do something with the contents of it. If you're not trying to do something with its contents then there's no point in reading it with Ruby just to write it to a different file: We have cp and/or mv to do those things for us witout Ruby being involved. So, this makes more sense if we're going to do something with the contents:
ruby test.rb > ./test.log.out
I'll reset the file contents using echo "foo" > ./test.log, and cat'ing it showed 'foo', so I'm ready to try the redirection test again:
Greg:Desktop greg$ ruby test.rb > ./test.log.out
Greg:Desktop greg$ cat test.log.out
Start
foo
End
That time it worked. Trying it again has the same result, so I won't show the results here.
If you're going to email the file you could add that code at this point. Replacing the puts in the puts File.read('./test.log') line with an assignment to a variable will store the file's content:
contents = File.read('./test.log')
Then you can use contents as the body of a email. (And, rather than use Ruby for all of this I'd probably do it using mail or mailx or pipe it directly to sendmail, using the command-line and shell, but that's your call.)
At this point things are in a good position to add the command to crontab, using the same command as used on the command-line. Because it's running in cron, and errors can happen that we'd want to know about, we'd add the 2>&1 redirect to capture STDERR also, just as you did before. Just remember that you can NOT write to the same file you're going to read from or you'll have an empty file to read.
That's enough to get your app working.
class FileLineRead
File.open("file_line_read.txt") do |file|
file.each do |line|
phone_number = line.gsub(/\n/,'')
user = User.find_by_phone_number(line)
user.destroy unless user.nil?
end
end
end
open file
read line
DB Select
DB Update
In the cron job you have already opened and cleared test.log (via redirection) before you have read it in the Ruby script.
Why not do both the read and write in Ruby?
It may be a permissions issue or the file may not exist.
f = File.open("test","r")
puts f.read()
f.close()
The above will read the file test. If the file exists in the current directory
The problem is, as I can see, already solved by Slomojo. I'll only add:
to read and print a text file in Ruby, just:
puts File.read("/tmp/log/test.log")

Resources