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?

Class Method Details

.component_of(versions) ⇒ Object



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

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



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

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



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

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



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

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

.in_environment(env) ⇒ Object



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

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

.with_library_repo(repo) ⇒ Object



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

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

Instance Method Details

#active_historyObject



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

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

#add_applied_filters!Object



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

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



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

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



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

def ansible_collections
  AnsibleCollection.in_repositories(archived_repos)
end

#archived_reposObject



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

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

#available_debsObject



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

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

#available_errataObject



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

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



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

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



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

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

#before_promote_hooksObject



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

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



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

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



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

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



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

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



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

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

#default_content_view?Boolean

Returns:

  • (Boolean)


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

def default_content_view?
  default?
end

#deletable?(from_env) ⇒ Boolean

Returns:

  • (Boolean)


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

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



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

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

#docker_manifest_listsObject



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

def docker_manifest_lists
  DockerManifestList.in_repositories(archived_repos)
end

#docker_manifestsObject



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

def docker_manifests
  DockerManifest.in_repositories(archived_repos)
end

#docker_tagsObject



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

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



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

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



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

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

#file_unitsObject



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

def file_units
  FileUnit.in_repositories(archived_repos)
end

#filters_applied?Boolean

Returns:

  • (Boolean)


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

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



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

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

#get_repo_clone(env, repo) ⇒ Object



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

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



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

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

#in_composite?Boolean

Returns:

  • (Boolean)


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

def in_composite?
  composite_content_views.any?
end

#in_environment?Boolean

Returns:

  • (Boolean)


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

def in_environment?
  environments.any?
end

#incrementally_updated?Boolean

Returns:

  • (Boolean)


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

def incrementally_updated?
  minor != 0
end

#last_eventObject



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

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

#latest?Boolean

Returns:

  • (Boolean)


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

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

#library_debsObject



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

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

#library_errataObject



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

def library_errata
  Erratum.in_repositories(library_repos)
end

#library_packagesObject



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

def library_packages
  Rpm.in_repositories(library_repos)
end

#library_reposObject



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

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

#module_streamsObject



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

def module_streams
  ModuleStream.in_repositories(archived_repos)
end

#nameObject



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

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

#next_incremental_versionObject



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

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

#non_archive_reposObject



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

def non_archive_repos
  self.repositories.non_archived
end

#package_groupsObject



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

def package_groups
  PackageGroup.in_repositories(archived_repos)
end

#packagesObject



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

def packages
  Rpm.in_repositories(archived_repos)
end

#products(env = nil) ⇒ Object



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

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)


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

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)


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

def published_in_composite?
  content_view_version_composites.any?
end

#rabl_pathObject



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

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

#removable?Boolean

Returns:

  • (Boolean)


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

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



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

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

#repos_ordered_by_product(env) ⇒ Object



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

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



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

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



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

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



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

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

#to_sObject



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

def to_s
  name
end

#update_content_counts!Object



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

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



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

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



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

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