/**
* 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.domain.server;
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.domain.BaseDomainHelper;
import com.redhat.rhn.domain.action.Action;
import com.redhat.rhn.domain.action.ActionFactory;
import com.redhat.rhn.domain.action.rhnpackage.PackageAction;
import com.redhat.rhn.domain.channel.Channel;
import com.redhat.rhn.domain.channel.ChannelFactory;
import com.redhat.rhn.domain.config.ConfigChannel;
import com.redhat.rhn.domain.config.ConfigRevision;
import com.redhat.rhn.domain.org.Org;
import com.redhat.rhn.domain.rhnpackage.PackageNevra;
import com.redhat.rhn.domain.user.User;
import com.redhat.rhn.frontend.dto.PackageListItem;
import com.redhat.rhn.frontend.dto.PackageMetadata;
import com.redhat.rhn.manager.action.ActionManager;
import com.redhat.rhn.manager.system.SystemManager;
import org.apache.commons.lang.builder.HashCodeBuilder;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
*
* ServerSnapshot
* @version $Rev$
*/
public class ServerSnapshot extends BaseDomainHelper {
private Org org;
private Server server;
private Long id;
private String reason;
private Set<Channel> channels = new HashSet<Channel>();
private Set<ConfigChannel> configChannels = new HashSet<ConfigChannel>();
private Set<ConfigRevision> configRevisions = new HashSet<ConfigRevision>();
private Set<ServerGroup> groups = new HashSet<ServerGroup>();
private Set<PackageNevra> packages = new HashSet<PackageNevra>();
private InvalidSnapshotReason invalidReason;
private static final DateFormat DF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/**
* @return Returns the channels.
*/
public Set<Channel> getChannels() {
return channels;
}
/**
* @param channelsIn The channels to set.
*/
public void setChannels(Set<Channel> channelsIn) {
this.channels = channelsIn;
}
/**
* @return Returns the configChannels.
*/
public Set<ConfigChannel> getConfigChannels() {
return configChannels;
}
/**
* @param configChannelsIn The configChannels to set.
*/
public void setConfigChannels(Set<ConfigChannel> configChannelsIn) {
this.configChannels = configChannelsIn;
}
/**
* @return Returns the configRevisions.
*/
public Set<ConfigRevision> getConfigRevisions() {
return configRevisions;
}
/**
* @param configRevisionsIn The configRevisions to set.
*/
public void setConfigRevisions(Set<ConfigRevision> configRevisionsIn) {
this.configRevisions = configRevisionsIn;
}
/**
* @return Returns the groups.
*/
public Set<ServerGroup> getGroups() {
return groups;
}
/**
* Add a group to the snapshot
* @param grp group to add
*/
public void addGroup(ServerGroup grp) {
groups.add(grp);
}
/**
* @param groupsIn The groups to set.
*/
public void setGroups(Set<ServerGroup> groupsIn) {
this.groups = groupsIn;
}
/**
* @return Returns the id.
*/
public Long getId() {
return id;
}
/**
* @param idIn The id to set.
*/
public void setId(Long idIn) {
this.id = idIn;
}
/**
* @return Returns the org.
*/
public Org getOrg() {
return org;
}
/**
* @param orgIn The org to set.
*/
public void setOrg(Org orgIn) {
this.org = orgIn;
}
/**
* @return Returns the reason.
*/
public String getReason() {
return reason;
}
/**
* @param reasonIn The reason to set.
*/
public void setReason(String reasonIn) {
this.reason = reasonIn;
}
/**
* @return Returns the server.
*/
public Server getServer() {
return server;
}
/**
* @param serverIn The server to set.
*/
public void setServer(Server serverIn) {
this.server = serverIn;
}
/**
* @return Returns the packages.
*/
public Set<PackageNevra> getPackages() {
return packages;
}
/**
* @param packagesIn The packages to set.
*/
public void setPackages(Set<PackageNevra> packagesIn) {
this.packages = packagesIn;
}
/**
* @return Returns the invalidReason.
*/
public InvalidSnapshotReason getInvalidReason() {
return invalidReason;
}
/**
* @param invalidReasonIn The invalidReason to set.
*/
public void setInvalidReason(InvalidSnapshotReason invalidReasonIn) {
this.invalidReason = invalidReasonIn;
}
/**
* @return Returns the tags.
*/
public List<SnapshotTag> getTags() {
return ServerFactory.getSnapshotTags(this);
}
/**
* adds tag to the snapshot
* @param tagName name of the tag
* @return true if tag was added to snapshot
*/
public boolean addTag(String tagName) {
for (SnapshotTag tag : getTags()) {
if (tagName.equals(tag.getName().getName())) {
return false;
}
}
ServerFactory.addTagToSnapshot(getId(), getOrg().getId(), tagName);
return true;
}
/**
*
* {@inheritDoc}
*/
public int hashCode() {
return new HashCodeBuilder().append(reason.hashCode())
.append(channels.hashCode())
.append(configChannels.hashCode())
.append(configRevisions.hashCode())
.append(server.hashCode())
.append(groups.hashCode())
.toHashCode();
}
/**
* @return Returns date in format yyyy-MM-dd HH:mm:ss so it can be used as a name
*/
public String getName() {
return DF.format(this.getCreated());
}
/**
* counts number of group diffs between server and snapshot
* @param sid server id
* @return number of differences
*/
public int groupDiffs(Long sid) {
return getDiffs(sid, "SystemGroup_queries", "snapshot_group_diff");
}
/**
* counts number of channel diffs between server and snapshot
* @param sid server id
* @return number of differences
*/
public int channelDiffs(Long sid) {
return getDiffs(sid, "Channel_queries", "snapshot_channel_diff");
}
/**
* counts number of package diffs between server and snapshot
* @param sid server id
* @return number of differences
*/
public int packageDiffs(Long sid) {
return getDiffs(sid, "Package_queries", "compare_packages_to_snapshot");
}
/**
* counts number of config channel diffs between server and snapshot
* @param sid server id
* @return number of differences
*/
public int configChannelsDiffs(Long sid) {
return getDiffs(sid, "config_queries", "snapshot_configchannel_diff");
}
/**
* private function to retrieve number of diffs from database
* @param sid server id
* @param name filename for ModeFactory.getMode()
* @param mode query name for ModeFactory.getMode()
* @return number of differences
*/
private int getDiffs(Long sid, String name, String mode) {
SelectMode m = ModeFactory.getMode(name, mode);
Map<String, Long> params = new HashMap<String, Long>();
params.put("ss_id", id);
params.put("sid", sid);
DataResult dr = m.execute(params);
return dr.size();
}
/**
* cancel pending action on system (needed fo rollback)
*/
public void cancelPendingActions() {
ActionFactory.cancelPendingForSystem(this.server.getId());
}
/**
* rollback server channels to snapshot
*/
public void rollbackChannels() {
// unsubscribe from all channels
DataResult<Map<String, Object>> chs = SystemManager.channelsForServer(
this.server);
for (Map<String, Object> ch : chs) {
SystemManager.unsubscribeServerFromChannel(this.server.getId(),
(Long) ch.get("id"));
}
// subscribe to appropriate channels
chs = snapshotChannelList();
for (Map<String, Object> ch : chs) {
SystemManager.subscribeServerToChannel(null, this.server,
ChannelFactory.lookupById((Long) ch.get("id")));
}
}
/**
* rollback server groups to snapshot
*/
public void rollbackGroups() {
// remove from all groups
Long sid = this.server.getId();
DataResult<Map<String, Object>> grps = SystemManager.listSystemGroups(sid);
for (Map<String, Object> grp : grps) {
ServerFactory.removeServerFromGroup(sid, (Long) grp.get("id"));
}
// add to appropriate groups
for (ServerGroup grp : getGroups()) {
ServerFactory.addServerToGroup(this.server, grp);
}
}
/**
* rollback server packages to snapshot
* @param user who schedules file deployment
* @return true if package update has been scheduled
*/
public boolean rollbackPackages(User user) {
// schedule package delta, if needed
if (packageDiffs(this.server.getId()) > 0) {
DataResult pkgs = preparePackagesForSync();
PackageAction action =
ActionManager.schedulePackageRunTransaction(
user, this.server, pkgs, new Date());
return true;
}
return false;
}
/**
* rollback server chonfig files to snapshot
* @param user who schedules file deployment
* @return true if any config files has been deployed
*/
public boolean rollbackConfigFiles(User user) {
boolean deployed = false;
// current config_channels
Set<ConfigChannel> ccs = new HashSet<ConfigChannel>(
this.server.getConfigChannels());
if (ccs != null) {
for (ConfigChannel cc : ccs) {
if (cc.isGlobalChannel()) {
this.server.unsubscribe(cc);
}
}
}
// get the config_channels recorded from the snapshot
ccs = getConfigChannels();
// tie config_channel list to server
if (ccs != null) {
for (ConfigChannel cc : ccs) {
if (cc.isGlobalChannel()) {
this.server.subscribe(cc);
}
}
}
// deploy the particular config files
Set<ConfigRevision> revs = getConfigRevisions();
if (revs != null) {
List<Long> revLongs = new ArrayList<Long>();
for (ConfigRevision rev : revs) {
revLongs.add(rev.getId());
deployed = true;
}
List<Long> serverIds = new ArrayList<Long>();
serverIds.add(this.server.getId());
Action action = ActionManager.createConfigAction(user, revLongs, serverIds,
ActionFactory.TYPE_CONFIGFILES_DEPLOY, new Date());
}
return deployed;
}
/**
* list of channel associated with snapshot
* @return Returns a DataResult of maps representing channels
*/
public DataResult<Map<String, Object>> snapshotChannelList() {
Map<String, Long> params = new HashMap<String, Long>();
params.put("sid", server.getId());
params.put("ss_id", this.id);
SelectMode m = ModeFactory.getMode("Channel_queries",
"system_snapshot_channel_list", Map.class);
return m.execute(params);
}
@SuppressWarnings("rawtypes")
private DataResult preparePackagesForSync() {
SelectMode m = ModeFactory.getMode("Package_queries",
"compare_packages_to_snapshot");
Map<String, Object> params = new HashMap<String, Object>();
params.put("sid", this.server.getId());
params.put("ss_id", this.id);
DataResult<Map<String, Object>> pkgsDiff = m.execute(params);
List<PackageMetadata> pkgsMeta = new ArrayList<PackageMetadata>();
for (Map pkgDiff : pkgsDiff) {
PackageListItem systemPkg = new PackageListItem();
systemPkg.setName((String) pkgDiff.get("package_name"));
systemPkg.setArch((String) pkgDiff.get("arch"));
systemPkg.setEpoch((String) pkgDiff.get("server_epoch"));
systemPkg.setVersion((String) pkgDiff.get("server_version"));
systemPkg.setRelease((String) pkgDiff.get("server_release"));
PackageListItem snapshotPkg = new PackageListItem();
snapshotPkg.setName((String) pkgDiff.get("package_name"));
snapshotPkg.setArch((String) pkgDiff.get("arch"));
snapshotPkg.setEpoch((String) pkgDiff.get("snapshot_epoch"));
snapshotPkg.setVersion((String) pkgDiff.get("snapshot_version"));
snapshotPkg.setRelease((String) pkgDiff.get("snapshot_release"));
PackageMetadata pm = new PackageMetadata(systemPkg, snapshotPkg);
int comparison;
switch (((Number) pkgDiff.get("comparison")).intValue()) {
case -2: comparison = PackageMetadata.KEY_OTHER_ONLY;
break;
case -1: comparison = PackageMetadata.KEY_OTHER_NEWER;
break;
case 1: comparison = PackageMetadata.KEY_THIS_NEWER;
break;
case 2: comparison = PackageMetadata.KEY_THIS_ONLY;
break;
default: comparison = PackageMetadata.KEY_NO_DIFF;
}
pm.setComparison(comparison);
pm.updateActionStatus();
pkgsMeta.add(pm);
}
DataResult<PackageMetadata> ret = new DataResult<PackageMetadata>(pkgsMeta);
return ret;
}
/**
* @return return list of unservable packages for snapshot
*/
public DataResult<Map<String, Object>> getUnservablePackages() {
return SystemManager.systemSnapshotUnservablePackages(org.getId(),
server.getId(), id, null);
}
}