canvas-lms/doc/using_guard_rail_in_develop...

2.3 KiB

Using GuardRail in Development

GuardRail allows activating different database configurations for specific blocks of code. This is frequently done to offload read queries to a replica (secondary) database in Canvas.

When offloading read queries to a replica, it's important to have the ability to test the change locally and verify no writes are occurring by accident.

This guide shows how to configure a read-only user to allow testing these kind of changes during development.

For more information on GuardRail see The Canvas Manual.

1. Open config/database.yml

2. Add the following to the common YML section:

secondary:
    replica: true
    username: canvas_read_only

This should result in a common section that looks something like this:

common: &common
  adapter: postgresql
  host: <%= ENV.fetch('CANVAS_DATABASE_HOST', 'postgres') %>
  ...
  secondary:
    replica: true
    username: canvas_read_only

3. Create a new user and grant read-only access to databases:

First, create the new user

docker-compose run --rm web psql -h postgres -U postgres -c "CREATE USER canvas_read_only WITH PASSWORD 'sekret'"

When prompted for a password, use the Canvas default postgres password (sekret at the time of writing),

Next, grant the user read-only privileges to all tables in each database.

For each database (development, test, etc.) run the following, substituting the correct name for <database name>:

docker-compose run --rm web psql -h postgres -U postgres -d <database name> -c 'GRANT SELECT ON ALL TABLES IN SCHEMA public TO canvas_read_only'

4. That's it!

To validate that the new user has read-only access try activating the read-only DB configuration (using GuardRail) and try creating a row in a Canvas Rails console:

=> GuardRail.activate(:secondary) { DeveloperKey.create! }

This should result in the following error:

ActiveRecord::StatementInvalid (PG::InsufficientPrivilege: ERROR:  permission denied for table developer_keys)

Activating the primary DB configuration, however, should allow inserting the new row:

=> GuardRail.activate(:primary) { DeveloperKey.create! }
...
SQL  (1.3ms)  COMMIT  [development:1 primary]