├── entrypoint ├── .dockerignore ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── Dockerfile ├── settings.gradle ├── build.gradle ├── gradlew.bat ├── .gitignore ├── src │ └── main │ │ ├── resources │ │ └── templates │ │ │ └── index.html │ │ └── java │ │ └── net │ │ └── coding │ │ └── Server.java └── gradlew ├── .env ├── deploy.sh ├── webhooks └── dockerhub │ ├── index.js │ ├── deploy_frontend.sh │ └── deploy_backend.sh ├── .gitignore ├── docker-compose.yml └── nginx_templates └── nginx.tmpl /entrypoint/.dockerignore: -------------------------------------------------------------------------------- 1 | ** 2 | !build/libs/entrypoint-fat.jar -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | COMPOSE_PROJECT_NAME=webide 2 | DOCKERHUB_TOKEN=140f7b40-2013-11e7-993e-830e4ab33491 3 | WEBIDE_CI_DOMAIN=localhost 4 | -------------------------------------------------------------------------------- /entrypoint/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding/WebIDE-CI/master/entrypoint/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | cd entrypoint 3 | ./gradlew clean shadowJar 4 | 5 | cd .. 6 | docker-compose build 7 | docker-compose up -d 8 | -------------------------------------------------------------------------------- /webhooks/dockerhub/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | 'webide/frontend': 'deploy_frontend.sh', 5 | 'webide/backend': 'deploy_backend.sh' 6 | } 7 | -------------------------------------------------------------------------------- /webhooks/dockerhub/deploy_frontend.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | docker rm -f frontend-$DOCKER_HUB_TAG 3 | docker run -d \ 4 | --name frontend-$DOCKER_HUB_TAG \ 5 | -e VIRTUAL_HOST=frontend-${DOCKER_HUB_TAG}.ide-ci.codelife.me \ 6 | -e VIRTUAL_PORT=80 \ 7 | webide/frontend:$DOCKER_HUB_TAG 8 | -------------------------------------------------------------------------------- /entrypoint/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Apr 16 18:34:18 CST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-all.zip 7 | -------------------------------------------------------------------------------- /webhooks/dockerhub/deploy_backend.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | docker rm -f backend-$DOCKER_HUB_TAG 3 | docker run -d \ 4 | --name backend-$DOCKER_HUB_TAG \ 5 | -e VIRTUAL_HOST=backend-${DOCKER_HUB_TAG}.ide-ci.codelife.me \ 6 | -e VIRTUAL_PORT=8080 \ 7 | -e ALLOWED_ORIGINS=* \ 8 | -v coding-ide-home:/root/.coding-ide \ 9 | webide/backend:$DOCKER_HUB_TAG 10 | -------------------------------------------------------------------------------- /entrypoint/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jre-alpine 2 | 3 | ENV VERTICLE_FILE entrypoint-fat.jar 4 | 5 | # Set the location of the verticles 6 | ENV VERTICLE_HOME /usr/verticles 7 | 8 | EXPOSE 8080 9 | 10 | # Copy your fat jar to the container 11 | COPY build/libs/$VERTICLE_FILE $VERTICLE_HOME/ 12 | 13 | # Launch the verticle 14 | WORKDIR $VERTICLE_HOME 15 | ENTRYPOINT ["sh", "-c"] 16 | CMD ["exec java -jar $VERTICLE_FILE"] -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### macOS template 2 | *.DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | 6 | # Icon must end with two \r 7 | Icon 8 | 9 | 10 | # Thumbnails 11 | ._* 12 | 13 | # Files that might appear in the root of a volume 14 | .DocumentRevisions-V100 15 | .fseventsd 16 | .Spotlight-V100 17 | .TemporaryItems 18 | .Trashes 19 | .VolumeIcon.icns 20 | .com.apple.timemachine.donotpresent 21 | 22 | # Directories potentially created on remote AFP share 23 | .AppleDB 24 | .AppleDesktop 25 | Network Trash Folder 26 | Temporary Items 27 | .apdisk 28 | -------------------------------------------------------------------------------- /entrypoint/settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This settings file was generated by the Gradle 'init' task. 3 | * 4 | * The settings file is used to specify which projects to include in your build. 5 | * In a single project build this file can be empty or even removed. 6 | * 7 | * Detailed information about configuring a multi-project build in Gradle can be found 8 | * in the user guide at https://docs.gradle.org/3.5/userguide/multi_project_builds.html 9 | */ 10 | 11 | /* 12 | // To declare projects as part of a multi-project build use the 'include' method 13 | include 'shared' 14 | include 'api' 15 | include 'services:webservice' 16 | */ 17 | 18 | rootProject.name = 'entrypoint' 19 | -------------------------------------------------------------------------------- /entrypoint/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'} 4 | } 5 | } 6 | 7 | plugins { 8 | id 'java' 9 | id 'application' 10 | id 'com.github.johnrengelman.shadow' version '1.2.4' 11 | } 12 | 13 | sourceCompatibility = '1.8' 14 | mainClassName = 'io.vertx.core.Launcher' 15 | 16 | ext { 17 | vertx_version = '3.4.1' 18 | mainVerticleName = 'net.coding.Server' 19 | } 20 | 21 | 22 | repositories { 23 | maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'} 24 | } 25 | 26 | dependencies { 27 | compile "io.vertx:vertx-core:$vertx_version" 28 | compile "io.vertx:vertx-rx-java:$vertx_version" 29 | compile "io.vertx:vertx-web:$vertx_version" 30 | compile "io.vertx:vertx-web-client:$vertx_version" 31 | compile "io.vertx:vertx-web-templ-thymeleaf:$vertx_version" 32 | compile "ch.qos.logback:logback-classic:1.2.3" 33 | 34 | testCompile 'junit:junit:4.11' 35 | } 36 | 37 | shadowJar { 38 | classifier = 'fat' 39 | manifest { 40 | attributes 'Main-Verticle': mainVerticleName 41 | } 42 | mergeServiceFiles { 43 | include 'META-INF/services/io.vertx.core.spi.VerticleFactory' 44 | } 45 | } 46 | 47 | run { 48 | args = ['run', mainVerticleName, "--redeploy=src/**/*.java", "--launcher-class=$mainClassName", "--on-redeploy='./gradlew classes'"] 49 | } 50 | 51 | 52 | task wrapper(type: Wrapper) { 53 | gradleVersion = '3.5' 54 | } 55 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | dockerhub-webook: 5 | image: vangie/dockerhub-webhook 6 | container_name: ci-dockerhub-webhook 7 | network_mode: bridge 8 | volumes: 9 | - /var/run/docker.sock:/var/run/docker.sock:ro 10 | - ./webhooks/dockerhub:/src/scripts 11 | environment: 12 | - TOKEN=${DOCKERHUB_TOKEN} 13 | - VIRTUAL_HOST=dockerhub-webhook.${WEBIDE_CI_DOMAIN} 14 | restart: always 15 | 16 | nginx: 17 | image: nginx:alpine 18 | container_name: ci-nginx 19 | network_mode: bridge 20 | ports: 21 | - "81:80" 22 | labels: 23 | - "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=true" 24 | volumes: 25 | - nginx_conf:/etc/nginx/conf.d 26 | - nginx_vhost:/etc/nginx/vhost.d 27 | - nginx_certs:/etc/nginx/certs:ro 28 | - nginx_webdir:/usr/share/nginx/html 29 | restart: always 30 | 31 | nginx-gen: 32 | image: jwilder/docker-gen 33 | container_name: ci-nginx-gen 34 | network_mode: bridge 35 | volumes: 36 | - /var/run/docker.sock:/tmp/docker.sock:ro 37 | - ./nginx_templates:/etc/docker-gen/templates:ro 38 | - nginx_conf:/etc/nginx/conf.d 39 | - nginx_certs:/etc/nginx/certs:ro 40 | command: >- 41 | -notify-sighup ci-nginx 42 | -watch -wait 5s:30s 43 | /etc/docker-gen/templates/nginx.tmpl 44 | /etc/nginx/conf.d/default.conf 45 | restart: always 46 | 47 | nginx-letsencrypt: 48 | image: jrcs/letsencrypt-nginx-proxy-companion 49 | container_name: ci-nginx-letsencrypt 50 | environment: 51 | - "NGINX_DOCKER_GEN_CONTAINER=ci-nginx-gen" 52 | volumes: 53 | - nginx_vhost:/etc/nginx/vhost.d 54 | - nginx_certs:/etc/nginx/certs 55 | - nginx_webdir:/usr/share/nginx/html 56 | - /var/run/docker.sock:/var/run/docker.sock:ro 57 | restart: always 58 | 59 | entrypoint: 60 | build: ./entrypoint 61 | image: webide/ci-entrypoint 62 | container_name: ci-entrypoint 63 | network_mode: bridge 64 | environment: 65 | - VIRTUAL_HOST=${WEBIDE_CI_DOMAIN} 66 | restart: always 67 | 68 | volumes: 69 | nginx_conf: 70 | nginx_vhost: 71 | nginx_certs: 72 | nginx_webdir: 73 | -------------------------------------------------------------------------------- /entrypoint/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /entrypoint/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### macOS template 3 | *.DS_Store 4 | .AppleDouble 5 | .LSOverride 6 | 7 | # Icon must end with two \r 8 | Icon 9 | 10 | 11 | # Thumbnails 12 | ._* 13 | 14 | # Files that might appear in the root of a volume 15 | .DocumentRevisions-V100 16 | .fseventsd 17 | .Spotlight-V100 18 | .TemporaryItems 19 | .Trashes 20 | .VolumeIcon.icns 21 | .com.apple.timemachine.donotpresent 22 | 23 | # Directories potentially created on remote AFP share 24 | .AppleDB 25 | .AppleDesktop 26 | Network Trash Folder 27 | Temporary Items 28 | .apdisk 29 | ### Java template 30 | # Compiled class file 31 | *.class 32 | 33 | # Log file 34 | *.log 35 | 36 | # BlueJ files 37 | *.ctxt 38 | 39 | # Mobile Tools for Java (J2ME) 40 | .mtj.tmp/ 41 | 42 | # Package Files # 43 | *.jar 44 | *.war 45 | *.ear 46 | *.zip 47 | *.tar.gz 48 | *.rar 49 | 50 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 51 | hs_err_pid* 52 | ### Gradle template 53 | .gradle 54 | /build/ 55 | 56 | # Ignore Gradle GUI config 57 | gradle-app.setting 58 | 59 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 60 | !gradle-wrapper.jar 61 | 62 | # Cache of project 63 | .gradletasknamecache 64 | 65 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 66 | # gradle/wrapper/gradle-wrapper.properties 67 | ### macOS template 68 | *.DS_Store 69 | .AppleDouble 70 | .LSOverride 71 | 72 | # Icon must end with two \r 73 | Icon 74 | 75 | 76 | # Thumbnails 77 | ._* 78 | 79 | # Files that might appear in the root of a volume 80 | .DocumentRevisions-V100 81 | .fseventsd 82 | .Spotlight-V100 83 | .TemporaryItems 84 | .Trashes 85 | .VolumeIcon.icns 86 | .com.apple.timemachine.donotpresent 87 | 88 | # Directories potentially created on remote AFP share 89 | .AppleDB 90 | .AppleDesktop 91 | Network Trash Folder 92 | Temporary Items 93 | .apdisk 94 | ### Java template 95 | # Compiled class file 96 | *.class 97 | 98 | # Log file 99 | *.log 100 | 101 | # BlueJ files 102 | *.ctxt 103 | 104 | # Mobile Tools for Java (J2ME) 105 | .mtj.tmp/ 106 | 107 | # Package Files # 108 | *.jar 109 | *.war 110 | *.ear 111 | *.zip 112 | *.tar.gz 113 | *.rar 114 | 115 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 116 | hs_err_pid* 117 | ### Gradle template 118 | .gradle 119 | /build/ 120 | 121 | # Ignore Gradle GUI config 122 | gradle-app.setting 123 | 124 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 125 | !gradle-wrapper.jar 126 | 127 | # Cache of project 128 | .gradletasknamecache 129 | 130 | ### JetBrains 131 | 132 | .idea/ 133 | 134 | # IntelliJ 135 | /out/ 136 | 137 | # mpeltonen/sbt-idea plugin 138 | .idea_modules/ 139 | 140 | 141 | .vertx 142 | -------------------------------------------------------------------------------- /entrypoint/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WebIDE-CI 5 | 6 | 7 | 8 | 18 | 19 | 20 |
21 | 22 | 23 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 62 | 63 | 64 |
Pull RequestsUpdated at
54 | 55 | rewrite Tab and DragAndDrop module with mobx 56 | 57 | 2017-04-13T10:24:15Z 60 | Open 61 |
65 | 66 |
67 | 68 | 69 | 70 | 71 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /entrypoint/src/main/java/net/coding/Server.java: -------------------------------------------------------------------------------- 1 | package net.coding; 2 | 3 | /** 4 | * Created by vangie on 2017/4/16. 5 | */ 6 | 7 | import io.vertx.core.json.JsonObject; 8 | import io.vertx.ext.web.client.WebClientOptions; 9 | import io.vertx.rxjava.core.AbstractVerticle; 10 | import io.vertx.rxjava.core.Vertx; 11 | import io.vertx.rxjava.ext.web.Cookie; 12 | import io.vertx.rxjava.ext.web.Router; 13 | import io.vertx.rxjava.ext.web.RoutingContext; 14 | import io.vertx.rxjava.ext.web.client.WebClient; 15 | import io.vertx.rxjava.ext.web.codec.BodyCodec; 16 | import io.vertx.rxjava.ext.web.handler.CookieHandler; 17 | import io.vertx.rxjava.ext.web.handler.StaticHandler; 18 | import io.vertx.rxjava.ext.web.templ.ThymeleafTemplateEngine; 19 | import rx.Observable; 20 | import rx.Subscriber; 21 | 22 | import java.util.AbstractMap.SimpleEntry; 23 | import java.util.Map; 24 | import java.util.concurrent.ConcurrentHashMap; 25 | 26 | public class Server extends AbstractVerticle { 27 | 28 | private final Map pullMap = new ConcurrentHashMap<>(); 29 | 30 | final ThymeleafTemplateEngine engine = ThymeleafTemplateEngine.create(); 31 | 32 | public void start() { 33 | vertx.createHttpServer() 34 | .requestHandler(router(vertx)::accept) 35 | .listen(8080); 36 | vertx.setPeriodic(1000 * 60 * 5, timerID -> updatePR()); 37 | updatePR(); 38 | } 39 | 40 | private Router router(Vertx vertx) { 41 | Router router = Router.router(vertx); 42 | router.route().handler(CookieHandler.create()); 43 | router.get("/").handler(this::index); 44 | router.get("/:owner/:repo/pull/:id").handler(this::deployment); 45 | router.route().handler(StaticHandler.create()); 46 | return router; 47 | } 48 | 49 | private void index(RoutingContext ctx) { 50 | 51 | ctx.put("pullMap", pullMap); 52 | 53 | engine.render(ctx, "templates/index.html", res -> { 54 | if (res.succeeded()) { 55 | ctx.response().end(res.result()); 56 | } else { 57 | ctx.fail(res.cause()); 58 | } 59 | }); 60 | 61 | 62 | } 63 | 64 | private WebClient client() { 65 | WebClientOptions options = new WebClientOptions() 66 | .setDefaultHost("api.github.com") 67 | .setDefaultPort(443) 68 | .setSsl(true) 69 | .setMaxPoolSize(1) 70 | .setKeepAlive(false); 71 | 72 | return WebClient.create(vertx, options); 73 | } 74 | 75 | private void updatePR() { 76 | Observable.merge( 77 | pullRequests("Coding", "WebIDE-Frontend"), 78 | pullRequests("Coding", "WebIDE-Backend") 79 | ) 80 | .map(e -> 81 | new SimpleEntry<>(e.getString("html_url").substring("https://github.com/".length()), e) 82 | ) 83 | .subscribe(new Subscriber>() { 84 | @Override 85 | public void onCompleted() {} 86 | 87 | @Override 88 | public void onError(Throwable e) { 89 | e.printStackTrace(); 90 | } 91 | 92 | @Override 93 | public void onNext(SimpleEntry e) { 94 | pullMap.put(e.getKey(), e.getValue()); 95 | } 96 | 97 | @Override 98 | public void onStart() { 99 | pullMap.clear(); 100 | } 101 | }); 102 | } 103 | 104 | private Observable pullRequests(String owner, String repo) { 105 | return client().get(String.format("/repos/%s/%s/pulls", owner, repo)) 106 | .addQueryParam("state", "open") 107 | .addQueryParam("sort", "updated") 108 | .addQueryParam("direction", "desc") 109 | .as(BodyCodec.jsonArray()) 110 | .rxSend() 111 | .map(res -> res.body()) 112 | .flatMapObservable(jsonArray -> Observable.from(jsonArray)) 113 | .map(obj -> (JsonObject) obj); 114 | } 115 | 116 | private void deployment(RoutingContext ctx) { 117 | String owner = ctx.request().getParam("owner"); 118 | String repo = ctx.request().getParam("repo"); 119 | String id = ctx.request().getParam("id"); 120 | String scheme = ctx.request().scheme(); 121 | String host = ctx.request().host(); 122 | 123 | JsonObject pull = pullMap.get(String.format("%s/%s/pull/%s", owner, repo, id)); 124 | 125 | String revision = "latest"; 126 | 127 | if (repo.equals("WebIDE-Frontend")) { 128 | revision = revision(pull); 129 | } 130 | 131 | String url = formatUrl(scheme, "frontend", revision, host); 132 | 133 | revision = "latest"; 134 | if (repo.equals("WebIDE-Backend")) { 135 | revision = revision(pull); 136 | } 137 | Cookie cookie = Cookie.cookie("BACKEND_URL", formatUrl(scheme, "backend", revision, host)); 138 | cookie.setPath("/"); 139 | cookie.setDomain("." + host.replaceAll(":.*", "")); 140 | 141 | ctx.addCookie(cookie) 142 | .response() 143 | .setStatusCode(307) 144 | .putHeader("location", url) 145 | .end(); 146 | 147 | } 148 | 149 | private String revision(JsonObject pull) { 150 | if (pull == null) { 151 | return "latest"; 152 | } 153 | return pull.getJsonObject("head").getString("sha").substring(0, 8); 154 | } 155 | 156 | private String formatUrl(String scheme, String module, String revision, String host) { 157 | return String.format("%s://%s-%s.%s", scheme, module, revision, host); 158 | } 159 | } -------------------------------------------------------------------------------- /entrypoint/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save ( ) { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /nginx_templates/nginx.tmpl: -------------------------------------------------------------------------------- 1 | {{ $CurrentContainer := where $ "ID" .Docker.CurrentContainerID | first }} 2 | 3 | {{ define "upstream" }} 4 | {{ if .Address }} 5 | {{/* If we got the containers from swarm and this container's port is published to host, use host IP:PORT */}} 6 | {{ if and .Container.Node.ID .Address.HostPort }} 7 | # {{ .Container.Node.Name }}/{{ .Container.Name }} 8 | server {{ .Container.Node.Address.IP }}:{{ .Address.HostPort }}; 9 | {{/* If there is no swarm node or the port is not published on host, use container's IP:PORT */}} 10 | {{ else if .Network }} 11 | # {{ .Container.Name }} 12 | server {{ .Network.IP }}:{{ .Address.Port }}; 13 | {{ end }} 14 | {{ else if .Network }} 15 | # {{ .Container.Name }} 16 | server {{ .Network.IP }} down; 17 | {{ end }} 18 | {{ end }} 19 | 20 | # If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the 21 | # scheme used to connect to this server 22 | map $http_x_forwarded_proto $proxy_x_forwarded_proto { 23 | default $http_x_forwarded_proto; 24 | '' $scheme; 25 | } 26 | 27 | # If we receive X-Forwarded-Port, pass it through; otherwise, pass along the 28 | # server port the client connected to 29 | map $http_x_forwarded_port $proxy_x_forwarded_port { 30 | default $http_x_forwarded_port; 31 | '' $server_port; 32 | } 33 | 34 | # If we receive Upgrade, set Connection to "upgrade"; otherwise, delete any 35 | # Connection header that may have been passed to this server 36 | map $http_upgrade $proxy_connection { 37 | default upgrade; 38 | '' close; 39 | } 40 | 41 | # Set appropriate X-Forwarded-Ssl header 42 | map $scheme $proxy_x_forwarded_ssl { 43 | default off; 44 | https on; 45 | } 46 | 47 | gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; 48 | 49 | log_format vhost '$host $remote_addr - $remote_user [$time_local] ' 50 | '"$request" $status $body_bytes_sent ' 51 | '"$http_referer" "$http_user_agent"'; 52 | 53 | access_log off; 54 | 55 | {{ if (exists "/etc/nginx/proxy.conf") }} 56 | include /etc/nginx/proxy.conf; 57 | {{ else }} 58 | # HTTP 1.1 support 59 | proxy_http_version 1.1; 60 | proxy_buffering off; 61 | proxy_set_header Host $http_host; 62 | proxy_set_header Upgrade $http_upgrade; 63 | proxy_set_header Connection $proxy_connection; 64 | proxy_set_header X-Real-IP $remote_addr; 65 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 66 | proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto; 67 | proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl; 68 | proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port; 69 | 70 | # Mitigate httpoxy attack (see README for details) 71 | proxy_set_header Proxy ""; 72 | {{ end }} 73 | 74 | {{ $enable_ipv6 := eq (or ($.Env.ENABLE_IPV6) "") "true" }} 75 | server { 76 | server_name _; # This is just an invalid value which will never trigger on a real hostname. 77 | listen 80; 78 | {{ if $enable_ipv6 }} 79 | listen [::]:80; 80 | {{ end }} 81 | access_log /var/log/nginx/access.log vhost; 82 | return 503; 83 | } 84 | 85 | {{ if (and (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} 86 | server { 87 | server_name _; # This is just an invalid value which will never trigger on a real hostname. 88 | listen 443 ssl http2; 89 | {{ if $enable_ipv6 }} 90 | listen [::]:443 ssl http2; 91 | {{ end }} 92 | access_log /var/log/nginx/access.log vhost; 93 | return 503; 94 | 95 | ssl_session_tickets off; 96 | ssl_certificate /etc/nginx/certs/default.crt; 97 | ssl_certificate_key /etc/nginx/certs/default.key; 98 | } 99 | {{ end }} 100 | 101 | {{ range $host, $containers := groupByMulti $ "Env.VIRTUAL_HOST" "," }} 102 | {{ $is_regexp := hasPrefix "~" $host }} 103 | {{ $upstream_name := when $is_regexp (sha1 $host) $host }} 104 | # {{ $host }} 105 | upstream {{ $upstream_name }} { 106 | {{ range $container := $containers }} 107 | {{ $addrLen := len $container.Addresses }} 108 | 109 | {{ range $knownNetwork := $CurrentContainer.Networks }} 110 | {{ range $containerNetwork := $container.Networks }} 111 | {{ if eq $knownNetwork.Name $containerNetwork.Name }} 112 | ## Can be connect with "{{ $containerNetwork.Name }}" network 113 | 114 | {{/* If only 1 port exposed, use that */}} 115 | {{ if eq $addrLen 1 }} 116 | {{ $address := index $container.Addresses 0 }} 117 | {{ template "upstream" (dict "Container" $container "Address" $address "Network" $containerNetwork) }} 118 | {{/* If more than one port exposed, use the one matching VIRTUAL_PORT env var, falling back to standard web port 80 */}} 119 | {{ else }} 120 | {{ $port := coalesce $container.Env.VIRTUAL_PORT "80" }} 121 | {{ $address := where $container.Addresses "Port" $port | first }} 122 | {{ template "upstream" (dict "Container" $container "Address" $address "Network" $containerNetwork) }} 123 | {{ end }} 124 | {{ end }} 125 | {{ end }} 126 | {{ end }} 127 | {{ end }} 128 | } 129 | 130 | {{ $default_host := or ($.Env.DEFAULT_HOST) "" }} 131 | {{ $default_server := index (dict $host "" $default_host "default_server") $host }} 132 | 133 | {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost, falling back to "http" */}} 134 | {{ $proto := or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http" }} 135 | 136 | {{/* Get the HTTPS_METHOD defined by containers w/ the same vhost, falling back to "redirect" */}} 137 | {{ $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) "redirect" }} 138 | 139 | {{/* Get the first cert name defined by containers w/ the same vhost */}} 140 | {{ $certName := (first (groupByKeys $containers "Env.CERT_NAME")) }} 141 | 142 | {{/* Get the best matching cert by name for the vhost. */}} 143 | {{ $vhostCert := (closest (dir "/etc/nginx/certs") (printf "%s.crt" $host))}} 144 | 145 | {{/* vhostCert is actually a filename so remove any suffixes since they are added later */}} 146 | {{ $vhostCert := trimSuffix ".crt" $vhostCert }} 147 | {{ $vhostCert := trimSuffix ".key" $vhostCert }} 148 | 149 | {{/* Use the cert specified on the container or fallback to the best vhost match */}} 150 | {{ $cert := (coalesce $certName $vhostCert) }} 151 | 152 | {{ $is_https := (and (ne $https_method "nohttps") (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert))) }} 153 | 154 | {{ if $is_https }} 155 | 156 | {{ if eq $https_method "redirect" }} 157 | server { 158 | server_name {{ $host }}; 159 | listen 80 {{ $default_server }}; 160 | {{ if $enable_ipv6 }} 161 | listen [::]:80 {{ $default_server }}; 162 | {{ end }} 163 | access_log /var/log/nginx/access.log vhost; 164 | return 301 https://$host$request_uri; 165 | } 166 | {{ end }} 167 | 168 | server { 169 | server_name {{ $host }}; 170 | listen 443 ssl http2 {{ $default_server }}; 171 | {{ if $enable_ipv6 }} 172 | listen [::]:443 ssl http2 {{ $default_server }}; 173 | {{ end }} 174 | access_log /var/log/nginx/access.log vhost; 175 | 176 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 177 | ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS'; 178 | 179 | ssl_prefer_server_ciphers on; 180 | ssl_session_timeout 5m; 181 | ssl_session_cache shared:SSL:50m; 182 | ssl_session_tickets off; 183 | 184 | ssl_certificate /etc/nginx/certs/{{ (printf "%s.crt" $cert) }}; 185 | ssl_certificate_key /etc/nginx/certs/{{ (printf "%s.key" $cert) }}; 186 | 187 | {{ if (exists (printf "/etc/nginx/certs/%s.dhparam.pem" $cert)) }} 188 | ssl_dhparam {{ printf "/etc/nginx/certs/%s.dhparam.pem" $cert }}; 189 | {{ end }} 190 | 191 | {{ if (ne $https_method "noredirect") }} 192 | add_header Strict-Transport-Security "max-age=31536000"; 193 | {{ end }} 194 | 195 | {{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }} 196 | include {{ printf "/etc/nginx/vhost.d/%s" $host }}; 197 | {{ else if (exists "/etc/nginx/vhost.d/default") }} 198 | include /etc/nginx/vhost.d/default; 199 | {{ end }} 200 | 201 | location / { 202 | {{ if eq $proto "uwsgi" }} 203 | include uwsgi_params; 204 | uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }}; 205 | {{ else }} 206 | proxy_pass {{ trim $proto }}://{{ trim $upstream_name }}; 207 | {{ end }} 208 | {{ if (exists (printf "/etc/nginx/htpasswd/%s" $host)) }} 209 | auth_basic "Restricted {{ $host }}"; 210 | auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" $host) }}; 211 | {{ end }} 212 | {{ if (exists (printf "/etc/nginx/vhost.d/%s_location" $host)) }} 213 | include {{ printf "/etc/nginx/vhost.d/%s_location" $host}}; 214 | {{ else if (exists "/etc/nginx/vhost.d/default_location") }} 215 | include /etc/nginx/vhost.d/default_location; 216 | {{ end }} 217 | } 218 | } 219 | 220 | {{ end }} 221 | 222 | {{ if or (not $is_https) (eq $https_method "noredirect") }} 223 | 224 | server { 225 | server_name {{ $host }}; 226 | listen 80 {{ $default_server }}; 227 | {{ if $enable_ipv6 }} 228 | listen [::]:80 {{ $default_server }}; 229 | {{ end }} 230 | access_log /var/log/nginx/access.log vhost; 231 | 232 | {{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }} 233 | include {{ printf "/etc/nginx/vhost.d/%s" $host }}; 234 | {{ else if (exists "/etc/nginx/vhost.d/default") }} 235 | include /etc/nginx/vhost.d/default; 236 | {{ end }} 237 | 238 | location / { 239 | {{ if eq $proto "uwsgi" }} 240 | include uwsgi_params; 241 | uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }}; 242 | {{ else }} 243 | proxy_pass {{ trim $proto }}://{{ trim $upstream_name }}; 244 | {{ end }} 245 | {{ if (exists (printf "/etc/nginx/htpasswd/%s" $host)) }} 246 | auth_basic "Restricted {{ $host }}"; 247 | auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" $host) }}; 248 | {{ end }} 249 | {{ if (exists (printf "/etc/nginx/vhost.d/%s_location" $host)) }} 250 | include {{ printf "/etc/nginx/vhost.d/%s_location" $host}}; 251 | {{ else if (exists "/etc/nginx/vhost.d/default_location") }} 252 | include /etc/nginx/vhost.d/default_location; 253 | {{ end }} 254 | } 255 | } 256 | 257 | {{ if (and (not $is_https) (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} 258 | server { 259 | server_name {{ $host }}; 260 | listen 443 ssl http2 {{ $default_server }}; 261 | {{ if $enable_ipv6 }} 262 | listen [::]:443 ssl http2 {{ $default_server }}; 263 | {{ end }} 264 | access_log /var/log/nginx/access.log vhost; 265 | return 500; 266 | 267 | ssl_certificate /etc/nginx/certs/default.crt; 268 | ssl_certificate_key /etc/nginx/certs/default.key; 269 | } 270 | {{ end }} 271 | 272 | {{ end }} 273 | {{ end }} 274 | --------------------------------------------------------------------------------