예제 #1
0
    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!")
예제 #2
0
    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)
예제 #3
0
    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)
예제 #4
0
    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!")