small fixes during first ever official development environment build-out #43
6 changed files with 110 additions and 10 deletions
|
@ -182,7 +182,7 @@ class DBModel:
|
||||||
self.connection.commit()
|
self.connection.commit()
|
||||||
|
|
||||||
def delete_vm(self, email, id):
|
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()
|
self.connection.commit()
|
||||||
|
|
||||||
def get_vm_detail(self, email, id):
|
def get_vm_detail(self, email, id):
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import json
|
import json
|
||||||
import ipaddress
|
import ipaddress
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
from flask import Blueprint
|
from flask import Blueprint
|
||||||
from flask import current_app
|
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_network = ipaddress.ip_network(network["public_ipv4_cidr_block"], False)
|
||||||
ipv4_first_usable_ip = network["public_ipv4_first_usable_ip"]
|
ipv4_first_usable_ip_int = ip2int(network["public_ipv4_first_usable_ip"])
|
||||||
ipv4_last_usable_ip = network["public_ipv4_last_usable_ip"]
|
ipv4_last_usable_ip_int = ip2int(network["public_ipv4_last_usable_ip"])
|
||||||
|
|
||||||
for ipv4_address in ipv4_network:
|
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:
|
if within_usable_range and str(ipv4_address) not in claimed_ipv4s:
|
||||||
allocated_ipv4_address = str(ipv4_address)
|
allocated_ipv4_address = str(ipv4_address)
|
||||||
break
|
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
|
# 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)
|
# enable static IP -> capsul mapping via libvirt (manage MAC addresses)
|
||||||
|
|
||||||
payload["network_name"] = 'public3'
|
payload["network_name"] = 'default'
|
||||||
payload["public_ipv4"] = ""
|
payload["public_ipv4"] = ""
|
||||||
|
|
||||||
return payload, ""
|
return payload, ""
|
||||||
|
@ -185,4 +188,15 @@ def on_create_claimed(payload, host_id):
|
||||||
network_name=payload['network_name'],
|
network_name=payload['network_name'],
|
||||||
public_ipv4=payload['public_ipv4'],
|
public_ipv4=payload['public_ipv4'],
|
||||||
ssh_authorized_keys=list(map(lambda x: x["name"], payload['ssh_authorized_keys'])),
|
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('.')))
|
|
@ -35,6 +35,7 @@ fi
|
||||||
|
|
||||||
case "$state" in
|
case "$state" in
|
||||||
1) printf '%s is already running\n' "$vmname" ;;
|
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" ;;
|
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
|
esac
|
||||||
|
|
|
@ -20,6 +20,9 @@ MAIL_PASSWORD=**************
|
||||||
```
|
```
|
||||||
#LOG_LEVEL=DEBUG
|
#LOG_LEVEL=DEBUG
|
||||||
|
|
||||||
|
FLASK_RUN_HOST=0.0.0.0
|
||||||
|
FLASK_RUN_PORT=5000
|
||||||
|
|
||||||
BASE_URL="https://capsul.org"
|
BASE_URL="https://capsul.org"
|
||||||
|
|
||||||
# hub url is used by the SPOKE_MODE to contact the hub. Since this server is the hub,
|
# 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`
|
- `memory_mb`
|
||||||
- `vcpus`
|
- `vcpus`
|
||||||
- `bandwidth_gb_per_month`
|
- `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)
|
## <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
|
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
|
||||||
|
|
|
@ -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).
|
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)
|
## <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.
|
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.
|
||||||
|
|
|
@ -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
|
## <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:
|
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 /var/www /tank/{vm,img,config}
|
||||||
sudo mkdir -p /tank/img/debian/10
|
sudo mkdir -p /tank/img/debian/10
|
||||||
cd !$
|
cd !$
|
||||||
sudo wget https://cloud.debian.org/images/cloud/buster/20201023-432/debian-10-genericcloud-amd64-20201023-432.qcow2 -O root.img.qcow2
|
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
|
## cyberia-cloudinit.yml
|
||||||
|
|
Loading…
Reference in a new issue