def get_frontend_node(self): """Returns the first node of the class specified in the configuration file as `ssh_to`, or the first node of the first class in alphabetic order. :return: :py:class:`Node` :raise: :py:class:`elasticluster.exceptions.NodeNotFound` if no valid frontend node is found """ if self.ssh_to: if self.ssh_to in self.nodes: cls = self.nodes[self.ssh_to] if cls: return cls[0] else: log.warning( "preferred `ssh_to` `%s` is empty: unable to " "get the choosen frontend node from that class.", self.ssh_to) else: raise NodeNotFound( "Invalid ssh_to `%s`. Please check your " "configuration file." % self.ssh_to) # If we reach this point, the preferred class was empty. Pick # one using the default logic. for cls in sorted(self.nodes.keys()): if self.nodes[cls]: return self.nodes[cls][0] # Uh-oh, no nodes in this cluster. raise NodeNotFound("Unable to find a valid frontend: " "cluster has no nodes!")
def remove_node(self, node, stop=False): """Removes a node from the cluster. By default, it doesn't also stop the node, just remove from the known hosts of this cluster. :param node: node to remove :type node: :py:class:`Node` :param stop: Stop the node :type stop: bool """ if node.kind not in self.nodes: raise NodeNotFound( "Unable to remove node %s: invalid node type `%s`.", node.name, node.kind) else: try: index = self.nodes[node.kind].index(node) if self.nodes[node.kind][index]: del self.nodes[node.kind][index] if stop: node.stop() self._naming_policy.free(node.kind, node.name) self.repository.save_or_update(self) except ValueError: raise NodeNotFound("Node %s not found in cluster" % node.name)
def get_node_by_name(self, nodename): """Return the node corresponding with name `nodename` :params nodename: Name of the node :type nodename: str """ nodes = dict((n.name, n) for n in self.get_all_nodes()) try: return nodes[nodename] except KeyError: raise NodeNotFound("Node %s not found" % nodename)
def get_ssh_to_node(self, ssh_to=None): """ Return target node for SSH/SFTP connections. The target node is the first node of the class specified in the configuration file as ``ssh_to`` (but argument ``ssh_to`` can override this choice). If not ``ssh_to`` has been specified in this cluster's config, then try node class names ``ssh``, ``login``, ``frontend``, and ``master``: if any of these is non-empty, return the first node. If all else fails, return the first node of the first class (in alphabetic order). :return: :py:class:`Node` :raise: :py:class:`elasticluster.exceptions.NodeNotFound` if no valid frontend node is found """ if ssh_to is None: ssh_to = self.ssh_to # first try to interpret `ssh_to` as a node name if ssh_to: try: return self.get_node_by_name(ssh_to) except NodeNotFound: pass # next, ensure `ssh_to` is a class name if ssh_to: try: parts = self._naming_policy.parse(ssh_to) log.warning( "Node `%s` not found." " Trying to find other node in class `%s` ...", ssh_to, parts['kind']) ssh_to = parts['kind'] except ValueError: # it's already a class name pass # try getting first node of kind `ssh_to` if ssh_to: try: nodes = self.nodes[ssh_to] except KeyError: raise ConfigurationError( "Invalid configuration item `ssh_to={ssh_to}` in cluster `{name}`:" " node class `{ssh_to}` does not exist in this cluster.". format(ssh_to=ssh_to, name=self.name)) try: return nodes[0] except IndexError: log.warning( "Chosen `ssh_to` class `%s` is empty: unable to " "get the choosen frontend node from that class.", ssh_to) # If we reach this point, `ssh_to` was not set or the # preferred class was empty. Try "natural" `ssh_to` values. for kind in ['ssh', 'login', 'frontend', 'master']: try: nodes = self.nodes[kind] return nodes[0] except (KeyError, IndexError): pass # ... if all else fails, return first node for kind in sorted(self.nodes.keys()): if self.nodes[kind]: return self.nodes[kind][0] # Uh-oh, no nodes in this cluster! raise NodeNotFound("Unable to find a valid frontend:" " cluster has no nodes!")