class AzureResourceConnector extends AbstractResourceConnector {

    @Override
    public List<CloudResourceStatus> launch(AuthenticatedContext ac, CloudStack stack, PersistenceNotifier notifier,
            AdjustmentType adjustmentType, Long threshold) {
        AzureCredentialView azureCredentialView = new AzureCredentialView(ac.getCloudCredential());
        CloudContext cloudContext = ac.getCloudContext();
        String stackName = azureUtils.getStackName(cloudContext);
        String resourceGroupName = azureResourceGroupMetadataProvider.getResourceGroupName(cloudContext, stack);
        AzureClient client = ac.getParameter(AzureClient.class);

        AzureImage image = azureStorage.getCustomImage(client, ac, stack);
        if (!image.getAlreadyExists()) {
            LOGGER.debug("Image {} has been created now, so we need to persist it", image.getName());
            CloudResource imageCloudResource = azureCloudResourceService.buildCloudResource(image.getName(), image.getId(), ResourceType.AZURE_MANAGED_IMAGE);
            azureCloudResourceService.saveCloudResources(notifier, ac.getCloudContext(), List.of(imageCloudResource));
        }
        String customImageId = image.getId();
        AzureStackView azureStackView = azureStackViewProvider.getAzureStack(azureCredentialView, stack, client, ac);
        String template = azureTemplateBuilder.build(stackName, customImageId, azureCredentialView, azureStackView,
                cloudContext, stack, AzureInstanceTemplateOperation.PROVISION);

        String parameters = azureTemplateBuilder.buildParameters(ac.getCloudCredential(), stack.getNetwork(), stack.getImage());

        boolean resourcesPersisted = false;
        try {
            List<CloudResource> instances;
            if (!client.templateDeploymentExists(resourceGroupName, stackName)) {
                Deployment templateDeployment = client.createTemplateDeployment(resourceGroupName, stackName, template, parameters);
                LOGGER.debug("Created template deployment for launch: {}", templateDeployment.exportTemplate().template());
                instances = persistCloudResources(ac, stack, notifier, cloudContext, stackName, resourceGroupName, templateDeployment);
            } else {
                Deployment templateDeployment = client.getTemplateDeployment(resourceGroupName, stackName);
                LOGGER.debug("Get template deployment for launch as it exists: {}", templateDeployment.exportTemplate().template());
                instances = persistCloudResources(ac, stack, notifier, cloudContext, stackName, resourceGroupName, templateDeployment);
            }
            resourcesPersisted = true;
            String networkName = azureUtils.getCustomNetworkId(stack.getNetwork());
            List<String> subnetNameList = azureUtils.getCustomSubnetIds(stack.getNetwork());
            List<CloudResource> networkResources = azureCloudResourceService.collectAndSaveNetworkAndSubnet(
                    resourceGroupName, stackName, notifier, cloudContext, subnetNameList, networkName, client);
            azureComputeResourceService.buildComputeResourcesForLaunch(ac, stack, adjustmentType, threshold, instances, networkResources);
        } catch (CloudException e) {
            LOGGER.info("Provisioning error, cloud exception happened: ", e);
            if (e.body() != null && e.body().details() != null) {
                String details = e.body().details().stream().map(CloudError::message).collect(Collectors.joining(", "));
                throw new CloudConnectorException(String.format("Stack provisioning failed, status code %s, error message: %s, details: %s",
                        e.body().code(), e.body().message(), details));
            } else {
                throw new CloudConnectorException(String.format("Stack provisioning failed: '%s', please go to Azure Portal for detailed message", e));
            }
        } catch (Exception e) {
            LOGGER.warn("Provisioning error:", e);
            throw new CloudConnectorException(String.format("Error in provisioning stack %s: %s", stackName, e.getMessage()));
        } finally {
            if (!resourcesPersisted) {
                Deployment templateDeployment = client.getTemplateDeployment(resourceGroupName, stackName);
                if (templateDeployment != null && templateDeployment.exportTemplate() != null) {
                    LOGGER.debug("Get template deployment to persist created resources: {}", templateDeployment.exportTemplate().template());
                    persistCloudResources(ac, stack, notifier, cloudContext, stackName, resourceGroupName, templateDeployment);
                }
            }
        }

        CloudResource cloudResource = new Builder()
                .type(ResourceType.ARM_TEMPLATE)
                .name(resourceGroupName)
                .build();
        List<CloudResourceStatus> resources = check(ac, Collections.singletonList(cloudResource));
        LOGGER.debug("Launched resources: {}", resources);
        return resources;
    }

}