Class: Katello::ContentView

Inherits:
Model
  • Object
show all
Includes:
Foreman::ObservableModel, ForemanTasks::Concerns::ActionSubject, Authorization::ContentView, Ext::LabelFromName
Defined in:
app/models/katello/content_view.rb

Overview

rubocop:disable Metrics/ClassLength

Defined Under Namespace

Classes: Jail

Constant Summary collapse

CONTENT_DIR =
"content_views".freeze
IMPORT_LIBRARY =
"Import-Library".freeze
EXPORT_LIBRARY =
"Export-Library".freeze

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Authorization::ContentView

#deletable?, #editable?, #promotable_or_removable?, #publishable?, #readable?

Methods included from Ext::LabelFromName

included, #label_not_changed, #setup_label_from_name

Methods inherited from Model

#destroy!

Class Method Details

.completer_scope_options(search) ⇒ Object



147
148
149
150
151
152
153
154
# File 'app/models/katello/content_view.rb', line 147

def self.completer_scope_options(search)
  if search.include?('content_views')
    # Don't autocomplete CCV names when searching for components
    { :value_filter => { :composite => false } }
  else
    {}
  end
end

.find_components_by_cv_name(_key, operator, value) ⇒ Object



139
140
141
142
143
144
145
# File 'app/models/katello/content_view.rb', line 139

def self.find_components_by_cv_name(_key, operator, value)
  kcv = Katello::ContentView.table_name
  kcvc = Katello::ContentViewComponent.table_name
  { :conditions => "#{kcv}.composite = 't' AND #{kcv}.id IN (SELECT #{kcvc}.composite_content_view_id FROM #{kcvc} WHERE #{kcvc}.content_view_id IN (SELECT #{kcv}.id FROM #{kcv} WHERE #{kcv}.name #{operator} ?))",
    :parameter => [value],
  }
end

.humanize_class_name(_name = nil) ⇒ Object



772
773
774
# File 'app/models/katello/content_view.rb', line 772

def self.humanize_class_name(_name = nil)
  _("Content Views")
end

.in_environment(env) ⇒ Object



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

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

.in_organization(org) ⇒ Object



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

def self.in_organization(org)
  where(organization_id: org.id) unless org.nil?
end

.published_with_repositories(root_repository) ⇒ Object



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

def self.published_with_repositories(root_repository)
  joins(:content_view_versions => :repositories).where("katello_repositories.root_id" => root_repository.id).uniq
end

Instance Method Details

#add_components(components_to_add) ⇒ Object

Adds content view components based on the input

:latest=> false, :latest=> true ..


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

def add_components(components_to_add)
  components_to_add.each do |cvc|
    content_view_components.build(cvc)
  end
end

#add_environment(env, version) ⇒ Object

Associate an environment with this content view. This can occur whenever a version of the view is promoted to an environment. It is necessary for candlepin to become aware that the view is available for consumers.



595
596
597
598
599
600
601
602
603
604
605
606
# File 'app/models/katello/content_view.rb', line 595

def add_environment(env, version)
  if self.content_view_environments.where(:environment_id => env.id).empty?
    label = generate_cp_environment_label(env)
    ContentViewEnvironment.create!(:name => label,
                                   :label => label,
                                   :cp_id => generate_cp_environment_id(env),
                                   :environment_id => env.id,
                                   :content_view => self,
                                   :content_view_version => version
    )
  end
end

#all_version_library_instancesObject

get the library instances of all repos within this view



509
510
511
512
513
# File 'app/models/katello/content_view.rb', line 509

def all_version_library_instances
  all_repos = all_version_repos.where(:library_instance_id => nil).pluck("#{Katello::Repository.table_name}.id")
  all_repos += all_version_repos.pluck(:library_instance_id)
  Repository.where(:id => all_repos)
end

#all_version_reposObject



403
404
405
406
# File 'app/models/katello/content_view.rb', line 403

def all_version_repos
  Repository.joins(:content_view_version).
    where("#{Katello::ContentViewVersion.table_name}.content_view_id" => self.id)
end

#as_json(options = {}) ⇒ Object

NOTE: this function will most likely become obsolete once we drop api v1



311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
# File 'app/models/katello/content_view.rb', line 311

def as_json(options = {})
  result = self.attributes
  result['organization'] = self.organization.try(:name)
  result['environments'] = environments.map { |e| e.try(:name) }
  result['versions'] = versions.map(&:version)
  result['versions_details'] = versions.map do |v|
    {
      :version => v.version,
      :published => v.created_at.to_s,
      :environments => v.environments.map { |e| e.name },
    }
  end

  if options && options[:environment].present?
    result['repositories'] = repos(options[:environment]).map(&:name)
  end

  result
end

#audited_changes_present?Boolean

Returns:



877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
# File 'app/models/katello/content_view.rb', line 877

def audited_changes_present?
  latest_version_created_at = latest_version_object.created_at
  cv_repository_ids = repositories.pluck(:id)

  audited_changes_like = ->(param) {
    Arel.sql("#{Audit.table_name}.audited_changes ilike '%#{param}%'")
  }

  table = Audit.arel_table
  repository_condition = table[:auditable_id].eq(id)
                                             .and(table[:auditable_type].eq('Katello::ContentView'))
                                             .and(audited_changes_like.call("repository_ids"))

  cv_repository_condition = table[:auditable_id].in(cv_repository_ids)
                                                .and(table[:auditable_type].eq('Katello::Repository'))
                                                .and(Arel.sql("(#{audited_changes_like.call("publication_href")} OR #{audited_changes_like.call("version_href")})"))

  content_view_filter_condition = table[:auditable_type].eq('Katello::ContentViewFilter').and(table[:associated_id].eq(id))

  filter_rule_condition = table[:associated_id].eq(id).and(table[:auditable_type].matches('%FilterRule%'))

  base_query = table[:created_at].gt(latest_version_created_at)

  final_query = base_query.and(repository_condition.or(cv_repository_condition).or(content_view_filter_condition).or(filter_rule_condition))

  Audit.where(final_query).exists?
end

#auto_publish_componentsObject



453
454
455
# File 'app/models/katello/content_view.rb', line 453

def auto_publish_components
  component_composites.where(latest: true).joins(:composite_content_view).where(self.class.table_name => { auto_publish: true })
end

#auto_publish_compositesObject



457
458
459
# File 'app/models/katello/content_view.rb', line 457

def auto_publish_composites
  Katello::ContentView.joins(:content_view_components).merge(auto_publish_components)
end

#blocking_taskObject



913
914
915
916
917
918
919
920
921
922
# File 'app/models/katello/content_view.rb', line 913

def blocking_task
  blocking_task_labels = [
    ::Actions::Katello::ContentView::Publish.name,
  ]
  ForemanTasks::Task::DynflowTask.where(:label => blocking_task_labels)
                                 .where.not(state: 'stopped')
                                 .for_resource(self)
                                 .order(:started_at)
                                 .last
end

#check_composite_action_allowed!(env) ⇒ Object



697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
# File 'app/models/katello/content_view.rb', line 697

def check_composite_action_allowed!(env)
  if composite? && Setting['restrict_composite_view']
    if components.size != content_view_components.size
      fail _("Make sure all the component content views are published before publishing/promoting the composite content view. "\
           "This restriction is optional and can be modified in the Administrator -> Settings -> Content "\
            "page using the restrict_composite_view flag.")
    end

    env_ids = env.try(:pluck, 'id') || []
    env_ids << env.id unless env_ids.size > 0
    components.each do |component|
      component_environment_ids = component.environments.pluck('id')
      unless (env_ids - component_environment_ids).empty?
        fail _("The action requested on this composite view cannot be performed until all of the "\
               "component content view versions have been promoted to the target environment: %{env}.  "\
               "This restriction is optional and can be modified in the Administrator -> Settings -> Content "\
               "page using the restrict_composite_view flag.") %
               { :env => env.try(:pluck, 'name') || env.name }
      end
    end
  end
  true
end

#check_default_label_nameObject



569
570
571
572
573
# File 'app/models/katello/content_view.rb', line 569

def check_default_label_name
  if default? && !(name == 'Default Organization View' && label == 'Default_Organization_View')
    errors.add(:base, _("Name and label of default content view should not be changed"))
  end
end

#check_docker_conflictsObject



575
576
577
578
579
580
# File 'app/models/katello/content_view.rb', line 575

def check_docker_conflicts
  duplicate_docker_repos.each do |repo|
    msg = _("Container Image repo '%{repo}' is present in multiple component content views.") % { repo: repo.name }
    errors.add(:base, msg)
  end
end

#check_docker_repository_names!(environments) ⇒ Object



680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
# File 'app/models/katello/content_view.rb', line 680

def check_docker_repository_names!(environments)
  environments.each do |environment|
    repositories = []
    publish_repositories do |all_repositories|
      repositories += all_repositories.keep_if { |repository| repository.content_type == Katello::Repository::DOCKER_TYPE }
    end
    next if repositories.empty?

    error_messages = ::Katello::Validators::EnvironmentDockerRepositoriesValidator.validate_repositories(environment.registry_name_pattern, repositories)
    unless error_messages.empty?
      error_messages << _("Consider changing the Lifecycle Environment's Registry Name Pattern to something more specific.")
      fail error_messages.join("  ")
    end
  end
  true
end

#check_non_composite_auto_publishObject



563
564
565
566
567
# File 'app/models/katello/content_view.rb', line 563

def check_non_composite_auto_publish
  if !composite? && auto_publish
    errors.add(:base, _("Cannot set auto publish to a non-composite content view"))
  end
end

#check_non_composite_componentsObject



557
558
559
560
561
# File 'app/models/katello/content_view.rb', line 557

def check_non_composite_components
  if !composite? && components.present?
    errors.add(:base, _("Cannot add component versions to a non-composite content view"))
  end
end

#check_orphaned_content_facets!(environments: []) ⇒ Object



721
722
723
724
725
726
727
728
729
730
731
# File 'app/models/katello/content_view.rb', line 721

def check_orphaned_content_facets!(environments: [])
  Location.no_taxonomy_scope do
    User.as_anonymous_admin do
      ::Katello::Host::ContentFacet.with_content_views(self).with_environments(environments).each do |facet|
        unless facet.host
          fail _("Orphaned content facets for deleted hosts exist for the content view and environment. Please run rake task : katello:clean_orphaned_facets and try again!")
        end
      end
    end
  end
end

#check_ready_to_destroy!Object



752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
# File 'app/models/katello/content_view.rb', line 752

def check_ready_to_destroy!
  check_orphaned_content_facets!(environments: self.environments)
  errors = []

  dependencies = { environments: _("environments"),
                   hosts: _("hosts"),
                   activation_keys: _("activation keys"),
  }

  dependencies.each do |key, name|
    if (models = self.association(key).scope).any?
      errors << _("Cannot delete '%{view}' due to associated %{dependent}: %{names}.") %
        { view: self.name, dependent: name, names: models.map(&:name).join(", ") }
    end
  end

  fail errors.join(" ") if errors.any?
  return true
end

#check_ready_to_import!Object



647
648
649
650
651
# File 'app/models/katello/content_view.rb', line 647

def check_ready_to_import!
  fail _("Cannot import a composite content view") if composite?
  fail _("This Content View must be set to Import-only before performing an import") unless import_only?
  true
end

#check_ready_to_publish!(importing: false, syncable: false) ⇒ Object



653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
# File 'app/models/katello/content_view.rb', line 653

def check_ready_to_publish!(importing: false, syncable: false)
  fail _("User must be logged in.") if ::User.current.nil?
  fail _("Cannot publish default content view") if default?

  if importing
    check_ready_to_import!
  else
    fail _("Import-only content views can not be published directly") if import_only? && !syncable
    check_repositories_blocking_publish!
    check_composite_action_allowed!(organization.library)
    check_docker_repository_names!([organization.library])
    check_orphaned_content_facets!(environments: self.environments)
  end

  true
end

#check_remove_from_environment!(env) ⇒ Object



733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
# File 'app/models/katello/content_view.rb', line 733

def check_remove_from_environment!(env)
  check_orphaned_content_facets!(environments: [env])
  errors = []

  dependencies = { hosts: _("hosts"),
                   activation_keys: _("activation keys"),
  }

  dependencies.each do |key, name|
    if (models = self.association(key).scope.in_environments(env)).any?
      errors << _("Cannot remove '%{view}' from environment '%{env}' due to associated %{dependent}: %{names}.") %
        { view: self.name, env: env.name, dependent: name, names: models.map(&:name).join(", ") }
    end
  end

  fail errors.join(" ") if errors.any?
  return true
end

#check_repositories_blocking_publish!Object



670
671
672
673
674
675
676
677
678
# File 'app/models/katello/content_view.rb', line 670

def check_repositories_blocking_publish!
  blocking_tasks = repositories&.map { |repo| repo.blocking_task }&.compact

  if blocking_tasks&.any?
    errored_tasks = blocking_tasks.uniq.map { |task| "- #{Setting['foreman_url']}/foreman_tasks/tasks/#{task&.id}" }.join("\n")
    fail _("Pending tasks detected in repositories of this content view. Please wait for the tasks: " +
             errored_tasks + " before publishing.")
  end
end

#component_idsObject



214
215
216
# File 'app/models/katello/content_view.rb', line 214

def component_ids
  components.map(&:id)
end

#component_ids=(component_version_ids_to_set) ⇒ Object

Warning this call wipes out existing associations And replaces them with the component version ids passed in.



242
243
244
245
246
247
248
249
250
# File 'app/models/katello/content_view.rb', line 242

def component_ids=(component_version_ids_to_set)
  content_view_components.destroy_all
  component_version_ids_to_set.each do |content_view_version_id|
    cvv = ContentViewVersion.find(content_view_version_id)
    content_view_components.build(:content_view_version => cvv,
                                  :latest => false,
                                  :composite_content_view => self)
  end
end

#component_repositoriesObject



486
487
488
# File 'app/models/katello/content_view.rb', line 486

def component_repositories
  components.map(&:archived_repos).flatten
end

#component_repository_idsObject



490
491
492
# File 'app/models/katello/content_view.rb', line 490

def component_repository_ids
  component_repositories.map(&:id)
end

#componentsObject



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

def components
  content_view_components.map(&:latest_version).compact.freeze
end

#components_with_repo(library_instance) ⇒ Object



449
450
451
# File 'app/models/katello/content_view.rb', line 449

def components_with_repo(library_instance)
  components.select { |component| component.repositories.where(:library_instance => library_instance).any? }
end

#composite_cv_components_changed?Boolean

Returns:



807
808
809
810
811
812
813
814
815
# File 'app/models/katello/content_view.rb', line 807

def composite_cv_components_changed?
  return true unless latest_version_object
  published_component_version_ids = latest_version_object.components.pluck(:id) || []
  unpublished_component_version_ids = content_view_components.where(latest: false).pluck(:content_view_version_id) || []
  content_view_components.where(latest: true).each do |latest_component|
    unpublished_component_version_ids << latest_component.content_view&.latest_version_object&.id
  end
  published_component_version_ids.compact.uniq.sort != unpublished_component_version_ids.compact.uniq.sort
end

#content_host_countObject



210
211
212
# File 'app/models/katello/content_view.rb', line 210

def content_host_count
  hosts.size
end

#content_view_environment(environment) ⇒ Object



582
583
584
# File 'app/models/katello/content_view.rb', line 582

def content_view_environment(environment)
  self.content_view_environments.where(:environment_id => environment.try(:id)).first
end

#copy(new_name) ⇒ Object



287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'app/models/katello/content_view.rb', line 287

def copy(new_name)
  new_view = ContentView.new
  new_view.name = new_name
  new_view.attributes = self.attributes.slice("description", "organization_id", "default", "composite", "solve_dependencies")
  new_view.save!
  new_view.repositories = self.repositories

  copy_components(new_view)

  copy_filters(new_view)
  new_view.save!
  new_view
end

#copy_components(new_view) ⇒ Object



252
253
254
255
256
257
258
# File 'app/models/katello/content_view.rb', line 252

def copy_components(new_view)
  self.content_view_components.each do |cvc|
    component = cvc.dup
    component.composite_content_view = new_view
    new_view.content_view_components << component
  end
end

#copy_filters(new_view) ⇒ Object



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# File 'app/models/katello/content_view.rb', line 260

def copy_filters(new_view)
  self.filters.each do |filter|
    new_filter = filter.dup
    new_filter.repositories = filter.repositories
    new_view.filters << new_filter

    case filter.type
    when ContentViewDebFilter.name
      filter.deb_rules.each do |rule|
        new_filter.deb_rules << rule.dup
      end
    when ContentViewPackageFilter.name
      filter.package_rules.each do |rule|
        new_filter.package_rules << rule.dup
      end
    when ContentViewPackageGroupFilter.name
      filter.package_group_rules.each do |rule|
        new_filter.package_group_rules << rule.dup
      end
    when ContentViewErratumFilter.name
      filter.erratum_rules.each do |rule|
        new_filter.erratum_rules << rule.dup
      end
    end
  end
end

#cp_environment_id(env) ⇒ Object



624
625
626
# File 'app/models/katello/content_view.rb', line 624

def cp_environment_id(env)
  ContentViewEnvironment.where(:content_view_id => self, :environment_id => env).first.try(:cp_id)
end

#cp_environment_label(env) ⇒ Object



620
621
622
# File 'app/models/katello/content_view.rb', line 620

def cp_environment_label(env)
  ContentViewEnvironment.where(:content_view_id => self, :environment_id => env).first.try(:label)
end

#create_new_version(major = next_version, minor = 0, components = self.components) ⇒ Object



628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
# File 'app/models/katello/content_view.rb', line 628

def create_new_version(major = next_version, minor = 0, components = self.components)
  version = ContentViewVersion.create!(:major => major,
                                       :minor => minor,
                                       :content_view => self,
                                       :components => components
  )

  # TODO: If a controller creates a new version and then uses latest_version_object, the old data is displayed.
  #       To prevent this, a 'reload' would currently be necessary, but this is not very performant.
  #       However, this is currently not a problem because after your create_new_version there is no immediate
  #       access to latest_version_object, but the ContentView object is first completely reloaded.
  #
  #       In Rails 7.1, individual connections can be reloaded:
  #       https://www.shakacode.com/blog/rails-7-1-allows-resetting-singular-associations/

  update(:next_version => major.to_i + 1) unless major.to_i < next_version
  version
end

#cv_repo_indexed_after_last_published?Boolean

Returns:



822
823
824
# File 'app/models/katello/content_view.rb', line 822

def cv_repo_indexed_after_last_published?
  repositories.any? { |repo| repo.last_indexed && repo.last_indexed > latest_version_object.created_at }
end

#delete(from_env) ⇒ Object



522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
# File 'app/models/katello/content_view.rb', line 522

def delete(from_env)
  if from_env.library? && in_non_library_environment?
    fail Errors::ChangesetContentException, _("Cannot delete view while it exists in environments")
  end

  version = self.version(from_env)
  if version.nil?
    fail Errors::ChangesetContentException, _("Cannot delete from %s, view does not exist there.") % from_env.name
  end
  version = ContentViewVersion.find(version.id)

  if (foreman_env = Environment.find_by_katello_id(self.organization, from_env, self))
    foreman_env.destroy
  end

  version.delete(from_env)
  self.destroy if self.versions.empty?
end

#dependency_solving_changed?Boolean

Returns:



905
906
907
# File 'app/models/katello/content_view.rb', line 905

def dependency_solving_changed?
  latest_version_object.applied_filters && solve_dependencies != latest_version_object.applied_filters['dependency_solving']
end

#duplicate_docker_reposObject



553
554
555
# File 'app/models/katello/content_view.rb', line 553

def duplicate_docker_repos
  duplicate_repositories.docker_type
end

#duplicate_repositoriesObject



545
546
547
548
549
550
551
# File 'app/models/katello/content_view.rb', line 545

def duplicate_repositories
  counts = repositories_to_publish.each_with_object(Hash.new(0)) do |repo, h|
    h[repo.library_instance_id] += 1
  end
  ids = counts.select { |_k, v| v > 1 }.keys
  Repository.where(:id => ids)
end

#duplicate_repositories_to_publishObject



444
445
446
447
# File 'app/models/katello/content_view.rb', line 444

def duplicate_repositories_to_publish
  return [] unless composite?
  repositories_to_publish_by_library_instance.select { |key, val| val.count > 1 && key.present? }.keys
end

#filtered?Boolean

Returns:



909
910
911
# File 'app/models/katello/content_view.rb', line 909

def filtered?
  filters.present?
end

#generated?Boolean

Returns:



306
307
308
# File 'app/models/katello/content_view.rb', line 306

def generated?
  !generated_for_none?
end

#generated_for_library?Boolean

Returns:



206
207
208
# File 'app/models/katello/content_view.rb', line 206

def generated_for_library?
  generated_for_library_export? || generated_for_library_import? || generated_for_library_export_syncable?
end

#generated_for_repository?Boolean

Returns:



202
203
204
# File 'app/models/katello/content_view.rb', line 202

def generated_for_repository?
  generated_for_repository_export? || generated_for_repository_import? || generated_for_repository_export_syncable?
end

#get_repo_clone(env, repo) ⇒ Object



515
516
517
518
519
520
# File 'app/models/katello/content_view.rb', line 515

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

#historyObject



371
372
373
374
# File 'app/models/katello/content_view.rb', line 371

def history
  Katello::ContentViewHistory.joins(:content_view_version).where(
    "#{Katello::ContentViewVersion.table_name}.content_view_id" => self.id)
end

#in_environment?(env) ⇒ Boolean

Returns:



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

def in_environment?(env)
  environments.include?(env)
end

#in_non_library_environment?Boolean

Returns:



541
542
543
# File 'app/models/katello/content_view.rb', line 541

def in_non_library_environment?
  environments.where(:library => false).length > 0
end

#last_publish_task_success?Boolean

Returns:



817
818
819
820
# File 'app/models/katello/content_view.rb', line 817

def last_publish_task_success?
  last_publish_result = latest_version_object&.history&.publish&.first&.task&.result
  return last_publish_result.present? && last_publish_result == 'success'
end

#last_taskObject



366
367
368
369
# File 'app/models/katello/content_view.rb', line 366

def last_task
  last_task_id = history.order(:created_at)&.last&.task_id
  last_task_id ? ForemanTasks::Task.find_by(id: last_task_id) : nil
end

#latest_versionObject



352
353
354
# File 'app/models/katello/content_view.rb', line 352

def latest_version
  latest_version_object.try(:version)
end

#latest_version_envObject



360
361
362
363
364
# File 'app/models/katello/content_view.rb', line 360

def latest_version_env
  environments = organization.readable_promotion_paths.flatten
  environments.insert(0, organization.library)
  environments.intersection(latest_version_object.try(:environments) || [])
end

#latest_version_idObject



356
357
358
# File 'app/models/katello/content_view.rb', line 356

def latest_version_id
  latest_version_object.try(:id)
end

#library_export?Boolean

Returns:



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

def library_export?
  name.start_with? EXPORT_LIBRARY
end

#library_import?Boolean

Returns:



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

def library_import?
  name == IMPORT_LIBRARY
end

#library_repo_idsObject



399
400
401
# File 'app/models/katello/content_view.rb', line 399

def library_repo_ids
  repos(self.organization.library).map { |r| r.library_instance_id }
end

#library_reposObject



395
396
397
# File 'app/models/katello/content_view.rb', line 395

def library_repos
  Repository.where(:id => library_repo_ids)
end

#needs_publish?Boolean

Returns:



830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
# File 'app/models/katello/content_view.rb', line 830

def needs_publish?
  #Returns
  # True:
  #     a) When content/repo/filter change audit records exist
  #     b) CV hasn't ever been published
  #     c) CV dependency_solving != latest_version.applied_filters.dependency_solving
  #     d) If repo was indexed after cv publish. This can happen under 3 cases:
  #       i) Index runs because last index(before publish) had failed and repo is picked up for index even if pulp publication hasn't changed.
  #       ii) Complete sync runs or sync adds/removes new content (Already true because new pulp publication/version gets created)
  #       iii) repo.index_content is run. (This doesn't necessarily indicate contents changed. Corner case where we play safe and return true)
  # nil:
  #     a) When CV version creation audit is missing(Indicating audit cleanup)
  #     b) Version doesn't have audited_filters set indicating
  #     it was published before 4.9 upgrade when we started auditing changes on the CV.
  #     c) Last publish task failed leaving us with no way of knowing if all content in the version is correct.
  # False:
  #     a) No changes were detected via audits *and*
  #        Audit for CV publish exists (Audits haven't been cleaned up)
  #        *and* applied_filters field is set(Published after upgrade)
  #     b) Default, import only and generated CVs can not be published, hence these will always return false.
  #
  return false if unpublishable?
  return true unless latest_version_object
  return nil unless last_publish_task_success?
  return composite_cv_components_changed? if composite?
  # return true if the audit records clearly show we have unpublished changes
  return true if audited_changes_present?
  # return true if the dependency solving changed for CV between last publish and now
  return true if dependency_solving_changed?
  # return true if any child repo's indexed_at > last_version.created_at
  return true if cv_repo_indexed_after_last_published?
  # if we didn't return `true` already, either the audit records show that we don't need to publish, or we may
  # have insufficient data to make the determination (either audits were cleaned, or never got created at all).
  # first, check for the `create` audit record; its absence indicates that audits were cleaned some time after
  # the cv version was created (i.e. the first indeterminate state) so we return `nil` in that case.
  return nil unless latest_version_object&.audits&.where(action: "create")&.exists?
  # even when the `create` audit exists, the other audits could still be absent due to the latest cv version
  # being created prior to the tracking of the other audits that were added in katello 4.9 (i.e. the second indeterminate state).
  # We determine that using the `applied_filters` field. This field was added in Katello 4.9 and is set to nil for
  # all versions published before that upgrade.
  # If `applied_filters` is nil we can not deterministically rule out changes before the upgrade
  # not captured by newer content change and filter change audits.
  # If that field is not nil, the version was published after upgrade, hence we have all the information to rule out
  # any audited changes to the CV and we can deterministically return false
  latest_version_object.applied_filters.nil? ? nil : false
end

#on_demand_repositoriesObject



780
781
782
# File 'app/models/katello/content_view.rb', line 780

def on_demand_repositories
  repositories.on_demand
end

#products(env = nil) ⇒ Object



503
504
505
506
# File 'app/models/katello/content_view.rb', line 503

def products(env = nil)
  repos = repos(env)
  Product.joins(:repositories).where("#{Katello::Repository.table_name}.id" => repos.map(&:id)).distinct
end

#promoted?Boolean

Returns:



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

def promoted?
  # if the view exists in more than 1 environment, it has been promoted
  self.environments.many?
end

#publish_repositories(override_components = nil) ⇒ Object



461
462
463
464
465
466
467
468
469
470
# File 'app/models/katello/content_view.rb', line 461

def publish_repositories(override_components = nil)
  repositories = composite? ? repositories_to_publish_by_library_instance(override_components).values : repositories_to_publish
  repositories.each do |repos|
    if repos.is_a? Array
      yield repos
    else
      yield [repos]
    end
  end
end


792
793
794
795
796
797
798
799
800
801
802
803
804
805
# File 'app/models/katello/content_view.rb', line 792

def related_composite_cvs
  content_views = []
  component_composites.each do |cv|
    cv_id = cv.composite_content_view_id
    cv_name = ContentView.find(cv_id).name
    content_views.push(
      {
        id: cv_id,
        name: cv_name,
      }
    )
  end
  content_views
end


784
785
786
787
788
789
790
# File 'app/models/katello/content_view.rb', line 784

def related_cv_count
  if composite
    content_view_components.length
  else
    component_composites.length
  end
end

#remove_components(components_to_remove) ⇒ Object

Removes selected content view components

1,2,34

> content view component ids/



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

def remove_components(components_to_remove)
  content_view_components.where(:id => components_to_remove).destroy_all
end

#remove_environment(env) ⇒ Object

Unassociate an environment from this content view. This can occur whenever a view is deleted from an environment. It is necessary to make candlepin aware that the view is no longer available for consumers.



611
612
613
614
615
616
617
618
# File 'app/models/katello/content_view.rb', line 611

def remove_environment(env)
  # Do not remove the content view environment, if there is still a view
  # version in the environment.
  if self.versions.in_environment(env).blank?
    view_env = self.content_view_environments.where(:environment_id => env.id)
    view_env.first.destroy unless view_env.blank?
  end
end

#repos(env = nil) ⇒ Object



386
387
388
389
390
391
392
393
# File 'app/models/katello/content_view.rb', line 386

def repos(env = nil)
  if env
    repo_ids = versions.flat_map { |version| version.repositories.in_environment(env) }.map(&:id)
  else
    repo_ids = versions.flat_map { |version| version.repositories }.map(&:id)
  end
  Repository.where(:id => repo_ids)
end

#repos_in_product(env, product) ⇒ Object



494
495
496
497
498
499
500
501
# File 'app/models/katello/content_view.rb', line 494

def repos_in_product(env, product)
  version = version(env)
  if version
    version.repositories.in_environment(env).in_product(product)
  else
    []
  end
end

#repositories_to_publish(override_components = nil) ⇒ Object



408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
# File 'app/models/katello/content_view.rb', line 408

def repositories_to_publish(override_components = nil)
  if composite?
    components_to_publish = []
    components.each do |component|
      override_component = override_components&.detect do |override_cvv|
        override_cvv.content_view == component.content_view
      end

      if override_component
        components_to_publish << override_component
      else
        components_to_publish << component
      end
    end
    ids = components_to_publish.flat_map { |version| version.repositories.archived }.map(&:id)
    Repository.where(:id => ids)
  else
    repositories
  end
end

#repositories_to_publish_by_library_instance(override_components = nil) ⇒ Object



433
434
435
436
437
438
439
440
441
442
# File 'app/models/katello/content_view.rb', line 433

def repositories_to_publish_by_library_instance(override_components = nil)
  # retrieve the list of repositories in a hash, where the key
  # is the library instance id, and the value is an array
  # of the repositories for that instance.
  repositories_to_publish(override_components).inject({}) do |result, repo|
    result[repo.library_instance] ||= []
    result[repo.library_instance] << repo
    result
  end
end

#repositories_to_publish_idsObject



429
430
431
# File 'app/models/katello/content_view.rb', line 429

def repositories_to_publish_ids
  composite? ? repositories_to_publish.pluck(&:id) : repository_ids
end

#resulting_productsObject



382
383
384
# File 'app/models/katello/content_view.rb', line 382

def resulting_products
  (self.repositories.collect { |r| r.product }).uniq
end

#sorted_versionsObject



222
223
224
# File 'app/models/katello/content_view.rb', line 222

def sorted_versions
  versions.order('created_at DESC')
end

#to_sObject



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

def to_s
  name
end

#total_deb_package_count(env) ⇒ Object



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

def total_deb_package_count(env)
  Katello::Deb.in_repositories(self.repos(env)).count
end

#total_package_count(env) ⇒ Object



331
332
333
# File 'app/models/katello/content_view.rb', line 331

def total_package_count(env)
  Katello::Rpm.in_repositories(self.repos(env)).count
end

#unpublishable?Boolean

Returns:



826
827
828
# File 'app/models/katello/content_view.rb', line 826

def unpublishable?
  default? || import_only? || generated? || rolling?
end

#update_cp_content(env) ⇒ Object



586
587
588
589
590
# File 'app/models/katello/content_view.rb', line 586

def update_cp_content(env)
  view_env = content_view_environment(env)

  view_env&.update_cp_content
end

#update_host_statuses(environment) ⇒ Object



472
473
474
475
476
477
478
479
480
481
482
483
484
# File 'app/models/katello/content_view.rb', line 472

def update_host_statuses(environment)
  # update errata applicability counts for all hosts in the CV & LE
  Location.no_taxonomy_scope do
    User.as_anonymous_admin do
      ::Katello::Host::ContentFacet.with_content_views(self).with_environments(environment).each do |facet|
        facet.update_applicability_counts
        facet.update_errata_status
      rescue NoMethodError
        Rails.logger.warn _('Errata statuses not updated for deleted content facet with UUID %s') % facet.uuid
      end
    end
  end
end

#version(env) ⇒ Object



348
349
350
# File 'app/models/katello/content_view.rb', line 348

def version(env)
  self.versions.in_environment(env).order("#{Katello::ContentViewVersion.table_name}.id ASC").readonly(false).last
end

#version_countObject



776
777
778
# File 'app/models/katello/content_view.rb', line 776

def version_count
  content_view_versions.size
end

#version_environment(env) ⇒ Object



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

def version_environment(env)
  # TODO: rewrite this into SQL or use content_view_environment when that
  # points to environment
  version(env).content_view_version_environments.select { |cvve| cvve.environment_id == env.id }
end