Skip to content

Commit

Permalink
mgmt, appservice, support async deploy with deployment ID (#26375)
Browse files Browse the repository at this point in the history
  • Loading branch information
weidongxu-microsoft authored Jan 17, 2022
1 parent ba79b1f commit e9a73a8
Show file tree
Hide file tree
Showing 8 changed files with 258 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## 2.11.0-beta.1 (Unreleased)

### Features Added

- Supported option for tracking deployment status via `pushDeploy` in `WebApp` and `DeploymentSlot`.

### Other Changes

#### Dependency Updates
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.azure.resourcemanager.appservice.models.DeployType;
import com.azure.resourcemanager.appservice.models.DeploymentSlot;
import com.azure.resourcemanager.appservice.models.DeploymentSlotBase;
import com.azure.resourcemanager.appservice.models.KuduDeploymentResult;
import com.azure.resourcemanager.appservice.models.WebApp;
import com.azure.resourcemanager.appservice.fluent.models.SiteConfigResourceInner;
import com.azure.resourcemanager.appservice.fluent.models.SiteInner;
Expand Down Expand Up @@ -172,4 +173,25 @@ public Mono<Void> deployAsync(DeployType type, InputStream file, long length, De
return kuduClient.deployAsync(type, file, length,
deployOptions.path(), deployOptions.restartSite(), deployOptions.cleanDeployment());
}

@Override
public KuduDeploymentResult pushDeploy(DeployType type, File file, DeployOptions deployOptions) {
return pushDeployAsync(type, file, deployOptions).block();
}

@Override
public Mono<KuduDeploymentResult> pushDeployAsync(DeployType type, File file, DeployOptions deployOptions) {
Objects.requireNonNull(type);
Objects.requireNonNull(file);
if (deployOptions == null) {
deployOptions = new DeployOptions();
}
try {
return kuduClient.pushDeployAsync(type, file,
deployOptions.path(), deployOptions.restartSite(), deployOptions.cleanDeployment(),
deployOptions.trackDeployment());
} catch (IOException e) {
return Mono.error(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,20 @@
import com.azure.core.annotation.Post;
import com.azure.core.annotation.QueryParam;
import com.azure.core.annotation.ServiceInterface;
import com.azure.core.exception.AzureException;
import com.azure.core.http.HttpHeader;
import com.azure.core.http.HttpPipeline;
import com.azure.core.http.HttpPipelineBuilder;
import com.azure.core.http.policy.HttpPipelinePolicy;
import com.azure.core.http.rest.Response;
import com.azure.core.http.rest.RestProxy;
import com.azure.core.http.rest.StreamResponse;
import com.azure.core.management.serializer.SerializerFactory;
import com.azure.core.util.FluxUtil;
import com.azure.core.util.logging.ClientLogger;
import com.azure.resourcemanager.appservice.models.DeployType;
import com.azure.resourcemanager.appservice.models.KuduAuthenticationPolicy;
import com.azure.resourcemanager.appservice.models.KuduDeploymentResult;
import com.azure.resourcemanager.appservice.models.WebAppBase;
import com.azure.resourcemanager.resources.fluentcore.policy.AuthenticationPolicy;
import com.azure.resourcemanager.resources.fluentcore.policy.AuxiliaryAuthenticationPolicy;
Expand Down Expand Up @@ -142,13 +146,16 @@ Mono<Void> zipDeploy(

@Headers({"Content-Type: application/octet-stream"})
@Post("api/publish")
Mono<Void> deploy(@HostParam("$host") String host,
Mono<Response<Void>> deploy(
@HostParam("$host") String host,
@BodyParam("application/octet-stream") Flux<ByteBuffer> file,
@HeaderParam("content-length") long size,
@QueryParam("type") DeployType type,
@QueryParam("path") String path,
@QueryParam("restart") Boolean restart,
@QueryParam("clean") Boolean clean);
@QueryParam("clean") Boolean clean,
@QueryParam("isAsync") Boolean isAsync,
@QueryParam("trackDeploymentProgress") Boolean trackDeploymentProgress);

@Get("api/settings")
Mono<Map<String, String>> settings(@HostParam("$host") String host);
Expand Down Expand Up @@ -298,15 +305,44 @@ Mono<Void> deployAsync(DeployType type,
InputStream file, long length,
String path, Boolean restart, Boolean clean) {
Flux<ByteBuffer> flux = FluxUtil.toFluxByteBuffer(file);
return retryOnError(service.deploy(host, flux, length, type, path, restart, clean));
return retryOnError(service.deploy(host, flux, length, type, path, restart, clean, false, false))
.then();
}

Mono<Void> deployAsync(DeployType type,
File file,
String path, Boolean restart, Boolean clean) throws IOException {
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(file.toPath(), StandardOpenOption.READ);
return retryOnError(service.deploy(host, FluxUtil.readFile(fileChannel), fileChannel.size(),
type, path, restart, clean))
type, path, restart, clean, false, false))
.then()
.doFinally(ignored -> {
try {
fileChannel.close();
} catch (IOException e) {
logger.logThrowableAsError(e);
}
});
}

Mono<KuduDeploymentResult> pushDeployAsync(DeployType type, File file, String path, Boolean restart,
Boolean clean, Boolean trackDeployment) throws IOException {
final boolean trackDeploymentProgress = trackDeployment == null || trackDeployment;

AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(file.toPath(), StandardOpenOption.READ);
return retryOnError(service.deploy(host, FluxUtil.readFile(fileChannel), fileChannel.size(),
type, path, restart, clean, true, trackDeployment))
.map(response -> {
HttpHeader deploymentIdHeader = response.getHeaders().get("SCM-DEPLOYMENT-ID");
if (trackDeploymentProgress && (deploymentIdHeader == null || deploymentIdHeader.getValue() == null
|| deploymentIdHeader.getValue().isEmpty())) {

// error, deployment ID not available
throw logger.logExceptionAsError(
new AzureException("Deployment ID not found in response header 'SCM-DEPLOYMENT-ID'"));
}
return new KuduDeploymentResult(deploymentIdHeader == null ? null : deploymentIdHeader.getValue());
})
.doFinally(ignored -> {
try {
fileChannel.close();
Expand All @@ -320,37 +356,6 @@ Mono<Map<String, String>> settings() {
return retryOnError(service.settings(host));
}

// private InputStreamFlux fluxFromInputStream(InputStream inputStream) {
// try {
// InputStreamFlux inputStreamFlux = new InputStreamFlux();
// if (inputStream instanceof FileInputStream) {
// inputStreamFlux.size = ((FileInputStream) inputStream).getChannel().size();
// inputStreamFlux.flux = FluxUtil.toFluxByteBuffer(inputStream);
// } else if (inputStream instanceof ByteArrayInputStream) {
// inputStreamFlux.size = inputStream.available();
// inputStreamFlux.flux = FluxUtil.toFluxByteBuffer(inputStream);
// } else {
// ByteArrayOutputStream buffer = new ByteArrayOutputStream();
// int nRead;
// byte[] data = new byte[16384];
// while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
// buffer.write(data, 0, nRead);
// }
// inputStreamFlux.bytes = buffer.toByteArray();
// inputStreamFlux.size = inputStreamFlux.bytes.length;
// }
// return inputStreamFlux;
// } catch (IOException e) {
// throw logger.logExceptionAsError(new IllegalStateException(e));
// }
// }
//
// private static class InputStreamFlux {
// private Flux<ByteBuffer> flux;
// private byte[] bytes;
// private long size;
// }

private <T> Mono<T> retryOnError(Mono<T> observable) {
final int retryCount = 5 + 1; // retryCount is 5, last 1 is guard
return observable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.azure.resourcemanager.appservice.models.DeployOptions;
import com.azure.resourcemanager.appservice.models.DeployType;
import com.azure.resourcemanager.appservice.models.DeploymentSlots;
import com.azure.resourcemanager.appservice.models.KuduDeploymentResult;
import com.azure.resourcemanager.appservice.models.OperatingSystem;
import com.azure.resourcemanager.appservice.models.PricingTier;
import com.azure.resourcemanager.appservice.models.RuntimeStack;
Expand Down Expand Up @@ -338,4 +339,25 @@ public Mono<Void> deployAsync(DeployType type, InputStream file, long length, De
return kuduClient.deployAsync(type, file, length,
deployOptions.path(), deployOptions.restartSite(), deployOptions.cleanDeployment());
}

@Override
public KuduDeploymentResult pushDeploy(DeployType type, File file, DeployOptions deployOptions) {
return pushDeployAsync(type, file, deployOptions).block();
}

@Override
public Mono<KuduDeploymentResult> pushDeployAsync(DeployType type, File file, DeployOptions deployOptions) {
Objects.requireNonNull(type);
Objects.requireNonNull(file);
if (deployOptions == null) {
deployOptions = new DeployOptions();
}
try {
return kuduClient.pushDeployAsync(type, file,
deployOptions.path(), deployOptions.restartSite(), deployOptions.cleanDeployment(),
deployOptions.trackDeployment());
} catch (IOException e) {
return Mono.error(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public class DeployOptions {
private String path;
private Boolean restartSite;
private Boolean cleanDeployment;
private Boolean trackDeployment;

/**
* @return the path for deploy
Expand Down Expand Up @@ -72,4 +73,25 @@ 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 KuduDeploymentResult#deploymentId()} to track deployment progress.
*
* This option only takes effect when used in
* {@link SupportsOneDeploy#pushDeploy(DeployType, java.io.File, DeployOptions)}.
*
* @param trackDeployment whether to track deployment progress
* @return the DeployOptions object
*/
public DeployOptions withTrackDeployment(Boolean trackDeployment) {
this.trackDeployment = trackDeployment;
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.resourcemanager.appservice.models;

/**
* Result of Kudu deployment.
*/
public final class KuduDeploymentResult {

private final String deploymentId;

/**
* Creates a KuduDeploymentResult instance.
*
* @param deploymentId the deployment ID.
*/
public KuduDeploymentResult(String deploymentId) {
this.deploymentId = deploymentId;
}

/**
* @return the deployment ID. It can be {@code null} if tracking deployment is disabled.
*/
public String deploymentId() {
return deploymentId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,26 @@ public interface SupportsOneDeploy {
* @return the completable of the operation
*/
Mono<Void> deployAsync(DeployType type, InputStream file, long length, 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
* if {@link DeployOptions#withTrackDeployment(Boolean)} set to True.
*/
KuduDeploymentResult 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
* if {@link DeployOptions#withTrackDeployment(Boolean)} set to True.
*/
Mono<KuduDeploymentResult> pushDeployAsync(DeployType type, File file, DeployOptions deployOptions);
}
Loading

0 comments on commit e9a73a8

Please sign in to comment.