Пример #1
0
    def add_node(self, node_list, lb_id, current_timestamp):
        """
        Returns the canned response for add nodes
        """
        if lb_id in self.lbs:

            _verify_and_update_lb_state(self, lb_id, False, current_timestamp)

            if self.lbs[lb_id]["status"] != "ACTIVE":
                resource = invalid_resource(
                    "Load Balancer '{0}' has a status of {1} and is considered "
                    "immutable.".format(lb_id, self.lbs[lb_id]["status"]), 422)
                return (resource, 422)

            nodes = _format_nodes_on_lb(node_list)

            if self.lbs[lb_id].get("nodes"):
                for existing_node in self.lbs[lb_id]["nodes"]:
                    for new_node in node_list:
                        if (existing_node["address"] == new_node["address"] and
                                existing_node["port"] == new_node["port"]):
                            resource = invalid_resource(
                                "Duplicate nodes detected. One or more nodes "
                                "already configured on load balancer.", 413)
                            return (resource, 413)

                self.lbs[lb_id]["nodes"] = self.lbs[lb_id]["nodes"] + nodes
            else:
                self.lbs[lb_id]["nodes"] = nodes
                self.lbs[lb_id]["nodeCount"] = len(self.lbs[lb_id]["nodes"])
                _verify_and_update_lb_state(self, lb_id,
                                            current_timestamp=current_timestamp)
            return {"nodes": nodes}, 202

        return not_found_response("loadbalancer"), 404
Пример #2
0
    def delete_node(self, lb_id, node_id, current_timestamp):
        """
        Determines whether the node to be deleted exists in the session store,
        deletes the node, and returns the response code.
        """
        if lb_id in self.lbs:

            _verify_and_update_lb_state(self, lb_id, False, current_timestamp)

            if self.lbs[lb_id]["status"] != "ACTIVE":
                # Error message verified as of 2015-04-22
                resource = invalid_resource(
                    "Load Balancer '{0}' has a status of '{1}' and is considered "
                    "immutable.".format(lb_id, self.lbs[lb_id]["status"]), 422)
                return (resource, 422)

            _verify_and_update_lb_state(self, lb_id,
                                        current_timestamp=current_timestamp)

            if _delete_node(self, lb_id, node_id):
                return None, 202
            else:
                return not_found_response("node"), 404

        return not_found_response("loadbalancer"), 404
Пример #3
0
    def del_load_balancer(self, lb_id, current_timestamp):
        """
        Returns response for a load balancer
         is in building status for 20
        seconds and response code 202, and adds the new lb to ``self.lbs``.
        A loadbalancer, on delete, goes into PENDING-DELETE and remains in DELETED
        status until a nightly job(maybe?)
        """
        if lb_id in self.lbs:

            if self.lbs[lb_id]["status"] == "PENDING-DELETE":
                msg = ("Must provide valid load balancers: {0} are immutable and "
                       "could not be processed.".format(lb_id))
                # Dont doubt this to be 422, it is 400!
                return invalid_resource(msg, 400), 400

            _verify_and_update_lb_state(self, lb_id, True, current_timestamp)

            if any([self.lbs[lb_id]["status"] == "ACTIVE",
                    self.lbs[lb_id]["status"] == "ERROR",
                    self.lbs[lb_id]["status"] == "PENDING-UPDATE"]):
                del self.lbs[lb_id]
                return EMPTY_RESPONSE, 202

            if self.lbs[lb_id]["status"] == "PENDING-DELETE":
                return EMPTY_RESPONSE, 202

            if self.lbs[lb_id]["status"] == "DELETED":
                _verify_and_update_lb_state(self, lb_id,
                                            current_timestamp=current_timestamp)
                msg = "Must provide valid load balancers: {0} could not be found.".format(lb_id)
                # Dont doubt this to be 422, it is 400!
                return invalid_resource(msg, 400), 400

        return not_found_response("loadbalancer"), 404
Пример #4
0
    def delete_node(self, lb_id, node_id):
        """
        Determines whether the node to be deleted exists in the session store,
        deletes the node, and returns the response code.
        """
        current_timestamp = self.clock.seconds()
        if lb_id in self.lbs:

            _verify_and_update_lb_state(self, lb_id, False, current_timestamp)

            if self.lbs[lb_id]["status"] != "ACTIVE":
                # Error message verified as of 2015-04-22
                return considered_immutable_error(self.lbs[lb_id]["status"],
                                                  lb_id)

            _verify_and_update_lb_state(self,
                                        lb_id,
                                        current_timestamp=current_timestamp)

            if _delete_node(self, lb_id, node_id):
                return None, 202
            else:
                return not_found_response("node"), 404

        return not_found_response("loadbalancer"), 404
Пример #5
0
 def get_load_balancers(self, lb_id):
     """
     Returns the load balancers with the given lb id, with response
     code 200. If no load balancers are found returns 404.
     """
     if lb_id in self.lbs:
         _verify_and_update_lb_state(self, lb_id, False,
                                     self.clock.seconds())
         log.msg(self.lbs[lb_id]["status"])
         return {'loadBalancer': self.lbs[lb_id].full_json()}, 200
     return not_found_response("loadbalancer"), 404
Пример #6
0
 def get_load_balancers(self, lb_id, current_timestamp):
     """
     Returns the load balancers with the given lb id, with response
     code 200. If no load balancers are found returns 404.
     """
     if lb_id in self.lbs:
         _verify_and_update_lb_state(self, lb_id, False, current_timestamp)
         log.msg(self.lbs[lb_id]["status"])
         new_lb = _lb_without_tenant(self, lb_id)
         return {'loadBalancer': new_lb}, 200
     return not_found_response("loadbalancer"), 404
Пример #7
0
 def get_load_balancers(self, lb_id):
     """
     Returns the load balancers with the given lb id, with response
     code 200. If no load balancers are found returns 404.
     """
     if lb_id in self.lbs:
         _verify_and_update_lb_state(self, lb_id, False,
                                     self.clock.seconds())
         log.msg(self.lbs[lb_id]["status"])
         return {'loadBalancer': self.lbs[lb_id].full_json()}, 200
     return not_found_response("loadbalancer"), 404
Пример #8
0
    def update_node(self, lb_id, node_id, node_updates):
        """
        Update the weight, condition, or type of a single node.  The IP, port,
        status, and ID are immutable, and attempting to change them will cause
        a 400 response to be returned.

        All success and error behavior verified as of 2016-06-16.

        :param str lb_id: the load balancer ID
        :param str node_id: the node ID to update
        :param dict node_updates: The JSON dictionary containing node
            attributes to update
        :param current_timestamp: What the current time is

        :return: a `tuple` of (json response as a dict, http status code)
        """
        # first, store whether address and port were provided - if they were
        # that's a validation error not a schema error
        things_wrong = dict([(k, True) for k in ("address", "port", "id")
                             if k in node_updates])
        node_updates = dict([(k, v) for k, v in node_updates.items()
                             if k not in ("address", "port")])
        # use the Node.from_json to check the schema
        try:
            Node.from_json(dict(address="1.1.1.1", port=80, **node_updates))
        except (TypeError, ValueError):
            return invalid_json_schema()

        # handle the possible validation (as opposed to schema) errors
        if not 1 <= node_updates.get('weight', 1) <= 100:
            things_wrong["weight"] = True
        if things_wrong:
            return updating_node_validation_error(**things_wrong)

        # Now, finally, check if the LB exists and node exists
        if lb_id in self.lbs:
            _verify_and_update_lb_state(self, lb_id, False,
                                        self.clock.seconds())

            if self.lbs[lb_id]["status"] != "ACTIVE":
                return considered_immutable_error(self.lbs[lb_id]["status"],
                                                  lb_id)

            for i, node in enumerate(self.lbs[lb_id].nodes):
                if node.id == node_id:
                    params = attr.asdict(node)
                    params.update(node_updates)
                    self.lbs[lb_id].nodes[i] = Node(**params)
                    return ("", 202)

            return node_not_found()

        return loadbalancer_not_found()
Пример #9
0
    def update_node(self, lb_id, node_id, node_updates):
        """
        Update the weight, condition, or type of a single node.  The IP, port,
        status, and ID are immutable, and attempting to change them will cause
        a 400 response to be returned.

        All success and error behavior verified as of 2016-06-16.

        :param str lb_id: the load balancer ID
        :param str node_id: the node ID to update
        :param dict node_updates: The JSON dictionary containing node
            attributes to update
        :param current_timestamp: What the current time is

        :return: a `tuple` of (json response as a dict, http status code)
        """
        # first, store whether address and port were provided - if they were
        # that's a validation error not a schema error
        things_wrong = dict([(k, True) for k in ("address", "port", "id")
                             if k in node_updates])
        node_updates = dict([(k, v) for k, v in node_updates.items()
                             if k not in ("address", "port")])
        # use the Node.from_json to check the schema
        try:
            Node.from_json(dict(address="1.1.1.1", port=80, **node_updates))
        except (TypeError, ValueError):
            return invalid_json_schema()

        # handle the possible validation (as opposed to schema) errors
        if not 1 <= node_updates.get('weight', 1) <= 100:
            things_wrong["weight"] = True
        if things_wrong:
            return updating_node_validation_error(**things_wrong)

        # Now, finally, check if the LB exists and node exists
        if lb_id in self.lbs:
            _verify_and_update_lb_state(self, lb_id, False,
                                        self.clock.seconds())

            if self.lbs[lb_id]["status"] != "ACTIVE":
                return considered_immutable_error(
                    self.lbs[lb_id]["status"], lb_id)

            for i, node in enumerate(self.lbs[lb_id].nodes):
                if node.id == node_id:
                    params = attr.asdict(node)
                    params.update(node_updates)
                    self.lbs[lb_id].nodes[i] = Node(**params)
                    return ("", 202)

            return node_not_found()

        return loadbalancer_not_found()
Пример #10
0
    def delete_nodes(self, lb_id, node_ids):
        """
        Bulk-delete multiple LB nodes.
        """
        if not node_ids:
            resp = {
                "message":
                "Must supply one or more id's to process this request.",
                "code": 400
            }
            return resp, 400

        if lb_id not in self.lbs:
            return not_found_response("loadbalancer"), 404

        current_timestamp = self.clock.seconds()
        _verify_and_update_lb_state(self, lb_id, False, current_timestamp)

        if self.lbs[lb_id]["status"] != "ACTIVE":
            # Error message verified as of 2015-04-22
            resp = {"message": "LoadBalancer is not ACTIVE", "code": 422}
            return resp, 422

        # We need to verify all the deletions up front, and only allow it through
        # if all of them are valid.
        all_ids = [node.id for node in self.lbs[lb_id].nodes]
        non_nodes = set(node_ids).difference(all_ids)
        if non_nodes:
            nodes = ','.join(map(str, non_nodes))
            resp = {
                "validationErrors": {
                    "messages": [
                        "Node ids {0} are not a part of your loadbalancer".
                        format(nodes)
                    ]
                },
                "message": "Validation Failure",
                "code": 400,
                "details": "The object is not valid"
            }
            return resp, 400

        for node_id in node_ids:
            # It should not be possible for this to fail, since we've already
            # checked that they all exist.
            assert _delete_node(self, lb_id, node_id) is True

        _verify_and_update_lb_state(self,
                                    lb_id,
                                    current_timestamp=current_timestamp)
        return EMPTY_RESPONSE, 202
Пример #11
0
    def list_load_balancers(self):
        """
        Returns the list of load balancers with the given tenant id with response
        code 200. If no load balancers are found returns empty list.

        :return: A 2-tuple, containing the HTTP response and code, in that order.
        """
        for each in self.lbs:
            _verify_and_update_lb_state(self, each, False,
                                        self.clock.seconds())
            log.msg(self.lbs[each]["status"])
        return (
            {'loadBalancers': [lb.short_json() for lb in self.lbs.values()]},
            200)
Пример #12
0
    def list_load_balancers(self):
        """
        Returns the list of load balancers with the given tenant id with response
        code 200. If no load balancers are found returns empty list.

        :return: A 2-tuple, containing the HTTP response and code, in that order.
        """
        for each in self.lbs:
            _verify_and_update_lb_state(self, each, False,
                                        self.clock.seconds())
            log.msg(self.lbs[each]["status"])
        return ({
            'loadBalancers': [lb.short_json() for lb in self.lbs.values()]
        }, 200)
Пример #13
0
    def delete_nodes(self, lb_id, node_ids):
        """
        Bulk-delete multiple LB nodes.
        """
        if not node_ids:
            resp = {
                "message": "Must supply one or more id's to process this request.",
                "code": 400}
            return resp, 400

        if lb_id not in self.lbs:
            return not_found_response("loadbalancer"), 404

        current_timestamp = self.clock.seconds()
        _verify_and_update_lb_state(self, lb_id, False, current_timestamp)

        if self.lbs[lb_id]["status"] != "ACTIVE":
            # Error message verified as of 2015-04-22
            resp = {"message": "LoadBalancer is not ACTIVE",
                    "code": 422}
            return resp, 422

        # We need to verify all the deletions up front, and only allow it through
        # if all of them are valid.
        all_ids = [node.id for node in self.lbs[lb_id].nodes]
        non_nodes = set(node_ids).difference(all_ids)
        if non_nodes:
            nodes = ','.join(map(str, non_nodes))
            resp = {
                "validationErrors": {
                    "messages": [
                        "Node ids {0} are not a part of your loadbalancer".format(nodes)
                    ]
                },
                "message": "Validation Failure",
                "code": 400,
                "details": "The object is not valid"}
            return resp, 400

        for node_id in node_ids:
            # It should not be possible for this to fail, since we've already
            # checked that they all exist.
            assert _delete_node(self, lb_id, node_id) is True

        _verify_and_update_lb_state(self, lb_id,
                                    current_timestamp=current_timestamp)
        return EMPTY_RESPONSE, 202
Пример #14
0
    def add_node(self, node_list, lb_id):
        """
        Add one or more nodes to a load balancer.  Fails if one or more of the
        nodes provided has the same address/port as an existing node.  Also
        fails if adding the nodes would exceed the maximum number of nodes on
        the CLB.

        :param list node_list: a `list` of `dict` containing specification for
            nodes

        :return: a `tuple` of (json response as a dict, http status code)
        """
        if lb_id in self.lbs:
            current_timestamp = self.clock.seconds()
            _verify_and_update_lb_state(self, lb_id, False, current_timestamp)

            if self.lbs[lb_id]["status"] != "ACTIVE":
                return considered_immutable_error(self.lbs[lb_id]["status"],
                                                  lb_id)

            nodes = [Node.from_json(blob) for blob in node_list]

            for existing_node in self.lbs[lb_id].nodes:
                for new_node in nodes:
                    if existing_node.same_as(new_node):
                        resource = invalid_resource(
                            "Duplicate nodes detected. One or more nodes "
                            "already configured on load balancer.", 413)
                        return (resource, 413)

            # If there were no duplicates
            new_nodeCount = len(self.lbs[lb_id].nodes) + len(nodes)
            if new_nodeCount <= self.node_limit:
                self.lbs[lb_id].nodes = self.lbs[lb_id].nodes + nodes
            else:
                resource = invalid_resource(
                    "Nodes must not exceed {0} "
                    "per load balancer.".format(self.node_limit), 413)
                return (resource, 413)

            _verify_and_update_lb_state(self,
                                        lb_id,
                                        current_timestamp=current_timestamp)
            return {"nodes": [node.as_json() for node in nodes]}, 202

        return not_found_response("loadbalancer"), 404
Пример #15
0
    def list_nodes(self, lb_id, current_timestamp):
        """
        Returns the list of nodes remaining on the load balancer
        """
        if lb_id in self.lbs:
            _verify_and_update_lb_state(self, lb_id, False, current_timestamp)
            if lb_id not in self.lbs:
                return not_found_response("loadbalancer"), 404

            if self.lbs[lb_id]["status"] == "DELETED":
                return invalid_resource("The loadbalancer is marked as deleted.", 410), 410
            node_list = []
            if self.lbs[lb_id].get("nodes"):
                node_list = self.lbs[lb_id]["nodes"]
            return {"nodes": node_list}, 200
        else:
            return not_found_response("loadbalancer"), 404
Пример #16
0
    def add_node(self, node_list, lb_id):
        """
        Add one or more nodes to a load balancer.  Fails if one or more of the
        nodes provided has the same address/port as an existing node.  Also
        fails if adding the nodes would exceed the maximum number of nodes on
        the CLB.

        :param list node_list: a `list` of `dict` containing specification for
            nodes

        :return: a `tuple` of (json response as a dict, http status code)
        """
        if lb_id in self.lbs:
            current_timestamp = self.clock.seconds()
            _verify_and_update_lb_state(self, lb_id, False, current_timestamp)

            if self.lbs[lb_id]["status"] != "ACTIVE":
                return considered_immutable_error(
                    self.lbs[lb_id]["status"], lb_id)

            nodes = [Node.from_json(blob) for blob in node_list]

            for existing_node in self.lbs[lb_id].nodes:
                for new_node in nodes:
                    if existing_node.same_as(new_node):
                        resource = invalid_resource(
                            "Duplicate nodes detected. One or more nodes "
                            "already configured on load balancer.", 413)
                        return (resource, 413)

            # If there were no duplicates
            new_nodeCount = len(self.lbs[lb_id].nodes) + len(nodes)
            if new_nodeCount <= self.node_limit:
                self.lbs[lb_id].nodes = self.lbs[lb_id].nodes + nodes
            else:
                resource = invalid_resource(
                    "Nodes must not exceed {0} "
                    "per load balancer.".format(self.node_limit), 413)
                return (resource, 413)

            _verify_and_update_lb_state(self, lb_id,
                                        current_timestamp=current_timestamp)
            return {"nodes": [node.as_json() for node in nodes]}, 202

        return not_found_response("loadbalancer"), 404
Пример #17
0
    def get_nodes(self, lb_id, node_id):
        """
        Returns the node on the load balancer
        """
        if lb_id in self.lbs:
            _verify_and_update_lb_state(self, lb_id, False,
                                        self.clock.seconds())

            if self.lbs[lb_id]["status"] == "DELETED":
                return (invalid_resource(
                    "The loadbalancer is marked as deleted.", 410), 410)

            for each in self.lbs[lb_id].nodes:
                if node_id == each.id:
                    return {"node": each.as_json()}, 200

            return not_found_response("node"), 404

        return not_found_response("loadbalancer"), 404
Пример #18
0
    def list_nodes(self, lb_id):
        """
        Returns the list of nodes remaining on the load balancer
        """
        if lb_id in self.lbs:
            _verify_and_update_lb_state(self, lb_id, False,
                                        self.clock.seconds())
            if lb_id not in self.lbs:
                return not_found_response("loadbalancer"), 404

            if self.lbs[lb_id]["status"] == "DELETED":
                return invalid_resource(
                    "The loadbalancer is marked as deleted.", 410), 410

            node_list = [node.as_json() for node in self.lbs[lb_id].nodes]

            return {"nodes": node_list}, 200
        else:
            return not_found_response("loadbalancer"), 404
Пример #19
0
    def list_nodes(self, lb_id):
        """
        Returns the list of nodes remaining on the load balancer
        """
        if lb_id in self.lbs:
            _verify_and_update_lb_state(self, lb_id, False,
                                        self.clock.seconds())
            if lb_id not in self.lbs:
                return not_found_response("loadbalancer"), 404

            if self.lbs[lb_id]["status"] == "DELETED":
                return invalid_resource("The loadbalancer is marked as deleted.", 410), 410

            node_list = [node.as_json()
                         for node in self.lbs[lb_id].nodes]

            return {"nodes": node_list}, 200
        else:
            return not_found_response("loadbalancer"), 404
Пример #20
0
    def get_nodes(self, lb_id, node_id, current_timestamp):
        """
        Returns the node on the load balancer
        """
        if lb_id in self.lbs:
            _verify_and_update_lb_state(self, lb_id, False, current_timestamp)

            if self.lbs[lb_id]["status"] == "DELETED":
                return (
                    invalid_resource(
                        "The loadbalancer is marked as deleted.", 410),
                    410)

            if self.lbs[lb_id].get("nodes"):
                for each in self.lbs[lb_id]["nodes"]:
                    if node_id == each["id"]:
                        return {"node": each}, 200
            return not_found_response("node"), 404

        return not_found_response("loadbalancer"), 404
Пример #21
0
    def list_load_balancers(self, tenant_id, current_timestamp):
        """
        Returns the list of load balancers with the given tenant id with response
        code 200. If no load balancers are found returns empty list.
        :param string tenant_id: The tenant which owns the load balancers.
        :param float current_timestamp: The current time, in seconds since epoch.

        :return: A 2-tuple, containing the HTTP response and code, in that order.
        """
        response = dict(
            (k, v) for (k, v) in self.lbs.items()
            if tenant_id == v['tenant_id']
        )
        for each in response:
            _verify_and_update_lb_state(self, each, False, current_timestamp)
            log.msg(self.lbs[each]["status"])
        updated_resp = dict(
            (k, v) for (k, v) in self.lbs.items()
            if tenant_id == v['tenant_id']
        )
        return {'loadBalancers': _prep_for_list(updated_resp.values()) or []}, 200
Пример #22
0
    def get_nodes(self, lb_id, node_id):
        """
        Returns the node on the load balancer
        """
        if lb_id in self.lbs:
            _verify_and_update_lb_state(self, lb_id, False,
                                        self.clock.seconds())

            if self.lbs[lb_id]["status"] == "DELETED":
                return (
                    invalid_resource(
                        "The loadbalancer is marked as deleted.", 410),
                    410)

            for each in self.lbs[lb_id].nodes:
                if node_id == each.id:
                    return {"node": each.as_json()}, 200

            return not_found_response("node"), 404

        return not_found_response("loadbalancer"), 404
Пример #23
0
    def del_load_balancer(self, lb_id):
        """
        Returns response for a load balancer
         is in building status for 20
        seconds and response code 202, and adds the new lb to ``self.lbs``.
        A loadbalancer, on delete, goes into PENDING-DELETE and remains in DELETED
        status until a nightly job(maybe?)
        """
        if lb_id in self.lbs:
            current_timestamp = self.clock.seconds()

            if self.lbs[lb_id]["status"] == "PENDING-DELETE":
                msg = (
                    "Must provide valid load balancers: {0} are immutable and "
                    "could not be processed.".format(lb_id))
                # Dont doubt this to be 422, it is 400!
                return invalid_resource(msg, 400), 400

            _verify_and_update_lb_state(self, lb_id, True, current_timestamp)

            if any([
                    self.lbs[lb_id]["status"] == "ACTIVE",
                    self.lbs[lb_id]["status"] == "ERROR",
                    self.lbs[lb_id]["status"] == "PENDING-UPDATE"
            ]):
                del self.lbs[lb_id]
                return EMPTY_RESPONSE, 202

            if self.lbs[lb_id]["status"] == "PENDING-DELETE":
                return EMPTY_RESPONSE, 202

            if self.lbs[lb_id]["status"] == "DELETED":
                _verify_and_update_lb_state(
                    self, lb_id, current_timestamp=current_timestamp)
                msg = "Must provide valid load balancers: {0} could not be found.".format(
                    lb_id)
                # Dont doubt this to be 422, it is 400!
                return invalid_resource(msg, 400), 400

        return not_found_response("loadbalancer"), 404
Пример #24
0
    def delete_node(self, lb_id, node_id):
        """
        Determines whether the node to be deleted exists in the session store,
        deletes the node, and returns the response code.
        """
        current_timestamp = self.clock.seconds()
        if lb_id in self.lbs:

            _verify_and_update_lb_state(self, lb_id, False, current_timestamp)

            if self.lbs[lb_id]["status"] != "ACTIVE":
                # Error message verified as of 2015-04-22
                return considered_immutable_error(
                    self.lbs[lb_id]["status"], lb_id)

            _verify_and_update_lb_state(self, lb_id,
                                        current_timestamp=current_timestamp)

            if _delete_node(self, lb_id, node_id):
                return None, 202
            else:
                return not_found_response("node"), 404

        return not_found_response("loadbalancer"), 404