├── .settings ├── org.eclipse.wst.jsdt.ui.superType.name ├── org.eclipse.wst.jsdt.ui.superType.container ├── org.eclipse.wst.common.project.facet.core.xml ├── org.eclipse.jdt.core.prefs ├── .jsdtscope └── org.eclipse.wst.common.component ├── web ├── META-INF │ └── MANIFEST.MF ├── favicon.ico ├── img │ └── guy.jpg ├── select2 │ ├── select2.png │ ├── select2x2.png │ ├── select2-spinner.gif │ └── select2.css ├── WEB-INF │ ├── lib │ │ ├── c3p0-0.9.1.2.jar │ │ ├── httpcore-4.3.2.jar │ │ ├── httpmime-4.3.5.jar │ │ ├── log4j-1.2.16.jar │ │ ├── fastjson-1.1.43.jar │ │ ├── fluent-hc-4.3.5.jar │ │ ├── httpclient-4.3.5.jar │ │ ├── slf4j-api-1.6.1.jar │ │ ├── commons-codec-1.6.jar │ │ ├── commons-lang3-3.3.2.jar │ │ ├── commons-pool-1.5.6.jar │ │ ├── freemarker-2.3.20.jar │ │ ├── slf4j-log4j12-1.6.1.jar │ │ ├── commons-logging-1.1.3.jar │ │ ├── httpclient-cache-4.3.5.jar │ │ ├── jfinal-1.8-bin-with-src.jar │ │ ├── java_memcached-release_2.6.6.jar │ │ └── mysql-connector-java-5.1.20-bin.jar │ ├── config.txt.example │ ├── tpl │ │ ├── app │ │ │ ├── scale.html │ │ │ ├── history.html │ │ │ ├── create.html │ │ │ ├── env.html │ │ │ ├── edit.html │ │ │ ├── instance.html │ │ │ └── deploy.html │ │ ├── domain │ │ │ ├── bind.html │ │ │ ├── create.html │ │ │ ├── edit.html │ │ │ └── index.html │ │ ├── common │ │ │ ├── _blank.html │ │ │ ├── _paginate.html │ │ │ └── _layout.html │ │ └── index.html │ └── web.xml ├── layer │ ├── skin │ │ ├── default │ │ │ ├── textbg.png │ │ │ ├── icon_ext.png │ │ │ ├── xubox_ico0.png │ │ │ ├── xubox_title0.png │ │ │ ├── xubox_loading0.gif │ │ │ ├── xubox_loading1.gif │ │ │ ├── xubox_loading2.gif │ │ │ └── xubox_loading3.gif │ │ ├── layer.ext.css │ │ └── layer.css │ ├── extend │ │ └── layer.ext.js │ └── layer.min.js ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff ├── css │ ├── g.css │ └── select2-bootstrap.css └── js │ ├── g.js │ ├── md5.js │ └── bootstrap.min.js ├── lib └── jetty-server-8.1.8.jar ├── .gitignore ├── frame └── com │ └── ulricqin │ ├── frame │ ├── exception │ │ └── RenderJsonMsgException.java │ └── kit │ │ ├── Checker.java │ │ └── StringKit.java │ └── jfinal │ └── ext │ └── plugin │ └── MemcachePlugin.java ├── src └── com │ └── ulricqin │ └── dash │ ├── controller │ ├── HealthController.java │ ├── CacheController.java │ ├── HistoryController.java │ ├── ApiController.java │ ├── MainController.java │ ├── AuthController.java │ ├── EnvController.java │ ├── DomainController.java │ └── AppController.java │ ├── model │ ├── History.java │ ├── Env.java │ ├── Team.java │ ├── Domain.java │ ├── User.java │ └── App.java │ ├── interceptor │ ├── AppFromUrlInterceptor.java │ ├── DomainFromUrlInterceptor.java │ ├── GlobalInterceptor.java │ └── LoginRequiredInterceptor.java │ ├── api │ ├── ServerApi.java │ └── UicApi.java │ └── config │ └── Config.java ├── README.md ├── conf └── log4j.properties ├── .classpath ├── .project └── scripts └── schema.sql /.settings/org.eclipse.wst.jsdt.ui.superType.name: -------------------------------------------------------------------------------- 1 | Window -------------------------------------------------------------------------------- /web/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Class-Path: 3 | 4 | -------------------------------------------------------------------------------- /web/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/favicon.ico -------------------------------------------------------------------------------- /web/img/guy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/img/guy.jpg -------------------------------------------------------------------------------- /web/select2/select2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/select2/select2.png -------------------------------------------------------------------------------- /lib/jetty-server-8.1.8.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/lib/jetty-server-8.1.8.jar -------------------------------------------------------------------------------- /web/select2/select2x2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/select2/select2x2.png -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.jsdt.ui.superType.container: -------------------------------------------------------------------------------- 1 | org.eclipse.wst.jsdt.launching.baseBrowserLibrary -------------------------------------------------------------------------------- /web/select2/select2-spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/select2/select2-spinner.gif -------------------------------------------------------------------------------- /web/WEB-INF/lib/c3p0-0.9.1.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/WEB-INF/lib/c3p0-0.9.1.2.jar -------------------------------------------------------------------------------- /web/WEB-INF/lib/httpcore-4.3.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/WEB-INF/lib/httpcore-4.3.2.jar -------------------------------------------------------------------------------- /web/WEB-INF/lib/httpmime-4.3.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/WEB-INF/lib/httpmime-4.3.5.jar -------------------------------------------------------------------------------- /web/WEB-INF/lib/log4j-1.2.16.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/WEB-INF/lib/log4j-1.2.16.jar -------------------------------------------------------------------------------- /web/layer/skin/default/textbg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/layer/skin/default/textbg.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | *.swp 3 | *.swo 4 | /var 5 | /web/WEB-INF/classes 6 | /web/WEB-INF/config.txt 7 | .DS_Store 8 | -------------------------------------------------------------------------------- /web/WEB-INF/lib/fastjson-1.1.43.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/WEB-INF/lib/fastjson-1.1.43.jar -------------------------------------------------------------------------------- /web/WEB-INF/lib/fluent-hc-4.3.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/WEB-INF/lib/fluent-hc-4.3.5.jar -------------------------------------------------------------------------------- /web/WEB-INF/lib/httpclient-4.3.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/WEB-INF/lib/httpclient-4.3.5.jar -------------------------------------------------------------------------------- /web/WEB-INF/lib/slf4j-api-1.6.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/WEB-INF/lib/slf4j-api-1.6.1.jar -------------------------------------------------------------------------------- /web/layer/skin/default/icon_ext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/layer/skin/default/icon_ext.png -------------------------------------------------------------------------------- /web/WEB-INF/lib/commons-codec-1.6.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/WEB-INF/lib/commons-codec-1.6.jar -------------------------------------------------------------------------------- /web/WEB-INF/lib/commons-lang3-3.3.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/WEB-INF/lib/commons-lang3-3.3.2.jar -------------------------------------------------------------------------------- /web/WEB-INF/lib/commons-pool-1.5.6.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/WEB-INF/lib/commons-pool-1.5.6.jar -------------------------------------------------------------------------------- /web/WEB-INF/lib/freemarker-2.3.20.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/WEB-INF/lib/freemarker-2.3.20.jar -------------------------------------------------------------------------------- /web/WEB-INF/lib/slf4j-log4j12-1.6.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/WEB-INF/lib/slf4j-log4j12-1.6.1.jar -------------------------------------------------------------------------------- /web/layer/skin/default/xubox_ico0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/layer/skin/default/xubox_ico0.png -------------------------------------------------------------------------------- /web/layer/skin/default/xubox_title0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/layer/skin/default/xubox_title0.png -------------------------------------------------------------------------------- /web/WEB-INF/lib/commons-logging-1.1.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/WEB-INF/lib/commons-logging-1.1.3.jar -------------------------------------------------------------------------------- /web/layer/skin/default/xubox_loading0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/layer/skin/default/xubox_loading0.gif -------------------------------------------------------------------------------- /web/layer/skin/default/xubox_loading1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/layer/skin/default/xubox_loading1.gif -------------------------------------------------------------------------------- /web/layer/skin/default/xubox_loading2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/layer/skin/default/xubox_loading2.gif -------------------------------------------------------------------------------- /web/layer/skin/default/xubox_loading3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/layer/skin/default/xubox_loading3.gif -------------------------------------------------------------------------------- /web/WEB-INF/lib/httpclient-cache-4.3.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/WEB-INF/lib/httpclient-cache-4.3.5.jar -------------------------------------------------------------------------------- /web/WEB-INF/lib/jfinal-1.8-bin-with-src.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/WEB-INF/lib/jfinal-1.8-bin-with-src.jar -------------------------------------------------------------------------------- /web/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /web/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /web/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /web/WEB-INF/lib/java_memcached-release_2.6.6.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/WEB-INF/lib/java_memcached-release_2.6.6.jar -------------------------------------------------------------------------------- /web/WEB-INF/lib/mysql-connector-java-5.1.20-bin.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinp/dash/HEAD/web/WEB-INF/lib/mysql-connector-java-5.1.20-bin.jar -------------------------------------------------------------------------------- /frame/com/ulricqin/frame/exception/RenderJsonMsgException.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.frame.exception; 2 | 3 | public class RenderJsonMsgException extends RuntimeException { 4 | 5 | private static final long serialVersionUID = 8534760341910402946L; 6 | 7 | public RenderJsonMsgException(String msg) { 8 | super(msg); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/com/ulricqin/dash/controller/HealthController.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.dash.controller; 2 | 3 | import com.jfinal.core.Controller; 4 | 5 | public class HealthController extends Controller { 6 | 7 | public void index() { 8 | renderText("ok"); 9 | } 10 | 11 | public void json() { 12 | setAttr("name", "Ulric"); 13 | renderJson(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.common.project.facet.core.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 4 | org.eclipse.jdt.core.compiler.compliance=1.8 5 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 6 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 7 | org.eclipse.jdt.core.compiler.source=1.8 8 | -------------------------------------------------------------------------------- /web/WEB-INF/config.txt.example: -------------------------------------------------------------------------------- 1 | jdbcUrl = jdbc:mysql://127.0.0.1/dash?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull 2 | user = dinp 3 | password = 4 | devMode = false 5 | memcacheAddrs = 127.0.0.1:11211 6 | memcachePrefix = dash: 7 | uicInternal = http://uic.com 8 | uicExternal = http://uic.com 9 | builder = http://build.com 10 | server = http://127.0.0.1:1980 11 | paasDomain = apps.io 12 | token = same-to-uic 13 | -------------------------------------------------------------------------------- /src/com/ulricqin/dash/model/History.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.dash.model; 2 | 3 | import java.util.List; 4 | 5 | import com.jfinal.plugin.activerecord.Model; 6 | 7 | public class History extends Model{ 8 | 9 | private static final long serialVersionUID = 2247813999236765493L; 10 | public static final History dao = new History(); 11 | 12 | public static List getByAppId(long appId) { 13 | return dao.find("select * from `history` where app_id = ? order by id desc", appId); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Dashboard 2 | ========= 3 | 4 | 这是DINP中的dashboard,是用户操作的入口。我们没有提供命令行的入口,只提供了web的入口,有三个原因: 5 | 6 | - 我们发现很多用户还是习惯web界面 7 | - 命令行工具需要安装,而浏览器无需安装 8 | - 人力问题 9 | 10 | dashboard采用 [UIC](http://ulricqin.com/project/uic/) 作为单点登录系统,故而,要run dashboard需要提前部署UIC。 11 | 12 | # 部署 13 | 14 | 和UIC一样,这也是一个java项目,也是采用JFinal框架,也是使用Ant来打包编译,也是采用JDK7+Tomcat7来run,请参考前面UIC的链接,里边介绍了UIC的部署方式 15 | 16 | # 手册 17 | 18 | http://dinp.qiniudn.com/manual.pdf 19 | 20 | # 传送门 21 | 22 | 国内用户使用github可能比较慢,我也push了一份到gitcafe: https://gitcafe.com/dinp/dash ,不用谢 23 | -------------------------------------------------------------------------------- /.settings/.jsdtscope: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /conf/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=info, stdout 2 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 3 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 4 | log4j.appender.stdout.layout.ConversionPattern=%n%-d{yyyy-MM-dd HH:mm:ss}%n[%p]-[Thread: %t]-[%C.%M()]: %m%n 5 | 6 | # Output to the File 7 | log4j.appender.file=org.apache.log4j.FileAppender 8 | log4j.appender.file.File=/home/work/logs/paas-dash.log 9 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 10 | log4j.appender.file.layout.ConversionPattern=%n%-d{yyyy-MM-dd HH:mm:ss}%n[%p]-[Thread: %t]-[%C.%M()]: %m%n 11 | -------------------------------------------------------------------------------- /src/com/ulricqin/dash/model/Env.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.dash.model; 2 | 3 | import java.util.List; 4 | 5 | import com.jfinal.plugin.activerecord.Db; 6 | import com.jfinal.plugin.activerecord.Model; 7 | 8 | public class Env extends Model{ 9 | 10 | private static final long serialVersionUID = -2098540094986122367L; 11 | public static final Env dao = new Env(); 12 | 13 | public static void deleteByAppId(Long appId) { 14 | Db.update("delete from `env` where app_id = ?", appId); 15 | } 16 | 17 | public List findByAppId(long appId) { 18 | return dao.find("select * from `env` where app_id = ?", appId); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/com/ulricqin/dash/controller/CacheController.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.dash.controller; 2 | 3 | import com.jfinal.aop.Before; 4 | import com.jfinal.core.Controller; 5 | import com.ulricqin.dash.interceptor.LoginRequiredInterceptor; 6 | import com.ulricqin.dash.model.User; 7 | import com.ulricqin.jfinal.ext.plugin.MemcachePlugin; 8 | 9 | @Before(LoginRequiredInterceptor.class) 10 | public class CacheController extends Controller { 11 | 12 | public void flush() { 13 | User me = getAttr("me"); 14 | if (me.getRole() > 0) { 15 | renderText("" + MemcachePlugin.flushAll()); 16 | } else { 17 | renderText("no privilege"); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.common.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /web/WEB-INF/tpl/app/scale.html: -------------------------------------------------------------------------------- 1 | <#include "../common/_layout.html"/> <@layout> 2 | 3 |
4 |
5 |

Scale Application ${app.name}:

6 |
7 |
8 | 9 |
10 | 12 |
13 | 14 | 15 | Cancel 16 | 17 |
18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /src/com/ulricqin/dash/controller/HistoryController.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.dash.controller; 2 | 3 | import com.jfinal.aop.Before; 4 | import com.jfinal.core.Controller; 5 | import com.ulricqin.dash.interceptor.LoginRequiredInterceptor; 6 | import com.ulricqin.dash.model.History; 7 | import com.ulricqin.frame.exception.RenderJsonMsgException; 8 | 9 | @Before(LoginRequiredInterceptor.class) 10 | public class HistoryController extends Controller { 11 | 12 | public void delete() { 13 | int historyId = getParaToInt(); 14 | if (historyId < 1) { 15 | throw new RenderJsonMsgException("parameter id is invalid"); 16 | } 17 | 18 | History.dao.deleteById(historyId); 19 | 20 | renderJson(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/com/ulricqin/dash/model/Team.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.dash.model; 2 | 3 | public class Team implements java.io.Serializable { 4 | 5 | private static final long serialVersionUID = -8072209407169886500L; 6 | 7 | private int id; 8 | private String name; 9 | 10 | public Team() { 11 | 12 | } 13 | 14 | public Team(int id, String name) { 15 | this.id = id; 16 | this.name = name; 17 | } 18 | 19 | public int getId() { 20 | return id; 21 | } 22 | 23 | public void setId(int id) { 24 | this.id = id; 25 | } 26 | 27 | public String getName() { 28 | return name; 29 | } 30 | 31 | public void setName(String name) { 32 | this.name = name; 33 | } 34 | 35 | @Override 36 | public String toString() { 37 | return "Team [id=" + id + ", name=" + name + "]"; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/com/ulricqin/dash/controller/ApiController.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.dash.controller; 2 | 3 | import com.jfinal.aop.Before; 4 | import com.jfinal.core.Controller; 5 | import com.ulricqin.dash.api.ServerApi; 6 | import com.ulricqin.dash.interceptor.AppFromUrlInterceptor; 7 | import com.ulricqin.dash.model.App; 8 | import com.ulricqin.frame.exception.RenderJsonMsgException; 9 | import com.ulricqin.frame.kit.StringKit; 10 | 11 | public class ApiController extends Controller { 12 | 13 | @Before(AppFromUrlInterceptor.class) 14 | public void instances() { 15 | App app = getAttr("app"); 16 | String jsonString = ServerApi.containersOf(app.getStr("name")); 17 | if (StringKit.isBlank(jsonString)) { 18 | throw new RenderJsonMsgException("curl server fail"); 19 | } 20 | 21 | renderJson(jsonString); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/com/ulricqin/dash/interceptor/AppFromUrlInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.dash.interceptor; 2 | 3 | import com.jfinal.aop.Interceptor; 4 | import com.jfinal.core.ActionInvocation; 5 | import com.jfinal.core.Controller; 6 | import com.ulricqin.dash.model.App; 7 | import com.ulricqin.frame.exception.RenderJsonMsgException; 8 | 9 | public class AppFromUrlInterceptor implements Interceptor { 10 | 11 | @Override 12 | public void intercept(ActionInvocation ai) { 13 | Controller controller = ai.getController(); 14 | int appId = controller.getParaToInt(); 15 | if (appId < 1) { 16 | throw new RenderJsonMsgException("parameter id is invalid"); 17 | } 18 | 19 | App app = App.dao.findById(appId); 20 | if (app == null) { 21 | throw new RenderJsonMsgException("no such app"); 22 | } 23 | 24 | controller.setAttr("app", app); 25 | ai.invoke(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /web/WEB-INF/tpl/domain/bind.html: -------------------------------------------------------------------------------- 1 | <#include "../common/_layout.html"/> <@layout> 2 | 3 |
4 |
5 |

${d.domain} bind app:

6 |
7 |
8 |
9 | 10 | 19 |
20 | 21 | 23 | Cancel 24 |
25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /src/com/ulricqin/dash/api/ServerApi.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.dash.api; 2 | 3 | import java.io.IOException; 4 | 5 | import org.apache.http.HttpResponse; 6 | import org.apache.http.StatusLine; 7 | import org.apache.http.client.fluent.Request; 8 | import org.apache.http.util.EntityUtils; 9 | 10 | import com.ulricqin.dash.config.Config; 11 | 12 | public class ServerApi { 13 | 14 | public static String containersOf(String appName) { 15 | HttpResponse resp; 16 | try { 17 | resp = Request.Get(Config.serverUrl + "/app/" + appName).execute() 18 | .returnResponse(); 19 | } catch (IOException e) { 20 | return null; 21 | } 22 | StatusLine statusLine = resp.getStatusLine(); 23 | if (statusLine.getStatusCode() != 200) { 24 | return null; 25 | } 26 | 27 | try { 28 | return EntityUtils.toString(resp.getEntity()); 29 | } catch (Exception e) { 30 | return null; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/com/ulricqin/dash/interceptor/DomainFromUrlInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.dash.interceptor; 2 | 3 | import com.jfinal.aop.Interceptor; 4 | import com.jfinal.core.ActionInvocation; 5 | import com.jfinal.core.Controller; 6 | import com.ulricqin.dash.model.Domain; 7 | import com.ulricqin.frame.exception.RenderJsonMsgException; 8 | 9 | public class DomainFromUrlInterceptor implements Interceptor { 10 | 11 | @Override 12 | public void intercept(ActionInvocation ai) { 13 | Controller controller = ai.getController(); 14 | int domainId = controller.getParaToInt(); 15 | if (domainId < 1) { 16 | throw new RenderJsonMsgException("parameter id is invalid"); 17 | } 18 | 19 | Domain d = Domain.dao.findById(domainId); 20 | if (d == null) { 21 | throw new RenderJsonMsgException("no such domain"); 22 | } 23 | 24 | controller.setAttr("domain", d); 25 | ai.invoke(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /web/WEB-INF/tpl/domain/create.html: -------------------------------------------------------------------------------- 1 | <#include "../common/_layout.html"/> <@layout> 2 | 3 |
4 |
5 |

create domain

6 |
7 |
8 |
9 | 10 |
11 |
12 | 17 |
18 | 20 | Cancel 21 |
22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /frame/com/ulricqin/frame/kit/Checker.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.frame.kit; 2 | 3 | import java.util.regex.Matcher; 4 | import java.util.regex.Pattern; 5 | 6 | public class Checker { 7 | 8 | public static boolean isIdentifier(String name) { 9 | if (StringKit.isBlank(name)) { 10 | throw new IllegalArgumentException("argument is blank"); 11 | } 12 | 13 | Pattern pattern = Pattern.compile("[a-zA-Z0-9\\-\\_]+"); 14 | Matcher matcher = pattern.matcher(name); 15 | return matcher.matches(); 16 | } 17 | 18 | public static boolean isDomain(String domain) { 19 | if (StringKit.isBlank(domain)) { 20 | throw new IllegalArgumentException("argument is blank"); 21 | } 22 | 23 | Pattern pattern = Pattern.compile("^[a-z0-9\\-\\_][a-z0-9\\-\\_\\.]+[a-z]$"); 24 | Matcher matcher = pattern.matcher(domain); 25 | return matcher.matches(); 26 | } 27 | 28 | public static void main(String[] args) { 29 | System.out.println(isDomain("_a.com")); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /frame/com/ulricqin/frame/kit/StringKit.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.frame.kit; 2 | 3 | import java.util.UUID; 4 | 5 | public class StringKit { 6 | 7 | public static boolean isBlank(String val) { 8 | if (val == null || val.equals("") || val.trim().equals("")) { 9 | return true; 10 | } else { 11 | return false; 12 | } 13 | } 14 | 15 | public static boolean isNotBlank(String val) { 16 | return !isBlank(val); 17 | } 18 | 19 | public static String firstCharToLowerCase(String str) { 20 | Character firstChar = str.charAt(0); 21 | String tail = str.substring(1); 22 | str = Character.toLowerCase(firstChar) + tail; 23 | return str; 24 | } 25 | 26 | public static String firstCharToUpperCase(String str) { 27 | Character firstChar = str.charAt(0); 28 | String tail = str.substring(1); 29 | str = Character.toUpperCase(firstChar) + tail; 30 | return str; 31 | } 32 | 33 | public static String randomStr32() { 34 | return UUID.randomUUID().toString().replace("-", ""); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /web/WEB-INF/tpl/domain/edit.html: -------------------------------------------------------------------------------- 1 | <#include "../common/_layout.html"/> <@layout> 2 | 3 |
4 |
5 |

edit domain: ${d.domain}

6 |
7 |
8 |
9 | 12 | 21 |
22 | 23 | 25 | Cancel 26 |
27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /web/WEB-INF/tpl/common/_blank.html: -------------------------------------------------------------------------------- 1 | <#macro layout> 2 | 3 | 4 | 5 | 6 | 7 | 8 | ${title!} 9 | 10 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | <#nested> 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/com/ulricqin/dash/interceptor/GlobalInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.dash.interceptor; 2 | 3 | import org.apache.commons.lang3.exception.ExceptionUtils; 4 | 5 | import com.jfinal.aop.Interceptor; 6 | import com.jfinal.core.ActionInvocation; 7 | import com.jfinal.core.Controller; 8 | import com.ulricqin.frame.exception.RenderJsonMsgException; 9 | import com.ulricqin.frame.kit.StringKit; 10 | 11 | public class GlobalInterceptor implements Interceptor { 12 | 13 | @Override 14 | public void intercept(ActionInvocation ai) { 15 | Controller controller = ai.getController(); 16 | try { 17 | ai.invoke(); 18 | String msg = controller.getAttr("msg"); 19 | if (StringKit.isBlank(msg)) { 20 | controller.setAttr("msg", ""); 21 | } 22 | } catch (RenderJsonMsgException e) { 23 | controller.renderJson("msg", e.getMessage()); 24 | } catch (Exception e) { 25 | String msg = ExceptionUtils.getMessage(e); 26 | System.out.println(msg); 27 | System.out.println(ExceptionUtils.getStackTrace(e)); 28 | controller.renderJson("msg", msg); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/com/ulricqin/dash/controller/MainController.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.dash.controller; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.jfinal.aop.Before; 7 | import com.jfinal.core.Controller; 8 | import com.ulricqin.dash.api.UicApi; 9 | import com.ulricqin.dash.config.Config; 10 | import com.ulricqin.dash.interceptor.LoginRequiredInterceptor; 11 | import com.ulricqin.dash.model.App; 12 | import com.ulricqin.dash.model.Team; 13 | import com.ulricqin.dash.model.User; 14 | 15 | @Before(LoginRequiredInterceptor.class) 16 | public class MainController extends Controller { 17 | 18 | public void index() { 19 | User me = getAttr("me"); 20 | List ts = UicApi.myTeams(me.getId()); 21 | List tids = new ArrayList(); 22 | if (ts != null && ts.size() > 0) { 23 | for (Team t : ts) { 24 | tids.add(t.getId()); 25 | } 26 | } 27 | 28 | List apps = App.mine(me.getId(), tids); 29 | setAttr("apps", apps); 30 | 31 | setAttr("paasDomain", Config.paasDomain); 32 | setAttr("title", "PaaS-Dashboard"); 33 | render("index.html"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /web/WEB-INF/tpl/app/history.html: -------------------------------------------------------------------------------- 1 | <#include "../common/_layout.html"/> <@layout> 2 | 3 |
4 |
5 |

build history of ${app.name}:

6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | <#list list as x> 19 | 20 | 21 | 22 | 23 | 26 | 27 | 28 | 29 |
ImageResumeCreateAtOperation
${x.image}${x.resume}${x.create_at}use 24 | ¦ 25 | delete
30 |
31 |
32 | 33 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /web/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | dash 8 | 9 | 10 | JFinal 11 | com.jfinal.core.JFinalFilter 12 | 13 | configClass 14 | com.ulricqin.dash.config.Config 15 | 16 | 17 | 18 | 19 | JFinal 20 | /* 21 | 22 | 23 | 24 | index.html 25 | index.htm 26 | index.jsp 27 | default.html 28 | default.htm 29 | default.jsp 30 | 31 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | dash 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.jsdt.core.javascriptValidator 10 | 11 | 12 | 13 | 14 | org.eclipse.jdt.core.javabuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.wst.common.project.facet.core.builder 20 | 21 | 22 | 23 | 24 | org.eclipse.wst.validation.validationbuilder 25 | 26 | 27 | 28 | 29 | 30 | org.eclipse.jem.workbench.JavaEMFNature 31 | org.eclipse.wst.common.modulecore.ModuleCoreNature 32 | org.eclipse.wst.common.project.facet.core.nature 33 | org.eclipse.jdt.core.javanature 34 | org.eclipse.wst.jsdt.core.jsNature 35 | 36 | 37 | -------------------------------------------------------------------------------- /web/WEB-INF/tpl/app/create.html: -------------------------------------------------------------------------------- 1 | <#include "../common/_layout.html"/> <@layout> 2 | 3 |
4 |
5 |

create app

6 |
7 |
8 |
9 | 11 |
12 |
13 | 18 |
19 |
20 | 21 | 22 |
23 | 25 | Cancel 26 |
27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /web/WEB-INF/tpl/app/env.html: -------------------------------------------------------------------------------- 1 | <#include "../common/_layout.html"/> <@layout> 2 | 3 |
4 |
5 |

app ${app.name} env variables:

6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | <#list envs as e> 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
KeyValueOperation
${e.k}${e.v}delete
26 |
27 |
28 | 30 |
31 |
32 | 34 |
35 | 36 | 37 |
38 |
39 |
40 | 41 | 42 | -------------------------------------------------------------------------------- /web/WEB-INF/tpl/app/edit.html: -------------------------------------------------------------------------------- 1 | <#include "../common/_layout.html"/> <@layout> 2 | 3 |
4 |
5 |

edit app: ${app.name}

6 |
7 |
8 |
9 | 12 | 21 |
22 |
23 | 24 | 25 |
26 | 27 | 29 | Cancel 30 |
31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /web/css/g.css: -------------------------------------------------------------------------------- 1 | body, input, div, span, h1, h2, h3, h4, h5, table, th, td, ul, li, dl, 2 | dt, dd, a { 3 | font-family: 'verdana', 'Microsoft YaHei', 'Consolas', 4 | 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono'; 5 | } 6 | 7 | .cut-line { 8 | margin: 0 5px; 9 | color: #D6D6D6; 10 | } 11 | 12 | .red { 13 | color: red; 14 | } 15 | 16 | .orange { 17 | color: orange; 18 | } 19 | 20 | .green { 21 | color: green; 22 | } 23 | 24 | .blue { 25 | color: blue; 26 | } 27 | 28 | .gray { 29 | color: #999 !important; 30 | } 31 | 32 | .mt0 { 33 | margin-top: 0px; 34 | } 35 | 36 | .mt10 { 37 | margin-top: 10px !important; 38 | } 39 | 40 | .mt20 { 41 | margin-top: 20px !important; 42 | } 43 | 44 | .thin-border { 45 | padding: 10px; 46 | line-height: 1; 47 | border: 1px solid #ddd; 48 | -webkit-border-radius: 4px; 49 | -moz-border-radius: 4px; 50 | border-radius: 4px; 51 | -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); 52 | -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); 53 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); 54 | background-color: #fff; 55 | } 56 | 57 | .line .tit { 58 | font-weight: bold; 59 | } 60 | 61 | .groups .group p{ 62 | line-height: 24px; 63 | } 64 | .groups .group p code { 65 | color: #F60!important; 66 | } -------------------------------------------------------------------------------- /web/WEB-INF/tpl/app/instance.html: -------------------------------------------------------------------------------- 1 | <#include "../common/_layout.html"/> <@layout> 2 | 22 |
23 |
24 |

running instances of ${app.name}:

25 |
26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
#IDIPPortStatus
41 |
42 |
43 | 44 | refresh 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/com/ulricqin/dash/controller/AuthController.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.dash.controller; 2 | 3 | import java.io.IOException; 4 | 5 | import org.apache.http.HttpResponse; 6 | import org.apache.http.StatusLine; 7 | import org.apache.http.client.fluent.Request; 8 | 9 | import com.jfinal.core.Controller; 10 | import com.ulricqin.dash.config.Config; 11 | import com.ulricqin.frame.exception.RenderJsonMsgException; 12 | import com.ulricqin.frame.kit.StringKit; 13 | 14 | public class AuthController extends Controller { 15 | 16 | public void logout() { 17 | String sig = getCookie("sig"); 18 | if (StringKit.isBlank(sig)) { 19 | throw new RenderJsonMsgException("u'r not login"); 20 | } 21 | 22 | HttpResponse resp = null; 23 | try { 24 | resp = Request.Get(Config.uicInternal + "/sso/logout/" + sig + "?token=" + Config.token).execute() 25 | .returnResponse(); 26 | } catch (IOException e) { 27 | throw new RenderJsonMsgException(e.getMessage()); 28 | } 29 | 30 | StatusLine statusLine = resp.getStatusLine(); 31 | if (statusLine.getStatusCode() != 200 && statusLine.getStatusCode() != 404) { 32 | throw new RenderJsonMsgException("curl " + Config.uicInternal + "/sso/logout/" + sig + " fail"); 33 | } 34 | 35 | setCookie("sig", "", 0, "/"); 36 | redirect("/"); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /web/WEB-INF/tpl/app/deploy.html: -------------------------------------------------------------------------------- 1 | <#include "../common/_layout.html"/> <@layout> 2 | 3 |
4 |
5 |

deploy ${app.name}:

6 |
7 |
8 | 9 |
10 | 11 | 12 |
13 | 14 |
15 | 16 | 17 |
18 | 19 |
20 | 21 | 22 |
23 | 24 |
25 | 26 | 27 |
28 | 29 | 30 | 32 | Cancel 33 | 34 | 35 |
36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/com/ulricqin/dash/controller/EnvController.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.dash.controller; 2 | 3 | import com.jfinal.aop.Before; 4 | import com.jfinal.core.Controller; 5 | import com.ulricqin.dash.interceptor.LoginRequiredInterceptor; 6 | import com.ulricqin.dash.model.App; 7 | import com.ulricqin.dash.model.Env; 8 | import com.ulricqin.frame.exception.RenderJsonMsgException; 9 | import com.ulricqin.frame.kit.StringKit; 10 | 11 | @Before(LoginRequiredInterceptor.class) 12 | public class EnvController extends Controller { 13 | 14 | public void add() { 15 | String k = getPara("k", ""); 16 | String v = getPara("v", ""); 17 | long appId = getParaToInt("app_id", 0); 18 | if (appId < 1) { 19 | throw new RenderJsonMsgException("parameter app_id is invalid"); 20 | } 21 | 22 | App app = App.dao.findById(appId); 23 | if (app == null) { 24 | throw new RenderJsonMsgException("no such app"); 25 | } 26 | 27 | if (StringKit.isBlank(k)) { 28 | throw new RenderJsonMsgException("parameter k is blank"); 29 | } 30 | 31 | Env env = new Env(); 32 | env.set("k", k); 33 | env.set("v", v); 34 | env.set("app_id", appId); 35 | env.set("app_name", app.getStr("name")); 36 | if (!env.save()) { 37 | throw new RenderJsonMsgException("occur unknown error"); 38 | } 39 | 40 | renderJson(); 41 | } 42 | 43 | public void delete() { 44 | int id = getParaToInt("id", 0); 45 | if (id < 1) { 46 | throw new RenderJsonMsgException("parameter id is invalid"); 47 | } 48 | 49 | if (!Env.dao.deleteById(id)) { 50 | throw new RenderJsonMsgException("occur unknown error"); 51 | } 52 | 53 | renderJson(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /web/WEB-INF/tpl/common/_paginate.html: -------------------------------------------------------------------------------- 1 | <#macro paginate currentPage totalPage actionUrl urlParas=""> 2 | <#if (totalPage <= 0) || (currentPage > totalPage)><#return> 3 | <#local startPage = currentPage - 4> 4 | <#if (startPage < 1)><#local startPage = 1> 5 | 6 | <#local endPage = currentPage + 4> 7 | <#if (endPage > totalPage)><#local endPage = totalPage> 8 | 9 |
    10 | <#if (currentPage <= 8)> 11 | <#local startPage = 1> 12 | 13 | <#if ((totalPage - currentPage) < 8)> 14 | <#local endPage = totalPage> 15 | 16 | 17 | <#if (currentPage == 1)> 18 |
  • 上页
  • 19 | <#else> 20 |
  • 上页
  • 21 | 22 | 23 | <#if (currentPage > 8)> 24 |
  • #{1}
  • 25 |
  • #{2}
  • 26 |
  • 27 | 28 | 29 | <#list startPage..endPage as i> 30 | <#if currentPage == i> 31 |
  • #{i}
  • 32 | <#else> 33 |
  • #{i}
  • 34 | 35 | 36 | 37 | <#if ((totalPage - currentPage) >= 8)> 38 |
  • 39 |
  • #{totalPage - 1}
  • 40 |
  • #{totalPage}
  • 41 | 42 | 43 | <#if (currentPage == totalPage)> 44 |
  • 下页
  • 45 | <#else> 46 |
  • 下页
  • 47 | 48 |
49 | -------------------------------------------------------------------------------- /src/com/ulricqin/dash/model/Domain.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.dash.model; 2 | 3 | import java.util.List; 4 | 5 | import org.apache.commons.lang3.StringUtils; 6 | 7 | import com.jfinal.plugin.activerecord.Db; 8 | import com.jfinal.plugin.activerecord.Model; 9 | 10 | public class Domain extends Model{ 11 | 12 | private static final long serialVersionUID = -9021991906913012024L; 13 | public static final Domain dao = new Domain(); 14 | 15 | public static void deleteByAppId(Long appId) { 16 | Db.update("delete from domain where app_id = ?", appId); 17 | } 18 | 19 | public static void unbindApp(Long appId) { 20 | Db.update("update domain set app_id = 0, app_name = '' where app_id = ?", appId); 21 | } 22 | 23 | public List findByAppId(long appId) { 24 | return dao.find("select * from `domain` where app_id = ?", appId); 25 | } 26 | 27 | public Domain findByName(String domain) { 28 | return dao.findFirst("select * from `domain` where `domain` = ?", domain); 29 | } 30 | 31 | public static List mine(int creator, List tids) { 32 | StringBuilder buf = new StringBuilder("select * from `domain` where `creator` = ?"); 33 | if (tids.size() > 0) { 34 | buf.append(" or `team_id` in (").append(StringUtils.join(tids, ',')).append(")"); 35 | } 36 | buf.append(" order by domain"); 37 | 38 | return dao.find(buf.toString(), creator); 39 | } 40 | 41 | public static boolean save(String domain, int tid, String tname, User u) { 42 | Domain d = new Domain(); 43 | d.set("domain", domain); 44 | d.set("team_id", tid); 45 | d.set("team_name", tname); 46 | d.set("creator", u.getId()); 47 | d.set("creator_name", u.getName()); 48 | d.set("bind_user_id", u.getId()); 49 | return d.save(); 50 | } 51 | 52 | public boolean updateTeam(int tid, String tname) { 53 | this.set("team_id", tid); 54 | this.set("team_name", tname); 55 | return this.update(); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /web/WEB-INF/tpl/domain/index.html: -------------------------------------------------------------------------------- 1 | <#include "../common/_layout.html"/> <@layout> 2 | 3 |
4 |
5 |

Domains

6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | <#list ds as o> 20 | 21 | 22 | 28 | 36 | 39 | 40 | 41 | 42 |
DomainTeamAppNameOperation
${o.domain} 23 | ${o.team_name} 24 | <#if (me.id == o.creator)> 25 | 26 | 27 | 29 | <#if o.app_id == 0> 30 | bind app 31 | <#else> 32 | ${o.app_name} 33 | 34 | 35 | 37 | 38 |
43 | 44 |
45 |
46 | 47 |
48 | Create Domain 49 |
50 | 51 | 52 | -------------------------------------------------------------------------------- /web/WEB-INF/tpl/common/_layout.html: -------------------------------------------------------------------------------- 1 | <#macro layout> 2 | 3 | 4 | 5 | 6 | 7 | 8 | ${title!} 9 | 10 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |
27 |
28 |
29 |
30 |
31 | 33 |
34 |
35 |

PaaS Dashboard

36 |
37 |
38 | welcome, ${(me.name)!} ¦ logout 40 |
41 |
42 |
43 |
44 | Domains 45 | Apps 46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | <#nested> 54 |
55 |
56 |
57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /frame/com/ulricqin/jfinal/ext/plugin/MemcachePlugin.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.jfinal.ext.plugin; 2 | 3 | import com.danga.MemCached.MemCachedClient; 4 | import com.danga.MemCached.SockIOPool; 5 | import com.jfinal.plugin.IPlugin; 6 | 7 | public class MemcachePlugin implements IPlugin { 8 | 9 | private static MemCachedClient client = new MemCachedClient(); 10 | private static String prefix = ""; 11 | 12 | private String[] addr; 13 | private Integer[] weights; 14 | 15 | public MemcachePlugin(String[] addr, Integer[] weights) { 16 | this.addr = addr; 17 | this.weights = weights; 18 | } 19 | 20 | @Override 21 | public boolean start() { 22 | SockIOPool pool = SockIOPool.getInstance(); 23 | pool.setServers(addr); 24 | pool.setWeights(weights); 25 | pool.setInitConn(5); 26 | pool.setMinConn(5); 27 | pool.setMaxConn(200); 28 | pool.setMaxIdle(1000 * 30 * 30); 29 | pool.setMaintSleep(30); 30 | pool.setNagle(false); 31 | pool.setSocketTO(30); 32 | pool.setSocketConnectTO(0); 33 | pool.initialize(); 34 | return true; 35 | } 36 | 37 | @Override 38 | public boolean stop() { 39 | SockIOPool pool = SockIOPool.getInstance(); 40 | pool.shutDown(); 41 | return true; 42 | } 43 | 44 | public static void setPrefix(String prefix) { 45 | MemcachePlugin.prefix = prefix; 46 | } 47 | 48 | public static Object get(String key) { 49 | return client.get(prefix + key); 50 | } 51 | 52 | public static boolean set(String key, Object val) { 53 | return client.set(prefix + key, val); 54 | } 55 | 56 | public static boolean flushAll() { 57 | return client.flushAll(); 58 | } 59 | 60 | public static void main(String[] args) { 61 | String[] addr = { "127.0.0.1:11211" }; 62 | Integer[] weights = { 3 }; 63 | MemcachePlugin plugin = new MemcachePlugin(addr, weights); 64 | plugin.start(); 65 | 66 | // 将数据放入缓存 67 | client.set("name", "Rain"); 68 | String name = (String) client.get("name"); 69 | System.out.println(name); 70 | 71 | client.set("name", "Flame"); 72 | System.out.println(client.get("name")); 73 | 74 | // 删除缓存数据 75 | client.delete("name"); 76 | System.out.println(client.get("name")); 77 | 78 | plugin.stop(); 79 | 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/com/ulricqin/dash/model/User.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.dash.model; 2 | 3 | public class User implements java.io.Serializable { 4 | 5 | private static final long serialVersionUID = 1674809083412836887L; 6 | 7 | private int id; 8 | private String name; 9 | private String cnname; 10 | private String email; 11 | private String phone; 12 | private String im; 13 | private String qq; 14 | private int role; 15 | private int creator; 16 | private String created; 17 | 18 | public int getId() { 19 | return id; 20 | } 21 | 22 | public void setId(int id) { 23 | this.id = id; 24 | } 25 | 26 | public String getName() { 27 | return name; 28 | } 29 | 30 | public void setName(String name) { 31 | this.name = name; 32 | } 33 | 34 | public String getCnname() { 35 | return cnname; 36 | } 37 | 38 | public void setCnname(String cnname) { 39 | this.cnname = cnname; 40 | } 41 | 42 | public String getEmail() { 43 | return email; 44 | } 45 | 46 | public void setEmail(String email) { 47 | this.email = email; 48 | } 49 | 50 | public String getPhone() { 51 | return phone; 52 | } 53 | 54 | public void setPhone(String phone) { 55 | this.phone = phone; 56 | } 57 | 58 | public String getIm() { 59 | return im; 60 | } 61 | 62 | public void setIm(String im) { 63 | this.im = im; 64 | } 65 | 66 | public String getQq() { 67 | return qq; 68 | } 69 | 70 | public void setQq(String qq) { 71 | this.qq = qq; 72 | } 73 | 74 | public int getRole() { 75 | return role; 76 | } 77 | 78 | public void setRole(int role) { 79 | this.role = role; 80 | } 81 | 82 | public int getCreator() { 83 | return creator; 84 | } 85 | 86 | public void setCreator(int creator) { 87 | this.creator = creator; 88 | } 89 | 90 | public String getCreated() { 91 | return created; 92 | } 93 | 94 | public void setCreated(String created) { 95 | this.created = created; 96 | } 97 | 98 | @Override 99 | public String toString() { 100 | return "User [id=" + id + ", name=" + name + ", cnname=" + cnname 101 | + ", email=" + email + ", phone=" + phone + ", im=" + im 102 | + ", qq=" + qq + ", role=" + role + ", creator=" + creator 103 | + ", created=" + created + "]"; 104 | } 105 | 106 | 107 | 108 | } 109 | -------------------------------------------------------------------------------- /web/WEB-INF/tpl/index.html: -------------------------------------------------------------------------------- 1 | <#include "common/_layout.html"/> <@layout> 2 | 3 |
4 |
5 |

Applications

6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | <#list apps as a> 21 | 22 | 23 | 24 | 25 | 28 | 42 | 43 | 44 | 45 |
NameMemory(in MB)InstanceTeamOperation
${a.name}${a.memory}${a.instance} total 26 | ${a.team_name} 27 | 29 | deploy 30 | ¦ 31 | scale 32 | ¦ 33 | instances 34 | ¦ 35 | env 36 | ¦ 37 | history 38 | ¦ 39 | 40 | 41 |
46 | 47 |
48 |
49 | 50 |
51 | create app 52 |
53 | 54 | 55 | -------------------------------------------------------------------------------- /src/com/ulricqin/dash/interceptor/LoginRequiredInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.dash.interceptor; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.net.URLEncoder; 5 | 6 | import javax.servlet.http.Cookie; 7 | import javax.servlet.http.HttpServletRequest; 8 | 9 | import com.jfinal.aop.Interceptor; 10 | import com.jfinal.core.ActionInvocation; 11 | import com.jfinal.core.Controller; 12 | import com.ulricqin.dash.api.UicApi; 13 | import com.ulricqin.dash.config.Config; 14 | import com.ulricqin.dash.model.User; 15 | import com.ulricqin.frame.exception.RenderJsonMsgException; 16 | import com.ulricqin.frame.kit.StringKit; 17 | 18 | public class LoginRequiredInterceptor implements Interceptor { 19 | 20 | @Override 21 | public void intercept(ActionInvocation ai) { 22 | Controller controller = ai.getController(); 23 | String sig = controller.getCookie("sig"); 24 | if (sig == null || sig.equals("")) { 25 | redirectToSSO(controller); 26 | return; 27 | } 28 | 29 | User user = UicApi.getUser(sig); 30 | if (user == null) { 31 | redirectToSSO(controller); 32 | return; 33 | } 34 | 35 | if (user.getRole() < 0) { 36 | redirectToSSO(controller); 37 | return; 38 | } 39 | 40 | controller.setAttr("me", user); 41 | ai.invoke(); 42 | } 43 | 44 | private void redirectToSSO(Controller controller) { 45 | String sig = UicApi.genSig(); 46 | if (StringKit.isBlank(sig)) { 47 | throw new RenderJsonMsgException("gen sig fail"); 48 | } 49 | 50 | HttpServletRequest req = controller.getRequest(); 51 | String callback = req.getRequestURL().toString(); 52 | String queryString = req.getQueryString(); 53 | if (StringKit.isNotBlank(queryString)) { 54 | callback += "?" + queryString; 55 | } 56 | 57 | String cb; 58 | try { 59 | cb = URLEncoder.encode(callback, "UTF-8"); 60 | } catch (UnsupportedEncodingException e) { 61 | throw new RenderJsonMsgException("url encoding fail:" 62 | + e.getMessage()); 63 | } 64 | 65 | controller.setCookie(genCookie(sig)); 66 | 67 | controller.redirect(Config.uicExternal + "/auth/login?sig=" + sig 68 | + "&callback=" + cb); 69 | } 70 | 71 | private Cookie genCookie(String sig) { 72 | int maxAge = 3600 * 24 * 30; 73 | Cookie cookie = new Cookie("sig", sig); 74 | cookie.setPath("/"); 75 | cookie.setMaxAge(maxAge); 76 | cookie.setHttpOnly(true); 77 | return cookie; 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /scripts/schema.sql: -------------------------------------------------------------------------------- 1 | USE dash; 2 | 3 | SET NAMES utf8; 4 | 5 | /** 6 | * app name要作为域名的一部分,所以全局唯一 7 | * app有个创建者creator 8 | * app一般有多个人来维护,所以对应一个team 9 | * memory的单位是MB 10 | * instance是实例数目 11 | * status: 表示app的状态,running、flapping之类的 12 | */ 13 | DROP TABLE IF EXISTS app; 14 | CREATE TABLE app ( 15 | id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 16 | name VARCHAR(64) NOT NULL UNIQUE, 17 | creator INT UNSIGNED NOT NULL, 18 | team_id INT UNSIGNED NOT NULL default 0, 19 | team_name varchar(64) NOT NULL default '', 20 | image VARCHAR(255) NOT NULL DEFAULT '', 21 | memory INT NOT NULL DEFAULT 256, 22 | instance INT NOT NULL DEFAULT 0 23 | COMMENT 'instance count', 24 | status TINYINT NOT NULL DEFAULT 0, 25 | KEY idx_app_team(team_id) 26 | ) 27 | ENGINE =innodb 28 | DEFAULT CHARSET =utf8 29 | COLLATE =utf8_general_ci; 30 | 31 | DROP TABLE IF EXISTS domain; 32 | CREATE TABLE domain ( 33 | id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 34 | domain VARCHAR(255) NOT NULL UNIQUE, 35 | team_id INT UNSIGNED NOT NULL default 0, 36 | team_name VARCHAR(64) NOT NULL default '', 37 | app_id INT UNSIGNED NOT NULL default 0, 38 | app_name VARCHAR(64) NOT NULL default '', 39 | creator INT UNSIGNED NOT NULL, 40 | creator_name VARCHAR(64) NOT NULL, 41 | bind_user_id VARCHAR(64) NOT NULL, 42 | bind_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 43 | KEY idx_domain_app_id(app_id) 44 | ) 45 | ENGINE =innodb 46 | DEFAULT CHARSET =utf8 47 | COLLATE =utf8_general_ci; 48 | 49 | /* 50 | * 对于某个app,可以设置一些环境变量,比如DB连接地址,先期可以手填,之后可以结合rds使用 51 | */ 52 | DROP TABLE IF EXISTS env; 53 | CREATE TABLE env ( 54 | id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 55 | k VARCHAR(128) NOT NULL, 56 | v VARCHAR(1024) NOT NULL, 57 | app_id INT UNSIGNED NOT NULL, 58 | app_name VARCHAR(64) NOT NULL, 59 | KEY idx_env_app_id(app_id) 60 | ) 61 | ENGINE =innodb 62 | DEFAULT CHARSET =utf8 63 | COLLATE =utf8_general_ci; 64 | 65 | DROP TABLE IF EXISTS history; 66 | CREATE TABLE history ( 67 | id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 68 | app_id INT UNSIGNED NOT NULL, 69 | app_name VARCHAR(64) NOT NULL, 70 | resume VARCHAR(255) NOT NULL DEFAULT '', 71 | image VARCHAR(1024) NOT NULL DEFAULT '', 72 | create_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, 73 | KEY idx_history_app_id(app_id) 74 | ) 75 | ENGINE =innodb 76 | DEFAULT CHARSET =utf8 77 | COLLATE =utf8_general_ci; 78 | 79 | alter table app add column health varchar(128) not null default ''; -------------------------------------------------------------------------------- /web/layer/skin/layer.ext.css: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | @Name: layer拓展样式 4 | @Date: 2012.12.13 5 | @Author: 贤心 6 | @blog: sentsin.com 7 | 8 | **/ 9 | 10 | .xubox_iconext{background:url(default/icon_ext.png) no-repeat;} 11 | 12 | /* prompt模式 */ 13 | .xubox_layer .xubox_form{width:240px; height:30px; line-height:30px; padding: 0 5px; border: 1px solid #ccc; background: url(default/textbg.png) #fff repeat-x; color:#333;} 14 | .xubox_layer .xubox_formArea{width:300px; height:100px; line-height:20px;} 15 | 16 | /* tab模式 */ 17 | .xubox_layer .xubox_tab{position:relative; background-color:#fff; box-shadow:1px 1px 50px rgba(0,0,0,.4)} 18 | .xubox_layer .xubox_tabmove{position:absolute; width:600px; height:30px; top:0; left:0;} 19 | .xubox_layer .xubox_tabtit{ display:block; height:34px; border-bottom:1px solid #ccc; background-color:#eee;} 20 | .xubox_layer .xubox_tabtit span{position:relative; float:left; width:120px; height:34px; line-height:34px; text-align:center; cursor:default;} 21 | .xubox_layer .xubox_tabtit span.xubox_tabnow{left:-1px; _top:1px; height:35px; border-left:1px solid #ccc; border-right:1px solid #ccc; background-color:#fff; z-index:10;} 22 | .xubox_layer .xubox_tab_main{line-height:24px; clear:both;} 23 | .xubox_layer .xubox_tab_main .xubox_tabli{display:none;} 24 | .xubox_layer .xubox_tab_main .xubox_tabli.xubox_tab_layer{display:block;} 25 | .xubox_layer .xubox_tabclose{position:absolute; right:10px; top:5px; cursor:pointer;} 26 | 27 | /* photo模式 */ 28 | .xubox_bigimg, .xubox_intro{height:300px} 29 | .xubox_bigimg{position:relative; display:block; width:600px; text-align:center; background:url(default/xubox_loading1.gif) center center no-repeat #000; overflow:hidden; } 30 | .xubox_bigimg img{position:relative; display:inline-block; visibility: hidden;} 31 | .xubox_intro{position:absolute; right:-315px; top:0; width:300px; background-color:#fff; overflow-x:hidden; overflow-y:auto;} 32 | .xubox_imgsee{display:none;} 33 | .xubox_prev, .xubox_next{position:absolute; top:50%; width:27px; _width:44px; height:44px; margin-top:-22px; outline:none;blr:expression(this.onFocus=this.blur());} 34 | .xubox_prev{left:10px; background-position:-5px -5px; _background-position:-70px -5px;} 35 | .xubox_prev:hover{background-position:-33px -5px; _background-position:-120px -5px;} 36 | .xubox_next{right:10px; _right:8px; background-position:-5px -50px; _background-position:-70px -50px;} 37 | .xubox_next:hover{background-position:-33px -50px; _background-position:-120px -50px;} 38 | .xubox_imgbar{position:absolute; left:0; bottom:0; width:100%; height:32px; line-height:32px; background-color:rgba(0,0,0,.8); background-color:#000\9; filter:Alpha(opacity=80); color:#fff; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; font-size:0;} 39 | .xubox_imgtit{/*position:absolute; left:20px;*/} 40 | .xubox_imgtit *{display:inline-block; *display:inline; *zoom:1; vertical-align:top; font-size:12px;} 41 | .xubox_imgtit a{max-width:65%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; color:#fff;} 42 | .xubox_imgtit a:hover{color:#fff; text-decoration:underline;} 43 | .xubox_imgtit em{padding-left:10px;} 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/com/ulricqin/dash/model/App.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.dash.model; 2 | 3 | import java.util.List; 4 | 5 | import org.apache.commons.lang3.StringUtils; 6 | 7 | import com.jfinal.aop.Before; 8 | import com.jfinal.plugin.activerecord.Model; 9 | import com.jfinal.plugin.activerecord.tx.Tx; 10 | import com.ulricqin.dash.api.UicApi; 11 | 12 | public class App extends Model{ 13 | 14 | private static final long serialVersionUID = -7308337862247316589L; 15 | public static final App dao = new App(); 16 | 17 | public static boolean save(String name, int team_id, String team_name, int user_id, String health) { 18 | App a = new App(); 19 | a.set("name", name); 20 | a.set("team_id", team_id); 21 | a.set("team_name", team_name); 22 | a.set("creator", user_id); 23 | a.set("health", health); 24 | return a.save(); 25 | } 26 | 27 | public static List mine(int creator, List tids) { 28 | StringBuilder buf = new StringBuilder("select * from `app` where `creator` = ?"); 29 | if (tids.size() > 0) { 30 | buf.append(" or `team_id` in (").append(StringUtils.join(tids, ',')).append(")"); 31 | } 32 | buf.append(" order by name"); 33 | 34 | return dao.find(buf.toString(), creator); 35 | } 36 | 37 | public boolean delete(User creator) { 38 | if (!hasPrivilege(creator)) { 39 | return false; 40 | } 41 | 42 | return deleteInTx(creator); 43 | } 44 | 45 | @Before(Tx.class) 46 | private boolean deleteInTx(User creator) { 47 | boolean success = this.delete(); 48 | if (!success) { 49 | return false; 50 | } 51 | 52 | Domain.unbindApp(this.getLong("id")); 53 | Env.deleteByAppId(this.getLong("id")); 54 | 55 | return true; 56 | } 57 | 58 | private boolean hasPrivilege(User creator) { 59 | boolean hasPrivilege = false; 60 | if (this.getLong("creator").intValue() == creator.getId()) { 61 | hasPrivilege = true; 62 | } else { 63 | List teams = UicApi.myTeams(creator.getId()); 64 | for (Team team : teams) { 65 | if (team.getId() == this.getLong("team_id").intValue() && team.getName().equals(this.getStr("team_name"))) { 66 | hasPrivilege = true; 67 | } 68 | } 69 | } 70 | return hasPrivilege; 71 | } 72 | 73 | public boolean scale(int instance) { 74 | this.set("instance", instance); 75 | this.set("status", 0); 76 | return this.update(); 77 | } 78 | 79 | public boolean updateProfile(int tid, String tname, String health) { 80 | this.set("team_id", tid); 81 | this.set("team_name", tname); 82 | this.set("health", health); 83 | return this.update(); 84 | } 85 | 86 | @Before(Tx.class) 87 | public boolean deploy(int memory, int instance, String image, 88 | String resume) { 89 | History his = new History(); 90 | his.set("image", image); 91 | his.set("resume", resume); 92 | his.set("app_id", this.getLong("id")); 93 | his.set("app_name", this.getStr("name")); 94 | 95 | this.set("memory", memory); 96 | this.set("instance", instance); 97 | this.set("image", image); 98 | this.set("status", 0); 99 | 100 | return his.save() && this.update(); 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /src/com/ulricqin/dash/api/UicApi.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.dash.api; 2 | 3 | import java.io.IOException; 4 | import java.util.ArrayList; 5 | import java.util.Collections; 6 | import java.util.List; 7 | 8 | import org.apache.commons.logging.Log; 9 | import org.apache.commons.logging.LogFactory; 10 | import org.apache.http.HttpResponse; 11 | import org.apache.http.StatusLine; 12 | import org.apache.http.client.fluent.Request; 13 | import org.apache.http.util.EntityUtils; 14 | 15 | import com.alibaba.fastjson.JSON; 16 | import com.alibaba.fastjson.JSONArray; 17 | import com.alibaba.fastjson.JSONObject; 18 | import com.ulricqin.dash.config.Config; 19 | import com.ulricqin.dash.model.Team; 20 | import com.ulricqin.dash.model.User; 21 | import com.ulricqin.jfinal.ext.plugin.MemcachePlugin; 22 | 23 | public class UicApi { 24 | 25 | private static final Log log = LogFactory.getLog(UicApi.class); 26 | 27 | public static String genSig() { 28 | try { 29 | HttpResponse resp = Request.Get(Config.uicInternal + "/sso/sig").execute() 30 | .returnResponse(); 31 | StatusLine statusLine = resp.getStatusLine(); 32 | if (statusLine.getStatusCode() != 200) { 33 | return null; 34 | } 35 | return EntityUtils.toString(resp.getEntity()); 36 | } catch (IOException e) { 37 | log.error(e); 38 | return null; 39 | } 40 | } 41 | 42 | public static User getUser(String sig) { 43 | String key = "u:"+sig; 44 | Object val = MemcachePlugin.get(key); 45 | if (val == null) { 46 | User u = getUserFromSSO(sig); 47 | if (u == null) { 48 | return null; 49 | } 50 | 51 | MemcachePlugin.set(key, u); 52 | return u; 53 | } 54 | 55 | return (User)val; 56 | } 57 | 58 | public static User getUserFromSSO(String sig) { 59 | try { 60 | HttpResponse resp = Request.Get(Config.uicInternal + "/sso/user/" + sig + "?token=" + Config.token).execute() 61 | .returnResponse(); 62 | StatusLine statusLine = resp.getStatusLine(); 63 | if (statusLine.getStatusCode() != 200) { 64 | return null; 65 | } 66 | String content = EntityUtils.toString(resp.getEntity()); 67 | JSONObject jsonObject = JSON.parseObject(content); 68 | if (!jsonObject.containsKey("user")) { 69 | return null; 70 | } 71 | 72 | JSONObject userJson = jsonObject.getJSONObject("user"); 73 | if (userJson == null) { 74 | return null; 75 | } 76 | 77 | User u = JSON.toJavaObject(userJson, User.class); 78 | return u; 79 | } catch (IOException e) { 80 | return null; 81 | } 82 | } 83 | 84 | public static List myTeams(int uid) { 85 | try { 86 | HttpResponse resp = Request.Get(Config.uicInternal + "/team/mine/" + uid + "?token=" + Config.token).execute() 87 | .returnResponse(); 88 | StatusLine statusLine = resp.getStatusLine(); 89 | if (statusLine.getStatusCode() != 200) { 90 | return Collections.emptyList(); 91 | } 92 | 93 | String content = EntityUtils.toString(resp.getEntity()); 94 | JSONObject jsonObject = JSON.parseObject(content); 95 | if (!jsonObject.containsKey("teams")) { 96 | return Collections.emptyList(); 97 | } 98 | 99 | JSONArray jsonArray = jsonObject.getJSONArray("teams"); 100 | if (jsonArray == null || jsonArray.size() == 0) { 101 | return Collections.emptyList(); 102 | } 103 | 104 | List list = new ArrayList(); 105 | for (int i = 0; i < jsonArray.size(); i++) { 106 | JSONObject jsonTeam = jsonArray.getJSONObject(i); 107 | list.add(new Team(jsonTeam.getIntValue("id"), jsonTeam.getString("name"))); 108 | } 109 | 110 | return list; 111 | } catch (IOException e) { 112 | return Collections.emptyList(); 113 | } 114 | } 115 | 116 | public static void main(String[] args) { 117 | // sig: de2b8faabdfd4ff58f35e209a13473d4 118 | System.out.println(getUserFromSSO("de2b8faabdfd4ff58f35e209a13473d4")); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/com/ulricqin/dash/config/Config.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.dash.config; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | 5 | import com.jfinal.config.Constants; 6 | import com.jfinal.config.Handlers; 7 | import com.jfinal.config.Interceptors; 8 | import com.jfinal.config.JFinalConfig; 9 | import com.jfinal.config.Plugins; 10 | import com.jfinal.config.Routes; 11 | import com.jfinal.core.JFinal; 12 | import com.jfinal.plugin.activerecord.ActiveRecordPlugin; 13 | import com.jfinal.plugin.c3p0.C3p0Plugin; 14 | import com.ulricqin.dash.controller.ApiController; 15 | import com.ulricqin.dash.controller.AppController; 16 | import com.ulricqin.dash.controller.AuthController; 17 | import com.ulricqin.dash.controller.CacheController; 18 | import com.ulricqin.dash.controller.DomainController; 19 | import com.ulricqin.dash.controller.EnvController; 20 | import com.ulricqin.dash.controller.HealthController; 21 | import com.ulricqin.dash.controller.HistoryController; 22 | import com.ulricqin.dash.controller.MainController; 23 | import com.ulricqin.dash.interceptor.GlobalInterceptor; 24 | import com.ulricqin.dash.model.App; 25 | import com.ulricqin.dash.model.Domain; 26 | import com.ulricqin.dash.model.Env; 27 | import com.ulricqin.dash.model.History; 28 | import com.ulricqin.jfinal.ext.plugin.MemcachePlugin; 29 | 30 | public class Config extends JFinalConfig { 31 | 32 | public static String uicExternal; 33 | public static String uicInternal; 34 | public static String paasDomain; 35 | public static String serverUrl; 36 | public static String token; 37 | public static String builder; 38 | 39 | @Override 40 | public void configConstant(Constants me) { 41 | loadPropertyFile("config.txt"); 42 | me.setDevMode(getPropertyToBoolean("devMode", false)); 43 | me.setBaseViewPath("/WEB-INF/tpl"); 44 | 45 | uicExternal = getProperty("uicExternal"); 46 | uicInternal = getProperty("uicInternal"); 47 | paasDomain = getProperty("paasDomain"); 48 | serverUrl = getProperty("server"); 49 | token = getProperty("token"); 50 | builder = getProperty("builder"); 51 | } 52 | 53 | @Override 54 | public void configRoute(Routes me) { 55 | me.add("/", MainController.class); 56 | me.add("/health", HealthController.class); 57 | me.add("/cache", CacheController.class); 58 | me.add("/auth", AuthController.class); 59 | me.add("/app", AppController.class); 60 | me.add("/env", EnvController.class); 61 | me.add("/domain", DomainController.class); 62 | me.add("/history", HistoryController.class); 63 | me.add("/api", ApiController.class); 64 | } 65 | 66 | @Override 67 | public void configPlugin(Plugins me) { 68 | String jdbcUrl = getProperty("jdbcUrl").trim(); 69 | String jdbcUser = getProperty("user").trim(); 70 | String jdbcPasswd = getProperty("password").trim(); 71 | 72 | C3p0Plugin c3p0Plugin = new C3p0Plugin(jdbcUrl, jdbcUser, jdbcPasswd); 73 | me.add(c3p0Plugin); 74 | 75 | ActiveRecordPlugin arp = new ActiveRecordPlugin(c3p0Plugin); 76 | arp.setShowSql(getPropertyToBoolean("devMode", false)); 77 | me.add(arp); 78 | 79 | arp.addMapping("app", App.class); 80 | arp.addMapping("history", History.class); 81 | arp.addMapping("domain", Domain.class); 82 | arp.addMapping("env", Env.class); 83 | 84 | String memcacheAddrs = getProperty("memcacheAddrs").trim(); 85 | String[] addrs = StringUtils.split(memcacheAddrs, ','); 86 | Integer[] weights = new Integer[addrs.length]; 87 | for (int i = 0; i < weights.length; i++) { 88 | weights[i] = new Integer(10); 89 | } 90 | String prefix = getProperty("memcachePrefix").trim(); 91 | MemcachePlugin memcachePlugin = new MemcachePlugin(addrs, weights); 92 | MemcachePlugin.setPrefix(prefix); 93 | me.add(memcachePlugin); 94 | } 95 | 96 | @Override 97 | public void configInterceptor(Interceptors me) { 98 | me.add(new GlobalInterceptor()); 99 | } 100 | 101 | @Override 102 | public void configHandler(Handlers me) { 103 | 104 | } 105 | 106 | public static void main(String[] args) { 107 | JFinal.start("web", 8088, "/", 5); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /web/js/g.js: -------------------------------------------------------------------------------- 1 | function err_message_quietly(msg, f) { 2 | $.layer({ 3 | title : false, 4 | closeBtn : false, 5 | time : 2, 6 | dialog : { 7 | msg : msg 8 | }, 9 | end : f 10 | }); 11 | } 12 | 13 | function ok_message_quietly(msg, f) { 14 | $.layer({ 15 | title : false, 16 | closeBtn : false, 17 | time : 1, 18 | dialog : { 19 | msg : msg, 20 | type : 1 21 | }, 22 | end : f 23 | }); 24 | } 25 | 26 | function my_confirm(msg, btns, yes_func, no_func) { 27 | $.layer({ 28 | shade : [ 0 ], 29 | area : [ 'auto', 'auto' ], 30 | dialog : { 31 | msg : msg, 32 | btns : 2, 33 | type : 4, 34 | btn : btns, 35 | yes : yes_func, 36 | no : no_func 37 | } 38 | }); 39 | } 40 | 41 | function handle_quietly(json, f) { 42 | if (json.msg.length > 0) { 43 | err_message_quietly(json.msg); 44 | } else { 45 | ok_message_quietly("successfully:-)", f); 46 | } 47 | } 48 | 49 | // - business function - 50 | function create_app() { 51 | $.post("/app/create", {"name": $("#name").val(), "team": $("#team").val(), "health": $("#health").val()}, function(json) { 52 | handle_quietly(json, function() { 53 | location.href="/"; 54 | }) 55 | }); 56 | } 57 | 58 | function del_app(app_id) { 59 | my_confirm('确定要删除???', ['确定', '取消'], function () { 60 | $.getJSON('/app/delete/' + app_id, {}, function (json) { 61 | handle_quietly(json, function() { 62 | location.reload(); 63 | }); 64 | }); 65 | }, function () { 66 | return false; 67 | }); 68 | } 69 | 70 | function add_env(app_id) { 71 | $.post("/env/add", {"k": $("#k").val(), "v": $("#v").val(), "app_id": $("#app_id").val()}, function(json) { 72 | handle_quietly(json, function() { 73 | location.reload(); 74 | }) 75 | }); 76 | } 77 | 78 | function del_env(env_id) { 79 | $.post("/env/delete", {"id": env_id}, function(json) { 80 | handle_quietly(json, function() { 81 | location.reload(); 82 | }) 83 | }); 84 | } 85 | 86 | function create_domain() { 87 | $.post("/domain/create", {"domain": $("#domain").val(), "team": $("#team").val()}, function(json) { 88 | handle_quietly(json, function() { 89 | location.href="/domain"; 90 | }) 91 | }); 92 | } 93 | 94 | function delete_domain(id) { 95 | $.post("/domain/delete/" + id, {}, function(json) { 96 | handle_quietly(json, function() { 97 | location.reload(); 98 | }) 99 | }); 100 | } 101 | 102 | function scale() { 103 | $.post("/app/scale/" + $("#app_id").val(), {"instance": $("#instance").val()}, function(json) { 104 | handle_quietly(json, function() { 105 | location.href = "/"; 106 | }) 107 | }); 108 | } 109 | 110 | function edit_app() { 111 | $.post("/app/edit/" + $("#app_id").val(), {"team": $("#team").val(), "health": $("#health").val()}, function(json) { 112 | handle_quietly(json, function() { 113 | location.href = "/"; 114 | }) 115 | }); 116 | } 117 | 118 | function edit_domain() { 119 | $.post("/domain/edit/" + $("#domain_id").val(), {"team": $("#team").val()}, function(json) { 120 | handle_quietly(json, function() { 121 | location.href = "/domain"; 122 | }) 123 | }); 124 | } 125 | 126 | function bind_app() { 127 | $.post("/domain/bind/" + $("#domain_id").val(), {"app_id": $("#app_id").val()}, function(json) { 128 | handle_quietly(json, function() { 129 | location.href = "/domain"; 130 | }) 131 | }); 132 | } 133 | 134 | function del_history(id) { 135 | $.post("/history/delete/" + id, {}, function(json) { 136 | handle_quietly(json, function() { 137 | location.reload(); 138 | }); 139 | }); 140 | } 141 | 142 | function deploy_app() { 143 | $.post("/app/deploy/" + $("#app_id").val(), { 144 | "memory": $("#memory").val(), 145 | "instance": $("#instance").val(), 146 | "resume": $("#resume").val(), 147 | "image": $("#image").val() 148 | }, function(json) { 149 | if (json.msg.length > 0) { 150 | err_message_quietly(json.msg); 151 | } else { 152 | ok_message_quietly("successfully:-) 后台正在努力部署...", function() { 153 | location.href="/app/instance/" + $("#app_id").val(); 154 | }); 155 | } 156 | }); 157 | } 158 | 159 | -------------------------------------------------------------------------------- /web/layer/extend/layer.ext.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | @Name: layer拓展类,依赖于layer 4 | @Date: 2014.08.13 5 | @Author: 贤心 6 | @Versions:1.8.5-ext 7 | @Api:http://sentsin.com/jquery/layer 8 | @Desc: 本拓展会持续更新 9 | 10 | */ 11 | 12 | layer.use("skin/layer.ext.css",function(){layer.ext&&layer.ext()}),layer.prompt=function(a,b,c){var d={},a=a||{},e={area:["auto","auto"],offset:[a.top||"",""],title:a.title||"信息",dialog:{btns:2,type:-1,msg:'',yes:function(c){var e=d.prompt.val();""===e?d.prompt.focus():e.replace(/\s/g,"").length>(a.length||1e3)?layer.tips("最多输入"+(a.length||1e3)+"个字数","#xubox_prompt",2):b&&b(e,c,d.prompt)},no:c},success:function(){d.prompt=$("#xubox_prompt"),d.prompt.focus()}};return 3===a.type&&(e.dialog.msg='"),$.layer(e)},layer.tab=function(a){var a=a||{},c=a.data||[],d={type:1,border:[0],area:["auto","auto"],bgcolor:"",title:!1,shade:a.shade,offset:a.offset,move:".xubox_tabmove",closeBtn:!1,page:{html:'
'}()+''+'
'+function(){var a=c.length,b=1,d="";if(a>0)for(d=''+c[0].title+"";a>b;b++)d+=""+c[b].title+"";return d}()+"
"+'
    '+function(){var a=c.length,b=1,d="";if(a>0)for(d='
  • '+(c[0].content||"content未传入")+"
  • ";a>b;b++)d+='
  • '+(c[b].content||"content未传入")+"
  • ";return d}()+"
"+'X'+"
"},success:function(a){var b=$(".xubox_tabtit").children(),c=$(".xubox_tab_main").children(),d=$(".xubox_tabclose");b.on("click",function(){var a=$(this),b=a.index();a.addClass("xubox_tabnow").siblings().removeClass("xubox_tabnow"),c.eq(b).show().siblings().hide()}),d.on("click",function(){layer.close(a.attr("times"))})}};return $.layer(d)},layer.photos=function(a){var b,c,d,e,f,g,h,i;if(a=a||{},b={imgIndex:1,end:null,html:$("html")},c=$(window),d=a.json,e=a.page,d){if(f=d.data,1!==d.status)return layer.msg("未请求到数据",2,8),void 0;if(b.imgLen=f.length,!(f.length>0))return layer.msg("没有任何图片",2,8),void 0;b.thissrc=f[d.start].src,b.pid=f[d.start].pid,b.imgsname=d.title||"",b.name=f[d.start].name,b.imgIndex=d.start+1}else g=$(e.parent).find("img"),h=g.eq(e.start),b.thissrc=h.attr("layer-img")||h.attr("src"),b.pid=h.attr("pid"),b.imgLen=g.length,b.imgsname=e.title||"",b.name=h.attr("alt"),b.imgIndex=e.start+1;return i={type:1,border:[0],area:[(a.html?915:600)+"px","auto"],title:!1,shade:[.9,"#000",!0],shadeClose:!0,offset:["25px",""],bgcolor:"",page:{html:'
'+(b.name||
'+function(){return b.imgLen>1?'':""}()+'
'+b.imgsname+" "+b.imgIndex+"/"+b.imgLen+"
"+function(){return a.html?'
'+a.html+"
":""}()},success:function(a){b.bigimg=a.find(".xubox_bigimg"),b.imgsee=b.bigimg.find(".xubox_imgsee"),b.imgbar=b.imgsee.find(".xubox_imgbar"),b.imgtit=b.imgbar.find(".xubox_imgtit"),b.layero=a;var c=b.imgs=b.bigimg.find("img");clearTimeout(b.timerr),b.timerr=setTimeout(function(){$("html").css("overflow","hidden").attr("layer-full",b.index)},10),c.load(function(){b.imgarea=[c.outerWidth(),c.outerHeight()],b.resize(a)}),b.event()},end:function(){layer.closeAll(),b.end=!0}},b.event=function(){b.bigimg.hover(function(){b.imgsee.show()},function(){b.imgsee.hide()}),i.imgprev=function(){b.imgIndex--,b.imgIndex<1&&(b.imgIndex=b.imgLen),b.tabimg()},b.bigimg.find(".xubox_prev").on("click",function(a){a.preventDefault(),i.imgprev()}),i.imgnext=function(){b.imgIndex++,b.imgIndex>b.imgLen&&(b.imgIndex=1),b.tabimg()},b.bigimg.find(".xubox_next").on("click",function(a){a.preventDefault(),i.imgnext()}),$(document).keyup(function(a){if(!b.end){var c=a.keyCode;a.preventDefault(),37===c?i.imgprev():39===c?i.imgnext():27===c&&layer.close(b.index)}}),b.tabimg=function(){var e,h,i,j,k;b.imgs.removeAttr("style"),d?(j=f[b.imgIndex-1],e=j.src,h=j.pid,i=j.name):(k=g.eq(b.imgIndex-1),e=k.attr("layer-img")||k.attr("src"),h=k.attr("layer-pid")||"",i=k.attr("alt")||""),b.imgs.attr({src:e,"layer-pid":h,alt:i}),b.imgtit.find("em").text(b.imgIndex+"/"+b.imgLen),b.imgsee.show(),a.tab&&a.tab({pid:h,name:i})}},b.resize=function(d){var g,e={},f=[c.width(),c.height()];e.limit=f[0]-f[0]/f[1]*(60*f[0]/f[1]),e.limit<600&&(e.limit=600),g=[e.limit,f[1]>400?f[1]-50:400],g[0]=a.html?g[0]:g[0]-300,layer.area(b.index,{width:g[0]+(a.html?15:0),height:g[1]}),e.flwidth=g[0]-(a.html?300:0),b.imgarea[0]>e.flwidth?b.imgs.css({width:e.flwidth}):b.imgs.css({width:b.imgarea[0]}),b.imgs.outerHeight() ts = UicApi.myTeams(me.getId()); 26 | List tids = new ArrayList(); 27 | if (ts != null && ts.size() > 0) { 28 | for (Team t : ts) { 29 | tids.add(t.getId()); 30 | } 31 | } 32 | 33 | List ds = Domain.mine(me.getId(), tids); 34 | setAttr("ds", ds); 35 | 36 | setAttr("title", "Domains"); 37 | render("index.html"); 38 | } 39 | 40 | public void create() { 41 | if (getRequest().getMethod().equalsIgnoreCase("GET")) { 42 | createGet(); 43 | } else { 44 | createPost(); 45 | } 46 | } 47 | 48 | private void createGet() { 49 | User me = getAttr("me"); 50 | List teams = UicApi.myTeams(me.getId()); 51 | setAttr("ts", teams); 52 | setAttr("uic", Config.uicExternal); 53 | setAttr("title", "create app"); 54 | render("create.html"); 55 | } 56 | 57 | private void createPost() { 58 | String domain = getPara("domain", ""); 59 | if (StringKit.isBlank(domain)) { 60 | throw new RenderJsonMsgException("parameter domain is blank"); 61 | } 62 | 63 | Domain dObj = Domain.dao.findByName(domain); 64 | if (dObj != null) { 65 | throw new RenderJsonMsgException("domain has already existent. creator: " + dObj.getStr("creator_name")); 66 | } 67 | 68 | if (!Checker.isDomain(domain)) { 69 | throw new RenderJsonMsgException("domain format error"); 70 | } 71 | 72 | int tid = 0; 73 | String tname = ""; 74 | String team_id_name = getPara("team", ""); 75 | if (StringKit.isNotBlank(team_id_name)) { 76 | int index = team_id_name.indexOf("-"); 77 | if (index < 0) { 78 | throw new RenderJsonMsgException("parameter team is invalid"); 79 | } 80 | 81 | String team_id = team_id_name.substring(0, index); 82 | tname = team_id_name.substring(index+1); 83 | tid = Integer.parseInt(team_id); 84 | } 85 | 86 | User me = getAttr("me"); 87 | if (!Domain.save(domain, tid, tname, me)) { 88 | throw new RenderJsonMsgException("create domain fail"); 89 | } 90 | 91 | renderJson(); 92 | } 93 | 94 | @Before(DomainFromUrlInterceptor.class) 95 | public void edit() { 96 | if (getRequest().getMethod().equalsIgnoreCase("GET")) { 97 | editGet(); 98 | } else { 99 | editPost(); 100 | } 101 | } 102 | 103 | private void editGet() { 104 | Domain domain = getAttr("domain"); 105 | User me = getAttr("me"); 106 | 107 | List teams = UicApi.myTeams(me.getId()); 108 | setAttr("ts", teams); 109 | setAttr("uic", Config.uicExternal); 110 | setAttr("d", domain); 111 | render("edit.html"); 112 | } 113 | 114 | private void editPost() { 115 | Domain domain = getAttr("domain"); 116 | 117 | int tid = 0; 118 | String tname = ""; 119 | String team_id_name = getPara("team", ""); 120 | if (StringKit.isNotBlank(team_id_name)) { 121 | int index = team_id_name.indexOf("-"); 122 | if (index < 0) { 123 | throw new RenderJsonMsgException("parameter team is invalid"); 124 | } 125 | 126 | String team_id = team_id_name.substring(0, index); 127 | tname = team_id_name.substring(index+1); 128 | tid = Integer.parseInt(team_id); 129 | } 130 | 131 | if (!domain.updateTeam(tid, tname)) { 132 | throw new RenderJsonMsgException("update team fail"); 133 | } 134 | 135 | renderJson(); 136 | } 137 | 138 | @Before(DomainFromUrlInterceptor.class) 139 | public void bind() { 140 | if (getRequest().getMethod().equalsIgnoreCase("GET")) { 141 | bindGet(); 142 | } else { 143 | bindPost(); 144 | } 145 | } 146 | 147 | private void bindGet() { 148 | Domain domain = getAttr("domain"); 149 | setAttr("d", domain); 150 | 151 | User me = getAttr("me"); 152 | List ts = UicApi.myTeams(me.getId()); 153 | List tids = new ArrayList(); 154 | if (ts != null && ts.size() > 0) { 155 | for (Team t : ts) { 156 | tids.add(t.getId()); 157 | } 158 | } 159 | 160 | List apps = App.mine(me.getId(), tids); 161 | setAttr("apps", apps); 162 | render("bind.html"); 163 | } 164 | 165 | private void bindPost() { 166 | Domain d = getAttr("domain"); 167 | 168 | long appId = getParaToInt("app_id", 0); 169 | if (appId < 1) { 170 | throw new RenderJsonMsgException("parameter app_id is invalid"); 171 | } 172 | 173 | App app = App.dao.findById(appId); 174 | if (app == null) { 175 | throw new RenderJsonMsgException("no such app"); 176 | } 177 | 178 | User me = getAttr("me"); 179 | 180 | d.set("app_id", appId); 181 | d.set("app_name", app.getStr("name")); 182 | d.set("bind_user_id", me.getId()); 183 | 184 | if (!d.update()) { 185 | throw new RenderJsonMsgException("occur unknown error"); 186 | } 187 | 188 | renderJson(); 189 | } 190 | 191 | @Before(DomainFromUrlInterceptor.class) 192 | public void delete() { 193 | Domain d = getAttr("domain"); 194 | 195 | if (!d.delete()) { 196 | throw new RenderJsonMsgException("occur unknown error"); 197 | } 198 | 199 | renderJson(); 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /web/js/md5.js: -------------------------------------------------------------------------------- 1 | /* 2 | CryptoJS v3.1.2 3 | code.google.com/p/crypto-js 4 | (c) 2009-2013 by Jeff Mott. All rights reserved. 5 | code.google.com/p/crypto-js/wiki/License 6 | */ 7 | var CryptoJS=CryptoJS||function(s,p){var m={},l=m.lib={},n=function(){},r=l.Base={extend:function(b){n.prototype=this;var h=new n;b&&h.mixIn(b);h.hasOwnProperty("init")||(h.init=function(){h.$super.init.apply(this,arguments)});h.init.prototype=h;h.$super=this;return h},create:function(){var b=this.extend();b.init.apply(b,arguments);return b},init:function(){},mixIn:function(b){for(var h in b)b.hasOwnProperty(h)&&(this[h]=b[h]);b.hasOwnProperty("toString")&&(this.toString=b.toString)},clone:function(){return this.init.prototype.extend(this)}}, 8 | q=l.WordArray=r.extend({init:function(b,h){b=this.words=b||[];this.sigBytes=h!=p?h:4*b.length},toString:function(b){return(b||t).stringify(this)},concat:function(b){var h=this.words,a=b.words,j=this.sigBytes;b=b.sigBytes;this.clamp();if(j%4)for(var g=0;g>>2]|=(a[g>>>2]>>>24-8*(g%4)&255)<<24-8*((j+g)%4);else if(65535>>2]=a[g>>>2];else h.push.apply(h,a);this.sigBytes+=b;return this},clamp:function(){var b=this.words,h=this.sigBytes;b[h>>>2]&=4294967295<< 9 | 32-8*(h%4);b.length=s.ceil(h/4)},clone:function(){var b=r.clone.call(this);b.words=this.words.slice(0);return b},random:function(b){for(var h=[],a=0;a>>2]>>>24-8*(j%4)&255;g.push((k>>>4).toString(16));g.push((k&15).toString(16))}return g.join("")},parse:function(b){for(var a=b.length,g=[],j=0;j>>3]|=parseInt(b.substr(j, 10 | 2),16)<<24-4*(j%8);return new q.init(g,a/2)}},a=v.Latin1={stringify:function(b){var a=b.words;b=b.sigBytes;for(var g=[],j=0;j>>2]>>>24-8*(j%4)&255));return g.join("")},parse:function(b){for(var a=b.length,g=[],j=0;j>>2]|=(b.charCodeAt(j)&255)<<24-8*(j%4);return new q.init(g,a)}},u=v.Utf8={stringify:function(b){try{return decodeURIComponent(escape(a.stringify(b)))}catch(g){throw Error("Malformed UTF-8 data");}},parse:function(b){return a.parse(unescape(encodeURIComponent(b)))}}, 11 | g=l.BufferedBlockAlgorithm=r.extend({reset:function(){this._data=new q.init;this._nDataBytes=0},_append:function(b){"string"==typeof b&&(b=u.parse(b));this._data.concat(b);this._nDataBytes+=b.sigBytes},_process:function(b){var a=this._data,g=a.words,j=a.sigBytes,k=this.blockSize,m=j/(4*k),m=b?s.ceil(m):s.max((m|0)-this._minBufferSize,0);b=m*k;j=s.min(4*b,j);if(b){for(var l=0;l>>32-j)+k}function m(a,k,b,h,l,j,m){a=a+(k&h|b&~h)+l+m;return(a<>>32-j)+k}function l(a,k,b,h,l,j,m){a=a+(k^b^h)+l+m;return(a<>>32-j)+k}function n(a,k,b,h,l,j,m){a=a+(b^(k|~h))+l+m;return(a<>>32-j)+k}for(var r=CryptoJS,q=r.lib,v=q.WordArray,t=q.Hasher,q=r.algo,a=[],u=0;64>u;u++)a[u]=4294967296*s.abs(s.sin(u+1))|0;q=q.MD5=t.extend({_doReset:function(){this._hash=new v.init([1732584193,4023233417,2562383102,271733878])}, 15 | _doProcessBlock:function(g,k){for(var b=0;16>b;b++){var h=k+b,w=g[h];g[h]=(w<<8|w>>>24)&16711935|(w<<24|w>>>8)&4278255360}var b=this._hash.words,h=g[k+0],w=g[k+1],j=g[k+2],q=g[k+3],r=g[k+4],s=g[k+5],t=g[k+6],u=g[k+7],v=g[k+8],x=g[k+9],y=g[k+10],z=g[k+11],A=g[k+12],B=g[k+13],C=g[k+14],D=g[k+15],c=b[0],d=b[1],e=b[2],f=b[3],c=p(c,d,e,f,h,7,a[0]),f=p(f,c,d,e,w,12,a[1]),e=p(e,f,c,d,j,17,a[2]),d=p(d,e,f,c,q,22,a[3]),c=p(c,d,e,f,r,7,a[4]),f=p(f,c,d,e,s,12,a[5]),e=p(e,f,c,d,t,17,a[6]),d=p(d,e,f,c,u,22,a[7]), 16 | c=p(c,d,e,f,v,7,a[8]),f=p(f,c,d,e,x,12,a[9]),e=p(e,f,c,d,y,17,a[10]),d=p(d,e,f,c,z,22,a[11]),c=p(c,d,e,f,A,7,a[12]),f=p(f,c,d,e,B,12,a[13]),e=p(e,f,c,d,C,17,a[14]),d=p(d,e,f,c,D,22,a[15]),c=m(c,d,e,f,w,5,a[16]),f=m(f,c,d,e,t,9,a[17]),e=m(e,f,c,d,z,14,a[18]),d=m(d,e,f,c,h,20,a[19]),c=m(c,d,e,f,s,5,a[20]),f=m(f,c,d,e,y,9,a[21]),e=m(e,f,c,d,D,14,a[22]),d=m(d,e,f,c,r,20,a[23]),c=m(c,d,e,f,x,5,a[24]),f=m(f,c,d,e,C,9,a[25]),e=m(e,f,c,d,q,14,a[26]),d=m(d,e,f,c,v,20,a[27]),c=m(c,d,e,f,B,5,a[28]),f=m(f,c, 17 | d,e,j,9,a[29]),e=m(e,f,c,d,u,14,a[30]),d=m(d,e,f,c,A,20,a[31]),c=l(c,d,e,f,s,4,a[32]),f=l(f,c,d,e,v,11,a[33]),e=l(e,f,c,d,z,16,a[34]),d=l(d,e,f,c,C,23,a[35]),c=l(c,d,e,f,w,4,a[36]),f=l(f,c,d,e,r,11,a[37]),e=l(e,f,c,d,u,16,a[38]),d=l(d,e,f,c,y,23,a[39]),c=l(c,d,e,f,B,4,a[40]),f=l(f,c,d,e,h,11,a[41]),e=l(e,f,c,d,q,16,a[42]),d=l(d,e,f,c,t,23,a[43]),c=l(c,d,e,f,x,4,a[44]),f=l(f,c,d,e,A,11,a[45]),e=l(e,f,c,d,D,16,a[46]),d=l(d,e,f,c,j,23,a[47]),c=n(c,d,e,f,h,6,a[48]),f=n(f,c,d,e,u,10,a[49]),e=n(e,f,c,d, 18 | C,15,a[50]),d=n(d,e,f,c,s,21,a[51]),c=n(c,d,e,f,A,6,a[52]),f=n(f,c,d,e,q,10,a[53]),e=n(e,f,c,d,y,15,a[54]),d=n(d,e,f,c,w,21,a[55]),c=n(c,d,e,f,v,6,a[56]),f=n(f,c,d,e,D,10,a[57]),e=n(e,f,c,d,t,15,a[58]),d=n(d,e,f,c,B,21,a[59]),c=n(c,d,e,f,r,6,a[60]),f=n(f,c,d,e,z,10,a[61]),e=n(e,f,c,d,j,15,a[62]),d=n(d,e,f,c,x,21,a[63]);b[0]=b[0]+c|0;b[1]=b[1]+d|0;b[2]=b[2]+e|0;b[3]=b[3]+f|0},_doFinalize:function(){var a=this._data,k=a.words,b=8*this._nDataBytes,h=8*a.sigBytes;k[h>>>5]|=128<<24-h%32;var l=s.floor(b/ 19 | 4294967296);k[(h+64>>>9<<4)+15]=(l<<8|l>>>24)&16711935|(l<<24|l>>>8)&4278255360;k[(h+64>>>9<<4)+14]=(b<<8|b>>>24)&16711935|(b<<24|b>>>8)&4278255360;a.sigBytes=4*(k.length+1);this._process();a=this._hash;k=a.words;for(b=0;4>b;b++)h=k[b],k[b]=(h<<8|h>>>24)&16711935|(h<<24|h>>>8)&4278255360;return a},clone:function(){var a=t.clone.call(this);a._hash=this._hash.clone();return a}});r.MD5=t._createHelper(q);r.HmacMD5=t._createHmacHelper(q)})(Math); 20 | -------------------------------------------------------------------------------- /src/com/ulricqin/dash/controller/AppController.java: -------------------------------------------------------------------------------- 1 | package com.ulricqin.dash.controller; 2 | 3 | import java.util.List; 4 | 5 | import com.jfinal.aop.Before; 6 | import com.jfinal.core.Controller; 7 | import com.ulricqin.dash.api.UicApi; 8 | import com.ulricqin.dash.config.Config; 9 | import com.ulricqin.dash.interceptor.AppFromUrlInterceptor; 10 | import com.ulricqin.dash.interceptor.LoginRequiredInterceptor; 11 | import com.ulricqin.dash.model.App; 12 | import com.ulricqin.dash.model.Domain; 13 | import com.ulricqin.dash.model.Env; 14 | import com.ulricqin.dash.model.History; 15 | import com.ulricqin.dash.model.Team; 16 | import com.ulricqin.dash.model.User; 17 | import com.ulricqin.frame.exception.RenderJsonMsgException; 18 | import com.ulricqin.frame.kit.Checker; 19 | import com.ulricqin.frame.kit.StringKit; 20 | 21 | @Before(LoginRequiredInterceptor.class) 22 | public class AppController extends Controller { 23 | 24 | public void create() { 25 | if (getRequest().getMethod().equalsIgnoreCase("GET")) { 26 | createGet(); 27 | } else { 28 | createPost(); 29 | } 30 | } 31 | 32 | private void createGet() { 33 | User me = getAttr("me"); 34 | List teams = UicApi.myTeams(me.getId()); 35 | setAttr("ts", teams); 36 | setAttr("uic", Config.uicExternal); 37 | setAttr("paasDomain", Config.paasDomain); 38 | setAttr("title", "create app"); 39 | render("create.html"); 40 | } 41 | 42 | private void createPost() { 43 | String health = getPara("health", "").trim(); 44 | if (StringKit.isNotBlank(health) && !health.startsWith("/")) { 45 | throw new RenderJsonMsgException("health must starts with: /"); 46 | } 47 | 48 | String name = getPara("name", ""); 49 | if (StringKit.isBlank(name)) { 50 | throw new RenderJsonMsgException("parameter name is blank"); 51 | } 52 | 53 | if (!Checker.isIdentifier(name)) { 54 | throw new RenderJsonMsgException("name should be an identifier: a-zA-Z0-9-_"); 55 | } 56 | 57 | int tid = 0; 58 | String tname = ""; 59 | String team_id_name = getPara("team", ""); 60 | if (StringKit.isNotBlank(team_id_name)) { 61 | int index = team_id_name.indexOf("-"); 62 | if (index < 0) { 63 | throw new RenderJsonMsgException("parameter team is invalid"); 64 | } 65 | 66 | String team_id = team_id_name.substring(0, index); 67 | tname = team_id_name.substring(index+1); 68 | tid = Integer.parseInt(team_id); 69 | } 70 | 71 | User me = getAttr("me"); 72 | if (!App.save(name, tid, tname, me.getId(), health)) { 73 | throw new RenderJsonMsgException("create app fail"); 74 | } 75 | 76 | renderJson(); 77 | } 78 | 79 | @Before(AppFromUrlInterceptor.class) 80 | public void delete() { 81 | App app = getAttr("app"); 82 | 83 | User me = getAttr("me"); 84 | if (!app.delete(me)) { 85 | throw new RenderJsonMsgException("delete app fail"); 86 | } 87 | 88 | renderJson(); 89 | } 90 | 91 | @Before(AppFromUrlInterceptor.class) 92 | public void env() { 93 | App app = getAttr("app"); 94 | 95 | List envs = Env.dao.findByAppId(app.getLong("id")); 96 | setAttr("envs", envs); 97 | setAttr("app", app); 98 | render("env.html"); 99 | } 100 | 101 | @Before(AppFromUrlInterceptor.class) 102 | public void domain() { 103 | App app = getAttr("app"); 104 | 105 | List domains = Domain.dao.findByAppId(app.getLong("id")); 106 | setAttr("domains", domains); 107 | setAttr("app", app); 108 | render("domain.html"); 109 | } 110 | 111 | @Before(AppFromUrlInterceptor.class) 112 | public void scale() { 113 | if (getRequest().getMethod().equalsIgnoreCase("GET")) { 114 | scaleGet(); 115 | } else { 116 | scalePost(); 117 | } 118 | } 119 | 120 | private void scalePost() { 121 | App app = getAttr("app"); 122 | 123 | int instance = getParaToInt("instance", 0); 124 | if (!app.scale(instance)) { 125 | throw new RenderJsonMsgException("occur unknown error"); 126 | } 127 | 128 | renderJson(); 129 | } 130 | 131 | private void scaleGet() { 132 | App app = getAttr("app"); 133 | setAttr("app", app); 134 | render("scale.html"); 135 | } 136 | 137 | @Before(AppFromUrlInterceptor.class) 138 | public void edit() { 139 | if (getRequest().getMethod().equalsIgnoreCase("GET")) { 140 | editGet(); 141 | } else { 142 | editPost(); 143 | } 144 | } 145 | 146 | private void editPost() { 147 | App app = getAttr("app"); 148 | String health = getPara("health", "").trim(); 149 | if (StringKit.isNotBlank(health) && !health.startsWith("/")) { 150 | throw new RenderJsonMsgException("health must starts with: /"); 151 | } 152 | 153 | int tid = 0; 154 | String tname = ""; 155 | String team_id_name = getPara("team", ""); 156 | if (StringKit.isNotBlank(team_id_name)) { 157 | int index = team_id_name.indexOf("-"); 158 | if (index < 0) { 159 | throw new RenderJsonMsgException("parameter team is invalid"); 160 | } 161 | 162 | String team_id = team_id_name.substring(0, index); 163 | tname = team_id_name.substring(index+1); 164 | tid = Integer.parseInt(team_id); 165 | } 166 | 167 | if (!app.updateProfile(tid, tname, health)) { 168 | throw new RenderJsonMsgException("update team fail"); 169 | } 170 | 171 | renderJson(); 172 | } 173 | 174 | private void editGet() { 175 | App app = getAttr("app"); 176 | User me = getAttr("me"); 177 | 178 | List teams = UicApi.myTeams(me.getId()); 179 | setAttr("ts", teams); 180 | setAttr("uic", Config.uicExternal); 181 | setAttr("app", app); 182 | render("edit.html"); 183 | } 184 | 185 | @Before(AppFromUrlInterceptor.class) 186 | public void history() { 187 | App app = getAttr("app"); 188 | 189 | List list = History.getByAppId(app.getLong("id")); 190 | setAttr("list", list); 191 | setAttr("app", app); 192 | setAttr("title", "build history"); 193 | render("history.html"); 194 | } 195 | 196 | @Before(AppFromUrlInterceptor.class) 197 | public void instance() { 198 | App app = getAttr("app"); 199 | setAttr("app", app); 200 | setAttr("paasDomain", Config.paasDomain); 201 | setAttr("title", "instances"); 202 | render("instance.html"); 203 | } 204 | 205 | @Before(AppFromUrlInterceptor.class) 206 | public void deploy() { 207 | if (getRequest().getMethod().equalsIgnoreCase("GET")) { 208 | deployGet(); 209 | } else { 210 | deployPost(); 211 | } 212 | } 213 | 214 | private void deployGet() { 215 | App app = getAttr("app"); 216 | setAttr("app", app); 217 | 218 | int historyId = getParaToInt("history", 0); 219 | if (historyId > 0) { 220 | setAttr("history", History.dao.findById(historyId)); 221 | } 222 | 223 | setAttr("builder", Config.builder); 224 | setAttr("title", "deploy"); 225 | render("deploy.html"); 226 | } 227 | 228 | private void deployPost() { 229 | App app = getAttr("app"); 230 | int memory = getParaToInt("memory", 0); 231 | if (memory < 128 || memory > 10240) { 232 | throw new RenderJsonMsgException("memory should >=128 or <= 10240"); 233 | } 234 | 235 | int instance = getParaToInt("instance", 0); 236 | String image = getPara("image", ""); 237 | if (StringKit.isBlank(image)) { 238 | throw new RenderJsonMsgException("image is blank"); 239 | } 240 | 241 | String resume = getPara("resume", ""); 242 | if (!app.deploy(memory, instance, image, resume)) { 243 | throw new RenderJsonMsgException("occur unknown error"); 244 | } 245 | 246 | renderJson(); 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /web/css/select2-bootstrap.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Select2 Bootstrap CSS 3 | * Compatible with Select2 3.3.2, 3.4.1, 3.4.2 and Twitter Bootstrap 3.0.0 4 | * MIT License 5 | */ 6 | /** 7 | * Reset Bootstrap 3 .form-control styles which - if applied to the 8 | * original