#!/usr/bin/perl

# 1. Make the RHN Satellite profile name the same as 'hostname -s'
#
# 2. Delete any old RHN Satellite profiles for this host name
#
# 3. Create a new config channel named the same as the host (this config channel may already exist)
#
# 4. Subscribe to the new config channel
#
# 5. Check to see if the SSH host keys are in the config channel
#If the keys are in the config channel, do nothing more as they'll be picked up after the script runs.
#Otherwise check sat01.tdms:/export/ssh/<hostname>/ for the keys.  If they're there then upload the to Satellite
#
# 6. Examine IP address and set the group membership

use strict;
use warnings;

use Data::Dumper;
use File::Basename;
use File::Copy;
use Frontier::Client;
use MIME::Base64;
use NetAddr::IP;
use Socket;
use Sys::Hostname;

use RHNSession;

my ($client, $session) = RHNSession::Session;

my $systems   = $client->call('system.list_user_systems', $session);
my $host      = hostname;
my $prog      = basename $0;
my $tmpdir    = "/tmp/$prog.$$";
my $satellite = "sw02.hpdms";

my (@ids, @channels, $counter);
my $sid = RHNSession::GetSID;

print "My name is $host, my system ID is $sid\n";
die "I don't know my own name, quitting now.\n" if $host eq 'unknown';

# Shorten hostname if required
for my $system (@$systems) {
	my ($sys_id, $sys_name);
	$sys_id = $system->{'id'};
	$sys_name = $system->{'name'};

	next unless $sys_id == $sid;

	if ($system->{'name'} eq 'unknown') {
		print "My profile name is 'unknown', changing it to '$host'...\n";
		$client->call('system.setProfileName', $session, $system->{'id'}, $host);
	}
}

# Because we might have made changes on the Satellite server, refresh the system list
$systems  = $client->call('system.list_user_systems', $session);

# Delete old entries in Satellite
for my $sys(sort { $a->{'name'} ge $b->{'name'} } @$systems) {
	next unless $sys->{'name'} eq $host;
	next if $sid == $sys->{'id'};
	print "$sys->{'id'} has my host name, killing it now\n";
	$client->call('system.delete_systems', $session, $sys->{'id'});
}

print "\nCurrently subscribed to these config channels\n";

my $channels = $client->call('system.config.listChannels', $session, $sid);
my @subscribed_configs;
my $subscribed = 0;
my $make_sat_client = 0;
if ($channels) {
	my $i = 0;
	print "Rank\tName (Label)\n";
	for my $channel (@$channels) {
		$i++;
		$subscribed = 1 if ($channel->{'label'} eq $host);
		push @subscribed_configs, $channel->{'label'};
		print "$i\t$channel->{'name'} ($channel->{'label'})\n";
	}
} else {
	print "No channels subscribed, this can't be a GoodThing(TM)\n";
	# Assume running from make_sat_client
	$client->call('system.config.setChannels', $session, $sid, 'Global');
	$make_sat_client = 1;
}

# csk = custom system key
my $csk = $client->call('system.custominfo.listAllKeys', $session);

# Get our IP address
my $location;
my $iaddr = gethostbyname($host) || '';
my $ip = $iaddr ? inet_ntoa($iaddr) : undef;
$ip = new NetAddr::IP($ip);

my $groups = $client->call('system.listGroups', $session, $sid);
my %Groups;

foreach my $group (@$groups) {
	$Groups{$group->{system_group_name}} = $group->{id};
}

# Based on our IP, what zone are we in and what is our location?
my $business = "";
foreach my $key (@$csk) {
	next unless $key->{label} =~ m/^zone-/ or $key->{label} =~ m/^location-/;
        # The IP address ranges for the zones are stored in the description
        for my $prefix (split(/\s/, $key->{description})) {
		$prefix = new NetAddr::IP($prefix);
                if ($ip->within($prefix)) {
			if ($key->{label} =~ m/^zone-/) {
	                        # Set the group membership to the zone if we match
				my $group = (split('-', $key->{label}, 2))[1];
#	                        $client->call('system.setGroupMembership', $session, $sid, Groups{$group}, 1);
				print "Would have set group to $group\n";
			} elsif ($key->{label} =~ m/^location-/) {
				$location = (split('-', $key->{label}, 2))[1];
#	                        $client->call('system.setGroupMembership', $session, $sid, $Groups{$location}, 1);
				print "Would have set location to $location\n";
			}
                }
        }
}

if ($location) {
	@subscribed_configs = ($location, @subscribed_configs);
}

open(RELEASE, "/etc/redhat-release") or die "Couldn't open /etc/redhat-release: $!";
while (<RELEASE>) {
	$_ =~ m/(\d)/;
	#$client->call('system.setGroupMembership', $session, $sid, $Group{"el$1"}, 1);
	print "Would have joined 'el$1'\n";

}
close(RELEASE);

if ($subscribed == 0) {
	print "Now subscribing to channel '$host'\n";

	my $chan_exist = $client->call('configchannel.channelExists', $session, $host);

	if ($chan_exist) {
		print "Config channel '$host' already exists, not creating again...\n";
	} else {
		$client->call('configchannel.create', $session, $host, $host, "Files specific to host $host");
		print "Created config channel '$host'\n" unless $@;
	}

	my @sids;
	push @sids, $sid;

print Dumper @subscribed_configs;

	@subscribed_configs = ($host, @subscribed_configs);

	foreach my $chan ($host, @subscribed_configs) {
		eval { $client->call('system.config.setChannels', $session, \@sids, $chan); };
	}

	$channels = $client->call('system.config.listChannels', $session, $sid);
	my $i = 0;

	print "Now subscribed to config channels:\n";
	print "Rank\tName (Label)\n";
	for my $channel (@$channels) {
		$i++;
		push @subscribed_configs, $channel->{'label'};
		print "$i\t$channel->{'name'} ($channel->{'label'})\n";
	}
} else {
	print "Already subscribed to config channel '$host'\n";
}
$counter = 0;
my $files = $client->call('configchannel.listFiles', $session, $host);

for my $file (@$files) {
	next unless $file->{'path'} =~ m|/etc/ssh/ssh_host_|;
	$counter++;
}

if ($counter lt 6) {
	print "SSH host keys are *not* on the Satellite server\n";
	# The files don't exist so we need ssh to create them
	if (! -f "/etc/ssh/ssh_host_key") {
		`/sbin/service sshd start ; /sbin/service sshd stop` if ($make_sat_client == 0);
	}

	opendir(DIR, "/etc/ssh/");
	my @ssh_files = grep /^ssh_host_/, readdir DIR;
	closedir(DIR);

	for my $filename (@ssh_files) {
		$filename = "/etc/ssh/".$filename;
		print "$filename\n";
		my ($filetype, $buffer) = (1, "");
		my %fileinfo;
		if (-f $filename) {
			$fileinfo{'contents'}    = do { local( *ARGV, $/ );  @ARGV=$filename; <> };
			$filetype = 0;
			if (-T $filename or -z $filename) {
				print "$filename is a text file, appending newline char\n";
				$fileinfo{'contents'} = $fileinfo{'contents'}."\n\r";
			} else {
				print "$filename is a binary file, encoding as MIME base 64\n";
				$fileinfo{'contents'}    = $client->base64(encode_base64($fileinfo{'contents'})) unless (-T $filename or -z $filename);
			}
		}
		$fileinfo{'owner'}       = getpwuid((stat($filename))[4]);
		$fileinfo{'group'}       = getgrgid((stat($filename))[5]);
		$fileinfo{'permissions'} = $client->string(sprintf("%04o", (stat($filename))[2] & 07777));
		# The below is done as an eval because if the API call fails the script will bomb out
		eval { $client->call('configchannel.createOrUpdatePath', $session, $host, $filename, $client->string($filetype), \%fileinfo); };
	}
} else {
	print "SSH host keys are on the Satellite server\nOur work here is done.\n";
}

# Lets play nicely and logout when we're finished
$client->call('auth.logout', $session);

exit;
