*/ use HasFactory, HasUuid; protected $fillable = [ 'name', 'datacenter', 'cluster', 'public_ip', 'wg_ip', 'wg_pubkey', 'ssh_host_key', 'api_token_ref', 'total_gb', 'total_ram_mb', 'cpu_cores', 'cpu_weight', 'reserve_pct', 'pve_version', 'status', 'last_seen_at', ]; protected $hidden = ['api_token_ref']; protected function casts(): array { return [ 'api_token_ref' => 'encrypted', 'last_seen_at' => 'datetime', 'total_gb' => 'integer', 'total_ram_mb' => 'integer', 'cpu_cores' => 'integer', 'cpu_weight' => 'integer', 'reserve_pct' => 'integer', ]; } /** Placement runs (polymorphic subject). */ public function runs(): MorphMany { return $this->morphMany(ProvisioningRun::class, 'subject'); } /** Runner hook: a failed onboarding run moves the host to the error status. */ public function onProvisioningFailed(): void { $this->update(['status' => 'error']); } /** Free committable storage: total minus reserve. Instance quotas subtract in B. */ public function freeGb(): int { if ($this->total_gb === null) { return 0; } return (int) floor($this->total_gb * (100 - $this->reserve_pct) / 100); } }