def _cleanup_single_vessel(vessel):
  """
  This function is passed by cleanup_vessels() as the function argument to
  run_parallelized().
  """
  
  # This does seem wasteful of lockserver communication to require four
  # round-trips with the lockserver (get handle, lock, unlock, release handle),
  # but if we really want to fix that then I think the best thing to do would
  # be to allow obtaining a lockhandle and releasing a lockhandle to be done
  # in the same calls as lock acquisition and release. 
  
  node_id = maindb.get_node_identifier_from_vessel(vessel)
  lockserver_handle = lockserver.create_lockserver_handle()
  
  # Lock the node that the vessels is on.
  lockserver.lock_node(lockserver_handle, node_id)
  try:
    # Get a new vessel object from the db in case it was modified in the db
    # before the lock was obtained.
    vessel = maindb.get_vessel(node_id, vessel.name)
    
    # Now that we have a lock on the node that this vessel is on, find out
    # if we should still clean up this vessel (e.g. maybe a node state
    # transition script moved the node to a new state and this vessel was
    # removed).
    needscleanup, reasonwhynot = maindb.does_vessel_need_cleanup(vessel)
    if not needscleanup:
      log.info("[_cleanup_single_vessel] Vessel " + str(vessel) + 
               " no longer needs cleanup: " + reasonwhynot)
      return
    
    nodeid = maindb.get_node_identifier_from_vessel(vessel)
    nodehandle = _get_node_handle_from_nodeid(nodeid)
    
    try:
      log.info("[_cleanup_single_vessel] About to ChangeUsers on vessel " + str(vessel))
      nodemanager.change_users(nodehandle, vessel.name, [''])
      log.info("[_cleanup_single_vessel] About to ResetVessel on vessel " + str(vessel))
      nodemanager.reset_vessel(nodehandle, vessel.name)
    except NodemanagerCommunicationError:
      # We don't pass this exception up. Maybe the node is offline now. At some
      # point, it will be marked in the database as offline (should we be doing
      # that here?). At that time, the dirty vessels on that node will not be
      # in the cleanup list anymore.
      log.info("[_cleanup_single_vessel] Failed to cleanup vessel " + 
               str(vessel) + ". " + traceback.format_exc())
      return
      
    # We only mark it as clean if no exception was raised when trying to
    # perform the above nodemanager operations.
    maindb.mark_vessel_as_clean(vessel)
  
    log.info("[_cleanup_single_vessel] Successfully cleaned up vessel " + str(vessel))

  finally:
    # Unlock the node.
    lockserver.unlock_node(lockserver_handle, node_id)
    lockserver.destroy_lockserver_handle(lockserver_handle)
Example #2
0
    def test_get_queryset_vessel_acquired_by_user_changes(self):
        """
    This is ultimately testing
    maindb._get_queryset_of_all_available_vessels_for_a_port_include_nat_nodes()
    """

        # Create a user who will be doing the acquiring.
        user = maindb.create_user("testuser", "password",
                                  "*****@*****.**", "affiliation", "1 2",
                                  "2 2 2", "3 4")

        userport = user.usable_vessel_port

        # Create two nodes that have three vessels but only one vessel on the user's port.
        portlist = [userport - 1, userport, userport + 1]
        ip = "127.0.0.1"
        create_node_and_vessels_with_one_port_each(ip, portlist)
        ip = "127.0.0.2"
        create_node_and_vessels_with_one_port_each(ip, portlist)

        # We expect two available vessels.
        queryset = _get_queryset_include_nat(userport)
        self.assertEqual(2, queryset.count())

        # Mark one of the vessels as acquired.
        vessel = queryset[0]
        maindb.record_acquired_vessel(user, vessel)

        # We expect one available vessel, and it shouldn't be the acquired one.
        queryset = _get_queryset_include_nat(userport)
        self.assertEqual(1, queryset.count())
        self.assertNotEqual(vessel, queryset[0])

        # Release the vessel. It should still be dirty.
        maindb.record_released_vessel(vessel)

        # We expect one available vessel, and it shouldn't be the acquired one.
        queryset = _get_queryset_include_nat(userport)
        self.assertEqual(1, queryset.count())
        self.assertNotEqual(vessel, queryset[0])

        # Mark the vessel as clean (as if the backend cleaned it up).
        maindb.mark_vessel_as_clean(vessel)

        # We expect two available vessels.
        queryset = _get_queryset_include_nat(userport)
        self.assertEqual(2, queryset.count())
    def test_get_queryset_vessel_acquired_by_user_changes(self):
        """
    This is ultimately testing
    maindb._get_queryset_of_all_available_vessels_for_a_port_include_nat_nodes()
    """

        # Create a user who will be doing the acquiring.
        user = maindb.create_user("testuser", "password", "*****@*****.**", "affiliation", "1 2", "2 2 2", "3 4")

        userport = user.usable_vessel_port

        # Create two nodes that have three vessels but only one vessel on the user's port.
        portlist = [userport - 1, userport, userport + 1]
        ip = "127.0.0.1"
        create_node_and_vessels_with_one_port_each(ip, portlist)
        ip = "127.0.0.2"
        create_node_and_vessels_with_one_port_each(ip, portlist)

        # We expect two available vessels.
        queryset = _get_queryset_include_nat(userport)
        self.assertEqual(2, queryset.count())

        # Mark one of the vessels as acquired.
        vessel = queryset[0]
        maindb.record_acquired_vessel(user, vessel)

        # We expect one available vessel, and it shouldn't be the acquired one.
        queryset = _get_queryset_include_nat(userport)
        self.assertEqual(1, queryset.count())
        self.assertNotEqual(vessel, queryset[0])

        # Release the vessel. It should still be dirty.
        maindb.record_released_vessel(vessel)

        # We expect one available vessel, and it shouldn't be the acquired one.
        queryset = _get_queryset_include_nat(userport)
        self.assertEqual(1, queryset.count())
        self.assertNotEqual(vessel, queryset[0])

        # Mark the vessel as clean (as if the backend cleaned it up).
        maindb.mark_vessel_as_clean(vessel)

        # We expect two available vessels.
        queryset = _get_queryset_include_nat(userport)
        self.assertEqual(2, queryset.count())
def _cleanup_single_vessel(vessel):
    """
  This function is passed by cleanup_vessels() as the function argument to
  run_parallelized().
  """

    # This does seem wasteful of lockserver communication to require four
    # round-trips with the lockserver (get handle, lock, unlock, release handle),
    # but if we really want to fix that then I think the best thing to do would
    # be to allow obtaining a lockhandle and releasing a lockhandle to be done
    # in the same calls as lock acquisition and release.

    node_id = maindb.get_node_identifier_from_vessel(vessel)
    lockserver_handle = lockserver.create_lockserver_handle()

    # Lock the node that the vessels is on.
    lockserver.lock_node(lockserver_handle, node_id)
    try:
        # Get a new vessel object from the db in case it was modified in the db
        # before the lock was obtained.
        vessel = maindb.get_vessel(node_id, vessel.name)

        # Now that we have a lock on the node that this vessel is on, find out
        # if we should still clean up this vessel (e.g. maybe a node state
        # transition script moved the node to a new state and this vessel was
        # removed).
        needscleanup, reasonwhynot = maindb.does_vessel_need_cleanup(vessel)
        if not needscleanup:
            log.info("[_cleanup_single_vessel] Vessel " + str(vessel) +
                     " no longer needs cleanup: " + reasonwhynot)
            return

        nodeid = maindb.get_node_identifier_from_vessel(vessel)
        nodehandle = _get_node_handle_from_nodeid(nodeid)

        try:
            log.info(
                "[_cleanup_single_vessel] About to ChangeUsers on vessel " +
                str(vessel))
            nodemanager.change_users(nodehandle, vessel.name, [''])
            log.info(
                "[_cleanup_single_vessel] About to ResetVessel on vessel " +
                str(vessel))
            nodemanager.reset_vessel(nodehandle, vessel.name)
        except NodemanagerCommunicationError:
            # We don't pass this exception up. Maybe the node is offline now. At some
            # point, it will be marked in the database as offline (should we be doing
            # that here?). At that time, the dirty vessels on that node will not be
            # in the cleanup list anymore.
            log.info("[_cleanup_single_vessel] Failed to cleanup vessel " +
                     str(vessel) + ". " + traceback.format_exc())
            return

        # We only mark it as clean if no exception was raised when trying to
        # perform the above nodemanager operations.
        maindb.mark_vessel_as_clean(vessel)

        log.info("[_cleanup_single_vessel] Successfully cleaned up vessel " +
                 str(vessel))

    finally:
        # Unlock the node.
        lockserver.unlock_node(lockserver_handle, node_id)
        lockserver.destroy_lockserver_handle(lockserver_handle)