Я запускаю Linux под QEMU как часть набора тестов для скрипта Python, который выполняет некоторые привилегированные операции. Для меня важно запустить полноценную виртуальную машину, потому что:
Мой подход состоит в том, чтобы запустить виртуальную машину QEMU с портом хоста, перенаправленным на SSH на виртуальной машине, отправить и запустить сценарий через SSH, запустить сценарий и подтвердить данные об удаленной системе. Раздражает в этой настройке порт SSH и порты для других сетевых приложений.
Мой вопрос: Как без конфликтов перенаправить порты в QEMU пользовательского режима?
Моя цель здесь - иметь возможность запускать несколько тестов одновременно без какой-либо предварительной настройки и без sudo, как упоминалось выше. Сеть в пользовательском режиме в QEMU поддерживает переадресацию портов, и когда я передаю 0
для порта хоста в объявлении hostfwd (hostfwd=tcp:127.0.0.1:0-:22
) ОС выделяет один динамически. Потрясающие! Проблема заключалась в том, чтобы надежно получить этот порт в родительском процессе.
Я делаю эквивалент:
#!/bin/sh
set -e
cd "$(mktemp -d)"
# Download cloud image.
image_base_url="https://cloud-images.ubuntu.com/releases/18.04/release/"
image_name="ubuntu-18.04-server-cloudimg-amd64.img"
image_url="$image_base_url$image_name"
curl --location -o linux.img $image_url
# Create SSH key.
ssh_key_path="$PWD/id_rsa"
ssh-keygen -t rsa -b 4096 -N "" -f "$ssh_key_path"
# Create cloud-init payload.
cat <<EOF > user_data
#cloud-config
password: ubuntu
chpasswd: { expire: False }
ssh_pwauth: True
ssh_authorized_keys:
- $(cat "${ssh_key_path}.pub")
EOF
cloud-localds user_data.img user_data
# Socket path for QMP.
qmp_socket="$PWD/qmp.sock"
# Start VM.
qemu-system-x86_64 \
-drive file=linux.img,format=qcow2 \
-drive file=user_data.img,format=raw \
-netdev user,id=net0,hostfwd=tcp:127.0.0.1:0-:22 \
-device rtl8139,netdev=net0 \
-enable-kvm \
-m 2G \
-serial mon:stdio \
-nographic \
-smp 2 \
-snapshot \
-qmp unix:$qmp_socket,server,nowait \
& \
;
# wait a bit, then test stuff here
# ...
Гостевая ОС подходит.
Вещи, которые я пробовал:
немного поиграл с QMP, но не смог найти команду, которая предоставила информацию
считается привязкой случайного порта в родительском процессе с SO_REUSEPORT
а затем указав его для дочерней команды, но QEMU не использует этот флаг, поэтому он не работает
netstat -nalp | grep $child_pid
, но это не будет использоваться при переадресации нескольких портов
выбор случайного несвязанного порта, попытка запустить с ним qemu и повторная попытка, если это не удается с соответствием сообщения Could not set up host forwarding rule 'tcp:...'
. Это работает, но
Это нормальный откат, но я надеюсь на более простое решение.
После небольшого дополнительного исследования: QEMU предоставляет информацию через info usernet
команда. Вот как выглядит результат:
(qemu) info usernet
VLAN -1 (net0):
Protocol[State] FD Source Address Port Dest. Address Port RecvQ SendQ
TCP[HOST_FORWARD] 13 127.0.0.1 38117 10.0.2.15 22 0 0
UDP[236 sec] 24 10.0.2.15 35061 91.189.89.198 123 0 0
UDP[204 sec] 26 10.0.2.15 60630 91.189.89.198 123 0 0
Он недоступен через QMP, но был отправлен патч для добавления эквивалентного query-usernet
Вот некоторое время назад.
В моем случае легко выставить монитор с помощью -monitor unix:$PWD/mon.sock,server,nowait
, подключитесь, отправьте команду, прочтите вывод и проанализируйте его на предмет требуемых значений.
Таким образом, чтобы использовать QEMU для тестирования сетевых приложений, не требуя sudo или других предварительных требований (кроме самого QEMU) и избегая конфликтов портов на хосте:
-netdev
) или монитор (netdev_add
), обеспечивая 0
для хост-портаmonitor
как сокет unix для приложения-потребителяinfo usernet
через сокет и извлеките порт источника для каждого сопоставления, который является фактическим портом, выделенным ОС.