Skip to content

Commit 12c2ee2

Browse files
author
Youngjin Jo
committed
refactor: handle grpc connection for local and static mode
Signed-off-by: Youngjin Jo <[email protected]>
1 parent 1dd537e commit 12c2ee2

File tree

5 files changed

+215
-57
lines changed

5 files changed

+215
-57
lines changed

cmd/common/fetchService.go

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,12 @@ func FetchService(serviceName string, verb string, resourceName string, options
236236
defer refClient.Reset()
237237

238238
// Call the service
239+
fmt.Println("serviceName:", serviceName)
240+
fmt.Println("verb:", verb)
241+
fmt.Println("resourceName:", resourceName)
242+
fmt.Println("apiEndpoint:", apiEndpoint)
243+
fmt.Println("identityEndpoint:", identityEndpoint)
244+
fmt.Println("hasIdentityService:", hasIdentityService)
239245
jsonBytes, err := fetchJSONResponse(config, serviceName, verb, resourceName, options, apiEndpoint, identityEndpoint, hasIdentityService)
240246
if err != nil {
241247
// Check if the error is about missing required parameters
@@ -427,19 +433,39 @@ func fetchJSONResponse(config *Config, serviceName string, verb string, resource
427433
}
428434
} else {
429435
if !hasIdentityService {
430-
urlParts := strings.Split(apiEndpoint, "//")
431-
if len(urlParts) != 2 {
432-
return nil, fmt.Errorf("invalid API endpoint format: %s", apiEndpoint)
433-
}
436+
// Handle gRPC+SSL protocol directly
437+
if strings.HasPrefix(config.Environments[config.Environment].Endpoint, "grpc+ssl://") {
438+
endpoint := config.Environments[config.Environment].Endpoint
439+
parts := strings.Split(endpoint, "/")
440+
endpoint = strings.Join(parts[:len(parts)-1], "/")
441+
parts = strings.Split(endpoint, "://")
442+
if len(parts) != 2 {
443+
return nil, fmt.Errorf("invalid endpoint format: %s", endpoint)
444+
}
434445

435-
domainParts := strings.Split(urlParts[1], ".")
436-
if len(domainParts) < 4 {
437-
return nil, fmt.Errorf("invalid domain format in API endpoint: %s", apiEndpoint)
438-
}
446+
hostParts := strings.Split(parts[1], ".")
447+
if len(hostParts) < 4 {
448+
return nil, fmt.Errorf("invalid endpoint format: %s", endpoint)
449+
}
439450

440-
domainParts[0] = convertServiceNameToEndpoint(serviceName)
451+
// Replace service name
452+
hostParts[0] = convertServiceNameToEndpoint(serviceName)
453+
hostPort = strings.Join(hostParts, ".")
454+
} else {
455+
// Original HTTP/HTTPS handling
456+
urlParts := strings.Split(apiEndpoint, "//")
457+
if len(urlParts) != 2 {
458+
return nil, fmt.Errorf("invalid API endpoint format: %s", apiEndpoint)
459+
}
441460

442-
hostPort = strings.Join(domainParts, ".") + ":443"
461+
domainParts := strings.Split(urlParts[1], ".")
462+
if len(domainParts) < 4 {
463+
return nil, fmt.Errorf("invalid domain format in API endpoint: %s", apiEndpoint)
464+
}
465+
466+
domainParts[0] = convertServiceNameToEndpoint(serviceName)
467+
hostPort = strings.Join(domainParts, ".") + ":443"
468+
}
443469
} else {
444470
trimmedEndpoint := strings.TrimPrefix(identityEndpoint, "grpc+ssl://")
445471
parts := strings.Split(trimmedEndpoint, ".")

cmd/other/apiResources.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,39 @@ func FetchEndpointsMap(endpoint string) (map[string]string, error) {
201201
}
202202

203203
if !hasIdentityService {
204+
// Handle gRPC+SSL protocol directly
205+
if strings.HasPrefix(endpoint, "grpc+ssl://") {
206+
// Parse the endpoint
207+
parts := strings.Split(endpoint, "/")
208+
endpoint = strings.Join(parts[:len(parts)-1], "/")
209+
parts = strings.Split(endpoint, "://")
210+
if len(parts) != 2 {
211+
return nil, fmt.Errorf("invalid endpoint format: %s", endpoint)
212+
}
213+
214+
hostParts := strings.Split(parts[1], ".")
215+
svc := hostParts[0]
216+
baseDomain := strings.Join(hostParts[1:], ".")
217+
218+
// Configure TLS
219+
tlsConfig := &tls.Config{
220+
InsecureSkipVerify: false,
221+
}
222+
opts := []grpc.DialOption{
223+
grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)),
224+
}
225+
226+
//If current service is not identity, modify hostPort to use identity service
227+
if svc != "identity" {
228+
hostPort := fmt.Sprintf("identity.%s", baseDomain)
229+
endpoints, err := invokeGRPCEndpointList(hostPort, opts)
230+
if err != nil {
231+
return nil, fmt.Errorf("failed to get endpoints from gRPC: %v", err)
232+
}
233+
return endpoints, nil
234+
}
235+
}
236+
204237
payload := map[string]string{}
205238
jsonPayload, err := json.Marshal(payload)
206239
if err != nil {

cmd/other/login.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,13 @@ func executeUserLogin(currentEnv string) {
697697
scope = "WORKSPACE"
698698
}
699699

700+
// Grant new token using the refresh token
701+
newAccessToken, err := grantToken("", identityEndpoint, hasIdentityService, refreshToken, scope, domainID, workspaceID)
702+
if err != nil {
703+
pterm.Error.Println("Failed to retrieve new access token:", err)
704+
exitWithError()
705+
}
706+
700707
// Create cache directory
701708
envCacheDir := filepath.Join(homeDir, ".cfctl", "cache", currentEnv)
702709
if err := os.MkdirAll(envCacheDir, 0700); err != nil {
@@ -710,7 +717,7 @@ func executeUserLogin(currentEnv string) {
710717
exitWithError()
711718
}
712719

713-
if err := os.WriteFile(filepath.Join(envCacheDir, "access_token"), []byte(accessToken), 0600); err != nil {
720+
if err := os.WriteFile(filepath.Join(envCacheDir, "access_token"), []byte(newAccessToken), 0600); err != nil {
714721
pterm.Error.Printf("Failed to save access token: %v\n", err)
715722
exitWithError()
716723
}
@@ -721,6 +728,12 @@ func executeUserLogin(currentEnv string) {
721728

722729
// GetAPIEndpoint fetches the actual API endpoint from the config endpoint
723730
func GetAPIEndpoint(endpoint string) (string, error) {
731+
// Handle gRPC+SSL protocol
732+
if strings.HasPrefix(endpoint, "grpc+ssl://") {
733+
// For gRPC+SSL endpoints, return as is since it's already in the correct format
734+
return endpoint, nil
735+
}
736+
724737
// Remove protocol prefix if exists
725738
endpoint = strings.TrimPrefix(endpoint, "https://")
726739
endpoint = strings.TrimPrefix(endpoint, "http://")
@@ -759,6 +772,20 @@ func GetAPIEndpoint(endpoint string) (string, error) {
759772

760773
// GetIdentityEndpoint fetches the identity service endpoint from the API endpoint
761774
func GetIdentityEndpoint(apiEndpoint string) (string, bool, error) {
775+
// If the endpoint is already gRPC+SSL
776+
if strings.HasPrefix(apiEndpoint, "grpc+ssl://") {
777+
// Check if it contains 'identity'
778+
containsIdentity := strings.Contains(apiEndpoint, "identity")
779+
780+
// Remove /v1 suffix if present
781+
if idx := strings.Index(apiEndpoint, "/v"); idx != -1 {
782+
apiEndpoint = apiEndpoint[:idx]
783+
}
784+
785+
return apiEndpoint, containsIdentity, nil
786+
}
787+
788+
// Original HTTP/HTTPS handling logic
762789
endpointListURL := fmt.Sprintf("%s/identity/endpoint/list", apiEndpoint)
763790

764791
payload := map[string]string{}
@@ -1062,7 +1089,7 @@ func loadEnvironmentConfig() {
10621089
"Please enable proxy mode and set identity endpoint first.")
10631090

10641091
pterm.DefaultBox.WithBoxStyle(pterm.NewStyle(pterm.FgCyan)).
1065-
Println("$ cfctl config endpoint -s identity\n" +
1092+
Println("$ cfctl setting endpoint -s identity\n" +
10661093
"$ cfctl login")
10671094

10681095
exitWithError()

cmd/other/setting.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,17 @@ You can either specify a new endpoint URL directly or use the service-based endp
493493
if listFlag {
494494
token, err := getToken(appV)
495495
if err != nil {
496+
if strings.HasSuffix(currentEnv, "-user") {
497+
pterm.DefaultBox.WithTitle("Authentication Required").
498+
WithTitleTopCenter().
499+
WithBoxStyle(pterm.NewStyle(pterm.FgLightCyan)).
500+
WithRightPadding(4).
501+
WithLeftPadding(4).
502+
Println("Please login to SpaceONE Console first.\n" +
503+
"Run the following command to authenticate:\n\n" +
504+
"$ cfctl login")
505+
return
506+
}
496507
pterm.Error.Println("Error retrieving token:", err)
497508
return
498509
}
@@ -1290,6 +1301,19 @@ func updateSetting(envName, endpoint string, envSuffix string) {
12901301
envKey := fmt.Sprintf("environments.%s.endpoint", fullEnvName)
12911302
v.Set(envKey, endpoint)
12921303

1304+
// Set proxy based on endpoint type
1305+
proxyKey := fmt.Sprintf("environments.%s.proxy", fullEnvName)
1306+
if strings.HasPrefix(endpoint, "grpc://") || strings.HasPrefix(endpoint, "grpc+ssl://") {
1307+
// Check if endpoint contains 'identity'
1308+
if strings.Contains(strings.ToLower(endpoint), "identity") {
1309+
v.Set(proxyKey, true)
1310+
} else {
1311+
v.Set(proxyKey, false)
1312+
}
1313+
} else {
1314+
v.Set(proxyKey, true)
1315+
}
1316+
12931317
// Set additional configurations based on environment type
12941318
if envName == "local" {
12951319
// Local environment settings (only for pure 'local', not 'local-user' or 'local-app')

cmd/root.go

Lines changed: 93 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,20 @@ func showInitializationGuide() {
233233
pterm.Info.Println("After updating the token, please try your command again.")
234234
}
235235
} else if strings.HasSuffix(currentEnv, "-user") {
236+
// Get endpoint from environment config
237+
envConfig := mainV.Sub(fmt.Sprintf("environments.%s", currentEnv))
238+
if envConfig == nil {
239+
pterm.Warning.Printf("No environment configuration found.\n")
240+
return
241+
}
242+
243+
endpoint := envConfig.GetString("endpoint")
244+
245+
// Skip authentication warning for gRPC+SSL endpoints
246+
if strings.HasPrefix(endpoint, "grpc+ssl://") {
247+
return
248+
}
249+
236250
pterm.Warning.Printf("Authentication required.\n")
237251
pterm.Info.Println("To see Available Commands, please authenticate first:")
238252
pterm.Info.Println("$ cfctl login")
@@ -318,70 +332,104 @@ func addDynamicServiceCommands() error {
318332
return nil
319333
}
320334

321-
// For non-local environments, continue with existing logic...
335+
// For non-local environments
336+
endpoint := config.Endpoint
337+
var apiEndpoint string
338+
339+
if strings.HasPrefix(endpoint, "grpc+ssl://") {
340+
apiEndpoint = endpoint
341+
} else if strings.HasPrefix(endpoint, "http://") || strings.HasPrefix(endpoint, "https://") {
342+
apiEndpoint, err = other.GetAPIEndpoint(endpoint)
343+
if err != nil {
344+
return fmt.Errorf("failed to get API endpoint: %v", err)
345+
}
346+
}
347+
348+
// Try to use cached endpoints first
322349
if cachedEndpointsMap != nil {
350+
currentService := ""
351+
if strings.HasPrefix(endpoint, "grpc+ssl://") {
352+
parts := strings.Split(endpoint, "://")
353+
if len(parts) == 2 {
354+
hostParts := strings.Split(parts[1], ".")
355+
if len(hostParts) > 0 {
356+
currentService = hostParts[0]
357+
}
358+
}
359+
}
360+
361+
if currentService != "identity" && currentService != "" {
362+
if cmd := createServiceCommand(currentService); cmd != nil {
363+
cmd.GroupID = "available"
364+
rootCmd.AddCommand(cmd)
365+
}
366+
return nil
367+
}
368+
369+
// If identity service or no specific service, add all available commands
323370
for serviceName := range cachedEndpointsMap {
324371
cmd := createServiceCommand(serviceName)
372+
cmd.GroupID = "available"
325373
rootCmd.AddCommand(cmd)
326374
}
327375
return nil
328376
}
329377

330-
// Only show progress bar when actually fetching services
331-
if len(os.Args) == 1 || (len(os.Args) > 1 &&
332-
os.Args[1] != "setting" &&
333-
os.Args[1] != "login" &&
334-
os.Args[1] != "api_resources" &&
335-
os.Args[1] != "short_name") {
336-
// Create progress bar
337-
progressbar, _ := pterm.DefaultProgressbar.
338-
WithTotal(4).
339-
WithTitle("Initializing services").
340-
Start()
341-
342-
progressbar.UpdateTitle("Preparing endpoint configuration")
343-
endpoint := config.Endpoint
344-
345-
var apiEndpoint string
346-
if strings.HasPrefix(endpoint, "http://") || strings.HasPrefix(endpoint, "https://") {
347-
apiEndpoint, err = other.GetAPIEndpoint(endpoint)
348-
if err != nil {
349-
pterm.Error.Printf("Failed to get API endpoint: %v\n", err)
350-
os.Exit(1)
351-
}
352-
}
378+
// If no cached endpoints, fetch them
379+
progressbar, _ := pterm.DefaultProgressbar.
380+
WithTotal(4).
381+
WithTitle("Initializing services").
382+
Start()
353383

354-
progressbar.Increment()
355-
time.Sleep(time.Millisecond * 300)
384+
progressbar.UpdateTitle("Fetching available services")
385+
endpointsMap, err := other.FetchEndpointsMap(apiEndpoint)
386+
if err != nil {
387+
return fmt.Errorf("failed to fetch services: %v", err)
388+
}
356389

357-
progressbar.UpdateTitle("Fetching available services")
358-
endpointsMap, err := other.FetchEndpointsMap(apiEndpoint)
359-
if err != nil {
360-
return fmt.Errorf("failed to fetch services: %v", err)
361-
}
362-
progressbar.Increment()
363-
time.Sleep(time.Millisecond * 300)
364-
365-
progressbar.UpdateTitle("Creating cache for faster subsequent runs")
366-
cachedEndpointsMap = endpointsMap
367-
if err := saveEndpointsCache(endpointsMap); err != nil {
368-
_, err2 := fmt.Fprintf(os.Stderr, "Warning: Failed to cache endpoints: %v\n", err)
369-
if err2 != nil {
370-
return err2
390+
progressbar.Increment()
391+
time.Sleep(time.Millisecond * 300)
392+
393+
progressbar.UpdateTitle("Creating cache for faster subsequent runs")
394+
cachedEndpointsMap = endpointsMap
395+
if err := saveEndpointsCache(endpointsMap); err != nil {
396+
fmt.Fprintf(os.Stderr, "Warning: Failed to cache endpoints: %v\n", err)
397+
}
398+
399+
progressbar.Increment()
400+
time.Sleep(time.Millisecond * 300)
401+
402+
//progressbar.UpdateTitle("Finalizing")
403+
progressbar.Increment()
404+
time.Sleep(time.Millisecond * 300)
405+
406+
fmt.Println()
407+
// Add commands based on the current service
408+
currentService := ""
409+
if strings.HasPrefix(endpoint, "grpc+ssl://") {
410+
parts := strings.Split(endpoint, "://")
411+
if len(parts) == 2 {
412+
hostParts := strings.Split(parts[1], ".")
413+
if len(hostParts) > 0 {
414+
currentService = hostParts[0]
371415
}
372416
}
373-
progressbar.Increment()
374-
time.Sleep(time.Millisecond * 300)
417+
}
375418

376-
progressbar.UpdateTitle("Registering verbs and resources commands to the cache")
419+
if currentService != "identity" && currentService != "" {
420+
if cmd := createServiceCommand(currentService); cmd != nil {
421+
cmd.GroupID = "available"
422+
rootCmd.AddCommand(cmd)
423+
}
424+
} else {
377425
for serviceName := range endpointsMap {
378426
cmd := createServiceCommand(serviceName)
427+
cmd.GroupID = "available"
379428
rootCmd.AddCommand(cmd)
380429
}
381-
progressbar.Increment()
382-
time.Sleep(time.Millisecond * 300)
383430
}
384431

432+
progressbar.Increment()
385433
return nil
386434
}
387435

0 commit comments

Comments
 (0)