def _mark_node_inactive(readonly, node):
  if node not in actionstaken["node_marked_inactive"]:
    actionstaken["node_marked_inactive"].append(node)
    
  if readonly:
    log.info(str(node) + " Not marking node as inactive because called in readonly mode.")
  else:
    log.info(str(node) + " Marking node as inactive.")
    maindb.mark_node_as_inactive(node)
def _mark_node_inactive(readonly, node):
    if node not in actionstaken["node_marked_inactive"]:
        actionstaken["node_marked_inactive"].append(node)

    if readonly:
        log.info(
            str(node) +
            " Not marking node as inactive because called in readonly mode.")
    else:
        log.info(str(node) + " Marking node as inactive.")
        maindb.mark_node_as_inactive(node)
def processnode(node_string, startstate_name, endstate_name, nodeprocess_func, nodeerror_func, mark_node_active, *nodeprocess_args):
  """
  <Purpose>
    First check the current state of the node, to ensure that it is in the
    correct state. Then run the nodeprocess_func on the node to process
    the node. Then set the new state of the node once the node has been
    processed properly.

  <Arguments>
    node_string - this is the node itself that is gotten from advertise_lookup,
      most likely an ip:port address or NAT:ip.

    startstate_name - the state in which the nodes are in now.

    endstate_name - the state we want to transition the nodes to.

    nodeprocess_func - the function that is used to process the node

    nodeerror_func - the function that is run, if there is an error

    mark_node_active - This bit determines if we want to mark the node
      as an active node or not.

    nodeprocess_args - the arguments for nodeprocess_func

  <Exceptions>
    NodeError - raised if the node is in a weird state, or if the 
      node does not exist

    NodemanagerCommunicationError - raised if problem communicating the node

    DatabaseError - raised if unable to access database

    UnexpectedError - if some unusual error occurs thats not caught by others

  <Side Effects>
    Database may get modified

  <Return>
    Return true if processing the node was successful, otherwise return false
    if any exceptions occured
  """
 
  # The pubkey for the state.
  startstate_pubkey = transition_state_keys[startstate_name]
  endstate_pubkey = transition_state_keys[endstate_name]

  # Make sure that the node is just not an empty string. 
  # The node_string could be bad due to bad advertise_lookup.
  if not node_string:
    raise NodeError("An empty node was passed down to processnode() with startstate: "+
                   startstate_name)

  # Note that the first portion of the node might be an ip or a NAT string.
  (ip_or_nat_string, port_num) = split_node_string(node_string)

  log("Starting to process node: "+node_string)

  # Try to retrieve the vessel dictionary for a node, 
  # on error raise a NodeError exception.
  try:
    node_info = nodemanager.get_node_info(ip_or_nat_string, port_num)
  except NodemanagerCommunicationError:
    raise
    

  # Extract the nodeID in order to acquire a lock
  nodeID =  _do_rsa_publickey_to_string(node_info['nodekey'])
  
  # Acquire a node lock
  lockserver_handle = acquire_node_lock(nodeID)

  try:
    log("Retrieving node vesseldict for node: "+node_string)   
    node_info = nodemanager.get_node_info(ip_or_nat_string, port_num)
   
    log("Successfully retrieved node_info for node: " + node_string)

    # If the nodes are in acceptdonationstate, update/check the database
    # to ensure that it matches the node information.
    if startstate_pubkey == transition_state_keys['acceptdonation']:
      add_new_node_to_db(node_string, node_info)         
      log("Successfully added node to the database for node" + node_string)
      log("The database should reflect the node information accurately")

    # Get the database object    
    database_nodeobject = maindb.get_node(nodeID)

    # Retrieve the node state and and the list of vessels.
    current_node_state_pubkey = get_node_state(node_info, database_nodeobject)
 
    # Make sure that the node is in the right state.
    if current_node_state_pubkey != startstate_pubkey:
      log("The node is not in the right transition state. NodeID is: " + nodeID +
          " Current state is " + str(current_node_state_pubkey) +
          ". Should be in state " + str(startstate_pubkey))
      raise NodeError("Node is no longer in the right state!")
  
    # Run the processnode function that was passed originally from the transition scripts.
    try:
      nodeprocess_func(node_string, node_info, database_nodeobject, *nodeprocess_args)
    except:
      log("Failed to process node: " + node_string)
      raise NodeError("Could not process node: " + node_string + traceback.format_exc())

    # Set the node state now that the node has been processed.
    if startstate_pubkey != endstate_pubkey:
      log("Trying to set new state for node: " + node_string)
      set_node_state(database_nodeobject, endstate_pubkey)
      
      # If the mark_node_active bit was set, then we want to mark the node
      # as active in the database. Until the node is marked active, the user
      # may not get credited. This is usually set at the final stage when all
      # vessels have been split.
      if mark_node_active:
        maindb.mark_node_as_active(database_nodeobject)
      else:
        maindb.mark_node_as_inactive(database_nodeobject)
        
      log("Finished setting new state " + endstate_name + " on node " + node_string) 

    else:
      log("Not setting node state: start state and end state are the same.")

  except NodeError:
    log("Node data problem when processing node: " + node_string + traceback.format_exc())
    return False    
  except NodemanagerCommunicationError:
    log("Node communication failed while processing node: " + node_string)
    return False
  except DatabaseError:
    log("Ran into problem accessing database while processing node: " + node_string)
    return False
  except UnexpectedError:
    log("Ran into some unexpected error while processing node: " + node_string)
    return False
  finally:
    release_node_lock(lockserver_handle, nodeID)

  #everything worked out fine
  return True  
def processnode(node_string, startstate_name, endstate_name, nodeprocess_func, nodeerror_func, mark_node_active, *nodeprocess_args):
  """
  <Purpose>
    First check the current state of the node, to ensure that it is in the
    correct state. Then run the nodeprocess_func on the node to process
    the node. Then set the new state of the node once the node has been
    processed properly.

  <Arguments>
    node_string - this is the node itself that is gotten from advertise_lookup,
      most likely an ip:port address or NAT:ip.

    startstate_name - the state in which the nodes are in now.

    endstate_name - the state we want to transition the nodes to.

    nodeprocess_func - the function that is used to process the node

    nodeerror_func - the function that is run, if there is an error

    mark_node_active - This bit determines if we want to mark the node
      as an active node or not.

    nodeprocess_args - the arguments for nodeprocess_func

  <Exceptions>
    NodeError - raised if the node is in a weird state, or if the 
      node does not exist

    NodemanagerCommunicationError - raised if problem communicating the node

    DatabaseError - raised if unable to access database

    UnexpectedError - if some unusual error occurs thats not caught by others

  <Side Effects>
    Database may get modified

  <Return>
    Return true if processing the node was successful, otherwise return false
    if any exceptions occured
  """
 
  # The pubkey for the state.
  startstate_pubkey = transition_state_keys[startstate_name]
  endstate_pubkey = transition_state_keys[endstate_name]

  # Make sure that the node is just not an empty string. 
  # The node_string could be bad due to bad advertise_lookup.
  if not node_string:
    raise NodeError("An empty node was passed down to processnode() with startstate: "+
                   startstate_name)

  # Note that the first portion of the node might be an ip or a NAT string.
  (ip_or_nat_string, port_num) = split_node_string(node_string)

  log("Starting to process node: "+node_string)

  # Try to retrieve the vessel dictionary for a node, 
  # on error raise a NodeError exception.
  try:
    node_info = nodemanager.get_node_info(ip_or_nat_string, port_num)
  except NodemanagerCommunicationError:
    raise
    

  # Extract the nodeID in order to acquire a lock
  nodeID =  _do_rsa_publickey_to_string(node_info['nodekey'])
  
  # Acquire a node lock
  lockserver_handle = acquire_node_lock(nodeID)

  try:
    log("Retrieving node vesseldict for node: "+node_string)   
    node_info = nodemanager.get_node_info(ip_or_nat_string, port_num)
   
    log("Successfully retrieved node_info for node: " + node_string)

    # If the nodes are in acceptdonationstate, update/check the database
    # to ensure that it matches the node information.
    if startstate_pubkey == transition_state_keys['acceptdonation']:
      add_new_node_to_db(node_string, node_info)         
      log("Successfully added node to the database for node" + node_string)
      log("The database should reflect the node information accurately")

    # Get the database object    
    database_nodeobject = maindb.get_node(nodeID)

    # Retrieve the node state and and the list of vessels.
    current_node_state_pubkey = get_node_state(node_info, database_nodeobject)
 
    # Make sure that the node is in the right state.
    if current_node_state_pubkey != startstate_pubkey:
      log("The node is not in the right transition state. NodeID is: " + nodeID +
          " Current state is " + str(current_node_state_pubkey) +
          ". Should be in state " + str(startstate_pubkey))
      raise NodeError("Node is no longer in the right state!")
  
    # Run the processnode function that was passed originally from the transition scripts.
    try:
      nodeprocess_func(node_string, node_info, database_nodeobject, *nodeprocess_args)
    except:
      log("Failed to process node: " + node_string)
      raise NodeError("Could not process node: " + node_string + traceback.format_exc())

    # Set the node state now that the node has been processed.
    if startstate_pubkey != endstate_pubkey:
      log("Trying to set new state for node: " + node_string)
      set_node_state(database_nodeobject, endstate_pubkey)
      
      # If the mark_node_active bit was set, then we want to mark the node
      # as active in the database. Until the node is marked active, the user
      # may not get credited. This is usually set at the final stage when all
      # vessels have been split.
      if mark_node_active:
        maindb.mark_node_as_active(database_nodeobject)
      else:
        maindb.mark_node_as_inactive(database_nodeobject)
        
      log("Finished setting new state " + endstate_name + " on node " + node_string) 

    else:
      log("Not setting node state: start state and end state are the same.")

  except NodeError:
    log("Node data problem when processing node: " + node_string + traceback.format_exc())
    return False    
  except NodemanagerCommunicationError:
    log("Node communication failed while processing node: " + node_string)
    return False
  except DatabaseError:
    log("Ran into problem accessing database while processing node: " + node_string)
    return False
  except UnexpectedError:
    log("Ran into some unexpected error while processing node: " + node_string)
    return False
  finally:
    release_node_lock(lockserver_handle, nodeID)

  #everything worked out fine
  return True