small fixes during first ever official development environment build-out #43

Open
forest wants to merge 7 commits from development into main
6 changed files with 110 additions and 10 deletions

View file

@ -182,7 +182,7 @@ class DBModel:
self.connection.commit()
def delete_vm(self, email, id):
self.cursor.execute("UPDATE vms SET deleted = now() WHERE email = %s AND id = %s", ( email, id))
self.cursor.execute("UPDATE vms SET deleted = now() WHERE email = %s AND id = %s AND deleted IS NULL", ( email, id))
self.connection.commit()
def get_vm_detail(self, email, id):

View file

@ -1,5 +1,6 @@
import json
import ipaddress
from functools import reduce
from flask import Blueprint
from flask import current_app
@ -144,11 +145,13 @@ def can_claim_create(payload, host_id) -> (str, str):
ipv4_network = ipaddress.ip_network(network["public_ipv4_cidr_block"], False)
ipv4_first_usable_ip = network["public_ipv4_first_usable_ip"]
ipv4_last_usable_ip = network["public_ipv4_last_usable_ip"]
ipv4_first_usable_ip_int = ip2int(network["public_ipv4_first_usable_ip"])
ipv4_last_usable_ip_int = ip2int(network["public_ipv4_last_usable_ip"])
for ipv4_address in ipv4_network:
within_usable_range = ipv4_first_usable_ip <= str(ipv4_address) and str(ipv4_address) <= ipv4_last_usable_ip
ipv4_address_int = ip2int(ipv4_address)
within_usable_range = ipv4_first_usable_ip_int <= ipv4_address_int and ipv4_address_int <= ipv4_last_usable_ip_int
if within_usable_range and str(ipv4_address) not in claimed_ipv4s:
allocated_ipv4_address = str(ipv4_address)
break
@ -165,7 +168,7 @@ def can_claim_create(payload, host_id) -> (str, str):
# hard-code the network name and IP for now until we can implement https://git.cyberia.club/cyberia/capsul-flask/issues/11
# enable static IP -> capsul mapping via libvirt (manage MAC addresses)
payload["network_name"] = 'public3'
payload["network_name"] = 'default'
payload["public_ipv4"] = ""
return payload, ""
@ -185,4 +188,15 @@ def on_create_claimed(payload, host_id):
network_name=payload['network_name'],
public_ipv4=payload['public_ipv4'],
ssh_authorized_keys=list(map(lambda x: x["name"], payload['ssh_authorized_keys'])),
)
)
# https://stackoverflow.com/questions/5619685/conversion-from-ip-string-to-integer-and-backward-in-python
def ip2int(ip):
"""
Convert IP string to integer
:param ip: IP string
:return: IP integer
"""
return reduce(lambda x, y: x * 256 + y, map(int, str(ip).split('.')))

View file

@ -35,6 +35,7 @@ fi
case "$state" in
1) printf '%s is already running\n' "$vmname" ;;
3) virsh resume "$vmname" ;;
4) printf '%s cannot be started while it is shutting down\n' "$vmname" ;;
[235-7]) virsh start "$vmname" > /dev/null ;;
[25-7]) virsh start "$vmname" ;;
esac

View file

@ -20,6 +20,9 @@ MAIL_PASSWORD=**************
```
#LOG_LEVEL=DEBUG
FLASK_RUN_HOST=0.0.0.0
FLASK_RUN_PORT=5000
BASE_URL="https://capsul.org"
# hub url is used by the SPOKE_MODE to contact the hub. Since this server is the hub,
@ -80,7 +83,20 @@ BTCPAY_PRIVATE_KEY='-----BEGIN EC PRIVATE KEY-----\n<redacted>\n-----END EC PRIV
- `memory_mb`
- `vcpus`
- `bandwidth_gb_per_month`
Example of replacing the default hub/spoke settings that are in the DB:
```
delete from host_network;
update hosts set id = 'myspoke', https_url = 'http://myspoke:5000', token = 'changeme';
insert into host_network(host, network_name, virtual_bridge_name, public_ipv4_cidr_block, public_ipv4_first_usable_ip, public_ipv4_last_usable_ip)
values ('myspoke', 'default', 'virbr0', '192.168.122.1/24', '192.168.122.3', '192.168.122.253');
```
## <a name="docker_secrets"></a>Loading variables from files (docker secrets)
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

View file

@ -4,6 +4,16 @@ Capsul has a ["hub and spoke" architecture](./architecture.md). The "Hub" runs t
The Postgres connections parameters are [configurable](./configuration.md).
## creating the capsul-flask postgres database
`sudo -u postgres psql -c 'create database "capsul-flask"; create user "capsul-flask" WITH PASSWORD '"'blah'"'; grant all privileges on database "capsul-flask" to "capsul-flask";'`
Then your postgres connection string in your config file `.env` would look like so:
`POSTGRES_CONNECTION_PARAMETERS="host=localhost port=5432 user=capsul-flask password=blah dbname=capsul-flask"`
## <a name="schema_management"></a>Database schema management (schema versions)
capsul-flask 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.

View file

@ -4,17 +4,76 @@ Capsul has a ["hub and spoke" architecture](./architecture.md). The "Hub" runs t
## <a name="spoke_mode_prerequisites"></a>Installing prerequisites for Spoke Mode
First of all, make sure that the computer you are running this on has a CPU that supports virtualization & it has virtualization enabled in the BIOS (built-in operating system). You can use the `kvm-ok` command for this:
```
$ kvm-ok
INFO: /dev/kvm does not exist
HINT: sudo modprobe kvm_intel
INFO: Your CPU supports KVM extensions
INFO: KVM (vmx) is disabled by your BIOS
HINT: Enter your BIOS setup and enable Virtualization Technology (VT),
and then hard poweroff/poweron your system
KVM acceleration can NOT be used
```
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 apt install cloud-image-utils 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
## network set-up
By default, libvirt will create a network called `default`, similar to the default "bridged" network that docker creates. For more information, see: https://wiki.libvirt.org/page/Networking#Host_configuration
Here's an example of SQL I ran to rewrite the hub/spoke and network config to match the default libvirt network on a new
machine with a fresh install of libvirt.
I ran it inside the postgres sql shell: `sudo -u postgres psql -d capsul-flask`
```
delete from host_network;
update hosts set id = 'myspoke', https_url = 'http://myspoke:5000', token = 'changeme';
insert into host_network(host, network_name, virtual_bridge_name, public_ipv4_cidr_block, public_ipv4_first_usable_ip, public_ipv4_last_usable_ip)
values ('myspoke', 'default', 'virbr0', '192.168.122.1/24', '192.168.122.3', '192.168.122.253');
```
I got the IP addresses from:
```
$ virsh net-list
Name State Autostart Persistent
--------------------------------------------
default active yes yes
$ virsh net-dumpxml default
<network>
<name>default</name>
<uuid>5b8008c5-e3c3-4b32-bbec-27071d8d0a92</uuid>
<forward mode='nat'>
<nat>
<port start='1024' end='65535'/>
</nat>
</forward>
<bridge name='virbr0' stp='on' delay='0'/>
<mac address='52:54:00:7e:17:de'/>
<ip address='192.168.122.1' netmask='255.255.255.0'>
<dhcp>
<range start='192.168.122.2' end='192.168.122.254'/>
</dhcp>
</ip>
</network>
```
> Note that "changeme" in `token = 'changeme'` needs to match the value of `SPOKE_HOST_TOKEN` in the config for your capsul-flask spoke.
## cyberia-cloudinit.yml