From 6f1dcab3767db847932281457ed5a172793b82c3 Mon Sep 17 00:00:00 2001 From: Youngjin Jo Date: Wed, 18 Dec 2024 22:33:02 +0900 Subject: [PATCH] refactor: add progress bar and save services_verbs to one file Signed-off-by: Youngjin Jo --- cmd/common/helpers.go | 111 +++++++++++++++++++++--------------- cmd/root.go | 129 ++++++++++++++++-------------------------- 2 files changed, 112 insertions(+), 128 deletions(-) diff --git a/cmd/common/helpers.go b/cmd/common/helpers.go index 1473b74..cd84732 100644 --- a/cmd/common/helpers.go +++ b/cmd/common/helpers.go @@ -32,7 +32,6 @@ func convertServiceNameToEndpoint(serviceName string) string { } func BuildVerbResourceMap(serviceName string) (map[string][]string, error) { - // Try to load from cache first home, err := os.UserHomeDir() if err != nil { return nil, fmt.Errorf("failed to get home directory: %v", err) @@ -44,71 +43,43 @@ func BuildVerbResourceMap(serviceName string) (map[string][]string, error) { } if strings.HasPrefix(config.Environment, "local-") { - conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure()) - if err != nil { - return nil, fmt.Errorf("local gRPC server connection failed: %v", err) - } - defer conn.Close() - - ctx := context.Background() - refClient := grpcreflect.NewClient(ctx, grpc_reflection_v1alpha.NewServerReflectionClient(conn)) - defer refClient.Reset() - - services, err := refClient.ListServices() - if err != nil { - return nil, fmt.Errorf("failed to list local services: %v", err) - } - - verbResourceMap := make(map[string][]string) - for _, s := range services { - if !strings.Contains(s, fmt.Sprintf(".%s.", serviceName)) { - continue - } - - serviceDesc, err := refClient.ResolveService(s) - if err != nil { - continue - } - - resourceName := s[strings.LastIndex(s, ".")+1:] - for _, method := range serviceDesc.GetMethods() { - verb := method.GetName() - if resources, ok := verbResourceMap[verb]; ok { - verbResourceMap[verb] = append(resources, resourceName) - } else { - verbResourceMap[verb] = []string{resourceName} - } - } - } - - return verbResourceMap, nil + return handleLocalEnvironment(serviceName) } cacheDir := filepath.Join(home, ".cfctl", "cache", config.Environment) - cacheFile := filepath.Join(cacheDir, fmt.Sprintf("%s_verbs.yaml", serviceName)) + cacheFile := filepath.Join(cacheDir, "verb_resources.yaml") - // Check if cache exists and is fresh (less than 1 hour old) if info, err := os.Stat(cacheFile); err == nil { if time.Since(info.ModTime()) < time.Hour { data, err := os.ReadFile(cacheFile) if err == nil { - verbResourceMap := make(map[string][]string) - if err := yaml.Unmarshal(data, &verbResourceMap); err == nil { - return verbResourceMap, nil + var allServices map[string]map[string][]string + if err := yaml.Unmarshal(data, &allServices); err == nil { + if verbMap, exists := allServices[serviceName]; exists { + return verbMap, nil + } } } } } - // Cache miss or expired, fetch from server verbResourceMap, err := fetchVerbResourceMap(serviceName, config) if err != nil { return nil, err } - // Save to cache + var allServices map[string]map[string][]string + if data, err := os.ReadFile(cacheFile); err == nil { + yaml.Unmarshal(data, &allServices) + } + if allServices == nil { + allServices = make(map[string]map[string][]string) + } + + allServices[serviceName] = verbResourceMap + if err := os.MkdirAll(cacheDir, 0755); err == nil { - data, err := yaml.Marshal(verbResourceMap) + data, err := yaml.Marshal(allServices) if err == nil { os.WriteFile(cacheFile, data, 0644) } @@ -117,6 +88,52 @@ func BuildVerbResourceMap(serviceName string) (map[string][]string, error) { return verbResourceMap, nil } +func handleLocalEnvironment(serviceName string) (map[string][]string, error) { + if serviceName != "plugin" { + return nil, fmt.Errorf("only plugin service is supported in local environment") + } + + // local 환경의 plugin 서비스 endpoint 설정 + conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure()) + if err != nil { + return nil, fmt.Errorf("failed to connect to local plugin service: %v", err) + } + defer conn.Close() + + ctx := context.Background() + refClient := grpcreflect.NewClient(ctx, grpc_reflection_v1alpha.NewServerReflectionClient(conn)) + defer refClient.Reset() + + services, err := refClient.ListServices() + if err != nil { + return nil, fmt.Errorf("failed to list local services: %v", err) + } + + verbResourceMap := make(map[string][]string) + for _, s := range services { + if !strings.Contains(s, ".plugin.") { + continue + } + + serviceDesc, err := refClient.ResolveService(s) + if err != nil { + continue + } + + resourceName := s[strings.LastIndex(s, ".")+1:] + for _, method := range serviceDesc.GetMethods() { + verb := method.GetName() + if resources, ok := verbResourceMap[verb]; ok { + verbResourceMap[verb] = append(resources, resourceName) + } else { + verbResourceMap[verb] = []string{resourceName} + } + } + } + + return verbResourceMap, nil +} + func fetchVerbResourceMap(serviceName string, config *Config) (map[string][]string, error) { envConfig := config.Environments[config.Environment] if envConfig.URL == "" { diff --git a/cmd/root.go b/cmd/root.go index 4036a5c..8ebd802 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,7 +1,6 @@ package cmd import ( - "context" "fmt" "gopkg.in/yaml.v3" "log" @@ -10,7 +9,6 @@ import ( "strings" "time" - "github.com/jhump/protoreflect/grpcreflect" "github.com/spf13/viper" "github.com/cloudforet-io/cfctl/cmd/common" @@ -18,8 +16,6 @@ import ( "github.com/pterm/pterm" "github.com/spf13/cobra" - "google.golang.org/grpc" - "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" ) var cfgFile string @@ -105,13 +101,9 @@ func init() { // Determine if the current command is 'setting environment -l' skipDynamicCommands := false - if len(os.Args) >= 3 && os.Args[1] == "setting" && os.Args[2] == "environment" { - for _, arg := range os.Args[3:] { - if arg == "-l" || arg == "--list" { - skipDynamicCommands = true - break - } - } + if len(os.Args) >= 2 && os.Args[1] == "setting" { + // Skip dynamic commands for all setting related operations + skipDynamicCommands = true } if !skipDynamicCommands { @@ -239,7 +231,19 @@ func showInitializationGuide(originalErr error) { } func addDynamicServiceCommands() error { - // If we already have in-memory cache, use it + config, err := loadConfig() + if err != nil { + return err + } + + // For local environment, only add plugin command + if strings.HasPrefix(config.Environment, "local-") { + cmd := createServiceCommand("plugin") + rootCmd.AddCommand(cmd) + return nil + } + + // For non-local environments, continue with existing logic... if cachedEndpointsMap != nil { for serviceName := range cachedEndpointsMap { cmd := createServiceCommand(serviceName) @@ -248,89 +252,52 @@ func addDynamicServiceCommands() error { return nil } - // Load configuration - setting, err := loadConfig() - if err != nil { - return fmt.Errorf("failed to load setting: %v", err) - } - - // Handle local environment - if strings.HasPrefix(setting.Environment, "local-") { - // Try connecting to local gRPC server - conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(2*time.Second)) - if err != nil { - pterm.Error.Printf("Cannot connect to local gRPC server (grpc://localhost:50051)\n") - pterm.Info.Println("Please check if your gRPC server is running") - return fmt.Errorf("local gRPC server connection failed: %v", err) + // Only show progress bar when actually fetching services + if len(os.Args) == 1 || (len(os.Args) > 1 && os.Args[1] != "setting") { + // Create progress bar + progressbar, _ := pterm.DefaultProgressbar. + WithTotal(4). + WithTitle("Initializing services"). + Start() + + progressbar.UpdateTitle("Preparing endpoint configuration") + endpoint := config.Endpoint + if !strings.Contains(endpoint, "identity") { + parts := strings.Split(endpoint, "://") + if len(parts) == 2 { + hostParts := strings.Split(parts[1], ".") + if len(hostParts) >= 4 { + env := hostParts[2] + endpoint = fmt.Sprintf("grpc+ssl://identity.api.%s.spaceone.dev:443", env) + } + } } - defer conn.Close() + progressbar.Increment() + time.Sleep(time.Millisecond * 300) - // Create reflection client - ctx := context.Background() - refClient := grpcreflect.NewClient(ctx, grpc_reflection_v1alpha.NewServerReflectionClient(conn)) - defer refClient.Reset() - - // List all services - services, err := refClient.ListServices() + progressbar.UpdateTitle("Fetching available services") + endpointsMap, err := other.FetchEndpointsMap(endpoint) if err != nil { - return fmt.Errorf("failed to list local services: %v", err) + return fmt.Errorf("failed to fetch services: %v", err) } + progressbar.Increment() + time.Sleep(time.Millisecond * 300) - endpointsMap := make(map[string]string) - for _, svc := range services { - if strings.HasPrefix(svc, "spaceone.api.") { - parts := strings.Split(svc, ".") - if len(parts) >= 4 { - serviceName := parts[2] - // Skip core service - if serviceName != "core" { - endpointsMap[serviceName] = "grpc://localhost:50051" - } - } - } - } - - // Store in both memory and file cache + progressbar.UpdateTitle("Creating cache for faster subsequent runs") cachedEndpointsMap = endpointsMap if err := saveEndpointsCache(endpointsMap); err != nil { fmt.Fprintf(os.Stderr, "Warning: Failed to cache endpoints: %v\n", err) } + progressbar.Increment() + time.Sleep(time.Millisecond * 300) - // Create commands for each service + progressbar.UpdateTitle("Registering verbs and resources commands to the cache") for serviceName := range endpointsMap { cmd := createServiceCommand(serviceName) rootCmd.AddCommand(cmd) } - - return nil - } - - // Continue with existing logic for non-local environments - endpoint := setting.Endpoint - if !strings.Contains(endpoint, "identity") { - parts := strings.Split(endpoint, "://") - if len(parts) == 2 { - hostParts := strings.Split(parts[1], ".") - if len(hostParts) >= 4 { - env := hostParts[2] - endpoint = fmt.Sprintf("grpc+ssl://identity.api.%s.spaceone.dev:443", env) - } - } - } - - endpointsMap, err := other.FetchEndpointsMap(endpoint) - if err != nil { - return fmt.Errorf("failed to fetch services: %v", err) - } - - cachedEndpointsMap = endpointsMap - if err := saveEndpointsCache(endpointsMap); err != nil { - fmt.Fprintf(os.Stderr, "Warning: Failed to cache endpoints: %v\n", err) - } - - for serviceName := range endpointsMap { - cmd := createServiceCommand(serviceName) - rootCmd.AddCommand(cmd) + progressbar.Increment() + time.Sleep(time.Millisecond * 300) } return nil