Skip to content

Commit

Permalink
Merge pull request red-hat-storage#9344 from dahorak/bm-upi-deploymen…
Browse files Browse the repository at this point in the history
…t-dnsmasq-configuration

BM UPI deployment - dnsmasq configuration
  • Loading branch information
dahorak authored Mar 11, 2024
2 parents 9399227 + e3fff5c commit 6a221a9
Show file tree
Hide file tree
Showing 7 changed files with 196 additions and 78 deletions.
230 changes: 162 additions & 68 deletions ocs_ci/deployment/baremetal.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -138,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):
"""
Expand Down Expand Up @@ -177,13 +326,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']}"
Expand All @@ -206,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"

# 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"
self.restart_dnsmasq_service_on_helper_vm()

# 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()
Expand All @@ -286,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}"
)
Expand All @@ -307,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}"
)
Expand Down Expand Up @@ -360,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
Expand All @@ -388,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
Expand Down Expand Up @@ -663,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
Expand Down
6 changes: 4 additions & 2 deletions ocs_ci/ocs/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -1855,8 +1855,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"
Expand Down
5 changes: 0 additions & 5 deletions ocs_ci/templates/ocp-deployment/dnsmasq.common.conf

This file was deleted.

13 changes: 13 additions & 0 deletions ocs_ci/templates/ocp-deployment/dnsmasq.common.conf.j2
Original file line number Diff line number Diff line change
@@ -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 %}
3 changes: 0 additions & 3 deletions ocs_ci/templates/ocp-deployment/dnsmasq.pxe.conf

This file was deleted.

3 changes: 3 additions & 0 deletions ocs_ci/templates/ocp-deployment/dnsmasq.pxe.conf.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dhcp-boot=pxelinux.0
enable-tftp
tftp-root={{ tftp_root }}
14 changes: 14 additions & 0 deletions ocs_ci/utility/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

0 comments on commit 6a221a9

Please sign in to comment.