Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
resources/cidrs.json
packages/mongodb-schema/examples/fanclub.json
packages/mongodb-runner/test/fixtures/sls/malformed/manifest.json
1 change: 1 addition & 0 deletions packages/mongodb-runner/.prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.nyc_output
dist
coverage
test/fixtures/sls/malformed
24 changes: 12 additions & 12 deletions packages/mongodb-runner/docs/disaggregated-storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,24 +70,23 @@ override.
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 image tag to use, typically the `pinned_sls_commit` from
`buildscripts/modules/atlas/manifest.json` in the mongodb server repository.
- 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
override it.

## Quick start

Given the compose file and image tag, everything else (compose environment
Given the compose file, 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`:

```bash
# 1. Look up the pinned SLS image tag
SLS_IMAGE_TAG=$(python3 -c "import json; print(json.load(open('$MONGO_REPO/buildscripts/modules/atlas/manifest.json'))['pinned_sls_commit'])")

# 2. Start a 2-node replica set backed by SLS (logs in to ECR automatically)
# The image tag is read from the manifest.json next to the compose file; pass
# --slsImageTag to override it. Logs in to ECR automatically.
@mongodb-js/mongodb-runner start -t replset \
--slsCompose=$MONGO_REPO/buildscripts/modules/atlas/sls-multicell-docker-compose.yml \
--slsImageTag=$SLS_IMAGE_TAG \
--binDir=/path/to/dsc-mongod/bin \
--debug
# or, instead of --binDir:
Expand Down Expand Up @@ -227,7 +226,8 @@ from the server codebase and returns:
| `ports` | The allocated host port per service, e.g. `ports['crs-cell1-0']` |
| `services` | Host `addr`/`uri` per service, e.g. `services['cms-cell1-0'].uri` |

Required options: `composeFile`, `imageTag`. Optional: `imageRepo`,
Required options: `composeFile`. Optional: `imageTag` (defaults to the
`pinned_sls_commit` from the manifest next to the compose file), `imageRepo`,
`thirdPartyImageRepo`, `testDataId` (container label for test attribution),
`hostInternalIP`. The service list is parsed from the compose file's
`ports:` mappings (`parseSLSComposeServices`), so it adapts to whatever
Expand All @@ -241,13 +241,13 @@ server parameter for one shard; options: `logId`, `cellMetadataService`,

## CLI use

For an SLS project, `--slsCompose` + `--slsImageTag` handle everything (see
Quick start):
For an SLS project, `--slsCompose` 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 \
--slsImageTag=<tag> --binDir=...
--binDir=...
```

Custom (non-SLS) storage backends are only supported through the programmatic
Expand Down
5 changes: 2 additions & 3 deletions packages/mongodb-runner/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,11 @@ import type { MongoClientOptions } from 'mongodb';
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)',
implies: 'slsImageTag',
})
.option('slsImageTag', {
type: 'string',
describe:
'SLS docker image tag to use with --slsCompose (e.g. the pinned_sls_commit from the server repo manifest)',
'SLS docker image tag to use with --slsCompose (defaults to the pinned_sls_commit from the manifest.json next to the compose file)',
})
.option('slsSkipEcrLogin', {
type: 'boolean',
Expand Down Expand Up @@ -139,7 +138,7 @@ import type { MongoClientOptions } from 'mongodb';
const disaggregatedStorage = argv.slsCompose
? await utilities.createSLSDisaggregatedStorageOptions({
composeFile: argv.slsCompose,
imageTag: argv.slsImageTag!,
imageTag: argv.slsImageTag,
ecrLogin: !argv.slsSkipEcrLogin,
})
: undefined;
Expand Down
1 change: 1 addition & 0 deletions packages/mongodb-runner/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export {
type SLSDisaggregatedStorageConfigOptions,
type SLSDisaggregatedStorageSetupOptions,
parseSLSComposeServices,
readPinnedSlsCommit,
SLS_HOSTNAME,
SLS_CELL1,
SLS_CELL2,
Expand Down
47 changes: 47 additions & 0 deletions packages/mongodb-runner/src/sls.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { expect } from 'chai';
import path from 'path';
import { readPinnedSlsCommit } from './sls';

const FIXTURES = path.resolve(__dirname, '..', 'test', 'fixtures', 'sls');

describe('readPinnedSlsCommit', function () {
it('reads pinned_sls_commit from a manifest', async function () {
expect(
await readPinnedSlsCommit(path.join(FIXTURES, 'complete')),
'should return the pinned commit verbatim',
).to.equal('abc123def456');
});

it('names the path it looked at when the manifest is absent', async function () {
const missing = path.join(FIXTURES, 'does-not-exist');
const err = await readPinnedSlsCommit(missing).catch((e: Error) => e);
expect(
(err as Error).message,
'error should name the manifest path that was checked',
).to.include(path.join(missing, 'manifest.json'));
expect(
(err as Error).message,
'error should mention the override flag',
).to.include('--slsImageTag');
});

it('reports a manifest that is missing the key', async function () {
const err = await readPinnedSlsCommit(path.join(FIXTURES, 'no-key')).catch(
(e: Error) => e,
);
expect(
(err as Error).message,
'error should name the missing key',
).to.include('pinned_sls_commit');
});

it('reports a malformed manifest', async function () {
const err = await readPinnedSlsCommit(
path.join(FIXTURES, 'malformed'),
).catch((e: Error) => e);
expect(
(err as Error).message,
'error should say the manifest could not be parsed',
).to.match(/parse/i);
});
});
48 changes: 44 additions & 4 deletions packages/mongodb-runner/src/sls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,44 @@ export const SLS_HOSTNAME = 'local.sls.mmscloudteam.com';
const DEFAULT_SLS_IMAGE_REPO =
'664315256653.dkr.ecr.us-east-1.amazonaws.com/disagg-storage/';

/** Name of the build manifest inside a Server build's atlas module directory. */
export const SLS_MANIFEST_FILE = 'manifest.json';

/**
* Read `pinned_sls_commit` from a Server build's
* `buildscripts/modules/atlas/manifest.json`. This is the SLS image tag
* matching the commit the binaries were built from.
*/
export async function readPinnedSlsCommit(atlasDir: string): Promise<string> {
const manifestPath = path.join(atlasDir, SLS_MANIFEST_FILE);
let contents: string;
try {
contents = await fs.readFile(manifestPath, 'utf8');
} catch (err) {
throw new Error(
`Could not read the SLS build manifest at ${manifestPath}: ` +
`${(err as Error).message}. Pass --slsImageTag explicitly to skip this lookup.`,
);
}
let manifest: unknown;
try {
manifest = JSON.parse(contents);
} catch (err) {
throw new Error(
`Could not parse the SLS build manifest at ${manifestPath}: ` +
`${(err as Error).message}. Pass --slsImageTag explicitly to skip this lookup.`,
);
}
const pinned = (manifest as Record<string, unknown>)?.pinned_sls_commit;
if (typeof pinned !== 'string' || !pinned) {
throw new Error(
`The SLS build manifest at ${manifestPath} has no pinned_sls_commit key. ` +
`Pass --slsImageTag explicitly to skip this lookup.`,
);
}
return pinned;
}

export interface SLSServiceInfo {
/** Environment variable through which the compose file receives the host port. */
portVar: string;
Expand Down Expand Up @@ -96,10 +134,10 @@ export interface SLSMultiCellEnvironmentOptions {
*/
composeFile: string;
/**
* Image tag for the SLS images (typically the `pinned_sls_commit` from the
* server repository's buildscripts/modules/atlas/manifest.json).
* Image tag for the SLS images. Defaults to the `pinned_sls_commit` from
* the `manifest.json` sitting next to the compose file.
*/
imageTag: string;
imageTag?: string;
/** Docker image repository for SLS images. */
imageRepo?: string;
/** Docker image repository for third-party images (default: imageRepo with 'disagg-storage' replaced by 'thirdparty'). */
Expand Down Expand Up @@ -130,7 +168,9 @@ export interface SLSMultiCellEnvironment {
export async function createSLSMultiCellEnvironment(
options: SLSMultiCellEnvironmentOptions,
): Promise<SLSMultiCellEnvironment> {
const { composeFile, imageTag } = options;
const { composeFile } = options;
const imageTag =
options.imageTag ?? (await readPinnedSlsCommit(path.dirname(composeFile)));
Comment on lines +172 to +173

const serviceInfo = parseSLSComposeServices(
await fs.readFile(composeFile, 'utf8'),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"pinned_sls_commit": "abc123def456",
"other_key": "ignored"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ this is not valid json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"other_key": "present but not the one we need"
}