/**
* Copyright (c) 2009--2016 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
* version 2 (GPLv2). There is NO WARRANTY for this software, express or
* implied, including the implied warranties of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
* along with this software; if not, see
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* Red Hat trademarks are not licensed under GPLv2. No permission is
* granted to use or replicate Red Hat trademarks that are incorporated
* in this software or its documentation.
*/
package com.redhat.rhn.manager.kickstart;
import com.redhat.rhn.common.conf.Config;
import com.redhat.rhn.common.conf.ConfigDefaults;
import com.redhat.rhn.domain.channel.Channel;
import com.redhat.rhn.domain.kickstart.KickstartCommand;
import com.redhat.rhn.domain.kickstart.KickstartData;
import com.redhat.rhn.domain.kickstart.KickstartInstallType;
import com.redhat.rhn.domain.kickstart.KickstartPackage;
import com.redhat.rhn.domain.kickstart.KickstartScript;
import com.redhat.rhn.domain.kickstart.KickstartSession;
import com.redhat.rhn.domain.kickstart.KickstartVirtualizationType;
import com.redhat.rhn.domain.kickstart.RegistrationType;
import com.redhat.rhn.domain.kickstart.RepoInfo;
import com.redhat.rhn.domain.kickstart.cobbler.CobblerSnippet;
import com.redhat.rhn.domain.kickstart.crypto.CryptoKey;
import com.redhat.rhn.domain.rhnpackage.Package;
import com.redhat.rhn.domain.rhnpackage.PackageFactory;
import com.redhat.rhn.domain.token.ActivationKey;
import com.redhat.rhn.domain.token.ActivationKeyFactory;
import com.redhat.rhn.domain.token.Token;
import com.redhat.rhn.domain.user.User;
import com.redhat.rhn.domain.user.UserFactory;
import com.redhat.rhn.manager.channel.ChannelManager;
import com.redhat.rhn.manager.download.DownloadManager;
import com.redhat.rhn.manager.kickstart.cobbler.CobblerXMLRPCHelper;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/**
* Simple class to reduce dependencies between Struts and database layers
*
* @version $Rev $
*/
public class KickstartFormatter {
private static Logger log = Logger.getLogger(KickstartFormatter.class);
private static final String REDHAT_REGISTER_SNIPPET = "spacewalk/redhat_register";
private static final String POST_REACTIVATION_SNIPPET =
"spacewalk/post_reactivation_key";
private static final String POST_DELETION_SNIPPET =
"spacewalk/post_delete_system";
private static final String KEEP_SYSTEM_ID_SNIPPET = "spacewalk/keep_system_id";
private static final String DEFAULT_MOTD = "spacewalk/default_motd";
private static final String RAW_START = "#raw";
private static final String RAW_END = "#end raw";
private static final String NEWLINE = "\n";
private static final String SPACE = " ";
private static final String DEPS = "--resolvedeps";
private static final String NO_BASE = "--nobase";
private static final String IGNORE_MISSING = "--ignoremissing";
private static final String PACKAGES = "%packages";
private static final String END = "%end";
private static final String INTERPRETER_OPT = "--interpreter";
private static final String NOCHROOT = "--nochroot";
private static final String ERRORONFAIL = "--erroronfail";
private static final String HEADER = "# Kickstart config file generated by " +
Config.get().getString("web.product_name") + " Config Management" +
NEWLINE;
private static final String COMMENT = "#" + NEWLINE;
private static final String RHN_LOG_FILE = "/root/ks-rhn-post.log";
private static final String BEGINRHN_LOG_APPEND = "# --Begin " +
Config.get().getString("web.product_name") + " command section--" + NEWLINE;
private static final String SAVE_KS_CFG = "cp `awk '{ if ($1 ~ /%include/) " +
"{print $2}}' /tmp/ks.cfg` /tmp/ks.cfg /mnt/sysimage/root";
private static final String POST_LOG_FILE = "/root/ks-post.log";
private static final String POST_LOG_NOCHROOT_FILE = "/mnt/sysimage/root/ks-post.log";
private static final String PRE_LOG_FILE = "/tmp/ks-pre.log";
private static final String KSTREE =
"# now copy from the ks-tree we saved in the non-chroot checkout" + NEWLINE +
"cp -fav /tmp/ks-tree-copy/* / 2>/dev/null" + NEWLINE +
"rm -Rf /tmp/ks-tree-copy" + NEWLINE +
"# --End " + Config.get().getString("web.product_name") + " command section--" +
NEWLINE;
public static final String[] UPDATE_PKG_NAMES =
{"pyOpenSSL", "rhnlib", "libxml2-python", "libxml2"};
public static final String[] FRESH_PKG_NAMES_RHEL34 =
{"up2date", "up2date-gnome"};
public static final String[] FRESH_PKG_NAMES_RHEL2 =
{"rhn_register", "up2date", "rhn_register-gnome", "up2date-gnome"};
private static final String UPDATE_OPT_PATH = "/tmp/rhn_rpms/optional/";
private static final String UPDATE_CMD = "rpm -Uvh --replacepkgs --replacefiles ";
private static final String FRESH_CMD = "rpm -Fvh /tmp/rhn_rpms/*rpm";
private static final String IMPORT_RHN_KEY34 =
"rpm --import /usr/share/rhn/RPM-GPG-KEY";
private static final String IMPORT_RHN_KEY2 =
"gpg $(up2date --gpg-flags) --batch --import /usr/share/rhn/RPM-GPG-KEY" +
NEWLINE +
"gpg $(up2date --gpg-flags) --batch --import /usr/share/rhn/RPM-GPG-KEY";
private static final String MKDIR_OPTIONAL = "mkdir -p /tmp/rhn_rpms/optional";
private static final String WGET_OPT_RPMS = "wget -P /tmp/rhn_rpms/optional ";
private static final String WGET_RPMS = "wget -P /tmp/rhn_rpms ";
private static final String REMOTE_CMD =
"mkdir -p /etc/sysconfig/rhn/allowed-actions/script" + NEWLINE +
"touch /etc/sysconfig/rhn/allowed-actions/script/run";
private static final String CONFIG_CMD =
"mkdir -p /etc/sysconfig/rhn/allowed-actions/configfiles" + NEWLINE +
"touch /etc/sysconfig/rhn/allowed-actions/configfiles/all";
private static final String RHNCHECK = "rhn_check";
private static final String RHN_NOCHROOT =
"mkdir /mnt/sysimage/tmp/ks-tree-copy" + NEWLINE +
"if [ -d /oldtmp/ks-tree-shadow ]; then" + NEWLINE +
"cp -fa /oldtmp/ks-tree-shadow/* /mnt/sysimage/tmp/ks-tree-copy" + NEWLINE +
"elif [ -d /tmp/ks-tree-shadow ]; then" + NEWLINE +
"cp -fa /tmp/ks-tree-shadow/* /mnt/sysimage/tmp/ks-tree-copy" + NEWLINE +
"fi" + NEWLINE +
"cp /etc/resolv.conf /mnt/sysimage/etc/resolv.conf" + NEWLINE +
"cp -f /tmp/ks-pre.log* /mnt/sysimage/root/ || :" + NEWLINE;
private static final String RHN_TRACE = "set -x" + NEWLINE;
private static final String XMLRPC_HOST =
Config.get().getString(ConfigDefaults.KICKSTART_HOST, "xmlrpc.rhn.redhat.com");
private static final String VIRT_HOST_GRUB_FIX =
"sed -i.backup 's/default=[0-9]*/default=0/' /boot/grub/grub.conf" + NEWLINE;
private static final String ISCRYPTED = "--iscrypted ";
//wregglej, 9/22/06 Temporary workarounds for a broken wget.
private static final String CHDIR_OPT_RPMS = "cd /tmp/rhn_rpms/optional ";
private static final String CHDIR_RPMS = "cd /tmp/rhn_rpms";
private static final String REDHAT_MGMT_SERVER = "$redhat_management_server";
public static final String STATIC_NETWORK_VAR = "static_network";
public static final String USE_IPV6_GATEWAY = "use_ipv6_gateway";
public static final String KS_DISTRO = "ks_distro";
private static final String STATIC_NETWORK_COMMAND = "network --bootproto static" +
" " + "--device %s" +
" " + "--gateway %s" +
" " + "--nameserver %s" +
" " + "--hostname %s";
private static final String STATIC_NETWORK_COMMAND1 = " " + "--ip %s" +
" " + "--netmask %s";
private static final String STATIC_NETWORK_COMMAND2 = " " + "--ipv6 %s";
private static final String STATIC_NETWORK_COMMAND3 = " " + "--ipv6 %s/%s";
private static final String NETWORK_STRING =
"#if $varExists('%s')" + NEWLINE +
"$%s" + NEWLINE +
"#else" + NEWLINE +
"%s" + NEWLINE +
"#end if" + NEWLINE;
private final KickstartData ksdata;
private final String ksHost;
private final User user;
private KickstartSession session;
private int postLogPostfix;
private int preLogPostfix;
/**
* constructor
* @param hostIn kickstart host
* @param ksdataIn KickstartData
*/
public KickstartFormatter(String hostIn, KickstartData ksdataIn) {
this.ksdata = ksdataIn;
this.ksHost = hostIn;
this.user = UserFactory.findRandomOrgAdmin(this.ksdata.getOrg());
this.postLogPostfix = 1;
this.preLogPostfix = 1;
}
/**
* Constructor with KickstartSession.
* @param hostIn that is kickstarting from
* @param ksdataIn that is is to be 'formatted' for output
* @param sessionIn associated with the formatting.
*/
public KickstartFormatter(String hostIn, KickstartData ksdataIn,
KickstartSession sessionIn) {
this(hostIn, ksdataIn);
this.session = sessionIn;
}
private void addLogBegin(StringBuilder buff, String logFile, String interpreter) {
if (ksdata.isRhel6OrGreater()) {
buff.append(" --log " + logFile);
}
else if (isBashInterpreter(interpreter)) {
buff.append(NEWLINE + "(");
}
buff.append(NEWLINE);
}
private void addLogEnd(StringBuilder buff, String logFile, String interpreter) {
if (ksdata.isRhel6OrGreater()) {
//nothing
}
else if (isBashInterpreter(interpreter)) {
buff.append(") >> " + logFile + " 2>&1" + NEWLINE);
}
}
/**
* Everythign RHEL 5 and older should not use %end at the end of
* each section, but anything fedora (version 8 and above) and RHEL 6
* can handle it (it's optional). Fedora 14 requires it!
* @param buff the String buffer to append to
*/
private void addEnd(StringBuilder buff) {
if (!ksdata.isRHEL5OrLess()) {
buff.append(END + NEWLINE);
}
}
/**
*
* @return String containing kickstart file
*/
public String getFileData() {
RegistrationType regType = ksdata.getRegistrationType(user);
List<KickstartScript> l = new LinkedList<KickstartScript>(this.ksdata.getScripts());
Collections.sort(l);
List<KickstartScript> preScripts = new ArrayList<KickstartScript>();
List<KickstartScript> postBeforeRedHatScripts = new ArrayList<KickstartScript>();
List<KickstartScript> postAfterRedHatScripts = new ArrayList<KickstartScript>();
for (KickstartScript ks : l) {
if (ks.getScriptType().equals(KickstartScript.TYPE_PRE)) {
preScripts.add(ks);
}
else if (ks.getPosition() < 0L) {
postBeforeRedHatScripts.add(ks);
}
else {
postAfterRedHatScripts.add(ks);
}
}
StringBuilder buf = new StringBuilder();
buf.append(getHeader());
buf.append(getCommands());
/*if (this.ksdata.isRhel5OrGreater()) {
buf.append(getRepoCommands());
buf.append(getKeyCommands());
}*/
buf.append(NEWLINE);
buf.append(getPackageOptions());
buf.append(getPackages());
addEnd(buf);
buf.append(NEWLINE);
buf.append("%" + KickstartScript.TYPE_PRE);
buf.append(NEWLINE);
if (CobblerXMLRPCHelper.getCobblerVersion() >= 2.2) {
addCobblerSnippet(buf, "kickstart_start");
}
else {
buf.append("$kickstart_start");
buf.append(NEWLINE);
}
buf.append(NEWLINE);
addCobblerSnippet(buf, "pre_install_network_config");
buf.append(NEWLINE);
if (!RegistrationType.NONE.equals(regType)) {
addCobblerSnippet(buf, KEEP_SYSTEM_ID_SNIPPET);
addEnd(buf);
}
else {
addEnd(buf);
}
buf.append(renderScripts(preScripts));
buf.append(NEWLINE);
// This script should always be the first post script to run
buf.append("%" + KickstartScript.TYPE_POST + SPACE + NOCHROOT + NEWLINE);
buf.append(RHN_NOCHROOT + NEWLINE);
if (this.ksdata.getKsCfg()) {
buf.append(SAVE_KS_CFG + NEWLINE);
}
addEnd(buf);
buf.append(renderScripts(postBeforeRedHatScripts));
buf.append(NEWLINE);
if (RegistrationType.REACTIVATION.equals(regType)) {
addCobblerSnippet(buf, POST_REACTIVATION_SNIPPET);
addEnd(buf);
}
else if (RegistrationType.DELETION.equals(regType)) {
addCobblerSnippet(buf, POST_DELETION_SNIPPET);
addEnd(buf);
}
buf.append(NEWLINE);
buf.append(getRhnPost());
buf.append(NEWLINE);
buf.append(renderScripts(postAfterRedHatScripts));
buf.append(NEWLINE);
buf.append("%" + KickstartScript.TYPE_POST); //new %post for last kernel stuff
addCobblerSnippet(buf, "post_install_kernel_options");
addCobblerSnippet(buf, "koan_environment");
buf.append(NEWLINE);
if (CobblerXMLRPCHelper.getCobblerVersion() >= 2.2) {
addCobblerSnippet(buf, "kickstart_done");
}
else {
buf.append("$kickstart_done");
}
buf.append(NEWLINE);
addEnd(buf);
String retval = buf.toString();
log.debug("fileData.retval:");
log.debug(retval);
return retval;
}
private void addCobblerSnippet(StringBuilder buf, String contents) {
buf.append(CobblerSnippet.makeFragment(contents));
buf.append(NEWLINE);
}
/**
*
* @return static string header
*/
private StringBuffer getHeader() {
StringBuffer header = new StringBuffer();
header.append(ConfigDefaults.get().getKickstartTemplateHeader()).append(NEWLINE);
header.append(HEADER);
header.append(COMMENT);
header.append("# Profile Label : " + this.ksdata.getLabel() + NEWLINE);
header.append("# Date Created : " + this.ksdata.getCreated() + NEWLINE);
header.append(COMMENT);
header.append(NEWLINE);
return header;
}
/**
*
* @return string containing kickstart commands
*/
private String getCommands() {
StringBuilder commands = new StringBuilder();
LinkedList l = new LinkedList(this.ksdata.getCommands());
Collections.sort(l);
for (Iterator itr = l.iterator(); itr.hasNext();) {
KickstartCommand command = (KickstartCommand) itr.next();
String cname = command.getCommandName().getName();
log.debug("getCommands name: " + cname);
if (cname.matches("rootpw")) {
commands.append(cname + SPACE + ISCRYPTED +
command.getArguments() + NEWLINE);
}
else if (cname.matches("url")) {
if (command.getArguments() != null) {
String argVal = adjustUrlHost(command);
commands.append(cname + SPACE + argVal + NEWLINE);
}
}
else if (cname.matches("repo")) {
RepoInfo repo = RepoInfo.parse(command);
commands.append(repo.getFormattedCommand(ksdata) + NEWLINE);
}
else if ("custom".equals(cname)) {
commands.append(command.getArguments() + NEWLINE);
}
else if ("network".equals(cname)) {
commands.append(String.format(NETWORK_STRING, STATIC_NETWORK_VAR,
STATIC_NETWORK_VAR,
cname + SPACE + command.getArguments()));
}
else {
String argVal = command.getArguments();
// some commands don't require an arg and are null in db
if (argVal == null) {
commands.append(cname).append(NEWLINE);
}
else {
commands.append(cname + SPACE + argVal + NEWLINE);
}
}
}
if (ksdata.isRhel5OrGreater() &&
!Config.get().getBoolean("ks_restrict_child_channels")) {
for (Channel child : ksdata.getChildChannels()) {
KickstartUrlHelper helper = new KickstartUrlHelper(ksdata);
commands.append(String.format("repo --name=%s --baseurl=%s",
child.getLabel(), helper.getKickstartChildRepoUrl(child) + NEWLINE));
}
}
commands.append(ksdata.getPartitionData() + NEWLINE);
return commands.toString();
}
/**
* Returns the network line for static networks
* network --bootproto static --device $DEVICE --ip $IPADDR
* --gateway $GATEWAY --nameserver $NAMESERVER
* --netmask $NETMASK --hostname $HOSTNAME
* @param device the network interface name (eth0)
* @param ip the ip address of the interface
* @param gateway the gateway information of the card
* @param nameServer the nameserver information
* @param netmask the netmask information
* @param hostName the host name information
* @return the network* line for a static host
*/
public static String makeStaticNetworkCommand(String device,
String ip, String gateway,
String nameServer, String netmask, String hostName) {
return String.format(STATIC_NETWORK_COMMAND + STATIC_NETWORK_COMMAND1, device,
gateway, nameServer, hostName, ip, netmask);
}
/**
* Returns the network line for static networks
* network --bootproto static --device $DEVICE --ip $IPADDR --ipv6 $IP6ADDR
* --gateway $GATEWAY --nameserver $NAMESERVER
* --netmask $NETMASK --hostname $HOSTNAME
* @param device the network interface name (eth0)
* @param hostName the host name info
* @param nameServer the nameserver info
* @param ip4 the ipv4 address of the interface
* @param nm4 the ipv4 netmask of the interface
* @param gw4 the ipv4 gateway
* @param ip6 the ipv6 address of the interface
* @param nm6 the ipv6 netmask of the interface
* @param gw6 the ipv6 gateway
* @param preferIpv6Gateway whether or not should ipv6 gateway be prefered
* @param ksDistro distro to be provisioned
* @return the network* line for a static host
*/
public static String makeStaticNetworkCommand(String device, String hostName,
String nameServer, String ip4, String nm4, String gw4,
String ip6, String nm6, String gw6, boolean preferIpv6Gateway,
String ksDistro) {
String gateway;
if (preferIpv6Gateway && gw6 != null && gw6.length() != 0) {
gateway = gw6;
}
else {
gateway = gw4;
}
String command = String.format(STATIC_NETWORK_COMMAND, device, gateway,
nameServer, hostName);
if (ip4 != null && ip4.length() > 0 && nm4 != null && nm4.length() > 0) {
command += String.format(STATIC_NETWORK_COMMAND1, ip4, nm4);
}
else {
command += " --noipv4";
}
if (ip6 != null && ip6.length() > 0 &&
(KickstartInstallType.FEDORA.equals(ksDistro) ||
KickstartInstallType.RHEL_6.equals(ksDistro))) {
if (nm6 == null || nm6.length() == 0 ||
!KickstartInstallType.FEDORA.equals(ksDistro)) {
command += String.format(STATIC_NETWORK_COMMAND2, ip6);
}
else {
command += String.format(STATIC_NETWORK_COMMAND3, ip6, nm6);
}
}
return command;
}
/**
* Adjust the URL hostname if necessary. Hostnames are stored in the db as relative
* paths if the user selects to use the default URL. When rendered we need to swap
* in the most appropriate hostname.
*
* If this hostname appears to be customized, no change is made and we return the URL
* as is.
*/
private String adjustUrlHost(KickstartCommand command) {
String argVal = command.getArguments();
String urlLocation;
if (argVal.startsWith("--url")) {
urlLocation = argVal.substring("--url ".length());
}
else {
urlLocation = argVal;
}
KickstartUrlHelper urlHelper = new KickstartUrlHelper(this.ksdata);
log.debug("Got URL : " + command.getArguments());
log.debug("isRhnTree: " + this.ksdata.getTree().isRhnTree());
log.debug("Actual URL: " + urlLocation);
StringBuilder url = new StringBuilder();
url.append("--url ");
if (urlLocation.equals(this.ksdata.getTree().getAbsolutePath())) {
log.debug("URL is not customized.");
log.debug("Formatting for view use.");
// /kickstart/dist/ks-rhel-i386-as-4-u2
url.append(urlHelper.getCobblerMediaUrl());
log.debug("constructed: " + url);
argVal = url.toString();
}
else if (urlLocation.startsWith("/")) {
log.debug("URL is customized.");
log.debug("Appending provided subpath to cobbler host.");
url.append(urlHelper.getCobblerMediaUrlBase());
url.append(urlLocation);
log.debug("constructed: " + url);
argVal = url.toString();
}
else {
log.debug("Just return the arg value.");
}
log.debug("returning url: " + argVal);
return argVal;
}
/**
*
* @return string containing package options
*/
private String getPackageOptions() {
// if kstree is > 2.1 then add the resolve deps, ignore other deps
String opts = this.ksdata.isRhel2() || this.ksdata.isRhel5OrGreater() ? "" : DEPS;
if (this.ksdata.getIgnoreMissing()) {
opts = opts + SPACE + IGNORE_MISSING;
}
if (this.ksdata.getNoBase()) {
opts = opts + SPACE + NO_BASE;
}
return PACKAGES + SPACE + opts + NEWLINE;
}
/**
*
* @return string containing packages
*/
private String getPackages() {
StringBuilder buf = new StringBuilder();
for (KickstartPackage kp : ksdata.getKsPackages()) {
buf.append(kp.getPackageName().getName() + NEWLINE);
}
if (KickstartVirtualizationType.paraHost().equals(ksdata.getKickstartDefaults().
getVirtualizationType())) {
buf.append("kernel-xen" + NEWLINE);
buf.append("xen" + NEWLINE);
}
// packages necessary for rhel2.1
if (this.ksdata.isRhel2()) {
buf.append("@ Network Support" + NEWLINE);
buf.append("openssh-server" + NEWLINE);
}
// packages necessary for RHEL 7
if (this.ksdata.isRhel7()) {
buf.append("perl" + NEWLINE);
buf.append("wget" + NEWLINE);
buf.append("rhn-setup" + NEWLINE);
buf.append("rhn-check" + NEWLINE);
buf.append("rhn-client-tools" + NEWLINE);
}
return buf.toString();
}
/**
* @param scrupts the kickstart scripts we want to render
* @return rendered script(s)
*/
private String renderScripts(List<KickstartScript> scripts) {
StringBuilder retval = new StringBuilder();
for (KickstartScript kss : scripts) {
boolean isPre = kss.getScriptType().equals(KickstartScript.TYPE_PRE);
retval.append(NEWLINE);
if (kss.getRaw()) {
retval.append(RAW_START + NEWLINE);
}
String command = "%" + kss.getScriptType();
if (!isPre && !kss.thisScriptIsChroot()) {
command += SPACE + NOCHROOT;
}
if (kss.getErrorOnFail()) {
command += SPACE + ERRORONFAIL;
}
if (!StringUtils.isBlank(kss.getInterpreter())) {
command += SPACE + INTERPRETER_OPT + SPACE + kss.getInterpreter();
}
retval.append(command);
if (ksdata.getPreLog() && isPre) {
addLogBegin(retval, PRE_LOG_FILE + "." + this.preLogPostfix,
kss.getInterpreter());
}
else if (ksdata.getPostLog() && !isPre && kss.thisScriptIsChroot()) {
addLogBegin(retval, POST_LOG_FILE + "." + this.postLogPostfix,
kss.getInterpreter());
}
else if (ksdata.getNonChrootPost() && !isPre && !kss.thisScriptIsChroot()) {
addLogBegin(retval, POST_LOG_NOCHROOT_FILE + "." + this.postLogPostfix,
kss.getInterpreter());
if (isBashInterpreter(kss.getInterpreter())) {
retval.append(RHN_TRACE);
}
}
else {
retval.append(NEWLINE);
}
retval.append(kss.getDataContents() + NEWLINE);
if (ksdata.getPreLog() && isPre) {
addLogEnd(retval, PRE_LOG_FILE + "." + kss.getPosition(),
kss.getInterpreter());
this.preLogPostfix += 1;
}
else if (ksdata.getPostLog() && !isPre && kss.thisScriptIsChroot()) {
addLogEnd(retval, POST_LOG_FILE + "." + this.postLogPostfix,
kss.getInterpreter());
this.postLogPostfix += 1;
}
else if (ksdata.getNonChrootPost() && !isPre && !kss.thisScriptIsChroot()) {
addLogEnd(retval, POST_LOG_NOCHROOT_FILE + "." + this.postLogPostfix,
kss.getInterpreter());
this.postLogPostfix += 1;
}
if (kss.getRaw()) {
retval.append(RAW_END + NEWLINE);
}
addEnd(retval);
} // end loop
return retval.toString();
}
private String getRhnPost() {
log.debug("getRhnPost called.");
StringBuilder retval = new StringBuilder();
retval.append("%" + KickstartScript.TYPE_POST);
addLogBegin(retval, RHN_LOG_FILE, "");
retval.append(BEGINRHN_LOG_APPEND);
retval.append(renderKeys() + NEWLINE);
List<ActivationKey> tokens = generateActKeyTokens(this.ksdata,
this.session);
HashSet updatePackages = getUpdatePackages(tokens);
HashSet freshPackages = getFreshPackages(tokens);
boolean isFresh = freshPackages.size() > 0;
boolean isUpdate = updatePackages.size() > 0;
// update the required/optional packages needed for the kickstart
if (isUpdate || isFresh) {
log.debug("need latest up2date");
//order matters, therfore multiple logic branches
retval.append(MKDIR_OPTIONAL + NEWLINE);
if (isUpdate) {
//wregglej - wget is broken, so workaround it.
retval.append(CHDIR_OPT_RPMS + NEWLINE);
retval.append(WGET_OPT_RPMS);
for (Iterator itr = updatePackages.iterator(); itr.hasNext();) {
retval.append(itr.next().toString() + SPACE);
}
retval.append(NEWLINE);
}
if (isFresh) {
//wregglej - work around wget again.
retval.append(CHDIR_RPMS + NEWLINE);
retval.append(WGET_RPMS);
for (Iterator itr = freshPackages.iterator(); itr.hasNext();) {
retval.append(itr.next().toString() + SPACE);
}
retval.append(NEWLINE);
}
if (isUpdate) {
retval.append(UPDATE_CMD);
for (int i = 0; i < UPDATE_PKG_NAMES.length; i++) {
retval.append(UPDATE_OPT_PATH + UPDATE_PKG_NAMES[i] + "* ");
}
retval.append(NEWLINE);
}
if (isFresh) {
retval.append(FRESH_CMD + NEWLINE);
}
}
if (this.ksdata.getKickstartDefaults().getVirtualizationType()
.getLabel().equals("para_host")) {
retval.append(VIRT_HOST_GRUB_FIX);
}
// For rhel2,3,4 we import a different key. otherwise we just
// rely on the cobbler snippet below to import the key.
if (this.ksdata.isRhel2()) {
retval.append(IMPORT_RHN_KEY2 + NEWLINE);
}
else if (this.ksdata.isRhel3() || this.ksdata.isRhel4()) {
retval.append(IMPORT_RHN_KEY34 + NEWLINE);
}
if (log.isDebugEnabled()) {
log.debug("kickstart_host: [" + XMLRPC_HOST + "] kshost: [" +
this.ksHost + "] indexof: " +
this.ksHost.indexOf(XMLRPC_HOST));
}
String up2datehost = REDHAT_MGMT_SERVER;
//check if server going through Spacewalk Proxy,
//if so, register through proxy instead
if (this.session != null &&
this.session.getSystemRhnHost() != null &&
!this.session.getSystemRhnHost().equals("unknown")) {
up2datehost = this.session.getSystemRhnHost();
}
log.debug("adding perl -npe for /etc/sysconfig/rhn/up2date");
if (this.ksdata.isRhel2()) {
retval.append("perl -npe " +
"'s|^(\\s*(noSSLS\\|s)erverURL\\s*=\\s*[^:]+://)[^/]*/|${1}" +
up2datehost +
"/|' -i /etc/sysconfig/rhn/rhn_register" + NEWLINE);
}
// both rhel 2 and rhel3/4 need the following
retval.append("perl -npe " +
"'s|^(\\s*(noSSLS\\|s)erverURL\\s*=\\s*[^:]+://)[^/]*/|\\${1}" +
up2datehost +
"/|' -i /etc/sysconfig/rhn/up2date" + NEWLINE);
if (this.ksdata.getVerboseUp2date()) {
retval.append("[ -r /etc/yum.conf ] && " +
"perl -npe 's/debuglevel=2/debuglevel=5/' -i /etc/yum.conf" +
NEWLINE);
retval.append("[ -r /etc/sysconfig/rhn/up2date ] && " +
"perl -npe 's/debug=0/debug=1/' -i /etc/sysconfig/rhn/up2date" +
NEWLINE);
}
if (this.ksdata.getKickstartDefaults().getRemoteCommandFlag().booleanValue()) {
retval.append(REMOTE_CMD + NEWLINE);
}
if (this.ksdata.getKickstartDefaults().getCfgManagementFlag().booleanValue()) {
retval.append(CONFIG_CMD + NEWLINE);
}
retval.append(NEWLINE);
retval.append(KSTREE);
retval.append(NEWLINE);
//RHEL 5u4 hack for bz 495680
if (ksdata.isRhel5()) {
retval.append("/etc/init.d/messagebus restart" + NEWLINE);
retval.append("/etc/init.d/haldaemon restart" + NEWLINE);
}
retval.append("# begin cobbler snippet" + NEWLINE);
retval.append(NEWLINE);
// Work around for bug #522251
if (!this.ksdata.getKickstartDefaults().getKstree().getChannel().
getChannelArch().getName().startsWith("s390")) {
addCobblerSnippet(retval, "post_install_network_config");
}
addCobblerSnippet(retval, DEFAULT_MOTD);
addCobblerSnippet(retval, REDHAT_REGISTER_SNIPPET);
retval.append("# end cobbler snippet" + NEWLINE);
retval.append(NEWLINE);
retval.append(RHNCHECK + NEWLINE);
addLogEnd(retval, RHN_LOG_FILE, "");
addEnd(retval);
return retval.toString();
}
/**
* Generate a comma separated list of activation keys to use with the
* associated KickstartData and KickstartSession
* @param ksdata to get list from
* @param ksession session containing keys
*
* @return String list of activationkeys separated by comman
*/
public static String generateActivationKeyString(KickstartData ksdata,
KickstartSession ksession) {
StringBuilder retval = new StringBuilder();
List<ActivationKey> tokens = generateActKeyTokens(ksdata, ksession);
for (Iterator itr = tokens.iterator(); itr.hasNext();) {
ActivationKey act = (ActivationKey) itr.next();
log.debug("rhnreg: key name: " + act.getKey());
retval.append(act.getKey());
if (itr.hasNext()) {
retval.append(",");
}
}
log.debug("generateActivationKeyString: " + retval);
return retval.toString();
}
/**
* @return
*/
private static List<ActivationKey> generateActKeyTokens(KickstartData ksdata,
KickstartSession ksession) {
List<ActivationKey> tokens = new ArrayList<ActivationKey>();
log.debug("Computing Activation Keys");
// If we are in a KickstartSession and dont have any activation keys
// associated with this KickstartProfile then we want to create a
// one time key.
if (log.isDebugEnabled()) {
log.debug("def reg tokens: " + ksdata.getDefaultRegTokens());
}
ActivationKey defaultKey = ksession == null ? null :
ActivationKeyFactory.lookupByKickstartSession(ksession);
log.debug("generateActKeyTokens :: defaultKey: " + defaultKey);
//if we need a reactivation key, add one
if (defaultKey != null) {
log.debug("Session isn't null. Lets use the profile's activation key.");
//ActivationKey oneTimeKey = ActivationKeyFactory.
// lookupByKickstartSession(this.session);
tokens.add(defaultKey);
if (log.isDebugEnabled()) {
log.debug("Found one time activation key: " + defaultKey.getKey());
}
}
log.debug("tokens size: " + tokens.size());
//add the activation keys associated with the kickstart profile
if (ksdata.getDefaultRegTokens() != null) {
if (ksdata.getDefaultRegTokens().size() > 0) {
for (Iterator itr = ksdata.getDefaultRegTokens().iterator();
itr.hasNext();) {
Token tk = (Token)itr.next();
ActivationKey act =
ActivationKeyFactory.lookupByToken(tk);
tokens.add(act);
}
}
}
return tokens;
}
private String renderKeys() {
StringBuilder retval = new StringBuilder();
HashSet sslKeys = new HashSet();
HashSet gpgKeys = new HashSet();
// setup keys for rendering
if (this.ksdata.getCryptoKeys() != null) {
for (Iterator itr = this.ksdata.getCryptoKeys().iterator(); itr.hasNext();) {
CryptoKey tmpKey = (CryptoKey)itr.next();
if (tmpKey.isGPG()) {
gpgKeys.add(tmpKey);
}
else if (tmpKey.isSSL()) {
sslKeys.add(tmpKey);
}
}
}
if (gpgKeys.size() > 0) {
retval.append(renderGpgKeys(gpgKeys));
}
if (sslKeys.size() > 0) {
retval.append(renderSslKeys(sslKeys));
}
return retval.toString();
}
/**
*
* @return list of packages we need to up2date
*/
private HashSet<String> getUpdatePackages(List<ActivationKey> keys) {
log.debug("getUpdatePackages() ..");
HashSet<String> retval = new HashSet<String>();
Channel c = ksdata.getKickstartDefaults().getKstree().getChannel();
for (ActivationKey key : keys) {
if (key.getChannels() != null) {
for (Channel chan : key.getChannels()) {
if (chan.isBaseChannel()) {
c = chan;
break;
}
}
}
}
if (ksdata.isRhel4()) {
for (int i = 0; i < UPDATE_PKG_NAMES.length; i++) {
Long packageId = ChannelManager.getLatestPackageEqualInTree(c.getId(),
UPDATE_PKG_NAMES[i]);
if (packageId == null) {
log.debug("package:" + packageId + "not found in kickstart's channel");
continue;
}
log.debug("package : " + UPDATE_PKG_NAMES[i]);
log.debug("packageId: " + packageId);
Package p =
PackageFactory.lookupByIdAndUser(packageId, user);
if (p != null) {
retval.add(getSHA1PackagePath(p));
}
}
}
return retval;
}
private String getSHA1PackagePath(Package p) {
String retval = null;
if (p != null) {
retval = "http://" + REDHAT_MGMT_SERVER +
DownloadManager.getPackageDownloadPathNoExpiration(p, user);
}
return retval;
}
/**
*
* @return list of optional packages we need to up2date to the latest nvr
*/
private HashSet<String> getFreshPackages(List<ActivationKey> keys) {
Channel c = ksdata.getKickstartDefaults().getKstree().getChannel();
for (ActivationKey key : keys) {
for (Channel chan : key.getChannels()) {
if (chan.isBaseChannel()) {
c = chan;
break;
}
}
}
String[] pkglist = {};
if (ksdata.isRhel2()) {
pkglist = FRESH_PKG_NAMES_RHEL2;
}
else if (ksdata.isRhel3() || ksdata.isRhel4()) {
pkglist = FRESH_PKG_NAMES_RHEL34;
}
HashSet<String> retval = new HashSet<String>();
for (String pkg : pkglist) {
Long packageId = ChannelManager.getLatestPackageEqualInTree(c.getId(), pkg);
if (packageId != null) {
Package p = PackageFactory.lookupByIdAndUser(packageId, user);
if (p != null) {
retval.add(getSHA1PackagePath(p));
}
}
}
return retval;
}
/**
* Helper method to render gpg keys for kickstart file
* @param setIn of gpg keys for this kickstart
* @return rendered gpg key string for kickstart
*/
private String renderGpgKeys(HashSet<CryptoKey> setIn) {
StringBuilder retval = new StringBuilder();
int peg = 1;
for (CryptoKey myKey : setIn) {
retval.append("cat > /tmp/gpg-key-" + peg + " <<'EOF'" + NEWLINE);
retval.append(myKey.getKeyString() + NEWLINE);
retval.append("EOF\n# gpg-key" + peg + NEWLINE);
if (this.ksdata.isRhel2()) {
retval.append(
"gpg $(up2date --gpg-flags) --batch --import /tmp/gpg-key-" +
peg + "\ngpg $(up2date --gpg-flags) --batch --import " +
"/tmp/gpg-key-" + peg + NEWLINE);
}
else {
retval.append("rpm --import /tmp/gpg-key-" + peg + NEWLINE);
}
peg++;
}
return retval.toString();
}
/**
* Helper method to render ssl keys for kickstart file
* @param setIn of sll keys for this kickstart
* @return rendered sll key string for kickstart
*/
private String renderSslKeys(HashSet setIn) {
StringBuilder retval = new StringBuilder();
int peg = 1;
for (Iterator itr = setIn.iterator(); itr.hasNext();) {
retval.append("cat > /tmp/ssl-key-" + peg + " <<'EOF'" + NEWLINE);
CryptoKey myKey = (CryptoKey)itr.next();
retval.append(myKey.getKeyString() + NEWLINE);
retval.append(NEWLINE);
retval.append("EOF\n# ssl-key" + peg + NEWLINE);
peg++;
}
retval.append("cat /tmp/ssl-key-* > /usr/share/rhn/RHN-ORG-TRUSTED-SSL-CERT" +
NEWLINE);
retval.append("perl -pe 's/RHNS-CA-CERT/RHN-ORG-TRUSTED-SSL-CERT/g' " +
"-i /etc/sysconfig/rhn/up2date" + NEWLINE);
return retval.toString();
}
/**
* Detects whether the interpreter is set to bash
* @param interpreter interpreter
* @return True if interpreter is bash
*/
private boolean isBashInterpreter(String interpreter) {
return StringUtils.isBlank(interpreter) || interpreter.endsWith("bash");
}
}