kuroko2 0.2.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 (338) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +15 -0
  4. data/Rakefile +26 -0
  5. data/app/assets/images/kuroko2/avatar.png +0 -0
  6. data/app/assets/images/kuroko2/kuroko-logo-horizontal.png +0 -0
  7. data/app/assets/javascripts/kuroko2/application.js +28 -0
  8. data/app/assets/javascripts/kuroko2/bootstrap.js +2363 -0
  9. data/app/assets/javascripts/kuroko2/definition_linker.js +20 -0
  10. data/app/assets/javascripts/kuroko2/instance_linker.js +10 -0
  11. data/app/assets/javascripts/kuroko2/job_definition_stats.js +67 -0
  12. data/app/assets/javascripts/kuroko2/job_definitions.js +79 -0
  13. data/app/assets/javascripts/kuroko2/job_instances.js +88 -0
  14. data/app/assets/javascripts/kuroko2/job_timelines.js.coffee +24 -0
  15. data/app/assets/javascripts/kuroko2/narrow_job_definitions.js +30 -0
  16. data/app/assets/stylesheets/kuroko2/admin-lte.css +3402 -0
  17. data/app/assets/stylesheets/kuroko2/application.scss +86 -0
  18. data/app/assets/stylesheets/kuroko2/bootstrap.css +6799 -0
  19. data/app/assets/stylesheets/kuroko2/fonts.scss +1 -0
  20. data/app/assets/stylesheets/kuroko2/job_definitions.scss +19 -0
  21. data/app/assets/stylesheets/kuroko2/users.scss +7 -0
  22. data/app/controllers/kuroko2/api/application_controller.rb +49 -0
  23. data/app/controllers/kuroko2/api/job_instances_controller.rb +46 -0
  24. data/app/controllers/kuroko2/api/stats_controller.rb +28 -0
  25. data/app/controllers/kuroko2/application_controller.rb +43 -0
  26. data/app/controllers/kuroko2/dashboard_controller.rb +27 -0
  27. data/app/controllers/kuroko2/execution_logs_controller.rb +19 -0
  28. data/app/controllers/kuroko2/executions_controller.rb +28 -0
  29. data/app/controllers/kuroko2/job_definition_stats_controller.rb +54 -0
  30. data/app/controllers/kuroko2/job_definitions_controller.rb +100 -0
  31. data/app/controllers/kuroko2/job_instances_controller.rb +87 -0
  32. data/app/controllers/kuroko2/job_schedules_controller.rb +39 -0
  33. data/app/controllers/kuroko2/job_suspend_schedules_controller.rb +38 -0
  34. data/app/controllers/kuroko2/job_timelines_controller.rb +56 -0
  35. data/app/controllers/kuroko2/logs_controller.rb +15 -0
  36. data/app/controllers/kuroko2/sessions_controller.rb +32 -0
  37. data/app/controllers/kuroko2/stars_controller.rb +30 -0
  38. data/app/controllers/kuroko2/tokens_controller.rb +47 -0
  39. data/app/controllers/kuroko2/users_controller.rb +62 -0
  40. data/app/controllers/kuroko2/workers_controller.rb +5 -0
  41. data/app/errors/http/bad_request.rb +4 -0
  42. data/app/errors/http/forbidden.rb +4 -0
  43. data/app/errors/http/unauthorized.rb +4 -0
  44. data/app/helpers/kuroko2/application_helper.rb +8 -0
  45. data/app/helpers/kuroko2/dashboard_helper.rb +4 -0
  46. data/app/helpers/kuroko2/executions_helper.rb +4 -0
  47. data/app/helpers/kuroko2/job_definitions_helper.rb +38 -0
  48. data/app/helpers/kuroko2/job_instances_helper.rb +71 -0
  49. data/app/helpers/kuroko2/job_schedules_helper.rb +4 -0
  50. data/app/helpers/kuroko2/logs_helper.rb +4 -0
  51. data/app/helpers/kuroko2/sessions_helper.rb +4 -0
  52. data/app/helpers/kuroko2/stars_helper.rb +4 -0
  53. data/app/helpers/kuroko2/tokens_helper.rb +4 -0
  54. data/app/helpers/kuroko2/users_helper.rb +4 -0
  55. data/app/helpers/kuroko2/workers_helper.rb +4 -0
  56. data/app/jobs/kuroko2/application_job.rb +4 -0
  57. data/app/mailers/kuroko2/application_mailer.rb +6 -0
  58. data/app/mailers/kuroko2/notifications.rb +63 -0
  59. data/app/models/concerns/kuroko2/table_name_customizable.rb +16 -0
  60. data/app/models/kuroko2/admin_assignment.rb +6 -0
  61. data/app/models/kuroko2/api/application_resource.rb +10 -0
  62. data/app/models/kuroko2/api/job_instance_resource.rb +7 -0
  63. data/app/models/kuroko2/application_record.rb +5 -0
  64. data/app/models/kuroko2/execution.rb +55 -0
  65. data/app/models/kuroko2/job_definition.rb +147 -0
  66. data/app/models/kuroko2/job_definition_tag.rb +6 -0
  67. data/app/models/kuroko2/job_instance.rb +118 -0
  68. data/app/models/kuroko2/job_schedule.rb +93 -0
  69. data/app/models/kuroko2/job_suspend_schedule.rb +35 -0
  70. data/app/models/kuroko2/log.rb +3 -0
  71. data/app/models/kuroko2/memory_consumption_log.rb +49 -0
  72. data/app/models/kuroko2/memory_expectancy.rb +21 -0
  73. data/app/models/kuroko2/process_signal.rb +14 -0
  74. data/app/models/kuroko2/star.rb +6 -0
  75. data/app/models/kuroko2/tag.rb +8 -0
  76. data/app/models/kuroko2/tick.rb +12 -0
  77. data/app/models/kuroko2/token.rb +101 -0
  78. data/app/models/kuroko2/user.rb +48 -0
  79. data/app/models/kuroko2/worker.rb +12 -0
  80. data/app/views/kaminari/history/_paginator.html.slim +15 -0
  81. data/app/views/kaminari/list/_paginator.html.slim +17 -0
  82. data/app/views/kuroko2/dashboard/_taglist.html.slim +13 -0
  83. data/app/views/kuroko2/dashboard/index.html.slim +49 -0
  84. data/app/views/kuroko2/execution_logs/index.json.jbuilder +16 -0
  85. data/app/views/kuroko2/executions/index.html.slim +35 -0
  86. data/app/views/kuroko2/job_definition_stats/execution_time.json.jbuilder +13 -0
  87. data/app/views/kuroko2/job_definition_stats/index.html.slim +48 -0
  88. data/app/views/kuroko2/job_definition_stats/memory.json.jbuilder +10 -0
  89. data/app/views/kuroko2/job_definitions/_alert.html.slim +7 -0
  90. data/app/views/kuroko2/job_definitions/_form.html.slim +93 -0
  91. data/app/views/kuroko2/job_definitions/_list.html.slim +26 -0
  92. data/app/views/kuroko2/job_definitions/_search_results.html.slim +51 -0
  93. data/app/views/kuroko2/job_definitions/_taglist.html.slim +13 -0
  94. data/app/views/kuroko2/job_definitions/edit.html.slim +15 -0
  95. data/app/views/kuroko2/job_definitions/index.html.slim +11 -0
  96. data/app/views/kuroko2/job_definitions/new.html.slim +12 -0
  97. data/app/views/kuroko2/job_definitions/show.html.slim +90 -0
  98. data/app/views/kuroko2/job_instances/_instance.html.slim +42 -0
  99. data/app/views/kuroko2/job_instances/index.html.slim +58 -0
  100. data/app/views/kuroko2/job_instances/show.html.slim +19 -0
  101. data/app/views/kuroko2/job_instances/working.html.slim +37 -0
  102. data/app/views/kuroko2/job_schedules/index.html.slim +32 -0
  103. data/app/views/kuroko2/job_suspend_schedules/index.html.slim +27 -0
  104. data/app/views/kuroko2/job_timelines/dataset.json.jbuilder +11 -0
  105. data/app/views/kuroko2/job_timelines/index.html.slim +31 -0
  106. data/app/views/kuroko2/kaminari/history/_paginator.html.slim +15 -0
  107. data/app/views/kuroko2/kaminari/list/_paginator.html.slim +17 -0
  108. data/app/views/kuroko2/layouts/application.html.slim +68 -0
  109. data/app/views/kuroko2/logs/index.html.slim +33 -0
  110. data/app/views/kuroko2/notifications/executor_not_assigned.text.erb +22 -0
  111. data/app/views/kuroko2/notifications/job_failure.html.slim +21 -0
  112. data/app/views/kuroko2/notifications/job_failure.text.erb +18 -0
  113. data/app/views/kuroko2/notifications/notify_long_elapsed_time.text.erb +9 -0
  114. data/app/views/kuroko2/notifications/process_absence.text.erb +22 -0
  115. data/app/views/kuroko2/notifications/remind_failure.html.slim +21 -0
  116. data/app/views/kuroko2/notifications/remind_failure.text.erb +10 -0
  117. data/app/views/kuroko2/sessions/new.html.slim +20 -0
  118. data/app/views/kuroko2/tokens/index.html.slim +42 -0
  119. data/app/views/kuroko2/users/index.html.slim +55 -0
  120. data/app/views/kuroko2/users/show.html.slim +76 -0
  121. data/app/views/kuroko2/workers/index.html.slim +40 -0
  122. data/app/views/layouts/kuroko2/application.html.slim +72 -0
  123. data/app/views/layouts/mailer.html.erb +13 -0
  124. data/app/views/layouts/mailer.text.erb +1 -0
  125. data/bin/cleanup_old_instances.rb +9 -0
  126. data/bin/remind_failure.rb +5 -0
  127. data/config/initializers/000_kuroko2.rb +16 -0
  128. data/config/initializers/assets.rb +9 -0
  129. data/config/initializers/garage.rb +2 -0
  130. data/config/initializers/kaminari_config.rb +3 -0
  131. data/config/initializers/omniauth.rb +5 -0
  132. data/config/locales/en.yml +28 -0
  133. data/config/routes.rb +54 -0
  134. data/db/migrate/001_create_job_definitions.rb +22 -0
  135. data/db/migrate/002_create_job_instances.rb +17 -0
  136. data/db/migrate/003_create_job_schedules.rb +14 -0
  137. data/db/migrate/004_create_ticks.rb +7 -0
  138. data/db/migrate/005_create_logs.rb +13 -0
  139. data/db/migrate/006_create_tokens.rb +21 -0
  140. data/db/migrate/007_create_executions.rb +26 -0
  141. data/db/migrate/008_create_process_signals.rb +15 -0
  142. data/db/migrate/009_create_users.rb +20 -0
  143. data/db/migrate/010_create_admin_assignments.rb +12 -0
  144. data/db/migrate/011_create_stars.rb +12 -0
  145. data/db/migrate/012_create_workers.rb +15 -0
  146. data/db/migrate/018_create_job_definition_tags.rb +13 -0
  147. data/db/migrate/019_create_tags.rb +11 -0
  148. data/db/migrate/021_create_memory_expectancies.rb +17 -0
  149. data/db/migrate/025_create_job_suspend_schedules.rb +12 -0
  150. data/lib/kuroko2/command/executor.rb +62 -0
  151. data/lib/kuroko2/command/kill.rb +24 -0
  152. data/lib/kuroko2/command/monitor.rb +109 -0
  153. data/lib/kuroko2/command/shell.rb +163 -0
  154. data/lib/kuroko2/configuration.rb +19 -0
  155. data/lib/kuroko2/engine.rb +59 -0
  156. data/lib/kuroko2/execution_logger/cloud_watch_logs.rb +92 -0
  157. data/lib/kuroko2/execution_logger/void.rb +13 -0
  158. data/lib/kuroko2/execution_logger.rb +20 -0
  159. data/lib/kuroko2/memory_sampler.rb +50 -0
  160. data/lib/kuroko2/return_to_validator.rb +14 -0
  161. data/lib/kuroko2/servers/base.rb +30 -0
  162. data/lib/kuroko2/servers/command_executor.rb +27 -0
  163. data/lib/kuroko2/servers/job_scheduler.rb +25 -0
  164. data/lib/kuroko2/servers/workflow_processor.rb +25 -0
  165. data/lib/kuroko2/util/logger.rb +19 -0
  166. data/lib/kuroko2/util/rails_logger_formatter.rb +9 -0
  167. data/lib/kuroko2/version.rb +3 -0
  168. data/lib/kuroko2/workflow/assertion_error.rb +6 -0
  169. data/lib/kuroko2/workflow/engine.rb +141 -0
  170. data/lib/kuroko2/workflow/engine_error.rb +6 -0
  171. data/lib/kuroko2/workflow/node.rb +124 -0
  172. data/lib/kuroko2/workflow/notifier/concerns/chat_message_builder.rb +39 -0
  173. data/lib/kuroko2/workflow/notifier/hipchat.rb +88 -0
  174. data/lib/kuroko2/workflow/notifier/mail.rb +44 -0
  175. data/lib/kuroko2/workflow/notifier/slack.rb +121 -0
  176. data/lib/kuroko2/workflow/notifier.rb +31 -0
  177. data/lib/kuroko2/workflow/processor.rb +40 -0
  178. data/lib/kuroko2/workflow/scheduler.rb +42 -0
  179. data/lib/kuroko2/workflow/script_parser.rb +66 -0
  180. data/lib/kuroko2/workflow/shell_scanner.rb +34 -0
  181. data/lib/kuroko2/workflow/syntax_error.rb +6 -0
  182. data/lib/kuroko2/workflow/task/auto_skip_error.rb +20 -0
  183. data/lib/kuroko2/workflow/task/base.rb +32 -0
  184. data/lib/kuroko2/workflow/task/env.rb +45 -0
  185. data/lib/kuroko2/workflow/task/execute.rb +128 -0
  186. data/lib/kuroko2/workflow/task/expected_time.rb +9 -0
  187. data/lib/kuroko2/workflow/task/fork.rb +45 -0
  188. data/lib/kuroko2/workflow/task/kuroko_runner.rb +24 -0
  189. data/lib/kuroko2/workflow/task/noop.rb +13 -0
  190. data/lib/kuroko2/workflow/task/queue.rb +27 -0
  191. data/lib/kuroko2/workflow/task/rails_env.rb +24 -0
  192. data/lib/kuroko2/workflow/task/sequence.rb +13 -0
  193. data/lib/kuroko2/workflow/task/sleep.rb +29 -0
  194. data/lib/kuroko2/workflow/task/sub_process.rb +53 -0
  195. data/lib/kuroko2/workflow/task/time_base.rb +44 -0
  196. data/lib/kuroko2/workflow/task/timeout.rb +9 -0
  197. data/lib/kuroko2/workflow/task/wait.rb +143 -0
  198. data/lib/kuroko2.rb +26 -0
  199. data/lib/tasks/kuroko2_tasks.rake +4 -0
  200. data/spec/command/kill_spec.rb +20 -0
  201. data/spec/command/monitor_spec.rb +68 -0
  202. data/spec/command/shell_spec.rb +87 -0
  203. data/spec/controllers/dashboard_controller_spec.rb +5 -0
  204. data/spec/controllers/executions_controller_spec.rb +23 -0
  205. data/spec/controllers/job_definition_stats_controller_spec.rb +95 -0
  206. data/spec/controllers/job_definitions_controller_spec.rb +89 -0
  207. data/spec/controllers/job_instances_controller_spec.rb +62 -0
  208. data/spec/controllers/job_schedules_controller_spec.rb +39 -0
  209. data/spec/controllers/job_suspend_schedules_controller_spec.rb +39 -0
  210. data/spec/controllers/job_timelines_controller_spec.rb +114 -0
  211. data/spec/controllers/logs_controller_spec.rb +5 -0
  212. data/spec/controllers/sessions_controller_spec.rb +58 -0
  213. data/spec/controllers/stars_controller_spec.rb +28 -0
  214. data/spec/controllers/tokens_controller_spec.rb +5 -0
  215. data/spec/controllers/users_controller_spec.rb +51 -0
  216. data/spec/controllers/workers_controller_spec.rb +5 -0
  217. data/spec/dummy/Rakefile +6 -0
  218. data/spec/dummy/app/assets/config/manifest.js +5 -0
  219. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  220. data/spec/dummy/app/assets/javascripts/cable.js +13 -0
  221. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  222. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  223. data/spec/dummy/app/channels/application_cable/connection.rb +4 -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/jobs/application_job.rb +2 -0
  227. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  228. data/spec/dummy/app/models/application_record.rb +3 -0
  229. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  230. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  231. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  232. data/spec/dummy/bin/bundle +3 -0
  233. data/spec/dummy/bin/rails +4 -0
  234. data/spec/dummy/bin/rake +4 -0
  235. data/spec/dummy/bin/setup +34 -0
  236. data/spec/dummy/bin/update +29 -0
  237. data/spec/dummy/config/application.rb +25 -0
  238. data/spec/dummy/config/boot.rb +3 -0
  239. data/spec/dummy/config/cable.yml +9 -0
  240. data/spec/dummy/config/database.yml +29 -0
  241. data/spec/dummy/config/environment.rb +5 -0
  242. data/spec/dummy/config/environments/development.rb +54 -0
  243. data/spec/dummy/config/environments/production.rb +86 -0
  244. data/spec/dummy/config/environments/test.rb +42 -0
  245. data/spec/dummy/config/initializers/application_controller_renderer.rb +6 -0
  246. data/spec/dummy/config/initializers/assets.rb +11 -0
  247. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  248. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  249. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  250. data/spec/dummy/config/initializers/inflections.rb +16 -0
  251. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  252. data/spec/dummy/config/initializers/new_framework_defaults.rb +23 -0
  253. data/spec/dummy/config/initializers/session_store.rb +3 -0
  254. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  255. data/spec/dummy/config/kuroko2.yml +35 -0
  256. data/spec/dummy/config/locales/en.yml +23 -0
  257. data/spec/dummy/config/puma.rb +47 -0
  258. data/spec/dummy/config/routes.rb +3 -0
  259. data/spec/dummy/config/secrets.yml +22 -0
  260. data/spec/dummy/config/spring.rb +6 -0
  261. data/spec/dummy/config.ru +5 -0
  262. data/spec/dummy/db/schema.rb +217 -0
  263. data/spec/dummy/lib/dummy_extention.rb +14 -0
  264. data/spec/dummy/lib/kuroko2/workflow/task/custom_task1.rb +13 -0
  265. data/spec/dummy/public/404.html +67 -0
  266. data/spec/dummy/public/422.html +67 -0
  267. data/spec/dummy/public/500.html +66 -0
  268. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  269. data/spec/dummy/public/apple-touch-icon.png +0 -0
  270. data/spec/dummy/public/favicon.ico +0 -0
  271. data/spec/execution_logger/cloud_watch_logs_spec.rb +95 -0
  272. data/spec/factories/execution_factory.rb +13 -0
  273. data/spec/factories/job_definition_factory.rb +21 -0
  274. data/spec/factories/job_instance_factory.rb +4 -0
  275. data/spec/factories/job_schedule_factory.rb +10 -0
  276. data/spec/factories/job_suspend_schedule_factory.rb +8 -0
  277. data/spec/factories/memory_expectancy_factory.rb +5 -0
  278. data/spec/factories/process_signal_factory.rb +4 -0
  279. data/spec/factories/star_factory.rb +4 -0
  280. data/spec/factories/tick_factory.rb +4 -0
  281. data/spec/factories/token_factory.rb +10 -0
  282. data/spec/factories/user_factory.rb +11 -0
  283. data/spec/factories/worker_factory.rb +8 -0
  284. data/spec/features/dashborad_spec.rb +82 -0
  285. data/spec/features/job_definition_spec.rb +74 -0
  286. data/spec/features/job_instance_spec.rb +94 -0
  287. data/spec/features/sign_in_and_out_spec.rb +17 -0
  288. data/spec/features/users_spec.rb +90 -0
  289. data/spec/features/workers_spec.rb +44 -0
  290. data/spec/helpers/executions_helper_spec.rb +4 -0
  291. data/spec/helpers/job_definition_helper_spec.rb +42 -0
  292. data/spec/helpers/job_schedules_helper_spec.rb +4 -0
  293. data/spec/helpers/logs_helper_spec.rb +4 -0
  294. data/spec/helpers/tokens_helper_spec.rb +4 -0
  295. data/spec/helpers/users_helper_spec.rb +4 -0
  296. data/spec/helpers/workers_helper_spec.rb +4 -0
  297. data/spec/mailers/notifications_spec.rb +54 -0
  298. data/spec/memory_sampler_spec.rb +11 -0
  299. data/spec/models/admin_assignment_spec.rb +4 -0
  300. data/spec/models/execution_spec.rb +26 -0
  301. data/spec/models/job_definition_spec.rb +163 -0
  302. data/spec/models/job_instance_spec.rb +115 -0
  303. data/spec/models/job_schedule_spec.rb +121 -0
  304. data/spec/models/job_suspend_schedule_spec.rb +32 -0
  305. data/spec/models/memory_consumption_log_spec.rb +50 -0
  306. data/spec/models/memory_expectancy_spec.rb +26 -0
  307. data/spec/models/star_spec.rb +4 -0
  308. data/spec/models/tick_spec.rb +23 -0
  309. data/spec/models/token_spec.rb +54 -0
  310. data/spec/models/user_spec.rb +17 -0
  311. data/spec/models/worker_spec.rb +5 -0
  312. data/spec/rails_helper.rb +81 -0
  313. data/spec/requests/api/job_instances_spec.rb +96 -0
  314. data/spec/requests/api/stats_spec.rb +45 -0
  315. data/spec/return_to_validator_spec.rb +28 -0
  316. data/spec/settings_spec.rb +10 -0
  317. data/spec/spec_helper.rb +49 -0
  318. data/spec/support/feature_sign_in_helper.rb +31 -0
  319. data/spec/support/sign_in_helper.rb +5 -0
  320. data/spec/support/wait_for_ajax.rb +11 -0
  321. data/spec/workflow/engine_spec.rb +241 -0
  322. data/spec/workflow/node_spec.rb +62 -0
  323. data/spec/workflow/notifier/hipchat_spec.rb +117 -0
  324. data/spec/workflow/notifier/mail_spec.rb +86 -0
  325. data/spec/workflow/notifier/slack_spec.rb +110 -0
  326. data/spec/workflow/script_parser_spec.rb +119 -0
  327. data/spec/workflow/shell_scanner_spec.rb +47 -0
  328. data/spec/workflow/task/auto_skip_error_spec.rb +35 -0
  329. data/spec/workflow/task/env_spec.rb +47 -0
  330. data/spec/workflow/task/execute_spec.rb +127 -0
  331. data/spec/workflow/task/expected_time_spec.rb +52 -0
  332. data/spec/workflow/task/fork_spec.rb +30 -0
  333. data/spec/workflow/task/queue_spec.rb +45 -0
  334. data/spec/workflow/task/rails_env_spec.rb +30 -0
  335. data/spec/workflow/task/sleep_spec.rb +22 -0
  336. data/spec/workflow/task/sub_process_spec.rb +32 -0
  337. data/spec/workflow/task/wait_spec.rb +162 -0
  338. metadata +1038 -0
@@ -0,0 +1,143 @@
1
+ module Kuroko2
2
+ module Workflow
3
+ module Task
4
+ class Wait < Base
5
+ PERIODS = %w(hourly daily weekly monthly)
6
+
7
+ def execute
8
+ if token.context['WAIT'].present?
9
+ if token.waiting?
10
+ process_waiting_job
11
+ else
12
+ Kuroko2.logger.info { "(token #{token.uuid}) Skip since current status marked as '#{token.status_name}'." }
13
+ token.mark_as_waiting
14
+
15
+ :pass
16
+ end
17
+ else
18
+ token.context['WAIT'] = parse_option(option, start_at: token.job_instance.created_at)
19
+
20
+ Kuroko2.logger.info { "(token #{token.uuid}) waiting jobs: #{token.context['WAIT']["jobs"]}" }
21
+
22
+ token.mark_as_waiting
23
+ message = "(token #{token.uuid}) Marked as 'waiting' #{node.option}."
24
+ token.job_instance.logs.info(message)
25
+ Kuroko2.logger.info(message)
26
+ token.save!
27
+
28
+ :pass
29
+ end
30
+ end
31
+
32
+ def process_waiting_job
33
+ receive_waiting_job_completion!
34
+
35
+ wait_option = token.context['WAIT']
36
+ if wait_option["jobs"].all? { |wait_job| wait_job["received"] }
37
+ token.mark_as_working
38
+ token.context.delete('WAIT')
39
+ token.save!
40
+
41
+ message = "(token #{token.uuid}) All waiting jobs are finished."
42
+ Kuroko2.logger.info(message)
43
+ token.job_instance.logs.info(message)
44
+
45
+ :next
46
+ elsif wait_option["timeout"].minutes.since(token.created_at).past?
47
+ message = "(token #{token.uuid}) waiting jobs `#{node.option}` timeout."
48
+ Kuroko2.logger.error(message)
49
+ token.job_instance.logs.error(message)
50
+
51
+ :failure
52
+ else
53
+ :pass
54
+ end
55
+ end
56
+
57
+ def validate
58
+ parse_option(option)
59
+ end
60
+
61
+ private
62
+
63
+ # ex. wait: 100/daily 200/daily
64
+ def parse_option(option, start_at: Time.now)
65
+ raise_assertion_error unless option
66
+
67
+ wait_option = { "jobs" => [], "timeout" => 60.minutes.to_i / 1.minute }
68
+ scanner = StringScanner.new(option)
69
+ until scanner.eos?
70
+ if scanner.scan(%r!(\d+)\s*/\s*(#{PERIODS.join('|')})!)
71
+ start_from, start_to = period_to_time(scanner[2], at: start_at)
72
+ wait_option["jobs"] << {
73
+ "job_definition_id" => parse_definition_id(scanner[1]),
74
+ "period" => scanner[2],
75
+ "start_from" => start_from.to_s,
76
+ "start_to" => start_to.to_s,
77
+ "received" => false,
78
+ }
79
+ elsif scanner.scan(/timeout=(\d+)h/)
80
+ wait_option["timeout"] = scanner[1].to_i.hours / 60
81
+ elsif scanner.scan(/timeout=(\d+)m/) || scanner.scan(/timeout=(\d+)/)
82
+ wait_option["timeout"] = scanner[1].to_i
83
+ elsif scanner.scan(/\s+|,/)
84
+ # do nothing
85
+ else
86
+ raise_assertion_error
87
+ end
88
+ end
89
+
90
+ wait_option
91
+ end
92
+
93
+ def receive_waiting_job_completion!
94
+ token.context['WAIT']["jobs"].each do |wait_job|
95
+ next if wait_job["received"] == true
96
+
97
+ start_from = Time.zone.parse(wait_job["start_from"])
98
+ start_to = Time.zone.parse(wait_job["start_to"])
99
+
100
+ received_instance = JobInstance.finished.where(
101
+ job_definition_id: wait_job["job_definition_id"].to_i,
102
+ created_at: start_from .. start_to
103
+ ).first
104
+
105
+ if received_instance.present?
106
+ wait_job["received"] = true
107
+ token.save!
108
+
109
+ message = "(token #{token.uuid}) A waiting job instance##{received_instance.job_definition_id}/#{received_instance.id} is finished."
110
+ Kuroko2.logger.info(message)
111
+ token.job_instance.logs.info(message)
112
+ end
113
+ end
114
+ end
115
+
116
+ def period_to_time(period, at: Time.now)
117
+ case period
118
+ when "hourly"
119
+ [at.beginning_of_hour, at.end_of_hour]
120
+ when "daily"
121
+ [at.beginning_of_day, at.end_of_day]
122
+ when "weekly"
123
+ [at.beginning_of_week, at.end_of_week]
124
+ when "monthly"
125
+ [at.beginning_of_month, at.end_of_month]
126
+ else
127
+ raise_assertion_error
128
+ end
129
+ end
130
+
131
+ def parse_definition_id(id)
132
+ JobDefinition.find(id.to_i).id
133
+ rescue ActiveRecord::RecordNotFound
134
+ raise Workflow::AssertionError, "Given Job Definition ID not found: #{id}"
135
+ end
136
+
137
+ def raise_assertion_error
138
+ raise Workflow::AssertionError, "Syntax error option value of wait: #{option}"
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
data/lib/kuroko2.rb ADDED
@@ -0,0 +1,26 @@
1
+ require 'chrono'
2
+ require 'addressable'
3
+ require 'aws-sdk'
4
+ require 'retryable'
5
+ require 'faraday'
6
+ require 'html/pipeline'
7
+
8
+ require "kuroko2/engine"
9
+ require "kuroko2/configuration"
10
+ require "kuroko2/util/logger"
11
+
12
+ module Kuroko2
13
+ class << self
14
+ def logger
15
+ @logger ||= defined?(Rails) && Rails.env.test? ? Rails.logger : Util::Logger.new($stdout)
16
+ end
17
+
18
+ def logger=(logger)
19
+ @logger = logger
20
+ end
21
+
22
+ def config
23
+ Configuration.config
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :kuroko2 do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,20 @@
1
+ require 'rails_helper'
2
+
3
+ module Kuroko2::Command
4
+ describe Kill do
5
+
6
+ describe '#execute' do
7
+ subject { Kill.new('test', '1').execute }
8
+
9
+ before { Process.detach(pid) }
10
+
11
+ let!(:signal) { create(:process_signal, pid: pid, hostname: 'test') }
12
+ let(:pid) { Process.spawn('sleep 10') }
13
+
14
+ it 'terminates spawned process' do
15
+ is_expected.to eq signal
16
+ expect { Process.kill(0, pid) }.to raise_error(Errno::ESRCH)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,68 @@
1
+ require 'rails_helper'
2
+
3
+
4
+ module Kuroko2::Command
5
+ describe Monitor do
6
+ let(:pid) { 32769 } # max int + 1
7
+ let(:hostname) { 'rspec' }
8
+
9
+ let(:definition) { create(:job_definition) }
10
+ let(:instance) { create(:job_instance, job_definition: definition) }
11
+ let(:token) { create(:token, job_definition: definition, job_instance: instance) }
12
+ let(:worker) { create(:worker, hostname: hostname) }
13
+
14
+ describe '#execute' do
15
+ let(:sent_mail) { ActionMailer::Base.deliveries.last }
16
+
17
+ context 'not running process' do
18
+ let!(:execution) { create(:execution, token: token, worker: worker, started_at: Time.now, finished_at: nil, pid: pid) }
19
+ let(:monitor) { Kuroko2::Command::Monitor.new(hostname: hostname, worker_id: 1) }
20
+
21
+ subject! { 15.times { monitor.execute } }
22
+
23
+ it 'sends a notification mail' do
24
+ execution.reload
25
+
26
+ expect(monitor.counter_size).to be_zero
27
+ expect(sent_mail).not_to be_nil
28
+ expect(sent_mail.subject).to eq '[CRITICAL] Process is not running on kuroko'
29
+ expect(execution.mailed_at).not_to be_nil
30
+ end
31
+ end
32
+
33
+ context 'not assigned process' do
34
+ let!(:execution) { create(:execution, token: token, worker: worker, started_at: 2.minutes.ago, finished_at: nil, pid: nil) }
35
+ subject! { Kuroko2::Command::Monitor.new(hostname: hostname, worker_id: 1).execute }
36
+
37
+ it 'sends a notification mail' do
38
+ execution.reload
39
+
40
+ expect(sent_mail.subject).to eq '[CRITICAL] Process is not assigned to any job-executor'
41
+ expect(execution.mailed_at).not_to be_nil
42
+ end
43
+ end
44
+ end
45
+
46
+ describe 'memory consumption monitoring' do
47
+ let!(:execution) { create(:execution, token: token, worker: worker, started_at: Time.now, finished_at: nil, pid: pid) }
48
+ let(:monitor) { Kuroko2::Command::Monitor.new(hostname: hostname, worker_id: 1) }
49
+ before do
50
+ allow(monitor).to receive(:check_process_absence).and_return(true)
51
+ allow(Kuroko2::MemorySampler).to receive(:get_by_pgid).and_return(1)
52
+ end
53
+
54
+ it 'logs memory consumption' do
55
+ expect {
56
+ monitor.execute
57
+ }.to change {
58
+ execution.job_definition.memory_expectancy.memory_consumption_logs.count
59
+ }.from(0).to(1)
60
+
61
+ log = execution.job_definition.memory_expectancy.memory_consumption_logs.first
62
+ expect(log.value).to be_kind_of(Integer)
63
+ expect(log.value).not_to eq(0)
64
+ expect(log.job_instance_id).to eq(instance.id)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,87 @@
1
+ require 'rails_helper'
2
+
3
+ module Kuroko2::Command
4
+ describe Shell do
5
+
6
+ describe '#execute' do
7
+ subject { Shell.new(hostname: 'rspec', worker: worker).execute }
8
+
9
+ let(:job_definition) { create(:job_definition) }
10
+ let(:job_instance) { create(:job_instance, job_definition: job_definition) }
11
+ let(:token) { create(:token, job_instance: job_instance, job_definition: job_definition) }
12
+ let!(:execution) { create(:execution, shell: shell, context: { 'ENV' => { 'NAME' => "kuroko" } }, started_at: nil, finished_at: nil, token: token) }
13
+ let(:shell) { 'ruby -e "true"' }
14
+
15
+ context 'when available worker exists' do
16
+ let(:worker) { create(:worker) }
17
+
18
+ context 'successfully' do
19
+ let(:shell) { 'ruby -e "puts ENV[\'NAME\'] + \\"\\\x99\\""' }
20
+
21
+ it do
22
+ is_expected.to eq execution
23
+
24
+ expect(subject.started_at).not_to be_nil
25
+ expect(subject.finished_at).not_to be_nil
26
+ expect(subject).to be_success
27
+ end
28
+ end
29
+
30
+ context 'failure' do
31
+ let(:shell) { 'wrong_script' }
32
+
33
+ it do
34
+ is_expected.to eq execution
35
+
36
+ expect(subject.started_at).not_to be_nil
37
+ expect(subject.finished_at).not_to be_nil
38
+ expect(subject).not_to be_success
39
+ end
40
+ end
41
+
42
+ context 'with 4byte utf-8 charactor' do
43
+ let(:shell) { 'ruby -e "puts ENV[\'NAME\'] + \\"\xF0\x9F\x98\x81\\""' }
44
+
45
+ it do
46
+ is_expected.to eq execution
47
+
48
+ expect(subject.started_at).not_to be_nil
49
+ expect(subject.finished_at).not_to be_nil
50
+ expect(subject).to be_success
51
+ end
52
+ end
53
+ end
54
+
55
+ context 'when all workers are busy' do
56
+ let(:worker) { create(:worker, execution_id: execution.id) }
57
+
58
+ it 'skips execution' do
59
+ is_expected.to be_nil
60
+ execution.reload
61
+ expect(execution.started_at).to be_nil
62
+ end
63
+ end
64
+
65
+ describe 'memory expectancy calculation' do
66
+ let(:worker) { create(:worker) }
67
+ let(:memory_expectancy) { execution.job_definition.memory_expectancy }
68
+
69
+ context 'when memory consumption logs exist' do
70
+ before do
71
+ (1..10).each {|i| job_instance.create_memory_consumption_log!(value: i) }
72
+ end
73
+
74
+ it 'calculates memory expectancy of related job definition' do
75
+ expect { subject }.to change { memory_expectancy.reload.expected_value }
76
+ end
77
+ end
78
+
79
+ context 'when no memory consumption logs exist' do
80
+ it 'does not calculates memory expectancy of related job definition' do
81
+ expect { subject }.not_to change { memory_expectancy.reload.expected_value }
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,5 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe Kuroko2::DashboardController, :type => :controller do
4
+ routes { Kuroko2::Engine.routes }
5
+ end
@@ -0,0 +1,23 @@
1
+ require 'rails_helper'
2
+
3
+ describe Kuroko2::ExecutionsController do
4
+ routes { Kuroko2::Engine.routes }
5
+
6
+ before { sign_in }
7
+
8
+ describe '#destroy' do
9
+ let(:definition) { create(:job_definition) }
10
+ let(:instance) { create(:job_instance, job_definition: definition) }
11
+ let(:token) { create(:token, job_instance: instance) }
12
+ let(:execution) { create(:execution, token: token, exit_status: nil, pid: 1) }
13
+ let!(:worker) { create(:worker, execution: execution) }
14
+
15
+ subject! { delete :destroy, params: { job_definition_id: definition.id, job_instance_id: instance.id, id: execution.id } }
16
+
17
+ it do
18
+ expect(response).to redirect_to(job_definition_job_instance_path(job_definition_id: definition.id, id: instance.id))
19
+ expect(Kuroko2::ProcessSignal.count).to eq 1
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,95 @@
1
+ require 'rails_helper'
2
+
3
+ describe Kuroko2::JobDefinitionStatsController do
4
+ routes { Kuroko2::Engine.routes }
5
+
6
+ before { sign_in }
7
+
8
+ let(:instance_num) { 2 }
9
+ let(:definition) do
10
+ create(
11
+ :job_definition_with_instances,
12
+ job_instances_count: instance_num,
13
+ job_instances_token_status: Kuroko2::Token::FINISHED
14
+ )
15
+ end
16
+
17
+ before do
18
+ definition.job_instances.first.update!(created_at: 2.months.ago)
19
+
20
+ definition.job_instances.each do |instance|
21
+ Kuroko2::MemoryConsumptionLog.create!(job_instance_id: instance.id, value: 1000 + rand(10))
22
+ end
23
+ end
24
+
25
+ describe '#index' do
26
+ before { get :index, params: { job_definition_id: definition.id } }
27
+
28
+ it do
29
+ expect(response).to have_http_status(:ok)
30
+ expect(response).to render_template('index')
31
+ expect(assigns(:definition)).to eq definition
32
+ end
33
+ end
34
+
35
+ describe '#memory' do
36
+ context 'without parameters' do
37
+ before { get :memory, params: { job_definition_id: definition.id }, xhr: true }
38
+
39
+ it do
40
+ expect(response).to have_http_status(:ok)
41
+ expect(assigns(:definition)).to eq definition
42
+ expect(assigns(:logs).size).to eq 2
43
+ end
44
+ end
45
+
46
+ context 'with period parameter' do
47
+ before { get :memory, params: { job_definition_id: definition.id, period: period }, xhr: true }
48
+
49
+ context 'with period is 1d' do
50
+ let(:period) { '1d' }
51
+ it { expect(assigns(:logs).size).to eq 1 }
52
+ end
53
+
54
+ context 'with period is 2w' do
55
+ let(:period) { '2w' }
56
+ it { expect(assigns(:logs).size).to eq 1 }
57
+ end
58
+
59
+ context 'with period is 3m' do
60
+ let(:period) { '3m' }
61
+ it { expect(assigns(:logs).size).to eq 2 }
62
+ end
63
+ end
64
+ end
65
+
66
+ describe '#execution_time' do
67
+ context 'without parameters' do
68
+ before { get :execution_time, params: { job_definition_id: definition.id }, xhr: true }
69
+ it do
70
+ expect(response).to have_http_status(:ok)
71
+ expect(assigns(:definition)).to eq definition
72
+ expect(assigns(:logs).size).to eq 2
73
+ end
74
+ end
75
+
76
+ context 'with peripd parameter' do
77
+ before { get :execution_time, params: { job_definition_id: definition.id, period: period }, xhr: true }
78
+
79
+ context 'with period is 1d' do
80
+ let(:period) { '1d' }
81
+ it { expect(assigns(:logs).size).to eq 1 }
82
+ end
83
+
84
+ context 'with period is 2w' do
85
+ let(:period) { '2w' }
86
+ it { expect(assigns(:logs).size).to eq 1 }
87
+ end
88
+
89
+ context 'with period is 3m' do
90
+ let(:period) { '3m' }
91
+ it { expect(assigns(:logs).size).to eq 2 }
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,89 @@
1
+ require 'rails_helper'
2
+
3
+ describe Kuroko2::JobDefinitionsController do
4
+ routes { Kuroko2::Engine.routes }
5
+
6
+ before { sign_in }
7
+
8
+ let(:definition) { create(:job_definition) }
9
+
10
+ describe '#index' do
11
+ subject! { get :index }
12
+ let!(:definitions) { create_list(:job_definition, 3) }
13
+
14
+ it do
15
+ expect(response).to have_http_status(:ok)
16
+ expect(response).to render_template('index')
17
+
18
+ expect(assigns(:definitions)).to eq definitions
19
+ end
20
+ end
21
+
22
+ describe '#show' do
23
+ subject! { get :show, params: { id: definition.id } }
24
+
25
+ it do
26
+ expect(response).to have_http_status(:ok)
27
+ expect(response).to render_template('show')
28
+
29
+ expect(assigns(:definition)).to eq definition
30
+ end
31
+ end
32
+
33
+ describe '#new' do
34
+ subject! { get :new }
35
+ it do
36
+ expect(response).to have_http_status(:ok)
37
+ expect(response).to render_template('new')
38
+
39
+ expect(assigns(:definition)).to be_new_record
40
+ end
41
+ end
42
+
43
+ describe '#create' do
44
+ subject! do
45
+ post :create, params: { job_definition: { name: 'Job Definition', description: 'This is description', script: "noop:\n" } }
46
+ end
47
+
48
+ it do
49
+ expect(response).to redirect_to(assigns(:definition))
50
+
51
+ expect(assigns(:definition)).not_to be_new_record
52
+ expect(assigns(:definition).admins).to eq [controller.current_user]
53
+ expect(assigns(:definition).memory_expectancy).not_to be_nil
54
+ end
55
+ end
56
+
57
+ describe '#edit' do
58
+ subject! { get :edit, params: { id: definition.id } }
59
+
60
+ it do
61
+ expect(response).to have_http_status(:ok)
62
+ expect(assigns(:definition)).to eq definition
63
+ end
64
+ end
65
+
66
+ describe '#update' do
67
+ let(:admin) { create(:user) }
68
+ subject! do
69
+ patch :update, params: { id: definition.id, job_definition: { name: 'Job Definition', description: 'This is description', script: "noop:\n" }, admin_assignments: { user_id: ["", admin.id] } }
70
+ end
71
+
72
+ it do
73
+ expect(response).to redirect_to(assigns(:definition))
74
+
75
+ expect(assigns(:definition)).not_to be_new_record
76
+ end
77
+ end
78
+
79
+ describe '#destroy' do
80
+ subject! { delete :destroy, params: { id: definition.id } }
81
+
82
+ it do
83
+ expect(response).to redirect_to(job_definitions_path)
84
+
85
+ expect(assigns(:definition)).to be_destroyed
86
+ end
87
+ end
88
+
89
+ end
@@ -0,0 +1,62 @@
1
+ require 'rails_helper'
2
+
3
+ describe Kuroko2::JobInstancesController do
4
+ routes { Kuroko2::Engine.routes }
5
+
6
+ before { sign_in }
7
+
8
+ let(:definition) { create(:job_definition_with_instances, job_instances_count: num_instances) }
9
+
10
+ describe '#index' do
11
+ let(:num_instances) { 2 }
12
+ before { get :index, params: { job_definition_id: definition.id } }
13
+
14
+ it do
15
+ expect(response).to have_http_status(:ok)
16
+ expect(response).to render_template('index')
17
+
18
+ expect(assigns(:definition)).to eq definition
19
+ expect(assigns(:instances).size).to eq num_instances
20
+ end
21
+ end
22
+
23
+ describe '#create' do
24
+ let(:num_instances) { 2 }
25
+ before { post :create, params: { job_definition_id: definition.id }, xhr: true }
26
+
27
+ it do
28
+ expect(response).to redirect_to(job_definition_job_instance_path(definition, assigns(:instance)))
29
+
30
+ expect(assigns(:definition)).to eq definition
31
+ end
32
+
33
+ context 'with Ad-Hoc `script` parameter' do
34
+ let(:script) { "execute: echo 1" }
35
+ before { post :create, params: { job_definition_id: definition.id, job_definition: { script: script } }, xhr: true }
36
+ it 'creates instance in Ad-Hoc script' do
37
+ expect(assigns(:instance).script).to eq script
38
+ end
39
+ end
40
+ end
41
+
42
+ describe '#destroy' do
43
+ before do
44
+ instance.tokens.each do |token|
45
+ token.update_column(:status, Kuroko2::Token::FAILURE)
46
+ end
47
+
48
+ delete :destroy, params: { job_definition_id: definition, id: instance }
49
+ end
50
+
51
+ let(:num_instances) { 1 }
52
+ let(:instance) { definition.job_instances.first }
53
+
54
+ it do
55
+ instance.reload
56
+
57
+ expect(response).to redirect_to(job_definition_job_instance_path(definition, instance))
58
+ expect(instance.tokens.size).to eq 0
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,39 @@
1
+ require 'rails_helper'
2
+
3
+ describe Kuroko2::JobSchedulesController do
4
+ routes { Kuroko2::Engine.routes }
5
+
6
+ before { sign_in }
7
+
8
+ let(:schedules) { create_list(:job_schedule, 1) }
9
+ let(:definition) { create(:job_definition, job_schedules: schedules) }
10
+
11
+ describe '#index' do
12
+ it do
13
+ get :index, params: { job_definition_id: definition.id }
14
+
15
+ expect(response).to have_http_status(:ok)
16
+ expect(assigns(:schedule)).to be_new_record
17
+ expect(assigns(:schedules)).to eq schedules
18
+ end
19
+ end
20
+
21
+ describe '#create' do
22
+ it do
23
+ post :create, params: { job_definition_id: definition.id, job_schedule: { cron: '* * * * *' } }
24
+
25
+ expect(response).to have_http_status(:created)
26
+ end
27
+ end
28
+
29
+ describe '#destroy' do
30
+
31
+ it do
32
+ delete :destroy, params: { job_definition_id: definition.id, id: schedules.first.id }
33
+ definition.reload
34
+
35
+ expect(response).to have_http_status(:ok)
36
+ expect(definition.job_schedules.size).to be 0
37
+ end
38
+ end
39
+ end