apiVersion: v1
kind: Namespace
metadata:
  name: clawmanager-system
---
apiVersion: v1
kind: Secret
metadata:
  name: clawmanager-secrets
  namespace: clawmanager-system
type: Opaque
stringData:
  mysql-root-password: root123
  mysql-password: clawreef123
  jwt-secret: change-me-in-production
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: clawmanager-mysql-init
  namespace: clawmanager-system
data:
  001_init_schema.sql: |
    CREATE DATABASE IF NOT EXISTS clawmanager CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
    USE clawmanager;

    CREATE TABLE IF NOT EXISTS users (
      id INT AUTO_INCREMENT PRIMARY KEY,
      username VARCHAR(255) UNIQUE NOT NULL,
      email VARCHAR(320) UNIQUE NOT NULL,
      password_hash VARCHAR(255) NOT NULL,
      role ENUM('admin', 'user') DEFAULT 'user',
      is_active BOOLEAN DEFAULT TRUE,
      created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
      updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      last_login TIMESTAMP,
      INDEX idx_username (username),
      INDEX idx_role (role)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

    CREATE TABLE IF NOT EXISTS instances (
      id INT AUTO_INCREMENT PRIMARY KEY,
      user_id INT NOT NULL,
      name VARCHAR(255) NOT NULL,
      description TEXT,
      type ENUM('openclaw', 'ubuntu', 'debian', 'centos', 'custom', 'webtop') DEFAULT 'ubuntu',
      status ENUM('creating', 'running', 'stopped', 'error', 'deleting') DEFAULT 'creating',
      cpu_cores INT NOT NULL,
      memory_gb INT NOT NULL,
      disk_gb INT NOT NULL,
      gpu_enabled BOOLEAN DEFAULT FALSE,
      gpu_type VARCHAR(100),
      gpu_count INT DEFAULT 0,
      os_type VARCHAR(50) NOT NULL,
      os_version VARCHAR(50) NOT NULL,
      image_registry VARCHAR(255),
      image_tag VARCHAR(100),
      storage_class VARCHAR(50) DEFAULT 'standard',
      mount_path VARCHAR(255) DEFAULT '/data',
      pod_name VARCHAR(255),
      pod_namespace VARCHAR(255),
      pod_ip VARCHAR(45),
      access_url VARCHAR(500),
      access_token VARCHAR(255),
      created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
      updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      started_at TIMESTAMP,
      stopped_at TIMESTAMP,
      FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
      INDEX idx_user_id (user_id),
      INDEX idx_status (status),
      INDEX idx_type (type)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

    CREATE TABLE IF NOT EXISTS persistent_volumes (
      id INT AUTO_INCREMENT PRIMARY KEY,
      instance_id INT NOT NULL,
      pvc_name VARCHAR(255) UNIQUE NOT NULL,
      pvc_namespace VARCHAR(255) NOT NULL,
      storage_size_gb INT NOT NULL,
      storage_class VARCHAR(50),
      mount_path VARCHAR(255),
      status ENUM('pending', 'bound', 'released', 'failed') DEFAULT 'pending',
      created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
      updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      FOREIGN KEY (instance_id) REFERENCES instances(id) ON DELETE CASCADE,
      INDEX idx_instance_id (instance_id),
      UNIQUE KEY uk_pvc_name_namespace (pvc_name, pvc_namespace)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

    CREATE TABLE IF NOT EXISTS backups (
      id INT AUTO_INCREMENT PRIMARY KEY,
      instance_id INT NOT NULL,
      backup_name VARCHAR(255) NOT NULL,
      backup_size_gb INT,
      backup_path VARCHAR(500),
      status ENUM('creating', 'completed', 'failed', 'deleted') DEFAULT 'creating',
      backup_type ENUM('manual', 'scheduled') DEFAULT 'manual',
      created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
      completed_at TIMESTAMP,
      expires_at TIMESTAMP,
      FOREIGN KEY (instance_id) REFERENCES instances(id) ON DELETE CASCADE,
      INDEX idx_instance_id (instance_id),
      INDEX idx_created_at (created_at)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

    CREATE TABLE IF NOT EXISTS backup_schedules (
      id INT AUTO_INCREMENT PRIMARY KEY,
      instance_id INT NOT NULL,
      schedule_name VARCHAR(255),
      cron_expression VARCHAR(100) NOT NULL,
      retention_days INT DEFAULT 30,
      is_active BOOLEAN DEFAULT TRUE,
      created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
      updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      FOREIGN KEY (instance_id) REFERENCES instances(id) ON DELETE CASCADE,
      INDEX idx_instance_id (instance_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

    CREATE TABLE IF NOT EXISTS user_quotas (
      id INT AUTO_INCREMENT PRIMARY KEY,
      user_id INT NOT NULL UNIQUE,
      max_instances INT DEFAULT 10,
      max_cpu_cores INT DEFAULT 40,
      max_memory_gb INT DEFAULT 100,
      max_storage_gb INT DEFAULT 500,
      max_gpu_count INT DEFAULT 2,
      created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
      updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
      INDEX idx_user_id (user_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

    CREATE TABLE IF NOT EXISTS instance_usage (
      id INT AUTO_INCREMENT PRIMARY KEY,
      instance_id INT NOT NULL,
      cpu_usage_percent DECIMAL(5,2),
      memory_usage_gb DECIMAL(10,2),
      disk_usage_gb DECIMAL(10,2),
      gpu_usage_percent DECIMAL(5,2),
      uptime_seconds INT,
      recorded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
      FOREIGN KEY (instance_id) REFERENCES instances(id) ON DELETE CASCADE,
      INDEX idx_instance_recorded (instance_id, recorded_at)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

    CREATE TABLE IF NOT EXISTS audit_logs (
      id INT AUTO_INCREMENT PRIMARY KEY,
      user_id INT,
      action VARCHAR(100) NOT NULL,
      resource_type VARCHAR(50) NOT NULL,
      resource_id INT,
      details JSON,
      ip_address VARCHAR(45),
      created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
      FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL,
      INDEX idx_user_id (user_id),
      INDEX idx_action (action),
      INDEX idx_created_at (created_at)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

    INSERT INTO users (username, email, password_hash, role, is_active)
    SELECT 'admin', 'admin@clawmanager.local', '$2a$10$pbenze514mwv3pvQySQBVOsF5J4DBXL2kVo1hLa8JFhQu5x3AKvBi', 'admin', TRUE
    WHERE NOT EXISTS (SELECT 1 FROM users WHERE username = 'admin');

    INSERT INTO user_quotas (user_id, max_instances, max_cpu_cores, max_memory_gb, max_storage_gb, max_gpu_count)
    SELECT id, 100, 200, 1000, 5000, 10 FROM users
    WHERE username = 'admin'
      AND NOT EXISTS (SELECT 1 FROM user_quotas WHERE user_id = users.id);
  002_add_webtop_instance_type.sql: |
    USE clawmanager;
    ALTER TABLE instances
    MODIFY COLUMN type ENUM('openclaw', 'ubuntu', 'debian', 'centos', 'custom', 'webtop') DEFAULT 'ubuntu';
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: clawmanager-mysql-pv
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: manual
  hostPath:
    path: /tmp/clawmanager/system/mysql
    type: DirectoryOrCreate
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-data
  namespace: clawmanager-system
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  storageClassName: manual
  volumeName: clawmanager-mysql-pv
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
  namespace: clawmanager-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          #image: mysql:8.4.8
          image: registry.cn-shenzhen.aliyuncs.com/shuhui/mysql:8.4.8
          ports:
            - containerPort: 3306
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: clawmanager-secrets
                  key: mysql-root-password
            - name: MYSQL_DATABASE
              value: clawmanager
            - name: MYSQL_USER
              value: clawmanager
            - name: MYSQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: clawmanager-secrets
                  key: mysql-password
          volumeMounts:
            - name: mysql-data
              mountPath: /var/lib/mysql
            - name: mysql-init
              mountPath: /docker-entrypoint-initdb.d
          readinessProbe:
            exec:
              command: ["sh", "-c", "mysqladmin ping -h 127.0.0.1 -uroot -p$MYSQL_ROOT_PASSWORD"]
            initialDelaySeconds: 20
            periodSeconds: 10
      volumes:
        - name: mysql-data
          persistentVolumeClaim:
            claimName: mysql-data
        - name: mysql-init
          configMap:
            name: clawmanager-mysql-init
---
apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: clawmanager-system
spec:
  selector:
    app: mysql
  ports:
    - name: mysql
      port: 3306
      targetPort: 3306
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: clawmanager-app
  namespace: clawmanager-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: clawmanager-app-cluster-admin
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: clawmanager-app
    namespace: clawmanager-system
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: clawmanager-app
  namespace: clawmanager-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: clawmanager-app
  template:
    metadata:
      labels:
        app: clawmanager-app
    spec:
      serviceAccountName: clawmanager-app
      containers:
        - name: clawmanager-app
          #image: ghcr.io/yuan-lab-llm/clawmanager:latest
          image: registry.cn-shenzhen.aliyuncs.com/shuhui/clawmanager:latest
          imagePullPolicy: IfNotPresent
          ports:
            - name: https
              containerPort: 8443
            - name: proxy
              containerPort: 9001
          env:
            - name: SERVER_ADDRESS
              value: ":9001"
            - name: SERVER_MODE
              value: "release"
            - name: DB_HOST
              value: "mysql"
            - name: DB_PORT
              value: "3306"
            - name: DB_USER
              value: "clawmanager"
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: clawmanager-secrets
                  key: mysql-password
            - name: DB_NAME
              value: "clawmanager"
            - name: JWT_SECRET
              valueFrom:
                secretKeyRef:
                  name: clawmanager-secrets
                  key: jwt-secret
            - name: K8S_MODE
              value: "incluster"
            - name: K8S_NAMESPACE
              value: "clawmanager"
            - name: K8S_STORAGE_CLASS
              value: "manual"
          volumeMounts:
            - name: tls-cert
              mountPath: /var/run/clawreef-tls
              readOnly: true
          readinessProbe:
            httpGet:
              scheme: HTTPS
              path: /healthz
              port: https
            initialDelaySeconds: 10
            periodSeconds: 10
          livenessProbe:
            httpGet:
              scheme: HTTPS
              path: /healthz
              port: https
            initialDelaySeconds: 30
            periodSeconds: 20
      volumes:
        - name: tls-cert
          secret:
            secretName: clawmanager-tls
            optional: true
---
apiVersion: v1
kind: Service
metadata:
  name: clawmanager-frontend
  namespace: clawmanager-system
spec:
  type: NodePort
  selector:
    app: clawmanager-app
  ports:
    - name: https
      port: 443
      targetPort: https
      nodePort: 39443
---
apiVersion: v1
kind: Service
metadata:
  name: clawmanager-gateway
  namespace: clawmanager-system
spec:
  type: ClusterIP
  selector:
    app: clawmanager-app
  ports:
    - name: api
      port: 9001
      targetPort: 9001
---
apiVersion: v1
kind: Service
metadata:
  name: clawmanager-egress-proxy
  namespace: clawmanager-system
spec:
  type: ClusterIP
  selector:
    app: clawmanager-app
  ports:
    - name: proxy
      port: 3128
      targetPort: 9001
