Example #1
0
    def test_parse_bucket_reference_id_bad(self):
        crushmap = {
            'trees': [{
                'type': 'root',
                'name': 'dc1',
                'id': -1,
                'children': [{
                    'weight': 1.0,
                    'reference_id': 'bad',
                }],
            }]
        }
        with pytest.raises(TypeError):
            LibCrush(verbose=1).parse(crushmap)

        crushmap = {
            'trees': [{
                'type':
                'root',
                'name':
                'dc1',
                'id':
                -1,
                'children': [{
                    'weight': 1.0,
                    'reference_id': 1,
                    'INVALID': 'foo',
                }],
            }]
        }
        with pytest.raises(RuntimeError) as e:
            LibCrush().parse(crushmap)
        assert 'INVALID is not among' in str(e.value)
Example #2
0
 def test_parse_step_set_backward(self):
     for backward in STEP_BACKWARDS:
         crushmap = {'rules': {'data': [["set_" + backward, 1234]]}}
         with pytest.raises(RuntimeError) as e:
             LibCrush(verbose=1).parse(crushmap)
         assert 'not allowed unless backward_compatibility' in str(e.value)
         LibCrush(verbose=1, backward_compatibility=1).parse(crushmap)
Example #3
0
    def test_parse_verbose(self, capsys):
        empty = {
            'trees': [],
        }
        assert LibCrush(verbose=1).parse(empty)
        out, err = capsys.readouterr()
        assert 'trees' in out

        assert LibCrush().parse(empty)
        out, err = capsys.readouterr()
        assert 'trees' not in out
Example #4
0
 def test_parse_tunables_backward_compatibity(self, capsys):
     for backward in PARSE_BACKWARDS:
         crushmap = {
             'tunables': {
                 backward: 1234,
             }
         }
         with pytest.raises(RuntimeError) as e:
             LibCrush(verbose=1).parse(crushmap)
         assert 'not allowed unless backward_compatibility' in str(e.value)
         LibCrush(verbose=1, backward_compatibility=1).parse(crushmap)
Example #5
0
    def test_pool_pps(self):
        c = LibCrush()

        pps_1 = c.ceph_pool_pps(0, 16, 16)
        assert 430787817 == pps_1['0.0']
        pps_1_values = sorted(set(pps_1.values()))
        assert 16 == len(pps_1)

        pps_2 = c.ceph_pool_pps(0, 23, 16)
        pps_2_values = sorted(set(pps_2.values()))
        assert pps_1_values == pps_2_values
Example #6
0
    def test_parse_tunables_invalid(self):
        wrong = {'tunables': 1}
        with pytest.raises(RuntimeError) as e:
            LibCrush().parse(wrong)
        assert 'must be a dict' in str(e.value)

        wrong = {'tunables': {1: 0}}
        with pytest.raises(TypeError):
            LibCrush().parse(wrong)

        wrong = {'tunables': {'choose_total_tries': 'wrong'}}
        with pytest.raises(TypeError):
            LibCrush().parse(wrong)
Example #7
0
 def test_parse_invalid_algorithm(self):
     wrong = {
         'trees': [{
             'type': 'root',
             'algorithm': 'FOOBAR',
         }]
     }
     with pytest.raises(RuntimeError) as e:
         LibCrush().parse(wrong)
     assert 'not FOOBAR' in str(e.value)
     wrong = {'trees': [{'type': 'root', 'algorithm': 0}]}
     with pytest.raises(TypeError) as e:
         LibCrush().parse(wrong)
Example #8
0
    def __init__(self, verbose=False, backward_compatibility=False):
        """Create a Crush.

        If the optional argument `verbose` is set to True, all methods
        will print debug information on stdout. It defaults to False.

        If the optional argument `backward_compatibility` is set to
        True, the tunables designed for backward_compatibility are
        allowed, otherwise trying to use them raises an exception. See
        **Backward compatibility** in the class documentation.

        """
        self.c = LibCrush(verbose=verbose and 1 or 0,
                          backward_compatibility=backward_compatibility and 1 or 0)
Example #9
0
    def test_map_wrong_weights(self):
        c = LibCrush(verbose=1)
        assert c.parse({"rules": {"data": []}})
        with pytest.raises(RuntimeError) as e:
            c.map(rule="data",
                  value=1234,
                  replication_count=1,
                  weights={"unknowndevice": 1.0})
        assert 'unknowndevice is not a known device' in str(e.value)

        assert c.parse({
            "trees": [{
                "type": "root",
                "name": "dc1",
                "children": [{
                    "name": "device0",
                    "id": 0
                }]
            }],
            "rules": {
                "data": []
            }
        })
        with pytest.raises(TypeError) as e:
            c.map(rule="data",
                  value=1234,
                  replication_count=1,
                  weights={"device0": "abc"})
Example #10
0
    def test_parse_step_set_bad(self):
        wrong = {'rules': {'data': [["set_choose_tries"]]}}
        with pytest.raises(RuntimeError) as e:
            LibCrush().parse(wrong)
        assert 'exactly two' in str(e.value)

        wrong = {'rules': {'data': [["set_wrong", 1]]}}
        with pytest.raises(RuntimeError) as e:
            LibCrush().parse(wrong)
        assert 'set operand unknown' in str(e.value)

        wrong = {'rules': {'data': [["set_choose_tries", "LK"]]}}
        with pytest.raises(Exception) as e:
            LibCrush().parse(wrong)
Example #11
0
    def test_parse_step_take_bad(self):
        wrong = {'rules': {'data': [["take"]]}}
        with pytest.raises(RuntimeError) as e:
            LibCrush().parse(wrong)
        assert 'exactly two' in str(e.value)

        wrong = {'rules': {'data': [["take", 1]]}}
        with pytest.raises(TypeError) as e:
            LibCrush().parse(wrong)

        wrong = {'rules': {'data': [["take", u"unknown"]]}}
        with pytest.raises(RuntimeError) as e:
            LibCrush().parse(wrong)
        assert 'not a known bucket' in str(e.value)
Example #12
0
 def test_parse_rules_invalid_key(self):
     wrong = {
         'rules': {
             1: 'root',
         }
     }
     with pytest.raises(TypeError):
         LibCrush().parse(wrong)
Example #13
0
 def test_parse_invalid_type(self):
     wrong = {
         'trees': [{
             'type': 1,
         }]
     }
     with pytest.raises(TypeError):
         LibCrush().parse(wrong)
Example #14
0
    def test_parse_straw_algorithm(self):
        """Test that LibCrush only parses the straw algorithm
        if backward_compatibility is set to True"""
        straw_map = {
            'trees': [{
                'type': 'root',
                'name': 'cluster',
                'algorithm': 'straw'
            }]
        }

        # Backward compatibility off: fails
        with pytest.raises(RuntimeError) as e:
            LibCrush().parse(straw_map)
        assert 'straw requires backward_compatibility' in str(e.value)

        # Backward compatibility on: it works
        LibCrush(backward_compatibility=True).parse(straw_map)
Example #15
0
 def test_map_bad(self):
     crushmap = {
         "trees": [{
             "type":
             "root",
             "id":
             -1,
             "name":
             "dc1",
             "children": [{
                 "id":
                 -2,
                 "name":
                 "host0",
                 "type":
                 "host",
                 "children": [
                     {
                         "id": 0,
                         "name": "device0",
                         "weight": 1.0
                     },
                     {
                         "id": 1,
                         "name": "device1",
                         "weight": 2.0
                     },
                 ]
             }],
         }],
         "rules": {
             "firstn": [["take", "dc1"],
                        ["chooseleaf", "firstn", 0, "type", "host"],
                        ["emit"]],
             "indep": [["take", "dc1"],
                       ["chooseleaf", "indep", 0, "type", "host"], ["emit"]]
         }
     }
     c = LibCrush(verbose=1)
     assert c.parse(crushmap)
     assert c.map(rule="firstn", value=1234,
                  replication_count=2) == ["device1"]
     assert c.map(rule="indep", value=1234,
                  replication_count=2) == ["device1", None]
Example #16
0
 def test_map_ok(self):
     crushmap = {
         "trees": [{
             "type": "root",
             "id": -1,
             "name": "dc1",
             "children": [],
         }],
         "rules": {
             "data": [["take", "dc1"],
                      ["chooseleaf", "firstn", 0, "type", "host"],
                      ["emit"]],
             "for_validation": [["take", "dc1"],
                                ["chooseleaf", "firstn", 0, "type", 0],
                                ["emit"]],
         }
     }
     crushmap['trees'][0]['children'].extend([{
         "type":
         "host",
         "id":
         -(i + 2),
         "name":
         "host%d" % i,
         "children": [
             {
                 "id": (2 * i),
                 "name": "device%02d" % (2 * i),
                 "weight": 1.0
             },
             {
                 "id": (2 * i + 1),
                 "name": "device%02d" % (2 * i + 1),
                 "weight": 2.0
             },
         ],
     } for i in range(0, 10)])
     c = LibCrush(verbose=1)
     assert c.parse(crushmap)
     assert c.map(rule="data", value=1234,
                  replication_count=1) == ["device19"]
     assert c.map(rule="data", value=1234,
                  replication_count=2) == ["device19", "device13"]
Example #17
0
 def test_parse_weight_invalid(self):
     wrong = {
         'trees': [{
             'type': 'root',
             'name': 'dc1',
             'weight': "some",
         }]
     }
     with pytest.raises(TypeError):
         LibCrush().parse(wrong)
Example #18
0
 def test_parse_tunables(self, capsys):
     total_tries = 1234
     crushmap = {
         'tunables': {
             'choose_total_tries': total_tries,
         }
     }
     assert LibCrush(verbose=1).parse(crushmap)
     out, err = capsys.readouterr()
     assert 'choose_total_tries = ' + str(total_tries) in out
Example #19
0
 def test_parse_trees_invalid_key(self):
     wrong = {
         'trees': [{
             'type': 'root',
             'name': 'dc1',
             1: 'some',
         }]
     }
     with pytest.raises(TypeError):
         LibCrush().parse(wrong)
Example #20
0
 def test_parse_weight_invalid(self):
     wrong = {
         'trees': [{
             'type': 'root',
             'name': 'dc1',
             'weight': "some",
         }]
     }
     with pytest.raises(RuntimeError) as e:
         LibCrush().parse(wrong)
     assert 'must be an int' in str(e.value)
Example #21
0
 def test_parse_invalid_children_element(self):
     wrong = {
         'trees': [{
             'type': 'root',
             'name': 'dc1',
             'children': [1],
         }]
     }
     with pytest.raises(RuntimeError) as e:
         LibCrush().parse(wrong)
     assert 'must be a dict' in str(e.value)
Example #22
0
 def test_parse_bucket_id_invalid(self):
     wrong = {
         'trees': [{
             'type': 'root',
             'name': 'dc1',
             'id': 2,
         }]
     }
     with pytest.raises(RuntimeError) as e:
         LibCrush().parse(wrong)
     assert "must be a negative integer" in str(e.value)
Example #23
0
 def test_parse_bucket_invalid_key(self):
     wrong = {
         'trees': [{
             'type': 'root',
             'name': 'dc1',
             'INVALID': 1,
         }]
     }
     with pytest.raises(RuntimeError) as e:
         LibCrush().parse(wrong)
     assert 'INVALID is not' in str(e.value)
Example #24
0
 def test_map_ok_choose_args(self):
     crushmap = {
         "trees": [{
             "type": "root",
             "id": -1,
             "name": "dc1",
             "children": [],
         }],
         "rules": {
             "data": [["take", "dc1"],
                      ["chooseleaf", "firstn", 0, "type", "host"],
                      ["emit"]],
             "for_validation": [["take", "dc1"],
                                ["chooseleaf", "firstn", 0, "type", 0],
                                ["emit"]],
         }
     }
     crushmap['trees'][0]['children'].extend([{
         "type":
         "host",
         "id":
         -(i + 2),
         "name":
         "host%d" % i,
         "children": [
             {
                 "id": (2 * i),
                 "name": "device%02d" % (2 * i),
                 "weight": 1 * 0x10000
             },
             {
                 "id": (2 * i + 1),
                 "name": "device%02d" % (2 * i + 1),
                 "weight": 2 * 0x10000
             },
         ],
     } for i in range(0, 10)])
     crushmap['choose_args'] = {
         "1": [
             {
                 "bucket_name": "host9",
                 "weight_set": [[2 * 0x10000,
                                 1 * 0x10000]]  # invert the weights
             },
         ]
     }
     c = LibCrush(verbose=1)
     assert c.parse(crushmap)
     assert c.map(rule="data", value=1234,
                  replication_count=2) == ["device19", "device13"]
     assert c.map(rule="data",
                  value=1234,
                  replication_count=2,
                  choose_args="1") == ["device18", "device13"]
     assert c.map(rule="data",
                  value=1234,
                  replication_count=2,
                  choose_args=crushmap['choose_args']["1"]) == [
                      "device18", "device13"
                  ]
Example #25
0
    def test_parse_types_invalid(self):
        wrong = {'types': 1}
        with pytest.raises(RuntimeError) as e:
            LibCrush().parse(wrong)
        assert 'must be a list' in str(e.value)

        wrong = {'types': [1]}
        with pytest.raises(RuntimeError) as e:
            LibCrush().parse(wrong)
        assert 'must be a dict' in str(e.value)

        wrong = {'types': [{}]}
        with pytest.raises(RuntimeError) as e:
            LibCrush().parse(wrong)
        assert 'missing type_id' in str(e.value)

        wrong = {'types': [{'type_id': []}]}
        with pytest.raises(TypeError):
            LibCrush().parse(wrong)

        wrong = {'types': [{'type_id': 1}]}
        with pytest.raises(RuntimeError) as e:
            LibCrush().parse(wrong)
        assert 'missing name' in str(e.value)

        wrong = {'types': [{'type_id': 1, 'name': []}]}
        with pytest.raises(TypeError):
            LibCrush().parse(wrong)
Example #26
0
    def test_parse_step_choose(self):
        wrong = {'rules': {'data': [["choose"]]}}
        with pytest.raises(RuntimeError) as e:
            LibCrush().parse(wrong)
        assert 'exactly five' in str(e.value)

        wrong = {'rules': {'data': [["choose", 1, 2, 3, 4]]}}
        with pytest.raises(TypeError) as e:
            LibCrush().parse(wrong)

        wrong = {'rules': {'data': [["choose", "notgood", 2, 3, 4]]}}
        with pytest.raises(RuntimeError) as e:
            LibCrush().parse(wrong)
        assert 'unknown notgood' in str(e.value)

        wrong = {'rules': {'data': [["choose", "firstn", "notgood", 3, 4]]}}
        with pytest.raises(TypeError) as e:
            LibCrush().parse(wrong)

        wrong = {'rules': {'data': [["choose", "firstn", 0, "notgood", 4]]}}
        with pytest.raises(RuntimeError) as e:
            LibCrush().parse(wrong)
        assert "must be 'type'" in str(e.value)

        wrong = {
            'rules': {
                'data': [["choose", "firstn", 0, "type", "unknown"]]
            }
        }
        with pytest.raises(RuntimeError) as e:
            LibCrush().parse(wrong)
        assert "type is unknown" in str(e.value)
Example #27
0
 def test_map_fail(self):
     crushmap = {
         "trees": [{
             "type": "root",
             "name": "dc1",
             "id": -1,
             "children": [{
                 "type": "host",
                 "name": "host0",
                 "id": -2
             }]
         }],
         "rules": {
             "data": [["take", "dc1"],
                      ["chooseleaf", "firstn", 0, "type", "host"], ["emit"]]
         }
     }
     c = LibCrush(verbose=1)
     assert c.parse(crushmap)
     with pytest.raises(RuntimeError) as e:
         c.map(rule="data", value=1234, replication_count=1)
     assert 'unable to map' in str(e.value)
Example #28
0
 def test_parse_device_id_invalid(self):
     wrong = {
         'trees': [{
             'type': 'root',
             'name': 'dc1',
             'children': [{
                 'name': 'device0',
                 'id': -1,
             }],
         }]
     }
     with pytest.raises(RuntimeError) as e:
         LibCrush().parse(wrong)
     assert "must be a positive integer" in str(e.value)
Example #29
0
 def test_parse_device_invalid_key(self):
     wrong = {
         'trees': [{
             'type':
             'root',
             'name':
             'dc1',
             'children': [{
                 'id': 1,
                 'name': 'device0',
                 'INVALID': 1,
             }]
         }]
     }
     with pytest.raises(RuntimeError) as e:
         LibCrush().parse(wrong)
     assert "'INVALID' is not" in str(e.value)
Example #30
0
 def test_parse_bucket_reference_id(self):
     crushmap = {
         'trees': [{
             'type':
             'root',
             'name':
             'dc1',
             'id':
             -1,
             'children': [{
                 'weight': 1.0,
                 'reference_id': -2,
             }, {
                 'type': 'host',
                 'name': 'host1',
                 'id': -2,
             }],
         }]
     }
     LibCrush(verbose=1).parse(crushmap)