Last active
December 1, 2025 19:30
-
-
Save ag4ve/2acea14d9f7a691023df8b8db1561b5b to your computer and use it in GitHub Desktop.
OCP/OKD deployment makefile
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| SHELL := /usr/bin/bash -eu -o pipefail | |
| .ONESHELL: | |
| .DEFAULT_GOAL := help | |
| # ============================================================================= | |
| # EXPECTED FILE LAYOUT | |
| # | |
| # project-root/ | |
| # Makefile # <--- this file | |
| # bin/ # created by prereqs/okd-download | |
| # assets/ # created by prereqs | |
| # clusters/ | |
| # hp-proliant/ | |
| # node.env # cluster-wide environment (this cluster) | |
| # nodes.mk # node inventory for this cluster | |
| # Makefile # optional stub: forwards to ../Makefile | |
| # dell-r740/ | |
| # node.env | |
| # nodes.mk | |
| # Makefile | |
| # | |
| # Typical usage: | |
| # # HP / OCP / IPv4 / iLO cluster: | |
| # sudo make -C clusters/hp-proliant all | |
| # | |
| # # Dell / OKD / IPv6 / DRAC cluster: | |
| # sudo make -C clusters/dell-r740 all | |
| # | |
| # The cluster-local Makefile (in clusters/<name>/Makefile) usually just runs: | |
| # $(MAKE) -f ../Makefile ENV_FILE=node.env NODES_FILE=nodes.mk MGMT_TYPE=... | |
| # | |
| # You can also run from project root: | |
| # sudo make ENV_FILE=clusters/hp-proliant/node.env \ | |
| # NODES_FILE=clusters/hp-proliant/nodes.mk \ | |
| # all | |
| # | |
| # ============================================================================= | |
| # FEATURE CHECKLIST | |
| # [x] nftables-only (no firewalld), exact-string teardown | |
| # [x] radvd (SLAAC+RDNSS, IPv6 mode) | |
| # [x] dnsmasq DHCPv6 with STATIC reservations (DUID/IAID, IPv6 mode) | |
| # [x] Pure iPXE (.ipxe) with MAC-based auto role selection from mapping files | |
| # [x] FCOS PXE artifacts via coreos-installer (kernel/initramfs/rootfs) | |
| # [x] Cluster assets (openshift-install/oc), distro-neutral via RELEASE_BASE_URL | |
| # [x] Authoritative DNS (BIND): forward api / *.apps + reverse ip6.arpa for /48 | |
| # [x] Zone generator from node.env (forward + reverse) | |
| # [x] Bootstrap node runs locally (KVM VM) on install host | |
| # [x] nftables rules for bootstrap phase (6443, 22623, 80, 443) + auto teardown | |
| # [x] Optional Cilium helpers (ENABLE_CILIUM=1) | |
| # [x] Backups + restore on teardown; all heredocs use <<- | |
| # [x] Node inventory (nodes.mk) with per-node: | |
| # - role (bootstrap/master/worker) | |
| # - PXE MAC | |
| # - install_dev (e.g. RAID virtual disk) | |
| # - optional management info (ilo/drac host/user) | |
| # [x] HP iLO helpers (raw + generic node-* interface) | |
| # [x] Dell DRAC helpers (raw + generic node-* interface) | |
| # [x] MGMT_TYPE=ilo|drac switch for node-level power/pxe recipes | |
| # [x] PXE discovery environment (FCOS live + SSH via Ignition) | |
| # [x] ipxe-discovery-maps target to point MACs at discovery boot | |
| # [x] raid-discovery target: SSH into discovery env, run lsblk, print *_install_dev lines | |
| # ============================================================================= | |
| # ----------------------------------------------------------------------------- | |
| # Cluster environment and node inventory | |
| # ----------------------------------------------------------------------------- | |
| # These are intended to be overridden when running in a cluster dir: | |
| # make -C clusters/<name> ENV_FILE=node.env NODES_FILE=nodes.mk ... | |
| # ----------------------------------------------------------------------------- | |
| ENV_FILE ?= ./node.env | |
| include $(ENV_FILE) | |
| export | |
| NODES_FILE ?= ./nodes.mk | |
| -include $(NODES_FILE) | |
| # ----------------------------------------------------------------------------- | |
| # Network / CNI / distro configuration | |
| # NETWORK_STACK : ipv6 | ipv4 | |
| # NETWORK_TYPE : OVNKubernetes | Other | |
| # ENABLE_CILIUM : 0 | 1 | |
| # DISTRO : okd | ocp (informational) | |
| # RELEASE_BASE_URL : base URL where openshift-install/oc tarballs are hosted | |
| # ----------------------------------------------------------------------------- | |
| NETWORK_STACK ?= ipv6 | |
| NETWORK_TYPE ?= OVNKubernetes | |
| ENABLE_CILIUM ?= 0 | |
| DISTRO ?= okd | |
| # RELEASE_BASE_URL must be set in node.env, e.g.: | |
| # For OCP: https://mirror.openshift.com/pub/openshift-v4/clients/ocp/latest | |
| # For OKD: https://github.com/okd-project/okd/releases/download/<release-tag> | |
| RELEASE_BASE_URL ?= | |
| # ----------------------------------------------------------------------------- | |
| # Paths & constants | |
| # ----------------------------------------------------------------------------- | |
| BIN_DIR := $(PWD)/bin | |
| ASSETS_DIR := $(PWD)/assets | |
| FCOS_DIR := $(ASSETS_DIR)/fcos | |
| HTTP_CLUSTER_DIR := $(HTTP_DIR) | |
| PXE_HTTP_DIR := $(HTTP_CLUSTER_DIR)/pxe | |
| # Provisioning host URL prefix (handles IPv4 vs IPv6 syntax) | |
| PROVISION_URL_PREFIX_v6 = http://[$(PROVISION_HOST)] | |
| PROVISION_URL_PREFIX_v4 = http://$(PROVISION_HOST) | |
| PROVISION_URL_PREFIX = $(if $(filter $(NETWORK_STACK),ipv6),$(PROVISION_URL_PREFIX_v6),$(PROVISION_URL_PREFIX_v4)) | |
| # nftables | |
| NFT_MAIN_CONF := /etc/nftables.conf | |
| NFT_CLUSTER_FILE := /etc/nftables.d/okd-nat66.nft | |
| NFT_SVC_FILE := /etc/nftables.d/okd-svc.nft | |
| NFT_CLUSTER_TABLE := okd_nat66 | |
| NFT_SVC_TABLE := okd_svc | |
| # dnsmasq (DHCPv6 + iPXE HTTP bootfile-url) | |
| DNSMASQ_FILE := /etc/dnsmasq.d/okd-pxe.conf | |
| # radvd | |
| RADVD_FILE := /etc/radvd.conf | |
| # BIND/named | |
| NAMED_CONF := /etc/named.conf | |
| NAMED_DIR := /var/named | |
| FWD_ZONE_FILE := $(NAMED_DIR)/$(CLUSTER_NAME).$(BASE_DOMAIN).zone | |
| REV_ZONE_FILE := $(NAMED_DIR)/$(CLUSTER_NAME).$(BASE_DOMAIN).ip6.arpa.zone | |
| # Backups | |
| BACKUP_SUFFIX := .bak.okd | |
| NFT_MAIN_BAK := $(NFT_MAIN_CONF)$(BACKUP_SUFFIX) | |
| DNSMASQ_BAK := $(DNSMASQ_FILE)$(BACKUP_SUFFIX) | |
| RADVD_BAK := $(RADVD_FILE)$(BACKUP_SUFFIX) | |
| NFT_CLUSTER_BAK := $(NFT_CLUSTER_FILE)$(BACKUP_SUFFIX) | |
| NFT_SVC_BAK := $(NFT_SVC_FILE)$(BACKUP_SUFFIX) | |
| NAMED_CONF_BAK := $(NAMED_CONF)$(BACKUP_SUFFIX) | |
| FWD_ZONE_BAK := $(FWD_ZONE_FILE)$(BACKUP_SUFFIX) | |
| REV_ZONE_BAK := $(REV_ZONE_FILE)$(BACKUP_SUFFIX) | |
| # Bootstrap VM | |
| BOOTSTRAP_VM ?= okd-bootstrap | |
| # Management defaults | |
| MGMT_TYPE ?= ilo # ilo | drac | |
| ILO_DEFAULT_USER ?= Administrator | |
| DRAC_USER ?= root | |
| help: | |
| @echo "Targets:" | |
| @echo " prereqs - Install packages; prep dirs" | |
| @echo " okd-download - Download openshift-install & oc (via RELEASE_BASE_URL)" | |
| @echo " install-config - Generate install-config.yaml (NETWORK_TYPE aware)" | |
| @echo " create-assets - Create manifests/ignitions; stage to HTTP" | |
| @echo " pxe-stage - FCOS PXE images (kernel/initramfs/rootfs)" | |
| @echo " ipxe-stage - iPXE scripts + MAC-based mapping (nodes.mk aware) + discovery" | |
| @echo " ipxe-discovery-maps - Point all NODES MACs at discovery boot" | |
| @echo " raid-discovery - SSH to NODES in discovery env, run lsblk, print *_install_dev lines" | |
| @echo " pxe-up - dnsmasq (DHCPv6 + iPXE), httpd" | |
| @echo " radvd-up - Router Advertisements (IPv6 only)" | |
| @echo " dns-generate - Generate forward + reverse (ip6.arpa /48) zones (IPv6 only)" | |
| @echo " dns-up - Write named.conf & start bind (IPv6 only)" | |
| @echo " nat66-up - IPv6 forwarding + NAT66 table (IPv6 only)" | |
| @echo " svc-allow-bootstrap - Open inbound nft rules for bootstrap/API/Ignition (IPv6 only)" | |
| @echo " svc-allow-bootstrap-down - Remove those rules immediately" | |
| @echo " bootstrap-host-up - Launch local KVM bootstrap VM" | |
| @echo " bootstrap-host-down - Stop local bootstrap VM" | |
| @echo " wait-bootstrap - Wait for bootstrap-complete, then auto svc-rules teardown" | |
| @echo " cilium-olm - Install Cilium OLM operator (when ENABLE_CILIUM=1)" | |
| @echo " cilium-migrate - Disable CNO safely; apply CiliumConfig; checks" | |
| @echo " bond-howto - Emit nmcli LACP bonding helper" | |
| @echo " ilo-show-nodes - Show node+iLO inventory from nodes.mk" | |
| @echo " node-power-on-<node> - Power on a node via MGMT_TYPE=ilo|drac" | |
| @echo " node-power-off-<node>- Power off a node via MGMT_TYPE=ilo|drac" | |
| @echo " node-reset-<node> - Reset a node via MGMT_TYPE=ilo|drac" | |
| @echo " node-set-pxe-<node> - Set one-time PXE via MGMT_TYPE=ilo|drac" | |
| @echo " drac-power-* / ilo-* - Raw vendor helpers (direct iLO/DRAC)" | |
| @echo " teardown - Stop services; delete nft tables; restore backups" | |
| @echo " all - Full prep up to nat66 + svc rules (IPv6 mode only)" | |
| # ----------------------------------------------------------------------------- | |
| # Prereqs | |
| # ----------------------------------------------------------------------------- | |
| .PHONY: prereqs | |
| prereqs: | |
| @test $$(id -u) -eq 0 || { echo "Run as root"; exit 1; } | |
| dnf -y install \ | |
| dnsmasq radvd \ | |
| coreos-installer podman jq curl unzip \ | |
| httpd tftp-server \ | |
| nftables policycoreutils-python-utils \ | |
| bind bind-utils \ | |
| qemu-kvm libvirt-daemon-kvm virt-install \ | |
| ipxe-bootimgs | |
| systemctl enable --now nftables || true | |
| mkdir -p $(BIN_DIR) $(ASSETS_DIR) $(FCOS_DIR) $(HTTP_CLUSTER_DIR) $(PXE_HTTP_DIR) | |
| semanage fcontext -a -t httpd_sys_content_t "$(HTTP_CLUSTER_DIR)(/.*)?" | |
| restorecon -Rv $(HTTP_CLUSTER_DIR) | |
| systemctl disable --now dnsmasq || true | |
| systemctl disable --now httpd || true | |
| systemctl disable --now radvd || true | |
| systemctl disable --now named || true | |
| # ----------------------------------------------------------------------------- | |
| # Download installer & clients (distro-neutral) | |
| # ----------------------------------------------------------------------------- | |
| .PHONY: okd-download | |
| okd-download: | |
| @if [ -z "$(RELEASE_BASE_URL)" ]; then \ | |
| echo "RELEASE_BASE_URL is not set."; \ | |
| echo " Example for OCP: https://mirror.openshift.com/pub/openshift-v4/clients/ocp/latest"; \ | |
| echo " Example for OKD: https://github.com/okd-project/okd/releases/download/<release-tag>"; \ | |
| exit 1; \ | |
| fi | |
| mkdir -p $(BIN_DIR) $(ASSETS_DIR) | |
| echo "Downloading openshift-install/oc from $(RELEASE_BASE_URL)" | |
| curl -fsSL -o $(ASSETS_DIR)/openshift-install-linux.tar.gz $(RELEASE_BASE_URL)/openshift-install-linux.tar.gz | |
| curl -fsSL -o $(ASSETS_DIR)/openshift-client-linux.tar.gz $(RELEASE_BASE_URL)/openshift-client-linux.tar.gz | |
| tar -C $(BIN_DIR) -xzf $(ASSETS_DIR)/openshift-install-linux.tar.gz openshift-install | |
| tar -C $(BIN_DIR) -xzf $(ASSETS_DIR)/openshift-client-linux.tar.gz oc kubectl || true | |
| chmod +x $(BIN_DIR)/* | |
| $(BIN_DIR)/openshift-install version | |
| # ----------------------------------------------------------------------------- | |
| # Cluster assets (NETWORK_TYPE-aware) | |
| # ----------------------------------------------------------------------------- | |
| .PHONY: install-config | |
| install-config: | |
| @test -f "$(PULL_SECRET_FILE)" || { echo "Missing PULL_SECRET_FILE $(PULL_SECRET_FILE)"; exit 1; } | |
| @test -f "$(SSH_PUB_KEY_FILE)" || { echo "Missing SSH_PUB_KEY_FILE $(SSH_PUB_KEY_FILE)"; exit 1; } | |
| mkdir -p $(ASSETS_DIR)/cluster | |
| cat > $(ASSETS_DIR)/cluster/install-config.yaml <<-EOF | |
| apiVersion: v1 | |
| baseDomain: $(BASE_DOMAIN) | |
| compute: | |
| - hyperthreading: Enabled | |
| name: worker | |
| replicas: 2 | |
| controlPlane: | |
| hyperthreading: Enabled | |
| name: master | |
| replicas: 3 | |
| metadata: | |
| name: $(CLUSTER_NAME) | |
| networking: | |
| networkType: $(NETWORK_TYPE) | |
| clusterNetwork: | |
| - cidr: $(CLUSTER_NETWORK_CIDR) | |
| hostPrefix: $(CLUSTER_NETWORK_HOSTPREFIX) | |
| machineNetwork: | |
| - cidr: $(MACHINE_NETWORK_CIDR) | |
| serviceNetwork: | |
| - $(SERVICE_NETWORK_CIDR) | |
| platform: | |
| none: {} | |
| fips: false | |
| pullSecret: '$(shell jq -c . $(PULL_SECRET_FILE))' | |
| sshKey: '$(shell cat $(SSH_PUB_KEY_FILE))' | |
| additionalTrustBundlePolicy: Proxyonly | |
| EOF | |
| @echo "install-config.yaml written (NETWORK_TYPE=$(NETWORK_TYPE))." | |
| .PHONY: create-assets | |
| create-assets: | |
| cd $(ASSETS_DIR)/cluster | |
| $(OPENSHIFT_INSTALL) create manifests --dir=$(ASSETS_DIR)/cluster | |
| $(OPENSHIFT_INSTALL) create ignition-configs --dir=$(ASSETS_DIR)/cluster | |
| cp -av $(ASSETS_DIR)/cluster/*.ign $(HTTP_CLUSTER_DIR)/ | |
| restorecon -Rv $(HTTP_CLUSTER_DIR) | |
| # ----------------------------------------------------------------------------- | |
| # FCOS PXE artifacts | |
| # ----------------------------------------------------------------------------- | |
| .PHONY: pxe-stage | |
| pxe-stage: | |
| cd $(FCOS_DIR) | |
| podman run --rm --pull=always --security-opt label=disable \ | |
| -v $(FCOS_DIR):/data -w /data quay.io/coreos/coreos-installer:release \ | |
| download -s $(FCOS_STREAM) -f pxe | |
| ln -sf *-live-kernel-x86_64 kernel-x86_64 | |
| ln -sf *-live-initramfs.x86_64.img initramfs.x86_64.img | |
| ln -sf *-live-rootfs.x86_64.img rootfs.x86_64.img | |
| mkdir -p $(HTTP_CLUSTER_DIR)/fcos | |
| cp -av $(FCOS_DIR)/kernel-x86_64 $(FCOS_DIR)/initramfs.x86_64.img $(FCOS_DIR)/rootfs.x86_64.img $(HTTP_CLUSTER_DIR)/fcos/ | |
| restorecon -Rv $(HTTP_CLUSTER_DIR) | |
| # ----------------------------------------------------------------------------- | |
| # iPXE stage: entrypoint + per-MAC mapping files + discovery | |
| # ----------------------------------------------------------------------------- | |
| .PHONY: ipxe-stage | |
| ipxe-stage: | |
| mkdir -p $(PXE_HTTP_DIR) $(PXE_HTTP_DIR)/mac | |
| # Discovery Ignition: FCOS live + SSH enabled for user "core" | |
| @test -f "$(SSH_PUB_KEY_FILE)" || { echo "Missing SSH_PUB_KEY_FILE $(SSH_PUB_KEY_FILE) for discovery SSH access"; exit 1; } | |
| cat > $(HTTP_CLUSTER_DIR)/discovery.ign <<-IGN | |
| { | |
| "ignition": { "version": "3.4.0" }, | |
| "passwd": { | |
| "users": [ | |
| { | |
| "name": "core", | |
| "sshAuthorizedKeys": [ "$(shell cat $(SSH_PUB_KEY_FILE))" ] | |
| } | |
| ] | |
| } | |
| } | |
| IGN | |
| restorecon -Rv $(HTTP_CLUSTER_DIR) | |
| # index.ipxe | |
| cat > $(PXE_HTTP_DIR)/index.ipxe <<-IPXE | |
| #!ipxe | |
| set base $(PROVISION_URL_PREFIX)/okd | |
| chain \${base}/pxe/mac/\${net0/mac}.ipxe || chain \${base}/pxe/unknown.ipxe | |
| IPXE | |
| # Role-based legacy scripts (still available) | |
| cat > $(PXE_HTTP_DIR)/bootstrap.ipxe <<-IPXE | |
| #!ipxe | |
| echo Bootstrapping cluster bootstrap (iPXE) | |
| kernel $(PROVISION_URL_PREFIX)/okd/fcos/kernel-x86_64 initrd=initramfs \ | |
| ip=dhcp rd.neednet=1 ignition.firstboot ignition.platform.id=metal \ | |
| coreos.live.rootfs_url=$(PROVISION_URL_PREFIX)/okd/fcos/rootfs.x86_64.img \ | |
| coreos.inst.ignition_url=$(PROVISION_URL_PREFIX)/okd/bootstrap.ign | |
| initrd $(PROVISION_URL_PREFIX)/okd/fcos/initramfs.x86_64.img | |
| boot | |
| IPXE | |
| cat > $(PXE_HTTP_DIR)/master.ipxe <<-IPXE | |
| #!ipxe | |
| echo Bootstrapping cluster master (iPXE) | |
| kernel $(PROVISION_URL_PREFIX)/okd/fcos/kernel-x86_64 initrd=initramfs \ | |
| ip=dhcp rd.neednet=1 ignition.firstboot ignition.platform.id=metal \ | |
| coreos.live.rootfs_url=$(PROVISION_URL_PREFIX)/okd/fcos/rootfs.x86_64.img \ | |
| coreos.inst.ignition_url=$(PROVISION_URL_PREFIX)/okd/master.ign | |
| initrd $(PROVISION_URL_PREFIX)/okd/fcos/initramfs.x86_64.img | |
| boot | |
| IPXE | |
| cat > $(PXE_HTTP_DIR)/worker.ipxe <<-IPXE | |
| #!ipxe | |
| echo Bootstrapping cluster worker (iPXE) | |
| kernel $(PROVISION_URL_PREFIX)/okd/fcos/kernel-x86_64 initrd=initramfs \ | |
| ip=dhcp rd.neednet=1 ignition.firstboot ignition.platform.id=metal \ | |
| coreos.live.rootfs_url=$(PROVISION_URL_PREFIX)/okd/fcos/rootfs.x86_64.img \ | |
| coreos.inst.ignition_url=$(PROVISION_URL_PREFIX)/okd/worker.ign | |
| initrd $(PROVISION_URL_PREFIX)/okd/fcos/initramfs.x86_64.img | |
| boot | |
| IPXE | |
| # Discovery iPXE script | |
| cat > $(PXE_HTTP_DIR)/discover.ipxe <<-IPXE | |
| #!ipxe | |
| echo Booting discovery environment (FCOS live, SSH enabled) | |
| kernel $(PROVISION_URL_PREFIX)/okd/fcos/kernel-x86_64 initrd=initramfs \ | |
| ip=dhcp rd.neednet=1 ignition.firstboot ignition.platform.id=metal \ | |
| coreos.live.rootfs_url=$(PROVISION_URL_PREFIX)/okd/fcos/rootfs.x86_64.img \ | |
| ignition.config.url=$(PROVISION_URL_PREFIX)/okd/discovery.ign | |
| initrd $(PROVISION_URL_PREFIX)/okd/fcos/initramfs.x86_64.img | |
| boot | |
| IPXE | |
| # Unknown MAC fallback | |
| cat > $(PXE_HTTP_DIR)/unknown.ipxe <<-IPXE | |
| #!ipxe | |
| echo Unknown MAC \${net0/mac}; falling back to worker | |
| chain $(PROVISION_URL_PREFIX)/okd/pxe/worker.ipxe | |
| IPXE | |
| # Per-MAC mapping: prefer NODES inventory, else legacy okd.env mapping. | |
| if [ -n "$(strip $(NODES))" ]; then \ | |
| echo "ipxe-stage: using node inventory (NODES=$(NODES))"; \ | |
| for n in $(NODES); do \ | |
| mac_var="$${n}_mac"; role_var="$${n}_role"; dev_var="$${n}_install_dev"; \ | |
| eval mac=\$${mac_var}; eval role=\$${role_var}; eval dev=\$${dev_var}; \ | |
| if [ -z "$$mac" ] || [ -z "$$role" ]; then \ | |
| echo " WARN: node $$n missing mac or role, skipping"; \ | |
| continue; \ | |
| fi; \ | |
| ign="$(PROVISION_URL_PREFIX)/okd/$$role.ign"; \ | |
| dev_arg=""; \ | |
| if [ -n "$$dev" ]; then \ | |
| dev_arg=" coreos.inst.install_dev=$$dev"; \ | |
| fi; \ | |
| f="$(PXE_HTTP_DIR)/mac/$$mac.ipxe"; \ | |
| echo " generating $$f for node=$$n role=$$role dev=$$dev"; \ | |
| cat > "$$f" <<-E | |
| #!ipxe | |
| echo Bootstrapping node $$n (role=$$role) install_dev=$$dev | |
| kernel $(PROVISION_URL_PREFIX)/okd/fcos/kernel-x86_64 initrd=initramfs \\ | |
| ip=dhcp rd.neednet=1 ignition.firstboot ignition.platform.id=metal \\ | |
| coreos.live.rootfs_url=$(PROVISION_URL_PREFIX)/okd/fcos/rootfs.x86_64.img \\ | |
| coreos.inst.ignition_url=$$ign$$dev_arg | |
| initrd $(PROVISION_URL_PREFIX)/okd/fcos/initramfs.x86_64.img | |
| boot | |
| E | |
| done; \ | |
| else \ | |
| echo "ipxe-stage: no NODES inventory; you may still use legacy mapping from node.env if defined."; \ | |
| fi | |
| restorecon -Rv $(PXE_HTTP_DIR) | |
| # ----------------------------------------------------------------------------- | |
| # iPXE discovery maps | |
| # ----------------------------------------------------------------------------- | |
| .PHONY: ipxe-discovery-maps | |
| ipxe-discovery-maps: | |
| @if [ -z "$(strip $(NODES))" ]; then \ | |
| echo "ipxe-discovery-maps: NODES is empty (nodes.mk missing or no nodes defined)."; \ | |
| exit 1; \ | |
| fi | |
| @for n in $(NODES); do \ | |
| mac_var="$${n}_mac"; eval mac=\$${mac_var}; \ | |
| if [ -z "$$mac" ]; then \ | |
| echo " WARN: node $$n has no _mac defined, skipping"; \ | |
| continue; \ | |
| fi; \ | |
| f="$(PXE_HTTP_DIR)/mac/$$mac.ipxe"; \ | |
| echo " discovery mapping $$n ($$mac) -> discover.ipxe"; \ | |
| cat > "$$f" <<-E | |
| #!ipxe | |
| echo Discovery boot for node $$n (MAC $$mac) | |
| chain $(PROVISION_URL_PREFIX)/okd/pxe/discover.ipxe | |
| E | |
| done | |
| restorecon -Rv $(PXE_HTTP_DIR) | |
| # ----------------------------------------------------------------------------- | |
| # raid-discovery: SSH into discovery env and suggest *_install_dev values | |
| # ----------------------------------------------------------------------------- | |
| .PHONY: raid-discovery | |
| raid-discovery: | |
| @if [ -z "$(strip $(NODES))" ]; then \ | |
| echo "raid-discovery: NODES is empty (nodes.mk missing or no nodes defined)."; \ | |
| exit 1; \ | |
| fi | |
| @echo "# Suggested *_install_dev assignments based on discovery environment:" | |
| @for n in $(NODES); do \ | |
| ssh_host_var="$${n}_ssh_host"; \ | |
| eval ssh_host=\$${ssh_host_var}; \ | |
| if [ -z "$$ssh_host" ]; then ssh_host="$$n"; fi; \ | |
| echo "# Node $$n: probing $$ssh_host ..."; \ | |
| dev_path=$$(ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ | |
| core@$$ssh_host ' \ | |
| disk=$$(lsblk -dn -o NAME,TYPE,SIZE | awk '"'"'$2=="disk"{print $1,$3}'"'"' | sort -k2 -h | tail -1 | cut -d" " -f1); \ | |
| if [ -z "$$disk" ]; then \ | |
| echo ""; \ | |
| exit 0; \ | |
| fi; \ | |
| id=$$(ls -1 /dev/disk/by-id | grep "$$disk$$" | head -1); \ | |
| if [ -z "$$id" ]; then \ | |
| echo ""; \ | |
| exit 0; \ | |
| fi; \ | |
| echo "/dev/disk/by-id/$$id" \ | |
| ' || true); \ | |
| if [ -z "$$dev_path" ]; then \ | |
| echo "# WARN: could not determine install device for $$n (ssh or lsblk failed)"; \ | |
| else \ | |
| echo "$${n}_install_dev := $$dev_path"; \ | |
| fi; \ | |
| done | |
| # ----------------------------------------------------------------------------- | |
| # pxe-up (IPv6 DHCPv6 only) | |
| # ----------------------------------------------------------------------------- | |
| .PHONY: pxe-up | |
| pxe-up: pxe-dnsmasq pxe-httpd | |
| .PHONY: pxe-dnsmasq | |
| pxe-dnsmasq: | |
| @if [ "$(NETWORK_STACK)" != "ipv6" ]; then \ | |
| echo "pxe-dnsmasq: IPv6-specific (DHCPv6). Skipped because NETWORK_STACK=$(NETWORK_STACK)."; \ | |
| exit 0; \ | |
| fi | |
| @if [ -f "$(DNSMASQ_FILE)" ] && [ ! -f "$(DNSMASQ_BAK)" ]; then cp -a "$(DNSMASQ_FILE)" "$(DNSMASQ_BAK)"; fi | |
| install -d -m 0755 $$(dirname "$(DNSMASQ_FILE)") | |
| cat > $(DNSMASQ_FILE) <<-EOF | |
| # Cluster iPXE over HTTP (DHCPv6), static DUID/IAID reservations | |
| interface=$(DHCP_INTERFACE) | |
| bind-interfaces | |
| dhcp-range=$(DHCP_RANGE_START),$(DHCP_RANGE_END),64,12h | |
| # Static reservations (DUID/IAID -> fixed IPv6 + hostname) | |
| $(if $(BOOTSTRAP_DUID),dhcp-host=$(BOOTSTRAP_IAID),id:$(BOOTSTRAP_DUID),[$(BOOTSTRAP_IP6)],bootstrap,infinite) | |
| $(if $(MASTER0_DUID),dhcp-host=$(MASTER0_IAID),id:$(MASTER0_DUID),[$(MASTER0_IP6)],master0,infinite) | |
| $(if $(MASTER1_DUID),dhcp-host=$(MASTER1_IAID),id:$(MASTER1_DUID),[$(MASTER1_IP6)],master1,infinite) | |
| $(if $(MASTER2_DUID),dhcp-host=$(MASTER2_IAID),id:$(MASTER2_DUID),[$(MASTER2_IP6)],master2,infinite) | |
| $(if $(WORKER0_DUID),dhcp-host=$(WORKER0_IAID),id:$(WORKER0_DUID),[$(WORKER0_IP6)],worker0,infinite) | |
| $(if $(WORKER1_DUID),dhcp-host=$(WORKER1_IAID),id:$(WORKER1_DUID),[$(WORKER1_IP6)],worker1,infinite) | |
| # All PXE clients get the same iPXE entry script; that script selects role by MAC | |
| dhcp-option=option6:bootfile-url,[http://[$(INSTALL_HOST_IP6)]/okd/pxe/index.ipxe] | |
| EOF | |
| systemctl enable --now dnsmasq | |
| systemctl status --no-pager dnsmasq || true | |
| .PHONY: pxe-httpd | |
| pxe-httpd: | |
| systemctl enable --now httpd | |
| @echo "Ignitions: $(PROVISION_URL_PREFIX)/okd/{bootstrap,master,worker}.ign" | |
| @echo "Discovery Ignition: $(PROVISION_URL_PREFIX)/okd/discovery.ign" | |
| @echo "iPXE entry: $(PROVISION_URL_PREFIX)/okd/pxe/index.ipxe" | |
| # ----------------------------------------------------------------------------- | |
| # radvd (IPv6 only) | |
| # ----------------------------------------------------------------------------- | |
| .PHONY: radvd-up | |
| radvd-up: | |
| @if [ "$(NETWORK_STACK)" != "ipv6" ]; then \ | |
| echo "radvd-up: skipped (NETWORK_STACK=$(NETWORK_STACK), IPv6 only)."; \ | |
| exit 0; \ | |
| fi | |
| @if [ -f "$(RADVD_FILE)" ] && [ ! -f "$(RADVD_BAK)" ]; then cp -a "$(RADVD_FILE)" "$(RADVD_BAK)"; fi | |
| cat > $(RADVD_FILE) <<-EOF | |
| interface $(DHCP_INTERFACE) | |
| { | |
| AdvSendAdvert on; | |
| MaxRtrAdvInterval 30; | |
| AdvManagedFlag off; | |
| AdvOtherConfigFlag on; | |
| prefix $(MACHINE_NETWORK_CIDR) | |
| { | |
| AdvOnLink on; | |
| AdvAutonomous on; | |
| }; | |
| RDNSS $(INSTALL_HOST_IP6) | |
| { | |
| AdvRDNSSLifetime 600; | |
| }; | |
| }; | |
| EOF | |
| systemctl enable --now radvd | |
| systemctl status --no-pager radvd || true | |
| # ----------------------------------------------------------------------------- | |
| # DNS (IPv6-only ip6.arpa helper) | |
| # ----------------------------------------------------------------------------- | |
| .PHONY: dns-generate | |
| dns-generate: | |
| @if [ "$(NETWORK_STACK)" != "ipv6" ]; then \ | |
| echo "dns-generate: IPv6-only implementation (ip6.arpa). Skipped because NETWORK_STACK=$(NETWORK_STACK)."; \ | |
| exit 0; \ | |
| fi | |
| @if [ -f "$(FWD_ZONE_FILE)" ] && [ ! -f "$(FWD_ZONE_BAK)" ]; then cp -a "$(FWD_ZONE_FILE)" "$(FWD_ZONE_BAK)"; fi | |
| @if [ -f "$(REV_ZONE_FILE)" ] && [ ! -f "$(REV_ZONE_BAK)" ]; then cp -a "$(REV_ZONE_FILE)" "$(REV_ZONE_BAK)"; fi | |
| install -d -m 0755 $(NAMED_DIR) | |
| cat > $(FWD_ZONE_FILE) <<-EOF | |
| \$TTL 60 | |
| @ IN SOA ns1.$(CLUSTER_NAME).$(BASE_DOMAIN). hostmaster.$(BASE_DOMAIN). ( | |
| $$(date +%Y%m%d%H) ; serial | |
| 60 ; refresh | |
| 30 ; retry | |
| 120 ; expire | |
| 60) ; minimum | |
| IN NS ns1.$(CLUSTER_NAME).$(BASE_DOMAIN). | |
| ns1 IN AAAA $(INSTALL_HOST_IP6) | |
| api IN AAAA $(API_VIP6) | |
| *.apps IN AAAA $(APPS_VIP6) | |
| bootstrap IN AAAA $(BOOTSTRAP_IP6) | |
| master0 IN AAAA $(MASTER0_IP6) | |
| master1 IN AAAA $(MASTER1_IP6) | |
| master2 IN AAAA $(MASTER2_IP6) | |
| worker0 IN AAAA $(WORKER0_IP6) | |
| worker1 IN AAAA $(WORKER1_IP6) | |
| EOF | |
| PREFIX_HEX=$$(echo "$(MACHINE_NETWORK_CIDR)" | cut -d/ -f1 | sed 's/://g' | tr '[:lower:]' '[:upper:]') | |
| PREFIX_LEN=$$(echo "$(MACHINE_NETWORK_CIDR)" | cut -d/ -f2) | |
| @if [ "$$PREFIX_LEN" != "48" ]; then echo "dns-generate expects /48, got /$$PREFIX_LEN"; exit 1; fi | |
| ZONE_SUFFIX=$$(echo "$$PREFIX_HEX" | cut -c1-12 | rev | sed 's/./&./g')ip6.arpa | |
| cat > $(REV_ZONE_FILE) <<-EOF | |
| \$TTL 60 | |
| @ IN SOA ns1.$(CLUSTER_NAME).$(BASE_DOMAIN). hostmaster.$(BASE_DOMAIN). ( | |
| $$(date +%Y%m%d%H) ; serial | |
| 60 ; refresh | |
| 30 ; retry | |
| 120 ; expire | |
| 60) ; minimum | |
| IN NS ns1.$(CLUSTER_NAME).$(BASE_DOMAIN). | |
| EOF | |
| emit_ptr() { ip=$$1; host=$$2; \ | |
| full=$$(python3 - <<PY | |
| import ipaddress,sys | |
| print(ipaddress.IPv6Address(sys.argv[1]).exploded) | |
| PY | |
| "$$ip"); \ | |
| hex=$$(echo $$full | tr -d ':' | tr '[:lower:]' '[:upper:]'); \ | |
| tail=$$(echo $$hex | cut -c13-32 | rev | sed 's/./&./g'); \ | |
| echo "$$tail IN PTR $$host.$(CLUSTER_NAME).$(BASE_DOMAIN)." >> $(REV_ZONE_FILE); } | |
| emit_ptr "$(BOOTSTRAP_IP6)" "bootstrap" | |
| emit_ptr "$(MASTER0_IP6)" "master0" | |
| emit_ptr "$(MASTER1_IP6)" "master1" | |
| emit_ptr "$(MASTER2_IP6)" "master2" | |
| emit_ptr "$(WORKER0_IP6)" "worker0" | |
| emit_ptr "$(WORKER1_IP6)" "worker1" | |
| @echo "Forward: $(FWD_ZONE_FILE)" | |
| @echo "Reverse: $(REV_ZONE_FILE)" | |
| .PHONY: dns-up | |
| dns-up: | |
| @if [ "$(NETWORK_STACK)" != "ipv6" ]; then \ | |
| echo "dns-up: IPv6-only named.conf helper (ip6.arpa). Skipped because NETWORK_STACK=$(NETWORK_STACK)."; \ | |
| exit 0; \ | |
| fi | |
| @if [ -f "$(NAMED_CONF)" ] && [ ! -f "$(NAMED_CONF_BAK)" ]; then cp -a "$(NAMED_CONF)" "$(NAMED_CONF_BAK)"; fi | |
| cat > $(NAMED_CONF) <<-EOF | |
| options { | |
| directory "$(NAMED_DIR)"; | |
| listen-on-v6 { any; }; | |
| allow-query { any; }; | |
| }; | |
| zone "$(CLUSTER_NAME).$(BASE_DOMAIN)" IN { | |
| type master; file "$(FWD_ZONE_FILE)"; allow-update { none; }; | |
| }; | |
| zone "$(shell HEX=$$(echo "$(MACHINE_NETWORK_CIDR)"|cut -d/ -f1|sed 's/://g'|tr a-z A-Z); echo $$HEX|cut -c1-12|rev|sed 's/./&./g')ip6.arpa" IN { | |
| type master; file "$(REV_ZONE_FILE)"; allow-update { none; }; | |
| }; | |
| EOF | |
| restorecon -Rv $(NAMED_DIR) $(NAMED_CONF) | |
| systemctl enable --now named | |
| systemctl status --no-pager named || true | |
| # ----------------------------------------------------------------------------- | |
| # NAT66 + svc-allow-bootstrap (IPv6-only) | |
| # ----------------------------------------------------------------------------- | |
| .PHONY: nat66-up | |
| nat66-up: | |
| @if [ "$(NETWORK_STACK)" != "ipv6" ]; then \ | |
| echo "nat66-up: NAT66 is IPv6-only. Skipped because NETWORK_STACK=$(NETWORK_STACK)."; \ | |
| exit 0; \ | |
| fi | |
| sysctl -w net.ipv6.conf.all.forwarding=1 | |
| sysctl -w net.ipv6.conf.default.forwarding=1 | |
| @if [ -f "$(NFT_MAIN_CONF)" ] && [ ! -f "$(NFT_MAIN_BAK)" ]; then cp -a "$(NFT_MAIN_CONF)" "$(NFT_MAIN_BAK)"; fi | |
| @if [ -f "$(NFT_CLUSTER_FILE)" ] && [ ! -f "$(NFT_CLUSTER_BAK)" ]; then cp -a "$(NFT_CLUSTER_FILE)" "$(NFT_CLUSTER_BAK)"; fi | |
| cat > $(NFT_CLUSTER_FILE) <<-EOF | |
| table ip6 $(NFT_CLUSTER_TABLE) { | |
| chain POSTROUTING { | |
| type nat hook postrouting priority srcnat; policy accept; | |
| oifname "$(NAT66_UPLINK)" masquerade | |
| } | |
| } | |
| EOF | |
| if ! grep -qF 'include "$(NFT_CLUSTER_FILE)"' "$(NFT_MAIN_CONF)"; then | |
| cat >> "$(NFT_MAIN_CONF)" <<-EOF | |
| include "$(NFT_CLUSTER_FILE)" | |
| EOF | |
| fi | |
| systemctl reload nftables || systemctl restart nftables | |
| nft list tables ip6 | sed -n '1,120p' | |
| .PHONY: svc-allow-bootstrap | |
| svc-allow-bootstrap: | |
| @if [ "$(NETWORK_STACK)" != "ipv6" ]; then \ | |
| echo "svc-allow-bootstrap: IPv6-only helper (ip6 tables). Skipped because NETWORK_STACK=$(NETWORK_STACK)."; \ | |
| exit 0; \ | |
| fi | |
| @if [ -f "$(NFT_SVC_FILE)" ] && [ ! -f "$(NFT_SVC_BAK)" ]; then cp -a "$(NFT_SVC_FILE)" "$(NFT_SVC_BAK)"; fi | |
| cat > $(NFT_SVC_FILE) <<-EOF | |
| table ip6 $(NFT_SVC_TABLE) { | |
| set okd_ports { type inet_service; flags interval; elements = { 80, 443, 6443, 22623 } } | |
| chain INPUT { | |
| type filter hook input priority 0; policy accept; | |
| ip6 saddr $(MACHINE_NETWORK_CIDR) tcp dport @okd_ports accept | |
| } | |
| } | |
| EOF | |
| if ! grep -qF 'include "$(NFT_SVC_FILE)"' "$(NFT_MAIN_CONF)"; then | |
| cat >> "$(NFT_MAIN_CONF)" <<-EOF | |
| include "$(NFT_SVC_FILE)" | |
| EOF | |
| fi | |
| systemctl reload nftables || systemctl restart nftables | |
| nft list tables ip6 | sed -n '1,200p' | |
| .PHONY: svc-allow-bootstrap-down | |
| svc-allow-bootstrap-down: | |
| if nft list tables ip6 | grep -q '^table ip6 $(NFT_SVC_TABLE)$$'; then | |
| nft delete table ip6 $(NFT_SVC_TABLE) || true | |
| fi | |
| if [ -f "$(NFT_MAIN_CONF)" ]; then | |
| sed -i '\|include "$(NFT_SVC_FILE)"|d' "$(NFT_MAIN_CONF)" || true | |
| fi | |
| @if [ -f "$(NFT_SVC_BAK)" ]; then cp -af "$(NFT_SVC_BAK)" "$(NFT_SVC_FILE)"; else rm -f "$(NFT_SVC_FILE)"; fi | |
| systemctl reload nftables || systemctl restart nftables || true | |
| @echo "Bootstrap svc-allow rules removed." | |
| # ----------------------------------------------------------------------------- | |
| # Bootstrap local VM | |
| # ----------------------------------------------------------------------------- | |
| .PHONY: bootstrap-host-up | |
| bootstrap-host-up: | |
| qemu-img create -f qcow2 $(ASSETS_DIR)/bootstrap.qcow2 40G | |
| qemu-system-x86_64 \ | |
| -enable-kvm -m 8192 -smp 4 -name $(BOOTSTRAP_VM) -cpu host \ | |
| -drive file=$(ASSETS_DIR)/bootstrap.qcow2,if=virtio \ | |
| -netdev user,id=net0,ipv6=on -device virtio-net-pci,netdev=net0 \ | |
| -kernel $(FCOS_DIR)/kernel-x86_64 \ | |
| -initrd $(FCOS_DIR)/initramfs.x86_64.img \ | |
| -append "ip=dhcp rd.neednet=1 ignition.firstboot ignition.platform.id=metal coreos.live.rootfs_url=$(PROVISION_URL_PREFIX)/okd/fcos/rootfs.x86_64.img coreos.inst.ignition_url=$(PROVISION_URL_PREFIX)/okd/bootstrap.ign console=ttyS0" \ | |
| -nographic & echo $$! > $(ASSETS_DIR)/bootstrap.pid | |
| @echo "Bootstrap VM started (PID $$(cat $(ASSETS_DIR)/bootstrap.pid))." | |
| .PHONY: bootstrap-host-down | |
| bootstrap-host-down: | |
| @if [ -f "$(ASSETS_DIR)/bootstrap.pid" ]; then kill $$(cat $(ASSETS_DIR)/bootstrap.pid) || true; rm -f $(ASSETS_DIR)/bootstrap.pid; fi | |
| @echo "Bootstrap VM stopped." | |
| # ----------------------------------------------------------------------------- | |
| # Wait for bootstrap | |
| # ----------------------------------------------------------------------------- | |
| .PHONY: wait-bootstrap | |
| wait-bootstrap: | |
| @echo "Waiting for bootstrap-complete ..." | |
| $(OPENSHIFT_INSTALL) --dir=$(ASSETS_DIR)/cluster wait-for bootstrap-complete --log-level=info | |
| @echo "Bootstrap complete. Tearing down bootstrap service rules (if IPv6)." | |
| -$(MAKE) svc-allow-bootstrap-down | |
| # ----------------------------------------------------------------------------- | |
| # Cilium helpers (gated by ENABLE_CILIUM) | |
| # ----------------------------------------------------------------------------- | |
| .PHONY: cilium-olm | |
| cilium-olm: | |
| @if [ "$(ENABLE_CILIUM)" != "1" ]; then \ | |
| echo "cilium-olm: disabled (ENABLE_CILIUM=$(ENABLE_CILIUM))."; \ | |
| exit 0; \ | |
| fi | |
| cat > $(ASSETS_DIR)/cilium-olm.yaml <<-YAML | |
| apiVersion: v1 | |
| kind: Namespace | |
| metadata: { name: cilium } | |
| --- | |
| apiVersion: operators.coreos.com/v1 | |
| kind: OperatorGroup | |
| metadata: { name: cilium-og, namespace: cilium } | |
| spec: { targetNamespaces: [ "cilium" ] } | |
| --- | |
| apiVersion: operators.coreos.com/v1alpha1 | |
| kind: Subscription | |
| metadata: { name: cilium-enterprise, namespace: cilium } | |
| spec: | |
| channel: stable | |
| name: cilium-olm | |
| source: redhat-operators | |
| sourceNamespace: openshift-marketplace | |
| YAML | |
| $(OC) apply -f $(ASSETS_DIR)/cilium-olm.yaml | |
| .PHONY: cilium-migrate | |
| cilium-migrate: | |
| @if [ "$(ENABLE_CILIUM)" != "1" ]; then \ | |
| echo "cilium-migrate: disabled (ENABLE_CILIUM=$(ENABLE_CILIUM))."; \ | |
| exit 0; \ | |
| fi | |
| @echo "== Cilium migration (review vendor docs to confirm steps/versions) ==" | |
| $(OC) -n openshift-network-operator scale deploy network-operator --replicas=0 || true | |
| cat > $(ASSETS_DIR)/network.operator.patch.yaml <<-YAML | |
| apiVersion: operator.openshift.io/v1 | |
| kind: Network | |
| metadata: | |
| name: cluster | |
| spec: | |
| defaultNetwork: | |
| type: Other | |
| disableMultiNetwork: true | |
| YAML | |
| $(OC) apply -f $(ASSETS_DIR)/network.operator.patch.yaml || true | |
| cat > $(ASSETS_DIR)/ciliumconfig.yaml <<-YAML | |
| apiVersion: cilium.io/v1alpha1 | |
| kind: CiliumConfig | |
| metadata: | |
| name: cilium | |
| namespace: cilium | |
| spec: | |
| cluster: | |
| name: $(CLUSTER_NAME) | |
| cni: | |
| exclusive: true | |
| ipam: | |
| mode: kubernetes | |
| k8sServiceHost: api.$(CLUSTER_NAME).$(BASE_DOMAIN) | |
| k8sServicePort: 6443 | |
| routingMode: tunnel | |
| enableIPv6: true | |
| enableIPv4: false | |
| kubeProxyReplacement: strict | |
| YAML | |
| $(OC) apply -f $(ASSETS_DIR)/ciliumconfig.yaml | |
| @echo "Check cilium pods and cluster networking per vendor guidance." | |
| # ----------------------------------------------------------------------------- | |
| # Bonding helper | |
| # ----------------------------------------------------------------------------- | |
| .PHONY: bond-howto | |
| bond-howto: | |
| cat > /root/postinstall_bond.sh <<-EOS | |
| #!/usr/bin/bash -eu | |
| nmcli con add type bond con-name bond0 ifname bond0 mode 802.3ad | |
| nmcli con modify bond0 bond.options "mode=802.3ad,miimon=100,xmit_hash_policy=layer2+3" | |
| for i in 1 2 3 4; do nmcli con add type ethernet con-name bond0-slave\${i} ifname eno\${i} master bond0; done | |
| nmcli con show bond0 | |
| EOS | |
| chmod +x /root/postinstall_bond.sh | |
| @echo "Wrote /root/postinstall_bond.sh" | |
| # ----------------------------------------------------------------------------- | |
| # HPE iLO helpers (raw) | |
| # ----------------------------------------------------------------------------- | |
| .PHONY: ilo-show-nodes | |
| ilo-show-nodes: | |
| @if [ -z "$(strip $(NODES))" ]; then \ | |
| echo "ilo-show-nodes: no NODES defined (nodes.mk missing or empty)."; \ | |
| exit 1; \ | |
| fi | |
| @for n in $(NODES); do \ | |
| ilo_ip_var="$${n}_ilo_ip"; ilo_user_var="$${n}_ilo_user"; role_var="$${n}_role"; dev_var="$${n}_install_dev"; mac_var="$${n}_mac"; \ | |
| eval ilo_ip=\$${ilo_ip_var}; eval ilo_user=\$${ilo_user_var}; eval role=\$${role_var}; eval dev=\$${dev_var}; eval mac=\$${mac_var}; \ | |
| if [ -z "$$ilo_ip" ]; then \ | |
| echo "$$n: role=$$role mac=$$mac install_dev=$$dev (no iLO IP set)"; \ | |
| else \ | |
| if [ -z "$$ilo_user" ]; then ilo_user="$(ILO_DEFAULT_USER)"; fi; \ | |
| echo "$$n: role=$$role mac=$$mac install_dev=$$dev iLO=$$ilo_ip user=$$ilo_user"; \ | |
| fi; \ | |
| done | |
| .PHONY: ilo-power-on-% ilo-power-off-% ilo-reset-% ilo-set-pxe-% | |
| ilo-power-on-%: | |
| @node="$*"; \ | |
| ilo_ip_var="$${node}_ilo_ip"; ilo_user_var="$${node}_ilo_user"; \ | |
| eval ilo_ip=\$${ilo_ip_var}; eval ilo_user=\$${ilo_user_var}; \ | |
| if [ -z "$$ilo_ip" ]; then \ | |
| echo "ilo-power-on-$$node: missing $${node}_ilo_ip"; exit 1; \ | |
| fi; \ | |
| if [ -z "$$ilo_user" ]; then ilo_user="$(ILO_DEFAULT_USER)"; fi; \ | |
| echo "ilo-power-on-$$node: $$ilo_user@$$ilo_ip"; \ | |
| ssh "$$ilo_user@$$ilo_ip" "power on" | |
| ilo-power-off-%: | |
| @node="$*"; \ | |
| ilo_ip_var="$${node}_ilo_ip"; ilo_user_var="$${node}_ilo_user"; \ | |
| eval ilo_ip=\$${ilo_ip_var}; eval ilo_user=\$${ilo_user_var}; \ | |
| if [ -z "$$ilo_ip" ]; then \ | |
| echo "ilo-power-off-$$node: missing $${node}_ilo_ip"; exit 1; \ | |
| fi; \ | |
| if [ -z "$$ilo_user" ]; then ilo_user="$(ILO_DEFAULT_USER)"; fi; \ | |
| echo "ilo-power-off-$$node: $$ilo_user@$$ilo_ip"; \ | |
| ssh "$$ilo_user@$$ilo_ip" "power off force" | |
| ilo-reset-%: | |
| @node="$*"; \ | |
| ilo_ip_var="$${node}_ilo_ip"; ilo_user_var="$${node}_ilo_user"; \ | |
| eval ilo_ip=\$${ilo_ip_var}; eval ilo_user=\$${ilo_user_var}; \ | |
| if [ -z "$$ilo_ip" ]; then \ | |
| echo "ilo-reset-$$node: missing $${node}_ilo_ip"; exit 1; \ | |
| fi; \ | |
| if [ -z "$$ilo_user" ]; then ilo_user="$(ILO_DEFAULT_USER)"; fi; \ | |
| echo "ilo-reset-$$node: $$ilo_user@$$ilo_ip"; \ | |
| ssh "$$ilo_user@$$ilo_ip" "power reset" | |
| ilo-set-pxe-%: | |
| @node="$*"; \ | |
| ilo_ip_var="$${node}_ilo_ip"; ilo_user_var="$${node}_ilo_user"; \ | |
| eval ilo_ip=\$${ilo_ip_var}; eval ilo_user=\$${ilo_user_var}; \ | |
| if [ -z "$$ilo_ip" ]; then \ | |
| echo "ilo-set-pxe-$$node: missing $${node}_ilo_ip"; exit 1; \ | |
| fi; \ | |
| if [ -z "$$ilo_user" ]; then ilo_user="$(ILO_DEFAULT_USER)"; fi; \ | |
| echo "ilo-set-pxe-$$node (one-time network boot): $$ilo_user@$$ilo_ip"; \ | |
| ssh "$$ilo_user@$$ilo_ip" "echo 'set /system1/bootconfig1/bootsource1 bootorder=network' | some_ilo_cli_placeholder" | |
| # ----------------------------------------------------------------------------- | |
| # DRAC helpers (raw, cluster-global) | |
| # ----------------------------------------------------------------------------- | |
| DRAC_HOST ?= | |
| .PHONY: drac-power-on drac-power-off drac-reset drac-set-pxe | |
| drac-power-on: | |
| @if [ -z "$(DRAC_HOST)" ]; then echo "DRAC_HOST not set"; exit 1; fi | |
| @echo "DRAC power on: $(DRAC_USER)@$(DRAC_HOST)" | |
| @ssh $(DRAC_USER)@$(DRAC_HOST) "racadm serveraction powerup" | |
| drac-power-off: | |
| @if [ -z "$(DRAC_HOST)" ]; then echo "DRAC_HOST not set"; exit 1; fi | |
| @echo "DRAC power off: $(DRAC_USER)@$(DRAC_HOST)" | |
| @ssh $(DRAC_USER)@$(DRAC_HOST) "racadm serveraction powerdown" | |
| drac-reset: | |
| @if [ -z "$(DRAC_HOST)" ]; then echo "DRAC_HOST not set"; exit 1; fi | |
| @echo "DRAC reset: $(DRAC_USER)@$(DRAC_HOST)" | |
| @ssh $(DRAC_USER)@$(DRAC_HOST) "racadm serveraction powercycle" | |
| drac-set-pxe: | |
| @if [ -z "$(DRAC_HOST)" ]; then echo "DRAC_HOST not set"; exit 1; fi | |
| @echo "DRAC one-time PXE boot: $(DRAC_USER)@$(DRAC_HOST)" | |
| @ssh $(DRAC_USER)@$(DRAC_HOST) "racadm config -g cfgServerInfo -o cfgServerBootOnce 1" | |
| @ssh $(DRAC_USER)@$(DRAC_HOST) "racadm config -g cfgServerInfo -o cfgServerFirstBootDevice PXE" | |
| # ----------------------------------------------------------------------------- | |
| # Generic node-level management (MGMT_TYPE=ilo|drac) | |
| # ----------------------------------------------------------------------------- | |
| .PHONY: node-power-on-% node-power-off-% node-reset-% node-set-pxe-% | |
| node-power-on-%: | |
| @node="$*"; \ | |
| if [ "$(MGMT_TYPE)" = "ilo" ]; then \ | |
| ilo_ip_var="$${node}_ilo_ip"; ilo_user_var="$${node}_ilo_user"; \ | |
| eval ilo_ip=\$${ilo_ip_var}; eval ilo_user=\$${ilo_user_var}; \ | |
| if [ -z "$$ilo_ip" ]; then echo "node-power-on-$$node: missing $${node}_ilo_ip"; exit 1; fi; \ | |
| if [ -z "$$ilo_user" ]; then ilo_user="$(ILO_DEFAULT_USER)"; fi; \ | |
| echo "node-power-on-$$node via iLO: $$ilo_user@$$ilo_ip"; \ | |
| ssh "$$ilo_user@$$ilo_ip" "power on"; \ | |
| elif [ "$(MGMT_TYPE)" = "drac" ]; then \ | |
| drac_host_var="$${node}_drac_host"; drac_user_var="$${node}_drac_user"; \ | |
| eval drac_host=\$${drac_host_var}; eval drac_user=\$${drac_user_var}; \ | |
| if [ -z "$$drac_host" ]; then echo "node-power-on-$$node: missing $${node}_drac_host"; exit 1; fi; \ | |
| if [ -z "$$drac_user" ]; then drac_user="$(DRAC_USER)"; fi; \ | |
| echo "node-power-on-$$node via DRAC: $$drac_user@$$drac_host"; \ | |
| ssh "$$drac_user@$$drac_host" "racadm serveraction powerup"; \ | |
| else \ | |
| echo "node-power-on-$$node: unsupported MGMT_TYPE=$(MGMT_TYPE) (expected ilo or drac)"; \ | |
| exit 1; \ | |
| fi | |
| node-power-off-%: | |
| @node="$*"; \ | |
| if [ "$(MGMT_TYPE)" = "ilo" ]; then \ | |
| ilo_ip_var="$${node}_ilo_ip"; ilo_user_var="$${node}_ilo_user"; \ | |
| eval ilo_ip=\$${ilo_ip_var}; eval ilo_user=\$${ilo_user_var}; \ | |
| if [ -z "$$ilo_ip" ]; then echo "node-power-off-$$node: missing $${node}_ilo_ip"; exit 1; fi; \ | |
| if [ -z "$$ilo_user" ]; then ilo_user="$(ILO_DEFAULT_USER)"; fi; \ | |
| echo "node-power-off-$$node via iLO: $$ilo_user@$$ilo_ip"; \ | |
| ssh "$$ilo_user@$$ilo_ip" "power off force"; \ | |
| elif [ "$(MGMT_TYPE)" = "drac" ]; then \ | |
| drac_host_var="$${node}_drac_host"; drac_user_var="$${node}_drac_user"; \ | |
| eval drac_host=\$${drac_host_var}; eval drac_user=\$${drac_user_var}; \ | |
| if [ -z "$$drac_host" ]; then echo "node-power-off-$$node: missing $${node}_drac_host"; exit 1; fi; \ | |
| if [ -z "$$drac_user" ]; then drac_user="$(DRAC_USER)"; fi; \ | |
| echo "node-power-off-$$node via DRAC: $$drac_user@$$drac_host"; \ | |
| ssh "$$drac_user@$$drac_host" "racadm serveraction powerdown"; \ | |
| else \ | |
| echo "node-power-off-$$node: unsupported MGMT_TYPE=$(MGMT_TYPE)"; \ | |
| exit 1; \ | |
| fi | |
| node-reset-%: | |
| @node="$*"; \ | |
| if [ "$(MGMT_TYPE)" = "ilo" ]; then \ | |
| ilo_ip_var="$${node}_ilo_ip"; ilo_user_var="$${node}_ilo_user"; \ | |
| eval ilo_ip=\$${ilo_ip_var}; eval ilo_user=\$${ilo_user_var}; \ | |
| if [ -z "$$ilo_ip" ]; then echo "node-reset-$$node: missing $${node}_ilo_ip"; exit 1; fi; \ | |
| if [ -z "$$ilo_user" ]; then ilo_user="$(ILO_DEFAULT_USER)"; fi; \ | |
| echo "node-reset-$$node via iLO: $$ilo_user@$$ilo_ip"; \ | |
| ssh "$$ilo_user@$$ilo_ip" "power reset"; \ | |
| elif [ "$(MGMT_TYPE)" = "drac" ]; then \ | |
| drac_host_var="$${node}_drac_host"; drac_user_var="$${node}_drac_user"; \ | |
| eval drac_host=\$${drac_host_var}; eval drac_user=\$${drac_user_var}; \ | |
| if [ -z "$$drac_host" ]; then echo "node-reset-$$node: missing $${node}_drac_host"; exit 1; fi; \ | |
| if [ -z "$$drac_user" ]; then drac_user="$(DRAC_USER)"; fi; \ | |
| echo "node-reset-$$node via DRAC: $$drac_user@$$drac_host"; \ | |
| ssh "$$drac_user@$$drac_host" "racadm serveraction powercycle"; \ | |
| else \ | |
| echo "node-reset-$$node: unsupported MGMT_TYPE=$(MGMT_TYPE)"; \ | |
| exit 1; \ | |
| fi | |
| node-set-pxe-%: | |
| @node="$*"; \ | |
| if [ "$(MGMT_TYPE)" = "ilo" ]; then \ | |
| ilo_ip_var="$${node}_ilo_ip"; ilo_user_var="$${node}_ilo_user"; \ | |
| eval ilo_ip=\$${ilo_ip_var}; eval ilo_user=\$${ilo_user_var}; \ | |
| if [ -z "$$ilo_ip" ]; then echo "node-set-pxe-$$node: missing $${node}_ilo_ip"; exit 1; fi; \ | |
| if [ -z "$$ilo_user" ]; then ilo_user="$(ILO_DEFAULT_USER)"; fi; \ | |
| echo "node-set-pxe-$$node via iLO (one-time network boot): $$ilo_user@$$ilo_ip"; \ | |
| ssh "$$ilo_user@$$ilo_ip" "echo 'set /system1/bootconfig1/bootsource1 bootorder=network' | some_ilo_cli_placeholder"; \ | |
| elif [ "$(MGMT_TYPE)" = "drac" ]; then \ | |
| drac_host_var="$${node}_drac_host"; drac_user_var="$${node}_drac_user"; \ | |
| eval drac_host=\$${drac_host_var}; eval drac_user=\$${drac_user_var}; \ | |
| if [ -z "$$drac_host" ]; then echo "node-set-pxe-$$node: missing $${node}_drac_host"; exit 1; fi; \ | |
| if [ -z "$$drac_user" ]; then drac_user="$(DRAC_USER)"; fi; \ | |
| echo "node-set-pxe-$$node via DRAC (one-time PXE boot): $$drac_user@$$drac_host"; \ | |
| ssh "$$drac_user@$$drac_host" "racadm config -g cfgServerInfo -o cfgServerBootOnce 1"; \ | |
| ssh "$$drac_user@$$drac_host" "racadm config -g cfgServerInfo -o cfgServerFirstBootDevice PXE"; \ | |
| else \ | |
| echo "node-set-pxe-$$node: unsupported MGMT_TYPE=$(MGMT_TYPE)"; \ | |
| exit 1; \ | |
| fi | |
| # ----------------------------------------------------------------------------- | |
| # Teardown | |
| # ----------------------------------------------------------------------------- | |
| .PHONY: teardown | |
| teardown: | |
| systemctl disable --now dnsmasq || true | |
| systemctl disable --now httpd || true | |
| systemctl disable --now radvd || true | |
| systemctl disable --now named || true | |
| -$(MAKE) bootstrap-host-down | |
| if nft list tables ip6 | grep -q '^table ip6 $(NFT_SVC_TABLE)$$'; then nft delete table ip6 $(NFT_SVC_TABLE) || true; fi | |
| if nft list tables ip6 | grep -q '^table ip6 $(NFT_CLUSTER_TABLE)$$'; then nft delete table ip6 $(NFT_CLUSTER_TABLE) || true; fi | |
| if [ -f "$(NFT_MAIN_CONF)" ]; then \ | |
| sed -i '\|include "$(NFT_SVC_FILE)"|d' "$(NFT_MAIN_CONF)" || true; \ | |
| sed -i '\|include "$(NFT_CLUSTER_FILE)"|d' "$(NFT_MAIN_CONF)" || true; \ | |
| fi | |
| @if [ -f "$(DNSMASQ_BAK)" ]; then cp -af "$(DNSMASQ_BAK)" "$(DNSMASQ_FILE)"; else rm -f "$(DNSMASQ_FILE)"; fi | |
| @if [ -f "$(RADVD_BAK)" ]; then cp -af "$(RADVD_BAK)" "$(RADVD_FILE)"; else rm -f "$(RADVD_FILE)"; fi | |
| @if [ -f "$(NFT_CLUSTER_BAK)" ]; then cp -af "$(NFT_CLUSTER_BAK)" "$(NFT_CLUSTER_FILE)"; else rm -f "$(NFT_CLUSTER_FILE)"; fi | |
| @if [ -f "$(NFT_SVC_BAK)" ]; then cp -af "$(NFT_SVC_BAK)" "$(NFT_SVC_FILE)"; else rm -f "$(NFT_SVC_FILE)"; fi | |
| @if [ -f "$(NAMED_CONF_BAK)" ]; then cp -af "$(NAMED_CONF_BAK)" "$(NAMED_CONF)"; fi | |
| @if [ -f "$(FWD_ZONE_BAK)" ]; then cp -af "$(FWD_ZONE_BAK)" "$(FWD_ZONE_FILE)"; else rm -f "$(FWD_ZONE_FILE)"; fi | |
| @if [ -f "$(REV_ZONE_BAK)" ]; then cp -af "$(REV_ZONE_BAK)" "$(REV_ZONE_FILE)"; else rm -f "$(REV_ZONE_FILE)"; fi | |
| systemctl reload nftables || systemctl restart nftables || true | |
| @echo "Teardown complete." | |
| # ----------------------------------------------------------------------------- | |
| # Convenience | |
| # ----------------------------------------------------------------------------- | |
| .PHONY: all | |
| all: prereqs okd-download install-config create-assets pxe-stage ipxe-stage pxe-up radvd-up dns-generate dns-up nat66-up svc-allow-bootstrap |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # ----------------------------------------------------------------------------- | |
| # Cluster environment (generic, vendor-agnostic) | |
| # ----------------------------------------------------------------------------- | |
| # Cluster identity | |
| CLUSTER_NAME=hp-ocp | |
| BASE_DOMAIN=lab.example.com | |
| # Network stack: ipv4 or ipv6 | |
| NETWORK_STACK=ipv4 | |
| # CNI | |
| NETWORK_TYPE=OVNKubernetes | |
| # Machine & service networks (IPv4 example) | |
| MACHINE_NETWORK_CIDR=192.168.90.0/24 | |
| CLUSTER_NETWORK_CIDR=10.128.0.0/14 | |
| CLUSTER_NETWORK_HOSTPREFIX=23 | |
| SERVICE_NETWORK_CIDR=172.30.0.0/16 | |
| # IPv6 placeholders (used only if NETWORK_STACK=ipv6) | |
| MACHINE_NETWORK_IPV6=2602:f6ae:aa::/48 | |
| CLUSTER_NETWORK_IPV6=fd00:10:64::/48 | |
| SERVICE_NETWORK_IPV6=fd00:10:96::/112 | |
| # VIPs | |
| API_VIP4=192.168.90.10 | |
| APPS_VIP4=192.168.90.11 | |
| API_VIP6=2602:f6ae:aa::50 | |
| APPS_VIP6=2602:f6ae:aa::60 | |
| # Provisioning host (this machine’s IP on the provisioning network) | |
| # For IPv4 clusters: | |
| PROVISION_HOST=192.168.90.5 | |
| # For IPv6 clusters, you’d use: | |
| # PROVISION_HOST=2602:f6ae:aa::10 | |
| # HTTP root for cluster artifacts | |
| HTTP_DIR=/var/www/html/okd | |
| # Optional TFTP root | |
| TFTP_DIR=/var/lib/tftpboot | |
| # PXE/DHCP interface on provisioning host | |
| DHCP_INTERFACE=eno1 | |
| # NAT uplink (used only in IPv6 NAT66) | |
| NAT66_UPLINK=eno2 | |
| # DHCPv6 range (only used when NETWORK_STACK=ipv6) | |
| DHCP_RANGE_START=2602:f6ae:aa::200 | |
| DHCP_RANGE_END=2602:f6ae:aa::2ff | |
| # IPv6 installer host address (for radvd/DNS in IPv6 mode) | |
| INSTALL_HOST_IP6=2602:f6ae:aa::10 | |
| # Example static IPv6s for named helpers (only used if you actually run IPv6 mode) | |
| BOOTSTRAP_IP6=2602:f6ae:aa::101 | |
| MASTER0_IP6=2602:f6ae:aa::111 | |
| MASTER1_IP6=2602:f6ae:aa::112 | |
| MASTER2_IP6=2602:f6ae:aa::113 | |
| WORKER0_IP6=2602:f6ae:aa::121 | |
| WORKER1_IP6=2602:f6ae:aa::122 | |
| # ----------------------------------------------------------------------------- | |
| # Distro + release | |
| # ----------------------------------------------------------------------------- | |
| # DISTRO is informational; the Makefile only cares that RELEASE_BASE_URL points | |
| # to a location containing: | |
| # - openshift-install-linux.tar.gz | |
| # - openshift-client-linux.tar.gz | |
| DISTRO=ocp | |
| # For fully licensed OpenShift (OCP), default to the "latest" client: | |
| RELEASE_BASE_URL=https://mirror.openshift.com/pub/openshift-v4/clients/ocp/latest | |
| # For OKD, you’d instead set, e.g.: | |
| # DISTRO=okd | |
| # RELEASE_BASE_URL=https://github.com/okd-project/okd/releases/download/4.20.0-okd-scos.4 | |
| # Paths to installer and client after download | |
| OPENSHIFT_INSTALL=${PWD}/bin/openshift-install | |
| OC=${PWD}/bin/oc | |
| # ----------------------------------------------------------------------------- | |
| # Auth / SSH | |
| # ----------------------------------------------------------------------------- | |
| # Pull secret: download from: | |
| # https://console.redhat.com/openshift/install/pull-secret | |
| # Save as secret.json in this cluster dir or project root. | |
| PULL_SECRET_FILE=${PWD}/secret.json | |
| # SSH key for core user on nodes + discovery env | |
| SSH_PUB_KEY_FILE=${HOME}/.ssh/id_rsa.pub | |
| # Optional trust bundle PEM file for internal registries (can be empty) | |
| ADDITIONAL_TRUST_BUNDLE_FILE= | |
| # FCOS stream | |
| FCOS_STREAM=stable | |
| # ----------------------------------------------------------------------------- | |
| # Cilium toggle | |
| # ----------------------------------------------------------------------------- | |
| ENABLE_CILIUM=0 | |
| # ----------------------------------------------------------------------------- | |
| # Node management type | |
| # ----------------------------------------------------------------------------- | |
| # MGMT_TYPE controls generic node-* targets: | |
| # ilo -> uses <node>_ilo_ip / <node>_ilo_user | |
| # drac -> uses <node>_drac_host / <node>_drac_user | |
| MGMT_TYPE=ilo | |
| # Default management users (can be overridden per node) | |
| ILO_DEFAULT_USER=Administrator | |
| DRAC_USER=root |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # ----------------------------------------------------------------------------- | |
| # Node inventory (vendor-agnostic) | |
| # One nodes.mk per cluster. | |
| # ----------------------------------------------------------------------------- | |
| # All nodes in this cluster | |
| NODES := node01 node02 node03 node04 node05 node06 | |
| # ---- Roles ------------------------------------------------------------------ | |
| node01_role := master | |
| node02_role := master | |
| node03_role := master | |
| node04_role := worker | |
| node05_role := worker | |
| node06_role := worker | |
| # ---- PXE MACs --------------------------------------------------------------- | |
| # MAC addresses of the NICs that will PXE boot from the provisioning network. | |
| node01_mac := aa:bb:cc:00:00:01 | |
| node02_mac := aa:bb:cc:00:00:02 | |
| node03_mac := aa:bb:cc:00:00:03 | |
| node04_mac := aa:bb:cc:00:00:04 | |
| node05_mac := aa:bb:cc:00:00:05 | |
| node06_mac := aa:bb:cc:00:00:06 | |
| # ---- Install devices (RAID/BOSS/whatever) ----------------------------------- | |
| # Populate after discovery: | |
| # make ipxe-discovery-maps | |
| # power nodes to PXE into discovery env | |
| # make raid-discovery | |
| # Then paste the suggested *_install_dev lines here. | |
| # | |
| # Examples: | |
| # node01_install_dev := /dev/disk/by-id/scsi-3600508e000000000000000001 | |
| # node02_install_dev := /dev/disk/by-id/scsi-3600508e000000000000000002 | |
| # node03_install_dev := /dev/disk/by-id/scsi-3600508e000000000000000003 | |
| # node04_install_dev := /dev/disk/by-id/scsi-3600508e000000000000000004 | |
| # node05_install_dev := /dev/disk/by-id/scsi-3600508e000000000000000005 | |
| # node06_install_dev := /dev/disk/by-id/scsi-3600508e000000000000000006 | |
| # ---- Management endpoints --------------------------------------------------- | |
| # Used by generic node-* targets depending on MGMT_TYPE in node.env: | |
| # | |
| # MGMT_TYPE=ilo -> <node>_ilo_ip / optional <node>_ilo_user | |
| # MGMT_TYPE=drac -> <node>_drac_host / optional <node>_drac_user | |
| # | |
| # Example: HP iLO nodes (when MGMT_TYPE=ilo) | |
| node01_ilo_ip := 10.0.10.11 | |
| node02_ilo_ip := 10.0.10.12 | |
| node03_ilo_ip := 10.0.10.13 | |
| node04_ilo_ip := 10.0.10.14 | |
| node05_ilo_ip := 10.0.10.15 | |
| node06_ilo_ip := 10.0.10.16 | |
| # Optional custom per-node user: | |
| # node01_ilo_user := Administrator | |
| # If you have a DRAC-based cluster instead, you’d use: | |
| # node01_drac_host := 10.0.20.11 | |
| # node02_drac_host := 10.0.20.12 | |
| # node03_drac_host := 10.0.20.13 | |
| # node04_drac_host := 10.0.20.14 | |
| # node05_drac_host := 10.0.20.15 | |
| # node06_drac_host := 10.0.20.16 | |
| # node01_drac_user := root | |
| # ---- Discovery SSH endpoints (optional) ------------------------------------- | |
| # raid-discovery will ssh as: | |
| # ssh core@<node> (default) | |
| # or, if defined: | |
| # ssh core@<node>_ssh_host | |
| # | |
| # Use these if DNS doesn’t resolve node01/node02 to the temporary discovery IPs. | |
| # node01_ssh_host := 192.168.90.21 | |
| # node02_ssh_host := 192.168.90.22 | |
| # node03_ssh_host := 192.168.90.23 | |
| # node04_ssh_host := 192.168.90.24 | |
| # node05_ssh_host := 192.168.90.25 | |
| # node06_ssh_host := 192.168.90.26 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment