diff --git a/Makefile b/Makefile index 54dd5dba..5a3fb576 100644 --- a/Makefile +++ b/Makefile @@ -59,6 +59,9 @@ addcopy: ## Add copyright to all files @echo "==> Generating serverless br client" swagger generate client -f pkg/tidbcloud/v1beta1/serverless_br/serverless-br.swagger.json -A tidbcloud-serverless -t pkg/tidbcloud/v1beta1/serverless_br +.PHONY: generate-connect-info +generate-connect-info: + @scripts/connect-info.sh .PHONY: fmt fmt: ## Format changed go diff --git a/internal/cli/serverless/branch/branch.go b/internal/cli/serverless/branch/branch.go index 1f0f4e7d..4c931afe 100644 --- a/internal/cli/serverless/branch/branch.go +++ b/internal/cli/serverless/branch/branch.go @@ -31,6 +31,6 @@ func Cmd(h *internal.Helper) *cobra.Command { branchCmd.AddCommand(DescribeCmd(h)) branchCmd.AddCommand(DeleteCmd(h)) branchCmd.AddCommand(ConnectCmd(h)) - branchCmd.AddCommand(ConnectInfoCmd(h)) + //branchCmd.AddCommand(ConnectInfoCmd(h)) return branchCmd } diff --git a/internal/cli/serverless/branch/connectinfo.go b/internal/cli/serverless/branch/connectinfo.go index 70f613d4..f5b4cbde 100644 --- a/internal/cli/serverless/branch/connectinfo.go +++ b/internal/cli/serverless/branch/connectinfo.go @@ -14,208 +14,209 @@ package branch -import ( - "fmt" - "runtime" - "strconv" - "strings" - - "tidbcloud-cli/internal" - "tidbcloud-cli/internal/config" - "tidbcloud-cli/internal/flag" - "tidbcloud-cli/internal/service/cloud" - "tidbcloud-cli/internal/util" - branchApi "tidbcloud-cli/pkg/tidbcloud/v1beta1/branch/client/branch_service" - - "github.com/juju/errors" - "github.com/spf13/cobra" -) - -type connectInfoOpts struct { - interactive bool -} - -func (c connectInfoOpts) NonInteractiveFlags() []string { - return []string{ - flag.ClusterID, - flag.BranchID, - flag.ClientName, - flag.OperatingSystem, - } -} - -func (c *connectInfoOpts) MarkInteractive(cmd *cobra.Command) error { - flags := c.NonInteractiveFlags() - for _, fn := range flags { - f := cmd.Flags().Lookup(fn) - if f != nil && f.Changed { - c.interactive = false - break - } - } - // Mark required flags - if !c.interactive { - for _, fn := range flags { - err := cmd.MarkFlagRequired(fn) - if err != nil { - return err - } - } - } - return nil -} - -func ConnectInfoCmd(h *internal.Helper) *cobra.Command { - opts := connectInfoOpts{ - interactive: true, - } - - cmd := &cobra.Command{ - Use: "connect-info", - Short: "Get connection string for a branch", - Example: fmt.Sprintf(` Get connection string in interactive mode: - $ %[1]s branch connect-info - - Get connection string in non-interactive mode: - $ %[1]s branch connect-info --cluster-id --branch-id --client --operating-system -`, config.CliName), - PreRunE: func(cmd *cobra.Command, args []string) error { - err := opts.MarkInteractive(cmd) - if err != nil { - return errors.Trace(err) - } - return nil - }, - RunE: func(cmd *cobra.Command, args []string) error { - // flags - var branchID, clusterID, client, operatingSystem string - - // Get TiDBCloudClient - d, err := h.Client() - if err != nil { - return err - } - - if opts.interactive { // interactive mode - if !h.IOStreams.CanPrompt { - return errors.New("The terminal doesn't support interactive mode, please use non-interactive mode") - } - - // Get cluster id - project, err := cloud.GetSelectedProject(h.QueryPageSize, d) - if err != nil { - return err - } - cluster, err := cloud.GetSelectedCluster(project.ID, h.QueryPageSize, d) - if err != nil { - return err - } - clusterID = cluster.ID - - // Get branch id - branch, err := cloud.GetSelectedBranch(clusterID, h.QueryPageSize, d) - if err != nil { - return err - } - branchID = branch.ID - - // Get client - clientNameForInteractive, err := cloud.GetSelectedConnectClient(util.ConnectClientsList) - if err != nil { - return err - } - client = util.ClientsForInteractiveMap[clientNameForInteractive] - - // Detect operating system - // TODO: detect linux operating system name - goOS := runtime.GOOS - if goOS == "darwin" { - goOS = "macOS" - } else if goOS == "windows" { - goOS = "Windows" - } - operatingSystems := util.OperatingSystemList - if goOS != "" && goOS != "linux" { - for id, value := range operatingSystems { - if strings.Contains(value, goOS) { - operatingSystems[id] = value + " (Detected)" - operatingSystems[0], operatingSystems[id] = operatingSystems[id], operatingSystems[0] - break - break - } - } - } - - // Get operating system - operatingSystemCombination, err := cloud.GetSelectedConnectOs(util.OperatingSystemList) - if err != nil { - return err - } - operatingSystem = strings.Split(operatingSystemCombination, "/")[0] - - } else { // non-interactive mode - clusterID, err = cmd.Flags().GetString(flag.ClusterID) - if err != nil { - return err - } - - branchID, err = cmd.Flags().GetString(flag.BranchID) - if err != nil { - return err - } - - clientNameForHelp, err := cmd.Flags().GetString(flag.ClientName) - if err != nil { - return err - } - if v, ok := util.ClientsForHelpMap[strings.ToLower(clientNameForHelp)]; ok { - client = v - } else { - return errors.New(fmt.Sprintf("Unsupported client. Run \"%[1]s cluster connect-info -h\" to check supported clients list", config.CliName)) - } - - operatingSystem, err = cmd.Flags().GetString(flag.OperatingSystem) - if err != nil { - return err - } - if !util.Contains(operatingSystem, util.OperatingSystemListForHelp) { - return errors.New(fmt.Sprintf("Unsupported operating system. Run \"%[1]s cluster connect-info -h\" to check supported operating systems list", config.CliName)) - } - } - - // Get branch info - params := branchApi.NewBranchServiceGetBranchParams().WithBranchID(branchID).WithClusterID(clusterID) - branchInfo, err := d.GetBranch(params) - if err != nil { - return err - } - - // Get connect parameter - defaultUser := fmt.Sprintf("%s.root", branchInfo.Payload.UserPrefix) - host := branchInfo.Payload.Endpoints.Public.Host - port := strconv.Itoa(int(branchInfo.Payload.Endpoints.Public.Port)) - - // Get connection string - connectInfo, err := cloud.RetrieveConnectInfo(d) - if err != nil { - return err - } - connectionString, err := util.GenerateConnectionString(connectInfo, client, host, defaultUser, port, util.SERVERLESS, operatingSystem, util.Shell) - if err != nil { - return err - } - fmt.Fprintln(h.IOStreams.Out) - fmt.Fprintln(h.IOStreams.Out, connectionString) - - return nil - }, - } - - cmd.Flags().StringP(flag.BranchID, flag.BranchIDShort, "", "The ID of the branch") - cmd.Flags().StringP(flag.ClusterID, flag.ClusterIDShort, "", "The cluster ID of the branch") - cmd.Flags().String(flag.ClientName, "", fmt.Sprintf("Connected client. Supported clients: %q", util.ConnectClientsListForHelp)) - cmd.Flags().String(flag.OperatingSystem, "", fmt.Sprintf("Operating system name. "+ - "Supported operating systems: %q", util.OperatingSystemListForHelp)) - - return cmd -} +// +//import ( +// "fmt" +// "runtime" +// "strconv" +// "strings" +// +// "tidbcloud-cli/internal" +// "tidbcloud-cli/internal/config" +// "tidbcloud-cli/internal/flag" +// "tidbcloud-cli/internal/service/cloud" +// "tidbcloud-cli/internal/util" +// branchApi "tidbcloud-cli/pkg/tidbcloud/v1beta1/branch/client/branch_service" +// +// "github.com/juju/errors" +// "github.com/spf13/cobra" +//) +// +//type connectInfoOpts struct { +// interactive bool +//} +// +//func (c connectInfoOpts) NonInteractiveFlags() []string { +// return []string{ +// flag.ClusterID, +// flag.BranchID, +// flag.ClientName, +// flag.OperatingSystem, +// } +//} +// +//func (c *connectInfoOpts) MarkInteractive(cmd *cobra.Command) error { +// flags := c.NonInteractiveFlags() +// for _, fn := range flags { +// f := cmd.Flags().Lookup(fn) +// if f != nil && f.Changed { +// c.interactive = false +// break +// } +// } +// // Mark required flags +// if !c.interactive { +// for _, fn := range flags { +// err := cmd.MarkFlagRequired(fn) +// if err != nil { +// return err +// } +// } +// } +// return nil +//} +// +//func ConnectInfoCmd(h *internal.Helper) *cobra.Command { +// opts := connectInfoOpts{ +// interactive: true, +// } +// +// cmd := &cobra.Command{ +// Use: "connect-info", +// Short: "Get connection string for a branch", +// Example: fmt.Sprintf(` Get connection string in interactive mode: +// $ %[1]s branch connect-info +// +// Get connection string in non-interactive mode: +// $ %[1]s branch connect-info --cluster-id --branch-id --client --operating-system +//`, config.CliName), +// PreRunE: func(cmd *cobra.Command, args []string) error { +// err := opts.MarkInteractive(cmd) +// if err != nil { +// return errors.Trace(err) +// } +// return nil +// }, +// RunE: func(cmd *cobra.Command, args []string) error { +// // flags +// var branchID, clusterID, client, operatingSystem string +// +// // Get TiDBCloudClient +// d, err := h.Client() +// if err != nil { +// return err +// } +// +// if opts.interactive { // interactive mode +// if !h.IOStreams.CanPrompt { +// return errors.New("The terminal doesn't support interactive mode, please use non-interactive mode") +// } +// +// // Get cluster id +// project, err := cloud.GetSelectedProject(h.QueryPageSize, d) +// if err != nil { +// return err +// } +// cluster, err := cloud.GetSelectedCluster(project.ID, h.QueryPageSize, d) +// if err != nil { +// return err +// } +// clusterID = cluster.ID +// +// // Get branch id +// branch, err := cloud.GetSelectedBranch(clusterID, h.QueryPageSize, d) +// if err != nil { +// return err +// } +// branchID = branch.ID +// +// // Get client +// clientNameForInteractive, err := cloud.GetSelectedConnectClient(util.ConnectInfoClient) +// if err != nil { +// return err +// } +// client = util.ClientsForInteractiveMap[clientNameForInteractive] +// +// // Detect operating system +// // TODO: detect linux operating system name +// goOS := runtime.GOOS +// if goOS == "darwin" { +// goOS = "macOS" +// } else if goOS == "windows" { +// goOS = "Windows" +// } +// operatingSystems := util.OperatingSystemList +// if goOS != "" && goOS != "linux" { +// for id, value := range operatingSystems { +// if strings.Contains(value, goOS) { +// operatingSystems[id] = value + " (Detected)" +// operatingSystems[0], operatingSystems[id] = operatingSystems[id], operatingSystems[0] +// break +// break +// } +// } +// } +// +// // Get operating system +// operatingSystemCombination, err := cloud.GetSelectedConnectOs(util.OperatingSystemList) +// if err != nil { +// return err +// } +// operatingSystem = strings.Split(operatingSystemCombination, "/")[0] +// +// } else { // non-interactive mode +// clusterID, err = cmd.Flags().GetString(flag.ClusterID) +// if err != nil { +// return err +// } +// +// branchID, err = cmd.Flags().GetString(flag.BranchID) +// if err != nil { +// return err +// } +// +// clientNameForHelp, err := cmd.Flags().GetString(flag.ClientName) +// if err != nil { +// return err +// } +// if v, ok := util.ClientsForHelpMap[strings.ToLower(clientNameForHelp)]; ok { +// client = v +// } else { +// return errors.New(fmt.Sprintf("Unsupported client. Run \"%[1]s cluster connect-info -h\" to check supported clients list", config.CliName)) +// } +// +// operatingSystem, err = cmd.Flags().GetString(flag.OperatingSystem) +// if err != nil { +// return err +// } +// if !util.Contains(operatingSystem, util.OperatingSystemListForHelp) { +// return errors.New(fmt.Sprintf("Unsupported operating system. Run \"%[1]s cluster connect-info -h\" to check supported operating systems list", config.CliName)) +// } +// } +// +// // Get branch info +// params := branchApi.NewBranchServiceGetBranchParams().WithBranchID(branchID).WithClusterID(clusterID) +// branchInfo, err := d.GetBranch(params) +// if err != nil { +// return err +// } +// +// // Get connect parameter +// defaultUser := fmt.Sprintf("%s.root", branchInfo.Payload.UserPrefix) +// host := branchInfo.Payload.Endpoints.Public.Host +// port := strconv.Itoa(int(branchInfo.Payload.Endpoints.Public.Port)) +// +// // Get connection string +// connectInfo, err := cloud.RetrieveConnectInfo(d) +// if err != nil { +// return err +// } +// connectionString, err := util.GenerateConnectionString(connectInfo, client, host, defaultUser, port, util.SERVERLESS, operatingSystem, util.Shell) +// if err != nil { +// return err +// } +// fmt.Fprintln(h.IOStreams.Out) +// fmt.Fprintln(h.IOStreams.Out, connectionString) +// +// return nil +// }, +// } +// +// cmd.Flags().StringP(flag.BranchID, flag.BranchIDShort, "", "The ID of the branch") +// cmd.Flags().StringP(flag.ClusterID, flag.ClusterIDShort, "", "The cluster ID of the branch") +// cmd.Flags().String(flag.ClientName, "", fmt.Sprintf("Connected client. Supported clients: %q", util.ConnectClientsListForHelp)) +// cmd.Flags().String(flag.OperatingSystem, "", fmt.Sprintf("Operating system name. "+ +// "Supported operating systems: %q", util.OperatingSystemListForHelp)) +// +// return cmd +//} diff --git a/internal/cli/serverless/connectinfo.go b/internal/cli/serverless/connectinfo.go index 63f71a0b..a5a628a8 100644 --- a/internal/cli/serverless/connectinfo.go +++ b/internal/cli/serverless/connectinfo.go @@ -79,7 +79,7 @@ func ConnectInfoCmd(h *internal.Helper) *cobra.Command { }, RunE: func(cmd *cobra.Command, args []string) error { // flags - var clusterID, client, operatingSystem string + var clusterID, clientID, operatingSystemID string // Get TiDBCloudClient d, err := h.Client() @@ -106,98 +106,135 @@ func ConnectInfoCmd(h *internal.Helper) *cobra.Command { } clusterID = cluster.ID - // Get client - clientNameForInteractive, err := cloud.GetSelectedConnectClient(util.ConnectClientsList) - if err != nil { - return err - } - client = util.ClientsForInteractiveMap[clientNameForInteractive] - // Detect operating system // TODO: detect linux operating system name goOS := runtime.GOOS if goOS == "darwin" { - goOS = "macOS" + goOS = "macos" } else if goOS == "windows" { - goOS = "Windows" - } - operatingSystems := util.OperatingSystemList - if goOS != "" && goOS != "linux" { - for id, value := range operatingSystems { - if strings.Contains(value, goOS) { - operatingSystems[id] = value + " (Detected)" - operatingSystems[0], operatingSystems[id] = operatingSystems[id], operatingSystems[0] - break - } + goOS = "windows" + } + println("Detected operating system:", goOS) + operatingSystems := make([]util.Os, len(util.ConnectInfoOs)) + for i, os := range util.ConnectInfoOs { + operatingSystems[i] = util.Os{ + ID: os.ID, + Name: os.Name, + } + if strings.Contains(os.ID, goOS) { + operatingSystems[i].Name = operatingSystems[i].Name + " (Detected)" + operatingSystems[0], operatingSystems[i] = operatingSystems[i], operatingSystems[0] } } // Get operating system - operatingSystemCombination, err := cloud.GetSelectedConnectOs(operatingSystems) + operatingSystem, err := cloud.GetSelectedConnectOs(operatingSystems) if err != nil { return err } - operatingSystem = strings.Split(operatingSystemCombination, "/")[0] + operatingSystemID = operatingSystem.ID + // Get client + client, err := cloud.GetSelectedConnectClient(util.ConnectInfoClient) + if err != nil { + return err + } + clientID = client.ID + if client.Options != nil && len(client.Options) > 0 { + // get options + option, err := cloud.GetSelectedConnectClientOptions(client.Options) + if err != nil { + return err + } + clientID = option.ID + } } else { // non-interactive mode clusterID, err = cmd.Flags().GetString(flag.ClusterID) if err != nil { return err } - clientNameForHelp, err := cmd.Flags().GetString(flag.ClientName) + clientName, err := cmd.Flags().GetString(flag.ClientName) if err != nil { return err } - if v, ok := util.ClientsForHelpMap[strings.ToLower(clientNameForHelp)]; ok { - client = v - } else { - return errors.New(fmt.Sprintf("Unsupported client. Run \"%[1]s cluster connect-info -h\" to check supported clients list", config.CliName)) + for _, v := range util.ConnectInfoClient { + name := v.Name + if v.Options != nil && len(v.Options) > 0 { + for _, option := range v.Options { + name = fmt.Sprintf("%s_%s", v.Name, option.Name) + } + } + if clientName == name { + clientID = v.ID + break + } + } + if clientID == "" { + return errors.New(fmt.Sprintf("Unsupported client. Run \"%[1]s serverless connect-info -h\" to check supported clients list", config.CliName)) } - operatingSystem, err = cmd.Flags().GetString(flag.OperatingSystem) + operatingSystemName, err := cmd.Flags().GetString(flag.OperatingSystem) if err != nil { return err } - if !util.Contains(operatingSystem, util.OperatingSystemListForHelp) { - return errors.New(fmt.Sprintf("Unsupported operating system. Run \"%[1]s cluster connect-info -h\" to check supported operating systems list", config.CliName)) + for _, v := range util.ConnectInfoOs { + osInfos := strings.Split(v.Name, "/") + for _, osInfo := range osInfos { + if operatingSystemName == osInfo { + operatingSystemID = v.ID + break + } + } + } + if operatingSystemID == "" { + return errors.New(fmt.Sprintf("Unsupported operating system. Run \"%[1]s serverless connect-info -h\" to check supported operating systems list", config.CliName)) } } - // Get cluster info + // get cluster info params := serverlessApi.NewServerlessServiceGetClusterParams().WithClusterID(clusterID) clusterInfo, err := d.GetCluster(params) if err != nil { return err } - - // Resolve cluster information - // Get connect parameter defaultUser := fmt.Sprintf("%s.root", clusterInfo.Payload.UserPrefix) host := clusterInfo.Payload.Endpoints.PublicEndpoint.Host port := strconv.Itoa(int(clusterInfo.Payload.Endpoints.PublicEndpoint.Port)) - clusterType := util.SERVERLESS - // Get connection string - connectInfo, err := cloud.RetrieveConnectInfo(d) + // get connect string + connectString, err := cloud.GetConnectString(clientID, operatingSystemID, defaultUser, host, port, "test") if err != nil { return err } - connectionString, err := util.GenerateConnectionString(connectInfo, client, host, defaultUser, port, clusterType, operatingSystem, util.Shell) - if err != nil { - return err - } - fmt.Fprintln(h.IOStreams.Out) - fmt.Fprintln(h.IOStreams.Out, connectionString) + fmt.Fprintln(h.IOStreams.Out) + fmt.Fprintln(h.IOStreams.Out, connectString) return nil }, } + var ConnectClientName []string + for _, v := range util.ConnectInfoClient { + if v.Options != nil && len(v.Options) > 0 { + for _, option := range v.Options { + ConnectClientName = append(ConnectClientName, fmt.Sprintf("%s(%s)", v.Name, option.Name)) + } + } else { + ConnectClientName = append(ConnectClientName, v.Name) + } + } + + var ConnectOsName []string + for _, v := range util.ConnectInfoOs { + osInfos := strings.Split(v.Name, "/") + ConnectOsName = append(ConnectOsName, osInfos...) + } + cmd.Flags().StringP(flag.ClusterID, flag.ClusterIDShort, "", "The ID of the Cluster") - cmd.Flags().String(flag.ClientName, "", fmt.Sprintf("Connected client. Supported clients: %q", util.ConnectClientsListForHelp)) + cmd.Flags().String(flag.ClientName, "", fmt.Sprintf("Connected client. Supported clients: %q", ConnectClientName)) cmd.Flags().String(flag.OperatingSystem, "", fmt.Sprintf("Operating system name. "+ - "Supported operating systems: %q", util.OperatingSystemListForHelp)) + "Supported operating systems: %q", ConnectOsName)) return cmd } diff --git a/internal/service/cloud/logic.go b/internal/service/cloud/logic.go index 55036d79..57ed408f 100644 --- a/internal/service/cloud/logic.go +++ b/internal/service/cloud/logic.go @@ -18,6 +18,7 @@ import ( "fmt" "math" "strconv" + "strings" "tidbcloud-cli/internal/ui" "tidbcloud-cli/internal/util" @@ -504,47 +505,108 @@ func RetrieveConnectInfo(d TiDBCloudClient) (*connectInfoModel.ConnectInfo, erro return connectInfo.Payload, nil } -func GetSelectedConnectClient(connectClientList []string) (string, error) { - s := make([]interface{}, len(connectClientList)) - for i, v := range connectClientList { +func GetSelectedConnectClient(connectInfoClient []util.Client) (util.Client, error) { + s := make([]interface{}, len(connectInfoClient)) + for i, v := range connectInfoClient { s[i] = v } model, err := ui.InitialSelectModel(s, "Choose the client") if err != nil { - return "", errors.Trace(err) + return util.Client{}, errors.Trace(err) } itemsPerPage := 6 model.EnablePagination(itemsPerPage) model.EnableFilter() p := tea.NewProgram(model) - connectClientModel, err := p.StartReturningModel() + connectClientModel, err := p.Run() if err != nil { - return "", errors.Trace(err) + return util.Client{}, errors.Trace(err) } if m, _ := connectClientModel.(ui.SelectModel); m.Interrupted { - return "", util.InterruptError + return util.Client{}, util.InterruptError } - connectClient := connectClientModel.(ui.SelectModel).GetSelectedItem().(string) + connectClient := connectClientModel.(ui.SelectModel).GetSelectedItem().(util.Client) return connectClient, nil } -func GetSelectedConnectOs(osList []string) (string, error) { - s := make([]interface{}, len(osList)) - for i, v := range osList { +func GetSelectedConnectClientOptions(connectInfoClientOption []util.Options) (util.Options, error) { + s := make([]interface{}, len(connectInfoClientOption)) + for i, v := range connectInfoClientOption { + s[i] = v + } + model, err := ui.InitialSelectModel(s, "Choose the client") + if err != nil { + return util.Options{}, errors.Trace(err) + } + itemsPerPage := 6 + model.EnablePagination(itemsPerPage) + model.EnableFilter() + p := tea.NewProgram(model) + connectClientModel, err := p.Run() + if err != nil { + return util.Options{}, errors.Trace(err) + } + if m, _ := connectClientModel.(ui.SelectModel); m.Interrupted { + return util.Options{}, util.InterruptError + } + connectClient := connectClientModel.(ui.SelectModel).GetSelectedItem().(util.Options) + return connectClient, nil +} + +func GetSelectedConnectOs(connectInfoOs []util.Os) (util.Os, error) { + s := make([]interface{}, len(connectInfoOs)) + for i, v := range connectInfoOs { s[i] = v } model, err := ui.InitialSelectModel(s, "Choose the operating system") if err != nil { - return "", errors.Trace(err) + return util.Os{}, errors.Trace(err) } p := tea.NewProgram(model) - connectClientModel, err := p.StartReturningModel() + connectClientModel, err := p.Run() if err != nil { - return "", errors.Trace(err) + return util.Os{}, errors.Trace(err) } if m, _ := connectClientModel.(ui.SelectModel); m.Interrupted { - return "", util.InterruptError + return util.Os{}, util.InterruptError } - operatingSystem := connectClientModel.(ui.SelectModel).GetSelectedItem().(string) + operatingSystem := connectClientModel.(ui.SelectModel).GetSelectedItem().(util.Os) return operatingSystem, nil } + +func GetConnectString(clientID, osID string, user, host, port, database string) (string, error) { + var connectInfo util.Connection + for _, v := range util.ConnectInfoConnection { + if v.Client == clientID && v.Endpoint == "public" { + connectInfo = v + } + } + if connectInfo.Client == "" { + return "", errors.New("Can not find the connection information for the client") + } + + // generate connection string + connectString := connectInfo.Content + connectString = strings.Replace(connectString, "${host}", host, -1) + connectString = strings.Replace(connectString, "${username}", user, -1) + connectString = strings.Replace(connectString, "${port}", port, -1) + connectString = strings.Replace(connectString, "${database}", database, -1) + connectString = strings.Replace(connectString, "${password}", "", -1) + downloadCa := false + for _, v := range connectInfo.DownloadCa { + if v == osID { + connectString = strings.Replace(connectString, "${ca_path}", "", -1) + downloadCa = true + break + } + } + if !downloadCa { + for _, v := range util.ConnectInfoCa { + if v.Os == osID { + connectString = strings.Replace(connectString, "${ca_path}", v.Path, -1) + break + } + } + } + return connectString, nil +} diff --git a/internal/util/connect-info.go b/internal/util/connect-info.go new file mode 100644 index 00000000..b08d5b66 --- /dev/null +++ b/internal/util/connect-info.go @@ -0,0 +1,434 @@ +// Copyright 2024 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code is generated. DO NOT EDIT. + +package util + +type ConnectInfo struct { + Endpoint []Endpoint + Os []Os + Ca []Ca + Client []Client + Variable []Variable + Connection []Connection +} +type Endpoint struct { + ID string + Name string +} + +func (e Endpoint) String() string { + return e.Name +} + +type Os struct { + ID string + Name string +} + +func (o Os) String() string { + return o.Name +} + +type Ca struct { + Os string + Type string + Path string +} +type Options struct { + ID string + Name string +} + +func (o Options) String() string { + return o.Name +} + +type Client struct { + ID string + Name string + Options []Options +} + +func (c Client) String() string { + return c.Name +} + +type Variable struct { + ID string + Placeholder string +} +type Connection struct { + Endpoint string + Client string + Type string + Path string + DownloadCa []string + Doc string + Content string +} + +var ConnectInfoEndpoint = []Endpoint{ + {ID: "public", Name: "Public"}, + {ID: "private", Name: "Private"}, +} +var ConnectInfoOs = []Os{ + {ID: "macos", Name: "macOS"}, + {ID: "debian", Name: "Debian/Ubuntu/Arch"}, + {ID: "centos", Name: "CentOS/RedHat/Fedora"}, + {ID: "alpine", Name: "Alpine"}, + {ID: "suse", Name: "OpenSUSE"}, + {ID: "windows", Name: "Windows"}, + {ID: "other", Name: "Others"}, +} +var ConnectInfoCa = []Ca{ + {Os: "macos", Type: "local", Path: "/etc/ssl/cert.pem"}, + {Os: "debian", Type: "local", Path: "/etc/ssl/certs/ca-certificates.crt"}, + {Os: "centos", Type: "local", Path: "/etc/pki/tls/certs/ca-bundle.crt"}, + {Os: "alpine", Type: "local", Path: "/etc/ssl/cert.pem"}, + {Os: "suse", Type: "local", Path: "/etc/ssl/ca-bundle.pem"}, + {Os: "windows", Type: "link", Path: "https://letsencrypt.org/certs/isrgrootx1.pem"}, + {Os: "other", Type: "link", Path: "https://letsencrypt.org/certs/isrgrootx1.pem"}, +} +var ConnectInfoClient = []Client{ + {ID: "general", Name: "General", Options: []Options{ + {ID: "generalparams", Name: "Parameters"}, + {ID: "generalstring", Name: "Connection String"}, + }}, + {ID: "mysqlcli", Name: "MySQL CLI", Options: []Options{}}, + {ID: "mariadbcli", Name: "MariaDB CLI", Options: []Options{}}, + {ID: "dotenv", Name: ".env", Options: []Options{}}, + {ID: "mysqlconnectorj", Name: "Java(MySQL Connector)", Options: []Options{}}, + {ID: "mariadbconnectorj", Name: "Java(MariaDB Connector)", Options: []Options{}}, + {ID: "pythonmysqlclient", Name: "Python(mysqlclient)", Options: []Options{}}, + {ID: "pythonpymysql", Name: "Python(PyMySQL)", Options: []Options{}}, + {ID: "pythonmysqlconnector", Name: "Python(MySQL Connector)", Options: []Options{}}, + {ID: "sqlalchemy", Name: "SQLAlchemy", Options: []Options{ + {ID: "sqlalchemymysqlclient", Name: "mysqlclient"}, + {ID: "sqlalchemypymysql", Name: "PyMySQL"}, + {ID: "sqlalchemymysqlconnector", Name: "MySQL Connector"}, + }}, + {ID: "django", Name: "Django", Options: []Options{}}, + {ID: "nodemysql2", Name: "Node.js(mysql2)", Options: []Options{}}, + {ID: "prisma", Name: "Prisma", Options: []Options{}}, + {ID: "serverlessjs", Name: "Serverless Driver", Options: []Options{}}, + {ID: "go", Name: "Go", Options: []Options{}}, + {ID: "rails", Name: "Rails", Options: []Options{}}, + {ID: "wordpress", Name: "WordPress", Options: []Options{}}, + {ID: "datagrip", Name: "DataGrip", Options: []Options{}}, + {ID: "vscode", Name: "VS Code", Options: []Options{}}, + {ID: "dbeaver", Name: "DBeaver", Options: []Options{}}, + {ID: "mysqlworkbench", Name: "MySQL Workbench", Options: []Options{}}, + {ID: "navicat", Name: "Navicat", Options: []Options{}}, +} +var ConnectInfoVariable = []Variable{ + {ID: "host", Placeholder: ""}, + {ID: "port", Placeholder: ""}, + {ID: "username", Placeholder: ""}, + {ID: "password", Placeholder: ""}, + {ID: "database", Placeholder: ""}, + {ID: "ca_path", Placeholder: ""}, +} +var ConnectInfoConnection = []Connection{ + {Endpoint: "public", Client: "generalparams", Type: "parameter", Path: "./public/general/params", DownloadCa: []string{ + "windows", + "other", + }, Doc: "", Content: `HOST ${host} +PORT ${port} +USERNAME ${username} +PASSWORD ${password} +DATABASE ${database} +CA ${ca_path} +`}, + {Endpoint: "private", Client: "generalparams", Type: "parameter", Path: "./private/general/params", DownloadCa: []string{}, Doc: "", Content: `HOST ${host} +PORT ${port} +USERNAME ${username} +PASSWORD ${password} +DATABASE ${database} +`}, + {Endpoint: "public", Client: "generalstring", Type: "code", Path: "./public/general/string", DownloadCa: []string{ + "windows", + "other", + }, Doc: "", Content: `mysql://${username}:${password}@${host}:${port}/${database} +`}, + {Endpoint: "private", Client: "generalstring", Type: "code", Path: "./private/general/string", DownloadCa: []string{}, Doc: "", Content: `mysql://${username}:${password}@${host}:${port}/${database} +`}, + {Endpoint: "public", Client: "dotenv", Type: "code", Path: "./public/db.env", DownloadCa: []string{}, Doc: "", Content: `DB_HOST=${host} +DB_PORT=${port} +DB_USERNAME=${username} +DB_PASSWORD=${password} +DB_DATABASE=${database} +`}, + {Endpoint: "private", Client: "dotenv", Type: "code", Path: "./private/db.env", DownloadCa: []string{}, Doc: "", Content: `DB_HOST=${host} +DB_PORT=${port} +DB_USERNAME=${username} +DB_PASSWORD=${password} +DB_DATABASE=${database} +`}, + {Endpoint: "public", Client: "mysqlcli", Type: "code", Path: "./public/mysql.sh", DownloadCa: []string{ + "windows", + "other", + }, Doc: "", Content: `mysql --comments -u '${username}' -h ${host} -P ${port} -D '${database}' --ssl-mode=VERIFY_IDENTITY --ssl-ca=${ca_path} -p'${password}' +`}, + {Endpoint: "private", Client: "mysqlcli", Type: "code", Path: "./private/mysql.sh", DownloadCa: []string{}, Doc: "", Content: `mysql --comments -u '${username}' -h ${host} -P ${port} -D '${database}' -p'${password}' +`}, + {Endpoint: "public", Client: "mariadbcli", Type: "code", Path: "./public/mariadb.sh", DownloadCa: []string{ + "windows", + "other", + }, Doc: "", Content: `mysql --comments -u '${username}' -h ${host} -P ${port} -D '${database}' --ssl-verify-server-cert --ssl-ca=${ca_path} -p'${password}' +`}, + {Endpoint: "private", Client: "mariadbcli", Type: "code", Path: "./private/mariadb.sh", DownloadCa: []string{}, Doc: "", Content: `mysql --comments -u '${username}' -h ${host} -P ${port} -D '${database}' -p'${password}' +`}, + {Endpoint: "public", Client: "mysqlconnectorj", Type: "code", Path: "./public/java/mysql", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-java-jdbc", Content: `jdbc:mysql://${username}:${password}@${host}:${port}/${database}?sslMode=VERIFY_IDENTITY +`}, + {Endpoint: "private", Client: "mysqlconnectorj", Type: "code", Path: "./private/java/mysql", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-java-jdbc", Content: `jdbc:mysql://${username}:${password}@${host}:${port}/${database} +`}, + {Endpoint: "public", Client: "mariadbconnectorj", Type: "code", Path: "./public/java/mariadb", DownloadCa: []string{}, Doc: "", Content: `jdbc:mariadb://${host}:${port}/${database}?user=${username}&password=${password}&sslMode=verify-full +`}, + {Endpoint: "private", Client: "mariadbconnectorj", Type: "code", Path: "./private/java/mariadb", DownloadCa: []string{}, Doc: "", Content: `jdbc:mariadb://${host}:${port}/${database}?user=${username}&password=${password} +`}, + {Endpoint: "public", Client: "pythonmysqlclient", Type: "code", Path: "./public/python/mysqlclient.py", DownloadCa: []string{ + "windows", + "other", + }, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-mysqlclient", Content: `import MySQLdb + +connection = MySQLdb.connect( + host = "${host}", + port = ${port}, + user = "${username}", + password = "${password}", + database = "${database}", + ssl_mode = "VERIFY_IDENTITY", + ssl = { + "ca": "${ca_path}" + } +) +`}, + {Endpoint: "private", Client: "pythonmysqlclient", Type: "code", Path: "./private/python/mysqlclient.py", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-mysqlclient", Content: `import MySQLdb + +connection = MySQLdb.connect( + host = "${host}", + port = ${port}, + user = "${username}", + password = "${password}", + database = "${database}", +) +`}, + {Endpoint: "public", Client: "pythonpymysql", Type: "code", Path: "./public/python/pymysql.py", DownloadCa: []string{ + "windows", + "other", + }, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-pymysql", Content: `import pymysql + +connection = pymysql.connect( + host = "${host}", + port = ${port}, + user = "${username}", + password = "${password}", + database = "${database}", + ssl_verify_cert = True, + ssl_verify_identity = True, + ssl_ca = "${ca_path}" +) +`}, + {Endpoint: "private", Client: "pythonpymysql", Type: "code", Path: "./private/python/pymysql.py", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-pymysql", Content: `import pymysql + +connection = pymysql.connect( + host = "${host}", + port = ${port}, + user = "${username}", + password = "${password}", + database = "${database}", +) +`}, + {Endpoint: "public", Client: "pythonmysqlconnector", Type: "code", Path: "./public/python/connector.py", DownloadCa: []string{ + "windows", + "other", + }, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-mysql-connector", Content: `import mysql.connector + +connection = mysql.connector.connect( + host = "${host}", + port = ${port}, + user = "${username}", + password = "${password}", + database = "${database}", + ssl_ca = "${ca_path}", + ssl_verify_cert = True, + ssl_verify_identity = True +) +`}, + {Endpoint: "private", Client: "pythonmysqlconnector", Type: "code", Path: "./private/python/connector.py", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-mysql-connector", Content: `import mysql.connector + +connection = mysql.connector.connect( + host = "${host}", + port = ${port}, + user = "${username}", + password = "${password}", + database = "${database}", +) +`}, + {Endpoint: "public", Client: "sqlalchemymysqlclient", Type: "code", Path: "./public/sqlalchemy/mysqlclient", DownloadCa: []string{ + "windows", + "other", + }, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-sqlalchemy", Content: `mysql+mysqldb://${username}:${password}@${host}:${port}/${database}?ssl_mode=VERIFY_IDENTITY&ssl_ca=${ca_path} +`}, + {Endpoint: "private", Client: "sqlalchemymysqlclient", Type: "code", Path: "./private/sqlalchemy/mysqlclient", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-sqlalchemy", Content: `mysql+mysqldb://${username}:${password}@${host}:${port}/${database} +`}, + {Endpoint: "public", Client: "sqlalchemypymysql", Type: "code", Path: "./public/sqlalchemy/pymysql", DownloadCa: []string{ + "windows", + "other", + }, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-sqlalchemy", Content: `mysql+pymysql://${username}:${password}@${host}:${port}/${database}?ssl_ca=${ca_path}&ssl_verify_cert=true&ssl_verify_identity=true +`}, + {Endpoint: "private", Client: "sqlalchemypymysql", Type: "code", Path: "./private/sqlalchemy/pymysql", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-sqlalchemy", Content: `mysql+pymysql://${username}:${password}@${host}:${port}/${database} +`}, + {Endpoint: "public", Client: "sqlalchemymysqlconnector", Type: "code", Path: "./public/sqlalchemy/connector", DownloadCa: []string{ + "windows", + "other", + }, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-sqlalchemy", Content: `mysql+mysqlconnector://${username}:${password}@${host}:${port}/${database}?ssl_ca=${ca_path}&ssl_verify_cert=true&ssl_verify_identity=true +`}, + {Endpoint: "private", Client: "sqlalchemymysqlconnector", Type: "code", Path: "./private/sqlalchemy/connector", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-sqlalchemy", Content: `mysql+mysqlconnector://${username}:${password}@${host}:${port}/${database} +`}, + {Endpoint: "public", Client: "django", Type: "code", Path: "./public/django.py", DownloadCa: []string{ + "windows", + "other", + }, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-django", Content: `DATABASES = { + 'default': { + 'ENGINE': 'django_tidb', + 'NAME': '${database}', + 'USER': '${username}', + 'PASSWORD': '${password}', + 'HOST': '${host}', + 'PORT': ${port}, + 'OPTIONS': { + 'ssl_mode': 'VERIFY_IDENTITY', + 'ssl': {'ca': '${ca_path}'} + } + }, +} +`}, + {Endpoint: "private", Client: "django", Type: "code", Path: "./private/django.py", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-django", Content: `DATABASES = { + 'default': { + 'ENGINE': 'django_tidb', + 'NAME': '${database}', + 'USER': '${username}', + 'PASSWORD': '${password}', + 'HOST': '${host}', + 'PORT': ${port}, + }, +} +`}, + {Endpoint: "public", Client: "nodemysql2", Type: "code", Path: "./public/js/mysql2", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-nodejs-mysql2", Content: `mysql://${username}:${password}@${host}:${port}/${database}?ssl={"rejectUnauthorized":true} +`}, + {Endpoint: "private", Client: "nodemysql2", Type: "code", Path: "./private/js/mysql2", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-nodejs-mysql2", Content: `mysql://${username}:${password}@${host}:${port}/${database} +`}, + {Endpoint: "public", Client: "prisma", Type: "code", Path: "./public/js/prisma", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-nodejs-prisma", Content: `mysql://${username}:${password}@${host}:${port}/${database}?sslaccept=strict +`}, + {Endpoint: "private", Client: "prisma", Type: "code", Path: "./private/js/prisma", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-nodejs-prisma", Content: `mysql://${username}:${password}@${host}:${port}/${database} +`}, + {Endpoint: "public", Client: "serverlessjs", Type: "code", Path: "./public/js/serverless", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/serverless-driver-node-example", Content: `mysql://${username}:${password}@${host}/${database} +`}, + {Endpoint: "private", Client: "serverlessjs", Type: "code", Path: "./private/js/serverless", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/serverless-driver-node-example", Content: `mysql://${username}:${password}@${host}/${database} +`}, + {Endpoint: "public", Client: "go", Type: "code", Path: "./public/mysql.go", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-golang-sql-driver", Content: `mysql.RegisterTLSConfig("tidb", &tls.Config{ + MinVersion: tls.VersionTLS12, + ServerName: "${host}", +}) + +db, err := sql.Open("mysql", "${username}:${password}@tcp(${host}:${port})/${database}?tls=tidb") +`}, + {Endpoint: "private", Client: "go", Type: "code", Path: "./private/mysql.go", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-golang-sql-driver", Content: `db, err := sql.Open("mysql", "${username}:${password}@tcp(${host}:${port})/${database}") +`}, + {Endpoint: "public", Client: "rails", Type: "code", Path: "./public/rails.yml", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-ruby-rails", Content: `development: + <<: *default + adapter: mysql2 + url: mysql2://${username}:${password}@${host}:${port}/${database}?ssl_mode=verify_identity +`}, + {Endpoint: "private", Client: "rails", Type: "code", Path: "./private/rails.yml", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-ruby-rails", Content: `development: + <<: *default + adapter: mysql2 + url: mysql2://${username}:${password}@${host}:${port}/${database} +`}, + {Endpoint: "public", Client: "datagrip", Type: "code", Path: "./public/gui/datagrip", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-gui-datagrip", Content: `jdbc:mysql://${host}:${port}/${database}?user=${username}&password=${password}&sslMode=VERIFY_IDENTITY +`}, + {Endpoint: "private", Client: "datagrip", Type: "code", Path: "./private/gui/datagrip", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-gui-datagrip", Content: `jdbc:mysql://${host}:${port}/${database}?user=${username}&password=${password} +`}, + {Endpoint: "public", Client: "dbeaver", Type: "code", Path: "./public/java/mysql", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-gui-dbeaver", Content: `jdbc:mysql://${username}:${password}@${host}:${port}/${database}?sslMode=VERIFY_IDENTITY +`}, + {Endpoint: "private", Client: "dbeaver", Type: "code", Path: "./private/java/mysql", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-gui-dbeaver", Content: `jdbc:mysql://${username}:${password}@${host}:${port}/${database} +`}, + {Endpoint: "public", Client: "vscode", Type: "parameter", Path: "./public/general/params", DownloadCa: []string{ + "windows", + "other", + }, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-gui-vscode-sqltools", Content: `HOST ${host} +PORT ${port} +USERNAME ${username} +PASSWORD ${password} +DATABASE ${database} +CA ${ca_path} +`}, + {Endpoint: "private", Client: "vscode", Type: "parameter", Path: "./private/general/params", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-gui-vscode-sqltools", Content: `HOST ${host} +PORT ${port} +USERNAME ${username} +PASSWORD ${password} +DATABASE ${database} +`}, + {Endpoint: "public", Client: "mysqlworkbench", Type: "parameter", Path: "./public/general/params", DownloadCa: []string{ + "windows", + "other", + }, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-gui-mysql-workbench", Content: `HOST ${host} +PORT ${port} +USERNAME ${username} +PASSWORD ${password} +DATABASE ${database} +CA ${ca_path} +`}, + {Endpoint: "private", Client: "mysqlworkbench", Type: "parameter", Path: "./private/general/params", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-gui-mysql-workbench", Content: `HOST ${host} +PORT ${port} +USERNAME ${username} +PASSWORD ${password} +DATABASE ${database} +`}, + {Endpoint: "public", Client: "navicat", Type: "parameter", Path: "./public/general/params", DownloadCa: []string{ + "windows", + "other", + }, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-gui-navicat", Content: `HOST ${host} +PORT ${port} +USERNAME ${username} +PASSWORD ${password} +DATABASE ${database} +CA ${ca_path} +`}, + {Endpoint: "private", Client: "navicat", Type: "parameter", Path: "./private/general/params", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-gui-navicat", Content: `HOST ${host} +PORT ${port} +USERNAME ${username} +PASSWORD ${password} +DATABASE ${database} +`}, + {Endpoint: "public", Client: "wordpress", Type: "parameter", Path: "./public/general/params", DownloadCa: []string{ + "windows", + "other", + }, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-wordpress", Content: `HOST ${host} +PORT ${port} +USERNAME ${username} +PASSWORD ${password} +DATABASE ${database} +CA ${ca_path} +`}, + {Endpoint: "private", Client: "wordpress", Type: "parameter", Path: "./private/general/params", DownloadCa: []string{}, Doc: "https://docs.pingcap.com/tidbcloud/dev-guide-wordpress", Content: `HOST ${host} +PORT ${port} +USERNAME ${username} +PASSWORD ${password} +DATABASE ${database} +`}, +} diff --git a/pkg/tidbcloud/connect-info/main.go b/pkg/tidbcloud/connect-info/main.go new file mode 100644 index 00000000..93599d2f --- /dev/null +++ b/pkg/tidbcloud/connect-info/main.go @@ -0,0 +1,225 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" +) + +type ConnectInfo struct { + Endpoint []Endpoint `json:"endpoint"` + Os []Os `json:"os"` + Ca []Ca `json:"ca"` + Client []Client `json:"client"` + Variable []Variable `json:"variable"` + Connection []Connection `json:"connection"` +} +type Endpoint struct { + ID string `json:"id"` + Name string `json:"name"` +} +type Os struct { + ID string `json:"id"` + Name string `json:"name"` +} +type Ca struct { + Os string `json:"os"` + Type string `json:"type"` + Path string `json:"path"` +} +type Options struct { + ID string `json:"id"` + Name string `json:"name"` +} +type Client struct { + ID string `json:"id"` + Name string `json:"name"` + Options []Options `json:"options,omitempty"` +} +type Variable struct { + ID string `json:"id"` + Placeholder string `json:"placeholder"` +} +type Connection struct { + Endpoint string `json:"endpoint"` + Client string `json:"client"` + Type string `json:"type"` + Path string `json:"path"` + DownloadCa []string `json:"download_ca,omitempty"` + Doc string `json:"doc,omitempty"` + Content string `json:"content,omitempty"` +} + +const ConnectInfoStruct = ` +type ConnectInfo struct { + Endpoint []Endpoint + Os []Os + Ca []Ca + Client []Client + Variable []Variable + Connection []Connection +} +type Endpoint struct { + ID string + Name string +} +func (e Endpoint) String() string { + return e.Name +} +type Os struct { + ID string + Name string +} +func (o Os) String() string { + return o.Name +} +type Ca struct { + Os string + Type string + Path string +} +type Options struct { + ID string + Name string +} +func (o Options) String() string { + return o.Name +} +type Client struct { + ID string + Name string + Options []Options +} +func (c Client) String() string { + return c.Name +} +type Variable struct { + ID string + Placeholder string +} +type Connection struct { + Endpoint string + Client string + Type string + Path string + DownloadCa []string + Doc string + Content string +} + +` + +const license = `// Copyright 2024 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +` + +func main() { + // read manifest file and unmarshal it to ConnectInfo struct + connectInfo, err := ReadManifest() + if err != nil { + panic(err) + } + // generate code + generateGoCode := GenerateCode(connectInfo) + + // write code to file + err = os.WriteFile("../../../internal/util/connect-info.go", []byte(generateGoCode), 0644) + if err != nil { + panic(err) + } +} + +func ReadManifest() (ConnectInfo, error) { + var connectInfo ConnectInfo + jsonString, err := os.ReadFile("meta/manifest.json") + if err != nil { + return connectInfo, err + } + err = json.Unmarshal(jsonString, &connectInfo) + if err != nil { + return connectInfo, err + } + return connectInfo, nil +} + +func GenerateCode(connectInfo ConnectInfo) string { + GenerateGoCode := license + GenerateGoCode += "// Code is generated. DO NOT EDIT.\n\n" + GenerateGoCode += "package util\n" + GenerateGoCode += ConnectInfoStruct + + endpoint := connectInfo.Endpoint + connectInfoOs := connectInfo.Os + ca := connectInfo.Ca + client := connectInfo.Client + variable := connectInfo.Variable + connection := connectInfo.Connection + + // Endpoint + GenerateGoCode += "var ConnectInfoEndpoint = []Endpoint{\n" + for _, v := range endpoint { + GenerateGoCode += "\t{ID: \"" + v.ID + "\", Name: \"" + v.Name + "\"},\n" + } + GenerateGoCode += "}\n" + + // Os + GenerateGoCode += "var ConnectInfoOs = []Os{\n" + for _, v := range connectInfoOs { + GenerateGoCode += "\t{ID: \"" + v.ID + "\", Name: \"" + v.Name + "\"},\n" + } + GenerateGoCode += "}\n" + + // Ca + GenerateGoCode += "var ConnectInfoCa = []Ca{\n" + for _, v := range ca { + GenerateGoCode += "\t{Os: \"" + v.Os + "\", Type: \"" + v.Type + "\", Path: \"" + v.Path + "\"},\n" + } + GenerateGoCode += "}\n" + + // Client + GenerateGoCode += "var ConnectInfoClient = []Client{\n" + for _, v := range client { + GenerateGoCode += "\t{ID: \"" + v.ID + "\", Name: \"" + v.Name + "\", Options: []Options{\n" + for _, o := range v.Options { + GenerateGoCode += "\t\t{ID: \"" + o.ID + "\", Name: \"" + o.Name + "\"},\n" + } + GenerateGoCode += "\t}},\n" + } + GenerateGoCode += "}\n" + // Variable + GenerateGoCode += "var ConnectInfoVariable = []Variable{\n" + for _, v := range variable { + GenerateGoCode += "\t{ID: \"" + v.ID + "\", Placeholder: \"" + v.Placeholder + "\"},\n" + } + GenerateGoCode += "}\n" + + // Connection + GenerateGoCode += "var ConnectInfoConnection = []Connection{\n" + for i, v := range connection { + path := v.Path[1:] + connectionString, err := os.ReadFile("meta" + path) + if err != nil { + panic(err) + } + connection[i].Content = string(connectionString) + GenerateGoCode += "\t{Endpoint: \"" + v.Endpoint + "\", Client: \"" + v.Client + "\", Type: \"" + v.Type + "\", Path: \"" + v.Path + "\", DownloadCa: []string{\n" + for _, d := range v.DownloadCa { + GenerateGoCode += "\t\t\"" + d + "\",\n" + } + GenerateGoCode += "\t}, Doc: \"" + v.Doc + "\", Content: " + fmt.Sprintf("`%s`},\n", v.Content) + } + GenerateGoCode += "}\n" + return GenerateGoCode +} diff --git a/pkg/tidbcloud/connect-info/meta/README.md b/pkg/tidbcloud/connect-info/meta/README.md new file mode 100644 index 00000000..c57314da --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/README.md @@ -0,0 +1,15 @@ +1. `endpoint` contains the id and value of Endpoint Types. value is used for display. +2. `os` contains the id and value of Operating System. value is used for display. +3. `ca` contains each file path of the corresponding operating system. +4. `client` is the list of supported tools/frameworks/drivers/ORMs. +5. `variable` is the default value displayed if the actual connection information cannot be retrieved. +6. `connection` the content of each client. `download_ca` means the client needs an explicit CA certificate but on these operating systems no builtin CA bundle exists. Users need to download the ISRG X1 Root Certificated manually. `doc` means there is an official doc page to refer to for detailed steps. This controls the bottom help message. `type` controls the render style on console. + +Each file contains the original content of the client's connection information. It will be parsed and transformed to frontend codes at build time. + +1. Placeholders should be substituded with proper values. Placeholders include `${username}`, `${password}`, `${host}`, `${port}`, `${database}` and `${ca_path}`. Except `${ca_path}`, others always exist. +2. When display, ${password} might not be created yet. +3. For ${ca_path}, it might be replace with a string, or a placeholder(e.g. Python driver on Windows). +4. For some clients, the values need be escaped first. + +https://pingcap.feishu.cn/docx/U0uedTQrCoHFJ0x7PJTcNF4hnuh \ No newline at end of file diff --git a/pkg/tidbcloud/connect-info/meta/go.mod b/pkg/tidbcloud/connect-info/meta/go.mod new file mode 100644 index 00000000..60a1a994 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/go.mod @@ -0,0 +1 @@ +module github.com/tidbcloud/ecosystem-service/api/v1/connect2 diff --git a/pkg/tidbcloud/connect-info/meta/manifest.json b/pkg/tidbcloud/connect-info/meta/manifest.json new file mode 100644 index 00000000..2da3118a --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/manifest.json @@ -0,0 +1,619 @@ +{ + "endpoint": [ + { + "id": "public", + "name": "Public" + }, + { + "id": "private", + "name": "Private" + } + ], + "os": [ + { + "id": "macos", + "name": "macOS" + }, + { + "id": "debian", + "name": "Debian/Ubuntu/Arch" + }, + { + "id": "centos", + "name": "CentOS/RedHat/Fedora" + }, + { + "id": "alpine", + "name": "Alpine" + }, + { + "id": "suse", + "name": "OpenSUSE" + }, + { + "id": "windows", + "name": "Windows" + }, + { + "id": "other", + "name": "Others" + } + ], + "ca": [ + { + "os": "macos", + "type": "local", + "path": "/etc/ssl/cert.pem" + }, + { + "os": "debian", + "type": "local", + "path": "/etc/ssl/certs/ca-certificates.crt" + }, + { + "os": "centos", + "type": "local", + "path": "/etc/pki/tls/certs/ca-bundle.crt" + }, + { + "os": "alpine", + "type": "local", + "path": "/etc/ssl/cert.pem" + }, + { + "os": "suse", + "type": "local", + "path": "/etc/ssl/ca-bundle.pem" + }, + { + "os": "windows", + "type": "link", + "path": "https://letsencrypt.org/certs/isrgrootx1.pem" + }, + { + "os": "other", + "type": "link", + "path": "https://letsencrypt.org/certs/isrgrootx1.pem" + } + ], + "client": [ + { + "id": "general", + "name": "General", + "options": [ + { + "id": "generalparams", + "name": "Parameters" + }, + { + "id": "generalstring", + "name": "Connection String" + } + ] + }, + { + "id": "mysqlcli", + "name": "MySQL CLI" + }, + { + "id": "mariadbcli", + "name": "MariaDB CLI" + }, + { + "id": "dotenv", + "name": ".env" + }, + { + "id": "mysqlconnectorj", + "name": "Java(MySQL Connector)" + }, + { + "id": "mariadbconnectorj", + "name": "Java(MariaDB Connector)" + }, + { + "id": "pythonmysqlclient", + "name": "Python(mysqlclient)" + }, + { + "id": "pythonpymysql", + "name": "Python(PyMySQL)" + }, + { + "id": "pythonmysqlconnector", + "name": "Python(MySQL Connector)" + }, + { + "id": "sqlalchemy", + "name": "SQLAlchemy", + "options": [ + { + "id": "sqlalchemymysqlclient", + "name": "mysqlclient" + }, + { + "id": "sqlalchemypymysql", + "name": "PyMySQL" + }, + { + "id": "sqlalchemymysqlconnector", + "name": "MySQL Connector" + } + ] + }, + { + "id": "django", + "name": "Django" + }, + { + "id": "nodemysql2", + "name": "Node.js(mysql2)" + }, + { + "id": "prisma", + "name": "Prisma" + }, + { + "id": "serverlessjs", + "name": "Serverless Driver" + }, + { + "id": "go", + "name": "Go" + }, + { + "id": "rails", + "name": "Rails" + }, + { + "id": "wordpress", + "name": "WordPress" + }, + { + "id": "datagrip", + "name": "DataGrip" + }, + { + "id": "vscode", + "name": "VS Code" + }, + { + "id": "dbeaver", + "name": "DBeaver" + }, + { + "id": "mysqlworkbench", + "name": "MySQL Workbench" + }, + { + "id": "navicat", + "name": "Navicat" + } + ], + "variable": [ + { + "id": "host", + "placeholder": "" + }, + { + "id": "port", + "placeholder": "" + }, + { + "id": "username", + "placeholder": "" + }, + { + "id": "password", + "placeholder": "" + }, + { + "id": "database", + "placeholder": "" + }, + { + "id": "ca_path", + "placeholder": "" + } + ], + "connection": [ + { + "endpoint": "public", + "client": "generalparams", + "type": "parameter", + "path": "./public/general/params", + "download_ca": [ + "windows", + "other" + ] + }, + { + "endpoint": "private", + "client": "generalparams", + "type": "parameter", + "path": "./private/general/params" + }, + { + "endpoint": "public", + "client": "generalstring", + "type": "code", + "path": "./public/general/string", + "download_ca": [ + "windows", + "other" + ] + }, + { + "endpoint": "private", + "client": "generalstring", + "type": "code", + "path": "./private/general/string" + }, + { + "endpoint": "public", + "client": "dotenv", + "type": "code", + "path": "./public/db.env" + }, + { + "endpoint": "private", + "client": "dotenv", + "type": "code", + "path": "./private/db.env" + }, + { + "endpoint": "public", + "client": "mysqlcli", + "type": "code", + "path": "./public/mysql.sh", + "download_ca": [ + "windows", + "other" + ] + }, + { + "endpoint": "private", + "client": "mysqlcli", + "type": "code", + "path": "./private/mysql.sh" + }, + { + "endpoint": "public", + "client": "mariadbcli", + "type": "code", + "path": "./public/mariadb.sh", + "download_ca": [ + "windows", + "other" + ] + }, + { + "endpoint": "private", + "client": "mariadbcli", + "type": "code", + "path": "./private/mariadb.sh" + }, + { + "endpoint": "public", + "client": "mysqlconnectorj", + "type": "code", + "path": "./public/java/mysql", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-java-jdbc" + }, + { + "endpoint": "private", + "client": "mysqlconnectorj", + "type": "code", + "path": "./private/java/mysql", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-java-jdbc" + }, + { + "endpoint": "public", + "client": "mariadbconnectorj", + "type": "code", + "path": "./public/java/mariadb" + }, + { + "endpoint": "private", + "client": "mariadbconnectorj", + "type": "code", + "path": "./private/java/mariadb" + }, + { + "endpoint": "public", + "client": "pythonmysqlclient", + "type": "code", + "path": "./public/python/mysqlclient.py", + "download_ca": [ + "windows", + "other" + ], + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-mysqlclient" + }, + { + "endpoint": "private", + "client": "pythonmysqlclient", + "type": "code", + "path": "./private/python/mysqlclient.py", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-mysqlclient" + }, + { + "endpoint": "public", + "client": "pythonpymysql", + "type": "code", + "path": "./public/python/pymysql.py", + "download_ca": [ + "windows", + "other" + ], + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-pymysql" + }, + { + "endpoint": "private", + "client": "pythonpymysql", + "type": "code", + "path": "./private/python/pymysql.py", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-pymysql" + }, + { + "endpoint": "public", + "client": "pythonmysqlconnector", + "type": "code", + "path": "./public/python/connector.py", + "download_ca": [ + "windows", + "other" + ], + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-mysql-connector" + }, + { + "endpoint": "private", + "client": "pythonmysqlconnector", + "type": "code", + "path": "./private/python/connector.py", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-mysql-connector" + }, + { + "endpoint": "public", + "client": "sqlalchemymysqlclient", + "type": "code", + "path": "./public/sqlalchemy/mysqlclient", + "download_ca": [ + "windows", + "other" + ], + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-sqlalchemy" + }, + { + "endpoint": "private", + "client": "sqlalchemymysqlclient", + "type": "code", + "path": "./private/sqlalchemy/mysqlclient", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-sqlalchemy" + }, + { + "endpoint": "public", + "client": "sqlalchemypymysql", + "type": "code", + "path": "./public/sqlalchemy/pymysql", + "download_ca": [ + "windows", + "other" + ], + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-sqlalchemy" + }, + { + "endpoint": "private", + "client": "sqlalchemypymysql", + "type": "code", + "path": "./private/sqlalchemy/pymysql", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-sqlalchemy" + }, + { + "endpoint": "public", + "client": "sqlalchemymysqlconnector", + "type": "code", + "path": "./public/sqlalchemy/connector", + "download_ca": [ + "windows", + "other" + ], + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-sqlalchemy" + }, + { + "endpoint": "private", + "client": "sqlalchemymysqlconnector", + "type": "code", + "path": "./private/sqlalchemy/connector", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-sqlalchemy" + }, + { + "endpoint": "public", + "client": "django", + "type": "code", + "path": "./public/django.py", + "download_ca": [ + "windows", + "other" + ], + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-django" + }, + { + "endpoint": "private", + "client": "django", + "type": "code", + "path": "./private/django.py", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-python-django" + }, + { + "endpoint": "public", + "client": "nodemysql2", + "type": "code", + "path": "./public/js/mysql2", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-nodejs-mysql2" + }, + { + "endpoint": "private", + "client": "nodemysql2", + "type": "code", + "path": "./private/js/mysql2", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-nodejs-mysql2" + }, + { + "endpoint": "public", + "client": "prisma", + "type": "code", + "path": "./public/js/prisma", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-nodejs-prisma" + }, + { + "endpoint": "private", + "client": "prisma", + "type": "code", + "path": "./private/js/prisma", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-nodejs-prisma" + }, + { + "endpoint": "public", + "client": "serverlessjs", + "type": "code", + "path": "./public/js/serverless", + "doc": "https://docs.pingcap.com/tidbcloud/serverless-driver-node-example" + }, + { + "endpoint": "private", + "client": "serverlessjs", + "type": "code", + "path": "./private/js/serverless", + "doc": "https://docs.pingcap.com/tidbcloud/serverless-driver-node-example" + }, + { + "endpoint": "public", + "client": "go", + "type": "code", + "path": "./public/mysql.go", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-golang-sql-driver" + }, + { + "endpoint": "private", + "client": "go", + "type": "code", + "path": "./private/mysql.go", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-golang-sql-driver" + }, + { + "endpoint": "public", + "client": "rails", + "type": "code", + "path": "./public/rails.yml", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-ruby-rails" + }, + { + "endpoint": "private", + "client": "rails", + "type": "code", + "path": "./private/rails.yml", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-sample-application-ruby-rails" + }, + { + "endpoint": "public", + "client": "datagrip", + "type": "code", + "path": "./public/gui/datagrip", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-gui-datagrip" + }, + { + "endpoint": "private", + "client": "datagrip", + "type": "code", + "path": "./private/gui/datagrip", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-gui-datagrip" + }, + { + "endpoint": "public", + "client": "dbeaver", + "type": "code", + "path": "./public/java/mysql", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-gui-dbeaver" + }, + { + "endpoint": "private", + "client": "dbeaver", + "type": "code", + "path": "./private/java/mysql", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-gui-dbeaver" + }, + { + "endpoint": "public", + "client": "vscode", + "type": "parameter", + "path": "./public/general/params", + "download_ca": [ + "windows", + "other" + ], + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-gui-vscode-sqltools" + }, + { + "endpoint": "private", + "client": "vscode", + "type": "parameter", + "path": "./private/general/params", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-gui-vscode-sqltools" + }, + { + "endpoint": "public", + "client": "mysqlworkbench", + "type": "parameter", + "path": "./public/general/params", + "download_ca": [ + "windows", + "other" + ], + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-gui-mysql-workbench" + }, + { + "endpoint": "private", + "client": "mysqlworkbench", + "type": "parameter", + "path": "./private/general/params", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-gui-mysql-workbench" + }, + { + "endpoint": "public", + "client": "navicat", + "type": "parameter", + "path": "./public/general/params", + "download_ca": [ + "windows", + "other" + ], + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-gui-navicat" + }, + { + "endpoint": "private", + "client": "navicat", + "type": "parameter", + "path": "./private/general/params", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-gui-navicat" + }, + { + "endpoint": "public", + "client": "wordpress", + "type": "parameter", + "path": "./public/general/params", + "download_ca": [ + "windows", + "other" + ], + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-wordpress" + }, + { + "endpoint": "private", + "client": "wordpress", + "type": "parameter", + "path": "./private/general/params", + "doc": "https://docs.pingcap.com/tidbcloud/dev-guide-wordpress" + } + ] +} diff --git a/pkg/tidbcloud/connect-info/meta/private/db.env b/pkg/tidbcloud/connect-info/meta/private/db.env new file mode 100644 index 00000000..f896c5d6 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/private/db.env @@ -0,0 +1,5 @@ +DB_HOST=${host} +DB_PORT=${port} +DB_USERNAME=${username} +DB_PASSWORD=${password} +DB_DATABASE=${database} diff --git a/pkg/tidbcloud/connect-info/meta/private/django.py b/pkg/tidbcloud/connect-info/meta/private/django.py new file mode 100644 index 00000000..f3dab773 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/private/django.py @@ -0,0 +1,10 @@ +DATABASES = { + 'default': { + 'ENGINE': 'django_tidb', + 'NAME': '${database}', + 'USER': '${username}', + 'PASSWORD': '${password}', + 'HOST': '${host}', + 'PORT': ${port}, + }, +} diff --git a/pkg/tidbcloud/connect-info/meta/private/general/params b/pkg/tidbcloud/connect-info/meta/private/general/params new file mode 100644 index 00000000..b8acffe0 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/private/general/params @@ -0,0 +1,5 @@ +HOST ${host} +PORT ${port} +USERNAME ${username} +PASSWORD ${password} +DATABASE ${database} diff --git a/pkg/tidbcloud/connect-info/meta/private/general/string b/pkg/tidbcloud/connect-info/meta/private/general/string new file mode 100644 index 00000000..8ddac534 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/private/general/string @@ -0,0 +1 @@ +mysql://${username}:${password}@${host}:${port}/${database} diff --git a/pkg/tidbcloud/connect-info/meta/private/gui/datagrip b/pkg/tidbcloud/connect-info/meta/private/gui/datagrip new file mode 100644 index 00000000..4726b635 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/private/gui/datagrip @@ -0,0 +1 @@ +jdbc:mysql://${host}:${port}/${database}?user=${username}&password=${password} diff --git a/pkg/tidbcloud/connect-info/meta/private/java/mariadb b/pkg/tidbcloud/connect-info/meta/private/java/mariadb new file mode 100644 index 00000000..5f3ab703 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/private/java/mariadb @@ -0,0 +1 @@ +jdbc:mariadb://${host}:${port}/${database}?user=${username}&password=${password} diff --git a/pkg/tidbcloud/connect-info/meta/private/java/mysql b/pkg/tidbcloud/connect-info/meta/private/java/mysql new file mode 100644 index 00000000..bd9d1d38 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/private/java/mysql @@ -0,0 +1 @@ +jdbc:mysql://${username}:${password}@${host}:${port}/${database} diff --git a/pkg/tidbcloud/connect-info/meta/private/js/mysql2 b/pkg/tidbcloud/connect-info/meta/private/js/mysql2 new file mode 100644 index 00000000..8ddac534 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/private/js/mysql2 @@ -0,0 +1 @@ +mysql://${username}:${password}@${host}:${port}/${database} diff --git a/pkg/tidbcloud/connect-info/meta/private/js/prisma b/pkg/tidbcloud/connect-info/meta/private/js/prisma new file mode 100644 index 00000000..8ddac534 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/private/js/prisma @@ -0,0 +1 @@ +mysql://${username}:${password}@${host}:${port}/${database} diff --git a/pkg/tidbcloud/connect-info/meta/private/js/serverless b/pkg/tidbcloud/connect-info/meta/private/js/serverless new file mode 100644 index 00000000..29dacd54 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/private/js/serverless @@ -0,0 +1 @@ +mysql://${username}:${password}@${host}/${database} diff --git a/pkg/tidbcloud/connect-info/meta/private/mariadb.sh b/pkg/tidbcloud/connect-info/meta/private/mariadb.sh new file mode 100644 index 00000000..df478c61 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/private/mariadb.sh @@ -0,0 +1 @@ +mysql --comments -u '${username}' -h ${host} -P ${port} -D '${database}' -p'${password}' diff --git a/pkg/tidbcloud/connect-info/meta/private/mysql.go b/pkg/tidbcloud/connect-info/meta/private/mysql.go new file mode 100644 index 00000000..0c869e7e --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/private/mysql.go @@ -0,0 +1 @@ +db, err := sql.Open("mysql", "${username}:${password}@tcp(${host}:${port})/${database}") diff --git a/pkg/tidbcloud/connect-info/meta/private/mysql.sh b/pkg/tidbcloud/connect-info/meta/private/mysql.sh new file mode 100644 index 00000000..df478c61 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/private/mysql.sh @@ -0,0 +1 @@ +mysql --comments -u '${username}' -h ${host} -P ${port} -D '${database}' -p'${password}' diff --git a/pkg/tidbcloud/connect-info/meta/private/python/connector.py b/pkg/tidbcloud/connect-info/meta/private/python/connector.py new file mode 100644 index 00000000..c1baae49 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/private/python/connector.py @@ -0,0 +1,9 @@ +import mysql.connector + +connection = mysql.connector.connect( + host = "${host}", + port = ${port}, + user = "${username}", + password = "${password}", + database = "${database}", +) diff --git a/pkg/tidbcloud/connect-info/meta/private/python/mysqlclient.py b/pkg/tidbcloud/connect-info/meta/private/python/mysqlclient.py new file mode 100644 index 00000000..50f09d9e --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/private/python/mysqlclient.py @@ -0,0 +1,9 @@ +import MySQLdb + +connection = MySQLdb.connect( + host = "${host}", + port = ${port}, + user = "${username}", + password = "${password}", + database = "${database}", +) diff --git a/pkg/tidbcloud/connect-info/meta/private/python/pymysql.py b/pkg/tidbcloud/connect-info/meta/private/python/pymysql.py new file mode 100644 index 00000000..9ccb1be2 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/private/python/pymysql.py @@ -0,0 +1,9 @@ +import pymysql + +connection = pymysql.connect( + host = "${host}", + port = ${port}, + user = "${username}", + password = "${password}", + database = "${database}", +) diff --git a/pkg/tidbcloud/connect-info/meta/private/rails.yml b/pkg/tidbcloud/connect-info/meta/private/rails.yml new file mode 100644 index 00000000..309abe89 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/private/rails.yml @@ -0,0 +1,4 @@ +development: + <<: *default + adapter: mysql2 + url: mysql2://${username}:${password}@${host}:${port}/${database} diff --git a/pkg/tidbcloud/connect-info/meta/private/sqlalchemy/connector b/pkg/tidbcloud/connect-info/meta/private/sqlalchemy/connector new file mode 100644 index 00000000..2e09b8b5 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/private/sqlalchemy/connector @@ -0,0 +1 @@ +mysql+mysqlconnector://${username}:${password}@${host}:${port}/${database} diff --git a/pkg/tidbcloud/connect-info/meta/private/sqlalchemy/mysqlclient b/pkg/tidbcloud/connect-info/meta/private/sqlalchemy/mysqlclient new file mode 100644 index 00000000..a842f372 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/private/sqlalchemy/mysqlclient @@ -0,0 +1 @@ +mysql+mysqldb://${username}:${password}@${host}:${port}/${database} diff --git a/pkg/tidbcloud/connect-info/meta/private/sqlalchemy/pymysql b/pkg/tidbcloud/connect-info/meta/private/sqlalchemy/pymysql new file mode 100644 index 00000000..3bf48995 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/private/sqlalchemy/pymysql @@ -0,0 +1 @@ +mysql+pymysql://${username}:${password}@${host}:${port}/${database} diff --git a/pkg/tidbcloud/connect-info/meta/public/db.env b/pkg/tidbcloud/connect-info/meta/public/db.env new file mode 100644 index 00000000..f896c5d6 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/public/db.env @@ -0,0 +1,5 @@ +DB_HOST=${host} +DB_PORT=${port} +DB_USERNAME=${username} +DB_PASSWORD=${password} +DB_DATABASE=${database} diff --git a/pkg/tidbcloud/connect-info/meta/public/django.py b/pkg/tidbcloud/connect-info/meta/public/django.py new file mode 100644 index 00000000..9216e5c8 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/public/django.py @@ -0,0 +1,14 @@ +DATABASES = { + 'default': { + 'ENGINE': 'django_tidb', + 'NAME': '${database}', + 'USER': '${username}', + 'PASSWORD': '${password}', + 'HOST': '${host}', + 'PORT': ${port}, + 'OPTIONS': { + 'ssl_mode': 'VERIFY_IDENTITY', + 'ssl': {'ca': '${ca_path}'} + } + }, +} diff --git a/pkg/tidbcloud/connect-info/meta/public/general/params b/pkg/tidbcloud/connect-info/meta/public/general/params new file mode 100644 index 00000000..2b287388 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/public/general/params @@ -0,0 +1,6 @@ +HOST ${host} +PORT ${port} +USERNAME ${username} +PASSWORD ${password} +DATABASE ${database} +CA ${ca_path} diff --git a/pkg/tidbcloud/connect-info/meta/public/general/string b/pkg/tidbcloud/connect-info/meta/public/general/string new file mode 100644 index 00000000..8ddac534 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/public/general/string @@ -0,0 +1 @@ +mysql://${username}:${password}@${host}:${port}/${database} diff --git a/pkg/tidbcloud/connect-info/meta/public/gui/datagrip b/pkg/tidbcloud/connect-info/meta/public/gui/datagrip new file mode 100644 index 00000000..e2e27e3d --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/public/gui/datagrip @@ -0,0 +1 @@ +jdbc:mysql://${host}:${port}/${database}?user=${username}&password=${password}&sslMode=VERIFY_IDENTITY diff --git a/pkg/tidbcloud/connect-info/meta/public/java/mariadb b/pkg/tidbcloud/connect-info/meta/public/java/mariadb new file mode 100644 index 00000000..ebb71094 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/public/java/mariadb @@ -0,0 +1 @@ +jdbc:mariadb://${host}:${port}/${database}?user=${username}&password=${password}&sslMode=verify-full diff --git a/pkg/tidbcloud/connect-info/meta/public/java/mysql b/pkg/tidbcloud/connect-info/meta/public/java/mysql new file mode 100644 index 00000000..83d5b5d9 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/public/java/mysql @@ -0,0 +1 @@ +jdbc:mysql://${username}:${password}@${host}:${port}/${database}?sslMode=VERIFY_IDENTITY diff --git a/pkg/tidbcloud/connect-info/meta/public/js/mysql2 b/pkg/tidbcloud/connect-info/meta/public/js/mysql2 new file mode 100644 index 00000000..cc7460bd --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/public/js/mysql2 @@ -0,0 +1 @@ +mysql://${username}:${password}@${host}:${port}/${database}?ssl={"rejectUnauthorized":true} diff --git a/pkg/tidbcloud/connect-info/meta/public/js/prisma b/pkg/tidbcloud/connect-info/meta/public/js/prisma new file mode 100644 index 00000000..d056fdde --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/public/js/prisma @@ -0,0 +1 @@ +mysql://${username}:${password}@${host}:${port}/${database}?sslaccept=strict diff --git a/pkg/tidbcloud/connect-info/meta/public/js/serverless b/pkg/tidbcloud/connect-info/meta/public/js/serverless new file mode 100644 index 00000000..29dacd54 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/public/js/serverless @@ -0,0 +1 @@ +mysql://${username}:${password}@${host}/${database} diff --git a/pkg/tidbcloud/connect-info/meta/public/mariadb.sh b/pkg/tidbcloud/connect-info/meta/public/mariadb.sh new file mode 100644 index 00000000..8cf90cce --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/public/mariadb.sh @@ -0,0 +1 @@ +mysql --comments -u '${username}' -h ${host} -P ${port} -D '${database}' --ssl-verify-server-cert --ssl-ca=${ca_path} -p'${password}' diff --git a/pkg/tidbcloud/connect-info/meta/public/mysql.go b/pkg/tidbcloud/connect-info/meta/public/mysql.go new file mode 100644 index 00000000..3884653e --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/public/mysql.go @@ -0,0 +1,6 @@ +mysql.RegisterTLSConfig("tidb", &tls.Config{ + MinVersion: tls.VersionTLS12, + ServerName: "${host}", +}) + +db, err := sql.Open("mysql", "${username}:${password}@tcp(${host}:${port})/${database}?tls=tidb") diff --git a/pkg/tidbcloud/connect-info/meta/public/mysql.sh b/pkg/tidbcloud/connect-info/meta/public/mysql.sh new file mode 100644 index 00000000..b3df3df3 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/public/mysql.sh @@ -0,0 +1 @@ +mysql --comments -u '${username}' -h ${host} -P ${port} -D '${database}' --ssl-mode=VERIFY_IDENTITY --ssl-ca=${ca_path} -p'${password}' diff --git a/pkg/tidbcloud/connect-info/meta/public/python/connector.py b/pkg/tidbcloud/connect-info/meta/public/python/connector.py new file mode 100644 index 00000000..4032e18d --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/public/python/connector.py @@ -0,0 +1,12 @@ +import mysql.connector + +connection = mysql.connector.connect( + host = "${host}", + port = ${port}, + user = "${username}", + password = "${password}", + database = "${database}", + ssl_ca = "${ca_path}", + ssl_verify_cert = True, + ssl_verify_identity = True +) diff --git a/pkg/tidbcloud/connect-info/meta/public/python/mysqlclient.py b/pkg/tidbcloud/connect-info/meta/public/python/mysqlclient.py new file mode 100644 index 00000000..e47b9476 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/public/python/mysqlclient.py @@ -0,0 +1,13 @@ +import MySQLdb + +connection = MySQLdb.connect( + host = "${host}", + port = ${port}, + user = "${username}", + password = "${password}", + database = "${database}", + ssl_mode = "VERIFY_IDENTITY", + ssl = { + "ca": "${ca_path}" + } +) diff --git a/pkg/tidbcloud/connect-info/meta/public/python/pymysql.py b/pkg/tidbcloud/connect-info/meta/public/python/pymysql.py new file mode 100644 index 00000000..5134c7e8 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/public/python/pymysql.py @@ -0,0 +1,12 @@ +import pymysql + +connection = pymysql.connect( + host = "${host}", + port = ${port}, + user = "${username}", + password = "${password}", + database = "${database}", + ssl_verify_cert = True, + ssl_verify_identity = True, + ssl_ca = "${ca_path}" +) diff --git a/pkg/tidbcloud/connect-info/meta/public/rails.yml b/pkg/tidbcloud/connect-info/meta/public/rails.yml new file mode 100644 index 00000000..05eb987f --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/public/rails.yml @@ -0,0 +1,4 @@ +development: + <<: *default + adapter: mysql2 + url: mysql2://${username}:${password}@${host}:${port}/${database}?ssl_mode=verify_identity diff --git a/pkg/tidbcloud/connect-info/meta/public/sqlalchemy/connector b/pkg/tidbcloud/connect-info/meta/public/sqlalchemy/connector new file mode 100644 index 00000000..8f1d9598 --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/public/sqlalchemy/connector @@ -0,0 +1 @@ +mysql+mysqlconnector://${username}:${password}@${host}:${port}/${database}?ssl_ca=${ca_path}&ssl_verify_cert=true&ssl_verify_identity=true diff --git a/pkg/tidbcloud/connect-info/meta/public/sqlalchemy/mysqlclient b/pkg/tidbcloud/connect-info/meta/public/sqlalchemy/mysqlclient new file mode 100644 index 00000000..da710bfd --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/public/sqlalchemy/mysqlclient @@ -0,0 +1 @@ +mysql+mysqldb://${username}:${password}@${host}:${port}/${database}?ssl_mode=VERIFY_IDENTITY&ssl_ca=${ca_path} diff --git a/pkg/tidbcloud/connect-info/meta/public/sqlalchemy/pymysql b/pkg/tidbcloud/connect-info/meta/public/sqlalchemy/pymysql new file mode 100644 index 00000000..9ea800ff --- /dev/null +++ b/pkg/tidbcloud/connect-info/meta/public/sqlalchemy/pymysql @@ -0,0 +1 @@ +mysql+pymysql://${username}:${password}@${host}:${port}/${database}?ssl_ca=${ca_path}&ssl_verify_cert=true&ssl_verify_identity=true diff --git a/scripts/connect-info.sh b/scripts/connect-info.sh new file mode 100755 index 00000000..e43e62ba --- /dev/null +++ b/scripts/connect-info.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# Copyright 2024 PingCAP, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cd pkg/tidbcloud/connect-info +#rm -rf meta +#git clone git@github.com:tidbcloud/ecosystem-service.git +#mv ecosystem-service/api/v1/connect2 meta +#rm -rf ecosystem-service + +go run main.go +