/**
* 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.frontend.xmlrpc.system.provisioning.snapshot;
import com.redhat.rhn.domain.action.ActionFactory;
import com.redhat.rhn.domain.config.ConfigRevision;
import com.redhat.rhn.domain.rhnpackage.PackageNevra;
import com.redhat.rhn.domain.server.Server;
import com.redhat.rhn.domain.server.ServerFactory;
import com.redhat.rhn.domain.server.ServerSnapshot;
import com.redhat.rhn.domain.server.SnapshotTag;
import com.redhat.rhn.domain.user.User;
import com.redhat.rhn.frontend.xmlrpc.BaseHandler;
import com.redhat.rhn.frontend.xmlrpc.InvalidArgsException;
import com.redhat.rhn.frontend.xmlrpc.InvalidSystemException;
import com.redhat.rhn.frontend.xmlrpc.NoSuchSnapshotException;
import com.redhat.rhn.frontend.xmlrpc.NoSuchSystemException;
import com.redhat.rhn.frontend.xmlrpc.SnapshotLookupException;
import com.redhat.rhn.frontend.xmlrpc.SnapshotTagAlreadyExistsException;
import com.redhat.rhn.frontend.xmlrpc.system.XmlRpcSystemHelper;
import com.redhat.rhn.manager.action.ActionManager;
import com.redhat.rhn.manager.system.SystemManager;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* SnapshotHandler
* @version $Rev$
* @xmlrpc.namespace system.provisioning.snapshot
* @xmlrpc.doc Provides methods to access and delete system snapshots.
*/
public class SnapshotHandler extends BaseHandler {
/**
* List the snapshots for a given system that were created on or between
* the dates specified.
* @param loggedInUser The current user
* @param sid system id
* @param dateDetails map containing optional start/end date
* @return list of server snapshots
* @since 10.1
*
* @xmlrpc.doc List snapshots for a given system.
* A user may optionally provide a start and end date to narrow the snapshots that
* will be listed. For example,
* <ul>
* <li>If the user provides startDate only, all snapshots created either on or after
* the date provided will be returned.</li>
* <li>If user provides startDate and endDate, all snapshots created on or between the
* dates provided will be returned.</li>
* <li>If the user doesn't provide a startDate and endDate, all snapshots associated
* with the server will be returned.</li>
* </ul>
* @xmlrpc.param #session_key()
* @xmlrpc.param #param("int", "serverId")
* @xmlrpc.param
* #struct("date details")
* #prop_desc($date, "startDate", "Optional, unless endDate
* is provided.")
* #prop_desc($date, "endDate", "Optional.")
* #struct_end()
* @xmlrpc.returntype
* #array()
* $ServerSnapshotSerializer
* #array_end()
*/
public List<ServerSnapshot> listSnapshots(User loggedInUser, Integer sid,
Map dateDetails) {
validateDateKeys(dateDetails);
Server server = lookupServer(loggedInUser, sid);
Date startDate = null;
Date endDate = null;
if (dateDetails.containsKey("startDate")) {
startDate = (Date)dateDetails.get("startDate");
}
if (dateDetails.containsKey("endDate")) {
endDate = (Date)dateDetails.get("endDate");
}
if ((startDate == null) && (endDate != null)) {
// TODO: throw exception...This is an invalid combination...
}
return ServerFactory.listSnapshots(server.getOrg(), server, startDate, endDate);
}
/**
* list the packages for a given snapshot
* @param loggedInUser The current user
* @param snapId snapshot id
* @return Set of packageNEvra objects
* @since 10.1
*
* @xmlrpc.doc List the packages associated with a snapshot.
* @xmlrpc.param #session_key()
* @xmlrpc.param #param("int", "snapId")
* @xmlrpc.returntype
* #array()
* $PackageNevraSerializer
* #array_end()
*/
public Set<PackageNevra> listSnapshotPackages(User loggedInUser, Integer snapId) {
ServerSnapshot snap = lookupSnapshot(loggedInUser, snapId);
return snap.getPackages();
}
/**
* list the config files for a given snapshot
* @param loggedInUser The current user
* @param snapId snapshot id
* @return Set of ConfigRevision objects
* @since 10.2
*
* @xmlrpc.doc List the config files associated with a snapshot.
* @xmlrpc.param #session_key()
* @xmlrpc.param #param("int", "snapId")
* @xmlrpc.returntype
* #array()
* $ConfigRevisionSerializer
* #array_end()
*/
public Set<ConfigRevision> listSnapshotConfigFiles(User loggedInUser, Integer snapId) {
ServerSnapshot snap = lookupSnapshot(loggedInUser, snapId);
return snap.getConfigRevisions();
}
/**
* Deletes all snapshots across multiple systems.
* @param loggedInUser The current user
* @param dateDetails map containing optional start/end Date objects.
* @return 1 on success
* @since 10.1
*
* @xmlrpc.doc Deletes all snapshots across multiple systems based on the given date
* criteria. For example,
* <ul>
* <li>If the user provides startDate only, all snapshots created either on or after
* the date provided will be removed.</li>
* <li>If user provides startDate and endDate, all snapshots created on or between the
* dates provided will be removed.</li>
* <li>If the user doesn't provide a startDate and endDate, all snapshots will be
* removed.</li>
* </ul>
*
* @xmlrpc.param #session_key()
* @xmlrpc.param
* #struct("date details")
* #prop_desc($date, "startDate", "Optional, unless endDate
* is provided.")
* #prop_desc($date, "endDate", "Optional.")
* #struct_end()
* @xmlrpc.returntype #return_int_success()
*/
public int deleteSnapshots(User loggedInUser, Map dateDetails) {
validateDateKeys(dateDetails);
Date startDate = null;
Date endDate = null;
if (dateDetails.containsKey("startDate")) {
startDate = (Date)dateDetails.get("startDate");
}
if (dateDetails.containsKey("endDate")) {
endDate = (Date)dateDetails.get("endDate");
}
if ((startDate == null) && (endDate != null)) {
// TODO: throw exception...This is an invalid combination...
}
ServerFactory.deleteSnapshots(loggedInUser.getOrg(), startDate, endDate);
return 1;
}
/**
* Deletes all snapshots for a given system based on the given date criteria.
* @param loggedInUser The current user
* @param sid system id
* @param dateDetails map containing optional start/end Date objects.
* @return 1 on success
* @since 10.1
*
* @xmlrpc.doc Deletes all snapshots for a given system based on the date
* criteria. For example,
* <ul>
* <li>If the user provides startDate only, all snapshots created either on or after
* the date provided will be removed.</li>
* <li>If user provides startDate and endDate, all snapshots created on or between the
* dates provided will be removed.</li>
* <li>If the user doesn't provide a startDate and endDate, all snapshots associated
* with the server will be removed.</li>
* </ul>
*
* @xmlrpc.param #session_key()
* @xmlrpc.param #param_desc("int", "sid", "system id of system to delete
* snapshots for")
* @xmlrpc.param
* #struct("date details")
* #prop_desc($date, "startDate", "Optional, unless endDate
* is provided.")
* #prop_desc($date, "endDate", "Optional.")
* #struct_end()
* @xmlrpc.returntype #return_int_success()
*/
public int deleteSnapshots(User loggedInUser, Integer sid, Map dateDetails) {
validateDateKeys(dateDetails);
Server server = lookupServer(loggedInUser, sid);
Date startDate = null;
Date endDate = null;
if (dateDetails.containsKey("startDate")) {
startDate = (Date)dateDetails.get("startDate");
}
if (dateDetails.containsKey("endDate")) {
endDate = (Date)dateDetails.get("endDate");
}
if ((startDate == null) && (endDate != null)) {
// TODO: throw exception...This is an invalid combination...
}
ServerFactory.deleteSnapshots(loggedInUser.getOrg(), server, startDate, endDate);
return 1;
}
/**
* Deletes a snapshot
* @param loggedInUser The current user
* @param snapId id of snapshot
* @return 1 on success
* @since 10.1
*
* @xmlrpc.doc Deletes a snapshot with the given snapshot id
* @xmlrpc.param #session_key()
* @xmlrpc.param #param_desc("int", "snapshotId", "Id of snapshot to delete")
* @xmlrpc.returntype #return_int_success()
*/
public int deleteSnapshot(User loggedInUser, Integer snapId) {
ServerSnapshot snap = lookupSnapshot(loggedInUser, snapId);
ServerFactory.deleteSnapshot(snap);
return 1;
}
/**
* Adds tag to snapshot
* @param loggedInUser The current user
* @param snapId shapshot id
* @param tagName name iof the snapshot tag
* @return 1 on success
*
* @xmlrpc.doc Adds tag to snapshot
* @xmlrpc.param #session_key()
* @xmlrpc.param #param_desc("int", "snapshotId", "Id of the snapshot")
* @xmlrpc.param #param_desc("string", "tag", "Name of the snapshot tag")
* @xmlrpc.returntype #return_int_success()
*/
public int addTagToSnapshot(User loggedInUser, Integer snapId, String tagName) {
ServerSnapshot snap = lookupSnapshot(loggedInUser, snapId);
if (!snap.addTag(tagName)) {
throw new SnapshotTagAlreadyExistsException(tagName);
}
return 1;
}
/**
* Private helper method to lookup a server from an sid, and throws a FaultException
* if the server cannot be found.
* @param user The user looking up the server
* @param sid The id of the server we're looking for
* @return Returns the server corresponding to sid
* @throws NoSuchSystemException A NoSuchSystemException is thrown if the server
* corresponding to sid cannot be found.
*/
private Server lookupServer(User user, Integer sid) throws NoSuchSystemException {
return XmlRpcSystemHelper.getInstance().lookupServer(user, sid);
}
private ServerSnapshot lookupSnapshot(User user, Integer snapId)
throws NoSuchSnapshotException {
ServerSnapshot snap = ServerFactory.lookupSnapshotById(snapId);
if (snap == null) {
throw new NoSuchSnapshotException(snapId);
}
lookupServer(user, snap.getServer().getId().intValue());
return snap;
}
private void validateDateKeys(Map map) throws InvalidArgsException {
// confirm that map contains only valid keys
Set<String> validKeys = new HashSet<String>();
validKeys.add("startDate");
validKeys.add("endDate");
validateMap(validKeys, map);
}
/**
* @param loggedInUser The current user
* @param serverId server ID
* @param snapshotId snapshot ID
* @return 1 in case of success, exception thrown otherwise
* @xmlrpc.doc Rollbacks server to snapshot
* @xmlrpc.param #session_key()
* @xmlrpc.param #param("int", "serverId")
* @xmlrpc.param #param_desc("int", "snapshotId", "Id of the snapshot")
* @xmlrpc.returntype #return_int_success()
*/
public int rollbackToSnapshot(User loggedInUser, Integer serverId,
Integer snapshotId) {
Server server = lookupServer(loggedInUser, serverId);
if (server == null) {
throw new InvalidSystemException();
}
ServerSnapshot snapshot = ServerFactory.lookupSnapshotById(snapshotId.intValue());
if (snapshot == null) {
throw new SnapshotLookupException(snapshotId);
}
doRollback(loggedInUser, snapshot);
return 1;
}
/**
* @param loggedInUser The current user
* @param serverId server ID
* @param tagName Snapshot tag name
* @return 1 in case of success, exception thrown otherwise
* @xmlrpc.doc Rollbacks server to snapshot
* @xmlrpc.param #session_key()
* @xmlrpc.param #param("int", "serverId")
* @xmlrpc.param #param_desc("string", "tagName", "Name of the snapshot tag")
* @xmlrpc.returntype #return_int_success()
*/
public int rollbackToTag(User loggedInUser, Integer serverId,
String tagName) {
SnapshotTag tag = ServerFactory.lookupSnapshotTagbyName(tagName);
for (ServerSnapshot snapshot : tag.getSnapshots()) {
if (snapshot.getServer().getId() == serverId.longValue()) {
doRollback(loggedInUser, snapshot);
}
}
return 1;
}
/**
* @param loggedInUser The current user
* @param tagName Snapshot tag name
* @return 1 in case of success, exception thrown otherwise
* @xmlrpc.doc Rollbacks server to snapshot
* @xmlrpc.param #session_key()
* @xmlrpc.param #param_desc("string", "tagName", "Name of the snapshot tag")
* @xmlrpc.returntype #return_int_success()
*/
public int rollbackToTag(User loggedInUser, String tagName) {
SnapshotTag tag = ServerFactory.lookupSnapshotTagbyName(tagName);
for (ServerSnapshot snapshot : tag.getSnapshots()) {
doRollback(loggedInUser, snapshot);
}
return 1;
}
private void doRollback(User loggedInUser, ServerSnapshot snapshot) {
SystemManager.ensureAvailableToUser(loggedInUser, snapshot.getServer().getId());
ActionManager.checkConfigActionOnServer(ActionFactory.TYPE_CONFIGFILES_DEPLOY,
snapshot.getServer());
snapshot.cancelPendingActions();
snapshot.rollbackChannels();
snapshot.rollbackGroups();
snapshot.rollbackPackages(loggedInUser);
snapshot.rollbackConfigFiles(loggedInUser);
}
}