Ruby enumeration has unexpected second pass - ruby

This is making me crazy. I'm trying to loop through email messages using ".each do |one_of|…end", but inserting one innocuous statement breaks the enumeration.
Here is an almost-stand-alone snippet. The authentication info is set up immediately preceding, as is the "require net/imap"
imap = Net::IMAP.new(IMAP_server)
imap.authenticate('LOGIN', IMAP_login, IMAP_pass)
imap.select(IMAP_folder)
[1,2,3,5].each do |mnum|
#message_ids = imap.search(['SUBJECT', 'NETGEAR R7000 Log']).each do |mnum|
puts(mnum)
msg = imap.fetch(mnum, 'BODY[TEXT]')
msg[0].values[1]['BODY[TEXT]'].each_line do |full_entry|
line = String.new(full_entry)
recType = line[/^\[.*\] /]
# recType = recType.tr('[]','')
puts recType
end
puts
puts
end
It was working (and not) when I was looping through message ID numbers, but I replaced that statement with a literal array to eliminate a potential problem source.
Running it with the ".tr" statement commented out produces expected results, lines like:
1
[DHCP IP: (192.168.1.9)]
[DoS attack: FIN Scan]
[DHCP IP: (192.168.1.8)]
[Admin login]
[Admin login failure]
[Admin login]
[DHCP IP: (192.168.1.7)]
[DHCP IP: (192.168.1.5)]
[Time synchronized with NTP server]
[Internet connected]
2
[LAN access from remote]
[LAN access from remote]
[LAN access from remote]
[UPnP set event: Public_UPNP_C3]
[UPnP set event: Public_UPNP_C3]
[UPnP set event: Public_UPNP_C3]
…
Now un-comment the ".tr" line, to remove the brackets, and it goes all the way through the first iteration, but then:
1
DHCP IP: (192.168.1.9)
DoS attack: FIN Scan
DHCP IP: (192.168.1.8)
Admin login
Admin login failure
Admin login
DHCP IP: (192.168.1.7)
DHCP IP: (192.168.1.5)
Time synchronized with NTP server
Internet connected
Traceback (most recent call last):
4: from /Users/jan/bin/MassageNetgear.rb:39:in `<main>'
3: from /Users/jan/bin/MassageNetgear.rb:39:in `each'
2: from /Users/jan/bin/MassageNetgear.rb:43:in `block in <main>'
1: from /Users/jan/bin/MassageNetgear.rb:43:in `each_line'
/Users/jan/bin/MassageNetgear.rb:45:in `block (2 levels) in <main>': undefined method `tr' for nil:NilClass (NoMethodError)
So, somehow, putting this one statement in is causing the second iteration of mnum to fail. It doesn't even print "2" for the second iteration. Line 45 in the traceback is the newly inserted statement, but it doesn't even get that far! Adding another puts as the first statement in the inner loop does nothing.
I've done this before to concatenate a bunch of emails containing router log messages, but I then modified that code, and I somehow broke it! I've cut and re-typed the problem statement, thinking there may have been invisibles in there, but I'm using BBEdit, which shows such things.
Please, point out where I'm doing something stupid!
Thanks!

nil prints as an empty string, so it's possible there is actually a last line which isn't matching the regexp and which is printing as an empty string. In that case, tr would fail since nil actually doesn't have a tr method.
You could use a conditional assignment, which will not execute the right-hand side if recType is falsy.
recType = line[/^\[.*\] /]
recType &&= recType.tr('[]','')
puts recType
Or (if you want to actually treat it as an empty string), you can simply unconditionally call to_s on it.
recType = line[/^\[.*\] /].to_s
recType = recType.tr('[]','')
puts recType

Related

To get IP addres of the specific host machine in rub

I want to find the IP address of other system. For example, I am executing my code from server wevrs1234 and I want the IP address of server apvrs1234 and store it in variable. Please help me to get this.
ip = IPSocket.getaddress(Socket.gethostname)
is the code I have so far.
AS per suggestion i have made this code but getting error. Please find my code
publish_vm = node['aem_dispatcher_cookbook']['publish'].to_s
nodes = search(:node, 'hostname:publish_vm')
node.default['aem_dispatcher_cookbook']['ip_address'] = 'nodes.first['ipaddress']'
template node['aem_dispatcher_cookbook']['owner']['home'] + '/conf.d/publish_farm.any' do
source 'publish_farm.any.erb'
owner node['aem_dispatcher_cookbook']['owner']['user']
group node['aem_dispatcher_cookbook']['owner']['group']
mode '0755'
variables(
publish_host: node['aem_dispatcher_cookbook']['publish'],
publish_port: node['aem_dispatcher_cookbook']['publish_port'],
ip_addr: node['aem_dispatcher_cookbook']['ip_address']
)
end
Error
[2020-05-20T06:09:52-05:00] DEBUG: Node wevrd64501.uhc.com loading cookbook aem_dispatcher_cookbook's attribute file /root/.chef/local-mode-cache/cache/cookbooks/aem_dispatcher_cookbook/attributes/default.rb
================================================================================
Recipe Compile Error in /root/.chef/local-mode-cache/cache/cookbooks/aem_dispatcher_cookbook/recipes/default.rb
================================================================================
SyntaxError
-----------
/root/.chef/local-mode-cache/cache/cookbooks/aem_dispatcher_cookbook/recipes/default.rb:333: syntax error, unexpected tIDENTIFIER, expecting keyword_end
...ess'] = 'nodes.first['ipaddress']'
... ^~~~~~~~~
System Info:
You tagged the question with [chef] and [chef-recipe], so I understand you are trying to get another machine's IP address inside recipe. If that another machine is also registered with Chef Server, the easiest would be search. You can search for any machine registered on the Chef Server by some attribute, in your case - hostname.
nodes = search(:node, 'hostname:<another_vm_hostname>')
p nodes.first['ipaddress']
Update:
You have an error in your 3rd line. Don't surround nodes.first['ipaddess'] with quotes.
node.default['aem_dispatcher_cookbook']['ip_address'] = nodes.first['ipaddress']
publish_vm = node['aem_dispatcher_cookbook']['publish'].to_s
ruby_block 'get_ip_from_publish' do
block do
Chef::Resource::RubyBlock.send(:include, Chef::Mixin::ShellOut)
command1 = "nslookup #{publish_vm} |grep '^Address' | awk '{print $2}'| tail -1"
command_out = shell_out(command1)
node.run_state['master_ip'] = command_out.stdout
end
action :run
end
This piece of code helped me to get ip address of desired host machine

A JSON text must at least contain two octets! (JSON::ParserError)

I'm working with a Ruby script that reads a .json file.
Here is the JSON file:
{
"feed.xml": "93d5b140dd2b4779edef0347ac835fb1",
"index.html": "1cbe25936e392161bad6074d65acdd91",
"md5.json": "655d7c1dbf83a271f348a50a44ba4f6a",
"test.sh": "9be192b1b5a9978cb3623737156445fd",
"index.html": "c064e204040cde216d494776fdcfb68f",
"main.css": "21b13d87db2186d22720e8c881a78580",
"welcome-to-jekyll.html": "01d7c7d66bdeecd9cd69feb5b4b4184d"
}
It is completely valid, and is checked for its existence before trying to read from it. Example:
if File.file?("md5.json")
puts "MD5s exists"
mddigests = File.open("md5.json", "r")
puts "MD5s" + mddigests.read
items = JSON.parse(mddigests.read) <--- Where it all goes wrong.
puts items["feed.xml"]
Everything works up until that point:
MD5s exists
MD5s{
"feed.xml": "93d5b140dd2b4779edef0347ac835fb1",
"index.html": "1cbe25936e392161bad6074d65acdd91",
"md5.json": "655d7c1dbf83a271f348a50a44ba4f6a",
"test.sh": "9be192b1b5a9978cb3623737156445fd",
"index.html": "c064e204040cde216d494776fdcfb68f",
"main.css": "21b13d87db2186d22720e8c881a78580",
"welcome-to-jekyll.html": "01d7c7d66bdeecd9cd69feb5b4b4184d"
}
common.rb:156:in `initialize': A JSON text must at least contain two octets! (JSON::ParserError)
I've searched and tried a lot of different things, to no avail. I'm stumped. Thanks!
You have a duplicate call to read() at the point that it all goes wrong. Replace the second call to read() with the variable mddigests and all should be fine.
This code should work like you'd expect:
if File.file?("md5.json")
puts "MD5s exists"
mddigests = File.open("md5.json", "r")
digests = mddigests.read
puts "MD5s" + digests
items = JSON.parse(digests) #<--- This should work now!
puts items["feed.xml"]
end
The reason is that the file pointer is moved after the first read(), and by the second read(), it's at the end of file, hence the message requiring at least 2 octets.

why do I get "200 Type set to I. (Net::FTPReplyError)"

Note: that I have both blocks of code (see below) in the same .rb file. The first time ftp.getbinaryfile() works then it throws the error.
Note: that file variable is a static path to the file used for debugging purposes only.
I have this code in ruby 2.0.0p481 (2014-05-08) [x64-mingw32]
file = "/Filetrack/E-mail_Gateway/_Installer/GA/E-mail Gateway_10.0_Changes_PUBLIC.pdf"
list = ftp.list('*')
list.each{|item|
counter=counter+1
counter++
ftp.getbinaryfile(file, where_to_save+File.basename(file)+counter.to_s, 1024)
puts "downloaded - .each used"
}
then in the same .rb file I got this code
ftp.list('*') { |item|
puts "downloading using .list('*') {"
counter++
ftp.getbinaryfile(file, where_to_save+File.basename(file)+counter.to_s, 1024)
puts "downloaded #{file}"
}
and that code throws me this error
Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:974:in `parse227': 200 Type set to I. (Net::FTPReplyError)
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:394:in `makepasv'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:406:in `transfercmd'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:487:in `block (2 levels) in retrbinary'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:199:in `with_binary'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:485:in `block in retrbinary'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/monitor.rb:211:in `mon_synchronize'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:484:in `retrbinary'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:617:in `getbinaryfile'
ftp session is created by
ftp = Net::FTP.new('ftp.***.***.net')
ftp.passive = false
ftp.debug_mode = true
ftp.login(ftp_username, ftp_password)
could someone explain why the second version works?
UPDATE
Added ftp debugging log:
put: USER r.***
get: 331 Password required for r.***.
put: PASS ************
get: 230-Welcome to FTP
get: 230 User r.****logged in.
put: TYPE I
get: 200 Type set to I.
put: CWD /Filetrack/E-mail_Gateway/_Installer/GA/010_000_003_000/
get: 250 CWD command successful.
put: TYPE A
get: 200 Type set to A.
put: PASV
get: 227 Entering Passive Mode (194,212,10,23,195,92).
put: LIST *
get: 125 Data connection already open; Transfer starting.
get: 226 Transfer complete.
put: TYPE I
get: 200 Type set to I.
put: PASV
get: 227 Entering Passive Mode (194,212,10,23,195,93).
put: RETR /Filetrack/E-mail_Gateway/_Installer/GA/010_000_003_000/E-mail Gateway_10.0_Changes_PUBLIC.pdf
get: 125 Data connection already open; Transfer starting.
get: 226 Transfer complete.
downloaded - .each used
put: TYPE A
get: 200 Type set to A.
put: PASV
get: 227 Entering Passive Mode (***,***,10,23,195,97).
put: LIST *
get: 125 Data connection already open; Transfer starting.
downloading using .list('*') {
put: TYPE I
get: 226 Transfer complete.
put: PASV
get: 200 Type set to I.
put: TYPE A
get: 227 Entering Passive Mode (***,***,10,23,195,98).
put: TYPE I
get: 200 Type set to A.
d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:974:in `parse227': 200 Type set to I. (Net::FTPReplyError)
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:394:in `makepasv'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:406:in `transfercmd'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:487:in `block (2 levels) in retrbinary'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:199:in `with_binary'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:485:in `block in retrbinary'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/monitor.rb:211:in `mon_synchronize'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:484:in `retrbinary'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:617:in `getbinaryfile'
from download2 - debugging.rb:41:in `block in <main>'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:518:in `block (3 levels) in retrlines'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:515:in `loop'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:515:in `block (2 levels) in retrlines'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:199:in `with_binary'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:512:in `block in retrlines'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/monitor.rb:211:in `mon_synchronize'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:511:in `retrlines'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:760:in `list'
from download2 - debugging.rb:38:in `<main>'
UPDATE2
log if ftp.passive = false is used
downloading using .list('*') {
put: TYPE I
get: 226 Transfer complete.
put: PORT ***,***,20,102,235,136
get: 200 Type set to I.
put: RETR /Filetrack/E-mail_Gateway/_Installer/GA/010_000_003_000/Email Gateway_10.0_Changes_PUBLIC.pdf
get: 200 PORT command successful.
put: TYPE A
put: TYPE I
d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/protocol.rb:211:in `write': An existing connection was forcibly closed by the remote host. (Errno::ECONNRESET)
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/protocol.rb:211:in `write0'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/protocol.rb:185:in `block in write'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/protocol.rb:202:in `writing'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/protocol.rb:184:in `write'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:283:in `putline'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:360:in `block in voidcmd'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/monitor.rb:211:in `mon_synchronize'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:359:in `voidcmd'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:183:in `send_type_command'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:172:in `binary='
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:201:in `ensure in with_binary'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:201:in `with_binary'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:512:in `block in retrlines'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/monitor.rb:211:in `mon_synchronize'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:511:in `retrlines'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:760:in `list'
from download2 - debugging.rb:39:in `<main>'
UPDATE3
I tried to run the same code in ftp active mode few times and actually all files are downloaded but the script finishes with an error.
downloading using .list('*') {
put: TYPE I
get: 200 Type set to I.
put: PORT **,**,20,102,197,73
get: 200 PORT command successful.
put: RETR /Filetrack/E-mail_Gateway/_Installer/GA/010_000_003_000/E-mail Gateway_10.0_Changes_PUBLIC.pdf
get: 150 Opening BINARY mode data connection for /Filetrack/E-mail_Gateway/_Installer/GA/010_000_003_000/E-mail Gateway_10.0_Changes_PUBLIC.pdf(
60911 bytes).
get: 226 Transfer complete.
put: TYPE A
get: 200 Type set to A.
downloaded /Filetrack/E-mail_Gateway/_Installer/GA/010_000_003_000/E-mail Gateway_10.0_Changes_PUBLIC.pdf
put: TYPE I
get: 200 Type set to I.
d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/protocol.rb:158:in `rescue in rbuf_fill': Net::ReadTimeout (Net::ReadTimeout)
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/protocol.rb:152:in `rbuf_fill'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/protocol.rb:134:in `readuntil'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:1108:in `readline'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:289:in `getline'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:300:in `getmultiline'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:318:in `getresp'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:338:in `voidresp'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:526:in `block (2 levels) in retrlines'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:199:in `with_binary'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:512:in `block in retrlines'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/monitor.rb:211:in `mon_synchronize'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:511:in `retrlines'
from d:/prog/Ruby200-x64/lib/ruby/2.0.0/net/ftp.rb:760:in `list'
from download2 - debugging.rb:39:in `<main>'
Reason for `200 Type set to I. (Net::FTPReplyError)`
Your connection uses PASSIVE mode. Since you have not shown the part of code you create FTP object, I will assume that you setting mode to passive explicitly.
ftp = Net::FTP.new('example.com')
ftp.passive = true
Based on the stack trace of exception, one can see that issue happens when the method makepasv issues PASV command, but instead of getting a response of 227 Entering Passive Mode (194,212,10,23,195,93)., it gets a response 200 Type set to I.
Implementation of makepasv and parse227 (Refer Reference 1 & Reference 2 later in the post) indicates that code specifically looks for return code of 227 and if that is not the case, it will throw an FTPError.
This is what is happening in the given scenario.
Why does `parse227` receive wrong response?
This can be attributed to the syntax shown below.
This may very well be not so well understood behavior (as I myself discovered during the course answering to this post)
ftp.list('*') { |item|
ftp.getbinaryfile(file, where_to_save+File.basename(file)+counter.to_s, 1024)
}
In the above code, a LIST * command is issued by ftp.list('*'). Typical response for this command would like below:
put: LIST *
get: 125 Data connection already open; Transfer starting.
get: 226 Transfer complete.
As can be seen, LIST * produces two lines of result. This fact is crucial to understand the issue.
The block passed to ftp.list('*') downloads a binary file using getbinaryfile method.
getbinaryfile will typically issue below commands:
TYPE I to put the connection in image (binary) mode
PASVto enter passive mode
RETR /path/of/file/to/download
When the block executes for the first result of ftp.list('*'), and starts issuing commands related to getbinaryfile, at that point of time, only first line of response of LIST * has been read - the second line is yet to be read. It is this second line that shows up as response to next command issued in the block.
Hence, when first command TYPE I is issued, the code reads the second line of LIST * as response (as evident in debug logs)
put: TYPE I
get: 226 Transfer complete.
When second command PASV is issued, the code reads the response of TYPE I (as evident from debug logs)
put: PASV
get: 200 Type set to I.
Implementation of makepasv is such that it expects that response to have response code of 227 (Refer line 394 and 973 in Reference 1 and Reference 2 respectively). An exception Net::FTPReplyError was thrown gets thrown in this case as parse227 was passed a response of TYPE I command.
In summary, when using passive mode, it seems that it is not feasible to perform other FTP operations in the block given to `ftp.list('*')
Why does `ftp.list('*').each` work?
In this case, the ftp.list('*') is invoked without a block, and hence it returns the Array of strings as output. Using each on that array does not create the similar situation - and hence, there are no issues observed.
Solution
It seems that author(s) of FTP#list expected the below two variants to work in equivalent manner:
ftp.list('*') { |f| } # block given to list
ftp.list('*').each { |f| } # block given to enum returned by list
As per official documentation of list API:
list(*args) { |line| ... }
Returns an array of file information in the
directory (the output is like ls -l). If a block is given, it
iterates through the listing.
If we look at the implementation of list, then, we see that when a block is given, each line read from ftp.list('*') is yielded to the block one by one. When using passive mode, if the block tries to execute any other FTP commands, this causes the above mentioned.
754 def list(*args, &block) # :yield: line
755 cmd = "LIST"
756 args.each do |arg|
757 cmd = cmd + " " + arg.to_s
758 end
759 if block
760 retrlines(cmd, &block)
761 else
762 lines = []
763 retrlines(cmd) do |line|
764 lines << line
765 end
766 return lines
767 end
768 end
We can solve this problem by changing the implementation to become equivalent to ftp.list('*').each variant by first collecting all lines from LIST * response into an array, and the passing that array to the block if a block was given. We will still stay true to the API documentation.
def list(*args, &block) # :yield: line
cmd = "LIST"
args.each do |arg|
cmd = cmd + " " + arg.to_s
end
# First lets fetch all the lines
lines = []
retrlines(cmd) do |line|
lines << line
end
if block
lines.each { |l| yield l }
else
return lines
end
end
I have reported a bug in Ruby Bug Tracker suggesting above change in implementation of FTP#list method.
Reference 1 - Implementation of makepasv
391 # sends the appropriate command to enable a passive connection
392 def makepasv # :nodoc:
393 if #sock.peeraddr[0] == "AF_INET"
394 host, port = parse227(sendcmd("PASV"))
395 else
396 host, port = parse229(sendcmd("EPSV"))
397 # host, port = parse228(sendcmd("LPSV"))
398 end
399 return host, port
400 end
Reference 2 - Implementation of parse227
968 # handler for response code 227
969 # (Entering Passive Mode (h1,h2,h3,h4,p1,p2))
970 #
971 # Returns host and port.
972 def parse227(resp) # :nodoc:
973 if resp[0, 3] != "227"
974 raise FTPReplyError, resp
975 end
976 if m = /\((?<host>\d+(,\d+){3}),(?<port>\d+,\d+)\)/.match(resp)
977 return parse_pasv_ipv4_host(m["host"]), parse_pasv_port(m["port"])
978 else
979 raise FTPProtoError, resp
980 end
981 end
Source code snippets were taken from ftp.rb.
UPDATE: 13 Sep, 2015
The proposed change has been accepted by Ruby core team for this issue.
I've solved it disabling "This server is sitting behind a router/firewall" function insde Server Advanced.
enter image description here

dynamic usage of attribute in recipe

I am trying to increment the value and use in another resource dynamically in recipe but still failing to do that.
Chef::Log.info("I am in #{cookbook_name}::#{recipe_name} and current disk count #{node[:oracle][:asm][:test]}")
bash "beforeTest" do
code lazy{ echo #{node[:oracle][:asm][:test]} }
end
ruby_block "test current disk count" do
block do
node.set[:oracle][:asm][:test] = "#{node[:oracle][:asm][:test]}".to_i+1
end
end
bash "test" do
code lazy{ echo #{node[:oracle][:asm][:test]} }
end
However I'm still getting the error bellow:
NoMethodError ------------- undefined method echo' for Chef::Resource::Bash
Cookbook Trace: ---------------
/var/chef/cache/cookbooks/Oracle11G/recipes/testSplit.rb:3:in block (2 levels) in from_file'
Resource Declaration: ---------------------
# In /var/chef/cache/cookbooks/Oracle11G/recipes/testSplit.rb
1: bash "beforeTest" do
2: code lazy{
3: echo "#{node[:oracle][:asm][:test]}"
4: }
5: end
Please can you help how lazy should be used in bash? If not lazy is there any other option?
bash "beforeTest" do
code lazy { "echo #{node[:oracle][:asm][:test]}" }
end
You should quote the command for the interpolation to work; if not, ruby would search for an echo command, which is unknown in ruby context (thus the error you get in log).
Warning: lazy has to be for the whole resource attribute; something like this WON'T work:
bash "beforeTest" do
code "echo node asm test is: #{lazy { node[:oracle][:asm][:test]} }"
end
The lazy evaluation takes a block of ruby code, as decribed here
You may have a better result with the log resource like this:
log "print before" do
message lazy { "node asm test is #{node[:oracle][:asm][:test]}" }
end
I've been drilling my head solving this problem until I came up with lambda expressions. But yet just using lambda didn't help me at all. So I thought of using both lambda and lazy evaluation. Though lambda is already lazy loading, when compiling chef recipe's, the resource where you call the lambda expression is still being evaluated. So to prevent it to being evaluated (somehow), I've put it inside a lazy evaluation string.
The lambda expression
app_version = lambda{`cat version`}
then the resource block
file 'tmp/validate.version' do
user 'user'
group 'user_group'
content lazy { app_version.call }
mode '0755'
end
Hope this can help others too :) or if you have some better solution please do let me know :)

Problems catching unidecoder exceptions

I'm trying out the unidecoder gem and it's giving me problems with some strings:
require 'unidecoder'
str = "\u00A3"
str.to_ascii
#: (C:/Ruby193/lib/ruby/gems/1.9.1/gems/unidecoder-1.1.1/lib/unidecoder/data/x00.yml):
found unknown escape character while parsing a quote d scalar at line
2 column 3
from C:/Ruby193/lib/ruby/1.9.1/psych.rb:203:in parse'
from C:/Ruby193/lib/ruby/1.9.1/psych.rb:203:inparse_stream'
from C:/Ruby193/lib/ruby/1.9.1/psych.rb:151:in parse'
from C:/Ruby193/lib/ruby/1.9.1/psych.rb:127:inload'
from C:/Ruby193/lib/ruby/1.9.1/psych.rb:297:in block in load_file'
from C:/Ruby193/lib/ruby/1.9.1/psych.rb:297:inopen'
from C:/Ruby193/lib/ruby/1.9.1/psych.rb:297:in load_file'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/unidecoder-1.1.1/lib/unidecoder.rb:8:in
block in '
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/unidecoder-1.1.1/lib/unidecoder.rb:78:in
yield'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/unidecoder-1.1.1/lib/unidecoder.rb:78:in
default'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/unidecoder-1.1.1/lib/unidecoder.rb:78:in
decode_char'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/unidecoder-1.1.1/lib/unidecoder.rb:39:in
block in decode'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/unidecoder-1.1.1/lib/unidecoder.rb:37:in
gsub'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/unidecoder-1.1.1/lib/unidecoder.rb:37:in
decode'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/unidecoder-1.1.1/lib/unidecoder.rb:16:in
to_ascii'
from (irb):21
from C:/Ruby193/bin/irb:12:in'>>
What's worse, I can't catch the error by doing:
foo = str.to_ascii rescue 'x'
Does anyone know what's happening here?
rescue clause with no parameter list, the parameter defaults to StandardError; it looks like unidecoder raises kinda other exception, but the stacktrace seems to be incomplete (it should show the exception type.)
Take a look at "C:/Ruby193/lib/ruby/gems/1.9.1/gems/unidecoder-1.1.1/lib/unidecoder/data/x00.yml". Line 2 is an YAML entry - "\z",which is not a valid escape sequence in Ruby(but a Regexp anchor to mark the end of string). This might be a bug. You can edit this line to - "\x00".
However, "\u00A3"(£) is not a valid ASCII character, I didn't find the point of encoding it to ASCII.
The exception raised is Psych::SyntaxError, you can catch that specific exception, as #mudasobwa commented.

Resources