Uploaded image for project: 'Puppet'
  1. Puppet
  2. PUP-8181

break() fails with illegal context error within hash iteration outside any function

    Details

    • Template:
    • Acceptance Criteria:
      Hide

      A break() in an iteration breaks the iteration irrespective of context the iteration is performed in.

      Show
      A break() in an iteration breaks the iteration irrespective of context the iteration is performed in.
    • Team:
      Platform Core
    • Method Found:
      Needs Assessment
    • Release Notes:
      Bug Fix
    • Release Notes Summary:
      Hide
      The break() function did not break the iteration over a hash as it was supposed to and ended up breaking the container in which a lambda called break(). This lead to an error about a break from an illegal context if the container was something other than a function, and for functions it would lead to early exit from the function. This is now fixed to behave as a break in an array iteration. All the iterative functions are now fixed wrt. break in both 4.10.z, 5.3.z, and 5.4.0)
      Show
      The break() function did not break the iteration over a hash as it was supposed to and ended up breaking the container in which a lambda called break(). This lead to an error about a break from an illegal context if the container was something other than a function, and for functions it would lead to early exit from the function. This is now fixed to behave as a break in an array iteration. All the iterative functions are now fixed wrt. break in both 4.10.z, 5.3.z, and 5.4.0)
    • QA Risk Assessment:
      Needs Assessment

      Description

      break() fails with an illegal context error within hash iteration outside any function

      It may be that I simply need to use a function and call it a day... I am, however, surprised that this doesn't work, and I wonder if this is by design or by accident.

      # test2.pp
       
      $test_hash = {
        'Linus'   => 'Torvalds',
        'Richard' => 'Stallman',
        'Dennis'  => 'Ritchie',
      }
       
      $test_hash.each |String $first, String $last| {
        if $last == 'Stallman' {
          notice("YES")
          break()
        }
        else {
          notice("NO")
        }
      }
      

      $ puppet apply test2.pp
      Notice: Scope(Class[main]): NO
      Notice: Scope(Class[main]): YES
      Error: break() from context where this is illegal at /tmp/test2.pp:12 on node <node>
      

      I've tried the same thing with return():

      $ puppet apply test2.pp
      Notice: Scope(Class[main]): NO
      Notice: Scope(Class[main]): YES
      Error: return() from context where this is illegal at /tmp/test2.pp:13 on node <node>
      

      If I run break() within a class, I get the same error.

      If I run return() within a class, it breaks out of the entire class rather than just the lambda in the .each loop:

      # test3.pp
       
      class test_class {
        $test_hash = {
          'Linus'   => 'Torvalds',
          'Richard' => 'Stallman',
          'Dennis'  => 'Ritchie',
        }
       
        $test_hash.each |String $first, String $last| {
          if $last == 'Stallman' {
            notice("YES")
            return()
          }
          else {
            notice("NO")
          }
        }
       
        notice("OUT OF THE LOOP")
      }
       
      include ::test_class
      

      $ puppet apply test3.pp
      Notice: Scope(Class[Test_class]): NO
      Notice: Scope(Class[Test_class]): YES
      Notice: Compiled catalog for <node> in environment production in 0.26 seconds
      Notice: Applied catalog in 0.45 seconds
      

      Edit: Issue may be confined to hashes. I'm trying `map` like in the language doc's examples (https://puppet.com/docs/puppet/5.3/function.html#break). The array example works fine. The hash example breaks.

      # test4.pp
       
      class test_class {
        $data = [1,2,3]
        notice $data.map |$x| {
          if $x == 3 {
            break()
          }
          $x*10
        }
       
        $data_hash = { 'a' => 1, 'b' => 2, 'c' => 3 }
        notice $data_hash.map |$key, $value| {
          if $value == 3 {
            break()
          }
          $value*10
        }
       
        notice("OUT OF THE LOOP")
      }
       
      include ::test_class
      

      $ puppet apply test4.pp
      Notice: Scope(Class[Test_class]): [10, 20]
      Error: break() from context where this is illegal at /tmp/test4.pp:15 on node <node>
      

      Example of a workaround using a function and return():

      # test5.pp
      function has_two($data) {
        $data.each |$key, $value| {
          if $value == 2 {
            return(true)
          }
        }
       
        return(false)
      }
       
      $data = { 'a' => 1, 'b' => 2, 'c' => 3 }
      if has_two($data) {
        notice "YES"
      }
      else {
        notice "NO"
      }
      

      $ puppet apply test5.pp
      Notice: Scope(Class[main]): YES
      Notice: Compiled catalog for <node> in environment production in 0.16 seconds
      Notice: Applied catalog in 0.49 seconds
      

        Attachments

          Activity

            People

            • Assignee:
              Unassigned
              Reporter:
              nrwahl2 Reid Wahl
            • Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Zendesk Support