def requestIdentification(self, conn, node_type, uuid, address, name): self.checkClusterName(name) app = self.app node = app.nm.getByUUID(uuid) if node: assert node_type is not NodeTypes.MASTER or node.getAddress() in ( address, None), (node, address) if node.isBroken(): raise BrokenNodeDisallowedError else: node = app.nm.getByAddress(address) peer_uuid = self._setupNode(conn, node_type, uuid, address, node) if app.primary: primary_address = app.server elif app.primary_master_node is not None: primary_address = app.primary_master_node.getAddress() else: primary_address = None known_master_list = [(app.server, app.uuid)] for n in app.nm.getMasterList(): if n.isBroken(): continue known_master_list.append((n.getAddress(), n.getUUID())) conn.answer( Packets.AcceptIdentification(NodeTypes.MASTER, app.uuid, app.pt.getPartitions(), app.pt.getReplicas(), peer_uuid, primary_address, known_master_list), )
def requestIdentification(self, conn, node_type, uuid, address, name, *_): if node_type != NodeTypes.ADMIN: raise ProtocolError("reject non-admin node") app = self.app try: backup = app.backup_dict[name] except KeyError: raise ProtocolError("unknown backup cluster %r" % name) if backup.conn is not None: raise ProtocolError("already connected") backup.conn = conn conn.setHandler(app.backup_handler) conn.answer(Packets.AcceptIdentification(NodeTypes.ADMIN, None, None))
def requestIdentification(self, conn, node_type, uuid, address, name): self.checkClusterName(name) # reject any incoming connections if not ready if not self.app.ready: raise NotReadyError app = self.app if uuid is None: if node_type != NodeTypes.STORAGE: raise ProtocolError('reject anonymous non-storage node') handler = StorageOperationHandler(self.app) conn.setHandler(handler) else: if uuid == app.uuid: raise ProtocolError("uuid conflict or loopback connection") node = app.nm.getByUUID(uuid) # If this node is broken, reject it. if node is not None and node.isBroken(): raise BrokenNodeDisallowedError # choose the handler according to the node type if node_type == NodeTypes.CLIENT: handler = ClientOperationHandler if node is None: node = app.nm.createClient(uuid=uuid) elif node.isConnected(): # This can happen if we haven't processed yet a notification # from the master, telling us the existing node is not # running anymore. If we accept the new client, we won't # know what to do with this late notification. raise NotReadyError('uuid conflict: retry later') node.setRunning() elif node_type == NodeTypes.STORAGE: if node is None: logging.error('reject an unknown storage node %s', uuid_str(uuid)) raise NotReadyError handler = StorageOperationHandler else: raise ProtocolError('reject non-client-or-storage node') # apply the handler and set up the connection handler = handler(self.app) conn.setHandler(handler) node.setConnection(conn, app.uuid < uuid) # accept the identification and trigger an event conn.answer( Packets.AcceptIdentification(NodeTypes.STORAGE, uuid and app.uuid, app.pt.getPartitions(), app.pt.getReplicas(), uuid, app.master_node.getAddress(), ())) handler.connectionCompleted(conn)
def requestIdentification(self, conn, node_type, uuid, address, name, id_timestamp): self.checkClusterName(name) app = self.app # reject any incoming connections if not ready if not app.operational: raise NotReadyError if uuid is None: if node_type != NodeTypes.STORAGE: raise ProtocolError('reject anonymous non-storage node') handler = StorageOperationHandler(self.app) conn.setHandler(handler) else: if uuid == app.uuid: raise ProtocolError("uuid conflict or loopback connection") node = app.nm.getByUUID(uuid, id_timestamp) # choose the handler according to the node type if node_type == NodeTypes.CLIENT: if app.dm.getBackupTID(): handler = ClientReadOnlyOperationHandler else: handler = ClientOperationHandler assert not node.isConnected(), node assert node.isRunning(), node elif node_type == NodeTypes.STORAGE: handler = StorageOperationHandler else: raise ProtocolError('reject non-client-or-storage node') # apply the handler and set up the connection handler = handler(self.app) conn.setHandler(handler) node.setConnection(conn, app.uuid < uuid) # accept the identification and trigger an event conn.answer( Packets.AcceptIdentification(NodeTypes.STORAGE, uuid and app.uuid, app.pt.getPartitions(), app.pt.getReplicas(), uuid)) handler.connectionCompleted(conn)
def requestIdentification(self, conn, node_type, uuid, address, name, id_timestamp, extra): app = self.app self.checkClusterName(name) if address == app.server: raise ProtocolError('address conflict') node = app.nm.getByUUID(uuid) by_addr = address and app.nm.getByAddress(address) while 1: if by_addr: if not by_addr.isIdentified(): if node is by_addr: break if not node or uuid < 0: # In case of address conflict for a peer with temporary # ids, we'll generate a new id. node = by_addr break elif node: if node.isIdentified(): if uuid < 0: # The peer wants a temporary id that's already assigned. # Let's give it another one. node = uuid = None break else: if node is app._node: node = None else: node.setAddress(address) break # Id conflict for a storage node. else: break # cloned/evil/buggy node connecting to us raise ProtocolError('already connected') new_nid = extra.pop('new_nid', None) state = NodeStates.RUNNING if node_type == NodeTypes.CLIENT: if app.cluster_state == ClusterStates.RUNNING: handler = app.client_service_handler elif app.cluster_state == ClusterStates.BACKINGUP: handler = app.client_ro_service_handler else: raise NotReadyError human_readable_node_type = ' client ' elif node_type == NodeTypes.STORAGE: if app.cluster_state == ClusterStates.STOPPING_BACKUP: raise NotReadyError manager = app._current_manager if manager is None: manager = app state, handler = manager.identifyStorageNode(uuid is not None and node is not None) if not address: if app.cluster_state == ClusterStates.RECOVERING: raise NotReadyError if uuid or not new_nid: raise ProtocolError state = NodeStates.DOWN # We'll let the storage node close the connection. If we # aborted it at the end of the method, BootstrapManager # (which is used by storage nodes) could see the closure # and try to reconnect to a master. human_readable_node_type = ' storage (%s) ' % (state, ) elif node_type == NodeTypes.MASTER: if app.election: if id_timestamp and \ (id_timestamp, address) < (app.election, app.server): raise PrimaryElected( by_addr or app.nm.createMaster(address=address)) handler = app.election_handler else: handler = app.secondary_handler human_readable_node_type = ' master ' elif node_type == NodeTypes.ADMIN: handler = app.administration_handler human_readable_node_type = 'n admin ' else: raise ProtocolError uuid = app.getNewUUID(uuid, address, node_type) logging.info('Accept a' + human_readable_node_type + uuid_str(uuid)) if node is None: node = app.nm.createFromNodeType(node_type, uuid=uuid, address=address) else: node.setUUID(uuid) node.extra = extra node.id_timestamp = monotonic_time() node.setState(state) app.broadcastNodesInformation([node]) if new_nid: changed_list = [] for offset in new_nid: changed_list.append((offset, uuid, CellStates.OUT_OF_DATE)) app.pt._setCell(offset, node, CellStates.OUT_OF_DATE) app.broadcastPartitionChanges(changed_list) conn.setHandler(handler) node.setConnection(conn, not node.isIdentified()) conn.answer( Packets.AcceptIdentification(NodeTypes.MASTER, app.uuid, uuid)) handler._notifyNodeInformation(conn) handler.handlerSwitched(conn, True)
def requestIdentification(self, conn, node_type, uuid, address, name, id_timestamp): app = self.app self.checkClusterName(name) if address == app.server: raise ProtocolError('address conflict') node = app.nm.getByUUID(uuid) by_addr = address and app.nm.getByAddress(address) while 1: if by_addr: if not by_addr.isIdentified(): if node is by_addr: break if not node or uuid < 0: # In case of address conflict for a peer with temporary # ids, we'll generate a new id. node = by_addr break elif node: if node.isIdentified(): if uuid < 0: # The peer wants a temporary id that's already assigned. # Let's give it another one. node = uuid = None break else: if node is app._node: node = None else: node.setAddress(address) break # Id conflict for a storage node. else: break # cloned/evil/buggy node connecting to us raise ProtocolError('already connected') state = NodeStates.RUNNING if node_type == NodeTypes.CLIENT: if app.cluster_state == ClusterStates.RUNNING: handler = app.client_service_handler elif app.cluster_state == ClusterStates.BACKINGUP: handler = app.client_ro_service_handler else: raise NotReadyError human_readable_node_type = ' client ' elif node_type == NodeTypes.STORAGE: if app.cluster_state == ClusterStates.STOPPING_BACKUP: raise NotReadyError manager = app._current_manager if manager is None: manager = app state, handler = manager.identifyStorageNode( uuid is not None and node is not None) human_readable_node_type = ' storage (%s) ' % (state, ) elif node_type == NodeTypes.MASTER: if app.election: if id_timestamp and \ (id_timestamp, address) < (app.election, app.server): raise PrimaryElected(by_addr or app.nm.createMaster(address=address)) handler = app.election_handler else: handler = app.secondary_handler human_readable_node_type = ' master ' elif node_type == NodeTypes.ADMIN: handler = app.administration_handler human_readable_node_type = 'n admin ' else: raise ProtocolError uuid = app.getNewUUID(uuid, address, node_type) logging.info('Accept a' + human_readable_node_type + uuid_str(uuid)) if node is None: node = app.nm.createFromNodeType(node_type, uuid=uuid, address=address) else: node.setUUID(uuid) node.id_timestamp = monotonic_time() node.setState(state) conn.setHandler(handler) node.setConnection(conn, not node.isIdentified()) app.broadcastNodesInformation([node], node) conn.answer(Packets.AcceptIdentification( NodeTypes.MASTER, app.uuid, app.pt.getPartitions(), app.pt.getReplicas(), uuid)) handler._notifyNodeInformation(conn) handler.connectionCompleted(conn, True)