Details
-
Type:
Bug
-
Status: Done
-
Priority:
High
-
Resolution: Fixed
-
Affects Version/s: None
-
Labels:None
Description
If mustache template files promise is in a bundle, and it repairs an existing file, the repair class is not propagated to the client bundle. The output file contents are, however, updated. See also #4611 (the repair status is available in the bundle that renders the template, but not for its client bundle).
Test
bundle agent main { methods: "test"; "check"; } bundle agent test { vars: "mustache_lines" slist => { "{{value}}" }; "template_path" string => "/tmp/mustache_calling_agent_test_template"; "output_path" string => "/tmp/mustache_calling_agent_test_output"; files: "$(template_path)" create => "true", edit_defaults => empty, edit_line => insert_lines(@(mustache_lines)); "$(output_path)" create => "true", edit_defaults => empty, edit_line => insert_lines("foo"); methods: # This should declare second_repaired but does not "template_output" usebundle => apply_template("{ \"value\" : 2 }"), classes => results( "namespace", "apply_template"); vars: "c" slist => classesmatching( "apply_template.*" ); reports: "$(c)"; apply_template_repaired:: "PASS"; !apply_template_repaired:: "FAIL"; } bundle agent apply_template(json) { files: "$(test.output_path)" create => "true", #edit_defaults => empty, edit_template => "$(test.template_path)", template_method => "mustache", template_data => parsejson($(json)), classes => results( "namespace", "file_template" ); vars: "c" slist => classesmatching( "file_template.*" ); reports: "$(c)"; } bundle agent check { classes: "OK" and => { "file_template_repaired", "file_template_kept", "file_template_reached", # For enterprise compliance the worst outcome is rolled up # as the promsie outcome, so in Mission Portal I would # expect to see the promise to apply the template as # repaired "apply_template_repaired", # We expect the bundle to have a repaired outcome "apply_template_kept", # Promises can have multiple outcomes, this is not incorrect "apply_template_reached" # Promises can have multiple outcomes, this is not incorrect }; reports: OK:: "$(this.promise_filename) Pass"; !OK:: "$(this.promise_filename) FAIL"; } bundle edit_line insert_lines(lines) { insert_lines: "$(lines)"; } body edit_defaults empty { empty_file_before_editing => "true"; edit_backup => "false"; } body classes if_repaired(x) { promise_repaired => { "$(x)" }; } 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" }; }
Test run output on 3.12.0
R: file_template_reached R: file_template_repaired R: file_template_kept R: FAIL R: apply_template_reached R: apply_template_kept R: /home/nickanderson/org/cfengine3-294058cj FAIL
The test fails because promise outcomes are rolled up to the calling method. I expect that the method should have been repaired but we can see that the method itself reported to be kept.
Original Test
body common control { bundlesequence => { "test" }; } bundle agent test { vars: "mustache_lines" slist => { "{{value}}" }; "template_path" string => "/tmp/mustache_calling_agent_test_template"; "output_path" string => "/tmp/mustache_calling_agent_test_output"; files: "$(test.template_path)" create => "true", edit_defaults => empty, edit_line => insert_lines(@(mustache_lines)); "$(test.output_path)" create => "true", edit_defaults => empty, edit_line => insert_lines("foo"); methods: # This should declare second_repaired but does not "template_output" usebundle => apply_template("{ \"value\" : 2 }"), classes => if_repaired("template_output_repaired"); reports: template_output_repaired:: "PASS"; !template_output_repaired:: "FAIL"; } bundle agent apply_template(json) { files: "$(test.output_path)" create => "true", edit_defaults => empty, edit_template => "$(test.template_path)", template_method => "mustache", template_data => parsejson($(json)); } bundle edit_line insert_lines(lines) { insert_lines: "$(lines)"; } body edit_defaults empty { empty_file_before_editing => "true"; edit_backup => "false"; } body classes if_repaired(x) { promise_repaired => { "$(x)" }; }
Outcome: Fail
Attachments
Issue Links
- duplicates
-
CFE-3010 Mustache promise changes do not propagate when used as part of another bundle
-
- Done
-