diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a6f89c2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target/ \ No newline at end of file diff --git a/pom.xml b/pom.xml index 1dd5808..89f282e 100755 --- a/pom.xml +++ b/pom.xml @@ -3,12 +3,12 @@ org.jenkins-ci.plugins plugin - 1.532 + 2.4 org.jenkins-ci.plugins diskcheck - 0.27 + 0.99 hpi @@ -31,6 +31,11 @@ Manoj Thakkar mthakkar@cloudera.com + + fsta + Frano Stanisic + frano.stanisic@serato.com + @@ -46,6 +51,8 @@ + + repo.jenkins-ci.org diff --git a/src/main/java/org/jenkinsci/plugin/Diskcheck.java b/src/main/java/org/jenkinsci/plugin/Diskcheck.java old mode 100644 new mode 100755 index 0de2de4..b4d9684 --- a/src/main/java/org/jenkinsci/plugin/Diskcheck.java +++ b/src/main/java/org/jenkinsci/plugin/Diskcheck.java @@ -2,6 +2,7 @@ import hudson.AbortException; import hudson.Extension; +import hudson.FilePath; import hudson.Launcher; import hudson.model.BuildListener; import hudson.model.AbstractBuild; @@ -10,195 +11,180 @@ import hudson.tasks.BuildWrapper; import hudson.node_monitors.*; import hudson.model.Node; -import hudson.model.Result; -import hudson.tasks.BatchFile; -import hudson.tasks.CommandInterpreter; -import hudson.tasks.Shell; import org.kohsuke.stapler.DataBoundConstructor; -import java.io.File; import java.io.IOException; import java.io.PrintStream; - - +import java.net.UnknownHostException; +import java.util.List; /** * Class to allow any build step to be performed before the SCM checkout occurs. - * + * * @author Manoj Thakkar + * @author Frano Stanisic (8th Decemeber 2015, updated deletion to use Jenkins API/only delete files up to a threshhold) * */ - - public class Diskcheck extends BuildWrapper { + public final boolean failOnError; + + public static FilePath lastFileModified(PrintStream log, FilePath dir) throws UnknownHostException, IOException, InterruptedException { + log.println("Determining file to delete ..."); + List files = dir.listDirectories(); + long lastMod = Long.MAX_VALUE; + FilePath choice = null; + for (FilePath file : files) { + if (file.lastModified() < lastMod) { + choice = file; + lastMod = file.lastModified(); + } + } + return choice; + } + + /** + * Constructor taking a list of buildsteps to use. + */ + @DataBoundConstructor + public Diskcheck(boolean failOnError) { + this.failOnError = failOnError; + } + + /** + * Overridden setup returns a noop class as we don't want to add anything + * here. + * + * @return noop Environment class + */ + @Override + public Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { + return new NoopEnv(); + } + + /** + * Overridden precheckout step, this is where we do all the work. + * + * Checks to make sure we have some buildsteps set, and then calls the + * prebuild and perform on all of them. + * + * TODO handle build steps failure in some sort of reasonable way + * + */ + @Override + public Descriptor getDescriptor() { + return (Descriptor) super.getDescriptor(); + } + + @Override + public void preCheckout(AbstractBuild build, Launcher launcher, + BuildListener listener) throws IOException, InterruptedException { + PrintStream log = listener.getLogger(); + // Default value of disk space check is 1GB + int SpaceThreshold = PluginImpl.getInstance().getSpacecheck(); + + log.println("Disk space upper threshold is set to :" + SpaceThreshold + "GB"); + log.println("Checking disk space now ..."); + + // Touch workspace so that it is created on first time. + FilePath workspacePath = build.getWorkspace(); + if (workspacePath == null) { + return; + } + if (!workspacePath.exists()) { + workspacePath.mkdirs(); + } - public final boolean failOnError; - - /** - * Constructor taking a list of buildsteps to use. - * - * @param buildstep - * list of but steps configured in the UI - */ - @DataBoundConstructor - public Diskcheck(boolean failOnError) { - this.failOnError = failOnError; - } - - /** - * Overridden setup returns a noop class as we don't want to add annything - * here. - * - * @param build - * @param launcher - * @param listener - * @return noop Environment class - */ - @Override - public Environment setUp(AbstractBuild build, Launcher launcher, - BuildListener listener) throws IOException, InterruptedException { - return new NoopEnv(); - } - - /** - * Overridden precheckout step, this is where wedo all the work. - * - * Checks to make sure we have some buildsteps set, and then calls the - * prebuild and perform on all of them. - * - * @todo handle build steps failure in some sort of reasonable way - * - * @param build - * @param launcher - * @param listener - */ - - @Override - public Descriptor getDescriptor() { - return (Descriptor) super.getDescriptor(); - } - @Override - public void preCheckout(AbstractBuild build, Launcher launcher, - BuildListener listener) throws IOException, InterruptedException { - PrintStream log = listener.getLogger(); -// Default value of disk space check is 1Gb - int SpaceThreshold; - SpaceThreshold = PluginImpl.getInstance().getSpacecheck(); - - - log.println("Disk space threshold is set to :" + SpaceThreshold + "Gb"); - log.println("Checking disk space Now "); - - /* touch workspace so that it is created on first time */ - if (!build.getWorkspace().exists()) { - build.getWorkspace().mkdirs(); - } - - Node node1 = build.getBuiltOn(); - Computer Comp = node1.toComputer(); - String NodeName = build.getBuiltOnStr(); - /* if (Comp.getChannel()==null) - { - log.println("Can not get slave infomration wait for 10 sec \n"); - Thread.sleep(10000); - if (Comp.getChannel()==null) - { - log.println("Waited long enough to get slave information exiting discheck for now \n"); - System.exit(0); - } - + Node node1 = build.getBuiltOn(); + if (node1 == null) { + return; } - */ - - if ( DiskSpaceMonitor.DESCRIPTOR.get(Comp)== null ) - { log.println("No Slave Data available trying to get data from slave"); + Computer Comp = node1.toComputer(); + String NodeName = build.getBuiltOnStr(); + + // This new implementation doesn't even touch this, but given I + // am not 100% on what it does I have just left it here. + if (DiskSpaceMonitor.DESCRIPTOR.get(Comp) == null) { + log.println("No slave data available, waiting and retrying ..."); Thread.sleep(10000); - if ( DiskSpaceMonitor.DESCRIPTOR.get(Comp)== null ) - - log.println(" Could not get Slave Information , Exiting Disk check for this slave"); - System.exit(0); + if (DiskSpaceMonitor.DESCRIPTOR.get(Comp) == null) { + log.println("Could not retrieve slave data, exiting disk check for this slave."); + } + return; } - - long size=0; - try - { - size = DiskSpaceMonitor.DESCRIPTOR.get(Comp).size; + // End unsure bit. + + long size = workspacePath.getParent().getUsableDiskSpace(); + int roundedSize = (int) (size / (1024 * 1024 * 1024)); + log.println("Total disk space available is: " + roundedSize + "GB"); + + if ("".equals(NodeName)) { + NodeName = "master"; } - catch(NullPointerException e ){ - log.println("Could not get Slave Information , Exiting Disk check for this slave"); - System.exit(0); - } - int roundedSize = (int) (size / (1024 * 1024 * 1024)); - log.println("Total Disk Space Available is: " + roundedSize + "Gb"); - - if (build.getBuiltOnStr() == "") { - NodeName = "master"; - } - - log.println(" Node Name: " + NodeName); - - if (PluginImpl.getInstance().isDiskrecyclerenabled()) { - if (roundedSize < SpaceThreshold) { - log.println("Disk Recycler is Enabled so I am going to wipe off the workspace Directory Now "); - String mycommand = "echo $WORKSPACE; rm -rf $WORKSPACE/../; df -k ."; - String mywincommand = "echo Deleting file from %WORKSPACE% && Del /R %WORKSPACE%"; - - /** - * This method will return the command intercepter as per the - * node OS - * - * @param launcher - * @param script - * @return CommandInterpreter - */ - CommandInterpreter runscript; - if (launcher.isUnix()) - runscript = new Shell(mycommand); - else - runscript = new BatchFile(mywincommand); - - Result result = runscript.perform(build, launcher, listener) ? Result.SUCCESS - : Result.FAILURE; - - if (result.toString() == "FAILURE") { - throw new AbortException( - "Something went wrong while deleting Files , Please check the error message above"); - } - } - } - - log.println("Running Prebuild steps"); - if (roundedSize < SpaceThreshold - && !(PluginImpl.getInstance().isDiskrecyclerenabled())) { - throw new AbortException( - "Disk Space is too low please look into it before starting a build"); - - } - } - - - @Extension - public static final class DescriptorImpl extends Descriptor { - - /** - * This human readable name is used in the configuration screen. - */ - public String getDisplayName() { - return "Check Disk Space"; - } - - - - public DescriptorImpl() { + + log.println("Node Name: " + NodeName); + boolean diskrecyclerenabled = PluginImpl.getInstance().isDiskrecyclerenabled(); + if (diskrecyclerenabled) { + if (roundedSize < SpaceThreshold) { + int clearUntil = PluginImpl.getInstance().getClearuntil(); + if (clearUntil == 0) { + log.println("clearUntil set to 0, clearing everything ..."); + // Jenkins api recursive delete, errors will cause a build failure. + workspacePath.getParent().deleteRecursive(); + log.println("All workspaces deleted successfully."); + } else { + if (clearUntil < SpaceThreshold) { + throw new AbortException( + "Your space clearing thresholds are the wrong way around." + + " Edit them and run this job again."); + } + // Not enough room on slave, start clearing until threshhold met. + while (roundedSize < clearUntil) { + FilePath lastUsedDir = lastFileModified(log, workspacePath.getParent()); + if (lastUsedDir == null) { + throw new AbortException( + "There is nothing left in the workspace, but room still needs to be made." + + " Either the thresholds are wrong, or there is an issue on the slave."); + } + log.println("Deleting workspace " + lastUsedDir.getRemote() + "."); + // Jenkins api recursive delete, errors will cause a build failure. + lastUsedDir.deleteRecursive(); + log.println("Workspace deleted."); + size = workspacePath.getParent().getUsableDiskSpace(); + roundedSize = (int) (size / (1024 * 1024 * 1024)); + log.println("New disk space available is: " + roundedSize + "GB"); + } + } + } + } + + log.println("Running prebuild steps ..."); + if (roundedSize < SpaceThreshold + && !diskrecyclerenabled) { + throw new AbortException( + "Disk space is too low, investigate prior to starting another build."); + + } + } + + @Extension + public static final class DescriptorImpl extends Descriptor { + + /** + * This human readable name is used in the configuration screen. + */ + @Override + public String getDisplayName() { + return "Check Disk Space"; + } + + public DescriptorImpl() { load(); } - - } - - - class NoopEnv extends Environment { - } + } + + class NoopEnv extends Environment { + } } diff --git a/src/main/java/org/jenkinsci/plugin/PluginImpl.java b/src/main/java/org/jenkinsci/plugin/PluginImpl.java index f8c44cd..51fb6dc 100755 --- a/src/main/java/org/jenkinsci/plugin/PluginImpl.java +++ b/src/main/java/org/jenkinsci/plugin/PluginImpl.java @@ -1,75 +1,86 @@ package org.jenkinsci.plugin; +import hudson.AbortException; import hudson.Plugin; -import hudson.model.*; -import hudson.model.AbstractBuild; -import hudson.model.AbstractProject; import hudson.model.Descriptor.FormException; -import hudson.model.Hudson; import java.io.IOException; import javax.servlet.ServletException; +import jenkins.model.Jenkins; import net.sf.json.JSONObject; import org.kohsuke.stapler.StaplerRequest; -//import com.innorium.crystalline.plugins.model.ScannerJobProperty; +public class PluginImpl extends Plugin { -public class PluginImpl extends Plugin{ - private boolean diskrecyclerenabled; - private int spacecheck; - - /** + private boolean diskrecyclerenabled; + private int spacecheck; + private int clearuntil; + + /** * Returns the singleton instance. * * @return the one. + * @throws hudson.AbortException + * If Jenkins instance is not ready */ - public static PluginImpl getInstance() { - return Hudson.getInstance().getPlugin(PluginImpl.class); + public static PluginImpl getInstance() throws AbortException { + // To remove warning. I don't think this would ever be null in our case. + Jenkins instance = Jenkins.getInstance(); + if (instance == null) { + throw new AbortException( + "Can't access Jenkins instance, it may not be ready."); + } + return instance.getPlugin(PluginImpl.class); } - - @Override - public void start() throws Exception { - super.start(); - load(); - } - - @Override - public void stop() throws Exception { - super.stop(); - } - - @Override - public void configure(StaplerRequest req, JSONObject formData) - throws IOException, ServletException, FormException { - formData=formData.getJSONObject("disk-check"); - spacecheck=formData.getInt("spacecheck"); - diskrecyclerenabled=formData.getBoolean("diskrecyclerenabled"); - - save(); - super.configure(req, formData); - - } - - - - public void setDiskrecyclerenabled(boolean diskrecyclerenabled) { - this.diskrecyclerenabled = diskrecyclerenabled; -} - - public int getSpacecheck() - { - return spacecheck; - } - - public void setSpacecheck(int spaceheck) - { - this.spacecheck = spacecheck; -} - public boolean isDiskrecyclerenabled() { - return diskrecyclerenabled; - } -} \ No newline at end of file + @Override + public void start() throws Exception { + super.start(); + load(); + } + + @Override + public void stop() throws Exception { + super.stop(); + } + + @Override + public void configure(StaplerRequest req, JSONObject formData) + throws IOException, ServletException, FormException { + formData = formData.getJSONObject("disk-check"); + spacecheck = formData.getInt("spacecheck"); + clearuntil = formData.getInt("clearuntil"); + diskrecyclerenabled = formData.getBoolean("diskrecyclerenabled"); + + save(); + super.configure(req, formData); + + } + + public void setDiskrecyclerenabled(boolean diskrecyclerenabled) { + this.diskrecyclerenabled = diskrecyclerenabled; + } + + public int getSpacecheck() { + return spacecheck; + } + + public void setSpacecheck(int spaceCheck) { + this.spacecheck = spaceCheck; + } + + public int getClearuntil() { + return clearuntil; + } + + public void setClearuntil(int clearUntil) { + this.clearuntil = clearUntil; + } + + public boolean isDiskrecyclerenabled() { + return diskrecyclerenabled; + } +} diff --git a/src/main/resources/index.jelly b/src/main/resources/index.jelly index b620b55..ddee10b 100755 --- a/src/main/resources/index.jelly +++ b/src/main/resources/index.jelly @@ -1,6 +1,7 @@ +
This plugin is to check the disk usage of your node
diff --git a/src/main/resources/org/jenkinsci/plugin/PluginImpl/config.jelly b/src/main/resources/org/jenkinsci/plugin/PluginImpl/config.jelly index 50391e0..2b70d78 100755 --- a/src/main/resources/org/jenkinsci/plugin/PluginImpl/config.jelly +++ b/src/main/resources/org/jenkinsci/plugin/PluginImpl/config.jelly @@ -1,3 +1,4 @@ +