Beispiel #1
0
 def test_filters_clb_types(self):
     """
     Only one CLB step is returned per CLB
     """
     steps = pbag([
         AddNodesToCLB(lb_id='5',
                       address_configs=s(
                           ('1.1.1.1', CLBDescription(lb_id='5',
                                                      port=80)))),
         RemoveNodesFromCLB(lb_id='5', node_ids=s('1')),
         # Unoptimizable step
         CreateServer(server_config=pmap({})),
     ])
     # returned steps could be pbag of any of the 2 lists below depending
     # on how `one_clb_step` iterates over the steps. Since it is pbag the
     # order of elements is not guaranteed
     list1 = [
         AddNodesToCLB(lb_id='5',
                       address_configs=s(
                           ('1.1.1.1', CLBDescription(lb_id='5',
                                                      port=80)))),
         CreateServer(server_config=pmap({}))
     ]
     list2 = [
         RemoveNodesFromCLB(lb_id='5', node_ids=s('1')),
         CreateServer(server_config=pmap({}))
     ]
     self.assertEqual(
         matches(MatchesAny(Equals(pbag(list1)), Equals(pbag(list2)))),
         optimize_steps(steps))
Beispiel #2
0
 def test_remove_nodes_from_clb_predicate(self):
     """
     :obj:`RemoveNodesFromCLB` only succeeds on 202.
     """
     lb_id = "12345"
     node_ids = [str(i) for i in range(5)]
     step = RemoveNodesFromCLB(lb_id=lb_id, node_ids=pset(node_ids))
     request = step.as_effect()
     self.assertTrue(request.intent.json_response)
     predicate = request.intent.success_pred
     self.assertTrue(predicate(StubResponse(202, {}), None))
     self.assertFalse(predicate(StubResponse(200, {}), None))
Beispiel #3
0
    def test_mixed_optimization(self):
        """
        Mixes of optimizable and unoptimizable steps still get optimized
        correctly.
        """
        steps = pbag([
            # CLB adds
            AddNodesToCLB(lb_id='5',
                          address_configs=s(
                              ('1.1.1.1', CLBDescription(lb_id='5',
                                                         port=80)))),
            AddNodesToCLB(lb_id='5',
                          address_configs=s(
                              ('1.1.1.2', CLBDescription(lb_id='5',
                                                         port=80)))),
            AddNodesToCLB(lb_id='6',
                          address_configs=s(
                              ('1.1.1.1', CLBDescription(lb_id='6',
                                                         port=80)))),
            AddNodesToCLB(lb_id='6',
                          address_configs=s(
                              ('1.1.1.2', CLBDescription(lb_id='6',
                                                         port=80)))),
            RemoveNodesFromCLB(lb_id='7', node_ids=s('1')),
            RemoveNodesFromCLB(lb_id='7', node_ids=s('2')),

            # Unoptimizable steps
            CreateServer(server_config=pmap({})),
        ])

        self.assertEqual(
            optimize_steps(steps),
            pbag([
                # Optimized CLB adds
                AddNodesToCLB(
                    lb_id='5',
                    address_configs=s(
                        ('1.1.1.1', CLBDescription(lb_id='5', port=80)),
                        ('1.1.1.2', CLBDescription(lb_id='5', port=80)))),
                AddNodesToCLB(
                    lb_id='6',
                    address_configs=s(
                        ('1.1.1.1', CLBDescription(lb_id='6', port=80)),
                        ('1.1.1.2', CLBDescription(lb_id='6', port=80)))),
                RemoveNodesFromCLB(lb_id='7', node_ids=s('1', '2')),

                # Unoptimizable steps
                CreateServer(server_config=pmap({}))
            ]))
Beispiel #4
0
    def test_remove_nodes_from_clb_retry(self):
        """
        :obj:`RemoveNodesFromCLB`, on receiving a 400, parses out the nodes
        that are no longer on the load balancer, and retries the bulk delete
        with those nodes removed.

        TODO: this has been left in as a regression test - this can probably be
        removed the next time it's touched, as this functionality happens
        in cloud_client now and there is a similar test there.
        """
        lb_id = "12345"
        node_ids = [str(i) for i in range(5)]
        error_body = {
            "validationErrors": {
                "messages": [
                    "Node ids 1,2,3 are not a part of your loadbalancer"
                ]
            },
            "message": "Validation Failure",
            "code": 400,
            "details": "The object is not valid"
        }

        expected_req = service_request(
            ServiceType.CLOUD_LOAD_BALANCERS,
            'DELETE',
            'loadbalancers/12345/nodes',
            params={'id': transform_eq(sorted, node_ids)},
            success_pred=ANY,
            json_response=True).intent
        expected_req2 = service_request(
            ServiceType.CLOUD_LOAD_BALANCERS,
            'DELETE',
            'loadbalancers/12345/nodes',
            params={'id': transform_eq(sorted, ['0', '4'])},
            success_pred=ANY,
            json_response=True).intent

        step = RemoveNodesFromCLB(lb_id=lb_id, node_ids=pset(node_ids))

        seq = [
            (expected_req,
             lambda i: raise_(APIError(400, json.dumps(error_body)))),
            (expected_req2, lambda i: stub_pure_response('', 202)),
        ]
        r = perform_sequence(seq, step.as_effect())
        self.assertEqual(r, (StepResult.SUCCESS, []))
Beispiel #5
0
    def test_optimize_clb_removes(self):
        """
        Aggregation is done on a per-load-balancer basis when remove nodes from
        a CLB.
        """
        steps = pbag([
            RemoveNodesFromCLB(lb_id='5', node_ids=s('1')),
            RemoveNodesFromCLB(lb_id='5', node_ids=s('2')),
            RemoveNodesFromCLB(lb_id='5', node_ids=s('3')),
            RemoveNodesFromCLB(lb_id='5', node_ids=s('4'))
        ])

        self.assertEqual(
            optimize_steps(steps),
            pbag([
                RemoveNodesFromCLB(lb_id='5', node_ids=s('1', '2', '3', '4'))
            ]))
Beispiel #6
0
    def test_remove_nodes_from_clb(self):
        """
        :obj:`RemoveNodesFromCLB` produces a request for deleting any number of
        nodes from a cloud load balancer.
        """
        lb_id = "12345"
        node_ids = [str(i) for i in range(5)]

        step = RemoveNodesFromCLB(lb_id=lb_id, node_ids=pset(node_ids))
        request = step.as_effect()
        self.assertEqual(
            request.intent,
            service_request(
                ServiceType.CLOUD_LOAD_BALANCERS,
                'DELETE',
                "loadbalancers/12345/nodes",
                params={'id': transform_eq(sorted, node_ids)},
                json_response=True,
                success_pred=ANY).intent)
Beispiel #7
0
 def test_mixed(self):
     """
     When there are multiple steps of same CLB then first step of each CLB
     is returned
     """
     steps = [
         CreateServer(server_config=pmap({"name": "server"})),
         DeleteServer(server_id="abc"),
         AddNodesToCLB(lb_id='5',
                       address_configs=s(
                           ('1.1.1.1', CLBDescription(lb_id='5',
                                                      port=80)))),
         RemoveNodesFromCLB(lb_id='5', node_ids=s('1')),
         RemoveNodesFromCLB(lb_id='6', node_ids=s('3')),
         AddNodesToCLB(lb_id='6',
                       address_configs=s(
                           ('2.1.1.1', CLBDescription(lb_id='6',
                                                      port=80)))),
         ChangeCLBNode(lb_id='7',
                       node_id='9',
                       condition=CLBNodeCondition.ENABLED,
                       weight=10,
                       type=CLBNodeType.PRIMARY),
         RemoveNodesFromCLB(lb_id='7', node_ids=s('4')),
         AddNodesToCLB(lb_id='7',
                       address_configs=s(
                           ('3.1.1.1', CLBDescription(lb_id='9',
                                                      port=80)))),
         ChangeCLBNode(lb_id='5',
                       node_id='11',
                       condition=CLBNodeCondition.ENABLED,
                       weight=10,
                       type=CLBNodeType.PRIMARY)
     ]
     self.assertEqual(
         list(one_clb_step(steps)),
         (
             steps[:3] +  # Non-CLB steps and 1 step for CLB 5
             [steps[4]] +  # One step for CLB 6
             [steps[6]])  # One step for CLB 7
     )
Beispiel #8
0
    def test_remove_nodes_from_clbs(self):
        """Logs :obj:`RemoveNodesFromCLB`."""
        removes = pbag([
            RemoveNodesFromCLB(lb_id='lbid1', node_ids=pset(['a', 'b', 'c'])),
            RemoveNodesFromCLB(lb_id='lbid2', node_ids=pset(['d', 'e', 'f']))
        ])

        self.assert_logs(removes, [
            Log('convergence-remove-clb-nodes',
                fields={
                    'lb_id': 'lbid1',
                    'nodes': ['a', 'b', 'c'],
                    'cloud_feed': True
                }),
            Log('convergence-remove-clb-nodes',
                fields={
                    'lb_id': 'lbid2',
                    'nodes': ['d', 'e', 'f'],
                    'cloud_feed': True
                }),
        ])
Beispiel #9
0
def remove_node_from_lb(node):
    """
    Remove a node from the load balancing entity.

    :ivar node: The node to be removed.
    :type node: :class:`ILBNode` provider
    """
    if isinstance(node, CLBNode):
        return RemoveNodesFromCLB(lb_id=node.description.lb_id,
                                  node_ids=pset([node.node_id]))
    elif isinstance(node, RCv3Node):
        return BulkRemoveFromRCv3(lb_node_pairs=pset(
            [(node.description.lb_id, node.cloud_server_id)]))
Beispiel #10
0
    def test_remove_nodes_from_clb_success_failures(self):
        """
        :obj:`AddNodesToCLB` succeeds if the CLB is not in existence (has been
        deleted or is not found).
        """
        successes = [CLBNotFoundError(lb_id=u'12345'),
                     CLBDeletedError(lb_id=u'12345'),
                     NoSuchCLBError(lb_id=u'12345')]
        eff = RemoveNodesFromCLB(lb_id='12345',
                                 node_ids=pset(['1', '2'])).as_effect()

        for exc in successes:
            seq = SequenceDispatcher([(eff.intent, lambda i: raise_(exc))])
            with seq.consume():
                self.assertEquals(sync_perform(seq, eff),
                                  (StepResult.SUCCESS, []))
Beispiel #11
0
    def test_remove_nodes_from_clb_terminal_failures(self):
        """
        :obj:`AddNodesToCLB` fails if there are any 4xx errors, then
        the error is propagated up and the result is a failure.
        """
        terminals = (APIError(code=403, body="You're out of luck."),
                     APIError(code=422, body="Oh look another 422."))
        eff = RemoveNodesFromCLB(lb_id='12345',
                                 node_ids=pset(['1', '2'])).as_effect()

        for exc in terminals:
            seq = SequenceDispatcher([(eff.intent, lambda i: raise_(exc))])
            with seq.consume():
                self.assertEquals(
                    sync_perform(seq, eff),
                    (StepResult.FAILURE, [ErrorReason.Exception(
                        matches(ContainsAll([type(exc), exc])))]))
Beispiel #12
0
 def test_optimize_leaves_other_steps(self):
     """
     Unoptimizable steps pass the optimizer unchanged.
     """
     steps = pbag([
         AddNodesToCLB(lb_id='5',
                       address_configs=s(
                           ('1.1.1.1', CLBDescription(lb_id='5',
                                                      port=80)))),
         RemoveNodesFromCLB(lb_id='6', node_ids=s('1')),
         CreateServer(server_config=pmap({})),
         BulkRemoveFromRCv3(lb_node_pairs=pset([("lb-1", "node-a")])),
         BulkAddToRCv3(lb_node_pairs=pset([("lb-2", "node-b")]))
         # Note that the add & remove pair should not be the same;
         # the optimizer might reasonably optimize opposite
         # operations away in the future.
     ])
     self.assertEqual(optimize_steps(steps), steps)
Beispiel #13
0
    def test_remove_nodes_from_clb_non_terminal_failures_to_retry(self):
        """
        :obj:`RemoveNodesFromCLB` retries if the CLB is temporarily locked,
        or if the request was rate-limited, or if there was an API error and
        the error is unknown but not a 4xx.
        """
        non_terminals = (CLBImmutableError(lb_id=u"12345"),
                         CLBRateLimitError(lb_id=u"12345"),
                         APIError(code=500, body="oops!"),
                         TypeError("You did something wrong in your code."))
        eff = RemoveNodesFromCLB(lb_id='12345',
                                 node_ids=pset(['1', '2'])).as_effect()

        for exc in non_terminals:
            seq = SequenceDispatcher([(eff.intent, lambda i: raise_(exc))])
            with seq.consume():
                self.assertEquals(
                    sync_perform(seq, eff),
                    (StepResult.RETRY, [ErrorReason.Exception(
                        matches(ContainsAll([type(exc), exc])))]))
Beispiel #14
0
    def _create_some_steps(self, counts={}):
        """
        Creates some steps for testing.

        :param counts: A mapping of supported step classes to the number of
            those steps to create. If unspecified, assumed to be zero.
        :return: A pbag of steps.
        """
        create_servers = [
            CreateServer(server_config=pmap({"sentinel": i}))
            for i in xrange(counts.get(CreateServer, 0))
        ]
        delete_servers = [
            DeleteServer(server_id='abc-' + str(i))
            for i in xrange(counts.get(DeleteServer, 0))
        ]
        remove_from_clbs = [
            RemoveNodesFromCLB(lb_id='1', node_ids=(str(i), ))
            for i in xrange(counts.get(RemoveNodesFromCLB, 0))
        ]

        return pbag(create_servers + delete_servers + remove_from_clbs)
Beispiel #15
0
    def test_clb_remove_multiple_load_balancers(self):
        """
        Multiple :class:`RemoveNodesFromCLB` steps for the same LB
        are merged into one.
        """
        steps = pbag([
            RemoveNodesFromCLB(lb_id='5', node_ids=s('1')),
            RemoveNodesFromCLB(lb_id='5', node_ids=s('2')),
            RemoveNodesFromCLB(lb_id='6', node_ids=s('3')),
            RemoveNodesFromCLB(lb_id='6', node_ids=s('4'))
        ])

        self.assertEqual(
            optimize_steps(steps),
            pbag([
                RemoveNodesFromCLB(lb_id='5', node_ids=s('1', '2')),
                RemoveNodesFromCLB(lb_id='6', node_ids=s('3', '4'))
            ]))