Managevisor: New app documentation (needs review)
Adding a new application to manage.attracs.com / manage-nightly.attracs.com
This guide walks through onboarding a new application to the Attracs management environments (stable and nightly). For adding organizations instead, see the separate organizations doc.
Prerequisites β ask the requesting developer
Collect the following before starting:
* Repository β Does the application already exist? If so, what's the repo URL?
* Application name β what should the app be called?
* Managed or unmanaged?
* Sendgrid? β Does it send mail via Sendgrid?
* Google services β Pub/Sub? Storage buckets? Anything else?
* Database?
* MySQL or Postgres?
* Dedicated instance or shared instance?
* Dedicated instances are very rare. By default, add a new database to the shared instance.
* Health-check path β /, /api/ping, /api/health, or something else?
1. Create the GitHub repository
GitHub repositories live under the Attracs organization. Enable branch protection for every new repo.
1a. Create a personal access token (classic)
GitHub β your profile β Settings β Developer settings β Personal access tokens β Tokens (classic) β Generate new token (classic).
Required scopes:
* repo (full scope)
If you hit 403 GithubException: You need admin access to the organizationβ¦, regenerate the token with the extended scopes:
* repo, repo:status, repo_deployment, public_repo, repo:invite, security_events
Copy the token (ghp_β¦) somewhere safe.
1b. Update the encrypted token file
The Ansible vault password lives in the root of attracs-linux-playbooks as .vault_password_file. If you don't have it, copy "Ansible Vault Encryption keys - linux password file" from 1Password.
Decrypt the token file, replace the value after ansible_token: with your token, then re-encrypt with the same password:
ansible-vault decrypt github.yml --vault-password-file=../../../.vault_password_file
# β¦edit the file, replace the ansible_token valueβ¦
ansible-vault encrypt github.yml --vault-password-file=../../../.vault_password_file
1c. Run the create-repo script
From the root of attracs-linux-playbooks:
./gcp/scripts/github/create_repo.sh <repo-name>
2. Reserve a port in the services_ports Google sheet
Each app needs a unique port for stable and nightly. * Choose the next port number in ascending order. * Do not reuse a previously assigned port, even if it looks unused. * Ports sheet https://docs.google.com/spreadsheets/d/10trjuvrp_N8-OrqwsHchAysTIcrJRNqZ/edit?usp=sharing&ouid=105978654382102392446&rtpof=true&sd=true
3. Create DNS entries
DNS is managed in Cloudflare. Use the helper script:
./gcp/scripts/dns/create_cname_record.sh <recordname> <recordvalue>
<recordname>β the hostname (e.g.my-app). Do not include.attracs.comor any other suffix β it will break the DNS entry.<recordvalue>β the load balancer name from the table below.
Load balancer reference
| Project | Load balancer | IP | Use |
|---|---|---|---|
attracs-devops |
devops-lb |
34.98.96.99 |
DevOps |
attracs-services-195009 |
gcplb |
34.120.86.122 |
TMS (stable) |
attracs-services-195009 |
lb2 |
34.120.155.57 |
CORE + others (stable) |
att-nightly |
lb1n |
34.117.203.247 |
TMS (nightly) |
att-nightly |
lb2n |
35.244.240.9 |
CORE + others (nightly) |
attracs-logistics |
road-cc-nightly-lb |
34.144.248.151 |
Road (nightly) |
attracs-logistics |
road-cc-stable-lb |
34.49.67.73 |
Road (stable) |
hetzner |
frontend |
95.216.1.224 |
Road (legacy) |
Example β create https://my-app.attracs.com pointing at Road's GCP LB:
./gcp/scripts/dns/create_cname_record.sh my-app lb3
Verify
dig my-app.attracs.com
If you mis-create a record
Log in to DNS Made Easy with the meshmoon credentials and fix the entry manually.
4. Create GCP infrastructure with Terraform (optional)
Skip this section if the app needs no GCP services (Pub/Sub, Storage, etc.).
1. In GCP, manually create the project folder under attracs.net β projects/.
2. In the adi-infra repository, create a new branch (e.g. pr-my-app).
3. Create a new directory under adi-infra/terraform/gcp/projects/ and copy the templates from adi-infra/terraform/gcp/templates/ into it.
4. Remove unused template files. The minimum required set is:
* api.tf
* iam.tf
* main.tf
* variable.tf
5. Make the necessary changes and validate with terraform plan.
6. Open a PR and get it approved.
7. Run terraform apply.
5. Create the database
Safety first. Test commands against a non-critical database (e.g. a clone of nightly) before touching stable. Use transactions β BEGIN; then ROLLBACK; or COMMIT; β when running anything destructive. Avoid cloning production databases when possible, as they may contain sensitive data.
Shared instance β Postgres
Set up cloud-sql-proxy first (see the cloud-sql-proxy doc).
Nightly β proxy on port 55435:
psql -h 127.0.0.1 -p 55435 -u postgres -d postgres
Stable β same setup, but the proxy port is 55432.
Check your permissions with \du. You need:
* Create database
* Create role attributes
* cloudsqlsuperuser role
If you're missing any of these, follow the "grant Postgres superuser" doc before continuing.
Create the database and user:
./gcp/scripts/database/create_db_and_user.sh \
./config/postgre/<environment-variable-file.yml> \
<application_database_name>
For an IAM-based user, pass the service-account email as the third argument:
./gcp/scripts/database/create_db_and_user.sh \
./config/postgre/<environment-variable-file.yml> \
<application_database_name> \
<service-account-name@project-id.iam>
Save the password the playbook prints at the end β you'll need it in the next step for Vault.
6. Add Vault secrets
Vault SSO login is currently broken. Use the root token until the ticket below is resolved. 1. Open the
kv-v2-nightlysecret engine. 2. Click Create secret +. 3. Add the following keys, depending on what the app uses:
| Key | Value | When |
|---|---|---|
database_host |
Public IP of the nightly DB instance | If app uses a DB |
database_password |
Password printed by the create-db playbook | If app uses a DB |
sendgrid_key |
Provided by the developer (share via 1Password) | If app uses Sendgrid |
To fix a typo in a key, use Create new version + rather than starting over.
7. Update attracs-application-configs
Edit the relevant template, e.g.:
attracs-application-configs/application-configs/<app-name>/attracs-nightly.yml.ctmpl
Then push the change from the root of attracs-linux-playbooks:
ansible-playbook vault_agent/vault_agent_config.yml \
--vault-password-file=.vault_password_file
8. Create the supervisor run config
Supervisor run configs tell Managevisor which applications to run on which backend.
* Location: attracs-linux-playbooks/supervisord/run/
* Filename: <application-name>-<deployment-environment>.conf.j2
Example (nightly)
[program:tms-feedback-nightly.attracs.com]
command=/bin/bash /etc/attracs-supervisor/run-process.sh -p tms-feedback-nightly.tar.gz -w server -x server -a -production -nightly -port 5056 -log-level debug -debug-database -reverse-proxy-host https://tms-feedback-nightly.attracs.com -config /etc/tms-feedback/attracs-nightly.yml
directory=/home/syncthing/attracs-builds/tms-feedback/nightly
stopwaitsecs=60
startsecs=5
autorestart=true
What to change
Resulting example
[program:example-app-nightly.attracs.com]
command=/bin/bash /etc/attracs-supervisor/run-process.sh -p example-app-nightly.tar.gz -w server -x server -a -production -nightly -port <CHANGEME> -log-level debug -debug-database -reverse-proxy-host https://example-app-nightly.attracs.com -config /etc/example-app/attracs-nightly.yml
directory=/home/syncthing/attracs-builds/example-app/nightly
stopwaitsecs=60
startsecs=5
autorestart=true
9. Add the run config to the backend host(s)
Each backend has a JSON file in attracs-linux-playbooks/supervisord/config/hosts/:
{
"includes": [
"/etc/attracs-supervisor/syncthing.conf",
"/etc/attracs-supervisor/attracs-managevisor-agent.conf",
"/etc/attracs-supervisor/attracs-managevisor.conf",
"/etc/attracs-supervisor/attracs-ci.conf",
"/etc/attracs-supervisor/memcached.conf"
]
}
Add a new entry for your app's .conf to the includes array. Watch the trailing commas β JSON is strict.
Push the change to the servers:
ansible-playbook supervisord/supervisord-update-all-configs.yml \
-l road-confidential-instance-nightly-1,road-confidential-instance-nightly-2 \
--vault-password-file=.vault_password_file
Replace the -l host list with the backends you're targeting.
10. Reload Managevisor
After the playbook completes successfully: 1. Open Managevisor. 2. Server actions β Reload Supervisor config.
Incomplete β needs more info
These sections were either missing, half-written, or unresolved in the original doc. Fill them in as you learn the details.
Cloudflare DNS automation
No automation exists yet for Cloudflare. The current flow uses create_cname_record.sh, which predates the Cloudflare migration. Document the actual Cloudflare workflow (UI? Terraform? API?) once decided.
Informing Ahola IT about new DNS
The original doc said: *"Inform Ahola IT about the new DNS β Where? How? Who?"* Document the contact (person/team/channel/ticket queue) and the format of the notification.
Road-nightly lb3 workaround ticket
"For road nightly, all DNS records go to lb2n until lb3 is fixed for nightly applications." The ticket reference was left blank β paste the Jira/Linear ticket link here.
Vault login ticket
Vault SSO login is currently broken; the doc references a ticket but the link was missing. Paste the ticket link here so people can track when normal login is restored.
Decrypting the personal-token file (path)
The fallback note about *"Decrypt the token file located in⦠TODO"* never specified the path. Confirm the canonical path inside attracs-linux-playbooks and document it.
Shared-instance MySQL setup
Section was empty. Document the equivalent of the Postgres flow: proxy ports (stable/nightly), how to connect with mysql CLI, required privileges, and the create_db_and_user.sh invocation (if there's a MySQL variant).
Dedicated database instances
Open question from the original doc: *"do we use these?"* If yes, document the provisioning steps. If no, delete this section.
Monitoring β Zabbix web scenario
Half-finished bullets in the original: Add step (name, path, status codes) Add graph Document the actual Zabbix workflow: which host group, which template, where the web scenario lives, screenshots if helpful.
Monitoring β Grafana response-code dashboard
Original noted: *"Add it to the Grafana Response Code dashboard, source Zabbix, override item name to look pretty."* Document the dashboard URL, the exact panel/source, and the naming convention for the override.
GCP load balancer backend additions
The original ended with a list of unfinished steps:
Add the named port to the instance group
Create a health check for the backend service
Create the backend service
Create host and path rules
Each of these needs the actual GCP console / gcloud commands documented. This is probably the biggest remaining gap β the app isn't reachable end-to-end without it.