mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-12 13:13:45 +01:00
Adding 2025 and 2026 incremental compiles options (#35850)
* feat: adding 2025 and 2026 incremental compiles options * feat: remove dmtcp from compiler list and autoselect checkpointing version with labs inclusion * feat: updating seccomp profile for checkpointing * feat: disable non-premium dmtcp compiles, and align checkpoint version detection between clsi and web * feat: adding in reminder of checkpoint experiment, and using session based split test retrieval * Increase Packer build.sh timeout from 1h15m to 1h30m as build takes approx 1h * fix: moving checkpointing check from tag name based to hasCheckpointing flag set as part of allowed_images, and removing uneeded seccomp rule * feat: move variant/ image selection to CLSI, and have web control only what options to set for a compile. removing uneeded extra variants from webs list of allowed images * feat: adding compile timer as a query string as well --------- Co-authored-by: Tim Gibbon <tim.gibbon@overleaf.com> GitOrigin-RevId: cdbdf76a62dcd5a585925f18d64b6cb9cd6ed373
This commit is contained in:
committed by
Copybot
co-authored by
Tim Gibbon
parent
35271cb33c
commit
baa9cf78d9
@@ -170,7 +170,7 @@ async function doCompile(request, stats, timings) {
|
||||
)
|
||||
|
||||
// set up environment variables for chktex
|
||||
const env = {
|
||||
let env = {
|
||||
OVERLEAF_PROJECT_ID: request.project_id,
|
||||
}
|
||||
if (Settings.texliveOpenoutAny && Settings.texliveOpenoutAny !== '') {
|
||||
@@ -194,10 +194,11 @@ async function doCompile(request, stats, timings) {
|
||||
}
|
||||
}
|
||||
|
||||
// Pass through checkpoint setting
|
||||
if (request.enableCheckpoint) {
|
||||
env.ENABLE_CHECKPOINT = '1'
|
||||
}
|
||||
// the requested compile options may need a variant of the requested image,
|
||||
// which brings its own environment
|
||||
const imageVariantSettings = _getImageVariantSettings(request)
|
||||
request.imageName = imageVariantSettings.imageName
|
||||
env = { ...env, ...imageVariantSettings.env }
|
||||
|
||||
const compileStart = Date.now()
|
||||
|
||||
@@ -769,10 +770,45 @@ function _parseWordcountFromOutput(output) {
|
||||
return results
|
||||
}
|
||||
|
||||
function _getAllowedImages() {
|
||||
return Settings.clsi?.docker?.allowedImages
|
||||
}
|
||||
|
||||
function _isImageNameAllowed(imageName) {
|
||||
const ALLOWED_IMAGES =
|
||||
Settings.clsi && Settings.clsi.docker && Settings.clsi.docker.allowedImages
|
||||
return !ALLOWED_IMAGES || ALLOWED_IMAGES.includes(imageName)
|
||||
const allowedImages = _getAllowedImages()
|
||||
return !allowedImages || allowedImages.includes(imageName)
|
||||
}
|
||||
|
||||
// Variants are images built on top of a base image, tagged with a suffix, eg
|
||||
// texlive-full:2026.1.checkpointing is the checkpointing variant of
|
||||
// texlive-full:2026.1. Returns the settings needed to compile the request on
|
||||
// the variant its options call for: the image to run and the environment that
|
||||
// image needs. Falls back to the requested image when no variant applies, or
|
||||
// when the variant is not available on this host.
|
||||
function _getImageVariantSettings(request) {
|
||||
const { imageName } = request
|
||||
|
||||
// checkpointing compiles run on the checkpointing variant of the image
|
||||
if (request.enableCheckpoint) {
|
||||
const checkpointingImageName = `${imageName}.checkpointing`
|
||||
if (imageName && _getAllowedImages()?.includes(checkpointingImageName)) {
|
||||
return {
|
||||
imageName: checkpointingImageName,
|
||||
env: { ENABLE_CHECKPOINT: '1' },
|
||||
}
|
||||
}
|
||||
// variant either doesnt exist when it should, or user was able to make a request they shouldnt be able to
|
||||
logger.error(
|
||||
{
|
||||
projectId: request.project_id,
|
||||
userId: request.user_id,
|
||||
imageName,
|
||||
},
|
||||
'no checkpointing variant available for image, compiling without it'
|
||||
)
|
||||
}
|
||||
|
||||
return { imageName, env: {} }
|
||||
}
|
||||
|
||||
function _emitMetrics(request, status, stats, timings) {
|
||||
|
||||
@@ -186,6 +186,16 @@ describe('CompileManager', () => {
|
||||
default: ctx.Settings,
|
||||
}))
|
||||
|
||||
ctx.logger = {
|
||||
debug: sinon.stub(),
|
||||
info: sinon.stub(),
|
||||
warn: sinon.stub(),
|
||||
error: sinon.stub(),
|
||||
}
|
||||
vi.doMock('@overleaf/logger', () => ({
|
||||
default: ctx.logger,
|
||||
}))
|
||||
|
||||
vi.doMock('@overleaf/metrics', () => ({
|
||||
default: {
|
||||
inc: sinon.stub(),
|
||||
@@ -390,6 +400,77 @@ describe('CompileManager', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('with the enableCheckpoint option', () => {
|
||||
beforeEach(ctx => {
|
||||
ctx.baseImage = 'example.com/texlive-full:2025.1'
|
||||
ctx.checkpointingImage = `${ctx.baseImage}.checkpointing`
|
||||
ctx.request.imageName = ctx.baseImage
|
||||
ctx.request.enableCheckpoint = true
|
||||
ctx.Settings.clsi.docker.allowedImages = [
|
||||
ctx.baseImage,
|
||||
ctx.checkpointingImage,
|
||||
]
|
||||
})
|
||||
|
||||
it('should compile on the checkpointing variant of the image', async ctx => {
|
||||
await ctx.CompileManager.promises.doCompileWithLock(ctx.request, {}, {})
|
||||
const { image, environment } =
|
||||
ctx.LatexRunner.promises.runLatex.args[0][1]
|
||||
expect(image).to.equal(ctx.checkpointingImage)
|
||||
expect(environment).to.have.property('ENABLE_CHECKPOINT', '1')
|
||||
})
|
||||
|
||||
it('should log an error and compile on the base image when there is no checkpointing variant', async ctx => {
|
||||
ctx.Settings.clsi.docker.allowedImages = [ctx.baseImage]
|
||||
await ctx.CompileManager.promises.doCompileWithLock(ctx.request, {}, {})
|
||||
const { image, environment } =
|
||||
ctx.LatexRunner.promises.runLatex.args[0][1]
|
||||
expect(image).to.equal(ctx.baseImage)
|
||||
expect(environment).to.not.have.property('ENABLE_CHECKPOINT')
|
||||
expect(ctx.logger.error).to.have.been.calledWith(
|
||||
sinon.match({ imageName: ctx.baseImage })
|
||||
)
|
||||
})
|
||||
|
||||
it('should log an error and compile on the base image when there is no allow list', async ctx => {
|
||||
delete ctx.Settings.clsi.docker.allowedImages
|
||||
await ctx.CompileManager.promises.doCompileWithLock(ctx.request, {}, {})
|
||||
const { image, environment } =
|
||||
ctx.LatexRunner.promises.runLatex.args[0][1]
|
||||
expect(image).to.equal(ctx.baseImage)
|
||||
expect(environment).to.not.have.property('ENABLE_CHECKPOINT')
|
||||
expect(ctx.logger.error).to.have.been.called
|
||||
})
|
||||
|
||||
it('should log an error and compile without an image when none is requested', async ctx => {
|
||||
delete ctx.request.imageName
|
||||
await ctx.CompileManager.promises.doCompileWithLock(ctx.request, {}, {})
|
||||
const { image, environment } =
|
||||
ctx.LatexRunner.promises.runLatex.args[0][1]
|
||||
expect(image).to.be.undefined
|
||||
expect(environment).to.not.have.property('ENABLE_CHECKPOINT')
|
||||
expect(ctx.logger.error).to.have.been.called
|
||||
})
|
||||
})
|
||||
|
||||
describe('without the enableCheckpoint option', () => {
|
||||
beforeEach(async ctx => {
|
||||
ctx.request.imageName = 'example.com/texlive-full:2025.1'
|
||||
ctx.Settings.clsi.docker.allowedImages = [
|
||||
'example.com/texlive-full:2025.1',
|
||||
'example.com/texlive-full:2025.1.checkpointing',
|
||||
]
|
||||
await ctx.CompileManager.promises.doCompileWithLock(ctx.request, {}, {})
|
||||
})
|
||||
|
||||
it('should not enable checkpointing or change the image', ctx => {
|
||||
const { image, environment } =
|
||||
ctx.LatexRunner.promises.runLatex.args[0][1]
|
||||
expect(image).to.equal('example.com/texlive-full:2025.1')
|
||||
expect(environment).to.not.have.property('ENABLE_CHECKPOINT')
|
||||
})
|
||||
})
|
||||
|
||||
describe('with a check option', () => {
|
||||
beforeEach(async ctx => {
|
||||
ctx.request.check = 'error'
|
||||
|
||||
@@ -194,6 +194,39 @@ describe('RequestParser', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('with enableCheckpoint set', () => {
|
||||
beforeEach(async ctx => {
|
||||
await new Promise((resolve, reject) => {
|
||||
ctx.validRequest.compile.options.enableCheckpoint = true
|
||||
ctx.RequestParser.parse(ctx.validRequest, (error, data) => {
|
||||
if (error) return reject(error)
|
||||
ctx.data = data
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should set the enableCheckpoint attribute', ctx => {
|
||||
expect(ctx.data.enableCheckpoint).to.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('with enableCheckpoint not specified', () => {
|
||||
beforeEach(async ctx => {
|
||||
await new Promise((resolve, reject) => {
|
||||
ctx.RequestParser.parse(ctx.validRequest, (error, data) => {
|
||||
if (error) return reject(error)
|
||||
ctx.data = data
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should default the enableCheckpoint attribute to false', ctx => {
|
||||
expect(ctx.data.enableCheckpoint).to.equal(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('without a timeout specified', () => {
|
||||
beforeEach(async ctx => {
|
||||
await new Promise((resolve, reject) => {
|
||||
|
||||
Reference in New Issue
Block a user