• Stars
    star
    839
  • Rank 53,947 (Top 2 %)
  • Language
    Rust
  • License
    Mozilla Public Li...
  • Created about 6 years ago
  • Updated 2 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Sync Storage server in Rust

License: MPL 2.0 Build Status Connect to Matrix via the Riot webapp

Syncstorage-rs

Mozilla Sync Storage built with Rust.

System Requirements

  • cmake
  • gcc
  • golang
  • libcurl4-openssl-dev
  • libssl-dev
  • make
  • pkg-config
  • Rust stable
  • python 3.9+
  • MySQL 5.7 (or compatible)
    • libmysqlclient (brew install mysql on macOS, apt install libmysqlclient-dev on Ubuntu, apt install libmariadb-dev-compat on Debian)

Depending on your OS, you may also need to install libgrpcdev, and protobuf-compiler-grpc. Note: if the code complies cleanly, but generates a Segmentation Fault within Sentry init, you probably are missing libcurl4-openssl-dev.

Local Setup

  1. Follow the instructions below to use either MySQL or Spanner as your DB.

  2. Now cp config/local.example.toml config/local.toml. Open config/local.toml and make sure you have the desired settings configured. For a complete list of available configuration options, check out docs/config.md.

  3. To start a local server in debug mode, run either:

    • make run_mysql if using MySQL or,
    • make run_spanner if using spanner.

    The above starts the server in debug mode, using your new local.toml file for config options. Or, simply cargo run with your own config options provided as env vars.

  4. Visit http://localhost:8000/__heartbeat__ to make sure the server is running.

MySQL

Durable sync needs only a valid mysql DSN in order to set up connections to a MySQL database. The database can be local and is usually specified with a DSN like:

mysql://_user_:_password_@_host_/_database_

To setup a fresh MySQL DB and user:

  • First make sure that you have a MySQL server running, to do that run: mysqld
  • Then, run the following to launch a mysql shell mysql -u root
  • Finally, run each of the following SQL statements
CREATE USER "sample_user"@"localhost" IDENTIFIED BY "sample_password";
CREATE DATABASE syncstorage_rs;
CREATE DATABASE tokenserver_rs;

GRANT ALL PRIVILEGES on syncstorage_rs.* to sample_user@localhost;
GRANT ALL PRIVILEGES on tokenserver_rs.* to sample_user@localhost;

Spanner

Authenticating via OAuth

The correct way to authenticate with Spanner is by generating an OAuth token and pointing your local application server to the token. In order for this to work, your Google Cloud account must have the correct permissions; contact the Ops team to ensure the correct permissions are added to your account.

First, install the Google Cloud command-line interface by following the instructions for your operating system here. Next, run the following to log in with your Google account (this should be the Google account associated with your Mozilla LDAP credentials):

gcloud auth application-default login

The above command will prompt you to visit a webpage in your browser to complete the login process. Once completed, ensure that a file called application_default_credentials.json has been created in the appropriate directory (on Linux, this directory is $HOME/.config/gcloud/). The Google Cloud SDK knows to check this location for your credentials, so no further configuration is needed.

Key Revocation

Accidents happen, and you may need to revoke the access of a set of credentials if they have been publicly leaked. To do this, run:

gcloud auth application-default revoke

This will revoke the access of the credentials currently stored in the application_default_credentials.json file. If the file in that location does not contain the leaked credentials, you will need to copy the file containing the leaked credentials to that location and re-run the above command. You can ensure that the leaked credentials are no longer active by attempting to connect to Spanner using the credentials. If access has been revoked, your application server should print an error saying that the token has expired or has been revoked.

Authenticating via Service Account

An alternative to authentication via application default credentials is authentication via a service account. Note that this method of authentication is not recommended. Service accounts are intended to be used by other applications or virtual machines and not people. See this article for more information.

Your system administrator will be able to tell you which service account keys have access to the Spanner instance to which you are trying to connect. Once you are given the email identifier of an active key, log into the Google Cloud Console Service Accounts page. Be sure to select the correct project.

  • Locate the email identifier of the access key and pick the vertical dot menu at the far right of the row.
  • Select "Create Key" from the pop-up menu.
  • Select "JSON" from the Dialog Box.

A proper key file will be downloaded to your local directory. It's important to safeguard that key file. For this example, we're going to name the file service-account.json.

The proper key file is in JSON format. An example file is provided below, with private information replaced by "..."

{
  "type": "service_account",
  "project_id": "...",
  "private_key_id": "...",
  "private_key": "...",
  "client_email": "...",
  "client_id": "...",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "..."
}

Note that the name service-account.json must be exactly correct to be ignored by .gitignore.

Connecting to Spanner

To point to a GCP-hosted Spanner instance from your local machine, follow these steps:

  1. Authenticate via either of the two methods outlined above.
  2. Open local.toml and replace database_url with a link to your spanner instance.
  3. Open the Makefile and ensure you've correctly set you PATH_TO_GRPC_CERT.
  4. make run_spanner.
  5. Visit http://localhost:8000/__heartbeat__ to make sure the server is running.

Note, that unlike MySQL, there is no automatic migrations facility. Currently, the Spanner schema must be hand edited and modified.

Emulator

Google supports an in-memory Spanner emulator, which can run on your local machine for development purposes. You can install the emulator via the gcloud CLI or Docker by following the instructions here. Once the emulator is running, you'll need to create a new instance and a new database. To create an instance using the REST API (exposed via port 9020 on the emulator), we can use curl:

curl --request POST \
  "localhost:9020/v1/projects/$PROJECT_ID/instances" \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data "{\"instance\":{\"config\":\"emulator-test-config\",\"nodeCount\":1,\"displayName\":\"Test Instance\"},\"instanceId\":\"$INSTANCE_ID\"}"

Note that you may set PROJECT_ID and INSTANCE_ID to your liking. To create a new database on this instance, we'll use a similar HTTP request, but we'll need to include information about the database schema. Since we don't have migrations for Spanner, we keep an up-to-date schema in src/db/spanner/schema.ddl. The jq utility allows us to parse this file for use in the JSON body of an HTTP POST request:

DDL_STATEMENTS=$(
  grep -v ^-- schema.ddl \
  | sed -n 's/ \+/ /gp' \
  | tr -d '\n' \
  | sed 's/\(.*\);/\1/' \
  | jq -R -s -c 'split(";")'
)

Finally, to create the database:

curl -sS --request POST \
  "localhost:9020/v1/projects/$PROJECT_ID/instances/$INSTANCE_ID/databases" \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data "{\"createStatement\":\"CREATE DATABASE \`$DATABASE_ID\`\",\"extraStatements\":$DDL_STATEMENTS}"

Note that, again, you may set DATABASE_ID to your liking. Make sure that the database_url config variable reflects your choice of project name, instance name, and database name (i.e. it should be of the format spanner://projects/<your project ID here>/instances/<your instance ID here>/databases/<your database ID here>).

To run an application server that points to the local Spanner emulator:

SYNC_SYNCSTORAGE__SPANNER_EMULATOR_HOST=localhost:9010 make run_spanner

Running via Docker

This requires access to the mozilla-rust-sdk which is now available at /vendor/mozilla-rust-sdk.

  1. Make sure you have Docker installed locally.
  2. Copy the contents of mozilla-rust-sdk into top level root dir here.
  3. Change cargo.toml mozilla-rust-sdk entry to point to "path = "mozilla-rust-sdk/googleapis-raw" instead of the parent dir.
  4. Comment out the image value under syncserver in either docker-compose.mysql.yml or docker-compose.spanner.yml (depending on which database backend you want to run), and add this instead:
      build:
        context: .
  5. If you are using MySQL, adjust the MySQL db credentials in docker-compose.mysql.yml to match your local setup.
  6. make docker_start_mysql or make docker_start_spanner - You can verify it's working by visiting localhost:8000/__heartbeat__

Connecting to Firefox

This will walk you through the steps to connect this project to your local copy of Firefox.

  1. Follow the steps outlined above for running this project using MySQL.

  2. Setup a local copy of syncserver, with a few special changes to syncserver.ini; make sure that you're using the following values (in addition to all of the other defaults):

    [server:main]
    port = 5000
    
    [syncserver]
    public_url = http://localhost:5000/
    
    # This value needs to match your "master_secret" for syncstorage-rs!
    secret = INSERT_SECRET_KEY_HERE
    
    [tokenserver]
    node_url = http://localhost:8000
    sqluri = pymysql://sample_user:[email protected]/syncstorage_rs
    
    [endpoints]
    sync-1.5 = "http://localhost:8000/1.5/1"```
    
    
  3. In Firefox, go to about:config. Change identity.sync.tokenserver.uri to http://localhost:5000/token/1.0/sync/1.5.

  4. Restart Firefox. Now, try syncing. You should see new BSOs in your local MySQL instance.

Logging

Sentry:

  1. If you want to connect to the existing Sentry project for local development, login to Sentry, and go to the page with api keys. Copy the DSN value.
  2. Comment out the human_logs line in your config/local.toml file.
  3. You can force an error to appear in Sentry by adding a panic! into main.rs, just before the final Ok(()).
  4. Now, SENTRY_DSN={INSERT_DSN_FROM_STEP_1_HERE} make run.
  5. You may need to stop the local server after it hits the panic! before errors will appear in Sentry.

RUST_LOG

We use env_logger: set the RUST_LOG env var.

Tests

Unit tests

make test - open the Makefile to adjust your SYNC_SYNCSTORAGE__DATABASE_URL as needed.

Debugging unit test state

In some cases, it is useful to inspect the mysql state of a failed test. By default, we use the diesel test_transaction functionality to ensure test data is not committed to the database. Therefore, there is an environment variable which can be used to turn off test_transaction.

    SYNC_SYNCSTORAGE__DATABASE_USE_TEST_TRANSACTIONS=false cargo test [testname]

Note that you will almost certainly want to pass a single test name. When running the entire test suite, data from previous tests will cause future tests to fail.

To reset the database state between test runs, drop and recreate the database in the mysql client:

    drop database syncstorage_rs; create database syncstorage_rs; use syncstorage_rs;

End-to-End tests

Functional tests live in server-syncstorage and can be run against a local server, e.g.:

  1. If you haven't already followed the instructions here to get all the dependencies for the server-syncstorage repo, you should start there.

  2. Install (Python) server-syncstorage:

     $ git clone https://github.com/mozilla-services/server-syncstorage/
     $ cd server-syncstorage
     $ make build
    
  3. Run an instance of syncstorage-rs (cargo run in this repo).

  4. To run all tests:

     $ ./local/bin/python syncstorage/tests/functional/test_storage.py http://localhost:8000#<SOMESECRET>
    
  5. Individual tests can be specified via the SYNC_TEST_PREFIX env var:

    $ SYNC_TEST_PREFIX=test_get_collection \
        ./local/bin/python syncstorage/tests/functional/test_storage.py http://localhost:8000#<SOMESECRET>
    

Creating Releases

  1. Switch to master branch of syncstorage-rs
  2. git pull to ensure that the local copy is up-to-date.
  3. git pull origin master to make sure that you've incorporated any changes to the master branch.
  4. git diff origin/master to ensure that there are no local staged or uncommited changes.
  5. Bump the version number in Cargo.toml (this new version number will be designated as <version> in this checklist)
  6. create a git branch for the new version git checkout -b release/<version>
  7. cargo build --release - Build with the release profile release mode.
  8. clog -C CHANGELOG.md - Generate release notes. We're using clog for release notes. Add a -p, -m or -M flag to denote major/minor/patch version, ie clog -C CHANGELOG.md -p.
  9. Review the CHANGELOG.md file and ensure all relevant changes since the last tag are included.
  10. Create a new release in Sentry: VERSION={release-version-here} bash scripts/sentry-release.sh. If you're doing this for the first time, checkout the tips below for troubleshooting sentry cli access.
  11. git commit -am "chore: tag <version>" to commit the new version and changes
  12. git tag -s -m "chore: tag <version>" <version> to create a signed tag of the current HEAD commit for release.
  13. git push origin release/<version> to push the commits to a new origin release branch
  14. git push --tags origin release/<version> to push the tags to the release branch.
  15. Submit a Pull Request (PR) on github to merge the release branch to master.
  16. Go to the GitHub release, you should see the new tag with no release information.
  17. Click the Draft a new release button.
  18. Enter the <version> number for Tag version.
  19. Copy and paste the most recent change set from CHANGELOG.md into the release description, omitting the top 2 lines (the name and version)
  20. Once your PR merges, click [Publish Release] on the GitHub release page.

Sync server is automatically deployed to STAGE, however QA may need to be notified if testing is required. Once QA signs off, then a bug should be filed to promote the server to PRODUCTION.

Troubleshooting

  • rm Cargo.lock; cargo clean; - Try this if you're having problems compiling.

  • Some versions of OpenSSL 1.1.1 can conflict with grpcio's built in BoringSSL. These errors can cause syncstorage to fail to run or compile. If you see a problem related to libssl you may need to specify the cargo option --features grpcio/openssl to force grpcio to use OpenSSL.

Sentry

  • If you're having trouble working with Sentry to create releases, try authenticating using their self hosted server option that's outlined here Ie, sentry-cli --url https://selfhosted.url.com/ login. It's also recommended to create a .sentryclirc config file. See this example for the config values you'll need.

Related Documentation

More Repositories

1

heka

DEPRECATED: Data collection and processing made easy.
Go
3,408
star
2

syncserver

Run-Your-Own Firefox Sync Server
Python
1,794
star
3

hindsight

Hindsight - light weight data processing skeleton
C
670
star
4

screenshots

Firefox Screenshots: the best way to take screenshots on the web.
FreeMarker
621
star
5

socorro

Socorro is the Mozilla crash ingestion pipeline. It accepts and processes Breakpad-style crash reports. It provides analysis tools.
Python
584
star
6

lua_sandbox

Generic Lua sandbox for dynamic data analysis
C
226
star
7

ios-sync-client

A standalone iOS client for Firefox Sync
C
219
star
8

autopush

Python Web Push Server used by Mozilla
Python
215
star
9

autopush-rs

Push Server in Rust
Rust
193
star
10

Dockerflow

Cloud Services Dockerflow specification
JavaScript
192
star
11

google-cloud-rust

Google Cloud Client Library for Rust
Rust
174
star
12

autograph

Mozilla's digital signature service
Go
141
star
13

shavar-prod-lists

Shavar/tracking protection lists used in prod
Python
139
star
14

GitHub-Audit

INACTIVE - Collection of Tools & Procedures for double checking GitHub configurations
Python
138
star
15

loads

SUPERSEDED BY https://github.com/loads
Go
107
star
16

powerhose

Runs workers via zmq to perform any kind of task
Python
98
star
17

server-syncstorage

The SyncServer server software, as used by Firefox Sync
Python
88
star
18

websec-check

web security checklist for Firefox Services
72
star
19

lua_sandbox_extensions

Extension packages (sandboxes and modules) for the lua_sandbox project
Lua
72
star
20

cliquet

CLIQUET IS NOW DEPRECATED use kinto.core instead
Python
65
star
21

loop-server

The mozilla loop server
JavaScript
61
star
22

tokenserver

The Mozilla Token Server
Python
61
star
23

iprepd

Centralized IP reputation daemon
Go
56
star
24

axe-selenium-python

aXe Selenium Integration python package
Python
56
star
25

android-sync

An outdated mirror of services and related code for Firefox for Android. See gecko-dev/mozilla-central.
Java
52
star
26

tokenlib

generic support library for signed-token-based auth schemes
Python
50
star
27

firefox-send-tab-to-device

OBSOLETE. A Firefox add-on that uses Sync to send tabs to remote devices.
JavaScript
46
star
28

mozilla-pipeline-schemas

Schemas for Mozilla's data ingestion pipeline and data lake outputs
Python
46
star
29

queuey

Mozilla Message Queue
Python
42
star
30

syncclient

Python client for Firefox Sync
Python
42
star
31

pyramid_multiauth

stacked authentication policies for pyramid
Python
41
star
32

guardian-vpn-windows-deprecated

Mozilla VPN for Windows
C#
41
star
33

userplex

Propagate users from Mozilla's Person API to third party systems.
Go
40
star
34

fernet-rs

Fernet implementation in Rust
Rust
40
star
35

go-cose

go library for CBOR Object Signing and Encryption (COSE)
Go
40
star
36

requests-hawk

Hawk authentication strategy for the requests python library.
Python
39
star
37

megaphone

Firefox Global Broadcast API
Rust
38
star
38

python-dockerflow

A Python package to implement tools and helpers for Mozilla Dockerflow
Python
38
star
39

metlog-py

Python library for Services metrics logging
Python
37
star
40

readinglist

Reading List Server
Python
34
star
41

konfig

Yet another configuration object
Python
34
star
42

mozservices

Various utilities for Pyramid-based Mozilla applications
Python
34
star
43

reaper

Reaper culls leftover AWS resources
Go
34
star
44

go-syncstorage

INACTIVE - SyncStorage Server with more golang and less indexes!
Go
32
star
45

merino

Web service for Firefox Suggest
Rust
31
star
46

tecken

Mozilla Symbol Server
Python
31
star
47

data-pipeline

Mozilla Services Data Pipeline
Lua
30
star
48

heka-build

Heka build environment
Python
29
star
49

heka-py

DEPRECATED - Heka Python Library - DEPRECATED
Python
29
star
50

heka-mozsvc-plugins

Set of heka plugins in use by Mozilla Services
Go
28
star
51

aws-signing-proxy

signs http requests using AWS V4 signer
Go
27
star
52

foxsec-pipeline

Log analysis pipeline utilizing Apache Beam
Java
25
star
53

services-central-legacy

Sync working branch. `master` in this repository is stable, and tracks https://hg.mozilla.org/services/services-central. Other branches are owned by developers, and are subject to change.
C++
24
star
54

minidump-stackwalk

Socorro breakpad minidump stackwalker
C++
21
star
55

telescope

A dumb auditing service
Python
21
star
56

antenna

Antenna is the collector for the Socorro crash ingestion pipeline
Python
20
star
57

shavar

Tracking Protection update service for Firefox based on Safe Browsing protocol
Python
20
star
58

zktools

Zookeeper Tools
Python
19
star
59

contile

This is the back-end server for the Mozilla Tile Service (MTS)
Rust
19
star
60

tuxedo

An improved version of Mozilla's download load balancer Bouncer, with a user interface written in Django/Python.
Python
18
star
61

shavar-plugin-blocklist

โŒ Firefox plugin blocklist
XSLT
18
star
62

demoapp

An empty app for the next-gen Services app
Python
17
star
63

marteau

client-server on the top of Funkload
Python
16
star
64

msisdn-gateway

An MSISDN based Authentication Server.
JavaScript
16
star
65

docs

Documentation for Mozilla Services Services
Makefile
16
star
66

tigerblood

Deprecated, use https://github.com/mozilla-services/iprepd
Go
15
star
67

readinglist-client

Readinglist client
JavaScript
14
star
68

ldappool

A Pool for python-ldap
14
star
69

buildhub

DEPRECATED: Mozilla Build Metadata Service
Python
13
star
70

skeleton

A Skeleton actix app
Rust
13
star
71

heka-node

DEPRECATED - This repository is no longer maintained. Please go over to : https://github.com/disqus/heka-node
JavaScript
13
star
72

deepspeech-server

Rust
13
star
73

go-bouncer

A Go version of the redirector portion of bouncer.
Go
13
star
74

zipalign

DEPRECATED - Golang implementation of Android's ZipAlign tool
Go
13
star
75

kinto-dist

Kinto Distribution for Mozilla Services
Python
12
star
76

server-full2

Experimental Run-Your-Own Sync2.0 Server
Python
12
star
77

shavar-list-creation

Script to transform the Disconnect block-list into Safebrowsing v2 format for Firefox Tracking Protection
Python
12
star
78

go-mozlogrus

DEPRECATED - A logging library which conforms to Mozilla's logging standard for logrus users.
Go
12
star
79

FindMyDevice

Find My Device - ๐Ÿšจ๐ŸšจThis server is obsolete and unsupported.๐Ÿšจ๐Ÿšจ
Go
11
star
80

hindsight_admin

Hindsight Administration User Interface
JavaScript
11
star
81

walint

script to validate web apps
Python
11
star
82

pyramid_ipauth

a pyramid authentication policy based on remote ip address
Python
11
star
83

push-service

Top-level repository for the Push Service
11
star
84

macauthlib

low-level library for implementing MAC Access Authentication
Python
11
star
85

pyramid_whoauth

a pyramid authentication policy using repoze.who
Python
10
star
86

merino-py

Web Service for Firefox Suggest
Python
9
star
87

go-mozlog

A logging library which conforms to Mozilla's logging standard.
Go
9
star
88

oidc-gateway

A Docker container and Kubernetes Helm chart to gate access to upstream services.
Lua
9
star
89

redbarrel

JavaScript
9
star
90

iprepd-nginx

Openresty nginx module for integrating with iprepd
Python
9
star
91

services-test

Tools and test scripts used by the Mozilla Cloud Services team
JavaScript
9
star
92

nginx_moz_ingest

HTTP Data Pipeline Ingestion
C
9
star
93

logstash-metlog

Extensions to logstash for metlog
Ruby
9
star
94

shavar-list-creation-config

contains config files needed to run the jenkins task that builds the shavar lists
9
star
95

topsites-proxy

Proxy server to track Top Sites default tile campaign attribution
JavaScript
8
star
96

hoverpad

DEPRECATED - Playing around with an Addons to sync some informations.
Elm
8
star
97

absearch

Python
8
star
98

updatebot

Automation for updating third party libraries for Firefox
Python
8
star
99

hawkauthlib

INACTIVE - low-level library for implementing MAC Access Authentication
Python
8
star
100

autopush-loadtester

Autopush Load-Tester
Python
8
star