Skip to content

Instantly share code, notes, and snippets.

@sideangleside
Last active February 11, 2017 22:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sideangleside/6e598b8228ab60934ee9e75a4b8ee620 to your computer and use it in GitHub Desktop.
Save sideangleside/6e598b8228ab60934ee9e75a4b8ee620 to your computer and use it in GitHub Desktop.
POC rhn to rhsm migration script (derived from katello-client-bootstrap)
#!/usr/bin/python
"""
Script to register a new host to Foreman/Satellite
or move it from Satellite 5 to 6.
Use `pydoc ./bootstrap.py` to get the documentation.
Use `awk -F'# >' 'NF>1 {print $2}' ./bootstrap.py` to see the flow.
"""
import getpass
import urllib2
import base64
import sys
import commands
import platform
import socket
import os
import pwd
import glob
import shutil
import rpm
import rpmUtils.miscutils
from datetime import datetime
from optparse import OptionParser
from urllib import urlencode
from ConfigParser import SafeConfigParser
def get_architecture():
"""
Helper function to get the architecture x86_64 vs. x86.
"""
return os.uname()[4]
"""Colors to be used by the multiple `print_*` functions."""
error_colors = {
'HEADER': '\033[95m',
'OKBLUE': '\033[94m',
'OKGREEN': '\033[92m',
'WARNING': '\033[93m',
'FAIL': '\033[91m',
'ENDC': '\033[0m',
}
def print_error(msg):
"""Helper function to output an ERROR message."""
print "[%sERROR%s], [%s], EXITING: [%s] failed to execute properly." % (
error_colors['FAIL'], error_colors['ENDC'], datetime.now().strftime('%Y-%m-%d %H:%M:%S'), msg)
def print_warning(msg):
"""Helper function to output a WARNING message."""
print "[%sWARNING%s], [%s], NON-FATAL: [%s] failed to execute properly." % (
error_colors['WARNING'], error_colors['ENDC'], datetime.now().strftime('%Y-%m-%d %H:%M:%S'), msg)
def print_success(msg):
"""Helper function to output a SUCCESS message."""
print "[%sSUCCESS%s], [%s], [%s], completed successfully." % (
error_colors['OKGREEN'], error_colors['ENDC'], datetime.now().strftime('%Y-%m-%d %H:%M:%S'), msg)
def print_running(msg):
"""Helper function to output a RUNNING message."""
print "[%sRUNNING%s], [%s], [%s] " % (
error_colors['OKBLUE'], error_colors['ENDC'], datetime.now().strftime('%Y-%m-%d %H:%M:%S'), msg)
def print_generic(msg):
"""Helper function to output a NOTIFICATION message."""
print "[NOTIFICATION], [%s], [%s] " % (datetime.now().strftime('%Y-%m-%d %H:%M:%S'), msg)
def exec_failok(command):
"""Helper function to call a command with only warning if failing."""
print_running(command)
output = commands.getstatusoutput(command)
retcode = output[0] >> 8
if retcode != 0:
print_warning(command)
print output[1]
print ""
return retcode
def exec_failexit(command):
"""Helper function to call a command with error and exit if failing."""
print_running(command)
output = commands.getstatusoutput(command)
retcode = output[0] >> 8
if retcode != 0:
print_error(command)
print output[1]
sys.exit(retcode)
print output[1]
print_success(command)
print ""
def delete_file(filename):
"""Helper function to delete files."""
if not os.path.exists(filename):
print_generic("%s does not exist - not removing" % filename)
return
try:
os.remove(filename)
print_success("Removing %s" % filename)
except OSError, e:
print_generic("Error when removing %s - %s" % (filename, e.strerror))
print_error("Removing %s" % filename)
sys.exit(1)
def delete_directory(directoryname):
"""Helper function to delete directories."""
if not os.path.exists(directoryname):
print_generic("%s does not exist - not removing" % directoryname)
return
try:
shutil.rmtree(directoryname)
print_success("Removing %s" % directoryname)
except OSError, e:
print_generic("Error when removing %s - %s" % (directoryname, e.strerror))
print_error("Removing %s" % directoryname)
sys.exit(1)
def yum(command, pkgs=""):
"""Helper function to call a yum command on a list of packages."""
exec_failexit("/usr/bin/yum -y %s %s" % (command, pkgs))
def check_migration_version():
"""
Verify that the command 'subscription-manager-migration' isn't too old.
"""
required_version = rpmUtils.miscutils.stringToVersion('1.14.2')
err = "subscription-manager-migration not found"
ts = rpm.TransactionSet()
mi = ts.dbMatch('name', 'subscription-manager-migration')
for h in mi:
if rpmUtils.miscutils.compareEVR(rpmUtils.miscutils.stringToVersion(h['evr']), required_version) < 0:
err = "%s-%s is too old" % (h['name'], h['evr'])
else:
err = None
if err:
print_error(err)
sys.exit(1)
def install_prereqs():
"""
Install subscription manager and its prerequisites.
"""
print_generic("Installing subscription manager prerequisites")
yum("remove", "subscription-manager-gnome")
yum("install", "subscription-manager 'subscription-manager-migration-*'")
yum("update", "yum openssl python")
generate_katello_facts()
def get_bootstrap_rpm():
"""
Retrieve Client CA Certificate RPMs from the Satellite 6 server.
If called with --force, calls clean_katello_agent().
"""
if options.force:
clean_katello_agent()
if os.path.exists('/etc/rhsm/ca/katello-server-ca.pem'):
print_generic("A Katello CA certificate is already installed. Assuming system is registered")
print_generic("To override this behavior, run the script with the --force option. Exiting.")
sys.exit(1)
print_generic("Retrieving Client CA Certificate RPMs")
exec_failexit("rpm -Uvh http://%s/pub/katello-ca-consumer-latest.noarch.rpm" % options.foreman_fqdn)
def disable_rhn_plugin():
if os.path.exists('/etc/yum/pluginconf.d/rhnplugin.conf'):
rhnpluginconfig = SafeConfigParser()
rhnpluginconfig.read('/etc/yum/pluginconf.d/rhnplugin.conf')
if rhnpluginconfig.get('main', 'enabled') == '1':
print_generic("RHN yum plugin was enabled. Disabling...")
rhnpluginconfig.set('main', 'enabled', '0')
rhnpluginconfig.write(open('/etc/yum/pluginconf.d/rhnplugin.conf', 'w'))
if os.path.exists('/etc/sysconfig/rhn/systemid'):
os.rename('/etc/sysconfig/rhn/systemid', '/etc/sysconfig/rhn/systemid.bootstrap-bak')
def enable_rhsmcertd():
"""
Enable and restart the rhsmcertd service
"""
exec_failexit("/sbin/chkconfig rhsmcertd on")
exec_failexit("/sbin/service rhsmcertd restart")
def migrate_systems(org_name, activationkey):
"""
Call `rhn-migrate-classic-to-rhsm` to migrate the machine from Satellite
5 to 6 using the organization name/label and the given activation key, and
configure subscription manager with the baseurl of Satellite6's pulp.
This allows the administrator to override the URL provided in the
katello-ca-consumer-latest RPM, which is useful in scenarios where the
Capsules/Servers are load-balanced or using subjectAltName certificates.
If called with "--legacy-purge", uses "legacy-user" and "legacy-password"
to remove the machine.
Option "--force" is always passed so that `rhn-migrate-classic-to-rhsm`
does not fail on channels which cannot be mapped either because they
are cloned channels, custom channels, or do not exist in the destination.
"""
# if options.no_foreman:
# org_label = org_name
# else:
# org_label = return_matching_katello_key('organizations', 'name="%s"' % org_name, 'label', False)
org_label = org_name
print_generic("Calling rhn-migrate-classic-to-rhsm")
options.rhsmargs += " --force --destination-url=https://%s" % (options.foreman_fqdn)
if options.legacy_purge:
options.rhsmargs += " --legacy-user '%s' --legacy-password '%s'" % (
options.legacy_login, options.legacy_password)
else:
options.rhsmargs += " --keep"
exec_failexit("/usr/sbin/rhn-migrate-classic-to-rhsm --org %s --activation-key '%s' %s" % (
org_label, activationkey, options.rhsmargs))
# exec_failexit("subscription-manager config --rhsm.baseurl=https://%s/pulp/repos" % options.foreman_fqdn)
enable_rhsmcertd()
# When rhn-migrate-classic-to-rhsm is called with --keep, it will leave the systemid
# file intact, which might confuse the (not yet removed) yum-rhn-plugin.
# Move the file to a backup name & disable the RHN plugin, so the user can still restore it if needed.
disable_rhn_plugin()
def register_systems(org_name, activationkey, release):
"""
Register the host to Satellite 6's organization using
`subscription-manager` and the given activation key.
Option "--force" is given further.
"""
# if options.no_foreman:
# org_label = org_name
# else:
# org_label = return_matching_katello_key('organizations', 'name="%s"' % org_name, 'label', False)
org_label = org_name
print_generic("Calling subscription-manager")
# options.smargs += " --serverurl=https://%s:%s/rhsm --baseurl=https://%s/pulp/repos" % (options.foreman_fqdn, API_PORT, options.foreman_fqdn)
if options.force:
options.smargs += " --force"
exec_failexit("/usr/sbin/subscription-manager register --org '%s' --name '%s' --activationkey '%s' %s" % (
org_label, FQDN, activationkey, options.smargs))
enable_rhsmcertd()
def unregister_system():
"""Unregister the host using `subscription-manager`."""
print_generic("Unregistering")
exec_failexit("/usr/sbin/subscription-manager unregister")
def clean_katello_agent():
"""Remove old Katello agent (aka Gofer) and certificate RPMs."""
print_generic("Removing old Katello agent and certs")
delete_file("/etc/rhsm/ca/katello-server-ca.pem")
yum("erase", "'katello-ca-consumer-*' katello-agent gofer")
def install_katello_agent():
"""Install Katello agent (aka Gofer) and activate /start it."""
print_generic("Installing the Katello agent")
yum("install", "katello-agent")
exec_failexit("/sbin/chkconfig goferd on")
exec_failexit("/sbin/service goferd restart")
def clean_puppet():
"""Remove old Puppet Agent and its configuration"""
print_generic("Cleaning old Puppet Agent")
yum("erase", "puppet")
delete_directory("/var/lib/puppet/")
def clean_environment():
"""
Undefine `LD_LIBRARY_PATH` and `LD_PRELOAD` as many environments
have it defined non-sensibly.
"""
for key in ['LD_LIBRARY_PATH', 'LD_PRELOAD']:
os.environ.pop(key, None)
def generate_katello_facts():
if FQDN.find(".") != -1 and not os.path.exists('/etc/rhsm/facts/katello.facts'):
print_generic("Workaround for FQDN")
katellofacts = open('/etc/rhsm/facts/katello.facts', 'w')
katellofacts.write('{"network.hostname":"%s"}\n' % (FQDN))
katellofacts.close()
def install_puppet_agent():
"""Install and configure, then enable and start the Puppet Agent"""
puppet_env = return_puppetenv_for_hg(
return_matching_foreman_key('hostgroups', 'title="%s"' % options.hostgroup, 'id', False))
print_generic("Installing the Puppet Agent")
yum("install", "puppet")
exec_failexit("/sbin/chkconfig puppet on")
puppet_conf = open('/etc/puppet/puppet.conf', 'wb')
puppet_conf.write("""
[main]
vardir = /var/lib/puppet
logdir = /var/log/puppet
rundir = /var/run/puppet
ssldir = $vardir/ssl
[agent]
pluginsync = true
report = true
ignoreschedules = true
daemon = false
ca_server = %s
certname = %s
environment = %s
server = %s
""" % (options.foreman_fqdn, FQDN, puppet_env, options.foreman_fqdn))
puppet_conf.close()
print_generic("Running Puppet in noop mode to generate SSL certs")
print_generic("Visit the UI and approve this certificate via Infrastructure->Capsules")
print_generic("if auto-signing is disabled")
exec_failexit("/usr/bin/puppet agent --test --noop --tags no_such_tag --waitforcert 10")
exec_failexit("/sbin/service puppet restart")
def remove_obsolete_packages():
"""Remove old RHN packages"""
print_generic("Removing old RHN packages")
yum("remove",
"rhn-setup rhn-client-tools yum-rhn-plugin rhnsd rhn-check rhnlib spacewalk-abrt spacewalk-oscap osad 'rh-*-rhui-client'")
def fully_update_the_box():
"""Call `yum -y update` to upgrade the host."""
print_generic("Fully Updating The Box")
yum("update")
# curl https://satellite.example.com:9090/ssh/pubkey >> ~/.ssh/authorized_keys
# sort -u ~/.ssh/authorized_keys
def install_foreman_ssh_key():
"""
Download and install the Satellite's SSH public key into the foreman user's
authorized keys file, so that remote execution becomes possible.
"""
userpw = pwd.getpwnam(options.remote_exec_user)
foreman_ssh_dir = os.sep.join([userpw.pw_dir, '.ssh'])
foreman_ssh_authfile = os.sep.join([foreman_ssh_dir, 'authorized_keys'])
if not os.path.isdir(foreman_ssh_dir):
os.mkdir(foreman_ssh_dir, 0700)
os.chown(foreman_ssh_dir, userpw.pw_uid, userpw.pw_gid)
try:
foreman_ssh_key = urllib2.urlopen("https://%s:9090/ssh/pubkey" % options.foreman_fqdn).read()
except urllib2.HTTPError, e:
print_generic("The server was unable to fulfill the request. Error: %s" % e.code)
except urllib2.URLError, e:
print_generic("Could not reach the server. Error: %s" % e.reason)
return
if os.path.isfile(foreman_ssh_authfile):
if foreman_ssh_key in open(foreman_ssh_authfile, 'r').read():
print_generic("Foreman's SSH key is already present in %s" % foreman_ssh_authfile)
return
output = os.fdopen(os.open(foreman_ssh_authfile, os.O_WRONLY | os.O_CREAT, 0600), 'a')
output.write(foreman_ssh_key)
os.chown(foreman_ssh_authfile, userpw.pw_uid, userpw.pw_gid)
print_generic("Foreman's SSH key was added to %s" % foreman_ssh_authfile)
output.close()
class BetterHTTPErrorProcessor(urllib2.BaseHandler):
"""
A substitute/supplement class to urllib2.HTTPErrorProcessor
that doesn't raise exceptions on status codes 201,204,206
"""
def http_error_201(self, request, response, code, msg, hdrs):
return response
def http_error_204(self, request, response, code, msg, hdrs):
return response
def http_error_206(self, request, response, code, msg, hdrs):
return response
def call_api(url, data=None, method='GET'):
"""
Helper function to place an API call returning JSON results and doing
some error handling. Any error results in an exit.
"""
try:
request = urllib2.Request(url)
if options.verbose:
print 'url: %s' % url
print 'method: %s' % method
print 'data: %s' % json.dumps(data, sort_keys=False, indent=2)
base64string = base64.encodestring('%s:%s' % (options.login, options.password)).strip()
request.add_header("Authorization", "Basic %s" % base64string)
request.add_header("Content-Type", "application/json")
request.add_header("Accept", "application/json")
if data:
request.add_data(json.dumps(data))
request.get_method = lambda: method
result = urllib2.urlopen(request)
jsonresult = json.load(result)
if options.verbose:
print 'result: %s' % json.dumps(jsonresult, sort_keys=False, indent=2)
return jsonresult
except urllib2.URLError, e:
print 'An error occured: %s' % e
print 'url: %s' % url
if isinstance(e, urllib2.HTTPError):
print 'code: %s' % e.code
if data:
print 'data: %s' % json.dumps(data, sort_keys=False, indent=2)
try:
jsonerr = json.load(e)
print 'error: %s' % json.dumps(jsonerr, sort_keys=False, indent=2)
except:
print 'error: %s' % e
sys.exit(1)
except Exception, e:
print "FATAL Error - %s" % (e)
sys.exit(2)
def get_json(url):
"""Use `call_api` to place a "GET" REST API call."""
return call_api(url)
def post_json(url, jdata):
"""Use `call_api` to place a "POST" REST API call."""
return call_api(url, data=jdata, method='POST')
def delete_json(url):
"""Use `call_api` to place a "DELETE" REST API call."""
return call_api(url, method='DELETE')
def put_json(url):
"""Use `call_api` to place a "PUT" REST API call."""
return call_api(url, method='PUT')
def return_matching_foreman_key(api_name, search_key, return_key, null_result_ok=False):
"""
Function uses `return_matching_key` to make an API call to Foreman.
"""
return return_matching_key("/api/v2/" + api_name, search_key, return_key, null_result_ok)
def return_matching_katello_key(api_name, search_key, return_key, null_result_ok=False):
"""
Function uses `return_matching_key` to make an API call to Katello.
"""
return return_matching_key("/katello/api/" + api_name, search_key, return_key, null_result_ok)
def return_matching_key(api_path, search_key, return_key, null_result_ok=False):
"""
Search in API given a search key, which must be unique, then returns the
field given in "return_key" as ID.
api_path is the path in url for API name, search_key must contain also
the key for search (name=, title=, ...).
The search_key must be quoted in advance.
"""
myurl = "https://" + options.foreman_fqdn + ":" + API_PORT + api_path + "/?" + urlencode(
[('search', '' + str(search_key))])
return_values = get_json(myurl)
result_len = len(return_values['results'])
if result_len == 1:
return_values_return_key = return_values['results'][0][return_key]
return return_values_return_key
elif result_len == 0 and null_result_ok is True:
return None
else:
print_error(
"%d element in array for search key '%s' in API '%s'. Please note that all searches are case-sensitive. Fatal error." % (
result_len, search_key, api_path))
sys.exit(2)
def return_puppetenv_for_hg(hg_id):
"""
Return the Puppet environment of the given hostgroup ID, either directly
or inherited through its hierarchy. If no environment is found,
"production" is assumed.
"""
myurl = "https://" + options.foreman_fqdn + ":" + API_PORT + "/api/v2/hostgroups/" + str(hg_id)
hostgroup = get_json(myurl)
if hostgroup['environment_name']:
return hostgroup['environment_name']
elif hostgroup['ancestry']:
parent = hostgroup['ancestry'].split('/')[-1]
return return_puppetenv_for_hg(parent)
else:
return 'production'
def create_domain(domain, orgid, locid):
"""
Call Foreman API to create a network domain associated with the given
organization and location.
"""
myurl = "https://" + options.foreman_fqdn + ":" + API_PORT + "/api/v2/domains"
domid = return_matching_foreman_key('domains', 'name="%s"' % domain, 'id', True)
if not domid:
jsondata = json.loads(
'{"domain": {"name": "%s", "organization_ids": [%s], "location_ids": [%s]}}' % (domain, orgid, locid))
print_running("Calling Foreman API to create domain %s associated with the org & location" % domain)
post_json(myurl, jsondata)
def create_host():
"""
Call Foreman API to create a host entry associated with the
host group, organization & location, domain and architecture.
"""
myhgid = return_matching_foreman_key('hostgroups', 'title="%s"' % options.hostgroup, 'id', False)
if options.location:
mylocid = return_matching_foreman_key('locations', 'title="%s"' % options.location, 'id', False)
else:
mylocid = None
myorgid = return_matching_foreman_key('organizations', 'name="%s"' % options.org, 'id', False)
if DOMAIN:
if options.add_domain:
create_domain(DOMAIN, myorgid, mylocid)
mydomainid = return_matching_foreman_key('domains', 'name="%s"' % DOMAIN, 'id', True)
if not mydomainid:
print_generic("Domain %s doesn't exist in Foreman, consider using the --add-domain option." % DOMAIN)
sys.exit(2)
else:
mydomainid = None
architecture_id = return_matching_foreman_key('architectures', 'name="%s"' % ARCHITECTURE, 'id', False)
host_id = return_matching_foreman_key('hosts', 'name="%s"' % FQDN, 'id', True)
# create the starting json, to be filled below
jsondata = json.loads(
'{"host": {"name": "%s","hostgroup_id": %s,"organization_id": %s, "mac":"%s","architecture_id":%s}}' % (
HOSTNAME, myhgid, myorgid, MAC, architecture_id))
# optional parameters
if options.operatingsystem is not None:
operatingsystem_id = return_matching_foreman_key('operatingsystems', 'title="%s"' % options.operatingsystem,
'id', False)
jsondata['host']['operatingsystem_id'] = operatingsystem_id
if options.partitiontable is not None:
partitiontable_id = return_matching_foreman_key('ptables', 'name="%s"' % options.partitiontable, 'id', False)
jsondata['host']['ptable_id'] = partitiontable_id
if not options.unmanaged:
jsondata['host']['managed'] = 'true'
else:
jsondata['host']['managed'] = 'false'
if mylocid:
jsondata['host']['location_id'] = mylocid
if mydomainid:
jsondata['host']['domain_id'] = mydomainid
myurl = "https://" + options.foreman_fqdn + ":" + API_PORT + "/api/v2/hosts/"
if options.force and host_id is not None:
disassociate_host(host_id)
delete_host(host_id)
print_running("Calling Foreman API to create a host entry associated with the group & org")
post_json(myurl, jsondata)
print_success("Successfully created host %s" % FQDN)
def delete_host(host_id):
"""Call Foreman API to delete the current host."""
myurl = "https://" + options.foreman_fqdn + ":" + API_PORT + "/api/v2/hosts/"
print_running("Deleting host id %s for host %s" % (host_id, FQDN))
delete_json("%s/%s" % (myurl, host_id))
def disassociate_host(host_id):
"""
Call Foreman API to disassociate host from content host before deletion.
"""
myurl = "https://" + options.foreman_fqdn + ":" + API_PORT + "/api/v2/hosts/" + str(host_id) + "/disassociate"
print_running("Disassociating host id %s for host %s" % (host_id, FQDN))
put_json(myurl)
def configure_subscription_manager():
productidconfig = SafeConfigParser()
productidconfig.read('/etc/yum/pluginconf.d/product-id.conf')
if productidconfig.get('main', 'enabled') == '0':
print_generic("Product-id yum plugin was disabled. Enabling...")
productidconfig.set('main', 'enabled', '1')
productidconfig.write(open('/etc/yum/pluginconf.d/product-id.conf', 'w'))
submanconfig = SafeConfigParser()
submanconfig.read('/etc/yum/pluginconf.d/subscription-manager.conf')
if submanconfig.get('main', 'enabled') == '0':
print_generic("subscription-manager yum plugin was disabled. Enabling...")
submanconfig.set('main', 'enabled', '1')
submanconfig.write(open('/etc/yum/pluginconf.d/subscription-manager.conf', 'w'))
def check_rhn_registration():
"""Helper function to check if host is registered to legacy RHN."""
if os.path.exists('/etc/sysconfig/rhn/systemid'):
retcode = commands.getstatusoutput('rhn-channel -l')[0] >> 8
return retcode == 0
else:
return False
def enable_repos():
"""Enable necessary repositories using subscription-manager."""
repostoenable = " ".join(['--enable=%s' % i for i in options.enablerepos.split(',')])
print_running("Enabling repositories - %s" % options.enablerepos)
exec_failok("subscription-manager repos %s" % repostoenable)
def get_api_port():
"""Helper function to get the server port from Subscription Manager."""
configparser = SafeConfigParser()
configparser.read('/etc/rhsm/rhsm.conf')
return configparser.get('server', 'port')
def get_rhsm_orgid():
myurl = "https://" + options.foreman_fqdn + ":" + API_PORT + "/subscription/users/" + options.login + "/owners"
results = get_json(myurl)
print 'RHSM Organization ID for user %s is ->> %s' % (options.login, results[0]['key'])
# return
print "Foreman Bootstrap Script"
print "This script is designed to register new systems or to migrate an existing system to a Foreman server with Katello"
def prepare_rhel5_migration():
"""
Execute specific preparations steps for RHEL 5. Older releases of RHEL 5
did not have a version of rhn-classic-migrate-to-rhsm which supported
activation keys. This function allows those systems to get a proper
product certificate.
"""
install_prereqs()
# only do the certificate magic if 69.pem is not present
# and we have active channels
if check_rhn_registration() and not os.path.exists('/etc/pki/product/69.pem'):
_LIBPATH = "/usr/share/rhsm"
# add to the path if need be
if _LIBPATH not in sys.path:
sys.path.append(_LIBPATH)
from subscription_manager.migrate import migrate
class MEOptions:
force = True
me = migrate.MigrationEngine()
me.options = MEOptions()
subscribed_channels = me.get_subscribed_channels_list()
me.print_banner(("System is currently subscribed to these RHNClassic Channels:"))
for channel in subscribed_channels:
print channel
me.check_for_conflicting_channels(subscribed_channels)
me.deploy_prod_certificates(subscribed_channels)
me.clean_up(subscribed_channels)
# at this point we should have at least 69.pem available, but lets
# doublecheck and copy it manually if not
if not os.path.exists('/etc/pki/product/'):
os.mkdir("/etc/pki/product/")
mapping_file = "/usr/share/rhsm/product/RHEL-5/channel-cert-mapping.txt"
if not os.path.exists('/etc/pki/product/69.pem') and os.path.exists(mapping_file):
for line in open(mapping_file):
if line.startswith('rhel-%s-server-5' % ARCHITECTURE):
cert = line.split(" ")[1]
shutil.copy('/usr/share/rhsm/product/RHEL-5/' + cert.strip(),
'/etc/pki/product/69.pem')
break
# cleanup
disable_rhn_plugin()
if __name__ == '__main__':
# > Register our better HTTP processor as default opener for URLs.
opener = urllib2.build_opener(BetterHTTPErrorProcessor)
urllib2.install_opener(opener)
# > Gather FQDN, HOSTNAME and DOMAIN.
FQDN = socket.getfqdn()
if FQDN.find(".") != -1:
HOSTNAME = FQDN.split('.')[0]
DOMAIN = FQDN[FQDN.index('.') + 1:]
else:
HOSTNAME = FQDN
DOMAIN = None
# > Gather MAC Address.
MAC = None
try:
import uuid
mac1 = uuid.getnode()
mac2 = uuid.getnode()
if mac1 == mac2:
MAC = ':'.join(("%012X" % mac1)[i:i + 2] for i in range(0, 12, 2))
except ImportError:
if os.path.exists('/sys/class/net/eth0/address'):
address_files = ['/sys/class/net/eth0/address']
else:
address_files = glob.glob('/sys/class/net/*/address')
for f in address_files:
MAC = open(f).readline().strip().upper()
if MAC != "00:00:00:00:00:00":
break
if not MAC:
MAC = "00:00:00:00:00:00"
# > Gather API port (HTTPS), ARCHITECTURE and (OS) RELEASE
API_PORT = "443"
ARCHITECTURE = get_architecture()
try:
RELEASE = platform.linux_distribution()[1]
except AttributeError:
RELEASE = platform.dist()[1]
# > Define and parse the options
parser = OptionParser()
parser.add_option("-s", "--server", dest="foreman_fqdn", default='subscription.rhsm.redhat.com',
help="FQDN of Foreman OR Capsule - omit https://", metavar="foreman_fqdn")
parser.add_option("-l", "--login", dest="login", help="Login user for API Calls", metavar="LOGIN")
parser.add_option("-p", "--password", dest="password", help="Password for specified user. Will prompt if omitted",
metavar="PASSWORD")
parser.add_option("--legacy-login", dest="legacy_login", default='admin',
help="Login user for Satellite 5 API Calls", metavar="LOGIN")
parser.add_option("--legacy-password", dest="legacy_password",
help="Password for specified Satellite 5 user. Will prompt if omitted", metavar="PASSWORD")
parser.add_option("--legacy-purge", dest="legacy_purge", action="store_true",
help="Purge system from the Legacy environment (e.g. Sat5)")
parser.add_option("-a", "--activationkey", dest="activationkey", help="Activation Key to register the system",
metavar="ACTIVATIONKEY")
parser.add_option("-o", "--organization", dest="org",
help="Name of the Organization in Foreman that the host is to be associated with", metavar="ORG")
parser.add_option("-S", "--subscription-manager-args", dest="smargs", default="",
help="Which additional arguments shall be passed to subscription-manager", metavar="ARGS")
parser.add_option("--rhn-migrate-args", dest="rhsmargs", default="",
help="Which additional arguments shall be passed to rhn-migrate-classic-to-rhsm", metavar="ARGS")
parser.add_option("-u", "--update", dest="update", action="store_true", help="Fully Updates the System")
parser.add_option("-v", "--verbose", dest="verbose", action="store_true", help="Verbose output")
parser.add_option("-f", "--force", dest="force", action="store_true",
help="Force registration (will erase old katello and puppet certs)")
parser.add_option("-r", "--release", dest="release", default=RELEASE, help="Specify release version")
parser.add_option("-R", "--remove-obsolete-packages", dest="removepkgs", action="store_true",
help="Remove old Red Hat Network and RHUI Packages (default)", default=True)
parser.add_option("--no-remove-obsolete-packages", dest="removepkgs", action="store_false",
help="Don't remove old Red Hat Network and RHUI Packages")
parser.add_option("--get-rhsm-org-id", dest="getorgid", action="store_true", help="Get RHSM Org ID")
parser.add_option("--enablerepos", dest="enablerepos",
help="Repositories to be enabled via subscription-manager - comma separated",
metavar="enablerepos")
(options, args) = parser.parse_args()
# > Validate that the options make sense or exit with a message.
if options.getorgid:
if not options.login:
print "Must specify login and password when using the --get-rhsm-org-id param. See usage:"
# parser.print_help()
print "\nExample usage: ./rhsm-bootstrap.py --get-rhsm-org-id -l portal_user"
sys.exit(1)
if not options.password:
options.password = getpass.getpass("%s's password:" % options.login)
else:
if not (options.org or options.activationkey):
print "Must specify RHSM organization and activation key. See usage:"
# parser.print_help()
print "\nExample usage: ./rhsm-bootstrap.py -o 112233 -a My_Activation_Key"
sys.exit(1)
# > If user wants to purge profile from RHN/Satellite 5, credentials are needed.
if options.legacy_purge and not options.legacy_password:
options.legacy_password = getpass.getpass("Legacy User %s's password:" % options.legacy_login)
# > Output all parameters if verbose.
if options.verbose:
print "HOSTNAME - %s" % HOSTNAME
print "DOMAIN - %s" % DOMAIN
print "RELEASE - %s" % RELEASE
print "MAC - %s" % MAC
print "foreman_fqdn - %s" % options.foreman_fqdn
print "LOGIN - %s" % options.login
print "PASSWORD - %s" % options.password
print "ACTIVATIONKEY - %s" % options.activationkey
print "UPDATE - %s" % options.update
print "LEGACY LOGIN - %s" % options.legacy_login
print "LEGACY PASSWORD - %s" % options.legacy_password
print "RHSM GET ORG IG %s" % options.getorgid
# > Exit if the user isn't root.
# Done here to allow an unprivileged user to run the script to see
# its various options.
if os.getuid() != 0:
print_error("This script requires root-level access")
sys.exit(1)
# > Try to import json or simplejson.
# do it at this point in the code to have our custom print and exec
# functions available
try:
import json
except ImportError:
try:
import simplejson as json
except ImportError:
print_warning("Could neither import json nor simplejson, will try to install simplejson and re-import")
yum("install", "python-simplejson")
try:
import simplejson as json
except ImportError:
print_error("Could not install python-simplejson")
sys.exit(1)
if options.getorgid:
get_rhsm_orgid()
sys.exit(1)
# > Clean the environment from LD_... variables
clean_environment()
# > IF RHEL 5 and not removing, prepare the migration.
if int(RELEASE[0]) == 5:
prepare_rhel5_migration()
if check_rhn_registration():
# > ELIF registered to RHN, install subscription-manager prerequs
# > get CA RPM, optionally create host,
# > migrate via rhn-classic-migrate-to-rhsm
print_generic('This system is registered to RHN. Attempting to migrate via rhn-classic-migrate-to-rhsm')
# sys.exit(1)
install_prereqs()
check_migration_version()
configure_subscription_manager()
migrate_systems(options.org, options.activationkey)
if options.enablerepos:
enable_repos()
else:
# > ELSE get CA RPM, optionally create host,
# > register via subscription-manager
print_generic('This system is not registered to RHN. Attempting to register via subscription-manager')
configure_subscription_manager()
register_systems(options.org, options.activationkey, options.release)
if options.enablerepos:
enable_repos()
# > IF not removing, install Katello agent, optionally update host,
# > optionally clean and install Puppet agent
# > optionally remove legacy RHN packages
if options.update:
fully_update_the_box()
if options.removepkgs:
remove_obsolete_packages()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment