Implement CheckCle Microservice Operation
A Go-based microservice for service operations including ICMP ping, DNS resolution, and TCP connectivity
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (h *OperationHandler) HandleHealth(w http.ResponseWriter, r *http.Request) {
|
||||
health := map[string]interface{}{
|
||||
"status": "healthy",
|
||||
"service": "service-operation",
|
||||
"timestamp": time.Now().Unix(),
|
||||
"version": "1.0.0",
|
||||
"operations": []string{"ping", "dns", "tcp", "http"},
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(health)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"service-operation/shared/savers"
|
||||
"service-operation/types"
|
||||
)
|
||||
|
||||
func (h *OperationHandler) saveMetricsToPocketBase(result *types.OperationResult, serviceID string) {
|
||||
metricsSaver := savers.NewMetricsSaver(h.pbClient)
|
||||
metricsSaver.SaveMetricsToPocketBase(result, serviceID)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"service-operation/config"
|
||||
"service-operation/pocketbase"
|
||||
)
|
||||
|
||||
type OperationHandler struct {
|
||||
config *config.Config
|
||||
pbClient *pocketbase.PocketBaseClient
|
||||
}
|
||||
|
||||
func NewOperationHandler(cfg *config.Config, pbClient *pocketbase.PocketBaseClient) *OperationHandler {
|
||||
return &OperationHandler{
|
||||
config: cfg,
|
||||
pbClient: pbClient,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"service-operation/operations"
|
||||
"service-operation/types"
|
||||
)
|
||||
|
||||
func (h *OperationHandler) HandleOperation(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
var req types.OperationRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http.Error(w, "Invalid JSON payload", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Host == "" && req.URL == "" {
|
||||
http.Error(w, "Host or URL is required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Set defaults
|
||||
if req.Count <= 0 {
|
||||
req.Count = h.config.DefaultCount
|
||||
}
|
||||
if req.Count > h.config.MaxCount {
|
||||
req.Count = h.config.MaxCount
|
||||
}
|
||||
|
||||
if req.Timeout <= 0 {
|
||||
req.Timeout = int(h.config.DefaultTimeout.Seconds())
|
||||
}
|
||||
if time.Duration(req.Timeout)*time.Second > h.config.MaxTimeout {
|
||||
req.Timeout = int(h.config.MaxTimeout.Seconds())
|
||||
}
|
||||
|
||||
timeout := time.Duration(req.Timeout) * time.Second
|
||||
var result *types.OperationResult
|
||||
var err error
|
||||
|
||||
switch req.Type {
|
||||
case types.OperationPing:
|
||||
pingOp := operations.NewPingOperation(timeout)
|
||||
result, err = pingOp.Execute(req.Host, req.Count)
|
||||
|
||||
case types.OperationDNS:
|
||||
dnsOp := operations.NewDNSOperation(timeout)
|
||||
query := req.Query
|
||||
if query == "" {
|
||||
query = "A"
|
||||
}
|
||||
result, err = dnsOp.Execute(req.Host, query)
|
||||
|
||||
case types.OperationTCP:
|
||||
if req.Port <= 0 {
|
||||
http.Error(w, "Port is required for TCP operations", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
tcpOp := operations.NewTCPOperation(timeout)
|
||||
result, err = tcpOp.Execute(req.Host, req.Port)
|
||||
|
||||
case types.OperationHTTP:
|
||||
httpOp := operations.NewHTTPOperation(timeout)
|
||||
url := req.URL
|
||||
if url == "" {
|
||||
url = req.Host
|
||||
}
|
||||
method := req.Method
|
||||
if method == "" {
|
||||
method = "GET"
|
||||
}
|
||||
result, err = httpOp.Execute(url, method)
|
||||
|
||||
default:
|
||||
http.Error(w, "Invalid operation type", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
result = &types.OperationResult{
|
||||
Type: req.Type,
|
||||
Host: req.Host,
|
||||
Port: req.Port,
|
||||
Success: false,
|
||||
Error: err.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
// Save metrics to PocketBase if available
|
||||
if h.pbClient != nil && h.pbClient.IsAuthenticated() {
|
||||
go h.saveMetricsToPocketBase(result, req.ServiceID)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(result)
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"service-operation/types"
|
||||
)
|
||||
|
||||
func (h *OperationHandler) HandleQuickOperation(w http.ResponseWriter, r *http.Request) {
|
||||
opType := r.URL.Query().Get("type")
|
||||
host := r.URL.Query().Get("host")
|
||||
|
||||
if host == "" || opType == "" {
|
||||
http.Error(w, "Type and host parameters are required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
req := types.OperationRequest{
|
||||
Type: types.OperationType(opType),
|
||||
Host: host,
|
||||
}
|
||||
|
||||
// Parse optional parameters
|
||||
if countStr := r.URL.Query().Get("count"); countStr != "" {
|
||||
if c, err := strconv.Atoi(countStr); err == nil && c > 0 && c <= h.config.MaxCount {
|
||||
req.Count = c
|
||||
}
|
||||
}
|
||||
|
||||
if portStr := r.URL.Query().Get("port"); portStr != "" {
|
||||
if p, err := strconv.Atoi(portStr); err == nil && p > 0 && p <= 65535 {
|
||||
req.Port = p
|
||||
}
|
||||
}
|
||||
|
||||
if query := r.URL.Query().Get("query"); query != "" {
|
||||
req.Query = query
|
||||
}
|
||||
|
||||
if url := r.URL.Query().Get("url"); url != "" {
|
||||
req.URL = url
|
||||
}
|
||||
|
||||
if method := r.URL.Query().Get("method"); method != "" {
|
||||
req.Method = method
|
||||
}
|
||||
|
||||
if serviceID := r.URL.Query().Get("service_id"); serviceID != "" {
|
||||
req.ServiceID = serviceID
|
||||
}
|
||||
|
||||
// Forward to main handler
|
||||
reqBody, _ := json.Marshal(req)
|
||||
r.Body = http.NoBody
|
||||
r.Method = http.MethodPost
|
||||
r.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// Create a new request with the body
|
||||
newReq := r.Clone(r.Context())
|
||||
newReq.Body = http.NoBody
|
||||
newReq.ContentLength = int64(len(reqBody))
|
||||
|
||||
h.HandleOperation(w, newReq)
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"service-operation/types"
|
||||
)
|
||||
|
||||
func getStatusString(success bool) string {
|
||||
if success {
|
||||
return "up"
|
||||
}
|
||||
return "down"
|
||||
}
|
||||
|
||||
func formatResultDetails(result *types.OperationResult) string {
|
||||
details := map[string]interface{}{
|
||||
"type": result.Type,
|
||||
"response_time": result.ResponseTime,
|
||||
"start_time": result.StartTime,
|
||||
"end_time": result.EndTime,
|
||||
}
|
||||
|
||||
// Add type-specific details
|
||||
switch result.Type {
|
||||
case types.OperationPing:
|
||||
details["packets_sent"] = result.PacketsSent
|
||||
details["packets_recv"] = result.PacketsRecv
|
||||
details["packet_loss"] = result.PacketLoss
|
||||
details["avg_rtt"] = result.AvgRTT
|
||||
case types.OperationHTTP:
|
||||
details["status_code"] = result.HTTPStatusCode
|
||||
details["method"] = result.HTTPMethod
|
||||
details["content_length"] = result.ContentLength
|
||||
case types.OperationTCP:
|
||||
details["tcp_connected"] = result.TCPConnected
|
||||
case types.OperationDNS:
|
||||
details["dns_records"] = result.DNSRecords
|
||||
details["dns_type"] = result.DNSType
|
||||
}
|
||||
|
||||
jsonData, _ := json.Marshal(details)
|
||||
return string(jsonData)
|
||||
}
|
||||
Reference in New Issue
Block a user