Commit bf8d963a authored by Vincent Pelletier's avatar Vincent Pelletier

Split neoctl implementation to have one method per command.

This allows using introspection to document available commands, so implement that too.


git-svn-id: https://svn.erp5.org/repos/neo/branches/prototype3@810 71dcc9de-d417-0410-9af5-da40c76e7ee4
parent feec8069
......@@ -27,6 +27,113 @@ from neo.connector import getConnectorHandler
from neo.util import bin
from neo import protocol
class ActionError(Exception): pass
def addAction(options):
"""
Add storage nodes pending addition into cluster.
Parameters:
node uuid
UUID of node to add, or "all".
"""
if len(options) == 1 and options[0] == 'all':
uuid_list = []
else:
uuid_list = [bin(opt) for opt in options]
return protocol.addPendingNodes(uuid_list)
def setClusterAction(options):
"""
Set cluster of given name to given state.
Parameters:
cluster state
State to put the cluster in.
"""
# XXX: why do we ask for a cluster name ?
# We connect to only one cluster that we get from configuration file,
# anyway.
name, state = options
state = protocol.cluster_states.getFromStr(state)
if state is None:
raise ActionError('unknown cluster state')
return protocol.setClusterState(name, state)
def setNodeAction(options):
"""
Put given node into given state.
Parameters:
node uuid
UUID of target node
node state
Node state to set.
change partition table (optional)
If given with a 1 value, allow partition table to be changed.
"""
uuid = bin(options.pop(0))
state = node_states.getFromStr(options.pop(0))
if state is None:
raise ActionError('unknown state type')
if len(options):
modify = int(options.pop(0))
else:
modify = 0
return protocol.setNodeState(uuid, state, modify)
def printClusterAction(options):
"""
Print cluster state.
"""
return protocol.askClusterState()
def printNodeAction(options):
"""
Print nodes of a given type.
Parameters:
node type
Print known nodes of given type.
"""
node_type = node_types.getFromStr(options.pop(0))
if node_type is None:
raise ActionError('unknown node type')
return protocol.askNodeList(node_type)
def printPTAction(options):
"""
Print the partition table.
Parameters:
range
all Prints the entire partition table.
1 10 Prints rows 1 to 10 of partition table.
10 0 Prints rows from 10 to the end of partition table.
node uuid (optional)
If given, prints only the rows in which given node is used.
"""
offset = options.pop(0)
if offset == "all":
min_offset = 0
max_offset = 0
else:
min_offset = int(offset)
max_offset = int(options.pop(0))
if len(options):
uuid = bin(options.pop(0))
else:
uuid = INVALID_UUID
return protocol.askPartitionList(min_offset, max_offset, uuid)
action_dict = {
'print': {
'pt': printPTAction,
'node': printNodeAction,
'cluster': printClusterAction,
},
'set': {
'node': setNodeAction,
'cluster': setClusterAction,
},
'add': addAction,
}
class Application(object):
"""The storage node application."""
......@@ -37,9 +144,25 @@ class Application(object):
self.em = EventManager()
self.ptid = INVALID_PTID
def execute(self, args):
"""Execute the command given."""
# print node type : print list of node of the given type (STORAGE_NODE_TYPE, MASTER_NODE_TYPE...)
# set node uuid state [1|0] : set the node for the given uuid to the state (RUNNING_STATE, DOWN_STATE...)
# and modify the partition if asked
# set cluster name [shutdown|operational] : either shutdown the cluster or mark it as operational
current_action = action_dict
level = 1
while current_action is not None and \
level < len(args) and \
isinstance(current_action, dict):
current_action = current_action.get(args[level])
level += 1
if callable(current_action):
try:
p = current_action(args[level:])
except ActionError, message:
self.result = message
else:
handler = CommandEventHandler(self)
# connect to admin node
conn = None
......@@ -55,77 +178,9 @@ class Application(object):
connector_handler = self.connector_handler)
if self.trying_admin_node is False:
break
except OperationFailure, msg:
return "FAIL : %s" %(msg,)
# here are the possible commands
# print pt 1-10 [uuid] : print the partition table for row from 1 to 10 [containing node with uuid]
# print pt all [uuid] : print the partition table for all rows [containing node with uuid]
# print pt 10-0 [uuid] : print the partition table for row 10 to the end [containing node with uuid]
# print node type : print list of node of the given type (STORAGE_NODE_TYPE, MASTER_NODE_TYPE...)
# set node uuid state [1|0] : set the node for the given uuid to the state (RUNNING_STATE, DOWN_STATE...)
# and modify the partition if asked
# set cluster name [shutdown|operational] : either shutdown the cluster or mark it as operational
command = args[0]
options = args[1:]
if command == "print":
print_type = options.pop(0)
if print_type == "pt":
offset = options.pop(0)
if offset == "all":
min_offset = 0
max_offset = 0
else:
min_offset = int(offset)
max_offset = int(options.pop(0))
if len(options):
uuid = bin(options.pop(0))
else:
uuid = INVALID_UUID
p = protocol.askPartitionList(min_offset, max_offset, uuid)
elif print_type == "node":
node_type = options.pop(0)
node_type = node_types.getFromStr(node_type)
if node_type is None:
return 'unknown node type'
p = protocol.askNodeList(node_type)
elif print_type == "cluster":
p = protocol.askClusterState()
else:
return "unknown command options"
elif command == "set":
set_type = options.pop(0)
if set_type == "node":
uuid = bin(options.pop(0))
state = options.pop(0)
state = node_states.getFromStr(state)
if state is None:
return "unknown state type"
if len(options):
modify = int(options.pop(0))
else:
modify = 0
p = protocol.setNodeState(uuid, state, modify)
elif set_type == "cluster":
name = options.pop(0)
state = options.pop(0)
state = protocol.cluster_states.getFromStr(state)
if state is None:
return "unknown cluster state"
p = protocol.setClusterState(name, state)
else:
return "unknown command options"
elif command == "add":
if len(options) == 1 and options[0] == 'all':
uuid_list = []
else:
uuid_list = [bin(opt) for opt in options]
p = protocol.addPendingNodes(uuid_list)
else:
return "unknown command"
conn.ask(p)
self.result = ""
while 1:
......@@ -134,4 +189,36 @@ class Application(object):
break
# close connection
conn.close()
else:
self.result = usage('unknown command')
return self.result
def _usage(action_dict, level=0):
result = []
append = result.append
sub_level = level + 1
for name, action in action_dict.iteritems():
append('%s%s' % (' ' * level, name))
if isinstance(action, dict):
append(_usage(action, level=sub_level))
else:
docstring_line_list = getattr(action, '__doc__',
'(no docstring)').split('\n')
# Strip empty lines at begining & end of line list
for end in (0, -1):
while len(docstring_line_list) \
and docstring_line_list[end] == '':
docstring_line_list.pop(end)
# Get the indentation of first line, to preserve other lines
# relative indentation.
first_line = docstring_line_list[0]
base_indentation = len(first_line) - len(first_line.lstrip())
result.extend([(' ' * sub_level) + x[base_indentation:] \
for x in docstring_line_list])
return '\n'.join(result)
def usage(message):
output_list = [message, 'Available commands:', _usage(action_dict)]
return '\n'.join(output_list)
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