Line data Source code
1 : /**
2 : * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 :
11 : #include "package_process_config.h"
12 :
13 : #include <fstream>
14 : #include <array>
15 : #include <vector>
16 : #include <unordered_set>
17 : #include "package_worker.h"
18 : #include "tsd_util_func.h"
19 :
20 : namespace tsd {
21 : namespace {
22 : const std::string PACKAGE_CONFIG_NAME = "name:";
23 : const std::string COMMON_SINK_PKG_CONFIG_NAME = "ascend_package_load.ini";
24 : const std::string COMMON_SINK_PKG_CONFIG_DIR = "/conf/";
25 : const size_t MAX_CONFIG_NUM = 100UL;
26 : } // namespace
27 :
28 5 : PackageProcessConfig::PackageProcessConfig()
29 30 : : configParaParseFuncMap_(
30 0 : {{"install_path", &PackageProcessConfig::ParseInstallPath},
31 0 : {"optional", &PackageProcessConfig::ParseOptionalFlag},
32 0 : {"package_path", &PackageProcessConfig::ParsePackagePath},
33 10 : {"load_as_per_soc", &PackageProcessConfig::ParseLoadAsPerSocFlag}})
34 10 : {}
35 :
36 341 : PackageProcessConfig* PackageProcessConfig::GetInstance()
37 : {
38 341 : static PackageProcessConfig instance;
39 341 : return &instance;
40 : }
41 :
42 32 : PackConfDetail PackageProcessConfig::GetConfigDetailInfo(const std::string& srcPath)
43 : {
44 32 : const std::lock_guard<std::mutex> lk(configMut_);
45 32 : const auto iter = configMap_.find(srcPath);
46 32 : if (iter != configMap_.end()) {
47 31 : return iter->second;
48 : } else {
49 1 : return PackConfDetail();
50 : }
51 32 : }
52 :
53 1 : bool PackageProcessConfig::SetConfigDataOnServer(const SinkPackageConfig& hdcConfig)
54 : {
55 1 : const std::string pkgName = hdcConfig.package_name();
56 1 : auto iter = configMap_.find(pkgName);
57 1 : if (iter != configMap_.end()) {
58 0 : iter->second.decDstDir = static_cast<DeviceInstallPath>(hdcConfig.file_dec_dst_dir());
59 0 : TSD_RUN_INFO(
60 : "update package:%s config, dest dir:%u", pkgName.c_str(), static_cast<uint32_t>(iter->second.decDstDir));
61 : } else {
62 1 : if (configMap_.size() >= MAX_CONFIG_NUM) {
63 0 : TSD_RUN_WARN("current config map is full:%zu, threshold is:%zu", configMap_.size(), MAX_CONFIG_NUM);
64 0 : return true;
65 : }
66 1 : PackConfDetail tempNode;
67 1 : tempNode.decDstDir = static_cast<DeviceInstallPath>(hdcConfig.file_dec_dst_dir());
68 1 : tempNode.validFlag = true;
69 1 : tempNode.PrintfInfo(pkgName);
70 : try {
71 1 : configMap_[pkgName] = tempNode;
72 1 : TSD_RUN_INFO("insert package:%s config", pkgName.c_str());
73 0 : } catch (...) {
74 0 : TSD_ERROR("");
75 0 : return false;
76 0 : }
77 1 : }
78 1 : return true;
79 1 : }
80 :
81 2 : TSD_StatusT PackageProcessConfig::ParseConfigDataFromProtoBuf(const HDCMessage& hdcMsg)
82 : {
83 2 : const std::lock_guard<std::mutex> lk(configMut_);
84 103 : for (auto j = 0; j < hdcMsg.sink_pkg_con_list_size(); j++) {
85 102 : const SinkPackageConfig& hdcConfig = hdcMsg.sink_pkg_con_list(j);
86 102 : if (!SetConfigDataOnServer(hdcConfig)) {
87 1 : TSD_RUN_WARN("invalid config data");
88 1 : return TSD_START_FAIL;
89 : }
90 : }
91 1 : hashCode_ = hdcMsg.package_config_hash_code();
92 1 : TSD_RUN_INFO("package config has stored hash code:%s", hashCode_.c_str());
93 1 : return TSD_OK;
94 2 : }
95 :
96 24 : std::string PackageProcessConfig::GetHostFilePath(const std::string& fileDir, const std::string& fileName) const
97 : {
98 24 : std::string configPath;
99 24 : GetScheduleEnv("ASCEND_HOME_PATH", configPath);
100 24 : if (configPath.empty()) {
101 0 : configPath = "/usr/local/Ascend/latest/";
102 0 : TSD_INFO("ASCEND_HOME_PATH is not set, use default value[%s]", configPath.c_str());
103 : }
104 :
105 24 : configPath = configPath + "/" + fileDir;
106 24 : if (access(configPath.c_str(), F_OK) != 0) {
107 5 : TSD_RUN_WARN("cannot get package path:%s, reason:%s", configPath.c_str(), SafeStrerror().c_str());
108 10 : return "";
109 : }
110 19 : configPath = configPath + fileName;
111 19 : if (access(configPath.c_str(), F_OK) != 0) {
112 0 : TSD_INFO("cannot get package file:%s, reason:%s", configPath.c_str(), SafeStrerror().c_str());
113 0 : return "";
114 : }
115 19 : TSD_INFO("get config path:%s", configPath.c_str());
116 19 : return configPath;
117 24 : }
118 :
119 8 : TSD_StatusT PackageProcessConfig::ParseConfigDataFromFile(const std::string& pkgTitle)
120 : {
121 8 : const std::string conFile = GetHostFilePath(COMMON_SINK_PKG_CONFIG_DIR, COMMON_SINK_PKG_CONFIG_NAME);
122 8 : if (access(conFile.c_str(), R_OK) != 0) {
123 0 : TSD_INFO("cannot access file:%s, errno=%d, strerror=%s", conFile.c_str(), errno, strerror(errno));
124 0 : return TSD_OK;
125 : }
126 :
127 8 : const std::lock_guard<std::mutex> lk(configMut_);
128 8 : if (finishParse_) {
129 5 : TSD_INFO("config already set, skip parse");
130 5 : return TSD_OK;
131 : }
132 :
133 3 : std::ifstream inFile(conFile);
134 3 : if (!inFile) {
135 0 : TSD_ERROR("open file:%s nok, errno=%d, strerror=%s", conFile.c_str(), errno, strerror(errno));
136 0 : return TSD_START_FAIL;
137 : }
138 6 : const ScopeGuard fileGuard([&inFile]() { inFile.close(); });
139 :
140 3 : std::string inputLine;
141 3 : size_t itCnt = 0;
142 14 : while (getline(inFile, inputLine) && itCnt < MAX_CONFIG_NUM) {
143 13 : TSD_INFO("read config data current line:%s", inputLine.c_str());
144 13 : std::string packageName;
145 13 : const size_t pos = inputLine.find(PACKAGE_CONFIG_NAME);
146 13 : if (pos != std::string::npos) {
147 13 : packageName = inputLine.substr(pos + PACKAGE_CONFIG_NAME.size());
148 13 : Trim(packageName);
149 13 : if (packageName.empty()) {
150 1 : TSD_ERROR("valid package name is empty read line:%s", inputLine.c_str());
151 1 : configMap_.clear();
152 1 : return TSD_START_FAIL;
153 : }
154 12 : if (configMap_.find(packageName) == configMap_.end()) {
155 12 : if (!SetConfigDataOnHost(inFile, packageName, pkgTitle)) {
156 1 : TSD_ERROR("package:%s config read but not store, clear all config", packageName.c_str());
157 1 : configMap_.clear();
158 1 : return TSD_START_FAIL;
159 : }
160 : }
161 11 : itCnt++;
162 : }
163 13 : }
164 1 : finishParse_ = true;
165 1 : return TSD_OK;
166 8 : }
167 :
168 59 : bool PackageProcessConfig::ParseSinglePara(
169 : std::string& inputLine, PackConfDetail& tempNode, std::unordered_set<std::string>& finishedParseItemSet) const
170 : {
171 59 : const std::size_t pos = inputLine.find(":");
172 59 : if (pos == std::string::npos) {
173 1 : TSD_ERROR("invalid config line:%s", inputLine.c_str());
174 1 : return false;
175 : }
176 58 : std::string key = inputLine.substr(0, pos);
177 58 : Trim(key);
178 58 : std::string value = inputLine.substr(pos + 1UL);
179 58 : Trim(value);
180 58 : const auto iter = configParaParseFuncMap_.find(key);
181 58 : if (iter == configParaParseFuncMap_.end()) {
182 1 : TSD_ERROR("invalid config item:%s, line:%s", key.c_str(), inputLine.c_str());
183 1 : return false;
184 : }
185 57 : if ((this->*(iter->second))(value, tempNode)) {
186 56 : finishedParseItemSet.insert(key);
187 56 : return true;
188 : }
189 1 : return false;
190 58 : }
191 :
192 16 : bool PackageProcessConfig::ParseInstallPath(const std::string& para, PackConfDetail& tempNode) const
193 : {
194 16 : if ((para == "0") || (para == "1") || (para == "2") || (para == "3")) {
195 15 : int32_t result = 0;
196 15 : (void)TransStrToInt(para, result);
197 15 : tempNode.decDstDir = static_cast<DeviceInstallPath>(result);
198 : } else {
199 1 : TSD_ERROR("invalid installPath:%s", para.c_str());
200 1 : return false;
201 : }
202 15 : return true;
203 : }
204 :
205 18 : bool PackageProcessConfig::ParseOptionalFlag(const std::string& para, PackConfDetail& tempNode) const
206 : {
207 18 : if ((para == "true") || (para == "false")) {
208 16 : tempNode.optionalFlag = para == "true" ? true : false;
209 : } else {
210 2 : TSD_ERROR("invalid optionalFlag:%s", para.c_str());
211 2 : return false;
212 : }
213 16 : return true;
214 : }
215 :
216 16 : bool PackageProcessConfig::ParsePackagePath(const std::string& para, PackConfDetail& tempNode) const
217 : {
218 16 : if (!para.empty()) {
219 15 : tempNode.findPath = para;
220 : } else {
221 1 : TSD_ERROR("invalid packagePath:%s", para.c_str());
222 1 : return false;
223 : }
224 15 : return true;
225 : }
226 :
227 15 : bool PackageProcessConfig::ParseLoadAsPerSocFlag(const std::string& para, PackConfDetail& tempNode) const
228 : {
229 15 : if ((para == "true") || (para == "false")) {
230 14 : tempNode.loadAsPerSocFlag = para == "true" ? true : false;
231 : } else {
232 1 : TSD_ERROR("invalid loadAsPerSocFlag:%s", para.c_str());
233 1 : return false;
234 : }
235 14 : return true;
236 : }
237 :
238 15 : bool PackageProcessConfig::SetConfigDataOnHost(
239 : std::ifstream& inFile, const std::string& fileName, const std::string& pkgTitle)
240 : {
241 15 : std::string inputLine;
242 15 : uint32_t itCnt = 0U;
243 15 : const uint32_t configItemNum = static_cast<uint32_t>(configParaParseFuncMap_.size());
244 15 : PackConfDetail tempNode = {};
245 15 : std::unordered_set<std::string> finishedParseItemSet;
246 70 : while ((itCnt < configItemNum) && (getline(inFile, inputLine))) {
247 56 : if (!ParseSinglePara(inputLine, tempNode, finishedParseItemSet)) {
248 1 : TSD_ERROR("parse config line failed:%s", inputLine.c_str());
249 1 : return false;
250 : }
251 55 : itCnt++;
252 : }
253 14 : if (finishedParseItemSet.size() != configItemNum) {
254 1 : TSD_ERROR("not all config items parsed");
255 1 : return false;
256 : }
257 13 : tempNode.validFlag = true;
258 : try {
259 13 : if (!SetPkgHostTruePath(tempNode, fileName, pkgTitle)) {
260 1 : TSD_ERROR("set package:%s host true path failed", fileName.c_str());
261 1 : return false;
262 : }
263 12 : configMap_[fileName] = tempNode;
264 12 : tempNode.PrintfInfo(fileName);
265 12 : TSD_RUN_INFO("insert package:%s config", fileName.c_str());
266 0 : } catch (...) {
267 0 : TSD_ERROR("insert package:%s config failed", fileName.c_str());
268 0 : return false;
269 0 : }
270 12 : return true;
271 15 : }
272 :
273 5 : void PackageProcessConfig::ConstructPkgConfigMsg(HDCMessage& hdcMsg)
274 : {
275 60 : for (auto iter = configMap_.begin(); iter != configMap_.end(); iter++) {
276 55 : SinkPackageConfig* curConf = hdcMsg.add_sink_pkg_con_list();
277 55 : curConf->set_package_name(iter->first);
278 55 : curConf->set_file_dec_dst_dir(static_cast<uint32_t>(iter->second.decDstDir));
279 : // 对于 compat plugin 包,附带 host 侧解析得到的 version/timestamp
280 55 : if (iter->second.decDstDir != DeviceInstallPath::COMPAT_PLUGIN_PATH) {
281 55 : continue;
282 : }
283 10 : std::lock_guard<std::mutex> lock(hostPluginVersionMut_);
284 10 : const auto verIt = hostPluginVersions_.find(iter->first);
285 10 : if (verIt == hostPluginVersions_.end() || verIt->second.Empty()) {
286 10 : continue;
287 : }
288 :
289 0 : PluginPackageVersionInfo* info = hdcMsg.add_host_plugin_versions();
290 0 : info->set_package_name(iter->first);
291 0 : info->set_version(verIt->second.version);
292 0 : info->set_timestamp(verIt->second.timestamp);
293 10 : }
294 : const std::string hashCode =
295 5 : CalFileSha256HashValue(GetHostFilePath(COMMON_SINK_PKG_CONFIG_DIR, COMMON_SINK_PKG_CONFIG_NAME));
296 : hdcMsg.set_package_config_hash_code(hashCode);
297 5 : TSD_INFO("set config hash code:%s", hashCode.c_str());
298 5 : }
299 :
300 1 : void PackageProcessConfig::RefreshHostPluginVersions()
301 : {
302 3 : for (auto& kv : configMap_) {
303 2 : if (kv.second.decDstDir != DeviceInstallPath::COMPAT_PLUGIN_PATH) {
304 1 : continue;
305 : }
306 2 : const std::string& pkgName = kv.first;
307 2 : const std::string& hostFile = kv.second.hostTruePath;
308 2 : PluginPkgVersion info;
309 2 : if (hostFile.empty()) {
310 1 : TSD_RUN_INFO("host plugin pkg:%s has empty host path, skip parse ini", pkgName.c_str());
311 1 : std::lock_guard<std::mutex> lock(hostPluginVersionMut_);
312 1 : hostPluginVersions_[pkgName] = info;
313 1 : continue;
314 1 : }
315 : // .ini 与 .tar.gz 同名同路径
316 1 : std::string iniPath = hostFile;
317 1 : const std::string suffix = ".tar.gz";
318 2 : if ((iniPath.size() > suffix.size()) &&
319 1 : (iniPath.compare(iniPath.size() - suffix.size(), suffix.size(), suffix) == 0)) {
320 1 : iniPath = iniPath.substr(0U, iniPath.size() - suffix.size()) + ".ini";
321 : } else {
322 0 : iniPath += ".ini";
323 : }
324 1 : if (!PluginPkgVersionUtil::ParseIniFile(iniPath, info)) {
325 1 : TSD_RUN_WARN(
326 : "parse plugin pkg:%s ini file:%s failed, fallback to checkcode compare", pkgName.c_str(),
327 : iniPath.c_str());
328 : } else {
329 0 : TSD_RUN_INFO(
330 : "host plugin pkg:%s ini parsed, version:%s timestamp:%s", pkgName.c_str(), info.version.c_str(),
331 : info.timestamp.c_str());
332 : }
333 1 : std::lock_guard<std::mutex> lock(hostPluginVersionMut_);
334 1 : hostPluginVersions_[pkgName] = info;
335 2 : }
336 1 : }
337 :
338 9 : PluginPkgVersion PackageProcessConfig::GetHostPluginVersion(const std::string& pkgName)
339 : {
340 9 : std::lock_guard<std::mutex> lock(hostPluginVersionMut_);
341 9 : const auto it = hostPluginVersions_.find(pkgName);
342 9 : if (it == hostPluginVersions_.end()) {
343 3 : return PluginPkgVersion{};
344 : }
345 6 : return it->second;
346 9 : }
347 :
348 0 : bool PackageProcessConfig::HasCompatPluginPackage() const
349 : {
350 0 : for (const auto& kv : configMap_) {
351 0 : if (kv.second.decDstDir == DeviceInstallPath::COMPAT_PLUGIN_PATH) {
352 0 : return true;
353 : }
354 : }
355 0 : return false;
356 : }
357 :
358 0 : bool PackageProcessConfig::IsNeedToUpdateConfig(const HDCMessage& hdcMsg) const
359 : {
360 0 : return (hdcMsg.package_config_hash_code() == hashCode_);
361 : }
362 :
363 2 : bool PackageProcessConfig::IsConfigPackageInfo(const std::string& oriPkgName)
364 : {
365 2 : const size_t pos = oriPkgName.find("_");
366 2 : if ((pos == std::string::npos) || (pos == oriPkgName.size() - 1)) {
367 2 : return false;
368 : }
369 0 : const std::string tempName = oriPkgName.substr(pos + 1);
370 0 : const std::lock_guard<std::mutex> lk(configMut_);
371 0 : auto iter = configMap_.find(tempName);
372 0 : if (iter != configMap_.end()) {
373 0 : return true;
374 : } else {
375 0 : return false;
376 : }
377 0 : }
378 :
379 30 : TSD_StatusT PackageProcessConfig::GetPkgHostAndDeviceDstPath(
380 : const std::string& pkgName, std::string& orgFile, std::string& dstFile, const pid_t hostPid)
381 : {
382 30 : const PackConfDetail detailInfo = GetConfigDetailInfo(pkgName);
383 30 : orgFile = detailInfo.hostTruePath;
384 :
385 30 : if (orgFile.empty()) {
386 15 : if (!detailInfo.optionalFlag) {
387 0 : TSD_ERROR("cannot find package:%s", pkgName.c_str());
388 0 : return TSD_INTERNAL_ERROR;
389 : } else {
390 15 : TSD_INFO("cannot find package:%s", pkgName.c_str());
391 15 : return TSD_OK;
392 : }
393 : }
394 :
395 15 : dstFile = dstFile + "/" + std::to_string(hostPid) + "_" + pkgName;
396 15 : TSD_RUN_INFO("get orgFile:%s, dstFile:%s", orgFile.c_str(), dstFile.c_str());
397 15 : return TSD_OK;
398 30 : }
399 :
400 15 : bool PackageProcessConfig::SetPkgHostTruePath(
401 : PackConfDetail& tempNode, const std::string& pkgName, const std::string& pkgTitle) const
402 : {
403 15 : const auto pos = pkgTitle.find(';');
404 15 : std::string packageTitle;
405 15 : std::string shortSocVersion;
406 15 : if (pos == std::string::npos) {
407 2 : packageTitle = pkgTitle;
408 : } else {
409 13 : packageTitle = pkgTitle.substr(0, pos);
410 13 : shortSocVersion = pkgTitle.substr(pos + 1UL);
411 : }
412 15 : std::string fileDirWholePath;
413 15 : if (pkgName.find("-aicpu_legacy.tar.gz") != std::string::npos) {
414 4 : fileDirWholePath = tempNode.findPath + "/" + packageTitle + "/aicpu/";
415 : } else {
416 11 : fileDirWholePath = tempNode.findPath + "/";
417 : }
418 15 : if (tempNode.loadAsPerSocFlag) {
419 3 : if (shortSocVersion.empty()) {
420 2 : TSD_ERROR("short_soc_version is empty, package:%s", pkgName.c_str());
421 2 : return false;
422 : } else {
423 1 : fileDirWholePath = fileDirWholePath + shortSocVersion + "/";
424 : }
425 : }
426 13 : tempNode.hostTruePath = GetHostFilePath(fileDirWholePath, pkgName);
427 13 : TSD_INFO("get package:%s host real path:%s", pkgName.c_str(), tempNode.hostTruePath.c_str());
428 13 : return true;
429 15 : }
430 :
431 0 : std::string PackageProcessConfig::GetPackageHostTruePath(const std::string& pkgName)
432 : {
433 0 : const std::lock_guard<std::mutex> lk(configMut_);
434 0 : auto iter = configMap_.find(pkgName);
435 0 : if (iter != configMap_.end()) {
436 0 : return iter->second.hostTruePath;
437 : } else {
438 0 : return "";
439 : }
440 0 : }
441 : } // namespace tsd
|