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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,24 @@ docker_start_spanner_rebuild:
docker_stop_spanner:
docker compose -f docker/docker-compose.spanner.yaml down

docker_oneshot_mysql: ## Build & run a stand-alone MySQL Syncserver (curl localhost:8000/__heartbeat__).
docker compose -f docker/docker-compose.one-shot.mysql.yaml up -d --build

docker_oneshot_mysql_stop: ## Stop the stand-alone MySQL Syncserver.
docker compose -f docker/docker-compose.one-shot.mysql.yaml down

docker_oneshot_postgres: ## Build & run a stand-alone PostgreSQL Syncserver (curl localhost:8000/__heartbeat__).
docker compose -f docker/docker-compose.one-shot.postgres.yaml up -d --build

docker_oneshot_postgres_stop: ## Stop the stand-alone PostgreSQL Syncserver.
docker compose -f docker/docker-compose.one-shot.postgres.yaml down

docker_oneshot_spanner: ## Build & run a stand-alone Spanner-emulator Syncserver, local dev only (curl localhost:8000/__heartbeat__).
docker compose -f docker/docker-compose.one-shot.spanner.yaml up -d --build

docker_oneshot_spanner_stop: ## Stop the stand-alone Spanner-emulator Syncserver.
docker compose -f docker/docker-compose.one-shot.spanner.yaml down

.ONESHELL:
docker_run_mysql_e2e_tests:
exit_code=0
Expand Down
101 changes: 101 additions & 0 deletions config/local.example.spanner.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# =============================================================================
# Default out-of-the-box configuration: Spanner build
# =============================================================================
#
# This is a ready-to-edit template for running syncstorage-rs against the
# standard Spanner build (`make run_spanner`, the `syncstorage-rs-spanner`
# Docker image). This mirrors the production topology: Syncstorage runs against
# Google Cloud Spanner, while Tokenserver runs against MySQL.
#
# Copy it to `config/local.toml` and edit the values marked REQUIRED:
#
# cp config/local.example.spanner.toml config/local.toml
#
# Every setting can also be supplied as an environment variable prefixed with
# `SYNC_` (nested keys use `__`), e.g. `syncstorage.database_url` becomes
# `SYNC_SYNCSTORAGE__DATABASE_URL`. Environment variables take precedence over
# the config file. See the full reference at docs/src/config.md, and the
# annotated `Settings` structs in `*-settings/src/lib.rs`.
#
# To run against the local Spanner emulator instead of real Spanner, set
# `syncstorage.spanner_emulator_host` (see below) and point the
# `GOOGLE_APPLICATION_CREDENTIALS` env var at a service-account key for real
# Spanner only.
#
# For the all-MySQL build, see `config/local.example.toml`.
# =============================================================================

# REQUIRED. Secret used to derive the Hawk signing/token secrets. Use a long,
# random string in any real deployment. No default.
master_secret = "INSERT_SECRET_KEY_HERE"

# Host/port the server binds to. Defaults: host = "127.0.0.1", port = 8000.
# Use "0.0.0.0" inside containers so the port is reachable from the host.
host = "127.0.0.1"
port = 8000

# Emit human-readable logs instead of mozlog JSON. Default: false (0).
human_logs = 1

# -----------------------------------------------------------------------------
# Syncstorage (BSO storage service) — Spanner
# -----------------------------------------------------------------------------

# Enable the Syncstorage service. Default: true.
syncstorage.enabled = true

# REQUIRED when syncstorage is enabled. Spanner DSN, of the form
# spanner://projects/<project>/instances/<instance>/databases/<database>.
# No usable default; the server fails fast at startup if it is unset. A
# "spanner://" scheme is what switches the syncstorage backend into Spanner
# mode (see `Settings::uses_spanner`).
syncstorage.database_url = "spanner://projects/SAMPLE_GCP_PROJECT/instances/SAMPLE_SPANNER_INSTANCE/databases/SAMPLE_SPANNER_DB"

# Local Spanner emulator host. Leave unset for real Spanner. When running the
# emulator (e.g. via docker/docker-compose.spanner.yaml) set this to the
# emulator's gRPC address so the client talks to the emulator instead of GCP.
# syncstorage.spanner_emulator_host = "localhost:9010"

# Max size of the syncstorage DB connection pool. Default: 10.
# syncstorage.database_pool_max_size = 10

# Quota tracking/enforcement (Spanner-only). Both default to false. Enable
# tracking to record per-user usage; additionally enable enforcement to reject
# writes over `limits.max_quota_limit` (default 2 GB).
syncstorage.enable_quota = 0
# syncstorage.enforce_quota = 0

# -----------------------------------------------------------------------------
# Tokenserver (node assignment + FxA OAuth verification) — MySQL
# -----------------------------------------------------------------------------

# Enable Tokenserver. Default: false.
tokenserver.enabled = true

# REQUIRED when tokenserver is enabled. In the production topology Tokenserver
# uses MySQL even when Syncstorage uses Spanner. No usable default.
tokenserver.database_url = "mysql://sample_user:sample_password@localhost/tokenserver_rs"

# Backend type reported in the token response (telemetry only). For the Spanner
# topology leave this as the default "spanner". Valid: "mysql"/"postgres"/"spanner".
tokenserver.node_type = "spanner"

# Run the tokenserver DB migrations on startup. Default: false.
# tokenserver.run_migrations = true

# FxA environment used to verify OAuth tokens. The defaults below point at the
# FxA *stage* environment; point them at production for a real deployment
# (fxa_email_domain = "api.accounts.firefox.com",
# fxa_oauth_server_url = "https://oauth.accounts.firefox.com").
tokenserver.fxa_email_domain = "api-accounts.stage.mozaws.net"
tokenserver.fxa_oauth_server_url = "https://oauth.stage.mozaws.net"

# REQUIRED for real deployments. Secret used to hash users' metrics UIDs so
# they stay anonymous. Default: "secret" (fine for local dev only).
tokenserver.fxa_metrics_hash_secret = "INSERT_SECRET_KEY_HERE"

# -----------------------------------------------------------------------------
# CORS (optional; sensible defaults applied when unset)
# -----------------------------------------------------------------------------
# cors_allowed_origin = "localhost" # Default: "*"
# cors_max_age = 86400 # Default: 1728000 (20 days)
102 changes: 83 additions & 19 deletions config/local.example.toml
Original file line number Diff line number Diff line change
@@ -1,31 +1,95 @@
# =============================================================================
# Default out-of-the-box configuration: MySQL build
# =============================================================================
#
# This is a ready-to-edit template for running syncstorage-rs against the
# standard MySQL build (the default `cargo build` / `make run_mysql` target,
# and the `syncstorage-rs-mysql` Docker image). It runs both Syncstorage and
# Tokenserver against MySQL.
#
# Copy it to `config/local.toml` and edit the values marked REQUIRED:
#
# cp config/local.example.toml config/local.toml
#
# Every setting can also be supplied as an environment variable prefixed with
# `SYNC_` (nested keys use `__`), e.g. `syncstorage.database_url` becomes
# `SYNC_SYNCSTORAGE__DATABASE_URL`. Environment variables take precedence over
# the config file. See the full reference at docs/src/config.md, and the
# annotated `Settings` structs in `*-settings/src/lib.rs`.
#
# For the Spanner build, see `config/local.example.spanner.toml`.
# =============================================================================

# REQUIRED. Secret used to derive the Hawk signing/token secrets. Use a long,
# random string in any real deployment. No default; the server cannot
# authenticate requests without it.
master_secret = "INSERT_SECRET_KEY_HERE"

# removing this line will default to moz_json formatted logs (which is preferred for production envs)
# Host/port the server binds to. Defaults: host = "127.0.0.1", port = 8000.
# Use "0.0.0.0" inside containers so the port is reachable from the host.
host = "127.0.0.1"
port = 8000

# Emit human-readable logs instead of mozlog JSON. Default: false (0).
# Leave JSON logging on for production; it is the format our tooling expects.
human_logs = 1

# Example Syncstorage settings:
# database_url is required when syncstorage is enabled; there is no default,
# and the server fails to start if it is unset.
# Example MySQL DSN:
# -----------------------------------------------------------------------------
# Syncstorage (BSO storage service)
# -----------------------------------------------------------------------------

# Enable the Syncstorage service. Default: true.
syncstorage.enabled = true

# REQUIRED when syncstorage is enabled. MySQL DSN for the syncstorage database.
# There is no usable default: the server fails fast at startup if it is unset,
# rather than silently connecting to a default host.
syncstorage.database_url = "mysql://sample_user:sample_password@localhost/syncstorage_rs"
# Example Spanner DSN:
# syncstorage.database_url="spanner://projects/SAMPLE_GCP_PROJECT/instances/SAMPLE_SPANNER_INSTANCE/databases/SAMPLE_SPANNER_DB"
# enable quota limits

# Max size of the syncstorage DB connection pool. Default: 10.
# syncstorage.database_pool_max_size = 10

# Quota tracking/enforcement are Spanner-only features and are force-disabled
# for non-Spanner backends, so they have no effect on the MySQL build.
syncstorage.enable_quota = 0
# set the quota limit to 2GB.
# max_quota_limit = 200000000
syncstorage.enabled = true

# Request/batch limits. Defaults shown in docs/src/config.md (Syncstorage
# Limits). `max_total_records` is also used to cap MySQL `get_bsos` result
# sizes; see issues #298/#333.
syncstorage.limits.max_total_records = 9984

# Example Tokenserver settings:
# database_url is required when tokenserver is enabled; there is no default,
# and the server fails to start if it is unset.
tokenserver.database_url = "mysql://sample_user:sample_password@localhost/tokenserver_rs"
# -----------------------------------------------------------------------------
# Tokenserver (node assignment + FxA OAuth verification)
# -----------------------------------------------------------------------------

# Enable Tokenserver. Default: false. Enable it for a self-contained server
# that both assigns nodes and stores data.
tokenserver.enabled = true

# REQUIRED when tokenserver is enabled. MySQL DSN for the tokenserver database.
# No usable default; the server fails fast at startup if it is unset.
tokenserver.database_url = "mysql://sample_user:sample_password@localhost/tokenserver_rs"

# Backend type reported in the token response (telemetry only). For the MySQL
# build set this to "mysql". Default: "spanner". Valid: "mysql"/"postgres"/"spanner".
tokenserver.node_type = "mysql"

# Run the tokenserver DB migrations on startup. Default: false.
# tokenserver.run_migrations = true

# FxA environment used to verify OAuth tokens. The defaults below point at the
# FxA *stage* environment; point them at production for a real deployment
# (fxa_email_domain = "api.accounts.firefox.com",
# fxa_oauth_server_url = "https://oauth.accounts.firefox.com").
tokenserver.fxa_email_domain = "api-accounts.stage.mozaws.net"
tokenserver.fxa_metrics_hash_secret = "INSERT_SECRET_KEY_HERE"
tokenserver.fxa_oauth_server_url = "https://oauth.stage.mozaws.net"

# cors settings
# cors_allowed_origin = "localhost"
# cors_max_age = 86400
# REQUIRED for real deployments. Secret used to hash users' metrics UIDs so
# they stay anonymous. Default: "secret" (fine for local dev only).
tokenserver.fxa_metrics_hash_secret = "INSERT_SECRET_KEY_HERE"

# -----------------------------------------------------------------------------
# CORS (optional; sensible defaults applied when unset)
# -----------------------------------------------------------------------------
# cors_allowed_origin = "localhost" # Default: "*"
# cors_max_age = 86400 # Default: 1728000 (20 days)
112 changes: 112 additions & 0 deletions docker/docker-compose.one-shot.mysql.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# One-shot, stand-alone MySQL-backed Syncserver.
#
# Unlike docker-compose.mysql.yaml (which is an end-to-end test harness:
# mock FxA server, prebuilt `app:build` image), this brings up a working
# server in a single command with no manual database setup:
#
# make docker_oneshot_mysql
# # or:
# docker compose -f docker/docker-compose.one-shot.mysql.yaml up -d --build
#
# Then confirm it is serving:
#
# curl http://localhost:8000/__heartbeat__
#
# Syncstorage applies its schema migrations at startup,
# SYNC_TOKENSERVER__RUN_MIGRATIONS applies the Tokenserver schema, and
# SYNC_TOKENSERVER__INIT_NODE_URL bootstraps the `sync-1.5` service and storage
# node records.
#
# This builds the MySQL server from the local checkout (build context is the
# repo root), so it does not depend on any published image. To use a published
# image instead, replace the syncserver `build:` block with:
#
# image: ghcr.io/mozilla-services/syncstorage-rs/syncstorage-rs-mysql:${SYNCSERVER_VERSION:?set SYNCSERVER_VERSION to a published tag}
# platform: linux/amd64
#
# Published images are tagged by commit SHA (no `latest`/semver), so
# SYNCSERVER_VERSION must be a tag from the syncstorage-rs-mysql packages page.
#
# Set SYNC_MASTER_SECRET to your own value for anything beyond local
# experimentation; the default below is a placeholder.

services:
syncserver:
build:
context: ..
args:
SYNCSTORAGE_DATABASE_BACKEND: mysql
TOKENSERVER_DATABASE_BACKEND: mysql
container_name: syncserver
ports:
- "${SYNC_PORT:-8000}:${SYNC_PORT:-8000}"
environment:
SYNC_HOST: "0.0.0.0"
SYNC_PORT: "${SYNC_PORT:-8000}"
SYNC_MASTER_SECRET: "${SYNC_MASTER_SECRET:-changeme_secret_key}"
SYNC_SYNCSTORAGE__DATABASE_URL: "mysql://sync:sync@sync-db:3306/syncstorage"
SYNC_TOKENSERVER__DATABASE_URL: "mysql://sync:sync@tokenserver-db:3306/tokenserver"
SYNC_TOKENSERVER__ENABLED: "true"
SYNC_TOKENSERVER__NODE_TYPE: "mysql"
SYNC_TOKENSERVER__RUN_MIGRATIONS: "true"
SYNC_TOKENSERVER__FXA_EMAIL_DOMAIN: "api.accounts.firefox.com"
SYNC_TOKENSERVER__FXA_OAUTH_SERVER_URL: "https://oauth.accounts.firefox.com"
SYNC_HUMAN_LOGS: "${SYNC_HUMAN_LOGS:-false}"
RUST_LOG: "${RUST_LOG:-info}"
SYNC_TOKENSERVER__INIT_NODE_URL: "${SYNC_TOKENSERVER__INIT_NODE_URL:-http://localhost:${SYNC_PORT:-8000}}"
depends_on:
sync-db:
condition: service_healthy
tokenserver-db:
condition: service_healthy
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:${SYNC_PORT:-8000}/__heartbeat__"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s

sync-db:
image: docker.io/library/mysql:8.0
container_name: syncserver-sync-db
command: --explicit_defaults_for_timestamp
environment:
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
MYSQL_DATABASE: syncstorage
MYSQL_USER: sync
MYSQL_PASSWORD: sync
volumes:
- sync_db_data:/var/lib/mysql
healthcheck:
test: ["CMD-SHELL", "mysqladmin -h 127.0.0.1 -usync -psync ping"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
restart: unless-stopped

tokenserver-db:
image: docker.io/library/mysql:8.0
container_name: syncserver-tokenserver-db
command: --explicit_defaults_for_timestamp
environment:
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
MYSQL_DATABASE: tokenserver
MYSQL_USER: sync
MYSQL_PASSWORD: sync
volumes:
- tokenserver_db_data:/var/lib/mysql
healthcheck:
test: ["CMD-SHELL", "mysqladmin -h 127.0.0.1 -usync -psync ping"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
restart: unless-stopped

volumes:
sync_db_data:
driver: local
tokenserver_db_data:
driver: local
Loading