Commit bc30c7f2 authored by Mark Lapierre's avatar Mark Lapierre

Update SSH keys delete script

- Defaults to deleting keys with new title prefix 'E2E test key:'
- Allows specifying the part of the title to match
- Allows a dry run that lists keys without deleting them
- Allows deletion only if keys were created before a given date
- Handles pagination
- Deletes keys for the user who owns the access token supplied.
  This lets us use the script in prod or other environments where
  we don't have an admin account
parent f48bd763
...@@ -41,7 +41,13 @@ end ...@@ -41,7 +41,13 @@ end
desc "Generate data and run load tests" desc "Generate data and run load tests"
task generate_data_and_run_load_test: [:generate_perf_testdata, :run_artillery_load_tests] task generate_data_and_run_load_test: [:generate_perf_testdata, :run_artillery_load_tests]
desc "Deletes test ssh keys for a provided user" desc "Deletes test ssh keys a user"
task :delete_test_ssh_keys do task :delete_test_ssh_keys, [:title_portion, :delete_before] do |t, args|
QA::Tools::DeleteTestSSHKeys.new.run QA::Tools::DeleteTestSSHKeys.new(args).run
end
desc "Dry run of deleting test ssh keys for a user. Lists keys to be deleted"
task :delete_test_ssh_keys_dry_run, [:title_portion, :delete_before] do |t, args|
args.with_defaults(dry_run: true)
QA::Tools::DeleteTestSSHKeys.new(args).run
end end
...@@ -2,59 +2,78 @@ ...@@ -2,59 +2,78 @@
require_relative '../../qa' require_relative '../../qa'
# This script deletes all test ssh keys (with titles including 'key for ssh tests' or 'key for audit event test') of a user specified by ENV['GITLAB_USERNAME'] # This script deletes all selected test ssh keys for a specific user
# Required environment variables: GITLAB_QA_ACCESS_TOKEN, GITLAB_ADDRESS and GITLAB_USERNAME # Keys can be selected by a string matching part of the key's title and by created date
# - Specify `title_portion` to delete only keys that include the string provided
# - Specify `delete_before` to delete only keys that were created before the given date
#
# If `dry_run` is true the script will list the keys by title and indicate whether each will be deleted
#
# Required environment variables: GITLAB_QA_ACCESS_TOKEN and GITLAB_ADDRESS
# - GITLAB_QA_ACCESS_TOKEN should have API access and belong to the user whose keys will be deleted
module QA module QA
module Tools module Tools
class DeleteTestSSHKeys class DeleteTestSSHKeys
include Support::Api include Support::Api
def initialize ITEMS_PER_PAGE = '100'
def initialize(title_portion: 'E2E test key:', delete_before: Date.today.to_s, dry_run: false)
raise ArgumentError, "Please provide GITLAB_ADDRESS" unless ENV['GITLAB_ADDRESS'] raise ArgumentError, "Please provide GITLAB_ADDRESS" unless ENV['GITLAB_ADDRESS']
raise ArgumentError, "Please provide GITLAB_QA_ACCESS_TOKEN" unless ENV['GITLAB_QA_ACCESS_TOKEN'] raise ArgumentError, "Please provide GITLAB_QA_ACCESS_TOKEN" unless ENV['GITLAB_QA_ACCESS_TOKEN']
raise ArgumentError, "Please provide GITLAB_USERNAME" unless ENV['GITLAB_USERNAME']
@api_client = Runtime::API::Client.new(ENV['GITLAB_ADDRESS'], personal_access_token: ENV['GITLAB_QA_ACCESS_TOKEN']) @api_client = Runtime::API::Client.new(ENV['GITLAB_ADDRESS'], personal_access_token: ENV['GITLAB_QA_ACCESS_TOKEN'])
@username = ENV['GITLAB_USERNAME'] @title_portion = title_portion
@delete_before = Date.parse(delete_before)
@dry_run = dry_run
end end
def run def run
STDOUT.puts 'Running...' STDOUT.puts 'Running...'
user_id = fetch_user_id keys_head_response = head Runtime::API::Request.new(@api_client, "/user/keys", per_page: ITEMS_PER_PAGE).url
test_ssh_key_ids = fetch_test_ssh_key_ids(user_id) total_pages = keys_head_response.headers[:x_total_pages]
test_ssh_key_ids = fetch_test_ssh_key_ids(total_pages)
STDOUT.puts "Number of test ssh keys to be deleted: #{test_ssh_key_ids.length}" STDOUT.puts "Number of test ssh keys to be deleted: #{test_ssh_key_ids.length}"
delete_ssh_keys(user_id, test_ssh_key_ids) unless test_ssh_key_ids.empty? return if dry_run?
delete_ssh_keys(test_ssh_key_ids) unless test_ssh_key_ids.empty?
STDOUT.puts "\nDone" STDOUT.puts "\nDone"
end end
private private
def fetch_user_id attr_reader :dry_run
get_user_response = get Runtime::API::Request.new(@api_client, "/users?username=#{@username}").url alias_method :dry_run?, :dry_run
user = JSON.parse(get_user_response.body).first
raise "Unexpected user found. Expected #{@username}, found #{user['username']}" unless user['username'] == @username
user["id"] def delete_ssh_keys(ssh_key_ids)
end
def delete_ssh_keys(user_id, ssh_key_ids)
STDOUT.puts "Deleting #{ssh_key_ids.length} ssh keys..." STDOUT.puts "Deleting #{ssh_key_ids.length} ssh keys..."
ssh_key_ids.each do |key_id| ssh_key_ids.each do |key_id|
delete_response = delete Runtime::API::Request.new(@api_client, "/users/#{user_id}/keys/#{key_id}").url delete_response = delete Runtime::API::Request.new(@api_client, "/user/keys/#{key_id}").url
dot_or_f = delete_response.code == 204 ? "\e[32m.\e[0m" : "\e[31mF\e[0m" dot_or_f = delete_response.code == 204 ? "\e[32m.\e[0m" : "\e[31mF\e[0m"
print dot_or_f print dot_or_f
end end
end end
def fetch_test_ssh_key_ids(user_id) def fetch_test_ssh_key_ids(pages)
get_keys_response = get Runtime::API::Request.new(@api_client, "/users/#{user_id}/keys").url key_ids = []
JSON.parse(get_keys_response.body)
.select { |key| (key["title"].include?('key for ssh tests') || key["title"].include?('key for audit event test')) } pages.to_i.times do |page_no|
.map { |key| key['id'] } get_keys_response = get Runtime::API::Request.new(@api_client, "/user/keys", page: (page_no + 1).to_s, per_page: ITEMS_PER_PAGE).url
.uniq keys = JSON.parse(get_keys_response.body).select do |key|
to_delete = key['title'].include?(@title_portion) && Date.parse(key['created_at']) < @delete_before
puts "Key title: #{key['title']}\tcreated_at: #{key['created_at']}\tdelete? #{to_delete}" if dry_run?
to_delete
end
key_ids.concat(keys.map { |key| key['id'] })
end
key_ids.uniq
end end
end end
end end
......
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