How CasaOS Implements Its Health Check Service: Architecture and Code Deep Dive
CasaOS implements its health check service through a dedicated HealthService interface that queries systemd for CasaOS service status and scans system ports, exposing the results via REST endpoints at /api/v2/health/services and /api/v2/health/ports.
The health check service in the IceWhaleTech/CasaOS repository provides real-time visibility into internal system services and network port utilization. This subsystem combines Go interface design with external utilities from the CasaOS-Common package to deliver both programmatic and HTTP access to critical health metrics. Understanding this implementation reveals how CasaOS monitors its own operational state through clean abstraction layers and standard Linux interfaces.
Health Service Architecture
The implementation follows a layered architecture consisting of an interface definition, concrete implementation, and HTTP exposure layer.
The HealthService Interface
The contract for health checks is defined in service/health.go through the HealthService interface. This interface declares two primary methods:
Services()– Returns a map categorizing CasaOS services by their running statusPorts()– Returns slices of occupied TCP and UDP ports
This abstraction allows the health subsystem to remain agnostic of specific implementation details while providing a consistent API for the rest of the application.
Concrete Implementation
The service struct in service/health.go provides the concrete implementation of the HealthService interface. When instantiated, it leverages two critical utilities from the CasaOS-Common package:
systemctl.ListServices("casaos*")– Queries systemd for services matching the CasaOS patternport.ListPortsInUse()– Enumerates open network ports by scanning/proc/net/{tcp,udp}or utilizingnetstat
The results are packaged into structures required by the interface, specifically splitting service lists into running and notRunning categories and returning port data as separate integer slices for TCP and UDP.
Service Registration
The health service is wired into the global dependency container in service/service.go. The NewHealthService() factory function creates fresh instances, which are then stored in the Repository struct under the health field. The Health() accessor method makes this service available to HTTP handlers and other consumers throughout the application.
Data Collection Mechanisms
Understanding how CasaOS gathers health data requires examining the interaction between the core service and underlying system utilities.
Querying Systemd Services
The (*service).Services() method invokes systemctl.ListServices("casaos*") from the CasaOS-Common utilities. This helper executes a systemctl query, parses the output, and returns a slice of structures containing Name and Running fields. The implementation then partitions these results into two lists keyed by boolean values: true for running services and false for non-running services.
Scanning Network Ports
For port enumeration, the (*service).Ports() method forwards calls to port.ListPortsInUse(). This CasaOS-Common utility examines the system's network tables to identify occupied TCP and UDP ports, returning them as separate integer slices. A minimal test in service/health_test.go ensures this functionality returns non-empty slices without errors, validating the helper works across different CI environments.
HTTP API Exposure
The REST endpoints exposing health data are implemented in route/v2/health.go. These handlers interact with the service layer through the global MyService repository.
The router registers three primary endpoints:
GET /api/v2/health/services– Returns running and stopped CasaOS services viaGetHealthServicesGET /api/v2/health/ports– Returns occupied TCP and UDP ports viaGetHealthPortsGET /api/v2/health/logs– Provides access to system logs (referenced in the route handlers)
Each handler calls MyService.Health() to access the service instance, executes the appropriate method, and marshals the results into OpenAPI-generated response models (HealthServices and HealthPorts). Errors are translated into 500 JSON payloads, while successful responses return structured data matching the API specification.
Practical Usage Examples
Developers can interact with the health check service either programmatically through Go or via HTTP requests.
Consuming the Health Service in Go
To access health data directly from within the CasaOS codebase or external Go packages:
import (
"github.com/IceWhaleTech/CasaOS/service"
"log"
)
func main() {
// Obtain a health service instance
h := service.NewHealthService()
// 1️⃣ Get service status
services, err := h.Services()
if err != nil {
log.Fatalf("failed to list services: %v", err)
}
log.Printf("Running: %v", *services[true])
log.Printf("NotRunning:%v", *services[false])
// 2️⃣ Get occupied ports
tcp, udp, err := h.Ports()
if err != nil {
log.Fatalf("failed to list ports: %v", err)
}
log.Printf("TCP ports: %v", tcp)
log.Printf("UDP ports: %v", udp)
}
This pattern mirrors the internal usage found in the HTTP handlers.
Accessing Health Endpoints via REST
For external monitoring or debugging, use standard HTTP requests:
# List running and stopped CasaOS services
curl -s http://localhost:80/api/v2/health/services | jq .
# List occupied ports
curl -s http://localhost:80/api/v2/health/ports | jq .
Both endpoints return JSON objects conforming to the OpenAPI definitions (HealthServices and HealthPorts), making them suitable for integration with monitoring systems and automated health checks.
Summary
- CasaOS exposes health metrics through a dedicated
HealthServiceinterface defined inservice/health.go, implementing dependency injection patterns for testability. - The service queries systemd via
systemctl.ListServices("casaos*")to determine which CasaOS services are running or stopped. - Port enumeration relies on
port.ListPortsInUse()from CasaOS-Common, scanning/proc/net/{tcp,udp}to identify occupied TCP and UDP ports. - Global registration occurs in
service/service.gothroughNewHealthService()and theMyServicerepository, making the health service accessible throughout the application. - REST endpoints in
route/v2/health.goexpose/api/v2/health/servicesand/api/v2/health/ports, returning OpenAPI-compliant JSON responses suitable for external monitoring tools.
Frequently Asked Questions
How does CasaOS determine if its services are running?
CasaOS queries systemd using the systemctl.ListServices("casaos*") function from the CasaOS-Common package. This utility executes a systemctl command, parses the output to extract service names and their running states, and returns structured data that the HealthService implementation partitions into running and non-running categories.
What network ports does the health check service monitor?
The service monitors all TCP and UDP ports currently in use on the system. The (*service).Ports() method calls port.ListPortsInUse(), which returns two separate integer slices—one for TCP ports and one for UDP ports—by examining the system's network tables or using netstat as a fallback.
Where is the health check service instantiated in the CasaOS codebase?
The health service is instantiated in service/service.go within the NewService() function. This function creates a new HealthService via NewHealthService() and stores it in the global MyService repository, making it accessible through the Health() accessor method used by HTTP handlers in route/v2/health.go.
Can I use the health check service programmatically outside of the HTTP API?
Yes, you can import github.com/IceWhaleTech/CasaOS/service and call NewHealthService() directly to obtain an instance. This allows you to invoke Services() and Ports() programmatically from other Go packages without routing through HTTP, as demonstrated in the usage examples above.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →