diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/agent/agent.go | 11 | ||||
-rw-r--r-- | lib/agent/apiv1-supervisor.go | 114 | ||||
-rw-r--r-- | lib/agent/apiv1.go | 3 | ||||
-rw-r--r-- | lib/agent/xdsserver.go | 2 | ||||
-rw-r--r-- | lib/agent/xdssupervior.go | 230 | ||||
-rw-r--r-- | lib/xdsconfig/config.go | 6 | ||||
-rw-r--r-- | lib/xdsconfig/configfile.go | 10 |
7 files changed, 370 insertions, 6 deletions
diff --git a/lib/agent/agent.go b/lib/agent/agent.go index 3aa89a8..58f336c 100644 --- a/lib/agent/agent.go +++ b/lib/agent/agent.go @@ -47,11 +47,12 @@ type Context struct { SThgCmd *exec.Cmd SThgInotCmd *exec.Cmd - webServer *WebServer - xdsServers map[string]*XdsServer - sessions *Sessions - events *Events - projects *Projects + webServer *WebServer + xdsServers map[string]*XdsServer + XdsSupervisor *XdsSupervisor + sessions *Sessions + events *Events + projects *Projects Exit chan os.Signal } diff --git a/lib/agent/apiv1-supervisor.go b/lib/agent/apiv1-supervisor.go new file mode 100644 index 0000000..a34a913 --- /dev/null +++ b/lib/agent/apiv1-supervisor.go @@ -0,0 +1,114 @@ +/* + * 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/golib" + "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 +} diff --git a/lib/agent/apiv1.go b/lib/agent/apiv1.go index 97165b3..504558e 100644 --- a/lib/agent/apiv1.go +++ b/lib/agent/apiv1.go @@ -67,6 +67,9 @@ 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) return s } diff --git a/lib/agent/xdsserver.go b/lib/agent/xdsserver.go index f74e3ba..24e51d7 100644 --- a/lib/agent/xdsserver.go +++ b/lib/agent/xdsserver.go @@ -157,7 +157,7 @@ func (xs *XdsServer) SetLoggerOutput(out io.Writer) { xs.logOut = out } -// GetConfig +// GetConfig return the current server config func (xs *XdsServer) GetConfig() xaapiv1.ServerCfg { return xaapiv1.ServerCfg{ ID: xs.ID, diff --git a/lib/agent/xdssupervior.go b/lib/agent/xdssupervior.go new file mode 100644 index 0000000..bbe2500 --- /dev/null +++ b/lib/agent/xdssupervior.go @@ -0,0 +1,230 @@ +/* + * 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 ( + "fmt" + "io" + "strings" + "time" + + common "gerrit.automotivelinux.org/gerrit/src/xds/xds-common.git/golib" + uuid "github.com/satori/go.uuid" +) + +// XdsSupervisor . +type XdsSupervisor struct { + *Context + ID string + BaseURL string + ConnRetry int + Connected bool + Disabled bool + + // Private fields + client *common.HTTPClient + logOut io.Writer + 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"` + Pids []int `json:"pids"` + WsName string `json:"ws"` +} + +// OnConnectedXdsSupervCB connect callback +type OnConnectedXdsSupervCB func(svr *XdsSupervisor) error + +// NewXdsSupervisor creates an instance of XdsSupervisor +func NewXdsSupervisor(ctx *Context) *XdsSupervisor { + return &XdsSupervisor{ + Context: ctx, + ID: "XdsSupervisor-" + uuid.NewV1().String(), + BaseURL: ctx.Config.FileConf.ProfileConf.XDSBinder.URL, + ConnRetry: ctx.Config.FileConf.ProfileConf.XDSBinder.ConnRetry, + Connected: false, + Disabled: false, + + logOut: ctx.Log.Out, + } +} + +// Connect Establish HTTP connection with XDS Supervisor Dameon +func (xs *XdsSupervisor) 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 Supervisor 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") + } + 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 *XdsSupervisor) 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 { + // 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 { + return xs.client.Get(xs._BuildURL("/list"), &res) +} + +// StartTrace Send Supervisor config and start tracing +func (xs *XdsSupervisor) 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 { + var cfg interface{} + return xs.client.Post(xs._BuildURL("/trace/stop"), cfg, res) +} + +/*** +** Private functions +***/ + +// _BuildURL . +func (xs *XdsSupervisor) _BuildURL(url string) string { + return url + "?token=HELLO&uuid=magic" +} + +// Create HTTP client +func (xs *XdsSupervisor) _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/xds", + CsrfDisable: true, + LogOut: xs.logOut, + LogPrefix: "XDSSUPERV: ", + 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 Supervisor %s", msg) + } + if xs.client == nil { + return fmt.Errorf("ERROR: cannot connect to XDS Supervisor (null client)") + } + + return nil +} + +// _Connect Established HTTP and WS connection +func (xs *XdsSupervisor) _Connect(reConn bool) error { + + var res interface{} + if err := xs.client.Get(xs._BuildURL("/ping"), &res); err != nil { + 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 *XdsSupervisor) _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) + } + */ +} diff --git a/lib/xdsconfig/config.go b/lib/xdsconfig/config.go index b7bf57b..352ba84 100644 --- a/lib/xdsconfig/config.go +++ b/lib/xdsconfig/config.go @@ -91,6 +91,12 @@ func Init(ctx *cli.Context, log *logrus.Logger) (*Config, error) { SThgConf: &SyncThingConf{ Home: defaultSTHomeDir, }, + ProfileConf: ProfileConfT{ + XDSBinder: XDSBinderConf{ + URL: "http://localhost:5678", + ConnRetry: 10, + }, + }, }, Log: log, } diff --git a/lib/xdsconfig/configfile.go b/lib/xdsconfig/configfile.go index 009517f..1390456 100644 --- a/lib/xdsconfig/configfile.go +++ b/lib/xdsconfig/configfile.go @@ -43,6 +43,15 @@ type XDSServerConf struct { APIPartialURL string `json:"-"` } +type XDSBinderConf struct { + URL string `json:"url"` + ConnRetry int `json:"connRetry"` +} + +type ProfileConfT struct { + XDSBinder XDSBinderConf `json:"xdsBinder"` +} + type FileConfig struct { HTTPPort string `json:"httpPort"` WebAppDir string `json:"webAppDir"` @@ -50,6 +59,7 @@ type FileConfig struct { XDSAPIKey string `json:"xds-apikey"` ServersConf []XDSServerConf `json:"xdsServers"` SThgConf *SyncThingConf `json:"syncthing"` + ProfileConf ProfileConfT `json:"profileConf"` } // readGlobalConfig reads configuration from a config file. |