diff --git a/cmd/common/api_resources.go b/cmd/common/api_resources.go index badc0bf..4692f25 100644 --- a/cmd/common/api_resources.go +++ b/cmd/common/api_resources.go @@ -35,7 +35,7 @@ func FetchApiResourcesCmd(serviceName string) *cobra.Command { } func ListAPIResources(serviceName string) error { - setting, err := configs.LoadSetting() + setting, err := configs.SetSettingFile() if err != nil { return fmt.Errorf("failed to load setting: %v", err) } @@ -87,7 +87,7 @@ func loadShortNames() (map[string]string, error) { return shortNamesMap, nil } -func FetchServiceResources(serviceName, endpoint string, shortNamesMap map[string]string, config *configs.Setting) ([][]string, error) { +func FetchServiceResources(serviceName, endpoint string, shortNamesMap map[string]string, config *configs.Environments) ([][]string, error) { parts := strings.Split(endpoint, "://") if len(parts) != 2 { return nil, fmt.Errorf("invalid endpoint format: %s", endpoint) diff --git a/cmd/other/setting.go b/cmd/other/setting.go index f38c16d..93b5c01 100644 --- a/cmd/other/setting.go +++ b/cmd/other/setting.go @@ -1372,7 +1372,7 @@ func updateSetting(envName, endpoint, envSuffix string) { v.Set(envKey, endpoint) proxyKey := fmt.Sprintf("environments.%s.proxy", envName) - if strings.HasPrefix(endpoint, "grpc://") || strings.HasPrefix(endpoint, "grpc+ssl://") { + if strings.HasPrefix(endpoint, "grpc+ssl://") { isProxy, err := transport.CheckIdentityProxyAvailable(endpoint) if err != nil { pterm.Warning.Printf("Failed to check gRPC endpoint: %v\n", err) diff --git a/cmd/root.go b/cmd/root.go index dbc9058..b9430b8 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -270,7 +270,7 @@ func addDynamicServiceCommands() error { 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) + Printfln("Current environment: %s\nUnable to connect to local gRPC server.\nPlease make sure your gRPC server is running on %s", config.Environment, config.Endpoint) return nil } defer func(conn *grpc.ClientConn) { @@ -376,7 +376,7 @@ func addDynamicServiceCommands() error { // If no cached endpoints, show progress with detailed messages progressbar, _ := pterm.DefaultProgressbar. WithTotal(4). - WithTitle(fmt.Sprintf("Setting up %s environment", config.Environment)). + WithTitle(fmt.Sprintf("Environments up %s environment", config.Environment)). Start() progressbar.UpdateTitle("Fetching available service endpoints from the API server") diff --git a/pkg/configs/endpoint.go b/pkg/configs/endpoint.go index dfdbd25..ae52e04 100644 --- a/pkg/configs/endpoint.go +++ b/pkg/configs/endpoint.go @@ -126,7 +126,7 @@ func GetIdentityEndpoint(apiEndpoint string) (string, bool, error) { return "", false, nil } -func GetServiceEndpoint(config *Setting, serviceName string) (string, error) { +func GetServiceEndpoint(config *Environments, serviceName string) (string, error) { envConfig := config.Environments[config.Environment] if envConfig.Endpoint == "" { return "", fmt.Errorf("endpoint not found in environment config") diff --git a/pkg/configs/setting_file.go b/pkg/configs/setting_file.go new file mode 100644 index 0000000..6c119be --- /dev/null +++ b/pkg/configs/setting_file.go @@ -0,0 +1,151 @@ +package configs + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/spf13/viper" +) + +// Environments represents the complete configuration structure +type Environments struct { + Environment string `yaml:"environment"` // Current active environment + Environments map[string]Environment `yaml:"environments"` // Map of available environments +} + +// Environment represents a single environment configuration +type Environment struct { + Endpoint string `yaml:"endpoint"` // gRPC or HTTP endpoint URL + Proxy string `yaml:"proxy"` // Proxy server address if required + Token string `yaml:"token"` // Authentication token +} + +// SetSettingFile loads the setting from the default location (~/.cfctl/setting.yaml) +func SetSettingFile() (*Environments, error) { + settingPath, err := GetSettingFilePath() + if err != nil { + return nil, err + } + + currentEnvName, err := getCurrentEnvName(settingPath) + if err != nil { + return nil, err + } + + currentEnvValues, err := getCurrentEnvValues(currentEnvName.Environment) + if err != nil { + return nil, err + } + + return &Environments{ + Environment: currentEnvName.Environment, + Environments: map[string]Environment{ + currentEnvName.Environment: *currentEnvValues, + }, + }, nil +} + +// GetSettingFilePath returns the path to the setting file in the .cfctl directory +func GetSettingFilePath() (string, error) { + home, err := os.UserHomeDir() + if err != nil { + return "", fmt.Errorf("failed to get home directory: %v", err) + } + + return filepath.Join(home, ".cfctl", "setting.yaml"), nil +} + +// getCurrentEnvName loads the main setting file using viper +func getCurrentEnvName(settingPath string) (*Environments, error) { + v, err := setViperWithSetting(settingPath) + if err != nil { + return nil, err + } + + currentEnv := v.GetString("environment") + if currentEnv == "" { + return nil, fmt.Errorf("no environment set in settings.yaml") + } + + return &Environments{Environment: currentEnv}, nil +} + +// getCurrentEnvValues loads environment-specific setting +func getCurrentEnvValues(env string) (*Environment, error) { + settingPath, err := GetSettingFilePath() + if err != nil { + return nil, err + } + + v, err := setViperWithSetting(settingPath) + if err != nil { + return nil, err + } + + envSetting := &Environment{ + Endpoint: v.GetString(fmt.Sprintf("environments.%s.endpoint", env)), + Proxy: v.GetString(fmt.Sprintf("environments.%s.proxy", env)), + } + + if err := loadToken(env, envSetting); err != nil { + return nil, err + } + + return envSetting, nil +} + +// loadToken loads the appropriate token based on environment type +func loadToken(env string, envSetting *Environment) error { + if strings.HasSuffix(env, "-user") { + return loadUserToken(env, envSetting) + } + + return loadAppToken(env, envSetting) +} + +// loadUserToken loads token for user environments from access_token file +func loadUserToken(env string, envSetting *Environment) error { + home, err := os.UserHomeDir() + if err != nil { + return fmt.Errorf("failed to get home directory: %v", err) + } + + tokenPath := filepath.Join(home, ".cfctl", "cache", env, "access_token") + tokenBytes, err := os.ReadFile(tokenPath) + if err == nil { + envSetting.Token = strings.TrimSpace(string(tokenBytes)) + } + + return nil +} + +// loadAppToken loads token for app environments from main setting +func loadAppToken(env string, envSetting *Environment) error { + settingPath, err := GetSettingFilePath() + if err != nil { + return err + } + + v, err := setViperWithSetting(settingPath) + if err != nil { + return err + } + + envSetting.Token = v.GetString(fmt.Sprintf("environments.%s.token", env)) + + return nil +} + +// setViperWithSetting creates a new viper instance with the given config file +func setViperWithSetting(settingPath string) (*viper.Viper, error) { + v := viper.New() + v.SetConfigFile(settingPath) + v.SetConfigType("yaml") + if err := v.ReadInConfig(); err != nil { + return nil, fmt.Errorf("failed to read config file: %v", err) + } + + return v, nil +} diff --git a/pkg/configs/settings.go b/pkg/configs/settings.go deleted file mode 100644 index d17e15d..0000000 --- a/pkg/configs/settings.go +++ /dev/null @@ -1,188 +0,0 @@ -package configs - -import ( - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/spf13/viper" -) - -// Environment represents a single environment configuration -type Environment struct { - Endpoint string `yaml:"endpoint"` // gRPC or HTTP endpoint URL - Proxy string `yaml:"proxy"` // Proxy server address if required - Token string `yaml:"token"` // Authentication token - URL string `yaml:"url"` // Web console URL -} - -// Setting represents the complete configuration structure -type Setting struct { - Environment string `yaml:"environment"` // Current active environment - Environments map[string]Environment `yaml:"environments"` // Map of available environments -} - -// SettingPaths contains all setting related paths -type SettingPaths struct { - CacheDir string // ~/.cfctl/cache - SettingDir string // ~/.cfctl - SettingFile string // ~/.cfctl/setting.yaml -} - -// LoadSetting loads the setting from the default location (~/.cfctl/setting.yaml) -// and handles environment-specific token loading. -func LoadSetting() (*Setting, error) { - settingPath, err := GetSettingPath() - if err != nil { - return nil, err - } - - setting, err := loadMainSetting(settingPath) - if err != nil { - return nil, err - } - - envSetting, err := loadEnvironmentSetting(setting.Environment) - if err != nil { - return nil, err - } - - return &Setting{ - Environment: setting.Environment, - Environments: map[string]Environment{ - setting.Environment: *envSetting, - }, - }, nil -} - -// GetCachePath returns the path to environment-specific cache directory -func GetCachePath(env string) (string, error) { - paths, err := GetSettingPaths() - if err != nil { - return "", err - } - return filepath.Join(paths.CacheDir, env), nil -} - -// GetSettingPath returns the path to the main setting file -func GetSettingPath() (string, error) { - home, err := os.UserHomeDir() - if err != nil { - return "", fmt.Errorf("failed to get home directory: %v", err) - } - return filepath.Join(home, ".cfctl", "setting.yaml"), nil -} - -// GetSettingPaths returns all setting related paths -func GetSettingPaths() (*SettingPaths, error) { - home, err := os.UserHomeDir() - if err != nil { - return nil, fmt.Errorf("failed to get home directory: %v", err) - } - - return &SettingPaths{ - CacheDir: filepath.Join(home, ".cfctl", "cache"), - SettingDir: filepath.Join(home, ".cfctl"), - SettingFile: filepath.Join(home, ".cfctl", "setting.yaml"), - }, nil -} - -// GetTokenPath returns the path to environment-specific token file -func GetTokenPath(env string) (string, error) { - cachePath, err := GetCachePath(env) - if err != nil { - return "", err - } - return filepath.Join(cachePath, "access_token"), nil -} - -// loadMainSetting loads the main setting file using viper -func loadMainSetting(settingPath string) (*Setting, error) { - v := viper.New() - v.SetConfigFile(settingPath) - v.SetConfigType("yaml") - - if err := v.ReadInConfig(); err != nil { - return nil, fmt.Errorf("failed to read config file: %v", err) - } - - currentEnv := v.GetString("environment") - if currentEnv == "" { - return nil, fmt.Errorf("no environment set in settings.yaml") - } - - return &Setting{Environment: currentEnv}, nil -} - -// loadEnvironmentSetting loads environment-specific setting -func loadEnvironmentSetting(env string) (*Environment, error) { - home, err := os.UserHomeDir() - if err != nil { - return nil, fmt.Errorf("failed to get home directory: %v", err) - } - - v := viper.New() - settingPath := filepath.Join(home, ".cfctl", "setting.yaml") - v.SetConfigFile(settingPath) - v.SetConfigType("yaml") - - if err := v.ReadInConfig(); err != nil { - return nil, fmt.Errorf("failed to read settings.yaml: %v", err) - } - - envSetting := &Environment{ - Endpoint: v.GetString(fmt.Sprintf("environments.%s.endpoint", env)), - Proxy: v.GetString(fmt.Sprintf("environments.%s.proxy", env)), - URL: v.GetString(fmt.Sprintf("environments.%s.url", env)), - } - - if err := loadToken(env, envSetting); err != nil { - return nil, err - } - - return envSetting, nil -} - -// loadToken loads the appropriate token based on environment type -func loadToken(env string, envSetting *Environment) error { - if strings.HasSuffix(env, "-user") { - return loadUserToken(env, envSetting) - } - return loadAppToken(env, envSetting) -} - -// loadUserToken loads token for user environments from access_token file -func loadUserToken(env string, envSetting *Environment) error { - home, err := os.UserHomeDir() - if err != nil { - return fmt.Errorf("failed to get home directory: %v", err) - } - - tokenPath := filepath.Join(home, ".cfctl", "cache", env, "access_token") - tokenBytes, err := os.ReadFile(tokenPath) - if err == nil { - envSetting.Token = strings.TrimSpace(string(tokenBytes)) - } - return nil -} - -// loadAppToken loads token for app environments from main setting -func loadAppToken(env string, envSetting *Environment) error { - v := viper.New() - home, err := os.UserHomeDir() - if err != nil { - return fmt.Errorf("failed to get home directory: %v", err) - } - - settingPath := filepath.Join(home, ".cfctl", "setting.yaml") - v.SetConfigFile(settingPath) - v.SetConfigType("yaml") - - if err := v.ReadInConfig(); err != nil { - return fmt.Errorf("failed to read setting file: %v", err) - } - - envSetting.Token = v.GetString(fmt.Sprintf("environments.%s.token", env)) - return nil -} diff --git a/pkg/transport/service.go b/pkg/transport/service.go index 41335ef..e90fde5 100644 --- a/pkg/transport/service.go +++ b/pkg/transport/service.go @@ -230,11 +230,12 @@ func FetchService(serviceName string, verb string, resourceName string, options // Configure gRPC connection var conn *grpc.ClientConn - if config.Environment == "local" { + if strings.HasPrefix(config.Environments[config.Environment].Endpoint, "grpc://") { + hostPort := strings.TrimPrefix(config.Environments[config.Environment].Endpoint, "grpc://") // For local environment, use insecure connection - conn, err = grpc.Dial("localhost:50051", grpc.WithInsecure()) + conn, err = grpc.Dial(hostPort, grpc.WithInsecure()) if err != nil { - pterm.Error.Printf("Cannot connect to local gRPC server (localhost:50051)\n") + pterm.Error.Printf("Cannot connect to local gRPC server (%s)\n", hostPort) pterm.Info.Println("Please check if your gRPC server is running") return nil, fmt.Errorf("failed to connect to local server: %v", err) } @@ -492,8 +493,9 @@ func fetchJSONResponse(config *Config, serviceName string, verb string, resource fmt.Sprintf("page_size=%d", options.PageSize)) } - if config.Environment == "local" { - conn, err = grpc.Dial("localhost:50051", grpc.WithInsecure(), + if strings.HasPrefix(config.Environments[config.Environment].Endpoint, "grpc://") { + hostPort = strings.TrimPrefix(config.Environments[config.Environment].Endpoint, "grpc://") + conn, err = grpc.Dial(hostPort, grpc.WithInsecure(), grpc.WithDefaultCallOptions( grpc.MaxCallRecvMsgSize(10*1024*1024), grpc.MaxCallSendMsgSize(10*1024*1024),