(doc about adding a new domain to an existing instance is at the bottom of this page)
Creating a new instance
This document is mainly a memo for not forgetting steps when trying to install a new instance (db + backend + frontend). It barely explains the reasons behind these operations. Reasons have to be found in the project repositories directly, in ops best-practices, or in my head🤷‍♂️. Many of these steps may only apply if you do the same kind of setup as ours (very AWS specific).
Required from others
- the domain name (then adding the domain name and TXT entry for the certificate)
- the supported languages and the default one
- the login-module client id and secret
itemPlatformId
to communicate with tasks- the title on top left (inc. language-specific ones) and in browser tabs for the frontend
- a logo if any
- whether skills are enabled
- whether groups should be shown in the left menu
SSL / DNS
- create a new certificate in the same region as the load balancer (+ TXT entry in the DNS to validate it)
- create a new DNS entry to the load balancer
Database
Run the following action as a db admin. I suppose the new instance is called “myinstance” (short token to be chosen).
Create the user/database
CREATE USER 'alg-myinstance-backend'@'%' IDENTIFIED BY '...'; # for the backend API
CREATE USER 'alg-myinstance-admin'@'%' IDENTIFIED BY '...'; # for migration and commands
CREATE DATABASE alg_myinstance_prod;
GRANT SELECT, INSERT, UPDATE, DELETE, DROP, CREATE TEMPORARY TABLES ON `alg_myinstance_prod`.* TO `alg-myinstance-backend`@`%`;
GRANT ALL PRIVILEGES ON alg_myinstance_prod.* TO 'alg-myinstance-admin'@'%';
Create the db schema:
If you do not have a running DB, install the schema on the backend and run migration (see “Seeding the database” section of the backend README).
Otherwise, you can copy another instance schema:
mysqldump --no-data --triggers --routines --events --add-drop-trigger --no-create-db --skip-opt -h <HOSTNAME> -u <ADMIN_USER> --protocol=TCP <EXISTING_DB_NAME> -p > db-schema-dump.sql
Search and replace <ADMIN_USER>
as trigger definer, to alg-myinstance-admin
. Remove “@SESSION.SQL_LOG_BIN” and “GLOBAL.GTID_PURGED” lines. Then:
mysql -h <HOSTNAME> -u alg-myinstance-admin --protocol=TCP alg_myinstance_prod -p < db-schema-dump.sql
Creating initial data
Copy the migration table
Copy the gorp_migrations
from the model database to the new one:
mysqldump -h <hostname> --no-create-db --no-create-info -u <user> -p <sourcedatabase> gorp_migrations > db-migration-dump.sql
Remove the line not related to data insertion and:
mysql -h <HOSTNAME> -u alg-myinstance-admin --protocol=TCP alg_myinstance_prod -p < db-migration-dump.sql
Create the default groups
INSERT INTO `groups` (id, name, type, text_id, description, is_open, is_public, frozen_membership) values (2, 'TempUsers', 'Base', 'TempUsers', 'temporary users', 0, 0, 1);
INSERT INTO `groups` (id, name, type, text_id, description, is_open, is_public, frozen_membership) values (3, 'AllUsers', 'Base', 'AllUsers', 'AllUsers', 0, 0, 1);
INSERT INTO `groups` (`id`, `name`, `type`, `text_id`, `description`, is_open, is_public, frozen_membership) VALUE (4, 'NonTempUsers', 'Base', 'NonTempUsers', 'non-temporary users',0, 0, 1);
INSERT INTO `groups_groups` (parent_group_id, child_group_id) values (3, 2), (3, 4)
Create supported languages for items
INSERT INTO languages VALUES ('en', 'English'), ('fr', 'French');
Create the initial item and set it as the root activity for the groups
SET FOREIGN_KEY_CHECKS=0;
INSERT INTO items (id, type, default_language_tag) VALUES (1, 'Chapter', 'en');
SET FOREIGN_KEY_CHECKS=1;
INSERT INTO items_strings (item_id, language_tag, title) VALUES (1, 'en', 'Root chapter (rename me)');
UPDATE `groups` SET root_activity_id = 1 WHERE id IN (2, 3);
INSERT INTO permissions_granted (group_id, item_id, source_group_id, origin, can_view) VALUES (2, 1, 2, 'group_membership', 'content') ;
INSERT INTO permissions_granted (group_id, item_id, source_group_id, origin, can_view) VALUES (3, 1, 3, 'group_membership', 'content') ;
Create the initial skill if enabled
SET FOREIGN_KEY_CHECKS=0;
INSERT INTO items (id, type, default_language_tag) VALUES (2, 'Skill', 'en');
SET FOREIGN_KEY_CHECKS=1;
INSERT INTO items_strings (item_id, language_tag, title) VALUES (2, 'en', 'Root skill (rename me)');
UPDATE `groups` SET root_skill_id = 2 WHERE id IN (2, 3);
INSERT INTO permissions_granted (group_id, item_id, source_group_id, origin, can_view) VALUES (3, 2, 3, 'group_membership', 'content') ;
Create an initial “admin” group
INSERT INTO `groups` (id, name, type, is_open, is_public, frozen_membership) VALUES (5, 'Platform admins', 'Other', 0, 0, 0);
INSERT INTO permissions_granted (group_id, item_id, source_group_id, origin, can_view, can_grant_view, can_watch, can_edit, is_owner) VALUES (5, 1, 5, 'group_membership', 'solution', 'solution_with_grant', 'answer_with_grant', 'all_with_grant', 1) ;
INSERT INTO group_managers (group_id, manager_id , can_manage, can_grant_group_access , can_watch_members) VALUES (3, 5, 'memberships_and_group', 1, 1);
If skills are enabled:
INSERT INTO permissions_granted (group_id, item_id, source_group_id, origin, can_view, can_grant_view, can_watch, can_edit, is_owner) VALUES (5, 2, 5, 'group_membership', 'solution', 'solution_with_grant', 'answer_with_grant', 'all_with_grant', 1) ;
Create default “platform”
insert into platforms (id, name, `regexp`, priority) values (0,'default', '.*',0);
Config
Frontend
On AlgoreaConfig, fork an existing frontend branch and change:
- the build config
- in the main config:
itemPlatformId
(for communication with tasks)oauthClientId
(for communication with the login-module)defaultActivityId
:1
if you have followed the steps abovedefaultSkillId
:2
if enabled and using our defaultallUsersGroupId
:3
if using our defaulttitle
andlanguageSpecificTitles
.searchApiUrl
: undefined for nowforumServerUrl
: undefined for now
Propagation end-point
In the ops repository, in src/backend-propagation
, run sls deploy --stage pbl --aws-profile algorea
to deploy the propagation end-point.
Update the “ALGOREA_SERVER__PROPAGATION_ENDPOINT” in the backend config with the end-point url.
Backend
In the AWS parameter store, create a /alg/myinstance-prod/Auth
, /alg/myinstance-prod/Database
, and /alg/myinstance-prod/Token
of type SecureString
and copy-update value from other instances.
For the key pair, generate one this way:
openssl genrsa --out private_key.pem 2048
openssl rsa -in private_key.pem -pubout -out public_key.pem
And then replace the line breaks by \n
.
Send the public key to the task manager if such tasks are used, and the token platform name if you chose it yourself.
On AlgoreaConfig, fork one backend branch and update the propagation end-point with the one given in the previous section.
Ops
-
In the ACM (certificate manager), create a new certificate for the new domain with DNS validation.
-
On AlgoreaConfig, in the
opsbot_prod
branch, add the new deployment environment in the env file. Force redeployment of the main branch of “AlgoreaOps” via the CI so that the bot is redeployed. -
Deploy the frontend and backend using the slack bot (
deploy frontend|backend <new_env_name> <version>
) -
Create manually the
released
tag on the “*-static-serve” and “server” lambda functions pointing to the deployed version -
re-compute the permissions via the slack bot:
command backend <env> db-recompute
ALB
-
In EC2/LB, create a new target rule for the lambda function, pointing to the
released
tag of the lambdas, enable multi-header on the backend target -
In EC2/ALB:
- add the new certificate
- copy the other rules to match the hosts (frontend and backend)
- depending on the default language you want to redirect the unknown path to, adapt the alias rule
Allow access to assets
If a new domain is used, add it to allowed origin in the response header policy of the CloudFront distribution (in policies > response headers).
Boostrap permissions on a first user
Once your first user has signed in, add him as a manager of group 5
:
INSERT INTO group_managers (group_id, manager_id, can_manage, can_grant_group_access, can_watch_members) VALUES (5,<new_user_group_id>,'memberships_and_group',1,1);
(find the the group_id
of the user using SELECT group_id, login FROM users WHERE temp_user = 0;
)
Then, the user can add himself (using the webapp) as the member of the group, which will give him access to manage content.
Forum
To setup the forum, first, in the ops repository:
- create a directory in
envionments/forum
based on the existing ones - refer it in the
environments/deployments.yaml
file
That should create the forum. Then copy the wss
url to the frontend config.
Search
TODO