From 1a5d20fa2f30bdf796481e268fa0b798c8092655 Mon Sep 17 00:00:00 2001 From: Daniel Horak Date: Mon, 29 Jan 2024 13:52:21 +0100 Subject: [PATCH 1/3] move connection to helper node to BAREMETALBASE - re-try the connection in case of failure Signed-off-by: Daniel Horak --- ocs_ci/deployment/baremetal.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/ocs_ci/deployment/baremetal.py b/ocs_ci/deployment/baremetal.py index 920e772006a..045be675ab4 100644 --- a/ocs_ci/deployment/baremetal.py +++ b/ocs_ci/deployment/baremetal.py @@ -10,6 +10,7 @@ import yaml import requests from semantic_version import Version +import socket from .flexy import FlexyBaremetalPSI from ocs_ci.utility import psiutils, aws, version @@ -75,6 +76,22 @@ def deploy_prereq(self): result == constants.BM_STATUS_RESPONSE_UPDATED ), "Failed to update request" + self.connect_to_helper_node() + + # the VM hosting the httpd, tftp and dhcp services might be just started and it might take some time to + # propagate the DDNS name, if used, so re-trying this function for 20 minutes + @retry((TimeoutError, socket.gaierror), tries=10, delay=120, backoff=1) + def connect_to_helper_node(self): + """ + Create connection to helper node hosting httpd, tftp and dhcp services for PXE boot + """ + self.host = self.bm_config["bm_httpd_server"] + self.user = self.bm_config["bm_httpd_server_user"] + self.private_key = os.path.expanduser(config.DEPLOYMENT["ssh_key_private"]) + + # wait till the server is up and running + self.helper_node_handler = Connection(self.host, self.user, self.private_key) + def check_bm_status_exist(self): """ Check if BM Cluster already exist @@ -177,13 +194,6 @@ def deploy_prereq(self): config.ENV_DATA.get("cluster_path"), constants.WORKER_IGN ) - self.host = self.bm_config["bm_httpd_server"] - self.user = self.bm_config["bm_httpd_server_user"] - self.private_key = os.path.expanduser(config.DEPLOYMENT["ssh_key_private"]) - - self.helper_node_handler = Connection( - self.host, self.user, self.private_key - ) cmd = f"rm -rf {self.bm_config['bm_path_to_upload']}" logger.info(self.helper_node_handler.exec_cmd(cmd=cmd)) cmd = f"mkdir -m 755 {self.bm_config['bm_path_to_upload']}" From ebdf0a25730e1fb22a854b4070a599ffabc469f0 Mon Sep 17 00:00:00 2001 From: Daniel Horak Date: Mon, 22 Jan 2024 08:56:17 +0100 Subject: [PATCH 2/3] add upload_file method to connection module Signed-off-by: Daniel Horak --- ocs_ci/utility/connection.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ocs_ci/utility/connection.py b/ocs_ci/utility/connection.py index 08f77757509..ddc013aaa45 100644 --- a/ocs_ci/utility/connection.py +++ b/ocs_ci/utility/connection.py @@ -129,3 +129,17 @@ def exec_cmd(self, cmd): ) logger.debug(f"stderr: {stderr}") return (retcode, stdout, stderr) + + def upload_file(self, localpath, remotepath): + """ + Upload a file to remote server + + Args: + localpath (str): Local file to upload + remotepath (str): Target path on the remote server. Filename should be included + + """ + sftp = self.client.open_sftp() + logger.info(f"uploading {localpath} to {self.user}@{self.host}:{remotepath}") + sftp.put(localpath, remotepath) + sftp.close() From e3fff5cb06c412695bd82d8d969a762c4e2573fc Mon Sep 17 00:00:00 2001 From: Daniel Horak Date: Wed, 7 Feb 2024 15:32:20 +0100 Subject: [PATCH 3/3] BM UPI deployment: update PXE boot server config - move dnsmasq configuraton to separated methods - use /tftpboot/ directory provided by syslinux-tftpboot package Signed-off-by: Daniel Horak --- ocs_ci/deployment/baremetal.py | 206 ++++++++++++------ ocs_ci/ocs/constants.py | 6 +- .../ocp-deployment/dnsmasq.common.conf | 5 - .../ocp-deployment/dnsmasq.common.conf.j2 | 13 ++ .../templates/ocp-deployment/dnsmasq.pxe.conf | 3 - .../ocp-deployment/dnsmasq.pxe.conf.j2 | 3 + 6 files changed, 165 insertions(+), 71 deletions(-) delete mode 100644 ocs_ci/templates/ocp-deployment/dnsmasq.common.conf create mode 100644 ocs_ci/templates/ocp-deployment/dnsmasq.common.conf.j2 delete mode 100644 ocs_ci/templates/ocp-deployment/dnsmasq.pxe.conf create mode 100644 ocs_ci/templates/ocp-deployment/dnsmasq.pxe.conf.j2 diff --git a/ocs_ci/deployment/baremetal.py b/ocs_ci/deployment/baremetal.py index 045be675ab4..87ac46f59bc 100644 --- a/ocs_ci/deployment/baremetal.py +++ b/ocs_ci/deployment/baremetal.py @@ -155,6 +155,138 @@ def destroy(self, log_level=""): result == constants.BM_STATUS_RESPONSE_UPDATED ), "Failed to update request" + def configure_dnsmasq_on_helper_vm(self): + """ + Install and configure dnsmasq and other required packages + for DHCP and PXE boot server on helper VM + """ + # Install Required packages + cmd = "yum install dnsmasq syslinux-tftpboot -y" + assert self.helper_node_handler.exec_cmd( + cmd=cmd + ), "Failed to install required packages" + + # Enable dnsmasq service on boot + cmd = "systemctl enable dnsmasq" + assert self.helper_node_handler.exec_cmd( + cmd=cmd + ), "Failed to Enable dnsmasq service" + + # Create pxelinux.cfg directory + cmd = f"mkdir -m 755 {self.bm_config['bm_tftp_base_dir']}/pxelinux.cfg" + assert self.helper_node_handler.exec_cmd( + cmd=cmd + ), "Failed to create required folder" + + if self.bm_config.get("bm_dnsmasq_common_config"): + self.configure_dnsmasq_common_config() + + if self.bm_config.get("bm_dnsmasq_pxe_config"): + self.configure_dnsmasq_pxe_config() + + if self.bm_config.get("bm_dnsmasq_hosts_config"): + self.configure_dnsmasq_hosts_config() + + self.restart_dnsmasq_service_on_helper_vm() + + def configure_dnsmasq_common_config(self): + """ + Prepare common configuration for dnsmasq + """ + # create dnsmasq common configuration + _templating = Templating() + template_data = { + "interface": self.bm_config["bm_dnsmasq_interface"], + "dhcp_range": self.bm_config["bm_dnsmasq_dhcp_range"], + "dhcp_options": self.bm_config["bm_dnsmasq_dhcp_options"], + } + common_config = _templating.render_template( + constants.DNSMASQ_COMMON_CONF_FILE_TEMPLATE, + template_data, + ) + common_config_temp_file = tempfile.NamedTemporaryFile( + mode="w+", prefix="dnsmasq.common", suffix=".conf", delete=False + ) + with open(common_config_temp_file.name, "w") as t_file: + t_file.writelines(common_config) + self.helper_node_handler.upload_file( + common_config_temp_file.name, + "/etc/dnsmasq.d/dnsmasq.common.conf", + ) + + def configure_dnsmasq_pxe_config(self): + """ + Prepare PXE configuration for dnsmasq + """ + # create dnsmasq PXE configuration + _templating = Templating() + template_data = {"tftp_root": self.bm_config["bm_tftp_base_dir"]} + pxe_config = _templating.render_template( + constants.DNSMASQ_PXE_CONF_FILE_TEMPLATE, + template_data, + ) + pxe_config_temp_file = tempfile.NamedTemporaryFile( + mode="w+", prefix="dnsmasq.pxe", suffix=".conf", delete=False + ) + with open(pxe_config_temp_file.name, "w") as t_file: + t_file.writelines(pxe_config) + self.helper_node_handler.upload_file( + pxe_config_temp_file.name, + "/etc/dnsmasq.d/dnsmasq.pxe.conf", + ) + + def configure_dnsmasq_hosts_config(self): + """ + prepare hosts configuration for dnsmasq dhcp + """ + hosts_config = "" + for machine in self.srv_details: + # which network is used for provisioning (public|private) + provisioning_network = self.bm_config["bm_provisioning_network"] + mac = self.srv_details[machine][f"{provisioning_network}_mac"] + ip = self.srv_details[machine][f"{provisioning_network}_ip"] + hostname = machine.split(".")[0] + hosts_config += f"dhcp-host={mac},{ip},{hostname},1h\n" + temp_file = tempfile.NamedTemporaryFile( + mode="w+", prefix="dnsmasq.hosts", suffix=".conf", delete=False + ) + with open(temp_file.name, "w") as t_file: + t_file.writelines(hosts_config) + self.helper_node_handler.upload_file( + temp_file.name, + f"/etc/dnsmasq.d/dnsmasq.hosts.{self.bm_config['env_name']}.conf", + ) + + def start_dnsmasq_service_on_helper_vm(self): + """ + Start dnsmasq service providing DHCP and TFTP services for UPI deployment + """ + # Starting dnsmasq service + cmd = "systemctl start dnsmasq" + assert self.helper_node_handler.exec_cmd( + cmd=cmd + ), "Failed to Start dnsmasq service" + + def stop_dnsmasq_service_on_helper_vm(self): + """ + Stop dnsmasq service providing DHCP and TFTP services for UPI deployment + """ + # Stopping dnsmasq service + cmd = "systemctl stop dnsmasq" + assert self.helper_node_handler.exec_cmd( + cmd=cmd + ), "Failed to Stop dnsmasq service" + + def restart_dnsmasq_service_on_helper_vm(self): + """ + Restart dnsmasq service providing DHCP and TFTP services for UPI deployment + """ + # Restarting dnsmasq service + cmd = "systemctl restart dnsmasq" + assert self.helper_node_handler.exec_cmd( + cmd=cmd + ), "Failed to restart dnsmasq service" + class BAREMETALUPI(BAREMETALBASE): """ @@ -216,62 +348,20 @@ def deploy_prereq(self): key_file=self.private_key, ) + self.configure_dnsmasq_on_helper_vm() + # Perform Cleanup for stale entry's - cmd = f"rm -rf {self.bm_config['bm_tftp_base_dir']}" + cmd = f"rm -rf {self.bm_config['bm_tftp_base_dir']}/upi" assert self.helper_node_handler.exec_cmd(cmd=cmd), "Failed to Delete folder" - # Installing Required packages - cmd = "yum install dnsmasq -y" - assert self.helper_node_handler.exec_cmd( - cmd=cmd - ), "Failed to install required package" - - # Enable dnsmasq service on boot - cmd = "systemctl enable dnsmasq" - assert self.helper_node_handler.exec_cmd( - cmd=cmd - ), "Failed to Enable dnsmasq service" - - # Starting dnsmasq service - cmd = "systemctl start dnsmasq" - assert self.helper_node_handler.exec_cmd( - cmd=cmd - ), "Failed to Start dnsmasq service" - - cmd = f"mkdir -m 755 -p {self.bm_config['bm_tftp_base_dir']}" - assert self.helper_node_handler.exec_cmd( - cmd=cmd - ), "Failed to create required folder" - - cmd = f"mkdir -m 755 -p {self.bm_config['bm_tftp_base_dir']}ocs4qe" - assert self.helper_node_handler.exec_cmd( - cmd=cmd - ), "Failed to create required folder" - - cmd = ( - f"mkdir -m 755 -p {self.bm_config['bm_tftp_base_dir']}ocs4qe/baremetal" - ) + # prepare pxe boot directory for UPI deployment + cmd = f"mkdir -m 755 -p {self.bm_config['bm_tftp_base_dir']}/upi" assert self.helper_node_handler.exec_cmd( cmd=cmd ), "Failed to create required folder" - # Install syslinux - cmd = "yum install syslinux -y" - assert self.helper_node_handler.exec_cmd( - cmd=cmd - ), "Failed to install required package" + self.restart_dnsmasq_service_on_helper_vm() - # Copy syslinux files to the tftp path - cmd = f"cp -ar /usr/share/syslinux/* {self.bm_config['bm_tftp_dir']}" - assert self.helper_node_handler.exec_cmd( - cmd=cmd - ), "Failed to Copy required files" - - # Restarting dnsmasq service - cmd = "systemctl restart dnsmasq" - assert self.helper_node_handler.exec_cmd( - cmd=cmd - ), "Failed to restart dnsmasq service" with open(constants.RHCOS_IMAGES_FILE) as file_stream: rhcos_images_file = yaml.safe_load(file_stream) ocp_version = get_ocp_version() @@ -296,7 +386,7 @@ def deploy_prereq(self): if check_for_rhcos_images(initramfs_image_path): cmd = ( "wget -O " - f"{self.bm_config['bm_tftp_dir']}" + f"{self.bm_config['bm_tftp_base_dir']}/upi" "/rhcos-installer-initramfs.x86_64.img " f"{initramfs_image_path}" ) @@ -317,7 +407,7 @@ def deploy_prereq(self): if check_for_rhcos_images(kernel_image_path): cmd = ( "wget -O " - f"{self.bm_config['bm_tftp_dir']}" + f"{self.bm_config['bm_tftp_base_dir']}/upi" "/rhcos-installer-kernel-x86_64 " f"{kernel_image_path}" ) @@ -370,12 +460,6 @@ def deploy_prereq(self): else: raise RhcosImageNotFound - # Create pxelinux.cfg directory - cmd = f"mkdir -m 755 {self.bm_config['bm_tftp_dir']}/pxelinux.cfg" - assert self.helper_node_handler.exec_cmd( - cmd=cmd - ), "Failed to create required folder" - def deploy(self, log_cli_level="DEBUG"): """ Deploy @@ -398,13 +482,13 @@ def deploy(self, log_cli_level="DEBUG"): upload_file( server=self.host, localpath=pxe_file_path, - remotepath=f"{self.bm_config['bm_tftp_dir']}" + remotepath=f"{self.bm_config['bm_tftp_base_dir']}" f"/pxelinux.cfg/01-{self.srv_details[machine]['private_mac'].replace(':', '-')}", user=self.user, key_file=self.private_key, ) # Applying Permission - cmd = f"chmod 755 -R {self.bm_config['bm_tftp_dir']}" + cmd = f"chmod 755 -R {self.bm_config['bm_tftp_base_dir']}" self.helper_node_handler.exec_cmd(cmd=cmd) # Applying Permission @@ -673,9 +757,9 @@ def create_pxe_files(self, ocp_version, role, disk_path): LABEL pxeboot MENU LABEL PXE Boot MENU DEFAULT - KERNEL rhcos-installer-kernel-x86_64 - APPEND ip=enp1s0f0:dhcp ip=enp1s0f1:dhcp rd.neednet=1 initrd=rhcos-installer-initramfs.x86_64.img console=ttyS0 \ -console=tty0 coreos.inst.install_dev=/dev/disk/by-id/{disk_path} {bm_metal_loc} \ + KERNEL upi/rhcos-installer-kernel-x86_64 + APPEND ip=enp1s0f0:dhcp ip=enp1s0f1:dhcp rd.neednet=1 initrd=upi/rhcos-installer-initramfs.x86_64.img \ +console=ttyS0 console=tty0 coreos.inst.install_dev=/dev/disk/by-id/{disk_path} {bm_metal_loc} \ coreos.inst.ignition_url={bm_install_files_loc}{role}.ign \ {extra_data} LABEL disk0 diff --git a/ocs_ci/ocs/constants.py b/ocs_ci/ocs/constants.py index 67ba7373883..c583b11bcbc 100644 --- a/ocs_ci/ocs/constants.py +++ b/ocs_ci/ocs/constants.py @@ -1848,8 +1848,10 @@ AWS_VOL_MON_IOPS = 3000 # Bare Metal constants -PXE_CONF_FILE = os.path.join(TEMPLATE_DIR, "ocp-deployment", "dnsmasq.pxe.conf") -COMMON_CONF_FILE = os.path.join(TEMPLATE_DIR, "ocp-deployment", "dnsmasq.common.conf") +DNSMASQ_PXE_CONF_FILE_TEMPLATE = os.path.join("ocp-deployment", "dnsmasq.pxe.conf.j2") +DNSMASQ_COMMON_CONF_FILE_TEMPLATE = os.path.join( + "ocp-deployment", "dnsmasq.common.conf.j2" +) RHCOS_IMAGES_FILE = os.path.join(TEMPLATE_DIR, "ocp-deployment", "rhcos_images.yaml") PXE_FILE = os.path.join(TEMPLATE_DIR, "baremetal-pxefile") coreos_url_prefix = "https://mirror.openshift.com/pub/openshift-v4/dependencies/rhcos" diff --git a/ocs_ci/templates/ocp-deployment/dnsmasq.common.conf b/ocs_ci/templates/ocp-deployment/dnsmasq.common.conf deleted file mode 100644 index 4913f3a15a6..00000000000 --- a/ocs_ci/templates/ocp-deployment/dnsmasq.common.conf +++ /dev/null @@ -1,5 +0,0 @@ -interface=* -except-interface=lo -bind-dynamic -log-queries -log-dhcp diff --git a/ocs_ci/templates/ocp-deployment/dnsmasq.common.conf.j2 b/ocs_ci/templates/ocp-deployment/dnsmasq.common.conf.j2 new file mode 100644 index 00000000000..6de08d31717 --- /dev/null +++ b/ocs_ci/templates/ocp-deployment/dnsmasq.common.conf.j2 @@ -0,0 +1,13 @@ +interface={{ interface }} +no-resolv +log-queries +log-dhcp +dhcp-range={{ dhcp_range }} +#dhcp-authoritative + +{% if dhcp_options is defined %} +{% for item in dhcp_options %} +dhcp-option={{ item }} + +{% endfor %} +{% endif %} diff --git a/ocs_ci/templates/ocp-deployment/dnsmasq.pxe.conf b/ocs_ci/templates/ocp-deployment/dnsmasq.pxe.conf deleted file mode 100644 index 4139abca5d1..00000000000 --- a/ocs_ci/templates/ocp-deployment/dnsmasq.pxe.conf +++ /dev/null @@ -1,3 +0,0 @@ -dhcp-boot=pxelinux.0 -enable-tftp -tftp-root=/var/lib/tftpboot/ocs4qe/baremetal/ diff --git a/ocs_ci/templates/ocp-deployment/dnsmasq.pxe.conf.j2 b/ocs_ci/templates/ocp-deployment/dnsmasq.pxe.conf.j2 new file mode 100644 index 00000000000..d3e9d840e78 --- /dev/null +++ b/ocs_ci/templates/ocp-deployment/dnsmasq.pxe.conf.j2 @@ -0,0 +1,3 @@ +dhcp-boot=pxelinux.0 +enable-tftp +tftp-root={{ tftp_root }}