/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package controllers.infra; import com.emc.storageos.coordinator.client.model.SiteState; import com.emc.storageos.model.db.DbConsistencyStatusRestRep; import com.emc.storageos.model.dr.SiteRestRep; import com.emc.vipr.model.sys.ClusterInfo; import com.emc.vipr.model.sys.DownloadProgress; import com.emc.vipr.model.sys.NodeProgress; import com.google.common.collect.Maps; import controllers.Common; import controllers.Maintenance; import controllers.deadbolt.Restrict; import controllers.deadbolt.Restrictions; import play.Logger; import play.mvc.Controller; import play.mvc.Util; import play.mvc.With; import util.BourneUtil; import util.DisasterRecoveryUtils; import util.MessagesUtils; import java.util.Collection; import java.util.Collections; import java.util.Map; import static util.BourneUtil.*; @With(Common.class) @Restrictions({ @Restrict("SYSTEM_ADMIN"), @Restrict("RESTRICTED_SYSTEM_ADMIN") }) public class Upgrade extends Controller { public static String TRUE = "1"; public static String FALSE = "0"; private static String DOWNLOADING_CLUSTER_STATE = "DOWNLOADING"; private static String NOT_STARTED = "NOT_STARTED"; public static void index() { render(); } public static void clusterStatus() { ClusterInfo clusterInfo = getSysClient().upgrade().getClusterInfo(); Collection<String> repositoryVersions = clusterInfo.getTargetState().getAvailable(); Collection<String> newVersions = clusterInfo.getNewVersions() == null ? Collections.<String> emptyList() : clusterInfo .getNewVersions(); String clusterState = calculateClusterState(clusterInfo); boolean isStable = clusterState.equalsIgnoreCase(ClusterInfo.ClusterState.STABLE.toString()); boolean isWorking = !isStable && !clusterState.equalsIgnoreCase(ClusterInfo.ClusterState.UNKNOWN.toString()); boolean isDownloading = clusterState.equals(DOWNLOADING_CLUSTER_STATE) || isStandbySiteDownloading(); DbConsistencyStatusRestRep checkDbState = getSysClient().upgrade().getDbCheckState(); String isDbCheckStatus = checkDbState.getStatus().toString(); int checkProgress = checkDbState.getProgress(); Map<String, Map<String, DownloadStatus>> downloadStatus = Maps.newLinkedHashMap(); if (isDownloading) { SiteRestRep activeSite = DisasterRecoveryUtils.getActiveSite(); DownloadProgress downloadProgress = getSysClient().upgrade().getDownloadProgress(); downloadStatus.put(activeSite.getName(), calculateDownloadStatus(downloadProgress)); for (SiteRestRep standby : DisasterRecoveryUtils.getStandbySites()) { downloadProgress = getSysClient().upgrade().getDownloadProgress(standby.getUuid()); downloadStatus.put(standby.getName(), calculateDownloadStatus(downloadProgress)); } } render(clusterInfo, clusterState, newVersions, repositoryVersions, isStable, isWorking, isDownloading, downloadStatus, checkProgress, isDbCheckStatus); } /* * Method to trigger Database consistency check */ public static void checkDbStatus() { ClusterInfo clusterInfo = getSysClient().upgrade().getClusterInfo(); String clusterState = calculateClusterState(clusterInfo); try { BourneUtil.getSysClient().upgrade().triggerDbCheck(); } catch (Exception e) { Logger.error(e, "Checking Database Consistency"); flash.error(MessagesUtils.escape(e.getMessage())); } render(clusterInfo,clusterState); } public static void checkDbStatusOK() { index(); } /* * Method to cancel ongoing Database check */ public static void cancelCheckDbStatus() { try { BourneUtil.getSysClient().upgrade().cancelDbCheck(); } catch (Exception e) { Logger.error(e, "Cancelling Database Consistency"); flash.error(MessagesUtils.escape(e.getMessage())); } index(); } public static void checkDbProgress() { DbConsistencyStatusRestRep dbState = getSysClient().upgrade().getDbCheckState(); renderJSON(dbState); } public static void installVersion(String version, boolean doPrecheck) { try { getSysClient().upgrade().setTargetVersion(version, doPrecheck); } catch (Exception e) { Logger.error(e, "Setting target version to %s", version); flash.error(MessagesUtils.escape(e.getMessage())); } flash.success(MessagesUtils.get("upgrade.setTargetVersion", version)); Maintenance.maintenance(Common.reverseRoute(Upgrade.class, "index")); } public static void removeImage(String version) { try { getSysClient().upgrade().removeImage(version, true); } catch (Exception e) { Logger.error(e, "Error removing Image %s", version); flash.error(MessagesUtils.escape(e.getMessage())); } index(); } public static void downloadImage(String version) { try { getSysClient().upgrade().installImage(version, false); } catch (Exception e) { Logger.error(e, "Installing Image %s", version); flash.error(MessagesUtils.escape(e.getMessage())); } index(); } public static void downloadProgress() { Map<String, Map<String, DownloadStatus>> siteProgress = Maps.newLinkedHashMap(); SiteRestRep activeSite = DisasterRecoveryUtils.getActiveSite(); DownloadProgress downloadProgress = getSysClient().upgrade().getDownloadProgress(); siteProgress.put(activeSite.getName(), calculateDownloadStatus(downloadProgress)); for (SiteRestRep standby : DisasterRecoveryUtils.getStandbySites()) { downloadProgress = getSysClient().upgrade().getDownloadProgress(standby.getUuid()); siteProgress.put(standby.getName(), calculateDownloadStatus(downloadProgress)); } renderJSON(siteProgress); } public static void cancelDownload() { try { getSysClient().upgrade().cancelInstallImage(); } catch (Exception e) { Logger.error(e, "Cancelling Install Image"); flash.error(MessagesUtils.escape(e.getMessage())); } index(); } /** * Allows the UI to ping the backend so that it knows when the upgrade is complete */ public static void statusChanged(String currentStatus) { ClusterInfo clusterInfo = getSysClient().upgrade().getClusterInfo(); String clusterState = calculateClusterState(clusterInfo); // if the current status is downloading, // don't go back to the index page until download is complete on all sites if (currentStatus.equals(DOWNLOADING_CLUSTER_STATE)) { renderJSON(!clusterState.equals(currentStatus) && !isStandbySiteDownloading()); } else { boolean statusChanged = !clusterState.equals(currentStatus); renderJSON(statusChanged); } } @Util private static boolean isStandbySiteDownloading() { for (SiteRestRep standby : DisasterRecoveryUtils.getStandbySites()) { if (SiteState.STANDBY_PAUSED.toString().equals(standby.getState()) || SiteState.STANDBY_PAUSING.toString().equals(standby.getState()) || SiteState.STANDBY_RESUMING.toString().equals(standby.getState())) { // these are supposed to be normal since pause/resume is considered part of the upgrade process continue; } try { ClusterInfo clusterInfo = getSysClient().upgrade().getClusterInfo(standby.getUuid()); if (calculateClusterState(clusterInfo, standby.getUuid()).equals(DOWNLOADING_CLUSTER_STATE)) { return true; } } catch (Exception e) { Logger.error(e, "Getting Standby Site Cluster Info"); flash.error(MessagesUtils.escape(String.format("Failed to get cluster state for site %s", standby.getName()))); } } return false; } @Util private static boolean isDownloadInProgress(DownloadProgress downloadProgress) { for (NodeProgress nodeProgress : downloadProgress.getProgress().values()) { if (nodeProgress.getStatus() == NodeProgress.DownloadStatus.NORMAL) { return true; } } return false; } @Util static Map<String, DownloadStatus> calculateDownloadStatus(DownloadProgress downloadProgress) { long imageSize = downloadProgress.getImageSize(); Map<String, DownloadStatus> nodeProgress = Maps.newHashMap(); for (Map.Entry<String, NodeProgress> nodeEntry : downloadProgress.getProgress().entrySet()) { String nodeId = nodeEntry.getKey().substring("syssvc-".length()); nodeProgress.put(nodeId, new DownloadStatus(calculatePercentage(nodeEntry.getValue().getBytesDownloaded(), imageSize), nodeEntry.getValue().getStatus().toString())); } return nodeProgress; } @Util private static int calculatePercentage(long bytes, long total) { return (int) Math.round(((double) bytes / (double) total) * 100); } @Util private static String calculateClusterState(ClusterInfo clusterInfo) { return calculateClusterState(clusterInfo, null); } @Util private static String calculateClusterState(ClusterInfo clusterInfo, String siteId) { if (clusterInfo.getCurrentState().equalsIgnoreCase(ClusterInfo.ClusterState.SYNCING.toString())) { DownloadProgress downloadProgress = getSysClient().upgrade().getDownloadProgress(siteId); if (isDownloadInProgress(downloadProgress)) { return DOWNLOADING_CLUSTER_STATE; } } return clusterInfo.getCurrentState(); } public static class DownloadStatus { Integer percent; String status; public DownloadStatus(Integer percent, String status) { this.percent = percent; this.status = status; } public boolean isErrorStatus() { return !(status.equals("COMPLETED") || status.equals("NORMAL")); } } }