Compare commits
1 Commits
117f5a05a1
...
56558d7241
Author | SHA1 | Date | |
---|---|---|---|
56558d7241 |
@ -1,14 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Emissary</h1>
|
||||
<ul>
|
||||
<li>Server URL: {{ .ServerURL }}</li>
|
||||
<li>Claimed: {{if .Claimed}}true{{else}}false{{end}}</li>
|
||||
<li>Connected: {{if .Connected}}true{{else}}false{{end}}</li>
|
||||
<li>Thumbprint: <code>{{ .Thumbprint }}</code></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
@ -1,13 +1,15 @@
|
||||
package registration
|
||||
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"
|
||||
)
|
||||
|
||||
@ -17,17 +19,23 @@ type Status struct {
|
||||
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 "registration-controller"
|
||||
return "status-controller"
|
||||
}
|
||||
|
||||
// Reconcile implements node.Controller.
|
||||
@ -36,16 +44,28 @@ func (c *Controller) Reconcile(ctx context.Context, state *agent.State) error {
|
||||
thumbprint := agent.Thumbprint(ctx)
|
||||
|
||||
connected := true
|
||||
agent, err := cl.GetAgent(
|
||||
ctx,
|
||||
state.AgentID(),
|
||||
)
|
||||
|
||||
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,
|
||||
@ -53,27 +73,14 @@ func (c *Controller) Reconcile(ctx context.Context, state *agent.State) error {
|
||||
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.reconcileAgent(ctx, connected, claimed); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Controller) reconcileAgent(ctx context.Context, connected bool, claimed bool) error {
|
||||
shouldStart := !connected || !claimed
|
||||
|
||||
if shouldStart {
|
||||
if err := c.startServer(ctx); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
} else {
|
||||
if err := c.stopServer(ctx); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -104,21 +111,6 @@ func (c *Controller) startServer(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Controller) stopServer(ctx context.Context) error {
|
||||
server := c.getServer()
|
||||
if server == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
defer c.setServer(nil)
|
||||
|
||||
if err := server.Close(); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Controller) setServer(s *http.Server) {
|
||||
c.server.Store(s)
|
||||
}
|
||||
@ -132,9 +124,12 @@ func (c *Controller) getServer() *http.Server {
|
||||
return server
|
||||
}
|
||||
|
||||
func NewController(addr string) *Controller {
|
||||
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{},
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package registration
|
||||
package status
|
||||
|
||||
import (
|
||||
"embed"
|
1
internal/agent/controller/status/public/bulma-0.9.4.min.css
vendored
Normal file
1
internal/agent/controller/status/public/bulma-0.9.4.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
internal/agent/controller/status/public/logo.png
Normal file
BIN
internal/agent/controller/status/public/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
2
internal/agent/controller/status/public/qrcode.min.js
vendored
Normal file
2
internal/agent/controller/status/public/qrcode.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
145
internal/agent/controller/status/templates/index.html.gotpl
Normal file
145
internal/agent/controller/status/templates/index.html.gotpl
Normal file
@ -0,0 +1,145 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="logo.png">
|
||||
<title>Status | Emissary Agent</title>
|
||||
<link rel="stylesheet" href="bulma-0.9.4.min.css">
|
||||
<style>
|
||||
body {
|
||||
background-color: #f7f7f7f7;
|
||||
}
|
||||
.logo {
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
margin-left: -40px;
|
||||
width: 100px;
|
||||
margin-top: -120px
|
||||
}
|
||||
.card {
|
||||
position:relative;
|
||||
padding-top: 70px;
|
||||
margin-top: 70px;
|
||||
}
|
||||
#qrcode {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
{{if or .Connected ( not .Claimed ) }}
|
||||
<script type="text/javascript" src="qrcode.min.js"></script>
|
||||
{{ end }}
|
||||
</head>
|
||||
<body>
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="column">
|
||||
<div class="has-text-centered">
|
||||
<h1 class="title is-size-1 ">Emissary</h1>
|
||||
<h2 class="subtitle is-size-4">Agent Status</h2>
|
||||
</div>
|
||||
<div class="box card">
|
||||
<img class="logo" src="logo.png" />
|
||||
<div class="overflow:hidden">
|
||||
<div class="level is-mobile" style="margin-top:-50px">
|
||||
<div class="level-left">
|
||||
<div class="level-item is-size-4-tablet is-size-7-mobile">
|
||||
<strong class="mr-2">Connected:</strong>{{if .Connected }}<span class="has-text-success">✔</span>{{ else }}<span class="has-text-danger">✕</span>{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
<div class="level-item is-size-4-tablet is-size-7-mobile">
|
||||
<strong class="mr-2">Claimed:</strong>{{if .Claimed }}<span class="has-text-success">✔</span>{{ else }}<span class="has-text-warning">✕</span>{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ if and .Connected ( not .Claimed ) }}
|
||||
<h3 class="is-size-3 mt-4">Claim your agent</h3>
|
||||
<p class="has-text-centered">
|
||||
You can claim your agent by clicking the following link:<br />
|
||||
<a class="button is-link is-medium mt-3" href="{{ .ClaimURL }}" target="_blank" rel="nofollow">Claim me</a><br />
|
||||
</p>
|
||||
<p class="has-text-centered mt-3">
|
||||
You can also scan the following QRCode:
|
||||
<div id="qrcode" class="mt-3" data-claim-url="{{ .ClaimURL }}"></div>
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
const qrCodeElement = document.getElementById("qrcode");
|
||||
const claimUrl = qrCodeElement.dataset.claimUrl;
|
||||
new QRCode(qrCodeElement, claimUrl);
|
||||
}())
|
||||
</script>
|
||||
</p>
|
||||
{{ end }}
|
||||
{{ if and .Connected .Claimed }}
|
||||
<h3 class="is-size-3 mt-4">Manage your agent</h3>
|
||||
<p class="has-text-centered">
|
||||
You can manage your agent by clicking the following link:<br />
|
||||
<a class="button is-link is-medium mt-3" href="{{ .AgentURL }}" target="_blank" rel="nofollow">Manage me</a><br />
|
||||
</p>
|
||||
<p class="has-text-centered mt-3">
|
||||
You can also scan the following QRCode:
|
||||
<div id="qrcode" class="mt-3" data-agent-url="{{ .AgentURL }}"></div>
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
const qrCodeElement = document.getElementById("qrcode");
|
||||
const agentUrl = qrCodeElement.dataset.agentUrl;
|
||||
new QRCode(qrCodeElement, agentUrl);
|
||||
}())
|
||||
</script>
|
||||
</p>
|
||||
{{ end }}
|
||||
<h3 class="is-size-3 mt-4">Informations</h3>
|
||||
<div class="table-container">
|
||||
<table class="table is-fullwidth">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Attribute</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Thumbprint</td>
|
||||
<td><code>{{ .Thumbprint }}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Agent ID</td>
|
||||
<td><code>{{ if .Agent }}{{ .Agent.ID }}{{ else }}unknown{{end}}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Agent Label</td>
|
||||
<td><code>{{ with .Agent }}{{ if .Label }}{{ .Label }}{{ else }}empty{{end}}{{ else }}unknown{{end}}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Last server contact</td>
|
||||
<td><code>{{ if .Agent }}{{ .Agent.ContactedAt }}{{ else }}unknown{{end}}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Server URL</td>
|
||||
<td><code>{{ .ServerURL }}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Claim URL</td>
|
||||
<td><code>{{ .ClaimURL }}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Agent URL</td>
|
||||
<td><code>{{ if .Agent }}{{ .AgentURL }}{{ else }}unknown{{end}}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Agent version</td>
|
||||
<td><code>{{ .AgentVersion }}</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
@ -9,8 +9,8 @@ import (
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/openwrt"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/persistence"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/proxy"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/registration"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/spec"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/status"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/metadata"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/metadata/collector/buildinfo"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/metadata/collector/shell"
|
||||
@ -95,9 +95,12 @@ func RunCommand() *cli.Command {
|
||||
))
|
||||
}
|
||||
|
||||
if ctrlConf.Registration.Enabled {
|
||||
controllers = append(controllers, registration.NewController(
|
||||
string(ctrlConf.Registration.Address),
|
||||
if ctrlConf.Status.Enabled {
|
||||
controllers = append(controllers, status.NewController(
|
||||
string(ctrlConf.Status.Address),
|
||||
string(ctrlConf.Status.ClaimURL),
|
||||
string(ctrlConf.Status.AgentURL),
|
||||
string(ctx.String("projectVersion")),
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ type ControllersConfig struct {
|
||||
App AppControllerConfig `yaml:"app"`
|
||||
SysUpgrade SysUpgradeControllerConfig `yaml:"sysupgrade"`
|
||||
MDNS MDNSControllerConfig `yaml:"mdns"`
|
||||
Registration RegistrationControllerConfig `yaml:"registration"`
|
||||
Status StatusControllerConfig `yaml:"status"`
|
||||
}
|
||||
|
||||
type PersistenceControllerConfig struct {
|
||||
@ -61,9 +61,11 @@ type MDNSControllerConfig struct {
|
||||
Enabled InterpolatedBool `yaml:"enabled"`
|
||||
}
|
||||
|
||||
type RegistrationControllerConfig struct {
|
||||
type StatusControllerConfig struct {
|
||||
Enabled InterpolatedBool `yaml:"enabled"`
|
||||
Address InterpolatedString `yaml:"address"`
|
||||
ClaimURL InterpolatedString `yaml:"claimURL"`
|
||||
AgentURL InterpolatedString `yaml:"agentURL"`
|
||||
}
|
||||
|
||||
func NewDefaultAgentConfig() AgentConfig {
|
||||
@ -100,9 +102,11 @@ func NewDefaultAgentConfig() AgentConfig {
|
||||
MDNS: MDNSControllerConfig{
|
||||
Enabled: true,
|
||||
},
|
||||
Registration: RegistrationControllerConfig{
|
||||
Status: StatusControllerConfig{
|
||||
Enabled: true,
|
||||
Address: ":42521",
|
||||
ClaimURL: "http://localhost:3001/claim/%s",
|
||||
AgentURL: "http://localhost:3001/agents/%v",
|
||||
},
|
||||
},
|
||||
Collectors: []ShellCollectorConfig{
|
||||
|
@ -63,6 +63,16 @@ agent:
|
||||
- -c
|
||||
- source /etc/openwrt_release && echo "$DISTRIB_ID-$DISTRIB_RELEASE-$DISTRIB_REVISION"
|
||||
|
||||
# Status controller configuration
|
||||
status:
|
||||
enabled: true
|
||||
# Status page listening address
|
||||
address: :42521
|
||||
# Agent claim URL template (see Emissary HQ)
|
||||
claimURL: http://127.0.0.1:3001/claim/%v
|
||||
# Agent URL template (see Emissary HQ)
|
||||
agentURL: http://127.0.0.1:3001/agents/%v
|
||||
|
||||
# Collectors configuration
|
||||
collectors:
|
||||
- name: uname
|
||||
|
Loading…
x
Reference in New Issue
Block a user