139 lines
2.8 KiB
Go
139 lines
2.8 KiB
Go
|
package status
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"fmt"
|
||
|
"net/http"
|
||
|
"sync/atomic"
|
||
|
|
||
|
"forge.cadoles.com/Cadoles/emissary/internal/agent"
|
||
|
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
||
|
"github.com/pkg/errors"
|
||
|
"gitlab.com/wpetit/goweb/api"
|
||
|
"gitlab.com/wpetit/goweb/logger"
|
||
|
)
|
||
|
|
||
|
type Status struct {
|
||
|
Agent *datastore.Agent
|
||
|
Connected bool
|
||
|
Claimed bool
|
||
|
Thumbprint string
|
||
|
ServerURL string
|
||
|
ClaimURL string
|
||
|
AgentURL string
|
||
|
AgentVersion string
|
||
|
}
|
||
|
|
||
|
type Controller struct {
|
||
|
status *atomic.Value
|
||
|
server *atomic.Value
|
||
|
addr string
|
||
|
claimURL string
|
||
|
agentURL string
|
||
|
agentVersion string
|
||
|
}
|
||
|
|
||
|
// Name implements node.Controller.
|
||
|
func (c *Controller) Name() string {
|
||
|
return "status-controller"
|
||
|
}
|
||
|
|
||
|
// Reconcile implements node.Controller.
|
||
|
func (c *Controller) Reconcile(ctx context.Context, state *agent.State) error {
|
||
|
cl := agent.Client(ctx)
|
||
|
thumbprint := agent.Thumbprint(ctx)
|
||
|
|
||
|
connected := true
|
||
|
|
||
|
agent, err := cl.GetAgent(ctx, state.AgentID())
|
||
|
if err != nil {
|
||
|
logger.Error(ctx, "could not get agent", logger.E(errors.WithStack(err)))
|
||
|
var apiErr *api.Error
|
||
|
if errors.As(err, &apiErr) {
|
||
|
switch apiErr.Code {
|
||
|
case api.ErrCodeForbidden:
|
||
|
// Contact is ok but agent may be not claimed yet
|
||
|
default:
|
||
|
connected = false
|
||
|
}
|
||
|
} else {
|
||
|
connected = false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
claimed := agent != nil && agent.TenantID != nil
|
||
|
var agentID datastore.AgentID
|
||
|
if agent != nil {
|
||
|
agentID = agent.ID
|
||
|
}
|
||
|
|
||
|
c.status.Store(Status{
|
||
|
Agent: agent,
|
||
|
Connected: connected,
|
||
|
Claimed: claimed,
|
||
|
Thumbprint: thumbprint,
|
||
|
ServerURL: cl.ServerURL(),
|
||
|
ClaimURL: fmt.Sprintf(c.claimURL, thumbprint),
|
||
|
AgentURL: fmt.Sprintf(c.agentURL, agentID),
|
||
|
AgentVersion: c.agentVersion,
|
||
|
})
|
||
|
|
||
|
if err := c.startServer(ctx); err != nil {
|
||
|
return errors.WithStack(err)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (c *Controller) startServer(ctx context.Context) error {
|
||
|
server := c.getServer()
|
||
|
if server != nil {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
server = &http.Server{
|
||
|
Addr: c.addr,
|
||
|
Handler: &Handler{
|
||
|
status: c.status,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
go func() {
|
||
|
defer c.setServer(nil)
|
||
|
|
||
|
if err := server.ListenAndServe(); err != nil {
|
||
|
logger.Error(ctx, "could not start server", logger.E(errors.WithStack(err)))
|
||
|
}
|
||
|
}()
|
||
|
|
||
|
c.setServer(server)
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (c *Controller) setServer(s *http.Server) {
|
||
|
c.server.Store(s)
|
||
|
}
|
||
|
|
||
|
func (c *Controller) getServer() *http.Server {
|
||
|
server, ok := c.server.Load().(*http.Server)
|
||
|
if !ok {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
return server
|
||
|
}
|
||
|
|
||
|
func NewController(addr string, claimURL string, agentURL string, agentVersion string) *Controller {
|
||
|
return &Controller{
|
||
|
addr: addr,
|
||
|
claimURL: claimURL,
|
||
|
agentURL: agentURL,
|
||
|
agentVersion: agentVersion,
|
||
|
status: &atomic.Value{},
|
||
|
server: &atomic.Value{},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var _ agent.Controller = &Controller{}
|