Ejemplo n.º 1
0
    def test_to_json(self):
        host = "test_host"
        block = AllocationBlock(network, host)

        # Set up an allocation
        attr = {
            AllocationBlock.ATTR_HANDLE_ID: "test_key",
            AllocationBlock.ATTR_SECONDARY: {
                "key1": "value1",
                "key2": "value2"
            }
        }
        block.attributes.append(attr)
        block.allocations[5] = 0
        assert_equal(block.count_free_addresses(), BLOCK_SIZE - 1)

        # Read out the JSON
        json_str = block.to_json()
        json_dict = json.loads(json_str)
        assert_equal(json_dict[AllocationBlock.CIDR], str(network))
        assert_equal(json_dict[AllocationBlock.AFFINITY], "host:test_host")
        assert_dict_equal(json_dict[AllocationBlock.ATTRIBUTES][0],
                          attr)
        expected_allocations = [None] * BLOCK_SIZE
        expected_allocations[5] = 0
        assert_list_equal(json_dict[AllocationBlock.ALLOCATIONS],
                          expected_allocations)

        # Verify we can read the JSON back in.
        result = Mock(spec=EtcdResult)
        result.value = json_str
        block2 = AllocationBlock.from_etcd_result(result)
        assert_equal(block2.to_json(), json_str)
Ejemplo n.º 2
0
    def test_init_block_id(self):

        host = "test_host"
        block = AllocationBlock(network, host)
        assert_equal(block.host_affinity, host)
        assert_equal(block.cidr, network)
        assert_equal(block.count_free_addresses(), BLOCK_SIZE)
Ejemplo n.º 3
0
    def test_from_etcd_result_no_unallocated(self):
        """
        Test the from_etcd_result processing when the allocation order is
        missing (this is allowed since it is a new field).
        """
        result = Mock(spec=EtcdResult)

        # Build a JSON object for the Block
        attr0 = {
            AllocationBlock.ATTR_HANDLE_ID: "test_key1",
            AllocationBlock.ATTR_SECONDARY: {
                "key1": "value11",
                "key2": "value21"
            }
        }
        attr1 = {
            AllocationBlock.ATTR_HANDLE_ID: "test_key2",
            AllocationBlock.ATTR_SECONDARY: {
                "key1": "value12",
                "key2": "value22"
            }
        }
        allocations = [None] * BLOCK_SIZE
        allocations[0] = 0
        allocations[1] = 0
        allocations[4] = 1
        json_dict = {
            AllocationBlock.CIDR: str(network),
            AllocationBlock.AFFINITY: "host:Sammy Davis, Jr.",
            AllocationBlock.STRICT_AFFINITY: True,
            AllocationBlock.ALLOCATIONS: allocations,
            AllocationBlock.ATTRIBUTES: [attr0, attr1]
        }
        result.value = json.dumps(json_dict)

        block = AllocationBlock.from_etcd_result(result)
        assert_equal(block.count_free_addresses(), BLOCK_SIZE - 3)
        assert_equal(block.db_result, result)
        assert_equal(block.cidr, network)
        assert_equal(block.host_affinity, "Sammy Davis, Jr.")
        assert_true(block.strict_affinity)
        assert_list_equal(block.allocations[:5], [0, 0, None, None, 1])
        assert_dict_equal(block.attributes[0], attr0)
        assert_dict_equal(block.attributes[1], attr1)

        # Verify the allocation order is correctly calculated from the
        # unassigned entries.
        unallocated = [o for o in range(BLOCK_SIZE)
                              if o not in (0, 1, 4)]
        assert_list_equal(block.unallocated, unallocated)

        # Verify we can get JSON back out.
        json_dict[AllocationBlock.UNALLOCATED] = unallocated
        assert_equal(json.dumps(json_dict), block.to_json())
Ejemplo n.º 4
0
 def _read_block(self, block_cidr):
     """
     Read the block from the data store.
     :param block_cidr: The IPNetwork identifier for a block.
     :return: An AllocationBlock object
     """
     key = _block_datastore_key(block_cidr)
     try:
         result = self.etcd_client.read(key)
     except EtcdKeyNotFound:
         raise KeyError(str(block_cidr))
     block = AllocationBlock.from_etcd_result(result)
     return block
Ejemplo n.º 5
0
 def _read_block(self, block_cidr):
     """
     Read the block from the data store.
     :param block_cidr: The IPNetwork identifier for a block.
     :return: An AllocationBlock object
     """
     key = _block_datastore_key(block_cidr)
     try:
         # Use quorum=True to ensure we don't get stale reads.  Without this
         # we allow many subtle race conditions, such as creating a block,
         # then later reading it and finding it doesn't exist.
         result = self.etcd_client.read(key, quorum=True)
     except EtcdKeyNotFound:
         raise KeyError(str(block_cidr))
     block = AllocationBlock.from_etcd_result(result)
     return block
Ejemplo n.º 6
0
    def test_update_result(self):

        result = Mock(spec=EtcdResult)

        # Build a JSON object for the Block
        attr0 = {
            AllocationBlock.ATTR_HANDLE_ID: "test_key1",
            AllocationBlock.ATTR_SECONDARY: {
                "key1": "value11",
                "key2": "value21"
            }
        }
        attr1 = {
            AllocationBlock.ATTR_HANDLE_ID: "test_key2",
            AllocationBlock.ATTR_SECONDARY: {
                "key1": "value12",
                "key2": "value22"
            }
        }
        allocations = [None] * BLOCK_SIZE
        allocations[0] = 0
        allocations[1] = 0
        allocations[2] = 1
        json_dict = {
            AllocationBlock.CIDR: str(network),
            AllocationBlock.AFFINITY: "host:Sammy Davis, Jr.",
            AllocationBlock.ALLOCATIONS: allocations,
            AllocationBlock.ATTRIBUTES: [attr0, attr1]
        }
        result.value = json.dumps(json_dict)

        block = AllocationBlock.from_etcd_result(result)

        # Modify the block.
        block.allocations[3] = 1

        # Get the update.  It should be the same result object, but with the
        # value set to the new JSON.
        block_json_str = block.to_json()
        updated = block.update_result()
        assert_equal(updated, result)
        assert_equal(result.value, block_json_str)

        # Verify the update appears in the JSON
        block_json_dict = json.loads(block_json_str)
        json_dict[AllocationBlock.ALLOCATIONS][3] = 1
        assert_dict_equal(block_json_dict, json_dict)
Ejemplo n.º 7
0
    def test_from_etcd_result_no_affinity(self):
        """
        Mainline test of from_etcd_result()
        """

        result = Mock(spec=EtcdResult)

        # Build a JSON object for the Block.  Assume the strict_affinity flag is
        # not present so that we default the value (to False).
        attr0 = {
            AllocationBlock.ATTR_HANDLE_ID: "test_key1",
            AllocationBlock.ATTR_SECONDARY: {
                "key1": "value11",
                "key2": "value21"
            }
        }
        attr1 = {
            AllocationBlock.ATTR_HANDLE_ID: "test_key2",
            AllocationBlock.ATTR_SECONDARY: {
                "key1": "value12",
                "key2": "value22"
            }
        }
        allocations = [None] * BLOCK_SIZE
        allocations[0] = 0
        allocations[1] = 0
        allocations[2] = 1
        unallocated = list(range(3, BLOCK_SIZE))
        json_dict = {
            AllocationBlock.CIDR: str(network),
            AllocationBlock.ALLOCATIONS: allocations,
            AllocationBlock.ATTRIBUTES: [attr0, attr1],
            AllocationBlock.UNALLOCATED: unallocated
        }
        result.value = json.dumps(json_dict)

        block = AllocationBlock.from_etcd_result(result)
        assert_equal(block.count_free_addresses(), BLOCK_SIZE - 3)
        assert_equal(block.db_result, result)
        assert_equal(block.cidr, network)
        assert_is_none(block.host_affinity)
        assert_false(block.strict_affinity)
        assert_list_equal(block.allocations[:3], [0, 0, 1])
        assert_dict_equal(block.attributes[0], attr0)
        assert_dict_equal(block.attributes[1], attr1)
Ejemplo n.º 8
0
    def test_from_etcd_result(self):

        result = Mock(spec=EtcdResult)

        # Build a JSON object for the Block
        attr0 = {
            AllocationBlock.ATTR_HANDLE_ID: "test_key1",
            AllocationBlock.ATTR_SECONDARY: {
                "key1": "value11",
                "key2": "value21"
            }
        }
        attr1 = {
            AllocationBlock.ATTR_HANDLE_ID: "test_key2",
            AllocationBlock.ATTR_SECONDARY: {
                "key1": "value12",
                "key2": "value22"
            }
        }
        allocations = [None] * BLOCK_SIZE
        allocations[0] = 0
        allocations[1] = 0
        allocations[2] = 1
        json_dict = {
            AllocationBlock.CIDR: str(network),
            AllocationBlock.AFFINITY: "host:Sammy Davis, Jr.",
            AllocationBlock.ALLOCATIONS: allocations,
            AllocationBlock.ATTRIBUTES: [attr0, attr1]
        }
        result.value = json.dumps(json_dict)

        block = AllocationBlock.from_etcd_result(result)
        assert_equal(block.count_free_addresses(), BLOCK_SIZE - 3)
        assert_equal(block.db_result, result)
        assert_equal(block.cidr, network)
        assert_equal(block.host_affinity, "Sammy Davis, Jr.")
        assert_list_equal(block.allocations[:3], [0, 0, 1])
        assert_dict_equal(block.attributes[0], attr0)
        assert_dict_equal(block.attributes[1], attr1)

        # Verify we can get JSON back out.
        json_str = block.to_json()
        assert_equal(result.value, json_str)
Ejemplo n.º 9
0
    def test_auto_assign_v6(self):
        block0 = _test_block_empty_v6()

        attr = {"key21": "value1", "key22": "value2"}
        ips = block0.auto_assign(1, "key2", attr, TEST_HOST)
        assert_list_equal([BLOCK_V6_1[0]], ips)
        assert_equal(block0.attributes[0][AllocationBlock.ATTR_HANDLE_ID],
                     "key2")
        assert_dict_equal(block0.attributes[0][AllocationBlock.ATTR_SECONDARY],
                          attr)
        assert_equal(block0.count_free_addresses(), BLOCK_SIZE - 1)

        # Allocate again from the first block, with a different key.
        ips = block0.auto_assign(3, "key3", attr, TEST_HOST)
        assert_list_equal([BLOCK_V6_1[1],
                           BLOCK_V6_1[2],
                           BLOCK_V6_1[3]], ips)
        assert_equal(block0.attributes[1][AllocationBlock.ATTR_HANDLE_ID],
                     "key3")
        assert_dict_equal(block0.attributes[1][AllocationBlock.ATTR_SECONDARY],
                          attr)
        assert_equal(block0.count_free_addresses(), BLOCK_SIZE - 4)

        # Allocate with different attributes.
        ips = block0.auto_assign(3, "key3", {}, TEST_HOST)
        assert_list_equal([BLOCK_V6_1[4],
                           BLOCK_V6_1[5],
                           BLOCK_V6_1[6]], ips)
        assert_equal(block0.attributes[2][AllocationBlock.ATTR_HANDLE_ID],
                     "key3")
        assert_dict_equal(block0.attributes[2][AllocationBlock.ATTR_SECONDARY],
                          {})
        assert_equal(block0.count_free_addresses(), BLOCK_SIZE - 7)

        # Allocate 3 from a new block.
        block1 = _test_block_empty_v6()
        ips = block1.auto_assign(3, "key2", attr, TEST_HOST)
        assert_list_equal([BLOCK_V6_1[0],
                           BLOCK_V6_1[1],
                           BLOCK_V6_1[2]], ips)
        assert_equal(block1.count_free_addresses(), BLOCK_SIZE - 3)

        # Allocate again with same keys.
        ips = block1.auto_assign(3, "key2", attr, TEST_HOST)
        assert_list_equal([BLOCK_V6_1[3],
                           BLOCK_V6_1[4],
                           BLOCK_V6_1[5]], ips)
        assert_equal(block1.count_free_addresses(), BLOCK_SIZE - 6)
        # Assert we didn't create another attribute entry.
        assert_equal(len(block1.attributes), 1)

        # Test allocating 0 IPs with a new key.
        ips = block1.auto_assign(0, "key3", attr, TEST_HOST)
        assert_list_equal(ips, [])
        assert_equal(len(block1.attributes), 1)
        assert_equal(block1.count_free_addresses(), BLOCK_SIZE - 6)

        # Allocate addresses, so the block is nearly full
        ips = block1.auto_assign(BLOCK_SIZE - 8, None, {}, TEST_HOST)
        assert_equal(len(ips), BLOCK_SIZE - 8)
        assert_equal(block1.count_free_addresses(), 2)

        # Allocate 4 addresses.  248+3+3 = 254, so only 2 addresses left
        ips = block1.auto_assign(4, None, {}, TEST_HOST)
        assert_list_equal([BLOCK_V6_1[-2],
                           BLOCK_V6_1[-1]], ips)
        assert_equal(block1.count_free_addresses(), 0)

        # Block is now full, further attempts return no addresses
        ips = block1.auto_assign(4, None, {}, TEST_HOST)
        assert_list_equal([], ips)

        # Test that we can cope with already allocated addresses that aren't
        # sequential.
        block2 = _test_block_not_empty_v6()
        assert_equal(block2.count_free_addresses(), BLOCK_SIZE - 2)
        ips = block2.auto_assign(4, None, {}, TEST_HOST)
        assert_list_equal([BLOCK_V6_1[0],
                           BLOCK_V6_1[1],
                           BLOCK_V6_1[3],
                           BLOCK_V6_1[5]], ips)
        assert_equal(block2.count_free_addresses(), BLOCK_SIZE - 6)

        # Test ordinal math still works for small IPv6 addresses
        sm_cidr = IPNetwork("::1234:5600/122")
        block3 = AllocationBlock(sm_cidr, "test_host1")
        ips = block3.auto_assign(4, None, {}, TEST_HOST)
        assert_list_equal([sm_cidr[0],
                           sm_cidr[1],
                           sm_cidr[2],
                           sm_cidr[3]], ips)
        assert_equal(block3.count_free_addresses(), BLOCK_SIZE - 4)
Ejemplo n.º 10
0
    def test_update_result_from_pre_unallocated(self):
        """
        Test mainline update_result() processing.

        This includes a check to ensure that updating a block that is stored
        without the allocation order is then correctly updated to include the
        allocation order.
        """

        result = Mock(spec=EtcdResult)

        # Build a JSON object for the Block
        attr0 = {
            AllocationBlock.ATTR_HANDLE_ID: "test_key1",
            AllocationBlock.ATTR_SECONDARY: {
                "key1": "value11",
                "key2": "value21"
            }
        }
        attr1 = {
            AllocationBlock.ATTR_HANDLE_ID: "test_key2",
            AllocationBlock.ATTR_SECONDARY: {
                "key1": "value12",
                "key2": "value22"
            }
        }
        allocations = [None] * BLOCK_SIZE
        allocations[0] = 0
        allocations[1] = 0
        allocations[2] = 1
        json_dict = {
            AllocationBlock.CIDR: str(network),
            AllocationBlock.AFFINITY: "host:Sammy Davis, Jr.",
            AllocationBlock.ALLOCATIONS: allocations,
            AllocationBlock.ATTRIBUTES: [attr0, attr1]
        }
        result.value = json.dumps(json_dict)

        block = AllocationBlock.from_etcd_result(result)

        # Verify that the allocation order is correctly initialised.
        unallocated = list(range(3, BLOCK_SIZE))
        assert_list_equal(block.unallocated, unallocated)

        # Modify the block (and the expected allocation order)
        block.allocations[3] = 1
        block.unallocated.remove(3)
        unallocated.remove(3)

        # Get the update.  It should be the same result object, but with the
        # value set to the new JSON.
        block_json_str = block.to_json()
        updated = block.update_result()
        assert_equal(updated, result)
        assert_equal(result.value, block_json_str)

        # Verify the update appears in the JSON and that the JSON now includes
        # the allocation order.
        json_dict[AllocationBlock.UNALLOCATED] = unallocated
        block_json_dict = json.loads(block_json_str)
        json_dict[AllocationBlock.ALLOCATIONS][3] = 1
        assert_dict_equal(block_json_dict, json_dict)
Ejemplo n.º 11
0
    def test_from_etcd_result(self):
        """
        Mainline test of from_etcd_result()
        """

        result = Mock(spec=EtcdResult)

        # Build a JSON object for the Block
        attr0 = {
            AllocationBlock.ATTR_HANDLE_ID: "test_key1",
            AllocationBlock.ATTR_SECONDARY: {
                "key1": "value11",
                "key2": "value21"
            }
        }
        attr1 = {
            AllocationBlock.ATTR_HANDLE_ID: "test_key2",
            AllocationBlock.ATTR_SECONDARY: {
                "key1": "value12",
                "key2": "value22"
            }
        }
        allocations = [None] * BLOCK_SIZE
        allocations[0] = 0
        allocations[1] = 0
        allocations[2] = 1
        unallocated = list(range(3, BLOCK_SIZE))
        json_dict = {
            AllocationBlock.CIDR: str(network),
            AllocationBlock.AFFINITY: "host:Sammy Davis, Jr.",
            AllocationBlock.ALLOCATIONS: allocations,
            AllocationBlock.ATTRIBUTES: [attr0, attr1],
            AllocationBlock.UNALLOCATED: unallocated
        }
        result.value = json.dumps(json_dict)

        block = AllocationBlock.from_etcd_result(result)
        assert_equal(block.count_free_addresses(), BLOCK_SIZE - 3)
        assert_equal(block.db_result, result)
        assert_equal(block.cidr, network)
        assert_equal(block.host_affinity, "Sammy Davis, Jr.")
        assert_list_equal(block.allocations[:3], [0, 0, 1])
        assert_dict_equal(block.attributes[0], attr0)
        assert_dict_equal(block.attributes[1], attr1)

        # Verify we can get JSON back out.
        json_str = block.to_json()
        assert_equal(result.value, json_str)

        # Modify the allocation order in the JSON so that it does not match
        # the allocations, and check the various unallocated asserts.
        # Check repeats
        json_dict[AllocationBlock.UNALLOCATED] = unallocated + [3]
        result.value = json.dumps(json_dict)
        self.assertRaises(AssertionError,
                          AllocationBlock.from_etcd_result, result)
        # Check invalid entry
        json_dict[AllocationBlock.UNALLOCATED] = unallocated + [0]
        result.value = json.dumps(json_dict)
        self.assertRaises(AssertionError,
                          AllocationBlock.from_etcd_result, result)
        # Check missing entry
        json_dict[AllocationBlock.UNALLOCATED] = unallocated[1:]
        result.value = json.dumps(json_dict)
        self.assertRaises(AssertionError,
                          AllocationBlock.from_etcd_result, result)
Ejemplo n.º 12
0
    def test_auto_assign_v6(self):
        block0 = _test_block_empty_v6()

        attr = {"key21": "value1", "key22": "value2"}
        ips = block0.auto_assign(1, "key2", attr)
        assert_list_equal([IPAddress("2001:abcd:def0::")], ips)
        assert_equal(block0.attributes[0][AllocationBlock.ATTR_HANDLE_ID],
                     "key2")
        assert_dict_equal(block0.attributes[0][AllocationBlock.ATTR_SECONDARY],
                          attr)
        assert_equal(block0.count_free_addresses(), BLOCK_SIZE - 1)

        # Allocate again from the first block, with a different key.
        ips = block0.auto_assign(3, "key3", attr)
        assert_list_equal([IPAddress("2001:abcd:def0::1"),
                           IPAddress("2001:abcd:def0::2"),
                           IPAddress("2001:abcd:def0::3")], ips)
        assert_equal(block0.attributes[1][AllocationBlock.ATTR_HANDLE_ID],
                     "key3")
        assert_dict_equal(block0.attributes[1][AllocationBlock.ATTR_SECONDARY],
                          attr)
        assert_equal(block0.count_free_addresses(), BLOCK_SIZE - 4)

        # Allocate with different attributes.
        ips = block0.auto_assign(3, "key3", {})
        assert_list_equal([IPAddress("2001:abcd:def0::4"),
                           IPAddress("2001:abcd:def0::5"),
                           IPAddress("2001:abcd:def0::6")], ips)
        assert_equal(block0.attributes[2][AllocationBlock.ATTR_HANDLE_ID],
                     "key3")
        assert_dict_equal(block0.attributes[2][AllocationBlock.ATTR_SECONDARY],
                          {})
        assert_equal(block0.count_free_addresses(), BLOCK_SIZE - 7)

        # Allocate 3 from a new block.
        block1 = _test_block_empty_v6()
        ips = block1.auto_assign(3, "key2", attr)
        assert_list_equal([IPAddress("2001:abcd:def0::"),
                           IPAddress("2001:abcd:def0::1"),
                           IPAddress("2001:abcd:def0::2")], ips)
        assert_equal(block1.count_free_addresses(), BLOCK_SIZE - 3)

        # Allocate again with same keys.
        ips = block1.auto_assign(3, "key2", attr)
        assert_list_equal([IPAddress("2001:abcd:def0::3"),
                           IPAddress("2001:abcd:def0::4"),
                           IPAddress("2001:abcd:def0::5")], ips)
        assert_equal(block1.count_free_addresses(), BLOCK_SIZE - 6)
        # Assert we didn't create another attribute entry.
        assert_equal(len(block1.attributes), 1)

        # Test allocating 0 IPs with a new key.
        ips = block1.auto_assign(0, "key3", attr)
        assert_list_equal(ips, [])
        assert_equal(len(block1.attributes), 1)
        assert_equal(block1.count_free_addresses(), BLOCK_SIZE - 6)

        # Allocate another 248 addresses, so the block is nearly full
        ips = block1.auto_assign(248, None, {})
        assert_equal(len(ips), 248)
        assert_equal(block1.count_free_addresses(), 2)

        # Allocate 4 addresses.  248+3+3 = 254, so only 2 addresses left
        ips = block1.auto_assign(4, None, {})
        assert_list_equal([IPAddress("2001:abcd:def0::fe"),
                           IPAddress("2001:abcd:def0::ff")], ips)
        assert_equal(block1.count_free_addresses(), 0)

        # Block is now full, further attempts return no addresses
        ips = block1.auto_assign(4, None, {})
        assert_list_equal([], ips)

        # Test that we can cope with already allocated addresses that aren't
        # sequential.
        block2 = _test_block_not_empty_v6()
        assert_equal(block2.count_free_addresses(), BLOCK_SIZE - 2)
        ips = block2.auto_assign(4, None, {})
        assert_list_equal([IPAddress("2001:abcd:def0::"),
                           IPAddress("2001:abcd:def0::1"),
                           IPAddress("2001:abcd:def0::3"),
                           IPAddress("2001:abcd:def0::5")], ips)
        assert_equal(block2.count_free_addresses(), BLOCK_SIZE - 6)

        # Test ordinal math still works for small IPv6 addresses
        block3 = AllocationBlock(IPNetwork("::1234:5600/120"), "test_host1")
        ips = block3.auto_assign(4, None, {})
        assert_list_equal([IPAddress("::1234:5600"),
                           IPAddress("::1234:5601"),
                           IPAddress("::1234:5602"),
                           IPAddress("::1234:5603")], ips)
        assert_equal(block3.count_free_addresses(), BLOCK_SIZE - 4)
Ejemplo n.º 13
0
def _test_block_empty_v6():
    block = AllocationBlock(BLOCK_V6_1, "test_host1", False)
    return block
Ejemplo n.º 14
0
    def test_auto_assign_v6(self):
        block0 = _test_block_empty_v6()

        attr = {"key21": "value1", "key22": "value2"}
        ips = block0.auto_assign(1, "key2", attr, TEST_HOST)
        assert_list_equal([BLOCK_V6_1[0]], ips)
        assert_equal(block0.attributes[0][AllocationBlock.ATTR_HANDLE_ID],
                     "key2")
        assert_dict_equal(block0.attributes[0][AllocationBlock.ATTR_SECONDARY],
                          attr)
        assert_equal(block0.count_free_addresses(), BLOCK_SIZE - 1)

        # Allocate again from the first block, with a different key.
        ips = block0.auto_assign(3, "key3", attr, TEST_HOST)
        assert_list_equal([BLOCK_V6_1[1], BLOCK_V6_1[2], BLOCK_V6_1[3]], ips)
        assert_equal(block0.attributes[1][AllocationBlock.ATTR_HANDLE_ID],
                     "key3")
        assert_dict_equal(block0.attributes[1][AllocationBlock.ATTR_SECONDARY],
                          attr)
        assert_equal(block0.count_free_addresses(), BLOCK_SIZE - 4)

        # Allocate with different attributes.
        ips = block0.auto_assign(3, "key3", {}, TEST_HOST)
        assert_list_equal([BLOCK_V6_1[4], BLOCK_V6_1[5], BLOCK_V6_1[6]], ips)
        assert_equal(block0.attributes[2][AllocationBlock.ATTR_HANDLE_ID],
                     "key3")
        assert_dict_equal(block0.attributes[2][AllocationBlock.ATTR_SECONDARY],
                          {})
        assert_equal(block0.count_free_addresses(), BLOCK_SIZE - 7)

        # Allocate 3 from a new block.
        block1 = _test_block_empty_v6()
        ips = block1.auto_assign(3, "key2", attr, TEST_HOST)
        assert_list_equal([BLOCK_V6_1[0], BLOCK_V6_1[1], BLOCK_V6_1[2]], ips)
        assert_equal(block1.count_free_addresses(), BLOCK_SIZE - 3)

        # Allocate again with same keys.
        ips = block1.auto_assign(3, "key2", attr, TEST_HOST)
        assert_list_equal([BLOCK_V6_1[3], BLOCK_V6_1[4], BLOCK_V6_1[5]], ips)
        assert_equal(block1.count_free_addresses(), BLOCK_SIZE - 6)
        # Assert we didn't create another attribute entry.
        assert_equal(len(block1.attributes), 1)

        # Test allocating 0 IPs with a new key.
        ips = block1.auto_assign(0, "key3", attr, TEST_HOST)
        assert_list_equal(ips, [])
        assert_equal(len(block1.attributes), 1)
        assert_equal(block1.count_free_addresses(), BLOCK_SIZE - 6)

        # Allocate addresses, so the block is nearly full
        ips = block1.auto_assign(BLOCK_SIZE - 8, None, {}, TEST_HOST)
        assert_equal(len(ips), BLOCK_SIZE - 8)
        assert_equal(block1.count_free_addresses(), 2)

        # Allocate 4 addresses.  248+3+3 = 254, so only 2 addresses left
        ips = block1.auto_assign(4, None, {}, TEST_HOST)
        assert_list_equal([BLOCK_V6_1[-2], BLOCK_V6_1[-1]], ips)
        assert_equal(block1.count_free_addresses(), 0)

        # Block is now full, further attempts return no addresses
        ips = block1.auto_assign(4, None, {}, TEST_HOST)
        assert_list_equal([], ips)

        # Test that we can cope with already allocated addresses that aren't
        # sequential.
        block2 = _test_block_not_empty_v6()
        assert_equal(block2.count_free_addresses(), BLOCK_SIZE - 2)
        ips = block2.auto_assign(4, None, {}, TEST_HOST)
        assert_list_equal(
            [BLOCK_V6_1[0], BLOCK_V6_1[1], BLOCK_V6_1[3], BLOCK_V6_1[5]], ips)
        assert_equal(block2.count_free_addresses(), BLOCK_SIZE - 6)

        # Test ordinal math still works for small IPv6 addresses
        sm_cidr = IPNetwork("::1234:5600/122")
        block3 = AllocationBlock(sm_cidr, "test_host1", False)
        ips = block3.auto_assign(4, None, {}, TEST_HOST)
        assert_list_equal([sm_cidr[0], sm_cidr[1], sm_cidr[2], sm_cidr[3]],
                          ips)
        assert_equal(block3.count_free_addresses(), BLOCK_SIZE - 4)
Ejemplo n.º 15
0
    def test_update_result_from_pre_unallocated(self):
        """
        Test mainline update_result() processing.

        This includes a check to ensure that updating a block that is stored
        without the allocation order is then correctly updated to include the
        allocation order.
        """

        result = Mock(spec=EtcdResult)

        # Build a JSON object for the Block
        attr0 = {
            AllocationBlock.ATTR_HANDLE_ID: "test_key1",
            AllocationBlock.ATTR_SECONDARY: {
                "key1": "value11",
                "key2": "value21"
            }
        }
        attr1 = {
            AllocationBlock.ATTR_HANDLE_ID: "test_key2",
            AllocationBlock.ATTR_SECONDARY: {
                "key1": "value12",
                "key2": "value22"
            }
        }
        allocations = [None] * BLOCK_SIZE
        allocations[0] = 0
        allocations[1] = 0
        allocations[2] = 1
        json_dict = {
            AllocationBlock.CIDR: str(network),
            AllocationBlock.AFFINITY: "",  # Test a block with no affinity
            AllocationBlock.STRICT_AFFINITY: False,
            AllocationBlock.ALLOCATIONS: allocations,
            AllocationBlock.ATTRIBUTES: [attr0, attr1]
        }
        result.value = json.dumps(json_dict)

        block = AllocationBlock.from_etcd_result(result)

        # Verify the block has no affinity
        assert_equal(block.host_affinity, None)

        # Verify that the allocation order is correctly initialised.
        unallocated = list(range(3, BLOCK_SIZE))
        assert_list_equal(block.unallocated, unallocated)

        # Modify the block (and the expected allocation order)
        block.allocations[3] = 1
        block.unallocated.remove(3)
        unallocated.remove(3)

        # Get the update.  It should be the same result object, but with the
        # value set to the new JSON.
        block_json_str = block.to_json()
        updated = block.update_result()
        assert_equal(updated, result)
        assert_equal(result.value, block_json_str)

        # Verify the update appears in the JSON and that the JSON now includes
        # the allocation order.
        json_dict[AllocationBlock.UNALLOCATED] = unallocated
        block_json_dict = json.loads(block_json_str)
        json_dict[AllocationBlock.ALLOCATIONS][3] = 1
        assert_dict_equal(block_json_dict, json_dict)
Ejemplo n.º 16
0
    def test_from_etcd_result(self):
        """
        Mainline test of from_etcd_result()
        """

        result = Mock(spec=EtcdResult)

        # Build a JSON object for the Block.  Assume the strict_affinity flag is
        # not present so that we default the value (to False).
        attr0 = {
            AllocationBlock.ATTR_HANDLE_ID: "test_key1",
            AllocationBlock.ATTR_SECONDARY: {
                "key1": "value11",
                "key2": "value21"
            }
        }
        attr1 = {
            AllocationBlock.ATTR_HANDLE_ID: "test_key2",
            AllocationBlock.ATTR_SECONDARY: {
                "key1": "value12",
                "key2": "value22"
            }
        }
        allocations = [None] * BLOCK_SIZE
        allocations[0] = 0
        allocations[1] = 0
        allocations[2] = 1
        unallocated = list(range(3, BLOCK_SIZE))
        json_dict = {
            AllocationBlock.CIDR: str(network),
            AllocationBlock.AFFINITY: "host:Sammy Davis, Jr.",
            AllocationBlock.ALLOCATIONS: allocations,
            AllocationBlock.ATTRIBUTES: [attr0, attr1],
            AllocationBlock.UNALLOCATED: unallocated
        }
        result.value = json.dumps(json_dict)

        block = AllocationBlock.from_etcd_result(result)
        assert_equal(block.count_free_addresses(), BLOCK_SIZE - 3)
        assert_equal(block.db_result, result)
        assert_equal(block.cidr, network)
        assert_equal(block.host_affinity, "Sammy Davis, Jr.")
        assert_false(block.strict_affinity)
        assert_list_equal(block.allocations[:3], [0, 0, 1])
        assert_dict_equal(block.attributes[0], attr0)
        assert_dict_equal(block.attributes[1], attr1)

        # Verify we can get JSON back out.  Note that the strict affinity flag
        # will now be present.
        json_dict[AllocationBlock.STRICT_AFFINITY] = False
        json_str = block.to_json()
        assert_equal(json.dumps(json_dict), json_str)

        # Modify the allocation order in the JSON so that it does not match
        # the allocations, and check the various unallocated asserts.
        # Check repeats
        json_dict[AllocationBlock.UNALLOCATED] = unallocated + [3]
        result.value = json.dumps(json_dict)
        self.assertRaises(AssertionError, AllocationBlock.from_etcd_result,
                          result)
        # Check invalid entry
        json_dict[AllocationBlock.UNALLOCATED] = unallocated + [0]
        result.value = json.dumps(json_dict)
        self.assertRaises(AssertionError, AllocationBlock.from_etcd_result,
                          result)
        # Check missing entry
        json_dict[AllocationBlock.UNALLOCATED] = unallocated[1:]
        result.value = json.dumps(json_dict)
        self.assertRaises(AssertionError, AllocationBlock.from_etcd_result,
                          result)