diff --git a/packages/mongodb-runner/README.md b/packages/mongodb-runner/README.md index bc31a208..714eb253 100644 --- a/packages/mongodb-runner/README.md +++ b/packages/mongodb-runner/README.md @@ -150,6 +150,18 @@ layer, managing the storage backend's docker compose project alongside the mongod processes. See [docs/disaggregated-storage.md](./docs/disaggregated-storage.md). +Point it at an SLS dir — the `buildscripts/modules/atlas` directory of a +disaggregated-storage-capable MongoDB build (an installed build or a Server +source checkout), or any parent containing it — and everything else is located +automatically: + +```bash +# installed build +npx @mongodb-js/mongodb-runner start -t replset --slsDir=/path/to/dsc-install --binDir=... +# Server source checkout +npx @mongodb-js/mongodb-runner start -t replset --slsDir=$MONGO_REPO --binDir=... +``` + ## License Apache 2.0 diff --git a/packages/mongodb-runner/docs/disaggregated-storage.md b/packages/mongodb-runner/docs/disaggregated-storage.md index 79414caf..65270c4d 100644 --- a/packages/mongodb-runner/docs/disaggregated-storage.md +++ b/packages/mongodb-runner/docs/disaggregated-storage.md @@ -42,46 +42,49 @@ override. - `binDir`: a local directory containing the binaries, or - `downloadUrl`: a URL to a tarball of such a build (cached by URL, standard release-tarball layout with a top-level directory containing `bin/`). -- The SLS multi-cell compose file — mongodb-runner does not ship one; point - it at the file you want to use, typically - `buildscripts/modules/atlas/sls-multicell-docker-compose.yml` in a mongodb - server checkout. Files it references (`slsbackup.proto`, - `flags-state.json`) are resolved relative to it, and the services/ports are - parsed from it, so any version of the file works as-is. +- The SLS dir — mongodb-runner does not ship these files. They live in the + `buildscripts/modules/atlas` directory of the 10gen/mongo repo and are: + - `sls-multicell-docker-compose.yml` — the multi-cell compose file. + - `manifest.json` — its `pinned_sls_commit` supplies the default image tag. + - `slsbackup.proto` and `flags-state.json` — files the compose file + references. + + Point `slsDir` at it; the runner locates and validates the files and reads + the image tag from the manifest. + - The image tag is read automatically from the `pinned_sls_commit` in - `manifest.json` sitting next to the compose file (the server repository's - `buildscripts/modules/atlas/manifest.json`). Pass `--slsImageTag` to + `manifest.json` sitting next to the compose file. Pass `--slsImageTag` to override it. ## Quick start -Given the compose file, everything else (image tag, compose environment +Given a disaggregated-storage-capable MongoDB build — an installed build or a +Server source checkout — everything else (image tag, compose environment variables, readiness polling, per-shard log creation, and the `disaggregatedStorageConfig` server parameter) is generated automatically. -Full sequence, assuming a mongodb server checkout at `$MONGO_REPO`: +Assuming a build at `$BUILD_DIR`: ```bash # 1. Log in to the SLS image registry aws ecr get-login-password --region us-east-1 | \ docker login --username AWS --password-stdin 664315256653.dkr.ecr.us-east-1.amazonaws.com -# 2. Start a 2-node replica set backed by SLS (the image tag is read from the -# manifest.json next to the compose file; pass --slsImageTag to override it) -@mongodb-js/mongodb-runner start -t replset \ - --slsCompose=$MONGO_REPO/buildscripts/modules/atlas/sls-multicell-docker-compose.yml \ - --binDir=/path/to/dsc-mongod/bin \ - --debug -# or, instead of --binDir: -# --downloadUrl=https://.../dsc-mongod.tgz +# 2. Start a 2-node replica set backed by SLS +@mongodb-js/mongodb-runner start --topology=replset --slsDir="$BUILD_DIR" \ + --binDir=/path/to/dsc-mongod/bin --logDir="$LOG_DIR" --id=tools-dsc ``` +`--slsDir` locates and validates the SLS dir and reads the image tag from its +`manifest.json`; for a Server source checkout, point it at the repo root and +the files are found under `buildscripts/modules/atlas`. + This prints the connection string once the cluster is up. To get the allocated SLS service ports/URIs as structured output, add `--json` and capture stdout to a file instead of scraping it: ```bash mongodb-runner start -t replset \ - --slsCompose=$MONGO_REPO/buildscripts/modules/atlas/sls-multicell-docker-compose.yml \ + --slsDir="$BUILD_DIR" \ --binDir=/path/to/dsc-mongod/bin \ --json > cluster.json ``` @@ -244,13 +247,11 @@ server parameter for one shard; options: `logId`, `cellMetadataService`, ## CLI use -For an SLS project, `--slsCompose` handles everything (see Quick start); +For an SLS project, `--slsDir` handles everything (see Quick start); `--slsImageTag` is optional and overrides the tag read from the manifest: ```bash -@mongodb-js/mongodb-runner start -t replset \ - --slsCompose=/path/to/sls-multicell-docker-compose.yml \ - --binDir=... +@mongodb-js/mongodb-runner start -t replset --slsDir=/path/to/dsc-install --binDir=... ``` Custom (non-SLS) storage backends are only supported through the programmatic diff --git a/packages/mongodb-runner/examples/sls-replset.js b/packages/mongodb-runner/examples/sls-replset.js index 1c9f5dc9..d5258c82 100644 --- a/packages/mongodb-runner/examples/sls-replset.js +++ b/packages/mongodb-runner/examples/sls-replset.js @@ -15,7 +15,7 @@ // // This is equivalent to: // mongodb-runner start -t replset \ -// --slsCompose= --binDir=... +// --slsDir= --binDir=... // Enable mongodb-runner debug output (compose progress, server startup, ...) // unless the user already configured DEBUG themselves. diff --git a/packages/mongodb-runner/src/cli.spec.ts b/packages/mongodb-runner/src/cli.spec.ts index de31415d..a6d6027e 100644 --- a/packages/mongodb-runner/src/cli.spec.ts +++ b/packages/mongodb-runner/src/cli.spec.ts @@ -21,6 +21,15 @@ async function runCli( return stdout; } +async function runCliExpectingFailure(args: string[]): Promise { + try { + await runCli(args); + } catch (err) { + return String((err as { stderr?: string }).stderr ?? ''); + } + throw new Error(`expected the CLI to fail: ${args.join(' ')}`); +} + describe('cli', function () { this.timeout(process.platform === 'win32' ? 400_000 : 100_000); let tmpDir = ''; @@ -213,4 +222,22 @@ describe('cli', function () { expect(JSON.parse(stdout)).to.deep.equal([]); }); + + it('rejects a --slsDir with no path', async function () { + const stderr = await runCliExpectingFailure(['start', '--slsDir']); + expect(stderr, 'the error should say a path is required').to.include( + '--slsDir requires a path', + ); + }); + + it('rejects a --slsDir that is not an SLS dir', async function () { + const stderr = await runCliExpectingFailure([ + 'start', + `--slsDir=${path.join(tmpDir, 'not-an-sls-dir')}`, + ]); + expect( + stderr, + 'a directory without the SLS files should be rejected', + ).to.include('not a disaggregated-storage-capable MongoDB build'); + }); }); diff --git a/packages/mongodb-runner/src/cli.ts b/packages/mongodb-runner/src/cli.ts index 6f217386..9d07d896 100644 --- a/packages/mongodb-runner/src/cli.ts +++ b/packages/mongodb-runner/src/cli.ts @@ -84,15 +84,15 @@ import type { MongoClientOptions } from 'mongodb'; type: 'string', describe: 'Configure OIDC authentication on the server', }) - .option('slsCompose', { + .option('slsDir', { type: 'string', describe: - 'Path to an SLS multi-cell docker-compose.yml; launches the SLS DSC project and configures mongod to use it (requires a DSC-capable mongod via --binDir or --downloadUrl)', + 'Path to an SLS dir: its buildscripts/modules/atlas directory, or any parent containing it (an installed build or a Server source checkout). Locates the compose file and reads the image tag from the manifest', }) .option('slsImageTag', { type: 'string', describe: - 'SLS docker image tag to use with --slsCompose (defaults to the pinned_sls_commit from the manifest.json next to the compose file)', + 'SLS docker image tag to use (defaults to the pinned_sls_commit from the manifest.json next to the compose file)', }) .option('debug', { type: 'boolean', describe: 'Enable debug output' }) .option('verbose', { type: 'boolean', describe: 'Enable verbose output' }) @@ -135,10 +135,26 @@ import type { MongoClientOptions } from 'mongodb'; ); } + async function resolveSlsComposeFile(): Promise { + if (argv.slsDir === undefined) { + return undefined; + } + if (!argv.slsDir) { + throw new Error( + '--slsDir requires a path to a directory containing the SLS services docker compose file and other helper files - see the disaggregated storage docs for more details', + ); + } + const resolved = await utilities.resolveSLSDir(argv.slsDir, { + requireManifest: !argv.slsImageTag, + }); + return resolved.composeFile; + } + async function start() { - const disaggregatedStorage = argv.slsCompose + const composeFile = await resolveSlsComposeFile(); + const disaggregatedStorage = composeFile ? await utilities.createSLSDisaggregatedStorageOptions({ - composeFile: argv.slsCompose, + composeFile, imageTag: argv.slsImageTag, }) : undefined; diff --git a/packages/mongodb-runner/src/index.ts b/packages/mongodb-runner/src/index.ts index 870df0f3..a96e0cc7 100644 --- a/packages/mongodb-runner/src/index.ts +++ b/packages/mongodb-runner/src/index.ts @@ -25,6 +25,8 @@ export { type SLSDisaggregatedStorageSetupOptions, parseSLSComposeServices, readPinnedSlsCommit, + resolveSLSDir, + SLS_ATLAS_SUBDIR, SLS_HOSTNAME, SLS_CELL1, SLS_CELL2, @@ -33,6 +35,8 @@ export { type SLSServiceInfo, type SLSMultiCellEnvironment, type SLSMultiCellEnvironmentOptions, + type SLSDir, + type ResolveSLSDirOptions, } from './sls'; export { DockerComposeProject, diff --git a/packages/mongodb-runner/src/sls.spec.ts b/packages/mongodb-runner/src/sls.spec.ts index 8a433e1c..c97fe211 100644 --- a/packages/mongodb-runner/src/sls.spec.ts +++ b/packages/mongodb-runner/src/sls.spec.ts @@ -6,6 +6,7 @@ import { createSLSDisaggregatedStorageOptions, createSLSMultiCellEnvironment, readPinnedSlsCommit, + resolveSLSDir, } from './sls'; import { allocatePorts, uuid } from './util'; import { isBindable } from '../test/helpers'; @@ -55,6 +56,124 @@ describe('sls', function () { }); }); + describe('resolveSLSDir', function () { + it('resolves an SLS dir addressed by install root', async function () { + const root = path.join(FIXTURES, 'sls-dir-complete'); + const slsDir = await resolveSLSDir(root); + expect( + slsDir.composeFile, + 'compose file should be found under buildscripts/modules/atlas', + ).to.equal( + path.join( + root, + 'buildscripts', + 'modules', + 'atlas', + 'sls-multicell-docker-compose.yml', + ), + ); + expect( + slsDir.manifestFile, + 'manifest should sit next to the compose file', + ).to.equal(path.join(slsDir.atlasDir, 'manifest.json')); + }); + + it('resolves an SLS dir addressed by its atlas directory', async function () { + const atlasDir = path.join( + FIXTURES, + 'sls-dir-complete', + 'buildscripts', + 'modules', + 'atlas', + ); + const slsDir = await resolveSLSDir(atlasDir); + expect( + slsDir.atlasDir, + 'passing the atlas dir directly should also work', + ).to.equal(atlasDir); + }); + + it('lists every missing file, not just the first', async function () { + const err = await resolveSLSDir( + path.join(FIXTURES, 'sls-dir-incomplete'), + ).catch((e: Error) => e); + const message = (err as Error).message; + expect( + message, + 'error should say this is not a disagg-capable build', + ).to.include('not a disaggregated-storage-capable MongoDB build'); + expect(message, 'should report the missing proto').to.include( + 'slsbackup.proto', + ); + expect(message, 'should report the missing flags state too').to.include( + 'flags-state.json', + ); + }); + + it('rejects a required file that is actually a directory', async function () { + const err = await resolveSLSDir( + path.join(FIXTURES, 'sls-dir-dir-placeholder'), + ).catch((e: Error) => e); + expect( + (err as Error).message, + 'a directory named like a required file should be reported missing', + ).to.include('slsbackup.proto'); + }); + + it('rejects a directory that is not a MongoDB build', async function () { + const err = await resolveSLSDir(path.join(FIXTURES, 'not-a-build')).catch( + (e: Error) => e, + ); + expect( + (err as Error).message, + 'a non-build directory should be rejected clearly', + ).to.include('not a disaggregated-storage-capable MongoDB build'); + }); + + it('returns absolute paths for a relative directory', async function () { + const relative = path.relative( + process.cwd(), + path.join(FIXTURES, 'sls-dir-complete'), + ); + const slsDir = await resolveSLSDir(relative); + expect( + path.isAbsolute(slsDir.composeFile), + 'the compose file must be absolute so it survives a change of cwd', + ).to.be.true; + expect( + path.isAbsolute(slsDir.atlasDir), + 'the atlas dir must be absolute too', + ).to.be.true; + }); + + it('requires a manifest by default', async function () { + const err = await resolveSLSDir( + path.join(FIXTURES, 'sls-dir-no-manifest'), + ).catch((e: Error) => e); + expect( + (err as Error).message, + 'a missing manifest should be reported by default', + ).to.include('manifest.json'); + }); + + it('allows a missing manifest when the tag is supplied', async function () { + const dir = path.join(FIXTURES, 'sls-dir-no-manifest'); + const slsDir = await resolveSLSDir(dir, { requireManifest: false }); + expect( + slsDir.composeFile, + 'the compose file should still be located without a manifest', + ).to.equal( + path.join( + dir, + 'buildscripts', + 'modules', + 'atlas', + 'sls-multicell-docker-compose.yml', + ), + ); + }); + }); + describe('createSLSMultiCellEnvironment', function () { let tmpDir: string; let composeFile: string; diff --git a/packages/mongodb-runner/src/sls.ts b/packages/mongodb-runner/src/sls.ts index 5eada7e5..645ad864 100644 --- a/packages/mongodb-runner/src/sls.ts +++ b/packages/mongodb-runner/src/sls.ts @@ -63,6 +63,96 @@ export async function readPinnedSlsCommit(atlasDir: string): Promise { return pinned; } +/** Relative path of the atlas module directory inside a Server build. */ +export const SLS_ATLAS_SUBDIR = path.join('buildscripts', 'modules', 'atlas'); + +const SLS_COMPOSE_FILE = 'sls-multicell-docker-compose.yml'; +const SLS_BACKUP_PROTO_FILE = 'slsbackup.proto'; +const SLS_FLAGS_STATE_FILE = 'flags-state.json'; + +/** Files that make up the SLS dir of a disaggregated-storage-capable build. */ +export interface SLSDir { + /** The `buildscripts/modules/atlas` directory holding the SLS files. */ + atlasDir: string; + composeFile: string; + manifestFile: string; + backupProtoFile: string; + flagsStateFile: string; +} + +async function exists(file: string): Promise { + try { + await fs.access(file); + return true; + } catch { + return false; + } +} + +async function isFile(file: string): Promise { + try { + // fs.stat follows symlinks, so a symlink to a file still counts. + return (await fs.stat(file)).isFile(); + } catch { + return false; + } +} + +export interface ResolveSLSDirOptions { + /** + * Whether `manifest.json` must be present. It is only read to derive the + * default image tag, so callers that pass an explicit tag can skip it. + * Defaults to true. + */ + requireManifest?: boolean; +} + +/** + * Locate the SLS dir inside a disaggregated-storage-capable MongoDB build. + * `dir` may be either the install root or the `buildscripts/modules/atlas` + * directory itself. All returned paths are absolute, so they remain valid + * when the SLS project is torn down from a different working directory. + */ +export async function resolveSLSDir( + dir: string, + options: ResolveSLSDirOptions = {}, +): Promise { + const base = path.resolve(dir); + const nested = path.join(base, SLS_ATLAS_SUBDIR); + const atlasDir = (await exists(nested)) ? nested : base; + + const slsDir: SLSDir = { + atlasDir, + composeFile: path.join(atlasDir, SLS_COMPOSE_FILE), + manifestFile: path.join(atlasDir, SLS_MANIFEST_FILE), + backupProtoFile: path.join(atlasDir, SLS_BACKUP_PROTO_FILE), + flagsStateFile: path.join(atlasDir, SLS_FLAGS_STATE_FILE), + }; + + const required = [ + slsDir.composeFile, + slsDir.backupProtoFile, + slsDir.flagsStateFile, + ]; + if (options.requireManifest ?? true) { + required.splice(1, 0, slsDir.manifestFile); + } + + const missing: string[] = []; + for (const file of required) { + if (!(await isFile(file))) missing.push(path.basename(file)); + } + if (missing.length) { + throw new Error( + `${dir} is not a disaggregated-storage-capable MongoDB build ` + + `(missing: ${missing.join(', ')}; looked in ${atlasDir})`, + ); + } + + debug('resolved SLS dir', { atlasDir }); + return slsDir; +} + export interface SLSServiceInfo { /** Environment variable through which the compose file receives the host port. */ portVar: string; @@ -173,7 +263,7 @@ export interface SLSMultiCellEnvironment { export async function createSLSMultiCellEnvironment( options: SLSMultiCellEnvironmentOptions, ): Promise { - const { composeFile } = options; + const composeFile = path.resolve(options.composeFile); const imageTag = options.imageTag ?? (await readPinnedSlsCommit(path.dirname(composeFile))); diff --git a/packages/mongodb-runner/test/fixtures/sls/not-a-build/.gitkeep b/packages/mongodb-runner/test/fixtures/sls/not-a-build/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/packages/mongodb-runner/test/fixtures/sls/sls-dir-complete/buildscripts/modules/atlas/flags-state.json b/packages/mongodb-runner/test/fixtures/sls/sls-dir-complete/buildscripts/modules/atlas/flags-state.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/mongodb-runner/test/fixtures/sls/sls-dir-complete/buildscripts/modules/atlas/flags-state.json @@ -0,0 +1 @@ +{} diff --git a/packages/mongodb-runner/test/fixtures/sls/sls-dir-complete/buildscripts/modules/atlas/manifest.json b/packages/mongodb-runner/test/fixtures/sls/sls-dir-complete/buildscripts/modules/atlas/manifest.json new file mode 100644 index 00000000..1f5ab420 --- /dev/null +++ b/packages/mongodb-runner/test/fixtures/sls/sls-dir-complete/buildscripts/modules/atlas/manifest.json @@ -0,0 +1 @@ +{ "pinned_sls_commit": "slsdircommit123" } diff --git a/packages/mongodb-runner/test/fixtures/sls/sls-dir-complete/buildscripts/modules/atlas/sls-multicell-docker-compose.yml b/packages/mongodb-runner/test/fixtures/sls/sls-dir-complete/buildscripts/modules/atlas/sls-multicell-docker-compose.yml new file mode 100644 index 00000000..a317d36f --- /dev/null +++ b/packages/mongodb-runner/test/fixtures/sls/sls-dir-complete/buildscripts/modules/atlas/sls-multicell-docker-compose.yml @@ -0,0 +1,4 @@ +services: + cms-cell1-0: + ports: + - '${CMS_CELL1_0_PORT:-30001}:27998' diff --git a/packages/mongodb-runner/test/fixtures/sls/sls-dir-complete/buildscripts/modules/atlas/slsbackup.proto b/packages/mongodb-runner/test/fixtures/sls/sls-dir-complete/buildscripts/modules/atlas/slsbackup.proto new file mode 100644 index 00000000..ff7bd09c --- /dev/null +++ b/packages/mongodb-runner/test/fixtures/sls/sls-dir-complete/buildscripts/modules/atlas/slsbackup.proto @@ -0,0 +1 @@ +// placeholder diff --git a/packages/mongodb-runner/test/fixtures/sls/sls-dir-dir-placeholder/buildscripts/modules/atlas/flags-state.json b/packages/mongodb-runner/test/fixtures/sls/sls-dir-dir-placeholder/buildscripts/modules/atlas/flags-state.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/mongodb-runner/test/fixtures/sls/sls-dir-dir-placeholder/buildscripts/modules/atlas/flags-state.json @@ -0,0 +1 @@ +{} diff --git a/packages/mongodb-runner/test/fixtures/sls/sls-dir-dir-placeholder/buildscripts/modules/atlas/manifest.json b/packages/mongodb-runner/test/fixtures/sls/sls-dir-dir-placeholder/buildscripts/modules/atlas/manifest.json new file mode 100644 index 00000000..1f5ab420 --- /dev/null +++ b/packages/mongodb-runner/test/fixtures/sls/sls-dir-dir-placeholder/buildscripts/modules/atlas/manifest.json @@ -0,0 +1 @@ +{ "pinned_sls_commit": "slsdircommit123" } diff --git a/packages/mongodb-runner/test/fixtures/sls/sls-dir-dir-placeholder/buildscripts/modules/atlas/sls-multicell-docker-compose.yml b/packages/mongodb-runner/test/fixtures/sls/sls-dir-dir-placeholder/buildscripts/modules/atlas/sls-multicell-docker-compose.yml new file mode 100644 index 00000000..a317d36f --- /dev/null +++ b/packages/mongodb-runner/test/fixtures/sls/sls-dir-dir-placeholder/buildscripts/modules/atlas/sls-multicell-docker-compose.yml @@ -0,0 +1,4 @@ +services: + cms-cell1-0: + ports: + - '${CMS_CELL1_0_PORT:-30001}:27998' diff --git a/packages/mongodb-runner/test/fixtures/sls/sls-dir-dir-placeholder/buildscripts/modules/atlas/slsbackup.proto/.gitkeep b/packages/mongodb-runner/test/fixtures/sls/sls-dir-dir-placeholder/buildscripts/modules/atlas/slsbackup.proto/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/packages/mongodb-runner/test/fixtures/sls/sls-dir-incomplete/buildscripts/modules/atlas/manifest.json b/packages/mongodb-runner/test/fixtures/sls/sls-dir-incomplete/buildscripts/modules/atlas/manifest.json new file mode 100644 index 00000000..1f5ab420 --- /dev/null +++ b/packages/mongodb-runner/test/fixtures/sls/sls-dir-incomplete/buildscripts/modules/atlas/manifest.json @@ -0,0 +1 @@ +{ "pinned_sls_commit": "slsdircommit123" } diff --git a/packages/mongodb-runner/test/fixtures/sls/sls-dir-incomplete/buildscripts/modules/atlas/sls-multicell-docker-compose.yml b/packages/mongodb-runner/test/fixtures/sls/sls-dir-incomplete/buildscripts/modules/atlas/sls-multicell-docker-compose.yml new file mode 100644 index 00000000..a317d36f --- /dev/null +++ b/packages/mongodb-runner/test/fixtures/sls/sls-dir-incomplete/buildscripts/modules/atlas/sls-multicell-docker-compose.yml @@ -0,0 +1,4 @@ +services: + cms-cell1-0: + ports: + - '${CMS_CELL1_0_PORT:-30001}:27998' diff --git a/packages/mongodb-runner/test/fixtures/sls/sls-dir-no-manifest/buildscripts/modules/atlas/flags-state.json b/packages/mongodb-runner/test/fixtures/sls/sls-dir-no-manifest/buildscripts/modules/atlas/flags-state.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/mongodb-runner/test/fixtures/sls/sls-dir-no-manifest/buildscripts/modules/atlas/flags-state.json @@ -0,0 +1 @@ +{} diff --git a/packages/mongodb-runner/test/fixtures/sls/sls-dir-no-manifest/buildscripts/modules/atlas/sls-multicell-docker-compose.yml b/packages/mongodb-runner/test/fixtures/sls/sls-dir-no-manifest/buildscripts/modules/atlas/sls-multicell-docker-compose.yml new file mode 100644 index 00000000..a317d36f --- /dev/null +++ b/packages/mongodb-runner/test/fixtures/sls/sls-dir-no-manifest/buildscripts/modules/atlas/sls-multicell-docker-compose.yml @@ -0,0 +1,4 @@ +services: + cms-cell1-0: + ports: + - '${CMS_CELL1_0_PORT:-30001}:27998' diff --git a/packages/mongodb-runner/test/fixtures/sls/sls-dir-no-manifest/buildscripts/modules/atlas/slsbackup.proto b/packages/mongodb-runner/test/fixtures/sls/sls-dir-no-manifest/buildscripts/modules/atlas/slsbackup.proto new file mode 100644 index 00000000..ff7bd09c --- /dev/null +++ b/packages/mongodb-runner/test/fixtures/sls/sls-dir-no-manifest/buildscripts/modules/atlas/slsbackup.proto @@ -0,0 +1 @@ +// placeholder