目录

前提条件

部署flask 程序

harbor1:

harbor2:

同步脚本

配置定时任务


前提条件

首先部署两个harbor,一个为主节点一个为从节点

部署flask 程序

废话不说直接上干货

harbor1:

系统自带的python2.7启动即可,需要安装一些依赖包。

文件名:harbor_api.py

#! /usr/bin/env python
#coding=utf-8
from flask import Flask,jsonify,request
import commands
import requests,json
import logging
app = Flask(__name__)
logtxt="/var/log/harbor_api.log"
def console_out(logFilename,log):
    # Define a Handler and set a format which output to file
    logging.basicConfig(
        level=logging.DEBUG,  # 定义输出到文件的log级别,大于此级别的都被输出
        format='%(asctime)s  %(filename)s : %(levelname)s  %(message)s',  # 定义输出log的格式
        datefmt='%Y-%m-%d %A %H:%M:%S',  # 时间
        filename=logFilename,  # log文件名
        filemode='a')  # 写入模式“w”或“
    console = logging.StreamHandler()  # 定义console handler
    console.setLevel(logging.INFO)  # 定义该handler级别
    formatter = logging.Formatter('%(asctime)s  %(filename)s : %(levelname)s  %(message)s')  # 定义该handler格式
    console.setFormatter(formatter)
    logging.getLogger().addHandler(console)  # 实例化添加handler
    logging.debug(log)

def get_project_id(name): #获取project_id
   # print name
    #status,result = commands.getstatusoutput('curl -sq -k -u "admin:Xxxxx" -X GET -H "Content-Type: application/json" "https://harbor.xxx-inc.com/api/search?q=%s"' % name)
    #get_data = json.loads(result)

    project_id = 0
    status,result = commands.getstatusoutput('curl -sq -k -u "admin:Xxxxx" -X GET -H "Content-Type: application/json" "https://harbor.xxx-inc.com/api/projects"')
    get_data = json.loads(result)
    for i in range(len(get_data)):
      if get_data[i]['name'] == name:
         project_id = get_data[i]['project_id']
    return project_id

@app.route('/api_ops/get_project_id',methods=['GET','POST'])
def get_projectid():  #获取项目id
    result=[]
    project_name = request.args.get("project_name")
    if project_name is None or project_name.strip()=='':
       url="https://harbor.xxx-inc.com/api/projects"
       r = requests.get(url,auth=('admin','Xxxxx'),verify=False)
       get_data = r.json()
       for i in range(len(get_data)):
           result2 = {'name':get_data[i]['name'],'project_id':get_data[i]['project_id']}
           result.append(result2)
    else:
           project_id=get_project_id(project_name)
           result2={'name':project_name,'project_id':project_id}
           result.append(result2)
    return json.dumps(result)

@app.route('/api_ops/get_item',methods=['GET','POST'])
def get_item():  #获取项目
    project_name = request.args.get("project_name")
    if project_name is None:
         harbor_url =  "curl -sq -k -u \"admin:Xxxxx\" -X GET -H \"Content-Type: application/json\" \"https://harbor.xxx-inc.com/api/projects?project_name=guest\""
    else:
         project_id=get_project_id(project_name)
         harbor_url = "curl -sq -k -u \"admin:Xxxxx\" -X GET -H \"Content-Type: application/json\" \"https://harbor.xxx-inc.com/api/projects/%s\"" % project_id
    status,result = commands.getstatusoutput(harbor_url)
    #result = json.dumps(result)
    console_out(logtxt,result)
    return result
   

@app.route('/api_ops/add_item',methods=['GET','POST']) #增加项目
def add_item():
    project_name = request.args.get("project_name")
    public = request.args.get("public")
    harbor_url = "curl -sq -k -u \"admin:Xxxxx\" -X POST -H \"Content-Type: application/json\" \"https://harbor.xxx-inc.com/api/projects\" -d '{\"project_name\": \"%s\",\"public\": %s}'" % (project_name,public)
    #add_user_url = "curl -sq -k -u \"admin:Xxxxx\" -X POST -H \"Content-Type: application/json\" \"https://harbor.xxx-inc.com/api/projects/%s/members/\" -d '{\"role_id\": 1,\"member_user\": {\"username\": \"wanglei\"}}'" % project_id
    status,result = commands.getstatusoutput(harbor_url)
    console_out(logtxt,result)
    return result
@app.route('/api_ops/add_user',methods=['GET','POST']) #项目添加用户
def add_user():
    project_name = request.args.get("project_name")
    username = request.args.get("username")
    role_id = request.args.get("role_id")
    project_id=get_project_id(project_name)
    print project_id
    harbor_url = "curl -sq -k -u \"admin:Xxxxx\" -X POST -H \"Content-Type: application/json\" \"https://harbor.xxx-inc.com/api/projects/%s/members/\" -d '{\"role_id\": %s,\"member_user\": {\"username\": \"%s\"}}'" % (project_id,role_id,username)
    status,result = commands.getstatusoutput(harbor_url)
    console_out(logtxt,result)
    return result

@app.route('/api_ops/del_item',methods=['GET','POST']) #按照项目名删除项目
def del_item():
    project_name = request.args.get("project_name")
    project_id=get_project_id(project_name)
    harbor_url = "curl -sq -k -u \"admin:Xxxxx\" -X DELETE -H \"Content-Type: application/json\" \"https://harbor.xxx-inc.com/api/projects/%s\"" % project_id
    status,result = commands.getstatusoutput(harbor_url)
    return result

@app.route('/api_ops/get_images',methods=['GET','POST'])#查询项目下有哪些镜像和查询具体镜像
def get_images():
    project_name = request.args.get("project_name")
    images_name = request.args.get("images_name")
    project_id=get_project_id(project_name)
    if images_name is None:
       harbor_url = "curl -sq -k -u \"admin:Xxxxx\" -X GET -H \"Content-Type: application/json\" \"https://harbor.xxx-inc.com/api/repositories?project_id=%s\"" % project_id
    else:
       harbor_url = "curl -sq -k -u \"admin:Xxxxx\" -X GET -H \"Content-Type: application/json\" \"https://harbor.xxx-inc.com/api/repositories?project_id=%s&q=%s\"" % (project_id,images_name)
    status,result = commands.getstatusoutput(harbor_url)
    return result

if __name__ == '__main__':
    app.run(host='10.126.156.27',port=12121,debug=True)

启动服务:

nohup python /home/sunwenbo/harbor_api.py &

harbor2:

几乎同样的代码,改掉对应的链接和密码即可

文件名:harbor_api.py

#/usr/bin.env python
#coding=utf-8
from flask import Flask,jsonify,request
import commands
import requests,json
import logging
app = Flask(__name__)
logtxt="/var/log/harbor_api.log"
def console_out(logFilename,log):
    # Define a Handler and set a format which output to file
    logging.basicConfig(
        level=logging.DEBUG,  # 定义输出到文件的log级别,大于此级别的都被输出
        format='%(asctime)s  %(filename)s : %(levelname)s  %(message)s',  # 定义输出log的格式
        datefmt='%Y-%m-%d %A %H:%M:%S',  # 时间
        filename=logFilename,  # log文件名
        filemode='a')  # 写入模式“w”或“
    console = logging.StreamHandler()  # 定义console handler
    console.setLevel(logging.INFO)  # 定义该handler级别
    formatter = logging.Formatter('%(asctime)s  %(filename)s : %(levelname)s  %(message)s')  # 定义该handler格式
    console.setFormatter(formatter)
    logging.getLogger().addHandler(console)  # 实例化添加handler
    logging.debug(log)

def get_project_id(name): #获取project_id
    #status,result = commands.getstatusoutput('curl -sq -k -u "admin:Xxxxx" -X GET -H "Content-Type: application/json" "https://harbor2.xxx-inc.com/api/search?q=%s"' % name)
    #get_data = json.loads(result)
    project_id = 0
    status,result = commands.getstatusoutput('curl -sq -k -u "admin:Xxxxx" -X GET -H "Content-Type: application/json" "https://harbor2.xxx-inc.com/api/projects"')
    get_data = json.loads(result)
    for i in range(len(get_data)):
      if get_data[i]['name'] == name:
         project_id = get_data[i]['project_id']
    return project_id

@app.route('/api_ops/get_project_id',methods=['GET','POST'])
def get_projectid():  #获取项目id
    result=[]
    project_name = request.args.get("project_name")
    if project_name is None or project_name.strip()=='':
       url="https://harbor2.xxx-inc.com/api/projects"
       r = requests.get(url,auth=('admin','Xxxxx'),verify=False)
       get_data = r.json()
       for i in range(len(get_data)):
           result2 = {'name':get_data[i]['name'],"project_id": get_data[i]['project_id']}
           result.append(result2)
    else:
           project_id=get_project_id(project_name)
           result2={'name':project_name,'project_id':project_id}
           result.append(result2)
    return json.dumps(result)
    
@app.route('/api_ops/get_item',methods=['GET','POST'])
def get_item():  #获取项目
    project_name = request.args.get("project_name")
    if project_name is None or project_name.strip()=='':
         harbor_url =  "curl -sq -k -u \"admin:Xxxxx\" -X GET -H \"Content-Type: application/json\" \"https://harbor2.xxx-inc.com/api/projects?project_name=guest\""
    else:
         project_id=get_project_id(project_name)
         harbor_url = "curl -sq -k -u \"admin:Xxxxx\" -X GET -H \"Content-Type: application/json\" \"https://harbor2.xxx-inc.com/api/projects/%s\"" % project_id
    status,result = commands.getstatusoutput(harbor_url)
    #result = json.dumps(result)
    console_out(logtxt,result)
    return result


@app.route('/api_ops/add_item',methods=['GET','POST']) #增加项目
def add_item():
    project_name = request.args.get("project_name")
    public = request.args.get("public")
    harbor_url = "curl -sq -k -u \"admin:Xxxxx\" -X POST -H \"Content-Type: application/json\" \"https://harbor2.xxx-inc.com/api/projects\" -d '{\"project_name\": \"%s\",\"public\": %s}'" % (project_name,public)
    #add_user_url = "curl -sq -k -u \"admin:Xxxxx\" -X POST -H \"Content-Type: application/json\" \"https://harbor2.xxx-inc.com/api/projects/%s/members/\" -d '{\"role_id\": 1,\"member_user\": {\"username\": \"wanglei\"}}'" % project_id
    status,result = commands.getstatusoutput(harbor_url)
    console_out(logtxt,result)
    return result
@app.route('/api_ops/add_user',methods=['GET','POST']) #项目添加用户
def add_user():
    project_name = request.args.get("project_name")
    username = request.args.get("username")
    role_id = request.args.get("role_id")
    project_id=get_project_id(project_name)
    print project_id
    harbor_url = "curl -sq -k -u \"admin:Xxxxx\" -X POST -H \"Content-Type: application/json\" \"https://harbor2.xxx-inc.com/api/projects/%s/members/\" -d '{\"role_id\": %s,\"member_user\": {\"username\": \"%s\"}}'" % (project_id,role_id,username)
    status,result = commands.getstatusoutput(harbor_url)
    console_out(logtxt,result)
    return result

@app.route('/api_ops/del_item',methods=['GET','POST']) #按照项目名删除项目
def del_item():
    project_name = request.args.get("project_name")
    project_id=get_project_id(project_name)
    harbor_url = "curl -sq -k -u \"admin:Xxxxx\" -X DELETE -H \"Content-Type: application/json\" \"https://harbor2.xxx-inc.com/api/projects/%s\"" % project_id
    status,result = commands.getstatusoutput(harbor_url)
    return result

@app.route('/api_ops/get_images',methods=['GET','POST'])#查询项目下有哪些镜像和查询具体镜像
def get_images():
    project_name = request.args.get("project_name")
    images_name = request.args.get("images_name")
    project_id=get_project_id(project_name)
    if images_name is None:
       harbor_url = "curl -sq -k -u \"admin:Xxxxx\" -X GET -H \"Content-Type: application/json\" \"https://harbor2.xxx-inc.com/api/repositories?project_id=%s\"" % project_id
    else:
       harbor_url = "curl -sq -k -u \"admin:Xxxxx\" -X GET -H \"Content-Type: application/json\" \"https://harbor2.xxx-inc.com/api/repositories?project_id=%s&q=%s\"" % (project_id,images_name)
    status,result = commands.getstatusoutput(harbor_url)
    return result

if __name__ == '__main__':
    app.run(host='10.126.156.2',port=12121,debug=True)

 启动服务:

nohup python /home/sunwenbo/harbor_api.py &

同步脚本

在harbor2 节点部署同步镜像脚本

文件名:harbor_replication.py

import json,requests,time,subprocess
import logging,datetime
from requests.packages.urllib3.exceptions import InsecureRequestWarning
from logging import handlers
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

class Logger(object):
    level_relations = {
        'debug':logging.DEBUG,
        'info':logging.INFO,
        'warning':logging.WARNING,
        'error':logging.ERROR,
        'crit':logging.CRITICAL
    }#日志级别关系映射

    def __init__(self,filename,level='info',when='D',backCount=3,fmt='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s'):
        self.logger = logging.getLogger(filename)
        format_str = logging.Formatter(fmt)#设置日志格式
        self.logger.setLevel(self.level_relations.get(level))#设置日志级别
        sh = logging.StreamHandler()#往屏幕上输出
        sh.setFormatter(format_str) #设置屏幕上显示的格式
        th = handlers.TimedRotatingFileHandler(filename=filename,when=when,backupCount=backCount,encoding='utf-8')#往文件里写入#指定间隔时间自动生成文件的处理器
        #实例化TimedRotatingFileHandler
        #interval是时间间隔,backupCount是备份文件的个数,如果超过这个个数,就会自动删除,when是间隔的时间单位,单位有以下几种:
        # S 秒
        # M 分
        # H 小时、
        # D 天、
        # W 每星期(interval==0时代表星期一)
        # midnight 每天凌晨
        th.setFormatter(format_str)#设置文件里写入的格式
        self.logger.addHandler(sh) #把对象加到logger里
        self.logger.addHandler(th)


def get_project_id(name): #获取project_id
    project_id = 0
    status,result = subprocess.getstatusoutput('curl -sq -k -u "admin:Xxxxx" -X GET -H "Content-Type: application/json" "https://harbor.xxx-inc.com/api/projects"')
    get_data = json.loads(result)
    for i in range(len(get_data)):
      if get_data[i]['name'] == name:
         project_id = get_data[i]['project_id']
    return project_id

def get_project(url): #获取有哪些项目
    harbor_result = requests.get(url)
    result =  harbor_result.json()
    project = []
    for i in range(len(result)):
        project.append(result[i]['name'])
    return project

def add_replication(*diff_project): #增加复制规则
    for name in diff_project:
        #console_out(logtxt,name)
        replication_name = name
        project_name = name
        project_id = get_project_id(name)

        url = "https://harbor.xxx-inc.com/api/policies/replication"

        payload = {
            "name": "content-process-cpp-component-server",
            "description": "",
            "trigger": {
                "kind": "Immediate"
            },
            "replicate_existing_image_now": True,
            "replicate_deletion": True,
            "filters": [],
            "projects": [
                {
                    "project_id": 27,
                    "owner_id": 1,
                    "name": "content-process-cpp-component-server",
                    "creation_time": "2022-12-02T03:16:38Z",
                    "update_time": "2022-12-02T03:16:38Z",
                    "deleted": False,
                    "owner_name": "",
                    "togglable": False,
                    "current_user_role_id": 0,
                    "repo_count": 0,
                    "chart_count": 0,
                    "metadata": {
                        "auto_scan": "false",
                        "enable_content_trust": "false",
                        "prevent_vul": "false",
                        "public": "true",
                        "severity": "low"
                    }
                }
            ],
            "targets": [
                {
                    "id": 2,
                    "endpoint": "https://harbor2.xxx-inc.com",
                    "name": "harbor2.xxx-inc.com",
                    "username": "admin",
                    "password": "",
                    "type": 0,
                    "insecure": True,
                    "creation_time": "2022-12-01T02:26:31.923545Z",
                    "update_time": "2022-12-02T16:43:21.755517Z"
                }
            ]
        }
        now_time = datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ')
        payload["name"] = project_name
        payload["projects"][0]["project_id"] = project_id
        payload["projects"][0]["name"]  = replication_name
        payload["projects"][0]["name"] = replication_name
        payload["projects"][0]["creation_time"] = now_time
        payload["projects"][0]["update_time"] = now_time

        payload = json.dumps(payload)
        headers = {
            'accept': 'application/json',
            'Content-Type': 'application/json',
            'X-Content-Type-Options': 'nosniff',
            'Authorization': 'Basic YWRtaW46T3BzMTIzNDU=',
            'Cookie': 'sid=b111caf0872f37009a9e0d36439581ef'
        }
        response = requests.request("POST", url, headers=headers, data=payload, verify=False)
        if response.status_code == 201:
            log.logger.info("%s project add replication successful. status_code: %d"  % (project_name,response.status_code))
            time.sleep(5)
        elif  response.status_code == 409:
            log.logger.warning("%s The mirror repository is empty. status_code: %d"  % (project_name,response.status_code))
        else:
            log.logger.error("%s project add replication failure. status_code: %d"  % (project_name,response.status_code))


harbor1_url = "http://10.126.156.27:12121/api_ops/get_item"
harbor2_url = "http://10.126.156.2:12121/api_ops/get_item"
harbor1_project = get_project(harbor1_url)
harbor2_project = get_project(harbor2_url)
log = Logger('/var/log/harbor/harbor_replication.log', level='debug')
# harbor1_project中有而harbor2_project中没有的,
diff_project = tuple(set(harbor1_project).difference(set(harbor2_project)))
add_replication(*diff_project)

配置定时任务

harbor2节点增加定时任务,每三十分钟执行一次

*/30 * * * *  /bin/python3 /home/sunwenbo/harbor_replication.py