kyutil 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. kyutil-0.2.1/PKG-INFO +51 -0
  2. kyutil-0.2.1/README.md +9 -0
  3. kyutil-0.2.1/kyutil/FTPUtils.py +343 -0
  4. kyutil-0.2.1/kyutil/__init__.py +1 -0
  5. kyutil-0.2.1/kyutil/ansible.py +74 -0
  6. kyutil-0.2.1/kyutil/base.py +356 -0
  7. kyutil-0.2.1/kyutil/base64_util.py +7 -0
  8. kyutil-0.2.1/kyutil/build.py +293 -0
  9. kyutil-0.2.1/kyutil/build_base.py +1140 -0
  10. kyutil-0.2.1/kyutil/build_ns8.py +265 -0
  11. kyutil-0.2.1/kyutil/celery_util.py +58 -0
  12. kyutil-0.2.1/kyutil/clean_disk.py +134 -0
  13. kyutil-0.2.1/kyutil/cmd.py +0 -0
  14. kyutil-0.2.1/kyutil/comps_ks.py +446 -0
  15. kyutil-0.2.1/kyutil/config.py +56 -0
  16. kyutil-0.2.1/kyutil/constant.py +484 -0
  17. kyutil-0.2.1/kyutil/ctdy_koji.py +647 -0
  18. kyutil-0.2.1/kyutil/data.py +56 -0
  19. kyutil-0.2.1/kyutil/date_utils.py +15 -0
  20. kyutil-0.2.1/kyutil/decorators.py +72 -0
  21. kyutil-0.2.1/kyutil/download.py +173 -0
  22. kyutil-0.2.1/kyutil/enums.py +79 -0
  23. kyutil-0.2.1/kyutil/env.py +245 -0
  24. kyutil-0.2.1/kyutil/excel.py +503 -0
  25. kyutil-0.2.1/kyutil/exceptions.py +139 -0
  26. kyutil-0.2.1/kyutil/file.py +747 -0
  27. kyutil-0.2.1/kyutil/file_compare.py +359 -0
  28. kyutil-0.2.1/kyutil/git_utils.py +70 -0
  29. kyutil-0.2.1/kyutil/host.py +129 -0
  30. kyutil-0.2.1/kyutil/hostinit.py +81 -0
  31. kyutil-0.2.1/kyutil/http_util.py +153 -0
  32. kyutil-0.2.1/kyutil/inject_ks.py +78 -0
  33. kyutil-0.2.1/kyutil/iso_check.py +779 -0
  34. kyutil-0.2.1/kyutil/iso_utils.py +681 -0
  35. kyutil-0.2.1/kyutil/koji_tools.py +60 -0
  36. kyutil-0.2.1/kyutil/kyemail.py +148 -0
  37. kyutil-0.2.1/kyutil/kyexcel.py +314 -0
  38. kyutil-0.2.1/kyutil/lanxin.py +208 -0
  39. kyutil-0.2.1/kyutil/log.py +125 -0
  40. kyutil-0.2.1/kyutil/log_annotation.py +189 -0
  41. kyutil-0.2.1/kyutil/log_show_tools.py +80 -0
  42. kyutil-0.2.1/kyutil/mash.py +239 -0
  43. kyutil-0.2.1/kyutil/mock.py +74 -0
  44. kyutil-0.2.1/kyutil/model/__init__.py +13 -0
  45. kyutil-0.2.1/kyutil/model/vo/__init__.py +13 -0
  46. kyutil-0.2.1/kyutil/model/vo/log_vo.py +65 -0
  47. kyutil-0.2.1/kyutil/mq.py +23 -0
  48. kyutil-0.2.1/kyutil/paths.py +93 -0
  49. kyutil-0.2.1/kyutil/pungi_util.py +254 -0
  50. kyutil-0.2.1/kyutil/reg_exp.py +25 -0
  51. kyutil-0.2.1/kyutil/release_bugfix.py +95 -0
  52. kyutil-0.2.1/kyutil/release_dependency.py +169 -0
  53. kyutil-0.2.1/kyutil/repo.py +115 -0
  54. kyutil-0.2.1/kyutil/repo_compare.py +52 -0
  55. kyutil-0.2.1/kyutil/repo_utils.py +161 -0
  56. kyutil-0.2.1/kyutil/repomd.py +204 -0
  57. kyutil-0.2.1/kyutil/response_util.py +269 -0
  58. kyutil-0.2.1/kyutil/rpm_compare.py +276 -0
  59. kyutil-0.2.1/kyutil/rpm_operation.py +182 -0
  60. kyutil-0.2.1/kyutil/rpms.py +194 -0
  61. kyutil-0.2.1/kyutil/schedule.py +15 -0
  62. kyutil-0.2.1/kyutil/sheeter.py +93 -0
  63. kyutil-0.2.1/kyutil/shell.py +272 -0
  64. kyutil-0.2.1/kyutil/signature.py +148 -0
  65. kyutil-0.2.1/kyutil/source_pkg.py +227 -0
  66. kyutil-0.2.1/kyutil/sso_login.py +88 -0
  67. kyutil-0.2.1/kyutil/t.py +0 -0
  68. kyutil-0.2.1/kyutil/thread.py +16 -0
  69. kyutil-0.2.1/kyutil/url.py +56 -0
  70. kyutil-0.2.1/kyutil/util_repo_info.py +480 -0
  71. kyutil-0.2.1/kyutil/util_rpm_info.py +1044 -0
  72. kyutil-0.2.1/kyutil.egg-info/PKG-INFO +51 -0
  73. kyutil-0.2.1/kyutil.egg-info/SOURCES.txt +76 -0
  74. kyutil-0.2.1/kyutil.egg-info/dependency_links.txt +1 -0
  75. kyutil-0.2.1/kyutil.egg-info/requires.txt +35 -0
  76. kyutil-0.2.1/kyutil.egg-info/top_level.txt +1 -0
  77. kyutil-0.2.1/pyproject.toml +43 -0
  78. kyutil-0.2.1/setup.cfg +4 -0
kyutil-0.2.1/PKG-INFO ADDED
@@ -0,0 +1,51 @@
1
+ Metadata-Version: 2.4
2
+ Name: kyutil
3
+ Version: 0.2.1
4
+ Summary: Python utils for kylin python application
5
+ Requires-Python: >=3.7
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: apscheduler>=3.10.4
8
+ Requires-Dist: beautifulsoup4>=4.13.5
9
+ Requires-Dist: celery>=5.2.7
10
+ Requires-Dist: configparser>=5.3.0
11
+ Requires-Dist: cryptography>=45.0.7
12
+ Requires-Dist: defusedxml>=0.7.1
13
+ Requires-Dist: dotenv>=0.9.9
14
+ Requires-Dist: fastapi>=0.103.2
15
+ Requires-Dist: gitpython>=3.1.45
16
+ Requires-Dist: kobo>=0.40.0
17
+ Requires-Dist: koji>=1.35.3
18
+ Requires-Dist: logzero>=1.7.0
19
+ Requires-Dist: lxml>=5.4.0
20
+ Requires-Dist: msgpack>=1.0.5
21
+ Requires-Dist: networkx>=2.6.3
22
+ Requires-Dist: numpy>=1.21.6
23
+ Requires-Dist: openpyxl>=3.1.3
24
+ Requires-Dist: packaging>=24.0
25
+ Requires-Dist: pandas>=1.1.5
26
+ Requires-Dist: paramiko>=3.5.1
27
+ Requires-Dist: pika>=1.3.2
28
+ Requires-Dist: productmd>=1.48
29
+ Requires-Dist: pydantic>=2.5.3
30
+ Requires-Dist: pydot>=2.0.0
31
+ Requires-Dist: pytest>=7.4.4
32
+ Requires-Dist: python-jenkins>=1.8.3
33
+ Requires-Dist: pyyaml>=6.0.1
34
+ Requires-Dist: redis>=5.0.8
35
+ Requires-Dist: requests>=2.31.0
36
+ Requires-Dist: retry>=0.9.2
37
+ Requires-Dist: six>=1.17.0
38
+ Requires-Dist: sqlalchemy>=2.0.43
39
+ Requires-Dist: starlette>=0.27.0
40
+ Requires-Dist: urllib3>=2.0.7
41
+ Requires-Dist: wget>=3.2
42
+
43
+ # kyutil
44
+ 麒麟python工具库
45
+
46
+ Changelog:
47
+ ### 0.1.12
48
+ - BUGFIX: 修复在mock环境内找不到celery.log的BUG
49
+ Changelog:
50
+ ### 0.1.0
51
+ - initial release
kyutil-0.2.1/README.md ADDED
@@ -0,0 +1,9 @@
1
+ # kyutil
2
+ 麒麟python工具库
3
+
4
+ Changelog:
5
+ ### 0.1.12
6
+ - BUGFIX: 修复在mock环境内找不到celery.log的BUG
7
+ Changelog:
8
+ ### 0.1.0
9
+ - initial release
@@ -0,0 +1,343 @@
1
+ # -*- coding: UTF-8 -*-
2
+ """FTPUtils.py"""
3
+ import ftplib
4
+ import os
5
+ import ssl
6
+ import traceback
7
+
8
+ from celery import states
9
+ from logzero import logger
10
+
11
+
12
+ class ReusedSslSocket(ssl.SSLSocket):
13
+ def unwrap(self):
14
+ pass
15
+
16
+
17
+ # MyFTP_TLS is derived to support TLS_RESUME(filezilla server)
18
+ class MyFtpTLS(ftplib.FTP_TLS):
19
+ """Explicit FTPS, with shared TLS session"""
20
+
21
+ def ntransfercmd(self, cmd, rest=None):
22
+ conn, size = ftplib.FTP.ntransfercmd(self, cmd, rest)
23
+ if self._prot_p:
24
+ conn = self.context.wrap_socket(
25
+ conn,
26
+ server_hostname=self.host,
27
+ session=self.sock.session)
28
+
29
+ conn.__class__ = ReusedSslSocket
30
+
31
+ return conn, size
32
+
33
+
34
+ MSG_FTP_CONNECT_SUCCESS = "FTP链接成功!"
35
+ MSG_FTP_CONNECT_FAILED = "FTP链接失败!"
36
+ MSG_FTP_LOGIN_SUCCESS = "FTP登录成功!"
37
+ MSG_FTP_LOGIN_FAILED = "FTP登录失败!"
38
+
39
+ STOR_CMD = 'STOR '
40
+
41
+
42
+ class FTP(object):
43
+ """FTPUtils(object)"""
44
+ # 上传过程必需参数列表
45
+
46
+ celery_task_field = [
47
+ 'ftpaddress', # ftp连接地址
48
+ 'ftpport', # ftp连接端口
49
+ 'ftpuser', # ftp连接用户
50
+ 'ftppassword', # ftp连接密码
51
+ 'upload_path', # ftp上传远端路径
52
+ 'isoname', # 上传的本地iso路径
53
+ ]
54
+
55
+ # celery参数
56
+ process_rate_status = 0 # 当前处理的进度,取值从0-100
57
+
58
+ def __init__(self, update_status_func, cfg, task_id, logger=logger):
59
+ """
60
+ :param update_status_func:
61
+ :param cfg:
62
+ cfg = {
63
+ 'ftpaddress': "server.kylinos.cn",
64
+ 'ftpport': "21",
65
+ 'ftpuser': "user_name",
66
+ 'ftppassword': "***",
67
+ 'upload_path': "/vsftpd/os/ISO/HOSTOS/x86_64/2022/06/test",
68
+ 'isoname': "/v10-sp1-0518-kx-x86_64-b3532/iso/Kylin-Server-10-SP1-kx.iso", # 上传的本地iso路径
69
+ }
70
+ :param task_id:
71
+ :param logger:
72
+ """
73
+ self.logger = logger
74
+ # celery状态更新函数以及taskid
75
+ self.call_back_task_process = update_status_func
76
+
77
+ # 本地ftp目录 默认上传标志关闭
78
+ self.process_rate_status = 10
79
+ self.celery_task_param = cfg
80
+ self.task_id = task_id
81
+ self.ftp_instance = self.ftp_connect()
82
+ self.log_and_send_task_status("ftp登录成功")
83
+
84
+ # log信息输出&日志信息回传&进度设置!
85
+ def log_and_send_task_status(self, msg):
86
+ self.logger.info(f"{msg},【{self.task_id[:4]}】 目前进度{self.process_rate_status}%")
87
+ # 得想办法把logger.info的输出放到msg里面,这样日志信息会携带时间戳等信息
88
+ if self.call_back_task_process is not None:
89
+ if self.process_rate_status == 0:
90
+ self.call_back_task_process(
91
+ state=states.FAILURE,
92
+ meta={'current': 0, 'total': 100, 'status': msg, "exc_type": "RuntimeException", "exc_message": msg}
93
+ )
94
+ elif self.process_rate_status == 100:
95
+ self.call_back_task_process(
96
+ state=states.SUCCESS,
97
+ meta={'current': 100, 'total': 100, 'status': msg, "exc_type": "RuntimeException", "exc_message": msg}
98
+ )
99
+ else:
100
+ self.call_back_task_process(
101
+ state=states.STARTED,
102
+ meta={'current': self.process_rate_status, 'total': 100, 'status': msg, "exc_type": "RuntimeException", "exc_message": msg}
103
+ )
104
+
105
+ def ftp_connect(self):
106
+ ftp_address = self.celery_task_param.get('ftpaddress')
107
+ ftp_port = int(self.celery_task_param.get('ftpport'))
108
+ ftp = MyFtpTLS(host=ftp_address, timeout=15)
109
+ ftp.auth()
110
+ ftp.port = ftp_port
111
+ ftp.prot_p()
112
+ ftp.set_pasv(1)
113
+ ftp.encoding = 'utf-8'
114
+ ftp_user = self.celery_task_param.get('ftpuser')
115
+ ftp_password = self.celery_task_param.get('ftppassword')
116
+
117
+ try:
118
+ self.process_rate_status = 20
119
+ ftp.connect(ftp_address, ftp_port)
120
+ self.log_and_send_task_status(MSG_FTP_CONNECT_SUCCESS)
121
+ except Exception:
122
+ self.log_and_send_task_status(MSG_FTP_CONNECT_FAILED)
123
+ raise ConnectionError(MSG_FTP_CONNECT_FAILED)
124
+ try:
125
+ self.process_rate_status = 40
126
+ ftp.login(ftp_user, ftp_password) # user/passwd
127
+ ftp.prot_p()
128
+ self.log_and_send_task_status(MSG_FTP_LOGIN_SUCCESS)
129
+ except Exception:
130
+ traceback.print_exc()
131
+ self.log_and_send_task_status(MSG_FTP_LOGIN_FAILED)
132
+ raise ConnectionError(MSG_FTP_LOGIN_FAILED)
133
+ return ftp
134
+
135
+ def is_same_size(self, local_file, remote_file):
136
+ """
137
+ 判断远程文件和本地文件大小是否一致
138
+
139
+ Args:
140
+ local_file: 本地文件
141
+ remote_file: 远程文件
142
+
143
+ Returns:
144
+
145
+ """
146
+ try:
147
+ remote_file_size = self.ftp_instance.size(remote_file)
148
+ except Exception as err:
149
+ self.logger.debug("get remote file_size failed, Err:%s" % err)
150
+ remote_file_size = -1
151
+
152
+ try:
153
+ local_file_size = os.path.getsize(local_file)
154
+ except Exception as err:
155
+ self.logger.debug("get local file_size failed, Err:%s" % err)
156
+ local_file_size = -1
157
+
158
+ result = True if (remote_file_size == local_file_size) else False
159
+
160
+ return result, remote_file_size, local_file_size
161
+
162
+ def upload_file(self, local_file, remote_file, ftp):
163
+ # 本地是否有此文件
164
+ if not os.path.exists(local_file):
165
+ self.logger.debug('no such file or directory %s.' % local_file)
166
+ return False
167
+
168
+ result, remote_file_size, local_file_size = self.is_same_size(local_file, remote_file)
169
+ if not result:
170
+ self.logger.debug('remote_file %s is not exist, now trying to upload...' % remote_file)
171
+ buff_size = 8192
172
+ try:
173
+ with open(local_file, 'rb') as file_handler:
174
+ if ftp.storbinary(STOR_CMD + remote_file, file_handler, buff_size):
175
+ result, remote_file_size, local_file_size = self.is_same_size(local_file, remote_file)
176
+ except Exception as err:
177
+ self.logger.debug(
178
+ 'some error happened in storbinary file :%s. Err:%s' % (local_file, err))
179
+ result = False
180
+
181
+ self.logger.debug('Upload 【%s】 %s , remote_file_size = %d, local_file_size = %d.' \
182
+ % (
183
+ remote_file, 'success' if (result is True) else 'failed', remote_file_size,
184
+ local_file_size))
185
+ self.logger.info('Upload 【%s】 %s , remote_file_size = %d, local_file_size = %d.' \
186
+ % (
187
+ remote_file, 'success' if (result is True) else 'failed', remote_file_size,
188
+ local_file_size))
189
+
190
+ # 01-ftp-connect连接及登录
191
+
192
+ # 02-创建远端文件目录
193
+ def create_remote_dir(self, upload_path):
194
+ try:
195
+ self.ftp_instance.cwd(upload_path)
196
+ except Exception as e:
197
+ self.log_and_send_task_status(f"ftp cwd异常:{e}")
198
+ self.ftp_instance.cwd('/')
199
+ # 分割目录名
200
+ base_dir, part_path = self.ftp_instance.pwd(), upload_path.split('/')
201
+ for p in part_path[1:]:
202
+ # 拼接子目录
203
+ base_dir = base_dir + p + '/'
204
+ try:
205
+ # 尝试切换子目录
206
+ self.ftp_instance.cwd(base_dir)
207
+ except Exception as e:
208
+ self.log_and_send_task_status(f"ftp cwd异常:{e}")
209
+ # 不存在创建当前子目录
210
+ self.ftp_instance.mkd(base_dir)
211
+ # 确保最后路径修改
212
+ self.ftp_instance.cwd(upload_path)
213
+ return True
214
+
215
+ # 03-上传本地指定文件
216
+ def ftp_upload_file(self, root_path_iso_path="/opt/integration_iso_files/") -> str:
217
+ iso_file = self.celery_task_param.get('isoname')
218
+ iso_rename = self.celery_task_param.get('filename_rename')
219
+
220
+ buffsize = 1024
221
+ self.ftp_instance.cwd(self.ftp_instance.pwd())
222
+
223
+ with open(root_path_iso_path + iso_file, 'rb') as f:
224
+ self.log_and_send_task_status('正在上传' + str(f))
225
+ if iso_rename is not None:
226
+ self.ftp_instance.storbinary(STOR_CMD + iso_rename, f, buffsize)
227
+ remote_file = str(self.ftp_instance.pwd()) + '/' + iso_rename
228
+ else:
229
+ self.ftp_instance.storbinary(STOR_CMD + iso_file.split('/')[-1], f, buffsize)
230
+ remote_file = str(self.ftp_instance.pwd()) + '/' + iso_file.split('/')[-1]
231
+ return remote_file
232
+
233
+ def instance_cwd(self, remote_path):
234
+ try:
235
+ self.ftp_instance.cwd(remote_path) # 切换工作路径
236
+ except Exception as e:
237
+ self.logger.error('Except INFO:', e)
238
+ base_dir, part_path = self.ftp_instance.pwd(), remote_path.split('/')
239
+ for sub_path in part_path:
240
+ # 针对类似 '/home/billing/scripts/zhf/send' 和 'home/billing/scripts/zhf/send' 两种格式的目录
241
+ # 如果第一个分解后的元素是''这种空字符,说明根目录是从/开始,如果最后一个是''这种空字符,说明目录是以/结束
242
+ # 例如 /home/billing/scripts/zhf/send/ 分解后得到 ['', 'home', 'billing', 'scripts', 'zhf', 'send', '']
243
+ # 首位和尾都不是有效名称
244
+ if '' == sub_path:
245
+ continue
246
+ base_dir = str(os.path.join(base_dir, sub_path)) # base_dir + subpath + '/' # 拼接子目录
247
+ try:
248
+ self.ftp_instance.cwd(base_dir) # 切换到子目录, 不存在则异常
249
+ except Exception as e:
250
+ self.logger.error('Except INFO:', e)
251
+ self.logger.error('remote not exist directory %s , create it.' % base_dir)
252
+ self.ftp_instance.mkd(base_dir) # 不存在创建当前子目录 直到创建所有
253
+ continue
254
+
255
+ # 03-上传目录
256
+ def upload_file_tree(self, local_path, remote_path, recursively):
257
+ # 创建服务器目录 如果服务器目录不存在 就从当前目录创建目标外层目录
258
+ # 打开该远程目录
259
+ self.instance_cwd(remote_path)
260
+
261
+ # 本地目录切换
262
+ try:
263
+ # 远端目录通过ftp对象已经切换到指定目录或创建的指定目录
264
+ file_list = os.listdir(local_path)
265
+ for file_name in file_list:
266
+ if os.path.isdir(os.path.join(local_path, file_name)):
267
+ self.logger.debug('%s is a directory...' % file_name)
268
+ if recursively: # 递归目录上传
269
+ # 创建相关的子目录 创建不成功则目录已存在
270
+ try:
271
+ cwd = self.ftp_instance.pwd()
272
+ self.ftp_instance.cwd(file_name) # 如果cwd成功 则表示该目录存在 退出到上一级
273
+ self.ftp_instance.cwd(cwd)
274
+ except Exception as e:
275
+ self.logger.error(
276
+ 'check remote directory %s not eixst, now trying to create it! Except INFO:%s.' % (
277
+ file_name, e))
278
+ self.ftp_instance.mkd(file_name)
279
+
280
+ self.logger.debug('trying to upload directory %s --> %s ...' % (file_name, remote_path))
281
+ p_local_path = os.path.join(local_path, file_name)
282
+ p_remote_path = os.path.join(self.ftp_instance.pwd(), file_name)
283
+ self.upload_file_tree(p_local_path, p_remote_path, recursively)
284
+ # 对于递归 ftp 每次传输完成后需要切换目录到上一级
285
+ self.ftp_instance.cwd("..")
286
+ else:
287
+ self.logger.debug(
288
+ 'translate mode is UnRecursively, %s is a directory, continue ...' % file_name)
289
+ continue
290
+ else:
291
+ # 是文件 直接上传
292
+ local_file = os.path.join(local_path, file_name)
293
+ remote_file = os.path.join(remote_path, file_name)
294
+ self.upload_file(local_file, remote_file, self.ftp_instance)
295
+ except Exception as e:
296
+ traceback.format_exc()
297
+ self.logger.debug(f'FTP 无法上传目录。 错误消息:{e}')
298
+
299
+ # 04-核实iso名称
300
+ def ftp_check_iso(self):
301
+ upload_path = self.celery_task_param.get('upload_path')
302
+ iso_file = self.celery_task_param.get('isoname')
303
+ iso_rename = self.celery_task_param.get('filename_rename')
304
+
305
+ flist = self.ftp_instance.nlst(upload_path)
306
+ for f in flist:
307
+ if f.endswith('.iso') and f.split('/')[-1] == iso_file.split('/')[-1] or (
308
+ f.endswith('.iso') and f.split('/')[-1] == iso_rename):
309
+ self.ftp_instance.quit()
310
+ return f
311
+ return None
312
+
313
+ # 外部调用ftp主函数入口
314
+ def upload_iso(self, root_path_iso_path="/opt/integration_iso_files/") -> str:
315
+ try:
316
+ self.process_rate_status = 50
317
+ self.create_remote_dir(self.celery_task_param.get('upload_path'))
318
+ self.log_and_send_task_status(
319
+ f'ftp上传路径:{self.celery_task_param.get("ftpaddress")}:{self.ftp_instance.pwd()}')
320
+
321
+ self.process_rate_status = 60
322
+
323
+ # 是否为空
324
+ if self.ftp_instance.nlst():
325
+ raise RuntimeError("目录不为空,无法上传")
326
+
327
+ self.log_and_send_task_status("ftp开始上传本地iso文件")
328
+ local_dir = root_path_iso_path + self.celery_task_param.get("isoname")[
329
+ :self.celery_task_param.get("isoname").rfind("/")]
330
+ self.upload_file_tree(local_dir, self.celery_task_param.get('upload_path'), True)
331
+
332
+ self.process_rate_status = 80
333
+ self.log_and_send_task_status("校验ftp远端iso文件")
334
+ if not self.ftp_check_iso():
335
+ self.log_and_send_task_status("ftp上传iso失败")
336
+
337
+ self.process_rate_status = 100
338
+ self.log_and_send_task_status("ftp上传iso完成")
339
+ return self.celery_task_param.get('upload_path')
340
+ except Exception as e:
341
+ self.process_rate_status = 0
342
+ self.log_and_send_task_status(f"ftp上传失败!{e}")
343
+ return ""
@@ -0,0 +1 @@
1
+ # -*- coding: UTF-8 -*-
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: UTF-8 -*-
3
+ """
4
+ @Project :kyutil
5
+ @File :ansible.py
6
+ @IDE :PyCharm
7
+ @Author :xuyong@kylinos.cn
8
+ @Date :2025/5/22 下午4:39
9
+ @Desc :说明:
10
+ """
11
+ import base64
12
+ import os
13
+ import random
14
+ import sys
15
+ from shutil import copyfile
16
+
17
+ import ansible_runner
18
+ from logzero import logger as log
19
+
20
+
21
+ def gen_random_base_64_str() -> bytes:
22
+ flag = "flag{**flag**}".encode("utf-8")
23
+ b64list = [lambda x: base64.b16encode(x), lambda x: base64.b32encode(x), lambda x: base64.b64encode(x)]
24
+ for _ in range(10):
25
+ choice = random.choice([0, 1, 2])
26
+ flag = b64list[choice](flag)
27
+ encoded = {
28
+ '16': lambda x: base64.b16encode(x),
29
+ '32': lambda x: base64.b32encode(x),
30
+ '64': lambda x: base64.b64encode(x)
31
+ }
32
+ choice = random.choice(['16', '32', '64'])
33
+ flag = encoded[choice](flag)
34
+ return flag[7:32]
35
+
36
+
37
+ def execute_playbook(operation_type, host_ip, logger=log) -> bool:
38
+ bp_prefix = "/opt/ctdy/build_iso_server/src/app/bp/"
39
+ b64random = bytes.decode(gen_random_base_64_str())
40
+ host_file = f"{bp_prefix}ansible/hosts.{str(b64random)}"
41
+ random_file = f"{bp_prefix}ansible/{operation_type}.yaml." + str(b64random)
42
+
43
+ copyfile(f"{bp_prefix}ansible/{operation_type}.yaml", random_file)
44
+ copyfile(bp_prefix + "ansible/hosts", host_file)
45
+ ssh_pass_sk_raw = "RmExYzBuQEt5bGluMTAyMzYxCg=="
46
+ ssh_pass_sk = base64.b64decode(bytes(ssh_pass_sk_raw, 'utf-8')).decode()
47
+ with open(host_file, encoding="utf-8", mode="a") as f:
48
+ f.write("\n" + host_ip + " ansible_ssh_user=root ansible_ssh_pass=\"" + ssh_pass_sk.strip() + "\"")
49
+ out, err, rc = ansible_runner.run_command(
50
+ executable_cmd='ansible-playbook',
51
+ cmdline_args=[random_file, '-i', host_file, '--extra-vars', "ansible_become_pass=" + ssh_pass_sk],
52
+ input_fd=sys.stdin,
53
+ output_fd=sys.stdout,
54
+ error_fd=sys.stderr
55
+ )
56
+ os.remove(random_file)
57
+ os.remove(host_file)
58
+ if rc == 0:
59
+ logger.debug(f"Playbook执行成功:{out}. RC:{rc} ERR:{err}")
60
+ return True
61
+ else:
62
+ logger.error(f"Playbook执行失败:{err}. RC:{rc}")
63
+ return False
64
+
65
+
66
+ def hosts_restart(host_list, logger=log):
67
+ oks, errs = [], []
68
+ for host in host_list:
69
+ ok = execute_playbook("restart", host.hostip)
70
+ if ok:
71
+ oks.append(host.hostip)
72
+ else:
73
+ errs.append(host.hostip)
74
+ return oks, errs