Add signed licensing enforcement and ISO notes
This commit is contained in:
1 parent
dee4486826
commit
d645249a13
14 files changed
+1526
-103
No files matched your search
+106
-21
@@ -7,6 +7,9 @@
|
||||
set -e
|
||||
|
||||
AIPACKAGE_DIR="/opt/aipackage"
|
||||
FEASIBILITY_SCRIPT="$AIPACKAGE_DIR/scripts/cezen-feasibility.sh"
|
||||
LICENSE_CHECK_SCRIPT="$AIPACKAGE_DIR/scripts/cezen-license-check.py"
|
||||
PUBLIC_KEY_PATH="${CEZEN_LICENSE_PUBLIC_KEY:-$AIPACKAGE_DIR/autoinstall/keys/cezen-license-public.pem}"
|
||||
LOG_FILE="/var/log/cezen-setup.log"
|
||||
INSTALL_LOG_FILE="/var/log/cezen-install.log"
|
||||
export TERM="${TERM:-linux}"
|
||||
@@ -187,25 +190,106 @@ CONTACT_EMAIL=$(whiptail --title "$TITLE" \
|
||||
--inputbox "\nStep 2 of 4: License & Customer Details\n\nCustomer/admin contact email:\n\nLeave blank if unavailable on site." \
|
||||
$H $W "" 3>&1 1>&2 2>&3)
|
||||
|
||||
LICENSE_KEY=$(whiptail --title "$TITLE" \
|
||||
--passwordbox "\nStep 2 of 4: License & Customer Details\n\nLicense key / activation code:\n\nLeave blank for offline field staging. Models and keys can be added later." \
|
||||
LICENSE_PATH=$(whiptail --title "$TITLE" \
|
||||
--inputbox "\nStep 2 of 4: License & Customer Details\n\nPath to signed license JSON:\n\nLeave blank for offline field staging.\nExample: /media/usb/customer-license.json" \
|
||||
$H $W "" 3>&1 1>&2 2>&3)
|
||||
|
||||
OVERRIDE_PATH=$(whiptail --title "$TITLE" \
|
||||
--inputbox "\nOptional: Cezen hardware override JSON path\n\nLeave blank unless support explicitly provided one." \
|
||||
$H $W "" 3>&1 1>&2 2>&3)
|
||||
|
||||
SUPPORT_UNTIL=$(whiptail --title "$TITLE" \
|
||||
--inputbox "\nStep 2 of 4: License & Customer Details\n\nSupport valid until (YYYY-MM-DD):\n\nLeave blank if not issued yet." \
|
||||
--inputbox "\nStep 2 of 4: License & Customer Details\n\nSupport valid until (YYYY-MM-DD):\n\nOptional local record field for field installs." \
|
||||
$H $W "" 3>&1 1>&2 2>&3)
|
||||
|
||||
mkdir -p /opt/cezen
|
||||
rm -f /opt/cezen/license.json /opt/cezen/license.override.json
|
||||
|
||||
if [ -n "$LICENSE_PATH" ]; then
|
||||
if [ ! -f "$LICENSE_PATH" ]; then
|
||||
whiptail --title "$TITLE" \
|
||||
--msgbox "\nLicense file not found:\n $LICENSE_PATH" \
|
||||
$H $W
|
||||
exit 1
|
||||
fi
|
||||
cp "$LICENSE_PATH" /opt/cezen/license.json
|
||||
chmod 0640 /opt/cezen/license.json
|
||||
chown root:cezen /opt/cezen/license.json 2>/dev/null || true
|
||||
fi
|
||||
|
||||
if [ -n "$OVERRIDE_PATH" ]; then
|
||||
if [ ! -f "$OVERRIDE_PATH" ]; then
|
||||
whiptail --title "$TITLE" \
|
||||
--msgbox "\nOverride file not found:\n $OVERRIDE_PATH" \
|
||||
$H $W
|
||||
exit 1
|
||||
fi
|
||||
cp "$OVERRIDE_PATH" /opt/cezen/license.override.json
|
||||
chmod 0640 /opt/cezen/license.override.json
|
||||
chown root:cezen /opt/cezen/license.override.json 2>/dev/null || true
|
||||
fi
|
||||
|
||||
bash "$FEASIBILITY_SCRIPT" /opt/cezen/feasibility.json >> "$LOG_FILE" 2>&1
|
||||
python3 "$LICENSE_CHECK_SCRIPT" \
|
||||
--license /opt/cezen/license.json \
|
||||
--override /opt/cezen/license.override.json \
|
||||
--feasibility /opt/cezen/feasibility.json \
|
||||
--public-key "$PUBLIC_KEY_PATH" > /tmp/cezen-license-check.json
|
||||
|
||||
LICENSE_STATUS=$(python3 - <<'PY'
|
||||
import json
|
||||
d=json.load(open("/tmp/cezen-license-check.json"))
|
||||
print((d.get("license") or {}).get("status","missing"))
|
||||
PY
|
||||
)
|
||||
LICENSE_ALLOWED_TIER=$(python3 - <<'PY'
|
||||
import json
|
||||
d=json.load(open("/tmp/cezen-license-check.json"))
|
||||
print((d.get("license") or {}).get("allowed_tier","basic"))
|
||||
PY
|
||||
)
|
||||
HARDWARE_TIER=$(python3 - <<'PY'
|
||||
import json
|
||||
d=json.load(open("/tmp/cezen-license-check.json"))
|
||||
print((d.get("hardware") or {}).get("recommended_tier","starter"))
|
||||
PY
|
||||
)
|
||||
|
||||
# ════════════════════════════════════════════════════════════
|
||||
# STEP 3: SELECT TIER
|
||||
# ════════════════════════════════════════════════════════════
|
||||
|
||||
mapfile -t TIER_MENU < <(python3 - <<'PY'
|
||||
import json
|
||||
d=json.load(open("/tmp/cezen-license-check.json"))
|
||||
labels = {
|
||||
"starter": "Starter — 1x RTX 5090 / 32GB VRAM · Small team",
|
||||
"basic": "Entry — 1x NVIDIA RTX Pro 6000 (96GB) · Up to 20 users",
|
||||
"pro": "Pro — 2x RTX 5090 / RTX Pro class · Up to 100 users",
|
||||
"max": "Max — 4-8x H100/H200/A100 class · 100+ users",
|
||||
}
|
||||
for opt in d.get("tier_options", []):
|
||||
if opt.get("selectable"):
|
||||
print(opt["tier"])
|
||||
print(labels.get(opt["tier"], opt["tier"]))
|
||||
PY
|
||||
)
|
||||
|
||||
if [ "${#TIER_MENU[@]}" -eq 0 ]; then
|
||||
whiptail --title "$TITLE" \
|
||||
--msgbox "\nNo installable tiers are available.\n\nLicense status: ${LICENSE_STATUS}\nHardware recommendation: ${HARDWARE_TIER}\n\nCheck the signed license or contact Cezen support." \
|
||||
$H $W
|
||||
exit 1
|
||||
fi
|
||||
|
||||
whiptail --title "$TITLE" \
|
||||
--msgbox "\nLicense status: ${LICENSE_STATUS}\nAllowed tier: ${LICENSE_ALLOWED_TIER}\nHardware recommendation: ${HARDWARE_TIER}\n\nOnly valid tiers will be shown next." \
|
||||
$H $W
|
||||
|
||||
TIER=$(whiptail --title "$TITLE" \
|
||||
--menu "\nStep 3 of 4: Select AI Package Tier\n\nChoose the tier that matches your hardware:" \
|
||||
--menu "\nStep 3 of 4: Select AI Package Tier\n\nChoose the tier allowed by your license and hardware:" \
|
||||
$H $W 4 \
|
||||
"starter" "Starter — 1× RTX 5090 / 32GB VRAM · Small team" \
|
||||
"basic" "Entry — 1× NVIDIA RTX Pro 6000 (96GB) · Up to 20 users" \
|
||||
"pro" "Pro — 2× RTX 5090 / RTX Pro class · Up to 100 users" \
|
||||
"max" "Max — 4–8× H100/H200/A100 class · 100+ users" \
|
||||
"${TIER_MENU[@]}" \
|
||||
3>&1 1>&2 2>&3)
|
||||
|
||||
# ════════════════════════════════════════════════════════════
|
||||
@@ -233,12 +317,12 @@ TOOLS=$(whiptail --title "$TITLE" \
|
||||
TOOLS_DISPLAY=$(echo "$TOOLS" | tr -d '"' | tr ' ' '\n' | sed 's/^/ · /' | tr '\n' '\n')
|
||||
MY_IP=$(hostname -I | awk '{print $1}')
|
||||
LICENSE_DISPLAY="Field staging / evaluation"
|
||||
if [ -n "$LICENSE_KEY" ]; then
|
||||
LICENSE_DISPLAY="Provided"
|
||||
if [ -n "$LICENSE_PATH" ]; then
|
||||
LICENSE_DISPLAY="Signed file (${LICENSE_STATUS})"
|
||||
fi
|
||||
|
||||
whiptail --title "$TITLE" \
|
||||
--yesno "\nReady to install. Please confirm:\n\nNetwork: ${NET_MODE} (${MY_IP})\nCustomer: ${CUSTOMER_NAME:-Not entered}\nLicense: ${LICENSE_DISPLAY}\nTier: ${TIER}\n\nTools:\n${TOOLS_DISPLAY}\n\nThis will take 20–40 minutes.\nThe server will reboot once during install (NVIDIA drivers).\n\nContinue?" \
|
||||
--yesno "\nReady to install. Please confirm:\n\nNetwork: ${NET_MODE} (${MY_IP})\nCustomer: ${CUSTOMER_NAME:-Not entered}\nLicense: ${LICENSE_DISPLAY}\nAllowed: ${LICENSE_ALLOWED_TIER}\nHardware: ${HARDWARE_TIER}\nTier: ${TIER}\n\nTools:\n${TOOLS_DISPLAY}\n\nThis will take 20–40 minutes.\nThe server will reboot once during install (NVIDIA drivers).\n\nContinue?" \
|
||||
$H $W
|
||||
|
||||
# ════════════════════════════════════════════════════════════
|
||||
@@ -271,29 +355,30 @@ TIER=${TIER}
|
||||
SKIP_ROLES=${SKIP_ROLES}
|
||||
EOF
|
||||
|
||||
export CUSTOMER_NAME CUSTOMER_ID CONTACT_EMAIL LICENSE_KEY SUPPORT_UNTIL TIER
|
||||
export CUSTOMER_NAME CUSTOMER_ID CONTACT_EMAIL SUPPORT_UNTIL TIER LICENSE_STATUS LICENSE_ALLOWED_TIER HARDWARE_TIER
|
||||
python3 - <<'PY'
|
||||
import json, os, time
|
||||
|
||||
payload = {
|
||||
"schema": "cezen.license.v1",
|
||||
"schema": "cezen.install_record.v1",
|
||||
"customer_name": os.environ.get("CUSTOMER_NAME", "").strip(),
|
||||
"customer_id": os.environ.get("CUSTOMER_ID", "").strip(),
|
||||
"contact_email": os.environ.get("CONTACT_EMAIL", "").strip(),
|
||||
"license_key": os.environ.get("LICENSE_KEY", "").strip(),
|
||||
"tier": os.environ.get("TIER", "basic").strip(),
|
||||
"selected_tier": os.environ.get("TIER", "basic").strip(),
|
||||
"provisioned_tier": os.environ.get("TIER", "basic").strip(),
|
||||
"support_until": os.environ.get("SUPPORT_UNTIL", "").strip(),
|
||||
"install_type": "licensed" if os.environ.get("LICENSE_KEY", "").strip() else "field-staging",
|
||||
"issued_by": "Cezen",
|
||||
"install_type": "licensed" if os.path.exists("/opt/cezen/license.json") else "field-staging",
|
||||
"license_status": os.environ.get("LICENSE_STATUS", "missing").strip(),
|
||||
"licensed_tier": os.environ.get("LICENSE_ALLOWED_TIER", "basic").strip(),
|
||||
"hardware_recommended_tier": os.environ.get("HARDWARE_TIER", "starter").strip(),
|
||||
"captured_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
|
||||
"signature_status": "unsigned-field-install",
|
||||
}
|
||||
|
||||
with open("/opt/cezen/license.json", "w") as f:
|
||||
with open("/opt/cezen/install-record.json", "w") as f:
|
||||
json.dump(payload, f, indent=2)
|
||||
PY
|
||||
chown root:cezen /opt/cezen/license.json 2>/dev/null || true
|
||||
chmod 0640 /opt/cezen/license.json
|
||||
chown root:cezen /opt/cezen/install-record.json 2>/dev/null || true
|
||||
chmod 0640 /opt/cezen/install-record.json
|
||||
|
||||
whiptail --title "$TITLE" \
|
||||
--infobox "\nInstalling Nexus One AI stack...\n\nThis can take several minutes.\n\nLogs are being written to:\n $INSTALL_LOG_FILE" \
|
||||
|
||||
Reference in new issue
Block a user