satisfactory: dev and server fall back instead of aborting (7.0.1)
--set dev=null aborted the render at .Values.dev.debug and --set server=null at .Values.server.replicas, while the third block, game, has fallen back to the chart defaults since 7.0.0. Half-safe is the worse state of the two: whoever sees game=null work assumes server=null does too. Both blocks now run through satisfactory.defaultedDict like game, via two new helpers next to it. server.resources is deliberately NOT re-defaulted there - it already runs through satisfactory.effectiveResources, which carries those defaults and is null-safe on its own, and a second copy of limitFactor: 2 / 4Gi / 1 / 5Gi would be a third place for them to drift. server is read in four files, not one, and the fourth is NOTES.txt, which helm template never renders - a fix confined to the manifests would have looked green and still aborted on a real helm install. All four go through the helpers. The single erased key was the quieter half of the bug and is fixed with it: a nulled server.gamePort rendered "port:" and "nodePort:" empty into the Service and an empty containerPort into the StatefulSet, and a nulled server.storage a PVC asking for no size - manifests rejected by nothing until the API server saw them. server.storage was documented in values.schema.json as deliberately not null-safe; that reasoning does not survive the block-level case, because it made "server: null" render a sizeless PVC instead of falling back like everything else. The schema note is replaced rather than left lying. Rendered output for valid values is unchanged: helm template against the chart defaults and against a full override set is byte-identical to 7.0.0, and so is NOTES.txt. Hence a patch bump, appVersion untouched. Fixes #16
This commit is contained in:
1 parent
8074e0de59
commit
5ff6e401c7
9 files changed
+109
-34
No files matched your search
@@ -3,7 +3,7 @@ name: satisfactory
|
||||
description: A Helm chart to deploy a Satisfactory Gameserver on Kubernetes
|
||||
icon: https://raw.githubusercontent.com/wolveix/satisfactory-server/main/.github/logo.png
|
||||
type: application
|
||||
version: 7.0.0+upv1.9.10
|
||||
version: 7.0.1+upv1.9.10
|
||||
appVersion: "v1.9.10"
|
||||
maintainers:
|
||||
- name: jklein
|
||||
@@ -1,17 +1,19 @@
|
||||
{{- $replicas := include "satisfactory.replicas" (dict "scaleDown" .Values.scaleDown "replicas" .Values.server.replicas) -}}
|
||||
{{- $gamePort := int .Values.server.gamePort -}}
|
||||
{{- $msgPort := int .Values.server.messagingPort -}}
|
||||
{{- $server := fromYaml (include "satisfactory.server" .Values.server) -}}
|
||||
{{- $dev := fromYaml (include "satisfactory.dev" .Values.dev) -}}
|
||||
{{- $replicas := include "satisfactory.replicas" (dict "scaleDown" .Values.scaleDown "replicas" (include "satisfactory.formatNumber" $server.replicas)) -}}
|
||||
{{- $gamePort := int $server.gamePort -}}
|
||||
{{- $msgPort := int $server.messagingPort -}}
|
||||
{{- $svc := printf "%s-%s-service" .Release.Name .Chart.Name -}}
|
||||
{{- $sfs := printf "%s-%s-sfs" .Release.Name .Chart.Name -}}
|
||||
{{- $pod := printf "%s-%s-sfs-0" .Release.Name .Chart.Name -}}
|
||||
{{- $pvc := printf "%s-%s-vc" .Release.Name .Chart.Name -}}
|
||||
{{- $storage := .Values.server.storage | default "unset" -}}
|
||||
{{- $res := fromYaml (include "satisfactory.effectiveResources" .Values.server.resources) -}}
|
||||
{{- $storage := $server.storage | default "unset" -}}
|
||||
{{- $res := fromYaml (include "satisfactory.effectiveResources" $server.resources) -}}
|
||||
{{- $lim := $res.limits | default dict -}}
|
||||
{{- $req := $res.requests | default dict -}}
|
||||
{{- $eph := index $lim "ephemeral-storage" | default "the computed ephemeral-storage limit" -}}
|
||||
{{- $mem := index $lim "memory" | default "the computed memory limit" -}}
|
||||
{{- $factor := (.Values.server.resources | default dict).limitFactor | default 2 -}}
|
||||
{{- $factor := ($server.resources | default dict).limitFactor | default 2 -}}
|
||||
{{- $startup := fromYaml (include "satisfactory.startupProbe" .Values.startupProbe) -}}
|
||||
{{- $budget := "" -}}
|
||||
{{- if and (kindIs "float64" $startup.periodSeconds) (kindIs "float64" $startup.failureThreshold) -}}
|
||||
@@ -21,7 +23,7 @@
|
||||
{{- $seasonalEnv := include "satisfactory.disableSeasonalEvents" $game.enableSeasonalEvents -}}
|
||||
{{- $seasonalOff := eq $seasonalEnv "true" -}}
|
||||
{{- $beta := eq (lower (printf "%v" $game.experimental)) "true" -}}
|
||||
{{- $debug := eq (lower (printf "%v" .Values.dev.debug)) "true" -}}
|
||||
{{- $debug := eq (lower (printf "%v" $dev.debug)) "true" -}}
|
||||
{{- $outOfRange := or (lt $gamePort 30000) (gt $gamePort 32767) (lt $msgPort 30000) (gt $msgPort 32767) -}}
|
||||
{{- $skipRaw := "" -}}
|
||||
{{- range $entry := .Values.env -}}
|
||||
|
||||
@@ -308,6 +308,54 @@ DISABLESEASONALEVENTS at "true", the value this chart has always rendered.
|
||||
{{- include "satisfactory.defaultedDict" (dict "defaults" $defaults "given" . "path" "game") -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
The effective dev block (Gitea issue #16, the rest of #99).
|
||||
|
||||
"--set dev=null" — or a leftover "dev:" whose last sub-key was deleted — used
|
||||
to abort the render with a nil-pointer error at .Values.dev.debug, in the
|
||||
StatefulSet and in NOTES.txt. It now falls back to the default values.yaml
|
||||
documents, the same way the game block has since 7.0.0.
|
||||
|
||||
The defaults below MUST stay in sync with the dev block in values.yaml, which
|
||||
stays the documented, user-facing place for them; this copy is only the
|
||||
fallback for the case where an override has erased the block.
|
||||
*/}}
|
||||
{{- define "satisfactory.dev" -}}
|
||||
{{- $defaults := dict
|
||||
"debug" false -}}
|
||||
{{- include "satisfactory.defaultedDict" (dict "defaults" $defaults "given" . "path" "dev") -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
The effective server block (Gitea issue #16, the rest of #99).
|
||||
|
||||
"--set server=null" used to abort the render at .Values.server.replicas, and a
|
||||
single erased sub-key was worse than that: it rendered silently. A nulled
|
||||
server.gamePort produced a Service with "port:" and "nodePort:" empty and a
|
||||
StatefulSet with an empty containerPort — a manifest the API server rejects
|
||||
only at apply time — and a nulled server.storage produced a PVC asking for no
|
||||
size at all. Both now fall back to the documented defaults instead.
|
||||
|
||||
Note what is NOT defaulted here: server.resources. That block already runs
|
||||
through satisfactory.effectiveResources, which carries its own defaults and is
|
||||
null-safe on its own; repeating limitFactor/4Gi/1/5Gi here would create a
|
||||
third place for them to drift apart. Keys the defaults do not mention are
|
||||
passed through by satisfactory.defaultedDict unchanged, so an erased
|
||||
"server:" simply leaves resources unset and effectiveResources supplies them.
|
||||
|
||||
The defaults below MUST stay in sync with the server block in values.yaml,
|
||||
which stays the documented, user-facing place for them; this copy is only the
|
||||
fallback for the case where an override has erased the block.
|
||||
*/}}
|
||||
{{- define "satisfactory.server" -}}
|
||||
{{- $defaults := dict
|
||||
"replicas" 1
|
||||
"gamePort" 30777
|
||||
"messagingPort" 30888
|
||||
"storage" "20Gi" -}}
|
||||
{{- include "satisfactory.defaultedDict" (dict "defaults" $defaults "given" . "path" "server") -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Render the DISABLESEASONALEVENTS env value from game.enableSeasonalEvents
|
||||
(issue #215).
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{{- $server := fromYaml (include "satisfactory.server" .Values.server) -}}
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
@@ -7,5 +8,5 @@ spec:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.server.storage }}
|
||||
storage: {{ $server.storage }}
|
||||
storageClassName: longhorn
|
||||
@@ -1,3 +1,6 @@
|
||||
{{- $server := fromYaml (include "satisfactory.server" .Values.server) -}}
|
||||
{{- $gamePort := include "satisfactory.formatNumber" $server.gamePort -}}
|
||||
{{- $msgPort := include "satisfactory.formatNumber" $server.messagingPort -}}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
@@ -8,19 +11,19 @@ spec:
|
||||
type: NodePort
|
||||
ports:
|
||||
- name: "api"
|
||||
port: {{ .Values.server.gamePort }}
|
||||
port: {{ $gamePort }}
|
||||
protocol: TCP
|
||||
nodePort: {{ .Values.server.gamePort }}
|
||||
targetPort: {{ .Values.server.gamePort }}
|
||||
nodePort: {{ $gamePort }}
|
||||
targetPort: {{ $gamePort }}
|
||||
- name: "game"
|
||||
port: {{ .Values.server.gamePort }}
|
||||
port: {{ $gamePort }}
|
||||
protocol: UDP
|
||||
nodePort: {{ .Values.server.gamePort }}
|
||||
targetPort: {{ .Values.server.gamePort }}
|
||||
nodePort: {{ $gamePort }}
|
||||
targetPort: {{ $gamePort }}
|
||||
- name: "messaging"
|
||||
port: {{ .Values.server.messagingPort }}
|
||||
port: {{ $msgPort }}
|
||||
protocol: TCP
|
||||
nodePort: {{ .Values.server.messagingPort }}
|
||||
targetPort: {{ .Values.server.messagingPort }}
|
||||
nodePort: {{ $msgPort }}
|
||||
targetPort: {{ $msgPort }}
|
||||
selector:
|
||||
app: {{ .Release.Name }}-{{ .Chart.Name }}-sfs
|
||||
@@ -1,4 +1,6 @@
|
||||
{{- $game := fromYaml (include "satisfactory.game" .Values.game) -}}
|
||||
{{- $dev := fromYaml (include "satisfactory.dev" .Values.dev) -}}
|
||||
{{- $server := fromYaml (include "satisfactory.server" .Values.server) -}}
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
@@ -10,7 +12,7 @@ spec:
|
||||
matchLabels:
|
||||
app: {{ .Release.Name }}-{{ .Chart.Name }}-sfs
|
||||
serviceName: {{ .Release.Name }}-{{ .Chart.Name }}-service
|
||||
replicas: {{ include "satisfactory.replicas" (dict "scaleDown" .Values.scaleDown "replicas" .Values.server.replicas) }}
|
||||
replicas: {{ include "satisfactory.replicas" (dict "scaleDown" .Values.scaleDown "replicas" (include "satisfactory.formatNumber" $server.replicas)) }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
@@ -24,7 +26,7 @@ spec:
|
||||
image: "ghcr.io/wolveix/satisfactory-server:{{ .Chart.AppVersion }}"
|
||||
env:
|
||||
- name: DEBUG
|
||||
value: "{{ .Values.dev.debug }}"
|
||||
value: "{{ $dev.debug }}"
|
||||
- name: MAXPLAYERS
|
||||
value: "{{ include "satisfactory.formatNumber" $game.maxPlayers }}"
|
||||
# PUID/PGID are only used by the image's root entrypoint path;
|
||||
@@ -42,9 +44,9 @@ spec:
|
||||
- name: DISABLESEASONALEVENTS
|
||||
value: "{{ include "satisfactory.disableSeasonalEvents" $game.enableSeasonalEvents }}"
|
||||
- name: SERVERGAMEPORT
|
||||
value: "{{ .Values.server.gamePort }}"
|
||||
value: "{{ include "satisfactory.formatNumber" $server.gamePort }}"
|
||||
- name: SERVERMESSAGINGPORT
|
||||
value: "{{ .Values.server.messagingPort }}"
|
||||
value: "{{ include "satisfactory.formatNumber" $server.messagingPort }}"
|
||||
{{- range $value := .Values.env }}
|
||||
{{- if $value.value }}
|
||||
- name: {{ $value.name }}
|
||||
@@ -67,13 +69,13 @@ spec:
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: "api"
|
||||
containerPort: {{ .Values.server.gamePort }}
|
||||
containerPort: {{ include "satisfactory.formatNumber" $server.gamePort }}
|
||||
protocol: TCP
|
||||
- name: "game"
|
||||
containerPort: {{ .Values.server.gamePort }}
|
||||
containerPort: {{ include "satisfactory.formatNumber" $server.gamePort }}
|
||||
protocol: UDP
|
||||
- name: "messaging"
|
||||
containerPort: {{ .Values.server.messagingPort }}
|
||||
containerPort: {{ include "satisfactory.formatNumber" $server.messagingPort }}
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
{{- include "satisfactory.livenessProbe" .Values.livenessProbe | nindent 12 }}
|
||||
@@ -82,7 +84,7 @@ spec:
|
||||
startupProbe:
|
||||
{{- include "satisfactory.startupProbe" .Values.startupProbe | nindent 12 }}
|
||||
resources:
|
||||
{{- include "satisfactory.effectiveResources" .Values.server.resources | nindent 12 }}
|
||||
{{- include "satisfactory.effectiveResources" $server.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: satisfactory-volume
|
||||
mountPath: /config
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft-07/schema#",
|
||||
"title": "satisfactory values",
|
||||
"description": "Strict values schema (issue #68). additionalProperties is false on every chart-owned object level, so a key that the chart does not read is rejected at render time instead of being silently ignored. The only objects that stay open are the ones passed verbatim into the Kubernetes pod spec (probes, security contexts, global) - the chart does not interpret their contents, so it cannot judge which keys are meaningful. The hardening, probe and resources blocks additionally accept null, because an erased block falls back to the chart defaults (issue #99). Note that this chart keeps env, probes and securityContext at the TOP level rather than under a chart-named key.",
|
||||
"description": "Strict values schema (issue #68). additionalProperties is false on every chart-owned object level, so a key that the chart does not read is rejected at render time instead of being silently ignored. The only objects that stay open are the ones passed verbatim into the Kubernetes pod spec (probes, security contexts, global) - the chart does not interpret their contents, so it cannot judge which keys are meaningful. The hardening, probe and resources blocks additionally accept null, because an erased block falls back to the chart defaults (issue #99); since 7.0.1 that holds for every chart-owned block, dev, game and server included (Gitea issue #16), so no block is half-safe any more. Note that this chart keeps env, probes and securityContext at the TOP level rather than under a chart-named key.",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@@ -13,11 +13,12 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"dev": {
|
||||
"type": "object",
|
||||
"description": "May be null / empty: the chart then falls back to its documented dev defaults (Gitea issue #16, the rest of issue #99) instead of aborting the render with a nil-pointer error, which is what an erased block used to do.",
|
||||
"type": ["object", "null"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"debug": {
|
||||
"description": "Passed to the image as DEBUG.",
|
||||
"description": "Passed to the image as DEBUG. Null means the chart default (false).",
|
||||
"type": ["boolean", "string", "null"]
|
||||
}
|
||||
}
|
||||
@@ -41,25 +42,29 @@
|
||||
}
|
||||
},
|
||||
"server": {
|
||||
"type": "object",
|
||||
"description": "May be null / empty: the chart then falls back to its documented server defaults (Gitea issue #16, the rest of issue #99) instead of aborting the render with a nil-pointer error, which is what an erased block used to do. server.resources is the exception - it is not defaulted here but passed through to the resources fallback, which carries the defaults for it.",
|
||||
"type": ["object", "null"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"replicas": {
|
||||
"type": "integer",
|
||||
"description": "Null means the chart default (1). An explicit 0 is kept and scales the StatefulSet down.",
|
||||
"type": ["integer", "null"],
|
||||
"minimum": 0
|
||||
},
|
||||
"gamePort": {
|
||||
"type": "integer",
|
||||
"description": "Null means the chart default (30777). Up to 7.0.0 an erased port rendered an empty port number into the Service and the StatefulSet, which only the API server rejected (Gitea issue #16).",
|
||||
"type": ["integer", "null"],
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
},
|
||||
"messagingPort": {
|
||||
"type": "integer",
|
||||
"description": "Null means the chart default (30888). Same erased-port trap as gamePort above.",
|
||||
"type": ["integer", "null"],
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
},
|
||||
"storage": {
|
||||
"description": "Size of the data PVC. Not null-safe on purpose: an erased value yields an invalid PVC rather than a silently degraded workload.",
|
||||
"description": "Size of the data PVC. Null means the chart default (20Gi). Up to 7.0.0 this was deliberately not null-safe, on the reasoning that an erased value should yield an invalid PVC rather than a silently degraded workload; that reasoning did not survive Gitea issue #16, because it made \"server: null\" render a sizeless PVC instead of falling back like every other block. The chart default is not a degradation - it is the documented size.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"resources": {
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
# Services stay in place; scaleDown: false brings the workloads back up.
|
||||
scaleDown: false
|
||||
|
||||
# Erasing this block (dev: with no sub-keys, or --set dev=null) falls back to
|
||||
# the defaults below instead of aborting the render — same for game, server and
|
||||
# the hardening/probe/resources blocks (Gitea issue #16, issue #99).
|
||||
dev:
|
||||
debug: false
|
||||
|
||||
@@ -28,12 +31,19 @@ game:
|
||||
# again. Set enableSeasonalEvents: true to actually switch the events on.
|
||||
enableSeasonalEvents: false
|
||||
|
||||
# Erasing this block, or any single key in it, falls back to the defaults below
|
||||
# (Gitea issue #16). Before 7.0.1 "server: null" aborted the render and a single
|
||||
# erased key was worse: a nulled gamePort rendered an empty port number into the
|
||||
# Service and the StatefulSet, and a nulled storage a PVC without a size — both
|
||||
# rejected by the API server at apply time, not by the render.
|
||||
server:
|
||||
# Replica count for this workload; 0 is allowed and scales it down.
|
||||
# The chart-global scaleDown flag takes precedence.
|
||||
replicas: 1
|
||||
gamePort: 30777
|
||||
messagingPort: 30888
|
||||
# The size of the data PVC. An erased value falls back to this default; up to
|
||||
# 7.0.0 it rendered a PVC asking for no size at all.
|
||||
storage: 20Gi
|
||||
resources:
|
||||
# Limits are optional: memory and ephemeral-storage limits default to
|
||||
|
||||
Reference in new issue
Block a user