#!/usr/bin/python

"""

 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; version 2 of the License.

 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.

 Copyright 2009  Colin Coe <colin.coe@gmail.com>

 Portions of code reused from the Satellite/Spacewalk documentation,
 'Mastering Regular Expressions (2nd Edition)', the RHN Satellite mailing
 list and from the Internet.

"""

import xmlrpclib, httplib
import socket, sys, re, os, struct, string, stat
import grp, pwd
import base64
import time
import md5

class ProxiedTransport(xmlrpclib.Transport):
    def set_proxy(self, proxy):
        self.proxy = proxy
    def make_connection(self, host):
        self.realhost = host
        h = httplib.HTTP(self.proxy)
        return h
    def send_request(self, connection, handler, request_body):
        connection.putrequest("POST", 'http://%s%s' % (self.realhost, handler))
    def send_host(self, connection, host):
        connection.putheader('Host', self.realhost)


def dottedQuadToBinary(addr):
   pattern = re.compile("[0-9]/[0-9]")
   result = pattern.search(addr)

   if result is not None:
      netaddr, mask = addr.split("/")
   else:
      netaddr = addr

   binnet = ""

   for i in netaddr.split("."):
      i = int(i)
      b = ''
      while i > 0:
         j = i & 1
         b = str(j) + b
         i >>= 1

      while len(b) < 8:
         b = "0%s" % b

      binnet = "%s%s" % (binnet, b)

   if result is not None:
      netmask = ""
      for i in range(int(mask)):
         netmask = "%s%s" % (netmask, "1")

      while len(netmask) < 32:
         netmask = "%s%s" % (netmask, "0")

      return(binnet, netmask)
   else:
      return(binnet)

def isIPinNetwork(netaddress, ip):
   netaddr, mask = dottedQuadToBinary(netaddress)

   bin_ip = dottedQuadToBinary(ip)

   return int(netaddr, 2) == int(bin_ip, 2) & int(mask, 2)


def readFileInString(file):
   infile = open(file,"rb")
   text = infile.read()
   infile.close()

   return text

def getSysId():
   text = readFileInString("/etc/sysconfig/rhn/systemid")
   pattern = re.compile("[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]")
   result = pattern.search(text)

   return result.group(0)

def getDistVer():
   text = readFileInString("/etc/redhat-release")
   pattern = re.compile("[0-9]")
   result = pattern.search(text)
   ver = result.group(0)
   pattern = re.compile("Red Hat Enterprise Linux .*")
   result = pattern.search(text)
   if result is not None:
      dist = "el"
   pattern = re.compile("Fedora .*")
   result = pattern.search(text)
   if result is not None:
      dist = "f"

   return "%s%s" % (dist,ver)

def testEnvVar(ev):
   try:
      var = os.environ[ev]
   except:
      return False
   return True

# We want the following environment variables defined
# SAT_HOST = the name of the Satellite server
# SAT_USER = the Satellite user name to login as
# SAT_PASS = should be obvious

if not testEnvVar('SAT_HOST'):
   sys.exit(1)
if not testEnvVar('SAT_USER'):
   sys.exit(1)
if not testEnvVar('SAT_PASS'):
   sys.exit(1)


SATELLITE_URL = "http://%s/rpc/api" % os.environ['SAT_HOST']
SATELLITE_LOGIN = os.environ['SAT_USER']

# If no proxy is defined, assume no proxy needed
if testEnvVar('proxy'):
   p = ProxiedTransport()
   p.set_proxy(os.environ['proxy']);
   client = xmlrpclib.Server(SATELLITE_URL, verbose=0, transport=p)
else:
   client = xmlrpclib.Server(SATELLITE_URL, verbose=0)
session = client.auth.login(SATELLITE_LOGIN, os.environ['SAT_PASS'])

hostname = socket.gethostname()
ip = socket.gethostbyname_ex(hostname)[2]
sid = int(getSysId())
ver = getDistVer()
#business = os.environ['business']

systems = client.system.listUserSystems(session)

for system in systems:
   sys_id = system['id']
   sys_name = system['name']
   if (sys_id == sid and sys_name == 'unknown'):
      print "My profile name is 'unknown', changing it to '", hostname, "'..."
      client.system.setProfileName(session, sid, hostname)

# Re-read the system list as we've altered our name
systems = client.system.listUserSystems(session)

# delete systems with our hostname, self-termination impossible
delete_systems = [ ]
for system in systems:
   sys_id = system['id']
   sys_name = system['name']
   if sys_name == hostname and sys_id != sid:
      print sys_id, " has my host name, killing it now"
      delete_systems.append(sys_id)

if len(delete_systems):
   client.system.deleteSystems(session, delete_systems)

#print "Currently subscribed to these config channels"
#try:
#   channels = client.system.config.listChannels(session, sid)
#except OverflowError:
#   time.sleep(2)
#   channels = client.system.config.listChannels(session, sid)

# Everyone gets the generic config channel
#subscribed_configs = ["%s-generic" % business]
subscribed = 0

#if channels:
#   i = 0
#   print "Rank\tName (Label)"
#   for channel in channels:
#      i += 1
#      if channel['label'] == hostname:
#         subscribed = 1
#      subscribed_configs.append(channel['label'])
##      print i, "\t", channel['name'], "(", channel['label'], ")"
#      print "%d\t%s (%s)" % (i, channel['name'], channel['label'])
#else:
#   print "No channels subscribed, this can't be a GoodThing(TM)"

# csk = custom system key
csk = client.system.custominfo.listAllKeys(session)
groups = client.system.listGroups(session, sid)
Groups = dict()
#location = ""

for group in client.system.listGroups(session, sid):
   Groups[group['system_group_name']] = group['id']

## Based on our IP, what zone are we in and what is our location?
#for key in client.system.custominfo.listAllKeys(session):
#   pattern = re.compile('^zone-.*$|^location-.*$')
#   result = pattern.search(key['label'])
#
#   if result is None:
#      print "no match"
#   else:
#      for prefix in string.split(key['description'], sep=' '):
#         if isIPinNetwork(prefix, ip[0]):
#            m = re.search('(?<=-).*$', key['label'])
#
#            client.system.setGroupMembership(session, sid, Groups[m.group(0)], 1)
#            pattern = re.compile('^location-.*$')
#            result = pattern.search(key['label'])
#            if result is not None:
#               subscribed_configs.append(m.group(0))

# Xen hosts get extra love
#pattern = re.compile('.*xen.*$')
#result = pattern.search(hostname)
#if result is not None:
if hostname.find("xen") >= 0:
   print hostname, "is a virtualisation host, setting up virtualization capabilities"
   client.system.removeEntitlements(session, sid, ['virtualization_host_platform'])
   client.system.removeEntitlements(session, sid, ['virtualization_host'])
   os.system("/bin/rpm -e rhn-virtualization-host rhn-virtualization-common")
   print "Run rhn_check"
   os.system("/usr/sbin/rhn_check")
   time.sleep(2)
   print "Add 'virtualization_host' entitlement"
   try:
      client.system.addEntitlements(session, sid, ['virtualization_host'])
   except:
      print "Failed to add 'virtualization_host', do you have any left?"
   time.sleep(20)
   print "Run rhn_check"
   os.system("/usr/sbin/rhn_check")
   time.sleep(10)
   print "/usr/sbin/rhn-profile-sync"
   os.system("/usr/bin/yum install -y rhn-virtualization-host")
   time.sleep(2)
   os.system("/usr/sbin/rhn-profile-sync")
   time.sleep(10)

   # But how do I tell if they are RHEL guests????
   vguests = client.system.listVirtualGuests(session, sid)
   if len(client.system.listVirtualGuests(session, sid)) > 4:
      print "Too many guests, upgrading to 'virtualization_host_platform' entitlement"
      client.system.removeEntitlements(session, sid, ['virtualization_host'])
      try:
         client.system.addEntitlements(session, sid, ['virtualization_host_platform'])
      except:
         print "Failed to add 'virtualization_host_platform', do you have any left?"
else:
   print hostname, "is not a virtualisation host"


#client.system.setGroupMembership(session, sid, Groups["%s-%s" % (business, ver)], 1)

#if subscribed == 0:
#   print "Now subscribing to channel", hostname
##   chan_exist = client.configchannel.channelExists(session, hostname)
#   if client.configchannel.channelExists(session, hostname):
#      print "Config channel", hostname, "already exists, not creating again..."
#   else:
#      client.configchannel.create(session, hostname, hostname, "Files specific to %s" % hostname)
#      print "Created config channel:", hostname

#   subscribed_configs.append(hostname)

#   client.system.config.setChannels(session, [sid], subscribed_configs);

#   i = 0
#   print "Rank\tName (Label)"
#   for channel in client.system.config.listChannels(session, sid):
#      i += 1
#      print i, "\t", channel['name'], "(", channel['label'], ")"

#if not os.path.exists("/etc/ssh/ssh_host_key"):
#   os.system("/sbin/service sshd start")
#
#for infile in os.listdir("/etc/ssh/"):
#   bin = False
#   if (infile.find('ssh_host_') != -1):
#      pathname = os.path.join("/etc/ssh/", infile)
#      fstat = os.stat(pathname)
#      fileinfo = dict()
#      text = readFileInString(pathname)
#      fileinfo['contents']    = xmlrpclib.Binary(text)
#      file_digest = "%s" % md5.new(text).hexdigest()
#      try:
#         details = client.system.config.lookupFileInfo(session, sid, [pathname], 1)
#         digest = details[0]['md5']
#      except:
#         # Couldn't get file details, assuming it is not present and should be uploaded
#         digest = ""
#      if file_digest != digest:
#         fileinfo['owner']       = pwd.getpwuid(fstat[4])[0]
#         fileinfo['group']       = grp.getgrgid(fstat[5])[0]
#         fileinfo['permissions'] = "%04o" % stat.S_IMODE(fstat[stat.ST_MODE])
#         try:
#            client.configchannel.createOrUpdatePath(session, hostname, pathname, 0, fileinfo)
#         except:
#            print "(EE) Error creating/updating", pathname

print "Our work here is done."

client.auth.logout(session)

