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
Related
If I want to run a bunch of ruby scripts (super similar, with maybe a number changed as a commandline argument) and still have them output to stdout, is there a way to do this?
i.e a script to run these:
ruby program1.rb input_1.txt
ruby program1.rb input_2.txt
ruby program1.rb input_3.txt
like
(1..3).each do |i|
ruby program1.rb input_#{i}'
end
in another script, so I can just run that script and see the output in a terminal from all 3 runs?
EDIT:
I'm struggling to implement the second highest voted suggested answer.
I don't have a main function within my program1.rb, whereas the suggested answer has one.
I've tried this, for script.rb:
require "program1.rb"
(1..6).each do |i|
driver("cmd_line_arg_#{i}","cmd_line_arg2")
end
but no luck. Is that right?
You can use load to run the script you need (the difference between load and require is that require will not run the script again if it has already been loaded).
To make each run have different arguments (given that they are read from the ARGV variable), you need to override the ARGV variable:
(1..6).each do |i|
ARGV = ["cmd_line_arg_#{i}","cmd_line_arg2"]
load 'program1.rb'
end
# script_runner.rb
require_relative 'program_1'
module ScriptRunner
class << self
def run
ARGV.each do | file |
SomeClass.new(file).process
end
end
end
end
ScriptRunner.run
.
# programe_1.rb
class SomeClass
attr_reader :file_path
def initialize(file_path)
#file_path = file_path
end
def process
puts File.open(file_path).read
end
end
Doing something like the code shown above would allow you to run:
ruby script_runner.rb input_1.txt input_2.txt input_3.txt
from the command line - useful if your input files change. Or even:
ruby script_runner.rb *.txt
if you want to run it on all text files. Or:
ruby script_runner.rb inputs/*
if you want to run it on all files in a specific dir (in this case called 'inputs').
This assumes whatever is in program_1.rb is not just a block of procedural code and instead provides some object (class) that encapsulates the logic you want to use on each file,meaning you can require program_1.rb once and then use the object it provides as many times as you like, otherwise you'll need to use #load:
# script_runner.rb
module ScriptRunner
class << self
def run
ARGV.each do | file |
load('program_1.rb', file)
end
end
end
end
ScriptRunner.run
.
# program_1.rb
puts File.open(ARGV[0]).read
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.
I want make interactive application where user launches it and can do various task by typing commands (some kind of shell)
example:
./myapp.rb
App says Hi
Commands:
help - display help about command
open - open task
do - do action
Start>help open
open <TaskName>
opens specified task
Start>open Something
Something>do SomeAction
Success!
Something> (blinking cursor here)
I searched but couldn't find any ruby gems that I could use specially for console interaction, so I'm about to my make my own...
I looked at Thor, but that's not exactly as I want, maybe I could use it, but not sure...
it could look something like:
class Tasks
attr_reader :opened_task
desc "open <TaskName>", "opens specified task"
def open(params)
end
desc "do <ActionName>", "do specified action"
def do(params)
end
end
tasks = Tasks.new
# theoretical Console class
console = Console.new
console.addCommand("open",tasks.method(:open),"open task")
console.addCommand("do",tasks.method(:do),"do action")
console.start("%s>",[*tasks.opened_task])
so my question is, what gems I could use to make such console class? maybe someone have already made something similar?
I plan using HighLine for input/output, but any other suggestion what could I use?
What you want is a REPL – Read → Evaluate → Print Loop.
IRB, for example, implements a REPL for the Ruby language.
Here's a very simple implementation of your application's REPL:
loop do
Application::Console.prompt.display
input = gets.chomp
command, *params = input.split /\s/
case command
when /\Ahelp\z/i
puts Application::Console.help_text
when /\Aopen\z/i
Application::Task.open params.first
when /\Ado\z/i
Application::Action.perform *params
else puts 'Invalid command'
end
end
\A and \z match the start of the string and the end of the string, respectively.
You could also try ripl. (from the documentation):
Creating and starting a custom shell is as simple as:
require 'ripl'
# Define plugins, load files, etc...
Ripl.start
There is a comprehensive list of plugins for ripl as well as list of console applications using ripl on the projects website.
ok, so I made this library for creating console applications in ruby. Actually it was some while ago, but only just decided to release it. It does support auto-completion if used with HighLine and Readline.
When I wrote it there wasn't any documentation nor tests/specs, but now I made some. Still not much but for beginning should be ok.
So gem cli-console and
code is at GitHub, here's usage example
TTY is a really good gem for easily doing this sort of things. You have plenty of tools which can work alone or with the full toolKit. You can use colors, prompts, execute shell natives, interact with the screen, print tables, progressbars and many other useful elements of command lines whith the easy of a goop api.
Particularly tty-prompt is really useful for asking for user input.
A brief example for the case you proposed:
require 'tty-prompt'
require 'pastel'
prompt = TTY::Prompt.new
loop do
cmd, parms* = prompt.ask('user#machine$ ').split /\s/
case cmd
when "hola"
puts "Hola amigo " parms
when "exit"
break if prompt.yes?('Do you really want to exit?')
end
end
Take a look at cliqr ruby gem. It looks like exactly what you need. Here is the github link with a descriptive readme: https://github.com/anshulverma/cliqr
It can execute the commands directly or within a inbuilt shell.
Here is a test case from its git repo:
it 'can execute a sub action from shell' do
cli = Cliqr.interface do
name 'my-command'
handler do
puts 'base command executed'
end
action :foo do
handler do
puts 'foo executed'
end
action :bar do
handler do
puts 'bar executed'
end
end
end
end
with_input(['', 'my-command', 'foo', 'foo bar', 'foo bar help']) do
result = cli.execute %w(my-command shell), output: :buffer
expect(result[:stdout]).to eq <<-EOS
Starting shell for command "my-command"
my-command > .
base command executed
my-command > my-command.
base command executed
my-command > foo.
foo executed
my-command > foo bar.
bar executed
my-command > foo bar help.
my-command foo bar
USAGE:
my-command foo bar [actions] [options] [arguments]
Available options:
--help, -h : Get helpful information for action "my-command foo bar" along with its usage information.
Available actions:
[ Type "my-command foo bar help [action-name]" to get more information about that action ]
help -- The help action for command "my-command foo bar" which provides details and usage information on how to use the command.
my-command > exit.
shell exited with code 0
EOS
end
end
class MyAPI
def self.__is__(text)
#__is__ = text
end
def self.method_added(method)
#__help__ ||= {}
#__help__[method.to_s] = #__is__
#__is__ = nil
end
def self.help(of)
#__help__[of]
end
__is__ "open file <file>"
def open(file)
#...
end
__is__ "do X"
def do(*params)
#...
end
__is__ "calls help, use help <command>"
def help(*args, &block)
self.class.help(*args, &block)
end
end
MyAPI.new(...).pry
Or you could use pry commands, but that defeats the
turing-completeness. Help might be implemented using commands, as I'm
not sure how well my approach works out. Those methods need to be
coded defensive. I can't remember how to use class variables :-/
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
I need an interactive environment to play with some algorithm stuff. I want to be able to view what's been defined (data, function) so far and be able save/load so I can continue from a previous saved snapshot if something went wrong. Since I chose ruby as my main scripting language, I hope it had these features built in.
If ruby interactive mode does not provide these functionality, what else you recommend for that?
Thanks
So here’s a technique that will append commands entered in your IRB session to a file in your home directory (idea from ruby-talk:58931). Put the following in your .irbrc:
module Readline
module History
LOG = "#{ENV['HOME']}/.irb-history"
def self.write_log(line)
File.open(LOG, 'ab') {|f| f << "#{line}
"}
end
def self.start_session_log
write_log("
# session start: #{Time.now}
")
at_exit { write_log("
# session stop: #{Time.now}
") }
end
end
alias :old_readline :readline
def readline(*args)
ln = old_readline(*args)
begin
History.write_log(ln)
rescue
end
ln
end
end
Readline::History.start_session_log
You should check out the sketches gem which let's you prototype code in a temporary file in your preferred editor. I don't think it supports snapshots.
In irb I would use it as follows:
>> sketch
# Write some code in an editor ...
# Lists sketches and their code
>> sketches
# Reopens the first sketch from above
>> sketch 1
If you want a more powerful interactive prototyping environment, see boson.