Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mgmt doc on LRO beginCreate/beginDelete #12899

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1786,7 +1786,7 @@ public Accepted<VirtualMachine> beginCreate() {
inner -> new VirtualMachineImpl(inner.name(), inner, this.manager(),
this.storageManager, this.networkManager, this.authorizationManager));

reset(accepted.getAcceptedResult().getValue().inner());
reset(accepted.getActivationResponse().getValue().inner());
return accepted;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,17 +211,17 @@ public void canCreateVirtualMachineSyncPoll() throws Exception {
.withOSDiskName("javatest")
.withLicenseType("Windows_Server")
.beginCreate();
VirtualMachine createdVirtualMachine = acceptedVirtualMachine.getAcceptedResult().getValue();
VirtualMachine createdVirtualMachine = acceptedVirtualMachine.getActivationResponse().getValue();
Assertions.assertNotEquals("Succeeded", createdVirtualMachine.provisioningState());

LongRunningOperationStatus pollStatus = acceptedVirtualMachine.getAcceptedResult().getStatus();
int delayInMills = acceptedVirtualMachine.getAcceptedResult().getRetryAfter() == null
LongRunningOperationStatus pollStatus = acceptedVirtualMachine.getActivationResponse().getStatus();
int delayInMills = acceptedVirtualMachine.getActivationResponse().getRetryAfter() == null
? 0
: (int) acceptedVirtualMachine.getAcceptedResult().getRetryAfter().toMillis();
: (int) acceptedVirtualMachine.getActivationResponse().getRetryAfter().toMillis();
while (!pollStatus.isComplete()) {
SdkContext.sleep(delayInMills);

PollResponse<Void> pollResponse = acceptedVirtualMachine.getSyncPoller().poll();
PollResponse<?> pollResponse = acceptedVirtualMachine.getSyncPoller().poll();
pollStatus = pollResponse.getStatus();
delayInMills = pollResponse.getRetryAfter() == null
? 10000
Expand All @@ -234,15 +234,15 @@ public void canCreateVirtualMachineSyncPoll() throws Exception {
Accepted<Void> acceptedDelete = computeManager.virtualMachines()
.beginDeleteByResourceGroup(virtualMachine.resourceGroupName(), virtualMachine.name());

pollStatus = acceptedDelete.getAcceptedResult().getStatus();
delayInMills = acceptedDelete.getAcceptedResult().getRetryAfter() == null
pollStatus = acceptedDelete.getActivationResponse().getStatus();
delayInMills = acceptedDelete.getActivationResponse().getRetryAfter() == null
? 0
: (int) acceptedDelete.getAcceptedResult().getRetryAfter().toMillis();
: (int) acceptedDelete.getActivationResponse().getRetryAfter().toMillis();

while (!pollStatus.isComplete()) {
SdkContext.sleep(delayInMills);

PollResponse<Void> pollResponse = acceptedDelete.getSyncPoller().poll();
PollResponse<?> pollResponse = acceptedDelete.getSyncPoller().poll();
pollStatus = pollResponse.getStatus();
delayInMills = pollResponse.getRetryAfter() == null
? 10000
Expand Down
3 changes: 3 additions & 0 deletions sdk/management/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ The key concepts of Azure Management Libraries includes:
- Integration with Azure role-based access control.
- Asynchronous operations with [Reactor][reactor]. (Preview)
- Configurable client, e.g. configuring HTTP client, retries, logging, etc.
- [API design][design]
- [API design (preview)][design_preview]

### Service features

Expand Down Expand Up @@ -325,4 +327,5 @@ If you would like to become an active contributor to this project please follow
[authenticate]: docs/AUTH.md
[sample]: docs/SAMPLE.md
[design]: docs/DESIGN.md
[design_preview]: docs/DESIGN_PREVIEW.md
[reactor]: https://projectreactor.io/
54 changes: 54 additions & 0 deletions sdk/management/docs/DESIGN_PREVIEW.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Design for Azure Management Libraries for Java (Preview)

## Fluent interface

### Fine control over long-running operation

Resource provision takes time, a typical solution adopted by Azure services is the [long-running operation (LRO)][lro].

Fluent interface does the polling operations in background, and only returns the final result.

Azure Management Libraries supports fine control over the polling for certain important resources, via `Accepted` and `SyncPoller` class. Method verb is `beginCreate` and `beginDelete`.

`Accepted` class provides following functionalities:
- `ActivationResponse` via `getActivationResponse` method provides the response of the first activation operation. Note that though it wraps a resource instance, some action on this resource instance will not work, since it is not provisioned yet.
- `SyncPoller` via `getSyncPoller` method provides the control of the polling operations. `SyncPoller.poll` can be called at desired time.
- Resource instance via `getFinalResult` method, after completion of the polling operations. The method will throw `ManagementException` if polling failed and resource cannot be provisioned.

Here is sample code for Deployment.

```java
// begin provision
Accepted<Deployment> acceptedDeployment = azure.deployments()
.define(name)
...
.beginCreate();
Deployment provisioningDeployment = acceptedDeployment.getAcceptedResult().getValue();

LongRunningOperationStatus pollStatus = acceptedDeployment.getAcceptedResult().getStatus();
int delayInMills = acceptedDeployment.getAcceptedResult().getRetryAfter() == null
? 0
: (int) acceptedDeployment.getAcceptedResult().getRetryAfter().toMillis();
while (!pollStatus.isComplete()) {
Thread.sleep(delayInMills);

// poll
PollResponse<?> pollResponse = acceptedDeployment.getSyncPoller().poll();
pollStatus = pollResponse.getStatus();
delayInMills = pollResponse.getRetryAfter() == null
? DEFAULT_DELAY_IN_MILLIS
: (int) pollResponse.getRetryAfter().toMillis();
}
// pollStatus == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED, if successful

// final result
Deployment deployment = acceptedDeployment.getFinalResult();
```

Supported Azure resources:
- `delete` for `ResourceGroup`
- `create` for `Deployment`
- `create` and `delete` for `GenericResource`
- `create` and `delete` for `VirtualMachine`

[lro]: https://docs.microsoft.com/en-us/azure/architecture/patterns/async-request-reply
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
public interface Accepted<T> {

/**
* Gets the accepted result of LRO.
* Gets the activation response of LRO.
*
* @return the accepted result
* @return the activation response
*/
ActivationResponse<T> getAcceptedResult();
ActivationResponse<T> getActivationResponse();

/**
* Gets the {@link SyncPoller} of LRO.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public AcceptedImpl(Response<Flux<ByteBuffer>> activationResponse,
}

@Override
public ActivationResponse<T> getAcceptedResult() {
public ActivationResponse<T> getActivationResponse() {
try {
T value = wrapOperation.apply(serializerAdapter.deserialize(
new String(getResponse(), StandardCharsets.UTF_8),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,13 +269,11 @@ protected <T extends Indexable> T taskResult(String key) {
}
}

@SuppressWarnings("unchecked")
protected Function<InnerModelT, FluentModelT> innerToFluentMap(final FluentModelImplT fluentModelImplT) {
return new Function<InnerModelT, FluentModelT>() {
@Override
public FluentModelT apply(InnerModelT innerModel) {
fluentModelImplT.setInner(innerModel);
return (FluentModelT) fluentModelImplT;
}
return innerModel -> {
fluentModelImplT.setInner(innerModel);
return (FluentModelT) fluentModelImplT;
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ public Accepted<Deployment> beginCreate() {
DeploymentExtendedInner.class,
inner -> new DeploymentImpl(inner, inner.name(), resourceManager));

setInner(accepted.getAcceptedResult().getValue().inner());
setInner(accepted.getActivationResponse().getValue().inner());
return accepted;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ public void deleteById(String id) {
deleteByIdAsync(id).block();
}


@Override
public Mono<Void> deleteByIdAsync(String id) {
return deleteByResourceGroupAsync(ResourceUtils.groupFromResourceId(id), ResourceUtils.nameFromResourceId(id));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@

package com.azure.resourcemanager.resources.implementation;

import com.azure.core.http.rest.Response;
import com.azure.core.util.logging.ClientLogger;
import com.azure.resourcemanager.resources.ResourceManager;
import com.azure.resourcemanager.resources.fluentcore.model.Accepted;
import com.azure.resourcemanager.resources.fluentcore.model.implementation.AcceptedImpl;
import com.azure.resourcemanager.resources.models.GenericResource;
import com.azure.resourcemanager.resources.models.Plan;
import com.azure.resourcemanager.resources.fluentcore.arm.ResourceUtils;
Expand All @@ -12,8 +16,11 @@
import com.azure.resourcemanager.resources.fluent.inner.GenericResourceInner;
import com.azure.resourcemanager.resources.ResourceManagementClient;
import com.azure.resourcemanager.resources.fluent.ResourcesClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.ByteBuffer;

/**
* The implementation for GenericResource and its nested interfaces.
*/
Expand All @@ -28,6 +35,9 @@ final class GenericResourceImpl
GenericResource.Definition,
GenericResource.UpdateStages.WithApiVersion,
GenericResource.Update {

private final ClientLogger logger = new ClientLogger(GenericResourceImpl.class);

private String resourceProviderNamespace;
private String parentResourcePath;
private String resourceType;
Expand Down Expand Up @@ -140,33 +150,44 @@ public GenericResourceImpl withApiVersion(String apiVersion) {
return this;
}

// CreateUpdateTaskGroup.ResourceCreator implementation
@Override
public Mono<GenericResource> createResourceAsync() {
final GenericResourceImpl self = this;
Mono<String> observable = null;
if (apiVersion != null) {
observable = Mono.just(apiVersion);
public Accepted<GenericResource> beginCreate() {
String apiVersion = this.getApiVersionAsync().block();

String name = this.name();
if (!isInCreateMode()) {
name = ResourceUtils.nameFromResourceId(inner().id());
}

Response<Flux<ByteBuffer>> activationResponse = this.manager().inner().getResources()
.createOrUpdateWithResponseAsync(
resourceGroupName(),
resourceProviderNamespace,
parentResourcePath(),
resourceType,
name,
apiVersion,
inner()).block();
if (activationResponse == null) {
throw logger.logExceptionAsError(new NullPointerException());
} else {
final ResourceManagementClient serviceClient = this.manager().inner();
observable = this.manager().providers().getByNameAsync(resourceProviderNamespace)
.flatMap(provider -> {
String id;
if (!isInCreateMode()) {
id = inner().id();
} else {
id = ResourceUtils.constructResourceId(
serviceClient.getSubscriptionId(),
resourceGroupName(),
resourceProviderNamespace(),
resourceType(),
this.name(),
parentResourcePath());
}
self.apiVersion = ResourceUtils.defaultApiVersion(id, provider);
return Mono.just(self.apiVersion);
});
Accepted<GenericResource> accepted = new AcceptedImpl<GenericResourceInner, GenericResource>(
activationResponse,
this.manager().inner().getSerializerAdapter(),
this.manager().inner().getHttpPipeline(),
GenericResourceInner.class,
GenericResourceInner.class,
inner -> new GenericResourceImpl(inner.id(), inner, this.manager()));

setInner(accepted.getActivationResponse().getValue().inner());
return accepted;
}
}

// CreateUpdateTaskGroup.ResourceCreator implementation
@Override
public Mono<GenericResource> createResourceAsync() {
Mono<String> observable = this.getApiVersionAsync();
final ResourcesClient resourceClient = this.manager().inner().getResources();
return observable
.flatMap(api -> {
Expand All @@ -183,7 +204,34 @@ public Mono<GenericResource> createResourceAsync() {
api,
inner())
.subscribeOn(SdkContext.getReactorScheduler())
.map(innerToFluentMap(self));
.map(innerToFluentMap(this));
});
}

private Mono<String> getApiVersionAsync() {
Mono<String> apiVersion;
if (this.apiVersion != null) {
apiVersion = Mono.just(this.apiVersion);
} else {
final ResourceManagementClient serviceClient = this.manager().inner();
apiVersion = this.manager().providers().getByNameAsync(resourceProviderNamespace)
.flatMap(provider -> {
String id;
if (!isInCreateMode()) {
id = inner().id();
} else {
id = ResourceUtils.constructResourceId(
serviceClient.getSubscriptionId(),
resourceGroupName(),
resourceProviderNamespace(),
resourceType(),
this.name(),
parentResourcePath());
}
this.apiVersion = ResourceUtils.defaultApiVersion(id, provider);
return Mono.just(this.apiVersion);
});
}
return apiVersion;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@

import com.azure.core.http.rest.PagedFlux;
import com.azure.core.http.rest.PagedIterable;
import com.azure.core.http.rest.Response;
import com.azure.core.util.logging.ClientLogger;
import com.azure.resourcemanager.resources.ResourceManager;
import com.azure.resourcemanager.resources.fluentcore.model.Accepted;
import com.azure.resourcemanager.resources.fluentcore.model.implementation.AcceptedImpl;
import com.azure.resourcemanager.resources.models.GenericResource;
import com.azure.resourcemanager.resources.models.GenericResources;
import com.azure.resourcemanager.resources.models.ResourceGroup;
Expand All @@ -17,9 +20,12 @@
import com.azure.resourcemanager.resources.fluentcore.utils.Utils;
import com.azure.resourcemanager.resources.fluent.inner.GenericResourceInner;
import com.azure.resourcemanager.resources.fluent.ResourcesClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.ByteBuffer;
import java.util.List;
import java.util.function.Function;

/**
* Implementation of the {@link GenericResources}.
Expand Down Expand Up @@ -179,7 +185,6 @@ public Mono<Void> deleteAsync(String resourceGroupName, String resourceProviderN
parentResourcePath, resourceType, resourceName, apiVersion);
}


@Override
protected GenericResourceImpl wrapModel(String id) {
return new GenericResourceImpl(id, new GenericResourceInner(), this.manager())
Expand Down Expand Up @@ -222,6 +227,24 @@ public Mono<Void> deleteByIdAsync(final String id) {
.flatMap(apiVersion -> inner.deleteByIdAsync(id, apiVersion));
}

@Override
public Accepted<Void> beginDeleteById(String id) {
String apiVersion = getApiVersionFromId(id).block();

Response<Flux<ByteBuffer>> activationResponse = this.inner()
.deleteByIdWithResponseAsync(id, apiVersion).block();
if (activationResponse == null) {
throw logger.logExceptionAsError(new NullPointerException());
} else {
return new AcceptedImpl<Void, Void>(activationResponse,
manager().inner().getSerializerAdapter(),
manager().inner().getHttpPipeline(),
Void.class,
Void.class,
Function.identity());
}
}

private Mono<String> getApiVersionFromId(final String id) {
return this.manager().providers().getByNameAsync(ResourceUtils.resourceProviderFromResourceId(id))
.map(provider -> ResourceUtils.defaultApiVersion(id, provider));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.azure.core.annotation.Fluent;
import com.azure.resourcemanager.resources.fluentcore.arm.models.GroupableResource;
import com.azure.resourcemanager.resources.fluentcore.arm.models.Resource;
import com.azure.resourcemanager.resources.fluentcore.model.Accepted;
import com.azure.resourcemanager.resources.fluentcore.model.Appliable;
import com.azure.resourcemanager.resources.fluentcore.model.Creatable;
import com.azure.resourcemanager.resources.fluentcore.model.Refreshable;
Expand Down Expand Up @@ -181,6 +182,13 @@ interface WithCreate extends
* @return the next stage of generic resource definition
*/
WithCreate withProperties(Object properties);

/**
* Begins creating the Azure resource.
*
* @return the accepted create operation
*/
Accepted<GenericResource> beginCreate();
}
}

Expand Down
Loading