Declaring Ruby Methods along with a menu - ruby

I've been fooling around with Ruby lately, so i decided to write an sftp client.
require 'net/sftp'
require 'ostruct'
require 'optparse'
class Sftp
def parse(arguments)
ARGV << "-h" if ARGV.empty?
#options = OpenStruct.new
args = OptionParser.new do |args|
args.banner = "Usage: #{__FILE__} [options]"
args.on("--host HOST", String,
) do |host|
#options.host = host
end
args.on("--username USERNAME", String,
) do |username|
#options.username = username
end
args.on("--password PASSWORD", String,
) do |password|
#options.password = password
end
args.on("--port=PORT", Integer,
) do |port|
#options.port = port
end
args.on("--mkdir=MAKE DIRECTORY", String,
) do |mkdir|
#options.mkdir = mkdir
end
args.on("--rmdir=REMOVE DIRECTORY", String,
) do |rmdir|
#options.rmdir = rmdir
end
args.on("-h", "--help", "Show help and exit") do
puts args
exit
end
end
begin
args.parse!(arguments)
rescue OptionParser::MissingArgument => error
puts "[!] ".red + error.message.bold
exit
rescue OptionParser::InvalidOption => error
puts "[!] ".red + error.message.bold
exit
end
def connect
Net::SFTP.start(#options.host, #options.username, :password => #options.password, :port => #options.port) do |sftp|
sftp.mkdir(#options.mkdir)
puts "Creating Directory: #{#options.mkdir}"
sftp.rmdir(#options.rmdir)
puts "Deleting Directory: #{#options.rmdir}"
end
end
end
def run(arguments)
parse(arguments)
connect
end
end
sftp = Sftp.new
sftp.run(ARGV)
I want these two commands to be separated. For example when i pass
the argument mkdir I just want only this to run and if I want to run rmdir again I just wanna run only this command.
It has to do with methods, but I can't find a proper solution. And I'm really rusty.
Any recommendation?

A very simple approach could be to check if the required value is set before running the command, and skip the command if the value is not set.
def connect
Net::SFTP.start(#options.host, #options.username, password: #options.password, port: #options.port) do |sftp|
if #options.mkdir
sftp.mkdir(#options.mkdir)
puts "Creating Directory: #{#options.mkdir}"
end
if #options.rmdir
sftp.rmdir(#options.rmdir)
puts "Deleting Directory: #{#options.rmdir}"
end
end
end

Related

Ruby: creating a case statement that checks csv file for string to authenticate user (terminal only)

I apologies if this is simple but I'm just starting out. Any constructive help welcome.
Problem:
Trying to create authentication from ruby terminal to CSV.
I'd like to create clean (and as short as possible) loop statement that goes to csv file checks the top row for header "pin" and then checks the gets.chomp entry against that to authenticate.
require 'csv'
class Menu
def self.login
system "clear"
puts "Welcome to Hip-Bikes & Coffee"
puts "Please login with your pin:"
print "> "
customer_pin = gets.chomp
verified = authentication(customer_pin)
end
def self.authentication(customer_pin)
case
when CSV.foreach('customers.csv', headers: true) { |row| ["pin"] == login.verified }
puts verified
else
puts "login failed. Please try again in 3 seconds..."
sleep(3.0)
self.login
This should work for you
UPD
require 'csv'
class Menu
class << self
def login
login_start
verified(gets.chomp)
end
def verified(input)
if authentication(input)
puts 'verified'
else
failed
end
end
def authentication(customer_pin)
CSV.foreach('customers.csv', headers: true).any? { |row| row['pin'] == customer_pin }
end
def failed
puts "login failed. Please try again in 3 seconds..."
sleep(3.0)
login
end
def login_start
system "clear"
print "Welcome to Hip-Bikes & Coffee\nPlease login with your pin:\n> "
end
end
end

How to use optparse to have a flags argument require another argument

I have a tool that I'm updating and need to have an argument require another argument, for example:
require 'optparse'
OPTIONS = {}
OptionParser.new do |opts|
opts.on('-t', '--type INPUT', String, 'Verify a type'){ |o| OPTIONS[:type] = o }
end.parse!
def help_page
puts 'ruby test.rb -t dev'
end
def gather_type
case OPTIONS[:type]
when /dev/
unlock(OPTIONS[:type])
else
help_page
end
end
def unlock(type)
if type == 'unlock' #Find out what type by passing argument another argument
puts 'Unlock account'
else
puts 'Reset account'
end
end
def start
case
when OPTIONS[:type]
gather_type
else
help_page
end
end
start
When this is run you get the following:
C:\Users\bin\ruby>ruby test.rb -t dev=unlock
Reset account
C:\Users\bin\ruby>ruby test.rb -t dev=reset
Reset account
Now that's all well and dandy but what I want to do is give the dev part an argument and go from there to decide if it's an unlock or if it's a reset:
ruby test.rb -t dev=unlock OR ruby test.rb -t dev=reset
After that I want the unlock(type) method to determine what argument was given to the flags argument and output the correct information, so
C:\Users\bin\ruby>ruby test.rb -t dev=unlock
Unlock account
C:\Users\bin\ruby>ruby test.rb -t dev=reset
Reset account
How can I go about to determine if an argument was given to the argument of the flag?
I figured out that if you put an options in parenthesis you can get what I'm asking:
require 'optparse'
OPTIONS = {}
OptionParser.new do |opts|
opts.on('-t', '--type INPUT[=INPUT]', String, 'Verify a type'){ |o| OPTIONS[:type] = o }
end.parse!
def help_page
puts 'ruby test.rb -t dev'
end
def gather_type
case OPTIONS[:type]
when /dev/
unlock(OPTIONS[:type])
else
help_page
end
end
def unlock(type)
if type =~ /unlock/ #Find out what type by passing argument another argument
puts 'Unlock account'
elsif type =~ /reset/
puts 'Reset account'
else
puts 'No flag given defaulting to unlock'
end
end
def start
case
when OPTIONS[:type]
gather_type
else
help_page
end
end
start
C:\Users\bin\ruby>ruby test.rb -t dev
No flag given defaulting to unlock
C:\Users\bin\ruby>ruby test.rb -t dev=unlock
Unlock account
C:\Users\bin\ruby>ruby test.rb -t dev=reset
Reset account

Implemeting amazon Simple nodification service in RUBY

Am trying to implement amazon SNS using ruby.
I want to create a topic,delete a topic,subscribe to a topic,publish to a topic.These are included in the following code.
#!/usr/bin/env ruby
require 'rubygems'
require 'aws-sdk'
AWS.config(:access_key_id => 'BT62W53Q', :secret_access_key => '0Edwg')
#sns=AWS::SNS.new
#D requirements
alpha = #sns.topics.create('CSC470Test-Alpha')
#sns.topics.create('CSC470Test-Beta')
temp=gets
#sns.topics.each do |topic|
puts topic.name
if(topic.name=='CSC470Test-Beta')
topic.delete
end
end
puts
puts 'Beta now deleted.'
puts
#sns.topics.each do |topic|
puts topic.name
end
puts
temp=gets
puts
#C requirements
#sns.topics.each do |topic|
if(topic.name=='CSC470Test-Alpha')
subbed1=false
subbed2=false
subbed3=false
topic.subscriptions.each do |sub|
if(sub.endpoint=='sn#aine.com')
subbed1=true;
end
if(sub.endpoint=='pran#aine.com')
subbed2=true;
end
if(sub.endpoint=='http://cloud.comtor.org/csc470logger/logger')
subbed3=true;
end
end
if(!subbed1)
puts 'Subscribed sika.'
topic.subscribe('sn#aine.com')
end
if(!subbed2)
puts 'Subscribed prka'
topic.subscribe('pran#aine.com', :json => true)
end
if(!subbed3)
puts 'Subscribed comtor site.'
topic.subscribe('http://cloud.comtor.org/csc470logger/logger')
end
end
end
temp=gets
puts 'Topics with info:'
#sns.topics.each do |topic|
puts
puts 'Arn'
puts topic.arn
puts 'Owner'
puts topic.owner
puts 'Policy'
puts topic.policy
puts 'Name'
puts topic.display_name
puts 'Confirmed Subscriptions:'
puts topic.subscriptions.
select{ |s| s.arn != 'PendingConfirmation' }.
map(&:endpoint)
# if(subs.confirmation_authenticated?)
# puts 'Arn: ' + subs.arn
# puts 'Endpoint: ' + subs.endpoint
# puts 'Protocol: ' + subs.protocol
# end
end
puts
temp=gets
#sns.subscriptions.each do |subs|
puts "SubscriptionARN: #{ subs.arn} "
puts "TopicARN: #{subs.topic_arn} "
puts "Owner: #{subs.owner_id} "
puts "Delivery Policy: #{ subs.delivery_policy_json} "
end
while running this code in rails console. iam getting this error
C:/ProgramData/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/aws-sdk-1.8.5/l
ib/aws/core/client.rb:339:in `return_or_raise': The request signature we calcula
ted does not match the signature you provided. Check your AWS Secret Access Key
and signing method. Consult the service documentation for details. (AWS::SNS::Er
rors::SignatureDoesNotMatch)
from C:/ProgramData/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/aw
s-sdk-1.8.5/lib/aws/core/client.rb:440:in `client_request'
from (eval):3:in `create_topic'
from C:/ProgramData/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/aw
s-sdk-1.8.5/lib/aws/sns/topic_collection.rb:24:in `create'

AuthenticationFailed net-ssh ruby

When I'm trying to Net::SSH.start to my debian ssh server and transfer a files, every time I've a very strange error message - `start': Net::SSH::AuthenticationFailed, but all the authentication data are correct, I don't know what a problem is. Does anyone faced same problem?
The code was written on ruby and net/ssh module are in use, here is a code:
require 'rubygems'
require 'net/ssh'
def copy_file(session, source_path, destination_path=nil)
destination_path ||= source_path
cmd = %{cat > "#{destination_path.gsub('"', '\"')}"}
session.process.popen3(cmd) do |i, o, e|
puts "Copying #{source_path} to #{destination_path}... "
open(source_path) { |f| i.write(f.read) }
puts 'Done.'
end
end
Net::SSH.start("192.168.112.129",
:username=>'username',
:password=>'password') do |session|
copy_file(session, 'D:/test/1.txt')
copy_file(session, '/home/timur/Documents/new_file.rb"')
end
There is no :username option in net/ssh 2.6, you can set it like parameter:
Net::SSH.start('192.168.112.129', 'username', password: 'password') do |ssh|
foo
end

How to get exit status with Ruby's Net::SSH library?

I have a snippet of code, simply trying to execute a script on a remote server, in the event that it fails, I'd like to make a follow-up call, imagine this:
require 'rubygems'
require 'net/ssh'
require 'etc'
server = 'localhost'
Net::SSH.start(server, Etc.getlogin) do |ssh|
puts (ssh.exec("true") ? 'Exit Success' : "Exit Failure")
puts (ssh.exec("false") ? 'Exit Success' : "Exit Failure")
end
I would expect (ignoring that stdout and stderr are printed in my contrived example) - but first line should exit with 0 which I would expect Ruby would interperate as false and display "Exit Failure" (sure, so the logic is wrong, the ternary needs to be flipped) - but the second line should exit with the opposite status, and it doesn't.
I can't even find anything in the documentation about how to do this, and I'm a little worried that I might be doing it wrong?!
I find the following way of running processes with Net::SSH much more useful. It provides you with distinct stdout and stderr, exit code and exit signal.
require 'rubygems'
require 'net/ssh'
require 'etc'
server = 'localhost'
def ssh_exec!(ssh, command)
stdout_data = ""
stderr_data = ""
exit_code = nil
exit_signal = nil
ssh.open_channel do |channel|
channel.exec(command) do |ch, success|
unless success
abort "FAILED: couldn't execute command (ssh.channel.exec)"
end
channel.on_data do |ch,data|
stdout_data+=data
end
channel.on_extended_data do |ch,type,data|
stderr_data+=data
end
channel.on_request("exit-status") do |ch,data|
exit_code = data.read_long
end
channel.on_request("exit-signal") do |ch, data|
exit_signal = data.read_long
end
end
end
ssh.loop
[stdout_data, stderr_data, exit_code, exit_signal]
end
Net::SSH.start(server, Etc.getlogin) do |ssh|
puts ssh_exec!(ssh, "true").inspect
# => ["", "", 0, nil]
puts ssh_exec!(ssh, "false").inspect
# => ["", "", 1, nil]
end
Hope this helps.
Building on the answer by flitzwald - I've monkey patched my version of this into Net::SSH (Ruby 1.9+)
class Net::SSH::Connection::Session
class CommandFailed < StandardError
end
class CommandExecutionFailed < StandardError
end
def exec_sc!(command)
stdout_data,stderr_data = "",""
exit_code,exit_signal = nil,nil
self.open_channel do |channel|
channel.exec(command) do |_, success|
raise CommandExecutionFailed, "Command \"#{command}\" was unable to execute" unless success
channel.on_data do |_,data|
stdout_data += data
end
channel.on_extended_data do |_,_,data|
stderr_data += data
end
channel.on_request("exit-status") do |_,data|
exit_code = data.read_long
end
channel.on_request("exit-signal") do |_, data|
exit_signal = data.read_long
end
end
end
self.loop
raise CommandFailed, "Command \"#{command}\" returned exit code #{exit_code}" unless exit_code == 0
{
stdout:stdout_data,
stderr:stderr_data,
exit_code:exit_code,
exit_signal:exit_signal
}
end
end
For newer versions of Net::SSH, you can just pass a status hash to Net::SSH::Connection::Session#exec:
status = {}
Net::SSH.start(hostname, user, options) do |ssh|
channel = ssh.exec(command, status: status)
channel.wait # wait for the command to actually be executed
end
puts status.inspect
# {:exit_code=>0}
By default, exec streams its output to $stdout and $stderr. You can pass a block to exec to do something different, a la:
ssh.exec(command, status: status) do |ch, stream, data|
if stream == :stdout
do_something_with_stdout(data)
else
do_something_with_stderr(data)
end
end
This works on 6.1.0 - not sure about availability for older versions. See http://net-ssh.github.io/net-ssh/Net/SSH/Connection/Session.html#method-i-exec for more details.

Resources