modify sonarqube
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
# Calypso Appliance - Airgap Installation Bundle
|
||||
|
||||
**Version:** 1.0.0
|
||||
**Target OS:** Ubuntu Server 24.04 LTS
|
||||
**Installation Type:** Offline/Airgap
|
||||
|
||||
## Bundle Contents
|
||||
|
||||
- **binaries/**: Pre-built Calypso binaries
|
||||
- **frontend/**: Built frontend assets
|
||||
- **packages/debs/**: All required DEB packages with dependencies (59 packages + ~200-300 dependencies)
|
||||
- **scripts/**: Installation scripts
|
||||
- **services/**: Systemd service files
|
||||
- **migrations/**: Database migration files
|
||||
- **configs/**: Configuration templates
|
||||
- **third_party/**: Optional third-party binaries (Go, Node.js)
|
||||
|
||||
## Installation
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Ubuntu Server 24.04 LTS
|
||||
- Root or sudo access
|
||||
- Minimum 10GB free disk space
|
||||
- Kernel headers installed (for kernel modules)
|
||||
|
||||
### Quick Install
|
||||
|
||||
```bash
|
||||
cd /path/to/bundle
|
||||
sudo ./install-airgap.sh
|
||||
```
|
||||
|
||||
The installer will:
|
||||
1. Install all packages from bundled DEB files
|
||||
2. Install Calypso binaries and frontend
|
||||
3. Setup database and configuration
|
||||
4. Install systemd services
|
||||
|
||||
### Post-Installation
|
||||
|
||||
1. Review configuration: `/etc/calypso/calypso.yaml`
|
||||
2. Install kernel modules (ZFS, SCST, mhVTL) if needed
|
||||
3. Start services: `systemctl start calypso-api`
|
||||
4. Enable services: `systemctl enable calypso-api`
|
||||
|
||||
## Verification
|
||||
|
||||
Check service status:
|
||||
```bash
|
||||
systemctl status calypso-api
|
||||
curl http://localhost:8080/api/v1/health
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
For issues, check:
|
||||
- Installation logs: `/var/log/calypso/install.log`
|
||||
- Service logs: `journalctl -u calypso-api`
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,64 @@
|
||||
# AtlasOS - Calypso API Configuration Template
|
||||
# This file will be copied to /etc/calypso/config.yaml during installation
|
||||
# Environment variables from /etc/calypso/secrets.env will be used for sensitive values
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
host: "0.0.0.0"
|
||||
read_timeout: 15s
|
||||
write_timeout: 15s
|
||||
idle_timeout: 60s
|
||||
# Response caching configuration
|
||||
cache:
|
||||
enabled: true # Enable response caching
|
||||
default_ttl: 5m # Default cache TTL (5 minutes)
|
||||
max_age: 300 # Cache-Control max-age in seconds (5 minutes)
|
||||
|
||||
database:
|
||||
host: "localhost"
|
||||
port: 5432
|
||||
user: "calypso"
|
||||
password: "" # Set via CALYPSO_DB_PASSWORD environment variable
|
||||
database: "calypso"
|
||||
ssl_mode: "disable"
|
||||
# Connection pool optimization
|
||||
max_connections: 25
|
||||
max_idle_conns: 5
|
||||
conn_max_lifetime: 5m
|
||||
|
||||
auth:
|
||||
jwt_secret: "" # Set via CALYPSO_JWT_SECRET environment variable
|
||||
token_lifetime: 24h
|
||||
argon2:
|
||||
memory: 65536 # 64 MB
|
||||
iterations: 3
|
||||
parallelism: 4
|
||||
salt_length: 16
|
||||
key_length: 32
|
||||
|
||||
logging:
|
||||
level: "info" # debug, info, warn, error
|
||||
format: "json" # json or text
|
||||
|
||||
# CORS configuration
|
||||
cors:
|
||||
allowed_origins:
|
||||
- "http://localhost:3000"
|
||||
- "http://localhost:5173"
|
||||
allowed_methods:
|
||||
- "GET"
|
||||
- "POST"
|
||||
- "PUT"
|
||||
- "DELETE"
|
||||
- "PATCH"
|
||||
allowed_headers:
|
||||
- "Content-Type"
|
||||
- "Authorization"
|
||||
allow_credentials: true
|
||||
|
||||
# Rate limiting
|
||||
rate_limit:
|
||||
enabled: true
|
||||
requests_per_minute: 100
|
||||
authenticated_requests_per_minute: 200
|
||||
|
||||
+66
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+207
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+6
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+3
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+2
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+2
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+2
@@ -0,0 +1,2 @@
|
||||
|
||||
//# sourceMappingURL=terminal-vendor-l0sNRNKZ.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"terminal-vendor-l0sNRNKZ.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
||||
+2
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+7
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,29 @@
|
||||
<!doctype html>
|
||||
<html class="dark" lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/png" href="/logo.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>AtlasOS - Calypso</title>
|
||||
<!-- Material Symbols -->
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<script type="module" crossorigin src="/assets/index-ChZMKDzx.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/react-vendor-Dvs2KPqW.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/query-vendor-BeRQtQod.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/utils-vendor-CJpcXyE0.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/ui-vendor-C4xvlrdo.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/chart-vendor-CnBPFalK.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BY0QR2-n.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
+215
@@ -0,0 +1,215 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Calypso Appliance - Airgap Installer
|
||||
# Installs Calypso from bundled files without internet connection
|
||||
#
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
BUNDLE_DIR="$SCRIPT_DIR"
|
||||
VERSION="${VERSION:-1.0.0}"
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
|
||||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
log_step() { echo -e "\n${BLUE}==>${NC} $1"; }
|
||||
|
||||
# Check root
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
log_error "This script must be run as root (use sudo)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check OS
|
||||
if [ ! -f /etc/os-release ]; then
|
||||
log_error "Cannot detect OS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
. /etc/os-release
|
||||
if [[ "$ID" != "ubuntu" ]] || [[ "$VERSION_ID" != "24.04" ]]; then
|
||||
log_warn "This installer is designed for Ubuntu 24.04 LTS"
|
||||
log_warn "Detected: $ID $VERSION_ID"
|
||||
read -p "Continue anyway? (y/N) " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
log_step "Calypso Appliance - Airgap Installation"
|
||||
log_info "Bundle directory: $BUNDLE_DIR"
|
||||
|
||||
# 1. Install packages from bundle
|
||||
log_step "Installing system packages from bundle..."
|
||||
|
||||
if [ -d "$BUNDLE_DIR/packages/debs" ] && [ "$(ls -A $BUNDLE_DIR/packages/debs/*.deb 2>/dev/null)" ]; then
|
||||
log_info "Installing packages from bundle..."
|
||||
|
||||
# Create local apt repository
|
||||
DEBS_DIR="$BUNDLE_DIR/packages/debs"
|
||||
REPO_DIR="/tmp/calypso-local-repo"
|
||||
|
||||
mkdir -p "$REPO_DIR"
|
||||
cp "$DEBS_DIR"/*.deb "$REPO_DIR/" 2>/dev/null || true
|
||||
|
||||
# Create Packages.gz if not exists
|
||||
cd "$REPO_DIR"
|
||||
if [ ! -f Packages.gz ]; then
|
||||
dpkg-scanpackages . /dev/null 2>/dev/null | gzip -9c > Packages.gz
|
||||
fi
|
||||
|
||||
# Add to sources.list temporarily
|
||||
echo "deb [trusted=yes] file://$REPO_DIR ./" > /tmp/calypso-local.list
|
||||
mv /tmp/calypso-local.list /etc/apt/sources.list.d/calypso-local.list
|
||||
|
||||
# Update apt cache
|
||||
apt-get update -qq
|
||||
|
||||
# Install packages from list
|
||||
PACKAGE_LIST="$BUNDLE_DIR/packages/package-list.txt"
|
||||
PACKAGES=$(grep -v '^#' "$PACKAGE_LIST" | grep -v '^$' | tr '\n' ' ')
|
||||
|
||||
log_info "Installing packages..."
|
||||
apt-get install -y --allow-unauthenticated $PACKAGES || {
|
||||
log_warn "Some packages failed to install, trying individual installation..."
|
||||
while IFS= read -r package || [ -n "$package" ]; do
|
||||
[[ "$package" =~ ^#.*$ ]] && continue
|
||||
[[ -z "$package" ]] && continue
|
||||
apt-get install -y --allow-unauthenticated "$package" 2>/dev/null || log_warn "Failed: $package"
|
||||
done < "$PACKAGE_LIST"
|
||||
}
|
||||
|
||||
# Cleanup
|
||||
rm -f /etc/apt/sources.list.d/calypso-local.list
|
||||
apt-get update -qq
|
||||
|
||||
log_info "✓ Packages installed from bundle"
|
||||
else
|
||||
log_warn "Package DEB files not found in bundle"
|
||||
log_warn "You need to install packages manually"
|
||||
log_info "Package list: $BUNDLE_DIR/packages/package-list.txt"
|
||||
read -p "Install packages from system repositories? (y/N) " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
apt-get update
|
||||
xargs -a "$BUNDLE_DIR/packages/package-list.txt" -r apt-get install -y
|
||||
fi
|
||||
fi
|
||||
|
||||
# 2. Install Go from bundle (if available)
|
||||
if [ -f "$BUNDLE_DIR/third_party/go.tar.gz" ]; then
|
||||
log_step "Installing Go from bundle..."
|
||||
rm -rf /usr/local/go
|
||||
tar -C /usr/local -xzf "$BUNDLE_DIR/third_party/go.tar.gz"
|
||||
export PATH=$PATH:/usr/local/go/bin
|
||||
if ! grep -q "/usr/local/go/bin" /etc/profile; then
|
||||
echo 'export PATH=$PATH:/usr/local/go/bin' >> /etc/profile
|
||||
fi
|
||||
log_info "✓ Go installed"
|
||||
fi
|
||||
|
||||
# 3. Install Node.js from bundle (if available)
|
||||
if [ -f "$BUNDLE_DIR/third_party/nodejs.tar.xz" ]; then
|
||||
log_step "Installing Node.js from bundle..."
|
||||
rm -rf /usr/local/node
|
||||
mkdir -p /usr/local/node
|
||||
tar -C /usr/local/node -xJf "$BUNDLE_DIR/third_party/nodejs.tar.xz" --strip-components=1
|
||||
export PATH=$PATH:/usr/local/node/bin
|
||||
if ! grep -q "/usr/local/node/bin" /etc/profile; then
|
||||
echo 'export PATH=$PATH:/usr/local/node/bin' >> /etc/profile
|
||||
fi
|
||||
log_info "✓ Node.js installed"
|
||||
fi
|
||||
|
||||
# 4. Create filesystem structure
|
||||
log_step "Creating filesystem structure..."
|
||||
INSTALL_PREFIX="/opt/adastra/calypso"
|
||||
CONFIG_DIR="/etc/calypso"
|
||||
DATA_DIR="/srv/calypso"
|
||||
LOG_DIR="/var/log/calypso"
|
||||
LIB_DIR="/var/lib/calypso"
|
||||
|
||||
mkdir -p "$INSTALL_PREFIX/releases/${VERSION}"/{bin,web,migrations,scripts}
|
||||
mkdir -p "$INSTALL_PREFIX/third_party"
|
||||
mkdir -p "$CONFIG_DIR"/{tls,integrations,system,scst,nfs,samba,clamav}
|
||||
mkdir -p "$DATA_DIR"/{db,backups,object,shares,vtl,iscsi,uploads,cache,_system,quarantine}
|
||||
mkdir -p "$LOG_DIR" "$LIB_DIR" "/run/calypso"
|
||||
|
||||
# Create calypso user
|
||||
if ! id "calypso" &>/dev/null; then
|
||||
useradd -r -s /bin/false -d "$LIB_DIR" -c "Calypso Appliance" calypso
|
||||
fi
|
||||
|
||||
# 5. Install binaries
|
||||
log_step "Installing Calypso binaries..."
|
||||
cp "$BUNDLE_DIR/binaries/calypso-api" "$INSTALL_PREFIX/releases/${VERSION}/bin/"
|
||||
chmod +x "$INSTALL_PREFIX/releases/${VERSION}/bin/calypso-api"
|
||||
|
||||
# Install frontend
|
||||
cp -r "$BUNDLE_DIR/frontend"/* "$INSTALL_PREFIX/releases/${VERSION}/web/"
|
||||
|
||||
# Install migrations
|
||||
cp -r "$BUNDLE_DIR/migrations"/* "$INSTALL_PREFIX/releases/${VERSION}/migrations/" 2>/dev/null || true
|
||||
|
||||
# Install scripts
|
||||
cp -r "$BUNDLE_DIR/scripts"/* "$INSTALL_PREFIX/releases/${VERSION}/scripts/" 2>/dev/null || true
|
||||
chmod +x "$INSTALL_PREFIX/releases/${VERSION}/scripts"/*.sh 2>/dev/null || true
|
||||
|
||||
# Create symlink
|
||||
ln -sfn "releases/${VERSION}" "$INSTALL_PREFIX/current"
|
||||
|
||||
# Set ownership
|
||||
chown -R calypso:calypso "$INSTALL_PREFIX" "$LIB_DIR" "$LOG_DIR" "$DATA_DIR" 2>/dev/null || chown -R root:root "$INSTALL_PREFIX" "$LIB_DIR" "$LOG_DIR" "$DATA_DIR"
|
||||
|
||||
log_info "✓ Binaries installed"
|
||||
|
||||
# 6. Install systemd services
|
||||
log_step "Installing systemd services..."
|
||||
if [ -d "$BUNDLE_DIR/services" ]; then
|
||||
cp "$BUNDLE_DIR/services"/*.service /etc/systemd/system/ 2>/dev/null || true
|
||||
systemctl daemon-reload
|
||||
log_info "✓ Systemd services installed"
|
||||
fi
|
||||
|
||||
# 7. Setup database
|
||||
log_step "Setting up database..."
|
||||
if systemctl is-active --quiet postgresql 2>/dev/null || systemctl is-enabled --quiet postgresql 2>/dev/null; then
|
||||
sudo -u postgres createdb calypso 2>/dev/null || true
|
||||
sudo -u postgres createuser calypso 2>/dev/null || true
|
||||
sudo -u postgres psql -c "ALTER USER calypso WITH PASSWORD 'calypso_change_me';" 2>/dev/null || true
|
||||
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE calypso TO calypso;" 2>/dev/null || true
|
||||
log_info "✓ Database setup complete"
|
||||
else
|
||||
log_warn "PostgreSQL not running. Please start it and run database setup manually."
|
||||
fi
|
||||
|
||||
# 8. Generate configuration
|
||||
log_step "Generating configuration..."
|
||||
if [ -f "$BUNDLE_DIR/configs/config.yaml.template" ]; then
|
||||
cp "$BUNDLE_DIR/configs/config.yaml.template" "$CONFIG_DIR/calypso.yaml"
|
||||
# Generate secrets
|
||||
if command -v openssl &> /dev/null; then
|
||||
JWT_SECRET=$(openssl rand -hex 32)
|
||||
sed -i "s/CHANGE_ME_JWT_SECRET/$JWT_SECRET/g" "$CONFIG_DIR/calypso.yaml"
|
||||
fi
|
||||
log_info "✓ Configuration generated"
|
||||
fi
|
||||
|
||||
log_step "Installation Complete!"
|
||||
log_info ""
|
||||
log_info "Next steps:"
|
||||
log_info "1. Review configuration: $CONFIG_DIR/calypso.yaml"
|
||||
log_info "2. Install kernel modules (ZFS, SCST, mhVTL) if needed"
|
||||
log_info "3. Start services: systemctl start calypso-api"
|
||||
log_info "4. Enable services: systemctl enable calypso-api"
|
||||
log_info ""
|
||||
log_info "Calypso API will be available at: http://localhost:8080"
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# AtlasOS - Calypso Appliance Installer
|
||||
# Complete installation script for Calypso backup appliance
|
||||
# Target OS: Ubuntu Server 24.04 LTS
|
||||
#
|
||||
# Usage: sudo ./installer/alpha/install.sh [options]
|
||||
#
|
||||
# Options:
|
||||
# --version VERSION Install specific version (default: auto-detect)
|
||||
# --skip-deps Skip system dependencies installation
|
||||
# --skip-zfs Skip ZFS installation
|
||||
# --skip-scst Skip SCST installation
|
||||
# --skip-mhvtl Skip MHVTL installation
|
||||
# --skip-bacula Skip Bacula installation
|
||||
# --config-only Only setup configuration, don't install binaries
|
||||
#
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Script directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
INSTALLER_DIR="$SCRIPT_DIR"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Logging functions
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
log_step() {
|
||||
echo -e "\n${BLUE}==>${NC} $1"
|
||||
}
|
||||
|
||||
# Configuration
|
||||
CALYPSO_VERSION="${CALYPSO_VERSION:-1.0.0-alpha}"
|
||||
INSTALL_PREFIX="/opt/adastra/calypso"
|
||||
CONFIG_DIR="/etc/calypso"
|
||||
DATA_DIR="/srv/calypso"
|
||||
LOG_DIR="/var/log/calypso"
|
||||
LIB_DIR="/var/lib/calypso"
|
||||
RUN_DIR="/run/calypso"
|
||||
|
||||
# Flags
|
||||
SKIP_DEPS=false
|
||||
SKIP_ZFS=false
|
||||
SKIP_SCST=false
|
||||
SKIP_MHVTL=false
|
||||
SKIP_BACULA=false
|
||||
CONFIG_ONLY=false
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--version)
|
||||
CALYPSO_VERSION="$2"
|
||||
shift 2
|
||||
;;
|
||||
--skip-deps)
|
||||
SKIP_DEPS=true
|
||||
shift
|
||||
;;
|
||||
--skip-zfs)
|
||||
SKIP_ZFS=true
|
||||
shift
|
||||
;;
|
||||
--skip-scst)
|
||||
SKIP_SCST=true
|
||||
shift
|
||||
;;
|
||||
--skip-mhvtl)
|
||||
SKIP_MHVTL=true
|
||||
shift
|
||||
;;
|
||||
--skip-bacula)
|
||||
SKIP_BACULA=true
|
||||
shift
|
||||
;;
|
||||
--config-only)
|
||||
CONFIG_ONLY=true
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Check if running as root
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
log_error "This script must be run as root (use sudo)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Detect OS
|
||||
if ! grep -q "Ubuntu" /etc/os-release 2>/dev/null; then
|
||||
log_warn "This installer is designed for Ubuntu. Proceeding anyway..."
|
||||
fi
|
||||
|
||||
log_info "=========================================="
|
||||
log_info "AtlasOS - Calypso Appliance Installer"
|
||||
log_info "Version: ${CALYPSO_VERSION}"
|
||||
log_info "=========================================="
|
||||
log_info ""
|
||||
|
||||
# Source helper scripts
|
||||
source "$INSTALLER_DIR/scripts/helpers.sh"
|
||||
source "$INSTALLER_DIR/scripts/filesystem.sh"
|
||||
source "$INSTALLER_DIR/scripts/dependencies.sh"
|
||||
source "$INSTALLER_DIR/scripts/components.sh"
|
||||
source "$INSTALLER_DIR/scripts/application.sh"
|
||||
source "$INSTALLER_DIR/scripts/database.sh"
|
||||
source "$INSTALLER_DIR/scripts/services.sh"
|
||||
source "$INSTALLER_DIR/scripts/configuration.sh"
|
||||
source "$INSTALLER_DIR/scripts/configure-services.sh"
|
||||
source "$INSTALLER_DIR/scripts/post-install.sh"
|
||||
|
||||
# Main installation function
|
||||
main() {
|
||||
log_step "Starting Calypso Appliance Installation"
|
||||
|
||||
# Pre-flight checks
|
||||
log_step "Pre-flight Checks"
|
||||
check_prerequisites
|
||||
|
||||
# Create filesystem structure
|
||||
log_step "Creating Filesystem Structure"
|
||||
create_filesystem_structure
|
||||
|
||||
# Install system dependencies
|
||||
if [[ "$SKIP_DEPS" == "false" ]]; then
|
||||
log_step "Installing System Dependencies"
|
||||
install_system_dependencies
|
||||
else
|
||||
log_info "Skipping system dependencies installation"
|
||||
fi
|
||||
|
||||
# Install components
|
||||
if [[ "$SKIP_ZFS" == "false" ]]; then
|
||||
log_step "Installing ZFS"
|
||||
install_zfs || log_warn "ZFS installation failed or already installed"
|
||||
fi
|
||||
|
||||
if [[ "$SKIP_SCST" == "false" ]]; then
|
||||
log_step "Installing SCST"
|
||||
install_scst || log_warn "SCST installation failed or already installed"
|
||||
fi
|
||||
|
||||
if [[ "$SKIP_MHVTL" == "false" ]]; then
|
||||
log_step "Installing MHVTL"
|
||||
install_mhvtl || log_warn "MHVTL installation failed or already installed"
|
||||
fi
|
||||
|
||||
if [[ "$SKIP_BACULA" == "false" ]]; then
|
||||
log_step "Installing Bacula (Optional)"
|
||||
install_bacula || log_warn "Bacula installation skipped or failed"
|
||||
fi
|
||||
|
||||
# File sharing services are installed in dependencies step
|
||||
# ClamAV is installed in dependencies step
|
||||
|
||||
# Build and install application
|
||||
if [[ "$CONFIG_ONLY" == "false" ]]; then
|
||||
log_step "Building and Installing Application"
|
||||
build_and_install_application
|
||||
else
|
||||
log_info "Skipping application build (config-only mode)"
|
||||
fi
|
||||
|
||||
# Setup database
|
||||
log_step "Setting Up Database"
|
||||
setup_database
|
||||
|
||||
# Setup configuration
|
||||
log_step "Setting Up Configuration"
|
||||
setup_configuration
|
||||
|
||||
# Install systemd services
|
||||
log_step "Installing Systemd Services"
|
||||
install_systemd_services
|
||||
|
||||
# Configure file sharing and antivirus services
|
||||
log_step "Configuring File Sharing and Antivirus Services"
|
||||
configure_all_services
|
||||
|
||||
# Final verification
|
||||
log_step "Verifying Installation"
|
||||
verify_installation
|
||||
|
||||
# Post-installation setup
|
||||
log_step "Post-Installation Setup"
|
||||
post_install_setup
|
||||
|
||||
# Print summary
|
||||
print_installation_summary
|
||||
}
|
||||
|
||||
# Run main installation
|
||||
main
|
||||
|
||||
log_info ""
|
||||
log_info "=========================================="
|
||||
log_info "Installation Complete!"
|
||||
log_info "=========================================="
|
||||
log_info ""
|
||||
log_info "Next steps:"
|
||||
log_info "1. Configure /etc/calypso/config.yaml"
|
||||
log_info "2. Set environment variables in /etc/calypso/secrets.env"
|
||||
log_info "3. Start services: sudo systemctl start calypso-api"
|
||||
log_info "4. Access web UI: http://<server-ip>:3000"
|
||||
log_info "5. Login with default admin credentials (check above)"
|
||||
log_info ""
|
||||
|
||||
+213
@@ -0,0 +1,213 @@
|
||||
-- AtlasOS - Calypso
|
||||
-- Initial Database Schema
|
||||
-- Version: 1.0
|
||||
|
||||
-- Users table
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
username VARCHAR(255) NOT NULL UNIQUE,
|
||||
email VARCHAR(255) NOT NULL UNIQUE,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
full_name VARCHAR(255),
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
is_system BOOLEAN NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
last_login_at TIMESTAMP
|
||||
);
|
||||
|
||||
-- Roles table
|
||||
CREATE TABLE IF NOT EXISTS roles (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(100) NOT NULL UNIQUE,
|
||||
description TEXT,
|
||||
is_system BOOLEAN NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Permissions table
|
||||
CREATE TABLE IF NOT EXISTS permissions (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(255) NOT NULL UNIQUE,
|
||||
resource VARCHAR(100) NOT NULL,
|
||||
action VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- User roles junction table
|
||||
CREATE TABLE IF NOT EXISTS user_roles (
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
|
||||
assigned_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
assigned_by UUID REFERENCES users(id),
|
||||
PRIMARY KEY (user_id, role_id)
|
||||
);
|
||||
|
||||
-- Role permissions junction table
|
||||
CREATE TABLE IF NOT EXISTS role_permissions (
|
||||
role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
|
||||
permission_id UUID NOT NULL REFERENCES permissions(id) ON DELETE CASCADE,
|
||||
granted_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
PRIMARY KEY (role_id, permission_id)
|
||||
);
|
||||
|
||||
-- Sessions table
|
||||
CREATE TABLE IF NOT EXISTS sessions (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
token_hash VARCHAR(255) NOT NULL UNIQUE,
|
||||
ip_address INET,
|
||||
user_agent TEXT,
|
||||
expires_at TIMESTAMP NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
last_activity_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Audit log table
|
||||
CREATE TABLE IF NOT EXISTS audit_log (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID REFERENCES users(id),
|
||||
username VARCHAR(255),
|
||||
action VARCHAR(100) NOT NULL,
|
||||
resource_type VARCHAR(100) NOT NULL,
|
||||
resource_id VARCHAR(255),
|
||||
method VARCHAR(10),
|
||||
path TEXT,
|
||||
ip_address INET,
|
||||
user_agent TEXT,
|
||||
request_body JSONB,
|
||||
response_status INTEGER,
|
||||
error_message TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Tasks table (for async operations)
|
||||
CREATE TABLE IF NOT EXISTS tasks (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
type VARCHAR(100) NOT NULL,
|
||||
status VARCHAR(50) NOT NULL DEFAULT 'pending',
|
||||
progress INTEGER NOT NULL DEFAULT 0,
|
||||
message TEXT,
|
||||
error_message TEXT,
|
||||
created_by UUID REFERENCES users(id),
|
||||
started_at TIMESTAMP,
|
||||
completed_at TIMESTAMP,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
metadata JSONB
|
||||
);
|
||||
|
||||
-- Alerts table
|
||||
CREATE TABLE IF NOT EXISTS alerts (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
severity VARCHAR(20) NOT NULL,
|
||||
source VARCHAR(100) NOT NULL,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
message TEXT NOT NULL,
|
||||
resource_type VARCHAR(100),
|
||||
resource_id VARCHAR(255),
|
||||
is_acknowledged BOOLEAN NOT NULL DEFAULT false,
|
||||
acknowledged_by UUID REFERENCES users(id),
|
||||
acknowledged_at TIMESTAMP,
|
||||
resolved_at TIMESTAMP,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
metadata JSONB
|
||||
);
|
||||
|
||||
-- System configuration table
|
||||
CREATE TABLE IF NOT EXISTS system_config (
|
||||
key VARCHAR(255) PRIMARY KEY,
|
||||
value TEXT NOT NULL,
|
||||
description TEXT,
|
||||
is_encrypted BOOLEAN NOT NULL DEFAULT false,
|
||||
updated_by UUID REFERENCES users(id),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Indexes for performance
|
||||
CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_active ON users(is_active);
|
||||
CREATE INDEX IF NOT EXISTS idx_sessions_user_id ON sessions(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_sessions_token_hash ON sessions(token_hash);
|
||||
CREATE INDEX IF NOT EXISTS idx_sessions_expires_at ON sessions(expires_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_log_user_id ON audit_log(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_log_created_at ON audit_log(created_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_log_resource ON audit_log(resource_type, resource_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_tasks_type ON tasks(type);
|
||||
CREATE INDEX IF NOT EXISTS idx_tasks_created_by ON tasks(created_by);
|
||||
CREATE INDEX IF NOT EXISTS idx_alerts_severity ON alerts(severity);
|
||||
CREATE INDEX IF NOT EXISTS idx_alerts_acknowledged ON alerts(is_acknowledged);
|
||||
CREATE INDEX IF NOT EXISTS idx_alerts_created_at ON alerts(created_at);
|
||||
|
||||
-- Insert default system roles
|
||||
INSERT INTO roles (name, description, is_system) VALUES
|
||||
('admin', 'Full system access and configuration', true),
|
||||
('operator', 'Day-to-day operations and monitoring', true),
|
||||
('readonly', 'Read-only access for monitoring and reporting', true)
|
||||
ON CONFLICT (name) DO NOTHING;
|
||||
|
||||
-- Insert default permissions
|
||||
INSERT INTO permissions (name, resource, action, description) VALUES
|
||||
-- System permissions
|
||||
('system:read', 'system', 'read', 'View system information'),
|
||||
('system:write', 'system', 'write', 'Modify system configuration'),
|
||||
('system:manage', 'system', 'manage', 'Full system management'),
|
||||
|
||||
-- Storage permissions
|
||||
('storage:read', 'storage', 'read', 'View storage information'),
|
||||
('storage:write', 'storage', 'write', 'Modify storage configuration'),
|
||||
('storage:manage', 'storage', 'manage', 'Full storage management'),
|
||||
|
||||
-- Tape permissions
|
||||
('tape:read', 'tape', 'read', 'View tape library information'),
|
||||
('tape:write', 'tape', 'write', 'Perform tape operations'),
|
||||
('tape:manage', 'tape', 'manage', 'Full tape management'),
|
||||
|
||||
-- iSCSI permissions
|
||||
('iscsi:read', 'iscsi', 'read', 'View iSCSI configuration'),
|
||||
('iscsi:write', 'iscsi', 'write', 'Modify iSCSI configuration'),
|
||||
('iscsi:manage', 'iscsi', 'manage', 'Full iSCSI management'),
|
||||
|
||||
-- IAM permissions
|
||||
('iam:read', 'iam', 'read', 'View users and roles'),
|
||||
('iam:write', 'iam', 'write', 'Modify users and roles'),
|
||||
('iam:manage', 'iam', 'manage', 'Full IAM management'),
|
||||
|
||||
-- Audit permissions
|
||||
('audit:read', 'audit', 'read', 'View audit logs'),
|
||||
|
||||
-- Monitoring permissions
|
||||
('monitoring:read', 'monitoring', 'read', 'View monitoring data'),
|
||||
('monitoring:write', 'monitoring', 'write', 'Acknowledge alerts')
|
||||
ON CONFLICT (name) DO NOTHING;
|
||||
|
||||
-- Assign permissions to roles
|
||||
-- Admin gets all permissions
|
||||
INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT r.id, p.id
|
||||
FROM roles r, permissions p
|
||||
WHERE r.name = 'admin'
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- Operator gets read and write (but not manage) for most resources
|
||||
INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT r.id, p.id
|
||||
FROM roles r, permissions p
|
||||
WHERE r.name = 'operator'
|
||||
AND p.action IN ('read', 'write')
|
||||
AND p.resource IN ('storage', 'tape', 'iscsi', 'monitoring')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- ReadOnly gets only read permissions
|
||||
INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT r.id, p.id
|
||||
FROM roles r, permissions p
|
||||
WHERE r.name = 'readonly'
|
||||
AND p.action = 'read'
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
+227
@@ -0,0 +1,227 @@
|
||||
-- AtlasOS - Calypso
|
||||
-- Storage and Tape Component Schema
|
||||
-- Version: 2.0
|
||||
|
||||
-- ZFS pools table
|
||||
CREATE TABLE IF NOT EXISTS zfs_pools (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(255) NOT NULL UNIQUE,
|
||||
description TEXT,
|
||||
raid_level VARCHAR(50) NOT NULL, -- stripe, mirror, raidz, raidz2, raidz3
|
||||
disks TEXT[] NOT NULL, -- array of device paths
|
||||
size_bytes BIGINT NOT NULL,
|
||||
used_bytes BIGINT NOT NULL DEFAULT 0,
|
||||
compression VARCHAR(50) NOT NULL DEFAULT 'lz4', -- off, lz4, zstd, gzip
|
||||
deduplication BOOLEAN NOT NULL DEFAULT false,
|
||||
auto_expand BOOLEAN NOT NULL DEFAULT false,
|
||||
scrub_interval INTEGER NOT NULL DEFAULT 30, -- days
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
health_status VARCHAR(50) NOT NULL DEFAULT 'online', -- online, degraded, faulted, offline
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES users(id)
|
||||
);
|
||||
|
||||
-- Disk repositories table
|
||||
CREATE TABLE IF NOT EXISTS disk_repositories (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(255) NOT NULL UNIQUE,
|
||||
description TEXT,
|
||||
volume_group VARCHAR(255) NOT NULL,
|
||||
logical_volume VARCHAR(255) NOT NULL,
|
||||
size_bytes BIGINT NOT NULL,
|
||||
used_bytes BIGINT NOT NULL DEFAULT 0,
|
||||
filesystem_type VARCHAR(50),
|
||||
mount_point TEXT,
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
warning_threshold_percent INTEGER NOT NULL DEFAULT 80,
|
||||
critical_threshold_percent INTEGER NOT NULL DEFAULT 90,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES users(id)
|
||||
);
|
||||
|
||||
-- Physical disks table
|
||||
CREATE TABLE IF NOT EXISTS physical_disks (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
device_path VARCHAR(255) NOT NULL UNIQUE,
|
||||
vendor VARCHAR(255),
|
||||
model VARCHAR(255),
|
||||
serial_number VARCHAR(255),
|
||||
size_bytes BIGINT NOT NULL,
|
||||
sector_size INTEGER,
|
||||
is_ssd BOOLEAN NOT NULL DEFAULT false,
|
||||
health_status VARCHAR(50) NOT NULL DEFAULT 'unknown',
|
||||
health_details JSONB,
|
||||
is_used BOOLEAN NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Volume groups table
|
||||
CREATE TABLE IF NOT EXISTS volume_groups (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(255) NOT NULL UNIQUE,
|
||||
size_bytes BIGINT NOT NULL,
|
||||
free_bytes BIGINT NOT NULL,
|
||||
physical_volumes TEXT[],
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- SCST iSCSI targets table
|
||||
CREATE TABLE IF NOT EXISTS scst_targets (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
iqn VARCHAR(512) NOT NULL UNIQUE,
|
||||
target_type VARCHAR(50) NOT NULL, -- 'disk', 'vtl', 'physical_tape'
|
||||
name VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
single_initiator_only BOOLEAN NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES users(id)
|
||||
);
|
||||
|
||||
-- SCST LUN mappings table
|
||||
CREATE TABLE IF NOT EXISTS scst_luns (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
target_id UUID NOT NULL REFERENCES scst_targets(id) ON DELETE CASCADE,
|
||||
lun_number INTEGER NOT NULL,
|
||||
device_name VARCHAR(255) NOT NULL,
|
||||
device_path VARCHAR(512) NOT NULL,
|
||||
handler_type VARCHAR(50) NOT NULL, -- 'vdisk', 'sg', 'tape'
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
UNIQUE(target_id, lun_number)
|
||||
);
|
||||
|
||||
-- SCST initiator groups table
|
||||
CREATE TABLE IF NOT EXISTS scst_initiator_groups (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
target_id UUID NOT NULL REFERENCES scst_targets(id) ON DELETE CASCADE,
|
||||
group_name VARCHAR(255) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
UNIQUE(target_id, group_name)
|
||||
);
|
||||
|
||||
-- SCST initiators table
|
||||
CREATE TABLE IF NOT EXISTS scst_initiators (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
group_id UUID NOT NULL REFERENCES scst_initiator_groups(id) ON DELETE CASCADE,
|
||||
iqn VARCHAR(512) NOT NULL,
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
UNIQUE(group_id, iqn)
|
||||
);
|
||||
|
||||
-- Physical tape libraries table
|
||||
CREATE TABLE IF NOT EXISTS physical_tape_libraries (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(255) NOT NULL UNIQUE,
|
||||
serial_number VARCHAR(255),
|
||||
vendor VARCHAR(255),
|
||||
model VARCHAR(255),
|
||||
changer_device_path VARCHAR(512),
|
||||
changer_stable_path VARCHAR(512),
|
||||
slot_count INTEGER,
|
||||
drive_count INTEGER,
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
discovered_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
last_inventory_at TIMESTAMP,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Physical tape drives table
|
||||
CREATE TABLE IF NOT EXISTS physical_tape_drives (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
library_id UUID NOT NULL REFERENCES physical_tape_libraries(id) ON DELETE CASCADE,
|
||||
drive_number INTEGER NOT NULL,
|
||||
device_path VARCHAR(512),
|
||||
stable_path VARCHAR(512),
|
||||
vendor VARCHAR(255),
|
||||
model VARCHAR(255),
|
||||
serial_number VARCHAR(255),
|
||||
drive_type VARCHAR(50), -- 'LTO-8', 'LTO-9', etc.
|
||||
status VARCHAR(50) NOT NULL DEFAULT 'unknown', -- 'idle', 'loading', 'ready', 'error'
|
||||
current_tape_barcode VARCHAR(255),
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
UNIQUE(library_id, drive_number)
|
||||
);
|
||||
|
||||
-- Physical tape slots table
|
||||
CREATE TABLE IF NOT EXISTS physical_tape_slots (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
library_id UUID NOT NULL REFERENCES physical_tape_libraries(id) ON DELETE CASCADE,
|
||||
slot_number INTEGER NOT NULL,
|
||||
barcode VARCHAR(255),
|
||||
tape_present BOOLEAN NOT NULL DEFAULT false,
|
||||
tape_type VARCHAR(50),
|
||||
last_updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
UNIQUE(library_id, slot_number)
|
||||
);
|
||||
|
||||
-- Virtual tape libraries table
|
||||
CREATE TABLE IF NOT EXISTS virtual_tape_libraries (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(255) NOT NULL UNIQUE,
|
||||
description TEXT,
|
||||
mhvtl_library_id INTEGER,
|
||||
backing_store_path TEXT NOT NULL,
|
||||
slot_count INTEGER NOT NULL DEFAULT 10,
|
||||
drive_count INTEGER NOT NULL DEFAULT 2,
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES users(id)
|
||||
);
|
||||
|
||||
-- Virtual tape drives table
|
||||
CREATE TABLE IF NOT EXISTS virtual_tape_drives (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
library_id UUID NOT NULL REFERENCES virtual_tape_libraries(id) ON DELETE CASCADE,
|
||||
drive_number INTEGER NOT NULL,
|
||||
device_path VARCHAR(512),
|
||||
stable_path VARCHAR(512),
|
||||
status VARCHAR(50) NOT NULL DEFAULT 'idle',
|
||||
current_tape_id UUID,
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
UNIQUE(library_id, drive_number)
|
||||
);
|
||||
|
||||
-- Virtual tapes table
|
||||
CREATE TABLE IF NOT EXISTS virtual_tapes (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
library_id UUID NOT NULL REFERENCES virtual_tape_libraries(id) ON DELETE CASCADE,
|
||||
barcode VARCHAR(255) NOT NULL,
|
||||
slot_number INTEGER,
|
||||
image_file_path TEXT NOT NULL,
|
||||
size_bytes BIGINT NOT NULL DEFAULT 0,
|
||||
used_bytes BIGINT NOT NULL DEFAULT 0,
|
||||
tape_type VARCHAR(50) NOT NULL DEFAULT 'LTO-8',
|
||||
status VARCHAR(50) NOT NULL DEFAULT 'idle', -- 'idle', 'in_drive', 'exported'
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
UNIQUE(library_id, barcode)
|
||||
);
|
||||
|
||||
-- Indexes for performance
|
||||
CREATE INDEX IF NOT EXISTS idx_disk_repositories_name ON disk_repositories(name);
|
||||
CREATE INDEX IF NOT EXISTS idx_disk_repositories_active ON disk_repositories(is_active);
|
||||
CREATE INDEX IF NOT EXISTS idx_physical_disks_device_path ON physical_disks(device_path);
|
||||
CREATE INDEX IF NOT EXISTS idx_scst_targets_iqn ON scst_targets(iqn);
|
||||
CREATE INDEX IF NOT EXISTS idx_scst_targets_type ON scst_targets(target_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_scst_luns_target_id ON scst_luns(target_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_scst_initiators_group_id ON scst_initiators(group_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_physical_tape_libraries_name ON physical_tape_libraries(name);
|
||||
CREATE INDEX IF NOT EXISTS idx_physical_tape_drives_library_id ON physical_tape_drives(library_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_physical_tape_slots_library_id ON physical_tape_slots(library_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_virtual_tape_libraries_name ON virtual_tape_libraries(name);
|
||||
CREATE INDEX IF NOT EXISTS idx_virtual_tape_drives_library_id ON virtual_tape_drives(library_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_virtual_tapes_library_id ON virtual_tapes(library_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_virtual_tapes_barcode ON virtual_tapes(barcode);
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
-- Migration: Object Storage Configuration
|
||||
-- Description: Creates table for storing MinIO object storage configuration
|
||||
-- Date: 2026-01-09
|
||||
|
||||
CREATE TABLE IF NOT EXISTS object_storage_config (
|
||||
id SERIAL PRIMARY KEY,
|
||||
dataset_path VARCHAR(255) NOT NULL UNIQUE,
|
||||
mount_point VARCHAR(512) NOT NULL,
|
||||
pool_name VARCHAR(255) NOT NULL,
|
||||
dataset_name VARCHAR(255) NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_object_storage_config_pool_name ON object_storage_config(pool_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_object_storage_config_updated_at ON object_storage_config(updated_at);
|
||||
|
||||
COMMENT ON TABLE object_storage_config IS 'Stores MinIO object storage configuration, linking to ZFS datasets';
|
||||
COMMENT ON COLUMN object_storage_config.dataset_path IS 'Full ZFS dataset path (e.g., pool/dataset)';
|
||||
COMMENT ON COLUMN object_storage_config.mount_point IS 'Mount point path for the dataset';
|
||||
COMMENT ON COLUMN object_storage_config.pool_name IS 'ZFS pool name';
|
||||
COMMENT ON COLUMN object_storage_config.dataset_name IS 'ZFS dataset name';
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
-- AtlasOS - Calypso
|
||||
-- Performance Optimization: Database Indexes
|
||||
-- Version: 3.0
|
||||
-- Description: Adds indexes for frequently queried columns to improve query performance
|
||||
|
||||
-- ============================================================================
|
||||
-- Authentication & Authorization Indexes
|
||||
-- ============================================================================
|
||||
|
||||
-- Users table indexes
|
||||
-- Username is frequently queried during login
|
||||
CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
|
||||
-- Email lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
|
||||
-- Active user lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_users_is_active ON users(is_active) WHERE is_active = true;
|
||||
|
||||
-- Sessions table indexes
|
||||
-- Token hash lookups are very frequent (every authenticated request)
|
||||
CREATE INDEX IF NOT EXISTS idx_sessions_token_hash ON sessions(token_hash);
|
||||
-- User session lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_sessions_user_id ON sessions(user_id);
|
||||
-- Expired session cleanup (index on expires_at for efficient cleanup queries)
|
||||
CREATE INDEX IF NOT EXISTS idx_sessions_expires_at ON sessions(expires_at);
|
||||
|
||||
-- User roles junction table
|
||||
-- Lookup roles for a user (frequent during permission checks)
|
||||
CREATE INDEX IF NOT EXISTS idx_user_roles_user_id ON user_roles(user_id);
|
||||
-- Lookup users with a role
|
||||
CREATE INDEX IF NOT EXISTS idx_user_roles_role_id ON user_roles(role_id);
|
||||
|
||||
-- Role permissions junction table
|
||||
-- Lookup permissions for a role
|
||||
CREATE INDEX IF NOT EXISTS idx_role_permissions_role_id ON role_permissions(role_id);
|
||||
-- Lookup roles with a permission
|
||||
CREATE INDEX IF NOT EXISTS idx_role_permissions_permission_id ON role_permissions(permission_id);
|
||||
|
||||
-- ============================================================================
|
||||
-- Audit & Monitoring Indexes
|
||||
-- ============================================================================
|
||||
|
||||
-- Audit log indexes
|
||||
-- Time-based queries (most common audit log access pattern)
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_log_created_at ON audit_log(created_at DESC);
|
||||
-- User activity queries
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_log_user_id ON audit_log(user_id);
|
||||
-- Resource-based queries
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_log_resource ON audit_log(resource_type, resource_id);
|
||||
|
||||
-- Alerts table indexes
|
||||
-- Time-based ordering (default ordering in ListAlerts)
|
||||
CREATE INDEX IF NOT EXISTS idx_alerts_created_at ON alerts(created_at DESC);
|
||||
-- Severity filtering
|
||||
CREATE INDEX IF NOT EXISTS idx_alerts_severity ON alerts(severity);
|
||||
-- Source filtering
|
||||
CREATE INDEX IF NOT EXISTS idx_alerts_source ON alerts(source);
|
||||
-- Acknowledgment status
|
||||
CREATE INDEX IF NOT EXISTS idx_alerts_acknowledged ON alerts(is_acknowledged) WHERE is_acknowledged = false;
|
||||
-- Resource-based queries
|
||||
CREATE INDEX IF NOT EXISTS idx_alerts_resource ON alerts(resource_type, resource_id);
|
||||
-- Composite index for common filter combinations
|
||||
CREATE INDEX IF NOT EXISTS idx_alerts_severity_acknowledged ON alerts(severity, is_acknowledged, created_at DESC);
|
||||
|
||||
-- ============================================================================
|
||||
-- Task Management Indexes
|
||||
-- ============================================================================
|
||||
|
||||
-- Tasks table indexes
|
||||
-- Status filtering (very common in task queries)
|
||||
CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);
|
||||
-- Created by user
|
||||
CREATE INDEX IF NOT EXISTS idx_tasks_created_by ON tasks(created_by);
|
||||
-- Time-based queries
|
||||
CREATE INDEX IF NOT EXISTS idx_tasks_created_at ON tasks(created_at DESC);
|
||||
-- Status + time composite (common query pattern)
|
||||
CREATE INDEX IF NOT EXISTS idx_tasks_status_created_at ON tasks(status, created_at DESC);
|
||||
-- Failed tasks lookup (for alerting)
|
||||
CREATE INDEX IF NOT EXISTS idx_tasks_failed_recent ON tasks(status, created_at DESC) WHERE status = 'failed';
|
||||
|
||||
-- ============================================================================
|
||||
-- Storage Indexes
|
||||
-- ============================================================================
|
||||
|
||||
-- Disk repositories indexes
|
||||
-- Active repository lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_disk_repositories_is_active ON disk_repositories(is_active) WHERE is_active = true;
|
||||
-- Name lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_disk_repositories_name ON disk_repositories(name);
|
||||
-- Volume group lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_disk_repositories_vg ON disk_repositories(volume_group);
|
||||
|
||||
-- Physical disks indexes
|
||||
-- Device path lookups (for sync operations)
|
||||
CREATE INDEX IF NOT EXISTS idx_physical_disks_device_path ON physical_disks(device_path);
|
||||
|
||||
-- ============================================================================
|
||||
-- SCST Indexes
|
||||
-- ============================================================================
|
||||
|
||||
-- SCST targets indexes
|
||||
-- IQN lookups (frequent during target operations)
|
||||
CREATE INDEX IF NOT EXISTS idx_scst_targets_iqn ON scst_targets(iqn);
|
||||
-- Active target lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_scst_targets_is_active ON scst_targets(is_active) WHERE is_active = true;
|
||||
|
||||
-- SCST LUNs indexes
|
||||
-- Target + LUN lookups (very frequent)
|
||||
CREATE INDEX IF NOT EXISTS idx_scst_luns_target_lun ON scst_luns(target_id, lun_number);
|
||||
-- Device path lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_scst_luns_device_path ON scst_luns(device_path);
|
||||
|
||||
-- SCST initiator groups indexes
|
||||
-- Target + group name lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_scst_initiator_groups_target ON scst_initiator_groups(target_id);
|
||||
-- Group name lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_scst_initiator_groups_name ON scst_initiator_groups(group_name);
|
||||
|
||||
-- SCST initiators indexes
|
||||
-- Group + IQN lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_scst_initiators_group_iqn ON scst_initiators(group_id, iqn);
|
||||
-- Active initiator lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_scst_initiators_is_active ON scst_initiators(is_active) WHERE is_active = true;
|
||||
|
||||
-- ============================================================================
|
||||
-- Tape Library Indexes
|
||||
-- ============================================================================
|
||||
|
||||
-- Physical tape libraries indexes
|
||||
-- Serial number lookups (for discovery)
|
||||
CREATE INDEX IF NOT EXISTS idx_physical_tape_libraries_serial ON physical_tape_libraries(serial_number);
|
||||
-- Active library lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_physical_tape_libraries_is_active ON physical_tape_libraries(is_active) WHERE is_active = true;
|
||||
|
||||
-- Physical tape drives indexes
|
||||
-- Library + drive number lookups (very frequent)
|
||||
CREATE INDEX IF NOT EXISTS idx_physical_tape_drives_library_drive ON physical_tape_drives(library_id, drive_number);
|
||||
-- Status filtering
|
||||
CREATE INDEX IF NOT EXISTS idx_physical_tape_drives_status ON physical_tape_drives(status);
|
||||
|
||||
-- Physical tape slots indexes
|
||||
-- Library + slot number lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_physical_tape_slots_library_slot ON physical_tape_slots(library_id, slot_number);
|
||||
-- Barcode lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_physical_tape_slots_barcode ON physical_tape_slots(barcode) WHERE barcode IS NOT NULL;
|
||||
|
||||
-- Virtual tape libraries indexes
|
||||
-- MHVTL library ID lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_virtual_tape_libraries_mhvtl_id ON virtual_tape_libraries(mhvtl_library_id);
|
||||
-- Active library lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_virtual_tape_libraries_is_active ON virtual_tape_libraries(is_active) WHERE is_active = true;
|
||||
|
||||
-- Virtual tape drives indexes
|
||||
-- Library + drive number lookups (very frequent)
|
||||
CREATE INDEX IF NOT EXISTS idx_virtual_tape_drives_library_drive ON virtual_tape_drives(library_id, drive_number);
|
||||
-- Status filtering
|
||||
CREATE INDEX IF NOT EXISTS idx_virtual_tape_drives_status ON virtual_tape_drives(status);
|
||||
-- Current tape lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_virtual_tape_drives_current_tape ON virtual_tape_drives(current_tape_id) WHERE current_tape_id IS NOT NULL;
|
||||
|
||||
-- Virtual tapes indexes
|
||||
-- Library + slot number lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_virtual_tapes_library_slot ON virtual_tapes(library_id, slot_number);
|
||||
-- Barcode lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_virtual_tapes_barcode ON virtual_tapes(barcode) WHERE barcode IS NOT NULL;
|
||||
-- Status filtering
|
||||
CREATE INDEX IF NOT EXISTS idx_virtual_tapes_status ON virtual_tapes(status);
|
||||
|
||||
-- ============================================================================
|
||||
-- Statistics Update
|
||||
-- ============================================================================
|
||||
|
||||
-- Update table statistics for query planner
|
||||
ANALYZE;
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
-- AtlasOS - Calypso
|
||||
-- Add ZFS Pools Table
|
||||
-- Version: 4.0
|
||||
-- Note: This migration adds the zfs_pools table that was added to migration 002
|
||||
-- but may not have been applied if migration 002 was run before the table was added
|
||||
|
||||
-- ZFS pools table
|
||||
CREATE TABLE IF NOT EXISTS zfs_pools (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(255) NOT NULL UNIQUE,
|
||||
description TEXT,
|
||||
raid_level VARCHAR(50) NOT NULL, -- stripe, mirror, raidz, raidz2, raidz3
|
||||
disks TEXT[] NOT NULL, -- array of device paths
|
||||
size_bytes BIGINT NOT NULL,
|
||||
used_bytes BIGINT NOT NULL DEFAULT 0,
|
||||
compression VARCHAR(50) NOT NULL DEFAULT 'lz4', -- off, lz4, zstd, gzip
|
||||
deduplication BOOLEAN NOT NULL DEFAULT false,
|
||||
auto_expand BOOLEAN NOT NULL DEFAULT false,
|
||||
scrub_interval INTEGER NOT NULL DEFAULT 30, -- days
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
health_status VARCHAR(50) NOT NULL DEFAULT 'online', -- online, degraded, faulted, offline
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES users(id)
|
||||
);
|
||||
|
||||
-- Create index on name for faster lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_zfs_pools_name ON zfs_pools(name);
|
||||
CREATE INDEX IF NOT EXISTS idx_zfs_pools_created_by ON zfs_pools(created_by);
|
||||
CREATE INDEX IF NOT EXISTS idx_zfs_pools_health_status ON zfs_pools(health_status);
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
-- AtlasOS - Calypso
|
||||
-- Add ZFS Datasets Table
|
||||
-- Version: 5.0
|
||||
-- Description: Stores ZFS dataset metadata in database for faster queries and consistency
|
||||
|
||||
-- ZFS datasets table
|
||||
CREATE TABLE IF NOT EXISTS zfs_datasets (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(512) NOT NULL UNIQUE, -- Full dataset name (e.g., pool/dataset)
|
||||
pool_id UUID NOT NULL REFERENCES zfs_pools(id) ON DELETE CASCADE,
|
||||
pool_name VARCHAR(255) NOT NULL, -- Denormalized for faster queries
|
||||
type VARCHAR(50) NOT NULL, -- filesystem, volume, snapshot
|
||||
mount_point TEXT, -- Mount point path (null for volumes)
|
||||
used_bytes BIGINT NOT NULL DEFAULT 0,
|
||||
available_bytes BIGINT NOT NULL DEFAULT 0,
|
||||
referenced_bytes BIGINT NOT NULL DEFAULT 0,
|
||||
compression VARCHAR(50) NOT NULL DEFAULT 'lz4', -- off, lz4, zstd, gzip
|
||||
deduplication VARCHAR(50) NOT NULL DEFAULT 'off', -- off, on, verify
|
||||
quota BIGINT DEFAULT -1, -- -1 for unlimited, bytes otherwise
|
||||
reservation BIGINT NOT NULL DEFAULT 0, -- Reserved space in bytes
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES users(id)
|
||||
);
|
||||
|
||||
-- Create indexes for faster lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_zfs_datasets_pool_id ON zfs_datasets(pool_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_zfs_datasets_pool_name ON zfs_datasets(pool_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_zfs_datasets_name ON zfs_datasets(name);
|
||||
CREATE INDEX IF NOT EXISTS idx_zfs_datasets_type ON zfs_datasets(type);
|
||||
CREATE INDEX IF NOT EXISTS idx_zfs_datasets_created_by ON zfs_datasets(created_by);
|
||||
|
||||
-- Composite index for common queries (list datasets by pool)
|
||||
CREATE INDEX IF NOT EXISTS idx_zfs_datasets_pool_type ON zfs_datasets(pool_id, type);
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
-- AtlasOS - Calypso
|
||||
-- Add ZFS Shares and iSCSI Export Tables
|
||||
-- Version: 6.0
|
||||
-- Description: Separate tables for filesystem shares (NFS/SMB) and volume iSCSI exports
|
||||
|
||||
-- ZFS Filesystem Shares Table (for NFS/SMB)
|
||||
CREATE TABLE IF NOT EXISTS zfs_shares (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
dataset_id UUID NOT NULL REFERENCES zfs_datasets(id) ON DELETE CASCADE,
|
||||
share_type VARCHAR(50) NOT NULL, -- 'nfs', 'smb', 'both'
|
||||
nfs_enabled BOOLEAN NOT NULL DEFAULT false,
|
||||
nfs_options TEXT, -- e.g., "rw,sync,no_subtree_check"
|
||||
nfs_clients TEXT[], -- Allowed client IPs/networks
|
||||
smb_enabled BOOLEAN NOT NULL DEFAULT false,
|
||||
smb_share_name VARCHAR(255), -- SMB share name
|
||||
smb_path TEXT, -- SMB share path (usually same as mount_point)
|
||||
smb_comment TEXT,
|
||||
smb_guest_ok BOOLEAN NOT NULL DEFAULT false,
|
||||
smb_read_only BOOLEAN NOT NULL DEFAULT false,
|
||||
smb_browseable BOOLEAN NOT NULL DEFAULT true,
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES users(id),
|
||||
UNIQUE(dataset_id) -- One share config per dataset
|
||||
);
|
||||
|
||||
-- ZFS Volume iSCSI Exports Table
|
||||
CREATE TABLE IF NOT EXISTS zfs_iscsi_exports (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
dataset_id UUID NOT NULL REFERENCES zfs_datasets(id) ON DELETE CASCADE,
|
||||
target_id UUID REFERENCES scst_targets(id) ON DELETE SET NULL, -- Link to SCST target
|
||||
lun_number INTEGER, -- LUN number in the target
|
||||
device_path TEXT, -- /dev/zvol/pool/volume path
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES users(id),
|
||||
UNIQUE(dataset_id) -- One iSCSI export per volume
|
||||
);
|
||||
|
||||
-- Create indexes
|
||||
CREATE INDEX IF NOT EXISTS idx_zfs_shares_dataset_id ON zfs_shares(dataset_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_zfs_shares_type ON zfs_shares(share_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_zfs_shares_active ON zfs_shares(is_active);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_zfs_iscsi_exports_dataset_id ON zfs_iscsi_exports(dataset_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_zfs_iscsi_exports_target_id ON zfs_iscsi_exports(target_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_zfs_iscsi_exports_active ON zfs_iscsi_exports(is_active);
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
-- Add vendor column to virtual_tape_libraries table
|
||||
ALTER TABLE virtual_tape_libraries ADD COLUMN IF NOT EXISTS vendor VARCHAR(255);
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
-- Add user groups feature
|
||||
-- Groups table
|
||||
CREATE TABLE IF NOT EXISTS groups (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(255) NOT NULL UNIQUE,
|
||||
description TEXT,
|
||||
is_system BOOLEAN NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- User groups junction table
|
||||
CREATE TABLE IF NOT EXISTS user_groups (
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
group_id UUID NOT NULL REFERENCES groups(id) ON DELETE CASCADE,
|
||||
assigned_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
assigned_by UUID REFERENCES users(id),
|
||||
PRIMARY KEY (user_id, group_id)
|
||||
);
|
||||
|
||||
-- Group roles junction table (groups can have roles)
|
||||
CREATE TABLE IF NOT EXISTS group_roles (
|
||||
group_id UUID NOT NULL REFERENCES groups(id) ON DELETE CASCADE,
|
||||
role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
|
||||
granted_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
PRIMARY KEY (group_id, role_id)
|
||||
);
|
||||
|
||||
-- Indexes
|
||||
CREATE INDEX IF NOT EXISTS idx_groups_name ON groups(name);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_groups_user_id ON user_groups(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_groups_group_id ON user_groups(group_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_group_roles_group_id ON group_roles(group_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_group_roles_role_id ON group_roles(role_id);
|
||||
|
||||
-- Insert default system groups
|
||||
INSERT INTO groups (name, description, is_system) VALUES
|
||||
('wheel', 'System administrators group', true),
|
||||
('operators', 'System operators group', true),
|
||||
('backup', 'Backup operators group', true),
|
||||
('auditors', 'Auditors group', true),
|
||||
('storage_admins', 'Storage administrators group', true),
|
||||
('services', 'Service accounts group', true)
|
||||
ON CONFLICT (name) DO NOTHING;
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
-- AtlasOS - Calypso
|
||||
-- Backup Jobs Schema
|
||||
-- Version: 9.0
|
||||
|
||||
-- Backup jobs table
|
||||
CREATE TABLE IF NOT EXISTS backup_jobs (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
job_id INTEGER NOT NULL UNIQUE, -- Bareos job ID
|
||||
job_name VARCHAR(255) NOT NULL,
|
||||
client_name VARCHAR(255) NOT NULL,
|
||||
job_type VARCHAR(50) NOT NULL, -- 'Backup', 'Restore', 'Verify', 'Copy', 'Migrate'
|
||||
job_level VARCHAR(50) NOT NULL, -- 'Full', 'Incremental', 'Differential', 'Since'
|
||||
status VARCHAR(50) NOT NULL, -- 'Running', 'Completed', 'Failed', 'Canceled', 'Waiting'
|
||||
bytes_written BIGINT NOT NULL DEFAULT 0,
|
||||
files_written INTEGER NOT NULL DEFAULT 0,
|
||||
duration_seconds INTEGER,
|
||||
started_at TIMESTAMP,
|
||||
ended_at TIMESTAMP,
|
||||
error_message TEXT,
|
||||
storage_name VARCHAR(255),
|
||||
pool_name VARCHAR(255),
|
||||
volume_name VARCHAR(255),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Indexes for performance
|
||||
CREATE INDEX IF NOT EXISTS idx_backup_jobs_job_id ON backup_jobs(job_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_backup_jobs_job_name ON backup_jobs(job_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_backup_jobs_client_name ON backup_jobs(client_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_backup_jobs_status ON backup_jobs(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_backup_jobs_started_at ON backup_jobs(started_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_backup_jobs_job_type ON backup_jobs(job_type);
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
-- AtlasOS - Calypso
|
||||
-- Add Backup Permissions
|
||||
-- Version: 10.0
|
||||
|
||||
-- Insert backup permissions
|
||||
INSERT INTO permissions (name, resource, action, description) VALUES
|
||||
('backup:read', 'backup', 'read', 'View backup jobs and history'),
|
||||
('backup:write', 'backup', 'write', 'Create and manage backup jobs'),
|
||||
('backup:manage', 'backup', 'manage', 'Full backup management')
|
||||
ON CONFLICT (name) DO NOTHING;
|
||||
|
||||
-- Assign backup permissions to roles
|
||||
|
||||
-- Admin gets all backup permissions (explicitly assign since admin query in 001 only runs once)
|
||||
INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT r.id, p.id
|
||||
FROM roles r, permissions p
|
||||
WHERE r.name = 'admin'
|
||||
AND p.resource = 'backup'
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- Operator gets read and write permissions for backup
|
||||
INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT r.id, p.id
|
||||
FROM roles r, permissions p
|
||||
WHERE r.name = 'operator'
|
||||
AND p.resource = 'backup'
|
||||
AND p.action IN ('read', 'write')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- ReadOnly gets only read permission for backup
|
||||
INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT r.id, p.id
|
||||
FROM roles r, permissions p
|
||||
WHERE r.name = 'readonly'
|
||||
AND p.resource = 'backup'
|
||||
AND p.action = 'read'
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
-- AtlasOS - Calypso
|
||||
-- PostgreSQL Function to Sync Jobs from Bacula to Calypso
|
||||
-- Version: 11.0
|
||||
--
|
||||
-- This function syncs jobs from Bacula database (Job table) to Calypso database (backup_jobs table)
|
||||
-- Uses dblink extension to query Bacula database from Calypso database
|
||||
--
|
||||
-- Prerequisites:
|
||||
-- 1. dblink extension must be installed: CREATE EXTENSION IF NOT EXISTS dblink;
|
||||
-- 2. User must have access to both databases
|
||||
-- 3. Connection parameters must be configured in the function
|
||||
|
||||
-- Create function to sync jobs from Bacula to Calypso
|
||||
CREATE OR REPLACE FUNCTION sync_bacula_jobs(
|
||||
bacula_db_name TEXT DEFAULT 'bacula',
|
||||
bacula_host TEXT DEFAULT 'localhost',
|
||||
bacula_port INTEGER DEFAULT 5432,
|
||||
bacula_user TEXT DEFAULT 'calypso',
|
||||
bacula_password TEXT DEFAULT ''
|
||||
)
|
||||
RETURNS TABLE(
|
||||
jobs_synced INTEGER,
|
||||
jobs_inserted INTEGER,
|
||||
jobs_updated INTEGER,
|
||||
errors INTEGER
|
||||
) AS $$
|
||||
DECLARE
|
||||
conn_str TEXT;
|
||||
jobs_count INTEGER := 0;
|
||||
inserted_count INTEGER := 0;
|
||||
updated_count INTEGER := 0;
|
||||
error_count INTEGER := 0;
|
||||
job_record RECORD;
|
||||
BEGIN
|
||||
-- Build dblink connection string
|
||||
conn_str := format(
|
||||
'dbname=%s host=%s port=%s user=%s password=%s',
|
||||
bacula_db_name,
|
||||
bacula_host,
|
||||
bacula_port,
|
||||
bacula_user,
|
||||
bacula_password
|
||||
);
|
||||
|
||||
-- Query jobs from Bacula database using dblink
|
||||
FOR job_record IN
|
||||
SELECT * FROM dblink(
|
||||
conn_str,
|
||||
$QUERY$
|
||||
SELECT
|
||||
j.JobId,
|
||||
j.Name as job_name,
|
||||
COALESCE(c.Name, 'unknown') as client_name,
|
||||
CASE
|
||||
WHEN j.Type = 'B' THEN 'Backup'
|
||||
WHEN j.Type = 'R' THEN 'Restore'
|
||||
WHEN j.Type = 'V' THEN 'Verify'
|
||||
WHEN j.Type = 'C' THEN 'Copy'
|
||||
WHEN j.Type = 'M' THEN 'Migrate'
|
||||
ELSE 'Backup'
|
||||
END as job_type,
|
||||
CASE
|
||||
WHEN j.Level = 'F' THEN 'Full'
|
||||
WHEN j.Level = 'I' THEN 'Incremental'
|
||||
WHEN j.Level = 'D' THEN 'Differential'
|
||||
WHEN j.Level = 'S' THEN 'Since'
|
||||
ELSE 'Full'
|
||||
END as job_level,
|
||||
CASE
|
||||
WHEN j.JobStatus = 'T' THEN 'Running'
|
||||
WHEN j.JobStatus = 'C' THEN 'Completed'
|
||||
WHEN j.JobStatus = 'f' OR j.JobStatus = 'F' THEN 'Failed'
|
||||
WHEN j.JobStatus = 'A' THEN 'Canceled'
|
||||
WHEN j.JobStatus = 'W' THEN 'Waiting'
|
||||
ELSE 'Waiting'
|
||||
END as status,
|
||||
COALESCE(j.JobBytes, 0) as bytes_written,
|
||||
COALESCE(j.JobFiles, 0) as files_written,
|
||||
j.StartTime as started_at,
|
||||
j.EndTime as ended_at,
|
||||
CASE
|
||||
WHEN j.EndTime IS NOT NULL AND j.StartTime IS NOT NULL
|
||||
THEN EXTRACT(EPOCH FROM (j.EndTime - j.StartTime))::INTEGER
|
||||
ELSE NULL
|
||||
END as duration_seconds
|
||||
FROM Job j
|
||||
LEFT JOIN Client c ON j.ClientId = c.ClientId
|
||||
ORDER BY j.StartTime DESC
|
||||
LIMIT 1000
|
||||
$QUERY$
|
||||
) AS t(
|
||||
job_id INTEGER,
|
||||
job_name TEXT,
|
||||
client_name TEXT,
|
||||
job_type TEXT,
|
||||
job_level TEXT,
|
||||
status TEXT,
|
||||
bytes_written BIGINT,
|
||||
files_written INTEGER,
|
||||
started_at TIMESTAMP,
|
||||
ended_at TIMESTAMP,
|
||||
duration_seconds INTEGER
|
||||
)
|
||||
LOOP
|
||||
BEGIN
|
||||
-- Check if job already exists (before insert/update)
|
||||
IF EXISTS (SELECT 1 FROM backup_jobs WHERE job_id = job_record.job_id) THEN
|
||||
updated_count := updated_count + 1;
|
||||
ELSE
|
||||
inserted_count := inserted_count + 1;
|
||||
END IF;
|
||||
|
||||
-- Upsert job to backup_jobs table
|
||||
INSERT INTO backup_jobs (
|
||||
job_id, job_name, client_name, job_type, job_level, status,
|
||||
bytes_written, files_written, started_at, ended_at, duration_seconds,
|
||||
updated_at
|
||||
) VALUES (
|
||||
job_record.job_id,
|
||||
job_record.job_name,
|
||||
job_record.client_name,
|
||||
job_record.job_type,
|
||||
job_record.job_level,
|
||||
job_record.status,
|
||||
job_record.bytes_written,
|
||||
job_record.files_written,
|
||||
job_record.started_at,
|
||||
job_record.ended_at,
|
||||
job_record.duration_seconds,
|
||||
NOW()
|
||||
)
|
||||
ON CONFLICT (job_id) DO UPDATE SET
|
||||
job_name = EXCLUDED.job_name,
|
||||
client_name = EXCLUDED.client_name,
|
||||
job_type = EXCLUDED.job_type,
|
||||
job_level = EXCLUDED.job_level,
|
||||
status = EXCLUDED.status,
|
||||
bytes_written = EXCLUDED.bytes_written,
|
||||
files_written = EXCLUDED.files_written,
|
||||
started_at = EXCLUDED.started_at,
|
||||
ended_at = EXCLUDED.ended_at,
|
||||
duration_seconds = EXCLUDED.duration_seconds,
|
||||
updated_at = NOW();
|
||||
|
||||
jobs_count := jobs_count + 1;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
error_count := error_count + 1;
|
||||
-- Log error but continue with next job
|
||||
RAISE WARNING 'Error syncing job %: %', job_record.job_id, SQLERRM;
|
||||
END;
|
||||
END LOOP;
|
||||
|
||||
-- Return summary
|
||||
RETURN QUERY SELECT jobs_count, inserted_count, updated_count, error_count;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Create a simpler version that uses current database connection settings
|
||||
-- This version assumes Bacula is on same host/port with same user
|
||||
CREATE OR REPLACE FUNCTION sync_bacula_jobs_simple()
|
||||
RETURNS TABLE(
|
||||
jobs_synced INTEGER,
|
||||
jobs_inserted INTEGER,
|
||||
jobs_updated INTEGER,
|
||||
errors INTEGER
|
||||
) AS $$
|
||||
DECLARE
|
||||
current_user_name TEXT;
|
||||
current_host TEXT;
|
||||
current_port INTEGER;
|
||||
current_db TEXT;
|
||||
BEGIN
|
||||
-- Get current connection info
|
||||
SELECT
|
||||
current_user,
|
||||
COALESCE(inet_server_addr()::TEXT, 'localhost'),
|
||||
COALESCE(inet_server_port(), 5432),
|
||||
current_database()
|
||||
INTO
|
||||
current_user_name,
|
||||
current_host,
|
||||
current_port,
|
||||
current_db;
|
||||
|
||||
-- Call main function with current connection settings
|
||||
-- Note: password needs to be passed or configured in .pgpass
|
||||
RETURN QUERY
|
||||
SELECT * FROM sync_bacula_jobs(
|
||||
'bacula', -- Try 'bacula' first
|
||||
current_host,
|
||||
current_port,
|
||||
current_user_name,
|
||||
'' -- Empty password - will use .pgpass or peer authentication
|
||||
);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Grant execute permission to calypso user
|
||||
GRANT EXECUTE ON FUNCTION sync_bacula_jobs(TEXT, TEXT, INTEGER, TEXT, TEXT) TO calypso;
|
||||
GRANT EXECUTE ON FUNCTION sync_bacula_jobs_simple() TO calypso;
|
||||
|
||||
-- Create index if not exists (should already exist from migration 009)
|
||||
CREATE INDEX IF NOT EXISTS idx_backup_jobs_job_id ON backup_jobs(job_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_backup_jobs_updated_at ON backup_jobs(updated_at);
|
||||
|
||||
COMMENT ON FUNCTION sync_bacula_jobs IS 'Syncs jobs from Bacula database to Calypso backup_jobs table using dblink';
|
||||
COMMENT ON FUNCTION sync_bacula_jobs_simple IS 'Simplified version that uses current connection settings (requires .pgpass for password)';
|
||||
|
||||
Vendored
+209
@@ -0,0 +1,209 @@
|
||||
-- AtlasOS - Calypso
|
||||
-- PostgreSQL Function to Sync Jobs from Bacula to Calypso
|
||||
-- Version: 11.0
|
||||
--
|
||||
-- This function syncs jobs from Bacula database (Job table) to Calypso database (backup_jobs table)
|
||||
-- Uses dblink extension to query Bacula database from Calypso database
|
||||
--
|
||||
-- Prerequisites:
|
||||
-- 1. dblink extension must be installed: CREATE EXTENSION IF NOT EXISTS dblink;
|
||||
-- 2. User must have access to both databases
|
||||
-- 3. Connection parameters must be configured in the function
|
||||
|
||||
-- Create function to sync jobs from Bacula to Calypso
|
||||
CREATE OR REPLACE FUNCTION sync_bacula_jobs(
|
||||
bacula_db_name TEXT DEFAULT 'bacula',
|
||||
bacula_host TEXT DEFAULT 'localhost',
|
||||
bacula_port INTEGER DEFAULT 5432,
|
||||
bacula_user TEXT DEFAULT 'calypso',
|
||||
bacula_password TEXT DEFAULT ''
|
||||
)
|
||||
RETURNS TABLE(
|
||||
jobs_synced INTEGER,
|
||||
jobs_inserted INTEGER,
|
||||
jobs_updated INTEGER,
|
||||
errors INTEGER
|
||||
) AS $$
|
||||
DECLARE
|
||||
conn_str TEXT;
|
||||
jobs_count INTEGER := 0;
|
||||
inserted_count INTEGER := 0;
|
||||
updated_count INTEGER := 0;
|
||||
error_count INTEGER := 0;
|
||||
job_record RECORD;
|
||||
BEGIN
|
||||
-- Build dblink connection string
|
||||
conn_str := format(
|
||||
'dbname=%s host=%s port=%s user=%s password=%s',
|
||||
bacula_db_name,
|
||||
bacula_host,
|
||||
bacula_port,
|
||||
bacula_user,
|
||||
bacula_password
|
||||
);
|
||||
|
||||
-- Query jobs from Bacula database using dblink
|
||||
FOR job_record IN
|
||||
SELECT * FROM dblink(
|
||||
conn_str,
|
||||
$$
|
||||
SELECT
|
||||
j.JobId,
|
||||
j.Name as job_name,
|
||||
COALESCE(c.Name, 'unknown') as client_name,
|
||||
CASE
|
||||
WHEN j.Type = 'B' THEN 'Backup'
|
||||
WHEN j.Type = 'R' THEN 'Restore'
|
||||
WHEN j.Type = 'V' THEN 'Verify'
|
||||
WHEN j.Type = 'C' THEN 'Copy'
|
||||
WHEN j.Type = 'M' THEN 'Migrate'
|
||||
ELSE 'Backup'
|
||||
END as job_type,
|
||||
CASE
|
||||
WHEN j.Level = 'F' THEN 'Full'
|
||||
WHEN j.Level = 'I' THEN 'Incremental'
|
||||
WHEN j.Level = 'D' THEN 'Differential'
|
||||
WHEN j.Level = 'S' THEN 'Since'
|
||||
ELSE 'Full'
|
||||
END as job_level,
|
||||
CASE
|
||||
WHEN j.JobStatus = 'T' THEN 'Running'
|
||||
WHEN j.JobStatus = 'C' THEN 'Completed'
|
||||
WHEN j.JobStatus = 'f' OR j.JobStatus = 'F' THEN 'Failed'
|
||||
WHEN j.JobStatus = 'A' THEN 'Canceled'
|
||||
WHEN j.JobStatus = 'W' THEN 'Waiting'
|
||||
ELSE 'Waiting'
|
||||
END as status,
|
||||
COALESCE(j.JobBytes, 0) as bytes_written,
|
||||
COALESCE(j.JobFiles, 0) as files_written,
|
||||
j.StartTime as started_at,
|
||||
j.EndTime as ended_at,
|
||||
CASE
|
||||
WHEN j.EndTime IS NOT NULL AND j.StartTime IS NOT NULL
|
||||
THEN EXTRACT(EPOCH FROM (j.EndTime - j.StartTime))::INTEGER
|
||||
ELSE NULL
|
||||
END as duration_seconds
|
||||
FROM Job j
|
||||
LEFT JOIN Client c ON j.ClientId = c.ClientId
|
||||
ORDER BY j.StartTime DESC
|
||||
LIMIT 1000
|
||||
$$
|
||||
) AS t(
|
||||
job_id INTEGER,
|
||||
job_name TEXT,
|
||||
client_name TEXT,
|
||||
job_type TEXT,
|
||||
job_level TEXT,
|
||||
status TEXT,
|
||||
bytes_written BIGINT,
|
||||
files_written INTEGER,
|
||||
started_at TIMESTAMP,
|
||||
ended_at TIMESTAMP,
|
||||
duration_seconds INTEGER
|
||||
)
|
||||
LOOP
|
||||
BEGIN
|
||||
-- Check if job already exists (before insert/update)
|
||||
IF EXISTS (SELECT 1 FROM backup_jobs WHERE job_id = job_record.job_id) THEN
|
||||
updated_count := updated_count + 1;
|
||||
ELSE
|
||||
inserted_count := inserted_count + 1;
|
||||
END IF;
|
||||
|
||||
-- Upsert job to backup_jobs table
|
||||
INSERT INTO backup_jobs (
|
||||
job_id, job_name, client_name, job_type, job_level, status,
|
||||
bytes_written, files_written, started_at, ended_at, duration_seconds,
|
||||
updated_at
|
||||
) VALUES (
|
||||
job_record.job_id,
|
||||
job_record.job_name,
|
||||
job_record.client_name,
|
||||
job_record.job_type,
|
||||
job_record.job_level,
|
||||
job_record.status,
|
||||
job_record.bytes_written,
|
||||
job_record.files_written,
|
||||
job_record.started_at,
|
||||
job_record.ended_at,
|
||||
job_record.duration_seconds,
|
||||
NOW()
|
||||
)
|
||||
ON CONFLICT (job_id) DO UPDATE SET
|
||||
job_name = EXCLUDED.job_name,
|
||||
client_name = EXCLUDED.client_name,
|
||||
job_type = EXCLUDED.job_type,
|
||||
job_level = EXCLUDED.job_level,
|
||||
status = EXCLUDED.status,
|
||||
bytes_written = EXCLUDED.bytes_written,
|
||||
files_written = EXCLUDED.files_written,
|
||||
started_at = EXCLUDED.started_at,
|
||||
ended_at = EXCLUDED.ended_at,
|
||||
duration_seconds = EXCLUDED.duration_seconds,
|
||||
updated_at = NOW();
|
||||
|
||||
jobs_count := jobs_count + 1;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
error_count := error_count + 1;
|
||||
-- Log error but continue with next job
|
||||
RAISE WARNING 'Error syncing job %: %', job_record.job_id, SQLERRM;
|
||||
END;
|
||||
END LOOP;
|
||||
|
||||
-- Return summary
|
||||
RETURN QUERY SELECT jobs_count, inserted_count, updated_count, error_count;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Create a simpler version that uses current database connection settings
|
||||
-- This version assumes Bacula is on same host/port with same user
|
||||
CREATE OR REPLACE FUNCTION sync_bacula_jobs_simple()
|
||||
RETURNS TABLE(
|
||||
jobs_synced INTEGER,
|
||||
jobs_inserted INTEGER,
|
||||
jobs_updated INTEGER,
|
||||
errors INTEGER
|
||||
) AS $$
|
||||
DECLARE
|
||||
current_user_name TEXT;
|
||||
current_host TEXT;
|
||||
current_port INTEGER;
|
||||
current_db TEXT;
|
||||
BEGIN
|
||||
-- Get current connection info
|
||||
SELECT
|
||||
current_user,
|
||||
COALESCE(inet_server_addr()::TEXT, 'localhost'),
|
||||
COALESCE(inet_server_port(), 5432),
|
||||
current_database()
|
||||
INTO
|
||||
current_user_name,
|
||||
current_host,
|
||||
current_port,
|
||||
current_db;
|
||||
|
||||
-- Call main function with current connection settings
|
||||
-- Note: password needs to be passed or configured in .pgpass
|
||||
RETURN QUERY
|
||||
SELECT * FROM sync_bacula_jobs(
|
||||
'bacula', -- Try 'bacula' first
|
||||
current_host,
|
||||
current_port,
|
||||
current_user_name,
|
||||
'' -- Empty password - will use .pgpass or peer authentication
|
||||
);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Grant execute permission to calypso user
|
||||
GRANT EXECUTE ON FUNCTION sync_bacula_jobs(TEXT, TEXT, INTEGER, TEXT, TEXT) TO calypso;
|
||||
GRANT EXECUTE ON FUNCTION sync_bacula_jobs_simple() TO calypso;
|
||||
|
||||
-- Create index if not exists (should already exist from migration 009)
|
||||
CREATE INDEX IF NOT EXISTS idx_backup_jobs_job_id ON backup_jobs(job_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_backup_jobs_updated_at ON backup_jobs(updated_at);
|
||||
|
||||
COMMENT ON FUNCTION sync_bacula_jobs IS 'Syncs jobs from Bacula database to Calypso backup_jobs table using dblink';
|
||||
COMMENT ON FUNCTION sync_bacula_jobs_simple IS 'Simplified version that uses current connection settings (requires .pgpass for password)';
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
-- Snapshot schedules table for automated snapshot creation
|
||||
CREATE TABLE IF NOT EXISTS snapshot_schedules (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(255) NOT NULL,
|
||||
dataset VARCHAR(255) NOT NULL,
|
||||
snapshot_name_template VARCHAR(255) NOT NULL, -- e.g., "auto-%Y-%m-%d-%H%M" or "daily-backup"
|
||||
schedule_type VARCHAR(50) NOT NULL, -- 'hourly', 'daily', 'weekly', 'monthly', 'cron'
|
||||
schedule_config JSONB NOT NULL, -- For cron: {"cron": "0 0 * * *"}, for others: {"time": "00:00", "day": 1, etc.}
|
||||
recursive BOOLEAN NOT NULL DEFAULT false,
|
||||
enabled BOOLEAN NOT NULL DEFAULT true,
|
||||
retention_count INTEGER, -- Keep last N snapshots (null = unlimited)
|
||||
retention_days INTEGER, -- Keep snapshots for N days (null = unlimited)
|
||||
last_run_at TIMESTAMP,
|
||||
next_run_at TIMESTAMP,
|
||||
created_by UUID REFERENCES users(id),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
UNIQUE(name)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_snapshot_schedules_enabled ON snapshot_schedules(enabled);
|
||||
CREATE INDEX IF NOT EXISTS idx_snapshot_schedules_next_run ON snapshot_schedules(next_run_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_snapshot_schedules_dataset ON snapshot_schedules(dataset);
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
-- ZFS Replication Tasks Table
|
||||
-- Supports both outbound (sender) and inbound (receiver) replication
|
||||
CREATE TABLE IF NOT EXISTS replication_tasks (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(255) NOT NULL,
|
||||
direction VARCHAR(20) NOT NULL, -- 'outbound' (sender) or 'inbound' (receiver)
|
||||
|
||||
-- For outbound replication (sender)
|
||||
source_dataset VARCHAR(512), -- Source dataset on this system (outbound) or remote system (inbound)
|
||||
target_host VARCHAR(255), -- Target host IP or hostname (for outbound)
|
||||
target_port INTEGER DEFAULT 22, -- SSH port (default 22, for outbound)
|
||||
target_user VARCHAR(255) DEFAULT 'root', -- SSH user (for outbound)
|
||||
target_dataset VARCHAR(512), -- Target dataset on remote system (for outbound)
|
||||
target_ssh_key_path TEXT, -- Path to SSH private key (for outbound)
|
||||
|
||||
-- For inbound replication (receiver)
|
||||
source_host VARCHAR(255), -- Source host IP or hostname (for inbound)
|
||||
source_port INTEGER DEFAULT 22, -- SSH port (for inbound)
|
||||
source_user VARCHAR(255) DEFAULT 'root', -- SSH user (for inbound)
|
||||
local_dataset VARCHAR(512), -- Local dataset to receive snapshots (for inbound)
|
||||
|
||||
-- Common settings
|
||||
schedule_type VARCHAR(50), -- 'manual', 'hourly', 'daily', 'weekly', 'monthly', 'cron'
|
||||
schedule_config JSONB, -- Schedule configuration (similar to snapshot schedules)
|
||||
compression VARCHAR(50) DEFAULT 'lz4', -- 'off', 'lz4', 'gzip', 'zstd'
|
||||
encryption BOOLEAN DEFAULT false, -- Enable encryption during transfer
|
||||
recursive BOOLEAN DEFAULT false, -- Replicate recursively
|
||||
incremental BOOLEAN DEFAULT true, -- Use incremental replication
|
||||
auto_snapshot BOOLEAN DEFAULT true, -- Auto-create snapshot before replication
|
||||
|
||||
-- Status and tracking
|
||||
enabled BOOLEAN NOT NULL DEFAULT true,
|
||||
status VARCHAR(50) DEFAULT 'idle', -- 'idle', 'running', 'failed', 'paused'
|
||||
last_run_at TIMESTAMP,
|
||||
last_run_status VARCHAR(50), -- 'success', 'failed', 'partial'
|
||||
last_run_error TEXT,
|
||||
next_run_at TIMESTAMP,
|
||||
last_snapshot_sent VARCHAR(512), -- Last snapshot successfully sent (for outbound)
|
||||
last_snapshot_received VARCHAR(512), -- Last snapshot successfully received (for inbound)
|
||||
|
||||
-- Statistics
|
||||
total_runs INTEGER DEFAULT 0,
|
||||
successful_runs INTEGER DEFAULT 0,
|
||||
failed_runs INTEGER DEFAULT 0,
|
||||
bytes_sent BIGINT DEFAULT 0, -- Total bytes sent (for outbound)
|
||||
bytes_received BIGINT DEFAULT 0, -- Total bytes received (for inbound)
|
||||
|
||||
created_by UUID REFERENCES users(id),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
|
||||
-- Validation: ensure required fields based on direction
|
||||
CONSTRAINT chk_direction CHECK (direction IN ('outbound', 'inbound')),
|
||||
CONSTRAINT chk_outbound_fields CHECK (
|
||||
direction != 'outbound' OR (
|
||||
source_dataset IS NOT NULL AND
|
||||
target_host IS NOT NULL AND
|
||||
target_dataset IS NOT NULL
|
||||
)
|
||||
),
|
||||
CONSTRAINT chk_inbound_fields CHECK (
|
||||
direction != 'inbound' OR (
|
||||
source_host IS NOT NULL AND
|
||||
source_dataset IS NOT NULL AND
|
||||
local_dataset IS NOT NULL
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
-- Create indexes
|
||||
CREATE INDEX IF NOT EXISTS idx_replication_tasks_direction ON replication_tasks(direction);
|
||||
CREATE INDEX IF NOT EXISTS idx_replication_tasks_enabled ON replication_tasks(enabled);
|
||||
CREATE INDEX IF NOT EXISTS idx_replication_tasks_status ON replication_tasks(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_replication_tasks_next_run ON replication_tasks(next_run_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_replication_tasks_source_dataset ON replication_tasks(source_dataset);
|
||||
CREATE INDEX IF NOT EXISTS idx_replication_tasks_target_host ON replication_tasks(target_host);
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
-- AtlasOS - Calypso
|
||||
-- Client Categories Schema
|
||||
-- Version: 14.0
|
||||
-- Adds category support for backup clients (File, Database, Virtual)
|
||||
|
||||
-- Client metadata table to store additional information about clients
|
||||
-- This extends the Bacula Client table with Calypso-specific metadata
|
||||
CREATE TABLE IF NOT EXISTS client_metadata (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
client_id INTEGER NOT NULL, -- Bacula Client.ClientId
|
||||
client_name VARCHAR(255) NOT NULL, -- Bacula Client.Name (for reference)
|
||||
category VARCHAR(50) NOT NULL DEFAULT 'File', -- 'File', 'Database', 'Virtual'
|
||||
description TEXT,
|
||||
tags JSONB, -- Additional tags/metadata as JSON
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
|
||||
-- Ensure one metadata entry per client
|
||||
CONSTRAINT unique_client_id UNIQUE (client_id),
|
||||
CONSTRAINT chk_category CHECK (category IN ('File', 'Database', 'Virtual'))
|
||||
);
|
||||
|
||||
-- Indexes for performance
|
||||
CREATE INDEX IF NOT EXISTS idx_client_metadata_client_id ON client_metadata(client_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_client_metadata_client_name ON client_metadata(client_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_client_metadata_category ON client_metadata(category);
|
||||
|
||||
-- Add comment
|
||||
COMMENT ON TABLE client_metadata IS 'Stores Calypso-specific metadata for backup clients, including category classification';
|
||||
COMMENT ON COLUMN client_metadata.category IS 'Client category: File (file system backups), Database (database backups), Virtual (virtual machine backups)';
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
-- AtlasOS - Calypso
|
||||
-- Migration 015: Add Bacula clients and capability history tables
|
||||
--
|
||||
-- Adds tables for tracking registered Bacula agents, their backup capabilities,
|
||||
-- and a history log for UI- or agent-triggered capability changes. Pending
|
||||
-- updates are stored on the client row until the agent pulls them.
|
||||
|
||||
CREATE TABLE IF NOT EXISTS bacula_clients (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
hostname TEXT NOT NULL,
|
||||
ip_address TEXT,
|
||||
agent_version TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'online',
|
||||
backup_types JSONB NOT NULL,
|
||||
pending_backup_types JSONB,
|
||||
pending_requested_by UUID,
|
||||
pending_requested_at TIMESTAMPTZ,
|
||||
pending_notes TEXT,
|
||||
metadata JSONB,
|
||||
registered_by_user_id UUID NOT NULL,
|
||||
last_seen TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
CONSTRAINT uniq_bacula_clients_hostname UNIQUE (hostname)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_bacula_clients_registered_by ON bacula_clients (registered_by_user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_bacula_clients_status ON bacula_clients (status);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS bacula_client_capability_history (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
client_id UUID NOT NULL REFERENCES bacula_clients (id) ON DELETE CASCADE,
|
||||
backup_types JSONB NOT NULL,
|
||||
source TEXT NOT NULL,
|
||||
requested_by_user_id UUID,
|
||||
requested_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
notes TEXT
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_bacula_client_capability_history_client ON bacula_client_capability_history (client_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_bacula_client_capability_history_requested_at ON bacula_client_capability_history (requested_at);
|
||||
|
||||
COMMENT ON TABLE bacula_clients IS 'Tracks Bacula clients registered with Calypso, including pending capability pushes.';
|
||||
COMMENT ON TABLE bacula_client_capability_history IS 'Audit history of backup capability changes per client.';
|
||||
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
dist/airgap/calypso-appliance-1.0.0-airgap/packages/debs/dhcpcd-base_1%3a10.0.6-1ubuntu3.1_amd64.deb
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user