fix(core): graceful fallback for cfsParams 500 error in createInstanceWithContext
- In provider/internal/core/client.go:
- If GET /instanceOperations/{opUid}?fields=cfsParams fails with 500 or JSON unmarshal error,
check whether provided parameters contain unresolved names via hasUnresolvedParams.
- If all parameters are already resolved (UUIDs/numbers/booleans/JSON), proceed to send
parameters via POST /instanceOperationCfsParams without hard-failing.
- If unresolved names remain, fail immediately with original error.
- Bumped DEV provider version to 2.0.2 in TOOLS/config/dev/profile.env, VERSIONS.md, and DEV_STAND/FullPipe/versions.tf.
- Built, signed, and published provider 2.0.2 to DEV registry bucket nubes-terraform-registry.
This commit is contained in:
@@ -270,17 +270,22 @@ func (c *UniversalClient) CreateGenericInstanceUniversalV6(ctx context.Context,
|
||||
}
|
||||
|
||||
opDetailsResp, _, err := c.doRequest(ctx, "GET", fmt.Sprintf("/instanceOperations/%s?fields=cfsParams", opUid), nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("не удалось получить детали операции: %w", err)
|
||||
}
|
||||
var opDetails universalOpResponse
|
||||
if err := json.Unmarshal(opDetailsResp, &opDetails); err != nil {
|
||||
return "", fmt.Errorf("не удалось разобрать детали операции: %w", err)
|
||||
}
|
||||
|
||||
params, err = c.resolveRefSvcParamValues(ctx, opDetails.InstanceOperation.CfsParams, params)
|
||||
hasOpDetails := false
|
||||
if err != nil {
|
||||
return "", err
|
||||
if hasUnresolvedParams(params) {
|
||||
return "", fmt.Errorf("не удалось получить детали операции: %w", err)
|
||||
}
|
||||
} else if jsonErr := json.Unmarshal(opDetailsResp, &opDetails); jsonErr != nil {
|
||||
if hasUnresolvedParams(params) {
|
||||
return "", fmt.Errorf("не удалось разобрать детали операции: %w", jsonErr)
|
||||
}
|
||||
} else {
|
||||
hasOpDetails = true
|
||||
params, err = c.resolveRefSvcParamValues(ctx, opDetails.InstanceOperation.CfsParams, params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
sent := make(map[int]bool)
|
||||
@@ -297,30 +302,32 @@ func (c *UniversalClient) CreateGenericInstanceUniversalV6(ctx context.Context,
|
||||
sent[paramId] = true
|
||||
}
|
||||
|
||||
for _, param := range opDetails.InstanceOperation.CfsParams {
|
||||
if sent[param.SvcOperationCfsParamId] {
|
||||
continue
|
||||
}
|
||||
if !param.IsRequired {
|
||||
continue
|
||||
}
|
||||
if hasOpDetails {
|
||||
for _, param := range opDetails.InstanceOperation.CfsParams {
|
||||
if sent[param.SvcOperationCfsParamId] {
|
||||
continue
|
||||
}
|
||||
if !param.IsRequired {
|
||||
continue
|
||||
}
|
||||
|
||||
val := ""
|
||||
if param.ParamValue != nil {
|
||||
val = *param.ParamValue
|
||||
} else if param.DefaultValue != nil {
|
||||
val = *param.DefaultValue
|
||||
}
|
||||
val = normalizeUniversalValueV6(val, param)
|
||||
val := ""
|
||||
if param.ParamValue != nil {
|
||||
val = *param.ParamValue
|
||||
} else if param.DefaultValue != nil {
|
||||
val = *param.DefaultValue
|
||||
}
|
||||
val = normalizeUniversalValueV6(val, param)
|
||||
|
||||
pPayload := genericParamReq{
|
||||
InstanceOperationUid: opUid,
|
||||
SvcOperationCfsParamId: param.SvcOperationCfsParamId,
|
||||
ParamValue: val,
|
||||
}
|
||||
_, _, err := c.doRequest(ctx, "POST", "/instanceOperationCfsParams", pPayload)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("не удалось отправить параметр по умолчанию %d: %w", param.SvcOperationCfsParamId, err)
|
||||
pPayload := genericParamReq{
|
||||
InstanceOperationUid: opUid,
|
||||
SvcOperationCfsParamId: param.SvcOperationCfsParamId,
|
||||
ParamValue: val,
|
||||
}
|
||||
_, _, err := c.doRequest(ctx, "POST", "/instanceOperationCfsParams", pPayload)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("не удалось отправить параметр по умолчанию %d: %w", param.SvcOperationCfsParamId, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1352,6 +1359,41 @@ func isUUIDLike(value string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// hasUnresolvedParams возвращает true, если хотя бы одно значение параметров похоже на
|
||||
// неразрешённое имя вместо UUID. Значения map-fixed/json/array, числа и булевы пропускаются.
|
||||
func hasUnresolvedParams(params map[int]string) bool {
|
||||
for _, val := range params {
|
||||
trimmed := strings.TrimSpace(val)
|
||||
if trimmed == "" || trimmed == "{}" || trimmed == "[]" {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(trimmed, "{") || strings.HasPrefix(trimmed, "[") {
|
||||
// json/map-fixed/array не являются именами одиночных инстансов
|
||||
continue
|
||||
}
|
||||
if trimmed == "true" || trimmed == "false" {
|
||||
continue
|
||||
}
|
||||
isNum := true
|
||||
for _, r := range trimmed {
|
||||
if r < '0' || r > '9' {
|
||||
isNum = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if isNum {
|
||||
continue
|
||||
}
|
||||
if isUUIDLike(trimmed) {
|
||||
continue
|
||||
}
|
||||
// Обнаружена не-числовая строка, не JSON и не UUID (потенциальное имя).
|
||||
// Если GET ?fields=cfsParams упал, такое имя невозможно разрешить в UUID.
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isHexDigit(r rune) bool {
|
||||
return (r >= '0' && r <= '9') || (r >= 'a' && r <= 'f') || (r >= 'A' && r <= 'F')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user