module Smith::AgentProcessObserver

Public Class Methods

acknowledge_start(agent_process, &blk) click to toggle source

FIXME: This doesn't appear to be being called.

# File lib/smith/agent_process.rb, line 204
def self.acknowledge_start(agent_process, &blk)
  logger.info { "Agent started: #{agent_process.name}, UUID: #{agent_process.uuid}, PID: #{agent_process.pid}" }
end
acknowledge_stop(agent_process) click to toggle source
# File lib/smith/agent_process.rb, line 226
def self.acknowledge_stop(agent_process)
  agent_process.delete
  logger.info { "Agent stopped: #{agent_process.name}, UUID: #{agent_process.uuid}, PID: #{agent_process.pid}" }
end
kill(agent_process) click to toggle source

This needs to use the PID class to verify if an agent is still running. FIXME

# File lib/smith/agent_process.rb, line 233
def self.kill(agent_process)
  if agent_process.pid
    if agent_process.pid == 0
      logger.info { "Agent's pid is 0. The agent probably didn't start correctly. Cleaning up." }
      agent_process.delete
    else
      logger.info { "Sending signal: TERM, #{agent_process.name}, UUID: #{agent_process.uuid}, PID: #{agent_process.pid}" }

      begin
        Process.kill('TERM', agent_process.pid)
      rescue
        logger.error { "Process does not exist. PID is stale: #{agent_process.pid}: #{agent_process.uuid}" }
      end
    end
  else
    logger.error { "Not sending kill signal, agent pid is not set: #{agent_process.uuid}" }
  end
  agent_process.delete
end
no_process_running(agent_process) click to toggle source
# File lib/smith/agent_process.rb, line 221
def self.no_process_running(agent_process)
  agent_process.delete
end
reap_agent(agent_process) click to toggle source

If an agent is in an unknown state then this will check to see if the process is still alive and if it is kill it, otherwise log a message. TODO this is not really a reaper but I haven't quite worked out what I'm going to do with it so I'll leave it as is

# File lib/smith/agent_process.rb, line 258
def self.reap_agent(agent_process)
  logger.info { "Reaping agent: #{agent_process.uuid}" }
  if Pathname.new('/proc').join(agent_process.pid.to_s).exist?
    logger.warn { "Agent is still alive: #{agent_process.uuid}" }
  else
    logger.warn { "Agent is already dead: #{agent_process.uuid}" }
  end
end
start(agent_process) click to toggle source
# File lib/smith/agent_process.rb, line 161
def self.start(agent_process)
  if agent_process.exists?
    agent_process.check
  else
    agent_process.delete
  end
end
start_process(agent_process) click to toggle source

Start an agent. This forks and execs the bootstrapper class which then becomes responsible for managing the agent process.

# File lib/smith/agent_process.rb, line 171
def self.start_process(agent_process)
  pid = fork do
    # Detach from the controlling terminal
    unless Process.setsid
      raise 'Cannot detach from controlling terminal'
    end

    # Close all file descriptors apart from stdin, stdout, stderr
    ObjectSpace.each_object(IO) do |io|
      unless [STDIN, STDOUT, STDERR].include?(io)
        io.close unless io.closed?
      end
    end

    # Sort out the remaining file descriptors. Don't do anything with
    # stdout (and by extension stderr) as want the agency to manage it.
    STDIN.reopen("/dev/null")
    STDERR.reopen(STDOUT)

    bootstrapper = Pathname.new(__FILE__).dirname.join('bootstrap.rb').expand_path

    binary = Smith.config.vm[agent_process.name.snake_case.to_sym] || Smith.config.vm.agent_default
    logger.debug { "Launching #{agent_process.name} with: #{binary}" }
    exec(binary, bootstrapper.to_s, agent_process.name, agent_process.uuid)
  end

  logger.info { "Detaching: #{agent_process.name}, UUID: #{agent_process.uuid}, PID: #{pid}" }

  # We don't want any zombies.
  Process.detach(pid)
end
stop(agent_process) click to toggle source
# File lib/smith/agent_process.rb, line 208
def self.stop(agent_process)
  Messaging::Sender.new(agent_process.control_queue_def) do |sender|
    sender.consumer_count do |count|
      if count > 0
        sender.publish(ACL::AgentCommand.new(:command => 'stop'))
      else
        logger.warn { "Agent is not listening. Setting state to dead: #{agent_process.name}, UUID: #{agent_process.uuid}, PID: #{agent_process.pid}" }
        agent_process.no_process_running
      end
    end
  end
end