Compare commits
15 Commits
3eaad85453
...
ds-live
| Author | SHA1 | Date | |
|---|---|---|---|
| 63727343ee | |||
| 19a4ff103f | |||
| 106aa68529 | |||
| cf4a2a3ea5 | |||
| 965d6fa5b9 | |||
| 0ed48e0de7 | |||
| d8ccbf209c | |||
| 5f68795185 | |||
| 3ab055008c | |||
| 71e80d2908 | |||
| 12a0f9d2b1 | |||
| 016f459252 | |||
| 030fa658f5 | |||
| 3c96921703 | |||
| 6f444e0187 |
183
client/client.go
183
client/client.go
@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
@ -21,6 +22,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/djherbis/times"
|
||||||
"repositories.action2quare.com/ayo/gocommon"
|
"repositories.action2quare.com/ayo/gocommon"
|
||||||
"repositories.action2quare.com/ayo/gocommon/flagx"
|
"repositories.action2quare.com/ayo/gocommon/flagx"
|
||||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
@ -29,6 +31,9 @@ import (
|
|||||||
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type runcommand struct {
|
type runcommand struct {
|
||||||
@ -42,6 +47,7 @@ type clientConfig struct {
|
|||||||
HttpAddress string `json:"http_server_address"`
|
HttpAddress string `json:"http_server_address"`
|
||||||
StorageRoot string `json:"storage_path"`
|
StorageRoot string `json:"storage_path"`
|
||||||
MetricNamespace string `json:"metric_namespace"`
|
MetricNamespace string `json:"metric_namespace"`
|
||||||
|
MetricPipeName string `json:"metric_pipe"`
|
||||||
ConstLabels map[string]string `json:"metric_const_labels"`
|
ConstLabels map[string]string `json:"metric_const_labels"`
|
||||||
Autorun map[string]runcommand `json:"autorun"`
|
Autorun map[string]runcommand `json:"autorun"`
|
||||||
}
|
}
|
||||||
@ -68,6 +74,7 @@ func loadClientConfig() (clientConfig, error) {
|
|||||||
type HoustonClient interface {
|
type HoustonClient interface {
|
||||||
Shutdown()
|
Shutdown()
|
||||||
Start()
|
Start()
|
||||||
|
MetricHandler() http.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
var seq = int32(1)
|
var seq = int32(1)
|
||||||
@ -95,6 +102,13 @@ func (pm *procmeta) setState(s protos.ProcessState) {
|
|||||||
atomic.StoreInt32(&pm.state, int32(s))
|
atomic.StoreInt32(&pm.state, int32(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type uploadRequest struct {
|
||||||
|
filePath string
|
||||||
|
name string
|
||||||
|
version string
|
||||||
|
uploadedFileName string
|
||||||
|
}
|
||||||
|
|
||||||
type houstonClient struct {
|
type houstonClient struct {
|
||||||
childProcs []*procmeta
|
childProcs []*procmeta
|
||||||
extraMetrics unsafe.Pointer // map[string]float32
|
extraMetrics unsafe.Pointer // map[string]float32
|
||||||
@ -104,12 +118,14 @@ type houstonClient struct {
|
|||||||
operationChan chan *protos.OperationQueryResponse
|
operationChan chan *protos.OperationQueryResponse
|
||||||
exitChan chan *exec.Cmd
|
exitChan chan *exec.Cmd
|
||||||
clientChan chan *grpc.ClientConn
|
clientChan chan *grpc.ClientConn
|
||||||
|
uploadChan chan uploadRequest
|
||||||
timestamp string
|
timestamp string
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
config clientConfig
|
config clientConfig
|
||||||
version string
|
version string
|
||||||
standalone bool
|
standalone bool
|
||||||
siblingProcIndex map[string]uint64
|
siblingProcIndex map[string]uint64
|
||||||
|
registry *prometheus.Registry
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshal[T any](val *T, src map[string]string) {
|
func unmarshal[T any](val *T, src map[string]string) {
|
||||||
@ -286,7 +302,9 @@ func NewClient(standalone bool) (HoustonClient, error) {
|
|||||||
timestamp: exefi.ModTime().String(),
|
timestamp: exefi.ModTime().String(),
|
||||||
version: string(ver),
|
version: string(ver),
|
||||||
standalone: standalone,
|
standalone: standalone,
|
||||||
|
uploadChan: make(chan uploadRequest, 100),
|
||||||
siblingProcIndex: make(map[string]uint64),
|
siblingProcIndex: make(map[string]uint64),
|
||||||
|
registry: prometheus.NewRegistry(),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
@ -317,6 +335,7 @@ func NewClient(standalone bool) (HoustonClient, error) {
|
|||||||
|
|
||||||
case newClient := <-hc.clientChan:
|
case newClient := <-hc.clientChan:
|
||||||
op = protos.NewOperationClient(newClient)
|
op = protos.NewOperationClient(newClient)
|
||||||
|
op.Refresh(context.Background(), hc.makeOperationQueryRequest())
|
||||||
|
|
||||||
case exited := <-exitChan:
|
case exited := <-exitChan:
|
||||||
var newprocs []*procmeta
|
var newprocs []*procmeta
|
||||||
@ -331,11 +350,15 @@ func NewClient(standalone bool) (HoustonClient, error) {
|
|||||||
proc.cmd.Process.Release()
|
proc.cmd.Process.Release()
|
||||||
|
|
||||||
if proc.isState(protos.ProcessState_Restart) {
|
if proc.isState(protos.ProcessState_Restart) {
|
||||||
hc.startChildProcess(&shared.StartProcessRequest{
|
if err := hc.startChildProcess(&shared.StartProcessRequest{
|
||||||
Version: proc.version,
|
Version: proc.version,
|
||||||
Name: proc.name,
|
Name: proc.name,
|
||||||
Args: proc.args,
|
Args: proc.args,
|
||||||
}, op)
|
}); err != nil {
|
||||||
|
logger.ErrorWithCallStack(err)
|
||||||
|
} else {
|
||||||
|
op.Refresh(context.Background(), hc.makeOperationQueryRequest())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}(proc)
|
}(proc)
|
||||||
}
|
}
|
||||||
@ -422,8 +445,10 @@ func NewClient(standalone bool) (HoustonClient, error) {
|
|||||||
case shared.Start:
|
case shared.Start:
|
||||||
var sr shared.StartProcessRequest
|
var sr shared.StartProcessRequest
|
||||||
unmarshal(&sr, resp.Args)
|
unmarshal(&sr, resp.Args)
|
||||||
if err := hc.startChildProcess(&sr, op); err != nil {
|
if err := hc.startChildProcess(&sr); err != nil {
|
||||||
logger.Println(err)
|
logger.ErrorWithCallStack(err)
|
||||||
|
} else {
|
||||||
|
op.Refresh(context.Background(), hc.makeOperationQueryRequest())
|
||||||
}
|
}
|
||||||
|
|
||||||
case shared.Stop:
|
case shared.Stop:
|
||||||
@ -486,6 +511,62 @@ func NewClient(standalone bool) (HoustonClient, error) {
|
|||||||
return hc, nil
|
return hc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func uploadSafe(url, filePath, name, version, uploadedFileName string) error {
|
||||||
|
defer func() {
|
||||||
|
r := recover()
|
||||||
|
if r != nil {
|
||||||
|
logger.Error(r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
t, err := times.Stat(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if file == nil {
|
||||||
|
return errors.New("upload file is missing :" + filePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// hc.config.HttpAddress+"/upload",
|
||||||
|
httpreq, err := http.NewRequest("POST", url, file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
hn, _ := os.Hostname()
|
||||||
|
// createTime := file.
|
||||||
|
httpreq.Header.Set("Houston-Service-Name", name)
|
||||||
|
httpreq.Header.Set("Houston-Service-Version", version)
|
||||||
|
if len(uploadedFileName) == 0 {
|
||||||
|
uploadedFileName = t.BirthTime().UTC().Format(time.DateOnly) + "." + hn + path.Ext(filePath)
|
||||||
|
}
|
||||||
|
httpreq.Header.Set("Houston-Service-Filename", uploadedFileName)
|
||||||
|
httpreq.Header.Set("Content-Type", "application/zip")
|
||||||
|
resp, err := http.DefaultClient.Do(httpreq)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return fmt.Errorf("upload file failed. response code : %s, %d", filePath, resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.Remove(filePath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (hc *houstonClient) Start() {
|
func (hc *houstonClient) Start() {
|
||||||
// receive from stream
|
// receive from stream
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -502,6 +583,30 @@ func (hc *houstonClient) Start() {
|
|||||||
proc.cmd.Wait()
|
proc.cmd.Wait()
|
||||||
proc.cmd.Process.Release()
|
proc.cmd.Process.Release()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close(hc.uploadChan)
|
||||||
|
}()
|
||||||
|
|
||||||
|
if len(hc.config.MetricPipeName) == 0 {
|
||||||
|
hc.config.MetricPipeName = "houston_metric_pipe"
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(hc.config.MetricNamespace) == 0 {
|
||||||
|
hc.config.MetricNamespace = "ou"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_metric_pipe_reader(hc.config, hc.registry, hc.ctx)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
// upload 고루틴
|
||||||
|
url := hc.config.HttpAddress + "/upload"
|
||||||
|
for req := range hc.uploadChan {
|
||||||
|
logger.Println("uploadSafe :", req)
|
||||||
|
err := uploadSafe(url, req.filePath, req.name, req.version, req.uploadedFileName)
|
||||||
|
if err != nil {
|
||||||
|
logger.Println("uploadSafe return err :", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
interrupt := make(chan os.Signal, 1)
|
interrupt := make(chan os.Signal, 1)
|
||||||
@ -517,6 +622,38 @@ func (hc *houstonClient) Start() {
|
|||||||
reconnCount := 0
|
reconnCount := 0
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
|
if autorun != nil && len(*autorun) > 0 {
|
||||||
|
hascount := strings.Split(*autorun, "/")
|
||||||
|
var service string
|
||||||
|
count := 1
|
||||||
|
if len(hascount) > 1 {
|
||||||
|
service = hascount[0]
|
||||||
|
if len(hascount[1]) > 0 {
|
||||||
|
count, _ = strconv.Atoi(hascount[1])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
service = *autorun
|
||||||
|
}
|
||||||
|
|
||||||
|
if cmd, ok := hc.config.Autorun[service]; ok {
|
||||||
|
// service 서비스
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
sr := shared.StartProcessRequest{
|
||||||
|
Name: service,
|
||||||
|
Version: cmd.Version,
|
||||||
|
Args: append([]string{cmd.Exec}, cmd.Args...),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := hc.startChildProcess(&sr); err != nil {
|
||||||
|
logger.Println("startChildProcess failed by autorun :", err)
|
||||||
|
logger.ErrorWithCallStack(err)
|
||||||
|
} else {
|
||||||
|
logger.Println("autorun success :", sr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-hc.ctx.Done():
|
case <-hc.ctx.Done():
|
||||||
@ -531,7 +668,7 @@ func (hc *houstonClient) Start() {
|
|||||||
reconnCount++
|
reconnCount++
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
dialContext, cancelDial := context.WithTimeout(context.Background(), 15*time.Second)
|
dialContext, cancelDial := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
client, err = grpc.DialContext(dialContext, hc.config.GrpcAddress, grpc.WithBlock(), grpc.WithTransportCredentials(insecure.NewCredentials()))
|
client, err = grpc.DialContext(dialContext, hc.config.GrpcAddress, grpc.WithBlock(), grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||||
cancelDial()
|
cancelDial()
|
||||||
|
|
||||||
@ -548,7 +685,6 @@ func (hc *houstonClient) Start() {
|
|||||||
err := hc.checkOperation(client)
|
err := hc.checkOperation(client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Println("grpc.DialContext hc.checkOperation failed :", err)
|
logger.Println("grpc.DialContext hc.checkOperation failed :", err)
|
||||||
|
|
||||||
client = nil
|
client = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -560,6 +696,12 @@ func (hc *houstonClient) Shutdown() {
|
|||||||
hc.shutdownFunc()
|
hc.shutdownFunc()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (hc *houstonClient) MetricHandler() http.Handler {
|
||||||
|
return promhttp.InstrumentMetricHandler(
|
||||||
|
hc.registry, promhttp.HandlerFor(hc.registry, promhttp.HandlerOpts{}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func (hc *houstonClient) checkOperation(client *grpc.ClientConn) error {
|
func (hc *houstonClient) checkOperation(client *grpc.ClientConn) error {
|
||||||
defer func() {
|
defer func() {
|
||||||
r := recover()
|
r := recover()
|
||||||
@ -580,35 +722,6 @@ func (hc *houstonClient) checkOperation(client *grpc.ClientConn) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if autorun != nil && len(*autorun) > 0 {
|
|
||||||
hascount := strings.Split(*autorun, "/")
|
|
||||||
var service string
|
|
||||||
count := 1
|
|
||||||
if len(hascount) > 1 {
|
|
||||||
service = hascount[0]
|
|
||||||
count, _ = strconv.Atoi(hascount[1])
|
|
||||||
} else {
|
|
||||||
service = *autorun
|
|
||||||
}
|
|
||||||
|
|
||||||
if cmd, ok := hc.config.Autorun[service]; ok {
|
|
||||||
// service 서비스
|
|
||||||
for i := 0; i < count; i++ {
|
|
||||||
sr := shared.StartProcessRequest{
|
|
||||||
Name: service,
|
|
||||||
Version: cmd.Version,
|
|
||||||
Args: append([]string{cmd.Exec}, cmd.Args...),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := hc.startChildProcess(&sr, op); err != nil {
|
|
||||||
logger.Println("startChildProcess failed by autorun :", err)
|
|
||||||
} else {
|
|
||||||
logger.Println("autorun success :", sr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
update, err := cl.Recv()
|
update, err := cl.Recv()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
185
client/houston_pipe_req.go
Normal file
185
client/houston_pipe_req.go
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/zip"
|
||||||
|
"bytes"
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var pipeReqPrefix = []byte("houston_pipe_req")
|
||||||
|
var pipeReqHandle = map[string]func(hc *houstonClient, meta *procmeta, param string) error{
|
||||||
|
"upload": handleStdOutUploadRequest,
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleHoustonPipeReq(hc *houstonClient, meta *procmeta, buff []byte) (pipeRequest bool, retErr error) {
|
||||||
|
if !bytes.HasPrefix(buff, pipeReqPrefix) {
|
||||||
|
return false, nil // Not a pipe request
|
||||||
|
}
|
||||||
|
|
||||||
|
command, param, err := parsePipeReq(buff)
|
||||||
|
if err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if handler, ok := pipeReqHandle[command]; ok {
|
||||||
|
if err := handler(hc, meta, param); err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var pipeReqDelimeter = []byte("|")
|
||||||
|
var pipeReqKey = []byte{
|
||||||
|
0x77, 0x77, 0x71, 0x3c, 0x75, 0x64, 0x22, 0x54,
|
||||||
|
0x3e, 0x41, 0x27, 0x68, 0x39, 0x6e, 0x23, 0x49,
|
||||||
|
0x5f, 0x66, 0x71, 0x50, 0x32, 0x68, 0x53, 0x43,
|
||||||
|
0x72, 0x2f, 0x62, 0x39, 0x6e, 0x22, 0x27, 0x2d,
|
||||||
|
}
|
||||||
|
var errInvalidRequestBuff = errors.New("parsePipeReq got invalid request format")
|
||||||
|
|
||||||
|
func parsePipeReq(buff []byte) (command, param string, err error) {
|
||||||
|
//buff == "houston_pipe_req|EncryptString\r\n"
|
||||||
|
parts := bytes.Split(buff, pipeReqDelimeter)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return "", "", errInvalidRequestBuff
|
||||||
|
}
|
||||||
|
|
||||||
|
//Decrypt
|
||||||
|
decryptBuff, err := decryptPipeReq(parts[1])
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
//buff == houston_pipe_req|command|example_paramstring|MD5
|
||||||
|
//decryptBuff == command|example_paramstring|MD5
|
||||||
|
parts = bytes.Split(decryptBuff, pipeReqDelimeter)
|
||||||
|
if len(parts) != 3 {
|
||||||
|
return "", "", errInvalidRequestBuff
|
||||||
|
}
|
||||||
|
|
||||||
|
command = string(parts[0])
|
||||||
|
param = string(parts[1])
|
||||||
|
receivedHash := string(parts[2])
|
||||||
|
if err := validatePipeReq(command, param, receivedHash); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return command, param, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func decryptPipeReq(encordBuff []byte) ([]byte, error) {
|
||||||
|
decordBuff, err := base64.StdEncoding.DecodeString(string(encordBuff))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(decordBuff)%aes.BlockSize != 0 {
|
||||||
|
return nil, errors.New("parsePipeReq got encrypted data which is not a multiple of the block size")
|
||||||
|
}
|
||||||
|
|
||||||
|
aesBlock, err := aes.NewCipher(pipeReqKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
decryptBuff := make([]byte, len(decordBuff))
|
||||||
|
for start := 0; start < len(decordBuff); start += aes.BlockSize {
|
||||||
|
aesBlock.Decrypt(decryptBuff[start:start+aes.BlockSize], decordBuff[start:start+aes.BlockSize])
|
||||||
|
}
|
||||||
|
return decryptBuff, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var errValidatePipeFail = errors.New("validatePipeReq fail to check validation of buff")
|
||||||
|
|
||||||
|
func validatePipeReq(command, param, receivedHash string) error {
|
||||||
|
//Decord receivedHash
|
||||||
|
receiveHashLen := md5.Size * 2
|
||||||
|
if len(receivedHash) < receiveHashLen {
|
||||||
|
return errValidatePipeFail
|
||||||
|
}
|
||||||
|
decordHash, err := hex.DecodeString(receivedHash[0:receiveHashLen])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
//Generate md5 from command and param
|
||||||
|
var reqBuilder strings.Builder
|
||||||
|
reqBuilder.WriteString(command)
|
||||||
|
reqBuilder.Write(pipeReqDelimeter)
|
||||||
|
reqBuilder.WriteString(param)
|
||||||
|
|
||||||
|
buffHashWriter := md5.New()
|
||||||
|
buffHashWriter.Write([]byte(reqBuilder.String()))
|
||||||
|
|
||||||
|
buffHash := buffHashWriter.Sum(nil)
|
||||||
|
if !bytes.Equal(decordHash, buffHash) {
|
||||||
|
return errValidatePipeFail
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleStdOutUploadRequest(hc *houstonClient, meta *procmeta, param string) error {
|
||||||
|
if uploadZipPath, err := compressFile(param); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
hc.uploadToAppendFile(uploadZipPath, meta.name, meta.version, filepath.Base(uploadZipPath))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compressFile(fullPath string) (string, error) {
|
||||||
|
ext := filepath.Ext(fullPath)
|
||||||
|
zipFullPath := fullPath[:len(fullPath)-len(ext)] + ".zip"
|
||||||
|
|
||||||
|
// Create
|
||||||
|
newZipFile, err := os.Create(zipFullPath)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer newZipFile.Close()
|
||||||
|
zipWriter := zip.NewWriter(newZipFile)
|
||||||
|
defer zipWriter.Close()
|
||||||
|
|
||||||
|
// Open
|
||||||
|
fileToZip, err := os.Open(fullPath)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer fileToZip.Close()
|
||||||
|
fileToZipInfo, err := fileToZip.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zip
|
||||||
|
fileToZipHeader, err := zip.FileInfoHeader(fileToZipInfo)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
fileToZipHeader.Name = fileToZipInfo.Name()
|
||||||
|
fileToZipHeader.Method = zip.Deflate
|
||||||
|
fileToZipWriter, err := zipWriter.CreateHeader(fileToZipHeader)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
_, err = io.Copy(fileToZipWriter, fileToZip)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove
|
||||||
|
err = os.Remove(fullPath)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return zipFullPath, nil
|
||||||
|
}
|
||||||
@ -1,133 +0,0 @@
|
|||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
stdlog "log"
|
|
||||||
"net/http"
|
|
||||||
_ "net/http/pprof"
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
|
||||||
promcollectors "github.com/prometheus/client_golang/prometheus/collectors"
|
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
||||||
"github.com/prometheus/common/version"
|
|
||||||
"github.com/prometheus/node_exporter/collector"
|
|
||||||
)
|
|
||||||
|
|
||||||
// handler wraps an unfiltered http.Handler but uses a filtered handler,
|
|
||||||
// created on the fly, if filtering is requested. Create instances with
|
|
||||||
// newHandler.
|
|
||||||
type handler struct {
|
|
||||||
unfilteredHandler http.Handler
|
|
||||||
// exporterMetricsRegistry is a separate registry for the metrics about
|
|
||||||
// the exporter itself.
|
|
||||||
exporterMetricsRegistry *prometheus.Registry
|
|
||||||
includeExporterMetrics bool
|
|
||||||
maxRequests int
|
|
||||||
logger log.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHandlerForNodeExporter(includeExporterMetrics bool, maxRequests int, logger log.Logger) *handler {
|
|
||||||
h := &handler{
|
|
||||||
exporterMetricsRegistry: prometheus.NewRegistry(),
|
|
||||||
includeExporterMetrics: includeExporterMetrics,
|
|
||||||
maxRequests: maxRequests,
|
|
||||||
logger: logger,
|
|
||||||
}
|
|
||||||
if h.includeExporterMetrics {
|
|
||||||
h.exporterMetricsRegistry.MustRegister(
|
|
||||||
promcollectors.NewProcessCollector(promcollectors.ProcessCollectorOpts{}),
|
|
||||||
promcollectors.NewGoCollector(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if innerHandler, err := h.innerHandler(); err != nil {
|
|
||||||
panic(fmt.Sprintf("Couldn't create metrics handler: %s", err))
|
|
||||||
} else {
|
|
||||||
h.unfilteredHandler = innerHandler
|
|
||||||
}
|
|
||||||
return h
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServeHTTP implements http.Handler.
|
|
||||||
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
filters := r.URL.Query()["collect[]"]
|
|
||||||
level.Debug(h.logger).Log("msg", "collect query:", "filters", filters)
|
|
||||||
|
|
||||||
if len(filters) == 0 {
|
|
||||||
// No filters, use the prepared unfiltered handler.
|
|
||||||
h.unfilteredHandler.ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// To serve filtered metrics, we create a filtering handler on the fly.
|
|
||||||
filteredHandler, err := h.innerHandler(filters...)
|
|
||||||
if err != nil {
|
|
||||||
level.Warn(h.logger).Log("msg", "Couldn't create filtered metrics handler:", "err", err)
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
w.Write([]byte(fmt.Sprintf("Couldn't create filtered metrics handler: %s", err)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
filteredHandler.ServeHTTP(w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// innerHandler is used to create both the one unfiltered http.Handler to be
|
|
||||||
// wrapped by the outer handler and also the filtered handlers created on the
|
|
||||||
// fly. The former is accomplished by calling innerHandler without any arguments
|
|
||||||
// (in which case it will log all the collectors enabled via command-line
|
|
||||||
// flags).
|
|
||||||
func (h *handler) innerHandler(filters ...string) (http.Handler, error) {
|
|
||||||
nc, err := collector.NewNodeCollector(h.logger, filters...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("couldn't create collector: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only log the creation of an unfiltered handler, which should happen
|
|
||||||
// only once upon startup.
|
|
||||||
if len(filters) == 0 {
|
|
||||||
level.Info(h.logger).Log("msg", "Enabled collectors")
|
|
||||||
collectors := []string{}
|
|
||||||
for n := range nc.Collectors {
|
|
||||||
collectors = append(collectors, n)
|
|
||||||
}
|
|
||||||
sort.Strings(collectors)
|
|
||||||
for _, c := range collectors {
|
|
||||||
level.Info(h.logger).Log("collector", c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
r := prometheus.NewRegistry()
|
|
||||||
r.MustRegister(version.NewCollector("node_exporter"))
|
|
||||||
if err := r.Register(nc); err != nil {
|
|
||||||
return nil, fmt.Errorf("couldn't register node collector: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var handler http.Handler
|
|
||||||
if h.includeExporterMetrics {
|
|
||||||
handler = promhttp.HandlerFor(
|
|
||||||
prometheus.Gatherers{h.exporterMetricsRegistry, r},
|
|
||||||
promhttp.HandlerOpts{
|
|
||||||
ErrorLog: stdlog.New(log.NewStdlibAdapter(level.Error(h.logger)), "", 0),
|
|
||||||
ErrorHandling: promhttp.ContinueOnError,
|
|
||||||
MaxRequestsInFlight: h.maxRequests,
|
|
||||||
Registry: h.exporterMetricsRegistry,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
// Note that we have to use h.exporterMetricsRegistry here to
|
|
||||||
// use the same promhttp metrics for all expositions.
|
|
||||||
handler = promhttp.InstrumentMetricHandler(
|
|
||||||
h.exporterMetricsRegistry, handler,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
handler = promhttp.HandlerFor(
|
|
||||||
r,
|
|
||||||
promhttp.HandlerOpts{
|
|
||||||
ErrorLog: stdlog.New(log.NewStdlibAdapter(level.Error(h.logger)), "", 0),
|
|
||||||
ErrorHandling: promhttp.ContinueOnError,
|
|
||||||
MaxRequestsInFlight: h.maxRequests,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return handler, nil
|
|
||||||
}
|
|
||||||
@ -14,13 +14,15 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/Knetic/govaluate"
|
||||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
"repositories.action2quare.com/ayo/gocommon/metric"
|
|
||||||
"repositories.action2quare.com/ayo/houston/shared"
|
"repositories.action2quare.com/ayo/houston/shared"
|
||||||
"repositories.action2quare.com/ayo/houston/shared/protos"
|
"repositories.action2quare.com/ayo/houston/shared/protos"
|
||||||
)
|
)
|
||||||
@ -41,6 +43,15 @@ func lastExecutionArgs(verpath string) []string {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (hc *houstonClient) uploadToAppendFile(filePath string, name string, version string, uploadedFileName string) {
|
||||||
|
hc.uploadChan <- uploadRequest{
|
||||||
|
filePath: filePath,
|
||||||
|
name: name,
|
||||||
|
version: version,
|
||||||
|
uploadedFileName: uploadedFileName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var errUploadZipLogFailed = errors.New("not ok")
|
var errUploadZipLogFailed = errors.New("not ok")
|
||||||
|
|
||||||
func (hc *houstonClient) uploadZipLogFile(zipFile string, name string, version string) error {
|
func (hc *houstonClient) uploadZipLogFile(zipFile string, name string, version string) error {
|
||||||
@ -237,6 +248,68 @@ func makeLogFilePrefix(meta *procmeta, index int) string {
|
|||||||
return path.Join(meta.verpath, "logs", fmt.Sprintf("%s_%d_%s", nameonly, index, ts))
|
return path.Join(meta.verpath, "logs", fmt.Sprintf("%s_%d_%s", nameonly, index, ts))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func evaluateExpression(expression string, params map[string]any) (any, error) {
|
||||||
|
expression = strings.TrimSpace(expression)
|
||||||
|
expr, err := govaluate.NewEvaluableExpression(expression)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return expr.Evaluate(params)
|
||||||
|
}
|
||||||
|
|
||||||
|
func evaluateArgs(args []string, params map[string]any) ([]string, error) {
|
||||||
|
re := regexp.MustCompile(`\$\(\((.*?)\)\)`)
|
||||||
|
|
||||||
|
for i, input := range args {
|
||||||
|
matches := re.FindAllStringSubmatch(input, -1)
|
||||||
|
if len(matches) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, match := range matches {
|
||||||
|
if len(match) > 1 {
|
||||||
|
expression := strings.TrimSpace(match[1])
|
||||||
|
expr, err := govaluate.NewEvaluableExpression(expression)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := expr.Evaluate(params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 원래 표현식을 결과로 대체
|
||||||
|
input = strings.Replace(input, match[0], fmt.Sprintf("%v", result), -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
args[i] = input
|
||||||
|
}
|
||||||
|
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseEnv(input []string) map[string]any {
|
||||||
|
output := make(map[string]any, len(input))
|
||||||
|
for _, envkv := range input {
|
||||||
|
kv := strings.SplitN(envkv, "=", 2)
|
||||||
|
parsed, err := strconv.ParseInt(kv[1], 10, 0)
|
||||||
|
if err == nil {
|
||||||
|
output[kv[0]] = parsed
|
||||||
|
} else {
|
||||||
|
parsed, err := strconv.ParseFloat(kv[1], 32)
|
||||||
|
if err == nil {
|
||||||
|
output[kv[0]] = parsed
|
||||||
|
} else {
|
||||||
|
output[kv[0]] = kv[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
func (hc *houstonClient) launch(meta *procmeta) error {
|
func (hc *houstonClient) launch(meta *procmeta) error {
|
||||||
stdout, err := meta.cmd.StdoutPipe()
|
stdout, err := meta.cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -248,7 +321,7 @@ func (hc *houstonClient) launch(meta *procmeta) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
stdReader := func(jobName string, r io.ReadCloser, index int) {
|
stdReader := func(r io.ReadCloser, index int) {
|
||||||
defer func() {
|
defer func() {
|
||||||
reco := recover()
|
reco := recover()
|
||||||
if reco != nil {
|
if reco != nil {
|
||||||
@ -272,68 +345,31 @@ func (hc *houstonClient) launch(meta *procmeta) error {
|
|||||||
thisFileSize := 0
|
thisFileSize := 0
|
||||||
logFileIndex := 0
|
logFileIndex := 0
|
||||||
|
|
||||||
var logWriter func([]byte)
|
logFileNamePrefix := makeLogFilePrefix(meta, index)
|
||||||
if *logger.UseLogFile {
|
logFileName := fmt.Sprintf("%s_%d.log", logFileNamePrefix, logFileIndex)
|
||||||
logFileNamePrefix := makeLogFilePrefix(meta, index)
|
targetFile, err := os.Create(logFileName)
|
||||||
logFileName := fmt.Sprintf("%s_%d.log", logFileNamePrefix, logFileIndex)
|
if err != nil {
|
||||||
targetFile, err := os.Create(logFileName)
|
logger.Println("failed to create log file :", logFileName)
|
||||||
if err != nil {
|
return
|
||||||
logger.Println("failed to create log file :", logFileName)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
exef, _ := os.Executable()
|
|
||||||
var linkPath string
|
|
||||||
if index == 0 {
|
|
||||||
linkPath = path.Join(path.Dir(exef), path.Dir(logFileName), meta.name+".log")
|
|
||||||
} else {
|
|
||||||
linkPath = path.Join(path.Dir(exef), path.Dir(logFileName), fmt.Sprintf("%s_%d.log", meta.name, index))
|
|
||||||
}
|
|
||||||
|
|
||||||
os.Remove(linkPath)
|
|
||||||
os.Symlink(path.Base(filepath.ToSlash(targetFile.Name())), linkPath)
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if targetFile != nil {
|
|
||||||
targetFile.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
logWriter = func(buff []byte) {
|
|
||||||
for written := 0; written < len(buff); {
|
|
||||||
n, err := targetFile.Write(buff)
|
|
||||||
if err != nil {
|
|
||||||
logger.Println("write log file failed :", logFileName, err)
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
written += n
|
|
||||||
thisFileSize += n
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if thisFileSize > 5*1024*1024 {
|
|
||||||
logFileIndex++
|
|
||||||
logFileName = fmt.Sprintf("%s_%d.log", logFileNamePrefix, logFileIndex)
|
|
||||||
nextTargetFile, err := os.Create(logFileName)
|
|
||||||
if err != nil {
|
|
||||||
logger.Println("failed to create log file :", logFileName)
|
|
||||||
} else {
|
|
||||||
targetFile.Close()
|
|
||||||
targetFile = nextTargetFile
|
|
||||||
os.Remove(linkPath)
|
|
||||||
os.Symlink(path.Base(filepath.ToSlash(targetFile.Name())), linkPath)
|
|
||||||
thisFileSize = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logWriter = func(buff []byte) {
|
|
||||||
os.Stdout.Write(buff)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
readingMetric := false
|
exef, _ := os.Executable()
|
||||||
var metricBuffer []byte
|
var linkPath string
|
||||||
|
if index == 0 {
|
||||||
|
linkPath = path.Join(path.Dir(exef), path.Dir(logFileName), meta.name+".log")
|
||||||
|
} else {
|
||||||
|
linkPath = path.Join(path.Dir(exef), path.Dir(logFileName), fmt.Sprintf("%s_%d.log", meta.name, index))
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Remove(linkPath)
|
||||||
|
os.Symlink(path.Base(filepath.ToSlash(targetFile.Name())), linkPath)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if targetFile != nil {
|
||||||
|
targetFile.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
logger.Println("stdReader is terminated :", meta.name)
|
logger.Println("stdReader is terminated :", meta.name)
|
||||||
if meta.isState(protos.ProcessState_Running) {
|
if meta.isState(protos.ProcessState_Running) {
|
||||||
@ -346,9 +382,6 @@ func (hc *houstonClient) launch(meta *procmeta) error {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
metricExporter := metric.NewPrometheusExport(hc.config.MetricNamespace)
|
|
||||||
defer metricExporter.Shutdown()
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
buff, err := reader.ReadBytes('\n')
|
buff, err := reader.ReadBytes('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -356,48 +389,31 @@ func (hc *houstonClient) launch(meta *procmeta) error {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if readingMetric {
|
for written := 0; written < len(buff); {
|
||||||
metricBuffer = append(metricBuffer, buff...)
|
n, err := targetFile.Write(buff)
|
||||||
} else if buff[0] == metric.METRIC_HEAD_INLINE {
|
if err != nil {
|
||||||
readingMetric = true
|
logger.Println("write log file failed :", logFileName, err)
|
||||||
metricBuffer = append(metricBuffer, buff[1:]...)
|
break
|
||||||
}
|
} else {
|
||||||
|
written += n
|
||||||
if readingMetric {
|
thisFileSize += n
|
||||||
if metricBuffer[len(metricBuffer)-2] == metric.METRIC_TAIL_INLINE {
|
|
||||||
readingMetric = false
|
|
||||||
|
|
||||||
metricBuffer = metricBuffer[:len(metricBuffer)-2]
|
|
||||||
if metricBuffer[0] == '{' {
|
|
||||||
var desc metric.MetricDescription
|
|
||||||
if err := json.Unmarshal(metricBuffer, &desc); err != nil {
|
|
||||||
logger.Println("unmarshal metric failed :", err, string(metricBuffer))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if desc.ConstLabels == nil {
|
|
||||||
desc.ConstLabels = make(map[string]string)
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range hc.config.ConstLabels {
|
|
||||||
desc.ConstLabels[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
desc.ConstLabels["job"] = jobName
|
|
||||||
|
|
||||||
metricExporter.RegisterMetric(&desc)
|
|
||||||
} else {
|
|
||||||
key, val := metric.ReadMetricValue(metricBuffer)
|
|
||||||
metricExporter.UpdateMetric(key, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
metricBuffer = metricBuffer[:0]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logWriter(buff)
|
if thisFileSize > 5*1024*1024 {
|
||||||
|
logFileIndex++
|
||||||
|
logFileName = fmt.Sprintf("%s_%d.log", logFileNamePrefix, logFileIndex)
|
||||||
|
nextTargetFile, err := os.Create(logFileName)
|
||||||
|
if err != nil {
|
||||||
|
logger.Println("failed to create log file :", logFileName)
|
||||||
|
} else {
|
||||||
|
targetFile.Close()
|
||||||
|
targetFile = nextTargetFile
|
||||||
|
os.Remove(linkPath)
|
||||||
|
os.Symlink(path.Base(filepath.ToSlash(targetFile.Name())), linkPath)
|
||||||
|
thisFileSize = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,10 +437,16 @@ func (hc *houstonClient) launch(meta *procmeta) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
go stdReader(meta.name, stdout, index)
|
go stdReader(stdout, index)
|
||||||
|
|
||||||
logger.Println("startChildProcess :", meta.cmd.Args)
|
|
||||||
meta.cmd.Env = append(os.Environ(), fmt.Sprintf("HOUSTON_SIBLIING_INDEX=%d", index))
|
meta.cmd.Env = append(os.Environ(), fmt.Sprintf("HOUSTON_SIBLIING_INDEX=%d", index))
|
||||||
|
meta.cmd.Args, err = evaluateArgs(meta.cmd.Args, parseEnv(meta.cmd.Env))
|
||||||
|
if err != nil {
|
||||||
|
logger.Println("evaluateArgs failed :", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Println("startChildProcess :", meta.cmd.Args)
|
||||||
|
|
||||||
err = meta.cmd.Start()
|
err = meta.cmd.Start()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
logger.Println("process index, pid =", index, meta.cmd.Process.Pid)
|
logger.Println("process index, pid =", index, meta.cmd.Process.Pid)
|
||||||
@ -435,7 +457,7 @@ func (hc *houstonClient) launch(meta *procmeta) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hc *houstonClient) startChildProcess(req *shared.StartProcessRequest, op protos.OperationClient) error {
|
func (hc *houstonClient) startChildProcess(req *shared.StartProcessRequest) error {
|
||||||
meta, err := prepareProcessLaunch(hc.config.StorageRoot, req)
|
meta, err := prepareProcessLaunch(hc.config.StorageRoot, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -465,8 +487,6 @@ func (hc *houstonClient) startChildProcess(req *shared.StartProcessRequest, op p
|
|||||||
}
|
}
|
||||||
|
|
||||||
hc.childProcs = append(hc.childProcs, meta)
|
hc.childProcs = append(hc.childProcs, meta)
|
||||||
op.Refresh(context.Background(), hc.makeOperationQueryRequest())
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
95
client/pipe_reader_common.go
Normal file
95
client/pipe_reader_common.go
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"maps"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/metric"
|
||||||
|
)
|
||||||
|
|
||||||
|
type pipeListener struct {
|
||||||
|
config clientConfig
|
||||||
|
registry *prometheus.Registry
|
||||||
|
}
|
||||||
|
|
||||||
|
func run_metric_pipe_reader(config clientConfig, registry *prometheus.Registry, ctx context.Context) {
|
||||||
|
r := &pipeListener{
|
||||||
|
config: config,
|
||||||
|
registry: registry,
|
||||||
|
}
|
||||||
|
|
||||||
|
go r.listen(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
type pipeReader struct {
|
||||||
|
handle io.ReadCloser
|
||||||
|
constLabels map[string]string
|
||||||
|
collector *metric.PrometheusCollector
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *pipeListener) startReader(r io.ReadCloser) {
|
||||||
|
reader := pipeReader{
|
||||||
|
handle: r,
|
||||||
|
constLabels: l.config.ConstLabels,
|
||||||
|
collector: metric.NewPrometheusCollector(l.config.MetricNamespace, l.registry),
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
reader.close(l.registry)
|
||||||
|
}()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(r)
|
||||||
|
for scanner.Scan() {
|
||||||
|
reader.parseLine(scanner.Text())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *pipeReader) close(registry *prometheus.Registry) {
|
||||||
|
registry.Unregister(r.collector)
|
||||||
|
r.handle.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *pipeReader) parseLine(line string) {
|
||||||
|
defer func() {
|
||||||
|
r := recover()
|
||||||
|
if r != nil {
|
||||||
|
logger.Println(r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
switch line[0] {
|
||||||
|
case '{':
|
||||||
|
var desc metric.MetricDescription
|
||||||
|
if err := json.Unmarshal([]byte(line), &desc); err != nil {
|
||||||
|
logger.Println("unmarshal metric failed :", err, line)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if desc.ConstLabels == nil {
|
||||||
|
desc.ConstLabels = make(map[string]string)
|
||||||
|
}
|
||||||
|
|
||||||
|
maps.Copy(desc.ConstLabels, r.constLabels)
|
||||||
|
r.collector = r.collector.RegisterMetric(&desc)
|
||||||
|
|
||||||
|
default:
|
||||||
|
kv := strings.Split(line, ":")
|
||||||
|
if len(kv) != 2 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(kv[1]) == 0 {
|
||||||
|
r.collector = r.collector.UnregisterMetric(kv[0])
|
||||||
|
} else {
|
||||||
|
if val, err := strconv.ParseFloat(kv[1], 64); err == nil {
|
||||||
|
r.collector.UpdateMetric(kv[0], val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
40
client/pipe_reader_linux.go
Normal file
40
client/pipe_reader_linux.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *pipeListener) listen(ctx context.Context) {
|
||||||
|
mode := 0666 // 읽기/쓰기 권한
|
||||||
|
pipeName := "/tmp/" + r.config.MetricPipeName
|
||||||
|
|
||||||
|
os.Remove(pipeName)
|
||||||
|
if err := unix.Mkfifo(pipeName, uint32(mode)); err != nil {
|
||||||
|
logger.Println("mkfifo failed :", pipeName, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer os.Remove(pipeName)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
// file에 쓰기 핸들을 하나 열고 ctx가 Done일 때 닫음. 이래야 reader가 계속 열려있게 됨
|
||||||
|
f, err := os.OpenFile(pipeName, os.O_WRONLY, 0)
|
||||||
|
if err != nil {
|
||||||
|
logger.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
<-ctx.Done()
|
||||||
|
f.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
file, err := os.Open(pipeName)
|
||||||
|
if err != nil {
|
||||||
|
logger.Println("FIFO open error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r.startReader(file)
|
||||||
|
}
|
||||||
35
client/pipe_reader_windows.go
Normal file
35
client/pipe_reader_windows.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/natefinch/npipe"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *pipeListener) listen(ctx context.Context) {
|
||||||
|
pipename := r.config.MetricPipeName
|
||||||
|
if !strings.HasPrefix(pipename, `\\.\pipe\`) {
|
||||||
|
pipename = `\\.\pipe\` + pipename
|
||||||
|
}
|
||||||
|
listener, err := npipe.Listen(pipename)
|
||||||
|
if err != nil {
|
||||||
|
logger.Println("metric pipe npipe.Listen failed :", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
<-ctx.Done()
|
||||||
|
logger.Println("listener close")
|
||||||
|
listener.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
if conn, err := listener.Accept(); err == nil {
|
||||||
|
go r.startReader(conn)
|
||||||
|
} else {
|
||||||
|
logger.Println("metric pipe listener.Accept failed :", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
90
go.mod
90
go.mod
@ -1,70 +1,82 @@
|
|||||||
module repositories.action2quare.com/ayo/houston
|
module repositories.action2quare.com/ayo/houston
|
||||||
|
|
||||||
go 1.19
|
go 1.23.0
|
||||||
|
|
||||||
|
toolchain go1.24.4
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/go-kit/log v0.2.1
|
github.com/Knetic/govaluate v3.0.0+incompatible
|
||||||
github.com/prometheus/client_golang v1.17.0
|
github.com/djherbis/times v1.6.0
|
||||||
github.com/prometheus/common v0.44.0
|
golang.org/x/sys v0.31.0
|
||||||
github.com/prometheus/node_exporter v1.6.1
|
golang.org/x/text v0.23.0
|
||||||
golang.org/x/sys v0.16.0
|
|
||||||
golang.org/x/text v0.14.0
|
|
||||||
google.golang.org/grpc v1.60.1
|
google.golang.org/grpc v1.60.1
|
||||||
google.golang.org/protobuf v1.32.0
|
google.golang.org/protobuf v1.36.1
|
||||||
repositories.action2quare.com/ayo/gocommon v0.0.0-20240708060921-18d284a4ea85
|
repositories.action2quare.com/ayo/gocommon v0.0.0-20250701095003-d77fa2108add
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/alecthomas/kingpin/v2 v2.3.2 // indirect
|
github.com/alecthomas/kingpin/v2 v2.4.0 // indirect
|
||||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
|
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
|
||||||
github.com/beevik/ntp v0.3.0 // indirect
|
github.com/beevik/ntp v1.4.3 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||||
github.com/dennwc/btrfs v0.0.0-20230312211831-a1f570bd01a1 // indirect
|
github.com/dennwc/btrfs v0.0.0-20240418142341-0167142bde7a // indirect
|
||||||
github.com/dennwc/ioctl v1.0.0 // indirect
|
github.com/dennwc/ioctl v1.0.0 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/ema/qdisc v1.0.0 // indirect
|
||||||
github.com/ema/qdisc v0.0.0-20230120214811-5b708f463de3 // indirect
|
|
||||||
github.com/go-logfmt/logfmt v0.5.1 // indirect
|
|
||||||
github.com/go-redis/redis/v8 v8.11.5 // indirect
|
|
||||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/google/go-cmp v0.6.0 // indirect
|
||||||
github.com/golang/snappy v0.0.1 // indirect
|
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
|
||||||
github.com/hashicorp/go-envparse v0.1.0 // indirect
|
github.com/hashicorp/go-envparse v0.1.0 // indirect
|
||||||
github.com/hodgesds/perf-utils v0.7.0 // indirect
|
github.com/hodgesds/perf-utils v0.7.0 // indirect
|
||||||
github.com/illumos/go-kstat v0.0.0-20210513183136-173c9b0a9973 // indirect
|
github.com/illumos/go-kstat v0.0.0-20210513183136-173c9b0a9973 // indirect
|
||||||
github.com/josharian/native v1.1.0 // indirect
|
github.com/josharian/native v1.1.0 // indirect
|
||||||
github.com/jsimonetti/rtnetlink v1.3.2 // indirect
|
github.com/jsimonetti/rtnetlink/v2 v2.0.2 // indirect
|
||||||
github.com/klauspost/compress v1.13.6 // indirect
|
|
||||||
github.com/lufia/iostat v1.2.1 // indirect
|
github.com/lufia/iostat v1.2.1 // indirect
|
||||||
github.com/mattn/go-xmlrpc v0.0.3 // indirect
|
github.com/mattn/go-xmlrpc v0.0.3 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
github.com/mdlayher/ethtool v0.2.0 // indirect
|
||||||
github.com/mdlayher/ethtool v0.0.0-20221212131811-ba3b4bc2e02c // indirect
|
github.com/mdlayher/genetlink v1.3.2 // indirect
|
||||||
github.com/mdlayher/genetlink v1.3.1 // indirect
|
|
||||||
github.com/mdlayher/netlink v1.7.2 // indirect
|
github.com/mdlayher/netlink v1.7.2 // indirect
|
||||||
github.com/mdlayher/socket v0.4.1 // indirect
|
github.com/mdlayher/socket v0.4.1 // indirect
|
||||||
github.com/mdlayher/wifi v0.0.0-20220330172155-a44c70b6d3c8 // indirect
|
github.com/mdlayher/wifi v0.3.1 // indirect
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
|
github.com/opencontainers/selinux v1.11.1 // indirect
|
||||||
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||||
|
github.com/prometheus-community/go-runit v0.1.0 // indirect
|
||||||
|
github.com/prometheus/client_golang v1.20.5 // indirect
|
||||||
|
github.com/prometheus/client_model v0.6.1 // indirect
|
||||||
|
github.com/prometheus/common v0.62.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.15.2-0.20240603130017-1754b780536b // indirect
|
||||||
|
github.com/safchain/ethtool v0.5.10 // indirect
|
||||||
|
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
|
||||||
|
go.uber.org/atomic v1.7.0 // indirect
|
||||||
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
|
||||||
|
howett.net/plist v1.0.1 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
|
github.com/go-kit/log v0.2.1 // indirect
|
||||||
|
github.com/go-logfmt/logfmt v0.5.1 // indirect
|
||||||
|
github.com/go-redis/redis/v8 v8.11.5 // indirect
|
||||||
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
|
github.com/golang/snappy v0.0.1 // indirect
|
||||||
|
github.com/klauspost/compress v1.17.9 // indirect
|
||||||
|
github.com/kr/pretty v0.3.1 // indirect
|
||||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
|
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
|
||||||
github.com/opencontainers/selinux v1.11.0 // indirect
|
github.com/natefinch/npipe v0.0.0-20160621034901-c1b8fa8bdcce
|
||||||
github.com/pires/go-proxyproto v0.7.0 // indirect
|
github.com/pires/go-proxyproto v0.7.0 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/prometheus-community/go-runit v0.1.0 // indirect
|
github.com/prometheus/node_exporter v1.9.1
|
||||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect
|
github.com/rogpeppe/go-internal v1.10.0 // indirect
|
||||||
github.com/prometheus/procfs v0.11.1 // indirect
|
github.com/stretchr/testify v1.10.0 // indirect
|
||||||
github.com/safchain/ethtool v0.3.0 // indirect
|
|
||||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||||
github.com/xdg-go/scram v1.1.1 // indirect
|
github.com/xdg-go/scram v1.1.1 // indirect
|
||||||
github.com/xdg-go/stringprep v1.0.3 // indirect
|
github.com/xdg-go/stringprep v1.0.3 // indirect
|
||||||
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
|
|
||||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
||||||
go.mongodb.org/mongo-driver v1.11.6 // indirect
|
go.mongodb.org/mongo-driver v1.11.6 // indirect
|
||||||
go.uber.org/atomic v1.7.0 // indirect
|
golang.org/x/crypto v0.36.0 // indirect
|
||||||
go.uber.org/multierr v1.6.0 // indirect
|
golang.org/x/net v0.37.0 // indirect
|
||||||
golang.org/x/crypto v0.18.0 // indirect
|
golang.org/x/sync v0.12.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
|
|
||||||
golang.org/x/net v0.20.0 // indirect
|
|
||||||
golang.org/x/sync v0.6.0 // indirect
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect
|
||||||
howett.net/plist v1.0.0 // indirect
|
|
||||||
)
|
)
|
||||||
|
|||||||
130
go.sum
130
go.sum
@ -1,28 +1,35 @@
|
|||||||
github.com/alecthomas/kingpin/v2 v2.3.2 h1:H0aULhgmSzN8xQ3nX1uxtdlTHYoPLu5AhHxWrKI6ocU=
|
github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg=
|
||||||
github.com/alecthomas/kingpin/v2 v2.3.2/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
|
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||||
|
github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY=
|
||||||
|
github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
|
||||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
|
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
|
||||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
||||||
github.com/beevik/ntp v0.3.0 h1:xzVrPrE4ziasFXgBVBZJDP0Wg/KpMwk2KHJ4Ba8GrDw=
|
github.com/beevik/ntp v1.4.3 h1:PlbTvE5NNy4QHmA4Mg57n7mcFTmr1W1j3gcK7L1lqho=
|
||||||
github.com/beevik/ntp v0.3.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
|
github.com/beevik/ntp v1.4.3/go.mod h1:Unr8Zg+2dRn7d8bHFuehIMSvvUYssHMxW3Q5Nx4RW5Q=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cilium/ebpf v0.10.0 h1:nk5HPMeoBXtOzbkZBWym+ZWq1GIiHUsBFXxwewXAHLQ=
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dennwc/btrfs v0.0.0-20230312211831-a1f570bd01a1 h1:ue4Es4Xzz255hWQ7NAWzZxuXG+YOV7URzzusLLSe0zU=
|
github.com/dennwc/btrfs v0.0.0-20240418142341-0167142bde7a h1:KfFsGLJFVdCXlySUkV2FmxNtmiztpJb6tV+XYBmmv8E=
|
||||||
github.com/dennwc/btrfs v0.0.0-20230312211831-a1f570bd01a1/go.mod h1:MYsOV9Dgsec3FFSOjywi0QK5r6TeBbdWxdrMGtiYXHA=
|
github.com/dennwc/btrfs v0.0.0-20240418142341-0167142bde7a/go.mod h1:MYsOV9Dgsec3FFSOjywi0QK5r6TeBbdWxdrMGtiYXHA=
|
||||||
github.com/dennwc/ioctl v1.0.0 h1:DsWAAjIxRqNcLn9x6mwfuf2pet3iB7aK90K4tF16rLg=
|
github.com/dennwc/ioctl v1.0.0 h1:DsWAAjIxRqNcLn9x6mwfuf2pet3iB7aK90K4tF16rLg=
|
||||||
github.com/dennwc/ioctl v1.0.0/go.mod h1:ellh2YB5ldny99SBU/VX7Nq0xiZbHphf1DrtHxxjMk0=
|
github.com/dennwc/ioctl v1.0.0/go.mod h1:ellh2YB5ldny99SBU/VX7Nq0xiZbHphf1DrtHxxjMk0=
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
github.com/ema/qdisc v0.0.0-20230120214811-5b708f463de3 h1:Jrl8sD8wO34+EE1dV2vhOXrqFAZa/FILDnZRaV28+cw=
|
github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c=
|
||||||
github.com/ema/qdisc v0.0.0-20230120214811-5b708f463de3/go.mod h1:FhIc0fLYi7f+lK5maMsesDqwYojIOh3VfRs8EVd5YJQ=
|
github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0=
|
||||||
|
github.com/ema/qdisc v1.0.0 h1:EHLG08FVRbWLg8uRICa3xzC9Zm0m7HyMHfXobWFnXYg=
|
||||||
|
github.com/ema/qdisc v1.0.0/go.mod h1:FhIc0fLYi7f+lK5maMsesDqwYojIOh3VfRs8EVd5YJQ=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
|
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
|
||||||
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||||
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
|
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
|
||||||
@ -32,7 +39,6 @@ github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq
|
|||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
@ -42,6 +48,8 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/hashicorp/go-envparse v0.1.0 h1:bE++6bhIsNCPLvgDZkYqo3nA+/PFI51pkrHdmPSDFPY=
|
github.com/hashicorp/go-envparse v0.1.0 h1:bE++6bhIsNCPLvgDZkYqo3nA+/PFI51pkrHdmPSDFPY=
|
||||||
github.com/hashicorp/go-envparse v0.1.0/go.mod h1:OHheN1GoygLlAkTlXLXvAdnXdZxy8JUweQ1rAXx1xnc=
|
github.com/hashicorp/go-envparse v0.1.0/go.mod h1:OHheN1GoygLlAkTlXLXvAdnXdZxy8JUweQ1rAXx1xnc=
|
||||||
github.com/hodgesds/perf-utils v0.7.0 h1:7KlHGMuig4FRH5fNw68PV6xLmgTe7jKs9hgAcEAbioU=
|
github.com/hodgesds/perf-utils v0.7.0 h1:7KlHGMuig4FRH5fNw68PV6xLmgTe7jKs9hgAcEAbioU=
|
||||||
@ -51,65 +59,84 @@ github.com/illumos/go-kstat v0.0.0-20210513183136-173c9b0a9973/go.mod h1:PoK3ejP
|
|||||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||||
github.com/jsimonetti/rtnetlink v1.3.2 h1:dcn0uWkfxycEEyNy0IGfx3GrhQ38LH7odjxAghimsVI=
|
github.com/jsimonetti/rtnetlink/v2 v2.0.2 h1:ZKlbCujrIpp4/u3V2Ka0oxlf4BCkt6ojkvpy3nZoCBY=
|
||||||
github.com/jsimonetti/rtnetlink v1.3.2/go.mod h1:BBu4jZCpTjP6Gk0/wfrO8qcqymnN3g0hoFqObRmUo6U=
|
github.com/jsimonetti/rtnetlink/v2 v2.0.2/go.mod h1:7MoNYNbb3UaDHtF8udiJo/RH6VsTKP1pqKLUTVCvToE=
|
||||||
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
|
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
|
||||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||||
|
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||||
|
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/lufia/iostat v1.2.1 h1:tnCdZBIglgxD47RyD55kfWQcJMGzO+1QBziSQfesf2k=
|
github.com/lufia/iostat v1.2.1 h1:tnCdZBIglgxD47RyD55kfWQcJMGzO+1QBziSQfesf2k=
|
||||||
github.com/lufia/iostat v1.2.1/go.mod h1:rEPNA0xXgjHQjuI5Cy05sLlS2oRcSlWHRLrvh/AQ+Pg=
|
github.com/lufia/iostat v1.2.1/go.mod h1:rEPNA0xXgjHQjuI5Cy05sLlS2oRcSlWHRLrvh/AQ+Pg=
|
||||||
github.com/mattn/go-xmlrpc v0.0.3 h1:Y6WEMLEsqs3RviBrAa1/7qmbGB7DVD3brZIbqMbQdGY=
|
github.com/mattn/go-xmlrpc v0.0.3 h1:Y6WEMLEsqs3RviBrAa1/7qmbGB7DVD3brZIbqMbQdGY=
|
||||||
github.com/mattn/go-xmlrpc v0.0.3/go.mod h1:mqc2dz7tP5x5BKlCahN/n+hs7OSZKJkS9JsHNBRlrxA=
|
github.com/mattn/go-xmlrpc v0.0.3/go.mod h1:mqc2dz7tP5x5BKlCahN/n+hs7OSZKJkS9JsHNBRlrxA=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
github.com/mdlayher/ethtool v0.2.0 h1:akcA4WZVWozzirPASeMq8qgLkxpF3ykftVXwnrMKrhY=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
github.com/mdlayher/ethtool v0.2.0/go.mod h1:W0pIBrNPK1TslIN4Z9wt1EVbay66Kbvek2z2f29VBfw=
|
||||||
github.com/mdlayher/ethtool v0.0.0-20221212131811-ba3b4bc2e02c h1:Y7LoKqIgD7vmqJ7+6ZVnADuwUO+m3tGXbf2lK0OvjIw=
|
github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw=
|
||||||
github.com/mdlayher/ethtool v0.0.0-20221212131811-ba3b4bc2e02c/go.mod h1:i0nPbE+sL2G3OtdIb9SXxW/T4UiAwh6rxPW7zcuX+KQ=
|
github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o=
|
||||||
github.com/mdlayher/genetlink v1.3.1 h1:roBiPnual+eqtRkKX2Jb8UQN5ZPWnhDCGj/wR6Jlz2w=
|
|
||||||
github.com/mdlayher/genetlink v1.3.1/go.mod h1:uaIPxkWmGk753VVIzDtROxQ8+T+dkHqOI0vB1NA9S/Q=
|
|
||||||
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
|
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
|
||||||
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
||||||
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
|
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
|
||||||
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
|
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
|
||||||
github.com/mdlayher/wifi v0.0.0-20220330172155-a44c70b6d3c8 h1:/HCRFfpoICSWHvNrJ356VO4opd9dg/LaU7m8Tzdf39c=
|
github.com/mdlayher/wifi v0.3.1 h1:bZDuMI1f7z5BtUUO3NgHRdR/R88YtywIe6dsEFI0Txs=
|
||||||
github.com/mdlayher/wifi v0.0.0-20220330172155-a44c70b6d3c8/go.mod h1:IqdtNfemiXr50M8tnxLWSFdZKZ9vcI1Mgt0oTrCIS7A=
|
github.com/mdlayher/wifi v0.3.1/go.mod h1:ODQaObvsglghTuNhezD9grkTB4shVNc28aJfTXmvSi8=
|
||||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
|
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
|
||||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
|
github.com/natefinch/npipe v0.0.0-20160621034901-c1b8fa8bdcce h1:TqjP/BTDrwN7zP9xyXVuLsMBXYMt6LLYi55PlrIcq8U=
|
||||||
|
github.com/natefinch/npipe v0.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:ifHPsLndGGzvgzcaXUvzmt6LxKT4pJ+uzEhtnMt+f7A=
|
||||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||||
|
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||||
github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU=
|
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||||
github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
|
github.com/opencontainers/selinux v1.11.1 h1:nHFvthhM0qY8/m+vfhJylliSshm8G1jJ2jDMcgULaH8=
|
||||||
|
github.com/opencontainers/selinux v1.11.1/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
|
||||||
github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs=
|
github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs=
|
||||||
github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4=
|
github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4=
|
||||||
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||||
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||||
github.com/prometheus-community/go-runit v0.1.0 h1:uTWEj/Fn2RoLdfg/etSqwzgYNOYPrARx1BHUN052tGA=
|
github.com/prometheus-community/go-runit v0.1.0 h1:uTWEj/Fn2RoLdfg/etSqwzgYNOYPrARx1BHUN052tGA=
|
||||||
github.com/prometheus-community/go-runit v0.1.0/go.mod h1:AvJ9Jo3gAFu2lbM4+qfjdpq30FfiLDJZKbQ015u08IQ=
|
github.com/prometheus-community/go-runit v0.1.0/go.mod h1:AvJ9Jo3gAFu2lbM4+qfjdpq30FfiLDJZKbQ015u08IQ=
|
||||||
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
|
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||||
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
|
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM=
|
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
|
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||||
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
|
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
||||||
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
|
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||||
github.com/prometheus/node_exporter v1.6.1 h1:Srqr6UAOUDnKhurvYGIYa7GZXuMCwJpzT9KP8uTJ4vw=
|
github.com/prometheus/node_exporter v1.9.1 h1:5PIaixeIW9WYDAymngAK2Ucg3yHbnbG2Fz5VZuoMgj4=
|
||||||
github.com/prometheus/node_exporter v1.6.1/go.mod h1:+zK+m9vwxu19JHl/kVVmixdCT6fWWHlmcOUHDFpkt0Y=
|
github.com/prometheus/node_exporter v1.9.1/go.mod h1:g6tnkDIRSFw3/UI59KRExdfmqlkLK95qzpT3+wTXarE=
|
||||||
github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
|
github.com/prometheus/procfs v0.15.2-0.20240603130017-1754b780536b h1:4EJkx3vycI+n5JY5ht+bnSUGamkmmXkpcNeO/OBT/0A=
|
||||||
github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
|
github.com/prometheus/procfs v0.15.2-0.20240603130017-1754b780536b/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||||
github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP0=
|
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||||
github.com/safchain/ethtool v0.3.0/go.mod h1:SA9BwrgyAqNo7M+uaL6IYbxpm5wk3L7Mm6ocLW+CJUs=
|
github.com/safchain/ethtool v0.5.10 h1:Im294gZtuf4pSGJRAOGKaASNi3wMeFaGaWuSaomedpc=
|
||||||
github.com/siebenmann/go-kstat v0.0.0-20210513183136-173c9b0a9973 h1:GfSdC6wKfTGcgCS7BtzF5694Amne1pGCSTY252WhlEY=
|
github.com/safchain/ethtool v0.5.10/go.mod h1:w9jh2Lx7YBR4UwzLkzCmWl85UY0W2uZdd7/DckVE5+c=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||||
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||||
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||||
@ -131,27 +158,38 @@ go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9i
|
|||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
|
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||||
|
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
|
||||||
|
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
||||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
|
||||||
|
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||||
|
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211031064116-611d5d643895/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211031064116-611d5d643895/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||||
|
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||||
|
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac h1:nUQEQmH/csSvFECKYRv6HWEyypysidKl2I6Qpsglq/0=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac h1:nUQEQmH/csSvFECKYRv6HWEyypysidKl2I6Qpsglq/0=
|
||||||
@ -162,16 +200,22 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
|
|||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
||||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
|
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
|
||||||
|
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
|
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
|
howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM=
|
||||||
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
|
howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
|
||||||
repositories.action2quare.com/ayo/gocommon v0.0.0-20240708060921-18d284a4ea85 h1:+mUz2LcDkv406BsXpGJRCWdeWB2zqMHunkM0sLtRhI4=
|
repositories.action2quare.com/ayo/gocommon v0.0.0-20250625075907-b6e187a0a747 h1:SJRRWoTKSj9hjzbEyKG55wW2YAHdxiT4cqLl1fJda9Y=
|
||||||
repositories.action2quare.com/ayo/gocommon v0.0.0-20240708060921-18d284a4ea85/go.mod h1:XA8+hQtUNh956T+kAbJKkUtMl5HUWj83knvdBvvPS5s=
|
repositories.action2quare.com/ayo/gocommon v0.0.0-20250625075907-b6e187a0a747/go.mod h1:q64I6gqlD61qwi9FfuPkwqy6Z6uzSHdcEjoHAJC27gQ=
|
||||||
|
repositories.action2quare.com/ayo/gocommon v0.0.0-20250701095003-d77fa2108add h1:V5XUI79yK4KPukSWkxJWgx4PsiejQTjoufiglZh2m7I=
|
||||||
|
repositories.action2quare.com/ayo/gocommon v0.0.0-20250701095003-d77fa2108add/go.mod h1:q64I6gqlD61qwi9FfuPkwqy6Z6uzSHdcEjoHAJC27gQ=
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
nohup /home/opdev/houston -client -logfile > /dev/null &
|
nohup ./houston -client -logfile > /dev/null &
|
||||||
|
|
||||||
|
|||||||
@ -6,8 +6,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
||||||
"repositories.action2quare.com/ayo/gocommon/flagx"
|
"repositories.action2quare.com/ayo/gocommon/flagx"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
"repositories.action2quare.com/ayo/houston/client"
|
"repositories.action2quare.com/ayo/houston/client"
|
||||||
|
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -21,9 +21,21 @@ func main() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
http.Handle("/metrics", promhttp.Handler())
|
http.Handle("/metrics", hc.MetricHandler())
|
||||||
server := &http.Server{Addr: ":9100", Handler: nil}
|
server := &http.Server{Addr: ":9200", Handler: nil}
|
||||||
go server.ListenAndServe()
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
logger.Println("metric server shutdown")
|
||||||
|
r := recover()
|
||||||
|
if r != nil {
|
||||||
|
logger.Println(r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
logger.Println("metric server start")
|
||||||
|
if err := server.ListenAndServe(); err != nil {
|
||||||
|
logger.Println("metric server cannot listen :", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
hc.Start()
|
hc.Start()
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
|||||||
@ -5,13 +5,14 @@ del houston.zip
|
|||||||
$Env:GOOS="linux"
|
$Env:GOOS="linux"
|
||||||
$Env:GOARCH="amd64"
|
$Env:GOARCH="amd64"
|
||||||
|
|
||||||
go get repositories.action2quare.com/ayo/gocommon
|
# go get repositories.action2quare.com/ayo/gocommon
|
||||||
go mod tidy
|
# go mod tidy
|
||||||
|
|
||||||
go build -ldflags="-s -w" -tags=client .
|
go build -ldflags="-s -w" -tags=client .
|
||||||
|
|
||||||
cp houston .\replacer\houston
|
cp houston .\replacer\houston
|
||||||
cp config.json .\replacer\config.json
|
cp config.json .\replacer\config.json
|
||||||
|
cp houston.sh .\replacer\houston.sh
|
||||||
|
|
||||||
cd replacer
|
cd replacer
|
||||||
go build -ldflags="-s -w" .
|
go build -ldflags="-s -w" .
|
||||||
@ -19,10 +20,12 @@ go build -ldflags="-s -w" .
|
|||||||
Compress-Archive -Path replacer -DestinationPath houston.zip -Force
|
Compress-Archive -Path replacer -DestinationPath houston.zip -Force
|
||||||
Compress-Archive -Path config.json -Update -DestinationPath houston.zip
|
Compress-Archive -Path config.json -Update -DestinationPath houston.zip
|
||||||
Compress-Archive -Path houston -Update -DestinationPath houston.zip
|
Compress-Archive -Path houston -Update -DestinationPath houston.zip
|
||||||
|
Compress-Archive -Path houston.sh -Update -DestinationPath houston.zip
|
||||||
|
|
||||||
del houston
|
del houston
|
||||||
del config.json
|
del config.json
|
||||||
del replacer
|
del replacer
|
||||||
|
del houston.sh
|
||||||
|
|
||||||
mv houston.zip ..\houston.zip
|
mv houston.zip ..\houston.zip
|
||||||
cd ..
|
cd ..
|
||||||
|
|||||||
@ -522,6 +522,34 @@ func (h *houstonHandler) GetLogFileLinks(w http.ResponseWriter, r *http.Request)
|
|||||||
enc.Encode(out)
|
enc.Encode(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *houstonHandler) GetDemoFileLink(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// <form action="/houston" method="post" enctype="multipart/form-data">
|
||||||
|
// <input type="text" name="name">
|
||||||
|
// <input type="text" name="version">
|
||||||
|
// <input type="text" name="filename">
|
||||||
|
// </form>
|
||||||
|
name := r.FormValue("name")
|
||||||
|
version := r.FormValue("version")
|
||||||
|
fileName := r.FormValue("filename")
|
||||||
|
logger.Println("GetDemoFileLink :", name, version, fileName)
|
||||||
|
|
||||||
|
if len(name) == 0 || len(version) == 0 || len(fileName) == 0 {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
demoFilePath := path.Join(h.downloadPath, name, version, fileName)
|
||||||
|
demoFileInfo, err := os.Stat(demoFilePath)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
out := []string{path.Join(sub_folder_name_downloads, name, version, demoFileInfo.Name())}
|
||||||
|
enc := json.NewEncoder(w)
|
||||||
|
enc.Encode(out)
|
||||||
|
}
|
||||||
|
|
||||||
func (h *houstonHandler) GetDeployingProgress(w http.ResponseWriter, r *http.Request) {
|
func (h *houstonHandler) GetDeployingProgress(w http.ResponseWriter, r *http.Request) {
|
||||||
json.NewEncoder(w).Encode(h.Operation().DeplyingProgress())
|
json.NewEncoder(w).Encode(h.Operation().DeplyingProgress())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,6 @@ package server
|
|||||||
import (
|
import (
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -14,13 +13,14 @@ import (
|
|||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"repositories.action2quare.com/ayo/gocommon"
|
||||||
"repositories.action2quare.com/ayo/gocommon/flagx"
|
"repositories.action2quare.com/ayo/gocommon/flagx"
|
||||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HoustonServerWithHandler interface {
|
type HoustonServerWithHandler interface {
|
||||||
HoustonServer
|
HoustonServer
|
||||||
RegisterHandlers(serveMux *http.ServeMux, prefix string) error
|
RegisterHandlers(serveMux gocommon.ServerMuxInterface, prefix string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type houstonHandler struct {
|
type houstonHandler struct {
|
||||||
@ -45,7 +45,7 @@ func NewHoustonHandler() HoustonServerWithHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *houstonHandler) RegisterHandlers(serveMux *http.ServeMux, prefix string) error {
|
func (h *houstonHandler) RegisterHandlers(serveMux gocommon.ServerMuxInterface, prefix string) error {
|
||||||
config := loadServerConfig()
|
config := loadServerConfig()
|
||||||
storagePath := config.StorageRoot
|
storagePath := config.StorageRoot
|
||||||
h.deployPath = path.Join(storagePath, sub_folder_name_deploys)
|
h.deployPath = path.Join(storagePath, sub_folder_name_deploys)
|
||||||
@ -93,24 +93,27 @@ func (h *houstonHandler) RegisterHandlers(serveMux *http.ServeMux, prefix string
|
|||||||
// config는 접근하기 편하게 단축 경로 제공
|
// config는 접근하기 편하게 단축 경로 제공
|
||||||
serveMux.HandleFunc("/config/", func(w http.ResponseWriter, r *http.Request) {
|
serveMux.HandleFunc("/config/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
logger.Println("config url.path :", r.URL.Path)
|
logger.Println("config url.path :", r.URL.Path)
|
||||||
h := md5.New()
|
testhash := md5.New()
|
||||||
h.Write([]byte(r.URL.Path))
|
testhash.Write([]byte(r.URL.Path))
|
||||||
at := hex.EncodeToString(h.Sum(nil))
|
at := hex.EncodeToString(testhash.Sum(nil))
|
||||||
hash := r.Header.Get("As-X-UrlHash")
|
hash := r.Header.Get("As-X-UrlHash")
|
||||||
logger.Println("config at = hash :", at, hash)
|
logger.Println("config at = hash :", at, hash)
|
||||||
if at == hash {
|
if at == hash {
|
||||||
urlpath := strings.TrimPrefix(r.URL.Path, "/config/")
|
urlpath := strings.TrimPrefix(r.URL.Path, "/config/")
|
||||||
dir := path.Dir(urlpath)
|
dir := path.Dir(urlpath)
|
||||||
file := path.Base(urlpath)
|
file := path.Base(urlpath)
|
||||||
dest := fmt.Sprintf("%s/config/%s", dir, file)
|
sourceFile := path.Join(h.deployPath, dir, "config", file)
|
||||||
logger.Println("config dest :", dest)
|
logger.Println("config dest :", sourceFile)
|
||||||
r2 := new(http.Request)
|
bt, err := os.ReadFile(sourceFile)
|
||||||
*r2 = *r
|
if err != nil && !os.IsExist(err) {
|
||||||
r2.URL = new(url.URL)
|
logger.Println("config file is missing :", sourceFile)
|
||||||
*r2.URL = *r.URL
|
w.WriteHeader(http.StatusNotFound)
|
||||||
r2.URL.Path = dest
|
} else {
|
||||||
r2.URL.RawPath = dest
|
if _, err = w.Write(bt); err != nil {
|
||||||
fsx.ServeHTTP(w, r2)
|
logger.Println("config write failed :", err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
}
|
}
|
||||||
@ -169,37 +172,37 @@ func (h *houstonHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
r.Body.Close()
|
r.Body.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var userinfo map[string]any
|
// var userinfo map[string]any
|
||||||
if !*noauth && (*authtype == "on" || *authtype == "both") {
|
// if !*noauth && (*authtype == "on" || *authtype == "both") {
|
||||||
authheader := r.Header.Get("Authorization")
|
// authheader := r.Header.Get("Authorization")
|
||||||
if len(authheader) == 0 {
|
// if len(authheader) == 0 {
|
||||||
logger.Println("Authorization header is not valid :", authheader)
|
// logger.Println("Authorization header is not valid :", authheader)
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
// w.WriteHeader(http.StatusBadRequest)
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
req, _ := http.NewRequest("GET", "https://graph.microsoft.com/oidc/userinfo", nil)
|
// req, _ := http.NewRequest("GET", "https://graph.microsoft.com/oidc/userinfo", nil)
|
||||||
req.Header.Add("Authorization", authheader)
|
// req.Header.Add("Authorization", authheader)
|
||||||
client := &http.Client{}
|
// client := &http.Client{}
|
||||||
|
|
||||||
resp, err := client.Do(req)
|
// resp, err := client.Do(req)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
logger.Println("graph microsoft api call failed :", err)
|
// logger.Println("graph microsoft api call failed :", err)
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
// w.WriteHeader(http.StatusBadRequest)
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
defer resp.Body.Close()
|
// defer resp.Body.Close()
|
||||||
|
|
||||||
raw, _ := io.ReadAll(resp.Body)
|
// raw, _ := io.ReadAll(resp.Body)
|
||||||
if err = json.Unmarshal(raw, &userinfo); err != nil {
|
// if err = json.Unmarshal(raw, &userinfo); err != nil {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
if _, expired := userinfo["error"]; expired {
|
// if _, expired := userinfo["error"]; expired {
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
// w.WriteHeader(http.StatusUnauthorized)
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
var operation string
|
var operation string
|
||||||
if r.Method == "POST" {
|
if r.Method == "POST" {
|
||||||
|
|||||||
Reference in New Issue
Block a user