1 package hudson.model; 2 3 import com.thoughtworks.xstream.XStream; 4 import groovy.lang.GroovyShell; 5 import hudson.FeedAdapter; 6 import hudson.Launcher; 7 import hudson.Launcher.LocalLauncher; 8 import hudson.Plugin; 9 import hudson.PluginManager; 10 import hudson.PluginWrapper; 11 import hudson.Util; 12 import hudson.XmlFile; 13 import hudson.FilePath; 14 import hudson.TcpSlaveAgentListener; 15 import static hudson.Util.fixEmpty; 16 import hudson.model.Descriptor.FormException; 17 import hudson.model.listeners.ItemListener; 18 import hudson.model.listeners.JobListener; 19 import hudson.model.listeners.JobListener.JobListenerAdapter; 20 import hudson.model.listeners.SCMListener; 21 import hudson.remoting.LocalChannel; 22 import hudson.remoting.VirtualChannel; 23 import hudson.scm.CVSSCM; 24 import hudson.scm.SCM; 25 import hudson.scm.SCMS; 26 import hudson.tasks.BuildStep; 27 import hudson.tasks.BuildWrapper; 28 import hudson.tasks.BuildWrappers; 29 import hudson.tasks.Builder; 30 import hudson.tasks.Mailer; 31 import hudson.tasks.Publisher; 32 import hudson.triggers.Trigger; 33 import hudson.triggers.Triggers; 34 import hudson.triggers.TriggerDescriptor; 35 import hudson.util.CopyOnWriteList; 36 import hudson.util.CopyOnWriteMap; 37 import hudson.util.FormFieldValidator; 38 import hudson.util.XStream2; 39 import org.apache.commons.fileupload.FileItem; 40 import org.apache.commons.fileupload.FileUploadException; 41 import org.apache.commons.fileupload.disk.DiskFileItemFactory; 42 import org.apache.commons.fileupload.servlet.ServletFileUpload; 43 import org.kohsuke.stapler.StaplerRequest; 44 import org.kohsuke.stapler.StaplerResponse; 45 46 import javax.servlet.ServletContext ; 47 import javax.servlet.ServletException ; 48 import javax.servlet.http.Cookie ; 49 import javax.servlet.http.HttpServletRequest ; 50 import javax.servlet.http.HttpServletResponse ; 51 import javax.servlet.http.HttpSession ; 52 import java.io.File ; 53 import java.io.FileFilter ; 54 import java.io.FileInputStream ; 55 import java.io.IOException ; 56 import java.io.PrintWriter ; 57 import java.io.StringWriter ; 58 import java.text.ParseException ; 59 import java.util.ArrayList ; 60 import java.util.Arrays ; 61 import java.util.Calendar ; 62 import java.util.Collection ; 63 import java.util.Collections ; 64 import java.util.Comparator ; 65 import java.util.GregorianCalendar ; 66 import java.util.HashMap ; 67 import java.util.HashSet ; 68 import java.util.Iterator ; 69 import java.util.List ; 70 import java.util.Map ; 71 import java.util.Map.Entry; 72 import java.util.Set ; 73 import java.util.TreeSet ; 74 import java.util.Vector ; 75 import java.util.StringTokenizer ; 76 import java.util.Stack ; 77 import java.util.logging.Level ; 78 import java.util.logging.LogRecord ; 79 80 85 public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node { 86 private transient final Queue queue = new Queue(); 87 88 91 private transient final Map<Node,Computer> computers = new CopyOnWriteMap.Hash<Node,Computer>(); 92 93 96 private int numExecutors = 2; 97 98 101 private boolean useSecurity = false; 102 103 106 private String systemMessage; 107 108 111 public transient final File root; 112 113 116 transient final Map<String ,TopLevelItem> items = new CopyOnWriteMap.Tree<String ,TopLevelItem>(); 117 118 121 private static Hudson theInstance; 122 123 private transient boolean isQuietingDown; 124 private transient boolean terminating; 125 126 private List<JDK> jdks = new ArrayList <JDK>(); 127 128 private transient volatile DependencyGraph dependencyGraph = DependencyGraph.EMPTY; 129 130 138 private volatile List<Slave> slaves; 139 140 145 Integer quietPeriod; 146 147 150 private List<ListView> views; 152 private transient final FingerprintMap fingerprintMap = new FingerprintMap(); 153 154 157 public transient final PluginManager pluginManager; 158 159 public transient final TcpSlaveAgentListener tcpSlaveAgentListener; 160 161 164 private transient final CopyOnWriteList<ItemListener> viewItemListeners = new CopyOnWriteList<ItemListener>(); 165 166 169 private transient final CopyOnWriteList<SCMListener> scmListeners = new CopyOnWriteList<SCMListener>(); 170 171 public static Hudson getInstance() { 172 return theInstance; 173 } 174 175 176 public Hudson(File root, ServletContext context) throws IOException { 177 this.root = root; 178 if(theInstance!=null) 179 throw new IllegalStateException ("second instance"); 180 theInstance = this; 181 182 pluginManager = new PluginManager(context); 184 185 tcpSlaveAgentListener = new TcpSlaveAgentListener(); 186 187 Items.LIST.hashCode(); 190 191 load(); 192 if(slaves==null) slaves = new ArrayList <Slave>(); 193 updateComputerList(); 194 195 getQueue().load(); 196 197 for (ItemListener l : viewItemListeners) 198 l.onLoaded(); 199 } 200 201 public TcpSlaveAgentListener getTcpSlaveAgentListener() { 202 return tcpSlaveAgentListener; 203 } 204 205 210 @Deprecated 211 public String getNodeName() { 212 return ""; 213 } 214 215 public String getNodeDescription() { 216 return "the master Hudson node"; 217 } 218 219 public String getDescription() { 220 return systemMessage; 221 } 222 223 public PluginManager getPluginManager() { 224 return pluginManager; 225 } 226 227 230 public Descriptor<SCM> getScm(String shortClassName) { 231 return findDescriptor(shortClassName,SCMS.SCMS); 232 } 233 234 237 public Descriptor<Builder> getBuilder(String shortClassName) { 238 return findDescriptor(shortClassName, BuildStep.BUILDERS); 239 } 240 241 244 public Descriptor<Publisher> getPublisher(String shortClassName) { 245 return findDescriptor(shortClassName, BuildStep.PUBLISHERS); 246 } 247 248 251 public TriggerDescriptor getTrigger(String shortClassName) { 252 return (TriggerDescriptor)findDescriptor(shortClassName, Triggers.TRIGGERS); 253 } 254 255 258 private <T extends Describable<T>> 259 Descriptor<T> findDescriptor(String shortClassName, Collection <? extends Descriptor<T>> descriptors) { 260 String name = '.'+shortClassName; 261 for (Descriptor<T> d : descriptors) { 262 if(d.clazz.getName().endsWith(name)) 263 return d; 264 } 265 return null; 266 } 267 268 274 public void addListener(JobListener l) { 275 viewItemListeners.add(new JobListenerAdapter(l)); 276 } 277 278 284 public boolean removeListener(JobListener l ) { 285 return viewItemListeners.remove(new JobListenerAdapter(l)); 286 } 287 288 291 public CopyOnWriteList<ItemListener> getJobListeners() { 292 return viewItemListeners; 293 } 294 295 298 public CopyOnWriteList<SCMListener> getSCMListeners() { 299 return scmListeners; 300 } 301 302 309 public Plugin getPlugin(String shortName) { 310 PluginWrapper p = pluginManager.getPlugin(shortName); 311 if(p==null) return null; 312 return p.getPlugin(); 313 } 314 315 318 public String getSystemMessage() { 319 return systemMessage; 320 } 321 322 public Launcher createLauncher(TaskListener listener) { 323 return new LocalLauncher(listener); 324 } 325 326 333 private void updateComputerList() throws IOException { 334 synchronized(computers) { Map<String ,Computer> byName = new HashMap <String ,Computer>(); 336 for (Computer c : computers.values()) { 337 if(c.getNode()==null) 338 continue; byName.put(c.getNode().getNodeName(),c); 340 } 341 342 Set <Computer> old = new HashSet <Computer>(computers.values()); 343 Set <Computer> used = new HashSet <Computer>(); 344 345 updateComputer(this, byName, used); 346 for (Slave s : getSlaves()) 347 updateComputer(s, byName, used); 348 349 old.removeAll(used); 353 for (Computer c : old) { 354 c.kill(); 355 } 356 } 357 getQueue().scheduleMaintenance(); 358 } 359 360 private void updateComputer(Node n, Map<String ,Computer> byNameMap, Set <Computer> used) { 361 Computer c; 362 c = byNameMap.get(n.getNodeName()); 363 if (c!=null) { 364 c.setNode(n); } else { 366 if(n.getNumExecutors()>0) 367 computers.put(n,c=n.createComputer()); 368 } 369 used.add(c); 370 } 371 372 void removeComputer(Computer computer) { 373 Iterator <Entry<Node,Computer>> itr=computers.entrySet().iterator(); 374 while(itr.hasNext()) { 375 Entry<Node, Computer> e = itr.next(); 376 if(e.getValue()==computer) { 377 computers.remove(e.getKey()); 378 return; 379 } 380 } 381 throw new IllegalStateException ("Trying to remove unknown computer"); 382 } 383 384 public String getFullName() { 385 return ""; 386 } 387 388 393 public List<TopLevelItem> getItems() { 394 return new ArrayList <TopLevelItem>(items.values()); 395 } 396 397 401 public <T extends Item> List<T> getAllItems(Class <T> type) { 402 List<T> r = new ArrayList <T>(); 403 404 Stack <ItemGroup> q = new Stack <ItemGroup>(); 405 q.push(this); 406 407 while(!q.isEmpty()) { 408 ItemGroup<?> parent = q.pop(); 409 for (Item i : parent.getItems()) { 410 if(type.isInstance(i)) 411 r.add(type.cast(i)); 412 if(i instanceof ItemGroup) 413 q.push((ItemGroup)i); 414 } 415 } 416 417 return r; 418 } 419 420 427 public List<Project> getProjects() { 428 return Util.createSubList(items.values(),Project.class); 429 } 430 431 434 public Collection <String > getJobNames() { 435 List<String > names = new ArrayList <String >(); 436 for (Job j : getAllItems(Job.class)) 437 names.add(j.getName()); 438 return names; 439 } 440 441 444 public Collection <String > getTopLevelItemNames() { 445 List<String > names = new ArrayList <String >(); 446 for (TopLevelItem j : items.values()) 447 names.add(j.getName()); 448 return names; 449 } 450 451 457 @Deprecated 458 public boolean contains(TopLevelItem view) { 459 return true; 460 } 461 462 public synchronized View getView(String name) { 463 if(views!=null) { 464 for (ListView v : views) { 465 if(v.getViewName().equals(name)) 466 return v; 467 } 468 } 469 if(this.getViewName().equals(name)) 470 return this; 471 else 472 return null; 473 } 474 475 478 public synchronized View[] getViews() { 479 if(views==null) 480 views = new ArrayList <ListView>(); 481 View[] r = new View[views.size()+1]; 482 views.toArray(r); 483 r[r.length-1] = r[0]; 485 Arrays.sort(r,1,r.length, View.SORTER); 486 r[0] = this; 487 return r; 488 } 489 490 public synchronized void deleteView(ListView view) throws IOException { 491 if(views!=null) { 492 views.remove(view); 493 save(); 494 } 495 } 496 497 public String getViewName() { 498 return "All"; 499 } 500 501 504 public Computer[] getComputers() { 505 Computer[] r = computers.values().toArray(new Computer[computers.size()]); 506 Arrays.sort(r,new Comparator <Computer>() { 507 public int compare(Computer lhs, Computer rhs) { 508 if(lhs.getNode()==Hudson.this) return -1; 509 if(rhs.getNode()==Hudson.this) return 1; 510 return lhs.getDisplayName().compareTo(rhs.getDisplayName()); 511 } 512 }); 513 return r; 514 } 515 516 public Computer getComputer(String name) { 517 for (Computer c : computers.values()) { 518 if(c.getNode().getNodeName().equals(name)) 519 return c; 520 } 521 return null; 522 } 523 524 public Queue getQueue() { 525 return queue; 526 } 527 528 public String getDisplayName() { 529 return "Hudson"; 530 } 531 532 public List<JDK> getJDKs() { 533 if(jdks==null) 534 jdks = new ArrayList <JDK>(); 535 return jdks; 536 } 537 538 541 public JDK getJDK(String name) { 542 for (JDK j : getJDKs()) { 543 if(j.getName().equals(name)) 544 return j; 545 } 546 return null; 547 } 548 549 552 public Slave getSlave(String name) { 553 for (Slave s : getSlaves()) { 554 if(s.getNodeName().equals(name)) 555 return s; 556 } 557 return null; 558 } 559 560 public List<Slave> getSlaves() { 561 return Collections.unmodifiableList(slaves); 562 } 563 564 567 public int getQuietPeriod() { 568 return quietPeriod!=null ? quietPeriod : 5; 569 } 570 571 576 public String getUrl() { 577 return ""; 578 } 579 580 public String getUrlChildPrefix() { 581 return "job"; 582 } 583 584 604 public String getRootUrl() { 605 return Mailer.DESCRIPTOR.getUrl(); 607 } 608 609 public File getRootDir() { 610 return root; 611 } 612 613 public FilePath getWorkspaceFor(TopLevelItem item) { 614 return new FilePath(new File(item.getRootDir(),"workspace")); 615 } 616 617 public boolean isUseSecurity() { 618 return useSecurity; 619 } 620 621 public void setUseSecurity(boolean useSecurity) { 622 this.useSecurity = useSecurity; 623 } 624 625 632 public boolean isQuietingDown() { 633 return isQuietingDown; 634 } 635 636 639 public boolean isTerminating() { 640 return terminating; 641 } 642 643 648 public TopLevelItem getJob(String name) { 649 return getItem(name); 650 } 651 652 655 public TopLevelItem getItem(String name) { 656 return items.get(name); 657 } 658 659 public File getRootDirFor(TopLevelItem child) { 660 return new File(new File(getRootDir(),"jobs"),child.getName()); 661 } 662 663 672 public <T extends Item> T getItemByFullName(String fullName, Class <T> type) { 673 StringTokenizer tokens = new StringTokenizer (fullName,"/"); 674 ItemGroup parent = this; 675 676 while(true) { 677 Item item = parent.getItem(tokens.nextToken()); 678 if(!tokens.hasMoreTokens()) { 679 if(type.isInstance(item)) 680 return type.cast(item); 681 else 682 return null; 683 } 684 685 if(!(item instanceof ItemGroup)) 686 return null; 688 parent = (ItemGroup) item; 689 } 690 } 691 692 public Item getItemByFullName(String fullName) { 693 return getItemByFullName(fullName,Item.class); 694 } 695 696 702 public User getUser(String name) { 703 return User.get(name); 704 } 705 706 712 public synchronized TopLevelItem createProject( TopLevelItemDescriptor type, String name ) throws IOException { 713 if(items.containsKey(name)) 714 throw new IllegalArgumentException (); 715 716 TopLevelItem item; 717 try { 718 item = type.newInstance(name); 719 } catch (Exception e) { 720 throw new IllegalArgumentException (e); 721 } 722 723 item.save(); 724 items.put(name,item); 725 return item; 726 } 727 728 731 void deleteJob(TopLevelItem item) throws IOException { 732 for (ItemListener l : viewItemListeners) 733 l.onDeleted(item); 734 735 items.remove(item.getName()); 736 if(views!=null) { 737 for (ListView v : views) { 738 synchronized(v) { 739 v.jobNames.remove(item.getName()); 740 } 741 } 742 save(); 743 } 744 } 745 746 750 void onRenamed(TopLevelItem job, String oldName, String newName) throws IOException { 751 items.remove(oldName); 752 items.put(newName,job); 753 754 if(views!=null) { 755 for (ListView v : views) { 756 synchronized(v) { 757 if(v.jobNames.remove(oldName)) 758 v.jobNames.add(newName); 759 } 760 } 761 save(); 762 } 763 } 764 765 public FingerprintMap getFingerprintMap() { 766 return fingerprintMap; 767 } 768 769 public Object getFingerprint( String md5sum ) throws IOException { 771 Fingerprint r = fingerprintMap.get(md5sum); 772 if(r==null) return new NoFingerprintMatch(md5sum); 773 else return r; 774 } 775 776 780 public Fingerprint _getFingerprint( String md5sum ) throws IOException { 781 return fingerprintMap.get(md5sum); 782 } 783 784 787 private XmlFile getConfigFile() { 788 return new XmlFile(XSTREAM, new File(root,"config.xml")); 789 } 790 791 public int getNumExecutors() { 792 return numExecutors; 793 } 794 795 public Mode getMode() { 796 return Mode.NORMAL; 797 } 798 799 public Computer createComputer() { 800 return new MasterComputer(); 801 } 802 803 private synchronized void load() throws IOException { 804 XmlFile cfg = getConfigFile(); 805 if(cfg.exists()) 806 cfg.unmarshal(this); 807 808 File projectsDir = new File(root,"jobs"); 809 if(!projectsDir.isDirectory() && !projectsDir.mkdirs()) { 810 if(projectsDir.exists()) 811 throw new IOException (projectsDir+" is not a directory"); 812 throw new IOException ("Unable to create "+projectsDir+"\nPermission issue? Please create this directory manually."); 813 } 814 File[] subdirs = projectsDir.listFiles(new FileFilter () { 815 public boolean accept(File child) { 816 return child.isDirectory(); 817 } 818 }); 819 items.clear(); 820 for (File subdir : subdirs) { 821 try { 822 TopLevelItem item = (TopLevelItem)Items.load(this,subdir); 823 items.put(item.getName(), item); 824 } catch (IOException e) { 825 e.printStackTrace(); } 827 } 828 rebuildDependencyGraph(); 829 } 830 831 834 public synchronized void save() throws IOException { 835 getConfigFile().write(this); 836 } 837 838 839 842 public void cleanUp() { 843 terminating = true; 844 for( Computer c : computers.values() ) { 845 c.interrupt(); 846 c.kill(); 847 } 848 ExternalJob.reloadThread.interrupt(); 849 Trigger.timer.cancel(); 850 tcpSlaveAgentListener.shutdown(); 851 852 if(pluginManager!=null) pluginManager.stop(); 854 855 getQueue().save(); 856 } 857 858 859 860 868 public synchronized void doConfigSubmit( StaplerRequest req, StaplerResponse rsp ) throws IOException , ServletException { 869 try { 870 if(!Hudson.adminCheck(req,rsp)) 871 return; 872 873 req.setCharacterEncoding("UTF-8"); 874 875 useSecurity = req.getParameter("use_security")!=null; 876 877 numExecutors = Integer.parseInt(req.getParameter("numExecutors")); 878 quietPeriod = Integer.parseInt(req.getParameter("quiet_period")); 879 880 systemMessage = Util.nullify(req.getParameter("system_message")); 881 882 { List<Slave> newSlaves = new ArrayList <Slave>(); 884 String [] names = req.getParameterValues("slave.name"); 885 if(names!=null) { 886 for(int i=0;i< names.length;i++) { 887 newSlaves.add(req.bindParameters(Slave.class,"slave.",i)); 888 } 889 } 890 this.slaves = newSlaves; 891 updateComputerList(); 892 } 893 894 { jdks.clear(); 896 String [] names = req.getParameterValues("jdk_name"); 897 String [] homes = req.getParameterValues("jdk_home"); 898 if(names!=null && homes!=null) { 899 int len = Math.min(names.length,homes.length); 900 for(int i=0;i<len;i++) { 901 jdks.add(new JDK(names[i],homes[i])); 902 } 903 } 904 } 905 906 boolean result = true; 907 908 for( Descriptor<Builder> d : BuildStep.BUILDERS ) 909 result &= d.configure(req); 910 911 for( Descriptor<Publisher> d : BuildStep.PUBLISHERS ) 912 result &= d.configure(req); 913 914 for( Descriptor<BuildWrapper> d : BuildWrappers.WRAPPERS ) 915 result &= d.configure(req); 916 917 for( Descriptor<SCM> scmd : SCMS.SCMS ) 918 result &= scmd.configure(req); 919 920 for( TriggerDescriptor d : Triggers.TRIGGERS ) 921 result &= d.configure(req); 922 923 for( JobPropertyDescriptor d : Jobs.PROPERTIES ) 924 result &= d.configure(req); 925 926 save(); 927 if(result) 928 rsp.sendRedirect("."); else 930 rsp.sendRedirect("configure"); } catch (FormException e) { 932 sendError(e,req,rsp); 933 } 934 } 935 936 939 public synchronized void doSubmitDescription( StaplerRequest req, StaplerResponse rsp ) throws IOException , ServletException { 940 if(!Hudson.adminCheck(req,rsp)) 941 return; 942 943 req.setCharacterEncoding("UTF-8"); 944 systemMessage = req.getParameter("description"); 945 save(); 946 rsp.sendRedirect("."); 947 } 948 949 public synchronized void doQuietDown( StaplerRequest req, StaplerResponse rsp ) throws IOException , ServletException { 950 if(!Hudson.adminCheck(req,rsp)) 951 return; 952 isQuietingDown = true; 953 rsp.sendRedirect2("."); 954 } 955 956 public synchronized void doCancelQuietDown( StaplerRequest req, StaplerResponse rsp ) throws IOException , ServletException { 957 if(!Hudson.adminCheck(req,rsp)) 958 return; 959 isQuietingDown = false; 960 getQueue().scheduleMaintenance(); 961 rsp.sendRedirect2("."); 962 } 963 964 public synchronized Item doCreateItem( StaplerRequest req, StaplerResponse rsp ) throws IOException , ServletException { 965 if(!Hudson.adminCheck(req,rsp)) 966 return null; 967 968 req.setCharacterEncoding("UTF-8"); 969 String name = req.getParameter("name").trim(); 970 String mode = req.getParameter("mode"); 971 972 try { 973 checkGoodName(name); 974 } catch (ParseException e) { 975 sendError(e,req,rsp); 976 return null; 977 } 978 979 if(getItem(name)!=null) { 980 sendError("A job already exists with the name '"+name+"'",req,rsp); 981 return null; 982 } 983 984 if(mode==null) { 985 rsp.sendError(HttpServletResponse.SC_BAD_REQUEST); 986 return null; 987 } 988 989 TopLevelItem result; 990 991 if(mode.equals("copyJob")) { 992 TopLevelItem src = getItem(req.getParameter("from")); 993 if(src==null) { 994 rsp.sendError(HttpServletResponse.SC_BAD_REQUEST); 995 return null; 996 } 997 998 result = createProject(src.getDescriptor(),name); 999 1000 Util.copyFile(Items.getConfigFile(src).getFile(),Items.getConfigFile(result).getFile()); 1002 1003 result = (TopLevelItem)Items.load(this,result.getRootDir()); 1005 result.onCopiedFrom(src); 1006 items.put(name,result); 1007 } else { 1008 result = createProject(Items.getDescriptor(mode), name); 1010 } 1011 1012 for (ItemListener l : viewItemListeners) 1013 l.onCreated(result); 1014 1015 rsp.sendRedirect2(req.getContextPath()+'/'+result.getUrl()+"configure"); 1016 return result; 1017 } 1018 1019 public synchronized void doCreateView( StaplerRequest req, StaplerResponse rsp ) throws IOException , ServletException { 1020 if(!Hudson.adminCheck(req,rsp)) 1021 return; 1022 1023 req.setCharacterEncoding("UTF-8"); 1024 1025 String name = req.getParameter("name"); 1026 1027 try { 1028 checkGoodName(name); 1029 } catch (ParseException e) { 1030 sendError(e, req, rsp); 1031 return; 1032 } 1033 1034 ListView v = new ListView(this, name); 1035 if(views==null) 1036 views = new Vector <ListView>(); 1037 views.add(v); 1038 save(); 1039 1040 rsp.sendRedirect2("./"+v.getUrl()+"configure"); 1042 } 1043 1044 1051 public static void checkGoodName(String name) throws ParseException { 1052 if(name==null || name.length()==0) 1053 throw new ParseException ("No name is specified",0); 1054 1055 for( int i=0; i<name.length(); i++ ) { 1056 char ch = name.charAt(i); 1057 if(Character.isISOControl(ch)) 1058 throw new ParseException ("No control code is allowed",i); 1059 if("?*()/\\%!@#$^&|<>".indexOf(ch)!=-1) 1060 throw new ParseException ("'"+ch+"' is an unsafe character",i); 1061 } 1062 1063 } 1065 1066 1069 public void doLoginEntry( StaplerRequest req, StaplerResponse rsp ) throws IOException { 1070 if(req.getUserPrincipal()==null) 1071 rsp.sendRedirect2("noPrincipal"); 1072 else 1073 rsp.sendRedirect2("."); 1074 } 1075 1076 1079 public void doLogout( StaplerRequest req, StaplerResponse rsp ) throws IOException { 1080 HttpSession session = req.getSession(false); 1081 if(session!=null) 1082 session.invalidate(); 1083 rsp.sendRedirect2(req.getContextPath()+"/"); 1084 } 1085 1086 1089 public void doLogRss( StaplerRequest req, StaplerResponse rsp ) throws IOException , ServletException { 1090 List<LogRecord > logs = logRecords; 1091 1092 String level = req.getParameter("level"); 1094 if(level!=null) { 1095 Level threshold = Level.parse(level); 1096 List<LogRecord > filtered = new ArrayList <LogRecord >(); 1097 for (LogRecord r : logs) { 1098 if(r.getLevel().intValue() >= threshold.intValue()) 1099 filtered.add(r); 1100 } 1101 logs = filtered; 1102 } 1103 1104 RSS.forwardToRss("Hudson log","", logs, new FeedAdapter<LogRecord >() { 1105 public String getEntryTitle(LogRecord entry) { 1106 return entry.getMessage(); 1107 } 1108 1109 public String getEntryUrl(LogRecord entry) { 1110 return "log"; } 1112 1113 public String getEntryID(LogRecord entry) { 1114 return String.valueOf(entry.getSequenceNumber()); 1115 } 1116 1117 public Calendar getEntryTimestamp(LogRecord entry) { 1118 GregorianCalendar cal = new GregorianCalendar (); 1119 cal.setTimeInMillis(entry.getMillis()); 1120 return cal; 1121 } 1122 },req,rsp); 1123 } 1124 1125 1128 public synchronized void doReload( StaplerRequest req, StaplerResponse rsp ) throws IOException { 1129 if(!Hudson.adminCheck(req,rsp)) 1130 return; 1131 1132 load(); 1133 rsp.sendRedirect2(req.getContextPath()+"/"); 1134 } 1135 1136 1139 public void doUploadPlugin( StaplerRequest req, StaplerResponse rsp ) throws IOException , ServletException { 1140 try { 1141 if(!Hudson.adminCheck(req,rsp)) 1142 return; 1143 1144 ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory()); 1145 1146 FileItem fileItem = (FileItem) upload.parseRequest(req).get(0); 1148 String fileName = Util.getFileName(fileItem.getName()); 1149 if(!fileName.endsWith(".hpi")) { 1150 sendError(fileName+" is not a Hudson plugin",req,rsp); 1151 return; 1152 } 1153 fileItem.write(new File(getPluginManager().rootDir, fileName)); 1154 1155 fileItem.delete(); 1156 1157 rsp.sendRedirect2("managePlugins"); 1158 } catch (IOException e) { 1159 throw e; 1160 } catch (Exception e) { throw new ServletException (e); 1162 } 1163 } 1164 1165 1168 public void doDoFingerprintCheck( StaplerRequest req, StaplerResponse rsp ) throws IOException , ServletException { 1169 try { 1170 ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory()); 1171 1172 @SuppressWarnings ("unchecked") List<FileItem> items = upload.parseRequest(req); 1175 1176 rsp.sendRedirect2(req.getContextPath()+"/fingerprint/"+ 1177 Util.getDigestOf(items.get(0).getInputStream())+'/'); 1178 1179 for (FileItem item : items) 1182 item.delete(); 1183 } catch (FileUploadException e) { 1184 throw new ServletException (e); } 1186 } 1187 1188 1195 public void doNocacheImages( StaplerRequest req, StaplerResponse rsp ) throws IOException { 1196 String path = req.getRestOfPath(); 1197 1198 if(path.length()==0) 1199 path = "/"; 1200 1201 if(path.indexOf("..")!=-1 || path.length()<1) { 1202 rsp.sendError(HttpServletResponse.SC_BAD_REQUEST); 1204 return; 1205 } 1206 1207 File f = new File(req.getServletContext().getRealPath("/images"),path.substring(1)); 1208 if(!f.exists()) { 1209 rsp.sendError(HttpServletResponse.SC_NOT_FOUND); 1210 return; 1211 } 1212 1213 if(f.isDirectory()) { 1214 rsp.sendError(HttpServletResponse.SC_FORBIDDEN); 1216 return; 1217 } 1218 1219 FileInputStream in = new FileInputStream (f); 1220 String contentType = req.getServletContext().getMimeType(f.getPath()); 1222 rsp.setContentType(contentType); 1223 rsp.setContentLength((int)f.length()); 1224 byte[] buf = new byte[1024]; 1225 int len; 1226 while((len=in.read(buf))>0) 1227 rsp.getOutputStream().write(buf,0,len); 1228 in.close(); 1229 } 1230 1231 1234 public void doGc( StaplerRequest req, StaplerResponse rsp ) throws IOException { 1235 System.gc(); 1236 rsp.setStatus(HttpServletResponse.SC_OK); 1237 rsp.setContentType("text/plain"); 1238 rsp.getWriter().println("GCed"); 1239 } 1240 1241 1245 public void doScript( StaplerRequest req, StaplerResponse rsp ) throws IOException , ServletException { 1246 if(!adminCheck(req,rsp)) 1247 return; 1249 String text = req.getParameter("script"); 1250 if(text!=null) { 1251 GroovyShell shell = new GroovyShell(); 1252 1253 StringWriter out = new StringWriter (); 1254 PrintWriter pw = new PrintWriter (out); 1255 shell.setVariable("out", pw); 1256 try { 1257 Object output = shell.evaluate(text); 1258 if(output!=null) 1259 pw.println("Result: "+output); 1260 } catch (Throwable t) { 1261 t.printStackTrace(pw); 1262 } 1263 req.setAttribute("output",out); 1264 } 1265 1266 req.getView(this,"_script.jelly").forward(req,rsp); 1267 } 1268 1269 1272 public void doIconSize( StaplerRequest req, StaplerResponse rsp ) throws IOException { 1273 rsp.addCookie(new Cookie ("iconSize",req.getQueryString())); 1274 String ref = req.getHeader("Referer"); 1275 if(ref==null) ref="."; 1276 rsp.sendRedirect2(ref); 1277 } 1278 1279 public void doFingerprintCleanup( StaplerRequest req, StaplerResponse rsp ) throws IOException { 1280 FingerprintCleanupThread.invoke(); 1281 rsp.setStatus(HttpServletResponse.SC_OK); 1282 rsp.setContentType("text/plain"); 1283 rsp.getWriter().println("Invoked"); 1284 } 1285 1286 public void doWorkspaceCleanup( StaplerRequest req, StaplerResponse rsp ) throws IOException { 1287 WorkspaceCleanupThread.invoke(); 1288 rsp.setStatus(HttpServletResponse.SC_OK); 1289 rsp.setContentType("text/plain"); 1290 rsp.getWriter().println("Invoked"); 1291 } 1292 1293 1296 public void doCheckLocalFSRoot( StaplerRequest req, StaplerResponse rsp ) throws IOException , ServletException { 1297 new FormFieldValidator(req,rsp,true) { 1299 public void check() throws IOException , ServletException { 1300 File f = getFileParameter("value"); 1301 if(f.isDirectory()) { ok(); 1303 } else { if(f.exists()) { 1305 error(f+" is not a directory"); 1306 } else { 1307 error("No such directory: "+f); 1308 } 1309 } 1310 } 1311 }.process(); 1312 } 1313 1314 1317 public void doJavaHomeCheck( StaplerRequest req, StaplerResponse rsp ) throws IOException , ServletException { 1318 new FormFieldValidator(req,rsp,true) { 1320 public void check() throws IOException , ServletException { 1321 File f = getFileParameter("value"); 1322 if(!f.isDirectory()) { 1323 error(f+" is not a directory"); 1324 return; 1325 } 1326 1327 File toolsJar = new File(f,"lib/tools.jar"); 1328 if(!toolsJar.exists()) { 1329 error(f+" doesn't look like a JDK directory"); 1330 return; 1331 } 1332 1333 ok(); 1334 } 1335 }.process(); 1336 } 1337 1338 1341 public void doItemExistsCheck(StaplerRequest req, StaplerResponse rsp) throws IOException , ServletException { 1342 new FormFieldValidator(req,rsp,true) { 1345 protected void check() throws IOException , ServletException { 1346 String job = fixEmpty(request.getParameter("value")); 1347 if(job==null) { 1348 ok(); return; 1350 } 1351 1352 if(getItem(job)==null) 1353 ok(); 1354 else 1355 error("Job named "+job+" already exists"); 1356 } 1357 }.process(); 1358 } 1359 1360 1361 public static boolean isWindows() { 1362 return File.pathSeparatorChar==';'; 1363 } 1364 1365 1366 1374 public Set <String > getAllCvsRoots() { 1375 Set <String > r = new TreeSet <String >(); 1376 for( AbstractProject p : getAllItems(AbstractProject.class) ) { 1377 SCM scm = p.getScm(); 1378 if (scm instanceof CVSSCM) { 1379 CVSSCM cvsscm = (CVSSCM) scm; 1380 r.add(cvsscm.getCvsRoot()); 1381 } 1382 } 1383 1384 return r; 1385 } 1386 1387 1390 public void rebuildDependencyGraph() { 1391 dependencyGraph = new DependencyGraph(); 1392 } 1393 1394 public DependencyGraph getDependencyGraph() { 1395 return dependencyGraph; 1396 } 1397 1398 public static final class MasterComputer extends Computer { 1399 private MasterComputer() { 1400 super(Hudson.getInstance()); 1401 } 1402 1403 @Override 1404 public VirtualChannel getChannel() { 1405 return localChannel; 1406 } 1407 1408 public void doLaunchSlaveAgent(StaplerRequest req, StaplerResponse rsp) throws IOException , ServletException { 1409 rsp.sendError(HttpServletResponse.SC_NOT_FOUND); 1412 } 1413 1414 1417 public static final LocalChannel localChannel = new LocalChannel(threadPoolForRemoting); 1418 } 1419 1420 public static boolean adminCheck(StaplerRequest req,StaplerResponse rsp) throws IOException { 1421 if(!getInstance().isUseSecurity()) 1422 return true; 1423 1424 if(req.isUserInRole("admin")) 1425 return true; 1426 1427 rsp.sendError(StaplerResponse.SC_FORBIDDEN); 1428 return false; 1429 } 1430 1431 1434 public static List<LogRecord > logRecords = Collections.emptyList(); 1436 1439 private static final XStream XSTREAM = new XStream2(); 1440 1441 static { 1442 XSTREAM.alias("hudson",Hudson.class); 1443 XSTREAM.alias("slave",Slave.class); 1444 XSTREAM.alias("jdk",JDK.class); 1445 XSTREAM.alias("view", ListView.class); 1447 XSTREAM.alias("listView", ListView.class); 1448 } 1449} 1450 | Popular Tags |