Class: Katello::ContentViewVersion

Inherits:
Model
  • Object
show all
Includes:
ForemanTasks::Concerns::ActionSubject, Authorization::ContentViewVersion, Katello::Concerns::SearchByRepositoryName
Defined in:
app/models/katello/content_view_version.rb

Overview

rubocop:disable Metrics/ClassLength

Defined Under Namespace

Classes: Jail

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Authorization::ContentViewVersion

#all_hosts_editable?

Methods inherited from Model

#destroy!

Class Method Details

.component_of(versions) ⇒ Object



96
97
98
# File 'app/models/katello/content_view_version.rb', line 96

def self.component_of(versions)
  joins(:content_view_version_composites).where("#{Katello::ContentViewVersionComponent.table_name}.composite_version_id" => versions)
end

.contains_file(file_unit_id) ⇒ Object



120
121
122
# File 'app/models/katello/content_view_version.rb', line 120

def self.contains_file(file_unit_id)
  where(id: Katello::Repository.where(id: Katello::RepositoryFileUnit.where(file_unit_id: file_unit_id).select(:repository_id)).select(:content_view_version_id))
end

.find_by_version(_key, operator, value) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'app/models/katello/content_view_version.rb', line 78

def self.find_by_version(_key, operator, value)
  conditions = ""
  if ['>', '<', '=', '<=', '>=', "<>", "!=", 'IN', 'NOT IN'].include?(operator) && value.to_f >= 0
    major, minor = value.split(".")
    case
    when /[<>]/ =~ operator
      minor ||= 0
      query = where("major #{operator} :major OR (major = :major AND minor #{operator} :minor)", :major => major, :minor => minor)
    when minor.nil?
      query = where("major #{operator} (:major)", :major => major)
    else
      query = where("major #{operator} (:major) and minor #{operator} (:minor)", :major => major, :minor => minor)
    end
    _, conditions = query.to_sql.split("WHERE")
  end
  { :conditions => conditions }
end

.for_version(version) ⇒ Object



104
105
106
107
108
# File 'app/models/katello/content_view_version.rb', line 104

def self.for_version(version)
  major, minor = version.to_s.split('.')
  minor ||= 0
  where(:major => major, :minor => minor)
end

.in_environment(env) ⇒ Object



224
225
226
# File 'app/models/katello/content_view_version.rb', line 224

def self.in_environment(env)
  joins(:content_view_environments).where("#{Katello::ContentViewEnvironment.table_name}.environment_id" => env)
end

.with_library_repo(repo) ⇒ Object



100
101
102
# File 'app/models/katello/content_view_version.rb', line 100

def self.with_library_repo(repo)
  joins(:repositories).where("#{Katello::Repository.table_name}.library_instance_id" => repo)
end

Instance Method Details

#active_historyObject



130
131
132
# File 'app/models/katello/content_view_version.rb', line 130

def active_history
  self.history.select { |history| history.task.try(:pending) }
end

#add_applied_filters!Object



434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
# File 'app/models/katello/content_view_version.rb', line 434

def add_applied_filters!
  applied_filters_and_rules = content_view.filters.map do |f|
    {
      filter: f,
      rules: f.rules,
      affected_repos: f.applicable_repos.map do |repo|
        repo.slice(:id, :name, :label, :arch, :major, :minor,
                   :content_type, :os_versions, :url, :content_id).merge(redhat: repo.redhat?, root: repo.root.id,
                                                                         product: repo.product.slice(:id, :label))
      end,
    }
  end
  self.applied_filters = {
    applied_filters: applied_filters_and_rules,
    dependency_solving: content_view.solve_dependencies,
  }
  save!
end

#after_promote_hooksObject



427
428
429
430
431
432
# File 'app/models/katello/content_view_version.rb', line 427

def after_promote_hooks
  run_callbacks :sync do
    logger.debug "custom hook after_promote on #{name} will be executed if defined."
    true
  end
end

#ansible_collectionsObject



124
125
126
# File 'app/models/katello/content_view_version.rb', line 124

def ansible_collections
  AnsibleCollection.in_repositories(archived_repos)
end

#archived_reposObject



190
191
192
# File 'app/models/katello/content_view_version.rb', line 190

def archived_repos
  (self.default? || self.rolling?) ? self.repositories : self.repos(nil)
end

#available_debsObject



305
306
307
# File 'app/models/katello/content_view_version.rb', line 305

def available_debs
  library_packages.where.not(:id => debs)
end

#available_errataObject



319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'app/models/katello/content_view_version.rb', line 319

def available_errata
  # The simple/obvious solution is:
  #   library_errata.where.not(:id => errata)
  # However, when the list of exclusions is large, the SQL "NOT IN" clause
  # is extremely inefficient, and it is much better to use a
  # "LEFT OUTER JOIN" with a subquery.
  # ActiveRecord .joins() only supports subqueries by supplying raw SQL.  We
  # use .to_sql to avoid hard-coding raw SQL for self.errata, although
  # .to_sql may also be somewhat brittle.  For example, see:
  # https://github.com/rails/rails/issues/18379
  library_errata.joins(
    "LEFT OUTER JOIN (#{errata.select('id').to_sql}) AS exclude_errata ON " \
    'katello_errata.id = exclude_errata.id'
  ).where('exclude_errata.id IS NULL')
end

#available_packagesObject



268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'app/models/katello/content_view_version.rb', line 268

def available_packages
  # The simple/obvious solution is:
  #   library_packages.where.not(:id => packages)
  # However, when the list of exclusions is large, the SQL "NOT IN" clause
  # is extremely inefficient, and it is much better to use a
  # "LEFT OUTER JOIN" with a subquery.
  # ActiveRecord .joins() only supports subqueries by supplying raw SQL.  We
  # use .to_sql to avoid hard-coding raw SQL for self.packages, although
  # .to_sql may also be somewhat brittle.  For example, see:
  # https://github.com/rails/rails/issues/18379
  library_packages.joins(
    "LEFT OUTER JOIN (#{packages.select('id').to_sql}) AS exclude_rpms ON " \
    'katello_rpms.id = exclude_rpms.id'
  ).where('exclude_rpms.id IS NULL')
end

#available_releasesObject



170
171
172
# File 'app/models/katello/content_view_version.rb', line 170

def available_releases
  Katello::RootRepository.where(:id => self.repositories.select(:root_id)).pluck(:minor).compact.uniq.sort
end

#before_promote_hooksObject



420
421
422
423
424
425
# File 'app/models/katello/content_view_version.rb', line 420

def before_promote_hooks
  run_callbacks :sync do
    logger.debug "custom hook before_promote on #{name} will be executed if defined."
    true
  end
end

#check_ready_to_promote!(to_env) ⇒ Object



382
383
384
385
386
387
# File 'app/models/katello/content_view_version.rb', line 382

def check_ready_to_promote!(to_env)
  fail _("Default and Rolling content view versions cannot be promoted") if default? || rolling?
  content_view.check_composite_action_allowed!(to_env)
  content_view.check_docker_repository_names!(to_env)
  content_view.check_orphaned_content_facets!(environments: [to_env])
end

#components_needing_errata(errata) ⇒ Object



249
250
251
252
253
254
# File 'app/models/katello/content_view_version.rb', line 249

def components_needing_errata(errata)
  component_repos = Repository.where(:content_view_version_id => self.components)
  library_repos = Repository.where(:id => component_repos.pluck(:library_instance_id)).with_errata(errata)
  component_repos -= component_repos.with_errata(errata) #find component repos without the errata
  component_repos.select { |repo| library_repos.include?(repo.library_instance) }.map(&:content_view_version).uniq
end

#content_counts_mapObject



374
375
376
377
378
379
380
# File 'app/models/katello/content_view_version.rb', line 374

def content_counts_map
  # if its empty, calculate it on demand
  update_content_counts! if content_counts.blank?
  counts = Hash[content_counts.map { |key, value| ["#{key}_count", value] }]
  counts.merge("module_stream_count" => counts["modulemd_count"],
               "package_count" => counts["rpm_count"])
end

#debsObject



297
298
299
# File 'app/models/katello/content_view_version.rb', line 297

def debs
  Katello::Deb.in_repositories(self.repositories.archived)
end

#default_content_view?Boolean

Returns:

  • (Boolean)


150
151
152
# File 'app/models/katello/content_view_version.rb', line 150

def default_content_view?
  default?
end

#deletable?(from_env) ⇒ Boolean

Returns:

  • (Boolean)


236
237
238
239
# File 'app/models/katello/content_view_version.rb', line 236

def deletable?(from_env)
  ::Host.in_content_view_environment(self.content_view, from_env).empty? ||
      self.content_view.versions.in_environment(from_env).count > 1
end

#descriptionObject



146
147
148
# File 'app/models/katello/content_view_version.rb', line 146

def description
  history.publish.first.try(:notes)
end

#docker_manifest_listsObject



343
344
345
# File 'app/models/katello/content_view_version.rb', line 343

def docker_manifest_lists
  DockerManifestList.in_repositories(archived_repos)
end

#docker_manifestsObject



339
340
341
# File 'app/models/katello/content_view_version.rb', line 339

def docker_manifests
  DockerManifest.in_repositories(archived_repos)
end

#docker_tagsObject



292
293
294
295
# File 'app/models/katello/content_view_version.rb', line 292

def docker_tags
  # Don't count tags from non-archived repos; this causes count errors
  ::Katello::DockerMetaTag.where(:id => RepositoryDockerMetaTag.where(:repository_id => repositories.archived.docker_type).select(:docker_meta_tag_id))
end

#env_promote_date(env) ⇒ Object



138
139
140
# File 'app/models/katello/content_view_version.rb', line 138

def env_promote_date(env)
  Katello::ContentViewEnvironment.where(:environment_id => env.id, :content_view_version_id => self.id).pluck(:updated_at).try(:first)
end

#errata(errata_type = nil) ⇒ Object



309
310
311
312
313
# File 'app/models/katello/content_view_version.rb', line 309

def errata(errata_type = nil)
  errata = Erratum.in_repositories(archived_repos)
  errata = errata.of_type(errata_type) if errata_type
  errata
end

#file_unitsObject



335
336
337
# File 'app/models/katello/content_view_version.rb', line 335

def file_units
  FileUnit.in_repositories(archived_repos)
end

#filters_applied?Boolean

Returns:

  • (Boolean)


453
454
455
456
457
458
# File 'app/models/katello/content_view_version.rb', line 453

def filters_applied?
  # For older content view versions, we do not know if filters were applied.
  # For these, return nil.
  return nil if applied_filters.nil?
  applied_filters["applied_filters"].present?
end

#generic_content_units(content_type) ⇒ Object



260
261
262
# File 'app/models/katello/content_view_version.rb', line 260

def generic_content_units(content_type)
  GenericContentUnit.in_repositories(archived_repos).where(content_type: content_type)
end

#get_repo_clone(env, repo) ⇒ Object



219
220
221
222
# File 'app/models/katello/content_view_version.rb', line 219

def get_repo_clone(env, repo)
  lib_id = repo.library_instance_id || repo.id
  self.repos(env).where("#{Katello::Repository.table_name}.library_instance_id" => lib_id)
end

#importable_repositoriesObject



412
413
414
415
416
417
418
# File 'app/models/katello/content_view_version.rb', line 412

def importable_repositories
  if default?
    repositories.exportable
  else
    archived_repos.exportable
  end
end

#in_composite?Boolean

Returns:

  • (Boolean)


158
159
160
# File 'app/models/katello/content_view_version.rb', line 158

def in_composite?
  composite_content_views.any?
end

#in_environment?Boolean

Returns:

  • (Boolean)


166
167
168
# File 'app/models/katello/content_view_version.rb', line 166

def in_environment?
  environments.any?
end

#incrementally_updated?Boolean

Returns:

  • (Boolean)


182
183
184
# File 'app/models/katello/content_view_version.rb', line 182

def incrementally_updated?
  minor != 0
end

#last_eventObject



134
135
136
# File 'app/models/katello/content_view_version.rb', line 134

def last_event
  self.history.order(:created_at).last
end

#latest?Boolean

Returns:

  • (Boolean)


154
155
156
# File 'app/models/katello/content_view_version.rb', line 154

def latest?
  content_view.latest_version_id == self.id
end

#library_debsObject



301
302
303
# File 'app/models/katello/content_view_version.rb', line 301

def library_debs
  Katello::Deb.in_repositories(library_repos)
end

#library_errataObject



315
316
317
# File 'app/models/katello/content_view_version.rb', line 315

def library_errata
  Erratum.in_repositories(library_repos)
end

#library_packagesObject



264
265
266
# File 'app/models/katello/content_view_version.rb', line 264

def library_packages
  Rpm.in_repositories(library_repos)
end

#library_reposObject



198
199
200
# File 'app/models/katello/content_view_version.rb', line 198

def library_repos
  archived_repos.includes(:library_instance).map(&:library_instance)
end

#module_streamsObject



288
289
290
# File 'app/models/katello/content_view_version.rb', line 288

def module_streams
  ModuleStream.in_repositories(archived_repos)
end

#nameObject



142
143
144
# File 'app/models/katello/content_view_version.rb', line 142

def name
  "#{content_view} #{version}"
end

#next_incremental_versionObject



174
175
176
# File 'app/models/katello/content_view_version.rb', line 174

def next_incremental_version
  "#{major}.#{minor + 1}"
end

#non_archive_reposObject



194
195
196
# File 'app/models/katello/content_view_version.rb', line 194

def non_archive_repos
  self.repositories.non_archived
end

#package_groupsObject



347
348
349
# File 'app/models/katello/content_view_version.rb', line 347

def package_groups
  PackageGroup.in_repositories(archived_repos)
end

#packagesObject



256
257
258
# File 'app/models/katello/content_view_version.rb', line 256

def packages
  Rpm.in_repositories(archived_repos)
end

#products(env = nil) ⇒ Object



202
203
204
205
206
207
208
# File 'app/models/katello/content_view_version.rb', line 202

def products(env = nil)
  if env
    repos(env).map(&:product).uniq(&:id)
  else
    self.repositories.map(&:product).uniq(&:id)
  end
end

#promotable?(target_envs) ⇒ Boolean

Returns:

  • (Boolean)


241
242
243
244
245
246
247
# File 'app/models/katello/content_view_version.rb', line 241

def promotable?(target_envs)
  target_envs = Array.wrap(target_envs)
  all_environments = target_envs + environments
  target_envs.all? do |environment|
    all_environments.include?(environment.prior) || environments.empty? && environment == organization.library
  end
end

#published_in_composite?Boolean

Returns:

  • (Boolean)


162
163
164
# File 'app/models/katello/content_view_version.rb', line 162

def published_in_composite?
  content_view_version_composites.any?
end

#rabl_pathObject



460
461
462
# File 'app/models/katello/content_view_version.rb', line 460

def rabl_path
  "katello/api/v2/#{self.class.to_s.demodulize.tableize}/show"
end

#removable?Boolean

Returns:

  • (Boolean)


228
229
230
231
232
233
234
# File 'app/models/katello/content_view_version.rb', line 228

def removable?
  if environments.blank?
    content_view.promotable_or_removable?
  else
    content_view.promotable_or_removable? && KTEnvironment.where(:id => environments).any_promotable?
  end
end

#repos(env) ⇒ Object



186
187
188
# File 'app/models/katello/content_view_version.rb', line 186

def repos(env)
  self.repositories.in_environment(env)
end

#repos_ordered_by_product(env) ⇒ Object



210
211
212
213
214
215
216
217
# File 'app/models/katello/content_view_version.rb', line 210

def repos_ordered_by_product(env)
  # The repository model has a default scope that orders repositories by name;
  # however, for content views, it is desirable to order the repositories
  # based on the name of the product the repository is part of.
  Repository.send(:with_exclusive_scope) do
    self.repositories.joins(:product).in_environment(env).order("#{Katello::Product.table_name}.name asc")
  end
end

#repository_type_counts_mapObject



366
367
368
369
370
371
372
# File 'app/models/katello/content_view_version.rb', line 366

def repository_type_counts_map
  counts = {}
  Katello::RepositoryTypeManager.enabled_repository_types.keys.each do |repo_type|
    counts["#{repo_type}_repository_count"] = archived_repos.with_type(repo_type).count
  end
  counts
end

#sorted_organization_readable_environmentsObject



114
115
116
117
118
# File 'app/models/katello/content_view_version.rb', line 114

def sorted_organization_readable_environments
  organization_readable_environments = organization.readable_promotion_paths.flatten
  organization_readable_environments.insert(0, organization.library)
  organization_readable_environments.intersection(environments)
end

#srpmsObject



284
285
286
# File 'app/models/katello/content_view_version.rb', line 284

def srpms
  Katello::Srpm.in_repositories(self.repositories)
end

#to_sObject



110
111
112
# File 'app/models/katello/content_view_version.rb', line 110

def to_s
  name
end

#update_content_counts!Object



351
352
353
354
355
356
357
358
359
360
361
362
363
364
# File 'app/models/katello/content_view_version.rb', line 351

def update_content_counts!
  self.content_counts = {}
  RepositoryTypeManager.indexable_content_types.each do |content_type|
    case content_type&.model_class::CONTENT_TYPE
    when DockerTag::CONTENT_TYPE
      content_counts[DockerTag::CONTENT_TYPE] = docker_tags.count
    when GenericContentUnit::CONTENT_TYPE
      content_counts[content_type.content_type] = content_type&.model_class&.in_repositories(self.repositories.archived)&.where(:content_type => content_type.content_type)&.count
    else
      content_counts[content_type&.model_class::CONTENT_TYPE] = content_type&.model_class&.in_repositories(self.repositories.archived)&.count
    end
  end
  save!
end

#validate_destroyable!(skip_environment_check: false) ⇒ Object



389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
# File 'app/models/katello/content_view_version.rb', line 389

def validate_destroyable!(skip_environment_check: false)
  unless organization.being_deleted?
    if !skip_environment_check && in_environment?
      fail _("Cannot delete version while it is in environments: %s") %
               environments.map(&:name).join(",")
    end

    if in_composite?
      fail _("Cannot delete version while it is in use by composite content views: %s") %
               composite_content_views.map(&:name).join(",")
    end

    if published_in_composite?
      list = composites.map do |version|
        "#{version.content_view.name} Version #{version.version}"
      end
      fail _("Cannot delete version while it is in use by composite content views: %s") %
               list.join(",")
    end
  end
  true
end

#versionObject



178
179
180
# File 'app/models/katello/content_view_version.rb', line 178

def version
  "#{major}.#{minor}"
end