2019-08-19 13:50:44 -07:00
'use strict' ;
exports = module . exports = {
2023-08-04 13:41:13 +05:30
reboot ,
2023-12-04 00:46:12 +01:00
getInfo ,
2023-08-11 21:47:49 +05:30
getUbuntuVersion ,
2022-11-04 15:09:37 +01:00
getSwaps ,
2021-01-04 11:05:42 -08:00
checkDiskSpace ,
2021-01-20 11:45:04 -08:00
getMemory ,
2022-10-12 10:26:21 +02:00
getDiskUsage ,
2023-08-04 13:41:13 +05:30
updateDiskUsage ,
startUpdateDiskUsage ,
getLogs ,
getBlockDevices ,
2023-08-10 18:45:27 +05:30
runSystemChecks ,
2023-12-04 00:23:25 +01:00
getProvider ,
2023-12-04 00:31:18 +01:00
getCpus ,
2024-11-30 10:41:01 +01:00
// exported for testing
2024-11-30 11:46:28 +01:00
_getFilesystems : getFilesystems
2019-08-19 13:50:44 -07:00
} ;
const apps = require ( './apps.js' ) ,
assert = require ( 'assert' ) ,
2023-08-04 11:24:28 +05:30
backups = require ( './backups.js' ) ,
2019-10-22 11:11:41 -07:00
BoxError = require ( './boxerror.js' ) ,
2024-01-30 11:52:59 +01:00
debug = require ( 'debug' ) ( 'box:system' ) ,
2022-10-18 19:32:07 +02:00
df = require ( './df.js' ) ,
2019-08-19 13:50:44 -07:00
docker = require ( './docker.js' ) ,
2023-12-04 01:38:08 +01:00
eventlog = require ( './eventlog.js' ) ,
2023-08-04 13:41:13 +05:30
fs = require ( 'fs' ) ,
logs = require ( './logs.js' ) ,
2019-08-19 13:50:44 -07:00
notifications = require ( './notifications.js' ) ,
2019-11-21 12:55:17 -08:00
os = require ( 'os' ) ,
2022-10-11 22:58:12 +02:00
path = require ( 'path' ) ,
2019-11-21 12:55:17 -08:00
paths = require ( './paths.js' ) ,
2020-01-31 13:37:07 -08:00
safe = require ( 'safetydance' ) ,
2024-10-14 19:10:31 +02:00
shell = require ( './shell.js' ) ( 'system' ) ,
2023-08-04 13:41:13 +05:30
tasks = require ( './tasks.js' ) ,
2021-01-04 11:05:42 -08:00
volumes = require ( './volumes.js' ) ;
2019-08-19 13:50:44 -07:00
2022-10-11 22:58:12 +02:00
const DU _CMD = path . join ( _ _dirname , 'scripts/du.sh' ) ;
2023-01-27 21:05:25 +01:00
const HDPARM _CMD = path . join ( _ _dirname , 'scripts/hdparm.sh' ) ;
2023-08-04 13:41:13 +05:30
const REBOOT _CMD = path . join ( _ _dirname , 'scripts/reboot.sh' ) ;
2022-10-11 22:58:12 +02:00
2022-10-12 11:59:28 +02:00
async function du ( file ) {
2022-10-11 23:14:50 +02:00
assert . strictEqual ( typeof file , 'string' ) ;
2024-10-14 19:10:31 +02:00
const [ error , stdoutResult ] = await safe ( shell . promises . sudo ( [ DU _CMD , file ] , { captureStdout : true } ) ) ;
2022-10-11 22:58:12 +02:00
if ( error ) throw new BoxError ( BoxError . FS _ERROR , error ) ;
return parseInt ( stdoutResult . trim ( ) , 10 ) ;
}
2023-01-27 21:05:25 +01:00
async function hdparm ( file ) {
assert . strictEqual ( typeof file , 'string' ) ;
2024-10-14 19:10:31 +02:00
const [ error , stdoutResult ] = await safe ( shell . promises . sudo ( [ HDPARM _CMD , file ] , { captureStdout : true } ) ) ;
2023-01-27 21:05:25 +01:00
if ( error ) throw new BoxError ( BoxError . FS _ERROR , error ) ;
const lines = stdoutResult . split ( '\n' ) ;
if ( lines . length != 4 ) return - 1 ;
if ( lines [ 2 ] . split ( '=' ) . length !== 2 ) return - 1 ;
const speed = lines [ 2 ] . split ( '=' ) [ 1 ] . slice ( 0 , 'MB/sec' . length ) . trim ( ) ;
return Number ( speed ) ;
}
2022-11-04 15:09:37 +01:00
async function getSwaps ( ) {
2024-10-15 10:10:15 +02:00
const [ error , stdout ] = await safe ( shell . spawn ( 'swapon' , [ '--noheadings' , '--raw' , '--bytes' , '--show=type,size,used,name' ] , { encoding : 'utf8' } ) ) ;
2024-02-20 22:57:36 +01:00
if ( error ) return { } ;
2024-03-22 10:39:35 +01:00
const output = stdout . trim ( ) ;
if ( ! output ) return { } ; // no swaps
2022-11-04 15:09:37 +01:00
const swaps = { } ;
2024-03-22 10:39:35 +01:00
for ( const line of output . split ( '\n' ) ) {
2022-11-04 15:09:37 +01:00
const parts = line . split ( ' ' , 4 ) ;
const name = parts [ 3 ] ;
swaps [ name ] = {
name : parts [ 3 ] ,
type : parts [ 0 ] , // partition or file
size : parseInt ( parts [ 1 ] ) ,
used : parseInt ( parts [ 2 ] ) ,
} ;
}
return swaps ;
}
2024-11-30 10:41:01 +01:00
// this gets information based on mounted filesystems
2024-11-30 11:46:28 +01:00
async function getFilesystems ( ) {
2024-11-30 12:01:25 +01:00
const FS _TYPES = [ 'ext4' , 'xfs' , 'cifs' , 'nfs' , 'fuse.sshfs' ] ; // we don't show size of contents in untracked disk types
2024-11-30 11:46:28 +01:00
const [ dfError , dfEntries ] = await safe ( df . filesystems ( ) ) ;
2022-10-12 09:42:14 +02:00
if ( dfError ) throw new BoxError ( BoxError . FS _ERROR , ` Error running df: ${ dfError . message } ` ) ;
2024-11-30 11:46:28 +01:00
const filesystems = { } ; // by file system
2022-10-12 09:42:14 +02:00
let rootDisk ;
2024-11-30 12:00:36 +01:00
for ( const dfEntry of dfEntries ) {
if ( ! FS _TYPES . includes ( dfEntry . type ) ) continue ;
if ( dfEntry . mountpoint === '/' ) rootDisk = dfEntry ;
filesystems [ dfEntry . filesystem ] = {
filesystem : dfEntry . filesystem ,
type : dfEntry . type ,
size : dfEntry . size ,
used : dfEntry . used ,
available : dfEntry . available ,
capacity : dfEntry . capacity ,
mountpoint : dfEntry . mountpoint ,
2022-10-12 09:42:14 +02:00
contents : [ ] // filled below
} ;
2021-05-11 17:50:48 -07:00
}
2021-01-04 11:05:42 -08:00
2022-10-12 09:42:14 +02:00
const standardPaths = [
{ type : 'standard' , id : 'platformdata' , path : paths . PLATFORM _DATA _DIR } ,
2022-10-12 11:59:28 +02:00
{ type : 'standard' , id : 'boxdata' , path : paths . BOX _DATA _DIR } ,
2022-10-12 09:42:14 +02:00
{ type : 'standard' , id : 'maildata' , path : paths . MAIL _DATA _DIR } ,
] ;
2021-01-04 11:05:42 -08:00
2022-10-12 09:42:14 +02:00
for ( const stdPath of standardPaths ) {
const [ dfError , diskInfo ] = await safe ( df . file ( stdPath . path ) ) ;
if ( dfError ) throw new BoxError ( BoxError . FS _ERROR , ` Error getting std path: ${ dfError . message } ` ) ;
2024-11-30 11:46:28 +01:00
filesystems [ diskInfo . filesystem ] . contents . push ( stdPath ) ;
2021-08-20 09:19:44 -07:00
}
2021-01-04 11:05:42 -08:00
2023-08-04 11:24:28 +05:30
const backupConfig = await backups . getConfig ( ) ;
2022-10-12 09:42:14 +02:00
if ( backupConfig . provider === 'filesystem' ) {
const [ , dfResult ] = await safe ( df . file ( backupConfig . backupFolder ) ) ;
2022-12-08 08:52:50 +01:00
const filesystem = dfResult ? . filesystem || rootDisk . filesystem ;
2024-11-30 11:46:28 +01:00
if ( filesystems [ filesystem ] ) filesystems [ filesystem ] . contents . push ( { type : 'standard' , id : 'cloudron-backup' , path : backupConfig . backupFolder } ) ;
2022-10-12 09:42:14 +02:00
}
2021-01-04 11:05:42 -08:00
2023-08-01 17:38:48 +05:30
// often the default backup dir is not cleaned up
if ( backupConfig . provider !== 'filesystem' || backupConfig . backupFolder !== paths . DEFAULT _BACKUP _DIR ) {
const [ , dfResult ] = await safe ( df . file ( paths . DEFAULT _BACKUP _DIR ) ) ;
const filesystem = dfResult ? . filesystem || rootDisk . filesystem ;
2024-11-30 11:46:28 +01:00
if ( filesystems [ filesystem ] ) filesystems [ filesystem ] . contents . push ( { type : 'cloudron-backup-default' , id : 'cloudron-backup-default' , path : paths . DEFAULT _BACKUP _DIR } ) ;
2023-08-01 17:38:48 +05:30
}
2022-10-12 09:42:14 +02:00
const [ dockerError , dockerInfo ] = await safe ( docker . info ( ) ) ;
if ( ! dockerError ) {
const [ , dfResult ] = await safe ( df . file ( dockerInfo . DockerRootDir ) ) ;
2022-12-08 08:52:50 +01:00
const filesystem = dfResult ? . filesystem || rootDisk . filesystem ;
2024-11-30 11:46:28 +01:00
if ( filesystems [ filesystem ] ) {
filesystems [ filesystem ] . contents . push ( { type : 'standard' , id : 'docker' , path : dockerInfo . DockerRootDir } ) ;
filesystems [ filesystem ] . contents . push ( { type : 'standard' , id : 'docker-volumes' , path : dockerInfo . DockerRootDir } ) ;
2023-10-17 16:34:00 +02:00
}
2021-08-25 19:41:46 -07:00
}
2022-10-12 09:42:14 +02:00
for ( const volume of await volumes . list ( ) ) {
2022-10-18 19:32:07 +02:00
const [ , dfResult ] = await safe ( df . file ( volume . hostPath ) ) ;
2022-12-08 08:52:50 +01:00
const filesystem = dfResult ? . filesystem || rootDisk . filesystem ;
2024-11-30 11:46:28 +01:00
if ( filesystems [ filesystem ] ) filesystems [ filesystem ] . contents . push ( { type : 'volume' , id : volume . id , path : volume . hostPath } ) ;
2022-10-12 09:42:14 +02:00
}
2021-08-25 19:41:46 -07:00
2022-10-12 09:42:14 +02:00
for ( const app of await apps . list ( ) ) {
2022-10-13 23:34:47 +02:00
if ( ! app . manifest . addons ? . localstorage ) continue ;
2019-08-19 13:50:44 -07:00
2022-10-12 09:42:14 +02:00
const dataDir = await apps . getStorageDir ( app ) ;
2024-06-06 15:22:33 +02:00
if ( dataDir === null ) continue ;
2022-10-12 09:42:14 +02:00
const [ , dfResult ] = await safe ( df . file ( dataDir ) ) ;
2022-12-08 08:52:50 +01:00
const filesystem = dfResult ? . filesystem || rootDisk . filesystem ;
2024-11-30 11:46:28 +01:00
if ( filesystems [ filesystem ] ) filesystems [ filesystem ] . contents . push ( { type : 'app' , id : app . id , path : dataDir } ) ;
2022-10-12 09:42:14 +02:00
}
2021-06-23 23:38:39 -07:00
2022-11-22 11:55:54 +01:00
const swaps = await getSwaps ( ) ;
for ( const k in swaps ) {
const swap = swaps [ k ] ;
if ( swap . type !== 'file' ) continue ;
const [ , dfResult ] = await safe ( df . file ( swap . name ) ) ;
2024-11-30 11:46:28 +01:00
filesystems [ dfResult ? . filesystem || rootDisk . filesystem ] . contents . push ( { type : 'swap' , id : swap . name , path : swap . name } ) ;
2022-11-22 11:55:54 +01:00
}
2024-11-30 11:46:28 +01:00
return filesystems ;
2021-08-25 19:41:46 -07:00
}
2019-08-19 13:50:44 -07:00
2021-08-25 19:41:46 -07:00
async function checkDiskSpace ( ) {
debug ( 'checkDiskSpace: checking disk space' ) ;
2019-08-19 13:50:44 -07:00
2024-11-30 11:46:28 +01:00
const filesystems = await getFilesystems ( ) ;
2021-06-23 23:38:39 -07:00
2021-08-25 19:41:46 -07:00
let markdownMessage = '' ;
2019-08-19 13:50:44 -07:00
2024-11-30 11:46:28 +01:00
for ( const fsPath in filesystems ) {
const filesystem = filesystems [ fsPath ] ;
if ( filesystem . contents . length === 0 ) continue ; // ignore if nothing interesting here
2021-06-03 12:20:44 -07:00
2024-11-30 11:46:28 +01:00
if ( filesystem . available <= ( 1.25 * 1024 * 1024 * 1024 ) ) { // 1.5G
markdownMessage += ` * ${ filesystem . filesystem } is at ${ filesystem . capacity * 100 } % capacity. \n ` ;
2021-08-25 19:41:46 -07:00
}
2022-10-12 09:42:14 +02:00
}
2021-08-25 19:41:46 -07:00
debug ( ` checkDiskSpace: disk space checked. out of space: ${ markdownMessage || 'no' } ` ) ;
2023-03-26 17:02:44 +02:00
if ( markdownMessage ) {
const finalMessage = ` One or more file systems are running out of space. Please increase the disk size at the earliest. \n \n ${ markdownMessage } ` ;
2024-12-11 15:47:41 +01:00
await notifications . pin ( notifications . TYPE _DISK _SPACE , 'Server is running out of disk space' , finalMessage , { } ) ;
2023-03-26 17:02:44 +02:00
} else {
2024-12-11 19:17:44 +01:00
await notifications . unpin ( notifications . TYPE _DISK _SPACE , { } ) ;
2023-03-26 17:02:44 +02:00
}
2019-08-19 13:50:44 -07:00
}
2019-11-21 12:55:17 -08:00
2022-11-04 15:09:37 +01:00
async function getSwapSize ( ) {
const swaps = await getSwaps ( ) ;
2022-12-05 12:20:42 +01:00
return Object . keys ( swaps ) . map ( n => swaps [ n ] . size ) . reduce ( ( acc , cur ) => acc + cur , 0 ) ;
2021-01-20 11:45:04 -08:00
}
2021-08-25 19:41:46 -07:00
async function getMemory ( ) {
return {
2019-11-21 12:55:17 -08:00
memory : os . totalmem ( ) ,
2022-11-04 15:09:37 +01:00
swap : await getSwapSize ( )
2021-08-25 19:41:46 -07:00
} ;
2019-11-21 12:55:17 -08:00
}
2021-01-20 11:45:04 -08:00
2022-10-12 10:35:12 +02:00
async function getDiskUsage ( ) {
2024-11-30 13:03:34 +01:00
const cache = safe . JSON . parse ( safe . fs . readFileSync ( paths . DISK _USAGE _CACHE _FILE , 'utf8' ) ) ;
2024-11-30 11:46:28 +01:00
if ( cache ? . disks ) {
cache . filesystems = cache . disks ; // legacy cache file had "disks"
delete cache . disks ;
}
return cache ;
2022-10-12 10:26:21 +02:00
}
async function updateDiskUsage ( progressCallback ) {
2022-10-12 10:35:12 +02:00
assert . strictEqual ( typeof progressCallback , 'function' ) ;
2022-10-12 10:26:21 +02:00
2024-11-30 11:46:28 +01:00
const filesystems = await getFilesystems ( ) ;
2022-10-12 10:26:21 +02:00
const now = Date . now ( ) ;
let percent = 1 ;
2024-11-30 12:01:25 +01:00
const dockerDf = await docker . df ( ) ;
2024-11-30 13:03:34 +01:00
const excludePaths = ( safe . fs . readFileSync ( paths . DISK _USAGE _EXCLUDE _FILE , 'utf8' ) || '' ) . split ( '\n' ) ;
2024-11-30 12:01:25 +01:00
const fsCount = Object . keys ( filesystems ) . length ;
2024-11-30 11:46:28 +01:00
for ( const fsPath in filesystems ) {
const filesystem = filesystems [ fsPath ] ;
2022-10-12 10:26:21 +02:00
2024-11-30 12:01:25 +01:00
if ( filesystem . type === 'ext4' || filesystem . type === 'xfs' ) { // hdparm only works with block devices
const [ speedError , speed ] = await safe ( hdparm ( fsPath ) ) ;
2023-08-01 16:31:01 +05:30
if ( speedError ) progressCallback ( { message : ` hdparm error: ${ speedError . message } ` } ) ;
2024-11-30 11:46:28 +01:00
filesystem . speed = speedError ? - 1 : speed ;
2023-08-01 16:31:01 +05:30
} else {
2024-11-30 11:46:28 +01:00
filesystem . speed = - 1 ;
2023-08-01 16:31:01 +05:30
}
2023-01-27 21:05:25 +01:00
2024-11-30 12:01:25 +01:00
percent += ( 100 / fsCount ) ;
progressCallback ( { percent , message : ` Checking contents of ${ fsPath } ` } ) ;
2023-10-17 16:34:00 +02:00
2024-11-30 11:46:28 +01:00
for ( const content of filesystem . contents ) {
2024-11-30 12:01:25 +01:00
progressCallback ( { message : ` Checking du of ${ content . id } ${ content . path } ` } ) ;
2022-10-12 10:35:12 +02:00
if ( content . id === 'docker' ) {
2023-10-17 16:34:00 +02:00
content . usage = dockerDf . LayersSize ;
} else if ( content . id === 'docker-volumes' ) {
content . usage = dockerDf . Volumes . map ( ( v ) => v . UsageData . Size ) . reduce ( ( a , b ) => a + b , 0 ) ;
2024-11-30 13:03:34 +01:00
} else if ( excludePaths . includes ( fsPath ) ) {
debug ( ` updateDiskUsage: skipping since path ${ fsPath } is excluded ` ) ;
content . usage = 0 ;
2022-10-12 10:26:21 +02:00
} else {
2022-10-13 23:34:47 +02:00
const [ error , usage ] = await safe ( du ( content . path ) ) ;
if ( error ) progressCallback ( { message : ` du error: ${ error . message } ` } ) ; // can happen if app is installing etc
content . usage = usage || 0 ;
2022-10-12 10:26:21 +02:00
}
progressCallback ( { message : ` du of ${ JSON . stringify ( content ) } : ${ content . usage } ` } ) ;
}
}
2024-11-30 13:03:34 +01:00
if ( ! safe . fs . writeFileSync ( paths . DISK _USAGE _CACHE _FILE , JSON . stringify ( { ts : now , filesystems } , null , 4 ) , 'utf8' ) ) throw new BoxError ( BoxError . FS _ERROR , ` Could not write du cache file: ${ safe . error . message } ` ) ;
2022-10-12 10:26:21 +02:00
2024-11-30 11:46:28 +01:00
return filesystems ;
2022-10-12 10:26:21 +02:00
}
2023-08-04 13:41:13 +05:30
async function reboot ( ) {
2024-12-11 15:47:41 +01:00
await notifications . unpin ( notifications . TYPE _REBOOT , { } ) ;
2023-08-04 13:41:13 +05:30
2024-10-14 19:10:31 +02:00
const [ error ] = await safe ( shell . promises . sudo ( [ REBOOT _CMD ] , { } ) ) ;
2023-08-04 13:41:13 +05:30
if ( error ) debug ( 'reboot: could not reboot. %o' , error ) ;
}
2023-12-04 00:46:12 +01:00
async function getInfo ( ) {
2023-08-04 13:41:13 +05:30
// https://serverfault.com/questions/92932/how-does-ubuntu-keep-track-of-the-system-restart-required-flag-in-motd
2023-12-04 00:46:12 +01:00
const rebootRequired = fs . existsSync ( '/var/run/reboot-required' ) ;
2023-12-04 01:09:42 +01:00
const uptime = safe . fs . readFileSync ( '/proc/uptime' , 'utf8' ) ;
const uptimeSecs = parseInt ( uptime . split ( ' ' ) [ 0 ] , 10 ) ;
const sysVendor = safe . fs . readFileSync ( '/sys/devices/virtual/dmi/id/sys_vendor' , 'utf8' ) ;
const productName = safe . fs . readFileSync ( '/sys/devices/virtual/dmi/id/product_name' , 'utf8' ) ;
2023-12-04 00:46:12 +01:00
2023-12-04 01:38:08 +01:00
const activationTime = ( await eventlog . getActivationEvent ( ) ) ? . creationTime || null ;
2023-12-04 00:46:12 +01:00
return {
2023-12-04 01:38:08 +01:00
sysVendor : sysVendor . trim ( ) ,
productName : productName . trim ( ) ,
2023-12-04 01:09:42 +01:00
uptimeSecs ,
2023-12-04 01:38:08 +01:00
rebootRequired ,
activationTime
2023-12-04 00:46:12 +01:00
} ;
2023-08-04 13:41:13 +05:30
}
async function startUpdateDiskUsage ( ) {
const taskId = await tasks . add ( tasks . TASK _UPDATE _DISK _USAGE , [ ] ) ;
tasks . startTask ( taskId , { } ) ;
return taskId ;
}
async function getLogs ( unit , options ) {
assert . strictEqual ( typeof unit , 'string' ) ;
assert ( options && typeof options === 'object' ) ;
2024-07-25 17:50:41 +02:00
if ( unit !== 'box' ) throw new BoxError ( BoxError . BAD _FIELD , ` No such unit ' ${ unit } ' ` ) ;
2023-08-04 13:41:13 +05:30
2024-07-25 17:50:41 +02:00
const logFile = path . join ( paths . LOG _DIR , 'box.log' ) ;
2023-08-04 13:41:13 +05:30
const cp = logs . tail ( [ logFile ] , { lines : options . lines , follow : options . follow } ) ;
const logStream = new logs . LogStream ( { format : options . format || 'json' , source : unit } ) ;
2024-02-24 17:18:38 +01:00
logStream . on ( 'close' , ( ) => cp . terminate ( ) ) ; // the caller has to call destroy() on logStream. destroy() of Transform emits 'close'
2023-08-04 13:41:13 +05:30
cp . stdout . pipe ( logStream ) ;
return logStream ;
}
2024-11-30 10:41:01 +01:00
// this gets block devices as opposed to mounted filesystems. this is used for configuring backups and volumes in the frontend
2023-08-04 13:41:13 +05:30
async function getBlockDevices ( ) {
2024-10-15 10:10:15 +02:00
const result = await shell . spawn ( 'lsblk' , [ '--paths' , '--json' , '--list' , '--fs' , '--output' , '+rota' ] , { encoding : 'utf8' } ) ;
2024-02-20 22:57:36 +01:00
const info = safe . JSON . parse ( result ) ;
if ( ! info ) throw new BoxError ( BoxError . INTERNAL _ERROR , ` failed to parse lsblk: ${ safe . error . message } ` ) ;
2023-08-04 13:41:13 +05:30
const devices = info . blockdevices . filter ( d => d . fstype === 'ext4' || d . fstype === 'xfs' ) ;
debug ( ` getBlockDevices: Found ${ devices . length } devices. ${ devices . map ( d => d . name ) . join ( ', ' ) } ` ) ;
return devices . map ( function ( d ) {
return {
path : d . name ,
size : d . fsavail || 0 ,
type : d . fstype ,
2023-08-08 12:34:19 +02:00
uuid : d . uuid ,
2024-09-30 14:09:02 +02:00
rota : d . rota , // false (ssd) true (hdd)
2023-12-03 21:18:16 +01:00
mountpoint : d . mountpoints ? d . mountpoints . pop ( ) : d . mountpoint // we only support one mountpoint here old lsblk only exposed one via .mountpoint
2023-08-04 13:41:13 +05:30
} ;
} ) ;
}
async function checkRebootRequired ( ) {
2023-12-04 00:46:12 +01:00
const { rebootRequired } = await getInfo ( ) ;
2023-08-04 13:41:13 +05:30
if ( rebootRequired ) {
2024-12-11 15:47:41 +01:00
await notifications . pin ( notifications . TYPE _REBOOT , 'Reboot Required' , 'To finish ubuntu security updates, a reboot is necessary.' , { } ) ;
2023-08-04 13:41:13 +05:30
} else {
2024-12-11 15:47:41 +01:00
await notifications . unpin ( notifications . TYPE _REBOOT , { } ) ;
2023-08-04 13:41:13 +05:30
}
}
2023-08-11 21:47:49 +05:30
async function getUbuntuVersion ( ) {
const release = safe . fs . readFileSync ( '/etc/lsb-release' , 'utf-8' ) ;
if ( release === null ) throw new BoxError ( BoxError . FS _ERROR , safe . error . message ) ;
return release . match ( /DISTRIB_DESCRIPTION="(.*)"/ ) [ 1 ] ;
}
2023-08-04 13:41:13 +05:30
async function checkUbuntuVersion ( ) {
2024-12-11 15:03:59 +01:00
const isBionic = fs . readFileSync ( '/etc/lsb-release' , 'utf-8' ) . includes ( '18.04' ) ;
if ( ! isBionic ) return ;
2023-08-04 13:41:13 +05:30
2024-12-11 15:47:41 +01:00
await notifications . pin ( notifications . TYPE _UPDATE _UBUNTU , 'Ubuntu upgrade required' , 'Ubuntu 18.04 has reached end of life and will not receive security and maintenance updates. Please follow https://docs.cloudron.io/guides/upgrade-ubuntu-20/ to upgrade to Ubuntu 20 at the earliest.' , { } ) ;
2023-08-04 13:41:13 +05:30
}
async function runSystemChecks ( ) {
debug ( 'runSystemChecks: checking status' ) ;
const checks = [
checkRebootRequired ( ) ,
checkUbuntuVersion ( )
] ;
await Promise . allSettled ( checks ) ;
}
2023-08-10 18:45:27 +05:30
function getProvider ( ) {
const provider = safe . fs . readFileSync ( paths . PROVIDER _FILE , 'utf8' ) ;
return provider ? provider . trim ( ) : 'generic' ;
}
2023-12-04 00:23:25 +01:00
async function getCpus ( ) {
return os . cpus ( ) ;
}