Implement SSH user data handling and adjust volume size

- Added functions to generate SSH user data in cloud-config format and encode it in Base64 for server creation.
- Updated the `create_gpu_server` function to include public key handling for SSH access.
- Adjusted the default boot volume size from 40GB to 30GB in `os_client.py`.
- Enhanced the `cmd_up` function to manage SSH key injection and server state more effectively.
- Improved logging for SSH connection attempts and error handling in `wait_ssh` to provide clearer feedback on authentication issues.
This commit is contained in:
Leonid Pershin
2026-08-21 04:35:02 +03:00
parent d6d247875b
commit 1f7237f7db
6 changed files with 155 additions and 22 deletions
+57 -8
View File
@@ -335,6 +335,30 @@ def _tag_server(conn, server, spot: bool) -> None:
pass
def _ssh_user_data(public_key: str) -> str:
"""Minimal cloud-config (Selectel docs: ssh_authorized_keys)."""
key = public_key.strip()
return (
"#cloud-config\n"
"ssh_authorized_keys:\n"
f" - {key}\n"
"users:\n"
" - default\n"
" - name: ubuntu\n"
" lock_passwd: true\n"
" shell: /bin/bash\n"
" sudo: ['ALL=(ALL) NOPASSWD:ALL']\n"
" ssh_authorized_keys:\n"
f" - {key}\n"
)
def _user_data_b64(public_key: str) -> str:
import base64
return base64.b64encode(_ssh_user_data(public_key).encode("utf-8")).decode("ascii")
def create_gpu_server(
conn,
*,
@@ -345,6 +369,7 @@ def create_gpu_server(
data_volume_id: str,
az: str,
spot: bool,
public_key: str,
log: Callable[[str], None],
) -> Any:
bdm = [
@@ -366,7 +391,7 @@ def create_gpu_server(
tags = [RESOURCE_TAG]
if spot:
tags.append(PREEMPTIBLE_TAG)
kwargs: dict[str, Any] = {
base: dict[str, Any] = {
"name": SERVER_NAME,
"flavor_id": flavor_id,
"networks": [{"uuid": net_id}],
@@ -374,16 +399,40 @@ def create_gpu_server(
"availability_zone": az,
"block_device_mapping_v2": bdm,
"security_groups": [{"name": sg_name}],
"tags": tags,
}
try:
server = conn.compute.create_server(**kwargs)
except Exception as exc:
kwargs.pop("tags", None)
ud_b64 = _user_data_b64(public_key)
ud_plain = _ssh_user_data(public_key)
# Selectel: OpenStack API expects Base64 user_data; config_drive often unsupported.
attempts: list[tuple[str, dict[str, Any]]] = [
("tags+user_data_b64", {**base, "tags": tags, "user_data": ud_b64}),
("user_data_b64", {**base, "user_data": ud_b64}),
("user_data_plain", {**base, "user_data": ud_plain}),
("key_name_only", {**base, "tags": tags}),
("minimal", dict(base)),
]
server = None
last_exc: BaseException | None = None
used = ""
for label, kwargs in attempts:
try:
server = conn.compute.create_server(**kwargs)
except Exception as exc2:
raise _wrap(exc2, "create server") from exc
used = label
break
except Exception as exc:
last_exc = exc
log(f"create {label}: {exc}")
if server is None:
raise _wrap(last_exc or RuntimeError("create failed"), "create server")
if "user_data" not in used:
log(
f"create OK ({used}) без user_data — ключ может не попасть на boot-from-volume; "
"смотри docs Selectel user-data (Base64)"
)
else:
log(f"create OK ({used})")
log("ждём Nova ACTIVE (GPU create может занять несколько минут)")
server = wait_server(conn, server, "ACTIVE")
_tag_server(conn, server, spot)