/**
* 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.cobbler;
import com.redhat.rhn.common.util.StringUtil;
import com.redhat.rhn.common.validator.ValidatorError;
import com.redhat.rhn.common.validator.ValidatorException;
import com.redhat.rhn.domain.kickstart.KickstartFactory;
import com.redhat.rhn.domain.kickstart.KickstartableTree;
import com.redhat.rhn.manager.kickstart.KickstartUrlHelper;
import org.apache.log4j.Logger;
import org.cobbler.Distro;
import java.io.File;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* @author paji
* @version $Rev$
*/
public class CobblerDistroSyncCommand extends CobblerCommand {
private Logger log;
/**
* Constructor to create a
* DistorSyncCommand
*/
public CobblerDistroSyncCommand() {
super();
log = Logger.getLogger(this.getClass());
}
protected Map<String, Distro> getDistros() {
Map<String, Distro> toReturn = new HashMap<String, Distro>();
List<Distro> distros = Distro.list(CobblerXMLRPCHelper.getAutomatedConnection());
for (Distro distro : distros) {
toReturn.put(distro.getUid(), distro);
}
return toReturn;
}
/**
* Sync spacewalk distros that have a null cobblerId
* we do this in store as well, (while doing other syncing
* tasks, but this is needed occasionally outside of store.
* @return an error if applicable
*/
public ValidatorError syncNullDistros() {
List<String> errors = new LinkedList<String>();
List<KickstartableTree> unSynced = KickstartFactory.listUnsyncedKickstartTrees();
String err;
for (KickstartableTree tree : unSynced) {
if (!tree.isPathsValid()) {
log.warn("Could not sync tree " + tree.getLabel());
continue;
}
Distro distro = Distro.lookupByName(
CobblerXMLRPCHelper.getAutomatedConnection(),
tree.getCobblerDistroName());
if (distro != null) {
tree.setCobblerId(distro.getUid());
}
else {
log.debug("syncing null distro " + tree.getLabel());
err = createDistro(tree, false);
if (err != null) {
errors.add(err);
}
}
//Now do virt
if (tree.doesParaVirt() && tree.getCobblerXenId() == null) {
distro = Distro.lookupByName(
CobblerXMLRPCHelper.getAutomatedConnection(),
tree.getCobblerXenDistroName());
if (distro != null) {
tree.setCobblerXenId(distro.getUid());
}
else {
err = createDistro(tree, true);
if (err != null) {
errors.add(err);
}
}
}
}
StringBuffer messages = new StringBuffer();
for (int i = 0; i < errors.size(); i++) {
messages.append(errors.get(i));
messages.append("\n");
}
if (messages.length() == 0) {
return null;
}
return new ValidatorError("kickstart.cobbler.distro.syncfail", messages);
}
/**
* {@inheritDoc}
*/
@Override
public ValidatorError store() {
List<String> errors = new LinkedList<String>();
List <KickstartableTree> trees = KickstartFactory.lookupKickstartTrees();
//Any distros exist on spacewalk and not in cobbler?
Map<String, Distro> cobblerDistros = getDistros();
for (KickstartableTree tree : trees) {
if (!cobblerDistros.containsKey(tree.getCobblerId())) {
String err = createDistro(tree, false);
if (err != null) {
errors.add(err);
}
}
if (!cobblerDistros.containsKey(tree.getCobblerXenId()) &&
tree.doesParaVirt()) {
String err = createDistro(tree, true);
if (err != null) {
errors.add(err);
}
}
}
log.debug(trees);
log.debug(cobblerDistros);
// Are there any distros that have changed
for (KickstartableTree tree : trees) {
Distro cobDistro = null;
if (cobblerDistros.containsKey(tree.getCobblerId())) {
cobDistro = cobblerDistros.get(tree.getCobblerId());
}
else if (cobblerDistros.containsKey(tree.getCobblerXenId())) {
cobDistro = cobblerDistros.get(tree.getCobblerXenId());
}
if (cobDistro != null) {
// last_modified is updated:
// 1) if we're inserting a new kickstartable tree
// 2) if we're updating a row and not changing cobbler_id, cobbler_xen_id,
// and last_modified -- aka we update tree_path or something
// 3) if you update it explicitly
// If everything is updated then they should be the same, this loop sets
// last_modified. If dates are different then sync Spacewalk's data to
// cobbler. Syncing the other way is not supported. Round to within
// 1 second to smooth out differences between storing fractional seconds
// or not.
if (Math.abs(cobDistro.getModified().getTime() -
tree.getLastModified().getTime()) > 1000) {
syncSpacewalkToDistro(tree);
// we've synced; set tree.last_modified to indicate we're in-sync
cobDistro.reload();
tree.setLastModified(cobDistro.getModified());
}
}
}
StringBuffer messages = new StringBuffer();
for (int i = 0; i < errors.size(); i++) {
messages.append(errors.get(i));
messages.append("\n");
}
if (messages.length() == 0) {
return null;
}
return new ValidatorError("kickstart.cobbler.distro.syncfail", messages);
}
private String createDistro(KickstartableTree tree, boolean xen) {
String treeLabel = tree.getLabel();
log.debug("Trying to create: " + treeLabel + " in cobbler over xmlrpc");
Map ksmeta = new HashMap();
KickstartUrlHelper helper = new KickstartUrlHelper(tree);
ksmeta.put(KickstartUrlHelper.COBBLER_MEDIA_VARIABLE,
helper.getKickstartMediaPath());
if (!xen) {
log.debug("tree missing in cobbler. " +
"creating non-xenpv distro in cobbler : " + treeLabel);
try {
tree.getKernelPath();
}
catch (ValidatorException e) {
return "ERROR: No kernel found in this path: [" +
StringUtil.join(", ", Arrays.asList(tree.getDefaultInitrdPath())) +
"] Cannot create the distro in cobbler which" +
" makes this kickstart distribution: [" + treeLabel +
"] unusable.";
}
try {
tree.getInitrdPath();
}
catch (ValidatorException e) {
return "ERROR: No initrd found in this path: [" +
StringUtil.join(", ", Arrays.asList(tree.getDefaultInitrdPath())) +
"] Cannot create the distro in cobbler which" +
" makes this kickstart distribution: [" + treeLabel +
"] unusable.";
}
Distro distro = Distro.create(CobblerXMLRPCHelper.getAutomatedConnection(),
tree.getCobblerDistroName(), tree.getKernelPath(),
tree.getInitrdPath(), ksmeta, tree.getInstallType().getCobblerBreed(),
tree.getInstallType().getCobblerOsVersion(),
tree.getChannel().getChannelArch().cobblerArch());
tree.setCobblerId(distro.getUid());
invokeCobblerUpdate();
}
else if (tree.doesParaVirt() && xen) {
log.debug("tree missing in cobbler. " +
"creating xenpv distro in cobbler : " + treeLabel);
String error =
validateKernelInitrd(treeLabel,
tree.getKernelXenPath(), tree.getInitrdXenPath());
if (error != null) {
return error;
}
Distro distroXen = Distro.create(CobblerXMLRPCHelper.getAutomatedConnection(),
tree.getCobblerXenDistroName(), tree.getKernelXenPath(),
tree.getInitrdXenPath(), ksmeta,
tree.getInstallType().getCobblerBreed(),
tree.getInstallType().getCobblerOsVersion(),
tree.getChannel().getChannelArch().cobblerArch());
tree.setCobblerXenId(distroXen.getUid());
}
tree.setModified(new Date());
return null;
}
private String validateKernelInitrd(String label, String kernelPath,
String initrdPath) {
File kernel = new File(kernelPath);
if (!kernel.exists()) {
String msg = "ERROR: No kernel found in this path: [" + kernelPath +
"] Cannot create the distro in cobbler which" +
" makes this kickstart distribution: [" + label +
"] unusable.";
log.error(msg);
return msg;
}
File initrd = new File(initrdPath);
if (!initrd.exists()) {
String msg = "ERROR: No initrd found in this path: [" + initrdPath +
"] Cannot create the distro in cobbler which" +
" makes this kickstart distribution: [" + label +
"] unusable.";
log.error(msg);
return msg;
}
return null;
}
private void syncSpacewalkToDistro(KickstartableTree tree) {
if (tree.isRhnTree()) {
log.debug("Syncing: " + tree.getLabel() + " to cobbler over xmlrpc");
CobblerDistroEditCommand command = new CobblerDistroEditCommand(tree);
command.store();
}
else {
//Do nothing. Let us be out of sync with cobbler
}
}
}