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

Fix: #12704 - integrate configCmd into startCmd #13157

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Next Next commit
attempt to integrate configCmd into startCmd
Signed-off-by: yaten2302 <yaten2302@gmail.com>
  • Loading branch information
yaten2302 committed Jan 5, 2025
commit b261ef31eb3ff318dce5af8b93eb6897643467ce
352 changes: 352 additions & 0 deletions mesheryctl/internal/cli/root/system/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
"strconv"
"strings"
"time"
"net/http"
"io"
"encoding/json"

"github.com/layer5io/meshery/mesheryctl/internal/cli/root/config"
"github.com/layer5io/meshery/mesheryctl/internal/cli/root/constants"
Expand All @@ -47,8 +50,303 @@
var (
skipUpdateFlag bool
skipBrowserFlag bool
configureCluster string
)

func getContexts(configFile string) ([]string, error) {

Check failure on line 56 in mesheryctl/internal/cli/root/system/start.go

View workflow job for this annotation

GitHub Actions / golangci-lint (1.23, ubuntu-22.04)

getContexts redeclared in this block
client := &http.Client{}

mctlCfg, err := config.GetMesheryCtl(viper.GetViper())
if err != nil {
utils.Log.Error(err)
return nil, nil
}

// GETCONTEXTS endpoint points to the URL return the contexts available
GETCONTEXTS := mctlCfg.GetBaseMesheryURL() + "/api/system/kubernetes/contexts"

req, err := utils.UploadFileWithParams(GETCONTEXTS, nil, utils.ParamName, configFile)
if err != nil {
return nil, ErrUploadFileParams(err)
}

res, err := client.Do(req)
yaten2302 marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, utils.ErrRequestResponse(err)
}
body, err := io.ReadAll(res.Body)
if err != nil {
return nil, utils.ErrReadResponseBody(err)
}

log.Debugf("Get context API response: %s", string(body))
var results []map[string]interface{}
err = json.Unmarshal(body, &results)
if err != nil {
return nil, utils.ErrUnmarshal(err)
}

if results == nil {
errstr := "Error unmarshalling the context info, check " + configFile + " file"
yaten2302 marked this conversation as resolved.
Show resolved Hide resolved
return nil, errors.New(errstr)
}

var contextNames []string
for _, ctx := range results {
ctxname, ok := ctx["name"].(string)
if !ok {
errstr := "Invalid context name: context name should be a string"
return nil, errors.New(errstr)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you check if there is an existing Meskit error or implement one here, there is already example in error.go file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lekaf974 Can this error be used here? It's mentioned in the error.go

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hum I think yes since it looks to be related to kubenertes context, can you check in the code where it is used to validate ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lekaf974 , the error code is - mesheryctl-1068

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
contextNames = append(contextNames, ctxname)
}
log.Debugf("Available contexts: %s", contextNames)
return contextNames, nil
}

func setContext(configFile, cname string) error {

Check failure on line 107 in mesheryctl/internal/cli/root/system/start.go

View workflow job for this annotation

GitHub Actions / golangci-lint (1.23, ubuntu-22.04)

setContext redeclared in this block
client := &http.Client{}
extraParams1 := map[string]string{
"contextName": cname,
}
mctlCfg, err := config.GetMesheryCtl(viper.GetViper())
if err != nil {
utils.Log.Error(err)
return nil
}

// SETCONTEXT endpoint points to set context
SETCONTEXT := mctlCfg.GetBaseMesheryURL() + "/api/system/kubernetes"
req, err := utils.UploadFileWithParams(SETCONTEXT, extraParams1, utils.ParamName, configFile)
if err != nil {
return ErrUploadFileParams(err)
}
res, err := client.Do(req)
if err != nil {
return utils.ErrRequestResponse(err)
}
body, err := io.ReadAll(res.Body)
if err != nil {
return utils.ErrReadResponseBody(err)
}
// TODO: Pretty print the output
log.Debugf("Set context API response: %s", string(body))
return nil
}

var aksConfigCmd = &cobra.Command{

Check failure on line 137 in mesheryctl/internal/cli/root/system/start.go

View workflow job for this annotation

GitHub Actions / golangci-lint (1.23, ubuntu-22.04)

aksConfigCmd redeclared in this block
Use: "aks",
Short: "Configure Meshery to use AKS cluster",
Long: `Configure Meshery to connect to AKS cluster`,
Example: `
// Configure Meshery to connect to AKS cluster using auth token
mesheryctl system config aks --token auth.json

// Configure Meshery to connect to AKS cluster (if session is logged in using login subcommand)
mesheryctl system config aks
`,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) >= 1 {
yaten2302 marked this conversation as resolved.
Show resolved Hide resolved
return errors.New("more than one config name provided")
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
aksCheck := exec.Command("az", "version")
aksCheck.Stdout = os.Stdout
aksCheck.Stderr = os.Stderr
err := aksCheck.Run()
if err != nil {
log.Fatalf("Azure CLI not found. Please install Azure CLI and try again. \nSee https://docs.microsoft.com/en-us/cli/azure/install-azure-cli ")
}
log.Info("Configuring Meshery to access AKS...")
var resourceGroup, aksName string

// Prompt user for Azure resource name
log.Info("Please enter the Azure resource group name:")
_, err = fmt.Scanf("%s", &resourceGroup)
if err != nil {
log.Warnf("Error reading Azure resource group name: %s", err.Error())
log.Info("Let's try again. Please enter the Azure resource group name:")
_, err = fmt.Scanf("%s", &resourceGroup)
if err != nil {
log.Fatalf("Error reading Azure resource group name: %s", err.Error())
}
}

// Prompt user for AKS cluster name
log.Info("Please enter the AKS cluster name:")
_, err = fmt.Scanf("%s", &aksName)
if err != nil {
log.Warnf("Error reading AKS cluster name: %s", err.Error())
log.Info("Let's try again. Please enter the AKS cluster name:")
_, err = fmt.Scanf("%s", &aksName)
if err != nil {
log.Fatalf("Error reading AKS cluster name: %s", err.Error())
}
}

// Build the Azure CLI syntax to fetch cluster config in kubeconfig.yaml file
aksCmd := exec.Command("az", "aks", "get-credentials", "--resource-group", resourceGroup, "--name", aksName, "--file", utils.ConfigPath)
aksCmd.Stdout = os.Stdout
aksCmd.Stderr = os.Stderr
// Write AKS compatible config to the filesystem
err = aksCmd.Run()
if err != nil {
log.Fatalf("Error generating kubeconfig: %s", err.Error())
return err
}
log.Debugf("AKS configuration is written to: %s", utils.ConfigPath)

// set the token in the chosen context
setToken()
return nil
},
}

var eksConfigCmd = &cobra.Command{

Check failure on line 207 in mesheryctl/internal/cli/root/system/start.go

View workflow job for this annotation

GitHub Actions / golangci-lint (1.23, ubuntu-22.04)

eksConfigCmd redeclared in this block
Use: "eks",
Short: "Configure Meshery to use EKS cluster",
Long: `Configure Meshery to connect to EKS cluster`,
Example: `
// Configure Meshery to connect to EKS cluster using auth token
mesheryctl system config eks --token auth.json

// Configure Meshery to connect to EKS cluster (if session is logged in using login subcommand)
mesheryctl system config eks
`,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) >= 1 {
yaten2302 marked this conversation as resolved.
Show resolved Hide resolved
return errors.New("more than one config name provided")
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
eksCheck := exec.Command("aws", "--version")
eksCheck.Stdout = os.Stdout
eksCheck.Stderr = os.Stderr
err := eksCheck.Run()
if err != nil {
log.Fatalf("AWS CLI not found. Please install AWS CLI and try again. \nSee https://docs.aws.amazon.com/cli/latest/reference/ ")
}
log.Info("Configuring Meshery to access EKS...")
var regionName, clusterName string

// Prompt user for AWS region name
log.Info("Please enter the AWS region name:")
_, err = fmt.Scanf("%s", &regionName)
if err != nil {
log.Warnf("Error reading AWS region name: %s", err.Error())
log.Info("Let's try again. Please enter the AWS region name:")
_, err = fmt.Scanf("%s", &regionName)
if err != nil {
log.Fatalf("Error reading AWS region name: %s", err.Error())
}
}

// Prompt user for AWS cluster name
log.Info("Please enter the AWS cluster name:")
_, err = fmt.Scanf("%s", &clusterName)
if err != nil {
log.Warnf("Error reading AWS cluster name: %s", err.Error())
log.Info("Let's try again. Please enter the AWS cluster name:")
_, err = fmt.Scanf("%s", &clusterName)
if err != nil {
log.Fatalf("Error reading AWS cluster name: %s", err.Error())
}
}

// Build the aws CLI syntax to fetch cluster config in kubeconfig.yaml file
eksCmd := exec.Command("aws", "eks", "--region", regionName, "update-kubeconfig", "--name", clusterName, "--kubeconfig", utils.ConfigPath)
eksCmd.Stdout = os.Stdout
eksCmd.Stderr = os.Stderr
// Write EKS compatible config to the filesystem
err = eksCmd.Run()
if err != nil {
log.Fatalf("Error generating kubeconfig: %s", err.Error())
return err
}
log.Debugf("EKS configuration is written to: %s", utils.ConfigPath)

// set the token in the chosen context
setToken()
return nil
},
}

var gkeConfigCmd = &cobra.Command{

Check failure on line 277 in mesheryctl/internal/cli/root/system/start.go

View workflow job for this annotation

GitHub Actions / golangci-lint (1.23, ubuntu-22.04)

gkeConfigCmd redeclared in this block
Use: "gke",
Short: "Configure Meshery to use GKE cluster",
Long: `Configure Meshery to connect to GKE cluster`,
Example: `
// Configure Meshery to connect to GKE cluster using auth token
mesheryctl system config gke --token auth.json

// Configure Meshery to connect to GKE cluster (if session is logged in using login subcommand)
mesheryctl system config gke
`,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) >= 1 {
return errors.New("more than one config name provided")
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
// TODO: move the GenerateConfigGKE logic to meshkit/client-go
log.Info("Configuring Meshery to access GKE...")
SAName := "sa-meshery-" + utils.StringWithCharset(8)
if err := utils.GenerateConfigGKE(utils.ConfigPath, SAName, "default"); err != nil {
log.Fatal("Error generating config:", err)
return err
}
log.Debugf("GKE configuration is written to: %s", utils.ConfigPath)

// set the token in the chosen context
setToken()
return nil
},
}

var minikubeConfigCmd = &cobra.Command{
Use: "minikube",
Short: "Configure Meshery to use minikube cluster",
Long: `Configure Meshery to connect to minikube cluster`,
Example: `
// Configure Meshery to connect to minikube cluster using auth token
mesheryctl system config minikube --token auth.json

// Configure Meshery to connect to minikube cluster (if session is logged in using login subcommand)
mesheryctl system config minikube
`,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) >= 1 {
return errors.New("more than one config name provided")
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
log.Info("Configuring Meshery to access Minikube...")
// Get the config from the default config path
if _, err = os.Stat(utils.KubeConfig); err != nil {
log.Fatal("Could not find the default kube config:", err)
return err
}

// Minifies and flattens kubeconfig and writes it to kubeconfig.yaml
_, _, err := meshkitkube.ProcessConfig(utils.KubeConfig, utils.ConfigPath)
if err != nil {
log.Fatal("Error writing config to file:", err)
return err
}

log.Debugf("Minikube configuration is written to: %s", utils.ConfigPath)

// set the token in the chosen context
setToken()
return nil
},
}

// startCmd represents the start command
var startCmd = &cobra.Command{
Use: "start",
Expand Down Expand Up @@ -112,6 +410,13 @@
if err := start(); err != nil {
return errors.Wrap(err, utils.SystemError("failed to start Meshery"))
}
if configureCluster != "" {
// authenticate the user if not already
log.Printf("Please login first to configure %s", configureCluster)
loginCmd.PersistentFlags().StringVarP(&providerFlag, "provider", "p", "", "login Meshery with specified provider")
log.Printf("authenticated")
}

return nil
},
PersistentPreRun: func(cmd *cobra.Command, args []string) {
Expand Down Expand Up @@ -447,11 +752,26 @@
}

func init() {
availableSubcommands = []*cobra.Command{
aksConfigCmd,
eksConfigCmd,
gkeConfigCmd,
minikubeConfigCmd,
}

aksConfigCmd.Flags().StringVarP(&utils.TokenFlag, "token", "t", "", "Path to token for authenticating to Meshery API")
eksConfigCmd.Flags().StringVarP(&utils.TokenFlag, "token", "t", "", "Path to token for authenticating to Meshery API")
gkeConfigCmd.Flags().StringVarP(&utils.TokenFlag, "token", "t", "", "Path to token for authenticating to Meshery API")
minikubeConfigCmd.Flags().StringVarP(&utils.TokenFlag, "token", "t", "", "Path to token for authenticating to Meshery API")

startCmd.PersistentFlags().StringVarP(&utils.PlatformFlag, "platform", "p", "", "platform to deploy Meshery to.")
startCmd.Flags().BoolVarP(&skipUpdateFlag, "skip-update", "", false, "(optional) skip checking for new Meshery's container images.")
startCmd.Flags().BoolVarP(&utils.ResetFlag, "reset", "", false, "(optional) reset Meshery's configuration file to default settings.")
startCmd.Flags().BoolVarP(&skipBrowserFlag, "skip-browser", "", false, "(optional) skip opening of MesheryUI in browser.")
startCmd.Flags().StringVarP(&configureCluster, "config-cluster", "", "", "(optional) configure the Kubernetes cluster used by Meshery.")
startCmd.PersistentFlags().StringVar(&providerFlag, "provider", "", "(optional) Defaults to the provider specified in the current context")

startCmd.AddCommand(availableSubcommands...)
}

// Apply Meshery helm charts
Expand Down Expand Up @@ -508,3 +828,35 @@
}
return nil
}

// Given the token path, get the context and set the token in the chosen context
func setToken() {
log.Debugf("Token path: %s", utils.TokenFlag)
contexts, err := getContexts(utils.ConfigPath)
if err != nil {
utils.Log.Error(err)
}
if contexts == nil || len(contexts) < 1 {
log.Fatalf("Error getting context: %s", fmt.Errorf("no contexts found"))
}
choosenCtx := contexts[0]
if len(contexts) > 1 {
fmt.Println("List of available contexts: ")
for i, ctx := range contexts {
fmt.Printf("(%d) %s \n", i+1, ctx)
}
var choice int
fmt.Print("Enter choice (number): ")
_, err = fmt.Scanf("%d", &choice)
if err != nil {
log.Fatalf("Error reading input: %s", err.Error())
}
choosenCtx = contexts[choice-1]
}

log.Debugf("Chosen context : %s out of the %d available contexts", choosenCtx, len(contexts))
err = setContext(utils.ConfigPath, choosenCtx)
if err != nil {
log.Fatalf("Error setting context: %s", err.Error())
}
}
Loading