Class: Katello::ErrataApplication

Inherits:
Model
  • Object
show all
Defined in:
app/models/katello/errata_application.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.determine_status(task, action) ⇒ Object

Determine application status from task and action



158
159
160
161
162
163
164
165
# File 'app/models/katello/errata_application.rb', line 158

def self.determine_status(task, action)
  if task.result.present? && task.result != 'pending'
    task.result.to_s
  else
    # Fallback: check action error
    action&.error.present? ? 'error' : 'success'
  end
end

.extract_errata_ids_from_task(task) ⇒ Object

Extract errata IDs from task

Parameters:

  • task (ForemanTasks::Task)

    The task to extract from



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'app/models/katello/errata_application.rb', line 94

def self.extract_errata_ids_from_task(task)
  if dynflow_initialized?
    begin
      input = task.input

      # Try to get errata from input if available
      if input.present?
        errata = input['errata'] || input['content']
        return errata if errata.present?

        # Check job_features to decide extraction method
        if input['job_features']&.include?('katello_errata_install_by_search')
          return extract_from_script(task)
        end
      end
    rescue StandardError
      # Fall through to template_invocation fallback
    end
  end

  # Fall back to template invocation input
  return [] unless task.template_invocation
  extract_from_template_input(task)
end

.extract_from_script(task) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'app/models/katello/errata_application.rb', line 119

def self.extract_from_script(task)
  return [] unless task.execution_plan_action

  # The script is in the ProxyAction, find it without hardcoding array index
  proxy_action = task.execution_plan_action.all_planned_actions(::Actions::RemoteExecution::ProxyAction).first
  # Fallback to legacy array access if ProxyAction not found (shouldn't happen)
  proxy_action ||= task.execution_plan_action.execution_plan.actions.find do |action|
    action.is_a?(::Actions::RemoteExecution::ProxyAction) && action.input['script'].present?
  end

  return [] unless proxy_action

  script = proxy_action.input['script'] || ''
  found = script.lines.find { |line| line.start_with?('# RESOLVED_ERRATA_IDS=') } || ''
  ids = (found.chomp.split('=', 2).last || '').split(',')
  ids.map(&:strip).reject(&:blank?)
end

.extract_from_template_input(task) ⇒ Object



137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'app/models/katello/errata_application.rb', line 137

def self.extract_from_template_input(task)
  # Search-based template (katello_errata_install_by_search) stores search query in template input,
  # not errata IDs. Only list-based template (katello_errata_install) stores comma-separated IDs.
  # This method should only be called for list-based templates when Dynflow is not available.

  value = ::TemplateInvocationInputValue
    .joins(:template_input)
    .where(template_invocation_id: task.template_invocation.id)
    .where("template_inputs.name = ?", 'errata')
    .first&.value

  parse_comma_separated_errata_ids(value)
end

.extract_host_id_from_task(task) ⇒ Object

Extract host ID from task input



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'app/models/katello/errata_application.rb', line 72

def self.extract_host_id_from_task(task)
  if dynflow_initialized?
    begin
      input = task.input

      if input
        if input['host'].is_a?(Hash)
          return input['host']['id']
        elsif input['host_id']
          return input['host_id']
        end
      end
    rescue StandardError
      # Fall through to template_invocation fallback
    end
  end

  task.template_invocation&.host_id
end

.record_from_task(task, action) ⇒ ErrataApplication?

Record errata applications from a completed task

Parameters:

  • task (ForemanTasks::Task)

    The completed task

  • action (Dynflow::Action)

    The action object

Returns:



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'app/models/katello/errata_application.rb', line 34

def self.record_from_task(task, action)
  return nil unless task

  host_id = extract_host_id_from_task(task)
  return nil unless host_id

  host = ::Host::Managed.find_by(id: host_id)
  return nil unless host

  errata_string_ids = extract_errata_ids_from_task(task)
  return nil if errata_string_ids.blank?

  # Reload task to get the latest result status
  task.reload
  status = determine_status(task, action)
  applied_at = task.ended_at || Time.zone.now
  user = task.user

  begin
    create!(
      host: host,
      errata_ids: errata_string_ids,
      task: task,
      user: user,
      applied_at: applied_at,
      status: status
    )
  rescue ActiveRecord::RecordInvalid => e
    if e.record.errors.of_kind?(:task_id, :taken)
      Rails.logger.warn("Skipped duplicate errata application: task=#{task.id}, host=#{host.name}")
      nil
    else
      raise
    end
  end
end

Instance Method Details

#errata_ids_must_be_arrayObject



25
26
27
28
# File 'app/models/katello/errata_application.rb', line 25

def errata_ids_must_be_array
  errors.add(:errata_ids, "must be an array") unless errata_ids.is_a?(Array)
  errors.add(:errata_ids, "cannot be empty") if errata_ids.blank?
end