Skip to content
Open
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
24 changes: 24 additions & 0 deletions PACKAGE-INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,30 @@

Repository-backed installation commands for DocumentDB.

> This repository serves v0.117-0. v1.0-RC1 is for testing only, gets no fixes (those go into
> RC2 or 1.0), has no upgrade path, and isn't in this repository; see
> [Try the 1.0 release candidate](https://documentdb.io/docs/getting-started/release-candidate/).

## Clean-host installer

On a clean Ubuntu 24.04 or EL9 host, download and run the installer:

```sh
curl -fsSLo documentdb-install.sh https://documentdb.io/install.sh &&
sh documentdb-install.sh
```

The default installs from the stable repository, currently v0.117-0.
For disposable RC1 testing, run `sh documentdb-install.sh --version v1.0-RC1`
instead. Both modes default to PostgreSQL 18; use `--pg-major 17` to select 17.
The RC path downloads checksum-verified release assets without putting them in
the stable repository. Existing DocumentDB packages, configuration, or data
are refused for RC installation.

The website publishes the canonical engine installer using the commit and
checksum pinned in `scripts/publish-installer.mjs`. This pin is independent
of `DOCUMENTDB_VERSION`, which selects the stable package mirror.

## What is published

Starting with **v0.116-0**, DocumentDB ships a multi-package layout with a setup wizard and
Expand Down
25 changes: 24 additions & 1 deletion app/services/articleService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,28 @@ The current official release publishes the full stack — extension, gateway, se
> [!NOTE]
> Need another distribution or PostgreSQL major? We welcome community builds. Check out the matching release tag and use the version-parameterized [packaging scripts](https://github.com/documentdb/documentdb/blob/v0.117-0/packaging/README.md). \`build_packages.sh\` builds the extension, \`gateway/build_gateway_packages.sh\` builds the gateway, and \`build_extra_packages.sh\` builds the common, tools, stand-alone, and meta packages. PostgreSQL 15 is extension-only because the setup tools require PostgreSQL 16 or newer. These builds are on demand and are not official release assets hosted by documentdb.io.

> [!NOTE]
> Want to try DocumentDB 1.0? [v1.0-RC1](/docs/getting-started/release-candidate) is for testing only, gets no fixes (those go into RC2 or 1.0) and has no upgrade path. It isn't in the package repository, so the commands below install v0.117-0.

You do not need PostgreSQL already installed — the setup wizard creates and manages its own instance. The install does add the PGDG repository and pull PostgreSQL, PostGIS and around 160 packages (about 140 MB), so pick a host you are willing to have PGDG on.

## Clean-host installer

On a fresh Ubuntu 24.04 or EL9 host, download and run the installer:

\`\`\`sh
curl -fsSLo documentdb-install.sh https://documentdb.io/install.sh &&
sh documentdb-install.sh
\`\`\`

This defaults to the stable repository, currently v0.117-0, and PostgreSQL 18.
Use \`--pg-major 17\` to select PostgreSQL 17. For disposable RC1 testing,
run \`sh documentdb-install.sh --version v1.0-RC1\` instead. The RC path
downloads checksum-verified release assets and refuses existing DocumentDB
packages, configuration, or data. RC1 has no maintenance or supported upgrades.
See [RC instructions](/docs/getting-started/release-candidate) for details.
The manual repository commands below remain on the stable channel.

## Install

### Ubuntu 24.04, PostgreSQL 18 (APT)
Expand Down Expand Up @@ -392,7 +412,9 @@ It does **not** install the gateway, create a network endpoint for drivers, or r

Use the extension package for your PostgreSQL major: \`postgresql-N-documentdb\` on Ubuntu
or \`postgresqlN-documentdb\` on EL9. You own PostgreSQL configuration, extension activation,
and service restarts. Follow the matching release's [manual package instructions](https://github.com/documentdb/documentdb/blob/v0.117-0/packaging/README.md),
and service restarts. Create \`documentdb_extended_rum\` as well as \`documentdb\`:
\`CREATE EXTENSION documentdb CASCADE\` does not pull it in, and without it every index
creation fails. Follow the matching release's [manual package instructions](https://github.com/documentdb/documentdb/blob/v0.117-0/packaging/README.md),
or the [extension-only offline instructions](/docs/linux-packages/offline#smaller-offline-cases)
when PostgreSQL and all extension dependencies are already installed.

Expand Down Expand Up @@ -1239,6 +1261,7 @@ The \`latest\` tag is a convenience alias. Pin an explicit tag for anything repr
| \`ghcr.io/documentdb/documentdb/documentdb-local:pg18-0.117.0\` | DocumentDB 0.117.0 on PostgreSQL 18 |
| \`…:pg17-0.117.0\` | DocumentDB 0.117.0 on PostgreSQL 17 |
| \`…:pg16-0.117.0\` · \`…:pg15-0.117.0\` | PostgreSQL 16 and 15 |
| \`…:pg15-1.0.0-rc1\` · \`…:pg16-1.0.0-rc1\` · \`…:pg17-1.0.0-rc1\` · \`…:pg18-1.0.0-rc1\` | [v1.0-RC1](https://github.com/documentdb/documentdb/releases/tag/v1.0-RC1), for testing only, with [no fixes to RC1 and no upgrade path](/docs/getting-started/release-candidate). No date for 1.0 yet. Use a new, empty data volume. The \`pgNN-1.0.0\` tags point at the same images today but will move to the final 1.0 build. |
| \`…:latest\` | Currently identical to \`pg17-0.117.0\` |

> \`latest\` tracks **PostgreSQL 17**, while the \`documentdb\` package on Linux pins
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"private": true,
"scripts": {
"dev": "npm run compile && next dev --turbopack",
"build": "npm run build:next && npm run build:blogs && npm run build:sitemap",
"build": "npm run build:next && npm run build:blogs && npm run build:sitemap && npm run build:installer",
"build:installer": "node scripts/publish-installer.mjs",
"build:next": "npm run compile && next build --turbopack",
"build:blogs": "bundle exec jekyll build --config blogs/_config.yml --source blogs --destination out/blogs --baseurl \"${JEKYLL_BASE_PATH:-/blogs}\"",
"build:sitemap": "node scripts/generate-sitemap.mjs",
Expand Down
32 changes: 32 additions & 0 deletions scripts/publish-installer.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { createHash } from 'node:crypto';
import { mkdir, writeFile } from 'node:fs/promises';
import { resolve } from 'node:path';
import { pathToFileURL } from 'node:url';

export const installerSource = {
revision: '2b0321c94daebdd6a5327b641069af0d0036997b',
sha256: 'b42077317d3eed19ac6090b757c59ce20b2f6a07b912cd4e134fd4cef7e3da0c',
};

export async function publishInstaller(outputDirectory = 'out') {
if (!/^[a-f0-9]{40}$/.test(installerSource.revision) ||
!/^[a-f0-9]{64}$/.test(installerSource.sha256)) {
throw new Error('Installer source must have a pinned commit and SHA256');
}
const url = `https://raw.githubusercontent.com/documentdb/documentdb/${installerSource.revision}/packaging/install.sh`;
const response = await fetch(url, { signal: AbortSignal.timeout(60_000) });
if (!response.ok) {
throw new Error(`Installer download failed: HTTP ${response.status}`);
}
const script = Buffer.from(await response.arrayBuffer());
const digest = createHash('sha256').update(script).digest('hex');
if (digest !== installerSource.sha256) {
throw new Error(`Installer checksum mismatch: ${digest}`);
}
await mkdir(outputDirectory, { recursive: true });
await writeFile(resolve(outputDirectory, 'install.sh'), script);
}

if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) {
await publishInstaller();
}
18 changes: 18 additions & 0 deletions tests/packageArticles.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
buildRpmInstallCommand,
buildSetupCommand,
} from '../app/lib/packageInstall';
import { FALLBACK_RELEASE } from '../app/lib/releaseInfo';

function getCodeBlocks(content: string, language: string): string[] {
const pattern = new RegExp('```' + language + '\\n([\\s\\S]*?)\\n```', 'g');
Expand Down Expand Up @@ -273,6 +274,23 @@ describe('Linux package articles', () => {
);
});

it('keeps package download and source links on the mirrored release', () => {
const tags = [
...`${linuxPackagesGuideContent}\n${linuxPackagesOperationsContent}`.matchAll(/documentdb\/(?:releases\/download|blob)\/(v[^/]+)\//g),
].map((match) => match[1]);

expect(tags.length).toBeGreaterThan(0);
expect(new Set(tags)).toEqual(new Set([FALLBACK_RELEASE.tagName]));
});

it('keeps stable installation as the default and makes RC1 an explicit selection', () => {
expect(linuxPackagesGuideContent).toContain('https://documentdb.io/install.sh');
expect(linuxPackagesGuideContent).toContain('sh documentdb-install.sh --version v1.0-RC1');
expect(linuxPackagesGuideContent).toContain('defaults to the stable repository, currently v0.117-0');
expect(linuxPackagesGuideContent).toContain('refuses existing DocumentDB');
expect(linuxPackagesGuideContent).toContain('RC1 has no maintenance or supported upgrades');
});

it('uses the current release package guide and artifact version', () => {
const offlineGuide = getArticleByPath('linux-packages', ['offline']);

Expand Down
65 changes: 65 additions & 0 deletions tests/publishInstaller.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { afterEach, describe, expect, it, vi } from 'vitest';
import { createHash } from 'node:crypto';
import { mkdtemp, readFile, rm } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import path from 'node:path';
import { installerSource, publishInstaller } from '../scripts/publish-installer.mjs';

const originalSource = { ...installerSource };
const directories: string[] = [];
const script = '#!/bin/sh\nprintf "installer fixture\\n"\n';

async function outputDirectory() {
const directory = await mkdtemp(path.join(tmpdir(), 'documentdb-installer-'));
directories.push(directory);
return directory;
}

afterEach(async () => {
Object.assign(installerSource, originalSource);
vi.unstubAllGlobals();
await Promise.all(directories.splice(0).map((directory) => rm(directory, { recursive: true })));
});

describe('published installer', () => {
it('pins the engine revision and checksum independently of the stable package channel', () => {
expect(installerSource.revision).toMatch(/^[a-f0-9]{40}$/);
expect(installerSource.sha256).toMatch(/^[a-f0-9]{64}$/);
});

it('publishes the verified bytes without changing the execution barrier', async () => {
installerSource.revision = 'a'.repeat(40);
installerSource.sha256 = createHash('sha256').update(script).digest('hex');
const download = vi.fn().mockResolvedValue(new Response(script));
vi.stubGlobal('fetch', download);
const directory = await outputDirectory();
await publishInstaller(directory);
expect(await readFile(path.join(directory, 'install.sh'), 'utf8')).toBe(script);
expect(download.mock.calls[0][0]).toBe(
`https://raw.githubusercontent.com/documentdb/documentdb/${'a'.repeat(40)}/packaging/install.sh`,
);
});

it.each(['HTTP error', 'checksum mismatch', 'network error'])('refuses %s without publishing', async (failure) => {
installerSource.revision = 'a'.repeat(40);
installerSource.sha256 = '0'.repeat(64);
const download = vi.fn();
if (failure === 'network error') {
download.mockRejectedValue(new Error('network error'));
} else {
download.mockResolvedValue(new Response(script, { status: failure === 'HTTP error' ? 404 : 200 }));
}
vi.stubGlobal('fetch', download);
const directory = await outputDirectory();
await expect(publishInstaller(directory)).rejects.toThrow();
await expect(readFile(path.join(directory, 'install.sh'))).rejects.toThrow();
});

it('rejects a moving source reference before downloading', async () => {
installerSource.revision = 'main';
const download = vi.fn();
vi.stubGlobal('fetch', download);
await expect(publishInstaller(await outputDirectory())).rejects.toThrow('pinned commit');
expect(download).not.toHaveBeenCalled();
});
});
Loading