refactor: P2.8 — adoptExistingInstanceOnCreate uses classifyStatus + exhaustive switch

This commit is contained in:
“Naeel”
2026-06-30 17:38:46 +04:00
parent f48772962b
commit 0998b19ec5
@@ -128,18 +128,19 @@ func adoptExistingInstanceOnCreate(ctx context.Context, client *core.UniversalCl
if !resumeIfExists { if !resumeIfExists {
return "", fmt.Errorf("инстанс с resource_name %s уже существует; выберите другое имя, если нужен новый ресурс, или выполните импорт через усыновление: установите adopt_existing_on_create=true и повторите apply. %s", displayName, formatInstanceDetails(existing, serviceID, displayName)) return "", fmt.Errorf("инстанс с resource_name %s уже существует; выберите другое имя, если нужен новый ресурс, или выполните импорт через усыновление: установите adopt_existing_on_create=true и повторите apply. %s", displayName, formatInstanceDetails(existing, serviceID, displayName))
} }
status := normalizeStatus(existing.ExplainedStatus) state := classifyStatus(existing)
if isStatusNotCreated(status) { statusText := normalizeStatus(existing.ExplainedStatus)
switch state {
case StateNotCreated:
// P0.2: авто-cleanup orphan-инстанса при adopt_existing_on_create=true. // P0.2: авто-cleanup orphan-инстанса при adopt_existing_on_create=true.
// Вместо «удалите вручную в ЛК» — удаляем сами и создаём новый.
if err := client.RunInstanceOperationUniversal(ctx, existing.InstanceUid, "delete", nil); err != nil { if err := client.RunInstanceOperationUniversal(ctx, existing.InstanceUid, "delete", nil); err != nil {
return "", fmt.Errorf("не удалось авто-удалить orphan-инстанс %s (статус: %s): %w. %s", return "", fmt.Errorf("не удалось авто-удалить orphan-инстанс %s (статус: %s): %w. %s",
existing.InstanceUid, status, err, formatInstanceDetails(existing, serviceID, displayName)) existing.InstanceUid, statusText, err, formatInstanceDetails(existing, serviceID, displayName))
} }
return client.CreateGenericInstanceUniversalV6(ctx, serviceID, displayName, params) return client.CreateGenericInstanceUniversalV6(ctx, serviceID, displayName, params)
}
if isStatusRunning(status) { case StateRunning, StateRunningPending:
// Валидация ref-параметров для running инстанса при adopt
refIssues, err := ValidateRefParamsOnAdopt(ctx, client, serviceID, params, existing.InstanceUid) refIssues, err := ValidateRefParamsOnAdopt(ctx, client, serviceID, params, existing.InstanceUid)
if err != nil { if err != nil {
return "", fmt.Errorf("ошибка валидации ref-параметров при adopt: %s", err) return "", fmt.Errorf("ошибка валидации ref-параметров при adopt: %s", err)
@@ -148,18 +149,15 @@ func adoptExistingInstanceOnCreate(ctx context.Context, client *core.UniversalCl
return "", fmt.Errorf("%s\n%s", FormatRefParamIssues(refIssues), formatInstanceDetails(existing, serviceID, displayName)) return "", fmt.Errorf("%s\n%s", FormatRefParamIssues(refIssues), formatInstanceDetails(existing, serviceID, displayName))
} }
return existing.InstanceUid, nil return existing.InstanceUid, nil
}
if !isStatusSuspended(status) { case StateSuspended:
return "", fmt.Errorf("инстанс с resource_name %s найден, но статус не подходит для авто-усыновления: %s. %s", displayName, status, formatInstanceDetails(existing, serviceID, displayName)) mismatches, err := RequiredParamsMismatch(ctx, client, serviceID, params, existing.InstanceUid)
} if err != nil {
mismatches, err := RequiredParamsMismatch(ctx, client, serviceID, params, existing.InstanceUid) return "", err
if err != nil { }
return "", err if len(mismatches) > 0 {
} return "", fmt.Errorf("required params mismatch for resource_name %s: %s. %s", displayName, FormatRequiredParamMismatchMessage(mismatches), formatInstanceDetails(existing, serviceID, displayName))
if len(mismatches) > 0 { }
return "", fmt.Errorf("required params mismatch for resource_name %s: %s. %s", displayName, FormatRequiredParamMismatchMessage(mismatches), formatInstanceDetails(existing, serviceID, displayName))
}
if isStatusSuspended(status) {
if err := client.RunInstanceOperationUniversal(ctx, existing.InstanceUid, "resume", nil); err != nil { if err := client.RunInstanceOperationUniversal(ctx, existing.InstanceUid, "resume", nil); err != nil {
return "", err return "", err
} }
@@ -167,18 +165,37 @@ func adoptExistingInstanceOnCreate(ctx context.Context, client *core.UniversalCl
if err != nil { if err != nil {
return "", err return "", err
} }
resumedStatus := normalizeStatus(resumed.ExplainedStatus) resumedState := classifyStatus(resumed)
if isStatusNonAdoptable(resumedStatus) || isStatusSuspended(resumedStatus) { if !isAdoptable(resumedState) {
return "", fmt.Errorf("resource not ready after resume: %s. %s", resumed.ExplainedStatus, formatInstanceDetails(resumed, serviceID, displayName)) return "", fmt.Errorf("resource not ready after resume: %s. %s", resumed.ExplainedStatus, formatInstanceDetails(resumed, serviceID, displayName))
} }
refIssues, err := ValidateRefParamsOnAdopt(ctx, client, serviceID, params, existing.InstanceUid)
if err != nil {
return "", fmt.Errorf("ошибка валидации ref-параметров после resume: %s", err)
}
if HasHardErrors(refIssues) {
return "", fmt.Errorf("%s\n%s", FormatRefParamIssues(refIssues), formatInstanceDetails(existing, serviceID, displayName))
}
return existing.InstanceUid, nil
case StateCreating, StateModifying, StateSuspending, StateResuming, StateDeleting:
return "", fmt.Errorf("инстанс с resource_name %s: операция в процессе (статус: %s). Дождитесь завершения и повторите apply. %s",
displayName, statusText, formatInstanceDetails(existing, serviceID, displayName))
case StateCreationFailed:
return "", fmt.Errorf("инстанс с resource_name %s: создание не удалось (статус: %s). Удалите его в Личном кабинете или установите adopt_existing_on_create=true для авто-очистки. %s",
displayName, statusText, formatInstanceDetails(existing, serviceID, displayName))
case StateModificationFailed, StateSuspendFailed, StateResumeFailed, StateDeletionFailed:
return "", fmt.Errorf("инстанс с resource_name %s: предыдущая операция завершилась ошибкой (статус: %s). Проверьте состояние в Личном кабинете. %s",
displayName, statusText, formatInstanceDetails(existing, serviceID, displayName))
case StateDeleted, StateOrphaned:
return "", fmt.Errorf("инстанс с resource_name %s: удалён или осиротел (статус: %s). Выберите другое имя для нового ресурса. %s",
displayName, statusText, formatInstanceDetails(existing, serviceID, displayName))
default:
return "", fmt.Errorf("инстанс с resource_name %s: неизвестный статус %q. %s",
displayName, statusText, formatInstanceDetails(existing, serviceID, displayName))
} }
// Валидация ref-параметров после resume/adopt
refIssues, err := ValidateRefParamsOnAdopt(ctx, client, serviceID, params, existing.InstanceUid)
if err != nil {
return "", fmt.Errorf("ошибка валидации ref-параметров после resume: %s", err)
}
if HasHardErrors(refIssues) {
return "", fmt.Errorf("%s\n%s", FormatRefParamIssues(refIssues), formatInstanceDetails(existing, serviceID, displayName))
}
return existing.InstanceUid, nil
} }