minicron 0.3 → 0.4

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +42 -33
  3. data/bin/minicron +3 -0
  4. data/lib/minicron.rb +12 -3
  5. data/lib/minicron/alert.rb +9 -6
  6. data/lib/minicron/cli.rb +15 -6
  7. data/lib/minicron/cli/commands.rb +35 -12
  8. data/lib/minicron/constants.rb +1 -1
  9. data/lib/minicron/cron.rb +71 -30
  10. data/lib/minicron/hub/app.rb +6 -0
  11. data/lib/minicron/hub/assets/app/components/schedules.js +1 -1
  12. data/lib/minicron/hub/assets/app/controllers/hosts.js +6 -2
  13. data/lib/minicron/hub/assets/app/controllers/jobs.js +5 -2
  14. data/lib/minicron/hub/assets/app/controllers/schedules.js +15 -13
  15. data/lib/minicron/hub/assets/app/models/host.js +1 -0
  16. data/lib/minicron/hub/assets/app/models/job.js +1 -0
  17. data/lib/minicron/hub/controllers/api/executions.rb +0 -1
  18. data/lib/minicron/hub/controllers/api/hosts.rb +12 -13
  19. data/lib/minicron/hub/controllers/api/job_execution_outputs.rb +0 -1
  20. data/lib/minicron/hub/controllers/api/jobs.rb +5 -3
  21. data/lib/minicron/hub/controllers/api/schedule.rb +3 -1
  22. data/lib/minicron/hub/db/schema.rb +8 -6
  23. data/lib/minicron/hub/db/schema.sql +4 -2
  24. data/lib/minicron/hub/views/handlebars/hosts.erb +18 -0
  25. data/lib/minicron/hub/views/handlebars/jobs.erb +18 -0
  26. data/lib/minicron/monitor.rb +14 -12
  27. data/lib/minicron/transport.rb +0 -1
  28. data/lib/minicron/transport/client.rb +19 -11
  29. data/lib/minicron/transport/faye/client.rb +16 -2
  30. data/lib/minicron/transport/faye/extensions/job_handler.rb +10 -4
  31. data/lib/minicron/transport/faye/server.rb +5 -4
  32. data/lib/minicron/transport/server.rb +9 -4
  33. data/lib/minicron/transport/ssh.rb +5 -4
  34. data/spec/minicron/alert/pagerduty_spec.rb +1 -0
  35. data/spec/minicron/alert/sms_spec.rb +1 -0
  36. data/spec/minicron/cli_spec.rb +1 -0
  37. data/spec/minicron/transport/client_spec.rb +1 -0
  38. data/spec/minicron/transport/faye/client_spec.rb +1 -0
  39. data/spec/minicron/transport/server_spec.rb +1 -0
  40. data/spec/minicron/transport_spec.rb +1 -0
  41. data/spec/minicron_spec.rb +6 -0
  42. metadata +88 -88
@@ -23,6 +23,10 @@ module Minicron::Hub
23
23
  # Disable internal middleware for presenting errors
24
24
  # as useful HTML pages
25
25
  set :show_exceptions, false
26
+
27
+ # Used to enable asset compression, currently nothing else
28
+ # relies on this
29
+ set :environment, :production
26
30
  end
27
31
 
28
32
  # Configure how we server assets
@@ -32,6 +36,8 @@ module Minicron::Hub
32
36
  serve '/fonts', :from => 'assets/fonts'
33
37
  serve '/app', :from => 'assets/app'
34
38
 
39
+ js_compression :simple
40
+
35
41
  # Set up the application css
36
42
  css :app, '/css/all.css', [
37
43
  '/css/bootswatch.min.css',
@@ -273,7 +273,7 @@
273
273
  });
274
274
  },
275
275
  cancel: function(schedule) {
276
- this.sendAction('cancel', schedule);
276
+ this.sendAction('cancel', this.get('job_id'));
277
277
  }
278
278
  }
279
279
  });
@@ -30,8 +30,10 @@
30
30
  // TODO: make this use a bootstrap model as a component
31
31
  var results = 'Test Results\n\n';
32
32
  results += 'connect: ' + data.connect + '\n';
33
- results += 'crontab readable: ' + data.read + '\n';
34
- results += 'crontab writeable: ' + data.write;
33
+ results += '/etc writeable: ' + data.etc.write + '\n';
34
+ results += '/etc executable: ' + data.etc.execute + '\n';
35
+ results += 'crontab readable: ' + data.crontab.read + '\n';
36
+ results += 'crontab writeable: ' + data.crontab.write;
35
37
 
36
38
  window.alert(results);
37
39
  } else {
@@ -73,6 +75,7 @@
73
75
  host = this.store.createRecord('host', {
74
76
  name: this.get('name'),
75
77
  fqdn: this.get('fqdn'),
78
+ user: this.get('user'),
76
79
  host: this.get('host'),
77
80
  port: this.get('port'),
78
81
  public_key: this.get('public_key')
@@ -101,6 +104,7 @@
101
104
  id: this.get('id'),
102
105
  name: this.get('name'),
103
106
  fqdn: this.get('fqdn'),
107
+ user: this.get('user'),
104
108
  host: this.get('host'),
105
109
  port: this.get('port'),
106
110
  public_key: this.get('public_key')
@@ -32,13 +32,15 @@
32
32
  Minicron.JobsNewController = Ember.ObjectController.extend({
33
33
  save_button: 'Save',
34
34
  job_name: null,
35
+ job_user: null,
35
36
  job_command: null,
36
37
  actions: {
37
38
  save: function() {
38
39
  var self = this,
39
40
  job = this.store.createRecord('job', {
40
41
  name: this.get('job_name'),
41
- command: this.get('job_command'),
42
+ user: this.get('job_user'),
43
+ command: this.get('job_command')
42
44
  });
43
45
  // Let the user know the job is being saved
44
46
  this.set('save_button', 'Saving..');
@@ -86,7 +88,8 @@
86
88
  var self = this,
87
89
  job = this.store.push('job', {
88
90
  id: this.get('id'),
89
- name: this.get('name')
91
+ name: this.get('name'),
92
+ user: this.get('user')
90
93
  });
91
94
 
92
95
  job.save().then(function(job) {
@@ -5,18 +5,20 @@
5
5
  var confirmation = "Are you sure want to delete this schedule? It will be removed from the host crontab also!\n";
6
6
  var job_id = schedule.get('job.id');
7
7
 
8
- schedule.deleteRecord();
8
+ if (window.confirm(confirmation)) {
9
+ schedule.deleteRecord();
9
10
 
10
- schedule.save().then(function() {
11
- // This is needed to reload all the relationships correctly after a delete
12
- // TODO: do this in a nicer way
13
- window.location.hash = '/jobs/' + job_id;
14
- window.location.reload();
15
- }, function(response) {
16
- schedule.rollback();
17
- console.log(response);
18
- window.prompt('Error deleting schedule, reason:', response.responseJSON.error);
19
- });
11
+ schedule.save().then(function() {
12
+ // This is needed to reload all the relationships correctly after a delete
13
+ // TODO: do this in a nicer way
14
+ window.location.hash = '/jobs/' + job_id;
15
+ window.location.reload();
16
+ }, function(response) {
17
+ schedule.rollback();
18
+ console.log(response);
19
+ window.prompt('Error deleting schedule, reason:', response.responseJSON.error);
20
+ });
21
+ }
20
22
  }
21
23
 
22
24
  Minicron.SchedulesNewController = Ember.ObjectController.extend({
@@ -38,8 +40,8 @@
38
40
  });
39
41
  });
40
42
  },
41
- cancel: function(schedule) {
42
- this.transitionToRoute('job', schedule.get('id'));
43
+ cancel: function(job_id) {
44
+ this.transitionToRoute('job', job_id);
43
45
  }
44
46
  }
45
47
  });
@@ -4,6 +4,7 @@
4
4
  Minicron.Host = DS.Model.extend({
5
5
  name: DS.attr('string'),
6
6
  fqdn: DS.attr('string'),
7
+ user: DS.attr('string'),
7
8
  host: DS.attr('string'),
8
9
  port: DS.attr('number'),
9
10
  public_key: DS.attr('string'),
@@ -4,6 +4,7 @@
4
4
  Minicron.Job = DS.Model.extend({
5
5
  job_hash: DS.attr('string'),
6
6
  name: DS.attr('string'),
7
+ user: DS.attr('string'),
7
8
  command: DS.attr('string'),
8
9
  created_at: DS.attr('date'),
9
10
  updated_at: DS.attr('date'),
@@ -1,6 +1,5 @@
1
1
  class Minicron::Hub::App
2
2
  # Get all job executions
3
- # TODO: Add offset/limit
4
3
  get '/api/executions' do
5
4
  content_type :json
6
5
  executions = Minicron::Hub::Execution.all.order(:created_at => :desc, :started_at => :desc)
@@ -2,7 +2,6 @@ require 'minicron/transport/ssh'
2
2
 
3
3
  class Minicron::Hub::App
4
4
  # Get all hosts that a job
5
- # TODO: Add offset/limit
6
5
  get '/api/hosts' do
7
6
  content_type :json
8
7
  hosts = Minicron::Hub::Host.all.includes(:jobs).order(:id => :asc)
@@ -26,10 +25,14 @@ class Minicron::Hub::App
26
25
  # Default the value of the port
27
26
  request_body['host']['port'] ||= 22
28
27
 
28
+ # Default the value of the user
29
+ request_body['host']['user'] ||= 'root'
30
+
29
31
  # Try and save the new host
30
32
  host = Minicron::Hub::Host.create(
31
33
  :name => request_body['host']['name'],
32
34
  :fqdn => request_body['host']['fqdn'],
35
+ :user => request_body['host']['user'],
33
36
  :host => request_body['host']['host'],
34
37
  :port => request_body['host']['port']
35
38
  )
@@ -66,6 +69,7 @@ class Minicron::Hub::App
66
69
  # Update its data
67
70
  host.name = request_body['host']['name']
68
71
  host.fqdn = request_body['host']['fqdn']
72
+ host.user = request_body['host']['user']
69
73
  host.host = request_body['host']['host']
70
74
  host.port = request_body['host']['port']
71
75
 
@@ -93,6 +97,7 @@ class Minicron::Hub::App
93
97
 
94
98
  # Get an ssh instance and open a connection
95
99
  ssh = Minicron::Transport::SSH.new(
100
+ :user => host.user,
96
101
  :host => host.host,
97
102
  :port => host.port,
98
103
  :private_key => "~/.ssh/minicron_host_#{host.id}_rsa"
@@ -131,29 +136,23 @@ class Minicron::Hub::App
131
136
 
132
137
  # Set up the ssh instance
133
138
  ssh = Minicron::Transport::SSH.new(
139
+ :user => host.user,
134
140
  :host => host.host,
135
141
  :port => host.port,
136
142
  :private_key => "~/.ssh/minicron_host_#{host.id}_rsa"
137
143
  )
138
144
 
139
- # Open the connection
140
- conn = ssh.open
141
-
142
- # Check if the crontab is readable
143
- read = conn.exec!('test -r /etc/crontab && echo "y" || echo "n"').strip
145
+ # Get an instance of the cron class
146
+ cron = Minicron::Cron.new(ssh)
144
147
 
145
- # Check if the crontab is writeable
146
- write = conn.exec!('test -w /etc/crontab && echo "y" || echo "n"').strip
148
+ # Test the SSH connection
149
+ test = cron.test_host_permissions
147
150
 
148
151
  # Tidy up
149
152
  ssh.close
150
153
 
151
154
  # Return the test results as JSON
152
- {
153
- :connect => true,
154
- :read => read == 'y',
155
- :write => write == 'y'
156
- }.to_json
155
+ test.to_json
157
156
  rescue Exception => e
158
157
  status 422
159
158
  { :connect => false, :error => e.message }.to_json
@@ -1,6 +1,5 @@
1
1
  class Minicron::Hub::App
2
2
  # Get all job execution outputs
3
- # TODO: Add offset/limit
4
3
  get '/api/jobExecutionOutputs' do
5
4
  content_type :json
6
5
 
@@ -2,7 +2,6 @@ require 'minicron/transport'
2
2
 
3
3
  class Minicron::Hub::App
4
4
  # Get all jobs
5
- # TODO: Add offset/limit
6
5
  get '/api/jobs' do
7
6
  content_type :json
8
7
 
@@ -11,7 +10,7 @@ class Minicron::Hub::App
11
10
  .where(:job_hash => params[:job_hash])
12
11
  else
13
12
  jobs = Minicron::Hub::Job.all.order(:created_at => :desc)
14
- .includes(:host, :schedules, :executions => :job_execution_outputs)
13
+ .includes(:host, :schedules, :executions => :job_execution_outputs)
15
14
  end
16
15
 
17
16
  Minicron::Hub::JobSerializer.new(jobs).serialize.to_json
@@ -39,6 +38,7 @@ class Minicron::Hub::App
39
38
  job = Minicron::Hub::Job.create(
40
39
  :job_hash => Minicron::Transport.get_job_hash(request_body['job']['command'], host.fqdn),
41
40
  :name => request_body['job']['name'],
41
+ :user => request_body['job']['user'],
42
42
  :command => request_body['job']['command'],
43
43
  :host_id => host.id
44
44
  )
@@ -65,8 +65,9 @@ class Minicron::Hub::App
65
65
  job = Minicron::Hub::Job.includes(:host, :schedules, :executions => :job_execution_outputs)
66
66
  .find(params[:id])
67
67
 
68
- # Update the name
68
+ # Update the name and user
69
69
  job.name = request_body['job']['name']
70
+ job.user = request_body['job']['user']
70
71
 
71
72
  job.save!
72
73
 
@@ -92,6 +93,7 @@ class Minicron::Hub::App
92
93
 
93
94
  # Get an ssh instance
94
95
  ssh = Minicron::Transport::SSH.new(
96
+ :user => job.host.user,
95
97
  :host => job.host.host,
96
98
  :port => job.host.port,
97
99
  :private_key => "~/.ssh/minicron_host_#{job.host.id}_rsa"
@@ -3,7 +3,6 @@ require 'minicron/cron'
3
3
 
4
4
  class Minicron::Hub::App
5
5
  # Get all schedules
6
- # TODO: Add offset/limit
7
6
  get '/api/schedules' do
8
7
  content_type :json
9
8
 
@@ -65,6 +64,7 @@ class Minicron::Hub::App
65
64
 
66
65
  # Get an ssh instance
67
66
  ssh = Minicron::Transport::SSH.new(
67
+ :user => job.host.user,
68
68
  :host => job.host.host,
69
69
  :port => job.host.port,
70
70
  :private_key => "~/.ssh/minicron_host_#{job.host.id}_rsa"
@@ -106,6 +106,7 @@ class Minicron::Hub::App
106
106
 
107
107
  # Get an ssh instance
108
108
  ssh = Minicron::Transport::SSH.new(
109
+ :user => schedule.job.host.user,
109
110
  :host => schedule.job.host.host,
110
111
  :port => schedule.job.host.port,
111
112
  :private_key => "~/.ssh/minicron_host_#{schedule.job.host.id}_rsa"
@@ -158,6 +159,7 @@ class Minicron::Hub::App
158
159
 
159
160
  # Get an ssh instance
160
161
  ssh = Minicron::Transport::SSH.new(
162
+ :user => schedule.job.host.user,
161
163
  :host => schedule.job.host.host,
162
164
  :port => schedule.job.host.port,
163
165
  :private_key => "~/.ssh/minicron_host_#{schedule.job.host.id}_rsa"
@@ -42,12 +42,13 @@ ActiveRecord::Schema.define(version: 0) do
42
42
 
43
43
  create_table "hosts", force: true do |t|
44
44
  t.string "name"
45
- t.string "fqdn", default: "", null: false
46
- t.string "host", default: "", null: false
47
- t.integer "port", null: false
45
+ t.string "fqdn", default: "", null: false
46
+ t.string "user", limit: 32, default: "", null: false
47
+ t.string "host", default: "", null: false
48
+ t.integer "port", null: false
48
49
  t.text "public_key"
49
- t.datetime "created_at", null: false
50
- t.datetime "updated_at", null: false
50
+ t.datetime "created_at", null: false
51
+ t.datetime "updated_at", null: false
51
52
  end
52
53
 
53
54
  add_index "hosts", ["fqdn"], name: "hostname", using: :btree
@@ -63,10 +64,11 @@ ActiveRecord::Schema.define(version: 0) do
63
64
  add_index "job_execution_outputs", ["seq"], name: "seq", using: :btree
64
65
 
65
66
  create_table "jobs", force: true do |t|
67
+ t.integer "host_id", null: false
66
68
  t.string "job_hash", limit: 32, default: "", null: false
67
69
  t.string "name"
70
+ t.string "user", limit: 32, null: false
68
71
  t.text "command", null: false
69
- t.integer "host_id", null: false
70
72
  t.datetime "created_at", null: false
71
73
  t.datetime "updated_at", null: false
72
74
  end
@@ -7,7 +7,7 @@
7
7
  #
8
8
  # Host: 127.0.0.1 (MySQL 5.6.16)
9
9
  # Database: minicron
10
- # Generation Time: 2014-04-01 03:35:39 +0000
10
+ # Generation Time: 2014-04-07 17:06:03 +0000
11
11
  # ************************************************************
12
12
 
13
13
 
@@ -73,6 +73,7 @@ CREATE TABLE `hosts` (
73
73
  `id` int(11) NOT NULL AUTO_INCREMENT,
74
74
  `name` varchar(255) DEFAULT NULL,
75
75
  `fqdn` varchar(255) NOT NULL DEFAULT '',
76
+ `user` varchar(32) NOT NULL DEFAULT '',
76
77
  `host` varchar(255) NOT NULL DEFAULT '',
77
78
  `port` int(11) NOT NULL,
78
79
  `public_key` text,
@@ -109,10 +110,11 @@ DROP TABLE IF EXISTS `jobs`;
109
110
 
110
111
  CREATE TABLE `jobs` (
111
112
  `id` int(11) NOT NULL AUTO_INCREMENT,
113
+ `host_id` int(11) NOT NULL,
112
114
  `job_hash` varchar(32) NOT NULL DEFAULT '',
113
115
  `name` varchar(255) DEFAULT NULL,
116
+ `user` varchar(32) NOT NULL,
114
117
  `command` text NOT NULL,
115
- `host_id` int(11) NOT NULL,
116
118
  `created_at` datetime NOT NULL,
117
119
  `updated_at` datetime NOT NULL,
118
120
  PRIMARY KEY (`id`),
@@ -55,6 +55,12 @@
55
55
  <div class="form-control form-control-view">{{fqdn}}</div>
56
56
  </div>
57
57
  </div>
58
+ <div class="form-group">
59
+ <label class="col-sm-2 control-label">User</label>
60
+ <div class="col-sm-10">
61
+ <div class="form-control form-control-view">{{user}}</div>
62
+ </div>
63
+ </div>
58
64
  <div class="form-group">
59
65
  <label class="col-sm-2 control-label">Host</label>
60
66
  <div class="col-sm-10">
@@ -141,6 +147,12 @@
141
147
  {{input value=fqdn type="text" class="form-control" placeholder="The machine fully qualified domain name e.g 'server1.host.com'"}}
142
148
  </div>
143
149
  </div>
150
+ <div class="form-group">
151
+ <label class="col-sm-2 control-label">User</label>
152
+ <div class="col-sm-10">
153
+ {{input value=user type="text" class="form-control" placeholder="The user to connect to the host as"}}
154
+ </div>
155
+ </div>
144
156
  <div class="form-group">
145
157
  <label class="col-sm-2 control-label">Host</label>
146
158
  <div class="col-sm-10">
@@ -183,6 +195,12 @@
183
195
  {{input value=fqdn type="text" class="form-control" placeholder="The machine fully qualified domain name e.g 'server1.host.com'"}}
184
196
  </div>
185
197
  </div>
198
+ <div class="form-group">
199
+ <label class="col-sm-2 control-label">User</label>
200
+ <div class="col-sm-10">
201
+ {{input value=user type="text" class="form-control" placeholder="The user to connect to the host as"}}
202
+ </div>
203
+ </div>
186
204
  <div class="form-group">
187
205
  <label class="col-sm-2 control-label">Host</label>
188
206
  <div class="col-sm-10">
@@ -48,6 +48,12 @@
48
48
  <div class="form-control form-control-view">{{name}}</div>
49
49
  </div>
50
50
  </div>
51
+ <div class="form-group">
52
+ <label class="col-sm-2 control-label">User</label>
53
+ <div class="col-sm-10">
54
+ <div class="form-control form-control-view">{{user}}</div>
55
+ </div>
56
+ </div>
51
57
  <div class="form-group">
52
58
  <label class="col-sm-2 control-label">Command</label>
53
59
  <div class="col-sm-10">
@@ -151,6 +157,12 @@
151
157
  {{input value=job_name type="text" class="form-control" placeholder="A nickname for the job"}}
152
158
  </div>
153
159
  </div>
160
+ <div class="form-group">
161
+ <label class="col-sm-2 control-label">User</label>
162
+ <div class="col-sm-10">
163
+ {{input value=job_user type="text" class="form-control" placeholder="What user should the job be run as"}}
164
+ </div>
165
+ </div>
154
166
  <div class="form-group">
155
167
  <label class="col-sm-2 control-label">Command</label>
156
168
  <div class="col-sm-10">
@@ -193,6 +205,12 @@
193
205
  {{input value=name type="text" class="form-control" placeholder="A nickname for the job"}}
194
206
  </div>
195
207
  </div>
208
+ <div class="form-group">
209
+ <label class="col-sm-2 control-label">User</label>
210
+ <div class="col-sm-10">
211
+ {{input value=user type="text" class="form-control" placeholder="What user should the job be run as"}}
212
+ </div>
213
+ </div>
196
214
  <div class="form-group">
197
215
  <div class="col-sm-offset-2 col-sm-10">
198
216
  <button type="submit" class="btn btn-success">Save</button>