foreman_patch 1.1.1

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 (312) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +619 -0
  3. data/README.md +38 -0
  4. data/Rakefile +53 -0
  5. data/app/assets/javascript/foreman_patch/plan_edit_windows.js +9 -0
  6. data/app/assets/stylesheets/foreman_patch/cycle_plans.scss +6 -0
  7. data/app/assets/stylesheets/foreman_patch/foreman_patch.css +4 -0
  8. data/app/controllers/concerns/foreman_patch/parameters/ticket_field.rb +26 -0
  9. data/app/controllers/foreman_patch/api/v2/base_controller.rb +12 -0
  10. data/app/controllers/foreman_patch/api/v2/cycles_controller.rb +78 -0
  11. data/app/controllers/foreman_patch/api/v2/groups_controller.rb +70 -0
  12. data/app/controllers/foreman_patch/api/v2/host_groups_controller.rb +13 -0
  13. data/app/controllers/foreman_patch/api/v2/invocations_controller.rb +70 -0
  14. data/app/controllers/foreman_patch/api/v2/plans_controller.rb +79 -0
  15. data/app/controllers/foreman_patch/api/v2/rounds_controller.rb +77 -0
  16. data/app/controllers/foreman_patch/api/v2/window_plans_controller.rb +73 -0
  17. data/app/controllers/foreman_patch/api/v2/windows_controller.rb +85 -0
  18. data/app/controllers/foreman_patch/concerns/api/v2/hosts_controller_extensions.rb +21 -0
  19. data/app/controllers/foreman_patch/concerns/hosts_controller_extensions.rb +61 -0
  20. data/app/controllers/foreman_patch/cycles_controller.rb +34 -0
  21. data/app/controllers/foreman_patch/groups_controller.rb +68 -0
  22. data/app/controllers/foreman_patch/invocations_controller.rb +51 -0
  23. data/app/controllers/foreman_patch/plans_controller.rb +59 -0
  24. data/app/controllers/foreman_patch/rounds_controller.rb +18 -0
  25. data/app/controllers/foreman_patch/ticket_fields_controller.rb +37 -0
  26. data/app/controllers/foreman_patch/window_plans_controller.rb +60 -0
  27. data/app/controllers/foreman_patch/windows_controller.rb +58 -0
  28. data/app/helpers/concerns/foreman_patch/hosts_helper_extensions.rb +13 -0
  29. data/app/helpers/foreman_patch/cycles_helper.rb +19 -0
  30. data/app/helpers/foreman_patch/hosts_helper.rb +52 -0
  31. data/app/helpers/foreman_patch/patching_helper.rb +116 -0
  32. data/app/helpers/foreman_patch/plans_helper.rb +45 -0
  33. data/app/helpers/foreman_patch/ticket_helper.rb +11 -0
  34. data/app/helpers/foreman_patch/window_patching_helper.rb +20 -0
  35. data/app/helpers/foreman_patch/window_plans_helper.rb +13 -0
  36. data/app/helpers/foreman_patch/windows_helper.rb +17 -0
  37. data/app/lib/actions/foreman_patch/cycle/complete.rb +41 -0
  38. data/app/lib/actions/foreman_patch/cycle/create.rb +69 -0
  39. data/app/lib/actions/foreman_patch/cycle/initiate.rb +68 -0
  40. data/app/lib/actions/foreman_patch/cycle/plan.rb +73 -0
  41. data/app/lib/actions/foreman_patch/cycle/prepare_content.rb +123 -0
  42. data/app/lib/actions/foreman_patch/host/reschedule.rb +32 -0
  43. data/app/lib/actions/foreman_patch/invocation/action.rb +135 -0
  44. data/app/lib/actions/foreman_patch/invocation/ensure_services.rb +47 -0
  45. data/app/lib/actions/foreman_patch/invocation/patch.rb +93 -0
  46. data/app/lib/actions/foreman_patch/invocation/reschedule.rb +21 -0
  47. data/app/lib/actions/foreman_patch/invocation/restart.rb +101 -0
  48. data/app/lib/actions/foreman_patch/invocation/update_packages.rb +52 -0
  49. data/app/lib/actions/foreman_patch/invocation/wait_for_host.rb +103 -0
  50. data/app/lib/actions/foreman_patch/round/add_missing_hosts.rb +21 -0
  51. data/app/lib/actions/foreman_patch/round/create.rb +37 -0
  52. data/app/lib/actions/foreman_patch/round/patch.rb +81 -0
  53. data/app/lib/actions/foreman_patch/round/plan.rb +33 -0
  54. data/app/lib/actions/foreman_patch/round/resolve_hosts.rb +45 -0
  55. data/app/lib/actions/foreman_patch/window/create.rb +41 -0
  56. data/app/lib/actions/foreman_patch/window/patch.rb +72 -0
  57. data/app/lib/actions/foreman_patch/window/plan.rb +43 -0
  58. data/app/lib/actions/foreman_patch/window/publish.rb +32 -0
  59. data/app/lib/actions/foreman_patch/window/resolve_hosts.rb +31 -0
  60. data/app/lib/actions/helpers/failure_notification.rb +20 -0
  61. data/app/lib/actions/helpers/with_feature_action.rb +102 -0
  62. data/app/lib/actions/middleware/check_exit_status.rb +31 -0
  63. data/app/mailers/foreman_patch/cycle_mailer.rb +17 -0
  64. data/app/mailers/foreman_patch/group_mailer.rb +41 -0
  65. data/app/mailers/foreman_patch/invocation_mailer.rb +19 -0
  66. data/app/models/foreman_patch/concerns/group_facet_host_extensions.rb +35 -0
  67. data/app/models/foreman_patch/concerns/host_managed_extensions.rb +17 -0
  68. data/app/models/foreman_patch/cycle.rb +49 -0
  69. data/app/models/foreman_patch/group.rb +43 -0
  70. data/app/models/foreman_patch/host/group_facet.rb +13 -0
  71. data/app/models/foreman_patch/invocation.rb +60 -0
  72. data/app/models/foreman_patch/plan.rb +110 -0
  73. data/app/models/foreman_patch/plan_task_group.rb +11 -0
  74. data/app/models/foreman_patch/round.rb +68 -0
  75. data/app/models/foreman_patch/ticket_field.rb +23 -0
  76. data/app/models/foreman_patch/window.rb +123 -0
  77. data/app/models/foreman_patch/window_plan.rb +77 -0
  78. data/app/models/foreman_patch/window_task_group.rb +11 -0
  79. data/app/models/setting/patching.rb +57 -0
  80. data/app/services/foreman_patch/cycle_name_generator.rb +38 -0
  81. data/app/services/foreman_patch/ticket/affected_items.rb +110 -0
  82. data/app/services/foreman_patch/ticket/api.rb +68 -0
  83. data/app/services/foreman_patch/ticket/change_request.rb +92 -0
  84. data/app/services/foreman_patch/ticket/field_render.rb +21 -0
  85. data/app/services/foreman_patch/ticket/payload.rb +136 -0
  86. data/app/services/foreman_patch/ticket.rb +14 -0
  87. data/app/views/dashboard/_foreman_patch_widget.html.erb +2 -0
  88. data/app/views/foreman_patch/api/v2/cycles/base.json.rabl +3 -0
  89. data/app/views/foreman_patch/api/v2/cycles/create.json.rabl +3 -0
  90. data/app/views/foreman_patch/api/v2/cycles/index.json.rabl +3 -0
  91. data/app/views/foreman_patch/api/v2/cycles/show.json.rabl +9 -0
  92. data/app/views/foreman_patch/api/v2/cycles/update.json.rabl +3 -0
  93. data/app/views/foreman_patch/api/v2/group_facet/base.json.rabl +7 -0
  94. data/app/views/foreman_patch/api/v2/group_facet/base_with_root.json.rabl +4 -0
  95. data/app/views/foreman_patch/api/v2/group_facet/show.json.rabl +3 -0
  96. data/app/views/foreman_patch/api/v2/groups/base.json.rabl +3 -0
  97. data/app/views/foreman_patch/api/v2/groups/create.json.rabl +3 -0
  98. data/app/views/foreman_patch/api/v2/groups/index.json.rabl +2 -0
  99. data/app/views/foreman_patch/api/v2/groups/show.json.rabl +14 -0
  100. data/app/views/foreman_patch/api/v2/groups/update.json.rabl +3 -0
  101. data/app/views/foreman_patch/api/v2/invocations/base.json.rabl +6 -0
  102. data/app/views/foreman_patch/api/v2/invocations/index.json.rabl +3 -0
  103. data/app/views/foreman_patch/api/v2/invocations/phase.json.rabl +7 -0
  104. data/app/views/foreman_patch/api/v2/invocations/show.json.rabl +7 -0
  105. data/app/views/foreman_patch/api/v2/plans/base.json.rabl +3 -0
  106. data/app/views/foreman_patch/api/v2/plans/create.json.rabl +2 -0
  107. data/app/views/foreman_patch/api/v2/plans/index.json.rabl +3 -0
  108. data/app/views/foreman_patch/api/v2/plans/show.json.rabl +9 -0
  109. data/app/views/foreman_patch/api/v2/plans/update.json.rabl +2 -0
  110. data/app/views/foreman_patch/api/v2/rounds/base.json.rabl +3 -0
  111. data/app/views/foreman_patch/api/v2/rounds/index.json.rabl +3 -0
  112. data/app/views/foreman_patch/api/v2/rounds/show.json.rabl +17 -0
  113. data/app/views/foreman_patch/api/v2/rounds/status.json.rabl +11 -0
  114. data/app/views/foreman_patch/api/v2/window_plans/base.json.rabl +4 -0
  115. data/app/views/foreman_patch/api/v2/window_plans/create.json.rabl +2 -0
  116. data/app/views/foreman_patch/api/v2/window_plans/index.json.rabl +2 -0
  117. data/app/views/foreman_patch/api/v2/window_plans/show.json.rabl +14 -0
  118. data/app/views/foreman_patch/api/v2/window_plans/update.json.rabl +2 -0
  119. data/app/views/foreman_patch/api/v2/windows/base.json.rabl +3 -0
  120. data/app/views/foreman_patch/api/v2/windows/index.json.rabl +3 -0
  121. data/app/views/foreman_patch/api/v2/windows/schedule.json.rabl +13 -0
  122. data/app/views/foreman_patch/api/v2/windows/show.json.rabl +13 -0
  123. data/app/views/foreman_patch/api/v2/windows/update.json.rabl +3 -0
  124. data/app/views/foreman_patch/cycle_mailer/_details.html.erb +4 -0
  125. data/app/views/foreman_patch/cycle_mailer/_round.html.erb +12 -0
  126. data/app/views/foreman_patch/cycle_mailer/_summary.html.erb +6 -0
  127. data/app/views/foreman_patch/cycle_mailer/_window.html.erb +4 -0
  128. data/app/views/foreman_patch/cycle_mailer/planned.html.erb +7 -0
  129. data/app/views/foreman_patch/cycles/_form.html.erb +9 -0
  130. data/app/views/foreman_patch/cycles/edit.html.erb +41 -0
  131. data/app/views/foreman_patch/cycles/index.html.erb +45 -0
  132. data/app/views/foreman_patch/cycles/show.html.erb +26 -0
  133. data/app/views/foreman_patch/group_mailer/_dashboard.html.erb +31 -0
  134. data/app/views/foreman_patch/group_mailer/_list.html.erb +17 -0
  135. data/app/views/foreman_patch/group_mailer/completed.html.erb +16 -0
  136. data/app/views/foreman_patch/group_mailer/initiated.html.erb +4 -0
  137. data/app/views/foreman_patch/groups/_form.html.erb +9 -0
  138. data/app/views/foreman_patch/groups/edit.html.erb +3 -0
  139. data/app/views/foreman_patch/groups/index.html.erb +40 -0
  140. data/app/views/foreman_patch/groups/new.html.erb +3 -0
  141. data/app/views/foreman_patch/hosts/hosts/new_action.html.erb +1 -0
  142. data/app/views/foreman_patch/hosts/new_action.html.erb +1 -0
  143. data/app/views/foreman_patch/invocation_mailer/_output_line_set.html.erb +6 -0
  144. data/app/views/foreman_patch/invocation_mailer/_output_line_set.text.erb +3 -0
  145. data/app/views/foreman_patch/invocation_mailer/failure.html.erb +50 -0
  146. data/app/views/foreman_patch/invocation_mailer/failure.text.erb +10 -0
  147. data/app/views/foreman_patch/invocations/_output_line_set.html.erb +8 -0
  148. data/app/views/foreman_patch/invocations/_phase.html.erb +17 -0
  149. data/app/views/foreman_patch/invocations/_primary.html.erb +1 -0
  150. data/app/views/foreman_patch/invocations/_refresh.js.erb +7 -0
  151. data/app/views/foreman_patch/invocations/show.html.erb +44 -0
  152. data/app/views/foreman_patch/invocations/show.js.erb +17 -0
  153. data/app/views/foreman_patch/layouts/react.html.erb +17 -0
  154. data/app/views/foreman_patch/plans/_form.html.erb +12 -0
  155. data/app/views/foreman_patch/plans/edit.html.erb +6 -0
  156. data/app/views/foreman_patch/plans/index.html.erb +32 -0
  157. data/app/views/foreman_patch/plans/new.html.erb +3 -0
  158. data/app/views/foreman_patch/plans/show.html.erb +19 -0
  159. data/app/views/foreman_patch/rounds/show.html.erb +54 -0
  160. data/app/views/foreman_patch/ticket_fields/_fields.html.erb +66 -0
  161. data/app/views/foreman_patch/ticket_fields/edit.html.erb +6 -0
  162. data/app/views/foreman_patch/ticket_fields/index.html.erb +26 -0
  163. data/app/views/foreman_patch/ticket_fields/new.html.erb +6 -0
  164. data/app/views/foreman_patch/window_plans/_form.html.erb +11 -0
  165. data/app/views/foreman_patch/window_plans/_hidden_layout.html.erb +7 -0
  166. data/app/views/foreman_patch/window_plans/edit.html.erb +3 -0
  167. data/app/views/foreman_patch/window_plans/new.html.erb +3 -0
  168. data/app/views/foreman_patch/windows/_form.html.erb +21 -0
  169. data/app/views/foreman_patch/windows/_groups.html.erb +2 -0
  170. data/app/views/foreman_patch/windows/_rounds.html.erb +24 -0
  171. data/app/views/foreman_patch/windows/_schedule.html.erb +16 -0
  172. data/app/views/foreman_patch/windows/_ticket.html.erb +12 -0
  173. data/app/views/foreman_patch/windows/edit.html.erb +3 -0
  174. data/app/views/foreman_patch/windows/new.html.erb +3 -0
  175. data/app/views/foreman_patch/windows/show.html.erb +27 -0
  176. data/app/views/foreman_patch/windows/show.json.erb +4 -0
  177. data/app/views/hosts/select_multiple_patch_group.html.erb +12 -0
  178. data/app/views/overrides/patch_groups/_host_patch_group_select.html.erb +9 -0
  179. data/app/views/templates/ensure_services.erb +28 -0
  180. data/config/api_routes.rb +37 -0
  181. data/config/initializers/pagelets.rb +6 -0
  182. data/config/initializers/safemode_jail.rb +4 -0
  183. data/config/routes/mount_engine.rb +3 -0
  184. data/config/routes/overrides.rb +10 -0
  185. data/config/routes.rb +47 -0
  186. data/db/migrate/20210202161304_create_foreman_patch_plans.rb +32 -0
  187. data/db/migrate/20210202163323_create_foreman_patch_cycles.rb +38 -0
  188. data/db/migrate/20210202164301_create_foreman_patch_groups.rb +37 -0
  189. data/db/migrate/20210226134103_add_name_to_cycles.rb +31 -0
  190. data/db/migrate/20210226162824_rename_default_window.rb +5 -0
  191. data/db/migrate/20210302165058_add_task_to_window_groups.rb +7 -0
  192. data/db/migrate/20210304141111_create_invocation.rb +16 -0
  193. data/db/migrate/20210519163923_add_cycle_end_date.rb +29 -0
  194. data/db/migrate/20210525154113_expand_window_groups.rb +27 -0
  195. data/db/migrate/20210723160142_add_cycle_plan_task_group.rb +7 -0
  196. data/db/migrate/20210831160044_cycle_plan_start_correction.rb +5 -0
  197. data/db/migrate/20210907104645_rename_group_priority.rb +5 -0
  198. data/db/migrate/20210909130118_remove_old_references.rb +14 -0
  199. data/db/migrate/20210910141428_rename_round.rb +7 -0
  200. data/db/migrate/20210910163542_rename_plan.rb +8 -0
  201. data/db/migrate/20211014212415_round_group_reference.rb +9 -0
  202. data/db/migrate/20220105224803_add_group_label.rb +25 -0
  203. data/db/migrate/20220114153808_plan_add_name_generator.rb +5 -0
  204. data/db/migrate/20220117103808_remove_cycle_description.rb +5 -0
  205. data/db/migrate/20220406110705_add_window_state.rb +37 -0
  206. data/db/migrate/20220407161120_add_round_status.rb +9 -0
  207. data/db/migrate/20220902134800_add_invocation_status.rb +28 -0
  208. data/db/seeds.d/100-assign_features_with_templates.rb +16 -0
  209. data/db/seeds.d/160-mail_notifications.rb +38 -0
  210. data/db/seeds.d/75-job_templates.rb +16 -0
  211. data/lib/foreman_patch/engine.rb +87 -0
  212. data/lib/foreman_patch/plugin.rb +47 -0
  213. data/lib/foreman_patch/version.rb +3 -0
  214. data/lib/foreman_patch.rb +4 -0
  215. data/lib/tasks/foreman_patch_tasks.rake +47 -0
  216. data/locale/Makefile +60 -0
  217. data/locale/en/foreman_patch.po +19 -0
  218. data/locale/foreman_patch.pot +19 -0
  219. data/locale/gemspec.rb +2 -0
  220. data/package.json +35 -0
  221. data/public/assets/foreman_patch/cycle_plans-e5667e178ba389908f5c815b24ec0ea77c340849d56bc39c5ce72bb626bd446a.scss +6 -0
  222. data/public/assets/foreman_patch/cycle_plans-e5667e178ba389908f5c815b24ec0ea77c340849d56bc39c5ce72bb626bd446a.scss.gz +0 -0
  223. data/public/assets/foreman_patch/foreman_patch-ce5805a60c0d5f896f557ff5246e5a09172043004c850b39bea54e618df1c485.css +1 -0
  224. data/public/assets/foreman_patch/foreman_patch-ce5805a60c0d5f896f557ff5246e5a09172043004c850b39bea54e618df1c485.css.gz +0 -0
  225. data/public/assets/foreman_patch/foreman_patch.json +1 -0
  226. data/public/assets/foreman_patch/plan_edit_windows-e656ba411642a7f983b51958ab30ac49c056322d19295a603cff4d5e6c71c8ed.js +1 -0
  227. data/public/assets/foreman_patch/plan_edit_windows-e656ba411642a7f983b51958ab30ac49c056322d19295a603cff4d5e6c71c8ed.js.gz +0 -0
  228. data/public/webpack/foreman_patch/bundle-200e97f4e2ad9ed413ea.css +1 -0
  229. data/public/webpack/foreman_patch/bundle-200e97f4e2ad9ed413ea.css.gz +0 -0
  230. data/public/webpack/foreman_patch/bundle-200e97f4e2ad9ed413ea.js +6 -0
  231. data/public/webpack/foreman_patch/bundle-200e97f4e2ad9ed413ea.js.gz +0 -0
  232. data/public/webpack/foreman_patch/bundle-200e97f4e2ad9ed413ea.js.map +1 -0
  233. data/public/webpack/foreman_patch/bundle-200e97f4e2ad9ed413ea.js.map.gz +0 -0
  234. data/public/webpack/foreman_patch/foreman_patch-1e4f2d5e6f040a27aa7a.css +1 -0
  235. data/public/webpack/foreman_patch/foreman_patch-1e4f2d5e6f040a27aa7a.css.gz +0 -0
  236. data/public/webpack/foreman_patch/foreman_patch-1e4f2d5e6f040a27aa7a.js +6 -0
  237. data/public/webpack/foreman_patch/foreman_patch-1e4f2d5e6f040a27aa7a.js.gz +0 -0
  238. data/public/webpack/foreman_patch/foreman_patch-1e4f2d5e6f040a27aa7a.js.map +1 -0
  239. data/public/webpack/foreman_patch/foreman_patch-1e4f2d5e6f040a27aa7a.js.map.gz +0 -0
  240. data/public/webpack/foreman_patch/manifest.json +26 -0
  241. data/public/webpack/foreman_patch/manifest.json.gz +0 -0
  242. data/public/webpack/foreman_patch/vendor-4b77c91f1e9103179596.js +2 -0
  243. data/public/webpack/foreman_patch/vendor-4b77c91f1e9103179596.js.gz +0 -0
  244. data/public/webpack/foreman_patch/vendor-4b77c91f1e9103179596.js.map +1 -0
  245. data/public/webpack/foreman_patch/vendor-4b77c91f1e9103179596.js.map.gz +0 -0
  246. data/test/factories/foreman_patch_factories.rb +5 -0
  247. data/test/test_plugin_helper.rb +6 -0
  248. data/test/unit/foreman_patch_test.rb +11 -0
  249. data/webpack/components/Cycle/Cycle.js +57 -0
  250. data/webpack/components/Cycle/CycleActions.js +21 -0
  251. data/webpack/components/Cycle/CycleConstants.js +2 -0
  252. data/webpack/components/Cycle/CycleHelpers.js +3 -0
  253. data/webpack/components/Cycle/CycleSelectors.js +10 -0
  254. data/webpack/components/Cycle/Window.js +32 -0
  255. data/webpack/components/Cycle/index.js +41 -0
  256. data/webpack/components/Groups/Group.js +20 -0
  257. data/webpack/components/Groups/Groups.js +46 -0
  258. data/webpack/components/Groups/GroupsHelpers.js +11 -0
  259. data/webpack/components/Groups/Priority.js +51 -0
  260. data/webpack/components/Invocation/Invocation.js +47 -0
  261. data/webpack/components/Invocation/InvocationActions.js +8 -0
  262. data/webpack/components/Invocation/InvocationConsts.js +1 -0
  263. data/webpack/components/Invocation/InvocationSelectors.js +14 -0
  264. data/webpack/components/Invocation/index.js +36 -0
  265. data/webpack/components/Invocations/Invocations.js +55 -0
  266. data/webpack/components/Invocations/InvocationsConstants.js +1 -0
  267. data/webpack/components/Invocations/InvocationsHelpers.js +11 -0
  268. data/webpack/components/Invocations/InvocationsPage.js +66 -0
  269. data/webpack/components/Invocations/InvocationsPage.scss +3 -0
  270. data/webpack/components/Invocations/InvocationsSelectors.js +21 -0
  271. data/webpack/components/Invocations/components/InvocationItem.js +66 -0
  272. data/webpack/components/Invocations/components/InvocationStatus.js +51 -0
  273. data/webpack/components/Invocations/index.js +99 -0
  274. data/webpack/components/Plan/Plan.js +90 -0
  275. data/webpack/components/Plan/PlanActions.js +12 -0
  276. data/webpack/components/Plan/PlanConstants.js +1 -0
  277. data/webpack/components/Plan/PlanSelectors.js +9 -0
  278. data/webpack/components/Plan/Window.js +33 -0
  279. data/webpack/components/Plan/index.js +36 -0
  280. data/webpack/components/PlanWindow/PlanWindow.js +55 -0
  281. data/webpack/components/PlanWindow/index.js +32 -0
  282. data/webpack/components/RoundProgress/AggregateStatus.js +58 -0
  283. data/webpack/components/RoundProgress/RoundProgress.js +48 -0
  284. data/webpack/components/RoundProgress/RoundProgressActions.js +9 -0
  285. data/webpack/components/RoundProgress/RoundProgressConstants.js +1 -0
  286. data/webpack/components/RoundProgress/RoundProgressSelectors.js +24 -0
  287. data/webpack/components/RoundProgress/index.js +44 -0
  288. data/webpack/components/Rounds/Rounds.js +57 -0
  289. data/webpack/components/Rounds/RoundsActions.js +8 -0
  290. data/webpack/components/Rounds/RoundsConsts.js +1 -0
  291. data/webpack/components/Rounds/RoundsSelectors.js +14 -0
  292. data/webpack/components/Rounds/components/RoundItem.js +52 -0
  293. data/webpack/components/Rounds/components/RoundStatus.js +40 -0
  294. data/webpack/components/Rounds/index.js +37 -0
  295. data/webpack/components/common/Calendar/Calendar.js +86 -0
  296. data/webpack/components/common/Calendar/Calendar.scss +76 -0
  297. data/webpack/components/common/Calendar/CalendarConstants.js +1 -0
  298. data/webpack/components/common/Calendar/CalendarHelpers.js +77 -0
  299. data/webpack/components/common/Calendar/Day/index.js +9 -0
  300. data/webpack/components/common/Calendar/Event.js +25 -0
  301. data/webpack/components/common/Calendar/Month/Day.js +51 -0
  302. data/webpack/components/common/Calendar/Month/Header.js +77 -0
  303. data/webpack/components/common/Calendar/Month/Month.js +47 -0
  304. data/webpack/components/common/Calendar/Month/index.js +1 -0
  305. data/webpack/components/common/Calendar/View.js +20 -0
  306. data/webpack/components/common/Calendar/Week/index.js +13 -0
  307. data/webpack/components/common/Calendar/index.js +2 -0
  308. data/webpack/components/common/Terminal/OutputLine.js +26 -0
  309. data/webpack/components/common/Terminal/Terminal.js +115 -0
  310. data/webpack/components/common/Terminal/Terminal.scss +47 -0
  311. data/webpack/index.js +20 -0
  312. metadata +438 -0
@@ -0,0 +1,72 @@
1
+ module Actions
2
+ module ForemanPatch
3
+ module Window
4
+ class Patch < Actions::EntryAction
5
+ execution_plan_hooks.use :update_window_status, on: ::Dynflow::ExecutionPlan.states
6
+
7
+ def resource_locks
8
+ :link
9
+ end
10
+
11
+ def delay(delay_options, window)
12
+ window.task_id = task.id
13
+ window.save!
14
+
15
+ action_subject(window)
16
+
17
+ super delay_options, window
18
+ end
19
+
20
+ def plan(window)
21
+ window.task_id = task.id
22
+ window.save!
23
+
24
+ action_subject(window)
25
+
26
+ sequence do
27
+ window.rounds.group_by(&:priority).each do |_, groups|
28
+ concurrence do
29
+ groups.each do |group|
30
+ plan_action(Actions::ForemanPatch::Round::Patch, group)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ plan_self
36
+ end
37
+
38
+ def window
39
+ @window ||= ::ForemanPatch::Window.find(input[:window][:id])
40
+ end
41
+
42
+ def rescue_strategy_for_self
43
+ ::Dynflow::Action::Rescue::Fail
44
+ end
45
+
46
+ def humanized_name
47
+ if input and input[:window][:name]
48
+ _('Run Patch Window: %{window}' % {window: input[:window][:name]})
49
+ else
50
+ _('Run Patch Window')
51
+ end
52
+ end
53
+
54
+ def update_window_status(execution_plan)
55
+ return unless root_action?
56
+
57
+ case execution_plan.state
58
+ when 'scheduled'
59
+ window.status = execution_plan.state
60
+ when 'pending','planning','planned','running'
61
+ window.status = 'running'
62
+ when 'stopped'
63
+ window.status = 'completed'
64
+ else
65
+ window.status = execution_plan.state
66
+ end
67
+ window.save!
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,43 @@
1
+ module Actions
2
+ module ForemanPatch
3
+ module Window
4
+ class Plan < Actions::EntryAction
5
+
6
+ def plan(window_plan, cycle)
7
+ input.update serialize_args(window_plan: window_plan, cycle: cycle)
8
+
9
+ sequence do
10
+ action = plan_action(::Actions::ForemanPatch::Window::Create, params(window_plan, cycle))
11
+
12
+ concurrence do
13
+ window_plan.groups.each do |group|
14
+ plan_action(::Actions::ForemanPatch::Round::Plan, group, action.output[:window])
15
+ end
16
+ end
17
+
18
+ plan_action(::Actions::ForemanPatch::Window::Publish, action.output[:window])
19
+ end
20
+ end
21
+
22
+ def humanized_name
23
+ _('Plan window: %s') % input[:window_plan][:name]
24
+ end
25
+
26
+ private
27
+
28
+ def params(window_plan, cycle)
29
+ {
30
+ cycle: cycle,
31
+ name: window_plan.name,
32
+ description: window_plan.description,
33
+ start_at: window_plan.start_at.to_s,
34
+ end_by: window_plan.end_by.to_s,
35
+ }
36
+ end
37
+
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+
@@ -0,0 +1,32 @@
1
+ module Actions
2
+ module ForemanPatch
3
+ module Window
4
+ class Publish < Actions::EntryAction
5
+
6
+ def plan(window)
7
+ input.update serialize_args(window: window)
8
+ plan_self
9
+ end
10
+
11
+ def run
12
+ ticket = window.ticket
13
+
14
+ input.update(payload: ticket.payload.raw.compact)
15
+
16
+ ticket.save
17
+
18
+ output.update(response: ticket.response)
19
+ end
20
+
21
+ def window
22
+ @window ||= ::ForemanPatch::Window.find(input[:window][:id])
23
+ end
24
+
25
+ def humanized_name
26
+ _('Publish ticket for %s') % window.name
27
+ end
28
+
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,31 @@
1
+ module Actions
2
+ module ForemanPatch
3
+ module Window
4
+ class ResolveHosts < Actions::EntryAction
5
+
6
+ def plan(window)
7
+ input.update serialize_args(window: window)
8
+
9
+ sequence do
10
+ concurrence do
11
+ window.rounds.each do |round|
12
+ plan_action(Actions::ForemanPatch::Round::ResolveHosts, round)
13
+ end
14
+ end
15
+
16
+ plan_action(Actions::ForemanPatch::Window::Publish, window)
17
+ end
18
+ end
19
+
20
+ def window
21
+ @window ||= ::ForemanPatch::Window.find(input[:window][:id])
22
+ end
23
+
24
+ def humanized_name
25
+ _('Resolve Hosts for %s') % window.name
26
+ end
27
+
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ module Actions
2
+ module Helpers
3
+ module FailureNotification
4
+
5
+ def send_failure_notification
6
+ users = ::User.select { |user| user.receives?(:patch_invocation_failure) }.compact
7
+
8
+ MailNotification[:patch_invocation_failure].deliver(
9
+ users: users,
10
+ host: host,
11
+ output: live_output
12
+ ) unless users.blank?
13
+ rescue => error
14
+ message = _('Unable to send patch invocation failure: %{error}') % {error: error}
15
+ Rails.logger.error(message)
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,102 @@
1
+ module Actions
2
+ module Helpers
3
+ module WithFeatureAction
4
+ include ::Actions::Helpers::WithDelegatedAction
5
+
6
+ class TemplateInvocationInputValue
7
+ attr_reader :template_invocation, :template_input, :value
8
+
9
+ def initialize(invocation, input, value)
10
+ @template_invocation = invocation
11
+ @template_input = input
12
+ @value = value
13
+ end
14
+ end
15
+
16
+ class TemplateInvocation
17
+ attr_reader :template, :input_values
18
+
19
+ def initialize(template, **input_values)
20
+ @template = template
21
+
22
+ @input_values = template.template_inputs_with_foreign.map do |template_input|
23
+ TemplateInvocationInputValue.new(self, template_input, input_values[template_input.name.intern])
24
+ end
25
+ end
26
+
27
+ def effective_user
28
+ if template.provider.supports_effective_user?
29
+ Setting[:remote_execution_effective_user]
30
+ else
31
+ nil
32
+ end
33
+ end
34
+
35
+ end
36
+
37
+ def plan_feature_action(feature_name, host, **input_values)
38
+ input['feature_name'] = feature_name
39
+
40
+ invocation = TemplateInvocation.new(template, **input_values)
41
+
42
+ provider = template.provider
43
+ proxy_selector = provider.required_proxy_selector_for(template) || ::RemoteExecutionProxySelector.new
44
+
45
+ proxy = proxy_selector.determine_proxy(host, template.provider_type.to_s)
46
+
47
+ renderer = InputTemplateRenderer.new(template, host, invocation)
48
+ script = renderer.render
49
+ raise _('Failed rendering template: %s') % renderer.error_message unless script
50
+
51
+ additional_options = {
52
+ hostname: provider.find_ip_or_hostname(host),
53
+ execution_timeout_interval: template.execution_timeout_interval,
54
+ script: script,
55
+ secrets: provider.secrets(host),
56
+ }
57
+ action_options = provider.proxy_command_options(invocation, host).merge(additional_options)
58
+
59
+ plan_delegated_action(proxy, provider.proxy_action_class, action_options)
60
+ end
61
+
62
+ def exit_status
63
+ delegated_output[:exit_status]
64
+ end
65
+
66
+ def feature
67
+ @feature ||= ::RemoteExecutionFeature.feature(input['feature_name'])
68
+ end
69
+
70
+ def template
71
+ @template ||= feature.job_template
72
+ end
73
+
74
+ def live_output
75
+ continuous_output.sort!
76
+ continuous_output.raw_outputs
77
+ end
78
+
79
+ def continuous_output_providers
80
+ super << self
81
+ end
82
+
83
+ def fill_continuous_output(continuous_output)
84
+ delegated_output.fetch('result', []).each do |raw_output|
85
+ continuous_output.add_raw_output(raw_output)
86
+ end
87
+
88
+ final_timestamp = (continuous_output.last_timestamp || task.ended_at).to_f + 1
89
+
90
+ continuous_output.add_output(_('Exit status: %s') % exit_status, 'stdout', final_timestamp) if exit_status
91
+ end
92
+
93
+ def feature_action
94
+ delegated_action
95
+ end
96
+
97
+ end
98
+ end
99
+ end
100
+
101
+
102
+
@@ -0,0 +1,31 @@
1
+ module Actions
2
+ module Middleware
3
+ class CheckExitStatus < Dynflow::Middleware
4
+
5
+ def run(*args)
6
+ pass(*args)
7
+
8
+ if action.exit_status != 0
9
+ send_failure_notification
10
+
11
+ raise "Non-zero exit status"
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def send_failure_notification
18
+ users = ::Users.select { |user| user.receives?(:patch_invocation_failure) }.compact
19
+
20
+ begin
21
+ MailNotification[:patch_invocation_failure].deliver(users: users,
22
+ host: action.host,
23
+ output: action.live_output) unless users.blank?
24
+ rescue => error
25
+ message = _('Unable to send patch invocation failure: %{error}') % { error: error }
26
+ Rails.logger.error(message)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,17 @@
1
+ module ForemanPatch
2
+ class CycleMailer < ApplicationMailer
3
+ helper ForemanPatch::TicketHelper
4
+
5
+ def planned(options)
6
+ @user = options[:user]
7
+
8
+ @cycle = options[:cycle]
9
+
10
+ set_locale_for(@user) do
11
+ mail(to: @user.mail, subject: (_("Patching Cycle Planned")))
12
+ end
13
+ end
14
+
15
+ end
16
+ end
17
+
@@ -0,0 +1,41 @@
1
+ module ForemanPatch
2
+ class GroupMailer < ApplicationMailer
3
+
4
+ def initiated(options)
5
+ user = options[:user]
6
+
7
+ @group = options[:group].name
8
+ @hosts = options[:group].invocations.pluck(:name)
9
+
10
+ set_locale_for(user) do
11
+ mail(to: user.mail, subject: (_("%s Patching Initiated") % @group))
12
+ end
13
+ end
14
+
15
+ def completed(options)
16
+ user = options[:user]
17
+
18
+ @group = options[:group].name
19
+ @total = options[:group].invocations.count
20
+ @successes = options[:group].invocations.successful.pluck(:name)
21
+ @warnings = options[:group].invocations.warning.pluck(:name)
22
+ @failures = options[:group].invocations.failed.pluck(:name)
23
+
24
+ set_locale_for(user) do
25
+ mail(to: user.mail, subject: (_("%s Patching Completed") % @group))
26
+ end
27
+ end
28
+
29
+ def report(options)
30
+ user = options[:user]
31
+
32
+ @group = options[:group].name
33
+ @result = options[:result]
34
+
35
+ set_locale_for(user) do
36
+ mail(to: user.mail, subject: (_("%s Preliminary Report") % @group))
37
+ end
38
+ end
39
+ end
40
+ end
41
+
@@ -0,0 +1,19 @@
1
+ module ForemanPatch
2
+ class InvocationMailer < ApplicationMailer
3
+ add_template_helper JobInvocationOutputHelper
4
+ add_template_helper RemoteExecutionHelper
5
+
6
+ def failure(options)
7
+ user = options[:user]
8
+
9
+ @host = options[:host]
10
+ @output = options[:output]
11
+ @line_counter = 0
12
+
13
+ set_locale_for(user) do
14
+ mail(to: user.mail, subject: (_("Patching Failure for %s") % @host.name))
15
+ end
16
+ end
17
+ end
18
+ end
19
+
@@ -0,0 +1,35 @@
1
+ module ForemanPatch
2
+ module Concerns
3
+ module GroupFacetHostExtensions
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ has_one :group, through: :group_facet
8
+
9
+ scoped_search relation: :group, on: :name, complete_value: true, rename: :patch_group
10
+ scoped_search relation: :group_facet, on: :last_patched_at, complete_value: true, rename: :last_patched
11
+
12
+ accepts_nested_attributes_for(
13
+ :group_facet,
14
+ self.nested_attributes_options[:group_facet].merge(
15
+ reject_if: :group_facet_ignore_update?
16
+ )
17
+ )
18
+
19
+ def group_facet_ignore_update?(attributes)
20
+ self.group_facet.blank? && (
21
+ attributes.values.all?(&:blank?) ||
22
+ attributes['group_id'].blank?
23
+ )
24
+ end
25
+ end
26
+
27
+ module ClassMethods
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ class ::Host::Managed::Jail < Safemode::Jail
34
+ allow :group
35
+ end
@@ -0,0 +1,17 @@
1
+ module ForemanPatch
2
+ module Concerns
3
+ module HostManagedExtensions
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ has_many :invocations, -> { unscope(:order) }, class_name: 'ForemanPatch::Invocation', foreign_key: :host_id, dependent: :delete_all
8
+ has_many :rounds, class_name: 'ForemanPatch::Round', through: :invocations
9
+ has_many :windows, class_name: 'ForemanPatch::Window', through: :rounds
10
+
11
+ scoped_search relation: :rounds, on: :id, complete_value: false, rename: :patch_round_id
12
+ end
13
+
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,49 @@
1
+ module ForemanPatch
2
+ class Cycle < ::ApplicationRecord
3
+ include ForemanTasks::Concerns::ActionSubject
4
+
5
+ belongs_to :plan, class_name: 'ForemanPatch::Plan'
6
+
7
+ has_many :windows, -> { order(start_at: :asc) }, class_name: 'ForemanPatch::Window', foreign_key: :cycle_id, inverse_of: :cycle, dependent: :delete_all
8
+ has_many :rounds, through: :windows
9
+ has_many :tasks, through: :windows
10
+ has_many :hosts, through: :windows
11
+
12
+ scoped_search on: :name, complete_value: true
13
+ scoped_search on: :start_date, complete_value: false
14
+ scoped_search on: :end_date, complete_value: false
15
+ scoped_search on: :plan_id, complete_value: false
16
+ scoped_search relation: :plan, on: :name, complete_value: true, rename: :plan
17
+
18
+ validates :name, presence: true
19
+ validates :start_date, presence: true
20
+ validates :end_date, presence: true
21
+
22
+ scope :planned, -> { where('start_date > ?', Date.current) }
23
+ scope :active, -> { where('end_date >= ?', Date.current) }
24
+ scope :running, -> { where('? BETWEEN start_date AND end_date', Date.current) }
25
+ scope :completed, -> { where('end_date < ?', Date.current) }
26
+
27
+ def planned?
28
+ start_date > Date.current
29
+ end
30
+
31
+ def active?
32
+ end_date >= Date.current
33
+ end
34
+
35
+ def running?
36
+ start_date <= Date.current and end_date >= Date.current
37
+ end
38
+
39
+ def completed?
40
+ end_date < Date.current
41
+ end
42
+
43
+ class Jail < ::Safemode::Jail
44
+ allow :id, :name, :description, :start_date, :end_date, :windows
45
+ end
46
+
47
+ end
48
+ end
49
+
@@ -0,0 +1,43 @@
1
+ module ForemanPatch
2
+ class Group < ::ApplicationRecord
3
+ include Katello::Ext::LabelFromName
4
+ include ForemanTasks::Concerns::ActionSubject
5
+ extend FriendlyId
6
+ friendly_id :label
7
+
8
+ include Authorizable
9
+
10
+ belongs_to :default_window_plan, class_name: 'ForemanPatch::WindowPlan'
11
+
12
+ has_many :group_facets, class_name: 'ForemanPatch::Host::GroupFacet', foreign_key: :group_id, inverse_of: :group, dependent: :nullify
13
+ has_many :hosts, through: :group_facets
14
+
15
+ has_many :rounds, class_name: 'ForemanPatch::Round', foreign_key: :group_id, dependent: :nullify
16
+
17
+ validates_lengths_from_database except: [:label]
18
+ validates :name, presence: true, uniqueness: true
19
+ validates :label, uniqueness: true,
20
+ presence: true
21
+
22
+ validates_with Katello::Validators::KatelloNameFormatValidator, attributes: :name
23
+ validates_with Katello::Validators::KatelloLabelFormatValidator, attributes: :label
24
+
25
+ scoped_search on: :id, complete_value: false
26
+ scoped_search on: :name, complete_value: true
27
+ scoped_search on: :label, complete_value: true
28
+ scoped_search on: :default_window_plan_id, complete_value: true, rename: :default_window_id
29
+ scoped_search on: :priority, complete_value: true
30
+
31
+ scoped_search relation: :default_window_plan, on: :name, complete_value: true, rename: :default_window
32
+
33
+ def hosts_count
34
+ hosts.count
35
+ end
36
+
37
+ class Jail < Safemode::Jail
38
+ allow :id, :name, :label, :default_window_plan, :hosts
39
+ end
40
+
41
+ end
42
+ end
43
+
@@ -0,0 +1,13 @@
1
+ module ForemanPatch
2
+ module Host
3
+ class GroupFacet < ::ApplicationRecord
4
+ self.table_name = 'foreman_patch_group_facets'
5
+ include Facets::Base
6
+
7
+ belongs_to :group, class_name: '::ForemanPatch::Group', inverse_of: :group_facets
8
+
9
+ validates :host, presence: true, allow_blank: false
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,60 @@
1
+ module ForemanPatch
2
+ class Invocation < ::ApplicationRecord
3
+ include ForemanTasks::Concerns::ActionSubject
4
+
5
+ belongs_to :round, class_name: 'ForemanPatch::Round', inverse_of: :invocations
6
+ has_one :window, through: :round
7
+ has_one :cycle, through: :window
8
+
9
+ belongs_to :host, class_name: 'Host::Managed'
10
+
11
+ belongs_to :task, class_name: 'ForemanTasks::Task'
12
+
13
+ scope :planned, -> { where(status: 'planned') }
14
+ scope :pending, -> { where(status: 'pending') }
15
+ scope :running, -> { where(status: 'running') }
16
+ scope :successful, -> { where(status: 'success') }
17
+ scope :warning, -> { where(status: 'warning') }
18
+ scope :failed, -> { where(status: 'error') }
19
+ scope :cancelled, -> { where(status: 'cancelled') }
20
+ scope :completed, -> { where(status: ['success', 'warning', 'error', 'cancelled']) }
21
+
22
+ scope :in_windows, -> (*args) { joins(:window).where(foreman_patch_windows: { id: args.flatten }) }
23
+
24
+ scoped_search on: :status, complete_value: true
25
+ scoped_search relation: :host, on: :name, complete_value: true
26
+
27
+ default_scope { includes(:host).order('hosts.name') }
28
+
29
+ def phases
30
+ task&.main_action&.planned_actions || []
31
+ end
32
+
33
+ def complete?
34
+ ['success', 'warning', 'failed', 'cancelled'].include? status
35
+ end
36
+
37
+ def warning?
38
+ status == 'warning'
39
+ end
40
+
41
+ def failed?
42
+ status == 'error'
43
+ end
44
+
45
+ def success?
46
+ status == 'success'
47
+ end
48
+
49
+ def to_action_input
50
+ {
51
+ id: id,
52
+ name: host.name
53
+ }
54
+ end
55
+
56
+ class Jail < ::Safemode::Jail
57
+ allow :id, :host, :status
58
+ end
59
+ end
60
+ end