feat: publish standalone worker
Separate worker packaging and service lifecycle from the control plane.
Этот коммит содержится в:
155
app/models/check_settings.go
Обычный файл
155
app/models/check_settings.go
Обычный файл
@@ -0,0 +1,155 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CheckHeader provides functionality.
|
||||
type CheckHeader struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// CheckSettings provides functionality.
|
||||
type CheckSettings struct {
|
||||
// HTTP Basic Auth Username
|
||||
HTTPUsername string `json:"http_username,omitempty"`
|
||||
// HTTP Basic Auth Password
|
||||
HTTPPassword string `json:"http_password,omitempty"`
|
||||
|
||||
// ExpectedAnswer (default, redirect, custom)
|
||||
ExpectedAnswer string `json:"expected_answer,omitempty"`
|
||||
// Expected redirect location
|
||||
ExpectedLocation string `json:"expected_location,omitempty"`
|
||||
// Expected HTTP status codes for custom
|
||||
ExpectedHTTPCode int `json:"expected_http_code,omitempty"`
|
||||
|
||||
// Keyword search type (off, present or absent)
|
||||
KeywordType string `json:"keyword_type,omitempty"`
|
||||
// Keyword to search for
|
||||
KeywordValue string `json:"keyword_value,omitempty"`
|
||||
|
||||
SlowTime int `json:"slow_time"`
|
||||
Timeout int `json:"timeout"`
|
||||
// Request Settings
|
||||
CheckIp bool `json:"checkip"` //nolint:revive // accepted lint exception
|
||||
CheckIPv6 bool `json:"checkipv6"`
|
||||
RequestHeader []CheckHeader `json:"request_headers"`
|
||||
RequestMethod string `json:"request_method"`
|
||||
RequestType string `json:"request_type"`
|
||||
RequestContent string `json:"request_content"`
|
||||
// SSH Settings
|
||||
Port string `json:"port"`
|
||||
|
||||
// Host optionally overrides the monitor host for checks that do
|
||||
// not naturally target the Monitor.Host (e.g. an ICMP/TCP/UDP
|
||||
// probe to a separate machine, or a different IP family). Used by
|
||||
// cping/ctcp/cudp.
|
||||
Host string `json:"host,omitempty"`
|
||||
|
||||
// Count is the per-check packet count for ping. Defaults to 1 in
|
||||
// cping when zero or negative.
|
||||
Count int `json:"count,omitempty"`
|
||||
|
||||
// PacketSize is the ICMP payload size for ping (bytes). Defaults
|
||||
// to 56 in cping when zero or negative.
|
||||
PacketSize int `json:"packet_size,omitempty"`
|
||||
|
||||
// Distributed marks this check as eligible for execution on the
|
||||
// distributed worker pool (multi-region, multi-worker) instead of
|
||||
// only the in-process scheduler. Reserved for paid plans; the
|
||||
// controller layer enforces the plan check.
|
||||
Distributed bool `json:"distributed"`
|
||||
}
|
||||
|
||||
// redirectCodes contains all HTTP redirect status codes.
|
||||
var redirectCodes = []int{300, 301, 302, 303, 307, 308}
|
||||
|
||||
// CheckKeyword provides functionality.
|
||||
func (s *CheckSettings) CheckKeyword(body []byte, warns []string) ([]string, error) {
|
||||
var err error
|
||||
|
||||
switch s.KeywordType {
|
||||
case "", "off":
|
||||
return warns, nil
|
||||
case "present":
|
||||
if !strings.Contains(string(body), s.KeywordValue) {
|
||||
err = errors.New("expected keyword " + s.KeywordValue + " not found")
|
||||
}
|
||||
case "absent":
|
||||
if strings.Contains(string(body), s.KeywordValue) {
|
||||
err = errors.New("unexpected keyword " + s.KeywordValue + " found")
|
||||
}
|
||||
}
|
||||
|
||||
return warns, err
|
||||
}
|
||||
|
||||
// CheckAnswer provides functionality.
|
||||
func (s *CheckSettings) CheckAnswer(resp *http.Response, body []byte) ([]string, error) {
|
||||
// log.Println("check answer, settings:")
|
||||
// spew.Dump(s)
|
||||
|
||||
isRedirect := false
|
||||
|
||||
for _, rc := range redirectCodes {
|
||||
if resp.StatusCode == rc {
|
||||
isRedirect = true
|
||||
}
|
||||
}
|
||||
|
||||
location := resp.Header.Get("location")
|
||||
|
||||
// log.Println("redirect?", isRedirect, location)
|
||||
|
||||
switch s.ExpectedAnswer {
|
||||
case "", "default":
|
||||
if isRedirect {
|
||||
return s.CheckKeyword(body, []string{"redirect: " + location})
|
||||
} else if resp.StatusCode != 200 {
|
||||
return []string{}, fmt.Errorf("bad status code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
case "redirect":
|
||||
if !isRedirect {
|
||||
return []string{}, fmt.Errorf("bad status code: %d (expected redirect)", resp.StatusCode)
|
||||
}
|
||||
|
||||
if s.ExpectedLocation != "" {
|
||||
if location != s.ExpectedLocation {
|
||||
return []string{}, fmt.Errorf(
|
||||
"bad location: %s (expected %s)",
|
||||
location,
|
||||
s.ExpectedLocation,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
case "custom":
|
||||
if s.ExpectedHTTPCode == 0 {
|
||||
s.ExpectedHTTPCode = 200
|
||||
}
|
||||
if resp.StatusCode != s.ExpectedHTTPCode {
|
||||
return []string{}, fmt.Errorf("bad status code: %d (expected %d)", resp.StatusCode, s.ExpectedHTTPCode)
|
||||
}
|
||||
|
||||
if s.ExpectedLocation != "" {
|
||||
if location != s.ExpectedLocation {
|
||||
return []string{}, fmt.Errorf(
|
||||
"bad location: %s (expected %s)",
|
||||
location,
|
||||
s.ExpectedLocation,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
panic("bad expectedAnswer")
|
||||
}
|
||||
|
||||
// return []string{}, nil
|
||||
return s.CheckKeyword(body, []string{})
|
||||
}
|
||||
Ссылка в новой задаче
Block a user