package hudson.plugins.disk_usage; import hudson.plugins.disk_usage.unused.DiskUsageNotUsedDataCalculationThread; import hudson.Extension; import hudson.Plugin; import hudson.Util; import hudson.model.*; import hudson.model.Item; import hudson.model.RootAction; import hudson.plugins.disk_usage.unused.DiskUsageItemGroup; import hudson.security.Permission; import hudson.util.Graph; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.servlet.ServletException; import jenkins.model.Jenkins; import org.jfree.data.category.DefaultCategoryDataset; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; /** * Entry point of the the plugin. * * @author dvrzalik * @plugin */ @Extension public class DiskUsagePlugin extends Plugin { // private Long diskUsageBuilds = 0l; // private Long diskUsageJobsWithoutBuilds = 0l; // private Long diskUsageNotLoadedJobs = 0l; // private Long diskUsageNotLoadedBuilds = 0l; // private Long diskUsageWorkspaces = 0l; // private Long diskUsageLockedBuilds = 0l; // private Long diskUsageNonSlaveWorkspaces = 0l; private Map<ItemGroup,DiskUsageItemGroup> diskUsageItemGroups = new ConcurrentHashMap<ItemGroup,DiskUsageItemGroup>(); public DiskUsagePlugin(){ } public void addNewItemGroup(ItemGroup group, DiskUsageItemGroup diskUsage){ DiskUsageItemGroup usage = diskUsageItemGroups.get(group); diskUsageItemGroups.put(group, diskUsage); if(usage==null){ usage.load(); } } protected void loadDiskUsageItemGroups(){ diskUsageItemGroups.clear(); List<Action> actions = Jenkins.getInstance().getActions(); for(Action a : actions){ if(a instanceof DiskUsageJenkinsAction){ DiskUsageJenkinsAction jenkinsDUAction = (DiskUsageJenkinsAction) a; diskUsageItemGroups.put(Jenkins.getInstance(), jenkinsDUAction.getDiskUsageItemGroup()); loadAllDiskUsageForSubItemGroups(Jenkins.getInstance()); return; } } loadAllDiskUsageItemGroups(Jenkins.getInstance()); } public void loadAllDiskUsageForSubItemGroups(ItemGroup group){ for(Item item : (Collection<Item>)group.getItems()){ if(item instanceof ItemGroup){ loadAllDiskUsageItemGroups((ItemGroup)item); } } } protected void loadAllDiskUsageItemGroups(ItemGroup group){ DiskUsageItemGroup diskUsage = new DiskUsageItemGroup(group); diskUsage.load(); diskUsageItemGroups.put(group,diskUsage); for(Item item : (Collection<Item>)group.getItems()){ if(item instanceof ItemGroup){ loadAllDiskUsageItemGroups((ItemGroup)item); } } } public Map<ItemGroup,DiskUsageItemGroup> getDiskUsageItemGroups(){ return diskUsageItemGroups; } protected DiskUsageItemGroup loadDiskUsageItemGroupForItemGroup(ItemGroup group){ DiskUsageItemGroup diskUsage = new DiskUsageItemGroup(group); if(diskUsage.getConfigFile().exists()){ diskUsage.load(); } //new one else{ diskUsage.save(); } diskUsageItemGroups.put(group,diskUsage); return diskUsage; } public DiskUsageItemGroup getDiskUsageItemGrouForJenkinsRootAction(){ DiskUsageItemGroup usage = diskUsageItemGroups.get(Jenkins.getInstance()); if(usage==null){ usage = new DiskUsageItemGroup(Jenkins.getInstance()); usage.load(); diskUsageItemGroups.put(Jenkins.getInstance(),usage); } return usage; } public DiskUsageItemGroup getDiskUsageItemGroup(ItemGroup group){ DiskUsageItemGroup usage = diskUsageItemGroups.get(group); if(usage==null){ return loadDiskUsageItemGroupForItemGroup(group); } return usage; } public void putDiskUsageItemGroup(ItemGroup group) throws IOException{ if(!diskUsageItemGroups.containsKey(group)){ DiskUsageItemGroup usage = new DiskUsageItemGroup(group); diskUsageItemGroups.put(group, usage); usage.save(); } } public void removeDiskUsageItemGroup(ItemGroup group){ diskUsageItemGroups.remove(group); } // public void loadNotUsedDataDiskUsage(){ // diskUsageGroupItems.load(); // } public void refreshGlobalInformation() throws IOException{ DiskUsageJenkinsAction.getInstance().actualizeAllCashedDate(); } public Long getCashedGlobalBuildsDiskUsage(){ return getDiskUsageItemGrouForJenkinsRootAction().getCaschedDiskUsageBuilds().get("all"); } public Long getCashedGlobalJobsDiskUsage(){ return (getCashedGlobalBuildsDiskUsage() + getCashedGlobalJobsWithoutBuildsDiskUsage()); } public Long getCashedGlobalJobsWithoutBuildsDiskUsage(){ return getDiskUsageItemGrouForJenkinsRootAction().getCashedDiskUsageWithoutBuilds(); } public Long getCashedGlobalLockedBuildsDiskUsage(){ return getDiskUsageItemGrouForJenkinsRootAction().getCaschedDiskUsageBuilds().get("locked"); } public Long getCashedGlobalNotLoadedBuildsDiskUsage(){ return getDiskUsageItemGrouForJenkinsRootAction().getCaschedDiskUsageBuilds().get("notLoaded"); } public Long getCashedGlobalWorkspacesDiskUsage(){ return getDiskUsageItemGrouForJenkinsRootAction().getCashedDiskUsageWorkspaces(); } public Long getCashedNonSlaveDiskUsageWorkspace(){ return getDiskUsageItemGrouForJenkinsRootAction().getCashedDiskUsageCustomWorkspaces(); } public Long getCashedSlaveDiskUsageWorkspace(){ return getCashedGlobalWorkspacesDiskUsage() - getCashedNonSlaveDiskUsageWorkspace(); } public Long getGlobalBuildsDiskUsage() throws IOException{ refreshGlobalInformation(); return getCashedGlobalBuildsDiskUsage(); } public Long getGlobalJobsDiskUsage() throws IOException{ refreshGlobalInformation(); return getCashedGlobalJobsDiskUsage(); } public Long getGlobalJobsWithoutBuildsDiskUsage() throws IOException{ refreshGlobalInformation(); return getCashedGlobalJobsWithoutBuildsDiskUsage(); } public Long getGlobalWorkspacesDiskUsage() throws IOException{ refreshGlobalInformation(); return this.getCashedGlobalWorkspacesDiskUsage(); } public Long getGlobalNonSlaveDiskUsageWorkspace() throws IOException{ refreshGlobalInformation(); return getCashedNonSlaveDiskUsageWorkspace(); } public Long getGlobalSlaveDiskUsageWorkspace() throws IOException{ refreshGlobalInformation(); return getCashedSlaveDiskUsageWorkspace(); } public Long getGlobalNotLoadedBuildsDiskUsageWorkspace() throws IOException{ refreshGlobalInformation(); return getCashedGlobalNotLoadedBuildsDiskUsage(); } public BuildDiskUsageCalculationThread getBuildsDiskUsageThread(){ return AperiodicWork.all().get(BuildDiskUsageCalculationThread.class); } public JobWithoutBuildsDiskUsageCalculation getJobsDiskUsageThread(){ return AperiodicWork.all().get(JobWithoutBuildsDiskUsageCalculation.class); } public WorkspaceDiskUsageCalculationThread getWorkspaceDiskUsageThread(){ return AperiodicWork.all().get(WorkspaceDiskUsageCalculationThread.class); } public DiskUsageNotUsedDataCalculationThread getNotUsedDataDiskUsageThread(){ return AperiodicWork.all().get(DiskUsageNotUsedDataCalculationThread.class); } /** * @return DiskUsage for given project (shortcut for the view). Never null. */ public ProjectDiskUsageAction getDiskUsage(Job project) { ProjectDiskUsageAction action = project.getAction(ProjectDiskUsageAction.class); return action; } public String getDiskUsageInString(Long size){ return DiskUsageUtil.getSizeString(size); } /** * @return Project list sorted by occupied disk space */ public List getProjectList() throws IOException { refreshGlobalInformation(); Comparator<AbstractProject> comparator = new Comparator<AbstractProject>() { public int compare(AbstractProject o1, AbstractProject o2) { ProjectDiskUsageAction dua1 = getDiskUsage(o1); ProjectDiskUsageAction dua2 = getDiskUsage(o2); long result = dua2.getJobRootDirDiskUsage(true) + dua2.getAllDiskUsageWorkspace(true) - dua1.getJobRootDirDiskUsage(true) - dua1.getAllDiskUsageWorkspace(true); if(result > 0) return 1; if(result < 0) return -1; return 0; } }; List<AbstractProject> projectList = Jenkins.getInstance().getAllItems(AbstractProject.class); Collections.sort(projectList, comparator); return projectList; } public void doFilter(StaplerRequest req, StaplerResponse rsp) throws ServletException, IOException{ Date older = DiskUsageUtil.getDate(req.getParameter("older"), req.getParameter("olderUnit")); Date younger = DiskUsageUtil.getDate(req.getParameter("younger"), req.getParameter("youngerUnit")); req.setAttribute("filter", "filter"); req.setAttribute("older", older); req.setAttribute("younger", younger); req.getView(this, "index.jelly").forward(req, rsp); } public DiskUsageProjectActionFactory.DescriptorImpl getConfiguration(){ return DiskUsageProjectActionFactory.DESCRIPTOR; } public Graph getOverallGraph(){ File jobsDir = new File(Jenkins.getInstance().getRootDir(), "jobs"); long maxValue = getCashedGlobalJobsDiskUsage(); if(getConfiguration().getShowFreeSpaceForJobDirectory()){ maxValue = jobsDir.getTotalSpace(); } long maxValueWorkspace = Math.max(getCashedNonSlaveDiskUsageWorkspace(), getCashedSlaveDiskUsageWorkspace()); List<DiskUsageOvearallGraphGenerator.DiskUsageRecord> record = DiskUsageProjectActionFactory.DESCRIPTOR.getHistory(); //First iteration just to get scale of the y-axis for (DiskUsageOvearallGraphGenerator.DiskUsageRecord usage : record){ if(getConfiguration().getShowFreeSpaceForJobDirectory()){ maxValue = Math.max(maxValue,usage.getAllSpace()); } maxValue = Math.max(maxValue, usage.getJobsDiskUsage()); maxValueWorkspace = Math.max(maxValueWorkspace, usage.getSlaveWorkspacesUsage()); maxValueWorkspace = Math.max(maxValueWorkspace, usage.getNonSlaveWorkspacesUsage()); } int floor = (int) DiskUsageUtil.getScale(maxValue); int floorWorkspace = (int) DiskUsageUtil.getScale(maxValueWorkspace); String unit = DiskUsageUtil.getUnitString(floor); String unitWorkspace = DiskUsageUtil.getUnitString(floorWorkspace); double base = Math.pow(1024, floor); double baseWorkspace = Math.pow(1024, floorWorkspace); DefaultCategoryDataset dataset = new DefaultCategoryDataset(); DefaultCategoryDataset datasetW = new DefaultCategoryDataset(); for (DiskUsageOvearallGraphGenerator.DiskUsageRecord usage : record) { Date label = usage.getDate(); if(getConfiguration().getShowFreeSpaceForJobDirectory()){ dataset.addValue(((Long) usage.getAllSpace()) / base, "space for jobs directory", label); } dataset.addValue(((Long) usage.getJobsDiskUsage()) / base, "all jobs", label); dataset.addValue(((Long) usage.getBuildsDiskUsage()) / base, "all builds", label); datasetW.addValue(((Long) usage.getSlaveWorkspacesUsage()) / baseWorkspace, "slave workspaces", label); datasetW.addValue(((Long) usage.getNonSlaveWorkspacesUsage()) / baseWorkspace, "non slave workspaces", label); } //add current state if(getConfiguration().getShowFreeSpaceForJobDirectory()){ dataset.addValue(((Long) jobsDir.getTotalSpace()) / base, "space for jobs directory", "current"); } dataset.addValue(((Long) getCashedGlobalJobsDiskUsage()) / base, "all jobs", "current"); dataset.addValue(((Long) getCashedGlobalBuildsDiskUsage()) / base, "all builds", "current"); datasetW.addValue(((Long) getCashedSlaveDiskUsageWorkspace()) / baseWorkspace, "slave workspaces", "current"); datasetW.addValue(((Long) getCashedNonSlaveDiskUsageWorkspace()) / baseWorkspace, "non slave workspaces", "current"); return new DiskUsageGraph(dataset, unit, datasetW, unitWorkspace); } public void doRecordBuildDiskUsage(StaplerRequest req, StaplerResponse res) throws ServletException, IOException, Exception { Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); if(getConfiguration().isCalculationBuildsEnabled() && !getBuildsDiskUsageThread().isExecuting()) getBuildsDiskUsageThread().doAperiodicRun(); res.forwardToPreviousPage(req); } public void doRecordJobsDiskUsage(StaplerRequest req, StaplerResponse res) throws ServletException, IOException, Exception { Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); if(getConfiguration().isCalculationJobsEnabled() && !getJobsDiskUsageThread().isExecuting()) getJobsDiskUsageThread().doAperiodicRun(); res.forwardToPreviousPage(req); } public void doRecordWorkspaceDiskUsage(StaplerRequest req, StaplerResponse res) throws ServletException, IOException, Exception { Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); if(getConfiguration().isCalculationWorkspaceEnabled() && !getWorkspaceDiskUsageThread().isExecuting()) getWorkspaceDiskUsageThread().doAperiodicRun(); res.forwardToPreviousPage(req); } public void doRecordNotUsedDataDiskUsage(StaplerRequest req, StaplerResponse res) throws ServletException, IOException, Exception { Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); if(getConfiguration().isCalculationNotUsedDataEnabled() && !getNotUsedDataDiskUsageThread().isExecuting()) getNotUsedDataDiskUsageThread().doAperiodicRun(); res.forwardToPreviousPage(req); } public String getCountIntervalForBuilds(){ long nextExecution = getBuildsDiskUsageThread().scheduledLastInstanceExecutionTime() - System.currentTimeMillis(); if(nextExecution<=0) //not scheduled nextExecution = getBuildsDiskUsageThread().getRecurrencePeriod(); return DiskUsageUtil.formatTimeInMilisec(nextExecution); } public String getCountIntervalForJobs(){ long nextExecution = getJobsDiskUsageThread().scheduledLastInstanceExecutionTime() - System.currentTimeMillis(); if(nextExecution<=0) //not scheduled nextExecution = getJobsDiskUsageThread().getRecurrencePeriod(); return DiskUsageUtil.formatTimeInMilisec(nextExecution); } public String getCountIntervalForWorkspaces(){ long nextExecution = getWorkspaceDiskUsageThread().scheduledLastInstanceExecutionTime() - System.currentTimeMillis(); if(nextExecution<=0) //not scheduled nextExecution = getWorkspaceDiskUsageThread().getRecurrencePeriod(); return DiskUsageUtil.formatTimeInMilisec(nextExecution); } public boolean hasAdministrativePermission(){ return Jenkins.getInstance().hasPermission(Jenkins.ADMINISTER); } public String getCountIntervalForNotUsedData(){ long nextExecution = getNotUsedDataDiskUsageThread().scheduledLastInstanceExecutionTime() - System.currentTimeMillis(); if(nextExecution<=0) //not scheduled nextExecution = getNotUsedDataDiskUsageThread().getRecurrencePeriod(); return DiskUsageUtil.formatTimeInMilisec(nextExecution); } public String getTotalSizeOfNotLoadedBuilds(){ Long size = 0L; for(Item item : Jenkins.getInstance().getItems()){ if(item instanceof AbstractProject){ AbstractProject project = (AbstractProject) item; ProjectDiskUsageAction action = project.getAction(ProjectDiskUsageAction.class); size += action.getAllDiskUsageNotLoadedBuilds(true); } } return DiskUsageUtil.getSizeString(size); } public Map<AbstractProject,Long> getNotLoadedBuilds(){ Map<AbstractProject,Long> notLoadedBuilds = new HashMap<AbstractProject,Long>(); for(Item item : Jenkins.getInstance().getItems()){ if(item instanceof AbstractProject){ AbstractProject project = (AbstractProject) item; ProjectDiskUsage usage = ((DiskUsageProperty)project.getProperty(DiskUsageProperty.class)).getDiskUsage(); ProjectDiskUsageAction action = project.getAction(ProjectDiskUsageAction.class); if(!usage.getNotLoadedBuilds().isEmpty()){ notLoadedBuilds.put(project, action.getAllDiskUsageNotLoadedBuilds(true)); } } } return notLoadedBuilds; } public void doUnused(StaplerRequest req, StaplerResponse res) throws IOException, ServletException{ Map<AbstractProject,Map<String,Long>> notLoadedBuilds = new HashMap<AbstractProject,Map<String,Long>>(); Map<String,Long> notLoadedJobs = new HashMap<String,Long>(); req.getView(this, "unused.jelly").forward(req, res); } }