Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/ZirconCode/huginn into Zi…
Browse files Browse the repository at this point in the history
…rconCode-master
  • Loading branch information
cantino committed Apr 19, 2014
2 parents 8d5d629 + e78928a commit 317642a
Show file tree
Hide file tree
Showing 2 changed files with 171 additions and 0 deletions.
101 changes: 101 additions & 0 deletions app/models/agents/command_agent.rb
@@ -0,0 +1,101 @@
module Agents
class CommandAgent < Agent

require 'open3'


default_schedule "midnight"


description <<-MD
The CommandAgent can execute commands on your local system, returning the output.
`command` specifies the command to be executed, and `path` will tell CommandAgent in what directory to run this command.
`expected_update_period_in_days` is used to determine if the Agent is working.
CommandAgent can also act upon recieveing events. These events may contain their own path and command arguments. If they do not, CommandAgent will use the configured options. For this reason, please specify defaults even if you are planning to have this Agent respond to events.
The resulting event will contain the `command` which was executed, the `path` it was executed under, the `exit_status` of the command, the `errors`, and the actual `output`. CommandAgent will not log an error if the result implies that something went wrong.
*Warning*: Misuse of this Agent can pose a security threat.
MD

event_description <<-MD
Events look like this:
{
'command' => 'pwd',
'path' => '/home/Huginn',
'exit_status' => '0',
'errors' => '',
'output' => '/home/Huginn'
}
MD

def default_options
{
'path' => "/home",
'command' => "pwd",
'expected_update_period_in_days' => 1
}
end

def validate_options
unless options['path'].present? && options['command'].present? && options['expected_update_period_in_days'].present?
errors.add(:base, "The path, command, and expected_update_period_in_days fields are all required.")
end
unless File.directory?(options['path'])
errors.add(:base, "#{options['path']} is not a real directory.")
end
end

def working?
event_created_within?(options['expected_update_period_in_days']) && !recent_error_logs?
end

def exec_command(opts = options)
command = opts['command'] || options['command']
path = opts['path'] || options['path']

result = nil
errors = nil
exit_status = nil

Dir.chdir(path){
begin
stdin, stdout, stderr, wait_thr = Open3.popen3(command)
exit_status = wait_thr.value.to_i
result = stdout.gets(nil)
errors = stderr.gets(nil)
rescue Exception => e
errors = e.to_s
end
}

result.chomp! if result.is_a?(String)
result = '' if result.nil?
errors = '' if errors.nil?

vals = {"command" => command, "path" => path, "exit_status" => exit_status, "errors" => errors, "output" => result}
evnt = create_event :payload => vals

log("Ran '#{command}' under '#{path}'", :outbound_event => evnt)
end


def receive(incoming_events)
incoming_events.each do |event|
exec_command(event.payload)
end
end

def check
exec_command(options)
end


end
end
70 changes: 70 additions & 0 deletions spec/models/agents/command_agent_spec.rb
@@ -0,0 +1,70 @@
require 'spec_helper'

describe Agents::CommandAgent do

before do
@valid_path = Dir.pwd
@valid_params = {
:path => @valid_path,
:command => "pwd",
:expected_update_period_in_days => "1",
}

@checker = Agents::CommandAgent.new(:name => "somename", :options => @valid_params)
@checker.user = users(:jane)
@checker.save!

@event = Event.new
@event.agent = agents(:jane_weather_agent)
@event.payload = {
:command => "pwd"
}
@event.save!
end

describe "validation" do
before do
@checker.should be_valid
end

it "should validate presence of necessary fields" do
@checker.options[:command] = nil
@checker.should_not be_valid
end

it "should validate path" do
@checker.options[:path] = 'notarealpath/itreallyisnt'
@checker.should_not be_valid
end
end

describe "#working?" do
it "checks if its generating events as scheduled" do
@checker.should_not be_working
@checker.check
@checker.reload.should be_working
three_days_from_now = 3.days.from_now
stub(Time).now { three_days_from_now }
@checker.should_not be_working
end
end

describe "#check" do
it "should check that initial run creates an event" do
expect { @checker.check }.to change { Event.count }.by(1)
end
end

describe "#receive" do
it "checks if creates events" do
@checker.receive([@event])
Event.last.payload[:path].should == @valid_path
end
it "checks if options are taken from event" do
@event.payload[:command] = 'notarealcommand'
@checker.receive([@event])
Event.last.payload[:command].should == 'notarealcommand'
end
end

end

0 comments on commit 317642a

Please sign in to comment.