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,22 @@
1
+ module Logical::Naf::ConstructionZone
2
+ class AdHocWorkOrder < WorkOrder
3
+ def initialize(*parameters)
4
+ maybe_hash = parameters.first
5
+ if maybe_hash.is_a?(Hash)
6
+ super(maybe_hash[:command],
7
+ maybe_hash[:application_type] || ::Naf::ApplicationType.rails,
8
+ maybe_hash[:application_run_group_restriction] || ::Naf::ApplicationRunGroupRestriction.limited_per_all_machines,
9
+ maybe_hash[:application_run_group_name] || :command,
10
+ maybe_hash[:application_run_group_limit] || 1,
11
+ maybe_hash[:priority] || 0,
12
+ maybe_hash[:affinities] || [],
13
+ maybe_hash[:prerequisites] || [],
14
+ maybe_hash[:enqueue_backlogs] || false,
15
+ maybe_hash[:application] || nil,
16
+ maybe_hash[:application_schedule] || nil)
17
+ else
18
+ super(*parameters)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ module Logical::Naf::ConstructionZone
2
+ class ApplicationScheduleWorkOrder < ApplicationWorkOrder
3
+ def initialize(application_schedule)
4
+ super(application_schedule.application,
5
+ application_schedule.application_run_group_restriction,
6
+ application_schedule.application_run_group_name,
7
+ application_schedule.application_run_group_limit,
8
+ application_schedule.priority,
9
+ application_schedule.affinities,
10
+ application_schedule.prerequisites,
11
+ application_schedule.enqueue_backlogs,
12
+ application_schedule)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ module Logical::Naf::ConstructionZone
2
+ class ApplicationWorkOrder < WorkOrder
3
+ def initialize(application,
4
+ application_run_group_restriction = ::Naf::ApplicationRunGroupRestriction.limited_per_all_machines,
5
+ application_run_group_name = :command,
6
+ application_run_group_limit = 1,
7
+ priority = 0,
8
+ affinities = [],
9
+ prerequisites = [],
10
+ enqueue_backlogs = false,
11
+ application_schedule = nil)
12
+ super(application.command,
13
+ application.application_type,
14
+ application_run_group_restriction,
15
+ application_run_group_name,
16
+ application_run_group_limit,
17
+ priority,
18
+ affinities,
19
+ prerequisites,
20
+ enqueue_backlogs,
21
+ application,
22
+ application_schedule)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,123 @@
1
+ module Logical::Naf::ConstructionZone
2
+ class Boss
3
+ include ::Af::Application::Component
4
+ create_proxy_logger
5
+
6
+ def initialize()
7
+ @foreman = Foreman.new()
8
+ end
9
+
10
+ def enqueue_application(application,
11
+ application_run_group_restriction,
12
+ application_run_group_name,
13
+ application_run_group_limit = 1,
14
+ priority = 0,
15
+ affinities = [],
16
+ prerequisites = [],
17
+ enqueue_backlogs = false)
18
+ work_order = ApplicationWorkOrder.new(application,
19
+ application_run_group_restriction,
20
+ application_run_group_name,
21
+ application_run_group_limit = 1,
22
+ priority = 0,
23
+ affinities = [],
24
+ prerequisites = [],
25
+ enqueue_backlogs = false)
26
+ @foreman.enqueue(work_order)
27
+ end
28
+
29
+ def enqueue_application_schedule(application_schedule)
30
+ work_order = ApplicationScheduleWorkOrder.new(application_schedule)
31
+ @foreman.enqueue(work_order)
32
+ end
33
+
34
+ def enqueue_rails_command(command,
35
+ application_run_group_restriction = ::Naf::ApplicationRunGroupRestriction.limited_per_all_machines,
36
+ application_run_group_name = :command,
37
+ application_run_group_limit = 1,
38
+ priority = 0,
39
+ affinities = [],
40
+ prerequisites = [],
41
+ enqueue_backlogs = false)
42
+ work_order = WorkOrder.new(command,
43
+ ::Naf::ApplicationType.rails,
44
+ application_run_group_restriction,
45
+ application_run_group_name,
46
+ application_run_group_limit,
47
+ priority,
48
+ affinities,
49
+ prerequisites,
50
+ enqueue_backlogs)
51
+ @foreman.enqueue(work_order)
52
+ end
53
+
54
+ def enqueue_command(command,
55
+ application_type = ::Naf::ApplicationType.rails,
56
+ application_run_group_restriction = ::Naf::ApplicationRunGroupRestriction.limited_per_all_machines,
57
+ application_run_group_name = :command,
58
+ application_run_group_limit = 1,
59
+ priority = 0,
60
+ affinities = [],
61
+ prerequisites = [],
62
+ enqueue_backlogs = false)
63
+ work_order = WorkOrder.new(application_type,
64
+ command,
65
+ application_run_group_restriction,
66
+ application_run_group_name,
67
+ application_run_group_limit,
68
+ priority,
69
+ affinities,
70
+ prerequisites,
71
+ enqueue_backlogs)
72
+ @foreman.enqueue(work_order)
73
+ end
74
+
75
+ def enqueue_ad_hoc_command(parameters)
76
+ work_order = AdHocWorkOrder.new(parameters)
77
+ @foreman.enqueue(work_order)
78
+ end
79
+
80
+ def enqueue_n_commands_on_machines(parameters, number_of_jobs = :from_limit, machines = [])
81
+ logger.detail "enqueuing #{parameters[:command]} #{number_of_jobs} time(s) on #{machines.length} machine(s)"
82
+ machines.each do |machine|
83
+ number_of_jobs = (parameters[:application_run_group_limit] || 1) if number_of_jobs == :from_limit
84
+ logger.info "enqueuing #{parameters[:command]} #{number_of_jobs} time(s) on #{machine}"
85
+ (1..number_of_jobs).each do
86
+ machine_parameters = {
87
+ :application_run_group_limit => number_of_jobs,
88
+ :application_run_group_restriction => ::Naf::ApplicationRunGroupRestriction.limited_per_machine
89
+ }.merge(parameters)
90
+ machine_parameters[:affinities] =
91
+ [machine.affinity] + if machine_parameters[:affinities].nil?
92
+ []
93
+ elsif machine_parameters[:affinities].is_a? Array
94
+ machine_parameters[:affinities]
95
+ else
96
+ [machine_parameters[:affinities]]
97
+ end
98
+ work_order = AdHocWorkOrder.new(machine_parameters)
99
+ @foreman.enqueue(work_order)
100
+ end
101
+ end
102
+ end
103
+
104
+ def enqueue_n_commands(parameters, number_of_jobs = :from_limit)
105
+ number_of_jobs = (parameters[:application_run_group_limit] || 1) if number_of_jobs == :from_limit
106
+ logger.info "enqueuing #{parameters[:command]} #{number_of_jobs} time(s) on #{machine}"
107
+ (1..number_of_jobs).each do
108
+ work_order = AdHocWorkOrder.new({:application_run_group_limit => number_of_jobs}.merge(parameters))
109
+ @foreman.enqueue(work_order)
110
+ end
111
+ end
112
+
113
+ def reenqueue(job)
114
+ enqueue_rails_command(job.command,
115
+ job.application_run_group_restriction,
116
+ job.application_run_group_name,
117
+ job.application_run_group_limit,
118
+ job.priority,
119
+ job.job_affinity_tabs.map{|jat| jat.affinity})
120
+ end
121
+
122
+ end
123
+ end
@@ -0,0 +1,53 @@
1
+ module Logical::Naf::ConstructionZone
2
+ class Foreman
3
+ include ::Af::Application::Component
4
+ create_proxy_logger
5
+
6
+ def initialize()
7
+ @proletariat = Proletariat.new
8
+ end
9
+
10
+ def enqueue(work_order)
11
+ limited = false
12
+ unless work_order.enqueue_backlogs
13
+ if limited_by_run_group?(work_order.application_run_group_restriction,
14
+ work_order.application_run_group_name,
15
+ work_order.application_run_group_limit)
16
+ limited = true
17
+ logger.warn "work order limited by run queue limits #{work_order.inspect}"
18
+ end
19
+ end
20
+ unless limited
21
+ @proletariat.create_job(work_order.historical_job_parameters,
22
+ work_order.historical_job_affinity_tab_parameters,
23
+ work_order.historical_job_prerequisite_historical_jobs)
24
+ end
25
+ end
26
+
27
+ def limited_by_run_group?(application_run_group_restriction, application_run_group_name, application_run_group_limit)
28
+ if (application_run_group_restriction.id == ::Naf::ApplicationRunGroupRestriction.no_limit.id ||
29
+ application_run_group_limit.nil? ||
30
+ application_run_group_name.nil?)
31
+ false
32
+ elsif application_run_group_restriction.id == ::Naf::ApplicationRunGroupRestriction.limited_per_machine.id
33
+ # XXX this is difficult to figure out, so we punt for now
34
+ # XXX we should check if there is any machine affinity (must pass that in) and
35
+ # XXX if so check if that machine has this application group running on it.
36
+ # XXX but this code is only used as a heuristic for queues
37
+
38
+ #(::Naf::QueuedJob.where(:application_run_group_name => application_run_group_name).count +
39
+ #::Naf::RunningJob.where(:application_run_group_name => application_run_group_name,
40
+ #:started_on_machine_id => @machine.id).count) >= application_run_group_limit
41
+
42
+ # XXX just returning false
43
+ false
44
+ elsif application_run_group_restriction.id == ::Naf::ApplicationRunGroupRestriction.limited_per_all_machines.id
45
+ (::Naf::QueuedJob.where(:application_run_group_name => application_run_group_name).count +
46
+ ::Naf::RunningJob.where(:application_run_group_name => application_run_group_name).count) >= application_run_group_limit
47
+ else
48
+ logger.warn "not limited by run group restriction but don't know why: #{application_run_group_restriction.inspect}"
49
+ true
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,40 @@
1
+ module Logical::Naf::ConstructionZone
2
+ class Proletariat
3
+ def create_job(parameters, affinities, prerequisites)
4
+ ::Naf::HistoricalJob.transaction do
5
+ historical_job = create_historical_job(parameters, affinities, prerequisites)
6
+ queued_job = create_queued_job(historical_job)
7
+ return historical_job
8
+ end
9
+ end
10
+
11
+ def create_historical_job(parameters, affinities, prerequisites)
12
+ ::Naf::HistoricalJob.transaction do
13
+ historical_job = ::Naf::HistoricalJob.create!(parameters)
14
+ affinities.each do |affinity|
15
+ ::Naf::HistoricalJobAffinityTab.create(affinity.merge(historical_job_id: historical_job.id))
16
+ end
17
+ historical_job.verify_prerequisites(prerequisites)
18
+ prerequisites.each do |prerequisite|
19
+ ::Naf::HistoricalJobPrerequisite.create({
20
+ historical_job_id: historical_job.id,
21
+ prerequisite_historical_job_id: prerequisite.id
22
+ })
23
+ end
24
+ return historical_job
25
+ end
26
+ end
27
+
28
+ def create_queued_job(historical_job)
29
+ queued_job = ::Naf::QueuedJob.new(application_id: historical_job.application_id,
30
+ application_type_id: historical_job.application_type_id,
31
+ command: historical_job.command,
32
+ application_run_group_restriction_id: historical_job.application_run_group_restriction_id,
33
+ application_run_group_name: historical_job.application_run_group_name,
34
+ application_run_group_limit: historical_job.application_run_group_limit,
35
+ priority: historical_job.priority)
36
+ queued_job.id = historical_job.id
37
+ queued_job.save!
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,100 @@
1
+ module Logical::Naf::ConstructionZone
2
+ class WorkOrder
3
+ attr_reader :command, :application_type, :application_run_group_restriction, :application_run_group_name
4
+ attr_reader :application_run_group_limit, :priority, :enqueue_backlogs
5
+ attr_reader :application, :application_schedule
6
+
7
+ def initialize(command,
8
+ application_type = ::Naf::ApplicationType.rails,
9
+ application_run_group_restriction = ::Naf::ApplicationRunGroupRestriction.limited_per_all_machines,
10
+ application_run_group_name = :command,
11
+ application_run_group_limit = 1,
12
+ priority = 0,
13
+ affinities = [],
14
+ prerequisites = [],
15
+ enqueue_backlogs = false,
16
+ application = nil,
17
+ application_schedule = nil)
18
+ @command = command
19
+ @application_type = application_type
20
+ @application_run_group_restriction = application_run_group_restriction
21
+ @application_run_group_name = (application_run_group_name == :command ? command : application_run_group_name)
22
+ @application_run_group_limit = application_run_group_limit
23
+ @priority = priority
24
+ @affinities = if affinities.nil?
25
+ []
26
+ elsif affinities.is_a? Array
27
+ affinities
28
+ else
29
+ [affinities]
30
+ end
31
+ @prerequisites = prerequisites
32
+ @enqueue_backlogs = enqueue_backlogs
33
+ @application = application
34
+ @application_schedule = application_schedule
35
+ end
36
+
37
+ def historical_job_parameters
38
+ {
39
+ command: command,
40
+ application_type_id: application_type.id,
41
+ application_run_group_restriction_id: application_run_group_restriction.id,
42
+ application_run_group_name: application_run_group_name,
43
+ application_run_group_limit: application_run_group_limit,
44
+ priority: priority,
45
+ application_id: application.try(:id)
46
+ }
47
+ end
48
+
49
+ def historical_job_affinity_tab_parameters
50
+ @affinities.map do |affinity|
51
+ if affinity.is_a? Symbol
52
+ # short_name of affinity
53
+ affinity_object = {
54
+ :affinity_id => ::Naf::Affinity.find_by_affinity_short_name(affinity).try(:id)
55
+ }
56
+ raise "no affinity provided" if affinity_object[:affinity_id].nil?
57
+ affinity_object
58
+ elsif affinity.is_a? ::Naf::Affinity
59
+ {
60
+ :affinity_id => affinity.id
61
+ }
62
+ elsif affinity.is_a? ::Naf::Machine
63
+ # affinity_for machine
64
+ {
65
+ :affinity_id => affinity.affinity.id
66
+ }
67
+ elsif affinity.is_a? ::Naf::ApplicationScheduleAffinityTab
68
+ # affinity_for application_schedule_affinity_tab
69
+ elsif affinity.is_a? Hash
70
+ # should have key: :affinity_id or :affinity_short_name or :affinity_name
71
+ # may have key: :affinity_parameter
72
+ affinity_object = {
73
+ }
74
+ if affinity.has_key?(:affinity_id)
75
+ affinity_object[:affinity_id] = affinity[:affinity_id]
76
+ elsif affinity.has_key?(:affinity_name)
77
+ affinity_object[:affinity_id] = ::Naf::Affinity.find_by_affinity_name(affinity[:affinity_name]).try(:id)
78
+ elsif affinity.has_key?(:affinity_short_name)
79
+ affinity_object[:affinity_id] = ::Naf::Affinity.find_by_affinity_short_name(affinity[:affinity_short_name]).try(:id)
80
+ end
81
+ raise "no affinity provided" if affinity_object[:affinity_id].nil?
82
+ affinity_object[:affinity_parameter] = affinity[:affinity_parameter] if affinity.has_key?(:affinity_parameter)
83
+ affinity_object
84
+ else
85
+ raise "unknown affinity kind: #{affinity.inspect}"
86
+ end
87
+ end
88
+ end
89
+
90
+ def historical_job_prerequisite_historical_jobs
91
+ # the idea here is that if it is a historical job its prerequisites have
92
+ # already been checked, we only need to check if the prerequisites are NOT
93
+ # the current job we are inserting (which can't happen in the current code path)
94
+ @prerequisites.each do |prerequisite|
95
+ raise "found a non Naf::HistoricalJob in prerequisites: #{prerequisite.inspect}" unless prerequisite.is_a? ::Naf::HistoricalJob
96
+ end
97
+ return @prerequisites
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,48 @@
1
+ module Logical
2
+ module Naf
3
+ class CreateInfrastructure
4
+ include ::Af::Application::SafeProxy
5
+
6
+ def initialize(model_names)
7
+ @model_names = model_names
8
+ end
9
+
10
+ def logger
11
+ return af_logger(self.class.name)
12
+ end
13
+
14
+ def work
15
+ first_model = nil
16
+ begin
17
+ @model_names.each do |target_model_name|
18
+ logger.info "target model: #{target_model_name}"
19
+ target_model = target_model_name.constantize rescue nil
20
+ if target_model.nil?
21
+ logger.error "couldn't find target_model #{target_model_name}"
22
+ else
23
+ unless first_model
24
+ target_model.connection.begin_db_transaction
25
+ first_model = target_model
26
+ end
27
+ begin
28
+ logger.info "#{target_model_name}: creating infrastructure"
29
+ target_model.create_infrastructure
30
+ logger.info "#{target_model_name}: creating new partitions"
31
+ target_model.create_new_partitions
32
+ logger.info "#{target_model_name}: done"
33
+ rescue StandardError => e
34
+ logger.error "couldn't create infrastructure for: #{target_model_name}, #{e.message}"
35
+ logger.error e.backtrace.join("\n")
36
+ end
37
+ end
38
+ end
39
+ ensure
40
+ if first_model
41
+ first_model.connection.commit_db_transaction
42
+ end
43
+ end
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,357 @@
1
+ # A wrapper around Naf::HistoricalJob used for rendering in views
2
+
3
+ module Logical
4
+ module Naf
5
+ class Job
6
+ include ActionView::Helpers::DateHelper
7
+ include ActionView::Helpers::TextHelper
8
+
9
+ COLUMNS = [:id,
10
+ :server,
11
+ :pid,
12
+ :queued_time,
13
+ :title,
14
+ :started_at,
15
+ :finished_at,
16
+ :run_time,
17
+ :affinities,
18
+ :tags,
19
+ :status]
20
+
21
+ ATTRIBUTES = [:title,
22
+ :id,
23
+ :status,
24
+ :server,
25
+ :pid,
26
+ :queued_time,
27
+ :command,
28
+ :started_at,
29
+ :finished_at,
30
+ :run_time,
31
+ :exit_status,
32
+ :script_type_name,
33
+ :log_level,
34
+ :request_to_terminate,
35
+ :machine_started_on_server_address,
36
+ :machine_started_on_server_name,
37
+ :application_run_group_name,
38
+ :application_run_group_limit,
39
+ :application_run_group_restriction_name]
40
+
41
+ FILTER_FIELDS = [:application_type_id,
42
+ :application_run_group_restriction_id,
43
+ :priority,
44
+ :failed_to_start,
45
+ :pid,
46
+ :exit_status,
47
+ :request_to_terminate,
48
+ :started_on_machine_id]
49
+
50
+ SEARCH_FIELDS = [:command, :application_run_group_name]
51
+
52
+ # Mapping of datatable column positions and job attributes
53
+ ORDER = { '0' => "id",
54
+ '2' => "pid",
55
+ '3' => "created_at",
56
+ '5' => "started_at",
57
+ '6' => "finished_at",
58
+ '10' => "status" }
59
+
60
+ def initialize(naf_job)
61
+ @job = naf_job
62
+ end
63
+
64
+ def method_missing(method_name, *arguments, &block)
65
+ if @job.respond_to?(method_name)
66
+ @job.send(method_name, *arguments, &block)
67
+ else
68
+ super
69
+ end
70
+ end
71
+
72
+ def status
73
+ if @job.request_to_terminate && @job.finished_at.nil?
74
+ "Terminating"
75
+ elsif @job.request_to_terminate && @job.finished_at.present?
76
+ "Terminated"
77
+ elsif @job.started_at and (not @job.finished_at)
78
+ "Running"
79
+ elsif (not @job.started_at) and (not @job.finished_at) and @job.failed_to_start
80
+ "Failed to Start"
81
+ elsif @job.exit_status and @job.exit_status > 0
82
+ "Error #{@job.exit_status}"
83
+ elsif @job.started_at and @job.finished_at
84
+ "Finished"
85
+ elsif @job.termination_signal
86
+ "Signaled #{@job.termination_signal}"
87
+ elsif @job.prerequisites.select { |pre| pre.started_at.nil? }.size > 0
88
+ "Waiting"
89
+ else
90
+ "Queued"
91
+ end
92
+ end
93
+
94
+ def title
95
+ if application
96
+ application.title
97
+ else
98
+ command
99
+ end
100
+ end
101
+
102
+ def application_run_group_name
103
+ if @job.application_run_group_name.blank?
104
+ "not set"
105
+ elsif @job.application_run_group_name == @job.command
106
+ "command"
107
+ else
108
+ @job.application_run_group_name
109
+ end
110
+ end
111
+
112
+ def server
113
+ if started_on_machine
114
+ name = started_on_machine.short_name_if_it_exist
115
+ if name.blank?
116
+ started_on_machine.server_address
117
+ else
118
+ name
119
+ end
120
+ end
121
+ end
122
+
123
+ # Given search, a hash of the search query for jobs on the queue,
124
+ # build up and return the ActiveRecord scope
125
+ #
126
+ # We eventually build up these results over created_at/1.week partitions.
127
+ def self.search(search)
128
+ if search[:order] == "status"
129
+ conditions = ""
130
+ values = {}
131
+ values[:limit] = search[:limit].to_i
132
+ values[:offset]= search[:offset].to_i*search[:limit].to_i
133
+ FILTER_FIELDS.each do |field|
134
+ if search[field].present?
135
+ conditions << " AND "
136
+ case field
137
+ when :failed_to_start, :request_to_terminate
138
+ values[field.to_sym] = search[field]
139
+ conditions << "#{field} = :#{field}"
140
+ else
141
+ values[field.to_sym] = search[field].to_i
142
+ conditions << "#{field} = :#{field}"
143
+ end
144
+ end
145
+ end
146
+ SEARCH_FIELDS.each do |field|
147
+ if search[field].present?
148
+ conditions << " AND "
149
+ conditions << "lower(#{field}) ~ :#{field}"
150
+ values[field.to_sym] = search[field].downcase
151
+ end
152
+ end
153
+
154
+ status = search[:status].blank? ? :all : search[:status]
155
+ sql =
156
+ case status.to_sym
157
+ when :queued
158
+ JobStatuses::Running.all(:queued, conditions) + "union all\n" +
159
+ JobStatuses::Queued.all(conditions) + "union all\n" +
160
+ JobStatuses::Waiting.all(conditions) + "union all\n" +
161
+ JobStatuses::FinishedLessMinute.all(conditions) + "union all\n" +
162
+ JobStatuses::Terminated.all(conditions)
163
+ when :running
164
+ JobStatuses::Running.all(conditions) + "union all\n" +
165
+ JobStatuses::FinishedLessMinute.all(conditions) + "union all\n" +
166
+ JobStatuses::Terminated.all(conditions)
167
+ when :waiting
168
+ JobStatuses::Waiting.all(conditions)
169
+ when :finished
170
+ JobStatuses::Finished.all(conditions)
171
+ when :errored
172
+ JobStatuses::Errored.all(conditions)
173
+ else
174
+ JobStatuses::Running.all(:queued, conditions) + "union all\n" +
175
+ JobStatuses::Queued.all(conditions) + "union all\n" +
176
+ JobStatuses::Waiting.all(conditions) + "union all\n" +
177
+ JobStatuses::Finished.all(conditions) + "union all\n" +
178
+ JobStatuses::Terminated.all(conditions)
179
+ end
180
+ sql << "LIMIT :limit OFFSET :offset"
181
+ jobs = ::Naf::HistoricalJob.find_by_sql([sql, values])
182
+
183
+ jobs.map{ |physical_job| new(physical_job) }
184
+ else
185
+ job_scope = self.get_job_scope(search)
186
+ order, direction = search[:order], search[:direction]
187
+ job_scope = job_scope.order("#{order} #{direction}").limit(search[:limit]).offset(search[:offset].to_i*search[:limit].to_i)
188
+
189
+ if search[:status] == 'waiting'
190
+ job_scope = job_scope.select{|job| job.prerequisites.select{ |pre| pre.started_at.nil? }.size > 0 }
191
+ end
192
+
193
+ job_scope.map{|physical_job| new(physical_job) }
194
+ end
195
+ end
196
+
197
+ def self.total_display_records(search)
198
+ job_scope = self.get_job_scope(search)
199
+
200
+ if search[:status] == 'waiting'
201
+ job_scope = job_scope.select{ |job| job.prerequisites.select{ |pre| pre.started_at.nil? }.size > 0 }
202
+ end
203
+
204
+ job_scope.count
205
+ end
206
+
207
+ def self.get_job_scope(search)
208
+ status = search[:status].blank? ? :all : search[:status]
209
+ case status.to_sym
210
+ when :queued
211
+ job_scope = ::Naf::HistoricalJob.queued_status
212
+ when :running
213
+ job_scope = ::Naf::HistoricalJob.running_status
214
+ when :waiting
215
+ job_scope = ::Naf::HistoricalJob.queued_with_waiting
216
+ when :finished
217
+ job_scope = ::Naf::HistoricalJob.finished
218
+ when :errored
219
+ job_scope = ::Naf::HistoricalJob.errored
220
+ else
221
+ job_scope = ::Naf::HistoricalJob.scoped
222
+ end
223
+
224
+ FILTER_FIELDS.each do |field|
225
+ job_scope = job_scope.where(field => search[field]) if search[field].present?
226
+ end
227
+ SEARCH_FIELDS.each do |field|
228
+ job_scope = job_scope.where(["lower(#{field}) ~ ?", search[field].downcase]) if search[field].present?
229
+ end
230
+
231
+ job_scope
232
+ end
233
+
234
+ def self.find(id)
235
+ physical_job = ::Naf::HistoricalJob.find(id)
236
+ physical_job ? new(physical_job) : nil
237
+ end
238
+
239
+ def application_url
240
+ if application = @job.application
241
+ return Rails.application.routes.url_helpers.application_path(application)
242
+ else
243
+ return nil
244
+ end
245
+ end
246
+
247
+ def to_detailed_hash
248
+ Hash[ ATTRIBUTES.map{ |m|
249
+ case m
250
+ when :started_at, :finished_at
251
+ if value = @job.send(m)
252
+ [m, value.localtime.strftime("%Y-%m-%d %r")]
253
+ else
254
+ [m, '']
255
+ end
256
+ else
257
+ [m, send(m)]
258
+ end
259
+ }]
260
+ end
261
+
262
+ # Format the hash of a job record nicely for the table
263
+ def to_hash
264
+ Hash[ COLUMNS.map{ |m| [m, send(m)] } ]
265
+ end
266
+
267
+ def started_at
268
+ if @job.started_at.present?
269
+ value = Time.zone.now - @job.started_at
270
+ if value < 60
271
+ "#{value.to_i} seconds ago, #{@job.started_at.localtime.strftime("%Y-%m-%d %r")}"
272
+ elsif value < 172_800
273
+ time_difference(value)
274
+ elsif value >= 172_800
275
+ "#{time_ago_in_words(@job.started_at, true)} ago, #{@job.started_at.localtime.strftime("%Y-%m-%d %r")}"
276
+ else
277
+ ""
278
+ end
279
+ else
280
+ ""
281
+ end
282
+ end
283
+
284
+ def time_difference(value, time_format_on=true)
285
+ seconds = value % 60
286
+ value = (value - seconds) / 60
287
+ minutes = value % 60
288
+ value = (value - minutes) / 60
289
+ hours = value % 24
290
+ value = (value - hours) / 24
291
+ days = value % 7
292
+ more_hours = hours + days * 24 if days > 0
293
+
294
+ if time_format_on
295
+ "-#{hours.to_i}h#{minutes.to_i}m, #{@job.started_at.localtime.strftime("%Y-%m-%d %r")}"
296
+ else
297
+ if days < 2
298
+ "-#{more_hours.to_i}h#{minutes.to_i}m#{seconds.to_i}s"
299
+ else
300
+ "-#{days.to_i}d#{hours.to_i}h#{minutes.to_i}m#{seconds.to_i}s"
301
+ end
302
+ end
303
+ end
304
+
305
+ def has_started?
306
+ @job.started_at.present?
307
+ end
308
+
309
+ def queued_time
310
+ created_at.localtime.strftime("%Y-%m-%d %r")
311
+ end
312
+
313
+ def run_time
314
+ if @job.started_at.present?
315
+ if @job.finished_at.present?
316
+ time_difference(@job.finished_at - @job.started_at, false)[1..-1]
317
+ else
318
+ time_difference(Time.zone.now - @job.started_at, false)[1..-1]
319
+ end
320
+ else
321
+ ""
322
+ end
323
+ end
324
+
325
+ def finished_at
326
+ if value = @job.finished_at
327
+ "#{time_ago_in_words(value, true)} ago, #{value.localtime.strftime("%Y-%m-%d %r")}"
328
+ else
329
+ ""
330
+ end
331
+ end
332
+
333
+ def affinities
334
+ @job.job_affinities.map do |job_affinity|
335
+ if job_affinity.present?
336
+ if job_affinity.affinity_short_name.present?
337
+ job_affinity.affinity_short_name
338
+ else
339
+ job_affinity.affinity_classification_name + '_' + job_affinity.affinity_name
340
+ end
341
+ end
342
+ end.join(", \n")
343
+ end
344
+
345
+ def tags
346
+ if @job.tags.present?
347
+ # Only show custom visible tags
348
+ job_tags = @job.tags.gsub(/[{}]/,'').split(',')
349
+ (job_tags.select { |elem| !['$', '_'].include?elem[0] }).join(', ')
350
+ else
351
+ nil
352
+ end
353
+ end
354
+
355
+ end
356
+ end
357
+ end