[DRE-commits] [chef] 03/03: Converge via fork

Antonio Terceiro terceiro at moszumanska.debian.org
Sat Jun 13 18:47:30 UTC 2015


This is an automated email from the git hooks/post-receive script.

terceiro pushed a commit to branch patch-queue/debian/wheezy
in repository chef.

commit c37ae6f5b740d4e0ea19145765d42f1696d8d981
Author: Antonio Terceiro <terceiro at debian.org>
Date:   Sat Feb 21 23:30:49 2015 -0300

    Converge via fork
    
    contains bits and pieces of the following upstream commits:
    
    eab92691df5665994c888f3727eecc3577fb5f69
    3772ff9857e9fd69e2d5ea3339189d1143123c50
    d637073f6c53ff83c098a4f22598b77a7b975962
    07ea110f8694b5b3a36fb936e7eaa46a9ce86050
---
 lib/chef/application/client.rb |  8 ++++++--
 lib/chef/application/solo.rb   |  7 ++++++-
 lib/chef/client.rb             | 44 ++++++++++++++++++++++++++++++++++++++++++
 lib/chef/config.rb             |  1 +
 lib/chef/daemon.rb             | 17 +++++++++++++++-
 lib/chef/exceptions.rb         |  1 +
 6 files changed, 74 insertions(+), 4 deletions(-)

diff --git a/lib/chef/application/client.rb b/lib/chef/application/client.rb
index e6806c0..889192f 100644
--- a/lib/chef/application/client.rb
+++ b/lib/chef/application/client.rb
@@ -153,6 +153,12 @@ class Chef::Application::Client < Chef::Application
       }
     }
 
+  option :client_fork,
+    :short        => "-f",
+    :long         => "--fork",
+    :description  => "Fork client",
+    :boolean      => true
+
   attr_reader :chef_client_json
 
   def initialize
@@ -272,7 +278,6 @@ class Chef::Application::Client < Chef::Application
       rescue Exception => e
         if Chef::Config[:interval]
           Chef::Log.error("#{e.class}: #{e}")
-          Chef::Application.debug_stacktrace(e)
           Chef::Log.error("Sleeping for #{Chef::Config[:interval]} seconds before trying again")
           unless SELF_PIPE.empty?
             client_sleep Chef::Config[:interval]
@@ -282,7 +287,6 @@ class Chef::Application::Client < Chef::Application
           end
           retry
         else
-          Chef::Application.debug_stacktrace(e)
           Chef::Application.fatal!("#{e.class}: #{e.message}", 1)
         end
       ensure
diff --git a/lib/chef/application/solo.rb b/lib/chef/application/solo.rb
index 1844880..78ab57b 100644
--- a/lib/chef/application/solo.rb
+++ b/lib/chef/application/solo.rb
@@ -122,6 +122,12 @@ class Chef::Application::Solo < Chef::Application
       }
     }
 
+  option :client_fork,
+    :short        => "-f",
+    :long         => "--fork",
+    :description  => "Fork client",
+    :boolean      => true
+
   attr_reader :chef_solo_json
 
   def initialize
@@ -222,7 +228,6 @@ class Chef::Application::Solo < Chef::Application
           sleep Chef::Config[:interval]
           retry
         else
-          Chef::Application.debug_stacktrace(e)
           Chef::Application.fatal!("#{e.class}: #{e.message}", 1)
         end
       ensure
diff --git a/lib/chef/client.rb b/lib/chef/client.rb
index 55fc674..820d9d0 100644
--- a/lib/chef/client.rb
+++ b/lib/chef/client.rb
@@ -135,6 +135,49 @@ class Chef
     end
 
     # Do a full run for this Chef::Client.  Calls:
+    # * do_run
+    #
+    # This provides a wrapper around #do_run allowing the
+    # run to be optionally forked.
+    # === Returns
+    # boolean:: Return value from #do_run. Should always returns true.
+    def run
+      if(Chef::Config[:client_fork] && Process.respond_to?(:fork))
+        Chef::Log.info "Forking chef instance to converge..."
+        pid = fork do
+          client_solo = Chef::Config[:solo] ? "chef-solo" : "chef-client"
+          $0 = "#{client_solo} worker: ppid=#{Process.ppid};start=#{Time.new.strftime("%R:%S")};"
+          begin
+            Chef::Log.debug "Forked instance now converging"
+            do_run
+          rescue Exception => e
+            exit 1
+          else
+            exit 0
+          end
+        end
+        Chef::Log.debug "Fork successful. Waiting for new chef pid: #{pid}"
+        result = Process.waitpid2(pid)
+        handle_child_exit(result)
+        Chef::Log.debug "Forked child successfully reaped (pid: #{pid})"
+        true
+      else
+        do_run
+      end
+    end
+
+    def handle_child_exit(pid_and_status)
+      status = pid_and_status[1]
+      return true if status.success?
+      message = if status.signaled?
+        "Chef run process terminated by signal #{status.termsig} (#{Signal.list.invert[status.termsig]})"
+      else
+        "Chef run process exited unsuccessfully (exit code #{status.exitstatus})"
+      end
+      raise Exceptions::ChildConvergeError, message
+    end
+
+    # Do a full run for this Chef::Client.  Calls:
     #
     #  * run_ohai - Collect information about the system
     #  * build_node - Get the last known state, merge with local changes
@@ -171,6 +214,7 @@ class Chef
         run_status.stop_clock
         run_status.exception = e
         run_failed
+        Chef::Application.debug_stacktrace(e)
         Chef::Log.debug("Re-raising exception: #{e.class} - #{e.message}\n#{e.backtrace.join("\n  ")}")
         raise
       ensure
diff --git a/lib/chef/config.rb b/lib/chef/config.rb
index dce9631..3de9ff4 100644
--- a/lib/chef/config.rb
+++ b/lib/chef/config.rb
@@ -184,6 +184,7 @@ class Chef
     run_command_stdout_timeout 120
     solo  false
     splay nil
+    client_fork true
 
     # Set these to enable SSL authentication / mutual-authentication
     # with the server
diff --git a/lib/chef/daemon.rb b/lib/chef/daemon.rb
index bb5ccf7..d5814df 100644
--- a/lib/chef/daemon.rb
+++ b/lib/chef/daemon.rb
@@ -115,8 +115,23 @@ class Chef
     
       # Delete the PID from the filesystem
       def remove_pid_file
-        FileUtils.rm(pid_file) if File.exists?(pid_file)
+        if ! forked?
+          FileUtils.rm(pid_file) if File.exists?(pid_file)
+        end
       end
+
+      def forked?
+        if running? and Process.ppid == pid_from_file.to_i
+          # chef daemon is running and this process is a child of it
+          true
+        elsif not running? and Process.ppid == 1
+          # an orphaned fork, its parent becomes init, launchd, etc. after chef daemon dies
+          true
+        else
+          false
+        end
+      end
+
            
       # Change process user/group to those specified in Chef::Config
       #
diff --git a/lib/chef/exceptions.rb b/lib/chef/exceptions.rb
index 72c8b8f..9bb064f 100644
--- a/lib/chef/exceptions.rb
+++ b/lib/chef/exceptions.rb
@@ -34,6 +34,7 @@ class Chef
     class Override < RuntimeError; end
     class UnsupportedAction < RuntimeError; end
     class MissingLibrary < RuntimeError; end
+    class ChildConvergeError < RuntimeError; end
     class MissingRole < RuntimeError; end
     class CannotDetermineNodeName < RuntimeError; end
     class User < RuntimeError; end

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/chef.git



More information about the Pkg-ruby-extras-commits mailing list