From dbd784e9ea3629a49d681dfc2f3c2229863bb83d Mon Sep 17 00:00:00 2001 From: RunOnFlux Date: Mon, 9 Dec 2024 16:40:12 +0000 Subject: [PATCH] Update from https://github.com/RunOnFlux/flux/commit/92d8eb7c89166f100934ba43ed09f32abe04b99d --- services/appsService.js | 8 +- services/backupRestoreService.js | 10 +- services/benchmarkService.js | 3 +- services/dockerService.js | 4 +- services/fluxshareService.js | 41 ++++---- services/syncthingService.js | 157 ++++++++++++++++++------------- services/systemService.js | 8 +- services/utils/daemonConfig.js | 2 +- 8 files changed, 134 insertions(+), 99 deletions(-) diff --git a/services/appsService.js b/services/appsService.js index f3a27d07..72c571a4 100644 --- a/services/appsService.js +++ b/services/appsService.js @@ -46,7 +46,9 @@ const { invalidMessages } = require('./invalidMessages'); const fluxCommunicationUtils = require('./fluxCommunicationUtils'); const fluxDirPath = path.join(__dirname, '../../../'); -const appsFolder = `${fluxDirPath}ZelApps/`; +// ToDo: Fix all the string concatenation in this file and use path.join() +const appsFolderPath = process.env.FLUX_APPS_FOLDER || path.join(fluxDirPath, 'ZelApps'); +const appsFolder = `${appsFolderPath}/`; const cmdAsync = util.promisify(nodecmd.get); const crontabLoad = util.promisify(systemcrontab.load); @@ -4551,10 +4553,10 @@ async function getGlobalAppsSpecifications(req, res) { query.hash = hash; } if (owner) { - query.owner = owner; + query['appSpecifications.owner'] = owner; } if (appname) { - query.name = appname; + query['appSpecifications.name'] = appname; } const projection = { projection: { _id: 0 } }; const results = await dbHelper.findInDatabase(database, globalAppsInformation, query, projection); diff --git a/services/backupRestoreService.js b/services/backupRestoreService.js index 1c8147cc..6602444d 100644 --- a/services/backupRestoreService.js +++ b/services/backupRestoreService.js @@ -8,7 +8,9 @@ const util = require('util'); const exec = util.promisify(require('child_process').exec); const fluxDirPath = path.join(__dirname, '../../../'); -const appsFolder = `${fluxDirPath}ZelApps/`; +// ToDo: Fix all the string concatenation in this file and use path.join() +const appsFolderPath = process.env.FLUX_APPS_FOLDER || path.join(fluxDirPath, 'ZelApps'); +const appsFolder = `${appsFolderPath}/`; /** * Validates if a file path belongs to a specific set of upload types within the appsFolder. @@ -168,7 +170,7 @@ async function getRemoteFileSize(req, res) { } const response = messageHelper.createDataMessage(fileSize); return res ? res.json(response) : response; - // eslint-disable-next-line no-else-return + // eslint-disable-next-line no-else-return } else { const errorResponse = messageHelper.errUnauthorizedMessage(); return res ? res.json(errorResponse) : errorResponse; @@ -209,7 +211,7 @@ async function removeBackupFile(req, res) { const output = await IOUtils.removeFile(filepath); const response = messageHelper.createSuccessMessage(output); return res.json(response); - // eslint-disable-next-line no-else-return + // eslint-disable-next-line no-else-return } else { const errMessage = messageHelper.errUnauthorizedMessage(); return res.json(errMessage); @@ -252,7 +254,7 @@ async function downloadLocalFile(req, res) { const cmd = `sudo chmod 777 "${filepath}"`; await exec(cmd, { maxBuffer: 1024 * 1024 * 10 }); return res.download(filepath, fileName); - // eslint-disable-next-line no-else-return + // eslint-disable-next-line no-else-return } else { const errMessage = messageHelper.errUnauthorizedMessage(); return res.json(errMessage); diff --git a/services/benchmarkService.js b/services/benchmarkService.js index fdec68cb..7256437a 100644 --- a/services/benchmarkService.js +++ b/services/benchmarkService.js @@ -17,8 +17,9 @@ let response = messageHelper.createErrorMessage(); let benchdClient = null; async function buildBenchdClient() { + // just use process.cwd() or os.homedir() or something const homeDirPath = path.join(__dirname, '../../../../'); - const fluxbenchdPath = path.join(homeDirPath, '.fluxbenchmark'); + const fluxbenchdPath = process.env.FLUXBENCH_PATH || path.join(homeDirPath, '.fluxbenchmark'); const exists = await fs.stat(fluxbenchdPath).catch(() => false); diff --git a/services/dockerService.js b/services/dockerService.js index d9ca5037..32314ae6 100644 --- a/services/dockerService.js +++ b/services/dockerService.js @@ -9,7 +9,9 @@ const deviceHelper = require('./deviceHelper'); const log = require('../lib/log'); const fluxDirPath = path.join(__dirname, '../../../'); -const appsFolder = `${fluxDirPath}ZelApps/`; +// ToDo: Fix all the string concatenation in this file and use path.join() +const appsFolderPath = process.env.FLUX_APPS_FOLDER || path.join(fluxDirPath, 'ZelApps'); +const appsFolder = `${appsFolderPath}/`; const docker = new Docker(); diff --git a/services/fluxshareService.js b/services/fluxshareService.js index ac15cb5d..883e4780 100644 --- a/services/fluxshareService.js +++ b/services/fluxshareService.js @@ -15,6 +15,9 @@ const generalService = require('./generalService'); const log = require('../lib/log'); const IOUtils = require('./IOUtils'); +const dirpath = path.join(__dirname, '../../../'); +const appsFolder = process.env.FLUX_APPS_FOLDER || path.join(dirpath, 'ZelApps'); + /** * Delete a specific FluxShare file. * @param {string} file Name of file to be deleted. @@ -88,8 +91,7 @@ function getAllFiles(dirPath, arrayOfFiles) { * @returns {number} Total file size (GB). */ function getFluxShareSize() { - const dirpath = path.join(__dirname, '../../../'); - const directoryPath = `${dirpath}ZelApps/ZelShare`; + const directoryPath = path.join(appsFolder, 'ZelShare'); const arrayOfFiles = getAllFiles(directoryPath); @@ -300,8 +302,7 @@ async function fluxShareDownloadFolder(req, res, authorized = false) { return; } - const dirpath = path.join(__dirname, '../../../'); - const folderpath = `${dirpath}ZelApps/ZelShare/${folder}`; + const folderpath = path.join(appsFolder, 'ZelShare', folder); // beautify name const folderNameArray = folderpath.split('/'); @@ -360,8 +361,7 @@ async function fluxShareDownloadFile(req, res) { return; } - const dirpath = path.join(__dirname, '../../../'); - const filepath = `${dirpath}ZelApps/ZelShare/${file}`; + const filepath = path.join(appsFolder, 'ZelShare', file); // beautify name const fileNameArray = file.split('/'); @@ -392,8 +392,7 @@ async function fluxShareDownloadFile(req, res) { } // check if file is file. If directory use zelshareDwonloadFolder - const dirpath = path.join(__dirname, '../../../'); - const filepath = `${dirpath}ZelApps/ZelShare/${file}`; + const filepath = path.join(appsFolder, 'ZelShare', file); const fileStats = await fs.promises.lstat(filepath); const isDirectory = fileStats.isDirectory(); @@ -452,14 +451,13 @@ async function fluxShareRename(req, res) { const fileURI = encodeURIComponent(oldpath); await fluxShareDatabaseFileDeleteMultiple(fileURI); - const dirpath = path.join(__dirname, '../../../'); - const oldfullpath = `${dirpath}ZelApps/ZelShare/${oldpath}`; - let newfullpath = `${dirpath}ZelApps/ZelShare/${newname}`; + const oldfullpath = path.join(appsFolder, 'ZelShare', oldpath); + let newfullpath = path.join(appsFolder, 'ZelShare', newname); const fileURIArray = fileURI.split('%2F'); fileURIArray.pop(); if (fileURIArray.length > 0) { const renamingFolder = fileURIArray.join('/'); - newfullpath = `${dirpath}ZelApps/ZelShare/${renamingFolder}/${newname}`; + newfullpath = path.join(appsFolder, 'ZelShare', renamingFolder, newname); } await fs.promises.rename(oldfullpath, newfullpath); @@ -504,8 +502,7 @@ async function fluxShareRemoveFile(req, res) { await fluxShareDatabaseFileDelete(fileURI); - const dirpath = path.join(__dirname, '../../../'); - const filepath = `${dirpath}ZelApps/ZelShare/${file}`; + const filepath = path.join(appsFolder, 'ZelShare', file); await fs.promises.unlink(filepath); const response = messageHelper.createSuccessMessage('File Removed'); @@ -545,8 +542,7 @@ async function fluxShareRemoveFolder(req, res) { throw new Error('No folder specified'); } - const dirpath = path.join(__dirname, '../../../'); - const filepath = `${dirpath}ZelApps/ZelShare/${folder}`; + const filepath = path.join(appsFolder, 'ZelShare', folder); // await fs.promises.rmdir(filepath); await IOUtils.removeDirectory(filepath); const response = messageHelper.createSuccessMessage('Folder Removed'); @@ -583,8 +579,7 @@ async function fluxShareGetFolder(req, res) { let { folder } = req.params; folder = folder || req.query.folder || ''; - const dirpath = path.join(__dirname, '../../../'); - const filepath = `${dirpath}ZelApps/ZelShare/${folder}`; + const filepath = path.join(appsFolder, 'ZelShare', folder); const options = { withFileTypes: false, }; @@ -654,8 +649,7 @@ async function fluxShareCreateFolder(req, res) { let { folder } = req.params; folder = folder || req.query.folder || ''; - const dirpath = path.join(__dirname, '../../../'); - const filepath = `${dirpath}ZelApps/ZelShare/${folder}`; + const filepath = path.join(appsFolder, 'ZelShare', folder); await fs.promises.mkdir(filepath); @@ -684,8 +678,7 @@ async function fluxShareFileExists(req, res) { let { file } = req.params; file = file || req.query.file; - const dirpath = path.join(__dirname, '../../../'); - const filepath = `${dirpath}ZelApps/ZelShare/${file}`; + const filepath = path.join(appsFolder, 'ZelShare', file); let fileExists = true; try { await fs.promises.access(filepath, fs.constants.F_OK); // check file exists and write ability @@ -802,8 +795,8 @@ async function fluxShareUpload(req, res) { if (folder) { folder += '/'; } - const dirpath = path.join(__dirname, '../../../'); - const uploadDir = `${dirpath}ZelApps/ZelShare/${folder}`; + const uploadDir = path.join(appsFolder, 'ZelShare', folder); + const options = { multiples: true, uploadDir, diff --git a/services/syncthingService.js b/services/syncthingService.js index 3150d601..67292e1f 100644 --- a/services/syncthingService.js +++ b/services/syncthingService.js @@ -47,15 +47,14 @@ const asyncLock = new AsyncLock(); const stc = new FluxController(); /** - * To get syncthing config xml file - * @returns {Promise<(string | null)>} config gile (XML). + * + * Temporary function until Arcane is deployed + * @param {string} configDir The uesrs config dir + * @param {string} syncthingDir The syncthing config dir + * @param {string} configFile The syncthing config file + * @returns {Promise} */ -async function getConfigFile() { - const homedir = os.homedir(); - const configDir = path.join(homedir, '.config'); - const syncthingDir = path.join(configDir, 'syncthing'); - const configFile = path.join(syncthingDir, 'config.xml'); - +async function changeSyncthingOwnership(configDir, syncthingDir, configFile) { const user = os.userInfo().username; const owner = `${user}:${user}`; @@ -66,7 +65,7 @@ async function getConfigFile() { params: [owner, configDir], }); - if (chownConfigDirError) return null; + if (chownConfigDirError) return false; const { error: chownSyncthingError } = await serviceHelper.runCommand('chown', { runAsRoot: true, @@ -74,7 +73,7 @@ async function getConfigFile() { params: [owner, syncthingDir], }); - if (chownSyncthingError) return null; + if (chownSyncthingError) return false; const { error: chmodError } = await serviceHelper.runCommand('chmod', { runAsRoot: true, @@ -82,7 +81,26 @@ async function getConfigFile() { params: ['644', configFile], }); - if (chmodError) return null; + if (chmodError) return false; + + return true; +} + +/** + * To get syncthing config xml file + * @returns {Promise<(string | null)>} config file (XML). + */ +async function getConfigFile() { + const homedir = os.homedir(); + const configDir = path.join(homedir, '.config'); + const syncthingDir = process.env.SYNCTHING_PATH || path.join(configDir, 'syncthing'); + const configFile = path.join(syncthingDir, 'config.xml'); + + // only arcane will have this env param + if (!process.env.SYNCTHING_PATH) { + const ownershipChanged = await changeSyncthingOwnership(configDir, syncthingDir, configFile); + if (!ownershipChanged) return null; + } let result = null; // this should never reject as chown would error first but just in case @@ -2477,6 +2495,66 @@ async function stopSyncthingSentinel() { log.info('Syncthing sentinel stopped'); } +/** + * Temporary function until moved over to Arcane + * @param {boolean} installed If syncthing is installed + * @returns {Promise} + */ +async function ensureSyncthingRunning(installed) { + if (!installed || !await getDeviceId()) { + log.error('Unable to get syncthing deviceId. Reconfiguring syncthing.'); + await stopSyncthing(); + await installSyncthingIdempotently(); + await configureDirectories(); + + const homedir = os.homedir(); + const syncthingHome = path.join(homedir, '.config/syncthing'); + const logFile = path.join(syncthingHome, 'syncthing.log'); + + log.info('Spawning Syncthing instance...'); + + // if nodeJS binary has the CAP_SETUID capability, can then set the uid to 0, + // without having to call sudo. IMO, Flux should be run as it's own user, not just + // whatever the operator installed as. + // this can throw + + // having issues with nodemon and pm2. Using pm2 --no-treekill stops syncthing getting + // killed, but then get issues with nodemon not dying. + + // adding old spawn with shell in the interim. + + childProcess.spawn( + `sudo nohup syncthing --logfile ${logFile} --logflags=3 --log-max-old-files=2 --log-max-size=26214400 --allow-newer-config --no-browser --home ${syncthingHome} >/dev/null 2>&1 /dev/null 2>&1 false);