chef error Chef::Util::FileEdit

1.9k Views Asked by At

I have following ruby_block in chef cookbook

ruby_block "hosts" do
  block do
    rc = Chef::Util::FileEdit.new("/etc/login.defs")
    rc.search_file_replace_line(
      /^PASS_MAX_DAYS   99999$/,
      "PASS_MAX_DAYS   150"
    )
    rc.write_file
  end
end

when i run chef-client i am getting following error

 * ruby_block[hosts] action run[2014-11-20T18:35:17+00:00] INFO: Processing ruby_block[hosts] action run (my_cookbook::default line 31)


    ================================================================================
    Error executing action `run` on resource 'ruby_block[hosts]'
    ================================================================================

    ArgumentError
    -------------
    invalid byte sequence in US-ASCII

    Cookbook Trace:
    ---------------
    /var/chef/cache/cookbooks/my_cookbook/recipes/default.rb:34:in `block (2 levels) in from_file'

    Resource Declaration:
    ---------------------
    # In /var/chef/cache/cookbooks/my_cookbook/recipes/default.rb

     31: ruby_block "hosts" do
     32:   block do
     33:     rc = Chef::Util::FileEdit.new("/etc/login.defs")
     34:     rc.search_file_replace_line(
     35:       /^PASS_MAX_DAYS   99999$/,
     36:       "PASS_MAX_DAYS   150"
     37:     )
     38:     rc.write_file
     39:   end
     40: end
     41:

    Compiled Resource:
    ------------------
    # Declared in /var/chef/cache/cookbooks/my_cookbook/recipes/default.rb:31:in `from_file'

    ruby_block("hosts") do
      action "run"
      retries 0
      retry_delay 2
      guard_interpreter :default
      block_name "hosts"
      cookbook_name "my_cookbook"
      recipe_name "default"
      block #<Proc:0x000000024e8cc8@/var/chef/cache/cookbooks/my_cookbook/recipes/default.rb:32>
    end

[2014-11-20T18:35:17+00:00] INFO: Running queued delayed notifications before re-raising exception

Running handlers:
[2014-11-20T18:35:17+00:00] ERROR: Running exception handlers
Running handlers complete
[2014-11-20T18:35:17+00:00] ERROR: Exception handlers complete
[2014-11-20T18:35:17+00:00] FATAL: Stacktrace dumped to /var/chef/cache/chef-stacktrace.out
Chef Client failed. 0 resources updated in 1.322765293 seconds
[2014-11-20T18:35:17+00:00] ERROR: ruby_block[hosts] (my_cookbook::default line 31) had an error: ArgumentError: invalid byte sequence in US-ASCII
[2014-11-20T18:35:17+00:00] FATAL: Chef::Exceptions::ChildConvergeError: Chef run process exited unsuccessfully (exit code 1)

Just for testing i have edit /etc/hosts file entry using above code and it works! look like /etc/login.defs has something wired

chef-stacktrace.out

root@node04:/etc# cat /var/chef/cache/chef-stacktrace.out
Generated at 2014-11-20 18:51:45 +0000
ArgumentError: ruby_block[hosts] (my_cookbook::default line 31) had an error: ArgumentError: invalid byte sequence in US-ASCII
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/util/editor.rb:79:in `match'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/util/editor.rb:79:in `match'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/util/editor.rb:79:in `block in replace_lines'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/util/editor.rb:78:in `map!'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/util/editor.rb:78:in `replace_lines'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/util/file_edit.rb:46:in `search_file_replace_line'
/var/chef/cache/cookbooks/my_cookbook/recipes/default.rb:34:in `block (2 levels) in from_file'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/provider/ruby_block.rb:33:in `call'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/provider/ruby_block.rb:33:in `block in action_run'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/mixin/why_run.rb:52:in `call'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/mixin/why_run.rb:52:in `add_action'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/provider.rb:156:in `converge_by'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/provider/ruby_block.rb:32:in `action_run'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/provider.rb:121:in `run_action'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/resource.rb:648:in `run_action'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/runner.rb:49:in `run_action'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/runner.rb:81:in `block (2 levels) in converge'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/runner.rb:81:in `each'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/runner.rb:81:in `block in converge'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/resource_collection.rb:98:in `block in execute_each_resource'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/resource_collection/stepable_iterator.rb:116:in `call'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/resource_collection/stepable_iterator.rb:116:in `call_iterator_block'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/resource_collection/stepable_iterator.rb:85:in `step'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/resource_collection/stepable_iterator.rb:104:in `iterate'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/resource_collection/stepable_iterator.rb:55:in `each_with_index'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/resource_collection.rb:96:in `execute_each_resource'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/runner.rb:80:in `converge'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/client.rb:345:in `converge'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/client.rb:431:in `do_run'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/client.rb:213:in `block in run'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/client.rb:207:in `fork'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/client.rb:207:in `run'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/application.rb:236:in `run_chef_client'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/application/client.rb:338:in `block in run_application'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/application/client.rb:327:in `loop'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/application/client.rb:327:in `run_application'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/lib/chef/application.rb:55:in `run'
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.16.4/bin/chef-client:26:in `<top (required)>'
/usr/bin/chef-client:23:in `load'
3

There are 3 best solutions below

3
On BEST ANSWER

FileEdit as written can't handle multibyte encodings. You can either fix FileEdit and submit a patch to Chef, or just not use it. Easiest solution is to convert all of login.defs to a cookbook_file or template resource, thus removing the need for FileEdit.

0
On

The line cookbook is typically what we recommend.

The approach that @mrigesh-priyadarshi uses in his answer to read the file, do the string substitution and then pass it as content to the file provider, is also perfectly acceptable.

Which one to use probably comes down personal preference, and the complexity and subjective readability of either approach.

The Chef::Util::FileEdit approach above is not only poor for multibyte encodings but the ruby_block will fire every time and is not idempotent and it would not be possible to chain a notification off of it that would only fire if the file contents were actually changed.

0
On

Though its too late. But just, if anyone came here searching for solution for this kind of issue.

file '/etc/login.defs' do
   action :create
   owner 'root'
   group 'root'
   mode '0644'
   content File.read("/etc/login.defs").gsub(/^PASS_MAX_DAYS\t99999$/, "PASS_MAX_DAYS\t150")
end

Kitchen Test run:-

     * file[/etc/login.defs] action create
       - update content in file /etc/login.defs from 11fa3a to 3d7172
       --- /etc/login.defs  2014-02-12 14:03:08.000000000 +0000
       +++ /etc/.chef-login.defs20160805-12038-orbb2x   2016-08-05 11:09:40.007822562 +0000
       @@ -22,7 +22,7 @@
        #   PASS_MIN_LEN    Minimum acceptable password length.
        #   PASS_WARN_AGE   Number of days warning given before a password expires.
        #
       -PASS_MAX_DAYS   99999
       +PASS_MAX_DAYS   150
        PASS_MIN_DAYS   0
        PASS_MIN_LEN    5
        PASS_WARN_AGE   7
       - restore selinux security context