Skip to content

Commit

Permalink
Merge pull request #21 from lenala/jar_deployment
Browse files Browse the repository at this point in the history
Spring Boot Jar deployment
  • Loading branch information
lenala authored Feb 21, 2019
2 parents b6d9975 + a6aa72b commit abba613
Show file tree
Hide file tree
Showing 26 changed files with 1,158 additions and 14 deletions.
59 changes: 46 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
- [Running sample ToDo app](#running-sample-todo-app)
- [Common settings](#common-settings)
- [Web App on Windows](#web-app-on-windows)
- [Deploy WAR](#deploy-war)
- [Deploy JAR](#deploy-jar)
- [Web App on Linux](#web-app-on-linux)
- [Web Apps on Containers](#web-apps-on-containers)
- [Deployment from Private Container Registry (Azure Container Registry)](#deployment-from-private-container-registry-azure-container-registry)
Expand Down Expand Up @@ -73,15 +75,15 @@ gradlew.bat azureWebappDeploy
|stopAppDuringDeployment | false | Specifies whether to stop Web App during deployment. Optional, default is false
| __appService__ | true | Block that specifies AppService settings
| type | true | Type of the AppService, one of {'linux','windows','docker'}
| runtimeStack ||
| runtimeStack | false | Supported are {'TOMCAT 8.5-jre8', 'TOMCAT 9.0-jre8', 'WILDFLY" 14-jre8', 'jre8'}
| javaWebContainer | false | One of WebContainer values, default is TOMCAT_8_5_NEWEST
| javaVersion | |
| imageName |
| startUpFile |
| serverId |
| username |
| password |
| registryUrl |
| javaVersion | false | For App Service on Windows, supported versions are: {1.7, 1.7.0_51, 1.7.0_71, 1.8, 1.8.0_25, 1.8.0_60, 1.8.0_73, 1.8.0_111, 1.8.0_92, 1.8.0_102, 1.8.0_144}
| imageName | false |
| startUpFile | false |
| serverId | false |
| username | false |
| password | false |
| registryUrl | false |
| pricingTier | false | Specifies the pricing tier for your Web App; the default value is S1.
| __authentication__ | true | Bloack that specifies authentication with Azure
| type | | Authentication type, one of {FILE,PROPERTIES,AZURECLI}
Expand All @@ -92,15 +94,18 @@ gradlew.bat azureWebappDeploy
| certificate | |
| certificatePassword;
| __deployment__ | true | Specifies deployment type and configuration
deploymentType | false | Deployment type - one of {FTP, WAR, ZIP, NONE}. Optional, default value is WAR.
target | false | Target artifact to deploy. Not used for Web Apps for containers. Optional, if not specified, default war file output produced by 'war' plugin will be used.
contextPath | | Url path
deploymentType | false | Deployment type - one of {FTP, WAR, JAR, ZIP, NONE}. Optional, default value is WAR.
warFile | false | Target war file to deploy. Not used for Web Apps for containers. Optional, if not specified, default war file output produced by 'war' plugin will be used.
jarFile | false | Target jar file to deploy. Not used for Web Apps for containers. Optional, if not specified, default jar file output produced by 'bootJar' plugin will be used.
contextPath | false | Url path


# 4 types of deployment are supported:
# These types of deployment are supported:

## Web App on Windows

### Deploy WAR

`appService` block should be specified, with the values:

Name | Value
Expand Down Expand Up @@ -134,7 +139,35 @@ azureWebApp {
}
}
```
[Usage example](./samples/todo-app-java-on-azure.appservice-on-linux)

### Deploy JAR
`appService` block should be specified, with the values:

Name | Value
---|---
type | 'windows'
javaVersion | Java version. Supported versions are: {1.7, 1.7.0_51, 1.7.0_71, 1.8, 1.8.0_25, 1.8.0_60, 1.8.0_73, 1.8.0_111, 1.8.0_92, 1.8.0_102, 1.8.0_144}
```
azureWebApp {
resourceGroup = "${System.env.WEBAPP_RESOURCE_GROUP}"
appName = "${System.env.WEBAPP_NAME}"
pricingTier = "S1"
appService = {
type = 'windows'
javaVersion = '1.8.0_25'
}
authentication = {
type = "file"
file = file('C:/stuff/2days.azureauth')
}
deployment = {
type = "jar"
// optional, if not provided, bootJar task output is used
// jarFile = file('<path_to_jar_file>')
}
}
```
[Sample ToDo app](./samples/todo-app-java-on-azure.jar)

## Web App on Linux

Expand Down
2 changes: 1 addition & 1 deletion azure-webapp-gradle-plugin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ repositories {
}

dependencies {
compile 'com.microsoft.azure:azure:1.15.1'
compile 'com.microsoft.azure:azure:1.17.1'
compile 'commons-net:commons-net:3.6'
compile 'commons-io:commons-io:2.2'
compile 'org.zeroturnaround:zt-zip:1.13'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
public class Deployment {
private DeploymentType type;
private String warFile;
private String jarFile;
private String contextPath;
private String deploymentSlot;
private List<FTPResource> resources = new ArrayList<FTPResource>();
Expand All @@ -27,6 +28,10 @@ public String getWarFile() {
return this.warFile;
}

public String getJarFile() {
return jarFile;
}

public String getDeploymentSlot() {
return deploymentSlot;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ public enum DeploymentType {
FTP,
WAR,
ZIP,
JAR,
UNKNOWN;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
import java.util.List;

public abstract class ArtifactHandlerBase implements ArtifactHandler {
protected static final String DEPLOY_START = "Trying to deploy artifact to %s...";
protected static final String DEPLOY_FINISH = "Successfully deployed the artifact to https://%s";

protected DeployTask task;

protected ArtifactHandlerBase(@Nonnull final DeployTask task) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ public ArtifactHandler getArtifactHandler(final DeployTask task) throws GradleEx
return new WarArtifactHandlerImpl(task);
case ZIP:
return new ZipArtifactHandlerImpl(task);
case JAR:
return new JarArtifactHandlerImpl(task);
case FTP:
default:
return new FTPArtifactHandlerImpl(task);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for
* license information.
*/
package com.microsoft.azure.gradle.webapp.handlers;

import com.google.common.io.Files;
import com.microsoft.azure.gradle.webapp.DeployTask;
import com.microsoft.azure.gradle.webapp.configuration.AppServiceType;
import com.microsoft.azure.gradle.webapp.configuration.DeployTarget;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.gradle.api.GradleException;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;

/**
* Artifact handler for deploying a JAR, self-contained, Java application (e.g.
* Spring Boot) to Azure App Service through FTP
*
* @since 1.3.0
*/
public final class JarArtifactHandlerImpl extends ZipArtifactHandlerImpl {
private static final String FILE_IS_NOT_JAR = "The deployment file is not a jar typed file.";
private static final String FIND_JAR_FILE_FAIL = "Failed to find the jar file: '%s'";

private static final String DEFAULT_LINUX_JAR_NAME = "app.jar";
private static final String JAR_CMD = ":JAR_COMMAND:";
private static final String FILENAME = ":FILENAME:";
private static final String DEFAULT_JAR_COMMAND = "-Djava.net.preferIPv4Stack=true " +
"-Dserver.port=%HTTP_PLATFORM_PORT% " +
"-jar &quot;%HOME%\\\\site\\\\wwwroot\\\\:FILENAME:&quot;";
private static final String GENERATE_WEB_CONFIG_FAIL = "Failed to generate web.config file for JAR deployment.";
private static final String READ_WEB_CONFIG_TEMPLATE_FAIL = "Failed to read the content of web.config.template.";
private static final String GENERATING_WEB_CONFIG = "Generating web.config for Web App on Windows.";

protected JarArtifactHandlerImpl(final DeployTask task) {
super(task);
}

@Override
public void publish(DeployTarget deployTarget) throws IOException {
final File jar = getJarFile();
assureJarFileExisted(jar);

prepareDeploymentFiles(jar);

super.publish(deployTarget);
}

protected void prepareDeploymentFiles(File jar) throws IOException {
final File parent = new File(getDeploymentStagingDirectoryPath());
parent.mkdirs();

if (AppServiceType.LINUX.equals(task.getAzureWebAppExtension().getAppService().getType())) {
Files.copy(jar, new File(parent, DEFAULT_LINUX_JAR_NAME));
} else {
Files.copy(jar, new File(parent, jar.getName()));
generateWebConfigFile(jar.getName());
}
}

protected void generateWebConfigFile(String jarFileName) throws IOException {
task.getLogger().quiet(GENERATING_WEB_CONFIG);
final String templateContent;
try (final InputStream is = getClass().getResourceAsStream("web.config.template")) {
templateContent = IOUtils.toString(is, "UTF-8");
} catch (IOException e) {
task.getLogger().quiet(READ_WEB_CONFIG_TEMPLATE_FAIL);
throw e;
}

final String webConfigFile = templateContent
.replaceAll(JAR_CMD, DEFAULT_JAR_COMMAND.replaceAll(FILENAME, jarFileName));

final File webConfig = new File(getDeploymentStagingDirectoryPath(), "web.config");
webConfig.createNewFile();

try (final FileOutputStream fos = new FileOutputStream(webConfig)) {
IOUtils.write(webConfigFile, fos, "UTF-8");
} catch (Exception e) {
task.getLogger().quiet(GENERATE_WEB_CONFIG_FAIL);
throw e;
}
}

protected File getJarFile() {
String jarFile = task.getAzureWebAppExtension().getDeployment().getJarFile();
if (StringUtils.isEmpty(jarFile)) {
jarFile = task.getProject().getTasks().getByPath("bootJar").getOutputs().getFiles().getAsPath();
}
return new File(jarFile);
}

protected void assureJarFileExisted(File jar) throws GradleException {
if (!Files.getFileExtension(jar.getName()).equalsIgnoreCase("jar")) {
throw new GradleException(FILE_IS_NOT_JAR);
}

if (!jar.exists() || !jar.isFile()) {
throw new GradleException(String.format(FIND_JAR_FILE_FAIL, jar.getAbsolutePath()));
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.io.IOException;

public class ZipArtifactHandlerImpl extends ArtifactHandlerBase {
private static final int DEFAULT_MAX_RETRY_TIMES = 3;

public ZipArtifactHandlerImpl(final DeployTask task) {
super(task);
Expand All @@ -24,6 +25,24 @@ public void publish(DeployTarget target) throws GradleException, IOException {
prepareResources();
assureStagingDirectoryNotEmpty();

File zipFile = getZipFile();
task.getLogger().info(String.format(DEPLOY_START, target.getName()));

// Add retry logic here to avoid Kudu's socket timeout issue.
// More details: https://github.com/Microsoft/azure-maven-plugins/issues/339
int retryCount = 0;
while (retryCount < DEFAULT_MAX_RETRY_TIMES) {
retryCount += 1;
try {
target.zipDeploy(zipFile);
task.getLogger().quiet(String.format(DEPLOY_FINISH, target.getDefaultHostName()));
return;
} catch (Exception e) {
task.getLogger().quiet(
String.format("Exception occurred when deploying the zip package: %s, " +
"retrying immediately (%d/%d)", e.getMessage(), retryCount, DEFAULT_MAX_RETRY_TIMES));
}
}
target.zipDeploy(getZipFile());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ public static RuntimeStack getLinuxRuntimeStackFromString(final String runtimeSt
return RuntimeStack.TOMCAT_8_5_JRE8;
} else if (runtimeStack.equalsIgnoreCase(RuntimeStack.TOMCAT_9_0_JRE8.toString())) {
return RuntimeStack.TOMCAT_9_0_JRE8;
} else if (runtimeStack.equalsIgnoreCase(RuntimeStack.WILDFLY_14_JRE8.toString())) {
return RuntimeStack.WILDFLY_14_JRE8;
} else if (runtimeStack.equalsIgnoreCase("jre8")) {
return RuntimeStack.JAVA_8_JRE8;
} else {
throw new GradleException(String.format(UNKNOWN_VALUE_TEMPLATE, "appService.runtimeStack"));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified"/>
</handlers>
<httpPlatform processPath="%JAVA_HOME%\bin\java.exe" arguments=":JAR_COMMAND:">
</httpPlatform>
</system.webServer>
</configuration>
21 changes: 21 additions & 0 deletions samples/todo-app-java-on-azure.jar/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) Microsoft Corporation. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
Loading

0 comments on commit abba613

Please sign in to comment.