Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
4.1 KiB
4.1 KiB
포털 ↔ HAL 작업 계약(HAL-JOBS)
포털 어댑터 portal/hal/client.mjs(deps.hal) 와 HAL /portal/v1/* 가 공유하는 계약. 인증은 lib/serviceauth(키 id portal).
deps.hal (포털 쪽 인터페이스)
hal.createJob({ kind, target, payload, idempotencyKey, groupId, subjectType, subjectId }) → { halJobId, status }
hal.getJob(halJobId) → { id, kind, status(lib/status JOB_STATUS 코드), steps:[{id,title,state,detail}], progress, result, error, errorCode, updatedAt, children? }
hal.cancelJob(halJobId) / hal.retryJob(halJobId) / hal.revertJob(halJobId) / hal.resumeJob(halJobId)
hal.listServers({ role }) → [{ id, name, role:'web'|'mail'|'backup'|'control', location, status:'ready'|'maintenance'|'isolated'|'offline', acceptsNew, health, lastSeenAt, capacity:{ diskFreeBytes, diskTotalBytes, memFreeBytes, cpuLoad, sitesHosted, reservedBytes }, version:{ agent, modules:{} } }]
hal.pickServer({ role:'web', needBytes }) → { serverId } | null // 신규 배치 허용·여유 있는 서버
hal.issueExternalAgentToken({ groupId, siteId, label }) → { agentId, token(1회), expiresAt, installCommand }
hal.getExternalAgent(agentId) → { id, status:'pending'|'connected'|'offline'|'revoked', lastSeenAt, version, lastDeploy:{...} }
hal.revokeExternalAgent(agentId)
hal.health() → { ok, version, uptime } // 실패 시 code 'service_unreachable'
HAL 이 응답하지 않으면 어댑터는 service_unreachable 을 던지고 호출자는 정보 확인 지연 을 표시하며 신규 증가를 허용하지 않는다.
HAL 은 작업 상태 변화를 포털 POST /internal/hal-events (키 id hal) 로 민다: { halJobId, status, steps, result, error, updatedAt }. 포털은 5초 주기 조회로도 맞춘다.
작업 종류와 payload (target = 관리 서버 id 또는 외부 Agent id)
| kind | payload | result |
|---|---|---|
site.deploy |
`{ siteId, versionRef, bundleUrl(포털이 Webmaker 저장본을 tar.gz 로 내놓는 서명 URL) 또는 bundleFromWebmaker:{projectId, versionRef}, runtime:'static' | 'node', env:{}, domains:[...], primaryDomain, previousVersion, external:bool }` |
site.rollback |
{ siteId, toVersion } |
{ version } |
site.remove |
{ siteId, keepData:bool } |
{ removed:true, leftovers:[] } |
site.check |
{ siteId, urls:[...], expectMarker } |
{ checks:[{url,status,ok,ms,tls:{valid,expiresAt}}] } |
site.usage |
{ siteIds:[...] } |
{ sites:{ [siteId]: { diskBytes, dbBytes, uploadsBytes, outBytesDay, outBytesMonth, outBytesTotal, inBytesDay, inBytesMonth, inBytesTotal, req24h, pv24h, series7d:[...], series30d:[...], errorRate, p95ms, measuredAt } } } |
domain.vhost |
{ siteId, domains:[...], primaryDomain, redirectOld:bool, maintenance:bool } |
{ applied:[...], certs:{domain:{state,expiresAt}} } |
domain.cert |
{ siteId, domains:[...], email } |
{ issued:[...], failed:[{domain,reason}], expiresAt } |
domain.probe |
{ name, expectA:[...], expectTxt:{name,value}? } |
{ a:[...], txtOk, resolvedAt } |
backup.create |
{ siteId, scope:{files,db,uploads,config}, storeServerId, retentionTag } |
{ backupId, location, sizeBytes, checksum, verified:true, createdAt } |
backup.verify |
{ location, checksum } |
{ ok } |
backup.restore |
{ siteId, location, checksum, protectPoint:true, isolatedVerify:true } |
{ protectPointLocation, restoredVersion, externalCheck } |
backup.delete |
{ location } |
{ deleted } |
site.relocate |
`{ siteId, fromServerId, toServerId, kind:'static' | 'dynamic', writeFreeze:bool, domains, primaryDomain }` |
module.deploy / module.update / module.rollback / module.health |
HAL 내부(운영자 콘솔) | 대상별 자식 작업 |
External Pull Agent(외부 서버)는 site.deploy·site.remove·site.check 만 받는다.