com.redhat.rhn.manager.kickstart.KickstartFormatter.java Source code

Java tutorial

Introduction

Here is the source code for com.redhat.rhn.manager.kickstart.KickstartFormatter.java

Source

/**
 * Copyright (c) 2009--2014 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 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;
import com.redhat.rhn.manager.kickstart.cobbler.CobblerXMLRPCHelper;

/**
 * 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) {
        CobblerSnippet.makeFragment(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")) {
                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);

        if (urlLocation.startsWith("/")) {
            log.debug("URL is not customized.");
            log.debug("Formatting for view use.");
            // /kickstart/dist/ks-rhel-i386-as-4-u2
            StringBuilder url = new StringBuilder();
            url.append("--url ");
            url.append(urlHelper.getCobblerMediaUrl());
            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);
        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, "");

        retval.append(NEWLINE);
        // Work around for bug #522251
        if (!this.ksdata.getKickstartDefaults().getKstree().getChannel().getChannelArch().getName()
                .startsWith("s390")) {
            addCobblerSnippet(retval, "post_install_network_config");
        }
        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;
                    }
                }
            }
        }
        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");
    }
}