naf 1.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 (295) hide show
  1. data/.gitignore +16 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +17 -0
  4. data/Gemfile +17 -0
  5. data/LICENSE +2 -0
  6. data/README.rdoc +22 -0
  7. data/RELEASE_NOTES.rdoc +18 -0
  8. data/Rakefile +43 -0
  9. data/app/assets/images/bg-grad.png +0 -0
  10. data/app/assets/images/clock.png +0 -0
  11. data/app/assets/images/control_play_blue.png +0 -0
  12. data/app/assets/images/down_arrow.gif +0 -0
  13. data/app/assets/images/papertrail_job.png +0 -0
  14. data/app/assets/images/papertrail_machine.png +0 -0
  15. data/app/assets/images/papertrail_machine_runner.png +0 -0
  16. data/app/assets/images/terminate.png +0 -0
  17. data/app/assets/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  18. data/app/assets/images/ui-bg_flat_0_ffffff_40x100.png +0 -0
  19. data/app/assets/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  20. data/app/assets/images/ui-bg_glass_0_f4f4f4_1x400.png +0 -0
  21. data/app/assets/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  22. data/app/assets/images/ui-bg_glass_65_f4f4f4_1x400.png +0 -0
  23. data/app/assets/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  24. data/app/assets/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  25. data/app/assets/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  26. data/app/assets/images/ui-bg_glass_75_f4f4f4_1x400.png +0 -0
  27. data/app/assets/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  28. data/app/assets/images/ui-bg_highlight-soft_0_f4f4f4_1x100.png +0 -0
  29. data/app/assets/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  30. data/app/assets/images/ui-icons_222222_256x240.png +0 -0
  31. data/app/assets/images/ui-icons_2e83ff_256x240.png +0 -0
  32. data/app/assets/images/ui-icons_454545_256x240.png +0 -0
  33. data/app/assets/images/ui-icons_888888_256x240.png +0 -0
  34. data/app/assets/images/ui-icons_cd0a0a_256x240.png +0 -0
  35. data/app/assets/images/up_arrow.gif +0 -0
  36. data/app/assets/javascripts/dataTablesTemplates/applications.js +94 -0
  37. data/app/assets/javascripts/dataTablesTemplates/jobs.js +163 -0
  38. data/app/assets/javascripts/dataTablesTemplates/machine_runner_invocations.js +60 -0
  39. data/app/assets/javascripts/dataTablesTemplates/machine_runners.js +82 -0
  40. data/app/assets/javascripts/dataTablesTemplates/machines.js +93 -0
  41. data/app/assets/javascripts/date.js +104 -0
  42. data/app/assets/javascripts/iso8601.js +41 -0
  43. data/app/assets/javascripts/jquery.dataTables.custom.js +62 -0
  44. data/app/assets/javascripts/jquery.dataTables.js +6862 -0
  45. data/app/assets/javascripts/naf.js +30 -0
  46. data/app/assets/javascripts/underscore.js +713 -0
  47. data/app/assets/stylesheets/jquery_ui/jquery-ui-1.8.5.custom.css.erb +572 -0
  48. data/app/assets/stylesheets/min_naf.css +14 -0
  49. data/app/assets/stylesheets/min_naf/layout.css.scss +355 -0
  50. data/app/assets/stylesheets/naf.css +14 -0
  51. data/app/assets/stylesheets/naf/layout.css.scss +497 -0
  52. data/app/controllers/naf/affinities_controller.rb +61 -0
  53. data/app/controllers/naf/application_controller.rb +43 -0
  54. data/app/controllers/naf/application_schedule_affinity_tabs_controller.rb +75 -0
  55. data/app/controllers/naf/applications_controller.rb +153 -0
  56. data/app/controllers/naf/historical_job_affinity_tabs_controller.rb +65 -0
  57. data/app/controllers/naf/historical_jobs_controller.rb +159 -0
  58. data/app/controllers/naf/janitorial_assignments_controller.rb +77 -0
  59. data/app/controllers/naf/logger_names_controller.rb +58 -0
  60. data/app/controllers/naf/logger_styles_controller.rb +59 -0
  61. data/app/controllers/naf/machine_affinity_slots_controller.rb +69 -0
  62. data/app/controllers/naf/machine_runner_invocations_controller.rb +59 -0
  63. data/app/controllers/naf/machine_runners_controller.rb +26 -0
  64. data/app/controllers/naf/machines_controller.rb +95 -0
  65. data/app/helpers/naf/application_helper.rb +275 -0
  66. data/app/models/log4r/papertrail_outputter.rb +19 -0
  67. data/app/models/logical/naf/application.rb +183 -0
  68. data/app/models/logical/naf/construction_zone/ad_hoc_work_order.rb +22 -0
  69. data/app/models/logical/naf/construction_zone/application_schedule_work_order.rb +15 -0
  70. data/app/models/logical/naf/construction_zone/application_work_order.rb +25 -0
  71. data/app/models/logical/naf/construction_zone/boss.rb +123 -0
  72. data/app/models/logical/naf/construction_zone/foreman.rb +53 -0
  73. data/app/models/logical/naf/construction_zone/proletariat.rb +40 -0
  74. data/app/models/logical/naf/construction_zone/work_order.rb +100 -0
  75. data/app/models/logical/naf/create_infrastructure.rb +48 -0
  76. data/app/models/logical/naf/job.rb +357 -0
  77. data/app/models/logical/naf/job_creator.rb +155 -0
  78. data/app/models/logical/naf/job_fetcher.rb +167 -0
  79. data/app/models/logical/naf/job_statuses/errored.rb +27 -0
  80. data/app/models/logical/naf/job_statuses/finished.rb +26 -0
  81. data/app/models/logical/naf/job_statuses/finished_less_minute.rb +25 -0
  82. data/app/models/logical/naf/job_statuses/queued.rb +32 -0
  83. data/app/models/logical/naf/job_statuses/running.rb +34 -0
  84. data/app/models/logical/naf/job_statuses/terminated.rb +25 -0
  85. data/app/models/logical/naf/job_statuses/waiting.rb +43 -0
  86. data/app/models/logical/naf/machine.rb +85 -0
  87. data/app/models/logical/naf/machine_runner.rb +46 -0
  88. data/app/models/logical/naf/machine_runner_invocation.rb +50 -0
  89. data/app/models/logical/naf/pickler.rb +74 -0
  90. data/app/models/logical/naf/unpickler.rb +98 -0
  91. data/app/models/naf/affinity.rb +145 -0
  92. data/app/models/naf/affinity_classification.rb +44 -0
  93. data/app/models/naf/application.rb +100 -0
  94. data/app/models/naf/application_run_group_restriction.rb +39 -0
  95. data/app/models/naf/application_schedule.rb +181 -0
  96. data/app/models/naf/application_schedule_affinity_tab.rb +86 -0
  97. data/app/models/naf/application_schedule_prerequisite.rb +50 -0
  98. data/app/models/naf/application_type.rb +72 -0
  99. data/app/models/naf/by_historical_job_id.rb +86 -0
  100. data/app/models/naf/historical_job.rb +334 -0
  101. data/app/models/naf/historical_job_affinity_tab.rb +61 -0
  102. data/app/models/naf/historical_job_prerequisite.rb +19 -0
  103. data/app/models/naf/janitorial_archive_assignment.rb +36 -0
  104. data/app/models/naf/janitorial_assignment.rb +37 -0
  105. data/app/models/naf/janitorial_create_assignment.rb +36 -0
  106. data/app/models/naf/janitorial_drop_assignment.rb +36 -0
  107. data/app/models/naf/logger_level.rb +21 -0
  108. data/app/models/naf/logger_name.rb +23 -0
  109. data/app/models/naf/logger_style.rb +58 -0
  110. data/app/models/naf/logger_style_name.rb +28 -0
  111. data/app/models/naf/machine.rb +257 -0
  112. data/app/models/naf/machine_affinity_slot.rb +78 -0
  113. data/app/models/naf/machine_runner.rb +51 -0
  114. data/app/models/naf/machine_runner_invocation.rb +71 -0
  115. data/app/models/naf/naf_base.rb +9 -0
  116. data/app/models/naf/queued_job.rb +164 -0
  117. data/app/models/naf/running_job.rb +80 -0
  118. data/app/models/process/naf/application.rb +164 -0
  119. data/app/models/process/naf/janitor.rb +117 -0
  120. data/app/models/process/naf/machine_manager.rb +150 -0
  121. data/app/models/process/naf/machine_upgrader.rb +112 -0
  122. data/app/models/process/naf/runner.rb +539 -0
  123. data/app/views/naf/affinities/_form.html.erb +50 -0
  124. data/app/views/naf/affinities/edit.html.erb +11 -0
  125. data/app/views/naf/affinities/index.html.erb +57 -0
  126. data/app/views/naf/affinities/new.html.erb +15 -0
  127. data/app/views/naf/affinities/show.html.erb +48 -0
  128. data/app/views/naf/application_schedule_affinity_tabs/_form.html.erb +31 -0
  129. data/app/views/naf/application_schedule_affinity_tabs/edit.html.erb +12 -0
  130. data/app/views/naf/application_schedule_affinity_tabs/new.html.erb +11 -0
  131. data/app/views/naf/applications/_application_schedule.html.erb +80 -0
  132. data/app/views/naf/applications/_application_schedule_prerequisites.html.erb +14 -0
  133. data/app/views/naf/applications/_form.html.erb +109 -0
  134. data/app/views/naf/applications/_search_container.html.erb +94 -0
  135. data/app/views/naf/applications/_show.html.erb +34 -0
  136. data/app/views/naf/applications/edit.html.erb +11 -0
  137. data/app/views/naf/applications/index.html.erb +51 -0
  138. data/app/views/naf/applications/index.json.erb +11 -0
  139. data/app/views/naf/applications/new.html.erb +11 -0
  140. data/app/views/naf/applications/show.html.erb +203 -0
  141. data/app/views/naf/datatable.html.erb +49 -0
  142. data/app/views/naf/historical_job_affinity_tabs/_form.html.erb +36 -0
  143. data/app/views/naf/historical_job_affinity_tabs/edit.html.erb +11 -0
  144. data/app/views/naf/historical_job_affinity_tabs/new.html.erb +11 -0
  145. data/app/views/naf/historical_jobs/_form.html.erb +94 -0
  146. data/app/views/naf/historical_jobs/_runners.html.erb +22 -0
  147. data/app/views/naf/historical_jobs/_search_container.html.erb +140 -0
  148. data/app/views/naf/historical_jobs/edit.html.erb +11 -0
  149. data/app/views/naf/historical_jobs/index.html.erb +48 -0
  150. data/app/views/naf/historical_jobs/index.json.erb +26 -0
  151. data/app/views/naf/historical_jobs/new.html.erb +61 -0
  152. data/app/views/naf/historical_jobs/show.html.erb +201 -0
  153. data/app/views/naf/janitorial_assignments/_form.html.erb +38 -0
  154. data/app/views/naf/janitorial_assignments/_rows.html.erb +17 -0
  155. data/app/views/naf/janitorial_assignments/edit.html.erb +11 -0
  156. data/app/views/naf/janitorial_assignments/index.html.erb +56 -0
  157. data/app/views/naf/janitorial_assignments/index.js.erb +1 -0
  158. data/app/views/naf/janitorial_assignments/new.html.erb +11 -0
  159. data/app/views/naf/layouts/jquery_datatables.json.erb +6 -0
  160. data/app/views/naf/logger_names/_form.html.erb +18 -0
  161. data/app/views/naf/logger_names/edit.html.erb +11 -0
  162. data/app/views/naf/logger_names/new.html.erb +11 -0
  163. data/app/views/naf/logger_names/show.html.erb +44 -0
  164. data/app/views/naf/logger_styles/_form.html.erb +30 -0
  165. data/app/views/naf/logger_styles/_logger_style_names.html.erb +19 -0
  166. data/app/views/naf/logger_styles/edit.html.erb +11 -0
  167. data/app/views/naf/logger_styles/new.html.erb +11 -0
  168. data/app/views/naf/logger_styles/show.html.erb +48 -0
  169. data/app/views/naf/machine_affinity_slots/_form.html.erb +36 -0
  170. data/app/views/naf/machine_affinity_slots/edit.html.erb +11 -0
  171. data/app/views/naf/machine_affinity_slots/new.html.erb +11 -0
  172. data/app/views/naf/machine_runner_invocations/_filter.html.erb +21 -0
  173. data/app/views/naf/machine_runner_invocations/index.html.erb +36 -0
  174. data/app/views/naf/machine_runner_invocations/index.json.erb +16 -0
  175. data/app/views/naf/machine_runner_invocations/show.html.erb +91 -0
  176. data/app/views/naf/machine_runners/index.html.erb +82 -0
  177. data/app/views/naf/machine_runners/index.json.erb +16 -0
  178. data/app/views/naf/machine_runners/show.html.erb +113 -0
  179. data/app/views/naf/machines/_filter.html.erb +26 -0
  180. data/app/views/naf/machines/_form.html.erb +62 -0
  181. data/app/views/naf/machines/_show.html.erb +169 -0
  182. data/app/views/naf/machines/edit.html.erb +11 -0
  183. data/app/views/naf/machines/index.html.erb +51 -0
  184. data/app/views/naf/machines/index.json.erb +23 -0
  185. data/app/views/naf/machines/new.html.erb +11 -0
  186. data/app/views/naf/machines/show.html.erb +92 -0
  187. data/app/views/naf/record.html.erb +46 -0
  188. data/app/views/naf/shared/_application.html.erb +50 -0
  189. data/app/views/naf/shared/_information_container.html.erb +19 -0
  190. data/app/views/naf/shared/_select_per_page.html.erb +72 -0
  191. data/ci/test-build.sh +17 -0
  192. data/ci/travis.sh +26 -0
  193. data/config/initializers/naf.rb +3 -0
  194. data/config/routes.rb +38 -0
  195. data/db/migrate/20120820023848_naf_schema.rb +413 -0
  196. data/doc/README_FOR_APP +2 -0
  197. data/lib/generators/naf_generator.rb +45 -0
  198. data/lib/generators/templates/config/logging/af.yml +26 -0
  199. data/lib/generators/templates/config/logging/naf.yml +22 -0
  200. data/lib/generators/templates/config/logging/nafjob.yml +16 -0
  201. data/lib/generators/templates/config/logging/nafrunner.yml +17 -0
  202. data/lib/generators/templates/naf.rb +11 -0
  203. data/lib/generators/templates/naf_layout.html.erb +15 -0
  204. data/lib/naf.rb +48 -0
  205. data/lib/naf/configuration.rb +23 -0
  206. data/lib/naf/engine.rb +18 -0
  207. data/lib/naf/version.rb +3 -0
  208. data/lib/tasks/naf_tasks.rake +370 -0
  209. data/naf.gemspec +30 -0
  210. data/script/rails +10 -0
  211. data/spec/controllers/naf/affinities_controller_spec.rb +79 -0
  212. data/spec/controllers/naf/application_controller_spec.rb +10 -0
  213. data/spec/controllers/naf/application_schedule_affinity_tabs_controller_spec.rb +106 -0
  214. data/spec/controllers/naf/applications_controller_spec.rb +109 -0
  215. data/spec/controllers/naf/historical_job_affinity_tabs_controller_spec.rb +96 -0
  216. data/spec/controllers/naf/historical_jobs_controller_spec.rb +19 -0
  217. data/spec/controllers/naf/machine_affinity_slots_controller_spec.rb +109 -0
  218. data/spec/controllers/naf/machines_controller_spec.rb +74 -0
  219. data/spec/dummy/.gitignore +12 -0
  220. data/spec/dummy/README +19 -0
  221. data/spec/dummy/Rakefile +7 -0
  222. data/spec/dummy/app/assets/javascripts/application.js +16 -0
  223. data/spec/dummy/app/assets/stylesheets/application.css +14 -0
  224. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  225. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  226. data/spec/dummy/app/models/my_script.rb +8 -0
  227. data/spec/dummy/app/models/other/base.rb.sample +10 -0
  228. data/spec/dummy/app/views/layouts/application.html.erb +15 -0
  229. data/spec/dummy/app/views/layouts/naf_layout.html.erb +15 -0
  230. data/spec/dummy/config.ru +4 -0
  231. data/spec/dummy/config/application.rb +62 -0
  232. data/spec/dummy/config/boot.rb +10 -0
  233. data/spec/dummy/config/database-non_primary.yml +20 -0
  234. data/spec/dummy/config/database-primary.yml +16 -0
  235. data/spec/dummy/config/environment.rb +5 -0
  236. data/spec/dummy/config/environments/development.rb +37 -0
  237. data/spec/dummy/config/environments/production.rb +67 -0
  238. data/spec/dummy/config/environments/test.rb +37 -0
  239. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  240. data/spec/dummy/config/initializers/inflections.rb +15 -0
  241. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  242. data/spec/dummy/config/initializers/naf.rb.non_primary +4 -0
  243. data/spec/dummy/config/initializers/naf.rb.primary +3 -0
  244. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  245. data/spec/dummy/config/initializers/session_store.rb +8 -0
  246. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  247. data/spec/dummy/config/locales/en.yml +5 -0
  248. data/spec/dummy/config/logging/af.yml +26 -0
  249. data/spec/dummy/config/logging/naf.yml +22 -0
  250. data/spec/dummy/config/logging/nafjob.yml +16 -0
  251. data/spec/dummy/config/logging/nafrunner.yml +17 -0
  252. data/spec/dummy/config/routes.rb +5 -0
  253. data/spec/dummy/db/.gitignore +2 -0
  254. data/spec/dummy/lib/tasks/dummy.rake +60 -0
  255. data/spec/dummy/public/404.html +26 -0
  256. data/spec/dummy/public/422.html +26 -0
  257. data/spec/dummy/public/500.html +25 -0
  258. data/spec/dummy/public/favicon.ico +0 -0
  259. data/spec/dummy/script/rails +6 -0
  260. data/spec/factories/naf.rb +433 -0
  261. data/spec/helpers/naf/application_helper_spec.rb +0 -0
  262. data/spec/models/logical/naf/application_spec.rb +69 -0
  263. data/spec/models/logical/naf/job_creator_spec.rb +32 -0
  264. data/spec/models/logical/naf/job_fetcher_spec.rb +140 -0
  265. data/spec/models/logical/naf/job_spec.rb +282 -0
  266. data/spec/models/logical/naf/machine_spec.rb +61 -0
  267. data/spec/models/naf/affinity_classification_spec.rb +56 -0
  268. data/spec/models/naf/affinity_spec.rb +100 -0
  269. data/spec/models/naf/application_run_group_restriction_spec.rb +57 -0
  270. data/spec/models/naf/application_schedule_affinity_tab_spec.rb +85 -0
  271. data/spec/models/naf/application_schedule_prerequisite_spec.rb +35 -0
  272. data/spec/models/naf/application_schedule_spec.rb +166 -0
  273. data/spec/models/naf/application_spec.rb +128 -0
  274. data/spec/models/naf/application_type_spec.rb +104 -0
  275. data/spec/models/naf/historical_job_affinity_tab_spec.rb +59 -0
  276. data/spec/models/naf/historical_job_prerequisite_spec.rb +25 -0
  277. data/spec/models/naf/historical_job_spec.rb +334 -0
  278. data/spec/models/naf/logger_level_spec.rb +34 -0
  279. data/spec/models/naf/logger_name_spec.rb +35 -0
  280. data/spec/models/naf/logger_style_name_spec.rb +39 -0
  281. data/spec/models/naf/logger_style_spec.rb +89 -0
  282. data/spec/models/naf/machine_affinity_slot_spec.rb +77 -0
  283. data/spec/models/naf/machine_runner_invocation_spec.rb +38 -0
  284. data/spec/models/naf/machine_runner_spec.rb +37 -0
  285. data/spec/models/naf/machine_spec.rb +425 -0
  286. data/spec/models/naf/naf_base_spec.rb +14 -0
  287. data/spec/models/naf/queued_job_spec.rb +171 -0
  288. data/spec/models/naf/running_job_spec.rb +107 -0
  289. data/spec/models/process/naf/application_spec.rb +8 -0
  290. data/spec/models/process/naf/janitor_spec.rb +10 -0
  291. data/spec/models/process/naf/runner_spec.rb +10 -0
  292. data/spec/spec_helper.rb +32 -0
  293. data/spec/support/engine_routing.rb +27 -0
  294. data/spec/support/script_spec_helper.rb +58 -0
  295. metadata +590 -0
@@ -0,0 +1,50 @@
1
+ module Naf
2
+ class ApplicationSchedulePrerequisite < ::Naf::NafBase
3
+ # Protect from mass-assignment issue
4
+ attr_accessible :application_schedule_id,
5
+ :prerequisite_application_schedule_id
6
+
7
+ #---------------------
8
+ # *** Associations ***
9
+ #+++++++++++++++++++++
10
+
11
+ belongs_to :application_schedule,
12
+ class_name: "::Naf::ApplicationSchedule"
13
+ belongs_to :prerequisite_application_schedule,
14
+ class_name: "::Naf::ApplicationSchedule"
15
+
16
+ #--------------------
17
+ # *** Validations ***
18
+ #++++++++++++++++++++
19
+
20
+ validates :prerequisite_application_schedule_id, presence: true
21
+ validates :application_schedule_id, uniqueness: {
22
+ scope: :prerequisite_application_schedule_id
23
+ }
24
+
25
+ def self.pickleables(pickler)
26
+ return self.joins([application_schedule: :application]).
27
+ where('applications.deleted = false').
28
+ where(
29
+ "NOT EXISTS(
30
+ SELECT
31
+ 1
32
+ FROM
33
+ #{::Naf.schema_name}.application_schedules AS a_s
34
+ WHERE
35
+ application_schedule_prerequisites.prerequisite_application_schedule_id = a_s.id AND
36
+ EXISTS(
37
+ SELECT
38
+ 1
39
+ FROM
40
+ #{::Naf.schema_name}.applications AS a
41
+ WHERE
42
+ a_s.application_id = a.id AND
43
+ deleted IS TRUE
44
+ )
45
+ )"
46
+ )
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,72 @@
1
+ module Naf
2
+ class ApplicationType < NafBase
3
+ # Protect from mass-assignment issue
4
+ attr_accessible :enabled,
5
+ :script_type_name,
6
+ :description,
7
+ :invocation_method
8
+
9
+ SCRIPT_RUNNER = "#{Gem.ruby} #{Rails.root}/script/rails runner"
10
+
11
+ #---------------------
12
+ # *** Associations ***
13
+ #+++++++++++++++++++++
14
+
15
+ has_many :applications,
16
+ class_name: "::Naf::Application"
17
+ has_many :historical_jobs,
18
+ class_name: "::Naf::HistoricalJob"
19
+
20
+ #--------------------
21
+ # *** Validations ***
22
+ #++++++++++++++++++++
23
+
24
+ validates :script_type_name,
25
+ :invocation_method, presence: true
26
+
27
+ #-------------------------
28
+ # *** Instance Methods ***
29
+ #+++++++++++++++++++++++++
30
+
31
+ def spawn(job)
32
+ self.send(invocation_method.to_sym, job)
33
+ end
34
+
35
+ def invoke(job, command)
36
+ Process.spawn({ "NAF_JOB_ID" => job.id.to_s }, command)
37
+ end
38
+
39
+ def rails_invocator(job)
40
+ invoke(job, SCRIPT_RUNNER + " " + job.command)
41
+ end
42
+
43
+ def bash_command_invocator(job)
44
+ invoke(job, job.command)
45
+ end
46
+
47
+ def bash_script_invocator(job)
48
+ invoke(job, job.command)
49
+ end
50
+
51
+ def ruby_script_invocator(job)
52
+ invoke(job, job.command)
53
+ end
54
+
55
+ def self.rails
56
+ @rails ||= find_by_script_type_name('rails')
57
+ end
58
+
59
+ def self.ruby
60
+ @ruby ||= find_by_script_type_name('ruby')
61
+ end
62
+
63
+ def self.bash_command
64
+ @bash_command ||= find_by_script_type_name('bash command')
65
+ end
66
+
67
+ def self.bash_script
68
+ @bash_script ||= find_by_script_type_name('bash script')
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,86 @@
1
+ module Naf
2
+ class ByHistoricalJobId < ::Partitioned::ByIntegerField
3
+ self.abstract_class = true
4
+
5
+ # Protect from mass-assignment issue
6
+ attr_accessible :historical_job_id
7
+
8
+ #---------------------
9
+ # *** Associations ***
10
+ #+++++++++++++++++++++
11
+
12
+ belongs_to :historical_job,
13
+ class_name: "::Naf::HistoricalJob"
14
+
15
+ #--------------------
16
+ # *** Validations ***
17
+ #++++++++++++++++++++
18
+
19
+ validates :historical_job_id, presence: true
20
+
21
+ #------------------
22
+ # *** Partition ***
23
+ #++++++++++++++++++
24
+
25
+ partitioned do |partition|
26
+ partition.index :id, unique: true
27
+
28
+ partition.foreign_key lambda { |model, *partition_key_values|
29
+ return ::Partitioned::PartitionedBase::Configurator::Data::ForeignKey.
30
+ new(model.partition_integer_field,
31
+ ::Naf::HistoricalJob.partition_table_name(*partition_key_values),
32
+ :id)
33
+ }
34
+
35
+ partition.janitorial_creates_needed lambda { |model, *partition_key_values|
36
+ sequence_name = model.connection.default_sequence_name(model.table_name)
37
+ current_id = model.find_by_sql("select last_value as id from #{sequence_name}").first.id
38
+ start_range = [0, current_id - (model.partition_table_size * model.partition_num_lead_buffers)].max
39
+ end_range = current_id + (model.partition_table_size * model.partition_num_lead_buffers)
40
+
41
+ return model.partition_generate_range(start_range, end_range).reject{ |p| model.sql_adapter.partition_exists?(p) }
42
+ }
43
+
44
+ partition.janitorial_archives_needed []
45
+ partition.janitorial_drops_needed lambda { |model, *partition_key_values|
46
+ sequence_name = model.connection.default_sequence_name(model.table_name)
47
+ current_id = model.find_by_sql("select last_value as id from #{sequence_name}").first.id
48
+ partition_key_value = current_id - (model.partition_table_size * model.partition_num_lead_buffers)
49
+ partition_key_values_to_drop = []
50
+ while model.sql_adapter.partition_exists?(partition_key_value)
51
+ partition_key_values_to_drop << partition_key_value
52
+ partition_key_value -= model.partition_table_size
53
+ end
54
+
55
+ return partition_key_values_to_drop
56
+ }
57
+ end
58
+
59
+ #----------------------
60
+ # *** Class Methods ***
61
+ #++++++++++++++++++++++
62
+
63
+ # the field to partition on
64
+ # @return [Integer] re-routed to {#self.partition_foreign_key}
65
+ def self.partition_integer_field
66
+ return :historical_job_id
67
+ end
68
+
69
+ def self.connection
70
+ return ::Naf::NafBase.connection
71
+ end
72
+
73
+ def self.full_table_name_prefix
74
+ return ::Naf::NafBase.full_table_name_prefix
75
+ end
76
+
77
+ def self.partition_table_size
78
+ return ::Naf::HistoricalJob.partition_table_size
79
+ end
80
+
81
+ def self.partition_num_lead_buffers
82
+ return ::Naf::HistoricalJob.partition_num_lead_buffers
83
+ end
84
+
85
+ end
86
+ end
@@ -0,0 +1,334 @@
1
+ module Naf
2
+ #
3
+ # Things you should know about jobs
4
+ # new jobs older than 1.week will not be searched in the queue. You should not run programs
5
+ # for more than a 1.week (instead, have them exit and restarted periodically)
6
+ #
7
+ class HistoricalJob < ::Partitioned::ById
8
+ class JobPrerequisiteLoop < StandardError
9
+ def initialize(job)
10
+ super("loop found in prerequisites for #{job}")
11
+ end
12
+ end
13
+
14
+ include PgAdvisoryLocker
15
+
16
+ # Protect from mass-assignment issue
17
+ attr_accessible :application_id,
18
+ :application_type_id,
19
+ :command,
20
+ :application_run_group_restriction_id,
21
+ :application_run_group_name,
22
+ :application_run_group_limit,
23
+ :priority,
24
+ :started_on_machine_id,
25
+ :failed_to_start,
26
+ :pid,
27
+ :exit_status,
28
+ :termination_signal,
29
+ :state,
30
+ :request_to_terminate,
31
+ :marked_dead_by_machine_id,
32
+ :log_level,
33
+ :tags,
34
+ :machine_runner_invocation_id
35
+
36
+ JOB_STALE_TIME = 1.week
37
+ SYSTEM_TAGS = {
38
+ startup: '$startup',
39
+ pre_work: '$pre-work',
40
+ work: '$work',
41
+ cleanup: '$cleanup'
42
+ }
43
+
44
+ #---------------------
45
+ # *** Associations ***
46
+ #+++++++++++++++++++++
47
+
48
+ belongs_to :application_type,
49
+ class_name: '::Naf::ApplicationType'
50
+ belongs_to :started_on_machine,
51
+ class_name: '::Naf::Machine',
52
+ foreign_key: 'started_on_machine_id'
53
+ belongs_to :marked_dead_by_machine,
54
+ class_name: '::Naf::Machine',
55
+ foreign_key: 'marked_dead_by_machine_id'
56
+ belongs_to :application,
57
+ class_name: "::Naf::Application"
58
+ belongs_to :application_run_group_restriction,
59
+ class_name: "::Naf::ApplicationRunGroupRestriction"
60
+ belongs_to :machine_runner_invocation,
61
+ class_name: "::Naf::MachineRunnerInvocation"
62
+ # Must access instance methods job_prerequisites through helper methods so we can use partitioning sql
63
+ has_many :historical_job_prerequisites,
64
+ class_name: "::Naf::HistoricalJobPrerequisite",
65
+ dependent: :destroy
66
+ has_many :prerequisites,
67
+ class_name: "::Naf::HistoricalJob",
68
+ through: :historical_job_prerequisites,
69
+ source: :prerequisite_historical_job
70
+ # Access supported through instance methods
71
+ has_many :historical_job_affinity_tabs,
72
+ class_name: "::Naf::HistoricalJobAffinityTab",
73
+ dependent: :destroy
74
+ has_many :affinities,
75
+ class_name: "::Naf::Affinity",
76
+ through: :historical_job_affinity_tabs
77
+
78
+ #--------------------
79
+ # *** Validations ***
80
+ #++++++++++++++++++++
81
+
82
+ validates :application_type_id,
83
+ :command,
84
+ :application_run_group_restriction_id, presence: true
85
+
86
+ validates :command, length: {
87
+ minimum: 3
88
+ }
89
+ validates :application_run_group_limit, numericality: {
90
+ only_integer: true,
91
+ greater_than_or_equal_to: 1,
92
+ less_than: 2147483647,
93
+ allow_blank: true
94
+ }
95
+
96
+ #--------------------
97
+ # *** Delegations ***
98
+ #++++++++++++++++++++
99
+
100
+ delegate :application_run_group_restriction_name, to: :application_run_group_restriction
101
+ delegate :script_type_name, to: :application_type
102
+
103
+ #------------------
104
+ # *** Partition ***
105
+ #++++++++++++++++++
106
+
107
+ partitioned do |partition|
108
+ partition.foreign_key :application_id, ::Naf::Application.table_name
109
+ partition.foreign_key :application_type_id, ::Naf::ApplicationType.table_name
110
+ partition.foreign_key :application_run_group_restriction_id, ::Naf::ApplicationRunGroupRestriction.table_name
111
+ partition.foreign_key :started_on_machine_id, ::Naf::Machine.table_name
112
+ partition.index :created_at
113
+ partition.index :application_id
114
+ partition.index :started_on_machine_id
115
+ partition.index :command
116
+ partition.index :application_run_group_name
117
+ partition.index :finished_at
118
+ partition.index :exit_status
119
+
120
+ partition.janitorial_creates_needed lambda { |model, *partition_key_values|
121
+ sequence_name = model.connection.default_sequence_name(model.table_name)
122
+ current_id = model.find_by_sql("select last_value as id from #{sequence_name}").first.id
123
+ start_range = [0, current_id - (model.partition_table_size * model.partition_num_lead_buffers)].max
124
+ end_range = current_id + (model.partition_table_size * model.partition_num_lead_buffers)
125
+ return model.partition_generate_range(start_range, end_range).reject{|p| model.sql_adapter.partition_exists?(p)}
126
+ }
127
+ partition.janitorial_archives_needed []
128
+ partition.janitorial_drops_needed lambda { |model, *partition_key_values|
129
+ sequence_name = model.connection.default_sequence_name(model.table_name)
130
+ current_id = model.find_by_sql("select last_value as id from #{sequence_name}").first.id
131
+ partition_key_value = current_id - (model.partition_table_size * model.partition_num_lead_buffers)
132
+ partition_key_values_to_drop = []
133
+ while model.sql_adapter.partition_exists?(partition_key_value)
134
+ partition_key_values_to_drop << partition_key_value
135
+ partition_key_value -= model.partition_table_size
136
+ end
137
+ return partition_key_values_to_drop
138
+ }
139
+ end
140
+
141
+ #----------------------
142
+ # *** Class Methods ***
143
+ #++++++++++++++++++++++
144
+
145
+ def self.connection
146
+ ::Naf::NafBase.connection
147
+ end
148
+
149
+ def self.full_table_name_prefix
150
+ ::Naf::NafBase.full_table_name_prefix
151
+ end
152
+
153
+ def self.partition_table_size
154
+ 100000
155
+ end
156
+
157
+ def self.partition_num_lead_buffers
158
+ 10
159
+ end
160
+
161
+ def self.queued_between(start_time, end_time)
162
+ where(["created_at >= ? AND created_at <= ?", start_time, end_time])
163
+ end
164
+
165
+ def self.canceled
166
+ where(request_to_terminate: true)
167
+ end
168
+
169
+ def self.application_last_runs
170
+ where("application_id IS NOT NULL").
171
+ group("application_id").
172
+ select("application_id, MAX(finished_at) AS finished_at").
173
+ reject{ |job| job.finished_at.nil? }
174
+ end
175
+
176
+ def self.application_last_queued
177
+ where("application_id IS NOT NULL").
178
+ group("application_id").
179
+ select("application_id, MAX(id) AS id, MAX(created_at) AS created_at")
180
+ end
181
+
182
+ def self.finished
183
+ where("finished_at IS NOT NULL OR request_to_terminate = true")
184
+ end
185
+
186
+ def self.queued_status
187
+ where("(started_at IS NULL AND request_to_terminate = false) OR
188
+ (finished_at > '#{Time.zone.now - 1.minute}') OR
189
+ (started_at IS NOT NULL AND finished_at IS NULL AND request_to_terminate = false)")
190
+ end
191
+
192
+ def self.running_status
193
+ where("(started_at IS NOT NULL AND finished_at IS NULL AND request_to_terminate = false) OR
194
+ (finished_at > '#{Time.zone.now - 1.minute}')")
195
+ end
196
+
197
+ def self.queued_with_waiting
198
+ where("(started_at IS NULL AND request_to_terminate = false)")
199
+ end
200
+
201
+ def self.errored
202
+ where("finished_at IS NOT NULL AND exit_status > 0 OR request_to_terminate = true")
203
+ end
204
+
205
+ def self.lock_for_job_queue(&block)
206
+ lock_record(0, &block)
207
+ end
208
+
209
+ #-------------------------
210
+ # *** Instance Methods ***
211
+ #+++++++++++++++++++++++++
212
+
213
+ def to_s
214
+ components = []
215
+
216
+ if started_at.nil?
217
+ components << "QUEUED"
218
+ else
219
+ if finished_at.nil?
220
+ if pid
221
+ extras = []
222
+ extras << pid.to_s
223
+ extras << 'RequestedToTerminate' if request_to_terminate
224
+ components << "RUNNING:#{extras.join(':')}"
225
+ else
226
+ components << "SPAWNING"
227
+ end
228
+ else
229
+ extras = []
230
+ extras << 'RequestedToTerminate' if request_to_terminate
231
+ extras << "FailedToStart" if failed_to_start
232
+ extras << "SIG#{termination_signal}" if termination_signal
233
+ if exit_status && exit_status != 0
234
+ extras << "STATUS=#{exit_status}"
235
+ end
236
+ if extras.length
237
+ extras_str = " (#{extras.join(',')})"
238
+ else
239
+ extras_str = ""
240
+ end
241
+ components << "FINISHED#{extras_str}"
242
+ end
243
+ end
244
+ components << "id: #{id}"
245
+ components << "\"#{command}\""
246
+
247
+ return "::Naf::HistoricalJob<#{components.join(', ')}>"
248
+ end
249
+
250
+ def title
251
+ application.try(:title)
252
+ end
253
+
254
+ def machine_started_on_server_name
255
+ started_on_machine.try(:server_name)
256
+ end
257
+
258
+ def machine_started_on_server_address
259
+ started_on_machine.try(:server_address)
260
+ end
261
+
262
+ def historical_job_affinity_tabs
263
+ ::Naf::HistoricalJobAffinityTab.
264
+ from_partition(id).
265
+ where(historical_job_id: id)
266
+ end
267
+
268
+ def job_affinities
269
+ historical_job_affinity_tabs.map{ |jat| jat.affinity }
270
+ end
271
+
272
+ def affinity_ids
273
+ historical_job_affinity_tabs.map{ |jat| jat.affinity_id }
274
+ end
275
+
276
+ def historical_job_prerequisites
277
+ ::Naf::HistoricalJobPrerequisite.
278
+ from_partition(id).
279
+ where(historical_job_id: id)
280
+ end
281
+
282
+ def prerequisites
283
+ historical_job_prerequisites.
284
+ map{ |hjp| ::Naf::HistoricalJob.from_partition(hjp.prerequisite_historical_job_id).
285
+ find_by_id(hjp.prerequisite_historical_job_id) }.
286
+ reject{ |j| j.nil? }
287
+ end
288
+
289
+ # XXX This should go away (it was moved to ConstructionZone::Foreman)
290
+
291
+ def verify_prerequisites(these_jobs)
292
+ these_jobs.each do |this_job|
293
+ if this_job.id == id
294
+ raise JobPrerequisiteLoop.new(self)
295
+ else
296
+ verify_prerequisites(this_job.prerequisites)
297
+ end
298
+ end
299
+ end
300
+
301
+ def spawn
302
+ application_type.spawn(self)
303
+ end
304
+
305
+ def add_tags(tags_to_add)
306
+ tags_array = nil
307
+ if self.tags.present?
308
+ tags_array = self.tags.gsub(/[{}]/,'').split(',')
309
+ new_tags = '{' + (tags_array | tags_to_add).join(',') + '}'
310
+ else
311
+ new_tags = '{' + tags_to_add.join(',') + '}'
312
+ end
313
+
314
+ self.tags = new_tags
315
+ self.save!
316
+ end
317
+
318
+ def remove_tags(tags_to_remove)
319
+ if self.tags.present?
320
+ tags_array = self.tags.gsub(/[{}]/,'').split(',')
321
+ new_tags = '{' + (tags_array - tags_to_remove).join(',') + '}'
322
+
323
+ self.tags = new_tags
324
+ self.save!
325
+ end
326
+ end
327
+
328
+ def remove_all_tags
329
+ self.tags = '{}'
330
+ self.save!
331
+ end
332
+
333
+ end
334
+ end