mirror of
https://github.com/fleetdm/fleet
synced 2026-04-21 13:37:30 +00:00
Improve osquery perf (#2503)
* Improve osquery perf * Update dependencies * Embed template so this can be run from the root of the repo * Fix lint * Address review comments
This commit is contained in:
parent
4d6956b6cb
commit
825939e3dc
3 changed files with 250 additions and 106 deletions
|
|
@ -3,29 +3,131 @@ package main
|
|||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"embed"
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
//go:embed *.tmpl
|
||||
var templatesFS embed.FS
|
||||
|
||||
type Stats struct {
|
||||
errors int
|
||||
enrollments int
|
||||
distributedwrites int
|
||||
|
||||
l sync.Mutex
|
||||
}
|
||||
|
||||
func (s *Stats) RecordStats(errors int, enrollments int, distributedwrites int) {
|
||||
s.l.Lock()
|
||||
defer s.l.Unlock()
|
||||
|
||||
s.errors += errors
|
||||
s.enrollments += enrollments
|
||||
s.distributedwrites += distributedwrites
|
||||
}
|
||||
|
||||
func (s *Stats) Log() {
|
||||
s.l.Lock()
|
||||
defer s.l.Unlock()
|
||||
|
||||
fmt.Printf(
|
||||
"%s :: error rate: %.2f \t enrollments: %d \t writes: %d\n",
|
||||
time.Now().String(),
|
||||
float64(s.errors)/float64(s.enrollments),
|
||||
s.enrollments,
|
||||
s.distributedwrites,
|
||||
)
|
||||
}
|
||||
|
||||
func (s *Stats) runLoop() {
|
||||
ticker := time.Tick(10 * time.Second)
|
||||
for range ticker {
|
||||
s.Log()
|
||||
}
|
||||
}
|
||||
|
||||
type NodeKeyManager struct {
|
||||
filepath string
|
||||
|
||||
l sync.Mutex
|
||||
nodekeys []string
|
||||
}
|
||||
|
||||
func (n *NodeKeyManager) LoadKeys() {
|
||||
if n.filepath == "" {
|
||||
return
|
||||
}
|
||||
|
||||
n.l.Lock()
|
||||
defer n.l.Unlock()
|
||||
|
||||
data, err := os.ReadFile(n.filepath)
|
||||
if err != nil {
|
||||
fmt.Println("WARNING (ignore if creating a new node key file): error loading nodekey file:", err)
|
||||
return
|
||||
}
|
||||
n.nodekeys = strings.Split(string(data), "\n")
|
||||
fmt.Printf("loaded %d node keys\n", len(n.nodekeys))
|
||||
}
|
||||
|
||||
func (n *NodeKeyManager) Get(i int) string {
|
||||
n.l.Lock()
|
||||
defer n.l.Unlock()
|
||||
|
||||
if len(n.nodekeys) > i {
|
||||
return n.nodekeys[i]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (n *NodeKeyManager) Add(nodekey string) {
|
||||
if n.filepath == "" {
|
||||
return
|
||||
}
|
||||
|
||||
// we lock just to make sure we write one at a time
|
||||
n.l.Lock()
|
||||
defer n.l.Unlock()
|
||||
|
||||
f, err := os.OpenFile(n.filepath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
|
||||
if err != nil {
|
||||
fmt.Println("error opening nodekey file:", err.Error())
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
if _, err := f.WriteString(nodekey + "\n"); err != nil {
|
||||
fmt.Println("error writing nodekey file:", err)
|
||||
}
|
||||
}
|
||||
|
||||
type Agent struct {
|
||||
ServerAddress string
|
||||
EnrollSecret string
|
||||
NodeKey string
|
||||
UUID string
|
||||
FastClient fasthttp.Client
|
||||
Client http.Client
|
||||
ConfigInterval time.Duration
|
||||
QueryInterval time.Duration
|
||||
Templates *template.Template
|
||||
strings map[string]string
|
||||
Stats *Stats
|
||||
NodeKeyManager *NodeKeyManager
|
||||
}
|
||||
|
||||
func NewAgent(serverAddress, enrollSecret string, templates *template.Template, configInterval, queryInterval time.Duration) *Agent {
|
||||
|
|
@ -39,8 +141,11 @@ func NewAgent(serverAddress, enrollSecret string, templates *template.Template,
|
|||
ConfigInterval: configInterval,
|
||||
QueryInterval: queryInterval,
|
||||
UUID: uuid.New().String(),
|
||||
Client: http.Client{Transport: transport},
|
||||
strings: make(map[string]string),
|
||||
FastClient: fasthttp.Client{
|
||||
TLSConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
},
|
||||
Client: http.Client{Transport: transport},
|
||||
strings: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -52,8 +157,10 @@ type distributedReadResponse struct {
|
|||
Queries map[string]string `json:"queries"`
|
||||
}
|
||||
|
||||
func (a *Agent) runLoop() {
|
||||
a.Enroll()
|
||||
func (a *Agent) runLoop(i int, onlyAlreadyEnrolled bool) {
|
||||
if err := a.Enroll(i, onlyAlreadyEnrolled); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
a.Config()
|
||||
resp, err := a.DistributedRead()
|
||||
|
|
@ -84,6 +191,89 @@ func (a *Agent) runLoop() {
|
|||
}
|
||||
}
|
||||
|
||||
func (a *Agent) waitingDo(req *fasthttp.Request, res *fasthttp.Response) {
|
||||
err := a.FastClient.Do(req, res)
|
||||
for err != nil || res.StatusCode() != http.StatusOK {
|
||||
fmt.Println(err, res.StatusCode())
|
||||
a.Stats.RecordStats(1, 0, 0)
|
||||
<-time.Tick(time.Duration(rand.Intn(120)+1) * time.Second)
|
||||
err = fasthttp.Do(req, res)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Agent) Enroll(i int, onlyAlreadyEnrolled bool) error {
|
||||
a.NodeKey = a.NodeKeyManager.Get(i)
|
||||
if a.NodeKey != "" {
|
||||
a.Stats.RecordStats(0, 1, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
if onlyAlreadyEnrolled {
|
||||
return fmt.Errorf("not enrolled")
|
||||
}
|
||||
|
||||
var body bytes.Buffer
|
||||
if err := a.Templates.ExecuteTemplate(&body, "enroll", a); err != nil {
|
||||
log.Println("execute template:", err)
|
||||
return err
|
||||
}
|
||||
|
||||
req := fasthttp.AcquireRequest()
|
||||
req.SetBody(body.Bytes())
|
||||
req.Header.SetMethod("POST")
|
||||
req.Header.SetContentType("application/json")
|
||||
req.Header.Add("User-Agent", "osquery/4.6.0")
|
||||
req.SetRequestURI(a.ServerAddress + "/api/v1/osquery/enroll")
|
||||
res := fasthttp.AcquireResponse()
|
||||
|
||||
a.waitingDo(req, res)
|
||||
|
||||
fasthttp.ReleaseRequest(req)
|
||||
defer fasthttp.ReleaseResponse(res)
|
||||
|
||||
if res.StatusCode() != http.StatusOK {
|
||||
log.Println("enroll status:", res.StatusCode())
|
||||
return fmt.Errorf("status code: %d", res.StatusCode())
|
||||
}
|
||||
|
||||
var parsedResp enrollResponse
|
||||
if err := json.Unmarshal(res.Body(), &parsedResp); err != nil {
|
||||
log.Println("json parse:", err)
|
||||
return err
|
||||
}
|
||||
|
||||
a.NodeKey = parsedResp.NodeKey
|
||||
a.Stats.RecordStats(0, 1, 0)
|
||||
|
||||
a.NodeKeyManager.Add(a.NodeKey)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Agent) Config() {
|
||||
body := bytes.NewBufferString(`{"node_key": "` + a.NodeKey + `"}`)
|
||||
|
||||
req := fasthttp.AcquireRequest()
|
||||
req.SetBody(body.Bytes())
|
||||
req.Header.SetMethod("POST")
|
||||
req.Header.SetContentType("application/json")
|
||||
req.Header.Add("User-Agent", "osquery/4.6.0")
|
||||
req.SetRequestURI(a.ServerAddress + "/api/v1/osquery/config")
|
||||
res := fasthttp.AcquireResponse()
|
||||
|
||||
a.waitingDo(req, res)
|
||||
|
||||
fasthttp.ReleaseRequest(req)
|
||||
defer fasthttp.ReleaseResponse(res)
|
||||
|
||||
if res.StatusCode() != http.StatusOK {
|
||||
log.Println("config status:", res.StatusCode())
|
||||
return
|
||||
}
|
||||
|
||||
// No need to read the config body
|
||||
}
|
||||
|
||||
const stringVals = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_."
|
||||
|
||||
func (a *Agent) randomString(n int) string {
|
||||
|
|
@ -104,94 +294,24 @@ func (a *Agent) CachedString(key string) string {
|
|||
return val
|
||||
}
|
||||
|
||||
func (a *Agent) Enroll() {
|
||||
var body bytes.Buffer
|
||||
if err := a.Templates.ExecuteTemplate(&body, "enroll", a); err != nil {
|
||||
log.Println("execute template:", err)
|
||||
return
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", a.ServerAddress+"/api/v1/osquery/enroll", &body)
|
||||
if err != nil {
|
||||
log.Println("create request:", err)
|
||||
return
|
||||
}
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
req.Header.Add("Accept", "application/json")
|
||||
req.Header.Add("User-Agent", "osquery/4.6.0")
|
||||
|
||||
resp, err := a.Client.Do(req)
|
||||
if err != nil {
|
||||
log.Println("do request:", err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
log.Println("status:", resp.Status)
|
||||
return
|
||||
}
|
||||
|
||||
var parsedResp enrollResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&parsedResp); err != nil {
|
||||
log.Println("json parse:", err)
|
||||
return
|
||||
}
|
||||
|
||||
a.NodeKey = parsedResp.NodeKey
|
||||
}
|
||||
|
||||
func (a *Agent) Config() {
|
||||
body := bytes.NewBufferString(`{"node_key": "` + a.NodeKey + `"}`)
|
||||
|
||||
req, err := http.NewRequest("POST", a.ServerAddress+"/api/v1/osquery/config", body)
|
||||
if err != nil {
|
||||
log.Println("create config request:", err)
|
||||
return
|
||||
}
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
req.Header.Add("Accept", "application/json")
|
||||
req.Header.Add("User-Agent", "osquery/4.6.0")
|
||||
|
||||
resp, err := a.Client.Do(req)
|
||||
if err != nil {
|
||||
log.Println("do config request:", err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
log.Println("config status:", resp.Status)
|
||||
return
|
||||
}
|
||||
|
||||
// No need to read the config body
|
||||
}
|
||||
|
||||
func (a *Agent) DistributedRead() (*distributedReadResponse, error) {
|
||||
body := bytes.NewBufferString(`{"node_key": "` + a.NodeKey + `"}`)
|
||||
|
||||
req, err := http.NewRequest("POST", a.ServerAddress+"/api/v1/osquery/distributed/read", body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create distributed read request: %s", err)
|
||||
}
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
req.Header.Add("Accept", "application/json")
|
||||
req := fasthttp.AcquireRequest()
|
||||
req.SetBody([]byte(`{"node_key": "` + a.NodeKey + `"}`))
|
||||
req.Header.SetMethod("POST")
|
||||
req.Header.SetContentType("application/json")
|
||||
req.Header.Add("User-Agent", "osquery/4.6.0")
|
||||
req.SetRequestURI(a.ServerAddress + "/api/v1/osquery/distributed/read")
|
||||
res := fasthttp.AcquireResponse()
|
||||
|
||||
resp, err := a.Client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("do distributed read request: %s", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
a.waitingDo(req, res)
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("distributed read status: %s", resp.Status)
|
||||
}
|
||||
fasthttp.ReleaseRequest(req)
|
||||
defer fasthttp.ReleaseResponse(res)
|
||||
|
||||
var parsedResp distributedReadResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&parsedResp); err != nil {
|
||||
return nil, fmt.Errorf("json parse distributed read response: %s", err)
|
||||
if err := json.Unmarshal(res.Body(), &parsedResp); err != nil {
|
||||
log.Println("json parse:", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &parsedResp, nil
|
||||
|
|
@ -228,26 +348,20 @@ func (a *Agent) DistributedWrite(queries map[string]string) {
|
|||
json.NewEncoder(&body).Encode(req)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", a.ServerAddress+"/api/v1/osquery/distributed/write", &body)
|
||||
if err != nil {
|
||||
log.Println("create distributed write request:", err)
|
||||
return
|
||||
}
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
req.Header.Add("Accept", "application/json")
|
||||
req := fasthttp.AcquireRequest()
|
||||
req.SetBody(body.Bytes())
|
||||
req.Header.SetMethod("POST")
|
||||
req.Header.SetContentType("application/json")
|
||||
req.Header.Add("User-Agent", "osquery/4.6.0")
|
||||
req.SetRequestURI(a.ServerAddress + "/api/v1/osquery/distributed/write")
|
||||
res := fasthttp.AcquireResponse()
|
||||
|
||||
resp, err := a.Client.Do(req)
|
||||
if err != nil {
|
||||
log.Println("do distributed write request:", err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
a.waitingDo(req, res)
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
log.Println("distributed write status:", resp.Status)
|
||||
return
|
||||
}
|
||||
fasthttp.ReleaseRequest(req)
|
||||
defer fasthttp.ReleaseResponse(res)
|
||||
|
||||
a.Stats.RecordStats(0, 0, 1)
|
||||
|
||||
// No need to read the distributed write body
|
||||
}
|
||||
|
|
@ -260,23 +374,37 @@ func main() {
|
|||
startPeriod := flag.Duration("start_period", 10*time.Second, "Duration to spread start of hosts over")
|
||||
configInterval := flag.Duration("config_interval", 1*time.Minute, "Interval for config requests")
|
||||
queryInterval := flag.Duration("query_interval", 10*time.Second, "Interval for live query requests")
|
||||
onlyAlreadyEnrolled := flag.Bool("only_already_enrolled", false, "Only start agents that are already enrolled")
|
||||
nodeKeyFile := flag.String("node_key_file", "", "File with node keys to use")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
rand.Seed(*randSeed)
|
||||
|
||||
tmpl, err := template.ParseGlob("*.tmpl")
|
||||
tmpl, err := template.ParseFS(templatesFS, "*.tmpl")
|
||||
if err != nil {
|
||||
log.Fatal("parse templates: ", err)
|
||||
}
|
||||
|
||||
// Spread starts over the interval to prevent thunering herd
|
||||
sleepTime := *startPeriod / time.Duration(*hostCount)
|
||||
|
||||
stats := &Stats{}
|
||||
go stats.runLoop()
|
||||
|
||||
nodeKeyManager := &NodeKeyManager{}
|
||||
if nodeKeyFile != nil {
|
||||
nodeKeyManager.filepath = *nodeKeyFile
|
||||
nodeKeyManager.LoadKeys()
|
||||
}
|
||||
|
||||
var agents []*Agent
|
||||
for i := 0; i < *hostCount; i++ {
|
||||
a := NewAgent(*serverURL, *enrollSecret, tmpl, *configInterval, *queryInterval)
|
||||
a.Stats = stats
|
||||
a.NodeKeyManager = nodeKeyManager
|
||||
agents = append(agents, a)
|
||||
go a.runLoop()
|
||||
go a.runLoop(i, onlyAlreadyEnrolled != nil && *onlyAlreadyEnrolled)
|
||||
time.Sleep(sleepTime)
|
||||
}
|
||||
|
||||
|
|
|
|||
3
go.mod
3
go.mod
|
|
@ -69,7 +69,8 @@ require (
|
|||
github.com/theupdateframework/go-tuf v0.0.0-20201230183259-aee6270feb55
|
||||
github.com/throttled/throttled/v2 v2.8.0
|
||||
github.com/urfave/cli/v2 v2.3.0
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
|
||||
github.com/valyala/fasthttp v1.31.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c
|
||||
golang.org/x/tools v0.1.5 // indirect
|
||||
google.golang.org/grpc v1.38.0
|
||||
|
|
|
|||
15
go.sum
15
go.sum
|
|
@ -93,6 +93,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
|
|||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E=
|
||||
github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
|
|
@ -319,6 +321,8 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
|
|||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 h1:23T5iq8rbUYlhpt5DB4XJkc6BU31uODLD1o1gKvZmD0=
|
||||
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4=
|
||||
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM=
|
||||
|
|
@ -515,6 +519,8 @@ github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
|
|||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.11.0/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.13.4 h1:0zhec2I8zGnjWcKyLl6i3gPqKANCCn5e9xmviEEeX6s=
|
||||
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/kolide/launcher v0.0.0-20180427153757-cb412b945cf7 h1:6E3WfyhTsIOTL7aP+TnLnh3cH2y6bd5mL0ssuYuJ8xo=
|
||||
github.com/kolide/launcher v0.0.0-20180427153757-cb412b945cf7/go.mod h1:EGgVr4L+g8f041t5OrmY/KV431GlIWhBxsHsT+qc2Mg=
|
||||
github.com/kolide/osquery-go v0.0.0-20190904034940-a74aa860032d h1:alVW+rIOMejarlhjLl4AYaQaGAyfvIUDg9NyyKRhSek=
|
||||
|
|
@ -836,10 +842,14 @@ github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
|
|||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/uudashr/gocognit v1.0.1 h1:MoG2fZ0b/Eo7NXoIwCVFLG5JED3qgQz5/NEE+rOsjPs=
|
||||
github.com/uudashr/gocognit v1.0.1/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA=
|
||||
github.com/valyala/fasthttp v1.31.0 h1:lrauRLII19afgCs2fnWRJ4M5IkV0lo2FqA61uGkNBfE=
|
||||
github.com/valyala/fasthttp v1.31.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus=
|
||||
github.com/valyala/quicktemplate v1.6.3/go.mod h1:fwPzK2fHuYEODzJ9pkw0ipCPNHZ2tD5KW4lOuSdPKzY=
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
||||
github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI=
|
||||
|
|
@ -899,6 +909,8 @@ golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPh
|
|||
golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
|
@ -984,6 +996,8 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd
|
|||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I=
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
|
@ -1077,6 +1091,7 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
|
|
|
|||
Loading…
Reference in a new issue