Updated agent to include ping in heartbeat.
This commit is contained in:
@@ -144,11 +144,16 @@ func shipLogs(ctx context.Context, apiClient *client.Client, cfg *config.Config)
|
|||||||
|
|
||||||
func reportHost(ctx context.Context, apiClient *client.Client, cfg *config.Config) error {
|
func reportHost(ctx context.Context, apiClient *client.Client, cfg *config.Config) error {
|
||||||
info := host.Detect()
|
info := host.Detect()
|
||||||
|
var pingPtr *int
|
||||||
|
if pingMs, err := apiClient.Ping(ctx); err == nil {
|
||||||
|
pingPtr = &pingMs
|
||||||
|
}
|
||||||
return retry(ctx, []time.Duration{250 * time.Millisecond, time.Second, 2 * time.Second}, func() error {
|
return retry(ctx, []time.Duration{250 * time.Millisecond, time.Second, 2 * time.Second}, func() error {
|
||||||
return apiClient.UpdateHost(ctx, cfg.ServerID, client.HeartbeatRequest{
|
return apiClient.UpdateHost(ctx, cfg.ServerID, client.HeartbeatRequest{
|
||||||
Host: info.Hostname,
|
Host: info.Hostname,
|
||||||
IPv4: info.IPv4,
|
IPv4: info.IPv4,
|
||||||
IPv6: info.IPv6,
|
IPv6: info.IPv6,
|
||||||
|
PingMs: pingPtr,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"server_url": "https://keywarden.dev.ntbx.io/api/v1",
|
"server_url": "https://keywarden.dev.ntbx.io/api/v1",
|
||||||
"server_id": "4",
|
"server_id": "4",
|
||||||
"server_ca_path": "",
|
"server_ca_path": "",
|
||||||
"sync_interval_seconds": 30,
|
"sync_interval_seconds": 5,
|
||||||
"log_batch_size": 500,
|
"log_batch_size": 500,
|
||||||
"state_dir": "/var/lib/keywarden-agent",
|
"state_dir": "/var/lib/keywarden-agent",
|
||||||
"account_policy": {
|
"account_policy": {
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -22,6 +24,10 @@ const defaultTimeout = 15 * time.Second
|
|||||||
type Client struct {
|
type Client struct {
|
||||||
baseURL string
|
baseURL string
|
||||||
http *http.Client
|
http *http.Client
|
||||||
|
tlsCfg *tls.Config
|
||||||
|
scheme string
|
||||||
|
host string
|
||||||
|
addr string
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg *config.Config) (*Client, error) {
|
func New(cfg *config.Config) (*Client, error) {
|
||||||
@@ -62,7 +68,36 @@ func New(cfg *config.Config) (*Client, error) {
|
|||||||
Transport: transport,
|
Transport: transport,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Client{baseURL: baseURL, http: httpClient}, nil
|
parsed, err := url.Parse(baseURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("parse server url: %w", err)
|
||||||
|
}
|
||||||
|
if parsed.Host == "" {
|
||||||
|
return nil, errors.New("server url missing host")
|
||||||
|
}
|
||||||
|
scheme := parsed.Scheme
|
||||||
|
if scheme == "" {
|
||||||
|
scheme = "https"
|
||||||
|
}
|
||||||
|
host := parsed.Hostname()
|
||||||
|
port := parsed.Port()
|
||||||
|
if port == "" {
|
||||||
|
if scheme == "http" {
|
||||||
|
port = "80"
|
||||||
|
} else {
|
||||||
|
port = "443"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addr := net.JoinHostPort(host, port)
|
||||||
|
|
||||||
|
return &Client{
|
||||||
|
baseURL: baseURL,
|
||||||
|
http: httpClient,
|
||||||
|
tlsCfg: tlsConfig,
|
||||||
|
scheme: scheme,
|
||||||
|
host: host,
|
||||||
|
addr: addr,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type EnrollRequest struct {
|
type EnrollRequest struct {
|
||||||
@@ -293,9 +328,10 @@ func (c *Client) SendLogBatch(ctx context.Context, serverID string, payload []by
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HeartbeatRequest struct {
|
type HeartbeatRequest struct {
|
||||||
Host string `json:"host,omitempty"`
|
Host string `json:"host,omitempty"`
|
||||||
IPv4 string `json:"ipv4,omitempty"`
|
IPv4 string `json:"ipv4,omitempty"`
|
||||||
IPv6 string `json:"ipv6,omitempty"`
|
IPv6 string `json:"ipv6,omitempty"`
|
||||||
|
PingMs *int `json:"ping_ms,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) UpdateHost(ctx context.Context, serverID string, reqBody HeartbeatRequest) error {
|
func (c *Client) UpdateHost(ctx context.Context, serverID string, reqBody HeartbeatRequest) error {
|
||||||
@@ -318,3 +354,29 @@ func (c *Client) UpdateHost(ctx context.Context, serverID string, reqBody Heartb
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) Ping(ctx context.Context) (int, error) {
|
||||||
|
if c.addr == "" {
|
||||||
|
return 0, errors.New("server address not configured")
|
||||||
|
}
|
||||||
|
start := time.Now()
|
||||||
|
dialer := &net.Dialer{Timeout: defaultTimeout}
|
||||||
|
if c.scheme == "http" {
|
||||||
|
conn, err := dialer.DialContext(ctx, "tcp", c.addr)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
_ = conn.Close()
|
||||||
|
return int(time.Since(start).Milliseconds()), nil
|
||||||
|
}
|
||||||
|
cfg := c.tlsCfg.Clone()
|
||||||
|
if cfg.ServerName == "" && c.host != "" {
|
||||||
|
cfg.ServerName = c.host
|
||||||
|
}
|
||||||
|
conn, err := tls.DialWithDialer(dialer, "tcp", c.addr, cfg)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
_ = conn.Close()
|
||||||
|
return int(time.Since(start).Milliseconds()), nil
|
||||||
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -70,7 +70,7 @@
|
|||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<span class="font-semibold text-gray-500">Last heartbeat</span>
|
<span class="font-semibold text-gray-500">Last heartbeat</span>
|
||||||
<span class="font-medium text-gray-900">
|
<span class="font-medium text-gray-900">
|
||||||
{% if server_status.heartbeat_at %}{{ server_status.heartbeat_at|date:"M j, Y H:i" }}{% else %}—{% endif %}
|
{% if server_status.heartbeat_at %}{{ server_status.heartbeat_at|date:"M j, Y H:i:s" }}{% else %}—{% endif %}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -69,7 +69,7 @@
|
|||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<span class="font-semibold text-gray-500">Last heartbeat</span>
|
<span class="font-semibold text-gray-500">Last heartbeat</span>
|
||||||
<span class="font-medium text-gray-900">
|
<span class="font-medium text-gray-900">
|
||||||
{% if item.status.heartbeat_at %}{{ item.status.heartbeat_at|date:"M j, Y H:i" }}{% else %}—{% endif %}
|
{% if item.status.heartbeat_at %}{{ item.status.heartbeat_at|date:"M j, Y H:i:s" }}{% else %}—{% endif %}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -189,16 +189,18 @@ def _format_age_short(delta: timedelta) -> str:
|
|||||||
if seconds < 60:
|
if seconds < 60:
|
||||||
return f"{seconds}s"
|
return f"{seconds}s"
|
||||||
minutes = seconds // 60
|
minutes = seconds // 60
|
||||||
|
rem_seconds = seconds % 60
|
||||||
if minutes < 60:
|
if minutes < 60:
|
||||||
return f"{minutes}m"
|
return f"{minutes}m {rem_seconds}s"
|
||||||
hours = minutes // 60
|
hours = minutes // 60
|
||||||
|
rem_minutes = minutes % 60
|
||||||
if hours < 48:
|
if hours < 48:
|
||||||
return f"{hours}h"
|
return f"{hours}h {rem_minutes}m {rem_seconds}s"
|
||||||
days = hours // 24
|
days = hours // 24
|
||||||
if days < 14:
|
if days < 14:
|
||||||
return f"{days}d"
|
return f"{days}d {hours % 24}h"
|
||||||
weeks = days // 7
|
weeks = days // 7
|
||||||
return f"{weeks}w"
|
return f"{weeks}w {days % 7}d"
|
||||||
|
|
||||||
|
|
||||||
def _build_server_status(server: Server, now):
|
def _build_server_status(server: Server, now):
|
||||||
|
|||||||
Reference in New Issue
Block a user