2022-07-20 05:03:47 +00:00
const shell = require ( "shelljs" ) ;
const fsPromises = require ( "fs/promises" ) ;
const Constants = require ( "./constants" ) ;
const childProcess = require ( "child_process" ) ;
fix: Fix replicaset check to not require ClusterMonitor role (#19997)
In the `entrypoint.sh` script, we check if the MongoDB in use, has
replicaSet initiated or not. This is usually done with a `rs.initiate()`
on the cluster.
We need the replicaSet to be enabled on MongoDB, since the backend
server relies on MongoDB `changeStream`s, which is a feature, only
available if replicaSet is enabled.
However, to use the `changeStream` APIs, having the `read` or
`readWrite` role on MongoDB is enough. But the check we do in
`entrypoint.sh`, runs `rs.status()` to see if `replicaSet` is initiated.
This `rs.status()` call, unfortunately, requires the `ClusterMonitor`
role, unlike the `changeStream` API.
To tackle this, we created the `appsmithctl check_replica_set` command.
This command would attempt to use the `changeStream` API, and report
success or failure. But this failed on certain configurations, where
MongoDB was running as a single-node-cluster, on localhost, or a
local/internal network. This was an edge case.
That edge case is solved by this PR. With this, we can use `appsmithctl
check-replica-set` in the `entrypoint.sh` again.
2023-02-07 00:08:37 +00:00
const { ConnectionString } = require ( "mongodb-connection-string-url" ) ;
2021-09-01 05:32:08 +00:00
function showHelp ( ) {
2022-07-20 05:03:47 +00:00
console . log (
"\nUsage: appsmith <command> to interact with appsmith utils tool"
) ;
console . log ( "\nOptions:\r" ) ;
console . log ( "\tex, export_db\t\tExport interal database.\r" ) ;
console . log ( "\tim, import_db\t\tImport interal database.\r" ) ;
console . log ( "\tmi, migrate\t\tMigrate new server.\r" ) ;
console . log ( "\tcrs, check_replica_set\tCheck replica set mongoDB.\r" ) ;
console . log ( "\tbackup\t\t\tTake a backup of Appsmith instance.\r" ) ;
console . log ( "\trestore\t\t\tRestore Appsmith instance from a backup.\r" ) ;
console . log ( "\t--help\t\t\t" + "Show help." ) ;
2021-09-01 05:32:08 +00:00
}
2022-06-09 03:44:18 +00:00
function stop ( apps ) {
2022-07-20 05:03:47 +00:00
const appsStr = apps . join ( " " ) ;
console . log ( "Stopping " + appsStr ) ;
shell . exec ( "/usr/bin/supervisorctl stop " + appsStr ) ;
console . log ( "Stopped " + appsStr ) ;
2022-06-09 03:44:18 +00:00
}
function start ( apps ) {
2022-07-20 05:03:47 +00:00
const appsStr = apps . join ( " " ) ;
console . log ( "Starting " + appsStr ) ;
shell . exec ( "/usr/bin/supervisorctl start " + appsStr ) ;
console . log ( "Started " + appsStr ) ;
2022-06-09 03:44:18 +00:00
}
function execCommand ( cmd , options ) {
return new Promise ( ( resolve , reject ) => {
let isPromiseDone = false ;
const p = childProcess . spawn ( cmd [ 0 ] , cmd . slice ( 1 ) , {
2022-07-20 05:03:47 +00:00
stdio : "inherit" ,
2022-06-09 03:44:18 +00:00
... options ,
} ) ;
2022-07-20 05:03:47 +00:00
p . on ( "exit" , ( code ) => {
2022-06-09 03:44:18 +00:00
if ( isPromiseDone ) {
return ;
}
isPromiseDone = true ;
if ( code === 0 ) {
resolve ( ) ;
} else {
reject ( ) ;
}
2022-07-20 05:03:47 +00:00
} ) ;
2022-06-09 03:44:18 +00:00
2022-07-20 05:03:47 +00:00
p . on ( "error" , ( err ) => {
2022-06-09 03:44:18 +00:00
if ( isPromiseDone ) {
return ;
}
isPromiseDone = true ;
2023-01-03 06:44:21 +00:00
console . error ( "Error running command" , err ) ;
2022-06-09 03:44:18 +00:00
reject ( ) ;
2022-07-20 05:03:47 +00:00
} ) ;
} ) ;
2022-06-09 03:44:18 +00:00
}
2022-07-20 05:03:47 +00:00
async function listLocalBackupFiles ( ) {
// Ascending order
2022-07-07 05:49:25 +00:00
const backupFiles = [ ] ;
2022-07-20 05:03:47 +00:00
await fsPromises
. readdir ( Constants . BACKUP _PATH )
. then ( ( filenames ) => {
for ( let filename of filenames ) {
if ( filename . match ( /^appsmith-backup-.*\.tar\.gz$/ ) ) {
backupFiles . push ( filename ) ;
}
}
} )
. catch ( ( err ) => {
console . log ( err ) ;
} ) ;
2022-07-07 05:49:25 +00:00
return backupFiles ;
}
2022-07-28 12:15:28 +00:00
async function updateLastBackupErrorMailSentInMilliSec ( ts ) {
await fsPromises . mkdir ( Constants . BACKUP _PATH , { recursive : true } ) ;
await fsPromises . writeFile ( Constants . LAST _ERROR _MAIL _TS , ts . toString ( ) ) ;
}
async function getLastBackupErrorMailSentInMilliSec ( ) {
try {
const ts = await fsPromises . readFile ( Constants . LAST _ERROR _MAIL _TS ) ;
return parseInt ( ts , 10 ) ;
} catch ( error ) {
return 0 ;
}
}
2023-01-03 06:44:21 +00:00
async function getCurrentAppsmithVersion ( ) {
const content = await fsPromises . readFile ( '/opt/appsmith/rts/version.js' , { encoding : 'utf8' } ) ;
return content . match ( /\bexports\.VERSION\s*=\s*["']([^"]+)["']/ ) [ 1 ] ;
}
fix: Fix replicaset check to not require ClusterMonitor role (#19997)
In the `entrypoint.sh` script, we check if the MongoDB in use, has
replicaSet initiated or not. This is usually done with a `rs.initiate()`
on the cluster.
We need the replicaSet to be enabled on MongoDB, since the backend
server relies on MongoDB `changeStream`s, which is a feature, only
available if replicaSet is enabled.
However, to use the `changeStream` APIs, having the `read` or
`readWrite` role on MongoDB is enough. But the check we do in
`entrypoint.sh`, runs `rs.status()` to see if `replicaSet` is initiated.
This `rs.status()` call, unfortunately, requires the `ClusterMonitor`
role, unlike the `changeStream` API.
To tackle this, we created the `appsmithctl check_replica_set` command.
This command would attempt to use the `changeStream` API, and report
success or failure. But this failed on certain configurations, where
MongoDB was running as a single-node-cluster, on localhost, or a
local/internal network. This was an edge case.
That edge case is solved by this PR. With this, we can use `appsmithctl
check-replica-set` in the `entrypoint.sh` again.
2023-02-07 00:08:37 +00:00
function preprocessMongoDBURI ( uri /* string */ ) {
// Partially taken from <https://github.com/mongodb-js/mongosh/blob/8fde100d6d5ec711eb9565b85cb2e28e2da47c80/packages/arg-parser/src/uri-generator.ts#L248>
// If we don't add the `directConnection` parameter for non-SRV URIs, we'll see the problem at <https://github.com/appsmithorg/appsmith/issues/16104>.
const cs = new ConnectionString ( uri ) ;
const params = cs . searchParams ;
params . set ( 'appName' , 'appsmithctl' ) ;
if (
! cs . isSRV
&& ! params . has ( 'replicaSet' )
&& ! params . has ( 'directConnection' )
&& ! params . has ( 'loadBalanced' )
&& cs . hosts . length === 1
) {
params . set ( 'directConnection' , 'true' ) ;
}
// For localhost connections, set a lower timeout to avoid hanging for too long.
// Taken from <https://github.com/mongodb-js/mongosh/blob/8fde100d6d5ec711eb9565b85cb2e28e2da47c80/packages/arg-parser/src/uri-generator.ts#L156>.
if ( ! params . has ( 'serverSelectionTimeoutMS' ) && cs . hosts . every ( host => [ 'localhost' , '127.0.0.1' ] . includes ( host . split ( ':' ) [ 0 ] ) ) ) {
params . set ( 'serverSelectionTimeoutMS' , '2000' ) ;
}
return cs . toString ( ) ;
}
2022-06-09 03:44:18 +00:00
module . exports = {
showHelp ,
start ,
stop ,
execCommand ,
2022-07-07 05:49:25 +00:00
listLocalBackupFiles ,
2022-07-28 12:15:28 +00:00
updateLastBackupErrorMailSentInMilliSec ,
getLastBackupErrorMailSentInMilliSec ,
fix: Fix replicaset check to not require ClusterMonitor role (#19997)
In the `entrypoint.sh` script, we check if the MongoDB in use, has
replicaSet initiated or not. This is usually done with a `rs.initiate()`
on the cluster.
We need the replicaSet to be enabled on MongoDB, since the backend
server relies on MongoDB `changeStream`s, which is a feature, only
available if replicaSet is enabled.
However, to use the `changeStream` APIs, having the `read` or
`readWrite` role on MongoDB is enough. But the check we do in
`entrypoint.sh`, runs `rs.status()` to see if `replicaSet` is initiated.
This `rs.status()` call, unfortunately, requires the `ClusterMonitor`
role, unlike the `changeStream` API.
To tackle this, we created the `appsmithctl check_replica_set` command.
This command would attempt to use the `changeStream` API, and report
success or failure. But this failed on certain configurations, where
MongoDB was running as a single-node-cluster, on localhost, or a
local/internal network. This was an edge case.
That edge case is solved by this PR. With this, we can use `appsmithctl
check-replica-set` in the `entrypoint.sh` again.
2023-02-07 00:08:37 +00:00
getCurrentAppsmithVersion ,
preprocessMongoDBURI ,
2022-06-09 03:44:18 +00:00
} ;