|
|
@@ -0,0 +1,180 @@
|
|
|
+package namedpipe
|
|
|
+
|
|
|
+import (
|
|
|
+ "fmt"
|
|
|
+ "github.com/coroot/coroot-node-agent/containers"
|
|
|
+ "github.com/coroot/coroot-node-agent/utils"
|
|
|
+ "github.com/coroot/coroot-node-agent/utils/enums"
|
|
|
+ log "github.com/sirupsen/logrus"
|
|
|
+ "io"
|
|
|
+ "path/filepath"
|
|
|
+ "runtime/debug"
|
|
|
+ "sync"
|
|
|
+ "time"
|
|
|
+)
|
|
|
+
|
|
|
+type NamedPipeCtl struct {
|
|
|
+ mtx *sync.Mutex
|
|
|
+ stopChan chan struct{}
|
|
|
+ isClosed bool
|
|
|
+ namedPipe NamedPipe
|
|
|
+}
|
|
|
+
|
|
|
+func NewNamedPipeCtl(stopChan chan struct{}) (*NamedPipeCtl, error) {
|
|
|
+ ctl := &NamedPipeCtl{
|
|
|
+ mtx: new(sync.Mutex),
|
|
|
+ stopChan: stopChan,
|
|
|
+ }
|
|
|
+ err := ctl.initNamedPipe()
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ return ctl, nil
|
|
|
+}
|
|
|
+
|
|
|
+func (ctl *NamedPipeCtl) initNamedPipe() error {
|
|
|
+
|
|
|
+ if ctl.isClosed {
|
|
|
+ log.Warnf("namedpipectl has been closed, return before try to listen namedpipe")
|
|
|
+ return fmt.Errorf("namedpipectl has been closed")
|
|
|
+ }
|
|
|
+
|
|
|
+ ctl.namedPipe = nil
|
|
|
+ errChan := make(chan error)
|
|
|
+ t := time.NewTimer(enums.TimeoutNamedPipe3S * time.Second)
|
|
|
+ defer utils.StopTimerWithDrainChan(t)
|
|
|
+ go func() {
|
|
|
+ defer ctl.recoverAndLogError("ListenNpipe")
|
|
|
+
|
|
|
+ log.Infof("namedpipectl to listen namedpipe")
|
|
|
+ //RootPath => /opt/cloudwise/omniagent/agents/apm/current/
|
|
|
+ p, err := ListenNpipe(enums.AgentNameEuspace, enums.AgentNameOneAgent, false, false, filepath.Join(filepath.Dir(filepath.Dir(filepath.Dir(utils.GetRootPath()))), "runtime"))
|
|
|
+ if err != nil || p == nil {
|
|
|
+ log.Errorf("namedpipectl to listen namedpipe,occurs error:%s ", err.Error())
|
|
|
+ errChan <- fmt.Errorf("namedpipectl to listen namedpipe error: %v", err.Error())
|
|
|
+ } else {
|
|
|
+ log.Infof("namedpipectl listen namedpipe success")
|
|
|
+ ctl.mtx.Lock()
|
|
|
+ if ctl.isClosed {
|
|
|
+ ctl.mtx.Unlock()
|
|
|
+ log.Infof("namedpipectl has been closed, will to free namedpipe")
|
|
|
+ if p != nil {
|
|
|
+ p.FreeUp4EOF()
|
|
|
+ }
|
|
|
+ errChan <- fmt.Errorf("namedpipectl has been closed,freed")
|
|
|
+ } else {
|
|
|
+ ctl.namedPipe = p
|
|
|
+ ctl.mtx.Unlock()
|
|
|
+ errChan <- nil
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }()
|
|
|
+
|
|
|
+ select {
|
|
|
+ case err := <-errChan:
|
|
|
+ return err
|
|
|
+ case <-t.C:
|
|
|
+ ctl.Close()
|
|
|
+ log.Errorf("namedpipectl to listen namedpipe timeout (%v s)", enums.TimeoutNamedPipe3S)
|
|
|
+ return fmt.Errorf("namedpipectl to listen namedpipe timeout")
|
|
|
+ case <-ctl.stopChan:
|
|
|
+ ctl.Close()
|
|
|
+ log.Infof("euspace stopping,close namedpipectl")
|
|
|
+ return fmt.Errorf("euspace was stoped")
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (ctl *NamedPipeCtl) Close() {
|
|
|
+ ctl.mtx.Lock()
|
|
|
+ defer ctl.mtx.Unlock()
|
|
|
+ if ctl.isClosed {
|
|
|
+ log.Warn("namedPipeCtl has been closed")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ ctl.isClosed = true
|
|
|
+ if ctl.namedPipe != nil {
|
|
|
+ ctl.namedPipe.FreeUp4EOF()
|
|
|
+ ctl.namedPipe = nil
|
|
|
+ log.Info("namedPipeCtl namedPipe is closed")
|
|
|
+ } else {
|
|
|
+ log.Warn("namedPipeCtl namedPipe is nil, do nothing")
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (ctl *NamedPipeCtl) recoverAndLogError(target string) {
|
|
|
+ if i := recover(); i != nil {
|
|
|
+ //获取错误消息
|
|
|
+ eMsg := ""
|
|
|
+ switch v := i.(type) {
|
|
|
+ case string:
|
|
|
+ eMsg = v
|
|
|
+ case error:
|
|
|
+ eMsg = v.Error()
|
|
|
+ default:
|
|
|
+ eMsg = fmt.Sprintf("%+v", v)
|
|
|
+ }
|
|
|
+ sMsg := string(debug.Stack())
|
|
|
+ log.Errorf("goroutine[ %s ] panic: %s ,stack: %s", target, eMsg, sMsg)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (ctl *NamedPipeCtl) AcceptAndDisposeMsg(reg *containers.Registry) {
|
|
|
+ log.Info("namedPipeCtl start listen and dispose msg")
|
|
|
+ go func() {
|
|
|
+ defer func() {
|
|
|
+ ctl.recoverAndLogError("AcceptAndDisposeMsg")
|
|
|
+ log.Info("namedPipeCtl stop listen and dispose msg")
|
|
|
+ }()
|
|
|
+
|
|
|
+ for {
|
|
|
+
|
|
|
+ if ctl.isClosed {
|
|
|
+ log.Errorf("AcceptAndDisposeMsg namedPipeCtl has been closed, stop accept msg.")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if ctl.namedPipe == nil {
|
|
|
+ if err := ctl.initNamedPipe(); err != nil {
|
|
|
+ log.Errorf("AcceptAndDisposeMsg re-initNamedPipe occurs error: %s", err.Error())
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if ctl.stopChan != nil {
|
|
|
+ select {
|
|
|
+ case <-ctl.stopChan:
|
|
|
+ log.Warnf("AcceptAndDisposeMsg euspace stopping, stop accept msg")
|
|
|
+ return
|
|
|
+ default:
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if msg, err := ctl.namedPipe.Accept(); err != nil {
|
|
|
+ if err == io.EOF {
|
|
|
+ log.Warnf("AcceptAndDisposeMsg get io.EOF,will re-initNamedPipe")
|
|
|
+ ctl.mtx.Lock()
|
|
|
+ ctl.namedPipe.FreeUp4EOF()
|
|
|
+ ctl.namedPipe = nil
|
|
|
+ ctl.mtx.Unlock()
|
|
|
+ if err := ctl.initNamedPipe(); err != nil {
|
|
|
+ log.Errorf("AcceptAndDisposeMsg get io.EOF,re-initNamedPipe occurs error: %s", err.Error())
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ log.Errorf("AcceptAndDisposeMsg occurs error: %s", err.Error())
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if ctl.isClosed {
|
|
|
+ log.Errorf("AcceptAndDisposeMsg namedPipeCtl has been closed, stop dispose msg :%#v", msg)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ switch msg.Type {
|
|
|
+ case MsgTypeFusing:
|
|
|
+ reg.DoFusing()
|
|
|
+ case MsgTypeResume:
|
|
|
+ if err := reg.DoResume(); err != nil {
|
|
|
+ log.Fatalf("AcceptAndDisposeMsg DoResume occurs error: %s", err.Error())
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }()
|
|
|
+}
|