Restore: фолбэк pull по тегу, если образ по digest удалён из реестра
Общий pull падал целиком (minio/minio удалён с Docker Hub), create не проходил. Теперь при ошибке образы тянутся по одному, для недоступных по digest закрепление снимается, а при полном отказе в todo попадает подсказка. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
97c7051021
commit
7e29fb11eb
1 file changed
+47
-2
@@ -54,6 +54,7 @@ func (r *restorer) restoreCompose(c manifest.Category) error {
|
|||||||
|
|
||||||
if err := compose("pull", "--ignore-buildable", "--quiet"); err != nil {
|
if err := compose("pull", "--ignore-buildable", "--quiet"); err != nil {
|
||||||
r.warn("%s: pull: %v", c.Name, err)
|
r.warn("%s: pull: %v", c.Name, err)
|
||||||
|
r.pullFallback(c, compose)
|
||||||
}
|
}
|
||||||
if hasBuilt(info) {
|
if hasBuilt(info) {
|
||||||
if err := compose("build"); err != nil {
|
if err := compose("build"); err != nil {
|
||||||
@@ -94,6 +95,46 @@ func hasBuilt(info *manifest.Compose) bool {
|
|||||||
|
|
||||||
// writePinFile пишет compose.restore.yml с образами по digest. Пустая строка — закреплять нечего.
|
// writePinFile пишет compose.restore.yml с образами по digest. Пустая строка — закреплять нечего.
|
||||||
func (r *restorer) writePinFile(c manifest.Category) (string, error) {
|
func (r *restorer) writePinFile(c manifest.Category) (string, error) {
|
||||||
|
return r.writePinFileSkip(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// pullFallback вызывается, когда общий pull не удался (например, образ по digest
|
||||||
|
// удалён из реестра — так случилось с minio/minio на Docker Hub). Тянет сервисы
|
||||||
|
// по одному; для тех, что не нашлись по digest, снимает закрепление и пробует
|
||||||
|
// тег из исходного compose-файла.
|
||||||
|
func (r *restorer) pullFallback(c manifest.Category, compose func(...string) error) {
|
||||||
|
var failed []string
|
||||||
|
for svc, img := range c.Compose.Images {
|
||||||
|
if img.Built {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := compose("pull", "--quiet", svc); err != nil {
|
||||||
|
failed = append(failed, svc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(failed) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
slices.Sort(failed)
|
||||||
|
skip := map[string]bool{}
|
||||||
|
for _, svc := range failed {
|
||||||
|
skip[svc] = true
|
||||||
|
}
|
||||||
|
if _, err := r.writePinFileSkip(c, skip); err != nil {
|
||||||
|
r.warn("%s: не удалось переписать %s: %v", c.Name, pinFile, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, svc := range failed {
|
||||||
|
if err := compose("pull", "--quiet", svc); err != nil {
|
||||||
|
r.warn("%s: образ сервиса %s недоступен ни по digest, ни по тегу: %v", c.Name, svc, err)
|
||||||
|
r.todo = append(r.todo, fmt.Sprintf("%s: образ сервиса %s недоступен в реестре (возможно, удалён или переехал, напр. minio/minio → quay.io/minio/minio). Поправьте image в compose-файле и выполните `docker compose up -d`", c.Name, svc))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r.warn("%s: сервис %s: образ по digest недоступен, взят по тегу из compose-файла (версия может отличаться)", c.Name, svc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *restorer) writePinFileSkip(c manifest.Category, skip map[string]bool) (string, error) {
|
||||||
var services []string
|
var services []string
|
||||||
for name := range c.Compose.Images {
|
for name := range c.Compose.Images {
|
||||||
services = append(services, name)
|
services = append(services, name)
|
||||||
@@ -105,16 +146,20 @@ func (r *restorer) writePinFile(c manifest.Category) (string, error) {
|
|||||||
n := 0
|
n := 0
|
||||||
for _, svc := range services {
|
for _, svc := range services {
|
||||||
img := c.Compose.Images[svc]
|
img := c.Compose.Images[svc]
|
||||||
if img.Built || img.Digest == "" {
|
if img.Built || img.Digest == "" || skip[svc] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Fprintf(&b, " %q:\n image: %q\n", svc, img.Digest)
|
fmt.Fprintf(&b, " %q:\n image: %q\n", svc, img.Digest)
|
||||||
n++
|
n++
|
||||||
}
|
}
|
||||||
|
p := filepath.Join(c.Compose.Dir, pinFile)
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
|
if skip != nil {
|
||||||
|
// файл уже подключён через -f: оставляем валидный пустой
|
||||||
|
return p, os.WriteFile(p, []byte("services: {}\n"), 0o644)
|
||||||
|
}
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
p := filepath.Join(c.Compose.Dir, pinFile)
|
|
||||||
return p, os.WriteFile(p, []byte(b.String()), 0o644)
|
return p, os.WriteFile(p, []byte(b.String()), 0o644)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user