#!/usr/bin/python

import os, sys, getopt, getpass, urlparse

if os.path.exists('/usr/share/mrepo/up2date_client/'):
    sys.path.insert(-1, '/usr/share/mrepo/')
    sys.path.insert(-1, '/usr/share/mrepo/up2date_client/')
elif os.path.exists('/usr/share/rhn/up2date_client/'):
    sys.path.insert(-1, '/usr/share/rhn/')
    sys.path.insert(-1, '/usr/share/rhn/up2date_client/')
else:
    print >>sys.stderr, 'rhnget: up2date libraries are not installed. Aborting execution'
    sys.exit(1)

from up2date_client import config, rpcServer, up2dateErrors
from rhn import rpclib

global cfg, loginInfo

def checkrelease(release, arch):
    releases = {
        '5Server': ('i386', 'ia64', 'ppc', 's390', 's390x', 'x86_64'),
        '5Client': ('i386', 'ia64', 'x86_64'),
        '4AS': ('i386', 'ia64', 'ppc', 's390', 's390x', 'x86_64'),
        '4ES': ('i386', 'ia64', 'x86_64'),
        '4WS': ('i386', 'ia64', 'x86_64'),
        '4Desktop': ('i386', 'x86_64'),
        '3AS': ('i386', 'ia64', 'ppc', 's390', 's390x', 'x86_64'),
        '3ES': ('i386', 'ia64', 'x86_64'),
        '3WS': ('i386', 'ia64', 'x86_64'),
        '3Desktop': ('i386', 'x86_64'),
        '2.1AS': ('i386', 'ia64'),
        '2.1ES': ('i386', ),
        '2.1WS': ('i386', ),
        '2.1AW': ('ia64', ),
    }
    if release not in releases.keys():
        raise Exception, 'Release name %s is not a known RHN release.' % release
    if arch not in releases[release]:
        raise Exception, 'RHN release %s does not exist for architecture %s.' % (release, arch)
    return True

def lowarch(arch):
    archs = {
        'i386': ['i486', 'i586', 'i686', 'athlon'],
        'ia64': [],
        'ppc': ['ppc64', 'ppc64pseries', 'ppc64iseries'],
        'x86_64': [],
        's390': [],
        's390x': [],
    }
    for key in archs:
        if arch == key:
            return arch
        elif arch in archs[key]:
            return key
    else:
        print 'gensystemid: Architecture %s unknown' % arch
        return None

class Options:
    def __init__(self, args):
        self.arch = None
        self.hostname = None
        self.paths = None
        self.quiet = False
        self.rhnpassword = None
        self.rhnrelease = None
        self.rhnusername = None
        self.verbose = 1

        try:
            opts, args = getopt.getopt (args, 'a:hqp:r:u:v',
                ['arch=', 'hostname=', 'quiet', 'release=', 'help', 'verbose', 'version'])
        except getopt.error, exc:
            print 'gensystemid: %s, try gensystemid -h for a list of all the options' % str(exc)
            sys.exit(1)

        for opt, arg in opts:
            if opt in ['-a', '--arch']:
                self.arch = arg
            elif opt in ['--hostname']:
                self.hostname = arg
            elif opt in ['-p', '--password']:
                self.rhnpassword = arg
            elif opt in ['-q', '--quiet']:
                self.quiet = True
            elif opt in ['-r', '--release']:
                self.rhnrelease = arg
            elif opt in ['-u', '--username']:
                self.rhnusername = arg
            elif opt in ['-h', '--help']:
                self.usage()
                self.help()
                sys.exit(0)
            elif opt in ['-v', '--verbose']:
                self.verbose = self.verbose + 1
            elif opt in ['--version']:
                self.version()
                sys.exit(0)

        if self.quiet:
            self.verbose = 0

        if self.verbose >= 3:
            print 'Verbosity set to level %d' % self.verbose

        if not self.arch:
            self.arch = lowarch(os.uname()[4])
            print 'gensystemid: Architecture not supplied, using system architecture %s' % self.arch

        if not self.hostname:
            self.hostname = '%s-%s-%s-mrepo' % (os.uname()[1].split('.')[0], self.rhnrelease, lowarch(self.arch))

        try:
            checkrelease(self.rhnrelease, self.arch)
        except Exception, e:
            print 'gensystemid:', e
            sys.exit(2)

        if len(args) <= 0:
            print 'gensystemid: no destination path given'
            sys.exit(1)

        self.paths = args

    def version(self):
        print 'gensystemid %s' % VERSION
        print 'Written by Dag Wieers <dag@wieers.com>'
        print
        print 'platform %s/%s' % (os.name, sys.platform)
        print 'python %s' % sys.version
        print
        print 'build revision $Rev: 4107 $'

    def usage(self):
        print 'usage: gensystemid -r release [-a arch] [-p password] [-q] [-u username] [-v] dir1 dir2 ...'

    def help(self):
        print '''Generate a custom RHN systemid

gensystemid options:
  -a, --arch=arch              specify architecture (i386, x86_64, ppc, ia64)
  -q, --quiet                  minimal output
  -p, --password=password      specify rhn password (asked when not given)
  -r, --release=rhnrelease     specify rhn release {2.1,3,4}{AS,ES,WS,Desktop} 5{Server,Client}
  -u, --username=username      specify rhn username (asked when not given)
  -v, --verbose                increase verbosity
  -vv, -vvv, -vvvv..           increase verbosity more
'''


cfg = {}
loginInfo = {}

def error(level, str):
    "Output error message"
    if level <= op.verbose:
        sys.stdout.write('gensystemid: %s\n' % str)

def info(level, str):
    "Output info message"
    if level <= op.verbose:
        sys.stdout.write('%s\n' % str)

def die(ret, str):
    "Print error and exit with errorcode"
    error(0, str)
    sys.exit(ret)

def main():
    if not op.rhnusername:
        op.rhnusername = raw_input('RHN Username: ')

    if not op.rhnpassword:
        op.rhnpassword = getpass.getpass('RHN Password: ')

    rhnsystemid = '/tmp/systemid'
    if os.path.isfile(rhnsystemid):
        os.remove(rhnsystemid)
    info(5, 'Using RHN systemid from %s' % rhnsystemid)

    cfg = {}
    loginInfo = {}

    cfg['systemIdPath'] = rhnsystemid
    cfg = config.initUp2dateConfig()
    cfg['systemIdPath'] = rhnsystemid
    cfg['useRhn'] = 1

    if op.rhnrelease:
        cfg['versionOverride'] = op.rhnrelease

    if op.arch:
        cfg['forceArch'] = '%s-redhat-linux' % op.arch

    if os.access('/var/log/up2date', os.W_OK):
        cfg['logFile'] = '/var/log/up2date'
    else:
        cfg['logFile'] = os.path.expanduser('~/up2date.log')

    ### Get proxy information from environment and set up2date config accordingly
    proxy = None
    if os.environ.has_key('http_proxy'):
        t, proxy, t, t, t, t = urlparse.urlparse(os.environ['http_proxy'])
    elif os.environ.has_key('https_proxy'):
        t, proxy, t, t, t, t = urlparse.urlparse(os.environ['https_proxy'])
    if proxy:
        cfg['enableProxy'] = 1
        cfg['httpProxy'] = proxy
        info(4, 'Setting proxy to %s' % proxy)
        ### FIXME: Implement proxy authentication
#       if proxy.username and proxy.password:
#           cfg['enableProxyAuth'] = 1
#           cfg['proxyPassword'] = proxy.password
#           cfg['proxyUser='] = proxy.username


    if op.verbose >= 5:
        cfg['debug'] = 10000

    ### FIXME: Insert correct release_name (eg. redhat-release-es) only for RHEL2.1
    auth = {
            'profile_name': op.hostname,
            'os_release': op.rhnrelease,
            'release_name': 'redhat-release',
            'architecture': '%s-redhat-linux' % op.arch,
            'username': op.rhnusername,
            'password': op.rhnpassword,
            'uuid': '',
            'rhnuuid': '',
    }

    s = rpcServer.getServer()
    try:
        systemid = rpcServer.doCall(s.registration.new_user, op.rhnusername, op.rhnpassword)
    except rpclib.Fault, f:
        error(0, 'Error registering user. %s' % f.faultString)
        sys.exit(1)
        
    s = rpcServer.getServer()
    try:
        systemid = rpcServer.doCall(s.registration.new_system, auth)
    except rpclib.Fault, f:
        error(0, 'Error registering system. %s' % f.faultString)
        sys.exit(1)

    for path in op.paths:
        file = os.path.join(path, 'systemid')
        info(1, 'Writing out file %s' % file)
        open(file, 'w').write(systemid)

### Unbuffered sys.stdout
sys.stdout = os.fdopen(1, 'w', 0)
sys.stderr = os.fdopen(2, 'w', 0)

### Workaround for python <= 2.2.1
try:
     True, False
except NameError:
     True = 1
     False = 0
Yes = yes = On = on = True
No = no = Off = off = False

### Main entrance
if __name__ == '__main__':
    op = Options(sys.argv[1:])
    try:
        main()
    except KeyboardInterrupt, e:
        die(6, 'Exiting on user request')
    except OSError, e:
#       print e.errno
        die(7, 'OSError: %s' % e)

# vim:ts=4:sw=4:et
