From acec744df88083a1b24dc5811bfdfa82af1e1f81 Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Sat, 23 May 2026 11:24:21 +0000 Subject: [PATCH] feat: update NFS configuration and add check-nfs script for server validation --- ADDING-APPS.md | 21 +++- nfs/install.sh | 229 --------------------------------------- nfs/manifest.yaml | 8 +- nfs/scripts/check-nfs.sh | 79 ++++++++++++++ 4 files changed, 104 insertions(+), 233 deletions(-) delete mode 100755 nfs/install.sh create mode 100755 nfs/scripts/check-nfs.sh diff --git a/ADDING-APPS.md b/ADDING-APPS.md index a3c6426..553a180 100644 --- a/ADDING-APPS.md +++ b/ADDING-APPS.md @@ -62,13 +62,32 @@ requiredSecrets: | `name` | Yes | App identifier (must match directory name) | | `is` | Yes | Unique id for this app. Used for `requires` mapping | | `description` | Yes | Brief app description shown in listings | -| `version` | Yes | App version (follow upstream versioning) | +| `version` | Yes | App version (see Versioning Convention below) | | `icon` | No | URL to app icon for UI display | | `requires` | No | List of dependency apps with optional aliases | | `defaultConfig` | Yes | Default configuration values merged into operator's `config.yaml` | | `defaultSecrets` | No | This app's secrets (no 'default' = auto-generated) | | `requiredSecrets` | No | List of secrets from dependency apps (format: `.`) | +### Versioning Convention + +Wild Cloud uses a two-part version scheme inspired by Debian packaging: `-`. + +- **Upstream version** tracks the third-party software version (e.g., `v4.0.18`, `1.120.2`) +- **Packaging revision** tracks Wild Cloud packaging changes (template fixes, manifest cleanup, config restructuring) that don't change the upstream software version + +**Examples:** +- `v4.0.18` — initial packaging of upstream v4.0.18 +- `v4.0.18-1` — first packaging fix (no upstream change) +- `v4.0.18-2` — second packaging fix +- `v4.0.19` — upstream version bump, revision resets + +**When to bump the packaging revision:** Any change to the app package that doesn't correspond to an upstream software update — manifest field changes, template improvements, kustomize restructuring, security context fixes, label corrections, etc. + +**When to bump the upstream version:** When updating the container image tag or deploying a new version of the third-party software. + +The web UI uses version comparison to detect available updates. If the deployed version differs from the wild-directory version, operators see an update indicator and can apply it from the app detail panel. + ### Dependency Configuration - Each dependency in `requires` can have: diff --git a/nfs/install.sh b/nfs/install.sh deleted file mode 100755 index 30b9d7c..0000000 --- a/nfs/install.sh +++ /dev/null @@ -1,229 +0,0 @@ -#!/bin/bash -set -e -set -o pipefail - -if [ -z "${WILD_INSTANCE}" ]; then - echo "ERROR: WILD_INSTANCE is not set" - exit 1 -fi - -if [ -z "${WILD_API_DATA_DIR}" ]; then - echo "ERROR: WILD_API_DATA_DIR is not set" - exit 1 -fi - -if [ -z "${KUBECONFIG}" ]; then - echo "ERROR: KUBECONFIG is not set" - exit 1 -fi - -INSTANCE_DIR="${WILD_API_DATA_DIR}/instances/${WILD_INSTANCE}" -CONFIG_FILE="${INSTANCE_DIR}/config.yaml" -NFS_DIR="${INSTANCE_DIR}/apps/nfs" - -echo "=== Registering NFS Server with Kubernetes Cluster ===" -echo "" - -echo "Using pre-compiled NFS templates..." -if [ ! -f "${NFS_DIR}/kustomization.yaml" ]; then - echo "ERROR: Compiled templates not found at ${NFS_DIR}" - echo "Templates should be compiled before deployment." - exit 1 -fi - -NFS_HOST="$(yq '.apps.nfs.host' "${CONFIG_FILE}" 2>/dev/null | tr -d '"')" -NFS_MEDIA_PATH="$(yq '.apps.nfs.mediaPath' "${CONFIG_FILE}" 2>/dev/null | tr -d '"')" -NFS_STORAGE_CAPACITY="$(yq '.apps.nfs.storageCapacity' "${CONFIG_FILE}" 2>/dev/null | tr -d '"')" - -echo "NFS Configuration:" -echo " Host: ${NFS_HOST}" -echo " Media path: ${NFS_MEDIA_PATH}" -echo " Storage capacity: ${NFS_STORAGE_CAPACITY}" -echo "" - -if [ -z "${NFS_HOST}" ] || [ "${NFS_HOST}" = "null" ]; then - echo "ERROR: apps.nfs.host not set in config" - exit 1 -fi -if [ -z "${NFS_MEDIA_PATH}" ] || [ "${NFS_MEDIA_PATH}" = "null" ]; then - echo "ERROR: apps.nfs.mediaPath not set in config" - exit 1 -fi -if [ -z "${NFS_STORAGE_CAPACITY}" ] || [ "${NFS_STORAGE_CAPACITY}" = "null" ]; then - echo "ERROR: apps.nfs.storageCapacity not set in config" - exit 1 -fi - -resolve_nfs_host() { - echo "Resolving NFS host: ${NFS_HOST}" - if [[ "${NFS_HOST}" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - NFS_HOST_IP="${NFS_HOST}" - echo " Host is already an IP address" - else - echo " Looking up hostname..." - NFS_HOST_IP=$(getent hosts "${NFS_HOST}" 2>/dev/null | awk '{print $1}' | head -n1 || true) - echo " Resolved to: ${NFS_HOST_IP}" - if [[ -z "${NFS_HOST_IP}" ]]; then - echo "ERROR: Unable to resolve hostname ${NFS_HOST} to IP address" - echo "Make sure ${NFS_HOST} is resolvable from this cluster" - exit 1 - fi - - if [[ "${NFS_HOST_IP}" =~ ^127\. ]]; then - echo "Warning: ${NFS_HOST} resolves to localhost (${NFS_HOST_IP})" - echo "Auto-detecting network IP for cluster access..." - - local network_ip=$(ip route get 8.8.8.8 | grep -oP 'src \K\S+' 2>/dev/null) - - if [[ -n "${network_ip}" && ! "${network_ip}" =~ ^127\. ]]; then - echo "Using detected network IP: ${network_ip}" - NFS_HOST_IP="${network_ip}" - else - echo "ERROR: Could not auto-detect network IP. Available IPs:" - ip addr show | grep "inet " | grep -v "127.0.0.1" | grep -v "10.42" | grep -v "172." | awk '{print " " $2}' | cut -d/ -f1 - echo "Please set NFS_HOST to the correct IP address manually." - exit 1 - fi - fi - fi - - echo "NFS server IP: ${NFS_HOST_IP}" - export NFS_HOST_IP -} - -test_nfs_accessibility() { - echo "" - echo "Testing NFS accessibility from cluster..." - - if ! command -v showmount >/dev/null 2>&1; then - echo "Installing NFS client tools..." - if command -v apt-get >/dev/null 2>&1; then - sudo apt-get update && sudo apt-get install -y nfs-common - elif command -v yum >/dev/null 2>&1; then - sudo yum install -y nfs-utils - elif command -v dnf >/dev/null 2>&1; then - sudo dnf install -y nfs-utils - else - echo "Warning: Unable to install NFS client tools. Skipping accessibility test." - return 0 - fi - fi - - echo "Testing connection to NFS server..." - if timeout 10 showmount -e "${NFS_HOST_IP}" >/dev/null 2>&1; then - echo "NFS server is accessible" - echo "Available exports:" - showmount -e "${NFS_HOST_IP}" - else - echo "ERROR: Cannot connect to NFS server at ${NFS_HOST_IP}" - echo "Make sure:" - echo " 1. NFS server is running on ${NFS_HOST}" - echo " 2. Network connectivity exists between cluster and NFS host" - echo " 3. Firewall allows NFS traffic (port 2049)" - exit 1 - fi - - if showmount -e "${NFS_HOST_IP}" | grep -q "${NFS_MEDIA_PATH}"; then - echo "Media path ${NFS_MEDIA_PATH} is exported" - else - echo "ERROR: Media path ${NFS_MEDIA_PATH} is not found in exports" - echo "Available exports:" - showmount -e "${NFS_HOST_IP}" - echo "" - echo "Run setup-nfs-host.sh on ${NFS_HOST} to configure the export" - exit 1 - fi -} - -test_nfs_mount() { - echo "" - echo "Testing NFS mount functionality..." - - local test_mount="/tmp/nfs-test-$$" - mkdir -p "${test_mount}" - - if timeout 30 sudo mount -t nfs4 "${NFS_HOST_IP}:${NFS_MEDIA_PATH}" "${test_mount}"; then - echo "NFS mount successful" - - if ls "${test_mount}" >/dev/null 2>&1; then - echo "NFS read access working" - else - echo "ERROR: NFS read access failed" - fi - - sudo umount "${test_mount}" || echo "Warning: Failed to unmount test directory" - else - echo "ERROR: NFS mount failed" - echo "Check NFS server configuration and network connectivity" - exit 1 - fi - - rmdir "${test_mount}" 2>/dev/null || true -} - -create_k8s_resources() { - echo "" - echo "Creating Kubernetes NFS resources..." - - echo "Applying NFS manifests..." - kubectl apply -k "${NFS_DIR}/" - - echo "NFS PersistentVolume and StorageClass created" - - echo "Verifying Kubernetes resources..." - if kubectl get storageclass nfs >/dev/null 2>&1; then - echo "StorageClass 'nfs' created" - else - echo "ERROR: StorageClass 'nfs' not found" - exit 1 - fi - - if kubectl get pv nfs-media-pv >/dev/null 2>&1; then - echo "PersistentVolume 'nfs-media-pv' created" - kubectl get pv nfs-media-pv - else - echo "ERROR: PersistentVolume 'nfs-media-pv' not found" - exit 1 - fi -} - -show_usage_instructions() { - echo "" - echo "=== NFS Kubernetes Setup Complete ===" - echo "" - echo "NFS server ${NFS_HOST} (${NFS_HOST_IP}) has been registered with the cluster" - echo "" - echo "Kubernetes resources created:" - echo " - StorageClass: nfs" - echo " - PersistentVolume: nfs-media-pv (${NFS_STORAGE_CAPACITY}, ReadWriteMany)" - echo "" - echo "To use NFS storage in your applications:" - echo " 1. Set storageClassName: nfs in your PVC" - echo " 2. Use accessMode: ReadWriteMany for shared access" - echo "" - echo "Example PVC:" - echo "---" - echo "apiVersion: v1" - echo "kind: PersistentVolumeClaim" - echo "metadata:" - echo " name: my-nfs-pvc" - echo "spec:" - echo " accessModes:" - echo " - ReadWriteMany" - echo " storageClassName: nfs" - echo " resources:" - echo " requests:" - echo " storage: 10Gi" - echo "" -} - -main() { - resolve_nfs_host - test_nfs_accessibility - test_nfs_mount - create_k8s_resources - show_usage_instructions -} - -echo "Starting NFS setup process..." -main "$@" diff --git a/nfs/manifest.yaml b/nfs/manifest.yaml index 8b669a0..e4ed3aa 100644 --- a/nfs/manifest.yaml +++ b/nfs/manifest.yaml @@ -1,10 +1,12 @@ name: nfs is: nfs description: NFS client provisioner for external NFS storage -version: v4.0.18 -deploymentName: "" -storageClassName: "nfs" +version: v4.0.18-2 category: infrastructure +scripts: + - name: check-nfs + path: scripts/check-nfs.sh + description: Verify NFS server is reachable and the export path is available defaultConfig: namespace: nfs host: "192.168.1.100" diff --git a/nfs/scripts/check-nfs.sh b/nfs/scripts/check-nfs.sh new file mode 100755 index 0000000..05d3252 --- /dev/null +++ b/nfs/scripts/check-nfs.sh @@ -0,0 +1,79 @@ +#!/bin/bash +# Verify NFS server is reachable and the export path is available. +# Run before or after deployment to validate NFS connectivity. +set -e +set -o pipefail + +if [ -z "${WILD_INSTANCE}" ] || [ -z "${WILD_API_DATA_DIR}" ]; then + echo "ERROR: WILD_INSTANCE and WILD_API_DATA_DIR must be set" + exit 1 +fi + +CONFIG_FILE="${WILD_API_DATA_DIR}/instances/${WILD_INSTANCE}/config.yaml" + +NFS_HOST="$(yq '.apps.nfs.host' "${CONFIG_FILE}" 2>/dev/null | tr -d '"')" +NFS_PATH="$(yq '.apps.nfs.mediaPath' "${CONFIG_FILE}" 2>/dev/null | tr -d '"')" + +if [ -z "${NFS_HOST}" ] || [ "${NFS_HOST}" = "null" ]; then + echo "ERROR: apps.nfs.host not set in config" + exit 1 +fi +if [ -z "${NFS_PATH}" ] || [ "${NFS_PATH}" = "null" ]; then + echo "ERROR: apps.nfs.mediaPath not set in config" + exit 1 +fi + +echo "NFS host: ${NFS_HOST}" +echo "NFS path: ${NFS_PATH}" + +# Resolve hostname to IP +if [[ "${NFS_HOST}" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + NFS_IP="${NFS_HOST}" +else + NFS_IP=$(getent hosts "${NFS_HOST}" 2>/dev/null | awk '{print $1}' | head -n1 || true) + if [ -z "${NFS_IP}" ]; then + echo "ERROR: Cannot resolve hostname ${NFS_HOST}" + exit 1 + fi + echo "Resolved to: ${NFS_IP}" +fi + +# Check showmount +if ! command -v showmount >/dev/null 2>&1; then + echo "WARNING: showmount not available, skipping export check" +else + echo "" + echo "Checking NFS exports..." + if timeout 10 showmount -e "${NFS_IP}" >/dev/null 2>&1; then + if showmount -e "${NFS_IP}" | grep -q "${NFS_PATH}"; then + echo "OK: ${NFS_PATH} is exported" + else + echo "ERROR: ${NFS_PATH} not found in NFS exports:" + showmount -e "${NFS_IP}" + exit 1 + fi + else + echo "ERROR: Cannot reach NFS server at ${NFS_IP}:2049" + exit 1 + fi +fi + +# Check k8s resources if KUBECONFIG is available +if [ -n "${KUBECONFIG}" ]; then + echo "" + echo "Checking Kubernetes resources..." + if kubectl get storageclass nfs >/dev/null 2>&1; then + echo "OK: StorageClass 'nfs' exists" + else + echo "WARNING: StorageClass 'nfs' not found (deploy NFS first)" + fi + if kubectl get pv nfs-media-pv >/dev/null 2>&1; then + echo "OK: PersistentVolume 'nfs-media-pv' exists" + kubectl get pv nfs-media-pv --no-headers + else + echo "WARNING: PersistentVolume 'nfs-media-pv' not found (deploy NFS first)" + fi +fi + +echo "" +echo "NFS check complete."