Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8a8ebfa
fix(api): add missing POST /api/getapihosts endpoint
yh-noh May 6, 2026
584d18a
fix(api): add missing POST /api/getapihosts endpoint
dogfootman May 6, 2026
1e6179d
fix(api,front): getapihosts api.yaml fallback + proxy cache auto-refresh
yh-noh May 6, 2026
c55d7fd
fix(readyz): auto-discover readyz operationId from mc-iam-manager reg…
yh-noh May 6, 2026
c4c0a65
feat(costanalysis): add mc-cost-optimizer-fe iframe with workspace/pr…
yh-noh May 6, 2026
054038b
fix(apihosts): remove IFRAME_TARGET_IS_HOST port-only transform (HTTP…
yh-noh May 7, 2026
61e1681
fix(api): cb-tumblebug v0.12.9 mci→infra API 경로 전면 갱신 (FR-FW-CONSOLE-…
yh-noh May 11, 2026
a21c3c1
feat(web-front): CSP accounts/connections 관리 화면 추가 및 credentials 개선
yh-noh May 11, 2026
27a5d39
Merge fix-web-bug-012-getapihosts-fallback into develop
yh-noh May 11, 2026
65058a0
Merge feat-web-frameworkversion-mcinfra-v012-patch into develop
yh-noh May 11, 2026
0aea76a
fix(web-front): WEB-BUG-013 RecommendSpec/Cluster weight·limit 타입 수정 …
yh-noh May 12, 2026
afb07cc
feat(api): queryParamTypes 타입 메타데이터로 queryParam 검증/정규화 지원
yh-noh May 12, 2026
ffbf9c7
feat(FR-FW-003): sync mc-infra-manager v0.12 API changes and improve UX
yh-noh May 12, 2026
dc86cf2
fix(api): add /api/getapihosts endpoint for iframe plugin host resolu…
yh-noh May 12, 2026
fb76bf6
fix(api): fix getapihosts response format to match iframe.js expectation
yh-noh May 12, 2026
c7f28c4
fix(api): sync getapihosts handler from develop branch
yh-noh May 12, 2026
26a1a73
merge: develop 브랜치 최신 변경사항 통합 (충돌 해결)
yh-noh May 12, 2026
5aca9dd
Merge pull request #177 from MZC-CSC/feat-web-frameworkversion-mcinfr…
MZC-CSC May 12, 2026
dbb4f99
fix(WEB-BUG-014): iframe plugins 화면 미표시 수정 및 -fe 서비스 분리
yh-noh May 20, 2026
d88f523
Merge pull request #178 from MZC-CSC/worktree-fix+iframe-plugins
MZC-CSC May 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 우회 + 토큰 노출 방지)
Expand Down
12 changes: 12 additions & 0 deletions api/internal/config/api_spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 호환)
Expand Down
16 changes: 10 additions & 6 deletions api/internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 도달성 확인 설정
Expand All @@ -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()
}
Expand Down Expand Up @@ -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 스펙 로드
Expand Down
113 changes: 113 additions & 0 deletions api/internal/handler/apihosts.go
Original file line number Diff line number Diff line change
@@ -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
}
Loading
Loading