1、脚本通过python调用api接口去删除镜像的,适用于harbor2.0的api接口,只保留镜像的最近的5个tag版本。
import requests
import logging
DATEFMT = '%Y/%m/%d %H:%M:%S'
FORMAT = '%(asctime)s %(levelname)s %(message)s'
# 设置保存路径、日志等级、样式、记录时间
logging.basicConfig(filename='cleanHarbor.log', filemode="w", level=logging.DEBUG, format=FORMAT, datefmt=DATEFMT)
class HarborApi(object):
def __init__(self):
url = "https://harbor.com"
version = "v2.0"
username = "admin"
password = ""
self.base_url = "{}/api/{}".format(url, version)
self.auth_info = (username, password)
def get_projects(self, page=1, page_size=15):
"""
获取projects
"""
# api_url = "{}/projects".format(self.base_url,)
api_url = f"{self.base_url}/projects"
payload = {
'page': page,
'page_size': page_size
}
r = requests.get(api_url, params=payload, auth=self.auth_info)
if r.status_code == 200:
data = {
'list': r.json(),
'total': int(r.headers.get('X-Total-Count'))
}
return data
else:
return False
def get_all_repositories_name(self, project_name):
"""
获取所有镜像库名称
"""
page_size = 100
r_data = self.get_repositories(
project_name=project_name, page_size=page_size)
# print(r_data)
r_total = r_data.get('total')
if r_total <= page_size:
r_name_list = [i.get('name').split(
f'{project_name}/')[1] for i in r_data.get('list')]
else:
r_page_count = int(r_total // page_size) + 1
r_list = list()
if r_page_count > 0:
for page_num in range(1, r_page_count + 1):
tmp_r_data = self.get_repositories(
project_name=project_name, page=page_num, page_size=page_size)
r_list += tmp_r_data.get('list')
r_name_list = [i.get('name').split(
f'{project_name}/')[1] for i in r_list]
return r_name_list
# repositories
def get_repositories(self, project_name, page=1, page_size=10):
"""
获取repositories
"""
api_url = f"{self.base_url}/projects/{project_name}/repositories"
payload = {
'page': page,
'page_size': page_size
}
r = requests.get(api_url, params=payload, auth=self.auth_info)
if r.status_code == 200:
data = {
'list': r.json(),
'total': int(r.headers.get('X-Total-Count'))
}
return data
else:
return False
# artifacts
def get_artifacts(self, project_name, repository_name, page=1, page_size=10):
"""
获取artifacts
"""
# api_url = self.base_url + 'projects/' + \
# project_name + '/repositories/' + repository_name + '/artifacts'
api_url = f"{self.base_url}/projects/{project_name}/repositories/{repository_name}/artifacts"
payload = {
'page': page,
'page_size': page_size
}
r = requests.get(api_url, params=payload, auth=self.auth_info)
if r.status_code == 200:
data = {
'list': r.json(),
'total': int(r.headers.get('X-Total-Count'))
}
return data
else:
return False
def get_artifacts_info(self, project_name, repository_name, page_size=100):
"""
返回字典
{
2202: {
'digest': 'sha256:42c81fef9bab44db198fb4123dc41a8511f491c0c5977803ad226184d0a8c93a',
'tags': ['dev-20220902151655']
},
2200: {
'digest': 'sha256:b8b98515dc61054fa19b74b7bb31f8414382585cdfff12c370c53d22b48a3021',
'tags': ['dev-20220902150345']
}
}
"""
a_data = self.get_artifacts(
project_name=project_name, repository_name=repository_name, page_size=page_size)
a_total = a_data.get('total')
if a_total <= page_size:
tmp_a_list = a_data.get('list')
else:
a_page_count = int(a_total // page_size) + 1
tmp_a_list = list()
if a_page_count > 0:
for page_num in range(1, a_page_count + 1):
tmp_a_data = self.get_artifacts(
project_name=project_name, repository_name=repository_name, page=page_num, page_size=page_size)
tmp_a_list += tmp_a_data.get('list')
a_dict = dict()
tags_list = list()
for artifact in tmp_a_list:
if artifact['tags'] and len(artifact['tags']) >= 0:
tags = [g['name'] for g in artifact.get('tags')]
a_dict[artifact.get('id')] = {
'digest': artifact.get('digest'),
'tags': tags
}
tags_list += tags
a_dict['tags'] = tags_list
return a_dict
def generate_delete_list(self, project_name, repository_name):
"""
生成删除列表
"""
save_max_num = 5
a_data = self.get_artifacts_info(
project_name=project_name, repository_name=repository_name)
tags_list = a_data.get('tags')
if len(tags_list) > save_max_num:
del_tags_list = tags_list[5:]
else:
del_tags_list = []
del_digest_list = list()
for k, v in a_data.items():
if type(v) is dict:
if v.get('tags')[0] in del_tags_list:
del_digest_list.append(v.get('digest'))
# print(len(tags_list),len(del_tags_list),len(del_digest_list))
return del_digest_list
# del artifacts
def del_artifact(self, project_name, repository_name, digest):
"""
删除镜像artifact
curl -u admin:sajdhaksh -X DELETE "https://harbor.com/api/v2.0/projects/izu/repositories/izu-mrcar-workflow/artifacts/sha256:26249cff21efc04d7b696c4c86bbae88d4e042407471ff8951aa292d583c34ff"
"""
api_url = f"{self.base_url}/projects/{project_name}/repositories/{repository_name}/artifacts/{digest}"
r = requests.delete(api_url, auth=self.auth_info)
if r.status_code == 200:
return True
else:
return False
def clean_artifact(self, project_name, repository_name):
"""
自动清理空间
1.获取所有仓库名称 get_all_repositories_name
2.获取仓库内制品 get_artifacts_info
3.只保留最近的5个tag
4.删除制品
"""
# if project_name != 'izu':
# return False
del_digest_list = self.generate_delete_list(
project_name=project_name, repository_name=repository_name)
real_del_num = 0
for digest in del_digest_list:
result = self.del_artifact(
project_name=project_name, repository_name=repository_name, digest=digest)
if result:
real_del_num += 1
logging.info(
f"项目:{project_name},仓库:{repository_name},总镜像数{5 + len(del_digest_list)},应删除{len(del_digest_list)},已删除{real_del_num}")
return f"项目:{project_name},仓库:{repository_name},总镜像数{5 + len(del_digest_list)},应删除{len(del_digest_list)},已删除{real_del_num}"
if __name__ == '__main__':
hb = HarborApi()
#填写需要清理horbor的项目名
project_names = ['', '']
for project_name in project_names:
r_name_list = hb.get_all_repositories_name(project_name=project_name)
# print(len(r_name_list))
for r_name in r_name_list:
res = hb.clean_artifact(project_name=project_name, repository_name=r_name)
print(res)
2、在harbor仓库里面系统管理-垃圾清理配置下定时清理规则