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.
- bmcgo/__init__.py +12 -0
- bmcgo/bmcgo.py +22 -0
- bmcgo/bmcgo_config.py +176 -0
- bmcgo/cli/__init__.py +10 -0
- bmcgo/cli/cli.py +584 -0
- bmcgo/codegen/__init__.py +14 -0
- bmcgo/codegen/c/__init__.py +9 -0
- bmcgo/codegen/c/annotation.py +52 -0
- bmcgo/codegen/c/argument.py +42 -0
- bmcgo/codegen/c/codegen.py +153 -0
- bmcgo/codegen/c/comment.py +22 -0
- bmcgo/codegen/c/ctype_defination.py +353 -0
- bmcgo/codegen/c/helper.py +87 -0
- bmcgo/codegen/c/interface.py +63 -0
- bmcgo/codegen/c/method.py +82 -0
- bmcgo/codegen/c/property.py +180 -0
- bmcgo/codegen/c/renderer.py +21 -0
- bmcgo/codegen/c/signal.py +64 -0
- bmcgo/codegen/c/template/client.c.mako +145 -0
- bmcgo/codegen/c/template/client.h.mako +36 -0
- bmcgo/codegen/c/template/interface.c.mako +0 -0
- bmcgo/codegen/c/template/interface.introspect.xml.mako +99 -0
- bmcgo/codegen/c/template/micro_component.c.mako +32 -0
- bmcgo/codegen/c/template/public.c.mako +228 -0
- bmcgo/codegen/c/template/public.h.mako +128 -0
- bmcgo/codegen/c/template/server.c.mako +104 -0
- bmcgo/codegen/c/template/server.h.mako +36 -0
- bmcgo/codegen/lua/.lua-format +7 -0
- bmcgo/codegen/lua/Makefile +101 -0
- bmcgo/codegen/lua/__init__.py +9 -0
- bmcgo/codegen/lua/codegen.py +171 -0
- bmcgo/codegen/lua/proto/Makefile +87 -0
- bmcgo/codegen/lua/proto/ipmi_types.proto +17 -0
- bmcgo/codegen/lua/proto/types.proto +52 -0
- bmcgo/codegen/lua/script/check_intfs.py +161 -0
- bmcgo/codegen/lua/script/dto/__init__.py +11 -0
- bmcgo/codegen/lua/script/dto/exception.py +53 -0
- bmcgo/codegen/lua/script/dto/kepler_abstract.py +47 -0
- bmcgo/codegen/lua/script/dto/options.py +33 -0
- bmcgo/codegen/lua/script/dto/print_simple.py +19 -0
- bmcgo/codegen/lua/script/dto/redfish_api.py +241 -0
- bmcgo/codegen/lua/script/dto/url_route.py +195 -0
- bmcgo/codegen/lua/script/gen_db_json.py +444 -0
- bmcgo/codegen/lua/script/gen_depends.py +89 -0
- bmcgo/codegen/lua/script/gen_entry.py +263 -0
- bmcgo/codegen/lua/script/gen_feature_json.py +156 -0
- bmcgo/codegen/lua/script/gen_historical_local_db_json.py +88 -0
- bmcgo/codegen/lua/script/gen_intf_json.py +261 -0
- bmcgo/codegen/lua/script/gen_intf_rpc_json.py +575 -0
- bmcgo/codegen/lua/script/gen_ipmi_json.py +485 -0
- bmcgo/codegen/lua/script/gen_mdb_json.py +117 -0
- bmcgo/codegen/lua/script/gen_rpc_msg_json.py +487 -0
- bmcgo/codegen/lua/script/gen_schema.py +302 -0
- bmcgo/codegen/lua/script/ipmi_types_pb2.py +135 -0
- bmcgo/codegen/lua/script/loader/__init__.py +11 -0
- bmcgo/codegen/lua/script/loader/file_utils.py +33 -0
- bmcgo/codegen/lua/script/loader/kepler_abstract_collect.py +79 -0
- bmcgo/codegen/lua/script/loader/kepler_abstract_loader.py +47 -0
- bmcgo/codegen/lua/script/loader/redfish_loader.py +127 -0
- bmcgo/codegen/lua/script/lua_format.py +62 -0
- bmcgo/codegen/lua/script/mds_util.py +385 -0
- bmcgo/codegen/lua/script/merge_model.py +330 -0
- bmcgo/codegen/lua/script/merge_proto_algo.py +85 -0
- bmcgo/codegen/lua/script/proto_loader.py +47 -0
- bmcgo/codegen/lua/script/proto_plugin.py +140 -0
- bmcgo/codegen/lua/script/redfish_source_tree.py +118 -0
- bmcgo/codegen/lua/script/render_utils/__init__.py +38 -0
- bmcgo/codegen/lua/script/render_utils/base.py +25 -0
- bmcgo/codegen/lua/script/render_utils/client_lua.py +98 -0
- bmcgo/codegen/lua/script/render_utils/controller_lua.py +71 -0
- bmcgo/codegen/lua/script/render_utils/db_lua.py +224 -0
- bmcgo/codegen/lua/script/render_utils/error_lua.py +185 -0
- bmcgo/codegen/lua/script/render_utils/factory.py +52 -0
- bmcgo/codegen/lua/script/render_utils/ipmi_lua.py +159 -0
- bmcgo/codegen/lua/script/render_utils/ipmi_message_lua.py +24 -0
- bmcgo/codegen/lua/script/render_utils/mdb_lua.py +177 -0
- bmcgo/codegen/lua/script/render_utils/mdb_register.py +215 -0
- bmcgo/codegen/lua/script/render_utils/message_lua.py +26 -0
- bmcgo/codegen/lua/script/render_utils/messages_lua.py +156 -0
- bmcgo/codegen/lua/script/render_utils/model_lua.py +485 -0
- bmcgo/codegen/lua/script/render_utils/old_model_lua.py +429 -0
- bmcgo/codegen/lua/script/render_utils/plugin_lua.py +38 -0
- bmcgo/codegen/lua/script/render_utils/redfish_proto.py +86 -0
- bmcgo/codegen/lua/script/render_utils/request_lua.py +76 -0
- bmcgo/codegen/lua/script/render_utils/service_lua.py +130 -0
- bmcgo/codegen/lua/script/render_utils/utils_message_lua.py +125 -0
- bmcgo/codegen/lua/script/render_utils/validate_lua.py +221 -0
- bmcgo/codegen/lua/script/sep_ipmi_message_cmds.py +217 -0
- bmcgo/codegen/lua/script/template.py +166 -0
- bmcgo/codegen/lua/script/types_pb2.py +516 -0
- bmcgo/codegen/lua/script/utils.py +663 -0
- bmcgo/codegen/lua/script/validate.py +80 -0
- bmcgo/codegen/lua/script/yaml_to_json.py +73 -0
- bmcgo/codegen/lua/templates/Makefile +114 -0
- bmcgo/codegen/lua/templates/apps/Makefile +261 -0
- bmcgo/codegen/lua/templates/apps/Makefile.mdb.mk +64 -0
- bmcgo/codegen/lua/templates/apps/app.lua.mako +19 -0
- bmcgo/codegen/lua/templates/apps/class.lua.mako +35 -0
- bmcgo/codegen/lua/templates/apps/client.lua.mako +429 -0
- bmcgo/codegen/lua/templates/apps/controller.lua.mako +276 -0
- bmcgo/codegen/lua/templates/apps/datas.lua.mako +8 -0
- bmcgo/codegen/lua/templates/apps/db.lua.mako +89 -0
- bmcgo/codegen/lua/templates/apps/entry.lua.mako +128 -0
- bmcgo/codegen/lua/templates/apps/feature.lua.mako +37 -0
- bmcgo/codegen/lua/templates/apps/generate_route.mako +25 -0
- bmcgo/codegen/lua/templates/apps/impl_feature.lua.mako +72 -0
- bmcgo/codegen/lua/templates/apps/ipmi.lua.mako +97 -0
- bmcgo/codegen/lua/templates/apps/ipmi_cmd.lua.mako +18 -0
- bmcgo/codegen/lua/templates/apps/ipmi_message.lua.mako +36 -0
- bmcgo/codegen/lua/templates/apps/local_db.lua.mako +263 -0
- bmcgo/codegen/lua/templates/apps/main.lua.mako +25 -0
- bmcgo/codegen/lua/templates/apps/mc.lua.mako +77 -0
- bmcgo/codegen/lua/templates/apps/mdb.lua.mako +45 -0
- bmcgo/codegen/lua/templates/apps/mdb_interface.lua.mako +73 -0
- bmcgo/codegen/lua/templates/apps/message.lua.mako +38 -0
- bmcgo/codegen/lua/templates/apps/model.lua.mako +239 -0
- bmcgo/codegen/lua/templates/apps/orm_classes.lua.mako +16 -0
- bmcgo/codegen/lua/templates/apps/plugin.lua.mako +8 -0
- bmcgo/codegen/lua/templates/apps/redfish.proto.mako +47 -0
- bmcgo/codegen/lua/templates/apps/service.lua.mako +440 -0
- bmcgo/codegen/lua/templates/apps/signal_listen.lua.mako +19 -0
- bmcgo/codegen/lua/templates/apps/utils/default_intf.lua.mako +41 -0
- bmcgo/codegen/lua/templates/apps/utils/enum.mako +10 -0
- bmcgo/codegen/lua/templates/apps/utils/imports.mako +13 -0
- bmcgo/codegen/lua/templates/apps/utils/mdb_intf.lua.mako +25 -0
- bmcgo/codegen/lua/templates/apps/utils/mdb_obj.lua.mako +23 -0
- bmcgo/codegen/lua/templates/apps/utils/message.mako +160 -0
- bmcgo/codegen/lua/templates/apps/utils/request.lua.mako +59 -0
- bmcgo/codegen/lua/templates/apps/utils/validate.mako +83 -0
- bmcgo/codegen/lua/templates/errors.lua.mako +36 -0
- bmcgo/codegen/lua/templates/messages.lua.mako +32 -0
- bmcgo/codegen/lua/templates/new_app/.clang-format.mako +170 -0
- bmcgo/codegen/lua/templates/new_app/.gitignore.mako +26 -0
- bmcgo/codegen/lua/templates/new_app/CHANGELOG.md.mako +0 -0
- bmcgo/codegen/lua/templates/new_app/CMakeLists.txt.mako +29 -0
- bmcgo/codegen/lua/templates/new_app/Makefile.mako +25 -0
- bmcgo/codegen/lua/templates/new_app/README.md.mako +0 -0
- bmcgo/codegen/lua/templates/new_app/conanfile.py.mako +7 -0
- bmcgo/codegen/lua/templates/new_app/config.cfg.mako +6 -0
- bmcgo/codegen/lua/templates/new_app/mds/model.json.mako +3 -0
- bmcgo/codegen/lua/templates/new_app/mds/service.json.mako +21 -0
- bmcgo/codegen/lua/templates/new_app/permissions.ini.mako +16 -0
- bmcgo/codegen/lua/templates/new_app/src/lualib/${project_name}_app.lua.mako +16 -0
- bmcgo/codegen/lua/templates/new_app/src/service/main.lua.mako +25 -0
- bmcgo/codegen/lua/templates/new_app/test/integration/test_${project_name}.conf.mako +9 -0
- bmcgo/codegen/lua/templates/new_app/test/integration/test_${project_name}.lua.mako +47 -0
- bmcgo/codegen/lua/templates/new_app/test/unit/test.lua.mako +23 -0
- bmcgo/codegen/lua/templates/new_app/user_conf/rootfs/etc/systemd/system/${project_name}.service.mako +18 -0
- bmcgo/codegen/lua/templates/new_app/user_conf/rootfs/etc/systemd/system/multi-user.target.wants/${project_name}.service.link +1 -0
- bmcgo/component/__init__.py +10 -0
- bmcgo/component/analysis/analysis.py +183 -0
- bmcgo/component/analysis/build_deps.py +165 -0
- bmcgo/component/analysis/data_deps.py +333 -0
- bmcgo/component/analysis/dep-rules.json +912 -0
- bmcgo/component/analysis/dep_node.py +110 -0
- bmcgo/component/analysis/intf_deps.py +163 -0
- bmcgo/component/analysis/intf_validation.py +254 -0
- bmcgo/component/analysis/rule.py +211 -0
- bmcgo/component/analysis/smc_dfx_whitelist.json +11 -0
- bmcgo/component/analysis/sr_validation.py +391 -0
- bmcgo/component/build.py +222 -0
- bmcgo/component/component_dt_version_parse.py +348 -0
- bmcgo/component/component_helper.py +114 -0
- bmcgo/component/coverage/__init__.py +11 -0
- bmcgo/component/coverage/c_incremental_cov_report.template +53 -0
- bmcgo/component/coverage/incremental_cov.py +464 -0
- bmcgo/component/deploy.py +110 -0
- bmcgo/component/gen.py +169 -0
- bmcgo/component/package_info.py +236 -0
- bmcgo/component/template/conanbase.py.mako +278 -0
- bmcgo/component/template/conanfile.deploy.py.mako +40 -0
- bmcgo/component/test.py +947 -0
- bmcgo/errors.py +119 -0
- bmcgo/frame.py +217 -0
- bmcgo/functional/__init__.py +10 -0
- bmcgo/functional/analysis.py +96 -0
- bmcgo/functional/bmc_studio_action.py +98 -0
- bmcgo/functional/check.py +185 -0
- bmcgo/functional/conan_index_build.py +251 -0
- bmcgo/functional/config.py +332 -0
- bmcgo/functional/csr_build.py +724 -0
- bmcgo/functional/deploy.py +263 -0
- bmcgo/functional/diff.py +235 -0
- bmcgo/functional/fetch.py +235 -0
- bmcgo/functional/full_component.py +391 -0
- bmcgo/functional/maintain.py +381 -0
- bmcgo/functional/new.py +166 -0
- bmcgo/functional/schema_valid.py +111 -0
- bmcgo/functional/simple_sign.py +104 -0
- bmcgo/functional/upgrade.py +78 -0
- bmcgo/ipmigen/__init__.py +13 -0
- bmcgo/ipmigen/ctype_defination.py +82 -0
- bmcgo/ipmigen/ipmigen.py +309 -0
- bmcgo/ipmigen/template/cmd.c.mako +366 -0
- bmcgo/ipmigen/template/ipmi.c.mako +25 -0
- bmcgo/ipmigen/template/ipmi.h.mako +51 -0
- bmcgo/logger.py +176 -0
- bmcgo/misc.py +117 -0
- bmcgo/target/app.yml +17 -0
- bmcgo/target/install_sdk.yml +15 -0
- bmcgo/target/personal.yml +53 -0
- bmcgo/target/publish.yml +45 -0
- bmcgo/tasks/__init__.py +11 -0
- bmcgo/tasks/download_buildtools_hm.py +124 -0
- bmcgo/tasks/misc.py +15 -0
- bmcgo/tasks/task.py +354 -0
- bmcgo/tasks/task_build_conan.py +714 -0
- bmcgo/tasks/task_build_rootfs_img.py +595 -0
- bmcgo/tasks/task_buildgppbin.py +88 -0
- bmcgo/tasks/task_buildhpm_ext4.py +82 -0
- bmcgo/tasks/task_create_interface_config.py +122 -0
- bmcgo/tasks/task_download_buildtools.py +99 -0
- bmcgo/tasks/task_download_dependency.py +72 -0
- bmcgo/tasks/task_hpm_envir_prepare.py +112 -0
- bmcgo/tasks/task_packet_to_supporte.py +87 -0
- bmcgo/tasks/task_prepare.py +105 -0
- bmcgo/tasks/task_sign_and_pack_hpm.py +42 -0
- bmcgo/utils/__init__.py +10 -0
- bmcgo/utils/buffer.py +128 -0
- bmcgo/utils/combine_json_schemas.py +170 -0
- bmcgo/utils/component_post.py +54 -0
- bmcgo/utils/component_version_check.py +86 -0
- bmcgo/utils/config.py +1067 -0
- bmcgo/utils/fetch_component_code.py +232 -0
- bmcgo/utils/install_manager.py +61 -0
- bmcgo/utils/installations/__init__.py +10 -0
- bmcgo/utils/installations/base_installer.py +70 -0
- bmcgo/utils/installations/install_consts.py +30 -0
- bmcgo/utils/installations/install_plans/bingo.yml +11 -0
- bmcgo/utils/installations/install_workflow.py +50 -0
- bmcgo/utils/installations/installers/apt_installer.py +177 -0
- bmcgo/utils/installations/installers/pip_installer.py +46 -0
- bmcgo/utils/installations/version_util.py +100 -0
- bmcgo/utils/mapping_config_patch.py +443 -0
- bmcgo/utils/perf_analysis.py +114 -0
- bmcgo/utils/tools.py +704 -0
- bmcgo/worker.py +417 -0
- openubmc_bingo-0.5.240.dist-info/METADATA +30 -0
- openubmc_bingo-0.5.240.dist-info/RECORD +242 -0
- openubmc_bingo-0.5.240.dist-info/WHEEL +5 -0
- openubmc_bingo-0.5.240.dist-info/entry_points.txt +2 -0
- 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
|
bmcgo/functional/diff.py
ADDED
|
@@ -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
|