diff options
Diffstat (limited to 'grid5000/steps/bootstrap')
-rw-r--r-- | grid5000/steps/bootstrap/debian/prepare_autoinstall.yaml | 11 | ||||
-rw-r--r-- | grid5000/steps/bootstrap/download_installer.yaml | 31 | ||||
-rw-r--r-- | grid5000/steps/bootstrap/prepare_appliance.yaml | 33 | ||||
-rw-r--r-- | grid5000/steps/bootstrap/prepare_disk.yaml | 10 | ||||
-rw-r--r-- | grid5000/steps/bootstrap/prepare_ssh_to_out_context.yaml | 23 | ||||
-rw-r--r-- | grid5000/steps/bootstrap/start_http_server.yaml | 19 | ||||
-rw-r--r-- | grid5000/steps/bootstrap/start_qemu.yaml | 227 |
7 files changed, 354 insertions, 0 deletions
diff --git a/grid5000/steps/bootstrap/debian/prepare_autoinstall.yaml b/grid5000/steps/bootstrap/debian/prepare_autoinstall.yaml new file mode 100644 index 0000000..f737d20 --- /dev/null +++ b/grid5000/steps/bootstrap/debian/prepare_autoinstall.yaml @@ -0,0 +1,11 @@ +- copy_autoinstall_script_to_http_directory: + - exec_local: mkdir -p $${http_directory} + - exec_local: cp $${base_preseed_path} $${http_directory}/preseed.cfg + +- customize_preseed: + - exec_local: sed -i -e 's|\(d-i passwd/root-password password \).*|\1$${root_password}|g' $${http_directory}/preseed.cfg + - exec_local: sed -i -e 's|\(d-i passwd/root-password-again password \).*|\1$${root_password}|g' $${http_directory}/preseed.cfg + - exec_local: sed -i -e 's|\(d-i mirror/http/hostname string \).*|\1$${deb_mirror_hostname}|g' $${http_directory}/preseed.cfg + - exec_local: sed -i -e 's|\(d-i mirror/http/directory string \).*|\1$${deb_mirror_directory}|g' $${http_directory}/preseed.cfg + - exec_local: sed -i -e 's|\(d-i apt-setup/security_host string \).*|\1$${deb_security_hostname}|g' $${http_directory}/preseed.cfg + - exec_local: sed -i -e 's|\(d-i apt-setup/security_path string \).*|\1$${deb_security_directory}|g' $${http_directory}/preseed.cfg diff --git a/grid5000/steps/bootstrap/download_installer.yaml b/grid5000/steps/bootstrap/download_installer.yaml new file mode 100644 index 0000000..f15f58c --- /dev/null +++ b/grid5000/steps/bootstrap/download_installer.yaml @@ -0,0 +1,31 @@ +- download_installer: + - test: + - exec_local: test -n "$${installer_iso_url}" -o -n "$${installer_iso_finder_helper}" + - group: + - test: + - exec_local: test -z "$${installer_iso_url}" + - exec_local: | + echo "Looking for the netinstall iso URL for $${installer_iso_finder_args}" + DOWNLOAD_SRC_URL=$(python2 $${installer_iso_finder_helper} $${installer_iso_finder_args}) + - download_file_local: + - $${installer_iso_url} + - $${qemu_iso_path} + - exec_local: unset DOWNLOAD_SRC_URL + - group: + - test: + - exec_local: test -n "$${installer_kernel_url}" + - download_file_local: + - $${installer_kernel_url} + - $${qemu_kernel_path} + - test: + - exec_local: test -n "$${installer_initrd_url}" + - download_file_local: + - $${installer_initrd_url} + - $${qemu_initrd_path} + +- delete_installer: + - on_checkpoint: skip + - on_export_clean: + - exec_local: rm -f $${qemu_iso_path} + - exec_local: rm -f $${qemu_kernel_path} + - exec_local: rm -f $${qemu_initrd_path} diff --git a/grid5000/steps/bootstrap/prepare_appliance.yaml b/grid5000/steps/bootstrap/prepare_appliance.yaml new file mode 100644 index 0000000..4f597c4 --- /dev/null +++ b/grid5000/steps/bootstrap/prepare_appliance.yaml @@ -0,0 +1,33 @@ +- insecure_ssh_key: $${kameleon_cwd}/insecure_ssh_key + +- generate_ssh_keys: + - check_cmd_local: ssh-keygen + - exec_local: echo -e 'y\n' | ssh-keygen -q -t rsa -b 4096 -f $${insecure_ssh_key} -N '' + - exec_local: cat $${insecure_ssh_key} + +- inject_ssh_private_key: + - check_cmd_local: virt-customize + - exec_local: | + virt-customize \ + -a $${image_disk}.$${image_format} \ + --run-command 'mkdir -p /root/.ssh' \ + --upload $${insecure_ssh_key}.pub:/root/.ssh/.kameleon_authorized_keys \ + --run-command 'touch /root/.ssh/authorized_keys' \ + --run-command 'cp /root/.ssh/authorized_keys /root/.ssh/authorized_keys.bak' \ + --run-command 'cat /root/.ssh/.kameleon_authorized_keys >> /root/.ssh/authorized_keys' \ + --run-command 'chmod 700 /root/.ssh' \ + --run-command 'chmod -R go-rw /root/.ssh' \ + --run-command 'chown -R root:root /root/.ssh' + - on_export_init: + - exec_local: | + virt-customize \ + -a $${image_disk}.$${image_format} \ + --run-command 'mv /root/.ssh/authorized_keys.bak /root/.ssh/authorized_keys' \ + --delete /root/.ssh/.kameleon_authorized_keys + +- add_insecure_key_to_ssh_config: + - on_checkpoint: redo + - exec_local: | + cat <<EOF >> $${ssh_config_file} + IdentityFile $${insecure_ssh_key} + EOF diff --git a/grid5000/steps/bootstrap/prepare_disk.yaml b/grid5000/steps/bootstrap/prepare_disk.yaml new file mode 100644 index 0000000..9c3dce4 --- /dev/null +++ b/grid5000/steps/bootstrap/prepare_disk.yaml @@ -0,0 +1,10 @@ +- create_initial_image: + - check_cmd_local: qemu-img + - exec_local: | + rm -f $${image_disk}.$${image_format} + qemu-img create -f qcow2 $${image_disk}.$${image_format} $${qemu_image_size} + +- delete_initial_image: + - on_checkpoint: skip + - on_export_clean: + - exec_local: rm -f $${image_disk}.$${image_format} diff --git a/grid5000/steps/bootstrap/prepare_ssh_to_out_context.yaml b/grid5000/steps/bootstrap/prepare_ssh_to_out_context.yaml new file mode 100644 index 0000000..172f7a4 --- /dev/null +++ b/grid5000/steps/bootstrap/prepare_ssh_to_out_context.yaml @@ -0,0 +1,23 @@ +- select_empty_port: + - on_checkpoint: redo + - exec_local: | + # Find empty SSH forwarding port + SSH_FWD_PORT=$(__find_free_port 50000 60000) + echo "SSH forwarding port: $SSH_FWD_PORT" +- prepare_ssh_config: + - on_checkpoint: redo + - write_local: + - $${ssh_config_file} + - | + Host $${kameleon_recipe_name} + HostName 127.0.0.1 + Port ${SSH_FWD_PORT} + User root + UserKnownHostsFile /dev/null + StrictHostKeyChecking no + PasswordAuthentication no + IdentitiesOnly yes + LogLevel FATAL + ForwardAgent yes + Compression yes + Protocol 2 diff --git a/grid5000/steps/bootstrap/start_http_server.yaml b/grid5000/steps/bootstrap/start_http_server.yaml new file mode 100644 index 0000000..59184c3 --- /dev/null +++ b/grid5000/steps/bootstrap/start_http_server.yaml @@ -0,0 +1,19 @@ +- http_script: $${kameleon_data_dir}/helpers/simple_http_server.py + +- run_http_server: + - exec_local: | + HTTP_PORT=$(__find_free_port 8000 8100) + echo "HTTP port: $HTTP_PORT" + export HTTP_PORT + - exec_local: python2 $${http_script} --root $${http_directory} --bind 0.0.0.0 --port $HTTP_PORT --daemon --pid $${http_pid} + - on_bootstrap_clean: + - exec_local: | + if [ -f $${http_pid} ]; then + HTTP_PID=$(cat $${http_pid}) + if ps -p $HTTP_PID > /dev/null; then + echo "Killing HTTP server (pid: $HTTP_PID)..." + kill -9 "$HTTP_PID" + rm -f $${http_pid} + fi + rm -f $${http_pid} + fi diff --git a/grid5000/steps/bootstrap/start_qemu.yaml b/grid5000/steps/bootstrap/start_qemu.yaml new file mode 100644 index 0000000..35e0206 --- /dev/null +++ b/grid5000/steps/bootstrap/start_qemu.yaml @@ -0,0 +1,227 @@ +# Require SSH_FWD_PORT bash environment variable to be set + +# This must be set if you want to boot an ISO image: +- qemu_iso_path: "" +- qemu_iso_boot: true +# Else that can be set to boot from a kernel, initrd and cmdline: +- qemu_kernel_path: "" +- qemu_initrd_path: "" +- qemu_append_cmdline: "" +# Else boot from disk. + +- vm_expected_service: ssh +- boot_timeout: 100 +- shutdown_timeout: 100 +- debug: false +- telnet_port: "" +- no_reboot: true +- socat_monitor: socat - UNIX-CONNECT:$${qemu_monitor_socket} +- qemu_sendkeys_script: $${kameleon_data_dir}/qemu-sendkeys.rb +- qemu_sendkeys_commands: +- vm_expected_service: ssh +- vm_cleanup_section: setup +- shutdown_vm_immediately: false +- force_vm_shutdown: true +- qemu_enable_kvm: true +- qemu_cpus: 2 +- qemu_memory_size: 1024 +- qemu_monitor_socket: $${kameleon_cwd}/qemu_monitor.socket +- qemu_arch: $${arch} +- qemu_image_size: 10G +- qemu_pidfile: $${kameleon_cwd}/qemu.pid +- qemu_uefi: false +- qemu_uefi_code_path: /usr/share/AAVMF/AAVMF_CODE.fd +- qemu_uefi_vars_path: /usr/share/AAVMF/AAVMF_VARS.fd +- qemu_netdev_user_options: +- disk_cache: unsafe + +- start_vm: + - on_checkpoint: redo + - check_cmd_local: qemu-system-$${qemu_arch} + - check_cmd_local: socat + - on_bootstrap_clean: + - test: + - exec_local: test "$${shutdown_vm_immediately}" == "false" -a "$${vm_cleanup_section}" == "bootstrap" + - group: + - exec_local: &1 | + if [ -f $${qemu_pidfile} ]; then + _QEMU_PID=$(< $${qemu_pidfile}) + if ps -p $_QEMU_PID > /dev/null; then + if [ "$${force_vm_shutdown}" == "true" ]; then + if [ -S $${qemu_monitor_socket} ]; then + echo "Executing a graceful shutdown of the qemu VM via the monitor socket..." + NEXT_WAIT_TIME=0 + echo system_powerdown | socat - UNIX-CONNECT:$${qemu_monitor_socket} || true + while ps -p $_QEMU_PID > /dev/null && [ $NEXT_WAIT_TIME -lt $${shutdown_timeout} ]; + do + sleep 1 + echo -en "\rWaiting for qemu virtual machine to shutdown...($(( $${shutdown_timeout} - 1 - NEXT_WAIT_TIME++ ))s)" + done + fi + else + echo "Waiting for the VM to shutdown" + echo "Run 'vncviewer :$VNC_PORT' to see what's happening in the VM" + while ps -p $_QEMU_PID > /dev/null; + do + sleep 2 + done + fi + fi + fi + - exec_local: &2 | + if [ -f $${qemu_pidfile} ]; then + _QEMU_PID=$(< $${qemu_pidfile}) + if ps -p $_QEMU_PID > /dev/null; then + if [ -S $${qemu_monitor_socket} ]; then + echo "The graceful shutdown of the qemu VM should have failed (monitor socket is there)..." + fi + echo "Killing qemu (pid: $_QEMU_PID)." + kill -9 "$_QEMU_PID" + fi + rm -f $${qemu_pidfile} + fi + rm -f $${qemu_monitor_socket} + - on_setup_clean: + - test: + - exec_local: test "$${shutdown_vm_immediately}" == "false" -a "$${vm_cleanup_section}" == "setup" + - group: + - exec_local: *1 + - exec_local: *2 + - on_export_clean: + - test: + - exec_local: test "$${shutdown_vm_immediately}" == "false" -a "$${vm_cleanup_section}" == "export" + - group: + - exec_local: *1 + - exec_local: *2 + - exec_local: | + if [ "$${shutdown_vm_immediately}" == "true" ]; then + echo "Qemu VM shutdown: immediately" + else + echo "Qemu VM shutdown: in $${vm_cleanup_section} section cleaning" + fi + - exec_local: | + if [ -r $${qemu_pidfile} ] && pgrep -F $${qemu_pidfile} > /dev/null; then + echo "Qemu pid file found, with process running: killing it !" 1>&2 + pkill -F $${qemu_pidfile} + sleep 0.5 + if pgrep -F $${qemu_pidfile} > /dev/null; then + echo "Failed to kill qemu process." 1>&2 + exit 1 + fi + fi + - exec_local: | + echo "Starting qemu..." + if [ "$${qemu_enable_kvm}" == "true" ] && (/usr/sbin/kvm-ok > /dev/null || egrep '(vmx|svm)' /proc/cpuinfo > /dev/null) ; then # print warning if /usr/sbin/kvm-ok is not installed + if [ "$${qemu_arch}" == "aarch64" ]; then + ENABLE_KVM="-enable-kvm -accel kvm -machine virt,gic-version=host,accel=kvm:tcg -cpu host" + #ENABLE_KVM="-global virtio-blk-pci.scsi=off -no-user-config -enable-fips -machine virt,gic-version=host,accel=kvm:tcg -cpu host -rtc driftfix=slew -object rng-random,filename=/dev/urandom,id=rng0 -device virtio-rng-pci,rng=rng0" + elif [ "$${qemu_arch}" == "ppc64" ]; then + ENABLE_KVM="-enable-kvm -accel kvm -machine pseries,accel=kvm:tcg -cpu host" + else #X86_64 + ENABLE_KVM="-enable-kvm -cpu host" + fi + BOOT_TIMEOUT=$${boot_timeout} + else + echo "No KVM acceleration used" + BOOT_TIMEOUT=$(($${boot_timeout}*2)) + fi + if [ -f "vm_state_to_load.txt" ] + then + SAVED_STATE="$(< vm_state_to_load.txt)" + LOADVM="-loadvm $SAVED_STATE" + rm -f vm_state_to_load.txt + fi + if [ "$${debug}" == "true" ]; then + VNC_OPT="" + else + # Find empty VNC port + VNC_PORT=$(( $(__find_free_port 5900 5910) - 5900 )) + echo "VNC port: $VNC_PORT" + VNC_OPT="-vnc :$VNC_PORT" + fi + if [ -n "$${telnet_port}" ]; then + SERIAL_TELNET="telnet:localhost:$${telnet_port},server" + fi + # Select disk + QEMU_DRIVES="-drive file=$${image_disk}.$${image_format},cache=$${disk_cache},media=disk,if=virtio,id=drive0" + QEMU_BOOT= + QEMU_APPEND_CMDLINE= + if [ "$${qemu_uefi}" == "true" ]; then + if [ ! -f $${kameleon_cwd}/qemu_uefi_vars.fd ]; then + cp $${qemu_uefi_vars_path} $${kameleon_cwd}/qemu_uefi_vars.fd + fi + QEMU_BOOT="-drive if=pflash,format=raw,readonly,file=$${qemu_uefi_code_path} -drive if=pflash,format=raw,file=$${kameleon_cwd}/qemu_uefi_vars.fd" + fi + if [ -n "$${qemu_iso_path}" ]; then + QEMU_DRIVES="-drive file=$${qemu_iso_path},readonly,media=cdrom $QEMU_DRIVES" + if [ "$${qemu_iso_boot}" == "true" ]; then + QEMU_BOOT="$QEMU_BOOT -boot order=d" + fi + elif [ -n "$${qemu_kernel_path}" ]; then + QEMU_BOOT="$QEMU_BOOT -kernel $${qemu_kernel_path}" + if [ -n "$${qemu_initrd_path}" ]; then + QEMU_BOOT="$QEMU_BOOT -initrd $${qemu_initrd_path}" + fi + if [ -n "$${qemu_append_cmdline}" ]; then + QEMU_APPEND_CMDLINE="$${qemu_append_cmdline}" + QEMU_APPEND_CMDLINE=${QEMU_APPEND_CMDLINE//%LOCAL_IP%/$${local_ip}} + QEMU_APPEND_CMDLINE=${QEMU_APPEND_CMDLINE//%HTTP_PORT%/$HTTP_PORT} + fi + fi + if [ -n "$${qemu_netdev_user_options}" ]; then + QEMU_NETDEV_USER_OPTIONS=",$${qemu_netdev_user_options}" + fi + if [ "$${no_reboot}" == "true" ]; then + NO_REBOOT="-no-reboot" + fi + if [ -n "${SSH_FWD_PORT}" ]; then + HOSTFWD=",hostfwd=tcp::${SSH_FWD_PORT}-:22" + fi + qemu-system-$${qemu_arch} $ENABLE_KVM -smp $${qemu_cpus} -m $${qemu_memory_size} -rtc base=localtime \ + -net nic,model=virtio -net user${QEMU_NETDEV_USER_OPTIONS}${HOSTFWD} \ + $QEMU_DRIVES \ + -monitor unix:$${qemu_monitor_socket},server,nowait -pidfile $${qemu_pidfile} -daemonize \ + $QEMU_BOOT ${QEMU_APPEND_CMDLINE:+-append "$QEMU_APPEND_CMDLINE"} $NO_REBOOT \ + $VNC_OPT $SERIAL_TELNET\ + $LOADVM + - exec_local: | + VM_AVAILABLE=0 + if [ "$${vm_expected_service}" == "ssh" ]; then + TIMEOUT=$(( $(date +%s) + $BOOT_TIMEOUT )) + until timeout 5 ssh -q -F $${ssh_config_file} -o ConnectionAttempts=1 $${kameleon_recipe_name} -t true && VM_AVAILABLE=1 || [ $(date +%s) -gt $TIMEOUT ]; + do + echo -en "\rWaiting for SSH to become available in VM for out_context...($(( TIMEOUT - $(date +%s) ))s)" + sleep 1 + done + echo + else + TIMEOUT=$(( $(date +%s) + $BOOT_TIMEOUT )) + until timeout 1 [ $(date +%s) -gt $TIMEOUT ]; + do + echo -en "\rWaiting for VM to become available : ($(( TIMEOUT - $(date +%s) ))s)" + sleep 1 + done + echo + VM_AVAILABLE=1 + fi + - rescue: + - exec_local: test $VM_AVAILABLE -eq 1 + - breakpoint: | + Failed to get VM up and running (expected service: $${vm_expected_service}). Please verify the VM successfully booted with a vnc client. + - test: + - exec_local: test -e "$${qemu_sendkeys_commands}" -a -s "$${qemu_sendkeys_commands}" + - exec_local: | + echo "Sending keyboard commands to the VM: $${qemu_sendkeys_commands}" + echo "(Local httpd server url: http://$${local_ip}:$HTTP_PORT)" + ruby $${qemu_sendkeys_script} -d 0.05 "$(sed -e s/%LOCAL_IP%/$${local_ip}/g -e s/%HTTP_PORT%/$HTTP_PORT/g $${qemu_sendkeys_commands})" | $${socat_monitor} > /dev/null + - exec_local: echo "No keyboard commands to send" + +- shutdown_vm: + - on_checkpoint: redo + - on_clean: + - test: + - exec_local: test "$${shutdown_vm_immediately}" == "true" + - exec_local: *2 + - test: + - exec_local: test "$${shutdown_vm_immediately}" == "true" + - exec_local: *1 |