Обновление: модули вне лицензии пропускаются с пояснением «не входит в лицензию — свяжитесь с ZETIT», а не срывают обновление
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
This commit is contained in:
@@ -97,6 +97,7 @@ func (u *Updater) CheckForUpdate(ctx context.Context) (UpdateStatus, error) {
|
|||||||
st.Available, st.Notes = m.Version, m.Notes
|
st.Available, st.Notes = m.Version, m.Notes
|
||||||
st.Components = release.Plan("", m, release.LoadInstalled(release.InstalledFile), BuildVersion)
|
st.Components = release.Plan("", m, release.LoadInstalled(release.InstalledFile), BuildVersion)
|
||||||
release.MarkSplitModules(st.Components, u.allowed)
|
release.MarkSplitModules(st.Components, u.allowed)
|
||||||
|
off := markUnlicensed(st.Components, u.allowed)
|
||||||
var upd []string
|
var upd []string
|
||||||
avail := map[string]string{}
|
avail := map[string]string{}
|
||||||
for _, c := range st.Components {
|
for _, c := range st.Components {
|
||||||
@@ -115,10 +116,39 @@ func (u *Updater) CheckForUpdate(ctx context.Context) (UpdateStatus, error) {
|
|||||||
} else {
|
} else {
|
||||||
st.Message = "все установленные компоненты актуальны (релиз " + m.Version + ")"
|
st.Message = "все установленные компоненты актуальны (релиз " + m.Version + ")"
|
||||||
}
|
}
|
||||||
|
st.Message += unlicensedNote(off)
|
||||||
u.saveCheckResult(st, avail)
|
u.saveCheckResult(st, avail)
|
||||||
return st, nil
|
return st, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// markUnlicensed — модули, установленные на сервере, но снятые с лицензии: не обновляются (сервер
|
||||||
|
// обновлений их файлы не отдаёт), в списке — с пояснением. Возвращает названия таких модулей.
|
||||||
|
func markUnlicensed(states []release.ComponentState, allowed func(string) bool) []string {
|
||||||
|
var off []string
|
||||||
|
for i := range states {
|
||||||
|
c := &states[i]
|
||||||
|
if c.Core || c.Feature == "" || c.Feature == "updates" || allowed(c.Feature) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
c.Update, c.New = false, false
|
||||||
|
if c.Present {
|
||||||
|
c.Blocked = "не входит в лицензию — модуль отключён и не обновляется; чтобы подключить, свяжитесь с ZETIT"
|
||||||
|
off = append(off, "«"+c.Title+"»")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return off
|
||||||
|
}
|
||||||
|
|
||||||
|
func unlicensedNote(off []string) string {
|
||||||
|
if len(off) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if len(off) == 1 {
|
||||||
|
return "; модуль " + off[0] + " не входит в лицензию — отключён и не обновлялся; чтобы подключить, свяжитесь с ZETIT"
|
||||||
|
}
|
||||||
|
return "; модули " + strings.Join(off, ", ") + " не входят в лицензию — отключены и не обновлялись; чтобы подключить, свяжитесь с ZETIT"
|
||||||
|
}
|
||||||
|
|
||||||
// updateChannel — канал обновлений установки (пусто = stable).
|
// updateChannel — канал обновлений установки (пусто = stable).
|
||||||
func updateChannel(s UpdateSettings) string {
|
func updateChannel(s UpdateSettings) string {
|
||||||
if c := strings.TrimSpace(s.Channel); c != "" {
|
if c := strings.TrimSpace(s.Channel); c != "" {
|
||||||
@@ -174,6 +204,7 @@ func (u *Updater) applyUpdate(ctx context.Context, names []string) (string, erro
|
|||||||
}
|
}
|
||||||
plan := release.Plan("", m, release.LoadInstalled(release.InstalledFile), BuildVersion)
|
plan := release.Plan("", m, release.LoadInstalled(release.InstalledFile), BuildVersion)
|
||||||
release.MarkSplitModules(plan, u.allowed)
|
release.MarkSplitModules(plan, u.allowed)
|
||||||
|
off := markUnlicensed(plan, u.allowed)
|
||||||
want := map[string]bool{}
|
want := map[string]bool{}
|
||||||
for _, n := range names {
|
for _, n := range names {
|
||||||
want[n] = true
|
want[n] = true
|
||||||
@@ -184,11 +215,16 @@ func (u *Updater) applyUpdate(ctx context.Context, names []string) (string, erro
|
|||||||
case len(want) > 0 && !want[c.Name]:
|
case len(want) > 0 && !want[c.Name]:
|
||||||
case c.Update:
|
case c.Update:
|
||||||
selected = append(selected, c)
|
selected = append(selected, c)
|
||||||
|
case want[c.Name] && c.Blocked != "":
|
||||||
|
return "", fmt.Errorf("%s: %s", c.Title, c.Blocked)
|
||||||
case want[c.Name]:
|
case want[c.Name]:
|
||||||
return "", fmt.Errorf("%s: обновление не требуется (установлена %s, в релизе %s)", c.Title, pickVersion(c.Installed), pickVersion(c.Available))
|
return "", fmt.Errorf("%s: обновление не требуется (установлена %s, в релизе %s)", c.Title, pickVersion(c.Installed), pickVersion(c.Available))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(selected) == 0 {
|
if len(selected) == 0 {
|
||||||
|
if len(off) > 0 {
|
||||||
|
return "обновлять нечего: компоненты лицензии актуальны (релиз " + m.Version + ")" + unlicensedNote(off), nil
|
||||||
|
}
|
||||||
return "", fmt.Errorf("нечего обновлять: все установленные компоненты актуальны (релиз %s)", m.Version)
|
return "", fmt.Errorf("нечего обновлять: все установленные компоненты актуальны (релиз %s)", m.Version)
|
||||||
}
|
}
|
||||||
// Прежний root-установщик не умеет впервые ставить выделенные из ядра модули: пока он сам не
|
// Прежний root-установщик не умеет впервые ставить выделенные из ядра модули: пока он сам не
|
||||||
@@ -240,6 +276,7 @@ func (u *Updater) applyUpdate(ctx context.Context, names []string) (string, erro
|
|||||||
progressTarget(c.Available)
|
progressTarget(c.Available)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
progressNote(strings.TrimPrefix(unlicensedNote(off), "; "))
|
||||||
progressStage(2, "Скачивание файлов")
|
progressStage(2, "Скачивание файлов")
|
||||||
stopWatch := progressWatchDir(staging, total)
|
stopWatch := progressWatchDir(staging, total)
|
||||||
for _, c := range selected {
|
for _, c := range selected {
|
||||||
@@ -282,6 +319,7 @@ func (u *Updater) applyUpdate(ctx context.Context, names []string) (string, erro
|
|||||||
if len(deferred) > 0 {
|
if len(deferred) > 0 {
|
||||||
msg += "; модули " + strings.Join(deferred, ", ") + " будут установлены после перезапуска bj-server новым установщиком"
|
msg += "; модули " + strings.Join(deferred, ", ") + " будут установлены после перезапуска bj-server новым установщиком"
|
||||||
}
|
}
|
||||||
|
msg += unlicensedNote(off)
|
||||||
return msg, nil
|
return msg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,6 +393,7 @@ func updateComponentRows(rc *RuntimeConfig) ([]release.ComponentState, bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
release.MarkSplitModules(out, func(f string) bool { return moduleAllowed(rc, f) })
|
release.MarkSplitModules(out, func(f string) bool { return moduleAllowed(rc, f) })
|
||||||
|
markUnlicensed(out, func(f string) bool { return moduleAllowed(rc, f) })
|
||||||
// Последняя проверка не удалась — предлагать установку по старым данным нельзя:
|
// Последняя проверка не удалась — предлагать установку по старым данным нельзя:
|
||||||
// кнопка ушла бы в тот же отказ. Показываем причину и просим проверить заново.
|
// кнопка ушла бы в тот же отказ. Показываем причину и просим проверить заново.
|
||||||
if updateResultFailed(set.LastResult) {
|
if updateResultFailed(set.LastResult) {
|
||||||
@@ -475,6 +514,7 @@ func (u *Updater) applyBundle(ctx context.Context, zipPath string) (string, erro
|
|||||||
}
|
}
|
||||||
plan := release.Plan("", m, release.LoadInstalled(release.InstalledFile), BuildVersion)
|
plan := release.Plan("", m, release.LoadInstalled(release.InstalledFile), BuildVersion)
|
||||||
release.MarkSplitModules(plan, u.allowed)
|
release.MarkSplitModules(plan, u.allowed)
|
||||||
|
markUnlicensed(plan, u.allowed)
|
||||||
var req struct {
|
var req struct {
|
||||||
Names []string `json:"names"`
|
Names []string `json:"names"`
|
||||||
New []string `json:"new,omitempty"`
|
New []string `json:"new,omitempty"`
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ type updateProgressState struct {
|
|||||||
Total int64 `json:"total"`
|
Total int64 `json:"total"`
|
||||||
Target string `json:"target,omitempty"` // версия ядра после обновления (если ядро обновляется)
|
Target string `json:"target,omitempty"` // версия ядра после обновления (если ядро обновляется)
|
||||||
Result string `json:"result,omitempty"`
|
Result string `json:"result,omitempty"`
|
||||||
|
Note string `json:"note,omitempty"` // пояснение, которое нужно показать и после перезапуска ядра
|
||||||
Err string `json:"error,omitempty"`
|
Err string `json:"error,omitempty"`
|
||||||
Started time.Time `json:"started"`
|
Started time.Time `json:"started"`
|
||||||
Version string `json:"version"` // версия работающего bj-server
|
Version string `json:"version"` // версия работающего bj-server
|
||||||
@@ -59,6 +60,12 @@ func progressTarget(v string) {
|
|||||||
updProg.s.Target = v
|
updProg.s.Target = v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func progressNote(n string) {
|
||||||
|
updProg.Lock()
|
||||||
|
defer updProg.Unlock()
|
||||||
|
updProg.s.Note = n
|
||||||
|
}
|
||||||
|
|
||||||
func progressEnd(result string, err error) {
|
func progressEnd(result string, err error) {
|
||||||
updProg.Lock()
|
updProg.Lock()
|
||||||
defer updProg.Unlock()
|
defer updProg.Unlock()
|
||||||
|
|||||||
@@ -599,7 +599,7 @@ label { font-size:13px; font-weight:500; }
|
|||||||
doneEl.style.display='block';
|
doneEl.style.display='block';
|
||||||
}
|
}
|
||||||
function run(form){
|
function run(form){
|
||||||
var startVer=null, target='', seenActive=false, postDone=false, lost=false, t0=Date.now(), seq0=null;
|
var note='', startVer=null, target='', seenActive=false, postDone=false, lost=false, t0=Date.now(), seq0=null;
|
||||||
show(); stageEl.textContent='Отправка запроса…'; bar.style.width='3%'; detail.textContent='';
|
show(); stageEl.textContent='Отправка запроса…'; bar.style.width='3%'; detail.textContent='';
|
||||||
var xhr=new XMLHttpRequest(); xhr.open('POST', form.action);
|
var xhr=new XMLHttpRequest(); xhr.open('POST', form.action);
|
||||||
var file=form.querySelector('input[type=file]');
|
var file=form.querySelector('input[type=file]');
|
||||||
@@ -613,8 +613,9 @@ label { font-size:13px; font-weight:500; }
|
|||||||
fetch('/admin/setup/update/progress',{cache:'no-store',credentials:'same-origin'}).then(function(r){ if(!r.ok) throw 0; return r.json(); }).then(function(p){
|
fetch('/admin/setup/update/progress',{cache:'no-store',credentials:'same-origin'}).then(function(r){ if(!r.ok) throw 0; return r.json(); }).then(function(p){
|
||||||
if(startVer===null){ startVer=p.version; seq0=p.seq; }
|
if(startVer===null){ startVer=p.version; seq0=p.seq; }
|
||||||
if(p.target) target=p.target;
|
if(p.target) target=p.target;
|
||||||
|
if(p.note) note=p.note;
|
||||||
if(lost){ // bj вернулся после перезапуска
|
if(lost){ // bj вернулся после перезапуска
|
||||||
if(!target || p.version===target || p.version!==startVer){ finish('Готово: bj перезапущен, работает версия '+p.version+'.', true); detail.textContent=''; return; }
|
if(!target || p.version===target || p.version!==startVer){ finish('Готово: bj перезапущен, работает версия '+p.version+'.', true); detail.textContent=note ? note.charAt(0).toUpperCase()+note.slice(1)+'.' : ''; return; }
|
||||||
}
|
}
|
||||||
var fresh = p.seq!==seq0 || seenActive || postDone;
|
var fresh = p.seq!==seq0 || seenActive || postDone;
|
||||||
if(p.active){ seenActive=true;
|
if(p.active){ seenActive=true;
|
||||||
|
|||||||
Reference in New Issue
Block a user