openubmc-bingo 0.5.240__py3-none-any.whl

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.

Potentially problematic release.


This version of openubmc-bingo might be problematic. Click here for more details.

Files changed (242) hide show
  1. bmcgo/__init__.py +12 -0
  2. bmcgo/bmcgo.py +22 -0
  3. bmcgo/bmcgo_config.py +176 -0
  4. bmcgo/cli/__init__.py +10 -0
  5. bmcgo/cli/cli.py +584 -0
  6. bmcgo/codegen/__init__.py +14 -0
  7. bmcgo/codegen/c/__init__.py +9 -0
  8. bmcgo/codegen/c/annotation.py +52 -0
  9. bmcgo/codegen/c/argument.py +42 -0
  10. bmcgo/codegen/c/codegen.py +153 -0
  11. bmcgo/codegen/c/comment.py +22 -0
  12. bmcgo/codegen/c/ctype_defination.py +353 -0
  13. bmcgo/codegen/c/helper.py +87 -0
  14. bmcgo/codegen/c/interface.py +63 -0
  15. bmcgo/codegen/c/method.py +82 -0
  16. bmcgo/codegen/c/property.py +180 -0
  17. bmcgo/codegen/c/renderer.py +21 -0
  18. bmcgo/codegen/c/signal.py +64 -0
  19. bmcgo/codegen/c/template/client.c.mako +145 -0
  20. bmcgo/codegen/c/template/client.h.mako +36 -0
  21. bmcgo/codegen/c/template/interface.c.mako +0 -0
  22. bmcgo/codegen/c/template/interface.introspect.xml.mako +99 -0
  23. bmcgo/codegen/c/template/micro_component.c.mako +32 -0
  24. bmcgo/codegen/c/template/public.c.mako +228 -0
  25. bmcgo/codegen/c/template/public.h.mako +128 -0
  26. bmcgo/codegen/c/template/server.c.mako +104 -0
  27. bmcgo/codegen/c/template/server.h.mako +36 -0
  28. bmcgo/codegen/lua/.lua-format +7 -0
  29. bmcgo/codegen/lua/Makefile +101 -0
  30. bmcgo/codegen/lua/__init__.py +9 -0
  31. bmcgo/codegen/lua/codegen.py +171 -0
  32. bmcgo/codegen/lua/proto/Makefile +87 -0
  33. bmcgo/codegen/lua/proto/ipmi_types.proto +17 -0
  34. bmcgo/codegen/lua/proto/types.proto +52 -0
  35. bmcgo/codegen/lua/script/check_intfs.py +161 -0
  36. bmcgo/codegen/lua/script/dto/__init__.py +11 -0
  37. bmcgo/codegen/lua/script/dto/exception.py +53 -0
  38. bmcgo/codegen/lua/script/dto/kepler_abstract.py +47 -0
  39. bmcgo/codegen/lua/script/dto/options.py +33 -0
  40. bmcgo/codegen/lua/script/dto/print_simple.py +19 -0
  41. bmcgo/codegen/lua/script/dto/redfish_api.py +241 -0
  42. bmcgo/codegen/lua/script/dto/url_route.py +195 -0
  43. bmcgo/codegen/lua/script/gen_db_json.py +444 -0
  44. bmcgo/codegen/lua/script/gen_depends.py +89 -0
  45. bmcgo/codegen/lua/script/gen_entry.py +263 -0
  46. bmcgo/codegen/lua/script/gen_feature_json.py +156 -0
  47. bmcgo/codegen/lua/script/gen_historical_local_db_json.py +88 -0
  48. bmcgo/codegen/lua/script/gen_intf_json.py +261 -0
  49. bmcgo/codegen/lua/script/gen_intf_rpc_json.py +575 -0
  50. bmcgo/codegen/lua/script/gen_ipmi_json.py +485 -0
  51. bmcgo/codegen/lua/script/gen_mdb_json.py +117 -0
  52. bmcgo/codegen/lua/script/gen_rpc_msg_json.py +487 -0
  53. bmcgo/codegen/lua/script/gen_schema.py +302 -0
  54. bmcgo/codegen/lua/script/ipmi_types_pb2.py +135 -0
  55. bmcgo/codegen/lua/script/loader/__init__.py +11 -0
  56. bmcgo/codegen/lua/script/loader/file_utils.py +33 -0
  57. bmcgo/codegen/lua/script/loader/kepler_abstract_collect.py +79 -0
  58. bmcgo/codegen/lua/script/loader/kepler_abstract_loader.py +47 -0
  59. bmcgo/codegen/lua/script/loader/redfish_loader.py +127 -0
  60. bmcgo/codegen/lua/script/lua_format.py +62 -0
  61. bmcgo/codegen/lua/script/mds_util.py +385 -0
  62. bmcgo/codegen/lua/script/merge_model.py +330 -0
  63. bmcgo/codegen/lua/script/merge_proto_algo.py +85 -0
  64. bmcgo/codegen/lua/script/proto_loader.py +47 -0
  65. bmcgo/codegen/lua/script/proto_plugin.py +140 -0
  66. bmcgo/codegen/lua/script/redfish_source_tree.py +118 -0
  67. bmcgo/codegen/lua/script/render_utils/__init__.py +38 -0
  68. bmcgo/codegen/lua/script/render_utils/base.py +25 -0
  69. bmcgo/codegen/lua/script/render_utils/client_lua.py +98 -0
  70. bmcgo/codegen/lua/script/render_utils/controller_lua.py +71 -0
  71. bmcgo/codegen/lua/script/render_utils/db_lua.py +224 -0
  72. bmcgo/codegen/lua/script/render_utils/error_lua.py +185 -0
  73. bmcgo/codegen/lua/script/render_utils/factory.py +52 -0
  74. bmcgo/codegen/lua/script/render_utils/ipmi_lua.py +159 -0
  75. bmcgo/codegen/lua/script/render_utils/ipmi_message_lua.py +24 -0
  76. bmcgo/codegen/lua/script/render_utils/mdb_lua.py +177 -0
  77. bmcgo/codegen/lua/script/render_utils/mdb_register.py +215 -0
  78. bmcgo/codegen/lua/script/render_utils/message_lua.py +26 -0
  79. bmcgo/codegen/lua/script/render_utils/messages_lua.py +156 -0
  80. bmcgo/codegen/lua/script/render_utils/model_lua.py +485 -0
  81. bmcgo/codegen/lua/script/render_utils/old_model_lua.py +429 -0
  82. bmcgo/codegen/lua/script/render_utils/plugin_lua.py +38 -0
  83. bmcgo/codegen/lua/script/render_utils/redfish_proto.py +86 -0
  84. bmcgo/codegen/lua/script/render_utils/request_lua.py +76 -0
  85. bmcgo/codegen/lua/script/render_utils/service_lua.py +130 -0
  86. bmcgo/codegen/lua/script/render_utils/utils_message_lua.py +125 -0
  87. bmcgo/codegen/lua/script/render_utils/validate_lua.py +221 -0
  88. bmcgo/codegen/lua/script/sep_ipmi_message_cmds.py +217 -0
  89. bmcgo/codegen/lua/script/template.py +166 -0
  90. bmcgo/codegen/lua/script/types_pb2.py +516 -0
  91. bmcgo/codegen/lua/script/utils.py +663 -0
  92. bmcgo/codegen/lua/script/validate.py +80 -0
  93. bmcgo/codegen/lua/script/yaml_to_json.py +73 -0
  94. bmcgo/codegen/lua/templates/Makefile +114 -0
  95. bmcgo/codegen/lua/templates/apps/Makefile +261 -0
  96. bmcgo/codegen/lua/templates/apps/Makefile.mdb.mk +64 -0
  97. bmcgo/codegen/lua/templates/apps/app.lua.mako +19 -0
  98. bmcgo/codegen/lua/templates/apps/class.lua.mako +35 -0
  99. bmcgo/codegen/lua/templates/apps/client.lua.mako +429 -0
  100. bmcgo/codegen/lua/templates/apps/controller.lua.mako +276 -0
  101. bmcgo/codegen/lua/templates/apps/datas.lua.mako +8 -0
  102. bmcgo/codegen/lua/templates/apps/db.lua.mako +89 -0
  103. bmcgo/codegen/lua/templates/apps/entry.lua.mako +128 -0
  104. bmcgo/codegen/lua/templates/apps/feature.lua.mako +37 -0
  105. bmcgo/codegen/lua/templates/apps/generate_route.mako +25 -0
  106. bmcgo/codegen/lua/templates/apps/impl_feature.lua.mako +72 -0
  107. bmcgo/codegen/lua/templates/apps/ipmi.lua.mako +97 -0
  108. bmcgo/codegen/lua/templates/apps/ipmi_cmd.lua.mako +18 -0
  109. bmcgo/codegen/lua/templates/apps/ipmi_message.lua.mako +36 -0
  110. bmcgo/codegen/lua/templates/apps/local_db.lua.mako +263 -0
  111. bmcgo/codegen/lua/templates/apps/main.lua.mako +25 -0
  112. bmcgo/codegen/lua/templates/apps/mc.lua.mako +77 -0
  113. bmcgo/codegen/lua/templates/apps/mdb.lua.mako +45 -0
  114. bmcgo/codegen/lua/templates/apps/mdb_interface.lua.mako +73 -0
  115. bmcgo/codegen/lua/templates/apps/message.lua.mako +38 -0
  116. bmcgo/codegen/lua/templates/apps/model.lua.mako +239 -0
  117. bmcgo/codegen/lua/templates/apps/orm_classes.lua.mako +16 -0
  118. bmcgo/codegen/lua/templates/apps/plugin.lua.mako +8 -0
  119. bmcgo/codegen/lua/templates/apps/redfish.proto.mako +47 -0
  120. bmcgo/codegen/lua/templates/apps/service.lua.mako +440 -0
  121. bmcgo/codegen/lua/templates/apps/signal_listen.lua.mako +19 -0
  122. bmcgo/codegen/lua/templates/apps/utils/default_intf.lua.mako +41 -0
  123. bmcgo/codegen/lua/templates/apps/utils/enum.mako +10 -0
  124. bmcgo/codegen/lua/templates/apps/utils/imports.mako +13 -0
  125. bmcgo/codegen/lua/templates/apps/utils/mdb_intf.lua.mako +25 -0
  126. bmcgo/codegen/lua/templates/apps/utils/mdb_obj.lua.mako +23 -0
  127. bmcgo/codegen/lua/templates/apps/utils/message.mako +160 -0
  128. bmcgo/codegen/lua/templates/apps/utils/request.lua.mako +59 -0
  129. bmcgo/codegen/lua/templates/apps/utils/validate.mako +83 -0
  130. bmcgo/codegen/lua/templates/errors.lua.mako +36 -0
  131. bmcgo/codegen/lua/templates/messages.lua.mako +32 -0
  132. bmcgo/codegen/lua/templates/new_app/.clang-format.mako +170 -0
  133. bmcgo/codegen/lua/templates/new_app/.gitignore.mako +26 -0
  134. bmcgo/codegen/lua/templates/new_app/CHANGELOG.md.mako +0 -0
  135. bmcgo/codegen/lua/templates/new_app/CMakeLists.txt.mako +29 -0
  136. bmcgo/codegen/lua/templates/new_app/Makefile.mako +25 -0
  137. bmcgo/codegen/lua/templates/new_app/README.md.mako +0 -0
  138. bmcgo/codegen/lua/templates/new_app/conanfile.py.mako +7 -0
  139. bmcgo/codegen/lua/templates/new_app/config.cfg.mako +6 -0
  140. bmcgo/codegen/lua/templates/new_app/mds/model.json.mako +3 -0
  141. bmcgo/codegen/lua/templates/new_app/mds/service.json.mako +21 -0
  142. bmcgo/codegen/lua/templates/new_app/permissions.ini.mako +16 -0
  143. bmcgo/codegen/lua/templates/new_app/src/lualib/${project_name}_app.lua.mako +16 -0
  144. bmcgo/codegen/lua/templates/new_app/src/service/main.lua.mako +25 -0
  145. bmcgo/codegen/lua/templates/new_app/test/integration/test_${project_name}.conf.mako +9 -0
  146. bmcgo/codegen/lua/templates/new_app/test/integration/test_${project_name}.lua.mako +47 -0
  147. bmcgo/codegen/lua/templates/new_app/test/unit/test.lua.mako +23 -0
  148. bmcgo/codegen/lua/templates/new_app/user_conf/rootfs/etc/systemd/system/${project_name}.service.mako +18 -0
  149. bmcgo/codegen/lua/templates/new_app/user_conf/rootfs/etc/systemd/system/multi-user.target.wants/${project_name}.service.link +1 -0
  150. bmcgo/component/__init__.py +10 -0
  151. bmcgo/component/analysis/analysis.py +183 -0
  152. bmcgo/component/analysis/build_deps.py +165 -0
  153. bmcgo/component/analysis/data_deps.py +333 -0
  154. bmcgo/component/analysis/dep-rules.json +912 -0
  155. bmcgo/component/analysis/dep_node.py +110 -0
  156. bmcgo/component/analysis/intf_deps.py +163 -0
  157. bmcgo/component/analysis/intf_validation.py +254 -0
  158. bmcgo/component/analysis/rule.py +211 -0
  159. bmcgo/component/analysis/smc_dfx_whitelist.json +11 -0
  160. bmcgo/component/analysis/sr_validation.py +391 -0
  161. bmcgo/component/build.py +222 -0
  162. bmcgo/component/component_dt_version_parse.py +348 -0
  163. bmcgo/component/component_helper.py +114 -0
  164. bmcgo/component/coverage/__init__.py +11 -0
  165. bmcgo/component/coverage/c_incremental_cov_report.template +53 -0
  166. bmcgo/component/coverage/incremental_cov.py +464 -0
  167. bmcgo/component/deploy.py +110 -0
  168. bmcgo/component/gen.py +169 -0
  169. bmcgo/component/package_info.py +236 -0
  170. bmcgo/component/template/conanbase.py.mako +278 -0
  171. bmcgo/component/template/conanfile.deploy.py.mako +40 -0
  172. bmcgo/component/test.py +947 -0
  173. bmcgo/errors.py +119 -0
  174. bmcgo/frame.py +217 -0
  175. bmcgo/functional/__init__.py +10 -0
  176. bmcgo/functional/analysis.py +96 -0
  177. bmcgo/functional/bmc_studio_action.py +98 -0
  178. bmcgo/functional/check.py +185 -0
  179. bmcgo/functional/conan_index_build.py +251 -0
  180. bmcgo/functional/config.py +332 -0
  181. bmcgo/functional/csr_build.py +724 -0
  182. bmcgo/functional/deploy.py +263 -0
  183. bmcgo/functional/diff.py +235 -0
  184. bmcgo/functional/fetch.py +235 -0
  185. bmcgo/functional/full_component.py +391 -0
  186. bmcgo/functional/maintain.py +381 -0
  187. bmcgo/functional/new.py +166 -0
  188. bmcgo/functional/schema_valid.py +111 -0
  189. bmcgo/functional/simple_sign.py +104 -0
  190. bmcgo/functional/upgrade.py +78 -0
  191. bmcgo/ipmigen/__init__.py +13 -0
  192. bmcgo/ipmigen/ctype_defination.py +82 -0
  193. bmcgo/ipmigen/ipmigen.py +309 -0
  194. bmcgo/ipmigen/template/cmd.c.mako +366 -0
  195. bmcgo/ipmigen/template/ipmi.c.mako +25 -0
  196. bmcgo/ipmigen/template/ipmi.h.mako +51 -0
  197. bmcgo/logger.py +176 -0
  198. bmcgo/misc.py +117 -0
  199. bmcgo/target/app.yml +17 -0
  200. bmcgo/target/install_sdk.yml +15 -0
  201. bmcgo/target/personal.yml +53 -0
  202. bmcgo/target/publish.yml +45 -0
  203. bmcgo/tasks/__init__.py +11 -0
  204. bmcgo/tasks/download_buildtools_hm.py +124 -0
  205. bmcgo/tasks/misc.py +15 -0
  206. bmcgo/tasks/task.py +354 -0
  207. bmcgo/tasks/task_build_conan.py +714 -0
  208. bmcgo/tasks/task_build_rootfs_img.py +595 -0
  209. bmcgo/tasks/task_buildgppbin.py +88 -0
  210. bmcgo/tasks/task_buildhpm_ext4.py +82 -0
  211. bmcgo/tasks/task_create_interface_config.py +122 -0
  212. bmcgo/tasks/task_download_buildtools.py +99 -0
  213. bmcgo/tasks/task_download_dependency.py +72 -0
  214. bmcgo/tasks/task_hpm_envir_prepare.py +112 -0
  215. bmcgo/tasks/task_packet_to_supporte.py +87 -0
  216. bmcgo/tasks/task_prepare.py +105 -0
  217. bmcgo/tasks/task_sign_and_pack_hpm.py +42 -0
  218. bmcgo/utils/__init__.py +10 -0
  219. bmcgo/utils/buffer.py +128 -0
  220. bmcgo/utils/combine_json_schemas.py +170 -0
  221. bmcgo/utils/component_post.py +54 -0
  222. bmcgo/utils/component_version_check.py +86 -0
  223. bmcgo/utils/config.py +1067 -0
  224. bmcgo/utils/fetch_component_code.py +232 -0
  225. bmcgo/utils/install_manager.py +61 -0
  226. bmcgo/utils/installations/__init__.py +10 -0
  227. bmcgo/utils/installations/base_installer.py +70 -0
  228. bmcgo/utils/installations/install_consts.py +30 -0
  229. bmcgo/utils/installations/install_plans/bingo.yml +11 -0
  230. bmcgo/utils/installations/install_workflow.py +50 -0
  231. bmcgo/utils/installations/installers/apt_installer.py +177 -0
  232. bmcgo/utils/installations/installers/pip_installer.py +46 -0
  233. bmcgo/utils/installations/version_util.py +100 -0
  234. bmcgo/utils/mapping_config_patch.py +443 -0
  235. bmcgo/utils/perf_analysis.py +114 -0
  236. bmcgo/utils/tools.py +704 -0
  237. bmcgo/worker.py +417 -0
  238. openubmc_bingo-0.5.240.dist-info/METADATA +30 -0
  239. openubmc_bingo-0.5.240.dist-info/RECORD +242 -0
  240. openubmc_bingo-0.5.240.dist-info/WHEEL +5 -0
  241. openubmc_bingo-0.5.240.dist-info/entry_points.txt +2 -0
  242. openubmc_bingo-0.5.240.dist-info/top_level.txt +1 -0
@@ -0,0 +1,263 @@
1
+ #!/usr/bin/env python3
2
+ # encoding=utf-8
3
+ # 描述:组件维护工具
4
+ # Copyright (c) 2024 Huawei Technologies Co., Ltd.
5
+ # openUBMC is licensed under Mulan PSL v2.
6
+ # You can use this software according to the terms and conditions of the Mulan PSL v2.
7
+ # You may obtain a copy of Mulan PSL v2 at:
8
+ # http://license.coscl.org.cn/MulanPSL2
9
+ # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
10
+ # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
11
+ # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
12
+ # See the Mulan PSL v2 for more details.
13
+ import os
14
+ import argparse
15
+ import json
16
+ import time
17
+ from multiprocessing import Process
18
+ import pysftp
19
+ import requests
20
+ import yaml
21
+ import urllib3
22
+ from bmcgo.misc import CommandInfo
23
+ from bmcgo.utils.tools import Tools
24
+ from bmcgo.bmcgo_config import BmcgoConfig
25
+
26
+ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
27
+
28
+ tool = Tools("deploy")
29
+ log = tool.log
30
+ command_info: CommandInfo = CommandInfo(
31
+ group="Misc commands",
32
+ name="deploy",
33
+ description=["产品包部署"],
34
+ hidden=True
35
+ )
36
+
37
+
38
+ def if_available(bconfig: BmcgoConfig):
39
+ # 只在二级流水线有效
40
+ return bconfig.component is None
41
+
42
+
43
+ class BmcHostException(Exception):
44
+ def __init__(self, *args, **kwargs):
45
+ super(BmcHostException, self).__init__(*args, **kwargs)
46
+
47
+ def __str__(self):
48
+ return super(BmcHostException, self).__str__()
49
+
50
+
51
+ class RestApiException(Exception):
52
+ def __init__(self, *args, **kwargs):
53
+ super(RestApiException, self).__init__(*args, **kwargs)
54
+
55
+ def __str__(self):
56
+ return super(RestApiException, self).__str__()
57
+
58
+
59
+ class UpgradeTask(Process):
60
+ def __init__(self, config, cfg_file, filename):
61
+ super().__init__()
62
+ self.host = config.get("ip")
63
+ self.port = config.get("port")
64
+ self.username = config.get("username")
65
+ self.password = config.get("password")
66
+ self.filename = filename
67
+ if self.host is None:
68
+ raise BmcHostException(f"配置文件{cfg_file}缺少ip配置项.")
69
+ if self.port is None:
70
+ self.port = 443
71
+ else:
72
+ self.port = int(self.port)
73
+ if self.username is None:
74
+ raise BmcHostException(f"配置文件{cfg_file}缺少username配置项.")
75
+ if self.host is None:
76
+ raise BmcHostException(f"配置文件{cfg_file}缺少password配置项.")
77
+ if self.port != 443:
78
+ self.base_url = "https://" + self.host + ":" + str(self.port)
79
+ else:
80
+ self.base_url = "https://" + self.host
81
+ self.session = None
82
+ self.request_header = None
83
+
84
+ def run(self):
85
+ if self.session is None:
86
+ self._login()
87
+ try:
88
+ self._upload(self.filename)
89
+ if self.filename.endswith(".hpm"):
90
+ self._upgrade(self.filename)
91
+ else:
92
+ log.warning(f"{self.filename}文件名不是以.hpm结尾, 不支持升级.")
93
+ except Exception as e:
94
+ self._logout()
95
+ log.error("部署失败,错误信息:" + str(e))
96
+ return -1
97
+ self._logout()
98
+ return 0
99
+
100
+ def _login(self):
101
+ url = f"{self.base_url}/UI/Rest/Login"
102
+ log.info(f"{self.host} >> 登录")
103
+ payload = {
104
+ "UserName": self.username,
105
+ "Password": self.password,
106
+ "Domain": "LocaliBMC",
107
+ "Type": "Local"
108
+ }
109
+ resp = requests.post(url, data=payload, verify=False, timeout=10)
110
+ if resp.status_code != 200:
111
+ raise RestApiException(f"登录失败,登录接口返回状态码 {resp.status_code}.")
112
+ cookies = resp.cookies
113
+ body = json.loads(resp.content)
114
+ scsrf_token = body.get("XCSRFToken")
115
+ self.session = body.get("Session")
116
+ self.request_header = {
117
+ "X-Csrf-Token": scsrf_token,
118
+ "Cookie": "SessionId=" + cookies.get("SessionId")
119
+ }
120
+
121
+ def _upload_by_sftp(self, filename):
122
+ log.info(f"{self.host} >> 尝试使用sftp接口上传文件")
123
+ with pysftp.Connection(self.host, username=self.username, password=self.password) as sftp:
124
+ sftp.makedirs('/tmp/web')
125
+ with sftp.cd('/tmp/web'):
126
+ sftp.put(filename)
127
+
128
+ def _upload(self, filename):
129
+ log.info(f"{self.host} >> 上传文件 {filename} 至 /tmp/web/{os.path.basename(filename)}")
130
+ url = f"{self.base_url}/UI/Rest/FirmwareInventory"
131
+ files = {
132
+ "imgfile": open(filename, 'rb')
133
+ }
134
+ resp = requests.post(url, files=files, headers=self.request_header, verify=False, timeout=300)
135
+ if resp.status_code == 200:
136
+ return
137
+ log.warning(f"{self.host} >> 使用Rest接口上传{filename}失败,返回状态码 {resp.status_code}.")
138
+ self._upload_by_sftp(filename)
139
+
140
+ def _upgrade(self, filename):
141
+ log.info(f"{self.host} >> 调用接口启动升级")
142
+ url = f"{self.base_url}/UI/Rest/BMCSettings/UpdateService/FirmwareUpdate"
143
+ payload = {
144
+ "FilePath": os.path.join("/tmp/web/", os.path.basename(filename))
145
+ }
146
+ resp = requests.post(url, data=payload, headers=self.request_header, verify=False, timeout=10)
147
+ if resp.status_code != 200:
148
+ raise BmcHostException(f"升级{self.host}失败,Rest接口返回状态码 {resp.status_code}, 响应: {resp.content.decode()}.")
149
+ body = json.loads(resp.content)
150
+ url = self.base_url + body.get("url")
151
+ log.info(f"{self.host} >> 启动升级成功,开始检测升级状态")
152
+ sleep_sec = 1
153
+ progress = 0
154
+ while True:
155
+ time.sleep(sleep_sec)
156
+ resp = requests.get(url, headers=self.request_header, verify=False)
157
+ if resp.status_code != 200:
158
+ log.warning(f"{self.host} >> 轮询升级状态失败,Rest接口返回状态码 {resp.status_code},升级可能失败,请自检.")
159
+ break
160
+ body = json.loads(resp.content)
161
+ state = body.get("state")
162
+ if state in ["Exception", "Suspended", "Interrupted", "Pending", "Killed", "Cancelled"]:
163
+ raise BmcHostException(f"{self.host} >> 升级状态接口返回状态异常{state},升级失败")
164
+ if state == "Completed":
165
+ log.info(f"{self.host} >> 升级状态接口返回Completed状态")
166
+ return
167
+ if state not in ["Starting", "New", "Running"]:
168
+ raise BmcHostException(f"{self.host} >> 升级状态接口返回未知的{state}状态,升级可能失败,请自检.")
169
+ new_progress = int(body.get("prepare_progress"))
170
+ if new_progress != progress:
171
+ log.info(f"{self.host} >> 升级进度:{new_progress}")
172
+ progress = new_progress
173
+ if sleep_sec <= 2:
174
+ sleep_sec += 0.1
175
+
176
+ def _logout(self):
177
+ log.info(f"{self.host} >> 退出登录")
178
+ session_id = self.session.get("SessionID")
179
+ url = f"{self.base_url}/UI/Rest/Sessions/" + session_id
180
+ resp = requests.delete(url, headers=self.request_header, verify=False, timeout=10)
181
+ if resp.status_code != 200:
182
+ log.error(f"{self.host} >> 退出登录失败, status code {resp.status_code}")
183
+
184
+
185
+ class BmcgoCommand:
186
+ def __init__(self, bconfig: BmcgoConfig, *args):
187
+ self.bconfig = bconfig
188
+ parser = argparse.ArgumentParser(prog="bingo deploy", description="BMC产品包部署升级,待部署主机配置由bmcgo config命令管理",
189
+ add_help=True, formatter_class=argparse.RawTextHelpFormatter)
190
+ parser.add_argument("-f", "--filename", help="待部署的文件", required=True)
191
+ parsed_args = parser.parse_args(*args)
192
+ self.filename = os.path.realpath(parsed_args.filename)
193
+ if not os.path.isfile(self.filename):
194
+ raise argparse.ArgumentError(f"file {parsed_args.filename} not exist")
195
+
196
+ @staticmethod
197
+ def _calc_checksum():
198
+ pass
199
+
200
+ def run(self):
201
+ tasks = self._read_hosts()
202
+ if len(tasks) == 0:
203
+ log.warning("未找到可用的部署配置")
204
+ return
205
+ if len(tasks) == 1:
206
+ tasks[0].run()
207
+ return
208
+ for task in tasks:
209
+ task.start()
210
+ while len(tasks) > 0:
211
+ time.sleep(1)
212
+ for task in tasks:
213
+ if task.is_alive():
214
+ continue
215
+ if task.exitcode is not None and task.exitcode != 0:
216
+ log.error(f"{task.host} >> 升级失败")
217
+ else:
218
+ log.success(f"{task.host} >> 升级完成")
219
+ tasks.remove(task)
220
+ log.warning("部署过程受账号、网络、会话、代理、存储、设备状态等多方面影响,失败问题需要使用者自己定位,构建工程不提供直接支持。")
221
+
222
+ def _read_hosts(self):
223
+ tasks: list[UpgradeTask] = []
224
+ tasks = self._read_yml_hosts()
225
+ if tasks:
226
+ return tasks
227
+ tasks = self._read_config_hosts()
228
+ return tasks
229
+
230
+ def _read_yml_hosts(self):
231
+ tasks: list[UpgradeTask] = []
232
+ cur_dir = os.getcwd()
233
+ log.info("从当前路径开始向上递归查找.openUBMC_config.yml文件")
234
+ while cur_dir != "/":
235
+ cfg_file = os.path.join(cur_dir, ".openUBMC_config.yml")
236
+ if not os.path.isfile(cfg_file):
237
+ cur_dir = os.path.dirname(cur_dir)
238
+ continue
239
+ log.info(f"读取配置文件 {cfg_file}")
240
+ with open(cfg_file, "r") as fp:
241
+ config = yaml.safe_load(fp)
242
+ hosts = config.get("hosts", None)
243
+ if hosts is None:
244
+ log.warning(f"配置文件 {cfg_file} 未配置hosts对象")
245
+ continue
246
+ if isinstance(hosts, list):
247
+ for conf in hosts:
248
+ tasks.append(UpgradeTask(conf, cfg_file, self.filename))
249
+ elif isinstance(hosts, object):
250
+ tasks.append(UpgradeTask(hosts, cfg_file, self.filename))
251
+ return tasks
252
+ return []
253
+
254
+ def _read_config_hosts(self):
255
+ tasks: list[UpgradeTask] = []
256
+ for item in filter(lambda x: x.startswith("deploy-"), self.bconfig.bmcgo_config_list.keys()):
257
+ cfg_file = item
258
+ conf = {}
259
+ conf["ip"] = item.split('-')[1]
260
+ for k, v in self.bconfig.bmcgo_config_list[item].items():
261
+ conf[k] = v
262
+ tasks.append(UpgradeTask(conf, cfg_file, self.filename))
263
+ return tasks
@@ -0,0 +1,235 @@
1
+ #!/usr/bin/env python3
2
+ # coding: utf-8
3
+ # Copyright (c) 2025 Huawei Technologies Co., Ltd.
4
+ # openUBMC is licensed under Mulan PSL v2.
5
+ # You can use this software according to the terms and conditions of the Mulan PSL v2.
6
+ # You may obtain a copy of Mulan PSL v2 at:
7
+ # http://license.coscl.org.cn/MulanPSL2
8
+ # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
9
+ # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
10
+ # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
11
+ # See the Mulan PSL v2 for more details.
12
+ import os
13
+ import subprocess
14
+ import re
15
+ import shutil
16
+ import json
17
+ from tempfile import NamedTemporaryFile
18
+ from git import Repo
19
+ from bmcgo import misc
20
+ from bmcgo.utils.tools import Tools
21
+ from bmcgo.bmcgo_config import BmcgoConfig
22
+ from bmcgo import errors
23
+
24
+ tools = Tools()
25
+ log = Tools().log
26
+
27
+ command_info: misc.CommandInfo = misc.CommandInfo(
28
+ group=misc.GRP_MISC,
29
+ name="diff",
30
+ description=["获取两个产品版本间, 组件版本变更时的合并记录"],
31
+ help_info=["usage: bingo diff <commit id before> <commit id after>"],
32
+ hidden=False
33
+ )
34
+
35
+
36
+ def if_available(bconfig: BmcgoConfig):
37
+ if bconfig.manifest is None:
38
+ return False
39
+ return True
40
+
41
+ CONAN_DATA = ".conan/data"
42
+ VERSION_KEY = "revision"
43
+
44
+
45
+ class BmcgoCommand:
46
+ def __init__(self, bconfig: BmcgoConfig, *args):
47
+ # 这里可以是两个版本号, 也可以是两个version id, 版本号功能不开放
48
+ self.bconfig = bconfig
49
+ if len(args) != 1 or len(args[0]) != 2:
50
+ log.info("\n".join(command_info.help_info))
51
+ raise errors.bingoException("参数格式错误, 请查看上述提示")
52
+ self.version_before = args[0][0]
53
+ self.version_after = args[0][1]
54
+
55
+ @staticmethod
56
+ def check_path(version):
57
+ # 获取组件名称, 并作为下载的目标目录
58
+ component_name = version.split('/')[0]
59
+ to_path = f"temp/cmp_diff/{component_name}"
60
+ # 清空下载的目标目录
61
+ if os.path.exists(to_path):
62
+ shutil.rmtree(to_path)
63
+ os.makedirs(to_path)
64
+ return to_path, component_name
65
+
66
+ @staticmethod
67
+ def log_print(version_msg: dict, log_list: list):
68
+ description = ""
69
+ commit_index = 0
70
+ new_commit = False
71
+ edit_description = False
72
+
73
+ def printall(current_commit: list, description: str, version_msg: dict):
74
+ description = description.strip()
75
+ description = "当前MR未填写修改描述" if description == '' else description
76
+ cur_version = version_msg.get('url')[:-4]
77
+ for _log in current_commit[::-1]:
78
+ if "See merge request" in _log:
79
+ line = re.search("(?<=!)\d+", _log)[0]
80
+ log.info("%s/merge_requests/%s: %s", cur_version, line, description)
81
+ break
82
+ #将数据分割为一个一个commit
83
+ for i, _log in enumerate(log_list):
84
+ if re.match('^\s*Created-by:', _log):
85
+ new_commit = False
86
+ edit_description = False
87
+ #都为真时记录描述信息
88
+ if new_commit and edit_description:
89
+ description += _log
90
+ if re.match('^\s*merge', _log):
91
+ edit_description = True
92
+ if re.match('^commit', _log):
93
+ new_commit = True
94
+ if i != 0:
95
+ current_commit = log_list[commit_index: i - 1]
96
+ printall(current_commit, description, version_msg)
97
+ description = ''
98
+ commit_index = i
99
+ if i == len(log_list) - 1:
100
+ current_commit = log_list[commit_index:]
101
+ printall(current_commit, description, version_msg)
102
+
103
+ @staticmethod
104
+ def get_version_msg(version):
105
+ tempfile = NamedTemporaryFile()
106
+ # 过滤只包含scm的信息, 并将其生成为字典对象
107
+ ret = tools.run_command(f"conan info {version} --json {tempfile.name} \
108
+ -r {misc.CONAN_REPO}", ignore_error=True, command_echo=False, capture_output=True)
109
+ file_handler = open(tempfile.name, "r")
110
+ conan_comps = json.load(file_handler)
111
+ version_msg = ""
112
+ for conan_comp in conan_comps:
113
+ comp_ref = conan_comp.get("reference", "")
114
+ if comp_ref == version:
115
+ version_msg = conan_comp.get("scm", "")
116
+ break
117
+ file_handler.close()
118
+ if ret.returncode != 0 or version_msg == "":
119
+ log.info(version)
120
+ log.info("仅自研软件支持版本对比功能!")
121
+ return 1, version_msg
122
+ # 由于两个组件版本之间的依赖可能冲突,所以清理一遍data
123
+ if os.path.exists(os.path.join(os.path.expanduser('~'), CONAN_DATA)):
124
+ shutil.rmtree(os.path.join(os.path.expanduser('~'), CONAN_DATA))
125
+ return ret.returncode, version_msg
126
+
127
+ def stage_match_parse(self, repo, stage):
128
+ merge_time_1 = repo.git.log("--pretty=format:%at", "-1", self.version_before)
129
+ merge_time_2 = repo.git.log("--pretty=format:%at", "-1", self.version_after)
130
+ # 先对比两个version id的subsys目录下的几个文件, 并获取到有差异的组件
131
+ if merge_time_1 > merge_time_2:
132
+ self.version_before, self.version_after = self.version_after, self.version_before
133
+
134
+ diff_list = repo.git.diff(self.version_before, self.version_after, "--", f"build/subsys/{stage}").split('\n')
135
+ log.info("====>>>>>> manifest 由 %s 演进至 %s <<<<<<====", self.version_before, self.version_after)
136
+ # 由于git diff会打印许多的无关内容, 这里对其过滤
137
+ cmp_bef_dict = {}
138
+ cmp_aft_dict = {}
139
+ for diff in diff_list:
140
+ # 时间旧的 version id
141
+ match_bef = None
142
+ match_bef = re.search("(?<=^- - conan: ).*", diff)
143
+ if match_bef is not None:
144
+ match_bef = match_bef[0].replace('"', '')
145
+ cmp_bef_dict[match_bef.split('/')[0]] = match_bef
146
+
147
+ # 时间新的 version id
148
+ match_aft = None
149
+ match_aft = re.search("(?<=^\+ - conan: ).*", diff)
150
+ if match_aft is not None:
151
+ match_aft = match_aft[0].replace('"', '')
152
+ cmp_aft_dict[match_aft.split('/')[0]] = match_aft
153
+
154
+ # 差集列表
155
+ bef_aft_diff_set_list = []
156
+ aft_bef_diff_set_list = []
157
+ for match_name, match in cmp_bef_dict.items():
158
+ if match_name not in cmp_aft_dict.keys():
159
+ bef_aft_diff_set_list.append(match)
160
+ else:
161
+ self.parse_component_merge(match, cmp_aft_dict.get(match_name))
162
+ cmp_aft_dict.pop(match_name)
163
+
164
+ aft_bef_diff_set_list = cmp_aft_dict.values()
165
+ for del_cmp in bef_aft_diff_set_list:
166
+ log.info("---- ---- 由 %s 演进至 %s 删除组件 ---- ----", self.version_before, self.version_after)
167
+ self.parse_component_merge(del_cmp)
168
+ for del_cmp in aft_bef_diff_set_list:
169
+ log.info("++++ ++++ 由 %s 演进至 %s 新增组件 ++++ ++++", self.version_before, self.version_after)
170
+ self.parse_component_merge(del_cmp)
171
+
172
+ def parse_component_merge(self, version_before=None, version_after=None, sigle_commit_mode=False):
173
+ """如果传入的是两个组件的版本,使用此接口分析
174
+ """
175
+ # 单个提交模式下,执行这个if会自动退出
176
+ to_path, component_name = self.check_path(version_before)
177
+
178
+ ret, version_msg1 = self.get_version_msg(version_before)
179
+ if ret != 0:
180
+ return
181
+ if version_after:
182
+ ret, version_msg2 = self.get_version_msg(version_after)
183
+ if ret != 0:
184
+ return
185
+
186
+ # 由于组件在版本变更时,可能存储地址发生了改变,旧地址不存在,导致下载失败,同时输入的新地址可能也不存在
187
+ # 故用try进行确认,确保创建目标目录和下载正确执行
188
+ try:
189
+ Repo.clone_from(version_msg1.get("url"), to_path=to_path, branch='main')
190
+ except Exception as e1:
191
+ if version_after:
192
+ try:
193
+ Repo.clone_from(version_msg2.get("url"), to_path=to_path, branch='main')
194
+ except Exception as e2:
195
+ log.error(f"远程软件仓库地址不存在:{version_msg2.get('url')}")
196
+ raise e2
197
+ else:
198
+ log.error(f"远程软件仓库地址不存在:{version_msg1.get('url')}")
199
+ raise e1
200
+ repo = Repo(to_path)
201
+
202
+ if version_after is None:
203
+ log.info("== %s: %s", component_name, version_before)
204
+ merge_log = repo.git.log('--merges', version_msg1.get(VERSION_KEY), '--remotes=main', "-3")
205
+ self.log_print(version_msg1, merge_log.split('\n'))
206
+ return
207
+
208
+ # 获取两个节点的提交时间, 使用 ‘old..new' 格式进行对比
209
+ merge_time_1 = repo.git.log("--pretty=format:%at", "-1", version_msg1.get(VERSION_KEY))
210
+ merge_time_2 = repo.git.log("--pretty=format:%at", "-1", version_msg2.get(VERSION_KEY))
211
+ if merge_time_1 > merge_time_2:
212
+ merge_time_1, merge_time_2 = merge_time_2, merge_time_1
213
+ version_before, version_after = version_after, version_before
214
+ log.info("==== ==== %s 由 %s 演进至 %s ==== ====", component_name, version_before, version_after)
215
+ merge_log = repo.git.log('--merges', f"{version_msg1.get(VERSION_KEY)}..{version_msg2.get(VERSION_KEY)}",
216
+ '--remotes=main')
217
+ self.log_print(version_msg1, merge_log.split('\n'))
218
+
219
+ def parse_commit_merge(self):
220
+ """如果是两个commit id, 那么使用此接口进行分析
221
+ """
222
+ log.info(f"合并记录为时间排序,并非编号排序")
223
+ log.info(f"版本演进均为旧版本演进为新版本, 回滚提交也视为演进")
224
+ repo = Repo(self.bconfig.manifest.folder)
225
+ self.stage_match_parse(repo, "stable")
226
+ self.stage_match_parse(repo, "rc")
227
+
228
+ def run(self):
229
+ if "@" in self.version_before and "@" in self.version_after:
230
+ raise errors.bingoException(f"不支持两个组件版本对比")
231
+ elif "@" not in self.version_before and "@" not in self.version_after:
232
+ self.parse_commit_merge()
233
+ else:
234
+ raise errors.bingoException("输入的版本号无法解析")
235
+ return 0