/* * (c) Copyright Ascensio System SIA 2010-2023 * * This program is a free software product. You can redistribute it and/or * modify it under the terms of the GNU Affero General Public License (AGPL) * version 3 as published by the Free Software Foundation. In accordance with * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect * that Ascensio System SIA expressly excludes the warranty of non-infringement * of any third-party rights. * * This program is distributed WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html * * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish * street, Riga, Latvia, EU, LV-1050. * * The interactive user interfaces in modified source and object code versions * of the Program must display Appropriate Legal Notices, as required under * Section 5 of the GNU AGPL version 3. * * Pursuant to Section 7(b) of the License you must retain the original Product * logo when distributing the program. Pursuant to Section 7(e) we decline to * grant you any rights under trademark law for use of our trademarks. * * All the Product's GUI elements, including illustrations and icon sets, as * well as technical writing content are licensed under the terms of the * Creative Commons Attribution-ShareAlike 4.0 International. See the License * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode * */ #include #include #include #include #include #include "help.h" #include "../common/File.h" #include "../common/Directory.h" #include "../../DesktopEditor/common/StringBuilder.h" #include "../../DesktopEditor/common/SystemUtils.h" #include "../../DesktopEditor/graphics/BaseThread.h" #include "../../OfficeUtils/src/OfficeUtils.h" #include "../../Common/Network/FileTransporter/include/FileTransporter.h" #ifdef CreateDirectory #undef CreateDirectory #endif #ifdef GetTempPath #undef GetTempPath #endif #ifdef LINUX #include #include #endif // Misc std::wstring CorrectValue(const std::wstring& value) { if (value.empty()) return L""; const wchar_t* data = value.c_str(); std::wstring::size_type pos1 = (data[0] == '\"') ? 1 : 0; std::wstring::size_type pos2 = value.length(); if (data[pos2 - 1] == '\"') --pos2; return value.substr(pos1, pos2 - pos1); } bool SplitStringAsVector(const std::wstring& sData, const std::wstring& sDelimiter, std::vector& arrOutput) { arrOutput.clear(); if ( sData.length() ) { std::wstring sTmp = sData; NSStringUtils::string_replace(sTmp, L", ", L","); size_t pos_start = 0, pos_end, delim_len = sDelimiter.length(); std::wstring token = L""; while ((pos_end = sTmp.find(sDelimiter, pos_start)) != std::wstring::npos) { token = sTmp.substr(pos_start, pos_end - pos_start); pos_start = pos_end + delim_len; if (token.length()) arrOutput.push_back(token); } token = sTmp.substr(pos_start); if ( token.length() ) arrOutput.push_back(token); } return arrOutput.size() > 0; } // enum SystemType { Debian = 0, RedHat, Empty }; class CVm { public: std::wstring m_sName; std::wstring m_sGuid; // from showvminfo command std::wstring m_sGuestOS; // real OS std::wstring m_sOperationSystem; SystemType m_eType; CVm() { m_sName = L""; m_sGuid = L""; m_sGuestOS = L""; m_sOperationSystem = L""; m_eType = Empty; } CVm(const std::wstring& sName, const std::wstring& sGuid, const std::wstring& sGuestOS, const SystemType& eType) { m_sName = sName; m_sGuid = sGuid; m_sGuestOS = sGuestOS; m_sOperationSystem = L""; m_eType = eType; } bool IsDebian() { return m_eType == Debian; } bool IsRedHat() { return m_eType == RedHat; } std::wstring ToString() { std::wstringstream sInfo; if ( m_sName.length() && m_sGuid.length() && m_sGuestOS.length() ) sInfo << m_sName << L"-" << m_sGuestOS << L"-" << m_sGuid; return sInfo.str(); } }; class CVirtualBox { private: std::wstring m_sVbmPath; std::wstring m_sVmUser; std::wstring m_sVmPassword; std::wstring m_sBranch; std::wstring m_sVersion; std::wstring m_sDebianUrl; std::wstring m_sCentosUrl; std::wstring m_sOpSuseUrl; std::wstring m_sEditorsPath; std::wstring m_sSuccessOutput; std::wstring m_sConfigName; std::wstring m_sReportName; std::wstring m_sStdoutFile; std::wstring m_sRunScript; std::wstring m_sSetupScript; std::vector m_arrVms; CVm* m_pVm; std::wstring m_sDebianStart; std::wstring m_sRedHatStart; std::wstring m_sDebianScript; std::wstring m_sRedHatScript; bool m_bVerboseLog; public: CVirtualBox() { m_pVm = NULL; m_sDebianStart = L""; m_sRedHatStart = L""; m_sDebianScript = L""; m_sRedHatScript = L""; m_sVmUser = L""; m_sVmPassword = L""; m_sRunScript = L"run"; m_sSetupScript = L"setup"; m_sConfigName = L"config"; m_sReportName = L"report.txt"; m_sStdoutFile = L"stdout.txt"; m_sEditorsPath = L"/opt/onlyoffice/desktopeditors/DesktopEditors"; m_sSuccessOutput = L"[DesktopEditors]: start page loaded"; m_sBranch = L""; m_sVersion = L""; m_sDebianUrl = L""; m_sCentosUrl = L""; m_sOpSuseUrl = L""; m_bVerboseLog = false; #ifdef WIN32 m_sVbmPath = L"\"c:\\Program Files\\Oracle\\VirtualBox\\VBoxManage.exe\""; #endif #ifdef LINUX m_sVbmPath = L"/usr/lib/virtualbox/VBoxManage"; #endif } // VboxManage bool InitVms() { m_arrVms.clear(); std::wstring sOutput = ExecuteCommand(L"list vms"); std::vector arrLines; if ( SplitStringAsVector(sOutput, L"\n", arrLines) ) { for (size_t i = 0; i < arrLines.size(); i++) { std::wstring sLine = arrLines[i]; std::wstring::size_type pos1 = sLine.find(L"{"); std::wstring::size_type pos2 = sLine.find(L"}", pos1); if (pos1 != std::wstring::npos && pos2 != std::wstring::npos && pos2 > pos1) { std::wstring sGuid = sLine.substr(pos1, pos2 - pos1 + 1); std::wstring sName = sLine.substr(0, pos1 - 1); sName = CorrectValue(sName); std::wstring sOs = GetVmOS(sGuid); SystemType eType = Empty; std::wstring sOsLower = sOs; std::transform(sOsLower.begin(), sOsLower.end(), sOsLower.begin(), tolower); if ( sOsLower.find(L"ubuntu") != std::wstring::npos || sOsLower.find(L"debian") != std::wstring::npos) eType = Debian; else if ( sOsLower.find(L"red hat") != std::wstring::npos || sOsLower.find(L"fedora") != std::wstring::npos || sOsLower.find(L"opensuse") != std::wstring::npos) eType = RedHat; m_arrVms.push_back(new CVm(sName, sGuid, sOs, eType)); } } } return m_arrVms.size() > 0; } void SetVm(CVm* pVm) { m_pVm = pVm; } std::vector GetStartVms() { std::vector arrResult; // Check Debian systems if ( m_sDebianStart.length() ) { std::vector arrDebian = GetDebianVms(); std::wstring sDebian = m_sDebianStart; std::vector list; NSStringUtils::string_replace(sDebian, L", ", L","); if ( SplitStringAsVector(sDebian, L",", list) ) { for (size_t i = 0; i < arrDebian.size(); i++) { if ( std::find(list.begin(), list.end(), arrDebian[i]->m_sName) != list.end() ) { arrResult.push_back(arrDebian[i]); } } } } // Check RedHat systems if ( m_sRedHatStart.length() ) { std::vector arrRedHat = GetRedHatVms(); std::wstring sRedHat = m_sRedHatStart; std::vector list; NSStringUtils::string_replace(sRedHat, L", ", L","); if ( SplitStringAsVector(sRedHat, L",", list) ) { for (size_t i = 0; i < arrRedHat.size(); i++) { if ( std::find(list.begin(), list.end(), arrRedHat[i]->m_sName) != list.end() ) { arrResult.push_back(arrRedHat[i]); } } } } return arrResult; } bool StartVm() { bool bResult = false; if ( m_pVm ) { if (m_bVerboseLog) { WriteReport(L"Starting VM"); WriteReport(L"---------------------------------------"); } WriteReport(m_pVm->m_sName); if (m_bVerboseLog) { WriteReport(m_pVm->m_sGuestOS); WriteReport(m_pVm->m_sGuid); } std::wstring sCommand = L"startvm " + m_pVm->m_sGuid; std::wstring sOutput = ExecuteCommand(sCommand); bResult = sOutput.find(L"started") != std::wstring::npos; if (m_bVerboseLog) WriteReportResult(bResult); } return bResult; } bool ResetVm() { bool bResult = false; if ( m_pVm ) { if (m_bVerboseLog) WriteReport(L"Restart VM"); std::wstring sCommand = L"controlvm " + m_pVm->m_sGuid + L" reset"; std::wstring sOutput = ExecuteCommand(sCommand); bResult = sOutput.find(L"") != std::wstring::npos; if (m_bVerboseLog) WriteReportResult(bResult); } return bResult; } bool StopVm(bool bSaveState = false) { bool bResult = false; if ( m_pVm ) { if (m_bVerboseLog) WriteReport(L"Stop VM"); std::wstring sCommand = L"controlvm " + m_pVm->m_sGuid + (bSaveState ? L" savestate" : L" poweroff"); std::wstring sOutput = ExecuteCommand(sCommand); bResult = sOutput.find(L"") != std::wstring::npos; if (m_bVerboseLog) WriteReportResult(bResult); } return bResult; } void WaitLoadVm() { // Wait success or 10 min int iSleep = 5000; int iCount = 10 * 60 * 1000 / iSleep; if (m_bVerboseLog) WriteReport(L"Waiting loading"); if ( m_pVm ) { while ( (iCount > 0) && !IsVmLoggedIn() ) { NSThreads::Sleep(iSleep); iCount--; } NSThreads::Sleep(30000); } if (m_bVerboseLog) WriteReportResult(iCount > 0); } bool WaitInstall() { // Wait success or 10 min int iSleep = 5000; int iCount = 10 * 60 * 1000 / iSleep; if (m_bVerboseLog) WriteReport(L"Waiting installation"); if ( m_pVm ) { std::vector arrProcess; if ( m_pVm->IsDebian() ) { arrProcess.push_back(L"apt"); arrProcess.push_back(L"dpkg"); } else if ( m_pVm->IsRedHat() ) { arrProcess.push_back(L"rpm"); } while ( iCount > 0 ) { bool bResult = IsLocationExists(m_sEditorsPath); for (size_t i = 0; i < arrProcess.size(); i++) { bResult &= !IsProcessExists(arrProcess[i]); } if ( bResult ) break; NSThreads::Sleep(iSleep); iCount--; } } // True - installation, False - timeout if (m_bVerboseLog) WriteReportResult(iCount > 0); return iCount > 0; } bool WaitStdout() { // Wait success or 1 min int iSleep = 5000; int iCount = 1 * 60 * 1000 / iSleep; bool bStdout = false; if (m_bVerboseLog) WriteReport(L"Waiting stdout"); if ( m_pVm ) { std::wstring sStdoutFile = GetWorkingDir() + L"/" + m_sStdoutFile; while ( (iCount > 0) && (!IsLocationExists(sStdoutFile)) ) { NSThreads::Sleep(iSleep); iCount--; } // File exists if ( iCount > 0 ) { std::wstring sCommand = L"guestcontrol " + m_pVm->m_sGuid + L" run --exe /bin/cat" + L" --username " + m_sVmUser + L" --password " + m_sVmPassword + L" --wait-stdout -- cat/arg0 " + sStdoutFile; std::wstring sOutput = ExecuteCommand(sCommand); if ( sOutput.find(m_sSuccessOutput) != std::wstring::npos ) bStdout = true; } } if (m_bVerboseLog) WriteReportResult(bStdout); // True - installation, False - timeout return bStdout && ( iCount > 0 ); } bool SaveScreenshot() { bool bResult = false; if ( m_pVm ) { if (m_bVerboseLog) WriteReport(L"Saving screenshot"); std::wstring sFilePath = GetReportDir() + L"/" + m_pVm->m_sName + L".png"; if ( NSFile::CFileBinary::Exists(sFilePath) ) NSFile::CFileBinary::Remove(sFilePath); std::wstring sCommand = L"controlvm " + m_pVm->m_sGuid + L" screenshotpng " + sFilePath; std::wstring sOutput = ExecuteCommand(sCommand); bResult = NSFile::CFileBinary::Exists(sFilePath); if (m_bVerboseLog) WriteReportResult(bResult); } return bResult; } bool CreateWorkingDir() { bool bResult = false; if ( m_pVm && m_sVmUser.length() ) { std::wstring sCommand = L"guestcontrol " + m_pVm->m_sGuid + L" --username " + m_sVmUser + L" --password " + m_sVmPassword + L" rmdir --recursive " + GetWorkingDir(); std::wstring sOutput = ExecuteCommand(sCommand); sCommand = L"guestcontrol " + m_pVm->m_sGuid + L" --username " + m_sVmUser + L" --password " + m_sVmPassword + L" mkdir " + GetWorkingDir(); sOutput = ExecuteCommand(sCommand); //NSThreads::Sleep(10000); bResult = true; } return bResult; } bool CheckOperationSystem() { bool bResult = false; if ( m_pVm ) { // Get real description m_pVm->m_sOperationSystem = L""; std::wstring sBin = L"/usr/bin/hostnamectl"; std::wstring sCommand = L"guestcontrol " + m_pVm->m_sGuid + L" run --exe " + sBin + L" --username " + m_sVmUser + L" --password " + m_sVmPassword + L" --wait-stdout"; std::wstring sOutput = ExecuteCommand(sCommand); std::vector arrLines; if ( SplitStringAsVector(sOutput, L"\n", arrLines) ) { std::wstring sPrefix = L"Operating System:"; for (size_t i = 0; i < arrLines.size(); i++) { std::wstring sLine = arrLines[i]; std::wstring::size_type pos = sLine.find(sPrefix); if ( pos != std::wstring::npos ) { m_pVm->m_sOperationSystem = sLine; pos = m_pVm->m_sOperationSystem.find(sPrefix + L" "); while ( pos != std::wstring::npos ) { NSStringUtils::string_replace(m_pVm->m_sOperationSystem, sPrefix + L" ", sPrefix); pos = m_pVm->m_sOperationSystem.find(sPrefix + L" "); } NSStringUtils::string_replace(m_pVm->m_sOperationSystem, sPrefix, L""); bResult = true; break; } } } } return bResult; } bool DownloadDistrib() { bool bResult = false; if ( m_pVm ) { // Prepare url std::wstring sUrl = L""; CheckOperationSystem(); if ( m_pVm->IsDebian() ) sUrl = m_sDebianUrl; else if ( m_pVm->IsRedHat() ) { std::wstring sOsLower = m_pVm->m_sOperationSystem; std::transform(sOsLower.begin(), sOsLower.end(), sOsLower.begin(), tolower); if ( sOsLower.find(L"centos") != std::wstring::npos || sOsLower.find(L"fedora") != std::wstring::npos) sUrl = m_sCentosUrl; else if ( sOsLower.find(L"opensuse") != std::wstring::npos ) sUrl = m_sOpSuseUrl; } if (m_bVerboseLog) WriteReport(L"Start downloading: " + sUrl); std::wstring sCommand = L"guestcontrol " + m_pVm->m_sGuid + L" run --exe /usr/bin/curl" + L" --username " + m_sVmUser + L" --password " + m_sVmPassword + L" --wait-stdout -- curl/arg0 " + sUrl + L" --output " + GetWorkingDir() + L"/" + NSFile::GetFileName(sUrl); std::wstring sOutput = ExecuteCommand(sCommand); // Wait flush to disk. Wait min NSThreads::Sleep(60000); bResult = true; if (m_bVerboseLog) WriteReportResult(bResult); } return bResult; } bool CopyScripts() { bool bResult = false; if ( m_pVm ) { if (m_bVerboseLog) WriteReport(L"Copiyng scripts"); // Setup std::wstring sData = L""; std::wstring sUrl = m_pVm->IsDebian() ? m_sDebianUrl : m_sCentosUrl; std::wstring sScriptPath = NSDirectory::GetTempPath() + L"/" + m_sSetupScript; std::wstring sDistribFile = NSFile::GetFileName(sUrl); if ( NSFile::CFileBinary::Exists(sScriptPath) ) NSFile::CFileBinary::Remove(sScriptPath); if ( m_pVm->IsDebian() ) { if ( m_sDebianScript.length() ) { if ( NSFile::CFileBinary::Exists(m_sDebianScript) ) { NSFile::CFileBinary::ReadAllTextUtf8(m_sDebianScript, sData); } } else { sData = L"#!/bin/bash\n" \ L"echo \"Install DesktopEditors\"\n" \ L"apt purge onlyoffice-desktopeditors -y\n" \ L"dpkg -i ./" + sDistribFile + "\n" \ L"apt install -f"; } } else if ( m_pVm->IsRedHat() ) { if ( m_sRedHatScript.length() ) { NSFile::CFileBinary::ReadAllTextUtf8(m_sRedHatScript, sData); } else { sData = L"#!/bin/bash\n" \ L"echo \"Install DesktopEditors\"\n" \ L"rpm -e onlyoffice-desktopeditors\n" \ L"rpm -i ./" + sDistribFile; } } NSFile::CFileBinary oFile; bResult = oFile.CreateFileW(sScriptPath); oFile.WriteStringUTF8(sData); oFile.CloseFile(); std::wstring sCommand = L"guestcontrol " + m_pVm->m_sGuid + L" --username " + m_sVmUser + L" --password " + m_sVmPassword + L" copyto " + sScriptPath + L" " + GetWorkingDir() + L"/" + m_sSetupScript; std::wstring sOutput = ExecuteCommand(sCommand); NSFile::CFileBinary::Remove(sScriptPath); //NSThreads::Sleep(10000); // Run sScriptPath = NSDirectory::GetTempPath() + L"/" + m_sRunScript; std::wstring sStdoutFile = GetWorkingDir() + L"/" + m_sStdoutFile; if ( NSFile::CFileBinary::Exists(sScriptPath) ) NSFile::CFileBinary::Remove(sScriptPath); std::wstring sEditorsFolder = m_sEditorsPath; NSStringUtils::string_replace(sEditorsFolder, NSFile::GetFileName(m_sEditorsPath), L""); sData = L"#!/bin/bash\n" \ L"LD_LIBRARY_PATH=" + sEditorsFolder + L" " + m_sEditorsPath + L" --ascdesktop-log-file=" + sStdoutFile; bResult &= oFile.CreateFileW(sScriptPath); oFile.WriteStringUTF8(sData); oFile.CloseFile(); sCommand = L"guestcontrol " + m_pVm->m_sGuid + L" --username " + m_sVmUser + L" --password " + m_sVmPassword + L" copyto " + sScriptPath + L" " + GetWorkingDir() + L"/" + m_sRunScript; sOutput = ExecuteCommand(sCommand); NSFile::CFileBinary::Remove(sScriptPath); //NSThreads::Sleep(10000); if (m_bVerboseLog) WriteReportResult(bResult); } return bResult; } bool RemoveScripts() { bool bResult = true; if ( m_pVm ) { if (m_bVerboseLog) WriteReport(L"Removing scripts"); std::vector arrScipts; arrScipts.push_back(m_sRunScript); arrScipts.push_back(m_sSetupScript); for (size_t i = 0; i < arrScipts.size(); i++) { std::wstring sScriptPath = GetWorkingDir() + L"/" + arrScipts[i]; if ( IsLocationExists(sScriptPath) ) { std::wstring sCommand = L"guestcontrol " + m_pVm->m_sGuid + L" --username " + m_sVmUser + L" --password " + m_sVmPassword + L" rm " + sScriptPath; std::wstring sOutput = ExecuteCommand(sCommand); bResult &= !IsLocationExists(sScriptPath); } } if (m_bVerboseLog) WriteReportResult(bResult); } return bResult; } bool RunEditors() { bool bResult = true; if ( m_pVm && IsLocationExists(m_sEditorsPath) ) { if (m_bVerboseLog) WriteReport(L"Runing DesktopEditors"); std::wstring sRunScript = GetWorkingDir() + L"/" + m_sRunScript; std::wstring sCommand = L"guestcontrol " + m_pVm->m_sGuid + L" start " + sRunScript + L" --username " + m_sVmUser + L" --password " + m_sVmPassword + L" --putenv DISPLAY=:0.0"; std::wstring sOutput = ExecuteCommand(sCommand); } return bResult; } bool IsReadyReset() { bool bResult = true; if ( m_pVm ) { if (m_bVerboseLog) WriteReport(L"Ready restart"); std::wstring sUrl = m_pVm->IsDebian() ? m_sDebianUrl : m_sCentosUrl; std::wstring sRunScript = GetWorkingDir() + L"/" + m_sSetupScript; std::wstring sSetupScript = GetWorkingDir() + L"/" + m_sSetupScript; std::wstring sDistribPath = GetWorkingDir() + L"/" + NSFile::GetFileName(sUrl); bResult = IsLocationExists(sRunScript) && IsLocationExists(sSetupScript) && IsLocationExists(sDistribPath); if (m_bVerboseLog) WriteReportResult(bResult); } return bResult; } bool IsEditorsRunned() { bool bResult = true; if ( m_pVm ) { if (m_bVerboseLog) WriteReport(L"DesktopEditors runned"); std::wstring sEditorProc = NSFile::GetFileName(m_sEditorsPath); bResult = IsProcessExists(sEditorProc); if (m_bVerboseLog) WriteReportResult(bResult); } return bResult; } // Report void CreateReport() { std::ofstream oFile; std::wstring sReportPath = GetReportDir() + L"/" + m_sReportName; oFile.open(U_TO_UTF8(sReportPath), std::ofstream::out | std::ofstream::trunc); oFile.close(); } void WriteReport(const std::wstring& sText) { if ( sText.length() ) { std::wofstream oFile; std::wstring sReportPath = GetReportDir() + L"/" + m_sReportName; oFile.open(U_TO_UTF8(sReportPath), std::ios_base::app); oFile << sText << std::endl; oFile.close(); std::wcout << sText << std::endl; } } void WriteReportResult(const bool& bResult) { std::wofstream oFile; std::wstring sReportPath = GetReportDir() + L"/" + m_sReportName; oFile.open(U_TO_UTF8(sReportPath), std::ios_base::app); oFile << BoolToStr(bResult) + L"\n" << std::endl; oFile.close(); std::wcout << BoolToStr(bResult) + L"\n" << std::endl; } void RemoveReport() { if ( NSDirectory::Exists(GetReportDir()) ) NSDirectory::DeleteDirectory(GetReportDir()); } // Config bool IsConfigExists() { return NSFile::CFileBinary::Exists(m_sConfigName); } bool CreateConfig() { std::wstring sDebian = L""; std::wstring sRedHat = L""; std::vector arrDebian = GetDebianVms(); std::vector arrRedHat = GetRedHatVms(); for (size_t i = 0; i < arrDebian.size(); i++) { sDebian += arrDebian[i]->m_sName + (i < arrDebian.size() - 1 ? L", " : L""); } for (size_t i = 0; i < arrRedHat.size(); i++) { sRedHat += arrRedHat[i]->m_sName + (i < arrRedHat.size() - 1 ? L", " : L""); } std::wstring sData = sCfgUser + L"\n" + sCfgPassword + L"\n\n" + sCfgBranch + L"7.4.0\n" + sCfgVersion + L"173\n\n" + sCfgDebianStart + sDebian + L"\n" + sCfgRedhatStart + sRedHat + L"\n\n" + sCfgDebianScript + L"\n" + sCfgRedhatScript + L"\n\n" + sCfgVerboseLog + L"0\n"; NSFile::CFileBinary oFile; oFile.CreateFileW(m_sConfigName); oFile.WriteStringUTF8(sData); oFile.CloseFile(); return IsConfigExists(); } bool ReadConfig() { bool bResult = false; if ( IsConfigExists() ) { std::wstring sData = L""; NSFile::CFileBinary oFile; if ( oFile.ReadAllTextUtf8(m_sConfigName, sData) ) { std::vector arrLines; if ( SplitStringAsVector(sData, L"\n", arrLines) ) { for (size_t i = 0; i < arrLines.size(); i++) { std::wstring sLine = arrLines[i]; // Auth if ( sLine.find(sCfgUser) != std::wstring::npos ) m_sVmUser = sLine.substr(sCfgUser.length()); else if ( sLine.find(sCfgPassword) != std::wstring::npos ) m_sVmPassword = sLine.substr(sCfgPassword.length()); // URL else if ( sLine.find(sCfgBranch) != std::wstring::npos ) m_sBranch = sLine.substr(sCfgBranch.length()); else if ( sLine.find(sCfgVersion) != std::wstring::npos ) m_sVersion = sLine.substr(sCfgVersion.length()); // Systems else if ( sLine.find(sCfgDebianStart) != std::wstring::npos ) m_sDebianStart = sLine.substr(sCfgDebianStart.length()); else if ( sLine.find(sCfgRedhatStart) != std::wstring::npos ) m_sRedHatStart = sLine.substr(sCfgRedhatStart.length()); // Custom setup scripts else if ( sLine.find(sCfgDebianScript) != std::wstring::npos ) m_sDebianScript = sLine.substr(sCfgDebianScript.length()); else if ( sLine.find(sCfgRedhatScript) != std::wstring::npos ) m_sRedHatScript = sLine.substr(sCfgRedhatScript.length()); // Log else if ( sLine.find(sCfgVerboseLog) != std::wstring::npos ) m_bVerboseLog = sLine.substr(sCfgVerboseLog.length()) == L"1"; } // Prepare urls if ( m_sBranch.length() && m_sVersion.length() ) { std::wstring sAmazonS3 = L"https://s3.eu-west-1.amazonaws.com/repo-doc-onlyoffice-com/desktop/linux"; if ( m_sDebianStart.length() ) { m_sDebianUrl = sAmazonS3 + L"/debian/onlyoffice-desktopeditors_{BRANCH}-{VERSION}_amd64.deb"; NSStringUtils::string_replace(m_sDebianUrl, L"{BRANCH}", m_sBranch); NSStringUtils::string_replace(m_sDebianUrl, L"{VERSION}", m_sVersion); } if ( m_sRedHatStart.length() ) { m_sCentosUrl = sAmazonS3 + L"/rhel/onlyoffice-desktopeditors-{BRANCH}-{VERSION}.el7.x86_64.rpm"; NSStringUtils::string_replace(m_sCentosUrl, L"{BRANCH}", m_sBranch); NSStringUtils::string_replace(m_sCentosUrl, L"{VERSION}", m_sVersion); m_sOpSuseUrl = sAmazonS3 + L"/suse/onlyoffice-desktopeditors-{BRANCH}-{VERSION}.suse12.x86_64.rpm"; NSStringUtils::string_replace(m_sOpSuseUrl, L"{BRANCH}", m_sBranch); NSStringUtils::string_replace(m_sOpSuseUrl, L"{VERSION}", m_sVersion); } } } oFile.CloseFile(); } } return bResult; } private: std::wstring GetWorkingDir() { std::wstring sDir = L""; if ( m_sVmUser.length() ) sDir = L"/home/" + m_sVmUser + L"/vboxtester"; return sDir; } std::wstring GetReportDir() { std::wstring sAppPath = NSFile::GetProcessDirectory(); sAppPath += L"/report"; if ( !NSDirectory::Exists(sAppPath) ) NSDirectory::CreateDirectory(sAppPath); return sAppPath; } bool IsLocationExists(const std::wstring& sPath) { // check ile or folder bool bResult = false; if ( m_pVm && sPath.length() ) { std::wstring sFile = L""; std::wstring sFolder = sPath; std::vector arrParts; if ( SplitStringAsVector(sPath, L"/", arrParts) ) { sFile = arrParts[arrParts.size() - 1]; NSStringUtils::string_replace(sFolder, L"/" + sFile, L""); } std::wstring sCommand = L"guestcontrol " + m_pVm->m_sGuid + L" run --exe /bin/ls" + L" --username " + m_sVmUser + L" --password " + m_sVmPassword + L" --wait-stdout -- ls/arg0 " + sFolder; std::wstring sOutput = ExecuteCommand(sCommand); if ( sOutput.length() ) { if ( SplitStringAsVector(sOutput, L"\n", arrParts) ) bResult = std::find(arrParts.begin(), arrParts.end(), sFile) != arrParts.end(); } } return bResult; } bool IsProcessExists(const std::wstring& sName) { bool bResult = false; if ( m_pVm && sName.length() ) { std::wstring sCommand = L"guestcontrol " + m_pVm->m_sGuid + L" run --exe /bin/ps" + L" --username " + m_sVmUser + L" --password " + m_sVmPassword + L" --wait-stdout -- ps/arg0 -e"; std::wstring sOutput = ExecuteCommand(sCommand); if ( sOutput.length() ) { std::vector arrLines; std::vector arrParts; if ( SplitStringAsVector(sOutput, L"\n", arrLines) ) { for (size_t i = 0; i < arrLines.size(); i++) { std::wstring sLine = arrLines[i]; if ( (i > 0) && SplitStringAsVector(sLine, L" ", arrParts) ) { if ( arrParts[arrParts.size() - 1] == sName ) { bResult = true; break; } } } } } } return bResult; } bool IsVmLoggedIn() { bool bResult = false; if ( m_pVm ) { // whoami check std::wstring sBin = L"/usr/bin/whoami"; if ( m_pVm->IsRedHat() ) NSStringUtils::string_replace(sBin, L"/usr", L""); std::wstring sCommand = L"guestcontrol " + m_pVm->m_sGuid + L" run --exe " + sBin + L" --username " + m_sVmUser + L" --password " + m_sVmPassword + L" --wait-stdout"; std::wstring sOutput = ExecuteCommand(sCommand); bool bWhoami = sOutput.find(m_sVmUser) != std::wstring::npos; // uptime check sBin = L"/usr/bin/uptime"; if ( m_pVm->IsRedHat() ) NSStringUtils::string_replace(sBin, L"/usr", L""); sCommand = L"guestcontrol " + m_pVm->m_sGuid + L" run --exe " + sBin + L" --username " + m_sVmUser + L" --password " + m_sVmPassword + L" --wait-stdout"; sOutput = ExecuteCommand(sCommand); bool bUptime = sOutput.find(L"user") != std::wstring::npos; // TODO check: ps -e | grep X // connection sCommand = L"guestcontrol " + m_pVm->m_sGuid + L" run --exe /usr/bin/curl" + L" --username " + m_sVmUser + L" --password " + m_sVmPassword + L" --wait-stdout -- curl/arg0 -I http://www.google.com"; sOutput = ExecuteCommand(sCommand); bool bConnection = sOutput.find(L"200 OK") != std::wstring::npos; bResult = (bWhoami || bUptime) && bConnection; } return bResult; } std::vector GetDebianVms() { std::vector arrVms; for (size_t i = 0; i < m_arrVms.size(); i++) { if ( m_arrVms[i]->IsDebian() ) { arrVms.push_back(m_arrVms[i]); } } return arrVms; } std::vector GetRedHatVms() { std::vector arrVms; for (size_t i = 0; i < m_arrVms.size(); i++) { if ( m_arrVms[i]->IsRedHat() ) { arrVms.push_back(m_arrVms[i]); } } return arrVms; } std::wstring GetVmOS(const std::wstring& sGuid) { return ParseVmInfo(sGuid, L"Guest OS"); } std::wstring ParseVmInfo(const std::wstring& sGuid, const std::wstring& sPref) { std::wstring sStatus = L""; if ( sGuid.length() && sPref.length() ) { std::wstring command = L"showvminfo " + sGuid; std::wstring sOutput = ExecuteCommand(command); std::vector arrLines; if ( SplitStringAsVector(sOutput, L"\n", arrLines) ) { std::wstring sPrefix = sPref + L":"; for (size_t i = 0; i < arrLines.size(); i++) { std::wstring sLine = arrLines[i]; std::wstring::size_type pos = sLine.find(sPrefix); if ( pos != std::wstring::npos ) { sStatus = sLine; pos = sStatus.find(sPrefix + L" "); while ( pos != std::wstring::npos ) { NSStringUtils::string_replace(sStatus, sPrefix + L" ", sPrefix); pos = sStatus.find(sPrefix + L" "); } NSStringUtils::string_replace(sStatus, sPrefix, L""); break; } } } } return sStatus; } std::wstring ExecuteCommand(const std::wstring& sArgs) { std::wstring sResult = L""; std::wstring sCommand = m_sVbmPath + L" " + sArgs; #ifdef WIN32 std::array aBuffer; FILE* pipe = _wpopen(sCommand.c_str(), L"r"); #endif #ifdef LINUX std::array aBuffer; FILE* pipe = popen(U_TO_UTF8(sCommand).c_str(), "r"); #endif if (!pipe) return sResult; #ifdef WIN32 while ( fgetws(aBuffer.data(), 128, pipe) != NULL ) { sResult += aBuffer.data(); } #endif #ifdef LINUX while ( fgets(aBuffer.data(), 128, pipe) != NULL ) { std::string sBuf = aBuffer.data(); sResult += UTF8_TO_U(sBuf); } #endif return sResult; } std::wstring BoolToStr(bool bResult) { return bResult ? L"OK" : L"ERROR"; } }; // Main #ifdef WIN32 int wmain(int argc, wchar_t** argv) #else int main(int argc, char** argv) #endif { // Test CVirtualBox oTester; oTester.InitVms(); if ( !oTester.IsConfigExists() ) { oTester.CreateConfig(); return 0; } oTester.ReadConfig(); oTester.RemoveReport(); oTester.CreateReport(); std::vector arrStartVms = oTester.GetStartVms(); for (size_t i = 0; i < arrStartVms.size(); i++) { CVm* pVm = arrStartVms[i]; std::wstring sGuid = pVm->m_sGuid; std::wstring sName = pVm->m_sName; oTester.SetVm(pVm); oTester.StartVm(); oTester.WaitLoadVm(); oTester.CreateWorkingDir(); oTester.CopyScripts(); oTester.DownloadDistrib(); bool bPassed = false; if ( oTester.IsReadyReset() ) { oTester.ResetVm(); oTester.WaitLoadVm(); if ( oTester.WaitInstall() ) { oTester.RunEditors(); oTester.WaitStdout(); if ( oTester.IsEditorsRunned() ) { oTester.SaveScreenshot(); bPassed = true; } } } oTester.WriteReport(bPassed ? L"PASSED\n" : L"FAILED\n"); oTester.RemoveScripts(); oTester.StopVm(); } return 0; }