diff --git a/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/AsyncDeploymentResult.java b/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/AsyncDeploymentResult.java new file mode 100644 index 00000000000..f7f18c8db3d --- /dev/null +++ b/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/AsyncDeploymentResult.java @@ -0,0 +1,31 @@ +/** + * 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.management.appservice; + +/** + * Result of async deployment. + */ +public class AsyncDeploymentResult { + + private final String deploymentId; + + /** + * Creates an AsyncDeploymentResult instance. + * + * @param deploymentId the deployment ID. + */ + public AsyncDeploymentResult(String deploymentId) { + this.deploymentId = deploymentId; + } + + /** + * @return the deployment ID. It can be {@code null} if tracking deployment is disabled. + */ + public String deploymentId() { + return deploymentId; + } +} diff --git a/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/BuildStatus.java b/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/BuildStatus.java new file mode 100644 index 00000000000..dd494a1e903 --- /dev/null +++ b/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/BuildStatus.java @@ -0,0 +1,62 @@ +/** + * 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.management.appservice; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.azure.management.resources.fluentcore.arm.ExpandableStringEnum; + +import java.util.Collection; + +public final class BuildStatus extends ExpandableStringEnum { + + /** Enum value RuntimeFailed. */ + public static final BuildStatus RUNTIME_FAILED = fromString("RuntimeFailed"); + + /** Enum value BuildAborted. */ + public static final BuildStatus BUILD_ABORTED = fromString("BuildAborted"); + + /** Enum value BuildFailed. */ + public static final BuildStatus BUILD_FAILED = fromString("BuildFailed"); + + /** Enum value BuildRequestReceived. */ + public static final BuildStatus BUILD_REQUEST_RECEIVED = fromString("BuildRequestReceived"); + + /** Enum value BuildPending. */ + public static final BuildStatus BUILD_PENDING = fromString("BuildPending"); + + /** Enum value BuildInProgress. */ + public static final BuildStatus BUILD_IN_PROGRESS = fromString("BuildInProgress"); + + /** Enum value BuildSuccessful. */ + public static final BuildStatus BUILD_SUCCESSFUL = fromString("BuildSuccessful"); + + /** Enum value PostBuildRestartRequired. */ + public static final BuildStatus POST_BUILD_RESTART_REQUIRED = fromString("PostBuildRestartRequired"); + + /** Enum value RuntimeStarting. */ + public static final BuildStatus RUNTIME_STARTING = fromString("RuntimeStarting"); + + /** Enum value RuntimeSuccessful. */ + public static final BuildStatus RUNTIME_SUCCESSFUL = fromString("RuntimeSuccessful"); + + /** + * Creates or finds a BuildStatus from its string representation. + * @param name a name to look for + * @return the corresponding BuildStatus + */ + @JsonCreator + public static BuildStatus fromString(String name) { + return fromString(name, BuildStatus.class); + } + + /** + * @return known SecurityRuleDirection values + */ + public static Collection values() { + return values(BuildStatus.class); + } +} diff --git a/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/DeployOptions.java b/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/DeployOptions.java index 6577a8b432b..e93b92af45e 100644 --- a/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/DeployOptions.java +++ b/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/DeployOptions.java @@ -6,6 +6,8 @@ package com.microsoft.azure.management.appservice; +import java.io.File; + /** * The options for OneDeploy. */ @@ -14,6 +16,7 @@ public class DeployOptions { private String path; private Boolean restartSite; private Boolean cleanDeployment; + private Boolean trackDeployment; /** * @return the path for deploy @@ -74,4 +77,24 @@ public DeployOptions withCleanDeployment(Boolean cleanDeployment) { this.cleanDeployment = cleanDeployment; return this; } + + /** + * @return whether to track deployment progress + */ + public Boolean trackDeployment() { + return trackDeployment; + } + + /** + * Specifies whether to have {@link AsyncDeploymentResult#deploymentId()} to track deployment progress. + * + * This option only takes effect when used in {@link SupportsOneDeploy#pushDeploy(DeployType, File, DeployOptions)}. + * + * @param trackDeployment whether to track deployment progress + * @return the DeployOptions object + */ + public DeployOptions withTrackDeployment(Boolean trackDeployment) { + this.trackDeployment = trackDeployment; + return this; + } } diff --git a/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/DeploymentStatus.java b/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/DeploymentStatus.java new file mode 100644 index 00000000000..ee03a5dce21 --- /dev/null +++ b/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/DeploymentStatus.java @@ -0,0 +1,49 @@ +/** + * 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.management.appservice; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; +import com.microsoft.rest.serializer.JsonFlatten; + +@JsonFlatten +public class DeploymentStatus extends ProxyResource { + + @JsonProperty(value = "properties.id") + private BuildStatus deploymentId; + + @JsonProperty(value = "properties.status") + private BuildStatus buildStatus; + + @JsonProperty(value = "properties.numberOfInstancesInProgress") + int numberOfInstancesInProgress; + + @JsonProperty(value = "properties.numberOfInstancesSuccessful") + int numberOfInstancesSuccessful; + + @JsonProperty(value = "properties.numberOfInstancesFailed") + int numberOfInstancesFailed; + + public BuildStatus deploymentId() { + return deploymentId; + } + + public BuildStatus buildStatus() { + return buildStatus; + } + + public int numberOfInstancesInProgress() { + return numberOfInstancesInProgress; + } + + public int numberOfInstancesSuccessful() { + return numberOfInstancesSuccessful; + } + + public int numberOfInstancesFailed() { + return numberOfInstancesFailed; + } +} diff --git a/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/SupportsOneDeploy.java b/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/SupportsOneDeploy.java index 21b86dbb471..e806a4cf5cb 100644 --- a/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/SupportsOneDeploy.java +++ b/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/SupportsOneDeploy.java @@ -8,6 +8,7 @@ import com.microsoft.azure.management.apigeneration.Beta; import rx.Completable; +import rx.Observable; import java.io.File; import java.io.InputStream; @@ -89,4 +90,44 @@ public interface SupportsOneDeploy { * @return a completable of the operation */ Completable deployAsync(DeployType type, InputStream file, DeployOptions deployOptions); + + /** + * Deploy a file to Azure site. + * + * @param type the deploy type + * @param file the file to upload + * @param deployOptions the deploy options + * @return the result of the deployment, which contains the deployment ID for query on the deployment status. + */ + AsyncDeploymentResult pushDeploy(DeployType type, File file, DeployOptions deployOptions); + + /** + * Deploy a file to Azure site. + * + * @param type the deploy type + * @param file the file to upload + * @param deployOptions the deploy options + * @return the result of the deployment, which contains the deployment ID for query on the deployment status. + */ + Observable pushDeployAsync(DeployType type, File file, DeployOptions deployOptions); + + /** + * Deploy a file to Azure site. + * + * @param type the deploy type + * @param file the file to upload + * @param deployOptions the deploy options + * @return the result of the deployment, which contains the deployment ID for query on the deployment status. + */ + AsyncDeploymentResult pushDeploy(DeployType type, InputStream file, DeployOptions deployOptions); + + /** + * Deploy a file to Azure site. + * + * @param type the deploy type + * @param file the file to upload + * @param deployOptions the deploy options + * @return the result of the deployment, which contains the deployment ID for query on the deployment status. + */ + Observable pushDeployAsync(DeployType type, InputStream file, DeployOptions deployOptions); } diff --git a/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/WebApp.java b/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/WebApp.java index 5fcc9ff323d..64938c0940f 100644 --- a/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/WebApp.java +++ b/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/WebApp.java @@ -16,6 +16,7 @@ import com.microsoft.azure.management.resources.fluentcore.model.Refreshable; import com.microsoft.azure.management.resources.fluentcore.model.Updatable; import rx.Completable; +import rx.Observable; import java.io.File; import java.io.InputStream; @@ -525,4 +526,60 @@ interface Update extends WebAppBase.Update, UpdateStages.WithDockerContainerImage { } -} \ No newline at end of file + + /** + * Asynchronous deploys a ZIP file onto the Azure specialized Java SE image on this web app. + * + * @see #getDeploymentStatusAsync(String) + * @param zipFile the ZIP file to upload + * @param trackDeployment whether to have {@link AsyncDeploymentResult#deploymentId()} to track deployment progress + * @return the result of the deployment, which contains the deployment ID for query on the deployment status. + */ + Observable pushZipDeployAsync(File zipFile, boolean trackDeployment); + + /** + * Asynchronous deploys a ZIP file onto the Azure specialized Java SE image on this web app. + * + * @see #getDeploymentStatusAsync(String) + * @param zipFile the ZIP file to upload + * @param trackDeployment whether to have {@link AsyncDeploymentResult#deploymentId()} to track deployment progress + * @return the result of the deployment, which contains the deployment ID for query on the deployment status. + */ + AsyncDeploymentResult pushZipDeploy(File zipFile, boolean trackDeployment); + + /** + * Asynchronous deploys a ZIP file onto the Azure specialized Java SE image on this web app. + * + * @see #getDeploymentStatus(String) + * @param zipFile the ZIP file to upload + * @param trackDeployment whether to have {@link AsyncDeploymentResult#deploymentId()} to track deployment progress + * @return the result of the deployment, which contains the deployment ID for query on the deployment status. + */ + AsyncDeploymentResult pushZipDeploy(InputStream zipFile, boolean trackDeployment); + + /** + * Asynchronous deploys a ZIP file onto the Azure specialized Java SE image on this web app. + * + * @see #getDeploymentStatusAsync(String) + * @param zipFile the ZIP file to upload + * @param trackDeployment whether to have {@link AsyncDeploymentResult#deploymentId()} to track deployment progress + * @return the result of the deployment, which contains the deployment ID for query on the deployment status. + */ + Observable pushZipDeployAsync(InputStream zipFile, boolean trackDeployment); + + /** + * Gets the deployment status of the web app. + * + * @param deploymentId the deployment ID of the web app. + * @return the deployment status. + */ + Observable getDeploymentStatusAsync(String deploymentId); + + /** + * Gets the deployment status of the web app. + * + * @param deploymentId the deployment ID of the web app. + * @return the deployment status. + */ + DeploymentStatus getDeploymentStatus(String deploymentId); +} diff --git a/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/implementation/DeploymentSlotImpl.java b/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/implementation/DeploymentSlotImpl.java index 403040a937d..cb82917e81f 100644 --- a/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/implementation/DeploymentSlotImpl.java +++ b/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/implementation/DeploymentSlotImpl.java @@ -7,11 +7,13 @@ package com.microsoft.azure.management.appservice.implementation; import com.microsoft.azure.management.apigeneration.LangDefinition; +import com.microsoft.azure.management.appservice.AsyncDeploymentResult; import com.microsoft.azure.management.appservice.DeployOptions; import com.microsoft.azure.management.appservice.DeployType; import com.microsoft.azure.management.appservice.DeploymentSlot; import com.microsoft.azure.management.appservice.WebApp; import rx.Completable; +import rx.Observable; import rx.exceptions.Exceptions; import rx.functions.Action0; @@ -201,4 +203,44 @@ public Completable deployAsync(DeployType type, InputStream file, DeployOptions } return kuduClient.deployAsync(type, file, deployOptions.path(), deployOptions.restartSite(), deployOptions.cleanDeployment()); } + + @Override + public AsyncDeploymentResult pushDeploy(DeployType type, File file, DeployOptions deployOptions) { + return pushDeployAsync(type, file, deployOptions).toBlocking().last(); + } + + @Override + public Observable pushDeployAsync(DeployType type, File file, DeployOptions deployOptions) { + Objects.requireNonNull(file); + try { + final InputStream is = new FileInputStream(file); + return pushDeployAsync(type, new FileInputStream(file), deployOptions).doAfterTerminate(new Action0() { + @Override + public void call() { + try { + is.close(); + } catch (IOException e) { + Exceptions.propagate(e); + } + } + }); + } catch (IOException e) { + return Observable.error(e); + } + } + + @Override + public AsyncDeploymentResult pushDeploy(DeployType type, InputStream file, DeployOptions deployOptions) { + return pushDeployAsync(type, file, deployOptions).toBlocking().last(); + } + + @Override + public Observable pushDeployAsync(DeployType type, InputStream file, DeployOptions deployOptions) { + Objects.requireNonNull(type); + Objects.requireNonNull(file); + if (deployOptions == null) { + deployOptions = new DeployOptions(); + } + return kuduClient.pushDeployAsync(type, file, deployOptions.path(), deployOptions.restartSite(), deployOptions.cleanDeployment(), deployOptions.trackDeployment()); + } } diff --git a/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/implementation/KuduClient.java b/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/implementation/KuduClient.java index ae1b9a5b3d4..95ac991207d 100644 --- a/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/implementation/KuduClient.java +++ b/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/implementation/KuduClient.java @@ -6,10 +6,12 @@ package com.microsoft.azure.management.appservice.implementation; +import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.base.Joiner; import com.google.common.io.ByteStreams; import com.google.common.reflect.TypeToken; import com.microsoft.azure.AzureResponseBuilder; +import com.microsoft.azure.management.appservice.AsyncDeploymentResult; import com.microsoft.azure.management.appservice.DeployType; import com.microsoft.azure.management.appservice.WebAppBase; import com.microsoft.rest.RestClient; @@ -28,6 +30,7 @@ import retrofit2.http.POST; import retrofit2.http.Query; import retrofit2.http.Streaming; +import retrofit2.http.Url; import rx.Completable; import rx.Emitter; import rx.Emitter.BackpressureMode; @@ -101,15 +104,19 @@ private interface KuduService { @Headers({ "Content-Type: application/octet-stream", "x-ms-logging-context: com.microsoft.azure.management.appservice.WebApps zipDeploy", "x-ms-body-logging: false" }) @POST("api/zipdeploy") - Observable> zipDeploy(@Body RequestBody zipFile); + Observable> zipDeploy(@Body RequestBody zipFile, @Query("isAsync") Boolean isAsync, @Query("trackDeploymentProgress") Boolean trackDeploymentProgress); @Headers({ "Content-Type: application/octet-stream", "x-ms-logging-context: com.microsoft.azure.management.appservice.WebApps publish", "x-ms-body-logging: false" }) @POST("api/publish") - Observable> deploy(@Body RequestBody file, @Query("type") DeployType type, @Query("path") String path, @Query("restart") Boolean restart, @Query("clean") Boolean clean); + Observable> deploy(@Body RequestBody file, @Query("type") DeployType type, @Query("path") String path, @Query("restart") Boolean restart, @Query("clean") Boolean clean, @Query("isAsync") Boolean isAsync, @Query("trackDeploymentProgress") Boolean trackDeploymentProgress); @Headers({ "x-ms-logging-context: com.microsoft.azure.management.appservice.WebApps settings" }) @GET("api/settings") Observable> settings(); + + @Headers({ "x-ms-logging-context: com.microsoft.azure.management.appservice.WebApps getDeployment" }) + @GET + Observable> getDeployment(@Url String deploymentUrl); } Observable streamApplicationLogsAsync() { @@ -198,24 +205,97 @@ Completable zipDeployAsync(InputStream zipFile) { try { RequestBody body = RequestBody.create(MediaType.parse("application/octet-stream"), ByteStreams.toByteArray(zipFile)); Observable> response = - retryOnError(handleResponse(service.zipDeploy(body))); + retryOnError(handleResponse(service.zipDeploy(body, false, false))); return response.toCompletable(); } catch (IOException e) { return Completable.error(e); } } + private static class DeploymentIntermediateResult { + private String deploymentUrl; + private String deploymentId; + } + + private static class DeploymentResponse { + @JsonProperty(value = "id") + private String id; + + @JsonProperty(value = "is_temp") + private Boolean isTemp; + } + + Observable pushZipDeployAsync(InputStream zipFile, Boolean trackDeployment) { + final boolean trackDeploymentProgress = trackDeployment == null || trackDeployment; + + try { + RequestBody body = RequestBody.create(MediaType.parse("application/octet-stream"), ByteStreams.toByteArray(zipFile)); + + // service returns 404 on deploymentStatus, if deployment ID is get from SCM-DEPLOYMENT-ID + Observable result = + retryOnError(handleResponse(service.zipDeploy(body, true, trackDeploymentProgress), new Func1, AsyncDeploymentResult>() { + @Override + public AsyncDeploymentResult call(Response responseBodyResponse) { + String deploymentId = responseBodyResponse.headers().get("SCM-DEPLOYMENT-ID"); + if (trackDeploymentProgress && (deploymentId == null || deploymentId.isEmpty())) { + // error if deployment ID not available + throw new RestException("Deployment ID not found in response", responseBodyResponse); + } + return new AsyncDeploymentResult(deploymentId); + } + })).map(new Func1, AsyncDeploymentResult>() { + @Override + public AsyncDeploymentResult call(ServiceResponse result) { + return result.body(); + } + }); + return result; + } catch (IOException e) { + return Observable.error(e); + } + } + Completable deployAsync(DeployType type, InputStream file, String path, Boolean restart, Boolean clean) { try { RequestBody body = RequestBody.create(MediaType.parse("application/octet-stream"), ByteStreams.toByteArray(file)); Observable> response = - retryOnError(handleResponse(service.deploy(body, type, path, restart, clean))); + retryOnError(handleResponse(service.deploy(body, type, path, restart, clean, false, false))); return response.toCompletable(); } catch (IOException e) { return Completable.error(e); } } + Observable pushDeployAsync(DeployType type, InputStream file, String path, Boolean restart, Boolean clean, Boolean trackDeployment) { + final boolean trackDeploymentProgress = trackDeployment == null || trackDeployment; + + try { + RequestBody body = RequestBody.create(MediaType.parse("application/octet-stream"), ByteStreams.toByteArray(file)); + + // service returns 404 on deploymentStatus, if deployment ID is get from SCM-DEPLOYMENT-ID + Observable result = + retryOnError(handleResponse(service.deploy(body, type, path, restart, clean, true, trackDeploymentProgress), new Func1, AsyncDeploymentResult>() { + @Override + public AsyncDeploymentResult call(Response responseBodyResponse) { + String deploymentId = responseBodyResponse.headers().get("SCM-DEPLOYMENT-ID"); + if (trackDeploymentProgress && (deploymentId == null || deploymentId.isEmpty())) { + // error if deployment ID not available + throw new RestException("Deployment ID not found in response", responseBodyResponse); + } + return new AsyncDeploymentResult(deploymentId); + } + })).map(new Func1, AsyncDeploymentResult>() { + @Override + public AsyncDeploymentResult call(ServiceResponse result) { + return result.body(); + } + }); + return result; + } catch (IOException e) { + return Observable.error(e); + } + } + Observable> settings() { return retryOnError(service.settings().flatMap(new Func1, Observable>>>() { @Override @@ -248,12 +328,21 @@ public Map call(ServiceResponse> response) { } private Observable> handleResponse(Observable> observable) { - return observable.flatMap(new Func1, Observable>>() { + return this.handleResponse(observable, new Func1, Void>() { + @Override + public Void call(Response responseBodyResponse) { + return null; + } + }); + } + + private Observable> handleResponse(Observable> observable, final Func1, T> responseFunc) { + return observable.flatMap(new Func1, Observable>>() { @Override - public Observable> call(Response response) { + public Observable> call(Response response) { try { if (response.isSuccessful()) { - return Observable.just(new ServiceResponse(null, response)); + return Observable.just(new ServiceResponse(responseFunc.call(response), response)); } else { String errorMessage = "Status code " + response.code(); if (response.errorBody() != null diff --git a/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/implementation/WebAppImpl.java b/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/implementation/WebAppImpl.java index a14bfba6750..fb04366ee2e 100644 --- a/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/implementation/WebAppImpl.java +++ b/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/implementation/WebAppImpl.java @@ -8,9 +8,11 @@ import com.microsoft.azure.management.apigeneration.LangDefinition; import com.microsoft.azure.management.appservice.AppServicePlan; +import com.microsoft.azure.management.appservice.AsyncDeploymentResult; import com.microsoft.azure.management.appservice.DeployType; import com.microsoft.azure.management.appservice.DeployOptions; import com.microsoft.azure.management.appservice.DeploymentSlots; +import com.microsoft.azure.management.appservice.DeploymentStatus; import com.microsoft.azure.management.appservice.OperatingSystem; import com.microsoft.azure.management.appservice.PricingTier; import com.microsoft.azure.management.appservice.RuntimeStack; @@ -254,6 +256,50 @@ public void zipDeploy(InputStream zipFile) { zipDeployAsync(zipFile).await(); } + @Override + public Observable pushZipDeployAsync(File zipFile, boolean trackDeployment) { + try { + final InputStream is = new FileInputStream(zipFile); + return pushZipDeployAsync(new FileInputStream(zipFile), trackDeployment).doAfterTerminate(new Action0() { + @Override + public void call() { + try { + is.close(); + } catch (IOException e) { + Exceptions.propagate(e); + } + } + }); + } catch (IOException e) { + return Observable.error(e); + } + } + + @Override + public Observable pushZipDeployAsync(InputStream zipFile, boolean trackDeployment) { + return kuduClient.pushZipDeployAsync(zipFile, trackDeployment); + } + + @Override + public AsyncDeploymentResult pushZipDeploy(File zipFile, boolean trackDeployment) { + return pushZipDeployAsync(zipFile, trackDeployment).toBlocking().last(); + } + + @Override + public AsyncDeploymentResult pushZipDeploy(InputStream zipFile, boolean trackDeployment) { + return pushZipDeployAsync(zipFile, trackDeployment).toBlocking().last(); + } + + @Override + public Observable getDeploymentStatusAsync(String deploymentId) { + return this.manager().inner().webApps().getDeploymentStatusAsync(this.resourceGroupName(), this.name(), deploymentId); + } + + @Override + public DeploymentStatus getDeploymentStatus(String deploymentId) { + return this.manager().inner().webApps().getDeploymentStatus(this.resourceGroupName(), this.name(), deploymentId); + } + @Override public void deploy(DeployType type, File file) { deployAsync(type, file).await(); @@ -314,6 +360,46 @@ public Completable deployAsync(DeployType type, InputStream file, DeployOptions return kuduClient.deployAsync(type, file, deployOptions.path(), deployOptions.restartSite(), deployOptions.cleanDeployment()); } + @Override + public AsyncDeploymentResult pushDeploy(DeployType type, File file, DeployOptions deployOptions) { + return pushDeployAsync(type, file, deployOptions).toBlocking().single(); + } + + @Override + public Observable pushDeployAsync(DeployType type, File file, DeployOptions deployOptions) { + Objects.requireNonNull(file); + try { + final InputStream is = new FileInputStream(file); + return pushDeployAsync(type, new FileInputStream(file), deployOptions).doAfterTerminate(new Action0() { + @Override + public void call() { + try { + is.close(); + } catch (IOException e) { + Exceptions.propagate(e); + } + } + }); + } catch (IOException e) { + return Observable.error(e); + } + } + + @Override + public AsyncDeploymentResult pushDeploy(DeployType type, InputStream file, DeployOptions deployOptions) { + return pushDeployAsync(type, file, deployOptions).toBlocking().single(); + } + + @Override + public Observable pushDeployAsync(DeployType type, InputStream file, DeployOptions deployOptions) { + Objects.requireNonNull(type); + Objects.requireNonNull(file); + if (deployOptions == null) { + deployOptions = new DeployOptions(); + } + return kuduClient.pushDeployAsync(type, file, deployOptions.path(), deployOptions.restartSite(), deployOptions.cleanDeployment(), deployOptions.trackDeployment()); + } + @Override Observable submitMetadata() { Observable observable = super.submitMetadata(); diff --git a/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/implementation/WebAppsInner.java b/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/implementation/WebAppsInner.java index 44ba7a3194b..5ebfe64635b 100644 --- a/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/implementation/WebAppsInner.java +++ b/azure-mgmt-appservice/src/main/java/com/microsoft/azure/management/appservice/implementation/WebAppsInner.java @@ -8,6 +8,7 @@ package com.microsoft.azure.management.appservice.implementation; +import com.microsoft.azure.management.appservice.DeploymentStatus; import com.microsoft.azure.management.resources.fluentcore.collection.InnerSupportsGet; import com.microsoft.azure.management.resources.fluentcore.collection.InnerSupportsDelete; import com.microsoft.azure.management.resources.fluentcore.collection.InnerSupportsListing; @@ -79,6 +80,10 @@ public WebAppsInner(Retrofit retrofit, WebSiteManagementClientImpl client) { * used by Retrofit to perform actually REST calls. */ interface WebAppsService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.appservice.WebApps getDeploymentStatus" }) + @GET("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{name}/deploymentStatus/{deploymentId}") + Observable> getDeploymentStatus(@Path("resourceGroupName") String resourceGroupName, @Path("name") String name, @Path("deploymentId") String deploymentId, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.appservice.WebApps list" }) @GET("subscriptions/{subscriptionId}/providers/Microsoft.Web/sites") Observable> list(@Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); @@ -49820,4 +49825,56 @@ private ServiceResponse> listWebJobsNextDelegate(Response< .build(response); } + public DeploymentStatus getDeploymentStatus(String resourceGroupName, String name, String deploymentId) { + return getDeploymentStatusWithServiceResponseAsync(resourceGroupName, name, deploymentId).toBlocking().single().body(); + } + + public ServiceFuture getDeploymentStatusAsync(String resourceGroupName, String name, String deploymentId, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getDeploymentStatusWithServiceResponseAsync(resourceGroupName, name, deploymentId), serviceCallback); + } + + public Observable getDeploymentStatusAsync(String resourceGroupName, String name, String deploymentId) { + return getDeploymentStatusWithServiceResponseAsync(resourceGroupName, name, deploymentId).map(new Func1, DeploymentStatus>() { + @Override + public DeploymentStatus call(ServiceResponse response) { + return response.body(); + } + }); + } + + public Observable> getDeploymentStatusWithServiceResponseAsync(String resourceGroupName, String name, String deploymentId) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (name == null) { + throw new IllegalArgumentException("Parameter name is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.getDeploymentStatus(resourceGroupName, name, deploymentId, this.client.subscriptionId(), "2021-03-01", this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDeploymentStatusDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDeploymentStatusDelegate(Response response) throws DefaultErrorResponseException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(201, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(DefaultErrorResponseException.class) + .build(response); + } } diff --git a/azure-mgmt-appservice/src/test/java/com/microsoft/azure/management/appservice/LinuxWebAppsTests.java b/azure-mgmt-appservice/src/test/java/com/microsoft/azure/management/appservice/LinuxWebAppsTests.java index 2b300437df5..1b1f8f0a133 100644 --- a/azure-mgmt-appservice/src/test/java/com/microsoft/azure/management/appservice/LinuxWebAppsTests.java +++ b/azure-mgmt-appservice/src/test/java/com/microsoft/azure/management/appservice/LinuxWebAppsTests.java @@ -13,9 +13,11 @@ import okhttp3.OkHttpClient; import okhttp3.Response; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; import java.io.ByteArrayInputStream; +import java.io.File; import java.util.concurrent.TimeUnit; import java.util.zip.ZipInputStream; @@ -42,6 +44,36 @@ protected void cleanUpResources() { resourceManager.resourceGroups().beginDeleteByName(RG_NAME_1); } + @Test + @Ignore + public void canGetDeploymentStatus() throws InterruptedException { +// WebApp wa = appServiceManager.webApps().getByResourceGroup("rg-weidxu1", "wa1weidxu"); + WebApp wa = appServiceManager.webApps().define("wa1weidxu") + .withRegion(Region.US_WEST_CENTRAL) + .withNewResourceGroup("rg-weidxu1") + .withNewLinuxPlan(PricingTier.STANDARD_S1) + .withBuiltInImage(RuntimeStack.JAVA_11_JAVA11) + .create(); + AsyncDeploymentResult result = wa.pushDeploy(DeployType.ZIP, new File("C:/github/app.zip"), null); +// AsyncDeploymentResult result = wa.pushZipDeploy(new File("C:/github/app.zip")); + DeploymentStatus status = wa.getDeploymentStatus(result.deploymentId()); + while (status == null) { + System.out.println("status not ready"); + Thread.sleep(10 * 1000); + // try again + status = wa.getDeploymentStatus(result.deploymentId()); + } + BuildStatus buildStatus = status.buildStatus(); + System.out.println("build status: " + buildStatus); + while (buildStatus != BuildStatus.RUNTIME_SUCCESSFUL) { + Thread.sleep(10 * 1000); + // poll again + status = wa.getDeploymentStatus(result.deploymentId()); + buildStatus = status.buildStatus(); + System.out.println("build status: " + buildStatus); + } + } + @Test // @Ignore("Pending ICM 39157077 & https://github.com/Azure-App-Service/kudu/issues/30") public void canCRUDLinuxWebApp() throws Exception {