jah 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.sw?
2
+ *.log
3
+ .DS_Store
4
+ coverage
5
+ rdoc
6
+ pkg
7
+ jah.yaml
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Marcos Piccinini
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,115 @@
1
+ # ![Jah](http://fireho.com/system/jahlogo.png)
2
+
3
+ Talk to your machines. Like a god.
4
+
5
+ ## Install
6
+
7
+ Just run it for the first time to create a config file.
8
+ Use `jah install` to force the wizard again.
9
+
10
+ Gems needed for XMPP mode:
11
+
12
+ * EventMachine (gem install eventmachine)
13
+ * Blather (gem install blather)
14
+
15
+
16
+ Jah will try to find a `jah.yaml` file on ~/.jah or /etc.
17
+
18
+
19
+ ## Modes
20
+
21
+ ### XMPP
22
+
23
+ Chat with your server with your favorite XMPP client (pidgin, adium..)
24
+ Receive reports and failures realtime!
25
+ Send commands and
26
+
27
+
28
+ ### POST
29
+
30
+ The old school way. Set up a Jah Web Server, and give Jah it`s address.
31
+ Jah will periodically post info. You can send commands through SSH.
32
+
33
+
34
+ ### DUMP
35
+
36
+ AkA: Security freak. Jah just writes to tmp/ or whatever a dump file,
37
+ Jah Web securely connects (scp) and downloads the data to parse.
38
+
39
+
40
+ ## Use God?
41
+
42
+
43
+ ## XMPP Bot
44
+
45
+
46
+ Execute sh commands:
47
+
48
+ pwd
49
+ $> /home/jah
50
+
51
+
52
+ Executing ruby statements:
53
+
54
+ ! 2 + 2
55
+ => 4
56
+
57
+ ! def foo; "hi"; end
58
+ ! foo
59
+ => "hi"
60
+
61
+
62
+ Execute Jah commands:
63
+
64
+ cpu?
65
+ msweet: 0.14, 0.25, 0.14
66
+
67
+ mem?
68
+ msweet: 53%
69
+
70
+ net?
71
+ 7 connections
72
+ [ips...]
73
+
74
+ ok?
75
+ [Personalized cool phrase...]
76
+
77
+
78
+ Group session:
79
+
80
+ me: ok?
81
+ msweet: I'm fine, thanks..
82
+ ssaint: Kinda busy right now..
83
+ naomi: I need you! Now!
84
+
85
+
86
+ Execute God statements:
87
+
88
+ Start, stop, restart, monitor and unmonitor words on the beginning
89
+ of a phrase will make Jah add a "god" on the front of it, making it
90
+ trivial to work with your services:
91
+
92
+
93
+ start nginx
94
+ restart nanites
95
+ unmonitor postgresql
96
+
97
+
98
+ More to come...
99
+
100
+
101
+
102
+ ## Note on Patches/Pull Requests
103
+
104
+ * Fork the project.
105
+ * Make your feature addition or bug fix.
106
+ * Add tests for it. This is important so I don't break it in a
107
+ future version unintentionally.
108
+ * Commit, do not mess with rakefile, version, or history.
109
+ (if you want to have your own version, that is fine but
110
+ bump version in a commit by itself I can ignore when I pull)
111
+ * Send me a pull request. Bonus points for topic branches.
112
+
113
+ ## Copyright
114
+
115
+ Copyright (c) 2009 Marcos Piccinini. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,75 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "jah"
8
+ gem.summary = "be omnipresent..."
9
+ gem.description = "talk to your machines"
10
+ gem.email = "x@nofxx.com"
11
+ gem.homepage = "http://github.com/nofxx/jah"
12
+ gem.authors = ["Marcos Piccinini"]
13
+ gem.add_dependency "blather"
14
+ gem.add_dependency "i18n"
15
+ gem.add_development_dependency "rspec"
16
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
+ end
18
+ rescue LoadError
19
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
20
+ end
21
+
22
+ require 'spec/rake/spectask'
23
+ Spec::Rake::SpecTask.new(:spec) do |spec|
24
+ spec.libs << 'lib' << 'spec'
25
+ spec.spec_files = FileList['spec/**/*_spec.rb']
26
+ end
27
+
28
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
29
+ spec.libs << 'lib' << 'spec'
30
+ spec.pattern = 'spec/**/*_spec.rb'
31
+ spec.rcov = true
32
+ end
33
+
34
+ task :spec => :check_dependencies
35
+ task :default => :spec
36
+
37
+ begin
38
+ require 'reek/rake_task'
39
+ Reek::RakeTask.new do |t|
40
+ t.fail_on_error = true
41
+ t.verbose = false
42
+ t.source_files = 'lib/**/*.rb'
43
+ end
44
+ rescue LoadError
45
+ task :reek do
46
+ abort "Reek is not available. In order to run reek, you must: sudo gem install reek"
47
+ end
48
+ end
49
+
50
+ begin
51
+ require 'roodi'
52
+ require 'roodi_task'
53
+ RoodiTask.new do |t|
54
+ t.verbose = false
55
+ end
56
+ rescue LoadError
57
+ task :roodi do
58
+ abort "Roodi is not available. In order to run roodi, you must: sudo gem install roodi"
59
+ end
60
+ end
61
+
62
+
63
+ require 'rake/rdoctask'
64
+ Rake::RDocTask.new do |rdoc|
65
+ if File.exist?('VERSION')
66
+ version = File.read('VERSION')
67
+ else
68
+ version = ""
69
+ end
70
+
71
+ rdoc.rdoc_dir = 'rdoc'
72
+ rdoc.title = "jah #{version}"
73
+ rdoc.rdoc_files.include('README*')
74
+ rdoc.rdoc_files.include('lib/**/*.rb')
75
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.3
data/bin/jah ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $VERBOSE = true # -w
4
+ $KCODE = "u" # -Ku
5
+
6
+ $LOAD_PATH << File.join(File.dirname(__FILE__), *%w[.. lib])
7
+ require "jah"
8
+
9
+ Jah::Cli.dispatch(ARGV)
data/jah.gemspec ADDED
@@ -0,0 +1,89 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{jah}
8
+ s.version = "0.0.3"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Marcos Piccinini"]
12
+ s.date = %q{2009-09-29}
13
+ s.default_executable = %q{jah}
14
+ s.description = %q{talk to your machines}
15
+ s.email = %q{x@nofxx.com}
16
+ s.executables = ["jah"]
17
+ s.extra_rdoc_files = [
18
+ "LICENSE",
19
+ "README.md"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ ".gitignore",
24
+ "LICENSE",
25
+ "README.md",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "bin/jah",
29
+ "jah.gemspec",
30
+ "lib/jah.rb",
31
+ "lib/jah.yaml.template",
32
+ "lib/jah/agent.rb",
33
+ "lib/jah/agents/dump.rb",
34
+ "lib/jah/agents/post.rb",
35
+ "lib/jah/agents/xmpp.rb",
36
+ "lib/jah/cli.rb",
37
+ "lib/jah/collector.rb",
38
+ "lib/jah/collectors/cpu.rb",
39
+ "lib/jah/collectors/disk.rb",
40
+ "lib/jah/collectors/mem.rb",
41
+ "lib/jah/collectors/net.rb",
42
+ "lib/jah/collectors/prok.rb",
43
+ "lib/jah/collectors/services.rb",
44
+ "lib/jah/collectors/who.rb",
45
+ "lib/jah/command.rb",
46
+ "lib/jah/commands/admin.rb",
47
+ "lib/jah/commands/extra.rb",
48
+ "lib/jah/commands/pub.rb",
49
+ "lib/jah/commands/status.rb",
50
+ "lib/jah/god.rb",
51
+ "lib/jah/install.rb",
52
+ "lib/locales/en_us.yml",
53
+ "lib/locales/pt_br.yml",
54
+ "lib/locales/pt_br_gostosa.yml",
55
+ "lib/locales/pt_br_mano.yml",
56
+ "lib/locales/pt_br_mineiro.yml",
57
+ "spec/console",
58
+ "spec/jah_spec.rb",
59
+ "spec/spec_helper.rb"
60
+ ]
61
+ s.homepage = %q{http://github.com/nofxx/jah}
62
+ s.rdoc_options = ["--charset=UTF-8"]
63
+ s.require_paths = ["lib"]
64
+ s.rubygems_version = %q{1.3.5}
65
+ s.summary = %q{be omnipresent...}
66
+ s.test_files = [
67
+ "spec/jah_spec.rb",
68
+ "spec/spec_helper.rb"
69
+ ]
70
+
71
+ if s.respond_to? :specification_version then
72
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
73
+ s.specification_version = 3
74
+
75
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
76
+ s.add_runtime_dependency(%q<blather>, [">= 0"])
77
+ s.add_runtime_dependency(%q<i18n>, [">= 0"])
78
+ s.add_development_dependency(%q<rspec>, [">= 0"])
79
+ else
80
+ s.add_dependency(%q<blather>, [">= 0"])
81
+ s.add_dependency(%q<i18n>, [">= 0"])
82
+ s.add_dependency(%q<rspec>, [">= 0"])
83
+ end
84
+ else
85
+ s.add_dependency(%q<blather>, [">= 0"])
86
+ s.add_dependency(%q<i18n>, [">= 0"])
87
+ s.add_dependency(%q<rspec>, [">= 0"])
88
+ end
89
+ end
data/lib/jah/agent.rb ADDED
@@ -0,0 +1,128 @@
1
+ require 'socket'
2
+ require 'net/https'
3
+ require 'net/http'
4
+ require 'zlib'
5
+ require 'stringio'
6
+ # require 'eventmachine'
7
+
8
+ module Jah
9
+ class Agent
10
+ PID_FILE = File.join("/tmp", "jah.pid")
11
+ autoload :XmppAgent, "jah/agents/xmpp"
12
+ autoload :PostAgent, "jah/agents/xmpp"
13
+ autoload :DumpAgent, "jah/agents/xmpp"
14
+
15
+ def initialize(options=nil)#, config)
16
+ if Jah.daemon?
17
+ puts "Jah starting in background.."
18
+ fork do
19
+ daemonize
20
+ run_agent_run
21
+ end
22
+ exit
23
+ end
24
+ run_agent_run
25
+ end
26
+
27
+ def pid_file
28
+ @pidfile ||= PID_FILE
29
+ end
30
+
31
+ def run_agent_run
32
+ case Jah.mode # @mode
33
+ when "xmpp" then XmppAgent.new.run
34
+ when "post" then PostAgent.new.run
35
+ else
36
+ DumpAgent.new
37
+ end
38
+ end
39
+
40
+ def self.start
41
+ new
42
+ end
43
+
44
+ def self.stop
45
+ if File.exists?(PID_FILE)
46
+ pid = File.read(PID_FILE)
47
+ puts "Stopping #{pid}"
48
+ `kill #{pid}`
49
+ else
50
+ puts "Jah not running..."
51
+ exit
52
+ end
53
+ end
54
+
55
+ def self.restart
56
+ stop
57
+ start
58
+ end
59
+
60
+ def self.install
61
+ Install.new
62
+ end
63
+
64
+ def daemonize
65
+ begin
66
+ File.open(pid_file, File::CREAT|File::EXCL|File::WRONLY) do |pid|
67
+ pid.puts $$
68
+ end
69
+ at_exit do
70
+ begin
71
+ File.unlink(pid_file)
72
+ rescue
73
+ Log.error "Unable to unlink pid file: #{$!.message}"
74
+ end
75
+ end
76
+ rescue
77
+ pid = File.read(pid_file).strip.to_i rescue "unknown"
78
+ running = true
79
+ begin
80
+ Process.kill(0, pid)
81
+ if stat = File.stat(pid_file)
82
+ if mtime = stat.mtime
83
+ if Time.now - mtime > 25 * 60 # assume process is hung after 25m
84
+ Log.info "Trying to KILL an old process..."
85
+ Process.kill("KILL", pid)
86
+ running = false
87
+ end
88
+ end
89
+ end
90
+ rescue Errno::ESRCH
91
+ running = false
92
+ rescue
93
+ # do nothing, we didn't have permission to check the running process
94
+ end
95
+ if running
96
+ if pid == "unknown"
97
+ Log.warn "Could not create or read PID file. " +
98
+ "You may need to the path to the config directory. " +
99
+ "See: http://scoutapp.com/help#data_file"
100
+ else
101
+ Log.warn "Process #{pid} was already running"
102
+ end
103
+ exit
104
+ else
105
+ Log.info "Stale PID file found. Clearing it and reloading..."
106
+ File.unlink(pid_file) rescue nil
107
+ retry
108
+ end
109
+ end
110
+
111
+ self
112
+ end
113
+ end
114
+
115
+
116
+ # def do_something!
117
+ # if @mode == :online
118
+ # puts "online"
119
+ # post(@config[:server], nil, format_out)
120
+ # else
121
+ # puts "Writing log.."
122
+ # f = open("/tmp/jah.txt", "a")
123
+ # f.write(format_out)
124
+ # f.close
125
+ # end
126
+ # end
127
+
128
+ end
@@ -0,0 +1,5 @@
1
+ module Jah
2
+ class DumpAgent
3
+
4
+ end
5
+ end
@@ -0,0 +1,18 @@
1
+
2
+ module Jah
3
+ class PostAgent
4
+
5
+
6
+ def post(url, error, body, headers = Hash.new, &response_handler)
7
+ return unless url
8
+ request(url, response_handler, error) do |connection|
9
+ post = Net::HTTP::Post.new( url.path +
10
+ (url.query ? ('?' + url.query) : ''),
11
+ HTTP_HEADERS.merge(headers) )
12
+ post.body = body
13
+ connection.request(post)
14
+ end
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,194 @@
1
+ require "eventmachine"#autoload :Client,
2
+ require "blather/client/client"
3
+
4
+ module Jah
5
+ # include Blather::DSL
6
+ class XmppAgent
7
+ ROSTER = []
8
+ attr_reader :client
9
+
10
+
11
+ def initialize #(jid, key, server, port=5222, debug=false, report=0)
12
+ Blather.logger.level = Logger::DEBUG if Jah.debug
13
+ @report = Jah.report
14
+ @client = Blather::Client.setup Jah.jid, Jah.key, Jah.server, Jah.port
15
+ setup
16
+ self
17
+ end
18
+
19
+ def process_message(to, msg, type = :chat)
20
+ if comm = Jah::Command.find(msg)
21
+ puts "Commmand => #{comm} | #{msg}"
22
+ args = msg.split(" ")
23
+ body = comm[2].send(comm[0], *args[1..-1])
24
+ else
25
+ keywords = %w{ start stop restart monitor unmonitor }
26
+ kind = :god if msg =~ /#{keywords.join("|")}/
27
+ kind ||= msg =~ /^\!/ ? :ruby : :sh
28
+ body = case kind
29
+ when :ruby
30
+ puts "Executing ruby command => #{msg}"
31
+ "=> #{execute_ruby(msg)}"
32
+ when :sh
33
+ puts "Executing *sh command => #{msg}"
34
+ "$> #{execute_sh(msg)}"
35
+ when :god
36
+ puts "Executing god command => #{msg}"
37
+ "G> #{execute_sh('god ' + msg)}"
38
+ else "dunno what to do...."
39
+ end
40
+ end
41
+ #beautify(body)
42
+ [ Blather::Stanza::Message.new(to, body, type)]
43
+ rescue => e
44
+ "Something is wrong.. #{e}\n#{e.backtrace.join("\n")}"
45
+ end
46
+
47
+ # Naive.... to be improved
48
+ def execute_ruby(code)
49
+ keywords = / class | module | def | do | while | for /
50
+ if code =~ keywords
51
+ return "Unmatched ends" if code.scan(keywords).length != code.scan(/end(\s|$)/).length
52
+ end
53
+ return "Unmatched.." if code.scan(/\{|\(|\[/).length != code.scan(/\}|\)|\]/).length
54
+ return "Unmatched quotes.." if code.scan(/\"|\'/).length % 2 != 0
55
+ begin
56
+ eval(code[1..-1]) || "nil"
57
+ rescue => e
58
+ "Fail => #{e}"
59
+ end
60
+ end
61
+
62
+ def execute_sh(code)
63
+ return I18n.t(:no_sudo) if code =~ /sudo/
64
+ res = `#{code}`.chomp
65
+ ex = $?.exitstatus
66
+ if ex != 0
67
+ res << I18n.t(:exit_code, :ex => ex.to_s)
68
+ else
69
+ res = "\n" + res unless res.split("\n").length < 2
70
+ end
71
+ res
72
+ end
73
+
74
+ #TODO: need to write raw....
75
+ def beautify(txt)
76
+ #txt.gsub!(/\*(.*)\*/, "<span style=\"font-weight: bold;\">\\1</span>")
77
+ #txt.gsub!(/\/(.*)\//, "<em>\\1</em>") # Italic
78
+ #txt.gsub!(/\_(.*)\_/, "<span style=\"font-decoration: underline;\">\\1</span>")
79
+ #txt.gsub!(/\-(.*)\-/, "<span style=\"font-decoration: line-through;\">\\1</span>")
80
+ # <span style="font-size: large;">ok?</span>
81
+ # <span style="color: #FF0000;">ok?</span>
82
+ txt
83
+ end
84
+
85
+ # [:iq, :query, :roster, :disco_info, :disco_items, :message, :presence,
86
+ # :status, :subscription, :pubsub_node, :pubsub_affiliations,
87
+ # :pubsub_create, :pubsub_event, :pubsub_items, :pubsub_publish,
88
+ # :pubsub_retract, :pubsub_subscribe, :pubsub_subscription,
89
+ # :pubsub_subscriptions, :pubsub_unsubscribe, :pubsub_owner,
90
+ # :pubsub_delete, :pubsub_purge]
91
+
92
+
93
+ def setup
94
+ # return if client && client.setup?
95
+ client.register_handler(:ready) do
96
+ puts "Connected!"
97
+ ROSTER << [client.roster.items.keys, Jah.groups].flatten.uniq
98
+ ROSTER.flatten!
99
+ ROSTER.select { |j| j =~ /\@conference\./ }.each do |c|
100
+ presence = Blather::Stanza::Presence.new
101
+ presence.to = "#{c}/#{Jah.hostname}"
102
+ client.write presence
103
+ end
104
+ end
105
+
106
+ client.register_handler :subscription, :request? do |s|
107
+ if ROSTER.include?(s.from.stripped.to_s)
108
+ puts "[REQUEST] Approve #{s}"
109
+ client.write s.approve!
110
+ else
111
+ puts "[REQUEST] Refuse #{s}"
112
+ client.write s.refuse!
113
+ end
114
+ end
115
+
116
+ # client.register_handler :message, :chat?, :body => 'exit' do |m|
117
+ # client.write Blather::Stanza::Message.new(m.from, 'Exiting...')
118
+ # client.close
119
+ # end
120
+ #client.register_handler :roster, [],
121
+ #client.register_handler :message, :error?, :body do |m|
122
+ #client.register_handler :message, :headline?, :body do |m|
123
+ #client.register_handler :message, :normal?, :body do |m|
124
+
125
+ client.register_handler :pubsub_event, :items do |m|
126
+ puts "[PUBSUB] => #{m.inspect}"
127
+ client.write m.body
128
+ end
129
+
130
+ client.register_handler :message, :groupchat? do |m|
131
+ if m.body =~ /^!|^>|^\\/ && m.to_s !~ /x.*:delay/ #delay.nil?
132
+ puts "[GROUP] => #{m.inspect}"
133
+ for msg in process_message(m.from.stripped, m.body, :groupchat)
134
+ client.write msg
135
+ end
136
+ end
137
+ end
138
+
139
+ client.register_handler :message, :chat?, :body do |m|
140
+ if ROSTER.include?(m.from.stripped.to_s)
141
+ puts "[PVT] => #{m.inspect}"
142
+ for msg in process_message(m.from, m.body)
143
+ client.write msg
144
+ end
145
+ end
146
+ end
147
+
148
+ end
149
+
150
+
151
+ def run
152
+ puts "Starting Jah Client...#{client.jid.stripped}"
153
+ trap(:INT) { EM.stop }
154
+ trap(:TERM) { EM.stop }
155
+
156
+ EM.run do
157
+ client.run
158
+ if @report != 0
159
+ puts "will report..."
160
+ EM.add_periodic_timer(@report) do
161
+ puts " I'm ok.. "
162
+ client.write Blather::Stanza::Message.new(
163
+ "nofxx@Jah.host.com", Jah::Collector.quick_results)
164
+ end
165
+ end
166
+
167
+ end
168
+
169
+
170
+ end
171
+
172
+ end
173
+
174
+ end
175
+
176
+
177
+ # # when_ready do
178
+ # # roster.grouped.each do |group, items|
179
+ # # puts "#{'*'*3} #{group || 'Ungrouped'} #{'*'*3}"
180
+ # # items.each { |item| puts "- #{item.name} (#{item.jid})" }
181
+ # # puts
182
+ # # end
183
+ # # shutdown
184
+ # # end
185
+
186
+ # # message :chat?, :body do |m|
187
+ # # begin
188
+ # # say m.from, eval(m.body)
189
+ # # rescue => e
190
+ # # say m.from, e.inspect
191
+ # # end
192
+
193
+
194
+ # end