diff --git a/.github/styles/config/vocabularies/embucket/accept.txt b/.github/styles/config/vocabularies/embucket/accept.txt index fd90266b..8d93fa86 100644 --- a/.github/styles/config/vocabularies/embucket/accept.txt +++ b/.github/styles/config/vocabularies/embucket/accept.txt @@ -48,3 +48,13 @@ unpatched deployer anonymized bootable +APIs? +ARNs? +[Dd]eployers? +CLI +[Ss]tatestore +GitLab +[Oo]pen-source +TLS +VPC +OTEL diff --git a/.github/workflows/docs-ci.yml b/.github/workflows/docs-ci.yml index a54f928b..27b28597 100644 --- a/.github/workflows/docs-ci.yml +++ b/.github/workflows/docs-ci.yml @@ -51,47 +51,10 @@ jobs: working-directory: ./docs run: pnpm prettier --check . - smoke: - name: Docs Smoke Checks - runs-on: ubuntu-latest - needs: [format] - steps: - - uses: actions/checkout@v6 - - name: Setup Node.js - uses: actions/setup-node@v6 - with: - node-version: "22" - - name: Setup PNPM - uses: pnpm/action-setup@v4 - with: - version: "10.11.0" - run_install: false - - name: Get pnpm store directory - id: pnpm-cache - shell: bash - run: | - echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT - - name: Setup pnpm cache - uses: actions/cache@v4 - with: - path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} - key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/docs/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store- - - name: Install dependencies - working-directory: ./docs - run: pnpm install - - name: Run Astro check - working-directory: ./docs - run: pnpm check - - name: Run docs smoke checks - working-directory: ./docs - run: pnpm smoke - build: name: Validate Build runs-on: ubuntu-latest - needs: [format, smoke] + needs: [format] steps: - uses: actions/checkout@v6 - name: Setup Node.js diff --git a/.gitignore b/.gitignore index 32751a99..a8774ed3 100644 --- a/.gitignore +++ b/.gitignore @@ -7,11 +7,10 @@ data/ .env metastore.yaml -# Ignore only the root styles directory; allow .github/styles for Vale -/styles/ -!/styles/config -!.github/styles/ -!.github/styles/** +# Vale styles — only keep custom vocabulary, ignore downloaded packages +.github/styles/Google/ +.github/styles/write-good/ +.github/styles/.vale-config/ **/*.rs.bk .DS_Store @@ -20,3 +19,4 @@ metastore.yaml .log metastore.yaml +docs/superpowers/ diff --git a/README.md b/README.md index a8120d18..25f178ad 100644 --- a/README.md +++ b/README.md @@ -1,109 +1,51 @@ # Embucket -Embucket exposes a Snowflake-compatible API over lakehouse data. The repo currently ships two runtime artifacts: +Embucket is a Snowflake-compatible query engine built on [Apache DataFusion](https://datafusion.apache.org/). It runs as an AWS Lambda function and uses S3 Tables (Apache Iceberg) for storage. Connect with any Snowflake-compatible tool or the [dbt-embucket](https://github.com/Embucket/dbt-embucket) adapter. -- `embucketd` for local and self-hosted runs -- `embucket-lambda` for AWS Lambda deployments +## Key features -## Choose your path +- Snowflake v1 REST API compatibility +- SQL dialect support via Apache DataFusion +- AWS Lambda serverless deployment +- S3 Tables (Iceberg/Parquet) storage +- Official dbt adapter for analytics workflows +- Snowflake CLI compatibility -- **Start locally** if you want the fastest test or evaluation loop. -- **Run from source** if you want to build `embucketd` yourself for local evaluation. -- **Deploy on AWS Lambda** if you want the current serverless runtime. -- **Connect dbt** if you want the recommended client path. -- **Run Snowplow web analytics** if you want a fuller example on the Lambda + dbt path. -- **Use S3 Tables** if you want the currently documented external catalog. -- **Troubleshoot** if your client, auth, or runtime setup does not behave as expected. +## Quick start -Relevant guides live under `docs/src/content/docs/`: - -- `essentials/quick-start.mdx` -- `essentials/runtime-modes.mdx` -- `guides/aws-lambda.mdx` -- `guides/dbt.mdx` -- `guides/self-hosted.mdx` -- `guides/snowplow.mdx` -- `guides/s3-tables.mdx` -- `guides/troubleshooting.mdx` - -If you want to build the local binary instead of using Docker, start with `docs/src/content/docs/guides/self-hosted.mdx`. - -If you want a fuller example on the recommended client path, start with `docs/src/content/docs/guides/snowplow.mdx`. - -## Support summary - -The current docs should make these distinctions explicit: - -- **Local mode** is the fastest path for tests and evaluation. -- **AWS Lambda + dbt-embucket** is verified and is the recommended client path. -- **AWS Lambda + Snowflake CLI over Function URL** is tested, but not production-ready because the Function URL is publicly reachable. -- **Production-facing Lambda deployments** should avoid a public Function URL. The AWS Lambda guide includes an anonymized private API Gateway example. -- **AWS S3 Tables** is the currently documented external catalog path. - -## Local quick start - -Run Embucket locally: +Run Embucket locally with Docker: ```bash docker run --name embucket --rm -p 3000:3000 embucket/embucket ``` -Expected startup log: - -```text -{"timestamp":"2025-07-01T15:35:05.687807Z","level":"INFO","fields":{"message":"Listening on http://0.0.0.0:3000"},"target":"embucketd"} -``` - -Configure Snowflake CLI for the local endpoint: +See the full [Quick Start guide](https://docs.embucket.com/getting-started/quick-start/) for next steps. -```bash -snow --info - -# Add this connection block to your Snowflake CLI config file. -[connections.local] -host = "localhost" -region = "us-east-2" -port = 3000 -protocol = "http" -database = "embucket" -schema = "public" -warehouse = "em.wh" -account = "acc.local" -user = "embucket" -password = "embucket" -``` +## Deploy -Validate the connection and run a query: +Deploy Embucket to AWS Lambda with the pre-built zip: ```bash -snow connection test -c local -snow sql -c local -q "SELECT 1 AS ok" +aws s3 cp s3://embucket-releases/lambda/embucket-lambda-latest.zip . ``` -You can also open `http://127.0.0.1:3000/` to inspect the current Swagger/OpenAPI surface served by `embucketd`. - -## AWS Lambda quick pointer +See the [AWS Lambda deployment guide](https://docs.embucket.com/deploy/aws-lambda/) for configuration and production setup. -If you want the current serverless path, start with `docs/src/content/docs/guides/aws-lambda.mdx`. - -The current runtime is built from `crates/embucket-lambda` and can be deployed with: - -```bash -make -C crates/embucket-lambda deploy -``` +## Connect -For test-only validation, you can expose a Function URL and connect Snowflake CLI to it. For production-facing traffic, keep the Lambda private and put an API gateway layer in front of it. +- **Snowflake CLI** -- connect any Snowflake-compatible client to your Embucket endpoint. See the [Snowflake CLI guide](https://docs.embucket.com/connect/snowflake-cli/). +- **dbt adapter** -- use `dbt-embucket` for analytics workflows. See the [dbt guide](https://docs.embucket.com/connect/dbt/). -## dbt quick pointer +## Documentation -If you want the recommended client workflow, start with `docs/src/content/docs/guides/dbt.mdx`. +- [Architecture](https://docs.embucket.com/reference/architecture/) +- [Snowflake compatibility](https://docs.embucket.com/reference/snowflake/) +- [Troubleshooting](https://docs.embucket.com/reference/troubleshooting/) -The official adapter lives in the sibling repository `Embucket/dbt-embucket` and uses: +## Contributing -- `type: embucket` -- `function_arn` to reach the deployed Lambda -- `dbt debug` and `dbt run` as the verified end-to-end checks +See [CONTRIBUTING.md](CONTRIBUTING.md). -## S3 Tables quick pointer +## License -The current docs treat AWS S3 Tables as the supported external catalog path. Start with `docs/src/content/docs/guides/s3-tables.mdx` for the YAML shape, AWS prerequisites, and query flow. +Embucket is licensed under the [Apache License 2.0](LICENSE). diff --git a/docs/README.md b/docs/README.md index 56f753d9..046ead14 100644 --- a/docs/README.md +++ b/docs/README.md @@ -38,15 +38,12 @@ To ensure everything is working correctly: ### Project structure ``` -. -├── public/ -├── src/ -│ ├── assets/ -│ ├── components/ -│ ├── content/ -│ │ ├── docs/ -│ └── content.config.ts -└── astro.config.mjs +docs/src/content/docs/ + getting-started/ — Quick Start + deploy/ — AWS Lambda, Configuration + connect/ — Snowflake CLI, dbt adapter + tutorials/ — Snowplow web analytics + reference/ — Architecture, Snowflake compatibility, Troubleshooting ``` Starlight looks for `.md` or `.mdx` files in the `src/content/docs/` directory. Each file is exposed as a route based on its filename. diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index fb94ae1e..13c3e006 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -18,16 +18,28 @@ export default defineConfig({ social: [{ icon: 'github', label: 'GitHub', href: 'https://github.com/embucket/embucket' }], sidebar: [ { - label: 'Essentials', - autogenerate: { directory: 'essentials' }, + label: 'Getting Started', + autogenerate: { directory: 'getting-started' }, }, { - label: 'Guides', - autogenerate: { directory: 'guides' }, + label: 'Deploy', + autogenerate: { directory: 'deploy' }, }, { - label: 'Development', - autogenerate: { directory: 'development' }, + label: 'Configuration', + autogenerate: { directory: 'configuration' }, + }, + { + label: 'Connect', + autogenerate: { directory: 'connect' }, + }, + { + label: 'Tutorials', + autogenerate: { directory: 'tutorials' }, + }, + { + label: 'Reference', + autogenerate: { directory: 'reference' }, }, ], customCss: ['./src/styles/global.css'], @@ -46,6 +58,21 @@ export default defineConfig({ plugins: [tailwindcss()], }, redirects: { - '/': '/essentials/quick-start/', + '/': '/getting-started/quick-start/', + '/essentials/quick-start/': '/getting-started/quick-start/', + '/essentials/architecture/': '/reference/architecture/', + '/essentials/configuration/': '/configuration/configuration/', + '/deploy/configuration/': '/configuration/configuration/', + '/essentials/runtime-modes/': '/deploy/aws-lambda/', + '/essentials/snowflake/': '/reference/snowflake/', + '/essentials/support-matrix/': '/deploy/aws-lambda/', + '/guides/aws-lambda/': '/deploy/aws-lambda/', + '/guides/dbt/': '/connect/dbt/', + '/guides/snowflake-cli/': '/connect/snowflake-cli/', + '/guides/snowplow/': '/tutorials/snowplow/', + '/guides/troubleshooting/': '/reference/troubleshooting/', + '/guides/s3-tables/': '/deploy/aws-lambda/', + '/guides/self-hosted/': '/getting-started/quick-start/', + '/guides/end-to-end-dbt/': '/connect/dbt/', }, }); diff --git a/docs/package.json b/docs/package.json index 14b71bc0..1cc5d3fb 100644 --- a/docs/package.json +++ b/docs/package.json @@ -11,7 +11,6 @@ "format": "prettier --write .", "ncu": "ncu -u", "preview": "astro preview", - "smoke": "node ./scripts/validate-docs-smoke.mjs", "start": "astro dev" }, "dependencies": { diff --git a/docs/scripts/validate-docs-smoke.mjs b/docs/scripts/validate-docs-smoke.mjs deleted file mode 100644 index 7487a6f9..00000000 --- a/docs/scripts/validate-docs-smoke.mjs +++ /dev/null @@ -1,113 +0,0 @@ -import { readFileSync } from 'node:fs'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const docsRoot = path.resolve(__dirname, '..'); -const repoRoot = path.resolve(docsRoot, '..'); - -function read(relativePath, base = repoRoot) { - return readFileSync(path.join(base, relativePath), 'utf8'); -} - -function assert(condition, message) { - if (!condition) { - throw new Error(message); - } -} - -function assertIncludes(content, expected, label) { - assert(content.includes(expected), `${label} is missing expected text: ${expected}`); -} - -const quickStart = read('docs/src/content/docs/essentials/quick-start.mdx'); -const snowflakeCli = read('docs/src/content/docs/guides/snowflake-cli.mdx'); -const troubleshooting = read('docs/src/content/docs/guides/troubleshooting.mdx'); -const runtimeModes = read('docs/src/content/docs/essentials/runtime-modes.mdx'); -const configuration = read('docs/src/content/docs/essentials/configuration.mdx'); -const supportMatrix = read('docs/src/content/docs/essentials/support-matrix.mdx'); -const dbtGuide = read('docs/src/content/docs/guides/dbt.mdx'); -const endToEndDbt = read('docs/src/content/docs/guides/end-to-end-dbt.mdx'); -const docsMaintenance = read('docs/src/content/docs/development/docs-maintenance.mdx'); -const awsLambda = read('docs/src/content/docs/guides/aws-lambda.mdx'); -const s3Tables = read('docs/src/content/docs/guides/s3-tables.mdx'); -const selfHosted = read('docs/src/content/docs/guides/self-hosted.mdx'); -const snowplow = read('docs/src/content/docs/guides/snowplow.mdx'); -const docsReadme = read('docs/README.md'); -const packageJson = JSON.parse(read('docs/package.json')); - -const highTrafficGuides = [ - 'docs/src/content/docs/essentials/quick-start.mdx', - 'docs/src/content/docs/essentials/runtime-modes.mdx', - 'docs/src/content/docs/guides/aws-lambda.mdx', - 'docs/src/content/docs/guides/dbt.mdx', - 'docs/src/content/docs/guides/end-to-end-dbt.mdx', - 'docs/src/content/docs/guides/self-hosted.mdx', - 'docs/src/content/docs/guides/snowplow.mdx', - 'docs/src/content/docs/guides/troubleshooting.mdx', -]; - -for (const guidePath of highTrafficGuides) { - const content = read(guidePath); - assert(/> Owner:/m.test(content), `${guidePath} must include an Owner block near the top`); - assert( - /> Last reviewed:/m.test(content), - `${guidePath} must include a Last reviewed block near the top`, - ); -} - -for (const [content, label] of [ - [quickStart, 'Quick Start'], - [snowflakeCli, 'Snowflake CLI guide'], - [troubleshooting, 'Troubleshooting guide'], -]) { - assertIncludes(content, 'embucket/embucket', label); - assertIncludes(content, '3000', label); - assertIncludes(content, 'embucket', label); -} - -assertIncludes(quickStart, 'http://127.0.0.1:3000/', 'Quick Start'); -assertIncludes(runtimeModes, 'private API Gateway example', 'Runtime modes'); -assertIncludes(configuration, 'METASTORE_CONFIG=./metastore.yaml', 'Configuration guide'); -assertIncludes(configuration, 'volumes: []', 'Configuration guide'); -assertIncludes(snowflakeCli, 'protocol = "http"', 'Snowflake CLI guide'); -assertIncludes(troubleshooting, 'protocol = "http"', 'Troubleshooting guide'); -assertIncludes(selfHosted, 'cargo build', 'Self-hosted guide'); -assertIncludes(selfHosted, 'target/debug/embucketd', 'Self-hosted guide'); -assertIncludes(selfHosted, 'snow connection test', 'Self-hosted guide'); -assertIncludes(selfHosted, 'evaluation and testing', 'Self-hosted guide'); -assertIncludes(selfHosted, 'METASTORE_CONFIG=./metastore.yaml', 'Self-hosted guide'); -assertIncludes(awsLambda, 'AWS::ApiGateway::RestApi', 'AWS Lambda guide'); -assertIncludes(awsLambda, 'AWS::EC2::VPCEndpoint', 'AWS Lambda guide'); -assertIncludes(snowplow, 'embucket-snowplow', 'Snowplow guide'); -assertIncludes(snowplow, 'dbt run', 'Snowplow guide'); -assertIncludes(snowplow, 'dbt show', 'Snowplow guide'); -assertIncludes(snowplow, 'compatibility workaround', 'Snowplow guide'); -assertIncludes(runtimeModes, '/guides/self-hosted/', 'Runtime modes'); -assertIncludes(runtimeModes, '/guides/snowplow/', 'Runtime modes'); -assertIncludes(supportMatrix, '/guides/self-hosted/', 'Support matrix'); -assertIncludes(supportMatrix, '/guides/snowplow/', 'Support matrix'); -assertIncludes(dbtGuide, '/guides/snowplow/', 'dbt guide'); -assertIncludes(endToEndDbt, '/guides/snowplow/', 'End-to-end dbt guide'); -assertIncludes(awsLambda, '/guides/snowplow/', 'AWS Lambda guide'); -assertIncludes(s3Tables, '/guides/snowplow/', 'S3 Tables guide'); -assertIncludes(docsMaintenance, 'Self-hosted local binary', 'Docs maintenance'); -assertIncludes(docsMaintenance, 'Snowplow web analytics', 'Docs maintenance'); - -const requiredCommands = [ - 'pnpm dev', - 'pnpm build', - 'pnpm preview', - 'pnpm astro', - 'pnpm format', - 'pnpm ncu', -]; -for (const command of requiredCommands) { - assertIncludes(docsReadme, command, 'docs/README.md'); -} - -for (const scriptName of ['astro', 'build', 'check', 'format', 'ncu', 'preview', 'smoke']) { - assert(scriptName in packageJson.scripts, `docs/package.json is missing script: ${scriptName}`); -} - -console.log('Docs smoke checks passed.'); diff --git a/docs/src/content/docs/configuration/configuration.mdx b/docs/src/content/docs/configuration/configuration.mdx new file mode 100644 index 00000000..3955c737 --- /dev/null +++ b/docs/src/content/docs/configuration/configuration.mdx @@ -0,0 +1,186 @@ +--- +title: Configuration +description: Environment variables, flags, and metastore settings for Embucket. +sidebar: + order: 0 +--- + +import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; + +This page covers every configuration option for Embucket, including CLI flags, environment variables, metastore YAML, and deploy-time settings. It doesn't cover connection setup for clients such as the Snowflake CLI or dbt. + +## Configuration precedence + +Embucket resolves each setting in the following order, from highest to lowest priority: + +1. **CLI flags** -- passed directly to the binary. +2. **Environment variables** -- exported in the shell or set in the container. +3. **`.env` file** -- loaded once at startup from the working directory. + +When the same setting appears at more than one level, the higher-priority source wins. + +## Core runtime settings + +| Purpose | Flag | Environment variable | Default | +| --------------------- | ------------------------- | ----------------------- | ----------- | +| Metastore config path | `--metastore-config` | `METASTORE_CONFIG` | unset | +| Bind host | `--host` | `BUCKET_HOST` | `localhost` | +| Bind port | `--port` | `BUCKET_PORT` | `3000` | +| Result serialization | `--data-format` | `DATA_FORMAT` | `json` | +| Parser dialect | `--sql-parser-dialect` | `SQL_PARSER_DIALECT` | `snowflake` | +| Query concurrency | `--max-concurrency-level` | `MAX_CONCURRENCY_LEVEL` | `8` | +| Query timeout | `--query-timeout-secs` | `QUERY_TIMEOUT_SECS` | `1200` | +| Demo user | `--auth-demo-user` | `AUTH_DEMO_USER` | `embucket` | +| Demo password | `--auth-demo-password` | `AUTH_DEMO_PASSWORD` | `embucket` | +| JWT signing secret | `--jwt-secret` | `JWT_SECRET` | unset | +| Tracing level | `--tracing-level` | `TRACING_LEVEL` | `info` | +| Service idle timeout | `--idle-timeout-seconds` | `IDLE_TIMEOUT_SECONDS` | `18000` | + +## Metastore configuration + +Embucket supports two ways to configure the metastore: a YAML configuration file or environment variables. The YAML file supports many volumes and full schema/table definitions. Environment variables configure a single volume and work well for simple deployments. + + + + +Set `METASTORE_CONFIG` to the path of a YAML file that defines volumes, databases, schemas, and tables. Embucket reads this file at startup and registers every declared object. + +A minimal configuration with no external volumes: + +```yaml +volumes: [] +``` + +**S3 Tables volume:** + +```yaml +volumes: + - ident: embucket + type: s3-tables + database: demo + credentials: + credential_type: access_key + aws-access-key-id: ACCESS_KEY + aws-secret-access-key: SECRET_ACCESS_KEY + arn: arn:aws:s3tables:us-east-2:123456789012:bucket/my-table-bucket +``` + +**External Iceberg tables on S3:** + +```yaml +volumes: + - ident: lakehouse + type: s3 + region: us-east-2 + bucket: YOUR_BUCKET_NAME + credentials: + credential_type: access_key + aws-access-key-id: YOUR_ACCESS_KEY + aws-secret-access-key: YOUR_SECRET_KEY + +databases: + - ident: demo + volume: lakehouse + +schemas: + - database: demo + schema: tpch_10 + +tables: + - database: demo + schema: tpch_10 + table: customer + metadata_location: s3://YOUR_BUCKET_NAME/tpch_10/customer/metadata/00001.metadata.json +``` + + + + +Set the following environment variables to configure a single volume without a YAML file. When you set `VOLUME_TYPE`, Embucket uses these variables instead of `METASTORE_CONFIG`. + +| Variable | Purpose | Default | +| ----------------- | ---------------------------------------------- | ---------- | +| `VOLUME_TYPE` | Storage backend: `s3tables`, `s3`, or `memory` | unset | +| `VOLUME_IDENT` | Volume identifier | `embucket` | +| `VOLUME_DATABASE` | Database name to associate with the volume | unset | + +{/* vale Google.Parens = NO */} + +**For S3 Tables (`VOLUME_TYPE=s3tables`):** + +| Variable | Purpose | Required | +| -------------------------- | --------------------- | -------- | +| `VOLUME_ARN` | S3 Tables bucket ARN | Yes | +| `VOLUME_ACCESS_KEY` | AWS access key ID | No | +| `VOLUME_SECRET_KEY` | AWS secret access key | No | +| `VOLUME_AWS_SESSION_TOKEN` | AWS session token | No | + +**For S3 (`VOLUME_TYPE=s3`):** + +| Variable | Purpose | Required | +| ------------------- | --------------------- | -------- | +| `VOLUME_ACCESS_KEY` | AWS access key ID | Yes | +| `VOLUME_SECRET_KEY` | AWS secret access key | Yes | + +{/* vale Google.Parens = YES */} + +Example for S3 Tables: + +```bash +export VOLUME_TYPE=s3tables +export VOLUME_IDENT=embucket +export VOLUME_DATABASE=demo +export VOLUME_ARN=arn:aws:s3tables:us-east-2:123456789012:bucket/my-table-bucket +export VOLUME_ACCESS_KEY=YOUR_ACCESS_KEY +export VOLUME_SECRET_KEY=YOUR_SECRET_KEY +``` + + + + +## Statestore settings + +When you enable the `state-store-query` feature, Embucket persists query state in DynamoDB. See [AWS Lambda deployment](/deploy/aws-lambda/) for how to enable this feature. Configure the table name and connection with the following variables. + +| Environment variable | Default | +| ------------------------------ | --------------------- | +| `STATESTORE_TABLE_NAME` | `embucket-statestore` | +| `STATESTORE_DYNAMODB_ENDPOINT` | unset | +| `AWS_DDB_ACCESS_KEY_ID` | unset | +| `AWS_DDB_SECRET_ACCESS_KEY` | unset | +| `AWS_DDB_SESSION_TOKEN` | unset | + +## Lambda deploy-time variables + +These variables control the Lambda packaging and deployment process. Set them before you run the deploy script. + +| Environment variable | Default | +| --------------------- | -------------------- | +| `FUNCTION_NAME` | `embucket-lambda` | +| `ENV_FILE` | `config/.env.lambda` | +| `AWS_LAMBDA_ROLE_ARN` | unset | +| `WITH_OTEL_CONFIG` | unset | +| `FEATURES` | unset | +| `LAYERS` | unset | + +## Memory and performance tuning + +Use these variables to adjust memory pools and network timeouts for your workload. + +| Environment variable | Default | +| ----------------------------------- | -------- | +| `MEM_POOL_TYPE` | `greedy` | +| `MEM_POOL_SIZE_MB` | unset | +| `DISK_POOL_SIZE_MB` | unset | +| `AWS_SDK_CONNECT_TIMEOUT_SECS` | `3` | +| `AWS_SDK_OPERATION_TIMEOUT_SECS` | `30` | +| `OBJECT_STORE_TIMEOUT_SECS` | `10` | +| `OBJECT_STORE_CONNECT_TIMEOUT_SECS` | `3` | + +## Authentication defaults + +Embucket ships with demo credentials for local development. The default username and password both equal `embucket`. Override them with `AUTH_DEMO_USER` and `AUTH_DEMO_PASSWORD` before you expose the service to any network beyond localhost. + + diff --git a/docs/src/content/docs/connect/dbt.mdx b/docs/src/content/docs/connect/dbt.mdx new file mode 100644 index 00000000..99fd6828 --- /dev/null +++ b/docs/src/content/docs/connect/dbt.mdx @@ -0,0 +1,173 @@ +--- +title: dbt adapter +description: Connect dbt to Embucket using the dbt-embucket adapter. +sidebar: + order: 1 +--- + +import { Aside, Steps } from '@astrojs/starlight/components'; + +[dbt](https://docs.getdbt.com/) provides a SQL-first transformation tool for analytics engineering. The `dbt-embucket` adapter connects to Embucket by invoking the Lambda function directly through AWS APIs, so no public endpoint proves necessary. + +## Prerequisites + +Before you begin, make sure you have the following: + +- **A deployed Embucket Lambda function** and its ARN. +- **AWS credentials** with permission to invoke the Lambda function. +- **Python 3.8 or later** and **dbt** installed on your system. + +{/* vale Vale.Terms = NO */} +{/* vale Google.Parens = NO */} + + +{/* vale Google.Parens = YES */} +{/* vale Vale.Terms = YES */} + +## Set up dbt with Embucket + + + +1. **Install the adapter** + + Install the `dbt-embucket` adapter from PyPI: + + ```bash + python -m pip install dbt-embucket + ``` + +2. **Create a minimal project** + + Create a project directory with a model: + + ```bash + mkdir embucket-dbt-demo && cd embucket-dbt-demo + mkdir -p models + ``` + + Create a `dbt_project.yml` file: + + ```yaml + name: embucket_demo + version: 1.0.0 + config-version: 2 + + profile: embucket + + model-paths: ['models'] + + models: + embucket_demo: + +materialized: view + ``` + + Create a `models/hello_embucket.sql` file: + + ```sql + select 1 as id, 'hello embucket' as message + ``` + +3. **Configure the profile** + + Add the following block to your `profiles.yml` file: + + ```yaml + embucket: + target: dev + outputs: + dev: + type: embucket + function_arn: "{{ env_var('EMBUCKET_FUNCTION_ARN') }}" + account: "{{ env_var('EMBUCKET_ACCOUNT', 'embucket') }}" + user: "{{ env_var('EMBUCKET_USER', 'embucket') }}" + password: "{{ env_var('EMBUCKET_PASSWORD', 'embucket') }}" + database: "{{ env_var('EMBUCKET_DATABASE', 'demo') }}" + schema: public + threads: 1 + ``` + + Export the Lambda function ARN as an environment variable: + + ```bash + export EMBUCKET_FUNCTION_ARN=arn:aws:lambda:us-east-2:123456789012:function:embucket-lambda + ``` + + **Profile field reference** + + | Field | Required | Description | + | -------------- | -------- | ---------------------------------- | + | `type` | Yes | Set to `embucket`. | + | `function_arn` | Yes | ARN of the target Lambda function. | + | `account` | Yes | Logical account identifier. | + | `user` | Yes | Authentication user name. | + | `password` | Yes | Authentication password. | + | `database` | Yes | Target database name. | + | `schema` | Yes | Target schema name. | + | `threads` | Yes | Number of concurrent dbt threads. | + +4. **Check the connection** + + Verify that dbt can reach the Lambda function: + + ```bash + dbt debug + ``` + + A successful check produces the following output: + + ```text + Connection test: [OK connection ok] + All checks passed! + ``` + +5. **Run a model** + + Build the example model: + + ```bash + dbt run + ``` + + dbt compiles and runs the `hello_embucket` model against Embucket. + +6. **Verify the result** + + Query the model output with `dbt show`: + + ```bash + dbt show --inline "select * from demo.public.hello_embucket" + ``` + + The query returns the following result: + + ```text + +----+----------------+ + | ID | MESSAGE | + |----+----------------| + | 1 | hello embucket | + +----+----------------+ + ``` + + + + + +## Caveats + +The adapter uses Lambda invoke transport, not a TCP connection. The adapter doesn't support Python models. Use AWS credentials that can invoke the target Lambda function. + +## Troubleshooting + +| Problem | Solution | +| ------------------------------------- | ----------------------------------------------------------------------------------------------------- | +| `profiles.yml` not found | Check that the file exists in your dbt profiles directory. Run `dbt debug --config-dir` to locate it. | +| `EMBUCKET_FUNCTION_ARN` missing | Export the variable before running `dbt debug`. | +| AWS credentials missing | The adapter needs IAM credentials with `lambda:InvokeFunction` permission. | +| Authentication failures | Verify the `user` and `password` values in your profile. | +| Runs succeed but data appears missing | Check the `database`, `schema`, and metastore configuration on the Lambda function. | + +## Next step + +For a complete analytics pipeline example, see [Snowplow web analytics](/tutorials/snowplow/). diff --git a/docs/src/content/docs/connect/snowflake-cli.mdx b/docs/src/content/docs/connect/snowflake-cli.mdx new file mode 100644 index 00000000..99980aa2 --- /dev/null +++ b/docs/src/content/docs/connect/snowflake-cli.mdx @@ -0,0 +1,119 @@ +--- +title: Snowflake CLI +description: Connect the Snowflake command-line tool to Embucket. +sidebar: + order: 0 +--- + +import { Aside, Steps } from '@astrojs/starlight/components'; + +The standard Snowflake command-line tool works with Embucket through its Snowflake-compatible REST API. + +## Prerequisites + +Before you begin, make sure you have the following: + +- **Python 3.8 or later** installed on your system. +- **Snowflake CLI** installed: + + ```bash + python -m pip install snowflake-cli + ``` + +- **A running Embucket instance.** Start one locally with Docker or deploy to AWS Lambda. + +{/* vale Vale.Terms = NO */} +{/* vale Google.Parens = NO */} + + +{/* vale Google.Parens = YES */} +{/* vale Vale.Terms = YES */} + +## Set up the connection + + + +1. **Find your configuration file** + + Run the following command to locate your Snowflake CLI configuration file: + + ```bash + snow --info + ``` + + Open the configuration file and add the following connection block: + + ```toml + [connections.local] + host = "localhost" + region = "us-east-2" + port = 3000 + protocol = "http" + database = "embucket" + schema = "public" + warehouse = "em.wh" + account = "acc.local" + user = "embucket" + password = "embucket" + ``` + +2. **Test the connection** + + Verify that the Snowflake CLI can reach your Embucket instance: + + ```bash + snow connection test -c local + ``` + + A successful connection produces the following output: + + ```text + +--------------------------------------------------------+ + | key | value | + |-----------------+--------------------------------------| + | Connection name | local | + | Status | OK | + | Host | localhost | + | Account | acc.local | + | User | embucket | + | Role | | + | Database | embucket | + | Warehouse | em.wh | + +--------------------------------------------------------+ + ``` + +3. **Run a query** + + Execute a SQL query through the Snowflake CLI: + + ```bash + snow sql -c local -q "SELECT 1 AS ok" + ``` + + The query returns the following result: + + ```text + +----+ + | OK | + |----| + | 1 | + +----+ + ``` + + + +## Troubleshooting + +{/* vale Google.Parens = NO */} + +| Problem | Solution | +| ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| Protocol or TLS (Transport Layer Security) errors | Set `protocol = "http"` in your connection block. Embucket doesn't require TLS for local connections. | +| Authentication failures | Use `embucket` for both the `user` and `password` fields. | +| Connection refused | Confirm that your Docker container runs and listens on port 3000. | +| No data returned | Configure a metastore so Embucket can access your data. See [Configuration](/configuration/configuration/) for details. | + +{/* vale Google.Parens = YES */} diff --git a/docs/src/content/docs/deploy/aws-lambda.mdx b/docs/src/content/docs/deploy/aws-lambda.mdx new file mode 100644 index 00000000..43ac25f6 --- /dev/null +++ b/docs/src/content/docs/deploy/aws-lambda.mdx @@ -0,0 +1,390 @@ +--- +title: AWS Lambda +description: Deploy Embucket to AWS Lambda with S3 Tables storage. +sidebar: + order: 0 +--- + +import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; + +Embucket runs as an AWS Lambda function that uses S3 Tables with Apache Iceberg for storage. This guide walks you through the full deployment, from creating your S3 table bucket to verifying a working query. + +## Prerequisites + +Before you begin, make sure you have the following: + +- AWS CLI installed and configured +- AWS credentials with permissions for Lambda, S3 Tables, and IAM + +## Step 1: Create an S3 table bucket + +Create a new S3 table bucket to store your Iceberg tables: + +```bash +aws s3tables create-table-bucket --name my-table-bucket --region us-east-2 +``` + +The command returns a JSON response with the bucket ARN: + +```json +{ + "arn": "arn:aws:s3tables:us-east-2:123456789012:bucket/my-table-bucket" +} +``` + +Save the bucket name, region, and ARN. You need these values in the next step. + +## Step 2: Configure the metastore + + + + Create the file `config/metastore.yaml`: + + ```yaml + volumes: + - ident: embucket + type: s3-tables + database: demo + credentials: + credential_type: access_key + aws-access-key-id: ACCESS_KEY + aws-secret-access-key: SECRET_ACCESS_KEY + arn: arn:aws:s3tables:us-east-2:123456789012:bucket/my-table-bucket + ``` + + + + Set the `METASTORE_CONFIG` environment variable on your Lambda function to the path of this file (for example, `config/metastore.yaml`). + + + + Configure a single volume through environment variables on the Lambda function: + + | Variable | Purpose | Example | + | -------------------------- | ------------------------------------------ | -------------------- | + | `VOLUME_TYPE` | Volume type: `s3tables`, `s3`, or `memory` | `s3tables` | + | `VOLUME_IDENT` | Volume identifier | `embucket` | + | `VOLUME_DATABASE` | Database name to associate | `demo` | + | `VOLUME_ARN` | S3 table bucket ARN (s3tables only) | `arn:aws:s3tables:…` | + | `VOLUME_ACCESS_KEY` | AWS access key ID | — | + | `VOLUME_SECRET_KEY` | AWS secret access key | — | + | `VOLUME_AWS_SESSION_TOKEN` | AWS session token (optional) | — | + + + + + + +## Step 3: Deploy the Lambda function + + + + Install the Rust toolchain and [cargo-lambda][cargo-lambda-install]. Build and deploy: + +[cargo-lambda-install]: https://www.cargo-lambda.info/guide/installation.html + + ```bash + cargo lambda build --release -p embucket-lambda --arm64 -o zip + cargo lambda deploy --binary-name bootstrap embucket-lambda + ``` + + You can also use the Makefile, which wraps `cargo lambda` and accepts several variables: + + ```bash + make -C crates/embucket-lambda deploy + ``` + + | Variable | Purpose | Default | + | --------------------- | ------------------------------- | -------------------- | + | `FUNCTION_NAME` | Lambda function name | `embucket-lambda` | + | `ENV_FILE` | Environment file path | `config/.env.lambda` | + | `AWS_LAMBDA_ROLE_ARN` | Execution role ARN | unset | + | `FEATURES` | Cargo features, comma-separated | unset | + | `LAYERS` | Additional Lambda layer ARNs | unset | + | `WITH_OTEL_CONFIG` | OpenTelemetry collector config | unset | + + + + Download the pre-built Lambda zip from S3: + + ```bash + aws s3 cp s3://embucket-releases/lambda/embucket-lambda-latest.zip . + ``` + + + + Create the Lambda function: + + ```bash + aws lambda create-function \ + --function-name embucket-lambda \ + --runtime provided.al2023 \ + --architectures arm64 \ + --handler bootstrap \ + --zip-file fileb://embucket-lambda-latest.zip \ + --role arn:aws:iam::123456789012:role/embucket-lambda-role \ + --memory-size 3008 \ + --timeout 30 \ + --environment "Variables={METASTORE_CONFIG=config/metastore.yaml,LOG_FORMAT=json,TRACING_LEVEL=debug,RUST_LOG=info}" + ``` + + Replace the role ARN with your own execution role. + + To update an existing function: + + ```bash + aws lambda update-function-code \ + --function-name embucket-lambda \ + --zip-file fileb://embucket-lambda-latest.zip + ``` + + + + +## Step 4: Verify the deployment + +For HTTP-level validation, send a login request directly with `curl`: + +```bash +curl -X POST https://FUNCTION_URL.lambda-url.us-east-2.on.aws/session/v1/login-request \ + -H "Content-Type: application/json" \ + -d '{"data": {"ACCOUNT_NAME": "account", "LOGIN_NAME": "embucket", "PASSWORD": "embucket", "CLIENT_APP_ID": "test"}}' +``` + +Replace `FUNCTION_URL` with your actual Lambda function URL. + +To tail CloudWatch logs: + +```bash +aws logs tail /aws/lambda/embucket-lambda --since 5m --follow +``` + +## IAM permissions + +You need separate IAM policies for the identity that deploys the function and for the Lambda execution role. + +### Deployer permissions + +The identity that runs `cargo lambda deploy` or `aws lambda create-function` needs the following permissions: + +```json +{ + "Effect": "Allow", + "Action": [ + "lambda:CreateFunction", + "lambda:UpdateFunctionCode", + "lambda:UpdateFunctionConfiguration", + "lambda:GetFunction", + "lambda:TagResource", + "lambda:CreateFunctionUrlConfig", + "lambda:UpdateFunctionUrlConfig", + "lambda:GetFunctionUrlConfig", + "lambda:AddPermission", + "logs:CreateLogGroup", + "iam:PassRole" + ], + "Resource": "*" +} +``` + + + +### Lambda execution role + +Attach policies that grant the Lambda function access to the services it uses. The required permissions depend on your volume type and whether you enable the state store. + +**S3 Tables permissions -- for the `s3tables` volume type:** + +```json +{ + "Effect": "Allow", + "Action": [ + "s3tables:GetTableBucket", + "s3tables:ListTableBuckets", + "s3tables:ListNamespaces", + "s3tables:GetNamespace", + "s3tables:ListTables", + "s3tables:GetTable", + "s3tables:GetTableMetadata", + "s3tables:PutTableMetadata", + "s3tables:CreateTable", + "s3tables:DeleteTable" + ], + "Resource": "arn:aws:s3tables:*:123456789012:bucket/*" +} +``` + +**S3 permissions -- for the `s3` volume type:** + +```json +{ + "Effect": "Allow", + "Action": [ + "s3:GetObject", + "s3:PutObject", + "s3:DeleteObject", + "s3:ListBucket", + "s3:HeadObject", + "s3:HeadBucket" + ], + "Resource": ["arn:aws:s3:::your-bucket", "arn:aws:s3:::your-bucket/*"] +} +``` + +**DynamoDB permissions -- required when you enable the state store:** + +```json +{ + "Effect": "Allow", + "Action": [ + "dynamodb:PutItem", + "dynamodb:GetItem", + "dynamodb:DeleteItem", + "dynamodb:Query", + "dynamodb:UpdateItem" + ], + "Resource": "arn:aws:dynamodb:*:123456789012:table/embucket-statestore*" +} +``` + +**CloudWatch Logs permissions:** + +```json +{ + "Effect": "Allow", + "Action": ["logs:CreateLogStream", "logs:PutLogEvents"], + "Resource": "arn:aws:logs:*:123456789012:log-group:/aws/lambda/embucket-lambda:*" +} +``` + +**X-Ray permissions -- optional, for tracing:** + +```json +{ + "Effect": "Allow", + "Action": ["xray:PutTraceSegments", "xray:PutTelemetryRecords"], + "Resource": "*" +} +``` + +### Client invoke + +Users who connect through dbt-embucket need `lambda:InvokeFunctionUrl` or `lambda:InvokeFunction` permission on the function ARN. Grant this permission in the client's IAM policy. + +## Lambda sizing + +The default configuration sets memory to 3008 MB and timeout to 30 seconds. Tracing defaults to `Active`. + +3008 MB represents the standard Lambda limit. To increase memory beyond this cap, up to 10 GB, submit an AWS support ticket. + +Override memory and timeout through the AWS Console or the `aws lambda update-function-configuration` command. + +## State store + +The pre-built Lambda zip includes the `state-store-query` feature, which persists query state in DynamoDB across invocations. To use it, create a DynamoDB table: + +```bash +aws dynamodb create-table \ + --table-name embucket-statestore \ + --attribute-definitions \ + AttributeName=PK,AttributeType=S \ + AttributeName=SK,AttributeType=S \ + AttributeName=query_id,AttributeType=S \ + AttributeName=request_id,AttributeType=S \ + AttributeName=session_id,AttributeType=S \ + --key-schema AttributeName=PK,KeyType=HASH AttributeName=SK,KeyType=RANGE \ + --global-secondary-indexes \ + "IndexName=GSI_QUERY_ID_INDEX,KeySchema=[{AttributeName=query_id,KeyType=HASH}],Projection={ProjectionType=ALL},ProvisionedThroughput={ReadCapacityUnits=5,WriteCapacityUnits=5}" \ + "IndexName=GSI_REQUEST_ID_INDEX,KeySchema=[{AttributeName=request_id,KeyType=HASH}],Projection={ProjectionType=ALL},ProvisionedThroughput={ReadCapacityUnits=5,WriteCapacityUnits=5}" \ + "IndexName=GSI_SESSION_ID_INDEX,KeySchema=[{AttributeName=session_id,KeyType=HASH}],Projection={ProjectionType=ALL},ProvisionedThroughput={ReadCapacityUnits=5,WriteCapacityUnits=5}" \ + --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \ + --region us-east-2 +``` + +Configure the state store with the following environment variables: + +| Variable | Purpose | Default | +| ------------------------------ | ------------------------------------------ | --------------------- | +| `STATESTORE_TABLE_NAME` | DynamoDB table name | `embucket-statestore` | +| `STATESTORE_DYNAMODB_ENDPOINT` | Custom DynamoDB endpoint for local testing | unset | +| `AWS_DDB_ACCESS_KEY_ID` | DynamoDB access key | unset | +| `AWS_DDB_SECRET_ACCESS_KEY` | DynamoDB secret key | unset | +| `AWS_DDB_SESSION_TOKEN` | DynamoDB session token | unset | + +## Production ingress + + + +{/* vale Google.Parens = NO */} +{/* vale Google.WordList = NO */} +The following CloudFormation skeleton provisions a private API Gateway with a VPC (Virtual Private Cloud) endpoint for `execute-api`, Lambda proxy integration, and a stage named `v1`: +{/* vale Google.WordList = YES */} +{/* vale Google.Parens = YES */} + +```yaml +Parameters: + LambdaFunctionName: + Type: String + Default: embucket-lambda + VpcId: + Type: AWS::EC2::VPC::Id + SubnetIds: + Type: List + VpcCidr: + Type: String + Default: 10.0.0.0/16 + +Resources: + ExecuteApiVpcEndpoint: + Type: AWS::EC2::VPCEndpoint + PrivateApi: + Type: AWS::ApiGateway::RestApi + LambdaInvokePermission: + Type: AWS::Lambda::Permission +``` + +This template creates a private API Gateway accessible only from within your VPC. Adapt the parameters and resource properties to match your networking setup. + +## Rollback and redeploy + +Keep your environment file and `metastore.yaml` in version control. If a deployment causes a regression, redeploy with the previous configuration: + +1. Restore the previous `config/.env.lambda` and `config/metastore.yaml`. +2. Run `make -C crates/embucket-lambda deploy`. +3. Run `make -C crates/embucket-lambda verify` to confirm the rollback. + +## Cleanup + +To remove the Lambda function URL: + +```bash +aws lambda delete-function-url-config --function-name embucket-lambda +``` + +After removing the function URL, delete the following resources if you no longer need them: + +- Lambda function -- `embucket-lambda` +- CloudWatch log group -- `/aws/lambda/embucket-lambda` +- API Gateway and VPC endpoint, if you created them for production ingress +- OpenTelemetry layers, if you deployed telemetry + +## Troubleshooting + +**Deploy succeeds but queries fail** -- Check that the `METASTORE_CONFIG` environment variable points to a valid `metastore.yaml` and that the credentials and ARN inside the file remain correct. + +**dbt can't connect** -- Verify that the client's AWS credentials have `lambda:InvokeFunction` permission on the function ARN. Confirm that your dbt profile sets `EMBUCKET_FUNCTION_ARN` correctly. + +**Timeouts on large queries** -- Review the Lambda timeout and memory settings. Increase the timeout with `cargo lambda deploy` flags or through the AWS Console. Request a memory increase through AWS Support if you need more than 3008 MB. + +**No traces or logs** -- Verify that your environment file defines `RUST_LOG` and `TRACING_LEVEL`. If you use OpenTelemetry, confirm that `WITH_OTEL_CONFIG` points to a valid collector config and that the OTEL exporter endpoint remains reachable. diff --git a/docs/src/content/docs/essentials/create-volume-1.png b/docs/src/content/docs/deploy/create-volume-1.png similarity index 100% rename from docs/src/content/docs/essentials/create-volume-1.png rename to docs/src/content/docs/deploy/create-volume-1.png diff --git a/docs/src/content/docs/essentials/create-volume-2.png b/docs/src/content/docs/deploy/create-volume-2.png similarity index 100% rename from docs/src/content/docs/essentials/create-volume-2.png rename to docs/src/content/docs/deploy/create-volume-2.png diff --git a/docs/src/content/docs/guides/s3-tables-query.png b/docs/src/content/docs/deploy/s3-tables-query.png similarity index 100% rename from docs/src/content/docs/guides/s3-tables-query.png rename to docs/src/content/docs/deploy/s3-tables-query.png diff --git a/docs/src/content/docs/development/docs-maintenance.mdx b/docs/src/content/docs/development/docs-maintenance.mdx deleted file mode 100644 index 6cfcf6cb..00000000 --- a/docs/src/content/docs/development/docs-maintenance.mdx +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: Docs maintenance -description: How to review docs and keep them current. -sidebar: - order: 1 ---- - -> Owner: Embucket maintainers -> Last reviewed: 2026-04-07 - -This page documents the current release-gate process for docs changes. - -## Automated checks - -The repository already includes a docs CI workflow at `.github/workflows/docs-ci.yml`. - -On docs changes, it currently runs: - -- formatting checks -- `astro check` -- repo-safe docs smoke checks for repeated constants, guide metadata, and referenced local files -- a full docs build -- Vale linting - -The docs site also uses `starlight-links-validator` during the build. - -## What still needs manual smoke testing - -Before release, manually check the commands in the highest-traffic guides: - -- `Quick Start` -- `Runtime modes` -- `Self-hosted local binary` -- `AWS Lambda` -- `dbt` -- `End-to-end dbt workflow` -- `Snowplow web analytics` -- `Troubleshooting` - -Confirm at least these points: - -- the local quick start still starts `embucket/embucket` -- the self-hosted guide still uses `cargo build` and can start `target/debug/embucketd` -- the Snowflake command-line tool can still run a simple query against the documented path -- the Lambda guide still reflects the current deploy flow -- the dbt guide still matches the current `dbt-embucket` adapter contract -- the Snowplow guide still matches the current `embucket-snowplow` flow and uses `dbt run` plus `dbt show` as the success state - -The automated smoke checks stay intentionally static. They do not call AWS, run dbt against a live Lambda, or execute the Snowflake command-line tool against live infrastructure. - -## Owner and freshness convention - -Major guides should include a short block near the top with: - -- owner -- last reviewed date - -This repository now uses that pattern in the highest-traffic guides so readers can see which pages the team reviewed recently. - -## Release checklist - -Before a release or launch push, confirm: - -1. current runtime names are consistent -2. quick-start ports and URLs still match the implementation -3. support claims still match verified workflows -4. docs CI is green -5. the top guides have a recent review date -6. self-hosted and Snowplow guides still match the current source repositories and local commands diff --git a/docs/src/content/docs/development/tracing.mdx b/docs/src/content/docs/development/tracing.mdx deleted file mode 100644 index f0c425de..00000000 --- a/docs/src/content/docs/development/tracing.mdx +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: Tracing and profiling -description: Learn how to use tracing and profiling features in Embucket for debugging and performance analysis. ---- - -## Tracing - -Embucket uses `tracing::instrument` to instrument code for tracing. You can use it in both development and production environments. For development, use `info`, `debug`, or `trace` levels. For production, use the `info` level. - -### Tracing span processor experimental async runtime - -Embucket uses `BatchSpanProcessor`, which uses a dedicated background thread for collecting and exporting spans. This processor works well in production. If a development environment hangs on startup, switch to the experimental async runtime instead. -Use this command-line argument: `--tracing-span-processor=batch-span-processor-experimental-async-runtime`. - -### Tracing span processor tuning - -You can tune BatchSpanProcessor with the following environment variables: - -- `OTEL_BSP_MAX_CONCURRENT_EXPORTS`: Max number of concurrent export threads. Use this when running with the command-line argument: - `--tracing-span-processor=batch-span-processor-experimental-async-runtime` -- `OTEL_BSP_SCHEDULE_DELAY`: Frequency for batch exports, in milliseconds. Higher values reduce "BatchSpanProcessor. ExportError" messages in logs when you don't use an OpenTelemetry Protocol (OTLP) collector. -- `OTEL_BSP_EXPORT_TIMEOUT`: Max time allowed to export data. -- `OTEL_BSP_MAX_EXPORT_BATCH_SIZE`: Max number of spans per single export. -- `OTEL_BSP_MAX_QUEUE_SIZE`: Max number of spans you can buffer. - -### Logging - -Logging provides the basic way to observe debug and tracing events. -`RUST_LOG=debug` works for most cases. For tracing, use `RUST_LOG=trace`. - -### OpenTelemetry with Jaeger - -Instrumented calls in Embucket produce tracing events and spans using the [OpenTelemetry](https://opentelemetry.io/) SDK. These events go via OpenTelemetry Protocol (OTLP) to port 4317, where the OpenTelemetry Collector listens. -The collector starts collecting data when you run the Docker container, which also serves a [Jaeger](https://www.jaegertracing.io/) dashboard at [http://localhost:16686/](http://localhost:16686). - -```bash -# Run docker container with Jaeger UI v2 -docker run --rm --name jaeger -p 16686:16686 -p 4317:4317 -p 4318:4318 -p 5778:5778 -p 9411:9411 jaegertracing/jaeger:2.6.0 -``` - -### Run Embucket in tracing mode - -Use the `RUST_LOG` environment variable to define log levels and the `--tracing-level` argument to enable tracing with [Jaeger](https://www.jaegertracing.io/). -Both default log level and default tracing level use `info`. - -```bash -target/debug/embucketd --jwt-secret=test --tracing-level=trace -``` - -## Profiling - -If you need to profile the `embucketd` executable, you can use [Samply](https://github.com/mstange/samply/). -This guide includes Samply as one way to profile, presented here as an experiment. This solution works out of the box on macOS, Linux, and Windows. - -To start profiling, prepend `samply record` to the `embucketd` command invocation. Perform the actions you need to profile, then stop profiling to open a profile report in the browser. - -```bash -# install Samply -cargo install --locked samply - -# Profile debug build -cargo build && samply record RUST_LOG=debug target/debug/embucketd --jwt-secret=test - -``` diff --git a/docs/src/content/docs/essentials/architecture.mdx b/docs/src/content/docs/essentials/architecture.mdx deleted file mode 100644 index 9d2595e0..00000000 --- a/docs/src/content/docs/essentials/architecture.mdx +++ /dev/null @@ -1,113 +0,0 @@ ---- -title: Architecture -description: Understand how Embucket handles data, metadata, query execution, authentication, and runtime packaging today. -sidebar: - order: 3 ---- - -import { Aside } from '@astrojs/starlight/components'; - -> Owner: Embucket maintainers -> Last reviewed: 2026-04-07 - -Embucket exposes a Snowflake-compatible API over lakehouse data. The current implementation is easiest to reason about if you separate it into five layers: runtime, metadata, storage, query execution, and auth/session handling. - -Use this page when you want the current mental model before choosing a runtime, configuring metadata, or planning around query and session limits. - -## Runtime model - -The repo currently ships two runtime artifacts: - -- `embucketd` for local and self-hosted runs -- `embucket-lambda` for AWS Lambda deployments - -The Lambda runtime wraps the same Snowflake-compatible router used by `embucketd`, so the client-facing API shape stays aligned across both runtime modes. - -Read [Runtime modes](/essentials/runtime-modes/) for the operational tradeoffs. - -If you are still choosing a path, start there before deploying. - -## Metadata model - -Embucket does not present itself as a managed metadata service. Instead, it loads metadata from configuration or supported external catalogs. - -Current documented paths are: - -- YAML metastore config loaded from `METASTORE_CONFIG` -- AWS S3 Tables as the documented external catalog path -- external Iceberg table definitions described in the metastore YAML - -If you need to configure metadata now, start with [Configuration](/essentials/configuration/) or [AWS S3 table bucket](/guides/s3-tables/). - - - -## Storage model - -Data stays in your object storage. The current docs and code paths center on: - -- Apache Iceberg metadata -- Parquet data files -- AWS S3 or S3-compatible object storage flows - -For AWS-managed table metadata, use [AWS S3 table bucket](/guides/s3-tables/). - -For a minimal local path, use the checked-in metastore config flow instead of starting with external catalog setup. - -## Query model - -Embucket executes Snowflake-flavored SQL through Apache DataFusion. The important operational property today is that query execution is **single-node per request**. - -That means: - -- each node handles complete queries independently -- there is no documented distributed query plan across many nodes -- scaling is primarily a throughput and placement question, not a distributed execution story - -This is why the docs distinguish local evaluation from the current Lambda deployment path instead of treating them as interchangeable production footprints. - -Plan for that limit before treating Lambda as a high-concurrency production endpoint. - -## Auth and session model - -The current Snowflake-compatible HTTP surface exposes: - -- `/session/v1/login-request` -- `/session` -- `/queries/v1/query-request` -- `/queries/v1/abort-request` - -The local demo path uses configurable demo credentials, which default to `embucket` / `embucket`. - -After login: - -- Embucket issues a JWT token -- clients can pass it in `Authorization: Snowflake Token="..."` -- the runtime also uses a `session_id` cookie for session continuity - -Current implementation details worth knowing: - -- JWT token lifetime is 3 days -- session inactivity expiry is 60 seconds - -If you are debugging auth problems, continue to [Troubleshooting](/guides/troubleshooting/). - -## When to use local mode or Lambda - -The API shape stays aligned, but the operational envelope changes: - -- **local mode** is the fastest path for tests and evaluation -- **Lambda + Function URL** is a tested validation path, but not production-ready because the URL is publicly reachable -- **Lambda + dbt-embucket** is the verified and recommended client workflow -- **private API gateway in front of Lambda** is the safer production-facing ingress pattern - -Use [Quick Start](/essentials/quick-start/) for local evaluation and [End-to-end dbt workflow](/guides/end-to-end-dbt/) for the shortest complete Lambda path. - -## Related guides - -- [Quick Start](/essentials/quick-start/) -- [Support matrix](/essentials/support-matrix/) -- [AWS Lambda](/guides/aws-lambda/) -- [dbt](/guides/dbt/) diff --git a/docs/src/content/docs/essentials/configuration.mdx b/docs/src/content/docs/essentials/configuration.mdx deleted file mode 100644 index 3020dd14..00000000 --- a/docs/src/content/docs/essentials/configuration.mdx +++ /dev/null @@ -1,146 +0,0 @@ ---- -title: Configuration -description: Configure Embucket with the current source-backed flags, environment variables, and metastore settings. -sidebar: - order: 2 ---- - -import { Aside } from '@astrojs/starlight/components'; - -> Owner: Embucket maintainers -> Last reviewed: 2026-04-07 - -This page covers the current configuration surface backed by the repository. It focuses on settings that are visible in `crates/embucketd/src/cli.rs`, plus the checked-in config examples in `config/`. - -## Configuration precedence - -The current local runtime supports these configuration sources, from highest to lowest precedence: - -1. command-line flags -2. environment variables -3. `.env` loaded at startup - - - -## Core runtime settings - -| Purpose | Flag | Environment variable | Default | -| --------------------- | ------------------------- | ----------------------- | ----------- | -| metastore config path | `--metastore-config` | `METASTORE_CONFIG` | unset | -| bind host | `--host` | `BUCKET_HOST` | `localhost` | -| bind port | `--port` | `BUCKET_PORT` | `3000` | -| result serialization | `--data-format` | `DATA_FORMAT` | `json` | -| parser dialect | `--sql-parser-dialect` | `SQL_PARSER_DIALECT` | `snowflake` | -| query concurrency | `--max-concurrency-level` | `MAX_CONCURRENCY_LEVEL` | `8` | -| query timeout | `--query-timeout-secs` | `QUERY_TIMEOUT_SECS` | `1200` | -| demo user | `--auth-demo-user` | `AUTH_DEMO_USER` | `embucket` | -| demo password | `--auth-demo-password` | `AUTH_DEMO_PASSWORD` | `embucket` | -| JWT signing secret | `--jwt-secret` | `JWT_SECRET` | unset | -| tracing level | `--tracing-level` | `TRACING_LEVEL` | `info` | -| service idle timeout | `--idle-timeout-seconds` | `IDLE_TIMEOUT_SECONDS` | `18000` | - -## Local `.env` example - -Start with a minimal local `.env` like this: - -```bash -METASTORE_CONFIG=./metastore.yaml -JWT_SECRET=secret -TRACING_LEVEL=debug -RUST_LOG=info -``` - -Use stronger secrets than the example when you share an environment with anyone else. - -## Metastore configuration - -Embucket currently expects metastore configuration through `METASTORE_CONFIG` or `--metastore-config`. - -For a minimal local file, start with: - -```yaml -volumes: [] -``` - -That keeps the local runtime usable for evaluation and testing while you build out a richer metastore definition. - -### Configure the table-bucket volume - -```yaml -volumes: - - ident: embucket - type: s3-tables - database: demo - credentials: - credential_type: access_key - aws-access-key-id: ACCESS_KEY - aws-secret-access-key: SECRET_ACCESS_KEY - arn: arn:aws:s3tables:us-east-2:123456789012:bucket/my-table-bucket -``` - -Use this path if you want the currently documented external catalog flow. See [AWS S3 table bucket](/guides/s3-tables/) for the end-to-end setup. - -### External Iceberg tables on S3 - -```yaml -volumes: - - ident: lakehouse - type: s3 - region: us-east-2 - bucket: YOUR_BUCKET_NAME - credentials: - credential_type: access_key - aws-access-key-id: YOUR_ACCESS_KEY - aws-secret-access-key: YOUR_SECRET_KEY - -databases: - - ident: demo - volume: lakehouse - -schemas: - - database: demo - schema: tpch_10 - -tables: - - database: demo - schema: tpch_10 - table: customer - metadata_location: s3://YOUR_BUCKET_NAME/tpch_10/customer/metadata/00001.metadata.json -``` - -This path is useful when you already have Iceberg metadata in object storage and want Embucket to expose it through the Snowflake-compatible API. - -## Runtime and tracing settings - -The current runtime also exposes memory, disk, AWS SDK, and object-store timeout controls. The most important ones for everyday operation are: - -- `MEM_POOL_TYPE` -- `MEM_POOL_SIZE_MB` -- `DISK_POOL_SIZE_MB` -- `AWS_SDK_CONNECT_TIMEOUT_SECS` -- `AWS_SDK_OPERATION_TIMEOUT_SECS` -- `OBJECT_STORE_TIMEOUT_SECS` -- `OBJECT_STORE_CONNECT_TIMEOUT_SECS` -- `TRACING_LEVEL` -- `RUST_LOG` - -For deeper tracing guidance, see [Tracing and profiling](/development/tracing/). - -## Current authentication defaults - -Local quick starts assume demo authentication: - -- username: `embucket` -- password: `embucket` - -Override them with `AUTH_DEMO_USER` and `AUTH_DEMO_PASSWORD` when you need different demo credentials. - -## Related guides - -- [Quick Start](/essentials/quick-start/) -- [Runtime modes](/essentials/runtime-modes/) -- [AWS Lambda](/guides/aws-lambda/) -- [Troubleshooting](/guides/troubleshooting/) diff --git a/docs/src/content/docs/essentials/quick-start.mdx b/docs/src/content/docs/essentials/quick-start.mdx deleted file mode 100644 index 8433879f..00000000 --- a/docs/src/content/docs/essentials/quick-start.mdx +++ /dev/null @@ -1,126 +0,0 @@ ---- -title: Quick Start -description: Start Embucket locally, connect the Snowflake command-line tool, and run a first query in the current test and evaluation path. -sidebar: - order: 0 ---- - -import { Aside, Steps } from '@astrojs/starlight/components'; - -> Owner: Embucket maintainers -> Last reviewed: 2026-04-07 - -This quick start is the fastest way to try Embucket locally. This is the current **test and evaluation** path, not the recommended production deployment path. - -By the end of this guide, you can: - -- start the current `embucket/embucket` container -- connect the Snowflake command-line tool to the local endpoint -- run a query successfully - -## Step 1: Start Embucket - -Run the local container: - -```bash -docker run --name embucket --rm -p 3000:3000 embucket/embucket -``` - -Expected startup output includes a line like: - -```text -{"timestamp":"2025-07-01T15:35:05.687807Z","level":"INFO","fields":{"message":"Listening on http://0.0.0.0:3000"},"target":"embucketd"} -``` - - - -## Step 2: Configure the Snowflake command-line tool - -Install the Snowflake command-line tool if you do not have it already: - -```bash -python -m pip install snowflake-cli -``` - -Find your Snowflake command-line tool config file: - -```bash -snow --info -``` - -Add this connection block: - -```toml -[connections.local] -host = "localhost" -region = "us-east-2" -port = 3000 -protocol = "http" -database = "embucket" -schema = "public" -warehouse = "em.wh" -account = "acc.local" -user = "embucket" -password = "embucket" -``` - -Check the connection: - -```bash -snow connection test -c local -``` - -Expected output: - -```text -+-----------------------------+ -| key | value | -|-----------------+-----------| -| Connection name | local | -| Status | OK | -| Host | localhost | -| Account | acc | -| User | embucket | -| Role | not set | -| Database | embucket | -| Warehouse | em.wh | -+-----------------------------+ -``` - -## Step 3: Run your first query - -```bash -snow sql -c local -q "select dateadd(day, -1, current_timestamp()) as yesterday;" -``` - -Expected output: - -```text -+----------------------------------+ -| yesterday | -|----------------------------------| -| 2025-01-02 03:04:05.040000+00:00 | -+----------------------------------+ -``` - -## Step 4: Inspect the HTTP surface - -Open `http://127.0.0.1:3000/` in your browser to inspect the current Swagger/OpenAPI surface served by `embucketd`. - - - -## Next steps - -- If you want to run the local binary from source instead of Docker, read [Self-hosted local binary](/guides/self-hosted/). -- If you want the current runtime choices, read [Runtime modes](/essentials/runtime-modes/). -- If you want serverless deployment, read [AWS Lambda](/guides/aws-lambda/). -- If you want the recommended client path, read [dbt](/guides/dbt/). -- If you want a fuller analytics example on the recommended path, read [Snowplow web analytics](/guides/snowplow/). -- If you want an external catalog, read [AWS S3 table bucket](/guides/s3-tables/). -- If something fails, read [Troubleshooting](/guides/troubleshooting/). diff --git a/docs/src/content/docs/essentials/runtime-modes.mdx b/docs/src/content/docs/essentials/runtime-modes.mdx deleted file mode 100644 index 1c497961..00000000 --- a/docs/src/content/docs/essentials/runtime-modes.mdx +++ /dev/null @@ -1,86 +0,0 @@ ---- -title: Runtime modes -description: Choose between local evaluation, AWS Lambda validation, and the current recommended production-facing path. -sidebar: - order: 1 ---- - -import { Aside } from '@astrojs/starlight/components'; - -> Owner: Embucket maintainers -> Last reviewed: 2026-04-07 - -Embucket currently has two runtime artifacts: `embucketd` and `embucket-lambda`. The right path depends on whether you are evaluating the product, validating a client, or planning a production-facing deployment. - -If you already know what you want to do, use this page as a chooser: - -- Local evaluation → [Quick Start](/essentials/quick-start/) -- Source-built local binary → [Self-hosted local binary](/guides/self-hosted/) -- Lambda API validation → [AWS Lambda](/guides/aws-lambda/) -- Recommended client workflow → [dbt](/guides/dbt/) -- Shortest complete walkthrough → [End-to-end dbt workflow](/guides/end-to-end-dbt/) -- Fuller analytics example → [Snowplow web analytics](/guides/snowplow/) - -## Choose your path - -| Path | Best for | Current status | Start here | -| ------------------------------------------------------- | ------------------------------------------------------- | ---------------------------------------------------------- | --------------------------------------- | -| local `embucketd` via Docker or source build | tests, evaluation, local debugging | current local path | [Quick Start](/essentials/quick-start/) | -| AWS Lambda + Function URL + Snowflake command-line tool | validating the API with the Snowflake command-line tool | tested, but not production-ready because the URL is public | [AWS Lambda](/guides/aws-lambda/) | -| AWS Lambda + `dbt-embucket` adapter | dbt projects and repeatable workflows | verified and recommended | [dbt](/guides/dbt/) | -| AWS Lambda + private API gateway | production-facing ingress pattern | recommended deployment shape | [AWS Lambda](/guides/aws-lambda/) | - -## If you want local evaluation - -Use local mode when you want the shortest feedback loop. - -- default host: `localhost` -- default port: `3000` -- default demo credentials: `embucket` / `embucket` -- current browser-visible HTTP surface: `http://127.0.0.1:3000/` - -This is the fastest path for tests and evaluation, but the docs do not currently treat it as the primary production deployment recommendation. - -Start with [Quick Start](/essentials/quick-start/). - -If you want to build the binary yourself, use [Self-hosted local binary](/guides/self-hosted/). That path is currently for evaluation and testing rather than long-lived production deployment. - -## If you want the current Lambda runtime - -Use Lambda when you want the current serverless runtime. - -- runtime artifact: `embucket-lambda` -- deployment toolchain: `cargo lambda` plus the repo Makefile -- current test path: Function URL plus the Snowflake command-line tool -- current recommended client path: `dbt-embucket` - - - -For the recommended client path on Lambda, continue to [dbt](/guides/dbt/). - -If you want a fuller example on top of that path, continue to [Snowplow web analytics](/guides/snowplow/). - -## If you are deploying for production-facing traffic - -For production-facing traffic, the current guidance is: - -1. deploy `embucket-lambda` with the Lambda guide -2. avoid exposing a public Function URL as your main ingress -3. put an API gateway layer in front of the Lambda -4. use the dbt adapter as the primary documented client path -5. verify the full client path with the end-to-end dbt workflow - -The AWS Lambda guide includes an anonymized private API Gateway example for this ingress pattern. - -## Related guides - -- [Quick Start](/essentials/quick-start/) -- [Support matrix](/essentials/support-matrix/) -- [AWS Lambda](/guides/aws-lambda/) -- [dbt](/guides/dbt/) -- [End-to-end dbt workflow](/guides/end-to-end-dbt/) -- [Self-hosted local binary](/guides/self-hosted/) -- [Snowplow web analytics](/guides/snowplow/) diff --git a/docs/src/content/docs/essentials/snowflake.mdx b/docs/src/content/docs/essentials/snowflake.mdx deleted file mode 100644 index 44c48503..00000000 --- a/docs/src/content/docs/essentials/snowflake.mdx +++ /dev/null @@ -1,134 +0,0 @@ ---- -title: Snowflake compatibility -description: What Embucket currently aims to support, what is explicitly verified, and where it still differs from Snowflake. -sidebar: - order: 5 ---- - -import { Aside, Steps } from '@astrojs/starlight/components'; - -> Owner: Embucket maintainers -> Last reviewed: 2026-04-07 - -Use this page to understand which Snowflake-style workflows work today, which ones have caveats, and where Embucket still differs from Snowflake. - -For the verified client/runtime combinations, read [Support matrix](/essentials/support-matrix/). - -## Current compatibility summary - -Embucket currently presents: - -- a Snowflake v1 REST API surface -- Snowflake-flavored SQL on top of Apache DataFusion -- client workflows for the Snowflake command-line tool and dbt -- a verified dbt adapter path through AWS Lambda - -## Before you rely on a workflow - -| Workflow shape | What to do | -| ------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | -| You want a verified path | use [Support matrix](/essentials/support-matrix/) and prefer the dbt adapter path | -| You want local evaluation | use [Quick Start](/essentials/quick-start/) and [Snowflake command-line tool](/guides/snowflake-cli/) | -| You want to understand differences from Snowflake | use the limitation sections below before release | - -## API compatibility - -Embucket provides a Snowflake v1 REST API that works with Snowflake-style login, session, and query flows. - -The current docs explicitly cover: - -- local Snowflake command-line tool against `embucketd` -- dbt via the `dbt-embucket` adapter on AWS Lambda -- Snowflake command-line tool against a Lambda Function URL for testing - -Choose one of those paths first instead of assuming all Snowflake-compatible tools behave the same way. - -## How the query engine behaves - -Embucket uses [Apache DataFusion](https://datafusion.apache.org/) for query execution. The goal is Snowflake-friendly behavior, but the current implementation still differs from Snowflake in important places. - -## Current limitations - -### Execution model - -- **Single-node execution**: query processing can use only one node's memory and CPU capacity -- **No documented distributed parallelism**: the current runtime story is not a distributed query engine - -### Data type limitations - -- **VARIANT**: Embucket stores it as JSON-serialized `TEXT` -- **Numeric coercion** can differ from Snowflake -- **Timestamp behavior** differs from Snowflake's precision and timezone semantics -- **Collation and character set support** remains limited - -### Error handling - -- error messages do not match Snowflake exactly - -### String escaping - -Backslash escaping differs from Snowflake in some cases. - -#### Literal backslashes - -**Snowflake:** - -```sql -SELECT * FROM VALUES ('\\b'); --- Returns: \b -``` - -**Embucket:** - -```sql -SELECT * FROM VALUES ('\\\\b'); --- Returns: \b -``` - -#### Single trailing backslash - -**Snowflake:** - -```sql -SELECT * FROM VALUES ('\\'); --- Returns: \ -``` - -**Embucket:** - -```sql -SELECT * FROM VALUES ('\\'); --- Error: Unterminated string literal -``` - -## VARIANT data type support - -Embucket implements VARIANT as JSON-serialized `TEXT` on the storage layer. - - - -1. **Create a table** - - ```sql - create table t2 (c1 variant) as values (parse_json('{"k1":1}')); - ``` - -2. **Read it back** - - ```sql - select * from t2; - ``` - -3. **Inspect the stored Arrow type** - - ```sql - select arrow_typeof(c1) from t2; - ``` - - - -## Next steps - -- Read [Support matrix](/essentials/support-matrix/) for verified workflows. -- Read [dbt](/guides/dbt/) for the recommended client path. -- Read [Troubleshooting](/guides/troubleshooting/) when compatibility expectations and current behavior diverge. diff --git a/docs/src/content/docs/essentials/support-matrix.mdx b/docs/src/content/docs/essentials/support-matrix.mdx deleted file mode 100644 index dc81e1d1..00000000 --- a/docs/src/content/docs/essentials/support-matrix.mdx +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: Support matrix -description: The currently documented and verified runtime and client combinations for Embucket. -sidebar: - order: 4 ---- - -> Owner: Embucket maintainers -> Last reviewed: 2026-04-07 - -Use this matrix to choose a supported runtime and client combination before you deploy, check, or troubleshoot. - -## Runtime and client matrix - -| Runtime + client path | Status | Recommended use | Evidence | -| --------------------------------------------------------- | ------------------------------ | ----------------------------------------------------- | ----------------------------------------------------------------------------------- | -| local `embucketd` + Snowflake command-line tool | documented | tests, evaluation, and local debugging | current quick start, self-hosted guide, and Snowflake command-line tool guide | -| AWS Lambda + `dbt-embucket` adapter | verified | recommended client path | official adapter tests run `dbt debug` and `dbt run` against a real Embucket Lambda | -| AWS Lambda + Snowflake command-line tool via Function URL | tested | API validation, but not production-facing traffic | current Lambda README and user guidance | -| AWS Lambda + private REST API gateway | recommended deployment pattern | production-facing ingress in front of the Lambda | AWS Lambda guide with an anonymized private API Gateway example | -| AWS S3 Tables external catalog | documented and supported | current external catalog path described in these docs | current S3 Tables guide and README | - -## Not currently covered in this docs set - -The current docs should **not** claim the following as verified unless new evidence supports them: - -- serverless deployments on GCP or Azure Functions -- a non-Lambda dbt transport for `dbt-embucket` -- broad benchmark conclusions not stated in official benchmark materials -- a full migration path from `embucket-labs` unless the docs include a dedicated migration guide - -## Names used in this guide - -- Use `embucket/embucket` for the current container image in public docs. -- Use `embucket-lambda` for the AWS Lambda runtime artifact. -- Treat `embucket-labs` as legacy naming unless a guide explicitly explains otherwise. - -## Example workflows in this docs set - -- [End-to-end dbt workflow](/guides/end-to-end-dbt/) is the shortest complete Lambda + dbt path. -- [Snowplow web analytics](/guides/snowplow/) is a fuller example built on the documented Lambda + `dbt-embucket` path. -- [Self-hosted local binary](/guides/self-hosted/) covers source-build local evaluation and testing. - -## Related guides - -- [Runtime modes](/essentials/runtime-modes/) -- [AWS Lambda](/guides/aws-lambda/) -- [dbt](/guides/dbt/) -- [End-to-end dbt workflow](/guides/end-to-end-dbt/) -- [Self-hosted local binary](/guides/self-hosted/) -- [Snowplow web analytics](/guides/snowplow/) -- [Troubleshooting](/guides/troubleshooting/) diff --git a/docs/src/content/docs/essentials/quick-start-ui.png b/docs/src/content/docs/getting-started/quick-start-ui.png similarity index 100% rename from docs/src/content/docs/essentials/quick-start-ui.png rename to docs/src/content/docs/getting-started/quick-start-ui.png diff --git a/docs/src/content/docs/getting-started/quick-start.mdx b/docs/src/content/docs/getting-started/quick-start.mdx new file mode 100644 index 00000000..bec3709f --- /dev/null +++ b/docs/src/content/docs/getting-started/quick-start.mdx @@ -0,0 +1,105 @@ +--- +title: Quick Start +description: Try Embucket locally with Docker and run your first query. +sidebar: + order: 0 +--- + +import { Aside, Steps } from '@astrojs/starlight/components'; + +Try Embucket locally before deploying to AWS. + + + +1. **Start Embucket** + + Run the Embucket container: + + ```bash + docker run --name embucket --rm -p 3000:3000 embucket/embucket + ``` + + You see the following output when the container starts accepting connections: + + ```text + Listening on http://0.0.0.0:3000 + ``` + +2. **Configure Snowflake CLI** + + Install the Snowflake CLI: + + ```bash + python -m pip install snowflake-cli + ``` + + Find your configuration path: + + ```bash + snow --info + ``` + + Open the configuration file and add the following connection block: + + ```toml + [connections.local] + host = "localhost" + region = "us-east-2" + port = 3000 + protocol = "http" + database = "embucket" + schema = "public" + warehouse = "em.wh" + account = "acc.local" + user = "embucket" + password = "embucket" + ``` + + Test the connection: + + ```bash + snow connection test -c local + ``` + + A successful connection produces the following output: + + ```text + +--------------------------------------------------------+ + | key | value | + |-----------------+--------------------------------------| + | Connection name | local | + | Status | OK | + | Host | localhost | + | Account | acc.local | + | User | embucket | + | Role | | + | Database | embucket | + | Warehouse | em.wh | + +--------------------------------------------------------+ + ``` + +3. **Run your first query** + + Execute a SQL query through the Snowflake CLI: + + ```bash + snow sql -c local -q "select dateadd(day, -1, current_timestamp()) as yesterday;" + ``` + + The query returns a result like the following: + + ```text + +-------------------------------+ + | yesterday | + |-------------------------------| + | 2025-06-24T11:30:00.000+0000 | + +-------------------------------+ + ``` + + + +## Next steps + +- [AWS Lambda deployment](/deploy/aws-lambda/) -- Deploy Embucket to production. +- [Snowflake CLI](/connect/snowflake-cli/) -- Explore more connection options. +- [dbt adapter](/connect/dbt/) -- Set up analytics workflows. diff --git a/docs/src/content/docs/guides/aws-lambda.mdx b/docs/src/content/docs/guides/aws-lambda.mdx deleted file mode 100644 index 2fedb444..00000000 --- a/docs/src/content/docs/guides/aws-lambda.mdx +++ /dev/null @@ -1,255 +0,0 @@ ---- -title: AWS Lambda -description: Build, deploy, verify, and operate the current Embucket Lambda runtime. -sidebar: - order: 0 ---- - -import { Aside } from '@astrojs/starlight/components'; - -> Owner: Embucket maintainers -> Last reviewed: 2026-04-07 - -Use this guide when you want the current serverless runtime. The runtime artifact is `embucket-lambda`, and the repo includes both build metadata and deployment helpers for it. - - - -## Prerequisites - -- Rust toolchain -- `cargo-lambda` -- AWS credentials with permission to deploy and invoke Lambda -- a metastore config under `config/` -- optional env file such as `config/.env.lambda` - -## Deployment modes - -The current repo supports two distinct Lambda access patterns: - -- **Function URL + Snowflake command-line tool** for validation and manual testing -- **direct Lambda invoke via `dbt-embucket`** for the recommended client path - -Treat them differently: - -- Function URL is convenient for quick validation -- direct Lambda invoke avoids exposing a public endpoint -- private API Gateway is the safer production-facing ingress shape - -## Runtime defaults and config surface - -Current deploy metadata in the repo sets: - -| Setting | Current default | -| ------------- | -------------------------- | -| binary name | `bootstrap` | -| memory | `3008` | -| timeout | `30` | -| tracing | `Active` | -| included file | your metastore config file | - -Current deploy-time environment defaults in `Cargo.toml` are: - -| Variable | Default | -| ------------------ | -------------------------------------- | -| `LOG_FORMAT` | `json` | -| `METASTORE_CONFIG` | path to your packaged metastore config | -| `TRACING_LEVEL` | `debug` | -| `RUST_LOG` | `info` | - -Optional deploy-time inputs exposed by the Makefile include: - -| Variable | Purpose | -| --------------------- | -------------------------------------------------------- | -| `FUNCTION_NAME` | override the Lambda function name | -| `ENV_FILE` | inject env vars from a file such as `config/.env.lambda` | -| `AWS_LAMBDA_ROLE_ARN` | supply an execution role when creating a new function | -| `WITH_OTEL_CONFIG` | include an OpenTelemetry collector config file | -| `FEATURES` | enable optional cargo features such as `streaming` | -| `LAYERS` | attach extra Lambda layers | - -## Step 1: Build and deploy - -From the repository root: - -```bash -make -C crates/embucket-lambda deploy -``` - -This path builds `embucket-lambda`, deploys the `bootstrap` binary, and creates a Function URL for the test path. - -If you want to supply an env file explicitly: - -```bash -ENV_FILE=config/.env.lambda make -C crates/embucket-lambda deploy -``` - -If you need to deploy a new function with an explicit execution role: - -```bash -AWS_LAMBDA_ROLE_ARN=arn:aws:iam::123456789012:role/embucket-lambda-role make -C crates/embucket-lambda deploy -``` - -## IAM and access model - -Two IAM concerns matter in the current deployment story: - -1. **deployer permissions** for the human or CI identity running `cargo lambda deploy` -2. **execution role permissions** for the Lambda function itself - -The repo shows this explicitly: - -- the Makefile accepts `AWS_LAMBDA_ROLE_ARN` when creating a new function -- `dbt-embucket` uses AWS credentials to invoke the Lambda directly by ARN -- the private API template creates API Gateway permission to invoke the function - -Plan for at least: - -- permission to deploy or update the Lambda -- permission to read logs for verification -- permission for dbt clients to invoke the target function when using the recommended adapter path - -## Step 2: Verify the deployment - -The crate Makefile includes a built-in check: - -```bash -make -C crates/embucket-lambda verify -``` - -That runs: - -```bash -snow sql -c lambda -q "SELECT 1 as test_column" -``` - -You can also tail logs: - -```bash -make -C crates/embucket-lambda logs -``` - -For HTTP-level validation, the crate README also shows a direct login request: - -```bash -curl -X POST https://.lambda-url.us-east-2.on.aws/session/v1/login-request \ - -H "Content-Type: application/json" \ - -d '{"data": {"ACCOUNT_NAME": "account", "LOGIN_NAME": "embucket", "PASSWORD": "embucket", "CLIENT_APP_ID": "test"}}' -``` - -## What to verify before calling the deployment healthy - -- the function deploys successfully -- logs are readable in CloudWatch -- `snow sql -c lambda -q "SELECT 1 as test_column"` succeeds if you are validating the Function URL path -- `dbt debug` succeeds if you are validating the recommended adapter path -- the deployed config points at the intended metastore file - -## Step 3: Check the Snowflake command-line tool path over Function URL - -The current repo supports this as a test path. - -1. deploy the Lambda -2. capture the Function URL -3. create a `snow` connection that points to that URL -4. run a simple query such as `SELECT 1` - - - -## Step 4: Recommended production-facing ingress - -For production-facing traffic, keep the Lambda private and put an API gateway layer in front of it. - -Use a private API Gateway shape like this with your own IDs and names: - -```yaml -Parameters: - LambdaFunctionName: - Type: String - Default: embucket-lambda - VpcId: - Type: AWS::EC2::VPC::Id - Default: vpc-xxxxxxxx - SubnetIds: - Type: List - Default: subnet-aaaaaaaa,subnet-bbbbbbbb - VpcCidr: - Type: String - Default: 10.0.0.0/16 - -Resources: - ExecuteApiVpcEndpoint: - Type: AWS::EC2::VPCEndpoint - PrivateApi: - Type: AWS::ApiGateway::RestApi - LambdaInvokePermission: - Type: AWS::Lambda::Permission -``` - -This pattern provisions: - -- a private API Gateway -- a VPC endpoint for `execute-api` -- a Lambda proxy integration -- a stage named `v1` - -If your platform standard uses a custom domain, place it on top of the gateway layer rather than exposing a raw public Function URL. - -## Check limits and observability before rollout - -Before you treat a Lambda deployment as rollout-ready, check: - -- CloudWatch logs for runtime verification -- optional OpenTelemetry collector configuration via `WITH_OTEL_CONFIG` -- a state-store-backed pattern in production-style demos -- timeout and memory settings that match your expected workload -- whether your chosen ingress path matches your client path - -## Rollback and redeploy guidance - -The repo does not ship a one-command rollback wrapper, so the safest current guidance is operationally simple: - -1. keep the previous env file and metastore config under version control -2. keep the last known-good deployment inputs -3. redeploy the function with the previous config if a change regresses behavior -4. re-run the same verification command you used before the change - -If you introduce API Gateway or other surrounding infrastructure, roll it back through the same IaC path that created it. - -## Step 5: Recommended client path - -After the Lambda is live, use the [dbt adapter](/guides/dbt/) for the primary documented workflow. - -If you want the shortest full walkthrough, follow [End-to-end dbt workflow](/guides/end-to-end-dbt/). - -If you want a fuller project example on the same runtime path, follow [Snowplow web analytics](/guides/snowplow/). - -## Cleanup - -If you used the Function URL test path and want to remove it: - -```bash -aws lambda delete-function-url-config --function-name embucket-lambda -``` - -Also clean up any surrounding resources you created for the deployment path you chose: - -- Lambda function -- CloudWatch log group -- API Gateway and VPC endpoint if you used the private ingress path -- extra telemetry layers or config files if you attached them - -Remove infrastructure with the same tool that created it so the Lambda, API, and network state do not drift apart. - -## Common failure modes - -- **deploy succeeds but queries fail**: check that `METASTORE_CONFIG` points to a real packaged file -- **dbt cannot connect**: check AWS credentials and `EMBUCKET_FUNCTION_ARN` -- **Snowflake command-line tool works but should not be public**: move to the private API Gateway path -- **timeouts or truncated responses**: review timeout, memory, and whether you need `streaming` -- **no useful traces**: verify `RUST_LOG`, `TRACING_LEVEL`, and any OTEL config you attached diff --git a/docs/src/content/docs/guides/dbt.mdx b/docs/src/content/docs/guides/dbt.mdx deleted file mode 100644 index 34fa27d0..00000000 --- a/docs/src/content/docs/guides/dbt.mdx +++ /dev/null @@ -1,190 +0,0 @@ ---- -title: dbt -description: Use the official dbt-embucket adapter with the AWS Lambda runtime. -sidebar: - order: 1 ---- - -import { Aside, Steps } from '@astrojs/starlight/components'; - -> Owner: Embucket maintainers -> Last reviewed: 2026-04-07 - -This is the recommended client path in the current docs. - -The official adapter lives in the sibling repository `Embucket/dbt-embucket`. Its current configuration model is Lambda-based: the profile uses `type: embucket` and `function_arn` to reach a deployed Embucket Lambda. - -## What is currently verified - -The official adapter repository includes live integration tests that run `dbt debug` and `dbt run` against a real Embucket Lambda. - -## Prerequisites - -- a deployed Embucket Lambda -- the Lambda function ARN -- AWS credentials that can invoke the function -- Python and dbt installed locally - -## What this guide gives you - -This page gives you enough material for a first successful setup: - -- install the adapter -- create a minimal project -- configure `profiles.yml` -- run `dbt debug` -- run `dbt run` on one model - -## Step 1: Install the adapter - -```bash -python -m pip install dbt-embucket -``` - -## Step 2: Create a minimal dbt project - -Create a new working directory and project files: - -```bash -mkdir embucket-dbt-demo -cd embucket-dbt-demo -mkdir -p models -``` - -Create `dbt_project.yml`: - -```yaml -name: embucket_demo -version: 1.0.0 -config-version: 2 - -profile: embucket - -model-paths: ['models'] - -models: - embucket_demo: - +materialized: view -``` - -Create `models/hello_embucket.sql`: - -```sql -select 1 as id, 'hello embucket' as message -``` - -## Step 3: Add a profile - -Add a profile like this to `profiles.yml`: - -```yaml -embucket: - target: dev - outputs: - dev: - type: embucket - function_arn: "{{ env_var('EMBUCKET_FUNCTION_ARN') }}" - account: "{{ env_var('EMBUCKET_ACCOUNT', 'embucket') }}" - user: "{{ env_var('EMBUCKET_USER', 'embucket') }}" - password: "{{ env_var('EMBUCKET_PASSWORD', 'embucket') }}" - database: "{{ env_var('EMBUCKET_DATABASE', 'demo') }}" - schema: public - threads: 1 -``` - -Export the Lambda ARN before running dbt: - -```bash -export EMBUCKET_FUNCTION_ARN=arn:aws:lambda:us-east-2:123456789012:function:embucket-lambda -``` - -If you want to keep credentials out of the file, also export these as needed: - -```bash -export EMBUCKET_ACCOUNT=embucket -export EMBUCKET_USER=embucket -export EMBUCKET_PASSWORD=embucket -export EMBUCKET_DATABASE=demo -``` - -### Profile field reference - -| Field | Required | Meaning | -| -------------- | -------- | ------------------------------------------------ | -| `type` | yes | must be `embucket` | -| `function_arn` | yes | target Lambda ARN | -| `account` | yes | logical account identifier sent in login payload | -| `user` | yes | Embucket login name | -| `password` | yes | Embucket login password | -| `database` | yes | default database | -| `schema` | yes | default schema | -| `threads` | yes | dbt concurrency setting | - -## Step 4: Check the connection - -```bash -dbt debug -``` - -Expected success signal: - -```text -Connection test: [OK connection ok] -All checks passed! -``` - -## Step 5: Run a model - -```bash -dbt run -``` - -Expected result: - -- dbt builds the `hello_embucket` model -- the run finishes successfully -- the object is available in the configured database and schema - -## Step 6: Verify the result from a client - -If you also have the Snowflake command-line tool configured for the same environment, run: - -```bash -snow sql -c lambda -q "select * from demo.public.hello_embucket" -``` - -You should see one row with `id = 1` and `message = 'hello embucket'`. - - - -## Current caveats - -- the official adapter is currently documented as a Lambda transport, not a local-runtime transport -- the adapter explicitly marks Python models as unsupported -- the adapter uses AWS Lambda invoke semantics rather than a long-lived TCP connection -- use the support matrix when you need to distinguish verified paths from documented-only paths - -## Common setup problems - -- **`profiles.yml` not found**: make sure dbt can see your profiles directory -- **`EMBUCKET_FUNCTION_ARN` missing**: export it before `dbt debug` -- **AWS credentials missing**: the adapter needs AWS credentials that can invoke the Lambda -- **auth failures**: check `EMBUCKET_USER` and `EMBUCKET_PASSWORD` -- **runs succeed but expected data is missing**: check database, schema, and metastore configuration on the Lambda side - -## Next step - -If you want the full ordered path from deploy to verification, read [End-to-end dbt workflow](/guides/end-to-end-dbt/). - -If you want a larger analytics example on the same adapter path, read [Snowplow web analytics](/guides/snowplow/). - -## Related guides - -- [AWS Lambda](/guides/aws-lambda/) -- [End-to-end dbt workflow](/guides/end-to-end-dbt/) -- [Snowplow web analytics](/guides/snowplow/) -- [Support matrix](/essentials/support-matrix/) -- [Troubleshooting](/guides/troubleshooting/) diff --git a/docs/src/content/docs/guides/end-to-end-dbt.mdx b/docs/src/content/docs/guides/end-to-end-dbt.mdx deleted file mode 100644 index aa47a1ab..00000000 --- a/docs/src/content/docs/guides/end-to-end-dbt.mdx +++ /dev/null @@ -1,170 +0,0 @@ ---- -title: End-to-end dbt workflow -description: Deploy Embucket on AWS Lambda, connect dbt-embucket, run a minimal model, and verify the result end to end. -sidebar: - order: 2 ---- - -import { Aside, Steps } from '@astrojs/starlight/components'; - -> Owner: Embucket maintainers -> Last reviewed: 2026-04-07 - -This guide is the shortest full workflow on the docs site. It takes you from a deployed Embucket Lambda to a successful dbt run and a verified query result. - - - -## What you need - -- AWS credentials -- a deployable Embucket checkout -- `cargo-lambda` -- Python with dbt and `dbt-embucket` -- a metastore config file for your deployment - -## Step 1: Deploy Embucket Lambda - -From the repo root: - -```bash -make -C crates/embucket-lambda deploy-only -``` - -If you want to inject an env file during deploy: - -```bash -ENV_FILE=config/.env.lambda make -C crates/embucket-lambda deploy-only -``` - -Record the function ARN for the next step. - -## Step 2: Install dbt-embucket - -```bash -python -m pip install dbt-embucket -``` - -## Step 3: Create a minimal dbt project - -```bash -mkdir embucket-dbt-demo -cd embucket-dbt-demo -mkdir -p models -``` - -Create `dbt_project.yml`: - -```yaml -name: embucket_demo -version: 1.0.0 -config-version: 2 - -profile: embucket - -model-paths: ['models'] - -models: - embucket_demo: - +materialized: view -``` - -Create `models/hello_embucket.sql`: - -```sql -select 1 as id, 'hello embucket' as message -``` - -## Step 4: Configure dbt - -Export the runtime values: - -```bash -export EMBUCKET_FUNCTION_ARN=arn:aws:lambda:us-east-2:123456789012:function:embucket-lambda -export EMBUCKET_ACCOUNT=embucket -export EMBUCKET_USER=embucket -export EMBUCKET_PASSWORD=embucket -export EMBUCKET_DATABASE=demo -``` - -Create `~/.dbt/profiles.yml`: - -```yaml -embucket: - target: dev - outputs: - dev: - type: embucket - function_arn: "{{ env_var('EMBUCKET_FUNCTION_ARN') }}" - account: "{{ env_var('EMBUCKET_ACCOUNT', 'embucket') }}" - user: "{{ env_var('EMBUCKET_USER', 'embucket') }}" - password: "{{ env_var('EMBUCKET_PASSWORD', 'embucket') }}" - database: "{{ env_var('EMBUCKET_DATABASE', 'demo') }}" - schema: public - threads: 1 -``` - -## Step 5: Check the connection - -```bash -dbt debug -``` - -Look for: - -```text -Connection test: [OK connection ok] -All checks passed! -``` - -## Step 6: Run the model - -```bash -dbt run -``` - -The run should create a `hello_embucket` object in the configured target schema. - -## Step 7: Verify the result - -If you have a `snow` connection for the same deployed runtime, verify with: - -```bash -snow sql -c lambda -q "select * from demo.public.hello_embucket" -``` - -Expected result shape: - -```text -+----+-----------------+ -| id | message | -|----+-----------------| -| 1 | hello embucket | -+----+-----------------+ -``` - -## Step 8: Clean up - -When you finish, remove: - -- the demo dbt project directory -- any local exported env vars or shell profile changes -- the deployed Lambda if you created that runtime only for evaluation - -Use the same deployment path that created the Lambda to tear it down cleanly. - -## Common failure points - -- `dbt debug` fails because `EMBUCKET_FUNCTION_ARN` is missing -- AWS credentials exist locally but do not have permission to invoke the Lambda -- the Lambda points at the wrong metastore config -- the database or schema in the dbt profile does not match the target you expect - -## Where to go next - -- For deeper Lambda operations, read [AWS Lambda](/guides/aws-lambda/) -- For adapter details, read [dbt](/guides/dbt/) -- For a fuller analytics example on the same path, read [Snowplow web analytics](/guides/snowplow/) -- For known failure modes, read [Troubleshooting](/guides/troubleshooting/) diff --git a/docs/src/content/docs/guides/s3-tables.mdx b/docs/src/content/docs/guides/s3-tables.mdx deleted file mode 100644 index a6d6a5b9..00000000 --- a/docs/src/content/docs/guides/s3-tables.mdx +++ /dev/null @@ -1,241 +0,0 @@ ---- -title: AWS S3 table bucket -description: Configure Embucket to read catalog metadata from an AWS S3 table bucket. ---- - -import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; - -> Owner: Embucket maintainers -> Last reviewed: 2026-04-07 - -Use this guide when you want Embucket to read catalog metadata from AWS S3 Tables. In the current docs set, S3 table buckets are the documented external catalog path. - -## What you'll learn - -Follow this guide to: - -- Create an AWS S3 table bucket using the AWS command-line tool -- Configure Embucket with an S3 table bucket as an external catalog -- Explore schemas, tables, and existing data -- Create tables and load data using familiar SQL commands -- Verify table creation and query data through AWS Console - -## Prerequisites - -Before you begin, verify you have: - -- AWS command-line tool installed and configured with appropriate permissions -- Embucket instance running locally or in your environment -- Valid AWS credentials with S3 Tables service permissions - -S3 table buckets map naturally to the current Embucket external catalog flow: one bucket ARN maps to one configured database. - - - -## Create an S3 table bucket - - - -1. **Create the table bucket** - - Use the AWS command-line tool to create your S3 table bucket: - - ```bash - aws s3tables create-table-bucket --name my-table-bucket --region us-east-2 - ``` - - The command returns the bucket ARN: - - ```json - { - "arn": "arn:aws:s3tables:us-east-2:123456789012:bucket/my-table-bucket" - } - ``` - -2. **Record the bucket information** - - Save the following information for the next step: - - **Bucket name**: `my-table-bucket` - - **Region**: `us-east-2` - - **ARN**: The full ARN returned by the command - - - -## Configure an Embucket volume - -In Embucket, volumes store data and metadata. Define configuration statically in the configuration file. Specify the configuration file location with the `--metastore-config` flag or the `METASTORE_CONFIG` environment variable. - -Create a section in the config file `volumes` and add an entry for the S3 table bucket volume. - -```yaml -volumes: - - ident: embucket - type: s3-tables - database: demo - credentials: - credential_type: access_key - aws-access-key-id: ACCESS_KEY - aws-secret-access-key: SECRET_ACCESS_KEY - arn: arn:aws:s3tables:us-east-2:123456789012:bucket/my-table-bucket -``` - -Parameters: - -- `ident`: Volume identifier -- `type`: Volume type `s3-tables`. This remains the only supported type. -- `database`: Database name that maps to this volume -- `credentials`: AWS access credentials -- `arn`: Full S3 table bucket ARN - - - -## Explore schemas and tables - -Explore schemas and tables in the S3 table bucket using the Snowflake command-line tool or any Snowflake-compatible tool. Use [Snowflake command-line tool guide](/guides/snowflake-cli) for the information on how to connect to Embucket. - - - -1. **Connect to Embucket** - - Start a Snowflake command-line tool session: - - ```bash - snow sql -c local - ``` - -2. **Explore schemas and tables** - - Explore schemas and tables: - - ```sql - SHOW SCHEMAS IN demo; - ``` - - Output: - - ``` - +----------------------------------------------------------------------------+ - | created_on | name | kind | database_name | schema_name | - |------------+--------------------------+------+---------------+-------------| - | None | public | None | demo | None | - | None | public_derived | None | demo | None | - | None | public_scratch | None | demo | None | - | None | public_snowplow_manifest | None | demo | None | - | None | tpcds_10 | None | demo | None | - | None | tpcds_100 | None | demo | None | - | None | tpch_10 | None | demo | None | - | None | tpch_100 | None | demo | None | - | None | information_schema | None | demo | None | - +----------------------------------------------------------------------------+ - ``` - -3. **Explore tables** - - Explore tables: - - ```sql - SHOW TABLES IN demo.tpch_10; - ``` - - Output: - - ``` - +-------------------------------------------------------------+ - | created_on | name | kind | database_name | schema_name | - |------------+----------+-------+---------------+-------------| - | None | orders | TABLE | demo | tpch_10 | - | None | nation | TABLE | demo | tpch_10 | - | None | customer | TABLE | demo | tpch_10 | - | None | part | TABLE | demo | tpch_10 | - | None | lineitem | TABLE | demo | tpch_10 | - | None | partsupp | TABLE | demo | tpch_10 | - | None | region | TABLE | demo | tpch_10 | - | None | supplier | TABLE | demo | tpch_10 | - +-------------------------------------------------------------+ - ``` - -4. **Create a table with data** - - Create and populate a table in one command: - - ```sql - CREATE TABLE demo.public.users ( - id INT, - name VARCHAR(100), - email VARCHAR(100) - ) AS VALUES - (1, 'John Doe', 'john.doe@example.com'), - (2, 'Jane Doe', 'jane.doe@example.com'); - ``` - - Output: - - ``` - +-------+ - | count | - |-------| - | 2 | - +-------+ - ``` - -5. **Query the table** - - Verify you can read the data: - - ```sql - SELECT * FROM demo.public.users; - ``` - - Output: - - ``` - +----+----------+----------------------+ - | id | name | email | - |----|----------|----------------------| - | 1 | John Doe | john.doe@example.com | - | 2 | Jane Doe | jane.doe@example.com | - +----+----------+----------------------+ - ``` - - - -## Verify in AWS console - -Verify table creation and query your data directly through AWS services: - - - -1. **Open AWS Console** - - Navigate to the S3 Tables service in the AWS Console. - -2. **Locate your table bucket** - - Find the `my-table-bucket` you created earlier. - -3. **Browse tables** - - Inside the table bucket, you see: - - Database: `demo` - - Table: `users` - -4. **Query with Athena** - - Select the `users` table and choose "Query table with Athena." The SQL editor opens with your table ready for queries. - - - -![S3 table bucket query interface](s3-tables-query.png) - -## Next steps - -Now that you have S3 table buckets working with Embucket, consider: - -- **Integration**: Connect BI tools and data pipelines to your Embucket instance -- **Analytics example**: If you want a fuller dbt-based workflow on Lambda, read [Snowplow web analytics](/guides/snowplow/) diff --git a/docs/src/content/docs/guides/self-hosted.mdx b/docs/src/content/docs/guides/self-hosted.mdx deleted file mode 100644 index d1cff1ff..00000000 --- a/docs/src/content/docs/guides/self-hosted.mdx +++ /dev/null @@ -1,160 +0,0 @@ ---- -title: Self-hosted local binary -description: Build and run embucketd from source for local evaluation and testing. -sidebar: - order: 2 ---- - -import { Aside } from '@astrojs/starlight/components'; - -> Owner: Embucket maintainers -> Last reviewed: 2026-04-07 - -Use this guide when you want to build `embucketd` from source and run it locally. This path is currently for **evaluation and testing**, not the primary production deployment recommendation. - - - -## What you can do - -- build the workspace from source with `cargo build` -- start `target/debug/embucketd` with local config -- connect the Snowflake command-line tool to the local deployment -- run a query successfully - -## Prerequisites - -- Rust toolchain -- Python 3.8 or newer -- Snowflake command-line tool -- a clone of `Embucket/embucket` - -## Step 1: Build the repo - -From the repository root: - -```bash -cargo build -``` - -The repo contributing guide uses `cargo build` as the standard source-build path. - -## Step 2: Create a minimal metastore file - -Create a local `metastore.yaml` file in the repo root: - -```yaml -volumes: [] -``` - -## Step 3: Create a local env file - -Create a local `.env` file: - -```bash -cat > .env <<'EOF' -METASTORE_CONFIG=./metastore.yaml -JWT_SECRET=secret -TRACING_LEVEL=debug -RUST_LOG=info -EOF -``` - -That file sets: - -- `METASTORE_CONFIG=./metastore.yaml` -- `JWT_SECRET=secret` -- `TRACING_LEVEL=debug` -- `RUST_LOG=info` - - - -## Step 4: Start the binary - -Run the local binary from the repo root: - -```bash -target/debug/embucketd -``` - -Expected startup signals: - -- the process stays running -- the service binds to `localhost:3000` -- you can open `http://127.0.0.1:3000/` in your browser - -## Step 5: Configure the Snowflake command-line tool - -Find your Snowflake command-line tool config file: - -```bash -snow --info -``` - -Add this connection block: - -```toml -[connections.embucket] -host = "localhost" -region = "us-east-2" -port = 3000 -protocol = "http" -database = "embucket" -schema = "public" -warehouse = "em.wh" -account = "acc.local" -user = "embucket" -password = "embucket" -``` - -## Step 6: Verify the local deployment - -Check the connection: - -```bash -snow connection test -c embucket -``` - -Run a query: - -```bash -snow sql -c embucket -q "SELECT 1 AS ok" -``` - -Expected output: - -```text -+----+ -| ok | -|----| -| 1 | -+----+ -``` - -## Current limits of this path - -- this is the current source-build local workflow for evaluation and testing -- this path is not the recommended production deployment path -- the starter metastore config is minimal and does not populate example tables by itself - -If you need an external catalog or richer metadata, continue to [AWS S3 table bucket](/guides/s3-tables/). - -## Troubleshooting - -- **binary not found**: make sure `cargo build` completed successfully and run from the repo root -- **auth issues**: the local defaults are `embucket` / `embucket` unless you changed `AUTH_DEMO_USER` or `AUTH_DEMO_PASSWORD` -- **missing config**: make sure `.env` points at `./metastore.yaml` -- **Snowflake command-line tool SSL/protocol errors**: set `protocol = "http"` - -## Related guides - -- [Quick Start](/essentials/quick-start/) -- [Snowflake command-line tool](/guides/snowflake-cli/) -- [Runtime modes](/essentials/runtime-modes/) -- [Troubleshooting](/guides/troubleshooting/) diff --git a/docs/src/content/docs/guides/snowflake-cli.mdx b/docs/src/content/docs/guides/snowflake-cli.mdx deleted file mode 100644 index 841b79ad..00000000 --- a/docs/src/content/docs/guides/snowflake-cli.mdx +++ /dev/null @@ -1,102 +0,0 @@ ---- -title: Snowflake command-line tool -description: Connect the Snowflake command-line tool to Embucket for the current local test and evaluation workflow. -sidebar: - order: 3 ---- - -import { Aside, Steps } from '@astrojs/starlight/components'; - -> Owner: Embucket maintainers -> Last reviewed: 2026-04-07 - -Use this guide when you want to run the Snowflake command-line tool against a local Embucket instance. This is the current **local test and evaluation** client flow. - - - -## Prerequisites - -- Python 3.8 or newer -- Snowflake command-line tool -- Docker or a source-built local Embucket binary -- a running local Embucket instance - -## Step 1: Start Embucket - -Use either local startup path: - -- the container path in [Quick Start](/essentials/quick-start/) -- the source-build path in [Self-hosted local binary](/guides/self-hosted/) - -For the Docker path, run: - -```bash -docker run --name embucket --rm -p 3000:3000 embucket/embucket -``` - -## Step 2: Configure the Snowflake command-line tool - -Find your config file: - -```bash -snow --info -``` - -Add this connection block: - -```toml -[connections.embucket] -host = "localhost" -region = "us-east-2" -port = 3000 -protocol = "http" -database = "embucket" -schema = "public" -warehouse = "em.wh" -account = "acc.local" -user = "embucket" -password = "embucket" -``` - -Check the connection: - -```bash -snow connection test -c embucket -``` - -## Step 3: Run a query - -```bash -snow sql -c embucket -q "SELECT 1 AS ok" -``` - -Expected output: - -```text -+----+ -| ok | -|----| -| 1 | -+----+ -``` - -## Step 4: Inspect the API surface - -Open `http://127.0.0.1:3000/` to inspect the current Swagger/OpenAPI surface served by `embucketd`. - -## Troubleshooting - -- **Protocol errors:** set `protocol = "http"` in the connection block. -- **Authentication failures:** use `embucket` / `embucket` unless you changed `AUTH_DEMO_USER` or `AUTH_DEMO_PASSWORD`. -- **Connection refused:** make sure the container is running and publishing port `3000`. -- **No data or schemas:** load a metastore config or follow the [AWS S3 table bucket](/guides/s3-tables/) guide. - -## Next steps - -- For the recommended client path, read [dbt](/guides/dbt/). -- To run the local binary from source, read [Self-hosted local binary](/guides/self-hosted/). -- For AWS deployment, read [AWS Lambda](/guides/aws-lambda/). -- For runtime tradeoffs, read [Runtime modes](/essentials/runtime-modes/). diff --git a/docs/src/content/docs/guides/snowplow.mdx b/docs/src/content/docs/guides/snowplow.mdx deleted file mode 100644 index f6d3e9b3..00000000 --- a/docs/src/content/docs/guides/snowplow.mdx +++ /dev/null @@ -1,161 +0,0 @@ ---- -title: Snowplow web analytics -description: Run the embucket-snowplow example on the documented AWS Lambda plus dbt path. -sidebar: - order: 5 ---- - -import { Aside } from '@astrojs/starlight/components'; - -> Owner: Embucket maintainers -> Last reviewed: 2026-04-07 - -Use this guide when you want a fuller analytics example on top of the documented AWS Lambda + `dbt-embucket` workflow. This guide follows the public `Embucket/embucket-snowplow` repository. - - - -## What success looks like - -By the end of this guide, you should be able to: - -- deploy the Snowplow example runtime path on Lambda -- run `dbt run` successfully -- inspect derived results with `dbt show` - -## Prerequisites - -- AWS credentials -- an AWS S3 Table Bucket ARN -- `uv` or a Python environment that can run the example project -- Git - -## Step 1: Clone the example repo - -```bash -git clone https://github.com/Embucket/embucket-snowplow.git -cd embucket-snowplow -``` - -This example runs without a Snowflake account. - -## Step 2: Set deploy-time values - -Set the stack name and S3 Table Bucket ARN: - -```bash -STACK_NAME="embucket-demo-$(whoami)-$(date +%s)" -BUCKET_ARN="arn:aws:s3tables:us-east-2:YOUR_ACCOUNT:bucket/YOUR_BUCKET" -``` - -Use your own deployment values here. Database, schema, credentials, and the Lambda ARN are all deployment-defined in this flow. - -## Step 3: Deploy the Lambda stack - -```bash -aws cloudformation deploy \ - --template-file deploy/embucket-lambda.cfn.yaml \ - --stack-name "$STACK_NAME" \ - --capabilities CAPABILITY_NAMED_IAM \ - --parameter-overrides S3TableBucketArn="$BUCKET_ARN" -``` - -Capture the Lambda ARN after deploy: - -```bash -LAMBDA_ARN=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" \ - --query 'Stacks[0].Outputs[?OutputKey==`LambdaFunctionArn`].OutputValue' \ - --output text) -echo "$LAMBDA_ARN" -``` - -## Step 4: Install dependencies - -```bash -uv sync -``` - -## Step 5: Configure the dbt profile - -Start from the example profile: - -```bash -cp profiles.yml.example profiles.yml -sed -i '' "s|YOUR_LAMBDA_ARN_HERE|$LAMBDA_ARN|" profiles.yml -``` - -Review the profile values before you run dbt. Credentials, database, and schema should match your deployment choices rather than a hardcoded docs default. - -## Step 6: Install dbt packages - -```bash -uv run dbt deps --profiles-dir . -``` - -## Step 7: Patch only if package checks require it - -Some dbt packages check `target.type == 'snowflake'` and do not recognize `embucket` yet. - -If your package has that kind of target-type check, run the example patch script: - -```bash -./scripts/patch_snowplow.sh -``` - -Treat this as a **compatibility workaround**. If your package already supports `embucket` or does not hardcode `snowflake` checks, prefer the unpatched path. - -## Step 8: Load the example source data - -```bash -uv run python scripts/load_data.py "$LAMBDA_ARN" -``` - -The example loader creates the required schemas and source tables for the Snowplow workflow. - -## Step 9: Run the pipeline - -```bash -uv run dbt seed --profiles-dir . -uv run dbt run --profiles-dir . -``` - -This is the primary success signal for the example workflow. - -## Step 10: Verify the results with `dbt show` - -Run `dbt show` against one of the derived relations produced by your deployment. - -For the official example layout, start with: - -```bash -uv run dbt show --profiles-dir . --inline "SELECT * FROM demo.atomic_derived.snowplow_web_page_views" --limit 10 -``` - -You can repeat that for other derived relations, for example: - -```bash -uv run dbt show --profiles-dir . --inline "SELECT * FROM demo.atomic_derived.snowplow_web_sessions" --limit 10 -uv run dbt show --profiles-dir . --inline "SELECT * FROM demo.atomic_derived.snowplow_web_users" --limit 10 -``` - -If your deployment uses different database or schema names, update the relation names accordingly. - -## Cleanup - -Delete the CloudFormation stack when you finish: - -```bash -aws cloudformation delete-stack --stack-name "$STACK_NAME" -``` - -The example repo notes that this step doesn't remove data from your S3 Table Bucket automatically. - -## Related guides - -- [AWS Lambda](/guides/aws-lambda/) -- [dbt](/guides/dbt/) -- [End-to-end dbt workflow](/guides/end-to-end-dbt/) -- [Troubleshooting](/guides/troubleshooting/) diff --git a/docs/src/content/docs/guides/troubleshooting.mdx b/docs/src/content/docs/guides/troubleshooting.mdx deleted file mode 100644 index 8369aac6..00000000 --- a/docs/src/content/docs/guides/troubleshooting.mdx +++ /dev/null @@ -1,139 +0,0 @@ ---- -title: Troubleshooting -description: Fix the most common runtime, client, auth, and deployment mistakes in the current Embucket docs. -sidebar: - order: 4 ---- - -import { Aside } from '@astrojs/starlight/components'; - -> Owner: Embucket maintainers -> Last reviewed: 2026-04-07 - -Use this page when the documented path doesn't behave as expected. - -## Local startup succeeds, but the browser step doesn't work - -Use port `3000` for the current local runtime. - -- start command: `docker run --name embucket --rm -p 3000:3000 embucket/embucket` -- current browser-visible HTTP surface: `http://127.0.0.1:3000/` - -If you expected a separate default UI on port `8080`, treat that as stale guidance. - -If you started the local runtime from source instead of Docker, follow [Self-hosted local binary](/guides/self-hosted/) to confirm the build, env file, and startup command. - -## Snowflake command-line tool fails with protocol or SSL errors - -Set the connection protocol explicitly: - -```toml -protocol = "http" -``` - -The local quick start and current Snowflake command-line tool guide both describe the local endpoint as plain HTTP on port `3000`. - -## Authentication fails locally - -Use these default demo credentials: - -- user: `embucket` -- password: `embucket` - -If you overrode `AUTH_DEMO_USER` or `AUTH_DEMO_PASSWORD`, update your client config to match. - -## Snowflake command-line tool connects, but data doesn't appear - -The runtime only exposes what you configure. - -Check that you have supplied: - -- `METASTORE_CONFIG=./metastore.yaml`, or -- a metastore config path with actual volumes, databases, schemas, or tables - -If you want the documented external catalog path, follow [AWS S3 table bucket](/guides/s3-tables/). - -## Docs or scripts still say `embucket-labs` - -For current public docs, use: - -- container image: `embucket/embucket` -- Lambda artifact: `embucket-lambda` - -Treat `embucket-labs` references in current docs as legacy drift unless a page explicitly calls out migration or historical context. - -## Lambda works with the Snowflake command-line tool, but public access creates a problem - -That concern makes sense. The current docs treat Function URLs as a test path, not the production-ready ingress path. - -Use a private API gateway layer in front of the Lambda instead. The [AWS Lambda](/guides/aws-lambda/) guide includes an anonymized private API Gateway example you can adapt. - -## Lambda deploy succeeded, but the runtime still fails - -Check these in order: - -- the packaged config file exists at the path referenced by `METASTORE_CONFIG` -- the function has the intended memory and timeout settings -- the log group contains the startup and query errors you expect to see -- your ingress path matches your client path: Function URL for Snowflake command-line tool testing, direct invoke for dbt - -If you recently changed env vars or metastore config, redeploy with the last known-good inputs and check again. - -## dbt can't connect - -Start with these checks: - -- install `dbt-embucket` -- set `EMBUCKET_FUNCTION_ARN` -- your AWS credentials can invoke the Lambda -- your profile has `type: embucket` - -Then run: - -```bash -dbt debug -``` - -If `dbt debug` still fails, also check: - -- your local AWS credential chain can invoke Lambda -- the ARN region is correct -- deploy the target Lambda and confirm the function responds -- the Lambda-side demo credentials still match the values in your profile - -## dbt runs, but the model doesn't appear - -Check the exact target database and schema from your profile. - -For the minimal example in the docs, verify with: - -```bash -snow sql -c lambda -q "select * from demo.public.hello_embucket" -``` - -If the object goes missing, check whether the Lambda-side metastore and the dbt target schema point at the same location. - -If you follow the larger example workflow, continue with [Snowplow web analytics](/guides/snowplow/) and verify the derived tables with `dbt show`. - -## Snowplow package checks fail on `target.type` - -Some dbt packages assume `target.type == 'snowflake'` and don't recognize `embucket` yet. - -If you follow the official Snowplow example, use the patch step documented in [Snowplow web analytics](/guides/snowplow/). Treat that as a compatibility workaround, not as a default step for every dbt workload. - -## Sessions or auth feel short-lived - -The current implementation uses: - -- JWT tokens with a 3-day lifetime -- session inactivity expiry of 60 seconds - -If a long-running interactive workflow feels fragile, prefer an automated client path such as dbt instead of treating the local demo path as a long-lived session environment. - -## Still stuck? - -Work from the support matrix outward: - -1. confirm you are on a documented runtime/client pair in [Support matrix](/essentials/support-matrix/) -2. check the runtime with [Quick Start](/essentials/quick-start/) or [AWS Lambda](/guides/aws-lambda/) -3. switch to the recommended client path in [dbt](/guides/dbt/) if you need a verified workflow diff --git a/docs/src/content/docs/reference/architecture.mdx b/docs/src/content/docs/reference/architecture.mdx new file mode 100644 index 00000000..fa689866 --- /dev/null +++ b/docs/src/content/docs/reference/architecture.mdx @@ -0,0 +1,63 @@ +--- +title: Architecture +description: How Embucket handles queries, metadata, storage, and authentication. +sidebar: + order: 0 +--- + +import { Aside } from '@astrojs/starlight/components'; + +Embucket exposes a Snowflake-compatible API over lakehouse data. The system separates into five layers: runtime, metadata, storage, query execution, and authentication. + +![Embucket architecture](architecture.png) + +{/* vale Google.Parens = NO */} + +## Runtime + +Embucket runs as an AWS Lambda function (`embucket-lambda`) for production deployments. A local binary also ships through Docker for development and testing. Both entry points share the same Snowflake-compatible API router. + +{/* vale Vale.Terms = NO */} + + +{/* vale Vale.Terms = YES */} + +## Metadata + +Embucket loads metadata from a YAML metastore file or external catalogs. You can define metadata through three paths: + +- **YAML metastore config** -- Set the `METASTORE_CONFIG` environment variable to point to a YAML file that declares volumes, databases, schemas, and tables. +- **AWS S3 Tables** -- Register an S3 Tables bucket as an external catalog. Each bucket maps to one database. +- **External Iceberg tables** -- Define existing Iceberg table locations in the metastore YAML to mount tables stored in your own S3 buckets. + + + +{/* vale Google.Parens = YES */} + +## Storage + +Data stays in your object storage. Embucket reads and writes data through three components: + +- **Apache Iceberg metadata** -- Tracks table schemas, snapshots, and partitions. +- **Parquet data files** -- Stores row data in a columnar format. +- **AWS S3 or S3-compatible storage** -- Serves as the backing object store for both metadata and data files. + +## Query execution + +Embucket executes Snowflake-compatible SQL through Apache DataFusion. Query execution runs single-node per request. Each invocation handles a complete query independently. The engine doesn't distribute queries across nodes. + +## Authentication and sessions + +Embucket provides a Snowflake-compatible HTTP surface with the following endpoints: + +- `/session/v1/login-request` -- Authenticates a user and returns a JWT token. +- `/session` -- Manages session state. +- `/queries/v1/query-request` -- Submits a SQL query for execution. +- `/queries/v1/abort-request` -- Cancels a running query. + +The default demo username and password both default to `embucket`. JWT tokens have a lifetime of 3 days. Sessions expire after 60 seconds of inactivity. diff --git a/docs/src/content/docs/essentials/architecture.png b/docs/src/content/docs/reference/architecture.png similarity index 100% rename from docs/src/content/docs/essentials/architecture.png rename to docs/src/content/docs/reference/architecture.png diff --git a/docs/src/content/docs/reference/snowflake.mdx b/docs/src/content/docs/reference/snowflake.mdx new file mode 100644 index 00000000..283783e9 --- /dev/null +++ b/docs/src/content/docs/reference/snowflake.mdx @@ -0,0 +1,221 @@ +--- +title: Snowflake compatibility +description: Snowflake compatibility status, known differences, and development roadmap. +sidebar: + order: 1 +--- + +import { Aside, Steps } from '@astrojs/starlight/components'; + +Embucket provides Snowflake compatibility through SQL dialect support and REST API compatibility. This page covers core SQL compatibility and API integration for analytical workloads. Snowflake enterprise features, data governance capabilities, and advanced security configurations fall out of scope. + +Key features: + +- Snowflake v1 REST API +- SQL dialect powered by Apache DataFusion +- Compatible with snowflake-connector-python and tools that depend on it + {/* vale Vale.Terms = NO */} +- Integration with dbt, snowflake-cli, and Apache Superset + {/* vale Vale.Terms = YES */} + +## API compatibility + +{/* vale Vale.Terms = NO */} +Embucket exposes a Snowflake v1 REST API that works with any Snowflake client. The API handles login, session management, and query execution through the same endpoints that Snowflake clients expect. Testing focuses primarily on snowflake-connector-python and tools that depend on it, including dbt, snowflake-cli, and Superset. +{/* vale Vale.Terms = YES */} + +## Query engine + +Embucket uses [Apache DataFusion](https://datafusion.apache.org/) as its query engine -- an Apache Arrow-native analytical query engine. The project targets full SQL dialect compatibility with Snowflake. Embucket supports a growing set of Snowflake SQL features. DataFusion also includes some built-in functions that Snowflake doesn't provide. + +## Compatibility testing + +Embucket verifies compatibility through two test methods: + +- **SQL Logic Tests** -- Verify SQL engine compatibility by running SQL statements and comparing results against expected output. +- **dbt integration tests** -- Verify REST API compatibility by running dbt models end-to-end. Embucket uses the [dbt GitLab project](https://github.com/dbt-labs/dbt-project-evaluator) as a compatibility benchmark. + +## Architecture differences + +Snowflake operates as a managed analytics database built on FoundationDB and object storage. See the [Snowflake whitepaper](https://www.cs.cmu.edu/~15721-f24/papers/Snowflake.pdf) for details on its architecture. Embucket offers an open-source alternative that uses Apache DataFusion, Apache Iceberg, Apache Arrow, and Parquet. + +The key structural differences include: + +- **Metadata storage** -- Embucket uses external catalogs such as S3 Tables instead of FoundationDB. +- **Data format** -- Embucket stores data in Iceberg and Parquet instead of a proprietary format. +- **Query execution** -- Embucket runs single-node DataFusion with Arrow in-memory representation instead of a distributed execution engine. + + + +## Current limitations + +### Architecture + +- **Single-node execution** -- Query processing uses only one node's memory and CPU capacity. +- **No distributed parallelism** -- The engine doesn't distribute queries across nodes. +- **Single writer** -- Only one Embucket instance can write to a table at a time. + +### Data types + +- **VARIANT** -- Stored as JSON-serialized `TEXT` because Parquet, Iceberg, and Arrow don't support the VARIANT type natively. +- **Numeric type coercion** -- Type promotion and coercion rules differ from Snowflake. +- **Timestamp precision** -- Arrow uses a fixed nanosecond precision for timestamps. +- **No collation or charset support** -- All text uses UTF-8 encoding. Snowflake's collation and character set options lack support. + +### Error handling + +Error messages don't match Snowflake's error format. Arrow and DataFusion generate errors in their own format. + +### Backslash escaping + +Backslash escaping differs from Snowflake in the following cases. + +**Literal backslashes:** + +Snowflake: + +```sql +SELECT * FROM VALUES ('\\b'); +``` + +```text +\b +``` + +Embucket: + +```sql +SELECT * FROM VALUES ('\\\\b'); +``` + +```text +\b +``` + +**Special characters:** + +In both Snowflake and Embucket, the following produces a backspace character: + +```sql +SELECT * FROM VALUES ('\b'); +``` + +**Single trailing backslash:** + +Snowflake: + +```sql +SELECT * FROM VALUES ('\\'); +``` + +```text +\ +``` + +Embucket: + +```sql +SELECT * FROM VALUES ('\\'); +``` + +```text +Error: Unterminated string literal +``` + +## VARIANT data type + +Embucket stores VARIANT values as JSON-serialized `TEXT` on the storage layer. The following example demonstrates how to create, read, and inspect VARIANT data. + + + +1. **Create a table with a VARIANT column** + + ```sql + create table t2 (c1 variant) as values (parse_json('{"k1":1}')); + ``` + + ```text + Count + ----- + 1 + ``` + +2. **Read the data back** + + ```sql + select * from t2; + ``` + + ```text + c1 + ---------- + {"k1":1} + ``` + +3. **Inspect the Arrow type** + + ```sql + select arrow_typeof(c1) from t2; + ``` + + ```text + arrow_typeof(t2.c1) + -------------------- + Utf8 + ``` + + + +## Numeric type handling + +DataFusion uses different numeric types than Snowflake. Embucket uses `Decimal128` for the closest behavior to Snowflake's `NUMBER` type. + +Embucket: + +```sql +select avg(a), system$typeof(avg(a)) from values (1.0), (2.0), (10.0) as t(a); +``` + +```text +avg(a) | system$typeof(avg(a)) +--------------------|---------------------- +4.333333333333333 | Decimal128(7,5) +``` + +Snowflake: + +```sql +select avg(a), system$typeof(avg(a)) from values (1.0), (2.0), (10.0) as t(a); +``` + +```text +AVG(A) | SYSTEM$TYPEOF(AVG(A)) +----------|---------------------- +4.333333 | NUMBER(20,6)[SB16] +``` + + + +## Timestamp handling + +Arrow represents timestamps as 64-bit integers with nanosecond precision. This precision stays constant and can't change per value. Snowflake uses variable precision for timestamps. + +Timezone handling also differs. Snowflake stores a timezone offset per timestamp value. Embucket stores a timezone offset per column. Query results may vary depending on the session timezone setting. + +## Error message format + +Arrow and DataFusion generate error messages that don't match Snowflake's error format. If your app parses Snowflake error codes or messages, expect differences when running against Embucket. + +## Development roadmap + +The following areas remain under active development: + +- **VARIANT** -- Native storage support when upstream dependencies -- Parquet, Iceberg, Arrow -- add VARIANT support. +- **Numeric types** -- Dynamic precision Decimal types for aggregation functions. +- **Timestamps** -- Per-value timezone handling to match Snowflake behavior. +- **Error format** -- Align error messages and codes with Snowflake's error format. diff --git a/docs/src/content/docs/reference/troubleshooting.mdx b/docs/src/content/docs/reference/troubleshooting.mdx new file mode 100644 index 00000000..7189c4f3 --- /dev/null +++ b/docs/src/content/docs/reference/troubleshooting.mdx @@ -0,0 +1,144 @@ +--- +title: Troubleshooting +description: Common issues and solutions for Embucket deployment and client connections. +sidebar: + order: 2 +--- + +import { Aside } from '@astrojs/starlight/components'; + +This page covers common issues you may encounter when running Embucket locally, deploying to AWS Lambda, or connecting clients. Individual pages contain inline troubleshooting for their specific workflows. + +## Local startup doesn't work + +Embucket listens on port 3000 by default. Start the container with the following command: + +```bash +docker run --name embucket --rm -p 3000:3000 embucket/embucket +``` + +Verify that the HTTP surface responds at `http://127.0.0.1:3000/`. If another process already occupies port 3000, stop it or map a different host port, for example `-p 3001:3000`. + +## Snowflake CLI fails with protocol or SSL errors + +{/* vale Google.Parens = NO */} +Embucket doesn't use TLS (Transport Layer Security) for local connections. Set `protocol = "http"` in your Snowflake CLI connection configuration: +{/* vale Google.Parens = YES */} + +```toml +[connections.local] +host = "localhost" +region = "us-east-2" +port = 3000 +protocol = "http" +database = "embucket" +schema = "public" +warehouse = "em.wh" +account = "acc.local" +user = "embucket" +password = "embucket" +``` + +The Snowflake CLI defaults to HTTPS, which causes protocol and SSL errors when connecting to a plain HTTP endpoint. + +## Authentication fails + +Embucket ships with default demo credentials. The username and password both default to `embucket`. If you override these values with the `AUTH_DEMO_USER` and `AUTH_DEMO_PASSWORD` environment variables, update your client configuration to match. + +{/* vale Google.Parens = NO */} + + +{/* vale Google.Parens = YES */} + +## Data doesn't appear + +Embucket requires a metastore configuration to discover your data. Verify that the `METASTORE_CONFIG` environment variable points to a YAML file that declares your volumes, databases, schemas, or tables. + +A minimal configuration with no external volumes looks like this: + +```yaml +volumes: [] +``` + +If data still doesn't appear, confirm that the credentials and resource ARNs inside your metastore YAML remain correct. + +{/* vale Google.Parens = NO */} + + +{/* vale Google.Parens = YES */} + +## Lambda deploy succeeds but runtime fails + +When a Lambda deployment succeeds but queries fail at runtime, check the following items in order: + +1. **Metastore config** -- Verify that `METASTORE_CONFIG` points to the packaged `metastore.yaml` file inside the Lambda deployment artifact. +2. **Memory and timeout** -- Confirm that the Lambda function has enough memory, which defaults to 3008 MB, and an appropriate timeout, which defaults to 30 seconds. +3. **CloudWatch logs** -- Open the log group for your Lambda function and look for error messages that identify the root cause. +4. **Ingress path** -- Confirm that the ingress path matches the client path. Use a Function URL for the Snowflake CLI and direct Lambda invoke for dbt. + +{/* vale Vale.Terms = NO */} +{/* vale Google.Parens = NO */} + + +{/* vale Google.Parens = YES */} +{/* vale Vale.Terms = YES */} + +## dbt can't connect + +If `dbt debug` fails, work through the following checklist: + +- Install the `dbt-embucket` adapter: `python -m pip install dbt-embucket`. +- Export the `EMBUCKET_FUNCTION_ARN` environment variable with the correct Lambda ARN. +- Verify that your AWS credentials have `lambda:InvokeFunction` permission on the function ARN. +- Confirm that your `profiles.yml` contains `type: embucket` in the output configuration. + +Run `dbt debug` after each change to isolate the issue. Also check the following: + +- The AWS credential chain resolves to the correct identity. +- The ARN region matches the region where you deployed the Lambda function. +- The Lambda function exists and responds to requests. +- The demo credentials in your profile match the values configured on the Lambda function. + +## dbt runs but model doesn't appear + +Check the `database` and `schema` values in your dbt profile. The model materializes in the database and schema you specify. Verify the result with the Snowflake CLI: + +```bash +snow sql -c lambda -q "select * from demo.public.hello_embucket" +``` + +If the query returns no results, confirm that the metastore configuration on the Lambda function includes the target database and schema. + +## Snowplow package target.type check fails + +Some dbt packages, including Snowplow packages, check `target.type == 'snowflake'` and don't recognize the `embucket` target type. Run the compatibility patch script from the Snowplow demo repository to work around this check: + +```bash +./scripts/patch_snowplow.sh +``` + +This script provides a compatibility workaround. It modifies package files to accept the `embucket` target type alongside `snowflake`. + +{/* vale Google.Parens = NO */} + + +{/* vale Google.Parens = YES */} + +## Sessions feel short-lived + +Embucket issues JWT tokens with a 3-day lifetime. Sessions expire after 60 seconds of inactivity, so interactive sessions may appear to disconnect if you pause between queries. + +For long-running workflows, use automated tools like dbt rather than interactive sessions. The dbt adapter handles authentication and session management automatically. + +Treat any `embucket-labs` references in older documentation, scripts, or configuration files as outdated. diff --git a/docs/src/content/docs/tutorials/snowplow.mdx b/docs/src/content/docs/tutorials/snowplow.mdx new file mode 100644 index 00000000..96848a0a --- /dev/null +++ b/docs/src/content/docs/tutorials/snowplow.mdx @@ -0,0 +1,181 @@ +--- +title: Snowplow web analytics +description: Build a real-world analytics pipeline with Embucket, dbt, and Snowplow. +sidebar: + order: 0 +--- + +import { Aside, Steps } from '@astrojs/starlight/components'; + +Build a complete web analytics pipeline using Embucket on AWS Lambda with the dbt-embucket adapter. You deploy a Snowplow analytics runtime, run dbt transformations, and inspect derived analytics tables. This tutorial follows the [embucket-snowplow](https://github.com/Embucket/embucket-snowplow) repository and runs without a Snowflake account. + +## What you'll build + +Snowplow provides an open source behavioral data platform that captures granular, event-level web analytics. In this tutorial you connect Snowplow's dbt packages to Embucket and produce three derived tables: + +- **Page views** -- aggregated metrics for each page view event. +- **Sessions** -- session-level summaries stitched from individual events. +- **Users** -- user-level roll-ups across all sessions. + +## Prerequisites + +Before you begin, make sure you have the following: + +- AWS credentials with permissions for Lambda, CloudFormation, IAM, and S3 Tables +- An S3 Table Bucket ARN (see the [AWS Lambda deployment](/deploy/aws-lambda/) guide to create one) +- `uv` or another Python environment manager +- Git + +{/* vale Vale.Terms = NO */} +{/* vale Google.Parens = NO */} + + +{/* vale Google.Parens = YES */} +{/* vale Vale.Terms = YES */} + +## Tutorial + + + +1. **Clone the repository** + + Clone the Snowplow demo repository and change into the project directory: + + ```bash + git clone https://github.com/Embucket/embucket-snowplow.git && cd embucket-snowplow + ``` + +2. **Set deploy values** + + Define a unique stack name and your S3 Table Bucket ARN: + + ```bash + STACK_NAME="embucket-demo-$(whoami)-$(date +%s)" + BUCKET_ARN="arn:aws:s3tables:us-east-2:YOUR_ACCOUNT:bucket/YOUR_BUCKET" + ``` + + Replace `YOUR_ACCOUNT` and `YOUR_BUCKET` with your actual AWS account ID and bucket name. + +3. **Deploy the Lambda stack** + + Deploy the CloudFormation stack that provisions the Lambda function: + + ```bash + aws cloudformation deploy \ + --template-file deploy/embucket-lambda.cfn.yaml \ + --stack-name "$STACK_NAME" \ + --capabilities CAPABILITY_NAMED_IAM \ + --parameter-overrides S3TableBucketArn="$BUCKET_ARN" + ``` + + After the stack deploys, capture the Lambda function ARN: + + ```bash + LAMBDA_ARN=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" \ + --query 'Stacks[0].Outputs[?OutputKey==`LambdaFunctionArn`].OutputValue' \ + --output text) + echo "$LAMBDA_ARN" + ``` + +4. **Install dependencies** + + Install the Python dependencies with `uv`: + + ```bash + uv sync + ``` + +5. **Configure the dbt profile** + + Copy the example profile and substitute your Lambda ARN: + + ```bash + cp profiles.yml.example profiles.yml + sed -i '' "s|YOUR_LAMBDA_ARN_HERE|$LAMBDA_ARN|" profiles.yml + ``` + + + +6. **Install dbt packages** + + Pull the Snowplow dbt packages: + + ```bash + uv run dbt deps --profiles-dir . + ``` + +7. **Patch packages for compatibility** + + Run the compatibility patch script: + + ```bash + ./scripts/patch_snowplow.sh + ``` + + + +8. **Load example data** + + Load sample Snowplow event data into your S3 Table Bucket: + + ```bash + uv run python scripts/load_data.py "$LAMBDA_ARN" + ``` + +9. **Run the pipeline** + + Seed reference data and run the dbt transformations: + + ```bash + uv run dbt seed --profiles-dir . + uv run dbt run --profiles-dir . + ``` + +10. **Verify the results** + + Query the derived tables to confirm the pipeline completed successfully. + + View page views: + + ```bash + uv run dbt show --profiles-dir . --inline \ + "SELECT * FROM demo.atomic_derived.snowplow_web_page_views" --limit 10 + ``` + + View sessions: + + ```bash + uv run dbt show --profiles-dir . --inline \ + "SELECT * FROM demo.atomic_derived.snowplow_web_sessions" --limit 10 + ``` + + View users: + + ```bash + uv run dbt show --profiles-dir . --inline \ + "SELECT * FROM demo.atomic_derived.snowplow_web_users" --limit 10 + ``` + + + +## Cleanup + +Delete the CloudFormation stack to remove all deployed resources: + +```bash +aws cloudformation delete-stack --stack-name "$STACK_NAME" +``` + +