add goc list
This commit is contained in:
parent
2459e2b8bb
commit
17a55bb41c
27
cmd/list.go
Normal file
27
cmd/list.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/qiniu/goc/v2/pkg/client"
|
||||||
|
"github.com/qiniu/goc/v2/pkg/config"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var listCmd = &cobra.Command{
|
||||||
|
Use: "list",
|
||||||
|
Short: "Lists all the registered services",
|
||||||
|
Long: "Lists all the registered services",
|
||||||
|
Example: `
|
||||||
|
goc list [flags]
|
||||||
|
`,
|
||||||
|
|
||||||
|
Run: list,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
listCmd.Flags().StringVarP(&config.GocConfig.Host, "host", "", "127.0.0.1:7777", "specify the host of the goc server")
|
||||||
|
rootCmd.AddCommand(listCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func list(cmd *cobra.Command, args []string) {
|
||||||
|
client.NewWorker("http://" + config.GocConfig.Host).ListAgents()
|
||||||
|
}
|
3
go.mod
3
go.mod
@ -9,8 +9,11 @@ require (
|
|||||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.13 // indirect
|
github.com/mattn/go-isatty v0.0.13 // indirect
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d
|
||||||
|
github.com/olekukonko/tablewriter v0.0.5
|
||||||
|
github.com/sirupsen/logrus v1.7.0
|
||||||
github.com/spf13/cobra v1.1.3
|
github.com/spf13/cobra v1.1.3
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/tongjingran/copy v1.4.2
|
github.com/tongjingran/copy v1.4.2
|
||||||
go.uber.org/zap v1.17.0
|
go.uber.org/zap v1.17.0
|
||||||
golang.org/x/mod v0.4.2
|
golang.org/x/mod v0.4.2
|
||||||
|
5
go.sum
5
go.sum
@ -853,6 +853,8 @@ github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
|
|||||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
|
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||||
|
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
github.com/mattn/go-shellwords v1.0.9/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
github.com/mattn/go-shellwords v1.0.9/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||||
github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||||
github.com/mattn/go-sqlite3 v0.0.0-20160514122348-38ee283dabf1/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v0.0.0-20160514122348-38ee283dabf1/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
@ -932,6 +934,8 @@ github.com/octago/sflags v0.2.0/go.mod h1:G0bjdxh4qPRycF74a2B8pU36iTp9QHGx0w0dFZ
|
|||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||||
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
|
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
|
||||||
|
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||||
|
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
@ -1096,6 +1100,7 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
|
|||||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
|
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
|
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
|
||||||
|
118
pkg/client/client.go
Normal file
118
pkg/client/client.go
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/olekukonko/tablewriter"
|
||||||
|
"github.com/qiniu/goc/v2/pkg/log"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Action provides methods to contact with the covered agent under test
|
||||||
|
type Action interface {
|
||||||
|
ListAgents()
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// CoverAgentsListAPI list all the registered agents
|
||||||
|
CoverAgentsListAPI = "/v2/rpcagents"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ERROR_GOC_LIST = errors.New("goc list failed")
|
||||||
|
)
|
||||||
|
|
||||||
|
type client struct {
|
||||||
|
Host string
|
||||||
|
client *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// gocListAgents response of the list request
|
||||||
|
type gocListAgents struct {
|
||||||
|
Items []gocCoveredAgent `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// gocCoveredAgent represents a covered client
|
||||||
|
type gocCoveredAgent struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
RemoteIP string `json:"remoteip"`
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
CmdLine string `json:"cmdline"`
|
||||||
|
Pid string `json:"pid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWorker creates a worker to contact with host
|
||||||
|
func NewWorker(host string) Action {
|
||||||
|
_, err := url.ParseRequestURI(host)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Parse url %s failed, err: %v", host, err)
|
||||||
|
}
|
||||||
|
return &client{
|
||||||
|
Host: host,
|
||||||
|
client: http.DefaultClient,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) ListAgents() {
|
||||||
|
u := fmt.Sprintf("%s%s", c.Host, CoverAgentsListAPI)
|
||||||
|
_, body, err := c.do("GET", u, "", nil)
|
||||||
|
if err != nil && isNetworkError(err) {
|
||||||
|
_, body, err = c.do("GET", u, "", nil)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("%w: %v", ERROR_GOC_LIST, err)
|
||||||
|
log.Fatalf(err.Error())
|
||||||
|
}
|
||||||
|
agents := gocListAgents{}
|
||||||
|
err = json.Unmarshal(body, &agents)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("%w: json unmarshal failed: %v", ERROR_GOC_LIST, err)
|
||||||
|
log.Fatalf(err.Error())
|
||||||
|
}
|
||||||
|
table := tablewriter.NewWriter(os.Stdout)
|
||||||
|
table.SetHeader([]string{"ID", "RemoteIP", "Hostname", "Pid", "CMD"})
|
||||||
|
table.SetAutoFormatHeaders(false)
|
||||||
|
table.SetColumnAlignment([]int{tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER})
|
||||||
|
for _, agent := range agents.Items {
|
||||||
|
table.Append([]string{agent.Id, agent.RemoteIP, agent.Hostname, agent.Pid, agent.CmdLine})
|
||||||
|
}
|
||||||
|
table.Render()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) do(method, url, contentType string, body io.Reader) (*http.Response, []byte, error) {
|
||||||
|
req, err := http.NewRequest(method, url, body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if contentType != "" {
|
||||||
|
req.Header.Set("Content-Type", contentType)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
responseBody, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return res, nil, err
|
||||||
|
}
|
||||||
|
return res, responseBody, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNetworkError(err error) bool {
|
||||||
|
if err == io.EOF {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
_, ok := err.(net.Error)
|
||||||
|
return ok
|
||||||
|
}
|
60
pkg/client/client_test.go
Normal file
60
pkg/client/client_test.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func captureStdout(f func()) string {
|
||||||
|
r, w, err := os.Pipe()
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Fatal("os pipe fail")
|
||||||
|
}
|
||||||
|
stdout := os.Stdout
|
||||||
|
os.Stdout = w
|
||||||
|
defer func() {
|
||||||
|
os.Stdout = stdout
|
||||||
|
}()
|
||||||
|
|
||||||
|
f()
|
||||||
|
w.Close()
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
io.Copy(&buf, r)
|
||||||
|
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClientListAgents(t *testing.T) {
|
||||||
|
mockAgents := `{"items": [{"id": "testID", "remoteip": "1.1.1.1", "hostname": "testHost", "cmdline": "testCmd", "pid": "0"}]}`
|
||||||
|
mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Write([]byte(mockAgents))
|
||||||
|
}))
|
||||||
|
defer mockServer.Close()
|
||||||
|
|
||||||
|
c := NewWorker(mockServer.URL)
|
||||||
|
output := captureStdout(c.ListAgents)
|
||||||
|
expected := `+--------+----------+----------+-----+---------+
|
||||||
|
| ID | RemoteIP | Hostname | Pid | CMD |
|
||||||
|
+--------+----------+----------+-----+---------+
|
||||||
|
| testID | 1.1.1.1 | testHost | 0 | testCmd |
|
||||||
|
+--------+----------+----------+-----+---------+
|
||||||
|
`
|
||||||
|
assert.Equal(t, output, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClientDo(t *testing.T) {
|
||||||
|
c := &client{
|
||||||
|
client: http.DefaultClient,
|
||||||
|
}
|
||||||
|
_, _, err := c.do(" ", "http://127.0.0.1:7777", "", nil) // a invalid method
|
||||||
|
assert.Contains(t, err.Error(), "invalid method")
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user