From 24b12804f20f02e32b2166733412c7e9cb7dceea Mon Sep 17 00:00:00 2001 From: Youngjin Jo Date: Tue, 14 Jan 2025 16:42:01 +0900 Subject: [PATCH] refactor: modify local environment Signed-off-by: Youngjin Jo --- cmd/common/api_resources.go | 31 ++++++++++++++- cmd/root.go | 77 +++++++++++++++++++++++++++++++++++++ pkg/configs/endpoint.go | 12 ++++++ pkg/format/output.go | 2 +- pkg/transport/service.go | 9 +++-- 5 files changed, 125 insertions(+), 6 deletions(-) diff --git a/cmd/common/api_resources.go b/cmd/common/api_resources.go index 9cb5ce4..badc0bf 100644 --- a/cmd/common/api_resources.go +++ b/cmd/common/api_resources.go @@ -17,6 +17,7 @@ import ( "github.com/spf13/viper" "google.golang.org/grpc" "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/metadata" "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" "gopkg.in/yaml.v3" @@ -101,6 +102,8 @@ func FetchServiceResources(serviceName, endpoint string, shortNamesMap map[strin } creds := credentials.NewTLS(tlsConfig) opts = append(opts, grpc.WithTransportCredentials(creds)) + } else if scheme == "grpc" { + opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) } else { return nil, fmt.Errorf("unsupported scheme: %s", scheme) } @@ -150,7 +153,33 @@ func FetchServiceResources(serviceName, endpoint string, shortNamesMap map[strin if strings.HasPrefix(s, "grpc.reflection.") { continue } - if !strings.Contains(s, fmt.Sprintf(".%s.", serviceName)) { + + displayServiceName := serviceName + if strings.HasPrefix(endpoint, "grpc://") && (strings.Contains(endpoint, "localhost") || strings.Contains(endpoint, "127.0.0.1")) { + parts := strings.Split(s, ".") + if len(parts) > 2 { + serviceDesc, err := refClient.ResolveService(s) + if err != nil { + log.Printf("Failed to resolve service %s: %v", s, err) + continue + } + + resourceName := s[strings.LastIndex(s, ".")+1:] + verbs := []string{} + for _, method := range serviceDesc.GetMethods() { + verbs = append(verbs, method.GetName()) + } + + sort.Strings(verbs) + data = append(data, []string{ + displayServiceName, + strings.Join(verbs, ", "), + resourceName, + "", + }) + continue + } + } else if !strings.Contains(s, fmt.Sprintf(".%s.", serviceName)) { continue } diff --git a/cmd/root.go b/cmd/root.go index 04fd5d4..dbc9058 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,6 +1,7 @@ package cmd import ( + "context" "fmt" "log" "os" @@ -11,6 +12,9 @@ import ( "github.com/cloudforet-io/cfctl/cmd/common" "github.com/cloudforet-io/cfctl/pkg/configs" "github.com/cloudforet-io/cfctl/pkg/transport" + "github.com/jhump/protoreflect/grpcreflect" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" "gopkg.in/yaml.v3" "github.com/spf13/viper" @@ -257,6 +261,79 @@ func addDynamicServiceCommands() error { endpointName := config.Endpoint var apiEndpoint string + // For local environment + if strings.HasPrefix(config.Endpoint, "grpc://") { + endpoint := strings.TrimPrefix(config.Endpoint, "grpc://") + + conn, err := grpc.Dial(endpoint, grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(time.Second)) + if err != nil { + pterm.DefaultBox.WithTitle("Local gRPC Server Not Found"). + WithTitleTopCenter(). + WithBoxStyle(pterm.NewStyle(pterm.FgYellow)). + Printfln("Unable to connect to local gRPC server.\nPlease make sure your gRPC server is running on %s", config.Endpoint) + return nil + } + defer func(conn *grpc.ClientConn) { + err := conn.Close() + if err != nil { + + } + }(conn) + + ctx := context.Background() + refClient := grpcreflect.NewClientV1Alpha(ctx, grpc_reflection_v1alpha.NewServerReflectionClient(conn)) + defer refClient.Reset() + + services, err := refClient.ListServices() + if err != nil { + return err + } + + // Check if plugin service exists + hasPlugin := false + microservices := make(map[string]bool) + + for _, service := range services { + // Skip grpc reflection and health check services + if strings.HasPrefix(service, "grpc.") { + continue + } + + // Handle plugin service + if strings.Contains(service, ".plugin.") { + hasPlugin = true + continue + } + + // Handle SpaceONE microservices + if strings.Contains(service, "spaceone.api.") { + parts := strings.Split(service, ".") + if len(parts) >= 4 { + serviceName := parts[2] + // Skip core service and version prefixes + if serviceName != "core" && !strings.HasPrefix(serviceName, "v") { + microservices[serviceName] = true + } + } + } + } + + if hasPlugin { + cmd := createServiceCommand(config.Environment) + cmd.GroupID = "available" + rootCmd.AddCommand(cmd) + } + + // Add commands for other microservices + for serviceName := range microservices { + cmd := createServiceCommand(serviceName) + cmd.GroupID = "available" + rootCmd.AddCommand(cmd) + } + + return nil + } + if strings.HasPrefix(endpointName, "grpc+ssl://") { apiEndpoint = endpointName } else if strings.HasPrefix(endpointName, "http://") || strings.HasPrefix(endpointName, "https://") { diff --git a/pkg/configs/endpoint.go b/pkg/configs/endpoint.go index 704fddd..dfdbd25 100644 --- a/pkg/configs/endpoint.go +++ b/pkg/configs/endpoint.go @@ -132,6 +132,12 @@ func GetServiceEndpoint(config *Setting, serviceName string) (string, error) { return "", fmt.Errorf("endpoint not found in environment config") } + if strings.HasPrefix(envConfig.Endpoint, "grpc://") { + if strings.Contains(envConfig.Endpoint, "localhost") { + return envConfig.Endpoint, nil + } + } + // Get console API endpoint apiEndpoint, err := GetAPIEndpoint(envConfig.Endpoint) if err != nil { @@ -163,6 +169,12 @@ func GetServiceEndpoint(config *Setting, serviceName string) (string, error) { } func FetchEndpointsMap(endpoint string) (map[string]string, error) { + if strings.HasPrefix(endpoint, "grpc://") { + endpointsMap := make(map[string]string) + endpointsMap["local"] = endpoint + return endpointsMap, nil + } + // Get identity service endpoint identityEndpoint, hasIdentityService, err := GetIdentityEndpoint(endpoint) listEndpointsUrl := endpoint + "/identity/endpoint/list" diff --git a/pkg/format/output.go b/pkg/format/output.go index f6d1b2f..4599a47 100644 --- a/pkg/format/output.go +++ b/pkg/format/output.go @@ -123,7 +123,7 @@ func RenderTable(data [][]string) { previousService := "" // Create table with headers - table := pterm.TableData{{"Service", "Verb", "Resource", "Short Names"}} + table := pterm.TableData{{"Service", "Verb", "Resource", "Alias"}} for _, row := range data { service := row[0] diff --git a/pkg/transport/service.go b/pkg/transport/service.go index d7c8d47..41335ef 100644 --- a/pkg/transport/service.go +++ b/pkg/transport/service.go @@ -183,7 +183,7 @@ func FetchService(serviceName string, verb string, resourceName string, options var apiEndpoint string var identityEndpoint string var hasIdentityService bool - if config.Environment == "local" { + if strings.HasPrefix(config.Environments[config.Environment].Endpoint, "grpc://") { hostPort = strings.TrimPrefix(config.Environments[config.Environment].Endpoint, "grpc://") } else { apiEndpoint, err = configs.GetAPIEndpoint(config.Environments[config.Environment].Endpoint) @@ -768,12 +768,13 @@ func discoverService(refClient *grpcreflect.Client, serviceName string, resource } for _, service := range services { - if strings.Contains(service, fmt.Sprintf("spaceone.api.%s", serviceName)) && - strings.HasSuffix(service, resourceName) { + if strings.Contains(service, ".plugin.") && strings.HasSuffix(service, resourceName) { return service, nil } + } - if strings.Contains(service, serviceName) && + for _, service := range services { + if strings.Contains(service, fmt.Sprintf("spaceone.api.%s", serviceName)) && strings.HasSuffix(service, resourceName) { return service, nil }