/** * Tencent is pleased to support the open source community by making Tars available. * * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * 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. */ #ifndef __PATCH_COMMAND_H_ #define __PATCH_COMMAND_H_ #include "SingleFileDownloader.h" #include "tars_patch.h" #include "NodeDescriptor.h" #include "RegistryProxy.h" #include "util/tc_file.h" #include "util/tc_md5.h" #include "ServerCommand.h" #include "NodeRollLogger.h" #include "util.h" class CommandPatch : public ServerCommand { public: CommandPatch(const ServerObjectPtr & server, const std::string & sDownloadPath, const tars::PatchRequest & request); ExeStatus canExecute(std::string &sResult); int execute(std::string &sResult); int updatePatchResult(std::string &sResult); int download(const std::string & sRemoteTgzPath, const std::string & sLocalTgzPath, const std::string & sShortFileName, const std::string& reqMd5, std::string & sResult); static string getOsType(); //是否检查操作系统类型 static bool checkOsType(); private: int backupfiles(std::string &sResult); private: ServerObjectPtr _serverObjectPtr; tars::PatchRequest _patchRequest; //本地存放tgz的目录 std::string _localTgzBasePath; //本地解压的文件目录 std::string _localExtractBasePath; StatExChangePtr _statExChange; }; class PatchDownloadEvent : public DownloadEvent { public: PatchDownloadEvent(ServerObjectPtr pServerObjectPtr) : _serverObjectPtr(pServerObjectPtr) {} virtual void onDownloading(const FileInfo &fi, int pos) { if (_serverObjectPtr && fi.size > 0) { _serverObjectPtr->setPatchPercent((int)(pos*100.0/fi.size)); } } private: ServerObjectPtr _serverObjectPtr; }; ////////////////////////////////////////////////////////////// // inline CommandPatch::CommandPatch(const ServerObjectPtr & server, const std::string & sDownloadPath, const tars::PatchRequest & request) : _serverObjectPtr(server), _patchRequest(request) { _localTgzBasePath = sDownloadPath + "/BatchPatchingLoad"; _localExtractBasePath = sDownloadPath + "/BatchPatching"; } inline string CommandPatch::getOsType() { string defaultOs = g_pconf->get("/tars/node", "suse"); string ret = defaultOs; vector vKey = g_pconf->getDomainKey("/tars/node/os_pattern"); NODE_LOG("patchPro")->debug() << FILE_FUN<< vKey.size() << endl; for(size_t i = 0; i < vKey.size(); i++) { string key = vKey[i]; string paths = g_pconf->get("/tars/node/os_pattern<" + key + ">", ""); NODE_LOG("patchPro")->debug() < vPath = TC_Common::sepstr(paths,":"); vector::iterator it = vPath.begin(); for(; it != vPath.end(); it ++) { string path = *it; if(TC_File::isFileExist(path)) { ret = key; NODE_LOG("patchPro")->debug() << FILE_FUN<< path << " is exist, ret:" << ret << endl; return ret; } else { NODE_LOG("patchPro")->debug() << FILE_FUN<< path << " not exist" << endl; } } } return ret; } inline bool CommandPatch::checkOsType() { string checkStr = g_pconf->get("/tars/node", "n"); if(checkStr == "Y" || checkStr == "y" || checkStr == "yes" || checkStr == "true") { return true; } else { return false; } } inline ServerCommand::ExeStatus CommandPatch::canExecute(string & sResult) { ServerObject::InternalServerState eState = _serverObjectPtr->getLastState(); ServerObject::InternalServerState eCurrentState =_serverObjectPtr->getInternalState(); NODE_LOG("patchPro")->debug()<< FILE_FUN <<_patchRequest.appname+"."+_patchRequest.servername<<"|sResult:"<toStringState(eCurrentState)<<"|last state :"<< _serverObjectPtr->toStringState(eState)<< endl; _statExChange = new StatExChange(_serverObjectPtr, ServerObject::BatchPatching, eState); _serverObjectPtr->setPatchVersion(_patchRequest.version); _serverObjectPtr->setPatchPercent(0); _serverObjectPtr->setPatchResult(""); return EXECUTABLE; } inline int CommandPatch::updatePatchResult(string & sResult) { try { NODE_LOG("patchPro")->debug() <getRegistryProxy(); if (!proxy) { sResult = "patch succ but update version and user fault, get registry proxy fail"; NODE_LOG("patchPro")->error() <updatePatchResult(patch); NODE_LOG("patchPro")->debug() <error() <error() <debug() <debug() <debug() <debug() <error() <stringToProxy(_patchRequest.patchobj); proxy->tars_timeout(60000); int downloadRet = SingleFileDownloader::download(proxy, sRemoteTgzFile, dtask.sLocalTgzFile, eventPtr, sResult); if(downloadRet != 0) { //返回码错开一下 iRet = downloadRet - 100; returned = true; } } catch (std::exception & ex) { sResult = "download from patch exception," + string(ex.what()); iRet = -3; NODE_LOG("patchPro")->error() <error() <debug() <error() <error() <error() <error() <error() < files; tars::TC_File::listDirectory(sLocalExtractPach, files, true); if(files.empty()) { sResult = cmd + ",error!"; NODE_LOG("patchPro")->error() <debug() << FILE_FUN << "unzip:" << cmd <debug() <error() << FILE_FUN << sResult << endl; iRet = -7; } } //对于tars_nodejs需要先删除exepath下的文件 if (iRet == 0) { if (_serverObjectPtr->getServerType() == "tars_nodejs") { if(TC_File::removeFile(_serverObjectPtr->getExePath(),true) != 0 || !TC_File::makeDirRecursive(_serverObjectPtr->getExePath())) { iRet = -8; //iRetCode = EM_ITEM_PERMISSION; NODE_LOG("patchPro")->error() <getExePath()<<"|"<getServerType() == "tars_nodejs") { TC_File::copyFile(sLocalExtractPach + "/" + sServerName+ "/" + sServerName, _serverObjectPtr->getExePath(), true); } else { //如果出错,这里会抛异常 TC_File::copyFile(sLocalExtractPach + "/" + sServerName, _serverObjectPtr->getExePath(), true); } //设置发布状态到主控 iRet = updatePatchResult(sResult); if(0 != iRet) { NODE_LOG("patchPro")->error() <debug() <debug() <error() <error() <setPatchResult(sResult, iRet == 0); //设置发布结果,如果是发布异常了这里也设置,主要是设置进度为100%,方便前端判断 _serverObjectPtr->setPatched(true); //发布后,core频率限制重新计算 _serverObjectPtr->resetCoreInfo(); g_app.reportServer(_patchRequest.appname + "." + _patchRequest.servername, sResult); return iRet; } inline int CommandPatch::backupfiles(std::string &sResult) { try { if (_serverObjectPtr->getServerType() == "tars_java") //如果是java服务的话需要清空目录,备份目录 { int maxbaknum = 5; string srcPath = "/usr/local/app/tars/tarsnode/data/" + _patchRequest.appname + "." + _patchRequest.servername + "/"; string destPath = "/usr/local/app/tars/tarsnode/tmp/" + _patchRequest.appname + "." + _patchRequest.servername + "/"; if (!TC_File::isFileExistEx(srcPath, S_IFDIR)) //不存在这个目录,先创建 { NODE_LOG("patchPro")->debug() <= 1; i--) { string destPathBak = + "bin_bak" + TC_Common::tostr(i) + "/"; if(!TC_File::isFileExistEx(destPathBak,S_IFDIR)) //不存在这个目录,可以继续循环 { NODE_LOG("patchPro")->debug() <bak2 { string newFile = destPath + "bin_bak" + TC_Common::tostr(i+1) + "/"; if(TC_File::isFileExistEx(newFile,S_IFDIR) && TC_File::removeFile(newFile, true) != 0) { NODE_LOG("patchPro")->error() <debug() <debug() <error() <debug() <debug() <debug() <debug() < vFileNames = TC_Common::sepstr(_serverObjectPtr->getBackupFileNames(), ";|"); for(vector::size_type i = 0;i< vFileNames.size();i++) { string sBackupSrc = destPathBak + vFileNames[i]; string sBackupDest = existFile + vFileNames[i]; if (TC_File::isFileExistEx(sBackupSrc,S_IFDIR)) { if (!TC_File::isFileExistEx(sBackupDest,S_IFDIR)) { if(!TC_File::makeDirRecursive(TC_File::simplifyDirectory(sBackupDest))) { NODE_LOG("patchPro")->error() <debug() <error() <error() <