diff --git a/app/dubboctl/cmd/registry.go b/app/dubboctl/cmd/registry.go new file mode 100644 index 000000000..5083b1900 --- /dev/null +++ b/app/dubboctl/cmd/registry.go @@ -0,0 +1,96 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You 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. + +package cmd + +import ( + "github.com/spf13/cobra" + + "github.com/apache/dubbo-kubernetes/app/dubboctl/internal/registry/zk" +) + +func addRegistryCmd(rootCmd *cobra.Command) { + addZkRegistryCmd(rootCmd) +} + +func addZkRegistryCmd(rootCmd *cobra.Command) { + zkRegistryCmd := &cobra.Command{ + Use: "zk", + Short: "Commands related to zookeeper registry", + Long: "Commands help user to operate zookeeper registry", + } + addZkLsCmd(zkRegistryCmd) + rootCmd.AddCommand(zkRegistryCmd) +} + +func addZkLsCmd(zkRegistryCmd *cobra.Command) { + zkAddr := "127.0.0.1:2181" + + lsCmd := &cobra.Command{ + Use: "ls", + Short: "List services or instances", + Long: "List all services or list instances of a service\n\n" + + "Usage:\n\n" + + "- List all services\n" + + " dubboctl zk ls\n\n" + + "- List instances of a service\n" + + " dubboctl zk ls [APP_NAME] [SERVICE_NAME]\n\n" + + "Example:\n\n" + + "- List all services\n" + + " dubboctl zk ls\n\n" + + "- List instances of a service\n" + + " dubboctl zk ls dubbo com.apache.dubbo.sample.basic.IGreeter\n", + Args: cobra.MaximumNArgs(2), + Run: func(cmd *cobra.Command, args []string) { + // if no args, list all services + if len(args) == 0 { + registry, err := zk.NewZkRegistry(zkAddr) + if err != nil { + cmd.Println(err) + return + } + services, err := registry.ListServices(nil) + if err != nil { + cmd.Println(err) + return + } + for _, service := range services { + cmd.Println(service) + } + return + } + if len(args) == 2 { + registry, err := zk.NewZkRegistry(zkAddr) + if err != nil { + cmd.Println(err) + return + } + instances, err := registry.ListInstances(nil, args[0], args[1]) + if err != nil { + cmd.Println(err) + return + } + for _, instance := range instances { + cmd.Println(instance) + } + return + } + cmd.Println("Invalid args, you can use `dubboctl zk ls` to list all services or use `dubboctl zk ls [APP_NAME] [SERVICE_NAME]` to list instances of a service") + }, + } + + lsCmd.Flags().StringVarP(&zkAddr, "addr", "a", "127.0.0.1:2181", "zookeeper address, if has multiple address, use comma to separate") + zkRegistryCmd.AddCommand(lsCmd) +} diff --git a/app/dubboctl/cmd/root.go b/app/dubboctl/cmd/root.go index 8744d5f49..cc3109063 100644 --- a/app/dubboctl/cmd/root.go +++ b/app/dubboctl/cmd/root.go @@ -82,6 +82,7 @@ func addSubCommands(rootCmd *cobra.Command, newClient ClientFactory) { addManifest(rootCmd) addProfile(rootCmd) addDashboard(rootCmd) + addRegistryCmd(rootCmd) } // bindFunc which conforms to the cobra PreRunE method signature diff --git a/app/dubboctl/internal/registry/registry.go b/app/dubboctl/internal/registry/registry.go new file mode 100644 index 000000000..b19b46734 --- /dev/null +++ b/app/dubboctl/internal/registry/registry.go @@ -0,0 +1,34 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You 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. + +package registry + +import "context" + +// Registry is the interface that wraps the basic methods of registry. +type Registry interface { + // ListServices list all services + ListServices(ctx *context.Context) ([]string, error) + // ListInstances list all instances of the service + ListInstances(ctx *context.Context, applicationName string, serviceName string) ([]string, error) + + // TODO add rules +} + +type Service struct { + Ip string + Port int + // TODO add more info? +} diff --git a/app/dubboctl/internal/registry/zk/zk.go b/app/dubboctl/internal/registry/zk/zk.go new file mode 100644 index 000000000..45e61ab12 --- /dev/null +++ b/app/dubboctl/internal/registry/zk/zk.go @@ -0,0 +1,107 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You 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. + +package zk + +import ( + "context" + "fmt" + "net/url" + "strings" + "time" + + "github.com/dubbogo/go-zookeeper/zk" + + "github.com/apache/dubbo-kubernetes/app/dubboctl/internal/registry" +) + +type zkRegistry struct { + client *zk.Conn +} + +// NewZkRegistry creates a new zookeeper registry +func NewZkRegistry(addr string) (registry.Registry, error) { + addrList := strings.Split(addr, ",") + conn, _, err := zk.Connect(addrList, 5*time.Second, zk.WithLogInfo(false)) + if err != nil { + return nil, err + } + return &zkRegistry{ + client: conn, + }, nil +} + +func (z *zkRegistry) ListServices(ctx *context.Context) ([]string, error) { + children, _, err := z.client.Children("/") + if err != nil { + return nil, err + } + // if contain provider, then it is a service + var services []string + for _, firstChild := range children { + // first level is application name, like "dubbo" + secondChildren, _, err := z.client.Children("/" + firstChild) + if err != nil { + continue + } + for _, secondChild := range secondChildren { + // second level is service name, like "com.example.user.UserProvider" + thirdChildren, _, err := z.client.Children("/" + firstChild + "/" + secondChild) + if err != nil { + continue + } + // third level is "providers" or "consumers" + for _, thirdChild := range thirdChildren { + if strings.Contains(thirdChild, "providers") { + seviceName := fmt.Sprintf("application: %s, service: %s", firstChild, secondChild) + services = append(services, seviceName) + break + } + } + } + + } + return services, nil +} + +func (z *zkRegistry) ListInstances(ctx *context.Context, applicationName string, serviceName string) ([]string, error) { + // get all instances of the service + children, _, err := z.client.Children("/" + applicationName + "/" + serviceName) + if err != nil { + return nil, err + } + // get all instances + var instances []string + for _, child := range children { + if strings.EqualFold(child, "providers") { + serviceInstance, _, err := z.client.Children("/" + applicationName + "/" + serviceName + "/" + child) + if err != nil { + continue + } + for _, instance := range serviceInstance { + queryUnescape, err := url.QueryUnescape(instance) + if err != nil { + continue + } + u, err := url.Parse(queryUnescape) + if err != nil { + continue + } + instances = append(instances, u.Host) + } + } + } + return instances, nil +} diff --git a/go.mod b/go.mod index 8f2b46f44..d6eb9c122 100644 --- a/go.mod +++ b/go.mod @@ -61,6 +61,7 @@ require ( github.com/kylelemons/godebug v1.1.0 github.com/mattbaird/jsonpatch v0.0.0-20230413205102-771768614e91 github.com/moby/term v0.5.0 + github.com/nacos-group/nacos-sdk-go v1.0.9 github.com/onsi/gomega v1.27.10 github.com/ory/viper v1.7.5 github.com/pkg/errors v0.9.1 @@ -256,6 +257,8 @@ require ( github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/leodido/go-urn v1.2.4 // indirect + github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f // indirect + github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect github.com/lib/pq v1.10.9 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect @@ -327,6 +330,7 @@ require ( github.com/tidwall/pretty v1.2.0 // indirect github.com/tklauser/go-sysconf v0.3.10 // indirect github.com/tklauser/numcpus v0.4.0 // indirect + github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect github.com/uber/jaeger-lib v2.4.1+incompatible // indirect diff --git a/go.sum b/go.sum index ae70f39a6..9d34d7c90 100644 --- a/go.sum +++ b/go.sum @@ -798,6 +798,7 @@ github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJ github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= +github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 h1:Ghm4eQYC0nEPnSJdVkTrXpu9KtoVCSo1hg7mtI7G9KU= github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239/go.mod h1:Gdwt2ce0yfBxPvZrHkprdPPTTS3N5rwmLE8T22KBXlw= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -1211,6 +1212,7 @@ github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aW github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jdxcode/netrc v1.0.0 h1:tJR3fyzTcjDi22t30pCdpOT8WJ5gb32zfYE1hFNCOjk= github.com/jdxcode/netrc v1.0.0/go.mod h1:Zi/ZFkEqFHTm7qkjyNJjaWH4LQA9LQhGJyF0lTYGpxw= +github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= @@ -1307,8 +1309,11 @@ github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6Fm github.com/leodido/go-urn v1.2.2/go.mod h1:kUaIbLZWttglzwNuG0pgsh5vuV6u2YcGBYz1hIPjtOQ= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 h1:0iQektZGS248WXmGIYOwRXSQhD4qn3icjMpuxwO7qlo= github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570/go.mod h1:BLt8L9ld7wVsvEWQbuLrUZnCMnUmLZ+CGDzKtclrTlE= +github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f h1:sgUSP4zdTUZYZgAGGtN5Lxk92rK+JUFOwf+FT99EEI4= github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f/go.mod h1:UGmTpUd3rjbtfIpwAPrcfmGf/Z1HS95TATB+m57TPB8= +github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 h1:Bvq8AziQ5jFF4BHGAEDSqwPW1NJS3XshxbRCxtjFAZc= github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042/go.mod h1:TPpsiPUEh0zFL1Snz4crhMlBe60PYxRHr5oFF3rRYg0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= @@ -1445,6 +1450,7 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nacos-group/nacos-sdk-go v1.0.8/go.mod h1:hlAPn3UdzlxIlSILAyOXKxjFSvDJ9oLzTJ9hLAK1KzA= +github.com/nacos-group/nacos-sdk-go v1.0.9 h1:sMvrp6tZj4LdhuHRsS4GCqASB81k3pjmT2ykDQQpwt0= github.com/nacos-group/nacos-sdk-go v1.0.9/go.mod h1:hlAPn3UdzlxIlSILAyOXKxjFSvDJ9oLzTJ9hLAK1KzA= github.com/nacos-group/nacos-sdk-go/v2 v2.1.2/go.mod h1:ys/1adWeKXXzbNWfRNbaFlX/t6HVLWdpsNDvmoWTw0g= github.com/nacos-group/nacos-sdk-go/v2 v2.2.2 h1:FI+7vr1fvCA4jbgx36KezmP3zlU/WoP/7wAloaSd1Ew= @@ -1732,6 +1738,7 @@ github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tebeka/strftime v0.1.3 h1:5HQXOqWKYRFfNyBMNVc9z5+QzuBtIXy03psIhtdJYto= github.com/tebeka/strftime v0.1.3/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIUJUJH6XQ= github.com/tetratelabs/wazero v1.2.1 h1:J4X2hrGzJvt+wqltuvcSjHQ7ujQxA9gb6PeMs4qlUWs= github.com/tetratelabs/wazero v1.2.1/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ= @@ -1761,6 +1768,7 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1 github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= +github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3 h1:kF/7m/ZU+0D4Jj5eZ41Zm3IH/J8OElK1Qtd7tVKAwLk= github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3/go.mod h1:QDlpd3qS71vYtakd2hmdpqhJ9nwv6mD6A30bQ1BPBFE= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=