Skip to content

Commit d7868fe

Browse files
author
Youngjin Jo
authored
Merge pull request #113 from yjinjo/master
Add internal flag
2 parents 2a0b475 + 63bfda6 commit d7868fe

File tree

3 files changed

+149
-3
lines changed

3 files changed

+149
-3
lines changed

cmd/other/setting.go

Lines changed: 131 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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{}
14031530
func 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")

pkg/transport/reflection.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,22 @@ func ListGRPCServices(endpoint string) ([]string, error) {
5656
return listServices(conn)
5757
}
5858

59+
// GetGrpcConnection establishes a gRPC connection with the specified endpoint
60+
func GetGrpcConnection(endpoint string) (*grpc.ClientConn, error) {
61+
parsedURL, err := url.Parse(endpoint)
62+
if err != nil {
63+
return nil, fmt.Errorf("failed to parse endpoint: %v", err)
64+
}
65+
66+
host := parsedURL.Hostname()
67+
port := parsedURL.Port()
68+
if port == "" {
69+
port = "443"
70+
}
71+
72+
return dialGRPC(endpoint, host, port)
73+
}
74+
5975
// CheckIdentityProxyAvailable checks if the given gRPC endpoint can be used as an identity proxy
6076
// by verifying the presence of both Endpoint and Token services.
6177
// These services are required for the identity service to act as a proxy.

pkg/transport/service.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,12 +187,14 @@ func FetchService(serviceName string, verb string, resourceName string, options
187187
hostPort = strings.TrimPrefix(config.Environments[config.Environment].Endpoint, "grpc://")
188188
} else {
189189
apiEndpoint, err = configs.GetAPIEndpoint(config.Environments[config.Environment].Endpoint)
190+
fmt.Println(apiEndpoint)
190191
if err != nil {
191192
pterm.Error.Printf("Failed to get API endpoint: %v\n", err)
192193
os.Exit(1)
193194
}
194195
// Get identity service endpoint
195196
identityEndpoint, hasIdentityService, err = configs.GetIdentityEndpoint(apiEndpoint)
197+
fmt.Println(identityEndpoint)
196198
if err != nil {
197199
pterm.Error.Printf("Failed to get identity endpoint: %v\n", err)
198200
os.Exit(1)

0 commit comments

Comments
 (0)