Skip to content

Commit

Permalink
refactor: modify api-resources command for user config
Browse files Browse the repository at this point in the history
Signed-off-by: Youngjin Jo <youngjinjo@megazone.com>
  • Loading branch information
yjinjo committed Nov 25, 2024
1 parent 1b4d481 commit d7bc46b
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 72 deletions.
75 changes: 63 additions & 12 deletions cmd/other/apiResources.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,34 +36,85 @@ var ApiResourcesCmd = &cobra.Command{
Use: "api-resources",
Short: "Displays supported API resources",
Run: func(cmd *cobra.Command, args []string) {
// Load the main configuration file
home, err := os.UserHomeDir()
if err != nil {
log.Fatalf("Unable to find home directory: %v", err)
}

configFile := filepath.Join(home, ".cfctl", "config.yaml")
viper.SetConfigFile(configFile)
if err := viper.ReadInConfig(); err != nil {
log.Fatalf("Error reading config file: %v", err)
cacheConfigFile := filepath.Join(home, ".cfctl", "cache", "config.yaml")

var currentEnv string
var envConfig *viper.Viper

// Try to read main config first
mainV := viper.New()
mainV.SetConfigFile(configFile)
mainConfigErr := mainV.ReadInConfig()

if mainConfigErr == nil {
// Main config exists, try to get environment
currentEnv = mainV.GetString("environment")
if currentEnv != "" {
envConfig = mainV.Sub(fmt.Sprintf("environments.%s", currentEnv))
}
}

// Get the current environment
currentEnv := viper.GetString("environment")
if currentEnv == "" {
log.Fatalf("No active environment specified in %s", configFile)
// If main config doesn't exist or has no environment set, try cache config
if mainConfigErr != nil || currentEnv == "" || envConfig == nil {
cacheV := viper.New()
cacheV.SetConfigFile(cacheConfigFile)
if err := cacheV.ReadInConfig(); err != nil {
log.Fatalf("Error reading both config files:\nMain config: %v\nCache config: %v", mainConfigErr, err)
}

// If no current environment set, try to get it from cache config
if currentEnv == "" {
currentEnv = cacheV.GetString("environment")
}

// If still no environment, try to find first user environment
if currentEnv == "" {
envs := cacheV.GetStringMap("environments")
for env := range envs {
if strings.HasSuffix(env, "-user") {
currentEnv = env
break
}
}
}

// Try to get environment config from cache if not found in main config
if envConfig == nil && currentEnv != "" {
envConfig = cacheV.Sub(fmt.Sprintf("environments.%s", currentEnv))
}
}

// Get environment-specific configurations
envConfig := viper.Sub(fmt.Sprintf("environments.%s", currentEnv))
if envConfig == nil {
log.Fatalf("No configuration found for environment: %s", currentEnv)
// Try one more time with both configs
mainV := viper.New()
mainV.SetConfigFile(configFile)
if err := mainV.ReadInConfig(); err == nil {
envConfig = mainV.Sub(fmt.Sprintf("environments.%s", currentEnv))
}

if envConfig == nil {
cacheV := viper.New()
cacheV.SetConfigFile(cacheConfigFile)
if err := cacheV.ReadInConfig(); err == nil {
envConfig = cacheV.Sub(fmt.Sprintf("environments.%s", currentEnv))
}
}

if envConfig == nil {
log.Fatalf("No configuration found for environment '%s' in either config file", currentEnv)
}
}

// Continue with the rest of the code...
endpoint := envConfig.GetString("endpoint")
proxy := envConfig.GetBool("proxy")

// Validate endpoint and proxy
if !proxy || !strings.Contains(endpoint, "identity") {
log.Fatalf("Endpoint for environment '%s' is not valid for fetching resources.", currentEnv)
}
Expand Down
182 changes: 122 additions & 60 deletions cmd/other/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -705,22 +705,28 @@ func loadConfig(v *viper.Viper, configPath string) error {
v.Set("environments", map[string]interface{}{})
v.Set("environment", "")

// Write the default config to the file
if err := v.WriteConfigAs(configPath); err != nil {
return fmt.Errorf("failed to create config file '%s': %w", configPath, err)
// Convert to YAML with 2-space indentation
config := map[string]interface{}{
"environments": map[string]interface{}{},
"environment": "",
}

// Read the newly created config file
if err := v.ReadInConfig(); err != nil {
return fmt.Errorf("failed to read newly created config file '%s': %w", configPath, err)
data, err := yaml.Marshal(config)
if err != nil {
return fmt.Errorf("failed to marshal config: %w", err)
}
} else {
// Read the existing config file
if err := v.ReadInConfig(); err != nil {
return fmt.Errorf("failed to read config file '%s': %w", configPath, err)

// Write the default config to the file
if err := os.WriteFile(configPath, data, 0644); err != nil {
return fmt.Errorf("failed to create config file '%s': %w", configPath, err)
}
}

// Read the config file
if err := v.ReadInConfig(); err != nil {
return fmt.Errorf("failed to read config file '%s': %w", configPath, err)
}

return nil
}

Expand Down Expand Up @@ -793,92 +799,148 @@ func parseEnvNameFromURL(urlStr string) (string, error) {
return "", fmt.Errorf("URL does not match any known environment patterns")
}

// updateConfig handles the actual configuration update
func updateConfig(envName, baseURL, mode string) {
var configPath string
var v *viper.Viper
// updateConfig updates the configuration files based on the environment type
func updateConfig(envName, urlStr, configType string) {
configDir := GetConfigDir()
mainConfigPath := filepath.Join(configDir, "config.yaml")

if mode == "app" {
configPath = filepath.Join(GetConfigDir(), "config.yaml")
v = viper.New()
} else {
configPath = filepath.Join(GetConfigDir(), "cache", "config.yaml")
v = viper.New()
// Create config directory if it doesn't exist
if err := os.MkdirAll(filepath.Dir(mainConfigPath), 0755); err != nil {
pterm.Error.Printf("Failed to create config directory: %v\n", err)
return
}

// Load or create the config file
if err := loadConfig(v, configPath); err != nil {
pterm.Error.Println(err)
return
// Initialize main viper instance
mainV := viper.New()
mainV.SetConfigFile(mainConfigPath)

// Read existing config or create new one
if err := mainV.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
pterm.Error.Printf("Error reading config file: %v\n", err)
return
}
}

// Check if the environment already exists
if v.IsSet(fmt.Sprintf("environments.%s", envName)) {
if mainV.IsSet(fmt.Sprintf("environments.%s", envName)) {
pterm.Warning.Printf("Environment '%s' already exists. Do you want to overwrite it? (y/n): ", envName)

// Get user input
var response string
fmt.Scanln(&response)
response = strings.ToLower(strings.TrimSpace(response))

// If user selects "n", exit the function
if response != "y" {
pterm.Info.Printf("Skipping initialization for '%s'. No changes were made.\n", envName)
return
}
}

var newEndpoint string
if baseURL != "" {
var err error
newEndpoint, err = constructEndpoint(baseURL)
// Update environment in main config
mainV.Set("environment", envName)

// Handle app type configuration
if configType == "app" && urlStr != "" {
endpoint, err := constructEndpoint(urlStr)
if err != nil {
pterm.Error.Println("Failed to construct endpoint:", err)
pterm.Error.Printf("Failed to construct endpoint: %v\n", err)
return
}
} else {
newEndpoint = "grpc://localhost:50051"
}

// Set default values for the environment
v.Set(fmt.Sprintf("environments.%s.endpoint", envName), newEndpoint)
v.Set(fmt.Sprintf("environments.%s.token", envName), "")
mainV.Set(fmt.Sprintf("environments.%s.endpoint", envName), endpoint)
mainV.Set(fmt.Sprintf("environments.%s.proxy", envName), true)
mainV.Set(fmt.Sprintf("environments.%s.token", envName), "")

if strings.Contains(newEndpoint, "identity") {
v.Set(fmt.Sprintf("environments.%s.proxy", envName), true)
} else {
v.Set(fmt.Sprintf("environments.%s.proxy", envName), false)
if err := mainV.WriteConfig(); err != nil {
pterm.Error.Printf("Failed to write config: %v\n", err)
return
}
}

// Write the updated configuration back to config.yaml or cache/config.yaml
if err := v.WriteConfig(); err != nil {
pterm.Error.Printf("Failed to write configuration: %v\n", err)
return
}
// Handle user type configuration
if configType == "user" {
cacheConfigPath := filepath.Join(configDir, "cache", "config.yaml")
if err := os.MkdirAll(filepath.Dir(cacheConfigPath), 0755); err != nil {
pterm.Error.Printf("Failed to create cache directory: %v\n", err)
return
}

// If mode is 'app', set the 'environment' field
if mode == "app" {
v.Set("environment", envName)
cacheV := viper.New()
cacheV.SetConfigFile(cacheConfigPath)

// Write the updated app configuration
if err := v.WriteConfig(); err != nil {
pterm.Error.Printf("Failed to write app config: %v\n", err)
return
if err := cacheV.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
pterm.Error.Printf("Error reading cache config: %v\n", err)
return
}
}
}

// If initializing a user environment, remove 'environment' field from user config
if mode == "user" {
err := removeEnvironmentField(v)
if err != nil {
pterm.Error.Printf("Failed to remove environment from user config: %v\n", err)
if cacheV.IsSet(fmt.Sprintf("environments.%s", envName)) {
pterm.Warning.Printf("Environment '%s' already exists in cache config. Do you want to overwrite it? (y/n): ", envName)

var response string
fmt.Scanln(&response)
response = strings.ToLower(strings.TrimSpace(response))

if response != "y" {
pterm.Info.Printf("Skipping initialization for '%s' in cache config. No changes were made.\n", envName)
return
}
}

if urlStr != "" {
endpoint, err := constructEndpoint(urlStr)
if err != nil {
pterm.Error.Printf("Failed to construct endpoint: %v\n", err)
return
}

cacheV.Set(fmt.Sprintf("environments.%s.endpoint", envName), endpoint)
cacheV.Set(fmt.Sprintf("environments.%s.proxy", envName), true)
cacheV.Set(fmt.Sprintf("environments.%s.token", envName), "")
}

if err := cacheV.WriteConfig(); err != nil {
pterm.Error.Printf("Failed to write cache config: %v\n", err)
return
}
}

pterm.Success.Printf("Environment '%s' successfully initialized.\n", envName)
}

// convertToStringMap converts map[interface{}]interface{} to map[string]interface{}
func convertToStringMap(m map[interface{}]interface{}) map[string]interface{} {
result := make(map[string]interface{})
for k, v := range m {
switch v := v.(type) {
case map[interface{}]interface{}:
result[k.(string)] = convertToStringMap(v)
case []interface{}:
result[k.(string)] = convertToSlice(v)
default:
result[k.(string)] = v
}
}
return result
}

// convertToSlice handles slice conversion if needed
func convertToSlice(s []interface{}) []interface{} {
result := make([]interface{}, len(s))
for i, v := range s {
switch v := v.(type) {
case map[interface{}]interface{}:
result[i] = convertToStringMap(v)
case []interface{}:
result[i] = convertToSlice(v)
default:
result[i] = v
}
}
return result
}

// removeEnvironmentField removes the 'environment' field from the given Viper instance
func removeEnvironmentField(v *viper.Viper) error {
config := make(map[string]interface{})
Expand Down

0 comments on commit d7bc46b

Please sign in to comment.