/**
* Copyright (c) 2009--2015 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.ConfigDefaults;
import com.redhat.rhn.common.db.datasource.DataResult;
import com.redhat.rhn.common.db.datasource.ModeFactory;
import com.redhat.rhn.common.db.datasource.SelectMode;
import com.redhat.rhn.common.hibernate.HibernateFactory;
import com.redhat.rhn.common.localization.LocalizationService;
import com.redhat.rhn.common.security.PermissionException;
import com.redhat.rhn.common.validator.ValidatorError;
import com.redhat.rhn.domain.action.Action;
import com.redhat.rhn.domain.action.ActionFactory;
import com.redhat.rhn.domain.action.kickstart.KickstartAction;
import com.redhat.rhn.domain.channel.Channel;
import com.redhat.rhn.domain.channel.ChannelArch;
import com.redhat.rhn.domain.channel.ChannelFactory;
import com.redhat.rhn.domain.kickstart.KickstartData;
import com.redhat.rhn.domain.kickstart.KickstartFactory;
import com.redhat.rhn.domain.kickstart.KickstartSession;
import com.redhat.rhn.domain.kickstart.KickstartSessionState;
import com.redhat.rhn.domain.kickstart.KickstartVirtualizationType;
import com.redhat.rhn.domain.kickstart.RegistrationType;
import com.redhat.rhn.domain.rhnpackage.Package;
import com.redhat.rhn.domain.rhnpackage.PackageEvr;
import com.redhat.rhn.domain.rhnpackage.PackageEvrFactory;
import com.redhat.rhn.domain.rhnpackage.PackageFactory;
import com.redhat.rhn.domain.rhnpackage.profile.Profile;
import com.redhat.rhn.domain.rhnpackage.profile.ProfileFactory;
import com.redhat.rhn.domain.server.NetworkInterface;
import com.redhat.rhn.domain.server.Server;
import com.redhat.rhn.domain.server.ServerConstants;
import com.redhat.rhn.domain.server.ServerFactory;
import com.redhat.rhn.domain.token.ActivationKey;
import com.redhat.rhn.domain.token.ActivationKeyFactory;
import com.redhat.rhn.domain.user.User;
import com.redhat.rhn.frontend.dto.PackageListItem;
import com.redhat.rhn.frontend.dto.ProfileDto;
import com.redhat.rhn.frontend.dto.kickstart.CobblerProfileDto;
import com.redhat.rhn.frontend.dto.kickstart.KickstartDto;
import com.redhat.rhn.manager.action.ActionManager;
import com.redhat.rhn.manager.channel.ChannelManager;
import com.redhat.rhn.manager.kickstart.cobbler.CobblerSystemCreateCommand;
import com.redhat.rhn.manager.kickstart.cobbler.CobblerXMLRPCHelper;
import com.redhat.rhn.manager.profile.ProfileManager;
import com.redhat.rhn.manager.rhnpackage.PackageManager;
import com.redhat.rhn.manager.system.BaseSystemOperation;
import com.redhat.rhn.manager.system.SystemManager;
import com.redhat.rhn.manager.token.ActivationKeyManager;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.cobbler.CobblerConnection;
import org.cobbler.SystemRecord;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Provides frequently used data for scheduling a kickstart
*
* Throughout this class you'll find references to two different servers: the host
* server and the target server. The target server is always the system being
* kickstarted. The host server is the system through which the kickstart is being
* performed; it can be thought of as a type of liason. The host server receives the
* kickstart actions, performs the actions on the target server, and represents the
* target server in the UI.
*
* For most kickstarts, the host server is the same as the target server; that is, the
* system being kickstarted is performing the kickstart on itself.
*
* For other types of kickstarts, such as in the case of virtual guests, the system
* being kickstarted is different from the system hosting the kickstart. The virtual
* host system performs the kickstart on the guest. When this happens, one of two
* situations is relevant:
*
* (1) There is no previously-existing target system; the host system must create
* it from scratch. In this scenario, null is passed in as the target system's
* ID (simply because it is not known yet).
*
* (2) There is a previously-existing target system and the host must kickstart it.
* In this scenario, the target system's ID is not null, but is also not the same
* as the host system's ID.
*
* Because of the distinction between host and target servers, constructors in this
* class which accept a single server ID will automatically assume that the system
* being kickstarted is both the host and the target system.
*
* @version $Rev $
*/
public class KickstartScheduleCommand extends BaseSystemOperation {
private static Logger log = Logger.getLogger(KickstartScheduleCommand.class);
public static final String DHCP_NETWORK_TYPE = "dhcp";
public static final String LINK_NETWORK_TYPE = "link";
// up2date is required to be 2.9.0
public static final String UP2DATE_VERSION = "2.9.0";
public static final String TARGET_PROFILE_TYPE_EXISTING = "existing";
public static final String TARGET_PROFILE_TYPE_PACKAGE = "package";
public static final String TARGET_PROFILE_TYPE_SYSTEM = "system";
public static final String TARGET_PROFILE_TYPE_NONE = "none";
public static final String PACKAGE_TO_REMOVE = "rhn-kickstart-virtualization";
private KickstartData ksdata;
protected String cobblerProfileLabel;
protected boolean cobblerOnly;
private KickstartSession kickstartSession;
private Date scheduleDate;
private List packagesToInstall;
private String profileType;
private String proxyHost;
private Server targetServer;
// Id of the server chosen when we
// sync to a different server's profile
private Long serverProfileId;
// Id of the stored profile chosen
private Long profileId;
// Profile created from this KS
private Profile createdProfile;
// Static device
private String networkInterface;
private boolean useIpv6Gateway = false;
private boolean isDhcp;
private String kernelOptions;
private String postKernelOptions;
// The server who serves the kickstarts
private String kickstartServerName;
// The id of the action scheduled to perform the kickstart
private Action scheduledAction;
// Bond configuration
private boolean createBond;
private String bondInterface;
private List<String> bondSlaveInterfaces;
private String bondOptions;
private boolean isBondDhcp;
private String bondAddress;
private String bondNetmask;
private String bondGateway;
/**
* Constructor for a kickstart where the host and the target are the same system.
* @param selectedServer server to kickstart
* @param userIn user performing the kickstart
*/
public KickstartScheduleCommand(Long selectedServer, User userIn) {
super(selectedServer);
initialize(selectedServer, selectedServer, userIn);
}
/**
* Constructor for a kickstart where the host and the target are the same system.
* @param selectedServer server to kickstart
* @param ksid id of the KickstartData we are using
* @param userIn user performing the kickstart
*/
public KickstartScheduleCommand(Long selectedServer, Long ksid,
User userIn) {
this(selectedServer, ksid, userIn, null, null);
}
/**
* Constructor for a kickstart where the host and the target are the same system.
* To be used when you want to call the store() method.
*
* @param selectedServer server to kickstart
* @param ksid id of the KickstartData we are using
* @param userIn user performing the kickstart
* @param scheduleDateIn Date to schedule the KS.
* @param kickstartServerNameIn the name of the server who is serving the kickstart
*/
public KickstartScheduleCommand(Long selectedServer,
Long ksid,
User userIn,
Date scheduleDateIn,
String kickstartServerNameIn) {
this(selectedServer,
selectedServer,
ksid,
userIn,
scheduleDateIn,
kickstartServerNameIn);
}
/**
* Constructor for a kickstart where the host and the target are the same system.
* To be used when you want to call the store() method.
*
* @param selectedServer server to kickstart
* @param data the KickstartData we are using
* @param userIn user performing the kickstart
* @param scheduleDateIn Date to schedule the KS.
* @param kickstartServerNameIn the name of the server who is serving the kickstart
*/
public KickstartScheduleCommand(Long selectedServer,
KickstartData data,
User userIn,
Date scheduleDateIn,
String kickstartServerNameIn) {
this(selectedServer,
selectedServer,
data,
userIn,
scheduleDateIn,
kickstartServerNameIn);
}
/**
* Constructor for a kickstart where the host and the target may or may *not* be
* the same system. If the target system does not yet exist, selectedTargetServer
* should be null. To be used when you want to call the store() method.
*
* @param selectedHostServer server to host the kickstart
* @param selectedTargetServer server to be kickstarted
* @param ksid id of the KickstartData we are using
* @param userIn user performing the kickstart
* @param scheduleDateIn Date to schedule the KS.
* @param kickstartServerNameIn the name of the server who is serving the kickstart
*/
public KickstartScheduleCommand(Long selectedHostServer,
Long selectedTargetServer,
Long ksid,
User userIn,
Date scheduleDateIn,
String kickstartServerNameIn) {
this(selectedHostServer,
selectedTargetServer,
KickstartFactory.lookupKickstartDataByIdAndOrg(userIn.getOrg(), ksid),
userIn,
scheduleDateIn,
kickstartServerNameIn);
}
/**
* Constructor for a kickstart where the host and the target may or may *not* be
* the same system. If the target system does not yet exist, selectedTargetServer
* should be null. To be used when you want to call the store() method.
*
* @param selectedHostServer server to host the kickstart
* @param selectedTargetServer server to be kickstarted
* @param ksLabel label of the KickstartData we are using
* @param userIn user performing the kickstart
* @param scheduleDateIn Date to schedule the KS.
* @param kickstartServerNameIn the name of the server who is serving the kickstart
*/
public KickstartScheduleCommand(Long selectedHostServer,
Long selectedTargetServer,
String ksLabel,
User userIn,
Date scheduleDateIn,
String kickstartServerNameIn) {
this(selectedHostServer,
selectedTargetServer,
KickstartFactory.
lookupKickstartDataByLabelAndOrgId(ksLabel, userIn.getOrg().getId()),
userIn,
scheduleDateIn,
kickstartServerNameIn);
}
/**
* Constructor for a kickstart where the host and the target may or may *not* be
* the same system. If the target system does not yet exist, selectedTargetServer
* should be null. To be used when you want to call the store() method.
*
* @param selectedHostServer server to host the kickstart
* @param selectedTargetServer server to be kickstarted
* @param data KickstartData object..
* @param userIn user performing the kickstart
* @param scheduleDateIn Date to schedule the KS.
* @param kickstartServerNameIn the name of the server who is serving the kickstart
*/
public KickstartScheduleCommand(Long selectedHostServer,
Long selectedTargetServer,
KickstartData data,
User userIn,
Date scheduleDateIn,
String kickstartServerNameIn) {
super(selectedHostServer);
initialize(selectedHostServer, selectedTargetServer, userIn);
this.setScheduleDate(scheduleDateIn);
if (data != null) {
this.setKsdata(data);
assert (this.getKsdata() != null);
}
this.setKickstartServerName(kickstartServerNameIn);
isDhcp = true;
networkInterface = LINK_NETWORK_TYPE;
}
/**
* Creates the Kickstart Sechdule command that works with a cobbler only
* kickstart where the host and the target are the same system
* To be used when you want to call the store() method.
*
* @param selectedHostServer server to host the kickstart
* @param label cobbler only profile label.
* @param userIn user performing the kickstart
* @param scheduleDateIn Date to schedule the KS.
* @param kickstartServerNameIn the name of the server who is serving the kickstart
* @return the created cobbler only profile aware kickstartScheduleCommand
*/
public static KickstartScheduleCommand createCobblerScheduleCommand(
Long selectedHostServer,
String label,
User userIn,
Date scheduleDateIn,
String kickstartServerNameIn) {
KickstartScheduleCommand cmd = new KickstartScheduleCommand(selectedHostServer,
selectedHostServer, (KickstartData)null,
userIn, scheduleDateIn, kickstartServerNameIn);
cmd.cobblerProfileLabel = label;
cmd.cobblerOnly = true;
return cmd;
}
private void initialize(Long selectedHostServerId,
Long selectedTargetServerId,
User userIn) {
log.debug("Initializing with selectedHostServerId=" + selectedHostServerId +
", selectedTargetServerId=" + selectedTargetServerId);
this.setPackagesToInstall(new LinkedList());
// There must always be a host server present.
Server hServer =
ServerFactory.lookupByIdAndOrg(selectedHostServerId, userIn.getOrg());
assert (hServer != null);
this.setHostServer(hServer);
// There may or may not be a target server present. If so, then look it up in
// the database. Otherwise, we'll create the target server later.
if (selectedTargetServerId != null) {
this.setTargetServer(ServerFactory.lookupByIdAndOrg(
selectedTargetServerId, userIn.getOrg()));
}
this.setUser(userIn);
networkInterface = "";
}
/**
* Looks up a list of applicable kickstart profiles. The list is generated based
* on matches between the server's base channel arch and the profile's channel arch
* @return DataResult, else null if the server does not exist or
* does not have a base channel assigned
*/
public DataResult<KickstartDto> getKickstartProfiles() {
log.debug("getKickstartProfiles()");
DataResult<KickstartDto> retval = new DataResult
<KickstartDto>(Collections.EMPTY_LIST);
// Profiles are associated with the host; the target system might not be created
// yet. Also, the host will be the one performing the kickstart, so the profile
// is relative to that system.
Server hostServer = getHostServer();
if (hostServer != null) {
log.debug("getKickstartProfiles(): hostServer isnt null");
Channel baseChannel = hostServer.getBaseChannel();
if (baseChannel != null) {
log.debug("getKickstartProfiles(): hostServer.baseChannel isnt null");
ChannelArch arch = baseChannel.getChannelArch();
SelectMode mode = getMode();
Map<String, Object> params = new HashMap<String, Object>();
params.put("org_id", this.user.getOrg().getId());
params.put("prim_arch_id", arch.getId());
if (arch.getName().equals("x86_64")) {
log.debug(" Adding IA-32 to search list.");
ChannelArch ia32arch = ChannelFactory.lookupArchByName("IA-32");
params.put("sec_arch_id", ia32arch.getId());
}
else if (arch.getName().equals("IA-32") &&
(hostServer.getServerArch().getName().equals(
ServerConstants.getArchI686().getName()) ||
hostServer.getServerArch().getName().equals(
ServerConstants.getArchATHLON().getName()))) {
log.debug(" Adding x86_64 to search list.");
ChannelArch x86Arch = ChannelFactory.lookupArchByName("x86_64");
params.put("sec_arch_id", x86Arch.getId());
}
else if (arch.getName().equals("PPC")) {
log.debug(" Adding ppc64le to search list.");
ChannelArch ppc64le = ChannelFactory.lookupArchByName("PPC64LE");
params.put("sec_arch_id", ppc64le.getId());
}
else if (arch.getName().equals("PPC64LE")) {
log.debug(" Adding ppc to search list.");
ChannelArch ppc = ChannelFactory.lookupArchByName("PPC");
params.put("sec_arch_id", ppc.getId());
}
else {
params.put("sec_arch_id", arch.getId());
}
retval = mode.execute(params);
if (log.isDebugEnabled()) {
log.debug("got back from DB: " + retval);
}
KickstartLister.getInstance().setKickstartUrls(retval, user);
KickstartLister.getInstance().pruneInvalid(user, retval);
retval.setTotalSize(retval.size());
}
}
List<CobblerProfileDto> dtos = KickstartLister.getInstance().
listCobblerProfiles(user);
if (log.isDebugEnabled()) {
log.debug("got back from cobbler: " + dtos);
}
retval.setTotalSize(retval.getTotalSize() + dtos.size());
retval.addAll(dtos);
return retval;
}
protected SelectMode getMode() {
return ModeFactory.getMode("General_queries",
"kickstarts_channels_for_org");
}
/**
* Get the DataResult list of com.redhat.rhn.frontend.dto.ProfileDto that are
* compatible with the BaseChannel for the selected KickstartData object.
*
* @return DataResult list
*/
public List<ProfileDto> getProfiles() {
if (!isCobblerOnly()) {
List<ProfileDto> profiles = ProfileManager.compatibleWithChannel(
this.ksdata.getKickstartDefaults().getKstree().getChannel(),
user.getOrg(), null);
return profiles;
}
return Collections.EMPTY_LIST;
}
/**
* @return Returns the id of the action scheduled to perform the kickstart.
*/
public Action getScheduledAction() {
return this.scheduledAction;
}
/**
* @return Returns the ksdata.
*/
public KickstartData getKsdata() {
return this.ksdata;
}
/**
* @param ksdataIn The ksdata to set.
*/
public void setKsdata(KickstartData ksdataIn) {
this.ksdata = ksdataIn;
}
/**
* @return Returns the String representation of the proxy host to use.
*/
public String getProxyHost() {
return this.proxyHost;
}
/**
* @param proxyHostIn The proxy host to set.
*/
public void setProxyHost(String proxyHostIn) {
this.proxyHost = proxyHostIn;
}
/**
* {@inheritDoc}
*/
public ValidatorError store() {
ValidatorError e = this.doValidation();
if (e != null) {
return e;
}
Server hostServer = getHostServer();
log.debug("** Server we are operating on: " + hostServer);
//rhn-kickstart-virtualization conflicts with this package, so we have to
// remove it
List<Map<String, Long>> installed = SystemManager.listInstalledPackage(
PACKAGE_TO_REMOVE, hostServer);
Action removal = null;
if (!installed.isEmpty()) {
removal = ActionManager.schedulePackageRemoval(user, hostServer,
installed, scheduleDate);
}
// Install packages on the host server.
log.debug("** Creating packageAction");
Action packageAction =
ActionManager.schedulePackageInstall(
this.user, hostServer, this.packagesToInstall, scheduleDate);
packageAction.setPrerequisite(removal);
log.debug("** Created packageAction ? " + packageAction.getId());
log.debug("** Cancelling existing sessions.");
cancelExistingSessions();
// Make sure we fail all existing sessions for this server since
// we are scheduling a new one
if (!cobblerOnly) {
kickstartSession = this.setupKickstartSession(packageAction);
storeActivationKeyInfo();
}
Action kickstartAction = this.scheduleKickstartAction(packageAction);
ActionFactory.save(packageAction);
scheduleRebootAction(kickstartAction);
String host = this.getKickstartServerName();
if (!StringUtils.isEmpty(this.getProxyHost())) {
host = this.getProxyHost();
}
CobblerSystemCreateCommand cmd = null;
if (!cobblerOnly) {
// Setup Cobbler system profile
KickstartUrlHelper uhelper = new KickstartUrlHelper(ksdata);
String tokenList;
if (ksdata.getRegistrationType(null).equals(RegistrationType.REACTIVATION)) {
tokenList = KickstartFormatter.generateActivationKeyString(
ksdata, kickstartSession);
}
else {
// RegistrationType.DELETION && RegistrationType.NONE
CobblerConnection connection = CobblerXMLRPCHelper
.getConnection(ConfigDefaults.get()
.getCobblerAutomatedUser());
tokenList = org.cobbler.Profile.lookupById(connection,
ksdata.getCobblerId()).getRedHatManagementKey();
}
cmd = getCobblerSystemCreateCommand(user, server,
ksdata, uhelper.
getKickstartMediaPath(kickstartSession, scheduleDate),
tokenList);
cmd.setKernelOptions(getExtraOptions());
}
else {
cmd = new CobblerSystemCreateCommand(user,
server, cobblerProfileLabel);
cmd.setKernelOptions(kernelOptions);
}
cmd.setKickstartHost(host);
cmd.setPostKernelOptions(postKernelOptions);
cmd.setScheduledAction(kickstartAction);
cmd.setNetworkInfo(isDhcp, networkInterface, this.useIpv6Gateway(),
ksdata.getInstallType().getLabel());
cmd.setBridgeInfo(createBond, bondInterface, bondSlaveInterfaces,
bondOptions, isBondDhcp, bondAddress, bondNetmask, bondGateway);
ValidatorError cobblerError = cmd.store();
if (cobblerError != null) {
return cobblerError;
}
SystemRecord rec = SystemRecord.lookupById(CobblerXMLRPCHelper.getConnection(
this.getUser().getLogin()), this.getServer().getCobblerId());
//This is a really really crappy way of doing this, but i don't want to restructure
// the actions too much at this point :/
// We only want to do this for the non-guest action
if (kickstartAction instanceof KickstartAction) {
((KickstartAction) kickstartAction).getKickstartActionDetails().
setCobblerSystemName(rec.getName());
}
ActionFactory.save(kickstartAction);
log.debug("** Created ksaction: " + kickstartAction.getId());
this.scheduledAction = kickstartAction;
log.debug("** Done scheduling kickstart session");
return null;
}
/**
* This method is extracted out so we can override them in the subclass
*/
protected CobblerSystemCreateCommand getCobblerSystemCreateCommand(User userIn,
Server serverIn, KickstartData ksdataIn, String mediaPath, String tokenList) {
return new CobblerSystemCreateCommand(userIn, serverIn,
ksdataIn, mediaPath, tokenList);
}
/**
* This method is extracted out so we can override them in the subclass
*/
protected CobblerSystemCreateCommand getCobblerSystemCreateCommand(User userIn,
Server serverIn, String cobblerProfileLabelIn) {
return new CobblerSystemCreateCommand(userIn,
serverIn, cobblerProfileLabelIn);
}
/**
*
*/
private void storeActivationKeyInfo() {
// If the target system exists already, remove any existing activation keys
// it might have associated with it.
log.debug("** ActivationType : Existing profile..");
if (getTargetServer() != null) {
List oldkeys =
ActivationKeyFactory.lookupByServer(getTargetServer());
if (oldkeys != null) {
log.debug("** Removing old tokens");
Iterator i = oldkeys.iterator();
while (i.hasNext()) {
log.debug("removing key.");
ActivationKey oldkey = (ActivationKey) i.next();
ActivationKeyFactory.removeKey(oldkey);
}
}
}
String note = null;
if (getTargetServer() != null) {
note =
LocalizationService.getInstance().getMessage(
"kickstart.session.newtokennote", getTargetServer().getName());
}
else {
// TODO: translate this
note = "Automatically generated activation key.";
}
RegistrationType regType = getKsdata().getRegistrationType(user);
if (regType.equals(RegistrationType.REACTIVATION)) {
// Create a new activation key for the target system.
boolean reactivation = RegistrationType.REACTIVATION
.equals(regType);
createKickstartActivationKey(this.user, this.ksdata,
reactivation ? getTargetServer() : null,
this.kickstartSession, 1L, note);
}
this.createdProfile = processProfileType(this.profileType);
log.debug("** profile created: " + createdProfile);
}
/**
* @param firstAction The first Action in the session's action chain
*
* return Returns the KickstartSession.
*/
protected KickstartSession setupKickstartSession(Action firstAction) {
kickstartSession = new KickstartSession();
Boolean deployConfig = this.getKsdata().
getKickstartDefaults().getCfgManagementFlag();
// TODO: Proxy logic
// Setup the KickstartSession
kickstartSession.setPackageFetchCount(new Long(0));
kickstartSession.setKickstartMode(KickstartSession.MODE_ONETIME);
kickstartSession.setDeployConfigs(deployConfig);
kickstartSession.setAction(firstAction);
kickstartSession.setKsdata(this.getKsdata());
kickstartSession.setKstree(this.getKsdata().getTree());
kickstartSession.setVirtualizationType(this.getKsdata()
.getKickstartDefaults().getVirtualizationType());
kickstartSession.setLastAction(new Date());
kickstartSession.setNewServer(this.getTargetServer());
kickstartSession.setOldServer(this.getTargetServer());
kickstartSession.setHostServer(this.getHostServer());
kickstartSession.setUser(this.getUser());
kickstartSession.setState(KickstartFactory.SESSION_STATE_CREATED);
kickstartSession.setOrg(this.getUser().getOrg());
kickstartSession.setSystemRhnHost(this.getProxyHost());
kickstartSession
.setVirtualizationType(this.getKsdata().
getKickstartDefaults().getVirtualizationType());
log.debug("** Saving new KickstartSession: " + kickstartSession.getId());
KickstartFactory.saveKickstartSession(kickstartSession);
log.debug("** Saved new KickstartSession: " + kickstartSession.getId());
return kickstartSession;
}
/**
* @param prereqAction the prerequisite for this action
*
* @return Returns the KickstartAction
*/
public Action scheduleKickstartAction(Action prereqAction) {
// We will schedule the kickstart action against the host server, since the host
// server is the liason for the target server.
Set fileList = Collections.EMPTY_SET;
if (!isCobblerOnly()) {
fileList = ksdata.getPreserveFileLists();
}
String server = this.getKickstartServerName();
if (this.getProxyHost() != null) {
server = this.getProxyHost();
}
KickstartAction ksAction =
ActionManager.scheduleKickstartAction(fileList,
this.getUser(),
this.getHostServer(),
this.getScheduleDate(),
this.getExtraOptions(),
server);
if (prereqAction != null) {
ksAction.setPrerequisite(prereqAction);
}
if (!isDhcp) {
ksAction.getKickstartActionDetails().setStaticDevice(networkInterface);
}
return ksAction;
}
/**
* @param prereqAction the prerequisite for this action
*
* @return Returns the rebootAction (if any)
*/
public Action scheduleRebootAction(Action prereqAction) {
// All actions must be scheduled against the host server.
Action rebootAction = ActionManager.scheduleRebootAction(this.getUser(),
this.getHostServer(), this.getScheduleDate());
log.debug("** Created rebootAction");
rebootAction.setPrerequisite(prereqAction);
rebootAction.setEarliestAction(this.getScheduleDate());
rebootAction.setOrg(this.getUser().getOrg());
rebootAction.setName(rebootAction.getActionType().getName());
log.debug("** saving reboot action: " + rebootAction.getName());
ActionFactory.save(rebootAction);
log.debug("** Saved rebootAction: " + rebootAction.getId());
return rebootAction;
}
/**
* Do the validation needed for this command. This ensures that the system
* hosting the kickstart has the necessary resources to do so.
*
* @return Returns a ValidatorError, if any errors occur
*/
public ValidatorError doValidation() {
ValidatorError error = validateNetworkInterface();
if (error != null) {
return error;
}
if (isCobblerOnly()) {
return null;
}
Server hostServer = getHostServer();
// Check base channel.
log.debug("** Checking basechannel.");
if (hostServer.getBaseChannel() == null) {
return new ValidatorError("kickstart.schedule.nobasechannel",
hostServer.getName());
}
// Check that we have a valid ks package
log.debug("** Checking validkspackage");
error = validateKickstartPackage();
if (error != null) {
return error;
}
if (ksdata.isRhel()) {
// Check that we have a valid up2date version
log.debug("** Checking valid up2date");
error = validateUp2dateVersion();
if (error != null) {
return error;
}
}
// we already shall be subscribed to the tools channel
// (since validateKickstartPackage), so no other actions needed
return null;
}
/**
* Create a one time activation key for use with a kickstart
* @param creator of the key
* @param ksdata associated with the key
* @param server being kickstarted (can be null)
* @param session associated with the kickstart (NOT NULL)
* @param note to add to key
* @param usageLimit to apply to the key. null for unlimited.
* @return ActivationKey that has been saved to the DB.
*/
public static ActivationKey createKickstartActivationKey(User creator,
KickstartData ksdata,
Server server,
KickstartSession session,
Long usageLimit,
String note) {
// Now create ActivationKey
ActivationKey key = ActivationKeyManager.getInstance().
createNewReActivationKey(creator, server, note, session);
key.setDeployConfigs(false);
key.setUsageLimit(usageLimit);
if (KickstartVirtualizationType.paraHost().
equals(ksdata.getKickstartDefaults().getVirtualizationType())) {
//we'll have to setup the key for virt
key.addEntitlement(ServerConstants.getServerGroupTypeVirtualizationEntitled());
}
ActivationKeyFactory.save(key);
// Add child channels to the key
if (ksdata.getChildChannels() != null && ksdata.getChildChannels().size() > 0) {
Iterator i = ksdata.getChildChannels().iterator();
log.debug("Add the child Channels");
while (i.hasNext()) {
key.addChannel((Channel) i.next());
}
}
log.debug("** Saving new token");
ActivationKeyFactory.save(key);
log.debug("** Saved new token: " + key.getId());
return key;
}
/**
* Create ExtraOptions string
* @return extraOptions that will be appended to the Kickstart.
*/
public String getExtraOptions() {
StringBuilder retval = new StringBuilder();
String kOptions = StringUtils.defaultString(kernelOptions);
/** Some examples:
dhcp:eth0 , dhcp:eth2, static:10.1.4.75
static:146.108.30.184, static:auto, static:eth0
*/
if (!StringUtils.isBlank(networkInterface)) {
if (!LINK_NETWORK_TYPE.equals(networkInterface)) {
// Get rid of the dhcp:
String params = " ksdevice=" + networkInterface;
if (!kOptions.contains("ksdevice")) {
retval.append(params);
}
}
}
else if (!kOptions.contains("ksdevice")) {
retval.append("ksdevice=" +
ConfigDefaults.get().getDefaultKickstartNetworkInterface());
}
retval.append(" ").append(kOptions);
return retval.toString();
}
private Profile processProfileType(String profileTypeIn) {
log.debug("PROFILE_TYPE=" + profileTypeIn);
if (profileTypeIn == null ||
profileTypeIn.length() == 0 || // TODO: fix this hack
profileTypeIn.equals(TARGET_PROFILE_TYPE_NONE)) {
return null;
}
Profile retval = null;
// Profile of this existing system's packages
String pname = LocalizationService.getInstance().
getMessage("kickstart.session.newprofile",
this.kickstartSession.getId().toString());
if (profileTypeIn.equals(TARGET_PROFILE_TYPE_EXISTING)) {
log.debug(" TARGET_PROFILE_TYPE_EXISTING");
// "Profile for kickstart session "
retval = ProfileManager.createProfile(
ProfileFactory.TYPE_SYNC_PROFILE, this.user,
getTargetServer().getBaseChannel(), pname, pname);
ProfileManager.copyFrom(this.server, retval);
}
// Profile of 'stored profile'
else if (profileTypeIn.equals(TARGET_PROFILE_TYPE_PACKAGE)) {
log.debug(" TARGET_PROFILE_TYPE_PACKAGE");
if (this.profileId == null) {
throw new UnsupportedOperationException(
"You specified a target profile type" +
TARGET_PROFILE_TYPE_PACKAGE +
" but this.profileId is null");
}
retval = ProfileManager.
lookupByIdAndOrg(this.profileId, this.user.getOrg());
}
// Some other system's profile
else if (profileTypeIn.equals(TARGET_PROFILE_TYPE_SYSTEM)) {
Server otherServer = ServerFactory.lookupById(this.serverProfileId);
log.debug(" TARGET_PROFILE_TYPE_SYSTEM");
log.debug(" this.serverProfileId : " + this.serverProfileId);
log.debug(" otherServer : " + otherServer);
if (otherServer != null) {
log.debug("otherServer.Id : " + otherServer.getId());
log.debug("otherServer.getBaseChannel: " + otherServer.getBaseChannel());
}
retval = ProfileManager.createProfile(
ProfileFactory.TYPE_SYNC_PROFILE, this.user,
otherServer.getBaseChannel(), pname, pname);
ProfileManager.copyFrom(otherServer, retval);
}
this.kickstartSession.setServerProfile(retval);
KickstartFactory.saveKickstartSession(this.kickstartSession);
if (getTargetServer() != null) {
HibernateFactory.getSession().refresh(getTargetServer());
}
// TODO: Compute missing packages and forward user to the missing page
return retval;
}
/**
* Cancel existing kickstart sessions on the host server for the system to be
* kickstarted (the target server).
*/
private void cancelExistingSessions() {
Server hostServer = getHostServer();
List sessions = KickstartFactory.
lookupAllKickstartSessionsByServer(hostServer.getId());
if (sessions != null) {
log.debug(" Found sessions: " + sessions);
Iterator i = sessions.iterator();
while (i.hasNext()) {
KickstartSession sess = (KickstartSession) i.next();
if (sess != null &&
sess.getState() != null) {
log.debug(" Working with session: " +
sess.getState().getLabel() + " id: " + sess.getId());
}
KickstartSessionState state = sess.getState();
if (!state.equals(KickstartFactory.SESSION_STATE_FAILED) ||
!state.equals(KickstartFactory.SESSION_STATE_COMPLETE)) {
log.debug(" need to cancel this Session this.s: " +
hostServer.getId() + " sess.hostServer: " +
(sess.getHostServer() == null ?
"null" :
"" + sess.getHostServer().getId()));
if (sess.getHostServer() != null &&
sess.getHostServer().getId().equals(hostServer.getId())) {
log.debug(" Marking session failed.");
sess.markFailed(
LocalizationService.getInstance().
getMessage("kickstart.session.newsession"));
}
}
}
}
}
/**
* Get the id of the Package installed for this KS. Here we'll verify that the
* kickstart package exists in the host server's tools channel. The host server will
* need it to perform necessary actions on either itself or the target system (if
* different).
* @return Long id of Package used for this KS.
*/
public ValidatorError validateKickstartPackage() {
if (cobblerOnly) {
return null;
}
Server hostServer = getHostServer();
Set<Long> serverChannelIds = new HashSet<Long>();
Iterator<Channel> i = hostServer.getChannels().iterator();
while (i.hasNext()) {
Channel c = i.next();
serverChannelIds.add(c.getId());
}
// check for package among channels the server is subscribed to.
// If one is found, return
Map<String, Long> pkgToInstall = findKickstartPackageToInstall(
hostServer, serverChannelIds);
if (pkgToInstall != null) {
this.packagesToInstall.add(pkgToInstall);
log.debug(" packagesToInstall: " + packagesToInstall);
return null;
}
// otherwise search in channels that can be subscribed.
// If one is found, subscribe channel and return
Set<Long> subscribableChannelIds = SystemManager.subscribableChannelIds(
hostServer.getId(), this.user.getId(), hostServer.getBaseChannel().getId());
pkgToInstall = findKickstartPackageToInstall(hostServer, subscribableChannelIds);
if (pkgToInstall != null) {
this.packagesToInstall.add(pkgToInstall);
log.debug(" packagesToInstall: " + packagesToInstall);
Long cid = pkgToInstall.get("channel_id");
log.debug(" Subscribing to: " + cid);
Channel c = ChannelFactory.lookupById(cid);
try {
SystemManager.subscribeServerToChannel(this.user, server, c);
log.debug(" Subscribed: " + cid);
}
catch (PermissionException pe) {
return new ValidatorError("kickstart.schedule.cantsubscribe");
}
catch (Exception e) {
return new ValidatorError("kickstart.schedule.cantsubscribe.channel",
c.getName(), server.getName());
}
return null;
}
return new ValidatorError("kickstart.schedule.nopackage",
this.getKsdata().getChannel().getName());
}
/**
* Looks for the package name among the specified channels and, if it is found,
* it returns the highest available version in Map form.
*
* @param server the server
* @param channelIds channels the server could be subscribed to
* @return a ValidationError or null
*/
public Map<String, Long> findKickstartPackageToInstall(Server server,
Collection<Long> channelIds) {
List<Map<String, Long>> results = new LinkedList<Map<String, Long>>();
for (Long chnnelId : channelIds) {
log.debug(" Checking on:" + chnnelId + " for: " + getKickstartPackageName());
List<Map<String, Object>> packages = ChannelManager.listLatestPackagesEqual(
chnnelId, getKickstartPackageName());
log.debug(" size: " + packages.size());
for (Map<String, Object> aPackage : packages) {
log.debug(" Found the package: " + aPackage);
Map<String, Long> result = new HashMap<String, Long>();
result.put("name_id", (Long)aPackage.get("name_id"));
result.put("evr_id", (Long)aPackage.get("evr_id"));
result.put("arch_id", (Long)aPackage.get("package_arch_id"));
result.put("channel_id", chnnelId);
results.add(result);
}
}
if (!results.isEmpty()) {
return Collections.max(results, new Comparator<Map<String, Long>>() {
public int compare(Map<String, Long> o1In, Map<String, Long> o2In) {
PackageEvr evr1 = PackageEvrFactory.lookupPackageEvrById(
o1In.get("evr_id"));
PackageEvr evr2 = PackageEvrFactory.lookupPackageEvrById(
o2In.get("evr_id"));
return evr1.compareTo(evr2);
}
});
}
else {
return null;
}
}
/**
* Return the kickstart package name for this kickstart action.
* @return kickstart package name
*/
public String getKickstartPackageName() {
return this.ksdata.getKickstartPackageName();
}
// Check to make sure up2date is 2.9.0
protected ValidatorError validateUp2dateVersion() {
Server hostServer = getHostServer();
List packages = PackageManager.systemPackageList(hostServer.getId(), null);
if (packages != null) {
log.debug(" packages.size() : " + packages.size());
}
// PackageListItem
Iterator i = packages.iterator();
String up2dateepoch = null;
String up2dateversion = null;
String up2daterelease = null;
while (i.hasNext()) {
PackageListItem pli = (PackageListItem) i.next();
if (pli.getName().equals("dnf-plugin-spacewalk")) {
// found dnf-plugin-spacewalk - returning
return null;
}
if (pli.getName().equals("yum-rhn-plugin")) {
// found yum-rhn-plugin - returning
return null;
}
if (pli.getName().equals("zypp-plugin-spacewalk")) {
// found zypp-plugin-spacewalk - returning
return null;
}
if (pli.getName().equals("up2date")) {
log.debug(" found up2date ...");
up2dateepoch = pli.getEpoch();
up2dateversion = pli.getVersion();
up2daterelease = pli.getRelease();
log.debug(" e: " + up2dateepoch + " v: " + up2dateversion +
" r : " + up2daterelease);
}
}
if (up2dateepoch == null && up2dateversion == null &&
up2daterelease == null) {
Object[] args = new Object[2];
args[0] = hostServer.getId();
args[1] = hostServer.getName();
return new ValidatorError("kickstart.schedule.noup2date", args);
}
up2dateepoch = up2dateepoch == null ? "0" : up2dateepoch;
up2dateversion = up2dateversion == null ? "0" : up2dateversion;
up2daterelease = up2daterelease == null ? "0" : up2daterelease;
int comp = PackageManager.verCmp(up2dateepoch,
up2dateversion,
up2daterelease,
"0",
UP2DATE_VERSION,
"0");
log.debug(" Got back comp from verCmp: " + comp);
if (comp < 0) {
Long packageId = PackageManager.
getServerNeededUpdatePackageByName(hostServer.getId(), "up2date");
if (packageId == null) {
Object[] args = new Object[2];
args[0] = UP2DATE_VERSION;
args[1] = up2dateversion;
return new ValidatorError("kickstart.schedule.noup2dateinchannel", args);
}
Package p = PackageFactory.lookupByIdAndUser(packageId, this.user);
Map evrmap = new HashMap();
evrmap.put("name_id", p.getPackageName().getId());
evrmap.put("evr_id", p.getPackageEvr().getId());
evrmap.put("arch_id", p.getPackageArch().getId());
packagesToInstall.add(evrmap);
}
else {
return null;
}
return null;
}
/**
* Get the list of compatible systems you could sync to
* @return DataResult of System DTOs
*/
public List<Map<String, Object>> getCompatibleSystems() {
if (!isCobblerOnly()) {
return SystemManager.systemsSubscribedToChannel(
this.getKsdata().getKickstartDefaults().getKstree().getChannel(), user);
}
return Collections.EMPTY_LIST;
}
/**
* @return Returns the packagesToInstall.
*/
public List getPackagesToInstall() {
return packagesToInstall;
}
/**
* @param packagesToInstallIn The packagesToInstall to set.
*/
public void setPackagesToInstall(List packagesToInstallIn) {
this.packagesToInstall = packagesToInstallIn;
}
/**
* @return Returns the profileType.
*/
public String getProfileType() {
return profileType;
}
/**
* @param profileTypeIn The profileType to set.
*/
public void setProfileType(String profileTypeIn) {
this.profileType = profileTypeIn;
}
/**
* @return Returns the kickstartSession.
*/
public KickstartSession getKickstartSession() {
return kickstartSession;
}
/**
* @param kickstartSessionIn The kickstartSession to set.
*/
public void setKickstartSession(KickstartSession kickstartSessionIn) {
this.kickstartSession = kickstartSessionIn;
}
/**
* @return Returns the profileId.
*/
public Long getProfileId() {
return profileId;
}
/**
* @param profileIdIn The profileId to set.
*/
public void setProfileId(Long profileIdIn) {
this.profileId = profileIdIn;
}
/**
* @return Returns the serverProfileId.
*/
public Long getServerProfileId() {
return serverProfileId;
}
/**
* @param serverProfileIdIn The serverProfileId to set.
*/
public void setServerProfileId(Long serverProfileIdIn) {
this.serverProfileId = serverProfileIdIn;
}
/**
* @return Returns the createdProfile.
*/
public Profile getCreatedProfile() {
return createdProfile;
}
/**
*
* @param serverIn Proxy Host to set for this ks session
*/
public void setProxy(Server serverIn) {
if (serverIn != null) {
this.proxyHost = serverIn.getHostname();
}
}
/**
* @return Returns the scheduleDate.
*/
public Date getScheduleDate() {
return scheduleDate;
}
/**
* @param scheduleDateIn The scheduleDate to set.
*/
public void setScheduleDate(Date scheduleDateIn) {
this.scheduleDate = scheduleDateIn;
}
/**
* @return Returns the kickstart server name.
*/
public String getKickstartServerName() {
return kickstartServerName;
}
/**
* @param kickstartServerNameIn The kickstartServerName to set.
*/
public void setKickstartServerName(String kickstartServerNameIn) {
this.kickstartServerName = kickstartServerNameIn;
}
/**
* @param networkType dhcp/static/link one of em.
* @param networkInterfaceIn The staticDevice to set.
*/
public void setNetworkDevice(String networkType, String networkInterfaceIn) {
if (StringUtils.isBlank(networkType) ||
LINK_NETWORK_TYPE.equals(networkType)) {
isDhcp = true;
networkInterface = LINK_NETWORK_TYPE;
}
else {
isDhcp = DHCP_NETWORK_TYPE.equals(networkType);
networkInterface = networkInterfaceIn;
}
}
/**
* Sets to use IPv6 gateway.
*/
public void setIpv6Gateway() {
useIpv6Gateway = true;
}
/**
* Indicate whether an IPv6 gateway is to be used for re-provisioning.
* @return true if IPv6 gateway is to be used, false otherwise.
*/
public boolean useIpv6Gateway() {
return useIpv6Gateway;
}
/**
* @return Returns the bond name.
*/
public String getBondInterface() {
return bondInterface;
}
/**
* @param bondInterfaceIn The bond name to set
*/
public void setBondInterface(String bondInterfaceIn) {
bondInterface = bondInterfaceIn;
}
/**
* @return Returns a list of the bond slave interfaces.
*/
public List<String> getBondSlaveInterfaces() {
return bondSlaveInterfaces;
}
/**
* @param bondSlaveInterfacesIn The bond slave interfaces to set.
*/
public void setBondSlaveInterfaces(List<String> bondSlaveInterfacesIn) {
bondSlaveInterfaces = bondSlaveInterfacesIn;
}
/**
* @return Returns whether or not we should create a bond
*/
public boolean createBond() {
return createBond;
}
/**
* @param createBondIn Whether or not to create a bond
*/
public void setCreateBond(boolean createBondIn) {
createBond = createBondIn;
}
/**
* @return Returns the bondOptions
*/
public String getBondOptions() {
return bondOptions;
}
/**
* @param bondOptionsIn The bond options to set.
*/
public void setBondOptions(String bondOptionsIn) {
bondOptions = bondOptionsIn;
}
/**
* @return Returns true if we are using dhcp for the bond
*/
public boolean isBondDhcp() {
return isBondDhcp;
}
/**
* @param isBondDhcpIn True if we want to use dhcp for the bond
*/
public void setBondDhcp(boolean isBondDhcpIn) {
this.isBondDhcp = isBondDhcpIn;
}
/**
* @return the bondAddress
*/
public String getBondAddress() {
return bondAddress;
}
/**
* @param bondAddressIn The bondAddress to set
*/
public void setBondAddress(String bondAddressIn) {
this.bondAddress = bondAddressIn;
}
/**
* @return The bondNetmask
*/
public String getBondNetmask() {
return bondNetmask;
}
/**
* @param bondNetmaskIn The bondNetmask to set
*/
public void setBondNetmask(String bondNetmaskIn) {
this.bondNetmask = bondNetmaskIn;
}
/**
* @return The bondGateway
*/
public String getBondGateway() {
return bondGateway;
}
/**
* @param bondGatewayIn The bondGateway to set
*/
public void setBondGateway(String bondGatewayIn) {
this.bondGateway = bondGatewayIn;
}
/**
* @return Returns the user.
*/
@Override
public User getUser() {
return user;
}
/**
* @param userIn The user to set.
*/
public void setUser(User userIn) {
this.user = userIn;
}
/**
* @return The host server.
*/
public Server getHostServer() {
return this.server;
}
/**
* @param serverIn The host server to set.
*/
public void setHostServer(Server serverIn) {
this.server = serverIn;
}
/**
* @return The target server.
*/
public Server getTargetServer() {
return this.targetServer;
}
/**
* @param serverIn The server to set.
*/
public void setTargetServer(Server serverIn) {
this.targetServer = serverIn;
}
/**
* @return true if this cmd carries a cobbler only profile
*/
public boolean isCobblerOnly() {
return cobblerOnly;
}
/**
* @param kernelOptionsIn The kernelOptions to set.
*/
public void setKernelOptions(String kernelOptionsIn) {
this.kernelOptions = kernelOptionsIn;
}
/**
* @param postKernelOptionsIn The postKernelOptions to set.
*/
public void setPostKernelOptions(String postKernelOptionsIn) {
this.postKernelOptions = postKernelOptionsIn;
}
private ValidatorError validateNetworkInterface() {
if (!LINK_NETWORK_TYPE.equals(networkInterface)) {
boolean nicAvailable = false;
for (NetworkInterface nic : server.getNetworkInterfaces()) {
if (networkInterface.equals(nic.getName())) {
nicAvailable = true;
break;
}
}
if (!nicAvailable) {
return new ValidatorError("kickstart.schedule.nosuchdevice",
server.getName(), networkInterface);
}
}
return null;
}
}