Commit c93ec0b4 authored by Rémy Coutable's avatar Rémy Coutable

ci: Automate the cleanup of stale PVC

This adds automated cleanup of stale PVC that were created as part of
Review Apps but are not is use anymore.
Signed-off-by: default avatarRémy Coutable <remy@rymai.me>
parent 4e2a2eff
...@@ -6,7 +6,7 @@ require "guard/rspec/dsl" ...@@ -6,7 +6,7 @@ require "guard/rspec/dsl"
cmd = ENV['GUARD_CMD'] || (ENV['SPRING'] ? 'spring rspec' : 'bundle exec rspec') cmd = ENV['GUARD_CMD'] || (ENV['SPRING'] ? 'spring rspec' : 'bundle exec rspec')
directories %w(app ee lib spec) directories %w(app ee lib rubocop tooling spec)
rspec_context_for = proc do |context_path| rspec_context_for = proc do |context_path|
OpenStruct.new(to_s: "spec").tap do |rspec| OpenStruct.new(to_s: "spec").tap do |rspec|
...@@ -42,6 +42,8 @@ guard_setup = proc do |context_path| ...@@ -42,6 +42,8 @@ guard_setup = proc do |context_path|
# Ruby files # Ruby files
watch(%r{^#{context_path}(lib/.+)\.rb$}) { |m| rspec.spec.call(m[1]) } watch(%r{^#{context_path}(lib/.+)\.rb$}) { |m| rspec.spec.call(m[1]) }
watch(%r{^#{context_path}(rubocop/.+)\.rb$}) { |m| rspec.spec.call(m[1]) }
watch(%r{^#{context_path}(tooling/.+)\.rb$}) { |m| rspec.spec.call(m[1]) }
# Rails files # Rails files
rails = rails_context_for.call(context_path, %w(erb haml slim)) rails = rails_context_for.call(context_path, %w(erb haml slim))
......
...@@ -115,6 +115,10 @@ class AutomatedCleanup ...@@ -115,6 +115,10 @@ class AutomatedCleanup
delete_helm_releases(releases_to_delete) delete_helm_releases(releases_to_delete)
end end
def perform_stale_pvc_cleanup!(days:)
kubernetes.cleanup_by_created_at(resource_type: 'pvc', created_before: threshold_time(days: days), wait: false)
end
private private
def fetch_environment(environment) def fetch_environment(environment)
...@@ -155,7 +159,7 @@ class AutomatedCleanup ...@@ -155,7 +159,7 @@ class AutomatedCleanup
releases_names = releases.map(&:name) releases_names = releases.map(&:name)
helm.delete(release_name: releases_names) helm.delete(release_name: releases_names)
kubernetes.cleanup(release_name: releases_names, wait: false) kubernetes.cleanup_by_release(release_name: releases_names, wait: false)
rescue Tooling::Helm3Client::CommandFailedError => ex rescue Tooling::Helm3Client::CommandFailedError => ex
raise ex unless ignore_exception?(ex.message, IGNORED_HELM_ERRORS) raise ex unless ignore_exception?(ex.message, IGNORED_HELM_ERRORS)
...@@ -198,4 +202,8 @@ timed('Helm releases cleanup') do ...@@ -198,4 +202,8 @@ timed('Helm releases cleanup') do
automated_cleanup.perform_helm_releases_cleanup!(days: 7) automated_cleanup.perform_helm_releases_cleanup!(days: 7)
end end
timed('Stale PVC cleanup') do
automated_cleanup.perform_stale_pvc_cleanup!(days: 30)
end
exit(0) exit(0)
...@@ -66,13 +66,15 @@ module Tooling ...@@ -66,13 +66,15 @@ module Tooling
%(--output json), %(--output json),
*args *args
] ]
releases = JSON.parse(run_command(command)) # rubocop:disable Gitlab/Json
response = run_command(command)
releases = JSON.parse(response) # rubocop:disable Gitlab/Json
releases.map do |release| releases.map do |release|
Release.new(*release.values_at(*RELEASE_JSON_ATTRIBUTES)) Release.new(*release.values_at(*RELEASE_JSON_ATTRIBUTES))
end end
rescue ::JSON::ParserError => ex rescue ::JSON::ParserError => ex
puts "Ignoring this JSON parsing error: #{ex}" # rubocop:disable Rails/Output puts "Ignoring this JSON parsing error: #{ex}\n\nResponse was:\n#{response}" # rubocop:disable Rails/Output
[] []
end end
......
# frozen_string_literal: true # frozen_string_literal: true
require 'json'
require 'time'
require_relative '../../../lib/gitlab/popen' unless defined?(Gitlab::Popen) require_relative '../../../lib/gitlab/popen' unless defined?(Gitlab::Popen)
require_relative '../../../lib/gitlab/json' unless defined?(Gitlab::JSON)
module Tooling module Tooling
class KubernetesClient class KubernetesClient
...@@ -14,11 +15,16 @@ module Tooling ...@@ -14,11 +15,16 @@ module Tooling
@namespace = namespace @namespace = namespace
end end
def cleanup(release_name:, wait: true) def cleanup_by_release(release_name:, wait: true)
delete_by_selector(release_name: release_name, wait: wait) delete_by_selector(release_name: release_name, wait: wait)
delete_by_matching_name(release_name: release_name) delete_by_matching_name(release_name: release_name)
end end
def cleanup_by_created_at(resource_type:, created_before:, wait: true)
resource_names = resource_names_created_before(resource_type: resource_type, created_before: created_before)
delete_by_exact_names(resource_type: resource_type, resource_names: resource_names, wait: wait)
end
private private
def delete_by_selector(release_name:, wait:) def delete_by_selector(release_name:, wait:)
...@@ -45,6 +51,21 @@ module Tooling ...@@ -45,6 +51,21 @@ module Tooling
run_command(command) run_command(command)
end end
def delete_by_exact_names(resource_names:, wait:, resource_type: nil)
command = [
'delete',
resource_type,
%(--namespace "#{namespace}"),
'--now',
'--ignore-not-found',
'--include-uninitialized',
%(--wait=#{wait}),
resource_names.join(' ')
]
run_command(command)
end
def delete_by_matching_name(release_name:) def delete_by_matching_name(release_name:)
resource_names = raw_resource_names resource_names = raw_resource_names
command = [ command = [
...@@ -70,8 +91,26 @@ module Tooling ...@@ -70,8 +91,26 @@ module Tooling
run_command(command).lines.map(&:strip) run_command(command).lines.map(&:strip)
end end
def resource_names_created_before(resource_type:, created_before:)
command = [
'get',
resource_type,
%(--namespace "#{namespace}"),
"--sort-by='{.metadata.creationTimestamp}'",
'-o json'
]
response = run_command(command)
JSON.parse(response)['items'] # rubocop:disable Gitlab/Json
.map { |resource| resource.dig('metadata', 'name') if Time.parse(resource.dig('metadata', 'creationTimestamp')) < created_before }
.compact
rescue ::JSON::ParserError => ex
puts "Ignoring this JSON parsing error: #{ex}\n\nResponse was:\n#{response}" # rubocop:disable Rails/Output
[]
end
def run_command(command) def run_command(command)
final_command = ['kubectl', *command].join(' ') final_command = ['kubectl', *command.compact].join(' ')
puts "Running command: `#{final_command}`" # rubocop:disable Rails/Output puts "Running command: `#{final_command}`" # rubocop:disable Rails/Output
result = Gitlab::Popen.popen_with_detail([final_command]) result = Gitlab::Popen.popen_with_detail([final_command])
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment