Not a solution per say, but a reasonable work around.  Call the attached 
script in a frequent cron job.

On Monday, August 15, 2016 at 11:02:50 AM UTC-5, Alvin Starr wrote:
>
> I have looked at this a bit more and your right.
> Its hard to believe that the ISC develpers would be that short sighted to 
> not extend the design so that changes made to the primary are copied to the 
> secondary.
>
> I can see 3 possible solutions.
> 1) fix the ISC DHCP server.
>     Fixing the DHCP server would be a major pain and there may be some 
> fundamental reason that its not possible to copy the static entries
>
> 2) change dhcp_isc_main.rb to contact both primary and secondary DHCP 
> servers.
>     Looking at the code it would be possible to change the omcmd routine 
> to talk to a secondary server.
>     This would require adding configuration items to handle the secondary.
>     The problem I can see here is what to do in the case of an error 
> condition from one server and not the other?
>
> 3) replace omshell with a shell that writes to both servers.
>     An omshell wrapper could parse the dhcpd.conf file and determine if 
> there is a secondary server.
>     If there is a secondary server the commands could be piped to both 
> servers.
>     Once again there is the issue of what to do about errors in one server 
> and not the other.
>     This solution would also likely require a small patch to dhcp_isc_main.rb 
> to allow for changing.
>
> I could supply a patch to the dhcp_isc_main.rb and do some testing on my 
> environment so that it would pass the initial sniff test but I am not in a 
> position to do a full pull request and then submit the patches via usual 
> developer channel.
>
>
>
>
> On 08/11/2016 06:40 PM, [email protected] <javascript:> wrote:
>
> DHCP will not replicate the static leases as I said before, you need twice 
> the omapi using omshell.
>
> I have discussed this with the ISC guys.
>
>
> Op vrijdag 12 augustus 2016 00:26:15 UTC+2 schreef Alvin Starr: 
>>
>> We have slightly different problems but are both limited by the nature of 
>> foremans dhcp-proxy.
>>
>> If you create static leases using omshell then I believe the data will be 
>> replicated to a failover dhcp server.
>> Forman will create new hosts using omshell.
>>
>> The comment about DNS is only because foreman can cleanly interact with 
>> DNS remotely.
>>
>>
>> On 08/11/2016 06:05 PM, [email protected] wrote:
>>
>> You are completely wrong.
>>
>> What we like to have is a second DHCP with a proxy where is talked to 
>> using OMAPI by foreman so we have a replication about the static leases.
>>
>> DHCP itself is unable to sync them this way and for Failover we need to 
>> have 2 writes to 2 DHCP servers which are in clutser mode.
>>
>> DNS is not involved here.
>>
>> Op donderdag 11 augustus 2016 23:50:43 UTC+2 schreef Alvin Starr: 
>>>
>>> A standalone DHCP server without lots of extra software installed.
>>> I do not want to install the whole forman-proxy on the DHCP or DNS ser
>>> vers
>>>
>>>
>>> As an aside the isc_dhcp proxy does not parse correctly formatted 
>>> dhcpd.conf files(I just filed a bug report).
>>>
>>>
>>> Looking at omapi I could be convinced that it is impossible to get the 
>>> current dhcp config information remotely.
>>>
>>>
>>> On 08/11/2016 05:26 PM, [email protected] wrote:
>>>
>>> What do you mean by a standalone DHCP server ? The proxy handles that 
>>> when you installed the proxy on the DHCP server.
>>>
>>> This goes about a second DHCP server that knows the same static leases 
>>> as the proxy knows for failover whent the primary, with proxy, fails.
>>>
>>> Op donderdag 11 augustus 2016 22:39:40 UTC+2 schreef Alvin Starr: 
>>>>
>>>> I have wondered about the same problem.
>>>> Since foreman needs to read and write the leases and config files it 
>>>> means that you cannot have a remote standalone DHCP server.
>>>>
>>>>
>>>> On 08/11/2016 04:32 PM, [email protected] wrote:
>>>>
>>>> Is this me or does no-one care about DHCP redundancy ?
>>>>
>>>>
>>>>
>>>> Op zaterdag 16 januari 2016 20:06:30 UTC+1 schreef Matt .: 
>>>>>
>>>>> Hi, 
>>>>>
>>>>> I was wondering if someone has a workaround for DHCP sync with 
>>>>> failover. 
>>>>>
>>>>> As foreman writes to the leases file directly this is an issue for 
>>>>> syncing. 
>>>>>
>>>>> Can't we write to a config file we include to the dhcpd.conf and 
>>>>> reload dhcp when the proxy did something to dhcp ? 
>>>>>
>>>>> Ideas are welcome. 
>>>>>
>>>>> Cheers, 
>>>>>
>>>>> Matt 
>>>>>
>>>> -- 
>>>> You received this message because you are subscribed to the Google 
>>>> Groups "Foreman users" group.
>>>> To unsubscribe from this group and stop receiving emails from it, send 
>>>> an email to [email protected].
>>>> To post to this group, send email to [email protected].
>>>> Visit this group at <https://groups.google.com/group/foreman-users>
>>>> https://groups.google.com/group/foreman-users.
>>>> For more options, visit <https://groups.google.com/d/optout>
>>>> https://groups.google.com/d/optout.
>>>>
>>>>
>>>> -- 
>>>> Alvin Starr                   ||   voice: (905)513-7688
>>>> Netvel Inc.                   ||   Cell:  (416)[email protected]    
>>>>           ||
>>>>
>>>>
>>> -- 
>>> Alvin Starr                   ||   voice: (905)513-7688
>>> Netvel Inc.                   ||   Cell:  (416)[email protected]     
>>>          ||
>>>
>>>
>> -- 
>> Alvin Starr                   ||   voice: (905)513-7688
>> Netvel Inc.                   ||   Cell:  (416)[email protected]      
>>         ||
>>
>>
> -- 
> Alvin Starr                   ||   voice: (905)513-7688
> Netvel Inc.                   ||   Cell:  (416)[email protected] 
> <javascript:>              ||
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Foreman users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/foreman-users.
For more options, visit https://groups.google.com/d/optout.
#!/usr/bin/env python3

import json

from urllib.request import Request, urlopen
from sys            import argv, stderr


def pp_json(data):
    pretty_json = json.dumps(data, sort_keys=True, indent=2, separators=(",", ": "))
    print(pretty_json)

def key_by(data, key):
    keyed_data = dict()

    for a_dict in data:
        keyed_data[a_dict[key]] = a_dict

    return keyed_data


# Thanks to Dave and Raj: http://stackoverflow.com/a/6312600/5347993
class RequestWithMethod(Request):
  def __init__(self, *args, **kwargs):
    self._method = kwargs.pop('method', None)
    Request.__init__(self, *args, **kwargs)

  def get_method(self):
    return self._method if self._method else super(RequestWithMethod, self).get_method()


# TODO: Support HTTPS
protocol = "http"

# Template for dhcp API base URLs
base_url_template  = "{0}://{1}/dhcp/{2}"
lease_url_template = "{0}/{1}"

# "Parse" arguments
dhcp_primary   = argv[1]
dhcp_secondary = argv[2]
subnet         = argv[3]

# Get the base urls
dhcp_primary_base_url   = base_url_template.format(protocol, dhcp_primary,   subnet)
dhcp_secondary_base_url = base_url_template.format(protocol, dhcp_secondary, subnet)

# Fetch the current records
with urlopen(dhcp_primary_base_url)   as primary_records_socket:
    primary_records_json   = primary_records_socket.read().decode("utf8")

with urlopen(dhcp_secondary_base_url) as secondary_records_socket:
    secondary_records_json = secondary_records_socket.read().decode("utf8")

# Parse the JSON
primary_records   = json.loads(primary_records_json)
secondary_records = json.loads(secondary_records_json)

# We just care about the reservations
primary_reservations   = primary_records[  "reservations"]
secondary_reservations = secondary_records["reservations"]

# Key for faster lookup
keyed_primary_reservations   = key_by(primary_reservations,   "ip")
keyed_secondary_reservations = key_by(secondary_reservations, "ip")

# Items to change in secondary
delete_ip_on_secondary = dict()
add_lease_on_secondary = dict()

for ip, lease in keyed_secondary_reservations.items():
    if ip not in keyed_primary_reservations:
        # Queue for deletion
        delete_ip_on_secondary[ip] = lease

for ip, lease in keyed_primary_reservations.items():
    primary_lease_url   = lease_url_template.format(dhcp_primary_base_url, ip)
    secondary_lease_url = lease_url_template.format(dhcp_primary_base_url, ip)

    # Obtain detail about reservation from primary
    with urlopen(primary_lease_url) as primary_lease_socket:
        primary_detail_lease_json = primary_lease_socket.read().decode("utf8")

    # Parse the detailed lease
    primary_detail_lease = json.loads(primary_detail_lease_json)

    if ip in keyed_secondary_reservations:
        # Obtain detail about reservation from secondary
        with urlopen(secondary_lease_url) as secondary_lease_socket:
            secondary_detail_lease_json = secondary_lease_socket.read().decode("utf8")

        # Parse the secondary detailed lease
        secondary_detail_lease = json.loads(secondary_detail_lease_json)

        # Continue if they are the same
        if set(primary_detail_lease.items()) == set(secondary_detail_lease.items()):
            continue

        # Queue for update
        delete_ip_on_secondary[ip] = lease
        add_lease_on_secondary[ip] = primary_detail_lease
    else:
        # Queue for addition
        add_lease_on_secondary[ip] = primary_detail_lease

for ip, lease in delete_ip_on_secondary.items():
    secondary_lease_url = lease_url_template.format(dhcp_secondary_base_url, ip)

    delete_request = RequestWithMethod(secondary_lease_url,
                                       method="DELETE")

    # Delete the lease
    with urlopen(delete_request) as lease_delete_socket:
        delete_response = lease_delete_socket.read().decode("utf8")

    # Notify about deletion
    print("Deleted reservation for {0} ({1}):\n".format(ip, lease["hostname"]),
          delete_response,
          file=stderr)

for ip, detail_lease in add_lease_on_secondary.items():
    secondary_lease_url = dhcp_secondary_base_url

    # This does not belong
    del detail_lease["subnet"]

    # This does belong
    detail_lease["name"] = detail_lease["hostname"]

    post_data = ""

    # Encode Request
    for k, v in detail_lease.items():
        if post_data:
            post_data += "&"

        post_data += "{0}={1}".format(k, v)

    post_request = RequestWithMethod(secondary_lease_url,
                                     data=post_data.encode("utf8"),
                                     method="POST")

    # Add the lease
    with urlopen(post_request) as lease_post_socket:
        post_response = lease_post_socket.read().decode("utf8")

    # Notify about addition
    print("Added reservation for {0} ({1}):\n".format(ip, lease["hostname"]),
          post_response,
          file=stderr)

exit(0)

# vim: set ts=4 sw=4 et syn=python:

Reply via email to