├── .gitignore ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src ├── main └── resources │ └── services │ ├── configuration │ ├── application-env.xml │ └── application-site.xml │ ├── metainfo.xml │ └── package │ ├── lib │ └── README.md │ ├── scripts │ ├── master.py │ ├── params.py │ └── status_params.py │ └── templates │ └── application.properties.j2 └── test └── resources └── org └── gradle └── test-resource.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | 14 | .gradle 15 | build/ 16 | 17 | # Ignore Gradle GUI config 18 | gradle-app.setting 19 | 20 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 21 | !gradle-wrapper.jar 22 | 23 | *.pydevproject 24 | .metadata 25 | .gradle 26 | bin/ 27 | tmp/ 28 | *.tmp 29 | *.bak 30 | *.swp 31 | *~.nib 32 | local.properties 33 | .settings/ 34 | .loadpath 35 | 36 | # Eclipse Core 37 | .project 38 | 39 | # External tool builders 40 | .externalToolBuilders/ 41 | 42 | # Locally stored "Eclipse launch configurations" 43 | *.launch 44 | 45 | # CDT-specific 46 | .cproject 47 | 48 | # JDT-specific (Eclipse Java Development Tools) 49 | .classpath 50 | 51 | # Java annotation processor (APT) 52 | .factorypath 53 | 54 | # PDT-specific 55 | .buildpath 56 | 57 | # sbteclipse plugin 58 | .target 59 | 60 | # TeXlipse plugin 61 | .texlipse 62 | 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Create Ambari Services from Spring Boot Applications 2 | 3 | Toolkit to bundle any [Spring Boot](http://projects.spring.io/spring-boot) application into an [Ambari Service](https://ambari.apache.org/). This allows Ambari to provision, manage and monitor the target spring boot applications, providing blueprint automation and versioned configuration management. 4 | 5 | To use the toolkit, copy the target spring boot application jar into the `lib` directory, set the name and the version of the generated Ambari Service and define the application properties to be managed by Ambari. Next the springboot-ambari-service toolkit generates an Ambari Service and RPMs to install it in the Ambari Server. Once installed you can use the Ambari Wizard or the Blueprint API to deploy the spring boot app as a native Ambari Service. 6 | 7 | [zeppelin-view](https://www.youtube.com/watch?v=gA95yC8QIJI) 8 | The [sample video](https://www.youtube.com/watch?v=gA95yC8QIJI) illustrates the toolkit capabilities. It shows how to build install and use Ambari Service from Spring Boot application. 9 | 10 | 11 | ### Quick Start 12 | Follow the instructions to bundle a Spring Boot application into an Ambari Service: 13 | 14 | 1) (Re)build your Spring Boot application using Spring Boot 1.3+ (e.g [1.3.0.M5](http://docs.spring.io/spring-boot/docs/1.3.0.M5/reference/htmlsingle/#getting-started-installation-instructions-for-java) or [1.3.0.BUILD-SNAPSHOT](http://docs.spring.io/spring-boot/docs/1.3.0.BUILD-SNAPSHOT/reference/htmlsingle/#getting-started-installation-instructions-for-java)) and enable the [maven/gradle plugin executable configuration](http://docs.spring.io/spring-boot/docs/1.3.0.BUILD-SNAPSHOT/reference/htmlsingle/#deployment-install) to produce [fully executable jar](http://docs.spring.io/spring-boot/docs/1.3.0.M5/reference/htmlsingle/#deployment-install). 15 | 16 | 2) Clone the [springboot-ambari-service](https://github.com/tzolov/springboot-ambari-service) project 17 | ``` 18 | git clone https://github.com/tzolov/springboot-ambari-service.git 19 | ``` 20 | 21 | 3) Copy the spring boot application jar (build in step 1) into the `src/main/resources/services/package/lib` folder. 22 | 23 | 4) Edit the `build.gradle` file and set the `applicationName`, `ambariServicerVersion` and `displayName` properties. 24 | 25 | 5) Edit the `src/main/resources/services/configuration/application-site.xml` to set all application and system properties to be exposed (e.g. the `applicaton.properties` entires) 26 | 27 | 6) Build the springboot-ambari-service RPMs. The springboot-ambari-service does all the plumbing 28 | ``` 29 | ./gradlew clean dist 30 | ``` 31 | 32 | 7) Copy the appropriate rpm (-phd30, -hdp22 or -hdp23) from `build/distribution` to the Ambari server node. 33 | ``` 34 | scp build/distributions/springboot-app-ambari-service-phd30-0.0.10-1.noarch.rpm 35 | ambari@ambari.server.node: 36 | ``` 37 | 38 | 8) On the Ambari node Install the rpm plugin and restart the Ambari server: 39 | ``` 40 | sudo yum -y install ./springboot-app-ambari-service-phd30-0.0.10-1.noarch.rpm 41 | sudo /etc/init.d/ambari-server restart 42 | ``` 43 | ### More info 44 | Blog entry: [How to bundle a Spring Boot application into an Apache Ambari managed service](http://blog.tzolov.net/2015/10/how-to-bundle-spring-boot-application.html) 45 | 46 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | import com.sun.org.apache.xerces.internal.parsers.XMLParser; 2 | 3 | // ---------------------------------------------------------------------------- 4 | // User Definitions 5 | // ---------------------------------------------------------------------------- 6 | 7 | // Unique Ambari Service name for the spring-boot application 8 | def applicationName = "springboot-app" 9 | 10 | // Ambari Service version for the spring-boot application 11 | def ambariServiceVersion = '0.0.10' 12 | 13 | // Ambari Service Component display name 14 | def displayName = "SpringBoot App" 15 | 16 | // (optional) Provide spring boot application description 17 | def applicationDescription = "Spring Boot Web Application" 18 | 19 | // (optional) Create a specific user/group account to run the spring-boot application 20 | def applicationUserName = "springboot" 21 | def applicationGroupName = "springboot" 22 | 23 | // (optional) Rpm/Deb package name and description 24 | def ambariPackageName = applicationName.replace("_", "-").replace(".", "-") + "-ambari-service" 25 | def ambariPackageDescription = applicationDescription + " Service for Apache Ambari" 26 | 27 | // Bintray credentials. 28 | def bintrayUserEnvVariable = 'BINTRAY_BIGDATA_USER' 29 | def bintrayKeyEnvVariable = 'BINTRAY_BIGDATA_KEY' 30 | 31 | // ---------------------------------------------------------------------------- 32 | // System Definitions. Usually you don't need to modify this section 33 | // ---------------------------------------------------------------------------- 34 | def springBootApplicationJarName = extractSpringBootApplicationJarName() 35 | def ambariServiceName = applicationName.replace(' ', '').replace(".", "_").replace("-", "_").toUpperCase() 36 | 37 | buildscript { 38 | repositories { 39 | mavenCentral() 40 | jcenter() 41 | } 42 | 43 | dependencies { 44 | classpath 'com.netflix.nebula:gradle-ospackage-plugin:2.2.6' 45 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2' 46 | } 47 | } 48 | 49 | apply plugin: 'java' 50 | apply plugin: 'os-package' 51 | apply plugin: 'rpm' 52 | apply plugin: 'distribution' 53 | apply plugin: 'com.jfrog.bintray' 54 | 55 | buildDeb.enabled = false 56 | buildRpm.enabled = false 57 | 58 | ospackage { 59 | version = ambariServiceVersion 60 | release = 1 61 | arch = NOARCH 62 | os = LINUX 63 | user 'root' 64 | permissionGroup = 'root' 65 | packageDescription = ambariPackageDescription 66 | packageGroup = 'Applications/Databases' 67 | license = 'Apache License v2.0' 68 | 69 | requires('ambari-server', '1.7', GREATER | EQUAL) 70 | requires('python', '2.6', GREATER | EQUAL) 71 | } 72 | 73 | bintray { 74 | user = System.getenv(bintrayUserEnvVariable) 75 | key = System.getenv(bintrayKeyEnvVariable) 76 | 77 | dryRun = false 78 | 79 | filesSpec { 80 | from ('build/distributions') { include '**/*.rpm' } 81 | into ambariPackageName 82 | } 83 | 84 | pkg { 85 | repo = 'rpm' 86 | name = ambariPackageName 87 | desc = ambariPackageDescription 88 | licenses = ['Apache-2.0'] 89 | vcsUrl = 'https://github.com/tzolov/' 90 | labels = [ 91 | 'SpringBoot', 92 | 'Ambari', 93 | 'Hadoop' 94 | ] 95 | publicDownloadNumbers = true 96 | version { 97 | name = ospackage.version + '-' + ospackage.release.toString() 98 | desc = ambariPackageDescription 99 | } 100 | } 101 | } 102 | 103 | def extractSpringBootApplicationJarName() { 104 | 105 | def jarFiles = file('src/main/resources/services/package/lib').listFiles({d, f-> f ==~ /.*.jar/ } as FilenameFilter) 106 | 107 | if (jarFiles.length == 0) { 108 | throw new RuntimeException("Copy the target spring boot application JAR file to the lib directory!") 109 | } 110 | 111 | if (jarFiles.length > 1) { 112 | throw new RuntimeException("Only one JAR file is permitted in the lib directory!") 113 | } 114 | 115 | if (jarFiles.length != 1) { 116 | throw new RuntimeException("Excactly one SpringBoot Jar file is expected in Lib!") 117 | } 118 | String jarFileName = jarFiles[0].getName() 119 | println("Spring Boot Jar File: " + jarFileName) 120 | return jarFileName 121 | } 122 | 123 | // Use the user defined properties to initialize the Ambari service files 124 | processResources { 125 | 126 | filesMatching('services/metainfo.xml') { 127 | filter { 128 | it.replace('@SERVICE_VERSION@', ambariServiceVersion) 129 | .replace('@SERVICE_NAME@', ambariServiceName) 130 | .replace('@SERVICE_DISPLAY_NAME@', applicationDescription) 131 | .replace('@COMPONENT_DISPLAY_NAME@', displayName) 132 | .replace('@SERVICE_DESCRIPTION@', applicationDescription) 133 | .replace('@CONFIGURATION_PREFFIX@', applicationName.replace(' ', '')) 134 | } 135 | } 136 | 137 | filesMatching('services/configuration/application-env.xml') { 138 | filter { 139 | it.replace('@APPLICATION_USER_NAME@', applicationUserName.toLowerCase()) 140 | .replace('@APPLICATION_GROUP_NAME@', applicationGroupName.toLowerCase()) 141 | } 142 | } 143 | 144 | filesMatching('services/package/scripts/params.py') { 145 | filter { 146 | it.replace('@APPLICATION_JAR_NAME@', springBootApplicationJarName) 147 | } 148 | } 149 | 150 | filesMatching('services/package/scripts/status_params.py') { 151 | filter { 152 | it.replace('@APPLICATION_NAME@', applicationName.replace(' ', '').toLowerCase()) 153 | } 154 | } 155 | 156 | // Rename the configuration files to make them unique accross the other services in Ambari 157 | // application-env.xml -> -env.xml 158 | rename { String fileName -> 159 | fileName.replace('application-env', applicationName + '-env') 160 | } 161 | 162 | // application-site.xml -> -site.xml 163 | rename { String fileName -> 164 | fileName.replace('application-site', applicationName + '-site') 165 | } 166 | } 167 | 168 | task phd30Rpm(type: Rpm) { 169 | packageName = ambariPackageName + '-phd30' 170 | from('build/resources/main/services') { into '/var/lib/ambari-server/resources/stacks/PHD/3.0/services/' + ambariServiceName } 171 | } 172 | 173 | task hdp22Rpm(type: Rpm) { 174 | packageName = ambariPackageName + '-hdp22' 175 | from('build/resources/main/services') { into '/var/lib/ambari-server/resources/stacks/HDP/2.2/services/' + ambariServiceName } 176 | } 177 | 178 | task hdp23Rpm(type: Rpm) { 179 | packageName = ambariPackageName + '-hdp23' 180 | from('build/resources/main/services') { into '/var/lib/ambari-server/resources/stacks/HDP/2.3/services/' + ambariServiceName } 181 | } 182 | 183 | task distTgz(type: Tar) { 184 | baseName = ambariPackageName + '-' + ospackage.version + '-' + ospackage.release.toString() 185 | compression = Compression.GZIP 186 | from { 'build/resources/main/services' } 187 | } 188 | 189 | task dist { 190 | dependsOn build, phd30Rpm, hdp22Rpm, hdp23Rpm, distTgz 191 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tzolov/springboot-ambari-service/a57c5d77672fe9a52823c9f012ec7e41605ed244/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Sep 24 20:52:16 CEST 2015 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-2.5-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 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 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /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 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 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 Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src/main/resources/services/configuration/application-env.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | install_dir 9 | /opt 10 | Local directory where to install the application. 11 | 12 | 13 | 14 | user 15 | @APPLICATION_USER_NAME@ 16 | User that the application runs as 17 | 18 | 19 | 20 | group 21 | @APPLICATION_GROUP_NAME@ 22 | Group that the application runs as 23 | 24 | 25 | 26 | pid_dir 27 | /var/run 28 | Directory containing process ID file 29 | 30 | 31 | 32 | log_dir 33 | /var/log 34 | Application log directory 35 | 36 | 37 | 38 | java_opts 39 | -Xmx1024m -XX:MaxPermSize=128M 40 | Spring Boot java options 41 | 42 | 43 | 46 | 47 | spring_boot_config_content 48 | Spring Boot init.d configuration file 49 | 50 | MODE=service 51 | SPRING_CONFIG_NAME={{application_properties_path}} 52 | PID_FOLDER={{pid_dir}} 53 | LOG_FOLDER={{log_dir}} 54 | RUN_ARGS="--logging.file={{log_file}} --spring.pidfile={{pid_dir}}/{{application_name}}/{{application_name}}.pid" 55 | JAVA_OPTS={{java_opts}} 56 | JAVA_HOME={{java64_home}} 57 | DEBUG=true 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/main/resources/services/configuration/application-site.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | server.port 19 | 8082 20 | Port the rest server is running on. Default value: 8082. 21 | 22 | 23 | 24 | security.user.password 25 | changeme 26 | Web server password 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/main/resources/services/metainfo.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 2.0 4 | 5 | 6 | @SERVICE_NAME@ 7 | @SERVICE_DISPLAY_NAME@ 8 | @SERVICE_DESCRIPTION@ 9 | @SERVICE_VERSION@ 10 | 11 | 12 | @SERVICE_NAME@ 13 | @COMPONENT_DISPLAY_NAME@ 14 | MASTER 15 | 1 16 | 17 | 18 | PYTHON 19 | 10000 20 | 21 | 22 | 23 | 24 | 25 | redhat7,redhat6,suse11 26 | 27 | 28 | wget 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | false 37 | 38 | @CONFIGURATION_PREFFIX@-site 39 | @CONFIGURATION_PREFFIX@-env 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/main/resources/services/package/lib/README.md: -------------------------------------------------------------------------------- 1 | # Your Spring Boot Application Jar 2 | 3 | The `lib` folder contains the target application jar to be wrapped as Ambari Service. Exactly one jar file can contained! 4 | 5 | Current version of the `springboot-ambari-service` leverages the Spring Boot 1.3+ feature to make fully executable applications for Unix systems (Linux, OSX, FreeBSD etc). Therefore the application jat has to be (re)build with Spring Boot 1.3+ or newer (e.g [1.3.0.M5](http://docs.spring.io/spring-boot/docs/1.3.0.M5/reference/htmlsingle/#getting-started-installation-instructions-for-java) or [1.3.0.BUILD-SNAPSHOT](http://docs.spring.io/spring-boot/docs/1.3.0.BUILD-SNAPSHOT/reference/htmlsingle/#getting-started-installation-instructions-for-java)). Also the build configuration must set the [maven/gradle plugin executable configuration](http://docs.spring.io/spring-boot/docs/1.3.0.M5/reference/htmlsingle/#deployment-install) to generate fully executable jars. 6 | 7 | -------------------------------------------------------------------------------- /src/main/resources/services/package/scripts/master.py: -------------------------------------------------------------------------------- 1 | """ 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | """ 16 | import sys, os, pwd, grp, signal, time, glob 17 | from resource_management import * 18 | from subprocess import call 19 | 20 | """ 21 | The Spring Boot application has to be complied with SpringBoot 1.3+ to leverage the Linux init.d support: http://bit.ly/1WMBHC5 22 | - On installation the spring boot application jar is linked as an init.d service enabling the start/stop/status/restart init.d operations 23 | - The execution environment is configured through a application-env.xml. It follows the customizing the startup script instructions: http://bit.ly/1MYUvcM 24 | - The application is configured through the application-site.xml file. All properties defined in the application-site.xml are converted into application.properties key/value entries. 25 | """ 26 | class Master(Script): 27 | 28 | def install(self, env): 29 | import params 30 | env.set_params(params) 31 | 32 | # Install the osSpecifics binary packages 33 | self.install_packages(env) 34 | 35 | # Create spring boot application user and group (if they don't exist) 36 | try: grp.getgrnam(params.group) 37 | except KeyError: Execute(format('groupadd {group}')) 38 | 39 | try: pwd.getpwnam(params.user) 40 | except KeyError: Execute(format('adduser {user} -g {group}')) 41 | 42 | # Create the log dir if it not already present 43 | Directory([os.path.join(params.pid_dir, params.application_name), params.log_dir, params.install_dir], 44 | owner=params.user, 45 | group=params.group, 46 | recursive=True) 47 | 48 | # Initialize the log file 49 | File(params.log_file, owner=params.user, group=params.group) 50 | 51 | # Fetch application jar build, if no cached 52 | if not os.path.exists(params.install_jar_path): 53 | # Move the spring boot application executable jar into the target install dir 54 | Execute(format('cp {application_jar_path} {install_jar_path} >> {log_file}'), 55 | user=params.user, 56 | group=params.group) 57 | # Make the jar executable so to used it as a Linux service. 58 | # http://docs.spring.io/spring-boot/docs/1.3.0.M5/reference/htmlsingle/#deployment-service 59 | Execute(format('chmod a+x {install_jar_path}'), user=params.user) 60 | # Make spring boot application jar a /etc/init.d service 61 | Link(format('/etc/init.d/{application_name}'), to=params.install_jar_path) 62 | 63 | # Update the configs specified by user 64 | self.configure(env) 65 | 66 | def configure(self, env): 67 | import params 68 | import status_params 69 | env.set_params(params) 70 | env.set_params(status_params) 71 | 72 | # Generate SpringBoot applicaiton.properties file. Fill in the properties form form the 73 | # -application-site.xml 74 | File(params.application_properties_path, 75 | content=Template("application.properties.j2", configurations=params.application_site), 76 | owner=params.user, 77 | group=params.group) 78 | 79 | # Create application SpringBoot configuration file: 80 | # http://docs.spring.io/spring-boot/docs/1.3.0.M5/reference/htmlsingle/#deployment-script-customization 81 | File(status_params.spring_boot_config_path, 82 | content=InlineTemplate(status_params.spring_boot_config_content), 83 | owner=params.user, 84 | group=params.group) 85 | 86 | def start(self, env): 87 | import params 88 | env.set_params(params) 89 | 90 | # Update the configs specified by user 91 | self.configure(env) 92 | 93 | # Service(params.application_name, action="start") 94 | Execute (format('/etc/init.d/{application_name} start'), 95 | user=params.user, 96 | group=params.group, 97 | logoutput=True, 98 | timeout=300) 99 | 100 | def stop(self, env): 101 | import params 102 | env.set_params(params) 103 | 104 | Execute(format('kill -9 + $(cat {pid_file} ) >> {log_file}'), user=params.user) 105 | 106 | def status(self, env): 107 | import status_params 108 | env.set_params(status_params) 109 | check_process_status(status_params.pid_file) 110 | 111 | if __name__ == "__main__": 112 | Master().execute() 113 | -------------------------------------------------------------------------------- /src/main/resources/services/package/scripts/params.py: -------------------------------------------------------------------------------- 1 | """ 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | """ 16 | import sys, os 17 | import status_params 18 | from resource_management import * 19 | from resource_management.libraries.script.script import Script 20 | from resource_management.libraries.functions.default import default 21 | 22 | # server configurations 23 | config = Script.get_config() 24 | 25 | ############################################################################### 26 | # User Space 27 | ############################################################################### 28 | 29 | # Add your properties here 30 | 31 | ############################################################################### 32 | # Do not modify the properties in the section below! 33 | ############################################################################### 34 | 35 | # Mirror the Spring Boot environment settings 36 | application_name = status_params.application_name 37 | user = status_params.user.lower() 38 | group = status_params.group.lower() 39 | pid_dir = status_params.pid_dir 40 | pid_file = status_params.pid_file 41 | log_dir = status_params.log_dir 42 | log_file = status_params.log_file 43 | install_dir = status_params.install_dir 44 | install_jar_path = status_params.install_jar_path 45 | 46 | # The absolute path of the target application.properties file 47 | application_properties_path = os.path.join(install_dir, 'application.properties') 48 | 49 | # Absolute path of the spring boot application jar file before it is moved to the install 50 | application_jar_path = os.path.join(os.path.dirname(__file__), '..', 'lib', '@APPLICATION_JAR_NAME@') 51 | 52 | application_site = default("/configurations/" + application_name + "-site", None) 53 | #application_site = config['configurations'][application_name + '-site'] 54 | 55 | # ambari_host = str(config['clusterHostInfo']['ambari_server_host'][0]) 56 | -------------------------------------------------------------------------------- /src/main/resources/services/package/scripts/status_params.py: -------------------------------------------------------------------------------- 1 | """ 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | """ 16 | from resource_management import * 17 | import sys, os 18 | 19 | config = Script.get_config() 20 | 21 | application_name = '@APPLICATION_NAME@' 22 | 23 | app_env = config['configurations'][application_name + '-env'] 24 | 25 | user = app_env['user'] 26 | group = app_env['group'] 27 | 28 | pid_dir = app_env['pid_dir'] 29 | pid_file = os.path.join(pid_dir, application_name, application_name + '.pid') 30 | 31 | java64_home = config['hostLevelParams']['java_home'] 32 | java_opts = app_env['java_opts'] 33 | 34 | log_dir = os.path.join(app_env['log_dir'], application_name) 35 | log_file = os.path.join(log_dir, application_name + '-setup.log') 36 | 37 | # Application specific properties 38 | install_dir = os.path.join(app_env['install_dir'], application_name) 39 | install_jar_path = os.path.join(*[install_dir, application_name + '.jar']) 40 | 41 | spring_boot_config_content = app_env['spring_boot_config_content'] 42 | spring_boot_config_path = os.path.join(install_dir, application_name + '.conf') 43 | -------------------------------------------------------------------------------- /src/main/resources/services/package/templates/application.properties.j2: -------------------------------------------------------------------------------- 1 | {# 2 | # Licensed to the Apache Software Foundation (ASF) under one 3 | # or more contributor license agreements. See the NOTICE file 4 | # distributed with this work for additional information 5 | # regarding copyright ownership. The ASF licenses this file 6 | # to you under the Apache License, Version 2.0 (the 7 | # "License"); you may not use this file except in compliance 8 | # with the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | #} 18 | 19 | # Licensed to the Apache Software Foundation (ASF) under one or more 20 | # contributor license agreements. See the NOTICE file distributed with 21 | # this work for additional information regarding copyright ownership. 22 | # The ASF licenses this file to You under the Apache License, Version 2.0 23 | # (the "License"); you may not use this file except in compliance with 24 | # the License. You may obtain a copy of the License at 25 | # 26 | # http://www.apache.org/licenses/LICENSE-2.0 27 | # 28 | # Unless required by applicable law or agreed to in writing, software 29 | # distributed under the License is distributed on an "AS IS" BASIS, 30 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 31 | # See the License for the specific language governing permissions and 32 | # limitations under the License. 33 | 34 | {% for key, value in configurations|dictsort if value|length > 1 %} 35 | {{key}}={{ value }} 36 | {% endfor %} -------------------------------------------------------------------------------- /src/test/resources/org/gradle/test-resource.xml: -------------------------------------------------------------------------------- 1 | 2 | --------------------------------------------------------------------------------