fix(ci): preserve installer compatibility with older releases
This commit is contained in:
5 files changed
+49
-23
No files matched your search
@@ -9,10 +9,17 @@ import (
|
|||||||
|
|
||||||
func cmdBootstrapAssets(args []string, stdout, stderr io.Writer) int {
|
func cmdBootstrapAssets(args []string, stdout, stderr io.Writer) int {
|
||||||
if len(args) != 1 {
|
if len(args) != 1 {
|
||||||
fmt.Fprintln(stderr, "felis bootstrap-assets: usage: felis bootstrap-assets crd|game-stack")
|
fmt.Fprintln(stderr, "felis bootstrap-assets: usage: felis bootstrap-assets crd|game-stack|config-keys")
|
||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
switch args[0] {
|
switch args[0] {
|
||||||
|
case "config-keys":
|
||||||
|
// Optional keys the installer may emit; older binaries reject this verb.
|
||||||
|
_, err := fmt.Fprintln(stdout, "velocity.game_version")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(stderr, "felis bootstrap-assets: write: %v\n", err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
case "crd":
|
case "crd":
|
||||||
crd, err := felis.MinecraftServerCRD()
|
crd, err := felis.MinecraftServerCRD()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -32,7 +39,7 @@ func cmdBootstrapAssets(args []string, stdout, stderr io.Writer) int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
fmt.Fprintln(stderr, "felis bootstrap-assets: usage: felis bootstrap-assets crd|game-stack")
|
fmt.Fprintln(stderr, "felis bootstrap-assets: usage: felis bootstrap-assets crd|game-stack|config-keys")
|
||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -5,8 +5,27 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/BurntSushi/toml"
|
||||||
|
|
||||||
|
"felis.lolicon.best/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestBootstrapConfigKeys(t *testing.T) {
|
||||||
|
var out, errBuf bytes.Buffer
|
||||||
|
if code := run([]string{"bootstrap-assets", "config-keys"}, &out, &errBuf); code != 0 {
|
||||||
|
t.Fatalf("exit code = %d: %s", code, errBuf.String())
|
||||||
|
}
|
||||||
|
var cfg config.Config
|
||||||
|
meta, err := toml.Decode(strings.TrimSpace(out.String())+` = "26.3"`, &cfg)
|
||||||
|
if err != nil || len(meta.Undecoded()) != 0 {
|
||||||
|
t.Fatalf("advertised config key is unsupported: %v, undecoded: %v", err, meta.Undecoded())
|
||||||
|
}
|
||||||
|
if cfg.Velocity.GameVersion != "26.3" {
|
||||||
|
t.Fatalf("advertised key did not set the game version: %q", cfg.Velocity.GameVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestRunNoArgsPrintsUsage(t *testing.T) {
|
func TestRunNoArgsPrintsUsage(t *testing.T) {
|
||||||
var out, errBuf bytes.Buffer
|
var out, errBuf bytes.Buffer
|
||||||
if code := run(nil, &out, &errBuf); code != 2 {
|
if code := run(nil, &out, &errBuf); code != 2 {
|
||||||
|
|||||||
+8
-1
@@ -4707,6 +4707,13 @@ offsite_enabled() {
|
|||||||
# database password.
|
# database password.
|
||||||
write_felis_toml() {
|
write_felis_toml() {
|
||||||
local target="$1" db_addr="$2" deployment="${3:-}" deployment_line="" smtp_block auth_body auth_source_blocks registry_block archive_block offsite_section
|
local target="$1" db_addr="$2" deployment="${3:-}" deployment_line="" smtp_block auth_body auth_source_blocks registry_block archive_block offsite_section
|
||||||
|
local config_keys game_version_line=""
|
||||||
|
# main's installer also installs older releases, whose strict TOML parser rejects
|
||||||
|
# newer optional keys. Ask the installed binary rather than guessing from its stamp.
|
||||||
|
config_keys="$("$HOST_BIN" bootstrap-assets config-keys 2>/dev/null || true)"
|
||||||
|
if grep -Fxq 'velocity.game_version' <<<"$config_keys"; then
|
||||||
|
game_version_line="game_version = \"${MC_VERSION:-}\""
|
||||||
|
fi
|
||||||
if [ -n "$deployment" ]; then
|
if [ -n "$deployment" ]; then
|
||||||
# Starts with the newline that ends the url line, so the pod copy has no blank line there.
|
# Starts with the newline that ends the url line, so the pod copy has no blank line there.
|
||||||
deployment_line="
|
deployment_line="
|
||||||
@@ -4762,7 +4769,7 @@ login_image = "${FELIS_LIMBO_IMAGE}"
|
|||||||
lobby_image = "${FELIS_LOBBY_IMAGE}"
|
lobby_image = "${FELIS_LOBBY_IMAGE}"
|
||||||
# The public port players connect on; the panel shows it in server addresses.
|
# The public port players connect on; the panel shows it in server addresses.
|
||||||
game_port = ${FELIS_GAME_PORT}
|
game_port = ${FELIS_GAME_PORT}
|
||||||
game_version = "${MC_VERSION:-}"
|
${game_version_line}
|
||||||
|
|
||||||
[registry]
|
[registry]
|
||||||
url = "${REGISTRY_URL}"
|
url = "${REGISTRY_URL}"
|
||||||
|
|||||||
@@ -2042,11 +2042,16 @@ run_write() { # out-file [state-dir] [database-deployment]; under the installer'
|
|||||||
[ -z "${CAT_FAILS:-}" ] || cat() { head -c 40; return 1; }
|
[ -z "${CAT_FAILS:-}" ] || cat() { head -c 40; return 1; }
|
||||||
persisted_smtp_block() { :; }
|
persisted_smtp_block() { :; }
|
||||||
persisted_auth_source_blocks() { :; }
|
persisted_auth_source_blocks() { :; }
|
||||||
|
felis() {
|
||||||
|
[ "$*" = "bootstrap-assets config-keys" ] || return 2
|
||||||
|
[ "${OLD_CONFIG:-0}" != 1 ] || return 2
|
||||||
|
printf "%s\n" velocity.game_version
|
||||||
|
}
|
||||||
. "$FNFILE"
|
. "$FNFILE"
|
||||||
FELIS_ROOT_DOMAIN=r.example.com DB_USER=u DB_PASSWORD=p DB_NAME=d MINECRAFT_NS=minecraft \
|
FELIS_ROOT_DOMAIN=r.example.com DB_USER=u DB_PASSWORD=p DB_NAME=d MINECRAFT_NS=minecraft \
|
||||||
FELIS_EGRESS_MODE=nodeport FELIS_LIMBO_IMAGE=li FELIS_LOBBY_IMAGE=lo FELIS_GAME_PORT=25570 MC_VERSION=26.3 \
|
FELIS_EGRESS_MODE=nodeport FELIS_LIMBO_IMAGE=li FELIS_LOBBY_IMAGE=lo FELIS_GAME_PORT=25570 MC_VERSION=26.3 \
|
||||||
REGISTRY_URL=registry.felis.svc:5000 BUILD_NS=felis-build FELIS_ARCHIVE_LOCAL_PATH=/a \
|
REGISTRY_URL=registry.felis.svc:5000 BUILD_NS=felis-build FELIS_ARCHIVE_LOCAL_PATH=/a \
|
||||||
FELIS_OFFSITE_BUCKET= write_felis_toml "$OUT_TOML" 127.0.0.1:15432 "$DEPLOY"'
|
HOST_BIN=felis FELIS_OFFSITE_BUCKET= write_felis_toml "$OUT_TOML" 127.0.0.1:15432 "$DEPLOY"'
|
||||||
}
|
}
|
||||||
|
|
||||||
run_write "$rdir/out.toml"
|
run_write "$rdir/out.toml"
|
||||||
@@ -2086,6 +2091,13 @@ expect "a re-run carries the scheduled backup retention" 'scheduled_retention =
|
|||||||
expect "the archive mount stays installer-owned" 'local_path = "/a"' "$out"
|
expect "the archive mount stays installer-owned" 'local_path = "/a"' "$out"
|
||||||
expect "the panel learns the public game port" 'game_port = 25570' "$out"
|
expect "the panel learns the public game port" 'game_port = 25570' "$out"
|
||||||
expect "the panel learns the built login protocol" 'game_version = "26.3"' "$out"
|
expect "the panel learns the built login protocol" 'game_version = "26.3"' "$out"
|
||||||
|
(OLD_CONFIG=1 run_write "$rdir/release.toml")
|
||||||
|
release_config="$(cat "$rdir/release.toml")"
|
||||||
|
case "$release_config" in
|
||||||
|
*game_version*) echo "FAIL an older binary must not receive velocity.game_version"; fails=$((fails + 1)) ;;
|
||||||
|
*) echo "PASS an older binary receives no unsupported game-version key" ;;
|
||||||
|
esac
|
||||||
|
expect "an older binary still receives the public game port" 'game_port = 25570' "$release_config"
|
||||||
expect "a re-run keeps the off-site bucket, set apart from the next section" '[offsite]
|
expect "a re-run keeps the off-site bucket, set apart from the next section" '[offsite]
|
||||||
endpoint = "https://objects.example"
|
endpoint = "https://objects.example"
|
||||||
bucket = "felis-offsite"
|
bucket = "felis-offsite"
|
||||||
|
|||||||
@@ -157,25 +157,6 @@ func (k *K8sRunner) awaitPod(ctx context.Context, p JobParams) (*corev1.Pod, err
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// podLog reads a finished Pod's log. Follow is off — the Pod has already
|
|
||||||
// terminated, so the log is complete and a follow would merely block until the
|
|
||||||
// stream closed.
|
|
||||||
func (k *K8sRunner) podLog(ctx context.Context, namespace, pod string) (string, error) {
|
|
||||||
stream, err := k.cs.CoreV1().Pods(namespace).GetLogs(pod, &corev1.PodLogOptions{
|
|
||||||
Container: containerName,
|
|
||||||
}).Stream(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("fileedit: read file job log: %w", err)
|
|
||||||
}
|
|
||||||
defer stream.Close()
|
|
||||||
|
|
||||||
b, err := io.ReadAll(io.LimitReader(stream, maxLogBytes))
|
|
||||||
if err != nil && !errors.Is(err, io.EOF) {
|
|
||||||
return "", fmt.Errorf("fileedit: read file job log: %w", err)
|
|
||||||
}
|
|
||||||
return string(b), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// extractResult finds the marked payload in a Pod log. It scans for the LAST line
|
// extractResult finds the marked payload in a Pod log. It scans for the LAST line
|
||||||
// carrying ResultPrefix because pods/log returns stdout and stderr MERGED: a Go
|
// carrying ResultPrefix because pods/log returns stdout and stderr MERGED: a Go
|
||||||
// runtime warning or a libc message can appear anywhere in the stream, so the
|
// runtime warning or a libc message can appear anywhere in the stream, so the
|
||||||
|
|||||||
Reference in new issue
Block a user