From 4bb6cb3ca4a002e3e8f6172ce816c47aaf414487 Mon Sep 17 00:00:00 2001 From: longbob <710190609@qq.com> Date: Fri, 5 Mar 2021 17:11:00 +0800 Subject: [PATCH 1/6] feat: add port map --- cmd/kubefwd/services/services.go | 19 +++++++++++++++++ pkg/fwdservice/fwdservice.go | 35 ++++++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/cmd/kubefwd/services/services.go b/cmd/kubefwd/services/services.go index ffc0f6ec..070e698d 100644 --- a/cmd/kubefwd/services/services.go +++ b/cmd/kubefwd/services/services.go @@ -19,6 +19,7 @@ import ( "fmt" "os" "os/signal" + "strings" "sync" "syscall" "time" @@ -53,6 +54,7 @@ var namespaces []string var contexts []string var verbose bool var domain string +var port string func init() { // override error output from k8s.io/apimachinery/pkg/util/runtime @@ -67,6 +69,8 @@ func init() { Cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on; supports '=', '==', and '!=' (e.g. -l key1=value1,key2=value2).") Cmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "Verbose output.") Cmd.Flags().StringVarP(&domain, "domain", "d", "", "Append a pseudo domain name to generated host names.") + // "The Issues https://github.com/txn2/kubefwd/issues/121" + Cmd.Flags().StringVarP(&port, "port", "p", "", "Map the ports you need.(e.g. host port:container port -p 8080:80") } @@ -410,6 +414,7 @@ func (opts *NamespaceOpts) AddServiceHandler(obj interface{}) { PortForwards: make(map[string]*fwdport.PortForwardOpts), SyncDebouncer: debounce.New(5 * time.Second), DoneChannel: make(chan struct{}), + PortMap: opts.ParsePortMap(port), } // Add the service to the catalog of services being forwarded @@ -435,3 +440,17 @@ func (opts *NamespaceOpts) UpdateServiceHandler(_ interface{}, new interface{}) log.Printf("update service %s.", key) } } + +// parse string port to PortMap +func (opts *NamespaceOpts) ParsePortMap(port string) *[]fwdservice.PortMap { + var portList []fwdservice.PortMap + if port == "" { + return nil + } + strArr := strings.Split(port, ",") + for _, s := range strArr { + portInfo := strings.Split(s, ":") + portList = append(portList, fwdservice.PortMap{SourcePort: portInfo[0], TargetPort: portInfo[1]}) + } + return &portList +} diff --git a/pkg/fwdservice/fwdservice.go b/pkg/fwdservice/fwdservice.go index eadc4cc8..357b37ca 100644 --- a/pkg/fwdservice/fwdservice.go +++ b/pkg/fwdservice/fwdservice.go @@ -59,8 +59,8 @@ type ServiceFWD struct { // while normally only a single pod is forwarded. Headless bool - LastSyncedAt time.Time // When was the set of pods last synced - + LastSyncedAt time.Time // When was the set of pods last synced + PortMap *[]PortMap // port map array. // Use debouncer for listing pods so we don't hammer the k8s when a bunch of changes happen at once SyncDebouncer func(f func()) @@ -70,6 +70,15 @@ type ServiceFWD struct { DoneChannel chan struct{} // After shutdown is complete, this channel will be closed } +/** +add port map +@url https://github.com/txn2/kubefwd/issues/121 +*/ +type PortMap struct { + SourcePort string + TargetPort string +} + // String representation of a ServiceFWD returns a unique name // in the form SERVICE_NAME.NAMESPACE.CONTEXT func (svcFwd *ServiceFWD) String() string { @@ -252,8 +261,12 @@ func (svcFwd *ServiceFWD) LoopPodsToForward(pods []v1.Pod, includePodNameInHost } podPort = port.TargetPort.String() - localPort := strconv.Itoa(int(port.Port)) - + localPort := svcFwd.getPortMap(port.Port) + v, err := strconv.ParseInt(localPort, 10, 32) + if err != nil { + log.Fatal(err) + } + port.Port = int32(v) if _, err := strconv.Atoi(podPort); err != nil { // search a pods containers for the named port if namedPodPort, ok := portSearch(podPort, pod.Spec.Containers); ok { @@ -362,3 +375,17 @@ func portSearch(portName string, containers []v1.Container) (string, bool) { return "", false } + +// port exist port map return +func (svcFwd *ServiceFWD) getPortMap(port int32) string { + p := strconv.Itoa(int(port)) + if svcFwd.PortMap != nil { + for _, portMapInfo := range *svcFwd.PortMap { + if p == portMapInfo.TargetPort { + //use map port + return portMapInfo.SourcePort + } + } + } + return p +} From 6dae886581da3ea0cbc7af330bad9a3435ef3ea9 Mon Sep 17 00:00:00 2001 From: longbob <710190609@qq.com> Date: Sat, 6 Mar 2021 11:37:43 +0800 Subject: [PATCH 2/6] feat: add doc --- README.md | 2 ++ README_CN.md | 2 ++ cmd/kubefwd/kubefwd.go | 4 +++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0ee9470d..e27a5d08 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,8 @@ Examples: kubefwd svc -n default -n the-project kubefwd svc -n default -d internal.example.com kubefwd svc -n the-project -x prod-cluster + kubefwd svc -n the-project -p "8080:80,3309:3306" + kubefwd svc -n the-project -p "8080:80" Flags: diff --git a/README_CN.md b/README_CN.md index b9f10c8e..b82e3734 100644 --- a/README_CN.md +++ b/README_CN.md @@ -128,6 +128,8 @@ Examples: kubefwd svc -n default -n the-project kubefwd svc -n default -d internal.example.com kubefwd svc -n the-project -x prod-cluster + kubefwd svc -n the-project -p "8080:80,3309:3306" + kubefwd svc -n the-project -p "8080:80" Flags: diff --git a/cmd/kubefwd/kubefwd.go b/cmd/kubefwd/kubefwd.go index 0e50c018..6164604d 100644 --- a/cmd/kubefwd/kubefwd.go +++ b/cmd/kubefwd/kubefwd.go @@ -45,7 +45,9 @@ func newRootCmd() *cobra.Command { " kubefwd svc -n the-project\n" + " kubefwd svc -n the-project -l env=dev,component=api\n" + " kubefwd svc -n default -l \"app in (ws, api)\"\n" + - " kubefwd svc -n default -n the-project\n", + " kubefwd svc -n default -n the-project\n" + + " kubefwd svc -n the-project -p \"8080:80,3309:3306\"\n" + + " kubefwd svc -n the-project -p \"8080:80\"\n", Long: globalUsage, } From 214003919b7d8363f28d7c20fbd3873c7b95e115 Mon Sep 17 00:00:00 2001 From: longbob <710190609@qq.com> Date: Sun, 12 Sep 2021 16:16:24 +0800 Subject: [PATCH 3/6] feat: add --all-namespace option like kubectl --- README.md | 2 ++ README_CN.md | 2 ++ cmd/kubefwd/kubefwd.go | 3 ++- cmd/kubefwd/services/services.go | 24 ++++++++++++++++++++++-- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f584424c..e43aa293 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,7 @@ Examples: kubefwd svc -n default -d internal.example.com kubefwd svc -n the-project -x prod-cluster kubefwd svc -n the-project -m 80:8080 -m 443:1443 + kubefwd svc -n the-project --all-namespaces Flags: @@ -150,6 +151,7 @@ Flags: -n, --namespace strings Specify a namespace. Specify multiple namespaces by duplicating this argument. -l, --selector string Selector (label query) to filter on; supports '=', '==', '!=' (e.g. -l key1=value1,key2=value2) and 'in' (e.g. -l "app in (value1, value2)"). -m, --mapping strings Specify a port mapping. Specify multiple mapping by duplicating this argument. + --all-namespaces Enable --all-namespaces or -A option like kubectl. -v, --verbose Verbose output. ``` diff --git a/README_CN.md b/README_CN.md index 8aa04f7c..f01b42f8 100644 --- a/README_CN.md +++ b/README_CN.md @@ -129,6 +129,7 @@ Examples: kubefwd svc -n default -d internal.example.com kubefwd svc -n the-project -x prod-cluster kubefwd svc -n the-project -m 80:8080 -m 443:1443 + kubefwd svc -n the-project --all-namespaces Flags: @@ -140,6 +141,7 @@ Flags: -n, --namespace strings Specify a namespace. Specify multiple namespaces by duplicating this argument. -l, --selector string Selector (label query) to filter on; supports '=', '==', and '!=' (e.g. -l key1=value1,key2=value2). -m, --mapping strings Specify a port mapping. Specify multiple mapping by duplicating this argument. + --all-namespaces Enable --all-namespaces or -A option like kubectl. -v, --verbose Verbose output. ``` diff --git a/cmd/kubefwd/kubefwd.go b/cmd/kubefwd/kubefwd.go index 5cc8fec2..842bed60 100644 --- a/cmd/kubefwd/kubefwd.go +++ b/cmd/kubefwd/kubefwd.go @@ -47,7 +47,8 @@ func newRootCmd() *cobra.Command { " kubefwd svc -n the-project -f metadata.name=service-name\n" + " kubefwd svc -n default -l \"app in (ws, api)\"\n" + " kubefwd svc -n default -n the-project\n" + - " kubefwd svc -n the-project -m 80:8080 -m 443:1443\n", + " kubefwd svc -n the-project -m 80:8080 -m 443:1443\n" + + " kubefwd svc --all-namespaces", Long: globalUsage, } diff --git a/cmd/kubefwd/services/services.go b/cmd/kubefwd/services/services.go index 8a775cf2..e728f267 100644 --- a/cmd/kubefwd/services/services.go +++ b/cmd/kubefwd/services/services.go @@ -55,6 +55,7 @@ var contexts []string var verbose bool var domain string var mappings []string +var isAllNs bool func init() { // override error output from k8s.io/apimachinery/pkg/util/runtime @@ -71,6 +72,7 @@ func init() { Cmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "Verbose output.") Cmd.Flags().StringVarP(&domain, "domain", "d", "", "Append a pseudo domain name to generated host names.") Cmd.Flags().StringSliceVarP(&mappings, "mapping", "m", []string{}, "Specify a port mapping. Specify multiple mapping by duplicating this argument.") + Cmd.Flags().BoolVarP(&isAllNs, "all-namespaces", "A", false, "Enable --all-namespaces option like kubectl.") } @@ -85,10 +87,23 @@ var Cmd = &cobra.Command{ " kubefwd svc -n default -n the-project\n" + " kubefwd svc -n default -d internal.example.com\n" + " kubefwd svc -n the-project -x prod-cluster\n" + - " kubefwd svc -n the-project -m 80:8080 -m 443:1443\n", + " kubefwd svc -n the-project -m 80:8080 -m 443:1443\n" + + " kubefwd svc --all-namespaces", Run: runCmd, } +// SetAllNamespace Form V1Core get all namespace +func SetAllNamespace(clientSet *kubernetes.Clientset, options metav1.ListOptions, namespaces *[]string) *[]string { + nsList, err := clientSet.CoreV1().Namespaces().List(context.TODO(), options) + if err != nil { + log.Fatalf("Error get all namespaces by CoreV1: %s\n", err.Error()) + } + for _, ns := range nsList.Items { + *namespaces = append(*namespaces, ns.Name) + } + return namespaces +} + // checkConnection tests if you can connect to the cluster in your config, // and if you have the necessary permissions to use kubefwd. func checkConnection(clientSet *kubernetes.Clientset, namespaces []string) error { @@ -258,6 +273,11 @@ Try: log.Fatalf("Error creating k8s clientSet: %s\n", err.Error()) } + // if use --all-namespace ,from v1 api get all ns. + if isAllNs { + SetAllNamespace(clientSet, listOptions, &namespaces) + } + // check connectivity err = checkConnection(clientSet, namespaces) if err != nil { @@ -443,7 +463,7 @@ func (opts *NamespaceOpts) UpdateServiceHandler(_ interface{}, new interface{}) } } -// parse string port to PortMap +// ParsePortMap parse string port to PortMap func (opts *NamespaceOpts) ParsePortMap(mappings []string) *[]fwdservice.PortMap { var portList []fwdservice.PortMap if mappings == nil { From c2f927df97ffdcfa96afb4f20ec6bd52854e2357 Mon Sep 17 00:00:00 2001 From: longbob <710190609@qq.com> Date: Sun, 12 Sep 2021 22:05:40 +0800 Subject: [PATCH 4/6] fix: maybe use --all-namespace and -n --- cmd/kubefwd/services/services.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cmd/kubefwd/services/services.go b/cmd/kubefwd/services/services.go index e728f267..832cf74c 100644 --- a/cmd/kubefwd/services/services.go +++ b/cmd/kubefwd/services/services.go @@ -92,8 +92,8 @@ var Cmd = &cobra.Command{ Run: runCmd, } -// SetAllNamespace Form V1Core get all namespace -func SetAllNamespace(clientSet *kubernetes.Clientset, options metav1.ListOptions, namespaces *[]string) *[]string { +// setAllNamespace Form V1Core get all namespace +func setAllNamespace(clientSet *kubernetes.Clientset, options metav1.ListOptions, namespaces *[]string) { nsList, err := clientSet.CoreV1().Namespaces().List(context.TODO(), options) if err != nil { log.Fatalf("Error get all namespaces by CoreV1: %s\n", err.Error()) @@ -101,7 +101,6 @@ func SetAllNamespace(clientSet *kubernetes.Clientset, options metav1.ListOptions for _, ns := range nsList.Items { *namespaces = append(*namespaces, ns.Name) } - return namespaces } // checkConnection tests if you can connect to the cluster in your config, @@ -275,7 +274,10 @@ Try: // if use --all-namespace ,from v1 api get all ns. if isAllNs { - SetAllNamespace(clientSet, listOptions, &namespaces) + if len(namespaces) >= 1 { + log.Fatalf("Error --all-namespace not use -n.") + } + setAllNamespace(clientSet, listOptions, &namespaces) } // check connectivity From 3c3ee94397c1457386f3a897ff99234afb721c62 Mon Sep 17 00:00:00 2001 From: longbob <710190609@qq.com> Date: Wed, 15 Sep 2021 14:22:04 +0800 Subject: [PATCH 5/6] fix: maybe use --all-namespace and -n --- cmd/kubefwd/services/services.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/kubefwd/services/services.go b/cmd/kubefwd/services/services.go index 832cf74c..5cd5bc7e 100644 --- a/cmd/kubefwd/services/services.go +++ b/cmd/kubefwd/services/services.go @@ -274,7 +274,7 @@ Try: // if use --all-namespace ,from v1 api get all ns. if isAllNs { - if len(namespaces) >= 1 { + if len(namespaces) > 1 { log.Fatalf("Error --all-namespace not use -n.") } setAllNamespace(clientSet, listOptions, &namespaces) From 38fa53a6d5a6d6573d53e7d59967869297b6c95c Mon Sep 17 00:00:00 2001 From: longbob <710190609@qq.com> Date: Wed, 15 Sep 2021 14:52:35 +0800 Subject: [PATCH 6/6] fix: txt Error: cannot combine options --all-namespaces and -n. --- cmd/kubefwd/services/services.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/kubefwd/services/services.go b/cmd/kubefwd/services/services.go index 5cd5bc7e..4fcba77b 100644 --- a/cmd/kubefwd/services/services.go +++ b/cmd/kubefwd/services/services.go @@ -275,7 +275,7 @@ Try: // if use --all-namespace ,from v1 api get all ns. if isAllNs { if len(namespaces) > 1 { - log.Fatalf("Error --all-namespace not use -n.") + log.Fatalf("Error: cannot combine options --all-namespaces and -n.") } setAllNamespace(clientSet, listOptions, &namespaces) }