katello 3.1.0.rc1 → 3.1.0.rc2.1

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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/katello/api/rhsm/candlepin_proxies_controller.rb +1 -1
  3. data/app/controllers/katello/api/v2/content_views_controller.rb +3 -1
  4. data/app/controllers/katello/api/v2/errata_controller.rb +1 -1
  5. data/app/controllers/katello/api/v2/host_errata_controller.rb +11 -2
  6. data/app/controllers/katello/api/v2/organizations_controller.rb +2 -2
  7. data/app/controllers/katello/api/v2/repositories_controller.rb +2 -2
  8. data/app/controllers/katello/concerns/filtered_auto_complete_search.rb +1 -1
  9. data/app/controllers/katello/sync_management_controller.rb +1 -4
  10. data/app/helpers/katello/packages_helper.rb +1 -1
  11. data/app/lib/actions/candlepin/candlepin_listening_service.rb +1 -1
  12. data/app/lib/actions/candlepin/listen_on_candlepin_events.rb +6 -12
  13. data/app/lib/actions/katello/capsule_content/sync.rb +2 -2
  14. data/app/lib/actions/katello/event_queue/monitor.rb +129 -0
  15. data/app/lib/actions/katello/event_queue/poller_thread.rb +45 -0
  16. data/app/lib/actions/katello/event_queue/run_once_coordinator_lock.rb +12 -0
  17. data/app/lib/actions/katello/event_queue/suspended_action.rb +23 -0
  18. data/app/lib/actions/katello/host/generate_applicability.rb +2 -3
  19. data/app/lib/actions/katello/host/update.rb +1 -1
  20. data/app/lib/actions/katello/repository/import_applicability.rb +3 -1
  21. data/app/lib/katello/api/v2/error_handling.rb +1 -1
  22. data/app/lib/katello/resources/cdn.rb +1 -1
  23. data/app/lib/katello/util/package.rb +1 -1
  24. data/app/lib/katello/util/support.rb +1 -1
  25. data/app/lib/katello/validators/content_view_erratum_filter_rule_validator.rb +2 -2
  26. data/app/lib/katello/validators/repo_disablement_validator.rb +1 -1
  27. data/app/models/katello/errata_status.rb +2 -2
  28. data/app/models/katello/erratum.rb +1 -0
  29. data/app/models/katello/event.rb +12 -0
  30. data/app/models/katello/events/import_host_errata.rb +16 -0
  31. data/app/models/katello/glue/provider.rb +1 -1
  32. data/app/models/katello/glue/pulp/repo.rb +3 -3
  33. data/app/models/katello/host_collection_hosts.rb +1 -1
  34. data/app/models/katello/puppet_module.rb +10 -3
  35. data/app/models/katello/repository.rb +4 -14
  36. data/app/models/katello/rhsm_fact_parser.rb +9 -0
  37. data/app/models/katello/sync_plan.rb +1 -1
  38. data/app/models/katello/system.rb +1 -1
  39. data/app/services/katello/event_queue.rb +39 -0
  40. data/app/views/katello/errata_mailer/_erratum.html.erb +1 -0
  41. data/app/views/katello/errata_mailer/promote_errata.html.erb +3 -6
  42. data/app/views/katello/errata_mailer/sync_errata.html.erb +1 -4
  43. data/config/katello.yml +34 -227
  44. data/db/migrate/20150930183738_migrate_content_hosts.rb +38 -3
  45. data/db/migrate/20160613150922_add_event_queue.rb +12 -0
  46. data/db/migrate/20160619223332_fix_viewer_role.rb +41 -0
  47. data/db/migrate/20160701180402_add_sortable_version_to_puppet_modules.rb +26 -0
  48. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/views/activation-key-add-subscriptions.html +6 -2
  49. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/views/activation-key-subscriptions-list.html +2 -2
  50. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-add-subscriptions.html +2 -2
  51. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-subscriptions-list.html +2 -2
  52. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/subscriptions/views/subscriptions-table-collapsed.html +2 -1
  53. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/subscriptions/views/subscriptions-table-full.html +2 -2
  54. data/engines/bastion_katello/app/assets/stylesheets/bastion_katello/bastion_katello.scss +2 -0
  55. data/engines/bastion_katello/app/assets/stylesheets/bastion_katello/colors.scss +1 -0
  56. data/engines/bastion_katello/app/assets/stylesheets/bastion_katello/subscriptions.scss +3 -0
  57. data/lib/katello/engine.rb +4 -0
  58. data/lib/katello/tasks/reindex.rake +1 -1
  59. data/lib/katello/tasks/upgrade_check.rake +18 -0
  60. data/lib/katello/version.rb +1 -1
  61. metadata +20 -20
  62. data/db/migrate/20160520175340_add_host_applicable_package.rb +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ae4ab15eb9d39a34a4069ff9b54905840aaf73af
4
- data.tar.gz: bf8993794d13a72a10086070b705af01bb006be9
3
+ metadata.gz: 395d8a31c2395972b2f577bb9355592371adfbcc
4
+ data.tar.gz: a606dbd1a2f6272f690beb0e88fa3a1557eafddc
5
5
  SHA512:
6
- metadata.gz: e0c4e3472f5e0c95405197c1f55c17e0b7fa3ea60319b0ce0d8089878616d3f8ba72f3adefc678f17a6ae6289a0a2314c9a1791f3a12d892370fd09958ab7564
7
- data.tar.gz: 29a7dadc2e1913b3761d182c10fd47937a8d0badb08bd2801e3e80918cb0d57601f59c72f27e90a9dd8e2a7912169a902ba16babf5f5b5cddd8da0f6c4eed13b
6
+ metadata.gz: 579ca099fa9cf2b6477c8795ccbcdfb37fa2e51bb93975c628a9134191bb9f983d2e6e466af98833213647e62b833c077d7d8000f7e0b0ac89bfe05c706858fe
7
+ data.tar.gz: 4f018616bf7be9e2fd7ff9243963728757cdd0ecc183409a32fb2e257907dfc0ede3e078da93bf004b3f01660318456e0a2d507bc63e76074d1b328727854ee4
@@ -132,7 +132,7 @@ module Katello
132
132
  #param :id, String, :desc => N_("UUID of the consumer"), :required => true
133
133
  def upload_package_profile
134
134
  User.as_anonymous_admin do
135
- sync_task(::Actions::Katello::Host::UploadPackageProfile, @host, params[:_json])
135
+ async_task(::Actions::Katello::Host::UploadPackageProfile, @host, params[:_json])
136
136
  end
137
137
  render :json => Resources::Candlepin::Consumer.get(@host.subscription_facet.uuid)
138
138
  end
@@ -99,9 +99,11 @@ module Katello
99
99
  query = PuppetModule.in_repositories(repositories)
100
100
  query = query.where(:name => params[:name]) if params[:name]
101
101
  query = query.where("#{PuppetModule.table_name}.uuid NOT in (?)", current_uuids) if current_uuids.present?
102
+ custom_sort = ->(sort_query) { sort_query.order('author, name, sortable_version DESC') }
102
103
 
103
104
  respond_for_index :template => 'puppet_modules',
104
- :collection => scoped_search(query, 'name', 'ASC', :resource_class => PuppetModule)
105
+ :collection => scoped_search(query, nil, nil, :resource_class => PuppetModule,
106
+ :custom_sort => custom_sort)
105
107
  end
106
108
 
107
109
  api :GET, "/content_views/:id/available_puppet_module_names",
@@ -55,7 +55,7 @@ module Katello
55
55
 
56
56
  def filter_by_content_view(filter, collection)
57
57
  repos = Katello::ContentView.find(filter.content_view_id).repositories
58
- uuid = repos.map { |r| r.send("errata").pluck("uuid") }
58
+ uuid = repos.map { |r| r.send("errata").pluck("uuid") }.flatten
59
59
  filter_by_ids(uuid, collection)
60
60
  end
61
61
 
@@ -28,7 +28,12 @@ module Katello
28
28
  end
29
29
 
30
30
  collection = scoped_search(index_relation, 'updated_at', 'desc', :resource_class => Erratum, :includes => [:cves])
31
- @installable_errata_ids = @host.content_facet.installable_errata.pluck("#{Katello::Erratum.table_name}.id")
31
+
32
+ @installable_errata_ids = []
33
+ if @host.content_facet
34
+ @installable_errata_ids = @host.content_facet.installable_errata.pluck("#{Katello::Erratum.table_name}.id")
35
+ end
36
+
32
37
  respond_for_index :collection => collection
33
38
  end
34
39
 
@@ -52,7 +57,11 @@ module Katello
52
57
  protected
53
58
 
54
59
  def index_relation
55
- @host.content_facet.installable_errata(@environment, @content_view)
60
+ relation = Katello::Erratum.none
61
+ if @host.content_facet
62
+ relation = @host.content_facet.installable_errata(@environment, @content_view)
63
+ end
64
+ relation
56
65
  end
57
66
 
58
67
  private
@@ -110,9 +110,9 @@ module Katello
110
110
  param :label, String, :desc => N_("Organization label")
111
111
  def download_debug_certificate
112
112
  pem = @organization.debug_cert
113
- data = "#{ pem[:key] }\n\n#{ pem[:cert] }"
113
+ data = "#{pem[:key]}\n\n#{pem[:cert]}"
114
114
  send_data data,
115
- :filename => "#{ @organization.name }-key-cert.pem",
115
+ :filename => "#{@organization.name}-key-cert.pem",
116
116
  :type => "application/text"
117
117
  end
118
118
 
@@ -47,7 +47,7 @@ module Katello
47
47
  param :erratum_id, String, :desc => N_("Id of an erratum to find repositories that contain the erratum")
48
48
  param :rpm_id, String, :desc => N_("Id of a package to find repositories that contain the rpm")
49
49
  param :library, :bool, :desc => N_("show repositories in Library and the default content view")
50
- param :content_type, RepositoryTypeManager.repository_types.keys, :desc => (N_("limit to only repositories of this type"))
50
+ param :content_type, RepositoryTypeManager.repository_types.keys, :desc => N_("limit to only repositories of this type")
51
51
  param :name, String, :desc => N_("name of the repository"), :required => false
52
52
  param :available_for, String, :desc => N_("interpret specified object to return only Repositories that can be associated with specified object. Only 'content_view' is supported."),
53
53
  :required => false
@@ -138,7 +138,7 @@ module Katello
138
138
  repo_params[:content_type], unprotected,
139
139
  gpg_key, repository_params[:checksum_type], repo_params[:download_policy])
140
140
  repository.docker_upstream_name = repo_params[:docker_upstream_name] if repo_params[:docker_upstream_name]
141
- repository.mirror_on_sync = ::Foreman::Cast.to_bool(repo_params[:mirror_on_sync]) if repo_params[:mirror_on_sync]
141
+ repository.mirror_on_sync = ::Foreman::Cast.to_bool(repo_params[:mirror_on_sync]) if repo_params.key?(:mirror_on_sync)
142
142
  sync_task(::Actions::Katello::Repository::Create, repository, false, true)
143
143
  repository = Repository.find(repository.id)
144
144
  respond_for_show(:resource => repository)
@@ -10,7 +10,7 @@ module Katello
10
10
  options = resource_class.respond_to?(:completer_scope_options) ? resource_class.completer_scope_options : {}
11
11
  items = resource_class.where(:id => self.index_relation).complete_for(params[:search], options)
12
12
  items = items.map do |item|
13
- category = (['and', 'or', 'not', 'has'].include?(item.to_s.sub(/^.*\s+/, ''))) ? _('Operators') : ''
13
+ category = ['and', 'or', 'not', 'has'].include?(item.to_s.sub(/^.*\s+/, '')) ? _('Operators') : ''
14
14
  part = item.to_s.sub(/^.*\b(and|or)\b/i) { |match| match.sub(/^.*\s+/, '') }
15
15
  completed = item.to_s.chomp(part)
16
16
  {:completed => completed, :part => part, :label => item, :category => category}
@@ -63,11 +63,8 @@ module Katello
63
63
  repos.each do |repo|
64
64
  if latest_task(repo).try(:state) != 'running'
65
65
  ForemanTasks.async_task(::Actions::Katello::Repository::Sync, repo)
66
- collected << format_sync_progress(repo)
67
- else
68
- notify.error N_("There is already an active sync process for the '%s' repository. Please try again later") %
69
- repo.name
70
66
  end
67
+ collected << format_sync_progress(repo)
71
68
  end
72
69
  collected
73
70
  end
@@ -1,7 +1,7 @@
1
1
  module Katello
2
2
  module PackagesHelper
3
3
  def format_changelog_changes(changes)
4
- (h(changes).gsub(/\n/, "<br>")).html_safe
4
+ h(changes).gsub(/\n/, "<br>").html_safe
5
5
  end
6
6
 
7
7
  def format_changelog_date(date)
@@ -65,7 +65,7 @@ module Actions
65
65
 
66
66
  def fetch_message
67
67
  {:result => retrieve, :error => nil}
68
- rescue Actions::Candlepin::ConnectionError => e
68
+ rescue ::Actions::Candlepin::ConnectionError => e
69
69
  {:result => nil, :error => e.message}
70
70
  end
71
71
 
@@ -180,10 +180,13 @@ module Actions
180
180
  def act_on_event(event)
181
181
  begin
182
182
  output[:connection] = "Connected"
183
- on_event(event)
183
+ Actions::Candlepin::ImportPoolHandler.new(Rails.logger).handle(event)
184
+ output[:last_message] = "#{event.message_id} - #{event.subject}"
185
+ output[:messages] = event.message_id
184
186
  rescue => e
185
- error!(e)
186
- raise e
187
+ output[:last_event_error] = e.message
188
+ action_logger.error("Failed Candlepin Event: #{e.message}")
189
+ action_logger.error(e.backtrace.join('\n'))
187
190
  end
188
191
  suspend
189
192
  end
@@ -210,15 +213,6 @@ module Actions
210
213
  error!(e)
211
214
  end
212
215
 
213
- def on_event(event)
214
- Actions::Candlepin::ImportPoolHandler.new(Rails.logger).handle(event)
215
- output[:last_message] = "#{event.message_id} - #{event.subject}"
216
- output[:messages] = event.message_id
217
- rescue => e
218
- close_service
219
- error!(e)
220
- end
221
-
222
216
  def error_message(error_id)
223
217
  CandlepinListeningService.instance.errors[error_id]
224
218
  end
@@ -71,7 +71,7 @@ module Actions
71
71
  repo_details = capsule.pulp_repo_facts(repo.pulp_id)
72
72
  next unless repo_details
73
73
  capsule_distributors = repo_details["distributors"]
74
- !(repo.distributors_match?(capsule_distributors))
74
+ !repo.distributors_match?(capsule_distributors)
75
75
  end
76
76
  end
77
77
 
@@ -81,7 +81,7 @@ module Actions
81
81
  repo_details = capsule.pulp_repo_facts(repo.pulp_id)
82
82
  next unless repo_details
83
83
  capsule_importer = repo_details["importers"][0]
84
- !(repo.importer_matches?(capsule_importer))
84
+ !repo.importer_matches?(capsule_importer)
85
85
  end
86
86
  end
87
87
 
@@ -0,0 +1,129 @@
1
+ module Actions
2
+ module Katello
3
+ module EventQueue
4
+ class Monitor < Actions::Base
5
+ Event = Algebrick.type do
6
+ fields! event_type: String, object_id: Integer, created_at: DateTime
7
+ end
8
+
9
+ Fatal = Algebrick.type do
10
+ fields! backtrace: String, message: String, kind: String
11
+ end
12
+
13
+ Ready = Algebrick.atom
14
+ Close = Algebrick.atom
15
+
16
+ cattr_accessor :triggered_action
17
+
18
+ def self.ensure_running(world = ForemanTasks.dynflow.world)
19
+ world.coordinator.acquire(RunOnceCoordinatorLock.new(world)) do
20
+ unless ForemanTasks::Task::DynflowTask.for_action(self).running.any?
21
+ self.triggered_action = ForemanTasks.trigger(self)
22
+ end
23
+ end
24
+ rescue Dynflow::Coordinator::LockError
25
+ return false
26
+ end
27
+
28
+ def plan
29
+ # Make sure we don't have two concurrent listening services competing
30
+ if already_running?
31
+ fail "Action #{self.class.name} is already active"
32
+ end
33
+ plan_self
34
+ end
35
+
36
+ def run(event = nil)
37
+ match(event,
38
+ (on nil do
39
+ initialize_service
40
+ end),
41
+ (on Ready do
42
+ listen_for_events
43
+ end),
44
+ (on Event do
45
+ act_on_event(event)
46
+ end),
47
+ (on Close | Dynflow::Action::Cancellable::Cancel do
48
+ close_service
49
+ end),
50
+ (on Fatal do
51
+ restart_poller(event)
52
+ end),
53
+ (on Dynflow::Action::Skip do
54
+ # do nothing, just skip
55
+ end))
56
+ rescue => e
57
+ action_logger.error(e.message)
58
+ close_service
59
+ error!(e)
60
+ end
61
+
62
+ def restart_poller(_event)
63
+ suspend do |suspended_action|
64
+ SuspendedAction.new(suspended_action).notify_ready
65
+ end
66
+ end
67
+
68
+ def close_service
69
+ PollerThread.close
70
+ end
71
+
72
+ def initialize_service
73
+ ::Katello::EventQueue.reset_in_progress
74
+ PollerThread.initialize(world.logger)
75
+ suspend do |suspended_action|
76
+ SuspendedAction.new(suspended_action).notify_ready
77
+
78
+ unless Rails.env.test?
79
+ world.before_termination do
80
+ finish_service
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ def finish_service
87
+ suspended_action.ask(Close).wait
88
+ if self.class.triggered_action
89
+ self.class.triggered_action.finished.wait
90
+ else
91
+ max_attempts = 10
92
+ (1..max_attempts).each do |attempt|
93
+ task.reload
94
+ if !task.pending? || task.paused?
95
+ break
96
+ else
97
+ sleep 1 if attempt != max_attempts
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ def listen_for_events
104
+ suspend do |suspended_action|
105
+ PollerThread.instance.poll_for_events(SuspendedAction.new(suspended_action))
106
+ end
107
+ end
108
+
109
+ def act_on_event(event)
110
+ User.as_anonymous_admin do
111
+ output[:last_event] = "#{event.event_type} - #{event.object_id}"
112
+ ::Katello::EventQueue.event_class(event.event_type).new(event.object_id).run
113
+ end
114
+ rescue => e
115
+ world.logger.error(e.message)
116
+ world.logger.error(e.backtrace.join("\n"))
117
+ output[:last_error] = e.message
118
+ ensure
119
+ ::Katello::EventQueue.clear_events(event.event_type, event.object_id, event.created_at)
120
+ suspend
121
+ end
122
+
123
+ def humanized_name
124
+ _('Monitor Event Queue')
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,45 @@
1
+ module Actions
2
+ module Katello
3
+ module EventQueue
4
+ class PollerThread
5
+ SLEEP_INTERVAL = 2
6
+ cattr_accessor :instance
7
+
8
+ def self.initialize(logger)
9
+ self.instance ||= self.new(logger)
10
+ end
11
+
12
+ def self.close
13
+ self.instance.close if self.instance
14
+ self.instance = nil
15
+ end
16
+
17
+ def initialize(logger)
18
+ @logger = logger
19
+ end
20
+
21
+ def close
22
+ @thread.kill if @thread
23
+ end
24
+
25
+ def poll_for_events(suspended_action)
26
+ @thread.kill if @thread
27
+ @thread = Thread.new do
28
+ loop do
29
+ begin
30
+ until (event = ::Katello::EventQueue.next_event).nil?
31
+ suspended_action.notify_queue_item(event.event_type, event.object_id, event.created_at) if event
32
+ end
33
+
34
+ sleep SLEEP_INTERVAL
35
+ rescue => e
36
+ suspended_action.notify_fatal(e)
37
+ raise e
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,12 @@
1
+ module Actions
2
+ module Katello
3
+ module EventQueue
4
+ class RunOnceCoordinatorLock < Dynflow::Coordinator::LockByWorld
5
+ def initialize(world)
6
+ super
7
+ @data[:id] = 'katello-event-queue'
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,23 @@
1
+ module Actions
2
+ module Katello
3
+ module EventQueue
4
+ class SuspendedAction
5
+ def initialize(suspended_action)
6
+ @suspended_action = suspended_action
7
+ end
8
+
9
+ def notify_queue_item(event_type, object_id, created_at)
10
+ @suspended_action << Monitor::Event[event_type, object_id, created_at.to_datetime]
11
+ end
12
+
13
+ def notify_ready
14
+ @suspended_action << Monitor::Ready
15
+ end
16
+
17
+ def notify_fatal(error)
18
+ @suspended_action << Monitor::Fatal[error.backtrace && error.backtrace.join('\n'), error.message, error.class.name]
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -13,9 +13,8 @@ module Actions
13
13
  end
14
14
 
15
15
  def finalize
16
- ::Host.where(:id => input[:host_ids]).each do |host|
17
- host.content_facet.try(:import_applicability)
18
- host.content_facet.update_errata_status
16
+ input[:host_ids].each do |host_id|
17
+ ::Katello::EventQueue.push_event(::Katello::Events::ImportHostErrata::EVENT_TYPE, host_id)
19
18
  end
20
19
  end
21
20
  end
@@ -44,7 +44,7 @@ module Actions
44
44
 
45
45
  def humanized_name
46
46
  if input.try(:[], :hostname)
47
- _('Update for host %s') % (input[:hostname])
47
+ _('Update for host %s') % input[:hostname]
48
48
  else
49
49
  _('Update for host')
50
50
  end
@@ -11,7 +11,9 @@ module Actions
11
11
 
12
12
  def run
13
13
  repo = ::Katello::Repository.find(input[:repo_id])
14
- repo.import_host_applicability
14
+ repo.hosts_with_applicability.each do |host|
15
+ ::Katello::EventQueue.push_event(::Katello::Events::ImportHostErrata::EVENT_TYPE, host.id)
16
+ end
15
17
  end
16
18
 
17
19
  def rescue_strategy_for_self