svc-api: переход на Gateway (lk-api-gateway), User-Agent+Referer для DDoS-Guard, метод Виталия /instanceOperations/default/{id} с dataDescriptor, LEGACY-пометки везде

This commit is contained in:
“Naeel”
2026-07-16 13:48:34 +04:00
parent b9130fdd79
commit f5547c0465
87 changed files with 505 additions and 288 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
# Stand profile: DEV
NUBES_API_ENDPOINT="https://deck-api-dev.ngcloud.ru/api/v1"
NUBES_API_ENDPOINT="https://lk-api-gateway-dev.ngcloud.ru/api/v1/svc"
TOKEN_FILE="secrets/dev.token"
# Release versions
+49 -46
View File
@@ -1,49 +1,52 @@
# service_id service_name # RU description
# DEV stand — generated from dev API 2026-03-26
# do not delete lines; to exclude a service, comment it with #
1 dummy # Болванка
2 template # Темплейт k8s
12 s3 # S3 Object Storage
13 s3bucket # S3 бакет
19 vcOrg # Организация в Cloud Director
# 20 vcOrgSaas # DEPRECATED — Организация без Keycloak (isProductionReady=false)
21 vc_vdc # Виртуальный датацентр (vDC)
22 vc_nsxt # Сетевой шлюз периметра (Edge)
# 23 vc_vm # DEPRECATED — VM в Cloud Director старый формат (isProductionReady=false)
# 24 vcNat # DEPRECATED — Правила маршрутизации VM (isProductionReady=false)
25 vcexternalip # Публичные IP адреса
26 vapp # Виртуальный каталог ВМ (vApp)
# 27 vc_vm_v2 # VM в Cloud Director v2 (isProductionReady=false)
28 vc_vm_v3 # Виртуальная машина
29 vcVdcGroup # Группа датацентров
# 32 vmpostgre # vc_vm_postgresql_std (isProductionReady=false)
50 nextcloud # Nextcloud
81 superset # Apache Superset
82 harbor # Container Registry
88 k8sZitiController # k8sZitiController
89 flask # Web-сервер с фреймворком Flask
90 postgres # PostgreSQL
91 redis # Redis
92 mongodb # MongoDB
93 rabbitmq # RabbitMQ
94 lucee # Lucee
95 nodejs # NodeJS
96 pgadmin # pgAdmin
97 nodered # NodeRed
98 http # Простой HTTP контейнер
99 gitea # Gitea
# 100 openwhisk # Serverless Openwhisk (isProductionReady=false)
109 zonesV2 # Управление днс-зонами и записями
110 dnszone # DNS зона
111 dnsrecord # DNS запись
# 112 tenant # Тенант в Grafana (isProductionReady=false)
# 113 vcComplex # Быстрый старт (isProductionReady=false)
115 mariadb # Mariadb
116 kafka # ApacheKafka
119 Akhq # Akhq
120 clickhouse # ClickHouse
149 valoTenant # VALO Cloud
150 k8sSthutrvalCluster # Kubernetes кластер Штурвал
151 k8sOpenbao # Vault
# 152 template # Темплейт k8s-2-clone (isProductionReady=false)
175 k8sGo # Go
163 llmAi # LLM
153 nifi # Nifi
151 k8sOpenbao # Vault
150 k8sSthutrvalCluster # Kubernetes кластер Штурвал
149 valoTenant # VALO Cloud
148 vcMgmtSthutrvalCluster # Менеджмент Kubernetes кластер Штурвал
120 clickhouse # ClickHouse
119 Akhq # Akhq
116 kafka # ApacheKafka
115 mariadb # Mariadb
113 vcComplex # Быстрый старт
112 tenant # Тенант в Grafana
111 dnsrecord # DNS запись
110 dnszone # DNS зона
109 zonesV2 # Управление DNS
100 openwhisk # Serverless Openwhisk (openwhisk_tenant)
99 gitea # Gitea
98 http # Простой HTTP контейнер
97 nodered # NodeRed
96 pgadmin # pgAdmin
95 nodejs # NodeJS
94 lucee # Lucee
93 rabbitmq # RabbitMQ
92 mongodb # MongoDB
91 redis # Redis
90 postgres # PostgreSQL
89 flask # Web-сервер с фреймворком Flask
88 k8sZitiController # k8sZitiController
87 k8svalkey # Valkey
86 k8sVelero # Velero
82 harbor # Container Registry
81 superset # Apache Superset
50 nextcloud # Nextcloud
32 vmpostgre # vc_vm_postgresql_std
29 vcVdcGroup # Группа датацентров
28 vc_vm_v3 # Виртуальная машина
27 vc_vm_v2 # VM в Cloud Director (vc_vmV2)
26 vapp # Виртуальный каталог ВМ (vApp)
25 vcexternalip # Публичные IP адреса
24 vcNat # DEPRECATED Правила маршрутизации для VM (vc_nat)
23 vc_vm # VM в Cloud Director (старый формат) (vc_vm)
22 vc_nsxt # Сетевой шлюз периметра (Edge)
21 vc_vdc # Виртуальный датацентр (vDC)
20 vcOrgSaas # Организация [DEPRECATED]
19 vcOrg # Организация в Cloud Director
13 s3bucket # S3 бакет
12 s3 # S3 Object Storage
2 template # Темплейт k8s
1 dummy # Болванка
+1 -1
View File
@@ -1,5 +1,5 @@
# Stand profile: PROD
NUBES_API_ENDPOINT="https://deck-api.ngcloud.ru/api/v1"
NUBES_API_ENDPOINT="https://lk-api-gateway.ngcloud.ru/api/v1/svc"
TOKEN_FILE="secrets/prod.token"
# Release versions
+46 -43
View File
@@ -1,46 +1,49 @@
# service_id service_name # RU description
# do not delete lines; to exclude a service, comment it with #
1 dummy # Болванка для тестов
2 template # Болванка для тестирования
12 s3 # Масштабируемое хранилище данных
13 s3bucket # Бакет в сервисе S3
19 vcOrg # Организация в Cloud Director
20 vcOrgSaas # Без интеграции Keycloak
21 vc_vdc # Выделение вычислительных ресурсов
22 vc_nsxt # Обеспечение сетевой доступности в тенанте
23 vc_vm # Виртуальная машина без каких-либо особенностей. <br/>Данная услуга запускает vc_ip для выдачи белого адреса и подключения к ВМ
# 24 DEPRECATED Правила маршрутизации для VM (vc_nat) # excluded from active generation
25 vcexternalip # Резервирование IP адреса
26 vapp # Группировка виртуальных машин
27 vc_vm_v2 # Виртуальная машина с возможностью настройки Cloud Init<br/>Можно развернуть в услуге несколько ВМ<br/>В зависимости от настроек можно выдавать на ВМ vip + dns
28 vc_vm_v3 # Создание виртуальной машины
29 vcVdcGroup # Обеспечение сетевой доступности между датацентрами
32 vmpostgre # Сервис настройки PostgreSQL для виртуальной машины.<br/>Требует наличия ВМ
50 nextcloud # Платформа совместной работы
81 superset # Сервер отчетов
82 harbor # Реестр для хранения образов контейнеров
88 k8sZitiController # Контроллер управления Client to service & service to service Zero trust network<br/>
89 flask # Flask
90 postgres # Управляемая база данных PostgreSQL
91 redis # Управляемая база данных Redis
92 mongodb # Управляемая база данных MongoDB
93 rabbitmq # Сервер очередей
94 lucee # Cервер приложений
95 nodejs # Cервер приложений
96 pgadmin # Административный интерфейс для PostgreSQL
97 nodered # Low-code платформа для IoT
163 llmAi # LLM
150 k8sSthutrvalCluster # Kubernetes кластер Штурвал
149 valoTenant # VALO Cloud
148 vcMgmtSthutrvalCluster # Менеджмент Kubernetes кластер Штурвал
120 clickhouse # ClickHouse
119 Akhq # Akhq
117 nifi # Nifi
116 kafka # ApacheKafka
115 mariadb # Mariadb
114 GiteaComplex # Комплексная услуга по созданию gitea
113 vcComplex # Быстрый старт
112 tenant # Тенант в Grafana
111 dnsrecord # DNS запись
110 dnszone # DNS зона
109 zonesV2 # Управление DNS
100 openwhisk # Serverless Openwhisk (openwhisk_tenant)
99 gitea # Gitea
98 http # Простой HTTP контейнер
99 gitea # Сервис контроля версий
100 openwhisk # Добавление и удаления пользователя (учетной записи, тенанта) для работы с Openwhisk
110 dnszone # Хостинг DNS зоны
111 dnsrecord # DNS запись в созданной зоне
112 tenant # Организация доступов к мониторингу
113 vcComplex # Создание готовой иерархии ресурсов
114 GiteaComplex # Комплексная услуга из [&quot;gittea&quot;, &quot;postgres&quot;]
115 mariadb # Управляемая база данных MySQL
116 kafka # Сервис создания кластера Apache Kafka
117 nifi # ETL-система
119 Akhq # Web интерфейс Akhq для работы с Apache Kafka
120 clickhouse # Управляемая база данных ClickHouse
149 valoTenant # Корпоративная система обмена и синхронизации файлов
150 k8sSthutrvalCluster # Платформа управления K8s<br/>
97 nodered # NodeRed
96 pgadmin # pgAdmin
95 nodejs # NodeJS
94 lucee # Lucee
93 rabbitmq # RabbitMQ
92 mongodb # MongoDB
91 redis # Redis
90 postgres # PostgreSQL
89 flask # Web-сервер с фреймворком Flask
88 k8sZitiController # k8sZitiController
86 k8sVelero # Velero
82 harbor # Container Registry
81 superset # Apache Superset
50 nextcloud # Nextcloud
29 vcVdcGroup # Группа датацентров
28 vc_vm_v3 # Виртуальная машина
27 vc_vm_v2 # VM в Cloud Director (vc_vmV2)
26 vapp # Виртуальный каталог ВМ (vApp)
25 vcexternalip # Публичные IP адреса
24 svc24 # DEPRECATED Правила маршрутизации для VM (vc_nat)
23 vc_vm # VM в Cloud Director (старый формат) (vc_vm)
22 vc_nsxt # Сетевой шлюз периметра (Edge)
21 vc_vdc # Виртуальный датацентр (vDC)
20 vcOrgSaas # Организация [DEPRECATED]
19 vcOrg # Организация в Cloud Director
13 s3bucket # S3 бакет
12 s3 # S3 Object Storage
2 template # Темплейт k8s
1 dummy # Болванка
+48 -43
View File
@@ -1,46 +1,51 @@
# service_id service_name # RU description
# do not delete lines; to exclude a service, comment it with #
1 dummy # Болванка для тестов
2 template # Болванка для тестирования
12 s3 # Масштабируемое хранилище данных
13 s3bucket # Бакет в сервисе S3
19 vcOrg # Организация в Cloud Director
20 vcOrgSaas # Без интеграции Keycloak
21 vc_vdc # Выделение вычислительных ресурсов
22 vc_nsxt # Обеспечение сетевой доступности в тенанте
23 vc_vm # Виртуальная машина без каких-либо особенностей. <br/>Данная услуга запускает vc_ip для выдачи белого адреса и подключения к ВМ
# 24 DEPRECATED Правила маршрутизации для VM (vc_nat) # excluded from active generation
25 vcexternalip # Резервирование IP адреса
26 vapp # Группировка виртуальных машин
27 vc_vm_v2 # Виртуальная машина с возможностью настройки Cloud Init<br/>Можно развернуть в услуге несколько ВМ<br/>В зависимости от настроек можно выдавать на ВМ vip + dns
28 vc_vm_v3 # Создание виртуальной машины
29 vcVdcGroup # Обеспечение сетевой доступности между датацентрами
32 vmpostgre # Сервис настройки PostgreSQL для виртуальной машины.<br/>Требует наличия ВМ
50 nextcloud # Платформа совместной работы
81 superset # Сервер отчетов
82 harbor # Реестр для хранения образов контейнеров
88 k8sZitiController # Контроллер управления Client to service & service to service Zero trust network<br/>
89 flask # Flask
90 postgres # Управляемая база данных PostgreSQL
91 redis # Управляемая база данных Redis
92 mongodb # Управляемая база данных MongoDB
93 rabbitmq # Сервер очередей
94 lucee # Cервер приложений
95 nodejs # Cервер приложений
96 pgadmin # Административный интерфейс для PostgreSQL
97 nodered # Low-code платформа для IoT
163 llmAi # LLM
151 k8sOpenbao # Vault
150 k8sSthutrvalCluster # Kubernetes кластер Штурвал
149 valoTenant # VALO Cloud
148 vcMgmtSthutrvalCluster # Менеджмент Kubernetes кластер Штурвал
120 clickhouse # ClickHouse
119 Akhq # Akhq
117 nifi # Nifi
116 kafka # ApacheKafka
115 mariadb # Mariadb
114 GiteaComplex # Комплексная услуга по созданию gitea
113 vcComplex # Быстрый старт
112 tenant # Тенант в Grafana
111 dnsrecord # DNS запись
110 dnszone # DNS зона
109 zonesV2 # Управление DNS
100 openwhisk # Serverless Openwhisk (openwhisk_tenant)
99 gitea # Gitea
98 http # Простой HTTP контейнер
99 gitea # Сервис контроля версий
100 openwhisk # Добавление и удаления пользователя (учетной записи, тенанта) для работы с Openwhisk
110 dnszone # Хостинг DNS зоны
111 dnsrecord # DNS запись в созданной зоне
112 tenant # Организация доступов к мониторингу
113 vcComplex # Создание готовой иерархии ресурсов
114 GiteaComplex # Комплексная услуга из [&quot;gittea&quot;, &quot;postgres&quot;]
115 mariadb # Управляемая база данных MySQL
116 kafka # Сервис создания кластера Apache Kafka
117 nifi # ETL-система
119 Akhq # Web интерфейс Akhq для работы с Apache Kafka
120 clickhouse # Управляемая база данных ClickHouse
149 valoTenant # Корпоративная система обмена и синхронизации файлов
150 k8sSthutrvalCluster # Платформа управления K8s<br/>
97 nodered # NodeRed
96 pgadmin # pgAdmin
95 nodejs # NodeJS
94 lucee # Lucee
93 rabbitmq # RabbitMQ
92 mongodb # MongoDB
91 redis # Redis
90 postgres # PostgreSQL
89 flask # Web-сервер с фреймворком Flask
88 k8sZitiController # k8sZitiController
86 k8sVelero # Velero
82 harbor # Container Registry
81 superset # Apache Superset
50 nextcloud # Nextcloud
32 vmpostgre # vc_vm_postgresql_std
29 vcVdcGroup # Группа датацентров
28 vc_vm_v3 # Виртуальная машина
27 vc_vm_v2 # VM в Cloud Director (vc_vmV2)
26 vapp # Виртуальный каталог ВМ (vApp)
25 vcexternalip # Публичные IP адреса
24 svc24 # DEPRECATED Правила маршрутизации для VM (vc_nat)
23 vc_vm # VM в Cloud Director (старый формат) (vc_vm)
22 vc_nsxt # Сетевой шлюз периметра (Edge)
21 vc_vdc # Виртуальный датацентр (vDC)
20 vcOrgSaas # Организация [DEPRECATED]
19 vcOrg # Организация в Cloud Director
13 s3bucket # S3 бакет
12 s3 # S3 Object Storage
2 template # Темплейт k8s
1 dummy # Болванка
+3 -1
View File
@@ -24,7 +24,9 @@ func main() {
servicesListFlag := flag.String("services", "", "Path to TOOLS/config/{stand}/services_list.txt")
excludeFlag := flag.String("exclude", "", "Comma-separated resource names to skip")
versionFlag := flag.String("version", "", "Provider version for example block")
apiEndpointFlag := flag.String("api-endpoint", "https://deck-api.ngcloud.ru/api/v1/index.cfm", "API endpoint for example block")
// ⛔ LEGACY DEFAULT (index.cfm) — переопределяется через NUBES_API_ENDPOINT в profile.env.
// Никогда не использовать deck-api.ngcloud.ru напрямую.
apiEndpointFlag := flag.String("api-endpoint", "https://lk-api-gateway.ngcloud.ru/api/v1/svc", "API endpoint for example block")
opsFlag := flag.Bool("ops", false, "Generate per-service operations docs (resources_ops_yaml → docs/.../operations)")
flag.Parse()
+3
View File
@@ -74,4 +74,7 @@ type ParamSpec struct {
// === Генератор-специфичные поля (не сериализуются в YAML) ===
IsModifiable *bool `yaml:"is_modifiable,omitempty"`
IsSensitive bool `yaml:"is_sensitive,omitempty"`
// SubParams — подполя для map-fixed/array-map-fixed параметров.
// Заполняется из dataDescriptor при генерации YAML.
SubParams []ParamSpec `yaml:"sub_params,omitempty"`
}
+2 -1
View File
@@ -105,7 +105,8 @@ if [[ ! -f "$SERVICES_FILE" ]]; then
exit 2
fi
API_ENDPOINT="${NUBES_API_ENDPOINT:-https://deck-api.ngcloud.ru/api/v1/index.cfm}"
# ⛔ LEGACY: deck-api.ngcloud.ru ЗАКРЫВАЕТСЯ. Default = Gateway. Override via NUBES_API_ENDPOINT.
API_ENDPOINT="${NUBES_API_ENDPOINT:-https://lk-api-gateway.ngcloud.ru/api/v1/svc}"
# Auto-detect API style: if endpoint contains "index.cfm" → legacy proxy (?endpoint=),
# otherwise → new REST gateway (direct paths). No forced /index.cfm normalization.
@@ -92,7 +92,8 @@ mkdir -p "$DOCS_DIR"
# Determine API endpoint for doc examples.
# Use NUBES_API_ENDPOINT from profile.env, fall back to production default.
DOCS_API_ENDPOINT="${NUBES_API_ENDPOINT:-https://deck-api.ngcloud.ru/api/v1/index.cfm}"
# ⛔ LEGACY: deck-api.ngcloud.ru ЗАКРЫВАЕТСЯ. Default = Gateway. Override via NUBES_API_ENDPOINT.
DOCS_API_ENDPOINT="${NUBES_API_ENDPOINT:-https://lk-api-gateway.ngcloud.ru/api/v1/svc}"
# If endpoint looks like new REST gateway (no index.cfm), keep as-is.
# If it's old-style without index.cfm, append it for backward compat in docs.
if [[ "$DOCS_API_ENDPOINT" != *"/index.cfm"* ]] && [[ "$DOCS_API_ENDPOINT" != *"/svc"* ]]; then
+4 -2
View File
@@ -9,8 +9,9 @@ PROFILE_DIR="${PROFILE_DIR:-}"
normalize_api_endpoint() {
local endpoint="$1"
endpoint="${endpoint%/}"
# ⛔ LEGACY: deck-api.ngcloud.ru ЗАКРЫВАЕТСЯ.
if [[ -z "$endpoint" ]]; then
echo "https://deck-api.ngcloud.ru/api/v1/index.cfm"
echo "https://lk-api-gateway.ngcloud.ru/api/v1/svc"
return
fi
# Keep as-is: both legacy proxy (index.cfm) and new REST gateway are valid.
@@ -84,7 +85,8 @@ if [[ -n "$PROFILE_DIR" ]]; then
fi
fi
DOCS_API_ENDPOINT="${NUBES_API_ENDPOINT:-https://deck-api.ngcloud.ru/api/v1/index.cfm}"
# ⛔ LEGACY: deck-api.ngcloud.ru ЗАКРЫВАЕТСЯ. Default = Gateway.
DOCS_API_ENDPOINT="${NUBES_API_ENDPOINT:-https://lk-api-gateway.ngcloud.ru/api/v1/svc}"
DOCS_API_ENDPOINT="$(normalize_api_endpoint "$DOCS_API_ENDPOINT")"
if [[ -n "${MKDOCS_DOCS_DIR:-}" ]]; then
+100 -5
View File
@@ -51,9 +51,12 @@ func (c *Client) GetService(serviceID int) (types.ServiceInfo, error) {
return res.Service, nil
}
// GetServiceOperation получает детали операции (параметры + MAN).
// GetServiceOperation получает детали операции (параметры + dataDescriptor + valueList).
// Использует /instanceOperations/default/{id} — метод Виталия (15.07.2026).
// Этот эндпоинт возвращает dataDescriptor (подполя map-fixed) и valueList,
// в отличие от /serviceOperation/{id} который даёт только плоский список.
func (c *Client) GetServiceOperation(svcOperationID int) (types.ServiceOperationInfo, error) {
endpoint := fmt.Sprintf("/serviceOperation/%d", svcOperationID)
endpoint := fmt.Sprintf("/instanceOperations/default/%d", svcOperationID)
var res types.ServiceOperationResponse
if err := c.callAPI(endpoint, &res); err != nil {
return types.ServiceOperationInfo{}, err
@@ -84,7 +87,9 @@ func (c *Client) callAPI(endpoint string, out interface{}) error {
if c.token != "" {
req.Header.Set("Authorization", "Bearer "+c.token)
}
req.Header.Set("User-Agent", "Mozilla/5.0 (compatible; Terraform-Provider-Nubes/Generator)")
// DDoS-Guard требует браузерный User-Agent ВСЕГДА (и старый, и новый API).
req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36")
req.Header.Set("Referer", c.refererFromEndpoint())
resp, err := c.httpClient.Do(req)
if err != nil {
lastErr = err
@@ -123,6 +128,26 @@ func (c *Client) isProxyAPI() bool {
return strings.Contains(c.endpoint, "index.cfm")
}
// refererFromEndpoint извлекает Referer из URL API (DDoS-Guard).
// lk-api-gateway-test.ngcloud.ru → https://deck-test.ngcloud.ru/
// lk-api-gateway.ngcloud.ru → https://deck.ngcloud.ru/
func (c *Client) refererFromEndpoint() string {
ep := c.endpoint
if strings.HasPrefix(ep, "https://") {
ep = ep[8:]
} else if strings.HasPrefix(ep, "http://") {
ep = ep[7:]
}
host := ep
if idx := strings.Index(host, "/"); idx >= 0 {
host = host[:idx]
}
// lk-api-gateway-stand → deck-stand, lk-api-gateway → deck
refererHost := strings.Replace(host, "lk-api-gateway-", "deck-", 1)
refererHost = strings.Replace(refererHost, "lk-api-gateway.", "deck.", 1)
return "https://" + refererHost + "/"
}
// CollectOperations собирает и классифицирует все операции сервиса.
func (c *Client) CollectOperations(ops []types.OperationInfo) ([]types.OperationSpec, bool, bool, bool, error) {
result := make([]types.OperationSpec, 0, len(ops))
@@ -140,7 +165,7 @@ func (c *Client) CollectOperations(ops []types.OperationInfo) ([]types.Operation
}
params := make([]types.ParamSpec, 0, len(opInfo.CfsParams))
for _, p := range opInfo.CfsParams {
params = append(params, types.ParamSpec{
param := types.ParamSpec{
ID: p.ID,
Code: p.Code,
DataType: strings.TrimSpace(p.DataType),
@@ -161,7 +186,32 @@ func (c *Client) CollectOperations(ops []types.OperationInfo) ([]types.Operation
DependsOn: p.DependsOnCfsParams,
IsModifiable: p.IsModifiable,
IsSensitive: p.IsSensitive,
})
}
// Разворачиваем dataDescriptor в SubParams (подполя map-fixed/array-map-fixed).
if len(p.DataDescriptor) > 0 {
subParams := make([]types.ParamSpec, 0, len(p.DataDescriptor))
for code, sub := range p.DataDescriptor {
subParams = append(subParams, types.ParamSpec{
ID: sub.SubParamID,
Code: code,
DataType: strings.TrimSpace(sub.DataType),
Required: sub.IsRequired,
Default: normalizeDefault(sub.DefaultValue),
// valueList в dataDescriptor — может быть строкой (comma-sep) или массивом
ValueList: normalizeSubValueList(sub.ValueList),
Descr: strings.TrimSpace(sub.Descr),
Man: strings.TrimSpace(sub.Man),
Regex: strings.TrimSpace(sub.Regex),
// isModifiableDefinition → IsModifiable
IsModifiable: boolPtr(sub.IsModifiableDefinition),
IsSensitive: sub.IsSensitive,
})
}
param.SubParams = subParams
}
params = append(params, param)
}
sort.Slice(params, func(i, j int) bool { return params[i].ID < params[j].ID })
@@ -232,3 +282,48 @@ func normalizeDefault(value interface{}) interface{} {
return value
}
}
// normalizeSubValueList — приводит valueList из dataDescriptor к []string.
// API может вернуть строку (comma-separated), массив, или null.
func normalizeSubValueList(v interface{}) []string {
if v == nil {
return nil
}
switch t := v.(type) {
case string:
return splitCommaList(t)
case []interface{}:
out := make([]string, 0, len(t))
for _, item := range t {
out = append(out, fmt.Sprintf("%v", item))
}
return out
default:
return nil
}
}
// splitCommaList — разбивает comma-separated строку из dataDescriptor в []string.
func splitCommaList(s string) []string {
s = strings.TrimSpace(s)
if s == "" {
return nil
}
parts := strings.Split(s, ",")
out := make([]string, 0, len(parts))
for _, p := range parts {
p = strings.TrimSpace(p)
if p != "" {
out = append(out, p)
}
}
if len(out) == 0 {
return nil
}
return out
}
// boolPtr — возвращает указатель на bool.
func boolPtr(b bool) *bool {
return &b
}
@@ -30,7 +30,7 @@ type ServiceRef struct {
// Load читает конфигурацию из переменных окружения и файлов.
func Load() (Config, error) {
apiEndpoint := getenvDefault("NUBES_API_ENDPOINT", "https://deck-api.ngcloud.ru/api/v1/index.cfm")
apiEndpoint := getenvDefault("NUBES_API_ENDPOINT", "https://lk-api-gateway.ngcloud.ru/api/v1/svc")
apiEndpoint = normalize.APIEndpoint(apiEndpoint)
apiToken, err := loadToken()
if err != nil {
@@ -63,6 +63,33 @@ type CfsParam struct {
DependsOnCfsParams interface{} `json:"dependsOnCfsParams"`
IsModifiable *bool `json:"isModifiable"`
IsSensitive bool `json:"isSensitive"`
// DataDescriptor — подполя для map-fixed/array-map-fixed параметров.
// Ключ — код подполя (например "cpu"), значение — метаданные подполя.
// Доступно только через /instanceOperations/default/{id}.
DataDescriptor map[string]CfsSubParam `json:"dataDescriptor"`
}
// CfsSubParam — подполе map-fixed параметра из dataDescriptor.
type CfsSubParam struct {
SubParamID int `json:"svcOperationCfsSubparamId"`
Code string `json:"svcOperationCfsSubparam"`
DataType string `json:"dataType"`
ValueList interface{} `json:"valueList"` // string (comma-sep) or array
IsRequired bool `json:"isRequired"`
IsModifiableDefinition bool `json:"isModifiableDefinition"`
IsSensitive bool `json:"isSensitive"`
IsHidden bool `json:"isHidden"`
DefaultValue interface{} `json:"defaultValue"`
Descr string `json:"descr"`
Man string `json:"man"`
Label string `json:"label"`
Regex string `json:"regex"`
Expression string `json:"expression"`
MaxLength interface{} `json:"maxlength"`
MinLength interface{} `json:"minlength"`
RefSvcID interface{} `json:"refSvcId"`
UniqueScope string `json:"uniqueScope"`
DependsOnCfsParams interface{} `json:"dependsOnCfsParams"`
}
// ─── YAML-типы (алиасы к lib — общий контракт) ─────────────────────────────