require 'active_support/core_ext/numeric/bytes'
require 'thor'
require 'table_print'
require 'debci/package'
module Debci
class StorageLimit
def storage_limit
@storage_limit ||= Debci.config.disk_storage_limit.megabytes
end
def packages_with_excess_storage(all: false)
expiration = Time.now - Debci.config.data_retention.days
query = "
SELECT packages.*, sum(jobs.log_size + jobs.artifacts_size) AS storage_used
FROM packages
JOIN jobs ON packages.id = jobs.package_id
WHERE jobs.date > '#{expiration}' AND NOT jobs.files_purged
GROUP BY packages.id
"
unless all
query += "
HAVING sum(jobs.log_size + jobs.artifacts_size) >= (CASE WHEN packages.storage_limit IS NOT NULL THEN packages.storage_limit ELSE #{storage_limit} END)
"
end
Debci::Package.find_by_sql(query)
end
def run
packages_with_excess_storage.each do |package|
self.cleanup_package(package)
end
end
def cleanup_package(package)
storage = 0
limit = package.storage_limit || storage_limit
package.jobs.where(files_purged: false).order("date DESC").in_batches.each do |subset|
subset.each do |job|
storage += job.disk_usage
if storage > limit
job.cleanup(reason: "package taking too much disk space")
end
end
end
end
class CLI < Thor
include ActiveSupport::NumberHelper
desc 'start', 'keeps storage limit by package/suite/architecture'
def start
::Debci::StorageLimit.new.run
end
desc 'list', 'Lists packages that are exceeding their storage limit'
option :all, type: :boolean, default: false, aliases: ["-a"], desc: "Lists all packages, not only exceeding ones"
def list
limit = ::Debci::StorageLimit.new
packages = limit.packages_with_excess_storage(options[:all])
used = ->(p) { number_to_human_size(p.storage_used) }
max = ->(p) { number_to_human_size(p.storage_limit || limit.storage_limit) }
tp packages, :name, { used: used }, { limit: max }
end
desc 'cleanup', 'Cleans up a single package'
def cleanup(pkg)
package = Debci::Package.find_by_name(pkg)
limit = ::Debci::StorageLimit.new
limit.cleanup_package(package)
end
default_task :start
end
end
end