Обновления из файла для закрытого контура: пакет с портала → проверка подписи → ядро, потом модули
- release: пакет обновления (ExtractBundle/ReadStagedManifest/WriteBundle), Artifact.MinCore, план блокирует модуль, которому нужно ядро новее, чем будет после установки - bj-release: модули получают min_core = версия релиза - настройки → Обновления: «Обновить из файла» (zip до 2 ГБ), фон как у сетевого обновления, причина блокировки в таблице компонентов Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q4YVo4UMopqT5DzicqpPjL
This commit is contained in:
@@ -78,6 +78,7 @@ func registerSetup(mux *http.ServeMux, a *admin, rc *RuntimeConfig, svc *Service
|
||||
mux.HandleFunc("/admin/setup/update", h.saveUpdate)
|
||||
mux.HandleFunc("/admin/setup/update/check", h.checkUpdate)
|
||||
mux.HandleFunc("/admin/setup/update/apply", h.applyUpdate)
|
||||
mux.HandleFunc("/admin/setup/update/upload", h.uploadUpdate)
|
||||
mux.HandleFunc("/admin/setup/license", h.saveLicense)
|
||||
mux.HandleFunc("/admin/setup/license/activate", h.licenseActivate)
|
||||
mux.HandleFunc("/admin/setup/license/renew", h.licenseRenewNow)
|
||||
@@ -1287,6 +1288,53 @@ func (h *setupHandlers) applyUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
setupFlash(w, r, "Обновление "+what+" запущено: файлы скачиваются и проверяются, затем перезапускаются службы. Итог — в строке «Последняя проверка» через минуту; при обновлении ядра страница временно не отвечает.")
|
||||
}
|
||||
|
||||
// uploadUpdate — POST /admin/setup/update/upload: пакет обновления файлом (закрытый контур).
|
||||
// Файл сохраняется в каталог подготовки, дальше — в фоне, как и обновление по сети.
|
||||
func (h *setupHandlers) uploadUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "method", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
r.Body = http.MaxBytesReader(w, r.Body, 2<<30)
|
||||
f, hdr, err := r.FormFile("bundle")
|
||||
if err != nil {
|
||||
setupFlash(w, r, "Обновление из файла: файл не получен ("+err.Error()+")")
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
if err := os.MkdirAll(updateStagingDir, 0o750); err != nil {
|
||||
setupFlash(w, r, "Обновление из файла: каталог подготовки: "+err.Error())
|
||||
return
|
||||
}
|
||||
dst := filepath.Join(updateStagingDir, fmt.Sprintf("upload-%d.zip", time.Now().UnixNano()))
|
||||
out, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o640)
|
||||
if err != nil {
|
||||
setupFlash(w, r, "Обновление из файла: "+err.Error())
|
||||
return
|
||||
}
|
||||
n, err := io.Copy(out, f)
|
||||
out.Close()
|
||||
if err != nil {
|
||||
_ = os.Remove(dst)
|
||||
setupFlash(w, r, "Обновление из файла: не удалось сохранить: "+err.Error())
|
||||
return
|
||||
}
|
||||
rc := h.rc
|
||||
go func() {
|
||||
msg, err := NewUpdater(rc).ApplyBundle(context.Background(), dst)
|
||||
cfg := rc.Snapshot().Update
|
||||
if err != nil {
|
||||
msg = "Обновление из файла не применено: " + err.Error()
|
||||
} else {
|
||||
msg = "Обновление: " + msg
|
||||
}
|
||||
log.Printf("lk-gateway: %s", msg)
|
||||
cfg.LastResult, cfg.LastCheck = msg, time.Now().UTC()
|
||||
_ = rc.SaveUpdateSettings(cfg)
|
||||
}()
|
||||
setupFlash(w, r, fmt.Sprintf("Файл %s (%d МБ) принят: проверяется подпись, затем ставятся компоненты новее текущих — ядро, потом модули. Итог — в строке «Последняя проверка» через минуту; при обновлении ядра страница временно не отвечает.", hdr.Filename, n>>20))
|
||||
}
|
||||
|
||||
// runTestClaim делает CreateClaim + ждёт финального состояния через GetClaim.
|
||||
func (h *setupHandlers) runTestClaim() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
|
||||
Reference in New Issue
Block a user