Class: ForemanTasks::Cleaner

Inherits:
Object
  • Object
show all
Defined in:
lib/foreman_tasks/cleaner.rb

Overview

Represents the cleanup mechanism for tasks

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Cleaner

seconds ago. If not specified, no implicit filtering on the date.

Parameters:

  • filter (String)

    scoped search matching the tasks to be deleted

  • after (String|nil)

    delete the tasks after they are older than the value: the number in string is expected to be followed by time unit specification one of s,h,d,y for

Raises:

  • (ArgumentError)


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/foreman_tasks/cleaner.rb', line 55

def initialize(options = {})
  default_options = { :after        => '0s',
                      :verbose      => false,
                      :batch_size   => 1000,
                      :noop         => false,
                      :states       => ["stopped"] }
  options         = default_options.merge(options)

  @filter         = options[:filter]
  @after          = parse_time_interval(options[:after])
  @states         = options[:states]
  @verbose        = options[:verbose]
  @batch_size     = options[:batch_size]
  @noop           = options[:noop]

  raise ArgumentError, 'filter not speficied' if @filter.nil?

  @full_filter    = prepare_filter
end

Instance Attribute Details

#afterObject (readonly)

Returns the value of attribute after.



48
49
50
# File 'lib/foreman_tasks/cleaner.rb', line 48

def after
  @after
end

#batch_sizeObject (readonly)

Returns the value of attribute batch_size.



48
49
50
# File 'lib/foreman_tasks/cleaner.rb', line 48

def batch_size
  @batch_size
end

#filterObject (readonly)

Returns the value of attribute filter.



48
49
50
# File 'lib/foreman_tasks/cleaner.rb', line 48

def filter
  @filter
end

#full_filterObject (readonly)

Returns the value of attribute full_filter.



48
49
50
# File 'lib/foreman_tasks/cleaner.rb', line 48

def full_filter
  @full_filter
end

#noopObject (readonly)

Returns the value of attribute noop.



48
49
50
# File 'lib/foreman_tasks/cleaner.rb', line 48

def noop
  @noop
end

#statesObject (readonly)

Returns the value of attribute states.



48
49
50
# File 'lib/foreman_tasks/cleaner.rb', line 48

def states
  @states
end

#verboseObject (readonly)

Returns the value of attribute verbose.



48
49
50
# File 'lib/foreman_tasks/cleaner.rb', line 48

def verbose
  @verbose
end

Class Method Details

.actions_with_default_cleanupObject



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/foreman_tasks/cleaner.rb', line 23

def self.actions_with_default_cleanup
  actions_with_periods = {}
  if cleanup_settings[:actions]
    cleanup_settings[:actions].each do |action|
      begin
        action_class = action[:name].constantize
        actions_with_periods[action_class] = action[:after]
      rescue => e
        Foreman::Logging.exception("Error handling #{action} cleanup settings", e)
      end
    end
  end
  (ForemanTasks.dynflow.world.action_classes - actions_with_periods.keys).each do |action_class|
    if action_class.respond_to?(:cleanup_after)
      actions_with_periods[action_class] = action_class.cleanup_after
    end
  end
  return actions_with_periods
end

.cleanup_settingsObject



43
44
45
46
# File 'lib/foreman_tasks/cleaner.rb', line 43

def self.cleanup_settings
  return @cleanup_settings if @cleanup_settings
  @cleanup_settings = SETTINGS[:'foreman-tasks'] && SETTINGS[:'foreman-tasks'][:cleanup] || {}
end

.run(options) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/foreman_tasks/cleaner.rb', line 5

def self.run(options)
  if options.key?(:filter)
    self.new(options).delete
  else
    [:after, :states].each do |invalid_option|
      if options.key?(invalid_option)
        raise "The option #{invalid_option} is not valid unless the filter specified"
      end
    end
    if cleanup_settings[:after]
      self.new(options.merge(:filter => "", :after  => cleanup_settings[:after])).delete
    end
    actions_with_default_cleanup.each do |action_class, period|
      self.new(options.merge(:filter => "label = #{action_class.name}", :after  => period)).delete
    end
  end
end

Instance Method Details

#deleteObject

Delete the filtered tasks, including the dynflow execution plans



76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/foreman_tasks/cleaner.rb', line 76

def delete
  if noop
    say "[noop] deleting all tasks matching filter #{full_filter}"
    say "[noop] #{ForemanTasks::Task.search_for(full_filter).size} tasks would be deleted"
  else
    start_tracking_progress
    while (chunk = ForemanTasks::Task.search_for(full_filter).limit(batch_size)).any?
      delete_tasks(chunk)
      delete_dynflow_plans(chunk)
      report_progress(chunk)
    end
  end
end

#delete_dynflow_plans(chunk) ⇒ Object



98
99
100
101
# File 'lib/foreman_tasks/cleaner.rb', line 98

def delete_dynflow_plans(chunk)
  dynflow_ids = chunk.find_all { |task| task.is_a? Task::DynflowTask }.map(&:external_id)
  ForemanTasks.dynflow.world.persistence.delete_execution_plans({ 'uuid' => dynflow_ids }, batch_size)
end

#delete_tasks(chunk) ⇒ Object



94
95
96
# File 'lib/foreman_tasks/cleaner.rb', line 94

def delete_tasks(chunk)
  ForemanTasks::Task.where(:id => chunk.map(&:id)).delete_all
end

#parse_time_interval(string) ⇒ Object



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/foreman_tasks/cleaner.rb', line 131

def parse_time_interval(string)
  matched_string = string.gsub(' ','').match(/\A(\d+)(\w)\Z/)
  unless matched_string
    raise ArgumentError, "String #{string} isn't an expected specification of time in format of \"{number}{time_unit}\""
  end
  number = matched_string[1].to_i
  value = case matched_string[2]
          when 's'
            number.seconds
          when 'h'
            number.hours
          when 'd'
            number.days
          when 'y'
            number.years
          else
            raise ArgumentError, "Unexpected time unit in #{string}, expected one of [s,h,d,y]"
          end
  return value
end

#prepare_filterObject



103
104
105
106
107
108
# File 'lib/foreman_tasks/cleaner.rb', line 103

def prepare_filter
  filter_parts = [filter]
  filter_parts << %{started_at < "#{after.ago.to_s(:db)}"} if after > 0
  filter_parts << states.map { |s| "state = #{s}" }.join(" OR ") if states.any?
  filter_parts.select(&:present?).join(' AND ')
end

#report_progress(chunk) ⇒ Object



117
118
119
120
121
122
# File 'lib/foreman_tasks/cleaner.rb', line 117

def report_progress(chunk)
  if verbose
    @current += chunk.size
    say "#{@current}/#{@total}", false
  end
end

#say(message, log = true) ⇒ Object



124
125
126
127
128
129
# File 'lib/foreman_tasks/cleaner.rb', line 124

def say(message, log = true)
  puts message
  if log
    Foreman::Logging.logger('foreman-tasks').info(message)
  end
end

#start_tracking_progressObject



110
111
112
113
114
115
# File 'lib/foreman_tasks/cleaner.rb', line 110

def start_tracking_progress
  if verbose
    @current, @total = 0, tasks.size
    say "#{@current}/#{@total}", false
  end
end

#tasksObject



90
91
92
# File 'lib/foreman_tasks/cleaner.rb', line 90

def tasks
  ForemanTasks::Task.search_for(full_filter).select('DISTINCT foreman_tasks_tasks.id, foreman_tasks_tasks.type, foreman_tasks_tasks.external_id')
end