From b1cea8a930c42240074680c11e5282fe775c1263 Mon Sep 17 00:00:00 2001 From: Repinoid Date: Tue, 22 Sep 2026 16:49:36 +0300 Subject: [PATCH] =?UTF-8?q?fix(core):=20fallback=20=D0=BD=D0=B0=20/instanc?= =?UTF-8?q?eOperations/default/{opId}=20=D0=BF=D1=80=D0=B8=20500=20getReso?= =?UTF-8?q?urceRealmConfig=20=D0=B2=20modify?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- provider/internal/core/client.go | 57 ++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/provider/internal/core/client.go b/provider/internal/core/client.go index 9d6721c..1de81a2 100644 --- a/provider/internal/core/client.go +++ b/provider/internal/core/client.go @@ -188,6 +188,13 @@ type universalOperation struct { CfsParams []universalCfsParam `json:"cfsParams"` } +// universalOpDefaultResponse — схема операции из GET /instanceOperations/default/{opId}. +// Не вычисляет instance-специфичные выражения (getResourceRealmConfig) и не падает +// с 500 на проблемных инстансах (см. docs/DEBUG_REPORT_VC_VDC_500.md). +type universalOpDefaultResponse struct { + SvcOperation universalOperation `json:"svcOperation"` +} + type universalSubParam struct { DefaultValue string `json:"defaultValue"` DataType string `json:"dataType"` @@ -400,6 +407,30 @@ func normalizeUniversalValueV6(val string, param universalCfsParam) string { return trimmed } +// fetchOperationCfsParams возвращает cfsParams операции. При неудаче живого +// GET /instanceOperations/{opUid}?fields=cfsParams (backend 500 в +// getResourceRealmConfig на проблемных инстансах) берёт схему из +// /instanceOperations/default/{opId}. +func (c *UniversalClient) fetchOperationCfsParams(ctx context.Context, opUid string, opId int) ([]universalCfsParam, error) { + opDetailsResp, _, err := c.doRequest(ctx, "GET", fmt.Sprintf("/instanceOperations/%s?fields=cfsParams", opUid), nil) + if err == nil { + var opDetails universalOpResponse + if uerr := json.Unmarshal(opDetailsResp, &opDetails); uerr == nil { + return opDetails.InstanceOperation.CfsParams, nil + } + } + + defResp, _, defErr := c.doRequest(ctx, "GET", fmt.Sprintf("/instanceOperations/default/%d", opId), nil) + if defErr != nil { + return nil, fmt.Errorf("не удалось получить детали операции: %w", defErr) + } + var def universalOpDefaultResponse + if uerr := json.Unmarshal(defResp, &def); uerr != nil { + return nil, fmt.Errorf("не удалось разобрать детали операции: %w", uerr) + } + return def.SvcOperation.CfsParams, nil +} + // RunInstanceOperationUniversal runs an available operation (modify/suspend/delete/resume) if possible. func (c *UniversalClient) RunInstanceOperationUniversal(ctx context.Context, instanceUid string, action string, params map[int]string) error { state, err := c.GetInstanceState(ctx, instanceUid) @@ -495,16 +526,12 @@ func (c *UniversalClient) RunInstanceOperationUniversalWithDefaults(ctx context. return fmt.Errorf("не удалось получить UID операции для %s", action) } - opDetailsResp, _, err := c.doRequest(ctx, "GET", fmt.Sprintf("/instanceOperations/%s?fields=cfsParams", opUid), nil) + cfsParams, err := c.fetchOperationCfsParams(ctx, opUid, opId) if err != nil { - return fmt.Errorf("не удалось получить детали операции: %w", err) - } - var opDetails universalOpResponse - if err := json.Unmarshal(opDetailsResp, &opDetails); err != nil { - return fmt.Errorf("не удалось разобрать детали операции: %w", err) + return err } - params, err = c.resolveRefSvcParamValues(ctx, opDetails.InstanceOperation.CfsParams, params) + params, err = c.resolveRefSvcParamValues(ctx, cfsParams, params) if err != nil { return err } @@ -523,7 +550,7 @@ func (c *UniversalClient) RunInstanceOperationUniversalWithDefaults(ctx context. sent[paramId] = true } - for _, param := range opDetails.InstanceOperation.CfsParams { + for _, param := range cfsParams { if sent[param.SvcOperationCfsParamId] { continue } @@ -1524,17 +1551,13 @@ func (c *UniversalClient) RunInstanceOperationUniversalByCode(ctx context.Contex return fmt.Errorf("не удалось получить UID операции для %s", action) } - opDetailsResp, _, err := c.doRequest(ctx, "GET", fmt.Sprintf("/instanceOperations/%s?fields=cfsParams", opUid), nil) + cfsParams, err := c.fetchOperationCfsParams(ctx, opUid, opId) if err != nil { - return fmt.Errorf("не удалось получить детали операции: %w", err) - } - var opDetails universalOpResponse - if err := json.Unmarshal(opDetailsResp, &opDetails); err != nil { - return fmt.Errorf("не удалось разобрать детали операции: %w", err) + return err } codeToParam := make(map[string]universalCfsParam) - for _, p := range opDetails.InstanceOperation.CfsParams { + for _, p := range cfsParams { if key := strings.ToLower(strings.TrimSpace(p.Code)); key != "" { codeToParam[key] = p } @@ -1553,7 +1576,7 @@ func (c *UniversalClient) RunInstanceOperationUniversalByCode(ctx context.Contex paramsByID[p.SvcOperationCfsParamId] = value } - paramsByID, err = c.resolveRefSvcParamValues(ctx, opDetails.InstanceOperation.CfsParams, paramsByID) + paramsByID, err = c.resolveRefSvcParamValues(ctx, cfsParams, paramsByID) if err != nil { return err } @@ -1572,7 +1595,7 @@ func (c *UniversalClient) RunInstanceOperationUniversalByCode(ctx context.Contex sent[paramId] = true } - for _, param := range opDetails.InstanceOperation.CfsParams { + for _, param := range cfsParams { if sent[param.SvcOperationCfsParamId] { continue }