Root cause: Previous config violated boot-time security model - Removed /etc/iscsi mount (iscsi-tools extension manages it) - Moved multipath.conf to post-boot DaemonSet - Added explicit kubelet nodeIP for dual-NIC workers Deliverables: - Fixed talconfig.yaml with working worker patch - iscsi-multipath-init.yaml DaemonSet for multipath config - Automated deployment and verification scripts - Complete documentation suite Ready for production deployment to fastpass worker nodes. Co-authored-by: Talos Specialist <subagent@hermes>
184 lines
7.1 KiB
Bash
Executable File
184 lines
7.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# verify-iscsi.sh
|
|
#
|
|
# Verifies iSCSI configuration on Talos worker nodes
|
|
# Run after applying the fixed configuration
|
|
|
|
set -euo pipefail
|
|
|
|
GREEN='\033[0;32m'
|
|
RED='\033[0;31m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
|
|
WORKER_NODES=(
|
|
"jungle-cruise:10.1.71.69"
|
|
"haunted-mansion:10.1.71.70"
|
|
"peter-pans-flight:10.1.71.71"
|
|
)
|
|
|
|
FLASHARRAY_ISCSI_IP="${1:-}"
|
|
|
|
if [[ -z "$FLASHARRAY_ISCSI_IP" ]]; then
|
|
echo -e "${YELLOW}Usage: $0 <flasharray-iscsi-ip>${NC}"
|
|
echo "Example: $0 10.1.75.100"
|
|
echo
|
|
echo "Testing without FlashArray connectivity check..."
|
|
echo
|
|
fi
|
|
|
|
echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}"
|
|
echo -e "${BLUE}║ Talos iSCSI Configuration Verification Report ║${NC}"
|
|
echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}"
|
|
echo
|
|
|
|
for node_spec in "${WORKER_NODES[@]}"; do
|
|
IFS=':' read -r hostname ip <<< "$node_spec"
|
|
|
|
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
echo -e "${BLUE}Node: $hostname ($ip)${NC}"
|
|
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
echo
|
|
|
|
# Check node is Ready
|
|
echo -n " Kubernetes node status: "
|
|
if kubectl get node "$hostname" -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}' 2>/dev/null | grep -q "True"; then
|
|
echo -e "${GREEN}✓ Ready${NC}"
|
|
else
|
|
echo -e "${RED}✗ Not Ready${NC}"
|
|
fi
|
|
|
|
# Check node IP
|
|
echo -n " Node internal IP: "
|
|
node_ip=$(kubectl get node "$hostname" -o jsonpath='{.status.addresses[?(@.type=="InternalIP")].address}' 2>/dev/null)
|
|
if [[ "$node_ip" == "10.1.71."* ]]; then
|
|
echo -e "${GREEN}✓ $node_ip (correct network)${NC}"
|
|
else
|
|
echo -e "${RED}✗ $node_ip (expected 10.1.71.x)${NC}"
|
|
fi
|
|
|
|
# Check system extensions
|
|
echo -n " iscsi-tools extension: "
|
|
if talosctl -n "$ip" get extensions 2>/dev/null | grep -q "iscsi-tools"; then
|
|
echo -e "${GREEN}✓ installed${NC}"
|
|
else
|
|
if talosctl -n "$ip" read /proc/modules 2>/dev/null | grep -q "iscsi_tcp"; then
|
|
echo -e "${GREEN}✓ active (module loaded)${NC}"
|
|
else
|
|
echo -e "${RED}✗ not found${NC}"
|
|
fi
|
|
fi
|
|
|
|
# Check kernel modules
|
|
echo -n " Kernel modules: "
|
|
modules_ok=true
|
|
for mod in iscsi_tcp dm_multipath dm_round_robin; do
|
|
if ! talosctl -n "$ip" read /proc/modules 2>/dev/null | grep -q "^$mod "; then
|
|
modules_ok=false
|
|
echo -e "${RED}✗ $mod not loaded${NC}"
|
|
echo -n " "
|
|
fi
|
|
done
|
|
if $modules_ok; then
|
|
echo -e "${GREEN}✓ all loaded${NC}"
|
|
fi
|
|
|
|
# Check iscsid service
|
|
echo -n " iscsid service: "
|
|
service_status=$(talosctl -n "$ip" service iscsid 2>/dev/null | grep "STATE" | awk '{print $2}' || echo "Unknown")
|
|
if [[ "$service_status" == "Running" ]]; then
|
|
echo -e "${GREEN}✓ Running${NC}"
|
|
elif [[ "$service_status" == "Finished" ]]; then
|
|
echo -e "${YELLOW}⚠ Finished (starts on-demand)${NC}"
|
|
else
|
|
echo -e "${YELLOW}⚠ $service_status${NC}"
|
|
fi
|
|
|
|
# Check initiator name
|
|
echo -n " iSCSI initiator: "
|
|
initiator=$(talosctl -n "$ip" read /etc/iscsi/initiatorname.iscsi 2>/dev/null | grep "InitiatorName=" | cut -d= -f2 || echo "")
|
|
if [[ -n "$initiator" ]]; then
|
|
echo -e "${GREEN}✓ ${initiator:0:40}...${NC}"
|
|
else
|
|
echo -e "${RED}✗ not configured${NC}"
|
|
fi
|
|
|
|
# Check /var/lib/iscsi
|
|
echo -n " iSCSI data directory: "
|
|
if talosctl -n "$ip" ls /var/lib/iscsi >/dev/null 2>&1; then
|
|
file_count=$(talosctl -n "$ip" ls /var/lib/iscsi 2>/dev/null | wc -l)
|
|
echo -e "${GREEN}✓ accessible ($file_count entries)${NC}"
|
|
else
|
|
echo -e "${RED}✗ not accessible${NC}"
|
|
fi
|
|
|
|
# Check multipath
|
|
echo -n " Multipath config: "
|
|
if talosctl -n "$ip" read /etc/multipath.conf >/dev/null 2>&1; then
|
|
if talosctl -n "$ip" read /etc/multipath.conf 2>/dev/null | grep -q "PURE"; then
|
|
echo -e "${GREEN}✓ configured for Pure Storage${NC}"
|
|
else
|
|
echo -e "${YELLOW}⚠ present but missing Pure config${NC}"
|
|
fi
|
|
else
|
|
echo -e "${YELLOW}⚠ not found (will be created by DaemonSet)${NC}"
|
|
fi
|
|
|
|
echo -n " Multipath devices: "
|
|
mp_devices=$(talosctl -n "$ip" exec -- multipath -ll 2>/dev/null | grep -c "^[a-z0-9]" || echo "0")
|
|
if [[ "$mp_devices" -gt 0 ]]; then
|
|
echo -e "${GREEN}✓ $mp_devices device(s)${NC}"
|
|
else
|
|
echo -e "${YELLOW}⚠ none (expected until iSCSI volumes attached)${NC}"
|
|
fi
|
|
|
|
# Check network connectivity on iSCSI interface
|
|
echo -n " iSCSI network (ens19): "
|
|
if talosctl -n "$ip" read /sys/class/net/ens19/operstate 2>/dev/null | grep -q "up"; then
|
|
iscsi_ip=$(talosctl -n "$ip" exec -- ip addr show ens19 2>/dev/null | grep "inet " | awk '{print $2}' | cut -d/ -f1)
|
|
echo -e "${GREEN}✓ up ($iscsi_ip)${NC}"
|
|
else
|
|
echo -e "${RED}✗ down${NC}"
|
|
fi
|
|
|
|
# Test FlashArray connectivity if IP provided
|
|
if [[ -n "$FLASHARRAY_ISCSI_IP" ]]; then
|
|
echo -n " FlashArray ping: "
|
|
if talosctl -n "$ip" exec -- ping -c 1 -W 2 "$FLASHARRAY_ISCSI_IP" >/dev/null 2>&1; then
|
|
echo -e "${GREEN}✓ reachable${NC}"
|
|
else
|
|
echo -e "${RED}✗ not reachable${NC}"
|
|
fi
|
|
|
|
echo -n " iSCSI discovery: "
|
|
if discovery_out=$(talosctl -n "$ip" exec -- iscsiadm -m discovery -t st -p "$FLASHARRAY_ISCSI_IP" 2>&1); then
|
|
target_count=$(echo "$discovery_out" | grep -c "iqn\." || echo "0")
|
|
echo -e "${GREEN}✓ found $target_count target(s)${NC}"
|
|
else
|
|
echo -e "${RED}✗ failed${NC}"
|
|
fi
|
|
fi
|
|
|
|
echo
|
|
done
|
|
|
|
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
echo -e "${BLUE}DaemonSet Status${NC}"
|
|
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
echo
|
|
|
|
if kubectl get daemonset iscsi-multipath-init -n kube-system >/dev/null 2>&1; then
|
|
kubectl get daemonset iscsi-multipath-init -n kube-system
|
|
echo
|
|
kubectl get pods -n kube-system -l app=iscsi-multipath-init -o wide
|
|
else
|
|
echo -e "${YELLOW}⚠ iscsi-multipath-init DaemonSet not deployed${NC}"
|
|
echo " Deploy with: kubectl apply -f iscsi-multipath-init.yaml"
|
|
fi
|
|
|
|
echo
|
|
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
echo -e "${GREEN}Verification complete!${NC}"
|
|
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|