core/go_pipeline/LogtailPlugin.cpp (561 lines of code) (raw):
// Copyright 2022 iLogtail Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "go_pipeline/LogtailPlugin.h"
#include "json/json.h"
#include "app_config/AppConfig.h"
#include "collection_pipeline/CollectionPipelineManager.h"
#include "collection_pipeline/queue/SenderQueueManager.h"
#include "common/CrashBackTraceUtil.h"
#include "common/DynamicLibHelper.h"
#include "common/HashUtil.h"
#include "common/JsonUtil.h"
#include "common/LogtailCommonFlags.h"
#include "common/TimeUtil.h"
#include "common/compression/CompressorFactory.h"
#include "container_manager/ConfigContainerInfoUpdateCmd.h"
#include "file_server/ConfigManager.h"
#include "logger/Logger.h"
#include "monitor/AlarmManager.h"
#include "monitor/Monitor.h"
#include "provider/Provider.h"
#ifdef APSARA_UNIT_TEST_MAIN
#include "unittest/pipeline/LogtailPluginMock.h"
#endif
DEFINE_FLAG_BOOL(enable_sls_metrics_format, "if enable format metrics in SLS metricstore log pattern", true);
DECLARE_FLAG_STRING(ALIYUN_LOG_FILE_TAGS);
DECLARE_FLAG_INT32(file_tags_update_interval);
DECLARE_FLAG_STRING(agent_host_id);
DECLARE_FLAG_BOOL(ilogtail_disable_core);
using namespace std;
using namespace logtail;
LogtailPlugin* LogtailPlugin::s_instance = NULL;
LogtailPlugin::LogtailPlugin() {
mPluginAdapterPtr = NULL;
mPluginBasePtr = NULL;
mLoadPipelineFun = NULL;
mUnloadPipelineFun = NULL;
mStopAllPipelinesFun = NULL;
mStopFun = NULL;
mStartFun = NULL;
mLoadGlobalConfigFun = NULL;
mPluginValid = false;
mPluginAlarmConfig.mLogstore = "logtail_alarm";
mPluginAlarmConfig.mAliuid = STRING_FLAG(logtail_profile_aliuid);
mPluginAlarmConfig.mCompressor = CompressorFactory::GetInstance()->Create(CompressType::ZSTD);
mPluginContainerConfig.mLogstore = "logtail_containers";
mPluginContainerConfig.mAliuid = STRING_FLAG(logtail_profile_aliuid);
mPluginContainerConfig.mCompressor = CompressorFactory::GetInstance()->Create(CompressType::ZSTD);
mPluginCfg["LoongCollectorConfDir"] = AppConfig::GetInstance()->GetLoongcollectorConfDir();
mPluginCfg["LoongCollectorLogDir"] = GetAgentLogDir();
mPluginCfg["LoongCollectorDataDir"] = GetAgentDataDir();
mPluginCfg["LoongCollectorLogConfDir"] = GetAgentGoLogConfDir();
mPluginCfg["LoongCollectorPluginLogName"] = GetPluginLogName();
mPluginCfg["LoongCollectorVersionTag"] = GetVersionTag();
mPluginCfg["LoongCollectorGoCheckPointDir"] = GetAgentGoCheckpointDir();
mPluginCfg["LoongCollectorGoCheckPointFile"] = GetGoPluginCheckpoint();
mPluginCfg["LoongCollectorThirdPartyDir"] = GetAgentThirdPartyDir();
mPluginCfg["LoongCollectorPrometheusAuthorizationPath"] = GetAgentPrometheusAuthorizationPath();
mPluginCfg["HostIP"] = LoongCollectorMonitor::mIpAddr;
mPluginCfg["Hostname"] = LoongCollectorMonitor::mHostname;
mPluginCfg["EnableSlsMetricsFormat"] = BOOL_FLAG(enable_sls_metrics_format);
}
LogtailPlugin::~LogtailPlugin() {
DynamicLibLoader::CloseLib(mPluginBasePtr);
DynamicLibLoader::CloseLib(mPluginAdapterPtr);
}
bool LogtailPlugin::LoadPipeline(const std::string& pipelineName,
const std::string& pipeline,
const std::string& project,
const std::string& logstore,
const std::string& region,
logtail::QueueKey logstoreKey) {
#ifndef APSARA_UNIT_TEST_MAIN
if (!mPluginValid) {
LoadPluginBase();
}
if (mPluginValid && mLoadPipelineFun != NULL) {
GoString goProject;
GoString goLogstore;
GoString goConfigName;
GoString goPluginConfig;
goConfigName.n = pipelineName.size();
goConfigName.p = pipelineName.c_str();
goPluginConfig.n = pipeline.size();
goPluginConfig.p = pipeline.c_str();
goProject.n = project.size();
goProject.p = project.c_str();
goLogstore.n = logstore.size();
goLogstore.p = logstore.c_str();
long long goLogStoreKey = static_cast<long long>(logstoreKey);
return mLoadPipelineFun(goProject, goLogstore, goConfigName, goLogStoreKey, goPluginConfig) == 0;
}
return false;
#else
return LogtailPluginMock::GetInstance()->LoadPipeline(
pipelineName, pipeline, project, logstore, region, logstoreKey);
#endif
}
bool LogtailPlugin::UnloadPipeline(const std::string& pipelineName) {
#ifndef APSARA_UNIT_TEST_MAIN
if (!mPluginValid) {
LOG_ERROR(sLogger, ("UnloadPipeline", "plugin not valid"));
return false;
}
if (mPluginValid && mUnloadPipelineFun != NULL) {
GoString goConfigName;
goConfigName.n = pipelineName.size();
goConfigName.p = pipelineName.c_str();
return mUnloadPipelineFun(goConfigName) == 0;
}
return false;
#else
return LogtailPluginMock::GetInstance()->UnloadPipeline(pipelineName);
#endif
}
void LogtailPlugin::StopAllPipelines(bool withInputFlag) {
#ifndef APSARA_UNIT_TEST_MAIN
if (mPluginValid && mStopAllPipelinesFun != NULL) {
LOG_INFO(sLogger, ("Go pipelines stop all", "starts"));
auto stopAllStart = GetCurrentTimeInMilliSeconds();
mStopAllPipelinesFun(withInputFlag ? 1 : 0);
auto stopAllCost = GetCurrentTimeInMilliSeconds() - stopAllStart;
LOG_INFO(sLogger, ("Go pipelines stop all", "succeeded")("cost", ToString(stopAllCost) + "ms"));
if (stopAllCost >= 10 * 1000) {
AlarmManager::GetInstance()->SendAlarm(HOLD_ON_TOO_SLOW_ALARM,
"Stopping all Go pipelines took " + ToString(stopAllCost) + "ms");
}
}
#else
LogtailPluginMock::GetInstance()->StopAllPipelines(withInputFlag);
#endif
}
void LogtailPlugin::Stop(const std::string& configName, bool removedFlag) {
#ifndef APSARA_UNIT_TEST_MAIN
if (mPluginValid && mStopFun != NULL) {
LOG_INFO(sLogger, ("Go pipelines stop", "starts")("config", configName));
auto stopStart = GetCurrentTimeInMilliSeconds();
GoString goConfigName;
goConfigName.n = configName.size();
goConfigName.p = configName.c_str();
mStopFun(goConfigName, removedFlag ? 1 : 0);
auto stopCost = GetCurrentTimeInMilliSeconds() - stopStart;
LOG_INFO(sLogger, ("Go pipelines stop", "succeeded")("config", configName)("cost", ToString(stopCost) + "ms"));
if (stopCost >= 10 * 1000) {
AlarmManager::GetInstance()->SendAlarm(
HOLD_ON_TOO_SLOW_ALARM, "Stopping Go pipeline " + configName + " took " + ToString(stopCost) + "ms");
}
}
#else
LogtailPluginMock::GetInstance()->Stop(configName, removedFlag);
#endif
}
void LogtailPlugin::StopBuiltInModules() {
if (mPluginValid && mStopFun != NULL) {
LOG_INFO(sLogger, ("Go pipelines stop built-in", "starts"));
mStopBuiltInModulesFun();
LOG_INFO(sLogger, ("Go pipelines stop built-in", "succeeded"));
}
}
void LogtailPlugin::Start(const std::string& configName) {
#ifndef APSARA_UNIT_TEST_MAIN
if (mPluginValid && mStartFun != NULL) {
LOG_INFO(sLogger, ("Go pipelines start", "starts")("config name", configName));
GoString goConfigName;
goConfigName.n = configName.size();
goConfigName.p = configName.c_str();
mStartFun(goConfigName);
LOG_INFO(sLogger, ("Go pipelines start", "succeeded")("config name", configName));
}
#else
LogtailPluginMock::GetInstance()->Start(configName);
#endif
}
int LogtailPlugin::IsValidToSend(long long logstoreKey) {
// TODO: because go profile pipeline is not controlled by C++, we cannot know queue key in advance
// therefore, we assume true here. This could be a potential problem if network is not available for profile info.
// However, since go profile pipeline will be stopped only during process exit, it should be fine.
if (logstoreKey == -1) {
return 0;
}
return SenderQueueManager::GetInstance()->IsValidToPush(logstoreKey) ? 0 : -1;
}
int LogtailPlugin::SendPb(const char* configName,
int32_t configNameSize,
const char* logstoreName,
int logstoreSize,
char* pbBuffer,
int32_t pbSize,
int32_t lines) {
return SendPbV2(configName, configNameSize, logstoreName, logstoreSize, pbBuffer, pbSize, lines, NULL, 0);
}
int LogtailPlugin::SendPbV2(const char* configName,
int32_t configNameSize,
const char* logstoreName,
int logstoreSize,
char* pbBuffer,
int32_t pbSize,
int32_t lines,
const char* shardHash,
int shardHashSize) {
static FlusherSLS* alarmConfig = &(LogtailPlugin::GetInstance()->mPluginAlarmConfig);
static FlusherSLS* containerConfig = &(LogtailPlugin::GetInstance()->mPluginContainerConfig);
string configNameStr = string(configName, configNameSize);
string logstore;
if (logstoreSize > 0 && logstoreName != NULL) {
logstore.assign(logstoreName, (size_t)logstoreSize);
}
// LOG_DEBUG(sLogger, ("send pb", configNameStr)("pb size", pbSize)("lines", lines));
FlusherSLS* pConfig = NULL;
if (configNameStr == alarmConfig->mLogstore) {
pConfig = alarmConfig;
pConfig->mProject = GetProfileSender()->GetDefaultProfileProjectName();
pConfig->mRegion = GetProfileSender()->GetDefaultProfileRegion();
if (pConfig->mProject.empty()) {
return 0;
}
} else if (configNameStr == containerConfig->mLogstore) {
pConfig = containerConfig;
pConfig->mProject = GetProfileSender()->GetDefaultProfileProjectName();
pConfig->mRegion = GetProfileSender()->GetDefaultProfileRegion();
if (pConfig->mProject.empty()) {
return 0;
}
} else {
shared_ptr<CollectionPipeline> p = CollectionPipelineManager::GetInstance()->FindConfigByName(configNameStr);
if (!p) {
LOG_INFO(sLogger,
("error", "SendPbV2 can not find config, maybe config updated")("config", configNameStr)(
"logstore", logstore));
return -2;
}
// TODO: support multi-flusher
pConfig = const_cast<FlusherSLS*>(static_cast<const FlusherSLS*>(p->GetFlushers()[0]->GetPlugin()));
}
std::string shardHashStr;
if (shardHashSize > 0) {
shardHashStr.assign(shardHash, static_cast<size_t>(shardHashSize));
}
return pConfig->Send(std::string(pbBuffer, pbSize), shardHashStr, logstore) ? 0 : -1;
}
int LogtailPlugin::ExecPluginCmd(
const char* configName, int configNameSize, int cmdId, const char* params, int paramsLen) {
if (cmdId < (int)PLUGIN_CMD_MIN || cmdId > (int)PLUGIN_CMD_MAX) {
LOG_ERROR(sLogger, ("invalid cmd", cmdId));
return -2;
}
string configNameStr(configName, configNameSize);
string paramsStr(params, paramsLen);
PluginCmdType cmdType = (PluginCmdType)cmdId;
LOG_DEBUG(sLogger, ("exec cmd", cmdType)("config", configNameStr)("detail", paramsStr));
// cmd 解析json
Json::Value jsonParams;
std::string errorMsg;
if (paramsStr.size() < 5UL || !ParseJsonTable(paramsStr, jsonParams, errorMsg)) {
LOG_ERROR(sLogger, ("invalid docker container params", paramsStr)("errorMsg", errorMsg));
return -2;
}
switch (cmdType) {
case PLUGIN_DOCKER_UPDATE_FILE: {
ConfigContainerInfoUpdateCmd* cmd = new ConfigContainerInfoUpdateCmd(configNameStr, false, jsonParams);
ConfigManager::GetInstance()->UpdateContainerPath(cmd);
} break;
case PLUGIN_DOCKER_STOP_FILE: {
ConfigContainerInfoUpdateCmd* cmd = new ConfigContainerInfoUpdateCmd(configNameStr, true, jsonParams);
ConfigManager::GetInstance()->UpdateContainerStopped(cmd);
} break;
case PLUGIN_DOCKER_REMOVE_FILE: {
ConfigContainerInfoUpdateCmd* cmd = new ConfigContainerInfoUpdateCmd(configNameStr, true, jsonParams);
ConfigManager::GetInstance()->UpdateContainerPath(cmd);
} break;
case PLUGIN_DOCKER_UPDATE_FILE_ALL: {
ConfigContainerInfoUpdateCmd* cmd = new ConfigContainerInfoUpdateCmd(configNameStr, false, jsonParams);
ConfigManager::GetInstance()->UpdateContainerPath(cmd);
} break;
default:
LOG_ERROR(sLogger, ("unknown cmd", cmdType));
break;
}
return 0;
}
bool LogtailPlugin::LoadPluginBase() {
if (mPluginValid) {
return true;
}
// load plugin adapter
if (mPluginAdapterPtr == NULL) {
DynamicLibLoader loader;
std::string error;
// load plugin adapter
if (!loader.LoadDynLib("GoPluginAdapter", error, AppConfig::GetInstance()->GetWorkingDir())) {
LOG_ERROR(sLogger, ("open adapter lib error, Message", error));
return mPluginValid;
}
auto versionFun = (PluginAdapterVersion)loader.LoadMethod("PluginAdapterVersion", error);
if (!error.empty()) {
LOG_ERROR(sLogger, ("load version function error, Message", error));
return mPluginValid;
}
int version = versionFun();
if (!(version / 100 == 2 || version / 100 == 3)) {
LOG_ERROR(sLogger, ("invalid plugin adapter version, version", version));
return mPluginValid;
}
LOG_INFO(sLogger, ("valid plugin adapter version, version", version));
// Be compatible with old libGoPluginAdapter.so, V2 -> V1.
auto registerV2Fun = (RegisterLogtailCallBackV2)loader.LoadMethod("RegisterLogtailCallBackV2", error);
if (error.empty()) {
registerV2Fun(LogtailPlugin::IsValidToSend,
LogtailPlugin::SendPb,
LogtailPlugin::SendPbV2,
LogtailPlugin::ExecPluginCmd);
} else {
LOG_WARNING(sLogger, ("load RegisterLogtailCallBackV2 failed", error)("try to load V1", ""));
auto registerFun = (RegisterLogtailCallBack)loader.LoadMethod("RegisterLogtailCallBack", error);
if (!error.empty()) {
LOG_WARNING(sLogger, ("load RegisterLogtailCallBack failed", error));
return mPluginValid;
}
registerFun(LogtailPlugin::IsValidToSend, LogtailPlugin::SendPb, LogtailPlugin::ExecPluginCmd);
}
mPluginAdapterPtr = loader.Release();
}
InitPluginBaseFun initBase = NULL;
InitPluginBaseV2Fun initBaseV2 = NULL;
// load plugin base
if (mPluginBasePtr == NULL) {
DynamicLibLoader loader;
std::string error;
// load plugin base
if (!loader.LoadDynLib("GoPluginBase", error, AppConfig::GetInstance()->GetWorkingDir())) {
LOG_ERROR(sLogger, ("open plugin base dl error, Message", error));
return mPluginValid;
}
// Try V2 -> V1.
initBaseV2 = (InitPluginBaseV2Fun)loader.LoadMethod("InitPluginBaseV2", error);
if (!error.empty()) {
LOG_WARNING(sLogger, ("load InitPluginBaseFunV2 error", error)("try to load V1", ""));
initBase = (InitPluginBaseFun)loader.LoadMethod("InitPluginBase", error);
if (!error.empty()) {
LOG_ERROR(sLogger, ("load InitPluginBase error", error));
return mPluginValid;
}
}
// 加载全局配置,目前应该没有调用点
mLoadGlobalConfigFun = (LoadGlobalConfigFun)loader.LoadMethod("LoadGlobalConfig", error);
if (!error.empty()) {
LOG_ERROR(sLogger, ("load LoadGlobalConfig error, Message", error));
return mPluginValid;
}
// 加载单个配置
mLoadPipelineFun = (LoadPipelineFun)loader.LoadMethod("LoadPipeline", error);
if (!error.empty()) {
LOG_ERROR(sLogger, ("load LoadPipelineFun error, Message", error));
return mPluginValid;
}
// 卸载单个配置
mUnloadPipelineFun = (UnloadPipelineFun)loader.LoadMethod("UnloadPipeline", error);
if (!error.empty()) {
LOG_ERROR(sLogger, ("load UnloadPipelineFun error, Message", error));
return mPluginValid;
}
// 停止所有插件
mStopAllPipelinesFun = (StopAllPipelinesFun)loader.LoadMethod("StopAllPipelines", error);
if (!error.empty()) {
LOG_ERROR(sLogger, ("load StopAllPipelines error, Message", error));
return mPluginValid;
}
// 停止单个插件
mStopFun = (StopFun)loader.LoadMethod("Stop", error);
if (!error.empty()) {
LOG_ERROR(sLogger, ("load Stop error, Message", error));
return mPluginValid;
}
// 停止内置功能
mStopBuiltInModulesFun = (StopBuiltInModulesFun)loader.LoadMethod("StopBuiltInModules", error);
if (!error.empty()) {
LOG_ERROR(sLogger, ("load StopBuiltInModules error, Message", error));
return mPluginValid;
}
// 插件恢复
mStartFun = (StartFun)loader.LoadMethod("Start", error);
if (!error.empty()) {
LOG_ERROR(sLogger, ("load Start error, Message", error));
return mPluginValid;
}
// C++获取容器信息的
mGetContainerMetaFun = (GetContainerMetaFun)loader.LoadMethod("GetContainerMeta", error);
if (!error.empty()) {
LOG_ERROR(sLogger, ("load GetContainerMeta error, Message", error));
return mPluginValid;
}
// C++传递单条数据到golang插件
mProcessLogsFun = (ProcessLogsFun)loader.LoadMethod("ProcessLog", error);
if (!error.empty()) {
LOG_ERROR(sLogger, ("load ProcessLogs error, Message", error));
return mPluginValid;
}
// C++传递数据到golang插件
mProcessLogGroupFun = (ProcessLogGroupFun)loader.LoadMethod("ProcessLogGroup", error);
if (!error.empty()) {
LOG_ERROR(sLogger, ("load ProcessLogGroup error, Message", error));
return mPluginValid;
}
// 获取golang部分指标信息
mGetGoMetricsFun = (GetGoMetricsFun)loader.LoadMethod("GetGoMetrics", error);
if (!error.empty()) {
LOG_ERROR(sLogger, ("load GetGoMetrics error, Message", error));
return mPluginValid;
}
mPluginBasePtr = loader.Release();
}
GoInt initRst = 0;
if (initBaseV2) {
std::string cfgStr = mPluginCfg.toStyledString();
GoString goCfgStr;
goCfgStr.p = cfgStr.c_str();
goCfgStr.n = cfgStr.length();
initRst = initBaseV2(goCfgStr);
} else {
initRst = initBase();
}
if (initRst != 0) {
LOG_ERROR(sLogger, ("Go plugin system init", "failed")("res", initRst));
mPluginValid = false;
} else {
LOG_INFO(sLogger, ("Go plugin system init", "succeeded"));
mPluginValid = true;
#ifdef __ENTERPRISE__
if (BOOL_FLAG(ilogtail_disable_core)) {
ResetCrashBackTrace();
}
#endif
}
return mPluginValid;
}
void LogtailPlugin::ProcessLog(const std::string& configName,
sls_logs::Log& log,
const std::string& packId,
const std::string& topic,
const std::string& tags) {
if (!log.has_time() || !(mPluginValid && mProcessLogsFun != NULL)) {
return;
}
std::string packIdPrefix = ToHexString(HashString(packId));
std::string realConfigName = configName + "/2";
GoString goConfigName;
GoSlice goLog;
GoString goPackId;
GoString goTopic;
GoSlice goTags;
goConfigName.n = realConfigName.size();
goConfigName.p = realConfigName.c_str();
goPackId.n = packIdPrefix.size();
goPackId.p = packIdPrefix.c_str();
goTopic.n = topic.size();
goTopic.p = topic.c_str();
goTags.data = (void*)tags.c_str();
goTags.len = goTags.cap = tags.length();
std::string sLog = log.SerializeAsString();
goLog.len = goLog.cap = sLog.length();
goLog.data = (void*)sLog.c_str();
GoInt rst = mProcessLogsFun(goConfigName, goLog, goPackId, goTopic, goTags);
if (rst != (GoInt)0) {
LOG_WARNING(sLogger, ("process log error", configName)("result", rst));
}
}
void LogtailPlugin::ProcessLogGroup(const std::string& configName,
const std::string& logGroup,
const std::string& packId) {
#ifndef APSARA_UNIT_TEST_MAIN
if (logGroup.empty() || !(mPluginValid && mProcessLogsFun != NULL)) {
return;
}
std::string realConfigName = configName + "/2";
std::string packIdPrefix = ToHexString(HashString(packId));
GoString goConfigName;
GoSlice goLog;
GoString goPackId;
goConfigName.n = realConfigName.size();
goConfigName.p = realConfigName.c_str();
goPackId.n = packIdPrefix.size();
goPackId.p = packIdPrefix.c_str();
goLog.len = goLog.cap = logGroup.length();
goLog.data = (void*)logGroup.c_str();
GoInt rst = mProcessLogGroupFun(goConfigName, goLog, goPackId);
if (rst != (GoInt)0) {
LOG_WARNING(sLogger, ("process loggroup error", configName)("result", rst));
}
#else
LogtailPluginMock::GetInstance()->ProcessLogGroup(configName, logGroup, packId);
#endif
}
void LogtailPlugin::GetGoMetrics(std::vector<std::map<std::string, std::string>>& metircsList,
const string& metricType) {
if (mGetGoMetricsFun != nullptr) {
GoString type;
type.n = metricType.size();
type.p = metricType.c_str();
auto metrics = mGetGoMetricsFun(type);
if (metrics != nullptr) {
for (int i = 0; i < metrics->count; ++i) {
std::map<std::string, std::string> item;
InnerPluginMetric* innerpm = metrics->metrics[i];
if (innerpm != nullptr) {
for (int j = 0; j < innerpm->count; ++j) {
InnerKeyValue* innerkv = innerpm->keyValues[j];
if (innerkv != nullptr) {
item.insert(std::make_pair(std::string(innerkv->key), std::string(innerkv->value)));
free(innerkv->key);
free(innerkv->value);
free(innerkv);
}
}
free(innerpm->keyValues);
free(innerpm);
}
metircsList.emplace_back(item);
}
free(metrics->metrics);
free(metrics);
}
}
}
K8sContainerMeta LogtailPlugin::GetContainerMeta(const string& containerID) {
if (mPluginValid && mGetContainerMetaFun != nullptr) {
GoString id;
id.n = containerID.size();
id.p = containerID.c_str();
auto innerMeta = mGetContainerMetaFun(id);
if (innerMeta != NULL) {
K8sContainerMeta meta;
meta.ContainerName.assign(innerMeta->containerName);
meta.Image.assign(innerMeta->image);
meta.K8sNamespace.assign(innerMeta->k8sNamespace);
meta.PodName.assign(innerMeta->podName);
for (int i = 0; i < innerMeta->containerLabelsSize; ++i) {
std::string key, value;
key.assign(innerMeta->containerLabelsKey[i]);
value.assign(innerMeta->containerLabelsVal[i]);
meta.containerLabels.insert(std::make_pair(std::move(key), std::move(key)));
}
for (int i = 0; i < innerMeta->k8sLabelsSize; ++i) {
std::string key, value;
key.assign(innerMeta->k8sLabelsKey[i]);
value.assign(innerMeta->k8sLabelsVal[i]);
meta.k8sLabels.insert(std::make_pair(std::move(key), std::move(key)));
}
for (int i = 0; i < innerMeta->envSize; ++i) {
std::string key, value;
key.assign(innerMeta->envsKey[i]);
value.assign(innerMeta->envsVal[i]);
meta.envs.insert(std::make_pair(std::move(key), std::move(key)));
}
free(innerMeta->containerName);
free(innerMeta->image);
free(innerMeta->k8sNamespace);
free(innerMeta->podName);
if (innerMeta->containerLabelsSize > 0) {
for (int i = 0; i < innerMeta->containerLabelsSize; ++i) {
free(innerMeta->containerLabelsKey[i]);
free(innerMeta->containerLabelsVal[i]);
}
free(innerMeta->containerLabelsKey);
free(innerMeta->containerLabelsVal);
}
if (innerMeta->k8sLabelsSize > 0) {
for (int i = 0; i < innerMeta->k8sLabelsSize; ++i) {
free(innerMeta->k8sLabelsKey[i]);
free(innerMeta->k8sLabelsVal[i]);
}
free(innerMeta->k8sLabelsKey);
free(innerMeta->k8sLabelsVal);
}
if (innerMeta->envSize > 0) {
for (int i = 0; i < innerMeta->envSize; ++i) {
free(innerMeta->envsKey[i]);
free(innerMeta->envsVal[i]);
}
free(innerMeta->envsKey);
free(innerMeta->envsVal);
}
free(innerMeta);
return meta;
}
}
return K8sContainerMeta();
}