The Python Script Of Jenkins Pipeline

Python Script 使用流程:

  • 基于devops的第一篇,其中会有基于对harbor自动创建相应的项目,基于项目所使用的机器人以及即时更新jenkins配置从而实现jenkins publish自动化的脚本展示
需求分析

http://ip:port/delete/projectName/serviceName/[timestamp|tag] # 删除某个tag的Artifact
http://ip:port/update/projectName/robot requestBody:robot的相关信息 # 修改robot的配置信息,比如robot过期时间,robot的各种权限
http://ip:port/create/projectName # 创建项目信息,同时创建对Artifact的tag的操作机制以及各环境对Artifact操作的robot

效果展示
  • web(api接口入口)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
import sys
import time
from datetime import datetime, timedelta, timezone
from http.server import BaseHTTPRequestHandler, HTTPServer
import urllib.parse
from doHarbor import DoHarbor
from doJenkins import DoJenkins

class RequestHandler(BaseHTTPRequestHandler):

def do_GET(self):
# 输出请求到达的时间
now = datetime.now()
time_format = now.strftime("%H:%M:%S")
print(f"请求到达的时间为 {time_format}")
self.doHarbor.loadConfig()
self.doJenkins.loadConfig()
# 对URI进行解析
parsed_path = urllib.parse.urlparse(self.path)
# 获取路径
paths = parsed_path.path[1:].split("/")
if len(paths) == 2:
method = paths[0]
env = paths[1]
match method:
case 'create':
# http://ip:port/create/dev-pjcxa
response_content = ""
# project
self.doHarbor.projectTemplate["project_name"] = env
response = self.doHarbor.cheackProjects(env)
if response == "-":
response = self.doHarbor.createProject(self.doHarbor.projectTemplate)
if response != "-" :
response_content += f"{env}的项目创建成功\n"
else:
response_content += f"{env}的项目已存在,正校验其他配置...\n"
project_id = self.doHarbor.getProjectIdOrName(env)["project_id"]
retention_id = self.doHarbor.getProjectIdOrName(env)["metadata"]["retention_id"]
# tag-retention
if retention_id is None:
retention_id = self.doHarbor.getProjectIdOrName(self.doHarbor.templateProject)["metadata"]["retention_id"]
retention = self.doHarbor.getRetention(retention_id).to_dict()
retention.pop("id",'该仓库暂不存在id')
retention["scope"]["ref"] = project_id
response = self.doHarbor.createRetention(retention)
if response != "-":
response_content += f"{env}的tag保留机制配置完成\n"
else:
response_content += f"{env}的tag保留机制已配置,正校验其他配置...\n"
# robot
robots = self.doHarbor.getRobotsInProjectIdOrName(env)
if len(robots) == 0:
robotTemplate = self.doHarbor.getRobotsInProjectIdOrName(self.doHarbor.templateProject)[0].to_dict()
robot = {}
robot["name"] = env
robot["duration"] = robotTemplate["duration"]
robot["expires_at"] = robotTemplate["expires_at"]
access_list = robotTemplate["permissions"][0]["access"]
robot_list = []
for resoure in access_list:
if resoure["resource"] == 'project':
continue
elif resoure["resource"] == 'metadata':
continue
resoure["resource"] = f"/project/{project_id}/{resoure['resource']}"
robot_list.append(resoure)
robot["access"] = robot_list
response = self.doHarbor.createRobotInProjectIdOrName(env,robot).to_dict()
robot = self.doHarbor.getRobotsInProjectIdOrNameAndRobotId(env,response["id"]).to_dict()
robot["duration"] = -1
robot["expires_at"] = -1
robot["update_time"] = datetime.now(timezone.utc)
response_1 = self.doHarbor.updateRobot(robot)
# print(response_1)
if response != "-" and response_1 == None:
# if response != "-" :
response_content += f"{env}的robot机器人配置完成\n"
robot_id = response["id"]
robot_name = response["name"]
robot_secret = response["secret"]
self.doHarbor.saveRobotMessage(robot_id, robot_name, robot_secret)
# robot -- jenkins
self.doJenkins.createCredential(robot_name, robot_secret, env)
response_content += f"{env}已配置到jenkins中\n"
else:
response_content += f"{env}的robot机器人已配置,正校验其他配置...\n"
response_content += f"{env}的已配置完毕...\n"
self.send_response(200)
self.send_header('Content-type', 'application/json; charset=utf-8')
self.end_headers()
self.wfile.write(response_content.encode('utf-8'))
case _:
self.send_error(404, "Not Found")
elif len(paths) == 3:
# http://ip:port/update/dev-pjcxa/robot
method = paths[0]
env = paths[1]
content = paths[2]
match method:
case 'update':
response_content = ""
match content:
case 'robot':
robot = self.doHarbor.getRobotsInProjectIdOrName(env)[0].to_dict()
# project_id = self.doHarbor.getProjectIdOrName(env)["project_id"]
# robot_id = robot["id"]
robot_expires_time = robot["expires_at"]
now_time = int(time.time())
robot_expires_time = datetime.utcfromtimestamp(robot_expires_time)
now_time = datetime.utcfromtimestamp(now_time)
delta = robot_expires_time - now_time
days = delta.days
if days <= 1:
robot["duration"] = -1
robot["expires_at"] = -1
robot["update_time"] = datetime.now(timezone.utc)
print(robot)
response = self.doHarbor.updateRobot(robot)
if response == None:
response_content += f"{env}的robot机器人配置修改为长期完毕\n"
else:
self.send_error(404, f"{env}的机器人配置修改失败")
return
# response = self.doHarbor.deleteRobotInProjectIdOrNameAndRobotId(env,robot_id)
# if response is None:
# robotTemplate = self.doHarbor.getRobotsInProjectIdOrName(self.doHarbor.templateProject)[
# 0].to_dict()
# robot = {}
# robot["name"] = env
# robot["duration"] = robotTemplate["duration"]
# robot["expires_at"] = robotTemplate["expires_at"]
# access_list = robotTemplate["permissions"][0]["access"]
# robot_list = []
# for resoure in access_list:
# if resoure["resource"] == 'project':
# continue
# elif resoure["resource"] == 'metadata':
# continue
# resoure["resource"] = f"/project/{project_id}/{resoure['resource']}"
# robot_list.append(resoure)
# robot["access"] = robot_list
# response = self.doHarbor.createRobotInProjectIdOrName(env, robot).to_dict()
# response_1 = self.doHarbor.updateRobot(robot)
# if response != "-" and response_1 != None:
# response = self.doHarbor.updateRobot(robot)
# response_content += f"{env}的robot机器人配置完成\n"
# robot_id = response["id"]
# robot_name = response["name"]
# robot_secret = response["secret"]
# self.doHarbor.saveRobotMessage(robot_id, robot_name, robot_secret)
# # robot -- jenkins
# self.doJenkins.createCredential(robot_name, robot_secret, env)
# response_content += f"{env}已更新到jenkins中\n"
# else:
# self.send_error(404, f"{env}的机器人删除失败")
# return
else:
response_content += f"{env}的robot机器人暂未过期,无需调整\n"
self.send_response(200)
self.send_header('Content-type', 'application/json; charset=utf-8')
self.end_headers()
self.wfile.write(response_content.encode('utf-8'))
case _:
self.send_error(404, "Not Found")
case 'status':
response_content = ""
# http://ip:port/status/dev-pjcxa/botstudio
repositories = self.doHarbor.listRepository(env)
for repository in repositories:
repository = repository.to_dict()
if repository["name"] == content:
response_content += f"{env}{content}存在...\n"
self.send_response(200)
self.send_header('Content-type', 'application/json; charset=utf-8')
self.end_headers()
self.wfile.write(response_content.encode('utf-8'))
return
else:
self.send_error(404, f"{env}'s {content} is not exist...")
case _:
self.send_error(404, "Not Found")
elif len(paths) == 4:
# http://ip:port/delete/dev-pjcxa/botstudio/timestamp
method = paths[0]
env = paths[1]
content = paths[2]
timestamps = paths[3]
response_content = ""
match method:
case 'delete':
response = self.doHarbor.deleteArtifact(env,content,timestamps)
if response is None:
response_content += f"{env}{content}中的{timestamps}已清除完毕...\n"
self.send_response(200)
self.send_header('Content-type', 'application/json; charset=utf-8')
self.end_headers()
self.wfile.write(response_content.encode('utf-8'))
else:
self.send_error(404, "Delete Artifact has something wrong...")
case _:
self.send_error(404, "Not Found")

def run(server_class=HTTPServer, handler_class=RequestHandler, port=81):
doHarbor = DoHarbor()
doJenkins = DoJenkins()
server_address = ('', port)
httpd = server_class(server_address, handler_class)
setattr(handler_class, "doHarbor", doHarbor)
setattr(handler_class, "doJenkins", doJenkins)
try:
httpd.serve_forever()
except KeyboardInterrupt:
print('Good Bye Everyone! Good everning Everyone!')
sys.exit(0)

if __name__ == "__main__":
# noinspection PyTypeChecker
run(port=81)

  • doHarbor(harbor api)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
import os
import time
import warnings
from datetime import datetime
from http.client import responses

import harbor_client
import yaml
from harbor_client.rest import ApiException


class DoHarbor(object):

def __init__(self):
self.dirname = os.path.dirname(os.path.abspath(__file__))
self.configuration = harbor_client.Configuration()
self.projectTemplate = {}
self.templateProject = ""

def loadConfig(self):
with open(os.path.join(self.dirname, "config", "HarborConfig.yaml"), encoding="UTF-8") as file:
data = yaml.safe_load(file)
self.configuration.host = data["host"]
self.configuration.username = data["username"]
self.configuration.password = data["password"]
self.projectTemplate = data["project"]
if self.projectTemplate["public"] == 'false':
self.projectTemplate["public"] = False
elif self.projectTemplate["public"] == 'true':
self.projectTemplate["public"] = True
self.projectTemplate["metadata"]["retention_id"] = None
self.templateProject = data["templateProject"]

def getHealth(self):
api_instance = harbor_client.HealthApi(harbor_client.ApiClient(self.configuration))
try:
result = api_instance.get_health(async_req=True).get()
anyParts = {k.name: k.status for k in result.components}
anyParts["overall"] = result.status
return anyParts
except ApiException as e:
return f"Error Reason: {e}"

# 项目相关
def getProjects(self):
api_instance = harbor_client.ProjectApi(harbor_client.ApiClient(self.configuration))
try:
return api_instance.list_projects(async_req=True).get()
except ApiException as e:
return f"Error Reason: {e}"

def getProjectIdOrName(self, project_name_or_id):
'''
:param project_name_or_id: 项目的id或名称
:return: 项目的基本内容,可用于创建项目
'''
api_instance = harbor_client.ProjectApi(harbor_client.ApiClient(self.configuration))
try:
return api_instance.get_project(project_name_or_id, async_req=True).get().to_dict()
except ApiException:
return "-"

def cheackProjects(self, project_name):
'''
:param project_name: 项目名
:return: NoneType if exists else "-"
'''
api_instance = harbor_client.ProjectApi(harbor_client.ApiClient(self.configuration))
try:
return api_instance.head_project(project_name, async_req=True).get()
except ApiException:
return "-"

def createProject(self, project):
# if self.cheackProjects(project["project_name"]) != "-":
# return None
api_instance = harbor_client.ProjectApi(harbor_client.ApiClient(self.configuration))
try:
return api_instance.create_project(project, async_req=True).get()
except ApiException:
return "-"

def listProjectMetadata(self, project_name_or_id):
api_instance = harbor_client.ProjectMetadataApi(harbor_client.ApiClient(self.configuration))
try:
return api_instance.list_project_metadatas(project_name_or_id, async_req=True).get()
except ApiException:
return "-"

# repository相关
def listRepository(self, project_name):
api_instance = harbor_client.RepositoryApi(harbor_client.ApiClient(self.configuration))
try:
return api_instance.list_repositories(project_name, async_req=True).get()
except ApiException:
return []

def updateRepository(self, project_name, repository):
api_instance = harbor_client.RepositoryApi(harbor_client.ApiClient(self.configuration))
try:
return api_instance.update_repository(project_name,repository["name"], repository, async_req=True).get()
except ApiException as e:
return f"Error Reason: {e}"

# artifact相关
def listArtifacts(self, project_name, repository_name):
api_instance = harbor_client.ArtifactApi(harbor_client.ApiClient(self.configuration))
try:
return api_instance.list_artifacts(project_name, repository_name, async_req=True).get()
except ApiException:
return []

def deleteArtifact(self, project_name, repository_name, tag_name):
api_instance = harbor_client.ArtifactApi(harbor_client.ApiClient(self.configuration))
try:
return api_instance.delete_artifact(project_name, repository_name, tag_name, async_req=True).get()
except ApiException:
return "-"

# tag保留机制:Retention
def getRetention(self, retention_id):
api_instance = harbor_client.RetentionApi(harbor_client.ApiClient(self.configuration))
try:
return api_instance.get_retention(retention_id, async_req=True).get()
except ApiException:
return "-"

def getRetentionMetadata(self):
warnings.warn("此方法用处不大,请忽视", DeprecationWarning)
api_instance = harbor_client.RetentionApi(harbor_client.ApiClient(self.configuration))
try:
return api_instance.get_rentenition_metadata(async_req=True).get()
except ApiException:
return "-"

def createRetention(self, retention):
api_instance = harbor_client.RetentionApi(harbor_client.ApiClient(self.configuration))
try:
return api_instance.create_retention(retention, async_req=True).get()
except ApiException as e:
return f"Error Reason: {e}"

# 机器人配置:robot,但此机器人是project级别
def getRobotsInProjectIdOrName(self, project_name_or_id):
api_instance = harbor_client.Robotv1Api(harbor_client.ApiClient(self.configuration))
try:
return api_instance.list_robot_v1(project_name_or_id, async_req=True).get()
except ApiException:
return []

def getRobotsInProjectIdOrNameAndRobotId(self, project_name_or_id, robot_id):
api_instance = harbor_client.Robotv1Api(harbor_client.ApiClient(self.configuration))
try:
return api_instance.get_robot_by_idv1(project_name_or_id, robot_id, async_req=True).get()
except ApiException:
return "-"

def createRobotInProjectIdOrName(self, project_name_or_id, robot):
api_instance = harbor_client.Robotv1Api(harbor_client.ApiClient(self.configuration))
try:
return api_instance.create_robot_v1(project_name_or_id, robot, async_req=True).get()
except ApiException:
return "-"

def updateRobotInProjectIdOrNameAndRobotId(self, project_name_or_id, robot):
warnings.warn("此方法无法真实修改机器人的过期时间,请忽视", DeprecationWarning)
api_instance = harbor_client.Robotv1Api(harbor_client.ApiClient(self.configuration))
try:
return api_instance.update_robot_v1(project_name_or_id, robot["id"], robot, async_req=True).get()
except ApiException:
return "-"

def updateRobot(self,robot):
# 神奇,创建的时候以项目级别,更新的时候与项目无关
api_instance = harbor_client.RobotApi(harbor_client.ApiClient(self.configuration))
try:
return api_instance.update_robot(robot["id"], robot, async_req=True).get()
except ApiException:
return "-"

def deleteRobotInProjectIdOrNameAndRobotId(self, project_name_or_id, robot_id):
api_instance = harbor_client.Robotv1Api(harbor_client.ApiClient(self.configuration))
try:
return api_instance.delete_robot_v1(project_name_or_id, robot_id, async_req=True).get()
except ApiException:
return "-"

def saveRobotMessage(self, robot_id, robot_name, robot_secret):
with open(os.path.join(self.dirname,"secrets",robot_name+".log"),"w+",encoding="utf-8") as file:
file.write(f"robotId:{robot_id}\n")
file.write(f"robotName:{robot_name}\n")
file.write(f"robotSecret:{robot_secret}\n")

  • doJenkins(jenkins api)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import os
import sys
from jenkinsapi.jenkins import Jenkins
from jenkinsapi.credential import UsernamePasswordCredential, SSHKeyCredential
import yaml

class DoJenkins(object):

def __init__(self):
self.dirname = os.path.dirname(os.path.abspath(__file__))
self.server = ""

def loadConfig(self):
with open(os.path.join(self.dirname, "config", "JenkinsConfig.yaml"), encoding="UTF-8") as file:
data = yaml.safe_load(file)
self.server = Jenkins(data[data["choice_server"]]["host"], username=data[data["choice_server"]]["username"], password=data[data["choice_server"]]["password"])

def listCredentials(self):
return self.server.credentials.keys()

def checkCredentials(self,project_name):
checkList = self.listCredentials()
if project_name in checkList:
return True
else:
return False

def createCredential(self, username, password, description):
creds = self.server.credentials
cred_dict = {
"userName": username,
"password": password,
"description": description,
"credential_id": description,
}
creds[description] = UsernamePasswordCredential(cred_dict)
del creds