Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding kvm_script folder example for fakefish #17

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ build-hpe-gen9:
build-custom: pre-reqs
podman build . -f custom_scripts/Containerfile -t $(IMAGE_URL):$(TAG) --label org.opencontainers.image.authors"=$(AUTHOR)"

build-kvm_scripts:
podman build . -f kvm_scripts/Containerfile -t $(IMAGE_URL):$(TAG) --label org.opencontainers.image.authors"=$(AUTHOR)"

.SILENT:
pre-reqs:
if [ $(shell find custom_scripts/ -name "*.sh" | grep -Ec "mountcd.sh|poweroff.sh|poweron.sh|unmountcd.sh|bootfromcdonce.sh") -ne 5 ];then echo 'Missing custom scripts or bad naming';exit 1;fi
Expand Down
8 changes: 8 additions & 0 deletions app/fakefish.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,16 @@ def get_credentials(flask_request):
return username, password

def set_env_vars(bmc_endpoint, username, password):
global vm_name
my_env = os.environ.copy()
my_env["BMC_ENDPOINT"] = bmc_endpoint
my_env["BMC_USERNAME"] = username
my_env["BMC_PASSWORD"] = password
try:
my_env["VM_NAME"] = vm_name
except:
pass

return my_env

def run(port, debug, tls_mode, cert_file, key_file):
Expand All @@ -190,6 +196,7 @@ def run(port, debug, tls_mode, cert_file, key_file):
parser.add_argument('--key-file', type=str, default='./cert.key', help='Path to the certificate private key file. (default: %(default)s)')
parser.add_argument('-r', '--remote-bmc', type=str, required=True, help='The BMC IP this FakeFish instance will connect to. e.g: 192.168.1.10')
parser.add_argument('-p','--listen-port', type=int, required=False, default=9000, help='The port where this FakeFish instance will listen for connections.')
parser.add_argument('--vm-name', type=str, required=False, help='For KVM Scripts this is the VM domain name in virsh.')
parser.add_argument('--debug', action='store_true')
args = parser.parse_args()

Expand All @@ -199,6 +206,7 @@ def run(port, debug, tls_mode, cert_file, key_file):
tls_mode = args.tls_mode
cert_file = args.cert_file
key_file = args.key_file
vm_name = args.vm_name

inserted = False
image_url = ''
Expand Down
28 changes: 28 additions & 0 deletions kvm_scripts/Containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
FROM registry.fedoraproject.org/fedora:35
MAINTAINER Mario Vazquez <[email protected]>

RUN set -x && \
dnf -y update && \
dnf install -y python3 python3-flask python3-requests python3-pyOpenSSL libvirt-client virt-install openssh-clients && \
dnf clean all && \
rm -rf /var/cache/yum /var/cache/dnf

RUN mkdir -p /opt/fakefish/

# The stars in the command below will only copy those files if they exist
COPY app/fakefish.py app/cert.pem* app/cert.key* /opt/fakefish/

ADD app/templates /opt/fakefish/templates
ADD kvm_scripts /opt/fakefish/custom_scripts

WORKDIR /opt/fakefish/

RUN mkdir /opt/fakefish/.ssh && \
echo "IdentityFile /opt/fakefish/.ssh/id_rsa" >> /opt/fakefish/.ssh/config && \
echo "PubKeyAuthentication yes" >> /opt/fakefish/.ssh/config && \
echo "StrictHostKeyChecking no" >> /opt/fakefish/.ssh/config && \
chown -R 1000 /opt/fakefish/

USER 1000

ENTRYPOINT ["/usr/bin/python3", "-u", "/opt/fakefish/fakefish.py"]
39 changes: 39 additions & 0 deletions kvm_scripts/bootfromcdonce.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/bin/bash

#### IMPORTANT: This script is only meant to show how to implement required scripts to make custom hardware compatible with FakeFish. Dell hardware is supported by the `idrac-virtualmedia` provider in Metal3.
#### This script has to set the server's boot to once from cd and return 0 if operation succeeded, 1 otherwise
#### You will get the following vars as environment vars
#### BMC_ENDPOINT - Has the BMC IP
#### BMC_USERNAME - Has the username configured in the BMH/InstallConfig and that is used to access BMC_ENDPOINT
#### BMC_PASSWORD - Has the password configured in the BMH/InstallConfig and that is used to access BMC_ENDPOINT
echo "Boot from CD Once Script"

SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
source ${SCRIPTPATH}/common.sh

# Check if VM exists
vm_status=$(get_vm_status)
if [ -z "${vm_status}" ]; then
echo "VM ${VM_NAME} does not exist"
exit 1
fi

# Get cdrom drive
cdrom_drive=$(get_cdrom_drive)

if [ -z "${cdrom_drive}" ]; then
echo "No cdrom drive found"
exit 1
fi

#poweroff VM
destroy_vm
wait_until_vm_is_stopped

virt-xml -c qemu+ssh://${BMC_USERNAME}@${BMC_ENDPOINT}/system ${VM_NAME} --edit target=${cdrom_drive} --disk="boot_order=1" --no-define --start
if [ $? -ne 0 ]; then
exit 1
else
exit 0
fi

197 changes: 197 additions & 0 deletions kvm_scripts/common.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
function get_vm_status() {
vm_status=$(virsh -c qemu+ssh://${BMC_USERNAME}@${BMC_ENDPOINT}/system list --all | grep ${VM_NAME} | awk '{ print $3}')
if [ $? -eq 0 ]; then
echo ${vm_status}
else
echo "Failed to get VM ${VM_NAME} status"
exit 1
fi
}

function power_on_vm() {
vm_status=$(get_vm_status)

if [ -z "${vm_status}" ]; then
echo "VM ${VM_NAME} does not exist or failed to get status"
exit 1
fi

if [ "${vm_status}" == "running" ]; then
echo "VM ${VM_NAME} is already running"
return 0
fi

virsh -c qemu+ssh://${BMC_USERNAME}@${BMC_ENDPOINT}/system start ${VM_NAME}
if [ $? -eq 0 ]; then
echo "VM ${VM_NAME} powered on successfully"
return 0
else
echo "Failed to power on VM ${VM_NAME}"
exit 1
fi
}

function power_off_vm() {
vm_status=$(get_vm_status)

if [ -z "${vm_status}" ]; then
echo "VM ${VM_NAME} does not exist or failed to get status"
exit 1
fi

if [ "${vm_status}" == "shut" ]; then
echo "VM ${VM_NAME} is already powered off"
return 0
fi

virsh -c qemu+ssh://${BMC_USERNAME}@${BMC_ENDPOINT}/system shutdown ${VM_NAME} --mode acpi
if [ $? -eq 0 ]; then
echo "VM ${VM_NAME} powered off successfully"
return 0
else
echo "Failed to power off VM ${VM_NAME}"
exit 1
fi
}

function reboot_vm() {
vm_status=$(get_vm_status)

if [ -z "${vm_status}" ]; then
echo "VM ${VM_NAME} does not exist or failed to get status"
exit 1
fi

virsh -c qemu+ssh://${BMC_USERNAME}@${BMC_ENDPOINT}/system reboot ${VM_NAME} --mode acpi
if [ $? -eq 0 ]; then
echo "VM ${VM_NAME} rebooted successfully"
return 0
else
echo "Failed to reboot VM ${VM_NAME}"
exit 1
fi
}

function destroy_vm() {
echo "Destroying VM ${VM_NAME}"
vm_status=$(get_vm_status)

if [ -z "${vm_status}" ]; then
echo "VM ${VM_NAME} does not exist or failed to get status"
exit 1
fi

if [ "${vm_status}" == "shut" ]; then
echo "VM ${VM_NAME} is already powered off"
return 0
fi

virsh -c qemu+ssh://${BMC_USERNAME}@${BMC_ENDPOINT}/system destroy ${VM_NAME}
if [ $? -eq 0 ]; then
echo "VM ${VM_NAME} destroyed successfully"
return 0
else
echo "Failed to destroy VM ${VM_NAME}"
exit 1
fi
}


function wait_until_vm_is_running() {
MAX_RETRIES=15
TRIES=0
while true
do
vm_status=$(get_vm_status)
if [ "${vm_status}" == "running" ]; then
echo "VM ${VM_NAME} is running"
return 0
else
if [[ ${TRIES} -ge ${MAX_RETRIES} ]];then
echo "Failed to power on VM ${VM_NAME}"
exit 1
fi
TRIES=$((TRIES + 1))
echo "Failed to power on VM ${VM_NAME}. Checkng again in 10 seconds. Retry [${TRIES}/${MAX_RETRIES}]"
sleep 10
fi
done
}

function wait_until_vm_is_stopped() {
MAX_RETRIES=15
TRIES=0
while true
do
vm_status=$(get_vm_status)
if [ "${vm_status}" == "shut" ]; then
echo "VM ${VM_NAME} is powered off"
return 0
else
if [[ ${TRIES} -ge ${MAX_RETRIES} ]];then
echo "Failed to power off VM ${VM_NAME} gracefully within ${MAX_RETRIES} retries. Destroying VM ${VM_NAME}"
destroy_vm
fi
TRIES=$((TRIES + 1))
echo "VM ${VM_NAME} not yet powered off. Checking again in 10 seconds. Retry [${TRIES}/${MAX_RETRIES}]"
sleep 10
fi
done
}

function get_cdrom_drive(){
virsh -c qemu+ssh://${BMC_USERNAME}@${BMC_ENDPOINT}/system dumpxml ${VM_NAME} | grep -A7 "device='cdrom'" | sed -n "s/.*<target dev='\([^']*\)'.*/\1/p" | head -n 1
}

function remote_download_iso() {
ssh -t ${BMC_USERNAME}@${BMC_ENDPOINT} "rm /tmp/${VM_NAME}.iso"
ssh -t ${BMC_USERNAME}@${BMC_ENDPOINT} "curl -k -C - -o /tmp/${VM_NAME}.iso ${ISO}"
if [ $? -eq 0 ]; then
echo "Downloaded ${ISO_NAME} successfully"
echo "/tmp/${ISO_NAME}"
else
echo "Failed to download ${ISO_NAME}"
exit 1
fi
}

function mount_iso_in_cdrom() {
iso_name=${1}
cdrom_drive=${2}

virsh -c qemu+ssh://${BMC_USERNAME}@${BMC_ENDPOINT}/system change-media ${VM_NAME} --path ${cdrom_drive} --source ${iso_name} --config
if [ $? -eq 0 ]; then
echo "Mounted ${iso_name} successfully"
return 0
else
echo "Failed to mount ${iso_name}"
return 1
fi
}

function get_mounted_iso() {
mounted_iso=$(virsh -c qemu+ssh://${BMC_USERNAME}@${BMC_ENDPOINT}/system dumpxml ${VM_NAME} | grep -A7 "device='cdrom'" | sed -n "s/.*<source file='\([^']*\)'.*/\1/p" | head -n 1)
echo ${mounted_iso}
}

function unmount_iso_in_cdrom() {
cdrom_drive=${1}

mounted_iso=$(get_mounted_iso)
if [ -z "${mounted_iso}" ]; then
echo "No iso mounted"
return 0
fi

output_string=$(virsh -c qemu+ssh://${BMC_USERNAME}@${BMC_ENDPOINT}/system change-media ${VM_NAME} --path ${cdrom_drive} --eject --config 2>&1)
if [ $? -eq 0 ]; then
echo "Unmounted ${mounted_iso} successfully"
return 0
elif [[ ${output_string} == *"doesn't have media"* ]]; then
echo "Virsh claims media not mounted"
return 0
else
echo "Failed to unmount ${mounted_iso}"
return 1
fi
}
51 changes: 51 additions & 0 deletions kvm_scripts/mountcd.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/bin/bash

#### IMPORTANT: This script is only meant to show how to implement required scripts to make custom hardware compatible with FakeFish. Dell hardware is supported by the `idrac-virtualmedia` provider in Metal3.
#### This script has to mount the iso in the server's virtualmedia and return 0 if operation succeeded, 1 otherwise
#### Note: Iso image to mount will be received as the first argument ($1)
#### You will get the following vars as environment vars
#### BMC_ENDPOINT - Has the BMC IP
#### BMC_USERNAME - Has the username configured in the BMH/InstallConfig and that is used to access BMC_ENDPOINT
#### BMC_PASSWORD - Has the password configured in the BMH/InstallConfig and that is used to access BMC_ENDPOINT


ISO=${1}
SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
source ${SCRIPTPATH}/common.sh

echo "Mount CD Script"
echo "Called to mount ${ISO} on ${VM_NAME}"

#Get VM Status
vm_status=$(get_vm_status)

#Check if VM exists or Error
if [ -z "${vm_status}" ]; then
echo "VM ${VM_NAME} does not exist"
exit 1
fi

echo "Mount CD Script"
#Get cdrom drive
cdrom_drive=$(get_cdrom_drive)
if [ -z "${cdrom_drive}" ]; then
echo "No cdrom drive found"
exit 1
fi

#Unmount ISO
unmount_iso_in_cdrom ${cdrom_drive} || true
echo "Mount CD Script"

#Remote Download ISO
remote_download_iso
echo "Mount CD Script"

# Mount Image
mount_iso_in_cdrom /tmp/${VM_NAME}.iso ${cdrom_drive}
echo "Mount CD Script"
if [ $? -ne 0 ]; then
exit 1
else
exit 0
fi
Loading