diff --git a/api/cmd/main.go b/api/cmd/main.go index f19d7b29..47ceb06d 100644 --- a/api/cmd/main.go +++ b/api/cmd/main.go @@ -99,6 +99,7 @@ func main() { // 단일 세그먼트 내부 핸들러 api.POST("/disklookup", handler.DiskLookup) + api.POST("/getapihosts", handler.GetApiHosts) // 관리자 전용 BFF 라우트 (와일드카드보다 먼저 등록되어야 정적 매칭됨) // FR-CLOUD-ADMIN-006-08: 외부 raw YAML 도달성 확인 (CORS 우회 + 토큰 노출 방지) diff --git a/api/internal/config/api_spec.go b/api/internal/config/api_spec.go index 4229d62b..17201a0e 100644 --- a/api/internal/config/api_spec.go +++ b/api/internal/config/api_spec.go @@ -53,6 +53,18 @@ func LoadApiSpec(path string) (*ApiSpec, error) { return &apiSpec, nil } +// GetService subsystem 서비스 정보만 조회 (action 불필요 시 사용) +func (a *ApiSpec) GetService(subsystem string) (*Service, error) { + subsystemLower := strings.ToLower(subsystem) + for key, svc := range a.Services { + if strings.ToLower(key) == subsystemLower { + s := svc + return &s, nil + } + } + return nil, fmt.Errorf("service not found: %s", subsystem) +} + // GetAction subsystem과 operationId로 액션 조회 func (a *ApiSpec) GetAction(subsystem, operationId string) (*Service, *ActionSpec, error) { // 소문자로 변환하여 매칭 (Buffalo 호환) diff --git a/api/internal/config/config.go b/api/internal/config/config.go index ada21dac..fed1a2b9 100644 --- a/api/internal/config/config.go +++ b/api/internal/config/config.go @@ -9,12 +9,13 @@ import ( // Config 전체 애플리케이션 설정 type Config struct { - Server ServerConfig - Database DatabaseConfig - MCIAM MCIAMConfig - ApiSpec *ApiSpec - RegistryCache RegistryCacheInterface - SetupYaml SetupYamlConfig + Server ServerConfig + Database DatabaseConfig + MCIAM MCIAMConfig + ApiSpec *ApiSpec + RegistryCache RegistryCacheInterface + SetupYaml SetupYamlConfig + IframeTargetIsHost bool // IFRAME_TARGET_IS_HOST 환경변수 } // SetupYamlConfig FR-CLOUD-ADMIN-006-08용 raw yaml 도달성 확인 설정 @@ -32,6 +33,8 @@ type RegistryCacheInterface interface { GetBaseURL(subsystem, operationId string) string // GetActionSpec 캐시의 ServiceActions에서 ActionSpec 반환. nil 이면 api.yaml ActionSpec 사용. GetActionSpec(subsystem, operationId string) *ActionSpec + // GetAllServices 캐시의 전체 서비스 목록 반환. 캐시 없음/만료이면 nil 반환. + GetAllServices() map[string]Service Store(responseData interface{}) Invalidate() } @@ -86,6 +89,7 @@ func Load() (*Config, error) { McWebconsoleMenuYaml: getEnv("MCWEBCONSOLE_MENUYAML", ""), McAdmincliApiYaml: getEnv("MCADMINCLI_APIYAML", ""), }, + IframeTargetIsHost: getEnv("IFRAME_TARGET_IS_HOST", "false") == "true", } // API 스펙 로드 diff --git a/api/internal/handler/apihosts.go b/api/internal/handler/apihosts.go new file mode 100644 index 00000000..69326491 --- /dev/null +++ b/api/internal/handler/apihosts.go @@ -0,0 +1,113 @@ +package handler + +import ( + "encoding/json" + "fmt" + "io" + "log" + "net/http" + // "regexp" + "strings" + + "mc_web_console_api/internal/config" + "mc_web_console_api/internal/model" + + "github.com/labstack/echo/v4" +) + +// ServiceNoAuth Auth 정보를 제외한 서비스 호스트 정보 (Buffalo ServiceNoAuth 호환) +type ServiceNoAuth struct { + BaseURL string `json:"BaseURL"` +} + +// GetApiHosts POST /api/getapihosts +// MCIAM_USE=false: api.yaml Services에서 추출 +// MCIAM_USE=true: RegistryCache 우선, 미적재 시 ListMcmpApisServices 호출 후 반환 +// IFRAME_TARGET_IS_HOST=true: BaseURL을 :port/path 형식으로 변환 +func GetApiHosts(c echo.Context) error { + cfg, _ := c.Get("config").(*config.Config) + if cfg == nil { + return c.JSON(http.StatusOK, map[string]interface{}{"error": "config not available"}) + } + + apiHosts := make(map[string]ServiceNoAuth) + + // api.yaml을 기본값으로 사용 (레지스트리 미등록 서비스도 포함) + for k, v := range cfg.ApiSpec.Services { + apiHosts[k] = ServiceNoAuth{BaseURL: v.BaseURL} + } + + if cfg.MCIAM.Use && cfg.RegistryCache != nil { + cached := cfg.RegistryCache.GetAllServices() + if cached == nil { + // 캐시 미적재 → ListMcmpApisServices 직접 호출하여 채워넣기 + if err := refreshRegistryCache(cfg, c); err != nil { + log.Printf("[GetApiHosts] cache refresh failed: %v", err) + } + cached = cfg.RegistryCache.GetAllServices() + } + // 레지스트리 값으로 override (BaseURL이 있는 경우만) + for k, v := range cached { + if v.BaseURL != "" { + apiHosts[k] = ServiceNoAuth{BaseURL: v.BaseURL} + } + } + } + + commonResponse := model.CommonResponseStatusOK(apiHosts) + + // IFRAME_TARGET_IS_HOST=true 시 :port/path 형식으로 변환하는 로직. + // HTTPS(HSTS) 환경에서 브라우저 protocol이 강제되어 http 서비스 접근 불가 문제로 비활성화. + // DB에 외부 접근 가능한 full URL을 그대로 저장하고 전달하는 방식으로 변경. + // if cfg.IframeTargetIsHost { + // re := regexp.MustCompile(`:(\d+.*)`) + // for fw, host := range apiHosts { + // if portURLStr := re.FindString(host.BaseURL); portURLStr != "" { + // host.BaseURL = portURLStr + // apiHosts[fw] = host + // } + // } + // commonResponse = model.CommonResponseStatusOK(apiHosts) + // } + + return c.JSON(commonResponse.Status.Code, commonResponse) +} + +// refreshRegistryCache mc-iam-manager의 ListMcmpApisServices를 직접 호출하여 RegistryCache 갱신. +// buildAuthHeader는 proxy.go에서 공유 (같은 handler 패키지). +func refreshRegistryCache(cfg *config.Config, c echo.Context) error { + service, actionSpec, err := cfg.ApiSpec.GetAction("mc-iam-manager", "ListMcmpApisServices") + if err != nil { + return fmt.Errorf("ListMcmpApisServices not found in api.yaml: %w", err) + } + + targetURL := service.BaseURL + actionSpec.ResourcePath + req, err := http.NewRequest(strings.ToUpper(actionSpec.Method), targetURL, nil) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + + if authHeader := buildAuthHeader(c, service); authHeader != "" { + req.Header.Set("Authorization", authHeader) + } + + resp, err := (&http.Client{}).Do(req) + if err != nil { + return fmt.Errorf("ListMcmpApisServices call failed: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("ListMcmpApisServices returned %d", resp.StatusCode) + } + + body, _ := io.ReadAll(resp.Body) + var responseData interface{} + if err := json.Unmarshal(body, &responseData); err != nil { + return fmt.Errorf("ListMcmpApisServices response parse failed: %w", err) + } + + cfg.RegistryCache.Store(responseData) + return nil +} diff --git a/api/internal/handler/proxy.go b/api/internal/handler/proxy.go index 5f278063..cf9e4e1d 100644 --- a/api/internal/handler/proxy.go +++ b/api/internal/handler/proxy.go @@ -2,8 +2,15 @@ package handler import ( "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" "encoding/base64" "encoding/json" + "encoding/pem" "fmt" "io" "log" @@ -42,9 +49,36 @@ func SubsystemAnyController(c echo.Context) error { // api.yaml에서 기본 Service + ActionSpec 조회 (fallback 및 Auth 설정 소스) service, actionSpec, err := cfg.ApiSpec.GetAction(subsystemName, operationId) if err != nil { - log.Printf("GetAction error: subsystem=%s operationId=%s err=%v", subsystemName, operationId, err) - msg := fmt.Sprintf("API not found: %s/%s (%s)", subsystemName, operationId, err.Error()) - return c.JSON(http.StatusNotFound, model.CommonResponseStatusNotFound(msg)) + // MCIAM_USE=true이면 RegistryCache에서 ActionSpec 조회 시도 + // (mc-iam-manager 레지스트리에만 있고 api.yaml에 없는 action 대응) + if cfg.MCIAM.Use && cfg.RegistryCache != nil { + if allSvcs := cfg.RegistryCache.GetAllServices(); allSvcs == nil { + _ = refreshRegistryCache(cfg, c) + } + if cachedSpec := cfg.RegistryCache.GetActionSpec(subsystemName, operationId); cachedSpec != nil { + if svc, svcErr := cfg.ApiSpec.GetService(subsystemName); svcErr == nil { + service = svc + actionSpec = cachedSpec + err = nil + log.Printf("[RegistryCache] ActionSpec fallback for %s/%s", subsystemName, operationId) + } + } + } + if err != nil { + log.Printf("GetAction error: subsystem=%s operationId=%s err=%v", subsystemName, operationId, err) + msg := fmt.Sprintf("API not found: %s/%s (%s)", subsystemName, operationId, err.Error()) + return c.JSON(http.StatusNotFound, model.CommonResponseStatusNotFound(msg)) + } + } + + // MCIAM_USE=true이고 캐시가 비어 있으면 ListMcmpApisServices 자동 갱신 + // (UpdateFrameworkService 후 invalidate된 캐시를 복원) + if cfg.MCIAM.Use && cfg.RegistryCache != nil { + if allSvcs := cfg.RegistryCache.GetAllServices(); allSvcs == nil { + if err := refreshRegistryCache(cfg, c); err != nil { + log.Printf("[SubsystemAnyController] cache refresh failed: %v", err) + } + } } // BaseURL: 캐시 우선 → 없으면 api.yaml BaseURL (mc-iam-manager 고정 주소) @@ -101,6 +135,16 @@ func SubsystemAnyController(c echo.Context) error { bodyBytes, _ = json.Marshal(commonRequest.Request) } + // mc-infra-manager RegisterCredential: 평문 → hybrid encryption 변환 + if strings.ToLower(subsystemName) == "mc-infra-manager" && + strings.EqualFold(operationId, "RegisterCredential") { + encrypted, encErr := encryptCredentialBody(bodyBytes, effectiveBaseURL, service) + if encErr != nil { + return errors.NewInternalServerError("credential encryption failed", encErr) + } + bodyBytes = encrypted + } + httpReq, err := http.NewRequest(strings.ToUpper(effectiveActionSpec.Method), targetURL, bytes.NewBuffer(bodyBytes)) if err != nil { return errors.NewInternalServerError("Failed to build request", err) @@ -113,6 +157,21 @@ func SubsystemAnyController(c echo.Context) error { httpReq.Header.Set("Authorization", authHeader) } + // mc-infra-manager 전용 헤더 포워딩 (v0.12 x-credential-holder 지원) + if strings.ToLower(subsystemName) == "mc-infra-manager" { + // 클라이언트 헤더 우선, 없으면 로그인 사용자 role 사용 + credHolder := c.Request().Header.Get("x-credential-holder") + if credHolder == "" { + credHolder, _ = c.Get("role").(string) + } + if credHolder != "" { + httpReq.Header.Set("x-credential-holder", credHolder) + } + if reqID := c.Request().Header.Get("x-request-id"); reqID != "" { + httpReq.Header.Set("x-request-id", reqID) + } + } + log.Printf("Proxying %s %s", httpReq.Method, targetURL) client := &http.Client{} @@ -154,6 +213,138 @@ func SubsystemAnyController(c echo.Context) error { return c.JSON(resp.StatusCode, commonResp) } +// publicKeyResponse GET /credential/publicKey 응답 구조 +type publicKeyResponse struct { + PublicKey string `json:"publicKey"` + PublicKeyTokenId string `json:"publicKeyTokenId"` +} + +// plainCredentialRequest 프론트에서 전달하는 평문 credential 요청 구조 +type plainCredentialRequest struct { + CredentialHolder string `json:"credentialHolder"` + ProviderName string `json:"providerName"` + CredentialKeyValueList []credentialKV `json:"credentialKeyValueList"` +} + +type credentialKV struct { + Key string `json:"key"` + Value string `json:"value"` +} + +// encryptedCredentialRequest mc-infra-manager RegisterCredential 암호화된 요청 구조 +type encryptedCredentialRequest struct { + CredentialHolder string `json:"credentialHolder"` + ProviderName string `json:"providerName"` + CredentialKeyValueList []credentialKV `json:"credentialKeyValueList"` + EncryptedClientAesKeyByPublicKey string `json:"encryptedClientAesKeyByPublicKey"` + PublicKeyTokenId string `json:"publicKeyTokenId"` +} + +// encryptCredentialBody 평문 credential payload를 hybrid encryption으로 변환한다. +// 1. GET /credential/publicKey → RSA 공개키 획득 +// 2. AES-256-GCM 키 생성, credentialKeyValueList[].value 암호화 +// 3. RSA-OAEP(SHA-256)으로 AES 키 암호화 → base64 +func encryptCredentialBody(plainBody []byte, baseURL string, service *config.Service) ([]byte, error) { + // 1. 공개키 조회 + pkURL := baseURL + "/credential/publicKey" + pkReq, err := http.NewRequest(http.MethodGet, pkURL, nil) + if err != nil { + return nil, fmt.Errorf("build publicKey request: %w", err) + } + // Basic auth 적용 + if service.Auth.Type == "basic" && service.Auth.Username != "" { + encoded := base64.StdEncoding.EncodeToString([]byte(service.Auth.Username + ":" + service.Auth.Password)) + pkReq.Header.Set("Authorization", "Basic "+encoded) + } + pkResp, err := (&http.Client{}).Do(pkReq) + if err != nil { + return nil, fmt.Errorf("get publicKey: %w", err) + } + defer pkResp.Body.Close() + pkBody, _ := io.ReadAll(pkResp.Body) + + var pkData publicKeyResponse + if err := json.Unmarshal(pkBody, &pkData); err != nil { + return nil, fmt.Errorf("parse publicKey response: %w", err) + } + if pkData.PublicKey == "" { + return nil, fmt.Errorf("empty publicKey from mc-infra-manager") + } + + // 2. RSA 공개키 파싱 + block, _ := pem.Decode([]byte(pkData.PublicKey)) + if block == nil { + return nil, fmt.Errorf("failed to decode PEM publicKey") + } + pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return nil, fmt.Errorf("parse RSA publicKey: %w", err) + } + rsaPub, ok := pubInterface.(*rsa.PublicKey) + if !ok { + return nil, fmt.Errorf("publicKey is not RSA") + } + + // 3. 평문 요청 파싱 + var plain plainCredentialRequest + if err := json.Unmarshal(plainBody, &plain); err != nil { + return nil, fmt.Errorf("parse plain credential body: %w", err) + } + + // 4. AES-256 키 생성 + aesKey := make([]byte, 32) + if _, err := rand.Read(aesKey); err != nil { + return nil, fmt.Errorf("generate AES key: %w", err) + } + + // 5. credentialKeyValueList[].value AES-256-GCM 암호화 + encryptedKVList := make([]credentialKV, len(plain.CredentialKeyValueList)) + for i, kv := range plain.CredentialKeyValueList { + cipherText, err := aesGCMEncrypt(aesKey, []byte(kv.Value)) + if err != nil { + return nil, fmt.Errorf("encrypt credential value [%s]: %w", kv.Key, err) + } + encryptedKVList[i] = credentialKV{ + Key: kv.Key, + Value: base64.StdEncoding.EncodeToString(cipherText), + } + } + + // 6. AES 키를 RSA-OAEP(SHA-256)으로 암호화 + encAESKey, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, rsaPub, aesKey, nil) + if err != nil { + return nil, fmt.Errorf("RSA-OAEP encrypt AES key: %w", err) + } + + // 7. 암호화된 payload 구성 + encrypted := encryptedCredentialRequest{ + CredentialHolder: plain.CredentialHolder, + ProviderName: plain.ProviderName, + CredentialKeyValueList: encryptedKVList, + EncryptedClientAesKeyByPublicKey: base64.StdEncoding.EncodeToString(encAESKey), + PublicKeyTokenId: pkData.PublicKeyTokenId, + } + return json.Marshal(encrypted) +} + +// aesGCMEncrypt AES-256-GCM 암호화. 반환값: nonce(12B) + ciphertext +func aesGCMEncrypt(key, plaintext []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + nonce := make([]byte, gcm.NonceSize()) + if _, err := rand.Read(nonce); err != nil { + return nil, err + } + ciphertext := gcm.Seal(nonce, nonce, plaintext, nil) + return ciphertext, nil +} + // buildAuthHeader api.yaml의 auth 타입에 따라 Authorization 헤더 값 반환 func buildAuthHeader(c echo.Context, service *config.Service) string { switch service.Auth.Type { diff --git a/api/internal/service/registry_cache.go b/api/internal/service/registry_cache.go index be9abf01..8f280470 100644 --- a/api/internal/service/registry_cache.go +++ b/api/internal/service/registry_cache.go @@ -50,6 +50,25 @@ func (rc *RegistryCache) Store(responseData interface{}) { log.Printf("[RegistryCache] stored %d services (actions: %d)", len(services), len(actions)) } +// GetAllServices 캐시가 유효한 경우 전체 서비스 목록 반환. +// 캐시 없음/만료이면 nil 반환. +func (rc *RegistryCache) GetAllServices() map[string]config.Service { + rc.mu.RLock() + services := rc.services + storedAt := rc.storedAt + rc.mu.RUnlock() + + if services == nil || rc.isExpired(storedAt) { + return nil + } + + result := make(map[string]config.Service, len(services)) + for k, v := range services { + result[k] = v + } + return result +} + // Invalidate 캐시 무효화. UpdateFrameworkService 성공 시 호출. func (rc *RegistryCache) Invalidate() { rc.mu.Lock() diff --git a/conf/api.yaml b/conf/api.yaml index 621ab24a..70cb5f1f 100644 --- a/conf/api.yaml +++ b/conf/api.yaml @@ -7,15 +7,15 @@ services: baseurl: http://spider_url:1024/spider auth: type: basic - username: null - password: null + username: + password: mc-iam-manager: version: 0.2.11 - baseurl: http://52.79.163.111:5006 + baseurl: http://mciam.onecloudcon.com:5006 auth: type: bearer mc-infra-manager: - version: 0.9.11 + version: 0.12.9 baseurl: http://52.79.163.111:1323/tumblebug auth: type: basic @@ -29,23 +29,39 @@ services: mc-observability: version: main baseurl: http://observability_url:18080 - auth: null + auth: mc-application-manager: version: main baseurl: http://localhost:18084 - auth: null + auth: + mc-application-manager-fe: + version: main + baseurl: http://application_manager_fe_url:18084 + auth: mc-workflow-manager: version: main baseurl: http://workflow_url:18083 - auth: null + auth: + mc-workflow-manager-fe: + version: main + baseurl: http://workflow_manager_fe_url:18083 + auth: mc-cost-optimizer: version: main baseurl: http://cost_optimizer_url:18082 auth: null + mc-cost-optimizer-fe: + version: main + baseurl: http://cost_optimizer_fe_url:7780 + auth: null mc-data-manager: version: main:20240923 baseurl: http://localhost:3300 - auth: null + auth: + mc-data-manager-fe: + version: main + baseurl: http://data_manager_fe_url:3300 + auth: serviceActions: mc-infra-connector: Remove-Nodegroup: @@ -75,8 +91,7 @@ serviceActions: Health-Check-Readyz: method: get resourcePath: /readyz - description: Checks the health of CB-Spider service and its dependencies via - /readyz endpoint. 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/Readiness-Check-Guide)] + description: Checks the health of CB-Spider service and its dependencies via /readyz endpoint. 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/Readiness-Check-Guide)] Unregister-Subnet: method: delete resourcePath: /regsubnet/{Name} @@ -88,15 +103,11 @@ serviceActions: List-All-Vpc: method: get resourcePath: /allvpc - description: Retrieve a comprehensive list of all Virtual Private Clouds (VPCs) - associated with a specific connection,
including those mapped between - CB-Spider and the CSP,
only registered in CB-Spider's metadata,
- and only existing in the CSP. + description: Retrieve a comprehensive list of all Virtual Private Clouds (VPCs) associated with a specific connection,
including those mapped between CB-Spider and the CSP,
only registered in CB-Spider's metadata,
and only existing in the CSP. Any-Call: method: post resourcePath: /anycall - description: Execute a custom function (FID) with key-value parameters through - AnyCall. 🕷️ [[Development Guide](https://github.com/cloud-barista/cb-spider/wiki/AnyCall-API-Extension-Guide)] + description: Execute a custom function (FID) with key-value parameters through AnyCall. 🕷️ [[Development Guide](https://github.com/cloud-barista/cb-spider/wiki/AnyCall-API-Extension-Guide)] Get-Credential: method: get resourcePath: /credential/{CredentialName} @@ -116,9 +127,7 @@ serviceActions: List-Product-Family: method: get resourcePath: /productfamily/{RegionName} - description: Retrieve a list of Product Families associated with a specific - connection and region. 🕷️ [[Concept Guide](https://github.com/cloud-barista/cb-spider/wiki/Price-Info-and-Cloud-Driver-API)], - 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/RestAPI-Multi%E2%80%90Cloud-Price-Information-Guide)] + description: Retrieve a list of Product Families associated with a specific connection and region. 🕷️ [[Concept Guide](https://github.com/cloud-barista/cb-spider/wiki/Price-Info-and-Cloud-Driver-API)], 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/RestAPI-Multi%E2%80%90Cloud-Price-Information-Guide)] Get-Region: method: get resourcePath: /region/{RegionName} @@ -134,10 +143,7 @@ serviceActions: List-All-Vm: method: get resourcePath: /allvm - description: Retrieve a comprehensive list of all Virtual Machines (VMs) associated - with a specific connection,
including those mapped between CB-Spider - and the CSP,
only registered in CB-Spider's metadata,
and only existing - in the CSP. + description: Retrieve a comprehensive list of all Virtual Machines (VMs) associated with a specific connection,
including those mapped between CB-Spider and the CSP,
only registered in CB-Spider's metadata,
and only existing in the CSP. Get-Myimage: method: get resourcePath: /myimage/{Name} @@ -165,10 +171,7 @@ serviceActions: List-All-Cluster: method: get resourcePath: /allcluster - description: Retrieve a comprehensive list of all Clusters associated with a - specific connection,
including those mapped between CB-Spider and the - CSP,
only registered in CB-Spider's metadata,
and only existing - in the CSP. + description: Retrieve a comprehensive list of all Clusters associated with a specific connection,
including those mapped between CB-Spider and the CSP,
only registered in CB-Spider's metadata,
and only existing in the CSP. Upgrade-Cluster: method: put resourcePath: /cluster/{Name}/upgrade @@ -180,8 +183,7 @@ serviceActions: Count-All-Nlbs: method: get resourcePath: /countnlb - description: Get the total number of Network Load Balancers (NLBs) across all - connections. + description: Get the total number of Network Load Balancers (NLBs) across all connections. Attach-Disk: method: put resourcePath: /disk/{Name}/attach @@ -197,20 +199,15 @@ serviceActions: Get-Region-Zone-Preconfig: method: get resourcePath: /preconfig/regionzone/{Name} - description: Retrieve details of a specific pre-configured Region Zone based - on driver and credential names. 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/REST-API-Region-Zone-Information-Guide)] + description: Retrieve details of a specific pre-configured Region Zone based on driver and credential names. 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/REST-API-Region-Zone-Information-Guide)] Get-Price-Info: method: post resourcePath: /priceinfo/{ProductFamily}/{RegionName} - description: 'Retrieve price details of a specific Product Family in a specific - Region. 🕷️ [[Concept Guide](https://github.com/cloud-barista/cb-spider/wiki/Price-Info-and-Cloud-Driver-API)], - 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/RestAPI-Multi%E2%80%90Cloud-Price-Information-Guide)] -
* example body: {"connectionName":"aws-connection","FilterList":[{"Key":"instanceType","Value":"t2.micro"}]}' + description: 'Retrieve price details of a specific Product Family in a specific Region. 🕷️ [[Concept Guide](https://github.com/cloud-barista/cb-spider/wiki/Price-Info-and-Cloud-Driver-API)], 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/RestAPI-Multi%E2%80%90Cloud-Price-Information-Guide)]
* example body: {"connectionName":"aws-connection","FilterList":[{"Key":"instanceType","Value":"t2.micro"}]}' Register-Vm: method: post resourcePath: /regvm - description: Register a new Virtual Machine (VM) with the specified name and - CSP ID. + description: Register a new Virtual Machine (VM) with the specified name and CSP ID. List-Key: method: get resourcePath: /keypair @@ -218,8 +215,7 @@ serviceActions: Create-Key: method: post resourcePath: /keypair - description: Create a new KeyPair with the specified configurations. 🕷️ [[User - Guide](https://github.com/cloud-barista/cb-spider/wiki/features-and-usages#5-vm-keypair-%EC%83%9D%EC%84%B1-%EB%B0%8F-%EC%A0%9C%EC%96%B4)] + description: Create a new KeyPair with the specified configurations. 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/features-and-usages#5-vm-keypair-%EC%83%9D%EC%84%B1-%EB%B0%8F-%EC%A0%9C%EC%96%B4)] Unregister-Vm: method: delete resourcePath: /regvm/{Name} @@ -227,10 +223,7 @@ serviceActions: List-All-Securitygroups: method: get resourcePath: /allsecuritygroup - description: Retrieve a comprehensive list of all Security Groups associated - with a specific connection,
including those mapped between CB-Spider - and the CSP,
only registered in CB-Spider's metadata,
and only existing - in the CSP. + description: Retrieve a comprehensive list of all Security Groups associated with a specific connection,
including those mapped between CB-Spider and the CSP,
only registered in CB-Spider's metadata,
and only existing in the CSP. Delete-Csp-Securitygroup: method: delete resourcePath: /cspsecuritygroup/{Id} @@ -238,9 +231,7 @@ serviceActions: List-Preconfigured-Original-Org-Region: method: get resourcePath: /preconfig/orgregion - description: Retrieve a list of pre-configured Original Regions based on driver - and credential names.
The response structure may vary depending on the - request DriverName and CredentialName. + description: Retrieve a list of pre-configured Original Regions based on driver and credential names.
The response structure may vary depending on the request DriverName and CredentialName. Unregister-Vpc: method: delete resourcePath: /regvpc/{Name} @@ -248,9 +239,7 @@ serviceActions: List-Org-Vm-Spec: method: get resourcePath: /vmorgspec - description: Retrieve a list of Original VM Specs associated with a specific - connection.
The response structure may vary depending on the request - ConnectionName. + description: Retrieve a list of Original VM Specs associated with a specific connection.
The response structure may vary depending on the request ConnectionName. Get-Org-Vm-Spec: method: get resourcePath: /vmorgspec/{Name} @@ -258,10 +247,7 @@ serviceActions: List-All-Key: method: get resourcePath: /allkeypair - description: Retrieve a comprehensive list of all KeyPairs associated with a - specific connection,
including those mapped between CB-Spider and the - CSP,
only registered in CB-Spider's metadata,
and only existing - in the CSP. + description: Retrieve a comprehensive list of all KeyPairs associated with a specific connection,
including those mapped between CB-Spider and the CSP,
only registered in CB-Spider's metadata,
and only existing in the CSP. Get-Region-Zone: method: get resourcePath: /regionzone/{Name} @@ -285,8 +271,7 @@ serviceActions: Register-Nlb: method: post resourcePath: /regnlb - description: Register a new Network Load Balancer (NLB) with the specified name - and CSP ID. + description: Register a new Network Load Balancer (NLB) with the specified name and CSP ID. Get-Securitygroup: method: get resourcePath: /securitygroup/{Name} @@ -326,13 +311,11 @@ serviceActions: Health-Check-Ping: method: get resourcePath: /ping - description: Checks the health of CB-Spider service and its dependencies via - /ping endpoint. 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/Readiness-Check-Guide)] + description: Checks the health of CB-Spider service and its dependencies via /ping endpoint. 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/Readiness-Check-Guide)] List-Vm-Status: method: get resourcePath: /vmstatus - description: Retrieve a list of statuses for Virtual Machines (VMs) associated - with a specific connection. + description: Retrieve a list of statuses for Virtual Machines (VMs) associated with a specific connection. Count-Connections-By-Provider: method: get resourcePath: /countconnectionconfig/{ProviderName} @@ -364,12 +347,7 @@ serviceActions: Create-Cluster: method: post resourcePath: /cluster - description: 'Create a new Cluster with specified configurations. 🕷️ [[Concept - Guide](https://github.com/cloud-barista/cb-spider/wiki/Provider-Managed-Kubernetes-and-Driver-API)] -
* NodeGroupList is optional, depends on CSP type:
 - Type-I - (e.g., Tencent, Alibaba): requires separate Node Group addition after Cluster - creation.
 - Type-II (e.g., Azure, NHN): mandates at least one Node - Group during initial Cluster creation.' + description: 'Create a new Cluster with specified configurations. 🕷️ [[Concept Guide](https://github.com/cloud-barista/cb-spider/wiki/Provider-Managed-Kubernetes-and-Driver-API)]
* NodeGroupList is optional, depends on CSP type:
 - Type-I (e.g., Tencent, Alibaba): requires separate Node Group addition after Cluster creation.
 - Type-II (e.g., Azure, NHN): mandates at least one Node Group during initial Cluster creation.' Count-All-Myimages: method: get resourcePath: /countmyimage @@ -389,23 +367,19 @@ serviceActions: List-Nlb: method: get resourcePath: /nlb - description: Retrieve a list of Network Load Balancers (NLBs) associated with - a specific connection. + description: Retrieve a list of Network Load Balancers (NLBs) associated with a specific connection. Create-Nlb: method: post resourcePath: /nlb - description: Create a new Network Load Balancer (NLB) with specified configurations. - 🕷️ [[Concept Guide](https://github.com/cloud-barista/cb-spider/wiki/Network-Load-Balancer-and-Driver-API)] + description: Create a new Network Load Balancer (NLB) with specified configurations. 🕷️ [[Concept Guide](https://github.com/cloud-barista/cb-spider/wiki/Network-Load-Balancer-and-Driver-API)] List-Org-Zone: method: get resourcePath: /orgzone - description: Retrieve a list of Original Zones associated with a specific connection. -
The response structure may vary depending on the request ConnectionName. + description: Retrieve a list of Original Zones associated with a specific connection.
The response structure may vary depending on the request ConnectionName. Health-Check-Healthcheck: method: get resourcePath: /healthcheck - description: Checks the health of CB-Spider service and its dependencies via - /healthcheck endpoint. 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/Readiness-Check-Guide)] + description: Checks the health of CB-Spider service and its dependencies via /healthcheck endpoint. 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/Readiness-Check-Guide)] Delete-Key: method: delete resourcePath: /keypair/{Name} @@ -417,8 +391,7 @@ serviceActions: List-Image: method: get resourcePath: /vmimage - description: Retrieve a list of Public Images associated with a specific connection. - 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/How-to-get-Image-List-with-REST-API)] + description: Retrieve a list of Public Images associated with a specific connection. 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/How-to-get-Image-List-with-REST-API)] Get-Cluster: method: get resourcePath: /cluster/{Name} @@ -438,13 +411,11 @@ serviceActions: Health-Check-Health: method: get resourcePath: /health - description: Checks the health of CB-Spider service and its dependencies via - /health endpoint. 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/Readiness-Check-Guide)] + description: Checks the health of CB-Spider service and its dependencies via /health endpoint. 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/Readiness-Check-Guide)] Register-Vpc: method: post resourcePath: /regvpc - description: Register a new Virtual Private Cloud (VPC) with the specified name - and CSP ID. + description: Register a new Virtual Private Cloud (VPC) with the specified name and CSP ID. Unregister-Nlb: method: delete resourcePath: /regnlb/{Name} @@ -456,25 +427,19 @@ serviceActions: Create-Vpc: method: post resourcePath: /vpc - description: Create a new Virtual Private Cloud (VPC) with specified subnet - configurations. 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/features-and-usages#3-vpcsubnet-%EC%83%9D%EC%84%B1-%EB%B0%8F-%EC%A0%9C%EC%96%B4)] + description: Create a new Virtual Private Cloud (VPC) with specified subnet configurations. 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/features-and-usages#3-vpcsubnet-%EC%83%9D%EC%84%B1-%EB%B0%8F-%EC%A0%9C%EC%96%B4)] List-Vpc: method: get resourcePath: /vpc - description: Retrieve a list of Virtual Private Clouds (VPCs) associated with - a specific connection. + description: Retrieve a list of Virtual Private Clouds (VPCs) associated with a specific connection. Control-Vm: method: put resourcePath: /controlvm/{Name} - description: Control the state of a Virtual Machine (VM) such as suspend, resume, - or reboot. + description: Control the state of a Virtual Machine (VM) such as suspend, resume, or reboot. List-All-Myimage: method: get resourcePath: /allmyimage - description: Retrieve a comprehensive list of all MyImages associated with a - specific connection,
including those mapped between CB-Spider and the - CSP,
only registered in CB-Spider's metadata,
and only existing - in the CSP. + description: Retrieve a comprehensive list of all MyImages associated with a specific connection,
including those mapped between CB-Spider and the CSP,
only registered in CB-Spider's metadata,
and only existing in the CSP. Count-Disks-By-Connection: method: get resourcePath: /countdisk/{ConnectionName} @@ -498,10 +463,7 @@ serviceActions: List-All-Nlb: method: get resourcePath: /allnlb - description: Retrieve a comprehensive list of all Network Load Balancers (NLBs) - associated with a specific connection,
including those mapped between - CB-Spider and the CSP,
only registered in CB-Spider's metadata,
- and only existing in the CSP. + description: Retrieve a comprehensive list of all Network Load Balancers (NLBs) associated with a specific connection,
including those mapped between CB-Spider and the CSP,
only registered in CB-Spider's metadata,
and only existing in the CSP. Set-Nodegroup-Autoscaling: method: put resourcePath: /cluster/{Name}/nodegroup/{NodeGroupName}/onautoscaling @@ -509,8 +471,7 @@ serviceActions: List-Vm-Spec: method: get resourcePath: /vmspec - description: Retrieve a list of VM specs associated with a specific connection. - 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/features-and-usages#2-vm-spec-%EC%A0%95%EB%B3%B4-%EC%A0%9C%EA%B3%B5)] + description: Retrieve a list of VM specs associated with a specific connection. 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/features-and-usages#2-vm-spec-%EC%A0%95%EB%B3%B4-%EC%A0%9C%EA%B3%B5)] Count-All-Disks: method: get resourcePath: /countdisk @@ -550,8 +511,7 @@ serviceActions: Count-Nlbs-By-Connection: method: get resourcePath: /countnlb/{ConnectionName} - description: Get the total number of Network Load Balancers (NLBs) for a specific - connection. + description: Get the total number of Network Load Balancers (NLBs) for a specific connection. Delete-Nlb: method: delete resourcePath: /nlb/{Name} @@ -571,9 +531,7 @@ serviceActions: List-Org-Region: method: get resourcePath: /orgregion - description: Retrieve a list of Original Regions associated with a specific - connection.
The response structure may vary depending on the request - ConnectionName. + description: Retrieve a list of Original Regions associated with a specific connection.
The response structure may vary depending on the request ConnectionName. Count-All-Vms: method: get resourcePath: /countvm @@ -605,8 +563,7 @@ serviceActions: Get-Vmgroup-Healthinfo: method: get resourcePath: /nlb/{Name}/health - description: Retrieve the health information of the VM group in a specified - Network Load Balancer (NLB). + description: Retrieve the health information of the VM group in a specified Network Load Balancer (NLB). List-Regions: method: get resourcePath: /region @@ -618,9 +575,7 @@ serviceActions: Create-Securitygroup: method: post resourcePath: /securitygroup - description: Create a new Security Group with specified rules and tags. 🕷️ [[Concept - Guide](https://github.com/cloud-barista/cb-spider/wiki/Security-Group-Rules-and-Driver-API)], - 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/features-and-usages#4-securitygroup-%EC%83%9D%EC%84%B1-%EB%B0%8F-%EC%A0%9C%EC%96%B4)] + description: Create a new Security Group with specified rules and tags. 🕷️ [[Concept Guide](https://github.com/cloud-barista/cb-spider/wiki/Security-Group-Rules-and-Driver-API)], 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/features-and-usages#4-securitygroup-%EC%83%9D%EC%84%B1-%EB%B0%8F-%EC%A0%9C%EC%96%B4)] List-Securitygroup: method: get resourcePath: /securitygroup @@ -628,9 +583,7 @@ serviceActions: List-All-Disk: method: get resourcePath: /alldisk - description: Retrieve a comprehensive list of all Disks associated with a specific - connection,
including those mapped between CB-Spider and the CSP,
- only registered in CB-Spider's metadata,
and only existing in the CSP. + description: Retrieve a comprehensive list of all Disks associated with a specific connection,
including those mapped between CB-Spider and the CSP,
only registered in CB-Spider's metadata,
and only existing in the CSP. Add-Nodegroup: method: post resourcePath: /cluster/{Name}/nodegroup @@ -642,14 +595,11 @@ serviceActions: Create-Disk: method: post resourcePath: /disk - description: Create a new Disk with the specified configuration. 🕷️ [[Concept - Guide](https://github.com/cloud-barista/cb-spider/wiki/Disk-and-Driver-API)], - [[Snapshot-MyImage,Disk Guide](https://github.com/cloud-barista/cb-spider/wiki/VM-Snapshot,-MyImage-and-Disk-Overview)] + description: Create a new Disk with the specified configuration. 🕷️ [[Concept Guide](https://github.com/cloud-barista/cb-spider/wiki/Disk-and-Driver-API)], [[Snapshot-MyImage,Disk Guide](https://github.com/cloud-barista/cb-spider/wiki/VM-Snapshot,-MyImage-and-Disk-Overview)] List-Region-Zone-Preconfig: method: get resourcePath: /preconfig/regionzone - description: Retrieve a list of pre-configured Region Zones based on driver - and credential names. 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/REST-API-Region-Zone-Information-Guide)] + description: Retrieve a list of pre-configured Region Zones based on driver and credential names. 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/REST-API-Region-Zone-Information-Guide)] Delete-Csp-Nlb: method: delete resourcePath: /cspnlb/{Id} @@ -657,8 +607,7 @@ serviceActions: List-Region-Zone: method: get resourcePath: /regionzone - description: Retrieve a list of Region Zones associated with a specific connection. - 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/REST-API-Region-Zone-Information-Guide)] + description: Retrieve a list of Region Zones associated with a specific connection. 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/REST-API-Region-Zone-Information-Guide)] Count-All-Connections: method: get resourcePath: /countconnectionconfig @@ -682,9 +631,7 @@ serviceActions: Snapshot-Vm: method: post resourcePath: /myimage - description: Create a new MyImage snapshot from a specified VM. 🕷️ [[Concept - Guide](https://github.com/cloud-barista/cb-spider/wiki/MyImage-and-Driver-API)], - [[Snapshot-MyImage,Disk Guide](https://github.com/cloud-barista/cb-spider/wiki/VM-Snapshot,-MyImage-and-Disk-Overview)] + description: Create a new MyImage snapshot from a specified VM. 🕷️ [[Concept Guide](https://github.com/cloud-barista/cb-spider/wiki/MyImage-and-Driver-API)], [[Snapshot-MyImage,Disk Guide](https://github.com/cloud-barista/cb-spider/wiki/VM-Snapshot,-MyImage-and-Disk-Overview)] Unregister-Key: method: delete resourcePath: /regkeypair/{Name} @@ -692,14 +639,11 @@ serviceActions: Start-Vm: method: post resourcePath: /vm - description: Start a new Virtual Machine (VM) with specified configurations. - 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/features-and-usages#2-%EB%A9%80%ED%8B%B0%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-vm-%EC%9D%B8%ED%94%84%EB%9D%BC-%EC%9E%90%EC%9B%90-%EC%A0%9C%EC%96%B4multi-cloud-vm-infra-resource-control)], - [[Snapshot-MyImage,Disk Guide](https://github.com/cloud-barista/cb-spider/wiki/VM-Snapshot,-MyImage-and-Disk-Overview)] + description: Start a new Virtual Machine (VM) with specified configurations. 🕷️ [[User Guide](https://github.com/cloud-barista/cb-spider/wiki/features-and-usages#2-%EB%A9%80%ED%8B%B0%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-vm-%EC%9D%B8%ED%94%84%EB%9D%BC-%EC%9E%90%EC%9B%90-%EC%A0%9C%EC%96%B4multi-cloud-vm-infra-resource-control)], [[Snapshot-MyImage,Disk Guide](https://github.com/cloud-barista/cb-spider/wiki/VM-Snapshot,-MyImage-and-Disk-Overview)] List-Vm: method: get resourcePath: /vm - description: Retrieve a list of Virtual Machines (VMs) associated with a specific - connection. + description: Retrieve a list of Virtual Machines (VMs) associated with a specific connection. Get-Cloudos-Metainfo: method: get resourcePath: /cloudos/metainfo/{CloudOSName} @@ -721,6 +665,10 @@ serviceActions: method: post resourcePath: /api/mcmp-apis/list description: "전체 프레임워크 서비스 목록 및 BaseURL 조회." + CreateFrameworkService: + method: post + resourcePath: /api/mcmp-apis + description: "프레임워크 서비스 신규 등록. body: {name, version, baseUrl, authType, isActive}" UpdateFrameworkService: method: put resourcePath: /api/mcmp-apis/name/{serviceName} @@ -824,8 +772,7 @@ serviceActions: Syncrolelistwithkeycloak: method: get resourcePath: /api/tool/keycloak/role/sync - description: "연결된 TB(mcinframanager)의 NS 리스트를 Project List 로 등록. \n \n기존 등록된\ - \ project 와 중복이 발생하면 오류 발생. 새로운 환경에서 첫 회 실행하는 것을 추천." + description: "연결된 TB(mcinframanager)의 NS 리스트를 Project List 로 등록. \n \n기존 등록된 project 와 중복이 발생하면 오류 발생. 새로운 환경에서 첫 회 실행하는 것을 추천." Searchworkspacesbyname: method: get resourcePath: /api/ws/workspace/{workspaceName} @@ -1038,8 +985,7 @@ serviceActions: Createapiresourcesbyapiyaml: method: post resourcePath: /api/resource/file/framework/{framework} - description: "mc-admin-cli 에서 생성한 api yaml을 바탕으로 모든 리소스를 등록합니다. \n리소스가 중복될시\ - \ 오류를 반환하고 업데이트 하지 않습니다." + description: "mc-admin-cli 에서 생성한 api yaml을 바탕으로 모든 리소스를 등록합니다. \n리소스가 중복될시 오류를 반환하고 업데이트 하지 않습니다." Resetresource: method: delete resourcePath: /api/resource/reset @@ -1047,8 +993,7 @@ serviceActions: Syncprojectlistwithmcinfra: method: get resourcePath: /api/tool/mcinfra/sync - description: "연결된 TB(mcinframanager)의 NS 리스트를 Project List 로 등록. \n \n기존 등록된\ - \ project 와 중복이 발생하면 오류 발생. 새로운 환경에서 첫 회 실행하는 것을 추천." + description: "연결된 TB(mcinframanager)의 NS 리스트를 Project List 로 등록. \n \n기존 등록된 project 와 중복이 발생하면 오류 발생. 새로운 환경에서 첫 회 실행하는 것을 추천." Getdependentpermissionsbypolicyid: method: get resourcePath: /api/permission/policyid/{policyid} @@ -1232,16 +1177,14 @@ serviceActions: description: "Lookup spec list" AddNLBVMs: method: post - resourcePath: /ns/{nsId}/mci/{mciId}/nlb/{nlbId}/vm + resourcePath: /ns/{nsId}/infra/{mciId}/nlb/{nlbId}/node description: Add VMs to NLB AnalyzeProvisioningRisk: method: get resourcePath: /provisioning/risk/{specId} - description: 'Evaluate the likelihood of provisioning failure based on historical - data for a specific VM specification and image combination. + description: 'Evaluate the likelihood of provisioning failure based on historical data for a specific VM specification and image combination. - This endpoint provides intelligent risk assessment to help prevent deployment - failures: + This endpoint provides intelligent risk assessment to help prevent deployment failures: **Risk Analysis Factors:** @@ -1268,8 +1211,7 @@ serviceActions: **Recommended Actions by Risk Level:** - - **High Risk**: Consider alternative specs or images, verify CSP quotas and - permissions + - **High Risk**: Consider alternative specs or images, verify CSP quotas and permissions - **Medium Risk**: Proceed with caution, have backup plans ready @@ -1285,21 +1227,17 @@ serviceActions: - Helpful for capacity planning and resource selection' AnalyzeProvisioningRiskDetailed: method: get - resourcePath: /tumblebug/provisioning/risk/detailed - description: 'Provides comprehensive risk analysis with separate assessments - for VM specification and image risks, plus actionable recommendations. + resourcePath: /provisioning/risk/detailed + description: 'Provides comprehensive risk analysis with separate assessments for VM specification and image risks, plus actionable recommendations. - This endpoint offers enhanced risk analysis by separating spec-level and image-level - risk factors: + This endpoint offers enhanced risk analysis by separating spec-level and image-level risk factors: **Risk Analysis Breakdown:** - - **Spec Risk**: Analyzes whether the VM specification itself has compatibility - or resource issues + - **Spec Risk**: Analyzes whether the VM specification itself has compatibility or resource issues - - **Image Risk**: Evaluates the track record of the specific image with this - spec + - **Image Risk**: Evaluates the track record of the specific image with this spec - **Overall Risk**: Combines both factors to determine the primary risk source @@ -1308,8 +1246,7 @@ serviceActions: **Spec Risk Factors:** - - Number of different images that failed with this spec (indicates spec-level - issues) + - Number of different images that failed with this spec (indicates spec-level issues) - Overall failure rate across all images @@ -1337,18 +1274,15 @@ serviceActions: resourcePath: /resources/globalDns/records description: 'Delete multiple DNS records from Route53 in a single request. - Records are grouped by domain and submitted as a single ChangeBatch per domain - for efficiency.' + Records are grouped by domain and submitted as a single ChangeBatch per domain for efficiency.' CancelExecutionTask: method: post - resourcePath: /ns/{nsId}/cmd/mci/{mciId}/task/{taskId}/cancel - description: Cancel a running execution task by task ID. This will send a cancellation - signal to the task and update the VM command status. + resourcePath: /ns/{nsId}/cmd/infra/{mciId}/task/{taskId}/cancel + description: Cancel a running execution task by task ID. This will send a cancellation signal to the task and update the VM command status. CheckHTTPVersion: method: get resourcePath: /httpVersion - description: Checks and logs the HTTP version of the incoming request to the - server console. + description: Checks and logs the HTTP version of the incoming request to the server console. CheckK8sNodeGroupsOnK8sCreation: method: get resourcePath: /checkK8sNodeGroupsOnK8sCreation @@ -1367,13 +1301,12 @@ serviceActions: description: Check resources' existence ClearAllVmCommandStatus: method: delete - resourcePath: /ns/{nsId}/mci/{mciId}/vm/{vmId}/commandStatusAll + resourcePath: /ns/{nsId}/infra/{mciId}/node/{vmId}/commandStatusAll description: Delete all command status records for a VM ComplementSshKeyRemoteCommand: method: put resourcePath: /ns/{nsId}/resources/sshKey/{sshKeyId}/complement - description: Update username and privateKey to enable remote command execution - on registered VMs + description: Update username and privateKey to enable remote command execution on registered VMs CreateObjectStorage: method: put resourcePath: /ns/{nsId}/resources/objectStorage @@ -1386,8 +1319,7 @@ serviceActions: **Important Notes:** - - The `objectStorageName` must be globally unique across all existing buckets - in the S3 compatible storage. + - The `objectStorageName` must be globally unique across all existing buckets in the S3 compatible storage. - The bucket namespace is shared by all users of the system.' CreateOrUpdateLabel: @@ -1410,17 +1342,19 @@ serviceActions: method: delete resourcePath: /ns/{nsId}/resources/image description: Delete all images - DelAllMci: + DelAllInfra: + method: delete - resourcePath: /ns/{nsId}/mci + resourcePath: /ns/{nsId}/infra description: Delete all MCIs - DelAllMciPolicy: + DelAllInfraPolicy: + method: delete - resourcePath: /ns/{nsId}/policy/mci + resourcePath: /ns/{nsId}/policy/infra description: Delete all MCI policies DelAllNLB: method: delete - resourcePath: /ns/{nsId}/mci/{mciId}/nlb + resourcePath: /ns/{nsId}/infra/{mciId}/nlb description: Delete all NLBs DelAllNs: method: delete @@ -1453,28 +1387,23 @@ serviceActions: DelFirewallRules: method: delete resourcePath: /ns/{nsId}/resources/securityGroup/{securityGroupId}/rules - description: 'Delete specific FirewallRules: Remove specified rules from the - Security Group while keeping other existing rules. + description: 'Delete specific FirewallRules: Remove specified rules from the Security Group while keeping other existing rules. - This API will remove only the specified rules from the Security Group, leaving - all other rules intact. + This API will remove only the specified rules from the Security Group, leaving all other rules intact. Usage: - Use this API to remove specific firewall rules from a Security Group. Only - the rules matching the provided criteria will be deleted. + Use this API to remove specific firewall rules from a Security Group. Only the rules matching the provided criteria will be deleted. - - Rules that exactly match the provided Direction, Protocol, Port, and CIDR - will be removed. + - Rules that exactly match the provided Direction, Protocol, Port, and CIDR will be removed. - All other existing rules will remain unchanged. Notes: - - "Ports" field supports single port ("22"), port range ("80-100"), and multiple - ports/ranges ("22,80-100,443"). + - "Ports" field supports single port ("22"), port range ("80-100"), and multiple ports/ranges ("22,80-100,443"). - "Protocol" can be TCP, UDP, ICMP, ALL, etc. (as supported by the cloud provider). @@ -1485,21 +1414,24 @@ serviceActions: method: delete resourcePath: /ns/{nsId}/resources/image/{imageId} description: Delete image - DelMci: + DelInfra: + method: delete - resourcePath: /ns/{nsId}/mci/{mciId} + resourcePath: /ns/{nsId}/infra/{mciId} description: Delete MCI - DelMciPolicy: + DelInfraPolicy: + method: delete - resourcePath: /ns/{nsId}/policy/mci/{mciId} + resourcePath: /ns/{nsId}/policy/infra/{mciId} description: Delete MCI Policy - DelMciVm: + DelInfraNode: + method: delete - resourcePath: /ns/{nsId}/mci/{mciId}/vm/{vmId} + resourcePath: /ns/{nsId}/infra/{mciId}/node/{vmId} description: Delete VM in specified MCI DelNLB: method: delete - resourcePath: /ns/{nsId}/mci/{mciId}/nlb/{nlbId} + resourcePath: /ns/{nsId}/infra/{mciId}/nlb/{nlbId} description: Delete NLB DelNs: method: delete @@ -1522,11 +1454,9 @@ serviceActions: resourcePath: /ns/{nsId}/resources/vNet/{vNetId}/subnet/{subnetId} description: 'Delete Subnet - - refine: delete a subnet `object` if there''s no resource on CSP or no inforamation - on Spider + - refine: delete a subnet `object` if there''s no resource on CSP or no inforamation on Spider - - force: force: delete a subnet `resource` on a CSP regardless of the current - resource status (e.g., attempt to delete even if in use)' + - force: force: delete a subnet `resource` on a CSP regardless of the current resource status (e.g., attempt to delete even if in use)' DelVNet: method: delete resourcePath: /ns/{nsId}/resources/vNet/{vNetId} @@ -1534,18 +1464,17 @@ serviceActions: - withsubnets: delete VNet and its subnets - - refine: delete information of VNet and its subnets if there''s no info/resource - in Spider/CSP + - refine: delete information of VNet and its subnets if there''s no info/resource in Spider/CSP - - force: delete VNet and its subnets regardless of the status of info/resource - in Spider/CSP' + - force: delete VNet and its subnets regardless of the status of info/resource in Spider/CSP' DeleteAllK8sCluster: method: delete resourcePath: /ns/{nsId}/k8sCluster description: Delete all K8sClusters - DeleteAllMciDynamicTemplate: + DeleteAllInfraDynamicTemplate: + method: delete - resourcePath: /ns/{nsId}/template/mci + resourcePath: /ns/{nsId}/template/infra description: Delete all MCI Dynamic Templates in a namespace. DeleteAllRequests: method: delete @@ -1578,8 +1507,7 @@ serviceActions: DeleteGlobalDnsRecord: method: delete resourcePath: /resources/globalDns/record - description: 'Delete DNS record(s) from Route53. If setIdentifier is provided, - deletes only that specific record. + description: 'Delete DNS record(s) from Route53. If setIdentifier is provided, deletes only that specific record. If setIdentifier is empty, deletes all records matching the name and type.' DeleteK8sCluster: @@ -1590,9 +1518,10 @@ serviceActions: method: delete resourcePath: /ns/{nsId}/k8sCluster/{k8sClusterId}/k8sNodeGroup/{k8sNodeGroupName} description: Remove a K8sNodeGroup - DeleteMciDynamicTemplate: + DeleteInfraDynamicTemplate: + method: delete - resourcePath: /ns/{nsId}/template/mci/{templateId} + resourcePath: /ns/{nsId}/template/infra/{templateId} description: Delete a specific MCI Dynamic Template. DeleteMultipleDataObjectsLagacy: method: post @@ -1666,8 +1595,7 @@ serviceActions: DeleteObjectStorageCORSLagacy: method: delete resourcePath: /resources/objectStorage/{objectStorageName}/cors - description: (To be deprecated) Delete CORS configuration of an object storage - (bucket) + description: (To be deprecated) Delete CORS configuration of an object storage (bucket) DeleteObjectStorageLagacy: method: delete resourcePath: /resources/objectStorage/{objectStorageName} @@ -1699,8 +1627,7 @@ serviceActions: - **Data Cleanup**: Remove outdated or irrelevant provisioning history - - **Fresh Start**: Clear history after infrastructure changes that resolve - previous issues + - **Fresh Start**: Clear history after infrastructure changes that resolve previous issues - **Privacy Compliance**: Remove logs containing sensitive error information @@ -1721,8 +1648,7 @@ serviceActions: DeleteScheduleRegisterCspResources: method: delete resourcePath: /registerCspResources/schedule/{jobId} - description: 'Stop and permanently delete a scheduled CSP resource registration - job + description: 'Stop and permanently delete a scheduled CSP resource registration job **Warning:** This operation is irreversible! @@ -1742,8 +1668,7 @@ serviceActions: DeleteScheduleRegisterCspResourcesAll: method: delete resourcePath: /registerCspResources/schedule - description: '⚠️ **DANGER: This operation deletes ALL scheduled jobs in the - system!** + description: '⚠️ **DANGER: This operation deletes ALL scheduled jobs in the system!** **⚠️ CRITICAL WARNINGS:** @@ -1786,12 +1711,11 @@ serviceActions: description: Delete a specific SecurityGroup Template. DeleteSiteToSiteVpn: method: delete - resourcePath: /ns/{nsId}/mci/{mciId}/vpn/{vpnId} + resourcePath: /ns/{nsId}/infra/{mciId}/vpn/{vpnId} description: 'Delete a site-to-site VPN - - Note: A one-time retry is performed to handle transient failures caused - by CSP-internal timing issues between dependent resources. + - Note: A one-time retry is performed to handle transient failures caused by CSP-internal timing issues between dependent resources. ' DeleteSqlDb: @@ -1810,56 +1734,46 @@ serviceActions: **Note: ** - - If no version is specified, we will define how it behaves and update it - when necessary. + - If no version is specified, we will define how it behaves and update it when necessary. ' DeleteVersionedObjectLagacy: method: delete resourcePath: /resources/objectStorage/{objectStorageName}/versions/{objectKey} - description: (To be deprecated) Delete a specific version of an object in an - object storage (bucket) + description: (To be deprecated) Delete a specific version of an object in an object storage (bucket) DeleteVmCommandStatus: method: delete - resourcePath: /ns/{nsId}/mci/{mciId}/vm/{vmId}/commandStatus/{index} + resourcePath: /ns/{nsId}/infra/{mciId}/node/{vmId}/commandStatus/{index} description: Delete a specific command status record by index for a VM DeleteVmCommandStatusByCriteria: method: delete - resourcePath: /ns/{nsId}/mci/{mciId}/vm/{vmId}/commandStatus - description: Delete multiple command status records for a VM based on filtering - criteria + resourcePath: /ns/{nsId}/infra/{mciId}/node/{vmId}/commandStatus + description: Delete multiple command status records for a VM based on filtering criteria DeleteVmSshHostKey: method: delete - resourcePath: /ns/{nsId}/mci/{mciId}/vm/{vmId}/sshHostKey - description: Reset the stored SSH host key for a specific VM. This should be - used when the VM's host key has legitimately changed (e.g., after VM recreation) - and you trust the new key. The next SSH connection will store the new host - key (TOFU). + resourcePath: /ns/{nsId}/infra/{mciId}/node/{vmId}/sshHostKey + description: Reset the stored SSH host key for a specific VM. This should be used when the VM's host key has legitimately changed (e.g., after VM recreation) and you trust the new key. The next SSH connection will store the new host key (TOFU). DeregisterCustomImage: method: delete resourcePath: /ns/{nsId}/deregisterResource/customImage/{customImageId} - description: Deregister customImage from Spider and TB without deleting the - actual CSP resource + description: Deregister customImage from Spider and TB without deleting the actual CSP resource DeregisterDataDisk: method: delete resourcePath: /ns/{nsId}/deregisterResource/dataDisk/{dataDiskId} - description: Deregister Data Disk from Spider and TB without deleting the actual - CSP resource - DeregisterMciVm: + description: Deregister Data Disk from Spider and TB without deleting the actual CSP resource + DeregisterInfraNode: + method: delete - resourcePath: /ns/{nsId}/deregisterResource/mci/{mciId}/vm/{vmId} - description: Deregister VM from Spider and TB without deleting the actual CSP - resource + resourcePath: /ns/{nsId}/deregisterResource/infra/{mciId}/node/{vmId} + description: Deregister VM from Spider and TB without deleting the actual CSP resource DeregisterSecurityGroup: method: delete resourcePath: /ns/{nsId}/deregisterResource/securityGroup/{securityGroupId} - description: Deregister Security Group from Spider and TB without deleting the - actual CSP resource + description: Deregister Security Group from Spider and TB without deleting the actual CSP resource DeregisterSshKey: method: delete resourcePath: /ns/{nsId}/deregisterResource/sshKey/{sshKeyId} - description: Deregister SSH Key from Spider and TB without deleting the actual - CSP resource + description: Deregister SSH Key from Spider and TB without deleting the actual CSP resource ExistObjectStorageLagacy: method: head resourcePath: /resources/objectStorage/{objectStorageName} @@ -1872,18 +1786,14 @@ serviceActions: **Provider Selection Options:** - - `targetProviders`: Specify exact providers to fetch (e.g., ["aws", "gcp"]). - When set, only these providers are processed and `excludedProviders` is ignored. + - `targetProviders`: Specify exact providers to fetch (e.g., ["aws", "gcp"]). When set, only these providers are processed and `excludedProviders` is ignored. - - `excludedProviders`: Specify providers to skip (e.g., ["azure"]). Only used - when `targetProviders` is not set. + - `excludedProviders`: Specify providers to skip (e.g., ["azure"]). Only used when `targetProviders` is not set. - - `regionAgnosticProviders`: Providers where images are shared across regions - (e.g., ["gcp", "tencent"]). Only one region will be fetched per provider. + - `regionAgnosticProviders`: Providers where images are shared across regions (e.g., ["gcp", "tencent"]). Only one region will be fetched per provider. - **Note:** `regionAgnosticProviders` should only contain providers that are - also in `targetProviders` (or not excluded).' + **Note:** `regionAgnosticProviders` should only contain providers that are also in `targetProviders` (or not excluded).' FetchImagesAsync: method: post resourcePath: /fetchImagesAsync @@ -1892,23 +1802,18 @@ serviceActions: **Provider Selection Options:** - - `targetProviders`: Specify exact providers to fetch (e.g., ["aws", "gcp"]). - When set, only these providers are processed and `excludedProviders` is ignored. + - `targetProviders`: Specify exact providers to fetch (e.g., ["aws", "gcp"]). When set, only these providers are processed and `excludedProviders` is ignored. - - `excludedProviders`: Specify providers to skip (e.g., ["azure"]). Only used - when `targetProviders` is not set. + - `excludedProviders`: Specify providers to skip (e.g., ["azure"]). Only used when `targetProviders` is not set. - - `regionAgnosticProviders`: Providers where images are shared across regions - (e.g., ["gcp", "tencent"]). Only one region will be fetched per provider. + - `regionAgnosticProviders`: Providers where images are shared across regions (e.g., ["gcp", "tencent"]). Only one region will be fetched per provider. - **Note:** `regionAgnosticProviders` should only contain providers that are - also in `targetProviders` (or not excluded).' + **Note:** `regionAgnosticProviders` should only contain providers that are also in `targetProviders` (or not excluded).' FetchPrice: method: post resourcePath: /fetchPrice - description: Fetch price from all CSP connections and update the price information - for associated specs in the system. + description: Fetch price from all CSP connections and update the price information for associated specs in the system. FetchSpecs: method: post resourcePath: /fetchSpecs @@ -1917,23 +1822,18 @@ serviceActions: **Provider Selection Options:** - - `targetProviders`: Specify exact providers to fetch (e.g., ["aws", "gcp"]). - When set, only these providers are processed and `excludedProviders` is ignored. + - `targetProviders`: Specify exact providers to fetch (e.g., ["aws", "gcp"]). When set, only these providers are processed and `excludedProviders` is ignored. - - `excludedProviders`: Specify providers to skip (e.g., ["azure"]). Only used - when `targetProviders` is not set. + - `excludedProviders`: Specify providers to skip (e.g., ["azure"]). Only used when `targetProviders` is not set. - - `regionAgnosticProviders`: Providers where specs are shared across regions - (e.g., ["gcp", "tencent"]). Only one region will be fetched per provider. + - `regionAgnosticProviders`: Providers where specs are shared across regions (e.g., ["gcp", "tencent"]). Only one region will be fetched per provider. - **Note:** `regionAgnosticProviders` should only contain providers that are - also in `targetProviders` (or not excluded).' + **Note:** `regionAgnosticProviders` should only contain providers that are also in `targetProviders` (or not excluded).' FilterSpecsByRange: method: post resourcePath: /ns/{nsId}/resources/filterSpecsByRange - description: Filter specs by range. Use limit field to control the maximum number - of results. If limit is 0 or not specified, returns all matching results. + description: Filter specs by range. Use limit field to control the maximum number of results. If limit is 0 or not specified, returns all matching results. ForwardAnyReqToAny: method: post resourcePath: /forward/{path} @@ -1941,19 +1841,16 @@ serviceActions: GeneratePresignedDownloadURLLagacy: method: get resourcePath: /resources/objectStorage/presigned/download/{objectStorageName}/{objectKey} - description: '(To be deprecated) Generate a presigned URL for downloading an - object from a bucket + description: '(To be deprecated) Generate a presigned URL for downloading an object from a bucket **Important Notes:** - The actual response will be XML format with root element `PresignedURLResult` - - The `expires` query parameter specifies the expiration time in seconds for - the presigned URL (default: 3600 seconds) + - The `expires` query parameter specifies the expiration time in seconds for the presigned URL (default: 3600 seconds) - - The generated presigned URL can be used to download the object directly - without further authentication + - The generated presigned URL can be used to download the object directly without further authentication **Actual XML Response Example:** @@ -1974,16 +1871,14 @@ serviceActions: ```' GeneratePresignedURL: - method: get - resourcePath: /ns/{nsId}/resources/objectStorage/{osId}/object/{objectKey} - description: 'Generate a presigned URL for uploading or downloading an object - to an object storage (bucket) + method: post + resourcePath: /ns/{nsId}/resources/objectStorage/{osId}/object/{objectKey}/presignedUrl + description: 'Generate a presigned URL for uploading or downloading an object to an object storage (bucket) **Important Notes:** - - The generated presigned URL can be used to upload the object directly without - further authentication + - The generated presigned URL can be used to upload the object directly without further authentication - The expiration time is specified in seconds (default: 3600 seconds) @@ -1994,8 +1889,7 @@ serviceActions: # Using the presigned URL to upload a file - curl -i -H "Content-Type: text/plain" -X PUT "" --data-binary - "@local-file.txt" + curl -i -H "Content-Type: text/plain" -X PUT "" --data-binary "@local-file.txt" ``` @@ -2012,19 +1906,16 @@ serviceActions: GeneratePresignedUploadURLLagacy: method: get resourcePath: /resources/objectStorage/presigned/upload/{objectStorageName}/{objectKey} - description: '(To be deprecated) Generate a presigned URL for uploading an object - to a bucket + description: '(To be deprecated) Generate a presigned URL for uploading an object to a bucket **Important Notes:** - The actual response will be XML format with root element `PresignedURLResult` - - The `expires` query parameter specifies the expiration time in seconds for - the presigned URL (default: 3600 seconds) + - The `expires` query parameter specifies the expiration time in seconds for the presigned URL (default: 3600 seconds) - - The generated presigned URL can be used to upload the object directly without - further authentication + - The generated presigned URL can be used to upload the object directly without further authentication **Actual XML Response Example:** @@ -2046,7 +1937,7 @@ serviceActions: ```' GetAllBenchmark: method: post - resourcePath: /ns/{nsId}/benchmarkAll/mci/{mciId} + resourcePath: /ns/{nsId}/benchmarkAll/infra/{mciId} description: Run MCI benchmark for all performance metrics and return results GetAllConfig: method: get @@ -2068,24 +1959,26 @@ serviceActions: method: get resourcePath: /ns/{nsId}/k8sCluster description: List all K8sClusters or K8sClusters' ID - GetAllMci: + GetAllInfra: + method: get - resourcePath: /ns/{nsId}/mci + resourcePath: /ns/{nsId}/infra description: List all MCIs or MCIs' ID - GetAllMciDynamicTemplate: + GetAllInfraDynamicTemplate: + method: get - resourcePath: /ns/{nsId}/template/mci + resourcePath: /ns/{nsId}/template/infra description: 'List all MCI Dynamic Templates in a namespace. - Optionally filter by keyword matching against template name or description - (case-insensitive).' - GetAllMciPolicy: + Optionally filter by keyword matching against template name or description (case-insensitive).' + GetAllInfraPolicy: + method: get - resourcePath: /ns/{nsId}/policy/mci + resourcePath: /ns/{nsId}/policy/infra description: List all MCI policies GetAllNLB: method: get - resourcePath: /ns/{nsId}/mci/{mciId}/nlb + resourcePath: /ns/{nsId}/infra/{mciId}/nlb description: List all NLBs or NLBs' ID GetAllNs: method: get @@ -2104,11 +1997,10 @@ serviceActions: resourcePath: /ns/{nsId}/template/securityGroup description: 'List all SecurityGroup Templates in a namespace. - Optionally filter by keyword matching against template name or description - (case-insensitive).' + Optionally filter by keyword matching against template name or description (case-insensitive).' GetAllSiteToSiteVpn: method: get - resourcePath: /ns/{nsId}/mci/{mciId}/vpn + resourcePath: /ns/{nsId}/infra/{mciId}/vpn description: Get all site-to-site VPNs GetAllSqlDb: method: get @@ -2131,8 +2023,7 @@ serviceActions: resourcePath: /ns/{nsId}/template/vNet description: 'List all vNet Templates in a namespace. - Optionally filter by keyword matching against template name or description - (case-insensitive).' + Optionally filter by keyword matching against template name or description (case-insensitive).' GetAvailableK8sNodeImage: method: get resourcePath: /availableK8sNodeImage @@ -2148,37 +2039,32 @@ serviceActions: GetAvailableRegionZonesForSpecList: method: post resourcePath: /availableRegionZonesForSpecList - description: Query the availability for multiple specs in parallel and return - batch results + description: Query the availability for multiple specs in parallel and return batch results GetAvailableZonesForSpec: method: get resourcePath: /availableZonesForSpec - description: Query verified zones for a spec based on connection configs. Returns - zones that are both verified and available for the specified spec. For Alibaba - Cloud, additional CSP API filtering is applied. + description: Query verified zones for a spec based on connection configs. Returns zones that are both verified and available for the specified spec. For Alibaba Cloud, additional CSP API filtering is applied. GetBastionNodes: method: get - resourcePath: /ns/{nsId}/mci/{mciId}/vm/{targetVmId}/bastion + resourcePath: /ns/{nsId}/infra/{mciId}/node/{targetVmId}/bastion description: Get bastion nodes for a VM GetBenchmark: method: post - resourcePath: /ns/{nsId}/benchmark/mci/{mciId} + resourcePath: /ns/{nsId}/benchmark/infra/{mciId} description: Run MCI benchmark for a single performance metric and return results GetCloudInfo: method: get resourcePath: /cloudInfo description: Get cloud information - GetCmdMciStream: + GetCmdInfraStream: + method: get - resourcePath: /ns/{nsId}/stream/cmd/mci/{mciId} - description: 'Subscribe to Server-Sent Events (SSE) for real-time command execution - logs. + resourcePath: /ns/{nsId}/stream/cmd/infra/{mciId} + description: 'Subscribe to Server-Sent Events (SSE) for real-time command execution logs. - Use the xRequestId returned from POST /ns/{nsId}/cmd/mci/{mciId}?async=true - to connect. + Use the xRequestId returned from POST /ns/{nsId}/cmd/mci/{mciId}?async=true to connect. - Events: CommandStatus (status transitions), CommandLog (stdout/stderr lines), - CommandDone (terminal).' + Events: CommandStatus (status transitions), CommandLog (stdout/stderr lines), CommandDone (terminal).' GetConfig: method: get resourcePath: /config/{configId} @@ -2191,18 +2077,23 @@ serviceActions: method: get resourcePath: /connConfig description: List all registered ConnConfig + FilterConnConfigByCredentialHolder: + method: get + resourcePath: /connConfig + description: Filter connection configs by credential holder name (queryParams.filterCredentialHolder) GetControlK8sCluster: method: get resourcePath: /ns/{nsId}/control/k8sCluster/{k8sClusterId} description: Control the creation of K8sCluster (continue, withdraw) - GetControlMci: + GetControlInfra: + method: get - resourcePath: /ns/{nsId}/control/mci/{mciId} - description: Control the lifecycle of MCI (refine, suspend, resume, reboot, - terminate) - GetControlMciVm: + resourcePath: /ns/{nsId}/control/infra/{mciId} + description: Control the lifecycle of MCI (refine, suspend, resume, reboot, terminate) + GetControlInfraNode: + method: get - resourcePath: /ns/{nsId}/control/mci/{mciId}/vm/{vmId} + resourcePath: /ns/{nsId}/control/infra/{mciId}/node/{vmId} description: Control the lifecycle of VM (suspend, resume, reboot, terminate) GetCredentialHolder: method: get @@ -2211,11 +2102,9 @@ serviceActions: GetCredentialHolderList: method: get resourcePath: /credentialHolder - description: 'List all credential holders derived from registered connection - configs. + description: 'List all credential holders derived from registered connection configs. - Each holder includes associated providers, connection counts, and verification - status.' + Each holder includes associated providers, connection counts, and verification status.' GetCustomImage: method: get resourcePath: /ns/{nsId}/resources/customImage/{customImageId} @@ -2232,11 +2121,9 @@ serviceActions: **Important Notes:** - - This API retrieves the metadata of an object without downloading the actual - content + - This API retrieves the metadata of an object without downloading the actual content - - Returns metadata in response headers (Content-Length, Content-Type, ETag, - Last-Modified)' + - Returns metadata in response headers (Content-Length, Content-Type, ETag, Last-Modified)' GetDataObjectInfoLagacy: method: head resourcePath: /resources/objectStorage/{objectStorageName}/{objectKey} @@ -2245,11 +2132,10 @@ serviceActions: **Important Notes:** - - The generated `Download file` link in Swagger UI may not work because this - API get the object metadata only.' + - The generated `Download file` link in Swagger UI may not work because this API get the object metadata only.' GetExecutionTask: method: get - resourcePath: /ns/{nsId}/cmd/mci/{mciId}/task/{taskId} + resourcePath: /ns/{nsId}/cmd/infra/{mciId}/task/{taskId} description: Get detailed information about a specific execution task by taskId GetFetchImagesAsyncResult: method: get @@ -2258,8 +2144,7 @@ serviceActions: GetGlobalDnsRecord: method: get resourcePath: /resources/globalDns/record - description: Get DNS records for a domain from Route53. Includes routing policy - and geoproximity info. + description: Get DNS records for a domain from Route53. Includes routing policy and geoproximity info. GetHostedZones: method: get resourcePath: /resources/globalDns/hostedZone @@ -2267,8 +2152,7 @@ serviceActions: GetImage: method: get resourcePath: /ns/{nsId}/resources/image/{imageId} - description: GetImage returns an image object if there are matched images for - the given namespace and imageKey(imageId) + description: GetImage returns an image object if there are matched images for the given namespace and imageKey(imageId) GetK8sCluster: method: get resourcePath: /ns/{nsId}/k8sCluster/{k8sClusterId} @@ -2282,86 +2166,87 @@ serviceActions: resourcePath: /ns/{nsId}/k8sCluster/{k8sClusterId}/token description: 'Get an access token for the specified K8sCluster. - Only applicable to CSPs that use exec-based authentication (e.g., GCP GKE, - AWS EKS).' + Only applicable to CSPs that use exec-based authentication (e.g., GCP GKE, AWS EKS).' GetLabels: method: get resourcePath: /label/{labelType}/{uid} description: Get labels for a resource identified by its uid GetLatencyBenchmark: method: get - resourcePath: /ns/{nsId}/benchmarkLatency/mci/{mciId} + resourcePath: /ns/{nsId}/benchmarkLatency/infra/{mciId} description: Run MCI benchmark for network latency - GetMci: + GetInfra: + method: get - resourcePath: /ns/{nsId}/mci/{mciId} + resourcePath: /ns/{nsId}/infra/{mciId} description: 'Get MCI object (option: status, accessInfo, vmId)' - GetMciAssociatedResources: + GetInfraAssociatedResources: + method: get - resourcePath: /ns/{nsId}/mci/{mciId}/associatedResources - description: Get associated resource ID list for a given MCI (VNet, Subnet, - SecurityGroup, SSHKey, etc.) - GetMciDynamicTemplate: + resourcePath: /ns/{nsId}/infra/{mciId}/associatedResources + description: Get associated resource ID list for a given MCI (VNet, Subnet, SecurityGroup, SSHKey, etc.) + GetInfraDynamicTemplate: + method: get - resourcePath: /ns/{nsId}/template/mci/{templateId} + resourcePath: /ns/{nsId}/template/infra/{templateId} description: Retrieve a specific MCI Dynamic Template by ID. - GetMciExecutionTasks: + GetInfraExecutionTasks: + method: get - resourcePath: /ns/{nsId}/cmd/mci/{mciId}/task - description: List all running and completed execution tasks for a specific MCI. - These tasks can be cancelled if still in progress. The task list is based - on persistent VM command status records. - GetMciGroupIds: + resourcePath: /ns/{nsId}/cmd/infra/{mciId}/task + description: List all running and completed execution tasks for a specific MCI. These tasks can be cancelled if still in progress. The task list is based on persistent VM command status records. + GetInfraGroupIds: + method: get - resourcePath: /ns/{nsId}/mci/{mciId}/subgroup + resourcePath: /ns/{nsId}/infra/{mciId}/nodegroup description: List SubGroup IDs in a specified MCI - GetMciGroupVms: + GetInfraGroupNodes: + method: get - resourcePath: /ns/{nsId}/mci/{mciId}/subgroup/{subgroupId} + resourcePath: /ns/{nsId}/infra/{mciId}/nodegroup/{subgroupId} description: List VMs with a SubGroup label in a specified MCI - GetMciHandlingCommandCount: + GetInfraHandlingCommandCount: + method: get - resourcePath: /ns/{nsId}/mci/{mciId}/handlingCount - description: Get the number of commands currently in 'Handling' status for all - VMs in an MCI. Returns per-VM counts and total count. - GetMciPolicy: + resourcePath: /ns/{nsId}/infra/{mciId}/handlingCount + description: Get the number of commands currently in 'Handling' status for all VMs in an MCI. Returns per-VM counts and total count. + GetInfraPolicy: + method: get - resourcePath: /ns/{nsId}/policy/mci/{mciId} + resourcePath: /ns/{nsId}/policy/infra/{mciId} description: Get MCI Policy - GetMciReqFromMci: + GetInfraReqFromInfra: + method: get - resourcePath: /ns/{nsId}/mci/{mciId}/configCopy - description: 'Reconstruct an MCI dynamic creation request body from an existing - MCI''s information. + resourcePath: /ns/{nsId}/infra/{mciId}/configCopy + description: 'Reconstruct an MCI dynamic creation request body from an existing MCI''s information. - Returns a dynamic request format where networking resources (vNet, subnet, - SG, sshKey) + Returns a dynamic request format where networking resources (vNet, subnet, SG, sshKey) are auto-created, making it easy to clone or recreate a similar MCI configuration. **Template Option:** - When the `template` query parameter is provided, the extracted configuration - is + When the `template` query parameter is provided, the extracted configuration is saved as a reusable MCI Dynamic Template with the given name.' - GetMciVm: + GetInfraNode: + method: get - resourcePath: /ns/{nsId}/mci/{mciId}/vm/{vmId} + resourcePath: /ns/{nsId}/infra/{mciId}/node/{vmId} description: Get VM in specified MCI GetMonitorData: method: get - resourcePath: /ns/{nsId}/monitoring/mci/{mciId}/metric/{metric} - description: Get monitoring data of specified MCI for specified monitoring metric - (cpu, memory, disk, network) + resourcePath: /ns/{nsId}/monitoring/infra/{mciId}/metric/{metric} + description: Get monitoring data of specified MCI for specified monitoring metric (cpu, memory, disk, network) GetNLB: method: get - resourcePath: /ns/{nsId}/mci/{mciId}/nlb/{nlbId} + resourcePath: /ns/{nsId}/infra/{mciId}/nlb/{nlbId} description: Get NLB GetNLBHealth: method: get - resourcePath: /ns/{nsId}/mci/{mciId}/nlb/{nlbId}/healthz + resourcePath: /ns/{nsId}/infra/{mciId}/nlb/{nlbId}/healthz description: Get NLB Health GetNs: method: get @@ -2382,8 +2267,7 @@ serviceActions: GetObjectStorageCORSLagacy: method: get resourcePath: /resources/objectStorage/{objectStorageName}/cors - description: '(To be deprecated) Get CORS configuration of an object storage - (bucket) + description: '(To be deprecated) Get CORS configuration of an object storage (bucket) **Important Notes:** @@ -2508,11 +2392,9 @@ serviceActions: GetObjectStorageSupport: method: get resourcePath: /objectStorage/support - description: 'Get CSP support information for object storage features (CORS, - Versioning) + description: 'Get CSP support information for object storage features (CORS, Versioning) - If cspType query parameter is provided, returns support information for that - specific CSP + If cspType query parameter is provided, returns support information for that specific CSP If cspType is not provided, returns support information for all CSPs' GetObjectStorageVersioning: @@ -2522,8 +2404,7 @@ serviceActions: GetObjectStorageVersioningLagacy: method: get resourcePath: /resources/objectStorage/{objectStorageName}/versioning - description: '(To be deprecated) Get versioning status of an object storage - (bucket) + description: '(To be deprecated) Get versioning status of an object storage (bucket) **Important Notes:** @@ -2555,8 +2436,7 @@ serviceActions: GetProvisioningLog: method: get resourcePath: /provisioning/log/{specId} - description: 'Retrieve detailed provisioning history for a specific VM specification - including success/failure patterns and risk analysis. + description: 'Retrieve detailed provisioning history for a specific VM specification including success/failure patterns and risk analysis. This endpoint provides comprehensive insights into provisioning reliability: @@ -2576,13 +2456,11 @@ serviceActions: **Use Cases:** - - **Pre-deployment Risk Assessment**: Check if a spec has historical failures - before creating MCI + - **Pre-deployment Risk Assessment**: Check if a spec has historical failures before creating MCI - **Troubleshooting**: Analyze failure patterns to identify root causes - - **Capacity Planning**: Understand reliability patterns for different specs - and regions + - **Capacity Planning**: Understand reliability patterns for different specs and regions - **Cost Optimization**: Avoid specs with high failure rates that waste resources @@ -2603,15 +2481,11 @@ serviceActions: GetPublicKeyForCredentialEncryption: method: get resourcePath: /credential/publicKey - description: Generates an RSA key pair using a 4096-bit key size with the RSA - algorithm. The public key is generated using the RSA algorithm with OAEP padding - and SHA-256 as the hash function. This key is used to encrypt an AES key that - will be used for hybrid encryption of credentials. + description: Generates an RSA key pair using a 4096-bit key size with the RSA algorithm. The public key is generated using the RSA algorithm with OAEP padding and SHA-256 as the hash function. This key is used to encrypt an AES key that will be used for hybrid encryption of credentials. GetReadyz: method: get resourcePath: /readyz - description: Check Tumblebug is ready. Returns ready status and initialization - status. + description: Check Tumblebug is ready. Returns ready status and initialization status. GetRegion: method: get resourcePath: /provider/{providerName}/region/{regionName} @@ -2626,7 +2500,7 @@ serviceActions: description: Get details of a specific request GetRequestStatusOfSiteToSiteVpn: method: get - resourcePath: /ns/{nsId}/mci/{mciId}/vpn/{vpnId}/request/{requestId} + resourcePath: /ns/{nsId}/infra/{mciId}/vpn/{vpnId}/request/{requestId} description: Check the status of a specific request by its ID GetRequiredK8sSubnetCount: method: get @@ -2635,35 +2509,27 @@ serviceActions: GetResourcesByLabelSelector: method: get resourcePath: /resources/{labelType} - description: 'Get resources based on a label selector. The label selector supports - the following operators: + description: 'Get resources based on a label selector. The label selector supports the following operators: - - `=` : Selects resources where the label key equals the specified value (e.g., - `env=production`). + - `=` : Selects resources where the label key equals the specified value (e.g., `env=production`). - - `!=` : Selects resources where the label key does not equal the specified - value (e.g., `tier!=frontend`). + - `!=` : Selects resources where the label key does not equal the specified value (e.g., `tier!=frontend`). - - `in` : Selects resources where the label key is in the specified set of - values (e.g., `region in (us-west, us-east)`). + - `in` : Selects resources where the label key is in the specified set of values (e.g., `region in (us-west, us-east)`). - - `notin` : Selects resources where the label key is not in the specified - set of values (e.g., `env notin (production, staging)`). + - `notin` : Selects resources where the label key is not in the specified set of values (e.g., `env notin (production, staging)`). - `exists` : Selects resources where the label key exists (e.g., `env exists`). - - `!exists` : Selects resources where the label key does not exist (e.g., - `env !exists`).' + - `!exists` : Selects resources where the label key does not exist (e.g., `env !exists`).' GetScheduleRegisterCspResourcesList: method: get resourcePath: /registerCspResources/schedule - description: Get a list of all scheduled CSP resource registration jobs (jobs - are not scoped to namespaces) + description: Get a list of all scheduled CSP resource registration jobs (jobs are not scoped to namespaces) GetScheduleRegisterCspResourcesStatus: method: get resourcePath: /registerCspResources/schedule/{jobId} - description: 'Get the current status of a specific scheduled CSP resource registration - job + description: 'Get the current status of a specific scheduled CSP resource registration job **Response Fields Explanation:** @@ -2708,11 +2574,12 @@ serviceActions: description: Retrieve a specific SecurityGroup Template by ID. GetSiteToSiteVpn: method: get - resourcePath: /ns/{nsId}/mci/{mciId}/vpn/{vpnId} + resourcePath: /ns/{nsId}/infra/{mciId}/vpn/{vpnId} description: Get resource info of a site-to-site VPN - GetSitesInMci: + GetSitesInInfra: + method: get - resourcePath: /ns/{nsId}/mci/{mciId}/site + resourcePath: /ns/{nsId}/infra/{mciId}/site description: Get sites in MCI GetSpec: method: get @@ -2744,22 +2611,20 @@ serviceActions: description: Retrieve a specific vNet Template by ID. GetVmCommandStatus: method: get - resourcePath: /ns/{nsId}/mci/{mciId}/vm/{vmId}/commandStatus/{index} + resourcePath: /ns/{nsId}/infra/{mciId}/node/{vmId}/commandStatus/{index} description: Get a specific command status record by index for a VM GetVmDataDisk: method: get - resourcePath: /ns/{nsId}/mci/{mciId}/vm/{vmId}/dataDisk + resourcePath: /ns/{nsId}/infra/{mciId}/node/{vmId}/dataDisk description: Get available dataDisks for a VM GetVmHandlingCommandCount: method: get - resourcePath: /ns/{nsId}/mci/{mciId}/vm/{vmId}/handlingCount - description: Get the number of commands currently in 'Handling' status for a - specific VM. Optimized for frequent polling. + resourcePath: /ns/{nsId}/infra/{mciId}/node/{vmId}/handlingCount + description: Get the number of commands currently in 'Handling' status for a specific VM. Optimized for frequent polling. GetVmSshHostKey: method: get - resourcePath: /ns/{nsId}/mci/{mciId}/vm/{vmId}/sshHostKey - description: Get the stored SSH host key information for a specific VM. This - is used for TOFU (Trust On First Use) verification. + resourcePath: /ns/{nsId}/infra/{mciId}/node/{vmId}/sshHostKey + description: Get the stored SSH host key information for a specific VM. This is used for TOFU (Trust On First Use) verification. InitAllConfig: method: delete resourcePath: /config @@ -2771,13 +2636,11 @@ serviceActions: InspectResources: method: post resourcePath: /inspectResources - description: Inspect Resources (vNet, securityGroup, sshKey, vm) registered - in CB-Tumblebug, CB-Spider, CSP + description: Inspect Resources (vNet, securityGroup, sshKey, vm) registered in CB-Tumblebug, CB-Spider, CSP InspectResourcesOverview: method: get resourcePath: /inspectResourcesOverview - description: Inspect Resources Overview (vNet, securityGroup, sshKey, vm) registered - in CB-Tumblebug and CSP for all connections + description: Inspect Resources Overview (vNet, securityGroup, sshKey, vm) registered in CB-Tumblebug and CSP for all connections ListDataObjects: method: get resourcePath: /ns/{nsId}/resources/objectStorage/{osId}/object @@ -2894,7 +2757,7 @@ serviceActions: ```' ListVmCommandStatus: method: get - resourcePath: /ns/{nsId}/mci/{mciId}/vm/{vmId}/commandStatus + resourcePath: /ns/{nsId}/infra/{mciId}/node/{vmId}/commandStatus description: List command status records for a VM with various filtering options GetAssetsSummary: method: get @@ -2905,9 +2768,7 @@ serviceActions: LoadAssets: method: get resourcePath: /loadAssets - description: Load Common Resources from internal asset files (Spec, Image). - By default, Azure images are excluded for faster initialization. Use includeAzure=true - to fetch Azure images (may take 40+ minutes). + description: Load Common Resources from internal asset files (Spec, Image). By default, Azure images are excluded for faster initialization. Use includeAzure=true to fetch Azure images (may take 40+ minutes). LookupImage: method: post resourcePath: /lookupImage @@ -2931,9 +2792,7 @@ serviceActions: PostBuildAgnosticImage: method: post resourcePath: /ns/{nsId}/buildAgnosticImage - description: Creates an MCI infrastructure, executes post-deployment commands, - creates snapshots from each subgroup, and optionally cleans up the MCI. This - is a complete workflow for building CSP-agnostic custom images. + description: Creates an MCI infrastructure, executes post-deployment commands, creates snapshots from each subgroup, and optionally cleans up the MCI. This is a complete workflow for building CSP-agnostic custom images. PostCmdK8sCluster: method: post resourcePath: /ns/{nsId}/cmd/k8sCluster/{k8sClusterId} @@ -2941,24 +2800,20 @@ serviceActions: [note] This feature is not intended for general use - This API is provided as an exceptional and limited function for specific purposes - such as migration. + This API is provided as an exceptional and limited function for specific purposes such as migration. + + Kubernetes resource information required as input for this API is not currently provided, and its availability in the future is uncertain.' + PostCmdInfra: - Kubernetes resource information required as input for this API is not currently - provided, and its availability in the future is uncertain.' - PostCmdMci: method: post - resourcePath: /ns/{nsId}/cmd/mci/{mciId} - description: 'Send a command to specified MCI. Use query parameters to target - specific subGroup or VM. + resourcePath: /ns/{nsId}/cmd/infra/{mciId} + description: 'Send a command to specified MCI. Use query parameters to target specific subGroup or VM. - When async=true, returns immediately with xRequestId and streams results via - SSE at GET /stream/ns/{nsId}/cmd/mci/{mciId}?xRequestId={xRequestId}' + When async=true, returns immediately with xRequestId and streams results via SSE at GET /stream/ns/{nsId}/cmd/mci/{mciId}?xRequestId={xRequestId}' PostConfig: method: post resourcePath: /config - description: Create or Update config (TB_SPIDER_REST_URL, TB_DRAGONFLY_REST_URL, - ...) + description: Create or Update config (TB_SPIDER_REST_URL, TB_DRAGONFLY_REST_URL, ...) PostCustomImage: method: post resourcePath: /ns/{nsId}/resources/customImage @@ -2967,51 +2822,45 @@ serviceActions: method: post resourcePath: /ns/{nsId}/resources/dataDisk description: Create Data Disk - PostDownloadFileFromMciVm: + PostDownloadFileFromInfraNode: + method: post - resourcePath: /ns/{nsId}/downloadFile/mci/{mciId}/vm/{vmId} - description: 'Download a file from a specific VM in MCI via SCP through bastion - host. + resourcePath: /ns/{nsId}/downloadFile/infra/{mciId}/node/{vmId} + description: 'Download a file from a specific VM in MCI via SCP through bastion host. The file size should be less than 200MB.' PostFileToK8sCluster: method: post resourcePath: /ns/{nsId}/transferFile/k8sCluster/{k8sClusterId} - description: 'Transfer a file to specified Container in K8sCluster. The tar - command is required in the container. + description: 'Transfer a file to specified Container in K8sCluster. The tar command is required in the container. [note] This feature is not intended for general use - This API is provided as an exceptional and limited function for specific purposes - such as migration. + This API is provided as an exceptional and limited function for specific purposes such as migration. + + Kubernetes resource information required as input for this API is not currently provided, and its availability in the future is uncertain.' + PostFileToInfra: - Kubernetes resource information required as input for this API is not currently - provided, and its availability in the future is uncertain.' - PostFileToMci: method: post - resourcePath: /ns/{nsId}/transferFile/mci/{mciId} + resourcePath: /ns/{nsId}/transferFile/infra/{mciId} description: 'Transfer a file to specified MCI to the specified path. The file size should be less than 10MB. - Not for gerneral file transfer but for specific purpose (small configuration - files).' + Not for gerneral file transfer but for specific purpose (small configuration files).' PostFirewallRules: method: post resourcePath: /ns/{nsId}/resources/securityGroup/{securityGroupId}/rules - description: 'Add new FirewallRules: Add the provided firewall rules to the - existing rules in the Security Group. + description: 'Add new FirewallRules: Add the provided firewall rules to the existing rules in the Security Group. This API will only add new rules without deleting or modifying existing ones. - If a rule with identical properties already exists, it will be skipped to - avoid duplicates. + If a rule with identical properties already exists, it will be skipped to avoid duplicates. Usage: - Use this API to add new firewall rules to a Security Group while preserving - existing rules. + Use this API to add new firewall rules to a Security Group while preserving existing rules. - Only new rules that don''t already exist will be added. @@ -3022,8 +2871,7 @@ serviceActions: Notes: - - "Ports" field supports single port ("22"), port range ("80-100"), and multiple - ports/ranges ("22,80-100,443"). + - "Ports" field supports single port ("22"), port range ("80-100"), and multiple ports/ranges ("22,80-100,443"). - The valid port number range is 0 to 65535 (inclusive). @@ -3036,13 +2884,15 @@ serviceActions: method: post resourcePath: /ns/{nsId}/resources/image description: Register image - PostInstallBenchmarkAgentToMci: + PostInstallBenchmarkAgentToInfra: + method: post - resourcePath: /ns/{nsId}/installBenchmarkAgent/mci/{mciId} + resourcePath: /ns/{nsId}/installBenchmarkAgent/infra/{mciId} description: Install the benchmark agent to specified MCI - PostInstallMonitorAgentToMci: + PostInstallMonitorAgentToInfra: + method: post - resourcePath: /ns/{nsId}/monitoring/install/mci/{mciId} + resourcePath: /ns/{nsId}/monitoring/install/infra/{mciId} description: Install monitoring agent (CB-Dragonfly agent) to MCI PostK8sCluster: method: post @@ -3055,8 +2905,7 @@ serviceActions: PostK8sClusterDynamicCheckRequest: method: post resourcePath: /k8sClusterDynamicCheckRequest - description: Check available ConnectionConfig list before create K8sCluster - Dynamically from common spec and image + description: Check available ConnectionConfig list before create K8sCluster Dynamically from common spec and image PostK8sMultiClusterDynamic: method: post resourcePath: /ns/{nsId}/k8sMultiClusterDynamic @@ -3064,8 +2913,7 @@ serviceActions: Create multiple K8sClusters in parallel from common spec and image. - If namePrefix is provided, cluster names will be auto-generated as ''{namePrefix}-{csp}-{number}'' - (e.g., ''across-aws-1'', ''across-alibaba-2''). + If namePrefix is provided, cluster names will be auto-generated as ''{namePrefix}-{csp}-{number}'' (e.g., ''across-aws-1'', ''across-alibaba-2''). If namePrefix is not provided, each cluster must have a name specified. @@ -3124,27 +2972,23 @@ serviceActions: description: Create K8sNodeGroup Dynamically from common spec and image PostMcNLB: method: post - resourcePath: /ns/{nsId}/mci/{mciId}/mcSwNlb - description: Create a special purpose MCI for NLB and depoly and setting SW - NLB - PostMci: + resourcePath: /ns/{nsId}/infra/{mciId}/mcSwNlb + description: Create a special purpose MCI for NLB and depoly and setting SW NLB + PostInfra: + method: post - resourcePath: /ns/{nsId}/mci + resourcePath: /ns/{nsId}/infra description: 'Create MCI with detailed VM specifications and resource configuration. This endpoint creates a complete multi-cloud infrastructure by: - 1. **VM Provisioning**: Creates VMs across multiple cloud providers using - predefined specs and images + 1. **VM Provisioning**: Creates VMs across multiple cloud providers using predefined specs and images - 2. **Resource Management**: Automatically handles VPC/VNet, security groups, - SSH keys, and network configuration + 2. **Resource Management**: Automatically handles VPC/VNet, security groups, SSH keys, and network configuration - 3. **Status Tracking**: Monitors VM creation progress and handles failures - based on policy settings + 3. **Status Tracking**: Monitors VM creation progress and handles failures based on policy settings - 4. **Post-Deployment**: Optionally installs monitoring agents and executes - custom commands + 4. **Post-Deployment**: Optionally installs monitoring agents and executes custom commands **Key Features:** @@ -3189,50 +3033,39 @@ serviceActions: - Sufficient CSP quotas and permissions - Network connectivity between components' - PostMciDynamic: + PostInfraDynamic: + method: post - resourcePath: /ns/{nsId}/mciDynamic - description: 'Create multi-cloud infrastructure dynamically using common specifications - and images with automatic resource discovery and optimization. + resourcePath: /ns/{nsId}/infraDynamic + description: 'Create multi-cloud infrastructure dynamically using common specifications and images with automatic resource discovery and optimization. - This is the **recommended approach** for MCI creation, providing simplified - configuration with powerful automation: + This is the **recommended approach** for MCI creation, providing simplified configuration with powerful automation: **Dynamic Resource Creation:** - 1. **Automatic Resource Discovery**: Validates and selects optimal VM specifications - and images from common namespace + 1. **Automatic Resource Discovery**: Validates and selects optimal VM specifications and images from common namespace - 2. **Intelligent Network Setup**: Creates VNets, subnets, security groups, - and SSH keys automatically per provider + 2. **Intelligent Network Setup**: Creates VNets, subnets, security groups, and SSH keys automatically per provider - 3. **Cross-Cloud Orchestration**: Coordinates VM provisioning across multiple - cloud providers simultaneously + 3. **Cross-Cloud Orchestration**: Coordinates VM provisioning across multiple cloud providers simultaneously - 4. **Dependency Management**: Handles resource creation order and inter-dependencies - automatically + 4. **Dependency Management**: Handles resource creation order and inter-dependencies automatically - 5. **Failure Recovery**: Implements configurable failure policies for robust - deployment + 5. **Failure Recovery**: Implements configurable failure policies for robust deployment **Key Advantages Over Static MCI:** - - **Simplified Configuration**: Use common spec/image IDs instead of provider-specific - resources + - **Simplified Configuration**: Use common spec/image IDs instead of provider-specific resources - - **Automatic Resource Management**: No need to pre-create VNets, security - groups, or SSH keys + - **Automatic Resource Management**: No need to pre-create VNets, security groups, or SSH keys - - **Multi-Cloud Optimization**: Intelligent placement and configuration across - providers + - **Multi-Cloud Optimization**: Intelligent placement and configuration across providers - - **Built-in Best Practices**: Security groups, network isolation, and access - controls applied automatically + - **Built-in Best Practices**: Security groups, network isolation, and access controls applied automatically - - **Scalable Architecture**: Supports large-scale deployments with optimized - resource utilization + - **Scalable Architecture**: Supports large-scale deployments with optimized resource utilization **Configuration Process:** @@ -3241,25 +3074,20 @@ serviceActions: 2. **Image Selection**: Use system namespace to discover compatible images - 3. **Request Validation**: Use `/mciDynamicCheckRequest` to validate configuration - before deployment + 3. **Request Validation**: Use `/mciDynamicCheckRequest` to validate configuration before deployment - 4. **Optional Preview**: Use `/mciDynamicReview` to estimate costs and review - configuration + 4. **Optional Preview**: Use `/mciDynamicReview` to estimate costs and review configuration - 5. **Deployment**: Submit MCI dynamic request with failure policy and deployment - options + 5. **Deployment**: Submit MCI dynamic request with failure policy and deployment options **Failure Policies (PolicyOnPartialFailure):** - - **`continue`** (default): Create MCI with successful VMs, failed VMs remain - for manual refinement + - **`continue`** (default): Create MCI with successful VMs, failed VMs remain for manual refinement - **`rollback`**: Delete entire MCI if any VM fails (all-or-nothing deployment) - - **`refine`**: Automatically clean up failed VMs, keep successful ones (recommended - for large deployments) + - **`refine`**: Automatically clean up failed VMs, keep successful ones (recommended for large deployments) **Deployment Options:** @@ -3340,49 +3168,38 @@ serviceActions: - Real-time status tracking and progress updates - Automatic resource labeling and metadata management' - PostMciDynamicCheckRequest: + PostInfraDynamicCheckRequest: + method: post - resourcePath: /mciDynamicCheckRequest - description: '**⚠️ DEPRECATED: This endpoint is deprecated and will be removed - in a future version. Please use `/mciDynamicReview` instead for comprehensive - validation and cost estimation.** + resourcePath: /infraDynamicCheckRequest + description: '**⚠️ DEPRECATED: This endpoint is deprecated and will be removed in a future version. Please use `/mciDynamicReview` instead for comprehensive validation and cost estimation.** - Validate resource availability and discover optimal connection configurations - before creating MCI dynamically. + Validate resource availability and discover optimal connection configurations before creating MCI dynamically. - This endpoint provides comprehensive resource validation and connection discovery - for MCI planning: + This endpoint provides comprehensive resource validation and connection discovery for MCI planning: **Resource Validation Process:** - 1. **Specification Analysis**: Validates that requested common specs exist - and are accessible + 1. **Specification Analysis**: Validates that requested common specs exist and are accessible - 2. **Provider Discovery**: Identifies available cloud providers and regions - for each specification + 2. **Provider Discovery**: Identifies available cloud providers and regions for each specification - 3. **Connectivity Assessment**: Tests connection configurations and CSP API - accessibility + 3. **Connectivity Assessment**: Tests connection configurations and CSP API accessibility - 4. **Quota Verification**: Checks available quotas and resource limits where - possible + 4. **Quota Verification**: Checks available quotas and resource limits where possible - 5. **Compatibility Matrix**: Generates matrix of viable spec-provider-region - combinations + 5. **Compatibility Matrix**: Generates matrix of viable spec-provider-region combinations **Connection Configuration Discovery:** - - **Available Providers**: Lists all configured cloud providers (AWS, Azure, - GCP, etc.) + - **Available Providers**: Lists all configured cloud providers (AWS, Azure, GCP, etc.) - - **Active Regions**: Shows available regions per provider with connectivity - status + - **Active Regions**: Shows available regions per provider with connectivity status - - **Specification Mapping**: Maps common specs to provider-specific instance - types + - **Specification Mapping**: Maps common specs to provider-specific instance types - **Image Compatibility**: Validates image availability across different providers/regions @@ -3391,8 +3208,7 @@ serviceActions: **Pre-Deployment Validation:** - - **Resource Existence**: Confirms all specified resources exist in system - namespace + - **Resource Existence**: Confirms all specified resources exist in system namespace - **Permission Verification**: Validates CSP credentials and required permissions @@ -3403,8 +3219,7 @@ serviceActions: **Optimization Recommendations:** - - **Cost-Effective Regions**: Suggests regions with lower pricing for specified - resources + - **Cost-Effective Regions**: Suggests regions with lower pricing for specified resources - **Performance Optimization**: Recommends regions with better network performance @@ -3446,9 +3261,10 @@ serviceActions: 3. Use `/mciDynamicReview` for detailed cost estimation and final validation 4. Proceed with `/mciDynamic` using validated configuration' - PostMciDynamicFromTemplate: + PostInfraDynamicFromTemplate: + method: post - resourcePath: /ns/{nsId}/mci/template/{templateId} + resourcePath: /ns/{nsId}/infra/template/{templateId} description: 'Create a new MCI by applying an MCI Dynamic Template. The template provides the base VM configuration, and the apply request @@ -3463,25 +3279,22 @@ serviceActions: - `description` (optional): Overrides the template''s description - All other configuration (specs, images, subgroups) comes from the template' - PostMciDynamicReview: + PostInfraDynamicReview: + method: post - resourcePath: /ns/{nsId}/mciDynamicReview - description: 'Review and validate MCI dynamic request comprehensively before - actual provisioning. + resourcePath: /ns/{nsId}/infraDynamicReview + description: 'Review and validate MCI dynamic request comprehensively before actual provisioning. - This endpoint performs comprehensive validation of MCI dynamic creation requests - without actually creating resources. + This endpoint performs comprehensive validation of MCI dynamic creation requests without actually creating resources. - It checks resource availability, validates specifications and images, estimates - costs, and provides detailed recommendations. + It checks resource availability, validates specifications and images, estimates costs, and provides detailed recommendations. **Key Features:** - Validates all VM specifications and images against CSP availability - - Provides cost estimation (including partial estimates when some costs are - unknown) + - Provides cost estimation (including partial estimates when some costs are unknown) - Identifies potential configuration issues and warnings @@ -3510,17 +3323,15 @@ serviceActions: - Configuration optimization - Multi-cloud resource planning' - PostMciDynamicSubGroupVmReview: + PostInfraDynamicNodeGroupNodeReview: + method: post - resourcePath: /ns/{nsId}/mci/{mciId}/subGroupDynamicReview - description: 'Review and validate a VM dynamic addition request for an existing - MCI before actual provisioning. + resourcePath: /ns/{nsId}/infra/{mciId}/nodeGroupDynamicReview + description: 'Review and validate a VM dynamic addition request for an existing MCI before actual provisioning. - This endpoint provides comprehensive validation for adding new VMs to existing - MCIs without actually creating resources. + This endpoint provides comprehensive validation for adding new VMs to existing MCIs without actually creating resources. - It checks resource availability, validates specifications and images, estimates - costs, and provides detailed recommendations. + It checks resource availability, validates specifications and images, estimates costs, and provides detailed recommendations. **Key Features:** @@ -3567,14 +3378,13 @@ serviceActions: - Configuration optimization before deployment - Risk assessment for VM addition to existing infrastructure' - PostMciDynamicTemplate: + PostInfraDynamicTemplate: + method: post - resourcePath: /ns/{nsId}/template/mci - description: 'Create a reusable MCI Dynamic Template. Templates store MCI dynamic - creation + resourcePath: /ns/{nsId}/template/infra + description: 'Create a reusable MCI Dynamic Template. Templates store MCI dynamic creation - request configurations that can be applied later to create MCIs with consistent - settings. + request configurations that can be applied later to create MCIs with consistent settings. **Template Contents:** @@ -3591,51 +3401,45 @@ serviceActions: Templates can be created manually or extracted from existing MCIs.' - PostMciPolicy: + PostInfraPolicy: + method: post - resourcePath: /ns/{nsId}/policy/mci/{mciId} + resourcePath: /ns/{nsId}/policy/infra/{mciId} description: Create MCI Automation policy - PostMciSnapshot: + PostInfraSnapshot: + method: post - resourcePath: /ns/{nsId}/mci/{mciId}/snapshot - description: Create snapshots for the first running VM in each subgroup of an - MCI in parallel - PostMciSubGroupDynamic: + resourcePath: /ns/{nsId}/infra/{mciId}/snapshot + description: Create snapshots for the first running VM in each subgroup of an MCI in parallel + PostInfraNodeGroupDynamic: + method: post - resourcePath: /ns/{nsId}/mci/{mciId}/subGroupDynamic - description: 'Dynamically add new virtual machines to an existing MCI using - common specifications and automated resource management. + resourcePath: /ns/{nsId}/infra/{mciId}/nodeGroupDynamic + description: 'Dynamically add new virtual machines to an existing MCI using common specifications and automated resource management. This endpoint provides elastic scaling capabilities for running MCIs: **Dynamic VM Addition Process:** - 1. **MCI Validation**: Verifies target MCI exists and is in a valid state - for expansion + 1. **MCI Validation**: Verifies target MCI exists and is in a valid state for expansion - 2. **Resource Discovery**: Resolves common spec and image to provider-specific - resources + 2. **Resource Discovery**: Resolves common spec and image to provider-specific resources - 3. **Network Integration**: Automatically configures new VMs to use existing - MCI network resources + 3. **Network Integration**: Automatically configures new VMs to use existing MCI network resources - 4. **Subgroup Management**: Creates new subgroups or expands existing ones - based on configuration + 4. **Subgroup Management**: Creates new subgroups or expands existing ones based on configuration - 5. **Status Synchronization**: Updates MCI status and metadata to reflect - new VM additions + 5. **Status Synchronization**: Updates MCI status and metadata to reflect new VM additions **Integration with Existing Infrastructure:** - - **Network Reuse**: New VMs automatically join existing VNets and security - groups + - **Network Reuse**: New VMs automatically join existing VNets and security groups - **SSH Key Sharing**: Uses existing SSH keys for consistent access management - - **Monitoring Integration**: New VMs inherit monitoring configuration from - parent MCI + - **Monitoring Integration**: New VMs inherit monitoring configuration from parent MCI - **Label Propagation**: Applies MCI-level labels and policies to new VMs @@ -3646,14 +3450,11 @@ serviceActions: - **Horizontal Scaling**: Add more instances to handle increased workload - - **Multi-Region Expansion**: Deploy VMs in new regions while maintaining - MCI cohesion + - **Multi-Region Expansion**: Deploy VMs in new regions while maintaining MCI cohesion - - **Provider Diversification**: Add VMs from different cloud providers for - redundancy + - **Provider Diversification**: Add VMs from different cloud providers for redundancy - - **Workload Specialization**: Deploy VMs with different specifications for - specific tasks + - **Workload Specialization**: Deploy VMs with different specifications for specific tasks **Configuration Requirements:** @@ -3698,40 +3499,33 @@ serviceActions: - Monitoring and logging are automatically configured - Application deployment and configuration management can proceed immediately' - PostMciSubGroupScaleOut: + PostInfraNodeGroupScaleOut: + method: post - resourcePath: /ns/{nsId}/mci/{mciId}/subgroup/{subgroupId} - description: 'Horizontally scale an existing VM subgroup by adding more identical - instances for increased capacity. + resourcePath: /ns/{nsId}/infra/{mciId}/nodegroup/{subgroupId} + description: 'Horizontally scale an existing VM subgroup by adding more identical instances for increased capacity. - This endpoint provides elastic scaling capabilities for running application - tiers: + This endpoint provides elastic scaling capabilities for running application tiers: **Scale-Out Process:** - 1. **SubGroup Validation**: Verifies target subgroup exists and is in scalable - state + 1. **SubGroup Validation**: Verifies target subgroup exists and is in scalable state - 2. **Template Replication**: Uses existing VM configuration as template for - new instances + 2. **Template Replication**: Uses existing VM configuration as template for new instances 3. **Resource Allocation**: Ensures sufficient CSP quotas and network resources - 4. **Parallel Deployment**: Deploys multiple new VMs simultaneously for faster - scaling + 4. **Parallel Deployment**: Deploys multiple new VMs simultaneously for faster scaling - 5. **Integration**: Seamlessly integrates new VMs into existing subgroup and - MCI + 5. **Integration**: Seamlessly integrates new VMs into existing subgroup and MCI **Configuration Inheritance:** - - **VM Specifications**: New VMs inherit exact specifications from existing - subgroup members + - **VM Specifications**: New VMs inherit exact specifications from existing subgroup members - - **Network Settings**: Automatically placed in same VNet, subnet, and security - groups + - **Network Settings**: Automatically placed in same VNet, subnet, and security groups - **SSH Keys**: Use same SSH key pairs for consistent access management @@ -3748,19 +3542,16 @@ serviceActions: - **Performance Optimization**: Add instances to reduce per-VM resource utilization - - **Geographic Expansion**: Scale existing workloads to handle broader user - base + - **Geographic Expansion**: Scale existing workloads to handle broader user base - **Fault Tolerance**: Increase redundancy by adding more instances **Intelligent Scaling:** - - **Sequential Naming**: New VMs follow established naming pattern (e.g., - web-4, web-5, web-6) + - **Sequential Naming**: New VMs follow established naming pattern (e.g., web-4, web-5, web-6) - - **Load Distribution**: New VMs are distributed optimally across availability - zones + - **Load Distribution**: New VMs are distributed optimally across availability zones - **Resource Efficiency**: Reuses existing network and security infrastructure @@ -3773,30 +3564,26 @@ serviceActions: - **Zero Downtime**: Existing VMs continue running during scale-out operation - - **Immediate Availability**: New VMs are ready for traffic as soon as deployment - completes + - **Immediate Availability**: New VMs are ready for traffic as soon as deployment completes - **Unified Management**: All VMs (old and new) managed through single subgroup - **Policy Consistency**: All scaling and management policies apply uniformly - - **Monitoring Integration**: New VMs automatically included in existing monitoring - dashboards + - **Monitoring Integration**: New VMs automatically included in existing monitoring dashboards **Scale-Out Considerations:** - **CSP Quotas**: Verifies sufficient instance, network, and storage quotas - - **Region Capacity**: Ensures target region has capacity for requested instance - types + - **Region Capacity**: Ensures target region has capacity for requested instance types - **Network Limits**: Validates that VNet can accommodate additional VMs - **Cost Impact**: Additional VMs incur proportional CSP billing costs - - **Application Readiness**: Applications should be designed to handle additional - instances + - **Application Readiness**: Applications should be designed to handle additional instances **Post-Scale Operations:** @@ -3819,47 +3606,37 @@ serviceActions: - Verify application clustering and session management handle new instances - Consider database connection limits and other resource constraints' - PostMciVm: + PostInfraNode: + method: post - resourcePath: /ns/{nsId}/mci/{mciId}/vm - description: 'Create and add a group of identical virtual machines (subgroup) - to an existing MCI using detailed specifications. + resourcePath: /ns/{nsId}/infra/{mciId}/node + description: 'Create and add a group of identical virtual machines (subgroup) to an existing MCI using detailed specifications. - This endpoint provides precise control over VM configuration and placement - within existing infrastructure: + This endpoint provides precise control over VM configuration and placement within existing infrastructure: **SubGroup Creation Process:** - 1. **MCI Integration**: Validates target MCI exists and can accommodate new - VMs + 1. **MCI Integration**: Validates target MCI exists and can accommodate new VMs - 2. **Resource Validation**: Verifies all specified resources (specs, images, - networks) exist and are accessible + 2. **Resource Validation**: Verifies all specified resources (specs, images, networks) exist and are accessible - 3. **Homogeneous Deployment**: Creates multiple identical VMs with consistent - configuration + 3. **Homogeneous Deployment**: Creates multiple identical VMs with consistent configuration - 4. **Network Integration**: Integrates new VMs with existing MCI networking - and security policies + 4. **Network Integration**: Integrates new VMs with existing MCI networking and security policies - 5. **Group Management**: Establishes subgroup for collective management and - operations + 5. **Group Management**: Establishes subgroup for collective management and operations **Detailed Configuration Control:** - - **Specific Resource References**: Uses exact resource IDs rather than common - specifications + - **Specific Resource References**: Uses exact resource IDs rather than common specifications - - **Network Placement**: Precise control over VNet, subnet, and security group - assignment + - **Network Placement**: Precise control over VNet, subnet, and security group assignment - - **Storage Configuration**: Detailed disk configuration including type, size, - and performance tiers + - **Storage Configuration**: Detailed disk configuration including type, size, and performance tiers - - **Instance Customization**: Full control over VM specifications, images, - and metadata + - **Instance Customization**: Full control over VM specifications, images, and metadata - **Security Settings**: Explicit security group and SSH key configuration @@ -3872,56 +3649,46 @@ serviceActions: - **Simplified Management**: Single configuration template for multiple VMs - - **Consistent Naming**: Automatic sequential naming (e.g., web-1, web-2, - web-3) + - **Consistent Naming**: Automatic sequential naming (e.g., web-1, web-2, web-3) - - **Group Policies**: Apply scaling, monitoring, and lifecycle policies at - subgroup level + - **Group Policies**: Apply scaling, monitoring, and lifecycle policies at subgroup level **Use Cases:** - - **Application Tiers**: Deploy multiple instances of web servers, application - servers, or databases + - **Application Tiers**: Deploy multiple instances of web servers, application servers, or databases - - **Load Distribution**: Create multiple identical VMs for load balancing - scenarios + - **Load Distribution**: Create multiple identical VMs for load balancing scenarios - **High Availability**: Deploy redundant instances across availability zones - **Batch Processing**: Create worker nodes for distributed computing workloads - - **Development Environments**: Provision identical development or testing - instances + - **Development Environments**: Provision identical development or testing instances **Configuration Requirements:** - **Resource IDs**: Must specify exact resource identifiers (not common specs) - - **Network Configuration**: VNet, subnet, and security group must exist and - be compatible + - **Network Configuration**: VNet, subnet, and security group must exist and be compatible - **SSH Keys**: Must specify valid SSH key pairs for access management - **Image Compatibility**: Specified image must be available in target region - - **Quota Validation**: Sufficient CSP quotas must be available for all requested - VMs + - **Quota Validation**: Sufficient CSP quotas must be available for all requested VMs **SubGroup Size Considerations:** - **Small Groups (1-5 VMs)**: Fast deployment, minimal resource contention - - **Medium Groups (6-20 VMs)**: Optimized parallel deployment with resource - batching + - **Medium Groups (6-20 VMs)**: Optimized parallel deployment with resource batching - - **Large Groups (21+ VMs)**: Advanced deployment strategies to avoid CSP - rate limits + - **Large Groups (21+ VMs)**: Advanced deployment strategies to avoid CSP rate limits - - **Resource Limits**: Respects CSP quotas and CB-Tumblebug configuration - limits + - **Resource Limits**: Respects CSP quotas and CB-Tumblebug configuration limits **Post-Deployment Integration:** @@ -3933,13 +3700,14 @@ serviceActions: - Can be scaled out further or individual VMs can be managed separately - Supports all standard CB-Tumblebug VM lifecycle operations' - PostMciVmSnapshot: + PostInfraNodeSnapshot: + method: post - resourcePath: /ns/{nsId}/mci/{mciId}/vm/{vmId}/snapshot + resourcePath: /ns/{nsId}/infra/{mciId}/node/{vmId}/snapshot description: Snapshot VM and create a Custom Image Object using the Snapshot PostNLB: method: post - resourcePath: /ns/{nsId}/mci/{mciId}/nlb + resourcePath: /ns/{nsId}/infra/{mciId}/nlb description: Create NLB PostNs: method: post @@ -3947,29 +3715,23 @@ serviceActions: description: Create namespace PostRegisterCSPNativeVM: method: post - resourcePath: /ns/{nsId}/registerCspVm - description: 'Import and register pre-existing virtual machines from cloud service - providers into CB-Tumblebug management. + resourcePath: /ns/{nsId}/registerCspNode + description: 'Import and register pre-existing virtual machines from cloud service providers into CB-Tumblebug management. - This endpoint allows you to bring existing CSP resources under CB-Tumblebug - control without recreating them: + This endpoint allows you to bring existing CSP resources under CB-Tumblebug control without recreating them: **Registration Process:** 1. **Discovery**: Validates that the specified VM exists in the target CSP - 2. **Metadata Import**: Retrieves VM configuration, network settings, and - current status + 2. **Metadata Import**: Retrieves VM configuration, network settings, and current status - 3. **Resource Mapping**: Creates CB-Tumblebug resource objects that reference - the existing CSP resources + 3. **Resource Mapping**: Creates CB-Tumblebug resource objects that reference the existing CSP resources - 4. **Status Synchronization**: Aligns CB-Tumblebug status with actual CSP - VM state + 4. **Status Synchronization**: Aligns CB-Tumblebug status with actual CSP VM state - 5. **Management Integration**: Enables CB-Tumblebug operations on the registered - VMs + 5. **Management Integration**: Enables CB-Tumblebug operations on the registered VMs **Supported VM States:** @@ -3985,8 +3747,7 @@ serviceActions: - VM must exist in a supported CSP (AWS, Azure, GCP, etc.) - - Network resources (VPC, subnets, security groups) will be discovered and - mapped + - Network resources (VPC, subnets, security groups) will be discovered and mapped - Storage volumes and attached disks will be registered automatically @@ -4024,31 +3785,23 @@ serviceActions: PostScheduleRegisterCspResources: method: post resourcePath: /registerCspResources/schedule - description: 'Create a scheduled job to periodically register CSP-native resources - (vNet, securityGroup, sshKey, vm) into CB-Tumblebug + description: 'Create a scheduled job to periodically register CSP-native resources (vNet, securityGroup, sshKey, vm) into CB-Tumblebug **Resource Registration Behavior:** This job registers CSP-native resources based on the `connectionName` field: - - If `connectionName` is specified: Registers resources from the **specified - connection only** + - If `connectionName` is specified: Registers resources from the **specified connection only** - - If `connectionName` is empty or omitted: Registers resources from **all - available connections** + - If `connectionName` is empty or omitted: Registers resources from **all available connections** **Usage Examples:** - - Single connection: `{"jobType": "registerCspResources", "nsId": "default", - "intervalSeconds": 60, "connectionName": "aws-ap-northeast-2", "mciNamePrefix": - "mci-01"}` + - Single connection: `{"jobType": "registerCspResources", "nsId": "default", "intervalSeconds": 60, "connectionName": "aws-ap-northeast-2", "mciNamePrefix": "mci-01"}` - - All connections: `{"jobType": "registerCspResources", "nsId": "default", - "intervalSeconds": 60, "connectionName": "", "mciNamePrefix": "mci-all"}` - or `{"jobType": "registerCspResources", "nsId": "default", "intervalSeconds": - 60, "mciNamePrefix": "mci-all"}` + - All connections: `{"jobType": "registerCspResources", "nsId": "default", "intervalSeconds": 60, "connectionName": "", "mciNamePrefix": "mci-all"}` or `{"jobType": "registerCspResources", "nsId": "default", "intervalSeconds": 60, "mciNamePrefix": "mci-all"}` **Job Status Values:** @@ -4099,8 +3852,7 @@ serviceActions: - System checks for existing jobs with same configuration - - Configuration uniqueness based on: jobType + nsId + connectionName + mciNamePrefix - + option + mciFlag + - Configuration uniqueness based on: jobType + nsId + connectionName + mciNamePrefix + option + mciFlag - Returns 409 Conflict if duplicate job exists with existing job ID' PostSecurityGroup: @@ -4112,8 +3864,7 @@ serviceActions: resourcePath: /ns/{nsId}/resources/securityGroup/template/{templateId} description: 'Create a new SecurityGroup by applying a SecurityGroup Template. - The template provides the base SecurityGroup configuration (connectionName, - vNetId, firewallRules), + The template provides the base SecurityGroup configuration (connectionName, vNetId, firewallRules), and the apply request allows overriding the SecurityGroup name and description. @@ -4124,16 +3875,13 @@ serviceActions: - `description` (optional): Overrides the template''s description - - All other configuration (connectionName, vNetId, firewallRules) comes from - the template' + - All other configuration (connectionName, vNetId, firewallRules) comes from the template' PostSecurityGroupTemplate: method: post resourcePath: /ns/{nsId}/template/securityGroup - description: 'Create a reusable SecurityGroup Template. Templates store SecurityGroup - creation + description: 'Create a reusable SecurityGroup Template. Templates store SecurityGroup creation - request configurations that can be applied later to create SecurityGroups - with consistent settings. + request configurations that can be applied later to create SecurityGroups with consistent settings. **Template Contents:** @@ -4150,7 +3898,7 @@ serviceActions: Templates can be created manually with desired SecurityGroup configurations.' PostSiteToSiteVpn: method: post - resourcePath: /ns/{nsId}/mci/{mciId}/vpn + resourcePath: /ns/{nsId}/infra/{mciId}/vpn description: 'Create a site-to-site VPN @@ -4163,8 +3911,7 @@ serviceActions: - Note: It will take about `15 ~ 45 minutes`. - - Note: A one-time retry is performed to handle transient failures caused - by CSP-internal timing issues between dependent resources. + - Note: A one-time retry is performed to handle transient failures caused by CSP-internal timing issues between dependent resources. ' PostSpec: @@ -4180,8 +3927,7 @@ serviceActions: - Spec availability in DB and CSP - - Image availability in DB and CSP (auto-registers if found in CSP but not - in DB) + - Image availability in DB and CSP (auto-registers if found in CSP but not in DB) - Cost estimation based on spec @@ -4201,12 +3947,10 @@ serviceActions: Supported CSPs: AWS, Azure, GCP, NCP - - Note - `connectionName` example: aws-ap-northeast-2, azure-koreacentral, - gcp-asia-northeast3, ncp-kr + - Note - `connectionName` example: aws-ap-northeast-2, azure-koreacentral, gcp-asia-northeast3, ncp-kr - - Note - Please check the `requiredCSPResource` property which includes CSP - specific values. + - Note - Please check the `requiredCSPResource` property which includes CSP specific values. - Note - You can find the API usage examples on this link, https://github.com/cloud-barista/mc-terrarium/discussions/110 @@ -4220,40 +3964,33 @@ serviceActions: method: post resourcePath: /ns/{nsId}/resources/vNet/{vNetId}/subnet description: Create Subnet - PostSystemMci: + PostSystemInfra: + method: post - resourcePath: /systemMci - description: 'Create specialized MCI instances for CB-Tumblebug system operations - and infrastructure probing. + resourcePath: /systemInfra + description: 'Create specialized MCI instances for CB-Tumblebug system operations and infrastructure probing. - This endpoint provisions system-level infrastructure that supports CB-Tumblebug''s - internal functions: + This endpoint provisions system-level infrastructure that supports CB-Tumblebug''s internal functions: **System MCI Types:** - - `probe`: Creates lightweight VMs for network connectivity testing and CSP - capability discovery + - `probe`: Creates lightweight VMs for network connectivity testing and CSP capability discovery - - `monitor`: Deploys monitoring infrastructure for system health and performance - tracking + - `monitor`: Deploys monitoring infrastructure for system health and performance tracking - - `test`: Provisions test environments for validating CSP integrations and - features + - `test`: Provisions test environments for validating CSP integrations and features **Probe MCI Features:** - - **Connectivity Testing**: Validates network paths between different CSP - regions + - **Connectivity Testing**: Validates network paths between different CSP regions - - **Latency Measurement**: Measures inter-region and inter-provider network - performance + - **Latency Measurement**: Measures inter-region and inter-provider network performance - **Feature Discovery**: Tests CSP-specific capabilities and service availability - - **Resource Validation**: Verifies that CB-Tumblebug can successfully provision - resources + - **Resource Validation**: Verifies that CB-Tumblebug can successfully provision resources **System Namespace:** @@ -4301,13 +4038,11 @@ serviceActions: PostTestStreamResponse: method: post resourcePath: /testStreamResponse - description: Receives a number and streams the decrementing number every second - until zero + description: Receives a number and streams the decrementing number every second until zero PostUtilToDesignNetwork: method: post resourcePath: /util/net/design - description: Design a hierarchical network configuration of a VPC network or - multi-cloud network consisting of multiple VPC networks + description: Design a hierarchical network configuration of a VPC network or multi-cloud network consisting of multiple VPC networks PostUtilToDesignVNet: method: post resourcePath: /util/vNet/design @@ -4315,8 +4050,7 @@ serviceActions: PostUtilToValidateNetwork: method: post resourcePath: /util/net/validate - description: Validate a hierarchical configuration of a VPC network or multi-cloud - network consisting of multiple VPC networks + description: Validate a hierarchical configuration of a VPC network or multi-cloud network consisting of multiple VPC networks PostVNet: method: post resourcePath: /ns/{nsId}/resources/vNet @@ -4326,8 +4060,7 @@ serviceActions: resourcePath: /ns/{nsId}/resources/vNet/template/{templateId} description: 'Create a new vNet by applying a vNet Template. - The template provides the base vNet configuration (connectionName, cidrBlock, - subnets), + The template provides the base vNet configuration (connectionName, cidrBlock, subnets), and the apply request allows overriding the vNet name and description. @@ -4338,15 +4071,13 @@ serviceActions: - `description` (optional): Overrides the template''s description - - All other configuration (connectionName, cidrBlock, subnets) comes from - the template' + - All other configuration (connectionName, cidrBlock, subnets) comes from the template' PostVNetTemplate: method: post resourcePath: /ns/{nsId}/template/vNet description: 'Create a reusable vNet Template. Templates store vNet creation - request configurations that can be applied later to create vNets with consistent - settings. + request configurations that can be applied later to create vNets with consistent settings. **Template Contents:** @@ -4363,7 +4094,7 @@ serviceActions: Templates can be created manually with desired vNet configurations.' PostVmDataDisk: method: post - resourcePath: /ns/{nsId}/mci/{mciId}/vm/{vmId}/dataDisk + resourcePath: /ns/{nsId}/infra/{mciId}/node/{vmId}/dataDisk description: Provisioning (Create and attach) dataDisk PutChangeK8sNodeGroupAutoscaleSize: method: put @@ -4386,35 +4117,28 @@ serviceActions: 2. Label Selector (labelSelector): Fetch IPs of matching resources. - 3. Manual IP Values (values): Manually provide IP addresses (simple routing - only).' + 3. Manual IP Values (values): Manually provide IP addresses (simple routing only).' PutImage: method: put resourcePath: /ns/{nsId}/resources/image/{imageId} description: Update image - PutMciAssociatedSecurityGroups: + PutInfraAssociatedSecurityGroups: + method: put - resourcePath: /ns/{nsId}/mci/{mciId}/associatedSecurityGroups - description: 'Update all Security Groups associated with a given MCI. The firewall - rules of all Security Groups will be synchronized to match the requested set. + resourcePath: /ns/{nsId}/infra/{mciId}/associatedSecurityGroups + description: 'Update all Security Groups associated with a given MCI. The firewall rules of all Security Groups will be synchronized to match the requested set. - Update all Security Groups associated with a given MCI. The firewall rules - of all associated Security Groups will be synchronized to match the requested - set. + Update all Security Groups associated with a given MCI. The firewall rules of all associated Security Groups will be synchronized to match the requested set. - This API will add missing rules and delete extra rules so that each Security - Group''s rules become identical to the requested set. + This API will add missing rules and delete extra rules so that each Security Group''s rules become identical to the requested set. - Only firewall rules are updated; other metadata (name, description, etc.) - is not changed. + Only firewall rules are updated; other metadata (name, description, etc.) is not changed. Usage: - Use this API to update (synchronize) the firewall rules of all Security Groups - associated with the specified MCI. The rules in the request body will become - the only rules in each Security Group after the operation. + Use this API to update (synchronize) the firewall rules of all Security Groups associated with the specified MCI. The rules in the request body will become the only rules in each Security Group after the operation. - All existing rules not present in the request will be deleted. @@ -4427,8 +4151,7 @@ serviceActions: Notes: - - "Ports" field supports single port ("22"), port range ("80-100"), and multiple - ports/ranges ("22,80-100,443"). + - "Ports" field supports single port ("22"), port range ("80-100"), and multiple ports/ranges ("22,80-100,443"). - The valid port number range is 0 to 65535 (inclusive). @@ -4438,19 +4161,18 @@ serviceActions: - "CIDR" is the allowed IP range. - - All existing rules not in the request (including default ICMP, etc.) will - be deleted. + - All existing rules not in the request (including default ICMP, etc.) will be deleted. - Metadata (name, description, etc.) is not changed.' - PutMciDynamicTemplate: + PutInfraDynamicTemplate: + method: put - resourcePath: /ns/{nsId}/template/mci/{templateId} + resourcePath: /ns/{nsId}/template/infra/{templateId} description: Update an existing MCI Dynamic Template. PutMonitorAgentStatusInstalled: method: put - resourcePath: /ns/{nsId}/monitoring/status/mci/{mciId}/vm/{vmId} - description: Set monitoring agent (CB-Dragonfly agent) installation status installed - (for Windows VM only) + resourcePath: /ns/{nsId}/monitoring/status/infra/{mciId}/node/{vmId} + description: Set monitoring agent (CB-Dragonfly agent) installation status installed (for Windows VM only) PutNs: method: put resourcePath: /ns/{nsId} @@ -4458,8 +4180,7 @@ serviceActions: PutScheduleRegisterCspResources: method: put resourcePath: /registerCspResources/schedule/{jobId} - description: 'Update the configuration of a scheduled CSP resource registration - job (interval, enabled status) + description: 'Update the configuration of a scheduled CSP resource registration job (interval, enabled status) **Updatable Fields:** @@ -4480,40 +4201,32 @@ serviceActions: - Change both: `{"intervalSeconds": 10, "enabled": true}` - **Note:** For simpler pause/resume operations, consider using dedicated `/pause` - and `/resume` endpoints' + **Note:** For simpler pause/resume operations, consider using dedicated `/pause` and `/resume` endpoints' PutScheduleRegisterCspResourcesPause: method: put resourcePath: /registerCspResources/schedule/{jobId}/pause - description: 'Temporarily pause a scheduled job without deleting it. The job - can be resumed later. + description: 'Temporarily pause a scheduled job without deleting it. The job can be resumed later. This sets enabled=false and preserves all job state and execution history.' PutScheduleRegisterCspResourcesResume: method: put resourcePath: /registerCspResources/schedule/{jobId}/resume - description: 'Resume a previously paused scheduled job to continue periodic - execution. + description: 'Resume a previously paused scheduled job to continue periodic execution. This sets enabled=true and restarts the job scheduler.' PutSecurityGroup: method: put resourcePath: /ns/{nsId}/resources/securityGroup/{securityGroupId} - description: 'Update Security Group: Synchronize the firewall rules of the specified - Security Group to match the requested list exactly. + description: 'Update Security Group: Synchronize the firewall rules of the specified Security Group to match the requested list exactly. - This API will add missing rules and delete extra rules so that the Security - Group''s rules become identical to the requested set. + This API will add missing rules and delete extra rules so that the Security Group''s rules become identical to the requested set. - Only firewall rules are updated; other metadata (name, description, etc.) - is not changed. + Only firewall rules are updated; other metadata (name, description, etc.) is not changed. Usage: - Use this API to update (synchronize) the firewall rules of a Security Group. - The rules in the request body will become the only rules in the Security Group - after the operation. + Use this API to update (synchronize) the firewall rules of a Security Group. The rules in the request body will become the only rules in the Security Group after the operation. - All existing rules not present in the request will be deleted. @@ -4526,8 +4239,7 @@ serviceActions: Notes: - - "Ports" field supports single port ("22"), port range ("80-100"), and multiple - ports/ranges ("22,80-100,443"). + - "Ports" field supports single port ("22"), port range ("80-100"), and multiple ports/ranges ("22,80-100,443"). - The valid port number range is 0 to 65535 (inclusive). @@ -4537,8 +4249,7 @@ serviceActions: - "CIDR" is the allowed IP range. - - All existing rules not in the request (including default ICMP, etc.) will - be deleted. + - All existing rules not in the request (including default ICMP, etc.) will be deleted. - Metadata (name, description, etc.) is not changed.' PutSecurityGroupTemplate: @@ -4567,18 +4278,16 @@ serviceActions: description: Update an existing vNet Template. PutVmDataDisk: method: put - resourcePath: /ns/{nsId}/mci/{mciId}/vm/{vmId}/dataDisk + resourcePath: /ns/{nsId}/infra/{mciId}/node/{vmId}/dataDisk description: Attach/Detach available dataDisk RecommendK8sNode: method: post resourcePath: /k8sClusterRecommendNode - description: Recommend K8sCluster's Node plan (filter and priority) Find details - from https://github.com/cloud-barista/cb-tumblebug/discussions/1234 + description: Recommend K8sCluster's Node plan (filter and priority) Find details from https://github.com/cloud-barista/cb-tumblebug/discussions/1234 RecommendSpec: method: post resourcePath: /recommendSpec - description: 'Recommend specs for configuring an infrastructure (filter and - priority) + description: 'Recommend specs for configuring an infrastructure (filter and priority) Find details from https://github.com/cloud-barista/cb-tumblebug/discussions/1234 @@ -4589,22 +4298,18 @@ serviceActions: RecommendSpecOptions: method: get resourcePath: /recommendSpecOptions - description: Get available options for filtering and prioritizing specs in RecommendSpec - API + description: Get available options for filtering and prioritizing specs in RecommendSpec API RecordProvisioningEvent: method: post resourcePath: /provisioning/event - description: 'Manually record a provisioning success or failure event for historical - tracking and analysis. + description: 'Manually record a provisioning success or failure event for historical tracking and analysis. - This endpoint allows external systems or manual processes to contribute to - provisioning history: + This endpoint allows external systems or manual processes to contribute to provisioning history: **Use Cases:** - - **External Provisioning Tools**: Record events from non-CB-Tumblebug provisioning - systems + - **External Provisioning Tools**: Record events from non-CB-Tumblebug provisioning systems - **Manual Testing**: Log results from manual deployment tests @@ -4639,23 +4344,16 @@ serviceActions: RegisterCredential: method: post resourcePath: /credential - description: This API registers credential information using hybrid encryption. - The process involves compressing and encrypting sensitive data with AES-256, - encrypting the AES key with a 4096-bit RSA public key (retrieved via `GET - /credential/publicKey`), and using OAEP padding with SHA-256. All values, - including the AES key, must be base64 encoded before sending, and the public - key token ID must be included in the request. + description: This API registers credential information using hybrid encryption. The process involves compressing and encrypting sensitive data with AES-256, encrypting the AES key with a 4096-bit RSA public key (retrieved via `GET /credential/publicKey`), and using OAEP padding with SHA-256. All values, including the AES key, must be base64 encoded before sending, and the public key token ID must be included in the request. RegisterCspNativeResources: method: post resourcePath: /registerCspResources - description: 'Register CSP Native Resources (vNet, securityGroup, sshKey, vm) - to CB-Tumblebug. + description: 'Register CSP Native Resources (vNet, securityGroup, sshKey, vm) to CB-Tumblebug. **New filtering approach (recommended):** - - Provider only: Registers resources from all connections of the specified - provider + - Provider only: Registers resources from all connections of the specified provider - Provider + Region: Registers resources from all zones within the region @@ -4666,29 +4364,24 @@ serviceActions: **Backward compatibility:** - - `connectionName` is still supported but deprecated. Use provider/region/zone - instead. + - `connectionName` is still supported but deprecated. Use provider/region/zone instead. **Usage Examples:** - All AWS: `{"provider": "aws", "nsId": "default"}` - - AWS Seoul region: `{"provider": "aws", "region": "ap-northeast-2", "nsId": - "default"}` + - AWS Seoul region: `{"provider": "aws", "region": "ap-northeast-2", "nsId": "default"}` - - AWS Seoul zone 2a: `{"provider": "aws", "region": "ap-northeast-2", "zone": - "ap-northeast-2a", "nsId": "default"}` + - AWS Seoul zone 2a: `{"provider": "aws", "region": "ap-northeast-2", "zone": "ap-northeast-2a", "nsId": "default"}` - All connections: `{"nsId": "default", "mciNamePrefix": "mci-all"}` - - Single connection (deprecated): `{"connectionName": "aws-ap-northeast-2", - "nsId": "default"}`' + - Single connection (deprecated): `{"connectionName": "aws-ap-northeast-2", "nsId": "default"}`' RegisterCspNativeResourcesAll: method: post resourcePath: /registerCspResourcesAll - description: '**DEPRECATED**: This endpoint is deprecated. Please use `/registerCspResources` - with empty `connectionName` instead. + description: '**DEPRECATED**: This endpoint is deprecated. Please use `/registerCspResources` with empty `connectionName` instead. This endpoint now redirects to `/registerCspResources` for unified API behavior. @@ -4696,32 +4389,29 @@ serviceActions: **Migration Guide:** - - Old: `POST /registerCspResourcesAll` with `{"nsId": "default", "mciNamePrefix": - "mci-all"}` + - Old: `POST /registerCspResourcesAll` with `{"nsId": "default", "mciNamePrefix": "mci-all"}` - - New: `POST /registerCspResources` with `{"connectionName": "", "nsId": "default", - "mciNamePrefix": "mci-all"}`' + - New: `POST /registerCspResources` with `{"connectionName": "", "nsId": "default", "mciNamePrefix": "mci-all"}`' RemoveBastionNodes: method: delete - resourcePath: /ns/{nsId}/mci/{mciId}/bastion/{bastionVmId} + resourcePath: /ns/{nsId}/infra/{mciId}/bastion/{bastionVmId} description: Remove a bastion VM from all vNets - RemoveBastionNodesWithMci: + RemoveBastionNodesWithInfra: + method: delete - resourcePath: /ns/{nsId}/mci/{mciId}/bastion/{bastionMciId}/{bastionVmId} - description: Remove a specific cross-MCI bastion from all vNets of the target - MCI + resourcePath: /ns/{nsId}/infra/{mciId}/bastion/{bastionMciId}/{bastionVmId} + description: Remove a specific cross-MCI bastion from all vNets of the target MCI RemoveBastionNodesWithNs: method: delete - resourcePath: /ns/{nsId}/mci/{mciId}/bastion/{bastionNsId}/{bastionMciId}/{bastionVmId} - description: Remove a specific cross-namespace bastion from all vNets of the - target MCI + resourcePath: /ns/{nsId}/infra/{mciId}/bastion/{bastionNsId}/{bastionMciId}/{bastionVmId} + description: Remove a specific cross-namespace bastion from all vNets of the target MCI RemoveLabel: method: delete resourcePath: /label/{labelType}/{uid}/{key} description: Remove a label from a resource identified by its uid RemoveNLBVMs: method: delete - resourcePath: /ns/{nsId}/mci/{mciId}/nlb/{nlbId}/vm + resourcePath: /ns/{nsId}/infra/{mciId}/nlb/{nlbId}/node description: Delete VMs from NLB RestDeleteObjectStorage: method: delete @@ -4741,12 +4431,8 @@ serviceActions: description: Get all available options for image search fields SetBastionNodes: method: put - resourcePath: /ns/{nsId}/mci/{mciId}/vm/{targetVmId}/bastion/{bastionVmId} + resourcePath: /ns/{nsId}/infra/{mciId}/node/{targetVmId}/bastion/{bastionVmId} description: "Set bastion nodes for a VM" - Postmcidynamic: - method: post - resourcePath: /ns/{nsId}/mciDynamic - description: "Create MCI Dynamically from common spec and image" Inspectresourcesoverview: method: get resourcePath: /inspectResourcesOverview @@ -4763,10 +4449,6 @@ serviceActions: method: delete resourcePath: /ns/{nsId}/k8sCluster/{k8sClusterId}/k8sNodeGroup/{k8sNodeGroupName} description: "Remove a K8sNodeGroup" - Getsitesinmci: - method: get - resourcePath: /ns/{nsId}/mci/{mciId}/site - description: "Get sites in MCI" Getalldatadisk: method: get resourcePath: /ns/{nsId}/resources/dataDisk @@ -4828,8 +4510,8 @@ serviceActions: resourcePath: /ns/{nsId}/resources/image/{imageId} description: "Delete image" ListSpec: - method: get - resourcePath: /ns/{nsId}/resources/spec + method: post + resourcePath: /ns/{nsId}/resources/filterSpecsByRange description: "List all specs in a namespace" RegisterSpec: method: post @@ -4839,20 +4521,15 @@ serviceActions: method: delete resourcePath: /ns/{nsId}/resources/spec/{specId} description: "Delete spec" - SetBastionNodesWithMci: + SetBastionNodesWithInfra: + method: put - resourcePath: /ns/{nsId}/mci/{mciId}/vm/{targetVmId}/bastion/{bastionMciId}/{bastionVmId} - description: Set bastion nodes for a target VM, specifying a bastion VM that - belongs to a different MCI within the same namespace (cross-MCI bastion). - This allows, for example, an AWS VM to serve as a bastion for an OpenStack - VM. + resourcePath: /ns/{nsId}/infra/{mciId}/node/{targetVmId}/bastion/{bastionMciId}/{bastionVmId} + description: Set bastion nodes for a target VM, specifying a bastion VM that belongs to a different MCI within the same namespace (cross-MCI bastion). This allows, for example, an AWS VM to serve as a bastion for an OpenStack VM. SetBastionNodesWithNs: method: put - resourcePath: /ns/{nsId}/mci/{mciId}/vm/{targetVmId}/bastion/{bastionNsId}/{bastionMciId}/{bastionVmId} - description: Set bastion nodes for a target VM, specifying a bastion VM that - belongs to a different namespace and MCI (cross-namespace bastion). This allows, - for example, a VM in a shared-services namespace to act as a bastion for VMs - in other namespaces. + resourcePath: /ns/{nsId}/infra/{mciId}/node/{targetVmId}/bastion/{bastionNsId}/{bastionMciId}/{bastionVmId} + description: Set bastion nodes for a target VM, specifying a bastion VM that belongs to a different namespace and MCI (cross-namespace bastion). This allows, for example, a VM in a shared-services namespace to act as a bastion for VMs in other namespaces. SetObjectStorageCORS: method: put resourcePath: /ns/{nsId}/resources/objectStorage/{osId}/cors @@ -4860,8 +4537,7 @@ serviceActions: SetObjectStorageCORSLagacy: method: put resourcePath: /resources/objectStorage/{objectStorageName}/cors - description: '(To be deprecated) Set CORS configuration of an object storage - (bucket) + description: '(To be deprecated) Set CORS configuration of an object storage (bucket) **Important Notes:** @@ -4926,8 +4602,7 @@ serviceActions: SetObjectStorageVersioningLagacy: method: put resourcePath: /resources/objectStorage/{objectStorageName}/versioning - description: '(To be deprecated) Set versioning status of an object storage - (bucket) + description: '(To be deprecated) Set versioning status of an object storage (bucket) **Important Notes:** @@ -4953,8 +4628,7 @@ serviceActions: SetSystemInitialized: method: put resourcePath: /readyz/init - description: Set the system initialization status to true. Called by init.py - after completing initialization. + description: Set the system initialization status to true. Called by init.py after completing initialization. TestJWTAuth: method: get resourcePath: /auth/test @@ -4962,18 +4636,20 @@ serviceActions: UnsetSystemInitialized: method: delete resourcePath: /readyz/init - description: Reset the system initialization status to false. Useful for re-initialization - scenarios. + description: Reset the system initialization status to false. Useful for re-initialization scenarios. UpdateExistingSpecListByAvailableRegionZones: method: post resourcePath: /ns/{nsId}/updateExistingSpecListByAvailableRegionZones - description: Query all specs for a specific provider across all regions, check - their availability, and remove specs that are not available in their respective - regions + description: Query all specs for a specific provider across all regions, check their availability, and remove specs that are not available in their respective regions UpdateImagesFromAsset: method: post resourcePath: /updateImagesFromAsset description: Update image information based on the cloudimage.csv asset file + PostFileAndCmdToInfra: + + method: post + resourcePath: /ns/{nsId}/transferFileAndCmd/infra/{infraId} + description: 'Transfer a file and execute commands on all nodes in the Infra. (v0.12.9 갱신: /ns/{nsId}/mci/{mciId}/fileAndCmd → /ns/{nsId}/transferFileAndCmd/infra/{infraId})' mc-web-console: Anycontroller: method: post @@ -5059,7 +4735,7 @@ serviceActions: GetMeasurementFields: method: get resourcePath: /api/o11y/monitoring/influxdb/measurement - queryParams: null + queryParams: description: Retrieve InfluxDB measurements GetMeasurementTags: method: get diff --git a/conf/webconsole_menu_resources.yaml b/conf/webconsole_menu_resources.yaml index f8198a2a..269d700e 100644 --- a/conf/webconsole_menu_resources.yaml +++ b/conf/webconsole_menu_resources.yaml @@ -120,6 +120,14 @@ menus: priority: 2 menunumber: 1350 + - id: cspaccounts + parentid: cloudsps + displayname: CSP Accounts + restype: menu + isaction: false + priority: 2 + menunumber: 1360 + - id: cloudresources parentid: environment displayname: Cloud Resources diff --git a/front/assets/js/common/api/services/connection_config_api.js b/front/assets/js/common/api/services/connection_config_api.js new file mode 100644 index 00000000..d68447db --- /dev/null +++ b/front/assets/js/common/api/services/connection_config_api.js @@ -0,0 +1,56 @@ +// Connection Config API 서비스 (mc-infra-manager v0.12) + +function unwrapResponse(response) { + if (!response) { + throw new Error('Invalid response from server'); + } + if (response.status === 204) { + return null; + } + if (!response.data) { + throw new Error('Invalid response from server'); + } + if (response.status >= 400) { + const msg = (response.data.status && response.data.status.message) + || response.data.message + || response.data.error + || 'Request failed'; + const err = new Error(msg); + err.response = response; + throw err; + } + return response.data.responseData; +} + +/** + * Credential Holder로 Connection Config 목록 필터링 + * GET /connConfig?filterCredentialHolder={credentialHolder} + * 빈 문자열 전달 시 전체 목록 반환 + * + * @param {string} credentialHolder - Credential Holder 이름 (빈 문자열이면 전체) + * @returns {Array} connectionconfig 배열 + */ +export async function filterConnConfigByCredentialHolder(credentialHolder = '') { + const controller = "/api/mc-infra-manager/FilterConnConfigByCredentialHolder"; + const data = {}; + if (credentialHolder) { + data.queryParams = { filterCredentialHolder: credentialHolder }; + } + const response = await webconsolejs["common/api/http"].commonAPIPost(controller, data); + const result = unwrapResponse(response); + if (!result) return []; + return Array.isArray(result.connectionconfig) ? result.connectionconfig : []; +} + +/** + * Connection Config 단건 조회 + * GET /connConfig/{connConfigName} + * + * @param {string} connConfigName - Connection Config 이름 + */ +export async function getConnConfig(connConfigName) { + const controller = "/api/mc-infra-manager/GetConnConfig"; + const data = { pathParams: { connConfigName: String(connConfigName) } }; + const response = await webconsolejs["common/api/http"].commonAPIPost(controller, data); + return unwrapResponse(response); +} diff --git a/front/assets/js/common/api/services/credential_holder_api.js b/front/assets/js/common/api/services/credential_holder_api.js new file mode 100644 index 00000000..4848645b --- /dev/null +++ b/front/assets/js/common/api/services/credential_holder_api.js @@ -0,0 +1,66 @@ +// CredentialHolder API 서비스 (mc-infra-manager v0.12) + +function unwrapResponse(response) { + if (!response) { + throw new Error('Invalid response from server'); + } + if (response.status === 204) { + return null; + } + if (!response.data) { + throw new Error('Invalid response from server'); + } + if (response.status >= 400) { + const msg = (response.data.status && response.data.status.message) + || response.data.message + || response.data.error + || 'Request failed'; + const err = new Error(msg); + err.response = response; + throw err; + } + return response.data.responseData; +} + +/** + * CredentialHolder 목록 조회 + * GET /credentialHolder + */ +export async function getCredentialHolderList() { + const controller = "/api/mc-infra-manager/GetCredentialHolderList"; + const response = await webconsolejs["common/api/http"].commonAPIPost(controller, {}); + return unwrapResponse(response); +} + +/** + * CredentialHolder 단건 조회 + * GET /credentialHolder/{holderId} + */ +export async function getCredentialHolder(holderId) { + const controller = "/api/mc-infra-manager/GetCredentialHolder"; + const data = { pathParams: { holderId: String(holderId) } }; + const response = await webconsolejs["common/api/http"].commonAPIPost(controller, data); + return unwrapResponse(response); +} + +/** + * Credential 등록 (평문 전달 — 암호화는 Go API 서버에서 처리) + * POST /credential (hybrid encryption: RSA-OAEP + AES-256-GCM) + * + * @param {object} params + * @param {string} params.credentialHolder - holder 이름 (예: "admin", "role01") + * @param {string} params.providerName - CSP 이름 (예: "aws", "gcp", "azure") + * @param {Array<{key: string, value: string}>} params.credentialKeyValueList - 자격증명 key-value 목록 + */ +export async function registerCredential({ credentialHolder, providerName, credentialKeyValueList }) { + const controller = "/api/mc-infra-manager/RegisterCredential"; + const data = { + request: { + credentialHolder, + providerName, + credentialKeyValueList, + }, + }; + const response = await webconsolejs["common/api/http"].commonAPIPost(controller, data); + return unwrapResponse(response); +} diff --git a/front/assets/js/common/api/services/import_api.js b/front/assets/js/common/api/services/import_api.js index b2bfaadd..fbdcb18c 100644 --- a/front/assets/js/common/api/services/import_api.js +++ b/front/assets/js/common/api/services/import_api.js @@ -124,10 +124,10 @@ export async function getMciListSimple(nsId) { try { const response = await webconsolejs["common/api/http"].commonAPIPost( - BASE_INFRA + "GetAllMci", + BASE_INFRA + "GetAllInfra", data ); - return response.data.responseData?.mci || []; + return response.data.responseData?.infra || []; } catch (e) { if (e.response?.status === 404) return []; throw e; diff --git a/front/assets/js/common/api/services/mci_api.js b/front/assets/js/common/api/services/mci_api.js index b8e64715..2f7ad724 100644 --- a/front/assets/js/common/api/services/mci_api.js +++ b/front/assets/js/common/api/services/mci_api.js @@ -15,8 +15,8 @@ export async function getMciList(nsId) { }, }; - var controller = "/api/" + "mc-infra-manager/" + "GetAllMci"; - + var controller = "/api/" + "mc-infra-manager/" + "GetAllInfra"; + try { const response = await webconsolejs["common/api/http"].commonAPIPost( controller, @@ -79,7 +79,7 @@ export async function getMci(nsId, mciId) { } } - var controller = "/api/" + "mc-infra-manager/" + "GetMci"; + var controller = "/api/" + "mc-infra-manager/" + "GetInfra"; try { const response = await webconsolejs["common/api/http"].commonAPIPost( @@ -117,7 +117,7 @@ export async function getMciVm(nsId, mciId, vmId) { } } - var controller = "/api/" + "mc-infra-manager/" + "GetMciVm"; + var controller = "/api/" + "mc-infra-manager/" + "GetInfraNode"; try { const response = await webconsolejs["common/api/http"].commonAPIPost( @@ -151,7 +151,7 @@ export function mciLifeCycle(type, currentMciId, nsId) { "action": type, } }; - let controller = "/api/" + "mc-infra-manager/" + "GetControlMci"; + let controller = "/api/" + "mc-infra-manager/" + "GetControlInfra"; let response = webconsolejs["common/api/http"].commonAPIPost( controller, data @@ -170,7 +170,7 @@ export function mciDelete(currentMciId, nsId) { option: "force" } }; - let controller = "/api/" + "mc-infra-manager/" + "Delmci"; + let controller = "/api/" + "mc-infra-manager/" + "DelInfra"; let response = webconsolejs["common/api/http"].commonAPIPost( controller, data @@ -189,7 +189,7 @@ export function vmDelete(mciId, nsId, vmId) { "option": "force" } }; - let controller = "/api/" + "mc-infra-manager/" + "Delmcivm"; + let controller = "/api/" + "mc-infra-manager/" + "DelInfraNode"; let response = webconsolejs["common/api/http"].commonAPIPost( controller, data @@ -210,7 +210,7 @@ export function vmLifeCycle(type, mciId, nsId, vmid) { "action": type } }; - let controller = "/api/" + "mc-infra-manager/" + "GetControlMciVm"; + let controller = "/api/" + "mc-infra-manager/" + "GetControlInfraNode"; let response = webconsolejs["common/api/http"].commonAPIPost( controller, data @@ -258,7 +258,7 @@ export async function mciDynamicReview(mciName, mciDesc, Express_Server_Config_A } } - var controller = "/api/" + "mc-infra-manager/" + "PostMciDynamicReview"; + var controller = "/api/" + "mc-infra-manager/" + "PostInfraDynamicReview"; const response = await webconsolejs["common/api/http"].commonAPIPost( controller, data @@ -302,7 +302,7 @@ export async function mciDynamic(mciName, mciDesc, Express_Server_Config_Arr, ns } } - var controller = "/api/" + "mc-infra-manager/" + "PostMciDynamic"; + var controller = "/api/" + "mc-infra-manager/" + "PostInfraDynamic"; const response = webconsolejs["common/api/http"].commonAPIPost( controller, data @@ -339,7 +339,7 @@ export async function vmDynamic(mciId, nsId, Express_Server_Config_Arr) { } - var controller = "/api/" + "mc-infra-manager/" + "PostMciSubGroupDynamic"; + var controller = "/api/" + "mc-infra-manager/" + "PostInfraNodeGroupDynamic"; const response = await webconsolejs["common/api/http"].commonAPIPost( controller, data @@ -347,7 +347,7 @@ export async function vmDynamic(mciId, nsId, Express_Server_Config_Arr) { } export async function mciRecommendVm(data) { - var controller = "/api/" + "mc-infra-manager/" + "recommendSpec"; + var controller = "/api/" + "mc-infra-manager/" + "RecommendSpec"; const response = await webconsolejs["common/api/http"].commonAPIPost( controller, data @@ -732,7 +732,7 @@ export async function postScaleOutSubGroup(nsId, mciId, subgroupId, numVMsToAdd) } }; - var controller = "/api/" + "mc-infra-manager/" + "Postmcisubgroupscaleout"; + var controller = "/api/" + "mc-infra-manager/" + "PostInfraNodeGroupScaleOut"; const response = await webconsolejs["common/api/http"].commonAPIPost( controller, data @@ -757,7 +757,7 @@ export async function getPolicyList(nsId) { }, }; - var controller = "/api/" + "mc-infra-manager/" + "Getallmcipolicy"; + var controller = "/api/" + "mc-infra-manager/" + "GetAllInfraPolicy"; try { const response = await webconsolejs["common/api/http"].commonAPIPost( @@ -795,7 +795,7 @@ export async function deletePolicy(nsId, mciId) { option: "force" } }; - let controller = "/api/" + "mc-infra-manager/" + "Delmcipolicy"; + let controller = "/api/" + "mc-infra-manager/" + "DelInfraPolicy"; let response = webconsolejs["common/api/http"].commonAPIPost( controller, data @@ -816,7 +816,7 @@ export async function createPolicy(nsId, mciId, policy) { policy: policy } }; - let controller = "/api/" + "mc-infra-manager/" + "Postmcipolicy"; + let controller = "/api/" + "mc-infra-manager/" + "PostInfraPolicy"; let response = await webconsolejs["common/api/http"].commonAPIPost( controller, data diff --git a/front/assets/js/common/api/services/readyz_api.js b/front/assets/js/common/api/services/readyz_api.js index d5ec3c3e..b7c527b2 100644 --- a/front/assets/js/common/api/services/readyz_api.js +++ b/front/assets/js/common/api/services/readyz_api.js @@ -25,20 +25,24 @@ const READYZ_EXCLUDE = new Set(['mc-web-console', 'mc-infra-connector']); /** * ListMcmpApisServices 응답(services 맵)으로부터 readyz 대상 프레임워크 목록 생성 * @param {Object} services - { "mc-infra-manager": { BaseURL, Version }, ... } + * @param {Object} serviceActions - { "mc-infra-manager": { "Getreadyz": { Method, ResourcePath }, ... }, ... } * @returns {Array<{ name, subsystem, operationId, initOperationId }>} */ -export function buildFrameworkList(services) { +export function buildFrameworkList(services, serviceActions = {}) { return Object.keys(services) .filter(name => !READYZ_EXCLUDE.has(name)) .sort() .map(name => { - const mapping = READYZ_OPERATIONID_MAP[name] || { operationId: null, initOperationId: null }; - return { - name, - subsystem: name, - operationId: mapping.operationId, - initOperationId: mapping.initOperationId, - }; + // ServiceActions에서 ResourcePath가 /readyz로 끝나는 action 자동 탐색 + const actions = serviceActions[name] || {}; + const readyzEntry = Object.entries(actions).find(([, spec]) => + spec.ResourcePath && spec.ResourcePath.split('?')[0].split('/').pop() === 'readyz' + ); + const operationId = readyzEntry + ? readyzEntry[0] + : (READYZ_OPERATIONID_MAP[name]?.operationId || null); + const initOperationId = READYZ_OPERATIONID_MAP[name]?.initOperationId || null; + return { name, subsystem: name, operationId, initOperationId }; }); } @@ -65,14 +69,14 @@ export async function callInit(subsystem, operationId) { } /** - * mc-iam-manager에서 전체 프레임워크 서비스 목록(BaseURL) 조회 - * @returns {Promise} { "mc-infra-manager": { Version, BaseURL, Auth }, ... } + * mc-iam-manager에서 전체 프레임워크 서비스 목록(BaseURL + ServiceActions) 조회 + * @returns {Promise<{ services: Object, serviceActions: Object }>} */ export async function listFrameworkServices() { const url = `/api/mc-iam-manager/ListMcmpApisServices`; const res = await webconsolejs["common/api/http"].commonAPIPost(url, {}, undefined, { loaderType: 'none' }); const d = res && res.data ? (res.data.responseData || res.data) : {}; - return d.Services || {}; + return { services: d.Services || {}, serviceActions: d.ServiceActions || {} }; } /** @@ -89,6 +93,13 @@ export async function updateFrameworkServiceUrl(serviceName, baseUrl) { }, undefined, { loaderType: 'none' }); } +export async function createFrameworkServiceUrl(serviceName, baseUrl) { + const url = `/api/mc-iam-manager/CreateFrameworkService`; + return await webconsolejs["common/api/http"].commonAPIPost(url, { + request: { name: serviceName, version: "v1", baseUrl: baseUrl, authType: "none", isActive: true }, + }, undefined, { loaderType: 'none' }); +} + /** * readyz 응답에서 상태 파싱 * ready 필드가 있으면 그 값을 사용, 없으면 HTTP 200 = ok diff --git a/front/assets/js/common/api/services/remotecmd_api.js b/front/assets/js/common/api/services/remotecmd_api.js index 337a49b2..6a382a83 100644 --- a/front/assets/js/common/api/services/remotecmd_api.js +++ b/front/assets/js/common/api/services/remotecmd_api.js @@ -76,7 +76,7 @@ export async function postRemoteCmd(nsid, resourceId, targetId, cmdarr, targetTy if (targetType === 'cluster') { controller = "/api/" + "mc-infra-manager/" + "Postclusterremotecmd"; } else { - controller = "/api/" + "mc-infra-manager/" + "Postcmdmci"; + controller = "/api/" + "mc-infra-manager/" + "PostCmdInfra"; } const response = await webconsolejs["common/api/http"].commonAPIPost(controller, data); @@ -118,7 +118,7 @@ export async function postFileToMci(nsId, mciId, file, targetPath, targetType, t } // 'mci' 타입은 query parameter 없음 - const controller = "/api/mc-infra-manager/Postfiletomci"; + const controller = "/api/mc-infra-manager/PostFileToInfra"; const response = await webconsolejs["common/api/http"].commonAPIPost(controller, data); diff --git a/front/assets/js/common/iframe/iframe.js b/front/assets/js/common/iframe/iframe.js index 1eac326a..9fd33a24 100644 --- a/front/assets/js/common/iframe/iframe.js +++ b/front/assets/js/common/iframe/iframe.js @@ -19,7 +19,6 @@ export async function GetApiHosts(frameworkName){ const framework = getapihostsresponse.data.responseData[frameworkName]; if (framework && framework.BaseURL) { return framework.BaseURL; - } else { - return 'Framework not found'; } + return null; } diff --git a/front/assets/js/pages/operation/analytics/dashboard.js b/front/assets/js/pages/operation/analytics/dashboard.js index 269de16c..e1dec825 100644 --- a/front/assets/js/pages/operation/analytics/dashboard.js +++ b/front/assets/js/pages/operation/analytics/dashboard.js @@ -118,8 +118,8 @@ async function loadMciList(nsId) { if (!nsId) return; try { var result = await webconsolejs['common/api/services/mci_api'].getMciList(nsId); - // getMciList returns responseData which is { mci: [...] } or array - var mciList = Array.isArray(result) ? result : (result && result.mci ? result.mci : []); + // getMciList returns responseData which is { infra: [...] } or array + var mciList = Array.isArray(result) ? result : (result && result.infra ? result.infra : []); mciList.forEach(function (mci) { var id = mci.id || mci.mciId || mci.name; $mciSel.append(''); diff --git a/front/assets/js/pages/operation/analytics/logmanage.js b/front/assets/js/pages/operation/analytics/logmanage.js index ace132a1..1c1c620c 100644 --- a/front/assets/js/pages/operation/analytics/logmanage.js +++ b/front/assets/js/pages/operation/analytics/logmanage.js @@ -76,7 +76,7 @@ function getMciListCallbackSuccess(nsId, mciList) { // MCI 목록을 셀렉트 박스에 설정 function setMciList(mciList) { - var res_item = mciList.mci; + var res_item = mciList.infra; // res_item이 배열인지 확인 if (Array.isArray(res_item)) { diff --git a/front/assets/js/pages/operation/analytics/monitoringconfig.js b/front/assets/js/pages/operation/analytics/monitoringconfig.js index ece314cb..1c9994dc 100644 --- a/front/assets/js/pages/operation/analytics/monitoringconfig.js +++ b/front/assets/js/pages/operation/analytics/monitoringconfig.js @@ -128,7 +128,7 @@ async function initMonitorConfig() { // workload 목록 조회 ( mci + pmk ) async function getWorkloadList(nsId){ var respMciList = await webconsolejs["common/api/services/mci_api"].getMciList(nsId); - var res_item = respMciList.mci + var res_item = respMciList.infra // HTML option 리스트 초기값 var html = ''; diff --git a/front/assets/js/pages/operation/manage/mci.js b/front/assets/js/pages/operation/manage/mci.js index 787d3007..c707b177 100644 --- a/front/assets/js/pages/operation/manage/mci.js +++ b/front/assets/js/pages/operation/manage/mci.js @@ -118,7 +118,7 @@ export async function refreshMciList() { // getMciList 호출 성공 시 async function getMciListCallbackSuccess(caller, mciList) { - window.totalMciListObj = mciList.mci; + window.totalMciListObj = mciList.infra; // Update label key dropdown with actual keys from MCI data updateLabelKeyDropdown(); diff --git a/front/assets/js/pages/operation/manage/monitoring.js b/front/assets/js/pages/operation/manage/monitoring.js index 8991fd1b..3379150c 100644 --- a/front/assets/js/pages/operation/manage/monitoring.js +++ b/front/assets/js/pages/operation/manage/monitoring.js @@ -80,7 +80,7 @@ function getMciListCallbackSuccess(nsId, mciList) { } function setMciList(mciList) { - var res_item = mciList.mci; + var res_item = mciList.infra; // res_item이 배열인지 확인 if (Array.isArray(res_item)) { diff --git a/front/assets/js/pages/operation/plugins/costoptimizer.iframe.js b/front/assets/js/pages/operation/plugins/costoptimizer.iframe.js index 37eabb95..26209b60 100644 --- a/front/assets/js/pages/operation/plugins/costoptimizer.iframe.js +++ b/front/assets/js/pages/operation/plugins/costoptimizer.iframe.js @@ -11,9 +11,9 @@ function getCostOptimizerData() { const currentProject = webconsolejs["common/api/services/workspace_api"].getCurrentProject(); console.log("Current Workspace:", currentWorkspace); console.log("Current Project:", currentProject); - + const accessToken = webconsolejs["common/storage/sessionstorage"].getSessionCurrentUserToken(); - + return { accessToken: accessToken, workspaceInfo: { @@ -29,13 +29,41 @@ function getCostOptimizerData() { }; } -document.addEventListener("DOMContentLoaded", async function(){ - var host = await webconsolejs["common/iframe/iframe"].GetApiHosts("mc-cost-optimizer") - const domain = window.location.protocol + '//' + window.location.hostname; - if (host.startsWith(":")) { - host = `${domain}${host}`; +async function loadCostOptimizer() { + const currentWorkspace = webconsolejs["common/api/services/workspace_api"].getCurrentWorkspace(); + const currentProject = webconsolejs["common/api/services/workspace_api"].getCurrentProject(); + + if (!currentWorkspace || !currentWorkspace.Id || !currentProject || !currentProject.Id) { + document.getElementById("costIframe").innerHTML = + '
Workspace와 Project를 선택해 주세요.
'; + return; } + + var host = await webconsolejs["common/iframe/iframe"].GetApiHosts("mc-cost-optimizer-fe"); + if (!host) { + document.getElementById("costIframe").innerHTML = + '
mc-cost-optimizer-fe 서비스 URL을 찾을 수 없습니다.
' + + 'Settings > Environment > Cloud SPs > Cloud Overview 에서 mc-cost-optimizer-fe URL을 등록해 주세요.
'; + return; + } + // IFRAME_TARGET_IS_HOST=true 환경에서 :port 형식으로 오던 값에 browser origin을 붙이던 로직. + // GetApiHosts가 DB full URL을 그대로 전달하도록 변경되어 비활성화. + // const domain = window.location.protocol + '//' + window.location.hostname; + // if (host.startsWith(":")) { + // host = `${domain}${host}`; + // } const data = getCostOptimizerData(); - webconsolejs["common/iframe/iframe"].addIframe("costIframe", host, data) -}); \ No newline at end of file + webconsolejs["common/iframe/iframe"].addIframe("costIframe", host, data); +} + +// project 변경 시 iframe 재로드 +$("#select-current-project").on('change', async function () { + let project = { "Id": this.value, "Name": this.options[this.selectedIndex].text, "NsId": this.options[this.selectedIndex].text }; + webconsolejs["common/api/services/workspace_api"].setCurrentProject(project); + await loadCostOptimizer(); +}); + +document.addEventListener("DOMContentLoaded", async function(){ + await loadCostOptimizer(); +}); diff --git a/front/assets/js/pages/operation/plugins/datamanager.iframe.js b/front/assets/js/pages/operation/plugins/datamanager.iframe.js index b24d5463..4c226baf 100644 --- a/front/assets/js/pages/operation/plugins/datamanager.iframe.js +++ b/front/assets/js/pages/operation/plugins/datamanager.iframe.js @@ -1,38 +1,51 @@ -// const data = { -// projectid: 'mzctestPrj', -// workspaceid: 'mzctestWs', -// usertoken: 'mzctoken' -// }; +function getDataManagerData() { + const currentWorkspace = webconsolejs["common/api/services/workspace_api"].getCurrentWorkspace(); + const currentProject = webconsolejs["common/api/services/workspace_api"].getCurrentProject(); + const accessToken = webconsolejs["common/storage/sessionstorage"].getSessionCurrentUserToken(); -// 데모환경에서 사용할 예제 데이터 입니다. -const data = { - accessToken: "accesstokenExample", - workspaceInfo: { - "id": "UUID", // 이부분은 UUID로 별도 정보가 필요할시 해당 ID 를 활용해 IAM 과 연동하시면됩니다. - "name": "ws01", // Display 용 이름입니다. - "description": "ws01 desc", // 설명입니다. - "created_at": "UTC", - "updated_at": "UTC" - }, - projectInfo: { - "id": "UUID", // 이부분은 UUID로 별도 정보가 필요할시 해당 ID 를 활용해 IAM 과 연동하시면됩니다. - "ns_id": "ns01", // 텀블벅 연동 ID 입니다. - "name": "ns01", // Display 용 이름입니다. - "description": "ns01 desc", // 설명입니다. - "created_at": "UTC", - "updated_at": "UTC" - }, - requestOperationId: "" -}; + return { + accessToken: accessToken, + workspaceInfo: { + "id": currentWorkspace.Id, + "name": currentWorkspace.Name, + }, + projectInfo: { + "id": currentProject.Id, + "ns_id": currentProject.NsId, + "name": currentProject.Name, + }, + requestOperationId: "" + }; +} -document.addEventListener("DOMContentLoaded", async function(){ - var host = await webconsolejs["common/iframe/iframe"].GetApiHosts("mc-data-manager") +async function loadDataManager() { + const currentWorkspace = webconsolejs["common/api/services/workspace_api"].getCurrentWorkspace(); + const currentProject = webconsolejs["common/api/services/workspace_api"].getCurrentProject(); - // 포트만 반환된 경우 현재 호스트 이름 추가 - if (host.startsWith(":")) { - const currentHost = window.location.protocol + "//" + window.location.hostname; - host = currentHost + host; + if (!currentWorkspace || !currentWorkspace.Id || !currentProject || !currentProject.Id) { + document.getElementById("targetIframe").innerHTML = + '
Workspace와 Project를 선택해 주세요.
'; + return; } - webconsolejs["common/iframe/iframe"].addIframe("targetIframe", host, data) -}); \ No newline at end of file + var host = await webconsolejs["common/iframe/iframe"].GetApiHosts("mc-data-manager-fe"); + if (!host) { + document.getElementById("targetIframe").innerHTML = + '
mc-data-manager-fe 서비스 URL을 찾을 수 없습니다.
' + + 'Settings > Environment에서 mc-data-manager-fe URL을 등록해 주세요.
'; + return; + } + + const data = getDataManagerData(); + webconsolejs["common/iframe/iframe"].addIframe("targetIframe", host, data); +} + +$("#select-current-project").on('change', async function () { + let project = { "Id": this.value, "Name": this.options[this.selectedIndex].text, "NsId": this.options[this.selectedIndex].text }; + webconsolejs["common/api/services/workspace_api"].setCurrentProject(project); + await loadDataManager(); +}); + +document.addEventListener("DOMContentLoaded", async function () { + await loadDataManager(); +}); diff --git a/front/assets/js/pages/operation/plugins/softwaremanager.iframe.js b/front/assets/js/pages/operation/plugins/softwaremanager.iframe.js index 20789e8d..58946b8d 100644 --- a/front/assets/js/pages/operation/plugins/softwaremanager.iframe.js +++ b/front/assets/js/pages/operation/plugins/softwaremanager.iframe.js @@ -1,40 +1,51 @@ -// 동적으로 workspace와 project 정보를 가져오는 함수 function getSoftwareManagerData() { + const currentWorkspace = webconsolejs["common/api/services/workspace_api"].getCurrentWorkspace(); + const currentProject = webconsolejs["common/api/services/workspace_api"].getCurrentProject(); + const accessToken = webconsolejs["common/storage/sessionstorage"].getSessionCurrentUserToken(); - const currentWorkspace = webconsolejs["common/api/services/workspace_api"].getCurrentWorkspace(); - const currentProject = webconsolejs["common/api/services/workspace_api"].getCurrentProject(); - console.log("Current Workspace:", currentWorkspace); - console.log("Current Project:", currentProject); - - const accessToken = webconsolejs["common/storage/sessionstorage"].getSessionCurrentUserToken(); - - return { - accessToken: accessToken, - workspaceInfo: { - "id": currentWorkspace.Id, - "name": currentWorkspace.Name, - }, - projectInfo: { - "id": currentProject.Id , - "ns_id": currentProject.NsId, - "name": currentProject.Name, - }, - requestOperationId: "" - }; + return { + accessToken: accessToken, + workspaceInfo: { + "id": currentWorkspace.Id, + "name": currentWorkspace.Name, + }, + projectInfo: { + "id": currentProject.Id, + "ns_id": currentProject.NsId, + "name": currentProject.Name, + }, + requestOperationId: "" + }; } -document.addEventListener("DOMContentLoaded", async function(){ - var host = await webconsolejs["common/iframe/iframe"].GetApiHosts("mc-application-manager") +async function loadSoftwareManager() { + const currentWorkspace = webconsolejs["common/api/services/workspace_api"].getCurrentWorkspace(); + const currentProject = webconsolejs["common/api/services/workspace_api"].getCurrentProject(); - // 포트만 반환된 경우 현재 호스트 이름 추가 - if (host.startsWith(":")) { - const currentHost = window.location.protocol + "//" + window.location.hostname; - host = currentHost + host; + if (!currentWorkspace || !currentWorkspace.Id || !currentProject || !currentProject.Id) { + document.getElementById("targetIframe-sofrwareCatalog").innerHTML = + '
Workspace와 Project를 선택해 주세요.
'; + return; + } + + var host = await webconsolejs["common/iframe/iframe"].GetApiHosts("mc-application-manager-fe"); + if (!host) { + document.getElementById("targetIframe-sofrwareCatalog").innerHTML = + '
mc-application-manager-fe 서비스 URL을 찾을 수 없습니다.
' + + 'Settings > Environment에서 mc-application-manager-fe URL을 등록해 주세요.
'; + return; } - // 동적으로 데이터 가져오기 const data = getSoftwareManagerData(); + webconsolejs["common/iframe/iframe"].addIframe("targetIframe-sofrwareCatalog", host + "/web/softwareCatalog", data); +} + +$("#select-current-project").on('change', async function () { + let project = { "Id": this.value, "Name": this.options[this.selectedIndex].text, "NsId": this.options[this.selectedIndex].text }; + webconsolejs["common/api/services/workspace_api"].setCurrentProject(project); + await loadSoftwareManager(); +}); - // webconsolejs["common/iframe/iframe"].addIframe("targetIframe-repository", host+"/web/repository/list", data) - webconsolejs["common/iframe/iframe"].addIframe("targetIframe-sofrwareCatalog", host+"/web/softwareCatalog", data) -}); \ No newline at end of file +document.addEventListener("DOMContentLoaded", async function () { + await loadSoftwareManager(); +}); diff --git a/front/assets/js/pages/operation/plugins/workflowmanager.iframe.js b/front/assets/js/pages/operation/plugins/workflowmanager.iframe.js index 7c6b3d61..37b11411 100644 --- a/front/assets/js/pages/operation/plugins/workflowmanager.iframe.js +++ b/front/assets/js/pages/operation/plugins/workflowmanager.iframe.js @@ -1,37 +1,51 @@ -// const data = { -// projectid: 'mzctestPrj', -// workspaceid: 'mzctestWs', -// usertoken: 'mzctoken' -// }; -// 데모환경에서 사용할 예제 데이터 입니다. -const data = { - accessToken: "accesstokenExample", - workspaceInfo: { - "id": "UUID", // 이부분은 UUID로 별도 정보가 필요할시 해당 ID 를 활용해 IAM 과 연동하시면됩니다. - "name": "ws01", // Display 용 이름입니다. - "description": "ws01 desc", // 설명입니다. - "created_at": "UTC", - "updated_at": "UTC" - }, - projectInfo: { - "id": "UUID", // 이부분은 UUID로 별도 정보가 필요할시 해당 ID 를 활용해 IAM 과 연동하시면됩니다. - "ns_id": "ns01", // 텀블벅 연동 ID 입니다. - "name": "ns01", // Display 용 이름입니다. - "description": "ns01 desc", // 설명입니다. - "created_at": "UTC", - "updated_at": "UTC" - }, - requestOperationId: "" -}; +function getWorkflowManagerData() { + const currentWorkspace = webconsolejs["common/api/services/workspace_api"].getCurrentWorkspace(); + const currentProject = webconsolejs["common/api/services/workspace_api"].getCurrentProject(); + const accessToken = webconsolejs["common/storage/sessionstorage"].getSessionCurrentUserToken(); -document.addEventListener("DOMContentLoaded", async function(){ - var host = await webconsolejs["common/iframe/iframe"].GetApiHosts("mc-workflow-manager") + return { + accessToken: accessToken, + workspaceInfo: { + "id": currentWorkspace.Id, + "name": currentWorkspace.Name, + }, + projectInfo: { + "id": currentProject.Id, + "ns_id": currentProject.NsId, + "name": currentProject.Name, + }, + requestOperationId: "" + }; +} - // 포트만 반환된 경우 현재 호스트 이름 추가 - if (host.startsWith(":")) { - const currentHost = window.location.protocol + "//" + window.location.hostname; - host = currentHost + host; +async function loadWorkflowManager() { + const currentWorkspace = webconsolejs["common/api/services/workspace_api"].getCurrentWorkspace(); + const currentProject = webconsolejs["common/api/services/workspace_api"].getCurrentProject(); + + if (!currentWorkspace || !currentWorkspace.Id || !currentProject || !currentProject.Id) { + document.getElementById("targetIframe").innerHTML = + '
Workspace와 Project를 선택해 주세요.
'; + return; + } + + var host = await webconsolejs["common/iframe/iframe"].GetApiHosts("mc-workflow-manager-fe"); + if (!host) { + document.getElementById("targetIframe").innerHTML = + '
mc-workflow-manager-fe 서비스 URL을 찾을 수 없습니다.
' + + 'Settings > Environment에서 mc-workflow-manager-fe URL을 등록해 주세요.
'; + return; } - webconsolejs["common/iframe/iframe"].addIframe("targetIframe", host+"/web/workflow/list", data) + const data = getWorkflowManagerData(); + webconsolejs["common/iframe/iframe"].addIframe("targetIframe", host + "/web/workflow/list", data); +} + +$("#select-current-project").on('change', async function () { + let project = { "Id": this.value, "Name": this.options[this.selectedIndex].text, "NsId": this.options[this.selectedIndex].text }; + webconsolejs["common/api/services/workspace_api"].setCurrentProject(project); + await loadWorkflowManager(); +}); + +document.addEventListener("DOMContentLoaded", async function () { + await loadWorkflowManager(); }); diff --git a/front/assets/js/pages/operations/analytics/eventsntraces/logconfig.js b/front/assets/js/pages/operations/analytics/eventsntraces/logconfig.js index d6d71aec..045dff1a 100644 --- a/front/assets/js/pages/operations/analytics/eventsntraces/logconfig.js +++ b/front/assets/js/pages/operations/analytics/eventsntraces/logconfig.js @@ -75,7 +75,7 @@ const LogConfigManager = { : { nsId: 'system' }; const nsId = (workspace && workspace.nsId) ? workspace.nsId : 'system'; const respMciList = await webconsolejs["common/api/services/mci_api"].getMciList(nsId); - const mciList = (respMciList && respMciList.mci) ? respMciList.mci : []; + const mciList = (respMciList && respMciList.infra) ? respMciList.infra : []; if (DOM.mciSelect) { DOM.mciSelect.innerHTML = ''; diff --git a/front/assets/js/pages/settings/environment/cloudsps/cloudoverview.js b/front/assets/js/pages/settings/environment/cloudsps/cloudoverview.js index 41a24990..fec268d4 100644 --- a/front/assets/js/pages/settings/environment/cloudsps/cloudoverview.js +++ b/front/assets/js/pages/settings/environment/cloudsps/cloudoverview.js @@ -468,6 +468,18 @@ export async function saveFrameworkUrl(frameworkName) { await ReadyzManager.saveFrameworkUrl(frameworkName); } +export function showAddServiceRow() { + ReadyzManager.showAddServiceRow(); +} + +export async function saveNewService() { + await ReadyzManager.saveNewService(); +} + +export function cancelAddService() { + ReadyzManager.cancelAddService(); +} + export async function toggleSelectedCspStatus() { if (!AppState.csp.selectedAccount) return; @@ -498,9 +510,9 @@ const ReadyzManager = { /** mc-iam-manager에서 framework 서비스 주소 로드 + 동적 목록 빌드 */ async loadFrameworkServices() { try { - const services = await readyzApi().listFrameworkServices(); + const { services, serviceActions } = await readyzApi().listFrameworkServices(); AppState.frameworkServices = services || {}; - AppState.frameworkList = readyzApi().buildFrameworkList(AppState.frameworkServices); + AppState.frameworkList = readyzApi().buildFrameworkList(AppState.frameworkServices, serviceActions); } catch (e) { console.warn('loadFrameworkServices failed:', e.message); AppState.frameworkServices = {}; @@ -716,6 +728,59 @@ const ReadyzManager = { if (desc && message) desc.textContent = (desc.textContent ? desc.textContent + ' | ' : '') + message; }, + /** Add Service 입력 행 표시 */ + showAddServiceRow() { + if (document.getElementById('readyz-add-service-row')) return; + const tbody = document.getElementById('readyz-table-body'); + if (!tbody) return; + const row = document.createElement('tr'); + row.id = 'readyz-add-service-row'; + row.innerHTML = ` + + + + +
+ + + +
+ + + `; + tbody.insertBefore(row, tbody.firstChild); + document.getElementById('readyz-add-service-name').focus(); + }, + + /** Add Service 저장 → mc-iam-manager → 테이블 갱신 */ + async saveNewService() { + const nameInput = document.getElementById('readyz-add-service-name'); + const urlInput = document.getElementById('readyz-add-service-url'); + if (!nameInput || !urlInput) return; + const serviceName = nameInput.value.trim(); + const serviceUrl = urlInput.value.trim(); + if (!serviceName) { alert('Service name을 입력하세요.'); nameInput.focus(); return; } + if (!serviceUrl) { alert('URL을 입력하세요.'); urlInput.focus(); return; } + try { + await readyzApi().createFrameworkServiceUrl(serviceName, serviceUrl); + this.cancelAddService(); + await this.loadFrameworkServices(); + this.renderTable(); + } catch (e) { + alert('서비스 등록 실패: ' + (e.message || String(e))); + } + }, + + /** Add Service 입력 행 취소 */ + cancelAddService() { + const row = document.getElementById('readyz-add-service-row'); + if (row) row.remove(); + }, + _esc(str) { return (str || '').replace(/"/g, '"'); }, diff --git a/front/assets/js/pages/settings/environment/cloudsps/connections.js b/front/assets/js/pages/settings/environment/cloudsps/connections.js new file mode 100644 index 00000000..21b43457 --- /dev/null +++ b/front/assets/js/pages/settings/environment/cloudsps/connections.js @@ -0,0 +1,195 @@ +import { TabulatorFull as Tabulator } from "tabulator-tables"; + +const DOM = { + connectionTable: document.getElementById('connection-table'), + detailPanel: document.getElementById('connection-detail-panel'), + detailNameLabel: document.getElementById('connection-detail-name-label'), + detailNameText: document.getElementById('connection-detail-name-text'), + filterSelect: document.getElementById('filter-credential-holder'), +}; + +const AppState = { + connections: [], + selectedConnection: null, + tables: { connectionTable: null }, +}; + +const PROVIDER_BADGE = { + aws: 'AWS', + gcp: 'GCP', + azure: 'Azure', + alibaba: 'Alibaba', + ncp: 'NCP', + nhncloud: 'NHN', + ktcloud: 'KT', + tencent: 'Tencent', +}; + +function getProviderBadge(provider) { + if (!provider) return '-'; + const key = (provider || '').toLowerCase(); + return PROVIDER_BADGE[key] || `${provider}`; +} + +function getVerifiedBadge(verified) { + return verified + ? 'Verified' + : 'Unverified'; +} + +// ─── TableManager ────────────────────────────────────────────────── + +const TableManager = { + initTable(data) { + if (AppState.tables.connectionTable) { + AppState.tables.connectionTable.replaceData(data); + return; + } + AppState.tables.connectionTable = new Tabulator('#connection-table', { + data, + layout: 'fitColumns', + placeholder: 'No Connections Found', + pagination: 'local', + paginationSize: 15, + paginationSizeSelector: [15, 30, 50], + paginationCounter: 'rows', + columns: [ + { + formatter: 'rowSelection', + titleFormatter: 'rowSelection', + hozAlign: 'center', + headerSort: false, + width: 40, + cellClick(e, cell) { cell.getRow().toggleSelect(); }, + }, + { title: 'Config Name', field: 'configName', sorter: 'string' }, + { title: 'Credential Holder', field: 'credentialHolder', sorter: 'string', width: 160 }, + { + title: 'Provider', + field: 'providerName', + formatter(cell) { return getProviderBadge(cell.getValue()); }, + width: 110, + }, + { title: 'Region Zone Info', field: 'regionZoneInfoName', sorter: 'string' }, + { + title: 'Verified', + field: 'verified', + formatter(cell) { return getVerifiedBadge(cell.getValue()); }, + hozAlign: 'center', + width: 110, + }, + ], + rowClick(e, row) { + ConnectionManager.loadDetail(row.getData().configName); + }, + }); + }, +}; + +// ─── UIManager ────────────────────────────────────────────────────── + +const UIManager = { + showDetail(conn) { + AppState.selectedConnection = conn; + + if (DOM.detailNameLabel) DOM.detailNameLabel.style.display = ''; + if (DOM.detailNameText) DOM.detailNameText.textContent = conn.configName || '-'; + + document.getElementById('detail-config-name').textContent = conn.configName || '-'; + document.getElementById('detail-credential-holder').textContent = conn.credentialHolder || '-'; + document.getElementById('detail-credential-name').textContent = conn.credentialName || '-'; + document.getElementById('detail-driver-name').textContent = conn.driverName || '-'; + document.getElementById('detail-provider-name').innerHTML = getProviderBadge(conn.providerName); + document.getElementById('detail-region-zone-info-name').textContent = conn.regionZoneInfoName || '-'; + + const regionDetail = conn.regionDetail || {}; + document.getElementById('detail-region-id').textContent = regionDetail.regionId || '-'; + const zones = Array.isArray(regionDetail.zones) ? regionDetail.zones.join(', ') : (regionDetail.zones || '-'); + document.getElementById('detail-zones').textContent = zones; + + const regionZoneInfo = conn.regionZoneInfo || {}; + document.getElementById('detail-assigned-region').textContent = regionZoneInfo.assignedRegion || '-'; + document.getElementById('detail-assigned-zone').textContent = regionZoneInfo.assignedZone || '-'; + + document.getElementById('detail-verified').innerHTML = getVerifiedBadge(conn.verified); + document.getElementById('detail-region-representative').innerHTML = conn.regionRepresentative + ? 'Yes' + : 'No'; + + if (DOM.detailPanel) DOM.detailPanel.style.display = ''; + }, + + hideDetail() { + AppState.selectedConnection = null; + if (DOM.detailPanel) DOM.detailPanel.style.display = 'none'; + }, +}; + +// ─── ConnectionManager ────────────────────────────────────────────── + +const ConnectionManager = { + async loadConnections(credentialHolder = '') { + try { + const connections = await webconsolejs["common/api/services/connection_config_api"].filterConnConfigByCredentialHolder(credentialHolder); + AppState.connections = connections; + TableManager.initTable(connections); + } catch (e) { + console.error('Connection 목록 조회 실패:', e); + TableManager.initTable([]); + } + }, + + async loadDetail(configName) { + try { + const conn = await webconsolejs["common/api/services/connection_config_api"].getConnConfig(configName); + if (conn) { + UIManager.showDetail(conn); + } + } catch (e) { + console.error('Connection 상세 조회 실패:', e); + } + }, + + async populateHolderFilter() { + try { + const result = await webconsolejs["common/api/services/credential_holder_api"].getCredentialHolderList(); + const holders = (result && result.credentialHolderList) ? result.credentialHolderList + : Array.isArray(result) ? result : []; + const select = DOM.filterSelect; + if (!select) return; + holders.forEach(h => { + const opt = document.createElement('option'); + opt.value = h.credentialHolder; + opt.textContent = h.credentialHolder; + select.appendChild(opt); + }); + } catch (e) { + console.error('CredentialHolder 목록 조회 실패:', e); + } + }, +}; + +// ─── Public exports ────────────────────────────────────────────────── + +export function refreshConnectionList() { + const holder = DOM.filterSelect ? DOM.filterSelect.value : ''; + ConnectionManager.loadConnections(holder); +} + +export function hideDetail() { + UIManager.hideDetail(); +} + +// ─── Init ────────────────────────────────────────────────────────── + +document.addEventListener('DOMContentLoaded', async () => { + await ConnectionManager.populateHolderFilter(); + await ConnectionManager.loadConnections(''); + + if (DOM.filterSelect) { + DOM.filterSelect.addEventListener('change', () => { + ConnectionManager.loadConnections(DOM.filterSelect.value); + UIManager.hideDetail(); + }); + } +}); diff --git a/front/assets/js/pages/settings/environment/cloudsps/credentials.js b/front/assets/js/pages/settings/environment/cloudsps/credentials.js index dc492118..87570438 100644 --- a/front/assets/js/pages/settings/environment/cloudsps/credentials.js +++ b/front/assets/js/pages/settings/environment/cloudsps/credentials.js @@ -1,48 +1,97 @@ import { TabulatorFull as Tabulator } from "tabulator-tables"; const DOM = { - credentialTable: document.getElementById('credential-table'), + holderTable: document.getElementById('credential-table'), detailPanel: document.getElementById('credential-detail-panel'), detailNameLabel: document.getElementById('credential-detail-name-label'), detailNameText: document.getElementById('credential-detail-name-text'), + kvContainer: document.getElementById('kv-list-container'), }; const AppState = { - credentials: [], - selectedCredential: null, - tables: { credentialTable: null }, + holders: [], + selectedHolder: null, + tables: { holderTable: null }, }; const PROVIDER_BADGE = { - AWS: 'AWS', - GCP: 'GCP', - AZURE: 'Azure', + aws: 'AWS', + gcp: 'GCP', + azure: 'Azure', }; function getProviderBadge(provider) { if (!provider) return '-'; - const key = (provider || '').toUpperCase(); + const key = (provider || '').toLowerCase(); return PROVIDER_BADGE[key] || `${provider}`; } -function getActiveBadge(active) { - return active - ? 'Active' - : 'Inactive'; +function getProvidersBadges(providers) { + if (!providers || !Array.isArray(providers) || providers.length === 0) return '-'; + return providers.map(p => getProviderBadge(p)).join(' '); } +function getDefaultBadge(isDefault) { + return isDefault + ? 'Default' + : 'Custom'; +} + +// ─── KV Row 관리 ────────────────────────────────────────────────── + +const KVManager = { + addRow(key = '', value = '') { + const container = document.getElementById('kv-list-container'); + if (!container) return; + const row = document.createElement('div'); + row.className = 'row g-2 mb-2 kv-row'; + row.innerHTML = ` +
+ +
+
+ +
+
+ +
`; + container.appendChild(row); + }, + + getKVList() { + const rows = document.querySelectorAll('#kv-list-container .kv-row'); + return Array.from(rows).map(row => ({ + key: row.querySelector('.kv-key').value.trim(), + value: row.querySelector('.kv-value').value.trim(), + })).filter(kv => kv.key !== ''); + }, + + reset() { + const container = document.getElementById('kv-list-container'); + if (container) container.innerHTML = ''; + KVManager.addRow(); + }, +}; + // ─── TableManager ────────────────────────────────────────────────── const TableManager = { initTable(data) { - if (AppState.tables.credentialTable) { - AppState.tables.credentialTable.replaceData(data); + if (AppState.tables.holderTable) { + AppState.tables.holderTable.replaceData(data); return; } - AppState.tables.credentialTable = new Tabulator('#credential-table', { + AppState.tables.holderTable = new Tabulator('#credential-table', { data, layout: 'fitColumns', - placeholder: 'No Credentials Found', + placeholder: 'No Credential Holders Found', pagination: 'local', paginationSize: 10, paginationSizeSelector: [10, 20, 50], @@ -56,24 +105,21 @@ const TableManager = { width: 40, cellClick(e, cell) { cell.getRow().toggleSelect(); }, }, - { title: 'ID', field: 'id', sorter: 'number', width: 80 }, - { title: 'Name', field: 'name', sorter: 'string' }, + { title: 'Credential Holder', field: 'credentialHolder', sorter: 'string' }, { - title: 'Provider', - field: 'cspType', - formatter(cell) { return getProviderBadge(cell.getValue()); }, + title: 'Providers', + field: 'providers', + formatter(cell) { return getProvidersBadges(cell.getValue()); }, }, + { title: 'Connections', field: 'connectionCount', sorter: 'number', hozAlign: 'center', width: 120 }, + { title: 'Verified', field: 'verifiedConnectionCount', sorter: 'number', hozAlign: 'center', width: 100 }, { - title: 'Active', - field: 'isActive', - formatter(cell) { return getActiveBadge(cell.getValue()); }, + title: 'Default', + field: 'isDefault', + formatter(cell) { return getDefaultBadge(cell.getValue()); }, hozAlign: 'center', width: 100, }, - { title: 'Created At', field: 'createdAt', sorter: 'string', formatter(cell) { - const v = cell.getValue(); - return v ? new Date(v).toLocaleString() : '-'; - }}, ], rowClick(e, row) { UIManager.showDetail(row.getData()); @@ -85,95 +131,74 @@ const TableManager = { // ─── UIManager ────────────────────────────────────────────────────── const UIManager = { - showDetail(cred) { - AppState.selectedCredential = cred; + showDetail(holder) { + AppState.selectedHolder = holder; if (DOM.detailNameLabel) DOM.detailNameLabel.style.display = ''; - if (DOM.detailNameText) DOM.detailNameText.textContent = cred.name || '-'; + if (DOM.detailNameText) DOM.detailNameText.textContent = holder.credentialHolder || '-'; - document.getElementById('detail-cred-id').textContent = cred.id || '-'; - document.getElementById('detail-cred-name').textContent = cred.name || '-'; - document.getElementById('detail-cred-provider').innerHTML = getProviderBadge(cred.cspType); - document.getElementById('detail-cred-status').textContent = cred.status || '-'; - document.getElementById('detail-cred-active').innerHTML = getActiveBadge(cred.isActive); - document.getElementById('detail-cred-created').textContent = cred.createdAt - ? new Date(cred.createdAt).toLocaleString() - : '-'; + document.getElementById('detail-holder-id').textContent = holder.credentialHolder || '-'; + document.getElementById('detail-holder-provider').innerHTML = getProvidersBadges(holder.providers); + document.getElementById('detail-holder-connections').textContent = holder.connectionCount ?? '-'; + document.getElementById('detail-holder-verified').textContent = holder.verifiedConnectionCount ?? '-'; + document.getElementById('detail-holder-default').innerHTML = getDefaultBadge(holder.isDefault); if (DOM.detailPanel) DOM.detailPanel.style.display = ''; }, hideDetail() { - AppState.selectedCredential = null; + AppState.selectedHolder = null; if (DOM.detailPanel) DOM.detailPanel.style.display = 'none'; }, }; -// ─── CredentialManager ────────────────────────────────────────────── +// ─── CredentialHolderManager ────────────────────────────────────── -const CredentialManager = { - async loadCredentials() { +const CredentialHolderManager = { + async loadHolders() { try { - const credentials = await webconsolejs["common/api/services/csp_accounts_api"].listCspAccounts(); - AppState.credentials = Array.isArray(credentials) ? credentials : []; - TableManager.initTable(AppState.credentials); + const result = await webconsolejs["common/api/services/credential_holder_api"].getCredentialHolderList(); + const holders = (result && result.credentialHolderList) ? result.credentialHolderList + : Array.isArray(result) ? result : []; + AppState.holders = holders; + TableManager.initTable(AppState.holders); } catch (e) { - console.error('자격증명 목록 조회 실패:', e); + console.error('CredentialHolder 목록 조회 실패:', e); TableManager.initTable([]); } }, - async createCredential() { - const nameEl = document.getElementById('create-cred-name'); - const providerEl = document.getElementById('create-cred-provider'); - const dataEl = document.getElementById('create-cred-data'); + async registerCredential() { + const holderEl = document.getElementById('create-holder-name'); + const providerEl = document.getElementById('create-holder-provider'); - if (!webconsolejs['common/utils/formvalidation'].validateForm('credential-create-form')) return; - - let credData; - try { - credData = JSON.parse(dataEl.value); - } catch (e) { - webconsolejs['common/util'].showToast('Invalid JSON in Credential Data field.', 'error'); - dataEl.classList.add('is-invalid'); + if (!holderEl.value.trim()) { + holderEl.classList.add('is-invalid'); return; } - - try { - await webconsolejs["common/api/services/csp_accounts_api"].createCspAccount({ - name: nameEl.value.trim(), - cspType: providerEl.value, - credential: credData, - }); - webconsolejs['common/util'].showToast('Credential created successfully.', 'success'); - bootstrap.Modal.getInstance(document.getElementById('credential-create-modal')).hide(); - await CredentialManager.loadCredentials(); - } catch (e) { - console.error('자격증명 생성 실패:', e); - webconsolejs['common/util'].showToast('Failed to create credential: ' + e.message, 'error'); + if (!providerEl.value) { + providerEl.classList.add('is-invalid'); + return; } - }, - async validateSelected() { - if (!AppState.selectedCredential) return; - try { - await webconsolejs["common/api/services/csp_accounts_api"].validateCspAccount(AppState.selectedCredential.id); - webconsolejs['common/util'].showToast('Credential validated successfully.', 'success'); - } catch (e) { - webconsolejs['common/util'].showToast('Validation failed: ' + e.message, 'error'); + const credentialKeyValueList = KVManager.getKVList(); + if (credentialKeyValueList.length === 0) { + webconsolejs['common/util'].showToast('At least one credential key-value pair is required.', 'error'); + return; } - }, - async deleteSelected() { - if (!AppState.selectedCredential) return; - if (!confirm(`Delete credential "${AppState.selectedCredential.name}"?`)) return; try { - await webconsolejs["common/api/services/csp_accounts_api"].deleteCspAccount(AppState.selectedCredential.id); - webconsolejs['common/util'].showToast('Credential deleted.', 'success'); - UIManager.hideDetail(); - await CredentialManager.loadCredentials(); + await webconsolejs["common/api/services/credential_holder_api"].registerCredential({ + credentialHolder: holderEl.value.trim(), + providerName: providerEl.value, + credentialKeyValueList, + }); + webconsolejs['common/util'].showToast('Credential registered successfully.', 'success'); + bootstrap.Modal.getInstance(document.getElementById('credential-create-modal')).hide(); + await CredentialHolderManager.loadHolders(); } catch (e) { - webconsolejs['common/util'].showToast('Delete failed: ' + e.message, 'error'); + console.error('Credential 등록 실패:', e); + webconsolejs['common/util'].showToast('Failed to register credential: ' + e.message, 'error'); } }, }; @@ -181,19 +206,15 @@ const CredentialManager = { // ─── Public exports ────────────────────────────────────────────────── export function refreshCredentialList() { - CredentialManager.loadCredentials(); -} - -export function createCredential() { - CredentialManager.createCredential(); + CredentialHolderManager.loadHolders(); } -export function validateSelected() { - CredentialManager.validateSelected(); +export function registerCredential() { + CredentialHolderManager.registerCredential(); } -export function deleteSelected() { - CredentialManager.deleteSelected(); +export function addKvRow() { + KVManager.addRow(); } export function hideDetail() { @@ -203,5 +224,6 @@ export function hideDetail() { // ─── Init ────────────────────────────────────────────────────────── document.addEventListener('DOMContentLoaded', () => { - CredentialManager.loadCredentials(); + KVManager.reset(); + CredentialHolderManager.loadHolders(); }); diff --git a/front/assets/js/pages/settings/environment/cloudsps/cspaccounts.js b/front/assets/js/pages/settings/environment/cloudsps/cspaccounts.js new file mode 100644 index 00000000..655dbe7b --- /dev/null +++ b/front/assets/js/pages/settings/environment/cloudsps/cspaccounts.js @@ -0,0 +1,207 @@ +import { TabulatorFull as Tabulator } from "tabulator-tables"; + +const DOM = { + credentialTable: document.getElementById('credential-table'), + detailPanel: document.getElementById('credential-detail-panel'), + detailNameLabel: document.getElementById('credential-detail-name-label'), + detailNameText: document.getElementById('credential-detail-name-text'), +}; + +const AppState = { + credentials: [], + selectedCredential: null, + tables: { credentialTable: null }, +}; + +const PROVIDER_BADGE = { + AWS: 'AWS', + GCP: 'GCP', + AZURE: 'Azure', +}; + +function getProviderBadge(provider) { + if (!provider) return '-'; + const key = (provider || '').toUpperCase(); + return PROVIDER_BADGE[key] || `${provider}`; +} + +function getActiveBadge(active) { + return active + ? 'Active' + : 'Inactive'; +} + +// ─── TableManager ────────────────────────────────────────────────── + +const TableManager = { + initTable(data) { + if (AppState.tables.credentialTable) { + AppState.tables.credentialTable.replaceData(data); + return; + } + AppState.tables.credentialTable = new Tabulator('#credential-table', { + data, + layout: 'fitColumns', + placeholder: 'No CSP Accounts Found', + pagination: 'local', + paginationSize: 10, + paginationSizeSelector: [10, 20, 50], + paginationCounter: 'rows', + columns: [ + { + formatter: 'rowSelection', + titleFormatter: 'rowSelection', + hozAlign: 'center', + headerSort: false, + width: 40, + cellClick(e, cell) { cell.getRow().toggleSelect(); }, + }, + { title: 'ID', field: 'id', sorter: 'number', width: 80 }, + { title: 'Name', field: 'name', sorter: 'string' }, + { + title: 'Provider', + field: 'cspType', + formatter(cell) { return getProviderBadge(cell.getValue()); }, + }, + { + title: 'Active', + field: 'isActive', + formatter(cell) { return getActiveBadge(cell.getValue()); }, + hozAlign: 'center', + width: 100, + }, + { title: 'Created At', field: 'createdAt', sorter: 'string', formatter(cell) { + const v = cell.getValue(); + return v ? new Date(v).toLocaleString() : '-'; + }}, + ], + rowClick(e, row) { + UIManager.showDetail(row.getData()); + }, + }); + }, +}; + +// ─── UIManager ────────────────────────────────────────────────────── + +const UIManager = { + showDetail(cred) { + AppState.selectedCredential = cred; + + if (DOM.detailNameLabel) DOM.detailNameLabel.style.display = ''; + if (DOM.detailNameText) DOM.detailNameText.textContent = cred.name || '-'; + + document.getElementById('detail-cred-id').textContent = cred.id || '-'; + document.getElementById('detail-cred-name').textContent = cred.name || '-'; + document.getElementById('detail-cred-provider').innerHTML = getProviderBadge(cred.cspType); + document.getElementById('detail-cred-status').textContent = cred.status || '-'; + document.getElementById('detail-cred-active').innerHTML = getActiveBadge(cred.isActive); + document.getElementById('detail-cred-created').textContent = cred.createdAt + ? new Date(cred.createdAt).toLocaleString() + : '-'; + + if (DOM.detailPanel) DOM.detailPanel.style.display = ''; + }, + + hideDetail() { + AppState.selectedCredential = null; + if (DOM.detailPanel) DOM.detailPanel.style.display = 'none'; + }, +}; + +// ─── CspAccountManager ────────────────────────────────────────────── + +const CspAccountManager = { + async loadAccounts() { + try { + const accounts = await webconsolejs["common/api/services/csp_accounts_api"].listCspAccounts(); + AppState.credentials = Array.isArray(accounts) ? accounts : []; + TableManager.initTable(AppState.credentials); + } catch (e) { + console.error('CSP 계정 목록 조회 실패:', e); + TableManager.initTable([]); + } + }, + + async createAccount() { + const nameEl = document.getElementById('create-cred-name'); + const providerEl = document.getElementById('create-cred-provider'); + const dataEl = document.getElementById('create-cred-data'); + + if (!webconsolejs['common/utils/formvalidation'].validateForm('credential-create-form')) return; + + let credData; + try { + credData = JSON.parse(dataEl.value); + } catch (e) { + webconsolejs['common/util'].showToast('Invalid JSON in Credential Data field.', 'error'); + dataEl.classList.add('is-invalid'); + return; + } + + try { + await webconsolejs["common/api/services/csp_accounts_api"].createCspAccount({ + name: nameEl.value.trim(), + cspType: providerEl.value, + credential: credData, + }); + webconsolejs['common/util'].showToast('CSP Account created successfully.', 'success'); + bootstrap.Modal.getInstance(document.getElementById('credential-create-modal')).hide(); + await CspAccountManager.loadAccounts(); + } catch (e) { + console.error('CSP 계정 생성 실패:', e); + webconsolejs['common/util'].showToast('Failed to create CSP Account: ' + e.message, 'error'); + } + }, + + async validateSelected() { + if (!AppState.selectedCredential) return; + try { + await webconsolejs["common/api/services/csp_accounts_api"].validateCspAccount(AppState.selectedCredential.id); + webconsolejs['common/util'].showToast('CSP Account validated successfully.', 'success'); + } catch (e) { + webconsolejs['common/util'].showToast('Validation failed: ' + e.message, 'error'); + } + }, + + async deleteSelected() { + if (!AppState.selectedCredential) return; + if (!confirm(`Delete CSP Account "${AppState.selectedCredential.name}"?`)) return; + try { + await webconsolejs["common/api/services/csp_accounts_api"].deleteCspAccount(AppState.selectedCredential.id); + webconsolejs['common/util'].showToast('CSP Account deleted.', 'success'); + UIManager.hideDetail(); + await CspAccountManager.loadAccounts(); + } catch (e) { + webconsolejs['common/util'].showToast('Delete failed: ' + e.message, 'error'); + } + }, +}; + +// ─── Public exports ────────────────────────────────────────────────── + +export function refreshCredentialList() { + CspAccountManager.loadAccounts(); +} + +export function createCredential() { + CspAccountManager.createAccount(); +} + +export function validateSelected() { + CspAccountManager.validateSelected(); +} + +export function deleteSelected() { + CspAccountManager.deleteSelected(); +} + +export function hideDetail() { + UIManager.hideDetail(); +} + +// ─── Init ────────────────────────────────────────────────────────── + +document.addEventListener('DOMContentLoaded', () => { + CspAccountManager.loadAccounts(); +}); diff --git a/front/assets/js/partials/operation/dashboard/mci_dashboard.js b/front/assets/js/partials/operation/dashboard/mci_dashboard.js index a1803a0d..7b4a0857 100644 --- a/front/assets/js/partials/operation/dashboard/mci_dashboard.js +++ b/front/assets/js/partials/operation/dashboard/mci_dashboard.js @@ -34,7 +34,7 @@ export async function initMciDashboard(callbackfunction, workspaceProject) { function getMciListCallbackSuccess(caller, mciList) { // totalMciListObj = mciList.mci; - totalMciListObj = mciList.mci; + totalMciListObj = mciList.infra; var returnMciListObj = new Object(); diff --git a/front/assets/js/partials/operation/manage/clusterrecommendation.js b/front/assets/js/partials/operation/manage/clusterrecommendation.js index 2c59200e..414b1fe3 100644 --- a/front/assets/js/partials/operation/manage/clusterrecommendation.js +++ b/front/assets/js/partials/operation/manage/clusterrecommendation.js @@ -319,7 +319,7 @@ export async function getRecommendVmInfo() { ] } ], - "weight": "0.3" + "weight": 0.3 } priorityArr.push(priorityPolicy) const data = { @@ -327,7 +327,7 @@ export async function getRecommendVmInfo() { "filter": { "policy": policyArr }, - "limit": "1000", + "limit": 1000, "priority": { "policy": priorityArr, } @@ -402,7 +402,7 @@ async function availableVMImageBySpec(id) { } } - var controller = "/api/" + "mc-infra-manager/" + "Postmcidynamiccheckrequest"; + var controller = "/api/" + "mc-infra-manager/" + "PostInfraDynamicCheckRequest"; const response = await webconsolejs["common/api/http"].commonAPIPost( controller, data diff --git a/front/assets/js/partials/operation/manage/pmk_serverrecommendation.js b/front/assets/js/partials/operation/manage/pmk_serverrecommendation.js index 6c802a48..714ccf1f 100644 --- a/front/assets/js/partials/operation/manage/pmk_serverrecommendation.js +++ b/front/assets/js/partials/operation/manage/pmk_serverrecommendation.js @@ -244,7 +244,7 @@ export async function getRecommendVmInfoPmk() { key: "coordinateClose", val: [lat + "/" + lon] }], - weight: "0.3" + weight: 0.3 }); } @@ -255,41 +255,46 @@ export async function getRecommendVmInfoPmk() { filter: { policy: policyArr }, - limit: "1000", + limit: 1000, priority: { policy: priorityArr } } }; - // PMK용 Spec 추천 API 호출 (기존 MCI API 사용) - const result = await webconsolejs["common/api/services/mci_api"].mciRecommendVm(data); - - if (result && result.status && result.status.code === 200) { - const specData = result.responseData; - - // 전역 변수에 데이터 저장 (필터링용) - recommendVmSpecListObjPmk = specData; - - // 테이블에 데이터 표시 (기존 MCI 방식과 동일) - if (specData && specData.length > 0) { - // 테이블이 존재하는지 확인 - if (recommendTablePmk && typeof recommendTablePmk.setData === 'function') { - recommendTablePmk.setData(specData); + const loadingEl = document.getElementById('spec-search-loading-pmk'); + if (loadingEl) loadingEl.style.display = 'block'; + try { + // PMK용 Spec 추천 API 호출 (기존 MCI API 사용) + const result = await webconsolejs["common/api/services/mci_api"].mciRecommendVm(data); + + if (result && result.status && result.status.code === 200) { + const specData = result.responseData; + + // 전역 변수에 데이터 저장 (필터링용) + recommendVmSpecListObjPmk = specData; + + // 테이블에 데이터 표시 (기존 MCI 방식과 동일) + if (specData && specData.length > 0) { + if (recommendTablePmk && typeof recommendTablePmk.setData === 'function') { + recommendTablePmk.setData(specData); + } + } else { + if (recommendTablePmk && typeof recommendTablePmk.setData === 'function') { + recommendTablePmk.setData([]); + } } } else { + console.error("Failed to call PMK Spec recommendation API:", result); + recommendVmSpecListObjPmk = []; if (recommendTablePmk && typeof recommendTablePmk.setData === 'function') { recommendTablePmk.setData([]); } } - } else { - console.error("Failed to call PMK Spec recommendation API:", result); - recommendVmSpecListObjPmk = []; - if (recommendTablePmk && typeof recommendTablePmk.setData === 'function') { - recommendTablePmk.setData([]); - } + } finally { + if (loadingEl) loadingEl.style.display = 'none'; } - + } catch (error) { console.error("Failed to recommend PMK spec:", error); recommendVmSpecListObjPmk = []; diff --git a/front/assets/js/partials/operation/manage/serverrecommendation.js b/front/assets/js/partials/operation/manage/serverrecommendation.js index 7748655c..1184e271 100644 --- a/front/assets/js/partials/operation/manage/serverrecommendation.js +++ b/front/assets/js/partials/operation/manage/serverrecommendation.js @@ -13,60 +13,6 @@ export function initServerRecommendation(callbackfunction) { if (callbackfunction != undefined) { returnFunction = callbackfunction; } - - // 클라우드 연결 목록 로드 - loadConnectionsIntoSelect(); - - // 모달 열기 이벤트 리스너 등록 - setupServerModalEvents(); -} - -// 클라우드 연결 목록을 Select에 동적 로드 -async function loadConnectionsIntoSelect() { - const select = document.getElementById("assistRecommendSpecConnectionName"); - if (!select) return; - - try { - const connections = await webconsolejs["common/api/services/mci_api"].getCloudConnection(); - if (!Array.isArray(connections) || connections.length === 0) return; - - // 기존 옵션 제거 후 재구성 - select.innerHTML = ''; - connections.forEach(conn => { - const opt = document.createElement("option"); - opt.value = conn.configName || conn.connectionName || conn.NameId || ""; - opt.textContent = conn.configName || conn.connectionName || conn.NameId || ""; - // 연결에 위경도 정보가 있으면 data 속성으로 저장 - if (conn.regionDetail?.location?.latitude) { - opt.dataset.lat = conn.regionDetail.location.latitude; - opt.dataset.lon = conn.regionDetail.location.longitude; - } - select.appendChild(opt); - }); - } catch (e) { - // 실패 시 기존 하드코딩 옵션 유지 - console.warn("Failed to load cloud connections:", e); - } -} - -// 서버 추천 모달 이벤트 설정 -function setupServerModalEvents() { - // Bootstrap 5 방식 - if (typeof bootstrap !== 'undefined' && bootstrap.Modal) { - var serverModal = document.getElementById('spec-search'); - if (serverModal) { - serverModal.addEventListener('shown.bs.modal', function() { - loadConnectionsIntoSelect(); - }); - } - } - - // jQuery 방식 - if (typeof $ !== 'undefined' && $.fn.modal) { - $("#spec-search").on('shown.bs.modal', function() { - // 모달이 열렸을 때의 처리 - }); - } } function initRecommendSpecTable() { @@ -445,30 +391,18 @@ export async function getRecommendVmInfo() { // var priorityArr = new Array(); - var priorityType = $("#assistRecommendPriorityType").val() || "location"; - - if (priorityType === "location") { - // 위치 기반 우선순위 - if (lat && lon) { - var priorityPolicy = { - "metric": "location", - "parameter": [ - { - "key": "coordinateClose", - "val": [lat + "/" + lon] - } - ], - "weight": 0.3 - }; - priorityArr.push(priorityPolicy); - } - } else if (priorityType === "cost") { - // 비용 우선순위 (낮은 시간당 비용 우선) - var costPriorityPolicy = { - "metric": "costPerHour", - "weight": 1.0 + if (lat && lon) { + var priorityPolicy = { + "metric": "location", + "parameter": [ + { + "key": "coordinateClose", + "val": [lat + "/" + lon] + } + ], + "weight": 0.3 }; - priorityArr.push(costPriorityPolicy); + priorityArr.push(priorityPolicy); } const data = { request: { @@ -482,19 +416,19 @@ export async function getRecommendVmInfo() { } } - $("#spec-table-loading").removeClass("d-none"); - $("#spec-table").addClass("d-none"); - var respData = await webconsolejs["common/api/services/mci_api"].mciRecommendVm(data); - $("#spec-table-loading").addClass("d-none"); - $("#spec-table").removeClass("d-none"); - //var specList = response.data.responseData - if (respData.status.code != 200) { - console.error(e) - // TODO : Error 표시 - return + const loadingEl = document.getElementById('spec-search-loading'); + if (loadingEl) loadingEl.style.display = 'block'; + try { + var respData = await webconsolejs["common/api/services/mci_api"].mciRecommendVm(data); + if (respData.status.code != 200) { + console.error("RecommendSpec failed", respData) + return + } + recommendVmSpecListObj = respData.responseData + recommendTable.setData(recommendVmSpecListObj) + } finally { + if (loadingEl) loadingEl.style.display = 'none'; } - recommendVmSpecListObj = respData.responseData - recommendTable.setData(recommendVmSpecListObj) } @@ -545,17 +479,6 @@ export async function applySpecInfo() { } export function showRecommendSpecSetting(value) { - // 선택된 option의 data 속성에서 위경도를 읽음 (동적 연결 로드 후 설정됨) - const select = document.getElementById("assistRecommendSpecConnectionName"); - const selectedOption = select ? select.options[select.selectedIndex] : null; - - if (selectedOption && selectedOption.dataset.lat && selectedOption.dataset.lon) { - $("#latitude").val(selectedOption.dataset.lat); - $("#longitude").val(selectedOption.dataset.lon); - return; - } - - // 하드코딩 폴백 (동적 로드 실패 시) if (value === "seoul") { $("#latitude").val("37.532600") $("#longitude").val("127.024612") diff --git a/front/templates/pages/settings/environment/cloudsps/cloudoverview.html b/front/templates/pages/settings/environment/cloudsps/cloudoverview.html index b4dcaf8b..3af04548 100644 --- a/front/templates/pages/settings/environment/cloudsps/cloudoverview.html +++ b/front/templates/pages/settings/environment/cloudsps/cloudoverview.html @@ -264,6 +264,14 @@

Add CSP Account

Readyz

Framework health check and initialization
+
+ +{{ javascriptTag("common/api/services/connection_config_api.js") | raw }} +{{ javascriptTag("common/api/services/credential_holder_api.js") | raw }} +{{ javascriptTag("pages/settings/environment/cloudsps/connections.js") | raw }} diff --git a/front/templates/pages/settings/environment/cloudsps/credentials.html b/front/templates/pages/settings/environment/cloudsps/credentials.html index 103c822b..f3ff4558 100644 --- a/front/templates/pages/settings/environment/cloudsps/credentials.html +++ b/front/templates/pages/settings/environment/cloudsps/credentials.html @@ -5,9 +5,9 @@
-

CSP Credentials

+

Credential Holders

- + CSP Credentials
- + -{{ javascriptTag("common/api/services/csp_accounts_api.js") | raw }} {{ javascriptTag("common/utils/formvalidation.js") | raw }} {{ javascriptTag("pages/settings/environment/cloudsps/credentials.js") | raw }} +{{ javascriptTag("common/api/services/credential_holder_api.js") | raw }} {{ javascriptTag("pages/settings/environment/cloudsps/credentials.js") | raw }} diff --git a/front/templates/pages/settings/environment/cloudsps/cspaccounts.html b/front/templates/pages/settings/environment/cloudsps/cspaccounts.html new file mode 100644 index 00000000..f39ad8a4 --- /dev/null +++ b/front/templates/pages/settings/environment/cloudsps/cspaccounts.html @@ -0,0 +1,168 @@ + + + + +{{ javascriptTag("common/api/services/csp_accounts_api.js") | raw }} {{ javascriptTag("common/utils/formvalidation.js") | raw }} {{ javascriptTag("pages/settings/environment/cloudsps/cspaccounts.js") | raw }} diff --git a/front/templates/partials/operation/manage/_pmk_serverrecommendation.html b/front/templates/partials/operation/manage/_pmk_serverrecommendation.html index c8ba1ec9..52fde7de 100644 --- a/front/templates/partials/operation/manage/_pmk_serverrecommendation.html +++ b/front/templates/partials/operation/manage/_pmk_serverrecommendation.html @@ -184,6 +184,12 @@

+
diff --git a/front/templates/partials/operation/manage/_serverrecommendation.html b/front/templates/partials/operation/manage/_serverrecommendation.html index d1e5f52e..5fefaaaf 100644 --- a/front/templates/partials/operation/manage/_serverrecommendation.html +++ b/front/templates/partials/operation/manage/_serverrecommendation.html @@ -21,19 +21,9 @@