OpsWorks Ruby returning nil for valid regex test

0 votes
asked Sep 11, 2017 by torpedobench

In OpsWorks, I'm trying to test the number suffix on a hostname of a given node, and to extract that number if it isn't 1. If the number isn't 1, I have this regex to match the number:

/([\d]+)$­/

Which is run against a node naming scheme that follows this pattern:

  • node1
  • node2
  • node3
  • node(n...)

I've verified this works using Rubular: http://rubular.com/r/Ei0kqjaxQn

However, when I run this against an instance with OpsWorks, this match returns nil, no matter what number the hostname has at the end. The OpsWorks agent version is the latest at time of writing (4023), using Chef 12.13.37.

This is the code in the cookbook trying use the matched number:

short_app_name.to_s + node['hostname'][/([\d]+)$­/, 1].to_s + '.' + app['domains'].first

The run fails with type error no implicit conversion of nil into String. However, regex searches against that property work earlier in the recipe, when checking the node's number suffix. Is there a different method I should be using to extract the node's suffix?


Edit: app['domains'].first is populated. This line still fails with the same type error if it is swapped out with domain.com.

3 Answers

0 votes
answered Sep 11, 2017 by gettalong

Judging from the cookbook code and the error message, the problem may be that app['domains'] is an empty array during the run. So you may want to verify that its value is correct.

0 votes
answered Sep 11, 2017 by simple-lime

When I copy your regex and paste it into my terminal to test, there's a soft hyphen character after the dollar sign at the end of the regex, removing this makes things work:

The website isn't showing it even when I copy it from my terminal, but a screenshot shows the issue:

enter image description here

That second line ('irb(main):002:0') is what I copy/pasted from your cookbook code, the character is "\xc2\xad"

0 votes
answered Sep 11, 2017 by engineersmnky

You error has nothing to do with the regex. The issue is when you try to concatenate your existing String with

app['domains'].first

This is the only place this error would be raised because even if your String#slice returned nil you are calling to_s so it is an empty String but String + nil as would be the case if app['domains'].first is nil will raise this error.

breakdown

#short_app_name can be nil because of explicit #to_s
short_app_name.to_s 
####
# assuming node is a Hash
# node must have 'hostname' key 
# or NoMethodError: undefined method `[]' for nil:NilClass wil be raised
# node['hostname'][/([\d]+)$­/, 1] can be nil because of explicit #to_s
node['hostname'][/([\d]+)$­/, 1].to_s 
#####
# assuming app is a Hash
# app must contain 'domains' key and the value must respond to first
# and the first value must be a String or be implicitly coercible (#to_str) or it will fail with 
# TypeError: no implicit conversion of ClassName into String
# could explicitly coerce (#to_s) like you do previously  
app['domains'].first

Example:

node = {"hostname" => 'nodable'}
app = {"domains" => []}
node['hostname'][/([\d]+)$­/, 1]
#=> nil
node['hostname'][/([\d]+)$­/, 1].to_s
#=> ""
app["domains"].first
#=> nil
node['hostname'][/([\d]+)$­/, 1].to_s + '.' + app["domains"].first
#=> TypeError: no implicit conversion of nil into String
node = {"hostname" => 'node2'}
app = {"domains" => ['here.com']}
node['hostname'][/([\d]+)$­/, 1].to_s + '.' + app["domains"].first
#=> "2.here.com"
Welcome to Q&A, where you can ask questions and receive answers from other members of the community.
Website Online Counter

...