Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add local environment #80

Merged
merged 9 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 55 additions & 43 deletions cmd/common/fetchService.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,22 +163,25 @@ func FetchService(serviceName string, verb string, resourceName string, options
hostPort := fmt.Sprintf("%s.api.%s.spaceone.dev:443", serviceName, envPrefix)

// Configure gRPC connection
tlsConfig := &tls.Config{
InsecureSkipVerify: false,
}
creds := credentials.NewTLS(tlsConfig)
opts := []grpc.DialOption{
grpc.WithTransportCredentials(creds),
grpc.WithDefaultCallOptions(
grpc.MaxCallRecvMsgSize(10*1024*1024), // 10MB
grpc.MaxCallSendMsgSize(10*1024*1024), // 10MB
),
}

// Establish the connection
conn, err := grpc.Dial(hostPort, opts...)
if err != nil {
return nil, fmt.Errorf("connection failed: unable to connect to %s: %v", hostPort, err)
var conn *grpc.ClientConn
if strings.HasPrefix(config.Environment, "local-") {
// For local environment, use insecure connection
conn, err = grpc.Dial("localhost:50051", grpc.WithInsecure())
if err != nil {
pterm.Error.Printf("Cannot connect to local gRPC server (localhost:50051)\n")
pterm.Info.Println("Please check if your gRPC server is running")
return nil, fmt.Errorf("failed to connect to local server: %v", err)
}
} else {
// Existing SSL connection logic for non-local environments
tlsConfig := &tls.Config{
InsecureSkipVerify: false,
}
creds := credentials.NewTLS(tlsConfig)
conn, err = grpc.Dial(hostPort, grpc.WithTransportCredentials(creds))
if err != nil {
return nil, fmt.Errorf("connection failed: %v", err)
}
}
defer conn.Close()

Expand Down Expand Up @@ -271,7 +274,7 @@ func FetchService(serviceName string, verb string, resourceName string, options
if results, ok := respMap["results"].([]interface{}); ok {
columns := strings.Split(options.Columns, ",")
filteredResults := make([]interface{}, len(results))

for i, result := range results {
if resultMap, ok := result.(map[string]interface{}); ok {
filteredMap := make(map[string]interface{})
Expand Down Expand Up @@ -353,7 +356,7 @@ func FetchService(serviceName string, verb string, resourceName string, options
if results, ok := respMap["results"].([]interface{}); ok {
columns := strings.Split(options.Columns, ",")
filteredResults := make([]interface{}, len(results))

for i, result := range results {
if resultMap, ok := result.(map[string]interface{}); ok {
filteredMap := make(map[string]interface{})
Expand Down Expand Up @@ -449,32 +452,42 @@ func loadConfig() (*Config, error) {
}

func fetchJSONResponse(config *Config, serviceName string, verb string, resourceName string, options *FetchOptions) ([]byte, error) {
var envPrefix string
if strings.HasPrefix(config.Environment, "dev-") {
envPrefix = "dev"
} else if strings.HasPrefix(config.Environment, "stg-") {
envPrefix = "stg"
}
hostPort := fmt.Sprintf("%s.api.%s.spaceone.dev:443", serviceName, envPrefix)

// Configure gRPC connection
var opts []grpc.DialOption
tlsConfig := &tls.Config{
InsecureSkipVerify: false,
var conn *grpc.ClientConn
var err error

if strings.HasPrefix(config.Environment, "local-") {
conn, err = grpc.Dial("localhost:50051", grpc.WithInsecure(),
grpc.WithDefaultCallOptions(
grpc.MaxCallRecvMsgSize(10*1024*1024),
grpc.MaxCallSendMsgSize(10*1024*1024),
))
if err != nil {
return nil, fmt.Errorf("connection failed: unable to connect to local server: %v", err)
}
} else {
var envPrefix string
if strings.HasPrefix(config.Environment, "dev-") {
envPrefix = "dev"
} else if strings.HasPrefix(config.Environment, "stg-") {
envPrefix = "stg"
}
hostPort := fmt.Sprintf("%s.api.%s.spaceone.dev:443", serviceName, envPrefix)
tlsConfig := &tls.Config{
InsecureSkipVerify: false,
}
creds := credentials.NewTLS(tlsConfig)

conn, err = grpc.Dial(hostPort,
grpc.WithTransportCredentials(creds),
grpc.WithDefaultCallOptions(
grpc.MaxCallRecvMsgSize(10*1024*1024),
grpc.MaxCallSendMsgSize(10*1024*1024),
))
if err != nil {
return nil, fmt.Errorf("connection failed: unable to connect to %s: %v", hostPort, err)
}
}
creds := credentials.NewTLS(tlsConfig)
opts = append(opts, grpc.WithTransportCredentials(creds))

opts = append(opts, grpc.WithDefaultCallOptions(
grpc.MaxCallRecvMsgSize(10*1024*1024), // 10MB
grpc.MaxCallSendMsgSize(10*1024*1024), // 10MB
))

// Establish the connection
conn, err := grpc.Dial(hostPort, opts...)
if err != nil {
return nil, fmt.Errorf("connection failed: unable to connect to %s: %v", hostPort, err)
}
defer conn.Close()

ctx := metadata.AppendToOutgoingContext(context.Background(), "token", config.Environments[config.Environment].Token)
Expand Down Expand Up @@ -991,4 +1004,3 @@ func formatCSVValue(val interface{}) string {
return fmt.Sprintf("%v", v)
}
}

55 changes: 28 additions & 27 deletions cmd/common/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,39 +34,42 @@ func BuildVerbResourceMap(serviceName string) (map[string][]string, error) {
return nil, fmt.Errorf("failed to load config: %v", err)
}

var envPrefix string
if strings.HasPrefix(config.Environment, "dev-") {
envPrefix = "dev"
} else if strings.HasPrefix(config.Environment, "stg-") {
envPrefix = "stg"
var conn *grpc.ClientConn
var refClient *grpcreflect.Client

if strings.HasPrefix(config.Environment, "local-") {
conn, err = grpc.Dial("localhost:50051", grpc.WithInsecure())
if err != nil {
return nil, fmt.Errorf("local connection failed: %v", err)
}
} else {
return nil, fmt.Errorf("unsupported environment prefix")
}
var envPrefix string
if strings.HasPrefix(config.Environment, "dev-") {
envPrefix = "dev"
} else if strings.HasPrefix(config.Environment, "stg-") {
envPrefix = "stg"
} else {
return nil, fmt.Errorf("unsupported environment prefix")
}

// Convert service name to endpoint format
endpointServiceName := convertServiceNameToEndpoint(serviceName)
hostPort := fmt.Sprintf("%s.api.%s.spaceone.dev:443", endpointServiceName, envPrefix)
endpointServiceName := convertServiceNameToEndpoint(serviceName)
hostPort := fmt.Sprintf("%s.api.%s.spaceone.dev:443", endpointServiceName, envPrefix)

// Configure gRPC connection
var opts []grpc.DialOption
tlsConfig := &tls.Config{
InsecureSkipVerify: false,
}
creds := credentials.NewTLS(tlsConfig)
opts = append(opts, grpc.WithTransportCredentials(creds))

// Establish the connection
conn, err := grpc.Dial(hostPort, opts...)
if err != nil {
return nil, fmt.Errorf("connection failed: unable to connect to %s: %v", hostPort, err)
tlsConfig := &tls.Config{
InsecureSkipVerify: false,
}
creds := credentials.NewTLS(tlsConfig)
conn, err = grpc.Dial(hostPort, grpc.WithTransportCredentials(creds))
if err != nil {
return nil, fmt.Errorf("connection failed: %v", err)
}
}
defer conn.Close()

ctx := metadata.AppendToOutgoingContext(context.Background(), "token", config.Environments[config.Environment].Token)
refClient := grpcreflect.NewClient(ctx, grpc_reflection_v1alpha.NewServerReflectionClient(conn))
refClient = grpcreflect.NewClient(ctx, grpc_reflection_v1alpha.NewServerReflectionClient(conn))
defer refClient.Reset()

// List all services
services, err := refClient.ListServices()
if err != nil {
return nil, fmt.Errorf("failed to list services: %v", err)
Expand All @@ -88,7 +91,6 @@ func BuildVerbResourceMap(serviceName string) (map[string][]string, error) {
continue
}

// Extract the resource name from the service name
parts := strings.Split(s, ".")
resourceName := parts[len(parts)-1]

Expand All @@ -101,10 +103,9 @@ func BuildVerbResourceMap(serviceName string) (map[string][]string, error) {
}
}

// Convert the map of resources to slices
result := make(map[string][]string)
for verb, resourcesSet := range verbResourceMap {
resources := []string{}
resources := make([]string, 0, len(resourcesSet))
for resource := range resourcesSet {
resources = append(resources, resource)
}
Expand Down
63 changes: 30 additions & 33 deletions cmd/other/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,15 @@ var settingInitLocalCmd = &cobra.Command{
Short: "Initialize configuration with a local environment",
Long: `Specify a local environment name to initialize the configuration.`,
Args: cobra.NoArgs,
Example: ` cfctl setting init local -n local-cloudone --app
or
cfctl setting init local -n local-cloudone --user`,
Example: ` cfctl setting init local -n [domain] --app --dev
or
cfctl setting init local -n [domain] --user --stg`,
Run: func(cmd *cobra.Command, args []string) {
localEnv, _ := cmd.Flags().GetString("name")
appFlag, _ := cmd.Flags().GetBool("app")
userFlag, _ := cmd.Flags().GetBool("user")
devFlag, _ := cmd.Flags().GetBool("dev")
stgFlag, _ := cmd.Flags().GetBool("stg")

if localEnv == "" {
pterm.Error.Println("The --name flag is required.")
Expand All @@ -139,6 +141,11 @@ var settingInitLocalCmd = &cobra.Command{
cmd.Help()
return
}
if !devFlag && !stgFlag {
pterm.Error.Println("You must specify either --dev or --stg flag.")
cmd.Help()
return
}

// Create setting directory if it doesn't exist
settingDir := GetSettingDir()
Expand All @@ -158,12 +165,23 @@ var settingInitLocalCmd = &cobra.Command{
}
}

envPrefix := ""
if devFlag {
envPrefix = "dev"
} else if stgFlag {
envPrefix = "stg"
}

var envName string
if appFlag {
envName = fmt.Sprintf("%s-app", localEnv)
envName = fmt.Sprintf("local-%s-%s-app", envPrefix, localEnv)
} else {
envName = fmt.Sprintf("local-%s-%s-user", envPrefix, localEnv)
}

if appFlag {
updateLocalSetting(envName, "app", mainSettingPath)
} else {
envName = fmt.Sprintf("%s-user", localEnv)
updateLocalSetting(envName, "user", filepath.Join(settingDir, "cache", "setting.toml"))
}

Expand Down Expand Up @@ -226,24 +244,16 @@ var envCmd = &cobra.Command{
// Set paths for app and user configurations
settingDir := GetSettingDir()
appSettingPath := filepath.Join(settingDir, "setting.toml")
userSettingPath := filepath.Join(settingDir, "cache", "setting.toml")

// Create separate Viper instances
appV := viper.New()
userV := viper.New()

// Load app configuration
if err := loadSetting(appV, appSettingPath); err != nil {
pterm.Error.Println(err)
return
}

// Load user configuration
if err := loadSetting(userV, userSettingPath); err != nil {
pterm.Error.Println(err)
return
}

// Get current environment (from app setting only)
currentEnv := getCurrentEnvironment(appV)

Expand All @@ -255,20 +265,17 @@ var envCmd = &cobra.Command{
if switchEnv != "" {
// Check environment in both app and user settings
appEnvMap := appV.GetStringMap("environments")
userEnvMap := userV.GetStringMap("environments")

if currentEnv == switchEnv {
pterm.Info.Printf("Already in '%s' environment.\n", currentEnv)
return
}

if _, existsApp := appEnvMap[switchEnv]; !existsApp {
if _, existsUser := userEnvMap[switchEnv]; !existsUser {
home, _ := os.UserHomeDir()
pterm.Error.Printf("Environment '%s' not found in %s/.cfctl/setting.toml",
switchEnv, home)
return
}
home, _ := os.UserHomeDir()
pterm.Error.Printf("Environment '%s' not found in %s/.cfctl/setting.toml",
switchEnv, home)
return
}

// Update only the environment field in app setting
Expand All @@ -290,14 +297,10 @@ var envCmd = &cobra.Command{
var targetViper *viper.Viper
var targetSettingPath string
envMapApp := appV.GetStringMap("environments")
envMapUser := userV.GetStringMap("environments")

if _, exists := envMapApp[removeEnv]; exists {
targetViper = appV
targetSettingPath = appSettingPath
} else if _, exists := envMapUser[removeEnv]; exists {
targetViper = userV
targetSettingPath = userSettingPath
} else {
home, _ := os.UserHomeDir()
pterm.Error.Printf("Environment '%s' not found in %s/.cfctl/setting.toml",
Expand Down Expand Up @@ -348,7 +351,6 @@ var envCmd = &cobra.Command{
if listOnly {
// Get environment maps from both app and user settings
appEnvMap := appV.GetStringMap("environments")
userEnvMap := userV.GetStringMap("environments")

// Map to store all unique environments
allEnvs := make(map[string]bool)
Expand All @@ -358,11 +360,6 @@ var envCmd = &cobra.Command{
allEnvs[envName] = true
}

// Add user environments
for envName := range userEnvMap {
allEnvs[envName] = true
}

if len(allEnvs) == 0 {
pterm.Println("No environments found in setting file")
return
Expand All @@ -377,8 +374,6 @@ var envCmd = &cobra.Command{
} else {
if _, isApp := appEnvMap[envName]; isApp {
pterm.Printf("%s\n", envName)
} else {
pterm.Printf("%s\n", envName)
}
}
}
Expand Down Expand Up @@ -874,7 +869,7 @@ func loadSetting(v *viper.Viper, settingPath string) error {
// Initialize with default values if file doesn't exist
defaultSettings := map[string]interface{}{
"environments": map[string]interface{}{},
"environment": "",
"environment": "",
}

// Convert to TOML
Expand Down Expand Up @@ -1118,6 +1113,8 @@ func init() {
settingInitLocalCmd.Flags().StringP("name", "n", "", "Local environment name for the environment")
settingInitLocalCmd.Flags().Bool("app", false, "Initialize as application configuration")
settingInitLocalCmd.Flags().Bool("user", false, "Initialize as user-specific configuration")
settingInitLocalCmd.Flags().Bool("dev", false, "Initialize as development environment")
settingInitLocalCmd.Flags().Bool("stg", false, "Initialize as staging environment")

envCmd.Flags().StringP("switch", "s", "", "Switch to a different environment")
envCmd.Flags().StringP("remove", "r", "", "Remove an environment")
Expand Down
Loading
Loading