settings.defaults.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. const Path = require('node:path')
  2. const os = require('node:os')
  3. const isPreEmptible = os.hostname().includes('pre-emp')
  4. module.exports = {
  5. compileSizeLimit: process.env.COMPILE_SIZE_LIMIT || '7mb',
  6. processLifespanLimitMs:
  7. parseInt(process.env.PROCESS_LIFE_SPAN_LIMIT_MS) || 60 * 60 * 24 * 1000 * 2,
  8. catchErrors: process.env.CATCH_ERRORS === 'true',
  9. path: {
  10. compilesDir:
  11. process.env.CLSI_COMPILES_PATH || Path.resolve(__dirname, '../compiles'),
  12. outputDir:
  13. process.env.CLSI_OUTPUT_PATH || Path.resolve(__dirname, '../output'),
  14. clsiCacheDir:
  15. process.env.CLSI_CACHE_PATH || Path.resolve(__dirname, '../cache'),
  16. synctexBaseDir(projectId) {
  17. return Path.join(this.compilesDir, projectId)
  18. },
  19. },
  20. internal: {
  21. clsi: {
  22. port: 3013,
  23. host: process.env.LISTEN_ADDRESS || '127.0.0.1',
  24. },
  25. load_balancer_agent: {
  26. report_load: process.env.LOAD_BALANCER_AGENT_REPORT_LOAD !== 'false',
  27. load_port: 3048,
  28. local_port: 3049,
  29. },
  30. },
  31. apis: {
  32. clsi: {
  33. // Internal requests (used by tests only at the time of writing).
  34. url: `http://${process.env.CLSI_HOST || '127.0.0.1'}:3013`,
  35. // External url prefix for output files, e.g. for requests via load-balancers.
  36. outputUrlPrefix: `${process.env.ZONE ? `/zone/${process.env.ZONE}` : ''}`,
  37. },
  38. clsiPerf: {
  39. host: `${process.env.CLSI_PERF_HOST || '127.0.0.1'}:${
  40. process.env.CLSI_PERF_PORT || '3043'
  41. }`,
  42. },
  43. },
  44. smokeTest: process.env.SMOKE_TEST || false,
  45. project_cache_length_ms: 1000 * 60 * 60 * 24,
  46. parallelFileDownloads: process.env.FILESTORE_PARALLEL_FILE_DOWNLOADS || 1,
  47. filestoreDomainOveride: process.env.FILESTORE_DOMAIN_OVERRIDE,
  48. texliveImageNameOveride: process.env.TEX_LIVE_IMAGE_NAME_OVERRIDE,
  49. texliveOpenoutAny: process.env.TEXLIVE_OPENOUT_ANY,
  50. texliveMaxPrintLine: process.env.TEXLIVE_MAX_PRINT_LINE,
  51. sentry: {
  52. dsn: process.env.SENTRY_DSN,
  53. },
  54. enablePdfCaching: process.env.ENABLE_PDF_CACHING === 'true',
  55. enablePdfCachingDark: process.env.ENABLE_PDF_CACHING_DARK === 'true',
  56. pdfCachingMinChunkSize:
  57. parseInt(process.env.PDF_CACHING_MIN_CHUNK_SIZE, 10) || 1024,
  58. pdfCachingMaxProcessingTime:
  59. parseInt(process.env.PDF_CACHING_MAX_PROCESSING_TIME, 10) || 10 * 1000,
  60. pdfCachingEnableWorkerPool:
  61. process.env.PDF_CACHING_ENABLE_WORKER_POOL === 'true',
  62. pdfCachingWorkerPoolSize:
  63. parseInt(process.env.PDF_CACHING_WORKER_POOL_SIZE, 10) || 4,
  64. pdfCachingWorkerPoolBackLogLimit:
  65. parseInt(process.env.PDF_CACHING_WORKER_POOL_BACK_LOG_LIMIT, 10) || 40,
  66. compileConcurrencyLimit: isPreEmptible ? 32 : 64,
  67. }
  68. if (process.env.ALLOWED_COMPILE_GROUPS) {
  69. try {
  70. module.exports.allowedCompileGroups =
  71. process.env.ALLOWED_COMPILE_GROUPS.split(' ')
  72. } catch (error) {
  73. console.error(error, 'could not apply allowed compile group setting')
  74. process.exit(1)
  75. }
  76. }
  77. if (process.env.DOCKER_RUNNER) {
  78. let seccompProfilePath
  79. module.exports.clsi = {
  80. dockerRunner: process.env.DOCKER_RUNNER === 'true',
  81. docker: {
  82. runtime: process.env.DOCKER_RUNTIME,
  83. image:
  84. process.env.TEXLIVE_IMAGE || 'quay.io/sharelatex/texlive-full:2017.1',
  85. env: {
  86. HOME: '/tmp',
  87. CLSI: 1,
  88. },
  89. socketPath: '/var/run/docker.sock',
  90. user: process.env.TEXLIVE_IMAGE_USER || 'tex',
  91. },
  92. optimiseInDocker: true,
  93. expireProjectAfterIdleMs: 24 * 60 * 60 * 1000,
  94. checkProjectsIntervalMs: 10 * 60 * 1000,
  95. }
  96. try {
  97. // Override individual docker settings using path-based keys, e.g.:
  98. // compileGroupDockerConfigs = {
  99. // priority: { 'HostConfig.CpuShares': 100 }
  100. // beta: { 'dotted.path.here', 'value'}
  101. // }
  102. const compileGroupConfig = JSON.parse(
  103. process.env.COMPILE_GROUP_DOCKER_CONFIGS || '{}'
  104. )
  105. // Automatically clean up wordcount and synctex containers
  106. const defaultCompileGroupConfig = {
  107. wordcount: { 'HostConfig.AutoRemove': true },
  108. synctex: { 'HostConfig.AutoRemove': true },
  109. }
  110. module.exports.clsi.docker.compileGroupConfig = Object.assign(
  111. defaultCompileGroupConfig,
  112. compileGroupConfig
  113. )
  114. } catch (error) {
  115. console.error(error, 'could not apply compile group docker configs')
  116. process.exit(1)
  117. }
  118. try {
  119. seccompProfilePath = Path.resolve(__dirname, '../seccomp/clsi-profile.json')
  120. module.exports.clsi.docker.seccomp_profile = JSON.stringify(
  121. JSON.parse(require('node:fs').readFileSync(seccompProfilePath))
  122. )
  123. } catch (error) {
  124. console.error(
  125. error,
  126. `could not load seccomp profile from ${seccompProfilePath}`
  127. )
  128. process.exit(1)
  129. }
  130. if (process.env.APPARMOR_PROFILE) {
  131. try {
  132. module.exports.clsi.docker.apparmor_profile = process.env.APPARMOR_PROFILE
  133. } catch (error) {
  134. console.error(error, 'could not apply apparmor profile setting')
  135. process.exit(1)
  136. }
  137. }
  138. if (process.env.ALLOWED_IMAGES) {
  139. try {
  140. module.exports.clsi.docker.allowedImages =
  141. process.env.ALLOWED_IMAGES.split(' ')
  142. } catch (error) {
  143. console.error(error, 'could not apply allowed images setting')
  144. process.exit(1)
  145. }
  146. }
  147. module.exports.path.synctexBaseDir = () => '/compile'
  148. module.exports.path.sandboxedCompilesHostDir = process.env.COMPILES_HOST_DIR
  149. }