Hi list,
WARNING: huge brain dump ahead.
During investigation of https://fedorahosted.org/freeipa/ticket/4305 me
and Petr Spaced (CC'ed) came to a conclusion that the IPA realm
autodiscovery code used by ipa-client-install is so convoluted, complex
and hard to understand that the cost of fixing a bug/adding a behavioral
change (there are some other tickets dealing with ipadiscovery, e.g. see
https://fedorahosted.org/freeipa/ticket/5270
https://fedorahosted.org/freeipa/ticket/3912 ) can potentially be higher
that a more large-scale rewrite of the module and related codebase.
Since we plan to do some general refactoring work anyway, I would like
to discuss the possible course of action we may take to tackle this
issue. I would like to present the following options we have been
discussing so far:
1.) Do a substantial rewrite of existing code ("ipaclient/ipadiscovery.py")
We may take the existing IPADiscovery class and try rewrite it in order
to get a more concise and deterministic code, which will:
* rely more on python-dns and answers provided by resolver (e.g. we are
directly parsing resolv.conf for available domains when we can ask the
resolver to get domains for us)
* be more pythonic (replace error codes with thrown exceptions, clean up
numerous C-isms etc.)
* not try to outsmart user when server/realm/domain is specified
beforehand. Currently, even if you specify all three options, there is
still some DNS discovery performed, hence bug #4305. I think that one
you specify server(s), not magic should be performed and the discovery
process should be reduced to checking whether they are IPA servers and
pull all other info (like realm) from them.
This may be a considerable effort requiring some time to implement and
get right, but IMHO still comparable to the time spent iteratively
placing 'if' statements into the existing code and hoping to not break
anything. I would even argue it is not worth the effort because we can
2.) Use realmd dbus interface to do DNS discovery
I have attached aquick and dirty script I have slapped together to
leverage 'org.freedesktop.realmd.Discover' interface to do IPA realm
discovery for us. This has a lot of appeal to me since we are leveraging
existing codebase for DNS discovery and will have to handle only cases
when the user manually specifies a list of IPA servers for the client.
This however pulls in realmd as a (potentially circular) dependency for
ipa client, and when we find bug in the discovery code, we will have to
poke upstream (Stef or Sumit I think) to fix it.
So from the long-term point of view, Jan Cholasta's (CC'ed) suggestion to:
3.) Split out IPA discovery portion of realmd to a separate C library
shared between IPA and realmd
may be best. Both projects will have shared codebase (maintained either
by us or realmd devs), which can be reused also by other people to
create their own discovery/enrollment solution. This would however
require sustained and concerted efforts of both teams to create the
library and possibly rewrite realmd to accommodate this change.
There may be some other options viable for us, if so please mention them
in a reply. Also please correct any piece of information I got wrong.
TL;DR: IPA realm/domain discovery is a mess, please suggest a way to fix it.
--
Martin^3 Babinsky
#!/usr/bin/env python
import dbus
from dns import resolver
bus = dbus.SystemBus()
realmd_name = 'org.freedesktop.realmd'
realmd_path = '/org/freedesktop/realmd'
def discover_realm(domain_name, next_routine):
proxy = bus.get_object(realmd_name, realmd_path)
provider = dbus.Interface(proxy, '.'.join([realmd_name, 'Provider']))
realms = provider.Discover(domain_name, {'server-software': 'ipa'})[1]
for realm in realms:
realm_props = dbus.Interface(bus.get_object(realmd_name, realm),
'org.freedesktop.DBus.Properties')
next_routine.send(realm_props)
def print_realm_info():
try:
while True:
realm_prop = (yield)
if realm_prop is not None:
print "==="
print "Realm: "
print realm_prop.Get('org.freedesktop.realmd.Kerberos', 'RealmName')
print "Domain: "
print realm_prop.Get('org.freedesktop.realmd.Kerberos', 'DomainName')
except GeneratorExit:
print "=== Done ==="
if __name__ == '__main__':
res = resolver.get_default_resolver()
client_domain = str(res.domain)
print "Searching for realms using default domain name {}".format(
client_domain)
p = print_realm_info()
p.next()
discover_realm(client_domain, p)
--
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code