katello 4.0.0.rc1 → 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 (106) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/katello/katello.scss +0 -72
  3. data/app/controllers/katello/api/v2/host_errata_controller.rb +1 -1
  4. data/app/controllers/katello/api/v2/host_packages_controller.rb +6 -6
  5. data/app/controllers/katello/api/v2/hosts_bulk_actions_controller.rb +1 -1
  6. data/app/controllers/katello/api/v2/upstream_subscriptions_controller.rb +1 -1
  7. data/app/lib/actions/katello/agent/dispatch_history_presenter.rb +64 -0
  8. data/app/lib/actions/katello/agent_action.rb +107 -0
  9. data/app/lib/actions/katello/bulk_agent_action.rb +21 -0
  10. data/app/lib/actions/katello/host/erratum/applicable_errata_install.rb +1 -1
  11. data/app/lib/actions/katello/host/erratum/install.rb +8 -26
  12. data/app/lib/actions/katello/host/package/install.rb +8 -21
  13. data/app/lib/actions/katello/host/package/remove.rb +8 -20
  14. data/app/lib/actions/katello/host/package/update.rb +9 -22
  15. data/app/lib/actions/katello/host/package_group/install.rb +8 -21
  16. data/app/lib/actions/katello/host/package_group/remove.rb +8 -20
  17. data/app/lib/actions/pulp/consumer.rb +0 -11
  18. data/app/lib/katello/agent/base_message.rb +38 -0
  19. data/app/lib/katello/agent/client_message_handler.rb +60 -0
  20. data/app/lib/katello/agent/connection.rb +24 -0
  21. data/app/lib/katello/agent/install_errata_message.rb +25 -0
  22. data/app/lib/katello/agent/install_package_group_message.rb +25 -0
  23. data/app/lib/katello/agent/install_package_message.rb +28 -0
  24. data/app/lib/katello/agent/remove_package_group_message.rb +25 -0
  25. data/app/lib/katello/agent/remove_package_message.rb +28 -0
  26. data/app/lib/katello/agent/update_package_message.rb +25 -0
  27. data/app/lib/katello/event_daemon/services/agent_event_receiver.rb +62 -0
  28. data/app/lib/katello/messaging/received_message.rb +1 -1
  29. data/app/lib/katello/qpid/connection.rb +130 -0
  30. data/app/models/katello/agent/dispatch_history.rb +17 -0
  31. data/app/models/katello/concerns/host_managed_extensions.rb +3 -0
  32. data/app/models/katello/events/delete_host_agent_queue.rb +19 -0
  33. data/app/models/katello/ping.rb +9 -1
  34. data/app/models/setting/content.rb +0 -2
  35. data/app/services/katello/agent/dispatcher.rb +66 -0
  36. data/app/services/katello/candlepin_event_listener.rb +1 -0
  37. data/app/services/katello/event_monitor/poller_thread.rb +1 -0
  38. data/app/services/katello/registration_manager.rb +10 -0
  39. data/app/views/katello/sync_management/_products.html.erb +1 -1
  40. data/db/migrate/20210122200618_create_katello_agent_dispatch_history.rb +11 -0
  41. data/db/migrate/20210125161911_delete_erratum_install_batch_size_setting.rb +5 -0
  42. data/db/migrate/20210208213920_add_available_module_stream_context.rb +8 -0
  43. data/engines/bastion/app/assets/javascripts/bastion/auth/authorization.service.js +1 -1
  44. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/subscriptions/subscription-start-date.directive.js +21 -0
  45. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/subscriptions/subscription-type.directive.js +16 -0
  46. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/subscriptions/views/subscription-start-date.html +2 -0
  47. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/subscriptions/views/subscription-type.html +18 -0
  48. data/lib/katello/engine.rb +7 -0
  49. data/lib/katello/plugin.rb +1 -0
  50. data/lib/katello/tasks/reset.rake +0 -15
  51. data/lib/katello/version.rb +1 -1
  52. data/locale/bn/katello.edit.po +8538 -0
  53. data/locale/bn/katello.po.time_stamp +0 -0
  54. data/locale/cs/katello.edit.po +8440 -0
  55. data/locale/cs/katello.po.time_stamp +0 -0
  56. data/locale/de/katello.edit.po +8344 -0
  57. data/locale/de/katello.po.time_stamp +0 -0
  58. data/locale/en/katello.edit.po +8161 -0
  59. data/locale/en/katello.po.time_stamp +0 -0
  60. data/locale/es/katello.edit.po +8306 -0
  61. data/locale/es/katello.po.time_stamp +0 -0
  62. data/locale/fr/katello.edit.po +8356 -0
  63. data/locale/fr/katello.po.time_stamp +0 -0
  64. data/locale/gu/katello.edit.po +8540 -0
  65. data/locale/gu/katello.po.time_stamp +0 -0
  66. data/locale/hi/katello.edit.po +8537 -0
  67. data/locale/hi/katello.po.time_stamp +0 -0
  68. data/locale/it/katello.edit.po +8293 -0
  69. data/locale/it/katello.po.time_stamp +0 -0
  70. data/locale/ja/katello.edit.po +8322 -0
  71. data/locale/ja/katello.po.time_stamp +0 -0
  72. data/locale/kn/katello.edit.po +8538 -0
  73. data/locale/kn/katello.po.time_stamp +0 -0
  74. data/locale/ko/katello.edit.po +8289 -0
  75. data/locale/ko/katello.po.time_stamp +0 -0
  76. data/locale/mr/katello.edit.po +8502 -0
  77. data/locale/mr/katello.po.time_stamp +0 -0
  78. data/locale/or/katello.edit.po +8538 -0
  79. data/locale/or/katello.po.time_stamp +0 -0
  80. data/locale/pa/katello.edit.po +8524 -0
  81. data/locale/pa/katello.po.time_stamp +0 -0
  82. data/locale/pt/katello.edit.po +8255 -0
  83. data/locale/pt/katello.po.time_stamp +0 -0
  84. data/locale/pt_BR/katello.edit.po +8289 -0
  85. data/locale/pt_BR/katello.po.time_stamp +0 -0
  86. data/locale/ru/katello.edit.po +8309 -0
  87. data/locale/ru/katello.po.time_stamp +0 -0
  88. data/locale/ta/katello.edit.po +8536 -0
  89. data/locale/ta/katello.po.time_stamp +0 -0
  90. data/locale/te/katello.edit.po +8536 -0
  91. data/locale/te/katello.po.time_stamp +0 -0
  92. data/locale/zh_CN/katello.edit.po +8288 -0
  93. data/locale/zh_CN/katello.po.time_stamp +0 -0
  94. data/locale/zh_TW/katello.edit.po +8420 -0
  95. data/locale/zh_TW/katello.po.time_stamp +0 -0
  96. metadata +62 -12
  97. data/app/lib/actions/pulp/consumer/abstract_content_action.rb +0 -71
  98. data/app/lib/actions/pulp/consumer/content_install.rb +0 -43
  99. data/app/lib/actions/pulp/consumer/content_uninstall.rb +0 -26
  100. data/app/lib/actions/pulp/consumer/content_update.rb +0 -32
  101. data/db/functions/empty_v01.sql +0 -7
  102. data/db/functions/evr_trigger_v01.sql +0 -9
  103. data/db/functions/isalpha_v01.sql +0 -11
  104. data/db/functions/isalphanum_v01.sql +0 -12
  105. data/db/functions/isdigit_v01.sql +0 -10
  106. data/db/functions/rpmver_array_v01.sql +0 -60
@@ -0,0 +1,28 @@
1
+ module Katello
2
+ module Agent
3
+ class RemovePackageMessage < BaseMessage
4
+ def initialize(content:, consumer_id:)
5
+ @packages = content
6
+ @consumer_id = consumer_id
7
+ @content_type = 'rpm'
8
+ @method = 'uninstall'
9
+ end
10
+
11
+ protected
12
+
13
+ def units
14
+ @packages.map do |package|
15
+ nvra = ::Katello::Util::Package.parse_nvrea_nvre(package)
16
+ unit_key = nvra || {
17
+ name: package
18
+ }
19
+
20
+ {
21
+ type_id: @content_type,
22
+ unit_key: unit_key
23
+ }
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,25 @@
1
+ module Katello
2
+ module Agent
3
+ class UpdatePackageMessage < BaseMessage
4
+ def initialize(content:, consumer_id:)
5
+ @packages = content
6
+ @consumer_id = consumer_id
7
+ @content_type = 'rpm'
8
+ @method = 'update'
9
+ end
10
+
11
+ protected
12
+
13
+ def units
14
+ @packages.map do |package|
15
+ {
16
+ type_id: @content_type,
17
+ unit_key: {
18
+ name: package
19
+ }
20
+ }
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,62 @@
1
+ module Katello
2
+ module EventDaemon
3
+ module Services
4
+ class AgentEventReceiver
5
+ STATUS_CACHE_KEY = 'katello_agent_events'.freeze
6
+
7
+ class Handler
8
+ attr_accessor :processed, :failed
9
+
10
+ def initialize
11
+ @processed = 0
12
+ @failed = 0
13
+ end
14
+
15
+ def handle(message)
16
+ ::Katello::Util::Support.with_db_connection do
17
+ ::Katello::Agent::ClientMessageHandler.new(message).handle
18
+ @processed += 1
19
+ rescue => e
20
+ @failed += 1
21
+ Rails.logger.error("Error handling Katello Agent client message")
22
+ Rails.logger.error(e.message)
23
+ Rails.logger.error(e.backtrace.join("\n"))
24
+ end
25
+ end
26
+ end
27
+
28
+ def self.logger
29
+ ::Foreman::Logging.logger('katello/agent')
30
+ end
31
+
32
+ def self.run
33
+ fail("Katello agent event receiver already started") if running?
34
+
35
+ @thread = Thread.new do
36
+ @handler = Handler.new
37
+ agent_connection = ::Katello::Agent::Connection.new
38
+ agent_connection.fetch_agent_messages(@handler)
39
+ end
40
+ end
41
+
42
+ def self.close
43
+ @thread&.kill
44
+ end
45
+
46
+ def self.running?
47
+ @thread&.status.present?
48
+ end
49
+
50
+ def self.status(refresh: true)
51
+ Rails.cache.fetch(STATUS_CACHE_KEY, force: refresh) do
52
+ {
53
+ running: running?,
54
+ processed_count: @handler&.processed || 0,
55
+ failed_count: @handler&.failed || 0
56
+ }
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -3,7 +3,7 @@ module Katello
3
3
  class ReceivedMessage
4
4
  attr_reader :headers, :body
5
5
 
6
- def initialize(body:, headers:)
6
+ def initialize(body:, headers: {})
7
7
  @body = body
8
8
  @headers = headers
9
9
  end
@@ -0,0 +1,130 @@
1
+ require 'qpid_proton'
2
+
3
+ module Katello
4
+ module Qpid
5
+ class Connection
6
+ class Sender < ::Qpid::Proton::MessagingHandler
7
+ def initialize(url, address, messages)
8
+ super()
9
+ @url = url
10
+ @address = address
11
+ @messages = messages
12
+ @sent = 0
13
+ @confirmed = 0
14
+ end
15
+
16
+ def on_container_start(container)
17
+ c = container.connect(@url)
18
+ c.open_sender
19
+ @receiver = c.open_receiver(@address) if @address
20
+ end
21
+
22
+ def on_sendable(sender)
23
+ @messages.each do |msg|
24
+ msg.reply_to = @receiver.remote_source.address if @receiver
25
+ sender.send(msg)
26
+ @sent += 1
27
+ end
28
+ ensure
29
+ sender.close
30
+ end
31
+
32
+ def on_tracker_accept(tracker)
33
+ @confirmed += 1
34
+ if @confirmed == @sent
35
+ tracker.connection.close
36
+ end
37
+ end
38
+
39
+ def on_message(_delivery, message)
40
+ opcode = message.properties['qmf.opcode']
41
+ if opcode == '_exception'
42
+ error_code = message.body.dig('_values', 'error_code')
43
+ if error_code != '7' # not found
44
+ error_message = message.body.dig('_values', 'error_text')
45
+ fail(error_message)
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ class Receiver < ::Qpid::Proton::MessagingHandler
52
+ def initialize(url, address, handler)
53
+ super()
54
+ @url = url
55
+ @address = address
56
+ @handler = handler
57
+ end
58
+
59
+ def on_container_start(container)
60
+ c = container.connect(@url,
61
+ idle_timeout: 4
62
+ )
63
+ c.open_receiver(@address)
64
+ end
65
+
66
+ def on_message(_delivery, message)
67
+ received = Katello::Messaging::ReceivedMessage.new(body: message.body)
68
+ @handler.handle(received)
69
+ end
70
+ end
71
+
72
+ def initialize(url)
73
+ @url = url
74
+ end
75
+
76
+ def delete_queue(queue_name)
77
+ address = "qmf.default.direct"
78
+ message = ::Qpid::Proton::Message.new
79
+ message.subject = 'broker'
80
+ message.address = address
81
+ message.body = {
82
+ '_object_id' => {
83
+ '_object_name' => 'org.apache.qpid.broker:broker:amqp-broker'
84
+ },
85
+ '_method_name' => 'delete',
86
+ '_arguments' => {
87
+ 'strict' => true,
88
+ 'name' => queue_name,
89
+ 'type' => 'queue',
90
+ 'properties' => {}
91
+ }
92
+ }
93
+
94
+ message.properties = {
95
+ 'qmf.opcode' => '_method_request',
96
+ 'x-amqp-0-10.app-id' => 'qmf2',
97
+ 'method' => 'request'
98
+ }
99
+
100
+ sender = Sender.new(@url, address, [message])
101
+ with_connection(sender)
102
+ end
103
+
104
+ def send_messages(messages)
105
+ qpid_messages = messages.map do |message|
106
+ msg = ::Qpid::Proton::Message.new
107
+ msg.body = message.to_s
108
+ msg.address = message.recipient_address
109
+ msg
110
+ end
111
+ sender = Sender.new(@url, nil, qpid_messages)
112
+ with_connection(sender)
113
+ end
114
+
115
+ def receive_messages(address:, handler:)
116
+ receiver = Receiver.new(@url, address, handler)
117
+ with_connection(receiver)
118
+ end
119
+
120
+ private
121
+
122
+ def with_connection(handler)
123
+ container = ::Qpid::Proton::Container.new(handler)
124
+ container.run
125
+ ensure
126
+ container&.stop
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,17 @@
1
+ module Katello
2
+ module Agent
3
+ class DispatchHistory < Katello::Model
4
+ self.table_name = 'katello_agent_dispatch_histories'
5
+
6
+ serialize :result, Hash
7
+
8
+ def accepted?
9
+ accepted_at.present?
10
+ end
11
+
12
+ def finished?
13
+ result.present?
14
+ end
15
+ end
16
+ end
17
+ end
@@ -33,6 +33,8 @@ module Katello
33
33
  included do
34
34
  prepend Overrides
35
35
 
36
+ has_many :dispatch_histories, :class_name => "::Katello::Agent::DispatchHistory", :foreign_key => :host_id, :dependent => :delete_all
37
+
36
38
  has_many :host_installed_packages, :class_name => "::Katello::HostInstalledPackage", :foreign_key => :host_id, :dependent => :delete_all
37
39
  has_many :installed_packages, :class_name => "::Katello::InstalledPackage", :through => :host_installed_packages
38
40
 
@@ -212,6 +214,7 @@ module Katello
212
214
  streams = {}
213
215
  module_streams.each do |module_stream|
214
216
  stream = AvailableModuleStream.where(name: module_stream["name"],
217
+ context: module_stream["context"],
215
218
  stream: module_stream["stream"]).first_or_create!
216
219
  streams[stream.id] = module_stream
217
220
  end
@@ -0,0 +1,19 @@
1
+ module Katello
2
+ module Events
3
+ class DeleteHostAgentQueue
4
+ EVENT_TYPE = 'delete_host_agent_queue'.freeze
5
+
6
+ attr_accessor :metadata
7
+
8
+ def initialize(_host_id)
9
+ yield(self) if block_given?
10
+ end
11
+
12
+ def run
13
+ if metadata[:queue_name]
14
+ Katello::Agent::Dispatcher.delete_client_queue(queue_name: metadata[:queue_name])
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -14,7 +14,7 @@ module Katello
14
14
 
15
15
  def services(capsule_id = nil)
16
16
  proxy = fetch_proxy(capsule_id)
17
- services = [:candlepin, :candlepin_auth, :foreman_tasks, :katello_events, :candlepin_events]
17
+ services = [:candlepin, :candlepin_auth, :foreman_tasks, :katello_events, :candlepin_events, :katello_agent]
18
18
  services += [:pulp3] if proxy&.pulp3_enabled? && pulpcore_enabled
19
19
  if proxy.nil? || proxy.has_feature?(SmartProxy::PULP_NODE_FEATURE) || proxy.has_feature?(SmartProxy::PULP_FEATURE)
20
20
  services += [:pulp, :pulp_auth]
@@ -38,6 +38,7 @@ module Katello
38
38
  ping_foreman_tasks(result[:foreman_tasks]) if result.include?(:foreman_tasks)
39
39
  ping_katello_events(result[:katello_events]) if result.include?(:katello_events)
40
40
  ping_candlepin_events(result[:candlepin_events]) if result.include?(:candlepin_events)
41
+ ping_katello_agent(result[:katello_agent]) if result.include?(:katello_agent)
41
42
 
42
43
  # set overall status result code
43
44
  result = {:services => result}
@@ -77,6 +78,13 @@ module Katello
77
78
  end
78
79
  end
79
80
 
81
+ def ping_katello_agent(result)
82
+ exception_watch(result) do
83
+ status = Katello::EventDaemon::Services::AgentEventReceiver.status(refresh: false)
84
+ event_daemon_status(status, result)
85
+ end
86
+ end
87
+
80
88
  def ping_pulp3_without_auth(service_result, capsule_id)
81
89
  exception_watch(service_result) do
82
90
  Katello::Ping.pulp3_without_auth(fetch_proxy(capsule_id).pulp3_url)
@@ -120,8 +120,6 @@ class Setting::Content < Setting
120
120
  '', N_('Subscription manager name registration fact'), nil),
121
121
  self.set('register_hostname_fact_strict_match', N_('If true, and register_hostname_fact is set and provided, registration will look for a new host by name only '\
122
122
  'using that fact, and will skip all hostname matching'), false, N_('Subscription manager name registration fact strict matching'), nil),
123
- self.set('erratum_install_batch_size', N_("Errata installed via katello-agent will be triggered in batches of this size. Set to 0 to install all errata in one batch."),
124
- 0, N_('Erratum Install Batch Size')),
125
123
  self.set('default_location_subscribed_hosts',
126
124
  N_('Default Location where new subscribed hosts will put upon registration'),
127
125
  nil, N_('Default Location subscribed hosts'), nil,
@@ -0,0 +1,66 @@
1
+ module Katello
2
+ module Agent
3
+ class Dispatcher
4
+ @supported_messages = {}
5
+
6
+ def self.register_message(name, klass)
7
+ @supported_messages[name] = klass
8
+ end
9
+
10
+ register_message(:install_package, Katello::Agent::InstallPackageMessage)
11
+ register_message(:remove_package, Katello::Agent::RemovePackageMessage)
12
+ register_message(:update_package, Katello::Agent::UpdatePackageMessage)
13
+ register_message(:install_errata, Katello::Agent::InstallErrataMessage)
14
+ register_message(:install_package_group, Katello::Agent::InstallPackageGroupMessage)
15
+ register_message(:remove_package_group, Katello::Agent::RemovePackageGroupMessage)
16
+
17
+ def self.dispatch(message_type, host_ids, args)
18
+ message_class = @supported_messages[message_type]
19
+
20
+ fail("Unsupported message type") unless message_class
21
+
22
+ uuid_data = ::Katello::Host::ContentFacet.where(host_id: host_ids).pluck(:host_id, :uuid)
23
+ fail("Couldn't find all hosts specified") unless host_ids.size == uuid_data.size
24
+
25
+ host_data = uuid_data.map do |host_id, consumer_id|
26
+ {
27
+ host_id: host_id,
28
+ consumer_id: consumer_id,
29
+ history: Katello::Agent::DispatchHistory.new(host_id: host_id),
30
+ message: message_class.new(**args.merge(consumer_id: consumer_id))
31
+ }
32
+ end
33
+
34
+ histories = host_data.map { |attrs| attrs[:history] }
35
+ ActiveRecord::Base.transaction do
36
+ Katello::Agent::DispatchHistory.import(histories)
37
+
38
+ host_data.each do |d|
39
+ d[:message].dispatch_history_id = d[:history].id
40
+ d[:message].recipient_address = settings[:client_queue_format] % [d[:consumer_id]]
41
+ d[:message].reply_to = settings[:event_queue_name]
42
+ end
43
+
44
+ connection = Connection.new
45
+ connection.send_messages(host_data.map { |d| d[:message] })
46
+ end
47
+
48
+ histories
49
+ end
50
+
51
+ def self.delete_client_queue(queue_name:)
52
+ connection = Connection.new
53
+ connection.delete_client_queue(queue_name)
54
+ end
55
+
56
+ def self.host_queue_name(host)
57
+ uuid = host.content_facet.uuid
58
+ settings[:client_queue_format] % uuid
59
+ end
60
+
61
+ def self.settings
62
+ SETTINGS[:katello][:agent]
63
+ end
64
+ end
65
+ end
66
+ end
@@ -1,4 +1,5 @@
1
1
  module Katello
2
+ # TODO: Move this class to app/lib/katello/event_daemon/services with other service definitions
2
3
  class CandlepinEventListener
3
4
  Event = Struct.new(:subject, :content)
4
5
 
@@ -1,5 +1,6 @@
1
1
  module Katello
2
2
  module EventMonitor
3
+ # TODO: Move this class to app/lib/katello/event_daemon/services with other service definitions
3
4
  class PollerThread
4
5
  SLEEP_INTERVAL = 3
5
6
 
@@ -115,6 +115,8 @@ module Katello
115
115
  # This can be cleaned up later via clean_backend_objects.
116
116
  pulp_consumer_destory(host.content_facet.uuid) if host.content_facet.try(:uuid) && pulp2_supported?
117
117
 
118
+ delete_agent_queue(host) if host.content_facet.try(:uuid)
119
+
118
120
  host.subscription_facet.try(:destroy!)
119
121
 
120
122
  if unregistering
@@ -266,6 +268,14 @@ module Katello
266
268
  Rails.logger.warn(_("Pulp Consumer %s has already been removed") % host_uuid)
267
269
  end
268
270
 
271
+ def delete_agent_queue(host)
272
+ queue_name = Katello::Agent::Dispatcher.host_queue_name(host)
273
+ Katello::EventQueue.push_event(::Katello::Events::DeleteHostAgentQueue::EVENT_TYPE, host.id) do |attrs|
274
+ attrs[:metadata] = { queue_name: queue_name }
275
+ attrs[:process_after] = 10.minutes.from_now
276
+ end
277
+ end
278
+
269
279
  def populate_content_facet(host, content_view_environment, uuid)
270
280
  content_facet = host.content_facet || ::Katello::Host::ContentFacet.new(:host => host)
271
281
  content_facet.content_view = content_view_environment.content_view