Uploaded image for project: 'CFEngine Community'
  1. CFEngine Community
  2. CFE-3867

error message when promised line could not select region should identify the region that can not be selected

    XMLWordPrintable

    Details

    • Type: Task
    • Status: Open
    • Priority: (None)
    • Resolution: Unresolved
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: cf-agent, Logging
    • Labels:
      None

      Description

      The error message when promised line could not select region should identify the region that can not be selected.

      For example, instead of error: The promised line insertion 'color=red' could not select an edit region in '/tmp/config', we should see error: The promised line insertion 'color=red' could not select region 'section 1' in '/tmp/config'

      set_variable_values_ini(tab, sectionName)

      bundle agent __main__
      {
        vars:
            '_config[section 1][color]'string => "red";
            '_config[section_2][something]'     string => "else";
            "sections" slist => getindices( _config );
      
        files:
          "/tmp/config"
            create => 'true',
            edit_line => set_variable_values_ini( "$(this.namespace):$(this.bundle)._config", $(sections) );
      
        reports:
            "/tmp/config" printfile => cat( $(this.promiser) );
      }
      
      #+begin_src from_stdlib
      body select_region INI_section(x)
      # @brief Restrict the `edit_line` promise to the lines in section `[x]`
      # @param x The name of the section in an INI-like configuration file
      {
              select_start => "\[$(x)\]\s*";
              select_end => "\[.*\]\s*";
      
      @if minimum_version(3.10)
              select_end_match_eof => "true";
      @endif
      }
      bundle edit_line set_variable_values_ini(tab, sectionName)
      # @brief Sets the RHS of configuration items in the file of the form
      # `LHS=RHS`
      #
      # If the line is commented out with `#`, it gets uncommented first.
      # Adds a new line if none exists.
      #
      # @param tab An associative array containing `tab[sectionName][LHS]="RHS"`.
      # The value is not changed when the `RHS` is "dontchange"
      # @param sectionName The section in the file within which values should be
      # modified
      #
      # **See also:** `manage_variable_values_ini()`
      {
        vars:
            "index" slist => getindices("$(tab)[$(sectionName)]");
      
            # Be careful if the index string contains funny chars
            "cindex[$(index)]" string => canonify("$(index)");
      
        classes:
            "edit_$(cindex[$(index)])"
              not => strcmp("$($(tab)[$(sectionName)][$(index)])","dontchange"),
      
              comment => "Create conditions to make changes";
      
        field_edits:
      
            # If the line is there, but commented out, first uncomment it
            "#+\s*$(index)\s*=.*"
            select_region => INI_section(escape("$(sectionName)")),
            edit_field => col("\s*=\s*","1","$(index)","set"),
              if => and("_section_$(section_name)_present_reached",
                        "edit_$(cindex[$(index)])");
      
      
            # match a line starting like the key something
            "\s*$(index)\s*=.*"
            edit_field => col("\s*=\s*","2","$($(tab)[$(sectionName)][$(index)])","set"),
            select_region => INI_section(escape("$(sectionName)")),
            classes => results("bundle", "set_variable_values_ini_not_$(cindex[$(index)])"),
              if => and("_section_$(section_name)_present_reached",
                         "edit_$(cindex[$(index)])");
      
        insert_lines:
            "[$(sectionName)]"
            location => start,
            comment => "Insert lines",
            classes => results( "bundle", "_section_$(section_name)_present" );
      
            "$(index)=$($(tab)[$(sectionName)][$(index)])"
            select_region => INI_section(escape("$(sectionName)")),
              if => "!(set_variable_values_ini_not_$(cindex[$(index)])_kept|set_variable_values_ini_not_$(cindex[$(index)])_repaired).edit_$(cindex[$(index)])";
      
      }
      body edit_field col(split,col,newval,method)
      # @brief Edit tabluar data with comma-separated sub-values
      # @param split The separator that defines columns
      # @param col The (1-based) index of the value to change
      # @param newval The new value
      # @param method The method by which to edit the field
      {
              field_separator    => "$(split)";
              select_field       => "$(col)";
              value_separator    => ",";
              field_value        => "$(newval)";
              field_operation    => "$(method)";
              extend_fields      => "true";
              allow_blank_fields => "true";
      }
      
      body location start
      # @brief Editing occurs before the matched line
      {
              before_after => "before";
      }
      body classes results(scope, class_prefix)
      # @brief Define classes prefixed with `class_prefix` and suffixed with
      # appropriate outcomes: _kept, _repaired, _not_kept, _error, _failed,
      # _denied, _timeout, _reached
      #
      # @param scope The scope in which the class should be defined (`bundle` or `namespace`)
      # @param class_prefix The prefix for the classes defined
      #
      # This body can be applied to any promise and sets global
      # (`namespace`) or local (`bundle`) classes based on its outcome. For
      # instance, with `class_prefix` set to `abc`:
      #
      # * if the promise is to change a file's owner to `nick` and the file
      # was already owned by `nick`, the classes `abc_reached` and
      # `abc_kept` will be set.
      #
      # * if the promise is to change a file's owner to `nick` and the file
      # was owned by `adam` and the change succeeded, the classes
      # `abc_reached` and `abc_repaired` will be set.
      #
      # This body is a simpler, more consistent version of the body
      # `scoped_classes_generic`, which see. The key difference is that
      # fewer classes are defined, and only for outcomes that we can know.
      # For example this body does not define "OK/not OK" outcome classes,
      # since a promise can be both kept and failed at the same time.
      #
      # It's important to understand that promises may do multiple things,
      # so a promise is not simply "OK" or "not OK." The best way to
      # understand what will happen when your specific promises get this
      # body is to test it in all the possible combinations.
      #
      # **Suffix Notes:**
      #
      # * `_reached` indicates the promise was tried. Any outcome will result
      #   in a class with this suffix being defined.
      #
      # * `_kept` indicates some aspect of the promise was kept
      #
      # * `_repaired` indicates some aspect of the promise was repaired
      #
      # * `_not_kept` indicates some aspect of the promise was not kept.
      #   error, failed, denied and timeout outcomes will result in a class
      #   with this suffix being defined
      #
      # * `_error` indicates the promise repair encountered an error
      #
      # * `_failed` indicates the promise failed
      #
      # * `_denied` indicates the promise repair was denied
      #
      # * `_timeout` indicates the promise timed out
      #
      # **Example:**
      #
      # ```cf3
      # bundle agent example
      # {
      #   commands:
      #     "/bin/true"
      #       classes => results("bundle", "my_class_prefix");
      #
      #   reports:
      #     my_class_prefix_kept::
      #       "My promise was kept";
      #
      #     my_class_prefix_repaired::
      #       "My promise was repaired";
      # }
      # ```
      #
      # **See also:** `scope`, `scoped_classes_generic`, `classes_generic`
      {
        scope => "$(scope)";
      
        promise_kept => { "$(class_prefix)_reached",
                          "$(class_prefix)_kept" };
      
        promise_repaired => { "$(class_prefix)_reached",
                              "$(class_prefix)_repaired" };
      
        repair_failed => { "$(class_prefix)_reached",
                           "$(class_prefix)_error",
                           "$(class_prefix)_not_kept",
                           "$(class_prefix)_failed" };
      
        repair_denied => { "$(class_prefix)_reached",
                           "$(class_prefix)_error",
                           "$(class_prefix)_not_kept",
                           "$(class_prefix)_denied" };
      
        repair_timeout => { "$(class_prefix)_reached",
                            "$(class_prefix)_error",
                            "$(class_prefix)_not_kept",
                            "$(class_prefix)_timeout" };
      }
      body printfile cat(file)
      # @brief Report the contents of a file
      # @param file The full path of the file to report
      {
              file_to_print => "$(file)";
              number_of_lines => "inf";
      }
      #+end_src
      

      A run with a starting empty config file

         error: The promised line insertion 'color=red' could not select an edit region in '/tmp/config'
         error: The promised line insertion 'color=red' could not select an edit region in '/tmp/config'
         error: The promised line insertion 'color=red' could not select an edit region in '/tmp/config'
          info: Inserted the promised line '[section 1]' into '/tmp/config'
          info: insert_lines promise '[section 1]' repaired
          info: Edited file '/tmp/config'
          info: Prepended the promised line '[section_2]' to /tmp/config
          info: insert_lines promise '[section_2]' repaired
          info: Inserted the promised line 'something=else' into '/tmp/config' after locator
          info: insert_lines promise 'something=else' repaired
          info: Edited file '/tmp/config'
      R: /tmp/config
      R: [section_2]
      R: something=else
      R: [section 1]
      

        Attachments

          Activity

            People

            Assignee:
            Unassigned Unassigned
            Reporter:
            a10042 Nick Anderson
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Dates

              Created:
              Updated: