diff --git a/sdk/resourcemanager/azure-resourcemanager-compute/src/test/java/com/azure/resourcemanager/compute/VirtualMachineOperationsTests.java b/sdk/resourcemanager/azure-resourcemanager-compute/src/test/java/com/azure/resourcemanager/compute/VirtualMachineOperationsTests.java index 1bb37a0505da9..26c590562c6ee 100644 --- a/sdk/resourcemanager/azure-resourcemanager-compute/src/test/java/com/azure/resourcemanager/compute/VirtualMachineOperationsTests.java +++ b/sdk/resourcemanager/azure-resourcemanager-compute/src/test/java/com/azure/resourcemanager/compute/VirtualMachineOperationsTests.java @@ -194,6 +194,8 @@ public void canCreateVirtualMachine() throws Exception { @Test public void canCreateVirtualMachineSyncPoll() throws Exception { + final long defaultDelayInMillis = 10 * 1000; + Accepted acceptedVirtualMachine = computeManager .virtualMachines() .define(vmName) @@ -215,17 +217,17 @@ public void canCreateVirtualMachineSyncPoll() throws Exception { Assertions.assertNotEquals("Succeeded", createdVirtualMachine.provisioningState()); LongRunningOperationStatus pollStatus = acceptedVirtualMachine.getActivationResponse().getStatus(); - int delayInMills = acceptedVirtualMachine.getActivationResponse().getRetryAfter() == null - ? 0 - : (int) acceptedVirtualMachine.getActivationResponse().getRetryAfter().toMillis(); + long delayInMills = acceptedVirtualMachine.getActivationResponse().getRetryAfter() == null + ? defaultDelayInMillis + : acceptedVirtualMachine.getActivationResponse().getRetryAfter().toMillis(); while (!pollStatus.isComplete()) { SdkContext.sleep(delayInMills); PollResponse pollResponse = acceptedVirtualMachine.getSyncPoller().poll(); pollStatus = pollResponse.getStatus(); delayInMills = pollResponse.getRetryAfter() == null - ? 10000 - : (int) pollResponse.getRetryAfter().toMillis(); + ? defaultDelayInMillis + : pollResponse.getRetryAfter().toMillis(); } Assertions.assertEquals(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED, pollStatus); VirtualMachine virtualMachine = acceptedVirtualMachine.getFinalResult(); @@ -236,7 +238,7 @@ public void canCreateVirtualMachineSyncPoll() throws Exception { pollStatus = acceptedDelete.getActivationResponse().getStatus(); delayInMills = acceptedDelete.getActivationResponse().getRetryAfter() == null - ? 0 + ? defaultDelayInMillis : (int) acceptedDelete.getActivationResponse().getRetryAfter().toMillis(); while (!pollStatus.isComplete()) { @@ -245,7 +247,7 @@ public void canCreateVirtualMachineSyncPoll() throws Exception { PollResponse pollResponse = acceptedDelete.getSyncPoller().poll(); pollStatus = pollResponse.getStatus(); delayInMills = pollResponse.getRetryAfter() == null - ? 10000 + ? defaultDelayInMillis : (int) pollResponse.getRetryAfter().toMillis(); } diff --git a/sdk/resourcemanager/azure-resourcemanager-resources/src/main/java/com/azure/resourcemanager/resources/fluentcore/model/implementation/AcceptedImpl.java b/sdk/resourcemanager/azure-resourcemanager-resources/src/main/java/com/azure/resourcemanager/resources/fluentcore/model/implementation/AcceptedImpl.java index 7c53a11ee5d67..c2734b3078edb 100644 --- a/sdk/resourcemanager/azure-resourcemanager-resources/src/main/java/com/azure/resourcemanager/resources/fluentcore/model/implementation/AcceptedImpl.java +++ b/sdk/resourcemanager/azure-resourcemanager-resources/src/main/java/com/azure/resourcemanager/resources/fluentcore/model/implementation/AcceptedImpl.java @@ -11,6 +11,7 @@ import com.azure.core.management.exception.ManagementException; import com.azure.core.management.polling.PollResult; import com.azure.core.management.polling.PollerFactory; +import com.azure.core.util.CoreUtils; import com.azure.core.util.FluxUtil; import com.azure.core.util.logging.ClientLogger; import com.azure.core.util.polling.LongRunningOperationStatus; @@ -24,6 +25,7 @@ import com.azure.resourcemanager.resources.fluentcore.model.HasInner; import com.azure.resourcemanager.resources.fluentcore.rest.ActivationResponse; import com.azure.resourcemanager.resources.fluentcore.utils.SdkContext; +import com.fasterxml.jackson.annotation.JsonProperty; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -79,23 +81,13 @@ public ActivationResponse getActivationResponse() { Duration retryAfter = getRetryAfter(activationResponse.getHeaders()); return new ActivationResponse<>(activationResponse.getRequest(), activationResponse.getStatusCode(), activationResponse.getHeaders(), value, - LongRunningOperationStatus.IN_PROGRESS, retryAfter); + getActivationResponseStatus(), retryAfter); } catch (IOException e) { throw logger.logExceptionAsError( new IllegalStateException("Failed to deserialize activation response body", e)); } } - private static Duration getRetryAfter(HttpHeaders headers) { - if (headers != null) { - final String value = headers.getValue("Retry-After"); - if (value != null) { - return Duration.ofSeconds(Long.parseLong(value)); - } - } - return null; - } - @Override public SyncPoller getSyncPoller() { if (syncPoller == null) { @@ -159,6 +151,60 @@ public T getFinalResult() { return this.getSyncPoller().getFinalResult(); } + private LongRunningOperationStatus getActivationResponseStatus() { + String responseBody = new String(getResponse(), StandardCharsets.UTF_8); + String provisioningState = null; + // try get "provisioningState" property. + if (!CoreUtils.isNullOrEmpty(responseBody)) { + try { + ResourceWithProvisioningState resource = serializerAdapter.deserialize(responseBody, + ResourceWithProvisioningState.class, SerializerEncoding.JSON); + provisioningState = resource != null + ? resource.getProvisioningState() + : null; + } catch (IOException ignored) { + + } + } + + // get LRO status, default is IN_PROGRESS + LongRunningOperationStatus status = LongRunningOperationStatus.IN_PROGRESS; + if (!CoreUtils.isNullOrEmpty(provisioningState)) { + // LRO status based on provisioningState. + status = toLongRunningOperationStatus(provisioningState); + } else { + // LRO status based on status code. + int statusCode = activationResponse.getStatusCode(); + if (statusCode == 200 || statusCode == 201 || statusCode == 204) { + status = LongRunningOperationStatus.SUCCESSFULLY_COMPLETED; + } + } + return status; + } + + private static LongRunningOperationStatus toLongRunningOperationStatus(String value) { + if (ProvisioningState.SUCCEEDED.equalsIgnoreCase(value)) { + return LongRunningOperationStatus.SUCCESSFULLY_COMPLETED; + } else if (ProvisioningState.FAILED.equalsIgnoreCase(value)) { + return LongRunningOperationStatus.FAILED; + } else if (ProvisioningState.CANCELED.equalsIgnoreCase(value)) { + return LongRunningOperationStatus.USER_CANCELLED; + } else if (ProvisioningState.IN_PROGRESS.equalsIgnoreCase(value)) { + return LongRunningOperationStatus.IN_PROGRESS; + } + return LongRunningOperationStatus.fromString(value, false); + } + + private static Duration getRetryAfter(HttpHeaders headers) { + if (headers != null) { + final String value = headers.getValue("Retry-After"); + if (value != null) { + return Duration.ofSeconds(Long.parseLong(value)); + } + } + return null; + } + private byte[] getResponse() { if (responseBytes == null) { responseBytes = FluxUtil.collectBytesInByteBufferStream(activationResponse.getValue()).block(); @@ -238,6 +284,31 @@ private PollResponse voidResponse(PollResponse> pollRes } } + private static class ResourceWithProvisioningState { + @JsonProperty(value = "properties") + private Properties properties; + + private String getProvisioningState() { + if (this.properties != null) { + return this.properties.provisioningState; + } else { + return null; + } + } + + private static class Properties { + @JsonProperty(value = "provisioningState") + private String provisioningState; + } + } + + private static class ProvisioningState { + static final String IN_PROGRESS = "InProgress"; + static final String SUCCEEDED = "Succeeded"; + static final String FAILED = "Failed"; + static final String CANCELED = "Canceled"; + } + public static Accepted newAccepted( ClientLogger logger, AzureServiceClient client, diff --git a/sdk/resourcemanager/azure-resourcemanager-resources/src/test/java/com/azure/resourcemanager/resources/DeploymentsTests.java b/sdk/resourcemanager/azure-resourcemanager-resources/src/test/java/com/azure/resourcemanager/resources/DeploymentsTests.java index 05fc6754d3e3d..5a2464ce179a2 100644 --- a/sdk/resourcemanager/azure-resourcemanager-resources/src/test/java/com/azure/resourcemanager/resources/DeploymentsTests.java +++ b/sdk/resourcemanager/azure-resourcemanager-resources/src/test/java/com/azure/resourcemanager/resources/DeploymentsTests.java @@ -236,6 +236,8 @@ public void canUpdateVirtualNetworkDeployment() throws Exception { @Test public void canDeployVirtualNetworkSyncPoll() throws Exception { + final long defaultDelayInMillis = 10 * 1000; + final String dp = "dpD" + testId; // Begin create @@ -250,17 +252,17 @@ public void canDeployVirtualNetworkSyncPoll() throws Exception { Assertions.assertNotEquals("Succeeded", createdDeployment.provisioningState()); LongRunningOperationStatus pollStatus = acceptedDeployment.getActivationResponse().getStatus(); - int delayInMills = acceptedDeployment.getActivationResponse().getRetryAfter() == null - ? 0 - : (int) acceptedDeployment.getActivationResponse().getRetryAfter().toMillis(); + long delayInMills = acceptedDeployment.getActivationResponse().getRetryAfter() == null + ? defaultDelayInMillis + : acceptedDeployment.getActivationResponse().getRetryAfter().toMillis(); while (!pollStatus.isComplete()) { SdkContext.sleep(delayInMills); PollResponse pollResponse = acceptedDeployment.getSyncPoller().poll(); pollStatus = pollResponse.getStatus(); delayInMills = pollResponse.getRetryAfter() == null - ? 10000 - : (int) pollResponse.getRetryAfter().toMillis(); + ? defaultDelayInMillis + : pollResponse.getRetryAfter().toMillis(); } Assertions.assertEquals(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED, pollStatus); Deployment deployment = acceptedDeployment.getFinalResult(); @@ -269,6 +271,8 @@ public void canDeployVirtualNetworkSyncPoll() throws Exception { @Test public void canDeployVirtualNetworkSyncPollWithFailure() throws Exception { + final long defaultDelayInMillis = 10 * 1000; + final String templateJson = "{ \"$schema\": \"https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#\", \"contentVersion\": \"1.0.0.0\", \"resources\": [ { \"type\": \"Microsoft.Storage/storageAccounts\", \"apiVersion\": \"2019-04-01\", \"name\": \"satestnameconflict\", \"location\": \"eastus\", \"sku\": { \"name\": \"Standard_LRS\" }, \"kind\": \"StorageV2\", \"properties\": { \"supportsHttpsTrafficOnly\": true } } ] }"; final String dp = "dpE" + testId; @@ -284,17 +288,17 @@ public void canDeployVirtualNetworkSyncPollWithFailure() throws Exception { Assertions.assertNotEquals("Succeeded", createdDeployment.provisioningState()); LongRunningOperationStatus pollStatus = acceptedDeployment.getActivationResponse().getStatus(); - int delayInMills = acceptedDeployment.getActivationResponse().getRetryAfter() == null - ? 0 - : (int) acceptedDeployment.getActivationResponse().getRetryAfter().toMillis(); + long delayInMills = acceptedDeployment.getActivationResponse().getRetryAfter() == null + ? defaultDelayInMillis + : acceptedDeployment.getActivationResponse().getRetryAfter().toMillis(); while (!pollStatus.isComplete()) { SdkContext.sleep(delayInMills); PollResponse pollResponse = acceptedDeployment.getSyncPoller().poll(); pollStatus = pollResponse.getStatus(); delayInMills = pollResponse.getRetryAfter() == null - ? 10000 - : (int) pollResponse.getRetryAfter().toMillis(); + ? defaultDelayInMillis + : pollResponse.getRetryAfter().toMillis(); } Assertions.assertEquals(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED, pollStatus); Deployment deployment = acceptedDeployment.getFinalResult(); @@ -317,7 +321,7 @@ public void canDeployVirtualNetworkSyncPollWithFailure() throws Exception { pollStatus = acceptedDeployment.getActivationResponse().getStatus(); delayInMills = acceptedDeployment.getActivationResponse().getRetryAfter() == null - ? 0 + ? defaultDelayInMillis : (int) acceptedDeployment.getActivationResponse().getRetryAfter().toMillis(); while (!pollStatus.isComplete()) { SdkContext.sleep(delayInMills); @@ -325,7 +329,7 @@ public void canDeployVirtualNetworkSyncPollWithFailure() throws Exception { PollResponse pollResponse = acceptedDeployment.getSyncPoller().poll(); pollStatus = pollResponse.getStatus(); delayInMills = pollResponse.getRetryAfter() == null - ? 10000 + ? defaultDelayInMillis : (int) pollResponse.getRetryAfter().toMillis(); } Assertions.assertEquals(LongRunningOperationStatus.FAILED, pollStatus); diff --git a/sdk/resourcemanager/azure-resourcemanager-resources/src/test/java/com/azure/resourcemanager/resources/GenericResourcesTests.java b/sdk/resourcemanager/azure-resourcemanager-resources/src/test/java/com/azure/resourcemanager/resources/GenericResourcesTests.java index 5d4019432b3ae..b85cdbca0d4ee 100644 --- a/sdk/resourcemanager/azure-resourcemanager-resources/src/test/java/com/azure/resourcemanager/resources/GenericResourcesTests.java +++ b/sdk/resourcemanager/azure-resourcemanager-resources/src/test/java/com/azure/resourcemanager/resources/GenericResourcesTests.java @@ -97,6 +97,8 @@ public void canCreateUpdateMoveResource() throws Exception { @Test public void canCreateDeleteResourceSyncPoll() throws Exception { + final long defaultDelayInMillis = 10 * 1000; + final String resourceName = "rs" + testId; // Create Accepted acceptedResource = genericResources.define(resourceName) @@ -110,17 +112,17 @@ public void canCreateDeleteResourceSyncPoll() throws Exception { .beginCreate(); LongRunningOperationStatus pollStatus = acceptedResource.getActivationResponse().getStatus(); - int delayInMills = acceptedResource.getActivationResponse().getRetryAfter() == null - ? 0 - : (int) acceptedResource.getActivationResponse().getRetryAfter().toMillis(); + long delayInMills = acceptedResource.getActivationResponse().getRetryAfter() == null + ? defaultDelayInMillis + : acceptedResource.getActivationResponse().getRetryAfter().toMillis(); while (!pollStatus.isComplete()) { SdkContext.sleep(delayInMills); PollResponse pollResponse = acceptedResource.getSyncPoller().poll(); pollStatus = pollResponse.getStatus(); delayInMills = pollResponse.getRetryAfter() == null - ? 10000 - : (int) pollResponse.getRetryAfter().toMillis(); + ? defaultDelayInMillis + : pollResponse.getRetryAfter().toMillis(); } Assertions.assertEquals(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED, pollStatus); GenericResource resource = acceptedResource.getFinalResult(); diff --git a/sdk/resourcemanager/azure-resourcemanager/src/test/java/com/azure/resourcemanager/TestVirtualMachineSyncPoller.java b/sdk/resourcemanager/azure-resourcemanager/src/test/java/com/azure/resourcemanager/TestVirtualMachineSyncPoller.java index a9626f7471be4..19ea34a2b56b5 100644 --- a/sdk/resourcemanager/azure-resourcemanager/src/test/java/com/azure/resourcemanager/TestVirtualMachineSyncPoller.java +++ b/sdk/resourcemanager/azure-resourcemanager/src/test/java/com/azure/resourcemanager/TestVirtualMachineSyncPoller.java @@ -3,10 +3,12 @@ package com.azure.resourcemanager; +import com.azure.core.util.logging.ClientLogger; import com.azure.core.util.polling.LongRunningOperationStatus; import com.azure.core.util.polling.PollResponse; import com.azure.core.util.polling.SyncPoller; import com.azure.resourcemanager.compute.models.Disk; +import com.azure.resourcemanager.compute.models.DiskSkuTypes; import com.azure.resourcemanager.compute.models.KnownLinuxVirtualMachineImage; import com.azure.resourcemanager.compute.models.VirtualMachine; import com.azure.resourcemanager.compute.models.VirtualMachineSizeTypes; @@ -22,11 +24,14 @@ import org.junit.jupiter.api.Assertions; import java.time.Duration; +import java.time.OffsetDateTime; public class TestVirtualMachineSyncPoller extends TestTemplate { private final NetworkManager networkManager; + private final ClientLogger logger = new ClientLogger(TestVirtualMachineSyncPoller.class); + public TestVirtualMachineSyncPoller(NetworkManager networkManager) { this.networkManager = networkManager; } @@ -53,17 +58,21 @@ public VirtualMachine createResource(VirtualMachines virtualMachines) throws Exc .create(); // public ip address, poll till complete + logger.info("{} {}", OffsetDateTime.now(), "begin create public IP"); Accepted publicIpAddressAccepted = this.networkManager.publicIpAddresses() .define(ipName) .withRegion(region) .withExistingResourceGroup(rgName) .beginCreate(); + logger.info("{} {}", OffsetDateTime.now(), "polling public IP till complete"); PollResponse publicIpAddressResponse = publicIpAddressAccepted.getSyncPoller().waitForCompletion(); Assertions.assertEquals(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED, publicIpAddressResponse.getStatus()); PublicIpAddress publicIpAddress = publicIpAddressAccepted.getFinalResult(); + logger.info("{} {}", OffsetDateTime.now(), "public IP created"); // nic and disk + logger.info("{} {}", OffsetDateTime.now(), "begin create nic"); Accepted networkInterfaceAccepted = this.networkManager.networkInterfaces() .define(nicName) @@ -75,36 +84,43 @@ public VirtualMachine createResource(VirtualMachines virtualMachines) throws Exc .withExistingPrimaryPublicIPAddress(publicIpAddress) .beginCreate(); + logger.info("{} {}", OffsetDateTime.now(), "begin create data disk"); Accepted diskAccepted = virtualMachines.manager().disks() .define(diskName) .withRegion(region) .withExistingResourceGroup(rgName) .withData() - .withSizeInGB(2) + .withSizeInGB(100) + .withSku(DiskSkuTypes.STANDARD_LRS) .beginCreate(); // poll nic and disk + LongRunningOperationStatus networkInterfaceLroStatus = networkInterfaceAccepted.getActivationResponse().getStatus(); + LongRunningOperationStatus diskLroStatus = diskAccepted.getActivationResponse().getStatus(); SyncPoller networkInterfaceSyncPoller = networkInterfaceAccepted.getSyncPoller(); SyncPoller diskSyncPoller = diskAccepted.getSyncPoller(); - PollResponse networkInterfacePollResponse = networkInterfaceSyncPoller.poll(); - PollResponse diskPollResponse = diskSyncPoller.poll(); - while (!networkInterfacePollResponse.getStatus().isComplete() || !diskPollResponse.getStatus().isComplete()) { - SdkContext.sleep(Duration.ofSeconds(2).toMillis()); + while (!networkInterfaceLroStatus.isComplete() || !diskLroStatus.isComplete()) { + SdkContext.sleep(Duration.ofSeconds(1).toMillis()); - if (!networkInterfacePollResponse.getStatus().isComplete()) { - networkInterfacePollResponse = networkInterfaceSyncPoller.poll(); + if (!networkInterfaceLroStatus.isComplete()) { + logger.info("{} {}", OffsetDateTime.now(), "poll network interface"); + networkInterfaceLroStatus = networkInterfaceSyncPoller.poll().getStatus(); } - if (!diskPollResponse.getStatus().isComplete()) { - diskPollResponse = diskSyncPoller.poll(); + if (!diskLroStatus.isComplete()) { + logger.info("{} {}", OffsetDateTime.now(), "poll data disk"); + diskLroStatus = diskSyncPoller.poll().getStatus(); } } - Assertions.assertEquals(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED, networkInterfacePollResponse.getStatus()); - Assertions.assertEquals(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED, diskPollResponse.getStatus()); + Assertions.assertEquals(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED, networkInterfaceLroStatus); + Assertions.assertEquals(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED, diskLroStatus); NetworkInterface networkInterface = networkInterfaceSyncPoller.getFinalResult(); + logger.info("{} {}", OffsetDateTime.now(), "network interface created"); Disk disk = diskSyncPoller.getFinalResult(); + logger.info("{} {}", OffsetDateTime.now(), "data disk created"); // virtual machine, poll till complete + logger.info("{} {}", OffsetDateTime.now(), "begin create vm"); Accepted virtualMachineAccepted = virtualMachines .define(vmName) @@ -117,8 +133,10 @@ public VirtualMachine createResource(VirtualMachines virtualMachines) throws Exc .withExistingDataDisk(disk) .withSize(VirtualMachineSizeTypes.STANDARD_A9) .beginCreate(); + logger.info("{} {}", OffsetDateTime.now(), "polling virtual machine till complete"); PollResponse virtualMachineResponse = virtualMachineAccepted.getSyncPoller().waitForCompletion(); Assertions.assertEquals(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED, virtualMachineResponse.getStatus()); + logger.info("{} {}", OffsetDateTime.now(), "virtual machine created"); return virtualMachineAccepted.getFinalResult(); } diff --git a/sdk/resourcemanager/docs/DESIGN_PREVIEW.md b/sdk/resourcemanager/docs/DESIGN_PREVIEW.md index 80302108ce1ed..ff5c4dc20fe9b 100644 --- a/sdk/resourcemanager/docs/DESIGN_PREVIEW.md +++ b/sdk/resourcemanager/docs/DESIGN_PREVIEW.md @@ -26,9 +26,9 @@ Accepted acceptedDeployment = azure.deployments() Deployment provisioningDeployment = acceptedDeployment.getActivationResponse().getValue(); LongRunningOperationStatus pollStatus = acceptedDeployment.getActivationResponse().getStatus(); -int delayInMills = acceptedDeployment.getActivationResponse().getRetryAfter() == null - ? 0 - : (int) acceptedDeployment.getActivationResponse().getRetryAfter().toMillis(); +long delayInMills = acceptedDeployment.getActivationResponse().getRetryAfter() == null + ? DEFAULT_DELAY_IN_MILLIS + : acceptedDeployment.getActivationResponse().getRetryAfter().toMillis(); while (!pollStatus.isComplete()) { Thread.sleep(delayInMills); @@ -37,7 +37,7 @@ while (!pollStatus.isComplete()) { pollStatus = pollResponse.getStatus(); delayInMills = pollResponse.getRetryAfter() == null ? DEFAULT_DELAY_IN_MILLIS - : (int) pollResponse.getRetryAfter().toMillis(); + : pollResponse.getRetryAfter().toMillis(); } // pollStatus == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED, if successful