react 0.0.1

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.md
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
22
+ *.gem
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Kriss Kowalik
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,74 @@
1
+ # React
2
+
3
+ React is a simple application that allows for remote execution of commands.
4
+ It uses Redis as a queue - it is blocking specified list and waits for new
5
+ entries - when an entry appears, then it is executing recognized command.
6
+
7
+ ## Inspiration
8
+
9
+ It's inspired by Simon Willson's example of "Queue-activated shell scripts"
10
+ in his redis-tutorial:
11
+
12
+ while [ 1 ] do
13
+ redis-cli blpop restart-httpd 0
14
+ apache2ctl graceful
15
+ done
16
+
17
+ ## Examples
18
+
19
+ Firs you have to prepare file with available commands. It can look like this:
20
+
21
+ # my_commands.yml
22
+ restart_httpd: |
23
+ apache2ctl graceful
24
+ restart_mysql: |
25
+ /etc/init.d/mysql restart
26
+ reboot: |
27
+ reboot
28
+
29
+ And now you can start consumer.
30
+
31
+ react my_commands.yml
32
+
33
+ ## Commands
34
+
35
+ While your consumer is working, you can push any of specified command to it's
36
+ queue (default queue name is `queue`), eg:
37
+
38
+ redis-cli lpush queue restart_httpd
39
+ redis-cli lpush queue reboot
40
+
41
+ ## Configuration
42
+
43
+ There are few more runtime options, which can be useful for you.
44
+
45
+ * you can specify queue wihch will be consumed:
46
+
47
+ react my_commands.yml --queue "my:queue:name"
48
+
49
+ * you can specify the database to which consumer should connect:
50
+
51
+ react my_commands.yml --host "yourhost.com" --port 6379 --db 2
52
+
53
+ * and finally, you can demonize the consumer:
54
+
55
+ react my_commands.yml --daemonize
56
+
57
+ ## Links
58
+
59
+ * [My website](http://nu7hatch.com/)
60
+ * [Simon Wilson's Redis tutorial](http://simonwillison.net/static/2010/redis-tutorial/)
61
+
62
+ ## Note on Patches/Pull Requests
63
+
64
+ * Fork the project.
65
+ * Make your feature addition or bug fix.
66
+ * Add tests for it. This is important so I don't break it in a
67
+ future version unintentionally.
68
+ * Commit, do not mess with rakefile, version, or history.
69
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
70
+ * Send me a pull request. Bonus points for topic branches.
71
+
72
+ ## Copyright
73
+
74
+ Copyright (c) 2010 Kriss Kowalik. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,54 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "react"
8
+ gem.version = "0.0.1"
9
+ gem.default_executable = 'react'
10
+ gem.executables = ['react']
11
+ gem.summary = %Q{Redis based remote command executor.}
12
+ gem.description = %Q{A simple application that allows for remote execution of commands.}
13
+ gem.email = "kriss.kowalik@gmail.com"
14
+ gem.homepage = "http://github.com/nu7hatch/react"
15
+ gem.authors = ["Kriss 'nu7hatch' Kowalik"]
16
+ gem.add_development_dependency "riot", ">= 0.11.3"
17
+ gem.add_dependency "daemons", ">= 0"
18
+ end
19
+ Jeweler::GemcutterTasks.new
20
+ rescue LoadError
21
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
22
+ end
23
+
24
+ require 'rake/testtask'
25
+ Rake::TestTask.new(:test) do |test|
26
+ test.libs << 'lib' << 'test'
27
+ test.pattern = 'test/**/*_test.rb'
28
+ test.verbose = true
29
+ end
30
+
31
+ begin
32
+ require 'rcov/rcovtask'
33
+ Rcov::RcovTask.new do |test|
34
+ test.libs << 'test'
35
+ test.pattern = 'test/**/*_test.rb'
36
+ test.verbose = true
37
+ end
38
+ rescue LoadError
39
+ task :rcov do
40
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
41
+ end
42
+ end
43
+
44
+ task :test => :check_dependencies
45
+
46
+ task :default => :test
47
+
48
+ require 'rake/rdoctask'
49
+ Rake::RDocTask.new do |rdoc|
50
+ rdoc.rdoc_dir = 'rdoc'
51
+ rdoc.title = "React"
52
+ rdoc.rdoc_files.include('README*')
53
+ rdoc.rdoc_files.include('lib/**/*.rb')
54
+ end
data/bin/react ADDED
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'react'
5
+ require 'optparse'
6
+ require 'daemons'
7
+
8
+ if ARGV.empty?
9
+ ARGV << '--help'
10
+ else
11
+ if File.exists?(ARGV[0])
12
+ options[:commands] = YAML.load_file(ARGV[0])
13
+ else
14
+ puts "ERROR: File not found: `#{ARGV[0]}`"
15
+ exit
16
+ end
17
+ end
18
+
19
+ options = {
20
+ :redis => {:host => '127.0.0.1', :port => 6379, :db => 0},
21
+ :commands => {},
22
+ :queue => 'queue'
23
+ }
24
+
25
+ opts = OptionParser.new do |opts|
26
+ opts.banner = "Usage: react commands.yml [options]"
27
+ opts.on('-q', '--queue [QUEUE]', 'Specify queue which will be consumed') {|val| val and options[:queue] = val }
28
+ opts.on('-h', '--host [HOST]', 'Select redis host') {|val| val and options[:redis][:host] = val }
29
+ opts.on('-p', '--port [PORT]', Integer, 'Select redis port') {|val| val and options[:redis][:port] = val }
30
+ opts.on('-D', '--db [DATABASE]', 'Select redis database number') {|val| val and options[:redis][:db] = val }
31
+ opts.on('-d', '--daemon', 'Run in background') { options[:daemon] = true }
32
+ end.parse(ARGV)
33
+
34
+ React.start(options).join
data/lib/react.rb ADDED
@@ -0,0 +1,101 @@
1
+ require 'redis'
2
+ require 'thread'
3
+
4
+ # React is a simple application that allows for remote execution of commands.
5
+ # It uses Redis as a queue - it is blocking specified list and waits for new
6
+ # entries - when an entry appears, then it is executing recognized command.
7
+ #
8
+ # == Inspiration
9
+ #
10
+ # It's inspired by Simon Willson's example of "Queue-activated shell scripts"
11
+ # in his redis-tutorial:
12
+ #
13
+ # while [ 1 ] do
14
+ # redis-cli blpop restart-httpd 0
15
+ # apache2ctl graceful
16
+ # done
17
+ #
18
+ # == Examples
19
+ #
20
+ # Firs you have to prepare file with available commands. It can look like this:
21
+ #
22
+ # # my_commands.yml
23
+ # restart_httpd: |
24
+ # apache2ctl graceful
25
+ # restart_mysql: |
26
+ # /etc/init.d/mysql restart
27
+ # reboot: |
28
+ # reboot
29
+ #
30
+ # Now you can start consumer.
31
+ #
32
+ # react my_commands.yml
33
+ #
34
+ # == Commands
35
+ #
36
+ # While your consumer is working, you can push any command to it's queue
37
+ # (default queue name is `queue`), eg:
38
+ #
39
+ # redis-cli lpush queue restart_httpd
40
+ # redis-cli lpush queue reboot
41
+ #
42
+ # == Configuration
43
+ #
44
+ # There are few more runtime options, which can be useful for you.
45
+ #
46
+ # # it will be consuming commands from specified queue
47
+ # react my_commands.yml --queue "my:queue:name"
48
+ #
49
+ # # you can specify the database to which React should connect
50
+ # react my_commands.yml --host "yourhost.com" --port 6379 --db 2
51
+ #
52
+ # # and finally, you can demonize your application
53
+ # react my_commands.yml --daemonize
54
+ module React
55
+
56
+ # It starts the consumer loop.
57
+ def self.start(conf)
58
+ @config = conf
59
+
60
+ puts "== Connected to #{redis.client.id}"
61
+ puts "== Waiting for commands from `#{@config[:queue]}`"
62
+
63
+ if @config[:daemon]
64
+ puts "== Daemonizing..."
65
+ Daemons.daemonize
66
+ end
67
+
68
+ loop do
69
+ begin
70
+ cid = redis.blpop(@config[:queue], 0)[1]
71
+ if cmd = @config[:commands][cid.to_s]
72
+ puts "\e[33m[#{Time.now}]\e[0m Reacting for `#{cid}` command"
73
+ threads.add(Thread.new { system(cmd) })
74
+ end
75
+ rescue Interrupt
76
+ puts "\nCleaning up..."
77
+ break
78
+ rescue Exception => ex
79
+ puts "ERROR: #{ex}"
80
+ end
81
+ end
82
+
83
+ self
84
+ end
85
+
86
+ # Returns group of executor threads.
87
+ def self.threads
88
+ @threads ||= ThreadGroup.new
89
+ end
90
+
91
+ # It joins all alive threads, and it's waiting till they will finish.
92
+ def self.join
93
+ threads.list.each {|t| t.join if t.alive? }
94
+ end
95
+
96
+ # Redis client instance.
97
+ def self.redis
98
+ @redis ||= Redis.new(@config[:redis])
99
+ end
100
+
101
+ end # React
data/react.gemspec ADDED
@@ -0,0 +1,59 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{react}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Kriss 'nu7hatch' Kowalik"]
12
+ s.date = %q{2010-08-16}
13
+ s.default_executable = %q{react}
14
+ s.description = %q{A simple application that allows remote execution of commands.}
15
+ s.email = %q{kriss.kowalik@gmail.com}
16
+ s.executables = ["react"]
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
+ "bin/react",
28
+ "lib/react.rb",
29
+ "react.gemspec",
30
+ "test/react_test.rb",
31
+ "test/teststrap.rb"
32
+ ]
33
+ s.homepage = %q{http://github.com/nu7hatch/react}
34
+ s.rdoc_options = ["--charset=UTF-8"]
35
+ s.require_paths = ["lib"]
36
+ s.rubygems_version = %q{1.3.6}
37
+ s.summary = %q{Redis based remote commands executor.}
38
+ s.test_files = [
39
+ "test/teststrap.rb",
40
+ "test/react_test.rb"
41
+ ]
42
+
43
+ if s.respond_to? :specification_version then
44
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
45
+ s.specification_version = 3
46
+
47
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
48
+ s.add_development_dependency(%q<riot>, [">= 0.11.3"])
49
+ s.add_runtime_dependency(%q<daemons>, [">= 0"])
50
+ else
51
+ s.add_dependency(%q<riot>, [">= 0.11.3"])
52
+ s.add_dependency(%q<daemons>, [">= 0"])
53
+ end
54
+ else
55
+ s.add_dependency(%q<riot>, [">= 0.11.3"])
56
+ s.add_dependency(%q<daemons>, [">= 0"])
57
+ end
58
+ end
59
+
@@ -0,0 +1 @@
1
+ require 'teststrap'
data/test/teststrap.rb ADDED
@@ -0,0 +1,6 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'rubygems'
5
+ require 'riot'
6
+ require 'react'
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: react
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Kriss 'nu7hatch' Kowalik
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-08-16 00:00:00 +02:00
18
+ default_executable: react
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: riot
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ - 11
30
+ - 3
31
+ version: 0.11.3
32
+ type: :development
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: daemons
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ version: "0"
44
+ type: :runtime
45
+ version_requirements: *id002
46
+ description: A simple application that allows remote execution of commands.
47
+ email: kriss.kowalik@gmail.com
48
+ executables:
49
+ - react
50
+ extensions: []
51
+
52
+ extra_rdoc_files:
53
+ - LICENSE
54
+ - README.md
55
+ files:
56
+ - .document
57
+ - .gitignore
58
+ - LICENSE
59
+ - README.md
60
+ - Rakefile
61
+ - bin/react
62
+ - lib/react.rb
63
+ - react.gemspec
64
+ - test/react_test.rb
65
+ - test/teststrap.rb
66
+ has_rdoc: true
67
+ homepage: http://github.com/nu7hatch/react
68
+ licenses: []
69
+
70
+ post_install_message:
71
+ rdoc_options:
72
+ - --charset=UTF-8
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ segments:
80
+ - 0
81
+ version: "0"
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ requirements: []
90
+
91
+ rubyforge_project:
92
+ rubygems_version: 1.3.6
93
+ signing_key:
94
+ specification_version: 3
95
+ summary: Redis based remote commands executor.
96
+ test_files:
97
+ - test/teststrap.rb
98
+ - test/react_test.rb