Commit 7358c9bf authored by Grégory Wisniewski's avatar Grégory Wisniewski

Define a new Enum class that don't fails with static analysies. This allow

gather good results from tools like 'pylint'.
Use this for cluster state for now, others will follow.


git-svn-id: https://svn.erp5.org/repos/neo/trunk@1333 71dcc9de-d417-0410-9af5-da40c76e7ee4
parent 911111de
......@@ -21,7 +21,7 @@ from time import time
from struct import pack, unpack
from neo import protocol
from neo.protocol import UUID_NAMESPACES, BOOTING_CLUSTER_STATE
from neo.protocol import UUID_NAMESPACES, ClusterStates
from neo.node import NodeManager
from neo.event import EventManager
from neo.connection import ListeningConnection, ClientConnection
......@@ -111,7 +111,7 @@ class Application(object):
self.listening_conn = ListeningConnection(self.em, None,
addr = self.server, connector_handler = self.connector_handler)
self.cluster_state = BOOTING_CLUSTER_STATE
self.cluster_state = ClusterStates.BOOTING
# Start the election of a primary master node.
self.electPrimary()
......@@ -375,7 +375,7 @@ class Application(object):
partition table or make a new table from scratch, if this is the first time."""
logging.info('begin the recovery of the status')
self.changeClusterState(protocol.RECOVERING_CLUSTER_STATE)
self.changeClusterState(ClusterStates.RECOVERING)
em = self.em
self.loid = None
......@@ -384,7 +384,7 @@ class Application(object):
self.target_uuid = None
# collect the last partition table available
while self.cluster_state == protocol.RECOVERING_CLUSTER_STATE:
while self.cluster_state == ClusterStates.RECOVERING:
em.poll(1)
logging.info('startup allowed')
......@@ -473,7 +473,7 @@ class Application(object):
"""Verify the data in storage nodes and clean them up, if necessary."""
em, nm = self.em, self.nm
self.changeClusterState(protocol.VERIFYING_CLUSTER_STATE)
self.changeClusterState(ClusterStates.VERIFYING)
# wait for any missing node
logging.debug('waiting for the cluster to be operational')
......@@ -556,7 +556,7 @@ class Application(object):
em = self.em
nm = self.nm
self.changeClusterState(protocol.RUNNING_CLUSTER_STATE)
self.changeClusterState(ClusterStates.RUNNING)
# This dictionary is used to hold information on transactions being finished.
self.finishing_transaction_dict = {}
......@@ -641,13 +641,13 @@ class Application(object):
nm, em = self.nm, self.em
# select the storage handler
if state == protocol.BOOTING_CLUSTER_STATE:
if state == ClusterStates.BOOTING:
storage_handler = recovery.RecoveryHandler
elif state == protocol.RECOVERING_CLUSTER_STATE:
elif state == ClusterStates.RECOVERING:
storage_handler = recovery.RecoveryHandler
elif state == protocol.VERIFYING_CLUSTER_STATE:
elif state == ClusterStates.VERIFYING:
storage_handler = verification.VerificationHandler
elif state == protocol.RUNNING_CLUSTER_STATE:
elif state == ClusterStates.RUNNING:
storage_handler = storage.StorageServiceHandler
else:
RuntimeError('Unexpected node type')
......@@ -664,7 +664,7 @@ class Application(object):
# those node types keep their own handler
continue
if node.isClient():
if state != protocol.RUNNING_CLUSTER_STATE:
if state != ClusterStates.RUNNING:
conn.close()
handler = client.ClientServiceHandler
elif node.isStorage():
......@@ -715,7 +715,7 @@ class Application(object):
while 1:
self.em.poll(1)
if len(self.finishing_transaction_dict) == 0:
if self.cluster_state == protocol.RUNNING_CLUSTER_STATE:
if self.cluster_state == ClusterStates.RUNNING:
sys.exit("Application has been asked to shut down")
else:
# no more transaction, ask clients to shutdown
......@@ -740,12 +740,12 @@ class Application(object):
def identifyStorageNode(self, uuid, node):
state = protocol.RUNNING_STATE
handler = None
if self.cluster_state == protocol.RECOVERING_CLUSTER_STATE:
if self.cluster_state == ClusterStates.RECOVERING:
if uuid is None:
logging.info('reject empty storage node')
raise protocol.NotReadyError
handler = recovery.RecoveryHandler
elif self.cluster_state == protocol.VERIFYING_CLUSTER_STATE:
elif self.cluster_state == ClusterStates.VERIFYING:
if uuid is None or node is None:
# if node is unknown, it has been forget when the current
# partition was validated by the admin
......@@ -754,12 +754,12 @@ class Application(object):
# conflicting UUID are rejected in the identification handler.
state = protocol.PENDING_STATE
handler = verification.VerificationHandler
elif self.cluster_state == protocol.RUNNING_CLUSTER_STATE:
elif self.cluster_state == ClusterStates.RUNNING:
if uuid is None or node is None:
# same as for verification
state = protocol.PENDING_STATE
handler = storage.StorageServiceHandler
elif self.cluster_state == protocol.STOPPING_CLUSTER_STATE:
elif self.cluster_state == ClusterStates.STOPPING:
raise protocol.NotReadyError
else:
raise RuntimeError('unhandled cluster state')
......@@ -785,7 +785,7 @@ class Application(object):
logging.info('Accept a master %s' % dump(uuid))
elif node_type == protocol.CLIENT_NODE_TYPE:
# refuse any client before running
if self.cluster_state != protocol.RUNNING_CLUSTER_STATE:
if self.cluster_state != ClusterStates.RUNNING:
logging.info('Reject a connection from a client')
raise protocol.NotReadyError
node_ctor = self.nm.createClient
......
......@@ -19,7 +19,7 @@ from neo import logging
from neo import protocol
from neo.master.handlers import MasterHandler
from neo.protocol import RUNNING_STATE
from neo.protocol import ClusterStates, RUNNING_STATE
from neo.util import dump
class AdministrationHandler(MasterHandler):
......@@ -38,7 +38,7 @@ class AdministrationHandler(MasterHandler):
self.app.changeClusterState(state)
p = protocol.noError('cluster state changed')
conn.answer(p, packet.getId())
if state == protocol.STOPPING_CLUSTER_STATE:
if state == ClusterStates.STOPPING:
self.app.cluster_state = state
self.app.shutdown()
......
......@@ -18,6 +18,7 @@
from neo.neoctl.neoctl import NeoCTL, NotReadyException
from neo.util import bin, dump
from neo import protocol
from neo.protocol import ClusterStates
action_dict = {
'print': {
......@@ -53,9 +54,7 @@ class TerminalNeoCTL(object):
return protocol.node_types.getFromStr(value)
def asClusterState(self, value):
if not value.endswith('_CLUSTER_STATE'):
value += '_CLUSTER_STATE'
return protocol.cluster_states.getFromStr(value)
return ClusterStates.getByName(value.upper())
def asNode(self, value):
return bin(value)
......@@ -154,7 +153,7 @@ class TerminalNeoCTL(object):
"""
Starts cluster operation after a startup.
Equivalent to:
set cluster VERIFYING_CLUSTER_STATE
set cluster verifying
"""
assert len(params) == 0
self.neoctl.startCluster()
......
......@@ -20,6 +20,7 @@ from neo.connection import ClientConnection
from neo.event import EventManager
from neo.neoctl.handler import CommandEventHandler
from neo import protocol
from neo.protocol import ClusterStates
class NotReadyException(Exception):
pass
......@@ -126,7 +127,7 @@ class NeoCTL(object):
"""
Set cluster into "verifying" state.
"""
self.setClusterState(protocol.VERIFYING_CLUSTER_STATE)
self.setClusterState(ClusterStates.VERIFYING)
def dropNode(self, node):
"""
......
......@@ -18,6 +18,8 @@
from struct import pack, unpack, error
from socket import inet_ntoa, inet_aton
from neo.util import Enum
class EnumItem(int):
"""
Enumerated value type.
......@@ -52,7 +54,7 @@ class EnumItem(int):
def __repr__(self):
return '<EnumItem %r (%r)>' % (self.name, int(self))
class Enum(dict):
class OldEnum(dict):
"""
C-style enumerated type support with extended typechecking.
Instantiate with a dict whose keys are variable names and values are
......@@ -79,6 +81,7 @@ class Enum(dict):
def getFromStr(self, value, default=None):
return self.str_enum_dict.get(value, default)
# The protocol version (major, minor).
PROTOCOL_VERSION = (4, 0)
......@@ -88,7 +91,7 @@ MAX_PACKET_SIZE = 0x4000000
PACKET_HEADER_SIZE = 10
# Message types.
packet_types = Enum({
packet_types = OldEnum({
# Error is a special type of message, because this can be sent against any other message,
# even if such a message does not expect a reply usually. Any -> Any.
......@@ -304,7 +307,7 @@ packet_types = Enum({
})
# Error codes.
error_codes = Enum({
error_codes = OldEnum({
'NO_ERROR_CODE': 0,
'NOT_READY_CODE': 1,
'OID_NOT_FOUND_CODE': 2,
......@@ -314,17 +317,18 @@ error_codes = Enum({
'INTERNAL_ERROR_CODE': 8,
})
# Cluster states
cluster_states = Enum({
'BOOTING_CLUSTER_STATE': 1,
'RECOVERING_CLUSTER_STATE': 2,
'VERIFYING_CLUSTER_STATE': 3,
'RUNNING_CLUSTER_STATE': 4,
'STOPPING_CLUSTER_STATE': 5,
})
class ClusterStates(Enum):
BOOTING = Enum.Item(1)
RECOVERING = Enum.Item(2)
VERIFYING = Enum.Item(3)
RUNNING = Enum.Item(4)
STOPPING = Enum.Item(5)
ClusterStates = ClusterStates()
# Node types.
node_types = Enum({
node_types = OldEnum({
'MASTER_NODE_TYPE' : 1,
'STORAGE_NODE_TYPE' : 2,
'CLIENT_NODE_TYPE' : 3,
......@@ -332,7 +336,7 @@ node_types = Enum({
})
# Node states.
node_states = Enum({
node_states = OldEnum({
'RUNNING_STATE': 0,
'TEMPORARILY_DOWN_STATE': 1,
'DOWN_STATE': 2,
......@@ -354,7 +358,7 @@ node_state_prefix_dict = {
}
# Partition cell states.
cell_states = Enum({
cell_states = OldEnum({
'UP_TO_DATE_STATE': 0,
'OUT_OF_DATE_STATE': 1,
'FEEDING_STATE': 2,
......@@ -494,9 +498,9 @@ def handle_errors(decoder):
return wrapper
def _decodeClusterState(state):
cluster_state = cluster_states.get(state)
cluster_state = ClusterStates.get(state)
if cluster_state is None:
raise PacketMalformedError('invalid node state %d' % state)
raise PacketMalformedError('invalid cluster state %d' % state)
return cluster_state
def _decodeNodeState(state):
......
......@@ -28,6 +28,7 @@ import unittest
import tempfile
import traceback
from neo.protocol import ClusterStates
from neo.client.Storage import Storage
from neo.tests import getNewUUID
from neo.util import dump
......@@ -433,13 +434,13 @@ class NEOCluster(object):
self.expectCondition(callback, timeout, delay)
def expectClusterRecovering(self, timeout=0, delay=1):
self.expectClusterState(protocol.RECOVERING_CLUSTER_STATE)
self.expectClusterState(ClusterStates.RECOVERING)
def expectClusterVeryfing(self, timeout=0, delay=1):
self.expectClusterState(protocol.VERIFYING_CLUSTER_STATE)
self.expectClusterState(ClusterStates.VERIFYING)
def expectClusterRunning(self, timeout=0, delay=1):
self.expectClusterState(protocol.RUNNING_CLUSTER_STATE)
self.expectClusterState(ClusterStates.RUNNING)
def __del__(self):
if self.cleanup_on_delete:
......
......@@ -23,6 +23,7 @@ from Persistence import Persistent
from neo.tests.functional import NEOCluster, NEOFunctionalTest
from neo.client.Storage import Storage as NEOStorage
from neo import protocol
from neo.protocol import ClusterStates
class PObject(Persistent):
......@@ -388,7 +389,7 @@ class StorageTests(NEOFunctionalTest):
every 1000 partition when sending a partition table. """
self.__setup(storage_number=2, partitions=5000, master_node_count=1)
neoctl = self.neo.getNEOCTL()
self.neo.expectClusterState(protocol.RUNNING_CLUSTER_STATE)
self.neo.expectClusterState(ClusterStates.RUNNING)
def testDropNodeThenRestartCluster(self):
""" Start a cluster with more than one storage, down one, shutdown the
......
......@@ -16,6 +16,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import re
from zlib import adler32
from struct import pack, unpack
from time import time, gmtime
......@@ -91,3 +92,43 @@ def parseMasterList(masters, except_node=None):
return master_node_list
class Enum(dict):
"""
Simulate an enumeration, define them as follow :
class MyEnum(Enum):
ITEM1 = Enum.Item(0)
ITEM2 = Enum.Item(1)
Enum items must be written in full upper case
"""
class Item(int):
def __new__(cls, value):
instance = super(Enum.Item, cls).__new__(cls, value)
instance._enum = None
instance._name = None
return instance
def __str__(self):
return self._name
def __repr__(self):
return "<EnumItem %s (%d)>" % (self._name, self)
def __eq__(self, other):
assert isinstance(other, (Enum.Item, int, float, long))
assert self._enum == other._enum
return int(self) == int(other)
def __init__(self):
for name in dir(self):
if not re.match('^[A-Z_]*$', name):
continue
item = getattr(self, name)
item._name = name
item._enum = self
self[int(item)] = item
def getByName(self, name):
return getattr(self, name)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment