#!/usr/bin/python

import os, sys, getopt, getpass

sys.path.insert(0, "/usr/share/rhn/")
sys.path.insert(1,"/usr/share/rhn/up2date_client")

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

global cfg, loginInfo

def checkrelease(release, arch):
	releases = {
		'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}
  -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')

	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
