Class: ForemanTasks::RecurringLogic

Inherits:
ApplicationRecord
  • Object
show all
Includes:
Authorizable
Defined in:
app/models/foreman_tasks/recurring_logic.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.allowed_statesObject



28
29
30
# File 'app/models/foreman_tasks/recurring_logic.rb', line 28

def self.allowed_states
  %w[active disabled finished cancelled failed]
end

.assemble_cronline(hash) ⇒ Object



161
162
163
164
165
# File 'app/models/foreman_tasks/recurring_logic.rb', line 161

def self.assemble_cronline(hash)
  hash.values_at(:minutes, :hours, :days, :months, :days_of_week)
      .map { |value| value.nil? || value.blank? ? '*' : value }
      .join(' ')
end

.cronline_hash(recurring_type, time_hash, days, days_of_week_hash) ⇒ Object



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'app/models/foreman_tasks/recurring_logic.rb', line 188

def self.cronline_hash(recurring_type, time_hash, days, days_of_week_hash)
  hash = Hash[[:years, :months, :days, :hours, :minutes].zip(time_hash.values)]
  days_of_week = days_of_week_hash.select { |_key, value| value == '1' }.keys.join(',')
  hash.update :days_of_week => days_of_week, :days => days
  allowed_keys = case recurring_type
                 when :monthly
                   [:minutes, :hours, :days]
                 when :weekly
                   [:minutes, :hours, :days_of_week]
                 when :daily
                   [:minutes, :hours]
                 when :hourly
                   [:minutes]
                 end
  hash.select { |key, _| allowed_keys.include? key }
end

.new_from_cronline(cronline) ⇒ Object



167
168
169
170
171
172
# File 'app/models/foreman_tasks/recurring_logic.rb', line 167

def self.new_from_cronline(cronline)
  new.tap do |logic|
    logic.cron_line = cronline
    logic.task_group = ::ForemanTasks::TaskGroups::RecurringLogicTaskGroup.new
  end
end

.new_from_triggering(triggering) ⇒ Object



174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'app/models/foreman_tasks/recurring_logic.rb', line 174

def self.new_from_triggering(triggering)
  cronline = if triggering.input_type == :cronline
               triggering.cronline
             else
               ::ForemanTasks::RecurringLogic.assemble_cronline(cronline_hash(triggering.input_type, triggering.time, triggering.days, triggering.days_of_week))
             end
  ::ForemanTasks::RecurringLogic.new_from_cronline(cronline).tap do |manager|
    manager.end_time = triggering.end_time if triggering.end_time_limited.present?
    manager.max_iteration = triggering.max_iteration if triggering.max_iteration.present?
    manager.purpose = triggering.purpose if triggering.purpose.present?
    manager.triggering = triggering
  end
end

Instance Method Details

#can_continue?(time = Time.zone.now) ⇒ Boolean

Returns:

  • (Boolean)


130
131
132
# File 'app/models/foreman_tasks/recurring_logic.rb', line 130

def can_continue?(time = Time.zone.now)
  %w[active disabled].include?(state) && can_start?(time)
end

#can_start?(time = Time.zone.now) ⇒ Boolean

Returns:

  • (Boolean)


125
126
127
128
# File 'app/models/foreman_tasks/recurring_logic.rb', line 125

def can_start?(time = Time.zone.now)
  (end_time.nil? || next_occurrence_time(time) < end_time) &&
    (max_iteration.nil? || iteration < max_iteration)
end

#cancelObject



92
93
94
95
96
# File 'app/models/foreman_tasks/recurring_logic.rb', line 92

def cancel
  self.state = 'cancelled'
  save!
  tasks.active.each(&:cancel)
end

#cancelled?Boolean

Returns:

  • (Boolean)


138
139
140
# File 'app/models/foreman_tasks/recurring_logic.rb', line 138

def cancelled?
  state == 'cancelled'
end

#disabled?Boolean

Returns:

  • (Boolean)


59
60
61
# File 'app/models/foreman_tasks/recurring_logic.rb', line 59

def disabled?
  !enabled?
end

#done?Boolean

Returns:

  • (Boolean)


142
143
144
# File 'app/models/foreman_tasks/recurring_logic.rb', line 142

def done?
  %w[cancelled finished].include?(state)
end

#enabled=(value) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'app/models/foreman_tasks/recurring_logic.rb', line 40

def enabled=(value)
  task = tasks.find_by(:state => :scheduled)
  if task
    ForemanTasks.dynflow.world.persistence.set_delayed_plan_frozen(task.execution_plan.id, !value, next_occurrence_time)
    if value
      task.update!(:start_at => next_occurrence_time) if task.start_at < Time.zone.now
      update(:state => 'active')
    end
  elsif value
    raise RecurringLogicCancelledException
  end

  update(:state => 'disabled') unless value
end

#enabled?Boolean

Returns:

  • (Boolean)


55
56
57
# File 'app/models/foreman_tasks/recurring_logic.rb', line 55

def enabled?
  state != 'disabled'
end

#finished?Boolean

Returns:

  • (Boolean)


134
135
136
# File 'app/models/foreman_tasks/recurring_logic.rb', line 134

def finished?
  state == 'finished'
end

#generate_delay_options(time = Time.zone.now, options = {}) ⇒ Object



106
107
108
109
110
111
112
113
# File 'app/models/foreman_tasks/recurring_logic.rb', line 106

def generate_delay_options(time = Time.zone.now, options = {})
  {
    :start_at => next_occurrence_time(time),
    :start_before => options['start_before'],
    :recurring_logic_id => id,
    :frozen => disabled?,
  }
end

#humanized_stateObject



146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'app/models/foreman_tasks/recurring_logic.rb', line 146

def humanized_state
  case state
  when 'active'
    N_('Active')
  when 'cancelled'
    N_('Cancelled')
  when 'finished'
    N_('Finished')
  when 'disabled'
    N_('Disabled')
  else
    N_('N/A')
  end
end

#last_taskObject



32
33
34
# File 'app/models/foreman_tasks/recurring_logic.rb', line 32

def last_task
  tasks.order(:started_at).where.not(started_at: nil).last
end

#next_occurrence_time(time = Time.zone.now) ⇒ Object



98
99
100
101
102
103
104
# File 'app/models/foreman_tasks/recurring_logic.rb', line 98

def next_occurrence_time(time = Time.zone.now)
  @parser ||= Fugit.do_parse_cron(cron_line)
  # @parser.next(start_time) is not inclusive of the start_time hence stepping back one run to include checking start_time for the first run.
  before_next = @parser.next_time(@parser.previous_time(time.iso8601))
  return before_next.utc.localtime if before_next >= time && tasks.count == 0
  @parser.next_time(time).utc.localtime
end

#next_taskObject



36
37
38
# File 'app/models/foreman_tasks/recurring_logic.rb', line 36

def next_task
  tasks.order(:start_at).where(started_at: nil).last
end

#start(action_class, *args) ⇒ Object



63
64
65
# File 'app/models/foreman_tasks/recurring_logic.rb', line 63

def start(action_class, *args)
  start_after(action_class, Time.zone.now, *args)
end

#start_after(action_class, time, *args) ⇒ Object



67
68
69
70
71
# File 'app/models/foreman_tasks/recurring_logic.rb', line 67

def start_after(action_class, time, *args)
  self.state = 'active'
  save!
  trigger_repeat_after(time, action_class, *args)
end

#trigger_repeat(action_class, *args) ⇒ Object



88
89
90
# File 'app/models/foreman_tasks/recurring_logic.rb', line 88

def trigger_repeat(action_class, *args)
  trigger_repeat_after(Time.zone.now, action_class, *args)
end

#trigger_repeat_after(time, action_class, *args) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'app/models/foreman_tasks/recurring_logic.rb', line 73

def trigger_repeat_after(time, action_class, *args)
  return if cancelled?
  if can_continue?(time)
    self.iteration += 1
    save!
    ::ForemanTasks.delay action_class,
                         generate_delay_options(time),
                         *args
  else
    self.state = 'finished'
    save!
    nil
  end
end

#valid?(*_) ⇒ Boolean

Returns:

  • (Boolean)


115
116
117
# File 'app/models/foreman_tasks/recurring_logic.rb', line 115

def valid?(*_)
  cron_line.present? && valid_cronline? && !state.nil? || can_start?
end

#valid_cronline?Boolean

Returns:

  • (Boolean)


119
120
121
122
123
# File 'app/models/foreman_tasks/recurring_logic.rb', line 119

def valid_cronline?
  !!next_occurrence_time
rescue ArgumentError => _
  false
end

#valid_purpose?Boolean

Returns:

  • (Boolean)


205
206
207
# File 'app/models/foreman_tasks/recurring_logic.rb', line 205

def valid_purpose?
  !(purpose.present? && self.class.where(:purpose => purpose, :state => %w[active disabled]).any?)
end