# Dataset Mountpoint Validation

## Issue
User meminta validasi bahwa mount point untuk dataset dan volume harus berada di dalam directory pool yang terkait.

## Solution
Menambahkan validasi untuk memastikan mount point dataset berada di dalam pool mount point directory (`/opt/calypso/data/pool/<pool-name>/`).

## Changes Made

### Updated `backend/internal/storage/zfs.go`
**File**: `backend/internal/storage/zfs.go` (line 728-814)

**Key Changes:**

1. **Mount Point Validation**
   - Validasi bahwa mount point yang user berikan harus berada di dalam pool directory
   - Menggunakan `filepath.Rel()` untuk memastikan mount point tidak keluar dari pool directory

2. **Default Mount Point**
   - Jika mount point tidak disediakan, set default ke `/opt/calypso/data/pool/<pool-name>/<dataset-name>/`
   - Memastikan semua dataset mount point berada di dalam pool directory

3. **Mount Point Always Set**
   - Untuk filesystem datasets, mount point selalu di-set (baik user-provided atau default)
   - Tidak lagi conditional pada `req.MountPoint != ""`

**Before:**
```go
if req.Type == "filesystem" && req.MountPoint != "" {
    mountPath := filepath.Clean(req.MountPoint)
    // ... create directory ...
}

// Later:
if req.Type == "filesystem" && req.MountPoint != "" {
    args = append(args, "-o", fmt.Sprintf("mountpoint=%s", req.MountPoint))
}
```

**After:**
```go
poolMountPoint := fmt.Sprintf("/opt/calypso/data/pool/%s", poolName)
var mountPath string

if req.Type == "filesystem" {
    if req.MountPoint != "" {
        // Validate mount point is within pool directory
        mountPath = filepath.Clean(req.MountPoint)
        // ... validation logic ...
    } else {
        // Use default mount point
        mountPath = filepath.Join(poolMountPoint, req.Name)
    }
    // ... create directory ...
}

// Later:
if req.Type == "filesystem" {
    args = append(args, "-o", fmt.Sprintf("mountpoint=%s", mountPath))
}
```

## Mount Point Structure

### Pool Mount Point
```
/opt/calypso/data/pool/<pool-name>/
```

### Dataset Mount Point (Default)
```
/opt/calypso/data/pool/<pool-name>/<dataset-name>/
```

### Dataset Mount Point (Custom - must be within pool)
```
/opt/calypso/data/pool/<pool-name>/<custom-path>/
```

## Validation Rules

1. **User-provided mount point**:
   - Must be within `/opt/calypso/data/pool/<pool-name>/`
   - Cannot use `..` to escape pool directory
   - Must be a valid directory path

2. **Default mount point**:
   - Automatically set to `/opt/calypso/data/pool/<pool-name>/<dataset-name>/`
   - Always within pool directory

3. **Volumes**:
   - Volumes cannot have mount points (already validated in handler)

## Error Messages

- `mount point must be within pool directory: <path> (pool mount: <pool-mount>)` - Jika mount point di luar pool directory
- `mount point path exists but is not a directory: <path>` - Jika path sudah ada tapi bukan directory
- `failed to create mount directory <path>` - Jika gagal membuat directory

## Testing

1. **Create dataset without mount point**:
   - Should use default: `/opt/calypso/data/pool/<pool-name>/<dataset-name>/`

2. **Create dataset with valid mount point**:
   - Mount point: `/opt/calypso/data/pool/<pool-name>/custom-path/`
   - Should succeed

3. **Create dataset with invalid mount point**:
   - Mount point: `/opt/calypso/data/other-path/`
   - Should fail with validation error

4. **Create volume**:
   - Should not set mount point (volumes don't have mount points)

## Status
✅ **COMPLETED** - Mount point validation untuk dataset sudah diterapkan

## Date
2026-01-09
