minicron 0.1.0

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.
Files changed (97) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +674 -0
  3. data/README.md +187 -0
  4. data/Rakefile +17 -0
  5. data/bin/minicron +26 -0
  6. data/lib/minicron.rb +179 -0
  7. data/lib/minicron/alert.rb +115 -0
  8. data/lib/minicron/alert/email.rb +50 -0
  9. data/lib/minicron/alert/pagerduty.rb +39 -0
  10. data/lib/minicron/alert/sms.rb +47 -0
  11. data/lib/minicron/cli.rb +367 -0
  12. data/lib/minicron/constants.rb +7 -0
  13. data/lib/minicron/cron.rb +192 -0
  14. data/lib/minicron/hub/app.rb +132 -0
  15. data/lib/minicron/hub/assets/app/application.js +151 -0
  16. data/lib/minicron/hub/assets/app/components/schedules.js +280 -0
  17. data/lib/minicron/hub/assets/app/controllers/executions.js +35 -0
  18. data/lib/minicron/hub/assets/app/controllers/hosts.js +129 -0
  19. data/lib/minicron/hub/assets/app/controllers/jobs.js +109 -0
  20. data/lib/minicron/hub/assets/app/controllers/schedules.js +80 -0
  21. data/lib/minicron/hub/assets/app/helpers.js +22 -0
  22. data/lib/minicron/hub/assets/app/models/execution.js +13 -0
  23. data/lib/minicron/hub/assets/app/models/host.js +15 -0
  24. data/lib/minicron/hub/assets/app/models/job.js +15 -0
  25. data/lib/minicron/hub/assets/app/models/job_execution_output.js +11 -0
  26. data/lib/minicron/hub/assets/app/models/schedule.js +32 -0
  27. data/lib/minicron/hub/assets/app/router.js +31 -0
  28. data/lib/minicron/hub/assets/app/routes/executions.js +36 -0
  29. data/lib/minicron/hub/assets/app/routes/hosts.js +42 -0
  30. data/lib/minicron/hub/assets/app/routes/index.js +9 -0
  31. data/lib/minicron/hub/assets/app/routes/jobs.js +52 -0
  32. data/lib/minicron/hub/assets/app/routes/schedules.js +37 -0
  33. data/lib/minicron/hub/assets/css/bootswatch.min.css +9 -0
  34. data/lib/minicron/hub/assets/css/main.scss +323 -0
  35. data/lib/minicron/hub/assets/fonts/glyphicons-halflings-regular.eot +0 -0
  36. data/lib/minicron/hub/assets/fonts/glyphicons-halflings-regular.svg +229 -0
  37. data/lib/minicron/hub/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
  38. data/lib/minicron/hub/assets/fonts/glyphicons-halflings-regular.woff +0 -0
  39. data/lib/minicron/hub/assets/fonts/lato-bold-700.woff +0 -0
  40. data/lib/minicron/hub/assets/fonts/lato-italic-400.woff +0 -0
  41. data/lib/minicron/hub/assets/fonts/lato-regular-400.woff +0 -0
  42. data/lib/minicron/hub/assets/js/ansi_up-1.1.1.min.js +6 -0
  43. data/lib/minicron/hub/assets/js/auth/ember-auth-9.0.7.min.js +2 -0
  44. data/lib/minicron/hub/assets/js/auth/ember-auth-request-jquery-1.0.3.min.js +1 -0
  45. data/lib/minicron/hub/assets/js/bootstrap-3.1.1.min.js +6 -0
  46. data/lib/minicron/hub/assets/js/ember-1.4.1.min.js +18 -0
  47. data/lib/minicron/hub/assets/js/ember-data-1.0.0-beta.7.f87cba88.min.js +10 -0
  48. data/lib/minicron/hub/assets/js/faye-browser-1.0.1.min.js +2 -0
  49. data/lib/minicron/hub/assets/js/handlebars-1.3.0.min.js +29 -0
  50. data/lib/minicron/hub/assets/js/jquery-2.1.0.min.js +4 -0
  51. data/lib/minicron/hub/assets/js/moment-2.5.1.min.js +7 -0
  52. data/lib/minicron/hub/controllers/api/executions.rb +34 -0
  53. data/lib/minicron/hub/controllers/api/hosts.rb +150 -0
  54. data/lib/minicron/hub/controllers/api/job_execution_outputs.rb +30 -0
  55. data/lib/minicron/hub/controllers/api/jobs.rb +118 -0
  56. data/lib/minicron/hub/controllers/api/schedule.rb +184 -0
  57. data/lib/minicron/hub/controllers/index.rb +5 -0
  58. data/lib/minicron/hub/db/schema.rb +98 -0
  59. data/lib/minicron/hub/db/schema.sql +158 -0
  60. data/lib/minicron/hub/models/alert.rb +7 -0
  61. data/lib/minicron/hub/models/execution.rb +8 -0
  62. data/lib/minicron/hub/models/host.rb +7 -0
  63. data/lib/minicron/hub/models/job.rb +18 -0
  64. data/lib/minicron/hub/models/job_execution_output.rb +7 -0
  65. data/lib/minicron/hub/models/schedule.rb +25 -0
  66. data/lib/minicron/hub/serializers/execution.rb +75 -0
  67. data/lib/minicron/hub/serializers/host.rb +57 -0
  68. data/lib/minicron/hub/serializers/job.rb +104 -0
  69. data/lib/minicron/hub/serializers/job_execution_output.rb +48 -0
  70. data/lib/minicron/hub/serializers/schedule.rb +68 -0
  71. data/lib/minicron/hub/views/handlebars/application.erb +51 -0
  72. data/lib/minicron/hub/views/handlebars/errors.erb +29 -0
  73. data/lib/minicron/hub/views/handlebars/executions.erb +79 -0
  74. data/lib/minicron/hub/views/handlebars/hosts.erb +205 -0
  75. data/lib/minicron/hub/views/handlebars/jobs.erb +203 -0
  76. data/lib/minicron/hub/views/handlebars/loading.erb +3 -0
  77. data/lib/minicron/hub/views/handlebars/schedules.erb +354 -0
  78. data/lib/minicron/hub/views/index.erb +7 -0
  79. data/lib/minicron/hub/views/layouts/app.erb +15 -0
  80. data/lib/minicron/monitor.rb +116 -0
  81. data/lib/minicron/transport.rb +15 -0
  82. data/lib/minicron/transport/client.rb +80 -0
  83. data/lib/minicron/transport/faye/client.rb +103 -0
  84. data/lib/minicron/transport/faye/extensions/job_handler.rb +184 -0
  85. data/lib/minicron/transport/faye/server.rb +58 -0
  86. data/lib/minicron/transport/server.rb +62 -0
  87. data/lib/minicron/transport/ssh.rb +51 -0
  88. data/spec/invalid_config.toml +2 -0
  89. data/spec/minicron/cli_spec.rb +154 -0
  90. data/spec/minicron/transport/client_spec.rb +8 -0
  91. data/spec/minicron/transport/faye/client_spec.rb +53 -0
  92. data/spec/minicron/transport/server_spec.rb +70 -0
  93. data/spec/minicron/transport_spec.rb +13 -0
  94. data/spec/minicron_spec.rb +133 -0
  95. data/spec/spec_helper.rb +33 -0
  96. data/spec/valid_config.toml +48 -0
  97. metadata +577 -0
@@ -0,0 +1,51 @@
1
+ require 'net/ssh'
2
+
3
+ module Minicron
4
+ module Transport
5
+ class SSH
6
+ # Set all the options for the ssh instance
7
+ #
8
+ # @option options [String] the host to connect to
9
+ # @option options [Integer] the port number
10
+ # @option options [String] the path to the private key
11
+ def initialize(options = {})
12
+ @host = options[:host]
13
+ @port = options[:port]
14
+ @private_key = File.expand_path(options[:private_key])
15
+
16
+ # TODO: Make these configurable?
17
+ @user = `whoami`.strip
18
+ @auth_methods = ['publickey']
19
+ @host_key = 'ssh-rsa'
20
+ @timeout = 10
21
+ end
22
+
23
+ # Open the SSH connection
24
+ def open
25
+ @ssh = Net::SSH.start(
26
+ @host,
27
+ @user,
28
+ {
29
+ :port => @port,
30
+ :keys => [@private_key],
31
+ :auth_methods => @auth_methods,
32
+ :host_key => @host_key,
33
+ :timeout => @timeout
34
+ }
35
+ )
36
+ end
37
+
38
+ # Execute a command on the host and block until output is returned
39
+ #
40
+ # @param command [String]
41
+ def exec!(command)
42
+ @ssh.exec!(command)
43
+ end
44
+
45
+ # Close the SSH connection
46
+ def close
47
+ @ssh.close
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,2 @@
1
+ # Test invalid config file
2
+ £^$YEhtglkja
@@ -0,0 +1,154 @@
1
+ require 'spec_helper'
2
+
3
+ describe Minicron::CLI do
4
+ let(:server) { Minicron::Transport::Server.new }
5
+ let(:thin_server) { Thin::Server }
6
+
7
+ describe '#server' do
8
+ it 'should start the minicron server' #do
9
+ # server.should_receive(:start!)
10
+ # server.should_receive(:running?)
11
+ # server.should_receive(:server)
12
+ # thin_server.should_receive(:new).and_return Thin::Server
13
+ # Thin::Server.stub(:start)
14
+
15
+ # Minicron::CLI.new.run(['server'])
16
+ # end
17
+ end
18
+
19
+ describe '#run' do
20
+ before :each do
21
+ Minicron.parse_file_config('./default.config.toml')
22
+ end
23
+
24
+ context 'when in --dry-run mode' do
25
+ it 'should run a simple command and print the output to stdout' do
26
+ Minicron::CLI.new.run(['run', 'echo hello', '--dry-run', '--trace']) do |output|
27
+ expect(output.clean).to eq 'hello'
28
+ end
29
+ end
30
+
31
+ it 'should run a simple multi-line command and print the output to stdout' do
32
+ command_output = ''
33
+
34
+ Minicron::CLI.new.run(['run', 'echo "hello\nworld"', '--dry-run', '--trace']) do |output|
35
+ command_output += output
36
+ end
37
+
38
+ expect(command_output.clean).to eq `echo "hello\nworld"`.clean
39
+ end
40
+
41
+ context 'when a non-existent command is run' do
42
+ it 'should return an error' do
43
+ Minicron.capture_output :type => :stderr do
44
+ expect do
45
+ Minicron::CLI.new.run(['lol', '--trace'])
46
+ end.to raise_error SystemExit
47
+ end
48
+ end
49
+ end
50
+
51
+ context 'when no argument is passed to the run action' do
52
+ it 'should raise ArgumentError' do
53
+ Minicron.capture_output :type => :stderr do
54
+ expect do
55
+ Minicron::CLI.new.run(['run', '--dry-run', '--trace'])
56
+ end.to raise_error ArgumentError
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ context 'when in --dry-run mode with a valid --config file passed' do
63
+ it 'should run a simple command and print the output to stdout' do
64
+ Minicron::CLI.new.run(['run', 'echo hello', '--dry-run', '--trace', '--config', './default.config.toml']) do |output|
65
+ expect(output.clean).to eq 'hello'
66
+ end
67
+ end
68
+
69
+ it 'should run a simple multi-line command and print the output to stdout' do
70
+ command_output = ''
71
+
72
+ Minicron::CLI.new.run(['run', 'echo "hello\nworld"', '--dry-run', '--trace', '--config', './default.config.toml']) do |output|
73
+ command_output += output
74
+ end
75
+
76
+ expect(command_output.clean).to eq `echo "hello\nworld"`.clean
77
+ end
78
+
79
+ context 'when a non-existent command is run' do
80
+ it 'should return an error' do
81
+ Minicron.capture_output :type => :stderr do
82
+ expect do
83
+ Minicron::CLI.new.run(['lol', '--trace'])
84
+ end.to raise_error SystemExit
85
+ end
86
+ end
87
+ end
88
+
89
+ context 'when no argument is passed to the run action' do
90
+ it 'should raise ArgumentError' do
91
+ Minicron.capture_output :type => :stderr do
92
+ expect do
93
+ Minicron::CLI.new.run(['run', '--dry-run', '--trace', '--config', './default.config.toml'])
94
+ end.to raise_error ArgumentError
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+
101
+ describe '#run_command' do
102
+ context 'when in verbose mode' do
103
+ it 'a one line command should result in 7 total line' do
104
+ minicron = Minicron::CLI.new
105
+ minicron.disable_coloured_output!
106
+ output = ''
107
+
108
+ minicron.run_command('echo 1', :verbose => true) do |line|
109
+ output += line[:output]
110
+ end
111
+
112
+ expect(output.split("\n").length).to eq 7
113
+ end
114
+ end
115
+ end
116
+
117
+ describe '#coloured_output?' do
118
+ context 'when Rainbow is enabled' do
119
+ it 'should return true' do
120
+ Rainbow.enabled = true
121
+
122
+ expect(Minicron::CLI.new.coloured_output?).to eq true
123
+ end
124
+ end
125
+
126
+ context 'when Rainbow is disabled' do
127
+ it 'should return false' do
128
+ Rainbow.enabled = false
129
+
130
+ expect(Minicron::CLI.new.coloured_output?).to eq false
131
+ end
132
+ end
133
+ end
134
+
135
+ describe '#enable_coloured_output!' do
136
+ it 'should set Rainbow.enabled to true' do
137
+ minicron = Minicron::CLI.new
138
+ minicron.enable_coloured_output!
139
+
140
+ expect(Rainbow.enabled).to eq true
141
+ expect(minicron.coloured_output?).to eq true
142
+ end
143
+ end
144
+
145
+ describe '#disable_coloured_output!' do
146
+ it 'should set Rainbow.enabled to false' do
147
+ minicron = Minicron::CLI.new
148
+ minicron.disable_coloured_output!
149
+
150
+ expect(Rainbow.enabled).to eq false
151
+ expect(minicron.coloured_output?).to eq false
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe Minicron::Transport::Client do
4
+ describe '#setup' do
5
+ it 'should send a setup message and ensure its delivery' #do
6
+ #end
7
+ end
8
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe Minicron::Transport::FayeClient do
4
+ let(:client) { Minicron::Transport::FayeClient }
5
+ let(:eventmachine) { EM }
6
+
7
+ describe '#initialize' do
8
+ it 'should set the host and queue instance variable' do
9
+ client_instance = client.new('http', '127.0.0.1', '80', '/test')
10
+ expect(client_instance.url).to eq 'http://127.0.0.1:80/test'
11
+ expect(client_instance.queue).to eq({})
12
+ end
13
+ end
14
+
15
+ describe '#ensure_em_running' do
16
+ context 'when eventmachine is not running' do
17
+ it 'should start eventmachine' #do
18
+ # eventmachine.stub(:reactor_running?).and_return(false, true)
19
+ # eventmachine.stub(:run)
20
+ # eventmachine.should_receive(:reactor_running?).twice
21
+ # eventmachine.should_receive(:run).once
22
+
23
+ # client.new('http://127.0.0.1/test').ensure_em_running
24
+ # end
25
+ end
26
+
27
+ context 'when eventmachine is running' do
28
+ it 'should not start eventmachine' #do
29
+ # eventmachine.stub(:reactor_running?).and_return true
30
+ # eventmachine.should_receive(:reactor_running?).twice
31
+
32
+ # client.new('http://127.0.0.1/test').ensure_em_running
33
+ # end
34
+ end
35
+ end
36
+
37
+ describe '#ensure_delivery' do
38
+ before(:each) { eventmachine.stub(:stop) }
39
+ it 'should block until the queue hash is empty and return nil' do
40
+ client_instance = client.new('http', '127.0.0.1', '80', '/test')
41
+ client_instance.stub(:queue).and_return({ :a => 1 }, { :a => 1, :b => 2 }, { :b => 2 }, {})
42
+
43
+ client_instance.ensure_delivery
44
+ expect(client_instance.queue.length).to eq 0
45
+ end
46
+ end
47
+
48
+ describe '#tidy_up'
49
+ it 'should stop eventmachine' do
50
+ eventmachine.should_receive(:stop)
51
+ client.new('http', '127.0.0.1', '80', '/test').tidy_up
52
+ end
53
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ describe Minicron::Transport::Server do
4
+ let(:server) { Minicron::Transport::Server.new }
5
+ let(:thin_server) { Thin::Server }
6
+
7
+ describe '#start!' do
8
+ context 'when the server is running' do
9
+ it 'should return false' do
10
+ server.stub(:server).and_return thin_server
11
+ server.should_receive(:running?).and_return true
12
+
13
+ expect(server.start!('127.0.0.1', 1337, '/lol')).to eq false
14
+ end
15
+ end
16
+
17
+ context 'when the server is not running' do
18
+ it 'should return true' do
19
+ server.should_receive(:running?).and_return false
20
+ thin_server.should_receive(:new).and_return thin_server
21
+ thin_server.stub(:start)
22
+
23
+ expect(server.start!('127.0.0.1', 1337, '/lol')).to eq true
24
+ end
25
+ end
26
+ end
27
+
28
+ describe '#stop!' do
29
+ context 'when the server is not running' do
30
+ it 'should return false' do
31
+ server.should_receive(:running?).and_return false
32
+
33
+ expect(server.stop!).to eq false
34
+ end
35
+ end
36
+
37
+ context 'when the server is running' do
38
+ it 'should return true' do
39
+ server.should_receive(:running?).and_return true
40
+ server.should_receive(:server).and_return thin_server
41
+ server.should_receive(:server).and_return thin_server
42
+ thin_server.should_receive(:stop).and_return true
43
+
44
+ expect(server.stop!).to eq true
45
+ end
46
+ end
47
+ end
48
+
49
+ describe '#running?' do
50
+ context 'when the server is not running' do
51
+ it 'should return false' do
52
+ server.should_receive(:server).and_return thin_server
53
+ server.should_receive(:server).and_return thin_server
54
+ thin_server.should_receive(:running?).and_return false
55
+
56
+ expect(server.running?).to eq false
57
+ end
58
+ end
59
+
60
+ context 'when the server is running' do
61
+ it 'should return true' do
62
+ server.should_receive(:server).and_return thin_server
63
+ server.should_receive(:server).and_return thin_server
64
+ thin_server.should_receive(:running?).and_return true
65
+
66
+ expect(server.running?).to eq true
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Minicron::Transport do
4
+ describe '.get_job_hash' do
5
+ context 'when the correct params are passed' do
6
+ it 'should return a 32 char string (md5 hash)' do
7
+ hash = Minicron::Transport.get_job_hash('ls', 'server1')
8
+
9
+ expect(hash.length).to eq 32
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,133 @@
1
+ require 'spec_helper'
2
+
3
+ describe Minicron do
4
+ describe '.capture_output' do
5
+ context 'when :stdout is passed as an option' do
6
+ it 'should return a StringIO instance' do
7
+ output = Minicron.capture_output(:type => :stdout) do
8
+ $stdout.write 'I like turtles!'
9
+ end
10
+
11
+ expect(output).to be_an_instance_of StringIO
12
+ end
13
+ end
14
+
15
+ context 'when :stderr is passed as an option' do
16
+ it 'should return a StringIO instance' do
17
+ output = Minicron.capture_output(:type => :stderr) do
18
+ $stderr.write 'Quit yo jibber jabber, fool!'
19
+ end
20
+
21
+ expect(output).to be_an_instance_of StringIO
22
+ end
23
+ end
24
+
25
+ context 'when :both is passed as an option' do
26
+ it 'should return a Hash' do
27
+ output = Minicron.capture_output(:type => :both) do
28
+ $stdout.write 'I like turtles!'
29
+ $stderr.write 'Quit yo jibber jabber, fool!'
30
+ end
31
+
32
+ expect(output).to be_an_instance_of Hash
33
+ end
34
+ end
35
+
36
+ context 'when :both is passed as an option' do
37
+ it 'should return a Hash containing :stdout and :stderr with two StringIO instances' do
38
+ output = Minicron.capture_output(:type => :both) do
39
+ $stdout.write 'I like turtles!'
40
+ $stderr.write 'Quit yo jibber jabber, fool!'
41
+ end
42
+
43
+ expect(output).to have_key :stdout
44
+ expect(output).to have_key :stderr
45
+ expect(output[:stdout]).to be_an_instance_of StringIO
46
+ expect(output[:stderr]).to be_an_instance_of StringIO
47
+ end
48
+ end
49
+
50
+ context 'when an invalid :type is used' do
51
+ it 'should raise an ArgumentError' do
52
+ expect do
53
+ Minicron.capture_output(:type => :lol) do
54
+ $stdout.write 'I like turtles!'
55
+ $stderr.write 'Quit yo jibber jabber, fool!'
56
+ end
57
+ end.to raise_error ArgumentError
58
+ end
59
+ end
60
+ end
61
+
62
+ describe '.parse_file_config' do
63
+ context 'when a valid toml file is passed' do
64
+ it 'should update the config class variable with the toml file config' do
65
+ expected_valid_config = {
66
+ 'global' => {
67
+ 'verbose' => true,
68
+ 'trace' => false
69
+ },
70
+ 'client' => {
71
+ 'scheme' => 'http',
72
+ 'host' => '127.0.0.1',
73
+ 'port' => 9292,
74
+ 'path' => '/',
75
+ 'connect_timeout' => 5,
76
+ 'inactivity_timeout' => 5
77
+ },
78
+ 'server' => {
79
+ 'host' => '127.0.0.1',
80
+ 'port' => 9292,
81
+ 'path' => '/'
82
+ },
83
+ 'database' => {
84
+ 'type' => 'mysql',
85
+ 'host' => '127.0.0.1',
86
+ 'database' => 'minicron',
87
+ 'username' => 'minicron',
88
+ 'password' => 'password'
89
+ },
90
+ 'cli' => {
91
+ 'mode' => 'line',
92
+ 'dry_run' => false
93
+ },
94
+ 'alerts' => {
95
+ 'email' => {
96
+ 'enabled' => false,
97
+ 'smtp' => {
98
+ 'address' => 'localhost',
99
+ 'port' => 25
100
+ }
101
+ },
102
+ 'sms' => {
103
+ 'enabled' => false
104
+ },
105
+ 'pagerduty' => {
106
+ 'enabled' => false
107
+ }
108
+ }
109
+ }
110
+
111
+ parse_file_config = Minicron.parse_file_config('./spec/valid_config.toml')
112
+ expect(parse_file_config).to eq expected_valid_config
113
+ expect(Minicron.config).to eq expected_valid_config
114
+ end
115
+ end
116
+
117
+ context 'when an invalid toml file is passed' do
118
+ it 'should update the config class variable with the toml file config' do
119
+ expect do
120
+ Minicron.parse_file_config('./spec/invalid_config.toml')
121
+ end.to raise_error Exception
122
+ end
123
+ end
124
+
125
+ context 'when a non existent toml file is passed' do
126
+ it 'should update the config class variable with the toml file config' do
127
+ expect do
128
+ Minicron.parse_file_config('./nowhere/minicron.toml')
129
+ end.to raise_error Exception
130
+ end
131
+ end
132
+ end
133
+ end