feat: allow job node selector

This commit is contained in:
Brad Stein 2026-02-06 04:08:23 -03:00
parent 1d02a3177d
commit eb6de2db73
3 changed files with 40 additions and 0 deletions

View File

@ -56,6 +56,7 @@ Environment variables:
- `SOTERIA_S3_ENDPOINT` (optional) Example: `s3.us-west-004.backblazeb2.com` - `SOTERIA_S3_ENDPOINT` (optional) Example: `s3.us-west-004.backblazeb2.com`
- `SOTERIA_S3_REGION` (optional) Example: `us-west-004` - `SOTERIA_S3_REGION` (optional) Example: `us-west-004`
- `SOTERIA_JOB_TTL_SECONDS` (default: 86400) - `SOTERIA_JOB_TTL_SECONDS` (default: 86400)
- `SOTERIA_JOB_NODE_SELECTOR` (optional) Comma-separated node selector, e.g. `kubernetes.io/arch=arm64,node-role.kubernetes.io/worker=true`
- `SOTERIA_JOB_SERVICE_ACCOUNT` (optional) ServiceAccount for backup Jobs - `SOTERIA_JOB_SERVICE_ACCOUNT` (optional) ServiceAccount for backup Jobs
- `SOTERIA_LISTEN_ADDR` (default: `:8080`) - `SOTERIA_LISTEN_ADDR` (default: `:8080`)

View File

@ -26,6 +26,7 @@ type Config struct {
S3Endpoint string S3Endpoint string
S3Region string S3Region string
JobTTLSeconds int32 JobTTLSeconds int32
JobNodeSelector map[string]string
WorkerServiceAccount string WorkerServiceAccount string
ListenAddr string ListenAddr string
} }
@ -56,6 +57,7 @@ func Load() (*Config, error) {
cfg.S3Region = getenv("SOTERIA_S3_REGION") cfg.S3Region = getenv("SOTERIA_S3_REGION")
cfg.WorkerServiceAccount = getenv("SOTERIA_JOB_SERVICE_ACCOUNT") cfg.WorkerServiceAccount = getenv("SOTERIA_JOB_SERVICE_ACCOUNT")
cfg.ListenAddr = getenvDefault("SOTERIA_LISTEN_ADDR", defaultListenAddr) cfg.ListenAddr = getenvDefault("SOTERIA_LISTEN_ADDR", defaultListenAddr)
cfg.JobNodeSelector = parseNodeSelector(getenv("SOTERIA_JOB_NODE_SELECTOR"))
if ttl, ok := getenvInt("SOTERIA_JOB_TTL_SECONDS"); ok { if ttl, ok := getenvInt("SOTERIA_JOB_TTL_SECONDS"); ok {
cfg.JobTTLSeconds = int32(ttl) cfg.JobTTLSeconds = int32(ttl)
@ -73,6 +75,9 @@ func Load() (*Config, error) {
if strings.Contains(cfg.ResticRepository, "..") { if strings.Contains(cfg.ResticRepository, "..") {
return nil, errors.New("SOTERIA_RESTIC_REPOSITORY contains invalid path segments") return nil, errors.New("SOTERIA_RESTIC_REPOSITORY contains invalid path segments")
} }
if cfg.JobNodeSelector == nil {
return nil, errors.New("SOTERIA_JOB_NODE_SELECTOR is invalid; expected key=value pairs")
}
return cfg, nil return cfg, nil
} }
@ -99,3 +104,31 @@ func getenvInt(key string) (int, bool) {
} }
return parsed, true return parsed, true
} }
func parseNodeSelector(raw string) map[string]string {
raw = strings.TrimSpace(raw)
if raw == "" {
return map[string]string{}
}
selector := map[string]string{}
parts := strings.Split(raw, ",")
for _, part := range parts {
part = strings.TrimSpace(part)
if part == "" {
continue
}
key, value, found := strings.Cut(part, "=")
if !found {
return nil
}
key = strings.TrimSpace(key)
value = strings.TrimSpace(value)
if key == "" || value == "" {
return nil
}
selector[key] = value
}
return selector
}

View File

@ -149,6 +149,9 @@ func buildBackupJob(cfg *config.Config, req api.BackupRequest, jobName, secretNa
}, },
} }
if len(cfg.JobNodeSelector) > 0 {
pod.NodeSelector = cfg.JobNodeSelector
}
if cfg.WorkerServiceAccount != "" { if cfg.WorkerServiceAccount != "" {
pod.ServiceAccountName = cfg.WorkerServiceAccount pod.ServiceAccountName = cfg.WorkerServiceAccount
} }
@ -209,6 +212,9 @@ func buildRestoreJob(cfg *config.Config, req api.RestoreTestRequest, jobName, se
}, },
} }
if len(cfg.JobNodeSelector) > 0 {
pod.NodeSelector = cfg.JobNodeSelector
}
if req.TargetPVC != "" { if req.TargetPVC != "" {
pod.Volumes[0] = corev1.Volume{ pod.Volumes[0] = corev1.Volume{
Name: "restore", Name: "restore",