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): diff --git a/capsulflask/hub_api.py b/capsulflask/hub_api.py index 0725d30..292c55f 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 @@ -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'])), - ) \ 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, str(ip).split('.'))) \ No newline at end of file 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 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..5196a6c 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -4,17 +4,76 @@ 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 !$ 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