340 lines
9.8 KiB
Go
340 lines
9.8 KiB
Go
package config
|
|
|
|
import "strings"
|
|
|
|
// defaultServiceChecklist runs one orchestration or CLI step.
|
|
// Signature: defaultServiceChecklist() []ServiceChecklistCheck.
|
|
// Why: startup must verify real external behavior per service (not only generic
|
|
// ingress reachability) so false positives do not pass drills.
|
|
func defaultServiceChecklist() []ServiceChecklistCheck {
|
|
return []ServiceChecklistCheck{
|
|
{
|
|
Name: "gitea-api",
|
|
URL: "https://scm.bstein.dev/api/healthz",
|
|
AcceptedStatuses: []int{200},
|
|
BodyContains: "pass",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "grafana-api",
|
|
URL: "https://metrics.bstein.dev/api/health",
|
|
AcceptedStatuses: []int{200},
|
|
BodyContains: "\"database\":\"ok\"",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "keycloak-oidc",
|
|
URL: "https://sso.bstein.dev/realms/atlas/.well-known/openid-configuration",
|
|
AcceptedStatuses: []int{200},
|
|
BodyContains: "\"issuer\":\"https://sso.bstein.dev/realms/atlas\"",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "harbor-registry-api",
|
|
URL: "https://registry.bstein.dev/v2/",
|
|
AcceptedStatuses: []int{401},
|
|
BodyContains: "unauthorized",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "alerts-ui",
|
|
URL: "https://alerts.bstein.dev/",
|
|
AcceptedStatuses: []int{200},
|
|
BodyContains: "Alertmanager",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "auth-gateway-user-session",
|
|
URL: "https://auth.bstein.dev/",
|
|
AcceptedStatuses: []int{200},
|
|
RequireRobotAuth: true,
|
|
FollowRedirects: true,
|
|
BodyContains: "Authenticated",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "home-site",
|
|
URL: "https://bstein.dev/",
|
|
AcceptedStatuses: []int{200},
|
|
BodyContains: "Titan Lab",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "actual-budget-ui",
|
|
URL: "https://budget.bstein.dev/",
|
|
AcceptedStatuses: []int{200},
|
|
BodyContains: "<title>Actual",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "element-call-ui",
|
|
URL: "https://call.live.bstein.dev/",
|
|
AcceptedStatuses: []int{200},
|
|
BodyContains: "Element Call",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "flux-gitops-ui",
|
|
URL: "https://cd.bstein.dev/",
|
|
AcceptedStatuses: []int{200},
|
|
BodyContains: "Weave GitOps",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "chat-ai-health",
|
|
URL: "https://chat.ai.bstein.dev/",
|
|
AcceptedStatuses: []int{200},
|
|
BodyContains: "\"ok\": true",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "jenkins-auth-gate",
|
|
URL: "https://ci.bstein.dev/",
|
|
AcceptedStatuses: []int{403},
|
|
BodyContains: "commenceLogin",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "nextcloud-login-redirect",
|
|
URL: "https://cloud.bstein.dev/",
|
|
AcceptedStatuses: []int{302},
|
|
LocationContains: "/index.php/login",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "wger-redirect",
|
|
URL: "https://health.bstein.dev/",
|
|
AcceptedStatuses: []int{302},
|
|
LocationContains: "/en/",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "livekit-edge",
|
|
URL: "https://kit.live.bstein.dev/",
|
|
AcceptedStatuses: []int{404},
|
|
BodyContains: "404 page not found",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "element-web-ui",
|
|
URL: "https://live.bstein.dev/",
|
|
AcceptedStatuses: []int{200},
|
|
BodyContains: "<title>Element</title>",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "logging-ui-user-session",
|
|
URL: "https://logs.bstein.dev/",
|
|
AcceptedStatuses: []int{200},
|
|
RequireRobotAuth: true,
|
|
FollowRedirects: true,
|
|
FinalURLNotContains: "/protocol/openid-connect/auth",
|
|
BodyContains: "OpenSearch Dashboards",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "logging-api-user-session",
|
|
URL: "https://logs.bstein.dev/api/status",
|
|
AcceptedStatuses: []int{200},
|
|
RequireRobotAuth: true,
|
|
FollowRedirects: true,
|
|
BodyContains: "\"state\":\"green\"",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "longhorn-api-user-session",
|
|
URL: "https://longhorn.bstein.dev/v1",
|
|
AcceptedStatuses: []int{200},
|
|
RequireRobotAuth: true,
|
|
FollowRedirects: true,
|
|
FinalURLNotContains: "/protocol/openid-connect/auth",
|
|
BodyContains: "\"id\":\"v1\"",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "matrix-auth-ui",
|
|
URL: "https://matrix.live.bstein.dev/",
|
|
AcceptedStatuses: []int{200},
|
|
BodyContains: "matrix-authentication-service",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "monero-edge",
|
|
URL: "https://monero.bstein.dev/",
|
|
AcceptedStatuses: []int{404},
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "firefly-login-redirect",
|
|
URL: "https://money.bstein.dev/",
|
|
AcceptedStatuses: []int{302},
|
|
LocationContains: "/login",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "outline-ui",
|
|
URL: "https://notes.bstein.dev/",
|
|
AcceptedStatuses: []int{200},
|
|
BodyContains: "<title>Outline</title>",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "collabora-probe",
|
|
URL: "https://office.bstein.dev/",
|
|
AcceptedStatuses: []int{200},
|
|
BodyContains: "OK",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "pegasus-ui",
|
|
URL: "https://pegasus.bstein.dev/",
|
|
AcceptedStatuses: []int{200},
|
|
BodyContains: "<title>Pegasus</title>",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "harbor-ui",
|
|
URL: "https://registry.bstein.dev/",
|
|
AcceptedStatuses: []int{200},
|
|
BodyContains: "<title>Harbor</title>",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "vault-ui-redirect",
|
|
URL: "https://secret.bstein.dev/",
|
|
AcceptedStatuses: []int{307},
|
|
LocationContains: "/ui/",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "sentinel-user-session",
|
|
URL: "https://sentinel.bstein.dev/healthz",
|
|
AcceptedStatuses: []int{200},
|
|
RequireRobotAuth: true,
|
|
FollowRedirects: true,
|
|
FinalURLNotContains: "/protocol/openid-connect/auth",
|
|
BodyContains: "ok",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "keycloak-admin-user-session",
|
|
URL: "https://sso.bstein.dev/admin/",
|
|
AcceptedStatuses: []int{200},
|
|
RequireRobotAuth: true,
|
|
FollowRedirects: true,
|
|
FinalURLContains: "/admin/master/console/",
|
|
FinalURLNotContains: "/login-actions/authenticate",
|
|
BodyContains: "Keycloak Administration Console",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "jellyfin-edge",
|
|
URL: "https://stream.bstein.dev/",
|
|
AcceptedStatuses: []int{302},
|
|
LocationContains: "web/",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "planka-ui",
|
|
URL: "https://tasks.bstein.dev/",
|
|
AcceptedStatuses: []int{200},
|
|
BodyContains: "<title>PLANKA</title>",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
{
|
|
Name: "vaultwarden-ui",
|
|
URL: "https://vault.bstein.dev/",
|
|
AcceptedStatuses: []int{200},
|
|
BodyContains: "<title>Vaultwarden Web</title>",
|
|
TimeoutSeconds: 12,
|
|
},
|
|
}
|
|
}
|
|
|
|
// defaultCriticalServiceEndpoints runs one orchestration or CLI step.
|
|
// Signature: defaultCriticalServiceEndpoints() []string.
|
|
// Why: service edge checks are insufficient for protected stacks; endpoint
|
|
// presence verifies that backends are actually routable before startup success.
|
|
func defaultCriticalServiceEndpoints() []string {
|
|
return []string{
|
|
"monitoring/victoria-metrics-single-server",
|
|
"monitoring/grafana",
|
|
"monitoring/kube-state-metrics",
|
|
"logging/oauth2-proxy-logs",
|
|
"logging/opensearch-dashboards",
|
|
"logging/opensearch-master",
|
|
}
|
|
}
|
|
|
|
// mergeServiceChecklistDefaults runs one orchestration or CLI step.
|
|
// Signature: mergeServiceChecklistDefaults(existing, defaults []ServiceChecklistCheck) []ServiceChecklistCheck.
|
|
// Why: host configs can keep custom checks while still inheriting mandatory
|
|
// baseline checks introduced after incident learnings.
|
|
func mergeServiceChecklistDefaults(existing, defaults []ServiceChecklistCheck) []ServiceChecklistCheck {
|
|
if len(existing) == 0 {
|
|
out := make([]ServiceChecklistCheck, 0, len(defaults))
|
|
out = append(out, defaults...)
|
|
return out
|
|
}
|
|
|
|
defaultByName := map[string]struct{}{}
|
|
for _, check := range defaults {
|
|
name := strings.TrimSpace(check.Name)
|
|
if name == "" {
|
|
continue
|
|
}
|
|
defaultByName[name] = struct{}{}
|
|
}
|
|
|
|
out := make([]ServiceChecklistCheck, 0, len(defaults)+len(existing))
|
|
out = append(out, defaults...)
|
|
for _, check := range existing {
|
|
name := strings.TrimSpace(check.Name)
|
|
if name == "" {
|
|
continue
|
|
}
|
|
if _, exists := defaultByName[name]; exists {
|
|
continue
|
|
}
|
|
out = append(out, check)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// mergeStringDefaults runs one orchestration or CLI step.
|
|
// Signature: mergeStringDefaults(existing, defaults []string) []string.
|
|
// Why: keeps baseline startup guards applied while preserving site-specific
|
|
// additions already declared in host configs.
|
|
func mergeStringDefaults(existing, defaults []string) []string {
|
|
if len(existing) == 0 {
|
|
out := make([]string, 0, len(defaults))
|
|
out = append(out, defaults...)
|
|
return out
|
|
}
|
|
seen := map[string]struct{}{}
|
|
out := make([]string, 0, len(existing)+len(defaults))
|
|
for _, item := range existing {
|
|
key := strings.TrimSpace(item)
|
|
if key == "" {
|
|
continue
|
|
}
|
|
if _, ok := seen[key]; ok {
|
|
continue
|
|
}
|
|
seen[key] = struct{}{}
|
|
out = append(out, key)
|
|
}
|
|
for _, item := range defaults {
|
|
key := strings.TrimSpace(item)
|
|
if key == "" {
|
|
continue
|
|
}
|
|
if _, ok := seen[key]; ok {
|
|
continue
|
|
}
|
|
seen[key] = struct{}{}
|
|
out = append(out, key)
|
|
}
|
|
return out
|
|
}
|