Merge branch 'master' into 14260-runtime-token
[arvados.git] / services / api / lib / sweep_trashed_objects.rb
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: AGPL-3.0
4
5 require 'current_api_client'
6
7 module SweepTrashedObjects
8   extend CurrentApiClient
9
10   def self.delete_project_and_contents(p_uuid)
11     p = Group.find_by_uuid(p_uuid)
12     if !p || p.group_class != 'project'
13       raise "can't sweep group '#{p_uuid}', it may not exist or not be a project"
14     end
15     # First delete sub projects
16     Group.where({group_class: 'project', owner_uuid: p_uuid}).each do |sub_project|
17       delete_project_and_contents(sub_project.uuid)
18     end
19     # Next, iterate over all tables which have owner_uuid fields, with some
20     # exceptions, and delete records owned by this project
21     skipped_classes = ['Group', 'User']
22     ActiveRecord::Base.descendants.reject(&:abstract_class?).each do |klass|
23       if !skipped_classes.include?(klass.name) && klass.columns.collect(&:name).include?('owner_uuid')
24         klass.where({owner_uuid: p_uuid}).destroy_all
25       end
26     end
27     # Finally delete the project itself
28     p.destroy
29   end
30
31   def self.sweep_now
32     act_as_system_user do
33       # Sweep trashed collections
34       Collection.
35         where('delete_at is not null and delete_at < statement_timestamp()').
36         destroy_all
37       Collection.
38         where('is_trashed = false and trash_at < statement_timestamp()').
39         update_all('is_trashed = true')
40
41       # Sweep trashed projects and their contents
42       Group.
43         where({group_class: 'project'}).
44         where('delete_at is not null and delete_at < statement_timestamp()').each do |project|
45           delete_project_and_contents(project.uuid)
46       end
47       Group.
48         where({group_class: 'project'}).
49         where('is_trashed = false and trash_at < statement_timestamp()').
50         update_all('is_trashed = true')
51
52       # Sweep expired tokens
53       ApiClientAuthorization.
54         where("expires_at <= statement_timestamp()").
55         destroy_all
56     end
57   end
58
59   def self.sweep_if_stale
60     return if Rails.configuration.trash_sweep_interval <= 0
61     exp = Rails.configuration.trash_sweep_interval.seconds
62     need = false
63     Rails.cache.fetch('SweepTrashedObjects', expires_in: exp) do
64       need = true
65     end
66     if need
67       Thread.new do
68         Thread.current.abort_on_exception = false
69         begin
70           sweep_now
71         rescue => e
72           Rails.logger.error "#{e.class}: #{e}\n#{e.backtrace.join("\n\t")}"
73         ensure
74           ActiveRecord::Base.connection.close
75         end
76       end
77     end
78   end
79 end