katello 3.18.0.rc2.1 → 4.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of katello might be problematic. Click here for more details.

Files changed (380) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/katello/katello.scss +0 -72
  3. data/app/controllers/katello/api/rhsm/candlepin_dynflow_proxy_controller.rb +0 -19
  4. data/app/controllers/katello/api/rhsm/candlepin_proxies_controller.rb +1 -3
  5. data/app/controllers/katello/api/v2/api_controller.rb +1 -2
  6. data/app/controllers/katello/api/v2/capsule_content_controller.rb +2 -2
  7. data/app/controllers/katello/api/v2/content_credentials_controller.rb +24 -24
  8. data/app/controllers/katello/api/v2/content_export_incrementals_controller.rb +98 -0
  9. data/app/controllers/katello/api/v2/content_exports_controller.rb +88 -0
  10. data/app/controllers/katello/api/v2/content_imports_controller.rb +59 -0
  11. data/app/controllers/katello/api/v2/content_view_filters_controller.rb +1 -1
  12. data/app/controllers/katello/api/v2/content_view_versions_controller.rb +56 -94
  13. data/app/controllers/katello/api/v2/content_views_controller.rb +2 -2
  14. data/app/controllers/katello/api/v2/host_errata_controller.rb +1 -1
  15. data/app/controllers/katello/api/v2/host_packages_controller.rb +6 -6
  16. data/app/controllers/katello/api/v2/host_subscriptions_controller.rb +2 -3
  17. data/app/controllers/katello/api/v2/hosts_bulk_actions_controller.rb +3 -2
  18. data/app/controllers/katello/api/v2/repositories_controller.rb +5 -19
  19. data/app/controllers/katello/api/v2/simple_content_access_controller.rb +34 -0
  20. data/app/controllers/katello/api/v2/subscriptions_controller.rb +1 -1
  21. data/app/controllers/katello/api/v2/upstream_subscriptions_controller.rb +8 -4
  22. data/app/controllers/katello/concerns/authorization/api/v2/content_views_controller.rb +1 -1
  23. data/app/helpers/katello/sync_management_helper.rb +0 -2
  24. data/app/lib/actions/candlepin/environment/create.rb +1 -1
  25. data/app/lib/actions/candlepin/environment/set_content.rb +1 -1
  26. data/app/lib/actions/katello/activation_key/create.rb +9 -11
  27. data/app/lib/actions/katello/agent/dispatch_history_presenter.rb +64 -0
  28. data/app/lib/actions/katello/agent_action.rb +107 -0
  29. data/app/lib/actions/katello/applicability/hosts/bulk_generate.rb +6 -2
  30. data/app/lib/actions/katello/bulk_agent_action.rb +21 -0
  31. data/app/lib/actions/katello/capsule_content/sync.rb +8 -8
  32. data/app/lib/actions/katello/capsule_content/sync_capsule.rb +16 -2
  33. data/app/lib/actions/katello/check_matching_content.rb +17 -0
  34. data/app/lib/actions/katello/content_view/environment_create.rb +6 -8
  35. data/app/lib/actions/katello/content_view/promote_to_environment.rb +1 -1
  36. data/app/lib/actions/katello/content_view/publish.rb +2 -2
  37. data/app/lib/actions/katello/content_view_version/import.rb +2 -1
  38. data/app/lib/actions/katello/content_view_version/import_library.rb +17 -0
  39. data/app/lib/actions/katello/content_view_version/incremental_update.rb +30 -10
  40. data/app/lib/actions/katello/host/erratum/applicable_errata_install.rb +1 -1
  41. data/app/lib/actions/katello/host/erratum/install.rb +8 -26
  42. data/app/lib/actions/katello/host/hypervisors_update.rb +4 -4
  43. data/app/lib/actions/katello/host/package/install.rb +8 -21
  44. data/app/lib/actions/katello/host/package/remove.rb +8 -20
  45. data/app/lib/actions/katello/host/package/update.rb +9 -22
  46. data/app/lib/actions/katello/host/package_group/install.rb +8 -21
  47. data/app/lib/actions/katello/host/package_group/remove.rb +8 -20
  48. data/app/lib/actions/katello/host/update_system_purpose.rb +1 -1
  49. data/app/lib/actions/katello/organization/create.rb +3 -5
  50. data/app/lib/actions/katello/organization/destroy.rb +1 -1
  51. data/app/lib/actions/katello/organization/manifest_delete.rb +3 -5
  52. data/app/lib/actions/katello/organization/manifest_import.rb +1 -1
  53. data/app/lib/actions/katello/organization/manifest_refresh.rb +1 -1
  54. data/app/lib/actions/katello/repository/check_matching_content.rb +3 -1
  55. data/app/lib/actions/katello/repository/clone_contents.rb +8 -11
  56. data/app/lib/actions/katello/repository/create.rb +0 -8
  57. data/app/lib/actions/katello/repository/filtered_index_content.rb +3 -0
  58. data/app/lib/actions/katello/repository/index_content.rb +1 -0
  59. data/app/lib/actions/katello/repository/multi_clone_contents.rb +9 -12
  60. data/app/lib/actions/katello/repository/update.rb +0 -8
  61. data/app/lib/actions/middleware/execute_if_contents_changed.rb +4 -1
  62. data/app/lib/actions/middleware/record_smart_proxy_sync_history.rb +24 -4
  63. data/app/lib/actions/pulp/consumer.rb +0 -11
  64. data/app/lib/actions/pulp/orchestration/repository/refresh_repos.rb +0 -6
  65. data/app/lib/actions/pulp3/capsule_content/refresh_distribution.rb +3 -3
  66. data/app/lib/actions/pulp3/content_migration.rb +10 -0
  67. data/app/lib/actions/pulp3/content_migration_presenter.rb +59 -0
  68. data/app/lib/actions/pulp3/content_view/delete_repository_references.rb +1 -1
  69. data/app/lib/actions/pulp3/content_view_version/export.rb +3 -2
  70. data/app/lib/actions/pulp3/import_migration.rb +6 -1
  71. data/app/lib/actions/pulp3/orchestration/content_view_version/copy_version_units_to_library.rb +2 -1
  72. data/app/lib/actions/pulp3/orchestration/content_view_version/export.rb +17 -13
  73. data/app/lib/actions/pulp3/orchestration/content_view_version/export_library.rb +60 -0
  74. data/app/lib/actions/pulp3/orchestration/content_view_version/import.rb +0 -4
  75. data/app/lib/actions/pulp3/orchestration/repository/import_upload.rb +16 -3
  76. data/app/lib/actions/pulp3/orchestration/repository/refresh_repos.rb +1 -6
  77. data/app/lib/actions/pulp3/repository/copy_content.rb +1 -1
  78. data/app/lib/actions/pulp3/repository/delete.rb +1 -1
  79. data/app/lib/actions/pulp3/repository/save_version.rb +1 -1
  80. data/app/lib/actions/pulp3/repository/upload_tag.rb +18 -0
  81. data/app/lib/katello/agent/base_message.rb +38 -0
  82. data/app/lib/katello/agent/client_message_handler.rb +60 -0
  83. data/app/lib/katello/agent/connection.rb +24 -0
  84. data/app/lib/katello/agent/install_errata_message.rb +25 -0
  85. data/app/lib/katello/agent/install_package_group_message.rb +25 -0
  86. data/app/lib/katello/agent/install_package_message.rb +28 -0
  87. data/app/lib/katello/agent/remove_package_group_message.rb +25 -0
  88. data/app/lib/katello/agent/remove_package_message.rb +28 -0
  89. data/app/lib/katello/agent/update_package_message.rb +25 -0
  90. data/app/lib/katello/concerns/base_template_scope_extensions.rb +8 -0
  91. data/app/lib/katello/event_daemon/monitor.rb +53 -0
  92. data/app/lib/katello/event_daemon/runner.rb +99 -0
  93. data/app/lib/katello/event_daemon/services/agent_event_receiver.rb +62 -0
  94. data/app/lib/katello/logging.rb +32 -0
  95. data/app/lib/katello/messaging/connection.rb +1 -7
  96. data/app/lib/katello/messaging/received_message.rb +1 -1
  97. data/app/lib/katello/qpid/connection.rb +130 -0
  98. data/app/lib/katello/validators/content_view_puppet_module_validator.rb +1 -1
  99. data/app/models/katello/activation_key.rb +2 -2
  100. data/app/models/katello/agent/dispatch_history.rb +17 -0
  101. data/app/models/katello/authorization/content_view_version.rb +25 -2
  102. data/app/models/katello/authorization/content_view_version_export_history.rb +1 -1
  103. data/app/models/katello/authorization/organization.rb +8 -0
  104. data/app/models/katello/candlepin/repository_mapper.rb +1 -1
  105. data/app/models/katello/concerns/host_managed_extensions.rb +3 -0
  106. data/app/models/katello/concerns/operatingsystem_extensions.rb +2 -0
  107. data/app/models/katello/concerns/organization_extensions.rb +2 -2
  108. data/app/models/katello/concerns/pulp_database_unit.rb +7 -0
  109. data/app/models/katello/concerns/redhat_extensions.rb +2 -2
  110. data/app/models/katello/concerns/smart_proxy_extensions.rb +31 -5
  111. data/app/models/katello/content_migration_progress.rb +4 -0
  112. data/app/models/katello/content_view.rb +10 -1
  113. data/app/models/katello/content_view_environment.rb +2 -2
  114. data/app/models/katello/content_view_history.rb +2 -1
  115. data/app/models/katello/content_view_package_filter.rb +1 -1
  116. data/app/models/katello/content_view_puppet_environment.rb +2 -2
  117. data/app/models/katello/content_view_version.rb +2 -1
  118. data/app/models/katello/content_view_version_export_history.rb +26 -1
  119. data/app/models/katello/erratum.rb +3 -1
  120. data/app/models/katello/events/delete_host_agent_queue.rb +19 -0
  121. data/app/models/katello/glue/candlepin/pool.rb +2 -0
  122. data/app/models/katello/glue/pulp/repo.rb +0 -6
  123. data/app/models/katello/glue/pulp/repos.rb +1 -22
  124. data/app/models/katello/host/subscription_facet.rb +4 -0
  125. data/app/models/katello/ping.rb +12 -4
  126. data/app/models/katello/pool.rb +5 -0
  127. data/app/models/katello/product.rb +3 -3
  128. data/app/models/katello/repository.rb +10 -3
  129. data/app/models/katello/subscription_status.rb +3 -2
  130. data/app/models/setting/content.rb +0 -2
  131. data/app/presenters/katello/host_subscription_presenter.rb +3 -4
  132. data/app/presenters/katello/host_subscriptions_presenter.rb +24 -0
  133. data/app/services/katello/agent/dispatcher.rb +66 -0
  134. data/app/services/katello/applicability/applicable_content_helper.rb +44 -15
  135. data/app/services/katello/candlepin_event_listener.rb +12 -19
  136. data/app/services/katello/event_monitor/poller_thread.rb +3 -11
  137. data/app/services/katello/pulp/smart_proxy_repository.rb +0 -15
  138. data/app/services/katello/pulp3/api/docker.rb +4 -0
  139. data/app/services/katello/pulp3/content_view_version/export.rb +63 -5
  140. data/app/services/katello/pulp3/content_view_version/import.rb +40 -0
  141. data/app/services/katello/pulp3/content_view_version/import_export_common.rb +0 -16
  142. data/app/services/katello/pulp3/content_view_version/import_validator.rb +26 -49
  143. data/app/services/katello/pulp3/docker_manifest.rb +1 -0
  144. data/app/services/katello/pulp3/docker_tag.rb +1 -0
  145. data/app/services/katello/pulp3/migration.rb +44 -9
  146. data/app/services/katello/pulp3/repository.rb +13 -4
  147. data/app/services/katello/pulp3/repository/docker.rb +5 -0
  148. data/app/services/katello/pulp3/repository/yum.rb +15 -9
  149. data/app/services/katello/pulp3/task.rb +4 -0
  150. data/app/services/katello/pulp3/task_group.rb +4 -0
  151. data/app/services/katello/registration_manager.rb +10 -0
  152. data/app/services/katello/repository_type.rb +1 -1
  153. data/app/views/foreman/smart_proxies/_content_tab.html.erb +4 -47
  154. data/app/views/foreman/smart_proxies/show.html.erb +1 -1
  155. data/app/views/katello/api/v2/capsule_content/sync_status.json.rabl +22 -25
  156. data/app/views/katello/api/v2/content_view_version_export_histories/show.json.rabl +1 -0
  157. data/app/views/katello/api/v2/content_views/show.json.rabl +6 -0
  158. data/app/views/katello/api/v2/organizations/show.json.rabl +7 -9
  159. data/app/views/katello/layouts/react.html.erb +3 -2
  160. data/app/views/katello/sync_management/_products.html.erb +1 -1
  161. data/app/views/overrides/activation_keys/_host_tab_pane.html.erb +1 -5
  162. data/app/views/overrides/organizations/_edit_override.html.erb +1 -4
  163. data/app/views/overrides/smart_proxies/_environment_tab.html.erb +1 -1
  164. data/app/views/overrides/smart_proxies/_environment_tab_pane.html.erb +1 -1
  165. data/config/katello.yaml.example +0 -3
  166. data/config/routes/api/v2.rb +31 -13
  167. data/db/migrate/20150930183738_migrate_content_hosts.rb +1 -1
  168. data/db/migrate/20191204214919_add_content_view_version_counts.rb +0 -1
  169. data/db/migrate/20200514092553_move_katello_fields_from_hostgroups.katello.rb +5 -2
  170. data/db/migrate/20201119211133_pulp3_migration_progress.rb +9 -0
  171. data/db/migrate/20210119162528_delete_puppet_and_ostree_repos.rb +56 -0
  172. data/db/migrate/20210122200618_create_katello_agent_dispatch_history.rb +11 -0
  173. data/db/migrate/20210125161911_delete_erratum_install_batch_size_setting.rb +5 -0
  174. data/db/migrate/20210128231228_add_type_and_from_cvv_to_cvv_export_history.rb +14 -0
  175. data/db/migrate/20210201163238_migrate_background_download_policy_to_migrate.rb +7 -0
  176. data/db/migrate/20210208213920_add_available_module_stream_context.rb +8 -0
  177. data/db/seeds.d/104-proxy.rb +1 -1
  178. data/db/seeds.d/111-upgrade_tasks.rb +2 -1
  179. data/engines/bastion/app/assets/javascripts/bastion/auth/authorization.service.js +1 -1
  180. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/capsule-content/capsule-content.controller.js +1 -1
  181. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/common/views/katello-agent-notice.html +1 -1
  182. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/views/content-hosts-bulk-system-purpose-modal.html +35 -40
  183. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content-host-register-os-client.directive.js +17 -0
  184. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-info.html +2 -2
  185. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/content-hosts.html +2 -2
  186. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/register-client.html +12 -5
  187. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/register-deb-client.html +38 -0
  188. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/register-oracle-client.html +5 -0
  189. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/register-sles-client.html +28 -0
  190. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/register.html +14 -11
  191. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/deletion/content-view-version-deletion-activation-keys.controller.js +8 -3
  192. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/deletion/content-view-version-deletion-content-hosts.controller.js +9 -3
  193. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/details/filters/views/package-filter-details.html +2 -2
  194. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/details/views/content-view-details.html +1 -1
  195. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/details/views/content-view-publish.html +4 -0
  196. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/bastion_katello.pot +78 -7
  197. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/de.po +17 -20
  198. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/es.po +17 -24
  199. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/fr.po +1292 -1170
  200. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/it.po +17 -20
  201. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ja.po +858 -807
  202. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ko.po +18 -19
  203. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pt_BR.po +17 -24
  204. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ru.po +17 -18
  205. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_CN.po +986 -971
  206. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_TW.po +19 -20
  207. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/translations.js +9 -9
  208. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/repository-details-info.controller.js +2 -2
  209. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-info.html +1 -1
  210. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/download-policy.service.js +0 -1
  211. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/views/new-repository.html +1 -1
  212. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/products.controller.js +2 -2
  213. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/subscriptions/subscription-start-date.directive.js +21 -0
  214. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/subscriptions/subscription-type.directive.js +16 -0
  215. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/subscriptions/views/subscription-start-date.html +2 -0
  216. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/subscriptions/views/subscription-type.html +18 -0
  217. data/lib/katello/engine.rb +12 -6
  218. data/lib/katello/middleware/event_daemon.rb +1 -1
  219. data/lib/katello/permission_creator.rb +26 -5
  220. data/lib/katello/plugin.rb +3 -2
  221. data/lib/katello/tasks/delete_orphaned_content.rake +1 -3
  222. data/lib/katello/tasks/jenkins.rake +1 -1
  223. data/lib/katello/tasks/pulp3_content_switchover.rake +1 -1
  224. data/lib/katello/tasks/pulp3_migration.rake +18 -6
  225. data/lib/katello/tasks/pulp3_migration_abort.rake +7 -2
  226. data/lib/katello/tasks/pulp3_migration_stats.rake +28 -8
  227. data/lib/katello/tasks/pulp3_post_migration_check.rake +1 -3
  228. data/lib/katello/tasks/receptor/extract_orgs.rake +1 -1
  229. data/lib/katello/tasks/reimport.rake +1 -1
  230. data/lib/katello/tasks/repository.rake +3 -5
  231. data/lib/katello/tasks/reset.rake +0 -15
  232. data/lib/katello/tasks/upgrades/4.0/remove_ostree_puppet_content.rake +16 -0
  233. data/lib/katello/version.rb +1 -1
  234. data/lib/proxy_api/container_gateway.rb +21 -0
  235. data/locale/action_names.rb +51 -51
  236. data/locale/bn/katello.edit.po +8538 -0
  237. data/locale/bn/katello.po +136 -51
  238. data/locale/bn/katello.po.time_stamp +0 -0
  239. data/locale/cs/katello.edit.po +8440 -0
  240. data/locale/cs/katello.po +136 -49
  241. data/locale/cs/katello.po.time_stamp +0 -0
  242. data/locale/de/katello.edit.po +8344 -0
  243. data/locale/de/katello.po +136 -48
  244. data/locale/de/katello.po.time_stamp +0 -0
  245. data/locale/en/katello.edit.po +8161 -0
  246. data/locale/en/katello.po +136 -48
  247. data/locale/en/katello.po.time_stamp +0 -0
  248. data/locale/es/katello.edit.po +8306 -0
  249. data/locale/es/katello.po +136 -48
  250. data/locale/es/katello.po.time_stamp +0 -0
  251. data/locale/fr/katello.edit.po +8356 -0
  252. data/locale/fr/katello.po +136 -48
  253. data/locale/fr/katello.po.time_stamp +0 -0
  254. data/locale/gu/katello.edit.po +8540 -0
  255. data/locale/gu/katello.po +136 -51
  256. data/locale/gu/katello.po.time_stamp +0 -0
  257. data/locale/hi/katello.edit.po +8537 -0
  258. data/locale/hi/katello.po +136 -51
  259. data/locale/hi/katello.po.time_stamp +0 -0
  260. data/locale/it/katello.edit.po +8293 -0
  261. data/locale/it/katello.po +136 -48
  262. data/locale/it/katello.po.time_stamp +0 -0
  263. data/locale/ja/katello.edit.po +8322 -0
  264. data/locale/ja/katello.po +136 -48
  265. data/locale/ja/katello.po.time_stamp +0 -0
  266. data/locale/katello.pot +941 -767
  267. data/locale/kn/katello.edit.po +8538 -0
  268. data/locale/kn/katello.po +136 -51
  269. data/locale/kn/katello.po.time_stamp +0 -0
  270. data/locale/ko/katello.edit.po +8289 -0
  271. data/locale/ko/katello.po +136 -48
  272. data/locale/ko/katello.po.time_stamp +0 -0
  273. data/locale/mr/katello.edit.po +8502 -0
  274. data/locale/mr/katello.po +136 -51
  275. data/locale/mr/katello.po.time_stamp +0 -0
  276. data/locale/or/katello.edit.po +8538 -0
  277. data/locale/or/katello.po +136 -51
  278. data/locale/or/katello.po.time_stamp +0 -0
  279. data/locale/pa/katello.edit.po +8524 -0
  280. data/locale/pa/katello.po +136 -51
  281. data/locale/pa/katello.po.time_stamp +0 -0
  282. data/locale/pt/katello.edit.po +8255 -0
  283. data/locale/pt/katello.po +136 -51
  284. data/locale/pt/katello.po.time_stamp +0 -0
  285. data/locale/pt_BR/katello.edit.po +8289 -0
  286. data/locale/pt_BR/katello.po +136 -48
  287. data/locale/pt_BR/katello.po.time_stamp +0 -0
  288. data/locale/ru/katello.edit.po +8309 -0
  289. data/locale/ru/katello.po +136 -48
  290. data/locale/ru/katello.po.time_stamp +0 -0
  291. data/locale/ta/katello.edit.po +8536 -0
  292. data/locale/ta/katello.po +136 -51
  293. data/locale/ta/katello.po.time_stamp +0 -0
  294. data/locale/te/katello.edit.po +8536 -0
  295. data/locale/te/katello.po +136 -51
  296. data/locale/te/katello.po.time_stamp +0 -0
  297. data/locale/zh_CN/katello.edit.po +8288 -0
  298. data/locale/zh_CN/katello.po +136 -48
  299. data/locale/zh_CN/katello.po.time_stamp +0 -0
  300. data/locale/zh_TW/katello.edit.po +8420 -0
  301. data/locale/zh_TW/katello.po +136 -48
  302. data/locale/zh_TW/katello.po.time_stamp +0 -0
  303. data/package.json +1 -1
  304. data/webpack/__mocks__/foremanReact/Root/Context/ForemanContext.js +0 -1
  305. data/webpack/__mocks__/foremanReact/components/Pagination/PaginationHooks.js +2 -0
  306. data/webpack/__mocks__/foremanReact/components/common/dates/LongDateTime.js +5 -0
  307. data/webpack/{scenes/ContentViews/Details/Repositories → components/SelectableDropdown}/SelectableDropdown.js +20 -3
  308. data/webpack/components/SelectableDropdown/__tests__/SelectableDropdown.test.js +45 -0
  309. data/webpack/components/SelectableDropdown/index.js +3 -0
  310. data/webpack/components/Table/TableWrapper.js +2 -1
  311. data/webpack/components/Table/helpers.js +14 -0
  312. data/webpack/components/TypeAhead/TypeAhead.js +2 -1
  313. data/webpack/components/TypeAhead/pf3Search/TypeAheadSearch.js +2 -1
  314. data/webpack/components/TypeAhead/pf4Search/TypeAheadSearch.js +0 -1
  315. data/webpack/containers/Application/overrides.scss +6 -0
  316. data/webpack/index.js +6 -0
  317. data/webpack/redux/actions/RedHatRepositories/helpers.js +5 -5
  318. data/webpack/scenes/ContentViews/ContentViewsActions.js +31 -2
  319. data/webpack/scenes/ContentViews/ContentViewsConstants.js +5 -1
  320. data/webpack/scenes/ContentViews/Copy/ContentViewCopySelectors.js +16 -0
  321. data/webpack/scenes/ContentViews/Copy/CopyContentViewForm.js +77 -0
  322. data/webpack/scenes/ContentViews/Copy/CopyContentViewModal.js +44 -0
  323. data/webpack/scenes/ContentViews/Copy/__tests__/contentViewCopyResult.fixtures.json +42 -0
  324. data/webpack/scenes/ContentViews/Copy/__tests__/copyContentView.test.js +39 -0
  325. data/webpack/scenes/ContentViews/Copy/index.js +4 -0
  326. data/webpack/scenes/ContentViews/Create/ContentViewCreateSelectors.js +16 -0
  327. data/webpack/scenes/ContentViews/Create/ContentViewFormComponents.js +58 -0
  328. data/webpack/scenes/ContentViews/Create/CreateContentViewForm.js +175 -0
  329. data/webpack/scenes/ContentViews/Create/CreateContentViewModal.js +27 -0
  330. data/webpack/scenes/ContentViews/Create/__tests__/contentViewCreateResult.fixtures.json +42 -0
  331. data/webpack/scenes/ContentViews/Create/__tests__/createContentView.test.js +92 -0
  332. data/webpack/scenes/ContentViews/Create/index.js +4 -0
  333. data/webpack/scenes/ContentViews/Details/ContentViewDetailActions.js +16 -0
  334. data/webpack/scenes/ContentViews/Details/ContentViewDetailSelectors.js +20 -1
  335. data/webpack/scenes/ContentViews/Details/ContentViewDetails.js +17 -7
  336. data/webpack/scenes/ContentViews/Details/ContentViewInfo.js +19 -13
  337. data/webpack/scenes/ContentViews/Details/Filters/ContentType.js +40 -0
  338. data/webpack/scenes/ContentViews/Details/Filters/ContentViewFilters.js +124 -0
  339. data/webpack/scenes/ContentViews/Details/Filters/__tests__/contentViewFilters.fixtures.json +134 -0
  340. data/webpack/scenes/ContentViews/Details/Filters/__tests__/contentViewFilters.test.js +92 -0
  341. data/webpack/scenes/ContentViews/Details/Repositories/ContentViewRepositories.js +44 -25
  342. data/webpack/scenes/ContentViews/Details/Repositories/__tests__/contentViewDetailRepos.test.js +17 -7
  343. data/webpack/scenes/ContentViews/Details/__tests__/contentViewDetail.test.js +24 -0
  344. data/webpack/scenes/ContentViews/Table/ContentViewsTable.js +53 -3
  345. data/webpack/scenes/ContentViews/Table/tableDataGenerator.js +4 -3
  346. data/webpack/scenes/ContentViews/__tests__/contentViewPage.test.js +41 -0
  347. data/webpack/scenes/ContentViews/helpers.js +13 -0
  348. data/webpack/scenes/SmartProxy/Content.js +17 -0
  349. data/webpack/scenes/SmartProxy/SmartProxyContentActions.js +11 -0
  350. data/webpack/scenes/SmartProxy/SmartProxyContentConstants.js +3 -0
  351. data/webpack/scenes/SmartProxy/SmartProxyContentSelectors.js +16 -0
  352. data/webpack/scenes/SmartProxy/SmartProxyContentTable.js +152 -0
  353. data/webpack/scenes/SmartProxy/__tests__/SmartProxyContentResult.fixtures.json +140 -0
  354. data/webpack/scenes/SmartProxy/__tests__/SmartProxyContentTest.js +38 -0
  355. data/webpack/scenes/SmartProxy/index.js +4 -0
  356. data/webpack/scenes/Subscriptions/Manifest/ManifestActions.js +3 -3
  357. data/webpack/scenes/Subscriptions/Manifest/__tests__/ManifestActions.test.js +2 -2
  358. data/webpack/scenes/Subscriptions/Manifest/__tests__/SimpleContentAccess.test.js +2 -2
  359. data/webpack/test-utils/react-testing-lib-wrapper.js +5 -2
  360. data/webpack/utils/helpers.js +3 -0
  361. metadata +160 -40
  362. data/app/controllers/katello/api/v2/gpg_keys_controller.rb +0 -114
  363. data/app/lib/actions/pulp/consumer/abstract_content_action.rb +0 -71
  364. data/app/lib/actions/pulp/consumer/content_install.rb +0 -43
  365. data/app/lib/actions/pulp/consumer/content_uninstall.rb +0 -26
  366. data/app/lib/actions/pulp/consumer/content_update.rb +0 -32
  367. data/app/overrides/disable_turbolinks_on_proxies_index.rb +0 -5
  368. data/app/services/katello/event_daemon.rb +0 -135
  369. data/app/services/katello/pulp/content_counts_calculator.rb +0 -60
  370. data/db/functions/empty_v01.sql +0 -7
  371. data/db/functions/evr_trigger_v01.sql +0 -9
  372. data/db/functions/isalpha_v01.sql +0 -11
  373. data/db/functions/isalphanum_v01.sql +0 -12
  374. data/db/functions/isdigit_v01.sql +0 -10
  375. data/db/functions/rpmver_array_v01.sql +0 -60
  376. data/lib/katello/tasks/common.rake +0 -7
  377. data/lib/katello/tasks/reports.rake +0 -4
  378. data/lib/katello/tasks/upgrades/3.10/update_gpg_key_urls.rake +0 -32
  379. data/webpack/components/TypeAhead/pf4Search/TypeAheadSearch.scss +0 -5
  380. data/webpack/scenes/ContentViews/Table/actionResolver.js +0 -28
@@ -0,0 +1,34 @@
1
+ module Katello
2
+ class Api::V2::SimpleContentAccessController < Api::V2::ApiController
3
+ before_action :find_organization
4
+ before_action :check_upstream_connection
5
+
6
+ resource_description do
7
+ description "Red Hat subscriptions management platform."
8
+ api_version 'v2'
9
+ end
10
+
11
+ api :GET, "/organizations/:organization_id/simple_content_access/eligible",
12
+ N_("Check if the specified organization is eligible for Simple Content Access")
13
+ def eligible
14
+ eligible = @organization.upstream_consumer.simple_content_access_eligible?
15
+ render json: { simple_content_access_eligible: eligible }
16
+ end
17
+
18
+ api :PUT, "/organizations/:organization_id/simple_content_access/enable",
19
+ N_("Enable simple content access for a manifest")
20
+ param :organization_id, :number, :desc => N_("Organization ID"), :required => true
21
+ def enable
22
+ task = async_task(::Actions::Katello::Organization::SimpleContentAccess::Enable, params[:organization_id])
23
+ respond_for_async :resource => task
24
+ end
25
+
26
+ api :PUT, "/organizations/:organization_id/simple_content_access/disable",
27
+ N_("Disable simple content access for a manifest")
28
+ param :organization_id, :number, :desc => N_("Organization ID"), :required => true
29
+ def disable
30
+ task = async_task(::Actions::Katello::Organization::SimpleContentAccess::Disable, params[:organization_id])
31
+ respond_for_async :resource => task
32
+ end
33
+ end
34
+ end
@@ -41,7 +41,7 @@ module Katello
41
41
  :start_date, :end_date, :available, :quantity, :account_number, :contract_number,
42
42
  :support_level, :ram, :stacking_id, :multi_entitlement, :type, :product_id,
43
43
  :unmapped_guest, :virt_only, :virt_who, :upstream?],
44
- ['Pool Id', 'Subscription Id', 'Name', 'Candlepin Id', 'Organization Id',
44
+ ['Pool Id Number', 'Subscription Id', 'Name', 'Pool Id', 'Organization Id',
45
45
  'Sockets', 'Cores', 'Start Date', 'End Date', 'Available', 'Quantity', 'Account Number',
46
46
  'Contract Number', 'Support Level', 'RAM', 'Stacking Id', 'Multi Entitlement', 'Type',
47
47
  'Product Id', 'Unmapped Guest', 'Virt Only', 'Requires Virt Who', 'Upstream'])
@@ -2,7 +2,7 @@ module Katello
2
2
  class Api::V2::UpstreamSubscriptionsController < Api::V2::ApiController
3
3
  before_action :find_organization
4
4
  before_action :check_upstream_connection
5
-
5
+ before_action :deprecated, only: [:simple_content_access_eligible, :enable_simple_content_access, :disable_simple_content_access]
6
6
  resource_description do
7
7
  description "Red Hat subscriptions management platform."
8
8
  api_version 'v2'
@@ -78,14 +78,14 @@ module Katello
78
78
  end
79
79
 
80
80
  api :GET, "/organizations/:organization_id/upstream_subscriptions/simple_content_access/eligible",
81
- N_("Check if the specified organization is eligible for Simple Content Access")
81
+ N_("Check if the specified organization is eligible for Simple Content Access"), :deprecated => true
82
82
  def simple_content_access_eligible
83
83
  eligible = @organization.upstream_consumer.simple_content_access_eligible?
84
84
  render json: { simple_content_access_eligible: eligible }
85
85
  end
86
86
 
87
87
  api :PUT, "/organizations/:organization_id/upstream_subscriptions/simple_content_access/enable",
88
- N_("Enable simple content access for a manifest")
88
+ N_("Enable simple content access for a manifest"), :deprecated => true
89
89
  param :organization_id, :number, :desc => N_("Organization ID"), :required => true
90
90
  def enable_simple_content_access
91
91
  task = async_task(::Actions::Katello::Organization::SimpleContentAccess::Enable, params[:organization_id])
@@ -93,7 +93,7 @@ module Katello
93
93
  end
94
94
 
95
95
  api :PUT, "/organizations/:organization_id/upstream_subscriptions/simple_content_access/disable",
96
- N_("Disable simple content access for a manifest")
96
+ N_("Disable simple content access for a manifest"), :deprecated => true
97
97
  param :organization_id, :number, :desc => N_("Organization ID"), :required => true
98
98
  def disable_simple_content_access
99
99
  task = async_task(::Actions::Katello::Organization::SimpleContentAccess::Disable, params[:organization_id])
@@ -124,5 +124,9 @@ module Katello
124
124
  { "pool" => pool[:id], "quantity" => pool[:quantity] } if pool
125
125
  end
126
126
  end
127
+
128
+ def deprecated
129
+ ::Foreman::Deprecation.api_deprecation_warning("This will be removed in Katello 4.2, Please see /api/v2/simple_content_access")
130
+ end
127
131
  end
128
132
  end
@@ -107,7 +107,7 @@ module Katello
107
107
  true
108
108
  end
109
109
 
110
- def authorize_remove_environments(view, options)
110
+ def authorize_remove_environments(view, options) # rubocop:disable Metrics/CyclomaticComplexity
111
111
  env_ids = options[:environment_ids]
112
112
 
113
113
  return true if env_ids.blank?
@@ -35,8 +35,6 @@ module Katello
35
35
  module RepoMethods
36
36
  # returns all repos in hash representation with minors and arch children included
37
37
  def collect_repos(products, env, include_feedless = true)
38
- Glue::Pulp::Repos.prepopulate! products, env, []
39
-
40
38
  products.map do |prod|
41
39
  minor_repos, repos_without_minor = collect_minor(prod.repos(env, nil, include_feedless))
42
40
  { :name => prod.name, :object => prod, :id => prod.id, :type => "product", :repos => repos_without_minor,
@@ -13,7 +13,7 @@ module Actions
13
13
  ::Katello::Resources::Candlepin::Environment.create(input['organization_label'],
14
14
  input['cp_id'],
15
15
  input['name'],
16
- input['description'])
16
+ input['description'].try(:truncate, 255))
17
17
  end
18
18
  end
19
19
  end
@@ -9,7 +9,7 @@ module Actions
9
9
  :new_content_id => new_content_id)
10
10
  end
11
11
 
12
- def finalize
12
+ def finalize # rubocop:disable Metrics/AbcSize
13
13
  content_view = ::Katello::ContentView.find(input[:content_view_id])
14
14
  environment = ::Katello::KTEnvironment.find(input[:environment_id])
15
15
  content_ids = content_view.repos(environment).map(&:content_id).uniq.compact
@@ -4,17 +4,15 @@ module Actions
4
4
  class Create < Actions::EntryAction
5
5
  def plan(activation_key, params = {})
6
6
  activation_key.save!
7
- if ::SETTINGS[:katello][:use_cp]
8
- cp_create = plan_action(Candlepin::ActivationKey::Create,
9
- organization_label: activation_key.organization.label,
10
- auto_attach: activation_key.auto_attach,
11
- service_level: params[:service_level],
12
- release_version: activation_key.release_version,
13
- purpose_role: activation_key.purpose_role,
14
- purpose_usage: activation_key.purpose_usage,
15
- purpose_addons: activation_key.purpose_addons.pluck(:name))
16
- cp_id = cp_create.output[:response][:id]
17
- end
7
+ cp_create = plan_action(Candlepin::ActivationKey::Create,
8
+ organization_label: activation_key.organization.label,
9
+ auto_attach: activation_key.auto_attach,
10
+ service_level: params[:service_level],
11
+ release_version: activation_key.release_version,
12
+ purpose_role: activation_key.purpose_role,
13
+ purpose_usage: activation_key.purpose_usage,
14
+ purpose_addons: activation_key.purpose_addons.pluck(:name))
15
+ cp_id = cp_create.output[:response][:id]
18
16
  action_subject(activation_key, :cp_id => cp_id)
19
17
  plan_self
20
18
  end
@@ -0,0 +1,64 @@
1
+ module Actions
2
+ module Katello
3
+ module Agent
4
+ class DispatchHistoryPresenter
5
+ def initialize(dispatch_history, action_type)
6
+ @result = dispatch_history&.result&.with_indifferent_access
7
+ @action_type = action_type
8
+ end
9
+
10
+ def humanized_output
11
+ return if @result.empty?
12
+
13
+ result = package_result
14
+
15
+ if result[:message]
16
+ result[:message]
17
+ elsif result[:packages].any?
18
+ packages = result[:packages].map { |package| package[:qname] }
19
+ packages.sort.join("\n")
20
+ else
21
+ humanized_no_package
22
+ end
23
+ end
24
+
25
+ def error_messages
26
+ messages = []
27
+ @result.each_value do |result|
28
+ if !result[:succeeded] && result.dig(:details, :message)
29
+ messages << result[:details][:message]
30
+ end
31
+ end
32
+ messages
33
+ end
34
+
35
+ private
36
+
37
+ def package_result
38
+ result = { packages: [] }
39
+
40
+ @result.each_value do |v|
41
+ if v[:succeeded]
42
+ result[:packages].concat(v[:details][:resolved] + v[:details][:deps])
43
+ break
44
+ else
45
+ result[:message] = v[:details][:message]
46
+ break
47
+ end
48
+ end
49
+
50
+ result
51
+ end
52
+
53
+ def humanized_no_package
54
+ case @action_type
55
+ when :content_install
56
+ _("No new packages installed")
57
+ when :content_uninstall
58
+ _("No packages removed")
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,107 @@
1
+ module Actions
2
+ module Katello
3
+ class AgentAction < Actions::EntryAction
4
+ include Dynflow::Action::Timeouts
5
+ include Helpers::Presenter
6
+
7
+ def self.agent_message
8
+ fail NotImplementedError
9
+ end
10
+
11
+ def agent_action_type
12
+ nil
13
+ end
14
+
15
+ def plan(host, options)
16
+ action_subject(host, :hostname => host.name, :content => options[:content])
17
+
18
+ # if already dispatched by bulk action use the provided history ID
19
+ dispatch_history_id = options.dig(:dispatch_histories, host.id.to_s)
20
+
21
+ unless dispatch_history_id
22
+ histories = ::Katello::Agent::Dispatcher.dispatch(
23
+ self.class.agent_message,
24
+ [host.id],
25
+ content: options[:content]
26
+ )
27
+
28
+ dispatch_history_id = histories.first.id
29
+ end
30
+
31
+ plan_self(
32
+ host_id: host.id,
33
+ dispatch_history_id: dispatch_history_id
34
+ )
35
+ end
36
+
37
+ def run(event = nil)
38
+ case event
39
+ when nil
40
+ history = dispatch_history
41
+
42
+ if history.finished?
43
+ fail_on_errors
44
+ return
45
+ elsif history.accepted?
46
+ schedule_timeout(finish_timeout)
47
+ else
48
+ schedule_timeout(accept_timeout)
49
+ end
50
+
51
+ suspend do |suspended_action|
52
+ history.dynflow_execution_plan_id = suspended_action.execution_plan_id
53
+ history.dynflow_step_id = suspended_action.step_id
54
+ history.save!
55
+ end
56
+ when Dynflow::Action::Timeouts::Timeout
57
+ process_timeout
58
+ when 'accepted'
59
+ schedule_timeout(finish_timeout)
60
+ suspend
61
+ else
62
+ fail_on_errors
63
+ end
64
+ end
65
+
66
+ def accept_timeout
67
+ Setting['content_action_accept_timeout']
68
+ end
69
+
70
+ def finish_timeout
71
+ Setting['content_action_finish_timeout']
72
+ end
73
+
74
+ def process_timeout
75
+ history = dispatch_history
76
+
77
+ unless history.accepted?
78
+ fail _("Host did not respond within %s seconds. The task has been cancelled. Is katello-agent installed and goferd running on the Host?") % accept_timeout
79
+ end
80
+
81
+ unless history.finished?
82
+ fail _("Host did not finish content action in %s seconds. The task has been cancelled.") % finish_timeout
83
+ end
84
+ end
85
+
86
+ def fail_on_errors
87
+ errors = presenter.error_messages
88
+
89
+ if errors.any?
90
+ fail errors.join("\n")
91
+ end
92
+ end
93
+
94
+ def presenter
95
+ Actions::Katello::Agent::DispatchHistoryPresenter.new(dispatch_history, agent_action_type)
96
+ end
97
+
98
+ def rescue_strategy
99
+ Dynflow::Action::Rescue::Skip
100
+ end
101
+
102
+ def dispatch_history
103
+ ::Katello::Agent::DispatchHistory.find_by_id(input[:dispatch_history_id])
104
+ end
105
+ end
106
+ end
107
+ end
@@ -9,8 +9,12 @@ module Actions
9
9
 
10
10
  def run
11
11
  input[:host_ids].each do |host_id|
12
- content_facet = ::Host.find(host_id).content_facet
13
- content_facet.calculate_and_import_applicability
12
+ content_facet = ::Katello::Host::ContentFacet.find_by_host_id(host_id)
13
+ if content_facet.present?
14
+ content_facet.calculate_and_import_applicability
15
+ else
16
+ Rails.logger.warn(_("Content Facet for host with id %s is non-existent. Skipping applicability calculation.") % host_id)
17
+ end
14
18
  end
15
19
  end
16
20
 
@@ -0,0 +1,21 @@
1
+ module Actions
2
+ module Katello
3
+ class BulkAgentAction < Actions::BulkAction
4
+ def plan(agent_action, hosts, args)
5
+ host_ids = hosts.map(&:id)
6
+ dispatch_args = {
7
+ content: args[:content]
8
+ }
9
+ histories = ::Katello::Agent::Dispatcher.dispatch(agent_action.agent_message, host_ids, dispatch_args)
10
+
11
+ grouped_histories = {}
12
+ histories.each { |h| grouped_histories[h.host_id] = h.id }
13
+ options = {
14
+ dispatch_histories: grouped_histories,
15
+ content: args[:content]
16
+ }
17
+ super(agent_action, hosts, options)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -30,18 +30,18 @@ module Actions
30
30
 
31
31
  fail _("Action not allowed for the default smart proxy.") if smart_proxy.pulp_primary?
32
32
 
33
- smart_proxy_helper = ::Katello::SmartProxyHelper.new(smart_proxy)
34
- repositories = smart_proxy_helper.combined_repos_available_to_capsule(environment, content_view, repository)
35
-
36
- smart_proxy.ping_pulp if repositories.any? { |repo| !smart_proxy.pulp3_support?(repo) }
37
-
38
33
  refresh_options = options.merge(content_view: content_view,
39
34
  environment: environment,
40
35
  repository: repository)
41
36
  sequence do
42
- plan_action(Actions::Pulp::Orchestration::Repository::RefreshRepos, smart_proxy, refresh_options)
43
- plan_action(Actions::Pulp3::CapsuleContent::RefreshContentGuard, smart_proxy) if repositories.any? { |repo| smart_proxy.pulp3_support?(repo) }
44
- plan_action(Actions::Pulp3::Orchestration::Repository::RefreshRepos, smart_proxy, refresh_options) if smart_proxy.pulp3_enabled?
37
+ if smart_proxy.has_feature?(SmartProxy::PULP_NODE_FEATURE)
38
+ plan_action(Actions::Pulp::Orchestration::Repository::RefreshRepos, smart_proxy, refresh_options)
39
+ end
40
+
41
+ if smart_proxy.has_feature?(SmartProxy::PULP3_FEATURE)
42
+ plan_action(Actions::Pulp3::CapsuleContent::RefreshContentGuard, smart_proxy)
43
+ plan_action(Actions::Pulp3::Orchestration::Repository::RefreshRepos, smart_proxy, refresh_options)
44
+ end
45
45
  plan_action(SyncCapsule, smart_proxy, refresh_options)
46
46
  end
47
47
  end
@@ -19,9 +19,14 @@ module Actions
19
19
  Actions::Pulp3::CapsuleContent::Sync],
20
20
  repo, smart_proxy,
21
21
  skip_metadata_check: skip_metadata_check)
22
+ end
23
+ end
24
+
25
+ concurrence do
26
+ repo_batch.each do |repo|
22
27
  if repo.is_a?(::Katello::Repository) &&
23
- repo.distribution_bootable? &&
24
- repo.download_policy == ::Runcible::Models::YumImporter::DOWNLOAD_ON_DEMAND
28
+ repo.distribution_bootable? &&
29
+ repo.download_policy == ::Runcible::Models::YumImporter::DOWNLOAD_ON_DEMAND
25
30
  plan_action(Katello::Repository::FetchPxeFiles,
26
31
  id: repo.id,
27
32
  capsule_id: smart_proxy.id)
@@ -30,6 +35,15 @@ module Actions
30
35
  end
31
36
  end
32
37
  end
38
+ update_unauthenticated_repo_list(smart_proxy) if smart_proxy.has_feature?("Container_Gateway")
39
+ end
40
+
41
+ def update_unauthenticated_repo_list(smart_proxy)
42
+ unauthenticated_repo_list =
43
+ ::Katello::SmartProxyHelper.new(smart_proxy).combined_repos_available_to_capsule.select do |repo|
44
+ repo.docker? && repo.environment.registry_unauthenticated_pull
45
+ end
46
+ smart_proxy.update_unauthenticated_repo_list(unauthenticated_repo_list.map(&:container_repository_name))
33
47
  end
34
48
 
35
49
  def repos_to_sync(smart_proxy, environment, content_view, repository, skip_metatadata_check = false)
@@ -0,0 +1,17 @@
1
+ module Actions
2
+ module Katello
3
+ module CheckMatchingContent
4
+ def check_matching_content(new_repository, source_repositories)
5
+ check_matching_content = ::Katello::RepositoryTypeManager.find(new_repository.content_type).metadata_publish_matching_check
6
+ if new_repository.environment && source_repositories.count == 1 && check_matching_content
7
+ match_check_output = plan_action(Katello::Repository::CheckMatchingContent,
8
+ :source_repo_id => source_repositories.first.id,
9
+ :target_repo_id => new_repository.id).output
10
+
11
+ return match_check_output[:matching_content]
12
+ end
13
+ false
14
+ end
15
+ end
16
+ end
17
+ end