#!/usr/bin/python
# Authors: Rob Crittenden <rcritten@redhat.com>
#
# Copyright (C) 2008  Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

# Documentation can be found at http://freeipa.org/page/LdapUpdate

# TODO
# save undo files?

import os
import sys
try:
    from ipapython.config import IPAOptionParser
    from ipapython import ipautil, config
    from ipaserver.install import installutils
    from ipaserver.install.ldapupdate import LDAPUpdate, BadSyntax, UPDATES_DIR
    from ipaserver.install.upgradeinstance import IPAUpgrade
    from ipapython import sysrestore
    import logging
    import krbV
except ImportError:
    print >> sys.stderr, """\
There was a problem importing one of the required Python modules. The
error was:

    %s
""" % sys.exc_value
    sys.exit(1)

def parse_options():
    usage = "%prog [options] input_file(s)\n"
    usage += "%prog [options]\n"
    parser = IPAOptionParser(usage=usage, formatter=config.IPAFormatter())

    parser.add_option("-d", "--debug", action="store_true", dest="debug",
                      help="Display debugging information about the update(s)")
    parser.add_option("-t", "--test", action="store_true", dest="test",
                      help="Run through the update without changing anything")
    parser.add_option("-y", dest="password",
                      help="File containing the Directory Manager password")
    parser.add_option("-l", '--ldapi', action="store_true", dest="ldapi",
                      default=False, help="Connect to the LDAP server using the ldapi socket")
    parser.add_option("-u", '--upgrade', action="store_true", dest="upgrade",
                      default=False, help="Upgrade an installed server in offline mode")
    parser.add_option("-W", '--password', action="store_true",
                      dest="ask_password",
                      help="Prompt for the Directory Manager password")

    options, args = parser.parse_args()
    safe_options = parser.get_safe_opts(options)

    return safe_options, options, args

def get_dirman_password():
    """Prompt the user for the Directory Manager password and verify its
       correctness.
    """
    password = installutils.read_password("Directory Manager", confirm=False, validate=False)

    return password

def main():
    loglevel = logging.INFO
    badsyntax = False
    upgradefailed = False

    safe_options, options, args = parse_options()
    if options.debug:
        loglevel = logging.DEBUG

    if os.getegid() == 0:
        installutils.check_server_configuration()
    elif not os.path.exists('/etc/ipa/default.conf'):
        sys.exit("IPA is not configured on this system.")

    dirman_password = ""
    if options.password:
        pw = ipautil.template_file(options.password, [])
        dirman_password = pw.strip()
    else:
        if (options.ask_password or not options.ldapi) and not options.upgrade:
            dirman_password = get_dirman_password()
            if dirman_password is None:
                sys.exit("\nDirectory Manager password required")

    files = []
    if len(args) > 0:
        files = args

    # Clear all existing log handler
    loggers = logging.getLogger()
    if loggers.handlers:
        for handler in loggers.handlers:
            loggers.removeHandler(handler)
    if options.upgrade:
        if os.getegid() != 0:
            sys.exit('Upgrade can only be done as root')
        logging.basicConfig(level=loglevel,
                            format='%(asctime)s %(levelname)s %(message)s',
                            filename='/var/log/ipaupgrade.log',
                            filemode='a')
        logging.debug('%s was invoked with arguments %s and options: %s' % (sys.argv[0], args, safe_options))
        realm = krbV.default_context().default_realm
        upgrade = IPAUpgrade(realm, files, live_run=not options.test)
        upgrade.create_instance()
        modified = upgrade.modified
        badsyntax = upgrade.badsyntax
        upgradefailed = upgrade.upgradefailed
    else:
        logging.basicConfig(level=loglevel,
                            format='%(levelname)s %(message)s')
        ld = LDAPUpdate(dm_password=dirman_password, sub_dict={}, live_run=not options.test, ldapi=options.ldapi)
        if len(files) < 1:
            files = ld.get_all_files(UPDATES_DIR)
        modified = ld.update(files)

    if badsyntax:
        print 'Bad syntax detected in upgrade file(s).'
        return 1
    elif upgradefailed:
        print 'IPA upgrade failed.'
        return 1
    elif modified and options.test:
        return 2
    else:
        return 0

try:
    if __name__ == "__main__":
        sys.exit(main())
except BadSyntax, e:
    print "There is a syntax error in this update file:"
    print "  %s" % e
    sys.exit(1)
except RuntimeError, e:
    sys.exit(e)
except SystemExit, e:
    sys.exit(e)
except KeyboardInterrupt, e:
    sys.exit(1)
