package jenkins.install;
import static java.util.logging.Level.FINE;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.inject.Provider;
import javax.servlet.http.HttpSession;
import org.apache.commons.io.FileUtils;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.WebApp;
import org.kohsuke.stapler.interceptor.RequirePOST;
import hudson.Extension;
import hudson.util.HttpResponses;
import jenkins.model.Jenkins;
import net.sf.json.JSONArray;
/**
* This class is responsible for specific upgrade behaviors in the Jenkins UI.
*
* Note an instance of this class is already an @Extension in {@link InstallState#UPGRADE}
*
* @author Kohsuke Kawaguchi, Keith Zantow
*/
@Restricted(NoExternalUse.class)
public class UpgradeWizard extends InstallState {
/**
* Is this instance fully upgraded?
*/
private volatile boolean isUpToDate = true;
/**
* Whether to show the upgrade wizard
*/
private static final String SHOW_UPGRADE_WIZARD_FLAG = UpgradeWizard.class.getName() + ".show";
/*package*/ UpgradeWizard() {
super("UPGRADE", false);
}
/**
* Get the upgrade wizard instance
*/
public static UpgradeWizard get() {
return (UpgradeWizard)InstallState.UPGRADE;
}
@Override
public void initializeState() {
// Initializing this state is directly related to
// running the detached plugin checks, these should be consolidated somehow
updateUpToDate();
// If there are no platform updates, proceed to running
if (isUpToDate) {
if (Jenkins.getInstance().getSetupWizard().getPlatformPluginUpdates().isEmpty()) {
Jenkins.getInstance().setInstallState(InstallState.RUNNING);
}
}
}
@Override
public boolean isSetupComplete() {
return !isDue();
}
private void updateUpToDate() {
// If we don't have any platform plugins, it's considered 'up to date' in terms
// of the updater
try {
JSONArray platformPlugins = Jenkins.getInstance().getSetupWizard().getPlatformPluginUpdates();
isUpToDate = platformPlugins.isEmpty();
} catch(Exception e) {
LOGGER.log(Level.WARNING, "Unable to get the platform plugin update list.", e);
}
}
/**
* Do we need to show the upgrade wizard prompt?
*/
public boolean isDue() {
if (isUpToDate)
return false;
// only admin users should see this
if (!Jenkins.getInstance().hasPermission(Jenkins.ADMINISTER))
return false;
// only show when Jenkins is fully up & running
WebApp wa = WebApp.getCurrent();
if (wa==null || !(wa.getApp() instanceof Jenkins))
return false;
return System.currentTimeMillis() > SetupWizard.getUpdateStateFile().lastModified();
}
/**
* Whether to show the upgrade wizard
*/
public boolean isShowUpgradeWizard() {
HttpSession session = Stapler.getCurrentRequest().getSession(false);
if(session != null) {
return Boolean.TRUE.equals(session.getAttribute(SHOW_UPGRADE_WIZARD_FLAG));
}
return false;
}
/**
* Call this to show the upgrade wizard
*/
public HttpResponse doShowUpgradeWizard() throws Exception {
Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER);
HttpSession session = Stapler.getCurrentRequest().getSession(true);
session.setAttribute(SHOW_UPGRADE_WIZARD_FLAG, true);
return HttpResponses.redirectToContextRoot();
}
/**
* Call this to hide the upgrade wizard
*/
public HttpResponse doHideUpgradeWizard() {
Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER);
HttpSession session = Stapler.getCurrentRequest().getSession(false);
if(session != null) {
session.removeAttribute(SHOW_UPGRADE_WIZARD_FLAG);
}
return HttpResponses.redirectToContextRoot();
}
/**
* Snooze the upgrade wizard notice.
*/
@RequirePOST
public HttpResponse doSnooze() throws IOException {
Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER);
File f = SetupWizard.getUpdateStateFile();
FileUtils.touch(f);
f.setLastModified(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1));
LOGGER.log(FINE, "Snoozed the upgrade wizard notice");
return HttpResponses.redirectToContextRoot();
}
@Extension
public static class ListenForInstallComplete extends InstallStateFilter {
@Override
public InstallState getNextInstallState(InstallState current, Provider<InstallState> proceed) {
InstallState next = proceed.get();
if (InstallState.INITIAL_SETUP_COMPLETED.equals(current)) {
UpgradeWizard.get().isUpToDate = true;
}
return next;
}
}
private static final Logger LOGGER = Logger.getLogger(UpgradeWizard.class.getName());
}