Beispiel #1
0
 def test_balance_status_in_progress(self):
     """
     Moc return value of run_command executing btrfs balance status
     pool_mount_point which is invoked inside of target function.
     :return:
     """
     # balance_status called with pool object of name=Pool object
     #
     # typical return for no current balance operation in progress:
     # out=["No balance found on '/mnt2/single-to-raid1'", '']
     # err=['']
     # rc=0
     # example return for ongoing balance operation:
     pool = Pool(raid='raid0', name='test-pool')
     out = [
         "Balance on '/mnt2/rock-pool' is running",
         '7 out of about 114 chunks balanced (8 considered),  94% left', ''
     ]
     err = ['']
     # N.B. the return code for in progress balance = 1
     rc = 1
     expected_results = {'status': 'running', 'percent_done': 6}
     self.mock_run_command.return_value = (out, err, rc)
     self.mock_mount_root.return_value = '/mnt2/test-mount'
     self.assertEqual(balance_status(pool),
                      expected_results,
                      msg=("Failed to correctly identify "
                           "balance running status"))
Beispiel #2
0
 def test_balance_status_in_progress(self):
     """
     Moc return value of run_command executing btrfs balance status
     pool_mount_point which is invoked inside of target function.
     :return:
     """
     # balance_status called with pool object of name=Pool object
     #
     # typical return for no current balance operation in progress:
     # out=["No balance found on '/mnt2/single-to-raid1'", '']
     # err=['']
     # rc=0
     # example return for ongoing balance operation:
     pool = Pool(raid='raid0', name='test-pool')
     out = ["Balance on '/mnt2/rock-pool' is running",
            '7 out of about 114 chunks balanced (8 considered),  94% left',
            '']
     err = ['']
     # N.B. the return code for in progress balance = 1
     rc = 1
     expected_results = {'status': 'running', 'percent_done': 6}
     self.mock_run_command.return_value = (out, err, rc)
     self.mock_mount_root.return_value = '/mnt2/test-mount'
     self.assertEqual(balance_status(pool), expected_results,
                      msg="Failed to correctly identify balance running status")
Beispiel #3
0
 def _balance_status(pool):
     try:
         # acquire a handle on the last pool balance status db entry
         ps = PoolBalance.objects.filter(pool=pool).order_by('-id')[0]
     except:
         # return empty handed if we have no 'last entry' to update
         return Response()
     # Check if we have a running task which matches our last pool status tid
     if (Task.objects.filter(uuid=ps.tid).exists()):
         to = Task.objects.get(uuid=ps.tid)
         if (to.failed is not None):
             ps.status = 'failed'
             ps.message = to.last_exception
             ps.end_time = to.failed
             ps.save()
             to.delete()
             return ps
     # Get the current status of balance on this pool, irrespective of
     # a running balance task, ie command line intervention.
     cur_status = balance_status(pool)
     previous_status = ps.status
     # TODO: future "Balance Cancel" button should call us to have these
     # TODO: values updated in the db table ready for display later.
     if previous_status == 'cancelling' \
             and cur_status['status'] == 'finished':
         # override current status as 'cancelled'
         cur_status['status'] = 'cancelled'
         cur_status['message'] = \
             'cancelled at %s%% complete' % ps.percent_done
         # and retain prior percent finished value
         cur_status['percent_done'] = ps.percent_done
     if previous_status != 'finished' and previous_status != 'cancelled':
         # update the last pool balance status with current status info.
         PoolBalance.objects.filter(id=ps.id).update(**cur_status)
     return ps
Beispiel #4
0
 def _balance_status(pool):
     try:
         # acquire a handle on the last pool balance status db entry
         ps = PoolBalance.objects.filter(pool=pool).order_by('-id')[0]
     except:
         # return empty handed if we have no 'last entry' to update
         return Response()
     # Check if we have a running task which matches our last pool status tid
     if (Task.objects.filter(uuid=ps.tid).exists()):
         to = Task.objects.get(uuid=ps.tid)
         if (to.failed is not None):
             ps.status = 'failed'
             ps.message = to.last_exception
             ps.end_time = to.failed
             ps.save()
             to.delete()
             return ps
     # Get the current status of balance on this pool, irrespective of
     # a running balance task, ie command line intervention.
     cur_status = balance_status(pool)
     previous_status = ps.status
     # TODO: future "Balance Cancel" button should call us to have these
     # TODO: values updated in the db table ready for display later.
     if previous_status == 'cancelling' \
             and cur_status['status'] == 'finished':
         # override current status as 'cancelled'
         cur_status['status'] = 'cancelled'
         cur_status['message'] = \
             'cancelled at %s%% complete' % ps.percent_done
         # and retain prior percent finished value
         cur_status['percent_done'] = ps.percent_done
     if previous_status != 'finished' and previous_status != 'cancelled':
         # update the last pool balance status with current status info.
         PoolBalance.objects.filter(id=ps.id).update(**cur_status)
     return ps
Beispiel #5
0
 def _balance_status(self, pool, disk):
     try:
         ps = PoolBalance.objects.filter(pool=pool).order_by('-id')[0]
     except:
         return Response()
     if (ps.status == 'started' or ps.status == 'running'):
         cur_status = balance_status(pool, disk.name)
         PoolBalance.objects.filter(id=ps.id).update(**cur_status)
     return ps
Beispiel #6
0
 def _balance_status(pool, disk):
     try:
         ps = PoolBalance.objects.filter(pool=pool).order_by('-id')[0]
     except:
         return Response()
     if (ps.status == 'started' or ps.status == 'running'):
         cur_status = balance_status(pool, disk.name)
         PoolBalance.objects.filter(id=ps.id).update(**cur_status)
     return ps
Beispiel #7
0
 def test_balance_status_paused(self):
     """
     Test to see if balance_status() correctly identifies a Paused balance state.
     :return:
     """
     pool = Pool(raid='raid0', name='test-pool')
     out = ["Balance on '/mnt2/rock-pool' is paused",
            '3 out of about 114 chunks balanced (4 considered),  97% left',
            '']
     err = ['']
     # N.B. the return code for in progress balance = 1
     rc = 1
     expected_results = {'status': 'paused', 'percent_done': 3}
     self.mock_run_command.return_value = (out, err, rc)
     self.mock_mount_root.return_value = '/mnt2/test-mount'
     self.assertEqual(balance_status(pool), expected_results,
                      msg="Failed to correctly identify balance paused status")
Beispiel #8
0
 def test_balance_status_cancel_requested(self):
     """
     As per test_balance_status_in_progress(self) but while balance is
     :return:
     """
     pool = Pool(raid='raid0', name='test-pool')
     # run_command moc return values.
     out = ["Balance on '/mnt2/rock-pool' is running, cancel requested",
            '15 out of about 114 chunks balanced (16 considered),  87% left',
            '']
     err = ['']
     # N.B. the return code for in progress balance = 1
     rc = 1
     expected_results = {'status': 'cancelling', 'percent_done': 13}
     self.mock_run_command.return_value = (out, err, rc)
     self.mock_mount_root.return_value = '/mnt2/test-mount'
     self.assertEqual(balance_status(pool), expected_results,
                      msg="Failed to correctly identify balance cancel requested status")
Beispiel #9
0
 def _balance_status(pool):
     try:
         ps = PoolBalance.objects.filter(pool=pool).order_by('-id')[0]
     except:
         return Response()
     if (Task.objects.filter(uuid=ps.tid).exists()):
         to = Task.objects.get(uuid=ps.tid)
         if (to.failed is not None):
             ps.status = 'failed'
             ps.message = to.last_exception
             ps.end_time = to.failed
             ps.save()
             to.delete()
             return ps
     elif (ps.status == 'started' or ps.status == 'running'):
         #task finished sucessfully or is still running
         cur_status = balance_status(pool)
         PoolBalance.objects.filter(id=ps.id).update(**cur_status)
     return ps
Beispiel #10
0
 def _balance_status(pool):
     try:
         ps = PoolBalance.objects.filter(pool=pool).order_by('-id')[0]
     except:
         return Response()
     if (Task.objects.filter(uuid=ps.tid).exists()):
         to = Task.objects.get(uuid=ps.tid)
         if (to.failed is not None):
             ps.status = 'failed'
             ps.message = to.last_exception
             ps.end_time = to.failed
             ps.save()
             to.delete()
             return ps
     elif (ps.status == 'started' or ps.status == 'running'):
         #task finished sucessfully or is still running
         cur_status = balance_status(pool)
         PoolBalance.objects.filter(id=ps.id).update(**cur_status)
     return ps
Beispiel #11
0
    def test_balance_status_paused(self):
        """Test to see if balance_status() correctly identifies a Paused balance
        state.  :return:

        """
        pool = Pool(raid='raid0', name='test-pool')
        out = [
            "Balance on '/mnt2/rock-pool' is paused",
            '3 out of about 114 chunks balanced (4 considered),  97% left', ''
        ]
        err = ['']
        # N.B. the return code for in progress balance = 1
        rc = 1
        expected_results = {'status': 'paused', 'percent_done': 3}
        self.mock_run_command.return_value = (out, err, rc)
        self.mock_mount_root.return_value = '/mnt2/test-mount'
        self.assertEqual(balance_status(pool),
                         expected_results,
                         msg=("Failed to correctly identify balance "
                              "paused status"))
Beispiel #12
0
 def test_balance_status_pause_requested(self):
     """
     As per test_balance_status_in_progress(self) but while pause requested
     :return:
     """
     pool = Pool(raid='raid0', name='test-pool')
     out = [
         "Balance on '/mnt2/rock-pool' is running, pause requested",
         '3 out of about 114 chunks balanced (4 considered),  97% left', ''
     ]
     err = ['']
     # N.B. the return code for in progress balance = 1
     rc = 1
     expected_results = {'status': 'pausing', 'percent_done': 3}
     self.mock_run_command.return_value = (out, err, rc)
     self.mock_mount_root.return_value = '/mnt2/test-mount'
     self.assertEqual(
         balance_status(pool),
         expected_results,
         msg="Failed to correctly identify balance pause requested status")
Beispiel #13
0
 def test_balance_status_cancel_requested(self):
     """
     As per test_balance_status_in_progress(self) but while balance is
     :return:
     """
     pool = Pool(raid='raid0', name='test-pool')
     # run_command moc return values.
     out = [
         "Balance on '/mnt2/rock-pool' is running, cancel requested",
         ('15 out of about 114 chunks balanced (16 considered),  '
          '87% left'), ''
     ]
     err = ['']
     # N.B. the return code for in progress balance = 1
     rc = 1
     expected_results = {'status': 'cancelling', 'percent_done': 13}
     self.mock_run_command.return_value = (out, err, rc)
     self.mock_mount_root.return_value = '/mnt2/test-mount'
     self.assertEqual(balance_status(pool),
                      expected_results,
                      msg=("Failed to correctly identify balance cancel "
                           "requested status"))
Beispiel #14
0
 def _balance_status(pool):
     try:
         # acquire a handle on the last pool balance status db entry
         ps = PoolBalance.objects.filter(pool=pool).order_by("-id")[0]
     except:
         # return empty handed if we have no 'last entry' to update
         return Response()
     # Check if we have a pending task which matches our tid.
     logger.debug("POOLS BALANCE MODEL PS.TID = {}".format(ps.tid))
     hi = HUEY
     logger.debug("HUEY.pending() {}".format(hi.pending()))
     # Pending balance tasks. N.B. Executing tasks are no longer pending.
     # There is a 1 to 3 second 'pending" status for Huey tasks.
     pending_task_ids = [
         task.id
         for task in hi.pending()
         if task.name in ["start_balance", "start_resize_pool"]
     ]
     logger.debug("Pending balance task.ids = {}".format(pending_task_ids))
     try:
         # https://huey.readthedocs.io/en/latest/api.html#Huey.get
         # The following does a destructive read unless preserve=True.
         # This read will also throw the TaskException which is our interest here.
         # https://huey.readthedocs.io/en/latest/api.html#Huey.result
         # https://github.com/coleifer/huey/issues/449#issuecomment-535028271
         # Syntax requires huey 2.1.3
         hi.result(ps.tid)
     except TaskException as e:
         ps.status = "failed"
         # N.B. metadata indexes: retries, traceback, task_id, error
         ps.message = e.metadata.get("traceback", "missing 'traceback' key")
         # TODO: Consider a huey signal to triggered the addition of end time
         #  currently no SIGNAL_ERROR is seen to be active (see task.py)
         # ps.end_time = to.failed  # defaults to Null in model.
         # https://docs.djangoproject.com/en/1.8/ref/models/instances
         #  /#specifying-which-fields-to-save
         ps.save(update_fields=["status", "message"])
         return ps
     if ps.status == u"started" and ps.tid in pending_task_ids:
         # Model default (i.e. a new balance) defaults to status "started".
         # Preserve this state while we await our pending task (1 to 3 seconds).
         logger.debug("WE CAN LEAVE OUR MODEL AS IS SO RETURN WITH IT")
         return ps
     # Get the current status of balance on this pool, irrespective of
     # a running balance task, ie command line intervention.
     if ps.internal:
         cur_status = balance_status_internal(pool)
     else:
         cur_status = balance_status(pool)
     previous_status = {"status": ps.status, "percent_done": ps.percent_done}
     logger.debug("PREVIOUS_STATUS = {}".format(previous_status))
     logger.debug("CURRENT STATUS = {}".format(cur_status))
     # TODO: future "Balance Cancel" button should call us to have these
     #  values updated in the db table ready for display later.
     # Update cur_state to become preferred proposed state.
     if (
         previous_status["status"] == u"cancelling"
         and cur_status["status"] == u"finished"
     ):
         # override current status as 'cancelled'
         cur_status["status"] = u"cancelled"
         cur_status["message"] = u"cancelled at {}% complete".format(ps.percent_done)
         # and retain prior percent finished value
         cur_status["percent_done"] = ps.percent_done
     elif (
         previous_status["status"] == u"failed"
         and cur_status["status"] == u"finished"
     ):
         # override current status as 'failed'
         cur_status["status"] = u"failed"
         # and retain prior percent finished value
         cur_status["percent_done"] = ps.percent_done
     logger.debug("PROPOSED STATUS = {}".format(cur_status))
     if cur_status == previous_status:
         logger.debug("PROPOSED STATUS = MODEL STATUS: NO UPDATE REQUIRED")
         return ps
     if (
         previous_status["status"] != u"finished"
         and previous_status["status"] != u"cancelled"
     ):
         # update the last pool balance status with current status info.
         logger.debug(
             "UPDATING BALANCE STATUS ID {} WITH {}".format(ps.id, cur_status)
         )
         PoolBalance.objects.filter(id=ps.id).update(**cur_status)
     return ps