Add LowCollector & rename Supervisor to Monitoring sandbox/SebD/dev_supervisor_als_2019
authorSebastien Douheret <sebastien.douheret@iot.bzh>
Sat, 13 Jul 2019 08:21:53 +0000 (10:21 +0200)
committerSebastien Douheret <sebastien.douheret@iot.bzh>
Sun, 14 Jul 2019 12:06:14 +0000 (14:06 +0200)
Change-Id: Ibd78f1200ed71b0100ebd48dddb9236377e2fb36
Signed-off-by: Sebastien Douheret <sebastien.douheret@iot.bzh>
28 files changed:
.vscode/settings.json
Makefile
lib/agent/agent.go
lib/agent/apiv1-monitoring.go [new file with mode: 0644]
lib/agent/apiv1-supervisor.go [deleted file]
lib/agent/apiv1.go
lib/agent/xds-low-collector.go [new file with mode: 0644]
lib/agent/xdsmonitoring.go [moved from lib/agent/xdssupervior.go with 69% similarity]
lib/aglafb/afb.go [new file with mode: 0644]
lib/xdsconfig/config.go
lib/xdsconfig/configfile.go
webapp/src/app/@core-xds/services/@core-xds-services.module.ts
webapp/src/app/@core-xds/services/monitoring.service.ts [new file with mode: 0644]
webapp/src/app/@core-xds/services/supervision.service.ts [deleted file]
webapp/src/app/@core-xds/services/xdsagent.service.ts
webapp/src/app/pages/config/config-global/config-global.component.html
webapp/src/app/pages/monitoring/monitoring-config.component.html [new file with mode: 0644]
webapp/src/app/pages/monitoring/monitoring-config.component.scss [moved from webapp/src/app/pages/supervision/supervision-config.component.scss with 95% similarity]
webapp/src/app/pages/monitoring/monitoring-config.component.ts [moved from webapp/src/app/pages/supervision/supervision-config.component.ts with 70% similarity]
webapp/src/app/pages/monitoring/monitoring.component.html [moved from webapp/src/app/pages/supervision/supervision.component.html with 96% similarity]
webapp/src/app/pages/monitoring/monitoring.component.scss [moved from webapp/src/app/pages/supervision/supervision.component.scss with 100% similarity]
webapp/src/app/pages/monitoring/monitoring.component.ts [moved from webapp/src/app/pages/supervision/supervision.component.ts with 86% similarity]
webapp/src/app/pages/monitoring/monitoring.module.ts [moved from webapp/src/app/pages/supervision/supervision.module.ts with 78% similarity]
webapp/src/app/pages/pages-menu.ts
webapp/src/app/pages/pages-routing.module.ts
webapp/src/app/pages/pages.module.ts
webapp/src/app/pages/supervision/supervision-config.component.html [deleted file]
webapp/tslint.json

index 59cafea..84bb4a3 100644 (file)
@@ -56,6 +56,7 @@
     "WSID",
     "XDSSUPERV",
     "abortinstall",
+    "aglafb",
     "apiv",
     "cmdi",
     "conv",
index 273458f..fe8c9ec 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -149,7 +149,7 @@ else
        @echo "Skipping webapp build (SKIP_WEBAPP_BUILD var is set)"
 endif
 
-webapp/debug:
+webapp/debug dev-frontend devf:
        cd webapp && npm run watch
 
 webapp/install:
index 506976d..e90c1a0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017-2018 "IoT.bzh"
+ * Copyright (C) 2017-2019 "IoT.bzh"
  * Author Sebastien Douheret <sebastien@iot.bzh>
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -47,12 +47,13 @@ type Context struct {
        SThgCmd       *exec.Cmd
        SThgInotCmd   *exec.Cmd
 
-       webServer     *WebServer
-       xdsServers    map[string]*XdsServer
-       XdsSupervisor *XdsSupervisor
-       sessions      *Sessions
-       events        *Events
-       projects      *Projects
+       webServer       *WebServer
+       xdsServers      map[string]*XdsServer
+       XdsMonitoring   *XdsMonitoring
+       XdsLowCollector *XdsLowCollector
+       sessions        *Sessions
+       events          *Events
+       projects        *Projects
 
        Exit chan os.Signal
 }
diff --git a/lib/agent/apiv1-monitoring.go b/lib/agent/apiv1-monitoring.go
new file mode 100644 (file)
index 0000000..cf651ce
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2017-2019 "IoT.bzh"
+ * Author Sebastien Douheret <sebastien@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package agent
+
+import (
+       "net/http"
+
+       "gerrit.automotivelinux.org/gerrit/src/xds/xds-agent.git/lib/aglafb"
+       common "gerrit.automotivelinux.org/gerrit/src/xds/xds-common.git"
+       "github.com/gin-gonic/gin"
+)
+
+//************************* AGL XDS Monitoring *************************
+
+// getMonitoringTopo : return current AGL daemons topology using monitoring
+func (s *APIService) getMonitoringTopo(c *gin.Context) {
+
+       xdspvr, err := s._initXdsMonitoring()
+       if err != nil {
+               common.APIError(c, err.Error())
+               return
+       }
+
+       var res aglafb.AfbReply
+       if err = xdspvr.GetTopo(&res); err != nil {
+               common.APIError(c, err.Error())
+               return
+       }
+
+       if res.Request.Status != "success" {
+               common.APIError(c, res.Request.Info)
+               return
+       }
+
+       c.JSON(http.StatusOK, res.Response)
+}
+
+// startMonitoring : resquest to monitoring to start tracing
+func (s *APIService) startMonitoring(c *gin.Context) {
+
+       xdspvr, err := s._initXdsMonitoring()
+       if err != nil {
+               common.APIError(c, err.Error())
+               return
+       }
+
+       var cfg XdsSuperVTraceConfig
+       if c.BindJSON(&cfg) != nil {
+               common.APIError(c, "Invalid config argument")
+               return
+       }
+       s.Log.Debugf("Start Monitoring cfgArg %v", cfg)
+
+       res := aglafb.NewAfbReply()
+       if err = xdspvr.StartTrace(cfg, res); err != nil {
+               common.APIError(c, err.Error())
+               return
+       }
+
+       if !res.Success() {
+               common.APIError(c, res.GetInfo())
+               return
+       }
+
+       c.JSON(http.StatusOK, res.Response)
+}
+
+// stopMonitoring : resquest to monitoring to stop tracing
+func (s *APIService) stopMonitoring(c *gin.Context) {
+
+       xdspvr, err := s._initXdsMonitoring()
+       if err != nil {
+               common.APIError(c, err.Error())
+               return
+       }
+
+       var res aglafb.AfbReply
+       if err = xdspvr.StopTrace(&res); err != nil {
+               common.APIError(c, err.Error())
+               return
+       }
+
+       if res.Request.Status != "success" {
+               common.APIError(c, res.Request.Info)
+               return
+       }
+
+       c.JSON(http.StatusOK, res.Response)
+}
+
+// _initXdsMonitoring .
+func (s *APIService) _initXdsMonitoring() (*XdsMonitoring, error) {
+
+       if s.XdsMonitoring == nil {
+               xs := NewXdsMonitoring(s.Context)
+               if err := xs.Connect(); err != nil {
+                       return nil, err
+               }
+               s.XdsMonitoring = xs
+       }
+       return s.XdsMonitoring, nil
+}
+
+//*************************  AGL Low Collector *************************
+
+// XdsLowCollectorConfig Configuration structure for ALC
+type XdsLowCollectorConfig struct {
+       Time int `json:"time"`
+}
+
+// StartLowCollector : resquest to Start low collector
+func (s *APIService) StartLowCollector(c *gin.Context) {
+
+       alc, err := s._initXdsLowCollector()
+       if err != nil {
+               common.APIError(c, err.Error())
+               return
+       }
+
+       s.Log.Debugf("Init & config AGL Low Collector")
+
+       if err = alc.Init(); err != nil {
+               common.APIError(c, err.Error())
+               return
+       }
+
+       // // Config is optional, if not set used define settings
+       var cfg XdsLowCollectorConfig
+       c.ShouldBindJSON(&cfg)
+
+       s.Log.Debugf("Start Low Collector cfgArg %v", cfg)
+
+       if err = alc.Start(cfg.Time); err != nil {
+               common.APIError(c, err.Error())
+               return
+       }
+
+       c.JSON(http.StatusOK, "done")
+}
+
+// StopLowCollector : resquest to Stop low collector
+func (s *APIService) StopLowCollector(c *gin.Context) {
+
+       alc, err := s._initXdsLowCollector()
+       if err != nil {
+               common.APIError(c, err.Error())
+               return
+       }
+
+       s.Log.Debugf("Stop AGL Low Collector")
+
+       if err = alc.Stop(); err != nil {
+               common.APIError(c, err.Error())
+       }
+
+       // SEB TODO
+       res := "done"
+       c.JSON(http.StatusOK, res)
+}
+
+// ReadLowCollector : read one data
+func (s *APIService) ReadLowCollector(c *gin.Context) {
+
+       alc, err := s._initXdsLowCollector()
+       if err != nil {
+               common.APIError(c, err.Error())
+               return
+       }
+       plugin := "cpu"
+       s.Log.Debugf("Read data of %s plugin AGL Low Collector", plugin)
+
+       var data interface{}
+       if err = alc.Read(&data); err != nil {
+               common.APIError(c, err.Error())
+       }
+
+       // SEB TODO
+       res := "done"
+       c.JSON(http.StatusOK, res)
+}
+
+// ResetLowCollector : Reset Low Collector
+func (s *APIService) ResetLowCollector(c *gin.Context) {
+       // SEB TODO
+       common.APIError(c, "Not implemented yet")
+}
+
+// _initXdsLowCollector .
+func (s *APIService) _initXdsLowCollector() (*XdsLowCollector, error) {
+
+       if s.XdsLowCollector == nil {
+               alc := NewXdsLowCollector(s.Context)
+               if err := alc.Connect(); err != nil {
+                       return nil, err
+               }
+               s.XdsLowCollector = alc
+       }
+       return s.XdsLowCollector, nil
+}
diff --git a/lib/agent/apiv1-supervisor.go b/lib/agent/apiv1-supervisor.go
deleted file mode 100644 (file)
index 20b9549..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2017-2018 "IoT.bzh"
- * Author Sebastien Douheret <sebastien@iot.bzh>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package agent
-
-import (
-       "net/http"
-
-       common "gerrit.automotivelinux.org/gerrit/src/xds/xds-common.git"
-       "github.com/gin-gonic/gin"
-)
-
-// getSupervisorTopo : return current AGL daemons topology using supervisor
-func (s *APIService) getSupervisorTopo(c *gin.Context) {
-
-       xdspvr, err := s._initXdsSupervisor()
-       if err != nil {
-               common.APIError(c, err.Error())
-               return
-       }
-
-       var res XdsSuperVReply
-       if err = xdspvr.GetTopo(&res); err != nil {
-               common.APIError(c, err.Error())
-               return
-       }
-
-       if res.Request.Status != "success" {
-               common.APIError(c, res.Request.Info)
-               return
-       }
-
-       c.JSON(http.StatusOK, res.Response)
-}
-
-// startSupervisor : resquest to supervisor to start tracing
-func (s *APIService) startSupervisor(c *gin.Context) {
-
-       xdspvr, err := s._initXdsSupervisor()
-       if err != nil {
-               common.APIError(c, err.Error())
-               return
-       }
-
-       var cfg XdsSuperVTraceConfig
-       if c.BindJSON(&cfg) != nil {
-               common.APIError(c, "Invalid config argument")
-               return
-       }
-       s.Log.Debugf("Start Supervisor cfgArg %v\n", cfg)
-
-       var res XdsSuperVReply
-       if err = xdspvr.StartTrace(cfg, &res); err != nil {
-               common.APIError(c, err.Error())
-               return
-       }
-
-       if res.Request.Status != "success" {
-               common.APIError(c, res.Request.Info)
-               return
-       }
-
-       c.JSON(http.StatusOK, res.Response)
-}
-
-// stopSupervisor : resquest to supervisor to stop tracing
-func (s *APIService) stopSupervisor(c *gin.Context) {
-
-       xdspvr, err := s._initXdsSupervisor()
-       if err != nil {
-               common.APIError(c, err.Error())
-               return
-       }
-
-       var res XdsSuperVReply
-       if err = xdspvr.StopTrace(&res); err != nil {
-               common.APIError(c, err.Error())
-               return
-       }
-
-       if res.Request.Status != "success" {
-               common.APIError(c, res.Request.Info)
-               return
-       }
-
-       c.JSON(http.StatusOK, res.Response)
-}
-
-// _initXdsSupervisor .
-func (s *APIService) _initXdsSupervisor() (*XdsSupervisor, error) {
-
-       if s.XdsSupervisor == nil {
-               xs := NewXdsSupervisor(s.Context)
-               if err := xs.Connect(); err != nil {
-                       return nil, err
-               }
-               s.XdsSupervisor = xs
-       }
-       return s.XdsSupervisor, nil
-}
index 4637bc4..ef9704c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017-2018 "IoT.bzh"
+ * Copyright (C) 2017-2019 "IoT.bzh"
  * Author Sebastien Douheret <sebastien@iot.bzh>
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -67,9 +67,13 @@ func NewAPIV1(ctx *Context) *APIService {
        s.apiRouter.POST("/events/register", s.eventsRegister)
        s.apiRouter.POST("/events/unregister", s.eventsUnRegister)
 
-       s.apiRouter.GET("/supervisor/topo", s.getSupervisorTopo)
-       s.apiRouter.POST("/supervisor/trace/start", s.startSupervisor)
-       s.apiRouter.POST("/supervisor/trace/stop", s.stopSupervisor)
+       s.apiRouter.GET("/monitoring/topo", s.getMonitoringTopo)
+       s.apiRouter.POST("/monitoring/trace/start", s.startMonitoring)
+       s.apiRouter.POST("/monitoring/trace/stop", s.stopMonitoring)
+       s.apiRouter.POST("/monitoring/alc/start", s.StartLowCollector)
+       s.apiRouter.POST("/monitoring/alc/stop", s.StopLowCollector)
+       s.apiRouter.GET("/monitoring/alc/read", s.ReadLowCollector)
+       s.apiRouter.POST("/monitoring/alc/reset", s.ResetLowCollector)
        return s
 }
 
diff --git a/lib/agent/xds-low-collector.go b/lib/agent/xds-low-collector.go
new file mode 100644 (file)
index 0000000..fdf696d
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2019 "IoT.bzh"
+ * Author Sebastien Douheret <sebastien@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package agent
+
+import (
+       "fmt"
+       "io"
+       "strings"
+       "time"
+
+       "gerrit.automotivelinux.org/gerrit/src/xds/xds-agent.git/lib/aglafb"
+       common "gerrit.automotivelinux.org/gerrit/src/xds/xds-common.git"
+       uuid "github.com/satori/go.uuid"
+)
+
+// XdsLowCollector .
+type XdsLowCollector struct {
+       *Context
+       ID                 string
+       BaseURL            string
+       ConnRetry          int
+       Connected          bool
+       Disabled           bool
+       DefaultPlugins     []string
+       DefaultCollectTime int
+       // Private fields
+       client      *common.HTTPClient
+       logOut      io.Writer
+       cbOnConnect OnConnectedXdsAlcCB
+}
+
+// OnConnectedXdsAlcCB connect callback
+type OnConnectedXdsAlcCB func(svr *XdsLowCollector) error
+
+// NewXdsLowCollector creates an instance of XdsLowCollector
+func NewXdsLowCollector(ctx *Context) *XdsLowCollector {
+       return &XdsLowCollector{
+               Context:   ctx,
+               ID:        "XdsAlc-" + uuid.NewV1().String(),
+               BaseURL:   ctx.Config.FileConf.ProfileConf.XDSLowCollector.URL,
+               ConnRetry: ctx.Config.FileConf.ProfileConf.XDSLowCollector.ConnRetry,
+               Connected: false,
+               Disabled:  false,
+               logOut:    ctx.Log.Out,
+               DefaultPlugins: []string{
+                       "cpu",
+                       "memory",
+                       // SEB "processes",
+                       //"cpufreq",
+                       //"thermal",
+                       //"systemd_journal",
+                       // SEB "systemd_file",
+               },
+               DefaultCollectTime: 5,
+       }
+}
+
+// Connect Establish HTTP connection with XDS Low Collector Dameon
+func (xs *XdsLowCollector) Connect() error {
+       var err error
+       var retry int
+
+       xs.Disabled = false
+       xs.Connected = false
+
+       err = nil
+       for retry = xs.ConnRetry; retry > 0; retry-- {
+               if err = xs._CreateConnectHTTP(); err == nil {
+                       break
+               }
+               if retry == xs.ConnRetry {
+                       // Notify only on the first conn error
+                       // doing that avoid 2 notifs (conn false; conn true) on startup
+                       xs._NotifyState()
+               }
+               xs.Log.Infof("Establishing connection to XDS Low Collector daemon (retry %d/%d)", retry, xs.ConnRetry)
+               time.Sleep(time.Second)
+       }
+       if retry == 0 {
+               // FIXME: re-use _Reconnect to wait longer in background
+               return fmt.Errorf("Connection to XDS Low Collector daemon failure")
+       }
+       if err != nil {
+               return err
+       }
+
+       // Check HTTP connection and establish WS connection
+       err = xs._Connect(false)
+
+       return err
+}
+
+// ConnectOn Register a callback on events reception
+func (xs *XdsLowCollector) ConnectOn(f OnConnectedXdsAlcCB) error {
+       xs.cbOnConnect = f
+       return nil
+}
+
+// GetVersion Send Get request to retrieve XDS Low Collector version
+func (xs *XdsLowCollector) GetVersion(res interface{}) error {
+       // FIXME add suffix URLSuffix in common HTTP client lib instead of _BuildURL
+       return xs.client.Get(xs._BuildURL("/version"), &res)
+}
+
+// Init Initialize collector plugins
+func (xs *XdsLowCollector) Init() error {
+       var err error
+
+       // Directly send config in order to init and config plugins
+
+       type alcCfgPluginT struct {
+               Plugin string `json:"plugin"`
+               Config string `json:"config"`
+       }
+
+       cfg := []alcCfgPluginT{}
+
+       for _, p := range xs.DefaultPlugins {
+               cfg = append(cfg, alcCfgPluginT{
+                       Plugin: p,
+                       Config: "default",
+               })
+       }
+
+       res := aglafb.NewAfbReply()
+       xs.Log.Debugf("Low Collector /config %v", cfg)
+       err = xs.client.Post(xs._BuildURL("/config"), cfg, res)
+
+       if err == nil && !res.Success() {
+               err = res.GetError()
+       }
+
+       return err
+}
+
+// Start data collection
+func (xs *XdsLowCollector) Start(time int) error {
+       var err error
+
+       // TODO - SEB : support start one or multiple plugins
+
+       if time == 0 {
+               time = xs.DefaultCollectTime
+       }
+
+       type alcStartT struct {
+               Plugin string `json:"plugin"`
+               Time   int    `json:"time"`
+       }
+
+       // TODO SEB : allow to start only 1 plugin
+       allInOne := true
+       if allInOne {
+
+               cfg := []alcStartT{}
+               for _, p := range xs.DefaultPlugins {
+                       cfg = append(cfg, alcStartT{Plugin: p, Time: time})
+               }
+
+               res := aglafb.NewAfbReply()
+               xs.Log.Debugf("Low Collector /start %v", cfg)
+               err = xs.client.Post(xs._BuildURL("/start"), cfg, res)
+
+               if err == nil && !res.Success() {
+                       err = res.GetError()
+               }
+       } else {
+               for _, p := range xs.DefaultPlugins {
+                       cfg := alcStartT{Plugin: p, Time: time}
+
+                       res := aglafb.NewAfbReply()
+                       xs.Log.Debugf("Low Collector /start %v", cfg)
+                       err = xs.client.Post(xs._BuildURL("/start"), cfg, res)
+                       if err != nil {
+                               return err
+                       }
+                       if !res.Success() {
+                               return res.GetError()
+                       }
+               }
+       }
+
+       return err
+}
+
+// Stop data collection
+func (xs *XdsLowCollector) Stop() error {
+
+       // TODO - SEB : support start one or multiple plugins
+
+       type alcStopT struct {
+               Plugin []string `json:"plugin"`
+       }
+
+       cfg := alcStopT{}
+       for _, p := range xs.DefaultPlugins {
+               cfg.Plugin = append(cfg.Plugin, p)
+       }
+
+       res := aglafb.NewAfbReply()
+       xs.Log.Debugf("Low Collector /stop %v", cfg)
+       err := xs.client.Post(xs._BuildURL("/stop"), cfg, res)
+
+       if err == nil && !res.Success() {
+               err = res.GetError()
+       }
+
+       return err
+}
+
+// Read a single data of a specific plugin
+func (xs *XdsLowCollector) Read(data interface{}) error {
+       return fmt.Errorf("No implemented")
+}
+
+/***
+** Private functions
+***/
+
+// _BuildURL .
+func (xs *XdsLowCollector) _BuildURL(url string) string {
+       return url + "?token=HELLO&uuid=magic"
+}
+
+// Create HTTP client
+func (xs *XdsLowCollector) _CreateConnectHTTP() error {
+       var err error
+       // FIXME SEB - Client key not in header but in cookie
+       // temporary workaround: used _BuildURL to append uuid=magic in URL
+       // map[Set-Cookie:[x-afb-uuid-5678=2b185cc3-276b-4097-91fa-d607eaf937e6; Path=/api; Max-Age=32000000; ...
+       //port := strings.Split(xs.BaseURL, ":")[2]
+       //"x-afb-uuid-" + port
+
+       xs.client, err = common.HTTPNewClient(xs.BaseURL,
+               common.HTTPClientConfig{
+                       //HeaderClientKeyName: "Xds-Sid",
+                       HeaderAPIKeyName: "token",
+                       Apikey:           "HELLO",
+                       URLPrefix:        "/api/alc",
+                       CsrfDisable:      true,
+                       LogOut:           xs.logOut,
+                       LogPrefix:        "XDSALC: ",
+                       LogLevel:         common.HTTPLogLevelWarning,
+               })
+
+       xs.client.SetLogLevel(xs.Log.Level.String())
+
+       if err != nil {
+               msg := ": " + err.Error()
+               if strings.Contains(err.Error(), "connection refused") {
+                       msg = fmt.Sprintf("(url: %s)", xs.BaseURL)
+               }
+               return fmt.Errorf("ERROR: cannot connect to XDS Low Collector %s", msg)
+       }
+       if xs.client == nil {
+               return fmt.Errorf("ERROR: cannot connect to XDS Low Collector (null client)")
+       }
+
+       return nil
+}
+
+// _Connect Established HTTP and WS connection
+func (xs *XdsLowCollector) _Connect(reConn bool) error {
+       var res interface{}
+       if err := xs.client.Get(xs._BuildURL("/ping"), &res); err != nil {
+
+               // SEB FIXME tempo Hack
+               time.Sleep(time.Microsecond * 300)
+               if err := xs.client.Get(xs._BuildURL("/ping"), &res); err != nil {
+                       // SEB Hack tempo
+                       // xs.Connected = false
+                       // if !reConn {
+                       //      xs._NotifyState()
+                       // }
+                       // return err
+               }
+       }
+
+       xs.Connected = true
+
+       // Call OnConnect callback
+       if xs.cbOnConnect != nil {
+               xs.cbOnConnect(xs)
+       }
+
+       xs._NotifyState()
+       return nil
+}
+
+// _NotifyState Send event to notify changes
+func (xs *XdsLowCollector) _NotifyState() {
+
+       /* TODO
+       evSts := xaapiv1.ServerCfg{
+               ID:         xs.ID,
+               URL:        xs.BaseURL,
+               APIURL:     xs.APIURL,
+               PartialURL: xs.PartialURL,
+               ConnRetry:  xs.ConnRetry,
+               Connected:  xs.Connected,
+       }
+       if err := xs.events.Emit(xaapiv1.EVTServerConfig, evSts, ""); err != nil {
+               xs.Log.Warningf("Cannot notify XdsServer state change: %v", err)
+       }
+       */
+}
similarity index 69%
rename from lib/agent/xdssupervior.go
rename to lib/agent/xdsmonitoring.go
index 48b3f90..42e5324 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017-2018 "IoT.bzh"
+ * Copyright (C) 2017-2019 "IoT.bzh"
  * Author Sebastien Douheret <sebastien@iot.bzh>
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,8 +27,8 @@ import (
        uuid "github.com/satori/go.uuid"
 )
 
-// XdsSupervisor .
-type XdsSupervisor struct {
+// XdsMonitoring .
+type XdsMonitoring struct {
        *Context
        ID        string
        BaseURL   string
@@ -42,19 +42,6 @@ type XdsSupervisor struct {
        cbOnConnect OnConnectedXdsSupervCB
 }
 
-// XdsSuperVRequest Resquest field of a reply
-type XdsSuperVRequest struct {
-       Status string `json:"status"`
-       Info   string `json:"info"`
-}
-
-// XdsSuperVReply Reply structure of XDS Supervision Daemon
-type XdsSuperVReply struct {
-       JType    string           `json:"jtype"`
-       Request  XdsSuperVRequest `json:"request"`
-       Response interface{}      `json:"response"`
-}
-
 // XdsSuperVTraceConfig
 type XdsSuperVTraceConfig struct {
        Pid    int    `json:"pid"`
@@ -63,15 +50,15 @@ type XdsSuperVTraceConfig struct {
 }
 
 // OnConnectedXdsSupervCB connect callback
-type OnConnectedXdsSupervCB func(svr *XdsSupervisor) error
+type OnConnectedXdsSupervCB func(svr *XdsMonitoring) error
 
-// NewXdsSupervisor creates an instance of XdsSupervisor
-func NewXdsSupervisor(ctx *Context) *XdsSupervisor {
-       return &XdsSupervisor{
+// NewXdsMonitoring creates an instance of XdsMonitoring
+func NewXdsMonitoring(ctx *Context) *XdsMonitoring {
+       return &XdsMonitoring{
                Context:   ctx,
-               ID:        "XdsSupervisor-" + uuid.NewV1().String(),
-               BaseURL:   ctx.Config.FileConf.ProfileConf.XDSBinder.URL,
-               ConnRetry: ctx.Config.FileConf.ProfileConf.XDSBinder.ConnRetry,
+               ID:        "XdsMonitoring-" + uuid.NewV1().String(),
+               BaseURL:   ctx.Config.FileConf.ProfileConf.XDSMonitoring.URL,
+               ConnRetry: ctx.Config.FileConf.ProfileConf.XDSMonitoring.ConnRetry,
                Connected: false,
                Disabled:  false,
 
@@ -79,8 +66,8 @@ func NewXdsSupervisor(ctx *Context) *XdsSupervisor {
        }
 }
 
-// Connect Establish HTTP connection with XDS Supervisor Dameon
-func (xs *XdsSupervisor) Connect() error {
+// Connect Establish HTTP connection with XDS Monitoring Dameon
+func (xs *XdsMonitoring) Connect() error {
        var err error
        var retry int
 
@@ -97,12 +84,12 @@ func (xs *XdsSupervisor) Connect() error {
                        // doing that avoid 2 notifs (conn false; conn true) on startup
                        xs._NotifyState()
                }
-               xs.Log.Infof("Establishing connection to XDS Supervisor daemon (retry %d/%d)", retry, xs.ConnRetry)
+               xs.Log.Infof("Establishing connection to XDS Monitoring daemon (retry %d/%d)", retry, xs.ConnRetry)
                time.Sleep(time.Second)
        }
        if retry == 0 {
                // FIXME: re-use _Reconnect to wait longer in background
-               return fmt.Errorf("Connection to XDS Supervisor daemon failure")
+               return fmt.Errorf("Connection to XDS Monitoring daemon failure")
        }
        if err != nil {
                return err
@@ -115,29 +102,29 @@ func (xs *XdsSupervisor) Connect() error {
 }
 
 // ConnectOn Register a callback on events reception
-func (xs *XdsSupervisor) ConnectOn(f OnConnectedXdsSupervCB) error {
+func (xs *XdsMonitoring) ConnectOn(f OnConnectedXdsSupervCB) error {
        xs.cbOnConnect = f
        return nil
 }
 
-// GetVersion Send Get request to retrieve XDS Supervision version
-func (xs *XdsSupervisor) GetVersion(res interface{}) error {
+// GetVersion Send Get request to retrieve XDS Monitoring version
+func (xs *XdsMonitoring) GetVersion(res interface{}) error {
        // FIXME add suffix URLSuffix in common HTTP client lib instead of _BuildURL
        return xs.client.Get(xs._BuildURL("/version"), &res)
 }
 
 // GetTopo Send Get request to retrieve Services/Daemons topology
-func (xs *XdsSupervisor) GetTopo(res interface{}) error {
+func (xs *XdsMonitoring) GetTopo(res interface{}) error {
        return xs.client.Get(xs._BuildURL("/list"), &res)
 }
 
-// StartTrace Send Supervisor config and start tracing
-func (xs *XdsSupervisor) StartTrace(cfg XdsSuperVTraceConfig, res interface{}) error {
+// StartTrace Send Monitoring config and start tracing
+func (xs *XdsMonitoring) StartTrace(cfg XdsSuperVTraceConfig, res interface{}) error {
        return xs.client.Post(xs._BuildURL("/trace/start"), cfg, &res)
 }
 
-// StopTrace Send Supervisor stop tracing
-func (xs *XdsSupervisor) StopTrace(res interface{}) error {
+// StopTrace Send Monitoring stop tracing
+func (xs *XdsMonitoring) StopTrace(res interface{}) error {
        var cfg interface{}
        return xs.client.Post(xs._BuildURL("/trace/stop"), cfg, res)
 }
@@ -147,12 +134,12 @@ func (xs *XdsSupervisor) StopTrace(res interface{}) error {
 ***/
 
 // _BuildURL .
-func (xs *XdsSupervisor) _BuildURL(url string) string {
+func (xs *XdsMonitoring) _BuildURL(url string) string {
        return url + "?token=HELLO&uuid=magic"
 }
 
 // Create HTTP client
-func (xs *XdsSupervisor) _CreateConnectHTTP() error {
+func (xs *XdsMonitoring) _CreateConnectHTTP() error {
        var err error
        // FIXME SEB - Client key not in header but in cookie
        // temporary workaround: used _BuildURL to append uuid=magic in URL
@@ -179,17 +166,17 @@ func (xs *XdsSupervisor) _CreateConnectHTTP() error {
                if strings.Contains(err.Error(), "connection refused") {
                        msg = fmt.Sprintf("(url: %s)", xs.BaseURL)
                }
-               return fmt.Errorf("ERROR: cannot connect to XDS Supervisor %s", msg)
+               return fmt.Errorf("ERROR: cannot connect to XDS Monitoring %s", msg)
        }
        if xs.client == nil {
-               return fmt.Errorf("ERROR: cannot connect to XDS Supervisor (null client)")
+               return fmt.Errorf("ERROR: cannot connect to XDS Monitoring (null client)")
        }
 
        return nil
 }
 
 // _Connect Established HTTP and WS connection
-func (xs *XdsSupervisor) _Connect(reConn bool) error {
+func (xs *XdsMonitoring) _Connect(reConn bool) error {
 
        var res interface{}
        if err := xs.client.Get(xs._BuildURL("/ping"), &res); err != nil {
@@ -212,7 +199,7 @@ func (xs *XdsSupervisor) _Connect(reConn bool) error {
 }
 
 // _NotifyState Send event to notify changes
-func (xs *XdsSupervisor) _NotifyState() {
+func (xs *XdsMonitoring) _NotifyState() {
 
        /* TODO
        evSts := xaapiv1.ServerCfg{
diff --git a/lib/aglafb/afb.go b/lib/aglafb/afb.go
new file mode 100644 (file)
index 0000000..85f6686
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 "IoT.bzh"
+ * Author Sebastien Douheret <sebastien@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package aglafb
+
+import "fmt"
+
+// AfbRequest Resquest field of a reply
+type AfbRequest struct {
+       Status string `json:"status"`
+       Info   string `json:"info"`
+}
+
+// AfbReply Reply structure of XDS Monitoring Daemon
+type AfbReply struct {
+       JType    string      `json:"jtype"`
+       Request  AfbRequest  `json:"request"`
+       Response interface{} `json:"response"`
+}
+
+func NewAfbReply() *AfbReply {
+       return &AfbReply{}
+}
+
+func (r *AfbReply) Success() bool {
+       return r.Request.Status == "success"
+}
+
+func (r *AfbReply) Failure() bool {
+       return !r.Success()
+}
+
+func (r *AfbReply) GetError() error {
+       return fmt.Errorf(r.Request.Info)
+}
+
+func (r *AfbReply) GetInfo() string {
+       return r.Request.Info
+}
index 93c8f4b..6a5e750 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017-2018 "IoT.bzh"
+ * Copyright (C) 2017-2019 "IoT.bzh"
  * Author Sebastien Douheret <sebastien@iot.bzh>
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -92,10 +92,14 @@ func Init(ctx *cli.Context, log *logrus.Logger) (*Config, error) {
                                Home: defaultSTHomeDir,
                        },
                        ProfileConf: ProfileConfT{
-                               XDSBinder: XDSBinderConf{
+                               XDSMonitoring: XDSMonitoringConf{
                                        URL:       "http://localhost:8810",
                                        ConnRetry: 10,
                                },
+                               XDSLowCollector: XDSLowCollectorConf{
+                                       URL:       "http://localhost:8820",
+                                       ConnRetry: 10,
+                               },
                        },
                },
                Log: log,
index 7ddb010..85e26bc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017-2018 "IoT.bzh"
+ * Copyright (C) 2017-2019 "IoT.bzh"
  * Author Sebastien Douheret <sebastien@iot.bzh>
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -43,13 +43,19 @@ type XDSServerConf struct {
        APIPartialURL string `json:"-"`
 }
 
-type XDSBinderConf struct {
+type XDSMonitoringConf struct {
+       URL       string `json:"url"`
+       ConnRetry int    `json:"connRetry"`
+}
+
+type XDSLowCollectorConf struct {
        URL       string `json:"url"`
        ConnRetry int    `json:"connRetry"`
 }
 
 type ProfileConfT struct {
-       XDSBinder XDSBinderConf `json:"xdsBinder"`
+       XDSMonitoring   XDSMonitoringConf   `json:"xdsMonitoring"`
+       XDSLowCollector XDSLowCollectorConf `json:"xdsLowCollector"`
 }
 
 type FileConfig struct {
index 6a4eb3c..b3606ec 100644 (file)
@@ -23,7 +23,7 @@ import { AlertService } from './alert.service';
 import { ConfigService } from './config.service';
 import { ProjectService } from './project.service';
 import { SdkService } from './sdk.service';
-import { SupervisionService } from './supervision.service';
+import { MonitoringService } from './monitoring.service';
 import { TargetService } from './target.service';
 import { UserService } from './users.service';
 import { XDSConfigService } from './xds-config.service';
@@ -34,7 +34,7 @@ const SERVICES = [
   ConfigService,
   ProjectService,
   SdkService,
-  SupervisionService,
+  MonitoringService,
   TargetService,
   UserService,
   XDSConfigService,
diff --git a/webapp/src/app/@core-xds/services/monitoring.service.ts b/webapp/src/app/@core-xds/services/monitoring.service.ts
new file mode 100644 (file)
index 0000000..a606909
--- /dev/null
@@ -0,0 +1,106 @@
+/**
+* @license
+* Copyright (C) 2018-2019 "IoT.bzh"
+* Author Sebastien Douheret <sebastien@iot.bzh>
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs/Observable';
+
+import { XDSAgentService } from './xdsagent.service';
+import { map } from 'rxjs/operators';
+
+export interface AglTopology {
+  name: string;
+  pid: number;
+  disabled: boolean;
+  isClient: boolean;
+  isServer: boolean;
+  ws_clients: string[];
+  ws_servers: string[];
+  apis: any;
+}
+
+export interface AglLowCollectorConfig {
+  time?: number;
+}
+
+@Injectable()
+export class MonitoringService {
+
+  constructor(private xdsSvr: XDSAgentService) {
+    /*
+    this.xdsSvr.XdsConfig$.subscribe(cfg => {
+      if (!cfg || cfg.servers.length < 1) {
+        return;
+      }
+    });
+    */
+  }
+
+  getTopo(): Observable<AglTopology[]> {
+    return this.xdsSvr.getTopoMonitoring().pipe(
+      map((tp: AglTopology[]) => {
+        // FIXME - move filter on backend side
+        const ignored: string[] = [
+          'agl-low-collector',
+          'harvester',
+        ];
+
+        tp.forEach(el => {
+          el.disabled = false;
+          ignored.forEach(iel => {
+            if (el.name.indexOf(iel) !== -1) {
+              el.disabled = true;
+            }
+          });
+
+          // replace unix:/run/xxx/ws by nothing
+          const wsc: string[] = [];
+          el.ws_clients.forEach(s => {
+            s = s.replace('unix:/run/platform/apis/ws/', '');
+            s = s.replace('unix:/run/user/1001/apis/ws/', '');
+            s = s.replace('unix:/run/user/0/apis/ws/', '');
+            wsc.push(s);
+          });
+          el.ws_clients = wsc;
+          // replace sd: by nothing
+          const wss: string[] = [];
+          el.ws_servers.forEach(s => {
+            wss.push(s.replace('sd:', ''));
+          });
+          el.ws_servers = wss;
+        });
+        return tp;
+      })
+    );
+  }
+
+  startTrace(cfg: any): Observable<any> {
+    return this.xdsSvr.startTraceMonitoring(cfg);
+  }
+
+  stopTrace(cfg: any): Observable<any> {
+    return this.xdsSvr.stopTraceMonitoring(cfg);
+  }
+
+  startLowCollector(cfg: AglLowCollectorConfig): Observable<any> {
+    return this.xdsSvr.startLowCollector(cfg);
+  }
+
+  stopLowCollector(): Observable<any> {
+    return this.xdsSvr.stopLowCollector();
+  }
+}
diff --git a/webapp/src/app/@core-xds/services/supervision.service.ts b/webapp/src/app/@core-xds/services/supervision.service.ts
deleted file mode 100644 (file)
index 4a9f578..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
-* @license
-* Copyright (C) 2018 "IoT.bzh"
-* Author Sebastien Douheret <sebastien@iot.bzh>
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*   http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-import { Injectable, SecurityContext, isDevMode } from '@angular/core';
-import { Observable } from 'rxjs/Observable';
-
-import { XDSAgentService } from '../services/xdsagent.service';
-
-export interface AglTopology {
-  name: string;
-  pid: number;
-  isClient: boolean;
-  isServer: boolean;
-  ws_clients: string[];
-  ws_servers: string[];
-  apis: any;
-}
-
-@Injectable()
-export class SupervisionService {
-
-  private curServerID;
-
-  constructor(private xdsSvr: XDSAgentService) {
-    /*
-    this.xdsSvr.XdsConfig$.subscribe(cfg => {
-      if (!cfg || cfg.servers.length < 1) {
-        return;
-      }
-    });
-    */
-  }
-
-  getTopo(): Observable<AglTopology[]> {
-    return this.xdsSvr.getTopoSupervisor();
-  }
-
-  startTrace(cfg: any): Observable<any> {
-    return this.xdsSvr.startTraceSupervisor(cfg);
-  }
-
-  stopTrace(cfg: any): Observable<any> {
-    return this.xdsSvr.stopTraceSupervisor(cfg);
-  }
-
-}
index 002c84b..35abe46 100644 (file)
@@ -1,6 +1,6 @@
 /**
 * @license
-* Copyright (C) 2017-2018 "IoT.bzh"
+* Copyright (C) 2017-2019 "IoT.bzh"
 * Author Sebastien Douheret <sebastien@iot.bzh>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
@@ -666,18 +666,33 @@ export class XDSAgentService {
   }
 
   /***
-  ** Supervision
+  ** Monitoring
   ***/
-  getTopoSupervisor(): Observable<any> {
-    return this._get('/supervisor/topo');
+  getTopoMonitoring(): Observable<any> {
+    return this._get('/monitoring/topo');
   }
 
-  startTraceSupervisor(cfg: any): Observable<any> {
-    return this._post('/supervisor/trace/start', cfg);
+  startTraceMonitoring(cfg: any): Observable<any> {
+    return this._post('/monitoring/trace/start', cfg);
   }
 
-  stopTraceSupervisor(cfg: any): Observable<any> {
-    return this._post('/supervisor/trace/stop', cfg);
+  stopTraceMonitoring(cfg: any): Observable<any> {
+    return this._post('/monitoring/trace/stop', cfg);
+  }
+
+  /***
+   ** AGL Low Collector
+   ***/
+  startLowCollector(cfg: any): Observable<any> {
+    return this._post('/monitoring/alc/start', cfg);
+  }
+
+  stopLowCollector(): Observable<any> {
+    return this._post('/monitoring/alc/stop', {});
+  }
+
+  resetLowCollector(): Observable<any> {
+    return this._post('/monitoring/alc/reset', {});
   }
 
   /**
@@ -692,7 +707,7 @@ export class XDSAgentService {
         error => {
           this.alert.error('ERROR while registering to all events: ' + error);
         },
-    );
+      );
   }
 
   private _getServer(ID: string): IXDServerCfg {
index c3bc8b4..3ae77d9 100644 (file)
@@ -26,7 +26,7 @@
 
   <div class="col-md-12">
     <nb-card>
-      <nb-card-header>Supervision Configuration</nb-card-header>
+      <nb-card-header>Monitoring Configuration</nb-card-header>
       <nb-card-body>
         <form (ngSubmit)="onSubmit()" #ConfigGlobalForm="ngForm">
           <div class="form-group row">
diff --git a/webapp/src/app/pages/monitoring/monitoring-config.component.html b/webapp/src/app/pages/monitoring/monitoring-config.component.html
new file mode 100644 (file)
index 0000000..ed76dd0
--- /dev/null
@@ -0,0 +1,77 @@
+<div class="row col-md-12">
+  <div class="col-md-2" style="display: inherit;">
+    <h3 style="margin-top: auto; margin-bottom: auto">Configuration</h3>
+  </div>
+  <div class="col-md-1">
+    <nb-card-body>
+      <div class="col-md-9">
+        <nb-actions size="small">
+          <nb-action>
+            <button id="refresh-topo" (click)="getAGLTopo()">
+              <i class="fa fa-refresh"></i>
+            </button>
+          </nb-action>
+        </nb-actions>
+      </div>
+    </nb-card-body>
+  </div>
+
+  <div class="col-md-8" style="text-align: right;">
+    <label>Monitoring actions</label>
+    <button id="start-trace" class="btn btn-primary" (click)="onStartTrace()" [disabled]="
+        isStartBtnDisable()">{{ starting ?"Starting... ":"Start" }}
+      <span *ngIf="starting" class="fa fa-gear faa-spin animated fa-size-x2"></span>
+    </button>
+
+    <button id="stop-trace" class="btn btn-primary" (click)="onStopTrace()" [disabled]="
+      isStopBtnDisable()">{{ stopping ?"Stopping... ":"Stop" }}
+      <span *ngIf="stopping" class="fa fa-gear faa-spin animated fa-size-x2"></span>
+    </button>
+
+    <button id="show-graph" class="btn btn-primary" (click)="showGraph()">
+      Show Graph
+    </button>
+  </div>
+</div>
+<div class="row col-md-12">
+  <table class="table table-striped" style="color:black;">
+    <tbody>
+      <tr>
+        <th>Name</th>
+        <th style="width: 6rem;">Pid</th>
+        <th>WS Clients</th>
+        <th>WS Servers</th>
+        <th style="width: 6rem;">Monitor</th>
+      </tr>
+      <ng-container *ngIf="aglTopoInit; else loading">
+        <ng-container *ngIf="daemonCheckboxes?.length; else noItems">
+          <tr *ngFor="let tp of daemonCheckboxes">
+            <td *ngFor="let col of ['name', 'pid', 'ws_clients', 'ws_servers']">
+              {{tp.topo[col]}}
+            </td>
+            <td style="text-align: center;">
+              <ng-container *ngIf="!tp.topo.disabled else disableTopo">
+                <nb-checkbox indeterminate [(ngModel)]="tp.value"></nb-checkbox>
+              </ng-container>
+              <ng-template #disableTopo>
+                <span style="font-size: smaller; color: grey; font-style: italic;">DISABLED
+                </span>
+              </ng-template>
+            </td>
+          </tr>
+        </ng-container>
+        <ng-template #noItems>No Items!</ng-template>
+        <ng-template #loading>loading...</ng-template>
+      </ng-container>
+      <ng-template #loading>loading...</ng-template>
+    </tbody>
+  </table>
+</div>
+
+<div class="row col-md-6" style="display: inherit;">
+  <h3 style="margin-top: auto; margin-bottom: auto">AGL Bindings Topology</h3>
+</div>
+<div class="row col-md-12" style="">
+  <svg id="graph" width="100%" height="800">
+  </svg>
+</div>
@@ -101,6 +101,14 @@ button#refresh-topo {
   }
 }
 
+table {
+  table-layout: fixed;
+}
+
+td {
+  word-wrap:break-word;
+}
+
 button#start-trace {
   margin-top: 10px;
   margin-left: 10px;
@@ -111,6 +119,11 @@ button#stop-trace {
   margin-left: 10px;
 }
 
+button#show-graph {
+  margin-top: 10px;
+  margin-left: 10px;
+}
+
 #ws-client {
   fill: green;
 }
@@ -1,6 +1,6 @@
 /**
 * @license
-* Copyright (C) 2017-2018 "IoT.bzh"
+* Copyright (C) 2017-2019 "IoT.bzh"
 * Author Sebastien Douheret <sebastien@iot.bzh>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * limitations under the License.
 */
 
-import { Component, OnInit, AfterViewInit, ViewEncapsulation } from '@angular/core';
-import { Injectable, Inject } from '@angular/core';
+import { Component, OnInit, AfterViewInit, ViewEncapsulation, Inject } from '@angular/core';
 import { DOCUMENT } from '@angular/common';
 import * as d3 from 'd3';
+import { Router } from '@angular/router';
 
-import { SupervisionService, AglTopology } from '../../@core-xds/services/supervision.service';
+import { MonitoringService, AglTopology } from '../../@core-xds/services/monitoring.service';
 import { AlertService } from '../../@core-xds/services/alert.service';
+import { BehaviorSubject } from 'rxjs/BehaviorSubject';
+import { Subscription } from 'rxjs/Subscription';
 
 interface WsCheckbox {
-  name: string;
-  pid: number;
+  topo: AglTopology;
   value: boolean;
-  disabled: boolean;
   tooltip: string;
 }
 
 @Component({
-  selector: 'xds-supervision',
-  styleUrls: ['./supervision-config.component.scss'],
-  templateUrl: './supervision-config.component.html',
+  selector: 'xds-monitoring',
+  styleUrls: ['./monitoring-config.component.scss'],
+  templateUrl: './monitoring-config.component.html',
   encapsulation: ViewEncapsulation.None,  // workaround about https://github.com/angular/angular/issues/7845
 })
-export class SupervisionConfigComponent implements OnInit, AfterViewInit {
+export class MonitoringConfigComponent implements OnInit, AfterViewInit {
 
+  aglTopoInit = new BehaviorSubject(false);
+  // FIXME: use Map instead of array and use '| keyvalue' for ngfor loop (but angular > 6.1 requested)
+  // daemonCheckboxes: Map<string, WsCheckbox> = new Map<string, WsCheckbox>();
   daemonCheckboxes: WsCheckbox[] = [];
   starting = false;
   stopping = false;
@@ -47,26 +50,32 @@ export class SupervisionConfigComponent implements OnInit, AfterViewInit {
   private graph: any;
   private svg: any;
   private links = [];
+  private _aglTopoSub: Subscription;
 
   constructor(@Inject(DOCUMENT) private document: Document,
-    private supervisorSvr: SupervisionService,
+    private router: Router,
+    private monitoringSvr: MonitoringService,
     private alert: AlertService,
   ) {
 
   }
 
   ngOnInit() {
-
   }
 
   ngAfterViewInit() {
     this.getAGLTopo();
+    this.aglTopoInit.next(true);
   }
 
   getAGLTopo() {
-    this.supervisorSvr.getTopo().subscribe(topo => {
+    if (this._aglTopoSub !== undefined) {
+      this._aglTopoSub.unsubscribe();
+    }
+
+    this._aglTopoSub = this.monitoringSvr.getTopo().subscribe(topo => {
       this.graphAGLBindings(topo);
-      this.updateCheckboxes(topo);
+      this.createCheckboxes(topo);
     });
   }
 
@@ -74,11 +83,21 @@ export class SupervisionConfigComponent implements OnInit, AfterViewInit {
     this.starting = true;
 
     const dmArr = [];
-    this.daemonCheckboxes.forEach(dm => dm.value && dmArr.push(dm.pid));
+    this.daemonCheckboxes.forEach(dm => dm.value && dmArr.push(dm.topo.pid));
+
+    this.monitoringSvr.startTrace({ pids: dmArr }).subscribe(res => {
+      // console.log('Trace Started: res', res);
+
+      this.monitoringSvr.startLowCollector(null).subscribe((/*res*/) => {
+        // console.log('Low Collector Started: res', res);
+        this.alert.info('Monitoring successfully started');
+        this.starting = false;
+
+      }, err => {
+        this.starting = false;
+        this.alert.error(err);
+      });
 
-    this.supervisorSvr.startTrace({ pids: dmArr }).subscribe(res => {
-      this.starting = false;
-      this.alert.info('Monitoring successfully started');
     }, err => {
       this.starting = false;
       this.alert.error(err);
@@ -87,15 +106,29 @@ export class SupervisionConfigComponent implements OnInit, AfterViewInit {
 
   onStopTrace() {
     this.stopping = true;
-    this.supervisorSvr.stopTrace({}).subscribe(res => {
-      this.stopping = false;
-      this.alert.info('Monitoring successfully stopped');
+    this.monitoringSvr.stopTrace({}).subscribe(res => {
+      // console.log('Trace Stopped: res', res);
+
+      this.monitoringSvr.stopLowCollector().subscribe((/*res*/) => {
+        // console.log('Low Collector Stopped: res', res);
+        this.alert.info('Monitoring successfully started');
+        this.stopping = false;
+
+      }, err => {
+        this.stopping = false;
+        this.alert.error(err);
+      });
+
     }, err => {
       this.stopping = false;
       this.alert.error(err);
     });
   }
 
+  showGraph() {
+    this.router.navigate([`/pages/monitoring/graph`]);
+  }
+
   isStartBtnDisable(): boolean {
     return this.starting;
   }
@@ -104,18 +137,42 @@ export class SupervisionConfigComponent implements OnInit, AfterViewInit {
     return this.stopping;
   }
 
-  private updateCheckboxes(topo: AglTopology[]) {
-    this.daemonCheckboxes = [];
+  isDaemonDisabled(name: string): boolean {
+    let sts = false;
+    // FIXME - better to use map
+    // with Map
+    // if (this.daemonCheckboxes.has(name)) {
+    //   sts = this.daemonCheckboxes[name].value;
+    // }
+    this.daemonCheckboxes.forEach(e => {
+      if (e.topo.name === name) {
+        sts = true;
+      }
+    });
+    return sts;
+  }
+
+  private createCheckboxes(topo: AglTopology[]) {
+
+    // let newDaemonChB: Map<string, WsCheckbox> = new Map<string, WsCheckbox>();
+    const newDaemonChB: WsCheckbox[] = [];
+    let prevVal = false;
+    this.daemonCheckboxes.forEach(e => {
+      if (e.topo.name === name) {
+        prevVal = e.value;
+      }
+    });
     topo.forEach(elem => {
-      this.daemonCheckboxes.push({
-        name: elem.name,
-        pid: elem.pid,
-        value: false,
-        disabled: false,
-        tooltip: 'Daemon ' + elem.name + ' (pid ' + elem.pid + ')',
+      // with Map
+      // newDaemonChB.set(elem.name, {
+      newDaemonChB.push({
+        topo: Object.assign({}, elem),
+        value: prevVal,
+        tooltip: 'Daemon binding ' + elem.name + ' (pid ' + elem.pid + ')',
       });
     });
 
+    this.daemonCheckboxes = newDaemonChB;
   }
 
 
@@ -64,6 +64,6 @@
 <!-- Display mode: using dashboard -->
 <div class="row" *ngIf="displayMode==='dashboard'">
   <div class="col-md-12">
-    <iframe [src]="getDashboard('xds_supervisor')" width="100%" height="800px" frameborder="0"></iframe>
+    <iframe [src]="getDashboard('xds_monitoring')" width="100%" height="800px" frameborder="0"></iframe>
   </div>
 </div>
@@ -1,6 +1,6 @@
 /**
 * @license
-* Copyright (C) 2017-2018 "IoT.bzh"
+* Copyright (C) 2017-2019 "IoT.bzh"
 * Author Sebastien Douheret <sebastien@iot.bzh>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
 
 import { Component, OnInit, Input } from '@angular/core';
-import { Observable } from 'rxjs/Observable';
-import { Subject } from 'rxjs/Subject';
 import { NbThemeService } from '@nebular/theme';
 import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
 
 import { ConfigService, IConfig } from '../../@core-xds/services/config.service';
-import { SupervisionService } from '../../@core-xds/services/supervision.service';
+import { MonitoringService } from '../../@core-xds/services/monitoring.service';
 import { AlertService } from '../../@core-xds/services/alert.service';
 
 export interface GrafanaDashboard {
@@ -41,12 +39,12 @@ export interface GrafanaPanel {
 }
 
 @Component({
-  selector: 'xds-supervision',
-  styleUrls: ['./supervision.component.scss'],
-  templateUrl: './supervision.component.html',
+  selector: 'xds-monitoring',
+  styleUrls: ['./monitoring.component.scss'],
+  templateUrl: './monitoring.component.html',
 })
 
-export class SupervisionComponent implements OnInit {
+export class MonitoringComponent implements OnInit {
 
   /* TODO bind tm_* and refresh in UI */
   @Input() theme = 'light';
@@ -59,17 +57,17 @@ export class SupervisionComponent implements OnInit {
   displayMode = 'dashboard';
 
   private dashboards: Map<string, GrafanaDashboard> = new Map<string, GrafanaDashboard>([
-    ['xds_supervisor', { name: 'AGL XDS Supervisor', shortname: 'agl-xds-supervisor' }],
+    ['xds_monitoring', { name: 'AGL XDS Monitoring', shortname: 'agl-xds-monitoring' }],
   ]);
 
   private panels: Map<string, GrafanaPanel> = new Map<string, GrafanaPanel>([
-    ['table', { name: 'Supervisor traces table', index: '2' }],
+    ['table', { name: 'Monitoring traces table', index: '2' }],
     ['evt_data_bytes', { name: 'Requests & Events per second', index: '5' }],
     ['req_evts_per_sec', { name: 'Events Data bytes', index: '12' }],
   ]);
 
   constructor(
-    private supervisionSvr: SupervisionService,
+    private monitoringSvr: MonitoringService,
     private alert: AlertService,
     private themeService: NbThemeService,
     private sanitizer: DomSanitizer,
@@ -129,7 +127,7 @@ export class SupervisionComponent implements OnInit {
   }
 
   private _initDashboard() {
-    // http://localhost:3000/d/Lbpwc6Iiz/agl-xds-supervisor?from=now-40s&to=now&refresh=5s
+    // http://localhost:3000/d/Lbpwc6Iiz/agl-xds-monitoring?from=now-40s&to=now&refresh=5s
     this.dashboards.forEach(dd => {
       dd.url = this._buildDashboardUrl(dd.shortname, this.tm_from, this.tm_to, this.refresh, this.theme);
       dd.safeUrl = this.sanitizer.bypassSecurityTrustResourceUrl(dd.url);
@@ -158,7 +156,7 @@ export class SupervisionComponent implements OnInit {
   }
 
   private _buildPanelUrl(idx, from, to, refresh, theme: string) {
-    let url = 'http://localhost:3000/d-solo/Lbpwc6Iiz/agl-xds-supervisor';
+    let url = 'http://localhost:3000/d-solo/Lbpwc6Iiz/agl-xds-monitoring';
     if (this.Config.grafanaDashboardUrl !== '') {
       url = this.Config.grafanaDashboardUrl;
     }
@@ -19,8 +19,8 @@
 import { NgModule } from '@angular/core';
 import { ThemeModule } from '../../@theme/theme.module';
 
-import { SupervisionComponent } from './supervision.component';
-import { SupervisionConfigComponent } from './supervision-config.component';
+import { MonitoringComponent } from './monitoring.component';
+import { MonitoringConfigComponent } from './monitoring-config.component';
 
 
 @NgModule({
@@ -28,10 +28,10 @@ import { SupervisionConfigComponent } from './supervision-config.component';
     ThemeModule,
   ],
   declarations: [
-    SupervisionComponent,
-    SupervisionConfigComponent,
+    MonitoringComponent,
+    MonitoringConfigComponent,
   ],
   entryComponents: [
   ],
 })
-export class SupervisionModule { }
+export class MonitoringModule { }
index 230966d..771c798 100644 (file)
@@ -86,17 +86,17 @@ export const MENU_ITEMS: NbMenuItem[] = [
     ],
   },
   {
-    title: 'Supervision / Monitoring',
+    title: 'Monitoring',
     icon: 'fa fa-bar-chart',
-    link: '/pages/supervision',
+    link: '/pages/monitoring',
     children: [
       {
         title: 'Config',
-        link: '/pages/supervision/config',
+        link: '/pages/monitoring/config',
       },
       {
         title: 'Graph',
-        link: '/pages/supervision/graph',
+        link: '/pages/monitoring/graph',
       },
     ],
   },
index ae2ef4a..c63d496 100644 (file)
@@ -27,8 +27,8 @@ import { SdkManagementComponent } from './sdks/sdk-management/sdk-management.com
 import { TargetsComponent } from './targets/targets.component';
 import { TerminalsComponent } from './targets/terminals/terminals.component';
 import { BuildComponent } from './build/build.component';
-import { SupervisionComponent } from './supervision/supervision.component';
-import { SupervisionConfigComponent } from './supervision/supervision-config.component';
+import { MonitoringComponent } from './monitoring/monitoring.component';
+import { MonitoringConfigComponent } from './monitoring/monitoring-config.component';
 
 const routes: Routes = [{
   path: '',
@@ -55,11 +55,11 @@ const routes: Routes = [{
     path: 'targets/term',
     component: TerminalsComponent,
   }, {
-    path: 'supervision/config',
-    component: SupervisionConfigComponent,
+    path: 'monitoring/config',
+    component: MonitoringConfigComponent,
   }, {
-    path: 'supervision/graph',
-    component: SupervisionComponent,
+    path: 'monitoring/graph',
+    component: MonitoringComponent,
   }, {
     path: 'config',
     loadChildren: './config/config.module#ConfigModule',
index 5ffa8d6..3481599 100644 (file)
@@ -26,7 +26,7 @@ import { DashboardModule } from './dashboard/dashboard.module';
 import { BuildModule } from './build/build.module';
 import { ProjectsModule } from './projects/projects.module';
 import { SdksModule } from './sdks/sdks.module';
-import { SupervisionModule } from './supervision/supervision.module';
+import { MonitoringModule } from './monitoring/monitoring.module';
 import { TargetsModule } from './targets/targets.module';
 import { PagesRoutingModule } from './pages-routing.module';
 import { NotificationsComponent } from './notifications/notifications.component';
@@ -49,7 +49,7 @@ const PAGES_COMPONENTS = [
     SdksModule,
     ToasterModule,
     TargetsModule,
-    SupervisionModule,
+    MonitoringModule,
   ],
   declarations: [
     ...PAGES_COMPONENTS,
diff --git a/webapp/src/app/pages/supervision/supervision-config.component.html b/webapp/src/app/pages/supervision/supervision-config.component.html
deleted file mode 100644 (file)
index 1fbcd70..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-<div class="row">
-  <h3 style="margin-top: auto; margin-bottom: auto">Configuration</h3>
-
-  <div class="row">
-    <div class="col-md-12">
-      <nb-card-body>
-        <div class="col-md-9">
-          <nb-actions size="small">
-            <nb-action>
-              <button id="refresh-topo" (click)="getAGLTopo()">
-                <i class="fa fa-refresh"></i>
-              </button>
-            </nb-action>
-          </nb-actions>
-        </div>
-      </nb-card-body>
-    </div>
-  </div>
-</div>
-<div class="row">
-  <div class="col-md-10">
-    <svg id="graph" width="100%" height="500">
-    </svg>
-  </div>
-  <div class="col-md-2">
-    <div>
-      <label>Daemons to monitor</label>
-    </div>
-    <nb-checkbox *ngFor="let wsCkx of daemonCheckboxes" [disabled]="wsCkx.disabled" [(ngModel)]="wsCkx.value">{{wsCkx.name}}
-    </nb-checkbox>
-    <div style="margin-top: 20px;">
-      <div>
-        <label>Monitoring actions:</label>
-      </div>
-      <button id="start-trace" class="btn btn-primary" (click)="onStartTrace()" [disabled]="
-        isStartBtnDisable()">{{ starting ?"Starting... ":"Start" }}
-        <span *ngIf="starting" class="fa fa-gear faa-spin animated fa-size-x2"></span>
-      </button>
-      <button id="stop-trace" class="btn btn-primary" (click)="onStopTrace()" [disabled]="
-      isStopBtnDisable()">{{ stopping ?"Stopping... ":"Stop" }}
-      <span *ngIf="stopping" class="fa fa-gear faa-spin animated fa-size-x2"></span>
-    </button>
-    </div>
-  </div>
-</div>
index 9bfdcb2..7a10b10 100644 (file)
@@ -6,8 +6,12 @@
     "trailing-comma": [
       true,
       {
-        "multiline": "always",
-        "singleline": "never"
+        "multiline": {
+          "objects": "ignore",
+          "arrays": "always",
+          "functions": "ignore",
+          "typeLiterals": "ignore"
+        }
       }
     ],
     "arrow-return-shorthand": true,
     "component-selector": [
       true,
       "element",
-      ["ngx", "xds"],
+      [
+        "ngx",
+        "xds"
+      ],
       "kebab-case"
     ],
     "use-input-property-decorator": true,