fix(core): подсказки при конфликте имени учитывают отсутствие suspend/resume (no adopt) + supportsSuspend в сигнатурах

This commit is contained in:
Repinoid
2026-09-21 20:26:41 +03:00
parent 3ca0752df8
commit 8d405ba695
@@ -17,15 +17,25 @@ import (
)
// PlanExistingResourceDiagnosticsWithParams returns diagnostics when resource exists and compares required params.
// Устаревшая обёртка: считает, что сервис поддерживает suspend/resume (старое поведение).
func PlanExistingResourceDiagnosticsWithParams(ctx context.Context, client *core.UniversalClient, serviceID int, resourceName string, adoptExistingOnCreate bool, desiredParams map[int]string) diag.Diagnostics {
return PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, client, serviceID, resourceName, adoptExistingOnCreate, desiredParams, "", nil)
return PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, client, serviceID, resourceName, adoptExistingOnCreate, desiredParams, "", nil, true)
}
// PlanExistingResourceDiagnosticsWithParamsAndDomain — см. PlanExistingResourceDiagnosticsWithParams.
func PlanExistingResourceDiagnosticsWithParamsAndDomain(ctx context.Context, client *core.UniversalClient, serviceID int, resourceName string, adoptExistingOnCreate bool, desiredParams map[int]string, desiredDomain string) diag.Diagnostics {
return PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, client, serviceID, resourceName, adoptExistingOnCreate, desiredParams, desiredDomain, nil)
return PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, client, serviceID, resourceName, adoptExistingOnCreate, desiredParams, desiredDomain, nil, true)
}
func PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx context.Context, client *core.UniversalClient, serviceID int, resourceName string, adoptExistingOnCreate bool, desiredParams map[int]string, desiredDomain string, allowedDomainServiceIDs []int) diag.Diagnostics {
// PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices — create-time проверка
// «инстанс с таким именем уже существует».
//
// supportsSuspend — поддерживает ли сервис операции suspend/resume (из YAML-спеки).
// Если НЕТ (например vc_nsxt/Edge), то:
// - советы про resume/adopt для состояния Suspend бессмысленны — такое состояние
// для такого сервиса вообще недостижимо, а усыновление требует resume;
// - корректные действия пользователя: удалить инстанс в ЛК или взять другое имя.
func PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx context.Context, client *core.UniversalClient, serviceID int, resourceName string, adoptExistingOnCreate bool, desiredParams map[int]string, desiredDomain string, allowedDomainServiceIDs []int, supportsSuspend bool) diag.Diagnostics {
f, _ := os.OpenFile("/tmp/nubes_find_debug.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if f != nil {
fmt.Fprintf(f, "[FIND-DEBUG] PlanExistingResourceDiagnostics entered: serviceId=%d name=%q adopt=%v client=%v\n", serviceID, resourceName, adoptExistingOnCreate, client != nil)
@@ -71,7 +81,7 @@ func PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx context.C
}
diags.AddError(
"РЕСУРС С ТАКИМ ИМЕНЕМ УЖЕ СУЩЕСТВУЕТ (RUNNING)",
"Инстанс с таким resource_name уже работает.\nАвто-усыновление отключено (adopt_existing_on_create=false).\nВыберите другое имя, если нужен новый ресурс.\nИли выполните импорт существующего ресурса через усыновление: установите adopt_existing_on_create=true и повторите apply."+formatInstanceDetails(existing, serviceID, resourceName),
"Инстанс с таким resource_name уже работает.\nАвто-усыновление отключено (adopt_existing_on_create=false).\nВыберите другое имя, если нужен новый ресурс."+runningConflictHint(supportsSuspend)+formatInstanceDetails(existing, serviceID, resourceName),
)
return diags
}
@@ -86,7 +96,7 @@ func PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx context.C
if !adoptExistingOnCreate {
diags.AddError(
"РЕСУРС С ТАКИМ ИМЕНЕМ УЖЕ СУЩЕСТВУЕТ (SUSPEND)",
"Инстанс найден в состоянии Suspend, но adopt_existing_on_create=false.\nДля восстановления/импорта этим ресурсом включите adopt_existing_on_create=true и повторите apply."+formatInstanceDetails(existing, serviceID, resourceName),
"Инстанс найден в состоянии Suspend, но adopt_existing_on_create=false."+suspendConflictHint(supportsSuspend)+formatInstanceDetails(existing, serviceID, resourceName),
)
return diags
}
@@ -192,11 +202,15 @@ func appendRemotePlanInputDiagnostics(ctx context.Context, client *core.Universa
}
}
// CreateExistingResourceDiagnosticsWithDomain — устаревшая обёртка (suspend считается
// поддерживаемым). См. CreateExistingResourceDiagnosticsWithDomainAndServices.
func CreateExistingResourceDiagnosticsWithDomain(ctx context.Context, client *core.UniversalClient, serviceID int, resourceName string, adoptExistingOnCreate bool, desiredDomain string) diag.Diagnostics {
return CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, client, serviceID, resourceName, adoptExistingOnCreate, desiredDomain, nil)
return CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, client, serviceID, resourceName, adoptExistingOnCreate, desiredDomain, nil, true)
}
func CreateExistingResourceDiagnosticsWithDomainAndServices(ctx context.Context, client *core.UniversalClient, serviceID int, resourceName string, adoptExistingOnCreate bool, desiredDomain string, allowedDomainServiceIDs []int) diag.Diagnostics {
// CreateExistingResourceDiagnosticsWithDomainAndServices — см.
// PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices (supportsSuspend).
func CreateExistingResourceDiagnosticsWithDomainAndServices(ctx context.Context, client *core.UniversalClient, serviceID int, resourceName string, adoptExistingOnCreate bool, desiredDomain string, allowedDomainServiceIDs []int, supportsSuspend bool) diag.Diagnostics {
var diags diag.Diagnostics
if client == nil {
return diags
@@ -230,7 +244,7 @@ func CreateExistingResourceDiagnosticsWithDomainAndServices(ctx context.Context,
}
diags.AddError(
"РЕСУРС С ТАКИМ ИМЕНЕМ УЖЕ СУЩЕСТВУЕТ (RUNNING)",
"Инстанс с таким resource_name уже работает.\nАвто-усыновление отключено (adopt_existing_on_create=false).\nВыберите другое имя, если нужен новый ресурс.\nИли выполните импорт существующего ресурса через усыновление: установите adopt_existing_on_create=true и повторите apply."+formatInstanceDetails(existing, serviceID, resourceName),
"Инстанс с таким resource_name уже работает.\nАвто-усыновление отключено (adopt_existing_on_create=false).\nВыберите другое имя, если нужен новый ресурс."+runningConflictHint(supportsSuspend)+formatInstanceDetails(existing, serviceID, resourceName),
)
return diags
}
@@ -240,7 +254,7 @@ func CreateExistingResourceDiagnosticsWithDomainAndServices(ctx context.Context,
}
diags.AddError(
"РЕСУРС С ТАКИМ ИМЕНЕМ УЖЕ СУЩЕСТВУЕТ (SUSPEND)",
"Инстанс найден в состоянии Suspend, но adopt_existing_on_create=false.\nДля восстановления/импорта этим ресурсом включите adopt_existing_on_create=true и повторите apply."+formatInstanceDetails(existing, serviceID, resourceName),
"Инстанс найден в состоянии Suspend, но adopt_existing_on_create=false."+suspendConflictHint(supportsSuspend)+formatInstanceDetails(existing, serviceID, resourceName),
)
return diags
}
@@ -252,6 +266,30 @@ func CreateExistingResourceDiagnosticsWithDomainAndServices(ctx context.Context,
return diags
}
// runningConflictHint — что предлагать, если инстанс с таким именем уже работает.
//
// Для сервисов БЕЗ suspend/resume усыновление работающего инстанса технически возможно
// (приостановка не требуется — adopt просто берёт существующий uid), но пользователю
// часто нужен именно destroy, поэтому называем оба пути явно.
func runningConflictHint(supportsSuspend bool) string {
if !supportsSuspend {
return "\nЛибо усыновите существующий инстанс: adopt_existing_on_create=true (он уже работает, suspend не требуется).\nЛибо удалите инстанс в Личном кабинете Nubes и повторите apply."
}
return "\nИли выполните импорт существующего ресурса через усыновление: установите adopt_existing_on_create=true и повторите apply."
}
// suspendConflictHint — что предлагать, если инстанс найден в состоянии Suspend.
//
// Для сервисов БЕЗ suspend/resume состояние Suspend недостижимо, а adopt требует
// resume — значит совет «включите adopt_existing_on_create=true» заведомо невыполним.
// Корректный выход один: удалить инстанс и/или взять другое имя.
func suspendConflictHint(supportsSuspend bool) string {
if !supportsSuspend {
return "\nСервис НЕ поддерживает suspend/resume, поэтому усыновление (adopt) для него невозможно.\nУдалите инстанс в Личном кабинете Nubes и повторите apply, либо выберите другое resource_name."
}
return "\nДля восстановления/импорта этим ресурсом включите adopt_existing_on_create=true и повторите apply."
}
func appendLocalPlanInputDiagnostics(serviceID int, desiredParams map[int]string, desiredDomain string, diags *diag.Diagnostics) {
if diags == nil {
return