@@ -143,14 +143,15 @@ This is useful for development or when connecting directly to specific service e
143143 }
144144
145145 pterm .Success .Printf ("Successfully initialized direct connection to %s\n " , endpoint )
146- updateSetting (envName , endpoint , "" )
147146 if err := v .ReadInConfig (); err == nil {
148147 v .Set (fmt .Sprintf ("environments.%s.proxy" , envName ), false )
149148 if err := v .WriteConfig (); err != nil {
150149 pterm .Error .Printf ("Failed to update proxy setting: %v\n " , err )
151150 return
152151 }
153152 }
153+
154+ updateSetting (envName , endpoint , "" , false )
154155 },
155156}
156157
@@ -253,8 +254,10 @@ var settingInitProxyCmd = &cobra.Command{
253254 }
254255 }
255256
257+ internalFlag , _ := cmd .Flags ().GetBool ("internal" )
258+
256259 // Update configuration
257- updateSetting (envName , endpointStr , envSuffix )
260+ updateSetting (envName , endpointStr , envSuffix , internalFlag )
258261 },
259262}
260263
@@ -1344,7 +1347,7 @@ func isIPAddress(host string) bool {
13441347}
13451348
13461349// updateSetting updates the configuration files
1347- func updateSetting (envName , endpoint , envSuffix string ) {
1350+ func updateSetting (envName , endpoint , envSuffix string , internal bool ) {
13481351 settingDir := GetSettingDir ()
13491352 mainSettingPath := filepath .Join (settingDir , "setting.yaml" )
13501353
@@ -1358,6 +1361,16 @@ func updateSetting(envName, endpoint, envSuffix string) {
13581361 // Set environment
13591362 v .Set ("environment" , envName )
13601363
1364+ if internal {
1365+ // Get internal endpoint
1366+ internalEndpoint , err := getInternalEndpoint (endpoint )
1367+ if err != nil {
1368+ pterm .Error .Printf ("Failed to get internal endpoint: %v\n " , err )
1369+ return
1370+ }
1371+ endpoint = internalEndpoint
1372+ }
1373+
13611374 // Handle protocol for endpoint
13621375 if ! strings .Contains (endpoint , "://" ) {
13631376 if strings .Contains (endpoint , "localhost" ) || strings .Contains (endpoint , "127.0.0.1" ) {
@@ -1399,6 +1412,120 @@ func updateSetting(envName, endpoint, envSuffix string) {
13991412 pterm .Info .Printf ("Configuration saved to: %s\n " , mainSettingPath )
14001413}
14011414
1415+ func getInternalEndpoint (endpoint string ) (string , error ) {
1416+ if strings .HasPrefix (endpoint , "grpc://" ) || strings .HasPrefix (endpoint , "grpc+ssl://" ) {
1417+ // Handle gRPC endpoint
1418+ conn , err := transport .GetGrpcConnection (endpoint )
1419+ if err != nil {
1420+ return "" , fmt .Errorf ("failed to connect to gRPC server: %v" , err )
1421+ }
1422+ defer conn .Close ()
1423+
1424+ client := grpc_reflection_v1alpha .NewServerReflectionClient (conn )
1425+ refClient := grpcreflect .NewClient (context .Background (), client )
1426+ defer refClient .Reset ()
1427+
1428+ serviceName := "spaceone.api.identity.v2.Endpoint"
1429+ methodName := "list"
1430+
1431+ serviceDesc , err := refClient .ResolveService (serviceName )
1432+ if err != nil {
1433+ return "" , fmt .Errorf ("failed to resolve service: %v" , err )
1434+ }
1435+
1436+ methodDesc := serviceDesc .FindMethodByName (methodName )
1437+ if methodDesc == nil {
1438+ return "" , fmt .Errorf ("method not found: %s" , methodName )
1439+ }
1440+
1441+ reqMsg := dynamic .NewMessage (methodDesc .GetInputType ())
1442+ reqMsg .SetField (reqMsg .GetMessageDescriptor ().FindFieldByName ("service" ), "identity" )
1443+ reqMsg .SetField (reqMsg .GetMessageDescriptor ().FindFieldByName ("endpoint_type" ), "INTERNAL" )
1444+ reqMsg .SetField (reqMsg .GetMessageDescriptor ().FindFieldByName ("query" ), map [string ]interface {}{})
1445+
1446+ respMsg := dynamic .NewMessage (methodDesc .GetOutputType ())
1447+ fullMethod := fmt .Sprintf ("/%s/%s" , serviceName , methodName )
1448+
1449+ if err := conn .Invoke (context .Background (), fullMethod , reqMsg , respMsg ); err != nil {
1450+ return "" , fmt .Errorf ("failed to invoke method: %v" , err )
1451+ }
1452+
1453+ results , err := respMsg .TryGetField (respMsg .GetMessageDescriptor ().FindFieldByName ("results" ))
1454+ if err != nil {
1455+ return "" , fmt .Errorf ("failed to get results: %v" , err )
1456+ }
1457+
1458+ resultsSlice := results .([]interface {})
1459+ if len (resultsSlice ) > 0 {
1460+ result := resultsSlice [0 ].(* dynamic.Message )
1461+ if internalEndpoint , err := result .TryGetField (result .GetMessageDescriptor ().FindFieldByName ("internal_endpoint" )); err == nil {
1462+ return internalEndpoint .(string ), nil
1463+ }
1464+ }
1465+ } else {
1466+ // Handle REST endpoint
1467+ // 1. First get the console API endpoint from config
1468+ client := & http.Client {}
1469+ configResp , err := client .Get (endpoint + "/config/production.json" )
1470+ if err != nil {
1471+ return "" , fmt .Errorf ("failed to get config: %v" , err )
1472+ }
1473+ defer configResp .Body .Close ()
1474+
1475+ var config struct {
1476+ ConsoleAPIV2 struct {
1477+ Endpoint string `json:"ENDPOINT"`
1478+ } `json:"CONSOLE_API_V2"`
1479+ }
1480+
1481+ if err := json .NewDecoder (configResp .Body ).Decode (& config ); err != nil {
1482+ return "" , fmt .Errorf ("failed to decode config: %v" , err )
1483+ }
1484+
1485+ // 2. Then use the console API endpoint to get internal endpoint
1486+ reqBody := map [string ]interface {}{
1487+ "service" : "identity" ,
1488+ "endpoint_type" : "INTERNAL" ,
1489+ "query" : map [string ]interface {}{},
1490+ }
1491+
1492+ jsonBody , err := json .Marshal (reqBody )
1493+ if err != nil {
1494+ return "" , fmt .Errorf ("failed to marshal request body: %v" , err )
1495+ }
1496+
1497+ req , err := http .NewRequest ("POST" , config .ConsoleAPIV2 .Endpoint + "/identity/endpoint/list" , bytes .NewBuffer (jsonBody ))
1498+ if err != nil {
1499+ return "" , fmt .Errorf ("failed to create request: %v" , err )
1500+ }
1501+
1502+ req .Header .Set ("Content-Type" , "application/json" )
1503+ req .Header .Set ("accept" , "application/json" )
1504+
1505+ resp , err := client .Do (req )
1506+ if err != nil {
1507+ return "" , fmt .Errorf ("failed to send request: %v" , err )
1508+ }
1509+ defer resp .Body .Close ()
1510+
1511+ var result struct {
1512+ Results []struct {
1513+ InternalEndpoint string `json:"internal_endpoint"`
1514+ } `json:"results"`
1515+ }
1516+
1517+ if err := json .NewDecoder (resp .Body ).Decode (& result ); err != nil {
1518+ return "" , fmt .Errorf ("failed to decode response: %v" , err )
1519+ }
1520+
1521+ if len (result .Results ) > 0 {
1522+ return result .Results [0 ].InternalEndpoint , nil
1523+ }
1524+ }
1525+
1526+ return "" , fmt .Errorf ("internal endpoint not found" )
1527+ }
1528+
14021529// convertToStringMap converts map[interface{}]interface{} to map[string]interface{}
14031530func convertToStringMap (m map [interface {}]interface {}) map [string ]interface {} {
14041531 result := make (map [string ]interface {})
@@ -1442,6 +1569,7 @@ func init() {
14421569
14431570 settingInitProxyCmd .Flags ().Bool ("app" , false , "Initialize as application configuration" )
14441571 settingInitProxyCmd .Flags ().Bool ("user" , false , "Initialize as user-specific configuration" )
1572+ settingInitProxyCmd .Flags ().Bool ("internal" , false , "Use internal endpoint for the environment" )
14451573
14461574 envCmd .Flags ().StringP ("switch" , "s" , "" , "Switch to a different environment" )
14471575 envCmd .Flags ().StringP ("remove" , "r" , "" , "Remove an environment" )
0 commit comments