mobilize-base 1.298 → 1.351
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/README.md +15 -6
- data/lib/mobilize-base/extensions/google_drive/file.rb +10 -36
- data/lib/mobilize-base/handlers/gdrive.rb +8 -4
- data/lib/mobilize-base/handlers/gfile.rb +1 -1
- data/lib/mobilize-base/handlers/gsheet.rb +1 -1
- data/lib/mobilize-base/handlers/resque.rb +10 -6
- data/lib/mobilize-base/helpers/jobtracker_helper.rb +143 -0
- data/lib/mobilize-base/helpers/runner_helper.rb +1 -1
- data/lib/mobilize-base/jobtracker.rb +14 -196
- data/lib/mobilize-base/models/runner.rb +5 -0
- data/lib/mobilize-base/models/stage.rb +13 -1
- data/lib/mobilize-base/version.rb +1 -1
- data/lib/samples/gdrive.yml +6 -0
- data/lib/samples/jobtracker.yml +0 -6
- data/test/base_job_rows.yml +5 -1
- data/test/mobilize-base_test.rb +20 -62
- data/test/test_helper.rb +79 -0
- metadata +5 -4
data/README.md
CHANGED
|
@@ -162,9 +162,15 @@ the same domain, and all Users should have emails in this domain.
|
|
|
162
162
|
* an owner name and password. You can set up separate owners
|
|
163
163
|
for different environments as in the below file, which will keep your
|
|
164
164
|
mission critical workers from getting rate-limit errors.
|
|
165
|
+
* one admin_group_name, which the owner and all admins should be added to -- this
|
|
166
|
+
group will need read permissions to read from and edit permissions to write
|
|
167
|
+
to files.
|
|
165
168
|
* one or more admins with email attributes -- these will be for people
|
|
166
169
|
who should be given write permissions to all Mobilize books in the
|
|
167
170
|
environment for maintenance purposes.
|
|
171
|
+
* one worker_group_name, which the owner and all workers should be added to -- this
|
|
172
|
+
group will need read permissions to read from and edit permissions to write
|
|
173
|
+
to files.
|
|
168
174
|
* one or more workers with name and pw attributes -- they will be used
|
|
169
175
|
to queue up google reads and writes. This can be the same as the owner
|
|
170
176
|
account for testing purposes or low-volume environments.
|
|
@@ -182,8 +188,10 @@ development:
|
|
|
182
188
|
owner:
|
|
183
189
|
name: owner_development
|
|
184
190
|
pw: google_drive_password
|
|
191
|
+
admin_group_name: admins_development
|
|
185
192
|
admins:
|
|
186
193
|
- name: admin
|
|
194
|
+
worker_group_name: workers_development
|
|
187
195
|
workers:
|
|
188
196
|
- name: worker_development001
|
|
189
197
|
pw: worker001_google_drive_password
|
|
@@ -194,8 +202,10 @@ test:
|
|
|
194
202
|
owner:
|
|
195
203
|
name: owner_test
|
|
196
204
|
pw: google_drive_password
|
|
205
|
+
admin_group_name: admins_test
|
|
197
206
|
admins:
|
|
198
207
|
- name: admin
|
|
208
|
+
worker_group_name: workers_test
|
|
199
209
|
workers:
|
|
200
210
|
- name: worker_test001
|
|
201
211
|
pw: worker001_google_drive_password
|
|
@@ -206,8 +216,10 @@ production:
|
|
|
206
216
|
owner:
|
|
207
217
|
name: owner_production
|
|
208
218
|
pw: google_drive_password
|
|
219
|
+
admin_group_name: admins_production
|
|
209
220
|
admins:
|
|
210
221
|
- name: admin
|
|
222
|
+
worker_group_name: workers_production
|
|
211
223
|
workers:
|
|
212
224
|
- name: worker_production001
|
|
213
225
|
pw: worker001_google_drive_password
|
|
@@ -266,6 +278,9 @@ The Jobtracker sits on your Resque and does 2 things:
|
|
|
266
278
|
|
|
267
279
|
Emails are sent using ActionMailer, through the owner Google Drive
|
|
268
280
|
account.
|
|
281
|
+
* errors are sent to the owner of the job/stage as well as the admin group.
|
|
282
|
+
* errors not specific to a job/stage are sent to the admin group only, as
|
|
283
|
+
given in gdrive.yml
|
|
269
284
|
|
|
270
285
|
To this end, it needs these parameters, for which there is a sample
|
|
271
286
|
below and in the [lib/samples][git_samples] folder:
|
|
@@ -278,24 +293,18 @@ development:
|
|
|
278
293
|
runner_read_freq: 300 #5 min between runner reads
|
|
279
294
|
max_run_time: 14400 # if a job runs for 4h+, notification will be sent
|
|
280
295
|
extensions: [] #additional Mobilize modules to load workers with
|
|
281
|
-
admins: #emails to send notifications to
|
|
282
|
-
- email: admin@host.com
|
|
283
296
|
test:
|
|
284
297
|
cycle_freq: 10 #time between Jobtracker sweeps
|
|
285
298
|
notification_freq: 3600 #1 hour between failure/timeout notifications
|
|
286
299
|
runner_read_freq: 300 #5 min between runner reads
|
|
287
300
|
max_run_time: 14400 # if a job runs for 4h+, notification will be sent
|
|
288
301
|
extensions: [] #additional Mobilize modules to load workers with
|
|
289
|
-
admins: #emails to send notifications to
|
|
290
|
-
- email: admin@host.com
|
|
291
302
|
production:
|
|
292
303
|
cycle_freq: 10 #time between Jobtracker sweeps
|
|
293
304
|
notification_freq: 3600 #1 hour between failure/timeout notifications
|
|
294
305
|
runner_read_freq: 300 #5 min between runner reads
|
|
295
306
|
max_run_time: 14400 # if a job runs for 4h+, notification will be sent
|
|
296
307
|
extensions: [] #additional Mobilize modules to load workers with
|
|
297
|
-
admins: #emails to send notifications to
|
|
298
|
-
- email: admin@host.com
|
|
299
308
|
```
|
|
300
309
|
|
|
301
310
|
<a name='section_Configure_Resque'></a>
|
|
@@ -3,42 +3,16 @@ module GoogleDrive
|
|
|
3
3
|
|
|
4
4
|
def add_worker_acl
|
|
5
5
|
f = self
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
f.update_acl(a)
|
|
9
|
-
end
|
|
6
|
+
email = "#{Mobilize::Gdrive.worker_group_name}@#{Mobilize::Gdrive.domain}"
|
|
7
|
+
f.update_acl(email,"group")
|
|
10
8
|
end
|
|
11
9
|
|
|
12
10
|
def add_admin_acl
|
|
13
11
|
f = self
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
f.update_acl(email)
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def has_admin_acl?
|
|
23
|
-
f = self
|
|
24
|
-
curr_emails = f.acls.map{|a| a.scope}.compact.sort
|
|
25
|
-
admin_emails = (Mobilize::Gdrive.admin_emails + Mobilize::Gdrive.worker_emails).uniq
|
|
26
|
-
if curr_emails == admin_emails or (curr_emails & admin_emails) == admin_emails
|
|
27
|
-
return true
|
|
28
|
-
else
|
|
29
|
-
return false
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def has_worker_acl?
|
|
34
|
-
f = self
|
|
35
|
-
curr_emails = f.acls.map{|a| a.scope}.compact.sort
|
|
36
|
-
worker_emails = Mobilize::Gdrive.worker_emails.sort
|
|
37
|
-
if curr_emails == worker_emails or (curr_emails & worker_emails) == worker_emails
|
|
38
|
-
return true
|
|
39
|
-
else
|
|
40
|
-
return false
|
|
41
|
-
end
|
|
12
|
+
email = "#{Mobilize::Gdrive.admin_group_name}@#{Mobilize::Gdrive.domain}"
|
|
13
|
+
f.update_acl(email,"group")
|
|
14
|
+
#if adding acl ,must currently add workers as well
|
|
15
|
+
f.add_worker_acl
|
|
42
16
|
end
|
|
43
17
|
|
|
44
18
|
def read(user_name)
|
|
@@ -51,7 +25,7 @@ module GoogleDrive
|
|
|
51
25
|
end
|
|
52
26
|
end
|
|
53
27
|
|
|
54
|
-
def update_acl(email,role="writer")
|
|
28
|
+
def update_acl(email,scope_type="user",role="writer")
|
|
55
29
|
f = self
|
|
56
30
|
#need these flags for HTTP retries
|
|
57
31
|
#create req_acl hash to add to current acl
|
|
@@ -64,16 +38,16 @@ module GoogleDrive
|
|
|
64
38
|
if entry.role != role
|
|
65
39
|
#for whatever reason
|
|
66
40
|
f.acl.delete(entry)
|
|
67
|
-
f.acl.push({:scope_type=>
|
|
41
|
+
f.acl.push({:scope_type=>scope_type,:scope=>email,:role=>role})
|
|
68
42
|
end
|
|
69
43
|
elsif !['reader','writer','owner'].include?(role)
|
|
70
44
|
raise "Invalid role #{role}"
|
|
71
45
|
end
|
|
72
46
|
else
|
|
73
47
|
begin
|
|
74
|
-
f.acl.push({:scope_type=>
|
|
48
|
+
f.acl.push({:scope_type=>scope_type,:scope=>email,:role=>role})
|
|
75
49
|
rescue => exc
|
|
76
|
-
raise exc unless exc.to_s.index("
|
|
50
|
+
raise exc unless exc.to_s.index("already has access")
|
|
77
51
|
end
|
|
78
52
|
end
|
|
79
53
|
return true
|
|
@@ -37,12 +37,16 @@ module Mobilize
|
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
def Gdrive.
|
|
41
|
-
Gdrive.
|
|
40
|
+
def Gdrive.worker_group_name
|
|
41
|
+
Gdrive.config['worker_group_name']
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def Gdrive.admin_group_name
|
|
45
|
+
Gdrive.config['admin_group_name']
|
|
42
46
|
end
|
|
43
47
|
|
|
44
|
-
def Gdrive.
|
|
45
|
-
Gdrive.
|
|
48
|
+
def Gdrive.worker_emails
|
|
49
|
+
Gdrive.workers.map{|w| [w['name'],Gdrive.domain].join("@")}
|
|
46
50
|
end
|
|
47
51
|
|
|
48
52
|
#email management - used to make sure not too many emails get used at the same time
|
|
@@ -58,7 +58,7 @@ module Mobilize
|
|
|
58
58
|
def Gfile.update_acl_by_path(path,gdrive_slot,role="writer",target_email=nil)
|
|
59
59
|
file = Gfile.find_by_path(path,target_email)
|
|
60
60
|
raise "File #{path} not found" unless file
|
|
61
|
-
file.update_acl(gdrive_slot,role)
|
|
61
|
+
file.update_acl(gdrive_slot,"user",role)
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
def Gfile.find_by_path(path)
|
|
@@ -109,7 +109,7 @@ module Mobilize
|
|
|
109
109
|
#only give the user edit permissions if they're the ones
|
|
110
110
|
#creating it
|
|
111
111
|
target_sheet = Gsheet.find_or_create_by_path(target_path,gdrive_slot)
|
|
112
|
-
target_sheet.spreadsheet.update_acl(u.email
|
|
112
|
+
target_sheet.spreadsheet.update_acl(u.email) unless target_sheet.spreadsheet.acl_entry(u.email).ie{|e| e and e.role=="owner"}
|
|
113
113
|
target_sheet.delete_sheet1
|
|
114
114
|
end
|
|
115
115
|
#pass it crop param to determine whether to shrink target sheet to fit data
|
|
@@ -19,13 +19,17 @@ module Mobilize
|
|
|
19
19
|
def Resque.workers(state="all")
|
|
20
20
|
workers = ::Resque.workers.select{|w| w.queues.first == Resque.queue_name}
|
|
21
21
|
return workers if state == 'all'
|
|
22
|
-
working_workers = workers.select{|w| w.job['queue']== Resque.queue_name}
|
|
22
|
+
working_workers = workers.select{|w| w.job['queue'] == Resque.queue_name}
|
|
23
23
|
return working_workers if state == 'working'
|
|
24
24
|
idle_workers = workers.select{|w| w.job['queue'].nil?}
|
|
25
25
|
return idle_workers if state == 'idle'
|
|
26
26
|
stale_workers = workers.select{|w| Time.parse(w.started) < Jobtracker.deployed_at}
|
|
27
27
|
return stale_workers if state == 'stale'
|
|
28
|
-
timeout_workers = workers.select
|
|
28
|
+
timeout_workers = workers.select do |w|
|
|
29
|
+
w.job['payload'] and
|
|
30
|
+
w.job['payload']['class']!='Jobtracker' and
|
|
31
|
+
w.job['run_at'] < (Time.now.utc - Jobtracker.max_run_time)
|
|
32
|
+
end
|
|
29
33
|
return timeout_workers if state == 'timeout'
|
|
30
34
|
raise "invalid state #{state}"
|
|
31
35
|
end
|
|
@@ -115,14 +119,14 @@ module Mobilize
|
|
|
115
119
|
s = Stage.where(:path=>stage_path).first
|
|
116
120
|
if s.params['notify'].to_s=="false"
|
|
117
121
|
next
|
|
118
|
-
elsif s.params['notify'].index("@")
|
|
122
|
+
elsif s.params['notify'].to_s.index("@")
|
|
119
123
|
s.params['notify']
|
|
120
124
|
else
|
|
121
125
|
s.job.runner.user.email
|
|
122
126
|
end
|
|
123
|
-
rescue
|
|
124
|
-
#jobs without stages are sent to
|
|
125
|
-
|
|
127
|
+
rescue ScriptError, StandardError
|
|
128
|
+
#jobs without stages are sent to admins
|
|
129
|
+
[Gdrive.admin_group_name,Gdrive.domain].join("@")
|
|
126
130
|
end
|
|
127
131
|
exc_to_s = f['error']
|
|
128
132
|
if fjobs[email].nil?
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
module Mobilize
|
|
2
|
+
module Jobtracker
|
|
3
|
+
def Jobtracker.config
|
|
4
|
+
Base.config('jobtracker')
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
#modify this to increase the frequency of request cycles
|
|
8
|
+
def Jobtracker.cycle_freq
|
|
9
|
+
Jobtracker.config['cycle_freq']
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
#frequency of notifications
|
|
13
|
+
def Jobtracker.notification_freq
|
|
14
|
+
Jobtracker.config['notification_freq']
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def Jobtracker.runner_read_freq
|
|
18
|
+
Jobtracker.config['runner_read_freq']
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
#long running tolerance
|
|
22
|
+
def Jobtracker.max_run_time
|
|
23
|
+
Jobtracker.config['max_run_time']
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def Jobtracker.admins
|
|
27
|
+
Jobtracker.config['admins']
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def Jobtracker.worker
|
|
31
|
+
Resque.find_worker_by_path("jobtracker")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def Jobtracker.workers(state="all")
|
|
35
|
+
Resque.workers(state)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def Jobtracker.status
|
|
39
|
+
args = Jobtracker.get_args
|
|
40
|
+
return args['status'] if args
|
|
41
|
+
job = Resque.jobs.select{|j| j['args'].first=='jobtracker'}.first
|
|
42
|
+
return 'queued' if job
|
|
43
|
+
return 'stopped'
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def Jobtracker.update_status(msg)
|
|
47
|
+
#this is to keep jobtracker from resisting stop commands
|
|
48
|
+
return false if Jobtracker.status=="stopping"
|
|
49
|
+
#Jobtracker has no persistent database state
|
|
50
|
+
Resque.set_worker_args_by_path("jobtracker",{'status'=>msg})
|
|
51
|
+
return true
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def Jobtracker.restart
|
|
55
|
+
Jobtracker.stop!
|
|
56
|
+
Jobtracker.start
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def Jobtracker.set_args(args)
|
|
60
|
+
Resque.set_worker_args(Jobtracker.worker,args)
|
|
61
|
+
return true
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def Jobtracker.get_args
|
|
65
|
+
Resque.get_worker_args(Jobtracker.worker)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def Jobtracker.kill_workers
|
|
69
|
+
Resque.kill_workers
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def Jobtracker.kill_idle_workers
|
|
73
|
+
Resque.kill_idle_workers
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def Jobtracker.kill_idle_and_stale_workers
|
|
77
|
+
Resque.kill_idle_and_stale_workers
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def Jobtracker.prep_workers
|
|
81
|
+
Resque.prep_workers
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def Jobtracker.failures
|
|
85
|
+
Resque.failures
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def Jobtracker.start
|
|
89
|
+
if Jobtracker.status!='stopped'
|
|
90
|
+
Jobtracker.update_status("Jobtracker still #{Jobtracker.status}")
|
|
91
|
+
else
|
|
92
|
+
#make sure that workers are running and at the right number
|
|
93
|
+
#Resque.prep_workers
|
|
94
|
+
#queue up the jobtracker (starts the perform method)
|
|
95
|
+
Jobtracker.enqueue!
|
|
96
|
+
end
|
|
97
|
+
return true
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def Jobtracker.enqueue!
|
|
101
|
+
::Resque::Job.create(Resque.queue_name, Jobtracker, 'jobtracker',{})
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def Jobtracker.restart!
|
|
105
|
+
Jobtracker.stop!
|
|
106
|
+
Jobtracker.start
|
|
107
|
+
return true
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def Jobtracker.restart_workers!
|
|
111
|
+
Jobtracker.kill_workers
|
|
112
|
+
sleep 10
|
|
113
|
+
Jobtracker.prep_workers
|
|
114
|
+
Jobtracker.update_status("put workers back on the queue")
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def Jobtracker.stop!
|
|
118
|
+
#send signal for Jobtracker to check for
|
|
119
|
+
Jobtracker.update_status('stopping')
|
|
120
|
+
sleep 5
|
|
121
|
+
i=0
|
|
122
|
+
while Jobtracker.status=='stopping'
|
|
123
|
+
puts "#{Jobtracker.to_s} still on queue, waiting"
|
|
124
|
+
sleep 5
|
|
125
|
+
i+=1
|
|
126
|
+
end
|
|
127
|
+
return true
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def Jobtracker.last_notification
|
|
131
|
+
return Jobtracker.get_args["last_notification"] if Jobtracker.get_args
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def Jobtracker.last_notification=(time)
|
|
135
|
+
Jobtracker.set_args({"last_notification"=>time})
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def Jobtracker.notif_due?
|
|
139
|
+
last_duetime = Time.now.utc - Jobtracker.notification_freq
|
|
140
|
+
return (Jobtracker.last_notification.to_s.length==0 || Jobtracker.last_notification.to_datetime < last_duetime)
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
@@ -36,7 +36,7 @@ module Mobilize
|
|
|
36
36
|
#creating it
|
|
37
37
|
jobs_sheet = Gsheet.find_or_create_by_path(r.path,gdrive_slot)
|
|
38
38
|
unless jobs_sheet.spreadsheet.acl_entry(u.email).ie{|e| e and e.role=="owner"}
|
|
39
|
-
jobs_sheet.spreadsheet.update_acl(u.email
|
|
39
|
+
jobs_sheet.spreadsheet.update_acl(u.email)
|
|
40
40
|
end
|
|
41
41
|
jobs_sheet.add_headers(r.headers)
|
|
42
42
|
begin;jobs_sheet.delete_sheet1;rescue;end #don't care if sheet1 deletion fails
|
|
@@ -1,148 +1,7 @@
|
|
|
1
1
|
module Mobilize
|
|
2
2
|
module Jobtracker
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
#modify this to increase the frequency of request cycles
|
|
8
|
-
def Jobtracker.cycle_freq
|
|
9
|
-
Jobtracker.config['cycle_freq']
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
#frequency of notifications
|
|
13
|
-
def Jobtracker.notification_freq
|
|
14
|
-
Jobtracker.config['notification_freq']
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def Jobtracker.runner_read_freq
|
|
18
|
-
Jobtracker.config['runner_read_freq']
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
#long running tolerance
|
|
22
|
-
def Jobtracker.max_run_time
|
|
23
|
-
Jobtracker.config['max_run_time']
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def Jobtracker.admins
|
|
27
|
-
Jobtracker.config['admins']
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def Jobtracker.admin_emails
|
|
31
|
-
Jobtracker.admins.map{|a| a['email'] }
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def Jobtracker.worker
|
|
35
|
-
Resque.find_worker_by_path("jobtracker")
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def Jobtracker.workers(state="all")
|
|
39
|
-
Resque.workers(state)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def Jobtracker.status
|
|
43
|
-
args = Jobtracker.get_args
|
|
44
|
-
return args['status'] if args
|
|
45
|
-
job = Resque.jobs.select{|j| j['args'].first=='jobtracker'}.first
|
|
46
|
-
return 'queued' if job
|
|
47
|
-
return 'stopped'
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def Jobtracker.update_status(msg)
|
|
51
|
-
#this is to keep jobtracker from resisting stop commands
|
|
52
|
-
return false if Jobtracker.status=="stopping"
|
|
53
|
-
#Jobtracker has no persistent database state
|
|
54
|
-
Resque.set_worker_args_by_path("jobtracker",{'status'=>msg})
|
|
55
|
-
return true
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def Jobtracker.restart
|
|
59
|
-
Jobtracker.stop!
|
|
60
|
-
Jobtracker.start
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def Jobtracker.set_args(args)
|
|
64
|
-
Resque.set_worker_args(Jobtracker.worker,args)
|
|
65
|
-
return true
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def Jobtracker.get_args
|
|
69
|
-
Resque.get_worker_args(Jobtracker.worker)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def Jobtracker.kill_workers
|
|
73
|
-
Resque.kill_workers
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def Jobtracker.kill_idle_workers
|
|
77
|
-
Resque.kill_idle_workers
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def Jobtracker.kill_idle_and_stale_workers
|
|
81
|
-
Resque.kill_idle_and_stale_workers
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def Jobtracker.prep_workers
|
|
85
|
-
Resque.prep_workers
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def Jobtracker.failures
|
|
89
|
-
Resque.failures
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def Jobtracker.start
|
|
93
|
-
if Jobtracker.status!='stopped'
|
|
94
|
-
Jobtracker.update_status("Jobtracker still #{Jobtracker.status}")
|
|
95
|
-
else
|
|
96
|
-
#make sure that workers are running and at the right number
|
|
97
|
-
#Resque.prep_workers
|
|
98
|
-
#queue up the jobtracker (starts the perform method)
|
|
99
|
-
Jobtracker.enqueue!
|
|
100
|
-
end
|
|
101
|
-
return true
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def Jobtracker.enqueue!
|
|
105
|
-
::Resque::Job.create(Resque.queue_name, Jobtracker, 'jobtracker',{})
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def Jobtracker.restart!
|
|
109
|
-
Jobtracker.stop!
|
|
110
|
-
Jobtracker.start
|
|
111
|
-
return true
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
def Jobtracker.restart_workers!
|
|
115
|
-
Jobtracker.kill_workers
|
|
116
|
-
sleep 10
|
|
117
|
-
Jobtracker.prep_workers
|
|
118
|
-
Jobtracker.update_status("put workers back on the queue")
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
def Jobtracker.stop!
|
|
122
|
-
#send signal for Jobtracker to check for
|
|
123
|
-
Jobtracker.update_status('stopping')
|
|
124
|
-
sleep 5
|
|
125
|
-
i=0
|
|
126
|
-
while Jobtracker.status=='stopping'
|
|
127
|
-
puts "#{Jobtracker.to_s} still on queue, waiting"
|
|
128
|
-
sleep 5
|
|
129
|
-
i+=1
|
|
130
|
-
end
|
|
131
|
-
return true
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def Jobtracker.last_notification
|
|
135
|
-
return Jobtracker.get_args["last_notification"] if Jobtracker.get_args
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
def Jobtracker.last_notification=(time)
|
|
139
|
-
Jobtracker.set_args({"last_notification"=>time})
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
def Jobtracker.notif_due?
|
|
143
|
-
last_duetime = Time.now.utc - Jobtracker.notification_freq
|
|
144
|
-
return (Jobtracker.last_notification.to_s.length==0 || Jobtracker.last_notification.to_datetime < last_duetime)
|
|
145
|
-
end
|
|
3
|
+
#adds convenience methods
|
|
4
|
+
require "#{File.dirname(__FILE__)}/helpers/jobtracker_helper"
|
|
146
5
|
|
|
147
6
|
def Jobtracker.max_run_time_workers
|
|
148
7
|
#return workers who have been cranking away for 6+ hours
|
|
@@ -176,19 +35,26 @@ module Mobilize
|
|
|
176
35
|
end
|
|
177
36
|
end.flatten.join("\n\n")
|
|
178
37
|
u = User.where(:name=>email.split("@").first).first
|
|
179
|
-
|
|
180
|
-
|
|
38
|
+
if u
|
|
39
|
+
runner_dst = Dataset.find_by_url("gsheet://#{u.runner.path}")
|
|
40
|
+
n['body'] += "\n\n#{runner_dst.http_url}" if runner_dst and runner_dst.http_url
|
|
41
|
+
end
|
|
181
42
|
n['to'] = email
|
|
182
|
-
n['bcc'] =
|
|
43
|
+
n['bcc'] = [Gdrive.admin_group_name,Gdrive.domain].join("@")
|
|
183
44
|
notifs << n
|
|
184
45
|
end
|
|
185
46
|
end
|
|
186
47
|
lws = Jobtracker.max_run_time_workers
|
|
187
48
|
if lws.length>0
|
|
49
|
+
bod = begin
|
|
50
|
+
lws.map{|w| w.job['payload']['args']}.first.join("\n")
|
|
51
|
+
rescue
|
|
52
|
+
"Failed to get job names"
|
|
53
|
+
end
|
|
188
54
|
n = {}
|
|
189
55
|
n['subject'] = "#{lws.length.to_s} max run time jobs"
|
|
190
|
-
n['body'] =
|
|
191
|
-
n['to'] =
|
|
56
|
+
n['body'] = bod
|
|
57
|
+
n['to'] = [Gdrive.admin_group_name,Gdrive.domain].join("@")
|
|
192
58
|
notifs << n
|
|
193
59
|
end
|
|
194
60
|
#deliver each email generated
|
|
@@ -250,53 +116,5 @@ module Mobilize
|
|
|
250
116
|
end.to_s.strip
|
|
251
117
|
Time.parse(deploy_time)
|
|
252
118
|
end
|
|
253
|
-
|
|
254
|
-
#test methods
|
|
255
|
-
def Jobtracker.restart_test_redis
|
|
256
|
-
Jobtracker.stop_test_redis
|
|
257
|
-
if !system("which redis-server")
|
|
258
|
-
raise "** can't find `redis-server` in your path, you need redis to run Resque and Mobilize"
|
|
259
|
-
end
|
|
260
|
-
"redis-server #{Base.root}/test/redis-test.conf".bash
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
def Jobtracker.stop_test_redis
|
|
264
|
-
processes = `ps -A -o pid,command | grep [r]edis-test`.split($/)
|
|
265
|
-
pids = processes.map { |process| process.split(" ")[0] }
|
|
266
|
-
puts "Killing test redis server..."
|
|
267
|
-
pids.each { |pid| Process.kill("TERM", pid.to_i) }
|
|
268
|
-
puts "removing redis db dump file"
|
|
269
|
-
sleep 5
|
|
270
|
-
`rm -f #{Base.root}/test/dump.rdb #{Base.root}/test/dump-cluster.rdb`
|
|
271
|
-
end
|
|
272
|
-
|
|
273
|
-
def Jobtracker.set_test_env
|
|
274
|
-
ENV['MOBILIZE_ENV']='test'
|
|
275
|
-
::Resque.redis="localhost:9736"
|
|
276
|
-
mongoid_config_path = "#{Base.root}/config/mobilize/mongoid.yml"
|
|
277
|
-
Mongoid.load!(mongoid_config_path, Base.env)
|
|
278
|
-
end
|
|
279
|
-
|
|
280
|
-
def Jobtracker.drop_test_db
|
|
281
|
-
Jobtracker.set_test_env
|
|
282
|
-
Mongoid.session(:default).collections.each do |collection|
|
|
283
|
-
unless collection.name =~ /^system\./
|
|
284
|
-
collection.drop
|
|
285
|
-
end
|
|
286
|
-
end
|
|
287
|
-
end
|
|
288
|
-
|
|
289
|
-
def Jobtracker.build_test_runner(user_name)
|
|
290
|
-
Jobtracker.set_test_env
|
|
291
|
-
u = User.where(:name=>user_name).first
|
|
292
|
-
Jobtracker.update_status("delete old books and datasets")
|
|
293
|
-
# delete any old runner from previous test runs
|
|
294
|
-
gdrive_slot = Gdrive.owner_email
|
|
295
|
-
u.runner.gsheet(gdrive_slot).spreadsheet.delete
|
|
296
|
-
Dataset.find_by_handler_and_path('gbook',u.runner.title).delete
|
|
297
|
-
Jobtracker.update_status("enqueue jobtracker, wait 45s")
|
|
298
|
-
Mobilize::Jobtracker.start
|
|
299
|
-
sleep 45
|
|
300
|
-
end
|
|
301
119
|
end
|
|
302
120
|
end
|
|
@@ -44,6 +44,14 @@ module Mobilize
|
|
|
44
44
|
|
|
45
45
|
def Stage.perform(id,*args)
|
|
46
46
|
s = Stage.where(:path=>id).first
|
|
47
|
+
#check to make sure params are parsable
|
|
48
|
+
begin
|
|
49
|
+
param_hash = s.params
|
|
50
|
+
raise ScriptError if param_hash.class!=Hash
|
|
51
|
+
rescue StandardError, ScriptError
|
|
52
|
+
s.fail({'signal'=>500,
|
|
53
|
+
'err_str'=>"Unable to parse stage params, make sure you don't have issues with your quotes, commas, or colons."})
|
|
54
|
+
end
|
|
47
55
|
s.update_attributes(:started_at=>Time.now.utc)
|
|
48
56
|
s.update_status(%{Starting at #{Time.now.utc}})
|
|
49
57
|
#get response by running method
|
|
@@ -112,7 +120,11 @@ module Mobilize
|
|
|
112
120
|
j = s.job
|
|
113
121
|
r = j.runner
|
|
114
122
|
u = r.user
|
|
115
|
-
|
|
123
|
+
begin
|
|
124
|
+
j.update_attributes(:active=>false) if s.params['always_on'].to_s=="false"
|
|
125
|
+
rescue StandardError, ScriptError
|
|
126
|
+
#skip due to parse error on params
|
|
127
|
+
end
|
|
116
128
|
s.update_attributes(:failed_at=>Time.now.utc,:response=>response)
|
|
117
129
|
stage_name = "#{j.name}_stage#{s.idx.to_s}.err"
|
|
118
130
|
target_path = (r.path.split("/")[0..-2] + [stage_name]).join("/")
|
data/lib/samples/gdrive.yml
CHANGED
|
@@ -4,8 +4,10 @@ development:
|
|
|
4
4
|
owner:
|
|
5
5
|
name: owner_development
|
|
6
6
|
pw: google_drive_password
|
|
7
|
+
admin_group_name: admins_development
|
|
7
8
|
admins:
|
|
8
9
|
- name: admin
|
|
10
|
+
worker_group_name: workers_development
|
|
9
11
|
workers:
|
|
10
12
|
- name: worker_development001
|
|
11
13
|
pw: worker001_google_drive_password
|
|
@@ -16,8 +18,10 @@ test:
|
|
|
16
18
|
owner:
|
|
17
19
|
name: owner_test
|
|
18
20
|
pw: google_drive_password
|
|
21
|
+
admin_group_name: admins_test
|
|
19
22
|
admins:
|
|
20
23
|
- name: admin
|
|
24
|
+
worker_group_name: workers_test
|
|
21
25
|
workers:
|
|
22
26
|
- name: worker_test001
|
|
23
27
|
pw: worker001_google_drive_password
|
|
@@ -28,8 +32,10 @@ production:
|
|
|
28
32
|
owner:
|
|
29
33
|
name: owner_production
|
|
30
34
|
pw: google_drive_password
|
|
35
|
+
admin_group_name: admins_production
|
|
31
36
|
admins:
|
|
32
37
|
- name: admin
|
|
38
|
+
worker_group_name: workers_production
|
|
33
39
|
workers:
|
|
34
40
|
- name: worker_production001
|
|
35
41
|
pw: worker001_google_drive_password
|
data/lib/samples/jobtracker.yml
CHANGED
|
@@ -5,21 +5,15 @@ development:
|
|
|
5
5
|
runner_read_freq: 300 #5 min between runner reads
|
|
6
6
|
max_run_time: 14400 # if a job runs for 4h+, notification will be sent
|
|
7
7
|
extensions: [] #additional Mobilize modules to load workers with
|
|
8
|
-
admins: #emails to send notifications to
|
|
9
|
-
- email: admin@host.com
|
|
10
8
|
test:
|
|
11
9
|
cycle_freq: 10 #time between Jobtracker sweeps
|
|
12
10
|
notification_freq: 3600 #1 hour between failure/timeout notifications
|
|
13
11
|
runner_read_freq: 300 #5 min between runner reads
|
|
14
12
|
max_run_time: 14400 # if a job runs for 4h+, notification will be sent
|
|
15
13
|
extensions: [] #additional Mobilize modules to load workers with
|
|
16
|
-
admins: #emails to send notifications to
|
|
17
|
-
- email: admin@host.com
|
|
18
14
|
production:
|
|
19
15
|
cycle_freq: 10 #time between Jobtracker sweeps
|
|
20
16
|
notification_freq: 3600 #1 hour between failure/timeout notifications
|
|
21
17
|
runner_read_freq: 300 #5 min between runner reads
|
|
22
18
|
max_run_time: 14400 # if a job runs for 4h+, notification will be sent
|
|
23
19
|
extensions: [] #additional Mobilize modules to load workers with
|
|
24
|
-
admins: #emails to send notifications to
|
|
25
|
-
- email: admin@host.com
|
data/test/base_job_rows.yml
CHANGED
|
@@ -3,9 +3,13 @@
|
|
|
3
3
|
trigger: once
|
|
4
4
|
status: ""
|
|
5
5
|
stage1: gsheet.write source:"gfile://test_base_1.tsv", target:base1.out
|
|
6
|
-
|
|
7
6
|
- name: base2
|
|
8
7
|
active: true
|
|
9
8
|
trigger: after base1
|
|
10
9
|
status: ""
|
|
11
10
|
stage1: gsheet.write source:base1.out, target:base2.out
|
|
11
|
+
- name: base3
|
|
12
|
+
active: true
|
|
13
|
+
trigger: after base2
|
|
14
|
+
status: ""
|
|
15
|
+
stage1: gsheet.write source:"base1."_"", target:base2.out
|
data/test/mobilize-base_test.rb
CHANGED
|
@@ -1,43 +1,34 @@
|
|
|
1
1
|
require 'test_helper'
|
|
2
2
|
|
|
3
3
|
describe "Mobilize" do
|
|
4
|
-
|
|
5
|
-
def before
|
|
6
|
-
puts 'nothing before'
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
# enqueues 4 workers on Resque
|
|
10
4
|
it "runs integration test" do
|
|
11
5
|
|
|
12
6
|
puts "restart test redis"
|
|
13
|
-
|
|
7
|
+
TestHelper.restart_test_redis
|
|
14
8
|
|
|
15
9
|
puts "clear out test db"
|
|
16
|
-
|
|
10
|
+
TestHelper.drop_test_db
|
|
17
11
|
|
|
18
12
|
puts "restart workers"
|
|
19
13
|
Mobilize::Jobtracker.restart_workers!
|
|
20
14
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
user_name = gdrive_slot.split("@").first
|
|
25
|
-
u = Mobilize::User.find_or_create_by_name(user_name)
|
|
26
|
-
assert u.email == gdrive_slot
|
|
15
|
+
u = TestHelper.owner_user
|
|
16
|
+
user_name = u.name
|
|
17
|
+
gdrive_slot = u.email
|
|
27
18
|
|
|
28
|
-
|
|
19
|
+
puts "build test runner"
|
|
20
|
+
TestHelper.build_test_runner(user_name)
|
|
29
21
|
assert Mobilize::Jobtracker.workers.length == Mobilize::Resque.config['max_workers'].to_i
|
|
30
22
|
|
|
31
23
|
puts "Jobtracker created runner with 'jobs' sheet?"
|
|
24
|
+
|
|
32
25
|
r = u.runner
|
|
33
26
|
jobs_sheet_url = "gsheet://#{r.path}"
|
|
34
27
|
jobs_sheet = Mobilize::Gsheet.find_by_path(r.path,gdrive_slot)
|
|
35
28
|
jobs_sheet_dst = Mobilize::Dataset.find_or_create_by_url(jobs_sheet_url)
|
|
36
29
|
jobs_sheet_tsv = jobs_sheet_dst.read(user_name,gdrive_slot)
|
|
37
|
-
assert jobs_sheet_tsv.tsv_header_array.join.length == 53 #total header length
|
|
38
30
|
|
|
39
|
-
|
|
40
|
-
#Mobilize::Jobtracker.stop!
|
|
31
|
+
assert jobs_sheet_tsv.tsv_header_array.join.length == 53 #total header length
|
|
41
32
|
|
|
42
33
|
puts "add base1 input file"
|
|
43
34
|
test_filename = "test_base_1"
|
|
@@ -53,55 +44,22 @@ describe "Mobilize" do
|
|
|
53
44
|
jobs_sheet.reload
|
|
54
45
|
jobs_sheet.add_or_update_rows(test_job_rows)
|
|
55
46
|
#wait for stages to complete
|
|
56
|
-
|
|
57
|
-
wait_for_stages
|
|
47
|
+
TestHelper.wait_for_stages
|
|
58
48
|
|
|
59
49
|
puts "jobtracker posted test sheet data to test destination, and checksum succeeded?"
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
50
|
+
tsv_hash = {}
|
|
51
|
+
["base1.out", "base2.out", "base3_stage1.err"].each do |sheet_name|
|
|
52
|
+
url = "gsheet://#{r.title}/#{sheet_name}"
|
|
53
|
+
data = Mobilize::Dataset.read_by_url(url,user_name,gdrive_slot)
|
|
54
|
+
tsv_hash[sheet_name] = data
|
|
55
|
+
end
|
|
66
56
|
|
|
67
|
-
assert
|
|
68
|
-
assert
|
|
57
|
+
assert tsv_hash["base1.out"].to_s.length>0
|
|
58
|
+
assert tsv_hash["base2.out"] == tsv_hash["base1.out"]
|
|
69
59
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
Mobilize::Dataset.write_by_url(test_error_sheet_url," ",user_name,gdrive_slot)
|
|
73
|
-
jobs_sheet.add_or_update_rows(test_job_rows)
|
|
60
|
+
base3_response = tsv_hash["base3_stage1.err"].tsv_to_hash_array.first['response']
|
|
61
|
+
assert base3_response == "Unable to parse stage params, make sure you don't have issues with your quotes, commas, or colons."
|
|
74
62
|
|
|
75
|
-
#wait for stages to complete
|
|
76
|
-
wait_for_stages
|
|
77
|
-
|
|
78
|
-
test_error_sheet = Mobilize::Gsheet.find_by_path("#{r.path.split("/")[0..-2].join("/")}/base1_stage1.err",gdrive_slot)
|
|
79
|
-
puts "jobtracker posted failing test error to sheet "
|
|
80
|
-
error_rows = test_error_sheet.read(user_name).tsv_to_hash_array
|
|
81
|
-
assert error_rows.first['response'] == "Could not get gfile://test_base_1.fail with error: unable to find test_base_1.fail"
|
|
82
63
|
Mobilize::Jobtracker.stop!
|
|
83
64
|
end
|
|
84
|
-
|
|
85
|
-
def wait_for_stages(time_limit=600,stage_limit=120,wait_length=10)
|
|
86
|
-
time = 0
|
|
87
|
-
time_since_stage = 0
|
|
88
|
-
#check for 10 min
|
|
89
|
-
while time < time_limit and time_since_stage < stage_limit
|
|
90
|
-
sleep wait_length
|
|
91
|
-
job_classes = Mobilize::Resque.jobs.map{|j| j['class']}
|
|
92
|
-
if job_classes.include?("Mobilize::Stage")
|
|
93
|
-
time_since_stage = 0
|
|
94
|
-
puts "saw stage at #{time.to_s} seconds"
|
|
95
|
-
else
|
|
96
|
-
time_since_stage += wait_length
|
|
97
|
-
puts "#{time_since_stage.to_s} seconds since stage seen"
|
|
98
|
-
end
|
|
99
|
-
time += wait_length
|
|
100
|
-
puts "total wait time #{time.to_s} seconds"
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
if time >= time_limit
|
|
104
|
-
raise "Timed out before stage completion"
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
65
|
end
|
data/test/test_helper.rb
CHANGED
|
@@ -8,3 +8,82 @@ $dir = File.dirname(File.expand_path(__FILE__))
|
|
|
8
8
|
ENV['MOBILIZE_ENV'] = 'test'
|
|
9
9
|
require 'mobilize-base'
|
|
10
10
|
$TESTING = true
|
|
11
|
+
module TestHelper
|
|
12
|
+
def TestHelper.wait_for_stages(time_limit=600,stage_limit=120,wait_length=10)
|
|
13
|
+
time = 0
|
|
14
|
+
time_since_stage = 0
|
|
15
|
+
#check for 10 min
|
|
16
|
+
while time < time_limit and time_since_stage < stage_limit
|
|
17
|
+
sleep wait_length
|
|
18
|
+
job_classes = Mobilize::Resque.jobs.map{|j| j['class']}
|
|
19
|
+
if job_classes.include?("Mobilize::Stage")
|
|
20
|
+
time_since_stage = 0
|
|
21
|
+
puts "saw stage at #{time.to_s} seconds"
|
|
22
|
+
else
|
|
23
|
+
time_since_stage += wait_length
|
|
24
|
+
puts "#{time_since_stage.to_s} seconds since stage seen"
|
|
25
|
+
end
|
|
26
|
+
time += wait_length
|
|
27
|
+
puts "total wait time #{time.to_s} seconds"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
if time >= time_limit
|
|
31
|
+
raise "Timed out before stage completion"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
#test methods
|
|
36
|
+
def TestHelper.restart_test_redis
|
|
37
|
+
TestHelper.stop_test_redis
|
|
38
|
+
if !system("which redis-server")
|
|
39
|
+
raise "** can't find `redis-server` in your path, you need redis to run Resque and Mobilize"
|
|
40
|
+
end
|
|
41
|
+
"redis-server #{Mobilize::Base.root}/test/redis-test.conf".bash
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def TestHelper.stop_test_redis
|
|
45
|
+
processes = `ps -A -o pid,command | grep [r]edis-test`.split($/)
|
|
46
|
+
pids = processes.map { |process| process.split(" ")[0] }
|
|
47
|
+
puts "Killing test redis server..."
|
|
48
|
+
pids.each { |pid| Process.kill("TERM", pid.to_i) }
|
|
49
|
+
puts "removing redis db dump file"
|
|
50
|
+
sleep 5
|
|
51
|
+
`rm -f #{Mobilize::Base.root}/test/dump.rdb #{Mobilize::Base.root}/test/dump-cluster.rdb`
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def TestHelper.set_test_env
|
|
55
|
+
ENV['MOBILIZE_ENV']='test'
|
|
56
|
+
::Resque.redis="localhost:9736"
|
|
57
|
+
mongoid_config_path = "#{Mobilize::Base.root}/config/mobilize/mongoid.yml"
|
|
58
|
+
Mongoid.load!(mongoid_config_path, Mobilize::Base.env)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def TestHelper.drop_test_db
|
|
62
|
+
TestHelper.set_test_env
|
|
63
|
+
Mongoid.session(:default).collections.each do |collection|
|
|
64
|
+
unless collection.name =~ /^system\./
|
|
65
|
+
collection.drop
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def TestHelper.build_test_runner(user_name)
|
|
71
|
+
TestHelper.set_test_env
|
|
72
|
+
u = Mobilize::User.where(:name=>user_name).first
|
|
73
|
+
Mobilize::Jobtracker.update_status("delete old books and datasets")
|
|
74
|
+
# delete any old runner from previous test runs
|
|
75
|
+
gdrive_slot = Mobilize::Gdrive.owner_email
|
|
76
|
+
u.runner.gsheet(gdrive_slot).spreadsheet.delete
|
|
77
|
+
Mobilize::Dataset.find_by_handler_and_path('gbook',u.runner.title).delete
|
|
78
|
+
Mobilize::Jobtracker.update_status("enqueue jobtracker, wait 45s")
|
|
79
|
+
Mobilize::Jobtracker.start
|
|
80
|
+
sleep 45
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def TestHelper.owner_user
|
|
84
|
+
gdrive_slot = Mobilize::Gdrive.owner_email
|
|
85
|
+
puts "create user 'mobilize'"
|
|
86
|
+
user_name = gdrive_slot.split("@").first
|
|
87
|
+
return Mobilize::User.find_or_create_by_name(user_name)
|
|
88
|
+
end
|
|
89
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mobilize-base
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: '1.
|
|
4
|
+
version: '1.351'
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2013-04-
|
|
12
|
+
date: 2013-04-25 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: rake
|
|
@@ -191,6 +191,7 @@ files:
|
|
|
191
191
|
- lib/mobilize-base/handlers/gsheet.rb
|
|
192
192
|
- lib/mobilize-base/handlers/resque.rb
|
|
193
193
|
- lib/mobilize-base/helpers/job_helper.rb
|
|
194
|
+
- lib/mobilize-base/helpers/jobtracker_helper.rb
|
|
194
195
|
- lib/mobilize-base/helpers/runner_helper.rb
|
|
195
196
|
- lib/mobilize-base/helpers/stage_helper.rb
|
|
196
197
|
- lib/mobilize-base/jobtracker.rb
|
|
@@ -228,7 +229,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
228
229
|
version: '0'
|
|
229
230
|
segments:
|
|
230
231
|
- 0
|
|
231
|
-
hash:
|
|
232
|
+
hash: 4420073828570035753
|
|
232
233
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
233
234
|
none: false
|
|
234
235
|
requirements:
|
|
@@ -237,7 +238,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
237
238
|
version: '0'
|
|
238
239
|
segments:
|
|
239
240
|
- 0
|
|
240
|
-
hash:
|
|
241
|
+
hash: 4420073828570035753
|
|
241
242
|
requirements: []
|
|
242
243
|
rubyforge_project: mobilize-base
|
|
243
244
|
rubygems_version: 1.8.25
|