Все знают, что в Win2012 сервис DHCP обладает собственным средством обеспечения отказоустойчивости - Failover. Это не кластер, это всего лишь пара серверов, обменивающихся информацией об одних и тех же диапазонах. Сдохнет один - второй возьмет на себя его обязанности.

Штука эта работает, хотя и с нареканиями. Но так уж вышло, что на одной из площадок работает она совсем уж через пень-колоду. И рвануло буквально вчера.

Нужно было по уже старому скрипту добавить новую запись о резервировании IP-адреса для нового устройства. Поначалу все штатно - проверить, что MAC нового устройства ни на каких других DHCP серверах не числится, а если числится - удалить. Затем выбрать из целевого диапазона первый попавшийся свободный адрес, и затем сделать новую запись. И на моменте создания записи получаем ошибку DHCP 20013.

Припыли. Этот код ошибки означает, что у нас бааааааальшие проблемы с JET-базой, в которой DHCP все и хранит. Начинаем разбираться.

База работает. DHCP нормально отдает новые адреса в аренду. В принципе, даже руками создавать записи можно. Но работать руками при наличии автоматизированного средства - фу. Пригляделся к ошибке по-внимательнее. Оказалось, что проблем даже не одна, а целых две. Первая - это сама ошибка 20013, которая не дает записывать в базу. Вторая еще интереснее - целевой адрес выбирается не тот, что ожидалось. Консоль DHCP показывает, что свободным адресом в текущем диапазоне является х.х.х.222, но скрипт почему-то выбирает х.х.х.234. Почему?

А покажи-ка мне все доступные записи о резервировании? Причем именно так, как это делает скрипт:

200 и 250 - это границы, в которых резервируются записи. Этот вариант и показывает, что ВСЕ адреса в диапазоне 200-233 заняты, и свободным, действительно, является аж 234. Консоль же упрямо продолжает твердить, что тот же 222 - свободен, вот прям сейчас можно туда кого-нибудь записать.

Ок, а что нам покажет вот такая запись:

То есть попытаться вытащить из базы все записи о зарезервированных адресах в конкретно заданном диапазоне. Каково же было мое удивление, когда я увидел, что результат этой команды в точности совпадает с той информацией, что нам выдает консоль DHCP! Ясно, в базе данных из-за совершенно криво работающего Failover и его репликации остались просроченные элементы, которые видны при довольно специфичных условиях.

Как лечить? Методов много, но суть одна и та же - новая база. Отличие лишь в том, как и откуда переносить туда данные. Сразу понятно, что любой бекап отпадает, потому что так будет перенесен весь мусор. На ум пришел старый добрый netsh. Проверяем:

netsh dhcp server и далее по тексту.

Утилита показывает ровно то, что нужно - актуальные записи о резервированных адресах. Отлично:
netsh dhcp server export d:\dhcpdb all

После чего раскатываем это дело на пустом DHCP сервере. Беда. Несмотря на то, что в режиме просмотра netsh не показывает мусор, тем не менее, он его так же бережно переносит в бекап и, следовательно, на новый сервер.

Руками переносить все резервированные адреса жуть, как не хочется, их довольно много. Начинаем прикидывать:
- объекты переноса - опции сервера, области, исключения в этих самых областях, опции областей, резервированные адреса, опции адресов. Ну и само собой, настройки DHCP-сервера в целом. Много объектов, да, без автоматизации никак.
- мы можем получить актуальные данные путем запроса всех резервированных адресов в конкретном скопе. Так почему бы всю эту полученную коллекцию и не перенести на свежий DHCP?
Что ж, поехали. Сидя на нашем сервере DHCP-test с развернутым мусорным бекапом и имея резервный пустой сервер с именем DHCP-test2 с поднятой на нем ролью DHCP (база пуста), выполняем:

На выходе получаем свежий DHCP-сервер с нужной информацией и отсутствием в базе всякого мусора. Прогон кода, выбирающего первый свободный адрес, это подтверждает.
Примечательно, что на соседней площадке ровно такой же DHCP-failover работает как часы. Впрочем, там и MS Exchange DAG никогда проблем не вызывала, но это уже другая история. Но похоже, что моя площадка реально проклята, баги собираем полными горстями