VM Tracker Client - Reference Documentation¶
Table of Contents¶
- Overview
- Data Structures
- Interfaces
- Functions
- Command Line Parameters
- Usage Examples
- Error Handling
- Integration
Overview¶
The VM Tracker Client is a service written in Go that automatically sends information about virtual machines (VMs) to a central API server. The client continuously monitors hostname and IP address of a VM and registers this information at regular intervals.
Main Features¶
- ✅ Automatic hostname detection
- ✅ Detection of IPv4 addresses on specific network interfaces
- ✅ Periodic registration with an API server
- ✅ Automatic retry on errors
- ✅ Graceful shutdown on SIGTERM/SIGINT
- ✅ Configurable update interval
Architecture¶
┌─────────────────────┐
│ VM Tracker Client │
│ │
│ ┌───────────────┐ │
│ │ Hostname │ │
│ │ Detection │ │
│ └───────────────┘ │
│ │
│ ┌───────────────┐ │
│ │ IP Address │ │
│ │ Detection │ │
│ └───────────────┘ │
│ │
│ ┌───────────────┐ │
│ │ HTTP Client │ │
│ │ Registration │ │
│ └───────────────┘ │
└─────────────────────┘
│
│ HTTP POST
│ /api/register
▼
┌─────────────────────┐
│ API Server │
└─────────────────────┘
Data Structures¶
VMInfo¶
The central data structure containing information about a VM.
Definition¶
type VMInfo struct {
Hostname string `json:"hostname"`
IPAddress string `json:"ip_address"`
Interface string `json:"interface"`
}
Fields¶
| Field | Type | JSON Tag | Description |
|---|---|---|---|
Hostname |
string |
hostname |
The hostname of the VM (e.g., "web-server-01") |
IPAddress |
string |
ip_address |
The IPv4 address of the VM (e.g., "192.168.1.100") |
Interface |
string |
interface |
The name of the network interface (e.g., "eth0", "enp0s1") |
JSON Representation¶
Usage¶
info := VMInfo{
Hostname: "my-vm",
IPAddress: "10.0.0.5",
Interface: "enp0s1",
}
// JSON marshaling
jsonData, err := json.Marshal(info)
if err != nil {
log.Fatal(err)
}
// JSON unmarshaling
var vmInfo VMInfo
err = json.Unmarshal(jsonData, &vmInfo)
if err != nil {
log.Fatal(err)
}
Validation¶
- Hostname: Can contain any characters but should conform to a valid hostname format
- IPAddress: Must be a valid IPv4 address (validated by
net.ParseIP()) - Interface: Must be an existing network interface on the system
Interfaces¶
HTTPClient¶
Interface for HTTP operations, enables mocking and testing.
Definition¶
type HTTPClient interface {
Post(url, contentType string, body *bytes.Buffer) (*http.Response, error)
}
Methods¶
Post¶
Parameters:
- url (string): The complete URL for the POST request
- contentType (string): MIME type of the request body (e.g., "application/json")
- body (*bytes.Buffer): The request body as a buffer
Return Values:
- *http.Response: The HTTP response or nil on error
- error: Error information or nil on success
Example:
client := &DefaultHTTPClient{}
body := bytes.NewBufferString(`{"key":"value"}`)
resp, err := client.Post("http://api.example.com/data", "application/json", body)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
DefaultHTTPClient¶
Production implementation of the HTTPClient interface.
Definition¶
Methods¶
func (c *DefaultHTTPClient) Post(url, contentType string, body *bytes.Buffer) (*http.Response, error)
Wrapper around the standard http.Post() function.
Usage:
Functions¶
getHostname¶
Determines the hostname of the system.
Signature¶
Return Values¶
string: The hostname of the system or "unknown" on error
Description¶
This function uses os.Hostname() to determine the hostname. On error, "unknown" is returned and the error is logged.
Example¶
Error Handling¶
- On errors, a warning is logged:
"Error getting hostname: <error>" - Return value is always a valid string (never empty)
See Also¶
- Reference: main.go:24
getIPAddress¶
Determines the IPv4 address of a specific network interface.
Signature¶
Parameters¶
interfaceName(string): Name of the network interface (e.g., "eth0", "enp0s1", "en0")
Return Values¶
string: The IPv4 address of the interface or empty string on errorerror: Error information ornilon success
Description¶
This function searches for the specified network interface and returns the first non-loopback IPv4 address found.
Example¶
ip, err := getIPAddress("eth0")
if err != nil {
log.Fatal(err)
}
fmt.Printf("IP Address: %s\n", ip)
// Output: IP Address: 192.168.1.100
Errors¶
| Error Type | Description |
|---|---|
"interface %s not found: %v" |
The specified interface doesn't exist |
"error getting addresses for %s: %v" |
Error retrieving addresses |
"no IPv4 address found on interface %s" |
No IPv4 address found on the interface |
Implementation Details¶
- Searches for the interface with
net.InterfaceByName() - Retrieves all addresses with
iface.Addrs() - Filters for non-loopback IPv4 addresses
- Returns the first address found
See Also¶
- Reference: main.go:33
sendRegistration¶
Sends a VM registration to the API server (production wrapper).
Signature¶
Parameters¶
apiURL(string): Base URL of the API server (e.g., "http://api.example.com:8080")info(VMInfo): VM information to send
Return Values¶
error: Error information ornilon success
Description¶
This function is a wrapper around sendRegistrationWithClient() and uses the DefaultHTTPClient for production environments.
Example¶
apiURL := "http://api.example.com:8080"
info := VMInfo{
Hostname: "web-01",
IPAddress: "192.168.1.100",
Interface: "eth0",
}
err := sendRegistration(apiURL, info)
if err != nil {
log.Printf("Registration failed: %v", err)
}
See Also¶
sendRegistrationWithClient()for detailed implementation- Reference: main.go:70
sendRegistrationWithClient¶
Sends a VM registration with a custom HTTP client.
Signature¶
Parameters¶
apiURL(string): Base URL of the API serverinfo(VMInfo): VM information to sendclient(HTTPClient): HTTP client for the request
Return Values¶
error: Error information ornilon success
Description¶
Sends an HTTP POST request to <apiURL>/api/register with the VM information as JSON body.
HTTP Request¶
Endpoint: POST /api/register
Headers:
Body:
HTTP Response¶
Success:
- Status Code: 200 OK
Error:
- Status Code: != 200 (any error code)
Errors¶
| Error Type | Description |
|---|---|
"error marshaling JSON: %v" |
JSON serialization failed |
"error sending request: %v" |
Network error when sending |
"server returned status %d" |
Server returned a non-200 status code |
Example with Mock Client¶
// Mock for testing
mockClient := &MockHTTPClient{
PostFunc: func(url, contentType string, body *bytes.Buffer) (*http.Response, error) {
return &http.Response{
StatusCode: 200,
Body: io.NopCloser(bytes.NewBufferString("OK")),
}, nil
},
}
info := VMInfo{
Hostname: "test-vm",
IPAddress: "192.168.1.100",
Interface: "eth0",
}
err := sendRegistrationWithClient("http://api.example.com", info, mockClient)
if err != nil {
log.Fatal(err)
}
Implementation Details¶
- Marshals
VMInfoto JSON - Sends POST request to
<apiURL>/api/register - Checks HTTP status code
- Properly closes response body
See Also¶
- Reference: main.go:74
Command Line Parameters¶
The VM Tracker Client supports the following command line flags:
-api¶
Type: string
Default: "http://10.0.2.196:8080"
Description: URL of the API server
Usage:
./vm-tracker-client -api "http://api.example.com:8080"
./vm-tracker-client -api "https://secure-api.example.com"
Notes: - Trailing slashes are automatically removed - Supports HTTP and HTTPS - Port can be optionally specified
-interface¶
Type: string
Default: "enp0s1"
Description: Name of the network interface to monitor
Usage:
./vm-tracker-client -interface "eth0"
./vm-tracker-client -interface "en0"
./vm-tracker-client -interface "wlan0"
Common Interface Names:
| Operating System | Typical Names |
|---|---|
| Linux | eth0, eth1, enp0s1, enp0s3 |
| macOS | en0, en1 |
| Windows | Ethernet, Wi-Fi |
-interval¶
Type: int
Default: 30
Unit: Seconds
Description: Interval between updates
Usage:
./vm-tracker-client -interval 60 # Every 60 seconds
./vm-tracker-client -interval 10 # Every 10 seconds
./vm-tracker-client -interval 300 # Every 5 minutes
Recommended Values: - Development: 10-30 seconds - Production: 60-300 seconds - Low load: 300+ seconds
-retry¶
Type: int
Default: 5
Unit: Seconds
Description: Wait time between retry attempts on errors
Usage:
-verbose¶
Type: bool
Default: false
Description: Enables verbose logging
Usage:
Output with -verbose:
2025/11/04 12:00:00 Sending registration: {Hostname:web-01 IPAddress:192.168.1.100 Interface:eth0}
2025/11/04 12:00:00 Update sent successfully
2025/11/04 12:00:30 Sending update: {Hostname:web-01 IPAddress:192.168.1.100 Interface:eth0}
2025/11/04 12:00:30 Update sent successfully
Usage Examples¶
Basic Usage¶
# Simplest start with default values
./vm-tracker-client
# With custom parameters
./vm-tracker-client \
-api "http://api.example.com:8080" \
-interface "eth0" \
-interval 60 \
-verbose
Docker Container¶
docker run -d \
--name vm-tracker-client \
--network host \
vm-tracker-client:latest \
-api "http://api-server:8080" \
-interface "eth0" \
-interval 30
Systemd Service¶
[Unit]
Description=VM Tracker Client
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/vm-tracker-client \
-api "http://api.example.com:8080" \
-interface "eth0" \
-interval 60 \
-retry 5
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Kubernetes Deployment¶
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: vm-tracker-client
spec:
selector:
matchLabels:
app: vm-tracker-client
template:
metadata:
labels:
app: vm-tracker-client
spec:
hostNetwork: true
containers:
- name: client
image: vm-tracker-client:latest
args:
- "-api"
- "http://vm-tracker-api:8080"
- "-interface"
- "eth0"
- "-interval"
- "60"
- "-verbose"
Programmatic Usage¶
package main
import (
"log"
"time"
)
func main() {
apiURL := "http://api.example.com:8080"
interfaceName := "eth0"
// Initial registration
hostname := getHostname()
ipAddress, err := getIPAddress(interfaceName)
if err != nil {
log.Fatalf("Failed to get IP: %v", err)
}
info := VMInfo{
Hostname: hostname,
IPAddress: ipAddress,
Interface: interfaceName,
}
err = sendRegistration(apiURL, info)
if err != nil {
log.Fatalf("Failed to register: %v", err)
}
log.Printf("Successfully registered: %s @ %s", hostname, ipAddress)
// Periodic updates
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()
for range ticker.C {
// Update and send
ipAddress, err := getIPAddress(interfaceName)
if err != nil {
log.Printf("Error getting IP: %v", err)
continue
}
info.IPAddress = ipAddress
err = sendRegistration(apiURL, info)
if err != nil {
log.Printf("Failed to send update: %v", err)
}
}
}
Error Handling¶
Retry Mechanism¶
The client implements automatic retry on errors:
Initial Registration¶
maxRetries := 3
retryCount := 0
for retryCount < maxRetries {
err := sendRegistration(apiURL, info)
if err == nil {
break // Success
}
log.Printf("Failed to register: %v, retrying in %d seconds...", err, retryDelay)
time.Sleep(time.Duration(retryDelay) * time.Second)
retryCount++
}
if retryCount >= maxRetries {
log.Fatalf("Failed to register after %d attempts, exiting", maxRetries)
}
Periodic Updates¶
For periodic updates, errors do not abort, only log:
for {
select {
case <-ticker.C:
err := sendRegistration(apiURL, info)
if err != nil {
log.Printf("Failed to send update: %v", err)
// Wait for next tick
}
}
}
Error Types¶
| Error Type | Description | Handling |
|---|---|---|
| Network Error | Connection to server failed | Retry with exponential backoff |
| HTTP 4xx | Client error (e.g., invalid data) | Log, possibly abort |
| HTTP 5xx | Server error | Retry with wait time |
| Interface Error | Network interface not found | Log, keep trying |
| JSON Error | Serialization error | Log, critical error |
Signal Handling¶
Graceful shutdown on SIGTERM/SIGINT:
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGINT)
for {
select {
case sig := <-sigChan:
log.Printf("Received signal %v, shutting down...", sig)
return
case <-ticker.C:
// Normal operation
}
}
Supported Signals:
- SIGTERM - Graceful shutdown
- SIGINT - Ctrl+C interrupt
Integration¶
API Server Requirements¶
The client expects a compatible API server with the following endpoint:
POST /api/register¶
Request:
POST /api/register HTTP/1.1
Host: api.example.com:8080
Content-Type: application/json
{
"hostname": "web-server-01",
"ip_address": "192.168.1.100",
"interface": "eth0"
}
Success Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"status": "registered",
"timestamp": "2025-11-04T12:00:00Z"
}
Error Response:
Monitoring & Logging¶
The client writes logs to stdout/stderr:
Log Levels:
| Level | Example | Description |
|---|---|---|
| INFO | VM Tracker Client starting... |
Normal operations |
| INFO | Successfully registered with API server |
Successful actions |
| WARNING | Warning: interface not found, retrying... |
Non-critical errors |
| ERROR | Failed to register: connection refused |
Errors with retry |
| FATAL | Failed to register after 3 attempts, exiting |
Critical errors, program abort |
Log Format:
Metrics¶
For monitoring, the following metrics can be captured:
- Registration Success Rate: Successful vs. failed registrations
- API Response Time: Time for /api/register calls
- Update Interval: Actual vs. configured interval
- Retry Count: Number of retry attempts
- Uptime: Runtime of the client
Health Checks¶
For container orchestration:
# Check if process is running
pgrep -f vm-tracker-client
# Check if updates are being sent (log-based)
timeout 65 tail -f /var/log/vm-tracker.log | grep -q "Update sent"
Appendix¶
Build Instructions¶
# Standard build
go build -o vm-tracker-client main.go
# With optimization
go build -ldflags="-s -w" -o vm-tracker-client main.go
# Cross-compilation for Linux
GOOS=linux GOARCH=amd64 go build -o vm-tracker-client-linux main.go
# With version info
go build -ldflags="-X main.Version=1.0.0" -o vm-tracker-client main.go
Testing¶
# Unit tests
go test -v
# With coverage
go test -v -cover -coverprofile=coverage.out
# Benchmarks
go test -bench=. -benchmem
Dependencies¶
The client uses only Go Standard Library:
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"log"
"net"
"net/http"
"os"
"os/signal"
"strings"
"syscall"
"time"
)
No external dependencies required!
Performance¶
Resource Usage: - CPU: < 1% idle, < 5% during updates - Memory: ~5-10 MB RAM - Network: Minimal (~1-2 KB per update)
Scaling: - Can run thousands of instances in parallel - Network load: ~2 KB × (Number of VMs) / Interval - Example: 1000 VMs @ 60s interval = ~33 KB/s
Security¶
Recommendations:
- Use HTTPS:
-api "https://api.example.com" - Authentication: Extend with API keys/tokens if needed
- Firewall: Only allow outbound connections to API server
- Least Privilege: Run client with minimal permissions
- Log Rotation: Regularly rotate and archive logs
License¶
Please refer to the project's license terms.
Support¶
For questions or problems:
- See unittests for test documentation
- Create an issue in the repository
- Check logs with -verbose flag
Version: 1.0 Last Updated: 2025-11-04 Author: VM Tracker Team