Revision 1a2e7fe9 lib/masterd/instance.py

b/lib/masterd/instance.py
50 50
  #: Time after which daemon must be listening
51 51
  DEFAULT_LISTEN_TIMEOUT = 10
52 52

  
53
  #: Progress update interval
54
  DEFAULT_PROGRESS_INTERVAL = 60
55

  
53 56
  __slots__ = [
54 57
    "error",
55 58
    "ready",
56 59
    "listen",
57 60
    "connect",
61
    "progress",
58 62
    ]
59 63

  
60 64
  def __init__(self, connect,
61 65
               listen=DEFAULT_LISTEN_TIMEOUT,
62 66
               error=DEFAULT_ERROR_TIMEOUT,
63
               ready=DEFAULT_READY_TIMEOUT):
67
               ready=DEFAULT_READY_TIMEOUT,
68
               progress=DEFAULT_PROGRESS_INTERVAL):
64 69
    """Initializes this class.
65 70

  
66 71
    @type connect: number
......
71 76
    @param error: Length of time until errors cause hard failure
72 77
    @type ready: number
73 78
    @param ready: Timeout for daemon to become ready
79
    @type progress: number
80
    @param progress: Progress update interval
74 81

  
75 82
    """
76 83
    self.error = error
77 84
    self.ready = ready
78 85
    self.listen = listen
79 86
    self.connect = connect
87
    self.progress = progress
80 88

  
81 89

  
82 90
class ImportExportCbBase(object):
......
101 109

  
102 110
    """
103 111

  
112
  def ReportProgress(self, ie, private):
113
    """Called when new progress information should be reported.
114

  
115
    @type ie: Subclass of L{_DiskImportExportBase}
116
    @param ie: Import/export object
117
    @param private: Private data passed to import/export object
118

  
119
    """
120

  
104 121
  def ReportFinished(self, ie, private):
105 122
    """Called when a transfer has finished.
106 123

  
......
157 174
    self._ts_connected = None
158 175
    self._ts_finished = None
159 176
    self._ts_cleanup = None
177
    self._ts_last_progress = None
160 178
    self._ts_last_error = None
161 179

  
162 180
    # Transfer status
......
178 196
    return None
179 197

  
180 198
  @property
199
  def progress(self):
200
    """Returns transfer progress information.
201

  
202
    """
203
    if not self._daemon:
204
      return None
205

  
206
    return (self._daemon.progress_mbytes,
207
            self._daemon.progress_throughput,
208
            self._daemon.progress_percent,
209
            self._daemon.progress_eta)
210

  
211
  @property
181 212
  def active(self):
182 213
    """Determines whether this transport is still active.
183 214

  
......
345 376

  
346 377
    return False
347 378

  
379
  def _CheckProgress(self):
380
    """Checks whether a progress update should be reported.
381

  
382
    """
383
    if ((self._ts_last_progress is None or
384
         _TimeoutExpired(self._ts_last_progress, self._timeouts.progress)) and
385
        self._daemon and
386
        self._daemon.progress_mbytes is not None and
387
        self._daemon.progress_throughput is not None):
388
      self._cbs.ReportProgress(self, self._private)
389
      self._ts_last_progress = time.time()
390

  
348 391
  def CheckFinished(self):
349 392
    """Checks whether the daemon exited.
350 393

  
......
358 401
      return True
359 402

  
360 403
    if self._daemon.exit_status is None:
404
      # TODO: Adjust delay for ETA expiring soon
405
      self._CheckProgress()
361 406
      return False
362 407

  
363 408
    self._ts_finished = time.time()
......
404 449
    """Finalizes this import/export.
405 450

  
406 451
    """
407
    assert error or self.success is not None
408

  
409 452
    if self._daemon_name:
410 453
      logging.info("Finalizing %s %r on %s",
411 454
                   self.MODE_TEXT, self._daemon_name, self.node_name)
......
576 619
    return self._ts_begin
577 620

  
578 621

  
622
def FormatProgress(progress):
623
  """Formats progress information for user consumption
624

  
625
  """
626
  (mbytes, throughput, percent, _) = progress
627

  
628
  parts = [
629
    utils.FormatUnit(mbytes, "h"),
630

  
631
    # Not using FormatUnit as it doesn't support kilobytes
632
    "%0.1f MiB/s" % throughput,
633
    ]
634

  
635
  if percent is not None:
636
    parts.append("%d%%" % percent)
637

  
638
  # TODO: Format ETA
639

  
640
  return utils.CommaJoin(parts)
641

  
642

  
579 643
class ImportExportLoop:
580 644
  MIN_DELAY = 1.0
581 645
  MAX_DELAY = 20.0
......
772 836
    self.feedback_fn("%s is sending data on %s" %
773 837
                     (dtp.data.name, ie.node_name))
774 838

  
839
  def ReportProgress(self, ie, dtp):
840
    """Called when new progress information should be reported.
841

  
842
    """
843
    progress = ie.progress
844
    if not progress:
845
      return
846

  
847
    self.feedback_fn("%s sent %s" % (dtp.data.name, FormatProgress(progress)))
848

  
775 849
  def ReportFinished(self, ie, dtp):
776 850
    """Called when a transfer has finished.
777 851

  
......
993 1067

  
994 1068
    self._feedback_fn("Disk %s is now sending data" % idx)
995 1069

  
1070
  def ReportProgress(self, ie, private):
1071
    """Called when new progress information should be reported.
1072

  
1073
    """
1074
    (idx, _) = private
1075

  
1076
    progress = ie.progress
1077
    if not progress:
1078
      return
1079

  
1080
    self._feedback_fn("Disk %s sent %s" % (idx, FormatProgress(progress)))
1081

  
996 1082
  def ReportFinished(self, ie, private):
997 1083
    """Called when a transfer has finished.
998 1084

  

Also available in: Unified diff