Split README up into separate files
230
README.md
@ -2,226 +2,10 @@
|
|||||||
|
|
||||||
Python Flask web application for capsul.org
|
Python Flask web application for capsul.org
|
||||||
|
|
||||||
|
How about a trip to the the `docs/` folder?
|
||||||
## how to run locally
|
- [Setting up Capsul locally](./docs/local-set-up.md)
|
||||||
|
- [Hub-and-spoke architecture](./docs/architecture.md)
|
||||||
Ensure you have the pre-requisites for the psycopg2 Postgres database adapter package
|
- [Deplying Capsul on a server](./docs/deployment.md)
|
||||||
|
- [Configuring Capsul](./docs/configuration.md)
|
||||||
```
|
- [Receiving cryptocurrency payments with BTCPay](./docs/btcpay.md)
|
||||||
sudo apt install python3-dev libpq-dev
|
- [Working with the database](./docs/database.md)
|
||||||
pg_config --version
|
|
||||||
```
|
|
||||||
|
|
||||||
Ensure you have the wonderful `pipenv` python package management and virtual environment cli
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo apt install pipenv
|
|
||||||
```
|
|
||||||
|
|
||||||
Create python virtual environment and install packages
|
|
||||||
|
|
||||||
```
|
|
||||||
# install deps
|
|
||||||
pipenv install
|
|
||||||
```
|
|
||||||
|
|
||||||
Run an instance of Postgres (I used docker for this, you can use whatever you want, point is its listening on localhost:5432)
|
|
||||||
|
|
||||||
```
|
|
||||||
docker run --rm -it -e POSTGRES_PASSWORD=dev -p 5432:5432 postgres
|
|
||||||
```
|
|
||||||
|
|
||||||
Run the app
|
|
||||||
|
|
||||||
```
|
|
||||||
pipenv run flask run
|
|
||||||
```
|
|
||||||
|
|
||||||
Run the app in gunicorn:
|
|
||||||
|
|
||||||
```
|
|
||||||
pipenv run gunicorn --bind 127.0.0.1:5000 -k gevent --worker-connections 1000 app:app
|
|
||||||
```
|
|
||||||
|
|
||||||
Once you log in for the first time, you will want to give yourself some free capsulbux so you can create fake capsuls for testing.
|
|
||||||
|
|
||||||
Note that by default when running locally, the `SPOKE_MODEL` is set to `mock`, meaning that it won't actually try to spawn vms.
|
|
||||||
|
|
||||||
```
|
|
||||||
pipenv run flask cli sql -c "INSERT INTO payments (email, dollars) VALUES ('<your email address here>', 20.00)"
|
|
||||||
```
|
|
||||||
|
|
||||||
## configuration:
|
|
||||||
|
|
||||||
Create a `.env` file to set up the application configuration:
|
|
||||||
|
|
||||||
```
|
|
||||||
nano .env
|
|
||||||
```
|
|
||||||
|
|
||||||
You can enter any environment variables referenced in `__init__.py` to this file.
|
|
||||||
|
|
||||||
For example you may enter your SMTP credentials like this:
|
|
||||||
```
|
|
||||||
MAIL_USERNAME=forest@nullhex.com
|
|
||||||
MAIL_DEFAULT_SENDER=forest@nullhex.com
|
|
||||||
MAIL_PASSWORD=**************
|
|
||||||
```
|
|
||||||
|
|
||||||
## how to view the logs on the database server (legion.cyberia.club)
|
|
||||||
|
|
||||||
`sudo -u postgres pg_dump capsul-flask | gzip -9 > capsul-backup-2021-02-15.gz`
|
|
||||||
|
|
||||||
-----
|
|
||||||
|
|
||||||
## cli
|
|
||||||
|
|
||||||
You can manually mess around with the database like this:
|
|
||||||
|
|
||||||
```
|
|
||||||
pipenv run flask cli sql -f test.sql
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
pipenv run flask cli sql -c 'SELECT * FROM vms'
|
|
||||||
```
|
|
||||||
|
|
||||||
This one selects the vms table with the column name header:
|
|
||||||
|
|
||||||
```
|
|
||||||
pipenv run flask cli sql -c "SELECT string_agg(column_name::text, ', ') from information_schema.columns WHERE table_name='vms'; SELECT * from vms"
|
|
||||||
```
|
|
||||||
|
|
||||||
How to modify a payment manually, like if you get a chargeback or to fix customer payment issues:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ pipenv run flask cli sql -c "SELECT id, created, email, dollars, invalidated from payments"
|
|
||||||
1, 2020-05-05T00:00:00, forest.n.johnson@gmail.com, 20.00, FALSE
|
|
||||||
|
|
||||||
$ pipenv run flask cli sql -c "UPDATE payments SET invalidated = True WHERE id = 1"
|
|
||||||
1 rows affected.
|
|
||||||
|
|
||||||
$ pipenv run flask cli sql -c "SELECT id, created, email, dollars, invalidated from payments"
|
|
||||||
1, 2020-05-05T00:00:00, forest.n.johnson@gmail.com, 20.00, TRUE
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
How you would kick off the scheduled task:
|
|
||||||
|
|
||||||
```
|
|
||||||
pipenv run flask cli cron-task
|
|
||||||
```
|
|
||||||
|
|
||||||
-----
|
|
||||||
|
|
||||||
## postgres database schema management
|
|
||||||
|
|
||||||
capsulflask has a concept of a schema version. When the application starts, it will query the database for a table named
|
|
||||||
`schemaversion` that has one row and one column (`version`). If the `version` it finds is not equal to the `desiredSchemaVersion` variable set in `db.py`, it will run migration scripts from the `schema_migrations` folder one by one until the `schemaversion` table shows the correct version.
|
|
||||||
|
|
||||||
For example, the script named `02_up_xyz.sql` should contain code that migrates the database from schema version 1 to schema version 2. Likewise, the script `02_down_xyz.sql` should contain code that migrates from schema version 2 back to schema version 1.
|
|
||||||
|
|
||||||
**IMPORTANT: if you need to make changes to the schema, make a NEW schema version. DO NOT EDIT the existing schema versions.**
|
|
||||||
|
|
||||||
In general, for safety, schema version upgrades should not delete data. Schema version downgrades will simply throw an error and exit for now.
|
|
||||||
|
|
||||||
-----
|
|
||||||
|
|
||||||
## hub-and-spoke architecture
|
|
||||||
|
|
||||||
![](readme/hub-and-spoke1.png)
|
|
||||||
|
|
||||||
This diagram was created with https://app.diagrams.net/.
|
|
||||||
To edit it, download the <a download href="readme/hub-and-spoke.xml">diagram file</a> and edit it with the https://app.diagrams.net/ web application, or you may run the application from [source](https://github.com/jgraph/drawio) if you wish.
|
|
||||||
|
|
||||||
right now I have 2 types of operations, immediate mode and async.
|
|
||||||
|
|
||||||
both types of operations do assignment synchronously. so if the system cant assign the operation to one or more hosts (spokes),
|
|
||||||
or whatever the operation requires, then it will fail.
|
|
||||||
|
|
||||||
some operations tolerate partial failures, like, `capacity_avaliable` will succeed if at least one spoke succeeds.
|
|
||||||
for immediate mode requests (like `list`, `capacity_avaliable`, `destroy`), assignment and completion of the operation are the same thing.
|
|
||||||
|
|
||||||
for async ones, they can be assigned without knowing whether or not they succeeded (`create`).
|
|
||||||
|
|
||||||
![](readme/hub-and-spoke2.png)
|
|
||||||
|
|
||||||
This diagram was created with https://app.diagrams.net/.
|
|
||||||
To edit it, download the <a download href="readme/hub-and-spoke.xml">diagram file</a> and edit it with the https://app.diagrams.net/ web application, or you may run the application from [source](https://github.com/jgraph/drawio) if you wish.
|
|
||||||
|
|
||||||
if you issue a create, and it technically could go to any number of hosts, but only one host responds, it will succeed
|
|
||||||
but if you issue a create and somehow 2 hosts both think they own that task, it will fail and throw a big error. cuz it expects exactly 1 to own the create task
|
|
||||||
|
|
||||||
currently its not set up to do any polling. its not really like a queue at all. It's all immediate for the most part
|
|
||||||
|
|
||||||
-----
|
|
||||||
|
|
||||||
## how to setup btcpay server
|
|
||||||
|
|
||||||
Generate a private key and the accompanying bitpay SIN for the btcpay API client.
|
|
||||||
|
|
||||||
I used this code as an example: https://github.com/bitpay/bitpay-python/blob/master/bitpay/key_utils.py#L6
|
|
||||||
|
|
||||||
```
|
|
||||||
$ pipenv run python ./readme/generate_btcpay_keys.py
|
|
||||||
```
|
|
||||||
|
|
||||||
It should output something looking like this:
|
|
||||||
|
|
||||||
```
|
|
||||||
-----BEGIN EC PRIVATE KEY-----
|
|
||||||
EXAMPLEIArx/EXAMPLEKH23EXAMPLEsYXEXAMPLE5qdEXAMPLEcFHoAcEXAMPLEK
|
|
||||||
oUQDQgAEnWs47PT8+ihhzyvXX6/yYMAWWODluRTR2Ix6ZY7Z+MV7v0W1maJzqeqq
|
|
||||||
NQ+cpBvPDbyrDk9+Uf/sEaRCma094g==
|
|
||||||
-----END EC PRIVATE KEY-----
|
|
||||||
|
|
||||||
|
|
||||||
EXAMPLEwzAEXAMPLEEXAMPLEURD7EXAMPLE
|
|
||||||
```
|
|
||||||
|
|
||||||
In order to register the key with the btcpay server, you have to first generate a pairing token using the btcpay server interface.
|
|
||||||
This requires your btcpay server account to have access to the capsul store. Ask Cass about this.
|
|
||||||
|
|
||||||
Navigate to `Manage store: Access Tokens` at: `https://btcpay.cyberia.club/stores/<store-id>/Tokens`
|
|
||||||
|
|
||||||
![](readme/btcpay_sin_pairing.jpg)
|
|
||||||
|
|
||||||
|
|
||||||
Finally, send an http request to the btcpay server to complete the pairing:
|
|
||||||
|
|
||||||
```
|
|
||||||
curl -H "Content-Type: application/json" https://btcpay.cyberia.club/tokens -d "{'id': 'EXAMPLEwzAEXAMPLEEXAMPLEURD7EXAMPLE', 'pairingCode': 'XXXXXXX'}"
|
|
||||||
```
|
|
||||||
|
|
||||||
It should respond with a token:
|
|
||||||
|
|
||||||
```
|
|
||||||
{"data":[{"policies":[],"pairingCode":"XXXXXXX","pairingExpiration":1589473817597,"dateCreated":1589472917597,"facade":"merchant","token":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","label":"capsulflask"}]}
|
|
||||||
```
|
|
||||||
|
|
||||||
And you should see the token in the btcpay server UI:
|
|
||||||
|
|
||||||
![](readme/paired.jpg)
|
|
||||||
|
|
||||||
Now simply set your `BTCPAY_PRIVATE_KEY` variable in `.env`
|
|
||||||
|
|
||||||
NOTE: make sure to use single quotes and replace the new lines with \n.
|
|
||||||
|
|
||||||
```
|
|
||||||
BTCPAY_PRIVATE_KEY='-----BEGIN EC PRIVATE KEY-----\nEXAMPLEIArx/EXAMPLEKH23EXAMPLEsYXEXAMPLE5qdEXAMPLEcFHoAcEXAMPLEK\noUQDQgAEnWs47PT8+ihhzyvXX6/yYMAWWODluRTR2Ix6ZY7Z+MV7v0W1maJzqeqq\nNQ+cpBvPDbyrDk9+Uf/sEaRCma094g==\n-----END EC PRIVATE KEY-----'
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
-----
|
|
||||||
|
|
||||||
## testing cryptocurrency payments
|
|
||||||
|
|
||||||
I used litecoin to test cryptocurrency payments, because its the simplest & lowest fee cryptocurrency that BTCPay server supports. You can download the easy-to-use litecoin SPV wallet `electrum-ltc` from [github.com/pooler/electrum-ltc](https://github.com/pooler/electrum-ltc) or [electrum-ltc.org](https://electrum-ltc.org/), set up a wallet, and then either purchase some litecoin from an exchange, or ask Forest for some litecoin to use for testing.
|
|
||||||
|
|
||||||
|
|
||||||
## sequence diagram explaining how BTC payment process works
|
|
||||||
|
|
||||||
![btcpayment_process](readme/btcpayment_process.png)
|
|
||||||
|
|
||||||
This diagram was created with https://app.diagrams.net/.
|
|
||||||
To edit it, download the <a download href="readme/btcpayment_process.drawio">diagram file</a> and edit it with the https://app.diagrams.net/ web application, or you may run the application from [source](https://github.com/jgraph/drawio) if you wish.
|
|
||||||
|
26
docs/architecture.md
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# hub-and-spoke architecture
|
||||||
|
|
||||||
|
![](images/hub-and-spoke1.png)
|
||||||
|
|
||||||
|
This diagram was created with https://app.diagrams.net/.
|
||||||
|
To edit it, download the <a download href="readme/hub-and-spoke.xml">diagram file</a> and edit it with the https://app.diagrams.net/ web application, or you may run the application from [source](https://github.com/jgraph/drawio) if you wish.
|
||||||
|
|
||||||
|
right now I have 2 types of operations, immediate mode and async.
|
||||||
|
|
||||||
|
both types of operations do assignment synchronously. so if the system cant assign the operation to one or more hosts (spokes),
|
||||||
|
or whatever the operation requires, then it will fail.
|
||||||
|
|
||||||
|
some operations tolerate partial failures, like, `capacity_avaliable` will succeed if at least one spoke succeeds.
|
||||||
|
for immediate mode requests (like `list`, `capacity_avaliable`, `destroy`), assignment and completion of the operation are the same thing.
|
||||||
|
|
||||||
|
for async ones, they can be assigned without knowing whether or not they succeeded (`create`).
|
||||||
|
|
||||||
|
![](images/hub-and-spoke2.png)
|
||||||
|
|
||||||
|
This diagram was created with https://app.diagrams.net/.
|
||||||
|
To edit it, download the <a download href="readme/hub-and-spoke.xml">diagram file</a> and edit it with the https://app.diagrams.net/ web application, or you may run the application from [source](https://github.com/jgraph/drawio) if you wish.
|
||||||
|
|
||||||
|
if you issue a create, and it technically could go to any number of hosts, but only one host responds, it will succeed
|
||||||
|
but if you issue a create and somehow 2 hosts both think they own that task, it will fail and throw a big error. cuz it expects exactly 1 to own the create task
|
||||||
|
|
||||||
|
currently its not set up to do any polling. its not really like a queue at all. It's all immediate for the most part
|
68
docs/btcpay.md
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
# Receiving cryptocurrency payments with BTCPay
|
||||||
|
|
||||||
|
Generate a private key and the accompanying bitpay SIN for the btcpay API client.
|
||||||
|
|
||||||
|
I used this code as an example: https://github.com/bitpay/bitpay-python/blob/master/bitpay/key_utils.py#L6
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pipenv run python ./readme/generate_btcpay_keys.py
|
||||||
|
```
|
||||||
|
|
||||||
|
It should output something looking like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
-----BEGIN EC PRIVATE KEY-----
|
||||||
|
EXAMPLEIArx/EXAMPLEKH23EXAMPLEsYXEXAMPLE5qdEXAMPLEcFHoAcEXAMPLEK
|
||||||
|
oUQDQgAEnWs47PT8+ihhzyvXX6/yYMAWWODluRTR2Ix6ZY7Z+MV7v0W1maJzqeqq
|
||||||
|
NQ+cpBvPDbyrDk9+Uf/sEaRCma094g==
|
||||||
|
-----END EC PRIVATE KEY-----
|
||||||
|
|
||||||
|
|
||||||
|
EXAMPLEwzAEXAMPLEEXAMPLEURD7EXAMPLE
|
||||||
|
```
|
||||||
|
|
||||||
|
In order to register the key with the btcpay server, you have to first generate a pairing token using the btcpay server interface.
|
||||||
|
This requires your btcpay server account to have access to the capsul store. Ask Cass about this.
|
||||||
|
|
||||||
|
Navigate to `Manage store: Access Tokens` at: `https://btcpay.cyberia.club/stores/<store-id>/Tokens`
|
||||||
|
|
||||||
|
![](readme/btcpay_sin_pairing.jpg)
|
||||||
|
|
||||||
|
|
||||||
|
Finally, send an http request to the btcpay server to complete the pairing:
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -H "Content-Type: application/json" https://btcpay.cyberia.club/tokens -d "{'id': 'EXAMPLEwzAEXAMPLEEXAMPLEURD7EXAMPLE', 'pairingCode': 'XXXXXXX'}"
|
||||||
|
```
|
||||||
|
|
||||||
|
It should respond with a token:
|
||||||
|
|
||||||
|
```
|
||||||
|
{"data":[{"policies":[],"pairingCode":"XXXXXXX","pairingExpiration":1589473817597,"dateCreated":1589472917597,"facade":"merchant","token":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","label":"capsulflask"}]}
|
||||||
|
```
|
||||||
|
|
||||||
|
And you should see the token in the btcpay server UI:
|
||||||
|
|
||||||
|
![](readme/paired.jpg)
|
||||||
|
|
||||||
|
Now simply set your `BTCPAY_PRIVATE_KEY` variable in `.env`
|
||||||
|
|
||||||
|
NOTE: make sure to use single quotes and replace the new lines with \n.
|
||||||
|
|
||||||
|
```
|
||||||
|
BTCPAY_PRIVATE_KEY='-----BEGIN EC PRIVATE KEY-----\nEXAMPLEIArx/EXAMPLEKH23EXAMPLEsYXEXAMPLE5qdEXAMPLEcFHoAcEXAMPLEK\noUQDQgAEnWs47PT8+ihhzyvXX6/yYMAWWODluRTR2Ix6ZY7Z+MV7v0W1maJzqeqq\nNQ+cpBvPDbyrDk9+Uf/sEaRCma094g==\n-----END EC PRIVATE KEY-----'
|
||||||
|
```
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
## testing cryptocurrency payments
|
||||||
|
|
||||||
|
I used litecoin to test cryptocurrency payments, because its the simplest & lowest fee cryptocurrency that BTCPay server supports. You can download the easy-to-use litecoin SPV wallet `electrum-ltc` from [github.com/pooler/electrum-ltc](https://github.com/pooler/electrum-ltc) or [electrum-ltc.org](https://electrum-ltc.org/), set up a wallet, and then either purchase some litecoin from an exchange, or ask Forest for some litecoin to use for testing.
|
||||||
|
|
||||||
|
|
||||||
|
## sequence diagram explaining how BTC payment process works
|
||||||
|
|
||||||
|
![btcpayment_process](readme/btcpayment_process.png)
|
||||||
|
|
||||||
|
This diagram was created with https://app.diagrams.net/.
|
||||||
|
To edit it, download the <a download href="readme/btcpayment_process.drawio">diagram file</a> and edit it with the https://app.diagrams.net/ web application, or you may run the application from [source](https://github.com/jgraph/drawio) if you wish.
|
23
docs/configuration.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Configuring Capsul-Flask
|
||||||
|
|
||||||
|
Create a `.env` file to set up the application configuration:
|
||||||
|
|
||||||
|
```
|
||||||
|
nano .env
|
||||||
|
```
|
||||||
|
|
||||||
|
You can enter any environment variables referenced in `__init__.py` to this file.
|
||||||
|
|
||||||
|
For example you may enter your SMTP credentials like this:
|
||||||
|
```
|
||||||
|
MAIL_USERNAME=forest@nullhex.com
|
||||||
|
MAIL_DEFAULT_SENDER=forest@nullhex.com
|
||||||
|
MAIL_PASSWORD=**************
|
||||||
|
```
|
||||||
|
|
||||||
|
## Loading variables from files
|
||||||
|
|
||||||
|
To support [Docker Secrets](https://docs.docker.com/engine/swarm/secrets/), you can also load secret values from files – for example, to load `MAIL_PASSWORD` from `/run/secrets/mail_password`, set
|
||||||
|
```sh
|
||||||
|
MAIL_PASSWORD_FILE=/run/secrets/mail_password
|
||||||
|
```
|
46
docs/database.md
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# Working with the Capsul database
|
||||||
|
|
||||||
|
## Running manual database queries
|
||||||
|
|
||||||
|
You can manually mess around with the database like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
pipenv run flask cli sql -f test.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
pipenv run flask cli sql -c 'SELECT * FROM vms'
|
||||||
|
```
|
||||||
|
|
||||||
|
This one selects the vms table with the column name header:
|
||||||
|
|
||||||
|
```
|
||||||
|
pipenv run flask cli sql -c "SELECT string_agg(column_name::text, ', ') from information_schema.columns WHERE table_name='vms'; SELECT * from vms"
|
||||||
|
```
|
||||||
|
|
||||||
|
How to modify a payment manually, like if you get a chargeback or to fix customer payment issues:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pipenv run flask cli sql -c "SELECT id, created, email, dollars, invalidated from payments"
|
||||||
|
1, 2020-05-05T00:00:00, forest.n.johnson@gmail.com, 20.00, FALSE
|
||||||
|
|
||||||
|
$ pipenv run flask cli sql -c "UPDATE payments SET invalidated = True WHERE id = 1"
|
||||||
|
1 rows affected.
|
||||||
|
|
||||||
|
$ pipenv run flask cli sql -c "SELECT id, created, email, dollars, invalidated from payments"
|
||||||
|
1, 2020-05-05T00:00:00, forest.n.johnson@gmail.com, 20.00, TRUE
|
||||||
|
```
|
||||||
|
|
||||||
|
## Database schema management
|
||||||
|
|
||||||
|
capsulflask has a concept of a schema version. When the application starts, it will query the database for a table named `schemaversion` that has one row and one column (`version`). If the `version` it finds is not equal to the `desiredSchemaVersion` variable set in `db.py`, it will run migration scripts from the `schema_migrations` folder one by one until the `schemaversion` table shows the correct version.
|
||||||
|
|
||||||
|
For example, the script named `02_up_xyz.sql` should contain code that migrates the database from schema version 1 to schema version 2. Likewise, the script `02_down_xyz.sql` should contain code that migrates from schema version 2 back to schema version 1.
|
||||||
|
|
||||||
|
**IMPORTANT: if you need to make changes to the schema, make a NEW schema version. DO NOT EDIT the existing schema versions.**
|
||||||
|
|
||||||
|
In general, for safety, schema version upgrades should not delete data. Schema version downgrades will simply throw an error and exit for now.
|
||||||
|
|
||||||
|
## how to view the logs on the database server (legion.cyberia.club)
|
||||||
|
|
||||||
|
`sudo -u postgres pg_dump capsul-flask | gzip -9 > capsul-backup-2021-02-15.gz`
|
68
docs/deployment.md
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
# Deploying Capsul on a server
|
||||||
|
|
||||||
|
## Installing prerequisites for Spoke Mode
|
||||||
|
|
||||||
|
On your spoke (see [Architecture](./architecture.md) You'll need `libvirtd`, `dnsmasq`, and `qemu-kvm`, plus a `/tank` diectory with some operating system images in it:
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo apt install libvirt-daemon-system virtinst git dnsmasq qemu qemu-kvm
|
||||||
|
sudo mkdir -p /var/www /tank/{vm,img,config}
|
||||||
|
sudo mkdir -p /tank/img/debian/10
|
||||||
|
cd !$
|
||||||
|
sudo wget https://cloud.debian.org/images/cloud/buster/20201023-432/debian-10-genericcloud-amd64-20201023-432.qcow2 -O root.img.qcow2
|
||||||
|
```
|
||||||
|
|
||||||
|
TODO: network set-up
|
||||||
|
TODO: cyberia-cloudinit.yml
|
||||||
|
|
||||||
|
## Deploying capsul-flask
|
||||||
|
|
||||||
|
### Extra Manual™
|
||||||
|
|
||||||
|
Follow the [local set-up instructions](./local-set-up.md) on your server.
|
||||||
|
|
||||||
|
Make sure to set `BASE_URL` correctly, generate your own secret tokens, and
|
||||||
|
configure your own daemon management for the capsul-flask server (e.g. writing
|
||||||
|
init scripts, or SystemD unit files).
|
||||||
|
|
||||||
|
Use the suggested `gunicorn` command (with appropriately-set address and port),
|
||||||
|
instead of `flask run`, to launch the server.
|
||||||
|
|
||||||
|
TODO: cron runner
|
||||||
|
|
||||||
|
### Using vanilla Docker Swarm
|
||||||
|
|
||||||
|
Download the Co-op Cloud swarm `compose.yml`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
wget https://git.autonomic.zone/coop-cloud/capsul/src/branch/main/compose.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
Optionally, download add-on compose files for Stripe, BTCPay, and Spoke Mode:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
wget https://git.autonomic.zone/coop-cloud/capsul/src/branch/main/compose.{stripe,btcpay,spoke}.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, create a `.env` file and configure appropriately -- you probably want to
|
||||||
|
define most settings in [the Co-op Cloud `.envrc.sample`
|
||||||
|
file](https://git.autonomic.zone/coop-cloud/capsul/src/branch/main/.envrc.sample).
|
||||||
|
|
||||||
|
Load the environment variables (using Python `direnv`, or a manual `set -a && source .env && set +a`), insert any necessary secrets, then run the deployment:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker stack deploy -c compose.yml -c compose.stripe.yml your_capsul
|
||||||
|
```
|
||||||
|
|
||||||
|
(where you'd add an extra `-c compose.btcpay.yml` for each optional compose file
|
||||||
|
you want, and set `your_capsul` to the "stack name" you want).
|
||||||
|
|
||||||
|
TODO: cron runner
|
||||||
|
|
||||||
|
### Using Co-op Cloud / Docker Swarm
|
||||||
|
|
||||||
|
Follow [the guide in the README for the Co-op Cloud capsul package](https://git.autonomic.zone/coop-cloud/capsul/).
|
||||||
|
|
||||||
|
### Using docker-compose
|
||||||
|
|
||||||
|
TODO
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 190 KiB After Width: | Height: | Size: 190 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
69
docs/local-set-up.md
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
# How to run Capsul locally
|
||||||
|
|
||||||
|
## With Docker
|
||||||
|
|
||||||
|
If you have Docker and Docker-Compose installed, you can use the
|
||||||
|
`3wordchant/capsul-flask` Docker image to launch capsul-flask, and a Postgres
|
||||||
|
database server, for you:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker-compose up
|
||||||
|
```
|
||||||
|
|
||||||
|
docker-compose will read settings from your `.env` file; you can set any of the
|
||||||
|
options mentioned in the [configuration documentation](./configuration.md).
|
||||||
|
|
||||||
|
## Manually
|
||||||
|
|
||||||
|
Ensure you have the pre-requisites for the psycopg2 Postgres database adapter package:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo apt install python3-dev libpq-dev
|
||||||
|
pg_config --version
|
||||||
|
```
|
||||||
|
|
||||||
|
Ensure you have the wonderful `pipenv` python package management and virtual environment cli:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo apt install pipenv
|
||||||
|
```
|
||||||
|
|
||||||
|
Create python virtual environment and install packages:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pipenv install
|
||||||
|
```
|
||||||
|
|
||||||
|
Run an instance of Postgres (I used docker for this, you can use whatever you want, point is its listening on `localhost:5432`):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker run --rm -it -e POSTGRES_PASSWORD=dev -p 5432:5432 postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the app
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pipenv run flask run
|
||||||
|
```
|
||||||
|
|
||||||
|
or, using Gunicorn:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pipenv run gunicorn --bind 127.0.0.1:5000 -k gevent --worker-connections 1000 app:app
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that by default when running locally, the `SPOKE_MODEL` is set to `mock`, meaning that it won't actually try to spawn vms.
|
||||||
|
|
||||||
|
## Crediting your account
|
||||||
|
|
||||||
|
Once you log in for the first time, you will want to give yourself some free capsulbux so you can create fake capsuls for testing.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pipenv run flask cli sql -c "INSERT INTO payments (email, dollars) VALUES ('<your email address here>', 20.00)"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running scheduled tasks:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pipenv run flask cli cron-task
|
||||||
|
```
|