Search code examples
regexrubyyamlpuppet

Puppet regular expression (grab path in var between quotation marks)


I have the following yaml:

role::project::conf::files:
  entry_01:
    - 'file "/var/project/some_file.txt" 5333;'
    - 'echo no;'
  entry_02:
    - 'file "/var/project/some_other_file.txt" 5334;'
    - 'echo yes;'
  entry_03:
    - 'file "/var/project/extra_file.txt" 5335;'
    - 'echo yes;'

then I've used the following regular expression https://regex101.com/r/pVzseA/1 in order to grab the value between those quotation marks (the regex works in regex101.com) but doesn't work in Puppet:

each($files) | $files_itm | {
  if $files_itm[1] =~ /"([^"]*)"/ {
    #how to get only the path here in var
  }
}

Update, the class:

class role::project::conf (
  $files = [],
){
  each($files) | $files_itm | {
    if $files_itm[1] =~ /"([^"]*)"/ {
      notify { "file ${1} seen": }
    }
  }
}

Solution

  • I've used the following regular expression https://regex101.com/r/pVzseA/1 in order to grab the value between those quotation marks (the regex works in regex101.com) but doesn't work in Puppet:

    each($files) | $files_itm | {
      if $files_itm[1] =~ /"([^"]*)"/ {
        #how to get only the path here in var
      }
    }
    

    As I noted in comments, Puppet uses Ruby's flavor of regular expression. This is not among those explicitly supported by Regex101, so it is not out of the question that a regex that worked there would not work with Puppet. However, the Ruby-flavor online regular expression tester at Rubular shows that your particular regular expression works just fine in Ruby, including the the matching group.

    You don't show how you tried to obtain the matched group in your Puppet code, but the appropriate procedure is given in Puppet's regular expression docs. In particular:

    Within conditional statements and node definitions, substrings withing [sic] parentheses () in a regular expression are available as numbered variables inside the associated code section. The first is $1, the second is $2, and so on. The entire match is available as $0. These are not normal variables, and have some special behaviors: [...]

    This is also reflected in the documentation for conditional statements.

    You have only one capture group, so inside the body of your conditional statement, you can refer to the captured content as $1. For example,

    each($files) | $files_itm | {
      if $files_itm[1] =~ /"([^"]*)"/ {
        notify { "file ${1} seen": }
      }
    }
    

    Note well, however, that the capture group variables are only accessible within the body of the conditional statement, and outside any nested conditionals that have a regular expression match in their condition. Also, it does not seem to be documented what the implications are if there are two or more regex-match expressions in the same conditional statement's condition.

    Update

    But the update to the question and the error messages you presented in comments show that the problem you're struggling with is something altogether different. The value associated with Hiera key role::project::conf::files is a hash, with string keys and array values, whereas you seem to expect an array according to the parameter default encoded into the class. When you iterate over a hash and capture the entries in a single variable, that variable will take two-element array values, where the first (element 0) is the entry's key and the second (element 1) is corresponding value.

    Thus, when the Hiera data presented in the question is bound to your $files parameter, your expression $files_itm[1] evaluates to array values such as ['file "/var/project/some_file.txt" 5333;', 'echo no;']. Those are not suitable left-hand operands for the =~ operator, which is what the error message is telling you.

    It's difficult to tell what you really want here, but this ought to at least avoid error (in conjunction with your YAML data):

    each($files) | $itm_key, $itm_value | {
      if $itm_value[0] =~ /"([^"]*)"/ {
        notify { "file ${1} seen": }
      }
    }