diff --git a/pkg/templates/partials/registry_secret.sh.tmpl b/pkg/templates/partials/registry_secret.sh.tmpl index 2b1a43a..a368027 100644 --- a/pkg/templates/partials/registry_secret.sh.tmpl +++ b/pkg/templates/partials/registry_secret.sh.tmpl @@ -1,13 +1,20 @@ {{define "registry_secret.sh.tmpl"}}# The registry pull secret for teknoir-registry-secret (tnctl bootstrap --docker-secret). Without one, -# a re-run keeps what the device already has, and a first run gets an empty but valid config: an empty -# .dockerconfigjson is invalid JSON and makes k3s reject the whole Teknoir manifest. +# a re-run keeps the credential the device already has: teknoir-registry-secret, or +# artifact-registry-secret from older installers (the default ServiceAccounts now point at +# teknoir-registry-secret only), skipping an empty {"auths":{}}. A first run gets an empty but valid +# config: an empty .dockerconfigjson is invalid JSON and makes k3s reject the whole Teknoir manifest. +_TN_EMPTY_DOCKER_SECRET=eyJhdXRocyI6e319 # {"auths":{}} _TN_DOCKER_SECRET="{{.DockerSecret}}" if [ -z "${_TN_DOCKER_SECRET}" ]; then - _TN_DOCKER_SECRET=$($SUDO k3s kubectl -n default get secret teknoir-registry-secret -o jsonpath='{.data.\.dockerconfigjson}' 2>/dev/null || true) - if [ -n "${_TN_DOCKER_SECRET}" ]; then - info "Keeping the registry pull secret the device already has" - else - _TN_DOCKER_SECRET=eyJhdXRocyI6e319 # {"auths":{}} - fi + for _tn_s in teknoir-registry-secret artifact-registry-secret; do + _TN_DOCKER_SECRET=$($SUDO k3s kubectl -n default get secret "${_tn_s}" -o jsonpath='{.data.\.dockerconfigjson}' 2>/dev/null || true) + if [ -n "${_TN_DOCKER_SECRET}" ] && [ "${_TN_DOCKER_SECRET}" != "${_TN_EMPTY_DOCKER_SECRET}" ]; then + info "Keeping the registry pull secret the device already has (${_tn_s})" + break + fi + _TN_DOCKER_SECRET= + done + [ -n "${_TN_DOCKER_SECRET}" ] || _TN_DOCKER_SECRET=${_TN_EMPTY_DOCKER_SECRET} + unset _tn_s fi {{end}} diff --git a/pkg/templates/registrysecret_test.go b/pkg/templates/registrysecret_test.go index 54aae6b..5e3516b 100644 --- a/pkg/templates/registrysecret_test.go +++ b/pkg/templates/registrysecret_test.go @@ -20,11 +20,16 @@ func registrySecretBlock(t *testing.T, ds string) string { return b.String() } -// runRegistrySecret runs the block with a fake k3s that prints existing (or fails when empty). -func runRegistrySecret(t *testing.T, ds, existing string) string { +// runRegistrySecret runs the block with a fake k3s that prints the .dockerconfigjson of the +// named secret from secrets (and fails for a secret that is not there). +func runRegistrySecret(t *testing.T, ds string, secrets map[string]string) string { t.Helper() dir := t.TempDir() - fake := "#!/bin/sh\n[ -n \"" + existing + "\" ] || exit 1\nprintf '%s' '" + existing + "'\n" + fake := "#!/bin/sh\ncase \"$6\" in\n" + for name, v := range secrets { + fake += name + ") printf '%s' '" + v + "' ;;\n" + } + fake += "*) exit 1 ;;\nesac\n" if err := os.WriteFile(filepath.Join(dir, "k3s"), []byte(fake), 0o755); err != nil { t.Fatal(err) } @@ -39,13 +44,20 @@ func runRegistrySecret(t *testing.T, ds, existing string) string { } func TestRegistrySecret(t *testing.T) { - for _, tt := range []struct{ name, ds, existing, want string }{ - {"given", "Z2l2ZW4=", "ZXhpc3Rpbmc=", "SECRET=Z2l2ZW4=\n"}, - {"re-run keeps the device's", "", "ZXhpc3Rpbmc=", "SECRET=ZXhpc3Rpbmc=\n"}, - {"first run gets a valid empty config", "", "", "SECRET=eyJhdXRocyI6e319\n"}, + const empty = "eyJhdXRocyI6e319" + for _, tt := range []struct { + name, ds string + secrets map[string]string + want string + }{ + {"given", "Z2l2ZW4=", map[string]string{"teknoir-registry-secret": "ZXhpc3Rpbmc="}, "SECRET=Z2l2ZW4=\n"}, + {"re-run keeps the device's", "", map[string]string{"teknoir-registry-secret": "ZXhpc3Rpbmc="}, "SECRET=ZXhpc3Rpbmc=\n"}, + {"re-run takes the legacy secret", "", map[string]string{"artifact-registry-secret": "bGVnYWN5"}, "SECRET=bGVnYWN5\n"}, + {"an empty config does not hide the legacy secret", "", map[string]string{"teknoir-registry-secret": empty, "artifact-registry-secret": "bGVnYWN5"}, "SECRET=bGVnYWN5\n"}, + {"first run gets a valid empty config", "", nil, "SECRET=" + empty + "\n"}, } { t.Run(tt.name, func(t *testing.T) { - if out := runRegistrySecret(t, tt.ds, tt.existing); !strings.Contains(out, tt.want) { + if out := runRegistrySecret(t, tt.ds, tt.secrets); !strings.Contains(out, tt.want) { t.Fatalf("want %q in:\n%s", tt.want, out) } }) diff --git a/pkg/templates/testdata/docker_server.golden.sh b/pkg/templates/testdata/docker_server.golden.sh index 1b89a6a..f0c66e5 100644 --- a/pkg/templates/testdata/docker_server.golden.sh +++ b/pkg/templates/testdata/docker_server.golden.sh @@ -125,16 +125,23 @@ node-name: ${_DEVICE_ID} EOL # The registry pull secret for teknoir-registry-secret (tnctl bootstrap --docker-secret). Without one, -# a re-run keeps what the device already has, and a first run gets an empty but valid config: an empty -# .dockerconfigjson is invalid JSON and makes k3s reject the whole Teknoir manifest. +# a re-run keeps the credential the device already has: teknoir-registry-secret, or +# artifact-registry-secret from older installers (the default ServiceAccounts now point at +# teknoir-registry-secret only), skipping an empty {"auths":{}}. A first run gets an empty but valid +# config: an empty .dockerconfigjson is invalid JSON and makes k3s reject the whole Teknoir manifest. +_TN_EMPTY_DOCKER_SECRET=eyJhdXRocyI6e319 # {"auths":{}} _TN_DOCKER_SECRET="TEST-ONLY-docker-secret" if [ -z "${_TN_DOCKER_SECRET}" ]; then - _TN_DOCKER_SECRET=$($SUDO k3s kubectl -n default get secret teknoir-registry-secret -o jsonpath='{.data.\.dockerconfigjson}' 2>/dev/null || true) - if [ -n "${_TN_DOCKER_SECRET}" ]; then - info "Keeping the registry pull secret the device already has" - else - _TN_DOCKER_SECRET=eyJhdXRocyI6e319 # {"auths":{}} - fi + for _tn_s in teknoir-registry-secret artifact-registry-secret; do + _TN_DOCKER_SECRET=$($SUDO k3s kubectl -n default get secret "${_tn_s}" -o jsonpath='{.data.\.dockerconfigjson}' 2>/dev/null || true) + if [ -n "${_TN_DOCKER_SECRET}" ] && [ "${_TN_DOCKER_SECRET}" != "${_TN_EMPTY_DOCKER_SECRET}" ]; then + info "Keeping the registry pull secret the device already has (${_tn_s})" + break + fi + _TN_DOCKER_SECRET= + done + [ -n "${_TN_DOCKER_SECRET}" ] || _TN_DOCKER_SECRET=${_TN_EMPTY_DOCKER_SECRET} + unset _tn_s fi info "Install Teknoir Manifests" $SUDO mkdir -p /var/lib/rancher/k3s/server/manifests diff --git a/pkg/templates/testdata/server.golden.sh b/pkg/templates/testdata/server.golden.sh index ea485d5..0749b67 100644 --- a/pkg/templates/testdata/server.golden.sh +++ b/pkg/templates/testdata/server.golden.sh @@ -2033,16 +2033,23 @@ tn_inst_finish tn_inst_publish_release # The registry pull secret for teknoir-registry-secret (tnctl bootstrap --docker-secret). Without one, -# a re-run keeps what the device already has, and a first run gets an empty but valid config: an empty -# .dockerconfigjson is invalid JSON and makes k3s reject the whole Teknoir manifest. +# a re-run keeps the credential the device already has: teknoir-registry-secret, or +# artifact-registry-secret from older installers (the default ServiceAccounts now point at +# teknoir-registry-secret only), skipping an empty {"auths":{}}. A first run gets an empty but valid +# config: an empty .dockerconfigjson is invalid JSON and makes k3s reject the whole Teknoir manifest. +_TN_EMPTY_DOCKER_SECRET=eyJhdXRocyI6e319 # {"auths":{}} _TN_DOCKER_SECRET="TEST-ONLY-docker-secret" if [ -z "${_TN_DOCKER_SECRET}" ]; then - _TN_DOCKER_SECRET=$($SUDO k3s kubectl -n default get secret teknoir-registry-secret -o jsonpath='{.data.\.dockerconfigjson}' 2>/dev/null || true) - if [ -n "${_TN_DOCKER_SECRET}" ]; then - info "Keeping the registry pull secret the device already has" - else - _TN_DOCKER_SECRET=eyJhdXRocyI6e319 # {"auths":{}} - fi + for _tn_s in teknoir-registry-secret artifact-registry-secret; do + _TN_DOCKER_SECRET=$($SUDO k3s kubectl -n default get secret "${_tn_s}" -o jsonpath='{.data.\.dockerconfigjson}' 2>/dev/null || true) + if [ -n "${_TN_DOCKER_SECRET}" ] && [ "${_TN_DOCKER_SECRET}" != "${_TN_EMPTY_DOCKER_SECRET}" ]; then + info "Keeping the registry pull secret the device already has (${_tn_s})" + break + fi + _TN_DOCKER_SECRET= + done + [ -n "${_TN_DOCKER_SECRET}" ] || _TN_DOCKER_SECRET=${_TN_EMPTY_DOCKER_SECRET} + unset _tn_s fi info "Install Teknoir Manifests" $SUDO mkdir -p ${DATA_DIR}/server/manifests