- Deploy Portworx Operator + CSI driver via ArgoCD - Support both iSCSI block and NFS file storage from FlashArray - Integrate with 1Password External Secrets for FlashArray credentials - Include comprehensive deployment documentation and validation script - Storage classes: pure-block (iSCSI) and pure-file (NFS) - Talos Linux compatible with iSCSI/multipath configuration
229 lines
7.0 KiB
Bash
Executable File
229 lines
7.0 KiB
Bash
Executable File
#!/bin/bash
|
|
# Pre-deployment validation script for Portworx CSI on Talos Linux
|
|
# Checks prerequisites before deploying Portworx CSI driver
|
|
|
|
set -e
|
|
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m' # No Color
|
|
|
|
ERRORS=0
|
|
WARNINGS=0
|
|
|
|
echo "======================================================================"
|
|
echo "Portworx CSI Pre-Deployment Validation"
|
|
echo "======================================================================"
|
|
echo ""
|
|
|
|
# Function to print results
|
|
check_pass() {
|
|
echo -e "${GREEN}✓${NC} $1"
|
|
}
|
|
|
|
check_fail() {
|
|
echo -e "${RED}✗${NC} $1"
|
|
((ERRORS++))
|
|
}
|
|
|
|
check_warn() {
|
|
echo -e "${YELLOW}!${NC} $1"
|
|
((WARNINGS++))
|
|
}
|
|
|
|
# Check kubectl connectivity
|
|
echo "=== Kubernetes Cluster Connectivity ==="
|
|
if kubectl cluster-info &>/dev/null; then
|
|
check_pass "kubectl can connect to cluster"
|
|
CLUSTER_NAME=$(kubectl config current-context)
|
|
echo " Context: $CLUSTER_NAME"
|
|
else
|
|
check_fail "kubectl cannot connect to cluster"
|
|
exit 1
|
|
fi
|
|
echo ""
|
|
|
|
# Check namespace
|
|
echo "=== Namespace Preparation ==="
|
|
if kubectl get namespace portworx &>/dev/null; then
|
|
check_warn "Namespace 'portworx' already exists (expected if re-deploying)"
|
|
else
|
|
check_pass "Namespace 'portworx' does not exist (will be created)"
|
|
fi
|
|
echo ""
|
|
|
|
# Check External Secrets Operator
|
|
echo "=== External Secrets Operator ==="
|
|
if kubectl get deployment -n external-secrets external-secrets &>/dev/null; then
|
|
check_pass "External Secrets Operator is deployed"
|
|
|
|
ESO_READY=$(kubectl get deployment -n external-secrets external-secrets -o jsonpath='{.status.readyReplicas}')
|
|
if [ "$ESO_READY" -ge 1 ]; then
|
|
check_pass "External Secrets Operator is ready ($ESO_READY replicas)"
|
|
else
|
|
check_fail "External Secrets Operator is not ready"
|
|
fi
|
|
else
|
|
check_fail "External Secrets Operator is not deployed (required for secret sync)"
|
|
fi
|
|
echo ""
|
|
|
|
# Check ClusterSecretStore
|
|
echo "=== ClusterSecretStore ==="
|
|
if kubectl get clustersecretstore onepassword &>/dev/null; then
|
|
check_pass "ClusterSecretStore 'onepassword' exists"
|
|
|
|
STORE_STATUS=$(kubectl get clustersecretstore onepassword -o jsonpath='{.status.conditions[0].status}')
|
|
if [ "$STORE_STATUS" = "True" ]; then
|
|
check_pass "ClusterSecretStore is ready"
|
|
else
|
|
check_warn "ClusterSecretStore may not be ready (status: $STORE_STATUS)"
|
|
fi
|
|
else
|
|
check_fail "ClusterSecretStore 'onepassword' not found (required for 1Password sync)"
|
|
fi
|
|
echo ""
|
|
|
|
# Check Talos nodes
|
|
echo "=== Talos Node Configuration ==="
|
|
NODES=$(kubectl get nodes -o jsonpath='{.items[*].metadata.name}')
|
|
NODE_COUNT=$(echo "$NODES" | wc -w)
|
|
|
|
if [ "$NODE_COUNT" -eq 0 ]; then
|
|
check_fail "No nodes found in cluster"
|
|
else
|
|
check_pass "Found $NODE_COUNT nodes in cluster"
|
|
|
|
for NODE in $NODES; do
|
|
echo " Checking node: $NODE"
|
|
|
|
# Check if Talos
|
|
OS=$(kubectl get node "$NODE" -o jsonpath='{.status.nodeInfo.osImage}')
|
|
if [[ "$OS" == *"Talos"* ]]; then
|
|
check_pass " Node is running Talos Linux"
|
|
else
|
|
check_warn " Node is not running Talos Linux (OS: $OS)"
|
|
fi
|
|
done
|
|
fi
|
|
echo ""
|
|
|
|
# Note: Cannot check iSCSI/multipath from kubectl - requires talosctl access
|
|
echo "=== Talos iSCSI and Multipath (manual verification required) ==="
|
|
check_warn "Cannot verify iSCSI/multipath from kubectl - requires talosctl"
|
|
echo " Run manually on each node:"
|
|
echo " talosctl -n <node-ip> get service iscsid"
|
|
echo " talosctl -n <node-ip> exec -- multipath -ll"
|
|
echo " talosctl -n <node-ip> read /etc/iscsi/initiatorname.iscsi"
|
|
echo ""
|
|
|
|
# Check existing CSI drivers
|
|
echo "=== Existing CSI Drivers ==="
|
|
EXISTING_CSI=$(kubectl get csidrivers -o jsonpath='{.items[*].metadata.name}')
|
|
if [[ "$EXISTING_CSI" == *"pxd.portworx.com"* ]]; then
|
|
check_warn "Portworx CSI driver already registered (re-deployment scenario)"
|
|
else
|
|
check_pass "Portworx CSI driver not yet registered"
|
|
fi
|
|
|
|
if [ -n "$EXISTING_CSI" ]; then
|
|
echo " Existing CSI drivers:"
|
|
for driver in $EXISTING_CSI; do
|
|
echo " - $driver"
|
|
done
|
|
fi
|
|
echo ""
|
|
|
|
# Check for conflicting StorageClasses
|
|
echo "=== StorageClass Conflicts ==="
|
|
if kubectl get storageclass pure-block &>/dev/null; then
|
|
check_warn "StorageClass 'pure-block' already exists (will be reconciled)"
|
|
else
|
|
check_pass "StorageClass 'pure-block' does not exist"
|
|
fi
|
|
|
|
if kubectl get storageclass pure-file &>/dev/null; then
|
|
check_warn "StorageClass 'pure-file' already exists (will be reconciled)"
|
|
else
|
|
check_pass "StorageClass 'pure-file' does not exist"
|
|
fi
|
|
echo ""
|
|
|
|
# Check ArgoCD
|
|
echo "=== ArgoCD ==="
|
|
if kubectl get namespace argocd &>/dev/null; then
|
|
check_pass "ArgoCD namespace exists"
|
|
|
|
if kubectl get application -n argocd portworx-csi &>/dev/null; then
|
|
check_warn "ArgoCD Application 'portworx-csi' already exists"
|
|
|
|
APP_STATUS=$(kubectl get application -n argocd portworx-csi -o jsonpath='{.status.sync.status}')
|
|
APP_HEALTH=$(kubectl get application -n argocd portworx-csi -o jsonpath='{.status.health.status}')
|
|
echo " Status: $APP_STATUS, Health: $APP_HEALTH"
|
|
else
|
|
check_pass "ArgoCD Application 'portworx-csi' does not exist (will be created)"
|
|
fi
|
|
else
|
|
check_fail "ArgoCD namespace not found (required for GitOps deployment)"
|
|
fi
|
|
echo ""
|
|
|
|
# Check if manifests exist in repo
|
|
echo "=== Repository Manifests ==="
|
|
MANIFEST_DIR="cluster/platform/portworx-csi"
|
|
|
|
if [ -d "$MANIFEST_DIR" ]; then
|
|
check_pass "Portworx CSI manifest directory exists"
|
|
|
|
REQUIRED_FILES=(
|
|
"application.yaml"
|
|
"operator-values.yaml"
|
|
"storagecluster.yaml"
|
|
"externalsecret.yaml"
|
|
"storageclass-block.yaml"
|
|
"storageclass-file.yaml"
|
|
)
|
|
|
|
for file in "${REQUIRED_FILES[@]}"; do
|
|
if [ -f "$MANIFEST_DIR/$file" ]; then
|
|
check_pass " Found: $file"
|
|
else
|
|
check_fail " Missing: $file"
|
|
fi
|
|
done
|
|
else
|
|
check_fail "Portworx CSI manifest directory not found: $MANIFEST_DIR"
|
|
fi
|
|
echo ""
|
|
|
|
# Check for network connectivity to FlashArray (if endpoint is known)
|
|
echo "=== FlashArray Connectivity (manual verification recommended) ==="
|
|
check_warn "Cannot test FlashArray connectivity without endpoint"
|
|
echo " Test manually:"
|
|
echo " ping <flasharray-mgmt-ip>"
|
|
echo " curl -k https://<flasharray-mgmt-ip>/api/2.0/arrays"
|
|
echo ""
|
|
|
|
# Summary
|
|
echo "======================================================================"
|
|
echo "Validation Summary"
|
|
echo "======================================================================"
|
|
if [ $ERRORS -eq 0 ] && [ $WARNINGS -eq 0 ]; then
|
|
echo -e "${GREEN}✓ All checks passed!${NC}"
|
|
echo "Ready to deploy Portworx CSI."
|
|
exit 0
|
|
elif [ $ERRORS -eq 0 ]; then
|
|
echo -e "${YELLOW}! $WARNINGS warnings found${NC}"
|
|
echo "Deployment may proceed, but review warnings above."
|
|
exit 0
|
|
else
|
|
echo -e "${RED}✗ $ERRORS errors found${NC}"
|
|
if [ $WARNINGS -gt 0 ]; then
|
|
echo -e "${YELLOW}! $WARNINGS warnings found${NC}"
|
|
fi
|
|
echo ""
|
|
echo "Please resolve errors before deploying Portworx CSI."
|
|
exit 1
|
|
fi
|