From 46cf692653ea6ce482e307fb1d942d95dc527e44 Mon Sep 17 00:00:00 2001 From: forest Date: Wed, 5 Oct 2022 19:13:17 -0500 Subject: [PATCH 1/7] fix can_claim_create non lexicographic number comparison issue --- capsulflask/hub_api.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/capsulflask/hub_api.py b/capsulflask/hub_api.py index 0725d30..a8dbd1d 100644 --- a/capsulflask/hub_api.py +++ b/capsulflask/hub_api.py @@ -144,11 +144,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 +167,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 +187,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'])), - ) \ No newline at end of file + ) + + + +# 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, ip.split('.'))) \ No newline at end of file -- 2.40.1 From 0383ed91b61ca090e06369fca4ba6baf724253d4 Mon Sep 17 00:00:00 2001 From: forest Date: Wed, 5 Oct 2022 19:13:47 -0500 Subject: [PATCH 2/7] docs enhancements made during dev env setup --- docs/configuration.md | 18 ++++++++++++++++- docs/database.md | 10 +++++++++ docs/deployment.md | 47 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 51ff7ee..8f57110 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -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\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'); +``` + + ## 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 diff --git a/docs/database.md b/docs/database.md index 4c02f81..b7179f5 100644 --- a/docs/database.md +++ b/docs/database.md @@ -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"` + + ## 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. diff --git a/docs/deployment.md b/docs/deployment.md index debb53e..b1b4dfb 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -14,7 +14,52 @@ 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 + + default + 5b8008c5-e3c3-4b32-bbec-27071d8d0a92 + + + + + + + + + + + + + +``` + +> 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 -- 2.40.1 From bb2ea35719ecfc06c085b6302f0e64f9e4de3dc5 Mon Sep 17 00:00:00 2001 From: forest Date: Wed, 5 Oct 2022 19:17:38 -0500 Subject: [PATCH 3/7] fix missing functools --- capsulflask/hub_api.py | 1 + 1 file changed, 1 insertion(+) diff --git a/capsulflask/hub_api.py b/capsulflask/hub_api.py index a8dbd1d..6b01aa7 100644 --- a/capsulflask/hub_api.py +++ b/capsulflask/hub_api.py @@ -1,5 +1,6 @@ import json import ipaddress +from functools import reduce from flask import Blueprint from flask import current_app -- 2.40.1 From 95800620c2ee98d0b375d2d1cf297869f7c69f54 Mon Sep 17 00:00:00 2001 From: forest Date: Wed, 5 Oct 2022 19:18:55 -0500 Subject: [PATCH 4/7] fix: ensure ip arg is a string --- capsulflask/hub_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/capsulflask/hub_api.py b/capsulflask/hub_api.py index 6b01aa7..292c55f 100644 --- a/capsulflask/hub_api.py +++ b/capsulflask/hub_api.py @@ -199,4 +199,4 @@ def ip2int(ip): :param ip: IP string :return: IP integer """ - return reduce(lambda x, y: x * 256 + y, map(int, ip.split('.'))) \ No newline at end of file + return reduce(lambda x, y: x * 256 + y, map(int, str(ip).split('.'))) \ No newline at end of file -- 2.40.1 From 5441b9fbe8fe9b70a9e02db5ea96177baeba75c9 Mon Sep 17 00:00:00 2001 From: forest Date: Mon, 10 Oct 2022 13:46:39 -0500 Subject: [PATCH 5/7] add kvm-ok to docs --- docs/deployment.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/deployment.md b/docs/deployment.md index b1b4dfb..5196a6c 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -4,10 +4,24 @@ Capsul has a ["hub and spoke" architecture](./architecture.md). The "Hub" runs t ## 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 !$ -- 2.40.1 From 29d60722c254437fe664131b8be91411748fe63a Mon Sep 17 00:00:00 2001 From: forest Date: Mon, 10 Oct 2022 13:46:55 -0500 Subject: [PATCH 6/7] fix start script to enable resuming vms --- capsulflask/shell_scripts/start.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/capsulflask/shell_scripts/start.sh b/capsulflask/shell_scripts/start.sh index f9e01d1..13a07a7 100755 --- a/capsulflask/shell_scripts/start.sh +++ b/capsulflask/shell_scripts/start.sh @@ -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 -- 2.40.1 From f862694c86db6a04ed2850b5ef037b7e95295d57 Mon Sep 17 00:00:00 2001 From: forest Date: Thu, 3 Nov 2022 11:34:43 -0500 Subject: [PATCH 7/7] fix terminated due to nonpayment related billing bug It messed up billing information for an account resulting in an epically massive negative account balance -- every single vm was marked as existing from its time of creation until the time the account ran out of funds -- the "deleted" timestamps of many many capsuls were moved far into the future, thus dramatically expanding the amount of money billed for those capsuls --- capsulflask/db_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/capsulflask/db_model.py b/capsulflask/db_model.py index 7fa509e..bb68a29 100644 --- a/capsulflask/db_model.py +++ b/capsulflask/db_model.py @@ -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): -- 2.40.1