first crack at adding ssh host key display to the capsul detail page
This commit is contained in:
parent
29008bc963
commit
50cea6e0b4
@ -11,7 +11,8 @@ from flask import current_app
|
||||
from psycopg2 import ProgrammingError
|
||||
from flask_mail import Message
|
||||
|
||||
from capsulflask.db import get_model, my_exec_info_message
|
||||
from capsulflask.db import get_model
|
||||
from capsulflask.shared import my_exec_info_message
|
||||
from capsulflask.console import get_account_balance
|
||||
|
||||
bp = Blueprint('cli', __name__)
|
||||
|
@ -1,5 +1,6 @@
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
from datetime import datetime, timedelta
|
||||
from flask import Blueprint
|
||||
from flask import flash
|
||||
@ -15,7 +16,8 @@ from nanoid import generate
|
||||
|
||||
from capsulflask.metrics import durations as metric_durations
|
||||
from capsulflask.auth import account_required
|
||||
from capsulflask.db import get_model, my_exec_info_message
|
||||
from capsulflask.db import get_model
|
||||
from capsulflask.shared import my_exec_info_message
|
||||
from capsulflask.payment import poll_btcpay_session
|
||||
from capsulflask import cli
|
||||
|
||||
@ -25,19 +27,21 @@ def makeCapsulId():
|
||||
lettersAndNumbers = generate(alphabet="1234567890qwertyuiopasdfghjklzxcvbnm", size=10)
|
||||
return f"capsul-{lettersAndNumbers}"
|
||||
|
||||
def double_check_capsul_address(id, ipv4):
|
||||
def double_check_capsul_address(id, ipv4, get_ssh_host_keys):
|
||||
try:
|
||||
result = current_app.config["VIRTUALIZATION_MODEL"].get(id)
|
||||
result = current_app.config["VIRTUALIZATION_MODEL"].get(id, get_ssh_host_keys)
|
||||
if result.ipv4 != ipv4:
|
||||
ipv4 = result.ipv4
|
||||
get_model().update_vm_ip(email=session["account"], id=id, ipv4=result.ipv4)
|
||||
if get_ssh_host_keys:
|
||||
get_model().update_vm_ssh_host_keys(email=session["account"], id=id, ssh_host_keys=result.ssh_host_keys)
|
||||
except:
|
||||
current_app.logger.error(f"""
|
||||
the virtualization model threw an error in double_check_capsul_address of {id}:
|
||||
{my_exec_info_message(sys.exc_info())}"""
|
||||
)
|
||||
|
||||
return ipv4
|
||||
return result
|
||||
|
||||
@bp.route("/")
|
||||
@account_required
|
||||
@ -53,7 +57,7 @@ def index():
|
||||
# for now we are going to check the IP according to the virt model
|
||||
# on every request. this could be done by a background job and cached later on...
|
||||
for vm in vms:
|
||||
vm["ipv4"] = double_check_capsul_address(vm["id"], vm["ipv4"])
|
||||
vm["ipv4"] = double_check_capsul_address(vm["id"], vm["ipv4"], False).ipv4
|
||||
|
||||
vms = list(map(
|
||||
lambda x: dict(
|
||||
@ -104,9 +108,17 @@ def detail(id):
|
||||
return render_template("capsul-detail.html", vm=vm, delete=True, deleted=True)
|
||||
|
||||
else:
|
||||
vm["ipv4"] = double_check_capsul_address(vm["id"], vm["ipv4"])
|
||||
needs_ssh_host_keys = "ssh_host_keys" not in vm or len(vm["ssh_host_keys"]) == 0
|
||||
vm_from_virt_model = double_check_capsul_address(vm["id"], vm["ipv4"], needs_ssh_host_keys)
|
||||
vm["ipv4"] = vm_from_virt_model.ipv4
|
||||
if needs_ssh_host_keys:
|
||||
vm["ssh_host_keys"] = vm_from_virt_model.ssh_host_keys
|
||||
|
||||
vm["created"] = vm['created'].strftime("%b %d %Y %H:%M")
|
||||
vm["ssh_public_keys"] = ", ".join(vm["ssh_public_keys"]) if len(vm["ssh_public_keys"]) > 0 else "<missing>"
|
||||
vm["ssh_authorized_keys"] = ", ".join(vm["ssh_authorized_keys"]) if len(vm["ssh_authorized_keys"]) > 0 else "<missing>"
|
||||
|
||||
|
||||
current_app.logger.info(f"asd {needs_ssh_host_keys} {json.dumps(vm['ssh_host_keys'])})")
|
||||
|
||||
return render_template(
|
||||
"capsul-detail.html",
|
||||
@ -123,12 +135,12 @@ def detail(id):
|
||||
def create():
|
||||
vm_sizes = get_model().vm_sizes_dict()
|
||||
operating_systems = get_model().operating_systems_dict()
|
||||
ssh_public_keys = get_model().list_ssh_public_keys_for_account(session["account"])
|
||||
public_keys_for_account = get_model().list_ssh_public_keys_for_account(session["account"])
|
||||
account_balance = get_account_balance(get_vms(), get_payments(), datetime.utcnow())
|
||||
capacity_avaliable = current_app.config["VIRTUALIZATION_MODEL"].capacity_avaliable(512*1024*1024)
|
||||
errors = list()
|
||||
|
||||
ssh_keys_from_db_string = "\n".join(list(map(lambda x: f"name: {x['name']}**content: {x['content']}", ssh_public_keys)))
|
||||
ssh_keys_from_db_string = "\n".join(list(map(lambda x: f"name: {x['name']}**content: {x['content']}", public_keys_for_account)))
|
||||
email_to_log = session["account"]
|
||||
current_app.logger.info(f"create for {email_to_log}: ssh keys from db:\n {ssh_keys_from_db_string}")
|
||||
|
||||
@ -161,7 +173,7 @@ def create():
|
||||
posted_name = request.form[f"ssh_key_{i}"]
|
||||
current_app.logger.info(f"ssh key posted_name: {posted_name}")
|
||||
key = None
|
||||
for x in ssh_public_keys:
|
||||
for x in public_keys_for_account:
|
||||
if x['name'] == posted_name:
|
||||
current_app.logger.info(f"ssh key posted_name {posted_name} was found")
|
||||
key = x
|
||||
@ -190,7 +202,7 @@ def create():
|
||||
id=id,
|
||||
size=size,
|
||||
os=os,
|
||||
ssh_public_keys=list(map(lambda x: x["name"], posted_keys))
|
||||
ssh_authorized_keys=list(map(lambda x: x["name"], posted_keys))
|
||||
)
|
||||
current_app.config["VIRTUALIZATION_MODEL"].create(
|
||||
email = session["account"],
|
||||
@ -198,7 +210,7 @@ def create():
|
||||
template_image_file_name=operating_systems[os]['template_image_file_name'],
|
||||
vcpus=vm_sizes[size]['vcpus'],
|
||||
memory_mb=vm_sizes[size]['memory_mb'],
|
||||
ssh_public_keys=list(map(lambda x: x["content"], posted_keys))
|
||||
ssh_authorized_keys=list(map(lambda x: x["content"], posted_keys))
|
||||
)
|
||||
|
||||
return redirect(f"{url_for('console.index')}?created={id}")
|
||||
@ -219,9 +231,9 @@ def create():
|
||||
csrf_token = session["csrf-token"],
|
||||
capacity_avaliable=capacity_avaliable,
|
||||
account_balance=format(account_balance, '.2f'),
|
||||
ssh_public_keys=ssh_public_keys,
|
||||
ssh_public_key_count=len(ssh_public_keys),
|
||||
no_ssh_public_keys=len(ssh_public_keys) == 0,
|
||||
ssh_public_keys=public_keys_for_account,
|
||||
ssh_public_key_count=len(public_keys_for_account),
|
||||
no_ssh_public_keys=len(public_keys_for_account) == 0,
|
||||
operating_systems=operating_systems,
|
||||
cant_afford=len(affordable_vm_sizes) == 0,
|
||||
vm_sizes=affordable_vm_sizes
|
||||
|
@ -9,6 +9,7 @@ from flask import current_app
|
||||
from flask import g
|
||||
|
||||
from capsulflask.db_model import DBModel
|
||||
from capsulflask.shared import my_exec_info_message
|
||||
|
||||
def init_app(app):
|
||||
databaseUrl = urlparse(app.config['DATABASE_URL'])
|
||||
@ -41,7 +42,7 @@ def init_app(app):
|
||||
hasSchemaVersionTable = False
|
||||
actionWasTaken = False
|
||||
schemaVersion = 0
|
||||
desiredSchemaVersion = 11
|
||||
desiredSchemaVersion = 12
|
||||
|
||||
cursor = connection.cursor()
|
||||
|
||||
@ -127,5 +128,3 @@ def close_db(e=None):
|
||||
db_model.cursor.close()
|
||||
current_app.config['PSYCOPG2_CONNECTION_POOL'].putconn(db_model.connection)
|
||||
|
||||
def my_exec_info_message(exec_info):
|
||||
return "{}: {}".format(".".join([exec_info[0].__module__, exec_info[0].__name__]), exec_info[1])
|
||||
|
@ -104,7 +104,17 @@ class DBModel:
|
||||
self.cursor.execute("UPDATE vms SET last_seen_ipv4 = %s WHERE email = %s AND id = %s", (ipv4, email, id))
|
||||
self.connection.commit()
|
||||
|
||||
def create_vm(self, email, id, size, os, ssh_public_keys):
|
||||
def update_vm_ssh_host_keys(self, email, id, ssh_host_keys):
|
||||
for key in ssh_host_keys:
|
||||
self.cursor.execute("""
|
||||
INSERT INTO vm_ssh_host_key (email, vm_id, key_type, content, sha256)
|
||||
VALUES (%s, %s, %s, %s, %s)
|
||||
""",
|
||||
(email, id, key['key_type'], key['content'], key['sha256'])
|
||||
)
|
||||
self.connection.commit()
|
||||
|
||||
def create_vm(self, email, id, size, os, ssh_authorized_keys):
|
||||
self.cursor.execute("""
|
||||
INSERT INTO vms (email, id, size, os)
|
||||
VALUES (%s, %s, %s, %s)
|
||||
@ -112,14 +122,14 @@ class DBModel:
|
||||
(email, id, size, os)
|
||||
)
|
||||
|
||||
for ssh_public_key in ssh_public_keys:
|
||||
current_app.logger.info(f"INSERT INTO vm_ssh_public_key (email, vm_id, ssh_public_key_name) VALUES (\"{email}\", \"{id}\", \"{ssh_public_key}\")")
|
||||
for ssh_authorized_key in ssh_authorized_keys:
|
||||
current_app.logger.info(f"INSERT INTO vm_ssh_authorized_key (email, vm_id, ssh_public_key_name) VALUES (\"{email}\", \"{id}\", \"{ssh_authorized_key}\")")
|
||||
|
||||
self.cursor.execute("""
|
||||
INSERT INTO vm_ssh_public_key (email, vm_id, ssh_public_key_name)
|
||||
INSERT INTO vm_ssh_authorized_key (email, vm_id, ssh_public_key_name)
|
||||
VALUES (%s, %s, %s)
|
||||
""",
|
||||
(email, id, ssh_public_key)
|
||||
(email, id, ssh_authorized_key)
|
||||
)
|
||||
self.connection.commit()
|
||||
|
||||
@ -147,11 +157,19 @@ class DBModel:
|
||||
)
|
||||
|
||||
self.cursor.execute("""
|
||||
SELECT ssh_public_key_name FROM vm_ssh_public_key
|
||||
WHERE vm_ssh_public_key.email = %s AND vm_ssh_public_key.vm_id = %s""",
|
||||
SELECT ssh_public_key_name FROM vm_ssh_authorized_key
|
||||
WHERE vm_ssh_authorized_key.email = %s AND vm_ssh_authorized_key.vm_id = %s""",
|
||||
(email, id)
|
||||
)
|
||||
vm["ssh_public_keys"] = list(map( lambda x: x[0], self.cursor.fetchall() ))
|
||||
vm["ssh_authorized_keys"] = list(map( lambda x: x[0], self.cursor.fetchall() ))
|
||||
|
||||
|
||||
self.cursor.execute("""
|
||||
SELECT key_type, content, sha256 FROM vm_ssh_host_key
|
||||
WHERE vm_ssh_host_key.email = %s AND vm_ssh_host_key.vm_id = %s""",
|
||||
(email, id)
|
||||
)
|
||||
vm["ssh_host_keys"] = list(map( lambda x: dict(key_type=x[0], content=x[1], sha256=x[2]), self.cursor.fetchall() ))
|
||||
|
||||
return vm
|
||||
|
||||
|
@ -5,6 +5,7 @@ from functools import reduce
|
||||
import requests
|
||||
#import json
|
||||
from datetime import datetime
|
||||
from threading import Lock
|
||||
from io import BytesIO
|
||||
from flask import Blueprint
|
||||
from flask import current_app
|
||||
@ -15,6 +16,7 @@ from werkzeug.exceptions import abort
|
||||
from capsulflask.db import get_model
|
||||
from capsulflask.auth import account_required
|
||||
|
||||
mutex = Lock()
|
||||
bp = Blueprint("metrics", __name__, url_prefix="/metrics")
|
||||
|
||||
durations = dict(
|
||||
@ -116,6 +118,7 @@ def get_plot_bytes(metric, capsulid, duration, size):
|
||||
return (502, None)
|
||||
|
||||
series = prometheus_response.json()["data"]["result"]
|
||||
|
||||
if len(series) == 0:
|
||||
now_timestamp = datetime.timestamp(datetime.now())
|
||||
series = [
|
||||
@ -129,13 +132,19 @@ def get_plot_bytes(metric, capsulid, duration, size):
|
||||
series[0]["values"]
|
||||
))
|
||||
|
||||
plot_bytes = draw_plot_png_bytes(time_series_data, scale=scales[metric], size_x=sizes[size][0], size_y=sizes[size][1])
|
||||
mutex.acquire()
|
||||
try:
|
||||
plot_bytes = draw_plot_png_bytes(time_series_data, scale=scales[metric], size_x=sizes[size][0], size_y=sizes[size][1])
|
||||
finally:
|
||||
mutex.release()
|
||||
|
||||
return (200, plot_bytes)
|
||||
|
||||
|
||||
def draw_plot_png_bytes(data, scale, size_x=3, size_y=1):
|
||||
|
||||
#current_app.logger.info(json.dumps(data, indent=4, default=str))
|
||||
|
||||
pyplot.style.use("seaborn-dark")
|
||||
fig, my_plot = pyplot.subplots(figsize=(size_x, size_y))
|
||||
|
||||
|
@ -20,7 +20,8 @@ from werkzeug.exceptions import abort
|
||||
|
||||
from capsulflask.auth import account_required
|
||||
|
||||
from capsulflask.db import get_model, my_exec_info_message
|
||||
from capsulflask.db import get_model
|
||||
from capsulflask.shared import my_exec_info_message
|
||||
|
||||
bp = Blueprint("payment", __name__, url_prefix="/payment")
|
||||
|
||||
|
7
capsulflask/schema_migrations/12_down_ssh_host_keys.sql
Normal file
7
capsulflask/schema_migrations/12_down_ssh_host_keys.sql
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
|
||||
DROP TABLE vm_ssh_host_key;
|
||||
|
||||
ALTER TABLE vm_ssh_authorized_key RENAME TO vm_ssh_public_key;
|
||||
|
||||
UPDATE schemaversion SET version = 11;
|
14
capsulflask/schema_migrations/12_up_ssh_host_keys.sql
Normal file
14
capsulflask/schema_migrations/12_up_ssh_host_keys.sql
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
CREATE TABLE vm_ssh_host_key (
|
||||
email TEXT NOT NULL,
|
||||
vm_id TEXT NOT NULL,
|
||||
key_type TEXT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
sha256 TEXT NOT NULL,
|
||||
FOREIGN KEY (email, vm_id) REFERENCES vms(email, id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (email, vm_id, key_type)
|
||||
);
|
||||
|
||||
ALTER TABLE vm_ssh_public_key RENAME TO vm_ssh_authorized_key;
|
||||
|
||||
UPDATE schemaversion SET version = 12;
|
20
capsulflask/shared.py
Normal file
20
capsulflask/shared.py
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
from typing import List
|
||||
|
||||
# I decided to just use dict everywhere instead because I have to use dict to read it from json
|
||||
# class SSHHostKey:
|
||||
# def __init__(self, key_type=None, content=None, sha256=None):
|
||||
# self.key_type = key_type
|
||||
# self.content = content
|
||||
# self.sha256 = sha256
|
||||
|
||||
class VirtualMachine:
|
||||
def __init__(self, id, ipv4: str = None, ipv6: str = None, ssh_host_keys: List[dict] = list()):
|
||||
self.id = id
|
||||
self.ipv4 = ipv4
|
||||
self.ipv6 = ipv6
|
||||
self.ssh_host_keys = ssh_host_keys
|
||||
|
||||
|
||||
def my_exec_info_message(exec_info):
|
||||
return "{}: {}".format(".".join([exec_info[0].__module__, exec_info[0].__name__]), exec_info[1])
|
22
capsulflask/shell_scripts/ssh-keyscan.sh
Normal file
22
capsulflask/shell_scripts/ssh-keyscan.sh
Normal file
@ -0,0 +1,22 @@
|
||||
#!/bin/sh
|
||||
|
||||
ip_address="$1"
|
||||
|
||||
if echo "$ip_address" | grep -vqE '^([0-9]{1,3}\.){3}[0-9]{1,3}$'; then
|
||||
echo "ip_address $ip_address must match "'"^([0-9]{1,3}\.){3}[0-9]{1,3}$"'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf '['
|
||||
DELIMITER="\n"
|
||||
ssh-keyscan "$ip_address" 2>/dev/null | while read -r line; do
|
||||
if echo "$line" | grep -qE "^$ip_address"' +(ssh|ecdsa)-[0-9A-Za-z+/_=@. -]+$'; then
|
||||
KEY_CONTENT="$(echo "$line" | awk '{ print $2 " " $3 }')"
|
||||
FINGERPRINT_OUTPUT="$(echo "$KEY_CONTENT" | ssh-keygen -l -E sha256 -f - | sed -E 's/^[0-9]+ SHA256:([0-9A-Za-z+/-]+) .+ \(([A-Z0-9]+)\)$/\1 \2/g')"
|
||||
SHA256_HASH="$(echo "$FINGERPRINT_OUTPUT" | awk '{ print $1 }')"
|
||||
KEY_TYPE="$(echo "$FINGERPRINT_OUTPUT" | awk '{ print $2 }')"
|
||||
printf '%s{"key_type":"%s", "content":"%s", "sha256":"%s"}' "$DELIMITER" "$KEY_TYPE" "$KEY_CONTENT" "$SHA256_HASH"
|
||||
DELIMITER=",\n"
|
||||
fi
|
||||
done
|
||||
printf '\n]\n'
|
@ -102,6 +102,9 @@ main {
|
||||
.row.grid-large > div {
|
||||
flex: 1 1 20em;
|
||||
}
|
||||
.row.grid-medium > div {
|
||||
flex: 1 1 13em;
|
||||
}
|
||||
.row.grid-small > div {
|
||||
flex: 0 0 8em;
|
||||
}
|
||||
@ -277,8 +280,12 @@ div.metric {
|
||||
border: 1px solid #777e73;
|
||||
background: #bdc7b810;
|
||||
}
|
||||
.break-word {
|
||||
word-break: break-word;
|
||||
pre.code.wrap {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.break-all {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.dim {
|
||||
|
@ -73,8 +73,8 @@
|
||||
<span id="ssh_username">cyberian</span>
|
||||
</div>
|
||||
<div class="row justify-start">
|
||||
<label class="align" for="ssh_public_keys">SSH Public Keys</label>
|
||||
<a id="ssh_public_keys" href="/console/ssh">{{ vm['ssh_public_keys'] }}</a>
|
||||
<label class="align" for="ssh_authorized_keys">SSH Authorized Keys</label>
|
||||
<a id="ssh_authorized_keys" href="/console/ssh">{{ vm['ssh_authorized_keys'] }}</a>
|
||||
</div>
|
||||
<div class="row center justify-start">
|
||||
<label class="align" for="delete_action">Actions</label>
|
||||
@ -85,6 +85,15 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row third-margin">
|
||||
<h1>ssh host key fingerprints</h1>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<pre class="code">{% for key in vm['ssh_host_keys'] %}
|
||||
SHA256:{{ key.sha256 }} ({{ key.key_type }}){% endfor %}</pre>
|
||||
</div>
|
||||
|
||||
<div class="row ">
|
||||
<hr/>
|
||||
</div>
|
||||
@ -136,6 +145,17 @@
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row ">
|
||||
<hr/>
|
||||
</div>
|
||||
<div class="row half-margin">
|
||||
add the following to your ~/.ssh/known_hosts file (optional)
|
||||
</div>
|
||||
<div class="row">
|
||||
<pre class="code wrap break-all smalltext">{% for key in vm['ssh_host_keys'] %}
|
||||
{{ vm['ipv4'] }} {{ key.content }}{% endfor %}
|
||||
</pre>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
import subprocess
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
|
||||
from flask import current_app
|
||||
from time import sleep
|
||||
@ -7,28 +9,23 @@ from os.path import join
|
||||
from subprocess import run
|
||||
|
||||
from capsulflask.db import get_model
|
||||
from capsulflask.shared import my_exec_info_message, VirtualMachine
|
||||
|
||||
def validate_capsul_id(id):
|
||||
if not re.match(r"^(cvm|capsul)-[a-z0-9]{10}$", id):
|
||||
raise ValueError(f"vm id \"{id}\" must match \"^capsul-[a-z0-9]{{10}}$\"")
|
||||
|
||||
class VirtualMachine:
|
||||
def __init__(self, id, ipv4=None, ipv6=None):
|
||||
self.id = id
|
||||
self.ipv4 = ipv4
|
||||
self.ipv6 = ipv6
|
||||
|
||||
class VirtualizationInterface:
|
||||
def capacity_avaliable(self, additional_ram_bytes: int) -> bool:
|
||||
pass
|
||||
|
||||
def get(self, id: str) -> VirtualMachine:
|
||||
def get(self, id: str, get_ssh_host_keys: bool) -> VirtualMachine:
|
||||
pass
|
||||
|
||||
def list_ids(self) -> list:
|
||||
pass
|
||||
|
||||
def create(self, email: str, id: str, template_image_file_name: str, vcpus: int, memory: int, ssh_public_keys: list):
|
||||
def create(self, email: str, id: str, template_image_file_name: str, vcpus: int, memory: int, ssh_authorized_keys: list):
|
||||
pass
|
||||
|
||||
def destroy(self, email: str, id: str):
|
||||
@ -38,14 +35,23 @@ class MockVirtualization(VirtualizationInterface):
|
||||
def capacity_avaliable(self, additional_ram_bytes):
|
||||
return True
|
||||
|
||||
def get(self, id):
|
||||
def get(self, id, get_ssh_host_keys):
|
||||
validate_capsul_id(id)
|
||||
|
||||
if get_ssh_host_keys:
|
||||
ssh_host_keys = json.loads("""[
|
||||
{"key_type":"ED25519", "content":"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN8cna0zeKSKl/r8whdn/KmDWhdzuWRVV0GaKIM+eshh", "sha256":"V4X2apAF6btGAfS45gmpldknoDX0ipJ5c6DLfZR2ttQ"},
|
||||
{"key_type":"RSA", "content":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCvotgzgEP65JUQ8S8OoNKy1uEEPEAcFetSp7QpONe6hj4wPgyFNgVtdoWdNcU19dX3hpdse0G8OlaMUTnNVuRlbIZXuifXQ2jTtCFUA2mmJ5bF+XjGm3TXKMNGh9PN+wEPUeWd14vZL+QPUMev5LmA8cawPiU5+vVMLid93HRBj118aCJFQxLgrdP48VPfKHFRfCR6TIjg1ii3dH4acdJAvlmJ3GFB6ICT42EmBqskz2MPe0rIFxH8YohCBbAbrbWYcptHt4e48h4UdpZdYOhEdv89GrT8BF2C5cbQ5i9qVpI57bXKrj8hPZU5of48UHLSpXG8mbH0YDiOQOfKX/Mt", "sha256":"ghee6KzRnBJhND2kEUZSaouk7CD6o6z2aAc8GPkV+GQ"},
|
||||
{"key_type":"ECDSA", "content":"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLLgOoATz9R4aS2kk7vWoxX+lshK63t9+5BIHdzZeFE1o+shlcf0Wji8cN/L1+m3bi0uSETZDOAWMP3rHLJj9Hk=", "sha256":"aCYG1aD8cv/TjzJL0bi9jdabMGksdkfa7R8dCGm1yYs"}
|
||||
]""")
|
||||
return VirtualMachine(id, ipv4="1.1.1.1", ssh_host_keys=ssh_host_keys)
|
||||
|
||||
return VirtualMachine(id, ipv4="1.1.1.1")
|
||||
|
||||
def list_ids(self) -> list:
|
||||
return get_model().all_non_deleted_vm_ids()
|
||||
|
||||
def create(self, email: str, id: str, template_image_file_name: str, vcpus: int, memory_mb: int, ssh_public_keys: list):
|
||||
def create(self, email: str, id: str, template_image_file_name: str, vcpus: int, memory_mb: int, ssh_authorized_keys: list):
|
||||
validate_capsul_id(id)
|
||||
current_app.logger.info(f"mock create: {id} for {email}")
|
||||
sleep(1)
|
||||
@ -91,19 +97,31 @@ class ShellScriptVirtualization(VirtualizationInterface):
|
||||
|
||||
return True
|
||||
|
||||
def get(self, id):
|
||||
def get(self, id, get_ssh_host_keys):
|
||||
validate_capsul_id(id)
|
||||
completedProcess = run([join(current_app.root_path, 'shell_scripts/get.sh'), id], capture_output=True)
|
||||
self.validate_completed_process(completedProcess)
|
||||
lines = completedProcess.stdout.splitlines()
|
||||
if len(lines) == 0:
|
||||
ipaddr_lines = completedProcess.stdout.splitlines()
|
||||
if len(ipaddr_lines) == 0:
|
||||
return None
|
||||
|
||||
ipaddr = lines[0].decode("utf-8")
|
||||
ipaddr = ipaddr_lines[0].decode("utf-8")
|
||||
|
||||
if not re.match(r"^([0-9]{1,3}\.){3}[0-9]{1,3}$", ipaddr):
|
||||
return None
|
||||
|
||||
if get_ssh_host_keys:
|
||||
try:
|
||||
completedProcess2 = run([join(current_app.root_path, 'shell_scripts/ssh-keyscan.sh'), ipaddr], capture_output=True)
|
||||
self.validate_completed_process(completedProcess2)
|
||||
ssh_host_keys = json.loads(completedProcess2.stdout)
|
||||
return VirtualMachine(id, ipv4=ipaddr, ssh_host_keys=ssh_host_keys)
|
||||
except:
|
||||
current_app.logger.warning(f"""
|
||||
failed to ssh-keyscan {id} at {ipaddr}:
|
||||
{my_exec_info_message(sys.exc_info())}"""
|
||||
)
|
||||
|
||||
return VirtualMachine(id, ipv4=ipaddr)
|
||||
|
||||
def list_ids(self) -> list:
|
||||
@ -111,13 +129,13 @@ class ShellScriptVirtualization(VirtualizationInterface):
|
||||
self.validate_completed_process(completedProcess)
|
||||
return list(map(lambda x: x.decode("utf-8"), completedProcess.stdout.splitlines() ))
|
||||
|
||||
def create(self, email: str, id: str, template_image_file_name: str, vcpus: int, memory_mb: int, ssh_public_keys: list):
|
||||
def create(self, email: str, id: str, template_image_file_name: str, vcpus: int, memory_mb: int, ssh_authorized_keys: list):
|
||||
validate_capsul_id(id)
|
||||
|
||||
if not re.match(r"^[a-zA-Z0-9/_.-]+$", template_image_file_name):
|
||||
raise ValueError(f"template_image_file_name \"{template_image_file_name}\" must match \"^[a-zA-Z0-9/_.-]+$\"")
|
||||
|
||||
for ssh_public_key in ssh_public_keys:
|
||||
for ssh_public_key in ssh_authorized_keys:
|
||||
if not re.match(r"^(ssh|ecdsa)-[0-9A-Za-z+/_=@. -]+$", ssh_public_key):
|
||||
raise ValueError(f"ssh_public_key \"{ssh_public_key}\" must match \"^(ssh|ecdsa)-[0-9A-Za-z+/_=@. -]+$\"")
|
||||
|
||||
@ -127,7 +145,7 @@ class ShellScriptVirtualization(VirtualizationInterface):
|
||||
if memory_mb < 512 or memory_mb > 16384:
|
||||
raise ValueError(f"memory_mb \"{memory_mb}\" must match 512 <= memory_mb <= 16384")
|
||||
|
||||
ssh_keys_string = "\n".join(ssh_public_keys)
|
||||
ssh_keys_string = "\n".join(ssh_authorized_keys)
|
||||
|
||||
current_app.logger.info(f"create vm virt model ssh_keys_string: {ssh_keys_string}")
|
||||
|
||||
@ -149,7 +167,7 @@ class ShellScriptVirtualization(VirtualizationInterface):
|
||||
template_image_file_name={template_image_file_name}
|
||||
vcpus={str(vcpus)}
|
||||
memory={str(memory_mb)}
|
||||
ssh_public_keys={ssh_keys_string}
|
||||
ssh_authorized_keys={ssh_keys_string}
|
||||
"""
|
||||
|
||||
current_app.logger.info(f"create vm status: {status} vmSettings: {vmSettings}")
|
||||
|
Loading…
Reference in New Issue
Block a user