Univention Bugzilla – Attachment 3609 Details for
Bug 22898
UMC2: Online-Updates
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Funktionalität fertig, Fehler behoben
univention-management-console-module-online-2011-10-07.patch (text/plain), 17.16 KB, created by
Frank Greif
on 2011-10-07 16:23 CEST
(
hide
)
Description:
Funktionalität fertig, Fehler behoben
Filename:
MIME Type:
Creator:
Frank Greif
Created:
2011-10-07 16:23 CEST
Size:
17.16 KB
patch
obsolete
>Index: umc/python/online/__init__.py >=================================================================== >--- umc/python/online/__init__.py (revision 3620) >+++ umc/python/online/__init__.py (working copy) >@@ -44,6 +44,7 @@ > from string import join > from subprocess import Popen > from hashlib import md5 >+from copy import deepcopy > > from univention.management.console.log import MODULE > from univention.management.console.protocol.definitions import * >@@ -104,8 +105,8 @@ > 'logfile': '/var/log/univention/updater.log', > 'statusfile': '/var/lib/univention-updater/univention-updater.status' > }, >- # no API available, and no wrapper-wrapper too (or at least, didn't find one). >- # Should I write a wrapper, especially to get consistent behaviour in terms of 'logfile' and 'statusfile'? >+ # *** IMPORTANT! *** the arg list from our request contains the COMPONENT name but the command >+ # here must contain the list of DEFAULTPACKAGES! > # cmd = '/usr/share/univention-updater/univention-updater-umc-univention-install %s' % (' '.join(pkglist)) > 'component': { > 'purpose': _("Install component '%s'"), >@@ -843,22 +844,30 @@ > MODULE.info(" << %s" % s) > # ----------------------------------- > result = None >- job = 'unknown' >+ job = '' > if self._current_job and 'job' in self._current_job: > job = self._current_job['job'] > else: >- job = request.options.get('job','none') >+ job = request.options.get('job','') > > count = request.options.get('count',0) > result = 0 if count < 0 else [] > if not job in INSTALLERS: >- MODULE.warn(" ?? Don't know a '%s' job" % job) >+ # job empty: this is the first call I can't avoid >+ if job != '': >+ MODULE.warn(" ?? Don't know a '%s' job" % job) > else: > if not 'logfile' in INSTALLERS[job]: > MODULE.warn(" ?? Job '%s' has no associated log file" % job) > else: > fname = INSTALLERS[job]['logfile'] >- result = self._logview(fname, count) >+ if count < 0: >+ result = self._logstamp(fname) >+ else: >+ # don't read complete file if we have an 'ignore' count >+ if (count == 0) and (self._current_job['lines']): >+ count = -self._current_job['lines'] >+ result = self._logview(fname, count) > > # again debug, shortened > if isinstance(result,int): >@@ -900,7 +909,12 @@ > job = request.options.get('job','') > result = {} > if job in INSTALLERS: >- result = INSTALLERS[job] >+ # make a copy, not a reference! >+# result = {} >+# for arg in INSTALLERS[job]: >+# result[arg] = INSTALLERS[job][arg] >+ result = deepcopy(INSTALLERS[job]) >+ > if 'statusfile' in INSTALLERS[job]: > try: > for line in open(INSTALLERS[job]['statusfile']): >@@ -944,6 +958,10 @@ > result['label'] = result['purpose'] % result['detail'] > else: > result['label'] = result['purpose'] >+ # Affordance to reboot... hopefully this gets set before >+ # we stop polling on this job status >+ self.ucr.load() # make it as current as possible >+ result['reboot'] = self.ucr.is_true('update/reboot/required',False) > > # ----------- DEBUG ----------------- > MODULE.info("online/installer/status returns:") >@@ -979,6 +997,9 @@ > MODULE.info(" << %s" % s) > # ----------------------------------- > >+ # Clean up any stored job details ... they're now obsolete. >+ self._current_job = {} >+ > result = {} > result['status'] = 0 # successful. If not: set result['message'] too. > >@@ -999,12 +1020,50 @@ > self.finished(request.id,result) > return > >- cmd = INSTALLERS[subject]['command'] >- if cmd.find('%') != -1: >- cmd = cmd % request.options.get('detail','') >- MODULE.info(" ++ Creating job: '%s'" % cmd) >- self.__create_at_job(cmd,detail) >+ # We want to limit the amount of logfile data being transferred >+ # to the frontend. So we remember the line count of the associated >+ # log file. >+ if 'logfile' in INSTALLERS[subject]: >+ fname = INSTALLERS[subject]['logfile'] >+ count = 0 >+ try: >+ file = open(fname,'r') >+ count = 0 >+ for line in file: >+ count += 1 >+ finally: >+ if file != None: >+ file.close() >+ self._current_job['lines'] = count > >+ try: >+ # Assemble the command line, now somewhat complicated: >+ # >+ # (1) take the 'command' entry from the INSTALLERS entry of this subject >+ # (2) if it doesn't contain a percent sign -> ready. >+ # (3) if it contains a percent sign: we must format something: >+ # (4) if the subject is about 'component' we must get the 'defaultpackages' >+ # entry from the UCR tuple named by 'detail' and use that. >+ # (5) if not, we can format the 'detail' field into the command. >+ # cmd = '%s' % INSTALLERS[subject]['command'] # I need a copy of this string! >+ cmd = INSTALLERS[subject]['command'] >+ if cmd.find('%') != -1: >+ if subject == 'component': >+ # Strictly spoken, we can't arrive here if 'defaultpackages' is not set >+ ucrs = '%s/%s/defaultpackages' % (COMPONENT_BASE,detail) >+ pkgs = self.ucr.get(ucrs,'') >+ cmd = cmd % pkgs >+ MODULE.info(" Resolution of default packages of the '%s' component:" % detail) >+ MODULE.info(" UCRS = '%s'" % ucrs) >+ MODULE.info(" PKGS = '%s'" % pkgs) >+ MODULE.info(" CMD = '%s'" % cmd) >+ else: >+ cmd = cmd % request.options.get('detail','') >+ MODULE.info(" ++ Creating job: '%s'" % cmd) >+ self.__create_at_job(cmd,detail) >+ except Exception,ex: >+ MODULE.warn(" ERROR: %s" % str(ex)) >+ > # ----------- DEBUG ----------------- > MODULE.info("online/installer/execute returns:") > pp = pprint.PrettyPrinter(indent=4) >@@ -1243,29 +1302,36 @@ > # > # ------------------------------------------------------------------------------ > >+ def _logstamp(self,fname): >+ """ Logfile timestamp. Now a seperate function. >+ """ >+ try: >+ st = stat(fname) >+ if st: >+ MODULE.info(" >> log file stamp = '%s'" % st[9]) >+ return st[9] >+ return 0 >+ except: >+ return 0 >+ > def _logview(self,fname,count): >- """Contains all functions needed to view or 'tail' an arbitrary text file. >- Argument 'count' can have different values: >- < 0 ... return Unix timestamp of log file, to avoid fetching unchanged file. >- 0 ..... return the whole file, splitted into lines. >- > 0 ... return the last 'count' lines of the file. (a.k.a. tail -n <count>)""" >+ """ Contains all functions needed to view or 'tail' an arbitrary text file. >+ Argument 'count' can have different values: >+ < 0 ... ignore this many lines, return the rest of the file >+ 0 ..... return the whole file, splitted into lines. >+ > 0 ... return the last 'count' lines of the file. (a.k.a. tail -n <count>) >+ """ > lines = [] >- if count < 0: >- try: >- st = stat(fname) >- if st: >- MODULE.info(" >> log file stamp = '%s'" % st[9]) >- return st[9] >- return 0 >- except: >- return 0 > try: > file = open(fname,'r') > for line in file: >- l = line.rstrip() >- lines.append(l) >- if (count) and (len(lines) > count): >- lines.pop(0) >+ if (count < 0): >+ count += 1 >+ else: >+ l = line.rstrip() >+ lines.append(l) >+ if (count > 0) and (len(lines) > count): >+ lines.pop(0) > finally: > if file != None: > file.close() >@@ -1289,6 +1355,7 @@ > script = ''' > #:started: %s > #:detail: %s >+#:command: %s > dpkg-statoverride --add root root 0644 /usr/sbin/univention-management-console-web-server > dpkg-statoverride --add root root 0644 /usr/sbin/univention-management-console-server > dpkg-statoverride --add root root 0644 /usr/sbin/apache2 >@@ -1301,7 +1368,7 @@ > dpkg-statoverride --remove /usr/sbin/univention-management-console-server > dpkg-statoverride --remove /usr/sbin/apache2 > chmod +x /usr/sbin/univention-management-console-server /usr/sbin/univention-management-console-web-server /usr/sbin/apache2 >-''' % (started,detail,command) >+''' % (started,detail,command,command) > p1 = subprocess.Popen( [ 'LC_ALL=C at now', ], stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True ) > (stdout,stderr) = p1.communicate( script ) > >@@ -1330,7 +1397,8 @@ > cmd = INSTALLERS[inst]['command'].split('%')[0] > MODULE.info(" ++ Checking for '%s'" % cmd) > if cmd in atout: >- self._current_job = {} >+# cleaning up is done in 'run_installer()' >+# self._current_job = {} > self._current_job['job'] = inst # job key > self._current_job['running'] = True # currently running: we have found it per 'at' job > self._current_job['time'] = int(time()) # record the last time we've seen this job >Index: umc/js/online.js >=================================================================== >--- umc/js/online.js (revision 3620) >+++ umc/js/online.js (working copy) >@@ -93,14 +93,27 @@ > > // waits for the Progress Page to be closed (automatically or by a close button) > dojo.connect(this._progress,'stopWatching',dojo.hitch(this, function(tab) { >- this._updates.refreshPage(true); > this.hideChild(this._progress); > this.showChild(this._updates); > this.showChild(this._components); > this.showChild(this._settings); >+ >+ // Revert to the 'Updates' page if the installer action encountered >+ // the 'reboot' affordance. >+ if (! tab) >+ { >+ tab = this._updates; >+ } > this.selectChild(tab); > })); > >+ // waits for the Progress Page to notify us that a job is finished. This >+ // should immediately refresh the 'Updates' and 'Components' pages. >+ dojo.connect(this._progress,'jobFinished',dojo.hitch(this, function() { >+ this._updates.refreshPage(true); >+ this._components.refreshPage(); >+ })); >+ > // waits for the Progress Page to notify us that a job is running > dojo.connect(this._progress,'jobStarted',dojo.hitch(this, function() { > this._switch_to_progress_page(); >@@ -210,6 +223,7 @@ > > this.hideChild(this._details); > this.hideChild(this._progress); >+ > }, > > // Seperate function that can be called the same way as _call_installer: >@@ -238,7 +252,7 @@ > { > txt += "<tr>\n"; > txt += "<td style='padding-left:1em;'>" + upd[i][0] + "</td>\n"; >- txt += "<td style='padding-left:1em;'>" + upd[i][1] + "</td>\n"; >+ txt += "<td style='padding-left:1em;padding-right:.5em;'>" + upd[i][1] + "</td>\n"; > txt += "</tr>\n"; > } > } >@@ -249,7 +263,7 @@ > { > txt += "<tr>\n"; > txt += "<td style='padding-left:1em;'>" + ins[i][0] + "</td>\n"; >- txt += "<td style='padding-left:1em;'>" + ins[i][1] + "</td>\n"; >+ txt += "<td style='padding-left:1em;padding-right:.5em;'>" + ins[i][1] + "</td>\n"; > txt += "</tr>\n"; > } > } >Index: umc/js/_online/ProgressPage.js >=================================================================== >--- umc/js/_online/ProgressPage.js (revision 3620) >+++ umc/js/_online/ProgressPage.js (working copy) >@@ -75,6 +75,16 @@ > region: 'bottom', > onClick: dojo.hitch(this, function() { > var tab = ''; >+ // Especially for the 'install a component' functionality: if we encounter >+ // that the 'reboot required' flag has been set we don't want to switch >+ // back to the 'Components' grid but rather to the 'Updates' page. We will >+ // request this by unsetting the _last_tab property, so the switching >+ // logic will revert to the first tab of our tab set. >+ if (this._reboot_required) >+ { >+ //alert("Resetting return tab to 'Updates'"); >+ this.last_tab = null; >+ } > if (this.last_tab) > { > tab = this.last_tab; >@@ -152,13 +162,21 @@ > > msg += this._statusfile_data(data.result); > >+ // -------------- DEBUG ------------------ >+// for (var v in this._last_job) >+// { >+// msg += ("<br/> " + v + " = '" + this._last_job[v] + "'"); >+// } >+ // --------------------------------------- >+ > this._head.set('content',msg); >- this._pane.layout(); > > if (! data.result['running']) > { > this._allow_close(true); // does the rest. > } >+ >+ this._pane.layout(); > } > } > >@@ -178,7 +196,9 @@ > > // takes a status structure as returned from the 'online/installer/status' call, > // extracts the fields that came directly from the status file (if any) and >- // formats them in a readable HTML fashion. >+ // formats them into a one-liner. Returns an empty string if nothing matches. >+ // >+ // FOR TEST: now includes the 'reboot' flag if it is present. > _statusfile_data: function(data) { > > var txt = ''; >@@ -193,6 +213,16 @@ > } > } > >+ if (data['reboot']) >+ { >+ txt += ' [REBOOT] '; >+ if (! this._reboot_required) // not set or not true >+ { >+ //alert("Setting REBOOT from _statusfile_data"); >+ this._reboot_required = true; >+ } >+ } >+ > if (txt != '') > { > txt = "(" + this._("Current status file content") + ":" + txt + ")<br/>"; >@@ -243,6 +273,10 @@ > { > if ((this._job_key != '') && (this._last_job)) > { >+ // First thing to do: notify the Module that the job is finished. So it can already >+ // refresh the 'Updates' and 'Components' pages before the user gets back there. >+ this.jobFinished(); >+ > // FIXME Manually making empty lines before and after this text; should better be done > // by a style or a style class. > var msg = " <br/>"; >@@ -256,18 +290,36 @@ > > msg += this._statusfile_data(this._last_job); > >+ // -------------- DEBUG ------------------ >+// for (var v in this._last_job) >+// { >+// msg += ("<br/> " + v + " = '" + this._last_job[v] + "'"); >+// } >+ // --------------------------------------- >+ > this._head.set('content',msg); > >- // for the last time: scroll log view to bottom and stop polling timer. >- this._log.scrollToBottom(); >- this._log.stopWatching(); >+ this._log.stopWatching(); // now log is freely scrollable manually > > //alert("Watching is finished, job is '" + this._job_key + "'"); > >+ if ((this._last_job) && (this._last_job['reboot'])) >+ { >+ var reb = this._last_job['reboot']; >+ if (typeof(reb) == 'string') >+ { >+ reb = (reb == 'true'); >+ } >+ if ((! this._reboot_required) || (reb != this._reboot_required)) >+ { >+ //alert("setting REBOOT from _allow_close()"); >+ this._reboot_required = reb; >+ } >+ } >+ > this._last_job = null; // can be deleted, but this._job_key should be retained! > } > } >- this._pane.layout(); > }, > > // gives a means to restart polling after reauthentication >@@ -281,9 +333,18 @@ > jobStarted: function() { > }, > >+ // This function will be called when the already opened ProgressPage encounters >+ // the end of the current job. The online Module listens here and will refresh >+ // the 'Updates' and 'Components' pages. >+ jobFinished: function() { >+ }, >+ > // online Module calls this when the ProgressPage is to be opened. > startWatching: function(args) { >- //alert("ProgressPage::startWatching()"); >+ >+ // ensure a clean look (and not some stale text from last job) >+ this._head.set('content',this._("... loading job data ...")); >+ > dojo.mixin(this,args); // as simple as possible. > this._allow_close(false); // forbid closing this tab. > this._log.startWatching(this._interval); // start logfile tail >@@ -291,10 +352,12 @@ > > // online Module listens to this event to close the page > // and reopen the named tab. >+ // >+ // This is a good place to reset the log viewer contents too. > stopWatching: function(tab) { > this._job_key = ''; > this._last_job = null; >- this._log.stopWatching(); >+ this._log.stopWatching(true); > }, > > // lets the timer loop stop when the module is closed. >Index: umc/js/_online/UpdatesPage.js >=================================================================== >--- umc/js/_online/UpdatesPage.js (revision 3620) >+++ umc/js/_online/UpdatesPage.js (working copy) >@@ -10,6 +10,7 @@ > dojo.declare("umc.modules._online.UpdatesPage", umc.modules._online.Page, { > > i18nClass: 'umc.modules.online', >+ _last_reboot: false, > > postMixInProperties: function() { > >@@ -507,6 +508,13 @@ > on = (on == 'true'); > } > >+ // pop a message up whenever the 'on' value changes >+ if (on != this._last_reboot) >+ { >+ //alert("Reboot affordance changed to " + on); >+ this._last_reboot = on; >+ } >+ > var pane = this._form.getChildren()[0].getChildren()[0]; > dojo.toggleClass(pane.domNode,'dijitHidden',! on); > >Index: umc/js/_online/_LogViewer.js >=================================================================== >--- umc/js/_online/_LogViewer.js (revision 3620) >+++ umc/js/_online/_LogViewer.js (working copy) >@@ -186,11 +186,10 @@ > // job key can't be an argument here as we don't know it. > startWatching: function(interval) { > >- //alert("LogViewer::StartWatching(" + interval + ")"); >- > this._check_interval = interval; > // clean up any stale display and states from last run > this.set('content',this._("... loading log file ...")); >+ > this._first_call = 3; > this._last_stamp = 0; > >@@ -207,8 +206,16 @@ > > // effectively stops the polling timer. Can be called from outside (if ProgressPage is being closed) > // or from inside (as 'uninitialize' handler) >- stopWatching: function() { >+ // >+ // Argument 'clean' = TRUE -> also clean up display buffer contents. >+ stopWatching: function(clean) { >+ > this._check_interval = 0; >+ >+ if ((typeof(clean) != 'undefined') && (clean)) >+ { >+ this.set('content',this._("... loading log file ...")); >+ } > }, > > uninitialize: function() {
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
Actions:
View
|
Diff
Attachments on
bug 22898
:
3608
| 3609 |
3830
|
3906
|
3999