Implement wait for node coordinator transition

References #72
This commit is contained in:
Joshua Boniface 2020-02-19 10:33:22 -05:00
parent 6db4df51c0
commit 0aefafa7f7
5 changed files with 48 additions and 15 deletions

View File

@ -618,7 +618,8 @@ class API_Node_CoordinatorState(Resource):
return api_helper.node_coordinator_state(node) return api_helper.node_coordinator_state(node)
@RequestParser([ @RequestParser([
{ 'name': 'state', 'choices': ('primary', 'secondary'), 'helptext': "A valid state must be specified", 'required': True } { 'name': 'state', 'choices': ('primary', 'secondary'), 'helptext': "A valid state must be specified", 'required': True },
{ 'name': 'wait' }
]) ])
@Authenticator @Authenticator
def post(self, node, reqargs): def post(self, node, reqargs):
@ -636,6 +637,10 @@ class API_Node_CoordinatorState(Resource):
enum: enum:
- primary - primary
- secondary - secondary
- in: query
name: wait
type: boolean
description: Whether to block waiting for the full state transition
responses: responses:
200: 200:
description: OK description: OK
@ -648,10 +653,11 @@ class API_Node_CoordinatorState(Resource):
type: object type: object
id: Message id: Message
""" """
wait = bool(strtobool(reqargs.get('wait', 'false')))
if reqargs['state'] == 'primary': if reqargs['state'] == 'primary':
return api_helper.node_primary(node) return api_helper.node_primary(node, wait)
if reqargs['state'] == 'secondary': if reqargs['state'] == 'secondary':
return api_helper.node_secondary(node) return api_helper.node_secondary(node, wait)
abort(400) abort(400)
api.add_resource(API_Node_CoordinatorState, '/node/<node>/coordinator-state') api.add_resource(API_Node_CoordinatorState, '/node/<node>/coordinator-state')

View File

@ -213,12 +213,12 @@ def node_domain_state(node):
return retdata, retcode return retdata, retcode
def node_secondary(node): def node_secondary(node, wait):
""" """
Take NODE out of primary router mode. Take NODE out of primary router mode.
""" """
zk_conn = pvc_common.startZKConnection(config['coordinators']) zk_conn = pvc_common.startZKConnection(config['coordinators'])
retflag, retdata = pvc_node.secondary_node(zk_conn, node) retflag, retdata = pvc_node.secondary_node(zk_conn, node, wait)
pvc_common.stopZKConnection(zk_conn) pvc_common.stopZKConnection(zk_conn)
if retflag: if retflag:
@ -231,12 +231,12 @@ def node_secondary(node):
} }
return output, retcode return output, retcode
def node_primary(node): def node_primary(node, wait):
""" """
Set NODE to primary router mode. Set NODE to primary router mode.
""" """
zk_conn = pvc_common.startZKConnection(config['coordinators']) zk_conn = pvc_common.startZKConnection(config['coordinators'])
retflag, retdata = pvc_node.primary_node(zk_conn, node) retflag, retdata = pvc_node.primary_node(zk_conn, node, wait)
pvc_common.stopZKConnection(zk_conn) pvc_common.stopZKConnection(zk_conn)
if retflag: if retflag:

View File

@ -26,7 +26,7 @@ from cli_lib.common import call_api
# #
# Primary functions # Primary functions
# #
def node_coordinator_state(config, node, action): def node_coordinator_state(config, node, action, wait):
""" """
Set node coordinator state state (primary/secondary) Set node coordinator state state (primary/secondary)
@ -35,7 +35,8 @@ def node_coordinator_state(config, node, action):
API schema: {"message": "{data}"} API schema: {"message": "{data}"}
""" """
params={ params={
'state': action 'state': action,
'wait': str(wait).lower()
} }
response = call_api(config, 'post', '/node/{node}/coordinator-state'.format(node=node), params=params) response = call_api(config, 'post', '/node/{node}/coordinator-state'.format(node=node), params=params)

View File

@ -348,7 +348,11 @@ def cli_node():
@click.argument( @click.argument(
'node' 'node'
) )
def node_secondary(node): @click.option(
'-w', '--wait', 'wait', is_flag=True, default=False,
help='Wait for transition to complete before returning.'
)
def node_secondary(node, wait):
""" """
Take NODE out of primary router mode. Take NODE out of primary router mode.
""" """
@ -360,7 +364,7 @@ def node_secondary(node):
click.echo(" node returns to primary state.") click.echo(" node returns to primary state.")
click.echo() click.echo()
retcode, retmsg = pvc_node.node_coordinator_state(config, node, 'secondary') retcode, retmsg = pvc_node.node_coordinator_state(config, node, 'secondary', wait)
cleanup(retcode, retmsg) cleanup(retcode, retmsg)
############################################################################### ###############################################################################
@ -370,7 +374,11 @@ def node_secondary(node):
@click.argument( @click.argument(
'node' 'node'
) )
def node_primary(node): @click.option(
'-w', '--wait', 'wait', is_flag=True, default=False,
help='Wait for transition to complete before returning.'
)
def node_primary(node, wait):
""" """
Put NODE into primary router mode. Put NODE into primary router mode.
""" """
@ -382,7 +390,7 @@ def node_primary(node):
click.echo(" node returns to primary state.") click.echo(" node returns to primary state.")
click.echo() click.echo()
retcode, retmsg = pvc_node.node_coordinator_state(config, node, 'primary') retcode, retmsg = pvc_node.node_coordinator_state(config, node, 'primary', wait)
cleanup(retcode, retmsg) cleanup(retcode, retmsg)
############################################################################### ###############################################################################

View File

@ -89,7 +89,7 @@ def getNodeInformation(zk_conn, node_name):
# #
# Direct Functions # Direct Functions
# #
def secondary_node(zk_conn, node): def secondary_node(zk_conn, node, wait=False):
# Verify node is valid # Verify node is valid
if not common.verifyNode(zk_conn, node): if not common.verifyNode(zk_conn, node):
return False, 'ERROR: No node named "{}" is present in the cluster.'.format(node) return False, 'ERROR: No node named "{}" is present in the cluster.'.format(node)
@ -111,12 +111,21 @@ def secondary_node(zk_conn, node):
zkhandler.writedata(zk_conn, { zkhandler.writedata(zk_conn, {
'/primary_node': 'none' '/primary_node': 'none'
}) })
if wait:
# Wait 1 second for lock acquisition
time.sleep(1)
# Set up and block on a write lock of /primary_node
transition_lock = zkhandler.writelock(zk_conn, '/primary_node')
transition_lock.acquire()
transition_lock.release()
retmsg = 'Set node {} in secondary router mode.'.format(node)
else: else:
return False, 'Node "{}" is already in secondary router mode.'.format(node) return False, 'Node "{}" is already in secondary router mode.'.format(node)
return True, retmsg return True, retmsg
def primary_node(zk_conn, node): def primary_node(zk_conn, node, wait=False):
# Verify node is valid # Verify node is valid
if not common.verifyNode(zk_conn, node): if not common.verifyNode(zk_conn, node):
return False, 'ERROR: No node named "{}" is present in the cluster.'.format(node) return False, 'ERROR: No node named "{}" is present in the cluster.'.format(node)
@ -138,6 +147,15 @@ def primary_node(zk_conn, node):
zkhandler.writedata(zk_conn, { zkhandler.writedata(zk_conn, {
'/primary_node': node '/primary_node': node
}) })
if wait:
# Wait 1 second for lock acquisition
time.sleep(1)
# Set up and block on a write lock of /primary_node
transition_lock = zkhandler.writelock(zk_conn, '/primary_node')
transition_lock.acquire()
transition_lock.release()
retmsg = 'Set node {} in primary router mode.'.format(node)
else: else:
return False, 'Node "{}" is already in primary router mode.'.format(node) return False, 'Node "{}" is already in primary router mode.'.format(node)